WebHID API: How do I parse data from inputReport event?

952 views Asked by At

I'm trying to grab sensor input from my digitizer ( X Tilt, Y Tilt, Tip Pressure, Tip Switch, Eraser, Pen, Puck .etc) using the WebHID API. This is what I've gotten so far:

index.js:

page_log = text => {
  let p = document.createElement("p");
  p.textContent = text;
  log.appendChild(p);
};

let device;

if (!("hid" in navigator)) {
  page_log("WebHID is not available yet.");
}

navigator.hid.getDevices().then(devices => {
  if (devices.length == 0) {
    page_log(`No HID devices selected. Press the "request device" button.`);
    return;
  }
  if (devices.length > 1) {
    page_log(`You have multiple devices.`);
  }
  device = devices[0];
  page_log(`User previously selected "${device.productName}" HID device.`);
  page_log(`Now press "open device" button to receive input reports.`);
});

requestDeviceButton.onclick = async event => {
  document.body.style.display = "none";
  try {
    const filters = [
      {
        vendorId: 0x056a, // Wacom Co., Ltd
        productId: 0x00b1 //PTZ-630 [Intuos3 (6x8)]
      },
      {
        vendorId: 0x056a, // Wacom Co., Ltd
        productId: 0x00b2 //PTZ-930 [Intuos3 (9x12)]
      },
      {
        vendorId: 0x056a, // Wacom Co., Ltd
        productId: 0x00b3 //PTZ-1230 [Intuos3 (12x12)]
      },
      {
        vendorId: 0x056a, // Wacom Co., Ltd
        productId: 0x00b4 //PTZ-1231W [Intuos3 (12x19)]
      },
    ];

    [device] = await navigator.hid.requestDevice({ filters });
    if (!device) return;

    page_log(`User selected "${device.productName}" HID device.`);
    page_log(`Now press "open device" button to receive input reports.`);
  } finally {
    document.body.style.display = "";
  }
};


openButton.onclick = async event => {
  if (!device) return;

  await device.open().catch(console.error);
  page_log(`Waiting for user to press button...`);

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

    let buffArray = new Uint8Array(data.buffer);
    console.log(buffArray);
    // console.log(device);
  
  });
};

console output:

index.js:72 Uint8Array(9) [224, 49, 125, 58, 74, 0, 35, 195, 85]
index.js:72 Uint8Array(9) [224, 49, 109, 58, 64, 0, 35, 194, 94]
index.js:72 Uint8Array(9) [224, 49, 94, 58, 43, 0, 35, 194, 102]
index.js:72 Uint8Array(9) [224, 49, 82, 58, 22, 0, 35, 193, 113]
index.js:72 Uint8Array(9) [224, 49, 52, 58, 1, 0, 35, 193, 123]
index.js:72 Uint8Array(9) [224, 49, 26, 57, 228, 0, 35, 192, 128]
index.js:72 Uint8Array(9) [224, 48, 253, 57, 190, 0, 35, 64, 141]
index.js:72 Uint8Array(9) [224, 48, 223, 57, 137, 0, 35, 65, 148]
index.js:72 Uint8Array(9) [224, 48, 203, 57, 90, 0, 35, 66, 159]
index.js:72 Uint8Array(9) [224, 48, 186, 57, 36, 0, 35, 66, 167]
index.js:72 Uint8Array(9) [224, 48, 177, 56, 242, 0, 35, 67, 174]
index.js:72 Uint8Array(9) [224, 48, 166, 56, 208, 0, 35, 196, 178]

How do I find out which sensor each number corresponds to?

I've tried reading WebHID spec and HID Usage Tables but I've so far been unable to locate the information I need to decipher the output.


Update:

I've tested in Windows after installing Wacom's official driver I get more data from the InputReport.

output: (Windows w/ wacom driver)

