xref: /dpdk/lib/cmdline/cmdline_os_windows.c (revision f44f2edd198a552b3ede6a1a10e4cf552b3e8b4b)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright (c) 2020 Dmitry Kozlyuk
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson 
599a2dd95SBruce Richardson #include <io.h>
699a2dd95SBruce Richardson 
799a2dd95SBruce Richardson #include "cmdline_private.h"
899a2dd95SBruce Richardson 
999a2dd95SBruce Richardson /* Missing from some MinGW-w64 distributions. */
1099a2dd95SBruce Richardson #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
1199a2dd95SBruce Richardson #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
1299a2dd95SBruce Richardson #endif
1399a2dd95SBruce Richardson 
1499a2dd95SBruce Richardson #ifndef ENABLE_VIRTUAL_TERMINAL_INPUT
1599a2dd95SBruce Richardson #define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200
1699a2dd95SBruce Richardson #endif
1799a2dd95SBruce Richardson 
1899a2dd95SBruce Richardson void
terminal_adjust(struct cmdline * cl)1999a2dd95SBruce Richardson terminal_adjust(struct cmdline *cl)
2099a2dd95SBruce Richardson {
2199a2dd95SBruce Richardson 	HANDLE handle;
2299a2dd95SBruce Richardson 	DWORD mode;
2399a2dd95SBruce Richardson 
2499a2dd95SBruce Richardson 	ZeroMemory(&cl->oldterm, sizeof(cl->oldterm));
2599a2dd95SBruce Richardson 
2699a2dd95SBruce Richardson 	/* Detect console input, set it up and make it emulate VT100. */
2799a2dd95SBruce Richardson 	handle = GetStdHandle(STD_INPUT_HANDLE);
2899a2dd95SBruce Richardson 	if (GetConsoleMode(handle, &mode)) {
2999a2dd95SBruce Richardson 		cl->oldterm.is_console_input = 1;
3099a2dd95SBruce Richardson 		cl->oldterm.input_mode = mode;
3199a2dd95SBruce Richardson 
3299a2dd95SBruce Richardson 		mode &= ~(
3399a2dd95SBruce Richardson 			ENABLE_LINE_INPUT |      /* no line buffering */
3499a2dd95SBruce Richardson 			ENABLE_ECHO_INPUT |      /* no echo */
3599a2dd95SBruce Richardson 			ENABLE_PROCESSED_INPUT | /* pass Ctrl+C to program */
3699a2dd95SBruce Richardson 			ENABLE_MOUSE_INPUT |     /* no mouse events */
3799a2dd95SBruce Richardson 			ENABLE_WINDOW_INPUT);    /* no window resize events */
3899a2dd95SBruce Richardson 		mode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
3999a2dd95SBruce Richardson 		SetConsoleMode(handle, mode);
4099a2dd95SBruce Richardson 	}
4199a2dd95SBruce Richardson 
4299a2dd95SBruce Richardson 	/* Detect console output and make it emulate VT100. */
4399a2dd95SBruce Richardson 	handle = GetStdHandle(STD_OUTPUT_HANDLE);
4499a2dd95SBruce Richardson 	if (GetConsoleMode(handle, &mode)) {
4599a2dd95SBruce Richardson 		cl->oldterm.is_console_output = 1;
4699a2dd95SBruce Richardson 		cl->oldterm.output_mode = mode;
4799a2dd95SBruce Richardson 
4899a2dd95SBruce Richardson 		mode &= ~ENABLE_WRAP_AT_EOL_OUTPUT;
4999a2dd95SBruce Richardson 		mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
5099a2dd95SBruce Richardson 		SetConsoleMode(handle, mode);
5199a2dd95SBruce Richardson 	}
5299a2dd95SBruce Richardson }
5399a2dd95SBruce Richardson 
5499a2dd95SBruce Richardson void
terminal_restore(const struct cmdline * cl)5599a2dd95SBruce Richardson terminal_restore(const struct cmdline *cl)
5699a2dd95SBruce Richardson {
5799a2dd95SBruce Richardson 	if (cl->oldterm.is_console_input) {
5899a2dd95SBruce Richardson 		HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
5999a2dd95SBruce Richardson 		SetConsoleMode(handle, cl->oldterm.input_mode);
6099a2dd95SBruce Richardson 	}
6199a2dd95SBruce Richardson 
6299a2dd95SBruce Richardson 	if (cl->oldterm.is_console_output) {
6399a2dd95SBruce Richardson 		HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
6499a2dd95SBruce Richardson 		SetConsoleMode(handle, cl->oldterm.output_mode);
6599a2dd95SBruce Richardson 	}
6699a2dd95SBruce Richardson }
6799a2dd95SBruce Richardson 
6899a2dd95SBruce Richardson static int
cmdline_is_key_down(const INPUT_RECORD * record)6999a2dd95SBruce Richardson cmdline_is_key_down(const INPUT_RECORD *record)
7099a2dd95SBruce Richardson {
7199a2dd95SBruce Richardson 	return (record->EventType == KEY_EVENT) &&
7299a2dd95SBruce Richardson 		record->Event.KeyEvent.bKeyDown;
7399a2dd95SBruce Richardson }
7499a2dd95SBruce Richardson 
7599a2dd95SBruce Richardson ssize_t
cmdline_read_char(struct cmdline * cl,char * c)7699a2dd95SBruce Richardson cmdline_read_char(struct cmdline *cl, char *c)
7799a2dd95SBruce Richardson {
7899a2dd95SBruce Richardson 	HANDLE handle;
7999a2dd95SBruce Richardson 	INPUT_RECORD record;
8099a2dd95SBruce Richardson 	KEY_EVENT_RECORD *key;
8199a2dd95SBruce Richardson 	DWORD events;
8299a2dd95SBruce Richardson 
8399a2dd95SBruce Richardson 	if (!cl->oldterm.is_console_input)
8499a2dd95SBruce Richardson 		return _read(cl->s_in, c, 1);
8599a2dd95SBruce Richardson 
8699a2dd95SBruce Richardson 	/* Return repeated strokes from previous event. */
8799a2dd95SBruce Richardson 	if (cl->repeat_count > 0) {
8899a2dd95SBruce Richardson 		*c = cl->repeated_char;
8999a2dd95SBruce Richardson 		cl->repeat_count--;
9099a2dd95SBruce Richardson 		return 1;
9199a2dd95SBruce Richardson 	}
9299a2dd95SBruce Richardson 
9399a2dd95SBruce Richardson 	handle = (HANDLE)_get_osfhandle(cl->s_in);
9499a2dd95SBruce Richardson 	key = &record.Event.KeyEvent;
9599a2dd95SBruce Richardson 	do {
9699a2dd95SBruce Richardson 		if (!ReadConsoleInput(handle, &record, 1, &events)) {
9799a2dd95SBruce Richardson 			if (GetLastError() == ERROR_HANDLE_EOF) {
9899a2dd95SBruce Richardson 				*c = EOF;
9999a2dd95SBruce Richardson 				return 0;
10099a2dd95SBruce Richardson 			}
10199a2dd95SBruce Richardson 			return -1;
10299a2dd95SBruce Richardson 		}
10399a2dd95SBruce Richardson 	} while (!cmdline_is_key_down(&record));
10499a2dd95SBruce Richardson 
10599a2dd95SBruce Richardson 	*c = key->uChar.AsciiChar;
10699a2dd95SBruce Richardson 
10799a2dd95SBruce Richardson 	/* Save repeated strokes from a single event. */
10899a2dd95SBruce Richardson 	if (key->wRepeatCount > 1) {
10999a2dd95SBruce Richardson 		cl->repeated_char = *c;
11099a2dd95SBruce Richardson 		cl->repeat_count = key->wRepeatCount - 1;
11199a2dd95SBruce Richardson 	}
11299a2dd95SBruce Richardson 
11399a2dd95SBruce Richardson 	return 1;
11499a2dd95SBruce Richardson }
11599a2dd95SBruce Richardson 
11699a2dd95SBruce Richardson int
cmdline_vdprintf(int fd,const char * format,va_list op)11799a2dd95SBruce Richardson cmdline_vdprintf(int fd, const char *format, va_list op)
11899a2dd95SBruce Richardson {
11999a2dd95SBruce Richardson 	int copy, ret;
12099a2dd95SBruce Richardson 	FILE *file;
12199a2dd95SBruce Richardson 
12299a2dd95SBruce Richardson 	copy = _dup(fd);
12399a2dd95SBruce Richardson 	if (copy < 0)
12499a2dd95SBruce Richardson 		return -1;
12599a2dd95SBruce Richardson 
12699a2dd95SBruce Richardson 	file = _fdopen(copy, "a");
12799a2dd95SBruce Richardson 	if (file == NULL) {
12899a2dd95SBruce Richardson 		_close(copy);
12999a2dd95SBruce Richardson 		return -1;
13099a2dd95SBruce Richardson 	}
13199a2dd95SBruce Richardson 
13299a2dd95SBruce Richardson 	ret = vfprintf(file, format, op);
13399a2dd95SBruce Richardson 
13499a2dd95SBruce Richardson 	fclose(file); /* also closes copy */
13599a2dd95SBruce Richardson 
13699a2dd95SBruce Richardson 	return ret;
13799a2dd95SBruce Richardson }
138*f1d0993eSStephen Hemminger 
139*f1d0993eSStephen Hemminger void
cmdline_cancel(struct cmdline * cl)140*f1d0993eSStephen Hemminger cmdline_cancel(struct cmdline *cl)
141*f1d0993eSStephen Hemminger {
142*f1d0993eSStephen Hemminger 	if (!cl)
143*f1d0993eSStephen Hemminger 		return;
144*f1d0993eSStephen Hemminger 
145*f1d0993eSStephen Hemminger 	/* force the outstanding read on console to exit */
146*f1d0993eSStephen Hemminger 	if (cl->oldterm.is_console_input) {
147*f1d0993eSStephen Hemminger 		HANDLE handle = (HANDLE)_get_osfhandle(cl->s_in);
148*f1d0993eSStephen Hemminger 
149*f1d0993eSStephen Hemminger 		CancelIoEx(handle, NULL);
150*f1d0993eSStephen Hemminger 	}
151*f1d0993eSStephen Hemminger }
152