added options for both hands (default), all devices, short pulse, and fixed touch timing mechanism

This commit is contained in:
SamGondelman 2016-06-06 15:03:08 -07:00
parent afca0ec2c9
commit e7743cd8e2
11 changed files with 105 additions and 41 deletions

View file

@ -31,6 +31,12 @@ namespace controller {
class Endpoint;
using EndpointPointer = std::shared_ptr<Endpoint>;
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

View file

@ -140,8 +140,22 @@ namespace controller {
return DependencyManager::get<UserInputMapper>()->getActionNames();
}
bool ScriptingInterface::triggerHapticPulse(unsigned int device, float strength, float duration, bool leftHand) const {
return DependencyManager::get<UserInputMapper>()->triggerHapticPulse(device, strength, duration, leftHand);
bool ScriptingInterface::triggerHapticPulse(float strength, float duration, controller::Hand hand) const {
return DependencyManager::get<UserInputMapper>()->triggerHapticPulse(strength, duration, hand);
}
bool ScriptingInterface::triggerShortHapticPulse(float strength, controller::Hand hand) const {
const float SHORT_HAPTIC_DURATION_MS = 250.0f;
return DependencyManager::get<UserInputMapper>()->triggerHapticPulse(strength, SHORT_HAPTIC_DURATION_MS, hand);
}
bool ScriptingInterface::triggerHapticPulseOnDevice(unsigned int device, float strength, float duration, controller::Hand hand) const {
return DependencyManager::get<UserInputMapper>()->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<UserInputMapper>()->triggerHapticPulseOnDevice(device, strength, SHORT_HAPTIC_DURATION_MS, hand);
}
void ScriptingInterface::updateMaps() {

View file

@ -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);

View file

@ -336,10 +336,19 @@ QVector<QString> 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<Action>();
int inputMetaTypeId = qRegisterMetaType<Input>();
int inputPairMetaTypeId = qRegisterMetaType<Input::NamedPair>();
int poseMetaTypeId = qRegisterMetaType<controller::Pose>("Pose");
int handMetaTypeId = qRegisterMetaType<controller::Hand>();
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<QVector<Action> >(engine);
qScriptRegisterSequenceMetaType<Input::NamedVector>(engine);
qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue);
qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue);
qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue);
qScriptRegisterMetaType(engine, handToScriptValue, handFromScriptValue);
qScriptRegisterMetaType(engine, Pose::toScriptValue, Pose::fromScriptValue);
}

View file

@ -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<controller::Input::NamedPair>)
Q_DECLARE_METATYPE(controller::Input)
Q_DECLARE_METATYPE(controller::Action)
Q_DECLARE_METATYPE(QVector<controller::Action>)
Q_DECLARE_METATYPE(controller::Hand)
// Cheating.
using UserInputMapper = controller::UserInputMapper;

View file

@ -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;
}

View file

@ -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();

View file

@ -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) {

View file

@ -10,7 +10,6 @@
#define hifi__OculusControllerManager
#include <QObject>
#include <QTimer>
#include <unordered_set>
#include <GLMHelpers.h>
@ -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<std::recursive_mutex>;
template <typename F>
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;
};

View file

@ -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;

View file

@ -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;