30#include "freertos/FreeRTOS.h"
31#include "freertos/task.h"
32#include "freertos/timers.h"
33#include "freertos/queue.h"
38#pragma GCC optimize ("O2")
51 : m_keyboardAvailable(false),
52 m_SCodeToVKConverterTask(nullptr),
53 m_virtualKeyQueue(nullptr),
63 enableVirtualKeys(
false,
false);
67void Keyboard::begin(
bool generateVirtualKeys,
bool createVKQueue,
int PS2Port)
69 PS2Device::begin(PS2Port);
81 m_capsLockLED =
false;
82 m_scrollLockLED =
false;
88 enableVirtualKeys(generateVirtualKeys, createVKQueue);
92void Keyboard::begin(gpio_num_t clkGPIO, gpio_num_t dataGPIO,
bool generateVirtualKeys,
bool createVKQueue)
94 PS2Controller::begin(clkGPIO, dataGPIO);
95 PS2Controller::setKeyboard(
this);
96 begin(generateVirtualKeys, createVKQueue, 0);
100void Keyboard::enableVirtualKeys(
bool generateVirtualKeys,
bool createVKQueue)
102 PS2DeviceLock lock(
this);
105 generateVirtualKeys =
true;
109 if (!m_virtualKeyQueue && createVKQueue)
112 if (!m_SCodeToVKConverterTask && generateVirtualKeys)
113 xTaskCreate(&SCodeToVKConverterTask,
"", Keyboard::scancodeToVirtualKeyTaskStackSize,
this,
FABGLIB_SCODETOVK_TASK_PRIORITY, &m_SCodeToVKConverterTask);
117 if (m_SCodeToVKConverterTask && !generateVirtualKeys) {
118 vTaskDelete(m_SCodeToVKConverterTask);
119 m_SCodeToVKConverterTask =
nullptr;
122 if (m_virtualKeyQueue && !createVKQueue) {
123 vQueueDelete(m_virtualKeyQueue);
124 m_virtualKeyQueue =
nullptr;
130bool Keyboard::reset()
132 memset(m_VKMap, 0,
sizeof(m_VKMap));
135 setLayout(&USLayout);
138 vTaskDelay(350 / portTICK_PERIOD_MS);
141 for (
int i = 0; i < 3; ++i) {
142 m_keyboardAvailable = send_cmdReset();
143 if (m_keyboardAvailable)
145 vTaskDelay(350 / portTICK_PERIOD_MS);
148 vTaskDelay(200 / portTICK_PERIOD_MS);
150 send_cmdSetScancodeSet(2);
152 return m_keyboardAvailable;
156bool Keyboard::setScancodeSet(
int value)
158 if (m_SCodeToVKConverterTask) {
160 if (value == 1 || value == 2) {
161 m_scancodeSet = value;
166 if (send_cmdSetScancodeSet(value)) {
167 m_scancodeSet = value;
175bool Keyboard::setLEDs(
bool numLock,
bool capsLock,
bool scrollLock)
177 m_numLockLED = numLock;
178 m_capsLockLED = capsLock;
179 m_scrollLockLED = scrollLock;
180 return send_cmdLEDs(numLock, capsLock, scrollLock);
184void Keyboard::getLEDs(
bool * numLock,
bool * capsLock,
bool * scrollLock)
186 *numLock = m_numLockLED;
187 *capsLock = m_capsLockLED;
188 *scrollLock = m_scrollLockLED;
192void Keyboard::updateLEDs()
194 send_cmdLEDs(m_NUMLOCK, m_CAPSLOCK, m_SCROLLLOCK);
195 m_numLockLED = m_NUMLOCK;
196 m_capsLockLED = m_CAPSLOCK;
197 m_scrollLockLED = m_SCROLLLOCK;
201int Keyboard::scancodeAvailable()
203 return dataAvailable();
207int Keyboard::getNextScancode(
int timeOutMS,
bool requestResendOnTimeOut)
210 int r = getData(timeOutMS);
211 if (r == -1 && CLKTimeOutError()) {
213 send_cmdEnableScanning();
215 if (r == -1 && requestResendOnTimeOut) {
216 requestToResendLastByte();
230#if FABGLIB_HAS_VirtualKeyO_STRING
231char const * Keyboard::virtualKeyToString(
VirtualKey virtualKey)
233 char const * VKTOSTR[] = {
"VK_NONE",
"VK_SPACE",
"VK_0",
"VK_1",
"VK_2",
"VK_3",
"VK_4",
"VK_5",
"VK_6",
"VK_7",
"VK_8",
"VK_9",
"VK_KP_0",
"VK_KP_1",
"VK_KP_2",
234 "VK_KP_3",
"VK_KP_4",
"VK_KP_5",
"VK_KP_6",
"VK_KP_7",
"VK_KP_8",
"VK_KP_9",
"VK_a",
"VK_b",
"VK_c",
"VK_d",
"VK_e",
"VK_f",
"VK_g",
"VK_h",
235 "VK_i",
"VK_j",
"VK_k",
"VK_l",
"VK_m",
"VK_n",
"VK_o",
"VK_p",
"VK_q",
"VK_r",
"VK_s",
"VK_t",
"VK_u",
"VK_v",
"VK_w",
"VK_x",
"VK_y",
"VK_z",
236 "VK_A",
"VK_B",
"VK_C",
"VK_D",
"VK_E",
"VK_F",
"VK_G",
"VK_H",
"VK_I",
"VK_J",
"VK_K",
"VK_L",
"VK_M",
"VK_N",
"VK_O",
"VK_P",
"VK_Q",
"VK_R",
237 "VK_S",
"VK_T",
"VK_U",
"VK_V",
"VK_W",
"VK_X",
"VK_Y",
"VK_Z",
"VK_GRAVEACCENT",
"VK_ACUTEACCENT",
"VK_QUOTE",
"VK_QUOTEDBL",
"VK_EQUALS",
"VK_MINUS",
"VK_KP_MINUS",
238 "VK_PLUS",
"VK_KP_PLUS",
"VK_KP_MULTIPLY",
"VK_ASTERISK",
"VK_BACKSLASH",
"VK_KP_DIVIDE",
"VK_SLASH",
"VK_KP_PERIOD",
"VK_PERIOD",
"VK_COLON",
239 "VK_COMMA",
"VK_SEMICOLON",
"VK_AMPERSAND",
"VK_VERTICALBAR",
"VK_HASH",
"VK_AT",
"VK_CARET",
"VK_DOLLAR",
"VK_POUND",
"VK_EURO",
"VK_PERCENT",
240 "VK_EXCLAIM",
"VK_QUESTION",
"VK_LEFTBRACE",
"VK_RIGHTBRACE",
"VK_LEFTBRACKET",
"VK_RIGHTBRACKET",
"VK_LEFTPAREN",
"VK_RIGHTPAREN",
"VK_LESS",
241 "VK_GREATER",
"VK_UNDERSCORE",
"VK_DEGREE",
"VK_SECTION",
"VK_TILDE",
"VK_NEGATION",
"VK_LSHIFT",
"VK_RSHIFT",
"VK_LALT",
"VK_RALT",
"VK_LCTRL",
"VK_RCTRL",
242 "VK_LGUI",
"VK_RGUI",
"VK_ESCAPE",
"VK_PRINTSCREEN",
"VK_SYSREQ",
"VK_INSERT",
"VK_KP_INSERT",
"VK_DELETE",
"VK_KP_DELETE",
"VK_BACKSPACE",
"VK_HOME",
"VK_KP_HOME",
"VK_END",
"VK_KP_END",
"VK_PAUSE",
"VK_BREAK",
243 "VK_SCROLLLOCK",
"VK_NUMLOCK",
"VK_CAPSLOCK",
"VK_TAB",
"VK_RETURN",
"VK_KP_ENTER",
"VK_APPLICATION",
"VK_PAGEUP",
"VK_KP_PAGEUP",
"VK_PAGEDOWN",
"VK_KP_PAGEDOWN",
"VK_UP",
"VK_KP_UP",
244 "VK_DOWN",
"VK_KP_DOWN",
"VK_LEFT",
"VK_KP_LEFT",
"VK_RIGHT",
"VK_KP_RIGHT",
"VK_KP_CENTER",
"VK_F1",
"VK_F2",
"VK_F3",
"VK_F4",
"VK_F5",
"VK_F6",
"VK_F7",
"VK_F8",
"VK_F9",
"VK_F10",
"VK_F11",
"VK_F12",
245 "VK_GRAVE_a",
"VK_GRAVE_e",
"VK_ACUTE_e",
"VK_GRAVE_i",
"VK_GRAVE_o",
"VK_GRAVE_u",
"VK_CEDILLA_c",
"VK_ESZETT",
"VK_UMLAUT_u",
246 "VK_UMLAUT_o",
"VK_UMLAUT_a",
"VK_CEDILLA_C",
"VK_TILDE_n",
"VK_TILDE_N",
"VK_UPPER_a",
"VK_ACUTE_a",
"VK_ACUTE_i",
"VK_ACUTE_o",
"VK_ACUTE_u",
"VK_UMLAUT_i",
"VK_EXCLAIM_INV",
"VK_QUESTION_INV",
247 "VK_ACUTE_A",
"VK_ACUTE_E",
"VK_ACUTE_I",
"VK_ACUTE_O",
"VK_ACUTE_U",
"VK_GRAVE_A",
"VK_GRAVE_E",
"VK_GRAVE_I",
"VK_GRAVE_O",
"VK_GRAVE_U",
"VK_INTERPUNCT",
"VK_DIAERESIS",
248 "VK_UMLAUT_e",
"VK_UMLAUT_A",
"VK_UMLAUT_E",
"VK_UMLAUT_I",
"VK_UMLAUT_O",
"VK_UMLAUT_U",
"VK_CARET_a",
"VK_CARET_e",
"VK_CARET_i",
"VK_CARET_o",
"VK_CARET_u",
"VK_CARET_A",
"VK_CARET_E",
249 "VK_CARET_I",
"VK_CARET_O",
"VK_CARET_U",
"VK_ASCII",
251 return VKTOSTR[virtualKey];
260 item.
vk = virtualKey;
265 item.
SHIFT = m_SHIFT;
270 return fabgl::virtualKeyToASCII(item, m_codepage);
278 if (layout ==
nullptr)
289 vk = scancodeToVK(scancode, isExtended, layout->
inherited);
295 if (m_NUMLOCK & !m_SHIFT) {
356 if (layout ==
nullptr)
360 if (!down && isVKDown(in_vk))
367 for (AltVirtualKeyDef
const * def = layout->alternateVK; def->reqVirtualKey !=
VK_NONE; ++def) {
368 if (def->reqVirtualKey == in_vk && isVKDown(def->
virtualKey)) {
379 for (AltVirtualKeyDef
const * def = layout->alternateVK; def->reqVirtualKey !=
VK_NONE; ++def) {
380 if (def->reqVirtualKey == in_vk && def->ctrl == m_CTRL &&
381 def->lalt == m_LALT &&
382 def->ralt == m_RALT &&
383 def->shift == m_SHIFT) {
390 if (vk ==
VK_NONE && layout->inherited)
391 vk = VKtoAlternateVK(in_vk, down, layout->inherited);
393 return vk ==
VK_NONE ? in_vk : vk;
397bool Keyboard::blockingGetVirtualKey(VirtualKeyItem * item)
404 item->SHIFT = m_SHIFT;
406 item->CAPSLOCK = m_CAPSLOCK;
407 item->NUMLOCK = m_NUMLOCK;
408 item->SCROLLLOCK = m_SCROLLLOCK;
410 uint8_t * scode = item->scancode;
412 *scode = getNextScancode();
413 if (*scode == 0xE0) {
415 *(++scode) = getNextScancode(100,
true);
416 if (*scode == 0xF0) {
418 *(++scode) = getNextScancode(100,
true);
419 item->vk = scancodeToVK(*scode,
true);
423 item->vk = scancodeToVK(*scode,
true);
425 }
else if (*scode == 0xE1) {
427 static const uint8_t PAUSECODES[] = {0x14, 0x77, 0xE1, 0xF0, 0x14, 0xF0, 0x77};
428 for (
int i = 0; i <
sizeof(PAUSECODES); ++i) {
429 *(++scode) = getNextScancode(100,
true);
430 if (*scode != PAUSECODES[i])
432 else if (i ==
sizeof(PAUSECODES) - 1)
435 }
else if (*scode == 0xF0) {
437 *(++scode) = getNextScancode(100,
true);
438 item->vk = scancodeToVK(*scode,
false);
442 item->vk = scancodeToVK(*scode,
false);
448 item->vk = manageCAPSLOCK(item->vk);
451 item->vk = VKtoAlternateVK(item->vk, item->down);
467 m_SHIFT = item->down;
475 m_CAPSLOCK = !m_CAPSLOCK;
481 m_NUMLOCK = !m_NUMLOCK;
487 m_SCROLLLOCK = !m_SCROLLLOCK;
499 if (item->vk == *dk) {
500 m_lastDeadKey = item->vk;
504 if (item->vk != m_lastDeadKey && item->vk !=
VK_NONE) {
505 for (DeadKeyVirtualKeyDef
const * dk = m_layout->deadkeysToVK; dk->deadKey !=
VK_NONE; ++dk) {
506 if (item->vk == dk->reqVirtualKey && m_lastDeadKey == dk->deadKey) {
507 item->vk = dk->virtualKey;
511 if (!item->down && (item->vk != m_lastDeadKey) && (item->vk !=
VK_RSHIFT) && (item->vk !=
VK_LSHIFT))
516 if (scode < item->scancode +
sizeof(VirtualKeyItem::scancode) - 1)
520 int ascii = fabgl::virtualKeyToASCII(*item, m_codepage);
521 item->ASCII = ascii > -1 ? ascii : 0;
531 m_VKMap[(int)item.
vk >> 3] |= 1 << ((
int)item.
vk & 7);
533 m_VKMap[(int)item.
vk >> 3] &= ~(1 << ((
int)item.
vk & 7));
536 if (m_virtualKeyQueue) {
537 auto ticksToWait = (m_uiApp ? 0 : portMAX_DELAY);
539 xQueueSendToFront(m_virtualKeyQueue, &item, ticksToWait);
541 xQueueSendToBack(m_virtualKeyQueue, &item, ticksToWait);
546void Keyboard::injectVirtualKey(
VirtualKey virtualKey,
bool keyDown,
bool insert)
549 item.
vk = virtualKey;
552 item.
ASCII = virtualKeyToASCII(virtualKey);
556 item.
SHIFT = m_SHIFT;
561 injectVirtualKey(item, insert);
569 injectVirtualKey(item,
false);
573 uiEvent evt = uiEvent(
nullptr, item.
down ? UIEVT_KEYDOWN : UIEVT_KEYUP);
574 evt.params.key.VK = item.
vk;
575 evt.params.key.ASCII = item.
ASCII;
576 evt.params.key.LALT = item.
LALT;
577 evt.params.key.RALT = item.
RALT;
578 evt.params.key.CTRL = item.
CTRL;
579 evt.params.key.SHIFT = item.
SHIFT;
580 evt.params.key.GUI = item.
GUI;
581 m_uiApp->postEvent(&evt);
627void Keyboard::SCodeToVKConverterTask(
void * pvParameters)
629 Keyboard * keyboard = (Keyboard*) pvParameters;
632 uint8_t ALTNUMValue = 0;
638 if (keyboard->blockingGetVirtualKey(&item)) {
641 keyboard->onVirtualKey(&item.vk, item.down);
646 if (!isALT(item.vk) && keyboard->m_LALT) {
648 int num = convKeypadVKToNum(item.vk);
652 ALTNUMValue = (ALTNUMValue * 10 + num) & 0xff;
656 keyboard->postVirtualKeyItem(item);
658 }
else if (ALTNUMValue > 0 && isALT(item.vk) && !item.down) {
660 keyboard->postVirtualKeyItem(item);
663 item.scancode[0] = 0;
664 item.ASCII = ALTNUMValue;
665 keyboard->postVirtualKeyItem(item);
667 keyboard->postVirtualKeyItem(item);
671 keyboard->postVirtualKeyItem(item);
685 bool r = m_VKMap[(int)virtualKey >> 3] & (1 << ((
int)virtualKey & 7));
689 m_VKMap[(int)virtualKey >> 3] &= ~(1 << ((
int)virtualKey & 7));
697 bool r = (m_SCodeToVKConverterTask && item && xQueueReceive(m_virtualKeyQueue, item, msToTicks(timeOutMS)) == pdTRUE);
698 if (r && m_scancodeSet == 1)
699 convertScancode2to1(item);
704VirtualKey Keyboard::getNextVirtualKey(
bool * keyDown,
int timeOutMS)
707 if (getNextVirtualKey(&item, timeOutMS)) {
709 *keyDown = item.
down;
716int Keyboard::virtualKeyAvailable()
718 return m_virtualKeyQueue ? uxQueueMessagesWaiting(m_virtualKeyQueue) : 0;
722void Keyboard::emptyVirtualKeyQueue()
724 xQueueReset(m_virtualKeyQueue);
731 uint8_t * wpos = rpos;
732 uint8_t * epos = rpos +
sizeof(VirtualKeyItem::scancode);
733 while (*rpos && rpos < epos) {
736 *wpos++ = 0x80 | convScancodeSet2To1(*rpos++);
738 *wpos++ = convScancodeSet2To1(*rpos++);
745uint8_t Keyboard::convScancodeSet2To1(uint8_t code)
748 static const uint8_t S2TOS1[256] = {
749 0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58, 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59,
750 0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a, 0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b,
751 0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c, 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d,
752 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e, 0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f,
753 0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60, 0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61,
754 0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e, 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76,
755 0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b, 0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f,
756 0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45, 0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54,
757 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
758 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
759 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
760 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
761 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
762 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
763 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
764 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
static int scancodeToVirtualKeyTaskStackSize
Stack size of the task that converts scancodes to Virtual Keys Keyboard.
#define FABGLIB_SCODETOVK_TASK_PRIORITY
#define FABGLIB_DEFAULT_SCODETOVK_TASK_STACK_SIZE
#define FABGLIB_KEYBOARD_VIRTUALKEY_QUEUE_SIZE
VirtualKey
Represents each possible real or derived (SHIFT + real) key.
This file contains fabgl::Keyboard definition.
VirtualKeyDef exScancodeToVK[22]
VirtualKeyDef scancodeToVK[86]
KeyboardLayout const * inherited
All in one structure to fully represent a keyboard layout.
Associates scancode to virtualkey.
A struct which contains a virtual key, key state and associated scan code.