Merge pull request #3026 from FoamyGuy/usb_host_keyboard_examples

usb host keyboard examples
This commit is contained in:
foamyguy 2025-04-24 08:07:13 -05:00 committed by GitHub
commit 7d22755433
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 850 additions and 1 deletions

View file

@ -78,7 +78,7 @@ class Game:
self._loading_group = displayio.Group() self._loading_group = displayio.Group()
self._tile_size = 24 # Default tile size (length and width) self._tile_size = 24 # Default tile size (length and width)
self._digit_dims = (0, 0) self._digit_dims = (0, 0)
self._gamelogic = GameLogic(data_file, audio) self._gamelogic = GameLogic(data_file, audio) # pylint: disable=too-many-function-args
self._databuffer = DataBuffer() self._databuffer = DataBuffer()
self._color_index = {} self._color_index = {}
self._init_display() self._init_display()

View file

@ -0,0 +1,110 @@
// SPDX-FileCopyrightText: 2024 Ha Thach for Adafruit Industries
//
// SPDX-License-Identifier: MIT
/*********************************************************************
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
MIT license, check LICENSE for more information
Copyright (c) 2019 Ha Thach for Adafruit Industries
All text above, and the splash screen below must be included in
any redistribution
*********************************************************************/
#ifndef USBH_HELPER_H
#define USBH_HELPER_H
#ifdef ARDUINO_ARCH_RP2040
// pio-usb is required for rp2040 host
#include "pio_usb.h"
// Pin D+ for host, D- = D+ + 1
#ifndef PIN_USB_HOST_DP
#define PIN_USB_HOST_DP 16
#endif
// Pin for enabling Host VBUS. comment out if not used
#ifndef PIN_5V_EN
#define PIN_5V_EN 18
#endif
#ifndef PIN_5V_EN_STATE
#define PIN_5V_EN_STATE 1
#endif
#endif // ARDUINO_ARCH_RP2040
#ifdef ARDUINO_ARCH_RP2350
// pio-usb is required for rp2040 host
#include "pio_usb.h"
// Pin D+ for host, D- = D+ + 1
#ifndef PIN_USB_HOST_DP
#define PIN_USB_HOST_DP 32
#endif
// Pin for enabling Host VBUS. comment out if not used
#ifndef PIN_5V_EN
#define PIN_5V_EN 29
#endif
#ifndef PIN_5V_EN_STATE
#define PIN_5V_EN_STATE 1
#endif
#endif // ARDUINO_ARCH_RP2350
#include "Adafruit_TinyUSB.h"
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
// USB Host using MAX3421E: SPI, CS, INT
#include "SPI.h"
#if defined(ARDUINO_METRO_ESP32S2)
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
Adafruit_USBH_Host USBHost(&SPI, 33, 15);
#else
// Default CS and INT are pin 10, 9
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
#endif
#else
// Native USB Host such as rp2040
Adafruit_USBH_Host USBHost;
#endif
//--------------------------------------------------------------------+
// Helper Functions
//--------------------------------------------------------------------+
#ifdef ARDUINO_ARCH_RP2040
static void rp2040_configure_pio_usb(void) {
//while ( !Serial ) delay(10); // wait for native usb
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
#ifdef PIN_5V_EN
pinMode(PIN_5V_EN, OUTPUT);
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
#endif
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.pin_dp = PIN_USB_HOST_DP;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
// For pico-w, PIO is also used to communicate with cyw43
// Therefore we need to alternate the pio-usb configuration
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
pio_cfg.sm_tx = 3;
pio_cfg.sm_rx = 2;
pio_cfg.sm_eop = 3;
pio_cfg.pio_rx_num = 0;
pio_cfg.pio_tx_num = 1;
pio_cfg.tx_ch = 9;
#endif
USBHost.configure_pio_usb(1, &pio_cfg);
}
#endif
#endif

View file

