From 767cdc1f6f6a63ce997fc9476911e2c361f9d402 Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Wed, 20 Feb 2013 20:33:05 -0500 Subject: Pushing missing changes --- MediaBrowser.UI/UserInput/KeyboardListener.cs | 215 ++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 MediaBrowser.UI/UserInput/KeyboardListener.cs (limited to 'MediaBrowser.UI/UserInput/KeyboardListener.cs') diff --git a/MediaBrowser.UI/UserInput/KeyboardListener.cs b/MediaBrowser.UI/UserInput/KeyboardListener.cs new file mode 100644 index 000000000..779da42fb --- /dev/null +++ b/MediaBrowser.UI/UserInput/KeyboardListener.cs @@ -0,0 +1,215 @@ +using MediaBrowser.Common.Logging; +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace MediaBrowser.UI.UserInput +{ + /// + /// 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. + /// + public static class KeyboardListener + { + #region KeyDown EventHandler + /// + /// The _ key down + /// + static volatile EventHandler _KeyDown; + /// + /// Fires whenever CurrentItem changes + /// + public static event EventHandler KeyDown + { + add + { + if (_KeyDown == null) + { + StartListening(); + } + + _KeyDown += value; + } + remove + { + _KeyDown -= value; + + if (_KeyDown == null && _hookID != IntPtr.Zero) + { + StopListening(); + } + } + } + + /// + /// Raises the event. + /// + /// The instance containing the event data. + 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) + { + Logger.LogException("KeyDown event listener had an error: ", ex); + } + } + } + #endregion + + /// + /// The W h_ KEYBOAR d_ LL + /// + private const int WH_KEYBOARD_LL = 13; + /// + /// The W m_ KEYDOWN + /// + private const int WM_KEYDOWN = 0x0100; + /// + /// The W m_ SYSKEYDOWN + /// + private const int WM_SYSKEYDOWN = 0x0104; + + /// + /// The _hook ID + /// + private static IntPtr _hookID = IntPtr.Zero; + /// + /// The _proc + /// + private static LowLevelKeyboardProc _proc = HookCallback; + + /// + /// Starts the listening. + /// + private static void StartListening() + { + Logger.LogInfo("Attaching low-level keyboard hook"); + _hookID = SetHook(_proc); + } + + /// + /// Stops the listening. + /// + private static void StopListening() + { + Logger.LogInfo("Detaching low-level keyboard hook"); + + UnhookWindowsHookEx(_hookID); + _hookID = IntPtr.Zero; + } + + /// + /// Sets the hook. + /// + /// The proc. + /// IntPtr. + 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); + } + } + + /// + /// Hooks the callback. + /// + /// The n code. + /// The w param. + /// The l param. + /// IntPtr. + 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); + } + + /// + /// Delegate LowLevelKeyboardProc + /// + /// The n code. + /// The w param. + /// The l param. + /// IntPtr. + private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam); + + #region Imports + /// + /// Sets the windows hook ex. + /// + /// The id hook. + /// The LPFN. + /// The h mod. + /// The dw thread id. + /// IntPtr. + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr SetWindowsHookEx(int idHook, + LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId); + + /// + /// Unhooks the windows hook ex. + /// + /// The HHK. + /// true if XXXX, false otherwise + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool UnhookWindowsHookEx(IntPtr hhk); + + /// + /// Calls the next hook ex. + /// + /// The HHK. + /// The n code. + /// The w param. + /// The l param. + /// IntPtr. + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, + IntPtr wParam, IntPtr lParam); + + /// + /// Gets the module handle. + /// + /// Name of the lp module. + /// IntPtr. + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr GetModuleHandle(string lpModuleName); + #endregion + } +} -- cgit v1.2.3