diff --git a/adafruit_usb_host_descriptors.py b/adafruit_usb_host_descriptors.py index c4a6f00..c02c1ba 100644 --- a/adafruit_usb_host_descriptors.py +++ b/adafruit_usb_host_descriptors.py @@ -14,6 +14,11 @@ from micropython import const +try: + from typing import Literal +except ImportError: + pass + __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_USB_Host_Descriptors.git" @@ -39,6 +44,7 @@ INTERFACE_HID = 0x03 SUBCLASS_BOOT = 0x01 PROTOCOL_MOUSE = 0x02 +PROTOCOL_KEYBOARD = 0x01 def get_descriptor(device, desc_type, index, buf, language_id=0): @@ -77,13 +83,7 @@ def get_configuration_descriptor(device, index): return full_buf -def find_boot_mouse_endpoint(device): - """ - Try to find a boot mouse endpoint in the device and return its - interface index, and endpoint address. - :param device: The device to search within - :return: mouse_interface_index, mouse_endpoint_address if found, or None, None otherwise - """ +def _find_boot_endpoint(device, protocol_type: Literal[PROTOCOL_MOUSE, PROTOCOL_KEYBOARD]): config_descriptor = get_configuration_descriptor(device, 0) i = 0 mouse_interface_index = None @@ -99,7 +99,7 @@ def find_boot_mouse_endpoint(device): if ( interface_class == INTERFACE_HID and interface_subclass == SUBCLASS_BOOT - and interface_protocol == PROTOCOL_MOUSE + and interface_protocol == protocol_type ): found_mouse = True mouse_interface_index = interface_number @@ -111,3 +111,23 @@ def find_boot_mouse_endpoint(device): return mouse_interface_index, endpoint_address i += descriptor_len return None, None + + +def find_boot_mouse_endpoint(device): + """ + Try to find a boot mouse endpoint in the device and return its + interface index, and endpoint address. + :param device: The device to search within + :return: mouse_interface_index, mouse_endpoint_address if found, or None, None otherwise + """ + return _find_boot_endpoint(device, PROTOCOL_MOUSE) + + +def find_boot_keyboard_endpoint(device): + """ + Try to find a boot keyboard endpoint in the device and return its + interface index, and endpoint address. + :param device: The device to search within + :return: keyboard_interface_index, keyboard_endpoint_address if found, or None, None otherwise + """ + return _find_boot_endpoint(device, PROTOCOL_KEYBOARD) diff --git a/examples/usb_host_descriptors_find_boot_keyboard.py b/examples/usb_host_descriptors_find_boot_keyboard.py new file mode 100644 index 0000000..9ee9bd6 --- /dev/null +++ b/examples/usb_host_descriptors_find_boot_keyboard.py @@ -0,0 +1,45 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +import array + +import usb + +import adafruit_usb_host_descriptors + +keyboard_interface_index = None +keyboard_endpoint_address = None +keyboard = None + +# scan for connected USB devices +for device in usb.core.find(find_all=True): + # check for boot keyboard endpoints on this device + keyboard_interface_index, keyboard_endpoint_address = ( + adafruit_usb_host_descriptors.find_boot_keyboard_endpoint(device) + ) + # if a boot keyboard interface index and endpoint address were found + if keyboard_interface_index is not None and keyboard_endpoint_address 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 the keyboard can be used + keyboard.set_configuration() + +buf = array.array("b", [0] * 8) + +while True: + # try to read data from the keyboard + try: + count = keyboard.read(keyboard_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 keyboard + continue + + for b in buf: + print(hex(b), end=" ") + print()