@ -0,0 +1,222 @@
// SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
//
// SPDX-License-Identifier: MIT
/*********************************************************************
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
MIT license, check LICENSE for more information
Copyright (c) 2019 Ha Thach for Adafruit Industries
All text above, and the splash screen below must be included in
any redistribution
*********************************************************************/
/* This example demonstrates use of usb host with a standard HID boot keyboard.
* - Host depends on MCU:
* - rp2040: bit-banging 2 GPIOs with Pico-PIO-USB library (roothub port1)
*
* Requirements:
* - For rp2040:
* - Pico-PIO-USB library
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
* - Provide VBus (5v) and GND for peripheral
*/
// USBHost is defined in usbh_helper.h
#include "usbh_helper.h"
#include "tusb.h"
#include "Adafruit_TinyUSB.h"
bool printed_blank = false;
void setup() {
Serial.begin(115200);
// configure pio-usb: defined in usbh_helper.h
rp2040_configure_pio_usb();
// run host stack on controller (rhport) 1
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
// host bit-banging processing works done in core1 to free up core0 for other works
USBHost.begin(1);
delay(3000);
Serial.print("USB D+ Pin:");
Serial.println(PIN_USB_HOST_DP);
Serial.print("USB 5V Pin:");
Serial.println(PIN_5V_EN);
}
void loop() {
USBHost.task();
Serial.flush();
}
//--------------------------------------------------------------------+
// HID Host Callback Functions
//--------------------------------------------------------------------+
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len)
{
Serial.printf("HID device mounted (address %d, instance %d)\n", dev_addr, instance);
// Start receiving HID reports
if (!tuh_hid_receive_report(dev_addr, instance))
{
Serial.printf("Error: cannot request to receive report\n");
}
}
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
{
Serial.printf("HID device unmounted (address %d, instance %d)\n", dev_addr, instance);
}
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {
if (len > 0){
//debug print report data
// Serial.print("Report data: ");
// for (int i = 0; i < len; i++) {
// Serial.print(report[i], HEX);
// Serial.print(" ");
// }
// Serial.println();
printKeyboardReport(report);
}
// Continue to receive the next report
if (!tuh_hid_receive_report(dev_addr, instance)) {
Serial.println("Error: cannot request to receive report");
}
}
// Helper function to print key names
void printKeyName(uint8_t key) {
// This is a simplified list. Full HID keyboard has many more key codes
switch (key) {
case 0x04: Serial.print("A"); break;
case 0x05: Serial.print("B"); break;
case 0x06: Serial.print("C"); break;
case 0x07: Serial.print("D"); break;
case 0x08: Serial.print("E"); break;
case 0x09: Serial.print("F"); break;
case 0x0A: Serial.print("G"); break;
case 0x0B: Serial.print("H"); break;
case 0x0C: Serial.print("I"); break;
case 0x0D: Serial.print("J"); break;
case 0x0E: Serial.print("K"); break;
case 0x0F: Serial.print("L"); break;
case 0x10: Serial.print("M"); break;
case 0x11: Serial.print("N"); break;
case 0x12: Serial.print("O"); break;
case 0x13: Serial.print("P"); break;
case 0x14: Serial.print("Q"); break;
case 0x15: Serial.print("R"); break;
case 0x16: Serial.print("S"); break;
case 0x17: Serial.print("T"); break;
case 0x18: Serial.print("U"); break;
case 0x19: Serial.print("V"); break;
case 0x1A: Serial.print("W"); break;
case 0x1B: Serial.print("X"); break;
case 0x1C: Serial.print("Y"); break;
case 0x1D: Serial.print("Z"); break;
case 0x1E: Serial.print("1"); break;
case 0x1F: Serial.print("2"); break;
case 0x20: Serial.print("3"); break;
case 0x21: Serial.print("4"); break;
case 0x22: Serial.print("5"); break;
case 0x23: Serial.print("6"); break;
case 0x24: Serial.print("7"); break;
case 0x25: Serial.print("8"); break;
case 0x26: Serial.print("9"); break;
case 0x27: Serial.print("0"); break;
case 0x28: Serial.print("ENTER"); break;
case 0x29: Serial.print("ESC"); break;
case 0x2A: Serial.print("BACKSPACE"); break;
case 0x2B: Serial.print("TAB"); break;
case 0x2C: Serial.print("SPACE"); break;
case 0x2D: Serial.print("MINUS"); break;
case 0x2E: Serial.print("EQUAL"); break;
case 0x2F: Serial.print("LBRACKET"); break;
case 0x30: Serial.print("RBRACKET"); break;
case 0x31: Serial.print("BACKSLASH"); break;
case 0x33: Serial.print("SEMICOLON"); break;
case 0x34: Serial.print("QUOTE"); break;
case 0x35: Serial.print("GRAVE"); break;
case 0x36: Serial.print("COMMA"); break;
case 0x37: Serial.print("PERIOD"); break;
case 0x38: Serial.print("SLASH"); break;
case 0x39: Serial.print("CAPS_LOCK"); break;
case 0x4F: Serial.print("RIGHT_ARROW"); break;
case 0x50: Serial.print("LEFT_ARROW"); break;
case 0x51: Serial.print("DOWN_ARROW"); break;
case 0x52: Serial.print("UP_ARROW"); break;
default:
if (key >= 0x3A && key <= 0x45) { // F1-F12
Serial.print("F");
Serial.print(key - 0x3A + 1);
} else {
// For keys not handled above, just print the HID code
Serial.print("0x");
Serial.print(key, HEX);
}
break;
}
}
void printKeyboardReport(uint8_t const* report) {
// First byte contains modifier keys
uint8_t modifiers = report[0];
// Print modifier keys if pressed
if (modifiers > 0) {
Serial.print("Modifiers: ");
if (modifiers & 0x01) Serial.print("LEFT_CTRL ");
if (modifiers & 0x02) Serial.print("LEFT_SHIFT ");
if (modifiers & 0x04) Serial.print("LEFT_ALT ");
if (modifiers & 0x08) Serial.print("LEFT_GUI ");
if (modifiers & 0x10) Serial.print("RIGHT_CTRL ");
if (modifiers & 0x20) Serial.print("RIGHT_SHIFT ");
if (modifiers & 0x40) Serial.print("RIGHT_ALT ");
if (modifiers & 0x80) Serial.print("RIGHT_GUI ");
Serial.println();
}
// Second byte is reserved (usually 0)
// Bytes 2-7 contain up to 6 key codes
bool keysPressed = false;
for (int i = 2; i < 8; i++) {
uint8_t key = report[i];
// Skip if no key or error rollover
if (key == 0 || key == 1) {
continue;
}
if (!keysPressed) {
Serial.print("Keys: ");
keysPressed = true;
}
// Print key name based on HID Usage Tables for standard keyboard
printKeyName(key);
Serial.print(" ");
}
if (keysPressed) {
Serial.println();
} else if (modifiers == 0) {
Serial.println("No keys pressed");
}
}

