如何在C#中模拟鼠标点击?

155

在 C# 的 winforms 应用中,如何模拟鼠标点击?


5
请提供更多信息以获得有用的答案。 - Andy
40
提示:如果您的标题与问题相同,则标题太长或问题太短。在这种情况下,问题过于简洁,您需要提供更多背景信息,以使回答者有机会给出有用的答案。 - Guffa
7个回答

192

我结合了几个来源,编写了下面的代码,目前正在使用。我还删除了Windows.Forms引用,以便在控制台和WPF应用程序中使用它而不需要额外的引用。

using System;
using System.Runtime.InteropServices;

public class MouseOperations
{
    [Flags]
    public enum MouseEventFlags
    {
        LeftDown = 0x00000002,
        LeftUp = 0x00000004,
        MiddleDown = 0x00000020,
        MiddleUp = 0x00000040,
        Move = 0x00000001,
        Absolute = 0x00008000,
        RightDown = 0x00000008,
        RightUp = 0x00000010
    }

    [DllImport("user32.dll", EntryPoint = "SetCursorPos")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool SetCursorPos(int x, int y);      

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetCursorPos(out MousePoint lpMousePoint);

    [DllImport("user32.dll")]
    private static extern void mouse_event(int dwFlags, int dx, int dy, int dwData, int dwExtraInfo);

    public static void SetCursorPosition(int x, int y) 
    {
        SetCursorPos(x, y);
    }

    public static void SetCursorPosition(MousePoint point)
    {
        SetCursorPos(point.X, point.Y);
    }

    public static MousePoint GetCursorPosition()
    {
        MousePoint currentMousePoint;
        var gotPoint = GetCursorPos(out currentMousePoint);
        if (!gotPoint) { currentMousePoint = new MousePoint(0, 0); }
        return currentMousePoint;
    }

    public static void MouseEvent(MouseEventFlags value)
    {
        MousePoint position = GetCursorPosition();

        mouse_event
            ((int)value,
             position.X,
             position.Y,
             0,
             0)
            ;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct MousePoint
    {
        public int X;
        public int Y;

        public MousePoint(int x, int y)
        {
            X = x;
            Y = y;
        }
    }
}

2
我看不出这段冗长的源代码相比于17个月前Marcos Placona发布的内容有任何优势。 - Al Kepp
59
考虑到问题的模糊性,我认为提供一个例子会让人们受益更多,这个例子可以让他们不仅仅能够进行左键单击、右键或中键单击,还可以进行点击并拖动操作。 - Keith
2
非常好用。我来这里是为了找类似的东西。 - CSharpie
非常好的答案,解决了我数小时的问题,感谢您! - Zoidberg
3
@ninjaxelite 我猜你发送了 1. SetCursorPos, 2. MouseEvent(LeftButtonDown), 3. SetCursorPos, 4. MouseEvent(LeftButtonUp)。可能需要将其封装在一个辅助方法中。 - Michal Ciechan
显示剩余2条评论

150

我在过去的某个地方找到了一个示例somewhere这里可能会有所帮助:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

public class Form1 : Form
{
   [DllImport("user32.dll",CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)]
   public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);
   //Mouse actions
   private const int MOUSEEVENTF_LEFTDOWN = 0x02;
   private const int MOUSEEVENTF_LEFTUP = 0x04;
   private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
   private const int MOUSEEVENTF_RIGHTUP = 0x10;

   public Form1()
   {
   }

   public void DoMouseClick()
   {
      //Call the imported function with the cursor's current position
      uint X = (uint)Cursor.Position.X;
      uint Y = (uint)Cursor.Position.Y;
      mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, X, Y, 0, 0);
   }

   //...other code needed for the application
}

13
也许是在这里吧:http://www.gamedev.net/topic/321029-how-to-simulate-a-mouse-click-in-c/ - mpen
3
干得好。已添加对原始答案的引用。 - Marcos Placona
2
我在这段代码中遇到了一个错误:调用PInvoke函数'MyForm!MyForm.Form1 :: mouse_event'导致堆栈不平衡。这可能是因为托管的PInvoke签名与非托管的目标签名不匹配。请检查PInvoke签名的调用约定和参数是否与目标非托管签名匹配。有什么想法吗? - Abdulla
12
你需要将X和Y转换为无符号整数。 - Dibesjr
1
工作完美,需要根据要求更改光标位置... - Anurag Rabadia
显示剩余4条评论

