diff --git a/Readme.md b/Readme.md index 989b8ba..05276c4 100644 --- a/Readme.md +++ b/Readme.md @@ -187,6 +187,7 @@ Override actions will take priority over non-override actions during simultaneou | Gravity Toggle | Binary/Button | Toggles Gravity state when pressed. | | Gravity Reverse | Binary/Button | Temporarily Reverses Gravity while held. | | Reset Offsets | Binary/Button | Resets your offset and rotation to 0. | +| Apply Offsets | Binary/Button | Recalibrates center/rotation from offsets | | Height Toggle | Binary/Button | Shifts the gravity floor level by offset configured in motion tab. If gravity is inactive: also shifts the user's current y-axis position by offset configured in motion tab. | | Snap-Turn Left | Binary/Button | Rotates a set value to the left based on settings in motion tab. | | Snap-Turn Right | Binary/Button | Rotates a set value to the right based on settings in motion tab. | diff --git a/build_scripts/compile_version_string.txt b/build_scripts/compile_version_string.txt index 6931a61..9eba3c0 100644 --- a/build_scripts/compile_version_string.txt +++ b/build_scripts/compile_version_string.txt @@ -1 +1 @@ -5.3.2-release \ No newline at end of file +5.4.0-release \ No newline at end of file diff --git a/build_scripts/qt/resources.pri b/build_scripts/qt/resources.pri index 49f5cd2..2900782 100644 --- a/build_scripts/qt/resources.pri +++ b/build_scripts/qt/resources.pri @@ -37,6 +37,7 @@ DISTFILES += \ src/res/qml/SettingsPage.qml \ src/res/qml/StatisticsPage.qml \ src/res/qml/steamvr_page/SteamVRPage.qml \ + src/res/qml/steamvr_page/steamvr_additional/* \ src/res/qml/steamvr_page/camera/* \ src/res/qml/steamvr_page/steamvrmisc/* \ src/res/qml/utilities_page/* \ diff --git a/build_scripts/qt/sources.pri b/build_scripts/qt/sources.pri index f56a721..67dce44 100644 --- a/build_scripts/qt/sources.pri +++ b/build_scripts/qt/sources.pri @@ -15,6 +15,8 @@ SOURCES += src/main.cpp\ src/openvr/ivrinput.cpp \ src/openvr/ovr_settings_wrapper.cpp \ src/openvr/ovr_overlay_wrapper.cpp \ + src/openvr/ovr_system_wrapper.cpp \ + src/openvr/lh_console_util.cpp \ src/utils/setup.cpp \ src/utils/paths.cpp \ src/utils/FrameRateUtils.cpp \ @@ -52,6 +54,8 @@ HEADERS += src/overlaycontroller.h \ src/openvr/ivrinput.h \ src/openvr/ovr_settings_wrapper.h \ src/openvr/ovr_overlay_wrapper.h \ + src/openvr/ovr_system_wrapper.h \ + src/openvr/lh_console_util.h \ src/utils/setup.h \ src/utils/paths.h \ src/utils/FrameRateUtils.h \ diff --git a/docs/building_for_windows.md b/docs/building_for_windows.md index e300042..84e5a48 100644 --- a/docs/building_for_windows.md +++ b/docs/building_for_windows.md @@ -21,6 +21,7 @@ For pushing changes to the repo: 2. Clang format. Part of the [LLVM collection](https://releases.llvm.org/download.html). + - **note** use version 9.0.1/9.0.0 of LLVM Additionally, for fully building portable and installer release versions: diff --git a/src/openvr/ivrinput.cpp b/src/openvr/ivrinput.cpp index 7a42b32..ef27afe 100644 --- a/src/openvr/ivrinput.cpp +++ b/src/openvr/ivrinput.cpp @@ -127,6 +127,7 @@ SteamIVRInput::SteamIVRInput() m_gravityReverse( action_keys::gravityReverse ), m_heightToggle( action_keys::heightToggle ), m_resetOffsets( action_keys::resetOffsets ), + m_applyOffsets( action_keys::applyOffsets ), m_snapTurnLeft( action_keys::snapTurnLeft ), m_snapTurnRight( action_keys::snapTurnRight ), m_smoothTurnLeft( action_keys::smoothTurnLeft ), @@ -277,6 +278,11 @@ bool SteamIVRInput::resetOffsets() return isDigitalActionActivatedOnce( m_resetOffsets ); } +bool SteamIVRInput::applyOffsets() +{ + return isDigitalActionActivatedOnce( m_applyOffsets ); +} + bool SteamIVRInput::snapTurnLeft() { return isDigitalActionActivatedOnce( m_snapTurnLeft ); diff --git a/src/openvr/ivrinput.h b/src/openvr/ivrinput.h index 91289a8..2629d90 100644 --- a/src/openvr/ivrinput.h +++ b/src/openvr/ivrinput.h @@ -41,6 +41,7 @@ namespace action_keys constexpr auto gravityToggle = "/actions/motion/in/GravityToggle"; constexpr auto gravityReverse = "/actions/motion/in/GravityReverse"; constexpr auto resetOffsets = "/actions/motion/in/ResetOffsets"; + constexpr auto applyOffsets = "/actions/motion/in/ApplyOffsets"; constexpr auto heightToggle = "/actions/motion/in/HeightToggle"; constexpr auto snapTurnLeft = "/actions/motion/in/SnapTurnLeft"; constexpr auto snapTurnRight = "/actions/motion/in/SnapTurnRight"; @@ -146,6 +147,7 @@ public: bool gravityReverse(); bool heightToggle(); bool resetOffsets(); + bool applyOffsets(); bool snapTurnLeft(); bool snapTurnRight(); bool smoothTurnLeft(); @@ -228,6 +230,7 @@ private: DigitalAction m_gravityReverse; DigitalAction m_heightToggle; DigitalAction m_resetOffsets; + DigitalAction m_applyOffsets; DigitalAction m_snapTurnLeft; DigitalAction m_snapTurnRight; DigitalAction m_smoothTurnLeft; diff --git a/src/openvr/lh_console_util.cpp b/src/openvr/lh_console_util.cpp new file mode 100644 index 0000000..41dfdac --- /dev/null +++ b/src/openvr/lh_console_util.cpp @@ -0,0 +1,151 @@ +#include "lh_console_util.h" + +namespace lh_con_util +{ +bool LHCUtil::FindAll() +{ + if ( !FindAllRX() ) + { + LOG( ERROR ) << "Find All Recievers Failed"; + return false; + } + if ( !FindAllTX() ) + { + LOG( ERROR ) << "Find All Transmitters Failed"; + return false; + } + return true; +} + +bool LHCUtil::FindAllRX() +{ + QProcess* lhProcess = new QProcess(); + QString program = "lighthouse_console.exe"; + lhProcess->start( path_, QStringList() << "" ); + lhProcess->waitForFinished(); + + QString output = QString( lhProcess->readAllStandardOutput() ); + QStringList outputLines + = output.split( QRegExp( "[\r\n]" ), QString::SkipEmptyParts ); + bool RecieverStart = false; + + for ( auto OutputLine : outputLines ) + { + if ( OutputLine.contains( "Attached lighthouse receiver devices:" ) ) + { + RecieverStart = true; + continue; + } + if ( RecieverStart ) + { + if ( OutputLine.contains( "lighthouse_console" ) ) + { + break; + } + OutputLine.simplified().remove( " " ); + OutputLine.remove( 0, 1 ); + // LOG( WARNING ) << OutputLine << std::endl; + RXTX_Pairs_.push_back( RXTX_Pair{ OutputLine, " ", true, false } ); + } + } + return !RXTX_Pairs_.empty(); +} + +bool LHCUtil::FindConnectedTX( QString RXSerial ) +{ + LOG( WARNING ) << RXSerial; + QProcess* lhProcess = new QProcess(); + lhProcess->start( path_, QStringList() << "/serial" << RXSerial << "exit" ); + lhProcess->waitForFinished(); + + QString output = QString( lhProcess->readAllStandardOutput() ); + QStringList outputLines + = output.split( QRegExp( "[\r\n]" ), QString::SkipEmptyParts ); + // std::vector OutputLines + // = exec( ( "\"" + path_ + "\" /serial " + RXSerial + " exit" ).c_str() + // ); + bool lhConFound = false; + for ( auto outputLine : outputLines ) + { + // LOG( WARNING ) << outputLine; + if ( outputLine.contains( "Connected to receiver" ) ) + { + auto splitList = outputLine.split( ":" ); + QString TXSerial = splitList[0]; + if ( TXSerial == "lighthouse_console" ) + { + lhConFound = true; + continue; + } + for ( auto& rxtx : RXTX_Pairs_ ) + { + if ( rxtx.RX_Serial == RXSerial ) + { + rxtx.TX_Serial = TXSerial; + rxtx.Is_Paired = true; + rxtx.Is_Init = true; + LOG( WARNING ) + << "tx serial stored: " << TXSerial.toStdString(); + return true; + } + } + // TODO error handling + return false; + } + } + if ( lhConFound ) + { + for ( auto rxtx : RXTX_Pairs_ ) + { + if ( rxtx.RX_Serial == RXSerial ) + { + rxtx.TX_Serial = ""; + rxtx.Is_Paired = false; + rxtx.Is_Init = true; + LOG( WARNING ) << "tx oops"; + return true; + } + } + } + // TODO error handling + return false; +} + +bool LHCUtil::FindAllTX() +{ + bool NoError = true; + for ( auto rxtx : RXTX_Pairs_ ) + { + if ( !FindConnectedTX( rxtx.RX_Serial ) ) + { + NoError = false; + } + } + return NoError; +} + +QString LHCUtil::GetLinkedTX( QString RXSerial ) +{ + for ( auto rxtx : RXTX_Pairs_ ) + { + if ( rxtx.RX_Serial == RXSerial ) + { + return rxtx.TX_Serial; + } + } + return ""; +} + +QString LHCUtil::GetLinkedRX( QString TXSerial ) +{ + for ( auto rxtx : RXTX_Pairs_ ) + { + if ( rxtx.TX_Serial == TXSerial ) + { + return rxtx.RX_Serial; + } + } + return ""; +} + +} // namespace lh_con_util diff --git a/src/openvr/lh_console_util.h b/src/openvr/lh_console_util.h new file mode 100644 index 0000000..cff50d2 --- /dev/null +++ b/src/openvr/lh_console_util.h @@ -0,0 +1,48 @@ +#pragma once +#include "openvr.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace lh_con_util +{ +struct RXTX_Pair +{ + QString RX_Serial = ""; + QString TX_Serial = ""; + bool Is_Init = false; + bool Is_Paired = false; +}; +class LHCUtil +{ +private: + QString path_; + bool InPairs( std::string RXSerial ); + bool FindAllRX(); + bool FindAllTX(); + bool path_Init = false; + +public: + explicit LHCUtil( QString path ) + { + path_ = path; + } + std::vector RXTX_Pairs_; + bool FindAll(); + bool FindConnectedTX( QString RXSerial ); + QString GetLinkedTX( QString RXSerial ); + QString GetLinkedRX( QString TXSerial ); + RXTX_Pair GetConnectedTXRXPair(); + bool pairDevice( QString RXSerial ); +}; +} // namespace lh_con_util diff --git a/src/openvr/ovr_system_wrapper.cpp b/src/openvr/ovr_system_wrapper.cpp new file mode 100644 index 0000000..57bcc25 --- /dev/null +++ b/src/openvr/ovr_system_wrapper.cpp @@ -0,0 +1,234 @@ +#include "ovr_system_wrapper.h" + +namespace ovr_system_wrapper +{ +SystemError handleTrackedPropertyErrors( vr::TrackedDeviceProperty tdp, + vr::ETrackedPropertyError error, + std::string customErrorMsg ) +{ + if ( error != vr::TrackedProp_Success ) + { + LOG( ERROR ) << "Could not get Property with error \"" + << vr::VRSystem()->GetPropErrorNameFromEnum( error ) + << "\" property: " + << "todo" + << " " << customErrorMsg; + if ( tdp == vr::Prop_TrackedDeviceProperty_Max ) + { + // Just for Error OPPS todo + } + return SystemError::UndefinedError; + } + return SystemError::NoError; +} + +std::string getPropertyFromTrackedEnum( vr::TrackedDeviceProperty ) +{ + return "TODO"; +} + +std::pair + getBoolTrackedProperty( int deviceIndex, + vr::TrackedDeviceProperty property, + std::string customErrorMsg ) + +{ + uint32_t unIndex = static_cast( deviceIndex ); + vr::ETrackedPropertyError error; + bool value; + value = vr::VRSystem()->GetBoolTrackedDeviceProperty( + unIndex, property, &error ); + SystemError e + = handleTrackedPropertyErrors( property, error, customErrorMsg ); + std::pair p( e, value ); + return p; +} + +std::pair + getInt32TrackedProperty( int deviceIndex, + vr::TrackedDeviceProperty property, + std::string customErrorMsg ) + +{ + uint32_t unIndex = static_cast( deviceIndex ); + int value; + vr::ETrackedPropertyError error; + value = static_cast( vr::VRSystem()->GetInt32TrackedDeviceProperty( + unIndex, property, &error ) ); + SystemError e + = handleTrackedPropertyErrors( property, error, customErrorMsg ); + std::pair p( e, value ); + return p; +} + +std::pair + getFloatTrackedProperty( int deviceIndex, + vr::TrackedDeviceProperty property, + std::string customErrorMsg ) + +{ + uint32_t unIndex = static_cast( deviceIndex ); + vr::ETrackedPropertyError error; + float value; + value = vr::VRSystem()->GetFloatTrackedDeviceProperty( + unIndex, property, &error ); + SystemError e + = handleTrackedPropertyErrors( property, error, customErrorMsg ); + std::pair p( e, value ); + return p; +} + +std::pair + getStringTrackedProperty( int deviceIndex, + vr::TrackedDeviceProperty property, + std::string customErrorMsg ) + +{ + // This appears to be correct value as set in CVRSettingHelper as of + // ovr 1.11.11 + const uint32_t bufferMax = 4096; + char cStringOut[bufferMax]; + uint32_t unIndex = static_cast( deviceIndex ); + vr::VRSystem()->GetStringTrackedDeviceProperty( + unIndex, property, cStringOut, bufferMax ); + std::string value = cStringOut; + SystemError e = handleTrackedPropertyErrors( + property, vr::TrackedProp_Success, customErrorMsg ); + std::pair p( e, value ); + return p; +} + +bool deviceConnected( int index ) +{ + uint32_t unIndex = static_cast( index ); + return vr::VRSystem()->IsTrackedDeviceConnected( unIndex ); +} + +vr::ETrackedDeviceClass getDeviceClass( int index ) +{ + uint32_t unIndex = static_cast( index ); + return vr::VRSystem()->GetTrackedDeviceClass( unIndex ); +} + +std::string getDeviceName( int index ) +{ + uint32_t unIndex = static_cast( index ); + // checks if connected returns unknown if not + if ( !vr::VRSystem()->IsTrackedDeviceConnected( unIndex ) ) + { + return "No Device Connected"; + } + // arbitary max size OVR specifies 32*1024 but that's unrealistic + auto controllerNamePair + = getStringTrackedProperty( index, vr::Prop_ControllerType_String ); + if ( controllerNamePair.first != SystemError::NoError ) + { + return "Error"; + } + std::string cn = controllerNamePair.second; + if ( strcmp( cn.c_str(), "oculus_touch" ) == 0 ) + { + return "Touch"; + } + if ( strcmp( cn.c_str(), "knuckles" ) == 0 ) + { + return "Knuckles"; + } + if ( strcmp( cn.c_str(), "vive_controller" ) == 0 ) + { + return "Wand"; + } + if ( strcmp( cn.c_str(), "hpmotioncontroller" ) == 0 ) + { + return "Reverb G2 WMR"; + } + if ( strcmp( cn.c_str(), "holographic_controller" ) == 0 ) + { + return "WMR"; + } + if ( strcmp( cn.c_str(), "vive_cosmos_controller" ) == 0 ) + { + return "Cosmos"; + } + if ( strcmp( cn.c_str(), "vive_tracker" ) == 0 ) + { + return "Tracker"; + } + if ( strcmp( cn.c_str(), "indexhmd" ) == 0 ) + { + return "Index Headset"; + } + if ( cn.find( "vive_tracker_" ) != std::string::npos ) + { + std::string side = ""; + if ( cn.find( "_left" ) != std::string::npos ) + { + side = "left "; + } + else if ( cn.find( "_right" ) != std::string::npos ) + { + side = "right "; + } + std::string part = ""; + if ( cn.find( "handed" ) != std::string::npos ) + { + part = " hand"; + } + else if ( cn.find( "shoulder" ) != std::string::npos ) + { + part = "shoulder"; + } + else if ( cn.find( "knee" ) != std::string::npos ) + { + part = "knee"; + } + else if ( cn.find( "elbow" ) != std::string::npos ) + { + part = "elbow"; + } + else if ( cn.find( "foot" ) != std::string::npos ) + { + part = "foot"; + } + else if ( cn.find( "camera" ) != std::string::npos ) + { + part = "camera"; + } + else if ( cn.find( "waist" ) != std::string::npos ) + { + part = "waist"; + } + return "Tracker " + side + part; + } + // TODO add HMD's + return std::string( controllerNamePair.second ); +} + +std::vector getAllConnectedDevices( bool onlyWearable ) +{ + std::vector output; + for ( int i = 0; i < static_cast( vr::k_unMaxTrackedDeviceCount ); + i++ ) + { + if ( deviceConnected( i ) ) + { + auto deviceClass = getDeviceClass( i ); + if ( onlyWearable ) + { + if ( deviceClass == vr::TrackedDeviceClass_Controller + || deviceClass == vr::TrackedDeviceClass_GenericTracker + || deviceClass == vr::TrackedDeviceClass_HMD ) + { + output.push_back( i ); + } + } + else + { + output.push_back( i ); + } + } + } + return output; +} + +} // namespace ovr_system_wrapper diff --git a/src/openvr/ovr_system_wrapper.h b/src/openvr/ovr_system_wrapper.h new file mode 100644 index 0000000..ee49f90 --- /dev/null +++ b/src/openvr/ovr_system_wrapper.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +/* Wrapper For OpenVR's IVR settings class, allows us to do our error logging + * while also minimizing code + * + */ +namespace ovr_system_wrapper +{ +// might make sense to mirror ovr's errors exactly, but for now this is more +// than sufficient + +enum class SystemError +{ + NoError, + UndefinedError, + +}; + +std::pair + getBoolTrackedProperty( int deviceIndex, + vr::TrackedDeviceProperty property, + std::string customErrorMsg = "" ); + +std::pair + getInt32TrackedProperty( int deviceIndex, + vr::TrackedDeviceProperty property, + std::string customErrorMsg = "" ); + +std::pair + getFloatTrackedProperty( int deviceIndex, + vr::TrackedDeviceProperty property, + std::string customErrorMsg = "" ); +std::pair + getStringTrackedProperty( int deviceIndex, + vr::TrackedDeviceProperty property, + std::string customErrorMsg = "" ); + +SystemError handleTrackedPropertyErrors( vr::TrackedDeviceProperty tdp, + vr::ETrackedPropertyError error, + std::string customErrorMsg ); +std::string getPropertyFromEnum( vr::TrackedDeviceProperty ); + +bool deviceConnected( int Index ); + +vr::ETrackedDeviceClass getDeviceClass( int index ); + +std::vector getAllConnectedDevices( bool onlyWearable = false ); +std::string getDeviceName( int index ); + +} // namespace ovr_system_wrapper diff --git a/src/overlaycontroller.cpp b/src/overlaycontroller.cpp index bec9952..213d535 100644 --- a/src/overlaycontroller.cpp +++ b/src/overlaycontroller.cpp @@ -602,6 +602,7 @@ void OverlayController::processMotionBindings() m_actions.gravityReverse() ); m_moveCenterTabController.heightToggleAction( m_actions.heightToggle() ); m_moveCenterTabController.resetOffsets( m_actions.resetOffsets() ); + m_moveCenterTabController.applyOffsets( m_actions.applyOffsets() ); m_moveCenterTabController.snapTurnLeft( m_actions.snapTurnLeft() ); m_moveCenterTabController.snapTurnRight( m_actions.snapTurnRight() ); m_moveCenterTabController.smoothTurnLeft( m_actions.smoothTurnLeft() ); @@ -818,16 +819,32 @@ void OverlayController::setExclusiveInputEnabled( bool value, bool notify ) } } +void OverlayController::setOpenXRFixEnabled( bool value, bool notify ) +{ + settings::setSetting( settings::BoolSetting::APPLICATION_openXRWorkAround, + value ); + if ( notify ) + { + emit openXRFixEnabledChanged( value ); + } +} + +bool OverlayController::openXRFixEnabled() const +{ + return settings::getSetting( + settings::BoolSetting::APPLICATION_openXRWorkAround ); +} + bool OverlayController::crashRecoveryDisabled() const { return settings::getSetting( - settings::BoolSetting::APPLICATION_crashRecoveryDisabled ); + settings::BoolSetting::APPLICATION_crashRecoveryDisabled2 ); } void OverlayController::setCrashRecoveryDisabled( bool value, bool notify ) { settings::setSetting( - settings::BoolSetting::APPLICATION_crashRecoveryDisabled, value ); + settings::BoolSetting::APPLICATION_crashRecoveryDisabled2, value ); if ( notify ) { emit crashRecoveryDisabledChanged( value ); @@ -1240,6 +1257,18 @@ void OverlayController::mainEventLoop() = std::sqrt( vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2] ); } auto universe = vr::VRCompositor()->GetTrackingSpace(); + // This Fix is hopefully temporary as OpenVR doesn't appear to have a way to + // tell if an application is OpenXR outside of VR_init which we don't have + // control over + if ( vr::VRApplications()->GetApplicationProcessId( + "openvr.tool.steamvr_room_setup" ) + == 0 + && openXRFixEnabled() ) + { + // OpenXR applications will appear as RawAndUncalibrated. + // Unless Room Setup is running, treat this case as Standing. + universe = vr::TrackingUniverseStanding; + } m_moveCenterTabController.eventLoopTick( universe, devicePoses ); m_utilitiesTabController.eventLoopTick(); diff --git a/src/overlaycontroller.h b/src/overlaycontroller.h index b4cb5f9..058596c 100644 --- a/src/overlaycontroller.h +++ b/src/overlaycontroller.h @@ -93,6 +93,8 @@ class OverlayController : public QObject Q_PROPERTY( bool exclusiveInputEnabled READ exclusiveInputEnabled WRITE setExclusiveInputEnabled NOTIFY exclusiveInputEnabledChanged ) + Q_PROPERTY( bool openXRFixEnabled READ openXRFixEnabled WRITE + setOpenXRFixEnabled NOTIFY openXRFixEnabledChanged ) private: vr::VROverlayHandle_t m_ulOverlayHandle = vr::k_ulOverlayHandleInvalid; @@ -238,6 +240,7 @@ public: bool crashRecoveryDisabled() const; bool exclusiveInputEnabled() const; + bool openXRFixEnabled() const; bool enableDebug() const; bool disableVersionCheck() const; bool newVersionDetected() const; @@ -270,6 +273,7 @@ public slots: void setVsyncDisabled( bool value, bool notify = true ); void setCustomTickRateMs( int value, bool notify = true ); void setDebugState( int value, bool notify = true ); + void setOpenXRFixEnabled( bool value, bool notify = true ); signals: void keyBoardInputSignal( QString input, unsigned long userValue = 0 ); @@ -282,6 +286,7 @@ signals: void vsyncDisabledChanged( bool value ); void customTickRateMsChanged( int value ); void debugStateChanged( int value ); + void openXRFixEnabledChanged( bool value ); }; } // namespace advsettings diff --git a/src/package_files/action_manifest.json b/src/package_files/action_manifest.json index 43ffb18..f481641 100644 --- a/src/package_files/action_manifest.json +++ b/src/package_files/action_manifest.json @@ -131,7 +131,12 @@ "requirement": "optional", "type": "boolean" }, - + { + "name": "/actions/motion/in/ApplyOffsets", + "requirement": "optional", + "type": "boolean" + }, + { "name": "/actions/motion/in/HeightToggle", @@ -282,6 +287,7 @@ "/actions/motion/in/GravityToggle" : "Gravity Toggle", "/actions/motion/in/GravityReverse" : "Gravity Reverse", "/actions/motion/in/ResetOffsets" : "Reset Offsets", + "/actions/motion/in/ApplyOffsets" : "Apply Offsets", "/actions/motion/in/HeightToggle" : "Height Toggle", "/actions/motion/in/SnapTurnLeft" : "Snap-Turn Left", "/actions/motion/in/SnapTurnRight" : "Snap-Turn Right", diff --git a/src/res/qml/SettingsPage.qml b/src/res/qml/SettingsPage.qml index 0f8766f..8335c31 100644 --- a/src/res/qml/SettingsPage.qml +++ b/src/res/qml/SettingsPage.qml @@ -62,10 +62,26 @@ MyStackViewPage { } MyToggleButton { - id: disableCrashRecoveryToggle - text: "Disable Automatic Crash Recovery of Chaperone Config" + id: enableUnccalMotionToggle + text: "Enable Motion Features When in Uncalibrated Mode (Experimental)" onCheckedChanged: { - OverlayController.setCrashRecoveryDisabled(checked, true) + MoveCenterTabController.setEnableUncalMotion(checked, true); + } + } + + MyToggleButton { + id: openXRFixToggle + text: "OpenXR Fix (force standing universe [Experimental])" + onCheckedChanged: { + OverlayController.setOpenXRFixEnabled(checked, true); + } + } + + MyToggleButton { + id: disableCrashRecoveryToggle + text: "Enable Automatic Crash Recovery of Chaperone Config" + onCheckedChanged: { + OverlayController.setCrashRecoveryDisabled(!checked, true) } } @@ -251,8 +267,9 @@ MyStackViewPage { oldStyleMotionToggle.checked = MoveCenterTabController.oldStyleMotion universeCenteredRotationToggle.checked = MoveCenterTabController.universeCenteredRotation enableSeatedMotionToggle.checked = MoveCenterTabController.enableSeatedMotion + enableUnccalMotionToggle.checked = MoveCenterTabController.enableUncalMotion - disableCrashRecoveryToggle.checked = OverlayController.crashRecoveryDisabled + disableCrashRecoveryToggle.checked = !OverlayController.crashRecoveryDisabled customTickRateText.text = OverlayController.customTickRateMs vsyncDisabledToggle.checked = OverlayController.vsyncDisabled customTickRateText.visible = vsyncDisabledToggle.checked @@ -264,6 +281,8 @@ MyStackViewPage { nativeChaperoneToggleButton.checked = SettingsTabController.nativeChaperoneToggle oculusSdkToggleButton.checked = SettingsTabController.oculusSdkToggle exclusiveInputToggleButton.checked = OverlayController.exclusiveInputEnabled + openXRFixToggle.checked = OverlayController.openXRFixEnabled + seatedOldExternalWarning.visible = MoveCenterTabController.allowExternalEdits && MoveCenterTabController.oldStyleMotion && MoveCenterTabController.enableSeatedMotion spaceAdjustChaperoneToggle.checked = MoveCenterTabController.adjustChaperone @@ -299,6 +318,9 @@ MyStackViewPage { enableSeatedMotionToggle.checked = MoveCenterTabController.enableSeatedMotion seatedOldExternalWarning.visible = MoveCenterTabController.allowExternalEdits && MoveCenterTabController.oldStyleMotion && MoveCenterTabController.enableSeatedMotion } + onEnableUncalMotionChanged: { + enableUnccalMotionToggle.checked = MoveCenterTabController.enableUncalMotion + } onAdjustChaperoneChanged: { spaceAdjustChaperoneToggle.checked = MoveCenterTabController.adjustChaperone } @@ -313,7 +335,7 @@ MyStackViewPage { customTickRateMsLabel.visible = vsyncDisabledToggle.checked } onCrashRecoveryDisabledChanged: { - disableCrashRecoveryToggle.checked = OverlayController.crashRecoveryDisabled + disableCrashRecoveryToggle.checked = !OverlayController.crashRecoveryDisabled } onCustomTickRateMsChanged: { @@ -333,6 +355,9 @@ MyStackViewPage { onExclusiveInputEnabledChanged:{ exclusiveInputToggleButton.checked = OverlayController.exclusiveInputEnabled } + onOpenXRFixEnabledChanged:{ + openXRFixToggle.checked = OverlayController.openXRFixEnabled + } } } // end scroll } diff --git a/src/res/qml/common/mainwidget.qml b/src/res/qml/common/mainwidget.qml index bbb6a79..2602424 100644 --- a/src/res/qml/common/mainwidget.qml +++ b/src/res/qml/common/mainwidget.qml @@ -10,6 +10,7 @@ import "../chaperone_page" import "../steamvr_page" import "../rotation_page" import "../chaperone_page/chaperone_additional" +import "../steamvr_page/steamvr_additional" Rectangle { id: root @@ -41,6 +42,11 @@ Rectangle { visible: false } + property SteamVRTXRXPage steamVRTXRXPage: SteamVRTXRXPage{ + stackView: mainView + visible: false + } + property PlayspacePage playspacePage: PlayspacePage { stackView: mainView visible: false diff --git a/src/res/qml/steamvr_page/SteamVRPage.qml b/src/res/qml/steamvr_page/SteamVRPage.qml index f20c191..0cac7d7 100644 --- a/src/res/qml/steamvr_page/SteamVRPage.qml +++ b/src/res/qml/steamvr_page/SteamVRPage.qml @@ -23,6 +23,16 @@ MyStackViewPage { RowLayout { Layout.fillWidth: true + MyPushButton { + text: "Device Pairing Information" + Layout.preferredWidth: 350 + + onClicked: { + MyResources.playFocusChangedSound() + mainView.push(steamVRTXRXPage) + } + } + Item { Layout.fillWidth: true} MyPushButton { diff --git a/src/res/qml/steamvr_page/steamvr_additional/SteamVRTXRXPage.qml b/src/res/qml/steamvr_page/steamvr_additional/SteamVRTXRXPage.qml new file mode 100644 index 0000000..bd9c971 --- /dev/null +++ b/src/res/qml/steamvr_page/steamvr_additional/SteamVRTXRXPage.qml @@ -0,0 +1,164 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Controls 2.5 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.2 +import ovras.advsettings 1.0 +import "." // QTBUG-34418, singletons require explicit import to load qmldir file +import "../../common" + + + +MyStackViewPage { + ListModel{ + id: listModelRXTX + ListElement{ + TX:"Controller" + RX:"Reciever" + Dev:"device" + DT: "Dongle Type" + } + } + headerText: "Device Pairing Information" + content: + ColumnLayout { + spacing: 10 + Layout.fillWidth: true + Layout.fillHeight: true + RowLayout{ + MyText{ + text: "dongles used: " + Layout.preferredWidth: 200 + } + MyText{ + id: donglesUse + text: "" + Layout.preferredWidth: 100 + } + + Item{ + Layout.fillWidth: true + } + MyPushButton{ + Layout.preferredWidth: 250 + text: "Refresh Device List" + id: searchButton + onClicked: { + getRXTX() + } + + } + } + RowLayout{ + Layout.fillHeight: true + Layout.fillWidth: true + ListView{ + id: lvDevInfo + model: listModelRXTX + spacing: 20 + Layout.fillHeight: true + Layout.fillWidth: true + clip: true + delegate: + GroupBox { + id: chaperoneTypeGroupBox + Layout.fillWidth: true + + label: RowLayout{ + MyText { + leftPadding: 10 + text: "Device: " + bottomPadding: -10 + } + MyText { + leftPadding: 10 + text: Dev + 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{ + Layout.fillHeight: true + Layout.fillWidth: true + clip: true + MyText{ + Layout.preferredWidth: 150 + text: "Device ID: " + } + MyText{ + Layout.preferredWidth: 250 + text: TX + } + Item{ + Layout.preferredWidth: 50 + } + MyText{ + Layout.preferredWidth: 300 + text: "Connected Dongle Type: " + } + MyText{ + Layout.preferredWidth: 250 + text: DT + } + } + RowLayout{ + Layout.fillHeight: true + Layout.fillWidth: true + clip: true + + Item{ + Layout.preferredWidth: 600 + } + MyText{ + Layout.preferredWidth: 150 + text: "Dongle ID: " + } + MyText{ + Layout.preferredWidth: 250 + text: RX + } + } + } + } + ScrollBar{ + clip: true + visible: true} + + } + } + } + Component.onCompleted: { + getRXTX() + } + function getRXTX() { + listModelRXTX.clear(); + SteamVRTabController.searchRXTX(); + donglesUse.text = SteamVRTabController.getDongleUsage(); + var pairCount = SteamVRTabController.getRXTXCount() + for (var i = 0; i < pairCount; i++) { + var RXget = SteamVRTabController.getRXList(i); + var TXget = SteamVRTabController.getTXList(i); + var nameGet = SteamVRTabController.getDeviceName(i) + var dongletyp = SteamVRTabController.getDongleType(i) + listModelRXTX.append({RX:RXget, TX:TXget, Dev:nameGet, DT:dongletyp}) + } + } +} + + + + //TODO content + diff --git a/src/settings/internal/settings_controller.h b/src/settings/internal/settings_controller.h index a8f4b4c..f964ca1 100644 --- a/src/settings/internal/settings_controller.h +++ b/src/settings/internal/settings_controller.h @@ -281,6 +281,10 @@ private: SettingCategory::Playspace, QtInfo{ "adjustChaperone2" }, false }, + BoolSettingValue{ BoolSetting::PLAYSPACE_enableUncalMotion, + SettingCategory::Playspace, + QtInfo{ "enableUncalMotion" }, + false }, BoolSettingValue{ BoolSetting::APPLICATION_disableVersionCheck, SettingCategory::Application, @@ -306,6 +310,14 @@ private: SettingCategory::Application, QtInfo{ "enableExclusiveInput" }, false }, + BoolSettingValue{ BoolSetting::APPLICATION_crashRecoveryDisabled2, + SettingCategory::Application, + QtInfo{ "crashRecoveryDisabled2" }, + true }, + BoolSettingValue{ BoolSetting::APPLICATION_openXRWorkAround, + SettingCategory::Application, + QtInfo{ "openXRWorkAround" }, + false }, BoolSettingValue{ BoolSetting::AUDIO_pttEnabled, SettingCategory::Audio, QtInfo{ "pttEnabled" }, diff --git a/src/settings/settings.h b/src/settings/settings.h index 7418b0d..95e9097 100644 --- a/src/settings/settings.h +++ b/src/settings/settings.h @@ -23,6 +23,7 @@ enum class BoolSetting PLAYSPACE_showLogMatricesButton, PLAYSPACE_simpleRecenter, PLAYSPACE_adjustChaperone2, + PLAYSPACE_enableUncalMotion, APPLICATION_disableVersionCheck, APPLICATION_previousShutdownSafe, @@ -30,6 +31,8 @@ enum class BoolSetting APPLICATION_crashRecoveryDisabled, APPLICATION_enableDebug, APPLICATION_enableExclusiveInput, + APPLICATION_crashRecoveryDisabled2, + APPLICATION_openXRWorkAround, AUDIO_pttEnabled, AUDIO_pttShowNotification, diff --git a/src/tabcontrollers/MoveCenterTabController.cpp b/src/tabcontrollers/MoveCenterTabController.cpp index 1b52497..91428fc 100644 --- a/src/tabcontrollers/MoveCenterTabController.cpp +++ b/src/tabcontrollers/MoveCenterTabController.cpp @@ -892,7 +892,32 @@ void MoveCenterTabController::setEnableSeatedMotion( bool value, bool notify ) if ( notify ) { - emit enableSeatedMotionChanged( value ); + emit enableUncalMotionChanged( value ); + } +} + +bool MoveCenterTabController::enableUncalMotion() const +{ + return settings::getSetting( + settings::BoolSetting::PLAYSPACE_enableUncalMotion ); +} + +void MoveCenterTabController::setEnableUncalMotion( bool value, bool notify ) +{ + if ( !value && m_initComplete ) + { + reset(); + } + settings::setSetting( settings::BoolSetting::PLAYSPACE_enableUncalMotion, + value ); + if ( !value && m_initComplete ) + { + m_pendingZeroOffsets = true; + } + + if ( notify ) + { + emit enableUncalMotionChanged( value ); } } @@ -976,7 +1001,7 @@ void MoveCenterTabController::incomingSeatedReset() void MoveCenterTabController::reset() { - if ( !m_chaperoneBasisAcquired ) + if ( !m_chaperoneBasisAcquired && !enableUncalMotion() ) { LOG( WARNING ) << "WARNING: Attempted reset offsets before chaperone " "basis is acquired!"; @@ -1115,7 +1140,8 @@ void MoveCenterTabController::zeroOffsets() // finished checking if out of bounds, proceed with normal zeroing offsets if ( vr::VRChaperone()->GetCalibrationState() - == vr::ChaperoneCalibrationState_OK ) + == vr::ChaperoneCalibrationState_OK + || enableUncalMotion() ) { m_oldOffsetX = 0.0f; m_oldOffsetY = 0.0f; @@ -1131,7 +1157,7 @@ void MoveCenterTabController::zeroOffsets() emit rotationChanged( m_rotation ); updateChaperoneResetData(); m_pendingZeroOffsets = false; - if ( !m_chaperoneBasisAcquired ) + if ( !m_chaperoneBasisAcquired && !enableUncalMotion() ) { m_chaperoneBasisAcquired = true; if ( !m_initComplete ) @@ -1962,6 +1988,14 @@ void MoveCenterTabController::resetOffsets( bool resetOffsetsJustPressed ) } } +void MoveCenterTabController::applyOffsets( bool applyOffsetsJustPressed ) +{ + if ( applyOffsetsJustPressed ) + { + zeroOffsets(); + } +} + void MoveCenterTabController::snapTurnLeft( bool snapTurnLeftJustPressed ) { if ( !snapTurnLeftJustPressed ) @@ -2933,6 +2967,7 @@ void MoveCenterTabController::eventLoopTick( vr::VRChaperoneSetup()->RevertWorkingCopy(); } setTrackingUniverse( int( universe ) ); + // TODO set to allow. return; } @@ -2958,7 +2993,9 @@ void MoveCenterTabController::eventLoopTick( // if we were in room setup, but got this far in the loop, universe is no // longer raw mode and we detect room setup exit and zeroOffsets() to apply // new setup. - if ( m_pendingZeroOffsets || m_roomSetupModeDetected ) + + if ( m_pendingZeroOffsets + || ( m_roomSetupModeDetected && !enableUncalMotion() ) ) { zeroOffsets(); // m_roomSetupModeDetected is set to false in zeroOffsets() if it's diff --git a/src/tabcontrollers/MoveCenterTabController.h b/src/tabcontrollers/MoveCenterTabController.h index 6759c55..07a03c5 100644 --- a/src/tabcontrollers/MoveCenterTabController.h +++ b/src/tabcontrollers/MoveCenterTabController.h @@ -139,6 +139,8 @@ class MoveCenterTabController : public QObject setEnableSeatedMotion NOTIFY enableSeatedMotionChanged ) Q_PROPERTY( bool simpleRecenter READ simpleRecenter WRITE setSimpleRecenter NOTIFY simpleRecenterChanged ) + Q_PROPERTY( bool enableUncalMotion READ enableUncalMotion WRITE + setEnableUncalMotion NOTIFY enableUncalMotionChanged ) private: OverlayController* parent; @@ -276,6 +278,7 @@ public: bool oldStyleMotion() const; bool universeCenteredRotation() const; bool enableSeatedMotion() const; + bool enableUncalMotion() const; bool simpleRecenter() const; bool isInitComplete() const; double getHmdYawTotal(); @@ -306,6 +309,7 @@ public: void gravityReverseAction( bool gravityReverseHeld ); void heightToggleAction( bool heightToggleJustPressed ); void resetOffsets( bool resetOffsetsJustPressed ); + void applyOffsets( bool applyOffsetsJustPressed ); void snapTurnLeft( bool snapTurnLeftJustPressed ); void snapTurnRight( bool snapTurnRightJustPressed ); void smoothTurnLeft( bool smoothTurnLeftActive ); @@ -356,6 +360,7 @@ public slots: void setOldStyleMotion( bool value, bool notify = true ); void setUniverseCenteredRotation( bool value, bool notify = true ); void setEnableSeatedMotion( bool value, bool notify = true ); + void setEnableUncalMotion( bool value, bool notify = true ); void setSimpleRecenter( bool value, bool notify = true ); void shutdown(); @@ -403,6 +408,7 @@ signals: void universeCenteredRotationChanged( bool value ); void enableSeatedMotionChanged( bool value ); void simpleRecenterChanged( bool value ); + void enableUncalMotionChanged( bool value ); void offsetProfilesUpdated(); }; diff --git a/src/tabcontrollers/SteamVRTabController.cpp b/src/tabcontrollers/SteamVRTabController.cpp index 90ccbc5..e51a0b9 100644 --- a/src/tabcontrollers/SteamVRTabController.cpp +++ b/src/tabcontrollers/SteamVRTabController.cpp @@ -289,6 +289,113 @@ bool SteamVRTabController::cameraDashboard() const return m_cameraDashboard; } +void SteamVRTabController::searchRXTX() +{ + deviceList.clear(); + int hmdIndex = -1; + auto indexList = ovr_system_wrapper::getAllConnectedDevices( true ); + m_dongleCountCur = 0; + for ( auto device : indexList ) + { + if ( vr::TrackedDeviceClass_HMD + == ovr_system_wrapper::getDeviceClass( device ) ) + { + hmdIndex = device; + continue; + } + deviceList.push_back( DeviceInfo{ device } ); + GatherDeviceInfo( deviceList.back() ); + } + + if ( hmdIndex != -1 ) + { + auto dongleList + = ovr_system_wrapper::getStringTrackedProperty( + hmdIndex, vr::Prop_AllWirelessDongleDescriptions_String ) + .second; + int count = 0; + if ( !dongleList.empty() ) + { + count++; + } + for ( auto c : dongleList ) + { + if ( c == ';' ) + { + count++; + } + } + m_dongleCountMax = count; + } + return; +} +void SteamVRTabController::GatherDeviceInfo( DeviceInfo& device ) +{ + std::string cd = ovr_system_wrapper::getStringTrackedProperty( + device.index, vr::Prop_ConnectedWirelessDongle_String ) + .second; + if ( cd.empty() || cd == " " ) + { + cd = "n/a"; + device.dongleType = "n/a"; + } + else + { + m_dongleCountCur++; + if ( cd.find( "-RYB" ) != std::string::npos + || cd.find( "-LYM" ) != std::string::npos ) + { + device.dongleType = "Headset"; + } + // TODO 1yx SN + else if ( std::regex_match( cd, std::regex( "(.*)(-[0-9]YX)" ) ) ) + { + device.dongleType = "Tundra Dongle"; + } + else + { + device.dongleType = "Standard Dongle"; + } + } + device.conDongle = cd; + + std::string dd = ovr_system_wrapper::getStringTrackedProperty( + device.index, vr::Prop_SerialNumber_String ) + .second; + if ( dd.empty() || dd == " " ) + { + dd = "n/a"; + } + device.txName = dd; + + auto devClass = ovr_system_wrapper::getDeviceClass( device.index ); + if ( devClass == vr::TrackedDeviceClass_HMD + || devClass == vr::TrackedDeviceClass_Controller + || devClass == vr::TrackedDeviceClass_GenericTracker ) + { + device.hasName = true; + device.deviceName = ovr_system_wrapper::getDeviceName( device.index ); + } + else + { + if ( device.txName.find( "LHB-" ) != std::string::npos ) + { + device.deviceName = "Lighthouse"; + } + } + int role = ovr_system_wrapper::getInt32TrackedProperty( + device.index, vr::Prop_ControllerRoleHint_Int32 ) + .second; + if ( role == 1 ) + { + device.deviceName += " (L)"; + } + else if ( role == 2 ) + { + device.deviceName += " (R)"; + } +} + void SteamVRTabController::launchBindingUI() { vr::VRActionSetHandle_t actionHandle = 0; @@ -335,4 +442,32 @@ void SteamVRTabController::restartSteamVR() QProcess::startDetached( cmd ); } +Q_INVOKABLE unsigned SteamVRTabController::getRXTXCount() +{ + return static_cast( deviceList.size() ); +} + +Q_INVOKABLE QString SteamVRTabController::getTXList( int i ) +{ + return QString::fromStdString( deviceList[i].txName ); +} + +Q_INVOKABLE QString SteamVRTabController::getDeviceName( int i ) +{ + return QString::fromStdString( deviceList[i].deviceName ); +} + +Q_INVOKABLE QString SteamVRTabController::getRXList( int i ) +{ + return QString::fromStdString( deviceList[i].conDongle ); +} +Q_INVOKABLE QString SteamVRTabController::getDongleType( int i ) +{ + return QString::fromStdString( deviceList[i].dongleType ); +} +Q_INVOKABLE QString SteamVRTabController::getDongleUsage() +{ + return QString::fromStdString( std::to_string( m_dongleCountCur ) + "/" + + std::to_string( m_dongleCountMax ) ); +} } // namespace advsettings diff --git a/src/tabcontrollers/SteamVRTabController.h b/src/tabcontrollers/SteamVRTabController.h index 0dced44..0de08b3 100644 --- a/src/tabcontrollers/SteamVRTabController.h +++ b/src/tabcontrollers/SteamVRTabController.h @@ -4,6 +4,13 @@ #include #include "../utils/FrameRateUtils.h" #include "../openvr/ovr_settings_wrapper.h" +#include "../openvr/lh_console_util.h" +#include +#include +#include "../openvr/lh_console_util.h" +#include +#include "../openvr/ovr_system_wrapper.h" +#include class QQuickWindow; // application namespace @@ -12,6 +19,18 @@ namespace advsettings // forward declaration class OverlayController; +struct DeviceInfo +{ + int index = -1; + std::string conDongle = ""; + std::string txName = ""; + std::string deviceName = ""; + std::string hand = ""; + std::string dongleType = "n/a"; + std::string serialNumber = ""; + bool hasName = false; +}; + class SteamVRTabController : public QObject { Q_OBJECT @@ -49,7 +68,13 @@ private: bool m_cameraBounds = false; bool m_cameraRoom = false; bool m_cameraDashboard = false; + bool m_pathRXTXInit = false; + int m_dongleCountCur = 0; + int m_dongleCountMax = 0; + std::vector deviceList; + + void GatherDeviceInfo( DeviceInfo& device ); void synchSteamVR(); public: @@ -70,8 +95,17 @@ public: bool cameraRoom() const; bool cameraDashboard() const; + Q_INVOKABLE void searchRXTX(); + Q_INVOKABLE void launchBindingUI(); + Q_INVOKABLE unsigned getRXTXCount(); + Q_INVOKABLE QString getTXList( int i ); + Q_INVOKABLE QString getRXList( int i ); + Q_INVOKABLE QString getDeviceName( int i ); + Q_INVOKABLE QString getDongleType( int i ); + Q_INVOKABLE QString getDongleUsage(); + public slots: void setPerformanceGraph( bool value, bool notify = true );