Mac 上按时段调暗屏幕,以及那个会把屏幕一路调成全黑的陷阱
按时段调暗屏幕听起来是两行代码的事:看表、设亮度。陷阱在「设」这个字上。如果你要设的值是从当前已有的值推算出来的,那么每复查一次屏幕就更暗一点——到早上它就全黑了。
这个功能,从用户角度看
一天被分成几个时间段——工作时段、傍晚时段、夜间时段——每一段各自带白点与亮度。没有全局开关;改 21:00 的行为不会影响 14:00。
时间以距本地午夜的分钟数存储。这带来一个漂亮的结果:结束时间早于开始时间就自动跨越午夜,所以「夜间 20:00 到 08:00」完全不需要特例——它和别的时段是同一套算术。
陷阱一——会自己越乘越小的「倍数」
下面这种写法看起来完全合理:
let current = display.brightness
let dimmed = current * 0.6 // 错的
apply(dimmed)
把它挂在 60 秒一次的心跳上,面板就会被反复乘以 0.6:0.6、0.36、0.22、0.13……屏幕会自己走向全黑,而用户的说法是「这个应用一夜之间把我屏幕弄坏了」。
解法是把值做成绝对量——按满量程的比例,而不是实时值的倍数:
let target = 0.6 // 满量程的比例
apply(target)
现在应用两次和应用一次的结果相同。用一个词说:这个调度器是幂等的。反复求值不等于空操作的调度器,不是幂等的——而它会漂移。
陷阱二——你拖滑杆时,心跳不跳了
第二个陷阱更安静。挂在默认 run loop 模式上的定时器,在用户拖动滑杆时不会触发——因为拖动会把 run loop 按在事件跟踪模式里。于是那个本该在 21:00 落下的复查,悄无声息地没落下。
把心跳注册在 .common 模式下,它就仍然会落下——而那恰恰是用户最容易注意到的时刻。
陷阱三——会自我重启的淡入淡出
值变成绝对量之后,紧接着的问题是:调度器对同一个时段做了两次决定会怎样?如果每次决定都重启淡入淡出,屏幕就会每分钟可见地脉冲一次。正确答案是:已经生效的时段是空操作,所以心跳不会重启一段已经在往正确目标走的过渡。用户明确要求时,走另一条「立即应用」的路径。
而且必须可逆
关掉日程时,把面板交还给开启日程之前的状态——不是交还给某个默认值。用户原本设的是 80%,就拿回 80%,而不是 100%。
两个更小、但值得点名的决定
- 淡入淡出的时长调到「长到读得出是一次过渡,短到不觉得迟钝」——一个真实的取舍,说出来而不是藏起来。
- 休息(番茄钟式计时)可以调暗或遮罩屏幕。状态机带一键跳过,可以提前结束休息回到工作——因为一个不能跳过的休息,人们会干脆把整个功能关掉。
诚实的边界
- 它调暗的是画面,不是背光。低亮度下黑位不再是真的黑。
- 改白点是软件色温,不是硬件校准。要准确的颜色得上色度计。
- 它与 Night Shift、f.lux 属于同一类机制——我们不声称比这更高级。
相关
全部指南 · 外接显示器亮度怎么调 · 色彩发灰 · DDC/CI 无响应