diff options
Diffstat (limited to 'src/input_common/drivers/sdl_driver.cpp')
| -rw-r--r-- | src/input_common/drivers/sdl_driver.cpp | 129 |
1 files changed, 105 insertions, 24 deletions
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 9835d99d2..9f26392b1 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp | |||
| @@ -109,14 +109,37 @@ public: | |||
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | bool RumblePlay(const Common::Input::VibrationStatus vibration) { | 111 | bool RumblePlay(const Common::Input::VibrationStatus vibration) { |
| 112 | constexpr u32 rumble_max_duration_ms = 1000; | 112 | constexpr u32 rumble_max_duration_ms = 2000; |
| 113 | constexpr f32 low_start_sensitivity_limit = 140.0; | ||
| 114 | constexpr f32 low_width_sensitivity_limit = 400.0; | ||
| 115 | constexpr f32 high_start_sensitivity_limit = 200.0; | ||
| 116 | constexpr f32 high_width_sensitivity_limit = 700.0; | ||
| 117 | // Try to provide some feeling of the frequency by reducing the amplitude depending on it. | ||
| 118 | f32 low_frequency_scale = 1.0; | ||
| 119 | if (vibration.low_frequency > low_start_sensitivity_limit) { | ||
| 120 | low_frequency_scale = | ||
| 121 | std::max(1.0f - (vibration.low_frequency - low_start_sensitivity_limit) / | ||
| 122 | low_width_sensitivity_limit, | ||
| 123 | 0.3f); | ||
| 124 | } | ||
| 125 | f32 low_amplitude = vibration.low_amplitude * low_frequency_scale; | ||
| 126 | |||
| 127 | f32 high_frequency_scale = 1.0; | ||
| 128 | if (vibration.high_frequency > high_start_sensitivity_limit) { | ||
| 129 | high_frequency_scale = | ||
| 130 | std::max(1.0f - (vibration.high_frequency - high_start_sensitivity_limit) / | ||
| 131 | high_width_sensitivity_limit, | ||
| 132 | 0.3f); | ||
| 133 | } | ||
| 134 | f32 high_amplitude = vibration.high_amplitude * high_frequency_scale; | ||
| 135 | |||
| 113 | if (sdl_controller) { | 136 | if (sdl_controller) { |
| 114 | return SDL_GameControllerRumble( | 137 | return SDL_GameControllerRumble(sdl_controller.get(), static_cast<u16>(low_amplitude), |
| 115 | sdl_controller.get(), static_cast<u16>(vibration.low_amplitude), | 138 | static_cast<u16>(high_amplitude), |
| 116 | static_cast<u16>(vibration.high_amplitude), rumble_max_duration_ms) != -1; | 139 | rumble_max_duration_ms) != -1; |
| 117 | } else if (sdl_joystick) { | 140 | } else if (sdl_joystick) { |
| 118 | return SDL_JoystickRumble(sdl_joystick.get(), static_cast<u16>(vibration.low_amplitude), | 141 | return SDL_JoystickRumble(sdl_joystick.get(), static_cast<u16>(low_amplitude), |
| 119 | static_cast<u16>(vibration.high_amplitude), | 142 | static_cast<u16>(high_amplitude), |
| 120 | rumble_max_duration_ms) != -1; | 143 | rumble_max_duration_ms) != -1; |
| 121 | } | 144 | } |
| 122 | 145 | ||
| @@ -127,6 +150,8 @@ public: | |||
| 127 | if (sdl_controller) { | 150 | if (sdl_controller) { |
| 128 | const auto type = SDL_GameControllerGetType(sdl_controller.get()); | 151 | const auto type = SDL_GameControllerGetType(sdl_controller.get()); |
| 129 | return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) || | 152 | return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) || |
| 153 | (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT) || | ||
| 154 | (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) || | ||
| 130 | (type == SDL_CONTROLLER_TYPE_PS5); | 155 | (type == SDL_CONTROLLER_TYPE_PS5); |
| 131 | } | 156 | } |
| 132 | return false; | 157 | return false; |
| @@ -205,9 +230,8 @@ public: | |||
| 205 | return false; | 230 | return false; |
| 206 | } | 231 | } |
| 207 | 232 | ||
| 208 | Common::Input::BatteryLevel GetBatteryLevel() { | 233 | Common::Input::BatteryLevel GetBatteryLevel(SDL_JoystickPowerLevel battery_level) { |
| 209 | const auto level = SDL_JoystickCurrentPowerLevel(sdl_joystick.get()); | 234 | switch (battery_level) { |
| 210 | switch (level) { | ||
| 211 | case SDL_JOYSTICK_POWER_EMPTY: | 235 | case SDL_JOYSTICK_POWER_EMPTY: |
| 212 | return Common::Input::BatteryLevel::Empty; | 236 | return Common::Input::BatteryLevel::Empty; |
| 213 | case SDL_JOYSTICK_POWER_LOW: | 237 | case SDL_JOYSTICK_POWER_LOW: |
| @@ -334,11 +358,27 @@ void SDLDriver::InitJoystick(int joystick_index) { | |||
| 334 | 358 | ||
| 335 | const auto guid = GetGUID(sdl_joystick); | 359 | const auto guid = GetGUID(sdl_joystick); |
| 336 | 360 | ||
| 361 | if (Settings::values.enable_joycon_driver) { | ||
| 362 | if (guid.uuid[5] == 0x05 && guid.uuid[4] == 0x7e && | ||
| 363 | (guid.uuid[8] == 0x06 || guid.uuid[8] == 0x07)) { | ||
| 364 | LOG_WARNING(Input, "Preferring joycon driver for device index {}", joystick_index); | ||
| 365 | SDL_JoystickClose(sdl_joystick); | ||
| 366 | return; | ||
| 367 | } | ||
| 368 | } | ||
| 369 | |||
| 370 | if (Settings::values.enable_procon_driver) { | ||
| 371 | if (guid.uuid[5] == 0x05 && guid.uuid[4] == 0x7e && guid.uuid[8] == 0x09) { | ||
| 372 | LOG_WARNING(Input, "Preferring joycon driver for device index {}", joystick_index); | ||
| 373 | SDL_JoystickClose(sdl_joystick); | ||
| 374 | return; | ||
| 375 | } | ||
| 376 | } | ||
| 377 | |||
| 337 | std::scoped_lock lock{joystick_map_mutex}; | 378 | std::scoped_lock lock{joystick_map_mutex}; |
| 338 | if (joystick_map.find(guid) == joystick_map.end()) { | 379 | if (joystick_map.find(guid) == joystick_map.end()) { |
| 339 | auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller); | 380 | auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller); |
| 340 | PreSetController(joystick->GetPadIdentifier()); | 381 | PreSetController(joystick->GetPadIdentifier()); |
| 341 | SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); | ||
| 342 | joystick->EnableMotion(); | 382 | joystick->EnableMotion(); |
| 343 | joystick_map[guid].emplace_back(std::move(joystick)); | 383 | joystick_map[guid].emplace_back(std::move(joystick)); |
| 344 | return; | 384 | return; |
| @@ -358,7 +398,6 @@ void SDLDriver::InitJoystick(int joystick_index) { | |||
| 358 | const int port = static_cast<int>(joystick_guid_list.size()); | 398 | const int port = static_cast<int>(joystick_guid_list.size()); |
| 359 | auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller); | 399 | auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller); |
| 360 | PreSetController(joystick->GetPadIdentifier()); | 400 | PreSetController(joystick->GetPadIdentifier()); |
| 361 | SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); | ||
| 362 | joystick->EnableMotion(); | 401 | joystick->EnableMotion(); |
| 363 | joystick_guid_list.emplace_back(std::move(joystick)); | 402 | joystick_guid_list.emplace_back(std::move(joystick)); |
| 364 | } | 403 | } |
| @@ -398,8 +437,6 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { | |||
| 398 | if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { | 437 | if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { |
| 399 | const PadIdentifier identifier = joystick->GetPadIdentifier(); | 438 | const PadIdentifier identifier = joystick->GetPadIdentifier(); |
| 400 | SetButton(identifier, event.jbutton.button, true); | 439 | SetButton(identifier, event.jbutton.button, true); |
| 401 | // Battery doesn't trigger an event so just update every button press | ||
| 402 | SetBattery(identifier, joystick->GetBatteryLevel()); | ||
| 403 | } | 440 | } |
| 404 | break; | 441 | break; |
| 405 | } | 442 | } |
| @@ -426,6 +463,13 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { | |||
| 426 | } | 463 | } |
| 427 | break; | 464 | break; |
| 428 | } | 465 | } |
| 466 | case SDL_JOYBATTERYUPDATED: { | ||
| 467 | if (auto joystick = GetSDLJoystickBySDLID(event.jbattery.which)) { | ||
| 468 | const PadIdentifier identifier = joystick->GetPadIdentifier(); | ||
| 469 | SetBattery(identifier, joystick->GetBatteryLevel(event.jbattery.level)); | ||
| 470 | } | ||
| 471 | break; | ||
| 472 | } | ||
| 429 | case SDL_JOYDEVICEREMOVED: | 473 | case SDL_JOYDEVICEREMOVED: |
| 430 | LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); | 474 | LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); |
| 431 | CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); | 475 | CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); |
| @@ -443,6 +487,10 @@ void SDLDriver::CloseJoysticks() { | |||
| 443 | } | 487 | } |
| 444 | 488 | ||
| 445 | SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) { | 489 | SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) { |
| 490 | // Set our application name. Currently passed to DBus by SDL and visible to the user through | ||
| 491 | // their desktop environment. | ||
| 492 | SDL_SetHint(SDL_HINT_APP_NAME, "yuzu"); | ||
| 493 | |||
| 446 | if (!Settings::values.enable_raw_input) { | 494 | if (!Settings::values.enable_raw_input) { |
| 447 | // Disable raw input. When enabled this setting causes SDL to die when a web applet opens | 495 | // Disable raw input. When enabled this setting causes SDL to die when a web applet opens |
| 448 | SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); | 496 | SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); |
| @@ -456,9 +504,25 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en | |||
| 456 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); | 504 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); |
| 457 | SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); | 505 | SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); |
| 458 | 506 | ||
| 459 | // Use hidapi driver for joycons. This will allow joycons to be detected as a GameController and | 507 | // Disable hidapi drivers for joycon controllers when the custom joycon driver is enabled |
| 460 | // not a generic one | 508 | if (Settings::values.enable_joycon_driver) { |
| 461 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); | 509 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "0"); |
| 510 | } else { | ||
| 511 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); | ||
| 512 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOYCON_HOME_LED, "0"); | ||
| 513 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "0"); | ||
| 514 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS, "1"); | ||
| 515 | } | ||
| 516 | |||
| 517 | // Disable hidapi drivers for pro controllers when the custom joycon driver is enabled | ||
| 518 | if (Settings::values.enable_procon_driver) { | ||
| 519 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "0"); | ||
| 520 | } else { | ||
| 521 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1"); | ||
| 522 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0"); | ||
| 523 | } | ||
| 524 | |||
| 525 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED, "1"); | ||
| 462 | 526 | ||
| 463 | // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native | 527 | // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native |
| 464 | // driver on Linux. | 528 | // driver on Linux. |
| @@ -548,7 +612,7 @@ std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const { | |||
| 548 | return devices; | 612 | return devices; |
| 549 | } | 613 | } |
| 550 | 614 | ||
| 551 | Common::Input::VibrationError SDLDriver::SetVibration( | 615 | Common::Input::DriverResult SDLDriver::SetVibration( |
| 552 | const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) { | 616 | const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) { |
| 553 | const auto joystick = | 617 | const auto joystick = |
| 554 | GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port)); | 618 | GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port)); |
| @@ -582,14 +646,14 @@ Common::Input::VibrationError SDLDriver::SetVibration( | |||
| 582 | .vibration = new_vibration, | 646 | .vibration = new_vibration, |
| 583 | }); | 647 | }); |
| 584 | 648 | ||
| 585 | return Common::Input::VibrationError::None; | 649 | return Common::Input::DriverResult::Success; |
| 586 | } | 650 | } |
| 587 | 651 | ||
| 588 | bool SDLDriver::IsVibrationEnabled(const PadIdentifier& identifier) { | 652 | bool SDLDriver::IsVibrationEnabled(const PadIdentifier& identifier) { |
| 589 | const auto joystick = | 653 | const auto joystick = |
| 590 | GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port)); | 654 | GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port)); |
| 591 | 655 | ||
| 592 | constexpr Common::Input::VibrationStatus test_vibration{ | 656 | static constexpr Common::Input::VibrationStatus test_vibration{ |
| 593 | .low_amplitude = 1, | 657 | .low_amplitude = 1, |
| 594 | .low_frequency = 160.0f, | 658 | .low_frequency = 160.0f, |
| 595 | .high_amplitude = 1, | 659 | .high_amplitude = 1, |
| @@ -597,7 +661,7 @@ bool SDLDriver::IsVibrationEnabled(const PadIdentifier& identifier) { | |||
| 597 | .type = Common::Input::VibrationAmplificationType::Exponential, | 661 | .type = Common::Input::VibrationAmplificationType::Exponential, |
| 598 | }; | 662 | }; |
| 599 | 663 | ||
| 600 | constexpr Common::Input::VibrationStatus zero_vibration{ | 664 | static constexpr Common::Input::VibrationStatus zero_vibration{ |
| 601 | .low_amplitude = 0, | 665 | .low_amplitude = 0, |
| 602 | .low_frequency = 160.0f, | 666 | .low_frequency = 160.0f, |
| 603 | .high_amplitude = 0, | 667 | .high_amplitude = 0, |
| @@ -625,12 +689,27 @@ bool SDLDriver::IsVibrationEnabled(const PadIdentifier& identifier) { | |||
| 625 | } | 689 | } |
| 626 | 690 | ||
| 627 | void SDLDriver::SendVibrations() { | 691 | void SDLDriver::SendVibrations() { |
| 692 | std::vector<VibrationRequest> filtered_vibrations{}; | ||
| 628 | while (!vibration_queue.Empty()) { | 693 | while (!vibration_queue.Empty()) { |
| 629 | VibrationRequest request; | 694 | VibrationRequest request; |
| 630 | vibration_queue.Pop(request); | 695 | vibration_queue.Pop(request); |
| 631 | const auto joystick = GetSDLJoystickByGUID(request.identifier.guid.RawString(), | 696 | const auto joystick = GetSDLJoystickByGUID(request.identifier.guid.RawString(), |
| 632 | static_cast<int>(request.identifier.port)); | 697 | static_cast<int>(request.identifier.port)); |
| 633 | joystick->RumblePlay(request.vibration); | 698 | const auto it = std::find_if(filtered_vibrations.begin(), filtered_vibrations.end(), |
| 699 | [request](VibrationRequest vibration) { | ||
| 700 | return vibration.identifier == request.identifier; | ||
| 701 | }); | ||
| 702 | if (it == filtered_vibrations.end()) { | ||
| 703 | filtered_vibrations.push_back(std::move(request)); | ||
| 704 | continue; | ||
| 705 | } | ||
| 706 | *it = request; | ||
| 707 | } | ||
| 708 | |||
| 709 | for (const auto& vibration : filtered_vibrations) { | ||
| 710 | const auto joystick = GetSDLJoystickByGUID(vibration.identifier.guid.RawString(), | ||
| 711 | static_cast<int>(vibration.identifier.port)); | ||
| 712 | joystick->RumblePlay(vibration.vibration); | ||
| 634 | } | 713 | } |
| 635 | } | 714 | } |
| 636 | 715 | ||
| @@ -721,10 +800,12 @@ ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& p | |||
| 721 | 800 | ||
| 722 | // This list is missing ZL/ZR since those are not considered buttons in SDL GameController. | 801 | // This list is missing ZL/ZR since those are not considered buttons in SDL GameController. |
| 723 | // We will add those afterwards | 802 | // We will add those afterwards |
| 724 | // This list also excludes Screenshot since theres not really a mapping for that | 803 | // This list also excludes Screenshot since there's not really a mapping for that |
| 725 | ButtonBindings switch_to_sdl_button; | 804 | ButtonBindings switch_to_sdl_button; |
| 726 | 805 | ||
| 727 | if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) { | 806 | if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO || |
| 807 | SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT || | ||
| 808 | SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) { | ||
| 728 | switch_to_sdl_button = GetNintendoButtonBinding(joystick); | 809 | switch_to_sdl_button = GetNintendoButtonBinding(joystick); |
| 729 | } else { | 810 | } else { |
| 730 | switch_to_sdl_button = GetDefaultButtonBinding(); | 811 | switch_to_sdl_button = GetDefaultButtonBinding(); |
| @@ -980,7 +1061,7 @@ MotionMapping SDLDriver::GetMotionMappingForDevice(const Common::ParamPackage& p | |||
| 980 | 1061 | ||
| 981 | Common::Input::ButtonNames SDLDriver::GetUIName(const Common::ParamPackage& params) const { | 1062 | Common::Input::ButtonNames SDLDriver::GetUIName(const Common::ParamPackage& params) const { |
| 982 | if (params.Has("button")) { | 1063 | if (params.Has("button")) { |
| 983 | // TODO(German77): Find how to substitue the values for real button names | 1064 | // TODO(German77): Find how to substitute the values for real button names |
| 984 | return Common::Input::ButtonNames::Value; | 1065 | return Common::Input::ButtonNames::Value; |
| 985 | } | 1066 | } |
| 986 | if (params.Has("hat")) { | 1067 | if (params.Has("hat")) { |