15

System.Windows.Forms 中的按钮(Button)这样的控件,具有“PerformClick”方法可以实现此功能。


如果控件没有PerformClick方法,您可以扩展/添加一个,只需要使用适当的MouseEventArgs参数调用OnMouseClick即可。 - Tony Hopkinson

11

1
这有点奇怪,因为它被隔离在Visual Studio UI测试命名空间中,但是如果我不需要按设备过滤事件,我会选择这个而不是PInvoke。 - kayleeFrye_onDeck
2
看起来 Visual Studio Community 版本没有随附这个 DLL 文件。 - C.M.
4
我刚刚花了一个小时尝试通过从“编码UI测试”项目复制DLL到另一个项目中来使其工作,除非你正在使用“编码UI测试”项目类型,否则我的建议是:不要费力了。即使我复制了所有必要的DLL,它仍然抛出了“InvalidUITestExtensionPackageException”异常,所以它似乎非常挑剔,只能在特定的项目类型中运行,很遗憾。 - Jez
@Jez - 很有用的信息,谢谢。我自己还没有遇到过任何问题,但现在至少知道一些问题存在了 ;0) - Rusty Nail

6

我尝试了马科斯发布的代码,但它对我没有起作用。无论我给Y坐标赋什么值,光标都不会在Y轴上移动。下面的代码可以工作,如果你想要相对于桌面左上角而不是相对于你的应用程序来获取光标位置。

    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    public static extern void mouse_event(long dwFlags, long dx, long dy, long cButtons, long dwExtraInfo);
    private const int MOUSEEVENTF_LEFTDOWN = 0x02;
    private const int MOUSEEVENTF_LEFTUP = 0x04;
    private const int MOUSEEVENTF_MOVE = 0x0001;

    public void DoMouseClick()
    {
        X = Cursor.Position.X;
        Y = Cursor.Position.Y;

        //move to coordinates
        pt = (Point)pc.ConvertFromString(X + "," + Y);
        Cursor.Position = pt;       

        //perform click            
        mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
        mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
    }

我只使用mouse_event函数来实现点击操作。你可以给出你想要的X和Y坐标,我使用了文本框中的值:

            X = Convert.ToInt32(tbX.Text);
            Y = Convert.ToInt32(tbY.Text);

这对我来说是正确的选择,基本上 Cursor.Position 足以将鼠标光标定位到任何位置,然后使用 WIN32API 进行实际点击。 - Ge Rong

0

我使用InvokeOnClick()方法。它需要两个参数:Control和EventArgs。如果你需要EventArgs,那么创建一个实例并传入,否则使用InvokeOnClick(controlToClick, null);。你可以使用从EventArgs派生的各种鼠标事件相关参数,例如MouseEventArgs。


-1

有些需求我无法像KeithMarcos Placona那样去完成,而不只是做到这一点。

using System;
using System.Windows.Forms;

namespace WFsimulateMouseClick
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            button1_Click(button1, new MouseEventArgs(System.Windows.Forms.MouseButtons.Left, 1, 1, 1, 1));

            //by the way
            //button1.PerformClick();
            // and
            //button1_Click(button1, new EventArgs());
            // are the same
        }

        private void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("clicked");
        }
    }
}

1
如果您不需要这些参数,也可以执行button1_Click(null, null)。 - sab669
@sab669 当然可以,但这还取决于他的需求 :-) - WiiMaxx
在第二个参数中不应使用“null”,否则会引发“NullReferenceException”异常,而应该使用“EventArgs.Empty”。 - Etor Madiv
1
@EtorMadiv 像我之前说的那样,这取决于你想要做什么...因为如果你像我上面那样使用它,你就不会得到NullReferenceException - WiiMaxx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接