From e7743cd8e2603927da7099ea6e82e696e237fd1c Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 6 Jun 2016 15:03:08 -0700 Subject: [PATCH] added options for both hands (default), all devices, short pulse, and fixed touch timing mechanism --- .../controllers/src/controllers/InputDevice.h | 8 +++- .../src/controllers/ScriptingInterface.cpp | 18 +++++++- .../src/controllers/ScriptingInterface.h | 5 ++- .../src/controllers/UserInputMapper.cpp | 25 ++++++++++- .../src/controllers/UserInputMapper.h | 4 +- plugins/hifiSdl2/src/Joystick.cpp | 2 +- plugins/hifiSdl2/src/Joystick.h | 2 +- .../oculus/src/OculusControllerManager.cpp | 45 ++++++++++++------- plugins/oculus/src/OculusControllerManager.h | 15 +++++-- plugins/openvr/src/ViveControllerManager.cpp | 10 ++--- plugins/openvr/src/ViveControllerManager.h | 12 ++--- 11 files changed, 105 insertions(+), 41 deletions(-) diff --git a/libraries/controllers/src/controllers/InputDevice.h b/libraries/controllers/src/controllers/InputDevice.h index cc158497e0..10e1a104f4 100644 --- a/libraries/controllers/src/controllers/InputDevice.h +++ b/libraries/controllers/src/controllers/InputDevice.h @@ -31,6 +31,12 @@ namespace controller { class Endpoint; using EndpointPointer = std::shared_ptr; +enum Hand { + LEFT = 0, + RIGHT, + BOTH +}; + // NOTE: If something inherits from both InputDevice and InputPlugin, InputPlugin must go first. // e.g. class Example : public InputPlugin, public InputDevice // instead of class Example : public InputDevice, public InputPlugin @@ -56,7 +62,7 @@ public: const QString& getName() const { return _name; } // By default, Input Devices do not support haptics - virtual bool triggerHapticPulse(float strength, float duration, bool leftHand) { return false; } + virtual bool triggerHapticPulse(float strength, float duration, controller::Hand hand) { return false; } // Update call MUST be called once per simulation loop // It takes care of updating the action states and deltas diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp index 97b7a9ddd9..78e9378c18 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.cpp +++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp @@ -140,8 +140,22 @@ namespace controller { return DependencyManager::get()->getActionNames(); } - bool ScriptingInterface::triggerHapticPulse(unsigned int device, float strength, float duration, bool leftHand) const { - return DependencyManager::get()->triggerHapticPulse(device, strength, duration, leftHand); + bool ScriptingInterface::triggerHapticPulse(float strength, float duration, controller::Hand hand) const { + return DependencyManager::get()->triggerHapticPulse(strength, duration, hand); + } + + bool ScriptingInterface::triggerShortHapticPulse(float strength, controller::Hand hand) const { + const float SHORT_HAPTIC_DURATION_MS = 250.0f; + return DependencyManager::get()->triggerHapticPulse(strength, SHORT_HAPTIC_DURATION_MS, hand); + } + + bool ScriptingInterface::triggerHapticPulseOnDevice(unsigned int device, float strength, float duration, controller::Hand hand) const { + return DependencyManager::get()->triggerHapticPulseOnDevice(device, strength, duration, hand); + } + + bool ScriptingInterface::triggerShortHapticPulseOnDevice(unsigned int device, float strength, controller::Hand hand) const { + const float SHORT_HAPTIC_DURATION_MS = 250.0f; + return DependencyManager::get()->triggerHapticPulseOnDevice(device, strength, SHORT_HAPTIC_DURATION_MS, hand); } void ScriptingInterface::updateMaps() { diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h index 015ec25454..713e864561 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.h +++ b/libraries/controllers/src/controllers/ScriptingInterface.h @@ -84,7 +84,10 @@ namespace controller { Q_INVOKABLE Pose getPoseValue(const int& source) const; Q_INVOKABLE Pose getPoseValue(StandardPoseChannel source, uint16_t device = 0) const; - Q_INVOKABLE bool triggerHapticPulse(unsigned int device, float strength, float duration, bool leftHand = true) const; + Q_INVOKABLE bool triggerHapticPulse(float strength, float duration, controller::Hand hand = BOTH) const; + Q_INVOKABLE bool triggerShortHapticPulse(float strength, controller::Hand hand = BOTH) const; + Q_INVOKABLE bool triggerHapticPulseOnDevice(unsigned int device, float strength, float duration, controller::Hand hand = BOTH) const; + Q_INVOKABLE bool triggerShortHapticPulseOnDevice(unsigned int device, float strength, controller::Hand hand = BOTH) const; Q_INVOKABLE QObject* newMapping(const QString& mappingName = QUuid::createUuid().toString()); Q_INVOKABLE void enableMapping(const QString& mappingName, bool enable = true); diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp index c7c62ad7d9..921f78c613 100755 --- a/libraries/controllers/src/controllers/UserInputMapper.cpp +++ b/libraries/controllers/src/controllers/UserInputMapper.cpp @@ -336,10 +336,19 @@ QVector UserInputMapper::getActionNames() const { return result; } -bool UserInputMapper::triggerHapticPulse(uint16 deviceID, float strength, float duration, bool leftHand) { +bool UserInputMapper::triggerHapticPulse(float strength, float duration, controller::Hand hand) { + Locker locker(_lock); + bool toReturn = false; + for (auto device : _registeredDevices) { + toReturn = toReturn || device.second->triggerHapticPulse(strength, duration, hand); + } + return toReturn; +} + +bool UserInputMapper::triggerHapticPulseOnDevice(uint16 deviceID, float strength, float duration, controller::Hand hand) { Locker locker(_lock); if (_registeredDevices.find(deviceID) != _registeredDevices.end()) { - return _registeredDevices[deviceID]->triggerHapticPulse(strength, duration, leftHand); + return _registeredDevices[deviceID]->triggerHapticPulse(strength, duration, hand); } return false; } @@ -348,6 +357,7 @@ int actionMetaTypeId = qRegisterMetaType(); int inputMetaTypeId = qRegisterMetaType(); int inputPairMetaTypeId = qRegisterMetaType(); int poseMetaTypeId = qRegisterMetaType("Pose"); +int handMetaTypeId = qRegisterMetaType(); QScriptValue inputToScriptValue(QScriptEngine* engine, const Input& input); void inputFromScriptValue(const QScriptValue& object, Input& input); @@ -355,6 +365,8 @@ QScriptValue actionToScriptValue(QScriptEngine* engine, const Action& action); void actionFromScriptValue(const QScriptValue& object, Action& action); QScriptValue inputPairToScriptValue(QScriptEngine* engine, const Input::NamedPair& inputPair); void inputPairFromScriptValue(const QScriptValue& object, Input::NamedPair& inputPair); +QScriptValue handToScriptValue(QScriptEngine* engine, const controller::Hand& hand); +void handFromScriptValue(const QScriptValue& object, controller::Hand& hand); QScriptValue inputToScriptValue(QScriptEngine* engine, const Input& input) { QScriptValue obj = engine->newObject(); @@ -393,12 +405,21 @@ void inputPairFromScriptValue(const QScriptValue& object, Input::NamedPair& inpu inputPair.second = QString(object.property("inputName").toVariant().toString()); } +QScriptValue handToScriptValue(QScriptEngine* engine, const controller::Hand& hand) { + return engine->newVariant((int)hand); +} + +void handFromScriptValue(const QScriptValue& object, controller::Hand& hand) { + hand = Hand(object.toVariant().toInt()); +} + void UserInputMapper::registerControllerTypes(QScriptEngine* engine) { qScriptRegisterSequenceMetaType >(engine); qScriptRegisterSequenceMetaType(engine); qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue); qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue); qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue); + qScriptRegisterMetaType(engine, handToScriptValue, handFromScriptValue); qScriptRegisterMetaType(engine, Pose::toScriptValue, Pose::fromScriptValue); } diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h index b23657fff7..811b621b09 100644 --- a/libraries/controllers/src/controllers/UserInputMapper.h +++ b/libraries/controllers/src/controllers/UserInputMapper.h @@ -89,7 +89,8 @@ namespace controller { void setActionState(Action action, float value) { _actionStates[toInt(action)] = value; } void deltaActionState(Action action, float delta) { _actionStates[toInt(action)] += delta; } void setActionState(Action action, const Pose& value) { _poseStates[toInt(action)] = value; } - bool triggerHapticPulse(uint16 deviceID, float strength, float duration, bool leftHand); + bool triggerHapticPulse(float strength, float duration, controller::Hand hand); + bool triggerHapticPulseOnDevice(uint16 deviceID, float strength, float duration, controller::Hand hand); static Input makeStandardInput(controller::StandardButtonChannel button); static Input makeStandardInput(controller::StandardAxisChannel axis); @@ -200,6 +201,7 @@ Q_DECLARE_METATYPE(QVector) Q_DECLARE_METATYPE(controller::Input) Q_DECLARE_METATYPE(controller::Action) Q_DECLARE_METATYPE(QVector) +Q_DECLARE_METATYPE(controller::Hand) // Cheating. using UserInputMapper = controller::UserInputMapper; diff --git a/plugins/hifiSdl2/src/Joystick.cpp b/plugins/hifiSdl2/src/Joystick.cpp index cf7dde371b..c20670d4bb 100644 --- a/plugins/hifiSdl2/src/Joystick.cpp +++ b/plugins/hifiSdl2/src/Joystick.cpp @@ -67,7 +67,7 @@ void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) { } } -bool Joystick::triggerHapticPulse(float strength, float duration, bool leftHand) { +bool Joystick::triggerHapticPulse(float strength, float duration, controller::Hand hand) { if (SDL_HapticRumblePlay(_sdlHaptic, strength, duration) != 0) { return false; } diff --git a/plugins/hifiSdl2/src/Joystick.h b/plugins/hifiSdl2/src/Joystick.h index 4f785f85ce..b37d22de39 100644 --- a/plugins/hifiSdl2/src/Joystick.h +++ b/plugins/hifiSdl2/src/Joystick.h @@ -37,7 +37,7 @@ public: virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override; virtual void focusOutEvent() override; - bool triggerHapticPulse(float strength, float duration, bool leftHand) override; + bool triggerHapticPulse(float strength, float duration, controller::Hand hand) override; Joystick() : InputDevice("GamePad") {} ~Joystick(); diff --git a/plugins/oculus/src/OculusControllerManager.cpp b/plugins/oculus/src/OculusControllerManager.cpp index 3151db1d90..2e7044bd69 100644 --- a/plugins/oculus/src/OculusControllerManager.cpp +++ b/plugins/oculus/src/OculusControllerManager.cpp @@ -55,11 +55,6 @@ bool OculusControllerManager::activate() { userInputMapper->registerDevice(_touch); } - _leftHapticTimer.setSingleShot(true); - _rightHapticTimer.setSingleShot(true); - connect(&_leftHapticTimer, SIGNAL(timeout()), this, SLOT(stopHapticPulse(true))); - connect(&_rightHapticTimer, SIGNAL(timeout()), this, SLOT(stopHapticPulse(false))); - return true; } @@ -221,6 +216,21 @@ void OculusControllerManager::TouchDevice::update(float deltaTime, const control _buttonPressedMap.insert(pair.second); } } + + // Haptics + { + Locker locker(_lock); + if (_leftHapticDuration > 0.0f) { + _leftHapticDuration -= deltaTime; + } else { + stopHapticPulse(true); + } + if (_rightHapticDuration > 0.0f) { + _rightHapticDuration -= deltaTime; + } else { + stopHapticPulse(false); + } + } } void OculusControllerManager::TouchDevice::focusOutEvent() { @@ -239,19 +249,22 @@ void OculusControllerManager::TouchDevice::handlePose(float deltaTime, pose.velocity = toGlm(handPose.LinearVelocity); } -bool OculusControllerManager::TouchDevice::triggerHapticPulse(float strength, float duration, bool leftHand) { - auto handType = (leftHand ? ovrControllerType_LTouch : ovrControllerType_RTouch); - if (ovr_SetControllerVibration(_parent._session, handType, 1.0f, strength) != ovrSuccess) { - return false; +bool OculusControllerManager::TouchDevice::triggerHapticPulse(float strength, float duration, controller::Hand hand) { + Locker locker(_lock); + bool toReturn = true; + if (hand == controller::BOTH || hand == controller::LEFT) { + if (ovr_SetControllerVibration(_parent._session, ovrControllerType_LTouch, 1.0f, strength) != ovrSuccess) { + toReturn = false; + } + _leftHapticDuration = duration; } - - if (leftHand) { - _parent._leftHapticTimer.start(duration); - } else { - _parent._rightHapticTimer.start(duration); + if (hand == controller::BOTH || hand == controller::RIGHT) { + if (ovr_SetControllerVibration(_parent._session, ovrControllerType_RTouch, 1.0f, strength) != ovrSuccess) { + toReturn = false; + } + _rightHapticDuration = duration; } - - return true; + return toReturn; } void OculusControllerManager::TouchDevice::stopHapticPulse(bool leftHand) { diff --git a/plugins/oculus/src/OculusControllerManager.h b/plugins/oculus/src/OculusControllerManager.h index e62c5f45ea..244fe41f67 100644 --- a/plugins/oculus/src/OculusControllerManager.h +++ b/plugins/oculus/src/OculusControllerManager.h @@ -10,7 +10,6 @@ #define hifi__OculusControllerManager #include -#include #include #include @@ -68,20 +67,28 @@ private: void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override; void focusOutEvent() override; - bool triggerHapticPulse(float strength, float duration, bool leftHand) override; + bool triggerHapticPulse(float strength, float duration, controller::Hand hand) override; private: void stopHapticPulse(bool leftHand); void handlePose(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, ovrHandType hand, const ovrPoseStatef& handPose); int _trackedControllers { 0 }; + + // perform an action when the TouchDevice mutex is acquired. + using Locker = std::unique_lock; + template + void withLock(F&& f) { Locker locker(_lock); f(); } + + float _leftHapticDuration { 0.0f }; + float _rightHapticDuration { 0.0f }; + mutable std::recursive_mutex _lock; + friend class OculusControllerManager; }; ovrSession _session { nullptr }; ovrInputState _inputState {}; RemoteDevice::Pointer _remote; - QTimer _leftHapticTimer; - QTimer _rightHapticTimer; TouchDevice::Pointer _touch; static const QString NAME; }; diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 39b5e620ad..27b4887edd 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -452,12 +452,13 @@ void ViveControllerManager::InputDevice::handlePoseEvent(float deltaTime, const _poseStateMap[isLeftHand ? controller::LEFT_HAND : controller::RIGHT_HAND] = avatarPose.transform(controllerToAvatar); } -bool ViveControllerManager::InputDevice::triggerHapticPulse(float strength, float duration, bool leftHand) { +bool ViveControllerManager::InputDevice::triggerHapticPulse(float strength, float duration, controller::Hand hand) { Locker locker(_lock); - if (leftHand) { + if (hand == controller::BOTH || hand == controller::LEFT) { _leftHapticStrength = strength; _leftHapticDuration = duration; - } else { + } + if (hand == controller::BOTH || hand == controller::RIGHT) { _rightHapticStrength = strength; _rightHapticDuration = duration; } @@ -481,9 +482,6 @@ void ViveControllerManager::InputDevice::hapticsHelper(float deltaTime, bool lef _system->TriggerHapticPulse(deviceIndex, 0, hapticTime); } - // Must wait 5 ms before triggering another pulse on this controller - // https://github.com/ValveSoftware/openvr/wiki/IVRSystem::TriggerHapticPulse - const float HAPTIC_RESET_TIME = 5.0f; float remainingHapticTime = duration - (hapticTime / 1000.0f + deltaTime * 1000.0f); // in milliseconds if (leftHand) { _leftHapticDuration = remainingHapticTime; diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 9bdbd0370e..3a2ef1573f 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -48,7 +48,7 @@ public: private: class InputDevice : public controller::InputDevice { public: - InputDevice(vr::IVRSystem*& system) : controller::InputDevice("Vive"), _system(system), _leftHapticDuration(0.0f), _rightHapticDuration(0.0f) {} + InputDevice(vr::IVRSystem*& system) : controller::InputDevice("Vive"), _system(system) {} private: // Device functions controller::Input::NamedVector getAvailableInputs() const override; @@ -56,7 +56,7 @@ private: void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override; void focusOutEvent() override; - bool triggerHapticPulse(float strength, float duration, bool leftHand) override; + bool triggerHapticPulse(float strength, float duration, controller::Hand hand) override; void hapticsHelper(float deltaTime, bool leftHand); void handleHandController(float deltaTime, uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand); @@ -100,10 +100,10 @@ private: int _trackedControllers { 0 }; vr::IVRSystem*& _system; - float _leftHapticStrength; - float _leftHapticDuration; - float _rightHapticStrength; - float _rightHapticDuration; + float _leftHapticStrength { 0.0f }; + float _leftHapticDuration { 0.0f }; + float _rightHapticStrength { 0.0f }; + float _rightHapticDuration { 0.0f }; mutable std::recursive_mutex _lock; friend class ViveControllerManager;