如何在C#中使用全局鼠标、键盘Hook

来源:互联网 发布:淘宝自动点内容回复 编辑:程序博客网 时间:2024/05/16 17:14

 今天,有个同事问我,怎样在C#中使用全局钩子?以前写的全局钩子都是用unmanaged C或C++写个DLL来实现,可大家都知道,C#是基于.Net Framework的,是managed,怎么实现全局钩子呢?于是开始到网上搜索,好不容易找到一篇,318804 - HOW TO: Set a Windows Hook in Visual C# .NET,里面详细的说明了如何使用鼠标钩子捕获鼠标的移动等,可是,它只能在Application里起作用,出了Application就没用了,就是说它还是没有实现全局钩子,而且文章结尾处说:“Global Hooks are not supported in the .NET Framework...”,这可怎么办呢?

  别担心,办法总是有的,经过一番摸索以后,发现WH_KEYBORAD_LL和WH_MOUSE_LL这两个low-level的hook可以被安装成全局的,这就好办了,我们不妨用这两个low-level的hook替换掉WH_KEYBORAD和WH_MOUSE,于是开始测试。结果成功了,在C#里实现了全局钩子。

  我们来看一下主要代码段。

  首先倒入所需要的windows函数,主要有三个,SetWindowsHookEX用来安装钩子,UnhookWindowsHookEX用来卸载钩子以及CallNextHookEX用来将hook信息传递到链表中下一个hook处理过程。

[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.dll", CharSet = CharSet.Auto,
             CallingConvention 
= CallingConvention.StdCall)]
        
private static extern int CallNextHookEx(
            
int idHook,
            
int nCode,
            
int wParam,
            IntPtr lParam);

  下面是有关这两个low-level hook在Winuser.h中的定义:

/// <summary>
        
/// Windows NT/2000/XP: Installs a hook procedure that monitors low-level mouse input events.
        
/// </summary>

        private const int WH_MOUSE_LL       = 14;
        
/// <summary>
        
/// Windows NT/2000/XP: Installs a hook procedure that monitors low-level keyboard  input events.
        
/// </summary>

        private const int WH_KEYBOARD_LL    = 13;

  在安装全局钩子的时候,我们就要做替换了,将WH_MOUSE和WH_KEYBORAD分别换成WH_MOUSE_LL和WH_KEYBORAD_LL:

//install hook
                hMouseHook = SetWindowsHookEx(
                    WH_MOUSE_LL, 
//原来是WH_MOUSE
                    MouseHookProcedure,
                    Marshal.GetHINSTANCE(
                        Assembly.GetExecutingAssembly().GetModules()[
0]),
                    
0);

//install hook
                hKeyboardHook = SetWindowsHookEx(
                    WH_KEYBOARD_LL, 
//原来是WH_KEYBORAD
                    KeyboardHookProcedure,
                    Marshal.GetHINSTANCE(
                    Assembly.GetExecutingAssembly().GetModules()[
0]),
                    
0);
 
  这样替换了之后,我们就可以实现全局钩子了,而且,不需要写DLL。看一下程序运行情况:



  下面是关于鼠标和键盘的两个Callback函数:

private int MouseHookProc(int nCode, int wParam, IntPtr lParam)
        
