diff options
Diffstat (limited to '')
-rw-r--r-- | win32/termios.c | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/win32/termios.c b/win32/termios.c new file mode 100644 index 000000000..b94f68f59 --- /dev/null +++ b/win32/termios.c | |||
@@ -0,0 +1,130 @@ | |||
1 | #include "libbb.h" | ||
2 | |||
3 | int tcsetattr(int fd, int mode UNUSED_PARAM, const struct termios *t) | ||
4 | { | ||
5 | HANDLE h = (HANDLE)_get_osfhandle(fd); | ||
6 | if (!SetConsoleMode(h, t->w_mode)) { | ||
7 | errno = err_win_to_posix(); | ||
8 | return -1; | ||
9 | } | ||
10 | |||
11 | return 0; | ||
12 | } | ||
13 | |||
14 | int tcgetattr(int fd, struct termios *t) | ||
15 | { | ||
16 | HANDLE h = (HANDLE)_get_osfhandle(fd); | ||
17 | if (!GetConsoleMode(h, &t->w_mode)) { | ||
18 | errno = err_win_to_posix(); | ||
19 | return -1; | ||
20 | } | ||
21 | |||
22 | t->c_cc[VINTR] = 3; // ctrl-c | ||
23 | t->c_cc[VEOF] = 4; // ctrl-d | ||
24 | |||
25 | if (t->w_mode & ENABLE_ECHO_INPUT) | ||
26 | t->c_lflag |= ECHO; | ||
27 | else | ||
28 | t->c_lflag &= ~ECHO; | ||
29 | |||
30 | return 0; | ||
31 | } | ||
32 | |||
33 | int64_t FAST_FUNC windows_read_key(int fd, char *buf UNUSED_PARAM, int timeout) | ||
34 | { | ||
35 | HANDLE cin = GetStdHandle(STD_INPUT_HANDLE); | ||
36 | INPUT_RECORD record; | ||
37 | DWORD nevent_out, mode; | ||
38 | int ret = -1; | ||
39 | DWORD alt_pressed = FALSE; | ||
40 | DWORD state; | ||
41 | |||
42 | if (fd != 0) | ||
43 | bb_error_msg_and_die("read_key only works on stdin"); | ||
44 | if (cin == INVALID_HANDLE_VALUE) | ||
45 | return -1; | ||
46 | GetConsoleMode(cin, &mode); | ||
47 | SetConsoleMode(cin, 0); | ||
48 | |||
49 | while (1) { | ||
50 | errno = 0; | ||
51 | if (timeout > 0) { | ||
52 | if (WaitForSingleObject(cin, timeout) != WAIT_OBJECT_0) | ||
53 | goto done; | ||
54 | } | ||
55 | if (!readConsoleInput_utf8(cin, &record, 1, &nevent_out)) | ||
56 | goto done; | ||
57 | |||
58 | if (record.EventType != KEY_EVENT) | ||
59 | continue; | ||
60 | |||
61 | state = record.Event.KeyEvent.dwControlKeyState; | ||
62 | if (!record.Event.KeyEvent.bKeyDown) { | ||
63 | /* ignore all key up events except Alt */ | ||
64 | if (!(alt_pressed && (state & LEFT_ALT_PRESSED) == 0 && | ||
65 | record.Event.KeyEvent.wVirtualKeyCode == VK_MENU)) | ||
66 | continue; | ||
67 | } | ||
68 | alt_pressed = state & LEFT_ALT_PRESSED; | ||
69 | |||
70 | if (!record.Event.KeyEvent.uChar.AsciiChar) { | ||
71 | if (alt_pressed && !(state & ENHANCED_KEY)) { | ||
72 | /* keys on numeric pad used to enter character codes */ | ||
73 | switch (record.Event.KeyEvent.wVirtualKeyCode) { | ||
74 | case VK_NUMPAD0: case VK_INSERT: | ||
75 | case VK_NUMPAD1: case VK_END: | ||
76 | case VK_NUMPAD2: case VK_DOWN: | ||
77 | case VK_NUMPAD3: case VK_NEXT: | ||
78 | case VK_NUMPAD4: case VK_LEFT: | ||
79 | case VK_NUMPAD5: case VK_CLEAR: | ||
80 | case VK_NUMPAD6: case VK_RIGHT: | ||
81 | case VK_NUMPAD7: case VK_HOME: | ||
82 | case VK_NUMPAD8: case VK_UP: | ||
83 | case VK_NUMPAD9: case VK_PRIOR: | ||
84 | continue; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | switch (record.Event.KeyEvent.wVirtualKeyCode) { | ||
89 | case VK_DELETE: ret = KEYCODE_DELETE; break; | ||
90 | case VK_INSERT: ret = KEYCODE_INSERT; break; | ||
91 | case VK_UP: ret = KEYCODE_UP; break; | ||
92 | case VK_DOWN: ret = KEYCODE_DOWN; break; | ||
93 | case VK_RIGHT: ret = KEYCODE_RIGHT; break; | ||
94 | case VK_LEFT: ret = KEYCODE_LEFT; break; | ||
95 | case VK_HOME: ret = KEYCODE_HOME; break; | ||
96 | case VK_END: ret = KEYCODE_END; break; | ||
97 | case VK_PRIOR: ret = KEYCODE_PAGEUP; break; | ||
98 | case VK_NEXT: ret = KEYCODE_PAGEDOWN; break; | ||
99 | default: | ||
100 | alt_pressed = FALSE; | ||
101 | continue; | ||
102 | } | ||
103 | |||
104 | if (state & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED)) | ||
105 | ret &= ~0x20; | ||
106 | if (state & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED)) | ||
107 | ret &= ~0x40; | ||
108 | if (state & SHIFT_PRESSED) | ||
109 | ret &= ~0x80; | ||
110 | goto done; | ||
111 | } | ||
112 | if ( (record.Event.KeyEvent.uChar.AsciiChar & 0x80) == 0x80 ) { | ||
113 | char *s = &record.Event.KeyEvent.uChar.AsciiChar; | ||
114 | conToCharBuffA(s, 1); | ||
115 | } | ||
116 | ret = record.Event.KeyEvent.uChar.AsciiChar; | ||
117 | if (state & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED)) { | ||
118 | switch (ret) { | ||
119 | case '\b': ret = KEYCODE_ALT_BACKSPACE; goto done; | ||
120 | case 'b': ret = KEYCODE_ALT_LEFT; goto done; | ||
121 | case 'd': ret = KEYCODE_ALT_D; goto done; | ||
122 | case 'f': ret = KEYCODE_ALT_RIGHT; goto done; | ||
123 | } | ||
124 | } | ||
125 | break; | ||
126 | } | ||
127 | done: | ||
128 | SetConsoleMode(cin, mode); | ||
129 | return ret; | ||
130 | } | ||