Mac 滑鼠滾輪一格一格地跳

macOS 把滑鼠滾輪當作一串離散的「格」交給應用程式,而觸控板拿到的是連續手勢。要讓滾輪變順暢,就得把這些格攔截下來、逐幀重新投遞——三個真實的坑就藏在這裡。

macOS 拿到滾輪後到底做了什麼

觸控板上報的是連續手勢——系統收到一串位置,並且知道手指還在動。滑鼠滾輪上報的是離散的「格」:一格就是一個事件,附帶一個行數,macOS 把它交給應用程式,然後就不管了。

所以滾輪「一格一格地跳」,不是哪裡壞了,而是它本來就被這樣要求:一格,一跳。會平滑滾輪的應用程式是自己做的;大多不做。

真正有效的機制

三步,缺一不可:

這正是開源專案 MOS 普及開來的架構,也是正確的做法——我們的滾動引擎是照它實作的,而不是另發明一個更差的滾輪。

坑一——並不是每一格都意味著「滾動」

這一條最咬人。在「照片」「地圖」「Keynote」「Numbers」以及大多數試算表裡,一格滾輪根本不是滾動,而是縮放的一步或翻一頁。

一旦平滑化,這一格會在你鬆手很久之後還在到達:照片從 80% 跳到 200%,簡報一次翻過十幾頁。使用者於是用「按應用程式加白名單」來繞開——而這恰恰是這類功能本該替人省掉的手工活。

所以在改造一個事件之前,引擎先問一個問題:這是滾動還是縮放?縮放語意的事件原樣放行,不做任何加工。對滾輪本來就是「按行精確」的應用程式同理——再加工只會更差,不會更好。

坑二——悄悄變成殭屍的顯示時鐘

CVDisplayLink 並不總能活過一夜。顯示器喚醒之後,或者發生重新配置(換線、過 KVM、改解析度),它可能停止投遞回呼,卻仍然聲稱自己在執行。

如果沒人檢查,外面看到的現象就是滾動突然不動畫了——以及「這應用程式莫名其妙壞了」。修法並不漂亮:假定這個時鐘會死,偵測它,然後重建它。

坑三——兩個工具搶同一個滾輪

同一層上的兩個事件監聽器都會消費滾輪。每個引擎都把對方吞掉的事件當成「輸入丟了」,又把自己重新發出的事件當成「新輸入」。兩個插值器於是互相追,結果就是滾動卡頓、翻倍,或者干脆停擺。

使用者很自然地得出結論:新裝的那個工具搞壞了我的滾動。把衝突說出來(「偵測到另一個滾動工具在執行」)遠比讓人盲目排查有用。

如果現在滾動就很難受,先查這幾條

誠實的邊界

平滑是改造輸入,不是創造輸入。它天然會帶來一點延遲,也無法讓一個本來就忽略精確增量的應用程式變好。當滾輪本來就已經正常時,正確答案是別去動它——這也正是上面那些語意與「按行精確」判斷存在的原因。

相關

DDC/CI 無回應 · 休眠後亮度被重置 · 文字發虛 · 色彩發灰 · 該用哪個工具?