diff --git a/src/ivrinput/ivrinput.cpp b/src/ivrinput/ivrinput.cpp index a44fdb0..fa5aa9a 100644 --- a/src/ivrinput/ivrinput.cpp +++ b/src/ivrinput/ivrinput.cpp @@ -6,6 +6,17 @@ namespace input { +/*! +Wrapper around the IVRInput GetAnalogActionData with error handling. + +The struct is created and zero initalized in this function instead of being +passed as reference since the size is currently only 28 bytes, and currently +only two bools are used from the entire struct. +MSVC on /O2 will likely completely optimize the function call away but even if +it isn't the struct will still need to be created somewhere, and with move +semantics it almost doesn't matter if the struct is created in the calling +function and passed as reference, or created in this function. +*/ vr::InputDigitalActionData_t getDigitalActionData( Action& action ) { if ( action.type() != ActionType::Digital ) @@ -37,6 +48,17 @@ vr::InputDigitalActionData_t getDigitalActionData( Action& action ) return handleData; } +/*! +Wrapper around the IVRInput GetAnalogActionData with error handling. + +The struct is created and zero initalized in this function instead of being +passed as reference since the size is currently only 28 bytes, and currently +only two bools are used from the entire struct. +MSVC on /O2 will likely completely optimize the function call away but even if +it isn't the struct will still need to be created somewhere, and with move +semantics it almost doesn't matter if the struct is created in the calling +function and passed as reference, or created in this function. +*/ vr::InputAnalogActionData_t getAnalogActionData( Action& action ) { if ( action.type() != ActionType::Analog ) @@ -68,6 +90,12 @@ vr::InputAnalogActionData_t getAnalogActionData( Action& action ) return handleData; } +/*! +Gets the action state of an Action. +This will only return true the first time the button is released. It is +necessary to release the button and the push it again in order for this function +to return true again. +*/ bool isDigitalActionActivatedOnce( Action& action ) { const auto handleData = getDigitalActionData( action ); @@ -75,6 +103,10 @@ bool isDigitalActionActivatedOnce( Action& action ) return handleData.bState && handleData.bChanged; } +/*! +Gets the action state of an Action. +This will continually return true while the button is held down. +*/ bool isDigitalActionActivatedConstant( Action& action ) { const auto handleData = getDigitalActionData( action ); @@ -82,6 +114,14 @@ bool isDigitalActionActivatedConstant( Action& action ) return handleData.bState; } +/*! +Sets up the input systems. +Actions should be added to the initializer list before the body of the +constructor. Actions should be certain that the action name strings are +correctly input, and that the correct type is provided. +Wrong action names may not result in direct error messages, but just features +mystically not working. +*/ SteamIVRInput::SteamIVRInput() : m_manifest(), m_mainSet( input_strings::k_setMain ), m_nextTrack( input_strings::k_actionNextTrack, ActionType::Digital ) @@ -90,13 +130,23 @@ SteamIVRInput::SteamIVRInput() m_activeActionSet.ulRestrictedToDevice = vr::k_ulInvalidInputValueHandle; m_activeActionSet.nPriority = 0; } +/*! +Returns true if the next media track should be played. +Will only return true the first time that the button is pressed. Holding the +button down will result in false until it has been released and pushed again. +*/ bool SteamIVRInput::nextSong() { return isDigitalActionActivatedOnce( m_nextTrack ); } -void SteamIVRInput::Loop() +/*! +Updates the active action set(s). +Should be called every frame, or however often you want the input system to +update state. +*/ +void SteamIVRInput::UpdateStates() { constexpr auto numberOfSets = 1; diff --git a/src/ivrinput/ivrinput.h b/src/ivrinput/ivrinput.h index 158a542..7bd2736 100644 --- a/src/ivrinput/ivrinput.h +++ b/src/ivrinput/ivrinput.h @@ -7,17 +7,40 @@ namespace input { +/*! +Responsible for controller input. + +UpdateStates should be called every frame. + +Binary actions should only have one function, +and they should reflect the expected behaviour. I.e. if a button being pressed +and held should only return true the first time, that logic should be in the +function. + +An action in the IVRInput API is entered in the actions manifest. This is a +.json file that is included with the final binary. +Currently an Action is created with a string and a type. The type determines +which function should be used for getting information from the API. The type in +the actions manifest must match the type in the source code. + +Actions should be added as member objects to SteamIVRInput and initialized in +the constructor. They should then make a small number of accessor functions +available for outside use. The internal structs of the IVRInput API are not +entirely stable, and should not be leaked outside this class. + +The name of the actions manifest must be set in ivrinput_manifest.h. +*/ class SteamIVRInput { public: SteamIVRInput(); - void Loop(); + + void UpdateStates(); bool nextSong(); // Destructor. There are no terminating calls for the IVRInput API, so it // is left blank. ~SteamIVRInput() {} - // These have been explicitly deleted to make sure there are no attempts at // copying the class in weird ways. It is not worth defining what should // happen on copy because it simply shouldn't be done. @@ -34,12 +57,18 @@ public: private: Manifest m_manifest; + ActionSet m_mainSet; vr::VRActiveActionSet_t m_activeActionSet = {}; Action m_nextTrack; }; +/*! +The IVRInput system is _very_ finnicky about strings matching and if they don't +match there are usually no errors logged reflecting that. constexpr auto strings +should be used to refer to all action manifest strings. +*/ namespace input_strings { constexpr auto k_actionNextTrack = "/actions/main/in/PlayNextTrack"; diff --git a/src/ivrinput/ivrinput_action.h b/src/ivrinput/ivrinput_action.h index f3fe439..09ca000 100644 --- a/src/ivrinput/ivrinput_action.h +++ b/src/ivrinput/ivrinput_action.h @@ -4,6 +4,11 @@ namespace input { +/*! +The type of function that should be called to get data for the action. +The IVRInput API does not give explicit warnings when the wrong functions are +called. This enum is an attempt at runtime checking. +*/ enum class ActionType { Undefined, @@ -11,6 +16,10 @@ enum class ActionType Analog, }; +/*! +Represents a single action from the actions manifest. Should be instantiated +with a name similar to that of the one in the actions manifest. +*/ class Action { public: @@ -25,14 +34,24 @@ public: << "'. OpenVR Error: " << error; } } + /*! + An API internal handle that identifies an action. + */ vr::VRActionHandle_t handle() const noexcept { return m_handle; } + /*! + The actions manfiest name of the action. Used for error reporting. + */ std::string name() const noexcept { return m_name; } + /*! + The type of the action. Used for runtime checking that the wrong functions + aren't called. + */ ActionType type() const noexcept { return m_type; diff --git a/src/ivrinput/ivrinput_action_set.h b/src/ivrinput/ivrinput_action_set.h index 66b35a0..70b2e5f 100644 --- a/src/ivrinput/ivrinput_action_set.h +++ b/src/ivrinput/ivrinput_action_set.h @@ -4,6 +4,9 @@ namespace input { +/*! +Represents an action set from the action manifest. +*/ class ActionSet { public: @@ -16,10 +19,16 @@ public: << "'. OpenVR Error: " << error; } } + /*! + The actions manfiest name of the set. Used for error reporting. + */ std::string name() { return m_name; } + /*! + An API internal handle that identifies a set. + */ vr::VRActionSetHandle_t handle() { return m_handle; diff --git a/src/overlaycontroller.cpp b/src/overlaycontroller.cpp index 1f94e98..314b068 100644 --- a/src/overlaycontroller.cpp +++ b/src/overlaycontroller.cpp @@ -476,7 +476,7 @@ void OverlayController::OnTimeoutPumpEvents() if ( !vr::VRSystem() ) return; - m_actions.Loop(); + m_actions.UpdateStates(); if ( m_actions.nextSong() ) {