From bea6fdd8902327ad3e1d820d616a4e20d25692f2 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 19 Oct 2015 19:31:25 -0700 Subject: [PATCH] Working on JSON parsing and cleanup Conflicts: libraries/controllers/src/controllers/Route.cpp libraries/controllers/src/controllers/ScriptingInterface.cpp libraries/controllers/src/controllers/StandardController.cpp libraries/controllers/src/controllers/impl/RouteBuilderProxy.h --- .../resources/controllers/keyboardMouse.json | 25 + interface/resources/controllers/standard.json | 41 + interface/resources/controllers/xbox.json | 40 +- interface/resources/qml/TestControllers.qml | 2 +- interface/src/Application.cpp | 66 +- interface/src/Application.h | 2 +- interface/src/devices/3DConnexionClient.cpp | 153 ++-- interface/src/devices/3DConnexionClient.h | 28 +- .../ControllerScriptingInterface.cpp | 25 - .../scripting/ControllerScriptingInterface.h | 2 - interface/src/ui/ApplicationCompositor.cpp | 2 +- interface/src/ui/PreferencesDialog.cpp | 4 +- .../controllers/src/controllers/Actions.cpp | 71 ++ .../controllers/src/controllers/Actions.h | 100 +++ .../src/controllers/DeviceProxy.cpp | 2 +- .../controllers/src/controllers/DeviceProxy.h | 24 +- .../controllers/src/controllers/Endpoint.h | 14 +- libraries/controllers/src/controllers/Input.h | 39 +- .../src/controllers/InputDevice.cpp | 107 +-- .../controllers/src/controllers/InputDevice.h | 45 +- .../controllers/src/controllers/Mapping.cpp | 8 - .../controllers/src/controllers/Mapping.h | 8 +- .../controllers/src/controllers/Pose.cpp | 8 +- libraries/controllers/src/controllers/Pose.h | 20 +- .../controllers/src/controllers/Route.cpp | 1 - libraries/controllers/src/controllers/Route.h | 9 +- .../src/controllers/ScriptingInterface.cpp | 620 +++---------- .../src/controllers/ScriptingInterface.h | 83 +- .../src/controllers/StandardController.cpp | 213 ++--- .../src/controllers/StandardController.h | 24 +- .../src/controllers/UserInputMapper.cpp | 830 ++++++++++++------ .../src/controllers/UserInputMapper.h | 351 +++----- .../controllers/impl/MappingBuilderProxy.cpp | 46 +- .../controllers/impl/MappingBuilderProxy.h | 13 +- .../controllers/impl/RouteBuilderProxy.cpp | 40 +- .../src/controllers/impl/RouteBuilderProxy.h | 13 +- libraries/entities-renderer/CMakeLists.txt | 2 +- .../src/input-plugins/Joystick.cpp | 190 ++-- .../src/input-plugins/Joystick.h | 10 +- .../src/input-plugins/KeyboardMouseDevice.cpp | 240 +++-- .../src/input-plugins/KeyboardMouseDevice.h | 16 +- .../src/input-plugins/SDL2Manager.cpp | 19 +- .../src/input-plugins/SixenseManager.cpp | 168 ++-- .../src/input-plugins/SixenseManager.h | 6 +- .../input-plugins/ViveControllerManager.cpp | 258 +++--- .../src/input-plugins/ViveControllerManager.h | 39 +- libraries/script-engine/src/ScriptEngine.cpp | 4 +- libraries/script-engine/src/ScriptEngine.h | 2 - tests/controllers/src/main.cpp | 8 +- 49 files changed, 1925 insertions(+), 2116 deletions(-) create mode 100644 interface/resources/controllers/keyboardMouse.json create mode 100644 interface/resources/controllers/standard.json create mode 100644 libraries/controllers/src/controllers/Actions.cpp create mode 100644 libraries/controllers/src/controllers/Actions.h diff --git a/interface/resources/controllers/keyboardMouse.json b/interface/resources/controllers/keyboardMouse.json new file mode 100644 index 0000000000..71450a0c48 --- /dev/null +++ b/interface/resources/controllers/keyboardMouse.json @@ -0,0 +1,25 @@ +{ + "name": "Keyboard/Mouse to Actions", + "channels": [ + { "from": "Keyboard.W", "to": "Actions.LONGITUDINAL_FORWARD" }, + { "from": "Keyboard.S", "to": "Actions.LONGITUDINAL_BACKWARD" }, + { "from": "Keyboard.A", "to": "Actions.YAW_LEFT" }, + { "from": "Keyboard.D", "to": "Actions.YAW_RIGHT" }, + { "from": "Keyboard.A", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" }, + { "from": "Keyboard.D", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" }, + { "from": "Keyboard.A", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_LEFT" }, + { "from": "Keyboard.D", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_RIGHT" }, + { "from": "Keyboard.C", "to": "Actions.VERTICAL_DOWN" }, + { "from": "Keyboard.E", "to": "Actions.VERTICAL_UP" }, + { "from": "Keyboard.Up", "to": "Actions.LONGITUDINAL_FORWARD" }, + { "from": "Keyboard.Down", "to": "Actions.LONGITUDINAL_BACKWARD" }, + { "from": "Keyboard.Left", "to": "Actions.YAW_LEFT" }, + { "from": "Keyboard.Right", "to": "Actions.YAW_RIGHT" }, + { "from": "Keyboard.PgDown", "to": "Actions.VERTICAL_DOWN" }, + { "from": "Keyboard.PgUp", "to": "Actions.VERTICAL_UP" }, + { "from": "Keyboard.MouseMoveLeft", "when": "Keyboard.RightMouseClick", "to": "Actions.YAW_LEFT" }, + { "from": "Keyboard.MouseMoveRight", "when": "Keyboard.RightMouseClick", "to": "Actions.YAW_RIGHT" }, + { "from": "Keyboard.MouseMoveUp", "when": "Keyboard.RightMouseClick", "to": "Actions.PITCH_UP" }, + { "from": "Keyboard.MouseMoveDown", "when": "Keyboard.RightMouseClick", "to": "Actions.PITCH_DOWN" } + ] +} diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json new file mode 100644 index 0000000000..364d24ae16 --- /dev/null +++ b/interface/resources/controllers/standard.json @@ -0,0 +1,41 @@ +{ + "name": "Standard to Action", + "channels": [ + { "from": "Standard.LY", "to": "Actions.TranslateZ" }, + { "from": "Standard.LX", "to": "Actions.TranslateX" }, + { "from": "Standard.RX", "to": "Actions.Yaw" }, + { "from": "Standard.RY", "to": "Actions.Pitch" }, + { + "from": "Standard.DU", + "to": "Actions.LONGITUDINAL_FORWARD", + "filters": [ { "type": "scale", "scale": 0.5 } ] + }, + { + "from": "Standard.DD", + "to": "Actions.LONGITUDINAL_BACKWARD", + "filters": [ { "type": "scale", "scale": 0.5 } ] + }, + { + "from": "Standard.DR", + "to": "Actions.LATERAL_RIGHT", + "filters": [ { "type": "scale", "scale": 0.5 } ] + }, + { + "from": "Standard.DL", + "to": "Actions.LATERAL_LEFT", + "filters": [ { "type": "scale", "scale": 0.5 } ] + }, + { "from": "Standard.Y", "to": "Actions.VERTICAL_UP" }, + { "from": "Standard.X", "to": "Actions.VERTICAL_DOWN" }, + { + "from": "Standard.RT", + "to": "Actions.BOOM_IN", + "filters": [ { "type": "scale", "scale": 0.1 } ] + }, + { + "from": "Standard.LT", + "to": "Actions.BOOM_OUT", + "filters": [ { "type": "scale", "scale": 0.1 } ] + } + ] +} diff --git a/interface/resources/controllers/xbox.json b/interface/resources/controllers/xbox.json index bf96320707..8c341dff83 100644 --- a/interface/resources/controllers/xbox.json +++ b/interface/resources/controllers/xbox.json @@ -1,29 +1,29 @@ { "name": "XBox to Standard", "channels": [ - { "from": "XBox.LY", "to": "Standard.LY" }, - { "from": "XBox.LX", "to": "Standard.LX" }, - { "from": "XBox.LT", "to": "Standard.LT" }, - { "from": "XBox.LB", "to": "Standard.LB" }, - { "from": "XBox.LS", "to": "Standard.LS" }, + { "from": "GamePad.LY", "to": "Standard.LY" }, + { "from": "GamePad.LX", "to": "Standard.LX" }, + { "from": "GamePad.LT", "to": "Standard.LT" }, + { "from": "GamePad.LB", "to": "Standard.LB" }, + { "from": "GamePad.LS", "to": "Standard.LS" }, - { "from": "XBox.RY", "to": "Standard.RY" }, - { "from": "XBox.RX", "to": "Standard.RX" }, - { "from": "XBox.RT", "to": "Standard.RT" }, - { "from": "XBox.RB", "to": "Standard.RB" }, - { "from": "XBox.RS", "to": "Standard.RS" }, + { "from": "GamePad.RY", "to": "Standard.RY" }, + { "from": "GamePad.RX", "to": "Standard.RX" }, + { "from": "GamePad.RT", "to": "Standard.RT" }, + { "from": "GamePad.RB", "to": "Standard.RB" }, + { "from": "GamePad.RS", "to": "Standard.RS" }, - { "from": "XBox.Back", "to": "Standard.Back" }, - { "from": "XBox.Start", "to": "Standard.Start" }, + { "from": "GamePad.Back", "to": "Standard.Back" }, + { "from": "GamePad.Start", "to": "Standard.Start" }, - { "from": "XBox.DU", "to": "Standard.DU" }, - { "from": "XBox.DD", "to": "Standard.DD" }, - { "from": "XBox.DL", "to": "Standard.DL" }, - { "from": "XBox.DR", "to": "Standard.DR" }, + { "from": "GamePad.DU", "to": "Standard.DU" }, + { "from": "GamePad.DD", "to": "Standard.DD" }, + { "from": "GamePad.DL", "to": "Standard.DL" }, + { "from": "GamePad.DR", "to": "Standard.DR" }, - { "from": "XBox.A", "to": "Standard.A" }, - { "from": "XBox.B", "to": "Standard.B" }, - { "from": "XBox.X", "to": "Standard.X" }, - { "from": "XBox.Y", "to": "Standard.Y" } + { "from": "GamePad.A", "to": "Standard.A" }, + { "from": "GamePad.B", "to": "Standard.B" }, + { "from": "GamePad.X", "to": "Standard.X" }, + { "from": "GamePad.Y", "to": "Standard.Y" } ] } diff --git a/interface/resources/qml/TestControllers.qml b/interface/resources/qml/TestControllers.qml index 79be877aa3..e409b7a4a4 100644 --- a/interface/resources/qml/TestControllers.qml +++ b/interface/resources/qml/TestControllers.qml @@ -25,7 +25,7 @@ HifiControls.VrDialog { Component.onCompleted: { enabled = true - var xboxRegex = /^X360Controller/; + var xboxRegex = /^GamePad/; var hydraRegex = /^Hydra/; for (var prop in Controller.Hardware) { if(xboxRegex.test(prop)) { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 77140fc0d3..c3eb3dfe7c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -631,7 +631,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : connect(userInputMapper.data(), &UserInputMapper::actionEvent, [this](int action, float state) { if (state) { switch (action) { - case UserInputMapper::Action::TOGGLE_MUTE: + case controller::Action::TOGGLE_MUTE: DependencyManager::get()->toggleMute(); break; } @@ -639,8 +639,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : }); // Setup the keyboardMouseDevice and the user input mapper with the default bindings - _keyboardMouseDevice->registerToUserInputMapper(*userInputMapper); - _keyboardMouseDevice->assignDefaultInputMapping(*userInputMapper); + userInputMapper->registerDevice(_keyboardMouseDevice); // check first run... if (_firstRun.get()) { @@ -2182,7 +2181,7 @@ float Application::getAvatarSimrate() { } void Application::setLowVelocityFilter(bool lowVelocityFilter) { - InputDevice::setLowVelocityFilter(lowVelocityFilter); + controller::InputDevice::setLowVelocityFilter(lowVelocityFilter); } ivec2 Application::getMouse() const { @@ -2710,19 +2709,28 @@ void Application::update(float deltaTime) { auto myAvatar = getMyAvatar(); auto userInputMapper = DependencyManager::get(); userInputMapper->setSensorToWorldMat(myAvatar->getSensorToWorldMatrix()); - // Dispatch input events - _controllerScriptingInterface->update(); + userInputMapper->update(deltaTime); + + bool jointsCaptured = false; + for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) { + if (inputPlugin->isActive()) { + inputPlugin->pluginUpdate(deltaTime, jointsCaptured); + if (inputPlugin->isJointController()) { + jointsCaptured = true; + } + } + } // Transfer the user inputs to the driveKeys myAvatar->clearDriveKeys(); if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) { if (!_controllerScriptingInterface->areActionsCaptured()) { - myAvatar->setDriveKeys(FWD, userInputMapper->getActionState(UserInputMapper::LONGITUDINAL_FORWARD)); - myAvatar->setDriveKeys(BACK, userInputMapper->getActionState(UserInputMapper::LONGITUDINAL_BACKWARD)); - myAvatar->setDriveKeys(UP, userInputMapper->getActionState(UserInputMapper::VERTICAL_UP)); - myAvatar->setDriveKeys(DOWN, userInputMapper->getActionState(UserInputMapper::VERTICAL_DOWN)); - myAvatar->setDriveKeys(LEFT, userInputMapper->getActionState(UserInputMapper::LATERAL_LEFT)); - myAvatar->setDriveKeys(RIGHT, userInputMapper->getActionState(UserInputMapper::LATERAL_RIGHT)); + myAvatar->setDriveKeys(FWD, userInputMapper->getActionState(controller::LONGITUDINAL_FORWARD)); + myAvatar->setDriveKeys(BACK, userInputMapper->getActionState(controller::LONGITUDINAL_BACKWARD)); + myAvatar->setDriveKeys(UP, userInputMapper->getActionState(controller::VERTICAL_UP)); + myAvatar->setDriveKeys(DOWN, userInputMapper->getActionState(controller::VERTICAL_DOWN)); + myAvatar->setDriveKeys(LEFT, userInputMapper->getActionState(controller::LATERAL_LEFT)); + myAvatar->setDriveKeys(RIGHT, userInputMapper->getActionState(controller::LATERAL_RIGHT)); if (deltaTime > FLT_EPSILON) { // For rotations what we really want are meausures of "angles per second" (in order to prevent // fps-dependent spin rates) so we need to scale the units of the controller contribution. @@ -2730,25 +2738,25 @@ void Application::update(float deltaTime) { // controllers to provide a delta_per_second value rather than a raw delta.) const float EXPECTED_FRAME_RATE = 60.0f; float timeFactor = EXPECTED_FRAME_RATE * deltaTime; - myAvatar->setDriveKeys(ROT_UP, userInputMapper->getActionState(UserInputMapper::PITCH_UP) / timeFactor); - myAvatar->setDriveKeys(ROT_DOWN, userInputMapper->getActionState(UserInputMapper::PITCH_DOWN) / timeFactor); - myAvatar->setDriveKeys(ROT_LEFT, userInputMapper->getActionState(UserInputMapper::YAW_LEFT) / timeFactor); - myAvatar->setDriveKeys(ROT_RIGHT, userInputMapper->getActionState(UserInputMapper::YAW_RIGHT) / timeFactor); + myAvatar->setDriveKeys(ROT_UP, userInputMapper->getActionState(controller::PITCH_UP) / timeFactor); + myAvatar->setDriveKeys(ROT_DOWN, userInputMapper->getActionState(controller::PITCH_DOWN) / timeFactor); + myAvatar->setDriveKeys(ROT_LEFT, userInputMapper->getActionState(controller::YAW_LEFT) / timeFactor); + myAvatar->setDriveKeys(ROT_RIGHT, userInputMapper->getActionState(controller::YAW_RIGHT) / timeFactor); } } - myAvatar->setDriveKeys(BOOM_IN, userInputMapper->getActionState(UserInputMapper::BOOM_IN)); - myAvatar->setDriveKeys(BOOM_OUT, userInputMapper->getActionState(UserInputMapper::BOOM_OUT)); + myAvatar->setDriveKeys(BOOM_IN, userInputMapper->getActionState(controller::BOOM_IN)); + myAvatar->setDriveKeys(BOOM_OUT, userInputMapper->getActionState(controller::BOOM_OUT)); } - UserInputMapper::PoseValue leftHand = userInputMapper->getPoseState(UserInputMapper::LEFT_HAND); - UserInputMapper::PoseValue rightHand = userInputMapper->getPoseState(UserInputMapper::RIGHT_HAND); + controller::Pose leftHand = userInputMapper->getPoseState(controller::LEFT_HAND); + controller::Pose rightHand = userInputMapper->getPoseState(controller::RIGHT_HAND); Hand* hand = DependencyManager::get()->getMyAvatar()->getHand(); - setPalmData(hand, leftHand, deltaTime, LEFT_HAND_INDEX, userInputMapper->getActionState(UserInputMapper::LEFT_HAND_CLICK)); - setPalmData(hand, rightHand, deltaTime, RIGHT_HAND_INDEX, userInputMapper->getActionState(UserInputMapper::RIGHT_HAND_CLICK)); + setPalmData(hand, leftHand, deltaTime, LEFT_HAND_INDEX, userInputMapper->getActionState(controller::LEFT_HAND_CLICK)); + setPalmData(hand, rightHand, deltaTime, RIGHT_HAND_INDEX, userInputMapper->getActionState(controller::RIGHT_HAND_CLICK)); if (Menu::getInstance()->isOptionChecked(MenuOption::EnableHandMouseInput)) { - emulateMouse(hand, userInputMapper->getActionState(UserInputMapper::LEFT_HAND_CLICK), - userInputMapper->getActionState(UserInputMapper::SHIFT), LEFT_HAND_INDEX); - emulateMouse(hand, userInputMapper->getActionState(UserInputMapper::RIGHT_HAND_CLICK), - userInputMapper->getActionState(UserInputMapper::SHIFT), RIGHT_HAND_INDEX); + emulateMouse(hand, userInputMapper->getActionState(controller::LEFT_HAND_CLICK), + userInputMapper->getActionState(controller::SHIFT), LEFT_HAND_INDEX); + emulateMouse(hand, userInputMapper->getActionState(controller::RIGHT_HAND_CLICK), + userInputMapper->getActionState(controller::SHIFT), RIGHT_HAND_INDEX); } updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... @@ -4806,7 +4814,7 @@ mat4 Application::getHMDSensorPose() const { return mat4(); } -void Application::setPalmData(Hand* hand, UserInputMapper::PoseValue pose, float deltaTime, int index, float triggerValue) { +void Application::setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, int index, float triggerValue) { PalmData* palm; bool foundHand = false; for (size_t j = 0; j < hand->getNumPalms(); j++) { @@ -4855,7 +4863,7 @@ void Application::setPalmData(Hand* hand, UserInputMapper::PoseValue pose, float palm->setRawAngularVelocity(glm::vec3(0.0f)); } - if (InputDevice::getLowVelocityFilter()) { + if (controller::InputDevice::getLowVelocityFilter()) { // Use a velocity sensitive filter to damp small motions and preserve large ones with // no latency. float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f); @@ -4911,7 +4919,7 @@ void Application::emulateMouse(Hand* hand, float click, float shift, int index) float yAngle = 0.5f - ((atan2f(direction.z, direction.y) + (float)M_PI_2)); auto canvasSize = getCanvasSize(); // Get the pixel range over which the xAngle and yAngle are scaled - float cursorRange = canvasSize.x * InputDevice::getCursorPixelRangeMult(); + float cursorRange = canvasSize.x * controller::InputDevice::getCursorPixelRangeMult(); pos.setX(canvasSize.x / 2.0f + cursorRange * xAngle); pos.setY(canvasSize.y / 2.0f + cursorRange * yAngle); diff --git a/interface/src/Application.h b/interface/src/Application.h index 829265c9fb..75cc418e94 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -352,7 +352,7 @@ private: void update(float deltaTime); - void setPalmData(Hand* hand, UserInputMapper::PoseValue pose, float deltaTime, int index, float triggerValue); + void setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, int index, float triggerValue); void emulateMouse(Hand* hand, float click, float shift, int index); // Various helper functions called during update() diff --git a/interface/src/devices/3DConnexionClient.cpp b/interface/src/devices/3DConnexionClient.cpp index 722fedcc3a..05795e87e9 100755 --- a/interface/src/devices/3DConnexionClient.cpp +++ b/interface/src/devices/3DConnexionClient.cpp @@ -10,8 +10,11 @@ // #include "3DConnexionClient.h" + +#include +#include + #include "Menu.h" -#include "UserActivityLogger.h" const float MAX_AXIS = 75.0f; // max forward = 2x speed @@ -25,8 +28,9 @@ ConnexionData& ConnexionData::getInstance() { return sharedInstance; } -ConnexionData::ConnexionData() { -} + +ConnexionData::ConnexionData() : InputDevice("ConnexionClient") {} + void ConnexionData::handleAxisEvent() { _axisStateMap[makeInput(ROTATION_AXIS_Y_POS).getChannel()] = (cc_rotation.y > 0.0f) ? cc_rotation.y / MAX_AXIS : 0.0f; @@ -48,76 +52,71 @@ void ConnexionData::setButton(int lastButtonState) { _buttonPressedMap.insert(lastButtonState); } -void ConnexionData::registerToUserInputMapper(UserInputMapper& mapper) { - // Grab the current free device ID - _deviceID = mapper.getFreeDeviceID(); +void ConnexionData::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) { + proxy->_name = _name = "ConnexionClient"; + proxy->getButton = [this](const controller::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); }; + proxy->getAxis = [this](const controller::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); }; + proxy->getAvailabeInputs = [this]() -> QVector { + QVector availableInputs; - auto proxy = UserInputMapper::DeviceProxy::Pointer(new UserInputMapper::DeviceProxy("ConnexionClient")); - 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; - - availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_1), "Left button")); - availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_2), "Right button")); - availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_3), "Both buttons")); - - availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_Y_NEG), "Move backward")); - availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_Y_POS), "Move forward")); - availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_X_POS), "Move right")); - availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_X_NEG), "Move Left")); - availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_Z_POS), "Move up")); - availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_Z_NEG), "Move down")); - availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_Y_NEG), "Rotate backward")); - availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_Y_POS), "Rotate forward")); - availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_X_POS), "Rotate right")); - availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_X_NEG), "Rotate left")); - availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_Z_POS), "Rotate up")); - availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_Z_NEG), "Rotate down")); + availableInputs.append(controller::Input::NamedPair(makeInput(BUTTON_1), "Left button")); + availableInputs.append(controller::Input::NamedPair(makeInput(BUTTON_2), "Right button")); + availableInputs.append(controller::Input::NamedPair(makeInput(BUTTON_3), "Both buttons")); + availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_Y_NEG), "Move backward")); + availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_Y_POS), "Move forward")); + availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_X_POS), "Move right")); + availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_X_NEG), "Move Left")); + availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_Z_POS), "Move up")); + availableInputs.append(controller::Input::NamedPair(makeInput(POSITION_AXIS_Z_NEG), "Move down")); + availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_Y_NEG), "Rotate backward")); + availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_Y_POS), "Rotate forward")); + availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_X_POS), "Rotate right")); + availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_X_NEG), "Rotate left")); + availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_Z_POS), "Rotate up")); + availableInputs.append(controller::Input::NamedPair(makeInput(ROTATION_AXIS_Z_NEG), "Rotate down")); return availableInputs; }; - proxy->resetDeviceBindings = [this, &mapper]() -> bool { - mapper.removeAllInputChannelsForDevice(_deviceID); - this->assignDefaultInputMapping(mapper); - return true; - }; - mapper.registerDevice(_deviceID, proxy); } -void ConnexionData::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) - // postion: Movement, strafing - mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(POSITION_AXIS_Y_NEG), JOYSTICK_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(POSITION_AXIS_Y_POS), JOYSTICK_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(POSITION_AXIS_X_POS), JOYSTICK_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(POSITION_AXIS_X_NEG), JOYSTICK_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(POSITION_AXIS_Z_NEG), JOYSTICK_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(POSITION_AXIS_Z_POS), JOYSTICK_MOVE_SPEED); - - // Rotation: Camera orientation with button 1 - mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(ROTATION_AXIS_Z_POS), JOYSTICK_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(ROTATION_AXIS_Z_NEG), JOYSTICK_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(ROTATION_AXIS_Y_NEG), JOYSTICK_PITCH_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(ROTATION_AXIS_Y_POS), JOYSTICK_PITCH_SPEED); - - // Button controls - // Zoom - mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(BUTTON_1), BOOM_SPEED); - mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(BUTTON_2), BOOM_SPEED); - - // Zoom - // mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(ROTATION_AXIS_Z_NEG), BOOM_SPEED); - // mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(ROTATION_AXIS_Z_POS), BOOM_SPEED); - +QString ConnexionData::getDefaultMappingConfig() { + static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/vive.json"; + return MAPPING_JSON; } +//void ConnexionData::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) +// // postion: Movement, strafing +// mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(POSITION_AXIS_Y_NEG), JOYSTICK_MOVE_SPEED); +// mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(POSITION_AXIS_Y_POS), JOYSTICK_MOVE_SPEED); +// mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(POSITION_AXIS_X_POS), JOYSTICK_MOVE_SPEED); +// mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(POSITION_AXIS_X_NEG), JOYSTICK_MOVE_SPEED); +// mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(POSITION_AXIS_Z_NEG), JOYSTICK_MOVE_SPEED); +// mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(POSITION_AXIS_Z_POS), JOYSTICK_MOVE_SPEED); +// +// // Rotation: Camera orientation with button 1 +// mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(ROTATION_AXIS_Z_POS), JOYSTICK_YAW_SPEED); +// mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(ROTATION_AXIS_Z_NEG), JOYSTICK_YAW_SPEED); +// mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(ROTATION_AXIS_Y_NEG), JOYSTICK_PITCH_SPEED); +// mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(ROTATION_AXIS_Y_POS), JOYSTICK_PITCH_SPEED); +// +// // Button controls +// // Zoom +// mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(BUTTON_1), BOOM_SPEED); +// mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(BUTTON_2), BOOM_SPEED); +// +// // Zoom +// // mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(ROTATION_AXIS_Z_NEG), BOOM_SPEED); +// // mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(ROTATION_AXIS_Z_POS), BOOM_SPEED); +// +//} + float ConnexionData::getButton(int channel) const { if (!_buttonPressedMap.empty()) { if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) { @@ -138,15 +137,15 @@ float ConnexionData::getAxis(int channel) const { } } -UserInputMapper::Input ConnexionData::makeInput(ConnexionData::ButtonChannel button) { - return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON); +controller::Input ConnexionData::makeInput(ConnexionData::ButtonChannel button) { + return controller::Input(_deviceID, button, controller::ChannelType::BUTTON); } -UserInputMapper::Input ConnexionData::makeInput(ConnexionData::PositionChannel axis) { - return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS); +controller::Input ConnexionData::makeInput(ConnexionData::PositionChannel axis) { + return controller::Input(_deviceID, axis, controller::ChannelType::AXIS); } -void ConnexionData::update() { +void ConnexionData::update(float deltaTime, bool jointsCaptured) { // the update is done in the ConnexionClient class. // for windows in the nativeEventFilter the inputmapper is connected or registed or removed when an 3Dconnnexion device is attached or detached // for osx the api will call DeviceAddedHandler or DeviceRemoveHandler when a 3Dconnexion device is attached or detached @@ -187,7 +186,6 @@ void ConnexionClient::destroy() { QAbstractEventDispatcher::instance()->removeNativeEventFilter(this); ConnexionData& connexiondata = ConnexionData::getInstance(); int deviceid = connexiondata.getDeviceID(); - connexiondata.setDeviceID(0); auto userInputMapper = DependencyManager::get(); userInputMapper->removeDevice(deviceid); } @@ -295,13 +293,10 @@ bool ConnexionClient::RawInputEventFilter(void* msg, long* result) { ConnexionData& connexiondata = ConnexionData::getInstance(); auto userInputMapper = DependencyManager::get(); if (Is3dmouseAttached() && connexiondata.getDeviceID() == 0) { - connexiondata.registerToUserInputMapper(*userInputMapper); - connexiondata.assignDefaultInputMapping(*userInputMapper); + userInputMapper->registerDevice(&connexiondata); UserActivityLogger::getInstance().connectedDevice("controller", "3Dconnexion"); } else if (!Is3dmouseAttached() && connexiondata.getDeviceID() != 0) { - int deviceid = connexiondata.getDeviceID(); - connexiondata.setDeviceID(0); - userInputMapper->removeDevice(deviceid); + userInputMapper->removeDevice(connexiondata.getDeviceID()); } if (!Is3dmouseAttached()) { @@ -894,8 +889,7 @@ void ConnexionClient::init() { if (Is3dmouseAttached() && connexiondata.getDeviceID() == 0) { auto userInputMapper = DependencyManager::get(); - connexiondata.registerToUserInputMapper(*userInputMapper); - connexiondata.assignDefaultInputMapping(*userInputMapper); + userInputMapper->registerDevice(&connexiondata); UserActivityLogger::getInstance().connectedDevice("controller", "3Dconnexion"); } //let one axis be dominant @@ -926,8 +920,7 @@ void DeviceAddedHandler(unsigned int connection) { if (connexiondata.getDeviceID() == 0) { qCWarning(interfaceapp) << "3Dconnexion device added "; auto userInputMapper = DependencyManager::get(); - connexiondata.registerToUserInputMapper(*userInputMapper); - connexiondata.assignDefaultInputMapping(*userInputMapper); + userInputMapper->registerDevice(&connexiondata); UserActivityLogger::getInstance().connectedDevice("controller", "3Dconnexion"); } } diff --git a/interface/src/devices/3DConnexionClient.h b/interface/src/devices/3DConnexionClient.h index bddb86a857..8f66a602a4 100755 --- a/interface/src/devices/3DConnexionClient.h +++ b/interface/src/devices/3DConnexionClient.h @@ -175,13 +175,12 @@ public slots: // connnects to the userinputmapper -class ConnexionData : public QObject { +class ConnexionData : public QObject, public controller::InputDevice { Q_OBJECT public: static ConnexionData& getInstance(); ConnexionData(); - enum PositionChannel { POSITION_AXIS_X_POS = 1, POSITION_AXIS_X_NEG = 2, @@ -209,19 +208,12 @@ public: float getButton(int channel) const; float getAxis(int channel) const; - UserInputMapper::Input makeInput(ConnexionData::PositionChannel axis); - UserInputMapper::Input makeInput(ConnexionData::ButtonChannel button); - - void registerToUserInputMapper(UserInputMapper& mapper); - void assignDefaultInputMapping(UserInputMapper& mapper); - - void update(); - void focusOutEvent(); - - int getDeviceID() { return _deviceID; } - void setDeviceID(int deviceID) { _deviceID = deviceID; } - - QString _name; + controller::Input makeInput(ConnexionData::PositionChannel axis); + controller::Input makeInput(ConnexionData::ButtonChannel button); + virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override; + virtual QString getDefaultMappingConfig() override; + virtual void update(float deltaTime, bool jointsCaptured) override; + virtual void focusOutEvent() override; glm::vec3 cc_position; glm::vec3 cc_rotation; @@ -229,12 +221,6 @@ public: void setButton(int lastButtonState); void handleAxisEvent(); - -protected: - int _deviceID = 0; - - ButtonPressedMap _buttonPressedMap; - AxisStateMap _axisStateMap; }; #endif // defined(hifi_3DConnexionClient_h) diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index f05d1a41a6..31f823de8b 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -167,31 +167,6 @@ void ControllerScriptingInterface::releaseInputController(controller::InputContr _inputControllers.erase(input->getKey()); } -void ControllerScriptingInterface::update() { - static float last = secTimestampNow(); - float now = secTimestampNow(); - float delta = now - last; - last = now; - - DependencyManager::get()->update(delta); - - bool jointsCaptured = false; - for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) { - if (inputPlugin->isActive()) { - inputPlugin->pluginUpdate(delta, jointsCaptured); - if (inputPlugin->isJointController()) { - jointsCaptured = true; - } - } - } - - for (auto entry : _inputControllers) { - entry.second->update(); - } - - controller::ScriptingInterface::update(); -} - 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 24065e6799..8be530c6ce 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -85,8 +85,6 @@ public: bool isKeyCaptured(const KeyEvent& event) const; bool isJoystickCaptured(int joystickIndex) const; - virtual void update() override; - public slots: virtual void captureKeyEvents(const KeyEvent& event); diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index 4fc2f3ddb4..ca5c60dc04 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -521,7 +521,7 @@ void ApplicationCompositor::renderControllerPointers(gpu::Batch& batch) { float yAngle = 0.5f - ((atan2f(direction.z, direction.y) + (float)PI_OVER_TWO)); // Get the pixel range over which the xAngle and yAngle are scaled - float cursorRange = canvasSize.x * InputDevice::getCursorPixelRangeMult(); + float cursorRange = canvasSize.x * controller::InputDevice::getCursorPixelRangeMult(); mouseX = (canvasSize.x / 2.0f + cursorRange * xAngle); mouseY = (canvasSize.y / 2.0f + cursorRange * yAngle); diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 4ba248c76c..d4bab86126 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -198,7 +198,7 @@ void PreferencesDialog::loadPreferences() { ui.oculusUIAngularSizeSpin->setValue(qApp->getApplicationCompositor().getHmdUIAngularSize()); #endif - ui.sixenseReticleMoveSpeedSpin->setValue(InputDevice::getReticleMoveSpeed()); + ui.sixenseReticleMoveSpeedSpin->setValue(controller::InputDevice::getReticleMoveSpeed()); // LOD items auto lodManager = DependencyManager::get(); @@ -273,7 +273,7 @@ void PreferencesDialog::savePreferences() { qApp->getApplicationCompositor().setHmdUIAngularSize(ui.oculusUIAngularSizeSpin->value()); - InputDevice::setReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value()); + controller::InputDevice::setReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value()); auto audio = DependencyManager::get(); MixedProcessedAudioStream& stream = audio->getReceivedAudioStream(); diff --git a/libraries/controllers/src/controllers/Actions.cpp b/libraries/controllers/src/controllers/Actions.cpp new file mode 100644 index 0000000000..2c5cf84931 --- /dev/null +++ b/libraries/controllers/src/controllers/Actions.cpp @@ -0,0 +1,71 @@ +// +// Created by Bradley Austin Davis on 2015/10/19 +// 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 "Actions.h" + +#include "UserInputMapper.h" + +namespace controller { + + // Device functions + void ActionsDevice::buildDeviceProxy(DeviceProxy::Pointer proxy) { + proxy->_name = _name; + proxy->getButton = [this](const Input& input, int timestamp) -> bool { return false; }; + proxy->getAxis = [this](const Input& input, int timestamp) -> float { return 0; }; + proxy->getAvailabeInputs = [this]() -> QVector { + QVector availableInputs{ + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, LONGITUDINAL_BACKWARD, ChannelType::AXIS), "LONGITUDINAL_BACKWARD"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, LONGITUDINAL_FORWARD, ChannelType::AXIS), "LONGITUDINAL_FORWARD"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, LATERAL_LEFT, ChannelType::AXIS), "LATERAL_LEFT"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, LATERAL_RIGHT, ChannelType::AXIS), "LATERAL_RIGHT"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, VERTICAL_DOWN, ChannelType::AXIS), "VERTICAL_DOWN"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, VERTICAL_UP, ChannelType::AXIS), "VERTICAL_UP"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, YAW_LEFT, ChannelType::AXIS), "YAW_LEFT"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, YAW_RIGHT, ChannelType::AXIS), "YAW_RIGHT"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, PITCH_DOWN, ChannelType::AXIS), "PITCH_DOWN"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, PITCH_UP, ChannelType::AXIS), "PITCH_UP"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, BOOM_IN, ChannelType::AXIS), "BOOM_IN"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, BOOM_OUT, ChannelType::AXIS), "BOOM_OUT"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, LEFT_HAND, ChannelType::POSE), "LEFT_HAND"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, RIGHT_HAND, ChannelType::POSE), "RIGHT_HAND"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, LEFT_HAND_CLICK, ChannelType::BUTTON), "LEFT_HAND_CLICK"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, RIGHT_HAND_CLICK, ChannelType::BUTTON), "RIGHT_HAND_CLICK"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, SHIFT, ChannelType::BUTTON), "SHIFT"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, ACTION1, ChannelType::BUTTON), "ACTION1"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, ACTION2, ChannelType::BUTTON), "ACTION2"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, CONTEXT_MENU, ChannelType::BUTTON), "CONTEXT_MENU"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, TOGGLE_MUTE, ChannelType::AXIS), "TOGGLE_MUTE"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, TRANSLATE_X, ChannelType::AXIS), "TranslateX"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, TRANSLATE_Y, ChannelType::AXIS), "TranslateY"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, TRANSLATE_Z, ChannelType::AXIS), "TranslateZ"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, ROLL, ChannelType::AXIS), "Roll"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, PITCH, ChannelType::AXIS), "Pitch"), + Input::NamedPair(Input(UserInputMapper::ACTIONS_DEVICE, YAW, ChannelType::AXIS), "Yaw") + }; + return availableInputs; + }; + + } + + QString ActionsDevice::getDefaultMappingConfig() { + return QString(); + } + + void ActionsDevice::update(float deltaTime, bool jointsCaptured) { + } + + void ActionsDevice::focusOutEvent() { + } + + ActionsDevice::ActionsDevice() : InputDevice("Actions") { + _deviceID = UserInputMapper::ACTIONS_DEVICE; + } + + ActionsDevice::~ActionsDevice() {} + +} diff --git a/libraries/controllers/src/controllers/Actions.h b/libraries/controllers/src/controllers/Actions.h new file mode 100644 index 0000000000..f4e9f665e2 --- /dev/null +++ b/libraries/controllers/src/controllers/Actions.h @@ -0,0 +1,100 @@ +// +// Created by Bradley Austin Davis on 2015/10/19 +// 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_controller_Actions_h +#define hifi_controller_Actions_h + +#include +#include + +#include "InputDevice.h" + +namespace controller { + +// Actions are the output channels of the Mapper, that's what the InputChannel map to +// For now the Actions are hardcoded, this is bad, but we will fix that in the near future +enum Action { + TRANSLATE_X = 0, + TRANSLATE_Y, + TRANSLATE_Z, + ROTATE_X, PITCH = ROTATE_X, + ROTATE_Y, YAW = ROTATE_Y, + ROTATE_Z, ROLL = ROTATE_Z, + + TRANSLATE_CAMERA_Z, + NUM_COMBINED_AXES, + + LEFT_HAND = NUM_COMBINED_AXES, + RIGHT_HAND, + + LEFT_HAND_CLICK, + RIGHT_HAND_CLICK, + + ACTION1, + ACTION2, + + CONTEXT_MENU, + TOGGLE_MUTE, + + SHIFT, + + // Biseced aliases for TRANSLATE_Z + LONGITUDINAL_BACKWARD, + LONGITUDINAL_FORWARD, + + // Biseced aliases for TRANSLATE_X + LATERAL_LEFT, + LATERAL_RIGHT, + + // Biseced aliases for TRANSLATE_Y + VERTICAL_DOWN, + VERTICAL_UP, + + // Biseced aliases for ROTATE_Y + YAW_LEFT, + YAW_RIGHT, + + // Biseced aliases for ROTATE_X + PITCH_DOWN, + PITCH_UP, + + // Biseced aliases for TRANSLATE_CAMERA_Z + BOOM_IN, + BOOM_OUT, + + NUM_ACTIONS, +}; + + +class ActionsDevice : public QObject, public InputDevice { + Q_OBJECT + Q_PROPERTY(QString name READ getName) + +public: + const QString& getName() const { return _name; } + + // Device functions + virtual void buildDeviceProxy(DeviceProxy::Pointer proxy) override; + virtual QString getDefaultMappingConfig() override; + virtual void update(float deltaTime, bool jointsCaptured) override; + virtual void focusOutEvent() override; + + ActionsDevice(); + virtual ~ActionsDevice(); +}; + +} + + + + +#include "StandardControls.h" + + +#endif // hifi_StandardController_h diff --git a/libraries/controllers/src/controllers/DeviceProxy.cpp b/libraries/controllers/src/controllers/DeviceProxy.cpp index 9ac701e80d..6cbfc1048d 100644 --- a/libraries/controllers/src/controllers/DeviceProxy.cpp +++ b/libraries/controllers/src/controllers/DeviceProxy.cpp @@ -20,7 +20,7 @@ namespace controller { return getAxis(input, timestamp); case ChannelType::POSE: - return getPose(input, timestamp)._valid ? 1.0f : 0.0f; + 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 index 78d13fe5c4..064abdbc7f 100644 --- a/libraries/controllers/src/controllers/DeviceProxy.h +++ b/libraries/controllers/src/controllers/DeviceProxy.h @@ -35,23 +35,15 @@ namespace controller { 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; + using Pointer = std::shared_ptr; + 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 const { return Input::NamedVector(); }; + float getValue(const Input& input, int timestamp = 0) const; + QString _name; }; - } #endif diff --git a/libraries/controllers/src/controllers/Endpoint.h b/libraries/controllers/src/controllers/Endpoint.h index 923412ac6c..3e4ce94490 100644 --- a/libraries/controllers/src/controllers/Endpoint.h +++ b/libraries/controllers/src/controllers/Endpoint.h @@ -14,7 +14,9 @@ #include #include -#include "UserInputMapper.h" +#include + +#include "Input.h" class QScriptValue; @@ -24,7 +26,7 @@ namespace controller { * i.e. Hydra.Button0, Standard.X, Action.Yaw */ class Endpoint : public QObject { - Q_OBJECT; + Q_OBJECT; public: using Pointer = std::shared_ptr; using List = std::list; @@ -32,18 +34,18 @@ namespace controller { using ReadLambda = std::function; using WriteLambda = std::function; - Endpoint(const UserInputMapper::Input& input) : _input(input) {} + Endpoint(const Input& input) : _input(input) {} virtual float value() = 0; virtual void apply(float newValue, float oldValue, const Pointer& source) = 0; - const UserInputMapper::Input& getInput() { return _input; } + const Input& getInput() { return _input; } protected: - UserInputMapper::Input _input; + Input _input; }; class LambdaEndpoint : public Endpoint { public: LambdaEndpoint(ReadLambda readLambda, WriteLambda writeLambda = [](float) {}) - : Endpoint(UserInputMapper::Input::INVALID_INPUT), _readLambda(readLambda), _writeLambda(writeLambda) { } + : Endpoint(Input::INVALID_INPUT), _readLambda(readLambda), _writeLambda(writeLambda) { } virtual float value() override { return _readLambda(); } virtual void apply(float newValue, float oldValue, const Pointer& source) override { _writeLambda(newValue); } diff --git a/libraries/controllers/src/controllers/Input.h b/libraries/controllers/src/controllers/Input.h index 8cc682df70..98377b7434 100644 --- a/libraries/controllers/src/controllers/Input.h +++ b/libraries/controllers/src/controllers/Input.h @@ -27,26 +27,21 @@ enum class ChannelType { // to the Action channels struct Input { union { + uint32_t id{ 0 }; // by default Input is 0 meaning invalid 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 + 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); } + bool isValid() const { return (id != INVALID_INPUT.id); } - 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; } + uint16_t getDevice() const { return device; } + uint16_t getChannel() const { return channel; } + uint32_t getID() const { return id; } + ChannelType getType() const { return (ChannelType) type; } bool isButton() const { return getType() == ChannelType::BUTTON; } bool isAxis() const { return getType() == ChannelType::AXIS; } @@ -54,13 +49,13 @@ struct Input { // 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; } + explicit Input() {} + 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 INVALID_INPUT.id != id && INVALID_INPUT.id != right.id && id == right.id; } + bool operator < (const Input& src) const { return id < src.id; } static const Input INVALID_INPUT; static const uint16_t INVALID_DEVICE; diff --git a/libraries/controllers/src/controllers/InputDevice.cpp b/libraries/controllers/src/controllers/InputDevice.cpp index 1f86741b88..78e920d4b5 100644 --- a/libraries/controllers/src/controllers/InputDevice.cpp +++ b/libraries/controllers/src/controllers/InputDevice.cpp @@ -10,75 +10,78 @@ // #include "InputDevice.h" -bool InputDevice::_lowVelocityFilter = false; +#include "Input.h" -const float DEFAULT_HAND_RETICLE_MOVE_SPEED = 37.5f; -float InputDevice::_reticleMoveSpeed = DEFAULT_HAND_RETICLE_MOVE_SPEED; +namespace controller { -//Constants for getCursorPixelRangeMultiplier() -const float MIN_PIXEL_RANGE_MULT = 0.4f; -const float MAX_PIXEL_RANGE_MULT = 2.0f; -const float RANGE_MULT = (MAX_PIXEL_RANGE_MULT - MIN_PIXEL_RANGE_MULT) * 0.01f; + bool InputDevice::_lowVelocityFilter = false; -//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; -} + const float DEFAULT_HAND_RETICLE_MOVE_SPEED = 37.5f; + float InputDevice::_reticleMoveSpeed = DEFAULT_HAND_RETICLE_MOVE_SPEED; -float InputDevice::getButton(int channel) const { - if (!_buttonPressedMap.empty()) { - if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) { - return 1.0f; + //Constants for getCursorPixelRangeMultiplier() + const float MIN_PIXEL_RANGE_MULT = 0.4f; + const float MAX_PIXEL_RANGE_MULT = 2.0f; + 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; + } + + float InputDevice::getButton(int channel) const { + if (!_buttonPressedMap.empty()) { + if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) { + return 1.0f; + } else { + return 0.0f; + } } - else { + return 0.0f; + } + + float InputDevice::getAxis(int channel) const { + auto axis = _axisStateMap.find(channel); + if (axis != _axisStateMap.end()) { + return (*axis).second; + } else { return 0.0f; } } - return 0.0f; -} -float InputDevice::getAxis(int channel) const { - auto axis = _axisStateMap.find(channel); - if (axis != _axisStateMap.end()) { - return (*axis).second; + Pose InputDevice::getPose(int channel) const { + auto pose = _poseStateMap.find(channel); + if (pose != _poseStateMap.end()) { + return (*pose).second; + } else { + return Pose(); + } } - else { - return 0.0f; + + Input InputDevice::makeInput(controller::StandardButtonChannel button) { + return Input(_deviceID, button, ChannelType::BUTTON); } -} -UserInputMapper::PoseValue InputDevice::getPose(int channel) const { - auto pose = _poseStateMap.find(channel); - if (pose != _poseStateMap.end()) { - return (*pose).second; + Input InputDevice::makeInput(controller::StandardAxisChannel axis) { + return Input(_deviceID, axis, ChannelType::AXIS); } - else { - return UserInputMapper::PoseValue(); + + Input InputDevice::makeInput(controller::StandardPoseChannel pose) { + return Input(_deviceID, pose, ChannelType::POSE); } -} -UserInputMapper::Input InputDevice::makeInput(controller::StandardButtonChannel button) { - return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON); -} + Input::NamedPair InputDevice::makePair(controller::StandardButtonChannel button, const QString& name) { + return Input::NamedPair(makeInput(button), name); + } -UserInputMapper::Input InputDevice::makeInput(controller::StandardAxisChannel axis) { - return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS); -} + Input::NamedPair InputDevice::makePair(controller::StandardAxisChannel axis, const QString& name) { + return Input::NamedPair(makeInput(axis), name); + } -UserInputMapper::Input InputDevice::makeInput(controller::StandardPoseChannel pose) { - return UserInputMapper::Input(_deviceID, pose, UserInputMapper::ChannelType::POSE); -} + Input::NamedPair InputDevice::makePair(controller::StandardPoseChannel pose, const QString& name) { + return Input::NamedPair(makeInput(pose), name); + } -UserInputMapper::InputPair InputDevice::makePair(controller::StandardButtonChannel button, const QString& name) { - return UserInputMapper::InputPair(makeInput(button), name); -} -UserInputMapper::InputPair InputDevice::makePair(controller::StandardAxisChannel axis, const QString& name) { - return UserInputMapper::InputPair(makeInput(axis), name); } - -UserInputMapper::InputPair InputDevice::makePair(controller::StandardPoseChannel pose, const QString& name) { - return UserInputMapper::InputPair(makeInput(pose), name); -} - diff --git a/libraries/controllers/src/controllers/InputDevice.h b/libraries/controllers/src/controllers/InputDevice.h index 4854df0ada..e01def2368 100644 --- a/libraries/controllers/src/controllers/InputDevice.h +++ b/libraries/controllers/src/controllers/InputDevice.h @@ -10,13 +10,23 @@ // #pragma once -#include "UserInputMapper.h" +#include +#include +#include + +#include + +#include "Pose.h" +#include "Input.h" #include "StandardControls.h" +#include "DeviceProxy.h" // Event types for each controller const unsigned int CONTROLLER_0_EVENT = 1500U; const unsigned int CONTROLLER_1_EVENT = 1501U; +namespace controller { + // NOTE: If something inherits from both InputDevice and InputPlugin, InputPlugin must go first. // e.g. class Example : public InputPlugin, public InputDevice // instead of class Example : public InputDevice, public InputPlugin @@ -24,17 +34,19 @@ class InputDevice { public: InputDevice(const QString& name) : _name(name) {} + using Pointer = std::shared_ptr; + typedef std::unordered_set ButtonPressedMap; typedef std::map AxisStateMap; - typedef std::map PoseStateMap; + typedef std::map PoseStateMap; // Get current state for each channel float getButton(int channel) const; float getAxis(int channel) const; - UserInputMapper::PoseValue getPose(int channel) const; + Pose getPose(int channel) const; - virtual void registerToUserInputMapper(UserInputMapper& mapper) = 0; - virtual void assignDefaultInputMapping(UserInputMapper& mapper) = 0; + virtual void buildDeviceProxy(DeviceProxy::Pointer proxy) = 0; + virtual QString getDefaultMappingConfig() = 0; // Update call MUST be called once per simulation loop // It takes care of updating the action states and deltas @@ -43,6 +55,7 @@ public: virtual void focusOutEvent() = 0; int getDeviceID() { return _deviceID; } + void setDeviceID(int deviceID) { _deviceID = deviceID; } static float getCursorPixelRangeMult(); static float getReticleMoveSpeed() { return _reticleMoveSpeed; } @@ -50,18 +63,18 @@ public: static bool getLowVelocityFilter() { return _lowVelocityFilter; }; - UserInputMapper::Input makeInput(controller::StandardButtonChannel button); - UserInputMapper::Input makeInput(controller::StandardAxisChannel axis); - UserInputMapper::Input makeInput(controller::StandardPoseChannel pose); - UserInputMapper::InputPair makePair(controller::StandardButtonChannel button, const QString& name); - UserInputMapper::InputPair makePair(controller::StandardAxisChannel button, const QString& name); - UserInputMapper::InputPair makePair(controller::StandardPoseChannel button, const QString& name); -public slots: + Input makeInput(StandardButtonChannel button); + Input makeInput(StandardAxisChannel axis); + Input makeInput(StandardPoseChannel pose); + Input::NamedPair makePair(StandardButtonChannel button, const QString& name); + Input::NamedPair makePair(StandardAxisChannel button, const QString& name); + Input::NamedPair makePair(StandardPoseChannel button, const QString& name); + public slots: static void setLowVelocityFilter(bool newLowVelocityFilter) { _lowVelocityFilter = newLowVelocityFilter; }; protected: - - int _deviceID = 0; + friend class UserInputMapper; + uint16_t _deviceID{ Input::INVALID_DEVICE }; QString _name; @@ -73,4 +86,6 @@ protected: private: static float _reticleMoveSpeed; -}; \ No newline at end of file +}; + +} \ No newline at end of file diff --git a/libraries/controllers/src/controllers/Mapping.cpp b/libraries/controllers/src/controllers/Mapping.cpp index 08e8aef9e8..68c43da393 100644 --- a/libraries/controllers/src/controllers/Mapping.cpp +++ b/libraries/controllers/src/controllers/Mapping.cpp @@ -6,11 +6,3 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "Mapping.h" - -namespace controller { - Mapping::Mapping(const QString& name ) : _name(name) { - - } - -} - diff --git a/libraries/controllers/src/controllers/Mapping.h b/libraries/controllers/src/controllers/Mapping.h index e9c8e7a323..ff988bf1b1 100644 --- a/libraries/controllers/src/controllers/Mapping.h +++ b/libraries/controllers/src/controllers/Mapping.h @@ -27,13 +27,11 @@ namespace controller { using Map = std::map; using Pointer = std::shared_ptr; - Mapping(const QString& name); + Mapping(const QString& name) : name(name) {} - Map _channelMappings; + Map channelMappings; - QString _name; - - protected: + QString name; }; } diff --git a/libraries/controllers/src/controllers/Pose.cpp b/libraries/controllers/src/controllers/Pose.cpp index a716955d70..e4674735b0 100644 --- a/libraries/controllers/src/controllers/Pose.cpp +++ b/libraries/controllers/src/controllers/Pose.cpp @@ -12,17 +12,17 @@ namespace controller { Pose::Pose(const vec3& translation, const quat& rotation, const vec3& velocity, const quat& angularVelocity) : - _translation(translation), _rotation(rotation), _velocity(velocity), _angularVelocity(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) { + 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(); + 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 index b77064f2c1..9243ceb734 100644 --- a/libraries/controllers/src/controllers/Pose.h +++ b/libraries/controllers/src/controllers/Pose.h @@ -17,11 +17,11 @@ namespace controller { struct Pose { public: - vec3 _translation; - quat _rotation; - vec3 _velocity; - quat _angularVelocity; - bool _valid{ false }; + vec3 translation; + quat rotation; + vec3 velocity; + quat angularVelocity; + bool valid{ false }; Pose() {} Pose(const vec3& translation, const quat& rotation, @@ -30,11 +30,11 @@ namespace controller { 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; } + 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; } }; diff --git a/libraries/controllers/src/controllers/Route.cpp b/libraries/controllers/src/controllers/Route.cpp index 08b6d1f4f2..56590e564a 100644 --- a/libraries/controllers/src/controllers/Route.cpp +++ b/libraries/controllers/src/controllers/Route.cpp @@ -6,5 +6,4 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - #include "Route.h" diff --git a/libraries/controllers/src/controllers/Route.h b/libraries/controllers/src/controllers/Route.h index 01770a87d1..8b0e70050f 100644 --- a/libraries/controllers/src/controllers/Route.h +++ b/libraries/controllers/src/controllers/Route.h @@ -16,20 +16,17 @@ class QJsonObject; namespace controller { - /* * encapsulates a source, destination and filters to apply */ class Route { public: - Endpoint::Pointer _source; - Endpoint::Pointer _destination; - Filter::List _filters; + Endpoint::Pointer source; + Endpoint::Pointer destination; + Filter::List filters; using Pointer = std::shared_ptr; using List = std::list; - - void parse(const QJsonObject); }; } diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp index dc305c4c6e..0f9b5678ca 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.cpp +++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp @@ -12,8 +12,6 @@ #include -#include -#include #include #include @@ -26,475 +24,146 @@ #include "Logging.h" #include "InputDevice.h" +static QRegularExpression SANITIZE_NAME_EXPRESSION{ "[\\(\\)\\.\\s]" }; + +static QVariantMap createDeviceMap(const controller::DeviceProxy::Pointer device) { + auto userInputMapper = DependencyManager::get(); + QVariantMap deviceMap; + for (const auto& inputMapping : device->getAvailabeInputs()) { + const auto& input = inputMapping.first; + const auto inputName = QString(inputMapping.second).remove(SANITIZE_NAME_EXPRESSION); + qCDebug(controllers) << "\tInput " << input.getChannel() << (int)input.getType() + << QString::number(input.getID(), 16) << ": " << inputName; + deviceMap.insert(inputName, input.getID()); + } + return deviceMap; +} + +// FIXME this throws a hissy fit on MSVC if I put it in the main controller namespace block +controller::ScriptingInterface::ScriptingInterface() { + auto userInputMapper = DependencyManager::get(); + + // FIXME make this thread safe + connect(userInputMapper.data(), &UserInputMapper::hardwareChanged, [=] { + updateMaps(); + }); + + + qCDebug(controllers) << "Setting up standard controller abstraction"; + _standard = createDeviceMap(userInputMapper->getStandardDevice()); + + // FIXME allow custom user actions? + auto actionNames = userInputMapper->getActionNames(); + int actionNumber = 0; + qCDebug(controllers) << "Setting up standard actions"; + for (const auto& namedInput : userInputMapper->getActionInputs()) { + const QString& actionName = namedInput.second; + const Input& actionInput = namedInput.first; + qCDebug(controllers) << "\tAction: " << actionName << " " << actionInput.getChannel(); + + // Expose the IDs to JS + QString cleanActionName = QString(actionName).remove(SANITIZE_NAME_EXPRESSION); + _actions.insert(cleanActionName, actionInput.getID()); + } + + updateMaps(); +} + namespace controller { - class VirtualEndpoint : public Endpoint { - public: - VirtualEndpoint(const UserInputMapper::Input& id = UserInputMapper::Input::INVALID_INPUT) - : Endpoint(id) { - } - - virtual float value() override { return _currentValue; } - virtual void apply(float newValue, float oldValue, const Pointer& source) override { _currentValue = newValue; } - - private: - float _currentValue{ 0.0f }; - }; - - - class JSEndpoint : public Endpoint { - public: - JSEndpoint(const QJSValue& callable) - : Endpoint(UserInputMapper::Input::INVALID_INPUT), _callable(callable) {} - - virtual float value() { - float result = (float)_callable.call().toNumber();; - return result; - } - - virtual void apply(float newValue, float oldValue, const Pointer& source) { - _callable.call(QJSValueList({ QJSValue(newValue) })); - } - - private: - QJSValue _callable; - }; - - float ScriptEndpoint::value() { - updateValue(); - return _lastValue; - } - - void ScriptEndpoint::updateValue() { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection); - return; - } - - _lastValue = (float)_callable.call().toNumber(); - } - - void ScriptEndpoint::apply(float newValue, float oldValue, const Pointer& source) { - internalApply(newValue, oldValue, source->getInput().getID()); - } - - 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)); - return; - } - _callable.call(QScriptValue(), - QScriptValueList({ QScriptValue(newValue), QScriptValue(oldValue), QScriptValue(sourceID) })); - } - - class CompositeEndpoint : public Endpoint, Endpoint::Pair { - public: - CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second) - : Endpoint(UserInputMapper::Input(UserInputMapper::Input::INVALID_INPUT)), Pair(first, second) { } - - virtual float value() { - float result = first->value() * -1.0f + second->value(); - return result; - } - - virtual void apply(float newValue, float oldValue, const Pointer& source) { - // Composites are read only - } - - private: - Endpoint::Pointer _first; - Endpoint::Pointer _second; - }; - - class ActionEndpoint : public Endpoint { - public: - ActionEndpoint(const UserInputMapper::Input& id = UserInputMapper::Input::INVALID_INPUT) - : Endpoint(id) { - } - - virtual float value() override { return _currentValue; } - virtual void apply(float newValue, float oldValue, const Pointer& source) override { - - _currentValue += newValue; - if (!(_input == UserInputMapper::Input::INVALID_INPUT)) { - auto userInputMapper = DependencyManager::get(); - userInputMapper->deltaActionState(UserInputMapper::Action(_input.getChannel()), newValue); - } - } - - private: - float _currentValue{ 0.0f }; - }; - - QRegularExpression ScriptingInterface::SANITIZE_NAME_EXPRESSION{ "[\\(\\)\\.\\s]" }; - - QVariantMap createDeviceMap(const UserInputMapper::DeviceProxy* device) { - auto userInputMapper = DependencyManager::get(); - QVariantMap deviceMap; - for (const auto& inputMapping : device->getAvailabeInputs()) { - const auto& input = inputMapping.first; - const auto inputName = QString(inputMapping.second).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION); - qCDebug(controllers) << "\tInput " << input.getChannel() << (int)input.getType() - << QString::number(input.getID(), 16) << ": " << inputName; - deviceMap.insert(inputName, input.getID()); - } - return deviceMap; - } - - - ScriptingInterface::~ScriptingInterface() { - } - QObject* ScriptingInterface::newMapping(const QString& mappingName) { - if (_mappingsByName.count(mappingName)) { - qCWarning(controllers) << "Refusing to recreate mapping named " << mappingName; - } - qDebug() << "Creating new Mapping " << mappingName; - auto mapping = std::make_shared(mappingName); - _mappingsByName[mappingName] = mapping; - return new MappingBuilderProxy(*this, mapping); + auto userInputMapper = DependencyManager::get(); + return new MappingBuilderProxy(*userInputMapper, userInputMapper->newMapping(mappingName)); } - QObject* ScriptingInterface::parseMapping(const QString& json) { - - 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(); - - 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 nullptr; - } - - QObject* ScriptingInterface::loadMapping(const QString& jsonUrl) { - QObject* result = nullptr; - auto request = ResourceManager::createResourceRequest(nullptr, QUrl(jsonUrl)); - if (request) { - QEventLoop eventLoop; - request->setCacheEnabled(false); - connect(request, &ResourceRequest::finished, &eventLoop, &QEventLoop::quit); - request->send(); - if (request->getState() != ResourceRequest::Finished) { - eventLoop.exec(); - } - - if (request->getResult() == ResourceRequest::Success) { - result = parseMapping(QString(request->getData())); - } else { - qCWarning(controllers) << "Failed to load mapping url <" << jsonUrl << ">" << endl; - } - request->deleteLater(); - } - return result; - } - - Q_INVOKABLE QObject* newMapping(const QJsonObject& json); - void ScriptingInterface::enableMapping(const QString& mappingName, bool enable) { - qCDebug(controllers) << "Attempting to enable mapping " << mappingName; - auto iterator = _mappingsByName.find(mappingName); - if (_mappingsByName.end() == iterator) { - qCWarning(controllers) << "Request to enable / disable unknown mapping " << mappingName; - return; - } - - auto mapping = iterator->second; - if (enable) { - _activeMappings.push_front(mapping); - } else { - auto activeIterator = std::find(_activeMappings.begin(), _activeMappings.end(), mapping); - if (_activeMappings.end() == activeIterator) { - qCWarning(controllers) << "Attempted to disable inactive mapping " << mappingName; - return; - } - _activeMappings.erase(activeIterator); - } + auto userInputMapper = DependencyManager::get(); + userInputMapper->enableMapping(mappingName, enable); } float ScriptingInterface::getValue(const int& source) const { - // return (sin(secTimestampNow()) + 1.0f) / 2.0f; - UserInputMapper::Input input(source); - auto iterator = _endpoints.find(input); - if (_endpoints.end() == iterator) { - return 0.0; - } - - const auto& endpoint = iterator->second; - return getValue(endpoint); - } - - float ScriptingInterface::getValue(const Endpoint::Pointer& endpoint) const { - auto valuesIterator = _overrideValues.find(endpoint); - if (_overrideValues.end() != valuesIterator) { - return valuesIterator->second; - } - - return endpoint->value(); + auto userInputMapper = DependencyManager::get(); + return userInputMapper->getValue(Input((uint32_t)source)); } float ScriptingInterface::getButtonValue(StandardButtonChannel source, uint16_t device) const { - return getValue(UserInputMapper::Input(device, source, UserInputMapper::ChannelType::BUTTON).getID()); + return getValue(Input(device, source, ChannelType::BUTTON).getID()); } float ScriptingInterface::getAxisValue(StandardAxisChannel source, uint16_t device) const { - return getValue(UserInputMapper::Input(device, source, UserInputMapper::ChannelType::AXIS).getID()); + return getValue(Input(device, source, ChannelType::AXIS).getID()); } Pose ScriptingInterface::getPoseValue(StandardPoseChannel source, uint16_t device) const { return Pose(); } - void ScriptingInterface::update() { - auto userInputMapper = DependencyManager::get(); - static auto deviceNames = userInputMapper->getDeviceNames(); + //bool ScriptingInterface::isPrimaryButtonPressed() const { + // return isButtonPressed(StandardButtonChannel::A); + //} + // + //glm::vec2 ScriptingInterface::getPrimaryJoystickPosition() const { + // return getJoystickPosition(0); + //} - if (deviceNames != userInputMapper->getDeviceNames()) { - updateMaps(); - deviceNames = userInputMapper->getDeviceNames(); - } + //int ScriptingInterface::getNumberOfButtons() const { + // return StandardButtonChannel::NUM_STANDARD_BUTTONS; + //} - _overrideValues.clear(); - EndpointSet readEndpoints; - EndpointSet writtenEndpoints; - // Now process the current values for each level of the stack - for (auto& mapping : _activeMappings) { - for (const auto& mappingEntry : mapping->_channelMappings) { - const auto& source = mappingEntry.first; + //bool ScriptingInterface::isButtonPressed(int buttonIndex) const { + // return getButtonValue((StandardButtonChannel)buttonIndex) == 0.0 ? false : true; + //} - // Endpoints can only be read once (though a given mapping can route them to - // multiple places). Consider... If the default is to wire the A button to JUMP - // and someone else wires it to CONTEXT_MENU, I don't want both to occur when - // I press the button. The exception is if I'm wiring a control back to itself - // in order to adjust my interface, like inverting the Y axis on an analog stick - if (readEndpoints.count(source)) { - continue; - } + //int ScriptingInterface::getNumberOfTriggers() const { + // return StandardCounts::TRIGGERS; + //} - // Apply the value to all the routes - const auto& routes = mappingEntry.second; + //float ScriptingInterface::getTriggerValue(int triggerIndex) const { + // return getAxisValue(triggerIndex == 0 ? StandardAxisChannel::LT : StandardAxisChannel::RT); + //} - for (const auto& route : routes) { - const auto& destination = route->_destination; - // THis could happen if the route destination failed to create - // FIXME: Maybe do not create the route if the destination failed and avoid this case ? - if (!source || !destination) { - continue; - } + //int ScriptingInterface::getNumberOfJoysticks() const { + // return StandardCounts::ANALOG_STICKS; + //} - if (writtenEndpoints.count(destination)) { - continue; - } + //glm::vec2 ScriptingInterface::getJoystickPosition(int joystickIndex) const { + // StandardAxisChannel xid = StandardAxisChannel::LX; + // StandardAxisChannel yid = StandardAxisChannel::LY; + // if (joystickIndex != 0) { + // xid = StandardAxisChannel::RX; + // yid = StandardAxisChannel::RY; + // } + // vec2 result; + // result.x = getAxisValue(xid); + // result.y = getAxisValue(yid); + // return result; + //} - // Standard controller destinations can only be can only be used once. - if (userInputMapper->getStandardDeviceID() == destination->getInput().getDevice()) { - writtenEndpoints.insert(destination); - } + //int ScriptingInterface::getNumberOfSpatialControls() const { + // return StandardCounts::POSES; + //} - // Only consume the input if the route isn't a loopback. - // This allows mappings like `mapping.from(xbox.RY).invert().to(xbox.RY);` - bool loopback = source == destination; - if (!loopback) { - readEndpoints.insert(source); - } + //glm::vec3 ScriptingInterface::getSpatialControlPosition(int controlIndex) const { + // // FIXME extract the position from the standard pose + // return vec3(); + //} - // Fetch the value, may have been overriden by previous loopback routes - float value = getValue(source); + //glm::vec3 ScriptingInterface::getSpatialControlVelocity(int controlIndex) const { + // // FIXME extract the velocity from the standard pose + // return vec3(); + //} - // Apply each of the filters. - for (const auto& filter : route->_filters) { - value = filter->apply(value); - } + //glm::vec3 ScriptingInterface::getSpatialControlNormal(int controlIndex) const { + // // FIXME extract the normal from the standard pose + // return vec3(); + //} + // + //glm::quat ScriptingInterface::getSpatialControlRawRotation(int controlIndex) const { + // // FIXME extract the rotation from the standard pose + // return quat(); + //} - if (loopback) { - _overrideValues[source] = value; - } else { - destination->apply(value, 0, source); - } - } - } - } - } - - Endpoint::Pointer ScriptingInterface::endpointFor(const QJSValue& endpoint) { - if (endpoint.isNumber()) { - return endpointFor(UserInputMapper::Input(endpoint.toInt())); - } - - if (endpoint.isCallable()) { - auto result = std::make_shared(endpoint); - return result; - } - - qWarning() << "Unsupported input type " << endpoint.toString(); - return Endpoint::Pointer(); - } - - Endpoint::Pointer ScriptingInterface::endpointFor(const QScriptValue& endpoint) { - if (endpoint.isNumber()) { - return endpointFor(UserInputMapper::Input(endpoint.toInt32())); - } - - if (endpoint.isFunction()) { - auto result = std::make_shared(endpoint); - return result; - } - - qWarning() << "Unsupported input type " << endpoint.toString(); - return Endpoint::Pointer(); - } - - UserInputMapper::Input ScriptingInterface::inputFor(const QString& inputName) { - return DependencyManager::get()->findDeviceInput(inputName); - } - - Endpoint::Pointer ScriptingInterface::endpointFor(const UserInputMapper::Input& inputId) { - auto iterator = _endpoints.find(inputId); - if (_endpoints.end() == iterator) { - qWarning() << "Unknown input: " << QString::number(inputId.getID(), 16); - return Endpoint::Pointer(); - } - return iterator->second; - } - - Endpoint::Pointer ScriptingInterface::compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second) { - EndpointPair pair(first, second); - Endpoint::Pointer result; - auto iterator = _compositeEndpoints.find(pair); - if (_compositeEndpoints.end() == iterator) { - result = std::make_shared(first, second); - _compositeEndpoints[pair] = result; - } else { - result = iterator->second; - } - return result; - } - - bool ScriptingInterface::isPrimaryButtonPressed() const { - return isButtonPressed(StandardButtonChannel::A); - } - - glm::vec2 ScriptingInterface::getPrimaryJoystickPosition() const { - return getJoystickPosition(0); - } - - int ScriptingInterface::getNumberOfButtons() const { - return StandardButtonChannel::NUM_STANDARD_BUTTONS; - } - - bool ScriptingInterface::isButtonPressed(int buttonIndex) const { - return getButtonValue((StandardButtonChannel)buttonIndex) == 0.0f ? false : true; - } - - int ScriptingInterface::getNumberOfTriggers() const { - return StandardCounts::TRIGGERS; - } - - float ScriptingInterface::getTriggerValue(int triggerIndex) const { - return getAxisValue(triggerIndex == 0 ? StandardAxisChannel::LT : StandardAxisChannel::RT); - } - - int ScriptingInterface::getNumberOfJoysticks() const { - return StandardCounts::ANALOG_STICKS; - } - - glm::vec2 ScriptingInterface::getJoystickPosition(int joystickIndex) const { - StandardAxisChannel xid = StandardAxisChannel::LX; - StandardAxisChannel yid = StandardAxisChannel::LY; - if (joystickIndex != 0) { - xid = StandardAxisChannel::RX; - yid = StandardAxisChannel::RY; - } - vec2 result; - result.x = getAxisValue(xid); - result.y = getAxisValue(yid); - return result; - } - - int ScriptingInterface::getNumberOfSpatialControls() const { - return StandardCounts::POSES; - } - - glm::vec3 ScriptingInterface::getSpatialControlPosition(int controlIndex) const { - // FIXME extract the position from the standard pose - return vec3(); - } - - glm::vec3 ScriptingInterface::getSpatialControlVelocity(int controlIndex) const { - // FIXME extract the velocity from the standard pose - return vec3(); - } - - glm::vec3 ScriptingInterface::getSpatialControlNormal(int controlIndex) const { - // FIXME extract the normal from the standard pose - return vec3(); - } - - glm::quat ScriptingInterface::getSpatialControlRawRotation(int controlIndex) const { - // FIXME extract the rotation from the standard pose - return quat(); - } - - void ScriptingInterface::updateMaps() { - auto userInputMapper = DependencyManager::get(); - auto devices = userInputMapper->getDevices(); - QSet foundDevices; - for (const auto& deviceMapping : devices) { - auto deviceID = deviceMapping.first; - if (deviceID != userInputMapper->getStandardDeviceID()) { - auto device = deviceMapping.second.get(); - auto deviceName = QString(device->getName()).remove(ScriptingInterface::SANITIZE_NAME_EXPRESSION); - qCDebug(controllers) << "Device" << deviceMapping.first << ":" << deviceName; - foundDevices.insert(device->getName()); - if (_hardware.contains(deviceName)) { - continue; - } - - // Expose the IDs to JS - _hardware.insert(deviceName, createDeviceMap(device)); - - // Create the endpoints - for (const auto& inputMapping : device->getAvailabeInputs()) { - const auto& input = inputMapping.first; - // Ignore aliases - if (_endpoints.count(input)) { - continue; - } - _endpoints[input] = std::make_shared([=] { - auto deviceProxy = userInputMapper->getDeviceProxy(input); - if (!deviceProxy) { - return 0.0f; - } - return deviceProxy->getValue(input, 0); - }); - } - } - } - } - - QVector ScriptingInterface::getAllActions() { + QVector ScriptingInterface::getAllActions() { return DependencyManager::get()->getAllActions(); } @@ -502,7 +171,7 @@ namespace controller { return DependencyManager::get()->getDeviceName((unsigned short)device); } - QVector ScriptingInterface::getAvailableInputs(unsigned int device) { + QVector ScriptingInterface::getAvailableInputs(unsigned int device) { return DependencyManager::get()->getAvailableInputs((unsigned short)device); } @@ -515,7 +184,7 @@ namespace controller { } float ScriptingInterface::getActionValue(int action) { - return DependencyManager::get()->getActionState(UserInputMapper::Action(action)); + return DependencyManager::get()->getActionState(Action(action)); } int ScriptingInterface::findAction(QString actionName) { @@ -526,41 +195,40 @@ namespace controller { return DependencyManager::get()->getActionNames(); } + void ScriptingInterface::updateMaps() { + auto userInputMapper = DependencyManager::get(); + auto devices = userInputMapper->getDevices(); + QSet foundDevices; + for (const auto& deviceMapping : devices) { + auto deviceID = deviceMapping.first; + if (deviceID != userInputMapper->getStandardDeviceID()) { + auto device = deviceMapping.second; + auto deviceName = QString(device->getName()).remove(SANITIZE_NAME_EXPRESSION); + qCDebug(controllers) << "Device" << deviceMapping.first << ":" << deviceName; + foundDevices.insert(device->getName()); + if (_hardware.contains(deviceName)) { + continue; + } + + // Expose the IDs to JS + _hardware.insert(deviceName, createDeviceMap(device)); + } + + } + } + + + QObject* ScriptingInterface::parseMapping(const QString& json) { + auto userInputMapper = DependencyManager::get(); + auto mapping = userInputMapper->parseMapping(json); + return new MappingBuilderProxy(*userInputMapper, mapping); + } + + QObject* ScriptingInterface::loadMapping(const QString& jsonUrl) { + return nullptr; + } + + } // namespace controllers -using namespace controller; -// FIXME this throws a hissy fit on MSVC if I put it in the main controller namespace block -ScriptingInterface::ScriptingInterface() { - auto userInputMapper = DependencyManager::get(); - qCDebug(controllers) << "Setting up standard controller abstraction"; - auto standardDevice = userInputMapper->getStandardDevice(); - // Expose the IDs to JS - _standard = createDeviceMap(standardDevice.get()); - // Create the endpoints - for (const auto& inputMapping : standardDevice->getAvailabeInputs()) { - const auto& standardInput = inputMapping.first; - // Ignore aliases - if (_endpoints.count(standardInput)) { - continue; - } - _endpoints[standardInput] = std::make_shared(standardInput); - } - - // FIXME allow custom user actions? - auto actionNames = userInputMapper->getActionNames(); - int actionNumber = 0; - qCDebug(controllers) << "Setting up standard actions"; - for (const auto& actionName : actionNames) { - 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); - _actions.insert(cleanActionName, actionInput.getID()); - - // Create the action endpoints - _endpoints[actionInput] = std::make_shared(actionInput); - } - - updateMaps(); -} diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h index f473562b9e..b43e065822 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.h +++ b/libraries/controllers/src/controllers/ScriptingInterface.h @@ -32,7 +32,6 @@ #include "UserInputMapper.h" #include "StandardControls.h" -#include "Mapping.h" namespace controller { class InputController : public QObject { @@ -65,10 +64,10 @@ namespace controller { public: ScriptingInterface(); - virtual ~ScriptingInterface(); + virtual ~ScriptingInterface() {}; - Q_INVOKABLE QVector getAllActions(); - Q_INVOKABLE QVector getAvailableInputs(unsigned int device); + 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); @@ -87,23 +86,23 @@ namespace controller { Q_INVOKABLE QObject* loadMapping(const QString& jsonUrl); - Q_INVOKABLE bool isPrimaryButtonPressed() const; - Q_INVOKABLE glm::vec2 getPrimaryJoystickPosition() const; + //Q_INVOKABLE bool isPrimaryButtonPressed() const; + //Q_INVOKABLE glm::vec2 getPrimaryJoystickPosition() const; - Q_INVOKABLE int getNumberOfButtons() const; - Q_INVOKABLE bool isButtonPressed(int buttonIndex) const; + //Q_INVOKABLE int getNumberOfButtons() const; + //Q_INVOKABLE bool isButtonPressed(int buttonIndex) const; - Q_INVOKABLE int getNumberOfTriggers() const; - Q_INVOKABLE float getTriggerValue(int triggerIndex) const; + //Q_INVOKABLE int getNumberOfTriggers() const; + //Q_INVOKABLE float getTriggerValue(int triggerIndex) const; - Q_INVOKABLE int getNumberOfJoysticks() const; - Q_INVOKABLE glm::vec2 getJoystickPosition(int joystickIndex) const; + //Q_INVOKABLE int getNumberOfJoysticks() const; + //Q_INVOKABLE glm::vec2 getJoystickPosition(int joystickIndex) const; - Q_INVOKABLE int getNumberOfSpatialControls() const; - Q_INVOKABLE glm::vec3 getSpatialControlPosition(int controlIndex) const; - Q_INVOKABLE glm::vec3 getSpatialControlVelocity(int controlIndex) const; - Q_INVOKABLE glm::vec3 getSpatialControlNormal(int controlIndex) const; - Q_INVOKABLE glm::quat getSpatialControlRawRotation(int controlIndex) const; + //Q_INVOKABLE int getNumberOfSpatialControls() const; + //Q_INVOKABLE glm::vec3 getSpatialControlPosition(int controlIndex) const; + //Q_INVOKABLE glm::vec3 getSpatialControlVelocity(int controlIndex) const; + //Q_INVOKABLE glm::vec3 getSpatialControlNormal(int controlIndex) const; + //Q_INVOKABLE glm::quat getSpatialControlRawRotation(int controlIndex) const; Q_INVOKABLE const QVariantMap& getHardware() { return _hardware; } Q_INVOKABLE const QVariantMap& getActions() { return _actions; } @@ -114,11 +113,7 @@ namespace controller { bool isWheelCaptured() const { return _wheelCaptured; } bool areActionsCaptured() const { return _actionsCaptured; } - static QRegularExpression SANITIZE_NAME_EXPRESSION; - public slots: - virtual void update(); - virtual void updateMaps(); virtual void captureMouseEvents() { _mouseCaptured = true; } virtual void releaseMouseEvents() { _mouseCaptured = false; } @@ -134,61 +129,19 @@ namespace controller { private: - friend class MappingBuilderProxy; - friend class RouteBuilderProxy; - - // FIXME move to unordered set / map - using MappingMap = std::map; - using MappingStack = std::list; - using InputToEndpointMap = std::map; - using EndpointSet = std::unordered_set; - using ValueMap = std::map; - using EndpointPair = std::pair; - using EndpointPairMap = std::map; - - void update(Mapping::Pointer& mapping, EndpointSet& consumed); - float getValue(const Endpoint::Pointer& endpoint) const; - Endpoint::Pointer endpointFor(const QJSValue& endpoint); - Endpoint::Pointer endpointFor(const QScriptValue& endpoint); - Endpoint::Pointer endpointFor(const UserInputMapper::Input& endpoint); - Endpoint::Pointer compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second); - - UserInputMapper::Input inputFor(const QString& inputName); + // Update the exposed variant maps reporting active hardware + void updateMaps(); QVariantMap _hardware; QVariantMap _actions; QVariantMap _standard; - InputToEndpointMap _endpoints; - EndpointPairMap _compositeEndpoints; - - ValueMap _overrideValues; - MappingMap _mappingsByName; - MappingStack _activeMappings; - bool _mouseCaptured{ false }; bool _touchCaptured{ false }; bool _wheelCaptured{ false }; bool _actionsCaptured{ false }; }; - class ScriptEndpoint : public Endpoint { - Q_OBJECT; - public: - ScriptEndpoint(const QScriptValue& callable) - : Endpoint(UserInputMapper::Input::INVALID_INPUT), _callable(callable) { - } - - virtual float value(); - virtual void apply(float newValue, float oldValue, const Pointer& source); - - protected: - Q_INVOKABLE void updateValue(); - Q_INVOKABLE virtual void internalApply(float newValue, float oldValue, int sourceID); - private: - QScriptValue _callable; - float _lastValue = 0.0f; - }; } diff --git a/libraries/controllers/src/controllers/StandardController.cpp b/libraries/controllers/src/controllers/StandardController.cpp index 5c13c66a07..f5389d1518 100644 --- a/libraries/controllers/src/controllers/StandardController.cpp +++ b/libraries/controllers/src/controllers/StandardController.cpp @@ -9,12 +9,21 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - -#include - #include "StandardController.h" +#include + +#include "DeviceProxy.h" +#include "UserInputMapper.h" + +namespace controller { + +const float CONTROLLER_THRESHOLD = 0.3f; + +StandardController::StandardController() : InputDevice("Standard") { + _deviceID = UserInputMapper::STANDARD_DEVICE; +} + StandardController::~StandardController() { } @@ -26,143 +35,111 @@ void StandardController::focusOutEvent() { _buttonPressedMap.clear(); }; -void StandardController::registerToUserInputMapper(UserInputMapper& mapper) { - // Grab the current free device ID - _deviceID = mapper.getStandardDeviceID(); - - 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; +void StandardController::buildDeviceProxy(DeviceProxy::Pointer proxy) { + proxy->_name = _name; + proxy->getButton = [this] (const Input& input, int timestamp) -> bool { return getButton(input.getChannel()); }; + proxy->getAxis = [this] (const Input& input, int timestamp) -> float { return 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")); + availableInputs.append(Input::NamedPair(makeInput(controller::A), "A")); + availableInputs.append(Input::NamedPair(makeInput(controller::B), "B")); + availableInputs.append(Input::NamedPair(makeInput(controller::X), "X")); + availableInputs.append(Input::NamedPair(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")); + availableInputs.append(Input::NamedPair(makeInput(controller::DU), "DU")); + availableInputs.append(Input::NamedPair(makeInput(controller::DD), "DD")); + availableInputs.append(Input::NamedPair(makeInput(controller::DL), "DL")); + availableInputs.append(Input::NamedPair(makeInput(controller::DR), "DR")); // Bumpers - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LB), "LB")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RB), "RB")); + availableInputs.append(Input::NamedPair(makeInput(controller::LB), "LB")); + availableInputs.append(Input::NamedPair(makeInput(controller::RB), "RB")); // Stick press - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LS), "LS")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RS), "RS")); + availableInputs.append(Input::NamedPair(makeInput(controller::LS), "LS")); + availableInputs.append(Input::NamedPair(makeInput(controller::RS), "RS")); // Center buttons - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::START), "Start")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::BACK), "Back")); + availableInputs.append(Input::NamedPair(makeInput(controller::START), "Start")); + availableInputs.append(Input::NamedPair(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")); + availableInputs.append(Input::NamedPair(makeInput(controller::LY), "LY")); + availableInputs.append(Input::NamedPair(makeInput(controller::LX), "LX")); + availableInputs.append(Input::NamedPair(makeInput(controller::RY), "RY")); + availableInputs.append(Input::NamedPair(makeInput(controller::RX), "RX")); // Triggers - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LT), "LT")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RT), "RT")); + availableInputs.append(Input::NamedPair(makeInput(controller::LT), "LT")); + availableInputs.append(Input::NamedPair(makeInput(controller::RT), "RT")); // Poses - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::LEFT), "LeftPose")); - availableInputs.append(UserInputMapper::InputPair(makeInput(controller::RIGHT), "RightPose")); + availableInputs.append(Input::NamedPair(makeInput(controller::LEFT), "LeftPose")); + availableInputs.append(Input::NamedPair(makeInput(controller::RIGHT), "RightPose")); // 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")); - - + availableInputs.append(Input::NamedPair(makeInput(controller::LB), "L1")); + availableInputs.append(Input::NamedPair(makeInput(controller::RB), "R1")); + availableInputs.append(Input::NamedPair(makeInput(controller::LT), "L2")); + availableInputs.append(Input::NamedPair(makeInput(controller::RT), "R2")); + availableInputs.append(Input::NamedPair(makeInput(controller::LS), "L3")); + availableInputs.append(Input::NamedPair(makeInput(controller::RS), "R3")); + availableInputs.append(Input::NamedPair(makeInput(controller::BACK), "Select")); + availableInputs.append(Input::NamedPair(makeInput(controller::A), "Cross")); + availableInputs.append(Input::NamedPair(makeInput(controller::B), "Circle")); + availableInputs.append(Input::NamedPair(makeInput(controller::X), "Square")); + availableInputs.append(Input::NamedPair(makeInput(controller::Y), "Triangle")); + availableInputs.append(Input::NamedPair(makeInput(controller::DU), "Up")); + availableInputs.append(Input::NamedPair(makeInput(controller::DD), "Down")); + availableInputs.append(Input::NamedPair(makeInput(controller::DL), "Left")); + availableInputs.append(Input::NamedPair(makeInput(controller::DR), "Right")); return availableInputs; }; - - 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)); +QString StandardController::getDefaultMappingConfig() { + static const QString DEFAULT_MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/standard.json"; + return DEFAULT_MAPPING_JSON; } -UserInputMapper::Input StandardController::makeInput(controller::StandardButtonChannel button) { - return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON); -} +// FIXME figure out how to move the shifted version to JSON +//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; +// +// // 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::StandardAxisChannel axis) { - return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS); -} - -UserInputMapper::Input StandardController::makeInput(controller::StandardPoseChannel pose) { - return UserInputMapper::Input(_deviceID, pose, UserInputMapper::ChannelType::POSE); } diff --git a/libraries/controllers/src/controllers/StandardController.h b/libraries/controllers/src/controllers/StandardController.h index c393af80f4..4aad513553 100644 --- a/libraries/controllers/src/controllers/StandardController.h +++ b/libraries/controllers/src/controllers/StandardController.h @@ -12,37 +12,31 @@ #ifndef hifi_StandardController_h #define hifi_StandardController_h -#include -#include +#include +#include #include "InputDevice.h" - #include "StandardControls.h" -typedef std::shared_ptr StandardControllerPointer; +namespace controller { class StandardController : public QObject, public InputDevice { Q_OBJECT Q_PROPERTY(QString name READ getName) public: - const QString& getName() const { return _name; } // Device functions - virtual void registerToUserInputMapper(UserInputMapper& mapper) override; - virtual void assignDefaultInputMapping(UserInputMapper& mapper) override; + virtual void buildDeviceProxy(DeviceProxy::Pointer proxy) override; + virtual QString getDefaultMappingConfig() override; virtual void update(float deltaTime, bool jointsCaptured) override; virtual void focusOutEvent() override; - - StandardController() : InputDevice("Standard") {} - ~StandardController(); - - UserInputMapper::Input makeInput(controller::StandardButtonChannel button); - UserInputMapper::Input makeInput(controller::StandardAxisChannel axis); - UserInputMapper::Input makeInput(controller::StandardPoseChannel pose); -private: + StandardController(); + virtual ~StandardController(); }; +} + #endif // hifi_StandardController_h diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp index 26e03b7719..7b009273a1 100755 --- a/libraries/controllers/src/controllers/UserInputMapper.cpp +++ b/libraries/controllers/src/controllers/UserInputMapper.cpp @@ -7,20 +7,156 @@ // #include "UserInputMapper.h" -#include "StandardController.h" +#include +#include + +#include +#include +#include + +#include + +#include "StandardController.h" #include "Logging.h" -const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - (uint16)1; -const uint16_t UserInputMapper::STANDARD_DEVICE = 0; +namespace controller { + const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - 0xFF; + const uint16_t UserInputMapper::STANDARD_DEVICE = 0; +} // Default contruct allocate the poutput size with the current hardcoded action channels -UserInputMapper::UserInputMapper() { - registerStandardDevice(); +controller::UserInputMapper::UserInputMapper() { + _activeMappings.push_back(_defaultMapping); + _standardController = std::make_shared(); + registerDevice(new ActionsDevice()); + registerDevice(_standardController.get()); assignDefaulActionScales(); - createActionNames(); } +namespace controller { + +class ScriptEndpoint : public Endpoint { + Q_OBJECT; +public: + ScriptEndpoint(const QScriptValue& callable) + : Endpoint(Input::INVALID_INPUT), _callable(callable) { + } + + virtual float value(); + virtual void apply(float newValue, float oldValue, const Pointer& source); + +protected: + Q_INVOKABLE void updateValue(); + Q_INVOKABLE virtual void internalApply(float newValue, float oldValue, int sourceID); +private: + QScriptValue _callable; + float _lastValue = 0.0f; +}; + +class VirtualEndpoint : public Endpoint { +public: + VirtualEndpoint(const Input& id = Input::INVALID_INPUT) + : Endpoint(id) { + } + + virtual float value() override { return _currentValue; } + virtual void apply(float newValue, float oldValue, const Pointer& source) override { _currentValue = newValue; } + +private: + float _currentValue{ 0.0f }; +}; + + +class JSEndpoint : public Endpoint { +public: + JSEndpoint(const QJSValue& callable) + : Endpoint(Input::INVALID_INPUT), _callable(callable) { + } + + virtual float value() { + float result = (float)_callable.call().toNumber();; + return result; + } + + virtual void apply(float newValue, float oldValue, const Pointer& source) { + _callable.call(QJSValueList({ QJSValue(newValue) })); + } + +private: + QJSValue _callable; +}; + +float ScriptEndpoint::value() { + updateValue(); + return _lastValue; +} + +void ScriptEndpoint::updateValue() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection); + return; + } + + _lastValue = (float)_callable.call().toNumber(); +} + +void ScriptEndpoint::apply(float newValue, float oldValue, const Pointer& source) { + internalApply(newValue, oldValue, source->getInput().getID()); +} + +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)); + return; + } + _callable.call(QScriptValue(), + QScriptValueList({ QScriptValue(newValue), QScriptValue(oldValue), QScriptValue(sourceID) })); +} + +class CompositeEndpoint : public Endpoint, Endpoint::Pair { +public: + CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second) + : Endpoint(Input(Input::INVALID_INPUT)), Pair(first, second) { } + + virtual float value() { + float result = first->value() * -1.0f + second->value(); + return result; + } + + virtual void apply(float newValue, float oldValue, const Pointer& source) { + // Composites are read only + } + +private: + Endpoint::Pointer _first; + Endpoint::Pointer _second; +}; + +class ActionEndpoint : public Endpoint { +public: + ActionEndpoint(const Input& id = Input::INVALID_INPUT) + : Endpoint(id) { + } + + virtual float value() override { return _currentValue; } + virtual void apply(float newValue, float oldValue, const Pointer& source) override { + + _currentValue += newValue; + if (!(_input == Input::INVALID_INPUT)) { + auto userInputMapper = DependencyManager::get(); + userInputMapper->deltaActionState(Action(_input.getChannel()), newValue); + } + } + +private: + float _currentValue{ 0.0f }; +}; + + UserInputMapper::~UserInputMapper() { } @@ -32,28 +168,58 @@ int UserInputMapper::recordDeviceOfType(const QString& deviceName) { return _deviceCounts[deviceName]; } -bool UserInputMapper::registerDevice(uint16 deviceID, const DeviceProxy::Pointer& proxy) { +void UserInputMapper::registerDevice(InputDevice* device) { + if (device->_deviceID == Input::INVALID_DEVICE) { + device->_deviceID = getFreeDeviceID(); + } + const auto& deviceID = device->_deviceID; + DeviceProxy::Pointer proxy = std::make_shared(); + proxy->_name = device->_name; + device->buildDeviceProxy(proxy); + int numberOfType = recordDeviceOfType(proxy->_name); - if (numberOfType > 1) { proxy->_name += QString::number(numberOfType); } - + qCDebug(controllers) << "Registered input device <" << proxy->_name << "> deviceID = " << deviceID; + + for (const auto& inputMapping : proxy->getAvailabeInputs()) { + const auto& input = inputMapping.first; + // Ignore aliases + if (_endpointsByInput.count(input)) { + continue; + } + Endpoint::Pointer endpoint; + if (input.device == STANDARD_DEVICE) { + endpoint = std::make_shared(input); + } else if (input.device == ACTIONS_DEVICE) { + endpoint = std::make_shared(input); + } else { + endpoint = std::make_shared([=] { + return proxy->getValue(input, 0); + }); + } + _inputsByEndpoint[endpoint] = input; + _endpointsByInput[input] = endpoint; + } + _registeredDevices[deviceID] = proxy; - return true; - + auto mapping = loadMapping(device->getDefaultMappingConfig()); + if (mapping) { + _mappingsByDevice[deviceID] = mapping; + for (const auto& entry : mapping->channelMappings) { + const auto& source = entry.first; + const auto& routes = entry.second; + auto& list = _defaultMapping->channelMappings[source]; + list.insert(list.end(), routes.begin(), routes.end()); + } + } + + emit hardwareChanged(); } - -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) { +DeviceProxy::Pointer UserInputMapper::getDeviceProxy(const Input& input) { auto device = _registeredDevices.find(input.getDevice()); if (device != _registeredDevices.end()) { return (device->second); @@ -69,25 +235,9 @@ QString UserInputMapper::getDeviceName(uint16 deviceID) { 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) { + if (device.second->_name == name) { return device.first; } } @@ -103,8 +253,11 @@ QVector UserInputMapper::getDeviceNames() { return result; } -UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName) const { - +int UserInputMapper::findAction(const QString& actionName) const { + return findDeviceInput("Actions." + actionName).getChannel(); +} + +Input UserInputMapper::findDeviceInput(const QString& inputName) const { // Split the full input name as such: deviceName.inputName auto names = inputName.split('.'); @@ -126,20 +279,9 @@ UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName qCDebug(controllers) << "Couldn\'t find InputChannel named <" << inputName << "> for device <" << deviceName << ">"; - } else if (deviceName == "Actions") { - deviceID = ACTIONS_DEVICE; - int actionNum = 0; - for (auto action : _actionNames) { - if (action == inputName) { - return Input(ACTIONS_DEVICE, actionNum, ChannelType::AXIS); - } - actionNum++; - } - - qCDebug(controllers) << "Couldn\'t find ActionChannel named <" << inputName << "> among actions"; - } else { qCDebug(controllers) << "Couldn\'t find InputDevice named <" << deviceName << ">"; + findDevice(deviceName); } } else { qCDebug(controllers) << "Couldn\'t understand <" << inputName << "> as a valid inputDevice.inputName"; @@ -148,100 +290,11 @@ UserInputMapper::Input UserInputMapper::findDeviceInput(const QString& inputName 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); - } -} - +// FIXME remove the associated device mappings 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; @@ -249,64 +302,17 @@ void fixBisectedAxis(float& full, float& negative, float& positive) { } 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(); + channel = Pose(); } - 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; - } - } + // Run the mappings code + update(); // Scale all the channel step with the scale for (auto i = 0; i < NUM_ACTIONS; i++) { @@ -337,7 +343,12 @@ void UserInputMapper::update(float deltaTime) { } } -QVector UserInputMapper::getAllActions() const { +Input::NamedVector UserInputMapper::getAvailableInputs(uint16 deviceID) const { + auto iterator = _registeredDevices.find(deviceID); + return iterator->second->getAvailabeInputs(); +} + +QVector UserInputMapper::getAllActions() const { QVector actions; for (auto i = 0; i < NUM_ACTIONS; i++) { actions.append(Action(i)); @@ -345,31 +356,20 @@ QVector UserInputMapper::getAllActions() const { 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; +QString UserInputMapper::getActionName(Action action) const { + for (auto actionPair : getActionInputs()) { + if (actionPair.first.channel == action) { + return actionPair.second; } } - // If the action isn't found, return -1 - return -1; + return QString(); } + QVector UserInputMapper::getActionNames() const { QVector result; - for (auto i = 0; i < NUM_ACTIONS; i++) { - result << _actionNames[i]; + for (auto actionPair : getActionInputs()) { + result << actionPair.second; } return result; } @@ -402,56 +402,18 @@ void UserInputMapper::assignDefaulActionScales() { _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"; -} +static int actionMetaTypeId = qRegisterMetaType(); +static int inputMetaTypeId = qRegisterMetaType(); +static int inputPairMetaTypeId = qRegisterMetaType(); -void UserInputMapper::registerStandardDevice() { - _standardController = std::make_shared(); - _standardController->registerToUserInputMapper(*this); - _standardController->assignDefaultInputMapping(*this); -} +QScriptValue inputToScriptValue(QScriptEngine* engine, const Input& input); +void inputFromScriptValue(const QScriptValue& object, Input& input); +QScriptValue actionToScriptValue(QScriptEngine* engine, const Action& action); +void actionFromScriptValue(const QScriptValue& object, Action& action); +QScriptValue inputPairToScriptValue(QScriptEngine* engine, const InputPair& inputPair); +void inputPairFromScriptValue(const QScriptValue& object, InputPair& inputPair); -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 inputToScriptValue(QScriptEngine* engine, const Input& input) { QScriptValue obj = engine->newObject(); obj.setProperty("device", input.getDevice()); obj.setProperty("channel", input.getChannel()); @@ -460,14 +422,11 @@ QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::In 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()); +void inputFromScriptValue(const QScriptValue& object, Input& input) { + input.id = object.property("id").toInt32(); } -QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action) { +QScriptValue actionToScriptValue(QScriptEngine* engine, const Action& action) { QScriptValue obj = engine->newObject(); auto userInputMapper = DependencyManager::get(); obj.setProperty("action", (int)action); @@ -475,38 +434,361 @@ QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::A return obj; } -void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action) { - action = UserInputMapper::Action(object.property("action").toVariant().toInt()); +void actionFromScriptValue(const QScriptValue& object, Action& action) { + action = Action(object.property("action").toVariant().toInt()); } -QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair) { +QScriptValue inputPairToScriptValue(QScriptEngine* engine, const 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) { +void inputPairFromScriptValue(const QScriptValue& object, 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); + qScriptRegisterSequenceMetaType >(engine); + qScriptRegisterSequenceMetaType >(engine); qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue); qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue); qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue); } -UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardButtonChannel button) { +Input UserInputMapper::makeStandardInput(controller::StandardButtonChannel button) { return Input(STANDARD_DEVICE, button, ChannelType::BUTTON); } -UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardAxisChannel axis) { +Input UserInputMapper::makeStandardInput(controller::StandardAxisChannel axis) { return Input(STANDARD_DEVICE, axis, ChannelType::AXIS); } -UserInputMapper::Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) { +Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) { return Input(STANDARD_DEVICE, pose, ChannelType::POSE); } + + + +void UserInputMapper::update() { + static auto deviceNames = getDeviceNames(); + _overrideValues.clear(); + + EndpointSet readEndpoints; + EndpointSet writtenEndpoints; + + static const int HARDWARE_PASS = 0; + static const int STANDARD_PASS = 1; + + // Now process the current values for each level of the stack + for (auto& mapping : _activeMappings) { + for (int pass = 0; pass < 2; ++pass) { + for (const auto& mappingEntry : mapping->channelMappings) { + const auto& source = mappingEntry.first; + if (_inputsByEndpoint.count(source)) { + auto sourceInput = _inputsByEndpoint[source]; + if ((sourceInput.device == STANDARD_DEVICE) ^ (pass == STANDARD_PASS)) { + continue; + } + } + + // Endpoints can only be read once (though a given mapping can route them to + // multiple places). Consider... If the default is to wire the A button to JUMP + // and someone else wires it to CONTEXT_MENU, I don't want both to occur when + // I press the button. The exception is if I'm wiring a control back to itself + // in order to adjust my interface, like inverting the Y axis on an analog stick + if (readEndpoints.count(source)) { + continue; + } + + // Apply the value to all the routes + const auto& routes = mappingEntry.second; + + for (const auto& route : routes) { + const auto& destination = route->destination; + // THis could happen if the route destination failed to create + // FIXME: Maybe do not create the route if the destination failed and avoid this case ? + if (!destination) { + continue; + } + + if (writtenEndpoints.count(destination)) { + continue; + } + + // Standard controller destinations can only be can only be used once. + if (getStandardDeviceID() == destination->getInput().getDevice()) { + writtenEndpoints.insert(destination); + } + + // Only consume the input if the route isn't a loopback. + // This allows mappings like `mapping.from(xbox.RY).invert().to(xbox.RY);` + bool loopback = source == destination; + if (!loopback) { + readEndpoints.insert(source); + } + + // Fetch the value, may have been overriden by previous loopback routes + float value = getValue(source); + + // Apply each of the filters. + const auto& filters = route->filters; + for (const auto& filter : route->filters) { + value = filter->apply(value); + } + + if (loopback) { + _overrideValues[source] = value; + } else { + destination->apply(value, 0, source); + } + } + } + } + } +} + +Endpoint::Pointer UserInputMapper::endpointFor(const QJSValue& endpoint) { + if (endpoint.isNumber()) { + return endpointFor(Input(endpoint.toInt())); + } + + if (endpoint.isCallable()) { + auto result = std::make_shared(endpoint); + return result; + } + + qWarning() << "Unsupported input type " << endpoint.toString(); + return Endpoint::Pointer(); +} + +Endpoint::Pointer UserInputMapper::endpointFor(const QScriptValue& endpoint) { + if (endpoint.isNumber()) { + return endpointFor(Input(endpoint.toInt32())); + } + + if (endpoint.isFunction()) { + auto result = std::make_shared(endpoint); + return result; + } + + qWarning() << "Unsupported input type " << endpoint.toString(); + return Endpoint::Pointer(); +} + +Endpoint::Pointer UserInputMapper::endpointFor(const Input& inputId) const { + auto iterator = _endpointsByInput.find(inputId); + if (_endpointsByInput.end() == iterator) { + qWarning() << "Unknown input: " << QString::number(inputId.getID(), 16); + return Endpoint::Pointer(); + } + return iterator->second; +} + +Endpoint::Pointer UserInputMapper::compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second) { + EndpointPair pair(first, second); + Endpoint::Pointer result; + auto iterator = _compositeEndpoints.find(pair); + if (_compositeEndpoints.end() == iterator) { + result = std::make_shared(first, second); + _compositeEndpoints[pair] = result; + } else { + result = iterator->second; + } + return result; +} + + +Mapping::Pointer UserInputMapper::newMapping(const QString& mappingName) { + if (_mappingsByName.count(mappingName)) { + qCWarning(controllers) << "Refusing to recreate mapping named " << mappingName; + } + qDebug() << "Creating new Mapping " << mappingName; + auto mapping = std::make_shared(mappingName); + _mappingsByName[mappingName] = mapping; + return mapping; +} + +// FIXME handle asynchronous loading in the UserInputMapper +//QObject* ScriptingInterface::loadMapping(const QString& jsonUrl) { +// QObject* result = nullptr; +// auto request = ResourceManager::createResourceRequest(nullptr, QUrl(jsonUrl)); +// if (request) { +// QEventLoop eventLoop; +// request->setCacheEnabled(false); +// connect(request, &ResourceRequest::finished, &eventLoop, &QEventLoop::quit); +// request->send(); +// if (request->getState() != ResourceRequest::Finished) { +// eventLoop.exec(); +// } +// +// if (request->getResult() == ResourceRequest::Success) { +// result = parseMapping(QString(request->getData())); +// } else { +// qCWarning(controllers) << "Failed to load mapping url <" << jsonUrl << ">" << endl; +// } +// request->deleteLater(); +// } +// return result; +//} + + +void UserInputMapper::enableMapping(const QString& mappingName, bool enable) { + qCDebug(controllers) << "Attempting to enable mapping " << mappingName; + auto iterator = _mappingsByName.find(mappingName); + if (_mappingsByName.end() == iterator) { + qCWarning(controllers) << "Request to enable / disable unknown mapping " << mappingName; + return; + } + + auto mapping = iterator->second; + if (enable) { + _activeMappings.push_front(mapping); + } else { + auto activeIterator = std::find(_activeMappings.begin(), _activeMappings.end(), mapping); + if (_activeMappings.end() == activeIterator) { + qCWarning(controllers) << "Attempted to disable inactive mapping " << mappingName; + return; + } + _activeMappings.erase(activeIterator); + } +} + +float UserInputMapper::getValue(const Endpoint::Pointer& endpoint) const { + auto valuesIterator = _overrideValues.find(endpoint); + if (_overrideValues.end() != valuesIterator) { + return valuesIterator->second; + } + + return endpoint->value(); +} + +float UserInputMapper::getValue(const Input& input) const { + auto endpoint = endpointFor(input); + if (!endpoint) { + return 0; + } + return endpoint->value(); +} + + +Mapping::Pointer UserInputMapper::loadMapping(const QString& jsonFile) { + if (jsonFile.isEmpty()) { + return Mapping::Pointer(); + } + QString json; + { + QFile file(jsonFile); + if (file.open(QFile::ReadOnly | QFile::Text)) { + json = QTextStream(&file).readAll(); + } + file.close(); + } + return parseMapping(json); +} + + +const QString JSON_NAME = QStringLiteral("name"); +const QString JSON_CHANNELS = QStringLiteral("channels"); +const QString JSON_CHANNEL_FROM = QStringLiteral("from"); +const QString JSON_CHANNEL_TO = QStringLiteral("to"); +const QString JSON_CHANNEL_FILTERS = QStringLiteral("filters"); + +Endpoint::Pointer UserInputMapper::parseEndpoint(const QJsonValue& value) { + if (value.isString()) { + auto input = findDeviceInput(value.toString()); + return endpointFor(input); + } else if (value.isObject()) { + // Endpoint is defined as an object, we expect a js function then + return Endpoint::Pointer(); + } + return Endpoint::Pointer(); +} + +Route::Pointer UserInputMapper::parseRoute(const QJsonValue& value) { + if (!value.isObject()) { + return Route::Pointer(); + } + + const auto& obj = value.toObject(); + Route::Pointer result = std::make_shared(); + result->source = parseEndpoint(obj[JSON_CHANNEL_FROM]); + if (!result->source) { + qWarning() << "Invalid route source " << obj[JSON_CHANNEL_FROM]; + return Route::Pointer(); + } + result->destination = parseEndpoint(obj[JSON_CHANNEL_TO]); + if (!result->destination) { + qWarning() << "Invalid route destination " << obj[JSON_CHANNEL_TO]; + return Route::Pointer(); + } + + const auto& filtersValue = obj[JSON_CHANNEL_FILTERS]; + if (filtersValue.isArray()) { + auto filtersArray = filtersValue.toArray(); + for (auto filterValue : filtersArray) { + if (filterValue.isObject()) { + qWarning() << "Invalid filter " << filterValue; + return Route::Pointer(); + } + Filter::Pointer filter = Filter::parse(filterValue.toObject()); + if (!filter) { + qWarning() << "Invalid filter " << filterValue; + return Route::Pointer(); + } + result->filters.push_back(filter); + } + } + return result; +} + +Mapping::Pointer UserInputMapper::parseMapping(const QJsonValue& json) { + if (!json.isObject()) { + return Mapping::Pointer(); + } + + auto obj = json.toObject(); + auto mapping = std::make_shared("default"); + mapping->name = obj[JSON_NAME].toString(); + mapping->channelMappings.clear(); + const auto& jsonChannels = obj[JSON_CHANNELS].toArray(); + Mapping::Map map; + for (const auto& channelIt : jsonChannels) { + Route::Pointer route = parseRoute(channelIt); + if (!route) { + qWarning() << "Couldn't parse route"; + continue; + } + mapping->channelMappings[route->source].push_back(route); + } + return mapping; +} + +Mapping::Pointer UserInputMapper::parseMapping(const QString& json) { + Mapping::Pointer result; + QJsonObject obj; + QJsonParseError error; + QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8(), &error); + // check validity of the document + if (doc.isNull()) { + return Mapping::Pointer(); + } + + if (!doc.isObject()) { + qWarning() << "Mapping json Document is not an object" << endl; + return Mapping::Pointer(); + } + + // FIXME how did we detect this? + // qDebug() << "Invalid JSON...\n"; + // qDebug() << error.errorString(); + // qDebug() << "JSON was:\n" << json << endl; + //} + return parseMapping(doc.object()); +} + +} + +#include "UserInputMapper.moc" diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h index d463ed0482..1c1a9506df 100644 --- a/libraries/controllers/src/controllers/UserInputMapper.h +++ b/libraries/controllers/src/controllers/UserInputMapper.h @@ -15,234 +15,155 @@ #include #include #include + +#include +#include + #include #include #include "Pose.h" #include "Input.h" +#include "InputDevice.h" #include "DeviceProxy.h" #include "StandardControls.h" +#include "Mapping.h" +#include "Endpoint.h" +#include "Actions.h" -class StandardController; -typedef std::shared_ptr StandardControllerPointer; +namespace controller { + class UserInputMapper : public QObject, public Dependency { + Q_OBJECT + SINGLETON_DEPENDENCY + Q_ENUMS(Action) -class UserInputMapper : public QObject, public Dependency { - Q_OBJECT - SINGLETON_DEPENDENCY - Q_ENUMS(Action) -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; - - static void registerControllerTypes(QScriptEngine* engine); - - static const uint16 ACTIONS_DEVICE; - static const uint16 STANDARD_DEVICE; - - - // Modifiers are just button inputID - typedef std::vector< Input > Modifiers; - typedef std::function ButtonGetter; - typedef std::function AxisGetter; - typedef std::function PoseGetter; - typedef QPair InputPair; - typedef std::function ()> AvailableInputGetter; - typedef std::function ResetBindings; - - typedef QVector AvailableInput; - - // GetFreeDeviceID should be called before registering a device to use an ID not used by a different device. - uint16 getFreeDeviceID() { return _nextFreeDeviceID++; } - - bool registerDevice(uint16 deviceID, const DeviceProxy::Pointer& device); - bool registerStandardDevice(const DeviceProxy::Pointer& device); - DeviceProxy::Pointer getDeviceProxy(const Input& input); - QString getDeviceName(uint16 deviceID); - QVector getAvailableInputs(uint16 deviceID) { return _registeredDevices[deviceID]->getAvailabeInputs(); } - void resetAllDeviceBindings(); - void resetDevice(uint16 deviceID); - int findDevice(QString name) const; - QVector getDeviceNames(); - - Input findDeviceInput(const QString& inputName) const; - - - // Actions are the output channels of the Mapper, that's what the InputChannel map to - // For now the Actions are hardcoded, this is bad, but we will fix that in the near future - enum Action { - TRANSLATE_X = 0, - TRANSLATE_Y, - TRANSLATE_Z, - ROTATE_X, PITCH = ROTATE_X, - ROTATE_Y, YAW = ROTATE_Y, - ROTATE_Z, ROLL = ROTATE_Z, - - TRANSLATE_CAMERA_Z, - NUM_COMBINED_AXES, - - LEFT_HAND = NUM_COMBINED_AXES, - RIGHT_HAND, - - LEFT_HAND_CLICK, - RIGHT_HAND_CLICK, - - ACTION1, - ACTION2, - - CONTEXT_MENU, - TOGGLE_MUTE, - - SHIFT, - - // Biseced aliases for TRANSLATE_Z - LONGITUDINAL_BACKWARD, - LONGITUDINAL_FORWARD, - - // Biseced aliases for TRANSLATE_X - LATERAL_LEFT, - LATERAL_RIGHT, - - // Biseced aliases for TRANSLATE_Y - VERTICAL_DOWN, - VERTICAL_UP, - - // Biseced aliases for ROTATE_Y - YAW_LEFT, - YAW_RIGHT, - - // Biseced aliases for ROTATE_X - PITCH_DOWN, - PITCH_UP, - - // Biseced aliases for TRANSLATE_CAMERA_Z - BOOM_IN, - BOOM_OUT, - - NUM_ACTIONS, - }; - - std::vector _actionNames = std::vector(NUM_ACTIONS); - void createActionNames(); - - QVector getAllActions() const; - QString getActionName(Action action) const { return UserInputMapper::_actionNames[(int) action]; } - float getActionState(Action action) const { return _actionStates[action]; } - PoseValue getPoseState(Action action) const { return _poseStates[action]; } - int findAction(const QString& actionName) const; - QVector getActionNames() const; - void assignDefaulActionScales(); - - void setActionState(Action action, float value) { _externalActionStates[action] = value; } - void deltaActionState(Action action, float delta) { _externalActionStates[action] += delta; } - - // Add input channel to the mapper and check that all the used channels are registered. - // 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 { public: - Input _input; - Input _modifier = Input(); // make it invalid by default, meaning no modifier - Action _action = LONGITUDINAL_BACKWARD; - float _scale = 0.0f; - - Input getInput() const { return _input; } - Input getModifier() const { return _modifier; } - Action getAction() const { return _action; } - float getScale() const { return _scale; } - - void setInput(Input input) { _input = input; } - void setModifier(Input modifier) { _modifier = modifier; } - void setAction(Action action) { _action = action; } - void setScale(float scale) { _scale = scale; } + using InputPair = Input::NamedPair; + // FIXME move to unordered set / map + using EndpointToInputMap = std::map; + using MappingNameMap = std::map; + using MappingDeviceMap = std::map; + using MappingStack = std::list; + using InputToEndpointMap = std::map; + using EndpointSet = std::unordered_set; + using ValueMap = std::map; + using EndpointPair = std::pair; + using EndpointPairMap = std::map; + using DevicesMap = std::map; + using uint16 = uint16_t; + using uint32 = uint32_t; - InputChannel() {} - InputChannel(const Input& input, const Input& modifier, Action action, float scale = 1.0f) : - _input(input), _modifier(modifier), _action(action), _scale(scale) {} - InputChannel(const InputChannel& src) : InputChannel(src._input, src._modifier, src._action, src._scale) {} - InputChannel& operator = (const InputChannel& src) { _input = src._input; _modifier = src._modifier; _action = src._action; _scale = src._scale; return (*this); } - bool operator ==(const InputChannel& right) const { return _input == right._input && _modifier == right._modifier && _action == right._action && _scale == right._scale; } - bool hasModifier() { return _modifier.isValid(); } + static const uint16_t ACTIONS_DEVICE; + static const uint16_t STANDARD_DEVICE; + + UserInputMapper(); + virtual ~UserInputMapper(); + + + static void registerControllerTypes(QScriptEngine* engine); + + + void registerDevice(InputDevice* device); + DeviceProxy::Pointer getDeviceProxy(const Input& input); + QString getDeviceName(uint16 deviceID); + + Input::NamedVector getAvailableInputs(uint16 deviceID) const; + Input::NamedVector getActionInputs() const { return getAvailableInputs(ACTIONS_DEVICE); } + Input::NamedVector getStandardInputs() const { return getAvailableInputs(STANDARD_DEVICE); } + + int findDevice(QString name) const; + QVector getDeviceNames(); + Input findDeviceInput(const QString& inputName) const; + + QVector getAllActions() const; + QString getActionName(Action action) const; + float getActionState(Action action) const { return _actionStates[action]; } + Pose getPoseState(Action action) const { return _poseStates[action]; } + int findAction(const QString& actionName) const; + QVector getActionNames() const; + void assignDefaulActionScales(); + + void setActionState(Action action, float value) { _externalActionStates[action] = value; } + void deltaActionState(Action action, float delta) { _externalActionStates[action] += delta; } + + static Input makeStandardInput(controller::StandardButtonChannel button); + static Input makeStandardInput(controller::StandardAxisChannel axis); + static Input makeStandardInput(controller::StandardPoseChannel pose); + + void removeDevice(int device); + + // Update means go grab all the device input channels and update the output channel values + void update(float deltaTime); + + void setSensorToWorldMat(glm::mat4 sensorToWorldMat) { _sensorToWorldMat = sensorToWorldMat; } + glm::mat4 getSensorToWorldMat() { return _sensorToWorldMat; } + + DevicesMap getDevices() { return _registeredDevices; } + uint16 getStandardDeviceID() const { return STANDARD_DEVICE; } + DeviceProxy::Pointer getStandardDevice() { return _registeredDevices[getStandardDeviceID()]; } + + Mapping::Pointer newMapping(const QString& mappingName); + Mapping::Pointer parseMapping(const QString& json); + Mapping::Pointer loadMapping(const QString& jsonFile); + + void enableMapping(const QString& mappingName, bool enable = true); + float getValue(const Input& input) const; + + signals: + void actionEvent(int action, float state); + void hardwareChanged(); + + protected: + virtual void update(); + // GetFreeDeviceID should be called before registering a device to use an ID not used by a different device. + uint16 getFreeDeviceID() { return _nextFreeDeviceID++; } + + InputDevice::Pointer _standardController; + DevicesMap _registeredDevices; + uint16 _nextFreeDeviceID = STANDARD_DEVICE + 1; + + std::vector _actionStates = std::vector(NUM_ACTIONS, 0.0f); + std::vector _externalActionStates = std::vector(NUM_ACTIONS, 0.0f); + std::vector _actionScales = std::vector(NUM_ACTIONS, 1.0f); + std::vector _lastActionStates = std::vector(NUM_ACTIONS, 0.0f); + std::vector _poseStates = std::vector(NUM_ACTIONS); + + glm::mat4 _sensorToWorldMat; + + int recordDeviceOfType(const QString& deviceName); + QHash _deviceCounts; + + float getValue(const Endpoint::Pointer& endpoint) const; + friend class RouteBuilderProxy; + friend class MappingBuilderProxy; + Endpoint::Pointer endpointFor(const QJSValue& endpoint); + Endpoint::Pointer endpointFor(const QScriptValue& endpoint); + Endpoint::Pointer endpointFor(const Input& endpoint) const; + Endpoint::Pointer compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second); + Mapping::Pointer parseMapping(const QJsonValue& json); + Route::Pointer parseRoute(const QJsonValue& value); + Endpoint::Pointer parseEndpoint(const QJsonValue& value); + + InputToEndpointMap _endpointsByInput; + EndpointToInputMap _inputsByEndpoint; + EndpointPairMap _compositeEndpoints; + + ValueMap _overrideValues; + MappingNameMap _mappingsByName; + Mapping::Pointer _defaultMapping{ std::make_shared("Default") }; + MappingDeviceMap _mappingsByDevice; + MappingStack _activeMappings; }; - typedef std::vector< InputChannel > InputChannels; +} - // Add a bunch of input channels, return the true number of channels that successfully were added - int addInputChannels(const InputChannels& channels); - // Remove the first found instance of the input channel from the input mapper, true if found - bool removeInputChannel(InputChannel channel); - void removeAllInputChannels(); - void removeAllInputChannelsForDevice(uint16 device); - void removeDevice(int device); - //Grab all the input channels currently in use, return the number - int getInputChannels(InputChannels& channels) const; - QVector getAllInputsForDevice(uint16 device); - QVector getInputChannelsForAction(UserInputMapper::Action action); - std::multimap getActionToInputsMap() { return _actionToInputsMap; } +Q_DECLARE_METATYPE(controller::UserInputMapper::InputPair) +Q_DECLARE_METATYPE(controller::Pose) +Q_DECLARE_METATYPE(QVector) +Q_DECLARE_METATYPE(controller::Input) +Q_DECLARE_METATYPE(controller::Action) +Q_DECLARE_METATYPE(QVector) - // Update means go grab all the device input channels and update the output channel values - void update(float deltaTime); - - void setSensorToWorldMat(glm::mat4 sensorToWorldMat) { _sensorToWorldMat = sensorToWorldMat; } - glm::mat4 getSensorToWorldMat() { return _sensorToWorldMat; } - - UserInputMapper(); - - typedef std::map DevicesMap; - DevicesMap getDevices() { return _registeredDevices; } - - uint16 getStandardDeviceID() const { return STANDARD_DEVICE; } - DeviceProxy::Pointer getStandardDevice() { return _registeredDevices[getStandardDeviceID()]; } - -signals: - void actionEvent(int action, float state); - - -protected: - void registerStandardDevice(); - StandardControllerPointer _standardController; - - DevicesMap _registeredDevices; - uint16 _nextFreeDeviceID = STANDARD_DEVICE + 1; - - typedef std::map InputToMoModifiersMap; - InputToMoModifiersMap _inputToModifiersMap; - - typedef std::multimap ActionToInputsMap; - ActionToInputsMap _actionToInputsMap; - - std::vector _actionStates = std::vector(NUM_ACTIONS, 0.0f); - std::vector _externalActionStates = std::vector(NUM_ACTIONS, 0.0f); - std::vector _actionScales = std::vector(NUM_ACTIONS, 1.0f); - std::vector _lastActionStates = std::vector(NUM_ACTIONS, 0.0f); - std::vector _poseStates = std::vector(NUM_ACTIONS); - - glm::mat4 _sensorToWorldMat; - - int recordDeviceOfType(const QString& deviceName); - QHash _deviceCounts; -}; - -Q_DECLARE_METATYPE(UserInputMapper::InputPair) -Q_DECLARE_METATYPE(UserInputMapper::PoseValue) -Q_DECLARE_METATYPE(QVector) -Q_DECLARE_METATYPE(UserInputMapper::Input) -Q_DECLARE_METATYPE(UserInputMapper::InputChannel) -Q_DECLARE_METATYPE(QVector) -Q_DECLARE_METATYPE(UserInputMapper::Action) -Q_DECLARE_METATYPE(QVector) +// Cheating. +using UserInputMapper = controller::UserInputMapper; #endif // hifi_UserInputMapper_h diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp index bde10defdc..462a319a90 100644 --- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp +++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp @@ -22,7 +22,7 @@ using namespace controller; QObject* MappingBuilderProxy::from(int input) { qCDebug(controllers) << "Creating new Route builder proxy from " << input; - auto sourceEndpoint = _parent.endpointFor(UserInputMapper::Input(input)); + auto sourceEndpoint = _parent.endpointFor(Input(input)); return from(sourceEndpoint); } @@ -41,7 +41,7 @@ QObject* MappingBuilderProxy::from(const QScriptValue& source) { QObject* MappingBuilderProxy::from(const Endpoint::Pointer& source) { if (source) { auto route = Route::Pointer(new Route()); - route->_source = source; + route->source = source; return new RouteBuilderProxy(_parent, _mapping, route); } else { qCDebug(controllers) << "MappingBuilderProxy::from : source is null so no route created"; @@ -55,48 +55,8 @@ QObject* MappingBuilderProxy::makeAxis(const QJSValue& source1, const QJSValue& return from(_parent.compositeEndpointFor(source1Endpoint, source2Endpoint)); } -const QString JSON_NAME = QStringLiteral("name"); -const QString JSON_CHANNELS = QStringLiteral("channels"); -const QString JSON_CHANNEL_FROM = QStringLiteral("from"); -const QString JSON_CHANNEL_TO = QStringLiteral("to"); -const QString JSON_CHANNEL_FILTERS = QStringLiteral("filters"); - - -void MappingBuilderProxy::parse(const QJsonObject& json) { - _mapping->_name = json[JSON_NAME].toString(); - - _mapping->_channelMappings.clear(); - const auto& jsonChannels = json[JSON_CHANNELS].toArray(); - for (const auto& channelIt : jsonChannels) { - parseRoute(channelIt); - } -} - -void MappingBuilderProxy::parseRoute(const QJsonValue& json) { - if (json.isObject()) { - const auto& jsonChannel = json.toObject(); - - auto newRoute = from(jsonChannel[JSON_CHANNEL_FROM]); - if (newRoute) { - auto route = dynamic_cast(newRoute); - route->filters(jsonChannel[JSON_CHANNEL_FILTERS]); - route->to(jsonChannel[JSON_CHANNEL_TO]); - } - } -} - -QObject* MappingBuilderProxy::from(const QJsonValue& json) { - if (json.isString()) { - return from(_parent.endpointFor(_parent.inputFor(json.toString()))); - } else if (json.isObject()) { - // Endpoint is defined as an object, we expect a js function then - return nullptr; - } - return nullptr; -} - QObject* MappingBuilderProxy::enable(bool enable) { - _parent.enableMapping(_mapping->_name, enable); + _parent.enableMapping(_mapping->name, enable); return this; } diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h index 53db901436..07c1730836 100644 --- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h +++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h @@ -22,13 +22,14 @@ class QJsonValue; namespace controller { class ScriptingInterface; +class UserInputMapper; // TODO migrate functionality to a MappingBuilder class and make the proxy defer to that // (for easier use in both C++ and JS) class MappingBuilderProxy : public QObject { Q_OBJECT public: - MappingBuilderProxy(ScriptingInterface& parent, Mapping::Pointer mapping) + MappingBuilderProxy(UserInputMapper& parent, Mapping::Pointer mapping) : _parent(parent), _mapping(mapping) { } Q_INVOKABLE QObject* from(int sourceInput); @@ -39,19 +40,11 @@ public: Q_INVOKABLE QObject* enable(bool enable = true); Q_INVOKABLE QObject* disable() { return enable(false); } - - // JSON route creation point - Q_INVOKABLE QObject* from(const QJsonValue& json); - - - void parse(const QJsonObject& json); -// void serialize(QJsonObject& json); - protected: QObject* from(const Endpoint::Pointer& source); friend class RouteBuilderProxy; - ScriptingInterface& _parent; + UserInputMapper& _parent; Mapping::Pointer _mapping; diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp index ba2cd60c8b..d60032cb43 100644 --- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp +++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp @@ -22,7 +22,7 @@ namespace controller { void RouteBuilderProxy::to(int destinationInput) { qCDebug(controllers) << "Completing route " << destinationInput; - auto destinationEndpoint = _parent.endpointFor(UserInputMapper::Input(destinationInput)); + auto destinationEndpoint = _parent.endpointFor(Input(destinationInput)); return to(destinationEndpoint); } @@ -39,9 +39,9 @@ void RouteBuilderProxy::to(const QScriptValue& destination) { } void RouteBuilderProxy::to(const Endpoint::Pointer& destination) { - auto sourceEndpoint = _route->_source; - _route->_destination = destination; - _mapping->_channelMappings[sourceEndpoint].push_back(_route); + auto sourceEndpoint = _route->source; + _route->destination = destination; + _mapping->channelMappings[sourceEndpoint].push_back(_route); deleteLater(); } @@ -104,37 +104,7 @@ void RouteBuilderProxy::addFilter(Filter::Lambda lambda) { } void RouteBuilderProxy::addFilter(Filter::Pointer filter) { - _route->_filters.push_back(filter); -} - - -QObject* RouteBuilderProxy::filters(const QJsonValue& json) { - // We expect an array of objects to define the filters - if (json.isArray()) { - const auto& jsonFilters = json.toArray(); - for (auto jsonFilter : jsonFilters) { - if (jsonFilter.isObject()) { - // The filter is an object, now let s check for type and potential arguments - Filter::Pointer filter = Filter::parse(jsonFilter.toObject()); - if (filter) { - addFilter(filter); - } - } - } - } - - return this; -} - -void RouteBuilderProxy::to(const QJsonValue& json) { - if (json.isString()) { - - return to(_parent.endpointFor(_parent.inputFor(json.toString()))); - } else if (json.isObject()) { - // Endpoint is defined as an object, we expect a js function then - //return to((Endpoint*) nullptr); - } - + _route->filters.push_back(filter); } } diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h index 66b5e85394..1b66a3d996 100644 --- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h +++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h @@ -10,10 +10,11 @@ #define hifi_Controllers_Impl_RouteBuilderProxy_h #include + #include "../Filter.h" #include "../Route.h" #include "../Mapping.h" - +#include "../UserInputMapper.h" class QJSValue; class QScriptValue; class QJsonValue; @@ -27,7 +28,7 @@ class ScriptingInterface; class RouteBuilderProxy : public QObject { Q_OBJECT public: - RouteBuilderProxy(ScriptingInterface& parent, Mapping::Pointer mapping, Route::Pointer route) + RouteBuilderProxy(UserInputMapper& parent, Mapping::Pointer mapping, Route::Pointer route) : _parent(parent), _mapping(mapping), _route(route) { } Q_INVOKABLE void to(int destination); @@ -44,15 +45,11 @@ class RouteBuilderProxy : public QObject { Q_INVOKABLE QObject* constrainToInteger(); Q_INVOKABLE QObject* constrainToPositiveInteger(); - // JSON route creation point - Q_INVOKABLE QObject* filters(const QJsonValue& json); - Q_INVOKABLE void to(const QJsonValue& json); - - private: +private: void to(const Endpoint::Pointer& destination); void addFilter(Filter::Lambda lambda); void addFilter(Filter::Pointer filter); - ScriptingInterface& _parent; + UserInputMapper& _parent; Mapping::Pointer _mapping; Route::Pointer _route; }; diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index 4f2a525f07..bb90c04c95 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -1,7 +1,7 @@ set(TARGET_NAME entities-renderer) AUTOSCRIBE_SHADER_LIB(gpu model render render-utils) setup_hifi_library(Widgets Network Script) -link_hifi_libraries(shared gpu procedural model model-networking script-engine controllers render render-utils) +link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils) target_bullet() diff --git a/libraries/input-plugins/src/input-plugins/Joystick.cpp b/libraries/input-plugins/src/input-plugins/Joystick.cpp index d3e4e7a629..30074b37d3 100644 --- a/libraries/input-plugins/src/input-plugins/Joystick.cpp +++ b/libraries/input-plugins/src/input-plugins/Joystick.cpp @@ -11,16 +11,15 @@ #include "Joystick.h" -#include -#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), +Joystick::Joystick(SDL_JoystickID instanceId, SDL_GameController* sdlGameController) : + InputDevice("GamePad"), _sdlGameController(sdlGameController), _sdlJoystick(SDL_GameControllerGetJoystick(_sdlGameController)), _instanceId(instanceId) @@ -72,136 +71,63 @@ void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) { #endif +void Joystick::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) { + using namespace controller; + proxy->_name = _name; + proxy->getButton = [this](const Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); }; + proxy->getAxis = [this](const Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); }; + proxy->getAvailabeInputs = [this]() -> QVector { + QVector availableInputs{ + makePair(A, "A"), + makePair(B, "B"), + makePair(X, "X"), + makePair(Y, "Y"), + // DPad + makePair(DU, "DU"), + makePair(DD, "DD"), + makePair(DL, "DL"), + makePair(DR, "DR"), + // Bumpers + makePair(LB, "LB"), + makePair(RB, "RB"), + // Stick press + makePair(LS, "LS"), + makePair(RS, "RS"), + // Center buttons + makePair(START, "Start"), + makePair(BACK, "Back"), + // Analog sticks + makePair(LX, "LX"), + makePair(LY, "LY"), + makePair(RX, "RX"), + makePair(RY, "RY"), + + // Triggers + makePair(LT, "LT"), + makePair(RT, "RT"), -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")); - + // Aliases, PlayStation style names + makePair(LB, "L1"), + makePair(RB, "R1"), + makePair(LT, "L2"), + makePair(RT, "R2"), + makePair(LS, "L3"), + makePair(RS, "R3"), + makePair(BACK, "Select"), + makePair(A, "Cross"), + makePair(B, "Circle"), + makePair(X, "Square"), + makePair(Y, "Triangle"), + makePair(DU, "Up"), + makePair(DD, "Down"), + makePair(DL, "Left"), + makePair(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 +QString Joystick::getDefaultMappingConfig() { + static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/xbox.json"; + return MAPPING_JSON; +} diff --git a/libraries/input-plugins/src/input-plugins/Joystick.h b/libraries/input-plugins/src/input-plugins/Joystick.h index 38f00f4f15..a9ed18607c 100644 --- a/libraries/input-plugins/src/input-plugins/Joystick.h +++ b/libraries/input-plugins/src/input-plugins/Joystick.h @@ -23,7 +23,7 @@ #include #include -class Joystick : public QObject, public InputDevice { +class Joystick : public QObject, public controller::InputDevice { Q_OBJECT Q_PROPERTY(QString name READ getName) @@ -36,16 +36,16 @@ public: const QString& getName() const { return _name; } // Device functions - virtual void registerToUserInputMapper(UserInputMapper& mapper) override; - virtual void assignDefaultInputMapping(UserInputMapper& mapper) override; + virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override; + virtual QString getDefaultMappingConfig() override; virtual void update(float deltaTime, bool jointsCaptured) override; virtual void focusOutEvent() override; - Joystick() : InputDevice("Joystick") {} + Joystick() : InputDevice("GamePad") {} ~Joystick(); #ifdef HAVE_SDL2 - Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController); + Joystick(SDL_JoystickID instanceId, SDL_GameController* sdlGameController); #endif void closeJoystick(); diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp index 4703d3ae6a..f5f8b47a90 100755 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp @@ -14,6 +14,8 @@ #include #include +#include +#include const QString KeyboardMouseDevice::NAME = "Keyboard/Mouse"; @@ -128,163 +130,153 @@ void KeyboardMouseDevice::touchUpdateEvent(const QTouchEvent* event) { _lastTouch = currentPos; } -UserInputMapper::Input KeyboardMouseDevice::makeInput(Qt::Key code) { - auto shortCode = (UserInputMapper::uint16)(code & KEYBOARD_MASK); +controller::Input KeyboardMouseDevice::makeInput(Qt::Key code) { + auto shortCode = (uint16_t)(code & KEYBOARD_MASK); if (shortCode != code) { shortCode |= 0x0800; // add this bit instead of the way Qt::Key add a bit on the 3rd byte for some keys } - return UserInputMapper::Input(_deviceID, shortCode, UserInputMapper::ChannelType::BUTTON); + return controller::Input(_deviceID, shortCode, controller::ChannelType::BUTTON); } -UserInputMapper::Input KeyboardMouseDevice::makeInput(Qt::MouseButton code) { +controller::Input KeyboardMouseDevice::makeInput(Qt::MouseButton code) { switch (code) { case Qt::LeftButton: - return UserInputMapper::Input(_deviceID, MOUSE_BUTTON_LEFT, UserInputMapper::ChannelType::BUTTON); + return controller::Input(_deviceID, MOUSE_BUTTON_LEFT, controller::ChannelType::BUTTON); case Qt::RightButton: - return UserInputMapper::Input(_deviceID, MOUSE_BUTTON_RIGHT, UserInputMapper::ChannelType::BUTTON); + return controller::Input(_deviceID, MOUSE_BUTTON_RIGHT, controller::ChannelType::BUTTON); case Qt::MiddleButton: - return UserInputMapper::Input(_deviceID, MOUSE_BUTTON_MIDDLE, UserInputMapper::ChannelType::BUTTON); + return controller::Input(_deviceID, MOUSE_BUTTON_MIDDLE, controller::ChannelType::BUTTON); default: - return UserInputMapper::Input(); + return controller::Input(); }; } -UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::MouseAxisChannel axis) { - return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS); +controller::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::MouseAxisChannel axis) { + return controller::Input(_deviceID, axis, controller::ChannelType::AXIS); } -UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchAxisChannel axis) { - return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS); +controller::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchAxisChannel axis) { + return controller::Input(_deviceID, axis, controller::ChannelType::AXIS); } -UserInputMapper::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchButtonChannel button) { - return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON); +controller::Input KeyboardMouseDevice::makeInput(KeyboardMouseDevice::TouchButtonChannel button) { + return controller::Input(_deviceID, button, controller::ChannelType::BUTTON); } -void KeyboardMouseDevice::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; +void KeyboardMouseDevice::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) { + using namespace controller; + proxy->getButton = [this] (const controller::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); }; + proxy->getAxis = [this] (const controller::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); }; + proxy->getAvailabeInputs = [this] () -> QVector { + QVector availableInputs; for (int i = (int) Qt::Key_0; i <= (int) Qt::Key_9; i++) { - availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString())); + availableInputs.append(Input::NamedPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString())); } for (int i = (int) Qt::Key_A; i <= (int) Qt::Key_Z; i++) { - availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString())); + availableInputs.append(Input::NamedPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString())); } for (int i = (int) Qt::Key_Left; i <= (int) Qt::Key_Down; i++) { - availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString())); + availableInputs.append(Input::NamedPair(makeInput(Qt::Key(i)), QKeySequence(Qt::Key(i)).toString())); } - availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key_Space), QKeySequence(Qt::Key_Space).toString())); - availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key_Shift), "Shift")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key_PageUp), QKeySequence(Qt::Key_PageUp).toString())); - availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::Key_PageDown), QKeySequence(Qt::Key_PageDown).toString())); + availableInputs.append(Input::NamedPair(makeInput(Qt::Key_Space), QKeySequence(Qt::Key_Space).toString())); + availableInputs.append(Input::NamedPair(makeInput(Qt::Key_Shift), "Shift")); + availableInputs.append(Input::NamedPair(makeInput(Qt::Key_PageUp), QKeySequence(Qt::Key_PageUp).toString())); + availableInputs.append(Input::NamedPair(makeInput(Qt::Key_PageDown), QKeySequence(Qt::Key_PageDown).toString())); - availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::LeftButton), "Left Mouse Click")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::MiddleButton), "Middle Mouse Click")); - availableInputs.append(UserInputMapper::InputPair(makeInput(Qt::RightButton), "Right Mouse Click")); + availableInputs.append(Input::NamedPair(makeInput(Qt::LeftButton), "Left Mouse Click")); + availableInputs.append(Input::NamedPair(makeInput(Qt::MiddleButton), "Middle Mouse Click")); + availableInputs.append(Input::NamedPair(makeInput(Qt::RightButton), "Right Mouse Click")); - availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_X_POS), "Mouse Move Right")); - availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_X_NEG), "Mouse Move Left")); - availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_Y_POS), "Mouse Move Up")); - availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_Y_NEG), "Mouse Move Down")); + availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_X_POS), "Mouse Move Right")); + availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_X_NEG), "Mouse Move Left")); + availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_Y_POS), "Mouse Move Up")); + availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_Y_NEG), "Mouse Move Down")); - availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_WHEEL_Y_POS), "Mouse Wheel Right")); - availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_WHEEL_Y_NEG), "Mouse Wheel Left")); - availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_WHEEL_X_POS), "Mouse Wheel Up")); - availableInputs.append(UserInputMapper::InputPair(makeInput(MOUSE_AXIS_WHEEL_X_NEG), "Mouse Wheel Down")); + availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_Y_POS), "Mouse Wheel Right")); + availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_Y_NEG), "Mouse Wheel Left")); + availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_X_POS), "Mouse Wheel Up")); + availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_X_NEG), "Mouse Wheel Down")); - availableInputs.append(UserInputMapper::InputPair(makeInput(TOUCH_AXIS_X_POS), "Touchpad Right")); - availableInputs.append(UserInputMapper::InputPair(makeInput(TOUCH_AXIS_X_NEG), "Touchpad Left")); - availableInputs.append(UserInputMapper::InputPair(makeInput(TOUCH_AXIS_Y_POS), "Touchpad Up")); - availableInputs.append(UserInputMapper::InputPair(makeInput(TOUCH_AXIS_Y_NEG), "Touchpad Down")); + availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_X_POS), "Touchpad Right")); + availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_X_NEG), "Touchpad Left")); + availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_Y_POS), "Touchpad Up")); + availableInputs.append(Input::NamedPair(makeInput(TOUCH_AXIS_Y_NEG), "Touchpad Down")); return availableInputs; }; - proxy->resetDeviceBindings = [this, &mapper] () -> bool { - mapper.removeAllInputChannelsForDevice(_deviceID); - this->assignDefaultInputMapping(mapper); - return true; - }; - mapper.registerDevice(_deviceID, proxy); } -void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) { - const float BUTTON_MOVE_SPEED = 1.0f; - const float BUTTON_YAW_SPEED = 0.75f; - const float BUTTON_PITCH_SPEED = 0.5f; - const float MOUSE_YAW_SPEED = 0.5f; - const float MOUSE_PITCH_SPEED = 0.25f; - const float TOUCH_YAW_SPEED = 0.5f; - const float TOUCH_PITCH_SPEED = 0.25f; - const float BUTTON_BOOM_SPEED = 0.1f; - - // AWSD keys mapping - mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(Qt::Key_S), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(Qt::Key_W), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(Qt::Key_A), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(Qt::Key_D), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(Qt::Key_C), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(Qt::Key_E), BUTTON_MOVE_SPEED); - - mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(Qt::Key_E), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); - mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(Qt::Key_C), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_A), makeInput(Qt::RightButton), BUTTON_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::RightButton), BUTTON_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_A), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(Qt::Key_S), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(Qt::Key_W), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED); - - // Arrow keys mapping - mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(Qt::Key_Down), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(Qt::Key_Up), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(Qt::Key_Left), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(Qt::Key_Right), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(Qt::Key_PageDown), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(Qt::Key_PageUp), BUTTON_MOVE_SPEED); - - mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::RightButton), BUTTON_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::RightButton), BUTTON_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED); - - // Mouse move - mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(MOUSE_AXIS_Y_NEG), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(MOUSE_AXIS_Y_POS), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(MOUSE_AXIS_X_NEG), makeInput(Qt::RightButton), MOUSE_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(MOUSE_AXIS_X_POS), makeInput(Qt::RightButton), MOUSE_YAW_SPEED); - - -#ifdef Q_OS_MAC - // wheel event modifier on Mac collide with the touchpad scroll event - mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED); -#else - // Touch pad yaw pitch - mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED); - mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED); - - // Wheel move - mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(MOUSE_AXIS_WHEEL_Y_POS), BUTTON_BOOM_SPEED); - mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(MOUSE_AXIS_WHEEL_Y_NEG), BUTTON_BOOM_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(MOUSE_AXIS_WHEEL_X_NEG), BUTTON_YAW_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(MOUSE_AXIS_WHEEL_X_POS), BUTTON_YAW_SPEED); - -#endif - - mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(Qt::Key_Space)); - mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(Qt::Key_R)); - mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(Qt::Key_T)); +QString KeyboardMouseDevice::getDefaultMappingConfig() { + static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/keyboardMouse.json"; + return MAPPING_JSON; } +//void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) { +// const float BUTTON_MOVE_SPEED = 1.0f; +// const float BUTTON_YAW_SPEED = 0.75f; +// const float BUTTON_PITCH_SPEED = 0.5f; +// const float MOUSE_YAW_SPEED = 0.5f; +// const float MOUSE_PITCH_SPEED = 0.25f; +// const float TOUCH_YAW_SPEED = 0.5f; +// const float TOUCH_PITCH_SPEED = 0.25f; +// const float BUTTON_BOOM_SPEED = 0.1f; +// +// // AWSD keys mapping +// +// mapper.addInputChannel(controller::BOOM_IN, makeInput(Qt::Key_E), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); +// mapper.addInputChannel(controller::BOOM_OUT, makeInput(Qt::Key_C), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); +// mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(Qt::Key_A), makeInput(Qt::RightButton), BUTTON_YAW_SPEED); +// mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::RightButton), BUTTON_YAW_SPEED); +// mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(Qt::Key_A), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); +// mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); +// mapper.addInputChannel(controller::PITCH_DOWN, makeInput(Qt::Key_S), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED); +// mapper.addInputChannel(controller::PITCH_UP, makeInput(Qt::Key_W), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED); +// +// // Arrow keys mapping +// mapper.addInputChannel(controller::LONGITUDINAL_BACKWARD, makeInput(Qt::Key_Down), BUTTON_MOVE_SPEED); +// mapper.addInputChannel(controller::LONGITUDINAL_FORWARD, makeInput(Qt::Key_Up), BUTTON_MOVE_SPEED); +// mapper.addInputChannel(controller::YAW_LEFT, makeInput(Qt::Key_Left), BUTTON_MOVE_SPEED); +// mapper.addInputChannel(controller::YAW_RIGHT, makeInput(Qt::Key_Right), BUTTON_MOVE_SPEED); +// mapper.addInputChannel(controller::VERTICAL_DOWN, makeInput(Qt::Key_PageDown), BUTTON_MOVE_SPEED); +// mapper.addInputChannel(controller::VERTICAL_UP, makeInput(Qt::Key_PageUp), BUTTON_MOVE_SPEED); +// +// mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::RightButton), BUTTON_YAW_SPEED); +// mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::RightButton), BUTTON_YAW_SPEED); +// mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); +// mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); +// mapper.addInputChannel(controller::PITCH_DOWN, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED); +// mapper.addInputChannel(controller::PITCH_UP, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED); +// +// // Mouse move +// mapper.addInputChannel(controller::PITCH_DOWN, makeInput(MOUSE_AXIS_Y_NEG), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED); +// mapper.addInputChannel(controller::PITCH_UP, makeInput(MOUSE_AXIS_Y_POS), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED); +// mapper.addInputChannel(controller::YAW_LEFT, makeInput(MOUSE_AXIS_X_NEG), makeInput(Qt::RightButton), MOUSE_YAW_SPEED); +// mapper.addInputChannel(controller::YAW_RIGHT, makeInput(MOUSE_AXIS_X_POS), makeInput(Qt::RightButton), MOUSE_YAW_SPEED); +// +// +//#ifdef Q_OS_MAC +// // wheel event modifier on Mac collide with the touchpad scroll event +// mapper.addInputChannel(controller::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED); +// mapper.addInputChannel(controller::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED); +// mapper.addInputChannel(controller::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED); +// mapper.addInputChannel(controller::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED); +//#else +// // Touch pad yaw pitch +// mapper.addInputChannel(controller::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED); +// mapper.addInputChannel(controller::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED); +// mapper.addInputChannel(controller::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED); +// mapper.addInputChannel(controller::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED); +// +// // Wheel move +// mapper.addInputChannel(controller::BOOM_IN, makeInput(MOUSE_AXIS_WHEEL_Y_POS), BUTTON_BOOM_SPEED); +// mapper.addInputChannel(controller::BOOM_OUT, makeInput(MOUSE_AXIS_WHEEL_Y_NEG), BUTTON_BOOM_SPEED); +// mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(MOUSE_AXIS_WHEEL_X_NEG), BUTTON_YAW_SPEED); +// mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(MOUSE_AXIS_WHEEL_X_POS), BUTTON_YAW_SPEED); +// +//#endif +// +// mapper.addInputChannel(controller::SHIFT, makeInput(Qt::Key_Space)); +// mapper.addInputChannel(controller::ACTION1, makeInput(Qt::Key_R)); +// mapper.addInputChannel(controller::ACTION2, makeInput(Qt::Key_T)); +//} + diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h index 3c935cab26..f89d877dcd 100644 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h @@ -24,7 +24,7 @@ class QKeyEvent; class QMouseEvent; class QWheelEvent; -class KeyboardMouseDevice : public InputPlugin, public InputDevice { +class KeyboardMouseDevice : public InputPlugin, public controller::InputDevice { Q_OBJECT public: enum KeyboardChannel { @@ -72,8 +72,8 @@ public: virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override { update(deltaTime, jointsCaptured); } // Device functions - virtual void registerToUserInputMapper(UserInputMapper& mapper) override; - virtual void assignDefaultInputMapping(UserInputMapper& mapper) override; + virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override; + virtual QString getDefaultMappingConfig() override; virtual void update(float deltaTime, bool jointsCaptured) override; virtual void focusOutEvent() override; @@ -91,11 +91,11 @@ public: void wheelEvent(QWheelEvent* event); // Let's make it easy for Qt because we assume we love Qt forever - UserInputMapper::Input makeInput(Qt::Key code); - UserInputMapper::Input makeInput(Qt::MouseButton code); - UserInputMapper::Input makeInput(KeyboardMouseDevice::MouseAxisChannel axis); - UserInputMapper::Input makeInput(KeyboardMouseDevice::TouchAxisChannel axis); - UserInputMapper::Input makeInput(KeyboardMouseDevice::TouchButtonChannel button); + controller::Input makeInput(Qt::Key code); + controller::Input makeInput(Qt::MouseButton code); + controller::Input makeInput(MouseAxisChannel axis); + controller::Input makeInput(TouchAxisChannel axis); + controller::Input makeInput(TouchButtonChannel button); static const QString NAME; diff --git a/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp b/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp index 28874efdb0..b052162c77 100644 --- a/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp +++ b/libraries/input-plugins/src/input-plugins/SDL2Manager.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "SDL2Manager.h" @@ -47,11 +48,11 @@ void SDL2Manager::init() { if (controller) { SDL_JoystickID id = getInstanceId(controller); if (!_openJoysticks.contains(id)) { - Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller); + //Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller); + Joystick* joystick = new Joystick(id, controller); _openJoysticks[id] = joystick; - auto userInputMapper = DependencyManager::get(); - joystick->registerToUserInputMapper(*userInputMapper); - joystick->assignDefaultInputMapping(*userInputMapper); + auto userInputMapper = DependencyManager::get(); + userInputMapper->registerDevice(joystick); emit joystickAdded(joystick); } } @@ -92,7 +93,7 @@ void SDL2Manager::pluginFocusOutEvent() { void SDL2Manager::pluginUpdate(float deltaTime, bool jointsCaptured) { #ifdef HAVE_SDL2 if (_isInitialized) { - auto userInputMapper = DependencyManager::get(); + auto userInputMapper = DependencyManager::get(); for (auto joystick : _openJoysticks) { joystick->update(deltaTime, jointsCaptured); } @@ -124,13 +125,11 @@ void SDL2Manager::pluginUpdate(float deltaTime, bool jointsCaptured) { } else if (event.type == SDL_CONTROLLERDEVICEADDED) { SDL_GameController* controller = SDL_GameControllerOpen(event.cdevice.which); - SDL_JoystickID id = getInstanceId(controller); if (!_openJoysticks.contains(id)) { - Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller); - _openJoysticks[id] = joystick; - joystick->registerToUserInputMapper(*userInputMapper); - joystick->assignDefaultInputMapping(*userInputMapper); + // Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller); + Joystick* joystick = new Joystick(id, controller); + userInputMapper->registerDevice(joystick); emit joystickAdded(joystick); } } else if (event.type == SDL_CONTROLLERDEVICEREMOVED) { diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp index b304f260b3..eab3c03740 100644 --- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp +++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp @@ -18,10 +18,13 @@ #include #include #include +#include +#include +#include +#include -#include "NumericalConstants.h" #include "SixenseManager.h" -#include "UserActivityLogger.h" + #ifdef HAVE_SIXENSE #include "sixense.h" @@ -119,8 +122,8 @@ void SixenseManager::activate() { loadSettings(); sixenseInit(); _activated = true; - auto userInputMapper = DependencyManager::get(); - registerToUserInputMapper(*userInputMapper); + auto userInputMapper = DependencyManager::get(); + userInputMapper->registerDevice(this); #endif } @@ -171,7 +174,7 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) { (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetNumActiveControllers"); #endif - auto userInputMapper = DependencyManager::get(); + auto userInputMapper = DependencyManager::get(); if (sixenseGetNumActiveControllers() == 0) { _poseStateMap.clear(); @@ -232,7 +235,7 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) { _poseStateMap.clear(); } } else { - _poseStateMap[left ? controller::StandardPoseChannel::LEFT : controller::StandardPoseChannel::RIGHT] = UserInputMapper::PoseValue(); + _poseStateMap[left ? controller::StandardPoseChannel::LEFT : controller::StandardPoseChannel::RIGHT] = controller::Pose(); } } @@ -440,8 +443,7 @@ void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, boo // TODO: find a shortcut with fewer rotations. rotation = _avatarRotation * postOffset * glm::inverse(sixenseToHand) * rotation * preOffset * sixenseToHand; - _poseStateMap[left ? controller::StandardPoseChannel::LEFT : controller::StandardPoseChannel::RIGHT] = - UserInputMapper::PoseValue(position, rotation); + _poseStateMap[left ? controller::StandardPoseChannel::LEFT : controller::StandardPoseChannel::RIGHT] = controller::Pose(position, rotation); #endif // HAVE_SIXENSE } @@ -456,85 +458,91 @@ 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(); - 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->getPose = [this](const UserInputMapper::Input& input, int timestamp) -> UserInputMapper::PoseValue { return this->getPose(input.getChannel()); }; - using namespace controller; - proxy->getAvailabeInputs = [this]() -> QVector { - QVector availableInputs; - 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(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")); +using namespace controller; + +void SixenseManager::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) { + proxy->getButton = [this](const Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); }; + proxy->getAxis = [this](const Input& input, int timestamp) -> float { + return this->getAxis(input.getChannel()); + }; + proxy->getPose = [this](const Input& input, int timestamp) -> Pose { return this->getPose(input.getChannel()); }; + proxy->getAvailabeInputs = [this]() -> QVector { + QVector availableInputs; + availableInputs.append(Input::NamedPair(makeInput(L0), "L0")); + availableInputs.append(Input::NamedPair(makeInput(L1), "L1")); + availableInputs.append(Input::NamedPair(makeInput(L2), "L2")); + availableInputs.append(Input::NamedPair(makeInput(L3), "L3")); + availableInputs.append(Input::NamedPair(makeInput(L4), "L4")); + availableInputs.append(Input::NamedPair(makeInput(LB), "LB")); + availableInputs.append(Input::NamedPair(makeInput(LS), "LS")); + availableInputs.append(Input::NamedPair(makeInput(LX), "LX")); + availableInputs.append(Input::NamedPair(makeInput(LY), "LY")); + availableInputs.append(Input::NamedPair(makeInput(LT), "LT")); + availableInputs.append(Input::NamedPair(makeInput(R0), "R0")); + availableInputs.append(Input::NamedPair(makeInput(R1), "R1")); + availableInputs.append(Input::NamedPair(makeInput(R2), "R2")); + availableInputs.append(Input::NamedPair(makeInput(R3), "R3")); + availableInputs.append(Input::NamedPair(makeInput(R4), "R4")); + availableInputs.append(Input::NamedPair(makeInput(RB), "RB")); + availableInputs.append(Input::NamedPair(makeInput(RS), "RS")); + availableInputs.append(Input::NamedPair(makeInput(RX), "RX")); + availableInputs.append(Input::NamedPair(makeInput(RY), "RY")); + availableInputs.append(Input::NamedPair(makeInput(RT), "RT")); + availableInputs.append(Input::NamedPair(makeInput(LEFT), "LeftPose")); + availableInputs.append(Input::NamedPair(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)); +QString SixenseManager::getDefaultMappingConfig() { + static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/hydra.json"; + return MAPPING_JSON; } +// +//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 897ca72940..91cdb5f60e 100644 --- a/libraries/input-plugins/src/input-plugins/SixenseManager.h +++ b/libraries/input-plugins/src/input-plugins/SixenseManager.h @@ -42,7 +42,7 @@ const unsigned int BUTTON_TRIGGER = 1U << 8; const bool DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS = false; // Handles interaction with the Sixense SDK (e.g., Razer Hydra). -class SixenseManager : public InputPlugin, public InputDevice { +class SixenseManager : public InputPlugin, public controller::InputDevice { Q_OBJECT public: SixenseManager(); @@ -60,8 +60,8 @@ public: virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override { update(deltaTime, jointsCaptured); } // Device functions - virtual void registerToUserInputMapper(UserInputMapper& mapper) override; - virtual void assignDefaultInputMapping(UserInputMapper& mapper) override; + virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override; + virtual QString getDefaultMappingConfig() override; virtual void update(float deltaTime, bool jointsCaptured) override; virtual void focusOutEvent() override; diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index a3374cc1c0..1c8d8c2add 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -12,15 +12,19 @@ #include "ViveControllerManager.h" #include - -#include "GeometryCache.h" +#include +#include #include #include #include #include -#include "NumericalConstants.h" +#include #include -#include "UserActivityLogger.h" +#include + +#include + +#include #ifdef Q_OS_WIN extern vr::IVRSystem* _hmd; @@ -29,18 +33,6 @@ extern vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount] extern mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount]; #endif -const unsigned int LEFT_MASK = 0U; -const unsigned int RIGHT_MASK = 1U; - -const uint64_t VR_BUTTON_A = 1U << 1; -const uint64_t VR_GRIP_BUTTON = 1U << 2; -const uint64_t VR_TRACKPAD_BUTTON = 1ULL << 32; -const uint64_t VR_TRIGGER_BUTTON = 1ULL << 33; - -const unsigned int BUTTON_A = 1U << 1; -const unsigned int GRIP_BUTTON = 1U << 2; -const unsigned int TRACKPAD_BUTTON = 1U << 3; -const unsigned int TRIGGER_BUTTON = 1U << 4; const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches const QString CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b"; @@ -173,8 +165,8 @@ void ViveControllerManager::updateRendering(RenderArgs* args, render::ScenePoint //pendingChanges.updateItem(_leftHandRenderID, ); - UserInputMapper::PoseValue leftHand = _poseStateMap[makeInput(JointChannel::LEFT_HAND).getChannel()]; - UserInputMapper::PoseValue rightHand = _poseStateMap[makeInput(JointChannel::RIGHT_HAND).getChannel()]; + controller::Pose leftHand = _poseStateMap[controller::StandardPoseChannel::LEFT]; + controller::Pose rightHand = _poseStateMap[controller::StandardPoseChannel::RIGHT]; gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { auto geometryCache = DependencyManager::get(); @@ -186,21 +178,20 @@ void ViveControllerManager::updateRendering(RenderArgs* args, render::ScenePoint //batch._glBindTexture(GL_TEXTURE_2D, _uexture); if (leftHand.isValid()) { - renderHand(leftHand, batch, LEFT_HAND); + renderHand(leftHand, batch, 1); } if (rightHand.isValid()) { - renderHand(rightHand, batch, RIGHT_HAND); + renderHand(rightHand, batch, -1); } }); } } -void ViveControllerManager::renderHand(UserInputMapper::PoseValue pose, gpu::Batch& batch, int index) { - auto userInputMapper = DependencyManager::get(); +void ViveControllerManager::renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign) { + auto userInputMapper = DependencyManager::get(); Transform transform(userInputMapper->getSensorToWorldMat()); transform.postTranslate(pose.getTranslation() + pose.getRotation() * glm::vec3(0, 0, CONTROLLER_LENGTH_OFFSET)); - int sign = index == LEFT_HAND ? 1 : -1; glm::quat rotation = pose.getRotation() * glm::angleAxis(PI, glm::vec3(1.0f, 0.0f, 0.0f)) * glm::angleAxis(sign * PI_OVER_TWO, glm::vec3(0.0f, 0.0f, 1.0f)); transform.postRotate(rotation); @@ -251,6 +242,7 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) { } numTrackedControllers++; + bool left = numTrackedControllers == 1; const mat4& mat = _trackedDevicePoseMat4[device]; @@ -264,14 +256,18 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) { //qDebug() << (numTrackedControllers == 1 ? "Left: " : "Right: "); //qDebug() << "Trackpad: " << controllerState.rAxis[0].x << " " << controllerState.rAxis[0].y; //qDebug() << "Trigger: " << controllerState.rAxis[1].x << " " << controllerState.rAxis[1].y; - handleButtonEvent(controllerState.ulButtonPressed, numTrackedControllers - 1); - for (int i = 0; i < vr::k_unControllerStateAxisCount; i++) { - handleAxisEvent(Axis(i), controllerState.rAxis[i].x, controllerState.rAxis[i].y, numTrackedControllers - 1); + for (uint32_t i = 0; i < vr::k_EButton_Max; ++i) { + auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i); + bool pressed = 0 != (controllerState.ulButtonPressed & mask); + handleButtonEvent(i, pressed, left); + } + for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) { + handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, left); } } } - auto userInputMapper = DependencyManager::get(); + auto userInputMapper = DependencyManager::get(); if (numTrackedControllers == 0) { if (_deviceID != 0) { @@ -282,8 +278,7 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) { } if (_trackedControllers == 0 && numTrackedControllers > 0) { - registerToUserInputMapper(*userInputMapper); - assignDefaultInputMapping(*userInputMapper); + userInputMapper->registerDevice(this); UserActivityLogger::getInstance().connectedDevice("spatial_controller", "steamVR"); } @@ -296,33 +291,41 @@ void ViveControllerManager::focusOutEvent() { _buttonPressedMap.clear(); }; -void ViveControllerManager::handleAxisEvent(Axis axis, float x, float y, int index) { - if (axis == TRACKPAD_AXIS) { - _axisStateMap[makeInput(AXIS_Y_POS, index).getChannel()] = (y > 0.0f) ? y : 0.0f; - _axisStateMap[makeInput(AXIS_Y_NEG, index).getChannel()] = (y < 0.0f) ? -y : 0.0f; - _axisStateMap[makeInput(AXIS_X_POS, index).getChannel()] = (x > 0.0f) ? x : 0.0f; - _axisStateMap[makeInput(AXIS_X_NEG, index).getChannel()] = (x < 0.0f) ? -x : 0.0f; - } else if (axis == TRIGGER_AXIS) { - _axisStateMap[makeInput(BACK_TRIGGER, index).getChannel()] = x; +// These functions do translation from the Steam IDs to the standard controller IDs +void ViveControllerManager::handleAxisEvent(uint32_t axis, float x, float y, bool left) { +#ifdef Q_OS_WIN + using namespace controller; + if (axis == vr::k_EButton_SteamVR_Touchpad) { + _axisStateMap[left ? LX : RX] = x; + _axisStateMap[left ? LY : RY] = y; + } else if (axis == vr::k_EButton_SteamVR_Trigger) { + _axisStateMap[left ? LT : RT] = x; } +#endif } -void ViveControllerManager::handleButtonEvent(uint64_t buttons, int index) { - if (buttons & VR_BUTTON_A) { - _buttonPressedMap.insert(makeInput(BUTTON_A, index).getChannel()); +// These functions do translation from the Steam IDs to the standard controller IDs +void ViveControllerManager::handleButtonEvent(uint32_t button, bool pressed, bool left) { +#ifdef Q_OS_WIN + if (!pressed) { + return; } - if (buttons & VR_GRIP_BUTTON) { - _buttonPressedMap.insert(makeInput(GRIP_BUTTON, index).getChannel()); - } - if (buttons & VR_TRACKPAD_BUTTON) { - _buttonPressedMap.insert(makeInput(TRACKPAD_BUTTON, index).getChannel()); - } - if (buttons & VR_TRIGGER_BUTTON) { - _buttonPressedMap.insert(makeInput(TRIGGER_BUTTON, index).getChannel()); + + if (button == vr::k_EButton_ApplicationMenu) { + // FIXME? + _buttonPressedMap.insert(left ? controller::A : controller::A); + } else if (button == vr::k_EButton_Grip) { + // Tony says these are harder to reach, so make them the meta buttons + _buttonPressedMap.insert(left ? controller::BACK : controller::START); + } else if (button == vr::k_EButton_SteamVR_Trigger) { + _buttonPressedMap.insert(left ? controller::LB : controller::RB); + } else if (button == vr::k_EButton_SteamVR_Touchpad) { + _buttonPressedMap.insert(left ? controller::LS : controller::RS); } +#endif } -void ViveControllerManager::handlePoseEvent(const mat4& mat, int index) { +void ViveControllerManager::handlePoseEvent(const mat4& mat, bool left) { glm::vec3 position = extractTranslation(mat); glm::quat rotation = glm::quat_cast(mat); @@ -378,7 +381,7 @@ void ViveControllerManager::handlePoseEvent(const mat4& mat, int index) { const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - float sign = (index == LEFT_HAND) ? -1.0f : 1.0f; + float sign = left ? -1.0f : 1.0f; const glm::quat signedQuaterZ = glm::angleAxis(sign * PI / 2.0f, glm::vec3(0.0f, 0.0f, 1.0f)); const glm::quat eighthX = glm::angleAxis(PI / 4.0f, glm::vec3(1.0f, 0.0f, 0.0f)); const glm::quat offset = glm::inverse(signedQuaterZ * eighthX); @@ -386,92 +389,93 @@ void ViveControllerManager::handlePoseEvent(const mat4& mat, int index) { position += rotation * glm::vec3(0, 0, -CONTROLLER_LENGTH_OFFSET); - _poseStateMap[makeInput(JointChannel(index)).getChannel()] = UserInputMapper::PoseValue(position, rotation); + _poseStateMap[left ? controller::LEFT : controller::RIGHT] = controller::Pose(position, rotation); } -void ViveControllerManager::registerToUserInputMapper(UserInputMapper& mapper) { - // Grab the current free device ID - _deviceID = mapper.getFreeDeviceID(); - - auto proxy = UserInputMapper::DeviceProxy::Pointer(new UserInputMapper::DeviceProxy(_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->getPose = [this](const UserInputMapper::Input& input, int timestamp) -> UserInputMapper::PoseValue { return this->getPose(input.getChannel()); }; - proxy->getAvailabeInputs = [this] () -> QVector { - QVector availableInputs; - availableInputs.append(UserInputMapper::InputPair(makeInput(LEFT_HAND), "Left Hand")); - - availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_A, 0), "Left Button A")); - availableInputs.append(UserInputMapper::InputPair(makeInput(GRIP_BUTTON, 0), "Left Grip Button")); - availableInputs.append(UserInputMapper::InputPair(makeInput(TRACKPAD_BUTTON, 0), "Left Trackpad Button")); - availableInputs.append(UserInputMapper::InputPair(makeInput(TRIGGER_BUTTON, 0), "Left Trigger Button")); +void ViveControllerManager::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) { + using namespace controller; + proxy->_name = _name; + proxy->getButton = [this](const Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); }; + proxy->getAxis = [this](const Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); }; + proxy->getPose = [this](const Input& input, int timestamp) -> Pose { return this->getPose(input.getChannel()); }; + proxy->getAvailabeInputs = [this]() -> QVector { + QVector availableInputs{ + // Trackpad analogs + makePair(LX, "LX"), + makePair(LY, "LY"), + makePair(RX, "RX"), + makePair(RY, "RY"), + // trigger analogs + makePair(LT, "LT"), + makePair(RT, "RT"), - availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_Y_POS, 0), "Left Trackpad Up")); - availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_Y_NEG, 0), "Left Trackpad Down")); - availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_X_POS, 0), "Left Trackpad Right")); - availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_X_NEG, 0), "Left Trackpad Left")); - availableInputs.append(UserInputMapper::InputPair(makeInput(BACK_TRIGGER, 0), "Left Back Trigger")); + makePair(LB, "LB"), + makePair(RB, "RB"), - - availableInputs.append(UserInputMapper::InputPair(makeInput(RIGHT_HAND), "Right Hand")); + makePair(LS, "LS"), + makePair(RS, "RS"), + }; - availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_A, 1), "Right Button A")); - availableInputs.append(UserInputMapper::InputPair(makeInput(GRIP_BUTTON, 1), "Right Grip Button")); - availableInputs.append(UserInputMapper::InputPair(makeInput(TRACKPAD_BUTTON, 1), "Right Trackpad Button")); - availableInputs.append(UserInputMapper::InputPair(makeInput(TRIGGER_BUTTON, 1), "Right Trigger Button")); + //availableInputs.append(Input::NamedPair(makeInput(LEFT_HAND), "Left Hand")); + + //availableInputs.append(Input::NamedPair(makeInput(BUTTON_A, 0), "Left Button A")); + //availableInputs.append(Input::NamedPair(makeInput(GRIP_BUTTON, 0), "Left Grip Button")); + //availableInputs.append(Input::NamedPair(makeInput(TRACKPAD_BUTTON, 0), "Left Trackpad Button")); + //availableInputs.append(Input::NamedPair(makeInput(TRIGGER_BUTTON, 0), "Left Trigger Button")); + + //availableInputs.append(Input::NamedPair(makeInput(AXIS_Y_POS, 0), "Left Trackpad Up")); + //availableInputs.append(Input::NamedPair(makeInput(AXIS_Y_NEG, 0), "Left Trackpad Down")); + //availableInputs.append(Input::NamedPair(makeInput(AXIS_X_POS, 0), "Left Trackpad Right")); + //availableInputs.append(Input::NamedPair(makeInput(AXIS_X_NEG, 0), "Left Trackpad Left")); + //availableInputs.append(Input::NamedPair(makeInput(BACK_TRIGGER, 0), "Left Back Trigger")); + + + //availableInputs.append(Input::NamedPair(makeInput(RIGHT_HAND), "Right Hand")); + + //availableInputs.append(Input::NamedPair(makeInput(BUTTON_A, 1), "Right Button A")); + //availableInputs.append(Input::NamedPair(makeInput(GRIP_BUTTON, 1), "Right Grip Button")); + //availableInputs.append(Input::NamedPair(makeInput(TRACKPAD_BUTTON, 1), "Right Trackpad Button")); + //availableInputs.append(Input::NamedPair(makeInput(TRIGGER_BUTTON, 1), "Right Trigger Button")); + + //availableInputs.append(Input::NamedPair(makeInput(AXIS_Y_POS, 1), "Right Trackpad Up")); + //availableInputs.append(Input::NamedPair(makeInput(AXIS_Y_NEG, 1), "Right Trackpad Down")); + //availableInputs.append(Input::NamedPair(makeInput(AXIS_X_POS, 1), "Right Trackpad Right")); + //availableInputs.append(Input::NamedPair(makeInput(AXIS_X_NEG, 1), "Right Trackpad Left")); + //availableInputs.append(Input::NamedPair(makeInput(BACK_TRIGGER, 1), "Right Back Trigger")); - availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_Y_POS, 1), "Right Trackpad Up")); - availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_Y_NEG, 1), "Right Trackpad Down")); - availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_X_POS, 1), "Right Trackpad Right")); - availableInputs.append(UserInputMapper::InputPair(makeInput(AXIS_X_NEG, 1), "Right Trackpad Left")); - availableInputs.append(UserInputMapper::InputPair(makeInput(BACK_TRIGGER, 1), "Right Back Trigger")); - return availableInputs; }; - proxy->resetDeviceBindings = [this, &mapper] () -> bool { - mapper.removeAllInputChannelsForDevice(_deviceID); - this->assignDefaultInputMapping(mapper); - return true; - }; - mapper.registerDevice(_deviceID, proxy); } -void ViveControllerManager::assignDefaultInputMapping(UserInputMapper& mapper) { - const float JOYSTICK_MOVE_SPEED = 1.0f; - - // Left Trackpad: Movement, strafing - mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(AXIS_Y_POS, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(AXIS_Y_NEG, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(AXIS_X_POS, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(AXIS_X_NEG, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED); - - // Right Trackpad: Vertical movement, zooming - mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(AXIS_Y_POS, 1), makeInput(TRACKPAD_BUTTON, 1), JOYSTICK_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(AXIS_Y_NEG, 1), makeInput(TRACKPAD_BUTTON, 1), JOYSTICK_MOVE_SPEED); - - // Buttons - mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_A, 0)); - mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_A, 1)); - - mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(GRIP_BUTTON, 0)); - mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(GRIP_BUTTON, 1)); - - mapper.addInputChannel(UserInputMapper::LEFT_HAND_CLICK, makeInput(BACK_TRIGGER, 0)); - mapper.addInputChannel(UserInputMapper::RIGHT_HAND_CLICK, makeInput(BACK_TRIGGER, 1)); - - // Hands - mapper.addInputChannel(UserInputMapper::LEFT_HAND, makeInput(LEFT_HAND)); - mapper.addInputChannel(UserInputMapper::RIGHT_HAND, makeInput(RIGHT_HAND)); +QString ViveControllerManager::getDefaultMappingConfig() { + static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/vive.json"; + return MAPPING_JSON; } -UserInputMapper::Input ViveControllerManager::makeInput(unsigned int button, int index) { - return UserInputMapper::Input(_deviceID, button | (index == 0 ? LEFT_MASK : RIGHT_MASK), UserInputMapper::ChannelType::BUTTON); -} - -UserInputMapper::Input ViveControllerManager::makeInput(ViveControllerManager::JoystickAxisChannel axis, int index) { - return UserInputMapper::Input(_deviceID, axis | (index == 0 ? LEFT_MASK : RIGHT_MASK), UserInputMapper::ChannelType::AXIS); -} - -UserInputMapper::Input ViveControllerManager::makeInput(JointChannel joint) { - return UserInputMapper::Input(_deviceID, joint, UserInputMapper::ChannelType::POSE); -} +//void ViveControllerManager::assignDefaultInputMapping(UserInputMapper& mapper) { +// const float JOYSTICK_MOVE_SPEED = 1.0f; +// +// // Left Trackpad: Movement, strafing +// mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(AXIS_Y_POS, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED); +// mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(AXIS_Y_NEG, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED); +// mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(AXIS_X_POS, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED); +// mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(AXIS_X_NEG, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED); +// +// // Right Trackpad: Vertical movement, zooming +// mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(AXIS_Y_POS, 1), makeInput(TRACKPAD_BUTTON, 1), JOYSTICK_MOVE_SPEED); +// mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(AXIS_Y_NEG, 1), makeInput(TRACKPAD_BUTTON, 1), JOYSTICK_MOVE_SPEED); +// +// // Buttons +// mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_A, 0)); +// mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_A, 1)); +// +// mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(GRIP_BUTTON, 0)); +// mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(GRIP_BUTTON, 1)); +// +// mapper.addInputChannel(UserInputMapper::LEFT_HAND_CLICK, makeInput(BACK_TRIGGER, 0)); +// mapper.addInputChannel(UserInputMapper::RIGHT_HAND_CLICK, makeInput(BACK_TRIGGER, 1)); +// +// // Hands +// mapper.addInputChannel(UserInputMapper::LEFT_HAND, makeInput(LEFT_HAND)); +// mapper.addInputChannel(UserInputMapper::RIGHT_HAND, makeInput(RIGHT_HAND)); +//} diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h index bcc27d07ae..67ad75c9e8 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h @@ -24,30 +24,9 @@ #include #include -class ViveControllerManager : public InputPlugin, public InputDevice { +class ViveControllerManager : public InputPlugin, public controller::InputDevice { Q_OBJECT public: - enum JoystickAxisChannel { - AXIS_Y_POS = 1U << 1, - AXIS_Y_NEG = 1U << 2, - AXIS_X_POS = 1U << 3, - AXIS_X_NEG = 1U << 4, - BACK_TRIGGER = 1U << 5, - }; - - enum Axis { - TRACKPAD_AXIS = 0, - TRIGGER_AXIS, - AXIS_2, - AXIS_3, - AXIS_4, - }; - - enum JointChannel { - LEFT_HAND = 0, - RIGHT_HAND, - }; - ViveControllerManager(); // Plugin functions @@ -62,8 +41,8 @@ public: virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override { update(deltaTime, jointsCaptured); } // Device functions - virtual void registerToUserInputMapper(UserInputMapper& mapper) override; - virtual void assignDefaultInputMapping(UserInputMapper& mapper) override; + virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override; + virtual QString getDefaultMappingConfig() override; virtual void update(float deltaTime, bool jointsCaptured) override; virtual void focusOutEvent() override; @@ -71,16 +50,12 @@ public: void setRenderControllers(bool renderControllers) { _renderControllers = renderControllers; } - UserInputMapper::Input makeInput(unsigned int button, int index); - UserInputMapper::Input makeInput(JoystickAxisChannel axis, int index); - UserInputMapper::Input makeInput(JointChannel joint); - private: - void renderHand(UserInputMapper::PoseValue pose, gpu::Batch& batch, int index); + void renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign); - void handleButtonEvent(uint64_t buttons, int index); - void handleAxisEvent(Axis axis, float x, float y, int index); - void handlePoseEvent(const mat4& mat, int index); + void handleButtonEvent(uint32_t button, bool pressed, bool left); + void handleAxisEvent(uint32_t axis, float x, float y, bool left); + void handlePoseEvent(const mat4& mat, bool left); int _trackedControllers; diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index dc08fd7a69..40de50b153 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -28,7 +28,9 @@ #include #include -#include "AnimationObject.h" +#include +#include + #include "ArrayBufferViewClass.h" #include "BatchLoader.h" #include "DataViewClass.h" diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 5a0fb64ae2..9cf1bf1e18 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -26,8 +26,6 @@ #include #include #include -#include - #include "MouseEvent.h" #include "ArrayBufferClass.h" diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp index eb080700fa..bc0ad179ef 100644 --- a/tests/controllers/src/main.cpp +++ b/tests/controllers/src/main.cpp @@ -123,20 +123,20 @@ int main(int argc, char** argv) { inputPlugin->pluginUpdate(delta, false); } - auto userInputMapper = DependencyManager::get(); + auto userInputMapper = DependencyManager::get(); userInputMapper->update(delta); }); timer.start(50); { - DependencyManager::set(); + DependencyManager::set(); foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { QString name = inputPlugin->getName(); inputPlugin->activate(); - auto userInputMapper = DependencyManager::get(); + auto userInputMapper = DependencyManager::get(); if (name == KeyboardMouseDevice::NAME) { auto keyboardMouseDevice = static_cast(inputPlugin.data()); // TODO: this seems super hacky - keyboardMouseDevice->registerToUserInputMapper(*userInputMapper); + userInputMapper->registerDevice(keyboardMouseDevice); } inputPlugin->pluginUpdate(0, false); }