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

UWP中HidDevice.FromIdAsync仅Read模式可用,求解决方案及测试工具

HID设备UWP读写权限问题及替代测试方案咨询

问题描述

已确认HID设备具备读写能力(WPF应用中验证:一个端点仅支持读取,另一个支持读写),但在UWP中调用HidDevice.FromIdAsync打开设备时,仅FileAccessMode.Read模式能获取非null实例,ReadWrite模式始终返回null。已在Package.appxmanifest中配置多个Usage权限,问题仍未解决。同时咨询除SuperMUTT(350美元)外的其他HID测试方法。

代码实现

//This method will be called on the UI thread
private async Task OpenDevice()
{
    string aqs = HidDevice.GetDeviceSelector(0x0001, 0x0005, 0xAAAA, 0xBBBB);
    //Two Endpoints are returned here, one of which can only be opened by Read, and the other cannot be opened by Read or ReadWrite
    var devices = await DeviceInformation.FindAllAsync(aqs);
    foreach (var deviceInfo in devices)
    {
        var access = DeviceAccessInformation.CreateFromId(deviceInfo.Id);
        if (access.CurrentStatus == DeviceAccessStatus.Allowed)
        {
            var deviceWithReadWrite = await HidDevice.FromIdAsync(deviceInfo.Id, FileAccessMode.ReadWrite);
            //deviceWithReadWrite is null
            var deviceWithRead = await HidDevice.FromIdAsync(deviceInfo.Id, FileAccessMode.Read);
            //deviceWithRead is not null
        }
    }
}

Package.appxmanifest权限配置

<Capabilities>
    <DeviceCapability Name="humaninterfacedevice">
        <Device Id="any">
            <Function Type="usage:0001 *"/>
            <Function Type="usage:0009 *"/>
            <Function Type="usage:FF00 *"/>
            <Function Type="usage:FFF0 *"/>
            <Function Type="usage:FF80 *"/>
        </Device>
    </DeviceCapability>
</Capabilities> 

HID报告描述符

0x08,              // Usage
0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
0x09, 0x05,        // Usage (Game Pad)
0xA1, 0x01,        // Collection (Application)
0x85, 0x01,        //   Report ID (1)
0x09, 0x30,        //   Usage (X)
0x09, 0x31,        //   Usage (Y)
0x09, 0x32,        //   Usage (Z)
0x09, 0x35,        //   Usage (Rz)
0x15, 0x00,        //   Logical Minimum (0)
0x26, 0xFF, 0x00,  //   Logical Maximum (255)
0x75, 0x08,        //   Report Size (8)
0x95, 0x04,        //   Report Count (4)
0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x39,        //   Usage (Hat switch)
0x15, 0x00,        //   Logical Minimum (0)
0x25, 0x07,        //   Logical Maximum (7)
0x35, 0x00,        //   Physical Minimum (0)
0x46, 0x3B, 0x01,  //   Physical Maximum (315)
0x65, 0x14,        //   Unit (System: English Rotation, Length: Centimeter)
0x75, 0x04,        //   Report Size (4)
0x95, 0x01,        //   Report Count (1)
0x81, 0x42,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0x65, 0x00,        //   Unit (None)
0x05, 0x09,        //   Usage Page (Button)
0x19, 0x01,        //   Usage Minimum (0x01)
0x29, 0x11,        //   Usage Maximum (0x11)
0x15, 0x00,        //   Logical Minimum (0)
0x25, 0x01,        //   Logical Maximum (1)
0x75, 0x01,        //   Report Size (1)
0x95, 0x11,        //   Report Count (17)
0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF,  //   Usage Page (Vendor Defined 0xFF00)
0x09, 0x20,        //   Usage (0x20)
0x75, 0x03,        //   Report Size (3)
0x95, 0x01,        //   Report Count (1)
0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01,        //   Usage Page (Generic Desktop Ctrls)
0x09, 0x33,        //   Usage (Rx)
0x09, 0x34,        //   Usage (Ry)
0x15, 0x00,        //   Logical Minimum (0)
0x26, 0xFF, 0x00,  //   Logical Maximum (255)
0x75, 0x08,        //   Report Size (8)
0x95, 0x02,        //   Report Count (2)
0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF,  //   Usage Page (Vendor Defined 0xFF00)
0x09, 0x21,        //   Usage (0x21)
0x95, 0x36,        //   Report Count (54)
0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x85, 0x05,        //   Report ID (5)
0x09, 0x22,        //   Usage (0x22)
0x95, 0x1F,        //   Report Count (31)
0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x03,        //   Report ID (3)
0x0A, 0x21, 0x27,  //   Usage (0x2721)
0x95, 0x2F,        //   Report Count (47)
0xB1, 0x02,        //   Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x06, 0x80, 0xFF,  //   Usage Page (Vendor Defined 0xFF80)
0x85, 0xE0,        //   Report ID (-32)
0x09, 0x57,        //   Usage (0x57)
0x95, 0x02,        //   Report Count (2)
0xB1, 0x02,        //   Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0,              // End Collection
0x06, 0xF0, 0xFF,  // Usage Page (Vendor Defined 0xFFF0)
0x09, 0x40,        // Usage (0x40)
0xA1, 0x01,        // Collection (Application)
0x85, 0xF0,        //   Report ID (-16)
0x09, 0x47,        //   Usage (0x47)
0x95, 0x3F,        // Report Count (63)
0xB1, 0x02,        // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF1,        //   Report ID (-15)
0x09, 0x48,        //   Usage (0x48)
0x95, 0x3F,        // Report Count (63)
0xB1, 0x02,        // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF2,        //   Report ID (-14)
0x09, 0x49,        //   Usage (0x49)
0x95, 0x0F,        // Report Count (15)
0xB1, 0x02,        // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF3,        //   Report ID (-13)
0x0A, 0x01, 0x47,  //   Usage (0x4701)
0x95, 0x07,        // Report Count (7)
0xB1, 0x02,        // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x06, 0x00, 0xFF,  // Usage Page (Vendor Defined 0xFF00)
0x09, 0x00,        // Usage (0x00)
0x85, 0x10,        // Report ID (16)
0x15, 0x00,        // Logical Minimum (0)
0x25, 0xFF,        // Logical Maximum (-1)
0x35, 0x00,        // Physical Minimum (0)
0x45, 0xFF,        // Physical Maximum (-1)
0x75, 0x08,        // Report Size (8)
0x95, 0x3F,        // Report Count (63)
0x81, 0x02,        // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF,  // Usage Page (Vendor Defined 0xFF00)
0x09, 0x20,        // Usage (0x20)
0x85, 0xDD,        // Report ID (-35)
0x75, 0x08,        // Report Size (8)
0x95, 0x3F,        // Report Count (63)
0x81, 0x02,        // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x85, 0x0F,        // Report ID (15)
0x09, 0x22,        // Usage (0x22)
0x95, 0x3F,        // Report Count (63)
0x91, 0x02,        // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0,              // End Collection

