diff options
| author | Jordan Woyak <jordan.woyak@gmail.com> | 2025-05-21 17:43:09 -0500 |
|---|---|---|
| committer | Jordan Woyak <jordan.woyak@gmail.com> | 2025-06-07 16:27:54 -0500 |
| commit | 6da3f5f26adf13b9fedfb85b0ebe844cb5b94a0c (patch) | |
| tree | cec042e71b76cd137fd735e5c65a980a4792a484 /Source/Core/InputCommon | |
| parent | da8610e76fc1ae09562df3152a28be7f50d6e317 (diff) | |
InputCommon: Update to use SDL3 and bump the SDL submodule in Externals to release-3.2.16.
Diffstat (limited to 'Source/Core/InputCommon')
5 files changed, 198 insertions, 212 deletions
diff --git a/Source/Core/InputCommon/CMakeLists.txt b/Source/Core/InputCommon/CMakeLists.txt index d19a1ef3a2..0e5612f353 100644 --- a/Source/Core/InputCommon/CMakeLists.txt +++ b/Source/Core/InputCommon/CMakeLists.txt @@ -180,8 +180,8 @@ if(ENABLE_SDL) ControllerInterface/SDL/SDLGamepad.cpp ControllerInterface/SDL/SDLGamepad.h ) - target_link_libraries(inputcommon PRIVATE SDL2::SDL2) - target_compile_definitions(inputcommon PUBLIC HAVE_SDL2=1) + target_link_libraries(inputcommon PRIVATE SDL3::SDL3) + target_compile_definitions(inputcommon PUBLIC HAVE_SDL3=1) endif() if(MSVC) diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h index d3998a4839..e5712f0a4f 100644 --- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h +++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h @@ -31,7 +31,7 @@ #define CIFACE_USE_PIPES #endif #define CIFACE_USE_DUALSHOCKUDPCLIENT -#if defined(HAVE_SDL2) +#if defined(HAVE_SDL3) #define CIFACE_USE_SDL #endif #if defined(HAVE_HIDAPI) diff --git a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp index 07a38b0289..59b3b21bea 100644 --- a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp +++ b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp @@ -3,6 +3,7 @@ #include "InputCommon/ControllerInterface/SDL/SDL.h" +#include <span> #include <thread> #include <vector> @@ -10,7 +11,7 @@ #include <Windows.h> #endif -#include <SDL.h> +#include <SDL3/SDL.h> #include "Common/Event.h" #include "Common/Logging/Log.h" @@ -31,7 +32,7 @@ public: void UpdateInput(std::vector<std::weak_ptr<ciface::Core::Device>>& devices_to_remove) override; private: - void OpenAndAddDevice(int index); + void OpenAndAddDevice(SDL_JoystickID instance_id); bool HandleEventAndContinue(const SDL_Event& e); @@ -48,10 +49,10 @@ std::unique_ptr<ciface::InputBackend> CreateInputBackend(ControllerInterface* co static void EnableSDLLogging() { - SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE); - SDL_LogSetOutputFunction( + SDL_SetLogPriorities(SDL_LOG_PRIORITY_VERBOSE); + SDL_SetLogOutputFunction( [](void*, int category, SDL_LogPriority priority, const char* message) { - std::string category_name; + std::string_view category_name{}; switch (category) { case SDL_LOG_CATEGORY_APPLICATION: @@ -81,8 +82,10 @@ static void EnableSDLLogging() case SDL_LOG_CATEGORY_TEST: category_name = "test"; break; + case SDL_LOG_CATEGORY_GPU: + category_name = "gpu"; + break; default: - category_name = fmt::format("unknown({})", category); break; } @@ -108,8 +111,16 @@ static void EnableSDLLogging() break; } - GENERIC_LOG_FMT(Common::Log::LogType::CONTROLLERINTERFACE, log_level, "{}: {}", - category_name, message); + if (category_name.empty()) + { + GENERIC_LOG_FMT(Common::Log::LogType::CONTROLLERINTERFACE, log_level, "unknown({}): {}", + category, message); + } + else + { + GENERIC_LOG_FMT(Common::Log::LogType::CONTROLLERINTERFACE, log_level, "{}: {}", + category_name, message); + } }, nullptr); } @@ -122,9 +133,8 @@ InputBackend::InputBackend(ControllerInterface* controller_interface) // This is required on windows so that SDL's joystick code properly pumps window messages SDL_SetHint(SDL_HINT_JOYSTICK_THREAD, "1"); - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); - // We want buttons to come in as positions, not labels - SDL_SetHint(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, "0"); + SDL_SetHint(SDL_HINT_JOYSTICK_ENHANCED_REPORTS, "1"); + // We have our own WGI backend. Enabling SDL's WGI handling creates even more redundant devices. SDL_SetHint(SDL_HINT_JOYSTICK_WGI, "0"); @@ -139,7 +149,7 @@ InputBackend::InputBackend(ControllerInterface* controller_interface) { Common::ScopeGuard init_guard([this] { m_init_event.Set(); }); - if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER) != 0) + if (!SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMEPAD)) { ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL failed to initialize"); return; @@ -160,7 +170,7 @@ InputBackend::InputBackend(ControllerInterface* controller_interface) // duplicate devices. Adding devices will actually "fail" here, as the ControllerInterface // hasn't finished initializing yet. SDL_Event e; - while (SDL_PollEvent(&e) != 0) + while (SDL_PollEvent(&e)) { if (!HandleEventAndContinue(e)) return; @@ -179,7 +189,7 @@ InputBackend::InputBackend(ControllerInterface* controller_interface) #endif SDL_Event e; - while (SDL_WaitEvent(&e) != 0) + while (SDL_WaitEvent(&e)) { if (!HandleEventAndContinue(e)) return; @@ -221,20 +231,20 @@ void InputBackend::PopulateDevices() SDL_PushEvent(&populate_event); } -void InputBackend::UpdateInput(std::vector<std::weak_ptr<ciface::Core::Device>>& devices_to_remove) +void InputBackend::UpdateInput(std::vector<std::weak_ptr<ciface::Core::Device>>&) { - SDL_GameControllerUpdate(); + SDL_UpdateGamepads(); } -void InputBackend::OpenAndAddDevice(int index) +void InputBackend::OpenAndAddDevice(SDL_JoystickID instance_id) { - SDL_GameController* gc = SDL_GameControllerOpen(index); - SDL_Joystick* js = SDL_JoystickOpen(index); + SDL_Gamepad* gc = SDL_OpenGamepad(instance_id); + SDL_Joystick* js = SDL_OpenJoystick(instance_id); - if (js) + if (js != nullptr) { - if (SDL_JoystickNumButtons(js) > 255 || SDL_JoystickNumAxes(js) > 255 || - SDL_JoystickNumHats(js) > 255 || SDL_JoystickNumBalls(js) > 255) + if (SDL_GetNumJoystickButtons(js) > 255 || SDL_GetNumJoystickAxes(js) > 255 || + SDL_GetNumJoystickHats(js) > 255 || SDL_GetNumJoystickBalls(js) > 255) { // This device is invalid, don't use it // Some crazy devices (HP webcam 2100) end up as HID devices @@ -249,17 +259,12 @@ void InputBackend::OpenAndAddDevice(int index) bool InputBackend::HandleEventAndContinue(const SDL_Event& e) { - if (e.type == SDL_JOYDEVICEADDED) + if (e.type == SDL_EVENT_JOYSTICK_ADDED) { - // NOTE: SDL_JOYDEVICEADDED's `jdevice.which` is a device index in SDL2. - // It will change to an "instance ID" in SDL3. - // OpenAndAddDevice impl and calls will need refactoring when changing to SDL3. - static_assert(!SDL_VERSION_ATLEAST(3, 0, 0), "Refactoring is needed for SDL3."); OpenAndAddDevice(e.jdevice.which); } - else if (e.type == SDL_JOYDEVICEREMOVED) + else if (e.type == SDL_EVENT_JOYSTICK_REMOVED) { - // NOTE: SDL_JOYDEVICEREMOVED's `jdevice.which` is an "instance ID". GetControllerInterface().RemoveDevice([&e](const auto* device) { return device->GetSource() == "SDL" && static_cast<const GameController*>(device)->GetSDLInstanceID() == e.jdevice.which; @@ -268,8 +273,12 @@ bool InputBackend::HandleEventAndContinue(const SDL_Event& e) else if (e.type == m_populate_event_type) { GetControllerInterface().PlatformPopulateDevices([this] { - for (int i = 0; i < SDL_NumJoysticks(); ++i) - OpenAndAddDevice(i); + int joystick_count = 0; + auto* const joystick_ids = SDL_GetJoysticks(&joystick_count); + for (auto instance_id : std::span(joystick_ids, joystick_count)) + OpenAndAddDevice(instance_id); + + SDL_free(joystick_ids); }); } else if (e.type == m_stop_event_type) diff --git a/Source/Core/InputCommon/ControllerInterface/SDL/SDLGamepad.cpp b/Source/Core/InputCommon/ControllerInterface/SDL/SDLGamepad.cpp index 78df8f7ed7..345bef00a3 100644 --- a/Source/Core/InputCommon/ControllerInterface/SDL/SDLGamepad.cpp +++ b/Source/Core/InputCommon/ControllerInterface/SDL/SDLGamepad.cpp @@ -4,9 +4,11 @@ #include "InputCommon/ControllerInterface/SDL/SDLGamepad.h" #include <array> +#include <span> #include <unordered_set> #include "Common/Logging/Log.h" +#include "Common/ScopeGuard.h" namespace ciface::SDL { @@ -17,16 +19,12 @@ bool IsTriggerAxis(int index) return index >= 4; } -GameController::GameController(SDL_GameController* const gamecontroller, - SDL_Joystick* const joystick) +GameController::GameController(SDL_Gamepad* const gamecontroller, SDL_Joystick* const joystick) : m_gamecontroller(gamecontroller), m_joystick(joystick) { - const char* name; - if (gamecontroller) - name = SDL_GameControllerName(gamecontroller); - else - name = SDL_JoystickName(joystick); - m_name = name != nullptr ? name : "Unknown"; + const char* const sdl_name = (gamecontroller != nullptr) ? SDL_GetGamepadName(gamecontroller) : + SDL_GetJoystickName(joystick); + m_name = (sdl_name != nullptr) ? sdl_name : "Unknown"; // If a Joystick input has a GameController equivalent button/hat we don't add it. // "Equivalent" axes are still added as hidden/undetectable inputs to handle @@ -35,17 +33,17 @@ GameController::GameController(SDL_GameController* const gamecontroller, std::unordered_set<int> registered_buttons; std::unordered_set<int> registered_hats; std::unordered_set<int> registered_axes; - const auto register_mapping = [&](const SDL_GameControllerButtonBind& bind) { - switch (bind.bindType) + const auto register_mapping = [&](const SDL_GamepadBinding& bind) { + switch (bind.input_type) { - case SDL_CONTROLLER_BINDTYPE_BUTTON: - registered_buttons.insert(bind.value.button); + case SDL_GAMEPAD_BINDTYPE_BUTTON: + registered_buttons.insert(bind.input.button); break; - case SDL_CONTROLLER_BINDTYPE_HAT: - registered_hats.insert(bind.value.hat.hat); + case SDL_GAMEPAD_BINDTYPE_HAT: + registered_hats.insert(bind.input.hat.hat); break; - case SDL_CONTROLLER_BINDTYPE_AXIS: - registered_axes.insert(bind.value.axis); + case SDL_GAMEPAD_BINDTYPE_AXIS: + registered_axes.insert(bind.input.axis.axis); break; default: break; @@ -55,25 +53,22 @@ GameController::GameController(SDL_GameController* const gamecontroller, if (gamecontroller != nullptr) { // Inputs + int binding_count = 0; + auto** bindings = SDL_GetGamepadBindings(gamecontroller, &binding_count); + Common::ScopeGuard free_bindings([&] { SDL_free(bindings); }); - // Buttons - for (u8 i = 0; i != size(s_sdl_button_names); ++i) + for (auto* const binding : std::span(bindings, binding_count)) { - SDL_GameControllerButton button = static_cast<SDL_GameControllerButton>(i); - if (SDL_GameControllerHasButton(m_gamecontroller, button)) - { - AddInput(new Button(gamecontroller, button)); - - register_mapping(SDL_GameControllerGetBindForButton(gamecontroller, button)); - } - } + register_mapping(*binding); - // Axes - for (u8 i = 0; i != size(s_sdl_axis_names); ++i) - { - SDL_GameControllerAxis axis = static_cast<SDL_GameControllerAxis>(i); - if (SDL_GameControllerHasAxis(m_gamecontroller, axis)) + switch (binding->output_type) + { + case SDL_GAMEPAD_BINDTYPE_BUTTON: + AddInput(new Button(gamecontroller, *binding)); + break; + case SDL_GAMEPAD_BINDTYPE_AXIS: { + const auto axis = binding->output.axis.axis; if (IsTriggerAxis(axis)) { AddInput(new Axis(m_gamecontroller, 32767, axis)); @@ -84,19 +79,23 @@ GameController::GameController(SDL_GameController* const gamecontroller, AddInput(new Axis(m_gamecontroller, -32768, axis)); AddInput(new Axis(m_gamecontroller, 32767, axis)); } - - register_mapping(SDL_GameControllerGetBindForAxis(gamecontroller, axis)); + break; + } + default: + break; } } + const auto properties = SDL_GetGamepadProperties(m_gamecontroller); + // Rumble - if (SDL_GameControllerHasRumble(m_gamecontroller)) + if (SDL_GetBooleanProperty(properties, SDL_PROP_GAMEPAD_CAP_RUMBLE_BOOLEAN, false)) { AddOutput(new CombinedMotor(*this, &m_low_freq_rumble, &m_high_freq_rumble)); AddOutput(new Rumble("Motor L", *this, &m_low_freq_rumble, &GameController::UpdateRumble)); AddOutput(new Rumble("Motor R", *this, &m_high_freq_rumble, &GameController::UpdateRumble)); } - if (SDL_GameControllerHasRumbleTriggers(m_gamecontroller)) + if (SDL_GetBooleanProperty(properties, SDL_PROP_GAMEPAD_CAP_TRIGGER_RUMBLE_BOOLEAN, false)) { AddOutput(new Rumble("Trigger L", *this, &m_trigger_l_rumble, &GameController::UpdateRumbleTriggers)); @@ -105,7 +104,7 @@ GameController::GameController(SDL_GameController* const gamecontroller, } // Touchpad - if (SDL_GameControllerGetNumTouchpads(m_gamecontroller) > 0) + if (SDL_GetNumGamepadTouchpads(m_gamecontroller) > 0) { const char* const name_x = "Touchpad X"; AddInput(new NonDetectableDirectionalInput<-1>(name_x, &m_touchpad_x)); @@ -119,7 +118,7 @@ GameController::GameController(SDL_GameController* const gamecontroller, // Motion const auto add_sensor = [this](SDL_SensorType type, std::string_view sensor_name, const SDLMotionAxisList& axes) { - if (SDL_GameControllerSetSensorEnabled(m_gamecontroller, type, SDL_TRUE) == 0) + if (SDL_SetGamepadSensorEnabled(m_gamecontroller, type, true)) { for (const SDLMotionAxis& axis : axes) { @@ -140,7 +139,7 @@ GameController::GameController(SDL_GameController* const gamecontroller, // Legacy inputs // Buttons - int n_legacy_buttons = SDL_JoystickNumButtons(joystick); + int n_legacy_buttons = SDL_GetNumJoystickButtons(joystick); if (n_legacy_buttons < 0) { ERROR_LOG_FMT(CONTROLLERINTERFACE, "Error in SDL_JoystickNumButtons(): {}", SDL_GetError()); @@ -155,7 +154,7 @@ GameController::GameController(SDL_GameController* const gamecontroller, } // Axes - int n_legacy_axes = SDL_JoystickNumAxes(joystick); + int n_legacy_axes = SDL_GetNumJoystickAxes(joystick); if (n_legacy_axes < 0) { ERROR_LOG_FMT(CONTROLLERINTERFACE, "Error in SDL_JoystickNumAxes(): {}", SDL_GetError()); @@ -171,7 +170,7 @@ GameController::GameController(SDL_GameController* const gamecontroller, } // Hats - int n_legacy_hats = SDL_JoystickNumHats(joystick); + int n_legacy_hats = SDL_GetNumJoystickHats(joystick); if (n_legacy_hats < 0) { ERROR_LOG_FMT(CONTROLLERINTERFACE, "Error in SDL_JoystickNumHats(): {}", SDL_GetError()); @@ -188,16 +187,16 @@ GameController::GameController(SDL_GameController* const gamecontroller, } // Haptics - if (SDL_JoystickIsHaptic(m_joystick)) + if (SDL_IsJoystickHaptic(m_joystick)) { - m_haptic = SDL_HapticOpenFromJoystick(m_joystick); + m_haptic = SDL_OpenHapticFromJoystick(m_joystick); if (m_haptic) { - const unsigned int supported_effects = SDL_HapticQuery(m_haptic); + const unsigned int supported_effects = SDL_GetMaxHapticEffects(m_haptic); // Disable autocenter: if (supported_effects & SDL_HAPTIC_AUTOCENTER) - SDL_HapticSetAutocenter(m_haptic, 0); + SDL_SetHapticAutocenter(m_haptic, 0); // Constant if (supported_effects & SDL_HAPTIC_CONSTANT) @@ -224,16 +223,19 @@ GameController::GameController(SDL_GameController* const gamecontroller, } } - // Needed to make the below power level not "UNKNOWN". - SDL_JoystickUpdate(); - // Battery - if (SDL_JoystickPowerLevel const power_level = SDL_JoystickCurrentPowerLevel(m_joystick); - power_level != SDL_JOYSTICK_POWER_UNKNOWN) - { - m_battery_value = GetBatteryValueFromSDLPowerLevel(power_level); + if (UpdateBatteryLevel()) AddInput(new BatteryInput{&m_battery_value}); - } +} + +bool GameController::UpdateBatteryLevel() +{ + int battery_percent = 0; + if (SDL_GetJoystickPowerInfo(m_joystick, &battery_percent) == SDL_POWERSTATE_ERROR) + return false; + + m_battery_value = std::max(0, battery_percent); + return true; } GameController::~GameController() @@ -241,20 +243,18 @@ GameController::~GameController() if (m_haptic) { // stop/destroy all effects - SDL_HapticStopAll(m_haptic); + SDL_StopHapticEffects(m_haptic); // close haptic before joystick - SDL_HapticClose(m_haptic); + SDL_CloseHaptic(m_haptic); m_haptic = nullptr; } if (m_gamecontroller) { // stop all rumble - SDL_GameControllerRumble(m_gamecontroller, 0, 0, 0); - // close game controller - SDL_GameControllerClose(m_gamecontroller); + SDL_RumbleGamepad(m_gamecontroller, 0, 0, 0); + SDL_CloseGamepad(m_gamecontroller); } - // close joystick - SDL_JoystickClose(m_joystick); + SDL_CloseJoystick(m_joystick); } std::string GameController::GetName() const @@ -267,20 +267,28 @@ std::string GameController::GetSource() const return "SDL"; } -int GameController::GetSDLInstanceID() const +SDL_JoystickID GameController::GetSDLInstanceID() const { - return SDL_JoystickInstanceID(m_joystick); + return SDL_GetJoystickID(m_joystick); } std::string GameController::Button::GetName() const { - return s_sdl_button_names[m_button]; + const auto button = m_binding.output.button; + + if (std::size_t(button) >= std::size(s_sdl_button_names)) + return GetLegacyButtonName(button); + + return s_sdl_button_names[button]; } std::string GameController::Axis::GetName() const { + if (std::size_t(m_axis) >= std::size(s_sdl_axis_names)) + return GetLegacyAxisName(m_axis, m_range); + if (IsTriggerAxis(m_axis)) - return std::string(s_sdl_axis_names[m_axis]); + return s_sdl_axis_names[m_axis]; bool negative = m_range < 0; @@ -293,12 +301,12 @@ std::string GameController::Axis::GetName() const ControlState GameController::Button::GetState() const { - return SDL_GameControllerGetButton(m_gc, m_button); + return SDL_GetGamepadButton(m_gc, m_binding.output.button); } ControlState GameController::Axis::GetState() const { - return ControlState(SDL_GameControllerGetAxis(m_gc, m_axis)) / m_range; + return ControlState(SDL_GetGamepadAxis(m_gc, m_axis)) / m_range; } bool GameController::Button::IsMatchingName(std::string_view name) const @@ -306,25 +314,26 @@ bool GameController::Button::IsMatchingName(std::string_view name) const if (GetName() == name) return true; - // So that SDL can be a superset of XInput - if (name == "Button A") - return GetName() == "Button S"; - if (name == "Button B") - return GetName() == "Button E"; - if (name == "Button X") - return GetName() == "Button W"; - if (name == "Button Y") - return GetName() == "Button N"; - - // Match legacy names. - const auto bind = SDL_GameControllerGetBindForButton(m_gc, m_button); - switch (bind.bindType) + // Positionally match XInput button names. + // e.g. Switch Pro controller A-button matches "Button B". + // e.g. PlayStation controller Circle-button matches "Button B". + if (m_binding.output.button == SDL_GAMEPAD_BUTTON_SOUTH && name == "Button A") + return true; + if (m_binding.output.button == SDL_GAMEPAD_BUTTON_EAST && name == "Button B") + return true; + if (m_binding.output.button == SDL_GAMEPAD_BUTTON_WEST && name == "Button X") + return true; + if (m_binding.output.button == SDL_GAMEPAD_BUTTON_NORTH && name == "Button Y") + return true; + + // Match the old "Button 0"-like names. + switch (m_binding.input_type) { - case SDL_CONTROLLER_BINDTYPE_BUTTON: - return name == GetLegacyButtonName(bind.value.button); - case SDL_CONTROLLER_BINDTYPE_HAT: - return name == GetLegacyHatName(bind.value.hat.hat, - GetDirectionFromHatMask(u8(bind.value.hat.hat_mask))); + case SDL_GAMEPAD_BINDTYPE_BUTTON: + return name == GetLegacyButtonName(m_binding.input.button); + case SDL_GAMEPAD_BINDTYPE_HAT: + return name == GetLegacyHatName(m_binding.input.hat.hat, + GetDirectionFromHatMask(m_binding.input.hat.hat_mask)); default: return false; } @@ -333,24 +342,24 @@ bool GameController::Button::IsMatchingName(std::string_view name) const ControlState GameController::MotionInput::GetState() const { std::array<float, 3> data{}; - SDL_GameControllerGetSensorData(m_gc, m_type, data.data(), (int)data.size()); + SDL_GetGamepadSensorData(m_gc, m_type, data.data(), (int)data.size()); return m_scale * data[m_index]; } // Legacy input ControlState GameController::LegacyButton::GetState() const { - return SDL_JoystickGetButton(m_js, m_index); + return SDL_GetJoystickButton(m_js, m_index); } ControlState GameController::LegacyAxis::GetState() const { - return ControlState(SDL_JoystickGetAxis(m_js, m_index)) / m_range; + return ControlState(SDL_GetJoystickAxis(m_js, m_index)) / m_range; } ControlState GameController::LegacyHat::GetState() const { - return (SDL_JoystickGetHat(m_js, m_index) & (1 << m_direction)) > 0; + return (SDL_GetJoystickHat(m_js, m_index) & (1 << m_direction)) > 0; } void GameController::HapticEffect::UpdateEffect() @@ -360,22 +369,22 @@ void GameController::HapticEffect::UpdateEffect() if (m_id < 0) { // Upload and try to play the effect. - m_id = SDL_HapticNewEffect(m_haptic, &m_effect); + m_id = SDL_CreateHapticEffect(m_haptic, &m_effect); if (m_id >= 0) - SDL_HapticRunEffect(m_haptic, m_id, 1); + SDL_RunHapticEffect(m_haptic, m_id, 1); } else { // Effect is already playing. Update parameters. - SDL_HapticUpdateEffect(m_haptic, m_id, &m_effect); + SDL_UpdateHapticEffect(m_haptic, m_id, &m_effect); } } else if (m_id >= 0) { // Stop and remove the effect. - SDL_HapticStopEffect(m_haptic, m_id); - SDL_HapticDestroyEffect(m_haptic, m_id); + SDL_StopHapticEffect(m_haptic, m_id); + SDL_DestroyHapticEffect(m_haptic, m_id); m_id = -1; } } diff --git a/Source/Core/InputCommon/ControllerInterface/SDL/SDLGamepad.h b/Source/Core/InputCommon/ControllerInterface/SDL/SDLGamepad.h index 4f03ea7d4a..e7e463d01d 100644 --- a/Source/Core/InputCommon/ControllerInterface/SDL/SDLGamepad.h +++ b/Source/Core/InputCommon/ControllerInterface/SDL/SDLGamepad.h @@ -5,8 +5,8 @@ #include <array> -#include <SDL.h> -#include <SDL_haptic.h> +#include <SDL3/SDL_gamepad.h> +#include <SDL3/SDL_haptic.h> #include "Common/MathUtil.h" @@ -29,7 +29,7 @@ std::string GetLegacyHatName(int index, int direction) return "Hat " + std::to_string(index) + ' ' + "NESW"[direction]; } -constexpr int GetDirectionFromHatMask(u8 mask) +constexpr int GetDirectionFromHatMask(int mask) { return MathUtil::IntLog2(mask); } @@ -37,38 +37,6 @@ constexpr int GetDirectionFromHatMask(u8 mask) static_assert(GetDirectionFromHatMask(SDL_HAT_UP) == 0); static_assert(GetDirectionFromHatMask(SDL_HAT_LEFT) == 3); -ControlState GetBatteryValueFromSDLPowerLevel(SDL_JoystickPowerLevel sdl_power_level) -{ - // Values come from comments in SDL_joystick.h - // A proper percentage will be exposed in SDL3. - ControlState result; - switch (sdl_power_level) - { - case SDL_JOYSTICK_POWER_EMPTY: - result = 0.025; - break; - case SDL_JOYSTICK_POWER_LOW: - result = 0.125; - break; - case SDL_JOYSTICK_POWER_MEDIUM: - result = 0.45; - break; - case SDL_JOYSTICK_POWER_FULL: - result = 0.85; - break; - case SDL_JOYSTICK_POWER_WIRED: - case SDL_JOYSTICK_POWER_MAX: - result = 1.0; - break; - case SDL_JOYSTICK_POWER_UNKNOWN: - default: - result = 0.0; - break; - } - - return result * ciface::BATTERY_INPUT_MAX_VALUE; -} - } // namespace namespace ciface::SDL @@ -82,29 +50,29 @@ private: { public: std::string GetName() const override; - Button(SDL_GameController* gc, SDL_GameControllerButton button) : m_gc(gc), m_button(button) {} + Button(SDL_Gamepad* gc, const SDL_GamepadBinding& binding) : m_gc(gc), m_binding(binding) {} ControlState GetState() const override; bool IsMatchingName(std::string_view name) const override; private: - SDL_GameController* const m_gc; - const SDL_GameControllerButton m_button; + SDL_Gamepad* const m_gc; + const SDL_GamepadBinding m_binding; }; class Axis : public Core::Device::Input { public: std::string GetName() const override; - Axis(SDL_GameController* gc, Sint16 range, SDL_GameControllerAxis axis) + Axis(SDL_Gamepad* gc, Sint16 range, SDL_GamepadAxis axis) : m_gc(gc), m_range(range), m_axis(axis) { } ControlState GetState() const override; private: - SDL_GameController* const m_gc; + SDL_Gamepad* const m_gc; const Sint16 m_range; - const SDL_GameControllerAxis m_axis; + const SDL_GamepadAxis m_axis; }; // Legacy inputs @@ -180,7 +148,7 @@ private: std::string GetName() const override { return m_name; } void SetState(ControlState state) override { - const auto new_state = state * std::numeric_limits<Uint16>::max(); + const auto new_state = std::lround(state * std::numeric_limits<Uint16>::max()); if (m_state == new_state) return; @@ -205,7 +173,7 @@ private: std::string GetName() const override { return "Motor"; } void SetState(ControlState state) override { - const auto new_state = state * std::numeric_limits<Uint16>::max(); + const auto new_state = std::lround(state * std::numeric_limits<Uint16>::max()); if (m_low_state == new_state && m_high_state == new_state) return; @@ -327,7 +295,7 @@ private: class MotionInput : public Input { public: - MotionInput(std::string name, SDL_GameController* gc, SDL_SensorType type, int index, + MotionInput(std::string name, SDL_Gamepad* gc, SDL_SensorType type, int index, ControlState scale) : m_name(std::move(name)), m_gc(gc), m_type(type), m_index(index), m_scale(scale) { @@ -340,7 +308,7 @@ private: private: std::string m_name; - SDL_GameController* const m_gc; + SDL_Gamepad* const m_gc; SDL_SensorType const m_type; int const m_index; @@ -348,26 +316,25 @@ private: }; public: - GameController(SDL_GameController* const gamecontroller, SDL_Joystick* const joystick); - ~GameController(); + GameController(SDL_Gamepad* gamecontroller, SDL_Joystick* joystick); + ~GameController() override; std::string GetName() const override; std::string GetSource() const override; - int GetSDLInstanceID() const; + SDL_JoystickID GetSDLInstanceID() const; Core::DeviceRemoval UpdateInput() override { - m_battery_value = GetBatteryValueFromSDLPowerLevel(SDL_JoystickCurrentPowerLevel(m_joystick)); + UpdateBatteryLevel(); // We only support one touchpad and one finger. const int touchpad_index = 0; const int finger_index = 0; - if (SDL_GameControllerGetNumTouchpads(m_gamecontroller) > touchpad_index && - SDL_GameControllerGetNumTouchpadFingers(m_gamecontroller, touchpad_index) > finger_index) + if (SDL_GetNumGamepadTouchpads(m_gamecontroller) > touchpad_index && + SDL_GetNumGamepadTouchpadFingers(m_gamecontroller, touchpad_index) > finger_index) { - Uint8 state = 0; - SDL_GameControllerGetTouchpadFinger(m_gamecontroller, touchpad_index, finger_index, &state, - &m_touchpad_x, &m_touchpad_y, &m_touchpad_pressure); + SDL_GetGamepadTouchpadFinger(m_gamecontroller, touchpad_index, finger_index, nullptr, + &m_touchpad_x, &m_touchpad_y, &m_touchpad_pressure); m_touchpad_x = m_touchpad_x * 2 - 1; m_touchpad_y = m_touchpad_y * 2 - 1; } @@ -378,23 +345,24 @@ public: private: void UpdateRumble() { - SDL_GameControllerRumble(m_gamecontroller, m_low_freq_rumble, m_high_freq_rumble, - RUMBLE_LENGTH_MS); + SDL_RumbleGamepad(m_gamecontroller, m_low_freq_rumble, m_high_freq_rumble, RUMBLE_LENGTH_MS); } void UpdateRumbleTriggers() { - SDL_GameControllerRumbleTriggers(m_gamecontroller, m_trigger_l_rumble, m_trigger_r_rumble, - RUMBLE_LENGTH_MS); + SDL_RumbleGamepadTriggers(m_gamecontroller, m_trigger_l_rumble, m_trigger_r_rumble, + RUMBLE_LENGTH_MS); } + bool UpdateBatteryLevel(); + Uint16 m_low_freq_rumble = 0; Uint16 m_high_freq_rumble = 0; Uint16 m_trigger_l_rumble = 0; Uint16 m_trigger_r_rumble = 0; - SDL_GameController* const m_gamecontroller; + SDL_Gamepad* const m_gamecontroller; std::string m_name; SDL_Joystick* const m_joystick; SDL_Haptic* m_haptic = nullptr; @@ -413,35 +381,35 @@ struct SDLMotionAxis using SDLMotionAxisList = std::array<SDLMotionAxis, 6>; static constexpr std::array<const char*, 21> s_sdl_button_names = { - "Button S", // SDL_CONTROLLER_BUTTON_A - "Button E", // SDL_CONTROLLER_BUTTON_B - "Button W", // SDL_CONTROLLER_BUTTON_X - "Button N", // SDL_CONTROLLER_BUTTON_Y - "Back", // SDL_CONTROLLER_BUTTON_BACK - "Guide", // SDL_CONTROLLER_BUTTON_GUIDE - "Start", // SDL_CONTROLLER_BUTTON_START - "Thumb L", // SDL_CONTROLLER_BUTTON_LEFTSTICK - "Thumb R", // SDL_CONTROLLER_BUTTON_RIGHTSTICK - "Shoulder L", // SDL_CONTROLLER_BUTTON_LEFTSHOULDER - "Shoulder R", // SDL_CONTROLLER_BUTTON_RIGHTSHOULDER - "Pad N", // SDL_CONTROLLER_BUTTON_DPAD_UP - "Pad S", // SDL_CONTROLLER_BUTTON_DPAD_DOWN - "Pad W", // SDL_CONTROLLER_BUTTON_DPAD_LEFT - "Pad E", // SDL_CONTROLLER_BUTTON_DPAD_RIGHT - "Misc 1", // SDL_CONTROLLER_BUTTON_MISC1 - "Paddle 1", // SDL_CONTROLLER_BUTTON_PADDLE1 - "Paddle 2", // SDL_CONTROLLER_BUTTON_PADDLE2 - "Paddle 3", // SDL_CONTROLLER_BUTTON_PADDLE3 - "Paddle 4", // SDL_CONTROLLER_BUTTON_PADDLE4 - "Touchpad", // SDL_CONTROLLER_BUTTON_TOUCHPAD + "Button S", // SDL_GAMEPAD_BUTTON_SOUTH + "Button E", // SDL_GAMEPAD_BUTTON_EAST + "Button W", // SDL_GAMEPAD_BUTTON_WEST + "Button N", // SDL_GAMEPAD_BUTTON_NORTH + "Back", // SDL_GAMEPAD_BUTTON_BACK + "Guide", // SDL_GAMEPAD_BUTTON_GUIDE + "Start", // SDL_GAMEPAD_BUTTON_START + "Thumb L", // SDL_GAMEPAD_BUTTON_LEFT_STICK + "Thumb R", // SDL_GAMEPAD_BUTTON_RIGHT_STICK + "Shoulder L", // SDL_GAMEPAD_BUTTON_LEFT_SHOULDER + "Shoulder R", // SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER + "Pad N", // SDL_GAMEPAD_BUTTON_DPAD_UP + "Pad S", // SDL_GAMEPAD_BUTTON_DPAD_DOWN + "Pad W", // SDL_GAMEPAD_BUTTON_DPAD_LEFT + "Pad E", // SDL_GAMEPAD_BUTTON_DPAD_RIGHT + "Misc 1", // SDL_GAMEPAD_BUTTON_MISC1 + "Paddle 1", // SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1 + "Paddle 2", // SDL_GAMEPAD_BUTTON_LEFT_PADDLE1 + "Paddle 3", // SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2 + "Paddle 4", // SDL_GAMEPAD_BUTTON_LEFT_PADDLE2 + "Touchpad", // SDL_GAMEPAD_BUTTON_TOUCHPAD }; static constexpr std::array<const char*, 6> s_sdl_axis_names = { - "Left X", // SDL_CONTROLLER_AXIS_LEFTX - "Left Y", // SDL_CONTROLLER_AXIS_LEFTY - "Right X", // SDL_CONTROLLER_AXIS_RIGHTX - "Right Y", // SDL_CONTROLLER_AXIS_RIGHTY - "Trigger L", // SDL_CONTROLLER_AXIS_TRIGGERLEFT - "Trigger R", // SDL_CONTROLLER_AXIS_TRIGGERRIGHT + "Left X", // SDL_GAMEPAD_AXIS_LEFTX + "Left Y", // SDL_GAMEPAD_AXIS_LEFTY + "Right X", // SDL_GAMEPAD_AXIS_RIGHTX + "Right Y", // SDL_GAMEPAD_AXIS_RIGHTY + "Trigger L", // SDL_GAMEPAD_AXIS_LEFT_TRIGGER + "Trigger R", // SDL_GAMEPAD_AXIS_RIGHT_TRIGGER }; static constexpr SDLMotionAxisList SDL_AXES_ACCELEROMETER = {{ {"Up", 1, 1}, |
