diff options
Diffstat (limited to 'src/input_common')
-rwxr-xr-x | src/input_common/analog_from_button.cpp | 195 | ||||
-rw-r--r-- | src/input_common/keyboard.cpp | 1 | ||||
-rw-r--r-- | src/input_common/sdl/sdl_impl.cpp | 281 | ||||
-rw-r--r-- | src/input_common/sdl/sdl_impl.h | 37 |
4 files changed, 381 insertions, 133 deletions
diff --git a/src/input_common/analog_from_button.cpp b/src/input_common/analog_from_button.cpp index f8ec179d0..100138d11 100755 --- a/src/input_common/analog_from_button.cpp +++ b/src/input_common/analog_from_button.cpp @@ -21,104 +21,153 @@ public: : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)), right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_), modifier_angle(modifier_angle_) { - update_thread_running.store(true); - update_thread = std::thread(&Analog::UpdateStatus, this); + Input::InputCallback<bool> callbacks{ + [this]([[maybe_unused]] bool status) { UpdateStatus(); }}; + up->SetCallback(callbacks); + down->SetCallback(callbacks); + left->SetCallback(callbacks); + right->SetCallback(callbacks); } - ~Analog() override { - if (update_thread_running.load()) { - update_thread_running.store(false); - if (update_thread.joinable()) { - update_thread.join(); - } - } + bool IsAngleGreater(float old_angle, float new_angle) const { + constexpr float TAU = Common::PI * 2.0f; + // Use wider angle to ease the transition. + constexpr float aperture = TAU * 0.15f; + const float top_limit = new_angle + aperture; + return (old_angle > new_angle && old_angle <= top_limit) || + (old_angle + TAU > new_angle && old_angle + TAU <= top_limit); } - void MoveToDirection(bool enable, float to_angle) { - if (!enable) { - return; - } + bool IsAngleSmaller(float old_angle, float new_angle) const { constexpr float TAU = Common::PI * 2.0f; // Use wider angle to ease the transition. constexpr float aperture = TAU * 0.15f; - const float top_limit = to_angle + aperture; - const float bottom_limit = to_angle - aperture; - - if ((angle > to_angle && angle <= top_limit) || - (angle + TAU > to_angle && angle + TAU <= top_limit)) { - angle -= modifier_angle; - if (angle < 0) { - angle += TAU; + const float bottom_limit = new_angle - aperture; + return (old_angle >= bottom_limit && old_angle < new_angle) || + (old_angle - TAU >= bottom_limit && old_angle - TAU < new_angle); + } + + float GetAngle(std::chrono::time_point<std::chrono::steady_clock> now) const { + constexpr float TAU = Common::PI * 2.0f; + float new_angle = angle; + + auto time_difference = static_cast<float>( + std::chrono::duration_cast<std::chrono::microseconds>(now - last_update).count()); + time_difference /= 1000.0f * 1000.0f; + if (time_difference > 0.5f) { + time_difference = 0.5f; + } + + if (IsAngleGreater(new_angle, goal_angle)) { + new_angle -= modifier_angle * time_difference; + if (new_angle < 0) { + new_angle += TAU; + } + if (!IsAngleGreater(new_angle, goal_angle)) { + return goal_angle; } - } else if ((angle >= bottom_limit && angle < to_angle) || - (angle - TAU >= bottom_limit && angle - TAU < to_angle)) { - angle += modifier_angle; - if (angle >= TAU) { - angle -= TAU; + } else if (IsAngleSmaller(new_angle, goal_angle)) { + new_angle += modifier_angle * time_difference; + if (new_angle >= TAU) { + new_angle -= TAU; + } + if (!IsAngleSmaller(new_angle, goal_angle)) { + return goal_angle; } } else { - angle = to_angle; + return goal_angle; } + return new_angle; } - void UpdateStatus() { - while (update_thread_running.load()) { - const float coef = modifier->GetStatus() ? modifier_scale : 1.0f; - - bool r = right->GetStatus(); - bool l = left->GetStatus(); - bool u = up->GetStatus(); - bool d = down->GetStatus(); - - // Eliminate contradictory movements - if (r && l) { - r = false; - l = false; - } - if (u && d) { - u = false; - d = false; - } + void SetGoalAngle(bool r, bool l, bool u, bool d) { + // Move to the right + if (r && !u && !d) { + goal_angle = 0.0f; + } + + // Move to the upper right + if (r && u && !d) { + goal_angle = Common::PI * 0.25f; + } - // Move to the right - MoveToDirection(r && !u && !d, 0.0f); + // Move up + if (u && !l && !r) { + goal_angle = Common::PI * 0.5f; + } - // Move to the upper right - MoveToDirection(r && u && !d, Common::PI * 0.25f); + // Move to the upper left + if (l && u && !d) { + goal_angle = Common::PI * 0.75f; + } - // Move up - MoveToDirection(u && !l && !r, Common::PI * 0.5f); + // Move to the left + if (l && !u && !d) { + goal_angle = Common::PI; + } - // Move to the upper left - MoveToDirection(l && u && !d, Common::PI * 0.75f); + // Move to the bottom left + if (l && !u && d) { + goal_angle = Common::PI * 1.25f; + } - // Move to the left - MoveToDirection(l && !u && !d, Common::PI); + // Move down + if (d && !l && !r) { + goal_angle = Common::PI * 1.5f; + } - // Move to the bottom left - MoveToDirection(l && !u && d, Common::PI * 1.25f); + // Move to the bottom right + if (r && !u && d) { + goal_angle = Common::PI * 1.75f; + } + } - // Move down - MoveToDirection(d && !l && !r, Common::PI * 1.5f); + void UpdateStatus() { + const float coef = modifier->GetStatus() ? modifier_scale : 1.0f; - // Move to the bottom right - MoveToDirection(r && !u && d, Common::PI * 1.75f); + bool r = right->GetStatus(); + bool l = left->GetStatus(); + bool u = up->GetStatus(); + bool d = down->GetStatus(); - // Move if a key is pressed - if (r || l || u || d) { - amplitude = coef; - } else { - amplitude = 0; - } + // Eliminate contradictory movements + if (r && l) { + r = false; + l = false; + } + if (u && d) { + u = false; + d = false; + } - // Delay the update rate to 100hz - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + // Move if a key is pressed + if (r || l || u || d) { + amplitude = coef; + } else { + amplitude = 0; } + + const auto now = std::chrono::steady_clock::now(); + const auto time_difference = static_cast<u64>( + std::chrono::duration_cast<std::chrono::milliseconds>(now - last_update).count()); + + if (time_difference < 10) { + // Disable analog mode if inputs are too fast + SetGoalAngle(r, l, u, d); + angle = goal_angle; + } else { + angle = GetAngle(now); + SetGoalAngle(r, l, u, d); + } + + last_update = now; } std::tuple<float, float> GetStatus() const override { if (Settings::values.emulate_analog_keyboard) { - return std::make_tuple(std::cos(angle) * amplitude, std::sin(angle) * amplitude); + const auto now = std::chrono::steady_clock::now(); + float angle_ = GetAngle(now); + return std::make_tuple(std::cos(angle_) * amplitude, std::sin(angle_) * amplitude); } constexpr float SQRT_HALF = 0.707106781f; int x = 0, y = 0; @@ -166,9 +215,9 @@ private: float modifier_scale; float modifier_angle; float angle{}; + float goal_angle{}; float amplitude{}; - std::thread update_thread; - std::atomic<bool> update_thread_running{}; + std::chrono::time_point<std::chrono::steady_clock> last_update; }; std::unique_ptr<Input::AnalogDevice> AnalogFromButton::Create(const Common::ParamPackage& params) { @@ -179,7 +228,7 @@ std::unique_ptr<Input::AnalogDevice> AnalogFromButton::Create(const Common::Para auto right = Input::CreateDevice<Input::ButtonDevice>(params.Get("right", null_engine)); auto modifier = Input::CreateDevice<Input::ButtonDevice>(params.Get("modifier", null_engine)); auto modifier_scale = params.Get("modifier_scale", 0.5f); - auto modifier_angle = params.Get("modifier_angle", 0.035f); + auto modifier_angle = params.Get("modifier_angle", 5.5f); return std::make_unique<Analog>(std::move(up), std::move(down), std::move(left), std::move(right), std::move(modifier), modifier_scale, modifier_angle); diff --git a/src/input_common/keyboard.cpp b/src/input_common/keyboard.cpp index c467ff4c5..8261e76fd 100644 --- a/src/input_common/keyboard.cpp +++ b/src/input_common/keyboard.cpp @@ -75,6 +75,7 @@ public: } else { pair.key_button->UnlockButton(); } + pair.key_button->TriggerOnChange(); } } } diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index b9b584b2a..68672a92b 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp @@ -18,16 +18,6 @@ #include <utility> #include <vector> -// Ignore -Wimplicit-fallthrough due to https://github.com/libsdl-org/SDL/issues/4307 -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wimplicit-fallthrough" -#endif -#include <SDL.h> -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - #include "common/logging/log.h" #include "common/math_util.h" #include "common/param_package.h" @@ -214,6 +204,40 @@ public: sdl_controller.reset(controller); } + bool IsJoyconLeft() const { + return std::strstr(GetControllerName().c_str(), "Joy-Con Left") != nullptr; + } + + bool IsJoyconRight() const { + return std::strstr(GetControllerName().c_str(), "Joy-Con Right") != nullptr; + } + + std::string GetControllerName() const { + if (sdl_controller) { + switch (SDL_GameControllerGetType(sdl_controller.get())) { + case SDL_CONTROLLER_TYPE_XBOX360: + return "XBox 360 Controller"; + case SDL_CONTROLLER_TYPE_XBOXONE: + return "XBox One Controller"; + default: + break; + } + const auto name = SDL_GameControllerName(sdl_controller.get()); + if (name) { + return name; + } + } + + if (sdl_joystick) { + const auto name = SDL_JoystickName(sdl_joystick.get()); + if (name) { + return name; + } + } + + return "Unknown"; + } + private: struct State { std::unordered_map<int, bool> buttons; @@ -858,23 +882,42 @@ SDLState::~SDLState() { std::vector<Common::ParamPackage> SDLState::GetInputDevices() { std::scoped_lock lock(joystick_map_mutex); std::vector<Common::ParamPackage> devices; + std::unordered_map<int, std::shared_ptr<SDLJoystick>> joycon_pairs; + for (const auto& [key, value] : joystick_map) { + for (const auto& joystick : value) { + if (!joystick->GetSDLJoystick()) { + continue; + } + std::string name = + fmt::format("{} {}", joystick->GetControllerName(), joystick->GetPort()); + devices.emplace_back(Common::ParamPackage{ + {"class", "sdl"}, + {"display", std::move(name)}, + {"guid", joystick->GetGUID()}, + {"port", std::to_string(joystick->GetPort())}, + }); + if (joystick->IsJoyconLeft()) { + joycon_pairs.insert_or_assign(joystick->GetPort(), joystick); + } + } + } + + // Add dual controllers for (const auto& [key, value] : joystick_map) { for (const auto& joystick : value) { - if (auto* const controller = joystick->GetSDLGameController()) { + if (joystick->IsJoyconRight()) { + if (!joycon_pairs.contains(joystick->GetPort())) { + continue; + } + const auto joystick2 = joycon_pairs.at(joystick->GetPort()); + std::string name = - fmt::format("{} {}", GetControllerName(controller), joystick->GetPort()); - devices.emplace_back(Common::ParamPackage{ - {"class", "sdl"}, - {"display", std::move(name)}, - {"guid", joystick->GetGUID()}, - {"port", std::to_string(joystick->GetPort())}, - }); - } else if (auto* const joy = joystick->GetSDLJoystick()) { - std::string name = fmt::format("{} {}", SDL_JoystickName(joy), joystick->GetPort()); + fmt::format("{} {}", "Nintendo Dual Joy-Con", joystick->GetPort()); devices.emplace_back(Common::ParamPackage{ {"class", "sdl"}, {"display", std::move(name)}, {"guid", joystick->GetGUID()}, + {"guid2", joystick2->GetGUID()}, {"port", std::to_string(joystick->GetPort())}, }); } @@ -883,17 +926,6 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() { return devices; } -std::string SDLState::GetControllerName(SDL_GameController* controller) const { - switch (SDL_GameControllerGetType(controller)) { - case SDL_CONTROLLER_TYPE_XBOX360: - return "XBox 360 Controller"; - case SDL_CONTROLLER_TYPE_XBOXONE: - return "XBox One Controller"; - default: - return SDL_GameControllerName(controller); - } -} - namespace { Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, float value = 0.1f) { @@ -1073,24 +1105,48 @@ ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& pa return {}; } const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); + auto* controller = joystick->GetSDLGameController(); if (controller == nullptr) { return {}; } - const bool invert = - SDL_GameControllerGetType(controller) != SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO; - // This list is missing ZL/ZR since those are not considered buttons in SDL GameController. // We will add those afterwards // This list also excludes Screenshot since theres not really a mapping for that - using ButtonBindings = - std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>; - const ButtonBindings switch_to_sdl_button{{ - {Settings::NativeButton::A, invert ? SDL_CONTROLLER_BUTTON_B : SDL_CONTROLLER_BUTTON_A}, - {Settings::NativeButton::B, invert ? SDL_CONTROLLER_BUTTON_A : SDL_CONTROLLER_BUTTON_B}, - {Settings::NativeButton::X, invert ? SDL_CONTROLLER_BUTTON_Y : SDL_CONTROLLER_BUTTON_X}, - {Settings::NativeButton::Y, invert ? SDL_CONTROLLER_BUTTON_X : SDL_CONTROLLER_BUTTON_Y}, + ButtonBindings switch_to_sdl_button; + + if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) { + switch_to_sdl_button = GetNintendoButtonBinding(joystick); + } else { + switch_to_sdl_button = GetDefaultButtonBinding(); + } + + // Add the missing bindings for ZL/ZR + static constexpr ZButtonBindings switch_to_sdl_axis{{ + {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT}, + {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT}, + }}; + + // Parameters contain two joysticks return dual + if (params.Has("guid2")) { + const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0)); + + if (joystick2->GetSDLGameController() != nullptr) { + return GetDualControllerMapping(joystick, joystick2, switch_to_sdl_button, + switch_to_sdl_axis); + } + } + + return GetSingleControllerMapping(joystick, switch_to_sdl_button, switch_to_sdl_axis); +} + +ButtonBindings SDLState::GetDefaultButtonBinding() const { + return { + std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B}, + {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A}, + {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y}, + {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X}, {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK}, {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK}, {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, @@ -1104,18 +1160,51 @@ ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& pa {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE}, - }}; + }; +} - // Add the missing bindings for ZL/ZR - using ZBindings = - std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>; - static constexpr ZBindings switch_to_sdl_axis{{ - {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT}, - {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT}, - }}; +ButtonBindings SDLState::GetNintendoButtonBinding( + const std::shared_ptr<SDLJoystick>& joystick) const { + // Default SL/SR mapping for pro controllers + auto sl_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; + auto sr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; + + if (joystick->IsJoyconLeft()) { + sl_button = SDL_CONTROLLER_BUTTON_PADDLE2; + sr_button = SDL_CONTROLLER_BUTTON_PADDLE4; + } + if (joystick->IsJoyconRight()) { + sl_button = SDL_CONTROLLER_BUTTON_PADDLE3; + sr_button = SDL_CONTROLLER_BUTTON_PADDLE1; + } + return { + std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_A}, + {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_B}, + {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_X}, + {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_Y}, + {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK}, + {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK}, + {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, + {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, + {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START}, + {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK}, + {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT}, + {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP}, + {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT}, + {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN}, + {Settings::NativeButton::SL, sl_button}, + {Settings::NativeButton::SR, sr_button}, + {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE}, + }; +} + +ButtonMapping SDLState::GetSingleControllerMapping( + const std::shared_ptr<SDLJoystick>& joystick, const ButtonBindings& switch_to_sdl_button, + const ZButtonBindings& switch_to_sdl_axis) const { ButtonMapping mapping; mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size()); + auto* controller = joystick->GetSDLGameController(); for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) { const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button); @@ -1133,11 +1222,68 @@ ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& pa return mapping; } +ButtonMapping SDLState::GetDualControllerMapping(const std::shared_ptr<SDLJoystick>& joystick, + const std::shared_ptr<SDLJoystick>& joystick2, + const ButtonBindings& switch_to_sdl_button, + const ZButtonBindings& switch_to_sdl_axis) const { + ButtonMapping mapping; + mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size()); + auto* controller = joystick->GetSDLGameController(); + auto* controller2 = joystick2->GetSDLGameController(); + + for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) { + if (IsButtonOnLeftSide(switch_button)) { + const auto& binding = SDL_GameControllerGetBindForButton(controller2, sdl_button); + mapping.insert_or_assign( + switch_button, + BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding)); + continue; + } + const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button); + mapping.insert_or_assign( + switch_button, + BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); + } + for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) { + if (IsButtonOnLeftSide(switch_button)) { + const auto& binding = SDL_GameControllerGetBindForAxis(controller2, sdl_axis); + mapping.insert_or_assign( + switch_button, + BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding)); + continue; + } + const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis); + mapping.insert_or_assign( + switch_button, + BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); + } + + return mapping; +} + +bool SDLState::IsButtonOnLeftSide(Settings::NativeButton::Values button) const { + switch (button) { + case Settings::NativeButton::DDown: + case Settings::NativeButton::DLeft: + case Settings::NativeButton::DRight: + case Settings::NativeButton::DUp: + case Settings::NativeButton::L: + case Settings::NativeButton::LStick: + case Settings::NativeButton::Minus: + case Settings::NativeButton::Screenshot: + case Settings::NativeButton::ZL: + return true; + default: + return false; + } +} + AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& params) { if (!params.Has("guid") || !params.Has("port")) { return {}; } const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); + const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0)); auto* controller = joystick->GetSDLGameController(); if (controller == nullptr) { return {}; @@ -1148,10 +1294,17 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX); const auto& binding_left_y = SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); - mapping.insert_or_assign(Settings::NativeAnalog::LStick, - BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), - binding_left_x.value.axis, - binding_left_y.value.axis)); + if (params.Has("guid2")) { + mapping.insert_or_assign( + Settings::NativeAnalog::LStick, + BuildParamPackageForAnalog(joystick2->GetPort(), joystick2->GetGUID(), + binding_left_x.value.axis, binding_left_y.value.axis)); + } else { + mapping.insert_or_assign( + Settings::NativeAnalog::LStick, + BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), + binding_left_x.value.axis, binding_left_y.value.axis)); + } const auto& binding_right_x = SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX); const auto& binding_right_y = @@ -1168,20 +1321,32 @@ MotionMapping SDLState::GetMotionMappingForDevice(const Common::ParamPackage& pa return {}; } const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); + const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0)); auto* controller = joystick->GetSDLGameController(); if (controller == nullptr) { return {}; } + MotionMapping mapping = {}; joystick->EnableMotion(); - if (!joystick->HasGyro() && !joystick->HasAccel()) { - return {}; + if (joystick->HasGyro() || joystick->HasAccel()) { + mapping.insert_or_assign(Settings::NativeMotion::MotionRight, + BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); + } + if (params.Has("guid2")) { + joystick2->EnableMotion(); + if (joystick2->HasGyro() || joystick2->HasAccel()) { + mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, + BuildMotionParam(joystick2->GetPort(), joystick2->GetGUID())); + } + } else { + if (joystick->HasGyro() || joystick->HasAccel()) { + mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, + BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); + } } - MotionMapping mapping = {}; - mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, - BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); return mapping; } namespace Polling { diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h index 121e01913..b77afcbd8 100644 --- a/src/input_common/sdl/sdl_impl.h +++ b/src/input_common/sdl/sdl_impl.h @@ -9,6 +9,17 @@ #include <mutex> #include <thread> #include <unordered_map> + +// Ignore -Wimplicit-fallthrough due to https://github.com/libsdl-org/SDL/issues/4307 +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +#endif +#include <SDL.h> +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + #include "common/common_types.h" #include "common/threadsafe_queue.h" #include "input_common/sdl/sdl.h" @@ -18,6 +29,11 @@ using SDL_GameController = struct _SDL_GameController; using SDL_Joystick = struct _SDL_Joystick; using SDL_JoystickID = s32; +using ButtonBindings = + std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>; +using ZButtonBindings = + std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>; + namespace InputCommon::SDL { class SDLAnalogFactory; @@ -66,8 +82,25 @@ private: /// Needs to be called before SDL_QuitSubSystem. void CloseJoysticks(); - /// Returns a custom name for specific controllers because the default name is not correct - std::string GetControllerName(SDL_GameController* controller) const; + /// Returns the default button bindings list for generic controllers + ButtonBindings GetDefaultButtonBinding() const; + + /// Returns the default button bindings list for nintendo controllers + ButtonBindings GetNintendoButtonBinding(const std::shared_ptr<SDLJoystick>& joystick) const; + + /// Returns the button mappings from a single controller + ButtonMapping GetSingleControllerMapping(const std::shared_ptr<SDLJoystick>& joystick, + const ButtonBindings& switch_to_sdl_button, + const ZButtonBindings& switch_to_sdl_axis) const; + + /// Returns the button mappings from two different controllers + ButtonMapping GetDualControllerMapping(const std::shared_ptr<SDLJoystick>& joystick, + const std::shared_ptr<SDLJoystick>& joystick2, + const ButtonBindings& switch_to_sdl_button, + const ZButtonBindings& switch_to_sdl_axis) const; + + /// Returns true if the button is on the left joycon + bool IsButtonOnLeftSide(Settings::NativeButton::Values button) const; // Set to true if SDL supports game controller subsystem bool has_gamecontroller = false; |