]>
Commit | Line | Data |
---|---|---|
1 | /* keyboard.c | |
2 | * Keyboard scan code conversion and injection. | |
3 | * NetWatch system management mode administration console | |
4 | * | |
5 | * Copyright (c) 2008 Jacob Potter and Joshua Wise. All rights reserved. | |
6 | * This program is free software; you can redistribute and/or modify it under | |
7 | * the terms found in the file LICENSE in the root of this source tree. | |
8 | * | |
9 | */ | |
10 | ||
11 | #include "keyboard.h" | |
12 | #include <stdint.h> | |
13 | #include <minilib.h> | |
14 | #include <output.h> | |
15 | ||
16 | static unsigned char kbd_inj_buffer[128]; | |
17 | static int kbd_inj_start = 0; | |
18 | static int kbd_inj_end = 0; | |
19 | int kbd_mode = 1; | |
20 | ||
21 | /* To save space, we don't store the first 32 characters in scancodes2, since | |
22 | * they're control characters. Thus, the offset is the amount to subtract | |
23 | * from a character before looking it up. */ | |
24 | ||
25 | #define SC2_OFFSET 32 | |
26 | #define SC2(x) ((x)-SC2_OFFSET) | |
27 | ||
28 | /* Keys are stored in somewhat compressed form, to save on data space. | |
29 | * | |
30 | * The "press" and "release" strings contain scancodes to be injected | |
31 | * into the buffer. However, they are modified beforehand, since two | |
32 | * bytes isn't enough for all keys. | |
33 | * | |
34 | * Rules: | |
35 | * - If press starts with \x12 (shift down), then \xf0\x12 (shift up) | |
36 | * will be appended to release. | |
37 | * - If press starts with \xe0, then \xe0 is *pre*pended to release. | |
38 | */ | |
39 | ||
40 | struct keyspec { | |
41 | char press[2]; | |
42 | char release[2]; | |
43 | }; | |
44 | ||
45 | static const struct keyspec scancodes2[] = { | |
46 | [SC2('a')] = { "\x1c", "\xf0\x1c" }, | |
47 | [SC2('b')] = { "\x32", "\xf0\x32" }, | |
48 | [SC2('c')] = { "\x21", "\xf0\x21" }, | |
49 | [SC2('d')] = { "\x23", "\xf0\x23" }, | |
50 | [SC2('e')] = { "\x24", "\xf0\x24" }, | |
51 | [SC2('f')] = { "\x2b", "\xf0\x2b" }, | |
52 | [SC2('g')] = { "\x34", "\xf0\x34" }, | |
53 | [SC2('h')] = { "\x33", "\xf0\x33" }, | |
54 | [SC2('i')] = { "\x43", "\xf0\x43" }, | |
55 | [SC2('j')] = { "\x3b", "\xf0\x3b" }, | |
56 | [SC2('k')] = { "\x42", "\xf0\x42" }, | |
57 | [SC2('l')] = { "\x4b", "\xf0\x4b" }, | |
58 | [SC2('m')] = { "\x3a", "\xf0\x3a" }, | |
59 | [SC2('n')] = { "\x31", "\xf0\x31" }, | |
60 | [SC2('o')] = { "\x44", "\xf0\x44" }, | |
61 | [SC2('p')] = { "\x4d", "\xf0\x4d" }, | |
62 | [SC2('q')] = { "\x15", "\xf0\x15" }, | |
63 | [SC2('r')] = { "\x2d", "\xf0\x2d" }, | |
64 | [SC2('s')] = { "\x1b", "\xf0\x1b" }, | |
65 | [SC2('t')] = { "\x2c", "\xf0\x2c" }, | |
66 | [SC2('u')] = { "\x3c", "\xf0\x3c" }, | |
67 | [SC2('v')] = { "\x2a", "\xf0\x2a" }, | |
68 | [SC2('w')] = { "\x1d", "\xf0\x1d" }, | |
69 | [SC2('x')] = { "\x22", "\xf0\x22" }, | |
70 | [SC2('y')] = { "\x35", "\xf0\x35" }, | |
71 | [SC2('z')] = { "\x1a", "\xf0\x1a" }, | |
72 | [SC2('A')] = { "\x12\x1c", "\xf0\x1c" }, | |
73 | [SC2('B')] = { "\x12\x32", "\xf0\x32" }, | |
74 | [SC2('C')] = { "\x12\x21", "\xf0\x21" }, | |
75 | [SC2('D')] = { "\x12\x23", "\xf0\x23" }, | |
76 | [SC2('E')] = { "\x12\x24", "\xf0\x24" }, | |
77 | [SC2('F')] = { "\x12\x2b", "\xf0\x2b" }, | |
78 | [SC2('G')] = { "\x12\x34", "\xf0\x34" }, | |
79 | [SC2('H')] = { "\x12\x33", "\xf0\x33" }, | |
80 | [SC2('I')] = { "\x12\x43", "\xf0\x43" }, | |
81 | [SC2('J')] = { "\x12\x3b", "\xf0\x3b" }, | |
82 | [SC2('K')] = { "\x12\x42", "\xf0\x42" }, | |
83 | [SC2('L')] = { "\x12\x4b", "\xf0\x4b" }, | |
84 | [SC2('M')] = { "\x12\x3a", "\xf0\x3a" }, | |
85 | [SC2('N')] = { "\x12\x31", "\xf0\x31" }, | |
86 | [SC2('O')] = { "\x12\x44", "\xf0\x44" }, | |
87 | [SC2('P')] = { "\x12\x4d", "\xf0\x4d" }, | |
88 | [SC2('Q')] = { "\x12\x15", "\xf0\x15" }, | |
89 | [SC2('R')] = { "\x12\x2d", "\xf0\x2d" }, | |
90 | [SC2('S')] = { "\x12\x1b", "\xf0\x1b" }, | |
91 | [SC2('T')] = { "\x12\x2c", "\xf0\x2c" }, | |
92 | [SC2('U')] = { "\x12\x3c", "\xf0\x3c" }, | |
93 | [SC2('V')] = { "\x12\x2a", "\xf0\x2a" }, | |
94 | [SC2('W')] = { "\x12\x1d", "\xf0\x1d" }, | |
95 | [SC2('X')] = { "\x12\x22", "\xf0\x22" }, | |
96 | [SC2('Y')] = { "\x12\x35", "\xf0\x35" }, | |
97 | [SC2('Z')] = { "\x12\x1a", "\xf0\x1a" }, | |
98 | [SC2('`')] = { "\x0e", "\xf0\x0e" }, | |
99 | [SC2('~')] = { "\x12\x0e", "\xf0\x0e" }, | |
100 | [SC2('1')] = { "\x16", "\xf0\x16" }, | |
101 | [SC2('!')] = { "\x12\x16", "\xf0\x16" }, | |
102 | [SC2('2')] = { "\x1e", "\xf0\x1e" }, | |
103 | [SC2('@')] = { "\x12\x1e", "\xf0\x1e" }, | |
104 | [SC2('3')] = { "\x26", "\xf0\x26" }, | |
105 | [SC2('#')] = { "\x12\x26", "\xf0\x26" }, | |
106 | [SC2('4')] = { "\x25", "\xf0\x25" }, | |
107 | [SC2('$')] = { "\x12\x25", "\xf0\x25" }, | |
108 | [SC2('5')] = { "\x2e", "\xf0\x2e" }, | |
109 | [SC2('%')] = { "\x12\x2e", "\xf0\x2e" }, | |
110 | [SC2('6')] = { "\x36", "\xf0\x36" }, | |
111 | [SC2('^')] = { "\x12\x36", "\xf0\x36" }, | |
112 | [SC2('7')] = { "\x3d", "\xf0\x3d" }, | |
113 | [SC2('&')] = { "\x12\x3d", "\xf0\x3d" }, | |
114 | [SC2('8')] = { "\x3e", "\xf0\x3e" }, | |
115 | [SC2('*')] = { "\x12\x3e", "\xf0\x3e" }, | |
116 | [SC2('9')] = { "\x46", "\xf0\x46" }, | |
117 | [SC2('(')] = { "\x12\x46", "\xf0\x46" }, | |
118 | [SC2('0')] = { "\x45", "\xf0\x45" }, | |
119 | [SC2(')')] = { "\x12\x45", "\xf0\x45" }, | |
120 | [SC2('-')] = { "\x4e", "\xf0\x4e" }, | |
121 | [SC2('_')] = { "\x12\x4e", "\xf0\x4e" }, | |
122 | [SC2('=')] = { "\x55", "\xf0\x55" }, | |
123 | [SC2('+')] = { "\x12\x55", "\xf0\x55" }, | |
124 | [SC2('[')] = { "\x54", "\xf0\x54" }, | |
125 | [SC2('{')] = { "\x12\x54", "\xf0\x54" }, | |
126 | [SC2(']')] = { "\x5b", "\xf0\x5b" }, | |
127 | [SC2('}')] = { "\x12\x5b", "\xf0\x5b" }, | |
128 | [SC2('\\')] = { "\x5d", "\xf0\x5d" }, | |
129 | [SC2('|')] = { "\x12\x5d", "\xf0\x5d" }, | |
130 | [SC2(';')] = { "\x4c", "\xf0\x4c" }, | |
131 | [SC2(':')] = { "\x12\x4c", "\xf0\x4c" }, | |
132 | [SC2('\'')] = { "\x52", "\xf0\x52" }, | |
133 | [SC2('"')] = { "\x12\x52", "\xf0\x52" }, | |
134 | [SC2(',')] = { "\x41", "\xf0\x41" }, | |
135 | [SC2('<')] = { "\x12\x41", "\xf0\x41" }, | |
136 | [SC2('.')] = { "\x49", "\xf0\x49" }, | |
137 | [SC2('>')] = { "\x12\x49", "\xf0\x49" }, | |
138 | [SC2('/')] = { "\x4a", "\xf0\x4a" }, | |
139 | [SC2(' ')] = { "\x29", "\xf0\x29" }, | |
140 | [SC2('?')] = { "\x12\x4a", "\xf0\x4a" } | |
141 | }; | |
142 | ||
143 | static const struct { | |
144 | char index; | |
145 | struct keyspec data; | |
146 | } scancodes2high[] = { | |
147 | { 0x08, { "\x66", "\xf0\x66" } }, | |
148 | { 0x09, { "\x0d", "\xf0\x0d" } }, | |
149 | { 0x0d, { "\x5a", "\xf0\x5a" } }, | |
150 | { 0x1b, { "\x76", "\xf0\x76" } }, | |
151 | { 0x63, { "\xe0\x70", "\xF0\x70" } }, | |
152 | { 0xff, { "\xe0\x71", "\xF0\x71" } }, | |
153 | { 0x50, { "\xe0\x6C", "\xF0\x6C" } }, | |
154 | { 0x57, { "\xe0\x69", "\xF0\x69" } }, | |
155 | { 0x55, { "\xe0\x75", "\xF0\x75" } }, | |
156 | { 0x56, { "\xe0\x7A", "\xF0\x7A" } }, | |
157 | { 0x51, { "\xe0\x74", "\xF0\x74" } }, | |
158 | { 0x52, { "\xe0\x75", "\xF0\x75" } }, | |
159 | { 0x53, { "\xe0\x6B", "\xF0\x6B" } }, | |
160 | { 0x54, { "\xe0\x72", "\xF0\x72" } }, | |
161 | { 0xe1, { "\x12", "" } }, | |
162 | { 0xe2, { "\x59", "\xf0\x59" } }, | |
163 | { 0xe3, { "\x14", "\xf0\x14" } }, | |
164 | { 0xe4, { "\xe0\x14", "\xF0\x14" } }, | |
165 | { 0xe9, { "\x11", "\xf0\x11" } }, | |
166 | { 0xea, { "\xe0\x11", "\xF0\x11" } }, | |
167 | { 0x00, { "", "" } } | |
168 | }; | |
169 | ||
170 | const unsigned char convert_table[] = { | |
171 | 0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58, 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59, | |
172 | 0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a, 0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b, | |
173 | 0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c, 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d, | |
174 | 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e, 0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f, | |
175 | 0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60, 0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61, | |
176 | 0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e, 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76, | |
177 | 0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b, 0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f, | |
178 | 0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45, 0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54, | |
179 | 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, | |
180 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, | |
181 | 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, | |
182 | 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, | |
183 | 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, | |
184 | 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, | |
185 | 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, | |
186 | 0x00, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff | |
187 | }; | |
188 | ||
189 | unsigned char sc_convert_1(unsigned char in) | |
190 | { | |
191 | static int shifted = 0; | |
192 | ||
193 | if (shifted) | |
194 | { | |
195 | shifted = 0; | |
196 | return convert_table[in] | 0x80; | |
197 | } | |
198 | ||
199 | if (in == 0xF0) | |
200 | { | |
201 | shifted = 1; | |
202 | return 0; | |
203 | } else { | |
204 | return convert_table[in]; | |
205 | } | |
206 | } | |
207 | ||
208 | void kbd_inject_scancode (unsigned char sc) | |
209 | { | |
210 | if (kbd_mode == 1) { | |
211 | sc = sc_convert_1(sc); | |
212 | if (!sc) return; | |
213 | } | |
214 | ||
215 | outputf("Buffering %02x", sc); | |
216 | kbd_inj_buffer[kbd_inj_end] = sc; | |
217 | kbd_inj_end += 1; | |
218 | kbd_inj_end %= sizeof(kbd_inj_buffer); | |
219 | } | |
220 | ||
221 | void kbd_inject_keysym(uint32_t k, int downflag) | |
222 | { | |
223 | const struct keyspec * ks = 0; | |
224 | const char * c = 0; | |
225 | int i; | |
226 | ||
227 | if ((k & 0xFFFFFF00) == 0 && (k & 0xFF) > SC2_OFFSET) | |
228 | { | |
229 | ks = &scancodes2[SC2(k & 0xFF)]; | |
230 | } else if ((k & 0xFFFFFF00) == 0xFF00) { | |
231 | for (i = 0; scancodes2high[i].index; i++) { | |
232 | if ((k & 0xff) == scancodes2high[i].index) { | |
233 | ks = &scancodes2high[i].data; | |
234 | break; | |
235 | } | |
236 | } | |
237 | } else { | |
238 | return; | |
239 | } | |
240 | ||
241 | if (!ks) return; | |
242 | ||
243 | if (downflag) | |
244 | c = ks->press; | |
245 | else | |
246 | c = ks->release; | |
247 | ||
248 | i = 0; | |
249 | ||
250 | if (ks->press[0] == '\xe0' && !downflag) | |
251 | kbd_inject_scancode('\xe0'); | |
252 | ||
253 | while (*c && i < 2) { | |
254 | kbd_inject_scancode(*c); | |
255 | c++; | |
256 | i++; | |
257 | } | |
258 | ||
259 | if (ks->press[0] == '\x12' && !downflag) { | |
260 | kbd_inject_scancode('\xf0'); | |
261 | kbd_inject_scancode('\x12'); | |
262 | } | |
263 | } | |
264 | ||
265 | unsigned char kbd_get_injected_scancode() | |
266 | { | |
267 | unsigned char b; | |
268 | ||
269 | if (kbd_inj_end != kbd_inj_start) | |
270 | { | |
271 | b = kbd_inj_buffer[kbd_inj_start]; | |
272 | kbd_inj_start += 1; | |
273 | kbd_inj_start %= sizeof(kbd_inj_buffer); | |
274 | outputf("Injecting %02x", b); | |
275 | return b; | |
276 | } else { | |
277 | outputf("Not injecting"); | |
278 | return 0; | |
279 | } | |
280 | } | |
281 | ||
282 | int kbd_has_injected_scancode() | |
283 | { | |
284 | if (kbd_inj_end != kbd_inj_start) | |
285 | { | |
286 | return 1; | |
287 | } else { | |
288 | return 0; | |
289 | } | |
290 | } |