应使用 mouse_event 配合 MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP 标志,并将屏幕坐标归一化为 0–65535 范围;需声明 dwFlags 为 uint,结构体加 [StructLayout(Sequential)],并注意 DPI 缩放影响。
怎么用
实现指定坐标的鼠标点击(C#)
Windows API 的
已废弃,但仍在 Win32 平台广泛可用;它不依赖前台窗口,能跨进程触发点击,适合自动化脚本。不过它操作的是**屏幕绝对坐标**,且需手动切换坐标系(默认是相对移动,要点击得先设为绝对模式)。
常见错误现象:
调用后没反应,或点在了错位置——大概率是忘了加
标志,或没把像素坐标缩放到 0–65535 范围。
必须传入
组合,缺一不可
坐标要归一化:
和
,否则永远点在左上角
调用前建议用
防系统休眠,尤其后台运行时
.NET 6+ 项目默认启用了“仅限 Windows”平台限制,若目标框架是
而非
,P/Invoke 会编译失败
替代方案更稳定,但要注意输入设备上下文
是微软推荐的现代替代接口,行为更可靠、支持多点触控和键盘组合,但它的输入事件会进入系统输入队列,受 UIPI(用户界面特权隔离)限制:普通权限进程无法向更高权限窗口(如管理员运行的记事本)发送输入。
使用场景:需要模拟真实用户输入链路(比如连按 + 键盘修饰)、或未来可能迁移到高 DPI/多显示器环境。
构造
结构体时,
必须是
,且
/
字段含义与
不同:同样需归一化,且单位仍是 0–65535
若只点一次,必须发两个事件:
+
,不能合并
调用后无返回值,失败时
返回 0,应检查
在远程桌面或锁屏状态下,
可能静默失败(事件被丢弃),而
同样受限,没有银弹
C# P/Invoke 声明里最容易漏掉的三个细节
写错 P/Invoke 签名是调用失败最常见原因,不是逻辑问题,而是声明失配。
C知道
CSDN推出的一款AI技术问答工具
下载
的
参数类型必须是
,不是
—— 否则高位标志(如
= 0x8000)会被符号扩展成负数
的第三个参数
必须传
,硬编码
或
在 x64/x86 混合环境下必崩
所有结构体(如
)必须加
,否则字段内存布局错乱,坐标值读成垃圾数据
高 DPI 和多显示器下坐标计算容易错在哪
Windows 10/11 默认开启 DPI 缩放,GetSystemMetrics(
) 返回的是虚拟屏幕宽,不是物理像素;直接用
也会被缩放干扰。
正确做法是用
+
获取当前显示区域的真实像素尺寸,但多数简单脚本其实只需绕过缩放:
用
获取主屏 DPI,再反推原始像素坐标
更稳妥:调用
(Windows 10 1703+)设为
,然后用
查每个屏的
如果只是点固定 UI 元素,优先用
+
把控件客户区坐标转屏幕坐标,比纯像素定位鲁棒得多
实际项目里,90% 的坐标偏差问题出在没处理 DPI 缩放,而不是 API 本身难用。
mouse_eventmouse_eventmouse_eventMOUSEEVENTF_ABSOLUTEMOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP(x * 65535 / screen_width)(y * 65535 / screen_height)SetThreadExecutionStatenet6.0net6.0-windowsSendInputSendInputINPUTdwTypeINPUT_MOUSEdxdymouse_eventMOUSEEVENTF_LEFTDOWNMOUSEEVENTF_LEFTUPSendInputMarshal.GetLastWin32Error()SendInputmouse_eventmouse_eventdwFlagsuintintMOUSEEVENTF_ABSOLUTESendInputcbSizeMarshal.SizeOf()2840MOUSEINPUT[StructLayout(LayoutKind.Sequential)]SM_CXSCREENScreen.PrimaryScreen.Bounds.WidthGetDpiForWindowGetSystemMetricsForDpiGraphics.FromHwnd(IntPtr.Zero).DpiXSetThreadDpiAwarenessContextDPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2GetMonitorInforcMonitorFindWindowClientToScreen