zoukankan      html  css  js  c++  java
  • 全局键盘钩子实现

    #region 全局钩子实现方法1
    //窗体变量
    Hotkey hotkey;
    int UHotkey;
    #region 全局键盘
    hotkey = new Hotkey(this.Handle);
    hotkey.RegisterHotkey(System.Windows.Forms.Keys.F1, Hotkey.KeyFlags.MOD_CONTROL);
    //定义快键(F1)  
    UHotkey = hotkey.RegisterHotkey(System.Windows.Forms.Keys.F1);
    hotkey.OnHotkey += new HotkeyEventHandler(OnHotkey);
    #endregion

    //添加快键调用函数   
    public void OnHotkey(int HotkeyID)
    {
       if (HotkeyID == UHotkey)
       {
           //do something      
       }
              
    }

    #endregion
      public delegate void HotkeyEventHandler(int HotKeyID);

        public class Hotkey : System.Windows.Forms.IMessageFilter
        {
            public System.Collections.Hashtable keyIDs = new System.Collections.Hashtable();
            IntPtr hWnd;

            public event HotkeyEventHandler OnHotkey;

            public enum KeyFlags
            {
                MOD_ALT = 0x1,
                MOD_CONTROL = 0x2,
                MOD_SHIFT = 0x4,
                MOD_WIN = 0x8
            }
            [DllImport("user32.dll")]
            public static extern UInt32 RegisterHotKey(IntPtr hWnd, UInt32 id, UInt32 fsModifiers, UInt32 vk);

            [DllImport("user32.dll")]
            public static extern UInt32 UnregisterHotKey(IntPtr hWnd, UInt32 id);

            [DllImport("kernel32.dll")]
            public static extern UInt32 GlobalAddAtom(String lpString);

            [DllImport("kernel32.dll")]
            public static extern UInt32 GlobalDeleteAtom(UInt32 nAtom);

            public Hotkey(IntPtr hWnd)
            {
                this.hWnd = hWnd;
                System.Windows.Forms.Application.AddMessageFilter(this);
            }

            public int RegisterHotkey(System.Windows.Forms.Keys Key, KeyFlags keyflags)
            {
                UInt32 hotkeyid = GlobalAddAtom(System.Guid.NewGuid().ToString());
                RegisterHotKey((IntPtr)hWnd, hotkeyid, (UInt32)keyflags, (UInt32)Key);
                keyIDs.Add(hotkeyid, hotkeyid);
                return (int)hotkeyid;
            }
            public int RegisterHotkey(System.Windows.Forms.Keys Key)
            {
                UInt32 hotkeyid = GlobalAddAtom(System.Guid.NewGuid().ToString());
                RegisterHotKey((IntPtr)hWnd, hotkeyid, (UInt32)0, (UInt32)Key);
                keyIDs.Add(hotkeyid, hotkeyid);
                return (int)hotkeyid;
            }
            public void UnregisterHotkeys()
            {
                System.Windows.Forms.Application.RemoveMessageFilter(this);
                foreach (UInt32 key in keyIDs.Values)
                {
                    UnregisterHotKey(hWnd, key);
                    GlobalDeleteAtom(key);
                }
            }


            public bool PreFilterMessage(ref System.Windows.Forms.Message m)
            {
                if (m.Msg == 0x312)
                {
                    if (OnHotkey != null)
                    {
                        foreach (UInt32 key in keyIDs.Values)
                        {
                            if ((UInt32)m.WParam == key)
                            {
                                OnHotkey((int)m.WParam);
                                return true;
                            }
                        }
                    }
                }
                return false;
            }
          
        }
    #region 方法二

         public class KeyboardHook

        {

            public event KeyEventHandler KeyDownEvent;
            public event KeyPressEventHandler KeyPressEvent;
            public event KeyEventHandler KeyUpEvent;

            public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
            static int hKeyboardHook = 0//声明键盘钩子处理的初始值。
            
    //值在Microsoft SDK的Winuser.h里查询
            public const int WH_KEYBOARD_LL = 13;    
            //线程键盘钩子监听鼠标消息设为2,全局键盘监听鼠标消息设为13。    
            HookProc KeyboardHookProcedure; //声明KeyboardHookProcedure作为HookProc类型。
            
    //键盘结构 
            [StructLayout(LayoutKind.Sequential)]
            public class KeyboardHookStruct
            {
                public int vkCode;    //定一个虚拟键码。该代码必须有一个价值的范围1至254 。 
                public int scanCode; // 指定的硬件扫描码的关键。 
                public int flags;  // 键标志
                public int time; // 指定的时间戳记的这个讯息。
                public int dwExtraInfo; // 指定额外信息相关的信息。
            }

            //使用此功能,安装了一个钩子。
            [DllImport("user32.dll", CharSet = CharSet.Auto,CallingConvention = CallingConvention.StdCall)]
            public static extern int SetWindowsHookEx(int idHook, 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,Int32 wParam, IntPtr lParam);
            // 取得当前线程编号(线程钩子需要用到) 
            [DllImport("kernel32.dll")]
            static extern int GetCurrentThreadId();
            public void Start()
            {
                // 安装键盘钩子
                if (hKeyboardHook == 0)
                {
                    KeyboardHookProcedure = new HookProc(KeyboardHookProc);
                    hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);
                    


                    //如果SetWindowsHookEx失败。
                    if (hKeyboardHook == 0)
                    {
                        Stop();
                        throw new Exception("安装键盘钩子失败");
                    }
                }
            }

            public void Stop()
            {
                bool retKeyboard = true;


                if (hKeyboardHook != 0)
                {
                    retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
                    hKeyboardHook = 0;
                }

                if (!(retKeyboard)) throw new Exception("卸载钩子失败!");
            }



            //ToAscii职能的转换指定的虚拟键码和键盘状态的相应字符或字符。
            [DllImport("user32")]
            public static extern int ToAscii(int uVirtKey, //[in] 指定虚拟关键代码进行翻译。 
                                             int uScanCode, // [in] 指定的硬件扫描码的关键须翻译成英文。高阶位的这个值设定的关键,如果是(不压) 。
                                             byte[] lpbKeyState, // [in] 指针,以256字节数组,包含当前键盘的状态。每个元素(字节)的数组包含状态的一个关键。如果高阶位的字节是一套,关键是下跌(按下)。在低比特,如果设置表明,关键是对切换。在此功能,只有肘位的CAPS LOCK键是相关的。在切换状态的NUM个锁和滚动锁定键被忽略。
                                             byte[] lpwTransKey, // [out] 指针的缓冲区收到翻译字符或字符。 
                                             int fuState); // [in] Specifies whether a menu is active. This parameter must be 1 if a menu is active, or 0 otherwise. 

            
    //获取按键的状态
            [DllImport("user32")]
            public static extern int GetKeyboardState(byte[] pbKeyState);

            private const int WM_KEYDOWN = 0x100;//KEYDOWN 
            private const int WM_KEYUP = 0x101;//KEYUP
            private const int WM_SYSKEYDOWN = 0x104;//SYSKEYDOWN
            private const int WM_SYSKEYUP = 0x105;//SYSKEYUP

            private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
            {
                // 侦听键盘事件
                if ((nCode >= 0) && (KeyDownEvent != null || KeyUpEvent != null || KeyPressEvent != null))
                {
                    KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
                    // raise KeyDown
                    if (KeyDownEvent != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
                    {
                        Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
                        KeyEventArgs e = new KeyEventArgs(keyData);
                        KeyDownEvent(this, e);
                    }

                    //键盘按下
                    if (KeyPressEvent != null && wParam == WM_KEYDOWN)
                    {
                        byte[] keyState = new byte[256];
                        GetKeyboardState(keyState);

                        byte[] inBuffer = new byte[2];
                        if (ToAscii(MyKeyboardHookStruct.vkCode,
                                    MyKeyboardHookStruct.scanCode,
                                    keyState,
                                    inBuffer,
                                    MyKeyboardHookStruct.flags) == 1)
                        {
                            KeyPressEventArgs e = new KeyPressEventArgs((char)inBuffer[0]);
                            KeyPressEvent(this, e);
                        }
                    }

                    // 键盘抬起 
                    if (KeyUpEvent != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
                    {
                        Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
                        KeyEventArgs e = new KeyEventArgs(keyData);
                        KeyUpEvent(this, e);
                    }

                }

                //如果返回1,则结束消息,这个消息到此为止,不再传递。
                
    //如果返回0或调用CallNextHookEx函数则消息出了这个钩子继续往下传递,也就是传给消息真正的接受者 
                return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
            }



            ~KeyboardHook()
            {
                Stop();
            }

        }

    #endregion 

     //************************************ 
    //键盘线程钩子 
    //SetWindowsHookEx( 2,KeyboardHookProcedure, IntPtr.Zero, GetCurrentThreadId());//指定要监听的线程idGetCurrentThreadId(),
    //键盘全局钩子,需要引用空间(using System.Reflection;) 
    //SetWindowsHookEx( 13,MouseHookProcedure,Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),0); 
    // 
    //关于SetWindowsHookEx (int idHook, HookProc lpfn, IntPtr hInstance, int threadId)函数将钩子加入到钩子链表中,说明一下四个参数: 
    //idHook 钩子类型,即确定钩子监听何种消息,上面的代码中设为2,即监听键盘消息并且是线程钩子,如果是全局钩子监听键盘消息应设为13, 
    //线程钩子监听鼠标消息设为7,全局钩子监听鼠标消息设为14。lpfn 钩子子程的地址指针。如果dwThreadId参数为0 或是一个由别的进程创建的 
    //线程的标识,lpfn必须指向DLL中的钩子子程。 除此以外,lpfn可以指向当前进程的一段钩子子程代码。钩子函数的入口地址,当钩子钩到任何 
    //消息后便调用这个函数。hInstance应用程序实例的句柄。标识包含lpfn所指的子程的DLL。如果threadId 标识当前进程创建的一个线程,而且子 
    //程代码位于当前进程,hInstance必须为NULL。可以很简单的设定其为本应用程序的实例句柄。threaded 与安装的钩子子程相关联的线程的标识符。 
    //如果为0,钩子子程与所有的线程关联,即为全局钩子。 
    //************************************ 

    //使用方法

    //声明窗体级变量 

    private KeyboardHook k_hook; 

    //安装钩子

     k_hook = new KeyboardHook();
    k_hook.KeyDownEvent += new KeyEventHandler(hook_KeyDown);

    k_hook.Start(); 

    private void hook_KeyDown(object sender, KeyEventArgs e) 

    {

    //do something 

    2者不同的地方是是在非模式窗口下方法一无法捕捉到按键消息
  • 相关阅读:
    Leetcode Unique Binary Search Trees
    Leetcode Decode Ways
    Leetcode Range Sum Query 2D
    Leetcode Range Sum Query
    Leetcode Swap Nodes in Pairs
    Leetcode Rotate Image
    Leetcode Game of Life
    Leetcode Set Matrix Zeroes
    Leetcode Linked List Cycle II
    CF1321A
  • 原文地址:https://www.cnblogs.com/keepsilence/p/2688288.html
Copyright © 2011-2022 走看看