You need to enable JavaScript to run this app. 多显示器场景下使用CGDisplayMoveCursor移动鼠标位置不符合预期
优惠活动
大模型
产品
解决方案
定价
更多

多显示器场景下使用CGDisplayMoveCursor移动鼠标位置不符合预期

问题根源

AppKit(NS)和Quartz(CG)两套框架的坐标系规则不同,是导致落点偏移的核心原因:

  • NS坐标系全局以主屏幕左下角为原点,y轴向上,你从NSScreen.frame拿到的每个屏幕位置都是基于这个全局坐标系计算的
  • CGDisplayMoveCursorToPoint要求传入目标点在指定显示器的局部CG坐标,这类坐标系以当前屏幕左上角为原点,y轴向下
坐标转换步骤

你已经完成了目标点归属显示器的判断,只要按以下两步转换坐标即可适配接口要求:

  1. 把全局NS坐标转换为目标显示器的局部NS坐标:用目标点坐标减去目标显示器frame的origin值
  2. 翻转y轴适配CG坐标系:用显示器的高度减去上一步得到的局部NS坐标y值,得到CG局部坐标的y值
适配后的代码实现
let point = NSPoint(x: x, y: y)
guard let monitor = Monitor.displayIdWithPoint(point) else {
    SendlogCallbackEvent("D", "", "Found nil in monitor with point", #function, #file, #line)
}
// 注:如果你的Monitor结构体没有关联对应NSScreen实例,可以在查找归属显示器的逻辑里同步返回匹配到的NSScreen frame
let monitorFrame = monitor.screen.frame
// 转换为显示器局部NS坐标
let localX = point.x - monitorFrame.origin.x
let localNSY = point.y - monitorFrame.origin.y
// 翻转y轴得到CG接口可识别的局部坐标
let localCGY = monitorFrame.height - localNSY
let targetCGPoint = CGPoint(x: localX, y: localCGY)

if CGDisplayMoveCursorToPoint(monitor.directDisplayId, targetCGPoint) == CGError.failure {
    SendlogCallbackEvent("D", "", "CGError.failer to move cursor", #function, #file, #line)
}
更简单的可选实现方案

如果不需要强制绑定指定显示器移动,你可以跳过显示器归属判断逻辑,直接转换全局坐标后调用CGWarpMouseCursorPosition实现:

let point = NSPoint(x: x, y: y)
// 计算全局NS坐标系的总高度(所有屏幕的最大y值)
let globalMaxY = NSScreen.screens.map { $0.frame.maxY }.max() ?? 0
// 全局NS坐标转全局CG坐标
let globalCGY = globalMaxY - point.y
let globalCGPoint = CGPoint(x: point.x, y: globalCGY)
CGWarpMouseCursorPosition(globalCGPoint)

内容的提问来源于stack exchange,提问作者Gama

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.20 04:06:06