From d615514799f8448b6858f96293f75f26b66bd82c Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sat, 17 Jul 2021 14:03:52 +1000 Subject: [PATCH] [host] windows: do not callback from the mouse hook context The windows hook WH_MOUSE_LL is called in such a way that any delay in processing causes a system wide stall. This change spawns an extra thread which waits on an event set by the hook which is then used to call the callback with an artifical limit of 1000Hz. --- host/platform/Windows/src/mousehook.c | 56 ++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/host/platform/Windows/src/mousehook.c b/host/platform/Windows/src/mousehook.c index cc12f6e7..7aadd8ef 100644 --- a/host/platform/Windows/src/mousehook.c +++ b/host/platform/Windows/src/mousehook.c @@ -31,8 +31,8 @@ struct mouseHook HHOOK hook; MouseHookFn callback; int x, y; - HANDLE event; - HANDLE thread; + HANDLE event , updateEvent; + HANDLE thread, updateThread; }; static struct mouseHook mouseHook = { 0 }; @@ -85,6 +85,31 @@ static VOID WINAPI winEventProc(HWINEVENTHOOK hWinEventHook, DWORD event, } } +static DWORD WINAPI updateThreadProc(LPVOID lParam) +{ + HANDLE events[2] = { + mouseHook.event, + mouseHook.updateEvent + }; + + while(true) + { + switch(WaitForMultipleObjects(2, events, FALSE, INFINITE)) + { + case WAIT_OBJECT_0: + DEBUG_INFO("Mouse hook update thread received quit request"); + return 0; + + case WAIT_OBJECT_0 + 1: + mouseHook.callback(mouseHook.x, mouseHook.y); + + // limit this to 1000Hz, who has a mouse that updates faster anyway? + Sleep(1); + break; + } + } +} + static DWORD WINAPI threadProc(LPVOID lParam) { if (mouseHook.installed) { @@ -143,11 +168,28 @@ void mouseHook_install(MouseHookFn callback) mouseHook.event = CreateEventA(NULL, FALSE, FALSE, NULL); if (!mouseHook.event) { - DEBUG_WINERROR("Failed to create mouse hook uninstall event", GetLastError()); + DEBUG_WINERROR("Failed to create mouse hook uninstall event", + GetLastError()); return; } } - mouseHook.thread = CreateThread(NULL, 0, threadProc, callback, 0, NULL); + + if (!mouseHook.updateEvent) + { + mouseHook.updateEvent = CreateEventA(NULL, FALSE, FALSE, NULL); + if (!mouseHook.event) + { + DEBUG_WINERROR("Failed to create mouse hook update event", + GetLastError()); + return; + } + } + + mouseHook.thread = + CreateThread(NULL, 0, threadProc, callback, 0, NULL); + + mouseHook.updateThread = + CreateThread(NULL, 0, updateThreadProc, 0, 0, NULL); } void mouseHook_remove(void) @@ -156,8 +198,10 @@ void mouseHook_remove(void) return; SetEvent(mouseHook.event); - WaitForSingleObject(mouseHook.thread, INFINITE); + WaitForSingleObject(mouseHook.thread , INFINITE); + WaitForSingleObject(mouseHook.updateThread, INFINITE); CloseHandle(mouseHook.thread); + CloseHandle(mouseHook.updateThread); } static LRESULT WINAPI mouseHook_hook(int nCode, WPARAM wParam, LPARAM lParam) @@ -169,7 +213,7 @@ static LRESULT WINAPI mouseHook_hook(int nCode, WPARAM wParam, LPARAM lParam) { mouseHook.x = msg->pt.x; mouseHook.y = msg->pt.y; - mouseHook.callback(msg->pt.x, msg->pt.y); + SetEvent(mouseHook.updateEvent); } } return CallNextHookEx(mouseHook.hook, nCode, wParam, lParam);