Added support for the new Steam Controller

This commit is contained in:
Sam Lantinga
2025-11-12 11:32:32 -08:00
parent 04a62cba1f
commit 1998b65045
15 changed files with 970 additions and 126 deletions
+5 -4
View File
@@ -82,16 +82,16 @@
<LibraryPath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Lib\x86;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>$(ProjectDir)/../../src;$(IncludePath)</IncludePath>
<IncludePath>$(ProjectDir)/../../src;$(ProjectDir)/../../src/core/windows;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>$(ProjectDir)/../../src;$(IncludePath)</IncludePath>
<IncludePath>$(ProjectDir)/../../src;$(ProjectDir)/../../src/core/windows;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>$(ProjectDir)/../../src;$(IncludePath)</IncludePath>
<IncludePath>$(ProjectDir)/../../src;$(ProjectDir)/../../src/core/windows;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(ProjectDir)/../../src;$(IncludePath)</IncludePath>
<IncludePath>$(ProjectDir)/../../src;$(ProjectDir)/../../src/core/windows;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<PreBuildEvent>
@@ -625,6 +625,7 @@
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_stadia.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_steam.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_steam_hori.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_steam_triton.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_steamdeck.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch2.c" />
+4
View File
@@ -1660,6 +1660,10 @@
<ClCompile Include="..\..\src\storage\generic\SDL_genericstorage.c" />
<ClCompile Include="..\..\src\storage\steam\SDL_steamstorage.c" />
<ClCompile Include="..\..\src\storage\SDL_storage.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_steam_triton.c">
<Filter>joystick\hidapi</Filter>
</ClCompile>
</ItemGroup>
<ClCompile Include="..\..\src\events\SDL_eventwatch.c" />
<ClCompile Include="..\..\src\core\windows\pch_cpp.cpp">
<Filter>core\windows</Filter>
+4
View File
@@ -415,6 +415,7 @@
F386F6F92884663E001840AA /* SDL_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = F386F6E62884663E001840AA /* SDL_utils.c */; };
F388C95528B5F6F700661ECF /* SDL_hidapi_ps3.c in Sources */ = {isa = PBXBuildFile; fileRef = F388C95428B5F6F600661ECF /* SDL_hidapi_ps3.c */; };
F39344CE2E99771B0056986F /* SDL_dlopennote.h in Headers */ = {isa = PBXBuildFile; fileRef = F39344CD2E99771B0056986F /* SDL_dlopennote.h */; settings = {ATTRIBUTES = (Public, ); }; };
F38C72492CEEB1DE000B0A90 /* SDL_hidapi_steam_triton.c in Sources */ = {isa = PBXBuildFile; fileRef = F38C72482CEEB1DE000B0A90 /* SDL_hidapi_steam_triton.c */; };
F395BF6525633B2400942BFF /* SDL_crc32.c in Sources */ = {isa = PBXBuildFile; fileRef = F395BF6425633B2400942BFF /* SDL_crc32.c */; };
F395C1932569C68F00942BFF /* SDL_iokitjoystick_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F395C1912569C68E00942BFF /* SDL_iokitjoystick_c.h */; };
F395C19C2569C68F00942BFF /* SDL_iokitjoystick.c in Sources */ = {isa = PBXBuildFile; fileRef = F395C1922569C68E00942BFF /* SDL_iokitjoystick.c */; };
@@ -998,6 +999,7 @@
F386F6E62884663E001840AA /* SDL_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_utils.c; sourceTree = "<group>"; };
F388C95428B5F6F600661ECF /* SDL_hidapi_ps3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_ps3.c; sourceTree = "<group>"; };
F39344CD2E99771B0056986F /* SDL_dlopennote.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_dlopennote.h; sourceTree = "<group>"; };
F38C72482CEEB1DE000B0A90 /* SDL_hidapi_steam_triton.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_steam_triton.c; sourceTree = "<group>"; };
F395BF6425633B2400942BFF /* SDL_crc32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_crc32.c; sourceTree = "<group>"; };
F395C1912569C68E00942BFF /* SDL_iokitjoystick_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_iokitjoystick_c.h; sourceTree = "<group>"; };
F395C1922569C68E00942BFF /* SDL_iokitjoystick.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_iokitjoystick.c; sourceTree = "<group>"; };
@@ -1962,6 +1964,7 @@
F3984CCF25BCC92800374F43 /* SDL_hidapi_stadia.c */,
A75FDAAC23E2795C00529352 /* SDL_hidapi_steam.c */,
F3FD042D2C9B755700824C4C /* SDL_hidapi_steam_hori.c */,
F38C72482CEEB1DE000B0A90 /* SDL_hidapi_steam_triton.c */,
A797456F2B2E9D39009D224A /* SDL_hidapi_steamdeck.c */,
A7D8A7C623E2513E00DCD162 /* SDL_hidapi_switch.c */,
A7D8A7C623E2513E00DCD163 /* SDL_hidapi_switch2.c */,
@@ -3009,6 +3012,7 @@
F316ABD92B5C3185002EF551 /* SDL_memcpy.c in Sources */,
A7D8B97A23E2514400DCD162 /* SDL_render.c in Sources */,
A7D8ABD323E2514100DCD162 /* SDL_stretch.c in Sources */,
F38C72492CEEB1DE000B0A90 /* SDL_hidapi_steam_triton.c in Sources */,
A7D8AC3923E2514100DCD162 /* SDL_blit_copy.c in Sources */,
A7D8B5CF23E2514300DCD162 /* SDL_syspower.m in Sources */,
F3B439512C935C2400792030 /* SDL_dummyprocess.c in Sources */,
+197 -86
View File
File diff suppressed because it is too large Load Diff
+3
View File
@@ -1252,6 +1252,9 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
if (SDL_IsJoystickSteamController(vendor, product)) {
// Steam controllers have 2 back paddle buttons
SDL_strlcat(mapping_string, "paddle1:b11,paddle2:b12,", sizeof(mapping_string));
} else if (SDL_IsJoystickSteamTriton(vendor, product)) {
// Steam controllers have 2 back paddle buttons
SDL_strlcat(mapping_string, "misc1:b11,paddle1:b12,paddle2:b13,paddle3:b14,paddle4:b15", sizeof(mapping_string));
} else if (SDL_IsJoystickNintendoSwitchPro(vendor, product) ||
SDL_IsJoystickNintendoSwitchProInputOnly(vendor, product)) {
// Nintendo Switch Pro controllers have a screenshot button
+6
View File
@@ -3295,6 +3295,12 @@ bool SDL_IsJoystickSteamDeck(Uint16 vendor_id, Uint16 product_id)
return eType == k_eControllerType_SteamControllerNeptune;
}
bool SDL_IsJoystickSteamTriton(Uint16 vendor_id, Uint16 product_id)
{
EControllerType eType = GuessControllerType(vendor_id, product_id);
return eType == k_eControllerType_SteamControllerTriton;
}
bool SDL_IsJoystickXInput(SDL_GUID guid)
{
return (guid.data[14] == 'x') ? true : false;
+3
View File
@@ -144,6 +144,9 @@ extern bool SDL_IsJoystickFlydigiController(Uint16 vendor_id, Uint16 product_id)
// Function to return whether a joystick is a Steam Deck
extern bool SDL_IsJoystickSteamDeck(Uint16 vendor_id, Uint16 product_id);
// Function to return whether a joystick is a Steam Triton
extern bool SDL_IsJoystickSteamTriton(Uint16 vendor_id, Uint16 product_id);
// Function to return whether a joystick guid comes from the XInput driver
extern bool SDL_IsJoystickXInput(SDL_GUID guid);
+7 -3
View File
@@ -588,9 +588,9 @@ static const ControllerDescription_t arrControllers[] = {
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa715 ), k_eControllerType_SwitchInputOnlyController, NULL }, // Power A Fusion Wireless Arcade Stick (USB Mode) Over BT is shows up as 057e 2009
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa716 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Nintendo Switch Fusion Pro Controller - USB requires toggling switch on back of device
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa718 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Nintendo Switch Nano Wired Controller
{ MAKE_CONTROLLER_ID( 0x33dd, 0x0001 ), k_eControllerType_SwitchInputOnlyController, NULL }, // ZUIKI MasCon for Nintendo Switch Black
{ MAKE_CONTROLLER_ID( 0x33dd, 0x0002 ), k_eControllerType_SwitchInputOnlyController, NULL }, // ZUIKI MasCon for Nintendo Switch ??
{ MAKE_CONTROLLER_ID( 0x33dd, 0x0003 ), k_eControllerType_SwitchInputOnlyController, NULL }, // ZUIKI MasCon for Nintendo Switch Red
{ MAKE_CONTROLLER_ID( 0x33dd, 0x0001 ), k_eControllerType_SwitchInputOnlyController, NULL }, // ZUIKI MasCon for Nintendo Switch Black
{ MAKE_CONTROLLER_ID( 0x33dd, 0x0002 ), k_eControllerType_SwitchInputOnlyController, NULL }, // ZUIKI MasCon for Nintendo Switch ??
{ MAKE_CONTROLLER_ID( 0x33dd, 0x0003 ), k_eControllerType_SwitchInputOnlyController, NULL }, // ZUIKI MasCon for Nintendo Switch Red
// Valve products
{ MAKE_CONTROLLER_ID( 0x0000, 0x11fb ), k_eControllerType_MobileTouch, NULL }, // Streaming mobile touch virtual controls
@@ -603,4 +603,8 @@ static const ControllerDescription_t arrControllers[] = {
{ MAKE_CONTROLLER_ID( 0x28de, 0x1201 ), k_eControllerType_SteamControllerV2, NULL }, // Valve wired Steam Controller (HEADCRAB)
{ MAKE_CONTROLLER_ID( 0x28de, 0x1202 ), k_eControllerType_SteamControllerV2, NULL }, // Valve Bluetooth Steam Controller (HEADCRAB)
{ MAKE_CONTROLLER_ID( 0x28de, 0x1205 ), k_eControllerType_SteamControllerNeptune, NULL }, // Valve Steam Deck Builtin Controller
{ MAKE_CONTROLLER_ID( 0x28de, 0x1302 ), k_eControllerType_SteamControllerTriton, NULL }, // Valve Steam Triton Controller
{ MAKE_CONTROLLER_ID( 0x28de, 0x1303 ), k_eControllerType_SteamControllerTriton, NULL }, // Valve Steam Triton Controller (BLE)
{ MAKE_CONTROLLER_ID( 0x28de, 0x1304 ), k_eControllerType_SteamControllerTriton, NULL }, // Valve Steam Proteus Dongle (Proprietary)
{ MAKE_CONTROLLER_ID( 0x28de, 0x1305 ), k_eControllerType_SteamControllerTriton, NULL }, // Valve Steam Nereid Dongle (Proprietary)
};
+2
View File
@@ -39,6 +39,8 @@ typedef enum
k_eControllerType_SteamControllerV2 = 3,
k_eControllerType_SteamControllerNeptune = 4,
k_eControllerType_SteamControllerTriton = 10,
// Other Controllers
k_eControllerType_UnknownNonSteamController = 30,
k_eControllerType_XBox360Controller = 31,
File diff suppressed because it is too large Load Diff
+3
View File
@@ -70,6 +70,9 @@ static SDL_HIDAPI_DeviceDriver *SDL_HIDAPI_drivers[] = {
#ifdef SDL_JOYSTICK_HIDAPI_STEAMDECK
&SDL_HIDAPI_DriverSteamDeck,
#endif
#ifdef SDL_JOYSTICK_HIDAPI_STEAMDECK
&SDL_HIDAPI_DriverSteamTriton,
#endif
#ifdef SDL_JOYSTICK_HIDAPI_SWITCH
&SDL_HIDAPI_DriverNintendoClassic,
&SDL_HIDAPI_DriverJoyCons,
@@ -43,6 +43,7 @@
#define SDL_JOYSTICK_HIDAPI_XBOXONE
#define SDL_JOYSTICK_HIDAPI_SHIELD
#define SDL_JOYSTICK_HIDAPI_STEAM_HORI
#define SDL_JOYSTICK_HIDAPI_STEAM_TRITON
#define SDL_JOYSTICK_HIDAPI_LG4FF
#define SDL_JOYSTICK_HIDAPI_8BITDO
#define SDL_JOYSTICK_HIDAPI_FLYDIGI
@@ -168,6 +169,7 @@ extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteamHori;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteamTriton;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverLg4ff;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_Driver8BitDo;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverFlydigi;
@@ -411,6 +411,12 @@ typedef enum {
TRACKPAD_NUM_MODES
} TrackpadDPadMode;
typedef enum
{
LIZARD_MODE_OFF,
LIZARD_MODE_ON,
} LizardModeState_t;
// Read-write controller settings (only add to this enum and never change the order)
typedef enum
{
@@ -423,7 +429,7 @@ typedef enum
SETTING_USB_DEBUG_MODE,
SETTING_LEFT_TRACKPAD_MODE,
SETTING_RIGHT_TRACKPAD_MODE,
SETTING_MOUSE_POINTER_ENABLED,
SETTING_LIZARD_MODE,
// 10
SETTING_DPAD_DEADZONE,
+193 -32
View File
@@ -154,6 +154,100 @@ typedef struct
} FeatureReportMsg;
// Triton and derivatives utilize output reports for haptic commands. This is a
// snapshot from Nov 2024 -- things may change.
// Triton Output Report Lengths #defs include +1 for the OR ID
// Output Report Haptic Messages for Triton
typedef struct
{
uint8_t type;
uint16_t intensity;
struct
{
uint16_t speed;
int8_t gain;
} left, right;
} MsgHapticRumble;
#define HID_RUMBLE_OUTPUT_REPORT_BYTES 10
typedef struct
{
uint8_t side;
uint16_t on_us;
uint16_t off_us;
uint16_t repeat_count;
uint16_t gain_db;
} MsgHapticPulse;
#define HID_HAPTIC_PULSE_OUTPUT_REPORT_BYTES 10
typedef struct
{
uint8_t side;
uint8_t command;
int8_t gain_db;
} MsgHapticCommand;
#define HID_HAPTIC_COMMAND_REPORT_BYTES 4
typedef struct
{
uint8_t side;
int8_t gain_db;
uint16_t frequency;
uint16_t duration_ms;
uint16_t lfo_freq;
uint8_t lfo_depth;
} MsgHapticLfoTone;
#define HID_HAPTIC_LFO_TONE_REPORT_BYTES 10
typedef struct
{
uint8_t side;
int8_t gain_db;
uint16_t duration_ms;
struct
{
uint16_t frequency;
} start, end;
} MsgHapticLogSweep;
#define HID_HAPTIC_LOG_SWEEP_REPORT_BYTES 9
typedef struct m
{
uint8_t side;
uint8_t script_id;
int8_t gain_db;
} MsgHapticScript;
#define HID_HAPTIC_SCRIPT_REPORT_BYTES 4
typedef enum
{
ID_OUT_REPORT_HAPTIC_RUMBLE = 0x80,
ID_OUT_REPORT_HAPTIC_PULSE = 0x81,
ID_OUT_REPORT_HAPTIC_COMMAND = 0x82,
ID_OUT_REPORT_HAPTIC_LFO_TONE = 0x83,
ID_OUT_REPORT_HAPTIC_LOG_SWEEP = 0x85,
ID_OUT_REPORT_HAPTIC_SCRIPT = 0x86,
} ValveTritonOutReportMessageIDs;
typedef struct
{
uint8_t report_id;
union
{
MsgHapticRumble hapticRumble;
MsgHapticPulse hapticPulse;
MsgHapticCommand hapticCommand;
MsgHapticLfoTone hapticLfoTone;
MsgHapticLogSweep hapticLogSweep;
MsgHapticScript hapticScript;
} payload;
} OutputReportMsg;
// Roll this version forward anytime that you are breaking compatibility of existing
// message types within ValveInReport_t or the header itself. Hopefully this should
// be super rare and instead you should just add new message payloads to the union,
@@ -413,51 +507,118 @@ typedef struct
unsigned short sPressurePadRight;
} SteamDeckStatePacket_t;
typedef struct
{
ValveInReportHeader_t header;
union
{
ValveControllerStatePacket_t controllerState;
ValveControllerBLEStatePacket_t controllerBLEState;
ValveControllerDebugPacket_t debugState;
ValveControllerTrackpadImage_t padImage;
ValveControllerRawTrackpadImage_t rawPadImage;
SteamControllerWirelessEvent_t wirelessEvent;
SteamControllerStatusEvent_t statusEvent;
SteamDeckStatePacket_t deckState;
} payload;
ValveInReportHeader_t header;
union
{
ValveControllerStatePacket_t controllerState;
ValveControllerBLEStatePacket_t controllerBLEState;
ValveControllerDebugPacket_t debugState;
ValveControllerTrackpadImage_t padImage;
ValveControllerRawTrackpadImage_t rawPadImage;
SteamControllerWirelessEvent_t wirelessEvent;
SteamControllerStatusEvent_t statusEvent;
SteamDeckStatePacket_t deckState;
} payload;
} ValveInReport_t;
// Enumeration for BLE packet protocol
enum EBLEPacketReportNums
{
// Skipping past 2-3 because they are escape characters in Uart protocol
k_EBLEReportState = 4,
k_EBLEReportStatus = 5,
k_EBLEReportState = 4,
k_EBLEReportStatus = 5,
};
// Enumeration of data chunks in BLE state packets
enum EBLEOptionDataChunksBitmask
{
// First byte upper nibble
k_EBLEButtonChunk1 = 0x10,
k_EBLEButtonChunk2 = 0x20,
k_EBLEButtonChunk3 = 0x40,
k_EBLELeftJoystickChunk = 0x80,
// First byte upper nibble
k_EBLEButtonChunk1 = 0x10,
k_EBLEButtonChunk2 = 0x20,
k_EBLEButtonChunk3 = 0x40,
k_EBLELeftJoystickChunk = 0x80,
// Second full byte
k_EBLELeftTrackpadChunk = 0x100,
k_EBLERightTrackpadChunk = 0x200,
k_EBLEIMUAccelChunk = 0x400,
k_EBLEIMUGyroChunk = 0x800,
k_EBLEIMUQuatChunk = 0x1000,
// Second full byte
k_EBLELeftTrackpadChunk = 0x100,
k_EBLERightTrackpadChunk = 0x200,
k_EBLEIMUAccelChunk = 0x400,
k_EBLEIMUGyroChunk = 0x800,
k_EBLEIMUQuatChunk = 0x1000,
};
// Triton and derivatives do not use the ValveInReport_t structure
enum ETritonReportIDTypes
{
ID_TRITON_CONTROLLER_STATE = 0x42,
ID_TRITON_BATTERY_STATUS = 0x43,
ID_TRITON_WIRELESS_STATUS_X = 0x46,
ID_TRITON_WIRELESS_STATUS = 0x79,
};
enum ETritonWirelessState
{
k_ETritonWirelessStateDisconnect = 1,
k_ETritonWirelessStateConnect = 2,
};
typedef struct
{
uint32_t uTimestamp;
short sAccelX;
short sAccelY;
short sAccelZ;
short sGyroX;
short sGyroY;
short sGyroZ;
short sGyroQuatW;
short sGyroQuatX;
short sGyroQuatY;
short sGyroQuatZ;
} TritonMTUIMU_t;
typedef struct
{
uint8_t cSeq_num;
uint32_t uButtons;
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;
TritonMTUIMU_t imu;
} TritonMTUFull_t;
typedef struct
{
unsigned char ucBatteryLevel;
unsigned short sBatteryVoltage;
unsigned short sSystemVoltage;
unsigned short sInputVoltage;
unsigned short sCurrent;
unsigned short sInputCurrent;
char cTemperature;
} TritonBatteryStatus_t;
typedef struct
{
unsigned char state;
} TritonWirelessStatus_t;
#pragma pack()
#endif // _CONTROLLER_STRUCTS
+2
View File
@@ -149,6 +149,8 @@
#define USB_PRODUCT_THRUSTMASTER_ESWAPX_PRO_PS4 0xd00e
#define USB_PRODUCT_THRUSTMASTER_T_FLIGHT_HOTAS_ONE 0xb68c
#define USB_PRODUCT_VALVE_STEAM_CONTROLLER_DONGLE 0x1142
#define USB_PRODUCT_VALVE_STEAM_PROTEUS_DONGLE 0x1304
#define USB_PRODUCT_VALVE_STEAM_NEREID_DONGLE 0x1305
#define USB_PRODUCT_VICTRIX_FS_PRO 0x0203
#define USB_PRODUCT_VICTRIX_FS_PRO_V2 0x0207
#define USB_PRODUCT_XBOX360_XUSB_CONTROLLER 0x02a1 // XUSB driver software PID