index.js:73 reportId: 15
index.js:76 Uint8Array(10) [2, 224, 55, 229, 45, 137, 0, 30, 176, 195]
index.js:73 reportId: 15
index.js:76 Uint8Array(21) [2, 224, 55, 163, 45, 99, 0, 31, 49, 189, 15, 2, 224, 55, 98, 45, 69, 0, 31, 49, 190]
index.js:73 reportId: 7
index.js:76 Uint8Array(37) [32, 29, 90, 238, 97, 50, 3, 0, 0, 34, 8, 16, 0, 87, 126, 112, 8, 34, 8, 16, 0, 0, 0, 0, 0, 0, 0, 212, 254, 192, 249, 232, 28, 184, 136, 0, 0]
index.js:73 reportId: 7
index.js:76 Uint8Array(37) [32, 241, 89, 197, 97, 30, 3, 0, 0, 34, 8, 16, 0, 87, 126, 112, 8, 34, 8, 16, 0, 0, 0, 0, 0, 0, 0, 56, 255, 36, 250, 76, 29, 228, 137, 0, 0]
index.js:73 reportId: 7
index.js:76 Uint8Array(37) [32, 162, 89, 144, 97, 30, 3, 0, 0, 34, 8, 16, 0, 87, 126, 112, 8, 34, 8, 16, 0, 0, 0, 0, 0, 0, 0, 56, 255, 36, 250, 76, 29, 228, 137, 0, 0]
index.js:73 reportId: 7
index.js:76 Uint8Array(37) [32, 136, 89, 123, 97, 22, 3, 0, 0, 34, 8, 16, 0, 87, 126, 112, 8, 34, 8, 16, 0, 0, 0, 0, 0, 0, 0, 56, 255, 36, 250, 76, 29, 228, 137, 0, 0]
index.js:73 reportId: 15
index.js:76 Uint8Array(10) [2, 224, 55, 34, 45, 31, 0, 31, 178, 185]
index.js:73 reportId: 15
index.js:76 Uint8Array(32) [2, 224, 54, 215, 45, 2, 0, 32, 50, 183, 15, 2, 224, 54, 139, 44, 226, 0, 32, 179, 183, 15, 2, 224, 54, 62, 44, 187, 0, 33, 52, 178]
index.js:73 reportId: 7
index.js:76 Uint8Array(37) [32, 27, 89, 51, 97, 14, 3, 0, 0, 34, 8, 16, 0, 87, 126, 112, 8, 34, 8, 16, 0, 0, 0, 0, 0, 0, 0, 156, 255, 136, 250, 176, 29, 16, 139, 0, 0]
index.js:73 reportId: 7
index.js:76 Uint8Array(37) [32, 171, 88, 237, 96, 6, 3, 0, 0, 34, 8, 16, 0, 87, 126, 112, 8, 34, 8, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 250, 176, 29, 0, 0, 0, 0]
index.js:73 reportId: 7
index.js:76 Uint8Array(37) [32, 53, 88, 163, 96, 254, 2, 0, 0, 34, 8, 16, 0, 87, 126, 112, 8, 34, 8, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 236, 250, 20, 30, 0, 0, 0, 0]
index.js:73 reportId: 15
index.js:76 Uint8Array(10) [2, 224, 53, 239, 44, 147, 0, 34, 54, 175]

Note: I've logged the reportId this time because I'm now getting 2 different ones.

I'm also noticing different data in the HIDDevice.collections object: devtools screenshot windows This time I'm getting something in one of my outputReports.

output: (Linux for comparison)

