blob: 149ea64659f2f13b50fe34ac9768ab22954f77cc [file] [log] [blame]
Denis Vlasenkod7cc2e62008-08-17 14:17:48 +00001/* 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 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02007 * Licensed under GPLv2, see file LICENSE in this source tree.
Denis Vlasenkod7cc2e62008-08-17 14:17:48 +00008 */
9
10#include "libbb.h"
11#include <linux/kd.h>
12
13// set raw tty mode
14// also used by microcom
15// libbb candidates?
Denys Vlasenkocc131532010-08-29 05:00:40 +020016static void xget1(struct termios *t, struct termios *oldt)
Denis Vlasenkod7cc2e62008-08-17 14:17:48 +000017{
Denys Vlasenkocc131532010-08-29 05:00:40 +020018 tcgetattr(STDIN_FILENO, oldt);
Denis Vlasenkod7cc2e62008-08-17 14:17:48 +000019 *t = *oldt;
20 cfmakeraw(t);
21}
22
Denys Vlasenkocc131532010-08-29 05:00:40 +020023static void xset1(struct termios *tio)
Denis Vlasenkod7cc2e62008-08-17 14:17:48 +000024{
Denys Vlasenkocc131532010-08-29 05:00:40 +020025 int ret = tcsetattr(STDIN_FILENO, TCSAFLUSH, tio);
Denis Vlasenkod7cc2e62008-08-17 14:17:48 +000026 if (ret) {
Denys Vlasenkocc131532010-08-29 05:00:40 +020027 bb_perror_msg("can't tcsetattr for stdin");
Denis Vlasenkod7cc2e62008-08-17 14:17:48 +000028 }
Denis Vlasenkod7cc2e62008-08-17 14:17:48 +000029}
30
31/*
32 * GLOBALS
33 */
34struct globals {
35 int kbmode;
36 struct termios tio, tio0;
37};
38#define G (*ptr_to_globals)
39#define kbmode (G.kbmode)
40#define tio (G.tio)
41#define tio0 (G.tio0)
42#define INIT_G() do { \
43 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
44} while (0)
45
46
47static void signal_handler(int signo)
48{
49 // restore keyboard and console settings
Denys Vlasenkocc131532010-08-29 05:00:40 +020050 xset1(&tio0);
Denis Vlasenko651d49a2008-09-28 16:44:28 +000051 xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)kbmode);
Denis Vlasenkod7cc2e62008-08-17 14:17:48 +000052 // alarmed? -> exit 0
53 exit(SIGALRM == signo);
54}
55
56int showkey_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
57int showkey_main(int argc UNUSED_PARAM, char **argv)
58{
59 enum {
60 OPT_a = (1<<0), // display the decimal/octal/hex values of the keys
61 OPT_k = (1<<1), // display only the interpreted keycodes (default)
62 OPT_s = (1<<2), // display only the raw scan-codes
63 };
64
65 // FIXME: aks are all mutually exclusive
66 getopt32(argv, "aks");
67
68 INIT_G();
69
70 // get keyboard settings
71 xioctl(STDIN_FILENO, KDGKBMODE, &kbmode);
72 printf("kb mode was %s\n\nPress any keys. Program terminates %s\n\n",
Denis Vlasenkoea7c9b32008-09-25 10:39:10 +000073 kbmode == K_RAW ? "RAW" :
74 (kbmode == K_XLATE ? "XLATE" :
75 (kbmode == K_MEDIUMRAW ? "MEDIUMRAW" :
Denis Vlasenkod7cc2e62008-08-17 14:17:48 +000076 (kbmode == K_UNICODE ? "UNICODE" : "?UNKNOWN?")))
77 , (option_mask32 & OPT_a) ? "when CTRL+D pressed" : "10s after last keypress"
78 );
79 // prepare for raw mode
Denys Vlasenkocc131532010-08-29 05:00:40 +020080 xget1(&tio, &tio0);
Denis Vlasenkod7cc2e62008-08-17 14:17:48 +000081 // put stdin in raw mode
Denys Vlasenkocc131532010-08-29 05:00:40 +020082 xset1(&tio);
Denis Vlasenkod7cc2e62008-08-17 14:17:48 +000083
84 if (option_mask32 & OPT_a) {
Denys Vlasenkocc131532010-08-29 05:00:40 +020085 unsigned char c;
Denis Vlasenkod7cc2e62008-08-17 14:17:48 +000086 // just read stdin char by char
87 while (1 == safe_read(STDIN_FILENO, &c, 1)) {
Denys Vlasenkocc131532010-08-29 05:00:40 +020088 printf("%3u 0%03o 0x%02x\r\n", c, c, c);
Denis Vlasenkod7cc2e62008-08-17 14:17:48 +000089 if (04 /*CTRL-D*/ == c)
90 break;
91 }
92 } else {
93 // we should exit on any signal
94 bb_signals(BB_FATAL_SIGS, signal_handler);
95 // set raw keyboard mode
Denis Vlasenko651d49a2008-09-28 16:44:28 +000096 xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)((option_mask32 & OPT_k) ? K_MEDIUMRAW : K_RAW));
Denis Vlasenkod7cc2e62008-08-17 14:17:48 +000097
98 // read and show scancodes
99 while (1) {
100 char buf[18];
101 int i, n;
102 // setup 10s watchdog
103 alarm(10);
104 // read scancodes
105 n = read(STDIN_FILENO, buf, sizeof(buf));
106 i = 0;
107 while (i < n) {
108 char c = buf[i];
109 // show raw scancodes ordered? ->
110 if (option_mask32 & OPT_s) {
111 printf("0x%02x ", buf[i++]);
112 // show interpreted scancodes (default) ? ->
113 } else {
114 int kc;
Denys Vlasenkocc131532010-08-29 05:00:40 +0200115 if (i+2 < n
116 && (c & 0x7f) == 0
117 && (buf[i+1] & 0x80) != 0
118 && (buf[i+2] & 0x80) != 0
119 ) {
Denis Vlasenkod7cc2e62008-08-17 14:17:48 +0000120 kc = ((buf[i+1] & 0x7f) << 7) | (buf[i+2] & 0x7f);
121 i += 3;
122 } else {
123 kc = (c & 0x7f);
124 i++;
125 }
Denys Vlasenkocc131532010-08-29 05:00:40 +0200126 printf("keycode %3u %s", kc, (c & 0x80) ? "release" : "press");
Denis Vlasenkod7cc2e62008-08-17 14:17:48 +0000127 }
128 }
129 puts("\r");
130 }
131 }
132
133 // cleanup
134 signal_handler(SIGALRM);
135
136 // should never be here!
137 return EXIT_SUCCESS;
138}