9 /* list of scancodes to demonstrate whether the keycodes are correct;
10 * source: http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html
12 static char *keydescr
[] = {
27 "Backspace", /* 0x0e */
68 "Keypad-*", /* 0x37 */
70 "Space bar", /* 0x39 */
71 "CapsLock", /* 0x3a */
83 "ScrollLock", /* 0x46 */
84 "Keypad-7/Home",/* 0x47 */
85 "Keypad-8/Up", /* 0x48 */
86 "Keypad-9/PgUp",/* 0x49 */
87 "Keypad--", /* 0x4a */
88 "Keypad-4/Left",/* 0x4b */
89 "Keypad-5", /* 0x4c */
90 "Keypad-6/Right",/* 0x4d */
91 "Keypad-+", /* 0x4e */
92 "Keypad-1/End", /* 0x4f */
93 "Keypad-2/Down",/* 0x50 */
94 "Keypad-3/PgDn",/* 0x51 */
95 "Keypad-0/Ins", /* 0x52 */
96 "Keypad-./Del", /* 0x53 */
97 "Alt-SysRq", /* 0x54 */
143 static char *keydescresc
[] = {
144 NULL
, /* 0xe0 0x00 */
145 NULL
, /* 0xe0 0x01 */
146 NULL
, /* 0xe0 0x02 */
147 NULL
, /* 0xe0 0x03 */
148 NULL
, /* 0xe0 0x04 */
149 NULL
, /* 0xe0 0x05 */
150 NULL
, /* 0xe0 0x06 */
151 NULL
, /* 0xe0 0x07 */
152 NULL
, /* 0xe0 0x08 */
153 NULL
, /* 0xe0 0x09 */
154 NULL
, /* 0xe0 0x0a */
155 NULL
, /* 0xe0 0x0b */
156 NULL
, /* 0xe0 0x0c */
157 NULL
, /* 0xe0 0x0d */
158 NULL
, /* 0xe0 0x0e */
159 NULL
, /* 0xe0 0x0f */
160 NULL
, /* 0xe0 0x10 */
161 NULL
, /* 0xe0 0x11 */
162 NULL
, /* 0xe0 0x12 */
163 NULL
, /* 0xe0 0x13 */
164 NULL
, /* 0xe0 0x14 */
165 NULL
, /* 0xe0 0x15 */
166 NULL
, /* 0xe0 0x16 */
167 NULL
, /* 0xe0 0x17 */
168 NULL
, /* 0xe0 0x18 */
169 NULL
, /* 0xe0 0x19 */
170 NULL
, /* 0xe0 0x1a */
171 NULL
, /* 0xe0 0x1b */
172 "Keypad Enter", /* 0xe0 0x1c */
173 "RCtrl", /* 0xe0 0x1d */
174 NULL
, /* 0xe0 0x1e */
175 NULL
, /* 0xe0 0x1f */
176 NULL
, /* 0xe0 0x20 */
177 NULL
, /* 0xe0 0x21 */
178 NULL
, /* 0xe0 0x22 */
179 NULL
, /* 0xe0 0x23 */
180 NULL
, /* 0xe0 0x24 */
181 NULL
, /* 0xe0 0x25 */
182 NULL
, /* 0xe0 0x26 */
183 NULL
, /* 0xe0 0x27 */
184 NULL
, /* 0xe0 0x28 */
185 NULL
, /* 0xe0 0x29 */
186 "fake LShift", /* 0xe0 0x2a */
187 NULL
, /* 0xe0 0x2b */
188 NULL
, /* 0xe0 0x2c */
189 NULL
, /* 0xe0 0x2d */
190 NULL
, /* 0xe0 0x2e */
191 NULL
, /* 0xe0 0x2f */
192 NULL
, /* 0xe0 0x30 */
193 NULL
, /* 0xe0 0x31 */
194 NULL
, /* 0xe0 0x32 */
195 NULL
, /* 0xe0 0x33 */
196 NULL
, /* 0xe0 0x34 */
197 "Keypad-/", /* 0xe0 0x35 */
198 "fake RShift", /* 0xe0 0x36 */
199 "Ctrl-PrtScn", /* 0xe0 0x37 */
200 "RAlt", /* 0xe0 0x38 */
201 NULL
, /* 0xe0 0x39 */
202 NULL
, /* 0xe0 0x3a */
203 NULL
, /* 0xe0 0x3b */
204 NULL
, /* 0xe0 0x3c */
205 NULL
, /* 0xe0 0x3d */
206 NULL
, /* 0xe0 0x3e */
207 NULL
, /* 0xe0 0x3f */
208 NULL
, /* 0xe0 0x40 */
209 NULL
, /* 0xe0 0x41 */
210 NULL
, /* 0xe0 0x42 */
211 NULL
, /* 0xe0 0x43 */
212 NULL
, /* 0xe0 0x44 */
213 NULL
, /* 0xe0 0x45 */
214 "Ctrl-Break", /* 0xe0 0x46 */
215 "Grey Home", /* 0xe0 0x47 */
216 "Grey Up", /* 0xe0 0x48 */
217 "Grey PgUp", /* 0xe0 0x49 */
218 NULL
, /* 0xe0 0x4a */
219 "Grey Left", /* 0xe0 0x4b */
220 NULL
, /* 0xe0 0x4c */
221 "Grey Right", /* 0xe0 0x4d */
222 NULL
, /* 0xe0 0x4e */
223 "Grey End", /* 0xe0 0x4f */
224 "Grey Down", /* 0xe0 0x50 */
225 "Grey PgDn", /* 0xe0 0x51 */
226 "Grey Insert", /* 0xe0 0x52 */
227 "Grey Delete", /* 0xe0 0x53 */
228 NULL
, /* 0xe0 0x54 */
229 NULL
, /* 0xe0 0x55 */
230 NULL
, /* 0xe0 0x56 */
231 NULL
, /* 0xe0 0x57 */
232 NULL
, /* 0xe0 0x58 */
233 NULL
, /* 0xe0 0x59 */
234 NULL
, /* 0xe0 0x5a */
235 "LeftWindow", /* 0xe0 0x5b */
236 "RightWindow", /* 0xe0 0x5c */
237 "Menu", /* 0xe0 0x5d */
238 "Power", /* 0xe0 0x5e */
239 "Sleep", /* 0xe0 0x5f */
240 NULL
, /* 0xe0 0x60 */
241 NULL
, /* 0xe0 0x61 */
242 NULL
, /* 0xe0 0x62 */
243 "Wake", /* 0xe0 0x63 */
244 NULL
, /* 0xe0 0x64 */
245 NULL
, /* 0xe0 0x65 */
246 NULL
, /* 0xe0 0x66 */
247 NULL
, /* 0xe0 0x67 */
248 NULL
, /* 0xe0 0x68 */
249 NULL
, /* 0xe0 0x69 */
250 NULL
, /* 0xe0 0x6a */
251 NULL
, /* 0xe0 0x6b */
252 NULL
, /* 0xe0 0x6c */
253 NULL
, /* 0xe0 0x6d */
254 NULL
, /* 0xe0 0x6e */
255 NULL
, /* 0xe0 0x6f */
256 NULL
, /* 0xe0 0x70 */
257 NULL
, /* 0xe0 0x71 */
258 NULL
, /* 0xe0 0x72 */
259 NULL
, /* 0xe0 0x73 */
260 NULL
, /* 0xe0 0x74 */
261 NULL
, /* 0xe0 0x75 */
262 NULL
, /* 0xe0 0x76 */
263 NULL
, /* 0xe0 0x77 */
264 NULL
, /* 0xe0 0x78 */
265 NULL
, /* 0xe0 0x79 */
266 NULL
, /* 0xe0 0x7a */
267 NULL
, /* 0xe0 0x7b */
268 NULL
, /* 0xe0 0x7c */
269 NULL
, /* 0xe0 0x7d */
270 NULL
, /* 0xe0 0x7e */
271 NULL
, /* 0xe0 0x7f */
274 #define CHECK(r) check((r), #r, __FILE__, __LINE__)
276 int check(long r
, const char *expr
, const char *file
, int line
)
280 snprintf(buffer
, sizeof(buffer
), "%s:%d: %s: result %ld, %s",
281 file
, line
, expr
, r
, strerror(errno
));
287 #define SCODE_ESC 0xe0
288 #define SCODE_BREAK 0x80
290 static int testscancode(int fd
)
292 static int escape
, lctrl
, rctrl
;
297 /* read a scancode and test for EOF */
298 CHECK(count
= read(fd
, &scode
, sizeof(scode
)));
299 if (count
< sizeof(scode
)) {
304 printf("0x%.2x ", scode
);
307 /* test for escape */
308 if (!escape
&& scode
== SCODE_ESC
) {
313 /* describe scancode */
314 scodedescr
= (escape
? keydescresc
: keydescr
)[scode
& ~SCODE_BREAK
];
316 printf("[%s] ", scodedescr
);
318 if (scode
& SCODE_BREAK
)
326 if ((scode
& ~SCODE_BREAK
) == 0x1d) {
328 rctrl
= !(scode
& SCODE_BREAK
);
330 lctrl
= !(scode
& SCODE_BREAK
);
332 if ((lctrl
|| rctrl
) && !escape
&& scode
== 0x2e) {
336 /* next key is not escaped */
342 static volatile int terminate
;
344 static void set_terminate(int signum
)
349 static int testscancodes(int fd
)
351 struct termios termios_old
, termios_scan
;
353 /* this test only works with a TTY as stdin */
354 if (!CHECK(isatty(fd
))) {
355 printf("warning: this test can only be run from a console\n");
359 /* catch fatal signals to restore the console */
360 CHECK((signal(SIGHUP
, set_terminate
) == SIG_ERR
) ? -1 : 0);
361 CHECK((signal(SIGINT
, set_terminate
) == SIG_ERR
) ? -1 : 0);
362 CHECK((signal(SIGQUIT
, set_terminate
) == SIG_ERR
) ? -1 : 0);
363 CHECK((signal(SIGABRT
, set_terminate
) == SIG_ERR
) ? -1 : 0);
364 CHECK((signal(SIGPIPE
, set_terminate
) == SIG_ERR
) ? -1 : 0);
365 CHECK((signal(SIGTERM
, set_terminate
) == SIG_ERR
) ? -1 : 0);
367 /* configure tty in raw input mode with scancodes and no echo */
368 CHECK(tcgetattr(fd
, &termios_old
));
369 termios_scan
= termios_old
;
370 termios_scan
.c_iflag
&= ~(BRKINT
| ICRNL
| IGNBRK
| IGNCR
| IGNPAR
);
371 termios_scan
.c_iflag
&= ~(INLCR
| INPCK
| ISTRIP
);
372 termios_scan
.c_iflag
&= ~(IXOFF
| IXON
| PARMRK
);
373 termios_scan
.c_iflag
|= SCANCODES
;
374 termios_scan
.c_lflag
&= ~(ECHO
| ECHOE
| ECHOK
| ECHONL
);
375 termios_scan
.c_lflag
&= ~(ICANON
| IEXTEN
| ISIG
| NOFLSH
);
376 CHECK(tcsetattr(fd
, TCSANOW
, &termios_scan
));
378 /* test: is scancode input supported? */
379 CHECK(tcgetattr(fd
, &termios_scan
));
380 if (termios_scan
.c_iflag
& SCANCODES
) {
381 while (!terminate
&& CHECK(testscancode(fd
))) ;
383 printf("warning: cannot enable SCANCODES "
384 "(are you running from a console?)\n");
387 /* report if closed by a signal */
389 printf("received signal %d, shutting down\n", terminate
);
392 /* restore original input mode */
393 CHECK(tcsetattr(fd
, TCSANOW
, &termios_old
));
395 /* clear buffered input */
396 CHECK(tcflush(fd
, TCIFLUSH
));
401 printf("try out some keys to find out whether SCANCODES works\n");
402 printf("press CTRL+C to end this test\n");
403 printf("please note that this test only works from a console tty\n");
405 /* perform test using stdin */
406 if (testscancodes(STDIN_FILENO
) < 0)