Crate hut

Source
Expand description

A wrapper around the HID Usage Tables (HUT).

In this document and unless stated otherwise, a reference to

This module is created through code generation from the HID Usage Tables.

§Terminology

See HID Section 5.5: a HID Usage is a 32 bit value comprising of a 16-bit Usage Page (MSB) and a 16-bit Usage ID (LSB) so that:

let usage: u32 = (usage_page << 16) | usage_id;

Note that the HID encoding requires little endian byte order on the wire.

In this module:

  • “Usage Page” refers to the 16-bit value. Where the Usage Page is converted to or from a 32-bit value the Usage Page is in the upper 16 bits of that value and the lower 16 bits are ignored or set to zero.
    let usage_page: u16 = (usage >> 16) as u16 & 0xffff;
  • “Usage ID” refers to the 16-bit value. Where the Usage ID is converted to or from a 32-bit value the Usage is in the lower 16 bits of that value and the upper 16 bits are ignored or set to zero.
    let usage_id: u16 = (usage & 0xffff) as u16;
  • “Usage” refers to the 32-bit value comprising a Usage Page and a Usage.

§Converting between types

All defined Usages and UsagePages implement AsUsagePage and (if applicable) AsUsage as well as the From<u16>, From<u32>, TryFrom<u16>, and TryFrom<u32> conversions so that:

let usage_page_value: u16 = 0x01; // Generic Desktop
let usage_id_value: u16 = 0x02; // Mouse
let usage_value: u32 = ((usage_page_value as u32) << 16) | usage_id_value as u32;

// Create a known Usage from a 32-bit value
let u: Usage = Usage::try_from(usage_value).unwrap();
assert!(matches!(u, Usage::GenericDesktop(GenericDesktop::Mouse)));

// Create a known Usage from the Usage Page and Usage ID values
let u2 = Usage::new_from_page_and_id(usage_page_value, usage_id_value).unwrap();
assert_eq!(u, u2);

// Create a known Usage from an individual Usage Page enum item
let u3 = Usage::from(GenericDesktop::Mouse);
assert_eq!(u, u3);

// Create a known Usage from an known Usage Page enum item
let gd_mouse = GenericDesktop::try_from(usage_id_value).unwrap();
let u4 = Usage::from(gd_mouse);
assert_eq!(u, u4);

// Convert to and fro the Usage either via u32 or the AsUsage trait
let u = GenericDesktop::Mouse;
assert_eq!(u32::from(&u), usage_value);
assert_eq!(u.usage_value(), usage_value);

// Extract the 16-bit Usage ID either via u16 or the AsUsage trait
assert_eq!(u16::from(&u), usage_id_value);
assert_eq!(u.usage_id_value(), usage_id_value);

// Extract the Usage Page from the Usage enum value
let up = u.usage_page();
assert!(matches!(up, UsagePage::GenericDesktop));
let up: UsagePage = UsagePage::from(&u);
assert!(matches!(up, UsagePage::GenericDesktop));

// Get the Usage Page numeric value is via the AsUsagePage
assert_eq!(u16::from(&up), usage_page_value);
assert_eq!(up.usage_page_value(), usage_page_value);

Naming Usages (e.g. GenericDesktop::Mouse) above works for Defined Usage Pages, Generated Usage Pages (see below) need to be destructured via their individual elements:

let usage_page_value: u16 = 0x09; // Button
let usage_id_value: u16 = 8; // Button number 8
let usage_value: u32 = ((usage_page_value as u32) << 16) | usage_id_value as u32;

let u = Usage::try_from(usage_value).unwrap();
let button = Usage::Button(Button::Button(8));
assert!(matches!(Usage::try_from(usage_value).unwrap(), button));
// or via from() or into()
let button: Usage = Button::Button(8).into();
assert!(matches!(Usage::try_from(usage_value).unwrap(), button));

Once a Usage is created, the AsUsagePage and AsUsage traits and conversion to and from u16 and u32 work the same as for a Defined Usage Page.

§Names of Usage Pages and Usage IDs

All defined Usages and UsagePages implement name() to return a string representing that page or usage:

let up = UsagePage::GenericDesktop;
assert_eq!(up.name(), "Generic Desktop");
let up = UsagePage::SimulationControls;
assert_eq!(up.name(), "Simulation Controls");

let usage = GenericDesktop::Mouse;
assert_eq!(usage.name(), "Mouse");
let usage = SimulationControls::CyclicControl;
assert_eq!(usage.name(), "Cyclic Control");

§Generated Usage Pages

The HUT differ between “Defined” and “Generated” Usage Pages. The former define Usage ID values and their meanings, the latter define a Usage ID range, with the actual Usage ID simply referring to “nth thing in this usage page”. One example for this is the Button Usage Page (0x09) where a Usage ID of 3 means “Button 3”.

let b = Button::Button(3);
let o = Ordinal::Ordinal(23);

Unlike Defined Usage Pages these Generated Usage Pages need to be destructured in match statements:

let b = Button::Button(3);
match b {
    Button::Button(b) => println!("Button {b}"),
    _ => {},
}

The following usage pages are Generated:

