summaryrefslogtreecommitdiff
path: root/src/input_common/drivers/sdl_driver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/input_common/drivers/sdl_driver.cpp')
-rw-r--r--src/input_common/drivers/sdl_driver.cpp167
1 files changed, 118 insertions, 49 deletions
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp
index 5cf1987ad..b72e4b397 100644
--- a/src/input_common/drivers/sdl_driver.cpp
+++ b/src/input_common/drivers/sdl_driver.cpp
@@ -1,6 +1,5 @@
1// Copyright 2018 Citra Emulator Project 1// SPDX-FileCopyrightText: 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version 2// SPDX-License-Identifier: GPL-2.0-or-later
3// Refer to the license.txt file included.
4 3
5#include "common/logging/log.h" 4#include "common/logging/log.h"
6#include "common/math_util.h" 5#include "common/math_util.h"
@@ -13,11 +12,11 @@
13namespace InputCommon { 12namespace InputCommon {
14 13
15namespace { 14namespace {
16std::string GetGUID(SDL_Joystick* joystick) { 15Common::UUID GetGUID(SDL_Joystick* joystick) {
17 const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); 16 const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
18 char guid_str[33]; 17 std::array<u8, 16> data{};
19 SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); 18 std::memcpy(data.data(), guid.data, sizeof(data));
20 return guid_str; 19 return Common::UUID{data};
21} 20}
22} // Anonymous namespace 21} // Anonymous namespace
23 22
@@ -31,9 +30,9 @@ static int SDLEventWatcher(void* user_data, SDL_Event* event) {
31 30
32class SDLJoystick { 31class SDLJoystick {
33public: 32public:
34 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, 33 SDLJoystick(Common::UUID guid_, int port_, SDL_Joystick* joystick,
35 SDL_GameController* game_controller) 34 SDL_GameController* game_controller)
36 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose}, 35 : guid{guid_}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose},
37 sdl_controller{game_controller, &SDL_GameControllerClose} { 36 sdl_controller{game_controller, &SDL_GameControllerClose} {
38 EnableMotion(); 37 EnableMotion();
39 } 38 }
@@ -41,13 +40,13 @@ public:
41 void EnableMotion() { 40 void EnableMotion() {
42 if (sdl_controller) { 41 if (sdl_controller) {
43 SDL_GameController* controller = sdl_controller.get(); 42 SDL_GameController* controller = sdl_controller.get();
44 if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) && !has_accel) { 43 has_accel = SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL);
44 has_gyro = SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO);
45 if (has_accel) {
45 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE); 46 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE);
46 has_accel = true;
47 } 47 }
48 if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) && !has_gyro) { 48 if (has_gyro) {
49 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE); 49 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE);
50 has_gyro = true;
51 } 50 }
52 } 51 }
53 } 52 }
@@ -62,7 +61,7 @@ public:
62 61
63 bool UpdateMotion(SDL_ControllerSensorEvent event) { 62 bool UpdateMotion(SDL_ControllerSensorEvent event) {
64 constexpr float gravity_constant = 9.80665f; 63 constexpr float gravity_constant = 9.80665f;
65 std::lock_guard lock{mutex}; 64 std::scoped_lock lock{mutex};
66 const u64 time_difference = event.timestamp - last_motion_update; 65 const u64 time_difference = event.timestamp - last_motion_update;
67 last_motion_update = event.timestamp; 66 last_motion_update = event.timestamp;
68 switch (event.sensor) { 67 switch (event.sensor) {
@@ -120,7 +119,7 @@ public:
120 */ 119 */
121 const PadIdentifier GetPadIdentifier() const { 120 const PadIdentifier GetPadIdentifier() const {
122 return { 121 return {
123 .guid = Common::UUID{guid}, 122 .guid = guid,
124 .port = static_cast<std::size_t>(port), 123 .port = static_cast<std::size_t>(port),
125 .pad = 0, 124 .pad = 0,
126 }; 125 };
@@ -129,7 +128,7 @@ public:
129 /** 128 /**
130 * The guid of the joystick 129 * The guid of the joystick
131 */ 130 */
132 const std::string& GetGUID() const { 131 const Common::UUID& GetGUID() const {
133 return guid; 132 return guid;
134 } 133 }
135 134
@@ -175,22 +174,23 @@ public:
175 return false; 174 return false;
176 } 175 }
177 176
178 BatteryLevel GetBatteryLevel() { 177 Common::Input::BatteryLevel GetBatteryLevel() {
179 const auto level = SDL_JoystickCurrentPowerLevel(sdl_joystick.get()); 178 const auto level = SDL_JoystickCurrentPowerLevel(sdl_joystick.get());
180 switch (level) { 179 switch (level) {
181 case SDL_JOYSTICK_POWER_EMPTY: 180 case SDL_JOYSTICK_POWER_EMPTY:
182 return BatteryLevel::Empty; 181 return Common::Input::BatteryLevel::Empty;
183 case SDL_JOYSTICK_POWER_LOW: 182 case SDL_JOYSTICK_POWER_LOW:
184 return BatteryLevel::Low; 183 return Common::Input::BatteryLevel::Low;
185 case SDL_JOYSTICK_POWER_MEDIUM: 184 case SDL_JOYSTICK_POWER_MEDIUM:
186 return BatteryLevel::Medium; 185 return Common::Input::BatteryLevel::Medium;
187 case SDL_JOYSTICK_POWER_FULL: 186 case SDL_JOYSTICK_POWER_FULL:
188 case SDL_JOYSTICK_POWER_MAX: 187 case SDL_JOYSTICK_POWER_MAX:
189 return BatteryLevel::Full; 188 return Common::Input::BatteryLevel::Full;
190 case SDL_JOYSTICK_POWER_UNKNOWN:
191 case SDL_JOYSTICK_POWER_WIRED: 189 case SDL_JOYSTICK_POWER_WIRED:
190 return Common::Input::BatteryLevel::Charging;
191 case SDL_JOYSTICK_POWER_UNKNOWN:
192 default: 192 default:
193 return BatteryLevel::Charging; 193 return Common::Input::BatteryLevel::None;
194 } 194 }
195 } 195 }
196 196
@@ -227,7 +227,7 @@ public:
227 } 227 }
228 228
229private: 229private:
230 std::string guid; 230 Common::UUID guid;
231 int port; 231 int port;
232 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; 232 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
233 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; 233 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
@@ -239,8 +239,8 @@ private:
239 BasicMotion motion; 239 BasicMotion motion;
240}; 240};
241 241
242std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickByGUID(const std::string& guid, int port) { 242std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickByGUID(const Common::UUID& guid, int port) {
243 std::lock_guard lock{joystick_map_mutex}; 243 std::scoped_lock lock{joystick_map_mutex};
244 const auto it = joystick_map.find(guid); 244 const auto it = joystick_map.find(guid);
245 245
246 if (it != joystick_map.end()) { 246 if (it != joystick_map.end()) {
@@ -258,11 +258,15 @@ std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickByGUID(const std::string&
258 return joystick_map[guid].emplace_back(std::move(joystick)); 258 return joystick_map[guid].emplace_back(std::move(joystick));
259} 259}
260 260
261std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickByGUID(const std::string& guid, int port) {
262 return GetSDLJoystickByGUID(Common::UUID{guid}, port);
263}
264
261std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { 265std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
262 auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id); 266 auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
263 const std::string guid = GetGUID(sdl_joystick); 267 const auto guid = GetGUID(sdl_joystick);
264 268
265 std::lock_guard lock{joystick_map_mutex}; 269 std::scoped_lock lock{joystick_map_mutex};
266 const auto map_it = joystick_map.find(guid); 270 const auto map_it = joystick_map.find(guid);
267 271
268 if (map_it == joystick_map.end()) { 272 if (map_it == joystick_map.end()) {
@@ -294,13 +298,14 @@ void SDLDriver::InitJoystick(int joystick_index) {
294 return; 298 return;
295 } 299 }
296 300
297 const std::string guid = GetGUID(sdl_joystick); 301 const auto guid = GetGUID(sdl_joystick);
298 302
299 std::lock_guard lock{joystick_map_mutex}; 303 std::scoped_lock lock{joystick_map_mutex};
300 if (joystick_map.find(guid) == joystick_map.end()) { 304 if (joystick_map.find(guid) == joystick_map.end()) {
301 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller); 305 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);
302 PreSetController(joystick->GetPadIdentifier()); 306 PreSetController(joystick->GetPadIdentifier());
303 SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); 307 SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel());
308 joystick->EnableMotion();
304 joystick_map[guid].emplace_back(std::move(joystick)); 309 joystick_map[guid].emplace_back(std::move(joystick));
305 return; 310 return;
306 } 311 }
@@ -312,6 +317,7 @@ void SDLDriver::InitJoystick(int joystick_index) {
312 317
313 if (joystick_it != joystick_guid_list.end()) { 318 if (joystick_it != joystick_guid_list.end()) {
314 (*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller); 319 (*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller);
320 (*joystick_it)->EnableMotion();
315 return; 321 return;
316 } 322 }
317 323
@@ -319,13 +325,14 @@ void SDLDriver::InitJoystick(int joystick_index) {
319 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller); 325 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
320 PreSetController(joystick->GetPadIdentifier()); 326 PreSetController(joystick->GetPadIdentifier());
321 SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); 327 SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel());
328 joystick->EnableMotion();
322 joystick_guid_list.emplace_back(std::move(joystick)); 329 joystick_guid_list.emplace_back(std::move(joystick));
323} 330}
324 331
325void SDLDriver::CloseJoystick(SDL_Joystick* sdl_joystick) { 332void SDLDriver::CloseJoystick(SDL_Joystick* sdl_joystick) {
326 const std::string guid = GetGUID(sdl_joystick); 333 const auto guid = GetGUID(sdl_joystick);
327 334
328 std::lock_guard lock{joystick_map_mutex}; 335 std::scoped_lock lock{joystick_map_mutex};
329 // This call to guid is safe since the joystick is guaranteed to be in the map 336 // This call to guid is safe since the joystick is guaranteed to be in the map
330 const auto& joystick_guid_list = joystick_map[guid]; 337 const auto& joystick_guid_list = joystick_map[guid];
331 const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), 338 const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
@@ -351,6 +358,8 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
351 if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { 358 if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
352 const PadIdentifier identifier = joystick->GetPadIdentifier(); 359 const PadIdentifier identifier = joystick->GetPadIdentifier();
353 SetButton(identifier, event.jbutton.button, true); 360 SetButton(identifier, event.jbutton.button, true);
361 // Battery doesn't trigger an event so just update every button press
362 SetBattery(identifier, joystick->GetBatteryLevel());
354 } 363 }
355 break; 364 break;
356 } 365 }
@@ -389,7 +398,7 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
389} 398}
390 399
391void SDLDriver::CloseJoysticks() { 400void SDLDriver::CloseJoysticks() {
392 std::lock_guard lock{joystick_map_mutex}; 401 std::scoped_lock lock{joystick_map_mutex};
393 joystick_map.clear(); 402 joystick_map.clear();
394} 403}
395 404
@@ -427,13 +436,21 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
427 initialized = true; 436 initialized = true;
428 if (start_thread) { 437 if (start_thread) {
429 poll_thread = std::thread([this] { 438 poll_thread = std::thread([this] {
430 Common::SetCurrentThreadName("yuzu:input:SDL"); 439 Common::SetCurrentThreadName("SDL_MainLoop");
431 using namespace std::chrono_literals; 440 using namespace std::chrono_literals;
432 while (initialized) { 441 while (initialized) {
433 SDL_PumpEvents(); 442 SDL_PumpEvents();
434 std::this_thread::sleep_for(1ms); 443 std::this_thread::sleep_for(1ms);
435 } 444 }
436 }); 445 });
446 vibration_thread = std::thread([this] {
447 Common::SetCurrentThreadName("SDL_Vibration");
448 using namespace std::chrono_literals;
449 while (initialized) {
450 SendVibrations();
451 std::this_thread::sleep_for(10ms);
452 }
453 });
437 } 454 }
438 // Because the events for joystick connection happens before we have our event watcher added, we 455 // Because the events for joystick connection happens before we have our event watcher added, we
439 // can just open all the joysticks right here 456 // can just open all the joysticks right here
@@ -449,6 +466,7 @@ SDLDriver::~SDLDriver() {
449 initialized = false; 466 initialized = false;
450 if (start_thread) { 467 if (start_thread) {
451 poll_thread.join(); 468 poll_thread.join();
469 vibration_thread.join();
452 SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER); 470 SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
453 } 471 }
454} 472}
@@ -466,7 +484,7 @@ std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const {
466 devices.emplace_back(Common::ParamPackage{ 484 devices.emplace_back(Common::ParamPackage{
467 {"engine", GetEngineName()}, 485 {"engine", GetEngineName()},
468 {"display", std::move(name)}, 486 {"display", std::move(name)},
469 {"guid", joystick->GetGUID()}, 487 {"guid", joystick->GetGUID().RawString()},
470 {"port", std::to_string(joystick->GetPort())}, 488 {"port", std::to_string(joystick->GetPort())},
471 }); 489 });
472 if (joystick->IsJoyconLeft()) { 490 if (joystick->IsJoyconLeft()) {
@@ -489,8 +507,8 @@ std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const {
489 devices.emplace_back(Common::ParamPackage{ 507 devices.emplace_back(Common::ParamPackage{
490 {"engine", GetEngineName()}, 508 {"engine", GetEngineName()},
491 {"display", std::move(name)}, 509 {"display", std::move(name)},
492 {"guid", joystick->GetGUID()}, 510 {"guid", joystick->GetGUID().RawString()},
493 {"guid2", joystick2->GetGUID()}, 511 {"guid2", joystick2->GetGUID().RawString()},
494 {"port", std::to_string(joystick->GetPort())}, 512 {"port", std::to_string(joystick->GetPort())},
495 }); 513 });
496 } 514 }
@@ -528,57 +546,75 @@ Common::Input::VibrationError SDLDriver::SetRumble(
528 .type = Common::Input::VibrationAmplificationType::Exponential, 546 .type = Common::Input::VibrationAmplificationType::Exponential,
529 }; 547 };
530 548
531 if (!joystick->RumblePlay(new_vibration)) { 549 if (vibration.type == Common::Input::VibrationAmplificationType::Test) {
532 return Common::Input::VibrationError::Unknown; 550 if (!joystick->RumblePlay(new_vibration)) {
551 return Common::Input::VibrationError::Unknown;
552 }
553 return Common::Input::VibrationError::None;
533 } 554 }
534 555
556 vibration_queue.Push(VibrationRequest{
557 .identifier = identifier,
558 .vibration = new_vibration,
559 });
560
535 return Common::Input::VibrationError::None; 561 return Common::Input::VibrationError::None;
536} 562}
537 563
538Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid, 564void SDLDriver::SendVibrations() {
565 while (!vibration_queue.Empty()) {
566 VibrationRequest request;
567 vibration_queue.Pop(request);
568 const auto joystick = GetSDLJoystickByGUID(request.identifier.guid.RawString(),
569 static_cast<int>(request.identifier.port));
570 joystick->RumblePlay(request.vibration);
571 }
572}
573
574Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, const Common::UUID& guid,
539 s32 axis, float value) const { 575 s32 axis, float value) const {
540 Common::ParamPackage params{}; 576 Common::ParamPackage params{};
541 params.Set("engine", GetEngineName()); 577 params.Set("engine", GetEngineName());
542 params.Set("port", port); 578 params.Set("port", port);
543 params.Set("guid", std::move(guid)); 579 params.Set("guid", guid.RawString());
544 params.Set("axis", axis); 580 params.Set("axis", axis);
545 params.Set("threshold", "0.5"); 581 params.Set("threshold", "0.5");
546 params.Set("invert", value < 0 ? "-" : "+"); 582 params.Set("invert", value < 0 ? "-" : "+");
547 return params; 583 return params;
548} 584}
549 585
550Common::ParamPackage SDLDriver::BuildButtonParamPackageForButton(int port, std::string guid, 586Common::ParamPackage SDLDriver::BuildButtonParamPackageForButton(int port, const Common::UUID& guid,
551 s32 button) const { 587 s32 button) const {
552 Common::ParamPackage params{}; 588 Common::ParamPackage params{};
553 params.Set("engine", GetEngineName()); 589 params.Set("engine", GetEngineName());
554 params.Set("port", port); 590 params.Set("port", port);
555 params.Set("guid", std::move(guid)); 591 params.Set("guid", guid.RawString());
556 params.Set("button", button); 592 params.Set("button", button);
557 return params; 593 return params;
558} 594}
559 595
560Common::ParamPackage SDLDriver::BuildHatParamPackageForButton(int port, std::string guid, s32 hat, 596Common::ParamPackage SDLDriver::BuildHatParamPackageForButton(int port, const Common::UUID& guid,
561 u8 value) const { 597 s32 hat, u8 value) const {
562 Common::ParamPackage params{}; 598 Common::ParamPackage params{};
563 params.Set("engine", GetEngineName()); 599 params.Set("engine", GetEngineName());
564 params.Set("port", port); 600 params.Set("port", port);
565 params.Set("guid", std::move(guid)); 601 params.Set("guid", guid.RawString());
566 params.Set("hat", hat); 602 params.Set("hat", hat);
567 params.Set("direction", GetHatButtonName(value)); 603 params.Set("direction", GetHatButtonName(value));
568 return params; 604 return params;
569} 605}
570 606
571Common::ParamPackage SDLDriver::BuildMotionParam(int port, std::string guid) const { 607Common::ParamPackage SDLDriver::BuildMotionParam(int port, const Common::UUID& guid) const {
572 Common::ParamPackage params{}; 608 Common::ParamPackage params{};
573 params.Set("engine", GetEngineName()); 609 params.Set("engine", GetEngineName());
574 params.Set("motion", 0); 610 params.Set("motion", 0);
575 params.Set("port", port); 611 params.Set("port", port);
576 params.Set("guid", std::move(guid)); 612 params.Set("guid", guid.RawString());
577 return params; 613 return params;
578} 614}
579 615
580Common::ParamPackage SDLDriver::BuildParamPackageForBinding( 616Common::ParamPackage SDLDriver::BuildParamPackageForBinding(
581 int port, const std::string& guid, const SDL_GameControllerButtonBind& binding) const { 617 int port, const Common::UUID& guid, const SDL_GameControllerButtonBind& binding) const {
582 switch (binding.bindType) { 618 switch (binding.bindType) {
583 case SDL_CONTROLLER_BINDTYPE_NONE: 619 case SDL_CONTROLLER_BINDTYPE_NONE:
584 break; 620 break;
@@ -931,4 +967,37 @@ u8 SDLDriver::GetHatButtonId(const std::string& direction_name) const {
931 return direction; 967 return direction;
932} 968}
933 969
970bool SDLDriver::IsStickInverted(const Common::ParamPackage& params) {
971 if (!params.Has("guid") || !params.Has("port")) {
972 return false;
973 }
974 const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
975 if (joystick == nullptr) {
976 return false;
977 }
978 auto* controller = joystick->GetSDLGameController();
979 if (controller == nullptr) {
980 return false;
981 }
982
983 const auto& axis_x = params.Get("axis_x", 0);
984 const auto& axis_y = params.Get("axis_y", 0);
985 const auto& binding_left_x =
986 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
987 const auto& binding_right_x =
988 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
989 const auto& binding_left_y =
990 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
991 const auto& binding_right_y =
992 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
993
994 if (axis_x != binding_left_y.value.axis && axis_x != binding_right_y.value.axis) {
995 return false;
996 }
997 if (axis_y != binding_left_x.value.axis && axis_y != binding_right_x.value.axis) {
998 return false;
999 }
1000 return true;
1001}
1002
934} // namespace InputCommon 1003} // namespace InputCommon