PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

712 line
22KB

  1. /*
  2. PS2Keyboard.cpp - PS2Keyboard library
  3. Copyright (c) 2007 Free Software Foundation. All right reserved.
  4. Written by Christian Weichel <info@32leaves.net>
  5. ** Mostly rewritten Paul Stoffregen <paul@pjrc.com> 2010, 2011
  6. ** Modified for use beginning with Arduino 13 by L. Abraham Smith, <n3bah@microcompdesign.com> *
  7. ** Modified for easy interrup pin assignement on method begin(datapin,irq_pin). Cuningan <cuninganreset@gmail.com> **
  8. for more information you can read the original wiki in arduino.cc
  9. at http://www.arduino.cc/playground/Main/PS2Keyboard
  10. or http://www.pjrc.com/teensy/td_libs_PS2Keyboard.html
  11. Version 2.4 (March 2013)
  12. - Support Teensy 3.0, Arduino Due, Arduino Leonardo & other boards
  13. - French keyboard layout, David Chochoi, tchoyyfr at yahoo dot fr
  14. Version 2.3 (October 2011)
  15. - Minor bugs fixed
  16. Version 2.2 (August 2011)
  17. - Support non-US keyboards - thanks to Rainer Bruch for a German keyboard :)
  18. Version 2.1 (May 2011)
  19. - timeout to recover from misaligned input
  20. - compatibility with Arduino "new-extension" branch
  21. - TODO: send function, proposed by Scott Penrose, scooterda at me dot com
  22. Version 2.0 (June 2010)
  23. - Buffering added, many scan codes can be captured without data loss
  24. if your sketch is busy doing other work
  25. - Shift keys supported, completely rewritten scan code to ascii
  26. - Slow linear search replaced with fast indexed table lookups
  27. - Support for Teensy, Arduino Mega, and Sanguino added
  28. This library is free software; you can redistribute it and/or
  29. modify it under the terms of the GNU Lesser General Public
  30. License as published by the Free Software Foundation; either
  31. version 2.1 of the License, or (at your option) any later version.
  32. This library is distributed in the hope that it will be useful,
  33. but WITHOUT ANY WARRANTY; without even the implied warranty of
  34. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  35. Lesser General Public License for more details.
  36. You should have received a copy of the GNU Lesser General Public
  37. License along with this library; if not, write to the Free Software
  38. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  39. */
  40. #include "PS2Keyboard.h"
  41. #define BUFFER_SIZE 45
  42. static volatile uint8_t buffer[BUFFER_SIZE];
  43. static volatile uint8_t head, tail;
  44. static uint8_t DataPin;
  45. static uint8_t CharBuffer=0;
  46. static uint8_t UTF8next=0;
  47. static const PS2Keymap_t *keymap=NULL;
  48. // The ISR for the external interrupt
  49. void ps2interrupt(void)
  50. {
  51. static uint8_t bitcount=0;
  52. static uint8_t incoming=0;
  53. static uint32_t prev_ms=0;
  54. uint32_t now_ms;
  55. uint8_t n, val;
  56. val = digitalRead(DataPin);
  57. now_ms = millis();
  58. if (now_ms - prev_ms > 250) {
  59. bitcount = 0;
  60. incoming = 0;
  61. }
  62. prev_ms = now_ms;
  63. n = bitcount - 1;
  64. if (n <= 7) {
  65. incoming |= (val << n);
  66. }
  67. bitcount++;
  68. if (bitcount == 11) {
  69. uint8_t i = head + 1;
  70. if (i >= BUFFER_SIZE) i = 0;
  71. if (i != tail) {
  72. buffer[i] = incoming;
  73. head = i;
  74. }
  75. bitcount = 0;
  76. incoming = 0;
  77. }
  78. }
  79. static inline uint8_t get_scan_code(void)
  80. {
  81. uint8_t c, i;
  82. i = tail;
  83. if (i == head) return 0;
  84. i++;
  85. if (i >= BUFFER_SIZE) i = 0;
  86. c = buffer[i];
  87. tail = i;
  88. return c;
  89. }
  90. // http://www.quadibloc.com/comp/scan.htm
  91. // http://www.computer-engineering.org/ps2keyboard/scancodes2.html
  92. // These arrays provide a simple key map, to turn scan codes into ISO8859
  93. // output. If a non-US keyboard is used, these may need to be modified
  94. // for the desired output.
  95. //
  96. const PROGMEM PS2Keymap_t PS2Keymap_US = {
  97. // without shift
  98. {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
  99. 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '`', 0,
  100. 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', '1', 0,
  101. 0, 0, 'z', 's', 'a', 'w', '2', 0,
  102. 0, 'c', 'x', 'd', 'e', '4', '3', 0,
  103. 0, ' ', 'v', 'f', 't', 'r', '5', 0,
  104. 0, 'n', 'b', 'h', 'g', 'y', '6', 0,
  105. 0, 0, 'm', 'j', 'u', '7', '8', 0,
  106. 0, ',', 'k', 'i', 'o', '0', '9', 0,
  107. 0, '.', '/', 'l', ';', 'p', '-', 0,
  108. 0, 0, '\'', 0, '[', '=', 0, 0,
  109. 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, ']', 0, '\\', 0, 0,
  110. 0, 0, 0, 0, 0, 0, PS2_BACKSPACE, 0,
  111. 0, '1', 0, '4', '7', 0, 0, 0,
  112. '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
  113. PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
  114. 0, 0, 0, PS2_F7 },
  115. // with shift
  116. {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
  117. 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '~', 0,
  118. 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'Q', '!', 0,
  119. 0, 0, 'Z', 'S', 'A', 'W', '@', 0,
  120. 0, 'C', 'X', 'D', 'E', '$', '#', 0,
  121. 0, ' ', 'V', 'F', 'T', 'R', '%', 0,
  122. 0, 'N', 'B', 'H', 'G', 'Y', '^', 0,
  123. 0, 0, 'M', 'J', 'U', '&', '*', 0,
  124. 0, '<', 'K', 'I', 'O', ')', '(', 0,
  125. 0, '>', '?', 'L', ':', 'P', '_', 0,
  126. 0, 0, '"', 0, '{', '+', 0, 0,
  127. 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '}', 0, '|', 0, 0,
  128. 0, 0, 0, 0, 0, 0, PS2_BACKSPACE, 0,
  129. 0, '1', 0, '4', '7', 0, 0, 0,
  130. '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
  131. PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
  132. 0, 0, 0, PS2_F7 },
  133. 0
  134. };
  135. const PROGMEM PS2Keymap_t PS2Keymap_German = {
  136. // without shift
  137. {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
  138. 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '^', 0,
  139. 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', '1', 0,
  140. 0, 0, 'y', 's', 'a', 'w', '2', 0,
  141. 0, 'c', 'x', 'd', 'e', '4', '3', 0,
  142. 0, ' ', 'v', 'f', 't', 'r', '5', 0,
  143. 0, 'n', 'b', 'h', 'g', 'z', '6', 0,
  144. 0, 0, 'm', 'j', 'u', '7', '8', 0,
  145. 0, ',', 'k', 'i', 'o', '0', '9', 0,
  146. 0, '.', '-', 'l', PS2_o_DIAERESIS, 'p', PS2_SHARP_S, 0,
  147. 0, 0, PS2_a_DIAERESIS, 0, PS2_u_DIAERESIS, '\'', 0, 0,
  148. 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '+', 0, '#', 0, 0,
  149. 0, '<', 0, 0, 0, 0, PS2_BACKSPACE, 0,
  150. 0, '1', 0, '4', '7', 0, 0, 0,
  151. '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
  152. PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
  153. 0, 0, 0, PS2_F7 },
  154. // with shift
  155. {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
  156. 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, PS2_DEGREE_SIGN, 0,
  157. 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'Q', '!', 0,
  158. 0, 0, 'Y', 'S', 'A', 'W', '"', 0,
  159. 0, 'C', 'X', 'D', 'E', '$', PS2_SECTION_SIGN, 0,
  160. 0, ' ', 'V', 'F', 'T', 'R', '%', 0,
  161. 0, 'N', 'B', 'H', 'G', 'Z', '&', 0,
  162. 0, 0, 'M', 'J', 'U', '/', '(', 0,
  163. 0, ';', 'K', 'I', 'O', '=', ')', 0,
  164. 0, ':', '_', 'L', PS2_O_DIAERESIS, 'P', '?', 0,
  165. 0, 0, PS2_A_DIAERESIS, 0, PS2_U_DIAERESIS, '`', 0, 0,
  166. 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '*', 0, '\'', 0, 0,
  167. 0, '>', 0, 0, 0, 0, PS2_BACKSPACE, 0,
  168. 0, '1', 0, '4', '7', 0, 0, 0,
  169. '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
  170. PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
  171. 0, 0, 0, PS2_F7 },
  172. 1,
  173. // with altgr
  174. {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
  175. 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, 0, 0,
  176. 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, '@', 0, 0,
  177. 0, 0, 0, 0, 0, 0, PS2_SUPERSCRIPT_TWO, 0,
  178. 0, 0, 0, 0, PS2_CURRENCY_SIGN, 0, PS2_SUPERSCRIPT_THREE, 0,
  179. 0, 0, 0, 0, 0, 0, 0, 0,
  180. 0, 0, 0, 0, 0, 0, 0, 0,
  181. 0, 0, PS2_MICRO_SIGN, 0, 0, '{', '[', 0,
  182. 0, 0, 0, 0, 0, '}', ']', 0,
  183. 0, 0, 0, 0, 0, 0, '\\', 0,
  184. 0, 0, 0, 0, 0, 0, 0, 0,
  185. 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '~', 0, '#', 0, 0,
  186. 0, '|', 0, 0, 0, 0, PS2_BACKSPACE, 0,
  187. 0, '1', 0, '4', '7', 0, 0, 0,
  188. '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
  189. PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
  190. 0, 0, 0, PS2_F7 }
  191. };
  192. const PROGMEM PS2Keymap_t PS2Keymap_French = {
  193. // without shift
  194. {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
  195. 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, PS2_SUPERSCRIPT_TWO, 0,
  196. 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'a', '&', 0,
  197. 0, 0, 'w', 's', 'q', 'z', PS2_e_ACUTE, 0,
  198. 0, 'c', 'x', 'd', 'e', '\'', '"', 0,
  199. 0, ' ', 'v', 'f', 't', 'r', '(', 0,
  200. 0, 'n', 'b', 'h', 'g', 'y', '-', 0,
  201. 0, 0, ',', 'j', 'u', PS2_e_GRAVE, '_', 0,
  202. 0, ';', 'k', 'i', 'o', PS2_a_GRAVE, PS2_c_CEDILLA, 0,
  203. 0, ':', '!', 'l', 'm', 'p', ')', 0,
  204. 0, 0, PS2_u_GRAVE, 0, '^', '=', 0, 0,
  205. 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '$', 0, '*', 0, 0,
  206. 0, '<', 0, 0, 0, 0, PS2_BACKSPACE, 0,
  207. 0, '1', 0, '4', '7', 0, 0, 0,
  208. '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
  209. PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
  210. 0, 0, 0, PS2_F7 },
  211. // with shift
  212. {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
  213. 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, 0, 0,
  214. 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'A', '1', 0,
  215. 0, 0, 'W', 'S', 'Q', 'Z', '2', 0,
  216. 0, 'C', 'X', 'D', 'E', '4', '3', 0,
  217. 0, ' ', 'V', 'F', 'T', 'R', '5', 0,
  218. 0, 'N', 'B', 'H', 'G', 'Y', '6', 0,
  219. 0, 0, '?', 'J', 'U', '7', '8', 0,
  220. 0, '.', 'K', 'I', 'O', '0', '9', 0,
  221. 0, '/', PS2_SECTION_SIGN, 'L', 'M', 'P', PS2_DEGREE_SIGN, 0,
  222. 0, 0, '%', 0, PS2_DIAERESIS, '+', 0, 0,
  223. 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, PS2_POUND_SIGN, 0, PS2_MICRO_SIGN, 0, 0,
  224. 0, '>', 0, 0, 0, 0, PS2_BACKSPACE, 0,
  225. 0, '1', 0, '4', '7', 0, 0, 0,
  226. '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
  227. PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
  228. 0, 0, 0, PS2_F7 },
  229. 1,
  230. // with altgr
  231. {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
  232. 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, 0, 0,
  233. 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, '@', 0, 0,
  234. 0, 0, 0, 0, 0, 0, '~', 0,
  235. 0, 0, 0, 0, 0 /*PS2_EURO_SIGN*/, '{', '#', 0,
  236. 0, 0, 0, 0, 0, 0, '[', 0,
  237. 0, 0, 0, 0, 0, 0, '|', 0,
  238. 0, 0, 0, 0, 0, '`', '\\', 0,
  239. 0, 0, 0, 0, 0, '@', '^', 0,
  240. 0, 0, 0, 0, 0, 0, ']', 0,
  241. 0, 0, 0, 0, 0, 0, '}', 0,
  242. 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, PS2_CURRENCY_SIGN, 0, '#', 0, 0,
  243. 0, '|', 0, 0, 0, 0, PS2_BACKSPACE, 0,
  244. 0, '1', 0, '4', '7', 0, 0, 0,
  245. '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
  246. PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
  247. 0, 0, 0, PS2_F7 }
  248. };
  249. const PROGMEM PS2Keymap_t PS2Keymap_Spanish = {
  250. // without shift
  251. {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
  252. 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, PS2_MASCULINE_ORDINAL, 0,
  253. 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', '1', 0,
  254. 0, 0, 'z', 's', 'a', 'w', '2', 0,
  255. 0, 'c', 'x', 'd', 'e', '4', '3', 0,
  256. 0, ' ', 'v', 'f', 't', 'r', '5', 0,
  257. 0, 'n', 'b', 'h', 'g', 'y', '6', 0,
  258. 0, 0, 'm', 'j', 'u', '7', '8', 0,
  259. 0, ',', 'k', 'i', 'o', '0', '9', 0,
  260. 0, '.', '-', 'l', 'n', 'p', '\'', 0,
  261. 0, 0, PS2_ACUTE_ACCENT, 0, '`', PS2_INVERTED_EXCLAMATION, 0, 0,
  262. 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '+', 0, PS2_c_CEDILLA, 0, 0,
  263. 0, '<', 0, 0, 0, 0, PS2_BACKSPACE, 0,
  264. 0, '1', 0, '4', '7', 0, 0, 0,
  265. '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
  266. PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
  267. 0, 0, 0, PS2_F7 },
  268. // with shift
  269. {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
  270. 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, PS2_FEMININE_ORDINAL, 0,
  271. 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'Q', '!', 0,
  272. 0, 0, 'Z', 'S', 'A', 'W', '\"', 0,
  273. 0, 'C', 'X', 'D', 'E', '$', PS2_MIDDLE_DOT, 0,
  274. 0, ' ', 'V', 'F', 'T', 'R', '%', 0,
  275. 0, 'N', 'B', 'H', 'G', 'Y', '&', 0,
  276. 0, 0, 'M', 'J', 'U', '/', '(', 0,
  277. 0, ';', 'K', 'I', 'O', '=', ')', 0,
  278. 0, ':', '_', 'L', 'N', 'P', '?', 0,
  279. 0, 0, PS2_DIAERESIS, 0, '^', PS2_INVERTED_QUESTION_MARK, 0, 0,
  280. 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '*', 0, PS2_C_CEDILLA, 0, 0,
  281. 0, '>', 0, 0, 0, 0, PS2_BACKSPACE, 0,
  282. 0, '1', 0, '4', '7', 0, 0, 0,
  283. '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
  284. PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
  285. 0, 0, 0, PS2_F7 },
  286. 1,
  287. // with altgr
  288. {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
  289. 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '\\', 0,
  290. 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', '|', 0,
  291. 0, 0, 'z', 's', 'a', 'w', '@', 0,
  292. 0, 'c', 'x', 'd', PS2_EURO_SIGN, '~', '#', 0,
  293. 0, ' ', 'v', 'f', 't', 'r', '5', 0,
  294. 0, 'n', 'b', 'h', 'g', 'y', PS2_NOT_SIGN, 0,
  295. 0, 0, 'm', 'j', 'u', '7', '8', 0,
  296. 0, ',', 'k', 'i', 'o', '0', '9', 0,
  297. 0, '.', '-', 'l', 'n', 'p', '\'', 0,
  298. 0, 0, '{', 0, '[', PS2_INVERTED_EXCLAMATION, 0, 0,
  299. 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, ']', 0, '}', 0, 0,
  300. 0, '|', 0, 0, 0, 0, PS2_BACKSPACE, 0,
  301. 0, '1', 0, '4', '7', 0, 0, 0,
  302. '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
  303. PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
  304. 0, 0, 0, PS2_F7 }
  305. };
  306. const PROGMEM PS2Keymap_t PS2Keymap_Italian = {
  307. // without shift
  308. {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
  309. 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '\\', 0,
  310. 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', '1', 0,
  311. 0, 0, 'z', 's', 'a', 'w', '2', 0,
  312. 0, 'c', 'x', 'd', 'e', '4', '3', 0,
  313. 0, ' ', 'v', 'f', 't', 'r', '5', 0,
  314. 0, 'n', 'b', 'h', 'g', 'y', '6', 0,
  315. 0, 0, 'm', 'j', 'u', '7', '8', 0,
  316. 0, ',', 'k', 'i', 'o', '0', '9', 0,
  317. 0, '.', '-', 'l', PS2_o_GRAVE, 'p', '\'', 0,
  318. 0, 0, PS2_a_GRAVE, 0, PS2_e_GRAVE, PS2_i_GRAVE, 0, 0,
  319. 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '+', 0, PS2_u_GRAVE, 0, 0,
  320. 0, '<', 0, 0, 0, 0, PS2_BACKSPACE, 0,
  321. 0, '1', 0, '4', '7', 0, 0, 0,
  322. '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
  323. PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
  324. 0, 0, 0, PS2_F7 },
  325. // with shift
  326. {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
  327. 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '|', 0,
  328. 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'Q', '!', 0,
  329. 0, 0, 'Z', 'S', 'A', 'W', '\"', 0,
  330. 0, 'C', 'X', 'D', 'E', '$', PS2_POUND_SIGN, 0,
  331. 0, ' ', 'V', 'F', 'T', 'R', '%', 0,
  332. 0, 'N', 'B', 'H', 'G', 'Y', '&', 0,
  333. 0, 0, 'M', 'J', 'U', '/', '(', 0,
  334. 0, ';', 'K', 'I', 'O', '=', ')', 0,
  335. 0, ':', '_', 'L', PS2_c_CEDILLA, 0, '?', 0,
  336. 0, 0, PS2_DEGREE_SIGN, 0, PS2_e_ACUTE, '^', 0, 0,
  337. 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '*', 0, PS2_SECTION_SIGN, 0, 0,
  338. 0, '>', 0, 0, 0, 0, PS2_BACKSPACE, 0,
  339. 0, '1', 0, '4', '7', 0, 0, 0,
  340. '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
  341. PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
  342. 0, 0, 0, PS2_F7 },
  343. 1,
  344. // with altgr
  345. {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
  346. 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, PS2_NOT_SIGN, 0,
  347. 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', PS2_SUPERSCRIPT_ONE, 0,
  348. 0, 0, 'z', 's', 'a', 'w', PS2_SUPERSCRIPT_TWO, 0,
  349. 0, 'c', 'x', 'd', PS2_EURO_SIGN, PS2_FRACTION_ONE_QUARTER, PS2_SUPERSCRIPT_THREE, 0,
  350. 0, ' ', 'v', 'f', 't', 'r', PS2_FRACTION_ONE_HALF, 0,
  351. 0, 'n', 'b', 'h', 'g', 'y', PS2_NOT_SIGN, 0,
  352. 0, 0, 'm', 'j', 'u', '{', '[', 0,
  353. 0, ',', 'k', 'i', 'o', '}', ']', 0,
  354. 0, '.', '-', 'l', '@', 'p', '\'', 0,
  355. 0, 0, '#', 0, '[', '~', 0, 0,
  356. 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, ']', 0, 0, 0, 0,
  357. 0, PS2_LEFT_DOUBLE_ANGLE_QUOTE, 0, 0, 0, 0, PS2_BACKSPACE, 0,
  358. 0, '1', 0, '4', '7', 0, 0, 0,
  359. '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
  360. PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
  361. 0, 0, 0, PS2_F7 }
  362. };
  363. const PROGMEM PS2Keymap_t PS2Keymap_UK = {
  364. // https://github.com/PaulStoffregen/PS2Keyboard/issues/15
  365. // without shift
  366. {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
  367. 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '`', 0,
  368. 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', '1', 0,
  369. 0, 0, 'z', 's', 'a', 'w', '2', 0,
  370. 0, 'c', 'x', 'd', 'e', '4', '3', 0,
  371. 0, ' ', 'v', 'f', 't', 'r', '5', 0,
  372. 0, 'n', 'b', 'h', 'g', 'y', '6', 0,
  373. 0, 0, 'm', 'j', 'u', '7', '8', 0,
  374. 0, ',', 'k', 'i', 'o', '0', '9', 0,
  375. 0, '.', '/', 'l', ';', 'p', '-', 0,
  376. 0, 0, '\'', 0, '[', '=', 0, 0,
  377. 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, ']', 0, '#', 0, 0,
  378. 0, '\\', 0, 0, 0, 0, PS2_BACKSPACE, 0,
  379. 0, '1', 0, '4', '7', 0, 0, 0,
  380. '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
  381. PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
  382. 0, 0, 0, PS2_F7 },
  383. // with shift
  384. {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
  385. 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, 172 /* ¬ */, 0,
  386. 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'Q', '!', 0,
  387. 0, 0, 'Z', 'S', 'A', 'W', '"', 0,
  388. 0, 'C', 'X', 'D', 'E', '$', 163 /* £ */, 0,
  389. 0, ' ', 'V', 'F', 'T', 'R', '%', 0,
  390. 0, 'N', 'B', 'H', 'G', 'Y', '^', 0,
  391. 0, 0, 'M', 'J', 'U', '&', '*', 0,
  392. 0, '<', 'K', 'I', 'O', ')', '(', 0,
  393. 0, '>', '?', 'L', ':', 'P', '_', 0,
  394. 0, 0, '@', 0, '{', '+', 0, 0,
  395. 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '}', 0, '~', 0, 0,
  396. 0, '|', 0, 0, 0, 0, PS2_BACKSPACE, 0,
  397. 0, '1', 0, '4', '7', 0, 0, 0,
  398. '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
  399. PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
  400. 0, 0, 0, PS2_F7 },
  401. 0
  402. };
  403. #define BREAK 0x01
  404. #define MODIFIER 0x02
  405. #define SHIFT_L 0x04
  406. #define SHIFT_R 0x08
  407. #define ALTGR 0x10
  408. static char get_iso8859_code(void)
  409. {
  410. static uint8_t state=0;
  411. uint8_t s;
  412. char c;
  413. while (1) {
  414. s = get_scan_code();
  415. if (!s) return 0;
  416. if (s == 0xF0) {
  417. state |= BREAK;
  418. } else if (s == 0xE0) {
  419. state |= MODIFIER;
  420. } else {
  421. if (state & BREAK) {
  422. if (s == 0x12) {
  423. state &= ~SHIFT_L;
  424. } else if (s == 0x59) {
  425. state &= ~SHIFT_R;
  426. } else if (s == 0x11 && (state & MODIFIER)) {
  427. state &= ~ALTGR;
  428. }
  429. // CTRL, ALT & WIN keys could be added
  430. // but is that really worth the overhead?
  431. state &= ~(BREAK | MODIFIER);
  432. continue;
  433. }
  434. if (s == 0x12) {
  435. state |= SHIFT_L;
  436. continue;
  437. } else if (s == 0x59) {
  438. state |= SHIFT_R;
  439. continue;
  440. } else if (s == 0x11 && (state & MODIFIER)) {
  441. state |= ALTGR;
  442. }
  443. c = 0;
  444. if (state & MODIFIER) {
  445. switch (s) {
  446. case 0x70: c = PS2_INSERT; break;
  447. case 0x6C: c = PS2_HOME; break;
  448. case 0x7D: c = PS2_PAGEUP; break;
  449. case 0x71: c = PS2_DELETE; break;
  450. case 0x69: c = PS2_END; break;
  451. case 0x7A: c = PS2_PAGEDOWN; break;
  452. case 0x75: c = PS2_UPARROW; break;
  453. case 0x6B: c = PS2_LEFTARROW; break;
  454. case 0x72: c = PS2_DOWNARROW; break;
  455. case 0x74: c = PS2_RIGHTARROW; break;
  456. case 0x4A: c = '/'; break;
  457. case 0x5A: c = PS2_ENTER; break;
  458. default: break;
  459. }
  460. } else if ((state & ALTGR) && keymap->uses_altgr) {
  461. if (s < PS2_KEYMAP_SIZE)
  462. c = pgm_read_byte(keymap->altgr + s);
  463. } else if (state & (SHIFT_L | SHIFT_R)) {
  464. if (s < PS2_KEYMAP_SIZE)
  465. c = pgm_read_byte(keymap->shift + s);
  466. } else {
  467. if (s < PS2_KEYMAP_SIZE)
  468. c = pgm_read_byte(keymap->noshift + s);
  469. }
  470. state &= ~(BREAK | MODIFIER);
  471. if (c) return c;
  472. }
  473. }
  474. }
  475. bool PS2Keyboard::available() {
  476. if (CharBuffer || UTF8next) return true;
  477. CharBuffer = get_iso8859_code();
  478. if (CharBuffer) return true;
  479. return false;
  480. }
  481. void PS2Keyboard::clear() {
  482. CharBuffer = 0;
  483. UTF8next = 0;
  484. }
  485. uint8_t PS2Keyboard::readScanCode(void)
  486. {
  487. return get_scan_code();
  488. }
  489. int PS2Keyboard::read() {
  490. uint8_t result;
  491. result = UTF8next;
  492. if (result) {
  493. UTF8next = 0;
  494. } else {
  495. result = CharBuffer;
  496. if (result) {
  497. CharBuffer = 0;
  498. } else {
  499. result = get_iso8859_code();
  500. }
  501. if (result >= 128) {
  502. UTF8next = (result & 0x3F) | 0x80;
  503. result = ((result >> 6) & 0x1F) | 0xC0;
  504. }
  505. }
  506. if (!result) return -1;
  507. return result;
  508. }
  509. int PS2Keyboard::readUnicode() {
  510. int result;
  511. result = CharBuffer;
  512. if (!result) result = get_iso8859_code();
  513. if (!result) return -1;
  514. UTF8next = 0;
  515. CharBuffer = 0;
  516. return result;
  517. }
  518. PS2Keyboard::PS2Keyboard() {
  519. // nothing to do here, begin() does it all
  520. }
  521. void PS2Keyboard::begin(uint8_t data_pin, uint8_t irq_pin, const PS2Keymap_t &map) {
  522. uint8_t irq_num=255;
  523. DataPin = data_pin;
  524. keymap = &map;
  525. // initialize the pins
  526. #ifdef INPUT_PULLUP
  527. pinMode(irq_pin, INPUT_PULLUP);
  528. pinMode(data_pin, INPUT_PULLUP);
  529. #else
  530. pinMode(irq_pin, INPUT);
  531. digitalWrite(irq_pin, HIGH);
  532. pinMode(data_pin, INPUT);
  533. digitalWrite(data_pin, HIGH);
  534. #endif
  535. #ifdef CORE_INT_EVERY_PIN
  536. irq_num = irq_pin;
  537. #else
  538. switch(irq_pin) {
  539. #ifdef CORE_INT0_PIN
  540. case CORE_INT0_PIN:
  541. irq_num = 0;
  542. break;
  543. #endif
  544. #ifdef CORE_INT1_PIN
  545. case CORE_INT1_PIN:
  546. irq_num = 1;
  547. break;
  548. #endif
  549. #ifdef CORE_INT2_PIN
  550. case CORE_INT2_PIN:
  551. irq_num = 2;
  552. break;
  553. #endif
  554. #ifdef CORE_INT3_PIN
  555. case CORE_INT3_PIN:
  556. irq_num = 3;
  557. break;
  558. #endif
  559. #ifdef CORE_INT4_PIN
  560. case CORE_INT4_PIN:
  561. irq_num = 4;
  562. break;
  563. #endif
  564. #ifdef CORE_INT5_PIN
  565. case CORE_INT5_PIN:
  566. irq_num = 5;
  567. break;
  568. #endif
  569. #ifdef CORE_INT6_PIN
  570. case CORE_INT6_PIN:
  571. irq_num = 6;
  572. break;
  573. #endif
  574. #ifdef CORE_INT7_PIN
  575. case CORE_INT7_PIN:
  576. irq_num = 7;
  577. break;
  578. #endif
  579. #ifdef CORE_INT8_PIN
  580. case CORE_INT8_PIN:
  581. irq_num = 8;
  582. break;
  583. #endif
  584. #ifdef CORE_INT9_PIN
  585. case CORE_INT9_PIN:
  586. irq_num = 9;
  587. break;
  588. #endif
  589. #ifdef CORE_INT10_PIN
  590. case CORE_INT10_PIN:
  591. irq_num = 10;
  592. break;
  593. #endif
  594. #ifdef CORE_INT11_PIN
  595. case CORE_INT11_PIN:
  596. irq_num = 11;
  597. break;
  598. #endif
  599. #ifdef CORE_INT12_PIN
  600. case CORE_INT12_PIN:
  601. irq_num = 12;
  602. break;
  603. #endif
  604. #ifdef CORE_INT13_PIN
  605. case CORE_INT13_PIN:
  606. irq_num = 13;
  607. break;
  608. #endif
  609. #ifdef CORE_INT14_PIN
  610. case CORE_INT14_PIN:
  611. irq_num = 14;
  612. break;
  613. #endif
  614. #ifdef CORE_INT15_PIN
  615. case CORE_INT15_PIN:
  616. irq_num = 15;
  617. break;
  618. #endif
  619. #ifdef CORE_INT16_PIN
  620. case CORE_INT16_PIN:
  621. irq_num = 16;
  622. break;
  623. #endif
  624. #ifdef CORE_INT17_PIN
  625. case CORE_INT17_PIN:
  626. irq_num = 17;
  627. break;
  628. #endif
  629. #ifdef CORE_INT18_PIN
  630. case CORE_INT18_PIN:
  631. irq_num = 18;
  632. break;
  633. #endif
  634. #ifdef CORE_INT19_PIN
  635. case CORE_INT19_PIN:
  636. irq_num = 19;
  637. break;
  638. #endif
  639. #ifdef CORE_INT20_PIN
  640. case CORE_INT20_PIN:
  641. irq_num = 20;
  642. break;
  643. #endif
  644. #ifdef CORE_INT21_PIN
  645. case CORE_INT21_PIN:
  646. irq_num = 21;
  647. break;
  648. #endif
  649. #ifdef CORE_INT22_PIN
  650. case CORE_INT22_PIN:
  651. irq_num = 22;
  652. break;
  653. #endif
  654. #ifdef CORE_INT23_PIN
  655. case CORE_INT23_PIN:
  656. irq_num = 23;
  657. break;
  658. #endif
  659. }
  660. #endif
  661. head = 0;
  662. tail = 0;
  663. if (irq_num < 255) {
  664. attachInterrupt(irq_num, ps2interrupt, FALLING);
  665. }
  666. }