问题分析与解决方案

1. ReadWrite模式返回null的原因排查

(1)端点匹配问题

UWP的HID API会将设备的每个HID集合视为单独的设备实例,你需要确认遍历到的deviceInfo是否对应支持读写的端点。可以打印deviceInfo.Name或deviceInfo.Properties中的设备细节来区分两个端点,避免误操作只读端点。

(2)权限配置遗漏

UWP的HID权限需要精确匹配报告描述符中的Usage Page和Usage组合,仅通配符可能无法覆盖所有必要权限。建议补充以下精确匹配的权限:

<Function Type="usage:0001 0005"/> <!-- Game Pad -->
<Function Type="usage:FF00 0020"/>
<Function Type="usage:FF00 0021"/>
<Function Type="usage:FF00 0022"/>
<Function Type="usage:FF80 0057"/>
<Function Type="usage:FFF0 0040"/>
<Function Type="usage:FFF0 0047"/>
<Function Type="usage:FFF0 0048"/>
<Function Type="usage:FFF0 0049"/>
<Function Type="usage:FFF0 4701"/>

同时确保Package.appxmanifest根节点添加了受限能力命名空间:

xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap mp rescap"

(3)设备独占访问冲突

如果有其他进程(如WPF测试应用)正在以读写模式占用设备,UWP会无法获取ReadWrite权限。测试时请关闭所有其他访问该设备的程序,再尝试打开。

(4)可写报告识别问题

UWP要求设备必须支持至少一个可写报告才能以ReadWrite模式打开。你可以在成功以Read模式打开设备后,通过deviceWithRead.OutputReportTypes属性确认是否识别到可写报告,若为空则说明UWP未正确解析设备的Output报告描述。

2. 替代SuperMUTT的HID测试方案

  • 低成本硬件模拟:
    • 用Arduino/ESP32开发板配合hidapi库编写固件,自定义HID报告描述符和读写逻辑,成本仅几十元,完全满足测试需求。
  • Windows内置工具:
    • 设备管理器:查看HID设备属性中的报告描述符,确认端点和报告类型。
    • hidtest.exe(Windows SDK自带,路径通常为C:\Program Files (x86)\Windows Kits\10\bin\<版本>\x64):直接测试HID设备的读写功能。
    • USB Device Viewer:详细查看USB设备的端点、接口和HID集合信息。
  • 第三方免费工具:
    • HID Explorer:可视化查看报告描述符,支持发送Output报告和接收Input报告。
    • USBlyzer/Wireshark(配合USBPcap):捕获HID通信数据包,分析设备交互逻辑。

内容的提问来源于stack exchange,提问作者Victor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 01:45:30