如何通过Windows API将HID关联到物理输入设备?
解决单个物理输入设备对应多个HID的关联问题
你当前使用的GetRawInputDeviceList和GetRawInputDeviceInfo仅能获取输入设备的RawInput层面信息,无法直接关联到物理设备。要实现多个HID接口到同一物理设备的关联,必须结合SetupAPI或CfgMgr32系列Windows API来完成。
核心思路
单个物理设备的多个HID接口,在设备路径中共享相同的VID(厂商ID)和PID(产品ID),但拥有不同的MI(接口编号)。要准确关联,需通过设备接口获取其所属的父物理设备节点——同一物理设备的所有HID接口会指向同一个父节点。
具体实现步骤
从RawInput设备路径匹配设备接口
从GetRawInputDeviceInfo获取的RIDI_DEVICENAME(设备路径),使用SetupDiOpenDeviceInterface打开对应的HID设备接口。定位设备实例句柄
通过SetupDiGetDeviceInterfaceDetail获取设备的详细信息,再用CM_Locate_DevNode定位到该设备的实例句柄。追溯父物理设备
调用CM_Get_Parent获取当前HID接口的父设备句柄,再用CM_Get_Device_ID获取父设备的唯一ID。同一物理设备的所有HID接口会返回相同的父设备ID,以此作为关联依据。
代码片段示例
#include <setupapi.h> #include <initguid.h> #include <hidclass.h> // 从RawInput设备路径获取父设备ID BOOL GetParentDeviceId(LPCWSTR rawDevicePath, WCHAR* parentId, DWORD parentIdSize) { HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_HID, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (hDevInfo == INVALID_HANDLE_VALUE) return FALSE; SP_DEVICE_INTERFACE_DATA deviceInterfaceData = {0}; deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); // 枚举设备接口,找到匹配的路径 DWORD index = 0; while (SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_HID, index, &deviceInterfaceData)) { index++; // 获取接口详情所需缓冲区大小 DWORD requiredSize = 0; SetupDiGetDeviceInterfaceDetail(hDevInfo, &deviceInterfaceData, NULL, 0, &requiredSize, NULL); if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) continue; // 分配缓冲区 PSP_DEVICE_INTERFACE_DETAIL_DATA pDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, requiredSize); if (!pDetailData) continue; pDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); SP_DEVINFO_DATA devInfoData = {0}; devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); if (SetupDiGetDeviceInterfaceDetail(hDevInfo, &deviceInterfaceData, pDetailData, requiredSize, NULL, &devInfoData)) { // 匹配RawInput返回的设备路径 if (_wcsicmp(pDetailData->DevicePath, rawDevicePath) == 0) { // 定位设备节点 DEVINST devInst; if (CM_Locate_DevNode(&devInst, devInfoData.DevInst, CM_LOCATE_DEVNODE_NORMAL) == CR_SUCCESS) { // 获取父设备节点 DEVINST parentDevInst; if (CM_Get_Parent(&parentDevInst, devInst, 0) == CR_SUCCESS) { // 获取父设备ID if (CM_Get_Device_ID(parentDevInst, parentId, parentIdSize, 0) == CR_SUCCESS) { LocalFree(pDetailData); SetupDiDestroyDeviceInfoList(hDevInfo); return TRUE; } } } } } LocalFree(pDetailData); } SetupDiDestroyDeviceInfoList(hDevInfo); return FALSE; }
补充说明
- 你可以将每个HID接口的父设备ID作为分组标识,相同父ID的HID接口即属于同一物理设备。
- 编译时需链接
setupapi.lib和cfgmgr32.lib。
内容的提问来源于stack exchange,提问作者skifli
相关产品推荐
相关产品推荐

