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