Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(usb_hid_keyboard): Adds Keyboard Layout and Sends reports just for Modifier Keys #10591

Merged
merged 6 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,16 @@ set(ARDUINO_LIBRARY_USB_SRCS
libraries/USB/src/USBMIDI.cpp
libraries/USB/src/USBHIDMouse.cpp
libraries/USB/src/USBHIDKeyboard.cpp
libraries/USB/src/keyboardLayout/KeyboardLayout_da_DK.cpp
libraries/USB/src/keyboardLayout/KeyboardLayout_de_DE.cpp
libraries/USB/src/keyboardLayout/KeyboardLayout_en_US.cpp
libraries/USB/src/keyboardLayout/KeyboardLayout_es_ES.cpp
libraries/USB/src/keyboardLayout/KeyboardLayout_fr_FR.cpp
libraries/USB/src/keyboardLayout/KeyboardLayout_hu_HU.cpp
libraries/USB/src/keyboardLayout/KeyboardLayout_it_IT.cpp
libraries/USB/src/keyboardLayout/KeyboardLayout_pt_BR.cpp
libraries/USB/src/keyboardLayout/KeyboardLayout_pt_PT.cpp
libraries/USB/src/keyboardLayout/KeyboardLayout_sv_SE.cpp
libraries/USB/src/USBHIDGamepad.cpp
libraries/USB/src/USBHIDConsumerControl.cpp
libraries/USB/src/USBHIDSystemControl.cpp
Expand Down
170 changes: 25 additions & 145 deletions libraries/USB/src/USBHIDKeyboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@
#if CONFIG_TINYUSB_HID_ENABLED

#include "USBHIDKeyboard.h"
#include "keyboardLayout/KeyboardLayout.h"

ESP_EVENT_DEFINE_BASE(ARDUINO_USB_HID_KEYBOARD_EVENTS);
esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait);
esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg);

static const uint8_t report_descriptor[] = {TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(HID_REPORT_ID_KEYBOARD))};