index.js:73 reportId: 2
index.js:74 Uint8Array(9) [224, 31, 174, 22, 67, 0, 38, 203, 177]
index.js:73 reportId: 2
index.js:74 Uint8Array(9) [224, 31, 33, 21, 8, 0, 39, 204, 180]
index.js:73 reportId: 2
index.js:74 Uint8Array(9) [224, 30, 165, 20, 8, 0, 40, 77, 183]
index.js:73 reportId: 2
index.js:74 Uint8Array(9) [224, 30, 16, 19, 51, 0, 40, 206, 182]
index.js:73 reportId: 2
index.js:74 Uint8Array(9) [224, 29, 134, 18, 97, 0, 41, 80, 181]
index.js:73 reportId: 2
index.js:74 Uint8Array(9) [224, 29, 9, 17, 191, 0, 39, 80, 183]
index.js:73 reportId: 2
index.js:74 Uint8Array(9) [224, 28, 210, 17, 27, 0, 36, 215, 184]
index.js:73 reportId: 2
index.js:74 Uint8Array(9) [224, 28, 225, 16, 150, 0, 35, 86, 186]
index.js:73 reportId: 2
index.js:74 Uint8Array(9) [224, 29, 45, 16, 15, 0, 33, 83, 184]
index.js:73 reportId: 2
index.js:74 Uint8Array(9) [224, 29, 162, 15, 153, 0, 32, 83, 190]
index.js:73 reportId: 2
index.js:74 Uint8Array(9) [224, 30, 110, 15, 51, 0, 32, 86, 195]
index.js:73 reportId: 2
index.js:74 Uint8Array(9) [224, 31, 96, 14, 214, 0, 31, 87, 199]
index.js:73 reportId: 2
index.js:74 Uint8Array(9) [160, 32, 212, 14, 142, 0, 26, 216, 202]

Also the HIDDevice.collections I get on linux: enter image description here

So I still don't understand how to map the data using either the featureReports, InputReports or OutputReports. So all I've figured out I get more HID data from Wacom's driver on Windows than linux.


Update 2:

I have been looking at the HIDDevice.collection Object on the Windows output and comparing it to Report Descriptors I get from running usbhid-dump with hidrd-convert (for making them human readable) on Linux. This is what I've found out so far.

  • It looks like all I need to look at is the inputReports element with the appropriate reportID as I'm only trying to read the sensor data being sent to the host.

  • I look at the array of items to see what data being sent by the report.

    • I look at the index number of the item in items to know the order to extract the data from the DataView (my data variable).
    • I look at reportCount and reportSize to know the shape of the data for that item in the DataView.
    • I look at the "Usage" each item to know what the data is for.
      • Unfortunately WebHID doesn't seem to expose "Usage" on a per item bases (Like my "Report Descriptors" from usbhid-dump shows). Instead it only exposes it on a per collection basis.
      • The "Usage" (if it was available) could be looked up in the HID Usage Tables by looking up the "Usage Page" by the hex value of usagePage for the collection, then doing the same for the given usage hex value.

Example:

    if (reportId !== 7) return;
    console.log('reportId: ' + reportId);
    let zero_through_six = data.getUint8(0);


    let report_data = [
      (zero_through_six & 128) == 128,  //0 (1-bit)
      (zero_through_six & 64) == 64,    //1 (1-bit)
      (zero_through_six & 32) == 32,    //2 (1-bit)
      (zero_through_six & 16) == 16,    //3 (1-bit)
      (zero_through_six & 8) == 8,      //4 (1-bit)
      (zero_through_six & 4) == 4,      //5 (1-bit)
      zero_through_six & 3,             //6 (2-bits)
      data.getUint16(1), //7
      data.getUint16(3), //8
      data.getUint16(5), //9
      data.getUint16(7), //10
      data.getUint32(9), //11
      data.getBigUint64(13), //12
      data.getUint32(21), //13
      data.getUint16(23), //14
      data.getUint16(25), //15
      data.getUint16(27), //16
      data.getUint16(29), //17
      data.getUint16(31), //18
      data.getUint16(33), //19
    ];

    console.log(report_data);

  });

This is something I did on the to split the data I was getting into and array on the Windows version. The first items[1-6] were 1-bit, items[7] 2-bits, items[7-10] 16-bits and so on.

Again, because WebHID doesn't expose "Usage" on a per item basis, the sensor/button each item is mapped to is still unknown. At least outside of simple testing each one individually, which is hard to do on such a complex device.

Update 3:

Turns out that I don't really need the WebHID API for my use case (getting sensor input from my digitizer). Looks like PointerEvent and MouseEvent properties cover my needs. (Really, should've look at that first actually (;一_一)) Atleast, I learned somewhat how to use the WebHID API.

1

There are 1 answers

0
François Beaufort On

I guess https://web.dev/devices-introduction/ would have been useful as it explains how to pick the appropriate API to communicate with a hardware device of your choice.

Glad you figured it out!