c#全局鼠标事件以及鼠标事件模拟

Posted LGED

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c#全局鼠标事件以及鼠标事件模拟相关的知识,希望对你有一定的参考价值。

最近在编写Max插件时,其主容器FlowLayoutPanel由于隐藏了滚动条,要实现按住鼠标中键上下拖动的功能,因此尝试了全局鼠标事件、以及鼠标勾子,可惜由于Max不争气?都未能实现,于是代码报废,故将其分享于此。

一、全局鼠标事件,首先构建鼠标事件处理器

public delegate void MouseMovedEvent();
public delegate void MouseMDownEvent();
public delegate void MouseMUpEvent();
public class GlobalMouseHandler : IMessageFilter
{
    private const int WM_MOUSEMOVE = 0x0200;
    private const int WM_MBUTTONDOWN = 0x0207;
    private const int WM_MBUTTONUP = 0x0208;
    public event MouseMovedEvent TheMouseMoved;
    public event MouseMDownEvent TheMouseMDown;
    public event MouseMUpEvent TheMouseMUp;
    #region IMessageFilter Members
    public bool PreFilterMessage(ref Message m)
    {
        if (m.Msg == WM_MOUSEMOVE)
            if (TheMouseMoved != null)
                TheMouseMoved();
        if (m.Msg == WM_MBUTTONDOWN)
            if (TheMouseMDown != null)
                TheMouseMDown();
        if (m.Msg == WM_MBUTTONUP)
            if (TheMouseMUp != null)
                TheMouseMUp();
        // Always allow message to continue to the next filter control
        return false;
    }
    #endregion
}

然后在FlowLayoutPanel的构造函数中添加如下代码(其事件,我这里使用的Lambda表达式)

GlobalMouseHandler gmh = new GlobalMouseHandler();
bool mFlag = false;
int scY = 0;
int msY = 0;
Cursor tempCur = null;

gmh.TheMouseMDown += () =>
{
    mFlag = true;
    scY = VerticalScroll.Value;
    msY = Cursor.Position.Y;
    tempCur = Cursor;
    Cursor = RCurs.Pan;
};
gmh.TheMouseMoved += () =>
{
    if (mFlag)
    {
        int val = scY + msY - Cursor.Position.Y;
        if (val < VerticalScroll.Minimum) val = VerticalScroll.Minimum;
        if (val > VerticalScroll.Maximum) val = VerticalScroll.Maximum;
        VerticalScroll.Value = val;
    }
};
gmh.TheMouseMUp += () =>
{
    mFlag = false;
    Cursor = tempCur;
};
Application.AddMessageFilter(gmh); //Application在Max中无效

 

二、鼠标勾子,此法亦在Max中行不通(后来是通过对FlowLayoutPanel中的各个控件实行事件穿透解决的)

public class MouseHook
{
    private const int WM_MOUSEMOVE = 0x200;
    private const int WM_LBUTTONDOWN = 0x201;
    private const int WM_RBUTTONDOWN = 0x204;
    private const int WM_MBUTTONDOWN = 0x207;
    private const int WM_LBUTTONUP = 0x202;
    private const int WM_RBUTTONUP = 0x205;
    private const int WM_MBUTTONUP = 0x208;
    private const int WM_LBUTTONDBLCLK = 0x203;
    private const int WM_RBUTTONDBLCLK = 0x206;
    private const int WM_MBUTTONDBLCLK = 0x209;

    //全局的事件  
    public event MouseEventHandler OnMouseActivity;

    static int hMouseHook = 0; //鼠标钩子句柄  

    //鼠标常量  
    public const int WH_MOUSE_LL = 14; //mouse hook constant  

    HookProc MouseHookProcedure; //声明鼠标钩子事件类型.  

    //声明一个Point的封送类型  
    [StructLayout(LayoutKind.Sequential)]
    public class POINT
    {
        public int x;
        public int y;
    }

    //声明鼠标钩子的封送结构类型  
    [StructLayout(LayoutKind.Sequential)]
    public class MouseHookStruct
    {
        public POINT pt;
        public int hWnd;
        public int wHitTestCode;
        public int dwExtraInfo;
    }

