Skip to content

Commit

Permalink
feat(usb_hid_keyboard): Adds Keyboard Layout and Sends reports just f…
Browse files Browse the repository at this point in the history
…or Modifier Keys (#10591)

* feat(usb_kb): add keyboard layouts. new pt_br layout

* feat(usb_kb): add kb layout and fixes modifier key press

* feat(usb_kb): update cmakelists.txt to add new kb layout code

* ci(pre-commit): Apply automatic fixes

---------

Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
  • Loading branch information
SuGlider and pre-commit-ci-lite[bot] authored Nov 11, 2024
1 parent 1a8e53f commit 54a7a3e
Show file tree
Hide file tree
Showing 23 changed files with 1,835 additions and 148 deletions.
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

0 comments on commit 54a7a3e

Please sign in to comment.