@@ -165,7 +165,7 @@ LRESULT CALLBACK LowLevelKeyboardHook(int nCode, WPARAM wParam, LPARAM lParam)
165165 ETWKeyDown (code, keyDownDetails.c_str (), 0 , 0 );
166166 }
167167
168- return CallNextHookEx (0 , nCode, wParam, lParam);
168+ return CallNextHookEx (nullptr , nCode, wParam, lParam);
169169}
170170
171171_Pre_satisfies_ (nCode == HC_ACTION)
@@ -228,7 +228,7 @@ LRESULT CALLBACK LowLevelMouseHook(int nCode, WPARAM wParam, LPARAM lParam) noex
228228 }
229229 }
230230
231- return CallNextHookEx (0 , nCode, wParam, lParam);
231+ return CallNextHookEx (nullptr , nCode, wParam, lParam);
232232}
233233
234234
@@ -252,30 +252,43 @@ DWORD __stdcall InputThread(LPVOID) noexcept
252252 // processed in a timely manner or else bad things will happen. Doing this on a
253253 // separate thread is a good idea, but even then bad things will happen to your system
254254 // if you halt in a debugger. Even simple things like calling printf() from the hook
255- // can easily cause system deadlocks which render the mouse unable to move!
256- HHOOK keyHook = SetWindowsHookEx (WH_KEYBOARD_LL, LowLevelKeyboardHook, NULL , 0 );
257- HHOOK mouseHook = SetWindowsHookEx (WH_MOUSE_LL, LowLevelMouseHook, NULL , 0 );
258-
259- if (!keyHook && !mouseHook)
260- return 0 ;
261-
262- // Run a message pump -- necessary so that the hooks will be processed
263- BOOL bRet;
264- MSG msg;
265- // Keeping pumping messages until WM_QUIT is received. If this is opened
266- // in a child thread then you can terminate it by using PostThreadMessage
267- // to send WM_QUIT.
268- while ((bRet = GetMessage (&msg, NULL , 0 , 0 )) != 0 )
255+ // can easily cause system deadlocks which cause all input to be processed
256+ // very slowly.
257+ // The default OS hook timeout seems to be 300 ms, which is long enough to
258+ // make input delays noticeable, but short enough to make the system sort of
259+ // usable. You can set a shorter timeout (10 ms in this case) with this
260+ // command:
261+ // reg add "HKCU\Control Panel\Desktop" /v LowLevelHooksTimeout /t REG_DWORD /f /d 10
262+ // Occasional input delays were, in one case, tracked down to an input hook
263+ // (unknown owner) that was briefly timing out. Twitter discussion is here:
264+ // https://twitter.com/BruceDawson0xB/status/1673375468127670273
265+ HHOOK keyHook = SetWindowsHookEx (WH_KEYBOARD_LL, LowLevelKeyboardHook, nullptr , 0 );
266+ HHOOK mouseHook = SetWindowsHookEx (WH_MOUSE_LL, LowLevelMouseHook, nullptr , 0 );
267+
268+ // Run the message pump if either hook is successfully registered (they should
269+ // always both be registered).
270+ if (keyHook || mouseHook)
269271 {
270- if (bRet == -1 )
271- {
272- // handle the error and possibly exit
273- break ;
274- }
275- else
272+ // Run a message pump -- necessary so that the hooks will be processed
273+ BOOL bRet;
274+ MSG msg;
275+ // Keeping pumping messages until WM_QUIT is received. If this is running
276+ // in a child thread then you can terminate it by using PostThreadMessage
277+ // to send WM_QUIT.
278+ while ((bRet = GetMessageW (&msg, nullptr , 0 , 0 )) != 0 )
276279 {
277- TranslateMessage (&msg);
278- DispatchMessage (&msg);
280+ // GetMessageW will normally only return when WM_QUIT is received, so this
281+ // loop normally doesn't ever run.
282+ if (bRet == -1 )
283+ {
284+ // Unexpected error. Quit.
285+ break ;
286+ }
287+ else
288+ {
289+ TranslateMessage (&msg);
290+ DispatchMessage (&msg);
291+ }
279292 }
280293 }
281294
@@ -312,7 +325,7 @@ void SetKeyloggingState(enum KeyLoggerState state) noexcept
312325 // it isn't running.
313326 if (!s_hThread)
314327 {
315- s_hThread = CreateThread (NULL , 0 , InputThread, NULL , 0 , &s_threadID);
328+ s_hThread = CreateThread (nullptr , 0 , InputThread, nullptr , 0 , &s_threadID);
316329 }
317330
318331 switch (state)
0 commit comments