FabGL
ESP32 Display Controller and Graphics Library
keyboard.cpp
1/*
2 Created by Fabrizio Di Vittorio (fdivitto2013@gmail.com) - <http://www.fabgl.com>
3 Copyright (c) 2019-2022 Fabrizio Di Vittorio.
4 All rights reserved.
5
6
7* Please contact fdivitto2013@gmail.com if you need a commercial license.
8
9
10* This library and related software is available under GPL v3.
11
12 FabGL is free software: you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation, either version 3 of the License, or
15 (at your option) any later version.
16
17 FabGL is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with FabGL. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26
27
28#include <string.h>
29
30#include "freertos/FreeRTOS.h"
31#include "freertos/task.h"
32#include "freertos/timers.h"
33#include "freertos/queue.h"
34
35#include "keyboard.h"
36
37
38#pragma GCC optimize ("O2")
39
40
41namespace fabgl {
42
43
44
45
47
48
49
50Keyboard::Keyboard()
51 : m_keyboardAvailable(false),
52 m_SCodeToVKConverterTask(nullptr),
53 m_virtualKeyQueue(nullptr),
54 m_scancodeSet(2),
55 m_lastDeadKey(VK_NONE),
56 m_codepage(nullptr)
57{
58}
59
60
61Keyboard::~Keyboard()
62{
63 enableVirtualKeys(false, false);
64}
65
66
67void Keyboard::begin(bool generateVirtualKeys, bool createVKQueue, int PS2Port)
68{
69 PS2Device::begin(PS2Port);
70
71 m_CTRL = false;
72 m_LALT = false;
73 m_RALT = false;
74 m_SHIFT = false;
75 m_CAPSLOCK = false;
76 m_GUI = false;
77 m_NUMLOCK = false;
78 m_SCROLLLOCK = false;
79
80 m_numLockLED = false;
81 m_capsLockLED = false;
82 m_scrollLockLED = false;
83
84 m_uiApp = nullptr;
85
86 reset();
87
88 enableVirtualKeys(generateVirtualKeys, createVKQueue);
89}
90
91
92void Keyboard::begin(gpio_num_t clkGPIO, gpio_num_t dataGPIO, bool generateVirtualKeys, bool createVKQueue)
93{
94 PS2Controller::begin(clkGPIO, dataGPIO);
95 PS2Controller::setKeyboard(this);
96 begin(generateVirtualKeys, createVKQueue, 0);
97}
98
99
100void Keyboard::enableVirtualKeys(bool generateVirtualKeys, bool createVKQueue)
101{
102 PS2DeviceLock lock(this);
103
104 if (createVKQueue)
105 generateVirtualKeys = true;
106
107 // create task and queue?
108
109 if (!m_virtualKeyQueue && createVKQueue)
110 m_virtualKeyQueue = xQueueCreate(FABGLIB_KEYBOARD_VIRTUALKEY_QUEUE_SIZE, sizeof(VirtualKeyItem));
111
112 if (!m_SCodeToVKConverterTask && generateVirtualKeys)
113 xTaskCreate(&SCodeToVKConverterTask, "", Keyboard::scancodeToVirtualKeyTaskStackSize, this, FABGLIB_SCODETOVK_TASK_PRIORITY, &m_SCodeToVKConverterTask);
114
115 // destroy in reverse order
116
117 if (m_SCodeToVKConverterTask && !generateVirtualKeys) {
118 vTaskDelete(m_SCodeToVKConverterTask);
119 m_SCodeToVKConverterTask = nullptr;
120 }
121
122 if (m_virtualKeyQueue && !createVKQueue) {
123 vQueueDelete(m_virtualKeyQueue);
124 m_virtualKeyQueue = nullptr;
125 }
126}
127
128
129// reset keyboard, set scancode 2 and US layout
130bool Keyboard::reset()
131{
132 memset(m_VKMap, 0, sizeof(m_VKMap));
133
134 // sets default layout
135 setLayout(&USLayout);
136
137 // 350ms keyboard poweron delay (look at NXP M68HC08 designer reference manual)
138 vTaskDelay(350 / portTICK_PERIOD_MS);
139
140 // tries up to three times to reset keyboard
141 for (int i = 0; i < 3; ++i) {
142 m_keyboardAvailable = send_cmdReset();
143 if (m_keyboardAvailable)
144 break;
145 vTaskDelay(350 / portTICK_PERIOD_MS);
146 }
147 // give the time to the device to be fully initialized
148 vTaskDelay(200 / portTICK_PERIOD_MS);
149
150 send_cmdSetScancodeSet(2);
151
152 return m_keyboardAvailable;
153}
154
155
156bool Keyboard::setScancodeSet(int value)
157{
158 if (m_SCodeToVKConverterTask) {
159 // virtual keys enabled, just 1 and 2 are allowed
160 if (value == 1 || value == 2) {
161 m_scancodeSet = value;
162 return true;
163 }
164 } else {
165 // no virtual keys enabled, just try to tell keyboard which set we need
166 if (send_cmdSetScancodeSet(value)) {
167 m_scancodeSet = value;
168 return true;
169 }
170 }
171 return false;
172}
173
174
175bool Keyboard::setLEDs(bool numLock, bool capsLock, bool scrollLock)
176{
177 m_numLockLED = numLock;
178 m_capsLockLED = capsLock;
179 m_scrollLockLED = scrollLock;
180 return send_cmdLEDs(numLock, capsLock, scrollLock);
181}
182
183
184void Keyboard::getLEDs(bool * numLock, bool * capsLock, bool * scrollLock)
185{
186 *numLock = m_numLockLED;
187 *capsLock = m_capsLockLED;
188 *scrollLock = m_scrollLockLED;
189}
190
191
192void Keyboard::updateLEDs()
193{
194 send_cmdLEDs(m_NUMLOCK, m_CAPSLOCK, m_SCROLLLOCK);
195 m_numLockLED = m_NUMLOCK;
196 m_capsLockLED = m_CAPSLOCK;
197 m_scrollLockLED = m_SCROLLLOCK;
198}
199
200
201int Keyboard::scancodeAvailable()
202{
203 return dataAvailable();
204}
205
206
207int Keyboard::getNextScancode(int timeOutMS, bool requestResendOnTimeOut)
208{
209 while (true) {
210 int r = getData(timeOutMS);
211 if (r == -1 && CLKTimeOutError()) {
212 // try to recover a stall sending a re-enable scanning command
213 send_cmdEnableScanning();
214 }
215 if (r == -1 && requestResendOnTimeOut) {
216 requestToResendLastByte();
217 continue;
218 }
219 return r;
220 }
221}
222
223
224void Keyboard::setLayout(const KeyboardLayout * layout)
225{
226 m_layout = layout;
227}
228
229
230#if FABGLIB_HAS_VirtualKeyO_STRING
231char const * Keyboard::virtualKeyToString(VirtualKey virtualKey)
232{
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",
250 };
251 return VKTOSTR[virtualKey];
252}
253#endif
254
255
256// -1 = virtual key cannot be translated to ASCII
257int Keyboard::virtualKeyToASCII(VirtualKey virtualKey)
258{
259 VirtualKeyItem item;
260 item.vk = virtualKey;
261 item.down = true;
262 item.CTRL = m_CTRL;
263 item.LALT = m_LALT;
264 item.RALT = m_RALT;
265 item.SHIFT = m_SHIFT;
266 item.GUI = m_GUI;
267 item.CAPSLOCK = m_CAPSLOCK;
268 item.NUMLOCK = m_NUMLOCK;
269 item.SCROLLLOCK = m_SCROLLLOCK;
270 return fabgl::virtualKeyToASCII(item, m_codepage);
271}
272
273
274VirtualKey Keyboard::scancodeToVK(uint8_t scancode, bool isExtended, KeyboardLayout const * layout)
275{
276 VirtualKey vk = VK_NONE;
277
278 if (layout == nullptr)
279 layout = m_layout;
280
281 VirtualKeyDef const * def = isExtended ? layout->exScancodeToVK : layout->scancodeToVK;
282 for (; def->scancode; ++def)
283 if (def->scancode == scancode) {
284 vk = def->virtualKey;
285 break;
286 }
287
288 if (vk == VK_NONE && layout->inherited)
289 vk = scancodeToVK(scancode, isExtended, layout->inherited);
290
291 // manage keypad
292 // NUMLOCK ON, SHIFT OFF => generate VK_KP_number
293 // NUMLOCK ON, SHIFT ON => generate VK_KP_cursor_control (as when NUMLOCK is OFF)
294 // NUMLOCK OFF => generate VK_KP_cursor_control
295 if (m_NUMLOCK & !m_SHIFT) {
296 switch (vk) {
297 case VK_KP_DELETE:
298 vk = VK_KP_PERIOD;
299 break;
300 case VK_KP_INSERT:
301 vk = VK_KP_0;
302 break;
303 case VK_KP_END:
304 vk = VK_KP_1;
305 break;
306 case VK_KP_DOWN:
307 vk = VK_KP_2;
308 break;
309 case VK_KP_PAGEDOWN:
310 vk = VK_KP_3;
311 break;
312 case VK_KP_LEFT:
313 vk = VK_KP_4;
314 break;
315 case VK_KP_CENTER:
316 vk = VK_KP_5;
317 break;
318 case VK_KP_RIGHT:
319 vk = VK_KP_6;
320 break;
321 case VK_KP_HOME:
322 vk = VK_KP_7;
323 break;
324 case VK_KP_UP:
325 vk = VK_KP_8;
326 break;
327 case VK_KP_PAGEUP:
328 vk = VK_KP_9;
329 break;
330 default:
331 break;
332 }
333 }
334
335 return vk;
336}
337
338
339VirtualKey Keyboard::manageCAPSLOCK(VirtualKey vk)
340{
341 if (m_CAPSLOCK) {
342 // inverts letters case
343 if (vk >= VK_a && vk <= VK_z)
344 vk = (VirtualKey)(vk - VK_a + VK_A);
345 else if (vk >= VK_A && vk <= VK_Z)
346 vk = (VirtualKey)(vk - VK_A + VK_a);
347 }
348 return vk;
349}
350
351
352VirtualKey Keyboard::VKtoAlternateVK(VirtualKey in_vk, bool down, KeyboardLayout const * layout)
353{
354 VirtualKey vk = VK_NONE;
355
356 if (layout == nullptr)
357 layout = m_layout;
358
359 // this avoids releasing a required key when SHIFT has been pressed after the key but before releasing
360 if (!down && isVKDown(in_vk))
361 vk = in_vk;
362
363 if (vk == VK_NONE) {
364 // handle this case:
365 // - derived KEY up without any SHIFT (because released before the KEY, ie SHIFT+"1" => "!", but you release the SHIFT before "1")
366 // this avoid to maintain a KEY DOWN when you release the SHIFT key before the KEY ()
367 for (AltVirtualKeyDef const * def = layout->alternateVK; def->reqVirtualKey != VK_NONE; ++def) {
368 if (def->reqVirtualKey == in_vk && isVKDown(def->virtualKey)) {
369 vk = def->virtualKey;
370 break;
371 }
372 }
373 }
374
375 if (vk == VK_NONE) {
376 // handle these cases:
377 // - KEY down with SHIFTs already down
378 // - KEY up with SHIFTs still down
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) {
384 vk = def->virtualKey;
385 break;
386 }
387 }
388 }
389
390 if (vk == VK_NONE && layout->inherited)
391 vk = VKtoAlternateVK(in_vk, down, layout->inherited);
392
393 return vk == VK_NONE ? in_vk : vk;
394}
395
396
397bool Keyboard::blockingGetVirtualKey(VirtualKeyItem * item)
398{
399 item->vk = VK_NONE;
400 item->down = true;
401 item->CTRL = m_CTRL;
402 item->LALT = m_LALT;
403 item->RALT = m_RALT;
404 item->SHIFT = m_SHIFT;
405 item->GUI = m_GUI;
406 item->CAPSLOCK = m_CAPSLOCK;
407 item->NUMLOCK = m_NUMLOCK;
408 item->SCROLLLOCK = m_SCROLLLOCK;
409
410 uint8_t * scode = item->scancode;
411
412 *scode = getNextScancode();
413 if (*scode == 0xE0) {
414 // two bytes scancode
415 *(++scode) = getNextScancode(100, true);
416 if (*scode == 0xF0) {
417 // two bytes scancode key up
418 *(++scode) = getNextScancode(100, true);
419 item->vk = scancodeToVK(*scode, true);
420 item->down = false;
421 } else {
422 // two bytes scancode key down
423 item->vk = scancodeToVK(*scode, true);
424 }
425 } else if (*scode == 0xE1) {
426 // special case: "PAUSE" : 0xE1, 0x14, 0x77, 0xE1, 0xF0, 0x14, 0xF0, 0x77
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])
431 break;
432 else if (i == sizeof(PAUSECODES) - 1)
433 item->vk = VK_PAUSE;
434 }
435 } else if (*scode == 0xF0) {
436 // one byte scancode, key up
437 *(++scode) = getNextScancode(100, true);
438 item->vk = scancodeToVK(*scode, false);
439 item->down = false;
440 } else {
441 // one byte scancode, key down
442 item->vk = scancodeToVK(*scode, false);
443 }
444
445 if (item->vk != VK_NONE) {
446
447 // manage CAPSLOCK
448 item->vk = manageCAPSLOCK(item->vk);
449
450 // alternate VK (virtualkeys modified by shift, alt, ...)
451 item->vk = VKtoAlternateVK(item->vk, item->down);
452
453 // update shift, alt, ctrl, capslock, numlock and scrollock states and LEDs
454 switch (item->vk) {
455 case VK_LCTRL:
456 case VK_RCTRL:
457 m_CTRL = item->down;
458 break;
459 case VK_LALT:
460 m_LALT = item->down;
461 break;
462 case VK_RALT:
463 m_RALT = item->down;
464 break;
465 case VK_LSHIFT:
466 case VK_RSHIFT:
467 m_SHIFT = item->down;
468 break;
469 case VK_LGUI:
470 case VK_RGUI:
471 m_GUI = item->down;
472 break;
473 case VK_CAPSLOCK:
474 if (!item->down) {
475 m_CAPSLOCK = !m_CAPSLOCK;
476 updateLEDs();
477 }
478 break;
479 case VK_NUMLOCK:
480 if (!item->down) {
481 m_NUMLOCK = !m_NUMLOCK;
482 updateLEDs();
483 }
484 break;
485 case VK_SCROLLLOCK:
486 if (!item->down) {
487 m_SCROLLLOCK = !m_SCROLLLOCK;
488 updateLEDs();
489 }
490 break;
491 default:
492 break;
493 }
494
495 }
496
497 // manage dead keys - Implemented by Carles Oriol (https://github.com/carlesoriol)
498 for (VirtualKey const * dk = m_layout->deadKeysVK; *dk != VK_NONE; ++dk) {
499 if (item->vk == *dk) {
500 m_lastDeadKey = item->vk;
501 item->vk = VK_NONE;
502 }
503 }
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;
508 break;
509 }
510 }
511 if (!item->down && (item->vk != m_lastDeadKey) && (item->vk != VK_RSHIFT) && (item->vk != VK_LSHIFT))
512 m_lastDeadKey = VK_NONE;
513 }
514
515 // ending zero to item->scancode
516 if (scode < item->scancode + sizeof(VirtualKeyItem::scancode) - 1)
517 *(++scode) = 0;
518
519 // fill ASCII field
520 int ascii = fabgl::virtualKeyToASCII(*item, m_codepage);
521 item->ASCII = ascii > -1 ? ascii : 0;
522
523 return item->vk != VK_NONE;
524}
525
526
527void Keyboard::injectVirtualKey(VirtualKeyItem const & item, bool insert)
528{
529 // update m_VKMap
530 if (item.down)
531 m_VKMap[(int)item.vk >> 3] |= 1 << ((int)item.vk & 7);
532 else
533 m_VKMap[(int)item.vk >> 3] &= ~(1 << ((int)item.vk & 7));
534
535 // has VK queue? Insert VK into it.
536 if (m_virtualKeyQueue) {
537 auto ticksToWait = (m_uiApp ? 0 : portMAX_DELAY); // 0, and not portMAX_DELAY to avoid uiApp locks
538 if (insert)
539 xQueueSendToFront(m_virtualKeyQueue, &item, ticksToWait);
540 else
541 xQueueSendToBack(m_virtualKeyQueue, &item, ticksToWait);
542 }
543}
544
545
546void Keyboard::injectVirtualKey(VirtualKey virtualKey, bool keyDown, bool insert)
547{
548 VirtualKeyItem item;
549 item.vk = virtualKey;
550 item.down = keyDown;
551 item.scancode[0] = 0; // this is a manual insert, not scancode associated
552 item.ASCII = virtualKeyToASCII(virtualKey);
553 item.CTRL = m_CTRL;
554 item.LALT = m_LALT;
555 item.RALT = m_RALT;
556 item.SHIFT = m_SHIFT;
557 item.GUI = m_GUI;
558 item.CAPSLOCK = m_CAPSLOCK;
559 item.NUMLOCK = m_NUMLOCK;
560 item.SCROLLLOCK = m_SCROLLLOCK;
561 injectVirtualKey(item, insert);
562}
563
564
565// inject a virtual key item into virtual key queue calling injectVirtualKey() and into m_uiApp
566void Keyboard::postVirtualKeyItem(VirtualKeyItem const & item)
567{
568 // add into m_virtualKeyQueue and update m_VKMap
569 injectVirtualKey(item, false);
570
571 // need to send events to uiApp?
572 if (m_uiApp) {
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);
582 }
583}
584
585
586// converts keypad virtual key to number (VK_KP_1 = 1, VK_KP_DOWN = 2, etc...)
587// -1 = no convertible
588int Keyboard::convKeypadVKToNum(VirtualKey vk)
589{
590 switch (vk) {
591 case VK_KP_0:
592 case VK_KP_INSERT:
593 return 0;
594 case VK_KP_1:
595 case VK_KP_END:
596 return 1;
597 case VK_KP_2:
598 case VK_KP_DOWN:
599 return 2;
600 case VK_KP_3:
601 case VK_KP_PAGEDOWN:
602 return 3;
603 case VK_KP_4:
604 case VK_KP_LEFT:
605 return 4;
606 case VK_KP_5:
607 case VK_KP_CENTER:
608 return 5;
609 case VK_KP_6:
610 case VK_KP_RIGHT:
611 return 6;
612 case VK_KP_7:
613 case VK_KP_HOME:
614 return 7;
615 case VK_KP_8:
616 case VK_KP_UP:
617 return 8;
618 case VK_KP_9:
619 case VK_KP_PAGEUP:
620 return 9;
621 default:
622 return -1;
623 };
624}
625
626
627void Keyboard::SCodeToVKConverterTask(void * pvParameters)
628{
629 Keyboard * keyboard = (Keyboard*) pvParameters;
630
631 // manage ALT + Keypad num
632 uint8_t ALTNUMValue = 0; // current value (0 = no value, 0 is not allowed)
633
634 while (true) {
635
636 VirtualKeyItem item;
637
638 if (keyboard->blockingGetVirtualKey(&item)) {
639
640 // onVirtualKey may set item.vk = VK_NONE!
641 keyboard->onVirtualKey(&item.vk, item.down);
642
643 if (item.vk != VK_NONE) {
644
645 // manage left-ALT + NUM
646 if (!isALT(item.vk) && keyboard->m_LALT) {
647 // ALT was down, is this a keypad number?
648 int num = convKeypadVKToNum(item.vk);
649 if (num >= 0) {
650 // yes this is a keypad num, if down update ALTNUMValue
651 if (item.down)
652 ALTNUMValue = (ALTNUMValue * 10 + num) & 0xff;
653 } else {
654 // no, back to normal case
655 ALTNUMValue = 0;
656 keyboard->postVirtualKeyItem(item);
657 }
658 } else if (ALTNUMValue > 0 && isALT(item.vk) && !item.down) {
659 // ALT is up and ALTNUMValue contains a valid value, add it
660 keyboard->postVirtualKeyItem(item); // post ALT up
661 item.vk = VK_ASCII;
662 item.down = true;
663 item.scancode[0] = 0;
664 item.ASCII = ALTNUMValue;
665 keyboard->postVirtualKeyItem(item); // ascii key down
666 item.down = false;
667 keyboard->postVirtualKeyItem(item); // ascii key up
668 ALTNUMValue = 0;
669 } else {
670 // normal case
671 keyboard->postVirtualKeyItem(item);
672 }
673
674 }
675
676 }
677
678 }
679
680}
681
682
683bool Keyboard::isVKDown(VirtualKey virtualKey)
684{
685 bool r = m_VKMap[(int)virtualKey >> 3] & (1 << ((int)virtualKey & 7));
686
687 // VK_PAUSE is never released (no scancode sent from keyboard on key up), so when queried it is like released
688 if (virtualKey == VK_PAUSE)
689 m_VKMap[(int)virtualKey >> 3] &= ~(1 << ((int)virtualKey & 7));
690
691 return r;
692}
693
694
695bool Keyboard::getNextVirtualKey(VirtualKeyItem * item, int timeOutMS)
696{
697 bool r = (m_SCodeToVKConverterTask && item && xQueueReceive(m_virtualKeyQueue, item, msToTicks(timeOutMS)) == pdTRUE);
698 if (r && m_scancodeSet == 1)
699 convertScancode2to1(item);
700 return r;
701}
702
703
704VirtualKey Keyboard::getNextVirtualKey(bool * keyDown, int timeOutMS)
705{
706 VirtualKeyItem item;
707 if (getNextVirtualKey(&item, timeOutMS)) {
708 if (keyDown)
709 *keyDown = item.down;
710 return item.vk;
711 }
712 return VK_NONE;
713}
714
715
716int Keyboard::virtualKeyAvailable()
717{
718 return m_virtualKeyQueue ? uxQueueMessagesWaiting(m_virtualKeyQueue) : 0;
719}
720
721
722void Keyboard::emptyVirtualKeyQueue()
723{
724 xQueueReset(m_virtualKeyQueue);
725}
726
727
728void Keyboard::convertScancode2to1(VirtualKeyItem * item)
729{
730 uint8_t * rpos = item->scancode;
731 uint8_t * wpos = rpos;
732 uint8_t * epos = rpos + sizeof(VirtualKeyItem::scancode);
733 while (*rpos && rpos < epos) {
734 if (*rpos == 0xf0) {
735 ++rpos;
736 *wpos++ = 0x80 | convScancodeSet2To1(*rpos++);
737 } else
738 *wpos++ = convScancodeSet2To1(*rpos++);
739 }
740 if (wpos < epos)
741 *wpos = 0;
742}
743
744
745uint8_t Keyboard::convScancodeSet2To1(uint8_t code)
746{
747 // 8042 scancodes set 2 to 1 translation table
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,
765 };
766 return S2TOS1[code];
767}
768
769
770} // end of namespace
static int scancodeToVirtualKeyTaskStackSize
Stack size of the task that converts scancodes to Virtual Keys Keyboard.
Definition: keyboard.h:399
#define FABGLIB_SCODETOVK_TASK_PRIORITY
Definition: fabglconf.h:98
#define FABGLIB_DEFAULT_SCODETOVK_TASK_STACK_SIZE
Definition: fabglconf.h:94
#define FABGLIB_KEYBOARD_VIRTUALKEY_QUEUE_SIZE
Definition: fabglconf.h:134
VirtualKey
Represents each possible real or derived (SHIFT + real) key.
Definition: fabutils.h:1097
@ VK_KP_LEFT
Definition: fabutils.h:1261
@ VK_NUMLOCK
Definition: fabutils.h:1246
@ VK_KP_RIGHT
Definition: fabutils.h:1263
@ VK_KP_PERIOD
Definition: fabutils.h:1190
@ VK_KP_6
Definition: fabutils.h:1118
@ VK_LSHIFT
Definition: fabutils.h:1220
@ VK_KP_5
Definition: fabutils.h:1117
@ VK_KP_END
Definition: fabutils.h:1242
@ VK_RALT
Definition: fabutils.h:1223
@ VK_KP_8
Definition: fabutils.h:1120
@ VK_KP_9
Definition: fabutils.h:1121
@ VK_KP_4
Definition: fabutils.h:1116
@ VK_KP_PAGEDOWN
Definition: fabutils.h:1255
@ VK_LALT
Definition: fabutils.h:1222
@ VK_a
Definition: fabutils.h:1123
@ VK_KP_UP
Definition: fabutils.h:1257
@ VK_KP_1
Definition: fabutils.h:1113
@ VK_z
Definition: fabutils.h:1148
@ VK_PAUSE
Definition: fabutils.h:1243
@ VK_KP_DELETE
Definition: fabutils.h:1237
@ VK_RGUI
Definition: fabutils.h:1227
@ VK_LCTRL
Definition: fabutils.h:1224
@ VK_KP_CENTER
Definition: fabutils.h:1264
@ VK_KP_0
Definition: fabutils.h:1112
@ VK_SCROLLLOCK
Definition: fabutils.h:1245
@ VK_KP_DOWN
Definition: fabutils.h:1259
@ VK_KP_7
Definition: fabutils.h:1119
@ VK_LGUI
Definition: fabutils.h:1226
@ VK_A
Definition: fabutils.h:1149
@ VK_KP_3
Definition: fabutils.h:1115
@ VK_Z
Definition: fabutils.h:1174
@ VK_NONE
Definition: fabutils.h:1098
@ VK_RCTRL
Definition: fabutils.h:1225
@ VK_KP_INSERT
Definition: fabutils.h:1235
@ VK_KP_2
Definition: fabutils.h:1114
@ VK_KP_HOME
Definition: fabutils.h:1240
@ VK_ASCII
Definition: fabutils.h:1372
@ VK_CAPSLOCK
Definition: fabutils.h:1247
@ VK_KP_PAGEUP
Definition: fabutils.h:1253
@ VK_RSHIFT
Definition: fabutils.h:1221
This file contains fabgl::Keyboard definition.
VirtualKeyDef exScancodeToVK[22]
Definition: kbdlayouts.h:87
VirtualKeyDef scancodeToVK[86]
Definition: kbdlayouts.h:86
KeyboardLayout const * inherited
Definition: kbdlayouts.h:85
All in one structure to fully represent a keyboard layout.
Definition: kbdlayouts.h:82
VirtualKey virtualKey
Definition: kbdlayouts.h:55
Associates scancode to virtualkey.
Definition: kbdlayouts.h:53
uint8_t scancode[8]
Definition: fabutils.h:1384
A struct which contains a virtual key, key state and associated scan code.
Definition: fabutils.h:1381