View file

@ -0,0 +1,110 @@
// SPDX-FileCopyrightText: 2024 Ha Thach for Adafruit Industries
//
// SPDX-License-Identifier: MIT
/*********************************************************************
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
MIT license, check LICENSE for more information
Copyright (c) 2019 Ha Thach for Adafruit Industries
All text above, and the splash screen below must be included in
any redistribution
*********************************************************************/
#ifndef USBH_HELPER_H
#define USBH_HELPER_H
#ifdef ARDUINO_ARCH_RP2040
// pio-usb is required for rp2040 host
#include "pio_usb.h"
// Pin D+ for host, D- = D+ + 1
#ifndef PIN_USB_HOST_DP
#define PIN_USB_HOST_DP 16
#endif
// Pin for enabling Host VBUS. comment out if not used
#ifndef PIN_5V_EN
#define PIN_5V_EN 18
#endif
#ifndef PIN_5V_EN_STATE
#define PIN_5V_EN_STATE 1
#endif
#endif // ARDUINO_ARCH_RP2040
#ifdef ARDUINO_ARCH_RP2350
// pio-usb is required for rp2040 host
#include "pio_usb.h"
// Pin D+ for host, D- = D+ + 1
#ifndef PIN_USB_HOST_DP
#define PIN_USB_HOST_DP 32
#endif
// Pin for enabling Host VBUS. comment out if not used
#ifndef PIN_5V_EN
#define PIN_5V_EN 29
#endif
#ifndef PIN_5V_EN_STATE
#define PIN_5V_EN_STATE 1
#endif
#endif // ARDUINO_ARCH_RP2350
#include "Adafruit_TinyUSB.h"
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
// USB Host using MAX3421E: SPI, CS, INT
#include "SPI.h"
#if defined(ARDUINO_METRO_ESP32S2)
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
Adafruit_USBH_Host USBHost(&SPI, 33, 15);
#else
// Default CS and INT are pin 10, 9
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
#endif
#else
// Native USB Host such as rp2040
Adafruit_USBH_Host USBHost;
#endif
//--------------------------------------------------------------------+
// Helper Functions
//--------------------------------------------------------------------+
#ifdef ARDUINO_ARCH_RP2040
static void rp2040_configure_pio_usb(void) {
//while ( !Serial ) delay(10); // wait for native usb
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
#ifdef PIN_5V_EN
pinMode(PIN_5V_EN, OUTPUT);
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
#endif
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.pin_dp = PIN_USB_HOST_DP;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
// For pico-w, PIO is also used to communicate with cyw43
// Therefore we need to alternate the pio-usb configuration
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
pio_cfg.sm_tx = 3;
pio_cfg.sm_rx = 2;
pio_cfg.sm_eop = 3;
pio_cfg.pio_rx_num = 0;
pio_cfg.pio_tx_num = 1;
pio_cfg.tx_ch = 9;
#endif
USBHost.configure_pio_usb(1, &pio_cfg);
}
#endif
#endif

