| #include <stdio.h> |
| #include <unistd.h> |
| #include <getopt.h> |
| #include <signal.h> |
| #include <fcntl.h> |
| #include <termios.h> |
| #include <linux/kd.h> |
| #include <linux/keyboard.h> |
| #include <sys/ioctl.h> |
| #include "getfd.h" |
| #include "nls.h" |
| #include "version.h" |
| |
| int tmp; /* for debugging */ |
| |
| int fd; |
| int oldkbmode; |
| struct termios old; |
| |
| /* |
| * version 0.81 of showkey would restore kbmode unconditially to XLATE, |
| * thus making the console unusable when it was called under X. |
| */ |
| static void |
| get_mode(void) { |
| char *m; |
| |
| if (ioctl(fd, KDGKBMODE, &oldkbmode)) { |
| perror("KDGKBMODE"); |
| exit(1); |
| } |
| switch(oldkbmode) { |
| case K_RAW: |
| m = "RAW"; break; |
| case K_XLATE: |
| m = "XLATE"; break; |
| case K_MEDIUMRAW: |
| m = "MEDIUMRAW"; break; |
| case K_UNICODE: |
| m = "UNICODE"; break; |
| default: |
| m = _("?UNKNOWN?"); break; |
| } |
| printf(_("kb mode was %s\n"), m); |
| if (oldkbmode != K_XLATE) { |
| printf(_("[ if you are trying this under X, it might not work\n" |
| "since the X server is also reading /dev/console ]\n")); |
| } |
| printf("\n"); |
| } |
| |
| static void |
| clean_up(void) { |
| if (ioctl(fd, KDSKBMODE, oldkbmode)) { |
| perror("KDSKBMODE"); |
| exit(1); |
| } |
| if (tcsetattr(fd, 0, &old) == -1) |
| perror("tcsetattr"); |
| close(fd); |
| } |
| |
| static void |
| die(int x) { |
| printf(_("caught signal %d, cleaning up...\n"), x); |
| clean_up(); |
| exit(1); |
| } |
| |
| static void |
| watch_dog(int x) { |
| clean_up(); |
| exit(0); |
| } |
| |
| static void |
| usage(void) { |
| fprintf(stderr, _( |
| "showkey version %s\n\n" |
| "usage: showkey [options...]\n" |
| "\n" |
| "valid options are:\n" |
| "\n" |
| " -h --help display this help text\n" |
| " -a --ascii display the decimal/octal/hex values of the keys\n" |
| " -s --scancodes display only the raw scan-codes\n" |
| " -k --keycodes display only the interpreted keycodes (default)\n" |
| ), VERSION); |
| exit(1); |
| } |
| |
| int |
| main (int argc, char *argv[]) { |
| const char *short_opts = "haskV"; |
| const struct option long_opts[] = { |
| { "help", no_argument, NULL, 'h' }, |
| { "ascii", no_argument, NULL, 'a' }, |
| { "scancodes", no_argument, NULL, 's' }, |
| { "keycodes", no_argument, NULL, 'k' }, |
| { "version", no_argument, NULL, 'V' }, |
| { NULL, 0, NULL, 0 } |
| }; |
| int c; |
| int show_keycodes = 1; |
| int print_ascii = 0; |
| |
| struct termios new; |
| unsigned char buf[16]; |
| int i, n; |
| |
| set_progname(argv[0]); |
| |
| setlocale(LC_ALL, ""); |
| bindtextdomain(PACKAGE, LOCALEDIR); |
| textdomain(PACKAGE); |
| |
| while ((c = getopt_long(argc, argv, |
| short_opts, long_opts, NULL)) != -1) { |
| switch (c) { |
| case 's': |
| show_keycodes = 0; |
| break; |
| case 'k': |
| show_keycodes = 1; |
| break; |
| case 'a': |
| print_ascii = 1; |
| break; |
| case 'V': |
| print_version_and_exit(); |
| case 'h': |
| case '?': |
| usage(); |
| } |
| } |
| |
| if (optind < argc) |
| usage(); |
| |
| if (print_ascii) { |
| /* no mode and signal and timer stuff - just read stdin */ |
| fd = 0; |
| |
| if (tcgetattr(fd, &old) == -1) |
| perror("tcgetattr"); |
| if (tcgetattr(fd, &new) == -1) |
| perror("tcgetattr"); |
| |
| new.c_lflag &= ~ (ICANON | ISIG); |
| new.c_lflag |= (ECHO | ECHOCTL); |
| new.c_iflag = 0; |
| new.c_cc[VMIN] = 1; |
| new.c_cc[VTIME] = 0; |
| |
| if (tcsetattr(fd, TCSAFLUSH, &new) == -1) |
| perror("tcgetattr"); |
| printf(_("\nPress any keys - " |
| "Ctrl-D will terminate this program\n\n")); |
| |
| while (1) { |
| n = read(fd, buf, 1); |
| if (n == 1) |
| printf(" \t%3d 0%03o 0x%02x\n", |
| buf[0], buf[0], buf[0]); |
| if (n != 1 || buf[0] == 04) |
| break; |
| } |
| |
| if (tcsetattr(fd, 0, &old) == -1) |
| perror("tcsetattr"); |
| exit(0); |
| } |
| |
| |
| fd = getfd(NULL); |
| |
| /* the program terminates when there is no input for 10 secs */ |
| signal(SIGALRM, watch_dog); |
| |
| /* |
| if we receive a signal, we want to exit nicely, in |
| order not to leave the keyboard in an unusable mode |
| */ |
| signal(SIGHUP, die); |
| signal(SIGINT, die); |
| signal(SIGQUIT, die); |
| signal(SIGILL, die); |
| signal(SIGTRAP, die); |
| signal(SIGABRT, die); |
| signal(SIGIOT, die); |
| signal(SIGFPE, die); |
| signal(SIGKILL, die); |
| signal(SIGUSR1, die); |
| signal(SIGSEGV, die); |
| signal(SIGUSR2, die); |
| signal(SIGPIPE, die); |
| signal(SIGTERM, die); |
| #ifdef SIGSTKFLT |
| signal(SIGSTKFLT, die); |
| #endif |
| signal(SIGCHLD, die); |
| signal(SIGCONT, die); |
| signal(SIGSTOP, die); |
| signal(SIGTSTP, die); |
| signal(SIGTTIN, die); |
| signal(SIGTTOU, die); |
| |
| get_mode(); |
| if (tcgetattr(fd, &old) == -1) |
| perror("tcgetattr"); |
| if (tcgetattr(fd, &new) == -1) |
| perror("tcgetattr"); |
| |
| new.c_lflag &= ~ (ICANON | ECHO | ISIG); |
| new.c_iflag = 0; |
| new.c_cc[VMIN] = sizeof(buf); |
| new.c_cc[VTIME] = 1; /* 0.1 sec intercharacter timeout */ |
| |
| if (tcsetattr(fd, TCSAFLUSH, &new) == -1) |
| perror("tcsetattr"); |
| if (ioctl(fd, KDSKBMODE, show_keycodes ? K_MEDIUMRAW : K_RAW)) { |
| perror("KDSKBMODE"); |
| exit(1); |
| } |
| |
| printf(_("press any key (program terminates 10s after last keypress)...\n")); |
| while (1) { |
| alarm(10); |
| n = read(fd, buf, sizeof(buf)); |
| for (i = 0; i < n; i++) { |
| if (!show_keycodes) |
| printf("0x%02x ", buf[i]); |
| else |
| printf(_("keycode %3d %s\n"), |
| buf[i] & 0x7f, |
| buf[i] & 0x80 ? _("release") |
| : _("press")); |
| } |
| if (!show_keycodes) |
| printf("\n"); |
| } |
| |
| clean_up(); |
| exit(0); |
| } |