Skip to content

hid

stable

Encode and decode USB HID reports, parse HID report descriptors, and look up usage page names, usage names, and vendor identifiers.

use plugin hid::{encode_report, decode_report, usage_page_name, …}
11 functions Systems
/ filter jk navigate Esc clear
Functions (11)
  1. encode_report Prepend report ID to data bytes
  2. decode_report Split bytes into report ID and data
  3. usage_page_name Look up HID usage page name by ID
  4. usage_name Look up HID usage name by page and usage ID
  5. report_type_name Map report type integer to name string
  6. parse_short_item Parse one HID descriptor short item
  7. build_device_info Build a device info table from IDs and strings
  8. vendor_name Look up well-known USB vendor name by vendor ID
  9. parse_keyboard_report Parse an 8-byte standard keyboard HID report
  10. parse_mouse_report Parse a 3–4 byte standard mouse HID report
  11. parse_descriptor Parse all items from a full HID report descriptor

Overview

hid is a pure-data toolkit for working with the USB Human Interface Device protocol without touching any real hardware. It operates entirely on byte sequences and integers: you hand it the raw bytes of a report or a report descriptor and it gives you back plain Zolo tables, and it turns the magic numbers in the HID spec (usage pages, usages, vendor IDs, report types) into readable names. There is no stateful device handle to open or close — every function is a stand-alone, side-effect-free transform.

Use it whenever you are decoding captured HID traffic, building or inspecting report descriptors, presenting keyboard and mouse reports in human terms, or labelling a device from its vendor and product identifiers.

Common patterns

Decode a captured input report and label its parts:

use plugin hid::{decode_report, report_type_name}

let raw = [0x01, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00]
let r = decode_report(raw)
print("report id {r["id"]} ({report_type_name(1)})")

Turn a raw keyboard report into a readable description:

use plugin hid::{parse_keyboard_report}

let report = [0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00]
let kb = parse_keyboard_report(report)
if kb["modifiers"]["left_shift"] {
  print("shift held, keycode {kb["keys"][1]}")
}

Identify a device and name the usage page it reports on:

use plugin hid::{build_device_info, vendor_name, usage_page_name}

let dev = build_device_info(0x046D, 0xC52B, "Logitech", "Unifying Receiver")
print("{vendor_name(dev["vendor_id"])} {dev["product_hex"]}")
print("reports on: {usage_page_name(0x01)}")

Prepend report ID to data bytes

Prepends the report_id byte to data, producing a complete HID output report byte sequence (returned as bytes).

use plugin hid::{encode_report}

let report = encode_report(1, [0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00])
print(report.len())

Split bytes into report ID and data

Splits a raw HID report byte sequence into {id, data} where id is the first byte and data is the remainder.

use plugin hid::{encode_report, decode_report}

let raw = encode_report(2, [0x01, 0x00, 0x10])
let r = decode_report(raw)
print(r["id"])

Look up HID usage page name by ID

Returns the human-readable name of an HID usage page by its numeric ID, such as "Generic Desktop" (0x01) or "Keyboard/Keypad" (0x07).

use plugin hid::{usage_page_name}

print(usage_page_name(0x01))
print(usage_page_name(0x0C))

Look up HID usage name by page and usage ID

Returns the usage name for a given usage page and usage ID combination. Covers Generic Desktop axes, buttons, consumer controls, and LED indicators.

use plugin hid::{usage_name}

print(usage_name(0x01, 0x30))
print(usage_name(0x0C, 0xCD))

Any usage on the Button page (0x09) is named positionally, so button index 1 becomes "Button 1":

use plugin hid::{usage_name}

print(usage_name(0x09, 1))
print(usage_name(0x09, 5))

Map report type integer to name string

Maps a report type integer (1, 2, or 3) to its name: "Input", "Output", or "Feature".

use plugin hid::{report_type_name}

print(report_type_name(1))
print(report_type_name(3))

Parse one HID descriptor short item

Parses the first HID descriptor short item from bytes. Returns {type, tag, size, data} where type is "Main", "Global", or "Local" and tag is the item name.

use plugin hid::{parse_short_item}

let item = parse_short_item([0x05, 0x01])
print(item["type"])
print(item["tag"])

The two low bits of the prefix encode the data size, so a Usage Page item with a one-byte payload reports size 1 and carries that byte in data:

use plugin hid::{parse_short_item}

let item = parse_short_item([0x05, 0x01])
print("{item["tag"]} size={item["size"]}")

Build a device info table from IDs and strings

Builds a device info table containing vendor_id, product_id, vendor_hex, product_hex, manufacturer, and product fields.

use plugin hid::{build_device_info, vendor_name}

let dev = build_device_info(0x046D, 0xC52B, "Logitech", "Unifying Receiver")
print(dev["vendor_hex"])
print(vendor_name(dev["vendor_id"]))

Look up well-known USB vendor name by vendor ID

Returns the well-known company name for a USB vendor ID. Covers common vendors including Logitech, Microsoft, Apple, Sony, Razer, Arduino, and others.

use plugin hid::{vendor_name}

print(vendor_name(0x046D))
print(vendor_name(0x2341))

Parse an 8-byte standard keyboard HID report

Parses a standard 8-byte USB keyboard HID report. Returns {modifiers, modifiers_raw, keys} where modifiers has named boolean fields (left_ctrl, left_shift, etc.) and keys is a list of active keycodes.

use plugin hid::{parse_keyboard_report}

let report = [0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00]
let parsed = parse_keyboard_report(report)
print(parsed["modifiers"]["left_shift"])
print(parsed["keys"][1])

Parse a 3–4 byte standard mouse HID report

Parses a standard 3–4 byte USB mouse HID report. Returns {left, right, middle, buttons_raw, dx, dy, wheel}.

use plugin hid::{parse_mouse_report}

let report = [0x01, 0x05, 0xFF, 0x00]
let m = parse_mouse_report(report)
print(m["left"])
print(m["dx"])

The X and Y deltas are signed, so a high byte like 0xFF decodes as -1 rather than 255, and the optional fourth byte carries the scroll wheel:

use plugin hid::{parse_mouse_report}

let m = parse_mouse_report([0x00, 0xFF, 0x01, 0xFF])
print("dx {m["dx"]} dy {m["dy"]} wheel {m["wheel"]}")

Parse all items from a full HID report descriptor

Iterates all short items in a complete HID report descriptor byte sequence. Returns a list of items each with type, tag, size, value, data, and offset.

use plugin hid::{parse_descriptor}

let items = parse_descriptor(descriptor_bytes)
print(items[1]["tag"])
print(items[1]["value"])

Each item also carries the little-endian numeric value and its byte offset, so you can walk a short descriptor and label every entry by usage page name:

use plugin hid::{parse_descriptor, usage_page_name}

let items = parse_descriptor([0x05, 0x01, 0x09, 0x02])
print("{items[1]["tag"]} = {usage_page_name(items[1]["value"])}")
print("{items[2]["tag"]} at offset {items[2]["offset"]}")
enespt-br