注意

这是最新开发分支配套的文档,可能包含已发布版本中尚未提供的功能。如果您要查看特定版本的文档,请使用左侧的下拉菜单并选择所需要的版本。

USB HID 示例#

概述#

CanMV 提供 usb 模块下的 HID 输入封装,可直接读取 USB 键盘、鼠标和触摸输入。

当前固件内置了 3 个配套示例:

  • src/canmv/resources/examples/03-Machine/usb_hid_keyboard.py

  • src/canmv/resources/examples/03-Machine/usb_hid_mouse.py

  • src/canmv/resources/examples/03-Machine/usb_hid_touch.py

这组示例具备以下特点:

  • 设备未插入时循环等待并重试打开

  • 设备断开后支持自动重连

  • 键盘示例会输出按键事件以及解析后的字符

  • 鼠标示例会输出按键边沿、相对位移和滚轮

  • 触摸示例会输出按下状态、压力和坐标

使用前提#

  1. 开发板工作在 USB Host 模式

  2. 已插入 USB HID 设备,例如键盘、鼠标或 USB 触摸设备

  3. 固件中包含 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

  • 需要输入文本时,用 charstext

处理超时返回#

  • poll(timeout_ms):超时返回 False

  • read(timeout_ms):超时返回 None

因此示例里通常先判断:

frame = keyboard.read(1000)
if not frame:
    continue

常见问题#

键盘按键字符和实际输入不一致怎么办?#

请更新到包含最新 USB HID 修复的固件版本。当前实现已经按 Linux input keycode 映射修正了字母键解析,并支持 CtrlShiftCaps Lock 的组合处理。

设备拔出后脚本会停止吗?#

如果启用了 auto_reconnect=True,脚本会进入等待重连状态;重新插入同类设备后会自动恢复。

鼠标和触摸都使用相同返回结构吗?#

两者都返回指针类帧结构,但鼠标主要使用相对坐标和按键位,触摸更常使用绝对坐标、压力和 touch_down

相关文档#

评论列表
条评论
登录