2013-07-01 96 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

無視這個,我可以設置它並增加時間。 –