From b333c04cccd338a7d81fff46c07415b0b82e89ca Mon Sep 17 00:00:00 2001 From: Vlad-Florin Ilie <35900803+VladFlorinIlie@users.noreply.github.com> Date: Thu, 14 May 2026 09:40:55 +0300 Subject: [PATCH] Fix Steam Controller 2026 (triton) rumble (#15558) --- src/joystick/hidapi/SDL_hidapi_steam_triton.c | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/joystick/hidapi/SDL_hidapi_steam_triton.c b/src/joystick/hidapi/SDL_hidapi_steam_triton.c index 812a9c4059..9d2b026eec 100644 --- a/src/joystick/hidapi/SDL_hidapi_steam_triton.c +++ b/src/joystick/hidapi/SDL_hidapi_steam_triton.c @@ -35,6 +35,9 @@ // Always 1kHz according to USB descriptor, but actually about 4 ms. #define TRITON_SENSOR_UPDATE_INTERVAL_US 4032 +// Steam Controller hardware safety timeout is around 50ms, so we resend rumble every 40ms +#define TRITON_RUMBLE_RESEND_INTERVAL_MS 40 + enum { SDL_GAMEPAD_BUTTON_STEAM_DECK_QAM = 11, @@ -96,6 +99,9 @@ typedef struct Uint64 sensor_timestamp_ns; Uint64 last_button_state; Uint64 last_lizard_update; + Uint16 low_frequency_rumble; + Uint16 high_frequency_rumble; + Uint64 last_rumble_time; } SDL_DriverSteamTriton_Context; static bool IsProteusDongle(Uint16 product_id) @@ -354,6 +360,8 @@ static void HIDAPI_DriverSteamTriton_SetDevicePlayerIndex(SDL_HIDAPI_Device *dev { } +static bool HIDAPI_DriverSteamTriton_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble); + static bool HIDAPI_DriverSteamTriton_UpdateDevice(SDL_HIDAPI_Device *device) { SDL_DriverSteamTriton_Context *ctx = (SDL_DriverSteamTriton_Context *)device->context; @@ -369,6 +377,12 @@ static bool HIDAPI_DriverSteamTriton_UpdateDevice(SDL_HIDAPI_Device *device) DisableSteamTritonLizardMode(device->dev); ctx->last_lizard_update = now; } + + if (ctx->low_frequency_rumble || ctx->high_frequency_rumble) { + if ((now - ctx->last_rumble_time) >= TRITON_RUMBLE_RESEND_INTERVAL_MS) { + HIDAPI_DriverSteamTriton_RumbleJoystick(device, joystick, ctx->low_frequency_rumble, ctx->high_frequency_rumble); + } + } } for (;;) { @@ -436,10 +450,14 @@ static bool HIDAPI_DriverSteamTriton_OpenJoystick(SDL_HIDAPI_Device *device, SDL static bool HIDAPI_DriverSteamTriton_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) { + SDL_DriverSteamTriton_Context *ctx = (SDL_DriverSteamTriton_Context *)device->context; int rc; - //RKRK Not sure about size. Probably 64+1 is OK for ORs - Uint8 buffer[HID_RUMBLE_OUTPUT_REPORT_BYTES]; + ctx->low_frequency_rumble = low_frequency_rumble; + ctx->high_frequency_rumble = high_frequency_rumble; + ctx->last_rumble_time = SDL_GetTicks(); + + Uint8 buffer[HID_RUMBLE_OUTPUT_REPORT_BYTES] = { 0 }; OutputReportMsg *msg = (OutputReportMsg *)(buffer); msg->report_id = ID_OUT_REPORT_HAPTIC_RUMBLE; @@ -450,9 +468,12 @@ static bool HIDAPI_DriverSteamTriton_RumbleJoystick(SDL_HIDAPI_Device *device, S msg->payload.hapticRumble.right.speed = high_frequency_rumble; msg->payload.hapticRumble.right.gain = 0; - rc = SDL_hid_write(device->dev, buffer, sizeof(buffer)); - if (rc != sizeof(buffer)) { + if (rc < 0) { + SDL_LogError(SDL_LOG_CATEGORY_INPUT, + "Steam Controller HID Write FAILED! rc: %d. SDL_Error: %s", + rc, SDL_GetError()); + return false; } return true;