轉貼自http://www.dotblogs.com.tw/optimist9266/archive/2011/06/08/27315.aspx
以下會利用SetWindowsHookEx原生方法來達到接收全域鍵盤事件的效果。
原生方法的宣告請參考[常用Windows原生方法整理(Windows API)]。
原生方法用到的常數請參考[Windows 原生指令常數 (Windows API Constansts)]。
原生方法用到的結構請參考[常用Windows原生結構]。
使用這個類別時必須注意,在這個類別引發的所有事件中查詢引發事件的按鍵狀態,將會收到與預期不同的結果。
因為範例程式碼中使用的是低階WinHook,因此當Windows都還沒收到訊號時就會執行事件委派,如果在這些委派中透過API查詢按鍵狀態,將不會是最新的按鍵狀態,因為Windows還沒有為其更新狀態。
public static class KeyboardHook { ////// 取得或設定是否獨佔所有鍵盤事件。 /// public static bool Monopolize { get; set; } ////// 不論是否擁有焦點,當鍵盤按下時引發此事件。 /// public static event EventHandlerGlobalKeyDown; /// /// 不論是否擁有焦點,當鍵盤放開時引發此事件。 /// public static event EventHandlerGlobalKeyUp; /// /// 取得或設定是否開始接收全域鍵盤事件。 /// public static bool Enabled { get { return m_Enabled; } set { if (m_Enabled != value) { m_Enabled = value; if (value) Install(); else Uninstall(); } } } private static bool m_Enabled = false; private static int m_HookHandle = 0; private static NativeStructs.HookProc m_HookProc; ////// 向Windows註冊Hook。 /// private static void Install() { if (m_HookHandle == 0) { Process curProcess = Process.GetCurrentProcess(); ProcessModule curModule = curProcess.MainModule; m_HookProc = new NativeStructs.HookProc(HookProc); m_HookHandle = NativeMethods.SetWindowsHookEx(NativeContansts.WH_KEYBOARD_LL, m_HookProc, NativeMethods.GetModuleHandle(curModule.ModuleName), 0); curModule.Dispose(); curProcess.Dispose(); if (m_HookHandle == 0) throw new Exception("Install Hook Faild."); } } private static void Uninstall() { if (m_HookHandle != 0) { bool ret = NativeMethods.UnhookWindowsHookEx(m_HookHandle); if (ret) m_HookHandle = 0; else throw new Exception("Uninstall Hook Faild."); } } ////// 註冊Windows Hook時用到的委派方法,當全域事件發生時會執行這個方法,並提供全域事件資料。 /// private static int HookProc(int nCode, IntPtr wParam, IntPtr lParam) { KeyEventArgs e = null; int wParam_Int32 = wParam.ToInt32(); if (nCode >= 0) { NativeStructs.KEYBOARDLLHookStruct keyboardHookStruct = (NativeStructs.KEYBOARDLLHookStruct)Marshal.PtrToStructure(lParam, typeof(NativeStructs.KEYBOARDLLHookStruct)); if (GlobalKeyDown != null && (wParam_Int32 == NativeContansts.WM_KEYDOWN || wParam_Int32 == NativeContansts.WM_SYSKEYDOWN)) { e = new KeyEventArgs(keyboardHookStruct.VirtualKeyCode); GlobalKeyDown.Invoke(null, e); } else if (GlobalKeyUp != null && (wParam_Int32 == NativeContansts.WM_KEYUP || wParam_Int32 == NativeContansts.WM_SYSKEYUP)) { e = new KeyEventArgs(keyboardHookStruct.VirtualKeyCode); GlobalKeyUp.Invoke(null, e); } } if (Monopolize || (e != null && e.Handled)) return -1; return NativeMethods.CallNextHookEx(m_HookHandle, nCode, wParam, lParam); } ////// 提供 GlobalKeyDown 或 GlobalKeyUp 事件的資料。 /// public class KeyEventArgs : EventArgs { ////// 取得或設定值,指出是否處理事件。 /// public bool Handled { get; set; } ////// 取得值,虛擬鍵盤碼的System.Windows.Forms.Keys表示。 /// public System.Windows.Forms.Keys Keys { get { return (System.Windows.Forms.Keys)VirtualKeyCode; } } ////// 取得值,虛擬鍵盤碼的System.Windows.Input.Key表示。 /// public System.Windows.Input.Key Key { get { return System.Windows.Input.KeyInterop.KeyFromVirtualKey(VirtualKeyCode); } } ////// 取得值,指出是否按下 ALT 鍵。 /// public bool Alt { get { return KeyIsDown((int)System.Windows.Forms.Keys.LMenu) || KeyIsDown((int)System.Windows.Forms.Keys.RMenu); } } ////// 取得值,指出是否按下 CTRL 鍵。 /// public bool Control { get { return KeyIsDown((int)System.Windows.Forms.Keys.LControlKey) || KeyIsDown((int)System.Windows.Forms.Keys.RControlKey); } } ////// 取得值,指出是否按下 SHIFT 鍵。 /// public bool Shift { get { return KeyIsDown((int)System.Windows.Forms.Keys.LShiftKey) || KeyIsDown((int)System.Windows.Forms.Keys.RShiftKey); } } ////// 取得值,引發事件的虛擬鍵盤碼。 /// public int VirtualKeyCode { get; private set; } internal KeyEventArgs(int virtualKey) { this.Handled = false; this.VirtualKeyCode = virtualKey; } private static bool KeyIsDown(int KeyCode) { if ((NativeMethods.GetKeyState(KeyCode) & 0x80) == 0x80) return true; else return false; } } }
0 意見:
張貼留言