Ps2KeyboardHost  1.0.1
Allows you to read from one or more PS2-style keyboards on an Arduino.
ps2_UsbTranslator.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 
21 // These translation tables were distilled from here:
22 // http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/translate.pdf
23 // They could certainly be ProgMem, but it's unlikely to matter to anybody,
24 // as if you're implementing a PS2->USB conversion on your Arduino, it's
25 // unlikely you'll be doing anything else that requires a ton of space,
26 // so we'll keep it simple.
27 
28 /*PROGMEM*/ const byte ps2ToUsbMap[] = {
29  0x00, // [00] unused
30  0x42, // [01] F9
31  0x00, // [02] unused
32  0x3e, // [03] F5
33  0x3c, // [04] F3
34  0x3a, // [05] F1
35  0x3b, // [06] F2
36  0x45, // [07] F12
37  0x68, // [08] F13
38  0x43, // [09] F10
39  0x41, // [0a] F8
40  0x3f, // [0b] F6
41  0x3d, // [0c] F4
42  0x2b, // [0d] Tab
43  0x35, // [0e] ` ~
44  0x67, // [0f] Keypad =
45  0x69, // [10] F14
46  0xe2, // [11] Left Alt
47  0xe1, // [12] Left Shift
48  0x00, // [13] unused
49  0xe0, // [14] Left Control
50  0x14, // [15] q Q
51  0x1e, // [16] 1 !
52  0x00, // [17] unused
53  0x6a, // [18] F15
54  0x00, // [19] unused
55  0x1d, // [1a] z Z
56  0x16, // [1b] s S
57  0x04, // [1c] a A
58  0x1a, // [1d] w W
59  0x1f, // [1e] 2 @
60  0x00, // [1f] unused
61  0x6b, // [20] F16
62  0x06, // [21] c C
63  0x1b, // [22] x X
64  0x07, // [23] d D
65  0x08, // [24] e E
66  0x21, // [25] 4 $
67  0x20, // [26] 3 #
68  0x00, // [27] unused
69  0x6c, // [28] F17
70  0x2c, // [29] Space
71  0x19, // [2a] v V
72  0x09, // [2b] f F
73  0x17, // [2c] t T
74  0x15, // [2d] r R
75  0x22, // [2e] 5 %
76  0x00, // [2f] unused
77  0x6d, // [30] F18
78  0x11, // [31] n N
79  0x05, // [32] b B
80  0x0b, // [33] h H
81  0x0a, // [34] g G
82  0x1c, // [35] y Y
83  0x23, // [36] 6 ^
84  0x00, // [37] unused
85  0x6e, // [38] F19
86  0x00, // [39] unused
87  0x10, // [3a] m M
88  0x0d, // [3b] j J
89  0x18, // [3c] u U
90  0x24, // [3d] 7 &
91  0x25, // [3e] 8 *
92  0x00, // [3f] unused
93  0x6f, // [40] F20
94  0x36, // [41] , <
95  0x0e, // [42] k K
96  0x0c, // [43] i I
97  0x12, // [44] o O
98  0x27, // [45] 0 )
99  0x26, // [46] 9 (
100  0x00, // [47] unused
101  0x70, // [48] F21
102  0x37, // [49] . >
103  0x38, // [4a] / ?
104  0x0f, // [4b] l L
105  0x33, // [4c] ; :
106  0x13, // [4d] p P
107  0x2d, // [4e] - _
108  0x00, // [4f] unused
109  0x71, // [50] F22
110  0x00, // [51] unused
111  0x34, // [52] ' "
112  0x00, // [53] unused
113  0x2f, // [54] [ {
114  0x2e, // [55] = +
115  0x00, // [56] unused
116  0x72, // [57] F23
117  0x39, // [58] Caps Lock
118  0xe5, // [59] Right Shift
119  0x28, // [5a] Return
120  0x30, // [5b] ] }
121  0x00, // [5c] unused
122  0x32, // [5d] Europe 1 (Note 2)
123  0x00, // [5e] unused
124  0x73, // [5f] F24
125  0x00, // [60] unused
126  0x64, // [61] Europe 2 (Note 2)
127  0x00, // [62] unused
128  0x00, // [63] unused
129  0x00, // [64] unused
130  0x00, // [65] unused
131  0x2a, // [66] Backspace
132  0x00, // [67] unused
133  0x00, // [68] unused
134  0x59, // [69] Keypad 1 End
135  0x00, // [6a] unused
136  0x5c, // [6b] Keypad 4 Left
137  0x5f, // [6c] Keypad 7 Home
138  0x00, // [6d] unused
139  0x00, // [6e] unused
140  0x00, // [6f] unused
141  0x62, // [70] Keypad 0 Insert
142  0x63, // [71] Keypad . Delete
143  0x5a, // [72] Keypad 2 Down
144  0x5d, // [73] Keypad 5
145  0x5e, // [74] Keypad 6 Right
146  0x60, // [75] Keypad 8 Up
147  0x29, // [76] Escape
148  0x53, // [77] Num Lock
149  0x44, // [78] F11
150  0x57, // [79] Keypad +
151  0x5b, // [7a] Keypad 3 PageDn
152  0x56, // [7b] Keypad -
153  0x55, // [7c] Keypad *
154  0x61, // [7d] Keypad 9 PageUp
155  0x47, // [7e] Scroll Lock <-- HAND EDIT!
156  0x00, // [7f] unused
157  0x00, // [80] unused
158  0x00, // [81] unused
159  0x00, // [82] unused
160  0x40, // [83] F7
161 };
162 
163 // This would probably be tighter as a switch statement.
164 /*PROGMEM*/ const byte extPs2ToUsbMap[] = {
165  0x00, // [00] unused
166  0x00, // [01] unused
167  0x00, // [02] unused
168  0x00, // [03] unused
169  0x00, // [04] unused
170  0x00, // [05] unused
171  0x00, // [06] unused
172  0x00, // [07] unused
173  0x00, // [08] unused
174  0x00, // [09] unused
175  0x00, // [0a] unused
176  0x00, // [0b] unused
177  0x00, // [0c] unused
178  0x00, // [0d] unused
179  0x00, // [0e] unused
180  0x00, // [0f] unused
181  0x00, // [10] unused
182  0xe6, // [11] Right Alt
183  0x00, // [12] unused
184  0x00, // [13] unused
185  0xe4, // [14] Right Control
186  0x00, // [15] unused
187  0x00, // [16] unused
188  0x00, // [17] unused
189  0x00, // [18] unused
190  0x00, // [19] unused
191  0x00, // [1a] unused
192  0x00, // [1b] unused
193  0x00, // [1c] unused
194  0x00, // [1d] unused
195  0x00, // [1e] unused
196  0xe3, // [1f] Left GUI
197  0x00, // [20] unused
198  0x00, // [21] unused
199  0x00, // [22] unused
200  0x00, // [23] unused
201  0x00, // [24] unused
202  0x00, // [25] unused
203  0x00, // [26] unused
204  0xe7, // [27] Right GUI
205  0x00, // [28] unused
206  0x00, // [29] unused
207  0x00, // [2a] unused
208  0x00, // [2b] unused
209  0x00, // [2c] unused
210  0x00, // [2d] unused
211  0x00, // [2e] unused
212  0x65, // [2f] Menu Key
213  0x00, // [30] unused
214  0x00, // [31] unused
215  0x00, // [32] unused
216  0x00, // [33] unused
217  0x00, // [34] unused
218  0x00, // [35] unused
219  0x00, // [36] unused
220  0x00, // [37] unused
221  0x00, // [38] unused
222  0x00, // [39] unused
223  0x00, // [3a] unused
224  0x00, // [3b] unused
225  0x00, // [3c] unused
226  0x00, // [3d] unused
227  0x00, // [3e] unused
228  0x00, // [3f] unused
229  0x00, // [40] unused
230  0x00, // [41] unused
231  0x00, // [42] unused
232  0x00, // [43] unused
233  0x00, // [44] unused
234  0x00, // [45] unused
235  0x00, // [46] unused
236  0x00, // [47] unused
237  0x00, // [48] unused
238  0x00, // [49] unused
239  0x54, // [4a] Keypad / (Note 1)
240  0x00, // [4b] unused
241  0x00, // [4c] unused
242  0x00, // [4d] unused
243  0x00, // [4e] unused
244  0x00, // [4f] unused
245  0x00, // [50] unused
246  0x00, // [51] unused
247  0x00, // [52] unused
248  0x00, // [53] unused
249  0x00, // [54] unused
250  0x00, // [55] unused
251  0x00, // [56] unused
252  0x00, // [57] unused
253  0x00, // [58] unused
254  0x00, // [59] unused
255  0x58, // [5a] Keypad Enter
256  0x00, // [5b] unused
257  0x00, // [5c] unused
258  0x00, // [5d] unused
259  0x00, // [5e] unused
260  0x00, // [5f] unused
261  0x00, // [60] unused
262  0x00, // [61] unused
263  0x00, // [62] unused
264  0x00, // [63] unused
265  0x00, // [64] unused
266  0x00, // [65] unused
267  0x00, // [66] unused
268  0x00, // [67] unused
269  0x00, // [68] unused
270  0x4d, // [69] End (Note 1)
271  0x00, // [6a] unused
272  0x50, // [6b] Left Arrow (Note 1)
273  0x4a, // [6c] Home (Note 1)
274  0x00, // [6d] unused
275  0x00, // [6e] unused
276  0x00, // [6f] unused
277  0x49, // [70] Insert (Note 1)
278  0x4c, // [71] Delete (Note 1)
279  0x51, // [72] Down Arrow (Note 1)
280  0x00, // [73] unused
281  0x4f, // [74] Right Arrow (Note 1)
282  0x52, // [75] Up Arrow (Note 1)
283  0x00, // [76] unused
284  0x00, // [77] unused
285  0x00, // [78] unused
286  0x00, // [79] unused
287  0x4e, // [7a] Page Down (Note 1)
288  0x00, // [7b] unused
289  0x46, // [7c] Print Screen
290  0x4b, // [7d] Page Up (Note 1)
291  0x48, // [7e] Pause (when ctrl is down)
292  0x00, // [7f] unused
293 };
294 
295 static const byte pauseKeySequence[] {
296  0xe1, 0x14, 0x77
297  //0xe1, 0xfc, 0x00, 0x04, 0x14, 0x77
298 };
299 
300 template <typename Diagnostics>
302 {
303  this->isSpecial = false;
304  this->isUnmake = false;
305  this->pauseKeySequenceIndex = 0;
306  this->diagnostics = &diagnostics;
307 }
308 
309 template <typename Diagnostics>
311  isSpecial = false;
312  isUnmake = false;
313 }
314 
315 template <typename Diagnostics>
317 {
319  | (((int)usbLeds & (int)ps2::UsbKeyboardLeds::numLock) ? ps2::KeyboardLeds::numLock : ps2::KeyboardLeds::none)
320  | (((int)usbLeds & (int)ps2::UsbKeyboardLeds::scrollLock) ? ps2::KeyboardLeds::scrollLock : ps2::KeyboardLeds::none);
321 }
322 
323 template <typename Diagnostics>
325 {
326  ps2::UsbKeyAction action;
327  action.hidCode = 0;
329 
330  if (ps2Scan == ps2::KeyboardOutput::unmake)
331  {
332  this->isUnmake = true;
333  return action;
334  }
335 
336  if (ps2Scan == ps2::KeyboardOutput::extend)
337  {
338  this->isSpecial = true;
339  return action;
340  }
341 
342  if (ps2Scan == ps2::KeyboardOutput::sc2_leftShift && this->isSpecial) {
343  // This sequence gets sent in front of keys like left-arrow when the shift key is down.
344  // This information doesn't need to get sent to the USB.
345  this->isSpecial = false;
346  this->isUnmake = false;
347  return action;
348  }
349 
350  byte usbCode = 0;
351  if ((uint8_t)ps2Scan == pauseKeySequence[pauseKeySequenceIndex]) {
352  ++pauseKeySequenceIndex;
353  if (pauseKeySequenceIndex < sizeof(pauseKeySequence))
354  return action;
355 
356  usbCode = 0x48; // The Pause key identifier in USB/HID
357  }
358  else if (this->isSpecial)
359  {
360  usbCode = (uint8_t)ps2Scan < sizeof(extPs2ToUsbMap) ? extPs2ToUsbMap[(uint8_t)ps2Scan] : 0;
361  }
362  else
363  {
364  usbCode = (uint8_t)ps2Scan < sizeof(ps2ToUsbMap) ? ps2ToUsbMap[(uint8_t)ps2Scan] : 0;
365  }
366  pauseKeySequenceIndex = 0;
367 
368  if (usbCode == 0)
369  {
370  diagnostics->noTranslationForKey(this->isSpecial, ps2Scan);
371  this->isUnmake = false;
372  this->isSpecial = false;
373  return action;
374  }
375 
376  action.hidCode = usbCode;
377  action.gesture = this->isUnmake ? ps2::UsbKeyAction::KeyUp : ps2::UsbKeyAction::KeyDown;
378 
379  this->isUnmake = false;
380  this->isSpecial = false;
381 
382  return action;
383 }
enum ps2::UsbKeyAction::@0 gesture
A translated PS2 keystroke - it indicates either a keydown, a key up, or that there should be no imme...
Definition: ps2_UsbTranslator.h:36
UsbKeyAction translatePs2Keycode(ps2::KeyboardOutput ps2Scan)
Examines a scan code (from the default PS2 scan code set) and translates it into the corresponding US...
Definition: ps2_UsbTranslator.hpp:324
const byte ps2ToUsbMap[]
Definition: ps2_UsbTranslator.hpp:28
Definition: ps2_UsbTranslator.h:40
Definition: ps2_UsbTranslator.h:41
KeyboardLeds translateLeds(UsbKeyboardLeds usbLeds)
Definition: ps2_UsbTranslator.hpp:316
void reset()
causes it to forget about any scan codes that it has recorded so far and start fresh.
Definition: ps2_UsbTranslator.hpp:310
UsbKeyboardLeds
The bitfield that describes USB LED&#39;s.
Definition: ps2_UsbTranslator.h:27
KeyboardOutput
Byte-codes sent back from the Ps2 keyboard to the host.
Definition: ps2_KeyboardOutput.h:31
KeyboardLeds
The LED&#39;s available on a standard PS2 keyboard.
Definition: ps2_KeyboardLeds.h:23
Definition: ps2_UsbTranslator.h:39
uint8_t hidCode
Definition: ps2_UsbTranslator.h:37
const byte extPs2ToUsbMap[]
Definition: ps2_UsbTranslator.hpp:164