如何将NSTouch坐标转换为macOS屏幕坐标?
把NSTouch的归一化坐标映射到屏幕坐标
嘿,刚好对这块儿熟,来给你捋捋~
首先得说,你提到的点特别准:在macOS的Cocoa框架里,NSTouch自带的归一化触摸坐标(x/y取值0.0-1.0)加上触控板设备尺寸的设计,确实给坐标映射留足了灵活度,逻辑上非常合理。
虽然你说“屏幕坐标定义不明确”,我先给你几个最常用的场景实现,你可以根据后续需求调整:
1. 最简比例映射(触控板全区域对应屏幕全区域)
如果只是想把触控板的触摸位置按比例直接对应到整个屏幕,步骤超简单:
- 先拿到当前主屏幕的尺寸,再获取
NSTouch的归一化坐标 - 注意Cocoa的坐标系原点在左下角,和iOS的UIKit不一样,别搞混
- 代码示例:
如果你的需求是映射到某个窗口内的坐标,把guard let touch = touchEvent.touches.first, let screenSize = NSScreen.main?.frame.size else { return } let normalizedPoint = touch.normalizedPosition // 转换为屏幕坐标(原点在屏幕左下角) let screenPoint = NSPoint(x: normalizedPoint.x * screenSize.width, y: normalizedPoint.y * screenSize.height)screenSize换成目标窗口的frame.size就行。
2. 物理尺寸精准映射(贴合触摸的物理位置)
如果想要更贴合真实触摸的物理对应(比如触控板左上角对应屏幕左上角),可以利用NSTouch的deviceSize(触控板物理尺寸,单位毫米)来计算比例:
- 要注意Retina屏的缩放因子,不然会出现坐标偏移
- 代码示例:
guard let touch = touchEvent.touches.first, let screen = NSScreen.main else { return } let touchDeviceSize = touch.deviceSize // 先算出屏幕的物理尺寸(去除Retina缩放) let screenPhysicalWidth = screen.frame.width / screen.backingScaleFactor let screenPhysicalHeight = screen.frame.height / screen.backingScaleFactor // 计算触控板与屏幕的物理比例 let widthRatio = screenPhysicalWidth / touchDeviceSize.width let heightRatio = screenPhysicalHeight / touchDeviceSize.height let normalizedPoint = touch.normalizedPosition // 转换为带缩放的屏幕像素坐标 let screenPoint = NSPoint(x: normalizedPoint.x * screenPhysicalWidth * screen.backingScaleFactor, y: normalizedPoint.y * screenPhysicalHeight * screen.backingScaleFactor)
3. 自定义区域映射(按需适配局部场景)
如果你的需求是把触控板的某块区域映射到屏幕的特定窗口/区域,只需要做线性映射调整:
- 先定义触控板上的目标归一化范围,再对应屏幕上的目标区域
- 代码示例(比如把触控板中间60%区域映射到主窗口):
// 定义触控板上的目标触摸范围 let targetTouchXRange = 0.2...0.8 let targetTouchYRange = 0.2...0.8 guard let targetWindow = NSApp.windows.first, let touch = touchEvent.touches.first else { return } let windowFrame = targetWindow.frame let normalizedPoint = touch.normalizedPosition // 把归一化坐标转换为目标范围内的相对值 let relativeX = (normalizedPoint.x - targetTouchXRange.lowerBound) / (targetTouchXRange.upperBound - targetTouchXRange.lowerBound) let relativeY = (normalizedPoint.y - targetTouchYRange.lowerBound) / (targetTouchYRange.upperBound - targetTouchYRange.lowerBound) // 映射到窗口坐标 let windowPoint = NSPoint(x: windowFrame.origin.x + relativeX * windowFrame.width, y: windowFrame.origin.y + relativeY * windowFrame.height)
最后补个小提醒:Cocoa里NSTouch的归一化坐标原点是触控板左下角,屏幕坐标原点也是屏幕左下角,所以不用翻转y轴,但如果是在NSView内部处理,要注意view自身的坐标系可能有变化哦。
内容的提问来源于stack exchange,提问作者ashcatch
相关产品推荐
相关产品推荐

