diff --git a/Readme.md b/Readme.md index 90902a1..010b8f2 100644 --- a/Readme.md +++ b/Readme.md @@ -126,7 +126,8 @@ If you want to try latest and greatest unreleased features, you can download lat - **Profile**: Allows to apply/define/delete supersampling profiles that save supersampling and reprojection settings. - **Application Supersampling**: Supersampling setting for OpenVR applications/games. Application supersampling [now behaves linearly](https://steamcommunity.com/games/250820/announcements/detail/1256913672017664045) where 2.0 means twice the number of pixel. - - **Note**: Manual Override for Super-Sampling must be checked in the SteamVR/OpenVR settings menu. + - **Note**: Manual Supersampling Override be checked. +- **Enable Manual Supersampling Override**: Enables user control of Supersampling, instead of SteamVR auto profiles. - **Enable Motion Smoothing**: Enables Motion Smoothing, and disables asynchronous reprojection. - **Restart SteamVR**: Restart SteamVR (May crash the Steam overlay when SteamVR Home is running when you restart. Therefore I advice that you close SteamVR Home before restarting). @@ -229,6 +230,7 @@ Any changes to controller settings are immediately applied by Revive (Requires R - **Steam Desktop Overlay Width:** Allows to increase the size of the Steam desktop overlay. Useful for multi-monitor setups. +- **Media Control Keys:** Allows controlling a media player through the media keys. This is the same as having a keyboard with media keys and then pressing them. Should support most common media players. ## - Accessibility Page: diff --git a/advancedSettings.pro b/advancedSettings.pro index 17c0b17..00dbaec 100644 --- a/advancedSettings.pro +++ b/advancedSettings.pro @@ -139,4 +139,5 @@ DISTFILES += \ src/res/qml/SettingsPage.qml \ src/res/qml/StatisticsPage.qml \ src/res/qml/SteamVRPage.qml \ - src/res/qml/UtilitiesPage.qml + src/res/qml/UtilitiesPage.qml \ + src/res/qml/media_keys/* diff --git a/docs/screenshots/SteamVRPage.png b/docs/screenshots/SteamVRPage.png index 53b18c6..81c835b 100644 Binary files a/docs/screenshots/SteamVRPage.png and b/docs/screenshots/SteamVRPage.png differ diff --git a/docs/screenshots/UtilitiesPage.png b/docs/screenshots/UtilitiesPage.png index 786066f..0cddbae 100644 Binary files a/docs/screenshots/UtilitiesPage.png and b/docs/screenshots/UtilitiesPage.png differ diff --git a/src/main.cpp b/src/main.cpp index 5c72d6b..65eb57a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -411,8 +411,11 @@ int main( int argc, char* argv[] ) advsettings::OverlayController controller( desktopMode, noSound, qmlEngine ); - QQmlComponent component( - &qmlEngine, QUrl::fromLocalFile( "res/qml/mainwidget.qml" ) ); + QString path = QStandardPaths::locate( + QStandardPaths::AppDataLocation, + QStringLiteral( "res/qml/mainwidget.qml" ) ); + + QQmlComponent component( &qmlEngine, QUrl::fromLocalFile( path ) ); auto errors = component.errors(); for ( auto& e : errors ) { diff --git a/src/overlaycontroller.cpp b/src/overlaycontroller.cpp index b73e465..bd85b1f 100644 --- a/src/overlaycontroller.cpp +++ b/src/overlaycontroller.cpp @@ -85,8 +85,9 @@ OverlayController::OverlayController( bool desktopMode, << focusChangedSoundFile; } - QString alarm01SoundFile = QApplication::applicationDirPath().append( - "/res/sounds/alarm01.wav" ); + QString alarm01SoundFile + = QStandardPaths::locate( QStandardPaths::AppDataLocation, + QStringLiteral( "res/sounds/alarm01.wav" ) ); QFileInfo alarm01SoundFileInfo( alarm01SoundFile ); if ( alarm01SoundFileInfo.exists() && alarm01SoundFileInfo.isFile() ) { @@ -433,13 +434,14 @@ void OverlayController::SetWidget( QQuickItem* quickItem, m_ulOverlayHandle, vr::VROverlayInputMethod_Mouse ); vr::VROverlay()->SetOverlayFlag( m_ulOverlayHandle, vr::VROverlayFlags_SendVRScrollEvents, true ); - std::string thumbIconPath - = QApplication::applicationDirPath().toStdString() - + "\\res\\thumbicon.png"; - if ( QFile::exists( QString::fromStdString( thumbIconPath ) ) ) + QString thumbIconPath + = QStandardPaths::locate( QStandardPaths::AppDataLocation, + QStringLiteral( "res/thumbicon.png" ) ); + if ( QFile::exists( thumbIconPath ) ) { - vr::VROverlay()->SetOverlayFromFile( m_ulOverlayThumbnailHandle, - thumbIconPath.c_str() ); + vr::VROverlay()->SetOverlayFromFile( + m_ulOverlayThumbnailHandle, + thumbIconPath.toStdString().c_str() ); } else { diff --git a/src/res/qml/SteamVRPage.qml b/src/res/qml/SteamVRPage.qml index 0f297c1..4119631 100644 --- a/src/res/qml/SteamVRPage.qml +++ b/src/res/qml/SteamVRPage.qml @@ -183,6 +183,7 @@ MyStackViewPage { } MyPushButton2 { + id: steamvrSupersampleDecrement text: "-" Layout.preferredWidth: 40 onClicked: { @@ -192,7 +193,7 @@ MyStackViewPage { MySlider { id: steamvrSupersamplingSlider - from: 0.1 + from: 0.2 to: 5.0 stepSize: 0.1 value: 1.0 @@ -208,6 +209,7 @@ MyStackViewPage { } MyPushButton2 { + id: steamvrSupersampleIncrement text: "+" Layout.preferredWidth: 40 onClicked: { @@ -239,6 +241,24 @@ MyStackViewPage { } } } + MyToggleButton { + id: steamvrAllowSupersampleOverrideToggle + text: "Enable Manual Supersampling Override" + onCheckedChanged: { + SteamVRTabController.setAllowSupersampleOverride(this.checked, false) + if(!this.checked){ + steamvrSupersamplingText.enabled = false + steamvrSupersamplingSlider.enabled = false + steamvrSupersampleIncrement.enabled = false + steamvrSupersampleDecrement.enabled = false + }else{ + steamvrSupersamplingText.enabled = true + steamvrSupersamplingSlider.enabled = true + steamvrSupersampleIncrement.enabled = true + steamvrSupersampleDecrement.enabled = true + } + } + } MyToggleButton { id: steamvrAllowSupersampleFilteringToggle text: "Enable Advanced Supersample Filtering" @@ -286,8 +306,16 @@ MyStackViewPage { if (s1 <= steamvrSupersamplingSlider.to) { steamvrSupersamplingSlider.value = s1 } + steamvrAllowSupersampleOverrideToggle.checked = SteamVRTabController.allowSupersampleOverride steamvrAllowSupersampleFilteringToggle.checked = SteamVRTabController.allowSupersampleFiltering steamvrMotionSmoothingToggle.checked = SteamVRTabController.motionSmoothing + if(!steamvrAllowSupersampleOverrideToggle.checked){ + steamvrSupersamplingText.enabled = false + steamvrSupersamplingSlider.enabled = false + steamvrSupersampleIncrement.enabled = false + steamvrSupersampleDecrement.enabled = false + } + reloadSteamVRProfiles() } @@ -300,6 +328,9 @@ MyStackViewPage { } steamvrSupersamplingText.text = s1 } + onAllowSupersampleOverrideChanged: { + steamvrAllowSupersampleOverrideToggle.checked = SteamVRTabController.allowSupersampleOverride + } onAllowSupersampleFilteringChanged: { steamvrAllowSupersampleFilteringToggle.checked = SteamVRTabController.allowSupersampleFiltering } diff --git a/src/res/qml/UtilitiesPage.qml b/src/res/qml/UtilitiesPage.qml index 76841cf..f085376 100644 --- a/src/res/qml/UtilitiesPage.qml +++ b/src/res/qml/UtilitiesPage.qml @@ -320,6 +320,155 @@ MyStackViewPage { } } + GroupBox { + id: mediaKeysGroupBox + Layout.fillWidth: true + + label: MyText { + leftPadding: 10 + text: "Media Control Keys" + bottomPadding: -10 + } + background: Rectangle { + color: "transparent" + border.color: "#ffffff" + radius: 8 + } + ColumnLayout { + anchors.fill: parent + + Rectangle { + color: "#ffffff" + height: 1 + Layout.fillWidth: true + Layout.bottomMargin: 5 + } + + + RowLayout { + property bool playButtonIsPlay: false + MyPushButton2 { + id: previousSongButton + Layout.preferredHeight: 48 + Layout.preferredWidth: 48 + contentItem: Image { + source: "media_keys/outline_skip_previous_white_24dp.svg" + sourceSize: Qt.size( imgSP.sourceSize.width*2, imgSP.sourceSize.height*2 ) + Image{ + id: imgSP + source: parent.source + width:0 + height:0 + } + anchors.fill: parent + } + onClicked: { + UtilitiesTabController.sendMediaPreviousSong() + } + + background: Rectangle { + opacity: parent.down ? 1.0 : (parent.activeFocus ? 0.5 : 0.0) + color: "#406288" + radius: 4 + anchors.fill: parent + } + } + MyPushButton2 { + id: stopSongButton + Layout.preferredHeight: 48 + Layout.preferredWidth: 48 + + contentItem: Image { + source: "media_keys/outline_stop_white_24dp.svg" + sourceSize: Qt.size( imgS.sourceSize.width*2, imgS.sourceSize.height*2 ) + Image{ + id: imgS + source: parent.source + width:0 + height:0 + } + anchors.fill: parent + } + onClicked: { + UtilitiesTabController.sendMediaStopSong() + playPauseSongButton.contentItem.source = "media_keys/outline_play_arrow_white_24dp.svg" + parent.playButtonIsPlay = true + } + + background: Rectangle { + opacity: parent.down ? 1.0 : (parent.activeFocus ? 0.5 : 0.0) + color: "#406288" + radius: 4 + anchors.fill: parent + } + } + MyPushButton2 { + id: playPauseSongButton + Layout.preferredHeight: 48 + Layout.preferredWidth: 48 + contentItem: Image { + // Assume that music is playing when people enter VR. + source: "media_keys/outline_pause_white_24dp.svg" + sourceSize: Qt.size( imgP.sourceSize.width*2, imgP.sourceSize.height*2 ) + Image{ + id: imgP + source: parent.source + width:0 + height:0 + } + + anchors.fill: parent + } + onClicked: { + UtilitiesTabController.sendMediaPausePlay() + if (parent.playButtonIsPlay) { + playPauseSongButton.contentItem.source = "media_keys/outline_pause_white_24dp.svg" + parent.playButtonIsPlay = false + } else { + playPauseSongButton.contentItem.source = "media_keys/outline_play_arrow_white_24dp.svg" + parent.playButtonIsPlay = true + } + + } + + background: Rectangle { + opacity: parent.down ? 1.0 : (parent.activeFocus ? 0.5 : 0.0) + color: "#406288" + radius: 4 + anchors.fill: parent + } + } + MyPushButton2 { + id: nextSongButton + Layout.preferredHeight: 48 + Layout.preferredWidth: 48 + + contentItem: Image { + source: "media_keys/outline_skip_next_white_24dp.svg" + sourceSize: Qt.size( imgSN.sourceSize.width*2, imgSN.sourceSize.height*2 ) + Image{ + id: imgSN + source: parent.source + width:0 + height:0 + } + anchors.fill: parent + } + onClicked: { + UtilitiesTabController.sendMediaNextSong() + } + + background: Rectangle { + opacity: parent.down ? 1.0 : (parent.activeFocus ? 0.5 : 0.0) + color: "#406288" + radius: 4 + anchors.fill: parent + } + } + } + } + } + Item { Layout.fillHeight: true } diff --git a/src/res/qml/media_keys/outline_pause_white_24dp.svg b/src/res/qml/media_keys/outline_pause_white_24dp.svg new file mode 100644 index 0000000..f59d7c9 --- /dev/null +++ b/src/res/qml/media_keys/outline_pause_white_24dp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/res/qml/media_keys/outline_play_arrow_white_24dp.svg b/src/res/qml/media_keys/outline_play_arrow_white_24dp.svg new file mode 100644 index 0000000..2b248b9 --- /dev/null +++ b/src/res/qml/media_keys/outline_play_arrow_white_24dp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/res/qml/media_keys/outline_skip_next_white_24dp.svg b/src/res/qml/media_keys/outline_skip_next_white_24dp.svg new file mode 100644 index 0000000..23fa6ea --- /dev/null +++ b/src/res/qml/media_keys/outline_skip_next_white_24dp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/res/qml/media_keys/outline_skip_previous_white_24dp.svg b/src/res/qml/media_keys/outline_skip_previous_white_24dp.svg new file mode 100644 index 0000000..1d08e59 --- /dev/null +++ b/src/res/qml/media_keys/outline_skip_previous_white_24dp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/res/qml/media_keys/outline_stop_white_24dp.svg b/src/res/qml/media_keys/outline_stop_white_24dp.svg new file mode 100644 index 0000000..2123cee --- /dev/null +++ b/src/res/qml/media_keys/outline_stop_white_24dp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/tabcontrollers/AudioTabController.cpp b/src/tabcontrollers/AudioTabController.cpp index dd0feb8..94e671e 100644 --- a/src/tabcontrollers/AudioTabController.cpp +++ b/src/tabcontrollers/AudioTabController.cpp @@ -70,13 +70,14 @@ void AudioTabController::initStage2( OverlayController* var_parent, notifKey.c_str(), notifKey.c_str(), &m_ulNotificationOverlayHandle ); if ( overlayError == vr::VROverlayError_None ) { - std::string notifIconPath - = QApplication::applicationDirPath().toStdString() - + "/res/qml/ptt_notification.png"; - if ( QFile::exists( QString::fromStdString( notifIconPath ) ) ) + QString notifIconPath = QStandardPaths::locate( + QStandardPaths::AppDataLocation, + QStringLiteral( "/res/qml/ptt_notification.png" ) ); + if ( QFile::exists( notifIconPath ) ) { - vr::VROverlay()->SetOverlayFromFile( m_ulNotificationOverlayHandle, - notifIconPath.c_str() ); + vr::VROverlay()->SetOverlayFromFile( + m_ulNotificationOverlayHandle, + notifIconPath.toStdString().c_str() ); vr::VROverlay()->SetOverlayWidthInMeters( m_ulNotificationOverlayHandle, 0.02f ); vr::HmdMatrix34_t notificationTransform diff --git a/src/tabcontrollers/KeyboardInput.h b/src/tabcontrollers/KeyboardInput.h index f660eb3..cb1226a 100644 --- a/src/tabcontrollers/KeyboardInput.h +++ b/src/tabcontrollers/KeyboardInput.h @@ -15,8 +15,12 @@ public: virtual void sendKeyboardInput( QString input ) = 0; virtual void sendKeyboardEnter() = 0; - virtual void sendKeyboardBackspace( int count ) = 0; + virtual void sendKeyboardBackspace( const int count ) = 0; virtual void sendKeyboardAltTab() = 0; + virtual void sendMediaNextSong() = 0; + virtual void sendMediaPreviousSong() = 0; + virtual void sendMediaPausePlay() = 0; + virtual void sendMediaStopSong() = 0; }; } // namespace advsettings diff --git a/src/tabcontrollers/SteamVRTabController.cpp b/src/tabcontrollers/SteamVRTabController.cpp index 67065bf..16dfbd5 100644 --- a/src/tabcontrollers/SteamVRTabController.cpp +++ b/src/tabcontrollers/SteamVRTabController.cpp @@ -8,6 +8,7 @@ namespace advsettings void SteamVRTabController::initStage1() { initMotionSmoothing(); + initSupersampleOverride(); eventLoopTick(); reloadSteamVRProfiles(); } @@ -19,106 +20,26 @@ void SteamVRTabController::initStage2( OverlayController* var_parent, this->widget = var_widget; } -void SteamVRTabController::reloadSteamVRProfiles() -{ - steamvrProfiles.clear(); - auto settings = OverlayController::appSettings(); - settings->beginGroup( "steamVRSettings" ); - auto profileCount = settings->beginReadArray( "steamVRProfiles" ); - for ( int i = 0; i < profileCount; i++ ) - { - settings->setArrayIndex( i ); - steamvrProfiles.emplace_back(); - auto& entry = steamvrProfiles[i]; - entry.profileName - = settings->value( "profileName" ).toString().toStdString(); - entry.includesSupersampling - = settings->value( "includesSupersampling", false ).toBool(); - if ( entry.includesSupersampling ) - { - entry.supersampling - = settings->value( "supersampling", 1.0f ).toFloat(); - } - entry.includesSupersampleFiltering - = settings->value( "includesSupersampleFiltering", false ).toBool(); - if ( entry.includesSupersampleFiltering ) - { - entry.supersampleFiltering - = settings->value( "supersampleFiltering", true ).toBool(); - } - entry.includesMotionSmoothing - = settings->value( "includesMotionSmoothing", false ).toBool(); - if ( entry.includesMotionSmoothing ) - { - entry.motionSmooth - = settings->value( "motionSmooth", true ).toBool(); - } - } - settings->endArray(); - settings->endGroup(); -} - -void SteamVRTabController::saveSteamVRProfiles() -{ - auto settings = OverlayController::appSettings(); - settings->beginGroup( "steamVRSettings" ); - settings->beginWriteArray( "steamVRProfiles" ); - unsigned i = 0; - for ( auto& p : steamvrProfiles ) - { - settings->setArrayIndex( i ); - settings->setValue( "profileName", - QString::fromStdString( p.profileName ) ); - settings->setValue( "includesSupersampling", p.includesSupersampling ); - if ( p.includesSupersampling ) - { - settings->setValue( "supersampling", p.supersampling ); - } - settings->setValue( "includesSupersampleFiltering", - p.includesSupersampleFiltering ); - if ( p.includesSupersampleFiltering ) - { - settings->setValue( "supersampleFiltering", - p.supersampleFiltering ); - } - settings->setValue( "includesMotionSmoothing", - p.includesMotionSmoothing ); - if ( p.includesMotionSmoothing ) - { - settings->setValue( "motionSmooth", p.motionSmooth ); - } - - i++; - } - settings->endArray(); - settings->endGroup(); -} - -Q_INVOKABLE unsigned SteamVRTabController::getSteamVRProfileCount() -{ - return ( unsigned ) steamvrProfiles.size(); -} - -Q_INVOKABLE QString - SteamVRTabController::getSteamVRProfileName( unsigned index ) -{ - if ( index >= steamvrProfiles.size() ) - { - return QString(); - } - else - { - return QString::fromStdString( steamvrProfiles[index].profileName ); - } -} -// TODO DISC does it make any sense to check these settings once every ~ -// 1second. primary purpose seems to be to re-sync settings if changed via other -// means? void SteamVRTabController::eventLoopTick() { if ( settingsUpdateCounter >= 50 ) { vr::EVRSettingsError vrSettingsError; + // checks supersampling override and resynchs if necessry + // also prints error if can't find. + auto sso = vr::VRSettings()->GetBool( + vr::k_pch_SteamVR_Section, + vr::k_pch_SteamVR_SupersampleManualOverride_Bool, + &vrSettingsError ); + if ( vrSettingsError != vr::VRSettingsError_None ) + { + LOG( WARNING ) << "Could not read \"" + << vr::k_pch_SteamVR_SupersampleManualOverride_Bool + << "\" setting: " + << vr::VRSettings()->GetSettingsErrorNameFromEnum( + vrSettingsError ); + } + setAllowSupersampleOverride( sso ); // checks supersampling and re-synchs if necessary auto ss = vr::VRSettings()->GetFloat( vr::k_pch_SteamVR_Section, @@ -185,10 +106,192 @@ void SteamVRTabController::eventLoopTick() } } -void SteamVRTabController::setSuperSampling( float value, bool notify ) +/* -----------------------------------------*/ +/*------------------------------------------*/ +/*Profile Logic Functions*/ + +void SteamVRTabController::addSteamVRProfile( + const QString name, + const bool includeSupersampling, + const bool includeSupersampleFiltering, + const bool includeMotionSmoothing ) +{ + SteamVRProfile* profile = nullptr; + for ( auto& p : steamvrProfiles ) + { + if ( p.profileName.compare( name.toStdString() ) == 0 ) + { + profile = &p; + break; + } + } + if ( !profile ) + { + auto i = steamvrProfiles.size(); + steamvrProfiles.emplace_back(); + profile = &steamvrProfiles[i]; + } + profile->profileName = name.toStdString(); + profile->includesSupersampling = includeSupersampling; + if ( includeSupersampling ) + { + profile->supersampleOverride = m_allowSupersampleOverride; + profile->supersampling = m_superSampling; + } + profile->includesSupersampleFiltering = includeSupersampleFiltering; + if ( includeSupersampleFiltering ) + { + profile->supersampleFiltering = m_allowSupersampleFiltering; + } + profile->includesMotionSmoothing = includeMotionSmoothing; + if ( includeMotionSmoothing ) + { + profile->motionSmooth = m_motionSmoothing; + } + saveSteamVRProfiles(); + OverlayController::appSettings()->sync(); + emit steamVRProfilesUpdated(); + emit steamVRProfileAdded(); +} + +void SteamVRTabController::applySteamVRProfile( const unsigned index ) +{ + if ( index < steamvrProfiles.size() ) + { + auto& profile = steamvrProfiles[index]; + if ( profile.includesSupersampling ) + { + setAllowSupersampleOverride( profile.supersampleOverride ); + setSuperSampling( profile.supersampling ); + } + if ( profile.includesSupersampleFiltering ) + { + setAllowSupersampleFiltering( profile.supersampleFiltering ); + } + if ( profile.includesMotionSmoothing ) + { + setMotionSmoothing( profile.motionSmooth ); + } + vr::VRSettings()->Sync( true ); + } +} + +void SteamVRTabController::deleteSteamVRProfile( const unsigned index ) +{ + if ( index < steamvrProfiles.size() ) + { + auto pos = steamvrProfiles.begin() + index; + steamvrProfiles.erase( pos ); + saveSteamVRProfiles(); + OverlayController::appSettings()->sync(); + emit steamVRProfilesUpdated(); + } +} + +void SteamVRTabController::reloadSteamVRProfiles() +{ + steamvrProfiles.clear(); + auto settings = OverlayController::appSettings(); + settings->beginGroup( "steamVRSettings" ); + auto profileCount = settings->beginReadArray( "steamVRProfiles" ); + for ( int i = 0; i < profileCount; i++ ) + { + settings->setArrayIndex( i ); + steamvrProfiles.emplace_back(); + auto& entry = steamvrProfiles[i]; + entry.profileName + = settings->value( "profileName" ).toString().toStdString(); + entry.includesSupersampling + = settings->value( "includesSupersampling", false ).toBool(); + if ( entry.includesSupersampling ) + { + entry.supersampleOverride + = settings->value( "supersamplingOverride", false ).toBool(); + entry.supersampling + = settings->value( "supersampling", 1.0f ).toFloat(); + } + entry.includesSupersampleFiltering + = settings->value( "includesSupersampleFiltering", false ).toBool(); + if ( entry.includesSupersampleFiltering ) + { + entry.supersampleFiltering + = settings->value( "supersampleFiltering", true ).toBool(); + } + entry.includesMotionSmoothing + = settings->value( "includesMotionSmoothing", false ).toBool(); + if ( entry.includesMotionSmoothing ) + { + entry.motionSmooth + = settings->value( "motionSmooth", true ).toBool(); + } + } + settings->endArray(); + settings->endGroup(); +} + +void SteamVRTabController::saveSteamVRProfiles() +{ + auto settings = OverlayController::appSettings(); + settings->beginGroup( "steamVRSettings" ); + settings->beginWriteArray( "steamVRProfiles" ); + unsigned i = 0; + for ( auto& p : steamvrProfiles ) + { + settings->setArrayIndex( i ); + settings->setValue( "profileName", + QString::fromStdString( p.profileName ) ); + settings->setValue( "includesSupersampling", p.includesSupersampling ); + if ( p.includesSupersampling ) + { + settings->setValue( "supersamplingOverride", + p.supersampleOverride ); + settings->setValue( "supersampling", p.supersampling ); + } + settings->setValue( "includesSupersampleFiltering", + p.includesSupersampleFiltering ); + if ( p.includesSupersampleFiltering ) + { + settings->setValue( "supersampleFiltering", + p.supersampleFiltering ); + } + settings->setValue( "includesMotionSmoothing", + p.includesMotionSmoothing ); + if ( p.includesMotionSmoothing ) + { + settings->setValue( "motionSmooth", p.motionSmooth ); + } + + i++; + } + settings->endArray(); + settings->endGroup(); +} +int SteamVRTabController::getSteamVRProfileCount() +{ + return static_cast( steamvrProfiles.size() ); +} + +QString SteamVRTabController::getSteamVRProfileName( const unsigned index ) +{ + if ( index >= steamvrProfiles.size() ) + { + return QString(); + } + else + { + return QString::fromStdString( steamvrProfiles[index].profileName ); + } +} + +/* -----------------------------------------*/ +/*------------------------------------------*/ +/*SuperSample (value) functions*/ + +void SteamVRTabController::setSuperSampling( float value, const bool notify ) { bool override = false; - if ( value <= 0.01f ) + // Mirrors Desktop Clamp + if ( value <= 0.2f ) { LOG( WARNING ) << "Encountered a supersampling value <= 0.01, setting " "supersampling to 1.0"; @@ -215,26 +318,16 @@ float SteamVRTabController::superSampling() const { return m_superSampling; } - +/* -----------------------------------------*/ +/*------------------------------------------*/ +/*Motion Smoothing boolean/toggle functions*/ bool SteamVRTabController::motionSmoothing() const { return m_motionSmoothing; } -/* -Name: setMotionSmoothing - -input: bool value, bool notify -output: none - -@value - value to be passed to m_motionSMoothing -@notify - whether QML is informed of change (default true) - -Description: -sets value of m_motionSmoothing AND applies changes in Steam/OpenVr -*/ - -void SteamVRTabController::setMotionSmoothing( bool value, bool notify ) +void SteamVRTabController::setMotionSmoothing( const bool value, + const bool notify ) { if ( m_motionSmoothing != value ) { @@ -250,21 +343,6 @@ void SteamVRTabController::setMotionSmoothing( bool value, bool notify ) } } -/* -Name: initMotionSmoothing - -input: none -output: none - -description: Gets the Value of Motion Smoothing from Steam/OpenVR. -Sets the member variable of motion smoothing for UI -Adds error to log if unable to find variable. - -OnError: -default value of true for motion smoothing is initialized, if user has disabled -motion smoothing on their end, they will have to toggle the variable twice to -get it to re-sync. -*/ void SteamVRTabController::initMotionSmoothing() { bool temporary = false; @@ -285,13 +363,17 @@ void SteamVRTabController::initMotionSmoothing() setMotionSmoothing( temporary, true ); } +/* -----------------------------------------*/ +/*------------------------------------------*/ +/*Supersample Filtering boolean/toggle functions*/ + bool SteamVRTabController::allowSupersampleFiltering() const { return m_allowSupersampleFiltering; } -void SteamVRTabController::setAllowSupersampleFiltering( bool value, - bool notify ) +void SteamVRTabController::setAllowSupersampleFiltering( const bool value, + const bool notify ) { if ( m_allowSupersampleFiltering != value ) { @@ -309,6 +391,56 @@ void SteamVRTabController::setAllowSupersampleFiltering( bool value, } } +/* -----------------------------------------*/ +/*------------------------------------------*/ +/*SuperSampling Override boolean/toggle functions*/ + +bool SteamVRTabController::allowSupersampleOverride() const +{ + return m_allowSupersampleOverride; +} + +void SteamVRTabController::setAllowSupersampleOverride( const bool value, + const bool notify ) +{ + if ( m_allowSupersampleOverride != value ) + { + m_allowSupersampleOverride = value; + vr::VRSettings()->SetBool( + vr::k_pch_SteamVR_Section, + vr::k_pch_SteamVR_SupersampleManualOverride_Bool, + m_allowSupersampleOverride ); + vr::VRSettings()->Sync(); + if ( notify ) + { + emit allowSupersampleOverrideChanged( m_allowSupersampleOverride ); + } + } +} + +void SteamVRTabController::initSupersampleOverride() +{ + bool temporary = false; + vr::EVRSettingsError vrSettingsError; + temporary = vr::VRSettings()->GetBool( + vr::k_pch_SteamVR_Section, + vr::k_pch_SteamVR_SupersampleManualOverride_Bool, + &vrSettingsError ); + if ( vrSettingsError != vr::VRSettingsError_None ) + { + LOG( WARNING ) << "Could not get SuperSampling Override State \"" + << vr::k_pch_SteamVR_SupersampleManualOverride_Bool + << "\" setting: " + << vr::VRSettings()->GetSettingsErrorNameFromEnum( + vrSettingsError ); + } + vr::VRSettings()->Sync(); + setAllowSupersampleOverride( temporary, true ); +} + +/*------------------------------------------*/ +/* -----------------------------------------*/ + void SteamVRTabController::reset() { vr::EVRSettingsError vrSettingsError; @@ -339,6 +471,45 @@ void SteamVRTabController::reset() vrSettingsError ); } + vr::VRSettings()->RemoveKeyInSection( + vr::k_pch_SteamVR_Section, + vr::k_pch_SteamVR_SupersampleManualOverride_Bool, + &vrSettingsError ); + if ( vrSettingsError != vr::VRSettingsError_None ) + { + LOG( WARNING ) << "Could not remove \"" + << vr::k_pch_SteamVR_SupersampleManualOverride_Bool + << "\" setting: " + << vr::VRSettings()->GetSettingsErrorNameFromEnum( + vrSettingsError ); + } + + vr::VRSettings()->RemoveKeyInSection( + vr::k_pch_SteamVR_Section, + vr::k_pch_SteamVR_SupersampleScale_Float, + &vrSettingsError ); + if ( vrSettingsError != vr::VRSettingsError_None ) + { + LOG( WARNING ) << "Could not remove \"" + << vr::k_pch_SteamVR_SupersampleScale_Float + << "\" setting: " + << vr::VRSettings()->GetSettingsErrorNameFromEnum( + vrSettingsError ); + } + + vr::VRSettings()->RemoveKeyInSection( + vr::k_pch_SteamVR_Section, + vr::k_pch_SteamVR_MotionSmoothing_Bool, + &vrSettingsError ); + if ( vrSettingsError != vr::VRSettingsError_None ) + { + LOG( WARNING ) << "Could not remove \"" + << vr::k_pch_SteamVR_MotionSmoothing_Bool + << "\" setting: " + << vr::VRSettings()->GetSettingsErrorNameFromEnum( + vrSettingsError ); + } + vr::VRSettings()->Sync(); settingsUpdateCounter = 999; // Easiest way to get default values } @@ -352,79 +523,4 @@ void SteamVRTabController::restartSteamVR() QProcess::startDetached( cmd ); } -void SteamVRTabController::addSteamVRProfile( QString name, - bool includeSupersampling, - bool includeSupersampleFiltering, - bool includeMotionSmoothing ) -{ - SteamVRProfile* profile = nullptr; - for ( auto& p : steamvrProfiles ) - { - if ( p.profileName.compare( name.toStdString() ) == 0 ) - { - profile = &p; - break; - } - } - if ( !profile ) - { - auto i = steamvrProfiles.size(); - steamvrProfiles.emplace_back(); - profile = &steamvrProfiles[i]; - } - profile->profileName = name.toStdString(); - profile->includesSupersampling = includeSupersampling; - if ( includeSupersampling ) - { - profile->supersampling = m_superSampling; - } - profile->includesSupersampleFiltering = includeSupersampleFiltering; - if ( includeSupersampleFiltering ) - { - profile->supersampleFiltering = m_allowSupersampleFiltering; - } - profile->includesMotionSmoothing = includeMotionSmoothing; - if ( includeMotionSmoothing ) - { - profile->motionSmooth = m_motionSmoothing; - } - saveSteamVRProfiles(); - OverlayController::appSettings()->sync(); - emit steamVRProfilesUpdated(); - emit steamVRProfileAdded(); -} - -void SteamVRTabController::applySteamVRProfile( unsigned index ) -{ - if ( index < steamvrProfiles.size() ) - { - auto& profile = steamvrProfiles[index]; - if ( profile.includesSupersampling ) - { - setSuperSampling( profile.supersampling ); - } - if ( profile.includesSupersampleFiltering ) - { - setAllowSupersampleFiltering( profile.supersampleFiltering ); - } - if ( profile.includesMotionSmoothing ) - { - setMotionSmoothing( profile.motionSmooth ); - } - vr::VRSettings()->Sync( true ); - } -} - -void SteamVRTabController::deleteSteamVRProfile( unsigned index ) -{ - if ( index < steamvrProfiles.size() ) - { - auto pos = steamvrProfiles.begin() + index; - steamvrProfiles.erase( pos ); - saveSteamVRProfiles(); - OverlayController::appSettings()->sync(); - emit steamVRProfilesUpdated(); - } -} - } // namespace advsettings diff --git a/src/tabcontrollers/SteamVRTabController.h b/src/tabcontrollers/SteamVRTabController.h index a6c2220..1974bc6 100644 --- a/src/tabcontrollers/SteamVRTabController.h +++ b/src/tabcontrollers/SteamVRTabController.h @@ -21,6 +21,7 @@ struct SteamVRProfile bool supersampleFiltering = false; bool motionSmooth = false; bool includesMotionSmoothing = false; + bool supersampleOverride = false; }; class SteamVRTabController : public QObject @@ -28,27 +29,27 @@ class SteamVRTabController : public QObject Q_OBJECT Q_PROPERTY( float superSampling READ superSampling WRITE setSuperSampling NOTIFY superSamplingChanged ) - /*Q_PROPERTY( - float compositorSuperSampling READ compositorSuperSampling WRITE - setCompositorSuperSampling NOTIFY compositorSuperSamplingChanged ) - */ Q_PROPERTY( bool motionSmoothing READ motionSmoothing WRITE setMotionSmoothing NOTIFY motionSmoothingChanged ) Q_PROPERTY( bool allowSupersampleFiltering READ allowSupersampleFiltering WRITE setAllowSupersampleFiltering NOTIFY allowSupersampleFilteringChanged ) + Q_PROPERTY( + bool allowSupersampleOverride READ allowSupersampleOverride WRITE + setAllowSupersampleOverride NOTIFY allowSupersampleOverrideChanged ) private: OverlayController* parent; QQuickWindow* widget; float m_superSampling = 1.0; - // float m_compositorSuperSampling = 1.0; bool m_motionSmoothing = true; bool m_allowSupersampleFiltering = true; + bool m_allowSupersampleOverride = false; void initMotionSmoothing(); + void initSupersampleOverride(); std::vector steamvrProfiles; @@ -61,21 +62,21 @@ public: void eventLoopTick(); float superSampling() const; - // float compositorSuperSampling() const; bool motionSmoothing() const; bool allowSupersampleFiltering() const; + bool allowSupersampleOverride() const; void reloadSteamVRProfiles(); void saveSteamVRProfiles(); - Q_INVOKABLE unsigned getSteamVRProfileCount(); + Q_INVOKABLE int getSteamVRProfileCount(); Q_INVOKABLE QString getSteamVRProfileName( unsigned index ); public slots: void setSuperSampling( float value, bool notify = true ); - // void setCompositorSuperSampling( float value, bool notify = true ); void setMotionSmoothing( bool value, bool notify = true ); void setAllowSupersampleFiltering( bool value, bool notify = true ); + void setAllowSupersampleOverride( bool value, bool notify = true ); void addSteamVRProfile( QString name, bool includeSupersampling, @@ -89,9 +90,9 @@ public slots: signals: void superSamplingChanged( float value ); - // void compositorSuperSamplingChanged( float value ); void motionSmoothingChanged( bool value ); void allowSupersampleFilteringChanged( bool value ); + void allowSupersampleOverrideChanged( bool value ); void steamVRProfilesUpdated(); void steamVRProfileAdded(); diff --git a/src/tabcontrollers/UtilitiesTabController.cpp b/src/tabcontrollers/UtilitiesTabController.cpp index 0684b46..948492e 100644 --- a/src/tabcontrollers/UtilitiesTabController.cpp +++ b/src/tabcontrollers/UtilitiesTabController.cpp @@ -83,11 +83,28 @@ void UtilitiesTabController::sendKeyboardAltTab() keyboardInput->sendKeyboardAltTab(); } -void UtilitiesTabController::sendKeyboardBackspace( int count ) +void UtilitiesTabController::sendKeyboardBackspace( const int count ) { keyboardInput->sendKeyboardBackspace( count ); } +void UtilitiesTabController::sendMediaNextSong() +{ + keyboardInput->sendMediaNextSong(); +} +void UtilitiesTabController::sendMediaPreviousSong() +{ + keyboardInput->sendMediaPreviousSong(); +} +void UtilitiesTabController::sendMediaPausePlay() +{ + keyboardInput->sendMediaPausePlay(); +} +void UtilitiesTabController::sendMediaStopSong() +{ + keyboardInput->sendMediaStopSong(); +} + bool UtilitiesTabController::alarmEnabled() const { return m_alarmEnabled; @@ -250,6 +267,14 @@ void UtilitiesTabController::modAlarmTimeMinute( int value, bool notify ) } } +QString getBatteryIconPath( int batteryState ) +{ + QString batteryPrefix = "/res/battery_"; + return QStandardPaths::locate( + QStandardPaths::AppDataLocation, + batteryPrefix + QString::number( batteryState ) + ".png" ); +} + vr::VROverlayHandle_t createBatteryOverlay( vr::TrackedDeviceIndex_t index ) { vr::VROverlayHandle_t handle = vr::k_ulOverlayHandleInvalid; @@ -259,13 +284,11 @@ vr::VROverlayHandle_t createBatteryOverlay( vr::TrackedDeviceIndex_t index ) batteryKey.c_str(), batteryKey.c_str(), &handle ); if ( overlayError == vr::VROverlayError_None ) { - std::string batteryIconPath - = QApplication::applicationDirPath().toStdString() - + "/res/battery_0.png"; - if ( QFile::exists( QString::fromStdString( batteryIconPath ) ) ) + QString batteryIconPath = getBatteryIconPath( 0 ); + if ( QFile::exists( batteryIconPath ) ) { - vr::VROverlay()->SetOverlayFromFile( handle, - batteryIconPath.c_str() ); + vr::VROverlay()->SetOverlayFromFile( + handle, batteryIconPath.toStdString().c_str() ); vr::VROverlay()->SetOverlayWidthInMeters( handle, 0.05f ); vr::HmdMatrix34_t notificationTransform = { { { 1.0f, 0.0f, 0.0f, 0.00f }, @@ -469,8 +492,7 @@ void UtilitiesTabController::eventLoopTick() if ( deviceClass == vr::ETrackedDeviceClass::TrackedDeviceClass_GenericTracker ) { - if ( m_batteryOverlayHandles[i] - == vr::k_ulOverlayHandleInvalid ) + if ( m_batteryOverlayHandles[i] == 0 ) { LOG( INFO ) << "Creating battery overlay for device " << i; m_batteryOverlayHandles[i] = createBatteryOverlay( i ); @@ -512,17 +534,15 @@ void UtilitiesTabController::eventLoopTick() { LOG( INFO ) << "Updating battery overlay for device " << i - << " to " << batteryState << "(" << battery << ""; - std::string batteryIconPath - = QApplication::applicationDirPath().toStdString() - + "/res/battery_" + std::to_string( batteryState ) - + ".png"; - if ( QFile::exists( - QString::fromStdString( batteryIconPath ) ) ) + << " to " << batteryState << "(" << battery << ")" + << QString::number( m_batteryOverlayHandles[i] ); + QString batteryIconPath + = getBatteryIconPath( batteryState ); + if ( QFile::exists( batteryIconPath ) ) { vr::VROverlay()->SetOverlayFromFile( m_batteryOverlayHandles[i], - batteryIconPath.c_str() ); + batteryIconPath.toStdString().c_str() ); } else { diff --git a/src/tabcontrollers/UtilitiesTabController.h b/src/tabcontrollers/UtilitiesTabController.h index 375e2e4..d73f8e8 100644 --- a/src/tabcontrollers/UtilitiesTabController.h +++ b/src/tabcontrollers/UtilitiesTabController.h @@ -44,8 +44,8 @@ private: QTime m_alarmLastCheckTime; bool m_steamDesktopOverlayAvailable = false; float m_steamDesktopOverlayWidth = 4.0f; - vr::VROverlayHandle_t - m_batteryOverlayHandles[vr::k_unMaxTrackedDeviceCount]; + vr::VROverlayHandle_t m_batteryOverlayHandles[vr::k_unMaxTrackedDeviceCount] + = { 0 }; int m_batteryState[vr::k_unMaxTrackedDeviceCount]; bool m_batteryVisible[vr::k_unMaxTrackedDeviceCount]; @@ -69,7 +69,11 @@ public slots: void sendKeyboardInput( QString input ); void sendKeyboardEnter(); void sendKeyboardAltTab(); - void sendKeyboardBackspace( int count ); + void sendKeyboardBackspace( const int count ); + void sendMediaNextSong(); + void sendMediaPreviousSong(); + void sendMediaPausePlay(); + void sendMediaStopSong(); void setAlarmEnabled( bool enabled, bool notify = true ); void setAlarmIsModal( bool modal, bool notify = true ); diff --git a/src/tabcontrollers/keyboardinput/KeyboardInputDummy.cpp b/src/tabcontrollers/keyboardinput/KeyboardInputDummy.cpp index 4bb4aea..f9b78c8 100644 --- a/src/tabcontrollers/keyboardinput/KeyboardInputDummy.cpp +++ b/src/tabcontrollers/keyboardinput/KeyboardInputDummy.cpp @@ -17,7 +17,7 @@ void KeyboardInputDummy::sendKeyboardEnter() // noop } -void KeyboardInputDummy::sendKeyboardBackspace( int count ) +void KeyboardInputDummy::sendKeyboardBackspace( const int count ) { // noop UNREFERENCED_PARAMETER( count ); @@ -28,4 +28,24 @@ void KeyboardInputDummy::sendKeyboardAltTab() // noop } +void KeyboardInputDummy::sendMediaNextSong() +{ + // noop +} + +void KeyboardInputDummy::sendMediaPreviousSong() +{ + // noop +} + +void KeyboardInputDummy::sendMediaPausePlay() +{ + // noop +} + +void KeyboardInputDummy::sendMediaStopSong() +{ + // noop +} + } // namespace advsettings diff --git a/src/tabcontrollers/keyboardinput/KeyboardInputDummy.h b/src/tabcontrollers/keyboardinput/KeyboardInputDummy.h index 66e5fa5..cf63f1f 100644 --- a/src/tabcontrollers/keyboardinput/KeyboardInputDummy.h +++ b/src/tabcontrollers/keyboardinput/KeyboardInputDummy.h @@ -11,8 +11,12 @@ class KeyboardInputDummy : public KeyboardInput public: virtual void sendKeyboardInput( QString input ) override; virtual void sendKeyboardEnter() override; - virtual void sendKeyboardBackspace( int count ) override; + virtual void sendKeyboardBackspace( const int count ) override; virtual void sendKeyboardAltTab() override; + virtual void sendMediaNextSong() override; + virtual void sendMediaPreviousSong() override; + virtual void sendMediaPausePlay() override; + virtual void sendMediaStopSong() override; }; } // namespace advsettings diff --git a/src/tabcontrollers/keyboardinput/KeyboardInputWindows.cpp b/src/tabcontrollers/keyboardinput/KeyboardInputWindows.cpp index 9ae37ac..8e5a84a 100644 --- a/src/tabcontrollers/keyboardinput/KeyboardInputWindows.cpp +++ b/src/tabcontrollers/keyboardinput/KeyboardInputWindows.cpp @@ -4,6 +4,20 @@ namespace advsettings { +/*! +Represents the state of a keyboard button press. Can be either Up or Down. + +Implemented because neither Qt nor Windows.h included a sensible key state enum. +*/ +enum class KeyStatus +{ + Up, + Down, +}; + +/*! +Fills out an INPUT struct ip with scanCode and keyup status. +*/ void fillKiStruct( INPUT& ip, WORD scanCode, bool keyup ) { ip.type = INPUT_KEYBOARD; @@ -21,11 +35,18 @@ void fillKiStruct( INPUT& ip, WORD scanCode, bool keyup ) ip.ki.time = 0; }; -void sendKeyboardInputRaw( int inputCount, LPINPUT input ) +/*! +Calls SendInput on an INPUT struct and has associated error handling. + +inputCount can't be deduced from input because of implicit conversions from +arrays to pointers when passed as arguments. +*/ +void sendKeyboardInputRaw( const int inputCount, const LPINPUT input ) { - if ( ( inputCount > 0 ) - && !SendInput( - static_cast( inputCount ), input, sizeof( INPUT ) ) ) + const auto success + = SendInput( static_cast( inputCount ), input, sizeof( INPUT ) ); + + if ( ( inputCount > 0 ) && !success ) { char* err; auto errCode = GetLastError(); @@ -50,6 +71,62 @@ void sendKeyboardInputRaw( int inputCount, LPINPUT input ) } } +/*! +Returns an INPUT struct with the corresponding virtualKeyCode and keyStatus set. + +All fields except ki.wVk and ki.dwFlags are zero. +The INPUT struct is used with the SendInput Windows function. +Official Docs: +https://docs.microsoft.com/en-us/windows/desktop/api/winuser/ns-winuser-taginput +*/ +INPUT createInputStruct( const WORD virtualKeyCode, const KeyStatus keyStatus ) +{ + // Zero init to ensure random data doesn't muck something up. + INPUT input = {}; + + input.type = INPUT_KEYBOARD; + + input.ki.wVk = virtualKeyCode; + + if ( keyStatus == KeyStatus::Up ) + { + input.ki.dwFlags = KEYEVENTF_KEYUP; + } + else if ( keyStatus == KeyStatus::Down ) + { + // Struct is already zero initialized, but this is here for clarity. + // Compiler will likely sort this out, otherwise the performance hit is + // negligible. + // There is no corresponding KEYDOWN event, you just don't + // set KEYEVENTF_KEYUP. + input.ki.dwFlags = 0; + } + + // The sizeof(INPUT) on MSVC is 28. Returning by value is a non-issue + // compared to the simplicity of not having to pass a ref to an already + // existing INPUT struct, and possibly forgetting to zero it out. + return input; +} + +/*! +Sends a key press to Windows. The virtualKeyCode is a Windows specific define +found in . + +Virtual Key Codes offical docs: +https://docs.microsoft.com/en-us/windows/desktop/inputdev/virtual-key-codes +*/ +void sendKeyPressAndRelease( const WORD virtualKeyCode ) +{ + const auto press = createInputStruct( virtualKeyCode, KeyStatus::Down ); + const auto release = createInputStruct( virtualKeyCode, KeyStatus::Up ); + + constexpr auto numberOfActions = 2; + + INPUT actions[numberOfActions] = { press, release }; + + sendKeyboardInputRaw( numberOfActions, actions ); +} + void KeyboardInputWindows::sendKeyboardInput( QString input ) { int len = input.length(); @@ -122,44 +199,85 @@ void KeyboardInputWindows::sendKeyboardInput( QString input ) } } +/*! +Sends a single Enter keypress to Windows. +*/ void KeyboardInputWindows::sendKeyboardEnter() { - LPINPUT ips = new INPUT[2]; - fillKiStruct( ips[0], VK_RETURN, false ); - fillKiStruct( ips[1], VK_RETURN, true ); - - sendKeyboardInputRaw( 2, ips ); - delete[] ips; + sendKeyPressAndRelease( VK_RETURN ); } -void KeyboardInputWindows::sendKeyboardBackspace( int count ) +/*! +Sends count amount of backspaces to Windows. count of 0 or below will do +nothing. +*/ +void KeyboardInputWindows::sendKeyboardBackspace( const int count ) { - if ( count > 0 ) + // We can only send a positive amount of key presses. + if ( count <= 0 ) { - // We ensure that count is nonnegative, therefore safe cast. - LPINPUT ips = new INPUT[static_cast( count ) * 2]; - for ( int i = 0; i < count; i++ ) - { - fillKiStruct( ips[2 * i], VK_BACK, false ); - fillKiStruct( ips[2 * i + 1], VK_BACK, true ); - } + return; + } - sendKeyboardInputRaw( count * 2, ips ); - delete[] ips; + for ( int presses = 0; presses < count; ++presses ) + { + sendKeyPressAndRelease( VK_BACK ); } } +/*! +Sends an Alt + Tab combination to Windows. + +Used for tabbing out of game windows blocking other programs on desktop while in +VR. At least one use case was tabbing out of a fullscreen game to be able to use +a music player. +*/ void KeyboardInputWindows::sendKeyboardAltTab() { - LPINPUT ips = new INPUT[4]; - // VK_MENU is alt - fillKiStruct( ips[0], VK_MENU, false ); - fillKiStruct( ips[1], VK_TAB, false ); - fillKiStruct( ips[2], VK_TAB, true ); - fillKiStruct( ips[3], VK_MENU, true ); + // VK_MENU is Alt. + const auto pressAlt = createInputStruct( VK_MENU, KeyStatus::Down ); + const auto pressTab = createInputStruct( VK_TAB, KeyStatus::Down ); + const auto releaseAlt = createInputStruct( VK_MENU, KeyStatus::Up ); + const auto releaseTab = createInputStruct( VK_TAB, KeyStatus::Up ); - sendKeyboardInputRaw( 4, ips ); - delete[] ips; + constexpr auto numberOfActions = 4; + + INPUT actions[numberOfActions] + = { pressAlt, pressTab, releaseAlt, releaseTab }; + + sendKeyboardInputRaw( numberOfActions, actions ); +} + +/*! +Sends a media key Next Song button to Windows. +*/ +void KeyboardInputWindows::sendMediaNextSong() +{ + sendKeyPressAndRelease( VK_MEDIA_NEXT_TRACK ); +} + +/*! +Sends a media key Previous Song button to Windows. +*/ +void KeyboardInputWindows::sendMediaPreviousSong() +{ + sendKeyPressAndRelease( VK_MEDIA_PREV_TRACK ); +} + +/*! +Sends a media key Play/Pause button to Windows. +*/ +void KeyboardInputWindows::sendMediaPausePlay() +{ + sendKeyPressAndRelease( VK_MEDIA_PLAY_PAUSE ); +} + +/*! +Sends a media key Stop button to Windows. +*/ +void KeyboardInputWindows::sendMediaStopSong() +{ + sendKeyPressAndRelease( VK_MEDIA_STOP ); } } // namespace advsettings diff --git a/src/tabcontrollers/keyboardinput/KeyboardInputWindows.h b/src/tabcontrollers/keyboardinput/KeyboardInputWindows.h index e376703..12ceb44 100644 --- a/src/tabcontrollers/keyboardinput/KeyboardInputWindows.h +++ b/src/tabcontrollers/keyboardinput/KeyboardInputWindows.h @@ -11,8 +11,12 @@ class KeyboardInputWindows : public KeyboardInput public: virtual void sendKeyboardInput( QString input ) override; virtual void sendKeyboardEnter() override; - virtual void sendKeyboardBackspace( int count ) override; + virtual void sendKeyboardBackspace( const int count ) override; virtual void sendKeyboardAltTab() override; + virtual void sendMediaNextSong() override; + virtual void sendMediaPreviousSong() override; + virtual void sendMediaPausePlay() override; + virtual void sendMediaStopSong() override; }; } // namespace advsettings