You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Windows API将HID关联到物理输入设备?

解决单个物理输入设备对应多个HID的关联问题

你当前使用的GetRawInputDeviceList和GetRawInputDeviceInfo仅能获取输入设备的RawInput层面信息,无法直接关联到物理设备。要实现多个HID接口到同一物理设备的关联,必须结合SetupAPI或CfgMgr32系列Windows API来完成。

核心思路

单个物理设备的多个HID接口,在设备路径中共享相同的VID(厂商ID)和PID(产品ID),但拥有不同的MI(接口编号)。要准确关联,需通过设备接口获取其所属的父物理设备节点——同一物理设备的所有HID接口会指向同一个父节点。

具体实现步骤

  1. 从RawInput设备路径匹配设备接口
    从GetRawInputDeviceInfo获取的RIDI_DEVICENAME(设备路径),使用SetupDiOpenDeviceInterface打开对应的HID设备接口。

  2. 定位设备实例句柄
    通过SetupDiGetDeviceInterfaceDetail获取设备的详细信息,再用CM_Locate_DevNode定位到该设备的实例句柄。

  3. 追溯父物理设备
    调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 01:57:48