summaryrefslogtreecommitdiff
path: root/src/input_common/sdl/sdl_impl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/input_common/sdl/sdl_impl.cpp')
-rw-r--r--src/input_common/sdl/sdl_impl.cpp117
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:
500class SDLAnalog final : public Input::AnalogDevice { 529class SDLAnalog final : public Input::AnalogDevice {
501public: 530public:
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
560class SDLVibration final : public Input::VibrationDevice { 593class 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
769private: 804private:
@@ -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
1136Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x, 1177Common::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 }