SDL: Added Steam Virtual Gamepad support to the GameInput driver (ebba6)

From ebba656bdbb634e590a4be8e3e847fa26dcd9803 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 24 Jul 2025 10:35:38 -0700
Subject: [PATCH] Added Steam Virtual Gamepad support to the GameInput driver

(cherry picked from commit 66dad9c21f62db17bfde2a8b6f3debb18f6e1e79)
---
 src/joystick/gdk/SDL_gameinputjoystick.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/src/joystick/gdk/SDL_gameinputjoystick.c b/src/joystick/gdk/SDL_gameinputjoystick.c
index 6cf0a902b7f17..1e729b93528cd 100644
--- a/src/joystick/gdk/SDL_gameinputjoystick.c
+++ b/src/joystick/gdk/SDL_gameinputjoystick.c
@@ -46,6 +46,7 @@ typedef struct GAMEINPUT_InternalDevice
     SDL_GUID guid;          // generated by SDL
     SDL_JoystickID device_instance; // generated by SDL
     const GameInputDeviceInfo *info;
+    int steam_virtual_gamepad_slot;
     bool isAdded;
     bool isDeleteRequested;
 } GAMEINPUT_InternalDevice;
@@ -77,6 +78,16 @@ static bool GAMEINPUT_InternalIsGamepad(const GameInputDeviceInfo *info)
     return false;
 }
 
+static int GetSteamVirtualGamepadSlot(const char *device_path)
+{
+    int slot = -1;
+
+    // The format for the raw input device path is documented here:
+    // https://partner.steamgames.com/doc/features/steam_controller/steam_input_gamepad_emulation_bestpractices
+    (void)SDL_sscanf(device_path, "\\\\.\\pipe\\HID#VID_045E&PID_028E&IG_00#%*X&%*X&%*X#%d#%*u", &slot);
+    return slot;
+}
+
 static bool GAMEINPUT_InternalAddOrFind(IGameInputDevice *pDevice)
 {
     GAMEINPUT_InternalDevice **devicelist = NULL;
@@ -147,6 +158,7 @@ static bool GAMEINPUT_InternalAddOrFind(IGameInputDevice *pDevice)
     elem->guid = SDL_CreateJoystickGUID(bus, vendor, product, version, manufacturer_string, product_string, 'g', 0);
     elem->device_instance = SDL_GetNextObjectID();
     elem->info = info;
+    elem->steam_virtual_gamepad_slot = GetSteamVirtualGamepadSlot(info->pnpPath);
 
     g_GameInputList.devices = devicelist;
     g_GameInputList.devices[g_GameInputList.count++] = elem;
@@ -333,7 +345,7 @@ static const char *GAMEINPUT_JoystickGetDevicePath(int device_index)
 
 static int GAMEINPUT_JoystickGetDeviceSteamVirtualGamepadSlot(int device_index)
 {
-    return -1;
+    return GAMEINPUT_InternalFindByIndex(device_index)->steam_virtual_gamepad_slot;
 }
 
 static int GAMEINPUT_JoystickGetDevicePlayerIndex(int device_index)