InterceptKeys() { keyStream = Observable.Create <InterceptKeyEventArgs>(observer => { Debug.Write("Subscribed to keys"); IntPtr hookId = IntPtr.Zero; // Need to hold onto this callback, otherwise it will get GC'd as it is an unmanged callback callback = (nCode, wParam, lParam) => { if (nCode >= 0) { var eventArgs = CreateEventArgs(wParam, lParam); observer.OnNext(eventArgs); if (eventArgs.Handled) { return((IntPtr)1); } } // ReSharper disable once AccessToModifiedClosure return(Win32Methods.CallNextHookEx(hookId, nCode, wParam, lParam)); }; hookId = SetHook(callback); return(Disposable.Create(() => { Debug.Write("Unsubscribed from keys"); Win32Methods.UnhookWindowsHookEx(hookId); callback = null; })); }) .Publish().RefCount(); }
IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) { if (nCode >= 0) { bool alt = (Control.ModifierKeys & Keys.Alt) != 0; bool control = (Control.ModifierKeys & Keys.Control) != 0; bool shift = (Control.ModifierKeys & Keys.Shift) != 0; bool keyDown = wParam == (IntPtr)Win32Methods.WM_KEYDOWN; bool keyUp = wParam == (IntPtr)Win32Methods.WM_KEYUP; int vkCode = Marshal.ReadInt32(lParam); var key = (Keys)vkCode; //http://msdn.microsoft.com/en-us/library/windows/desktop/ms646286(v=vs.85).aspx if (key != Keys.RMenu && key != Keys.LMenu && wParam == (IntPtr)Win32Methods.WM_SYSKEYDOWN) { alt = true; keyDown = true; } if (key != Keys.RMenu && key != Keys.LMenu && wParam == (IntPtr)Win32Methods.WM_SYSKEYUP) { alt = true; keyUp = true; } var interceptKeyEventArgs = new InterceptKeyEventArgs( key, keyDown ? KeyDirection.Down: keyUp ? KeyDirection.Up: KeyDirection.Unknown, alt, control, shift); subject.OnNext(interceptKeyEventArgs); Debug.Write(key); if (interceptKeyEventArgs.Handled) { Debug.WriteLine(" handled"); return((IntPtr)1); //handled } } return(Win32Methods.CallNextHookEx(hookId, nCode, wParam, lParam)); }