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)
}
}
我正在使用此类进行鼠标悬停事件。但不知怎的,这不起作用,它适用于移动和其他鼠标事件,但对于鼠标悬停我无论如何都无法使用它。尝试了所有在线但没有的东西。我在哪里错了?
感谢您帮助我。
答案 0 :(得分:0)
MouseHookProc()
(lParam
)的最后一个参数实际上不是HWND
,而是指向MOUSEHOOKSTRUCT
的指针,因此您将无效的有效内容传递给tme.hwndTrack
。
查看相关的MSDN页面:
不确定它是否是那里唯一的错误。
答案 1 :(得分:0)
WM_MOUSEHOVER
不是真正的鼠标消息,它是由内部定时器proc生成的,当你调用TrackMouseEvent
时(它检查鼠标是否移动并向窗口发送消息,如果仍然存在)仍然在给定的时间)。因此,WH_MOUSE
钩子不会捕获它。
您可以使用WH_CALLWNDPROC
或WH_GETMESSAGE
挂钩来抓住它。