summaryrefslogtreecommitdiff
path: root/src/input_common/sdl
diff options
context:
space:
mode:
Diffstat (limited to 'src/input_common/sdl')
-rw-r--r--src/input_common/sdl/sdl.h3
-rw-r--r--src/input_common/sdl/sdl_impl.cpp153
-rw-r--r--src/input_common/sdl/sdl_impl.h1
3 files changed, 154 insertions, 3 deletions
diff --git a/src/input_common/sdl/sdl.h b/src/input_common/sdl/sdl.h
index 42bbf14d4..b5d41bba4 100644
--- a/src/input_common/sdl/sdl.h
+++ b/src/input_common/sdl/sdl.h
@@ -37,6 +37,9 @@ public:
37 virtual AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&) { 37 virtual AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&) {
38 return {}; 38 return {};
39 } 39 }
40 virtual MotionMapping GetMotionMappingForDevice(const Common::ParamPackage&) {
41 return {};
42 }
40}; 43};
41 44
42class NullState : public State { 45class NullState : public State {
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 288557968..b9b584b2a 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -29,6 +29,7 @@
29#endif 29#endif
30 30
31#include "common/logging/log.h" 31#include "common/logging/log.h"
32#include "common/math_util.h"
32#include "common/param_package.h" 33#include "common/param_package.h"
33#include "common/settings_input.h" 34#include "common/settings_input.h"
34#include "common/threadsafe_queue.h" 35#include "common/threadsafe_queue.h"
@@ -68,13 +69,57 @@ public:
68 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, 69 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick,
69 SDL_GameController* game_controller) 70 SDL_GameController* game_controller)
70 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose}, 71 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose},
71 sdl_controller{game_controller, &SDL_GameControllerClose} {} 72 sdl_controller{game_controller, &SDL_GameControllerClose} {
73 EnableMotion();
74 }
75
76 void EnableMotion() {
77 if (sdl_controller) {
78 SDL_GameController* controller = sdl_controller.get();
79 if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) && !has_accel) {
80 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE);
81 has_accel = true;
82 }
83 if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) && !has_gyro) {
84 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE);
85 has_gyro = true;
86 }
87 }
88 }
72 89
73 void SetButton(int button, bool value) { 90 void SetButton(int button, bool value) {
74 std::lock_guard lock{mutex}; 91 std::lock_guard lock{mutex};
75 state.buttons.insert_or_assign(button, value); 92 state.buttons.insert_or_assign(button, value);
76 } 93 }
77 94
95 void SetMotion(SDL_ControllerSensorEvent event) {
96 constexpr float gravity_constant = 9.80665f;
97 std::lock_guard lock{mutex};
98 u64 time_difference = event.timestamp - last_motion_update;
99 last_motion_update = event.timestamp;
100 switch (event.sensor) {
101 case SDL_SENSOR_ACCEL: {
102 const Common::Vec3f acceleration = {-event.data[0], event.data[2], -event.data[1]};
103 motion.SetAcceleration(acceleration / gravity_constant);
104 break;
105 }
106 case SDL_SENSOR_GYRO: {
107 const Common::Vec3f gyroscope = {event.data[0], -event.data[2], event.data[1]};
108 motion.SetGyroscope(gyroscope / (Common::PI * 2));
109 break;
110 }
111 }
112
113 // Ignore duplicated timestamps
114 if (time_difference == 0) {
115 return;
116 }
117
118 motion.SetGyroThreshold(0.0001f);
119 motion.UpdateRotation(time_difference * 1000);
120 motion.UpdateOrientation(time_difference * 1000);
121 }
122
78 bool GetButton(int button) const { 123 bool GetButton(int button) const {
79 std::lock_guard lock{mutex}; 124 std::lock_guard lock{mutex};
80 return state.buttons.at(button); 125 return state.buttons.at(button);
@@ -121,6 +166,14 @@ public:
121 return std::make_tuple(x, y); 166 return std::make_tuple(x, y);
122 } 167 }
123 168
169 bool HasGyro() const {
170 return has_gyro;
171 }
172
173 bool HasAccel() const {
174 return has_accel;
175 }
176
124 const MotionInput& GetMotion() const { 177 const MotionInput& GetMotion() const {
125 return motion; 178 return motion;
126 } 179 }
@@ -173,8 +226,11 @@ private:
173 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; 226 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
174 mutable std::mutex mutex; 227 mutable std::mutex mutex;
175 228
176 // Motion is initialized without PID values as motion input is not aviable for SDL2 229 // Motion is initialized with the PID values
177 MotionInput motion{0.0f, 0.0f, 0.0f}; 230 MotionInput motion{0.3f, 0.005f, 0.0f};
231 u64 last_motion_update{};
232 bool has_gyro{false};
233 bool has_accel{false};
178}; 234};
179 235
180std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { 236std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
@@ -298,6 +354,12 @@ void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
298 } 354 }
299 break; 355 break;
300 } 356 }
357 case SDL_CONTROLLERSENSORUPDATE: {
358 if (auto joystick = GetSDLJoystickBySDLID(event.csensor.which)) {
359 joystick->SetMotion(event.csensor);
360 }
361 break;
362 }
301 case SDL_JOYDEVICEREMOVED: 363 case SDL_JOYDEVICEREMOVED:
302 LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); 364 LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which);
303 CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); 365 CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which));
@@ -451,6 +513,18 @@ private:
451 std::shared_ptr<SDLJoystick> joystick; 513 std::shared_ptr<SDLJoystick> joystick;
452}; 514};
453 515
516class SDLMotion final : public Input::MotionDevice {
517public:
518 explicit SDLMotion(std::shared_ptr<SDLJoystick> joystick_) : joystick(std::move(joystick_)) {}
519
520 Input::MotionStatus GetStatus() const override {
521 return joystick->GetMotion().GetMotion();
522 }
523
524private:
525 std::shared_ptr<SDLJoystick> joystick;
526};
527
454class SDLDirectionMotion final : public Input::MotionDevice { 528class SDLDirectionMotion final : public Input::MotionDevice {
455public: 529public:
456 explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_) 530 explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
@@ -660,6 +734,10 @@ public:
660 734
661 auto joystick = state.GetSDLJoystickByGUID(guid, port); 735 auto joystick = state.GetSDLJoystickByGUID(guid, port);
662 736
737 if (params.Has("motion")) {
738 return std::make_unique<SDLMotion>(joystick);
739 }
740
663 if (params.Has("hat")) { 741 if (params.Has("hat")) {
664 const int hat = params.Get("hat", 0); 742 const int hat = params.Get("hat", 0);
665 const std::string direction_name = params.Get("direction", ""); 743 const std::string direction_name = params.Get("direction", "");
@@ -719,6 +797,17 @@ SDLState::SDLState() {
719 RegisterFactory<VibrationDevice>("sdl", vibration_factory); 797 RegisterFactory<VibrationDevice>("sdl", vibration_factory);
720 RegisterFactory<MotionDevice>("sdl", motion_factory); 798 RegisterFactory<MotionDevice>("sdl", motion_factory);
721 799
800 // Enable HIDAPI rumble. This prevents SDL from disabling motion on PS4 and PS5 controllers
801 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
802 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
803
804 // Tell SDL2 to use the hidapi driver. This will allow joycons to be detected as a
805 // GameController and not a generic one
806 SDL_SetHint("SDL_JOYSTICK_HIDAPI_JOY_CONS", "1");
807
808 // Turn off Pro controller home led
809 SDL_SetHint("SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED", "0");
810
722 // If the frontend is going to manage the event loop, then we don't start one here 811 // If the frontend is going to manage the event loop, then we don't start one here
723 start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0; 812 start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0;
724 if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) { 813 if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) {
@@ -855,6 +944,13 @@ Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s
855 return params; 944 return params;
856} 945}
857 946
947Common::ParamPackage BuildMotionParam(int port, std::string guid) {
948 Common::ParamPackage params({{"engine", "sdl"}, {"motion", "0"}});
949 params.Set("port", port);
950 params.Set("guid", std::move(guid));
951 return params;
952}
953
858Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { 954Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
859 switch (event.type) { 955 switch (event.type) {
860 case SDL_JOYAXISMOTION: { 956 case SDL_JOYAXISMOTION: {
@@ -909,6 +1005,35 @@ Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Eve
909 } 1005 }
910 break; 1006 break;
911 } 1007 }
1008 case SDL_CONTROLLERSENSORUPDATE: {
1009 bool is_motion_shaking = false;
1010 constexpr float gyro_threshold = 5.0f;
1011 constexpr float accel_threshold = 11.0f;
1012 if (event.csensor.sensor == SDL_SENSOR_ACCEL) {
1013 const Common::Vec3f acceleration = {-event.csensor.data[0], event.csensor.data[2],
1014 -event.csensor.data[1]};
1015 if (acceleration.Length() > accel_threshold) {
1016 is_motion_shaking = true;
1017 }
1018 }
1019
1020 if (event.csensor.sensor == SDL_SENSOR_GYRO) {
1021 const Common::Vec3f gyroscope = {event.csensor.data[0], -event.csensor.data[2],
1022 event.csensor.data[1]};
1023 if (gyroscope.Length() > gyro_threshold) {
1024 is_motion_shaking = true;
1025 }
1026 }
1027
1028 if (!is_motion_shaking) {
1029 break;
1030 }
1031
1032 if (const auto joystick = state.GetSDLJoystickBySDLID(event.csensor.which)) {
1033 return BuildMotionParam(joystick->GetPort(), joystick->GetGUID());
1034 }
1035 break;
1036 }
912 } 1037 }
913 return {}; 1038 return {};
914} 1039}
@@ -1038,6 +1163,27 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa
1038 return mapping; 1163 return mapping;
1039} 1164}
1040 1165
1166MotionMapping SDLState::GetMotionMappingForDevice(const Common::ParamPackage& params) {
1167 if (!params.Has("guid") || !params.Has("port")) {
1168 return {};
1169 }
1170 const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
1171 auto* controller = joystick->GetSDLGameController();
1172 if (controller == nullptr) {
1173 return {};
1174 }
1175
1176 joystick->EnableMotion();
1177
1178 if (!joystick->HasGyro() && !joystick->HasAccel()) {
1179 return {};
1180 }
1181
1182 MotionMapping mapping = {};
1183 mapping.insert_or_assign(Settings::NativeMotion::MotionLeft,
1184 BuildMotionParam(joystick->GetPort(), joystick->GetGUID()));
1185 return mapping;
1186}
1041namespace Polling { 1187namespace Polling {
1042class SDLPoller : public InputCommon::Polling::DevicePoller { 1188class SDLPoller : public InputCommon::Polling::DevicePoller {
1043public: 1189public:
@@ -1151,6 +1297,7 @@ public:
1151 [[fallthrough]]; 1297 [[fallthrough]];
1152 case SDL_JOYBUTTONUP: 1298 case SDL_JOYBUTTONUP:
1153 case SDL_JOYHATMOTION: 1299 case SDL_JOYHATMOTION:
1300 case SDL_CONTROLLERSENSORUPDATE:
1154 return {SDLEventToMotionParamPackage(state, event)}; 1301 return {SDLEventToMotionParamPackage(state, event)};
1155 } 1302 }
1156 return std::nullopt; 1303 return std::nullopt;
diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h
index 8b7363f56..121e01913 100644
--- a/src/input_common/sdl/sdl_impl.h
+++ b/src/input_common/sdl/sdl_impl.h
@@ -57,6 +57,7 @@ public:
57 57
58 ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; 58 ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override;
59 AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; 59 AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override;
60 MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& params) override;
60 61
61private: 62private:
62 void InitJoystick(int joystick_index); 63 void InitJoystick(int joystick_index);