You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 14:50:19