Ps2KeyboardHost  1.0.1
Allows you to read from one or more PS2-style keyboards on an Arduino.
ps2_AnsiTranslator.hpp
Go to the documentation of this file.
1 /*
2 Copyright (C) 2017 Steve Benz <s8878992@hotmail.com>
3 
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8 
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13 
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
17 USA
18 */
19 #pragma once
20 #include <Arduino.h>
21 
22 namespace ps2 {
23  // For reference: http://www.computer-engineering.org/ps2keyboard/scancodes2.html
24  template<typename Diagnostics>
26  '\t', // [0d] Tab
27  '`', // [0e] ` ~
28  '=', // [0f] Keypad =
29  '\0', // [10] F14
30  '\0', // [11] Left Alt
31  '\0', // [12] Left Shift
32  '\0', // [13] unused
33  '\0', // [14] Left Control
34  'q', // [15] q Q
35  '1', // [16] 1 !
36  '\0', // [17] unused
37  '\0', // [18] F15
38  '\0', // [19] unused
39  'z', // [1a] z Z
40  's', // [1b] s S
41  'a', // [1c] a A
42  'w', // [1d] w W
43  '2', // [1e] 2 @
44  '\0', // [1f] unused
45  '\0', // [20] F16
46  'c', // [21] c C
47  'x', // [22] x X
48  'd', // [23] d D
49  'e', // [24] e E
50  '4', // [25] 4 $
51  '3', // [26] 3 #
52  '\0', // [27] unused
53  '\0', // [28] F17
54  ' ', // [29] Space
55  'v', // [2a] v V
56  'f', // [2b] f F
57  't', // [2c] t T
58  'r', // [2d] r R
59  '5', // [2e] 5 %
60  '\0', // [2f] unused
61  '\0', // [30] F18
62  'n', // [31] n N
63  'b', // [32] b B
64  'h', // [33] h H
65  'g', // [34] g G
66  'y', // [35] y Y
67  '6', // [36] 6 ^
68  '\0', // [37] unused
69  '\0', // [38] F19
70  '\0', // [39] unused
71  'm', // [3a] m M
72  'j', // [3b] j J
73  'u', // [3c] u U
74  '7', // [3d] 7 &
75  '8', // [3e] 8 *
76  '\0', // [3f] unused
77  '\0', // [40] F20
78  ',', // [41] , <
79  'k', // [42] k K
80  'i', // [43] i I
81  'o', // [44] o O
82  '0', // [45] 0 )
83  '9', // [46] 9 (
84  '\0', // [47] unused
85  '\0', // [48] F21
86  '.', // [49] . >
87  '/', // [4a] / ?
88  'l', // [4b] l L
89  ';', // [4c] ; :
90  'p', // [4d] p P
91  '-', // [4e] - _
92  '\0', // [4f] unused
93  '\0', // [50] F22
94  '\0', // [51] unused
95  '\'', // [52] ' "
96  '\0', // [53] unused
97  '[', // [54] [ {
98  '=', // [55] = +
99  '\0', // [56] unused
100  '\0', // [57] F23
101  '\0', // [58] Caps Lock
102  '\0', // [59] Right Shift
103  '\r', // [5a] Return
104  ']', // [5b] ] }
105  '\0', // [5c] unused
106  '\\', // [5d] \ |
107  '\0', // [5e] unused
108  '\0', // [5f] F24
109  '\0', // [60] unused
110  '\0', // [61] Europe 2 (Note 2)
111  '\0', // [62] unused
112  '\0', // [63] unused
113  '\0', // [64] unused
114  '\0', // [65] unused
115  '\b', // [66] Backspace
116  '\0', // [67] unused
117  '\0', // [68] unused
118  '1', // [69] Keypad 1 End
119  '\0', // [6a] unused
120  '4', // [6b] Keypad 4 Left
121  '7', // [6c] Keypad 7 Home
122  '\0', // [6d] unused
123  '\0', // [6e] unused
124  '\0', // [6f] unused
125  '0', // [70] Keypad 0 Insert
126  '.', // [71] Keypad . Delete
127  '2', // [72] Keypad 2 Down
128  '5', // [73] Keypad 5
129  '6', // [74] Keypad 6 Right
130  '8', // [75] Keypad 8 Up
131  (char)27, // [76] Escape
132  '\0', // [77] Num Lock
133  '\0', // [78] F11
134  '+', // [79] Keypad +
135  '3', // [7a] Keypad 3 PageDn
136  '-', // [7b] Keypad -
137  '*', // [7c] Keypad *
138  '9', // [7d] Keypad 9 PageUp
139  };
140 
141  template<typename Diagnostics>
142  const byte AnsiTranslator<Diagnostics>::pauseKeySequence[] PROGMEM {
143  0xe1, 0x14, 0x77
144  };
145 
146  template<typename Diagnostics>
148  {
149  this->isSpecial = false;
150  this->isUnmake = false;
151  this->isCtrlDown = false;
152  this->isShiftDown = false;
153  this->isCapsLockMode = false;
154  this->isNumLockMode = false;
155  this->pauseKeySequenceIndex = 0;
156  this->diagnostics = Diagnostics::defaultInstance();
157  }
158 
159  template<typename Diagnostics>
161  {
162  this->isSpecial = false;
163  this->isUnmake = false;
164  this->isCtrlDown = false;
165  this->isShiftDown = false;
166  this->isCapsLockMode = false;
167  this->isNumLockMode = false;
168  this->pauseKeySequenceIndex = 0;
169  this->diagnostics = &diagnostics;
170  }
171 
172  template<typename Diagnostics>
174  this->isSpecial = false;
175  this->isUnmake = false;
176  }
177 
178  template<typename Diagnostics>
180  {
181  if (ps2Scan == KeyboardOutput::unmake)
182  {
183  this->isUnmake = true;
184  return '\0';
185  }
186 
187  if (ps2Scan == KeyboardOutput::extend)
188  {
189  this->isSpecial = true;
190  return '\0';
191  }
192 
193  byte usbCode = 0;
194  if ((uint8_t)ps2Scan == pgm_read_byte(pauseKeySequence + this->pauseKeySequenceIndex)) {
195  ++this->pauseKeySequenceIndex;
196  if (this->pauseKeySequenceIndex < sizeof(pauseKeySequence))
197  return '\0';
198 
199  this->pauseKeySequenceIndex = 0;
200  this->isSpecial = false;
201  this->isUnmake = false;
202  return '\0';
203  }
204 
205  switch (ps2Scan) {
208  this->isShiftDown = !this->isUnmake;
209  break;
210  case KeyboardOutput::sc2_leftCtrl: // sc2_exRightControl
211  this->isCtrlDown = !this->isUnmake;
212  break;
213  }
214 
215  // We have a complete make or unmake sequence here, so we'll reset to be ready for the next key
216  // and we can return when we know something...
217  pauseKeySequenceIndex = 0;
218 
219  if (this->isUnmake || (this->isSpecial && ps2Scan != KeyboardOutput::sc2ex_keypadEnter)) {
220  // We only care about unmakes for modifier keys
221  // None of the extended set are normal characters except for the Keypad Enter key
222  this->isUnmake = false;
223  this->isSpecial = false;
224  return '\0';
225  }
226 
227  switch (ps2Scan) {
229  this->isNumLockMode = !this->isNumLockMode;
230  return '\0';
232  this->isCapsLockMode = !this->isCapsLockMode;
233  return '\0';
234  }
235 
236  char charTranslation = this->rawTranslate(ps2Scan);
237  if (charTranslation == '\0') {
238  return '\0';
239  }
240  else if (!this->isNumLockMode && isKeyAffectedByNumlock(ps2Scan, charTranslation)) {
241  return '\0';
242  }
243  else if (charTranslation >= 'a' && charTranslation <= 'z')
244  {
245  // Shift Caps ToUpper?
246  // F F F
247  // T F T
248  // F T T
249  // T T F
250  if (charTranslation >= 'a' && charTranslation <= 'z' && (this->isShiftDown != this->isCapsLockMode)) {
251  charTranslation = charTranslation - 'a' + 'A';
252  }
253  if (charTranslation >= 'a' && charTranslation <= 'z' && this->isCtrlDown) {
254  charTranslation = charTranslation - 'a' + 1;
255  }
256  }
257  else if (this->isShiftDown) {
258  switch (charTranslation) {
259  case '`':
260  charTranslation = '~';
261  break;
262  case '1':
263  charTranslation = '!';
264  break;
265  case '2':
266  charTranslation = '@';
267  break;
268  case '3':
269  charTranslation = '#';
270  break;
271  case '4':
272  charTranslation = '$';
273  break;
274  case '5':
275  charTranslation = '%';
276  break;
277  case '6':
278  charTranslation = '^';
279  break;
280  case '7':
281  charTranslation = '&';
282  break;
283  case '8':
284  charTranslation = '*';
285  break;
286  case '9':
287  charTranslation = '(';
288  break;
289  case '0':
290  charTranslation = ')';
291  break;
292  case '-':
293  charTranslation = '_';
294  break;
295  case '=':
296  charTranslation = '+';
297  break;
298  case '[':
299  charTranslation = '{';
300  break;
301  case ']':
302  charTranslation = '}';
303  break;
304  case ';':
305  charTranslation = ':';
306  break;
307  case '\'':
308  charTranslation = '"';
309  break;
310  case ',':
311  charTranslation = '<';
312  break;
313  case '.':
314  charTranslation = '>';
315  break;
316  case '/':
317  charTranslation = '?';
318  break;
319  case '\\':
320  charTranslation = '|';
321  break;
322  }
323  }
324 
325  return charTranslation;
326  }
327 
328  template<typename Diagnostics>
330  return ((uint8_t)ps2Scan >= 0x0d && ((uint8_t)ps2Scan - 0x0d) < sizeof(ps2ToAsciiMap))
331  ? (char)pgm_read_byte(ps2ToAsciiMap + (uint8_t)ps2Scan - 0x0d)
332  : '\0';
333  }
334 
335  template<typename Diagnostics>
336  bool AnsiTranslator<Diagnostics>::isKeyAffectedByNumlock(KeyboardOutput ps2Scan, char rawTranslation) {
337  if (ps2Scan < KeyboardOutput::sc2_keypad1)
338  return false;
339  return rawTranslation == '.' || (rawTranslation >= '0' && rawTranslation <= '9');
340  }
341 }
char translatePs2Keycode(ps2::KeyboardOutput ps2Scan)
Processes the given scan code from the keyboard. It only gives you keydown events for keys that have ...
Definition: ps2_AnsiTranslator.hpp:179
Definition: ps2_AnsiTranslator.h:24
This class provides a translation from PS2 incoming scancodes to Ansi. Right now, the name "Ansi" is ...
Definition: ps2_AnsiTranslator.h:39
void reset()
Definition: ps2_AnsiTranslator.hpp:173
KeyboardOutput
Byte-codes sent back from the Ps2 keyboard to the host.
Definition: ps2_KeyboardOutput.h:31
AnsiTranslator()
Definition: ps2_AnsiTranslator.hpp:147
const char AnsiTranslator< Diagnostics >::ps2ToAsciiMap [] PROGMEM
Definition: ps2_AnsiTranslator.hpp:25