From 79f5f674bd1675347b86d07565668f8c82a8f42f Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 12 Feb 2026 16:02:21 -0800
Subject: [PATCH] Use the correct report format for BLE Steam Controller
reports
---
src/joystick/hidapi/SDL_hidapi_steam_triton.c | 56 +++++++++----------
.../hidapi/steam/controller_structs.h | 38 ++++++++++++-
2 files changed, 63 insertions(+), 31 deletions(-)
diff --git a/src/joystick/hidapi/SDL_hidapi_steam_triton.c b/src/joystick/hidapi/SDL_hidapi_steam_triton.c
index 453becdec27a1..aad2f3bfaebf8 100644
--- a/src/joystick/hidapi/SDL_hidapi_steam_triton.c
+++ b/src/joystick/hidapi/SDL_hidapi_steam_triton.c
@@ -125,67 +125,67 @@ static bool DisableSteamTritonLizardMode(SDL_hid_device *dev)
static void HIDAPI_DriverSteamTriton_HandleState(SDL_HIDAPI_Device *device,
SDL_Joystick *joystick,
- TritonMTUFull_t *pTritonReport)
+ TritonMTUNoQuat_t *pTritonReport)
{
float values[3];
SDL_DriverSteamTriton_Context *ctx = (SDL_DriverSteamTriton_Context *)device->context;
Uint64 timestamp = SDL_GetTicksNS();
- if (pTritonReport->uButtons != ctx->last_button_state) {
+ if (pTritonReport->buttons != ctx->last_button_state) {
Uint8 hat = 0;
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH,
- ((pTritonReport->uButtons & TRITON_LBUTTON_A) != 0));
+ ((pTritonReport->buttons & TRITON_LBUTTON_A) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST,
- ((pTritonReport->uButtons & TRITON_LBUTTON_B) != 0));
+ ((pTritonReport->buttons & TRITON_LBUTTON_B) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST,
- ((pTritonReport->uButtons & TRITON_LBUTTON_X) != 0));
+ ((pTritonReport->buttons & TRITON_LBUTTON_X) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH,
- ((pTritonReport->uButtons & TRITON_LBUTTON_Y) != 0));
+ ((pTritonReport->buttons & TRITON_LBUTTON_Y) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER,
- ((pTritonReport->uButtons & TRITON_LBUTTON_L) != 0));
+ ((pTritonReport->buttons & TRITON_LBUTTON_L) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER,
- ((pTritonReport->uButtons & TRITON_LBUTTON_R) != 0));
+ ((pTritonReport->buttons & TRITON_LBUTTON_R) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK,
- ((pTritonReport->uButtons & TRITON_LBUTTON_MENU) != 0));
+ ((pTritonReport->buttons & TRITON_LBUTTON_MENU) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START,
- ((pTritonReport->uButtons & TRITON_LBUTTON_VIEW) != 0));
+ ((pTritonReport->buttons & TRITON_LBUTTON_VIEW) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE,
- ((pTritonReport->uButtons & TRITON_LBUTTON_STEAM) != 0));
+ ((pTritonReport->buttons & TRITON_LBUTTON_STEAM) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_STEAM_DECK_QAM,
- ((pTritonReport->uButtons & TRITON_HBUTTON_QAM) != 0));
+ ((pTritonReport->buttons & TRITON_HBUTTON_QAM) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK,
- ((pTritonReport->uButtons & TRITON_LBUTTON_L3) != 0));
+ ((pTritonReport->buttons & TRITON_LBUTTON_L3) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK,
- ((pTritonReport->uButtons & TRITON_LBUTTON_R3) != 0));
+ ((pTritonReport->buttons & TRITON_LBUTTON_R3) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_STEAM_DECK_RIGHT_PADDLE1,
- ((pTritonReport->uButtons & TRITON_HBUTTON_R4) != 0));
+ ((pTritonReport->buttons & TRITON_HBUTTON_R4) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_STEAM_DECK_LEFT_PADDLE1,
- ((pTritonReport->uButtons & TRITON_HBUTTON_L4) != 0));
+ ((pTritonReport->buttons & TRITON_HBUTTON_L4) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_STEAM_DECK_RIGHT_PADDLE2,
- ((pTritonReport->uButtons & TRITON_LBUTTON_R5) != 0));
+ ((pTritonReport->buttons & TRITON_LBUTTON_R5) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_STEAM_DECK_LEFT_PADDLE2,
- ((pTritonReport->uButtons & TRITON_LBUTTON_L5) != 0));
+ ((pTritonReport->buttons & TRITON_LBUTTON_L5) != 0));
- if (pTritonReport->uButtons & TRITON_LBUTTON_DPAD_UP) {
+ if (pTritonReport->buttons & TRITON_LBUTTON_DPAD_UP) {
hat |= SDL_HAT_UP;
}
- if (pTritonReport->uButtons & TRITON_LBUTTON_DPAD_DOWN) {
+ if (pTritonReport->buttons & TRITON_LBUTTON_DPAD_DOWN) {
hat |= SDL_HAT_DOWN;
}
- if (pTritonReport->uButtons & TRITON_LBUTTON_DPAD_LEFT) {
+ if (pTritonReport->buttons & TRITON_LBUTTON_DPAD_LEFT) {
hat |= SDL_HAT_LEFT;
}
- if (pTritonReport->uButtons & TRITON_LBUTTON_DPAD_RIGHT) {
+ if (pTritonReport->buttons & TRITON_LBUTTON_DPAD_RIGHT) {
hat |= SDL_HAT_RIGHT;
}
SDL_SendJoystickHat(timestamp, joystick, 0, hat);
- ctx->last_button_state = pTritonReport->uButtons;
+ ctx->last_button_state = pTritonReport->buttons;
}
// RKRK There're button bits for this if you so choose.
@@ -203,8 +203,8 @@ static void HIDAPI_DriverSteamTriton_HandleState(SDL_HIDAPI_Device *device,
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY,
-pTritonReport->sRightStickY);
- if (ctx->report_sensors && pTritonReport->imu.uTimestamp != ctx->last_sensor_tick) {
- Uint32 delta_us = (pTritonReport->imu.uTimestamp - ctx->last_sensor_tick);
+ if (ctx->report_sensors && pTritonReport->imu.timestamp != ctx->last_sensor_tick) {
+ Uint32 delta_us = (pTritonReport->imu.timestamp - ctx->last_sensor_tick);
ctx->sensor_timestamp_ns += SDL_US_TO_NS(delta_us);
@@ -218,7 +218,7 @@ static void HIDAPI_DriverSteamTriton_HandleState(SDL_HIDAPI_Device *device,
values[2] = (-pTritonReport->imu.sAccelY / 32768.0f) * 2.0f * SDL_STANDARD_GRAVITY;
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, ctx->sensor_timestamp_ns, values, 3);
- ctx->last_sensor_tick = pTritonReport->imu.uTimestamp;
+ ctx->last_sensor_tick = pTritonReport->imu.timestamp;
}
}
@@ -393,8 +393,8 @@ static bool HIDAPI_DriverSteamTriton_UpdateDevice(SDL_HIDAPI_Device *device)
joystick = SDL_GetJoystickFromID(device->joysticks[0]);
}
}
- if (joystick && r >= (1 + sizeof(TritonMTUFull_t))) {
- TritonMTUFull_t *pTritonReport = (TritonMTUFull_t *)&data[1];
+ if (joystick && r >= (1 + sizeof(TritonMTUNoQuat_t))) {
+ TritonMTUNoQuat_t *pTritonReport = (TritonMTUNoQuat_t *)&data[1];
HIDAPI_DriverSteamTriton_HandleState(device, joystick, pTritonReport);
}
break;
diff --git a/src/joystick/hidapi/steam/controller_structs.h b/src/joystick/hidapi/steam/controller_structs.h
index 2657346421db2..8b850e0f83e7e 100644
--- a/src/joystick/hidapi/steam/controller_structs.h
+++ b/src/joystick/hidapi/steam/controller_structs.h
@@ -567,7 +567,7 @@ enum ETritonWirelessState
typedef struct
{
- uint32_t uTimestamp;
+ uint32_t timestamp;
short sAccelX;
short sAccelY;
short sAccelZ;
@@ -582,10 +582,21 @@ typedef struct
short sGyroQuatZ;
} TritonMTUIMU_t;
+typedef struct {
+ uint32_t timestamp;
+ short sAccelX;
+ short sAccelY;
+ short sAccelZ;
+
+ short sGyroX;
+ short sGyroY;
+ short sGyroZ;
+} TritonMTUIMUNoQuat_t;
+
typedef struct
{
- uint8_t cSeq_num;
- uint32_t uButtons;
+ uint8_t seq_num;
+ uint32_t buttons;
short sTriggerLeft;
short sTriggerRight;
@@ -604,6 +615,27 @@ typedef struct
TritonMTUIMU_t imu;
} TritonMTUFull_t;
+typedef struct {
+ uint8_t seq_num;
+ uint32_t buttons;
+ short sTriggerLeft;
+ short sTriggerRight;
+
+ short sLeftStickX;
+ short sLeftStickY;
+ short sRightStickX;
+ short sRightStickY;
+
+ short sLeftPadX;
+ short sLeftPadY;
+ unsigned short ucPressureLeft;
+
+ short sRightPadX;
+ short sRightPadY;
+ unsigned short ucPressureRight;
+ TritonMTUIMUNoQuat_t imu;
+} TritonMTUNoQuat_t;
+
enum EChargeState
{
k_EChargeStateReset,