WebHID API 如何在不发送输出报告的情况下获取输入报告

WebHID API How to get Input Report without sending Output Report

有没有办法使用 WebHID API 请求输入报告? API好像有直接读取Feature Report的功能,但是我不明白为什么要等事件来监听Input Report。根据我对输入报告的理解,主机 PC 必须触发获取报告的请求,我认为当我编写输出报告时它可以触发读取。打开设备也应该触发读取。

const dataView = await device.receiveFeatureReport(/* reportId= */ 1);

因为我知道我正在尝试读取的 ReportID 不是功能报告类型,所以此功能不起作用。

使用事件监听方法,我在打开设备或向输出报告写入报告后尝试触发输入报告时遇到问题。该设备是一个实现 USB HID 的 STM32L4x 设备。我没有问题向它写入输出报告,但我似乎无法触发读取输入报告事件。该事件似乎永远不会触发。与此 post 此处 () 的问题相同,但由于驱动程序安装要求,我不想切换到使用 WebUSB。

这与几个示例使用的事件侦听代码相同。

if (!device.opened) await device.open();

device.addEventListener("inputreport", event => {
  const { data, device, reportId } = event;

  if (device.productId !== 0x5751) return;

  const value = data.getUint8(0);
  if (value == 0) return;
 
  console.log(`Data: ${value}.`);
});

我可以通过 device.collections 进行交互以正确获取所有报告类型

for (let collection of device.collections) {
  // An HID collection includes usage, usage page, reports, and subcollections.

  msg += `Usage: ${collection.usage}` + "<br>";
  msg += `Usage page: ${collection.usagePage}`+ "<br>";

  for (let inputReport of collection.inputReports) {
    msg += `Input report: ${inputReport.reportId}`+ "<br>";
    // Loop through inputReport.items
  }

  for (let outputReport of collection.outputReports) {
    msg += `Output report: ${outputReport.reportId}`+ "<br>";
    // Loop through outputReport.items
  }

  for (let featureReport of collection.featureReports) {
    msg += `Feature report: ${featureReport.reportId}`+ "<br>";
    // Loop through featureReport.items
  }
}
showMessage(msg);

这是输出:

Usage: 1
Usage page: 255
Input report: 1
Input report: 3
Output report: 2
Output report: 4

我能找到的示例不多,可以让我直接获得输入报告而无需执行监听事件。也许我对 USB HID 报告的理解不完整,所以任何帮助将不胜感激。

我今天了解到,要触发输入报告事件,设备必须在中断请求期间发送输入报告,例如写入输出报告或执行连接之类的操作时。如果设备没有实现它,那么在事件期间没有任何内容作为输入报告返回。按照我的设备的工作方式,我必须使用传输控件来检索输入报告。这在 Windows 中不是问题,因为 HID.dll 具有输入报告请求功能。在 LibUSB 中也有一个可以与 Linux 和 MacOS 一起使用,get_input_report 的实现如下:

int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length)
{
int res = -1;
int skipped_report_id = 0;
int report_number = data[0];

if (report_number == 0x0) {
    /* Offset the return buffer by 1, so that the report ID
       will remain in byte 0. */
    data++;
    length--;
    skipped_report_id = 1;
}
res = libusb_control_transfer(dev->device_handle,
    LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_IN,
    0x01/*HID get_report*/,
    (1/*HID Input*/ << 8) | report_number,
    dev->interface,
    (unsigned char *)data, length,
    1000/*timeout millis*/);

if (res < 0)
    return -1;

if (skipped_report_id)
    res++;

return res;
}

不幸的是,我似乎无法找到一种方法让当前版本的 WebHID 使用 low-level 传输控制函数调用来复制它。在 WebHID 实现某种“get_input_report”方法之前,我想我暂时不走运。我们可能不得不转向功能报告,因为 WebHID 实现了 receiveFeatureReport 函数。

根据我们对 WebHID GitHub 未解决问题的讨论,我们的硬件可能无法根据标准正确实现 USB HID。因此,在固件上工作以正确实现 USB HID 标准比尝试使用 get_report 功能绕过正常方法更有意义。

关闭此问题。