• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/busybox/console-tools/
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