View file

@ -0,0 +1,222 @@
// SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
//
// SPDX-License-Identifier: MIT
/*********************************************************************
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
MIT license, check LICENSE for more information
Copyright (c) 2019 Ha Thach for Adafruit Industries
All text above, and the splash screen below must be included in
any redistribution
*********************************************************************/
/* This example demonstrates use of usb host with a standard HID boot keyboard.
* - Host depends on MCU:
* - rp2040: bit-banging 2 GPIOs with Pico-PIO-USB library (roothub port1)
*
* Requirements:
* - For rp2040:
* - Pico-PIO-USB library
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
* - Provide VBus (5v) and GND for peripheral
*/
// USBHost is defined in usbh_helper.h
#include "usbh_helper.h"
#include "tusb.h"
#include "Adafruit_TinyUSB.h"
bool printed_blank = false;
void setup() {
Serial.begin(115200);
// configure pio-usb: defined in usbh_helper.h
rp2040_configure_pio_usb();
// run host stack on controller (rhport) 1
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
// host bit-banging processing works done in core1 to free up core0 for other works
USBHost.begin(1);
delay(3000);
Serial.print("USB D+ Pin:");
Serial.println(PIN_USB_HOST_DP);
Serial.print("USB 5V Pin:");
Serial.println(PIN_5V_EN);
}
void loop() {
USBHost.task();
Serial.flush();
}
//--------------------------------------------------------------------+
// HID Host Callback Functions
//--------------------------------------------------------------------+
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len)
{
Serial.printf("HID device mounted (address %d, instance %d)\n", dev_addr, instance);
// Start receiving HID reports
if (!tuh_hid_receive_report(dev_addr, instance))
{
Serial.printf("Error: cannot request to receive report\n");
}
}
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
{
Serial.printf("HID device unmounted (address %d, instance %d)\n", dev_addr, instance);
}
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {
if (len > 0){
//debug print report data
// Serial.print("Report data: ");
// for (int i = 0; i < len; i++) {
// Serial.print(report[i], HEX);
// Serial.print(" ");
// }
// Serial.println();
printKeyboardReport(report);
}
// Continue to receive the next report
if (!tuh_hid_receive_report(dev_addr, instance)) {
Serial.println("Error: cannot request to receive report");
}
}
// Helper function to print key names
void printKeyName(uint8_t key) {
// This is a simplified list. Full HID keyboard has many more key codes
switch (key) {
case 0x04: Serial.print("A"); break;
case 0x05: Serial.print("B"); break;
case 0x06: Serial.print("C"); break;
case 0x07: Serial.print("D"); break;
case 0x08: Serial.print("E"); break;
case 0x09: Serial.print("F"); break;
case 0x0A: Serial.print("G"); break;
case 0x0B: Serial.print("H"); break;
case 0x0C: Serial.print("I"); break;
case 0x0D: Serial.print("J"); break;
case 0x0E: Serial.print("K"); break;
case 0x0F: Serial.print("L"); break;
case 0x10: Serial.print("M"); break;
case 0x11: Serial.print("N"); break;
case 0x12: Serial.print("O"); break;
case 0x13: Serial.print("P"); break;
case 0x14: Serial.print("Q"); break;
case 0x15: Serial.print("R"); break;
case 0x16: Serial.print("S"); break;
case 0x17: Serial.print("T"); break;
case 0x18: Serial.print("U"); break;
case 0x19: Serial.print("V"); break;
case 0x1A: Serial.print("W"); break;
case 0x1B: Serial.print("X"); break;
case 0x1C: Serial.print("Y"); break;
case 0x1D: Serial.print("Z"); break;
case 0x1E: Serial.print("1"); break;
case 0x1F: Serial.print("2"); break;
case 0x20: Serial.print("3"); break;
case 0x21: Serial.print("4"); break;
case 0x22: Serial.print("5"); break;
case 0x23: Serial.print("6"); break;
case 0x24: Serial.print("7"); break;
case 0x25: Serial.print("8"); break;
case 0x26: Serial.print("9"); break;
case 0x27: Serial.print("0"); break;
case 0x28: Serial.print("ENTER"); break;
case 0x29: Serial.print("ESC"); break;
case 0x2A: Serial.print("BACKSPACE"); break;
case 0x2B: Serial.print("TAB"); break;
case 0x2C: Serial.print("SPACE"); break;
case 0x2D: Serial.print("MINUS"); break;
case 0x2E: Serial.print("EQUAL"); break;
case 0x2F: Serial.print("LBRACKET"); break;
case 0x30: Serial.print("RBRACKET"); break;
case 0x31: Serial.print("BACKSLASH"); break;
case 0x33: Serial.print("SEMICOLON"); break;
case 0x34: Serial.print("QUOTE"); break;
case 0x35: Serial.print("GRAVE"); break;
case 0x36: Serial.print("COMMA"); break;
case 0x37: Serial.print("PERIOD"); break;
case 0x38: Serial.print("SLASH"); break;
case 0x39: Serial.print("CAPS_LOCK"); break;
case 0x4F: Serial.print("RIGHT_ARROW"); break;
case 0x50: Serial.print("LEFT_ARROW"); break;
case 0x51: Serial.print("DOWN_ARROW"); break;
case 0x52: Serial.print("UP_ARROW"); break;
default:
if (key >= 0x3A && key <= 0x45) { // F1-F12
Serial.print("F");
Serial.print(key - 0x3A + 1);
} else {
// For keys not handled above, just print the HID code
Serial.print("0x");
Serial.print(key, HEX);
}
break;
}
}
void printKeyboardReport(uint8_t const* report) {
// First byte contains modifier keys
uint8_t modifiers = report[0];
// Print modifier keys if pressed
if (modifiers > 0) {
Serial.print("Modifiers: ");
if (modifiers & 0x01) Serial.print("LEFT_CTRL ");
if (modifiers & 0x02) Serial.print("LEFT_SHIFT ");
if (modifiers & 0x04) Serial.print("LEFT_ALT ");
if (modifiers & 0x08) Serial.print("LEFT_GUI ");
if (modifiers & 0x10) Serial.print("RIGHT_CTRL ");
if (modifiers & 0x20) Serial.print("RIGHT_SHIFT ");
if (modifiers & 0x40) Serial.print("RIGHT_ALT ");
if (modifiers & 0x80) Serial.print("RIGHT_GUI ");
Serial.println();
}
// Second byte is reserved (usually 0)
// Bytes 2-7 contain up to 6 key codes
bool keysPressed = false;
for (int i = 2; i < 8; i++) {
uint8_t key = report[i];
// Skip if no key or error rollover
if (key == 0 || key == 1) {
continue;
}
if (!keysPressed) {
Serial.print("Keys: ");
keysPressed = true;
}
// Print key name based on HID Usage Tables for standard keyboard
printKeyName(key);
Serial.print(" ");
}
if (keysPressed) {
Serial.println();
} else if (modifiers == 0) {
Serial.println("No keys pressed");
}
}

