Terminal J - An IBM Model M USB Teensy-based Codable Keyboard Adapter with Arduino Source Code
The goal of this project was to have a USB hardware converter for our IBM Model M and have our own source code. We wanted to have the code base to build upon (rather than use the Soarer's keyboard converter). The code below will compile and run on a Teensy 3.2.The Teensy and the adapter is in the Ethernet jack below.
Image By Raymangold22 - Own work, CC0, https://commons.wikimedia.org/w/index.php?curid=37410391
Our hardware:
We used an Ethernet RJ45 Keystone jack because we didn't want to cut the plug off of the Model M.
Wiring:
- Teensy to Ethernet Adapter
- GND – (Ethernet 6) GND
- Pin 2 – (Ethernet 5) CLK
- Pin 3 – (Ethernet 4) Data
- VIN – (Ethernet 3) 5V
Notes:
- When you setup your Teensy, be sure to select USB Type: "Keyboard".
- On the Ethernet jack, 1, 2, 7, and 8 are not used.
- Also Pin 2 and 3 may be reversed in the RJ45 in case yours is different.
This post is also at: Wordpress, Google, GitHub.
The code:
/*
IBM Model M Keyboard Scancode Converter
By J Pagliaccio
Parts of this code came from the PS2Keyboard library.
PS2Keyboard.h - PS2Keyboard library
Copyright (c) 2007 Free Software Foundation. All right reserved.
Written by Christian Weichel
** Mostly rewritten Paul Stoffregen , June 2010
** Modified for use with Arduino 13 by L. Abraham Smith, *
** Modified for easy interrup pin assignement on method begin(datapin,irq_pin). Cuningan **
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
For Jules.
Notes
--------------------------------------------------------
This was written for the IBM Model M Keyboard - early version without the LEDs
and the RJ-45 plug.
This was written and tested using the Teensey 3.2.
Use F1 to set debug mode and pressing escape unsets it.
Its off by default staring in beta 00.00.01
ESC - to escape from special keys mode
Shift Hold is reboot
ESC is debug off
F1 is debug on
Left Reset = ALT
Right Reset is CTRL
BLANK 1 is dump
Blank 2 is clear
ATTEN is Alex
If you want no modifier keys pressed, use a zero.
Keyboard.set_modifier(0);
To press just one modifier is simple.
Keyboard.set_modifier(MODIFIERKEY_SHIFT);
To press more than one modifier, use the logic OR operator. For example:
Keyboard.set_modifier(MODIFIERKEY_CTRL | MODIFIERKEY_ALT);
Key send code
57985 hibernate and shut down
57986 sleep (quick)
58509 win media center
58592 Vol Up
58594 Vol ???
58601 vol up
58602 vol down
58755 media player
58762 outlook email
58770 calculator
58772 open windows explorer - my computer
58913 search
58914 google search
*/
#define KEY_INTERNET_SEARCH 58915
#define KEY_CALCULATOR 58770
#define KEY_SLEEP 57986
#define KEY_SHUTDOWN 58000
#define KEY_VOL_UP 58592
#define KEY_VOL_DOWN 58602
//#include "PS2Keyboard.h"
#define PROGNAME "IBM Model M Keyboard Scancode Converter v00.00.01"
// Map the key to the decimal scan code and it works
// eg: #define KEY_VOL_UP 61447 is a lower case d, Hex: F007
// 59600
// F9 Dec: 71, E0 7A 57466
//#define KEY_VOL_UP 58000
// F10 Decimal in is 79,
//#define KEY_VOL_DN 57505
// 57394
const int ledPin = 13;
int clockPin = 2;
int dataPin = 3;
int first_bit_test = 0;
int counter = 0;
int numbits = 11;
bool debug = false;
static uint8_t incoming = 0;
//#define BUFFER_SIZE 45
//static volatile uint8_t buffer[BUFFER_SIZE];
//static volatile uint8_t head, tail;
bool shift = false;
bool ctrl = false;
bool alt = false;
bool caps = false;
bool ledState = false;
#define BUFMAX 9999
char keyBuffer[BUFMAX];
int keyBufferPos = 0;
unsigned long previousMillis = 0L;
unsigned long interval = 1000L;
// 58000
unsigned long b = 0;
//
// Setup
//----------------------------------------------------------
//
void setup() {
pinMode(dataPin, INPUT);
pinMode(clockPin, INPUT);
pinMode(ledPin, OUTPUT);
Serial.begin(115200);
delay(10);
Serial.println(PROGNAME);
digitalWrite(ledPin, HIGH);
delay(99);
digitalWrite(ledPin, LOW);
delay(99);
digitalWrite(ledPin, HIGH);
delay(99);
digitalWrite(ledPin, LOW);
Serial.print("KEY_PRINTSCREEN = ");
Serial.println(KEY_PRINTSCREEN);
attachInterrupt(clockPin, ps2interrupt, FALLING);
}
//
// The main loop
//----------------------------------------------------------
//
void loop() {
if (digitalRead(clockPin) == LOW && first_bit_test == 0 && counter < numbits) {
first_bit_test = 1;
digitalWrite(ledPin, HIGH);
// data = data >> 1;
//if (digitalRead(dataPin) == HIGH) {
// bitSet(data, 7);
// }
counter++;
}
if (digitalRead(clockPin) == HIGH && first_bit_test == 1) {
first_bit_test = 0;
}
if (counter >= numbits) {
if (debug) {
Serial.print("Incoming decimal = ");
Serial.println(incoming);
}
process_key(int(incoming));
digitalWrite(ledPin, LOW);
incoming = 0;
counter = 0;
}
if (millis() - previousMillis > interval) {
previousMillis = millis();
// if the LED is off turn it on and vice-versa:
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
digitalWrite(ledPin, ledState);
}
}
//
// The interrupt service routine from the clock pin
//----------------------------------------------------------
//
void ps2interrupt(void)
{
static uint8_t bitcount = 0;
static uint32_t prev_millis = 0;
uint32_t now_millis;
uint8_t n, val;
val = digitalRead(dataPin);
// get the milliseconds since boot
now_millis = millis();
// See if its been more than one millisecond since we had an inturrupt
if (now_millis - prev_millis > 1) {
bitcount = 0;
incoming = 0;
}
prev_millis = now_millis;
n = bitcount - 1;
if (n <= 7) {
incoming |= (val << n);
}
bitcount++;
// The scan code size
if (bitcount == 11) {
bitcount = 0;
}
}
//
// Process - eg: remap the key inputs
//----------------------------------------------------------
//
void process_key(int r)
{
long s = 0L;
char c = 0;
switch (r) {
case 7: s = KEY_F1;
debug = true;
break;
case 8: s = KEY_ESC; // escape
debug = false;
Keyboard.releaseAll();
Keyboard.set_modifier(0);
keyBufferPos = 0;
c = 0;
break;
case 13: s = KEY_TAB; break;
case 14: s = KEY_TILDE; break;
case 17: // Left Enter is now LEFT_CTRL
if (ctrl == false) {
ctrl = true;
//Keyboard.press(KEY_LEFT_CTRL);
Keyboard.set_modifier(MODIFIERKEY_CTRL);
} else {
ctrl = false;
//Keyboard.release(KEY_LEFT_CTRL);
Keyboard.set_modifier(0);
Keyboard.set_key1(0);
Keyboard.send_now();
}
// see 240 for release all
break;
case 18: // Left Shift
if (shift == false) {
//Keyboard.press(KEY_LEFT_SHIFT);
Keyboard.set_modifier(MODIFIERKEY_SHIFT);
shift = true;
} else {
Keyboard.releaseAll();
Keyboard.set_modifier(0);
Keyboard.set_key1(0);
Keyboard.send_now();
shift = false;
}
break;
case 20:
s = KEY_CAPS_LOCK;
break;
case 21: s = KEY_Q; c = 'q'; break;
case 22: s = KEY_1; c = '1'; break;
case 25: // Left Alt
if (alt == false) {
Keyboard.set_modifier(MODIFIERKEY_ALT);
alt = true;
} else {
Keyboard.set_modifier(0);
Keyboard.set_key1(0);
Keyboard.send_now();
alt = false;
}
break; // ALT
case 26: s = KEY_Z; c = 'z'; break;
case 27: s = KEY_S; c = 's'; break;
case 28: s = KEY_A; c = 'a'; break;
case 29: s = KEY_W; c = 'w'; break;
case 30: s = KEY_2; c = '2'; break;
case 33: s = KEY_C; c = 'c'; break;
case 34: s = KEY_X; c = 'x'; break;
case 35: s = KEY_D; c = 'd'; break;
case 36: s = KEY_E; c = 'e'; break;
case 37: s = KEY_4; c = '4'; break;
case 38: s = KEY_3; c = '3'; break;
case 41: s = KEY_SPACE; c = ' '; break;
case 42: s = KEY_V; c = 'v'; break;
case 43: s = KEY_F; c = 'f'; break;
case 44: s = KEY_T; c = 't'; break;
case 45: s = KEY_R; c = 'r'; break;
case 46: s = KEY_5; c = '5'; break;
case 49: s = KEY_N; c = 'n'; break;
case 50: s = KEY_B; c = 'b'; break;
case 51: s = KEY_H; c = 'h'; break;
case 52: s = KEY_G; c = 'g'; break;
case 53: s = KEY_Y; c = 'y'; break;
case 54: s = KEY_6; c = '6'; break;
case 57: // Right ALT
if (alt == false) {
Keyboard.set_modifier(MODIFIERKEY_ALT);
alt = true;
} else {
Keyboard.set_modifier(0);
Keyboard.set_key1(0);
Keyboard.send_now();
alt = false;
}
break;
case 58: s = KEY_M; c = 'm'; break;
case 59: s = KEY_J; c = 'j'; break;
case 60: s = KEY_U; c = 'u'; break;
case 61: s = KEY_7; c = '7'; break;
case 62: s = KEY_8; c = '8'; break;
case 65: s = KEY_COMMA; c = ','; break;
case 66: s = KEY_K; c = 'k'; break;
case 67: s = KEY_I; c = 'i'; break;
case 68: s = KEY_O; c = 'o'; break;
case 69: s = KEY_0; c = '0'; break;
case 70: s = KEY_9; c = '9'; break;
case 71: // F9
s = KEY_VOL_DOWN;
c = '?';
break;
case 73: s = KEY_PERIOD; c = '.'; break;
case 74: s = KEY_SLASH; c = '/'; break;
case 75: s = KEY_L; c = 'l'; break;
case 76: s = KEY_SEMICOLON; c = ';'; break;
case 77: s = KEY_P; c = 'p'; break;
case 78: s = KEY_MINUS; c = '-'; break;
case 79: // F10
s = KEY_VOL_UP;
break;
case 82: s = KEY_QUOTE; c = '"'; break;
case 84: s = KEY_LEFT_BRACE; c = '['; break;
case 85: s = KEY_EQUAL; c = '='; break;
case 86: // F11
s = KEY_INTERNET_SEARCH;
break;
case 87: s = KEY_PRINTSCREEN; break;
case 88: // Right Reset is CTRL
if (ctrl == false) {
ctrl = true;
Keyboard.set_modifier(MODIFIERKEY_CTRL);
} else {
ctrl = false;
Keyboard.set_modifier(0);
Keyboard.set_key1(0);
Keyboard.send_now();
}
break;
case 89: //Keyboard.press(KEY_RIGHT_SHIFT);
if (shift == false) {
Keyboard.set_modifier(MODIFIERKEY_SHIFT);
shift = true;
} else {
Keyboard.set_modifier(0);
Keyboard.set_key1(0);
Keyboard.send_now();
shift = false;
}
break;
case 90: s = KEY_ENTER; c = '\n'; break;
case 91: s = KEY_RIGHT_BRACE; c = ']'; break;
case 92: s = KEY_BACKSLASH; c = '\\'; break;
case 93: s = KEY_QUOTE; c = '"'; break;
case 94: // F12
s = KEY_CALCULATOR;
break;
case 95: s = KEY_PRINTSCREEN; break;
case 96: s = KEY_DOWN_ARROW; break;
case 97: s = KEY_LEFT_ARROW; break;
case 98: // HOLD and Shift Hold Key
if (shift) {
SCB_AIRCR = 0x05FA0004; // software reset
}
break;
case 99: s = KEY_UP_ARROW; break;
case 100: s = KEY_DELETE; break;
case 101: s = KEY_END; break;
case 102: s = KEY_BACKSPACE; break;
case 103: s = KEY_INSERT; break;
case 105: s = KEY_1; c = '1'; break;
case 106: s = KEY_RIGHT_ARROW; break;
case 107: s = KEY_4; c = '4'; break;
case 108: s = KEY_7; c = '7'; break;
case 109: s = KEY_PAGE_DOWN; break;
case 110: s = KEY_HOME; break;
case 111: s = KEY_PAGE_UP; break;
case 112: s = KEY_0; c = '0'; break;
case 113: s = KEY_PERIOD; c = '.'; break;
case 114: s = KEY_2; c = '2'; break;
case 115: s = KEY_5; c = '5'; break;
case 116: s = KEY_6; c = '6'; break;
case 117: s = KEY_8; c = '8'; break;
case 118:
// Display the keystroke buffer to the output
Keyboard.print(keyBuffer);
break;
case 119:
// Empty the keystroke buffer
keyBufferPos = 0;
break;
case 120: // F11
s = KEY_INTERNET_SEARCH;
break;
// case 121: s = KEY_PLUS; break;
case 122: s = KEY_3; c = '3'; break;
case 123: s = KEY_MINUS; c = '-'; break;
case 125: s = KEY_9; c = '9'; break;
case 126: s = KEY_SCROLL_LOCK; break;
case 131: s = KEY_F7; break;
case 132:
Keyboard.print("Alex19 isn't so great? Are you kidding me? ");
Keyboard.print("When was the last time you saw a player with such an ability and movement with fox? ");
Keyboard.print("Alex puts the game in another level, and we will be blessed if we ever see a player with his skill ");
Keyboard.print("and passion for the game again. mang0 breaks records. Armada breaks records. ");
Keyboard.println("Alex19 breaks the rules. You can keep your statistics. I prefer the magic.");
break;
case 240: // the release of a modal key
Keyboard.set_modifier(0);
Keyboard.set_key1(0);
Keyboard.send_now();
Keyboard.releaseAll();
break;
default: break;
}
// save these keystrokes
if (keyBufferPos < BUFMAX && c) {
keyBuffer[keyBufferPos++] = c;
keyBuffer[keyBufferPos + 1] = 0;
}
// If the scan code is not zero
// It will be zero/null for the special keys and skip this
if (s) {
if (debug) {
Serial.print(" Scan code = ");
Serial.println(s);
}
// otherwise - for all normal keys we do this
Keyboard.press(s);
Keyboard.release(s);
}
}
This is end of the main code.
Here is the "Full" include file. A lot of it is commented out or not used but it's good for reference.
This is the start of the header include file.
/*
IBM Model M Keyboard scan code converter
Parts of this code came from the PS2Keyboard library
PS2Keyboard.h - PS2Keyboard library
Copyright (c) 2007 Free Software Foundation. All right reserved.
Written by Christian Weichel
** Mostly rewritten Paul Stoffregen , June 2010
** Modified for use with Arduino 13 by L. Abraham Smith, *
** Modified for easy interrup pin assignement on method begin(datapin,irq_pin). Cuningan **
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
Key Hexadecimal value Decimal value
KEY_LEFT_CTRL 0x80 128
KEY_LEFT_SHIFT 0x81 129
KEY_LEFT_ALT 0x82 130
KEY_LEFT_GUI 0x83 131
KEY_RIGHT_CTRL 0x84 132
KEY_RIGHT_SHIFT 0x85 133
KEY_RIGHT_ALT 0x86 134
KEY_RIGHT_GUI 0x87 135
KEY_UP_ARROW 0xDA 218
KEY_DOWN_ARROW 0xD9 217
KEY_LEFT_ARROW 0xD8 216
KEY_RIGHT_ARROW 0xD7 215
KEY_BACKSPACE 0xB2 178
KEY_TAB 0xB3 179
KEY_RETURN 0xB0 176
KEY_ESC 0xB1 177
KEY_INSERT 0xD1 209
KEY_DELETE 0xD4 212
KEY_PAGE_UP 0xD3 211
KEY_PAGE_DOWN 0xD6 214
KEY_HOME 0xD2 210
KEY_END 0xD5 213
KEY_CAPS_LOCK 0xC1 193
KEY_F1 0xC2 194
KEY_F2 0xC3 195
KEY_F3 0xC4 196
KEY_F4 0xC5 197
KEY_F5 0xC6 198
KEY_F6 0xC7 199
KEY_F7 0xC8 200
KEY_F8 0xC9 201
KEY_F9 0xCA 202
KEY_F10 0xCB 203
KEY_F11 0xCC 204
KEY_F12 0xCD 205
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* Modifier key bit values */
#define MODBIT_LEFT_CTRL 0x01
#define MODBIT_LEFT_SHIFT 0x02
#define MODBIT_LEFT_ALT 0x04
#define MODBIT_LEFT_GUI 0x08
#define MODBIT_RIGHT_CTRL 0x10
#define MODBIT_RIGHT_SHIFT 0x20
#define MODBIT_RIGHT_ALT 0x40
#define MODBIT_RIGHT_GUI 0x80
/* From USB HID Usage Tables Version 1.12, Section 10 */
#define KEY_NONE 0
#define KEY_ErrorRollOver 1
#define KEY_POSTFail 2
#define KEY_ErrorUndefined 3
#define KEY_A 4
#define KEY_B 5
#define KEY_C 6
#define KEY_D 7
#define KEY_E 8
#define KEY_F 9
#define KEY_G 10
#define KEY_H 11
#define KEY_I 12
#define KEY_J 13
#define KEY_K 14
#define KEY_L 15
#define KEY_M 16
#define KEY_N 17
#define KEY_O 18
#define KEY_P 19
#define KEY_Q 20
#define KEY_R 21
#define KEY_S 22
#define KEY_T 23
#define KEY_U 24
#define KEY_V 25
#define KEY_W 26
#define KEY_X 27
#define KEY_Y 28
#define KEY_Z 29
#define KEY_1 30
#define KEY_2 31
#define KEY_3 32
#define KEY_4 33
#define KEY_5 34
#define KEY_6 35
#define KEY_7 36
#define KEY_8 37
#define KEY_9 38
#define KEY_0 39
#define KEY_ENTER 40
#define KEY_ESC 41
#define KEY_BACKSPACE 42
#define KEY_TAB 43
#define KEY_SPACE 44
#define KEY_MINUS 45 /* And underscore */
#define KEY_EQUALS 46 /* And plus */
#define KEY_OPEN_SQUARE 47 /* And open-curly-bracket */
#define KEY_CLOSE_SQUARE 48 /* And close-curly-bracket */
#define KEY_BACKSLASH 49
#define KEY_HASH_TILDE 50
#define KEY_SEMICOLON 51
#define KEY_SINGLE_QUOTE 52
#define KEY_BACKTICK_TILDE 53
#define KEY_COMMA 54 /* And less-than */
#define KEY_PERIOD 55 /* And greater-than */
#define KEY_SLASH 56 /* And question-mark */
#define KEY_CAPS_LOCK 57
#define KEY_F1 58
#define KEY_F2 59
#define KEY_F3 60
#define KEY_F4 61
#define KEY_F5 62
#define KEY_F6 63
#define KEY_F7 64
#define KEY_F8 65
#define KEY_F9 66
#define KEY_F10 67
#define KEY_F11 68
#define KEY_F12 69
#define KEY_PRINT_SCREEN 70
#define KEY_SCROLL_LOCK 71
#define KEY_PAUSE 72
#define KEY_INSERT 73
#define KEY_HOME 74
#define KEY_PAGE_UP 75
#define KEY_DELETE 76 /* i.e. forward delete */
#define KEY_END 77
#define KEY_PAGE_DOWN 78
#define KEY_RIGHT_ARROW 79
#define KEY_LEFT_ARROW 80
#define KEY_DOWN_ARROW 81
#define KEY_UP_ARROW 82
/* TODO: keypad codes */
#define KEY_LEFT_CTRL 0xE0
#define KEY_LEFT_SHIFT 0xE1
#define KEY_LEFT_ALT 0xE2
#define KEY_LEFT_GUI 0xE3
#define KEY_RIGHT_CTRL 0xE4
#define KEY_RIGHT_SHIFT 0xE5
#define KEY_RIGHT_ALT 0xE6
#define KEY_RIGHT_GUI 0xE7
#define KEY_MODIFIERS_START 0xE0
#define KEY_MODIFIERS_END 0xE7
#define IS_MODIFIER(key) ((key) >= KEY_MODIFIERS_START && (key) <= KEY_MODIFIERS_END)
#define MODIFIER_BIT(key) (1 << ((key)-KEY_MODIFIERS_START))
//#endif /* USB_HID_KEYBOARD_H */
#ifndef USB_HID_KEYBOARD_H
#define USB_HID_KEYBOARD_H
/* Modifier key bit values */
#define MODBIT_LEFT_CTRL 0x01
#define MODBIT_LEFT_SHIFT 0x02
#define MODBIT_LEFT_ALT 0x04
#define MODBIT_LEFT_GUI 0x08
#define MODBIT_RIGHT_CTRL 0x10
#define MODBIT_RIGHT_SHIFT 0x20
#define MODBIT_RIGHT_ALT 0x40
#define MODBIT_RIGHT_GUI 0x80
/* From USB HID Usage Tables Version 1.12, Section 10 */
#define KEY_NONE 0
#define KEY_ErrorRollOver 1
#define KEY_POSTFail 2
#define KEY_ErrorUndefined 3
#define KEY_A 4
#define KEY_B 5
#define KEY_C 6
#define KEY_D 7
#define KEY_E 8
#define KEY_F 9
#define KEY_G 10
#define KEY_H 11
#define KEY_I 12
#define KEY_J 13
#define KEY_K 14
#define KEY_L 15
#define KEY_M 16
#define KEY_N 17
#define KEY_O 18
#define KEY_P 19
#define KEY_Q 20
#define KEY_R 21
#define KEY_S 22
#define KEY_T 23
#define KEY_U 24
#define KEY_V 25
#define KEY_W 26
#define KEY_X 27
#define KEY_Y 28
#define KEY_Z 29
#define KEY_1 30
#define KEY_2 31
#define KEY_3 32
#define KEY_4 33
#define KEY_5 34
#define KEY_6 35
#define KEY_7 36
#define KEY_8 37
#define KEY_9 38
#define KEY_0 39
#define KEY_ENTER 40
#define KEY_ESC 41
#define KEY_BACKSPACE 42
#define KEY_TAB 43
#define KEY_SPACE 44
#define KEY_MINUS 45 /* And underscore */
#define KEY_EQUALS 46 /* And plus */
#define KEY_OPEN_SQUARE 47 /* And open-curly-bracket */
#define KEY_CLOSE_SQUARE 48 /* And close-curly-bracket */
#define KEY_BACKSLASH 49
#define KEY_HASH_TILDE 50
#define KEY_SEMICOLON 51
#define KEY_SINGLE_QUOTE 52
#define KEY_BACKTICK_TILDE 53
#define KEY_COMMA 54 /* And less-than */
#define KEY_PERIOD 55 /* And greater-than */
#define KEY_SLASH 56 /* And question-mark */
#define KEY_CAPS_LOCK 57
#define KEY_F1 58
#define KEY_F2 59
#define KEY_F3 60
#define KEY_F4 61
#define KEY_F5 62
#define KEY_F6 63
#define KEY_F7 64
#define KEY_F8 65
#define KEY_F9 66
#define KEY_F10 67
#define KEY_F11 68
#define KEY_F12 69
#define KEY_PRINT_SCREEN 70
#define KEY_SCROLL_LOCK 71
#define KEY_PAUSE 72
#define KEY_INSERT 73
#define KEY_HOME 74
#define KEY_PAGE_UP 75
#define KEY_DELETE 76 /* i.e. forward delete */
#define KEY_END 77
#define KEY_PAGE_DOWN 78
#define KEY_RIGHT_ARROW 79
#define KEY_LEFT_ARROW 80
#define KEY_DOWN_ARROW 81
#define KEY_UP_ARROW 82
/* TODO: keypad codes */
#define KEY_LEFT_CTRL 0xE0
#define KEY_LEFT_SHIFT 0xE1
#define KEY_LEFT_ALT 0xE2
#define KEY_LEFT_GUI 0xE3
#define KEY_RIGHT_CTRL 0xE4
#define KEY_RIGHT_SHIFT 0xE5
#define KEY_RIGHT_ALT 0xE6
#define KEY_RIGHT_GUI 0xE7
#define KEY_MODIFIERS_START 0xE0
#define KEY_MODIFIERS_END 0xE7
#define IS_MODIFIER(key) ((key) >= KEY_MODIFIERS_START && (key) <= KEY_MODIFIERS_END)
#define MODIFIER_BIT(key) (1 << ((key)-KEY_MODIFIERS_START))
#endif /* USB_HID_KEYBOARD_H */
#ifndef USB_HID_KEYBOARD_H
#define USB_HID_KEYBOARD_H
/* Modifier key bit values */
#define MODBIT_LEFT_CTRL 0x01
#define MODBIT_LEFT_SHIFT 0x02
#define MODBIT_LEFT_ALT 0x04
#define MODBIT_LEFT_GUI 0x08
#define MODBIT_RIGHT_CTRL 0x10
#define MODBIT_RIGHT_SHIFT 0x20
#define MODBIT_RIGHT_ALT 0x40
#define MODBIT_RIGHT_GUI 0x80
/* From USB HID Usage Tables Version 1.12, Section 10 */
#define KEY_NONE 0
#define KEY_ErrorRollOver 1
#define KEY_POSTFail 2
#define KEY_ErrorUndefined 3
#define KEY_A 4
#define KEY_B 5
#define KEY_C 6
#define KEY_D 7
#define KEY_E 8
#define KEY_F 9
#define KEY_G 10
#define KEY_H 11
#define KEY_I 12
#define KEY_J 13
#define KEY_K 14
#define KEY_L 15
#define KEY_M 16
#define KEY_N 17
#define KEY_O 18
#define KEY_P 19
#define KEY_Q 20
#define KEY_R 21
#define KEY_S 22
#define KEY_T 23
#define KEY_U 24
#define KEY_V 25
#define KEY_W 26
#define KEY_X 27
#define KEY_Y 28
#define KEY_Z 29
#define KEY_1 30
#define KEY_2 31
#define KEY_3 32
#define KEY_4 33
#define KEY_5 34
#define KEY_6 35
#define KEY_7 36
#define KEY_8 37
#define KEY_9 38
#define KEY_0 39
#define KEY_ENTER 40
#define KEY_ESC 41
#define KEY_BACKSPACE 42
#define KEY_TAB 43
#define KEY_SPACE 44
#define KEY_MINUS 45 /* And underscore */
#define KEY_EQUALS 46 /* And plus */
#define KEY_OPEN_SQUARE 47 /* And open-curly-bracket */
#define KEY_CLOSE_SQUARE 48 /* And close-curly-bracket */
#define KEY_BACKSLASH 49
#define KEY_HASH_TILDE 50
#define KEY_SEMICOLON 51
#define KEY_SINGLE_QUOTE 52
#define KEY_BACKTICK_TILDE 53
#define KEY_COMMA 54 /* And less-than */
#define KEY_PERIOD 55 /* And greater-than */
#define KEY_SLASH 56 /* And question-mark */
#define KEY_CAPS_LOCK 57
#define KEY_F1 58
#define KEY_F2 59
#define KEY_F3 60
#define KEY_F4 61
#define KEY_F5 62
#define KEY_F6 63
#define KEY_F7 64
#define KEY_F8 65
#define KEY_F9 66
#define KEY_F10 67
#define KEY_F11 68
#define KEY_F12 69
#define KEY_PRINT_SCREEN 70
#define KEY_SCROLL_LOCK 71
#define KEY_PAUSE 72
#define KEY_INSERT 73
#define KEY_HOME 74
#define KEY_PAGE_UP 75
#define KEY_DELETE 76 /* i.e. forward delete */
#define KEY_END 77
#define KEY_PAGE_DOWN 78
#define KEY_RIGHT_ARROW 79
#define KEY_LEFT_ARROW 80
#define KEY_DOWN_ARROW 81
#define KEY_UP_ARROW 82
/* TODO: keypad codes */
#define KEY_LEFT_CTRL 0xE0
#define KEY_LEFT_SHIFT 0xE1
#define KEY_LEFT_ALT 0xE2
#define KEY_LEFT_GUI 0xE3
#define KEY_RIGHT_CTRL 0xE4
#define KEY_RIGHT_SHIFT 0xE5
#define KEY_RIGHT_ALT 0xE6
#define KEY_RIGHT_GUI 0xE7
#define KEY_MODIFIERS_START 0xE0
#define KEY_MODIFIERS_END 0xE7
#define IS_MODIFIER(key) ((key) >= KEY_MODIFIERS_START && (key) <= KEY_MODIFIERS_END)
#define MODIFIER_BIT(key) (1 << ((key)-KEY_MODIFIERS_START))
#endif /* USB_HID_KEYBOARD_H */
#ifndef PS2Keyboard_h
#define PS2Keyboard_h
#include
#include
#include
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h" // for attachInterrupt, FALLING
#else
#include "WProgram.h"
#endif
// Every call to read() returns a single byte for each
// keystroke. These configure what byte will be returned
// for each "special" key. To ignore a key, use zero.
#define PS2_TAB 9
#define PS2_ENTER 13
#define PS2_LINEFEED 10
#define PS2_BACKSPACE 127
#define PS2_ESC 27
#define PS2_INSERT 0
#define PS2_DELETE 127
#define PS2_HOME 0
#define PS2_END 0
#define PS2_PAGEUP 25
#define PS2_PAGEDOWN 26
#define PS2_UPARROW 11
#define PS2_LEFTARROW 8
#define PS2_DOWNARROW 12
#define PS2_RIGHTARROW 21
#define PS2_F1 1
#define PS2_F2 2
#define PS2_F3 3
#define PS2_F4 4
#define PS2_F5 5
#define PS2_F6 6
#define PS2_F7 7
#define PS2_F8 8
#define PS2_F9 9
#define PS2_F10 10
#define PS2_F11 11
#define PS2_F12 12
#define PS2_SCROLL 0
#define PS2_INVERTED_EXCLAMATION 161 // ¡
#define PS2_CENT_SIGN 162 // ¢
#define PS2_POUND_SIGN 163 // £
#define PS2_CURRENCY_SIGN 164 // ¤
#define PS2_YEN_SIGN 165 // ¥
#define PS2_BROKEN_BAR 166 // ¦
#define PS2_SECTION_SIGN 167 // §
#define PS2_DIAERESIS 168 // ¨
#define PS2_COPYRIGHT_SIGN 169 // ©
#define PS2_FEMININE_ORDINAL 170 // ª
#define PS2_LEFT_DOUBLE_ANGLE_QUOTE 171 // «
#define PS2_NOT_SIGN 172 // ¬
#define PS2_HYPHEN 173
#define PS2_REGISTERED_SIGN 174 // ®
#define PS2_MACRON 175 // ¯
#define PS2_DEGREE_SIGN 176 // °
#define PS2_PLUS_MINUS_SIGN 177 // ±
#define PS2_SUPERSCRIPT_TWO 178 // ²
#define PS2_SUPERSCRIPT_THREE 179 // ³
#define PS2_ACUTE_ACCENT 180 // ´
#define PS2_MICRO_SIGN 181 // µ
#define PS2_PILCROW_SIGN 182 // ¶
#define PS2_MIDDLE_DOT 183 // ·
#define PS2_CEDILLA 184 // ¸
#define PS2_SUPERSCRIPT_ONE 185 // ¹
#define PS2_MASCULINE_ORDINAL 186 // º
#define PS2_RIGHT_DOUBLE_ANGLE_QUOTE 187 // »
#define PS2_FRACTION_ONE_QUARTER 188 // ¼
#define PS2_FRACTION_ONE_HALF 189 // ½
#define PS2_FRACTION_THREE_QUARTERS 190 // ¾
#define PS2_INVERTED_QUESTION MARK 191 // ¿
#define PS2_A_GRAVE 192 // À
#define PS2_A_ACUTE 193 // Á
#define PS2_A_CIRCUMFLEX 194 // Â
#define PS2_A_TILDE 195 // Ã
#define PS2_A_DIAERESIS 196 // Ä
#define PS2_A_RING_ABOVE 197 // Å
#define PS2_AE 198 // Æ
#define PS2_C_CEDILLA 199 // Ç
#define PS2_E_GRAVE 200 // È
#define PS2_E_ACUTE 201 // É
#define PS2_E_CIRCUMFLEX 202 // Ê
#define PS2_E_DIAERESIS 203 // Ë
#define PS2_I_GRAVE 204 // Ì
#define PS2_I_ACUTE 205 // Í
#define PS2_I_CIRCUMFLEX 206 // Î
#define PS2_I_DIAERESIS 207 // Ï
#define PS2_ETH 208 // Ð
#define PS2_N_TILDE 209 // Ñ
#define PS2_O_GRAVE 210 // Ò
#define PS2_O_ACUTE 211 // Ó
#define PS2_O_CIRCUMFLEX 212 // Ô
#define PS2_O_TILDE 213 // Õ
#define PS2_O_DIAERESIS 214 // Ö
#define PS2_MULTIPLICATION 215 // ×
#define PS2_O_STROKE 216 // Ø
#define PS2_U_GRAVE 217 // Ù
#define PS2_U_ACUTE 218 // Ú
#define PS2_U_CIRCUMFLEX 219 // Û
#define PS2_U_DIAERESIS 220 // Ü
#define PS2_Y_ACUTE 221 // Ý
#define PS2_THORN 222 // Þ
#define PS2_SHARP_S 223 // ß
#define PS2_a_GRAVE 224 // à
#define PS2_a_ACUTE 225 // á
#define PS2_a_CIRCUMFLEX 226 // â
#define PS2_a_TILDE 227 // ã
#define PS2_a_DIAERESIS 228 // ä
#define PS2_a_RING_ABOVE 229 // å
#define PS2_ae 230 // æ
#define PS2_c_CEDILLA 231 // ç
#define PS2_e_GRAVE 232 // è
#define PS2_e_ACUTE 233 // é
#define PS2_e_CIRCUMFLEX 234 // ê
#define PS2_e_DIAERESIS 235 // ë
#define PS2_i_GRAVE 236 // ì
#define PS2_i_ACUTE 237 // í
#define PS2_i_CIRCUMFLEX 238 // î
#define PS2_i_DIAERESIS 239 // ï
#define PS2_eth 240 // ð
#define PS2_n_TILDE 241 // ñ
#define PS2_o_GRAVE 242 // ò
#define PS2_o_ACUTE 243 // ó
#define PS2_o_CIRCUMFLEX 244 // ô
#define PS2_o_TILDE 245 // õ
#define PS2_o_DIAERESIS 246 // ö
#define PS2_DIVISION 247 // ÷
#define PS2_o_STROKE 248 // ø
#define PS2_u_GRAVE 249 // ù
#define PS2_u_ACUTE 250 // ú
#define PS2_u_CIRCUMFLEX 251 // û
#define PS2_u_DIAERESIS 252 // ü
#define PS2_y_ACUTE 253 // ý
#define PS2_thorn 254 // þ
#define PS2_y_DIAERESIS 255 // ÿ
#define PS2_KEYMAP_SIZE 136
typedef struct {
uint8_t noshift[PS2_KEYMAP_SIZE];
uint8_t shift[PS2_KEYMAP_SIZE];
uint8_t uses_altgr;
uint8_t altgr[PS2_KEYMAP_SIZE];
} PS2Keymap_t;
extern const PROGMEM PS2Keymap_t PS2Keymap_US;
//
// 8 in each row starting with 0
//
char keymap[] =
// without shift
{0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, 'F1', /* 7 */
0, PS2_F10, PS2_F8, PS2_F6, '4', PS2_TAB, '`', 'F2', /* 15 */
0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', '1', 'F3', /* 23 */
0, 0, 'z', 's', 'a', 'w', '2', 0,
0, 'c', 'x', 'd', 'e', '4', '3', 0,
0, ' ', 'v', 'f', 't', 'r', '5', 0,
0, 'n', 'b', 'h', 'g', 'y', '6', 0,
0, 0, 'm', 'j', 'u', '7', '8', 0,
0, ',', 'k', 'i', 'o', '0', '9', 0,
0, '.', '/', 'l', ';', 'p', '-', 0,
0, 0, '\'', 0, '[', '=', 0, 0,
0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, ']', 0, '\\', 0, 0,
0, 0, 0, 0, 0, 0, PS2_BACKSPACE, 0,
0, '1', 0, '4', '7', 0, 0, 0,
'0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
0, 0, 0, PS2_F7 };
const PROGMEM char keymap1[] =
// with shift
{0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '~', 0,
0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'Q', '!', 0,
0, 0, 'Z', 'S', 'A', 'W', '@', 0,
0, 'C', 'X', 'D', 'E', '$', '#', 0,
0, ' ', 'V', 'F', 'T', 'R', '%', 0,
0, 'N', 'B', 'H', 'G', 'Y', '^', 0,
0, 0, 'M', 'J', 'U', '&', '*', 0,
0, '<', 'K', 'I', 'O', ')', '(', 0,
0, '>', '?', 'L', ':', 'P', '_', 0,
0, 0, '"', 0, '{', '+', 0, 0,
0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '}', 0, '|', 0, 0,
0, 0, 0, 0, 0, 0, PS2_BACKSPACE, 0,
0, '1', 0, '4', '7', 0, 0, 0,
'0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
0, 0, 0, PS2_F7
};
/**
* Purpose: Provides an easy access to PS2 keyboards
* Author: Christian Weichel
*/
class PS2Keyboard {
public:
/**
* This constructor does basically nothing. Please call the begin(int,int)
* method before using any other method of this class.
*/
PS2Keyboard();
/**
* Starts the keyboard "service" by registering the external interrupt.
* setting the pin modes correctly and driving those needed to high.
* The propably best place to call this method is in the setup routine.
*/
static void begin(uint8_t dataPin, uint8_t irq_pin, const PS2Keymap_t &map = PS2Keymap_US);
/**
* Returns true if there is a char to be read, false if not.
*/
static bool available();
/**
* Returns the char last read from the keyboard.
* If there is no char availble, -1 is returned.
*/
static int read();
};
// interrupt pins for known boards
#if !defined(CORE_INT0_PIN)
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) // Arduino Mega
#define CORE_INT0_PIN 2
#define CORE_INT1_PIN 3
#define CORE_INT2_PIN 21
#define CORE_INT3_PIN 20
#define CORE_INT4_PIN 19
#define CORE_INT5_PIN 18
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) // Sanguino
#define CORE_INT0_PIN 10
#define CORE_INT1_PIN 11
#define CORE_INT2_PIN 2
#else // Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, etc...
#define CORE_INT0_PIN 2
#define CORE_INT1_PIN 3
#endif
#endif
#endif