123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- using System;
- using System.Diagnostics;
- using System.Runtime.InteropServices;
- using System.Windows.Forms;
- namespace MediaBrowser.UI.UserInput
- {
- /// <summary>
- /// Provides a basic low-level keyboard listener
- /// Inspired by http://blogs.msdn.com/b/toub/archive/2006/05/03/589423.aspx
- /// Use the KeyDown event to listen for keys.
- /// Make sure to detach from the event when not needed.
- /// </summary>
- public static class KeyboardListener
- {
- #region KeyDown EventHandler
- /// <summary>
- /// The _ key down
- /// </summary>
- static volatile EventHandler<KeyEventArgs> _KeyDown;
- /// <summary>
- /// Fires whenever CurrentItem changes
- /// </summary>
- public static event EventHandler<KeyEventArgs> KeyDown
- {
- add
- {
- if (_KeyDown == null)
- {
- StartListening();
- }
- _KeyDown += value;
- }
- remove
- {
- _KeyDown -= value;
- if (_KeyDown == null && _hookID != IntPtr.Zero)
- {
- StopListening();
- }
- }
- }
- /// <summary>
- /// Raises the <see cref="E:KeyDown" /> event.
- /// </summary>
- /// <param name="e">The <see cref="KeyEventArgs" /> instance containing the event data.</param>
- private static void OnKeyDown(KeyEventArgs e)
- {
- e.SuppressKeyPress = false;
- if (_KeyDown != null)
- {
- // For now, don't async this
- // This will give listeners a chance to modify SuppressKeyPress if they want
- try
- {
- _KeyDown(null, e);
- }
- catch (Exception ex)
- {
- }
- }
- }
- #endregion
- /// <summary>
- /// The W h_ KEYBOAR d_ LL
- /// </summary>
- private const int WH_KEYBOARD_LL = 13;
- /// <summary>
- /// The W m_ KEYDOWN
- /// </summary>
- private const int WM_KEYDOWN = 0x0100;
- /// <summary>
- /// The W m_ SYSKEYDOWN
- /// </summary>
- private const int WM_SYSKEYDOWN = 0x0104;
- /// <summary>
- /// The _hook ID
- /// </summary>
- private static IntPtr _hookID = IntPtr.Zero;
- /// <summary>
- /// The _proc
- /// </summary>
- private static LowLevelKeyboardProc _proc = HookCallback;
- /// <summary>
- /// Starts the listening.
- /// </summary>
- private static void StartListening()
- {
- _hookID = SetHook(_proc);
- }
- /// <summary>
- /// Stops the listening.
- /// </summary>
- private static void StopListening()
- {
- UnhookWindowsHookEx(_hookID);
- _hookID = IntPtr.Zero;
- }
- /// <summary>
- /// Sets the hook.
- /// </summary>
- /// <param name="proc">The proc.</param>
- /// <returns>IntPtr.</returns>
- private static IntPtr SetHook(LowLevelKeyboardProc proc)
- {
- using (var curProcess = Process.GetCurrentProcess())
- using (var curModule = curProcess.MainModule)
- {
- return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
- GetModuleHandle(curModule.ModuleName), 0);
- }
- }
- /// <summary>
- /// Hooks the callback.
- /// </summary>
- /// <param name="nCode">The n code.</param>
- /// <param name="wParam">The w param.</param>
- /// <param name="lParam">The l param.</param>
- /// <returns>IntPtr.</returns>
- private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
- {
- var suppressKeyPress = false;
- if (nCode >= 0)
- {
- if (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN)
- {
- var vkCode = Marshal.ReadInt32(lParam);
- var keyData = (Keys)vkCode;
- var e = new KeyEventArgs(keyData);
- OnKeyDown(e);
- suppressKeyPress = e.SuppressKeyPress;
- }
- }
- if (suppressKeyPress)
- {
- return IntPtr.Zero;
- }
- return CallNextHookEx(_hookID, nCode, wParam, lParam);
- }
- /// <summary>
- /// Delegate LowLevelKeyboardProc
- /// </summary>
- /// <param name="nCode">The n code.</param>
- /// <param name="wParam">The w param.</param>
- /// <param name="lParam">The l param.</param>
- /// <returns>IntPtr.</returns>
- private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
- #region Imports
- /// <summary>
- /// Sets the windows hook ex.
- /// </summary>
- /// <param name="idHook">The id hook.</param>
- /// <param name="lpfn">The LPFN.</param>
- /// <param name="hMod">The h mod.</param>
- /// <param name="dwThreadId">The dw thread id.</param>
- /// <returns>IntPtr.</returns>
- [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- private static extern IntPtr SetWindowsHookEx(int idHook,
- LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
- /// <summary>
- /// Unhooks the windows hook ex.
- /// </summary>
- /// <param name="hhk">The HHK.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool UnhookWindowsHookEx(IntPtr hhk);
- /// <summary>
- /// Calls the next hook ex.
- /// </summary>
- /// <param name="hhk">The HHK.</param>
- /// <param name="nCode">The n code.</param>
- /// <param name="wParam">The w param.</param>
- /// <param name="lParam">The l param.</param>
- /// <returns>IntPtr.</returns>
- [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
- IntPtr wParam, IntPtr lParam);
- /// <summary>
- /// Gets the module handle.
- /// </summary>
- /// <param name="lpModuleName">Name of the lp module.</param>
- /// <returns>IntPtr.</returns>
- [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- private static extern IntPtr GetModuleHandle(string lpModuleName);
- #endregion
- }
- }
|