From 6a8d1cdd49ca6c9d4656b9450253c71438ef5c49 Mon Sep 17 00:00:00 2001 From: James Ross-Gowan Date: Thu, 13 Oct 2016 22:40:00 +1100 Subject: [PATCH] terminal-win: clean up console input The original version of this code in getch2-win.c fetched 128 console events at once. This was probably to maximize the chance of getting a key event if there were other events in the buffer, because it returned the value of the first key event it found and ignored all others. Since that code was written, it has been modified to receive console input in an event-based way using an input thread, so it is probably not necessary to fetch so many events at once any more. Also, I'm not sure what it would have done if there were more than 128 events in the console input buffer. It's possible that fetching multiple events at a time also had performance advantages, but I can't find any other programs that do this. Even libuv just fetches one console event at a time. Change read_input() to fetch only one event at a time and to consume all available events before returning to WaitForMultipleObjects. Also remove some outdated comments and pass the console handle through to the input thread instead of calling GetStdHandle multiple times (I think this is theoretically more correct because it is possible for the handles returned by GetStdHandle to be changed by other threads.) --- osdep/terminal-win.c | 86 ++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 51 deletions(-) diff --git a/osdep/terminal-win.c b/osdep/terminal-win.c index c04a13a639..0064550b42 100644 --- a/osdep/terminal-win.c +++ b/osdep/terminal-win.c @@ -18,10 +18,6 @@ * with mpv. If not, see . */ -// See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp -// for additional virtual keycodes - - #include "config.h" #include #include @@ -70,66 +66,54 @@ void terminal_get_size(int *w, int *h) } } -static void read_input(void) +static bool has_input_events(HANDLE h) { - DWORD retval; - HANDLE in = GetStdHandle(STD_INPUT_HANDLE); + DWORD num_events; + if (!GetNumberOfConsoleInputEvents(h, &num_events)) + return false; + return !!num_events; +} - /*check if there are input events*/ - if (!GetNumberOfConsoleInputEvents(in, &retval)) - return; - if (!retval) - return; - - /*read all events*/ - INPUT_RECORD eventbuffer[128]; - if (!ReadConsoleInput(in, eventbuffer, MP_ARRAY_SIZE(eventbuffer), &retval)) - return; - - /*filter out keyevents*/ - for (int i = 0; i < retval; i++) { - switch (eventbuffer[i].EventType) { - case KEY_EVENT: { - KEY_EVENT_RECORD *record = &eventbuffer[i].Event.KeyEvent; - - /*only a pressed key is interesting for us*/ - if (record->bKeyDown) { - UINT vkey = record->wVirtualKeyCode; - bool ext = record->dwControlKeyState & ENHANCED_KEY; - - int mpkey = mp_w32_vkey_to_mpkey(vkey, ext); - if (mpkey) { - mp_input_put_key(input_ctx, mpkey); - } else { - /*only characters should be remaining*/ - int c = record->uChar.UnicodeChar; - if (c > 0) - mp_input_put_key(input_ctx, c); - } - } - break; - } - case MOUSE_EVENT: - case WINDOW_BUFFER_SIZE_EVENT: - case FOCUS_EVENT: - case MENU_EVENT: - default: +static void read_input(HANDLE in) +{ + // Process any input events in the buffer + while (has_input_events(in)) { + INPUT_RECORD event; + if (!ReadConsoleInputW(in, &event, 1, &(DWORD){0})) break; + + // Only key-down events are interesting to us + if (event.EventType != KEY_EVENT) + continue; + KEY_EVENT_RECORD *record = &event.Event.KeyEvent; + if (!record->bKeyDown) + continue; + + UINT vkey = record->wVirtualKeyCode; + bool ext = record->dwControlKeyState & ENHANCED_KEY; + + int mpkey = mp_w32_vkey_to_mpkey(vkey, ext); + if (mpkey) { + mp_input_put_key(input_ctx, mpkey); + } else { + // Only characters should be remaining + int c = record->uChar.UnicodeChar; + if (c >= 0x20) + mp_input_put_key(input_ctx, c); } } - return; } static void *input_thread_fn(void *ptr) { mpthread_set_name("terminal"); - HANDLE in = GetStdHandle(STD_INPUT_HANDLE); + HANDLE in = ptr; HANDLE stuff[2] = {in, death}; while (1) { DWORD r = WaitForMultipleObjects(2, stuff, FALSE, INFINITE); if (r != WAIT_OBJECT_0) break; - read_input(); + read_input(in); } return NULL; } @@ -142,10 +126,10 @@ void terminal_setup_getch(struct input_ctx *ictx) HANDLE in = GetStdHandle(STD_INPUT_HANDLE); if (GetNumberOfConsoleInputEvents(in, &(DWORD){0})) { input_ctx = ictx; - death = CreateEvent(NULL, TRUE, FALSE, NULL); + death = CreateEventW(NULL, TRUE, FALSE, NULL); if (!death) return; - if (pthread_create(&input_thread, NULL, input_thread_fn, NULL)) { + if (pthread_create(&input_thread, NULL, input_thread_fn, in)) { CloseHandle(death); return; }