zoukankan      html  css  js  c++  java
  • 鼠标和键盘操作的全局钩子库

    注意只能用于AnyCPU、.NET版本一致、只能用于Winform。

    简化后的代码如下:

    using System;
    using System.ComponentModel;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    
    namespace UserActivityMonitor
    {
        /// <summary>
        /// This class monitors all mouse activities globally (also outside of the application) 
        /// and provides appropriate events.
        /// </summary>
        public static class HookManager
        {
            /// <summary>
            /// Occurs when the mouse pointer is moved. 
            /// </summary>
            public static event MouseEventHandler MouseMove
            {
                add
                {
                    EnsureSubscribedToGlobalMouseEvents();
                    s_MouseMove += value;
                }
    
                remove
                {
                    s_MouseMove -= value;
                    TryUnsubscribeFromGlobalMouseEvents();
                }
            }
            /// <summary>
            /// Occurs when a click was performed by the mouse. 
            /// </summary>
            public static event MouseEventHandler MouseClick
            {
                add
                {
                    EnsureSubscribedToGlobalMouseEvents();
                    s_MouseClick += value;
                }
                remove
                {
                    s_MouseClick -= value;
                    TryUnsubscribeFromGlobalMouseEvents();
                }
            }
            /// <summary>
            /// Occurs when the mouse a mouse button is pressed. 
            /// </summary>
            public static event MouseEventHandler MouseDown
            {
                add
                {
                    EnsureSubscribedToGlobalMouseEvents();
                    s_MouseDown += value;
                }
                remove
                {
                    s_MouseDown -= value;
                    TryUnsubscribeFromGlobalMouseEvents();
                }
            }
            /// <summary>
            /// Occurs when a mouse button is released. 
            /// </summary>
            public static event MouseEventHandler MouseUp
            {
                add
                {
                    EnsureSubscribedToGlobalMouseEvents();
                    s_MouseUp += value;
                }
                remove
                {
                    s_MouseUp -= value;
                    TryUnsubscribeFromGlobalMouseEvents();
                }
            }
            /// <summary>
            /// Occurs when the mouse wheel moves. 
            /// </summary>
            public static event MouseEventHandler MouseWheel
            {
                add
                {
                    EnsureSubscribedToGlobalMouseEvents();
                    s_MouseWheel += value;
                }
                remove
                {
                    s_MouseWheel -= value;
                    TryUnsubscribeFromGlobalMouseEvents();
                }
            }
            /// <summary>
            /// Occurs when a double clicked was performed by the mouse. 
            /// </summary>
            public static event MouseEventHandler MouseDoubleClick
            {
                add
                {
                    EnsureSubscribedToGlobalMouseEvents();
                    if (s_MouseDoubleClick == null)
                    {
                        s_DoubleClickTimer = new Timer
                            {
                                Interval = GetDoubleClickTime(),
                                Enabled = false
                            };
                        s_DoubleClickTimer.Tick += DoubleClickTimeElapsed;
                        MouseUp += OnMouseUp;
                    }
                    s_MouseDoubleClick += value;
                }
                remove
                {
                    if (s_MouseDoubleClick != null)
                    {
                        s_MouseDoubleClick -= value;
                        if (s_MouseDoubleClick == null)
                        {
                            MouseUp -= OnMouseUp;
                            s_DoubleClickTimer.Tick -= DoubleClickTimeElapsed;
                            s_DoubleClickTimer = null;
                        }
                    }
                    TryUnsubscribeFromGlobalMouseEvents();
                }
            }
            /// <summary>
            /// Occurs when a key is released. 
            /// </summary>
            public static event KeyEventHandler KeyUp
            {
                add
                {
                    EnsureSubscribedToGlobalKeyboardEvents();
                    s_KeyUp += value;
                }
                remove
                {
                    s_KeyUp -= value;
                    TryUnsubscribeFromGlobalKeyboardEvents();
                }
            }
            /// <summary>
            /// Occurs when a key is preseed. 
            /// </summary>
            public static event KeyEventHandler KeyDown
            {
                add
                {
                    EnsureSubscribedToGlobalKeyboardEvents();
                    s_KeyDown += value;
                }
                remove
                {
                    s_KeyDown -= value;
                    TryUnsubscribeFromGlobalKeyboardEvents();
                }
            }
            /// <summary>
            /// Occurs when a key is pressed.
            /// </summary>
            /// <remarks>
            /// Key events occur in the following order: 
            /// <list type="number">
            /// <item>KeyDown</item>
            /// <item>KeyPress</item>
            /// <item>KeyUp</item>
            /// </list>
            ///The KeyPress event is not raised by noncharacter keys; however, the noncharacter keys do raise the KeyDown and KeyUp events. 
            ///Use the KeyChar property to sample keystrokes at run time and to consume or modify a subset of common keystrokes. 
            ///To handle keyboard events only in your application and not enable other applications to receive keyboard events, 
            /// set the KeyPressEventArgs.Handled property in your form's KeyPress event-handling method to <b>true</b>. 
            /// </remarks>
            public static event KeyPressEventHandler KeyPress
            {
                add
                {
                    EnsureSubscribedToGlobalKeyboardEvents();
                    s_KeyPress += value;
                }
                remove
                {
                    s_KeyPress -= value;
                    TryUnsubscribeFromGlobalKeyboardEvents();
                }
            }
            private static event MouseEventHandler s_MouseMove;
            private static event MouseEventHandler s_MouseClick;
            private static event MouseEventHandler s_MouseDown;
            private static event MouseEventHandler s_MouseUp;
            private static event MouseEventHandler s_MouseWheel;
            private static event MouseEventHandler s_MouseDoubleClick;
            private static MouseButtons s_PrevClickedButton;
            private static Timer s_DoubleClickTimer;
            private static void DoubleClickTimeElapsed(object sender, EventArgs e)
            {
                s_DoubleClickTimer.Enabled = false;
                s_PrevClickedButton = MouseButtons.None;
            }
            private static void OnMouseUp(object sender, MouseEventArgs e)
            {
                if (e.Clicks < 1)
                {
                    return;
                }
                if (e.Button.Equals(s_PrevClickedButton))
                {
                    if (s_MouseDoubleClick != null)
                    {
                        s_MouseDoubleClick.Invoke(null, e);
                    }
                    s_DoubleClickTimer.Enabled = false;
                    s_PrevClickedButton = MouseButtons.None;
                }
                else
                {
                    s_DoubleClickTimer.Enabled = true;
                    s_PrevClickedButton = e.Button;
                }
            }
            private static event KeyPressEventHandler s_KeyPress;
            private static event KeyEventHandler s_KeyUp;
            private static event KeyEventHandler s_KeyDown;
            private const int WH_MOUSE_LL = 14;
            private const int WH_KEYBOARD_LL = 13;
            private const int WM_LBUTTONDOWN = 0x201;
            private const int WM_RBUTTONDOWN = 0x204;
            private const int WM_LBUTTONUP = 0x202;
            private const int WM_RBUTTONUP = 0x205;
            private const int WM_LBUTTONDBLCLK = 0x203;
            private const int WM_RBUTTONDBLCLK = 0x206;
            private const int WM_MOUSEWHEEL = 0x020A;
            private const int WM_KEYDOWN = 0x100;
            private const int WM_KEYUP = 0x101;
            private const int WM_SYSKEYDOWN = 0x104;
            private const int WM_SYSKEYUP = 0x105;
            private const byte VK_SHIFT = 0x10;
            private const byte VK_CAPITAL = 0x14;
            [DllImport("user32.dll", CharSet = CharSet.Auto,
                CallingConvention = CallingConvention.StdCall)]
            private static extern int CallNextHookEx(
                int idHook,
                int nCode,
                int wParam,
                IntPtr lParam);
            [DllImport("user32.dll", CharSet = CharSet.Auto,
                CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            private static extern int SetWindowsHookEx(
                int idHook,
                HookProc lpfn,
                IntPtr hMod,
                int dwThreadId);
            [DllImport("user32.dll", CharSet = CharSet.Auto,
                CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            private static extern int UnhookWindowsHookEx(int idHook);
            [DllImport("user32")]
            private static extern int GetDoubleClickTime();
            [DllImport("user32")]
            private static extern int ToAscii(
                int uVirtKey,
                int uScanCode,
                byte[] lpbKeyState,
                byte[] lpwTransKey,
                int fuState);
            [DllImport("user32")]
            private static extern int GetKeyboardState(byte[] pbKeyState);
            [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
            private static extern short GetKeyState(int vKey);
            [StructLayout(LayoutKind.Sequential)]
            private struct Point
            {
                internal readonly int X;
                internal readonly int Y;
            }
            [StructLayout(LayoutKind.Sequential)]
            private struct MouseLLHookStruct
            {
                internal Point Point;
                internal readonly int MouseData;
                private readonly int Flags;
                private readonly int Time;
                private readonly int ExtraInfo;
            }
            [StructLayout(LayoutKind.Sequential)]
            private struct KeyboardHookStruct
            {
                internal readonly int VirtualKeyCode;
                internal readonly int ScanCode;
                internal readonly int Flags;
                private readonly int Time;
                private readonly int ExtraInfo;
            }
            private delegate int HookProc(int nCode, int wParam, IntPtr lParam);
            private static HookProc s_MouseDelegate;
            private static int s_MouseHookHandle;
            private static int m_OldX;
            private static int m_OldY;
            private static int MouseHookProc(int nCode, int wParam, IntPtr lParam)
            {
                if (nCode >= 0)
                {
                    var mouseHookStruct = (MouseLLHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLLHookStruct));
                    var button = MouseButtons.None;
                    short mouseDelta = 0;
                    var clickCount = 0;
                    var mouseDown = false;
                    var mouseUp = false;
    
                    switch (wParam)
                    {
                        case WM_LBUTTONDOWN:
                            mouseDown = true;
                            button = MouseButtons.Left;
                            clickCount = 1;
                            break;
                        case WM_LBUTTONUP:
                            mouseUp = true;
                            button = MouseButtons.Left;
                            clickCount = 1;
                            break;
                        case WM_LBUTTONDBLCLK:
                            button = MouseButtons.Left;
                            clickCount = 2;
                            break;
                        case WM_RBUTTONDOWN:
                            mouseDown = true;
                            button = MouseButtons.Right;
                            clickCount = 1;
                            break;
                        case WM_RBUTTONUP:
                            mouseUp = true;
                            button = MouseButtons.Right;
                            clickCount = 1;
                            break;
                        case WM_RBUTTONDBLCLK:
                            button = MouseButtons.Right;
                            clickCount = 2;
                            break;
                        case WM_MOUSEWHEEL:
                            mouseDelta = (short)((mouseHookStruct.MouseData >> 16) & 0xffff);
                            break;
                    }
    
                    var e = new MouseEventExtArgs(
                        button,
                        clickCount,
                        mouseHookStruct.Point.X,
                        mouseHookStruct.Point.Y,
                        mouseDelta);
    
                    if (s_MouseUp != null && mouseUp)
                    {
                        s_MouseUp.Invoke(null, e);
                    }
    
                    if (s_MouseDown != null && mouseDown)
                    {
                        s_MouseDown.Invoke(null, e);
                    }
    
                    if (s_MouseClick != null && clickCount > 0)
                    {
                        s_MouseClick.Invoke(null, e);
                    }
    
                    if (s_MouseDoubleClick != null && clickCount == 2)
                    {
                        s_MouseDoubleClick.Invoke(null, e);
                    }
    
                    if (s_MouseWheel != null && mouseDelta != 0)
                    {
                        s_MouseWheel.Invoke(null, e);
                    }
    
                    if ((s_MouseMove != null) && (m_OldX != mouseHookStruct.Point.X || m_OldY != mouseHookStruct.Point.Y))
                    {
                        m_OldX = mouseHookStruct.Point.X;
                        m_OldY = mouseHookStruct.Point.Y;
                        if (s_MouseMove != null)
                        {
                            s_MouseMove.Invoke(null, e);
                        }
                    }
    
                    if (e.Handled)
                    {
                        return -1;
                    }
                }
    
                return CallNextHookEx(s_MouseHookHandle, nCode, wParam, lParam);
            }
            private static void EnsureSubscribedToGlobalMouseEvents()
            {
                if (s_MouseHookHandle != 0)
                {
                    return;
                }
                s_MouseDelegate = MouseHookProc;
                s_MouseHookHandle = SetWindowsHookEx(
                    WH_MOUSE_LL,
                    s_MouseDelegate,
                    Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),
                    0);
                if (s_MouseHookHandle != 0)
                {
                    return;
                }
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
            private static void TryUnsubscribeFromGlobalMouseEvents()
            {
                if (s_MouseClick == null &&
                    s_MouseDown == null &&
                    s_MouseMove == null &&
                    s_MouseUp == null &&
                    s_MouseWheel == null)
                {
                    ForceUnsunscribeFromGlobalMouseEvents();
                }
            }
            private static void ForceUnsunscribeFromGlobalMouseEvents()
            {
                if (s_MouseHookHandle == 0)
                {
                    return;
                }
                var result = UnhookWindowsHookEx(s_MouseHookHandle);
                s_MouseHookHandle = 0;
                s_MouseDelegate = null;
                if (result != 0)
                {
                    return;
                }
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
            private static HookProc s_KeyboardDelegate;
            private static int s_KeyboardHookHandle;
            private static int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
            {
                var handled = false;
                if (nCode >= 0)
                {
                    var MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
                    if (s_KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
                    {
                        var keyData = (Keys)MyKeyboardHookStruct.VirtualKeyCode;
                        var e = new KeyEventArgs(keyData);
                        s_KeyDown.Invoke(null, e);
                        handled = e.Handled;
                    }
    
                    if (s_KeyPress != null && wParam == WM_KEYDOWN)
                    {
                        var isDownShift = ((GetKeyState(VK_SHIFT) & 0x80) == 0x80);
                        var isDownCapslock = (GetKeyState(VK_CAPITAL) != 0);
    
                        var keyState = new byte[256];
                        GetKeyboardState(keyState);
                        var inBuffer = new byte[2];
                        if (ToAscii(MyKeyboardHookStruct.VirtualKeyCode,
                                    MyKeyboardHookStruct.ScanCode,
                                    keyState,
                                    inBuffer,
                                    MyKeyboardHookStruct.Flags) == 1)
                        {
                            var key = (char)inBuffer[0];
                            if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key);
                            var e = new KeyPressEventArgs(key);
                            s_KeyPress.Invoke(null, e);
                            handled = handled || e.Handled;
                        }
                    }
    
                    if (s_KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
                    {
                        var keyData = (Keys)MyKeyboardHookStruct.VirtualKeyCode;
                        var e = new KeyEventArgs(keyData);
                        s_KeyUp.Invoke(null, e);
                        handled = handled || e.Handled;
                    }
                }
    
                if (handled)
                {
                    return -1;
                }
    
                return CallNextHookEx(s_KeyboardHookHandle, nCode, wParam, lParam);
            }
            private static void EnsureSubscribedToGlobalKeyboardEvents()
            {
                if (s_KeyboardHookHandle != 0)
                {
                    return;
                }
                s_KeyboardDelegate = KeyboardHookProc;
                s_KeyboardHookHandle = SetWindowsHookEx(
                    WH_KEYBOARD_LL,
                    s_KeyboardDelegate,
                    Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),
                    0);
                if (s_KeyboardHookHandle != 0)
                {
                    return;
                }
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
            private static void TryUnsubscribeFromGlobalKeyboardEvents()
            {
                if (s_KeyDown != null || s_KeyUp != null || s_KeyPress != null)
                {
                    return;
                }
                if (s_KeyboardHookHandle == 0)
                {
                    return;
                }
                var result = UnhookWindowsHookEx(s_KeyboardHookHandle);
                s_KeyboardHookHandle = 0;
                s_KeyboardDelegate = null;
                if (result != 0)
                {
                    return;
                }
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
        }
        internal class MouseEventExtArgs : MouseEventArgs
        {
            internal MouseEventExtArgs(MouseButtons buttons, int clicks, int x, int y, int delta)
                : base(buttons, clicks, x, y, delta)
            { }
            internal bool Handled { get; set; }
        }
    }
  • 相关阅读:
    XML
    DAO
    JDBC
    事物、视图、索引、备份和恢复
    用户
    高级查询2
    高级查询1
    数据库设计
    初识MySQL
    古代和现在的区别Hashtable和HashMap
  • 原文地址:https://www.cnblogs.com/yao2yao4/p/3256356.html
Copyright © 2011-2022 走看看