全局键盘钩子实现

#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者不同的地方是是在非模式窗口下方法一无法捕捉到按键消息

转载于:https://www.cnblogs.com/keepsilence/archive/2012/09/17/2688288.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值