【问题标题】:WM_MOUSEHOVER not working for global hookWM_MOUSEHOVER 不适用于全局挂钩
【发布时间】:2013-07-01 14:19:18
【问题描述】:
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)
    }
}

我将这个类用于鼠标悬停事件。但不知何故,这不起作用,它非常适用于移动和其他鼠标事件,但对于鼠标悬停,我无论如何都无法使用它。尝试了所有在线但没有的东西。我哪里错了?

谢谢你帮我解决这个问题。

【问题讨论】:

    标签: c# winapi interop


    【解决方案1】:

    WM_MOUSEHOVER 不是真正的鼠标消息,它是由调用 TrackMouseEvent 时建立的内部计时器 proc 生成的(检查鼠标是否已移动,如果在给定的情况下保持静止,则向窗口发送消息时间)。因此WH_MOUSE 钩子不会捕获它。

    您可能可以使用 WH_CALLWNDPROCWH_GETMESSAGE 钩子捕获它。

    【讨论】:

    • 我会尝试并告诉你。感谢您为我澄清了一些事情。
    • 感谢您帮助我完成这个。你是对的。太棒了:) 现在我想知道有没有办法增加悬停的计时器?我已经测试过了,它很快,如果我能把它改成 500 毫秒或 1 秒那就太好了!再次感谢您的宝贵帮助。
    • 忽略这个我可以设置它并增加时间。
    【解决方案2】:

    MouseHookProc() (lParam) 的最后一个参数实际上不是HWND,而是指向MOUSEHOOKSTRUCT 的指针,因此您将无效有效传递给tme.hwndTrack

    查看相关的 MSDN 页面:

    不确定这是否是那里唯一的错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多