问题描述
我正在 WPF c# 中创建一个应用程序,它需要能够分别检测鼠标点击和点击事件。为了做到这一点,我使用了我在网上找到的 Global Mouse Hook 的代码。代码的唯一问题是它使用 EventArgs 作为 EventHandler,因此每次我发送 MouseUp 和 MouseDown 时它都传递相同的函数。为了解决这个问题,我使用了 MouseButtonEventArgs 构造函数。我现在遇到的问题是构造函数需要 3 个参数:MouseDevice、timestamp 和 MouseButton,构造函数才能实际工作。我已经弄清楚时间戳和鼠标按钮,但我不知道为 MouseDevice 放什么。我在这里放什么来使构造函数工作?这是我的低级鼠标钩类代码。
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Input;
namespace Keystrokedisplay
{
public static class MouseHook
{
public static event MouseEventHandler MouseAction = delegate { };
public static void Start()
{
_hookID = SetHook(_proc);
}
public static void stop()
{
UnhookWindowsHookEx(_hookID);
}
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetwindowsHookEx(WH_MOUSE_LL,proc,GetModuleHandle(curModule.ModuleName),0);
}
}
private delegate IntPtr LowLevelMouseProc(int nCode,IntPtr wParam,IntPtr lParam);
private static IntPtr HookCallback(int nCode,IntPtr lParam)
{
if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
{
MsllHOOKSTRUCT hookStruct = (MsllHOOKSTRUCT)Marshal.PtrToStructure(lParam,typeof(MsllHOOKSTRUCT));
MouseAction(null,new MouseButtonEventArgs(mouse: ????????,timestamp: 0,button: MouseButton.Left));
}
if (nCode >= 0 && MouseMessages.WM_LBUTTONUP == (MouseMessages)wParam)
{
MsllHOOKSTRUCT hookStruct = (MsllHOOKSTRUCT)Marshal.PtrToStructure(lParam,button: MouseButton.Left));
}
return CallNextHookEx(_hookID,nCode,wParam,lParam);
}
public const int WH_MOUSE_LL = 14;
public enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,WM_LBUTTONUP = 0x0202,WM_RBUTTONDOWN = 0x0204,WM_RBUTTONUP = 0x0205
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MsllHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
[DllImport("user32.dll",CharSet = CharSet.Auto,SetLastError = true)]
private static extern IntPtr SetwindowsHookEx(int idHook,LowLevelMouseProc lpfn,IntPtr hMod,uint dwThreadId);
[DllImport("user32.dll",SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll",SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk,int nCode,IntPtr lParam);
[DllImport("kernel32.dll",SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
}
我该如何解决这个问题?另外,我对 c# 还很陌生,所以我可能需要一些额外的帮助来理解您的答案。
解决方法
我看不出有任何理由使用 MouseEventHandler
。
您想分别检测鼠标点击和点击事件,因此您可以为鼠标点击和点击创建两个委托,并传递自己的事件参数。您只对按下了哪个鼠标按钮感兴趣。
public delegate void MouseUpEventHandler(object sender,MyMouseEventArgs e);
public delegate void MouseDownEventHandler(object sender,MyMouseEventArgs e);
public class MyMouseEventArgs : EventArgs
{
public MouseButton MouseButton { get; }
public MyMouseEventArgs(MouseButton mouseButton)
{
MouseButton = mouseButton;
}
}
然后替换
public static event MouseEventHandler MouseAction = delegate { };
与
public static event MouseUpEventHandler MouseUpAction = delegate { };
public static event MouseDownEventHandler MouseDownAction = delegate { };
在 HookCallback
中调用 MouseDownAction
或 MouseUpAction
。
private static IntPtr HookCallback(int nCode,IntPtr wParam,IntPtr lParam)
{
if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam,typeof(MSLLHOOKSTRUCT));
MouseDownAction(null,new MyMouseEventArgs(MouseButton.Left));
}
if (nCode >= 0 && MouseMessages.WM_LBUTTONUP == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam,typeof(MSLLHOOKSTRUCT));
MouseUpAction(null,new MyMouseEventArgs(MouseButton.Left));
}
return CallNextHookEx(_hookID,nCode,wParam,lParam);
}