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.cpp668
1 files changed, 668 insertions, 0 deletions
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
new file mode 100644
index 000000000..6e8376549
--- /dev/null
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -0,0 +1,668 @@
1// Copyright 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <atomic>
7#include <cmath>
8#include <functional>
9#include <iterator>
10#include <mutex>
11#include <string>
12#include <thread>
13#include <tuple>
14#include <unordered_map>
15#include <utility>
16#include <vector>
17#include <SDL.h>
18#include "common/assert.h"
19#include "common/logging/log.h"
20#include "common/math_util.h"
21#include "common/param_package.h"
22#include "common/threadsafe_queue.h"
23#include "core/frontend/input.h"
24#include "input_common/sdl/sdl_impl.h"
25
26namespace InputCommon {
27
28namespace SDL {
29
30static std::string GetGUID(SDL_Joystick* joystick) {
31 SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
32 char guid_str[33];
33 SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str));
34 return guid_str;
35}
36
37/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice
38static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event);
39
40static int SDLEventWatcher(void* userdata, SDL_Event* event) {
41 SDLState* sdl_state = reinterpret_cast<SDLState*>(userdata);
42 // Don't handle the event if we are configuring
43 if (sdl_state->polling) {
44 sdl_state->event_queue.Push(*event);
45 } else {
46 sdl_state->HandleGameControllerEvent(*event);
47 }
48 return 0;
49}
50
51class SDLJoystick {
52public:
53 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick,
54 decltype(&SDL_JoystickClose) deleter = &SDL_JoystickClose)
55 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, deleter} {}
56
57 void SetButton(int button, bool value) {
58 std::lock_guard<std::mutex> lock(mutex);
59 state.buttons[button] = value;
60 }
61
62 bool GetButton(int button) const {
63 std::lock_guard<std::mutex> lock(mutex);
64 return state.buttons.at(button);
65 }
66
67 void SetAxis(int axis, Sint16 value) {
68 std::lock_guard<std::mutex> lock(mutex);
69 state.axes[axis] = value;
70 }
71
72 float GetAxis(int axis) const {
73 std::lock_guard<std::mutex> lock(mutex);
74 return state.axes.at(axis) / 32767.0f;
75 }
76
77 std::tuple<float, float> GetAnalog(int axis_x, int axis_y) const {
78 float x = GetAxis(axis_x);
79 float y = GetAxis(axis_y);
80 y = -y; // 3DS uses an y-axis inverse from SDL
81
82 // Make sure the coordinates are in the unit circle,
83 // otherwise normalize it.
84 float r = x * x + y * y;
85 if (r > 1.0f) {
86 r = std::sqrt(r);
87 x /= r;
88 y /= r;
89 }
90
91 return std::make_tuple(x, y);
92 }
93
94 void SetHat(int hat, Uint8 direction) {
95 std::lock_guard<std::mutex> lock(mutex);
96 state.hats[hat] = direction;
97 }
98
99 bool GetHatDirection(int hat, Uint8 direction) const {
100 std::lock_guard<std::mutex> lock(mutex);
101 return (state.hats.at(hat) & direction) != 0;
102 }
103 /**
104 * The guid of the joystick
105 */
106 const std::string& GetGUID() const {
107 return guid;
108 }
109
110 /**
111 * The number of joystick from the same type that were connected before this joystick
112 */
113 int GetPort() const {
114 return port;
115 }
116
117 SDL_Joystick* GetSDLJoystick() const {
118 return sdl_joystick.get();
119 }
120
121 void SetSDLJoystick(SDL_Joystick* joystick,
122 decltype(&SDL_JoystickClose) deleter = &SDL_JoystickClose) {
123 sdl_joystick =
124 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)>(joystick, deleter);
125 }
126
127private:
128 struct State {
129 std::unordered_map<int, bool> buttons;
130 std::unordered_map<int, Sint16> axes;
131 std::unordered_map<int, Uint8> hats;
132 } state;
133 std::string guid;
134 int port;
135 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
136 mutable std::mutex mutex;
137};
138
139/**
140 * Get the nth joystick with the corresponding GUID
141 */
142std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
143 std::lock_guard<std::mutex> lock(joystick_map_mutex);
144 const auto it = joystick_map.find(guid);
145 if (it != joystick_map.end()) {
146 while (it->second.size() <= port) {
147 auto joystick = std::make_shared<SDLJoystick>(guid, it->second.size(), nullptr,
148 [](SDL_Joystick*) {});
149 it->second.emplace_back(std::move(joystick));
150 }
151 return it->second[port];
152 }
153 auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, [](SDL_Joystick*) {});
154 return joystick_map[guid].emplace_back(std::move(joystick));
155}
156
157/**
158 * Check how many identical joysticks (by guid) were connected before the one with sdl_id and so tie
159 * it to a SDLJoystick with the same guid and that port
160 */
161std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
162 auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
163 const std::string guid = GetGUID(sdl_joystick);
164 std::lock_guard<std::mutex> lock(joystick_map_mutex);
165 auto map_it = joystick_map.find(guid);
166 if (map_it != joystick_map.end()) {
167 auto vec_it = std::find_if(map_it->second.begin(), map_it->second.end(),
168 [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) {
169 return sdl_joystick == joystick->GetSDLJoystick();
170 });
171 if (vec_it != map_it->second.end()) {
172 // This is the common case: There is already an existing SDL_Joystick maped to a
173 // SDLJoystick. return the SDLJoystick
174 return *vec_it;
175 }
176 // Search for a SDLJoystick without a mapped SDL_Joystick...
177 auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(),
178 [](const std::shared_ptr<SDLJoystick>& joystick) {
179 return !joystick->GetSDLJoystick();
180 });
181 if (nullptr_it != map_it->second.end()) {
182 // ... and map it
183 (*nullptr_it)->SetSDLJoystick(sdl_joystick);
184 return *nullptr_it;
185 }
186 // There is no SDLJoystick without a mapped SDL_Joystick
187 // Create a new SDLJoystick
188 auto joystick = std::make_shared<SDLJoystick>(guid, map_it->second.size(), sdl_joystick);
189 return map_it->second.emplace_back(std::move(joystick));
190 }
191 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick);
192 return joystick_map[guid].emplace_back(std::move(joystick));
193}
194
195void SDLState::InitJoystick(int joystick_index) {
196 SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
197 if (!sdl_joystick) {
198 LOG_ERROR(Input, "failed to open joystick {}", joystick_index);
199 return;
200 }
201 std::string guid = GetGUID(sdl_joystick);
202 std::lock_guard<std::mutex> lock(joystick_map_mutex);
203 if (joystick_map.find(guid) == joystick_map.end()) {
204 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick);
205 joystick_map[guid].emplace_back(std::move(joystick));
206 return;
207 }
208 auto& joystick_guid_list = joystick_map[guid];
209 const auto it = std::find_if(
210 joystick_guid_list.begin(), joystick_guid_list.end(),
211 [](const std::shared_ptr<SDLJoystick>& joystick) { return !joystick->GetSDLJoystick(); });
212 if (it != joystick_guid_list.end()) {
213 (*it)->SetSDLJoystick(sdl_joystick);
214 return;
215 }
216 auto joystick = std::make_shared<SDLJoystick>(guid, joystick_guid_list.size(), sdl_joystick);
217 joystick_guid_list.emplace_back(std::move(joystick));
218}
219
220void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
221 std::string guid = GetGUID(sdl_joystick);
222 std::shared_ptr<SDLJoystick> joystick;
223 {
224 std::lock_guard<std::mutex> lock(joystick_map_mutex);
225 // This call to guid is safe since the joystick is guaranteed to be in the map
226 auto& joystick_guid_list = joystick_map[guid];
227 const auto joystick_it =
228 std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
229 [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) {
230 return joystick->GetSDLJoystick() == sdl_joystick;
231 });
232 joystick = *joystick_it;
233 }
234 // Destruct SDL_Joystick outside the lock guard because SDL can internally call event calback
235 // which locks the mutex again
236 joystick->SetSDLJoystick(nullptr, [](SDL_Joystick*) {});
237}
238
239void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
240 switch (event.type) {
241 case SDL_JOYBUTTONUP: {
242 if (auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
243 joystick->SetButton(event.jbutton.button, false);
244 }
245 break;
246 }
247 case SDL_JOYBUTTONDOWN: {
248 if (auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
249 joystick->SetButton(event.jbutton.button, true);
250 }
251 break;
252 }
253 case SDL_JOYHATMOTION: {
254 if (auto joystick = GetSDLJoystickBySDLID(event.jhat.which)) {
255 joystick->SetHat(event.jhat.hat, event.jhat.value);
256 }
257 break;
258 }
259 case SDL_JOYAXISMOTION: {
260 if (auto joystick = GetSDLJoystickBySDLID(event.jaxis.which)) {
261 joystick->SetAxis(event.jaxis.axis, event.jaxis.value);
262 }
263 break;
264 }
265 case SDL_JOYDEVICEREMOVED:
266 LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which);
267 CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which));
268 break;
269 case SDL_JOYDEVICEADDED:
270 LOG_DEBUG(Input, "Controller connected with device index {}", event.jdevice.which);
271 InitJoystick(event.jdevice.which);
272 break;
273 }
274}
275
276void SDLState::CloseJoysticks() {
277 std::lock_guard<std::mutex> lock(joystick_map_mutex);
278 joystick_map.clear();
279}
280
281class SDLButton final : public Input::ButtonDevice {
282public:
283 explicit SDLButton(std::shared_ptr<SDLJoystick> joystick_, int button_)
284 : joystick(std::move(joystick_)), button(button_) {}
285
286 bool GetStatus() const override {
287 return joystick->GetButton(button);
288 }
289
290private:
291 std::shared_ptr<SDLJoystick> joystick;
292 int button;
293};
294
295class SDLDirectionButton final : public Input::ButtonDevice {
296public:
297 explicit SDLDirectionButton(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
298 : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {}
299
300 bool GetStatus() const override {
301 return joystick->GetHatDirection(hat, direction);
302 }
303
304private:
305 std::shared_ptr<SDLJoystick> joystick;
306 int hat;
307 Uint8 direction;
308};
309
310class SDLAxisButton final : public Input::ButtonDevice {
311public:
312 explicit SDLAxisButton(std::shared_ptr<SDLJoystick> joystick_, int axis_, float threshold_,
313 bool trigger_if_greater_)
314 : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_),
315 trigger_if_greater(trigger_if_greater_) {}
316
317 bool GetStatus() const override {
318 float axis_value = joystick->GetAxis(axis);
319 if (trigger_if_greater)
320 return axis_value > threshold;
321 return axis_value < threshold;
322 }
323
324private:
325 std::shared_ptr<SDLJoystick> joystick;
326 int axis;
327 float threshold;
328 bool trigger_if_greater;
329};
330
331class SDLAnalog final : public Input::AnalogDevice {
332public:
333 SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, float deadzone_)
334 : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_) {}
335
336 std::tuple<float, float> GetStatus() const override {
337 const auto [x, y] = joystick->GetAnalog(axis_x, axis_y);
338 const float r = std::sqrt((x * x) + (y * y));
339 if (r > deadzone) {
340 return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone),
341 y / r * (r - deadzone) / (1 - deadzone));
342 }
343 return std::make_tuple<float, float>(0.0f, 0.0f);
344 }
345
346private:
347 std::shared_ptr<SDLJoystick> joystick;
348 const int axis_x;
349 const int axis_y;
350 const float deadzone;
351};
352
353/// A button device factory that creates button devices from SDL joystick
354class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> {
355public:
356 explicit SDLButtonFactory(SDLState& state_) : state(state_) {}
357
358 /**
359 * Creates a button device from a joystick button
360 * @param params contains parameters for creating the device:
361 * - "guid": the guid of the joystick to bind
362 * - "port": the nth joystick of the same type to bind
363 * - "button"(optional): the index of the button to bind
364 * - "hat"(optional): the index of the hat to bind as direction buttons
365 * - "axis"(optional): the index of the axis to bind
366 * - "direction"(only used for hat): the direction name of the hat to bind. Can be "up",
367 * "down", "left" or "right"
368 * - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is
369 * triggered if the axis value crosses
370 * - "direction"(only used for axis): "+" means the button is triggered when the axis
371 * value is greater than the threshold; "-" means the button is triggered when the axis
372 * value is smaller than the threshold
373 */
374 std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override {
375 const std::string guid = params.Get("guid", "0");
376 const int port = params.Get("port", 0);
377
378 auto joystick = state.GetSDLJoystickByGUID(guid, port);
379
380 if (params.Has("hat")) {
381 const int hat = params.Get("hat", 0);
382 const std::string direction_name = params.Get("direction", "");
383 Uint8 direction;
384 if (direction_name == "up") {
385 direction = SDL_HAT_UP;
386 } else if (direction_name == "down") {
387 direction = SDL_HAT_DOWN;
388 } else if (direction_name == "left") {
389 direction = SDL_HAT_LEFT;
390 } else if (direction_name == "right") {
391 direction = SDL_HAT_RIGHT;
392 } else {
393 direction = 0;
394 }
395 // This is necessary so accessing GetHat with hat won't crash
396 joystick->SetHat(hat, SDL_HAT_CENTERED);
397 return std::make_unique<SDLDirectionButton>(joystick, hat, direction);
398 }
399
400 if (params.Has("axis")) {
401 const int axis = params.Get("axis", 0);
402 const float threshold = params.Get("threshold", 0.5f);
403 const std::string direction_name = params.Get("direction", "");
404 bool trigger_if_greater;
405 if (direction_name == "+") {
406 trigger_if_greater = true;
407 } else if (direction_name == "-") {
408 trigger_if_greater = false;
409 } else {
410 trigger_if_greater = true;
411 LOG_ERROR(Input, "Unknown direction {}", direction_name);
412 }
413 // This is necessary so accessing GetAxis with axis won't crash
414 joystick->SetAxis(axis, 0);
415 return std::make_unique<SDLAxisButton>(joystick, axis, threshold, trigger_if_greater);
416 }
417
418 const int button = params.Get("button", 0);
419 // This is necessary so accessing GetButton with button won't crash
420 joystick->SetButton(button, false);
421 return std::make_unique<SDLButton>(joystick, button);
422 }
423
424private:
425 SDLState& state;
426};
427
428/// An analog device factory that creates analog devices from SDL joystick
429class SDLAnalogFactory final : public Input::Factory<Input::AnalogDevice> {
430public:
431 explicit SDLAnalogFactory(SDLState& state_) : state(state_) {}
432 /**
433 * Creates analog device from joystick axes
434 * @param params contains parameters for creating the device:
435 * - "guid": the guid of the joystick to bind
436 * - "port": the nth joystick of the same type
437 * - "axis_x": the index of the axis to be bind as x-axis
438 * - "axis_y": the index of the axis to be bind as y-axis
439 */
440 std::unique_ptr<Input::AnalogDevice> Create(const Common::ParamPackage& params) override {
441 const std::string guid = params.Get("guid", "0");
442 const int port = params.Get("port", 0);
443 const int axis_x = params.Get("axis_x", 0);
444 const int axis_y = params.Get("axis_y", 1);
445 float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f);
446
447 auto joystick = state.GetSDLJoystickByGUID(guid, port);
448
449 // This is necessary so accessing GetAxis with axis_x and axis_y won't crash
450 joystick->SetAxis(axis_x, 0);
451 joystick->SetAxis(axis_y, 0);
452 return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, deadzone);
453 }
454
455private:
456 SDLState& state;
457};
458
459SDLState::SDLState() {
460 using namespace Input;
461 RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>(*this));
462 RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>(*this));
463
464 // If the frontend is going to manage the event loop, then we dont start one here
465 start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK);
466 if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) {
467 LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError());
468 return;
469 }
470 if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) {
471 LOG_ERROR(Input, "Failed to set Hint for background events", SDL_GetError());
472 }
473
474 SDL_AddEventWatch(&SDLEventWatcher, this);
475
476 initialized = true;
477 if (start_thread) {
478 poll_thread = std::thread([this] {
479 using namespace std::chrono_literals;
480 while (initialized) {
481 SDL_PumpEvents();
482 std::this_thread::sleep_for(10ms);
483 }
484 });
485 }
486 // Because the events for joystick connection happens before we have our event watcher added, we
487 // can just open all the joysticks right here
488 for (int i = 0; i < SDL_NumJoysticks(); ++i) {
489 InitJoystick(i);
490 }
491}
492
493SDLState::~SDLState() {
494 using namespace Input;
495 UnregisterFactory<ButtonDevice>("sdl");
496 UnregisterFactory<AnalogDevice>("sdl");
497
498 CloseJoysticks();
499 SDL_DelEventWatch(&SDLEventWatcher, this);
500
501 initialized = false;
502 if (start_thread) {
503 poll_thread.join();
504 SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
505 }
506}
507
508Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
509 Common::ParamPackage params({{"engine", "sdl"}});
510
511 switch (event.type) {
512 case SDL_JOYAXISMOTION: {
513 auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
514 params.Set("port", joystick->GetPort());
515 params.Set("guid", joystick->GetGUID());
516 params.Set("axis", event.jaxis.axis);
517 if (event.jaxis.value > 0) {
518 params.Set("direction", "+");
519 params.Set("threshold", "0.5");
520 } else {
521 params.Set("direction", "-");
522 params.Set("threshold", "-0.5");
523 }
524 break;
525 }
526 case SDL_JOYBUTTONUP: {
527 auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
528 params.Set("port", joystick->GetPort());
529 params.Set("guid", joystick->GetGUID());
530 params.Set("button", event.jbutton.button);
531 break;
532 }
533 case SDL_JOYHATMOTION: {
534 auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
535 params.Set("port", joystick->GetPort());
536 params.Set("guid", joystick->GetGUID());
537 params.Set("hat", event.jhat.hat);
538 switch (event.jhat.value) {
539 case SDL_HAT_UP:
540 params.Set("direction", "up");
541 break;
542 case SDL_HAT_DOWN:
543 params.Set("direction", "down");
544 break;
545 case SDL_HAT_LEFT:
546 params.Set("direction", "left");
547 break;
548 case SDL_HAT_RIGHT:
549 params.Set("direction", "right");
550 break;
551 default:
552 return {};
553 }
554 break;
555 }
556 }
557 return params;
558}
559
560namespace Polling {
561
562class SDLPoller : public InputCommon::Polling::DevicePoller {
563public:
564 explicit SDLPoller(SDLState& state_) : state(state_) {}
565
566 void Start() override {
567 state.event_queue.Clear();
568 state.polling = true;
569 }
570
571 void Stop() override {
572 state.polling = false;
573 }
574
575protected:
576 SDLState& state;
577};
578
579class SDLButtonPoller final : public SDLPoller {
580public:
581 explicit SDLButtonPoller(SDLState& state_) : SDLPoller(state_) {}
582
583 Common::ParamPackage GetNextInput() override {
584 SDL_Event event;
585 while (state.event_queue.Pop(event)) {
586 switch (event.type) {
587 case SDL_JOYAXISMOTION:
588 if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
589 break;
590 }
591 case SDL_JOYBUTTONUP:
592 case SDL_JOYHATMOTION:
593 return SDLEventToButtonParamPackage(state, event);
594 }
595 }
596 return {};
597 }
598};
599
600class SDLAnalogPoller final : public SDLPoller {
601public:
602 explicit SDLAnalogPoller(SDLState& state_) : SDLPoller(state_) {}
603
604 void Start() override {
605 SDLPoller::Start();
606
607 // Reset stored axes
608 analog_xaxis = -1;
609 analog_yaxis = -1;
610 analog_axes_joystick = -1;
611 }
612
613 Common::ParamPackage GetNextInput() override {
614 SDL_Event event;
615 while (state.event_queue.Pop(event)) {
616 if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) {
617 continue;
618 }
619 // An analog device needs two axes, so we need to store the axis for later and wait for
620 // a second SDL event. The axes also must be from the same joystick.
621 int axis = event.jaxis.axis;
622 if (analog_xaxis == -1) {
623 analog_xaxis = axis;
624 analog_axes_joystick = event.jaxis.which;
625 } else if (analog_yaxis == -1 && analog_xaxis != axis &&
626 analog_axes_joystick == event.jaxis.which) {
627 analog_yaxis = axis;
628 }
629 }
630 Common::ParamPackage params;
631 if (analog_xaxis != -1 && analog_yaxis != -1) {
632 auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
633 params.Set("engine", "sdl");
634 params.Set("port", joystick->GetPort());
635 params.Set("guid", joystick->GetGUID());
636 params.Set("axis_x", analog_xaxis);
637 params.Set("axis_y", analog_yaxis);
638 analog_xaxis = -1;
639 analog_yaxis = -1;
640 analog_axes_joystick = -1;
641 return params;
642 }
643 return params;
644 }
645
646private:
647 int analog_xaxis = -1;
648 int analog_yaxis = -1;
649 SDL_JoystickID analog_axes_joystick = -1;
650};
651} // namespace Polling
652
653std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> SDLState::GetPollers(
654 InputCommon::Polling::DeviceType type) {
655 std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> pollers;
656 switch (type) {
657 case InputCommon::Polling::DeviceType::Analog:
658 pollers.emplace_back(std::make_unique<Polling::SDLAnalogPoller>(*this));
659 break;
660 case InputCommon::Polling::DeviceType::Button:
661 pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this));
662 break;
663 return pollers;
664 }
665}
666
667} // namespace SDL
668} // namespace InputCommon