diff options
| author | 2021-04-25 18:03:57 -0500 | |
|---|---|---|
| committer | 2021-05-15 08:56:58 -0500 | |
| commit | f20f4587e65160a193f336c98cfcb03af3aef256 (patch) | |
| tree | 14d75f5a675c243277b8948262dc5e4f934e91c0 /src/input_common/sdl/sdl_impl.cpp | |
| parent | Merge pull request #6300 from Morph1984/mbedtls (diff) | |
| download | yuzu-f20f4587e65160a193f336c98cfcb03af3aef256.tar.gz yuzu-f20f4587e65160a193f336c98cfcb03af3aef256.tar.xz yuzu-f20f4587e65160a193f336c98cfcb03af3aef256.zip | |
input_common: Implement SDL motion
Diffstat (limited to '')
| -rw-r--r-- | src/input_common/sdl/sdl_impl.cpp | 153 |
1 files changed, 150 insertions, 3 deletions
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index f682a6db4..822d0b555 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 | ||
| 180 | std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { | 236 | std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { |
| @@ -296,6 +352,12 @@ void SDLState::HandleGameControllerEvent(const SDL_Event& event) { | |||
| 296 | } | 352 | } |
| 297 | break; | 353 | break; |
| 298 | } | 354 | } |
| 355 | case SDL_CONTROLLERSENSORUPDATE: { | ||
| 356 | if (auto joystick = GetSDLJoystickBySDLID(event.csensor.which)) { | ||
| 357 | joystick->SetMotion(event.csensor); | ||
| 358 | } | ||
| 359 | break; | ||
| 360 | } | ||
| 299 | case SDL_JOYDEVICEREMOVED: | 361 | case SDL_JOYDEVICEREMOVED: |
| 300 | LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); | 362 | LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); |
| 301 | CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); | 363 | CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); |
| @@ -449,6 +511,18 @@ private: | |||
| 449 | std::shared_ptr<SDLJoystick> joystick; | 511 | std::shared_ptr<SDLJoystick> joystick; |
| 450 | }; | 512 | }; |
| 451 | 513 | ||
| 514 | class SDLMotion final : public Input::MotionDevice { | ||
| 515 | public: | ||
| 516 | explicit SDLMotion(std::shared_ptr<SDLJoystick> joystick_) : joystick(std::move(joystick_)) {} | ||
| 517 | |||
| 518 | Input::MotionStatus GetStatus() const override { | ||
| 519 | return joystick->GetMotion().GetMotion(); | ||
| 520 | } | ||
| 521 | |||
| 522 | private: | ||
| 523 | std::shared_ptr<SDLJoystick> joystick; | ||
| 524 | }; | ||
| 525 | |||
| 452 | class SDLDirectionMotion final : public Input::MotionDevice { | 526 | class SDLDirectionMotion final : public Input::MotionDevice { |
| 453 | public: | 527 | public: |
| 454 | explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_) | 528 | explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_) |
| @@ -658,6 +732,10 @@ public: | |||
| 658 | 732 | ||
| 659 | auto joystick = state.GetSDLJoystickByGUID(guid, port); | 733 | auto joystick = state.GetSDLJoystickByGUID(guid, port); |
| 660 | 734 | ||
| 735 | if (params.Has("motion")) { | ||
| 736 | return std::make_unique<SDLMotion>(joystick); | ||
| 737 | } | ||
| 738 | |||
| 661 | if (params.Has("hat")) { | 739 | if (params.Has("hat")) { |
| 662 | const int hat = params.Get("hat", 0); | 740 | const int hat = params.Get("hat", 0); |
| 663 | const std::string direction_name = params.Get("direction", ""); | 741 | const std::string direction_name = params.Get("direction", ""); |
| @@ -717,6 +795,17 @@ SDLState::SDLState() { | |||
| 717 | RegisterFactory<VibrationDevice>("sdl", vibration_factory); | 795 | RegisterFactory<VibrationDevice>("sdl", vibration_factory); |
| 718 | RegisterFactory<MotionDevice>("sdl", motion_factory); | 796 | RegisterFactory<MotionDevice>("sdl", motion_factory); |
| 719 | 797 | ||
| 798 | // Enable HIDAPI rumble. This prevents SDL from disabling motion on PS4 and PS5 controllers | ||
| 799 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); | ||
| 800 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); | ||
| 801 | |||
| 802 | // Tell SDL2 to use the hidapi driver. This will allow joycons to be detected as a | ||
| 803 | // GameController and not a generic one | ||
| 804 | SDL_SetHint("SDL_JOYSTICK_HIDAPI_JOY_CONS", "1"); | ||
| 805 | |||
| 806 | // Turn off Pro controller home led | ||
| 807 | SDL_SetHint("SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED", "0"); | ||
| 808 | |||
| 720 | // If the frontend is going to manage the event loop, then we don't start one here | 809 | // If the frontend is going to manage the event loop, then we don't start one here |
| 721 | start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0; | 810 | start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0; |
| 722 | if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) { | 811 | if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) { |
| @@ -853,6 +942,13 @@ Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s | |||
| 853 | return params; | 942 | return params; |
| 854 | } | 943 | } |
| 855 | 944 | ||
| 945 | Common::ParamPackage BuildMotionParam(int port, std::string guid) { | ||
| 946 | Common::ParamPackage params({{"engine", "sdl"}, {"motion", "0"}}); | ||
| 947 | params.Set("port", port); | ||
| 948 | params.Set("guid", std::move(guid)); | ||
| 949 | return params; | ||
| 950 | } | ||
| 951 | |||
| 856 | Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { | 952 | Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { |
| 857 | switch (event.type) { | 953 | switch (event.type) { |
| 858 | case SDL_JOYAXISMOTION: { | 954 | case SDL_JOYAXISMOTION: { |
| @@ -907,6 +1003,35 @@ Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Eve | |||
| 907 | } | 1003 | } |
| 908 | break; | 1004 | break; |
| 909 | } | 1005 | } |
| 1006 | case SDL_CONTROLLERSENSORUPDATE: { | ||
| 1007 | bool is_motion_shaking = false; | ||
| 1008 | constexpr float gyro_threshold = 5.0f; | ||
| 1009 | constexpr float accel_threshold = 11.0f; | ||
| 1010 | if (event.csensor.sensor == SDL_SENSOR_ACCEL) { | ||
| 1011 | const Common::Vec3f acceleration = {-event.csensor.data[0], event.csensor.data[2], | ||
| 1012 | -event.csensor.data[1]}; | ||
| 1013 | if (acceleration.Length() > accel_threshold) { | ||
| 1014 | is_motion_shaking = true; | ||
| 1015 | } | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | if (event.csensor.sensor == SDL_SENSOR_GYRO) { | ||
| 1019 | const Common::Vec3f gyroscope = {event.csensor.data[0], -event.csensor.data[2], | ||
| 1020 | event.csensor.data[1]}; | ||
| 1021 | if (gyroscope.Length() > gyro_threshold) { | ||
| 1022 | is_motion_shaking = true; | ||
| 1023 | } | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | if (!is_motion_shaking) { | ||
| 1027 | break; | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | if (const auto joystick = state.GetSDLJoystickBySDLID(event.csensor.which)) { | ||
| 1031 | return BuildMotionParam(joystick->GetPort(), joystick->GetGUID()); | ||
| 1032 | } | ||
| 1033 | break; | ||
| 1034 | } | ||
| 910 | } | 1035 | } |
| 911 | return {}; | 1036 | return {}; |
| 912 | } | 1037 | } |
| @@ -1036,6 +1161,27 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa | |||
| 1036 | return mapping; | 1161 | return mapping; |
| 1037 | } | 1162 | } |
| 1038 | 1163 | ||
| 1164 | MotionMapping SDLState::GetMotionMappingForDevice(const Common::ParamPackage& params) { | ||
| 1165 | if (!params.Has("guid") || !params.Has("port")) { | ||
| 1166 | return {}; | ||
| 1167 | } | ||
| 1168 | const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); | ||
| 1169 | auto* controller = joystick->GetSDLGameController(); | ||
| 1170 | if (controller == nullptr) { | ||
| 1171 | return {}; | ||
| 1172 | } | ||
| 1173 | |||
| 1174 | joystick->EnableMotion(); | ||
| 1175 | |||
| 1176 | if (!joystick->HasGyro() && !joystick->HasAccel()) { | ||
| 1177 | return {}; | ||
| 1178 | } | ||
| 1179 | |||
| 1180 | MotionMapping mapping = {}; | ||
| 1181 | mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, | ||
| 1182 | BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); | ||
| 1183 | return mapping; | ||
| 1184 | } | ||
| 1039 | namespace Polling { | 1185 | namespace Polling { |
| 1040 | class SDLPoller : public InputCommon::Polling::DevicePoller { | 1186 | class SDLPoller : public InputCommon::Polling::DevicePoller { |
| 1041 | public: | 1187 | public: |
| @@ -1149,6 +1295,7 @@ public: | |||
| 1149 | [[fallthrough]]; | 1295 | [[fallthrough]]; |
| 1150 | case SDL_JOYBUTTONUP: | 1296 | case SDL_JOYBUTTONUP: |
| 1151 | case SDL_JOYHATMOTION: | 1297 | case SDL_JOYHATMOTION: |
| 1298 | case SDL_CONTROLLERSENSORUPDATE: | ||
| 1152 | return {SDLEventToMotionParamPackage(state, event)}; | 1299 | return {SDLEventToMotionParamPackage(state, event)}; |
| 1153 | } | 1300 | } |
| 1154 | return std::nullopt; | 1301 | return std::nullopt; |