模拟鼠标点击

 模拟鼠标点击大概率跟键盘输入一样,某些软件会检测 物理

将实时鼠标坐标直接显示在窗口标题栏,既能简化界面(无需额外文本框),又能直观看到坐标,以下是优化后的完整代码,核心改动是把实时X/Y坐标更新到Form的Text属性,同时保留复制坐标、输入坐标模拟点击的核心功能。

一、优化后代码(简化界面+标题栏显示坐标)

步骤1:WinForm界面控件(极简版)

控件类型 名称 文本/用途
TextBox txtTargetX 输入X坐标
TextBox txtTargetY 输入Y坐标
Button btnSimulateClick 模拟点击

(无需再添加显示实时坐标的文本框,所有实时坐标直接显示在窗口标题)

步骤2:核心代码(Form1.cs)

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

namespace MouseClickSimulator
{
    public partial class Form1 : Form
    {
        // ====================== Windows API声明 ======================
        [DllImport("user32.dll")]
        private static extern bool SetCursorPos(int X, int Y);

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

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

        // 鼠标事件常量
        private const int MOUSEEVENTF_LEFTDOWN = 0x02;
        private const int MOUSEEVENTF_LEFTUP = 0x04;

        // 点结构体
        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            public int X;
            public int Y;
        }

        // 存储当前鼠标坐标(方便复制)
        private int _currentX;
        private int _currentY;

        // ====================== 窗体初始化 ======================
        public Form1()
        {
            InitializeComponent();
            // 初始化窗口标题
            this.Text = "鼠标坐标模拟器 - 当前坐标:X=0, Y=0";

            // 定时器轮询获取全局鼠标坐标(50ms刷新一次)
            Timer timer = new Timer
            {
                Interval = 50
            };
            timer.Tick += Timer_Tick;
            timer.Start();
        }

        // ====================== 核心:标题栏实时显示坐标 ======================
        private void Timer_Tick(object sender, EventArgs e)
        {
            if (GetCursorPos(out POINT currentPos))
            {
                // 更新全局变量(用于复制)
                _currentX = currentPos.X;
                _currentY = currentPos.Y;

                // 更新窗口标题(核心改动)
                this.Text = $"鼠标坐标模拟器 - 当前坐标:X={_currentX}, Y={_currentY}";
            }
        } 
        // ====================== 模拟坐标点击 ======================
        private void btnSimulateClick_Click(object sender, EventArgs e)
        {
            // 验证输入
            if (!int.TryParse(txtTargetX.Text.Trim(), out int targetX) ||
                !int.TryParse(txtTargetY.Text.Trim(), out int targetY))
            {
                MessageBox.Show("请输入有效的数字坐标!");
                return;
            }

            try
            {
                // 移动鼠标+模拟点击
                SetCursorPos(targetX, targetY);
                mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, targetX, targetY, 0, 0);
                MessageBox.Show($"已模拟点击:X={targetX}, Y={targetY}");
            }
            catch (Exception ex)
            {
                MessageBox.Show($"模拟点击失败:{ex.Message}\n请以管理员身份运行!");
            }
        }
    }
}

二、核心优化点说明

  1. 标题栏实时显示坐标

    • 直接通过this.Text = $"XXX{_currentX},{_currentY}"更新窗口标题。
    • 保留_currentX/_currentY全局变量,用于复制坐标和后续扩展。
  2. 界面极简化

    • 仅保留必要控件: 目标坐标输入框、模拟点击按钮,界面更清爽。

三、使用效果

  1. 运行程序后,窗口标题会实时刷新:
    鼠标坐标模拟器 - 当前坐标:X=156, Y=389
  2. 移动鼠标时,标题栏的X/Y数值会立即更新(50ms刷新一次,肉眼无延迟)。
  3. 将复制的坐标粘贴到目标坐标输入框(拆分X/Y),点击「模拟点击」即可触发操作。

四、额外优化(可选)

1. 标题栏格式自定义

若想让标题更简洁,可修改标题格式:

// 极简格式(仅显示坐标)
this.Text = $"X:{_currentX} Y:{_currentY}"; 
// 带备注格式
this.Text = $"坐标模拟器 | X={_currentX} Y={_currentY}";

2. 高DPI适配

若屏幕缩放导致坐标偏移,可在窗体初始化时添加DPI适配:

public Form1()
{
    InitializeComponent();
    // 禁用DPI缩放(避免坐标偏移)
    this.AutoScaleMode = AutoScaleMode.None;
    // 其他初始化代码...
}

3. 延迟点击(实用扩展)

添加一个NumericUpDown控件(命名nudDelay),实现延迟点击(方便切换到目标窗口):

