Reputation: 14239
I have a little Python script which collects statistics about my keyboard and mouse usage on a Windows machine.
I set it up via windll.user32.SetWindowsHookExA(win32con.WH_MOUSE_LL, mouse_pointer, win32api.GetModuleHandle(None), 0)
. I write this so that you can see which API I'm using. It could just as well have been a c++ programm.
It works perfectly fine, with one exception: When I use Android Studio to compile an app, my Core i7 with 4 cores maxes out at 100% on all cores, the mouse and the OS in general becomes unresponsive, which is a known issue with Android Studio.
Usually when such a very high CPU load occurs for a couple of seconds (4+) the WH_MOUSE_LL hook gets detached by the OS, as if it's saying "Nope, we don't have time for you, we're unregistering you"
I don't blame this on Python, because I also have a sound volume manager called PowerMixer which apparently also registers a mouse hook so that it can track mouse scroll wheel actions on the lower taskbar (explorer.exe Shell_TrayWnd) and this application also looses it's ability to use that mouse hook after compiling.
Also, when I am compiling and constantly scroll the scroll wheel (just for fun) the computer starts to beep, as in a very low level system beep and then the keyboard hooks get unregistered as well.
How can I detect via the Windows API if my hooks got detached / unhooked? I don't require a Python specific answer, just infos on the proper way to use the Win32 API to deal with this.
The remarks section of the SetWindowsHookEx documentation says:
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.
Am I out of luck here?
Update: A couple of weeks later, I just want to inform that Hans Passan's suggestion is working very well. I recommend this. While 10.000 ms seems a bit high, I've set it to this value and have no negative effects. This is the way to go to solve the issue system wide within a couple of minutes.
Upvotes: 1
Views: 1371
Reputation: 596938
How can I detect via the Windows API if my hooks got detached / unhooked?
There is no direct way to do it, and your own question quoted the MSDN documentation that backs it up:
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.
However, an indirect way might be to have your hook keep track of the last time it is called, and then your main app/script can call GetLastInputInfo()
periodically and compare that time to your tracked time. If the difference is a significant margin higher than the hook timeout that is stored in the Registry (see the documentation), it is probably a good bet that your hook may be gone.
The following MSDN blog explains the details of the hook timeout:
Global hooks getting lost on Windows 7
But, most importantly, it states:
My recommendation is that low level hooks should be avoided whenever possible. If you are monitoring keystrokes (and not trying to block them), you can get the keyboard input via Raw Input. This is lighter weight than hooks, won’t affect other apps’ responsiveness, and won’t be turned off if the app isn’t responsive.
Which is the same as Microsoft's own recommendation in the LowLevelMouseProc()
and LowLevelKeyboardProc()
documentations:
If the application must use low level hooks, it should run the hooks on a dedicated thread that passes the work off to a worker thread and then immediately returns. In most cases where the application needs to use low level hooks, it should monitor raw input instead. This is because raw input can asynchronously monitor mouse and keyboard messages that are targeted for other threads more effectively than low level hooks can. For more information on raw input, see Raw Input.
Upvotes: 3