    //装置钩子的函数  
    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);

    //卸下钩子的函数  
    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    public static extern bool UnhookWindowsHookEx(int idHook);

    //下一个钩挂的函数  
    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);

    public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);

    /// <summary>  
    /// 墨认的构造函数构造当前类的实例.  
    /// </summary>  
    public MouseHook()
    {
    }

    //析构函数.  
    ~MouseHook()
    {
        Stop();
    }

    public void Start()
    {
        //安装鼠标钩子  
        if (hMouseHook == 0)
        {
            //生成一个HookProc的实例.  
            MouseHookProcedure = new HookProc(MouseHookProc);

            hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProcedure, Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0]), 0);

            //如果装置失败停止钩子  
            if (hMouseHook == 0)
            {
                Stop();
                throw new Exception("SetWindowsHookEx failed.");  //Max中会抛出异常
            }
        }
    }

    public void Stop()
    {
        bool retMouse = true;
        if (hMouseHook != 0)
        {
            retMouse = UnhookWindowsHookEx(hMouseHook);
            hMouseHook = 0;
        }

        //如果卸下钩子失败  
        if (!(retMouse)) throw new Exception("UnhookWindowsHookEx failed.");
    }

    private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam)
    {
        //如果正常运行并且用户要监听鼠标的消息  
        if ((nCode >= 0) && (OnMouseActivity != null))
        {
            MouseButtons button = MouseButtons.None;
            int clickCount = 0;

            switch (wParam)
            {
                case WM_MBUTTONDOWN:
                    button = MouseButtons.Middle;
                    clickCount = 1;
                    break;
                case WM_MBUTTONUP:
                    button = MouseButtons.Middle;
                    clickCount = 0;
                    break;
            }

            //从回调函数中得到鼠标的信息  
            MouseHookStruct MyMouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));
            MouseEventArgs e = new MouseEventArgs(button, clickCount, MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y, 0);
            //if(e.X>700)return 1;//如果想要限制鼠标在屏幕中的移动区域可以在此处设置  
            OnMouseActivity(this, e);
        }
        return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
    }
}

调用的方法为:

MouseHook mouse = new MouseHook();
mouse.OnMouseActivity += (s, e) =>
{
    string str = "X:" + e.X + "  Y:" + e.Y + " " + e.Button + " " + e.Clicks;
    this.Text = str;
};
mouse.Start();  

 

三、鼠标事件模拟

//切换到窗口
[DllImport("user32.dll")]
public static extern bool SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
//获取鼠标所在窗口名柄
[DllImport("user32.dll")]
internal static extern IntPtr WindowFromPoint(Point Point);
[DllImport("user32.dll")]
internal static extern bool GetCursorPos(out Point lpPoint);
public static IntPtr GetMouseWindow()
{
    Point p;
    GetCursorPos(out p);
    return WindowFromPoint(p);
}
//获取前台窗口
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();

/// <summary>
/// 模拟鼠标操作
/// </summary>
[DllImport("user32")]
private static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
//移动鼠标 
const int MOUSEEVENTF_MOVE = 0x0001;
//模拟鼠标左键按下 
const int MOUSEEVENTF_LEFTDOWN = 0x0002;
//模拟鼠标左键抬起 
const int MOUSEEVENTF_LEFTUP = 0x0004;
//模拟鼠标右键按下 
const int MOUSEEVENTF_RIGHTDOWN = 0x0008;
//模拟鼠标右键抬起 
const int MOUSEEVENTF_RIGHTUP = 0x0010;
//模拟鼠标中键按下 
const int MOUSEEVENTF_MIDDLEDOWN = 0x0020;
//模拟鼠标中键抬起 
const int MOUSEEVENTF_MIDDLEUP = 0x0040;
//标示是否采用绝对坐标 
const int MOUSEEVENTF_ABSOLUTE = 0x8000;
public static void MouseMove(int x, int y)
{
    mouse_event(MOUSEEVENTF_MOVE, x, y, 0, 0);
}
public static void MouseClick()
{
    mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); //再复制一份则为双击
}
public static void MouseDown()
{
    mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
}
public static void MouseUp()
{
    mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
}

 

以上是关于c#全局鼠标事件以及鼠标事件模拟的主要内容,如果未能解决你的问题,请参考以下文章

C#怎么模拟鼠标点击

使用Robot类模拟鼠标键盘事件

C#当鼠标移动事件时,时间循环停止

全局鼠标事件处理程序

C# winform窗体有个button按钮,我想鼠标点击它不松一直会触发一个事件?是button的哪个事件?

C# 挂钩以获取原始鼠标/键事件