Skip to content

Commit c2a026a

Browse files
committed
First version of a real keyboard translator
1 parent fd706e6 commit c2a026a

File tree

3 files changed

+217
-0
lines changed

3 files changed

+217
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
*.swp

keyboardv1/README.md

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Keyboard v1
2+
3+
An Arduino sketch to retrieve serial binary from the Vector Graph 4 keyboard.
4+
5+
After an active-low trigger, the first bit is skipped, then
6+
subsequent bits are shifted in LSB to MSB, for 7 bits.
7+
8+
Then, a simple lookup is used to translate to the key to send via USB.
9+
10+
This version must be run on an Arduino that [CITATION NEEDED] can send back
11+
USB commands as keyboard commands.
12+

keyboardv1/keyboardv1.ino

+203
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
/*
2+
Simple keyboard interface. Triggers when the data pin goes low.
3+
Records 8 bits at 110 baud and looks up the value to send back.
4+
*/
5+
6+
#include <keyboard.h>
7+
8+
const int dataPin = 7; // pin 6 on the KB connector (and pin 6 of the RJ12)
9+
const int resetPin = 9; // pin 2 on the KB connector (and pin 4 on the RJ12)
10+
11+
void setup() {
12+
pinMode(resetPin, OUTPUT);
13+
pinMode(dataPin, INPUT);
14+
setupTable();
15+
16+
Serial.begin(9600);
17+
Serial.println("Hello keyboard passthrough");
18+
// Keyboard.begin();
19+
20+
// Set the reset pin low for 10 ms.
21+
digitalWrite(resetPin, LOW);
22+
delay(10);
23+
digitalWrite(resetPin, HIGH);
24+
}
25+
26+
char translationTable[256];
27+
char numLockTable[256];
28+
29+
#define SPECIAL 255
30+
#define VG_F13 205
31+
#define VG_F14 206
32+
#define VG_NP0 128
33+
#define VG_NP_DOT 207
34+
35+
void setupTable() {
36+
for (int i = 0; i < 256; i++) {
37+
if (i >= ' ' && i <= '~') {
38+
// Printable characters
39+
translationTable[i] = i;
40+
} else if (i < ' '){
41+
translationTable[i] = SPECIAL; // Control characters, except for exceptions, below.
42+
} else {
43+
translationTable[i] = ' '; // initialize the whole table so defaults anything not mapped to space
44+
}
45+
numLockTable[i] = ' ';
46+
}
47+
48+
//translationTable[VG_BACKSPACE] = ;
49+
translationTable[8] = KEY_TAB;
50+
translationTable[13] = KEY_RETURN;
51+
translationTable[27] = KEY_ESC;
52+
53+
translationTable[192] = KEY_F1; // map vg help key to f1
54+
translationTable[193] = KEY_F2; // map vg f1 to f2
55+
translationTable[194] = KEY_F3; // map vg f2 to f3
56+
translationTable[195] = KEY_F4; // map vg f3 to f4
57+
translationTable[196] = KEY_F5; // map vg f4 to f6
58+
translationTable[197] = KEY_F6; // map vg f5 to f6
59+
// NOTE: NO 198 (F6), because you can't type F6 on this keyboard...
60+
translationTable[199] = KEY_F7; // FROM HERE, the mappings are correct
61+
translationTable[200] = KEY_F8;
62+
translationTable[201] = KEY_F9;
63+
translationTable[202] = KEY_F10;
64+
translationTable[203] = KEY_F11;
65+
translationTable[204] = KEY_F12;
66+
translationTable[VG_F13] = SPECIAL;
67+
translationTable[VG_F14] = SPECIAL;
68+
69+
// translationTable[VG_UP] = KEY_UP_ARROW;
70+
// translationTable[VG_DOWN] = KEY_DOWN_ARROW;
71+
// translationTable[VG_LEFT] = KEY_LEFT_ARROW;
72+
// translationTable[VG_RIGHT] = KEY_RIGHT_ARROW;
73+
// translationTable[VG_NP_ENTER] = KEY_RETURN;
74+
75+
// Numlock:
76+
numLockTable[VG_NP0] = '0';
77+
// TODO: NP1-9, enter, comma, dash, up, down, left, right
78+
// numLockTable[VG_NP_1] = '1';
79+
// numLockTable[VG_NP_2] = '2';
80+
// numLockTable[VG_NP_3] = '3';
81+
// numLockTable[VG_NP_4] = '4';
82+
// numLockTable[VG_NP_5] = '5';
83+
// numLockTable[VG_NP_6] = '6';
84+
// numLockTable[VG_NP_7] = '7';
85+
// numLockTable[VG_NP_8] = '8';
86+
// numLockTable[VG_NP_9] = '9';
87+
// numLockTable[VG_NP_COMMA] = ',';
88+
numLockTable[VG_NP_DOT] = '.'; // NP DOT
89+
// numlockTable[VG_NP_MINUS] = '-';
90+
91+
// Numlock off: cursor keys:
92+
translationTable[VG_NP0] = KEY_INS;
93+
// translationTable{VG_NP_1] = KEY_END;
94+
// translationTable{VG_NP_2] = KEY_DOWN_ARROW;
95+
// translationTable{VG_NP_3] = KEY_PAGE_DOWN;
96+
// translationTable{VG_NP_4] = KEY_LEFT_ARROW;
97+
// translationTable{VG_NP_3] = '5';
98+
// translationTable{VG_NP_6] = KEY_RIGHT_ARROW;
99+
// translationTable{VG_NP_7] = KEY_HOME;
100+
// translationTable{VG_NP_8] = KEY_UP_ARROW;
101+
// translationTable{VG_NP_9] = KEY_PAGE_UP;
102+
// translationTable[VG_NP_COMMA] = ',';
103+
translationTable[VG_NP_DOT] = KEY_DELETE;
104+
// translationTable[VG_NP_MINUS] = '-';
105+
}
106+
107+
108+
// Microseconds to wait between bits. Corresponds to 110 baud, empirically determined.
109+
const int baudDelay = 3387;
110+
111+
112+
void loop() {
113+
int data = digitalRead(dataPin);
114+
if (data == LOW) {
115+
116+
// Wait half a cycle so that we're sampling in the middle of the bit.
117+
delayMicroseconds(baudDelay / 2);
118+
119+
char key = getChar();
120+
sendChar(key);
121+
}
122+
}
123+
124+
char getChar() {
125+
int theKey = 0;
126+
for (int i = 0; i < 8; ++i) {
127+
data = digitalRead(dataPin);
128+
129+
// Shift right and possibly shift in a 1.
130+
theKey >>= 1;
131+
if (data == HIGH) {
132+
theKey = theKey | 0x80;
133+
}
134+
135+
// Wait for the next bit
136+
delayMicroseconds(baudDelay);
137+
}
138+
139+
char keyChar = (char)theKey;
140+
Serial.print(keyChar);
141+
Serial.print(" (dec "); Serial.print(theKey); Serial.print(" =0b");
142+
for (int i = 7; i >= 0; i--) {
143+
Serial.write(bitRead(theKey, i));
144+
}
145+
Serial.println(")");
146+
147+
return keyChar;
148+
}
149+
150+
bool nextIsAlt = false;
151+
bool numLock = false;
152+
153+
void sendChar(char key) {
154+
// Figure out what to do with the key
155+
// * printable characters just get returned.
156+
// * control characters: ctrl + letter
157+
// * numpad needs to get translated
158+
// * HELP is ??? (192)
159+
// * F1 (193)-F12 (204) need to be translated
160+
// * F13 is "send next char as "alt""
161+
// * F14 is "numLock toggle"
162+
if (key >= ' ' && i <= '~') {
163+
if (nextIsAlt) {
164+
Serial.print("Alt+"); Serial.println(key);
165+
// Keyboard.press(KEY_ALT)
166+
// Keyboard.press(key);
167+
// Keyboard.releaseAll();
168+
nextIsAlt = false;
169+
return;
170+
}
171+
Serial.print("Printable: "); Serial.println(key);
172+
return;
173+
}
174+
175+
char translated;
176+
if (numLock) {
177+
translated = numLockTable[key];
178+
} else {
179+
translated = translationTable[key];
180+
}
181+
if (translated == SPECIAL) {
182+
// deal with F13 & F14
183+
if (key == VG_F13) {
184+
Serial.println("F13: Next-alt");
185+
nextIsAlt = true;
186+
} else if (key == VG_F14) {
187+
numLock = !numLock;
188+
Serial.print("F14: Toggling numlock "); Serial.println(numLock);
189+
} else if (key < ' ') {
190+
Serial.print("ctrl-"); Serial.println(key+64);
191+
// Keyboard.press(KEY_LEFT_CTRL);
192+
// Keyboard.press(key + 64)
193+
// Keyboard.releaseAll();
194+
}
195+
} else if (translated >= ' ' && translated <= '~') {
196+
Serial.print("Printable: "); Serial.print(translated); Serial.print("; was: "); Serial.print((int) key);
197+
// Keyboard.print(translated);
198+
} else {
199+
Serial.print("Unprintable: "); Serial.print((int) translated); Serial.print("; was: "); Serial.print((int) key);
200+
// Keyboard.press(key);
201+
// Keyboard.releaseAll();
202+
}
203+
}

0 commit comments

Comments
 (0)