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