Skip to content

Commit

Permalink
use hidapi to get mouse/keyboard string
Browse files Browse the repository at this point in the history
  • Loading branch information
expikr authored and slouken committed Feb 21, 2025
1 parent 7855842 commit 3293eb1
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 5 deletions.
2 changes: 2 additions & 0 deletions src/core/windows/SDL_hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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");
Expand Down
2 changes: 2 additions & 0 deletions src/core/windows/SDL_hid.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,13 +191,15 @@ 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);
typedef NTSTATUS (WINAPI *HidP_GetValueCaps_t)(HIDP_REPORT_TYPE ReportType, PHIDP_VALUE_CAPS ValueCaps, PUSHORT ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData);
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;
Expand Down
109 changes: 104 additions & 5 deletions src/video/windows/SDL_windowsevents.c
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}
Expand All @@ -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);
}
}
Expand Down

0 comments on commit 3293eb1

Please sign in to comment.