From c981a597dc7c69e7532796b3a206071807479d35 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sat, 9 Dec 2023 23:05:34 -0800
Subject: [PATCH] Added Steam Input API support for game controllers
Added support for getting the real controller info, as well as the function SDL_GetGamepadSteamHandle() to get the Steam Input API handle, from the virtual gamepads provided by Steam.
Also added an event SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED which is triggered when a controller's API handle changes, e.g. the controllers were reassigned slots in the Steam UI.
---
VisualC-GDK/SDL/SDL.vcxproj | 2 +
VisualC-GDK/SDL/SDL.vcxproj.filters | 6 +
VisualC-WinRT/SDL-UWP.vcxproj | 2 +
VisualC-WinRT/SDL-UWP.vcxproj.filters | 6 +
VisualC/SDL/SDL.vcxproj | 2 +
VisualC/SDL/SDL.vcxproj.filters | 6 +
Xcode/SDL/SDL.xcodeproj/project.pbxproj | 20 +-
include/SDL3/SDL_events.h | 3 +-
include/SDL3/SDL_gamepad.h | 13 +
src/dynapi/SDL_dynapi.sym | 1 +
src/dynapi/SDL_dynapi_overrides.h | 1 +
src/dynapi/SDL_dynapi_procs.h | 1 +
src/events/SDL_events.c | 3 +
src/joystick/SDL_gamepad.c | 45 +++-
src/joystick/SDL_joystick.c | 140 +++++++++-
src/joystick/SDL_joystick_c.h | 4 +
src/joystick/SDL_steam_virtual_gamepad.c | 248 ++++++++++++++++++
src/joystick/SDL_steam_virtual_gamepad.h | 36 +++
src/joystick/SDL_sysjoystick.h | 4 +
src/joystick/android/SDL_sysjoystick.c | 6 +
src/joystick/apple/SDL_mfijoystick.m | 11 +
src/joystick/bsd/SDL_bsdjoystick.c | 6 +
src/joystick/darwin/SDL_iokitjoystick.c | 21 ++
src/joystick/darwin/SDL_iokitjoystick_c.h | 1 +
src/joystick/dummy/SDL_sysjoystick.c | 6 +
src/joystick/emscripten/SDL_sysjoystick.c | 6 +
src/joystick/haiku/SDL_haikujoystick.cc | 6 +
src/joystick/hidapi/SDL_hidapijoystick.c | 6 +
src/joystick/linux/SDL_sysjoystick.c | 38 +--
src/joystick/n3ds/SDL_sysjoystick.c | 6 +
src/joystick/ps2/SDL_sysjoystick.c | 7 +
src/joystick/psp/SDL_sysjoystick.c | 6 +
src/joystick/virtual/SDL_virtualjoystick.c | 6 +
src/joystick/vita/SDL_sysjoystick.c | 6 +
src/joystick/windows/SDL_dinputjoystick.c | 15 +-
src/joystick/windows/SDL_rawinputjoystick.c | 21 ++
.../windows/SDL_windows_gaming_input.c | 36 +++
src/joystick/windows/SDL_windowsjoystick.c | 19 +-
src/joystick/windows/SDL_windowsjoystick_c.h | 1 +
src/joystick/windows/SDL_xinputjoystick.c | 26 +-
src/joystick/windows/SDL_xinputjoystick_c.h | 1 +
test/testcontroller.c | 19 ++
42 files changed, 779 insertions(+), 40 deletions(-)
create mode 100644 src/joystick/SDL_steam_virtual_gamepad.c
create mode 100644 src/joystick/SDL_steam_virtual_gamepad.h
diff --git a/VisualC-GDK/SDL/SDL.vcxproj b/VisualC-GDK/SDL/SDL.vcxproj
index 40bf69560b16..7fe307986cd1 100644
--- a/VisualC-GDK/SDL/SDL.vcxproj
+++ b/VisualC-GDK/SDL/SDL.vcxproj
@@ -407,6 +407,7 @@
<ClInclude Include="..\..\src\joystick\SDL_gamepad_c.h" />
<ClInclude Include="..\..\src\joystick\SDL_gamepad_db.h" />
<ClInclude Include="..\..\src\joystick\SDL_joystick_c.h" />
+ <ClInclude Include="..\..\src\joystick\SDL_steam_virtual_gamepad.h" />
<ClInclude Include="..\..\src\joystick\SDL_sysjoystick.h" />
<ClInclude Include="..\..\src\joystick\usb_ids.h" />
<ClInclude Include="..\..\src\joystick\virtual\SDL_virtualjoystick_c.h" />
@@ -634,6 +635,7 @@
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xboxone.c" />
<ClCompile Include="..\..\src\joystick\SDL_gamepad.c" />
<ClCompile Include="..\..\src\joystick\SDL_joystick.c" />
+ <ClCompile Include="..\..\src\joystick\SDL_steam_virtual_gamepad.c" />
<ClCompile Include="..\..\src\joystick\virtual\SDL_virtualjoystick.c" />
<ClCompile Include="..\..\src\joystick\windows\SDL_dinputjoystick.c" />
<ClCompile Include="..\..\src\joystick\windows\SDL_rawinputjoystick.c" />
diff --git a/VisualC-GDK/SDL/SDL.vcxproj.filters b/VisualC-GDK/SDL/SDL.vcxproj.filters
index cd21c505f0d9..08257eaf35f4 100644
--- a/VisualC-GDK/SDL/SDL.vcxproj.filters
+++ b/VisualC-GDK/SDL/SDL.vcxproj.filters
@@ -507,6 +507,9 @@
<ClInclude Include="..\..\src\joystick\SDL_joystick_c.h">
<Filter>joystick</Filter>
</ClInclude>
+ <ClInclude Include="..\..\src\joystick\SDL_steam_virtual_gamepad.h">
+ <Filter>joystick</Filter>
+ </ClInclude>
<ClInclude Include="..\..\src\joystick\SDL_sysjoystick.h">
<Filter>joystick</Filter>
</ClInclude>
@@ -964,6 +967,9 @@
<ClCompile Include="..\..\src\joystick\SDL_joystick.c">
<Filter>joystick</Filter>
</ClCompile>
+ <ClCompile Include="..\..\src\joystick\SDL_steam_virtual_gamepad.c">
+ <Filter>joystick</Filter>
+ </ClCompile>
<ClCompile Include="..\..\src\libm\e_atan2.c">
<Filter>libm</Filter>
</ClCompile>
diff --git a/VisualC-WinRT/SDL-UWP.vcxproj b/VisualC-WinRT/SDL-UWP.vcxproj
index 9c2d387d23cf..2e1701a4d627 100644
--- a/VisualC-WinRT/SDL-UWP.vcxproj
+++ b/VisualC-WinRT/SDL-UWP.vcxproj
@@ -127,6 +127,7 @@
<ClInclude Include="..\src\joystick\SDL_gamepad_c.h" />
<ClInclude Include="..\src\joystick\SDL_gamepad_db.h" />
<ClInclude Include="..\src\joystick\SDL_joystick_c.h" />
+ <ClInclude Include="..\src\joystick\SDL_steam_virtual_gamepad.h" />
<ClInclude Include="..\src\joystick\SDL_sysjoystick.h" />
<ClInclude Include="..\src\joystick\virtual\SDL_virtualjoystick_c.h" />
<ClInclude Include="..\src\joystick\windows\SDL_dinputjoystick_c.h" />
@@ -331,6 +332,7 @@
<ClCompile Include="..\src\joystick\controller_type.c" />
<ClCompile Include="..\src\joystick\SDL_gamepad.c" />
<ClCompile Include="..\src\joystick\SDL_joystick.c" />
+ <ClCompile Include="..\src\joystick\SDL_steam_virtual_gamepad.c" />
<ClCompile Include="..\src\joystick\virtual\SDL_virtualjoystick.c" />
<ClCompile Include="..\src\joystick\windows\SDL_dinputjoystick.c" />
<ClCompile Include="..\src\joystick\windows\SDL_windowsjoystick.c" />
diff --git a/VisualC-WinRT/SDL-UWP.vcxproj.filters b/VisualC-WinRT/SDL-UWP.vcxproj.filters
index 586b0d2a5d2a..d92ce733801e 100644
--- a/VisualC-WinRT/SDL-UWP.vcxproj.filters
+++ b/VisualC-WinRT/SDL-UWP.vcxproj.filters
@@ -261,6 +261,9 @@
<ClInclude Include="..\src\joystick\SDL_joystick_c.h">
<Filter>Source Files</Filter>
</ClInclude>
+ <ClInclude Include="..\src\joystick\SDL_steam_virtual_gamepad.h">
+ <Filter>Source Files</Filter>
+ </ClInclude>
<ClInclude Include="..\src\joystick\SDL_sysjoystick.h">
<Filter>Source Files</Filter>
</ClInclude>
@@ -585,6 +588,9 @@
<ClCompile Include="..\src\joystick\SDL_joystick.c">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\src\joystick\SDL_steam_virtual_gamepad.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\src\joystick\virtual\SDL_virtualjoystick.c">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/VisualC/SDL/SDL.vcxproj b/VisualC/SDL/SDL.vcxproj
index b89ae43ba009..3f38d13f89f9 100644
--- a/VisualC/SDL/SDL.vcxproj
+++ b/VisualC/SDL/SDL.vcxproj
@@ -357,6 +357,7 @@
<ClInclude Include="..\..\src\joystick\SDL_gamepad_c.h" />
<ClInclude Include="..\..\src\joystick\SDL_gamepad_db.h" />
<ClInclude Include="..\..\src\joystick\SDL_joystick_c.h" />
+ <ClInclude Include="..\..\src\joystick\SDL_steam_virtual_gamepad.h" />
<ClInclude Include="..\..\src\joystick\SDL_sysjoystick.h" />
<ClInclude Include="..\..\src\joystick\usb_ids.h" />
<ClInclude Include="..\..\src\joystick\virtual\SDL_virtualjoystick_c.h" />
@@ -537,6 +538,7 @@
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xboxone.c" />
<ClCompile Include="..\..\src\joystick\SDL_gamepad.c" />
<ClCompile Include="..\..\src\joystick\SDL_joystick.c" />
+ <ClCompile Include="..\..\src\joystick\SDL_steam_virtual_gamepad.c" />
<ClCompile Include="..\..\src\joystick\virtual\SDL_virtualjoystick.c" />
<ClCompile Include="..\..\src\joystick\windows\SDL_dinputjoystick.c" />
<ClCompile Include="..\..\src\joystick\windows\SDL_rawinputjoystick.c" />
diff --git a/VisualC/SDL/SDL.vcxproj.filters b/VisualC/SDL/SDL.vcxproj.filters
index 79a582b8e1a5..6002a968c609 100644
--- a/VisualC/SDL/SDL.vcxproj.filters
+++ b/VisualC/SDL/SDL.vcxproj.filters
@@ -501,6 +501,9 @@
<ClInclude Include="..\..\src\joystick\SDL_joystick_c.h">
<Filter>joystick</Filter>
</ClInclude>
+ <ClInclude Include="..\..\src\joystick\SDL_steam_virtual_gamepad.h">
+ <Filter>joystick</Filter>
+ </ClInclude>
<ClInclude Include="..\..\src\joystick\SDL_sysjoystick.h">
<Filter>joystick</Filter>
</ClInclude>
@@ -945,6 +948,9 @@
<ClCompile Include="..\..\src\joystick\SDL_joystick.c">
<Filter>joystick</Filter>
</ClCompile>
+ <ClCompile Include="..\..\src\joystick\SDL_steam_virtual_gamepad.c">
+ <Filter>joystick</Filter>
+ </ClCompile>
<ClCompile Include="..\..\src\libm\e_atan2.c">
<Filter>libm</Filter>
</ClCompile>
diff --git a/Xcode/SDL/SDL.xcodeproj/project.pbxproj b/Xcode/SDL/SDL.xcodeproj/project.pbxproj
index e4dca89aa188..2f9d04f15658 100644
--- a/Xcode/SDL/SDL.xcodeproj/project.pbxproj
+++ b/Xcode/SDL/SDL.xcodeproj/project.pbxproj
@@ -384,6 +384,10 @@
F32DDAD32AB795A30041EAA5 /* SDL_audioqueue.h in Headers */ = {isa = PBXBuildFile; fileRef = F32DDACD2AB795A30041EAA5 /* SDL_audioqueue.h */; };
F32DDAD42AB795A30041EAA5 /* SDL_audioresample.c in Sources */ = {isa = PBXBuildFile; fileRef = F32DDACE2AB795A30041EAA5 /* SDL_audioresample.c */; };
F34B9895291DEFF500AAC96E /* SDL_hidapi_steam.c in Sources */ = {isa = PBXBuildFile; fileRef = A75FDAAC23E2795C00529352 /* SDL_hidapi_steam.c */; };
+ F362B9192B3349E200D30B94 /* controller_list.h in Headers */ = {isa = PBXBuildFile; fileRef = F362B9152B3349E200D30B94 /* controller_list.h */; };
+ F362B91A2B3349E200D30B94 /* SDL_gamepad_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F362B9162B3349E200D30B94 /* SDL_gamepad_c.h */; };
+ F362B91B2B3349E200D30B94 /* SDL_steam_virtual_gamepad.h in Headers */ = {isa = PBXBuildFile; fileRef = F362B9172B3349E200D30B94 /* SDL_steam_virtual_gamepad.h */; };
+ F362B91C2B3349E200D30B94 /* SDL_steam_virtual_gamepad.c in Sources */ = {isa = PBXBuildFile; fileRef = F362B9182B3349E200D30B94 /* SDL_steam_virtual_gamepad.c */; };
F36C7AD1294BA009004D61C3 /* SDL_runapp.c in Sources */ = {isa = PBXBuildFile; fileRef = F36C7AD0294BA009004D61C3 /* SDL_runapp.c */; };
F376F6552559B4E300CFC0BC /* SDL_hidapi.c in Sources */ = {isa = PBXBuildFile; fileRef = A7D8A81423E2513F00DCD162 /* SDL_hidapi.c */; };
F37A8E1A28405AA100C38E95 /* CMake in Resources */ = {isa = PBXBuildFile; fileRef = F37A8E1928405AA100C38E95 /* CMake */; };
@@ -879,6 +883,10 @@
F32DDACC2AB795A30041EAA5 /* SDL_audio_resampler_filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_audio_resampler_filter.h; sourceTree = "<group>"; };
F32DDACD2AB795A30041EAA5 /* SDL_audioqueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_audioqueue.h; sourceTree = "<group>"; };
F32DDACE2AB795A30041EAA5 /* SDL_audioresample.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audioresample.c; sourceTree = "<group>"; };
+ F362B9152B3349E200D30B94 /* controller_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = controller_list.h; sourceTree = "<group>"; };
+ F362B9162B3349E200D30B94 /* SDL_gamepad_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_gamepad_c.h; sourceTree = "<group>"; };
+ F362B9172B3349E200D30B94 /* SDL_steam_virtual_gamepad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_steam_virtual_gamepad.h; sourceTree = "<group>"; };
+ F362B9182B3349E200D30B94 /* SDL_steam_virtual_gamepad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_steam_virtual_gamepad.c; sourceTree = "<group>"; };
F36C7AD0294BA009004D61C3 /* SDL_runapp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_runapp.c; sourceTree = "<group>"; };
F376F6182559B29300CFC0BC /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.1.sdk/System/Library/Frameworks/OpenGLES.framework; sourceTree = DEVELOPER_DIR; };
F376F61A2559B2AF00CFC0BC /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/iOSSupport/System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
@@ -1670,12 +1678,16 @@
A7D8A7BE23E2513E00DCD162 /* hidapi */,
A7D8A7A123E2513E00DCD162 /* steam */,
75E09157241EA924004729E1 /* virtual */,
- A7D8A7AD23E2513E00DCD162 /* SDL_gamepad.c */,
- A7D8A7A923E2513E00DCD162 /* SDL_joystick.c */,
+ F362B9152B3349E200D30B94 /* controller_list.h */,
F3820712284F3609004DD584 /* controller_type.c */,
A7D8A7D923E2513E00DCD162 /* controller_type.h */,
+ F362B9162B3349E200D30B94 /* SDL_gamepad_c.h */,
A7D8A79E23E2513E00DCD162 /* SDL_gamepad_db.h */,
+ A7D8A7AD23E2513E00DCD162 /* SDL_gamepad.c */,
A7D8A7D023E2513E00DCD162 /* SDL_joystick_c.h */,
+ A7D8A7A923E2513E00DCD162 /* SDL_joystick.c */,
+ F362B9182B3349E200D30B94 /* SDL_steam_virtual_gamepad.c */,
+ F362B9172B3349E200D30B94 /* SDL_steam_virtual_gamepad.h */,
A7D8A7CF23E2513E00DCD162 /* SDL_sysjoystick.h */,
A7D8A7CB23E2513E00DCD162 /* usb_ids.h */,
);
@@ -2167,6 +2179,7 @@
F3F7D9B92933074E00816151 /* SDL_cpuinfo.h in Headers */,
F3990E062A788303000D8759 /* SDL_hidapi_ios.h in Headers */,
A7D8B98023E2514400DCD162 /* SDL_d3dmath.h in Headers */,
+ F362B91A2B3349E200D30B94 /* SDL_gamepad_c.h in Headers */,
A7D8B8A223E2514400DCD162 /* SDL_diskaudio.h in Headers */,
A7D8BB3F23E2514500DCD162 /* SDL_displayevents_c.h in Headers */,
A7D8BA1923E2514400DCD162 /* SDL_draw.h in Headers */,
@@ -2180,6 +2193,7 @@
A7D8AB1023E2514100DCD162 /* SDL_dynapi_overrides.h in Headers */,
A7D8AB1C23E2514100DCD162 /* SDL_dynapi_procs.h in Headers */,
F3F7D9252933074E00816151 /* SDL_egl.h in Headers */,
+ F362B9192B3349E200D30B94 /* controller_list.h in Headers */,
A7D8ABD923E2514100DCD162 /* SDL_egl_c.h in Headers */,
F3F7D93D2933074E00816151 /* SDL_endian.h in Headers */,
F3F7D9352933074E00816151 /* SDL_error.h in Headers */,
@@ -2219,6 +2233,7 @@
F3F7D91D2933074E00816151 /* SDL_messagebox.h in Headers */,
F3F7D98D2933074E00816151 /* SDL_metal.h in Headers */,
F395C1BA2569C6A000942BFF /* SDL_mfijoystick_c.h in Headers */,
+ F362B91B2B3349E200D30B94 /* SDL_steam_virtual_gamepad.h in Headers */,
F3F7D9992933074E00816151 /* SDL_misc.h in Headers */,
F3F7D9AD2933074E00816151 /* SDL_mouse.h in Headers */,
A7D8BB1B23E2514500DCD162 /* SDL_mouse_c.h in Headers */,
@@ -2583,6 +2598,7 @@
A7D8BAD323E2514500DCD162 /* s_tan.c in Sources */,
A7D8AA6523E2514000DCD162 /* SDL_hints.c in Sources */,
A7D8B53F23E2514300DCD162 /* SDL_hidapi_ps4.c in Sources */,
+ F362B91C2B3349E200D30B94 /* SDL_steam_virtual_gamepad.c in Sources */,
A7D8AD6E23E2514100DCD162 /* SDL_pixels.c in Sources */,
A7D8B75E23E2514300DCD162 /* SDL_sysloadso.c in Sources */,
A7D8BBD723E2574800DCD162 /* SDL_uikitevents.m in Sources */,
diff --git a/include/SDL3/SDL_events.h b/include/SDL3/SDL_events.h
index 1b9edd2bd824..11276e5ff53b 100644
--- a/include/SDL3/SDL_events.h
+++ b/include/SDL3/SDL_events.h
@@ -170,6 +170,7 @@ typedef enum
SDL_EVENT_GAMEPAD_TOUCHPAD_UP, /**< Gamepad touchpad finger was lifted */
SDL_EVENT_GAMEPAD_SENSOR_UPDATE, /**< Gamepad sensor was updated */
SDL_EVENT_GAMEPAD_UPDATE_COMPLETE, /**< Gamepad update is complete */
+ SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED, /**< Gamepad Steam handle has changed */
/* Touch events */
SDL_EVENT_FINGER_DOWN = 0x700,
@@ -457,7 +458,7 @@ typedef struct SDL_GamepadButtonEvent
*/
typedef struct SDL_GamepadDeviceEvent
{
- Uint32 type; /**< ::SDL_EVENT_GAMEPAD_ADDED, ::SDL_EVENT_GAMEPAD_REMOVED, or ::SDL_EVENT_GAMEPAD_REMAPPED or ::SDL_EVENT_GAMEPAD_UPDATE_COMPLETE */
+ Uint32 type; /**< ::SDL_EVENT_GAMEPAD_ADDED, ::SDL_EVENT_GAMEPAD_REMOVED, or ::SDL_EVENT_GAMEPAD_REMAPPED, ::SDL_EVENT_GAMEPAD_UPDATE_COMPLETE or ::SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED */
Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */
SDL_JoystickID which; /**< The joystick instance id */
} SDL_GamepadDeviceEvent;
diff --git a/include/SDL3/SDL_gamepad.h b/include/SDL3/SDL_gamepad.h
index f536ce352ab6..d7da172763e1 100644
--- a/include/SDL3/SDL_gamepad.h
+++ b/include/SDL3/SDL_gamepad.h
@@ -758,6 +758,19 @@ extern DECLSPEC Uint16 SDLCALL SDL_GetGamepadFirmwareVersion(SDL_Gamepad *gamepa
*/
extern DECLSPEC const char * SDLCALL SDL_GetGamepadSerial(SDL_Gamepad *gamepad);
+/**
+ * Get the Steam Input handle of an opened gamepad, if available.
+ *
+ * Returns an InputHandle_t for the gamepad that can be used with Steam Input API:
+ * https://partner.steamgames.com/doc/api/ISteamInput
+ *
+ * \param gamepad the gamepad object to query.
+ * \returns the gamepad handle, or 0 if unavailable.
+ *
+ * \since This function is available since SDL 3.0.0.
+ */
+extern DECLSPEC Uint64 SDLCALL SDL_GetGamepadSteamHandle(SDL_Gamepad *gamepad);
+
/**
* Get the battery level of a gamepad, if available.
*
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index 7a68abb99806..9b22950ec927 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -965,6 +965,7 @@ SDL3_0.0.0 {
SDL_SyncWindow;
SDL_SetSurfaceScaleMode;
SDL_GetSurfaceScaleMode;
+ SDL_GetGamepadSteamHandle;
# extra symbols go here (don't modify this line)
local: *;
};
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index acfbb8c7cf90..4c3007636b17 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -990,3 +990,4 @@
#define SDL_SyncWindow SDL_SyncWindow_REAL
#define SDL_SetSurfaceScaleMode SDL_SetSurfaceScaleMode_REAL
#define SDL_GetSurfaceScaleMode SDL_GetSurfaceScaleMode_REAL
+#define SDL_GetGamepadSteamHandle SDL_GetGamepadSteamHandle_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index faf3d553e2a0..7c7993c6f50b 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -1015,3 +1015,4 @@ SDL_DYNAPI_PROC(wchar_t*,SDL_wcsnstr,(const wchar_t *a, const wchar_t *b, size_t
SDL_DYNAPI_PROC(int,SDL_SyncWindow,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_SetSurfaceScaleMode,(SDL_Surface *a, SDL_ScaleMode b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_GetSurfaceScaleMode,(SDL_Surface *a, SDL_ScaleMode *b),(a,b),return)
+SDL_DYNAPI_PROC(Uint64,SDL_GetGamepadSteamHandle,(SDL_Gamepad *a),(a),return)
diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c
index ac36e25cc2e7..0801db7d3134 100644
--- a/src/events/SDL_events.c
+++ b/src/events/SDL_events.c
@@ -433,6 +433,9 @@ static void SDL_LogEvent(const SDL_Event *event)
SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_REMAPPED)
PRINT_GAMEPADDEV_EVENT(event);
break;
+ SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED)
+ PRINT_GAMEPADDEV_EVENT(event);
+ break;
#undef PRINT_GAMEPADDEV_EVENT
#define PRINT_CTOUCHPAD_EVENT(event) \
diff --git a/src/joystick/SDL_gamepad.c b/src/joystick/SDL_gamepad.c
index e206f7feb67b..c911183da849 100644
--- a/src/joystick/SDL_gamepad.c
+++ b/src/joystick/SDL_gamepad.c
@@ -25,6 +25,7 @@
#include "../SDL_utils_c.h"
#include "SDL_sysjoystick.h"
#include "SDL_joystick_c.h"
+#include "SDL_steam_virtual_gamepad.h"
#include "SDL_gamepad_c.h"
#include "SDL_gamepad_db.h"
#include "controller_type.h"
@@ -2411,7 +2412,21 @@ SDL_GamepadType SDL_GetGamepadInstanceType(SDL_JoystickID instance_id)
SDL_GamepadType SDL_GetRealGamepadInstanceType(SDL_JoystickID instance_id)
{
- return SDL_GetGamepadTypeFromGUID(SDL_GetJoystickInstanceGUID(instance_id), SDL_GetJoystickInstanceName(instance_id));
+ SDL_GamepadType type = SDL_GAMEPAD_TYPE_UNKNOWN;
+ const SDL_SteamVirtualGamepadInfo *info;
+
+ SDL_LockJoysticks();
+ {
+ info = SDL_GetJoystickInstanceVirtualGamepadInfo(instance_id);
+ if (info) {
+ type = info->type;
+ } else {
+ type = SDL_GetGamepadTypeFromGUID(SDL_GetJoystickInstanceGUID(instance_id), SDL_GetJoystickInstanceName(instance_id));
+ }
+ }
+ SDL_UnlockJoysticks();
+
+ return type;
}
char *SDL_GetGamepadInstanceMapping(SDL_JoystickID instance_id)
@@ -2518,7 +2533,7 @@ SDL_bool SDL_ShouldIgnoreGamepad(const char *name, SDL_JoystickGUID guid)
#ifdef __LINUX__
bSteamVirtualGamepad = (vendor == USB_VENDOR_VALVE && product == USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD);
#elif defined(__MACOS__)
- bSteamVirtualGamepad = (vendor == USB_VENDOR_MICROSOFT && product == USB_PRODUCT_XBOX360_WIRED_CONTROLLER && version == 1);
+ bSteamVirtualGamepad = (vendor == USB_VENDOR_MICROSOFT && product == USB_PRODUCT_XBOX360_WIRED_CONTROLLER && version == 0);
#elif defined(__WIN32__)
/* We can't tell on Windows, but Steam will block others in input hooks */
bSteamVirtualGamepad = SDL_TRUE;
@@ -3190,7 +3205,8 @@ const char *SDL_GetGamepadName(SDL_Gamepad *gamepad)
{
CHECK_GAMEPAD_MAGIC(gamepad, NULL);
- if (SDL_strcmp(gamepad->name, "*") == 0) {
+ if (SDL_strcmp(gamepad->name, "*") == 0 ||
+ gamepad->joystick->steam_handle != 0) {
retval = SDL_GetJoystickName(gamepad->joystick);
} else {
retval = gamepad->name;
@@ -3214,12 +3230,18 @@ const char *SDL_GetGamepadPath(SDL_Gamepad *gamepad)
SDL_GamepadType SDL_GetGamepadType(SDL_Gamepad *gamepad)
{
SDL_GamepadType type;
+ const SDL_SteamVirtualGamepadInfo *info;
SDL_LockJoysticks();
{
CHECK_GAMEPAD_MAGIC(gamepad, SDL_GAMEPAD_TYPE_UNKNOWN);
- type = gamepad->type;
+ info = SDL_GetJoystickInstanceVirtualGamepadInfo(gamepad->joystick->instance_id);
+ if (info) {
+ type = info->type;
+ } else {
+ type = gamepad->type;
+ }
}
SDL_UnlockJoysticks();
@@ -3310,6 +3332,21 @@ const char * SDL_GetGamepadSerial(SDL_Gamepad *gamepad)
return SDL_GetJoystickSerial(joystick);
}
+Uint64 SDL_GetGamepadSteamHandle(SDL_Gamepad *gamepad)
+{
+ Uint64 handle = 0;
+
+ SDL_LockJoysticks();
+ {
+ CHECK_GAMEPAD_MAGIC(gamepad, 0);
+
+ handle = gamepad->joystick->steam_handle;
+ }
+ SDL_UnlockJoysticks();
+
+ return handle;
+}
+
SDL_JoystickPowerLevel SDL_GetGamepadPowerLevel(SDL_Gamepad *gamepad)
{
SDL_Joystick *joystick = SDL_GetGamepadJoystick(gamepad);
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index 28fcdda3af76..b555449e53fa 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -26,6 +26,7 @@
#include "../SDL_hints_c.h"
#include "SDL_gamepad_c.h"
#include "SDL_joystick_c.h"
+#include "SDL_steam_virtual_gamepad.h"
#ifndef SDL_EVENTS_DISABLED
#include "../events/SDL_events_c.h"
@@ -624,6 +625,8 @@ int SDL_InitJoysticks(void)
SDL_AddHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
SDL_JoystickAllowBackgroundEventsChanged, NULL);
+ SDL_InitSteamVirtualGamepadInfo();
+
status = -1;
for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
if (SDL_joystick_drivers[i]->Init() >= 0) {
@@ -696,6 +699,19 @@ SDL_JoystickID *SDL_GetJoysticks(int *count)
return joysticks;
}
+const SDL_SteamVirtualGamepadInfo *SDL_GetJoystickInstanceVirtualGamepadInfo(SDL_JoystickID instance_id)
+{
+ SDL_JoystickDriver *driver;
+ int device_index;
+ const SDL_SteamVirtualGamepadInfo *info = NULL;
+
+ if (SDL_SteamVirtualGamepadEnabled() &&
+ SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) {
+ info = SDL_GetSteamVirtualGamepadInfo(driver->GetDeviceSteamVirtualGamepadSlot(device_index));
+ }
+ return info;
+}
+
/*
* Get the implementation dependent name of a joystick
*/
@@ -704,9 +720,13 @@ const char *SDL_GetJoystickInstanceName(SDL_JoystickID instance_id)
SDL_JoystickDriver *driver;
int device_index;
const char *name = NULL;
+ const SDL_SteamVirtualGamepadInfo *info;
SDL_LockJoysticks();
- if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) {
+ info = SDL_GetJoystickInstanceVirtualGamepadInfo(instance_id);
+ if (info) {
+ name = info->name;
+ } else if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) {
name = driver->GetDeviceName(device_index);
}
SDL_UnlockJoysticks();
@@ -993,6 +1013,7 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id)
const char *joystickpath = NULL;
SDL_JoystickPowerLevel initial_power_level;
SDL_bool invert_sensors = SDL_FALSE;
+ const SDL_SteamVirtualGamepadInfo *info;
SDL_LockJoysticks();
@@ -1076,6 +1097,12 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id)
joystick->is_gamepad = SDL_IsGamepad(instance_id);
+ /* Get the Steam Input API handle */
+ info = SDL_GetJoystickInstanceVirtualGamepadInfo(instance_id);
+ if (info) {
+ joystick->steam_handle = info->handle;
+ }
+
/* Use system gyro and accelerometer if the gamepad doesn't have built-in sensors */
if (ShouldAttemptSensorFusion(joystick, &invert_sensors)) {
AttemptSensorFusion(joystick, invert_sensors);
@@ -1491,15 +1518,20 @@ SDL_PropertiesID SDL_GetJoystickProperties(SDL_Joystick *joystick)
const char *SDL_GetJoystickName(SDL_Joystick *joystick)
{
const char *retval;
+ const SDL_SteamVirtualGamepadInfo *info;
SDL_LockJoysticks();
- {
+ info = SDL_GetJoystickInstanceVirtualGamepadInfo(joystick->instance_id);
+ if (info) {
+ retval = info->name;
+ } else {
CHECK_JOYSTICK_MAGIC(joystick, NULL);
retval = joystick->name;
}
SDL_UnlockJoysticks();
+ /* FIXME: Really we should reference count this name so it doesn't go away after unlock */
return retval;
}
@@ -1823,6 +1855,8 @@ void SDL_QuitJoysticks(void)
SDL_QuitSubSystem(SDL_INIT_EVENTS);
#endif
+ SDL_QuitSteamVirtualGamepadInfo();
+
SDL_DelHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
SDL_JoystickAllowBackgroundEventsChanged, NULL);
@@ -1921,7 +1955,10 @@ void SDL_PrivateJoystickAdded(SDL_JoystickID instance_id)
SDL_joystick_being_added = SDL_TRUE;
if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) {
- player_index = driver->GetDevicePlayerIndex(device_index);
+ player_index = driver->GetDeviceSteamVirtualGamepadSlot(device_index);
+ if (player_index < 0) {
+ player_index = driver->GetDevicePlayerIndex(device_index);
+ }
}
if (player_index < 0 && SDL_IsGamepad(instance_id)) {
player_index = SDL_FindFreePlayerIndex();
@@ -2200,6 +2237,43 @@ int SDL_SendJoystickButton(Uint64 timestamp, SDL_Joystick *joystick, Uint8 butto
return posted;
}
+static void SendSteamHandleUpdateEvents(void)
+{
+ SDL_Joystick *joystick;
+ const SDL_SteamVirtualGamepadInfo *info;
+
+ /* Check to see if any Steam handles changed */
+ for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
+ SDL_bool changed = SDL_FALSE;
+
+ if (!joystick->is_gamepad) {
+ continue;
+ }
+
+ info = SDL_GetJoystickInstanceVirtualGamepadInfo(joystick->instance_id);
+ if (info) {
+ if (joystick->steam_handle != info->handle) {
+ joystick->steam_handle = info->handle;
+ changed = SDL_TRUE;
+ }
+ } else {
+ if (joystick->steam_handle != 0) {
+ joystick->steam_handle = 0;
+ changed = SDL_TRUE;
+ }
+ }
+ if (changed) {
+ SDL_Event event;
+
+ SDL_zero(event);
+ event.type = SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED;
+ event.common.timestamp = 0;
+ event.gdevice.which = joystick->instance_id;
+ SDL_PushEvent(&event);
+ }
+ }
+}
+
void SDL_UpdateJoysticks(void)
{
int i;
@@ -2212,6 +2286,10 @@ void SDL_UpdateJoysticks(void)
SDL_LockJoysticks();
+ if (SDL_UpdateSteamVirtualGamepadInfo()) {
+ SendSteamHandleUpdateEvents();
+ }
+
#ifdef SDL_JOYSTICK_HIDAPI
/* Special function for HIDAPI devices, as a single device can provide multiple SDL_Joysticks */
HIDAPI_UpdateDevices();
@@ -3083,18 +3161,38 @@ SDL_JoystickGUID SDL_GetJoystickInstanceGUID(SDL_JoystickID instance_id)
Uint16 SDL_GetJoystickInstanceVendor(SDL_JoystickID instance_id)
{
Uint16 vendor;
- SDL_JoystickGUID guid = SDL_GetJoystickInstanceGUID(instance_id);
+ const SDL_SteamVirtualGamepadInfo *info;
+
+ SDL_LockJoysticks();
+ info = SDL_GetJoystickInstanceVirtualGamepadInfo(instance_id);
+ if (info) {
+ vendor = info->vendor_id;
+ } else {
+ SDL_JoystickGUID guid = SDL_GetJoystickInstanceGUID(instance_id);
+
+ SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL, NULL);
+ }
+ SDL_UnlockJoysticks();
- SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL, NULL);
return vendor;
}
Uint16 SDL_GetJoystickInstanceProduct(SDL_JoystickID instance_id)
{
Uint16 product;
- SDL_JoystickGUID guid = SDL_GetJoystickInstanceGUID(instance_id);
+ const SDL_SteamVirtualGamepadInfo *info;
+
+ SDL_LockJoysticks();
+ info = SDL_GetJoystickInstanceVirtualGamepadInfo(instance_id);
+ if (info) {
+ product = info->product_id;
+ } else {
+ SDL_JoystickGUID guid = SDL_GetJoystickInstanceGUID(instance_id);
+
+ SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL, NULL);
+ }
+ SDL_UnlockJoysticks();
- SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL, NULL);
return product;
}
@@ -3141,18 +3239,38 @@ SDL_JoystickGUID SDL_GetJoystickGUID(SDL_Joystick *joystick)
Uint16 SDL_GetJoystickVendor(SDL_Joystick *joystick)
{
Uint16 vendor;
- SDL_JoystickGUID guid = SDL_GetJoystickGUID(joystick);
+ const SDL_SteamVirtualGamepadInfo *info;
+
+ SDL_LockJoysticks();
+ info = SDL_GetJoystickInstanceVirtualGamepadInfo(joystick->instance_id);
+ if (info) {
+ vendor = info->vendor_id;
+ } else {
+ SDL_JoystickGUID guid = SDL_GetJoystickGUID(joystick);
+
+ SDL_GetJoystickGUIDInfo(guid,
(Patch may be truncated, please check the link at the top of this post.)