A further special case of this is the Unicode usage page which is not in the HUT document and was inserted during code generation.

§Vendor Defined Usage Pages (0xFF00 to 0xFFFF)

Vendor Defined Usage Pages and VendorUsages are not autogenerated and thus follow a different approach: the Usage inside the Usage Page is a simple numeric usage that needs to be destructured in match statements.

let v = Usage::VendorDefinedPage {
    vendor_page: VendorPage::try_from(0xff00 as u16).unwrap(),
    usage: VendorDefinedPage::VendorUsage { usage_id: 0x01 },
};
match v {
    Usage::VendorDefinedPage {
        vendor_page,
        usage,
    } => println!("Vendor Usage ID {usage}"),
    _ => {},
}

A notable exception is the Wacom (0xFF0D) which is technically a Vendor-defined page but with defined Usages. Converting from a UsagePage or Usage numeric value will produce the correct or Wacom Usage, not a VendorDefinedPage::VendorUsage.

§Reserved Usage Pages

Reserved Usage Pages and ReservedUsages are not autogenerated and thus follow a different approach: the Usage inside the Usage Page is a simple numeric usage that needs to be destructured in match statements.

Unlike the Vendor Defined Usage Pages a Reserved Usage Page may become a defined page in a later version of the HUT standard and thus in a future version of this crate. A caller must not rely on a Reserved Usage Page or Reserved Usage to remain so.

The following Usage Pages are reserved as of HUT 1.5 (see HUT Section 3, p15):

  • 0x13, 0x15-0x1F
  • 0x21-0x3F
  • 0x42-0x58
  • 0x5A-0x7F
  • 0x83-0x83
  • 0x86-0x8B
  • 0x8F-0x8F
  • 0x93-0xF1CF
  • 0xF1D1-0xFEFF

§Renames

For technical reasons, spaces, ( ), dashes (-), and slashes (/) are stripped out of Usage Page and Usage names. The string representation via the Display trait will have the unmodified value.

Structs§

ReservedPage
Represents a Reserved Page number value of in the current range of reserved values. See ReservedUsagePage.
VendorPage
Represents a Vendor Defined Page number value of in the range 0xFF00..=0xFFFF. See VendorDefinedPage.

Enums§

Arcade
Usage Page 0x91: “Arcade”
AuxiliaryDisplay
Usage Page 0x14: “Auxiliary Display”
BarcodeScanner
Usage Page 0x8C: “Barcode Scanner”
BatterySystem
Usage Page 0x85: “Battery System”
BrailleDisplay
Usage Page 0x41: “Braille Display”
Button
Usage Page 0x9: “Button”
CameraControl
Usage Page 0x90: “Camera Control”
Consumer
Usage Page 0xC: “Consumer”
Digitizers
Usage Page 0xD: “Digitizers”
EyeandHeadTrackers
Usage Page 0x12: “Eye and Head Trackers”
FIDOAlliance
Usage Page 0xF1D0: “FIDO Alliance”
GameControls
Usage Page 0x5: “Game Controls”
GenericDesktop
Usage Page 0x1: “Generic Desktop”
GenericDeviceControls
Usage Page 0x6: “Generic Device Controls”
Haptics
Usage Page 0xE: “Haptics”
HutError
Error raised if conversion between HUT elements fails.
KeyboardKeypad
Usage Page 0x7: “Keyboard/Keypad”
LED
Usage Page 0x8: “LED”
LightingAndIllumination
Usage Page 0x59: “Lighting And Illumination”
MagneticStripeReader
Usage Page 0x8E: “Magnetic Stripe Reader”
MedicalInstrument
Usage Page 0x40: “Medical Instrument”
Monitor
Usage Page 0x80: “Monitor”
MonitorEnumerated
Usage Page 0x81: “Monitor Enumerated”
Ordinal
Usage Page 0xA: “Ordinal”
PhysicalInputDevice
Usage Page 0xF: “Physical Input Device”
Power
Usage Page 0x84: “Power”
ReservedUsagePage
Reserved Usage Pages
Scales
Usage Page 0x8D: “Scales”
Sensors
Usage Page 0x20: “Sensors”
SimulationControls
Usage Page 0x2: “Simulation Controls”
SoC
Usage Page 0x11: “SoC”
SportControls
Usage Page 0x4: “Sport Controls”
TelephonyDevice
Usage Page 0xB: “Telephony Device”
Unicode
Usage Page 0x10: “Unicode”
Usage
An enum wrapping all known Usages in the HUT.
UsagePage
A HID UsagePage, see HID Section 5.5. This represents the upper 16 bits in the 32-bit Usage. Where a UsagePage is converted to or from 32 bit, the UsagePage value are the upper 16 bits only and the lower 16 bits are ignored or set to zero.
VESAVirtualControls
Usage Page 0x82: “VESA Virtual Controls”
VRControls
Usage Page 0x3: “VR Controls”
VendorDefinedPage
Usage Page 0xFF00 to 0xFFFF: The Vendor Defined Pages
Wacom
Usage Page 0xFF0D: “Wacom”

Traits§

AsUsage
A trait to return the Usage and Usage ID as numeric value
AsUsagePage
A trait to return the Usage Page as numeric value