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