Created
September 24, 2015 06:22
-
-
Save Jia-Hong-Peng/068a33bcce6326e976a9 to your computer and use it in GitHub Desktop.
KeyboardHook.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using System.Text; | |
| using System.Diagnostics; | |
| using System.Reflection; | |
| using System.Runtime.InteropServices; | |
| namespace WindowsHookSample | |
| { | |
| /// <summary> | |
| /// 提供Unmanaged方法接收全域鍵盤事件。 | |
| /// </summary> | |
| public static class KeyboardHook | |
| { | |
| /// <summary> | |
| /// 取得或設定是否獨佔所有鍵盤事件。 | |
| /// </summary> | |
| public static bool Monopolize { get; set; } | |
| /// <summary> | |
| /// 不論是否擁有焦點,當鍵盤按下時引發此事件。 | |
| /// </summary> | |
| public static event EventHandler<KeyEventArgs> GlobalKeyDown; | |
| /// <summary> | |
| /// 不論是否擁有焦點,當鍵盤放開時引發此事件。 | |
| /// </summary> | |
| public static event EventHandler<KeyEventArgs> GlobalKeyUp; | |
| /// <summary> | |
| /// 取得或設定是否開始接收全域鍵盤事件。 | |
| /// </summary> | |
| 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; | |
| /// <summary> | |
| /// 向Windows註冊Hook。 | |
| /// </summary> | |
| 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."); | |
| } | |
| } | |
| /// <summary> | |
| /// 註冊Windows Hook時用到的委派方法,當全域事件發生時會執行這個方法,並提供全域事件資料。 | |
| /// </summary> | |
| 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); | |
| } | |
| /// <summary> | |
| /// 提供 GlobalKeyDown 或 GlobalKeyUp 事件的資料。 | |
| /// </summary> | |
| public class KeyEventArgs : EventArgs | |
| { | |
| /// <summary> | |
| /// 取得或設定值,指出是否處理事件。 | |
| /// </summary> | |
| public bool Handled { get; set; } | |
| /// <summary> | |
| /// 取得值,虛擬鍵盤碼的System.Windows.Forms.Keys表示。 | |
| /// </summary> | |
| public System.Windows.Forms.Keys Keys { get { return (System.Windows.Forms.Keys)VirtualKeyCode; } } | |
| /// <summary> | |
| /// 取得值,虛擬鍵盤碼的System.Windows.Input.Key表示。 | |
| /// </summary> | |
| public System.Windows.Input.Key Key { get { return System.Windows.Input.KeyInterop.KeyFromVirtualKey(VirtualKeyCode); } } | |
| /// <summary> | |
| /// 取得值,指出是否按下 ALT 鍵。 | |
| /// </summary> | |
| public bool Alt | |
| { | |
| get | |
| { | |
| return KeyIsDown((int)System.Windows.Forms.Keys.LMenu) || KeyIsDown((int)System.Windows.Forms.Keys.RMenu); | |
| } | |
| } | |
| /// <summary> | |
| /// 取得值,指出是否按下 CTRL 鍵。 | |
| /// </summary> | |
| public bool Control | |
| { | |
| get | |
| { | |
| return KeyIsDown((int)System.Windows.Forms.Keys.LControlKey) || KeyIsDown((int)System.Windows.Forms.Keys.RControlKey); | |
| } | |
| } | |
| /// <summary> | |
| /// 取得值,指出是否按下 SHIFT 鍵。 | |
| /// </summary> | |
| public bool Shift | |
| { | |
| get | |
| { | |
| return KeyIsDown((int)System.Windows.Forms.Keys.LShiftKey) || KeyIsDown((int)System.Windows.Forms.Keys.RShiftKey); | |
| } | |
| } | |
| /// <summary> | |
| /// 取得值,引發事件的虛擬鍵盤碼。 | |
| /// </summary> | |
| 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; | |
| } | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using System.Text; | |
| using System.Diagnostics; | |
| using System.Runtime.InteropServices; | |
| using System.Reflection; | |
| using System.Windows.Forms; | |
| namespace WindowsHookSample | |
| { | |
| /// <summary> | |
| /// 提供Unmanaged方法接收全域滑鼠事件。 | |
| /// </summary> | |
| public static class MouseHook | |
| { | |
| /// <summary> | |
| /// 取得或設定是否獨佔所有滑鼠事件。 | |
| /// </summary> | |
| public static bool Monopolize { get; set; } | |
| /// <summary> | |
| /// 當滑鼠按鍵壓下時引發此事件。 | |
| /// </summary> | |
| public static event EventHandler<MouseEventArgs> GlobalMouseDown; | |
| /// <summary> | |
| /// 當滑鼠按鍵放開時引發此事件。 | |
| /// </summary> | |
| public static event EventHandler<MouseEventArgs> GlobalMouseUp; | |
| /// <summary> | |
| /// 當滑鼠按鍵點擊時引發此事件。 | |
| /// </summary> | |
| public static event EventHandler<MouseEventArgs> GlobalMouseClick; | |
| /// <summary> | |
| /// 當滑鼠按鍵連點兩次時引發此事件。 | |
| /// </summary> | |
| public static event EventHandler<MouseEventArgs> GlobalMouseDoubleClick; | |
| /// <summary> | |
| /// 當滑鼠滾輪滾動時引發此事件。 | |
| /// </summary> | |
| public static event EventHandler<MouseEventArgs> GlobalMouseWheel; | |
| /// <summary> | |
| /// 當滑鼠移動時引發此事件。 | |
| /// </summary> | |
| public static event EventHandler<MouseEventArgs> GlobalMouseMove; | |
| /// <summary> | |
| /// 取得或設定是否開始接收全域滑鼠事件。 | |
| /// </summary> | |
| 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; | |
| /// <summary> | |
| /// 向Windows註冊Hook。 | |
| /// </summary> | |
| 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_MOUSE_LL, m_HookProc, NativeMethods.GetModuleHandle(curModule.ModuleName), 0); | |
| curModule.Dispose(); | |
| curProcess.Dispose(); | |
| m_DoubleClickTimer = new Timer | |
| { | |
| Interval = NativeMethods.GetDoubleClickTime(), | |
| Enabled = false | |
| }; | |
| m_DoubleClickTimer.Tick += DoubleClickTimeElapsed; | |
| GlobalMouseDown += OnMouseDown; | |
| 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."); | |
| } | |
| } | |
| //記憶游標上一次的位置,避免MouseMove事件一直引發。 | |
| private static int m_OldX = 0; | |
| private static int m_OldY = 0; | |
| //記憶上次MouseDonw的引發位置,如果與MouseUp的位置不同則不引發Click事件。 | |
| private static int m_LastBTDownX = 0; | |
| private static int m_LastBTDownY = 0; | |
| /// <summary> | |
| /// 註冊Windows Hook時用到的委派方法,當全域事件發生時會執行這個方法,並提供全域事件資料。 | |
| /// </summary> | |
| private static int HookProc(int nCode, IntPtr wParam, IntPtr lParam) | |
| { | |
| MouseEventArgs e = null; | |
| if (nCode >= 0) | |
| { | |
| int wParam_Int32 = wParam.ToInt32(); | |
| NativeStructs.MOUSELLHookStruct mouseHookStruct = (NativeStructs.MOUSELLHookStruct)Marshal.PtrToStructure(lParam, typeof(NativeStructs.MOUSELLHookStruct)); | |
| short mouseDelta = 0; | |
| if (GlobalMouseWheel != null && wParam_Int32 == NativeContansts.WM_MOUSEWHEEL) | |
| mouseDelta = (short)((mouseHookStruct.MouseData >> 16) & 0xffff); | |
| e = new MouseEventArgs(wParam_Int32, mouseHookStruct.Point.X, mouseHookStruct.Point.Y, mouseDelta); | |
| if (GlobalMouseWheel != null && wParam_Int32 == NativeContansts.WM_MOUSEWHEEL) | |
| GlobalMouseWheel.Invoke(null, e); | |
| else if (GlobalMouseUp != null && (wParam_Int32 == NativeContansts.WM_LBUTTONUP || wParam_Int32 == NativeContansts.WM_RBUTTONUP || wParam_Int32 == NativeContansts.WM_MBUTTONUP)) | |
| { | |
| GlobalMouseUp.Invoke(null, e); | |
| if (GlobalMouseClick != null && (mouseHookStruct.Point.X == m_LastBTDownX && mouseHookStruct.Point.Y == m_LastBTDownY)) | |
| GlobalMouseClick.Invoke(null, e); | |
| } | |
| else if (GlobalMouseDown != null && (wParam_Int32 == NativeContansts.WM_LBUTTONDOWN || wParam_Int32 == NativeContansts.WM_RBUTTONDOWN || wParam_Int32 == NativeContansts.WM_MBUTTONDOWN)) | |
| { | |
| m_LastBTDownX = mouseHookStruct.Point.X; | |
| m_LastBTDownY = mouseHookStruct.Point.Y; | |
| GlobalMouseDown.Invoke(null, e); | |
| } | |
| else if (GlobalMouseMove != null && (m_OldX != mouseHookStruct.Point.X || m_OldY != mouseHookStruct.Point.Y)) | |
| { | |
| m_OldX = mouseHookStruct.Point.X; | |
| m_OldY = mouseHookStruct.Point.Y; | |
| if (GlobalMouseMove != null) | |
| GlobalMouseMove.Invoke(null, e); | |
| } | |
| } | |
| if (Monopolize || (e != null && e.Handled)) | |
| return -1; | |
| return NativeMethods.CallNextHookEx(m_HookHandle, nCode, wParam, lParam); | |
| } | |
| private static void OnMouseDown(object sender, MouseEventArgs e) | |
| { | |
| if (e.Button.Equals(m_LastClickedButton)) | |
| { | |
| if (GlobalMouseDoubleClick != null) | |
| GlobalMouseDoubleClick.Invoke(null, e); | |
| } | |
| else | |
| { | |
| m_DoubleClickTimer.Enabled = true; | |
| m_LastClickedButton = e.Button; | |
| } | |
| } | |
| private static Buttons m_LastClickedButton; | |
| private static System.Windows.Forms.Timer m_DoubleClickTimer; | |
| private static void DoubleClickTimeElapsed(object sender, EventArgs e) | |
| { | |
| m_DoubleClickTimer.Enabled = false; | |
| m_LastClickedButton = Buttons.None; | |
| } | |
| /// <summary> | |
| /// 提供 GlobalMouseUp、GlobalMouseDown 和 GlobalMouseMove 事件的資料。 | |
| /// </summary> | |
| public class MouseEventArgs : EventArgs | |
| { | |
| /// <summary> | |
| /// 取得按下哪個滑鼠鍵的資訊。 | |
| /// </summary> | |
| public Buttons Button { get; private set; } | |
| /// <summary> | |
| /// 取得滑鼠滾輪滾動時帶有正負號的刻度數乘以 WHEEL_DELTA 常數。 一個刻度是一個滑鼠滾輪的刻痕。 | |
| /// </summary> | |
| public int Delta { get; private set; } | |
| /// <summary> | |
| /// 取得滑鼠在產生滑鼠事件期間的 X 座標。 | |
| /// </summary> | |
| public int X { get; private set; } | |
| /// <summary> | |
| /// 取得滑鼠在產生滑鼠事件期間的 Y 座標。 | |
| /// </summary> | |
| public int Y { get; private set; } | |
| internal MouseEventArgs(int wParam, int x, int y, int delta) | |
| { | |
| Button = Buttons.None; | |
| switch (wParam) | |
| { | |
| case (int)NativeContansts.WM_LBUTTONDOWN: | |
| case (int)NativeContansts.WM_LBUTTONUP: | |
| Button = Buttons.Left; | |
| break; | |
| case (int)NativeContansts.WM_RBUTTONDOWN: | |
| case (int)NativeContansts.WM_RBUTTONUP: | |
| Button = Buttons.Right; | |
| break; | |
| case (int)NativeContansts.WM_MBUTTONDOWN: | |
| case (int)NativeContansts.WM_MBUTTONUP: | |
| Button = Buttons.Middle; | |
| break; | |
| } | |
| this.X = x; | |
| this.Y = y; | |
| this.Delta = delta; | |
| } | |
| private bool m_Handled; | |
| /// <summary> | |
| /// 取得或設定值,指出是否處理事件。 | |
| /// </summary> | |
| public bool Handled | |
| { | |
| get { return m_Handled; } | |
| set { m_Handled = value; } | |
| } | |
| } | |
| } | |
| /// <summary> | |
| /// 指定定義按哪個滑鼠按鈕的常數。 | |
| /// </summary> | |
| public enum Buttons | |
| { | |
| /// <summary> | |
| /// 不按任何滑鼠鍵。 | |
| /// </summary> | |
| None, | |
| /// <summary> | |
| /// 按滑鼠左鍵。 | |
| /// </summary> | |
| Left, | |
| /// <summary> | |
| /// 按滑鼠右鍵。 | |
| /// </summary> | |
| Right, | |
| /// <summary> | |
| /// 按滑鼠中間鍵。 | |
| /// </summary> | |
| Middle, | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using System.Text; | |
| namespace WindowsHookSample | |
| { | |
| internal class NativeContansts | |
| { | |
| public const int WH_MOUSE_LL = 14; | |
| public const int WH_KEYBOARD_LL = 13; | |
| public const int WH_MOUSE = 7; | |
| public const int WH_KEYBOARD = 2; | |
| public const int WM_MOUSEMOVE = 0x200; | |
| public const int WM_LBUTTONDOWN = 0x201; | |
| public const int WM_RBUTTONDOWN = 0x204; | |
| public const int WM_MBUTTONDOWN = 0x207; | |
| public const int WM_LBUTTONUP = 0x202; | |
| public const int WM_RBUTTONUP = 0x205; | |
| public const int WM_MBUTTONUP = 0x208; | |
| public const int WM_LBUTTONDBLCLK = 0x203; | |
| public const int WM_RBUTTONDBLCLK = 0x206; | |
| public const int WM_MBUTTONDBLCLK = 0x209; | |
| public const int WM_MOUSEWHEEL = 0x020A; | |
| public const int WM_KEYDOWN = 0x100; | |
| public const int WM_KEYUP = 0x101; | |
| public const int WM_SYSKEYDOWN = 0x104; | |
| public const int WM_SYSKEYUP = 0x105; | |
| public const int MEF_LEFTDOWN = 0x00000002; | |
| public const int MEF_LEFTUP = 0x00000004; | |
| public const int MEF_MIDDLEDOWN = 0x00000020; | |
| public const int MEF_MIDDLEUP = 0x00000040; | |
| public const int MEF_RIGHTDOWN = 0x00000008; | |
| public const int MEF_RIGHTUP = 0x00000010; | |
| public const int KEF_EXTENDEDKEY = 0x1; | |
| public const int KEF_KEYUP = 0x2; | |
| public const byte VK_SHIFT = 0x10; | |
| public const byte VK_CAPITAL = 0x14; | |
| public const byte VK_NUMLOCK = 0x90; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using System.Text; | |
| using System.Runtime.InteropServices; | |
| namespace WindowsHookSample | |
| { | |
| internal static class NativeMethods | |
| { | |
| [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] | |
| public static extern short GetKeyState(int keyCode); | |
| [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] | |
| public static extern int SetWindowsHookEx(int idHook, NativeStructs.HookProc lpfn, IntPtr hInstance, int threadId); | |
| [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] | |
| public static extern bool UnhookWindowsHookEx(int idHook); | |
| [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] | |
| public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam); | |
| [DllImport("user32")] | |
| public static extern int GetDoubleClickTime(); | |
| [DllImport("user32")] | |
| public static extern int ToAscii(int uVirtKey, int uScanCode, byte[] lpbKeyState, byte[] lpwTransKey, int fuState); | |
| [DllImport("user32")] | |
| public static extern int GetKeyboardState(byte[] pbKeyState); | |
| [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] | |
| public static extern IntPtr GetModuleHandle(string lpModuleName); | |
| [DllImport("user32.dll")] | |
| public static extern IntPtr SendMessageW(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using System.Text; | |
| using System.Runtime.InteropServices; | |
| namespace WindowsHookSample | |
| { | |
| internal static class NativeStructs | |
| { | |
| public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam); | |
| [StructLayout(LayoutKind.Sequential)] | |
| public struct Point | |
| { | |
| public int X; | |
| public int Y; | |
| } | |
| [StructLayout(LayoutKind.Sequential)] | |
| public struct MOUSELLHookStruct | |
| { | |
| public Point Point; | |
| public int MouseData; | |
| public int Flags; | |
| public int Time; | |
| public int ExtraInfo; | |
| } | |
| [StructLayout(LayoutKind.Sequential)] | |
| public struct KEYBOARDLLHookStruct | |
| { | |
| public int VirtualKeyCode; | |
| public int ScanCode; | |
| public int Flags; | |
| public int Time; | |
| public int ExtraInfo; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment