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: } bool RumblePlay(const Common::Input::VibrationStatus vibration) { - constexpr u32 rumble_max_duration_ms = 1000; + constexpr u32 rumble_max_duration_ms = 2000; + constexpr f32 low_start_sensitivity_limit = 140.0; + constexpr f32 low_width_sensitivity_limit = 400.0; + constexpr f32 high_start_sensitivity_limit = 200.0; + constexpr f32 high_width_sensitivity_limit = 700.0; + // Try to provide some feeling of the frequency by reducing the amplitude depending on it. + f32 low_frequency_scale = 1.0; + if (vibration.low_frequency > low_start_sensitivity_limit) { + low_frequency_scale = + std::max(1.0f - (vibration.low_frequency - low_start_sensitivity_limit) / + low_width_sensitivity_limit, + 0.3f); + } + f32 low_amplitude = vibration.low_amplitude * low_frequency_scale; + + f32 high_frequency_scale = 1.0; + if (vibration.high_frequency > high_start_sensitivity_limit) { + high_frequency_scale = + std::max(1.0f - (vibration.high_frequency - high_start_sensitivity_limit) / + high_width_sensitivity_limit, + 0.3f); + } + f32 high_amplitude = vibration.high_amplitude * high_frequency_scale; + if (sdl_controller) { - return SDL_GameControllerRumble( - sdl_controller.get(), static_cast<u16>(vibration.low_amplitude), - static_cast<u16>(vibration.high_amplitude), rumble_max_duration_ms) != -1; + return SDL_GameControllerRumble(sdl_controller.get(), static_cast<u16>(low_amplitude), + static_cast<u16>(high_amplitude), + rumble_max_duration_ms) != -1; } else if (sdl_joystick) { - return SDL_JoystickRumble(sdl_joystick.get(), static_cast<u16>(vibration.low_amplitude), - static_cast<u16>(vibration.high_amplitude), + return SDL_JoystickRumble(sdl_joystick.get(), static_cast<u16>(low_amplitude), + static_cast<u16>(high_amplitude), rumble_max_duration_ms) != -1; } @@ -127,6 +150,8 @@ public: if (sdl_controller) { const auto type = SDL_GameControllerGetType(sdl_controller.get()); return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) || + (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT) || + (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) || (type == SDL_CONTROLLER_TYPE_PS5); } return false; @@ -205,9 +230,8 @@ public: return false; } - Common::Input::BatteryLevel GetBatteryLevel() { - const auto level = SDL_JoystickCurrentPowerLevel(sdl_joystick.get()); - switch (level) { + Common::Input::BatteryLevel GetBatteryLevel(SDL_JoystickPowerLevel battery_level) { + switch (battery_level) { case SDL_JOYSTICK_POWER_EMPTY: return Common::Input::BatteryLevel::Empty; case SDL_JOYSTICK_POWER_LOW: @@ -334,11 +358,27 @@ void SDLDriver::InitJoystick(int joystick_index) { const auto guid = GetGUID(sdl_joystick); + if (Settings::values.enable_joycon_driver) { + if (guid.uuid[5] == 0x05 && guid.uuid[4] == 0x7e && + (guid.uuid[8] == 0x06 || guid.uuid[8] == 0x07)) { + LOG_WARNING(Input, "Preferring joycon driver for device index {}", joystick_index); + SDL_JoystickClose(sdl_joystick); + return; + } + } + + if (Settings::values.enable_procon_driver) { + if (guid.uuid[5] == 0x05 && guid.uuid[4] == 0x7e && guid.uuid[8] == 0x09) { + LOG_WARNING(Input, "Preferring joycon driver for device index {}", joystick_index); + SDL_JoystickClose(sdl_joystick); + return; + } + } + std::scoped_lock lock{joystick_map_mutex}; if (joystick_map.find(guid) == joystick_map.end()) { auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller); PreSetController(joystick->GetPadIdentifier()); - SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); joystick->EnableMotion(); joystick_map[guid].emplace_back(std::move(joystick)); return; @@ -358,7 +398,6 @@ void SDLDriver::InitJoystick(int joystick_index) { const int port = static_cast<int>(joystick_guid_list.size()); auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller); PreSetController(joystick->GetPadIdentifier()); - SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); joystick->EnableMotion(); joystick_guid_list.emplace_back(std::move(joystick)); } @@ -398,8 +437,6 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { const PadIdentifier identifier = joystick->GetPadIdentifier(); SetButton(identifier, event.jbutton.button, true); - // Battery doesn't trigger an event so just update every button press - SetBattery(identifier, joystick->GetBatteryLevel()); } break; } @@ -426,6 +463,13 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { } break; } + case SDL_JOYBATTERYUPDATED: { + if (auto joystick = GetSDLJoystickBySDLID(event.jbattery.which)) { + const PadIdentifier identifier = joystick->GetPadIdentifier(); + SetBattery(identifier, joystick->GetBatteryLevel(event.jbattery.level)); + } + break; + } case SDL_JOYDEVICEREMOVED: LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); @@ -443,6 +487,10 @@ void SDLDriver::CloseJoysticks() { } SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) { + // Set our application name. Currently passed to DBus by SDL and visible to the user through + // their desktop environment. + SDL_SetHint(SDL_HINT_APP_NAME, "yuzu"); + if (!Settings::values.enable_raw_input) { // Disable raw input. When enabled this setting causes SDL to die when a web applet opens SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); @@ -456,9 +504,25 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); - // Use hidapi driver for joycons. This will allow joycons to be detected as a GameController and - // not a generic one - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); + // Disable hidapi drivers for joycon controllers when the custom joycon driver is enabled + if (Settings::values.enable_joycon_driver) { + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "0"); + } else { + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOYCON_HOME_LED, "0"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "0"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS, "1"); + } + + // Disable hidapi drivers for pro controllers when the custom joycon driver is enabled + if (Settings::values.enable_procon_driver) { + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "0"); + } else { + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0"); + } + + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED, "1"); // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native // driver on Linux. @@ -548,7 +612,7 @@ std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const { return devices; } -Common::Input::VibrationError SDLDriver::SetVibration( +Common::Input::DriverResult SDLDriver::SetVibration( const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) { const auto joystick = GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port)); @@ -582,14 +646,14 @@ Common::Input::VibrationError SDLDriver::SetVibration( .vibration = new_vibration, }); - return Common::Input::VibrationError::None; + return Common::Input::DriverResult::Success; } bool SDLDriver::IsVibrationEnabled(const PadIdentifier& identifier) { const auto joystick = GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port)); - constexpr Common::Input::VibrationStatus test_vibration{ + static constexpr Common::Input::VibrationStatus test_vibration{ .low_amplitude = 1, .low_frequency = 160.0f, .high_amplitude = 1, @@ -597,7 +661,7 @@ bool SDLDriver::IsVibrationEnabled(const PadIdentifier& identifier) { .type = Common::Input::VibrationAmplificationType::Exponential, }; - constexpr Common::Input::VibrationStatus zero_vibration{ + static constexpr Common::Input::VibrationStatus zero_vibration{ .low_amplitude = 0, .low_frequency = 160.0f, .high_amplitude = 0, @@ -625,12 +689,27 @@ bool SDLDriver::IsVibrationEnabled(const PadIdentifier& identifier) { } void SDLDriver::SendVibrations() { + std::vector<VibrationRequest> filtered_vibrations{}; while (!vibration_queue.Empty()) { VibrationRequest request; vibration_queue.Pop(request); const auto joystick = GetSDLJoystickByGUID(request.identifier.guid.RawString(), static_cast<int>(request.identifier.port)); - joystick->RumblePlay(request.vibration); + const auto it = std::find_if(filtered_vibrations.begin(), filtered_vibrations.end(), + [request](VibrationRequest vibration) { + return vibration.identifier == request.identifier; + }); + if (it == filtered_vibrations.end()) { + filtered_vibrations.push_back(std::move(request)); + continue; + } + *it = request; + } + + for (const auto& vibration : filtered_vibrations) { + const auto joystick = GetSDLJoystickByGUID(vibration.identifier.guid.RawString(), + static_cast<int>(vibration.identifier.port)); + joystick->RumblePlay(vibration.vibration); } } @@ -721,10 +800,12 @@ ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& p // This list is missing ZL/ZR since those are not considered buttons in SDL GameController. // We will add those afterwards - // This list also excludes Screenshot since theres not really a mapping for that + // This list also excludes Screenshot since there's not really a mapping for that ButtonBindings switch_to_sdl_button; - if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) { + if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO || + SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT || + SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) { switch_to_sdl_button = GetNintendoButtonBinding(joystick); } else { switch_to_sdl_button = GetDefaultButtonBinding(); @@ -980,7 +1061,7 @@ MotionMapping SDLDriver::GetMotionMappingForDevice(const Common::ParamPackage& p Common::Input::ButtonNames SDLDriver::GetUIName(const Common::ParamPackage& params) const { if (params.Has("button")) { - // TODO(German77): Find how to substitue the values for real button names + // TODO(German77): Find how to substitute the values for real button names return Common::Input::ButtonNames::Value; } if (params.Has("hat")) { |
