2013-07-01 64 views
0
public class InputHook 
{ 
    #region Windows function imports 

    [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); 

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)] 
    public static extern IntPtr GetModuleHandle(string lpModuleName); 

    [DllImport("user32.dll")] 
    internal static extern IntPtr GetActiveWindow(); 
    [DllImport("user32.dll", EntryPoint = "TrackMouseEvent", CallingConvention = CallingConvention.StdCall)] 
    private extern static bool Win32TrackMouseEvent(ref TRACKMOUSEEVENT tme); 

    private delegate int HookProc(int nCode, int wParam, IntPtr lParam); 

    #endregion 

    #region Windows constants 

    // ReSharper disable InconsistentNaming 
    private const int WH_MOUSE_LL = 14; 
    private const int WH_MOUSE = 7; 
    private const int WH_GETMESSAGE = 3; 
    private const int WM_MOUSEMOVE = 0x200; 
    private const int WM_MOUSEHOVER = 0x2A1; 
    private const int GWL_WNDPROC = -4; 
    private const int WM_IME_SETCONTEXT = 0x281; 
    private const int WM_INPUTLANGCHANGE = 0x51; 
    private const int WM_GETDLGCODE = 0x87; 
    private const int WM_IME_COMPOSITION = 0x10F; 
    private const int DLGC_WANTALLKEYS = 4; 

    private const int TID_POLLMOUSE = 100; 
    private const int MOUSE_POLL_DELAY = 500; 
    private const int WM_TIMER = 0x0113; 
    private const int WM_MOUSEENTER = 0x41E; 
    private const int WM_MOUSELEAVE = 0x41F; 
    // ReSharper restore InconsistentNaming 

    #endregion 

    #region Events 

    /// <summary>Event raised when the mouse has hovered in the same location for a short period of time.</summary> 
    public event MouseEventHandler MouseHover; 

    #endregion 

    public InputHook(bool installMouseHook = true) 
    { 
     Start(installMouseHook); 
    } 

    ~InputHook() 
    { 
     Stop(true, false); 
    } 

    private int m_hMouseHook; 

    private static HookProc s_mouseHookProcedure; 

    private void Start(bool installMouseHook) 
    { 
     // install Mouse hook only if it is not installed and must be installed 
     if(m_hMouseHook == 0 && installMouseHook) 
     { 
      s_mouseHookProcedure = MouseHookProc; 
      m_hMouseHook = SetWindowsHookEx(WH_MOUSE, s_mouseHookProcedure, (IntPtr)0, AppDomain.GetCurrentThreadId()); 

      if(m_hMouseHook == 0) 
      { 
       var errorCode = Marshal.GetLastWin32Error(); 
       Stop(true, false); 
       throw new Win32Exception(errorCode); 
      } 
     } 
    } 

    public void Stop(bool uninstallMouseHook = true, bool throwExceptions = true) 
    { 
     if(m_hMouseHook != 0 && uninstallMouseHook) 
     { 
      var retMouse = UnhookWindowsHookEx(m_hMouseHook); 
      m_hMouseHook = 0; 
      if(retMouse == 0 && throwExceptions) 
      { 
       var errorCode = Marshal.GetLastWin32Error(); 
       throw new Win32Exception(errorCode); 
      } 
     } 
    } 

    #region Mouse Input 

    private int MouseHookProc(int nCode, int wParam, IntPtr lParam) 
    { 
     if((nCode >= 0) && (MouseHover != null)) 
     { 
      short x, y; 
      MouseLocationFromLParam(lParam.ToInt32(), out x, out y); 

      switch(wParam) 
      { 
       case WM_MOUSEMOVE: 
        TRACKMOUSEEVENT tme = new TRACKMOUSEEVENT(); 
        tme.cbSize = Marshal.SizeOf(tme); 
        tme.dwFlags = TMEFlags.TME_HOVER; 
        tme.dwHoverTime = 100; 
        tme.hwndTrack = lParam; 
        Win32TrackMouseEvent(ref tme); 
        break; 
       case WM_MOUSEHOVER: 
        if(MouseHover != null) 
         MouseHover(null, new MouseEventArgs(MouseButtons.None, 0, x, y, 0)); 
        break; 
      } 
     } 

     return CallNextHookEx(m_hMouseHook, nCode, wParam, lParam); 
    } 

    #endregion 

    #region Mouse Message Helpers 

    private static void MouseLocationFromLParam(int lParam, out short x, out short y) 
    { 
     // Cast to signed shorts to get sign extension on negative coordinates (of course this would only be possible if mouse capture was enabled). 
     x = (short)(lParam & 0xFFFF); 
     y = (short)(lParam >> 16); 
    } 

    #endregion 

    [StructLayout(LayoutKind.Sequential)] 
    private struct TRACKMOUSEEVENT 
    { 
     internal int cbSize; 
     internal TMEFlags dwFlags; 
     internal IntPtr hwndTrack; 
     internal int dwHoverTime; 
    } 

    [Flags] 
    private enum TMEFlags 
    { 
     TME_HOVER = 0x00000001, 
     TME_LEAVE = 0x00000002, 
     TME_NONCLIENT = 0x00000010, 
     TME_QUERY = unchecked((int)0x40000000), 
     TME_CANCEL = unchecked((int)0x80000000) 
    } 
} 

我正在使用此类作为mousehover事件。但不知何故,这不起作用,它适用于移动和其他鼠标事件,但对于鼠标悬停,我无法使用它。尝试了一切在线,但没有。我在哪里错了?WM_MOUSEHOVER不适用于全局钩子

谢谢你帮助我。

回答

0

WM_MOUSEHOVER是不是一个真正的鼠标消息,它是由当你调用既定的内部定时器PROC产生TrackMouseEvent(即检查如果鼠标移动,如果仍然在给定的时间将消息发送到窗口)。因此一个WH_MOUSE挂钩不会陷入它。

你或许可以用WH_CALLWNDPROCWH_GETMESSAGE钩来捕捉它。

+0

我会尝试并让你知道。感谢您为我澄清一些事情。 –

+0

感谢您帮助我解决这个问题。你是对的。辉煌:)现在我想知道有没有办法增加徘徊的计时器?我测试过它,速度很快,如果我可以将它改为500毫秒或1秒,那就太棒了!再次感谢宝贵的帮助。 –

+0

无视这个,我可以设置它并增加时间。 –