summaryrefslogtreecommitdiff
path: root/win32/termios.c
blob: 25f2ea48cae012a3d0c176bac7a768f0fa0c07ed (plain)
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
#include "libbb.h"

int64_t FAST_FUNC 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;
#if ENABLE_FEATURE_EURO
	wchar_t uchar;
	char achar;
#else
	char *s;
#endif
	int 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) {
		if (timeout > 0) {
			if (WaitForSingleObject(cin, timeout) != WAIT_OBJECT_0)
				goto done;
		}
#if ENABLE_FEATURE_EURO
		if (!ReadConsoleInputW(cin, &record, 1, &nevent_out))
#else
		if (!ReadConsoleInput(cin, &record, 1, &nevent_out))
#endif
			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))
				alt_pressed = FALSE;
			else
				continue;
		}
		else {
			alt_pressed = ((state & LEFT_ALT_PRESSED) != 0);
		}

#if ENABLE_FEATURE_EURO
		if (!record.Event.KeyEvent.uChar.UnicodeChar) {
#else
		if (!record.Event.KeyEvent.uChar.AsciiChar) {
#endif
			if (alt_pressed) {
				switch (record.Event.KeyEvent.wVirtualKeyCode) {
				case VK_MENU:
				case VK_INSERT:
				case VK_END:
				case VK_DOWN:
				case VK_NEXT:
				case VK_LEFT:
				case VK_CLEAR:
				case VK_RIGHT:
				case VK_HOME:
				case VK_UP:
				case VK_PRIOR:
				case VK_KANA:
					continue;
				}
			}

			switch (record.Event.KeyEvent.wVirtualKeyCode) {
			case VK_DELETE: ret = KEYCODE_DELETE; goto done;
			case VK_INSERT: ret = KEYCODE_INSERT; goto done;
			case VK_UP: ret = KEYCODE_UP; goto done;
			case VK_DOWN: ret = KEYCODE_DOWN; goto done;
			case VK_RIGHT:
				if (state & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED)) {
					ret = KEYCODE_CTRL_RIGHT;
					goto done;
				}
				ret = KEYCODE_RIGHT;
				goto done;
			case VK_LEFT:
				if (state & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED)) {
					ret = KEYCODE_CTRL_LEFT;
					goto done;
				}
				ret = KEYCODE_LEFT;
				goto done;
			case VK_HOME: ret = KEYCODE_HOME; goto done;
			case VK_END: ret = KEYCODE_END; goto done;
			case VK_PRIOR: ret = KEYCODE_PAGEUP; goto done;
			case VK_NEXT: ret = KEYCODE_PAGEDOWN; goto done;
			}
			continue;
		}
#if ENABLE_FEATURE_EURO
		uchar = record.Event.KeyEvent.uChar.UnicodeChar;
		achar = uchar & 0x7f;
		if (achar != uchar)
			WideCharToMultiByte(CP_ACP, 0, &uchar, 1, &achar, 1, NULL, NULL);
		ret = achar;
#else
		if ( (record.Event.KeyEvent.uChar.AsciiChar & 0x80) == 0x80 ) {
			s = &record.Event.KeyEvent.uChar.AsciiChar;
			OemToCharBuff(s, s, 1);
		}
		ret = record.Event.KeyEvent.uChar.AsciiChar;
#endif
		break;
	}
 done:
	SetConsoleMode(cin, mode);
	return ret;
}