如何将macOS滚轮NSEvent的deltaY转换为物理滚动距离(英寸)
计算macOS滚轮事件的物理滚动距离
关键前提纠正
你之前误解了scrollingDeltaY的单位:它默认不是点(points),而是线(lines),对应系统设置里的“滚动速度”(默认每滚动一个滚轮齿,deltaY为1.0)。如果是精确滚动设备(如触控板、高精度鼠标),scrollingDeltaY会是基于物理滚动距离的浮点值,需要结合设备特性处理。
正确计算步骤
1. 获取系统滚动速度系数
如果用户修改过系统偏好设置的滚动速度,需要读取该值来修正计算:
import Foundation func getScrollSpeed() -> CGFloat { let defaults = UserDefaults.standard // 系统滚动速度的默认值为1.0 return defaults.float(forKey: "com.apple.scrollwheel.scaling") ?? 1.0 }
2. 分设备类型计算物理距离
普通鼠标滚轮(非精确滚动)
标准鼠标滚轮每滚动0.25英寸对应deltaY = 1.0(系统默认规格),结合滚动速度的计算公式:
let scrollSpeed = getScrollSpeed() let physicalDistanceInInches = abs(event.scrollingDeltaY) * 0.25 / scrollSpeed
精确滚动设备(触控板/高精度鼠标)
这类设备的scrollingDeltaY单位是点(points),需要结合屏幕PPI转换为物理英寸:
if event.hasPreciseScrollingDeltas { guard let mainScreen = NSScreen.main else { return } let displaySize = CGDisplayScreenSize(CGMainDisplayID()) // 单位为毫米 let screenWidthInInches = displaySize.width / 25.4 let pixelsPerInch = mainScreen.frame.width / screenWidthInInches * mainScreen.backingScaleFactor let deltaPoints = abs(event.scrollingDeltaY) let physicalDistanceInInches = deltaPoints / pixelsPerInch }
3. 修正你的PPI计算代码
原代码存在语法错误,修正后版本:
guard let mainScreen = NSScreen.main else { let pixelsPerInch: CGFloat = 96 // 兜底默认值 return } let frameWidth = mainScreen.frame.width let displaySize = CGDisplayScreenSize(CGMainDisplayID()) let screenWidthInInches = displaySize.width / 25.4 let pixelsPerInch = frameWidth / screenWidthInInches * mainScreen.backingScaleFactor
4. 累计滚动距离实现
在处理器中维护累计变量即可:
private var totalScrollDistanceInInches: CGFloat = 0.0 func scrollWheel(with event: NSEvent) { var distance: CGFloat = 0.0 let scrollSpeed = getScrollSpeed() if event.hasPreciseScrollingDeltas { guard let mainScreen = NSScreen.main else { return } let displaySize = CGDisplayScreenSize(CGMainDisplayID()) let screenWidthInInches = displaySize.width / 25.4 let pixelsPerInch = mainScreen.frame.width / screenWidthInInches * mainScreen.backingScaleFactor distance = abs(event.scrollingDeltaY) / pixelsPerInch } else { distance = abs(event.scrollingDeltaY) * 0.25 / scrollSpeed } totalScrollDistanceInInches += distance print("累计滚动距离:\(totalScrollDistanceInInches) 英寸") }
内容的提问来源于stack exchange,提问作者WWWillems
相关产品推荐
相关产品推荐

