From bb6551e5dc238ca742a82810632e7bd4c4e5f50b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joshua=20Vanda=C3=ABle?= Date: Mon, 15 Jun 2026 16:42:16 +0200 Subject: [PATCH] SDLGamepad: Support multiple touchpads --- .../ControllerInterface/SDL/SDLGamepad.cpp | 22 ++++++---- .../ControllerInterface/SDL/SDLGamepad.h | 43 +++++++++++-------- 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/Source/Core/InputCommon/ControllerInterface/SDL/SDLGamepad.cpp b/Source/Core/InputCommon/ControllerInterface/SDL/SDLGamepad.cpp index 09457598c6..3de2518212 100644 --- a/Source/Core/InputCommon/ControllerInterface/SDL/SDLGamepad.cpp +++ b/Source/Core/InputCommon/ControllerInterface/SDL/SDLGamepad.cpp @@ -104,15 +104,21 @@ Gamepad::Gamepad(SDL_Gamepad* const gamepad, SDL_Joystick* const joystick) } // Touchpad - if (SDL_GetNumGamepadTouchpads(m_gamepad) > 0) + const int num_touchpads = SDL_GetNumGamepadTouchpads(m_gamepad); + if (num_touchpads > 0) { - const char* const name_x = "Touchpad X"; - AddInput(new NonDetectableDirectionalInput<-1>(name_x, &m_touchpad_x)); - AddInput(new NonDetectableDirectionalInput<+1>(name_x, &m_touchpad_x)); - const char* const name_y = "Touchpad Y"; - AddInput(new NonDetectableDirectionalInput<-1>(name_y, &m_touchpad_y)); - AddInput(new NonDetectableDirectionalInput<+1>(name_y, &m_touchpad_y)); - AddInput(new NormalizedInput("Touchpad Pressure", &m_touchpad_pressure)); + m_touchpads.resize(num_touchpads); + for (int t = 0; t < num_touchpads; ++t) + { + // We do not number the first touchpad to keep backwards compatibility with existing configs + // that use "Touchpad X" and "Touchpad Y" as input names. + const std::string prefix = t > 0 ? fmt::format("Touchpad {} ", t + 1) : "Touchpad "; + AddInput(new NonDetectableDirectionalInput<-1>(prefix + "X", &m_touchpads[t].x)); + AddInput(new NonDetectableDirectionalInput<+1>(prefix + "X", &m_touchpads[t].x)); + AddInput(new NonDetectableDirectionalInput<-1>(prefix + "Y", &m_touchpads[t].y)); + AddInput(new NonDetectableDirectionalInput<+1>(prefix + "Y", &m_touchpads[t].y)); + AddInput(new NormalizedInput(prefix + "Pressure", &m_touchpads[t].pressure)); + } } // Motion diff --git a/Source/Core/InputCommon/ControllerInterface/SDL/SDLGamepad.h b/Source/Core/InputCommon/ControllerInterface/SDL/SDLGamepad.h index 0a431866e7..6faa24b559 100644 --- a/Source/Core/InputCommon/ControllerInterface/SDL/SDLGamepad.h +++ b/Source/Core/InputCommon/ControllerInterface/SDL/SDLGamepad.h @@ -42,6 +42,13 @@ static_assert(GetDirectionFromHatMask(SDL_HAT_LEFT) == 3); namespace ciface::SDL { +struct TouchpadState +{ + float x = 0.f; + float y = 0.f; + float pressure = 0.f; +}; + class Gamepad : public Core::Device { private: @@ -262,15 +269,15 @@ private: class NormalizedInput : public Input { public: - NormalizedInput(const char* name, const float* state) : m_name{std::move(name)}, m_state{*state} + NormalizedInput(std::string name, const float* state) : m_name{std::move(name)}, m_state{*state} { } - std::string GetName() const override { return std::string{m_name}; } + std::string GetName() const override { return m_name; } ControlState GetState() const override { return m_state; } private: - const char* const m_name; + const std::string m_name; const float& m_state; }; @@ -278,17 +285,17 @@ private: class NonDetectableDirectionalInput : public Input { public: - NonDetectableDirectionalInput(const char* name, const float* state) + NonDetectableDirectionalInput(std::string name, const float* state) : m_name{std::move(name)}, m_state{*state} { } - std::string GetName() const override { return std::string{m_name} + (Scale > 0 ? '+' : '-'); } + std::string GetName() const override { return m_name + (Scale > 0 ? '+' : '-'); } bool IsDetectable() const override { return false; } ControlState GetState() const override { return m_state * Scale; } private: - const char* const m_name; + const std::string m_name; const float& m_state; }; @@ -326,17 +333,17 @@ public: { UpdateBatteryLevel(); - // We only support one touchpad and one finger. - const int touchpad_index = 0; - const int finger_index = 0; - - if (SDL_GetNumGamepadTouchpads(m_gamepad) > touchpad_index && - SDL_GetNumGamepadTouchpadFingers(m_gamepad, touchpad_index) > finger_index) + // We only support one finger per touchpad + static constexpr int finger_index = 0; + for (int t = 0; t < static_cast(m_touchpads.size()); ++t) { - SDL_GetGamepadTouchpadFinger(m_gamepad, 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; + if (SDL_GetNumGamepadTouchpadFingers(m_gamepad, t) <= finger_index) + continue; + + SDL_GetGamepadTouchpadFinger(m_gamepad, t, finger_index, nullptr, &m_touchpads[t].x, + &m_touchpads[t].y, &m_touchpads[t].pressure); + m_touchpads[t].x = m_touchpads[t].x * 2 - 1; + m_touchpads[t].y = m_touchpads[t].y * 2 - 1; } return Core::DeviceRemoval::Keep; @@ -366,9 +373,7 @@ private: SDL_Joystick* const m_joystick; SDL_Haptic* m_haptic = nullptr; ControlState m_battery_value; - float m_touchpad_x = 0.f; - float m_touchpad_y = 0.f; - float m_touchpad_pressure = 0.f; + std::vector m_touchpads; }; struct SDLMotionAxis