[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.
This commit is contained in:
Geoffrey McRae 2021-07-17 14:03:52 +10:00
parent ed717351cf
commit d615514799

View File

@ -31,8 +31,8 @@ struct mouseHook
HHOOK hook; HHOOK hook;
MouseHookFn callback; MouseHookFn callback;
int x, y; int x, y;
HANDLE event; HANDLE event , updateEvent;
HANDLE thread; HANDLE thread, updateThread;
}; };
static struct mouseHook mouseHook = { 0 }; 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) { static DWORD WINAPI threadProc(LPVOID lParam) {
if (mouseHook.installed) if (mouseHook.installed)
{ {
@ -143,11 +168,28 @@ void mouseHook_install(MouseHookFn callback)
mouseHook.event = CreateEventA(NULL, FALSE, FALSE, NULL); mouseHook.event = CreateEventA(NULL, FALSE, FALSE, NULL);
if (!mouseHook.event) if (!mouseHook.event)
{ {
DEBUG_WINERROR("Failed to create mouse hook uninstall event", GetLastError()); DEBUG_WINERROR("Failed to create mouse hook uninstall event",
GetLastError());
return; 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) void mouseHook_remove(void)
@ -156,8 +198,10 @@ void mouseHook_remove(void)
return; return;
SetEvent(mouseHook.event); SetEvent(mouseHook.event);
WaitForSingleObject(mouseHook.thread, INFINITE); WaitForSingleObject(mouseHook.thread , INFINITE);
WaitForSingleObject(mouseHook.updateThread, INFINITE);
CloseHandle(mouseHook.thread); CloseHandle(mouseHook.thread);
CloseHandle(mouseHook.updateThread);
} }
static LRESULT WINAPI mouseHook_hook(int nCode, WPARAM wParam, LPARAM lParam) 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.x = msg->pt.x;
mouseHook.y = msg->pt.y; mouseHook.y = msg->pt.y;
mouseHook.callback(msg->pt.x, msg->pt.y); SetEvent(mouseHook.updateEvent);
} }
} }
return CallNextHookEx(mouseHook.hook, nCode, wParam, lParam); return CallNextHookEx(mouseHook.hook, nCode, wParam, lParam);