From 74a746281f2208e07a7680560fcb7ec57565228e Mon Sep 17 00:00:00 2001 From: Kuratius <47481645+Kuratius@users.noreply.github.com> Date: Sat, 25 Apr 2026 01:18:57 +0200 Subject: [PATCH] Expose Steam Controller touchpads in Gamepad API (#15378) --- src/joystick/hidapi/SDL_hidapi_steam.c | 65 ++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/joystick/hidapi/SDL_hidapi_steam.c b/src/joystick/hidapi/SDL_hidapi_steam.c index ca5fe5b76f..624e8b5dd5 100644 --- a/src/joystick/hidapi/SDL_hidapi_steam.c +++ b/src/joystick/hidapi/SDL_hidapi_steam.c @@ -1011,6 +1011,13 @@ typedef struct Uint64 sensor_timestamp; Uint64 pairing_time; + bool left_touch_down; + float left_touch_x; + float left_touch_y; + bool right_touch_down; + float right_touch_x; + float right_touch_y; + SteamControllerPacketAssembler m_assembler; SteamControllerStateInternal_t m_state; SteamControllerStateInternal_t m_last_state; @@ -1269,6 +1276,9 @@ static bool HIDAPI_DriverSteam_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joyst SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, update_rate_in_hz); SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, update_rate_in_hz); + SDL_PrivateJoystickAddTouchpad(joystick, 1); + SDL_PrivateJoystickAddTouchpad(joystick, 1); + SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_STEAM_HOME_LED, SDL_HomeLEDHintChanged, ctx); @@ -1348,6 +1358,21 @@ static bool ControllerConnected(SDL_HIDAPI_Device *device, SDL_Joystick **joysti return true; } +static float FilterTouch(float newValue, float oldValue) +{ + const float jitter = 256.0f / (1 << 16); + if (newValue > (oldValue - jitter * 0.5f) && newValue < (oldValue + jitter * 0.5f)) { + return oldValue; + } + if (newValue > (oldValue - jitter) && newValue < (oldValue + jitter)) { + return oldValue * 0.75f + newValue * 0.25f; + } + if (newValue > (oldValue - jitter * 2.0f) && newValue < (oldValue + jitter * 2.0f)) { + return (oldValue + newValue) * 0.5f; + } + return newValue; +} + static void ControllerDisconnected(SDL_HIDAPI_Device *device, SDL_Joystick **joystick) { SDL_DriverSteam_Context *ctx = (SDL_DriverSteam_Context *)device->context; @@ -1469,6 +1494,46 @@ static bool HIDAPI_DriverSteam_UpdateDevice(SDL_HIDAPI_Device *device) SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, ctx->m_state.sRightPadX); SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, ~ctx->m_state.sRightPadY); + // Note that the left pad is normally mapped to D-Pad, so you should ignore that input if you use the touchpad instead. + { + const bool down = (ctx->m_state.ulButtons & STEAM_LEFTPAD_FINGERDOWN_MASK) ? true : false; + if (down || ctx->left_touch_down) { + const bool clicked = (ctx->m_state.ulButtons & STEAM_BUTTON_LEFTPAD_CLICKED_MASK) ? true : false; + const float leftX = (float)ctx->m_state.sLeftPadX / (1 << 16) + 0.5f; + const float leftY = -(float)ctx->m_state.sLeftPadY / (1 << 16) + 0.5f; + float pressure = down ? 0.5f : 0.0f; + if (clicked) { + pressure += 0.5f; + } + if (down) { + ctx->left_touch_x = FilterTouch(leftX, ctx->left_touch_x); + ctx->left_touch_y = FilterTouch(leftY, ctx->left_touch_y); + } + SDL_SendJoystickTouchpad(timestamp, joystick, 0, 0, down, ctx->left_touch_x, ctx->left_touch_y, pressure); + ctx->left_touch_down = down; + } + } + + // Note that the right pad is normally mapped to right thumbstick, so you should ignore that input if you use the touchpad instead. + { + const bool down = (ctx->m_state.ulButtons & STEAM_RIGHTPAD_FINGERDOWN_MASK) ? true : false; + if (down || ctx->right_touch_down) { + const bool clicked = (ctx->m_state.ulButtons & STEAM_BUTTON_RIGHTPAD_CLICKED_MASK) ? true : false; + const float rightX = (float)ctx->m_state.sRightPadX / (1 << 16) + 0.5f; + const float rightY = -(float)ctx->m_state.sRightPadY / (1 << 16) + 0.5f; + float pressure = down ? 0.5f : 0.0f; + if (clicked) { + pressure += 0.5f; + } + if (down) { + ctx->right_touch_x = FilterTouch(rightX, ctx->right_touch_x); + ctx->right_touch_y = FilterTouch(rightY, ctx->right_touch_y); + } + SDL_SendJoystickTouchpad(timestamp, joystick, 1, 0, down, ctx->right_touch_x, ctx->right_touch_y, pressure); + ctx->right_touch_down = down; + } + } + if (ctx->report_sensors) { float values[3];