Skip to content

Commit

Permalink
terminal-win: clean up console input
Browse files Browse the repository at this point in the history
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.)
  • Loading branch information
rossy committed Oct 13, 2016
1 parent b5357e8 commit 6a8d1cd
Showing 1 changed file with 33 additions and 49 deletions.
82 changes: 33 additions & 49 deletions osdep/terminal-win.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@
* with mpv. If not, see <http://www.gnu.org/licenses/>.
*/

// 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 <fcntl.h>
#include <stdio.h>
Expand Down Expand Up @@ -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);

/*check if there are input events*/
if (!GetNumberOfConsoleInputEvents(in, &retval))
return;
if (!retval)
return;
DWORD num_events;
if (!GetNumberOfConsoleInputEvents(h, &num_events))
return false;
return !!num_events;
}

/*read all events*/
INPUT_RECORD eventbuffer[128];
if (!ReadConsoleInput(in, eventbuffer, MP_ARRAY_SIZE(eventbuffer), &retval))
return;
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;

/*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 key-down events are interesting to us
if (event.EventType != KEY_EVENT)
continue;
KEY_EVENT_RECORD *record = &event.Event.KeyEvent;
if (!record->bKeyDown)
continue;

/*only a pressed key is interesting for us*/
if (record->bKeyDown) {
UINT vkey = record->wVirtualKeyCode;
bool ext = record->dwControlKeyState & ENHANCED_KEY;
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:
break;
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;
}
Expand All @@ -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;
}
Expand Down

0 comments on commit 6a8d1cd

Please sign in to comment.