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 | } | ||
