Typed pure Python library to parse HID report descriptors
>>> import hid_parser >>> simple_mouse_rdesc_raw = [ ... 0x05, 0x01, # .Usage Page (Generic Desktop) 0 ... 0x09, 0x02, # .Usage (Mouse) 2 ... 0xa1, 0x01, # .Collection (Application) 4 ... 0x09, 0x02, # ..Usage (Mouse) 6 ... 0xa1, 0x02, # ..Collection (Logical) 8 ... 0x09, 0x01, # ...Usage (Pointer) 10 ... 0xa1, 0x00, # ...Collection (Physical) 12 ... 0x05, 0x09, # ....Usage Page (Button) 14 ... 0x19, 0x01, # ....Usage Minimum (1) 16 ... 0x29, 0x03, # ....Usage Maximum (3) 18 ... 0x15, 0x00, # ....Logical Minimum (0) 20 ... 0x25, 0x01, # ....Logical Maximum (1) 22 ... 0x75, 0x01, # ....Report Size (1) 24 ... 0x95, 0x03, # ....Report Count (3) 26 ... 0x81, 0x02, # ....Input (Data,Var,Abs) 28 ... 0x75, 0x05, # ....Report Size (5) 30 ... 0x95, 0x01, # ....Report Count (1) 32 ... 0x81, 0x03, # ....Input (Cnst,Var,Abs) 34 ... 0x05, 0x01, # ....Usage Page (Generic Desktop) 36 ... 0x09, 0x30, # ....Usage (X) 38 ... 0x09, 0x31, # ....Usage (Y) 40 ... 0x15, 0x81, # ....Logical Minimum (-127) 42 ... 0x25, 0x7f, # ....Logical Maximum (127) 44 ... 0x75, 0x08, # ....Report Size (8) 46 ... 0x95, 0x02, # ....Report Count (2) 48 ... 0x81, 0x06, # ....Input (Data,Var,Rel) 50 ... 0xc0, # ...End Collection 52 ... 0xc0, # ..End Collection 53 ... 0xc0, # .End Collection 54 ... ] >>> rdesc = hid_parser.ReportDescriptor(simple_mouse_rdesc_raw) >>> rdesc.get_input_report_size() 3bytes >>> for item in rdesc.get_input_items(): ... print(item) ... VariableItem(offset=0bits, size=1bit, usage=Usage(page=Button, usage=Button 1 (primary/trigger))) VariableItem(offset=1bit, size=1bit, usage=Usage(page=Button, usage=Button 2 (secondary))) VariableItem(offset=2bits, size=1bit, usage=Usage(page=Button, usage=Button 3 (tertiary))) PaddingItem(offset=3bits, size=5bits) VariableItem(offset=1byte, size=1byte, usage=Usage(page=Generic Desktop Controls, usage=X)) VariableItem(offset=2bytes, size=1byte, usage=Usage(page=Generic Desktop Controls, usage=Y)) >>> for usage, value in rdesc.parse_input_report([0b10100000, 0x50, 0x60]): ... print(f'{usage} = {value}') ... Usage(page=Button, usage=Button 2 (secondary)) = False Usage(page=Button, usage=Button 3 (tertiary)) = True Usage(page=Button, usage=Button 1 (primary/trigger)) = True Usage(page=Generic Desktop Controls, usage=X) = 80 Usage(page=Generic Desktop Controls, usage=Y) = 96
>>> import hid_parser >>> keyboard_rdesc_raw = [ ... 0x05, 0x01, # Usage Page (Generic Desktop) 0 ... 0x09, 0x06, # Usage (Keyboard) 2 ... 0xa1, 0x01, # Collection (Application) 4 ... 0x05, 0x07, # Usage Page (Keyboard) 6 ... 0x19, 0xe0, # Usage Minimum (224) 8 ... 0x29, 0xe7, # Usage Maximum (231) 10 ... 0x15, 0x00, # Logical Minimum (0) 12 ... 0x25, 0x01, # Logical Maximum (1) 14 ... 0x75, 0x01, # Report Size (1) 16 ... 0x95, 0x08, # Report Count (8) 18 ... 0x81, 0x02, # Input (Data,Var,Abs) 20 ... 0x95, 0x01, # Report Count (1) 22 ... 0x75, 0x08, # Report Size (8) 24 ... 0x81, 0x01, # Input (Cnst,Arr,Abs) 26 ... 0x95, 0x03, # Report Count (3) 28 ... 0x75, 0x01, # Report Size (1) 30 ... 0x05, 0x08, # Usage Page (LEDs) 32 ... 0x19, 0x01, # Usage Minimum (1) 34 ... 0x29, 0x03, # Usage Maximum (3) 36 ... 0x91, 0x02, # Output (Data,Var,Abs) 38 ... 0x95, 0x05, # Report Count (5) 40 ... 0x75, 0x01, # Report Size (1) 42 ... 0x91, 0x01, # Output (Cnst,Arr,Abs) 44 ... 0x95, 0x06, # Report Count (6) 46 ... 0x75, 0x08, # Report Size (8) 48 ... 0x15, 0x00, # Logical Minimum (0) 50 ... 0x26, 0xff, 0x00, # Logical Maximum (255) 52 ... 0x05, 0x07, # Usage Page (Keyboard) 55 ... 0x19, 0x00, # Usage Minimum (0) 57 ... 0x2a, 0xff, 0x00, # Usage Maximum (255) 59 ... 0x81, 0x00, # Input (Data,Arr,Abs) 62 ... 0xc0, # End Collection 64 ... ] >>> rdesc = hid_parser.ReportDescriptor(keyboard_rdesc_raw) >>> for item in rdesc.get_input_items(): ... print(item) ... VariableItem(offset=0bits, size=1bit, usage=Usage(page=Keyboard/Keypad, usage=Keyboard LeftControl)) VariableItem(offset=1bit, size=1bit, usage=Usage(page=Keyboard/Keypad, usage=Keyboard LeftShift)) VariableItem(offset=2bits, size=1bit, usage=Usage(page=Keyboard/Keypad, usage=Keyboard LeftAlt)) VariableItem(offset=3bits, size=1bit, usage=Usage(page=Keyboard/Keypad, usage=Keyboard Left GUI)) VariableItem(offset=4bits, size=1bit, usage=Usage(page=Keyboard/Keypad, usage=Keyboard RightControl)) VariableItem(offset=5bits, size=1bit, usage=Usage(page=Keyboard/Keypad, usage=Keyboard RightShift)) VariableItem(offset=6bits, size=1bit, usage=Usage(page=Keyboard/Keypad, usage=Keyboard RightAlt)) VariableItem(offset=7bits, size=1bit, usage=Usage(page=Keyboard/Keypad, usage=Keyboard Right GUI)) PaddingItem(offset=1byte, size=1byte) ArrayItem( offset=2bytes, size=1byte, count=6, usages=[ Usage(page=Keyboard/Keypad, usage=No event indicated), ... Usage(page=Keyboard/Keypad, usage=0x00ff), ], ) >>> for usage, value in rdesc.parse_input_report([0b10100101, 0x00, 0x04, 0x05, 0x06, 0x00, 0x00, 0x00]): ... print(f'{usage} = {value}') ... Usage(page=Keyboard/Keypad, usage=Keyboard Left GUI) = 0 Usage(page=Keyboard/Keypad, usage=Keyboard LeftAlt) = 1 Usage(page=Keyboard/Keypad, usage=Keyboard RightControl) = 0 Usage(page=Keyboard/Keypad, usage=Keyboard RightShift) = 1 Usage(page=Keyboard/Keypad, usage=Keyboard RightAlt) = 0 Usage(page=Keyboard/Keypad, usage=Keyboard Right GUI) = 1 Usage(page=Keyboard/Keypad, usage=Keyboard a and A) = True Usage(page=Keyboard/Keypad, usage=Keyboard b and B) = True Usage(page=Keyboard/Keypad, usage=Keyboard c and C) = True Usage(page=Keyboard/Keypad, usage=Keyboard LeftShift) = 0 Usage(page=Keyboard/Keypad, usage=Keyboard LeftControl) = 1
>>> import hid_parser >>> vendor_command_rdesc_raw = [ ... 0x06, 0x00, 0xff, # .Usage Page (Vendor Defined Page 1) 0 ... 0x09, 0x01, # .Usage (Vendor Usage 1) 3 ... 0xa1, 0x01, # .Collection (Application) 5 ... 0x85, 0x10, # ..Report ID (16) 7 ... 0x75, 0x08, # ..Report Size (8) 9 ... 0x95, 0x06, # ..Report Count (6) 11 ... 0x15, 0x00, # ..Logical Minimum (0) 12 ... 0x26, 0xff, 0x00, # ..Logical Maximum (255) 15 ... 0x09, 0x01, # ..Usage (Vendor Usage 1) 18 ... 0x81, 0x00, # ..Input (Data,Arr,Abs) 20 ... 0x09, 0x01, # ..Usage (Vendor Usage 1) 22 ... 0x91, 0x00, # ..Output (Data,Arr,Abs) 24 ... 0xc0, # .End Collection 26 ... ] >>> rdesc = hid_parser.ReportDescriptor(vendor_command_rdesc_raw) >>> rdesc.get_input_report_size(0x10) 6bytes >>> for item in rdesc.get_input_items(0x10): ... print(item) ... ArrayItem( offset=0bits, size=1byte, count=6, usages=[ Usage(page=Vendor Page, usage=0x0001), ], ) >>> for usage, value in rdesc.parse_input_report([0x10, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08])) ... print(f'{usage} = {value}') ... Usage(page=Vendor Page, usage=0x0001) = 257 Usage(page=Vendor Page, usage=0x0002) = 514 Usage(page=Vendor Page, usage=0x0003) = 771 Usage(page=Vendor Page, usage=0x0004) = 1028 Usage(page=Vendor Page, usage=0x0005) = 1285 Usage(page=Vendor Page, usage=0x0006) = 1542