SDL: Get the real GameInput device name if possible

From ae4aa2508288cab793818733668062fa02bc2ffb Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sat, 17 Feb 2024 20:10:41 -0800
Subject: [PATCH] Get the real GameInput device name if possible

---
 src/joystick/gdk/SDL_gameinputjoystick.c | 48 ++++++++++++------------
 1 file changed, 23 insertions(+), 25 deletions(-)

diff --git a/src/joystick/gdk/SDL_gameinputjoystick.c b/src/joystick/gdk/SDL_gameinputjoystick.c
index 5f744c1ec9d6..ee302305b5ea 100644
--- a/src/joystick/gdk/SDL_gameinputjoystick.c
+++ b/src/joystick/gdk/SDL_gameinputjoystick.c
@@ -34,7 +34,7 @@ typedef struct GAMEINPUT_InternalDevice
 {
     IGameInputDevice *device;
     char path[(APP_LOCAL_DEVICE_ID_SIZE * 2) + 1];
-    const char *name;         /* this is a constant string literal */
+    char *name;
     Uint16 vendor;
     Uint16 product;
     SDL_JoystickGUID guid;          /* generated by SDL */
@@ -75,6 +75,8 @@ static int GAMEINPUT_InternalAddOrFind(IGameInputDevice *pDevice)
     Uint16 vendor = 0;
     Uint16 product = 0;
     Uint16 version = 0;
+    const char *manufacturer_string = NULL;
+    const char *product_string = NULL;
     char tmp[4];
     int idx = 0;
 
@@ -111,18 +113,26 @@ static int GAMEINPUT_InternalAddOrFind(IGameInputDevice *pDevice)
         return SDL_OutOfMemory();
     }
 
-    /* generate a device name */
+    /* Generate a device path */
     for (idx = 0; idx < APP_LOCAL_DEVICE_ID_SIZE; ++idx) {
         SDL_snprintf(tmp, SDL_arraysize(tmp), "%02hhX", devinfo->deviceId.value[idx]);
         SDL_strlcat(elem->path, tmp, SDL_arraysize(tmp));
     }
 
+    if (devinfo->deviceStrings) {
+        /* In theory we could get the manufacturer and product strings here, but they're NULL for all the controllers I've tested */
+    }
+
+    if (devinfo->displayName) {
+        /* This could give us a product string, but it's NULL for all the controllers I've tested */
+    }
+
     IGameInputDevice_AddRef(pDevice);
     elem->device = pDevice;
-    elem->name = "GameInput Gamepad";
+    elem->name = SDL_CreateJoystickName(vendor, product, manufacturer_string, product_string);
     elem->vendor = vendor;
     elem->product = product;
-    elem->guid = SDL_CreateJoystickGUID(bus, vendor, product, version, "GameInput", "Gamepad", 'g', 0);
+    elem->guid = SDL_CreateJoystickGUID(bus, vendor, product, version, manufacturer_string, product_string, 'g', 0);
     elem->device_instance = SDL_GetNextObjectID();
     elem->wireless = (devinfo->capabilities & GameInputDeviceCapabilityWireless);
     elem->sensors_supported = (devinfo->supportedInput & GameInputKindMotion);
@@ -137,18 +147,20 @@ static int GAMEINPUT_InternalAddOrFind(IGameInputDevice *pDevice)
 static int GAMEINPUT_InternalRemoveByIndex(int idx)
 {
     GAMEINPUT_InternalDevice **devicelist = NULL;
+    GAMEINPUT_InternalDevice *elem;
     int bytes = 0;
 
     if (idx < 0 || idx >= g_GameInputList.count) {
         return SDL_SetError("GAMEINPUT_InternalRemoveByIndex argument idx %d is out of range", idx);
     }
 
-    IGameInputDevice_Release(g_GameInputList.devices[idx]->device);
-
-    if (g_GameInputList.devices[idx]) {
-        SDL_free(g_GameInputList.devices[idx]);
-        g_GameInputList.devices[idx] = NULL;
+    elem = g_GameInputList.devices[idx];
+    if (elem) {
+        IGameInputDevice_Release(elem->device);
+        SDL_free(elem->name);
+        SDL_free(elem);
     }
+    g_GameInputList.devices[idx] = NULL;
 
     if (g_GameInputList.count == 1) {
         /* last element in the list, free the entire list then */
@@ -159,13 +171,6 @@ static int GAMEINPUT_InternalRemoveByIndex(int idx)
             bytes = sizeof(*devicelist) * (g_GameInputList.count - idx);
             SDL_memmove(&g_GameInputList.devices[idx], &g_GameInputList.devices[idx + 1], bytes);
         }
-
-        devicelist = (GAMEINPUT_InternalDevice **)SDL_realloc(g_GameInputList.devices, sizeof(*devicelist) * (g_GameInputList.count - 1LL));
-        if (!devicelist) {
-            return SDL_OutOfMemory();
-        }
-
-        g_GameInputList.devices = devicelist;
     }
 
     /* decrement the count and return */
@@ -516,22 +521,15 @@ static void GAMEINPUT_JoystickClose(SDL_Joystick* joystick)
 
 static void GAMEINPUT_JoystickQuit(void)
 {
-    int idx;
-
     if (g_pGameInput) {
         /* free the callback */
         IGameInput_UnregisterCallback(g_pGameInput, g_GameInputCallbackToken, /*timeoutInUs:*/ 10000);
         g_GameInputCallbackToken = GAMEINPUT_INVALID_CALLBACK_TOKEN_VALUE;
 
         /* free the list */
-        for (idx = 0; idx < g_GameInputList.count; ++idx) {
-            IGameInputDevice_Release(g_GameInputList.devices[idx]->device);
-            SDL_free(g_GameInputList.devices[idx]);
-            g_GameInputList.devices[idx] = NULL;
+        while (g_GameInputList.count > 0) {
+            GAMEINPUT_InternalRemoveByIndex(0);
         }
-        SDL_free(g_GameInputList.devices);
-        g_GameInputList.devices = NULL;
-        g_GameInputList.count = 0;
 
         IGameInput_Release(g_pGameInput);
         g_pGameInput = NULL;