{
            
// if ok and someone listens to our events
            if ((nCode >= 0&& (OnMouseActivity != null))
            
{
                
//Marshall the data from callback.
                MouseLLHookStruct mouseHookStruct = (MouseLLHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLLHookStruct));

                
//detect button clicked
                MouseButtons button = MouseButtons.None;
                
short mouseDelta = 0;
                
switch (wParam)
                
{
                    
case WM_LBUTTONDOWN:
                        
//case WM_LBUTTONUP: 
                        
//case WM_LBUTTONDBLCLK: 
                        button = MouseButtons.Left;
                        
break;
                    
case WM_RBUTTONDOWN:
                        
//case WM_RBUTTONUP: 
                        
//case WM_RBUTTONDBLCLK: 
                        button = MouseButtons.Right;
                        
break;
                    
case WM_MOUSEWHEEL:
                        
//If the message is WM_MOUSEWHEEL, the high-order word of mouseData member is the wheel delta. 
                        
//One wheel click is defined as WHEEL_DELTA, which is 120. 
                        
//(value >> 16) & 0xffff; retrieves the high-order word from the given 32-bit value
                        mouseDelta = (short)((mouseHookStruct.mouseData >> 16& 0xffff);
                        
//TODO: X BUTTONS (I havent them so was unable to test)
                        
//If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, 
                        
//or WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was pressed or released, 
                        
//and the low-order word is reserved. This value can be one or more of the following values. 
                        
//Otherwise, mouseData is not used. 
                        break;
                }


                
//double clicks
                int clickCount = 0;
                
if (button != MouseButtons.None)
                    
if (wParam == WM_LBUTTONDBLCLK || wParam == WM_RBUTTONDBLCLK) clickCount = 2;
                    
else clickCount = 1;

                
//generate event 
                 MouseEventArgs e = new MouseEventArgs(
                                                    button,
                                                    clickCount,
                                                    mouseHookStruct.pt.x,
                                                    mouseHookStruct.pt.y,
                                                    mouseDelta);
                
//raise it
                OnMouseActivity(this, e);
            }

            
//call next hook
            return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
        }


private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
        
{
            
//indicates if any of underlaing events set e.Handled flag
            bool handled = false;
            
//it was ok and someone listens to events
            if ((nCode >= 0&& (KeyDown != null || KeyUp != null || KeyPress != null))
            
{
                
//read structure KeyboardHookStruct at lParam
                KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
                
//raise KeyDown
                if (KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
                
{
                    Keys keyData 
= (Keys)MyKeyboardHookStruct.vkCode;
                    KeyEventArgs e 
= new KeyEventArgs(keyData);
                    KeyDown(
this, e);
                    handled 
= handled || e.Handled;
                }


                
// raise KeyPress
                if (KeyPress != null && wParam == WM_KEYDOWN)
                
{
                    
bool isDownShift = ((GetKeyState(VK_SHIFT) & 0x80== 0x80 ? true : false);
                    
bool isDownCapslock = (GetKeyState(VK_CAPITAL) != 0 ? true : false);

                    
byte[] keyState = new byte[256];
                    GetKeyboardState(keyState);
                    
byte[] inBuffer = new byte[2];
                    
if (ToAscii(MyKeyboardHookStruct.vkCode,
                              MyKeyboardHookStruct.scanCode,
                              keyState,
                              inBuffer,
                              MyKeyboardHookStruct.flags) 
== 1)
                    
{
                        
char key = (char)inBuffer[0];
                        
if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key);
                        KeyPressEventArgs e 
= new KeyPressEventArgs(key);
                        KeyPress(
this, e);
                        handled 
= handled || e.Handled;
                    }

                }


                
// raise KeyUp
                if (KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
                
{
                    Keys keyData 
= (Keys)MyKeyboardHookStruct.vkCode;
                    KeyEventArgs e 
= new KeyEventArgs(keyData);
                    KeyUp(
this, e);
                    handled 
= handled || e.Handled;
                }


            }


            
//if event handled in application do not handoff to other listeners
            if (handled)
                
return 1;
            
else
                
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
        }

  参考资料:MSDN
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 总是感觉睡不够好困怎么办 两岁宝宝说有鬼怎么办 阳台改成了卧室晒衣服怎么办 室外墙角边墙泥受潮脱落怎么办 新房装修墙体发霉了怎么办 宝宝吃多了发烧怎么办 宝宝睡觉不爱盖被子怎么办 1岁宝宝不盖被子怎么办 2岁宝宝不盖被子怎么办 买的芬琳漆不够刷的怎么办 1.3米宽厨房门怎么办 墙面漆颜色刷深了怎么办 地板上沾了墙漆怎么办 孩子连发高烧8天了怎么办 孩子对数字不敏感怎么办 三岁宝宝不爱学习怎么办 5岁还不认识数字怎么办 小孩上中班还不认识数字怎么办 中班小孩数字都不认识怎么办 中班小孩记不住数字怎么办 中班小孩不肯练数字描红怎么办 2个月吃母乳婴儿缺钙怎么办 月经期接吻水多怎么办 4岁宝宝晚上尿多怎么办 2岁宝宝晚上尿多怎么办 3岁宝宝晚上尿多怎么办 宝宝拉肚子拉绿色的屎怎么办 婴儿吃奶粉大便干燥怎么办 母乳宝宝不拉大便怎么办 我儿子8岁拉肚子怎么办 1岁宝宝经常便秘怎么办 两个月宝宝拉水怎么办 宝宝吃奶粉上火便秘怎么办 20多天的宝宝便秘怎么办 宝宝五十天消化不良不拉屎怎么办 一周七个月宝宝消化不良拉屎怎么办 孩子总是消化不良拉屎不成型怎么办 一岁宝宝长牙慢怎么办 一岁宝宝不喝水怎么办 七个月的宝宝咳嗽怎么办 怀孕七个月感冒了怎么办