USBHIDKeyboard::USBHIDKeyboard() : hid(HID_ITF_PROTOCOL_KEYBOARD), shiftKeyReports(true) {
USBHIDKeyboard::USBHIDKeyboard() : hid(HID_ITF_PROTOCOL_KEYBOARD), _asciimap(KeyboardLayout_en_US), shiftKeyReports(false) {
static bool initialized = false;
if (!initialized) {
initialized = true;
Expand All @@ -45,7 +46,8 @@ uint16_t USBHIDKeyboard::_onGetDescriptor(uint8_t *dst) {
return sizeof(report_descriptor);
}

void USBHIDKeyboard::begin() {
void USBHIDKeyboard::begin(const uint8_t *layout) {
_asciimap = layout;
hid.begin();
}

Expand Down Expand Up @@ -80,139 +82,6 @@ void USBHIDKeyboard::setShiftKeyReports(bool set) {
shiftKeyReports = set;
}

#define SHIFT 0x80
const uint8_t _asciimap[128] = {
0x00, // NUL
0x00, // SOH
0x00, // STX
0x00, // ETX
0x00, // EOT
0x00, // ENQ
0x00, // ACK
0x00, // BEL
0x2a, // BS Backspace
0x2b, // TAB Tab
0x28, // LF Enter
0x00, // VT
0x00, // FF
0x00, // CR
0x00, // SO
0x00, // SI
0x00, // DEL
0x00, // DC1
0x00, // DC2
0x00, // DC3
0x00, // DC4
0x00, // NAK
0x00, // SYN
0x00, // ETB
0x00, // CAN
0x00, // EM
0x00, // SUB
0x00, // ESC
0x00, // FS
0x00, // GS
0x00, // RS
0x00, // US

0x2c, // ' '
0x1e | SHIFT, // !
0x34 | SHIFT, // "
0x20 | SHIFT, // #
0x21 | SHIFT, // $
0x22 | SHIFT, // %
0x24 | SHIFT, // &
0x34, // '
0x26 | SHIFT, // (
0x27 | SHIFT, // )
0x25 | SHIFT, // *
0x2e | SHIFT, // +
0x36, // ,
0x2d, // -
0x37, // .
0x38, // /
0x27, // 0
0x1e, // 1
0x1f, // 2
0x20, // 3
0x21, // 4
0x22, // 5
0x23, // 6
0x24, // 7
0x25, // 8
0x26, // 9
0x33 | SHIFT, // :
0x33, // ;
0x36 | SHIFT, // <
0x2e, // =
0x37 | SHIFT, // >
0x38 | SHIFT, // ?
0x1f | SHIFT, // @
0x04 | SHIFT, // A
0x05 | SHIFT, // B
0x06 | SHIFT, // C
0x07 | SHIFT, // D
0x08 | SHIFT, // E
0x09 | SHIFT, // F
0x0a | SHIFT, // G
0x0b | SHIFT, // H
0x0c | SHIFT, // I
0x0d | SHIFT, // J
0x0e | SHIFT, // K
0x0f | SHIFT, // L
0x10 | SHIFT, // M
0x11 | SHIFT, // N
0x12 | SHIFT, // O
0x13 | SHIFT, // P
0x14 | SHIFT, // Q
0x15 | SHIFT, // R
0x16 | SHIFT, // S
0x17 | SHIFT, // T
0x18 | SHIFT, // U
0x19 | SHIFT, // V
0x1a | SHIFT, // W
0x1b | SHIFT, // X
0x1c | SHIFT, // Y
0x1d | SHIFT, // Z
0x2f, // [
0x31, // bslash
0x30, // ]
0x23 | SHIFT, // ^
0x2d | SHIFT, // _
0x35, // `
0x04, // a
0x05, // b
0x06, // c
0x07, // d
0x08, // e
0x09, // f
0x0a, // g
0x0b, // h
0x0c, // i
0x0d, // j
0x0e, // k
0x0f, // l
0x10, // m
0x11, // n
0x12, // o
0x13, // p
0x14, // q
0x15, // r
0x16, // s
0x17, // t
0x18, // u
0x19, // v
0x1a, // w
0x1b, // x
0x1c, // y
0x1d, // z
0x2f | SHIFT, // {
0x31 | SHIFT, // |
0x30 | SHIFT, // }
0x35 | SHIFT, // ~
0 // DEL
};

size_t USBHIDKeyboard::pressRaw(uint8_t k) {
uint8_t i;
if (k >= 0xE0 && k < 0xE8) {
Expand All @@ -234,7 +103,7 @@ size_t USBHIDKeyboard::pressRaw(uint8_t k) {
return 0;
}
}
} else {
} else if (_keyReport.modifiers == 0) {
//not a modifier and not a key
return 0;
}
Expand All @@ -255,11 +124,8 @@ size_t USBHIDKeyboard::releaseRaw(uint8_t k) {
_keyReport.keys[i] = 0x00;
}
}
} else {
//not a modifier and not a key
return 0;
}

// Allowing for the release of a modifier key without a corresponding press
sendReport(&_keyReport);
return 1;
}
Expand All @@ -274,19 +140,26 @@ size_t USBHIDKeyboard::press(uint8_t k) {
} else if (k >= 0x80) { // it's a modifier key
_keyReport.modifiers |= (1 << (k - 0x80));
k = 0;
} else { // it's a printing key
} else { // it's a printing key (k is a ASCII 0..127)
k = _asciimap[k];
if (!k) {
return 0;
}
if (k & 0x80) { // it's a capital letter or other character reached with shift
if ((k & SHIFT) == SHIFT) { // it's a capital letter or other character reached with shift
// At boot, some PCs need a separate report with the shift key down like a real keyboard.
if (shiftKeyReports) {
pressRaw(HID_KEY_SHIFT_LEFT);
} else {
_keyReport.modifiers |= 0x02; // the left shift modifier
}
k &= 0x7F;
k &= ~SHIFT;
}
if ((k & ALT_GR) == ALT_GR) {
_keyReport.modifiers |= 0x40; // AltGr = right Alt
k &= ~ALT_GR;
}
if (k == ISO_REPLACEMENT) {
k = ISO_KEY;
}
}
return pressRaw(k);
Expand All @@ -306,15 +179,22 @@ size_t USBHIDKeyboard::release(uint8_t k) {
if (!k) {
return 0;
}
if (k & 0x80) { // it's a capital letter or other character reached with shift
if ((k & SHIFT) == SHIFT) { // it's a capital letter or other character reached with shift
if (shiftKeyReports) {
releaseRaw(k & 0x7F); // Release key without shift modifier
k = HID_KEY_SHIFT_LEFT; // Below, release shift modifier
} else {
_keyReport.modifiers &= ~(0x02); // the left shift modifier
k &= 0x7F;
k &= ~SHIFT;
}
}
if ((k & ALT_GR) == ALT_GR) {
_keyReport.modifiers &= ~(0x40); // AltGr = right Alt
k &= ~ALT_GR;
}
if (k == ISO_REPLACEMENT) {
k = ISO_KEY;
}
}
return releaseRaw(k);
}
Expand Down
37 changes: 34 additions & 3 deletions libraries/USB/src/USBHIDKeyboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,32 @@ typedef union {
uint8_t leds;
} arduino_usb_hid_keyboard_event_data_t;

// Supported keyboard layouts
extern const uint8_t KeyboardLayout_de_DE[];
extern const uint8_t KeyboardLayout_en_US[];
extern const uint8_t KeyboardLayout_es_ES[];
extern const uint8_t KeyboardLayout_fr_FR[];
extern const uint8_t KeyboardLayout_it_IT[];
extern const uint8_t KeyboardLayout_pt_PT[];
extern const uint8_t KeyboardLayout_sv_SE[];
extern const uint8_t KeyboardLayout_da_DK[];
extern const uint8_t KeyboardLayout_hu_HU[];
extern const uint8_t KeyboardLayout_pt_BR[];

#define KEY_LEFT_CTRL 0x80
#define KEY_LEFT_SHIFT 0x81
#define KEY_LEFT_ALT 0x82
#define KEY_LEFT_GUI 0x83
#define KEY_RIGHT_CTRL 0x84
#define KEY_RIGHT_SHIFT 0x85
#define KEY_RIGHT_ALT 0x86
#define KEY_RIGHT_ALT 0x86 // AltGr (Right Alt) Key
#define KEY_RIGHT_GUI 0x87

#define KEY_UP_ARROW 0xDA
#define KEY_DOWN_ARROW 0xD9
#define KEY_LEFT_ARROW 0xD8
#define KEY_RIGHT_ARROW 0xD7
#define KEY_MENU 0xFE
#define KEY_MENU 0xED // "Keyboard Application" in USB standard
#define KEY_SPACE 0x20
#define KEY_BACKSPACE 0xB2
#define KEY_TAB 0xB3
Expand Down Expand Up @@ -111,6 +123,24 @@ typedef union {
#define LED_COMPOSE 0x08
#define LED_KANA 0x10

// Numeric keypad
#define KEY_KP_SLASH 0xDC
#define KEY_KP_ASTERISK 0xDD
#define KEY_KP_MINUS 0xDE
#define KEY_KP_PLUS 0xDF
#define KEY_KP_ENTER 0xE0
#define KEY_KP_1 0xE1
#define KEY_KP_2 0xE2
#define KEY_KP_3 0xE3
#define KEY_KP_4 0xE4
#define KEY_KP_5 0xE5
#define KEY_KP_6 0xE6
#define KEY_KP_7 0xE7
#define KEY_KP_8 0xE8
#define KEY_KP_9 0xE9
#define KEY_KP_0 0xEA
#define KEY_KP_DOT 0xEB

// Low level key report: up to 6 keys and shift, ctrl etc at once
typedef struct {
uint8_t modifiers;
Expand All @@ -122,11 +152,12 @@ class USBHIDKeyboard : public USBHIDDevice, public Print {
private:
USBHID hid;
KeyReport _keyReport;
const uint8_t *_asciimap;
bool shiftKeyReports;

public:
USBHIDKeyboard(void);
void begin(void);
void begin(const uint8_t *layout = KeyboardLayout_en_US);
void end(void);
size_t write(uint8_t k);
size_t write(const uint8_t *buffer, size_t size);
Expand Down
Loading
Loading