private void btnSimulateClick_Click(object sender, EventArgs e)
{
    if (!int.TryParse(txtTargetX.Text.Trim(), out int targetX) ||
        !int.TryParse(txtTargetY.Text.Trim(), out int targetY))
    {
        MessageBox.Show("请输入有效的数字坐标!");
        return;
    }

    // 获取延迟时间(默认0秒)
    int delayMs = (int)nudDelay.Value * 1000;

    // 延迟执行点击
    Task.Delay(delayMs).ContinueWith(t =>
    {
        try
        {
            SetCursorPos(targetX, targetY);
            mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, targetX, targetY, 0, 0);
            this.Invoke(new Action(() => 
                MessageBox.Show($"延迟{delayMs/1000}秒后点击:X={targetX}, Y={targetY}")
            ));
        }
        catch (Exception ex)
        {
            this.Invoke(new Action(() => 
                MessageBox.Show($"点击失败:{ex.Message}")
            ));
        }
    }, TaskScheduler.FromCurrentSynchronizationContext());
}

实现鼠标双击

只需在单击基础上补充一次 “按下 + 抬起” 的操作(或直接用双击专用常量)

一、核心原理(双击实现)

Windows 系统中,双击本质是两次快速的单击(间隔约 500ms 内),有两种实现方式:

  1. 简易版:连续调用两次单击事件(最通用,兼容所有系统);
  2. 原生版:使用MOUSEEVENTF_LEFTDBLCLK常量(直接触发双击,部分控件更适配)。
RadioButton rdoDoubleClick 双击
  // 鼠标事件常量
        private const int MOUSEEVENTF_LEFTDOWN = 0x02;    // 左键按下
        private const int MOUSEEVENTF_LEFTUP = 0x04;      // 左键抬起
        private const int MOUSEEVENTF_LEFTDBLCLK = 0x08;  // 左键双击(原生常量)
 // 方式1:原生双击(推荐,部分控件更适配)
                    mouse_event(MOUSEEVENTF_LEFTDBLCLK, targetX, targetY, 0, 0);

                    // 方式2:连续两次单击(兼容所有场景,可替代上面一行)
                    // mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, targetX, targetY, 0, 0);
                    // System.Threading.Thread.Sleep(50); // 双击间隔(50ms,可调整)
                    // mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, targetX, targetY, 0, 0);
 

1. 两种双击实现方式对比

方式 代码示例 适用场景
原生双击(推荐) mouse_event(MOUSEEVENTF_LEFTDBLCLK, X, Y, 0, 0) 系统原生控件(如文件夹、按钮),更贴合实际操作
连续单击(兼容) 两次LEFTDOWN+LEFTUP + 50ms 延迟 自定义控件 / 游戏等不识别原生双击的场

2. 双击间隔调整

若原生双击失效,改用 “连续单击” 时,可调整Thread.Sleep(50)的数值(范围 50-200ms),匹配系统双击间隔(Windows 默认双击间隔是 500ms,可在「控制面板→鼠标」中查看)。

3. 高兼容性替代方案(SendInput)

mouse_event在新版 Windows 中失效,可替换为SendInput实现双击(更稳定):

// 补充SendInput相关API
[StructLayout(LayoutKind.Sequential)]
private struct INPUT { public int type; public MOUSEINPUT mi; }
[StructLayout(LayoutKind.Sequential)]
private struct MOUSEINPUT { public int dx, dy, mouseData, dwFlags, time; public IntPtr dwExtraInfo; }
[DllImport("user32.dll")]
private static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);

// 模拟双击(SendInput版)
private void SimulateDoubleClick(int x, int y)
{
    // 坐标归一化(适配多屏幕)
    int dx = (x * 65535) / Screen.PrimaryScreen.Bounds.Width;
    int dy = (y * 65535) / Screen.PrimaryScreen.Bounds.Height;

    INPUT[] inputs = new INPUT[4];
    // 移动鼠标
    inputs[0].type = 0;
    inputs[0].mi.dx = dx;
    inputs[0].mi.dy = dy;
    inputs[0].mi.dwFlags = 0x8000 | 0x0001; // MOVE + VIRTUALDESK

    // 第一次单击(按下+抬起)
    inputs[1].type = 0;
    inputs[1].mi.dwFlags = 0x0002; // LEFTDOWN
    inputs[2].type = 0;
    inputs[2].mi.dwFlags = 0x0004; // LEFTUP

    // 第二次单击(按下+抬起,双击核心)
    inputs[3].type = 0;
    inputs[3].mi.dwFlags = 0x0002 | 0x0004; // LEFTDOWN + LEFTUP

    SendInput(4, inputs, Marshal.SizeOf(typeof(INPUT)));
}

快捷键触发:添加 F5(单击)、F6(双击)快捷键,无需点击按钮:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    if (keyData == Keys.F5) { btnSimulateClick.PerformClick(); return true; }
    if (keyData == Keys.F6) { rdoDoubleClick.Checked = true; btnSimulateClick.PerformClick(); return true; }
    return base.ProcessCmdKey(ref msg, keyData);
}