diff --git a/interface/resources/qml/TestControllers.qml b/interface/resources/qml/TestControllers.qml index 388e452335..79be877aa3 100644 --- a/interface/resources/qml/TestControllers.qml +++ b/interface/resources/qml/TestControllers.qml @@ -1,171 +1,218 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.2 -import QtQuick.Layouts 1.0 -import QtQuick.Dialogs 1.0 - -import "controller" -import "controls" as HifiControls -import "styles" - -HifiControls.VrDialog { - id: root - HifiConstants { id: hifi } - title: "Controller Test" - resizable: true - contentImplicitWidth: clientArea.implicitWidth - contentImplicitHeight: clientArea.implicitHeight - backgroundColor: "beige" - - property var actions: Controller.Actions - property var standard: Controller.Standard - property var hydra: null - property var testMapping: null - property var xbox: null - - - Component.onCompleted: { - enabled = true - var xboxRegex = /^X360Controller/; - var hydraRegex = /^Hydra/; - for (var prop in Controller.Hardware) { - if(xboxRegex.test(prop)) { - root.xbox = Controller.Hardware[prop] - print("found xbox") - continue - } - if (hydraRegex.test(prop)) { - root.hydra = Controller.Hardware[prop] - print("found hydra") - continue - } - } - } - - Column { - id: clientArea - spacing: 12 - x: root.clientX - y: root.clientY - - Row { - spacing: 8 - Button { - text: "Default Mapping" - onClicked: { - var mapping = Controller.newMapping("Default"); - mapping.from(xbox.A).to(standard.A); - mapping.from(xbox.B).to(standard.B); - mapping.from(xbox.X).to(standard.X); - mapping.from(xbox.Y).to(standard.Y); - mapping.from(xbox.Up).to(standard.DU); - mapping.from(xbox.Down).to(standard.DD); - mapping.from(xbox.Left).to(standard.DL); - mapping.from(xbox.Right).to(standard.Right); - mapping.from(xbox.LB).to(standard.LB); - mapping.from(xbox.RB).to(standard.RB); - mapping.from(xbox.LS).to(standard.LS); - mapping.from(xbox.RS).to(standard.RS); - mapping.from(xbox.Start).to(standard.Start); - mapping.from(xbox.Back).to(standard.Back); - mapping.from(xbox.LY).to(standard.LY); - mapping.from(xbox.LX).to(standard.LX); - mapping.from(xbox.RY).to(standard.RY); - mapping.from(xbox.RX).to(standard.RX); - mapping.from(xbox.LT).to(standard.LT); - mapping.from(xbox.RT).to(standard.RT); - Controller.enableMapping("Default"); - enabled = false; - text = "Built" - } - } - - Button { - text: "Build Mapping" - onClicked: { - var mapping = Controller.newMapping(); - // Inverting a value - mapping.from(hydra.RY).invert().to(standard.RY); - mapping.from(hydra.RX).to(standard.RX); - mapping.from(hydra.LY).to(standard.LY); - mapping.from(hydra.LY).to(standard.LX); - // Assigning a value from a function - // mapping.from(function() { return Math.sin(Date.now() / 250); }).to(standard.RX); - // Constrainting a value to -1, 0, or 1, with a deadzone -// mapping.from(xbox.LY).deadZone(0.5).constrainToInteger().to(standard.LY); - mapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw); -// mapping.from(actions.Yaw).clamp(0, 1).invert().to(actions.YAW_RIGHT); -// mapping.from(actions.Yaw).clamp(-1, 0).to(actions.YAW_LEFT); - // mapping.modifier(keyboard.Ctrl).scale(2.0) -// mapping.from(keyboard.A).to(actions.TranslateLeft) -// mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft) -// mapping.from(keyboard.A, keyboard.Shift, keyboard.Ctrl).scale(2.0).to(actions.TurnLeft) -// // First loopbacks -// // Then non-loopbacks by constraint level (number of inputs) -// mapping.from(xbox.RX).deadZone(0.2).to(xbox.RX) -// mapping.from(standard.RB, standard.LB, keyboard.Shift).to(actions.TurnLeft) -// mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft) -// mapping.from(keyboard.W).when(keyboard.Shift).to(actions.Forward) - testMapping = mapping; - enabled = false - text = "Built" - } - } - - Button { - text: "Enable Mapping" - onClicked: root.testMapping.enable() - } - - Button { - text: "Disable Mapping" - onClicked: root.testMapping.disable() - } - - Button { - text: "Enable Mapping" - onClicked: print(Controller.getValue(root.xbox.LY)); - } - } - - Row { - Xbox { device: root.standard; label: "Standard"; width: 360 } - } - - Row { - spacing: 8 - Xbox { device: root.xbox; label: "XBox"; width: 360 } - Hydra { device: root.hydra; width: 360 } - } -// Row { -// spacing: 8 -// ScrollingGraph { -// controlId: Controller.Actions.Yaw -// label: "Yaw" -// min: -3.0 -// max: 3.0 -// size: 128 -// } -// -// ScrollingGraph { -// controlId: Controller.Actions.YAW_LEFT -// label: "Yaw Left" -// min: -3.0 -// max: 3.0 -// size: 128 -// } -// -// ScrollingGraph { -// controlId: Controller.Actions.YAW_RIGHT -// label: "Yaw Right" -// min: -3.0 -// max: 3.0 -// size: 128 -// } -// } - } -} // dialog - - - - - +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Layouts 1.0 +import QtQuick.Dialogs 1.0 + +import "controller" +import "controls" as HifiControls +import "styles" + +HifiControls.VrDialog { + id: root + HifiConstants { id: hifi } + title: "Controller Test" + resizable: true + contentImplicitWidth: clientArea.implicitWidth + contentImplicitHeight: clientArea.implicitHeight + backgroundColor: "beige" + + property var actions: Controller.Actions + property var standard: Controller.Standard + property var hydra: null + property var testMapping: null + property var xbox: null + + + Component.onCompleted: { + enabled = true + var xboxRegex = /^X360Controller/; + var hydraRegex = /^Hydra/; + for (var prop in Controller.Hardware) { + if(xboxRegex.test(prop)) { + root.xbox = Controller.Hardware[prop] + print("found xbox") + continue + } + if (hydraRegex.test(prop)) { + root.hydra = Controller.Hardware[prop] + print("found hydra") + continue + } + } + } + + Column { + id: clientArea + spacing: 12 + x: root.clientX + y: root.clientY + + Row { + spacing: 8 + Button { + text: "Standard Mapping" + onClicked: { + var mapping = Controller.newMapping("Default"); + mapping.from(standard.LX).to(actions.TranslateX); + mapping.from(standard.LY).to(actions.TranslateZ); + mapping.from(standard.RY).to(actions.Pitch); + mapping.from(standard.RX).to(actions.Yaw); + mapping.from(standard.DU).scale(0.5).to(actions.LONGITUDINAL_FORWARD); + mapping.from(standard.DD).scale(0.5).to(actions.LONGITUDINAL_BACKWARD); + mapping.from(standard.DL).scale(0.5).to(actions.LATERAL_LEFT); + mapping.from(standard.DR).scale(0.5).to(actions.LATERAL_RIGHT); + mapping.from(standard.X).to(actions.VERTICAL_DOWN); + mapping.from(standard.Y).to(actions.VERTICAL_UP); + mapping.from(standard.RT).scale(0.1).to(actions.BOOM_IN); + mapping.from(standard.LT).scale(0.1).to(actions.BOOM_OUT); + mapping.from(standard.B).to(actions.ACTION1); + mapping.from(standard.A).to(actions.ACTION2); + mapping.from(standard.RB).to(actions.SHIFT); + mapping.from(standard.Back).to(actions.TOGGLE_MUTE); + mapping.from(standard.Start).to(actions.CONTEXT_MENU); + Controller.enableMapping("Default"); + enabled = false; + text = "Standard Built" + } + } + + Button { + text: root.xbox ? "XBox Mapping" : "XBox not found" + property bool built: false + enabled: root.xbox && !built + onClicked: { + var mapping = Controller.newMapping(); + mapping.from(xbox.A).to(standard.A); + mapping.from(xbox.B).to(standard.B); + mapping.from(xbox.X).to(standard.X); + mapping.from(xbox.Y).to(standard.Y); + mapping.from(xbox.Up).to(standard.DU); + mapping.from(xbox.Down).to(standard.DD); + mapping.from(xbox.Left).to(standard.DL); + mapping.from(xbox.Right).to(standard.Right); + mapping.from(xbox.LB).to(standard.LB); + mapping.from(xbox.RB).to(standard.RB); + mapping.from(xbox.LS).to(standard.LS); + mapping.from(xbox.RS).to(standard.RS); + mapping.from(xbox.Start).to(standard.Start); + mapping.from(xbox.Back).to(standard.Back); + mapping.from(xbox.LY).to(standard.LY); + mapping.from(xbox.LX).to(standard.LX); + mapping.from(xbox.RY).to(standard.RY); + mapping.from(xbox.RX).to(standard.RX); + mapping.from(xbox.LT).to(standard.LT); + mapping.from(xbox.RT).to(standard.RT); + mapping.enable(); + built = false; + text = "XBox Built" + } + } + + Button { + text: root.hydra ? "Hydra Mapping" : "Hydra Not Found" + property bool built: false + enabled: root.hydra && !built + onClicked: { + var mapping = Controller.newMapping(); + mapping.from(hydra.LY).invert().to(standard.LY); + mapping.from(hydra.LX).to(standard.LX); + mapping.from(hydra.RY).invert().to(standard.RY); + mapping.from(hydra.RX).to(standard.RX); + mapping.from(hydra.LT).to(standard.LT); + mapping.from(hydra.RT).to(standard.RT); + mapping.enable(); + built = false; + text = "Hydra Built" + } + } + + Button { + text: "Test Mapping" + onClicked: { + var mapping = Controller.newMapping(); + // Inverting a value + mapping.from(hydra.RY).invert().to(standard.RY); + mapping.from(hydra.RX).to(standard.RX); + mapping.from(hydra.LY).to(standard.LY); + mapping.from(hydra.LX).to(standard.LX); + // Assigning a value from a function + // mapping.from(function() { return Math.sin(Date.now() / 250); }).to(standard.RX); + // Constrainting a value to -1, 0, or 1, with a deadzone +// mapping.from(xbox.LY).deadZone(0.5).constrainToInteger().to(standard.LY); + mapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw); +// mapping.from(actions.Yaw).clamp(0, 1).invert().to(actions.YAW_RIGHT); +// mapping.from(actions.Yaw).clamp(-1, 0).to(actions.YAW_LEFT); + // mapping.modifier(keyboard.Ctrl).scale(2.0) +// mapping.from(keyboard.A).to(actions.TranslateLeft) +// mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft) +// mapping.from(keyboard.A, keyboard.Shift, keyboard.Ctrl).scale(2.0).to(actions.TurnLeft) +// // First loopbacks +// // Then non-loopbacks by constraint level (number of inputs) +// mapping.from(xbox.RX).deadZone(0.2).to(xbox.RX) +// mapping.from(standard.RB, standard.LB, keyboard.Shift).to(actions.TurnLeft) +// mapping.from(keyboard.A, keyboard.Shift).to(actions.TurnLeft) +// mapping.from(keyboard.W).when(keyboard.Shift).to(actions.Forward) + testMapping = mapping; + enabled = false + text = "Built" + } + } + + Button { + text: "Enable Mapping" + onClicked: root.testMapping.enable() + } + + Button { + text: "Disable Mapping" + onClicked: root.testMapping.disable() + } + + Button { + text: "Enable Mapping" + onClicked: print(Controller.getValue(root.xbox.LY)); + } + } + + Row { + Xbox { device: root.standard; label: "Standard"; width: 360 } + } + + Row { + spacing: 8 + Xbox { device: root.xbox; label: "XBox"; width: 360 } + Hydra { device: root.hydra; width: 360 } + } +// Row { +// spacing: 8 +// ScrollingGraph { +// controlId: Controller.Actions.Yaw +// label: "Yaw" +// min: -3.0 +// max: 3.0 +// size: 128 +// } +// +// ScrollingGraph { +// controlId: Controller.Actions.YAW_LEFT +// label: "Yaw Left" +// min: -3.0 +// max: 3.0 +// size: 128 +// } +// +// ScrollingGraph { +// controlId: Controller.Actions.YAW_RIGHT +// label: "Yaw Right" +// min: -3.0 +// max: 3.0 +// size: 128 +// } +// } + } +} // dialog + + + + + diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b0c0109b71..77140fc0d3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2710,22 +2710,6 @@ void Application::update(float deltaTime) { auto myAvatar = getMyAvatar(); auto userInputMapper = DependencyManager::get(); userInputMapper->setSensorToWorldMat(myAvatar->getSensorToWorldMatrix()); - // userInputMapper->update(deltaTime); - - // This needs to go after userInputMapper->update() because of the keyboard - bool jointsCaptured = false; - auto inputPlugins = PluginManager::getInstance()->getInputPlugins(); - foreach(auto inputPlugin, inputPlugins) { - QString name = inputPlugin->getName(); - QAction* action = Menu::getInstance()->getActionForOption(name); - if (action && action->isChecked()) { - inputPlugin->pluginUpdate(deltaTime, jointsCaptured); - if (inputPlugin->isJointController()) { - jointsCaptured = true; - } - } - } - // Dispatch input events _controllerScriptingInterface->update(); diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index f1f7b08587..1e35713e16 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -23,109 +23,6 @@ // TODO: this needs to be removed, as well as any related controller-specific information #include -ControllerScriptingInterface::ControllerScriptingInterface() : - _mouseCaptured(false), - _touchCaptured(false), - _wheelCaptured(false), - _actionsCaptured(false) -{ - -} - -ControllerScriptingInterface::~ControllerScriptingInterface() { -} - - -static int actionMetaTypeId = qRegisterMetaType(); -static int inputChannelMetaTypeId = qRegisterMetaType(); -static int inputMetaTypeId = qRegisterMetaType(); -static int inputPairMetaTypeId = qRegisterMetaType(); - -QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input); -void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input); -QScriptValue inputChannelToScriptValue(QScriptEngine* engine, const UserInputMapper::InputChannel& inputChannel); -void inputChannelFromScriptValue(const QScriptValue& object, UserInputMapper::InputChannel& inputChannel); -QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action); -void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action); -QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair); -void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair); - -QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input) { - QScriptValue obj = engine->newObject(); - obj.setProperty("device", input.getDevice()); - obj.setProperty("channel", input.getChannel()); - obj.setProperty("type", (unsigned short) input.getType()); - obj.setProperty("id", input.getID()); - return obj; -} - -void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input) { - input.setDevice(object.property("device").toUInt16()); - input.setChannel(object.property("channel").toUInt16()); - input.setType(object.property("type").toUInt16()); - input.setID(object.property("id").toInt32()); -} - -QScriptValue inputChannelToScriptValue(QScriptEngine* engine, const UserInputMapper::InputChannel& inputChannel) { - QScriptValue obj = engine->newObject(); - obj.setProperty("input", inputToScriptValue(engine, inputChannel.getInput())); - obj.setProperty("modifier", inputToScriptValue(engine, inputChannel.getModifier())); - obj.setProperty("action", inputChannel.getAction()); - obj.setProperty("scale", inputChannel.getScale()); - return obj; -} - -void inputChannelFromScriptValue(const QScriptValue& object, UserInputMapper::InputChannel& inputChannel) { - UserInputMapper::Input input; - UserInputMapper::Input modifier; - inputFromScriptValue(object.property("input"), input); - inputChannel.setInput(input); - inputFromScriptValue(object.property("modifier"), modifier); - inputChannel.setModifier(modifier); - inputChannel.setAction(UserInputMapper::Action(object.property("action").toVariant().toInt())); - inputChannel.setScale(object.property("scale").toVariant().toFloat()); -} - -QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action) { - QScriptValue obj = engine->newObject(); - auto userInputMapper = DependencyManager::get(); - QVector inputChannels = userInputMapper->getInputChannelsForAction(action); - QScriptValue _inputChannels = engine->newArray(inputChannels.size()); - for (int i = 0; i < inputChannels.size(); i++) { - _inputChannels.setProperty(i, inputChannelToScriptValue(engine, inputChannels[i])); - } - obj.setProperty("action", (int) action); - obj.setProperty("actionName", userInputMapper->getActionName(action)); - obj.setProperty("inputChannels", _inputChannels); - return obj; -} - -void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action) { - action = UserInputMapper::Action(object.property("action").toVariant().toInt()); -} - -QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair) { - QScriptValue obj = engine->newObject(); - obj.setProperty("input", inputToScriptValue(engine, inputPair.first)); - obj.setProperty("inputName", inputPair.second); - return obj; -} - -void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair) { - inputFromScriptValue(object.property("input"), inputPair.first); - inputPair.second = QString(object.property("inputName").toVariant().toString()); -} - -void ControllerScriptingInterface::registerControllerTypes(QScriptEngine* engine) { - qScriptRegisterSequenceMetaType >(engine); - qScriptRegisterSequenceMetaType >(engine); - qScriptRegisterSequenceMetaType >(engine); - qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue); - qScriptRegisterMetaType(engine, inputChannelToScriptValue, inputChannelFromScriptValue); - qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue); - qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue); -} - void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) { if (event->type() == HFActionEvent::startType()) { emit actionStartEvent(static_cast(*event)); @@ -183,162 +80,6 @@ const PalmData* ControllerScriptingInterface::getActivePalm(int palmIndex) const return NULL; } -/* -bool ControllerScriptingInterface::isPrimaryButtonPressed() const { - const PalmData* primaryPalm = getPrimaryPalm(); - if (primaryPalm) { - if (primaryPalm->getControllerButtons() & BUTTON_FWD) { - return true; - } - } - - return false; -} - -glm::vec2 ControllerScriptingInterface::getPrimaryJoystickPosition() const { - const PalmData* primaryPalm = getPrimaryPalm(); - if (primaryPalm) { - return glm::vec2(primaryPalm->getJoystickX(), primaryPalm->getJoystickY()); - } - - return glm::vec2(0); -} - -int ControllerScriptingInterface::getNumberOfButtons() const { - return getNumberOfActivePalms() * NUMBER_OF_BUTTONS_PER_PALM; -} - -bool ControllerScriptingInterface::isButtonPressed(int buttonIndex) const { - int palmIndex = buttonIndex / NUMBER_OF_BUTTONS_PER_PALM; - int buttonOnPalm = buttonIndex % NUMBER_OF_BUTTONS_PER_PALM; - const PalmData* palmData = getActivePalm(palmIndex); - if (palmData) { - switch (buttonOnPalm) { - case 0: - return palmData->getControllerButtons() & BUTTON_0; - case 1: - return palmData->getControllerButtons() & BUTTON_1; - case 2: - return palmData->getControllerButtons() & BUTTON_2; - case 3: - return palmData->getControllerButtons() & BUTTON_3; - case 4: - return palmData->getControllerButtons() & BUTTON_4; - case 5: - return palmData->getControllerButtons() & BUTTON_FWD; - } - } - return false; -} - -int ControllerScriptingInterface::getNumberOfTriggers() const { - return getNumberOfActivePalms() * NUMBER_OF_TRIGGERS_PER_PALM; -} - -float ControllerScriptingInterface::getTriggerValue(int triggerIndex) const { - // we know there's one trigger per palm, so the triggerIndex is the palm Index - int palmIndex = triggerIndex; - const PalmData* palmData = getActivePalm(palmIndex); - if (palmData) { - return palmData->getTrigger(); - } - return 0.0f; -} - -int ControllerScriptingInterface::getNumberOfJoysticks() const { - return getNumberOfActivePalms() * NUMBER_OF_JOYSTICKS_PER_PALM; -} - -glm::vec2 ControllerScriptingInterface::getJoystickPosition(int joystickIndex) const { - // we know there's one joystick per palm, so the joystickIndex is the palm Index - int palmIndex = joystickIndex; - const PalmData* palmData = getActivePalm(palmIndex); - if (palmData) { - return glm::vec2(palmData->getJoystickX(), palmData->getJoystickY()); - } - return glm::vec2(0); -} - -int ControllerScriptingInterface::getNumberOfSpatialControls() const { - return getNumberOfActivePalms() * NUMBER_OF_SPATIALCONTROLS_PER_PALM; -} - -glm::vec3 ControllerScriptingInterface::getSpatialControlPosition(int controlIndex) const { - int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM; - int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM; - const PalmData* palmData = getActivePalm(palmIndex); - if (palmData) { - switch (controlOfPalm) { - case PALM_SPATIALCONTROL: - return palmData->getPosition(); - case TIP_SPATIALCONTROL: - return palmData->getTipPosition(); - } - } - return glm::vec3(0); // bad index -} - -glm::vec3 ControllerScriptingInterface::getSpatialControlVelocity(int controlIndex) const { - int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM; - int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM; - const PalmData* palmData = getActivePalm(palmIndex); - if (palmData) { - switch (controlOfPalm) { - case PALM_SPATIALCONTROL: - return palmData->getVelocity(); - case TIP_SPATIALCONTROL: - return palmData->getTipVelocity(); - } - } - return glm::vec3(0); // bad index -} - -glm::quat ControllerScriptingInterface::getSpatialControlRawRotation(int controlIndex) const { - int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM; - int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM; - const PalmData* palmData = getActivePalm(palmIndex); - if (palmData) { - switch (controlOfPalm) { - case PALM_SPATIALCONTROL: - return palmData->getRawRotation(); - case TIP_SPATIALCONTROL: - return palmData->getRawRotation(); // currently the tip doesn't have a unique rotation, use the palm rotation - } - } - return glm::quat(); // bad index -} - -glm::vec3 ControllerScriptingInterface::getSpatialControlRawAngularVelocity(int controlIndex) const { - int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM; - int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM; - const PalmData* palmData = getActivePalm(palmIndex); - if (palmData) { - switch (controlOfPalm) { - case PALM_SPATIALCONTROL: - return palmData->getRawAngularVelocity(); - case TIP_SPATIALCONTROL: - return palmData->getRawAngularVelocity(); // Tip = palm angular velocity - } - } - return glm::vec3(0); // bad index -} - -glm::vec3 ControllerScriptingInterface::getSpatialControlNormal(int controlIndex) const { - int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM; - int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM; - const PalmData* palmData = getActivePalm(palmIndex); - if (palmData) { - switch (controlOfPalm) { - case PALM_SPATIALCONTROL: - return palmData->getNormal(); - case TIP_SPATIALCONTROL: - return palmData->getFingerDirection(); - } - } - return glm::vec3(0); // bad index -} -*/ - bool ControllerScriptingInterface::isKeyCaptured(QKeyEvent* event) const { return isKeyCaptured(KeyEvent(*event)); } @@ -432,15 +173,18 @@ void ControllerScriptingInterface::update() { float delta = now - last; last = now; - for(auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) { + DependencyManager::get()->update(delta); + + bool jointsCaptured = false; + for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) { if (inputPlugin->isActive()) { - inputPlugin->pluginUpdate(delta, false); + inputPlugin->pluginUpdate(delta, jointsCaptured); + if (inputPlugin->isJointController()) { + jointsCaptured = true; + } } } - auto userInputMapper = DependencyManager::get(); - userInputMapper->update(delta); - for (auto entry : _inputControllers) { entry.second->update(); } @@ -448,62 +192,6 @@ void ControllerScriptingInterface::update() { controller::ScriptingInterface::update(); } -QVector ControllerScriptingInterface::getAllActions() { - return DependencyManager::get()->getAllActions(); -} - -QVector ControllerScriptingInterface::getInputChannelsForAction(UserInputMapper::Action action) { - return DependencyManager::get()->getInputChannelsForAction(action); -} - -QString ControllerScriptingInterface::getDeviceName(unsigned int device) { - return DependencyManager::get()->getDeviceName((unsigned short)device); -} - -QVector ControllerScriptingInterface::getAllInputsForDevice(unsigned int device) { - return DependencyManager::get()->getAllInputsForDevice(device); -} - -bool ControllerScriptingInterface::addInputChannel(UserInputMapper::InputChannel inputChannel) { - return DependencyManager::get()->addInputChannel(inputChannel._action, inputChannel._input, inputChannel._modifier, inputChannel._scale); -} - -bool ControllerScriptingInterface::removeInputChannel(UserInputMapper::InputChannel inputChannel) { - return DependencyManager::get()->removeInputChannel(inputChannel); -} - -QVector ControllerScriptingInterface::getAvailableInputs(unsigned int device) { - return DependencyManager::get()->getAvailableInputs((unsigned short)device); -} - -void ControllerScriptingInterface::resetAllDeviceBindings() { - DependencyManager::get()->resetAllDeviceBindings(); -} - -void ControllerScriptingInterface::resetDevice(unsigned int device) { - DependencyManager::get()->resetDevice(device); -} - -int ControllerScriptingInterface::findDevice(QString name) { - return DependencyManager::get()->findDevice(name); -} - -QVector ControllerScriptingInterface::getDeviceNames() { - return DependencyManager::get()->getDeviceNames(); -} - -float ControllerScriptingInterface::getActionValue(int action) { - return DependencyManager::get()->getActionState(UserInputMapper::Action(action)); -} - -int ControllerScriptingInterface::findAction(QString actionName) { - return DependencyManager::get()->findAction(actionName); -} - -QVector ControllerScriptingInterface::getActionNames() const { - return DependencyManager::get()->getActionNames(); -} - InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) : _deviceTrackerId(deviceTrackerId), _subTrackerId(subTrackerId), diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h index 25d9a523d3..24065e6799 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -63,33 +63,8 @@ class ControllerScriptingInterface : public controller::ScriptingInterface { public: - ControllerScriptingInterface(); - ~ControllerScriptingInterface(); + virtual ~ControllerScriptingInterface() {} - Q_INVOKABLE QVector getAllActions(); - - Q_INVOKABLE bool addInputChannel(UserInputMapper::InputChannel inputChannel); - Q_INVOKABLE bool removeInputChannel(UserInputMapper::InputChannel inputChannel); - Q_INVOKABLE QVector getInputChannelsForAction(UserInputMapper::Action action); - - Q_INVOKABLE QVector getAvailableInputs(unsigned int device); - Q_INVOKABLE QVector getAllInputsForDevice(unsigned int device); - - Q_INVOKABLE QString getDeviceName(unsigned int device); - - Q_INVOKABLE float getActionValue(int action); - - Q_INVOKABLE void resetDevice(unsigned int device); - Q_INVOKABLE void resetAllDeviceBindings(); - Q_INVOKABLE int findDevice(QString name); - Q_INVOKABLE QVector getDeviceNames(); - - Q_INVOKABLE int findAction(QString actionName); - Q_INVOKABLE QVector getActionNames() const; - - - virtual void registerControllerTypes(QScriptEngine* engine); - void emitKeyPressEvent(QKeyEvent* event); void emitKeyReleaseEvent(QKeyEvent* event); @@ -108,10 +83,6 @@ public: bool isKeyCaptured(QKeyEvent* event) const; bool isKeyCaptured(const KeyEvent& event) const; - bool isMouseCaptured() const { return _mouseCaptured; } - bool isTouchCaptured() const { return _touchCaptured; } - bool isWheelCaptured() const { return _wheelCaptured; } - bool areActionsCaptured() const { return _actionsCaptured; } bool isJoystickCaptured(int joystickIndex) const; virtual void update() override; @@ -121,18 +92,6 @@ public slots: virtual void captureKeyEvents(const KeyEvent& event); virtual void releaseKeyEvents(const KeyEvent& event); - virtual void captureMouseEvents() { _mouseCaptured = true; } - virtual void releaseMouseEvents() { _mouseCaptured = false; } - - virtual void captureTouchEvents() { _touchCaptured = true; } - virtual void releaseTouchEvents() { _touchCaptured = false; } - - virtual void captureWheelEvents() { _wheelCaptured = true; } - virtual void releaseWheelEvents() { _wheelCaptured = false; } - - virtual void captureActionEvents() { _actionsCaptured = true; } - virtual void releaseActionEvents() { _actionsCaptured = false; } - virtual void captureJoystick(int joystickIndex); virtual void releaseJoystick(int joystickIndex); @@ -173,10 +132,6 @@ private: int getNumberOfActivePalms() const; const PalmData* getActivePalm(int palmIndex) const; - bool _mouseCaptured; - bool _touchCaptured; - bool _wheelCaptured; - bool _actionsCaptured; QMultiMap _capturedKeys; QSet _capturedJoysticks; diff --git a/libraries/controllers/src/controllers/DeviceProxy.cpp b/libraries/controllers/src/controllers/DeviceProxy.cpp new file mode 100644 index 0000000000..9ac701e80d --- /dev/null +++ b/libraries/controllers/src/controllers/DeviceProxy.cpp @@ -0,0 +1,31 @@ +// +// Created by Bradley Austin Davis on 2015/10/18 +// (based on UserInputMapper inner class created by Sam Gateau on 4/27/15) +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "DeviceProxy.h" + +namespace controller { + + float DeviceProxy::getValue(const Input& input, int timestamp) const { + switch (input.getType()) { + case ChannelType::BUTTON: + return getButton(input, timestamp) ? 1.0f : 0.0f; + + case ChannelType::AXIS: + return getAxis(input, timestamp); + + case ChannelType::POSE: + return getPose(input, timestamp)._valid ? 1.0f : 0.0f; + + default: + return NAN; + } + } + +} + diff --git a/libraries/controllers/src/controllers/DeviceProxy.h b/libraries/controllers/src/controllers/DeviceProxy.h new file mode 100644 index 0000000000..78d13fe5c4 --- /dev/null +++ b/libraries/controllers/src/controllers/DeviceProxy.h @@ -0,0 +1,57 @@ +// +// Created by Bradley Austin Davis on 2015/10/18 +// (based on UserInputMapper inner class created by Sam Gateau on 4/27/15) +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once +#ifndef hifi_controllers_DeviceProxy_h +#define hifi_controllers_DeviceProxy_h + +#include + +#include +#include + +#include "Input.h" +#include "Pose.h" + +namespace controller { + + using Modifiers = std::vector; + typedef QPair InputPair; + + + template + using InputGetter = std::function; + using ButtonGetter = InputGetter; + using AxisGetter = InputGetter; + using PoseGetter = InputGetter; + using ResetBindings = std::function; + using AvailableInputGetter = std::function; + + class DeviceProxy { + public: + DeviceProxy(QString name) : _baseName(name), _name(name) {} + const QString& getBaseName() const { return _baseName; } + const QString& getName() const { return _name; } + + ButtonGetter getButton = [] (const Input& input, int timestamp) -> bool { return false; }; + AxisGetter getAxis = [] (const Input& input, int timestamp) -> float { return 0.0f; }; + PoseGetter getPose = [](const Input& input, int timestamp) -> Pose { return Pose(); }; + AvailableInputGetter getAvailabeInputs = []() -> Input::NamedVector { return Input::NamedVector(); }; + ResetBindings resetDeviceBindings = [] () -> bool { return true; }; + float getValue(const Input& input, int timestamp = 0) const; + + using Pointer = std::shared_ptr; + + QString _baseName; + QString _name; + }; + +} + +#endif diff --git a/libraries/controllers/src/controllers/Input.cpp b/libraries/controllers/src/controllers/Input.cpp new file mode 100644 index 0000000000..29d2fed617 --- /dev/null +++ b/libraries/controllers/src/controllers/Input.cpp @@ -0,0 +1,19 @@ +// +// Created by Bradley Austin Davis on 2015/10/18 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Input.h" + +namespace controller { + + const Input Input::INVALID_INPUT = Input(UINT32_MAX); + const uint16_t Input::INVALID_DEVICE = INVALID_INPUT.getDevice(); + const uint16_t Input::INVALID_CHANNEL = INVALID_INPUT.getChannel(); + const uint16_t Input::INVALID_TYPE = (uint16_t)INVALID_INPUT.getType(); + +} + diff --git a/libraries/controllers/src/controllers/Input.h b/libraries/controllers/src/controllers/Input.h new file mode 100644 index 0000000000..8cc682df70 --- /dev/null +++ b/libraries/controllers/src/controllers/Input.h @@ -0,0 +1,76 @@ +// +// Created by Bradley Austin Davis on 2015/10/18 +// (based on UserInputMapper inner class created by Sam Gateau on 4/27/15) +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once +#ifndef hifi_controllers_Input_h +#define hifi_controllers_Input_h + +#include + +namespace controller { + +enum class ChannelType { + UNKNOWN = 0, + BUTTON = 1, + AXIS, + POSE, +}; + +// Input is the unique identifier to find a n input channel of a particular device +// Devices are responsible for registering to the UseInputMapper so their input channels can be sued and mapped +// to the Action channels +struct Input { + union { + struct { + uint16_t _device; // Up to 64K possible devices + uint16_t _channel : 13; // 2^13 possible channel per Device + uint16_t _type : 2; // 2 bits to store the Type directly in the ID + uint16_t _padding : 1; // 2 bits to store the Type directly in the ID + }; + uint32_t _id = 0; // by default Input is 0 meaning invalid + }; + + bool isValid() const { return (_id != 0); } + + uint16_t getDevice() const { return _device; } + uint16_t getChannel() const { return _channel; } + uint32_t getID() const { return _id; } + ChannelType getType() const { return (ChannelType) _type; } + + void setDevice(uint16_t device) { _device = device; } + void setChannel(uint16_t channel) { _channel = channel; } + void setType(uint16_t type) { _type = type; } + void setID(uint32_t ID) { _id = ID; } + + bool isButton() const { return getType() == ChannelType::BUTTON; } + bool isAxis() const { return getType() == ChannelType::AXIS; } + bool isPose() const { return getType() == ChannelType::POSE; } + + // WORKAROUND: the explicit initializer here avoids a bug in GCC-4.8.2 (but not found in 4.9.2) + // where the default initializer (a C++-11ism) for the union data above is not applied. + explicit Input() : _id(0) {} + explicit Input(uint32_t id) : _id(id) {} + explicit Input(uint16_t device, uint16_t channel, ChannelType type) : _device(device), _channel(channel), _type(uint16_t(type)), _padding(0) {} + Input(const Input& src) : _id(src._id) {} + Input& operator = (const Input& src) { _id = src._id; return (*this); } + bool operator ==(const Input& right) const { return _id == right._id; } + bool operator < (const Input& src) const { return _id < src._id; } + + static const Input INVALID_INPUT; + static const uint16_t INVALID_DEVICE; + static const uint16_t INVALID_CHANNEL; + static const uint16_t INVALID_TYPE; + + using NamedPair = QPair; + using NamedVector = QVector; +}; + +} + +#endif diff --git a/libraries/controllers/src/controllers/InputDevice.cpp b/libraries/controllers/src/controllers/InputDevice.cpp index 4b2376d32a..1f86741b88 100644 --- a/libraries/controllers/src/controllers/InputDevice.cpp +++ b/libraries/controllers/src/controllers/InputDevice.cpp @@ -13,7 +13,7 @@ bool InputDevice::_lowVelocityFilter = false; const float DEFAULT_HAND_RETICLE_MOVE_SPEED = 37.5f; -float InputDevice::reticleMoveSpeed = DEFAULT_HAND_RETICLE_MOVE_SPEED; +float InputDevice::_reticleMoveSpeed = DEFAULT_HAND_RETICLE_MOVE_SPEED; //Constants for getCursorPixelRangeMultiplier() const float MIN_PIXEL_RANGE_MULT = 0.4f; @@ -23,7 +23,7 @@ const float RANGE_MULT = (MAX_PIXEL_RANGE_MULT - MIN_PIXEL_RANGE_MULT) * 0.01f; //Returns a multiplier to be applied to the cursor range for the controllers float InputDevice::getCursorPixelRangeMult() { //scales (0,100) to (MINIMUM_PIXEL_RANGE_MULT, MAXIMUM_PIXEL_RANGE_MULT) - return InputDevice::reticleMoveSpeed * RANGE_MULT + MIN_PIXEL_RANGE_MULT; + return InputDevice::_reticleMoveSpeed * RANGE_MULT + MIN_PIXEL_RANGE_MULT; } float InputDevice::getButton(int channel) const { diff --git a/libraries/controllers/src/controllers/InputDevice.h b/libraries/controllers/src/controllers/InputDevice.h index 66f7addc58..4854df0ada 100644 --- a/libraries/controllers/src/controllers/InputDevice.h +++ b/libraries/controllers/src/controllers/InputDevice.h @@ -34,7 +34,7 @@ public: UserInputMapper::PoseValue getPose(int channel) const; virtual void registerToUserInputMapper(UserInputMapper& mapper) = 0; - virtual void assignDefaultInputMapping(UserInputMapper& mapper) {}; + virtual void assignDefaultInputMapping(UserInputMapper& mapper) = 0; // Update call MUST be called once per simulation loop // It takes care of updating the action states and deltas @@ -45,8 +45,8 @@ public: int getDeviceID() { return _deviceID; } static float getCursorPixelRangeMult(); - static float getReticleMoveSpeed() { return reticleMoveSpeed; } - static void setReticleMoveSpeed(float sixenseReticleMoveSpeed) { reticleMoveSpeed = sixenseReticleMoveSpeed; } + static float getReticleMoveSpeed() { return _reticleMoveSpeed; } + static void setReticleMoveSpeed(float reticleMoveSpeed) { _reticleMoveSpeed = reticleMoveSpeed; } static bool getLowVelocityFilter() { return _lowVelocityFilter; }; @@ -72,5 +72,5 @@ protected: static bool _lowVelocityFilter; private: - static float reticleMoveSpeed; + static float _reticleMoveSpeed; }; \ No newline at end of file diff --git a/libraries/controllers/src/controllers/Pose.cpp b/libraries/controllers/src/controllers/Pose.cpp new file mode 100644 index 0000000000..a716955d70 --- /dev/null +++ b/libraries/controllers/src/controllers/Pose.cpp @@ -0,0 +1,30 @@ +// +// Created by Bradley Austin Davis on 2015/10/18 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Pose.h" + +namespace controller { + + Pose::Pose(const vec3& translation, const quat& rotation, + const vec3& velocity, const quat& angularVelocity) : + _translation(translation), _rotation(rotation), _velocity(velocity), _angularVelocity(angularVelocity) { } + + bool Pose::operator==(const Pose& right) const { + // invalid poses return false for comparison, even against identical invalid poses, like NaN + if (_valid || !right._valid) { + return false; + } + + // FIXME add margin of error? Or add an additional withinEpsilon function? + return _translation == right.getTranslation() && _rotation == right.getRotation() && + _velocity == right.getVelocity() && _angularVelocity == right.getAngularVelocity(); + } + + +} + diff --git a/libraries/controllers/src/controllers/Pose.h b/libraries/controllers/src/controllers/Pose.h new file mode 100644 index 0000000000..b77064f2c1 --- /dev/null +++ b/libraries/controllers/src/controllers/Pose.h @@ -0,0 +1,43 @@ +// +// Created by Bradley Austin Davis on 2015/10/18 +// (based on UserInputMapper inner class created by Sam Gateau on 4/27/15) +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once +#ifndef hifi_controllers_Pose_h +#define hifi_controllers_Pose_h + +#include + +namespace controller { + + struct Pose { + public: + vec3 _translation; + quat _rotation; + vec3 _velocity; + quat _angularVelocity; + bool _valid{ false }; + + Pose() {} + Pose(const vec3& translation, const quat& rotation, + const vec3& velocity = vec3(), const quat& angularVelocity = quat()); + + Pose(const Pose&) = default; + Pose& operator = (const Pose&) = default; + bool operator ==(const Pose& right) const; + bool isValid() const { return _valid; } + vec3 getTranslation() const { return _translation; } + quat getRotation() const { return _rotation; } + vec3 getVelocity() const { return _velocity; } + quat getAngularVelocity() const { return _angularVelocity; } + }; + + +} + +#endif diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp index 6d4ad1a566..c5c7969604 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.cpp +++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp @@ -67,7 +67,7 @@ namespace controller { void ScriptEndpoint::updateValue() { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection); + QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection); return; } @@ -80,10 +80,10 @@ namespace controller { void ScriptEndpoint::internalApply(float newValue, float oldValue, int sourceID) { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "internalApply", Qt::QueuedConnection, - Q_ARG(float, newValue), - Q_ARG(float, oldValue), - Q_ARG(int, sourceID)); + QMetaObject::invokeMethod(this, "internalApply", Qt::QueuedConnection, + Q_ARG(float, newValue), + Q_ARG(float, oldValue), + Q_ARG(int, sourceID)); return; } _callable.call(QScriptValue(), @@ -163,28 +163,28 @@ namespace controller { QJsonObject obj; QJsonParseError error; QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8(), &error); - // check validity of the document - if (!doc.isNull()) { - if (doc.isObject()) { - obj = doc.object(); - + // check validity of the document + if (!doc.isNull()) { + if (doc.isObject()) { + obj = doc.object(); + auto mapping = std::make_shared("default"); auto mappingBuilder = new MappingBuilderProxy(*this, mapping); mappingBuilder->parse(obj); _mappingsByName[mapping->_name] = mapping; - - return mappingBuilder; - } else { - qDebug() << "Mapping json Document is not an object" << endl; - } - } else { - qDebug() << "Invalid JSON...\n"; - qDebug() << error.errorString(); - qDebug() << "JSON was:\n" << json << endl; - - } + + return mappingBuilder; + } else { + qDebug() << "Mapping json Document is not an object" << endl; + } + } else { + qDebug() << "Invalid JSON...\n"; + qDebug() << error.errorString(); + qDebug() << "JSON was:\n" << json << endl; + + } return nullptr; } @@ -204,7 +204,7 @@ namespace controller { if (request->getResult() == ResourceRequest::Success) { result = parseMapping(QString(request->getData())); } else { - qCWarning(controllers) << "Failed to load mapping url <" << jsonUrl << ">" << endl; + qCWarning(controllers) << "Failed to load mapping url <" << jsonUrl << ">" << endl; } request->deleteLater(); } @@ -263,8 +263,8 @@ namespace controller { return getValue(UserInputMapper::Input(device, source, UserInputMapper::ChannelType::AXIS).getID()); } - glm::mat4 ScriptingInterface::getPoseValue(StandardPoseChannel source, uint16_t device) const { - return glm::mat4(); + Pose ScriptingInterface::getPoseValue(StandardPoseChannel source, uint16_t device) const { + return Pose(); } void ScriptingInterface::update() { @@ -368,7 +368,7 @@ namespace controller { } UserInputMapper::Input ScriptingInterface::inputFor(const QString& inputName) { - return DependencyManager::get()->findDeviceInput(inputName); + return DependencyManager::get()->findDeviceInput(inputName); } Endpoint::Pointer ScriptingInterface::endpointFor(const UserInputMapper::Input& inputId) { @@ -494,6 +494,39 @@ namespace controller { } } } + + QVector ScriptingInterface::getAllActions() { + return DependencyManager::get()->getAllActions(); + } + + QString ScriptingInterface::getDeviceName(unsigned int device) { + return DependencyManager::get()->getDeviceName((unsigned short)device); + } + + QVector ScriptingInterface::getAvailableInputs(unsigned int device) { + return DependencyManager::get()->getAvailableInputs((unsigned short)device); + } + + int ScriptingInterface::findDevice(QString name) { + return DependencyManager::get()->findDevice(name); + } + + QVector ScriptingInterface::getDeviceNames() { + return DependencyManager::get()->getDeviceNames(); + } + + float ScriptingInterface::getActionValue(int action) { + return DependencyManager::get()->getActionState(UserInputMapper::Action(action)); + } + + int ScriptingInterface::findAction(QString actionName) { + return DependencyManager::get()->findAction(actionName); + } + + QVector ScriptingInterface::getActionNames() const { + return DependencyManager::get()->getActionNames(); + } + } // namespace controllers @@ -520,7 +553,7 @@ ScriptingInterface::ScriptingInterface() { int actionNumber = 0; qCDebug(controllers) << "Setting up standard actions"; for (const auto& actionName : actionNames) { - UserInputMapper::Input actionInput(UserInputMapper::Input::ACTIONS_DEVICE, actionNumber++, UserInputMapper::ChannelType::AXIS); + UserInputMapper::Input actionInput(UserInputMapper::ACTIONS_DEVICE, actionNumber++, UserInputMapper::ChannelType::AXIS); qCDebug(controllers) << "\tAction: " << actionName << " " << QString::number(actionInput.getID(), 16); // Expose the IDs to JS QString cleanActionName = QString(actionName).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION); @@ -532,43 +565,3 @@ ScriptingInterface::ScriptingInterface() { updateMaps(); } - -//var mapping = Controller.newMapping(); -//mapping.map(hydra.LeftButton0, actions.ContextMenu); -//mapping.map(hydra.LeftButton0).to(xbox.RT); -//mapping.from(xbox.RT).constrainToBoolean().invert().to(actions.Foo) -// mapping.from(xbox.RY).invert().deadZone(0.2).to(actions.Pitch) -// mapping.from(xbox.RY).filter(function(newValue, oldValue) { -// return newValue * 2.0 -//}).to(actions.Pitch) - -//mapping.from(function(time) { -// return Math.cos(time); -// }).to(actions.Pitch); - -// mapping.mapFromFunction(function() { -// return x; -// }, actions.ContextMenu); - -// mapping.from(xbox.LY).clamp(0, 1).to(actions.Forward); -// mapping.from(xbox.LY).clamp(-1, 0).to(actions.Backward); -// mapping.from(xbox.RY).clamp(0, 1).to(actions.Forward); -// mapping.from(xbox.RS).to(); -// mapping.from(xbox.ALL).to(); - -// mapping.from(xbox.RY).to(function(...) { ... }); -// mapping.from(xbox.RY).pass(); - -// mapping.suppress() ≅ mapping.to(null) -// mapping.pass() ≅ mapping.to(fromControl) - -// mapping.from(keyboard.RightParen).invert().to(actions.Yaw) -// mapping.from(keyboard.LeftParen).to(actions.Yaw) - -// mapping.from(hydra.LX).pulse(MIN_SNAP_TIME, 3.0).to(Actions.Yaw) - -// mapping.from(keyboard.LeftParen).pulse(MIN_SNAP_TIME).to(Actions.Yaw) -// // Enable and disable as above - -// mappingSnap.from(hydra.LX).to(function(newValue, oldValue) { -// timeSinceLastYaw += deltaTime diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h index ef9d61c32d..f473562b9e 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.h +++ b/libraries/controllers/src/controllers/ScriptingInterface.h @@ -67,15 +67,22 @@ namespace controller { ScriptingInterface(); virtual ~ScriptingInterface(); + Q_INVOKABLE QVector getAllActions(); + Q_INVOKABLE QVector getAvailableInputs(unsigned int device); + Q_INVOKABLE QString getDeviceName(unsigned int device); + Q_INVOKABLE float getActionValue(int action); + Q_INVOKABLE int findDevice(QString name); + Q_INVOKABLE QVector getDeviceNames(); + Q_INVOKABLE int findAction(QString actionName); + Q_INVOKABLE QVector getActionNames() const; + Q_INVOKABLE float getValue(const int& source) const; Q_INVOKABLE float getButtonValue(StandardButtonChannel source, uint16_t device = 0) const; Q_INVOKABLE float getAxisValue(StandardAxisChannel source, uint16_t device = 0) const; - Q_INVOKABLE glm::mat4 getPoseValue(StandardPoseChannel source, uint16_t device = 0) const; + Q_INVOKABLE Pose getPoseValue(StandardPoseChannel source, uint16_t device = 0) const; Q_INVOKABLE QObject* newMapping(const QString& mappingName = QUuid::createUuid().toString()); Q_INVOKABLE void enableMapping(const QString& mappingName, bool enable = true); - Q_INVOKABLE void disableMapping(const QString& mappingName) { - enableMapping(mappingName, false); - } + Q_INVOKABLE void disableMapping(const QString& mappingName) { enableMapping(mappingName, false); } Q_INVOKABLE QObject* parseMapping(const QString& json); Q_INVOKABLE QObject* loadMapping(const QString& jsonUrl); @@ -102,13 +109,30 @@ namespace controller { Q_INVOKABLE const QVariantMap& getActions() { return _actions; } Q_INVOKABLE const QVariantMap& getStandard() { return _standard; } + bool isMouseCaptured() const { return _mouseCaptured; } + bool isTouchCaptured() const { return _touchCaptured; } + bool isWheelCaptured() const { return _wheelCaptured; } + bool areActionsCaptured() const { return _actionsCaptured; } + static QRegularExpression SANITIZE_NAME_EXPRESSION; public slots: virtual void update(); - virtual void registerControllerTypes(QScriptEngine* engine) = 0; virtual void updateMaps(); + virtual void captureMouseEvents() { _mouseCaptured = true; } + virtual void releaseMouseEvents() { _mouseCaptured = false; } + + virtual void captureTouchEvents() { _touchCaptured = true; } + virtual void releaseTouchEvents() { _touchCaptured = false; } + + virtual void captureWheelEvents() { _wheelCaptured = true; } + virtual void releaseWheelEvents() { _wheelCaptured = false; } + + virtual void captureActionEvents() { _actionsCaptured = true; } + virtual void releaseActionEvents() { _actionsCaptured = false; } + + private: friend class MappingBuilderProxy; friend class RouteBuilderProxy; @@ -141,6 +165,11 @@ namespace controller { ValueMap _overrideValues; MappingMap _mappingsByName; MappingStack _activeMappings; + + bool _mouseCaptured{ false }; + bool _touchCaptured{ false }; + bool _wheelCaptured{ false }; + bool _actionsCaptured{ false }; }; class ScriptEndpoint : public Endpoint { diff --git a/libraries/controllers/src/controllers/StandardController.cpp b/libraries/controllers/src/controllers/StandardController.cpp index 9c423eded2..6b1ada25ed 100644 --- a/libraries/controllers/src/controllers/StandardController.cpp +++ b/libraries/controllers/src/controllers/StandardController.cpp @@ -96,16 +96,65 @@ void StandardController::registerToUserInputMapper(UserInputMapper& mapper) { return availableInputs; }; - proxy->resetDeviceBindings = [this, &mapper] () -> bool { - mapper.removeAllInputChannelsForDevice(_deviceID); - this->assignDefaultInputMapping(mapper); - return true; - }; - mapper.registerStandardDevice(proxy); } void StandardController::assignDefaultInputMapping(UserInputMapper& mapper) { + const float JOYSTICK_MOVE_SPEED = 1.0f; + const float DPAD_MOVE_SPEED = 0.5f; + const float JOYSTICK_YAW_SPEED = 0.5f; + const float JOYSTICK_PITCH_SPEED = 0.25f; + const float BOOM_SPEED = 0.1f; + + // Y axes are flipped (up is negative) + // Left Joystick: Movement, strafing + mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), JOYSTICK_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LX), JOYSTICK_MOVE_SPEED); + // Right Joystick: Camera orientation + mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), JOYSTICK_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), JOYSTICK_PITCH_SPEED); + + // Dpad movement + mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), DPAD_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), DPAD_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), DPAD_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), DPAD_MOVE_SPEED); + + // Button controls + mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), DPAD_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), DPAD_MOVE_SPEED); + + // Zoom + mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), BOOM_SPEED); + mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LB), BOOM_SPEED); + + // Hold front right shoulder button for precision controls + // Left Joystick: Movement, strafing + mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f); + mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f); + + // Right Joystick: Camera orientation + mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), makeInput(controller::RB), JOYSTICK_YAW_SPEED / 2.0f); + mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), makeInput(controller::RB), JOYSTICK_PITCH_SPEED / 2.0f); + + // Dpad movement + mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f); + mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f); + mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f); + mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f); + + // Button controls + mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f); + mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f); + + // Zoom + mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), makeInput(controller::RB), BOOM_SPEED / 2.0f); + mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LT), makeInput(controller::RB), BOOM_SPEED / 2.0f); + + mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(controller::RB)); + + mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(controller::B)); + mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(controller::A)); } UserInputMapper::Input StandardController::makeInput(controller::StandardButtonChannel button) { diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp index fbf1994d87..26e03b7719 100755 --- a/libraries/controllers/src/controllers/UserInputMapper.cpp +++ b/libraries/controllers/src/controllers/UserInputMapper.cpp @@ -1,115 +1,108 @@ -// -// UserInputMapper.cpp -// input-plugins/src/input-plugins -// -// Created by Sam Gateau on 4/27/15. -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "UserInputMapper.h" -#include "StandardController.h" - +// +// Created by Sam Gateau on 4/27/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "UserInputMapper.h" +#include "StandardController.h" + #include "Logging.h" - -const UserInputMapper::Input UserInputMapper::Input::INVALID_INPUT = UserInputMapper::Input(UINT16_MAX); -const uint16_t UserInputMapper::Input::INVALID_DEVICE = INVALID_INPUT.getDevice(); -const uint16_t UserInputMapper::Input::INVALID_CHANNEL = INVALID_INPUT.getChannel(); -const uint16_t UserInputMapper::Input::INVALID_TYPE = (uint16_t)INVALID_INPUT.getType(); -const uint16_t UserInputMapper::Input::ACTIONS_DEVICE = INVALID_DEVICE - (uint16)1; -const uint16_t UserInputMapper::Input::STANDARD_DEVICE = 0; - -// Default contruct allocate the poutput size with the current hardcoded action channels -UserInputMapper::UserInputMapper() { - registerStandardDevice(); - assignDefaulActionScales(); - createActionNames(); -} - -UserInputMapper::~UserInputMapper() { -} - -int UserInputMapper::recordDeviceOfType(const QString& deviceName) { - if (!_deviceCounts.contains(deviceName)) { - _deviceCounts[deviceName] = 0; - } - _deviceCounts[deviceName] += 1; - return _deviceCounts[deviceName]; -} - -bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy) { - int numberOfType = recordDeviceOfType(proxy->_name); - - if (numberOfType > 1) { - proxy->_name += QString::number(numberOfType); - } - + +const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - (uint16)1; +const uint16_t UserInputMapper::STANDARD_DEVICE = 0; + +// Default contruct allocate the poutput size with the current hardcoded action channels +UserInputMapper::UserInputMapper() { + registerStandardDevice(); + assignDefaulActionScales(); + createActionNames(); +} + +UserInputMapper::~UserInputMapper() { +} + +int UserInputMapper::recordDeviceOfType(const QString& deviceName) { + if (!_deviceCounts.contains(deviceName)) { + _deviceCounts[deviceName] = 0; + } + _deviceCounts[deviceName] += 1; + return _deviceCounts[deviceName]; +} + +bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy) { + int numberOfType = recordDeviceOfType(proxy->_name); + + if (numberOfType > 1) { + proxy->_name += QString::number(numberOfType); + } + qCDebug(controllers) << "Registered input device <" << proxy->_name << "> deviceID = " << deviceID; - _registeredDevices[deviceID] = proxy; - return true; - -} - - + _registeredDevices[deviceID] = proxy; + return true; + +} + + bool UserInputMapper::registerStandardDevice(const DeviceProxy::Pointer& device) { device->_name = "Standard"; // Just to make sure _registeredDevices[getStandardDeviceID()] = device; return true; } - - -UserInputMapper::DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) { - auto device = _registeredDevices.find(input.getDevice()); - if (device != _registeredDevices.end()) { - return (device->second); - } else { - return DeviceProxy::Pointer(); - } -} - -QString UserInputMapper::getDeviceName(uint16 deviceID) { - if (_registeredDevices.find(deviceID) != _registeredDevices.end()) { - return _registeredDevices[deviceID]->_name; - } - return QString("unknown"); -} - - -void UserInputMapper::resetAllDeviceBindings() { - for (auto device : _registeredDevices) { - device.second->resetDeviceBindings(); - } -} - -void UserInputMapper::resetDevice(uint16 deviceID) { - auto device = _registeredDevices.find(deviceID); - if (device != _registeredDevices.end()) { - device->second->resetDeviceBindings(); - } -} - -int UserInputMapper::findDevice(QString name) const { - for (auto device : _registeredDevices) { - if (device.second->_name.split(" (")[0] == name) { - return device.first; - } else if (device.second->_baseName == name) { - return device.first; - } - } - return Input::INVALID_DEVICE; -} - -QVector UserInputMapper::getDeviceNames() { - QVector result; - for (auto device : _registeredDevices) { - QString deviceName = device.second->_name.split(" (")[0]; - result << deviceName; - } - return result; -} - + + +UserInputMapper::DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) { + auto device = _registeredDevices.find(input.getDevice()); + if (device != _registeredDevices.end()) { + return (device->second); + } else { + return DeviceProxy::Pointer(); + } +} + +QString UserInputMapper::getDeviceName(uint16 deviceID) { + if (_registeredDevices.find(deviceID) != _registeredDevices.end()) { + return _registeredDevices[deviceID]->_name; + } + return QString("unknown"); +} + + +void UserInputMapper::resetAllDeviceBindings() { + for (auto device : _registeredDevices) { + device.second->resetDeviceBindings(); + } +} + +void UserInputMapper::resetDevice(uint16 deviceID) { + auto device = _registeredDevices.find(deviceID); + if (device != _registeredDevices.end()) { + device->second->resetDeviceBindings(); + } +} + +int UserInputMapper::findDevice(QString name) const { + for (auto device : _registeredDevices) { + if (device.second->_name.split(" (")[0] == name) { + return device.first; + } else if (device.second->_baseName == name) { + return device.first; + } + } + return Input::INVALID_DEVICE; +} + +QVector UserInputMapper::getDeviceNames() { + QVector result; + for (auto device : _registeredDevices) { + QString deviceName = device.second->_name.split(" (")[0]; + result << deviceName; + } + return result; +} + UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName) const { // Split the full input name as such: deviceName.inputName @@ -134,11 +127,11 @@ UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName qCDebug(controllers) << "Couldn\'t find InputChannel named <" << inputName << "> for device <" << deviceName << ">"; } else if (deviceName == "Actions") { - deviceID = Input::ACTIONS_DEVICE; + deviceID = ACTIONS_DEVICE; int actionNum = 0; for (auto action : _actionNames) { if (action == inputName) { - return Input(Input::ACTIONS_DEVICE, actionNum, ChannelType::AXIS); + return Input(ACTIONS_DEVICE, actionNum, ChannelType::AXIS); } actionNum++; } @@ -152,296 +145,368 @@ UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName qCDebug(controllers) << "Couldn\'t understand <" << inputName << "> as a valid inputDevice.inputName"; } - return Input(); + return Input::INVALID_INPUT; } - - -bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) { - return addInputChannel(action, input, Input(), scale); -} - -bool UserInputMapper::addInputChannel(Action action, const Input& input, const Input& modifier, float scale) { - // Check that the device is registered - if (!getDeviceProxy(input)) { - qDebug() << "UserInputMapper::addInputChannel: The input comes from a device #" << input.getDevice() << "is unknown. no inputChannel mapped."; - return false; - } - - auto inputChannel = InputChannel(input, modifier, action, scale); - - // Insert or replace the input to modifiers - if (inputChannel.hasModifier()) { - auto& modifiers = _inputToModifiersMap[input.getID()]; - modifiers.push_back(inputChannel._modifier); - std::sort(modifiers.begin(), modifiers.end()); - } - - // Now update the action To Inputs side of things - _actionToInputsMap.insert(ActionToInputsMap::value_type(action, inputChannel)); - - return true; -} - -int UserInputMapper::addInputChannels(const InputChannels& channels) { - int nbAdded = 0; - for (auto& channel : channels) { - nbAdded += addInputChannel(channel._action, channel._input, channel._modifier, channel._scale); - } - return nbAdded; -} - -bool UserInputMapper::removeInputChannel(InputChannel inputChannel) { - // Remove from Input to Modifiers map - if (inputChannel.hasModifier()) { - _inputToModifiersMap.erase(inputChannel._input.getID()); - } - - // Remove from Action to Inputs map - std::pair ret; - ret = _actionToInputsMap.equal_range(inputChannel._action); - for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) { - if (it->second == inputChannel) { - _actionToInputsMap.erase(it); - return true; - } - } - - return false; -} - -void UserInputMapper::removeAllInputChannels() { - _inputToModifiersMap.clear(); - _actionToInputsMap.clear(); -} - -void UserInputMapper::removeAllInputChannelsForDevice(uint16 device) { - QVector channels = getAllInputsForDevice(device); - for (auto& channel : channels) { - removeInputChannel(channel); - } -} - -void UserInputMapper::removeDevice(int device) { - removeAllInputChannelsForDevice((uint16) device); - _registeredDevices.erase(device); -} - -int UserInputMapper::getInputChannels(InputChannels& channels) const { - for (auto& channel : _actionToInputsMap) { - channels.push_back(channel.second); - } - - return _actionToInputsMap.size(); -} - -QVector UserInputMapper::getAllInputsForDevice(uint16 device) { - InputChannels allChannels; - getInputChannels(allChannels); - - QVector channels; - for (InputChannel inputChannel : allChannels) { - if (inputChannel._input._device == device) { - channels.push_back(inputChannel); - } - } - - return channels; -} - -void UserInputMapper::update(float deltaTime) { - - // Reset the axis state for next loop - for (auto& channel : _actionStates) { - channel = 0.0f; - } - - for (auto& channel : _poseStates) { - channel = PoseValue(); - } - - int currentTimestamp = 0; - - for (auto& channelInput : _actionToInputsMap) { - auto& inputMapping = channelInput.second; - auto& inputID = inputMapping._input; - bool enabled = true; - - // Check if this input channel has modifiers and collect the possibilities - auto modifiersIt = _inputToModifiersMap.find(inputID.getID()); - if (modifiersIt != _inputToModifiersMap.end()) { - Modifiers validModifiers; - bool isActiveModifier = false; - for (auto& modifier : modifiersIt->second) { - auto deviceProxy = getDeviceProxy(modifier); - if (deviceProxy->getButton(modifier, currentTimestamp)) { - validModifiers.push_back(modifier); - isActiveModifier |= (modifier.getID() == inputMapping._modifier.getID()); - } - } - enabled = (validModifiers.empty() && !inputMapping.hasModifier()) || isActiveModifier; - } - - // if enabled: default input or all modifiers on - if (enabled) { - auto deviceProxy = getDeviceProxy(inputID); - switch (inputMapping._input.getType()) { - case ChannelType::BUTTON: { - _actionStates[channelInput.first] += inputMapping._scale * float(deviceProxy->getButton(inputID, currentTimestamp));// * deltaTime; // weight the impulse by the deltaTime - break; - } - case ChannelType::AXIS: { - _actionStates[channelInput.first] += inputMapping._scale * deviceProxy->getAxis(inputID, currentTimestamp); - break; - } - case ChannelType::POSE: { - if (!_poseStates[channelInput.first].isValid()) { - _poseStates[channelInput.first] = deviceProxy->getPose(inputID, currentTimestamp); - } - break; - } - default: { - break; //silence please - } - } - } else{ - // Channel input not enabled - enabled = false; - } - } - - // Scale all the channel step with the scale - static const float EPSILON = 0.01f; - for (auto i = 0; i < NUM_ACTIONS; i++) { - if (_externalActionStates[i] != 0) { - _actionStates[i] += _externalActionStates[i]; - _externalActionStates[i] = 0.0f; - } - _actionStates[i] *= _actionScales[i]; - - // Emit only on change, and emit when moving back to 0 - if (fabsf(_actionStates[i] - _lastActionStates[i]) > EPSILON) { - _lastActionStates[i] = _actionStates[i]; - emit actionEvent(i, _actionStates[i]); - } - // TODO: emit signal for pose changes - } -} - -QVector UserInputMapper::getAllActions() const { - QVector actions; - for (auto i = 0; i < NUM_ACTIONS; i++) { - actions.append(Action(i)); - } - return actions; -} - -QVector UserInputMapper::getInputChannelsForAction(UserInputMapper::Action action) { - QVector inputChannels; - std::pair ret; - ret = _actionToInputsMap.equal_range(action); - for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) { - inputChannels.append(it->second); - } - return inputChannels; -} - -int UserInputMapper::findAction(const QString& actionName) const { - auto actions = getAllActions(); - for (auto action : actions) { - if (getActionName(action) == actionName) { - return action; - } - } - // If the action isn't found, return -1 - return -1; -} - -QVector UserInputMapper::getActionNames() const { - QVector result; - for (auto i = 0; i < NUM_ACTIONS; i++) { - result << _actionNames[i]; - } - return result; -} - -void UserInputMapper::assignDefaulActionScales() { - _actionScales[LONGITUDINAL_BACKWARD] = 1.0f; // 1m per unit - _actionScales[LONGITUDINAL_FORWARD] = 1.0f; // 1m per unit - _actionScales[LATERAL_LEFT] = 1.0f; // 1m per unit - _actionScales[LATERAL_RIGHT] = 1.0f; // 1m per unit - _actionScales[VERTICAL_DOWN] = 1.0f; // 1m per unit - _actionScales[VERTICAL_UP] = 1.0f; // 1m per unit - _actionScales[YAW_LEFT] = 1.0f; // 1 degree per unit - _actionScales[YAW_RIGHT] = 1.0f; // 1 degree per unit - _actionScales[PITCH_DOWN] = 1.0f; // 1 degree per unit - _actionScales[PITCH_UP] = 1.0f; // 1 degree per unit - _actionScales[BOOM_IN] = 0.5f; // .5m per unit - _actionScales[BOOM_OUT] = 0.5f; // .5m per unit - _actionScales[LEFT_HAND] = 1.0f; // default - _actionScales[RIGHT_HAND] = 1.0f; // default - _actionScales[LEFT_HAND_CLICK] = 1.0f; // on - _actionScales[RIGHT_HAND_CLICK] = 1.0f; // on - _actionScales[SHIFT] = 1.0f; // on - _actionScales[ACTION1] = 1.0f; // default - _actionScales[ACTION2] = 1.0f; // default - _actionScales[TRANSLATE_X] = 1.0f; // default - _actionScales[TRANSLATE_Y] = 1.0f; // default - _actionScales[TRANSLATE_Z] = 1.0f; // default - _actionScales[ROLL] = 1.0f; // default - _actionScales[PITCH] = 1.0f; // default - _actionScales[YAW] = 1.0f; // default -} - -// This is only necessary as long as the actions are hardcoded -// Eventually you can just add the string when you add the action -void UserInputMapper::createActionNames() { - _actionNames[LONGITUDINAL_BACKWARD] = "LONGITUDINAL_BACKWARD"; - _actionNames[LONGITUDINAL_FORWARD] = "LONGITUDINAL_FORWARD"; - _actionNames[LATERAL_LEFT] = "LATERAL_LEFT"; - _actionNames[LATERAL_RIGHT] = "LATERAL_RIGHT"; - _actionNames[VERTICAL_DOWN] = "VERTICAL_DOWN"; - _actionNames[VERTICAL_UP] = "VERTICAL_UP"; - _actionNames[YAW_LEFT] = "YAW_LEFT"; - _actionNames[YAW_RIGHT] = "YAW_RIGHT"; - _actionNames[PITCH_DOWN] = "PITCH_DOWN"; - _actionNames[PITCH_UP] = "PITCH_UP"; - _actionNames[BOOM_IN] = "BOOM_IN"; - _actionNames[BOOM_OUT] = "BOOM_OUT"; - _actionNames[LEFT_HAND] = "LEFT_HAND"; - _actionNames[RIGHT_HAND] = "RIGHT_HAND"; - _actionNames[LEFT_HAND_CLICK] = "LEFT_HAND_CLICK"; - _actionNames[RIGHT_HAND_CLICK] = "RIGHT_HAND_CLICK"; - _actionNames[SHIFT] = "SHIFT"; - _actionNames[ACTION1] = "ACTION1"; - _actionNames[ACTION2] = "ACTION2"; - _actionNames[CONTEXT_MENU] = "CONTEXT_MENU"; - _actionNames[TOGGLE_MUTE] = "TOGGLE_MUTE"; - _actionNames[TRANSLATE_X] = "TranslateX"; - _actionNames[TRANSLATE_Y] = "TranslateY"; - _actionNames[TRANSLATE_Z] = "TranslateZ"; - _actionNames[ROLL] = "Roll"; - _actionNames[PITCH] = "Pitch"; - _actionNames[YAW] = "Yaw"; -} - -void UserInputMapper::registerStandardDevice() { - _standardController = std::make_shared(); - _standardController->registerToUserInputMapper(*this); -} - -float UserInputMapper::DeviceProxy::getValue(const Input& input, int timestamp) const { - switch (input.getType()) { - case UserInputMapper::ChannelType::BUTTON: - return getButton(input, timestamp) ? 1.0f : 0.0f; - - case UserInputMapper::ChannelType::AXIS: - return getAxis(input, timestamp); - - case UserInputMapper::ChannelType::POSE: - return getPose(input, timestamp)._valid ? 1.0f : 0.0f; - - default: - return 0.0f; - } -} \ No newline at end of file + + +bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) { + return addInputChannel(action, input, Input(), scale); +} + +bool UserInputMapper::addInputChannel(Action action, const Input& input, const Input& modifier, float scale) { + // Check that the device is registered + if (!getDeviceProxy(input)) { + qDebug() << "UserInputMapper::addInputChannel: The input comes from a device #" << input.getDevice() << "is unknown. no inputChannel mapped."; + return false; + } + + auto inputChannel = InputChannel(input, modifier, action, scale); + + // Insert or replace the input to modifiers + if (inputChannel.hasModifier()) { + auto& modifiers = _inputToModifiersMap[input.getID()]; + modifiers.push_back(inputChannel._modifier); + std::sort(modifiers.begin(), modifiers.end()); + } + + // Now update the action To Inputs side of things + _actionToInputsMap.insert(ActionToInputsMap::value_type(action, inputChannel)); + + return true; +} + +int UserInputMapper::addInputChannels(const InputChannels& channels) { + int nbAdded = 0; + for (auto& channel : channels) { + nbAdded += addInputChannel(channel._action, channel._input, channel._modifier, channel._scale); + } + return nbAdded; +} + +bool UserInputMapper::removeInputChannel(InputChannel inputChannel) { + // Remove from Input to Modifiers map + if (inputChannel.hasModifier()) { + _inputToModifiersMap.erase(inputChannel._input.getID()); + } + + // Remove from Action to Inputs map + std::pair ret; + ret = _actionToInputsMap.equal_range(inputChannel._action); + for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) { + if (it->second == inputChannel) { + _actionToInputsMap.erase(it); + return true; + } + } + + return false; +} + +void UserInputMapper::removeAllInputChannels() { + _inputToModifiersMap.clear(); + _actionToInputsMap.clear(); +} + +void UserInputMapper::removeAllInputChannelsForDevice(uint16 device) { + QVector channels = getAllInputsForDevice(device); + for (auto& channel : channels) { + removeInputChannel(channel); + } +} + +void UserInputMapper::removeDevice(int device) { + removeAllInputChannelsForDevice((uint16) device); + _registeredDevices.erase(device); +} + +int UserInputMapper::getInputChannels(InputChannels& channels) const { + for (auto& channel : _actionToInputsMap) { + channels.push_back(channel.second); + } + + return _actionToInputsMap.size(); +} + +QVector UserInputMapper::getAllInputsForDevice(uint16 device) { + InputChannels allChannels; + getInputChannels(allChannels); + + QVector channels; + for (InputChannel inputChannel : allChannels) { + if (inputChannel._input._device == device) { + channels.push_back(inputChannel); + } + } + + return channels; +} + +void fixBisectedAxis(float& full, float& negative, float& positive) { + full = full + (negative * -1.0f) + positive; + negative = full >= 0.0f ? 0.0f : full * -1.0f; + positive = full <= 0.0f ? 0.0f : full; +} + +void UserInputMapper::update(float deltaTime) { + + // Reset the axis state for next loop + for (auto& channel : _actionStates) { + channel = 0.0f; + } + + for (auto& channel : _poseStates) { + channel = PoseValue(); + } + + int currentTimestamp = 0; + for (auto& channelInput : _actionToInputsMap) { + auto& inputMapping = channelInput.second; + auto& inputID = inputMapping._input; + bool enabled = true; + + // Check if this input channel has modifiers and collect the possibilities + auto modifiersIt = _inputToModifiersMap.find(inputID.getID()); + if (modifiersIt != _inputToModifiersMap.end()) { + Modifiers validModifiers; + bool isActiveModifier = false; + for (auto& modifier : modifiersIt->second) { + auto deviceProxy = getDeviceProxy(modifier); + if (deviceProxy->getButton(modifier, currentTimestamp)) { + validModifiers.push_back(modifier); + isActiveModifier |= (modifier.getID() == inputMapping._modifier.getID()); + } + } + enabled = (validModifiers.empty() && !inputMapping.hasModifier()) || isActiveModifier; + } + + // if enabled: default input or all modifiers on + if (enabled) { + auto deviceProxy = getDeviceProxy(inputID); + switch (inputMapping._input.getType()) { + case ChannelType::BUTTON: { + _actionStates[channelInput.first] += inputMapping._scale * float(deviceProxy->getButton(inputID, currentTimestamp));// * deltaTime; // weight the impulse by the deltaTime + break; + } + case ChannelType::AXIS: { + _actionStates[channelInput.first] += inputMapping._scale * deviceProxy->getAxis(inputID, currentTimestamp); + break; + } + case ChannelType::POSE: { + if (!_poseStates[channelInput.first].isValid()) { + _poseStates[channelInput.first] = deviceProxy->getPose(inputID, currentTimestamp); + } + break; + } + default: { + break; //silence please + } + } + } else{ + // Channel input not enabled + enabled = false; + } + } + + // Scale all the channel step with the scale + for (auto i = 0; i < NUM_ACTIONS; i++) { + if (_externalActionStates[i] != 0) { + _actionStates[i] += _externalActionStates[i]; + _externalActionStates[i] = 0.0f; + } + } + + // merge the bisected and non-bisected axes for now + fixBisectedAxis(_actionStates[TRANSLATE_X], _actionStates[LATERAL_LEFT], _actionStates[LATERAL_RIGHT]); + fixBisectedAxis(_actionStates[TRANSLATE_Y], _actionStates[VERTICAL_DOWN], _actionStates[VERTICAL_UP]); + fixBisectedAxis(_actionStates[TRANSLATE_Z], _actionStates[LONGITUDINAL_FORWARD], _actionStates[LONGITUDINAL_BACKWARD]); + fixBisectedAxis(_actionStates[TRANSLATE_CAMERA_Z], _actionStates[BOOM_IN], _actionStates[BOOM_OUT]); + fixBisectedAxis(_actionStates[ROTATE_Y], _actionStates[YAW_LEFT], _actionStates[YAW_RIGHT]); + fixBisectedAxis(_actionStates[ROTATE_X], _actionStates[PITCH_UP], _actionStates[PITCH_DOWN]); + + + static const float EPSILON = 0.01f; + for (auto i = 0; i < NUM_ACTIONS; i++) { + _actionStates[i] *= _actionScales[i]; + // Emit only on change, and emit when moving back to 0 + if (fabsf(_actionStates[i] - _lastActionStates[i]) > EPSILON) { + _lastActionStates[i] = _actionStates[i]; + emit actionEvent(i, _actionStates[i]); + } + // TODO: emit signal for pose changes + } +} + +QVector UserInputMapper::getAllActions() const { + QVector actions; + for (auto i = 0; i < NUM_ACTIONS; i++) { + actions.append(Action(i)); + } + return actions; +} + +QVector UserInputMapper::getInputChannelsForAction(UserInputMapper::Action action) { + QVector inputChannels; + std::pair ret; + ret = _actionToInputsMap.equal_range(action); + for (ActionToInputsMap::iterator it=ret.first; it!=ret.second; ++it) { + inputChannels.append(it->second); + } + return inputChannels; +} + +int UserInputMapper::findAction(const QString& actionName) const { + auto actions = getAllActions(); + for (auto action : actions) { + if (getActionName(action) == actionName) { + return action; + } + } + // If the action isn't found, return -1 + return -1; +} + +QVector UserInputMapper::getActionNames() const { + QVector result; + for (auto i = 0; i < NUM_ACTIONS; i++) { + result << _actionNames[i]; + } + return result; +} + +void UserInputMapper::assignDefaulActionScales() { + _actionScales[LONGITUDINAL_BACKWARD] = 1.0f; // 1m per unit + _actionScales[LONGITUDINAL_FORWARD] = 1.0f; // 1m per unit + _actionScales[LATERAL_LEFT] = 1.0f; // 1m per unit + _actionScales[LATERAL_RIGHT] = 1.0f; // 1m per unit + _actionScales[VERTICAL_DOWN] = 1.0f; // 1m per unit + _actionScales[VERTICAL_UP] = 1.0f; // 1m per unit + _actionScales[YAW_LEFT] = 1.0f; // 1 degree per unit + _actionScales[YAW_RIGHT] = 1.0f; // 1 degree per unit + _actionScales[PITCH_DOWN] = 1.0f; // 1 degree per unit + _actionScales[PITCH_UP] = 1.0f; // 1 degree per unit + _actionScales[BOOM_IN] = 0.5f; // .5m per unit + _actionScales[BOOM_OUT] = 0.5f; // .5m per unit + _actionScales[LEFT_HAND] = 1.0f; // default + _actionScales[RIGHT_HAND] = 1.0f; // default + _actionScales[LEFT_HAND_CLICK] = 1.0f; // on + _actionScales[RIGHT_HAND_CLICK] = 1.0f; // on + _actionScales[SHIFT] = 1.0f; // on + _actionScales[ACTION1] = 1.0f; // default + _actionScales[ACTION2] = 1.0f; // default + _actionScales[TRANSLATE_X] = 1.0f; // default + _actionScales[TRANSLATE_Y] = 1.0f; // default + _actionScales[TRANSLATE_Z] = 1.0f; // default + _actionScales[ROLL] = 1.0f; // default + _actionScales[PITCH] = 1.0f; // default + _actionScales[YAW] = 1.0f; // default +} + +// This is only necessary as long as the actions are hardcoded +// Eventually you can just add the string when you add the action +void UserInputMapper::createActionNames() { + _actionNames[LONGITUDINAL_BACKWARD] = "LONGITUDINAL_BACKWARD"; + _actionNames[LONGITUDINAL_FORWARD] = "LONGITUDINAL_FORWARD"; + _actionNames[LATERAL_LEFT] = "LATERAL_LEFT"; + _actionNames[LATERAL_RIGHT] = "LATERAL_RIGHT"; + _actionNames[VERTICAL_DOWN] = "VERTICAL_DOWN"; + _actionNames[VERTICAL_UP] = "VERTICAL_UP"; + _actionNames[YAW_LEFT] = "YAW_LEFT"; + _actionNames[YAW_RIGHT] = "YAW_RIGHT"; + _actionNames[PITCH_DOWN] = "PITCH_DOWN"; + _actionNames[PITCH_UP] = "PITCH_UP"; + _actionNames[BOOM_IN] = "BOOM_IN"; + _actionNames[BOOM_OUT] = "BOOM_OUT"; + _actionNames[LEFT_HAND] = "LEFT_HAND"; + _actionNames[RIGHT_HAND] = "RIGHT_HAND"; + _actionNames[LEFT_HAND_CLICK] = "LEFT_HAND_CLICK"; + _actionNames[RIGHT_HAND_CLICK] = "RIGHT_HAND_CLICK"; + _actionNames[SHIFT] = "SHIFT"; + _actionNames[ACTION1] = "ACTION1"; + _actionNames[ACTION2] = "ACTION2"; + _actionNames[CONTEXT_MENU] = "CONTEXT_MENU"; + _actionNames[TOGGLE_MUTE] = "TOGGLE_MUTE"; + _actionNames[TRANSLATE_X] = "TranslateX"; + _actionNames[TRANSLATE_Y] = "TranslateY"; + _actionNames[TRANSLATE_Z] = "TranslateZ"; + _actionNames[ROLL] = "Roll"; + _actionNames[PITCH] = "Pitch"; + _actionNames[YAW] = "Yaw"; +} + +void UserInputMapper::registerStandardDevice() { + _standardController = std::make_shared(); + _standardController->registerToUserInputMapper(*this); + _standardController->assignDefaultInputMapping(*this); +} + +static int actionMetaTypeId = qRegisterMetaType(); +static int inputMetaTypeId = qRegisterMetaType(); +static int inputPairMetaTypeId = qRegisterMetaType(); + +QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input); +void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input); +QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action); +void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action); +QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair); +void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair); + +QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input) { + QScriptValue obj = engine->newObject(); + obj.setProperty("device", input.getDevice()); + obj.setProperty("channel", input.getChannel()); + obj.setProperty("type", (unsigned short)input.getType()); + obj.setProperty("id", input.getID()); + return obj; +} + +void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input) { + input.setDevice(object.property("device").toUInt16()); + input.setChannel(object.property("channel").toUInt16()); + input.setType(object.property("type").toUInt16()); + input.setID(object.property("id").toInt32()); +} + +QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action) { + QScriptValue obj = engine->newObject(); + auto userInputMapper = DependencyManager::get(); + obj.setProperty("action", (int)action); + obj.setProperty("actionName", userInputMapper->getActionName(action)); + return obj; +} + +void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action) { + action = UserInputMapper::Action(object.property("action").toVariant().toInt()); +} + +QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair) { + QScriptValue obj = engine->newObject(); + obj.setProperty("input", inputToScriptValue(engine, inputPair.first)); + obj.setProperty("inputName", inputPair.second); + return obj; +} + +void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair) { + inputFromScriptValue(object.property("input"), inputPair.first); + inputPair.second = QString(object.property("inputName").toVariant().toString()); +} + +void UserInputMapper::registerControllerTypes(QScriptEngine* engine) { + qScriptRegisterSequenceMetaType >(engine); + qScriptRegisterSequenceMetaType >(engine); + qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue); + qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue); + qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue); +} + +UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardButtonChannel button) { + return Input(STANDARD_DEVICE, button, ChannelType::BUTTON); +} + +UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardAxisChannel axis) { + return Input(STANDARD_DEVICE, axis, ChannelType::AXIS); +} + +UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) { + return Input(STANDARD_DEVICE, pose, ChannelType::POSE); +} diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h index 8b466d79c9..d463ed0482 100644 --- a/libraries/controllers/src/controllers/UserInputMapper.h +++ b/libraries/controllers/src/controllers/UserInputMapper.h @@ -1,7 +1,4 @@ // -// UserInputMapper.h -// input-plugins/src/input-plugins -// // Created by Sam Gateau on 4/27/15. // Copyright 2015 High Fidelity, Inc. // @@ -9,6 +6,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#pragma once #ifndef hifi_UserInputMapper_h #define hifi_UserInputMapper_h @@ -20,6 +18,11 @@ #include #include +#include "Pose.h" +#include "Input.h" +#include "DeviceProxy.h" +#include "StandardControls.h" + class StandardController; typedef std::shared_ptr StandardControllerPointer; @@ -30,86 +33,22 @@ class UserInputMapper : public QObject, public Dependency { public: ~UserInputMapper(); + using DeviceProxy = controller::DeviceProxy; + using PoseValue = controller::Pose; + using Input = controller::Input; + using ChannelType = controller::ChannelType; + typedef unsigned short uint16; typedef unsigned int uint32; - enum class ChannelType { - UNKNOWN = 0, - BUTTON = 1, - AXIS, - POSE, - }; + static void registerControllerTypes(QScriptEngine* engine); - // Input is the unique identifier to find a n input channel of a particular device - // Devices are responsible for registering to the UseInputMapper so their input channels can be sued and mapped - // to the Action channels - class Input { - public: - union { - struct { - uint16 _device; // Up to 64K possible devices - uint16 _channel : 13; // 2^13 possible channel per Device - uint16 _type : 2; // 2 bits to store the Type directly in the ID - uint16 _padding : 1; // 2 bits to store the Type directly in the ID - }; - uint32 _id = 0; // by default Input is 0 meaning invalid - }; - - bool isValid() const { return (_id != 0); } - - uint16 getDevice() const { return _device; } - uint16 getChannel() const { return _channel; } - uint32 getID() const { return _id; } - ChannelType getType() const { return (ChannelType) _type; } - - void setDevice(uint16 device) { _device = device; } - void setChannel(uint16 channel) { _channel = channel; } - void setType(uint16 type) { _type = type; } - void setID(uint32 ID) { _id = ID; } - - bool isButton() const { return getType() == ChannelType::BUTTON; } - bool isAxis() const { return getType() == ChannelType::AXIS; } - bool isPose() const { return getType() == ChannelType::POSE; } - - // WORKAROUND: the explicit initializer here avoids a bug in GCC-4.8.2 (but not found in 4.9.2) - // where the default initializer (a C++-11ism) for the union data above is not applied. - explicit Input() : _id(0) {} - explicit Input(uint32 id) : _id(id) {} - explicit Input(uint16 device, uint16 channel, ChannelType type) : _device(device), _channel(channel), _type(uint16(type)), _padding(0) {} - Input(const Input& src) : _id(src._id) {} - Input& operator = (const Input& src) { _id = src._id; return (*this); } - bool operator ==(const Input& right) const { return _id == right._id; } - bool operator < (const Input& src) const { return _id < src._id; } - - static const Input INVALID_INPUT; - static const uint16 INVALID_DEVICE; - static const uint16 INVALID_CHANNEL; - static const uint16 INVALID_TYPE; - static const uint16 ACTIONS_DEVICE; - static const uint16 STANDARD_DEVICE; - }; + static const uint16 ACTIONS_DEVICE; + static const uint16 STANDARD_DEVICE; // Modifiers are just button inputID typedef std::vector< Input > Modifiers; - - class PoseValue { - public: - glm::vec3 _translation{ 0.0f }; - glm::quat _rotation; - bool _valid; - - PoseValue() : _valid(false) {}; - PoseValue(glm::vec3 translation, glm::quat rotation) : _translation(translation), _rotation(rotation), _valid(true) {} - PoseValue(const PoseValue&) = default; - PoseValue& operator = (const PoseValue&) = default; - bool operator ==(const PoseValue& right) const { return _translation == right.getTranslation() && _rotation == right.getRotation() && _valid == right.isValid(); } - - bool isValid() const { return _valid; } - glm::vec3 getTranslation() const { return _translation; } - glm::quat getRotation() const { return _rotation; } - }; - typedef std::function ButtonGetter; typedef std::function AxisGetter; typedef std::function PoseGetter; @@ -119,22 +58,6 @@ public: typedef QVector AvailableInput; - class DeviceProxy { - public: - DeviceProxy(QString name) : _baseName(name), _name(name) {} - const QString& getBaseName() const { return _baseName; } - const QString& getName() const { return _name; } - - QString _baseName; - QString _name; - ButtonGetter getButton = [] (const Input& input, int timestamp) -> bool { return false; }; - AxisGetter getAxis = [] (const Input& input, int timestamp) -> float { return 0.0f; }; - PoseGetter getPose = [] (const Input& input, int timestamp) -> PoseValue { return PoseValue(); }; - AvailableInputGetter getAvailabeInputs = [] () -> AvailableInput { return QVector(); }; - ResetBindings resetDeviceBindings = [] () -> bool { return true; }; - float getValue(const Input& input, int timestamp = 0) const; - typedef std::shared_ptr Pointer; - }; // GetFreeDeviceID should be called before registering a device to use an ID not used by a different device. uint16 getFreeDeviceID() { return _nextFreeDeviceID++; } @@ -162,8 +85,9 @@ public: ROTATE_Z, ROLL = ROTATE_Z, TRANSLATE_CAMERA_Z, + NUM_COMBINED_AXES, - LEFT_HAND, + LEFT_HAND = NUM_COMBINED_AXES, RIGHT_HAND, LEFT_HAND_CLICK, @@ -222,7 +146,11 @@ public: // Return true if theinput channel is created correctly, false either bool addInputChannel(Action action, const Input& input, float scale = 1.0f); bool addInputChannel(Action action, const Input& input, const Input& modifer, float scale = 1.0f); - + + UserInputMapper::Input makeStandardInput(controller::StandardButtonChannel button); + UserInputMapper::Input makeStandardInput(controller::StandardAxisChannel axis); + UserInputMapper::Input makeStandardInput(controller::StandardPoseChannel pose); + // Under the hood, the input channels are organized in map sorted on the _output // The InputChannel class is just the full values describing the input channel in one object class InputChannel { @@ -276,7 +204,7 @@ public: typedef std::map DevicesMap; DevicesMap getDevices() { return _registeredDevices; } - uint16 getStandardDeviceID() const { return Input::STANDARD_DEVICE; } + uint16 getStandardDeviceID() const { return STANDARD_DEVICE; } DeviceProxy::Pointer getStandardDevice() { return _registeredDevices[getStandardDeviceID()]; } signals: @@ -288,7 +216,7 @@ protected: StandardControllerPointer _standardController; DevicesMap _registeredDevices; - uint16 _nextFreeDeviceID = Input::STANDARD_DEVICE + 1; + uint16 _nextFreeDeviceID = STANDARD_DEVICE + 1; typedef std::map InputToMoModifiersMap; InputToMoModifiersMap _inputToModifiersMap; @@ -309,6 +237,7 @@ protected: }; Q_DECLARE_METATYPE(UserInputMapper::InputPair) +Q_DECLARE_METATYPE(UserInputMapper::PoseValue) Q_DECLARE_METATYPE(QVector) Q_DECLARE_METATYPE(UserInputMapper::Input) Q_DECLARE_METATYPE(UserInputMapper::InputChannel) diff --git a/libraries/input-plugins/src/input-plugins/Joystick.cpp b/libraries/input-plugins/src/input-plugins/Joystick.cpp index aa5bbbba07..d3e4e7a629 100644 --- a/libraries/input-plugins/src/input-plugins/Joystick.cpp +++ b/libraries/input-plugins/src/input-plugins/Joystick.cpp @@ -1,145 +1,207 @@ -// -// Joystick.cpp -// input-plugins/src/input-plugins -// -// Created by Stephen Birarda on 2014-09-23. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "Joystick.h" - -#include -#include - -const float CONTROLLER_THRESHOLD = 0.3f; - -#ifdef HAVE_SDL2 -const float MAX_AXIS = 32768.0f; - -Joystick::Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController) : - InputDevice(name), - _sdlGameController(sdlGameController), - _sdlJoystick(SDL_GameControllerGetJoystick(_sdlGameController)), - _instanceId(instanceId) -{ - -} - -#endif - -Joystick::~Joystick() { - closeJoystick(); -} - -void Joystick::closeJoystick() { -#ifdef HAVE_SDL2 - SDL_GameControllerClose(_sdlGameController); -#endif -} - -void Joystick::update(float deltaTime, bool jointsCaptured) { - for (auto axisState : _axisStateMap) { - if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) { - _axisStateMap[axisState.first] = 0.0f; - } - } -} - -void Joystick::focusOutEvent() { - _axisStateMap.clear(); - _buttonPressedMap.clear(); -}; - -#ifdef HAVE_SDL2 - -void Joystick::handleAxisEvent(const SDL_ControllerAxisEvent& event) { - SDL_GameControllerAxis axis = (SDL_GameControllerAxis) event.axis; - _axisStateMap[makeInput((controller::StandardAxisChannel)axis).getChannel()] = (float)event.value / MAX_AXIS; -} - -void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) { - auto input = makeInput((controller::StandardButtonChannel)event.button); - bool newValue = event.state == SDL_PRESSED; - if (newValue) { - _buttonPressedMap.insert(input.getChannel()); - } else { - _buttonPressedMap.erase(input.getChannel()); - } -} - -#endif - - -void Joystick::registerToUserInputMapper(UserInputMapper& mapper) { - // Grab the current free device ID - _deviceID = mapper.getFreeDeviceID(); - - auto proxy = std::make_shared(_name); - proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); }; - proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); }; - proxy->getAvailabeInputs = [this] () -> QVector { - QVector availableInputs; - // Buttons - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "A")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "B")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "X")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Y")); - - // DPad - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "DU")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "DD")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "DL")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "DR")); - - // Bumpers - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "LB")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "RB")); - - // Stick press - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "LS")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "RS")); - - // Center buttons - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::START), "Start")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Back")); - - // Analog sticks - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LY), "LY")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LX), "LX")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RY), "RY")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RX), "RX")); - - // Triggers - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "LT")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "RT")); - - // Aliases, PlayStation style names - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "L1")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "R1")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "L2")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "R2")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "L3")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "R3")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Select")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "Cross")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "Circle")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "Square")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Triangle")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "Up")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "Down")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "Left")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "Right")); - - return availableInputs; - }; - proxy->resetDeviceBindings = [this, &mapper] () -> bool { - mapper.removeAllInputChannelsForDevice(_deviceID); - this->assignDefaultInputMapping(mapper); - return true; - }; - mapper.registerDevice(_deviceID, proxy); -} - +// +// Joystick.cpp +// input-plugins/src/input-plugins +// +// Created by Stephen Birarda on 2014-09-23. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Joystick.h" + +#include +#include + +const float CONTROLLER_THRESHOLD = 0.3f; + +#ifdef HAVE_SDL2 +const float MAX_AXIS = 32768.0f; + +Joystick::Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController) : + InputDevice(name), + _sdlGameController(sdlGameController), + _sdlJoystick(SDL_GameControllerGetJoystick(_sdlGameController)), + _instanceId(instanceId) +{ + +} + +#endif + +Joystick::~Joystick() { + closeJoystick(); +} + +void Joystick::closeJoystick() { +#ifdef HAVE_SDL2 + SDL_GameControllerClose(_sdlGameController); +#endif +} + +void Joystick::update(float deltaTime, bool jointsCaptured) { + for (auto axisState : _axisStateMap) { + if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) { + _axisStateMap[axisState.first] = 0.0f; + } + } +} + +void Joystick::focusOutEvent() { + _axisStateMap.clear(); + _buttonPressedMap.clear(); +}; + +#ifdef HAVE_SDL2 + +void Joystick::handleAxisEvent(const SDL_ControllerAxisEvent& event) { + SDL_GameControllerAxis axis = (SDL_GameControllerAxis) event.axis; + _axisStateMap[makeInput((controller::StandardAxisChannel)axis).getChannel()] = (float)event.value / MAX_AXIS; +} + +void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) { + auto input = makeInput((controller::StandardButtonChannel)event.button); + bool newValue = event.state == SDL_PRESSED; + if (newValue) { + _buttonPressedMap.insert(input.getChannel()); + } else { + _buttonPressedMap.erase(input.getChannel()); + } +} + +#endif + + +void Joystick::registerToUserInputMapper(UserInputMapper& mapper) { + // Grab the current free device ID + _deviceID = mapper.getFreeDeviceID(); + + auto proxy = std::make_shared(_name); + proxy->getButton = [this] (const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); }; + proxy->getAxis = [this] (const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); }; + proxy->getAvailabeInputs = [this] () -> QVector { + QVector availableInputs; + // Buttons + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "A")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "B")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "X")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Y")); + + // DPad + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "DU")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "DD")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "DL")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "DR")); + + // Bumpers + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "LB")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "RB")); + + // Stick press + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "LS")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "RS")); + + // Center buttons + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::START), "Start")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Back")); + + // Analog sticks + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LY), "LY")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LX), "LX")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RY), "RY")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RX), "RX")); + + // Triggers + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "LT")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "RT")); + + // Aliases, PlayStation style names + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "L1")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "R1")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "L2")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "R2")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "L3")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "R3")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Select")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::A), "Cross")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::B), "Circle")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::X), "Square")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::Y), "Triangle")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DU), "Up")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DD), "Down")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DL), "Left")); + availableInputs.append(UserInputMapper::InputPair(makeInput(controller::DR), "Right")); + + return availableInputs; + }; + proxy->resetDeviceBindings = [this, &mapper] () -> bool { + mapper.removeAllInputChannelsForDevice(_deviceID); + this->assignDefaultInputMapping(mapper); + return true; + }; + mapper.registerDevice(_deviceID, proxy); +} + + +void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) { +#if 0 +#ifdef HAVE_SDL2 + const float JOYSTICK_MOVE_SPEED = 1.0f; + const float DPAD_MOVE_SPEED = 0.5f; + const float JOYSTICK_YAW_SPEED = 0.5f; + const float JOYSTICK_PITCH_SPEED = 0.25f; + const float BOOM_SPEED = 0.1f; + + // Y axes are flipped (up is negative) + // Left Joystick: Movement, strafing + mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), JOYSTICK_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LX), JOYSTICK_MOVE_SPEED); + // Right Joystick: Camera orientation + mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), JOYSTICK_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), JOYSTICK_PITCH_SPEED); + + // Dpad movement + mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), DPAD_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), DPAD_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), DPAD_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), DPAD_MOVE_SPEED); + + // Button controls + mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), DPAD_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), DPAD_MOVE_SPEED); + + // Zoom + mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), BOOM_SPEED); + mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LT), BOOM_SPEED); + + // Hold front right shoulder button for precision controls + // Left Joystick: Movement, strafing + mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f); + mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f); + + // Right Joystick: Camera orientation + mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), makeInput(controller::RB), JOYSTICK_YAW_SPEED / 2.0f); + mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), makeInput(controller::RB), JOYSTICK_PITCH_SPEED / 2.0f); + + // Dpad movement + mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f); + mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f); + mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f); + mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f); + + // Button controls + mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f); + mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f); + + // Zoom + mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), makeInput(controller::RB), BOOM_SPEED / 2.0f); + mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LT), makeInput(controller::RB), BOOM_SPEED / 2.0f); + + mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(controller::RB)); + + mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(controller::B)); + mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(controller::A)); +#endif +#endif +} \ No newline at end of file diff --git a/libraries/input-plugins/src/input-plugins/Joystick.h b/libraries/input-plugins/src/input-plugins/Joystick.h index 8e4cdb365f..38f00f4f15 100644 --- a/libraries/input-plugins/src/input-plugins/Joystick.h +++ b/libraries/input-plugins/src/input-plugins/Joystick.h @@ -1,69 +1,70 @@ -// -// Joystick.h -// input-plugins/src/input-plugins -// -// Created by Stephen Birarda on 2014-09-23. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_Joystick_h -#define hifi_Joystick_h - -#include -#include - -#ifdef HAVE_SDL2 -#include -#undef main -#endif - -#include -#include - -class Joystick : public QObject, public InputDevice { - Q_OBJECT - Q_PROPERTY(QString name READ getName) - -#ifdef HAVE_SDL2 - Q_PROPERTY(int instanceId READ getInstanceId) -#endif - -public: - - const QString& getName() const { return _name; } - - // Device functions - virtual void registerToUserInputMapper(UserInputMapper& mapper) override; - virtual void update(float deltaTime, bool jointsCaptured) override; - virtual void focusOutEvent() override; - - Joystick() : InputDevice("Joystick") {} - ~Joystick(); - -#ifdef HAVE_SDL2 - Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController); -#endif - - void closeJoystick(); - -#ifdef HAVE_SDL2 - void handleAxisEvent(const SDL_ControllerAxisEvent& event); - void handleButtonEvent(const SDL_ControllerButtonEvent& event); -#endif - -#ifdef HAVE_SDL2 - int getInstanceId() const { return _instanceId; } -#endif - -private: -#ifdef HAVE_SDL2 - SDL_GameController* _sdlGameController; - SDL_Joystick* _sdlJoystick; - SDL_JoystickID _instanceId; -#endif -}; - -#endif // hifi_Joystick_h +// +// Joystick.h +// input-plugins/src/input-plugins +// +// Created by Stephen Birarda on 2014-09-23. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_Joystick_h +#define hifi_Joystick_h + +#include +#include + +#ifdef HAVE_SDL2 +#include +#undef main +#endif + +#include +#include + +class Joystick : public QObject, public InputDevice { + Q_OBJECT + Q_PROPERTY(QString name READ getName) + +#ifdef HAVE_SDL2 + Q_PROPERTY(int instanceId READ getInstanceId) +#endif + +public: + + const QString& getName() const { return _name; } + + // Device functions + virtual void registerToUserInputMapper(UserInputMapper& mapper) override; + virtual void assignDefaultInputMapping(UserInputMapper& mapper) override; + virtual void update(float deltaTime, bool jointsCaptured) override; + virtual void focusOutEvent() override; + + Joystick() : InputDevice("Joystick") {} + ~Joystick(); + +#ifdef HAVE_SDL2 + Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController); +#endif + + void closeJoystick(); + +#ifdef HAVE_SDL2 + void handleAxisEvent(const SDL_ControllerAxisEvent& event); + void handleButtonEvent(const SDL_ControllerButtonEvent& event); +#endif + +#ifdef HAVE_SDL2 + int getInstanceId() const { return _instanceId; } +#endif + +private: +#ifdef HAVE_SDL2 + SDL_GameController* _sdlGameController; + SDL_Joystick* _sdlJoystick; + SDL_JoystickID _instanceId; +#endif +}; + +#endif // hifi_Joystick_h diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp index 9d3d06ecb7..e8cebd8e54 100644 --- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp +++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp @@ -449,6 +449,17 @@ void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, boo #endif // HAVE_SIXENSE } +static const auto L0 = controller::BACK; +static const auto L1 = controller::DL; +static const auto L2 = controller::DD; +static const auto L3 = controller::DR; +static const auto L4 = controller::DU; +static const auto R0 = controller::START; +static const auto R1 = controller::X; +static const auto R2 = controller::A; +static const auto R3 = controller::B; +static const auto R4 = controller::Y; + void SixenseManager::registerToUserInputMapper(UserInputMapper& mapper) { // Grab the current free device ID _deviceID = mapper.getFreeDeviceID(); @@ -459,31 +470,75 @@ void SixenseManager::registerToUserInputMapper(UserInputMapper& mapper) { using namespace controller; proxy->getAvailabeInputs = [this]() -> QVector { QVector availableInputs; - availableInputs.append(UserInputMapper::InputPair(makeInput(BACK), "L0")); - availableInputs.append(UserInputMapper::InputPair(makeInput(DL), "L1")); - availableInputs.append(UserInputMapper::InputPair(makeInput(DD), "L2")); - availableInputs.append(UserInputMapper::InputPair(makeInput(DR), "L3")); - availableInputs.append(UserInputMapper::InputPair(makeInput(DU), "L4")); + availableInputs.append(UserInputMapper::InputPair(makeInput(L0), "L0")); + availableInputs.append(UserInputMapper::InputPair(makeInput(L1), "L1")); + availableInputs.append(UserInputMapper::InputPair(makeInput(L2), "L2")); + availableInputs.append(UserInputMapper::InputPair(makeInput(L3), "L3")); + availableInputs.append(UserInputMapper::InputPair(makeInput(L4), "L4")); availableInputs.append(UserInputMapper::InputPair(makeInput(LB), "LB")); availableInputs.append(UserInputMapper::InputPair(makeInput(LS), "LS")); availableInputs.append(UserInputMapper::InputPair(makeInput(LX), "LX")); availableInputs.append(UserInputMapper::InputPair(makeInput(LY), "LY")); availableInputs.append(UserInputMapper::InputPair(makeInput(LT), "LT")); - availableInputs.append(UserInputMapper::InputPair(makeInput(START), "R0")); - availableInputs.append(UserInputMapper::InputPair(makeInput(X), "R1")); - availableInputs.append(UserInputMapper::InputPair(makeInput(A), "R2")); - availableInputs.append(UserInputMapper::InputPair(makeInput(B), "R3")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Y), "R4")); + availableInputs.append(UserInputMapper::InputPair(makeInput(R0), "R0")); + availableInputs.append(UserInputMapper::InputPair(makeInput(R1), "R1")); + availableInputs.append(UserInputMapper::InputPair(makeInput(R2), "R2")); + availableInputs.append(UserInputMapper::InputPair(makeInput(R3), "R3")); + availableInputs.append(UserInputMapper::InputPair(makeInput(R4), "R4")); availableInputs.append(UserInputMapper::InputPair(makeInput(RB), "RB")); availableInputs.append(UserInputMapper::InputPair(makeInput(RS), "RS")); availableInputs.append(UserInputMapper::InputPair(makeInput(RX), "RX")); availableInputs.append(UserInputMapper::InputPair(makeInput(RY), "RY")); availableInputs.append(UserInputMapper::InputPair(makeInput(RT), "RT")); + availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT), "LeftPose")); + availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT), "RightPose")); return availableInputs; }; mapper.registerDevice(_deviceID, proxy); } +void SixenseManager::assignDefaultInputMapping(UserInputMapper& mapper) { + const float JOYSTICK_MOVE_SPEED = 1.0f; + const float JOYSTICK_YAW_SPEED = 0.5f; + const float JOYSTICK_PITCH_SPEED = 0.25f; + const float BUTTON_MOVE_SPEED = 1.0f; + const float BOOM_SPEED = 0.1f; + using namespace controller; + + // Left Joystick: Movement, strafing + mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(LY), JOYSTICK_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(LX), JOYSTICK_MOVE_SPEED); + + // Right Joystick: Camera orientation + mapper.addInputChannel(UserInputMapper::YAW, makeInput(RX), JOYSTICK_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH, makeInput(RY), JOYSTICK_PITCH_SPEED); + + // Buttons + mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(L3), BOOM_SPEED); + mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(L1), BOOM_SPEED); + + mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(R3), BUTTON_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(R1), BUTTON_MOVE_SPEED); + + mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(L2)); + mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(R2)); + + mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(L4)); + mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(R4)); + + // FIXME +// mapper.addInputChannel(UserInputMapper::LEFT_HAND, makeInput(LEFT_HAND)); +// mapper.addInputChannel(UserInputMapper::RIGHT_HAND, makeInput(RIGHT_HAND)); + + mapper.addInputChannel(UserInputMapper::LEFT_HAND_CLICK, makeInput(LT)); + mapper.addInputChannel(UserInputMapper::RIGHT_HAND_CLICK, makeInput(RT)); + + // TODO find a mechanism to allow users to navigate the context menu via + mapper.addInputChannel(UserInputMapper::CONTEXT_MENU, makeInput(L0)); + mapper.addInputChannel(UserInputMapper::TOGGLE_MUTE, makeInput(R0)); + +} + // virtual void SixenseManager::saveSettings() const { Settings settings; diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.h b/libraries/input-plugins/src/input-plugins/SixenseManager.h index 2e7dd3223d..897ca72940 100644 --- a/libraries/input-plugins/src/input-plugins/SixenseManager.h +++ b/libraries/input-plugins/src/input-plugins/SixenseManager.h @@ -61,6 +61,8 @@ public: // Device functions virtual void registerToUserInputMapper(UserInputMapper& mapper) override; + virtual void assignDefaultInputMapping(UserInputMapper& mapper) override; + virtual void update(float deltaTime, bool jointsCaptured) override; virtual void focusOutEvent() override; diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 0dfc2fe09e..dc08fd7a69 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -308,8 +308,6 @@ void ScriptEngine::init() { registerGlobalObject("Script", this); registerGlobalObject("Audio", &AudioScriptingInterface::getInstance()); - auto scriptingInterface = DependencyManager::get(); - registerGlobalObject("Controller", scriptingInterface.data()); registerGlobalObject("Entities", entityScriptingInterface.data()); registerGlobalObject("Quat", &_quatLibrary); registerGlobalObject("Vec3", &_vec3Library); @@ -319,11 +317,9 @@ void ScriptEngine::init() { // constants globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE))); - if (scriptingInterface) { - scriptingInterface->registerControllerTypes(this); - } - - + auto scriptingInterface = DependencyManager::get(); + registerGlobalObject("Controller", scriptingInterface.data()); + UserInputMapper::registerControllerTypes(this); } void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) {