跳转至

Keyboard_Class & KeysState

头文件: utility/Keyboard/Keyboard.h
访问: M5Cardputer.Keyboard

处理所有键盘输入:物理按键扫描、字符映射、修饰键跟踪、Caps Lock 以及 USB HID 键码生成。


KeysState

struct Keyboard_Class::KeysState

当前按下按键的快照,由 updateKeysState() 填充。

字段

字段 类型 说明
tab bool Tab 键被按下
fn bool Fn 修饰键激活
shift bool Shift 修饰键激活
ctrl bool Ctrl 修饰键激活
opt bool Opt 修饰键激活
alt bool Alt 修饰键激活
del bool 退格键被按下
enter bool 回车键被按下
space bool 空格键被按下
modifiers uint8_t USB HID 修饰键位掩码
word std::vector<char> 可打印字符(遵循 Shift/Ctrl/Caps 状态)
hid_keys std::vector<uint8_t> 所有非修饰键的 USB HID 键码
modifier_keys std::vector<uint8_t> 修饰键的 USB HID 键码

reset()

void reset();

清空所有字段:布尔值 → false,向量清空。

KeysState state = M5Cardputer.Keyboard.keysState();
// ... 使用 state ...
state.reset();  // 准备下一帧

Keyboard_Class 方法

begin()

void begin();

自动检测板型并创建对应的 KeyboardReader: - board_M5CardputerIOMatrixKeyboardReader(GPIO 矩阵) - board_M5CardputerADVTCA8418KeyboardReader(I2C/TCA8418)

M5Cardputer.begin() 自动调用 — 通常无需手动调用。


begin(reader)

void begin(std::unique_ptr<KeyboardReader> reader);

注入自定义的 KeyboardReader 实现。用于测试或自定义键盘硬件。

auto customReader = std::make_unique<IOMatrixKeyboardReader>();
M5Cardputer.Keyboard.begin(std::move(customReader));

updateKeyList()

void updateKeyList();

委托给活动的 KeyboardReader 扫描物理矩阵并刷新按键列表。由 M5Cardputer.update() 自动调用。


keyList()

const std::vector<Point2D_t>& keyList();

返回所有当前按下的按键坐标,格式为 Point2D_t {x, y}

返回值 说明
const std::vector<Point2D_t>& 按下的按键位置列表
void loop() {
    M5Cardputer.update();
    auto& keys = M5Cardputer.Keyboard.keyList();
    M5Cardputer.Display.setCursor(0, 0);
    M5Cardputer.Display.printf("按下按键: %d\n", keys.size());
}

isPressed()

uint8_t isPressed();

返回当前按住的按键数量。无按键时返回 0

返回值 说明
uint8_t 按下的按键数量
void loop() {
    M5Cardputer.update();

    if (M5Cardputer.Keyboard.isPressed()) {
        // 至少有一个键被按住
        M5Cardputer.Display.drawString("输入中...", 10, 10);
    }
}

isChange()

bool isChange();

自上次调用以来按键数量发生变化时返回 true。用于检测新输入而无需每帧处理。

返回值 说明
true 按键数量变化(按下或释放)
false 自上次检查以来无变化
void loop() {
    M5Cardputer.update();

    if (M5Cardputer.Keyboard.isChange()) {
        if (M5Cardputer.Keyboard.isPressed()) {
            M5Cardputer.Keyboard.updateKeysState();
            auto& state = M5Cardputer.Keyboard.keysState();

            // 处理新输入
            for (char c : state.word) {
                M5Cardputer.Display.print(c);
            }
            if (state.enter) M5Cardputer.Display.println();
        } else {
            // 所有按键已释放
            M5Cardputer.Display.println("按键已释放");
        }
    }
}

isKeyPressed(c)

bool isKeyPressed(char c);

ASCII 字符 c 对应的按键当前被按下时返回 true

参数 类型 说明
c char 要检查的 ASCII 字符
void loop() {
    M5Cardputer.update();

    // WASD 移动
    int x = 100, y = 100;
    if (M5Cardputer.Keyboard.isKeyPressed('w')) y--;
    if (M5Cardputer.Keyboard.isKeyPressed('s')) y++;
    if (M5Cardputer.Keyboard.isKeyPressed('a')) x--;
    if (M5Cardputer.Keyboard.isKeyPressed('d')) x++;

    M5Cardputer.Display.fillRect(x, y, 8, 8, TFT_GREEN);

    // 退出快捷键
    if (M5Cardputer.Keyboard.isKeyPressed('q')) {
        M5Cardputer.Display.println("正在退出...");
    }
}

getKey(keyCoor)

uint8_t getKey(Point2D_t keyCoor);

返回指定物理按键位置的 ASCII 字符,自动应用当前 Shift/Ctrl/Caps Lock 状态。

参数 类型 说明
keyCoor Point2D_t 按键坐标 {x, y}
返回值 说明
uint8_t ASCII 字符,无效或缺失时返回 0
void loop() {
    M5Cardputer.update();

    // 读取位置 (5, 1) 是什么字符
    Point2D_t keyPos = {5, 1};  // 't' 键
    uint8_t ch = M5Cardputer.Keyboard.getKey(keyPos);
    M5Cardputer.Display.printf("按键(5,1) = '%c'\n", ch);
}

getKeyValue(keyCoor)

KeyValue_t getKeyValue(const Point2D_t& keyCoor);

