summaryrefslogtreecommitdiff
path: root/src/input_common/sdl/sdl_impl.cpp
diff options
context:
space:
mode:
authorGravatar James Rowe2018-09-20 00:28:05 -0600
committerGravatar fearlessTobi2019-03-02 19:09:34 +0100
commit09ac66388c01187ed6a402efcad76984c8af9a2e (patch)
treebeed8a86e7b7e02e0c5526723bbf812920341d12 /src/input_common/sdl/sdl_impl.cpp
parentInput: Copy current SDL.h/cpp files to impl (diff)
downloadyuzu-09ac66388c01187ed6a402efcad76984c8af9a2e.tar.gz
yuzu-09ac66388c01187ed6a402efcad76984c8af9a2e.tar.xz
yuzu-09ac66388c01187ed6a402efcad76984c8af9a2e.zip
Input: Remove global variables from SDL Input
Changes the interface as well to remove any unique methods that frontends needed to call such as StartJoystickEventHandler by conditionally starting the polling thread only if the frontend hasn't started it already. Additionally, moves all global state into a single SDLState class in order to guarantee that the destructors are called in the proper order
Diffstat (limited to 'src/input_common/sdl/sdl_impl.cpp')
-rw-r--r--src/input_common/sdl/sdl_impl.cpp193
1 files changed, 108 insertions, 85 deletions
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 7c1ecc2e0..83fcf354e 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -1,4 +1,4 @@
1// Copyright 2017 Citra Emulator Project 1// Copyright 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
@@ -20,30 +20,13 @@
20#include "common/math_util.h" 20#include "common/math_util.h"
21#include "common/param_package.h" 21#include "common/param_package.h"
22#include "common/threadsafe_queue.h" 22#include "common/threadsafe_queue.h"
23#include "input_common/main.h" 23#include "core/frontend/input.h"
24#include "input_common/sdl/sdl.h" 24#include "input_common/sdl/sdl_impl.h"
25 25
26namespace InputCommon { 26namespace InputCommon {
27 27
28namespace SDL { 28namespace SDL {
29 29
30class SDLJoystick;
31class SDLButtonFactory;
32class SDLAnalogFactory;
33
34/// Map of GUID of a list of corresponding virtual Joysticks
35static std::unordered_map<std::string, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map;
36static std::mutex joystick_map_mutex;
37
38static std::shared_ptr<SDLButtonFactory> button_factory;
39static std::shared_ptr<SDLAnalogFactory> analog_factory;
40
41/// Used by the Pollers during config
42static std::atomic<bool> polling;
43static Common::SPSCQueue<SDL_Event> event_queue;
44
45static std::atomic<bool> initialized = false;
46
47static std::string GetGUID(SDL_Joystick* joystick) { 30static std::string GetGUID(SDL_Joystick* joystick) {
48 SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); 31 SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
49 char guid_str[33]; 32 char guid_str[33];
@@ -51,6 +34,20 @@ static std::string GetGUID(SDL_Joystick* joystick) {
51 return guid_str; 34 return guid_str;
52} 35}
53 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
54class SDLJoystick { 51class SDLJoystick {
55public: 52public:
56 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, 53 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick,
@@ -142,7 +139,7 @@ private:
142/** 139/**
143 * Get the nth joystick with the corresponding GUID 140 * Get the nth joystick with the corresponding GUID
144 */ 141 */
145static std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port) { 142std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
146 std::lock_guard<std::mutex> lock(joystick_map_mutex); 143 std::lock_guard<std::mutex> lock(joystick_map_mutex);
147 const auto it = joystick_map.find(guid); 144 const auto it = joystick_map.find(guid);
148 if (it != joystick_map.end()) { 145 if (it != joystick_map.end()) {
@@ -161,7 +158,7 @@ static std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid
161 * Check how many identical joysticks (by guid) were connected before the one with sdl_id and so tie 158 * Check how many identical joysticks (by guid) were connected before the one with sdl_id and so tie
162 * it to a SDLJoystick with the same guid and that port 159 * it to a SDLJoystick with the same guid and that port
163 */ 160 */
164static std::shared_ptr<SDLJoystick> GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { 161std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
165 std::lock_guard<std::mutex> lock(joystick_map_mutex); 162 std::lock_guard<std::mutex> lock(joystick_map_mutex);
166 auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id); 163 auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
167 const std::string guid = GetGUID(sdl_joystick); 164 const std::string guid = GetGUID(sdl_joystick);
@@ -195,7 +192,7 @@ static std::shared_ptr<SDLJoystick> GetSDLJoystickBySDLID(SDL_JoystickID sdl_id)
195 return joystick_map[guid].emplace_back(std::move(joystick)); 192 return joystick_map[guid].emplace_back(std::move(joystick));
196} 193}
197 194
198void InitJoystick(int joystick_index) { 195void SDLState::InitJoystick(int joystick_index) {
199 std::lock_guard<std::mutex> lock(joystick_map_mutex); 196 std::lock_guard<std::mutex> lock(joystick_map_mutex);
200 SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index); 197 SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
201 if (!sdl_joystick) { 198 if (!sdl_joystick) {
@@ -220,10 +217,10 @@ void InitJoystick(int joystick_index) {
220 joystick_guid_list.emplace_back(std::move(joystick)); 217 joystick_guid_list.emplace_back(std::move(joystick));
221} 218}
222 219
223void CloseJoystick(SDL_Joystick* sdl_joystick) { 220void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
224 std::lock_guard<std::mutex> lock(joystick_map_mutex); 221 std::lock_guard<std::mutex> lock(joystick_map_mutex);
225 std::string guid = GetGUID(sdl_joystick); 222 std::string guid = GetGUID(sdl_joystick);
226 // This call to guid is save since the joystick is guranteed to be in that map 223 // This call to guid is safe since the joystick is guaranteed to be in the map
227 auto& joystick_guid_list = joystick_map[guid]; 224 auto& joystick_guid_list = joystick_map[guid];
228 const auto joystick_it = 225 const auto joystick_it =
229 std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), 226 std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
@@ -233,32 +230,28 @@ void CloseJoystick(SDL_Joystick* sdl_joystick) {
233 (*joystick_it)->SetSDLJoystick(nullptr, [](SDL_Joystick*) {}); 230 (*joystick_it)->SetSDLJoystick(nullptr, [](SDL_Joystick*) {});
234} 231}
235 232
236void HandleGameControllerEvent(const SDL_Event& event) { 233void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
237 switch (event.type) { 234 switch (event.type) {
238 case SDL_JOYBUTTONUP: { 235 case SDL_JOYBUTTONUP: {
239 auto joystick = GetSDLJoystickBySDLID(event.jbutton.which); 236 if (auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
240 if (joystick) {
241 joystick->SetButton(event.jbutton.button, false); 237 joystick->SetButton(event.jbutton.button, false);
242 } 238 }
243 break; 239 break;
244 } 240 }
245 case SDL_JOYBUTTONDOWN: { 241 case SDL_JOYBUTTONDOWN: {
246 auto joystick = GetSDLJoystickBySDLID(event.jbutton.which); 242 if (auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
247 if (joystick) {
248 joystick->SetButton(event.jbutton.button, true); 243 joystick->SetButton(event.jbutton.button, true);
249 } 244 }
250 break; 245 break;
251 } 246 }
252 case SDL_JOYHATMOTION: { 247 case SDL_JOYHATMOTION: {
253 auto joystick = GetSDLJoystickBySDLID(event.jhat.which); 248 if (auto joystick = GetSDLJoystickBySDLID(event.jhat.which)) {
254 if (joystick) {
255 joystick->SetHat(event.jhat.hat, event.jhat.value); 249 joystick->SetHat(event.jhat.hat, event.jhat.value);
256 } 250 }
257 break; 251 break;
258 } 252 }
259 case SDL_JOYAXISMOTION: { 253 case SDL_JOYAXISMOTION: {
260 auto joystick = GetSDLJoystickBySDLID(event.jaxis.which); 254 if (auto joystick = GetSDLJoystickBySDLID(event.jaxis.which)) {
261 if (joystick) {
262 joystick->SetAxis(event.jaxis.axis, event.jaxis.value); 255 joystick->SetAxis(event.jaxis.axis, event.jaxis.value);
263 } 256 }
264 break; 257 break;
@@ -274,33 +267,11 @@ void HandleGameControllerEvent(const SDL_Event& event) {
274 } 267 }
275} 268}
276 269
277void CloseSDLJoysticks() { 270void SDLState::CloseJoysticks() {
278 std::lock_guard<std::mutex> lock(joystick_map_mutex); 271 std::lock_guard<std::mutex> lock(joystick_map_mutex);
279 joystick_map.clear(); 272 joystick_map.clear();
280} 273}
281 274
282void PollLoop() {
283 if (SDL_Init(SDL_INIT_JOYSTICK) < 0) {
284 LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError());
285 return;
286 }
287
288 SDL_Event event;
289 while (initialized) {
290 // Wait for 10 ms or until an event happens
291 if (SDL_WaitEventTimeout(&event, 10)) {
292 // Don't handle the event if we are configuring
293 if (polling) {
294 event_queue.Push(event);
295 } else {
296 HandleGameControllerEvent(event);
297 }
298 }
299 }
300 CloseSDLJoysticks();
301 SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
302}
303
304class SDLButton final : public Input::ButtonDevice { 275class SDLButton final : public Input::ButtonDevice {
305public: 276public:
306 explicit SDLButton(std::shared_ptr<SDLJoystick> joystick_, int button_) 277 explicit SDLButton(std::shared_ptr<SDLJoystick> joystick_, int button_)
@@ -369,6 +340,8 @@ private:
369/// A button device factory that creates button devices from SDL joystick 340/// A button device factory that creates button devices from SDL joystick
370class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> { 341class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> {
371public: 342public:
343 explicit SDLButtonFactory(SDLState& state_) : state(state_) {}
344
372 /** 345 /**
373 * Creates a button device from a joystick button 346 * Creates a button device from a joystick button
374 * @param params contains parameters for creating the device: 347 * @param params contains parameters for creating the device:
@@ -389,7 +362,7 @@ public:
389 const std::string guid = params.Get("guid", "0"); 362 const std::string guid = params.Get("guid", "0");
390 const int port = params.Get("port", 0); 363 const int port = params.Get("port", 0);
391 364
392 auto joystick = GetSDLJoystickByGUID(guid, port); 365 auto joystick = state.GetSDLJoystickByGUID(guid, port);
393 366
394 if (params.Has("hat")) { 367 if (params.Has("hat")) {
395 const int hat = params.Get("hat", 0); 368 const int hat = params.Get("hat", 0);
@@ -434,11 +407,15 @@ public:
434 joystick->SetButton(button, false); 407 joystick->SetButton(button, false);
435 return std::make_unique<SDLButton>(joystick, button); 408 return std::make_unique<SDLButton>(joystick, button);
436 } 409 }
410
411private:
412 SDLState& state;
437}; 413};
438 414
439/// An analog device factory that creates analog devices from SDL joystick 415/// An analog device factory that creates analog devices from SDL joystick
440class SDLAnalogFactory final : public Input::Factory<Input::AnalogDevice> { 416class SDLAnalogFactory final : public Input::Factory<Input::AnalogDevice> {
441public: 417public:
418 explicit SDLAnalogFactory(SDLState& state_) : state(state_) {}
442 /** 419 /**
443 * Creates analog device from joystick axes 420 * Creates analog device from joystick axes
444 * @param params contains parameters for creating the device: 421 * @param params contains parameters for creating the device:
@@ -453,37 +430,71 @@ public:
453 const int axis_x = params.Get("axis_x", 0); 430 const int axis_x = params.Get("axis_x", 0);
454 const int axis_y = params.Get("axis_y", 1); 431 const int axis_y = params.Get("axis_y", 1);
455 432
456 auto joystick = GetSDLJoystickByGUID(guid, port); 433 auto joystick = state.GetSDLJoystickByGUID(guid, port);
457 434
458 // This is necessary so accessing GetAxis with axis_x and axis_y won't crash 435 // This is necessary so accessing GetAxis with axis_x and axis_y won't crash
459 joystick->SetAxis(axis_x, 0); 436 joystick->SetAxis(axis_x, 0);
460 joystick->SetAxis(axis_y, 0); 437 joystick->SetAxis(axis_y, 0);
461 return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y); 438 return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y);
462 } 439 }
440
441private:
442 SDLState& state;
463}; 443};
464 444
465void Init() { 445SDLState::SDLState() {
466 using namespace Input; 446 using namespace Input;
467 RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>()); 447 RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>(*this));
468 RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>()); 448 RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>(*this));
469 polling = false; 449
450 // If the frontend is going to manage the event loop, then we dont start one here
451 start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK);
452 if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) {
453 LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError());
454 return;
455 }
456
457 SDL_AddEventWatch(&SDLEventWatcher, this);
458
470 initialized = true; 459 initialized = true;
460 if (start_thread) {
461 poll_thread = std::thread([&] {
462 using namespace std::chrono_literals;
463 SDL_Event event;
464 while (initialized) {
465 SDL_PumpEvents();
466 std::this_thread::sleep_for(std::chrono::duration(10ms));
467 }
468 });
469 }
470 // Because the events for joystick connection happens before we have our event watcher added, we
471 // can just open all the joysticks right here
472 for (int i = 0; i < SDL_NumJoysticks(); ++i) {
473 InitJoystick(i);
474 }
471} 475}
472 476
473void Shutdown() { 477SDLState::~SDLState() {
474 if (initialized) { 478 using namespace Input;
475 using namespace Input; 479 UnregisterFactory<ButtonDevice>("sdl");
476 UnregisterFactory<ButtonDevice>("sdl"); 480 UnregisterFactory<AnalogDevice>("sdl");
477 UnregisterFactory<AnalogDevice>("sdl"); 481
478 initialized = false; 482 CloseJoysticks();
483 SDL_DelEventWatch(&SDLEventWatcher, this);
484
485 initialized = false;
486 if (start_thread) {
487 poll_thread.join();
488 SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
479 } 489 }
480} 490}
481 491
482Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event) { 492Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
483 Common::ParamPackage params({{"engine", "sdl"}}); 493 Common::ParamPackage params({{"engine", "sdl"}});
494
484 switch (event.type) { 495 switch (event.type) {
485 case SDL_JOYAXISMOTION: { 496 case SDL_JOYAXISMOTION: {
486 auto joystick = GetSDLJoystickBySDLID(event.jaxis.which); 497 auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
487 params.Set("port", joystick->GetPort()); 498 params.Set("port", joystick->GetPort());
488 params.Set("guid", joystick->GetGUID()); 499 params.Set("guid", joystick->GetGUID());
489 params.Set("axis", event.jaxis.axis); 500 params.Set("axis", event.jaxis.axis);
@@ -497,14 +508,14 @@ Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event) {
497 break; 508 break;
498 } 509 }
499 case SDL_JOYBUTTONUP: { 510 case SDL_JOYBUTTONUP: {
500 auto joystick = GetSDLJoystickBySDLID(event.jbutton.which); 511 auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
501 params.Set("port", joystick->GetPort()); 512 params.Set("port", joystick->GetPort());
502 params.Set("guid", joystick->GetGUID()); 513 params.Set("guid", joystick->GetGUID());
503 params.Set("button", event.jbutton.button); 514 params.Set("button", event.jbutton.button);
504 break; 515 break;
505 } 516 }
506 case SDL_JOYHATMOTION: { 517 case SDL_JOYHATMOTION: {
507 auto joystick = GetSDLJoystickBySDLID(event.jhat.which); 518 auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
508 params.Set("port", joystick->GetPort()); 519 params.Set("port", joystick->GetPort());
509 params.Set("guid", joystick->GetGUID()); 520 params.Set("guid", joystick->GetGUID());
510 params.Set("hat", event.jhat.hat); 521 params.Set("hat", event.jhat.hat);
@@ -534,21 +545,28 @@ namespace Polling {
534 545
535class SDLPoller : public InputCommon::Polling::DevicePoller { 546class SDLPoller : public InputCommon::Polling::DevicePoller {
536public: 547public:
548 explicit SDLPoller(SDLState& state_) : state(state_) {}
549
537 void Start() override { 550 void Start() override {
538 event_queue.Clear(); 551 state.event_queue.Clear();
539 polling = true; 552 state.polling = true;
540 } 553 }
541 554
542 void Stop() override { 555 void Stop() override {
543 polling = false; 556 state.polling = false;
544 } 557 }
558
559protected:
560 SDLState& state;
545}; 561};
546 562
547class SDLButtonPoller final : public SDLPoller { 563class SDLButtonPoller final : public SDLPoller {
548public: 564public:
565 explicit SDLButtonPoller(SDLState& state_) : SDLPoller(state_) {}
566
549 Common::ParamPackage GetNextInput() override { 567 Common::ParamPackage GetNextInput() override {
550 SDL_Event event; 568 SDL_Event event;
551 while (event_queue.Pop(event)) { 569 while (state.event_queue.Pop(event)) {
552 switch (event.type) { 570 switch (event.type) {
553 case SDL_JOYAXISMOTION: 571 case SDL_JOYAXISMOTION:
554 if (std::abs(event.jaxis.value / 32767.0) < 0.5) { 572 if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
@@ -556,7 +574,7 @@ public:
556 } 574 }
557 case SDL_JOYBUTTONUP: 575 case SDL_JOYBUTTONUP:
558 case SDL_JOYHATMOTION: 576 case SDL_JOYHATMOTION:
559 return SDLEventToButtonParamPackage(event); 577 return SDLEventToButtonParamPackage(state, event);
560 } 578 }
561 } 579 }
562 return {}; 580 return {};
@@ -565,6 +583,8 @@ public:
565 583
566class SDLAnalogPoller final : public SDLPoller { 584class SDLAnalogPoller final : public SDLPoller {
567public: 585public:
586 explicit SDLAnalogPoller(SDLState& state_) : SDLPoller(state_) {}
587
568 void Start() override { 588 void Start() override {
569 SDLPoller::Start(); 589 SDLPoller::Start();
570 590
@@ -576,7 +596,7 @@ public:
576 596
577 Common::ParamPackage GetNextInput() override { 597 Common::ParamPackage GetNextInput() override {
578 SDL_Event event; 598 SDL_Event event;
579 while (event_queue.Pop(event)) { 599 while (state.event_queue.Pop(event)) {
580 if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) { 600 if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) {
581 continue; 601 continue;
582 } 602 }
@@ -593,7 +613,7 @@ public:
593 } 613 }
594 Common::ParamPackage params; 614 Common::ParamPackage params;
595 if (analog_xaxis != -1 && analog_yaxis != -1) { 615 if (analog_xaxis != -1 && analog_yaxis != -1) {
596 auto joystick = GetSDLJoystickBySDLID(event.jaxis.which); 616 auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
597 params.Set("engine", "sdl"); 617 params.Set("engine", "sdl");
598 params.Set("port", joystick->GetPort()); 618 params.Set("port", joystick->GetPort());
599 params.Set("guid", joystick->GetGUID()); 619 params.Set("guid", joystick->GetGUID());
@@ -612,18 +632,21 @@ private:
612 int analog_yaxis = -1; 632 int analog_yaxis = -1;
613 SDL_JoystickID analog_axes_joystick = -1; 633 SDL_JoystickID analog_axes_joystick = -1;
614}; 634};
635} // namespace Polling
615 636
616void GetPollers(InputCommon::Polling::DeviceType type, 637std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> SDLState::GetPollers(
617 std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>>& pollers) { 638 InputCommon::Polling::DeviceType type) {
639 std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> pollers;
618 switch (type) { 640 switch (type) {
619 case InputCommon::Polling::DeviceType::Analog: 641 case InputCommon::Polling::DeviceType::Analog:
620 pollers.emplace_back(std::make_unique<SDLAnalogPoller>()); 642 pollers.emplace_back(std::make_unique<Polling::SDLAnalogPoller>(*this));
621 break; 643 break;
622 case InputCommon::Polling::DeviceType::Button: 644 case InputCommon::Polling::DeviceType::Button:
623 pollers.emplace_back(std::make_unique<SDLButtonPoller>()); 645 pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this));
624 break; 646 break;
647 return pollers;
625 } 648 }
626} 649}
627} // namespace Polling 650
628} // namespace SDL 651} // namespace SDL
629} // namespace InputCommon 652} // namespace InputCommon