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-2021 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 
41 namespace fabgl {
42 
43 
44 
45 
47 
48 
49 
50 Keyboard::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 
61 Keyboard::~Keyboard()
62 {
63  enableVirtualKeys(false, false);
64 }
65 
66 
67 void 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 
92 void 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 
100 void 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
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 
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 
175 bool 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 
184 void Keyboard::getLEDs(bool * numLock, bool * capsLock, bool * scrollLock)
185 {
186  *numLock = m_numLockLED;
187  *capsLock = m_capsLockLED;
188  *scrollLock = m_scrollLockLED;
189 }
190 
191 
192 void 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 
202 {
203  return dataAvailable();
204 }
205 
206 
207 int 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 
225 {
226  m_layout = layout;
227 }
228 
229 
230 #if FABGLIB_HAS_VirtualKeyO_STRING
231 char 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
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 
274 VirtualKey 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 
339 VirtualKey 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 
352 VirtualKey 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 
397 bool 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 
527 void 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 
546 void 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
566 void 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
588 int 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 
627 void 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 
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 
695 bool 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 
704 VirtualKey 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 
717 {
718  return m_virtualKeyQueue ? uxQueueMessagesWaiting(m_virtualKeyQueue) : 0;
719 }
720 
721 
723 {
724  xQueueReset(m_virtualKeyQueue);
725 }
726 
727 
728 void 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 
745 uint8_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
#define FABGLIB_SCODETOVK_TASK_PRIORITY
Definition: fabglconf.h:98
void injectVirtualKey(VirtualKey virtualKey, bool keyDown, bool insert=false)
Adds or inserts a virtual key into the virtual keys queue.
Definition: keyboard.cpp:546
All in one structure to fully represent a keyboard layout.
Definition: kbdlayouts.h:82
void enableVirtualKeys(bool generateVirtualKeys, bool createVKQueue)
Dynamically enables or disables Virtual Keys generation.
Definition: keyboard.cpp:100
bool lock(int timeOutMS)
Gets exclusive access to the device.
Definition: ps2device.cpp:91
VirtualKey deadKeysVK[8]
Definition: kbdlayouts.h:90
VirtualKey virtualKey
Definition: kbdlayouts.h:55
int virtualKeyToASCII(VirtualKey virtualKey)
Converts virtual key to ASCII.
Definition: keyboard.cpp:257
This file contains fabgl::Keyboard definition.
void emptyVirtualKeyQueue()
Empties the virtual keys queue.
Definition: keyboard.cpp:722
void getLEDs(bool *numLock, bool *capsLock, bool *scrollLock)
Gets keyboard LEDs status.
Definition: keyboard.cpp:184
bool isVKDown(VirtualKey virtualKey)
Gets the virtual keys status.
Definition: keyboard.cpp:683
A struct which contains a virtual key, key state and associated scan code.
Definition: fabutils.h:1304
#define FABGLIB_DEFAULT_SCODETOVK_TASK_STACK_SIZE
Definition: fabglconf.h:94
VirtualKey
Represents each possible real or derived (SHIFT + real) key.
Definition: fabutils.h:1036
bool setLEDs(bool numLock, bool capsLock, bool scrollLock)
Sets keyboard LEDs status.
Definition: keyboard.cpp:175
VirtualKeyDef exScancodeToVK[22]
Definition: kbdlayouts.h:87
void begin(gpio_num_t clkGPIO, gpio_num_t dataGPIO, bool generateVirtualKeys=true, bool createVKQueue=true)
Initializes Keyboard specifying CLOCK and DATA GPIOs.
Definition: keyboard.cpp:92
Definition: canvas.cpp:36
VirtualKey getNextVirtualKey(bool *keyDown=nullptr, int timeOutMS=-1)
Gets a virtual key from the queue.
Definition: keyboard.cpp:704
int virtualKeyAvailable()
Gets the number of virtual keys available in the queue.
Definition: keyboard.cpp:716
Associates scancode to virtualkey.
Definition: kbdlayouts.h:53
uint8_t scancode[8]
Definition: fabutils.h:1307
bool reset()
Sends a Reset command to the keyboard.
Definition: keyboard.cpp:130
int getNextScancode(int timeOutMS=-1, bool requestResendOnTimeOut=false)
Gets a scancode from the queue.
Definition: keyboard.cpp:207
DeadKeyVirtualKeyDef deadkeysToVK[60]
Definition: kbdlayouts.h:91
#define FABGLIB_KEYBOARD_VIRTUALKEY_QUEUE_SIZE
Definition: fabglconf.h:130
int scancodeAvailable()
Gets the number of scancodes available in the queue.
Definition: keyboard.cpp:201
static int scancodeToVirtualKeyTaskStackSize
Stack size of the task that converts scancodes to Virtual Keys Keyboard.
Definition: keyboard.h:399
bool postEvent(uiEvent const *event)
Places an event in the event queue and returns without waiting for the receiver to process the event...
Definition: fabui.cpp:609
bool setScancodeSet(int value)
Sets the scancode set.
Definition: keyboard.cpp:156
void setLayout(KeyboardLayout const *layout)
Sets keyboard layout.
Definition: keyboard.cpp:224
KeyboardLayout const * inherited
Definition: kbdlayouts.h:85
VirtualKeyDef scancodeToVK[86]
Definition: kbdlayouts.h:86
static void begin(gpio_num_t port0_clkGPIO, gpio_num_t port0_datGPIO, gpio_num_t port1_clkGPIO=GPIO_UNUSED, gpio_num_t port1_datGPIO=GPIO_UNUSED)
Initializes PS2 device controller.