csharp 全局键盘鼠标钩子

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了csharp 全局键盘鼠标钩子相关的知识,希望对你有一定的参考价值。

    internal class MouseHookHelper
    {
        #region PInvoke

        private enum HookType : int
        {
            WH_JOURNALRECORD = 0,
            WH_JOURNALPLAYBACK = 1,
            WH_KEYBOARD = 2,
            WH_GETMESSAGE = 3,
            WH_CALLWNDPROC = 4,
            WH_CBT = 5,
            WH_SYSMSGFILTER = 6,
            WH_MOUSE = 7,
            WH_HARDWARE = 8,
            WH_DEBUG = 9,
            WH_SHELL = 10,
            WH_FOREGROUNDIDLE = 11,
            WH_CALLWNDPROCRET = 12,
            WH_KEYBOARD_LL = 13,
            WH_MOUSE_LL = 14
        }

        private struct POINT
        {
            public int x;
            public int y;
        }

        private struct MSLLHOOKSTRUCT
        {
            public POINT pt;
            public int mouseData;
            public UInt32 flags;
            public UInt32 time;
            public IntPtr dwExtraInfo;
        }

        private enum MouseMessages
        {
            WM_LBUTTONDOWN = 0x0201,
            WM_LBUTTONUP = 0x0202,
            WM_MOUSEMOVE = 0x0200,
            WM_MOUSEWHEEL = 0x020A,
            WM_RBUTTONDOWN = 0x0204,
            WM_RBUTTONUP = 0x0205
        }

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        [DllImport("user32.dll")]
        private static extern IntPtr SetWindowsHookEx(int idHook, IntPtr lpfn, IntPtr hMod, int dwThreadId);

        [DllImport("user32.dll")]
        private static extern int UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll")]
        private static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        private delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);

        #endregion PInvoke

        public delegate void MouseEventDelegate(MouseHookEventArgs e);

        public event MouseEventDelegate MouseDownEvent;

        public event MouseEventDelegate MouseUpEvent;

        public event MouseEventDelegate MouseMoveEvent;

        public event MouseEventDelegate MouseWheelEvent;

        public delegate void KeyUpEventDelegate(MouseHookEventArgs e);

        private HookProc _hookproc;
        private IntPtr _hhook;

        public void StartHook()
        {
            _hookproc = new HookProc(HookCallback);
            _hhook = SetWindowsHookEx((int)HookType.WH_MOUSE_LL, Marshal.GetFunctionPointerForDelegate(_hookproc), GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
            if (_hhook == null || _hhook == IntPtr.Zero)
            {
                Win32Exception LastError = new Win32Exception(Marshal.GetLastWin32Error());
            }
        }

        public void StopHook()
        {
            if (_hhook != IntPtr.Zero)
            {
                UnhookWindowsHookEx(_hhook);
            }
        }

        private int HookCallback(int code, IntPtr wParam, IntPtr lParam)
        {
            int result = 0;
            MouseHookEventArgs args = null;
            try
            {
                if (code >= 0)
                {
                    MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
                    var button = MouseButtons.None;
                    if (wParam.ToInt32() == (int)MouseMessages.WM_LBUTTONDOWN || wParam.ToInt32() == (int)MouseMessages.WM_LBUTTONUP)
                    {
                        button = MouseButtons.Left;
                    }
                    if (wParam.ToInt32() == (int)MouseMessages.WM_RBUTTONDOWN || wParam.ToInt32() == (int)MouseMessages.WM_RBUTTONUP)
                    {
                        button = MouseButtons.Right;
                    }
                    args = new MouseHookEventArgs(button, hookStruct.pt.x, hookStruct.pt.y, hookStruct.mouseData, hookStruct.flags, hookStruct.time, hookStruct.dwExtraInfo);
                    if (wParam.ToInt32() == (int)MouseMessages.WM_LBUTTONDOWN || wParam.ToInt32() == (int)MouseMessages.WM_RBUTTONDOWN)
                    {
                        MouseDownEvent?.Invoke(args);
                    }
                    if (wParam.ToInt32() == (int)MouseMessages.WM_LBUTTONUP || wParam.ToInt32() == (int)MouseMessages.WM_RBUTTONUP)
                    {
                        MouseUpEvent?.Invoke(args);
                    }
                    if (wParam.ToInt32() == (int)MouseMessages.WM_MOUSEMOVE)
                    {
                        MouseMoveEvent?.Invoke(args);
                    }
                    if (wParam.ToInt32() == (int)MouseMessages.WM_MOUSEWHEEL)
                    {
                        MouseWheelEvent?.Invoke(args);
                    }
                }
            }
            finally
            {
                result = CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
            }

            if (args != null && args.Cancel)
            {
                return 1;
            }
            else
            {
                return result;
            }
        }
    }

    internal class MouseHookEventArgs : CancelEventArgs
    {
        public MouseButtons Button { get; private set; }
        public int X { get; private set; }
        public int Y { get; private set; }
        public int Delta { get; private set; }
        public IntPtr ExtraInfo { get; private set; }

        internal MouseHookEventArgs(MouseButtons button, int x, int y, int mouseData, UInt32 flags, UInt32 time, IntPtr dwExtraInfo)
        {
            Button = button;
            X = x;
            Y = y;
            Delta = mouseData;
            ExtraInfo = dwExtraInfo;
        }

        public override string ToString()
        {
            return string.Format("Button={0}; X={1}; Y={2}; Delta={3}", new object[] { Button, X, Y, Delta });
        }
    }
    internal class KeyboardHookHelper
    {
        #region PInvoke

        private enum HookType : int
        {
            WH_JOURNALRECORD = 0,
            WH_JOURNALPLAYBACK = 1,
            WH_KEYBOARD = 2,
            WH_GETMESSAGE = 3,
            WH_CALLWNDPROC = 4,
            WH_CBT = 5,
            WH_SYSMSGFILTER = 6,
            WH_MOUSE = 7,
            WH_HARDWARE = 8,
            WH_DEBUG = 9,
            WH_SHELL = 10,
            WH_FOREGROUNDIDLE = 11,
            WH_CALLWNDPROCRET = 12,
            WH_KEYBOARD_LL = 13,
            WH_MOUSE_LL = 14
        }

        private struct KBDLLHOOKSTRUCT
        {
            public UInt32 vkCode;
            public UInt32 scanCode;
            public UInt32 flags;
            public UInt32 time;
            public IntPtr extraInfo;
        }

        private enum KeyboardMessages
        {
            WM_KEYDOWN = 0x100,
            WM_KEYUP = 0x101,
            WM_SYSKEYDOWN = 0x0104,
            WM_SYSKEYUP = 0x105
        }

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        [DllImport("user32.dll")]
        private static extern IntPtr SetWindowsHookEx(int idHook, IntPtr lpfn, IntPtr hMod, int dwThreadId);

        [DllImport("user32.dll")]
        private static extern int UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll")]
        private static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        private delegate int LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

        #endregion PInvoke

        public delegate void KeyboardEventDelegate(KeyboardHookEventArgs e);

        public event KeyboardEventDelegate KeyDownEvent;

        public event KeyboardEventDelegate KeyUpEvent;

        private LowLevelKeyboardProc _hookproc;
        private IntPtr _hhook;

        public void StartHook()
        {
            _hookproc = new LowLevelKeyboardProc(HookCallback);
            _hhook = SetWindowsHookEx((int)HookType.WH_KEYBOARD_LL, Marshal.GetFunctionPointerForDelegate(_hookproc), GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
            if (_hhook == null || _hhook == IntPtr.Zero)
            {
                Win32Exception LastError = new Win32Exception(Marshal.GetLastWin32Error());
            }
        }

        public void StopHook()
        {
            if (_hhook != IntPtr.Zero)
            {
                UnhookWindowsHookEx(_hhook);
            }
        }

        private int HookCallback(int code, IntPtr wParam, IntPtr lParam)
        {
            int result = 0;
            KeyboardHookEventArgs args = null;
            try
            {
                if (code >= 0)
                {
                    KBDLLHOOKSTRUCT hookStruct = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
                    args = new KeyboardHookEventArgs(hookStruct.vkCode, hookStruct.scanCode, hookStruct.flags, hookStruct.time, hookStruct.extraInfo);
                    if (wParam.ToInt32() == (int)KeyboardMessages.WM_SYSKEYDOWN || wParam.ToInt32() == (int)KeyboardMessages.WM_KEYDOWN)
                    {
                        KeyDownEvent?.Invoke(args);
                    }
                    if (wParam.ToInt32() == (int)KeyboardMessages.WM_SYSKEYUP || wParam.ToInt32() == (int)KeyboardMessages.WM_KEYUP)
                    {
                        KeyUpEvent?.Invoke(args);
                    }
                }
            }
            finally
            {
                result = CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
            }

            if (args != null && args.Cancel)
            {
                return 1;
            }
            else
            {
                return result;
            }
        }
    }

    internal class KeyboardHookEventArgs : CancelEventArgs
    {
        #region PInvoke

        [DllImport("user32.dll")]
        private static extern short GetKeyState(VirtualKeyStates nVirtKey);

        private enum VirtualKeyStates : int
        {
            VK_LWIN = 0x5B,
            VK_RWIN = 0x5C,
            VK_LSHIFT = 0xA0,
            VK_RSHIFT = 0xA1,
            VK_LCONTROL = 0xA2,
            VK_RCONTROL = 0xA3,
            VK_LALT = 0xA4, //aka VK_LMENU
            VK_RALT = 0xA5, //aka VK_RMENU
        }

        private const int KEY_PRESSED = 0x8000;

        #endregion PInvoke

        public Keys Key { get; private set; }
        public IntPtr ExtraInfo { get; private set; }

        public bool isAltPressed { get { return isLAltPressed || isRAltPressed; } }
        public bool isLAltPressed { get; private set; }
        public bool isRAltPressed { get; private set; }
        public bool isCtrlPressed { get { return isLCtrlPressed || isRCtrlPressed; } }
        public bool isLCtrlPressed { get; private set; }
        public bool isRCtrlPressed { get; private set; }
        public bool isShiftPressed { get { return isLShiftPressed || isRShiftPressed; } }
        public bool isLShiftPressed { get; private set; }
        public bool isRShiftPressed { get; private set; }
        public bool isWinPressed { get { return isLWinPressed || isRWinPressed; } }
        public bool isLWinPressed { get; private set; }
        public bool isRWinPressed { get; private set; }

        internal KeyboardHookEventArgs(UInt32 vkCode, UInt32 scanCode, UInt32 flags, UInt32 time, IntPtr dwExtraInfo)
        {
            Key = (Keys)vkCode;
            ExtraInfo = dwExtraInfo;

            //Control.ModifierKeys doesn't capture alt/win, and doesn't have r/l granularity
            this.isLAltPressed = Convert.ToBoolean(GetKeyState(VirtualKeyStates.VK_LALT) & KEY_PRESSED) || this.Key == Keys.LMenu;
            this.isRAltPressed = Convert.ToBoolean(GetKeyState(VirtualKeyStates.VK_RALT) & KEY_PRESSED) || this.Key == Keys.RMenu;

            this.isLCtrlPressed = Convert.ToBoolean(GetKeyState(VirtualKeyStates.VK_LCONTROL) & KEY_PRESSED) || this.Key == Keys.LControlKey;
            this.isRCtrlPressed = Convert.ToBoolean(GetKeyState(VirtualKeyStates.VK_RCONTROL) & KEY_PRESSED) || this.Key == Keys.RControlKey;

            this.isLShiftPressed = Convert.ToBoolean(GetKeyState(VirtualKeyStates.VK_LSHIFT) & KEY_PRESSED) || this.Key == Keys.LShiftKey;
            this.isRShiftPressed = Convert.ToBoolean(GetKeyState(VirtualKeyStates.VK_RSHIFT) & KEY_PRESSED) || this.Key == Keys.RShiftKey;

            this.isLWinPressed = Convert.ToBoolean(GetKeyState(VirtualKeyStates.VK_LWIN) & KEY_PRESSED) || this.Key == Keys.LWin;
            this.isRWinPressed = Convert.ToBoolean(GetKeyState(VirtualKeyStates.VK_RWIN) & KEY_PRESSED) || this.Key == Keys.RWin;
            if (this.Key == Keys.LMenu || this.Key == Keys.RMenu)
            {
                this.Key = Keys.Menu;
            }
            if (this.Key == Keys.LControlKey || this.Key == Keys.RControlKey)
            {
                this.Key = Keys.ControlKey;
            }
            if (this.Key == Keys.LShiftKey || this.Key == Keys.RShiftKey)
            {
                this.Key = Keys.ShiftKey;
            }
        }

        public override string ToString()
        {
            return string.Format("Key={0}; Win={1}; Alt={2}; Ctrl={3}; Shift={4}", new object[] { Key, isWinPressed, isAltPressed, isCtrlPressed, isShiftPressed });
        }
    }

以上是关于csharp 全局键盘鼠标钩子的主要内容,如果未能解决你的问题,请参考以下文章

钩子编程(HOOK) 屏蔽全部按键鼠标及系统功能键

C++怎样简单实现全局钩子或者键盘监控

我在VC++中写了键盘勾子程序,但当我把鼠标点到任务栏后,钩子程序就失去效果。请问啥原因呢?有啥解决

delphi 键盘全局钩子

钩子注入的原理机制

全局键盘钩子