diff --git a/src/core/windows/SDL_hid.c b/src/core/windows/SDL_hid.c index 98748154bc..87e873544a 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 8b20df11e5..46c22f243c 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 af3407c407..727f3a4e70 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); } }