返回指定坐标的原始 KeyValue_t {value_first, value_second},不应用修饰键。

Point2D_t keyPos = {1, 0};  // '1' 键
KeyValue_t kv = M5Cardputer.Keyboard.getKeyValue(keyPos);
// kv.value_first  = '1'
// kv.value_second = '!'
M5Cardputer.Display.printf("'%c' / '%c'\n", kv.value_first, kv.value_second);

updateKeysState()

void updateKeysState();

扫描所有按下的按键并填充 KeysState 缓冲区。采用两遍算法:

  1. 第一遍: 识别修饰键(Fn、Opt、Ctrl、Shift、Alt)
  2. 第二遍: 以正确的修饰键状态处理所有其他按键(可打印字符、Tab、Enter、Backspace、Space)

填充 wordhid_keysmodifier_keys 以及所有布尔标志。在读取 keysState() 之前调用。


keysState()

KeysState& keysState();

返回当前 KeysState 缓冲区的引用。缓冲区由 updateKeysState() 填充。

void loop() {
    M5Cardputer.update();

    if (M5Cardputer.Keyboard.isChange() && M5Cardputer.Keyboard.isPressed()) {
        M5Cardputer.Keyboard.updateKeysState();
        auto& state = M5Cardputer.Keyboard.keysState();

        // 显示按下的字符
        M5Cardputer.Display.setCursor(0, 0);
        M5Cardputer.Display.print("输入: ");
        for (char c : state.word) {
            M5Cardputer.Display.print(c);
        }

        // 显示当前修饰键
        M5Cardputer.Display.setCursor(0, 20);
        if (state.shift) M5Cardputer.Display.print("SHIFT ");
        if (state.ctrl)  M5Cardputer.Display.print("CTRL ");
        if (state.alt)   M5Cardputer.Display.print("ALT ");
        if (state.fn)    M5Cardputer.Display.print("FN ");
    }
}

capslocked() / setCapsLocked()

bool capslocked(void);
void setCapsLocked(bool isLocked);

软件管理的大写锁定状态。启用后 getKey() 返回大写字符。不是 硬件 LED — 应用程序自行管理视觉指示。

// 按 Tab 切换大写锁定
void loop() {
    M5Cardputer.update();
    if (M5Cardputer.Keyboard.isChange() && M5Cardputer.Keyboard.isPressed()) {
        M5Cardputer.Keyboard.updateKeysState();
        auto& state = M5Cardputer.Keyboard.keysState();

        if (state.tab) {
            bool caps = M5Cardputer.Keyboard.capslocked();
            M5Cardputer.Keyboard.setCapsLocked(!caps);
            M5Cardputer.Display.print(caps ? "大写: 关\n" : "大写: 开\n");
        }
    }
}

按键布局

物理键盘为 4 行 × 14 列 矩阵,存储在 _key_value_map[4][14] 中。每个位置有 value_first(正常)和 value_second(Shift)。

第0行: `  1  2  3  4  5  6  7  8  9  0  -  =  BKSP
第1行: TAB q  w  e  r  t  y  u  i  o  p  [  ]  \
第2行: FN  SHIFT a s d f g h j k l ; ' ENTER
第3行: CTRL OPT ALT z x c v b n m , . / SPACE

坐标: Point2D_t {列, 行}。例如 a 键位于 {2, 2}ENTER 键位于 {13, 2}


键码常量

定义于 utility/Keyboard/Keyboard_def.h。用于 USB HID 键盘模拟。

修饰键

常量 USB HID 说明
KEY_LEFT_CTRL 0x80 0xE0 左 Ctrl
KEY_LEFT_SHIFT 0x81 0xE1 左 Shift
KEY_LEFT_ALT 0x82 0xE2 左 Alt
KEY_FN 0xFF Fn(M5Cardputer 特有)
KEY_OPT 0x00 Opt(M5Cardputer 特有)

特殊按键

常量 USB HID 说明
KEY_BACKSPACE 0x2A 0x2A 退格
KEY_TAB 0x2B 0x2B Tab
KEY_ENTER 0x28 0x28 回车

SHIFT 标志

#define SHIFT 0x80

_kb_asciimap[] 中某键码设置了此位,表示该键需要 Shift。

_kb_asciimap[128]

将 ASCII 字符映射到 USB HID 键码。内部用于填充 KeysState.hid_keys。完整表格见 src/utility/Keyboard/Keyboard_def.h


完整使用模式

#include <M5Cardputer.h>

void setup() {
    auto cfg = M5.config();
    M5Cardputer.begin(cfg, true);
    M5Cardputer.Display.setRotation(1);
}

void loop() {
    M5Cardputer.update();

    // 消抖:仅在状态变化时处理
    if (M5Cardputer.Keyboard.isChange()) {
        if (M5Cardputer.Keyboard.isPressed()) {
            M5Cardputer.Keyboard.updateKeysState();
            auto& state = M5Cardputer.Keyboard.keysState();

            // 打印字符
            for (char c : state.word) {
                M5Cardputer.Display.print(c);
            }
            if (state.enter) M5Cardputer.Display.println();
            if (state.del) {
                // 在此实现退格逻辑
            }
        }
    }

    // 轮询:按住期间持续触发
    if (M5Cardputer.Keyboard.isKeyPressed('r')) {
        M5Cardputer.Display.fillScreen(TFT_RED);
    }
}