busybox/console-tools/showkey.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * shows keys pressed. inspired by kbd package
   4 *
   5 * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
   6 *
   7 * Licensed under GPLv2, see file LICENSE in this tarball for details.
   8 */
   9
  10#include "libbb.h"
  11#include <linux/kd.h>
  12
  13// set raw tty mode
  14// also used by microcom
  15// libbb candidates?
  16static void xget1(int fd, struct termios *t, struct termios *oldt)
  17{
  18        tcgetattr(fd, oldt);
  19        *t = *oldt;
  20        cfmakeraw(t);
  21}
  22
  23static int xset1(int fd, struct termios *tio, const char *device)
  24{
  25        int ret = tcsetattr(fd, TCSAFLUSH, tio);
  26
  27        if (ret) {
  28                bb_perror_msg("can't tcsetattr for %s", device);
  29        }
  30        return ret;
  31}
  32
  33/*
  34 * GLOBALS
  35 */
  36struct globals {
  37        int kbmode;
  38        struct termios tio, tio0;
  39};
  40#define G (*ptr_to_globals)
  41#define kbmode  (G.kbmode)
  42#define tio     (G.tio)
  43#define tio0    (G.tio0)
  44#define INIT_G() do { \
  45        SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
  46} while (0)
  47
  48
  49static void signal_handler(int signo)
  50{
  51        // restore keyboard and console settings
  52        xset1(STDIN_FILENO, &tio0, "stdin");
  53        xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)kbmode);
  54        // alarmed? -> exit 0
  55        exit(SIGALRM == signo);
  56}
  57
  58int showkey_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  59int showkey_main(int argc UNUSED_PARAM, char **argv)
  60{
  61        enum {
  62                OPT_a = (1<<0), // display the decimal/octal/hex values of the keys
  63                OPT_k = (1<<1), // display only the interpreted keycodes (default)
  64                OPT_s = (1<<2), // display only the raw scan-codes
  65        };
  66
  67        // FIXME: aks are all mutually exclusive
  68        getopt32(argv, "aks");
  69
  70        INIT_G();
  71
  72        // get keyboard settings
  73        xioctl(STDIN_FILENO, KDGKBMODE, &kbmode);
  74        printf("kb mode was %s\n\nPress any keys. Program terminates %s\n\n",
  75                kbmode == K_RAW ? "RAW" :
  76                        (kbmode == K_XLATE ? "XLATE" :
  77                                (kbmode == K_MEDIUMRAW ? "MEDIUMRAW" :
  78                                        (kbmode == K_UNICODE ? "UNICODE" : "?UNKNOWN?")))
  79                , (option_mask32 & OPT_a) ? "when CTRL+D pressed" : "10s after last keypress"
  80        );
  81        // prepare for raw mode
  82        xget1(STDIN_FILENO, &tio, &tio0);
  83        // put stdin in raw mode
  84        xset1(STDIN_FILENO, &tio, "stdin");
  85
  86        if (option_mask32 & OPT_a) {
  87                char c;
  88                // just read stdin char by char
  89                while (1 == safe_read(STDIN_FILENO, &c, 1)) {
  90                        printf("%3d 0%03o 0x%02x\r\n", c, c, c);
  91                        if (04 /*CTRL-D*/ == c)
  92                                break;
  93                }
  94        } else {
  95                // we should exit on any signal
  96                bb_signals(BB_FATAL_SIGS, signal_handler);
  97                // set raw keyboard mode
  98                xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)((option_mask32 & OPT_k) ? K_MEDIUMRAW : K_RAW));
  99
 100                // read and show scancodes
 101                while (1) {
 102                        char buf[18];
 103                        int i, n;
 104                        // setup 10s watchdog
 105                        alarm(10);
 106                        // read scancodes
 107                        n = read(STDIN_FILENO, buf, sizeof(buf));
 108                        i = 0;
 109                        while (i < n) {
 110                                char c = buf[i];
 111                                // show raw scancodes ordered? ->
 112                                if (option_mask32 & OPT_s) {
 113                                        printf("0x%02x ", buf[i++]);
 114                                // show interpreted scancodes (default) ? ->
 115                                } else {
 116                                        int kc;
 117                                        if (i+2 < n && (c & 0x7f) == 0
 118                                                && (buf[i+1] & 0x80) != 0
 119                                                && (buf[i+2] & 0x80) != 0) {
 120                                                kc = ((buf[i+1] & 0x7f) << 7) | (buf[i+2] & 0x7f);
 121                                                i += 3;
 122                                        } else {
 123                                                kc = (c & 0x7f);
 124                                                i++;
 125                                        }
 126                                        printf("keycode %3d %s", kc, (c & 0x80) ? "release" : "press");
 127                                }
 128                        }
 129                        puts("\r");
 130                }
 131        }
 132
 133        // cleanup
 134        signal_handler(SIGALRM);
 135
 136        // should never be here!
 137        return EXIT_SUCCESS;
 138}
 139