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