HID Keyboard Report Format là gì?

Cấu trúc 8 byte của HID keyboard report: modifier byte, reserved byte, 6 keycode slot. Cách gửi report từ STM32 middleware.

Cập nhật 5 phút đọc
Đọc bằng Tiếng Việt English
USB cover

HID keyboard report là gói dữ liệu firmware gửi lên host mỗi khi có thay đổi trạng thái bàn phím. Điểm dễ nhầm là report này không chứa ký tự ASCII, firmware không gửi chữ a, firmware gửi usage ID của phím a, còn host tự quyết định ký tự cuối cùng dựa trên layout bàn phím và giá trị modifier (phím chức năng).

Nhiều HID keyboard hỗ trợ định dạng boot keyboard 8 byte vì nó đơn giản và tương thích tốt với firmware/BIOS/UEFI. Một số bàn phím nâng cao có thể dùng Report Protocol riêng ví dụ như NKRO bitmap hoặc consumer control report.

1. Cấu trúc 8 byte

Offset  Nội dung
──────────────────────────────────────────
  0     Modifier byte
  1     Reserved (0x00)
  2     Keycode 1
  3     Keycode 2
  4     Keycode 3
  5     Keycode 4
  6     Keycode 5
  7     Keycode 6

Cấu trúc trong C:

typedef struct {    uint8_t modifier;       /* Modifier keys (Ctrl, Shift, Alt, GUI) */    uint8_t reserved;       /* Always 0x00                           */    uint8_t keycodes[6];    /* Up to 6 simultaneous keycodes         */} HID_KeyboardReport_t;

Ví dụ report thật, nhấn phím “1” trên keypad: 00 00 1E 00 00 00 00 00, capture từ Wireshark. 0x1E là HID usage cho phím 1/! trong Usage Page Keyboard.

2. Modifier byte

Modifier byte là bitmask, mỗi bit ứng với một modifier key:

Bit Mask Phím
0 0x01 Left Ctrl
1 0x02 Left Shift
2 0x04 Left Alt
3 0x08 Left GUI
4 0x10 Right Ctrl
5 0x20 Right Shift
6 0x40 Right Alt
7 0x80 Right GUI

Ví dụ nhấn Left Shift + A:

HID_KeyboardReport_t report = {0};report.modifier    = 0x02;    /* Left Shift */report.keycodes[0] = 0x04;    /* HID keycode của 'a' */

3. Mảng keycode: 6-key rollover

6 slot keycode cho phép tối đa 6 phím (ngoài modifier) được nhấn đồng thời, đây cũng là giới hạn của Boot Protocol.

/* Khi nhấn phím: tìm slot trống và điền vào */for (uint8_t i = 0; i < 6; i++) {    if (report.keycodes[i] == 0x00) {        report.keycodes[i] = new_keycode;        break;    }}/* Khi thả phím: tìm keycode đó và xóa đi */for (uint8_t i = 0; i < 6; i++) {    if (report.keycodes[i] == new_keycode) {        report.keycodes[i] = 0x00;        break;    }}

Không cần sắp xếp hay dồn mảng. Keycode 0x00 là “không có phím”. Host chỉ quan tâm các giá trị khác 0.

4. ErrorRollOver

Khi firmware không thể xác định tổ hợp phím hợp lệ (ví dụ ma trận không diode, nhấn quá 6 phím), Boot Protocol của bàn phím có ErrorRollOver usage 0x01:

Report gửi ErrorRollOver:  00 00 01 01 01 01 01 01
Report null tiếp theo:     00 00 00 00 00 00 00 00

Sau khi gửi ErrorRollOver nên gửi thêm null report để host biết trạng thái đã reset. Report này không phải là lỗi phần mềm, host cũng không hiển thị thông báo hay kí tự đặc biệt gì. Vì vậyd đối với người dùng cuối thì hoàn toàn không có ảnh hưởng gì.

Report này chỉ có thể xác nhận qua USB protocol analyzer, Wireshark capture,…hoặc các công cụ debug USB chuyên dụng.

5. Gửi report từ application

Ví dụ dưới đây dùng ST USB Device Library. Tên API và cách gọi có thể khác nhau tùy thuộc vào middleware.

extern USBD_HandleTypeDef hUsbDeviceFS;void Keyboard_SendReport(const HID_KeyboardReport_t *report){    USBD_HID_SendReport(&hUsbDeviceFS,                        (uint8_t *)report,                        sizeof(HID_KeyboardReport_t));}

6. Report khi không có phím nào nhấn

Nhấn phím chỉ là một nửa câu chuyện. Host cũng cần biết khi nào phím đã được thả.

HID_KeyboardReport_t empty_report = {0};Keyboard_SendReport(&empty_report);

Nếu firmware chỉ gửi report khi nhấn nhưng không gửi report rỗng khi thả hết phím, host sẽ nghĩ phím vẫn đang nhấn và phím sẽ repeat vô hạn.

Một cách áp dụng phổ biến là “tap-style”: sau mỗi report key-down, firmware gửi ngay null report ở lần gọi kế tiếp thay vì chờ sự kiện thả phím thật. Cách này giúp firmware tự kiểm soát tốc độ repeat thay vì để OS áp dụng typematic repeat theo tốc độ riêng của nó.

7. Rollover và ghosting

6-key rollover (6KRO) là giới hạn của Boot Protocol: tối đa 6 keycode + modifier. Nếu cần nhận nhiều phím đồng thời hơn, nên thiết kế Report Descriptor riêng thay vì cố nhồi vào boot report 8 byte.

N-key rollover (NKRO) không bị giới hạn số phím đồng thời, nhưng cần HID Report Descriptor khác (bitmap thay vì mảng) và không tương thích với Boot Protocol.

Ghosting là hiện tượng phần cứng trên ma trận không diode. Đây là vấn đề phần cứng, không liên quan đến định dạng HID report.

Bài liên quan

Nguồn tham khảo public

Bài viết này hữu ích với bạn?

Chia sẻ, góp ý, hoặc ủng hộ nếu bạn thấy nội dung này có giá trị.

Góp ý

Nội dung liên quan

Một số bài viết, ghi chú hoặc project có liên quan đến nội dung bạn vừa đọc.

Biến note thành bài viết hoàn chỉnh

Notes là nơi ghi nhanh khái niệm.