Lunar 5.6.6 深度解析:基于环境光的 Auto XDR、非 Apple 显示器 Sync 源与版本改进
Lunar 5.6.6 深度解析:基于环境光的 Auto XDR、非 Apple 显示器 Sync 源与版本改进
Lunar 5.6.6 这一版本的核心主题是让 XDR 亮度的启用更“自动化”与“场景化”:它新增了一个基于环境光传感器读数自动切换 XDR 的开关,并允许把非 Apple 显示器作为 Sync Mode 的同步源。读完本文,你将掌握 Auto XDR(环境光触发)的默认参数、硬件限制、配置键与底层实现链路,以及该版本附带的所有改进与修复项。
基于环境光的 Auto XDR:核心新功能
5.6.6 最重要的特性是 基于环境光的 Auto XDR(Auto XDR based on ambient light),其官方行为定义如下:
- 当环境光足够亮时,XDR 会被自动启用;
- 当环境光低到普通亮度即可看清屏幕时,XDR 会自动关闭;
- 该功能仅在 MacBook Pro 2021 单独使用时生效(即不接外接显示器)。
这与 Lunar 原有的 Auto XDR(根据内容亮度自动判断是否提高亮度)不同:新功能是拿**环境光传感器读数(lux)**作为切换 XDR 的判据,适合“强光环境下想要更亮更通透的显示效果、暗光环境下又希望省电护眼”的用户。
配置项与默认值
从源码 LunarShortcuts/Shared.swift 中的 Defaults.Keys 定义(L104-L110)可以看到该功能涉及的配置键与默认值:
static let autoXdr = Key<Bool>("autoXdr", default: true)
static let autoXdrSensor = Key<Bool>("autoXdrSensor", default: false)
static let autoXdrSensorShowOSD = Key<Bool>("autoXdrSensorShowOSD", default: true)
static let autoXdrSensorLuxThreshold = Key<Float>("autoXdrSensorLuxThreshold", default: XDR_DEFAULT_LUX)
对应关系与含义:
| 配置键 | 默认值 | 说明 |
|---|---|---|
autoXdr |
true |
原有 Auto XDR(基于内容亮度)总开关 |
autoXdrSensor |
false |
本版本新增:基于环境光的 Auto XDR 开关,默认关闭 |
autoXdrSensorLuxThreshold |
6500 lux |
触发阈值。环境光高于该值时启用 XDR,低于时关闭 |
autoXdrSensorShowOSD |
true |
XDR 自动切换时是否弹出 OSD 通知 |
其中默认阈值常量定义在 Shared.swift:
let XDR_DEFAULT_LUX: Float = 6500
6500 lux 大致对应明亮日光或强光室内环境,因此默认行为符合发布说明中“环境光非常亮时才启用”的描述。
硬件限制在源码中的体现
“仅在 MacBook Pro 2021 单独使用(无外接显示器)时生效”这一限制,在源码中有明确的守卫条件。DisplayController.swift 中订阅 autoXdrSensor 开关的逻辑是:
autoXdrSensorPublisher
.debounce(for: .seconds(1), scheduler: RunLoop.main)
.sink { [self] change in
autoXdrSensor = change.newValue
guard let display = builtinDisplay, display.isMacBookXDR, let lux = SensorMode.getInternalSensorLux() else {
xdrSensorTask = nil
return
}
internalSensorLux = lux.f
xdrSensorTask = change.newValue ? getSensorTask() : nil
}.store(in: &observers)
可以看到三个前提条件,任一不满足就会把 xdrSensorTask 置空、功能不工作:
- 存在内置屏(
builtinDisplay),即当前是 MacBook; display.isMacBookXDR为真;- 能成功读取内部环境光传感器读数(
SensorMode.getInternalSensorLux())。
其中 isMacBookXDR 的定义在 Display.swift:
var isMacBookXDR: Bool { isMacBook && supportsEnhance }
supportsEnhance 对应 Lunar 中“支持 XDR 亮度增强”的能力判断。从源码结构看,只有 XDR 面板(即 MacBook Pro 2021 及之后的 XDR 机型)才有内部传感器驱动的这条链路;而“接了外接显示器就不工作”这一点,也与 DisplayController.swift 中显示器列表变动时重新评估 xdrSensorTask 的机制一致——外接屏接入会改变活跃显示器集合,进而影响该任务的存续。
另外,DisplayController 暴露了两个发布属性用于驱动 UI 显示(DisplayController.swift):
@Published var autoXdrSensorPausedReason: String? = nil
@Published var internalSensorLux: Float = 0
前者在传感器暂停自动 XDR 时给出原因(例如用户手动取消后 3 小时内保持暂停,见 cancelAutoXdr 逻辑),后者实时保存最近一次读到的环境光值。
设置界面:阈值滑杆的非线性映射
用户在设置页看到的界面对应 HDRSettingsView.swift,包含:
- 开关 “Toggle XDR Brightness based on ambient light”(绑定
autoXdrSensor); - 说明文字:“XDR Brightness will be automatically enabled when ambient light is above N lux”,N 为当前阈值;
- 一个带
sun.dust.fill图标的阈值滑杆,滑杆上有一个标记(mark)指示当前实时环境光读数在刻度上的位置; - 一个
Reset按钮,把阈值恢复为XDR_DEFAULT_LUX(6500 lux); - 开关打开时,底部显示 “Current ambient light: N lux”,或显示暂停原因(
autoXdrSensorPausedReason); - 子开关 “Show OSD when toggling XDR automatically”(绑定
autoXdrSensorShowOSD)。
值得注意的是滑杆与阈值之间并非线性关系,源码使用了 0.25 次幂映射(HDRSettingsView.swift):
let luxBinding = Binding<Float>(
get: { powf(max(autoXdrSensorLuxThreshold - XDR_LUX_LEAST_NONZERO, 0) / XDR_MAX_LUX, 0.25) },
set: { autoXdrSensorLuxThreshold = powf($0, 4) * XDR_MAX_LUX + XDR_LUX_LEAST_NONZERO }
)
这种开方两次(四次方的反函数)的设计,让滑杆前段(低 lux 区间)拖动更精细、后段(高 lux 区间)跨度更大——因为环境光从 100 lux 到 10000 lux 跨越 2 个数量级,线性滑杆在小亮度侧几乎不可控。XDR_MAX_LUX 与 XDR_LUX_LEAST_NONZERO 是约束滑杆有效区间的常量,用于避免阈值为 0 或超量程。
环境光读数从哪来
Lunar 内部环境光读数统一通过 SensorMode.getInternalSensorLux() 获取,外部传感器(如连接了 Raspberry Pi 等)则优先使用 SensorMode.specific.lastAmbientLight。这一优先级同样体现在 CLI 的 lux 命令中(CLI.swift):
if SensorMode.specific.externalSensorAvailable, let lux = SensorMode.specific.lastAmbientLight {
cliPrint(lux)
} else {
cliPrint(average ? (SensorMode.computeLuxWindowAverage() ?? -1.0) : (SensorMode.getInternalSensorLux() ?? -1.0))
}
也就是说,你可以在终端执行 lunar lux 来验证内部传感器是否可用、读数是否合理——这正是调阈值前的必要检查手段。
Alpha 阶段的 100% 亮度 Bug
回顾 5.6.6 的发布节奏:该功能在 alpha 3 才加入,随后 alpha 4 立即发布热修复(见 ReleaseNotes/5.6.6a4.md):
Auto XDR based on ambient light was setting brightness to 100% wrongly
即自动启用 XDR 时曾错误地把屏幕亮度直接设为 100%。正式版 5.6.6 已包含此修复。若你在 alpha 渠道看到该现象,属于已知缺陷而非硬件异常。
允许非 Apple 显示器作为 Sync Mode 源
5.6.6 的第二个特性是:Sync Mode 可以把非 Apple 显示器作为同步源(Add option to use non-Apple monitors as sources for Sync Mode)。此前只有具备环境光自适应能力且支持 Gamma 的显示器才能当“源”。
对应的配置键是 Shared.swift 中的:
static let allowAnySyncSource = Key<Bool>("allowAnySyncSource", default: true)
该选项默认开启。它对显示器“能否作为源”的判定逻辑在 Display.swift:
@objc dynamic lazy var canBeSource: Bool = {
allowAnySyncSourcePublisher.sink { [weak self] change in
guard let self else { return }
canBeSource = (hasAmbientLightAdaptiveBrightness && supportsGammaByDefault) || change.newValue
}.store(in: &observers)
return (hasAmbientLightAdaptiveBrightness && supportsGammaByDefault) || CachedDefaults[.allowAnySyncSource]
}()
逻辑可以解读为:canBeSource =(原生支持环境光自适应 && 默认支持 Gamma)|| allowAnySyncSource。开启 allowAnySyncSource 后,任意受管显示器都可以被选为源,亮度同步的目标(targetDisplays 即“非源”的活跃显示器,见 DisplayController.swift)则照旧跟随源亮度。这一选项还通过 allowAnySyncSourcePublisher 实现了热更新——运行时切换无需重启应用。
其他改进项
发布说明中的 Improvements 部分包含三条,逐一说明:
1. 相同型号显示器自动将 Curve Slope 设为中点
Automatically set Curve Slope to middle point on target monitors identical to the source:当 Sync Mode 的目标显示器与源显示器型号完全相同时,Lunar 会自动把该目标上的 Gamma 曲线斜率(Curve Slope)设为中点。原理上,两台同型号显示器在相同 DDC 亮度值下的响应曲线一致,此时保持斜率为中点即可得到最“中性”的同步效果,避免 Lunar 为补偿不同显示器响应差异而施加的斜率调节在“同型号”场景下反而引入偏差。
2. displays CLI 命令支持跨屏打印单一属性
Print single property on multiple displays when using the displays CLI command:在多台显示器同时连接时,lunar displays 相关命令现在可以只对单一属性在所有显示器上逐一输出。这简化了脚本化场景:例如只想知道每台屏当前的亮度/对比度/色温,而不必解析整块输出。
3. Configuration 页新增 Hide Menubar Icon
Add Hide Menubar Icon setting on the Configuration page:在设置(Configuration)页面上新增了“隐藏菜单栏图标”的开关,允许使用纯菜单栏交互方式之外、或希望完全隐藏状态栏图标的用户关闭图标显示。注意原发布说明此处链接为 lunar://configuration 自定义 URL Scheme(用于从文档直接唤起应用内页面),并非仓库内文件路径。
修复项
本版本 Fixes 部分有两条,都指向工程稳定性:
- Fix CLI hanging:修复 CLI 命令挂起问题。Lunar 的 CLI 通过本地 socket 与服务端进程通信(默认端口 23803,见 Shared.swift 中的
LUNAR_CLI_PORT),此前某些调用路径会导致命令阻塞不返回,本版本修复后lunar命令行可稳定退出; - Run some UI logging async to avoid blocking the main thread:将部分 UI 日志改为异步执行,避免阻塞主线程。这一项在 5.6.6a1 就已以热修复形式先行发布,说明它在开发早期就观察到了界面卡顿现象。
配置与验证路径小结
结合上文,实际使用建议按以下顺序验证:
- 确认机型为带 XDR 屏的 MacBook Pro(2021 起),且不接外接显示器——这是功能生效的硬前提;
- 用
lunar lux(或lunar lux --average取 15 秒窗口均值,见 CLI.swift)确认环境光读数正常; - 在设置页打开 “Toggle XDR Brightness based on ambient light”,按需拖动阈值滑杆,默认 6500 lux,可用
Reset恢复; - 打开 “Show OSD when toggling XDR automatically” 可直观看到每次自动启用/关闭 XDR 的反馈;
- 手动切换 XDR 后注意:连续两次手动操作会暂停自动逻辑约 3 小时(
autoXDRCancelCount机制,见 DisplayController.swift),这是防止手动与自动互相打架的设计,并非 Bug。
相关源码入口汇总:
- 配置键定义:LunarShortcuts/Shared.swift
- 传感器任务调度与暂停逻辑:Lunar/Utils/DisplayController.swift
- XDR 机型判定:Lunar/Data/Display.swift
- Sync 源资格判定:Lunar/Data/Display.swift
- 设置界面:Lunar/SwiftUIViews/HDRSettingsView.swift
- 缓存键与发布器:Lunar/Data/DataStore.swift
版本定位
5.6.6 整体是一个以“自动化体验”为目标的版本:环境光驱动 XDR 让显示亮度策略从“内容感知”扩展到“环境感知”,Sync Mode 放开源设备限制则让多屏同步不再受限于 Apple 生态内的原生能力。配合两条稳定性修复,该版本适合 XDR 机型用户与多屏用户重点升级。