Add scancode reading capability to TTY
This commit is contained in:
parent
8005ac2c64
commit
32f43d7571
2 changed files with 418 additions and 0 deletions
10
test/scancodes/Makefile
Normal file
10
test/scancodes/Makefile
Normal file
|
@ -0,0 +1,10 @@
|
|||
all: test-scancodes
|
||||
|
||||
clean:
|
||||
rm -f *.o test-scancodes
|
||||
|
||||
test-scancodes: test-scancodes.o
|
||||
|
||||
test-scancodes.o: test-scancodes.c
|
||||
|
||||
|
408
test/scancodes/test-scancodes.c
Normal file
408
test/scancodes/test-scancodes.c
Normal file
|
@ -0,0 +1,408 @@
|
|||
#define _MINIX
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* list of scancodes to demonstrate whether the keycodes are correct;
|
||||
* source: http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html
|
||||
*/
|
||||
static char *keydescr[] = {
|
||||
NULL, /* 0x00 */
|
||||
"Esc", /* 0x01 */
|
||||
"1!", /* 0x02 */
|
||||
"2@", /* 0x03 */
|
||||
"3#", /* 0x04 */
|
||||
"4$", /* 0x05 */
|
||||
"5%", /* 0x06 */
|
||||
"6^", /* 0x07 */
|
||||
"7&", /* 0x08 */
|
||||
"8*", /* 0x09 */
|
||||
"9(", /* 0x0a */
|
||||
"0)", /* 0x0b */
|
||||
"-_", /* 0x0c */
|
||||
"=+", /* 0x0d */
|
||||
"Backspace", /* 0x0e */
|
||||
"Tab", /* 0x0f */
|
||||
"Q", /* 0x10 */
|
||||
"W", /* 0x11 */
|
||||
"E", /* 0x12 */
|
||||
"R", /* 0x13 */
|
||||
"T", /* 0x14 */
|
||||
"Y", /* 0x15 */
|
||||
"U", /* 0x16 */
|
||||
"I", /* 0x17 */
|
||||
"O", /* 0x18 */
|
||||
"P", /* 0x19 */
|
||||
"[{", /* 0x1a */
|
||||
"]}", /* 0x1b */
|
||||
"Enter", /* 0x1c */
|
||||
"LCtrl", /* 0x1d */
|
||||
"A", /* 0x1e */
|
||||
"S", /* 0x1f */
|
||||
"D", /* 0x20 */
|
||||
"F", /* 0x21 */
|
||||
"G", /* 0x22 */
|
||||
"H", /* 0x23 */
|
||||
"J", /* 0x24 */
|
||||
"K", /* 0x25 */
|
||||
"L", /* 0x26 */
|
||||
";:", /* 0x27 */
|
||||
"'\"", /* 0x28 */
|
||||
"`~", /* 0x29 */
|
||||
"LShift", /* 0x2a */
|
||||
"\\|", /* 0x2b */
|
||||
"Z", /* 0x2c */
|
||||
"X", /* 0x2d */
|
||||
"C", /* 0x2e */
|
||||
"V", /* 0x2f */
|
||||
"B", /* 0x30 */
|
||||
"N", /* 0x31 */
|
||||
"M", /* 0x32 */
|
||||
",<", /* 0x33 */
|
||||
".>", /* 0x34 */
|
||||
"/?", /* 0x35 */
|
||||
"RShift", /* 0x36 */
|
||||
"Keypad-*", /* 0x37 */
|
||||
"LAlt", /* 0x38 */
|
||||
"Space bar", /* 0x39 */
|
||||
"CapsLock", /* 0x3a */
|
||||
"F1", /* 0x3b */
|
||||
"F2", /* 0x3c */
|
||||
"F3", /* 0x3d */
|
||||
"F4", /* 0x3e */
|
||||
"F5", /* 0x3f */
|
||||
"F6", /* 0x40 */
|
||||
"F7", /* 0x41 */
|
||||
"F8", /* 0x42 */
|
||||
"F9", /* 0x43 */
|
||||
"F10", /* 0x44 */
|
||||
"NumLock", /* 0x45 */
|
||||
"ScrollLock", /* 0x46 */
|
||||
"Keypad-7/Home",/* 0x47 */
|
||||
"Keypad-8/Up", /* 0x48 */
|
||||
"Keypad-9/PgUp",/* 0x49 */
|
||||
"Keypad--", /* 0x4a */
|
||||
"Keypad-4/Left",/* 0x4b */
|
||||
"Keypad-5", /* 0x4c */
|
||||
"Keypad-6/Right",/* 0x4d */
|
||||
"Keypad-+", /* 0x4e */
|
||||
"Keypad-1/End", /* 0x4f */
|
||||
"Keypad-2/Down",/* 0x50 */
|
||||
"Keypad-3/PgDn",/* 0x51 */
|
||||
"Keypad-0/Ins", /* 0x52 */
|
||||
"Keypad-./Del", /* 0x53 */
|
||||
"Alt-SysRq", /* 0x54 */
|
||||
NULL, /* 0x55 */
|
||||
NULL, /* 0x56 */
|
||||
"F11", /* 0x57 */
|
||||
"F12", /* 0x58 */
|
||||
NULL, /* 0x59 */
|
||||
NULL, /* 0x5a */
|
||||
NULL, /* 0x5b */
|
||||
NULL, /* 0x5c */
|
||||
NULL, /* 0x5d */
|
||||
NULL, /* 0x5e */
|
||||
NULL, /* 0x5f */
|
||||
NULL, /* 0x60 */
|
||||
NULL, /* 0x61 */
|
||||
NULL, /* 0x62 */
|
||||
NULL, /* 0x63 */
|
||||
NULL, /* 0x64 */
|
||||
NULL, /* 0x65 */
|
||||
NULL, /* 0x66 */
|
||||
NULL, /* 0x67 */
|
||||
NULL, /* 0x68 */
|
||||
NULL, /* 0x69 */
|
||||
NULL, /* 0x6a */
|
||||
NULL, /* 0x6b */
|
||||
NULL, /* 0x6c */
|
||||
NULL, /* 0x6d */
|
||||
NULL, /* 0x6e */
|
||||
NULL, /* 0x6f */
|
||||
NULL, /* 0x70 */
|
||||
NULL, /* 0x71 */
|
||||
NULL, /* 0x72 */
|
||||
NULL, /* 0x73 */
|
||||
NULL, /* 0x74 */
|
||||
NULL, /* 0x75 */
|
||||
NULL, /* 0x76 */
|
||||
NULL, /* 0x77 */
|
||||
NULL, /* 0x78 */
|
||||
NULL, /* 0x79 */
|
||||
NULL, /* 0x7a */
|
||||
NULL, /* 0x7b */
|
||||
NULL, /* 0x7c */
|
||||
NULL, /* 0x7d */
|
||||
NULL, /* 0x7e */
|
||||
NULL, /* 0x7f */
|
||||
};
|
||||
|
||||
static char *keydescresc[] = {
|
||||
NULL, /* 0xe0 0x00 */
|
||||
NULL, /* 0xe0 0x01 */
|
||||
NULL, /* 0xe0 0x02 */
|
||||
NULL, /* 0xe0 0x03 */
|
||||
NULL, /* 0xe0 0x04 */
|
||||
NULL, /* 0xe0 0x05 */
|
||||
NULL, /* 0xe0 0x06 */
|
||||
NULL, /* 0xe0 0x07 */
|
||||
NULL, /* 0xe0 0x08 */
|
||||
NULL, /* 0xe0 0x09 */
|
||||
NULL, /* 0xe0 0x0a */
|
||||
NULL, /* 0xe0 0x0b */
|
||||
NULL, /* 0xe0 0x0c */
|
||||
NULL, /* 0xe0 0x0d */
|
||||
NULL, /* 0xe0 0x0e */
|
||||
NULL, /* 0xe0 0x0f */
|
||||
NULL, /* 0xe0 0x10 */
|
||||
NULL, /* 0xe0 0x11 */
|
||||
NULL, /* 0xe0 0x12 */
|
||||
NULL, /* 0xe0 0x13 */
|
||||
NULL, /* 0xe0 0x14 */
|
||||
NULL, /* 0xe0 0x15 */
|
||||
NULL, /* 0xe0 0x16 */
|
||||
NULL, /* 0xe0 0x17 */
|
||||
NULL, /* 0xe0 0x18 */
|
||||
NULL, /* 0xe0 0x19 */
|
||||
NULL, /* 0xe0 0x1a */
|
||||
NULL, /* 0xe0 0x1b */
|
||||
"Keypad Enter", /* 0xe0 0x1c */
|
||||
"RCtrl", /* 0xe0 0x1d */
|
||||
NULL, /* 0xe0 0x1e */
|
||||
NULL, /* 0xe0 0x1f */
|
||||
NULL, /* 0xe0 0x20 */
|
||||
NULL, /* 0xe0 0x21 */
|
||||
NULL, /* 0xe0 0x22 */
|
||||
NULL, /* 0xe0 0x23 */
|
||||
NULL, /* 0xe0 0x24 */
|
||||
NULL, /* 0xe0 0x25 */
|
||||
NULL, /* 0xe0 0x26 */
|
||||
NULL, /* 0xe0 0x27 */
|
||||
NULL, /* 0xe0 0x28 */
|
||||
NULL, /* 0xe0 0x29 */
|
||||
"fake LShift", /* 0xe0 0x2a */
|
||||
NULL, /* 0xe0 0x2b */
|
||||
NULL, /* 0xe0 0x2c */
|
||||
NULL, /* 0xe0 0x2d */
|
||||
NULL, /* 0xe0 0x2e */
|
||||
NULL, /* 0xe0 0x2f */
|
||||
NULL, /* 0xe0 0x30 */
|
||||
NULL, /* 0xe0 0x31 */
|
||||
NULL, /* 0xe0 0x32 */
|
||||
NULL, /* 0xe0 0x33 */
|
||||
NULL, /* 0xe0 0x34 */
|
||||
"Keypad-/", /* 0xe0 0x35 */
|
||||
"fake RShift", /* 0xe0 0x36 */
|
||||
"Ctrl-PrtScn", /* 0xe0 0x37 */
|
||||
"RAlt", /* 0xe0 0x38 */
|
||||
NULL, /* 0xe0 0x39 */
|
||||
NULL, /* 0xe0 0x3a */
|
||||
NULL, /* 0xe0 0x3b */
|
||||
NULL, /* 0xe0 0x3c */
|
||||
NULL, /* 0xe0 0x3d */
|
||||
NULL, /* 0xe0 0x3e */
|
||||
NULL, /* 0xe0 0x3f */
|
||||
NULL, /* 0xe0 0x40 */
|
||||
NULL, /* 0xe0 0x41 */
|
||||
NULL, /* 0xe0 0x42 */
|
||||
NULL, /* 0xe0 0x43 */
|
||||
NULL, /* 0xe0 0x44 */
|
||||
NULL, /* 0xe0 0x45 */
|
||||
"Ctrl-Break", /* 0xe0 0x46 */
|
||||
"Grey Home", /* 0xe0 0x47 */
|
||||
"Grey Up", /* 0xe0 0x48 */
|
||||
"Grey PgUp", /* 0xe0 0x49 */
|
||||
NULL, /* 0xe0 0x4a */
|
||||
"Grey Left", /* 0xe0 0x4b */
|
||||
NULL, /* 0xe0 0x4c */
|
||||
"Grey Right", /* 0xe0 0x4d */
|
||||
NULL, /* 0xe0 0x4e */
|
||||
"Grey End", /* 0xe0 0x4f */
|
||||
"Grey Down", /* 0xe0 0x50 */
|
||||
"Grey PgDn", /* 0xe0 0x51 */
|
||||
"Grey Insert", /* 0xe0 0x52 */
|
||||
"Grey Delete", /* 0xe0 0x53 */
|
||||
NULL, /* 0xe0 0x54 */
|
||||
NULL, /* 0xe0 0x55 */
|
||||
NULL, /* 0xe0 0x56 */
|
||||
NULL, /* 0xe0 0x57 */
|
||||
NULL, /* 0xe0 0x58 */
|
||||
NULL, /* 0xe0 0x59 */
|
||||
NULL, /* 0xe0 0x5a */
|
||||
"LeftWindow", /* 0xe0 0x5b */
|
||||
"RightWindow", /* 0xe0 0x5c */
|
||||
"Menu", /* 0xe0 0x5d */
|
||||
"Power", /* 0xe0 0x5e */
|
||||
"Sleep", /* 0xe0 0x5f */
|
||||
NULL, /* 0xe0 0x60 */
|
||||
NULL, /* 0xe0 0x61 */
|
||||
NULL, /* 0xe0 0x62 */
|
||||
"Wake", /* 0xe0 0x63 */
|
||||
NULL, /* 0xe0 0x64 */
|
||||
NULL, /* 0xe0 0x65 */
|
||||
NULL, /* 0xe0 0x66 */
|
||||
NULL, /* 0xe0 0x67 */
|
||||
NULL, /* 0xe0 0x68 */
|
||||
NULL, /* 0xe0 0x69 */
|
||||
NULL, /* 0xe0 0x6a */
|
||||
NULL, /* 0xe0 0x6b */
|
||||
NULL, /* 0xe0 0x6c */
|
||||
NULL, /* 0xe0 0x6d */
|
||||
NULL, /* 0xe0 0x6e */
|
||||
NULL, /* 0xe0 0x6f */
|
||||
NULL, /* 0xe0 0x70 */
|
||||
NULL, /* 0xe0 0x71 */
|
||||
NULL, /* 0xe0 0x72 */
|
||||
NULL, /* 0xe0 0x73 */
|
||||
NULL, /* 0xe0 0x74 */
|
||||
NULL, /* 0xe0 0x75 */
|
||||
NULL, /* 0xe0 0x76 */
|
||||
NULL, /* 0xe0 0x77 */
|
||||
NULL, /* 0xe0 0x78 */
|
||||
NULL, /* 0xe0 0x79 */
|
||||
NULL, /* 0xe0 0x7a */
|
||||
NULL, /* 0xe0 0x7b */
|
||||
NULL, /* 0xe0 0x7c */
|
||||
NULL, /* 0xe0 0x7d */
|
||||
NULL, /* 0xe0 0x7e */
|
||||
NULL, /* 0xe0 0x7f */
|
||||
};
|
||||
|
||||
#define CHECK(r) check((r), #r, __FILE__, __LINE__)
|
||||
|
||||
int check(long r, const char *expr, const char *file, int line)
|
||||
{
|
||||
char buffer[256];
|
||||
if (r < 0) {
|
||||
snprintf(buffer, sizeof(buffer), "%s:%d: %s: result %ld, %s",
|
||||
file, line, expr, r, strerror(errno));
|
||||
exit(-1);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
#define SCODE_ESC 0xe0
|
||||
#define SCODE_BREAK 0x80
|
||||
|
||||
static int testscancode(int fd)
|
||||
{
|
||||
static int escape, lctrl, rctrl;
|
||||
ssize_t count;
|
||||
unsigned char scode;
|
||||
char *scodedescr;
|
||||
|
||||
/* read a scancode and test for EOF */
|
||||
CHECK(count = read(fd, &scode, sizeof(scode)));
|
||||
if (count < sizeof(scode)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* print scancode */
|
||||
printf("0x%.2x ", scode);
|
||||
fflush(stdout);
|
||||
|
||||
/* test for escape */
|
||||
if (!escape && scode == SCODE_ESC) {
|
||||
escape = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* describe scancode */
|
||||
scodedescr = (escape ? keydescresc : keydescr)[scode & ~SCODE_BREAK];
|
||||
if (scodedescr)
|
||||
printf("[%s] ", scodedescr);
|
||||
|
||||
if (scode & SCODE_BREAK)
|
||||
printf("up\n");
|
||||
else
|
||||
printf("down\n");
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
/* exit on ctrl-C */
|
||||
if ((scode & ~SCODE_BREAK) == 0x1d) {
|
||||
if (escape)
|
||||
rctrl = !(scode & SCODE_BREAK);
|
||||
else
|
||||
lctrl = !(scode & SCODE_BREAK);
|
||||
}
|
||||
if ((lctrl || rctrl) && !escape && scode == 0x2e) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* next key is not escaped */
|
||||
escape = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static volatile int terminate;
|
||||
|
||||
static void set_terminate(int signum)
|
||||
{
|
||||
terminate = signum;
|
||||
}
|
||||
|
||||
static int testscancodes(int fd)
|
||||
{
|
||||
struct termios termios_old, termios_scan;
|
||||
|
||||
/* this test only works with a TTY as stdin */
|
||||
if (!CHECK(isatty(fd))) {
|
||||
printf("warning: this test can only be run from a console\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* catch fatal signals to restore the console */
|
||||
CHECK((signal(SIGHUP, set_terminate) == SIG_ERR) ? -1 : 0);
|
||||
CHECK((signal(SIGINT, set_terminate) == SIG_ERR) ? -1 : 0);
|
||||
CHECK((signal(SIGQUIT, set_terminate) == SIG_ERR) ? -1 : 0);
|
||||
CHECK((signal(SIGABRT, set_terminate) == SIG_ERR) ? -1 : 0);
|
||||
CHECK((signal(SIGPIPE, set_terminate) == SIG_ERR) ? -1 : 0);
|
||||
CHECK((signal(SIGTERM, set_terminate) == SIG_ERR) ? -1 : 0);
|
||||
|
||||
/* configure tty in raw input mode with scancodes and no echo */
|
||||
CHECK(tcgetattr(fd, &termios_old));
|
||||
termios_scan = termios_old;
|
||||
termios_scan.c_iflag &= ~(BRKINT | ICRNL | IGNBRK | IGNCR | IGNPAR);
|
||||
termios_scan.c_iflag &= ~(INLCR | INPCK | ISTRIP);
|
||||
termios_scan.c_iflag &= ~(IXOFF | IXON | PARMRK);
|
||||
termios_scan.c_iflag |= SCANCODES;
|
||||
termios_scan.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
|
||||
termios_scan.c_lflag &= ~(ICANON | IEXTEN | ISIG | NOFLSH);
|
||||
CHECK(tcsetattr(fd, TCSANOW, &termios_scan));
|
||||
|
||||
/* test: is scancode input supported? */
|
||||
CHECK(tcgetattr(fd, &termios_scan));
|
||||
if (termios_scan.c_iflag & SCANCODES) {
|
||||
while (!terminate && CHECK(testscancode(fd))) ;
|
||||
} else {
|
||||
printf("warning: cannot enable SCANCODES "
|
||||
"(are you running from a console?)\n");
|
||||
}
|
||||
|
||||
/* report if closed by a signal */
|
||||
if (terminate) {
|
||||
printf("received signal %d, shutting down\n", terminate);
|
||||
}
|
||||
|
||||
/* restore original input mode */
|
||||
CHECK(tcsetattr(fd, TCSANOW, &termios_old));
|
||||
|
||||
/* clear buffered input */
|
||||
CHECK(tcflush(fd, TCIFLUSH));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* perform test using stdin */
|
||||
if (testscancodes(STDIN_FILENO) < 0)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue