From 58a9610acfc264cd93def625157774a8dc0e79ed Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 21 Aug 2014 22:15:32 +0200 Subject: terminal-win: read input from a thread Surprisingly, WaitFor* works on console handles. We can simply run the code for reading the console in a thread, and don't have to worry about crazy win32 crap in the rest of the player's input code anymore. This also fixes the issue that you couldn't unpause the player from the terminal, because the player would stop polling for input. --- osdep/terminal-unix.c | 4 +-- osdep/terminal-win.c | 76 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 51 insertions(+), 29 deletions(-) diff --git a/osdep/terminal-unix.c b/osdep/terminal-unix.c index 3a0117389c..2bac169f36 100644 --- a/osdep/terminal-unix.c +++ b/osdep/terminal-unix.c @@ -29,6 +29,7 @@ #include #include #include +#include #if HAVE_TERMIOS #if HAVE_TERMIOS_H @@ -557,8 +558,7 @@ static void quit_request_sighandler(int signum) static void getch2_enable(void) { - if (getch2_enabled) - return; + assert(!getch2_enabled); // handlers to fix terminal settings setsigaction(SIGCONT, continue_sighandler, 0, true); diff --git a/osdep/terminal-win.c b/osdep/terminal-win.c index af8b3aa47b..22751b31f8 100644 --- a/osdep/terminal-win.c +++ b/osdep/terminal-win.c @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include "common/common.h" #include "input/keycodes.h" #include "input/input.h" @@ -51,6 +53,11 @@ static const unsigned char ansi2win32[8] = { FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED, }; +static bool running; +static HANDLE death; +static pthread_t input_thread; +static struct input_ctx *input_ctx; + void terminal_get_size(int *w, int *h) { CONSOLE_SCREEN_BUFFER_INFO cinfo; @@ -60,23 +67,21 @@ void terminal_get_size(int *w, int *h) } } -static int getch2_status = 0; - -static int getch2_internal(void) +static void read_input(void) { DWORD retval; HANDLE in = GetStdHandle(STD_INPUT_HANDLE); /*check if there are input events*/ if (!GetNumberOfConsoleInputEvents(in, &retval)) - return -1; + return; if (retval <= 0) - return -1; + return; /*read all events*/ INPUT_RECORD eventbuffer[128]; if (!ReadConsoleInput(in, eventbuffer, MP_ARRAY_SIZE(eventbuffer), &retval)) - return -1; + return; /*filter out keyevents*/ for (int i = 0; i < retval; i++) { @@ -90,11 +95,14 @@ static int getch2_internal(void) bool ext = record->dwControlKeyState & ENHANCED_KEY; int mpkey = mp_w32_vkey_to_mpkey(vkey, ext); - if (mpkey) - return mpkey; - - /*only characters should be remaining*/ - return eventbuffer[i].Event.KeyEvent.uChar.UnicodeChar; + if (mpkey) { + mp_input_put_key(input_ctx, mpkey); + } else { + /*only characters should be remaining*/ + int c = eventbuffer[i].Event.KeyEvent.uChar.UnicodeChar; + if (c > 0) + mp_input_put_key(input_ctx, c); + } } break; } @@ -106,29 +114,38 @@ static int getch2_internal(void) break; } } - return -1; -} - -static bool getch2(struct input_ctx *ctx) -{ - int r = getch2_internal(); - if (r >= 0) - mp_input_put_key(ctx, r); - return true; + return; } -static int read_keys(void *ctx, int fd) +static void *input_thread_fn(void *ptr) { - if (getch2(ctx)) - return MP_INPUT_NOTHING; - return MP_INPUT_DEAD; + HANDLE in = GetStdHandle(STD_INPUT_HANDLE); + HANDLE stuff[2] = {in, death}; + while (1) { + DWORD r = WaitForMultipleObjects(2, stuff, FALSE, INFINITE); + if (r != WAIT_OBJECT_0) + break; + read_input(); + } + return NULL; } void terminal_setup_getch(struct input_ctx *ictx) { - mp_input_add_fd(ictx, 0, 1, NULL, read_keys, NULL, ictx); + assert(!running); + HANDLE in = GetStdHandle(STD_INPUT_HANDLE); - getch2_status = !!GetNumberOfConsoleInputEvents(in, &(DWORD){0}); + if (GetNumberOfConsoleInputEvents(in, &(DWORD){0})) { + input_ctx = ictx; + death = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!death) + return; + if (pthread_create(&input_thread, NULL, input_thread_fn, NULL)) { + CloseHandle(death); + return; + } + running = true; + } } void getch2_poll(void) @@ -137,7 +154,12 @@ void getch2_poll(void) void terminal_uninit(void) { - getch2_status = 0; + if (running) { + SetEvent(death); + pthread_join(input_thread, NULL); + input_ctx = NULL; + running = false; + } } bool terminal_in_background(void) -- cgit v1.2.3