Make test3 fail on the first error.
[minix.git] / test / scancodes / test-scancodes.c
blob1ca9179092ce584ddcf9ad47aa45fb126464ad3f
1 #define _MINIX
3 #include <errno.h>
4 #include <signal.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <termios.h>
9 #include <unistd.h>
11 /* list of scancodes to demonstrate whether the keycodes are correct;
12 * source: http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html
14 static char *keydescr[] = {
15 NULL, /* 0x00 */
16 "Esc", /* 0x01 */
17 "1!", /* 0x02 */
18 "2@", /* 0x03 */
19 "3#", /* 0x04 */
20 "4$", /* 0x05 */
21 "5%", /* 0x06 */
22 "6^", /* 0x07 */
23 "7&", /* 0x08 */
24 "8*", /* 0x09 */
25 "9(", /* 0x0a */
26 "0)", /* 0x0b */
27 "-_", /* 0x0c */
28 "=+", /* 0x0d */
29 "Backspace", /* 0x0e */
30 "Tab", /* 0x0f */
31 "Q", /* 0x10 */
32 "W", /* 0x11 */
33 "E", /* 0x12 */
34 "R", /* 0x13 */
35 "T", /* 0x14 */
36 "Y", /* 0x15 */
37 "U", /* 0x16 */
38 "I", /* 0x17 */
39 "O", /* 0x18 */
40 "P", /* 0x19 */
41 "[{", /* 0x1a */
42 "]}", /* 0x1b */
43 "Enter", /* 0x1c */
44 "LCtrl", /* 0x1d */
45 "A", /* 0x1e */
46 "S", /* 0x1f */
47 "D", /* 0x20 */
48 "F", /* 0x21 */
49 "G", /* 0x22 */
50 "H", /* 0x23 */
51 "J", /* 0x24 */
52 "K", /* 0x25 */
53 "L", /* 0x26 */
54 ";:", /* 0x27 */
55 "'\"", /* 0x28 */
56 "`~", /* 0x29 */
57 "LShift", /* 0x2a */
58 "\\|", /* 0x2b */
59 "Z", /* 0x2c */
60 "X", /* 0x2d */
61 "C", /* 0x2e */
62 "V", /* 0x2f */
63 "B", /* 0x30 */
64 "N", /* 0x31 */
65 "M", /* 0x32 */
66 ",<", /* 0x33 */
67 ".>", /* 0x34 */
68 "/?", /* 0x35 */
69 "RShift", /* 0x36 */
70 "Keypad-*", /* 0x37 */
71 "LAlt", /* 0x38 */
72 "Space bar", /* 0x39 */
73 "CapsLock", /* 0x3a */
74 "F1", /* 0x3b */
75 "F2", /* 0x3c */
76 "F3", /* 0x3d */
77 "F4", /* 0x3e */
78 "F5", /* 0x3f */
79 "F6", /* 0x40 */
80 "F7", /* 0x41 */
81 "F8", /* 0x42 */
82 "F9", /* 0x43 */
83 "F10", /* 0x44 */
84 "NumLock", /* 0x45 */
85 "ScrollLock", /* 0x46 */
86 "Keypad-7/Home",/* 0x47 */
87 "Keypad-8/Up", /* 0x48 */
88 "Keypad-9/PgUp",/* 0x49 */
89 "Keypad--", /* 0x4a */
90 "Keypad-4/Left",/* 0x4b */
91 "Keypad-5", /* 0x4c */
92 "Keypad-6/Right",/* 0x4d */
93 "Keypad-+", /* 0x4e */
94 "Keypad-1/End", /* 0x4f */
95 "Keypad-2/Down",/* 0x50 */
96 "Keypad-3/PgDn",/* 0x51 */
97 "Keypad-0/Ins", /* 0x52 */
98 "Keypad-./Del", /* 0x53 */
99 "Alt-SysRq", /* 0x54 */
100 NULL, /* 0x55 */
101 NULL, /* 0x56 */
102 "F11", /* 0x57 */
103 "F12", /* 0x58 */
104 NULL, /* 0x59 */
105 NULL, /* 0x5a */
106 NULL, /* 0x5b */
107 NULL, /* 0x5c */
108 NULL, /* 0x5d */
109 NULL, /* 0x5e */
110 NULL, /* 0x5f */
111 NULL, /* 0x60 */
112 NULL, /* 0x61 */
113 NULL, /* 0x62 */
114 NULL, /* 0x63 */
115 NULL, /* 0x64 */
116 NULL, /* 0x65 */
117 NULL, /* 0x66 */
118 NULL, /* 0x67 */
119 NULL, /* 0x68 */
120 NULL, /* 0x69 */
121 NULL, /* 0x6a */
122 NULL, /* 0x6b */
123 NULL, /* 0x6c */
124 NULL, /* 0x6d */
125 NULL, /* 0x6e */
126 NULL, /* 0x6f */
127 NULL, /* 0x70 */
128 NULL, /* 0x71 */
129 NULL, /* 0x72 */
130 NULL, /* 0x73 */
131 NULL, /* 0x74 */
132 NULL, /* 0x75 */
133 NULL, /* 0x76 */
134 NULL, /* 0x77 */
135 NULL, /* 0x78 */
136 NULL, /* 0x79 */
137 NULL, /* 0x7a */
138 NULL, /* 0x7b */
139 NULL, /* 0x7c */
140 NULL, /* 0x7d */
141 NULL, /* 0x7e */
142 NULL, /* 0x7f */
145 static char *keydescresc[] = {
146 NULL, /* 0xe0 0x00 */
147 NULL, /* 0xe0 0x01 */
148 NULL, /* 0xe0 0x02 */
149 NULL, /* 0xe0 0x03 */
150 NULL, /* 0xe0 0x04 */
151 NULL, /* 0xe0 0x05 */
152 NULL, /* 0xe0 0x06 */
153 NULL, /* 0xe0 0x07 */
154 NULL, /* 0xe0 0x08 */
155 NULL, /* 0xe0 0x09 */
156 NULL, /* 0xe0 0x0a */
157 NULL, /* 0xe0 0x0b */
158 NULL, /* 0xe0 0x0c */
159 NULL, /* 0xe0 0x0d */
160 NULL, /* 0xe0 0x0e */
161 NULL, /* 0xe0 0x0f */
162 NULL, /* 0xe0 0x10 */
163 NULL, /* 0xe0 0x11 */
164 NULL, /* 0xe0 0x12 */
165 NULL, /* 0xe0 0x13 */
166 NULL, /* 0xe0 0x14 */
167 NULL, /* 0xe0 0x15 */
168 NULL, /* 0xe0 0x16 */
169 NULL, /* 0xe0 0x17 */
170 NULL, /* 0xe0 0x18 */
171 NULL, /* 0xe0 0x19 */
172 NULL, /* 0xe0 0x1a */
173 NULL, /* 0xe0 0x1b */
174 "Keypad Enter", /* 0xe0 0x1c */
175 "RCtrl", /* 0xe0 0x1d */
176 NULL, /* 0xe0 0x1e */
177 NULL, /* 0xe0 0x1f */
178 NULL, /* 0xe0 0x20 */
179 NULL, /* 0xe0 0x21 */
180 NULL, /* 0xe0 0x22 */
181 NULL, /* 0xe0 0x23 */
182 NULL, /* 0xe0 0x24 */
183 NULL, /* 0xe0 0x25 */
184 NULL, /* 0xe0 0x26 */
185 NULL, /* 0xe0 0x27 */
186 NULL, /* 0xe0 0x28 */
187 NULL, /* 0xe0 0x29 */
188 "fake LShift", /* 0xe0 0x2a */
189 NULL, /* 0xe0 0x2b */
190 NULL, /* 0xe0 0x2c */
191 NULL, /* 0xe0 0x2d */
192 NULL, /* 0xe0 0x2e */
193 NULL, /* 0xe0 0x2f */
194 NULL, /* 0xe0 0x30 */
195 NULL, /* 0xe0 0x31 */
196 NULL, /* 0xe0 0x32 */
197 NULL, /* 0xe0 0x33 */
198 NULL, /* 0xe0 0x34 */
199 "Keypad-/", /* 0xe0 0x35 */
200 "fake RShift", /* 0xe0 0x36 */
201 "Ctrl-PrtScn", /* 0xe0 0x37 */
202 "RAlt", /* 0xe0 0x38 */
203 NULL, /* 0xe0 0x39 */
204 NULL, /* 0xe0 0x3a */
205 NULL, /* 0xe0 0x3b */
206 NULL, /* 0xe0 0x3c */
207 NULL, /* 0xe0 0x3d */
208 NULL, /* 0xe0 0x3e */
209 NULL, /* 0xe0 0x3f */
210 NULL, /* 0xe0 0x40 */
211 NULL, /* 0xe0 0x41 */
212 NULL, /* 0xe0 0x42 */
213 NULL, /* 0xe0 0x43 */
214 NULL, /* 0xe0 0x44 */
215 NULL, /* 0xe0 0x45 */
216 "Ctrl-Break", /* 0xe0 0x46 */
217 "Grey Home", /* 0xe0 0x47 */
218 "Grey Up", /* 0xe0 0x48 */
219 "Grey PgUp", /* 0xe0 0x49 */
220 NULL, /* 0xe0 0x4a */
221 "Grey Left", /* 0xe0 0x4b */
222 NULL, /* 0xe0 0x4c */
223 "Grey Right", /* 0xe0 0x4d */
224 NULL, /* 0xe0 0x4e */
225 "Grey End", /* 0xe0 0x4f */
226 "Grey Down", /* 0xe0 0x50 */
227 "Grey PgDn", /* 0xe0 0x51 */
228 "Grey Insert", /* 0xe0 0x52 */
229 "Grey Delete", /* 0xe0 0x53 */
230 NULL, /* 0xe0 0x54 */
231 NULL, /* 0xe0 0x55 */
232 NULL, /* 0xe0 0x56 */
233 NULL, /* 0xe0 0x57 */
234 NULL, /* 0xe0 0x58 */
235 NULL, /* 0xe0 0x59 */
236 NULL, /* 0xe0 0x5a */
237 "LeftWindow", /* 0xe0 0x5b */
238 "RightWindow", /* 0xe0 0x5c */
239 "Menu", /* 0xe0 0x5d */
240 "Power", /* 0xe0 0x5e */
241 "Sleep", /* 0xe0 0x5f */
242 NULL, /* 0xe0 0x60 */
243 NULL, /* 0xe0 0x61 */
244 NULL, /* 0xe0 0x62 */
245 "Wake", /* 0xe0 0x63 */
246 NULL, /* 0xe0 0x64 */
247 NULL, /* 0xe0 0x65 */
248 NULL, /* 0xe0 0x66 */
249 NULL, /* 0xe0 0x67 */
250 NULL, /* 0xe0 0x68 */
251 NULL, /* 0xe0 0x69 */
252 NULL, /* 0xe0 0x6a */
253 NULL, /* 0xe0 0x6b */
254 NULL, /* 0xe0 0x6c */
255 NULL, /* 0xe0 0x6d */
256 NULL, /* 0xe0 0x6e */
257 NULL, /* 0xe0 0x6f */
258 NULL, /* 0xe0 0x70 */
259 NULL, /* 0xe0 0x71 */
260 NULL, /* 0xe0 0x72 */
261 NULL, /* 0xe0 0x73 */
262 NULL, /* 0xe0 0x74 */
263 NULL, /* 0xe0 0x75 */
264 NULL, /* 0xe0 0x76 */
265 NULL, /* 0xe0 0x77 */
266 NULL, /* 0xe0 0x78 */
267 NULL, /* 0xe0 0x79 */
268 NULL, /* 0xe0 0x7a */
269 NULL, /* 0xe0 0x7b */
270 NULL, /* 0xe0 0x7c */
271 NULL, /* 0xe0 0x7d */
272 NULL, /* 0xe0 0x7e */
273 NULL, /* 0xe0 0x7f */
276 #define CHECK(r) check((r), #r, __FILE__, __LINE__)
278 int check(long r, const char *expr, const char *file, int line)
280 char buffer[256];
281 if (r < 0) {
282 snprintf(buffer, sizeof(buffer), "%s:%d: %s: result %ld, %s",
283 file, line, expr, r, strerror(errno));
284 exit(-1);
286 return r;
289 #define SCODE_ESC 0xe0
290 #define SCODE_BREAK 0x80
292 static int testscancode(int fd)
294 static int escape, lctrl, rctrl;
295 ssize_t count;
296 unsigned char scode;
297 char *scodedescr;
299 /* read a scancode and test for EOF */
300 CHECK(count = read(fd, &scode, sizeof(scode)));
301 if (count < sizeof(scode)) {
302 return 0;
305 /* print scancode */
306 printf("0x%.2x ", scode);
307 fflush(stdout);
309 /* test for escape */
310 if (!escape && scode == SCODE_ESC) {
311 escape = 1;
312 return 1;
315 /* describe scancode */
316 scodedescr = (escape ? keydescresc : keydescr)[scode & ~SCODE_BREAK];
317 if (scodedescr)
318 printf("[%s] ", scodedescr);
320 if (scode & SCODE_BREAK)
321 printf("up\n");
322 else
323 printf("down\n");
325 fflush(stdout);
327 /* exit on ctrl-C */
328 if ((scode & ~SCODE_BREAK) == 0x1d) {
329 if (escape)
330 rctrl = !(scode & SCODE_BREAK);
331 else
332 lctrl = !(scode & SCODE_BREAK);
334 if ((lctrl || rctrl) && !escape && scode == 0x2e) {
335 return 0;
338 /* next key is not escaped */
339 escape = 0;
341 return 1;
344 static volatile int terminate;
346 static void set_terminate(int signum)
348 terminate = signum;
351 static int testscancodes(int fd)
353 struct termios termios_old, termios_scan;
355 /* this test only works with a TTY as stdin */
356 if (!CHECK(isatty(fd))) {
357 printf("warning: this test can only be run from a console\n");
358 return 0;
361 /* catch fatal signals to restore the console */
362 CHECK((signal(SIGHUP, set_terminate) == SIG_ERR) ? -1 : 0);
363 CHECK((signal(SIGINT, set_terminate) == SIG_ERR) ? -1 : 0);
364 CHECK((signal(SIGQUIT, set_terminate) == SIG_ERR) ? -1 : 0);
365 CHECK((signal(SIGABRT, set_terminate) == SIG_ERR) ? -1 : 0);
366 CHECK((signal(SIGPIPE, set_terminate) == SIG_ERR) ? -1 : 0);
367 CHECK((signal(SIGTERM, set_terminate) == SIG_ERR) ? -1 : 0);
369 /* configure tty in raw input mode with scancodes and no echo */
370 CHECK(tcgetattr(fd, &termios_old));
371 termios_scan = termios_old;
372 termios_scan.c_iflag &= ~(BRKINT | ICRNL | IGNBRK | IGNCR | IGNPAR);
373 termios_scan.c_iflag &= ~(INLCR | INPCK | ISTRIP);
374 termios_scan.c_iflag &= ~(IXOFF | IXON | PARMRK);
375 termios_scan.c_iflag |= SCANCODES;
376 termios_scan.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
377 termios_scan.c_lflag &= ~(ICANON | IEXTEN | ISIG | NOFLSH);
378 CHECK(tcsetattr(fd, TCSANOW, &termios_scan));
380 /* test: is scancode input supported? */
381 CHECK(tcgetattr(fd, &termios_scan));
382 if (termios_scan.c_iflag & SCANCODES) {
383 while (!terminate && CHECK(testscancode(fd))) ;
384 } else {
385 printf("warning: cannot enable SCANCODES "
386 "(are you running from a console?)\n");
389 /* report if closed by a signal */
390 if (terminate) {
391 printf("received signal %d, shutting down\n", terminate);
394 /* restore original input mode */
395 CHECK(tcsetattr(fd, TCSANOW, &termios_old));
397 /* clear buffered input */
398 CHECK(tcflush(fd, TCIFLUSH));
401 int main(void)
403 printf("try out some keys to find out whether SCANCODES works\n");
404 printf("press CTRL+C to end this test\n");
405 printf("please note that this test only works from a console tty\n");
407 /* perform test using stdin */
408 if (testscancodes(STDIN_FILENO) < 0)
409 return -1;
410 else
411 return 0;