From 3293eb1a162d99914c7737b8e7a3ea4d7a97e841 Mon Sep 17 00:00:00 2001
From: expikr <[EMAIL REDACTED]>
Date: Wed, 19 Feb 2025 02:57:43 +0800
Subject: [PATCH] use hidapi to get mouse/keyboard string
---
src/core/windows/SDL_hid.c | 2 +
src/core/windows/SDL_hid.h | 2 +
src/video/windows/SDL_windowsevents.c | 109 ++++++++++++++++++++++++--
3 files changed, 108 insertions(+), 5 deletions(-)
diff --git a/src/core/windows/SDL_hid.c b/src/core/windows/SDL_hid.c
index 98748154bc271..87e873544ab04 100644
--- a/src/core/windows/SDL_hid.c
+++ b/src/core/windows/SDL_hid.c
@@ -22,6 +22,7 @@
#include "SDL_hid.h"
+HidD_GetAttributes_t SDL_HidD_GetAttributes;
HidD_GetString_t SDL_HidD_GetManufacturerString;
HidD_GetString_t SDL_HidD_GetProductString;
HidP_GetCaps_t SDL_HidP_GetCaps;
@@ -50,6 +51,7 @@ bool WIN_LoadHIDDLL(void)
SDL_assert(s_HIDDLLRefCount == 0);
s_HIDDLLRefCount = 1;
+ SDL_HidD_GetAttributes = (HidD_GetAttributes_t)GetProcAddress(s_pHIDDLL, "HidD_GetAttributes");
SDL_HidD_GetManufacturerString = (HidD_GetString_t)GetProcAddress(s_pHIDDLL, "HidD_GetManufacturerString");
SDL_HidD_GetProductString = (HidD_GetString_t)GetProcAddress(s_pHIDDLL, "HidD_GetProductString");
SDL_HidP_GetCaps = (HidP_GetCaps_t)GetProcAddress(s_pHIDDLL, "HidP_GetCaps");
diff --git a/src/core/windows/SDL_hid.h b/src/core/windows/SDL_hid.h
index 8b20df11e54b6..46c22f243cff8 100644
--- a/src/core/windows/SDL_hid.h
+++ b/src/core/windows/SDL_hid.h
@@ -191,6 +191,7 @@ typedef struct
extern bool WIN_LoadHIDDLL(void);
extern void WIN_UnloadHIDDLL(void);
+typedef BOOLEAN (WINAPI *HidD_GetAttributes_t)(HANDLE HidDeviceObject, PHIDD_ATTRIBUTES Attributes);
typedef BOOLEAN (WINAPI *HidD_GetString_t)(HANDLE HidDeviceObject, PVOID Buffer, ULONG BufferLength);
typedef NTSTATUS (WINAPI *HidP_GetCaps_t)(PHIDP_PREPARSED_DATA PreparsedData, PHIDP_CAPS Capabilities);
typedef NTSTATUS (WINAPI *HidP_GetButtonCaps_t)(HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps, PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData);
@@ -198,6 +199,7 @@ typedef NTSTATUS (WINAPI *HidP_GetValueCaps_t)(HIDP_REPORT_TYPE ReportType, PHID
typedef ULONG (WINAPI *HidP_MaxDataListLength_t)(HIDP_REPORT_TYPE ReportType, PHIDP_PREPARSED_DATA PreparsedData);
typedef NTSTATUS (WINAPI *HidP_GetData_t)(HIDP_REPORT_TYPE ReportType, PHIDP_DATA DataList, PULONG DataLength, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength);
+extern HidD_GetAttributes_t SDL_HidD_GetAttributes;
extern HidD_GetString_t SDL_HidD_GetManufacturerString;
extern HidD_GetString_t SDL_HidD_GetProductString;
extern HidP_GetCaps_t SDL_HidP_GetCaps;
diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index af3407c407dc7..727f3a4e70dd7 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -861,7 +861,7 @@ static bool HasDeviceID(Uint32 deviceID, const Uint32 *list, int count)
}
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
-static void GetDeviceName(HDEVINFO devinfo, const char *instance, char *name, size_t len)
+static void GetDeviceName(HANDLE hDevice, HDEVINFO devinfo, const char *instance, char *name, size_t len)
{
name[0] = '\0';
@@ -883,9 +883,108 @@ static void GetDeviceName(HDEVINFO devinfo, const char *instance, char *name, si
if (SDL_strcasecmp(instance, DeviceInstanceId) == 0) {
SetupDiGetDeviceRegistryPropertyA(devinfo, &data, SPDRP_DEVICEDESC, NULL, (PBYTE)name, (DWORD)len, NULL);
- return;
+ break;
+ }
+ }
+
+ size_t desc_len = 0;
+ for (size_t i = 0; i < len; i++) {
+ if (name[i] == '\0') {
+ desc_len = i;
+ break;
}
}
+
+ char devName[MAX_PATH + 1];
+ devName[MAX_PATH] = '\0';
+ UINT devName_cap = MAX_PATH;
+ UINT devName_len = GetRawInputDeviceInfoA(hDevice, RIDI_DEVICENAME, devName, &devName_cap);
+ if (0 != ~devName_len) {
+ devName[devName_len] = '\0';
+ }
+
+ if (desc_len + 3 < len && WIN_LoadHIDDLL()) { // reference counted
+ // important: for devices with exclusive access mode as per
+ // https://learn.microsoft.com/en-us/windows-hardware/drivers/hid/top-level-collections-opened-by-windows-for-system-use
+ // they can only be opened with a desired access of none instead of generic read.
+ HANDLE hFile = CreateFileA(devName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+ if (hFile != INVALID_HANDLE_VALUE) {
+ HIDD_ATTRIBUTES attr;
+ WCHAR vend[128], prod[128];
+ attr.VendorID = 0;
+ attr.ProductID = 0;
+ attr.Size = sizeof(attr);
+ vend[0] = 0;
+ prod[0] = 0;
+ SDL_HidD_GetAttributes(hFile, &attr);
+ SDL_HidD_GetManufacturerString(hFile, vend, sizeof(vend));
+ SDL_HidD_GetProductString(hFile, prod, sizeof(prod));
+ CloseHandle(hFile);
+
+ size_t vend_len, prod_len;
+ for (vend_len = 0; vend_len < 128; vend_len++) {
+ if (vend[vend_len] == 0) {
+ break;
+ }
+ }
+ for (prod_len = 0; prod_len < 128; prod_len++) {
+ if (prod[prod_len] == 0) {
+ break;
+ }
+ }
+ if (vend_len > 0 || prod_len > 0) {
+ name[desc_len] = ' ';
+ name[desc_len+1] = '(';
+ size_t start = desc_len + 2;
+ size_t n = start;
+ for (size_t i = 0; i < vend_len; i++) {
+ n = start + i;
+ if (n < len) {
+ name[n] = (char)(vend[i] & 0x7f); // TODO: do proper WCHAR conversion
+ }
+ }
+ if (vend_len > 0) {
+ n += 1;
+ if (n < len) {
+ name[n] = ' ';
+ }
+ n += 1;
+ }
+ size_t m = n;
+ for (size_t i = 0; i < prod_len; i++) {
+ m = n + i;
+ if (m < len) {
+ name[m] = (char)(prod[i] & 0x7f); // TODO: do proper WCHAR conversion
+ }
+ }
+ {
+ m += 1;
+ if (m < len) {
+ name[m] = ')';
+ }
+ m += 1;
+ if (m < len) {
+ name[m] = '\0';
+ }
+ }
+ } else if (attr.VendorID && attr.ProductID) {
+ char buf[17];
+ int written = SDL_snprintf(buf, sizeof(buf), " (0x%.4x/0x%.4x)", attr.VendorID, attr.ProductID);
+ buf[16] = '\0'; // just to be safe
+ if (written > 0 && desc_len > 0) {
+ for (size_t i = 0; i < sizeof(buf); i++) {
+ size_t j = desc_len + i;
+ if (j < len) {
+ name[j] = buf[j];
+ }
+ }
+ }
+ }
+ }
+ WIN_UnloadHIDDLL();
+ }
+
+ name[len-1] = '\0'; // just to be safe
}
void WIN_CheckKeyboardAndMouseHotplug(SDL_VideoDevice *_this, bool initial_check)
@@ -938,7 +1037,7 @@ void WIN_CheckKeyboardAndMouseHotplug(SDL_VideoDevice *_this, bool initial_check
UINT nameSize = SDL_arraysize(devName);
int vendor = 0, product = 0;
DWORD dwType = raw_devices[i].dwType;
- char *instance, *ptr, name[64];
+ char *instance, *ptr, name[256];
if (dwType != RIM_TYPEKEYBOARD && dwType != RIM_TYPEMOUSE) {
continue;
@@ -976,7 +1075,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)) {
- GetDeviceName(devinfo, instance, name, sizeof(name));
+ GetDeviceName(raw_devices[i].hDevice, devinfo, instance, name, sizeof(name));
SDL_AddKeyboard(keyboardID, name, send_event);
}
}
@@ -986,7 +1085,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)) {
- GetDeviceName(devinfo, instance, name, sizeof(name));
+ GetDeviceName(raw_devices[i].hDevice, devinfo, instance, name, sizeof(name));
SDL_AddMouse(mouseID, name, send_event);
}
}