• 全局键盘钩子实现


    #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者不同的地方是是在非模式窗口下方法一无法捕捉到按键消息
  • 相关阅读:
    MongoDB 创建数据库
    MongoDB
    MongoDB 概念解析
    window平台安装 MongoDB(二)
    MongoDB入门学习(1)
    解决DevExpress10.2.4版本在VS2012工具箱控件不显示的问题
    Aspose.Word 输出表格后空格字符丢失的解决方法
    ArcEngine 创建空间参考设置默认域
    SPATIALITE 各版本数据库差异
    WGS84投影的WKID说明
  • 原文地址:https://www.cnblogs.com/keepsilence/p/2688288.html
Copyright © 2020-2023  润新知