Skip to content

Commit 21ab387

Browse files
committed
add find_boot_keyboard function and example
1 parent 71816de commit 21ab387

File tree

2 files changed

+75
-8
lines changed

2 files changed

+75
-8
lines changed

adafruit_usb_host_descriptors.py

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414

1515
from micropython import const
1616

17+
try:
18+
from typing import Literal
19+
except ImportError:
20+
pass
21+
1722
__version__ = "0.0.0+auto.0"
1823
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_USB_Host_Descriptors.git"
1924

@@ -39,6 +44,7 @@
3944
INTERFACE_HID = 0x03
4045
SUBCLASS_BOOT = 0x01
4146
PROTOCOL_MOUSE = 0x02
47+
PROTOCOL_KEYBOARD = 0x01
4248

4349

4450
def get_descriptor(device, desc_type, index, buf, language_id=0):
@@ -77,13 +83,7 @@ def get_configuration_descriptor(device, index):
7783
return full_buf
7884

7985

80-
def find_boot_mouse_endpoint(device):
81-
"""
82-
Try to find a boot mouse endpoint in the device and return its
83-
interface index, and endpoint address.
84-
:param device: The device to search within
85-
:return: mouse_interface_index, mouse_endpoint_address if found, or None, None otherwise
86-
"""
86+
def _find_boot_endpoint(device, protocol_type: Literal[PROTOCOL_MOUSE, PROTOCOL_KEYBOARD]):
8787
config_descriptor = get_configuration_descriptor(device, 0)
8888
i = 0
8989
mouse_interface_index = None
@@ -99,7 +99,7 @@ def find_boot_mouse_endpoint(device):
9999
if (
100100
interface_class == INTERFACE_HID
101101
and interface_subclass == SUBCLASS_BOOT
102-
and interface_protocol == PROTOCOL_MOUSE
102+
and interface_protocol == protocol_type
103103
):
104104
found_mouse = True
105105
mouse_interface_index = interface_number
@@ -111,3 +111,23 @@ def find_boot_mouse_endpoint(device):
111111
return mouse_interface_index, endpoint_address
112112
i += descriptor_len
113113
return None, None
114+
115+
116+
def find_boot_mouse_endpoint(device):
117+
"""
118+
Try to find a boot mouse endpoint in the device and return its
119+
interface index, and endpoint address.
120+
:param device: The device to search within
121+
:return: mouse_interface_index, mouse_endpoint_address if found, or None, None otherwise
122+
"""
123+
return _find_boot_endpoint(device, PROTOCOL_MOUSE)
124+
125+
126+
def find_boot_keyboard_endpoint(device):
127+
"""
128+
Try to find a boot keyboard endpoint in the device and return its
129+
interface index, and endpoint address.
130+
:param device: The device to search within
131+
:return: keyboard_interface_index, keyboard_endpoint_address if found, or None, None otherwise
132+
"""
133+
return _find_boot_endpoint(device, PROTOCOL_KEYBOARD)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
import array
5+
6+
import usb
7+
8+
import adafruit_usb_host_descriptors
9+
10+
# lists for mouse interface indexes, endpoint addresses, and USB Device instances
11+
# each of these will end up with length 2 once we find both mice
12+
mouse_interface_indexes = None
13+
mouse_endpoint_addresses = None
14+
keyboard = None
15+
16+
# scan for connected USB devices
17+
for device in usb.core.find(find_all=True):
18+
# check for boot mouse endpoints on this device
19+
kbd_interface_index, kbd_endpoint_address = (
20+
adafruit_usb_host_descriptors.find_boot_keyboard_endpoint(device)
21+
)
22+
# if a boot mouse interface index and endpoint address were found
23+
if kbd_interface_index is not None and kbd_interface_index is not None:
24+
keyboard = device
25+
26+
# detach device from kernel if needed
27+
if keyboard.is_kernel_driver_active(0):
28+
keyboard.detach_kernel_driver(0)
29+
30+
# set the mouse configuration so it can be used
31+
keyboard.set_configuration()
32+
33+
buf = array.array("b", [0] * 8)
34+
35+
while True:
36+
# try to read data from the mouse
37+
try:
38+
count = keyboard.read(mouse_endpoint_addresses, buf, timeout=10)
39+
40+
# if there is no data it will raise USBTimeoutError
41+
except usb.core.USBTimeoutError:
42+
# Nothing to do if there is no data for this mouse
43+
continue
44+
45+
for b in buf:
46+
print(hex(b), end=" ")
47+
print()

0 commit comments

Comments
 (0)