I am facing an issue with a Windows C++ application that involves a 1-second delay when calling mouse_event() inside a LowLevelMouseProc function. The delay persists even when the operating system is booted in safe mode and with different mouse devices.
Here is a simplified version of the code:
#include <windows.h>
#include <iostream>
HHOOK miHook;
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (wParam == WM_LBUTTONUP) {
//this gives ~1000ms delay before click when called, same with SendInput() but no delay with SendMessage()
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
return -1;
}
return CallNextHookEx(miHook, nCode, wParam, lParam);
}
DWORD WINAPI ThreadProc(void*) {
SetWindowsHookEx(WH_MOUSE_LL, LowLevelMouseProc, NULL, 0);
MSG msg;
while (GetMessage(&msg, 0, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(miHook);
return 0;
}
int main() {
CreateThread(NULL, 0, ThreadProc, NULL, 0, 0);
while (true) {
Sleep(150000);
}
return 0;
}
Problem:
mouse_event() function inside the LowLevelMouseProc function introduces an unexpected delay of approximately 1000 milliseconds before mouse is clicked and further code is executed. This delay is observed even with different mouse devices and in OS safe mode, but not in Windows 7.
The problem persists with mouse_event() and SendInput() functions, but not with SendMessage() or PostMessage().
Compiled in Visual Studio 2022 (v17.6.3)
Any insights or suggestions on how to resolve this issue would be greatly appreciated. Thank you!
UPD: Updated version of the LowLevelMouseProc function (nCode check and valid return) gives the same results:
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode < 0) {
return CallNextHookEx(miHook, nCode, wParam, lParam);
}
if (wParam == WM_LBUTTONUP) {
printf("0 msec\n");
INPUT input;
input.type = INPUT_MOUSE;
input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
SendInput(1, &input, sizeof(INPUT));
printf("1001 msec\n");
}
return CallNextHookEx(miHook, nCode, wParam, lParam);
}
I'm not an expert in hooking, but I can see a few possible issues.
mouse_event has been superseded by SendInput.
LowLevelMouseProc isn't checking nCode.
If nCode is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx. [emphasis added]
Injecting a button down event before letting the current button up message be handled seems weird. (What's your goal?) It's not hard to imagine ways this might just plug up the works.
The system has timeouts to detect faulty hooks.
The hook procedure should process a message in less time than the data entry specified in the LowLevelHooksTimeout value in the following registry key:
HKEY_CURRENT_USER\Control Panel\Desktop
The value is in milliseconds. If the hook procedure times out, the system passes the message to the next hook. However, on Windows 7 and later, the hook is silently removed without being called. There is no way for the application to know whether the hook is removed.
And it seems likely the timeout is 1000 ms, at least in some versions of Windows 10.
Windows 10 version 1709 and later The maximum timeout value the system allows is 1000 milliseconds (1 second). The system will default to using a 1000 millisecond timeout if the LowLevelHooksTimeout value is set to a value larger than 1000.
My guess is that either the failure to immediately pass on a hook with a negative nCode or the injection of an input event before processing of a conflicting event is completed is causing the hook to hang. When the timeout is reached, the system intervenes to get things unstuck, creating the appearance of a 1000 ms delay.