diff options
Diffstat (limited to 'src/input_common/sdl/sdl_impl.cpp')
| -rw-r--r-- | src/input_common/sdl/sdl_impl.cpp | 117 |
1 files changed, 88 insertions, 29 deletions
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index 70a0ba09c..ecb00d428 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp | |||
| @@ -21,7 +21,7 @@ | |||
| 21 | #include "common/logging/log.h" | 21 | #include "common/logging/log.h" |
| 22 | #include "common/math_util.h" | 22 | #include "common/math_util.h" |
| 23 | #include "common/param_package.h" | 23 | #include "common/param_package.h" |
| 24 | #include "common/settings_input.h" | 24 | #include "common/settings.h" |
| 25 | #include "common/threadsafe_queue.h" | 25 | #include "common/threadsafe_queue.h" |
| 26 | #include "core/frontend/input.h" | 26 | #include "core/frontend/input.h" |
| 27 | #include "input_common/motion_input.h" | 27 | #include "input_common/motion_input.h" |
| @@ -82,6 +82,12 @@ public: | |||
| 82 | state.buttons.insert_or_assign(button, value); | 82 | state.buttons.insert_or_assign(button, value); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | void PreSetButton(int button) { | ||
| 86 | if (!state.buttons.contains(button)) { | ||
| 87 | SetButton(button, false); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 85 | void SetMotion(SDL_ControllerSensorEvent event) { | 91 | void SetMotion(SDL_ControllerSensorEvent event) { |
| 86 | constexpr float gravity_constant = 9.80665f; | 92 | constexpr float gravity_constant = 9.80665f; |
| 87 | std::lock_guard lock{mutex}; | 93 | std::lock_guard lock{mutex}; |
| @@ -155,9 +161,17 @@ public: | |||
| 155 | state.axes.insert_or_assign(axis, value); | 161 | state.axes.insert_or_assign(axis, value); |
| 156 | } | 162 | } |
| 157 | 163 | ||
| 158 | float GetAxis(int axis, float range) const { | 164 | void PreSetAxis(int axis) { |
| 165 | if (!state.axes.contains(axis)) { | ||
| 166 | SetAxis(axis, 0); | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | float GetAxis(int axis, float range, float offset) const { | ||
| 159 | std::lock_guard lock{mutex}; | 171 | std::lock_guard lock{mutex}; |
| 160 | return static_cast<float>(state.axes.at(axis)) / (32767.0f * range); | 172 | const float value = static_cast<float>(state.axes.at(axis)) / 32767.0f; |
| 173 | const float offset_scale = (value + offset) > 0.0f ? 1.0f + offset : 1.0f - offset; | ||
| 174 | return (value + offset) / range / offset_scale; | ||
| 161 | } | 175 | } |
| 162 | 176 | ||
| 163 | bool RumblePlay(u16 amp_low, u16 amp_high) { | 177 | bool RumblePlay(u16 amp_low, u16 amp_high) { |
| @@ -174,9 +188,10 @@ public: | |||
| 174 | return false; | 188 | return false; |
| 175 | } | 189 | } |
| 176 | 190 | ||
| 177 | std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range) const { | 191 | std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range, float offset_x, |
| 178 | float x = GetAxis(axis_x, range); | 192 | float offset_y) const { |
| 179 | float y = GetAxis(axis_y, range); | 193 | float x = GetAxis(axis_x, range, offset_x); |
| 194 | float y = GetAxis(axis_y, range, offset_y); | ||
| 180 | y = -y; // 3DS uses an y-axis inverse from SDL | 195 | y = -y; // 3DS uses an y-axis inverse from SDL |
| 181 | 196 | ||
| 182 | // Make sure the coordinates are in the unit circle, | 197 | // Make sure the coordinates are in the unit circle, |
| @@ -240,11 +255,25 @@ public: | |||
| 240 | } | 255 | } |
| 241 | 256 | ||
| 242 | bool IsJoyconLeft() const { | 257 | bool IsJoyconLeft() const { |
| 243 | return std::strstr(GetControllerName().c_str(), "Joy-Con Left") != nullptr; | 258 | const std::string controller_name = GetControllerName(); |
| 259 | if (std::strstr(controller_name.c_str(), "Joy-Con Left") != nullptr) { | ||
| 260 | return true; | ||
| 261 | } | ||
| 262 | if (std::strstr(controller_name.c_str(), "Joy-Con (L)") != nullptr) { | ||
| 263 | return true; | ||
| 264 | } | ||
| 265 | return false; | ||
| 244 | } | 266 | } |
| 245 | 267 | ||
| 246 | bool IsJoyconRight() const { | 268 | bool IsJoyconRight() const { |
| 247 | return std::strstr(GetControllerName().c_str(), "Joy-Con Right") != nullptr; | 269 | const std::string controller_name = GetControllerName(); |
| 270 | if (std::strstr(controller_name.c_str(), "Joy-Con Right") != nullptr) { | ||
| 271 | return true; | ||
| 272 | } | ||
| 273 | if (std::strstr(controller_name.c_str(), "Joy-Con (R)") != nullptr) { | ||
| 274 | return true; | ||
| 275 | } | ||
| 276 | return false; | ||
| 248 | } | 277 | } |
| 249 | 278 | ||
| 250 | std::string GetControllerName() const { | 279 | std::string GetControllerName() const { |
| @@ -483,7 +512,7 @@ public: | |||
| 483 | trigger_if_greater(trigger_if_greater_) {} | 512 | trigger_if_greater(trigger_if_greater_) {} |
| 484 | 513 | ||
| 485 | bool GetStatus() const override { | 514 | bool GetStatus() const override { |
| 486 | const float axis_value = joystick->GetAxis(axis, 1.0f); | 515 | const float axis_value = joystick->GetAxis(axis, 1.0f, 0.0f); |
| 487 | if (trigger_if_greater) { | 516 | if (trigger_if_greater) { |
| 488 | return axis_value > threshold; | 517 | return axis_value > threshold; |
| 489 | } | 518 | } |
| @@ -500,12 +529,14 @@ private: | |||
| 500 | class SDLAnalog final : public Input::AnalogDevice { | 529 | class SDLAnalog final : public Input::AnalogDevice { |
| 501 | public: | 530 | public: |
| 502 | explicit SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, | 531 | explicit SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, |
| 503 | bool invert_x_, bool invert_y_, float deadzone_, float range_) | 532 | bool invert_x_, bool invert_y_, float deadzone_, float range_, |
| 533 | float offset_x_, float offset_y_) | ||
| 504 | : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_), | 534 | : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_), |
| 505 | invert_y(invert_y_), deadzone(deadzone_), range(range_) {} | 535 | invert_y(invert_y_), deadzone(deadzone_), range(range_), offset_x(offset_x_), |
| 536 | offset_y(offset_y_) {} | ||
| 506 | 537 | ||
| 507 | std::tuple<float, float> GetStatus() const override { | 538 | std::tuple<float, float> GetStatus() const override { |
| 508 | auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range); | 539 | auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range, offset_x, offset_y); |
| 509 | const float r = std::sqrt((x * x) + (y * y)); | 540 | const float r = std::sqrt((x * x) + (y * y)); |
| 510 | if (invert_x) { | 541 | if (invert_x) { |
| 511 | x = -x; | 542 | x = -x; |
| @@ -522,8 +553,8 @@ public: | |||
| 522 | } | 553 | } |
| 523 | 554 | ||
| 524 | std::tuple<float, float> GetRawStatus() const override { | 555 | std::tuple<float, float> GetRawStatus() const override { |
| 525 | const float x = joystick->GetAxis(axis_x, range); | 556 | const float x = joystick->GetAxis(axis_x, range, offset_x); |
| 526 | const float y = joystick->GetAxis(axis_y, range); | 557 | const float y = joystick->GetAxis(axis_y, range, offset_y); |
| 527 | return {x, -y}; | 558 | return {x, -y}; |
| 528 | } | 559 | } |
| 529 | 560 | ||
| @@ -555,6 +586,8 @@ private: | |||
| 555 | const bool invert_y; | 586 | const bool invert_y; |
| 556 | const float deadzone; | 587 | const float deadzone; |
| 557 | const float range; | 588 | const float range; |
| 589 | const float offset_x; | ||
| 590 | const float offset_y; | ||
| 558 | }; | 591 | }; |
| 559 | 592 | ||
| 560 | class SDLVibration final : public Input::VibrationDevice { | 593 | class SDLVibration final : public Input::VibrationDevice { |
| @@ -621,7 +654,7 @@ public: | |||
| 621 | trigger_if_greater(trigger_if_greater_) {} | 654 | trigger_if_greater(trigger_if_greater_) {} |
| 622 | 655 | ||
| 623 | Input::MotionStatus GetStatus() const override { | 656 | Input::MotionStatus GetStatus() const override { |
| 624 | const float axis_value = joystick->GetAxis(axis, 1.0f); | 657 | const float axis_value = joystick->GetAxis(axis, 1.0f, 0.0f); |
| 625 | bool trigger = axis_value < threshold; | 658 | bool trigger = axis_value < threshold; |
| 626 | if (trigger_if_greater) { | 659 | if (trigger_if_greater) { |
| 627 | trigger = axis_value > threshold; | 660 | trigger = axis_value > threshold; |
| @@ -720,13 +753,13 @@ public: | |||
| 720 | LOG_ERROR(Input, "Unknown direction {}", direction_name); | 753 | LOG_ERROR(Input, "Unknown direction {}", direction_name); |
| 721 | } | 754 | } |
| 722 | // This is necessary so accessing GetAxis with axis won't crash | 755 | // This is necessary so accessing GetAxis with axis won't crash |
| 723 | joystick->SetAxis(axis, 0); | 756 | joystick->PreSetAxis(axis); |
| 724 | return std::make_unique<SDLAxisButton>(joystick, axis, threshold, trigger_if_greater); | 757 | return std::make_unique<SDLAxisButton>(joystick, axis, threshold, trigger_if_greater); |
| 725 | } | 758 | } |
| 726 | 759 | ||
| 727 | const int button = params.Get("button", 0); | 760 | const int button = params.Get("button", 0); |
| 728 | // This is necessary so accessing GetButton with button won't crash | 761 | // This is necessary so accessing GetButton with button won't crash |
| 729 | joystick->SetButton(button, false); | 762 | joystick->PreSetButton(button); |
| 730 | return std::make_unique<SDLButton>(joystick, button, toggle); | 763 | return std::make_unique<SDLButton>(joystick, button, toggle); |
| 731 | } | 764 | } |
| 732 | 765 | ||
| @@ -757,13 +790,15 @@ public: | |||
| 757 | const std::string invert_y_value = params.Get("invert_y", "+"); | 790 | const std::string invert_y_value = params.Get("invert_y", "+"); |
| 758 | const bool invert_x = invert_x_value == "-"; | 791 | const bool invert_x = invert_x_value == "-"; |
| 759 | const bool invert_y = invert_y_value == "-"; | 792 | const bool invert_y = invert_y_value == "-"; |
| 793 | const float offset_x = std::clamp(params.Get("offset_x", 0.0f), -0.99f, 0.99f); | ||
| 794 | const float offset_y = std::clamp(params.Get("offset_y", 0.0f), -0.99f, 0.99f); | ||
| 760 | auto joystick = state.GetSDLJoystickByGUID(guid, port); | 795 | auto joystick = state.GetSDLJoystickByGUID(guid, port); |
| 761 | 796 | ||
| 762 | // This is necessary so accessing GetAxis with axis_x and axis_y won't crash | 797 | // This is necessary so accessing GetAxis with axis_x and axis_y won't crash |
| 763 | joystick->SetAxis(axis_x, 0); | 798 | joystick->PreSetAxis(axis_x); |
| 764 | joystick->SetAxis(axis_y, 0); | 799 | joystick->PreSetAxis(axis_y); |
| 765 | return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, invert_x, invert_y, deadzone, | 800 | return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, invert_x, invert_y, deadzone, |
| 766 | range); | 801 | range, offset_x, offset_y); |
| 767 | } | 802 | } |
| 768 | 803 | ||
| 769 | private: | 804 | private: |
| @@ -844,13 +879,13 @@ public: | |||
| 844 | LOG_ERROR(Input, "Unknown direction {}", direction_name); | 879 | LOG_ERROR(Input, "Unknown direction {}", direction_name); |
| 845 | } | 880 | } |
| 846 | // This is necessary so accessing GetAxis with axis won't crash | 881 | // This is necessary so accessing GetAxis with axis won't crash |
| 847 | joystick->SetAxis(axis, 0); | 882 | joystick->PreSetAxis(axis); |
| 848 | return std::make_unique<SDLAxisMotion>(joystick, axis, threshold, trigger_if_greater); | 883 | return std::make_unique<SDLAxisMotion>(joystick, axis, threshold, trigger_if_greater); |
| 849 | } | 884 | } |
| 850 | 885 | ||
| 851 | const int button = params.Get("button", 0); | 886 | const int button = params.Get("button", 0); |
| 852 | // This is necessary so accessing GetButton with button won't crash | 887 | // This is necessary so accessing GetButton with button won't crash |
| 853 | joystick->SetButton(button, false); | 888 | joystick->PreSetButton(button); |
| 854 | return std::make_unique<SDLButtonMotion>(joystick, button); | 889 | return std::make_unique<SDLButtonMotion>(joystick, button); |
| 855 | } | 890 | } |
| 856 | 891 | ||
| @@ -869,16 +904,21 @@ SDLState::SDLState() { | |||
| 869 | RegisterFactory<VibrationDevice>("sdl", vibration_factory); | 904 | RegisterFactory<VibrationDevice>("sdl", vibration_factory); |
| 870 | RegisterFactory<MotionDevice>("sdl", motion_factory); | 905 | RegisterFactory<MotionDevice>("sdl", motion_factory); |
| 871 | 906 | ||
| 907 | if (!Settings::values.enable_raw_input) { | ||
| 908 | // Disable raw input. When enabled this setting causes SDL to die when a web applet opens | ||
| 909 | SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); | ||
| 910 | } | ||
| 911 | |||
| 872 | // Enable HIDAPI rumble. This prevents SDL from disabling motion on PS4 and PS5 controllers | 912 | // Enable HIDAPI rumble. This prevents SDL from disabling motion on PS4 and PS5 controllers |
| 873 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); | 913 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); |
| 874 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); | 914 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); |
| 875 | 915 | ||
| 876 | // Tell SDL2 to use the hidapi driver. This will allow joycons to be detected as a | 916 | // Tell SDL2 to use the hidapi driver. This will allow joycons to be detected as a |
| 877 | // GameController and not a generic one | 917 | // GameController and not a generic one |
| 878 | SDL_SetHint("SDL_JOYSTICK_HIDAPI_JOY_CONS", "1"); | 918 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); |
| 879 | 919 | ||
| 880 | // Turn off Pro controller home led | 920 | // Turn off Pro controller home led |
| 881 | SDL_SetHint("SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED", "0"); | 921 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0"); |
| 882 | 922 | ||
| 883 | // If the frontend is going to manage the event loop, then we don't start one here | 923 | // If the frontend is going to manage the event loop, then we don't start one here |
| 884 | start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0; | 924 | start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0; |
| @@ -995,6 +1035,7 @@ Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid | |||
| 995 | params.Set("port", port); | 1035 | params.Set("port", port); |
| 996 | params.Set("guid", std::move(guid)); | 1036 | params.Set("guid", std::move(guid)); |
| 997 | params.Set("button", button); | 1037 | params.Set("button", button); |
| 1038 | params.Set("toggle", false); | ||
| 998 | return params; | 1039 | return params; |
| 999 | } | 1040 | } |
| 1000 | 1041 | ||
| @@ -1134,13 +1175,15 @@ Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& gu | |||
| 1134 | } | 1175 | } |
| 1135 | 1176 | ||
| 1136 | Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x, | 1177 | Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x, |
| 1137 | int axis_y) { | 1178 | int axis_y, float offset_x, float offset_y) { |
| 1138 | Common::ParamPackage params; | 1179 | Common::ParamPackage params; |
| 1139 | params.Set("engine", "sdl"); | 1180 | params.Set("engine", "sdl"); |
| 1140 | params.Set("port", port); | 1181 | params.Set("port", port); |
| 1141 | params.Set("guid", guid); | 1182 | params.Set("guid", guid); |
| 1142 | params.Set("axis_x", axis_x); | 1183 | params.Set("axis_x", axis_x); |
| 1143 | params.Set("axis_y", axis_y); | 1184 | params.Set("axis_y", axis_y); |
| 1185 | params.Set("offset_x", offset_x); | ||
| 1186 | params.Set("offset_y", offset_y); | ||
| 1144 | params.Set("invert_x", "+"); | 1187 | params.Set("invert_x", "+"); |
| 1145 | params.Set("invert_y", "+"); | 1188 | params.Set("invert_y", "+"); |
| 1146 | return params; | 1189 | return params; |
| @@ -1342,24 +1385,39 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa | |||
| 1342 | const auto& binding_left_y = | 1385 | const auto& binding_left_y = |
| 1343 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); | 1386 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); |
| 1344 | if (params.Has("guid2")) { | 1387 | if (params.Has("guid2")) { |
| 1388 | joystick2->PreSetAxis(binding_left_x.value.axis); | ||
| 1389 | joystick2->PreSetAxis(binding_left_y.value.axis); | ||
| 1390 | const auto left_offset_x = -joystick2->GetAxis(binding_left_x.value.axis, 1.0f, 0); | ||
| 1391 | const auto left_offset_y = -joystick2->GetAxis(binding_left_y.value.axis, 1.0f, 0); | ||
| 1345 | mapping.insert_or_assign( | 1392 | mapping.insert_or_assign( |
| 1346 | Settings::NativeAnalog::LStick, | 1393 | Settings::NativeAnalog::LStick, |
| 1347 | BuildParamPackageForAnalog(joystick2->GetPort(), joystick2->GetGUID(), | 1394 | BuildParamPackageForAnalog(joystick2->GetPort(), joystick2->GetGUID(), |
| 1348 | binding_left_x.value.axis, binding_left_y.value.axis)); | 1395 | binding_left_x.value.axis, binding_left_y.value.axis, |
| 1396 | left_offset_x, left_offset_y)); | ||
| 1349 | } else { | 1397 | } else { |
| 1398 | joystick->PreSetAxis(binding_left_x.value.axis); | ||
| 1399 | joystick->PreSetAxis(binding_left_y.value.axis); | ||
| 1400 | const auto left_offset_x = -joystick->GetAxis(binding_left_x.value.axis, 1.0f, 0); | ||
| 1401 | const auto left_offset_y = -joystick->GetAxis(binding_left_y.value.axis, 1.0f, 0); | ||
| 1350 | mapping.insert_or_assign( | 1402 | mapping.insert_or_assign( |
| 1351 | Settings::NativeAnalog::LStick, | 1403 | Settings::NativeAnalog::LStick, |
| 1352 | BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), | 1404 | BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), |
| 1353 | binding_left_x.value.axis, binding_left_y.value.axis)); | 1405 | binding_left_x.value.axis, binding_left_y.value.axis, |
| 1406 | left_offset_x, left_offset_y)); | ||
| 1354 | } | 1407 | } |
| 1355 | const auto& binding_right_x = | 1408 | const auto& binding_right_x = |
| 1356 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX); | 1409 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX); |
| 1357 | const auto& binding_right_y = | 1410 | const auto& binding_right_y = |
| 1358 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY); | 1411 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY); |
| 1412 | joystick->PreSetAxis(binding_right_x.value.axis); | ||
| 1413 | joystick->PreSetAxis(binding_right_y.value.axis); | ||
| 1414 | const auto right_offset_x = -joystick->GetAxis(binding_right_x.value.axis, 1.0f, 0); | ||
| 1415 | const auto right_offset_y = -joystick->GetAxis(binding_right_y.value.axis, 1.0f, 0); | ||
| 1359 | mapping.insert_or_assign(Settings::NativeAnalog::RStick, | 1416 | mapping.insert_or_assign(Settings::NativeAnalog::RStick, |
| 1360 | BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), | 1417 | BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), |
| 1361 | binding_right_x.value.axis, | 1418 | binding_right_x.value.axis, |
| 1362 | binding_right_y.value.axis)); | 1419 | binding_right_y.value.axis, right_offset_x, |
| 1420 | right_offset_y)); | ||
| 1363 | return mapping; | 1421 | return mapping; |
| 1364 | } | 1422 | } |
| 1365 | 1423 | ||
| @@ -1563,8 +1621,9 @@ public: | |||
| 1563 | } | 1621 | } |
| 1564 | 1622 | ||
| 1565 | if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) { | 1623 | if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) { |
| 1624 | // Set offset to zero since the joystick is not on center | ||
| 1566 | auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), | 1625 | auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), |
| 1567 | first_axis, axis); | 1626 | first_axis, axis, 0, 0); |
| 1568 | first_axis = -1; | 1627 | first_axis = -1; |
| 1569 | return params; | 1628 | return params; |
| 1570 | } | 1629 | } |