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.cpp300
1 files changed, 264 insertions, 36 deletions
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index a9e676f4b..9c3035920 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -5,6 +5,7 @@
5#include <algorithm> 5#include <algorithm>
6#include <array> 6#include <array>
7#include <atomic> 7#include <atomic>
8#include <chrono>
8#include <cmath> 9#include <cmath>
9#include <functional> 10#include <functional>
10#include <mutex> 11#include <mutex>
@@ -21,6 +22,7 @@
21#include "common/param_package.h" 22#include "common/param_package.h"
22#include "common/threadsafe_queue.h" 23#include "common/threadsafe_queue.h"
23#include "core/frontend/input.h" 24#include "core/frontend/input.h"
25#include "input_common/motion_input.h"
24#include "input_common/sdl/sdl_impl.h" 26#include "input_common/sdl/sdl_impl.h"
25#include "input_common/settings.h" 27#include "input_common/settings.h"
26 28
@@ -54,9 +56,9 @@ static int SDLEventWatcher(void* user_data, SDL_Event* event) {
54class SDLJoystick { 56class SDLJoystick {
55public: 57public:
56 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, 58 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick,
57 SDL_GameController* gamecontroller) 59 SDL_GameController* game_controller)
58 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose}, 60 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose},
59 sdl_controller{gamecontroller, &SDL_GameControllerClose} {} 61 sdl_controller{game_controller, &SDL_GameControllerClose} {}
60 62
61 void SetButton(int button, bool value) { 63 void SetButton(int button, bool value) {
62 std::lock_guard lock{mutex}; 64 std::lock_guard lock{mutex};
@@ -75,7 +77,34 @@ public:
75 77
76 float GetAxis(int axis, float range) const { 78 float GetAxis(int axis, float range) const {
77 std::lock_guard lock{mutex}; 79 std::lock_guard lock{mutex};
78 return state.axes.at(axis) / (32767.0f * range); 80 return static_cast<float>(state.axes.at(axis)) / (32767.0f * range);
81 }
82
83 bool RumblePlay(f32 amp_low, f32 amp_high, u32 time) {
84 const u16 raw_amp_low = static_cast<u16>(amp_low * 0xFFFF);
85 const u16 raw_amp_high = static_cast<u16>(amp_high * 0xFFFF);
86 // Lower drastically the number of state changes
87 if (raw_amp_low >> 11 == last_state_rumble_low >> 11 &&
88 raw_amp_high >> 11 == last_state_rumble_high >> 11) {
89 if (raw_amp_low + raw_amp_high != 0 ||
90 last_state_rumble_low + last_state_rumble_high == 0) {
91 return false;
92 }
93 }
94 // Don't change state if last vibration was < 20ms
95 const auto now = std::chrono::system_clock::now();
96 if (std::chrono::duration_cast<std::chrono::milliseconds>(now - last_vibration) <
97 std::chrono::milliseconds(20)) {
98 return raw_amp_low + raw_amp_high == 0;
99 }
100
101 last_vibration = now;
102 last_state_rumble_low = raw_amp_low;
103 last_state_rumble_high = raw_amp_high;
104 if (sdl_joystick) {
105 SDL_JoystickRumble(sdl_joystick.get(), raw_amp_low, raw_amp_high, time);
106 }
107 return false;
79 } 108 }
80 109
81 std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range) const { 110 std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range) const {
@@ -95,6 +124,10 @@ public:
95 return std::make_tuple(x, y); 124 return std::make_tuple(x, y);
96 } 125 }
97 126
127 const MotionInput& GetMotion() const {
128 return motion;
129 }
130
98 void SetHat(int hat, Uint8 direction) { 131 void SetHat(int hat, Uint8 direction) {
99 std::lock_guard lock{mutex}; 132 std::lock_guard lock{mutex};
100 state.hats.insert_or_assign(hat, direction); 133 state.hats.insert_or_assign(hat, direction);
@@ -139,9 +172,15 @@ private:
139 } state; 172 } state;
140 std::string guid; 173 std::string guid;
141 int port; 174 int port;
175 u16 last_state_rumble_high = 0;
176 u16 last_state_rumble_low = 0;
177 std::chrono::time_point<std::chrono::system_clock> last_vibration;
142 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; 178 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
143 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; 179 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
144 mutable std::mutex mutex; 180 mutable std::mutex mutex;
181
182 // Motion is initialized without PID values as motion input is not aviable for SDL2
183 MotionInput motion{0.0f, 0.0f, 0.0f};
145}; 184};
146 185
147std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { 186std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
@@ -153,7 +192,7 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& g
153 nullptr, nullptr); 192 nullptr, nullptr);
154 it->second.emplace_back(std::move(joystick)); 193 it->second.emplace_back(std::move(joystick));
155 } 194 }
156 return it->second[port]; 195 return it->second[static_cast<std::size_t>(port)];
157 } 196 }
158 auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, nullptr); 197 auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, nullptr);
159 return joystick_map[guid].emplace_back(std::move(joystick)); 198 return joystick_map[guid].emplace_back(std::move(joystick));
@@ -173,7 +212,7 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_
173 return sdl_joystick == joystick->GetSDLJoystick(); 212 return sdl_joystick == joystick->GetSDLJoystick();
174 }); 213 });
175 if (vec_it != map_it->second.end()) { 214 if (vec_it != map_it->second.end()) {
176 // This is the common case: There is already an existing SDL_Joystick maped to a 215 // This is the common case: There is already an existing SDL_Joystick mapped to a
177 // SDLJoystick. return the SDLJoystick 216 // SDLJoystick. return the SDLJoystick
178 return *vec_it; 217 return *vec_it;
179 } 218 }
@@ -181,7 +220,7 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_
181 // Search for a SDLJoystick without a mapped SDL_Joystick... 220 // Search for a SDLJoystick without a mapped SDL_Joystick...
182 const auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(), 221 const auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(),
183 [](const std::shared_ptr<SDLJoystick>& joystick) { 222 [](const std::shared_ptr<SDLJoystick>& joystick) {
184 return !joystick->GetSDLJoystick(); 223 return joystick->GetSDLJoystick() == nullptr;
185 }); 224 });
186 if (nullptr_it != map_it->second.end()) { 225 if (nullptr_it != map_it->second.end()) {
187 // ... and map it 226 // ... and map it
@@ -207,7 +246,7 @@ void SDLState::InitJoystick(int joystick_index) {
207 sdl_gamecontroller = SDL_GameControllerOpen(joystick_index); 246 sdl_gamecontroller = SDL_GameControllerOpen(joystick_index);
208 } 247 }
209 if (!sdl_joystick) { 248 if (!sdl_joystick) {
210 LOG_ERROR(Input, "failed to open joystick {}", joystick_index); 249 LOG_ERROR(Input, "Failed to open joystick {}", joystick_index);
211 return; 250 return;
212 } 251 }
213 const std::string guid = GetGUID(sdl_joystick); 252 const std::string guid = GetGUID(sdl_joystick);
@@ -234,22 +273,19 @@ void SDLState::InitJoystick(int joystick_index) {
234void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) { 273void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
235 const std::string guid = GetGUID(sdl_joystick); 274 const std::string guid = GetGUID(sdl_joystick);
236 275
237 std::shared_ptr<SDLJoystick> joystick; 276 std::lock_guard lock{joystick_map_mutex};
238 { 277 auto& joystick_guid_list = joystick_map[guid];
239 std::lock_guard lock{joystick_map_mutex}; 278 auto joystick_it = std::find_if(
240 // This call to guid is safe since the joystick is guaranteed to be in the map 279 joystick_guid_list.begin(), joystick_guid_list.end(),
241 const auto& joystick_guid_list = joystick_map[guid]; 280 [&sdl_joystick](auto& joystick) { return joystick->GetSDLJoystick() == sdl_joystick; });
242 const auto joystick_it =
243 std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
244 [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) {
245 return joystick->GetSDLJoystick() == sdl_joystick;
246 });
247 joystick = *joystick_it;
248 }
249 281
250 // Destruct SDL_Joystick outside the lock guard because SDL can internally call the 282 if (joystick_it != joystick_guid_list.end()) {
251 // event callback which locks the mutex again. 283 (*joystick_it)->SetSDLJoystick(nullptr, nullptr);
252 joystick->SetSDLJoystick(nullptr, nullptr); 284 joystick_guid_list.erase(joystick_it);
285 if (joystick_guid_list.empty()) {
286 joystick_map.erase(guid);
287 }
288 }
253} 289}
254 290
255void SDLState::HandleGameControllerEvent(const SDL_Event& event) { 291void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
@@ -303,6 +339,12 @@ public:
303 return joystick->GetButton(button); 339 return joystick->GetButton(button);
304 } 340 }
305 341
342 bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const override {
343 const f32 new_amp_low = pow(amp_low, 0.5f) * (3.0f - 2.0f * pow(amp_low, 0.15f));
344 const f32 new_amp_high = pow(amp_high, 0.5f) * (3.0f - 2.0f * pow(amp_high, 0.15f));
345 return joystick->RumblePlay(new_amp_low, new_amp_high, 250);
346 }
347
306private: 348private:
307 std::shared_ptr<SDLJoystick> joystick; 349 std::shared_ptr<SDLJoystick> joystick;
308 int button; 350 int button;
@@ -347,8 +389,8 @@ private:
347 389
348class SDLAnalog final : public Input::AnalogDevice { 390class SDLAnalog final : public Input::AnalogDevice {
349public: 391public:
350 SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, float deadzone_, 392 explicit SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_,
351 float range_) 393 float deadzone_, float range_)
352 : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), 394 : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_),
353 range(range_) {} 395 range(range_) {}
354 396
@@ -386,6 +428,68 @@ private:
386 const float range; 428 const float range;
387}; 429};
388 430
431class SDLDirectionMotion final : public Input::MotionDevice {
432public:
433 explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
434 : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {}
435
436 Input::MotionStatus GetStatus() const override {
437 if (joystick->GetHatDirection(hat, direction)) {
438 return joystick->GetMotion().GetRandomMotion(2, 6);
439 }
440 return joystick->GetMotion().GetRandomMotion(0, 0);
441 }
442
443private:
444 std::shared_ptr<SDLJoystick> joystick;
445 int hat;
446 Uint8 direction;
447};
448
449class SDLAxisMotion final : public Input::MotionDevice {
450public:
451 explicit SDLAxisMotion(std::shared_ptr<SDLJoystick> joystick_, int axis_, float threshold_,
452 bool trigger_if_greater_)
453 : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_),
454 trigger_if_greater(trigger_if_greater_) {}
455
456 Input::MotionStatus GetStatus() const override {
457 const float axis_value = joystick->GetAxis(axis, 1.0f);
458 bool trigger = axis_value < threshold;
459 if (trigger_if_greater) {
460 trigger = axis_value > threshold;
461 }
462
463 if (trigger) {
464 return joystick->GetMotion().GetRandomMotion(2, 6);
465 }
466 return joystick->GetMotion().GetRandomMotion(0, 0);
467 }
468
469private:
470 std::shared_ptr<SDLJoystick> joystick;
471 int axis;
472 float threshold;
473 bool trigger_if_greater;
474};
475
476class SDLButtonMotion final : public Input::MotionDevice {
477public:
478 explicit SDLButtonMotion(std::shared_ptr<SDLJoystick> joystick_, int button_)
479 : joystick(std::move(joystick_)), button(button_) {}
480
481 Input::MotionStatus GetStatus() const override {
482 if (joystick->GetButton(button)) {
483 return joystick->GetMotion().GetRandomMotion(2, 6);
484 }
485 return joystick->GetMotion().GetRandomMotion(0, 0);
486 }
487
488private:
489 std::shared_ptr<SDLJoystick> joystick;
490 int button;
491};
492
389/// A button device factory that creates button devices from SDL joystick 493/// A button device factory that creates button devices from SDL joystick
390class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> { 494class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> {
391public: 495public:
@@ -492,20 +596,86 @@ private:
492 SDLState& state; 596 SDLState& state;
493}; 597};
494 598
599/// A motion device factory that creates motion devices from SDL joystick
600class SDLMotionFactory final : public Input::Factory<Input::MotionDevice> {
601public:
602 explicit SDLMotionFactory(SDLState& state_) : state(state_) {}
603 /**
604 * Creates motion device from joystick axes
605 * @param params contains parameters for creating the device:
606 * - "guid": the guid of the joystick to bind
607 * - "port": the nth joystick of the same type
608 */
609 std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override {
610 const std::string guid = params.Get("guid", "0");
611 const int port = params.Get("port", 0);
612
613 auto joystick = state.GetSDLJoystickByGUID(guid, port);
614
615 if (params.Has("hat")) {
616 const int hat = params.Get("hat", 0);
617 const std::string direction_name = params.Get("direction", "");
618 Uint8 direction;
619 if (direction_name == "up") {
620 direction = SDL_HAT_UP;
621 } else if (direction_name == "down") {
622 direction = SDL_HAT_DOWN;
623 } else if (direction_name == "left") {
624 direction = SDL_HAT_LEFT;
625 } else if (direction_name == "right") {
626 direction = SDL_HAT_RIGHT;
627 } else {
628 direction = 0;
629 }
630 // This is necessary so accessing GetHat with hat won't crash
631 joystick->SetHat(hat, SDL_HAT_CENTERED);
632 return std::make_unique<SDLDirectionMotion>(joystick, hat, direction);
633 }
634
635 if (params.Has("axis")) {
636 const int axis = params.Get("axis", 0);
637 const float threshold = params.Get("threshold", 0.5f);
638 const std::string direction_name = params.Get("direction", "");
639 bool trigger_if_greater;
640 if (direction_name == "+") {
641 trigger_if_greater = true;
642 } else if (direction_name == "-") {
643 trigger_if_greater = false;
644 } else {
645 trigger_if_greater = true;
646 LOG_ERROR(Input, "Unknown direction {}", direction_name);
647 }
648 // This is necessary so accessing GetAxis with axis won't crash
649 joystick->SetAxis(axis, 0);
650 return std::make_unique<SDLAxisMotion>(joystick, axis, threshold, trigger_if_greater);
651 }
652
653 const int button = params.Get("button", 0);
654 // This is necessary so accessing GetButton with button won't crash
655 joystick->SetButton(button, false);
656 return std::make_unique<SDLButtonMotion>(joystick, button);
657 }
658
659private:
660 SDLState& state;
661};
662
495SDLState::SDLState() { 663SDLState::SDLState() {
496 using namespace Input; 664 using namespace Input;
497 analog_factory = std::make_shared<SDLAnalogFactory>(*this); 665 analog_factory = std::make_shared<SDLAnalogFactory>(*this);
498 button_factory = std::make_shared<SDLButtonFactory>(*this); 666 button_factory = std::make_shared<SDLButtonFactory>(*this);
667 motion_factory = std::make_shared<SDLMotionFactory>(*this);
499 RegisterFactory<AnalogDevice>("sdl", analog_factory); 668 RegisterFactory<AnalogDevice>("sdl", analog_factory);
500 RegisterFactory<ButtonDevice>("sdl", button_factory); 669 RegisterFactory<ButtonDevice>("sdl", button_factory);
670 RegisterFactory<MotionDevice>("sdl", motion_factory);
501 671
502 // If the frontend is going to manage the event loop, then we dont start one here 672 // If the frontend is going to manage the event loop, then we don't start one here
503 start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK); 673 start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0;
504 if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) { 674 if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) {
505 LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError()); 675 LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError());
506 return; 676 return;
507 } 677 }
508 has_gamecontroller = SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER); 678 has_gamecontroller = SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0;
509 if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) { 679 if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) {
510 LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError()); 680 LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError());
511 } 681 }
@@ -533,6 +703,7 @@ SDLState::~SDLState() {
533 using namespace Input; 703 using namespace Input;
534 UnregisterFactory<ButtonDevice>("sdl"); 704 UnregisterFactory<ButtonDevice>("sdl");
535 UnregisterFactory<AnalogDevice>("sdl"); 705 UnregisterFactory<AnalogDevice>("sdl");
706 UnregisterFactory<MotionDevice>("sdl");
536 707
537 CloseJoysticks(); 708 CloseJoysticks();
538 SDL_DelEventWatch(&SDLEventWatcher, this); 709 SDL_DelEventWatch(&SDLEventWatcher, this);
@@ -549,8 +720,8 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
549 std::vector<Common::ParamPackage> devices; 720 std::vector<Common::ParamPackage> devices;
550 for (const auto& [key, value] : joystick_map) { 721 for (const auto& [key, value] : joystick_map) {
551 for (const auto& joystick : value) { 722 for (const auto& joystick : value) {
552 auto joy = joystick->GetSDLJoystick(); 723 auto* joy = joystick->GetSDLJoystick();
553 if (auto controller = joystick->GetSDLGameController()) { 724 if (auto* controller = joystick->GetSDLGameController()) {
554 std::string name = 725 std::string name =
555 fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort()); 726 fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort());
556 devices.emplace_back(Common::ParamPackage{ 727 devices.emplace_back(Common::ParamPackage{
@@ -574,7 +745,7 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
574} 745}
575 746
576namespace { 747namespace {
577Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, u8 axis, 748Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis,
578 float value = 0.1f) { 749 float value = 0.1f) {
579 Common::ParamPackage params({{"engine", "sdl"}}); 750 Common::ParamPackage params({{"engine", "sdl"}});
580 params.Set("port", port); 751 params.Set("port", port);
@@ -590,7 +761,7 @@ Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid
590 return params; 761 return params;
591} 762}
592 763
593Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, u8 button) { 764Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, s32 button) {
594 Common::ParamPackage params({{"engine", "sdl"}}); 765 Common::ParamPackage params({{"engine", "sdl"}});
595 params.Set("port", port); 766 params.Set("port", port);
596 params.Set("guid", std::move(guid)); 767 params.Set("guid", std::move(guid));
@@ -598,7 +769,7 @@ Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid
598 return params; 769 return params;
599} 770}
600 771
601Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, u8 hat, u8 value) { 772Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s32 hat, s32 value) {
602 Common::ParamPackage params({{"engine", "sdl"}}); 773 Common::ParamPackage params({{"engine", "sdl"}});
603 774
604 params.Set("port", port); 775 params.Set("port", port);
@@ -628,17 +799,42 @@ Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Eve
628 case SDL_JOYAXISMOTION: { 799 case SDL_JOYAXISMOTION: {
629 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); 800 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
630 return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), 801 return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
631 event.jaxis.axis, event.jaxis.value); 802 static_cast<s32>(event.jaxis.axis),
803 event.jaxis.value);
804 }
805 case SDL_JOYBUTTONUP: {
806 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
807 return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
808 static_cast<s32>(event.jbutton.button));
809 }
810 case SDL_JOYHATMOTION: {
811 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
812 return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
813 static_cast<s32>(event.jhat.hat),
814 static_cast<s32>(event.jhat.value));
815 }
816 }
817 return {};
818}
819
820Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Event& event) {
821 switch (event.type) {
822 case SDL_JOYAXISMOTION: {
823 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
824 return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
825 static_cast<s32>(event.jaxis.axis),
826 event.jaxis.value);
632 } 827 }
633 case SDL_JOYBUTTONUP: { 828 case SDL_JOYBUTTONUP: {
634 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which); 829 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
635 return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), 830 return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
636 event.jbutton.button); 831 static_cast<s32>(event.jbutton.button));
637 } 832 }
638 case SDL_JOYHATMOTION: { 833 case SDL_JOYHATMOTION: {
639 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which); 834 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
640 return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), 835 return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
641 event.jhat.hat, event.jhat.value); 836 static_cast<s32>(event.jhat.hat),
837 static_cast<s32>(event.jhat.value));
642 } 838 }
643 } 839 }
644 return {}; 840 return {};
@@ -809,6 +1005,35 @@ public:
809 } 1005 }
810}; 1006};
811 1007
1008class SDLMotionPoller final : public SDLPoller {
1009public:
1010 explicit SDLMotionPoller(SDLState& state_) : SDLPoller(state_) {}
1011
1012 Common::ParamPackage GetNextInput() override {
1013 SDL_Event event;
1014 while (state.event_queue.Pop(event)) {
1015 const auto package = FromEvent(event);
1016 if (package) {
1017 return *package;
1018 }
1019 }
1020 return {};
1021 }
1022 [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const {
1023 switch (event.type) {
1024 case SDL_JOYAXISMOTION:
1025 if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
1026 break;
1027 }
1028 [[fallthrough]];
1029 case SDL_JOYBUTTONUP:
1030 case SDL_JOYHATMOTION:
1031 return {SDLEventToMotionParamPackage(state, event)};
1032 }
1033 return std::nullopt;
1034 }
1035};
1036
812/** 1037/**
813 * Attempts to match the press to a controller joy axis (left/right stick) and if a match 1038 * Attempts to match the press to a controller joy axis (left/right stick) and if a match
814 * isn't found, checks if the event matches anything from SDLButtonPoller and uses that 1039 * isn't found, checks if the event matches anything from SDLButtonPoller and uses that
@@ -838,7 +1063,7 @@ public:
838 if (event.type == SDL_JOYAXISMOTION) { 1063 if (event.type == SDL_JOYAXISMOTION) {
839 const auto axis = event.jaxis.axis; 1064 const auto axis = event.jaxis.axis;
840 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); 1065 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
841 const auto controller = joystick->GetSDLGameController(); 1066 auto* const controller = joystick->GetSDLGameController();
842 if (controller) { 1067 if (controller) {
843 const auto axis_left_x = 1068 const auto axis_left_x =
844 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) 1069 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX)
@@ -900,6 +1125,9 @@ SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
900 case InputCommon::Polling::DeviceType::Button: 1125 case InputCommon::Polling::DeviceType::Button:
901 pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this)); 1126 pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this));
902 break; 1127 break;
1128 case InputCommon::Polling::DeviceType::Motion:
1129 pollers.emplace_back(std::make_unique<Polling::SDLMotionPoller>(*this));
1130 break;
903 } 1131 }
904 1132
905 return pollers; 1133 return pollers;