Move ivrinput into openvr folder

Doesn't make sense for it to have it's own folder when there's an openvr
folder now.
This commit is contained in:
Vasily
2019-03-10 23:12:26 +01:00
committed by username223
parent b7ff972997
commit dd5ae97b62
8 changed files with 7 additions and 8 deletions
+345
View File
@@ -0,0 +1,345 @@
#include "ivrinput.h"
#include <openvr.h>
#include <iostream>
#include <QStandardPaths>
#include <easylogging++.h>
namespace input
{
/*!
Wrapper around the IVRInput GetDigitalActionData 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 )
{
LOG( ERROR )
<< "Action was passed to IVRInput getDigitalActionData without "
"being a digital type. Action: "
<< action.name();
throw std::runtime_error(
"Action was passed to IVRInput getDigitalActionData without being "
"a digital type. See log for details." );
}
vr::InputDigitalActionData_t handleData = {};
const auto error = vr::VRInput()->GetDigitalActionData(
action.handle(),
&handleData,
sizeof( handleData ),
vr::k_ulInvalidInputValueHandle );
if ( error != vr::EVRInputError::VRInputError_None )
{
LOG( ERROR ) << "Error getting IVRInput Digital Action Data for handle "
<< action.name() << ". SteamVR Error: " << error;
}
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 )
{
LOG( ERROR )
<< "Action was passed to IVRInput getAnalogActionData without "
"being an analog type. Action: "
<< action.name();
throw std::runtime_error(
"Action was passed to IVRInput getAnalogActionData without being "
"an analog type. See log for details." );
}
vr::InputAnalogActionData_t handleData = {};
const auto error
= vr::VRInput()->GetAnalogActionData( action.handle(),
&handleData,
sizeof( handleData ),
vr::k_ulInvalidInputValueHandle );
if ( error != vr::EVRInputError::VRInputError_None )
{
LOG( ERROR ) << "Error getting IVRInput Digital Action Data for handle "
<< action.name() << ". SteamVR Error: " << error;
}
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 );
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 );
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 ),
m_previousTrack( input_strings::k_actionPreviousTrack,
ActionType::Digital ),
m_pausePlayTrack( input_strings::k_actionPausePlayTrack,
ActionType::Digital ),
m_stopTrack( input_strings::k_actionStopTrack, ActionType::Digital ),
m_leftHandSpaceTurn( input_strings::k_actionLeftHandSpaceTurn,
ActionType::Digital ),
m_rightHandSpaceTurn( input_strings::k_actionRightHandSpaceTurn,
ActionType::Digital ),
m_leftHandSpaceDrag( input_strings::k_actionLeftHandSpaceDrag,
ActionType::Digital ),
m_rightHandSpaceDrag( input_strings::k_actionRightHandSpaceDrag,
ActionType::Digital ),
m_optionalOverrideLeftHandSpaceTurn(
input_strings::k_actionOptionalOverrideLeftHandSpaceTurn,
ActionType::Digital ),
m_optionalOverrideRightHandSpaceTurn(
input_strings::k_actionOptionalOverrideRightHandSpaceTurn,
ActionType::Digital ),
m_optionalOverrideLeftHandSpaceDrag(
input_strings::k_actionOptionalOverrideLeftHandSpaceDrag,
ActionType::Digital ),
m_optionalOverrideRightHandSpaceDrag(
input_strings::k_actionOptionalOverrideRightHandSpaceDrag,
ActionType::Digital ),
m_swapSpaceDragToLeftHandOverride(
input_strings::k_actionSwapSpaceDragToLeftHandOverride,
ActionType::Digital ),
m_swapSpaceDragToRightHandOverride(
input_strings::k_actionSwapSpaceDragToRightHandOverride,
ActionType::Digital ),
m_gravityToggle( input_strings::k_actionGravityToggle,
ActionType::Digital ),
m_heightToggle( input_strings::k_actionHeightToggle,
ActionType::Digital ),
m_resetOffsets( input_strings::k_actionResetOffsets,
ActionType::Digital ),
m_snapTurnLeft( input_strings::k_actionSnapTurnLeft,
ActionType::Digital ),
m_snapTurnRight( input_strings::k_actionSnapTurnRight,
ActionType::Digital ),
m_xAxisLockToggle( input_strings::k_actionXAxisLockToggle,
ActionType::Digital ),
m_yAxisLockToggle( input_strings::k_actionYAxisLockToggle,
ActionType::Digital ),
m_zAxisLockToggle( input_strings::k_actionZAxisLockToggle,
ActionType::Digital ),
m_pushToTalk( input_strings::k_actionPushToTalk, ActionType::Digital )
{
m_activeActionSet.ulActionSet = m_mainSet.handle();
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 );
}
/*!
Returns true if the previous 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::previousSong()
{
return isDigitalActionActivatedOnce( m_previousTrack );
}
/*!
Returns true if media playback should be paused/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::pausePlaySong()
{
return isDigitalActionActivatedOnce( m_pausePlayTrack );
}
/*!
Returns true if media playback should be stopped.
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::stopSong()
{
return isDigitalActionActivatedOnce( m_stopTrack );
}
bool SteamIVRInput::leftHandSpaceTurn()
{
return isDigitalActionActivatedConstant( m_leftHandSpaceTurn );
}
bool SteamIVRInput::rightHandSpaceTurn()
{
return isDigitalActionActivatedConstant( m_rightHandSpaceTurn );
}
bool SteamIVRInput::leftHandSpaceDrag()
{
return isDigitalActionActivatedConstant( m_leftHandSpaceDrag );
}
bool SteamIVRInput::rightHandSpaceDrag()
{
return isDigitalActionActivatedConstant( m_rightHandSpaceDrag );
}
bool SteamIVRInput::optionalOverrideLeftHandSpaceTurn()
{
return isDigitalActionActivatedConstant(
m_optionalOverrideLeftHandSpaceTurn );
}
bool SteamIVRInput::optionalOverrideRightHandSpaceTurn()
{
return isDigitalActionActivatedConstant(
m_optionalOverrideRightHandSpaceTurn );
}
bool SteamIVRInput::optionalOverrideLeftHandSpaceDrag()
{
return isDigitalActionActivatedConstant(
m_optionalOverrideLeftHandSpaceDrag );
}
bool SteamIVRInput::optionalOverrideRightHandSpaceDrag()
{
return isDigitalActionActivatedConstant(
m_optionalOverrideRightHandSpaceDrag );
}
bool SteamIVRInput::swapSpaceDragToLeftHandOverride()
{
return isDigitalActionActivatedConstant(
m_swapSpaceDragToLeftHandOverride );
}
bool SteamIVRInput::swapSpaceDragToRightHandOverride()
{
return isDigitalActionActivatedConstant(
m_swapSpaceDragToRightHandOverride );
}
bool SteamIVRInput::gravityToggle()
{
return isDigitalActionActivatedOnce( m_gravityToggle );
}
bool SteamIVRInput::heightToggle()
{
return isDigitalActionActivatedOnce( m_heightToggle );
}
bool SteamIVRInput::resetOffsets()
{
return isDigitalActionActivatedOnce( m_resetOffsets );
}
bool SteamIVRInput::snapTurnLeft()
{
return isDigitalActionActivatedOnce( m_snapTurnLeft );
}
bool SteamIVRInput::snapTurnRight()
{
return isDigitalActionActivatedOnce( m_snapTurnRight );
}
bool SteamIVRInput::xAxisLockToggle()
{
return isDigitalActionActivatedOnce( m_xAxisLockToggle );
}
bool SteamIVRInput::yAxisLockToggle()
{
return isDigitalActionActivatedOnce( m_yAxisLockToggle );
}
bool SteamIVRInput::zAxisLockToggle()
{
return isDigitalActionActivatedOnce( m_zAxisLockToggle );
}
bool SteamIVRInput::pushToTalk()
{
return isDigitalActionActivatedConstant( m_pushToTalk );
}
/*!
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;
const auto error = vr::VRInput()->UpdateActionState(
&m_activeActionSet, sizeof( m_activeActionSet ), numberOfSets );
if ( error != vr::EVRInputError::VRInputError_None )
{
LOG( ERROR )
<< "Error during IVRInput action state update. OpenVR Error: "
<< error;
}
}
} // namespace input
+165
View File
@@ -0,0 +1,165 @@
#pragma once
#include <openvr.h>
#include "ivrinput_action.h"
#include "ivrinput_manifest.h"
#include "ivrinput_action_set.h"
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 UpdateStates();
bool nextSong();
bool previousSong();
bool pausePlaySong();
bool stopSong();
bool leftHandSpaceTurn();
bool rightHandSpaceTurn();
bool leftHandSpaceDrag();
bool rightHandSpaceDrag();
bool optionalOverrideLeftHandSpaceTurn();
bool optionalOverrideRightHandSpaceTurn();
bool optionalOverrideLeftHandSpaceDrag();
bool optionalOverrideRightHandSpaceDrag();
bool swapSpaceDragToLeftHandOverride();
bool swapSpaceDragToRightHandOverride();
bool gravityToggle();
bool heightToggle();
bool resetOffsets();
bool snapTurnLeft();
bool snapTurnRight();
bool xAxisLockToggle();
bool yAxisLockToggle();
bool zAxisLockToggle();
bool pushToTalk();
// 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.
// They are declared public because compilers will give wrong error messages
// if they are private.
// Copy constructor
SteamIVRInput( const SteamIVRInput& ) = delete;
// Copy assignment
SteamIVRInput& operator=( const SteamIVRInput& ) = delete;
// Move constructor
SteamIVRInput( SteamIVRInput&& ) = delete;
// Move assignment
SteamIVRInput& operator=( const SteamIVRInput&& ) = delete;
private:
Manifest m_manifest;
ActionSet m_mainSet;
vr::VRActiveActionSet_t m_activeActionSet = {};
// Music player bindings
Action m_nextTrack;
Action m_previousTrack;
Action m_pausePlayTrack;
Action m_stopTrack;
// Space bindings
Action m_leftHandSpaceTurn;
Action m_rightHandSpaceTurn;
Action m_leftHandSpaceDrag;
Action m_rightHandSpaceDrag;
Action m_optionalOverrideLeftHandSpaceTurn;
Action m_optionalOverrideRightHandSpaceTurn;
Action m_optionalOverrideLeftHandSpaceDrag;
Action m_optionalOverrideRightHandSpaceDrag;
Action m_swapSpaceDragToLeftHandOverride;
Action m_swapSpaceDragToRightHandOverride;
Action m_gravityToggle;
Action m_heightToggle;
Action m_resetOffsets;
Action m_snapTurnLeft;
Action m_snapTurnRight;
Action m_xAxisLockToggle;
Action m_yAxisLockToggle;
Action m_zAxisLockToggle;
// Push To Talk
Action m_pushToTalk;
};
/*!
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/NextTrack";
constexpr auto k_actionPreviousTrack = "/actions/main/in/PreviousTrack";
constexpr auto k_actionPausePlayTrack = "/actions/main/in/PausePlayTrack";
constexpr auto k_actionStopTrack = "/actions/main/in/StopTrack";
constexpr auto k_actionLeftHandSpaceTurn
= "/actions/main/in/LeftHandSpaceTurn";
constexpr auto k_actionRightHandSpaceTurn
= "/actions/main/in/RightHandSpaceTurn";
constexpr auto k_actionLeftHandSpaceDrag
= "/actions/main/in/LeftHandSpaceDrag";
constexpr auto k_actionRightHandSpaceDrag
= "/actions/main/in/RightHandSpaceDrag";
constexpr auto k_actionOptionalOverrideLeftHandSpaceTurn
= "/actions/main/in/OptionalOverrideLeftHandSpaceTurn";
constexpr auto k_actionOptionalOverrideRightHandSpaceTurn
= "/actions/main/in/OptionalOverrideRightHandSpaceTurn";
constexpr auto k_actionOptionalOverrideLeftHandSpaceDrag
= "/actions/main/in/OptionalOverrideLeftHandSpaceDrag";
constexpr auto k_actionOptionalOverrideRightHandSpaceDrag
= "/actions/main/in/OptionalOverrideRightHandSpaceDrag";
constexpr auto k_actionSwapSpaceDragToLeftHandOverride
= "/actions/main/in/SwapSpaceDragToLeftHandOverride";
constexpr auto k_actionSwapSpaceDragToRightHandOverride
= "/actions/main/in/SwapSpaceDragToRightHandOverride";
constexpr auto k_actionGravityToggle = "/actions/main/in/GravityToggle";
constexpr auto k_actionHeightToggle = "/actions/main/in/HeightToggle";
constexpr auto k_actionResetOffsets = "/actions/main/in/ResetOffsets";
constexpr auto k_actionSnapTurnLeft = "/actions/main/in/SnapTurnLeft";
constexpr auto k_actionSnapTurnRight = "/actions/main/in/SnapTurnRight";
constexpr auto k_actionXAxisLockToggle = "/actions/main/in/XAxisLockToggle";
constexpr auto k_actionYAxisLockToggle = "/actions/main/in/YAxisLockToggle";
constexpr auto k_actionZAxisLockToggle = "/actions/main/in/ZAxisLockToggle";
constexpr auto k_actionPushToTalk = "/actions/main/in/PushToTalk";
constexpr auto k_setMain = "/actions/main";
} // namespace input_strings
} // namespace input
+66
View File
@@ -0,0 +1,66 @@
#pragma once
#include <openvr.h>
#include <easylogging++.h>
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,
Digital,
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:
Action( const char* const actionName, const ActionType type )
: m_name( actionName ), m_type( type )
{
auto error = vr::VRInput()->GetActionHandle( actionName, &m_handle );
if ( error != vr::EVRInputError::VRInputError_None )
{
LOG( ERROR ) << "Error getting handle for '" << actionName
<< "'. 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;
}
private:
vr::VRActionHandle_t m_handle = 0;
const std::string m_name;
const ActionType m_type = ActionType::Undefined;
};
} // namespace input
+42
View File
@@ -0,0 +1,42 @@
#pragma once
#include <openvr.h>
#include <easylogging++.h>
namespace input
{
/*!
Represents an action set from the action manifest.
*/
class ActionSet
{
public:
ActionSet( const char* setName ) : m_name( setName )
{
auto error = vr::VRInput()->GetActionSetHandle( setName, &m_handle );
if ( error != vr::EVRInputError::VRInputError_None )
{
LOG( ERROR ) << "Error getting handle for '" << setName
<< "'. 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;
}
private:
const std::string m_name;
vr::VRActionSetHandle_t m_handle = 0;
};
} // namespace input
+44
View File
@@ -0,0 +1,44 @@
#pragma once
#include <QStandardPaths>
#include <openvr.h>
#include <easylogging++.h>
namespace input
{
/*!
Initializes IVRInput to point at the correct manifest. Can't be done in the
constructor body since objects being initialized require this to be set.
*/
class Manifest
{
public:
Manifest()
{
QString actionManifestPath = QStandardPaths::locate(
QStandardPaths::AppDataLocation,
QStringLiteral( "action_manifest.json" ) );
auto error = vr::VRInput()->SetActionManifestPath(
actionManifestPath.toStdString().c_str() );
if ( error != vr::EVRInputError::VRInputError_None )
{
LOG( ERROR ) << "Error setting action manifest path: "
<< actionManifestPath << ". OpenVR Error: " << error;
}
}
// Explicitly deleted because this object should do nothing but run the
// constructor during initialization.
// Destructor left blank on purpose since there are no terminating calls.
~Manifest() {}
// Copy constructor
Manifest( const Manifest& ) = delete;
// Copy assignment
Manifest& operator=( const Manifest& ) = delete;
// Move constructor
Manifest( const Manifest&& ) = delete;
// Move assignment
Manifest& operator=( const Manifest&& ) = delete;
};
} // namespace input
+1 -1
View File
@@ -3,7 +3,7 @@
#include <QMessageBox>
#include "openvr_init.h"
#include <easylogging++.h>
#include "../ivrinput/ivrinput_manifest.h"
#include "../openvr/ivrinput_manifest.h"
namespace openvr_init
{