From 3526e14e66e1d1640918cd2d3d830292bd9958ac Mon Sep 17 00:00:00 2001 From: Malin E Date: Thu, 4 Nov 2021 13:19:43 +0100 Subject: [PATCH] Add support for several joysticks at the smae time --- .../interaction/joystickcamerastates.h | 58 ++-- .../interaction/joystickinputstate.h | 13 +- .../openspace/navigation/navigationhandler.h | 19 +- modules/imgui/src/guijoystickcomponent.cpp | 7 +- src/interaction/joystickcamerastates.cpp | 266 +++++++++++++----- src/interaction/joystickinputstate.cpp | 76 +++-- src/navigation/navigationhandler.cpp | 35 ++- src/navigation/navigationhandler_lua.inl | 51 ++-- 8 files changed, 359 insertions(+), 166 deletions(-) diff --git a/include/openspace/interaction/joystickcamerastates.h b/include/openspace/interaction/joystickcamerastates.h index ae0a3b0035..2ac5aa2f71 100644 --- a/include/openspace/interaction/joystickcamerastates.h +++ b/include/openspace/interaction/joystickcamerastates.h @@ -77,43 +77,55 @@ public: void updateStateFromInput( const JoystickInputStates& joystickInputStates, double deltaTime); - void setAxisMapping(int axis, AxisType mapping, + void setAxisMapping(const std::string& joystickName, int axis, AxisType mapping, AxisInvert shouldInvert = AxisInvert::No, AxisNormalize shouldNormalize = AxisNormalize::No, bool isSticky = false, double sensitivity = 0.0 ); - AxisInformation axisMapping(int axis) const; + AxisInformation axisMapping(const std::string& joystickName, int axis) const; - void setDeadzone(int axis, float deadzone); - float deadzone(int axis) const; + void setDeadzone(const std::string& joystickName, int axis, float deadzone); + float deadzone(const std::string& joystickName, int axis) const; - - void bindButtonCommand(int button, std::string command, JoystickAction action, - ButtonCommandRemote remote, std::string documentation); - void clearButtonCommand(int button); - std::vector buttonCommand(int button) const; + void bindButtonCommand(const std::string& joystickName, int button, + std::string command, JoystickAction action, ButtonCommandRemote remote, + std::string documentation); + void clearButtonCommand(const std::string& joystickName, int button); + std::vector buttonCommand(const std::string& joystickName, + int button) const; private: - // We use an array for the axes and a map for the buttons since the axis are going to - // be accessed much more often and thus have to be more efficient. And storing a few - // extra AxisInformation that are not used will not matter that much; finding an axis - // location in a potential map each frame, however, would + struct JoystickCameraState { + std::string joystickName; - std::array _axisMapping; + // We use an array for the axes and a map for the buttons since the axis are going to + // be accessed much more often and thus have to be more efficient. And storing a few + // extra AxisInformation that are not used will not matter that much; finding an axis + // location in a potential map each frame, however, would - // This array is used to store the old axis values from the previous frame, - // it is used to calculate the difference in the values in the case of a sticky axis - std::array _prevAxisValues; + std::array axisMapping; - struct ButtonInformation { - std::string command; - JoystickAction action; - ButtonCommandRemote synchronization; - std::string documentation; + // This array is used to store the old axis values from the previous frame, + // it is used to calculate the difference in the values in the case of a sticky axis + std::array prevAxisValues; + + struct ButtonInformation { + std::string command; + JoystickAction action; + ButtonCommandRemote synchronization; + std::string documentation; + }; + + std::multimap buttonMapping; }; - std::multimap _buttonMapping; + std::vector _joystickCameraStates; + + // Find the item in _joystickCameraStates that corresponds to the given joystickName + // return a pointer to the item, if not found then return nullptr + JoystickCameraState* getJoystickCameraState(const std::string& joystickName); + const JoystickCameraState* getJoystickCameraState(const std::string& joystickName) const; }; } // namespace openspace::interaction diff --git a/include/openspace/interaction/joystickinputstate.h b/include/openspace/interaction/joystickinputstate.h index e256f39552..adcfc028c3 100644 --- a/include/openspace/interaction/joystickinputstate.h +++ b/include/openspace/interaction/joystickinputstate.h @@ -72,11 +72,6 @@ struct JoystickInputState { /// \c nAxes values are defined values, the rest are undefined std::array axes; - /// The axis values can either go back to 0 when the joystick is released or it can - /// stay at the value it was before the joystick was released. - /// The latter is called a sticky axis, when the values don't go back to 0. - bool isSticky = false; - /// The number of buttons that this joystick possesses int nButtons = 0; /// The status of each button. Only the first \c nButtons values are defined, the rest @@ -88,6 +83,10 @@ struct JoystickInputState { /// derived from the available GLFW constants constexpr const int MaxJoysticks = 16; struct JoystickInputStates : public std::array { + /// The maximum number of joysticks that are supported by this system. This number is + /// derived from the available GLFW constants + static constexpr const int MaxNumJoysticks = 16; + /** * This function adds the contributions of all connected joysticks for the provided * \p axis. After adding each joysticks contribution, the result is clamped to [-1,1]. @@ -99,7 +98,7 @@ struct JoystickInputStates : public std::array * * \pre \p axis must be 0 or positive */ - float axis(int axis) const; + float axis(const std::string& joystickName, int axis) const; /** * This functions checks whether any connected joystick has its \p button in the @@ -113,7 +112,7 @@ struct JoystickInputStates : public std::array * * \pre \p button must be 0 or positive */ - bool button(int button, JoystickAction action) const; + bool button(const std::string& joystickName, int button, JoystickAction action) const; }; } // namespace openspace::interaction diff --git a/include/openspace/navigation/navigationhandler.h b/include/openspace/navigation/navigationhandler.h index 8cdee66abb..5fa4c105b4 100644 --- a/include/openspace/navigation/navigationhandler.h +++ b/include/openspace/navigation/navigationhandler.h @@ -98,7 +98,8 @@ public: void mousePositionCallback(double x, double y); void mouseScrollWheelCallback(double pos); - void setJoystickAxisMapping(int axis, JoystickCameraStates::AxisType mapping, + void setJoystickAxisMapping(const std::string& joystickName, + int axis, JoystickCameraStates::AxisType mapping, JoystickCameraStates::AxisInvert shouldInvert = JoystickCameraStates::AxisInvert::No, JoystickCameraStates::AxisNormalize shouldNormalize = @@ -106,16 +107,20 @@ public: bool isSticky = false, double sensitivity = 0.0 ); - JoystickCameraStates::AxisInformation joystickAxisMapping(int axis) const; + JoystickCameraStates::AxisInformation joystickAxisMapping( + const std::string& joystickName, int axis) const; - void setJoystickAxisDeadzone(int axis, float deadzone); - float joystickAxisDeadzone(int axis) const; + void setJoystickAxisDeadzone(const std::string& joystickName, int axis, + float deadzone); + float joystickAxisDeadzone(const std::string& joystickName, int axis) const; - void bindJoystickButtonCommand(int button, std::string command, JoystickAction action, + void bindJoystickButtonCommand(const std::string& joystickName, int button, + std::string command, JoystickAction action, JoystickCameraStates::ButtonCommandRemote remote, std::string documentation); - void clearJoystickButtonCommand(int button); - std::vector joystickButtonCommand(int button) const; + void clearJoystickButtonCommand(const std::string& joystickName, int button); + std::vector joystickButtonCommand(const std::string& joystickName, + int button) const; // Websockets void setWebsocketAxisMapping(int axis, WebsocketCameraStates::AxisType mapping, diff --git a/modules/imgui/src/guijoystickcomponent.cpp b/modules/imgui/src/guijoystickcomponent.cpp index b63fdb5ac4..2654d3a78d 100644 --- a/modules/imgui/src/guijoystickcomponent.cpp +++ b/modules/imgui/src/guijoystickcomponent.cpp @@ -26,7 +26,6 @@ #include #include -#include #include namespace { @@ -86,7 +85,7 @@ void GuiJoystickComponent::render() { ImGui::Text("%s", "Summed contributions"); ImGui::Text("%s", "Axes"); for (int i = 0; i < JoystickInputState::MaxAxes; ++i) { - float f = global::joystickInputStates->axis(i); + float f = global::joystickInputStates->axis("", i); ImGui::SliderFloat( std::to_string(i).c_str(), &f, @@ -98,8 +97,8 @@ void GuiJoystickComponent::render() { for (int i = 0; i < JoystickInputState::MaxButtons; ++i) { ImGui::RadioButton( std::to_string(i).c_str(), - global::joystickInputStates->button(i, JoystickAction::Press) || - global::joystickInputStates->button(i, JoystickAction::Repeat) + global::joystickInputStates->button("", i, JoystickAction::Press) || + global::joystickInputStates->button("", i, JoystickAction::Repeat) ); } diff --git a/src/interaction/joystickcamerastates.cpp b/src/interaction/joystickcamerastates.cpp index 6e3c6de8f9..2eadf18a61 100644 --- a/src/interaction/joystickcamerastates.cpp +++ b/src/interaction/joystickcamerastates.cpp @@ -26,10 +26,15 @@ #include #include +#include #include #include #include +namespace { + constexpr const char* _loggerCat = "JoystickCameraStates"; +} // namespace + namespace openspace::interaction { JoystickCameraStates::JoystickCameraStates(double sensitivity, double velocityScaleFactor) @@ -46,49 +51,61 @@ void JoystickCameraStates::updateStateFromInput( std::pair globalRoll = { false, glm::dvec2(0.0) }; std::pair localRotation = { false, glm::dvec2(0.0) }; - for (int i = 0; i < JoystickInputState::MaxAxes; ++i) { - AxisInformation t = _axisMapping[i]; - if (t.type == AxisType::None) { + for (const JoystickInputState& joystickInputState : joystickInputStates) { + if (joystickInputState.name.empty()) { continue; } - float rawValue = joystickInputStates.axis(i); - float value = rawValue; + JoystickCameraState* joystickCameraState = + getJoystickCameraState(joystickInputState.name); - if (t.isSticky) { - value = rawValue - _prevAxisValues[i]; - _prevAxisValues[i] = rawValue; - } - - if (std::fabs(value) <= t.deadzone) { + if (!joystickCameraState) { continue; } - if (t.normalize) { - value = (value + 1.f) / 2.f; - } + for (int i = 0; i < JoystickInputState::MaxAxes; ++i) { + AxisInformation t = joystickCameraState->axisMapping[i]; + if (t.type == AxisType::None) { + continue; + } - if (t.invert) { - value *= -1.f; - } + float rawValue = joystickInputStates.axis(joystickInputState.name, i); + float value = rawValue; - if (std::abs(t.sensitivity) > std::numeric_limits::epsilon()) { - value = static_cast(value * t.sensitivity * _sensitivity); - } - else { - value = static_cast(value * _sensitivity); - } + if (t.isSticky) { + value = rawValue - joystickCameraState->prevAxisValues[i]; + joystickCameraState->prevAxisValues[i] = rawValue; + } - switch (t.type) { + if (std::fabs(value) <= t.deadzone) { + continue; + } + + if (t.normalize) { + value = (value + 1.f) / 2.f; + } + + if (t.invert) { + value *= -1.f; + } + + if (std::abs(t.sensitivity) > std::numeric_limits::epsilon()) { + value = static_cast(value * t.sensitivity * _sensitivity); + } + else { + value = static_cast(value * _sensitivity); + } + + switch (t.type) { case AxisType::None: break; case AxisType::OrbitX: globalRotation.first = true; - globalRotation.second.x = value; + globalRotation.second.x += value; break; case AxisType::OrbitY: globalRotation.first = true; - globalRotation.second.y = value; + globalRotation.second.y += value; break; case AxisType::Zoom: case AxisType::ZoomIn: @@ -101,28 +118,47 @@ void JoystickCameraStates::updateStateFromInput( break; case AxisType::LocalRollX: localRoll.first = true; - localRoll.second.x = value; + localRoll.second.x += value; break; case AxisType::LocalRollY: localRoll.first = true; - localRoll.second.y = value; + localRoll.second.y += value; break; case AxisType::GlobalRollX: globalRoll.first = true; - globalRoll.second.x = value; + globalRoll.second.x += value; break; case AxisType::GlobalRollY: globalRoll.first = true; - globalRoll.second.y = value; + globalRoll.second.y += value; break; case AxisType::PanX: localRotation.first = true; - localRotation.second.x = value; + localRotation.second.x += value; break; case AxisType::PanY: localRotation.first = true; - localRotation.second.y = value; + localRotation.second.y += value; break; + } + } + + for (int i = 0; i < JoystickInputState::MaxButtons; ++i) { + auto itRange = joystickCameraState->buttonMapping.equal_range(i); + for (auto it = itRange.first; it != itRange.second; ++it) { + bool active =global::joystickInputStates->button( + joystickInputState.name, + i, + it->second.action + ); + + if (active) { + global::scriptEngine->queueScript( + it->second.command, + scripting::ScriptEngine::RemoteScripting(it->second.synchronization) + ); + } + } } } @@ -160,23 +196,10 @@ void JoystickCameraStates::updateStateFromInput( else { _localRotationState.velocity.decelerate(deltaTime); } - - for (int i = 0; i < JoystickInputState::MaxButtons; ++i) { - auto itRange = _buttonMapping.equal_range(i); - for (auto it = itRange.first; it != itRange.second; ++it) { - bool active = global::joystickInputStates->button(i, it->second.action); - - if (active) { - global::scriptEngine->queueScript( - it->second.command, - scripting::ScriptEngine::RemoteScripting(it->second.synchronization) - ); - } - } - } } -void JoystickCameraStates::setAxisMapping(int axis, AxisType mapping, +void JoystickCameraStates::setAxisMapping(const std::string& joystickName, + int axis, AxisType mapping, AxisInvert shouldInvert, AxisNormalize shouldNormalize, bool isSticky, @@ -184,48 +207,119 @@ void JoystickCameraStates::setAxisMapping(int axis, AxisType mapping, { ghoul_assert(axis < JoystickInputState::MaxAxes, "axis must be < MaxAxes"); - _axisMapping[axis].type = mapping; - _axisMapping[axis].invert = shouldInvert; - _axisMapping[axis].normalize = shouldNormalize; - _axisMapping[axis].isSticky = isSticky; - _axisMapping[axis].sensitivity = sensitivity; - - if (isSticky) { - global::joystickInputStates->at(axis).isSticky = true; + JoystickCameraState* joystickCameraState = getJoystickCameraState(joystickName); + if (!joystickCameraState) { + if (_joystickCameraStates.size() < JoystickInputStates::MaxNumJoysticks) { + _joystickCameraStates.push_back(JoystickCameraState()); + joystickCameraState = &_joystickCameraStates.back(); + joystickCameraState->joystickName = joystickName; + } + else { + LWARNING(fmt::format("Cannot add more joysticks, only {} joysticks are " + "supported", JoystickInputStates::MaxNumJoysticks)); + return; + } } - _prevAxisValues[axis] = global::joystickInputStates->axis(axis); + joystickCameraState->axisMapping[axis].type = mapping; + joystickCameraState->axisMapping[axis].invert = shouldInvert; + joystickCameraState->axisMapping[axis].normalize = shouldNormalize; + joystickCameraState->axisMapping[axis].isSticky = isSticky; + joystickCameraState->axisMapping[axis].sensitivity = sensitivity; + + joystickCameraState->prevAxisValues[axis] = + global::joystickInputStates->axis(joystickName, axis); } -JoystickCameraStates::AxisInformation JoystickCameraStates::axisMapping(int axis) const { - return _axisMapping[axis]; +JoystickCameraStates::AxisInformation JoystickCameraStates::axisMapping( + const std::string& joystickName, + int axis) const +{ + const JoystickCameraState* joystickCameraState = getJoystickCameraState(joystickName); + if (!joystickCameraState) { + LWARNING(fmt::format("Cannot find JoystickCameraState with name '{}' " + "(axisMapping)", joystickName)); + JoystickCameraStates::AxisInformation dummy; + return dummy; + } + + return joystickCameraState->axisMapping[axis]; } -void JoystickCameraStates::setDeadzone(int axis, float deadzone) { - _axisMapping[axis].deadzone = deadzone; +void JoystickCameraStates::setDeadzone(const std::string& joystickName, int axis, + float deadzone) +{ + JoystickCameraState* joystickCameraState = getJoystickCameraState(joystickName); + if (!joystickCameraState) { + if (_joystickCameraStates.size() < JoystickInputStates::MaxNumJoysticks) { + _joystickCameraStates.push_back(JoystickCameraState()); + joystickCameraState = &_joystickCameraStates.back(); + joystickCameraState->joystickName = joystickName; + } + else { + LWARNING(fmt::format("Cannot add more joysticks, only {} joysticks are " + "supported", JoystickInputStates::MaxNumJoysticks)); + return; + } + } + + joystickCameraState->axisMapping[axis].deadzone = deadzone; } -float JoystickCameraStates::deadzone(int axis) const { - return _axisMapping[axis].deadzone; +float JoystickCameraStates::deadzone(const std::string& joystickName, int axis) const { + const JoystickCameraState* joystickCameraState = getJoystickCameraState(joystickName); + if (!joystickCameraState) { + LWARNING(fmt::format("Cannot find JoystickCameraState with name '{}' (deadzone)", + joystickName)); + return 0.0f; + } + + return joystickCameraState->axisMapping[axis].deadzone; } -void JoystickCameraStates::bindButtonCommand(int button, std::string command, +void JoystickCameraStates::bindButtonCommand(const std::string& joystickName, + int button, std::string command, JoystickAction action, ButtonCommandRemote remote, std::string documentation) { - _buttonMapping.insert({ + JoystickCameraState* joystickCameraState = getJoystickCameraState(joystickName); + if (!joystickCameraState) { + if (_joystickCameraStates.size() < JoystickInputStates::MaxNumJoysticks) { + _joystickCameraStates.push_back(JoystickCameraState()); + joystickCameraState = &_joystickCameraStates.back(); + joystickCameraState->joystickName = joystickName; + } + else { + LWARNING(fmt::format("Cannot add more joysticks, only {} joysticks are " + "supported", JoystickInputStates::MaxNumJoysticks)); + return; + } + } + + joystickCameraState->buttonMapping.insert({ button, { std::move(command), action, remote, std::move(documentation) } }); } -void JoystickCameraStates::clearButtonCommand(int button) { - for (auto it = _buttonMapping.begin(); it != _buttonMapping.end();) { +void JoystickCameraStates::clearButtonCommand(const std::string& joystickName, + int button) +{ + JoystickCameraState* joystickCameraState = getJoystickCameraState(joystickName); + if (!joystickCameraState) { + LWARNING(fmt::format("Cannot find JoystickCameraState with name '{}' " + "(clearButtonCommand)", joystickName)); + return; + } + + for (auto it = joystickCameraState->buttonMapping.begin(); + it != joystickCameraState->buttonMapping.end(); ) + { // If the current iterator is the button that we are looking for, delete it // (std::multimap::erase will return the iterator to the next element for us) if (it->first == button) { - it = _buttonMapping.erase(it); + it = joystickCameraState->buttonMapping.erase(it); } else { ++it; @@ -233,14 +327,48 @@ void JoystickCameraStates::clearButtonCommand(int button) { } } -std::vector JoystickCameraStates::buttonCommand(int button) const { +std::vector JoystickCameraStates::buttonCommand( + const std::string& joystickName, + int button) const +{ std::vector result; - auto itRange = _buttonMapping.equal_range(button); + const JoystickCameraState* joystickCameraState = getJoystickCameraState(joystickName); + if (!joystickCameraState) { + LWARNING(fmt::format("Cannot find JoystickCameraState with name '{}' " + "(buttonCommand)", joystickName)); + return result; + } + + auto itRange = joystickCameraState->buttonMapping.equal_range(button); for (auto it = itRange.first; it != itRange.second; ++it) { result.push_back(it->second.command); } return result; } +JoystickCameraStates::JoystickCameraState* JoystickCameraStates::getJoystickCameraState( + const std::string& joystickName) +{ + for (JoystickCameraState& joystickCameraState : _joystickCameraStates) { + if (joystickCameraState.joystickName == joystickName) { + return &joystickCameraState; + } + } + + return nullptr; +} + +const JoystickCameraStates::JoystickCameraState* JoystickCameraStates::getJoystickCameraState( + const std::string& joystickName) const +{ + for (const JoystickCameraState& joystickCameraState : _joystickCameraStates) { + if (joystickCameraState.joystickName == joystickName) { + return &joystickCameraState; + } + } + + return nullptr; +} + } // namespace openspace::interaction diff --git a/src/interaction/joystickinputstate.cpp b/src/interaction/joystickinputstate.cpp index 4a5537a353..9c0da27225 100644 --- a/src/interaction/joystickinputstate.cpp +++ b/src/interaction/joystickinputstate.cpp @@ -33,38 +33,68 @@ namespace openspace::interaction { -float JoystickInputStates::axis(int axis) const { +float JoystickInputStates::axis(const std::string& joystickName, int axis) const { ghoul_precondition(axis >= 0, "axis must be 0 or positive"); - float res = std::accumulate( - begin(), - end(), - 0.f, - [axis](float value, const JoystickInputState& state) { - if (state.isConnected) { - value += state.axes[axis]; + if(joystickName.empty()) { + float res = std::accumulate( + begin(), + end(), + 0.f, + [axis](float value, const JoystickInputState& state) { + if (state.isConnected) { + value += state.axes[axis]; + } + return value; } - return value; - } - ); + ); - // If multiple joysticks are connected, we might get values outside the -1,1 range by - // summing them up - glm::clamp(res, -1.f, 1.f); - return res; + // If multiple joysticks are connected, we might get values outside the -1,1 range by + // summing them up + glm::clamp(res, -1.f, 1.f); + return res; + } + + const JoystickInputState* state = nullptr; + for (auto it = begin(); it < end(); ++it) { + if (it->name == joystickName) { + state = &(*it); + } + } + + if (!state) { + return 0.0f; + } + + return state->axes[axis]; } -bool JoystickInputStates::button(int button, JoystickAction action) const { +bool JoystickInputStates::button(const std::string& joystickName, int button, JoystickAction action) const { ghoul_precondition(button >= 0, "button must be 0 or positive"); - bool res = std::any_of( - begin(), - end(), - [button, action](const JoystickInputState& state) { - return state.isConnected ? (state.buttons[button] == action) : false; + if(joystickName.empty()) { + bool res = std::any_of( + begin(), + end(), + [button, action](const JoystickInputState& state) { + return state.isConnected ? (state.buttons[button] == action) : false; + } + ); + return res; + } + + const JoystickInputState* state = nullptr; + for (auto it = begin(); it < end(); ++it) { + if (it->name == joystickName) { + state = &(*it); } - ); - return res; + } + + if (!state) { + return false; + } + + return state->isConnected ? (state->buttons[button] == action) : false; } } // namespace openspace::interaction diff --git a/src/navigation/navigationhandler.cpp b/src/navigation/navigationhandler.cpp index 43da79c0dd..8a2d67ae9f 100644 --- a/src/navigation/navigationhandler.cpp +++ b/src/navigation/navigationhandler.cpp @@ -498,7 +498,7 @@ void NavigationHandler::loadNavigationState(const std::string& filepath) { } } -void NavigationHandler::setJoystickAxisMapping(int axis, +void NavigationHandler::setJoystickAxisMapping(const std::string& joystickName, int axis, JoystickCameraStates::AxisType mapping, JoystickCameraStates::AxisInvert shouldInvert, JoystickCameraStates::AxisNormalize shouldNormalize, @@ -506,6 +506,7 @@ void NavigationHandler::setJoystickAxisMapping(int axis, double sensitivity) { _orbitalNavigator.joystickStates().setAxisMapping( + joystickName, axis, mapping, shouldInvert, @@ -530,25 +531,31 @@ void NavigationHandler::setWebsocketAxisMapping(int axis, JoystickCameraStates::AxisInformation -NavigationHandler::joystickAxisMapping(int axis) const +NavigationHandler::joystickAxisMapping(const std::string& joystickName, int axis) const { - return _orbitalNavigator.joystickStates().axisMapping(axis); + return _orbitalNavigator.joystickStates().axisMapping(joystickName, axis); } -void NavigationHandler::setJoystickAxisDeadzone(int axis, float deadzone) { - _orbitalNavigator.joystickStates().setDeadzone(axis, deadzone); +void NavigationHandler::setJoystickAxisDeadzone(const std::string& joystickName, int axis, + float deadzone) +{ + _orbitalNavigator.joystickStates().setDeadzone(joystickName, axis, deadzone); } -float NavigationHandler::joystickAxisDeadzone(int axis) const { - return _orbitalNavigator.joystickStates().deadzone(axis); +float NavigationHandler::joystickAxisDeadzone(const std::string& joystickName, + int axis) const +{ + return _orbitalNavigator.joystickStates().deadzone(joystickName, axis); } -void NavigationHandler::bindJoystickButtonCommand(int button, std::string command, +void NavigationHandler::bindJoystickButtonCommand(const std::string& joystickName, + int button, std::string command, JoystickAction action, JoystickCameraStates::ButtonCommandRemote remote, std::string documentation) { _orbitalNavigator.joystickStates().bindButtonCommand( + joystickName, button, std::move(command), action, @@ -557,12 +564,16 @@ void NavigationHandler::bindJoystickButtonCommand(int button, std::string comman ); } -void NavigationHandler::clearJoystickButtonCommand(int button) { - _orbitalNavigator.joystickStates().clearButtonCommand(button); +void NavigationHandler::clearJoystickButtonCommand(const std::string& joystickName, + int button) +{ + _orbitalNavigator.joystickStates().clearButtonCommand(joystickName, button); } -std::vector NavigationHandler::joystickButtonCommand(int button) const { - return _orbitalNavigator.joystickStates().buttonCommand(button); +std::vector NavigationHandler::joystickButtonCommand( + const std::string& joystickName, int button) const +{ + return _orbitalNavigator.joystickStates().buttonCommand(joystickName, button); } scripting::LuaLibrary NavigationHandler::luaLibrary() { diff --git a/src/navigation/navigationhandler_lua.inl b/src/navigation/navigationhandler_lua.inl index 02cb94216c..59795a2bf9 100644 --- a/src/navigation/navigationhandler_lua.inl +++ b/src/navigation/navigationhandler_lua.inl @@ -151,10 +151,11 @@ int retargetAim(lua_State* L) { } int bindJoystickAxis(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, { 2, 6 }, "lua::bindJoystickAxis"); - auto [axis, axisType, shouldInvert, shouldNormalize, isSticky, sensitivity] = + ghoul::lua::checkArgumentsAndThrow(L, { 3, 7 }, "lua::bindJoystickAxis"); + auto [joystickName, axis, axisType, shouldInvert, shouldNormalize, isSticky, + sensitivity] = ghoul::lua::values< - int, std::string, std::optional, std::optional, + std::string, int, std::string, std::optional, std::optional, std::optional, std::optional >(L); shouldInvert = shouldInvert.value_or(false); @@ -163,6 +164,7 @@ int bindJoystickAxis(lua_State* L) { sensitivity = sensitivity.value_or(0.0); global::navigationHandler->setJoystickAxisMapping( + joystickName, axis, ghoul::from_string(axisType), interaction::JoystickCameraStates::AxisInvert(*shouldInvert), @@ -174,11 +176,11 @@ int bindJoystickAxis(lua_State* L) { } int joystickAxis(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::joystickAxis"); - const int axis = ghoul::lua::value(L); + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::joystickAxis"); + auto [joystickName, axis] = ghoul::lua::values(L); using AI = interaction::JoystickCameraStates::AxisInformation; - AI info = global::navigationHandler->joystickAxisMapping(axis); + AI info = global::navigationHandler->joystickAxisMapping(joystickName, axis); ghoul::lua::push( L, @@ -192,27 +194,32 @@ int joystickAxis(lua_State* L) { } int setJoystickAxisDeadzone(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::setJoystickAxisDeadzone"); - auto [axis, deadzone] = ghoul::lua::values(L); + ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setJoystickAxisDeadzone"); + auto [joystickName, axis, deadzone] = ghoul::lua::values(L); - global::navigationHandler->setJoystickAxisDeadzone(axis, deadzone); + global::navigationHandler->setJoystickAxisDeadzone(joystickName, axis, deadzone); return 0; } int joystickAxisDeadzone(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::joystickAxisDeadzone"); - const int axis = ghoul::lua::value(L); + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::joystickAxisDeadzone"); + auto [joystickName, axis] = ghoul::lua::values(L); - const float deadzone = global::navigationHandler->joystickAxisDeadzone(axis); + const float deadzone = global::navigationHandler->joystickAxisDeadzone(joystickName, axis); ghoul::lua::push(L, deadzone); return 1; } int bindJoystickButton(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, { 3, 5 }, "lua::bindJoystickButton"); - auto [button, command, documentation, actionStr, isRemote] = + ghoul::lua::checkArgumentsAndThrow(L, { 4, 6 }, "lua::bindJoystickButton"); + auto [joystickName, button, command, documentation, actionStr, isRemote] = ghoul::lua::values< - int, std::string, std::string, std::optional, std::optional + std::string, + int, + std::string, + std::string, + std::optional, + std::optional >(L); actionStr = actionStr.value_or("Press"); isRemote = isRemote.value_or(true); @@ -221,6 +228,7 @@ int bindJoystickButton(lua_State* L) { ghoul::from_string(*actionStr); global::navigationHandler->bindJoystickButtonCommand( + joystickName, button, command, action, @@ -231,18 +239,19 @@ int bindJoystickButton(lua_State* L) { } int clearJoystickButton(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::clearJoystickButton"); - const int button = ghoul::lua::value(L); - global::navigationHandler->clearJoystickButtonCommand(button); + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::clearJoystickButton"); + auto [joystickName, button] = ghoul::lua::values(L); + + global::navigationHandler->clearJoystickButtonCommand(joystickName, button); return 0; } int joystickButton(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::joystickButton"); - const int button = ghoul::lua::value(L); + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::joystickButton"); + auto [joystickName, button] = ghoul::lua::values(L); const std::vector& cmds = - global::navigationHandler->joystickButtonCommand(button); + global::navigationHandler->joystickButtonCommand(joystickName, button); std::string cmd = std::accumulate( cmds.cbegin(),