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
[] = {
29 "Backspace", /* 0x0e */
70 "Keypad-*", /* 0x37 */
72 "Space bar", /* 0x39 */
73 "CapsLock", /* 0x3a */
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 */
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
)
282 snprintf(buffer
, sizeof(buffer
), "%s:%d: %s: result %ld, %s",
283 file
, line
, expr
, r
, strerror(errno
));
289 #define SCODE_ESC 0xe0
290 #define SCODE_BREAK 0x80
292 static int testscancode(int fd
)
294 static int escape
, lctrl
, rctrl
;
299 /* read a scancode and test for EOF */
300 CHECK(count
= read(fd
, &scode
, sizeof(scode
)));
301 if (count
< sizeof(scode
)) {
306 printf("0x%.2x ", scode
);
309 /* test for escape */
310 if (!escape
&& scode
== SCODE_ESC
) {
315 /* describe scancode */
316 scodedescr
= (escape
? keydescresc
: keydescr
)[scode
& ~SCODE_BREAK
];
318 printf("[%s] ", scodedescr
);
320 if (scode
& SCODE_BREAK
)
328 if ((scode
& ~SCODE_BREAK
) == 0x1d) {
330 rctrl
= !(scode
& SCODE_BREAK
);
332 lctrl
= !(scode
& SCODE_BREAK
);
334 if ((lctrl
|| rctrl
) && !escape
&& scode
== 0x2e) {
338 /* next key is not escaped */
344 static volatile int terminate
;
346 static void set_terminate(int 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");
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
))) ;
385 printf("warning: cannot enable SCANCODES "
386 "(are you running from a console?)\n");
389 /* report if closed by a signal */
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
));
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)