View file

@ -0,0 +1,18 @@
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import sys
import supervisor
# main loop
while True:
# check how many bytes are available
available = supervisor.runtime.serial_bytes_available
# if there are some bytes available
if available:
# read data from the keyboard input
c = sys.stdin.read(available)
# print the data that was read
print(c, end="")

View file

@ -0,0 +1,167 @@
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import array
import usb
import adafruit_usb_host_descriptors
# lists for mouse interface indexes, endpoint addresses, and USB Device instances
# each of these will end up with length 2 once we find both mice
kbd_interface_index = None
kbd_endpoint_address = None
keyboard = None
# scan for connected USB devices
for device in usb.core.find(find_all=True):
# check for boot mouse endpoints on this device
kbd_interface_index, kbd_endpoint_address = (
adafruit_usb_host_descriptors.find_boot_keyboard_endpoint(device)
)
# if a boot keyboard interface index and endpoint address were found
if kbd_interface_index is not None and kbd_interface_index is not None:
keyboard = device
# detach device from kernel if needed
if keyboard.is_kernel_driver_active(0):
keyboard.detach_kernel_driver(0)
# set the configuration so it can be used
keyboard.set_configuration()
if keyboard is None:
raise RuntimeError("No boot keyboard endpoint found")
buf = array.array("b", [0] * 8)
def print_keyboard_report(report_data):
# Dictionary for modifier keys (first byte)
modifier_dict = {
0x01: "LEFT_CTRL",
0x02: "LEFT_SHIFT",
0x04: "LEFT_ALT",
0x08: "LEFT_GUI",
0x10: "RIGHT_CTRL",
0x20: "RIGHT_SHIFT",
0x40: "RIGHT_ALT",
0x80: "RIGHT_GUI",
}
# Dictionary for key codes (main keys)
key_dict = {
0x04: "A",
0x05: "B",
0x06: "C",
0x07: "D",
0x08: "E",
0x09: "F",
0x0A: "G",
0x0B: "H",
0x0C: "I",
0x0D: "J",
0x0E: "K",
0x0F: "L",
0x10: "M",
0x11: "N",
0x12: "O",
0x13: "P",
0x14: "Q",
0x15: "R",
0x16: "S",
0x17: "T",
0x18: "U",
0x19: "V",
0x1A: "W",
0x1B: "X",
0x1C: "Y",
0x1D: "Z",
0x1E: "1",
0x1F: "2",
0x20: "3",
0x21: "4",
0x22: "5",
0x23: "6",
0x24: "7",
0x25: "8",
0x26: "9",
0x27: "0",
0x28: "ENTER",
0x29: "ESC",
0x2A: "BACKSPACE",
0x2B: "TAB",
0x2C: "SPACE",
0x2D: "MINUS",
0x2E: "EQUAL",
0x2F: "LBRACKET",
0x30: "RBRACKET",
0x31: "BACKSLASH",
0x33: "SEMICOLON",
0x34: "QUOTE",
0x35: "GRAVE",
0x36: "COMMA",
0x37: "PERIOD",
0x38: "SLASH",
0x39: "CAPS_LOCK",
0x4F: "RIGHT_ARROW",
0x50: "LEFT_ARROW",
0x51: "DOWN_ARROW",
0x52: "UP_ARROW",
}
# Add F1-F12 keys to the dictionary
for i in range(12):
key_dict[0x3A + i] = f"F{i + 1}"
# First byte contains modifier keys
modifiers = report_data[0]
# Print modifier keys if pressed
if modifiers > 0:
print("Modifiers:", end=" ")
# Check each bit for modifiers and print if pressed
for bit, name in modifier_dict.items():
if modifiers & bit:
print(name, end=" ")
print()
# Bytes 2-7 contain up to 6 key codes (byte 1 is reserved)
keys_pressed = False
for i in range(2, 8):
key = report_data[i]
# Skip if no key or error rollover
if key in {0, 1}:
continue
if not keys_pressed:
print("Keys:", end=" ")
keys_pressed = True
# Print key name based on dictionary lookup
if key in key_dict:
print(key_dict[key], end=" ")
else:
# For keys not in the dictionary, print the HID code
print(f"0x{key:02X}", end=" ")
if keys_pressed:
print()
elif modifiers == 0:
print("No keys pressed")
while True:
# try to read data from the keyboard
try:
count = keyboard.read(kbd_endpoint_address, buf, timeout=10)
# if there is no data it will raise USBTimeoutError
except usb.core.USBTimeoutError:
# Nothing to do if there is no data for this mouse
continue
print_keyboard_report(buf)