I am creating a program that controls keystrokes for managing iTunes around the world. It also has several WinForms (for displaying track information and editing options).
A low-level keyboard works fine for a while. If I just started the program, the keyboard hook will be installed on the keyboard and iTunes will open. Then I open Notepad and can pick up tons of things very quickly, and each hit is captured, with a maximum of 30 ms spent on the hook function (and for the most part <10 ms). The hook function simply adds events to the queue that is being processed by another thread. It runs on its own high priority chain, using its own Application.Run ().
However, if I start doing something in iTunes (for example, a few play / pause clicks that generate events in my program) or inside the program (for example, opening the options window), the hook function will cease to be called! This can happen even if the keyboard has never been used (for example, launch, press the play button several times and pause in iTunes, then press the key).
The reason that the call is not called is due to not too much time spent on the hook function.
When I call UnhookWindowsHookEx, it always returns true, regardless of whether the hook function was still called.
So what could be the reason?
One idea (although I have no evidence or solutions) is that the managed thread is no longer the correct native thread. I use numerous (managed) threads in my program, and I read that one native thread can start many managed threads and that a managed thread can change which native thread starts it. Is it possible that the hook is still generating messages, but sending them to the wrong chain? If so, how can I get around this?
Edit: hook and callbacks
A slightly stripped down version of my KeyMonitor. For clarity, it is removed. I removed some utilities (for example, most Key enumeration values ββand many Keys class functions, such as ToString () and FromString ()), and some processing errors.
Most important things are in the KeyMonitor class. KeyMonitor.Start () starts the thread for messages, KeyMonitor.HookThread () is the thread and creates a hook along with Application.Run () for the message loop, KeyMonitor.KeyboardHookProc () is the callback function and KeyMonitor. HookEventDispatchThread () is what dispatches events recorded by the callback.
using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading; using System.Windows.Forms; namespace KeyTest { enum Key : int { Shift = 0x10, Ctrl, Alt, Left_Win = 0x5B, Right_Win, Left_Shift = 0xA0, Right_Shift, Left_Ctrl, Right_Ctrl, Left_Alt, Right_Alt, } class Keys { [DllImport("user32.dll")] private static extern int GetKeyboardState(byte[] pbKeyState); public const int Count = 256; // vkCode are from 1 to 254, but GetKeyboardState uses 0-255 private readonly bool[] keys = new bool[Count]; public Keys() { } private void DoModifier(Key x, Key l, Key r) { keys[(int)x] = keys[(int)l] || keys[(int)r]; } private void DoModifiers() { DoModifier(Key.Shift, Key.Left_Shift, Key.Right_Shift); DoModifier(Key.Ctrl, Key.Left_Ctrl, Key.Right_Ctrl); DoModifier(Key.Alt, Key.Left_Alt, Key.Right_Alt); } private void DoModifier(Key x, Key l, Key r, Key k) { if (k == l || k == r) keys[(int)x] = keys[(int)l] || keys[(int)r]; } private void DoModifiers(Key k) { DoModifier(Key.Shift, Key.Left_Shift, Key.Right_Shift, k); DoModifier(Key.Ctrl, Key.Left_Ctrl, Key.Right_Ctrl, k); DoModifier(Key.Alt, Key.Left_Alt, Key.Right_Alt, k); } public bool this[int i] { get { return this.keys[i]; } set { this.keys[i] = value; DoModifiers((Key)i); } } public bool this[Key k] { get { return this.keys[(int)k]; } set { this.keys[(int)k] = value; DoModifiers(k); } } public void LoadCurrentState() { byte[] keyState = new byte[Count]; if (GetKeyboardState(keyState) != 0) for (int i = 0; i < Count; ++i) keys[i] = (keyState[i] & 0x80) != 0; DoModifiers(); } } static class KeyMonitor {