You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
237 lines
6.6 KiB
C++
237 lines
6.6 KiB
C++
#ifndef VR_INPUT_HPP
|
|
#define VR_INPUT_HPP
|
|
|
|
#include "vrviewer.hpp"
|
|
#include "openxraction.hpp"
|
|
|
|
#include "../mwinput/inputmanagerimp.hpp"
|
|
|
|
namespace MWVR
|
|
{
|
|
/// Extension of MWInput's set of actions.
|
|
enum VrActions
|
|
{
|
|
A_VrFirst = MWInput::A_Last + 1,
|
|
A_VrMetaMenu,
|
|
A_ActivateTouch,
|
|
A_HapticsLeft,
|
|
A_HapticsRight,
|
|
A_HandPoseLeft,
|
|
A_HandPoseRight,
|
|
A_MenuUpDown,
|
|
A_MenuLeftRight,
|
|
A_MenuSelect,
|
|
A_MenuBack,
|
|
A_Recenter,
|
|
A_VrLast
|
|
};
|
|
|
|
enum class VrControlType
|
|
{
|
|
Press,
|
|
LongPress,
|
|
Hold,
|
|
Pose,
|
|
Haptic,
|
|
Axis
|
|
};
|
|
|
|
/// \brief Suggest a binding by binding an action to a path on a given hand (left or right).
|
|
struct SuggestedBinding
|
|
{
|
|
std::string path;
|
|
std::string action;
|
|
};
|
|
|
|
using SuggestedBindings = std::vector<SuggestedBinding>;
|
|
|
|
/// \brief Enumeration of action sets
|
|
enum class ActionSet
|
|
{
|
|
GUI = 0,
|
|
Gameplay = 1,
|
|
Tracking = 2,
|
|
Haptics = 3,
|
|
};
|
|
|
|
/// \brief Action for applying haptics
|
|
class HapticsAction
|
|
{
|
|
public:
|
|
HapticsAction(std::unique_ptr<OpenXRAction> xrAction) : mXRAction{ std::move(xrAction) } {};
|
|
|
|
//! Apply vibration at the given amplitude
|
|
void apply(float amplitude);
|
|
|
|
//! Convenience
|
|
operator XrAction() { return *mXRAction; }
|
|
|
|
private:
|
|
std::unique_ptr<OpenXRAction> mXRAction;
|
|
float mAmplitude{ 0.f };
|
|
};
|
|
|
|
/// \brief Action for capturing tracking information
|
|
class PoseAction
|
|
{
|
|
public:
|
|
PoseAction(std::unique_ptr<OpenXRAction> xrAction);
|
|
|
|
//! Current value of an axis or lever action
|
|
Pose value() const { return mValue; }
|
|
|
|
//! Previous value
|
|
Pose previousValue() const { return mPrevious; }
|
|
|
|
//! Convenience
|
|
operator XrAction() { return *mXRAction; }
|
|
|
|
//! Update pose value
|
|
void update(long long time);
|
|
|
|
//! Action space
|
|
XrSpace xrSpace() { return mXRSpace; }
|
|
|
|
private:
|
|
std::unique_ptr<OpenXRAction> mXRAction;
|
|
XrSpace mXRSpace;
|
|
Pose mValue{};
|
|
Pose mPrevious{};
|
|
};
|
|
|
|
/// \brief Generic action
|
|
/// \sa ButtonPressAction ButtonLongPressAction ButtonHoldAction AxisAction
|
|
class Action
|
|
{
|
|
public:
|
|
Action(int openMWAction, std::unique_ptr<OpenXRAction> xrAction) : mXRAction(std::move(xrAction)), mOpenMWAction(openMWAction) {}
|
|
virtual ~Action() {};
|
|
|
|
//! True if action changed to being released in the last update
|
|
bool isActive() const { return mActive; };
|
|
|
|
//! True if activation turned on this update (i.e. onPress)
|
|
bool onActivate() const { return mOnActivate; }
|
|
|
|
//! True if activation turned off this update (i.e. onRelease)
|
|
bool onDeactivate() const { return mOnDeactivate; }
|
|
|
|
//! OpenMW Action code of this action
|
|
int openMWActionCode() const { return mOpenMWAction; }
|
|
|
|
//! Current value of an axis or lever action
|
|
float value() const { return mValue; }
|
|
|
|
//! Previous value
|
|
float previousValue() const { return mPrevious; }
|
|
|
|
//! Update internal states. Note that subclasses maintain both mValue and mActivate to allow
|
|
//! axis and press to subtitute one another.
|
|
virtual void update() = 0;
|
|
|
|
//! Determines if an action update should be queued
|
|
virtual bool shouldQueue() const = 0;
|
|
|
|
//! Convenience
|
|
operator XrAction() { return *mXRAction; }
|
|
|
|
//! Update and queue action if applicable
|
|
void updateAndQueue(std::deque<const Action*>& queue);
|
|
|
|
protected:
|
|
std::unique_ptr<OpenXRAction> mXRAction;
|
|
int mOpenMWAction;
|
|
float mValue{ 0.f };
|
|
float mPrevious{ 0.f };
|
|
bool mActive{ false };
|
|
bool mOnActivate{ false };
|
|
bool mOnDeactivate{ false };
|
|
};
|
|
|
|
//! Action that activates once on release.
|
|
//! Times out if the button is held longer than gHoldDelay.
|
|
class ButtonPressAction : public Action
|
|
{
|
|
public:
|
|
using Action::Action;
|
|
|
|
static const XrActionType ActionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
|
|
|
|
void update() override;
|
|
|
|
virtual bool shouldQueue() const override { return onActivate() || onDeactivate(); }
|
|
|
|
bool mPressed{ false };
|
|
std::chrono::steady_clock::time_point mPressTime{};
|
|
std::chrono::steady_clock::time_point mTimeout{};
|
|
};
|
|
|
|
//! Action that activates once on a long press
|
|
//! The press time is the same as the timeout for a regular press, allowing keys with double roles.
|
|
class ButtonLongPressAction : public Action
|
|
{
|
|
public:
|
|
using Action::Action;
|
|
|
|
static const XrActionType ActionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
|
|
|
|
void update() override;
|
|
|
|
virtual bool shouldQueue() const override { return onActivate() || onDeactivate(); }
|
|
|
|
bool mPressed{ false };
|
|
bool mActivated{ false };
|
|
std::chrono::steady_clock::time_point mPressTime{};
|
|
std::chrono::steady_clock::time_point mTimein{};
|
|
};
|
|
|
|
//! Action that is active whenever the button is pressed down.
|
|
//! Useful for e.g. non-toggling sneak and automatically repeating actions
|
|
class ButtonHoldAction : public Action
|
|
{
|
|
public:
|
|
using Action::Action;
|
|
|
|
static const XrActionType ActionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
|
|
|
|
void update() override;
|
|
|
|
virtual bool shouldQueue() const override { return mActive || onDeactivate(); }
|
|
|
|
bool mPressed{ false };
|
|
};
|
|
|
|
//! Action for axis actions, such as thumbstick axes or certain triggers/squeeze levers.
|
|
//! Float axis are considered active whenever their magnitude is greater than gAxisEpsilon. This is useful
|
|
//! as a touch subtitute on levers without touch.
|
|
class AxisAction : public Action
|
|
{
|
|
public:
|
|
class Deadzone
|
|
{
|
|
public:
|
|
void applyDeadzone(float& value);
|
|
|
|
void setDeadzoneRadius(float deadzoneRadius);
|
|
|
|
private:
|
|
float mActiveRadiusInner{ 0.f };
|
|
float mActiveRadiusOuter{ 1.f };
|
|
float mActiveScale{ 1.f };
|
|
};
|
|
|
|
public:
|
|
AxisAction(int openMWAction, std::unique_ptr<OpenXRAction> xrAction, std::shared_ptr<AxisAction::Deadzone> deadzone);
|
|
|
|
static const XrActionType ActionType = XR_ACTION_TYPE_FLOAT_INPUT;
|
|
|
|
void update() override;
|
|
|
|
virtual bool shouldQueue() const override { return mActive || onDeactivate(); }
|
|
|
|
std::shared_ptr<AxisAction::Deadzone> mDeadzone;
|
|
};
|
|
}
|
|
|
|
#endif
|