USB HID 示例#
概述#
CanMV 提供 usb 模块下的 HID 输入封装,可直接读取 USB 键盘、鼠标和触摸输入。
当前固件内置了 3 个配套示例:
src/canmv/resources/examples/03-Machine/usb_hid_keyboard.pysrc/canmv/resources/examples/03-Machine/usb_hid_mouse.pysrc/canmv/resources/examples/03-Machine/usb_hid_touch.py
这组示例具备以下特点:
设备未插入时循环等待并重试打开
设备断开后支持自动重连
键盘示例会输出按键事件以及解析后的字符
鼠标示例会输出按键边沿、相对位移和滚轮
触摸示例会输出按下状态、压力和坐标
使用前提#
开发板工作在 USB Host 模式
已插入 USB HID 设备,例如键盘、鼠标或 USB 触摸设备
固件中包含
usb模块和 USB HID 主机支持
键盘示例#
import time
from usb import Keyboard
def open_keyboard():
keyboard = Keyboard(timeout_ms=1000, auto_reconnect=True)
while True:
try:
keyboard.open()
info = keyboard.info()
print("USB keyboard ready:", info)
return keyboard
except OSError as err:
print("waiting for USB keyboard:", err)
time.sleep_ms(500)
keyboard = open_keyboard()
while True:
frame = keyboard.read(1000)
if not frame:
continue
events = frame["events"]
if not events:
continue
text = frame["text"]
chars = frame["chars"]
for keycode, value in events:
if value == Keyboard.VALUE_PRESSED:
state = "pressed"
elif value == Keyboard.VALUE_REPEAT:
state = "repeat"
else:
state = "released"
print("keycode=%d state=%s" % (keycode, state))
if chars:
print(
"parsed chars=%s text=%r ctrl=%s shift=%s alt=%s meta=%s caps_lock=%s"
% (
chars,
text,
frame["ctrl"],
frame["shift"],
frame["alt"],
frame["meta"],
frame["caps_lock"],
)
)
输出说明#
events:原始键盘事件帧,每个元素是(keycode, value)chars:本帧解析出的字符编码列表text:本帧解析出的字节串,例如b"abc"ctrl/shift/alt/meta/caps_lock:当前修饰键状态
键盘示例输出参考#
USB keyboard ready: {'kind': 'keyboard', 'name': 'Logitech USB Keyboard', 'path': '/dev/hidk0', ...}
keycode=34 state=pressed
parsed chars=(103,) text=b'g' ctrl=False shift=False alt=False meta=False caps_lock=False
keycode=34 state=released
鼠标示例#
import time
from usb import Mouse
def open_mouse():
mouse = Mouse(timeout_ms=1000, auto_reconnect=True)
while True:
try:
mouse.open()
info = mouse.info()
print("USB mouse ready:", info)
print("button masks:", Mouse.BTN_LEFT_MASK, Mouse.BTN_RIGHT_MASK, Mouse.BTN_MIDDLE_MASK)
return mouse
except OSError as err:
print("waiting for USB mouse:", err)
time.sleep_ms(500)
mouse = open_mouse()
while True:
frame = mouse.read(1000)
if not frame:
continue
moved = frame["has_rel"] or frame["has_abs"]
button_edge = frame["pressed_mask"] or frame["released_mask"]
wheel_move = frame["wheel"] or frame["hwheel"]
if not moved and not button_edge and not wheel_move:
continue
print(
"buttons=%d pressed=%d released=%d rel=(%d,%d) abs=(%d,%d) wheel=(%d,%d)" % (
frame["buttons"],
frame["pressed_mask"],
frame["released_mask"],
frame["rel_x"],
frame["rel_y"],
frame["abs_x"],
frame["abs_y"],
frame["wheel"],
frame["hwheel"],
)
)
鼠标示例输出参考#
USB mouse ready: {'kind': 'mouse', 'name': 'USB Optical Mouse', 'path': '/dev/hidm0', ...}
button masks: 1 2 4
buttons=1 pressed=1 released=0 rel=(12,-3) abs=(0,0) wheel=(0,0)
触摸示例#
import time
from usb import Touch
def open_touch():
touch = Touch(timeout_ms=1000, auto_reconnect=True)
while True:
try:
touch.open()
info = touch.info()
print("USB touch ready:", info)
return touch
except OSError as err:
print("waiting for USB touch device:", err)
time.sleep_ms(500)
touch = open_touch()
while True:
frame = touch.read(1000)
if not frame:
continue
active = frame["touch_seen"] or frame["buttons"] or frame["pressure"]
moved = frame["has_abs"] or frame["has_rel"]
if not active and not moved:
continue
print(
"down=%s pressure=%d buttons=%d abs=(%d,%d) rel=(%d,%d)" % (
frame["touch_down"],
frame["pressure"],
frame["buttons"],
frame["abs_x"],
frame["abs_y"],
frame["rel_x"],
frame["rel_y"],
)
)
常见用法建议#
使用自动重连#
建议创建对象时启用:
kbd = Keyboard(timeout_ms=1000, auto_reconnect=True)
这样在 USB HID 设备拔出后,后续 poll()、read()、info() 会尝试自动恢复。
区分原始按键与解析字符#
需要做快捷键、游戏控制、原始按键处理时,用
events需要输入文本时,用
chars和text
处理超时返回#
poll(timeout_ms):超时返回Falseread(timeout_ms):超时返回None
因此示例里通常先判断:
frame = keyboard.read(1000)
if not frame:
continue
常见问题#
键盘按键字符和实际输入不一致怎么办?#
请更新到包含最新 USB HID 修复的固件版本。当前实现已经按 Linux input keycode 映射修正了字母键解析,并支持 Ctrl、Shift、Caps Lock 的组合处理。
设备拔出后脚本会停止吗?#
如果启用了 auto_reconnect=True,脚本会进入等待重连状态;重新插入同类设备后会自动恢复。
鼠标和触摸都使用相同返回结构吗?#
两者都返回指针类帧结构,但鼠标主要使用相对坐标和按键位,触摸更常使用绝对坐标、压力和 touch_down。
