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
|
#include "libbb.h"
int tcsetattr(int fd, int mode UNUSED_PARAM, const struct termios *t)
{
if (terminal_mode(FALSE) & VT_INPUT) {
HANDLE h = (HANDLE)_get_osfhandle(fd);
if (!SetConsoleMode(h, t->imode)) {
errno = err_win_to_posix();
return -1;
}
}
return 0;
}
int tcgetattr(int fd, struct termios *t)
{
if (terminal_mode(FALSE) & VT_INPUT) {
HANDLE h = (HANDLE)_get_osfhandle(fd);
if (!GetConsoleMode(h, &t->imode)) {
errno = err_win_to_posix();
return -1;
}
}
t->c_cc[VINTR] = 3; // ctrl-c
t->c_cc[VEOF] = 4; // ctrl-d
return 0;
}
int64_t FAST_FUNC windows_read_key(int fd, char *buf UNUSED_PARAM, int timeout)
{
HANDLE cin = GetStdHandle(STD_INPUT_HANDLE);
INPUT_RECORD record;
DWORD nevent_out, mode;
int ret = -1;
DWORD alt_pressed = FALSE;
DWORD state;
if (fd != 0)
bb_error_msg_and_die("read_key only works on stdin");
if (cin == INVALID_HANDLE_VALUE)
return -1;
GetConsoleMode(cin, &mode);
SetConsoleMode(cin, 0);
while (1) {
errno = 0;
if (timeout > 0) {
if (WaitForSingleObject(cin, timeout) != WAIT_OBJECT_0)
goto done;
}
if (!readConsoleInput_utf8(cin, &record, 1, &nevent_out))
goto done;
if (record.EventType != KEY_EVENT)
continue;
state = record.Event.KeyEvent.dwControlKeyState;
if (!record.Event.KeyEvent.bKeyDown) {
/* ignore all key up events except Alt */
if (!(alt_pressed && (state & LEFT_ALT_PRESSED) == 0 &&
record.Event.KeyEvent.wVirtualKeyCode == VK_MENU))
continue;
}
alt_pressed = state & LEFT_ALT_PRESSED;
if (!record.Event.KeyEvent.uChar.AsciiChar) {
if (alt_pressed && !(state & ENHANCED_KEY)) {
/* keys on numeric pad used to enter character codes */
switch (record.Event.KeyEvent.wVirtualKeyCode) {
case VK_NUMPAD0: case VK_INSERT:
case VK_NUMPAD1: case VK_END:
case VK_NUMPAD2: case VK_DOWN:
case VK_NUMPAD3: case VK_NEXT:
case VK_NUMPAD4: case VK_LEFT:
case VK_NUMPAD5: case VK_CLEAR:
case VK_NUMPAD6: case VK_RIGHT:
case VK_NUMPAD7: case VK_HOME:
case VK_NUMPAD8: case VK_UP:
case VK_NUMPAD9: case VK_PRIOR:
continue;
}
}
switch (record.Event.KeyEvent.wVirtualKeyCode) {
case VK_DELETE: ret = KEYCODE_DELETE; break;
case VK_INSERT: ret = KEYCODE_INSERT; break;
case VK_UP: ret = KEYCODE_UP; break;
case VK_DOWN: ret = KEYCODE_DOWN; break;
case VK_RIGHT: ret = KEYCODE_RIGHT; break;
case VK_LEFT: ret = KEYCODE_LEFT; break;
case VK_HOME: ret = KEYCODE_HOME; break;
case VK_END: ret = KEYCODE_END; break;
case VK_PRIOR: ret = KEYCODE_PAGEUP; break;
case VK_NEXT: ret = KEYCODE_PAGEDOWN; break;
default:
alt_pressed = FALSE;
continue;
}
if (state & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED))
ret &= ~0x20;
if (state & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED))
ret &= ~0x40;
if (state & SHIFT_PRESSED)
ret &= ~0x80;
goto done;
}
if ( (record.Event.KeyEvent.uChar.AsciiChar & 0x80) == 0x80 ) {
char *s = &record.Event.KeyEvent.uChar.AsciiChar;
conToCharBuffA(s, 1);
}
ret = record.Event.KeyEvent.uChar.AsciiChar;
if (state & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED)) {
switch (ret) {
case '\b': ret = KEYCODE_ALT_BACKSPACE; goto done;
case 'b': ret = KEYCODE_ALT_LEFT; goto done;
case 'd': ret = KEYCODE_ALT_D; goto done;
case 'f': ret = KEYCODE_ALT_RIGHT; goto done;
}
}
break;
}
done:
SetConsoleMode(cin, mode);
return ret;
}
|