相关参考文档:
http://www.cnblogs.com/michaelxu/archive/2006/09/22/511557.html
http://www.cnblogs.com/Johness/archive/2012/12/28/2837977.html
http://support.microsoft.com/default.aspx?scid=kb;en-us;318804
使用Low-level的钩子可以实现全局捕获相关动作,微软提供的有WH_MOUSE_LL和WH_KEYBOARD_LL这两个Low-level的钩子来实现对全局鼠标和全局键盘的捕获,配合SetWindowsHookEx,就可以将具体的钩子挂在到全局。
网上很多例子中,对于鼠标双击的动作捕获,都是认为可以捕获WM_LBUTTONDBLCLK这个消息,通过该消息来设定是否为双击,但实际挂在钩子后,Windows并不会直接捕获到WM_LBUTTONDBLCLK这个消息,而是两次WM_LBUTTONDOWN消息,因此,如果要实现双击的捕获,可考虑计算两次点击的时间间隔,和系统的双击时间间隔进行比较,从而判定是否为双击。
代码中引入系统的双击时间
[DllImport("user32.dll")] public static extern int GetDoubleClickTime();
设定一个静态变量存储上一次点击的时间,以及一个静态变量存储具体的点击数
static DateTime lastClickTime;
static clickCount;
鼠标钩子回调函数中通过计算两次点击的时间间隔来区分双击与否,合理利用clickCount来避免三次快速点击时候被识别为两次双击
private int CallBackMouseHookProc(int nCode, int wParam, IntPtr lParam) { if (nCode < 0) { CallNextHookEx(mshHook, nCode, wParam, lParam); } MOUSEHOOKSTRUCT mouseHookStruct = (MOUSEHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MOUSEHOOKSTRUCT)); MouseButtons mouseButton = MouseButtons.None; switch (wParam) { case (int)MsgType.WM_LBUTTONDOWN: mouseButton = MouseButtons.Left; break; case (int)MsgType.WM_RBUTTONDOWN: mouseButton = MouseButtons.Right; break; case (int)MsgType.WM_MOUSEMOVE: clickCount = 0; break; default: break; } if (mouseButton == MouseButtons.Left) { System.TimeSpan deltaMs = DateTime.Now - lastClickTime; lastClickTime = DateTime.Now; if (deltaMs.TotalMilliseconds <= GetDoubleClickTime()) { clickCount++; } else { clickCount = 1; } if (clickCount == 2) { MouseEventArgs e = new MouseEventArgs( mouseButton, clickCount, mouseHookStruct.pt.x, mouseHookStruct.pt.y, 0); clickCount = 0; OnMouseDoubleClick(this, e); } } return CallNextHookEx(mshHook, nCode, wParam, lParam); }
更精确的还需要当鼠标移动时候则取消上一次的计算,不计入双击点击中