WebHID: no compatible device found, but device shows up in Chrome device log?

4.5k views Asked by At

For starters I used navigator.hid.requestDevice without any filters. So I can see which devices are available before adding a custom filter, but my device doesn't show up in the HID browser device picker.

enter image description here

However, in the chrome device log chrome://device-log/ I can see connection/disconnection events for the device with both HID and USB labels:

enter image description here

I don't think this device is on the block list, so I'm not really sure why it's not showing up as an option when requesting HID devices. It shows up in Windows in the Device Manager under HID category as well.

If I use navigator.usb then the device does show up when requested, but when opened the device gets a Security Error, which possibly means it needs WinUSB driver. It's a HID USB device and works with libs outside of WebHID and WebUSB.

Any reasons it's not showing up?

Edit 1:

My device showed up in chrome://usb-internals/ where I see that it says HID is blocked by WebUSB. Not sure how to solve this yet.

enter image description here

Edit 2:

Using Chrome Canary and the devtools console provided a debug message when using the HID Device picker: Chooser dialog is not displaying a device blocked by the HID blocklist: vendorId=7992, productId=258, name='TEST', serial=''

Looking at the HID blocklist https://github.com/WICG/webhid/blob/main/blocklist.txt I still don't see an issue with the vendor id or product id. The usage page and usage don't match either, but the debug message doesn't mention those, so it's hard to say the exact reason.

Edit 3:

With chrome canary 103.0.5034.0 the new output gives this reason this device is blocked:

Chooser dialog is not displaying a device blocked by the HID blocklist: vendorId=7992, productId=258, name='TEST', serial='', numberOfCollections=1, numberOfProtectedInputReports=0, numberOfProtectedOutputReports=0, numberOfProtectedFeatureReports=0
2

There are 2 answers

1
karamazovbros On BEST ANSWER

I want to give an extra thanks to François Beaufort for pointing me in the right direction and adding debug logs to Chrome Canary specifically for WebHID testing.

The issue was that WebHID saw the number of input and output reports both as 0 and blocked the device from appearing in the HID device picker. Again, the device I was using works natively on Windows, so this issue was hidden until working with WebHID.

The exact issue was in the HID descriptor of the device firmware in the input & output sections of the HID descriptor. While I can't share the whole descriptor the input and output sections look as follows for the fix:

0x81, 0x00, // INPUT (Data, Var, Abs)
...
...
...
0x91, 0x01, // OUTPUT (Data, Var, Abs)

The first values 0x81 and 0x91 were correct, but the 2nd values needed to be changed to the above values to work. Once the firmware was modified the device immediately displayed using the WebHID device picker. Communication is working fine with WebHID now and the device still works natively on Windows as well.

21
François Beaufort On

If you're seeing it in the browser picker when you don't define any filters, it means this device is not blocklisted indeed.

I'd recommend you grab information such as vendorId and productId from https://nondebug.github.io/webhid-explorer/ for instance. After you connect your device, check out vendorId and productId info and use them as filters:

const filters = [{ vendorId: 0x1234, productId: 0x5678 }];

const [device] = await navigator.hid.requestDevice({ filters });

More generally, https://web.dev/hid/ is a great resource to get started with WebHID.

Edit 1

If you're not seeing your device in the browser picker when you don't have any filters but see "HID device added" in about:device-log, it means the browser picker is hiding it (either because it has a top-level collection with a FIDO usage or is blocklisted (https://github.com/WICG/webhid/blob/main/blocklist.txt). See Chromium source code at chrome/browser/ui/hid/hid_chooser_controller.cc:


bool HidChooserController::DisplayDevice(
    const device::mojom::HidDeviceInfo& device) const {
  // Check if `device` has a top-level collection with a FIDO usage. FIDO
  // devices may be displayed if the origin is privileged or the blocklist is
  // disabled.
  const bool has_fido_collection =
      base::Contains(device.collections, device::mojom::kPageFido,
                     [](const auto& c) { return c->usage->usage_page; });
  if (has_fido_collection) {
    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
            switches::kDisableHidBlocklist) ||
        (chooser_context_ &&
         chooser_context_->IsFidoAllowedForOrigin(origin_))) {
      return FilterMatchesAny(device) && !IsExcluded(device);
    }
    VLOG(1) << "Not displaying a FIDO HID device.";
    return false;
  }

  if (!device::HidBlocklist::IsDeviceExcluded(device))
    return FilterMatchesAny(device) && !IsExcluded(device);

  VLOG(1) << "Not displaying a device blocked by the HID blocklist.";
  return false;
}

Edit 2

Note that it is possible your device is blocklisted if it doesn't have any collection. See HidBlocklist::IsDeviceExcluded() source code. Is that the case?

By the way, it is possible to disable the HID blocklist by running Chrome with a special flag:

$ chrome --disable-hid-blocklist

See Run Chromium with flags page.