SDL: Include the VID/PID of generic keyboard/mouse devices on Windows

From 281f0fae1cec348330080739417e5bfe13b18032 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Wed, 26 Feb 2025 12:53:39 -0800
Subject: [PATCH] Include the VID/PID of generic keyboard/mouse devices on
 Windows

---
 src/SDL_utils.c                       |  8 +++---
 src/SDL_utils_c.h                     |  2 +-
 src/joystick/SDL_joystick.c           |  2 +-
 src/video/windows/SDL_windowsevents.c | 37 ++++++++++++++++++---------
 4 files changed, 31 insertions(+), 18 deletions(-)

diff --git a/src/SDL_utils.c b/src/SDL_utils.c
index b66e3a7106fed..8d321430b274c 100644
--- a/src/SDL_utils.c
+++ b/src/SDL_utils.c
@@ -413,7 +413,7 @@ static int PrefixMatch(const char *a, const char *b)
     return matchlen;
 }
 
-char *SDL_CreateDeviceName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name)
+char *SDL_CreateDeviceName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name, const char *default_name)
 {
     static struct
     {
@@ -434,7 +434,7 @@ char *SDL_CreateDeviceName(Uint16 vendor, Uint16 product, const char *vendor_nam
         { "QANBA USA,LLC", "Qanba" },
         { "Unknown ", "" },
     };
-    char *name;
+    char *name = NULL;
     size_t i, len;
 
     if (!vendor_name) {
@@ -488,8 +488,8 @@ char *SDL_CreateDeviceName(Uint16 vendor, Uint16 product, const char *vendor_nam
             }
             break;
         }
-    } else {
-        name = SDL_strdup("Controller");
+    } else if (default_name) {
+        name = SDL_strdup(default_name);
     }
 
     if (!name) {
diff --git a/src/SDL_utils_c.h b/src/SDL_utils_c.h
index e8e98f241e9c3..5e0e8f519ebef 100644
--- a/src/SDL_utils_c.h
+++ b/src/SDL_utils_c.h
@@ -73,6 +73,6 @@ extern void SDL_SetObjectsInvalid(void);
 
 extern const char *SDL_GetPersistentString(const char *string);
 
-extern char *SDL_CreateDeviceName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name);
+extern char *SDL_CreateDeviceName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name, const char *default_name);
 
 #endif // SDL_utils_h_
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index 9221bce9cb5b9..7574adc6c0771 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -2553,7 +2553,7 @@ char *SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_n
         return SDL_strdup(custom_name);
     }
 
-    return SDL_CreateDeviceName(vendor, product, vendor_name, product_name);
+    return SDL_CreateDeviceName(vendor, product, vendor_name, product_name, "Controller");
 }
 
 SDL_GUID SDL_CreateJoystickGUID(Uint16 bus, Uint16 vendor, Uint16 product, Uint16 version, const char *vendor_name, const char *product_name, Uint8 driver_signature, Uint8 driver_data)
diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index 8e1ddd7d3c8e5..5e56816ed7ec8 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -861,8 +861,10 @@ static bool HasDeviceID(Uint32 deviceID, const Uint32 *list, int count)
 }
 
 #if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
-static char *GetDeviceName(HANDLE hDevice, HDEVINFO devinfo, const char *instance, bool hid_loaded)
+static char *GetDeviceName(HANDLE hDevice, HDEVINFO devinfo, const char *instance, const char *default_name, bool hid_loaded)
 {
+    char *vendor_name = NULL;
+    char *product_name = NULL;
     char *name = NULL;
 
     // These are 126 for USB, but can be longer for Bluetooth devices
@@ -870,6 +872,7 @@ static char *GetDeviceName(HANDLE hDevice, HDEVINFO devinfo, const char *instanc
     vend[0] = 0;
     prod[0] = 0;
 
+
     HIDD_ATTRIBUTES attr;
     attr.VendorID = 0;
     attr.ProductID = 0;
@@ -895,7 +898,13 @@ static char *GetDeviceName(HANDLE hDevice, HDEVINFO devinfo, const char *instanc
         }
     }
 
-    if (!prod[0]) {
+    if (vend[0]) {
+        vendor_name = WIN_StringToUTF8W(vend);
+    }
+
+    if (prod[0]) {
+        product_name = WIN_StringToUTF8W(prod);
+    } else {
         SP_DEVINFO_DATA data;
         SDL_zero(data);
         data.cbSize = sizeof(data);
@@ -922,21 +931,25 @@ static char *GetDeviceName(HANDLE hDevice, HDEVINFO devinfo, const char *instanc
                         size = (SDL_arraysize(prod) - 1);
                     }
                     prod[size] = 0;
+
+                    if (attr.VendorID || attr.ProductID) {
+                        SDL_asprintf(&product_name, "%S (0x%.4x/0x%.4x)", prod, attr.VendorID, attr.ProductID);
+                    } else {
+                        product_name = WIN_StringToUTF8W(prod);
+                    }
                 }
                 break;
             }
         }
     }
 
-    if (prod[0]) {
-        char *vendor_name = vend[0] ? WIN_StringToUTF8W(vend) : NULL;
-        char *product_name = WIN_StringToUTF8W(prod);
-        if (product_name) {
-            name = SDL_CreateDeviceName(attr.VendorID, attr.ProductID, vendor_name, product_name);
-        }
-        SDL_free(vendor_name);
-        SDL_free(product_name);
+    if (!product_name && (attr.VendorID || attr.ProductID)) {
+        SDL_asprintf(&product_name, "%s (0x%.4x/0x%.4x)", default_name, attr.VendorID, attr.ProductID);
     }
+    name = SDL_CreateDeviceName(attr.VendorID, attr.ProductID, vendor_name, product_name, default_name);
+    SDL_free(vendor_name);
+    SDL_free(product_name);
+
     return name;
 }
 
@@ -1029,7 +1042,7 @@ void WIN_CheckKeyboardAndMouseHotplug(SDL_VideoDevice *_this, bool initial_check
                 SDL_KeyboardID keyboardID = (Uint32)(uintptr_t)raw_devices[i].hDevice;
                 AddDeviceID(keyboardID, &new_keyboards, &new_keyboard_count);
                 if (!HasDeviceID(keyboardID, old_keyboards, old_keyboard_count)) {
-                    name = GetDeviceName(raw_devices[i].hDevice, devinfo, instance, hid_loaded);
+                    name = GetDeviceName(raw_devices[i].hDevice, devinfo, instance, "Keyboard", hid_loaded);
                     SDL_AddKeyboard(keyboardID, name, send_event);
                     SDL_free(name);
                 }
@@ -1040,7 +1053,7 @@ void WIN_CheckKeyboardAndMouseHotplug(SDL_VideoDevice *_this, bool initial_check
                 SDL_MouseID mouseID = (Uint32)(uintptr_t)raw_devices[i].hDevice;
                 AddDeviceID(mouseID, &new_mice, &new_mouse_count);
                 if (!HasDeviceID(mouseID, old_mice, old_mouse_count)) {
-                    name = GetDeviceName(raw_devices[i].hDevice, devinfo, instance, hid_loaded);
+                    name = GetDeviceName(raw_devices[i].hDevice, devinfo, instance, "Mouse", hid_loaded);
                     SDL_AddMouse(mouseID, name, send_event);
                     SDL_free(name);
                 }