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.cpp665
1 files changed, 558 insertions, 107 deletions
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 675b477fa..bd480570a 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -3,10 +3,14 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <array>
6#include <atomic> 7#include <atomic>
8#include <chrono>
7#include <cmath> 9#include <cmath>
8#include <functional> 10#include <functional>
9#include <mutex> 11#include <mutex>
12#include <optional>
13#include <sstream>
10#include <string> 14#include <string>
11#include <thread> 15#include <thread>
12#include <tuple> 16#include <tuple>
@@ -15,15 +19,17 @@
15#include <vector> 19#include <vector>
16#include <SDL.h> 20#include <SDL.h>
17#include "common/logging/log.h" 21#include "common/logging/log.h"
18#include "common/math_util.h"
19#include "common/param_package.h" 22#include "common/param_package.h"
20#include "common/threadsafe_queue.h" 23#include "common/threadsafe_queue.h"
21#include "core/frontend/input.h" 24#include "core/frontend/input.h"
25#include "input_common/motion_input.h"
22#include "input_common/sdl/sdl_impl.h" 26#include "input_common/sdl/sdl_impl.h"
27#include "input_common/settings.h"
23 28
24namespace InputCommon::SDL { 29namespace InputCommon::SDL {
25 30
26static std::string GetGUID(SDL_Joystick* joystick) { 31namespace {
32std::string GetGUID(SDL_Joystick* joystick) {
27 const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); 33 const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
28 char guid_str[33]; 34 char guid_str[33];
29 SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); 35 SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str));
@@ -31,7 +37,8 @@ static std::string GetGUID(SDL_Joystick* joystick) {
31} 37}
32 38
33/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice 39/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice
34static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event); 40Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event);
41} // Anonymous namespace
35 42
36static int SDLEventWatcher(void* user_data, SDL_Event* event) { 43static int SDLEventWatcher(void* user_data, SDL_Event* event) {
37 auto* const sdl_state = static_cast<SDLState*>(user_data); 44 auto* const sdl_state = static_cast<SDLState*>(user_data);
@@ -48,8 +55,10 @@ static int SDLEventWatcher(void* user_data, SDL_Event* event) {
48 55
49class SDLJoystick { 56class SDLJoystick {
50public: 57public:
51 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick) 58 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick,
52 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose} {} 59 SDL_GameController* gamecontroller)
60 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose},
61 sdl_controller{gamecontroller, &SDL_GameControllerClose} {}
53 62
54 void SetButton(int button, bool value) { 63 void SetButton(int button, bool value) {
55 std::lock_guard lock{mutex}; 64 std::lock_guard lock{mutex};
@@ -66,14 +75,41 @@ public:
66 state.axes.insert_or_assign(axis, value); 75 state.axes.insert_or_assign(axis, value);
67 } 76 }
68 77
69 float GetAxis(int axis) const { 78 float GetAxis(int axis, float range) const {
70 std::lock_guard lock{mutex}; 79 std::lock_guard lock{mutex};
71 return state.axes.at(axis) / 32767.0f; 80 return state.axes.at(axis) / (32767.0f * range);
72 } 81 }
73 82
74 std::tuple<float, float> GetAnalog(int axis_x, int axis_y) const { 83 bool RumblePlay(f32 amp_low, f32 amp_high, int time) {
75 float x = GetAxis(axis_x); 84 const u16 raw_amp_low = static_cast<u16>(amp_low * 0xFFFF);
76 float y = GetAxis(axis_y); 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;
108 }
109
110 std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range) const {
111 float x = GetAxis(axis_x, range);
112 float y = GetAxis(axis_y, range);
77 y = -y; // 3DS uses an y-axis inverse from SDL 113 y = -y; // 3DS uses an y-axis inverse from SDL
78 114
79 // Make sure the coordinates are in the unit circle, 115 // Make sure the coordinates are in the unit circle,
@@ -88,6 +124,10 @@ public:
88 return std::make_tuple(x, y); 124 return std::make_tuple(x, y);
89 } 125 }
90 126
127 const InputCommon::MotionInput& GetMotion() const {
128 return motion;
129 }
130
91 void SetHat(int hat, Uint8 direction) { 131 void SetHat(int hat, Uint8 direction) {
92 std::lock_guard lock{mutex}; 132 std::lock_guard lock{mutex};
93 state.hats.insert_or_assign(hat, direction); 133 state.hats.insert_or_assign(hat, direction);
@@ -115,10 +155,15 @@ public:
115 return sdl_joystick.get(); 155 return sdl_joystick.get();
116 } 156 }
117 157
118 void SetSDLJoystick(SDL_Joystick* joystick) { 158 void SetSDLJoystick(SDL_Joystick* joystick, SDL_GameController* controller) {
159 sdl_controller.reset(controller);
119 sdl_joystick.reset(joystick); 160 sdl_joystick.reset(joystick);
120 } 161 }
121 162
163 SDL_GameController* GetSDLGameController() const {
164 return sdl_controller.get();
165 }
166
122private: 167private:
123 struct State { 168 struct State {
124 std::unordered_map<int, bool> buttons; 169 std::unordered_map<int, bool> buttons;
@@ -127,8 +172,15 @@ private:
127 } state; 172 } state;
128 std::string guid; 173 std::string guid;
129 int port; 174 int port;
175 u16 last_state_rumble_high;
176 u16 last_state_rumble_low;
177 std::chrono::time_point<std::chrono::system_clock> last_vibration;
130 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; 178 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
179 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
131 mutable std::mutex mutex; 180 mutable std::mutex mutex;
181
182 // motion is initalized without PID values as motion input is not aviable for SDL2
183 InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f};
132}; 184};
133 185
134std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { 186std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
@@ -136,18 +188,19 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& g
136 const auto it = joystick_map.find(guid); 188 const auto it = joystick_map.find(guid);
137 if (it != joystick_map.end()) { 189 if (it != joystick_map.end()) {
138 while (it->second.size() <= static_cast<std::size_t>(port)) { 190 while (it->second.size() <= static_cast<std::size_t>(port)) {
139 auto joystick = 191 auto joystick = std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()),
140 std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()), nullptr); 192 nullptr, nullptr);
141 it->second.emplace_back(std::move(joystick)); 193 it->second.emplace_back(std::move(joystick));
142 } 194 }
143 return it->second[port]; 195 return it->second[port];
144 } 196 }
145 auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr); 197 auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, nullptr);
146 return joystick_map[guid].emplace_back(std::move(joystick)); 198 return joystick_map[guid].emplace_back(std::move(joystick));
147} 199}
148 200
149std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { 201std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
150 auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id); 202 auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
203 auto sdl_controller = SDL_GameControllerFromInstanceID(sdl_id);
151 const std::string guid = GetGUID(sdl_joystick); 204 const std::string guid = GetGUID(sdl_joystick);
152 205
153 std::lock_guard lock{joystick_map_mutex}; 206 std::lock_guard lock{joystick_map_mutex};
@@ -171,32 +224,36 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_
171 }); 224 });
172 if (nullptr_it != map_it->second.end()) { 225 if (nullptr_it != map_it->second.end()) {
173 // ... and map it 226 // ... and map it
174 (*nullptr_it)->SetSDLJoystick(sdl_joystick); 227 (*nullptr_it)->SetSDLJoystick(sdl_joystick, sdl_controller);
175 return *nullptr_it; 228 return *nullptr_it;
176 } 229 }
177 230
178 // There is no SDLJoystick without a mapped SDL_Joystick 231 // There is no SDLJoystick without a mapped SDL_Joystick
179 // Create a new SDLJoystick 232 // Create a new SDLJoystick
180 const int port = static_cast<int>(map_it->second.size()); 233 const int port = static_cast<int>(map_it->second.size());
181 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick); 234 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_controller);
182 return map_it->second.emplace_back(std::move(joystick)); 235 return map_it->second.emplace_back(std::move(joystick));
183 } 236 }
184 237
185 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick); 238 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_controller);
186 return joystick_map[guid].emplace_back(std::move(joystick)); 239 return joystick_map[guid].emplace_back(std::move(joystick));
187} 240}
188 241
189void SDLState::InitJoystick(int joystick_index) { 242void SDLState::InitJoystick(int joystick_index) {
190 SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index); 243 SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
244 SDL_GameController* sdl_gamecontroller = nullptr;
245 if (SDL_IsGameController(joystick_index)) {
246 sdl_gamecontroller = SDL_GameControllerOpen(joystick_index);
247 }
191 if (!sdl_joystick) { 248 if (!sdl_joystick) {
192 LOG_ERROR(Input, "failed to open joystick {}", joystick_index); 249 LOG_ERROR(Input, "Failed to open joystick {}", joystick_index);
193 return; 250 return;
194 } 251 }
195 const std::string guid = GetGUID(sdl_joystick); 252 const std::string guid = GetGUID(sdl_joystick);
196 253
197 std::lock_guard lock{joystick_map_mutex}; 254 std::lock_guard lock{joystick_map_mutex};
198 if (joystick_map.find(guid) == joystick_map.end()) { 255 if (joystick_map.find(guid) == joystick_map.end()) {
199 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick); 256 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);
200 joystick_map[guid].emplace_back(std::move(joystick)); 257 joystick_map[guid].emplace_back(std::move(joystick));
201 return; 258 return;
202 } 259 }
@@ -205,11 +262,11 @@ void SDLState::InitJoystick(int joystick_index) {
205 joystick_guid_list.begin(), joystick_guid_list.end(), 262 joystick_guid_list.begin(), joystick_guid_list.end(),
206 [](const std::shared_ptr<SDLJoystick>& joystick) { return !joystick->GetSDLJoystick(); }); 263 [](const std::shared_ptr<SDLJoystick>& joystick) { return !joystick->GetSDLJoystick(); });
207 if (it != joystick_guid_list.end()) { 264 if (it != joystick_guid_list.end()) {
208 (*it)->SetSDLJoystick(sdl_joystick); 265 (*it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller);
209 return; 266 return;
210 } 267 }
211 const int port = static_cast<int>(joystick_guid_list.size()); 268 const int port = static_cast<int>(joystick_guid_list.size());
212 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick); 269 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
213 joystick_guid_list.emplace_back(std::move(joystick)); 270 joystick_guid_list.emplace_back(std::move(joystick));
214} 271}
215 272
@@ -231,7 +288,7 @@ void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
231 288
232 // Destruct SDL_Joystick outside the lock guard because SDL can internally call the 289 // Destruct SDL_Joystick outside the lock guard because SDL can internally call the
233 // event callback which locks the mutex again. 290 // event callback which locks the mutex again.
234 joystick->SetSDLJoystick(nullptr); 291 joystick->SetSDLJoystick(nullptr, nullptr);
235} 292}
236 293
237void SDLState::HandleGameControllerEvent(const SDL_Event& event) { 294void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
@@ -285,6 +342,12 @@ public:
285 return joystick->GetButton(button); 342 return joystick->GetButton(button);
286 } 343 }
287 344
345 bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const override {
346 const f32 new_amp_low = pow(amp_low, 0.5f) * (3.0f - 2.0f * pow(amp_low, 0.15f));
347 const f32 new_amp_high = pow(amp_high, 0.5f) * (3.0f - 2.0f * pow(amp_high, 0.15f));
348 return joystick->RumblePlay(new_amp_low, new_amp_high, 250);
349 }
350
288private: 351private:
289 std::shared_ptr<SDLJoystick> joystick; 352 std::shared_ptr<SDLJoystick> joystick;
290 int button; 353 int button;
@@ -313,7 +376,7 @@ public:
313 trigger_if_greater(trigger_if_greater_) {} 376 trigger_if_greater(trigger_if_greater_) {}
314 377
315 bool GetStatus() const override { 378 bool GetStatus() const override {
316 const float axis_value = joystick->GetAxis(axis); 379 const float axis_value = joystick->GetAxis(axis, 1.0f);
317 if (trigger_if_greater) { 380 if (trigger_if_greater) {
318 return axis_value > threshold; 381 return axis_value > threshold;
319 } 382 }
@@ -329,22 +392,24 @@ private:
329 392
330class SDLAnalog final : public Input::AnalogDevice { 393class SDLAnalog final : public Input::AnalogDevice {
331public: 394public:
332 SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, float deadzone_) 395 SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, float deadzone_,
333 : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_) {} 396 float range_)
397 : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_),
398 range(range_) {}
334 399
335 std::tuple<float, float> GetStatus() const override { 400 std::tuple<float, float> GetStatus() const override {
336 const auto [x, y] = joystick->GetAnalog(axis_x, axis_y); 401 const auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range);
337 const float r = std::sqrt((x * x) + (y * y)); 402 const float r = std::sqrt((x * x) + (y * y));
338 if (r > deadzone) { 403 if (r > deadzone) {
339 return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone), 404 return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone),
340 y / r * (r - deadzone) / (1 - deadzone)); 405 y / r * (r - deadzone) / (1 - deadzone));
341 } 406 }
342 return std::make_tuple<float, float>(0.0f, 0.0f); 407 return {};
343 } 408 }
344 409
345 bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { 410 bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
346 const auto [x, y] = GetStatus(); 411 const auto [x, y] = GetStatus();
347 const float directional_deadzone = 0.4f; 412 const float directional_deadzone = 0.5f;
348 switch (direction) { 413 switch (direction) {
349 case Input::AnalogDirection::RIGHT: 414 case Input::AnalogDirection::RIGHT:
350 return x > directional_deadzone; 415 return x > directional_deadzone;
@@ -363,6 +428,69 @@ private:
363 const int axis_x; 428 const int axis_x;
364 const int axis_y; 429 const int axis_y;
365 const float deadzone; 430 const float deadzone;
431 const float range;
432};
433
434class SDLDirectionMotion final : public Input::MotionDevice {
435public:
436 explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
437 : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {}
438
439 Input::MotionStatus GetStatus() const override {
440 if (joystick->GetHatDirection(hat, direction)) {
441 return joystick->GetMotion().GetRandomMotion(2, 6);
442 }
443 return joystick->GetMotion().GetRandomMotion(0, 0);
444 }
445
446private:
447 std::shared_ptr<SDLJoystick> joystick;
448 int hat;
449 Uint8 direction;
450};
451
452class SDLAxisMotion final : public Input::MotionDevice {
453public:
454 explicit SDLAxisMotion(std::shared_ptr<SDLJoystick> joystick_, int axis_, float threshold_,
455 bool trigger_if_greater_)
456 : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_),
457 trigger_if_greater(trigger_if_greater_) {}
458
459 Input::MotionStatus GetStatus() const override {
460 const float axis_value = joystick->GetAxis(axis, 1.0f);
461 bool trigger = axis_value < threshold;
462 if (trigger_if_greater) {
463 trigger = axis_value > threshold;
464 }
465
466 if (trigger) {
467 return joystick->GetMotion().GetRandomMotion(2, 6);
468 }
469 return joystick->GetMotion().GetRandomMotion(0, 0);
470 }
471
472private:
473 std::shared_ptr<SDLJoystick> joystick;
474 int axis;
475 float threshold;
476 bool trigger_if_greater;
477};
478
479class SDLButtonMotion final : public Input::MotionDevice {
480public:
481 explicit SDLButtonMotion(std::shared_ptr<SDLJoystick> joystick_, int button_)
482 : joystick(std::move(joystick_)), button(button_) {}
483
484 Input::MotionStatus GetStatus() const override {
485 if (joystick->GetButton(button)) {
486 return joystick->GetMotion().GetRandomMotion(2, 6);
487 }
488 return joystick->GetMotion().GetRandomMotion(0, 0);
489 }
490
491private:
492 std::shared_ptr<SDLJoystick> joystick;
493 int button;
366}; 494};
367 495
368/// A button device factory that creates button devices from SDL joystick 496/// A button device factory that creates button devices from SDL joystick
@@ -457,14 +585,78 @@ public:
457 const int port = params.Get("port", 0); 585 const int port = params.Get("port", 0);
458 const int axis_x = params.Get("axis_x", 0); 586 const int axis_x = params.Get("axis_x", 0);
459 const int axis_y = params.Get("axis_y", 1); 587 const int axis_y = params.Get("axis_y", 1);
460 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f); 588 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
461 589 const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
462 auto joystick = state.GetSDLJoystickByGUID(guid, port); 590 auto joystick = state.GetSDLJoystickByGUID(guid, port);
463 591
464 // This is necessary so accessing GetAxis with axis_x and axis_y won't crash 592 // This is necessary so accessing GetAxis with axis_x and axis_y won't crash
465 joystick->SetAxis(axis_x, 0); 593 joystick->SetAxis(axis_x, 0);
466 joystick->SetAxis(axis_y, 0); 594 joystick->SetAxis(axis_y, 0);
467 return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, deadzone); 595 return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, deadzone, range);
596 }
597
598private:
599 SDLState& state;
600};
601
602/// A motion device factory that creates motion devices from SDL joystick
603class SDLMotionFactory final : public Input::Factory<Input::MotionDevice> {
604public:
605 explicit SDLMotionFactory(SDLState& state_) : state(state_) {}
606 /**
607 * Creates motion device from joystick axes
608 * @param params contains parameters for creating the device:
609 * - "guid": the guid of the joystick to bind
610 * - "port": the nth joystick of the same type
611 */
612 std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override {
613 const std::string guid = params.Get("guid", "0");
614 const int port = params.Get("port", 0);
615
616 auto joystick = state.GetSDLJoystickByGUID(guid, port);
617
618 if (params.Has("hat")) {
619 const int hat = params.Get("hat", 0);
620 const std::string direction_name = params.Get("direction", "");
621 Uint8 direction;
622 if (direction_name == "up") {
623 direction = SDL_HAT_UP;
624 } else if (direction_name == "down") {
625 direction = SDL_HAT_DOWN;
626 } else if (direction_name == "left") {
627 direction = SDL_HAT_LEFT;
628 } else if (direction_name == "right") {
629 direction = SDL_HAT_RIGHT;
630 } else {
631 direction = 0;
632 }
633 // This is necessary so accessing GetHat with hat won't crash
634 joystick->SetHat(hat, SDL_HAT_CENTERED);
635 return std::make_unique<SDLDirectionMotion>(joystick, hat, direction);
636 }
637
638 if (params.Has("axis")) {
639 const int axis = params.Get("axis", 0);
640 const float threshold = params.Get("threshold", 0.5f);
641 const std::string direction_name = params.Get("direction", "");
642 bool trigger_if_greater;
643 if (direction_name == "+") {
644 trigger_if_greater = true;
645 } else if (direction_name == "-") {
646 trigger_if_greater = false;
647 } else {
648 trigger_if_greater = true;
649 LOG_ERROR(Input, "Unknown direction {}", direction_name);
650 }
651 // This is necessary so accessing GetAxis with axis won't crash
652 joystick->SetAxis(axis, 0);
653 return std::make_unique<SDLAxisMotion>(joystick, axis, threshold, trigger_if_greater);
654 }
655
656 const int button = params.Get("button", 0);
657 // This is necessary so accessing GetButton with button won't crash
658 joystick->SetButton(button, false);
659 return std::make_unique<SDLButtonMotion>(joystick, button);
468 } 660 }
469 661
470private: 662private:
@@ -473,8 +665,12 @@ private:
473 665
474SDLState::SDLState() { 666SDLState::SDLState() {
475 using namespace Input; 667 using namespace Input;
476 RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>(*this)); 668 analog_factory = std::make_shared<SDLAnalogFactory>(*this);
477 RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>(*this)); 669 button_factory = std::make_shared<SDLButtonFactory>(*this);
670 motion_factory = std::make_shared<SDLMotionFactory>(*this);
671 RegisterFactory<AnalogDevice>("sdl", analog_factory);
672 RegisterFactory<ButtonDevice>("sdl", button_factory);
673 RegisterFactory<MotionDevice>("sdl", motion_factory);
478 674
479 // If the frontend is going to manage the event loop, then we dont start one here 675 // If the frontend is going to manage the event loop, then we dont start one here
480 start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK); 676 start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK);
@@ -482,6 +678,7 @@ SDLState::SDLState() {
482 LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError()); 678 LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError());
483 return; 679 return;
484 } 680 }
681 has_gamecontroller = SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER);
485 if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) { 682 if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) {
486 LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError()); 683 LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError());
487 } 684 }
@@ -494,7 +691,7 @@ SDLState::SDLState() {
494 using namespace std::chrono_literals; 691 using namespace std::chrono_literals;
495 while (initialized) { 692 while (initialized) {
496 SDL_PumpEvents(); 693 SDL_PumpEvents();
497 std::this_thread::sleep_for(10ms); 694 std::this_thread::sleep_for(5ms);
498 } 695 }
499 }); 696 });
500 } 697 }
@@ -509,6 +706,7 @@ SDLState::~SDLState() {
509 using namespace Input; 706 using namespace Input;
510 UnregisterFactory<ButtonDevice>("sdl"); 707 UnregisterFactory<ButtonDevice>("sdl");
511 UnregisterFactory<AnalogDevice>("sdl"); 708 UnregisterFactory<AnalogDevice>("sdl");
709 UnregisterFactory<MotionDevice>("sdl");
512 710
513 CloseJoysticks(); 711 CloseJoysticks();
514 SDL_DelEventWatch(&SDLEventWatcher, this); 712 SDL_DelEventWatch(&SDLEventWatcher, this);
@@ -520,65 +718,251 @@ SDLState::~SDLState() {
520 } 718 }
521} 719}
522 720
523static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { 721std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
722 std::scoped_lock lock(joystick_map_mutex);
723 std::vector<Common::ParamPackage> devices;
724 for (const auto& [key, value] : joystick_map) {
725 for (const auto& joystick : value) {
726 auto joy = joystick->GetSDLJoystick();
727 if (auto controller = joystick->GetSDLGameController()) {
728 std::string name =
729 fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort());
730 devices.emplace_back(Common::ParamPackage{
731 {"class", "sdl"},
732 {"display", std::move(name)},
733 {"guid", joystick->GetGUID()},
734 {"port", std::to_string(joystick->GetPort())},
735 });
736 } else if (joy) {
737 std::string name = fmt::format("{} {}", SDL_JoystickName(joy), joystick->GetPort());
738 devices.emplace_back(Common::ParamPackage{
739 {"class", "sdl"},
740 {"display", std::move(name)},
741 {"guid", joystick->GetGUID()},
742 {"port", std::to_string(joystick->GetPort())},
743 });
744 }
745 }
746 }
747 return devices;
748}
749
750namespace {
751Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, u8 axis,
752 float value = 0.1f) {
524 Common::ParamPackage params({{"engine", "sdl"}}); 753 Common::ParamPackage params({{"engine", "sdl"}});
754 params.Set("port", port);
755 params.Set("guid", std::move(guid));
756 params.Set("axis", axis);
757 if (value > 0) {
758 params.Set("direction", "+");
759 params.Set("threshold", "0.5");
760 } else {
761 params.Set("direction", "-");
762 params.Set("threshold", "-0.5");
763 }
764 return params;
765}
766
767Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, u8 button) {
768 Common::ParamPackage params({{"engine", "sdl"}});
769 params.Set("port", port);
770 params.Set("guid", std::move(guid));
771 params.Set("button", button);
772 return params;
773}
525 774
775Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, u8 hat, u8 value) {
776 Common::ParamPackage params({{"engine", "sdl"}});
777
778 params.Set("port", port);
779 params.Set("guid", std::move(guid));
780 params.Set("hat", hat);
781 switch (value) {
782 case SDL_HAT_UP:
783 params.Set("direction", "up");
784 break;
785 case SDL_HAT_DOWN:
786 params.Set("direction", "down");
787 break;
788 case SDL_HAT_LEFT:
789 params.Set("direction", "left");
790 break;
791 case SDL_HAT_RIGHT:
792 params.Set("direction", "right");
793 break;
794 default:
795 return {};
796 }
797 return params;
798}
799
800Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
526 switch (event.type) { 801 switch (event.type) {
527 case SDL_JOYAXISMOTION: { 802 case SDL_JOYAXISMOTION: {
528 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); 803 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
529 params.Set("port", joystick->GetPort()); 804 return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
530 params.Set("guid", joystick->GetGUID()); 805 event.jaxis.axis, event.jaxis.value);
531 params.Set("axis", event.jaxis.axis);
532 if (event.jaxis.value > 0) {
533 params.Set("direction", "+");
534 params.Set("threshold", "0.5");
535 } else {
536 params.Set("direction", "-");
537 params.Set("threshold", "-0.5");
538 }
539 break;
540 } 806 }
541 case SDL_JOYBUTTONUP: { 807 case SDL_JOYBUTTONUP: {
542 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which); 808 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
543 params.Set("port", joystick->GetPort()); 809 return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
544 params.Set("guid", joystick->GetGUID()); 810 event.jbutton.button);
545 params.Set("button", event.jbutton.button);
546 break;
547 } 811 }
548 case SDL_JOYHATMOTION: { 812 case SDL_JOYHATMOTION: {
549 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which); 813 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
550 params.Set("port", joystick->GetPort()); 814 return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
551 params.Set("guid", joystick->GetGUID()); 815 event.jhat.hat, event.jhat.value);
552 params.Set("hat", event.jhat.hat); 816 }
553 switch (event.jhat.value) { 817 }
554 case SDL_HAT_UP: 818 return {};
555 params.Set("direction", "up"); 819}
556 break; 820
557 case SDL_HAT_DOWN: 821Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Event& event) {
558 params.Set("direction", "down"); 822 switch (event.type) {
559 break; 823 case SDL_JOYAXISMOTION: {
560 case SDL_HAT_LEFT: 824 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
561 params.Set("direction", "left"); 825 return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
562 break; 826 event.jaxis.axis, event.jaxis.value);
563 case SDL_HAT_RIGHT:
564 params.Set("direction", "right");
565 break;
566 default:
567 return {};
568 }
569 break;
570 } 827 }
828 case SDL_JOYBUTTONUP: {
829 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
830 return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
831 event.jbutton.button);
571 } 832 }
833 case SDL_JOYHATMOTION: {
834 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
835 return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
836 event.jhat.hat, event.jhat.value);
837 }
838 }
839 return {};
840}
841
842Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid,
843 const SDL_GameControllerButtonBind& binding) {
844 switch (binding.bindType) {
845 case SDL_CONTROLLER_BINDTYPE_AXIS:
846 return BuildAnalogParamPackageForButton(port, guid, binding.value.axis);
847 case SDL_CONTROLLER_BINDTYPE_BUTTON:
848 return BuildButtonParamPackageForButton(port, guid, binding.value.button);
849 case SDL_CONTROLLER_BINDTYPE_HAT:
850 return BuildHatParamPackageForButton(port, guid, binding.value.hat.hat,
851 binding.value.hat.hat_mask);
852 }
853 return {};
854}
855
856Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x,
857 int axis_y) {
858 Common::ParamPackage params;
859 params.Set("engine", "sdl");
860 params.Set("port", port);
861 params.Set("guid", guid);
862 params.Set("axis_x", axis_x);
863 params.Set("axis_y", axis_y);
572 return params; 864 return params;
573} 865}
866} // Anonymous namespace
574 867
575namespace Polling { 868ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& params) {
869 if (!params.Has("guid") || !params.Has("port")) {
870 return {};
871 }
872 const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
873 auto* controller = joystick->GetSDLGameController();
874 if (controller == nullptr) {
875 return {};
876 }
877
878 // This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
879 // We will add those afterwards
880 // This list also excludes Screenshot since theres not really a mapping for that
881 using ButtonBindings =
882 std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>;
883 static constexpr ButtonBindings switch_to_sdl_button{{
884 {Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
885 {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
886 {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
887 {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
888 {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
889 {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
890 {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
891 {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
892 {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
893 {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
894 {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
895 {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
896 {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
897 {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
898 {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
899 {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
900 {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
901 }};
902
903 // Add the missing bindings for ZL/ZR
904 using ZBindings =
905 std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>;
906 static constexpr ZBindings switch_to_sdl_axis{{
907 {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
908 {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
909 }};
910
911 ButtonMapping mapping;
912 mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
913
914 for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
915 const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
916 mapping.insert_or_assign(
917 switch_button,
918 BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
919 }
920 for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
921 const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis);
922 mapping.insert_or_assign(
923 switch_button,
924 BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
925 }
926
927 return mapping;
928}
929
930AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& params) {
931 if (!params.Has("guid") || !params.Has("port")) {
932 return {};
933 }
934 const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
935 auto* controller = joystick->GetSDLGameController();
936 if (controller == nullptr) {
937 return {};
938 }
939
940 AnalogMapping mapping = {};
941 const auto& binding_left_x =
942 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
943 const auto& binding_left_y =
944 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
945 mapping.insert_or_assign(Settings::NativeAnalog::LStick,
946 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
947 binding_left_x.value.axis,
948 binding_left_y.value.axis));
949 const auto& binding_right_x =
950 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
951 const auto& binding_right_y =
952 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
953 mapping.insert_or_assign(Settings::NativeAnalog::RStick,
954 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
955 binding_right_x.value.axis,
956 binding_right_y.value.axis));
957 return mapping;
958}
576 959
960namespace Polling {
577class SDLPoller : public InputCommon::Polling::DevicePoller { 961class SDLPoller : public InputCommon::Polling::DevicePoller {
578public: 962public:
579 explicit SDLPoller(SDLState& state_) : state(state_) {} 963 explicit SDLPoller(SDLState& state_) : state(state_) {}
580 964
581 void Start() override { 965 void Start(const std::string& device_id) override {
582 state.event_queue.Clear(); 966 state.event_queue.Clear();
583 state.polling = true; 967 state.polling = true;
584 } 968 }
@@ -598,71 +982,135 @@ public:
598 Common::ParamPackage GetNextInput() override { 982 Common::ParamPackage GetNextInput() override {
599 SDL_Event event; 983 SDL_Event event;
600 while (state.event_queue.Pop(event)) { 984 while (state.event_queue.Pop(event)) {
601 switch (event.type) { 985 const auto package = FromEvent(event);
602 case SDL_JOYAXISMOTION: 986 if (package) {
603 if (std::abs(event.jaxis.value / 32767.0) < 0.5) { 987 return *package;
604 break;
605 }
606 [[fallthrough]];
607 case SDL_JOYBUTTONUP:
608 case SDL_JOYHATMOTION:
609 return SDLEventToButtonParamPackage(state, event);
610 } 988 }
611 } 989 }
612 return {}; 990 return {};
613 } 991 }
992 [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const {
993 switch (event.type) {
994 case SDL_JOYAXISMOTION:
995 if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
996 break;
997 }
998 [[fallthrough]];
999 case SDL_JOYBUTTONUP:
1000 case SDL_JOYHATMOTION:
1001 return {SDLEventToButtonParamPackage(state, event)};
1002 }
1003 return std::nullopt;
1004 }
614}; 1005};
615 1006
616class SDLAnalogPoller final : public SDLPoller { 1007class SDLMotionPoller final : public SDLPoller {
617public: 1008public:
618 explicit SDLAnalogPoller(SDLState& state_) : SDLPoller(state_) {} 1009 explicit SDLMotionPoller(SDLState& state_) : SDLPoller(state_) {}
619 1010
620 void Start() override { 1011 Common::ParamPackage GetNextInput() override {
621 SDLPoller::Start(); 1012 SDL_Event event;
1013 while (state.event_queue.Pop(event)) {
1014 const auto package = FromEvent(event);
1015 if (package) {
1016 return *package;
1017 }
1018 }
1019 return {};
1020 }
1021 [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const {
1022 switch (event.type) {
1023 case SDL_JOYAXISMOTION:
1024 if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
1025 break;
1026 }
1027 [[fallthrough]];
1028 case SDL_JOYBUTTONUP:
1029 case SDL_JOYHATMOTION:
1030 return {SDLEventToMotionParamPackage(state, event)};
1031 }
1032 return std::nullopt;
1033 }
1034};
1035
1036/**
1037 * Attempts to match the press to a controller joy axis (left/right stick) and if a match
1038 * isn't found, checks if the event matches anything from SDLButtonPoller and uses that
1039 * instead
1040 */
1041class SDLAnalogPreferredPoller final : public SDLPoller {
1042public:
1043 explicit SDLAnalogPreferredPoller(SDLState& state_)
1044 : SDLPoller(state_), button_poller(state_) {}
622 1045
1046 void Start(const std::string& device_id) override {
1047 SDLPoller::Start(device_id);
1048 // Load the game controller
623 // Reset stored axes 1049 // Reset stored axes
624 analog_x_axis = -1; 1050 analog_x_axis = -1;
625 analog_y_axis = -1; 1051 analog_y_axis = -1;
626 analog_axes_joystick = -1;
627 } 1052 }
628 1053
629 Common::ParamPackage GetNextInput() override { 1054 Common::ParamPackage GetNextInput() override {
630 SDL_Event event; 1055 SDL_Event event;
631 while (state.event_queue.Pop(event)) { 1056 while (state.event_queue.Pop(event)) {
632 if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) { 1057 // Filter out axis events that are below a threshold
1058 if (event.type == SDL_JOYAXISMOTION && std::abs(event.jaxis.value / 32767.0) < 0.5) {
633 continue; 1059 continue;
634 } 1060 }
635 // An analog device needs two axes, so we need to store the axis for later and wait for 1061 // Simplify controller config by testing if game controller support is enabled.
636 // a second SDL event. The axes also must be from the same joystick. 1062 if (event.type == SDL_JOYAXISMOTION) {
637 const int axis = event.jaxis.axis; 1063 const auto axis = event.jaxis.axis;
638 if (analog_x_axis == -1) { 1064 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
639 analog_x_axis = axis; 1065 const auto controller = joystick->GetSDLGameController();
640 analog_axes_joystick = event.jaxis.which; 1066 if (controller) {
641 } else if (analog_y_axis == -1 && analog_x_axis != axis && 1067 const auto axis_left_x =
642 analog_axes_joystick == event.jaxis.which) { 1068 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX)
643 analog_y_axis = axis; 1069 .value.axis;
1070 const auto axis_left_y =
1071 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY)
1072 .value.axis;
1073 const auto axis_right_x =
1074 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX)
1075 .value.axis;
1076 const auto axis_right_y =
1077 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY)
1078 .value.axis;
1079
1080 if (axis == axis_left_x || axis == axis_left_y) {
1081 analog_x_axis = axis_left_x;
1082 analog_y_axis = axis_left_y;
1083 break;
1084 } else if (axis == axis_right_x || axis == axis_right_y) {
1085 analog_x_axis = axis_right_x;
1086 analog_y_axis = axis_right_y;
1087 break;
1088 }
1089 }
1090 }
1091
1092 // If the press wasn't accepted as a joy axis, check for a button press
1093 auto button_press = button_poller.FromEvent(event);
1094 if (button_press) {
1095 return *button_press;
644 } 1096 }
645 } 1097 }
646 Common::ParamPackage params; 1098
647 if (analog_x_axis != -1 && analog_y_axis != -1) { 1099 if (analog_x_axis != -1 && analog_y_axis != -1) {
648 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); 1100 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
649 params.Set("engine", "sdl"); 1101 auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
650 params.Set("port", joystick->GetPort()); 1102 analog_x_axis, analog_y_axis);
651 params.Set("guid", joystick->GetGUID());
652 params.Set("axis_x", analog_x_axis);
653 params.Set("axis_y", analog_y_axis);
654 analog_x_axis = -1; 1103 analog_x_axis = -1;
655 analog_y_axis = -1; 1104 analog_y_axis = -1;
656 analog_axes_joystick = -1;
657 return params; 1105 return params;
658 } 1106 }
659 return params; 1107 return {};
660 } 1108 }
661 1109
662private: 1110private:
663 int analog_x_axis = -1; 1111 int analog_x_axis = -1;
664 int analog_y_axis = -1; 1112 int analog_y_axis = -1;
665 SDL_JoystickID analog_axes_joystick = -1; 1113 SDLButtonPoller button_poller;
666}; 1114};
667} // namespace Polling 1115} // namespace Polling
668 1116
@@ -670,12 +1118,15 @@ SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
670 Pollers pollers; 1118 Pollers pollers;
671 1119
672 switch (type) { 1120 switch (type) {
673 case InputCommon::Polling::DeviceType::Analog: 1121 case InputCommon::Polling::DeviceType::AnalogPreferred:
674 pollers.emplace_back(std::make_unique<Polling::SDLAnalogPoller>(*this)); 1122 pollers.emplace_back(std::make_unique<Polling::SDLAnalogPreferredPoller>(*this));
675 break; 1123 break;
676 case InputCommon::Polling::DeviceType::Button: 1124 case InputCommon::Polling::DeviceType::Button:
677 pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this)); 1125 pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this));
678 break; 1126 break;
1127 case InputCommon::Polling::DeviceType::Motion:
1128 pollers.emplace_back(std::make_unique<Polling::SDLMotionPoller>(*this));
1129 break;
679 } 1130 }
680 1131
681 return pollers; 1132 return pollers;