Skip to content

滑鼠測試能測出什麼:瀏覽器滑鼠事件看得到與看不到的 ​

滑鼠測試能測出什麼:網頁收得到按鍵事件,但測不到 DPI、回報率,也讀不到系統的雙擊速度設定

圖:網頁收得到按鍵事件,卻拿不到 DPI、回報率和系統的雙擊速度設定。

滑鼠按一下卻變成兩下(俗稱連點),或側鍵好像沒反應時,很多人會先上網找個「滑鼠測試」網站按按看。我最近也做了一個:Device Tester 裝置測試 ↗。它可以測五顆按鍵、雙擊間隔、滾輪,還有每秒點幾下(CPS,Clicks Per Second)。

本來以為這只是個小工具。做完才發現,整個設計都繞著一個問題打轉:網頁到底知道什麼? 答案是:網頁只知道瀏覽器轉交給它的「事件」。滑鼠的硬體、韌體、驅動程式和作業系統設定,網頁一樣都碰不到。所以工具頁面上寫得很直白:它只看瀏覽器收到的事件,不能直接診斷硬體。

這篇把開發時弄懂的幾件事整理出來。程式碼看不懂也沒關係,直接跳過不影響閱讀。

看得到的:按鍵、點擊與滾輪事件 ​

先講什麼是「事件」。你每按一下、放開、滾一下,瀏覽器就會發一則通知給網頁,告訴它剛剛發生了什麼。這則通知就叫事件。網頁能拿到的滑鼠資訊,全都來自下面這幾種:

  • pointerdown/pointerup:按下與放開。pointer 是「指標」,滑鼠、觸控筆、手指都算。這兩個事件會附上三項資訊:pointerType 是哪種裝置(mouse 是滑鼠、pen 是觸控筆、touch 是手指),button 是這次動到哪一顆鍵,buttons 是現在按住了哪些鍵。
  • click、dblclick、auxclick、contextmenu:瀏覽器根據你的按下和放開,自己整理出來的事件,分別代表「點一下」「點兩下」「用左鍵以外的鍵(例如中鍵)點了一下」和「叫出右鍵選單」。
  • wheel:滾輪。會附上橫向和直向各滾了多少(deltaX、deltaY),以及這個數字的單位(deltaMode)。

最容易搞混的是 button 和 buttons,因為兩邊的編號不一樣:

按鍵button 的值buttons 的號碼
左鍵01
中鍵(滾輪鍵)14
右鍵22
上一頁鍵38
下一頁鍵416

button 是一個編號,說的是「這一次動到哪顆鍵」。buttons 則是一個總和:每顆鍵各有一個號碼(1、2、4、8、16),現在按住哪幾顆,就把它們的號碼加起來。例如左鍵和右鍵一起按住,buttons 就是 1 + 2 = 3。這些號碼都是 2 的次方,怎麼加都不會撞號,工程師把這種寫法叫「位元遮罩」(bitmask)。

另外要注意,中鍵和右鍵的順序在兩邊剛好相反:button 是中鍵 1、右鍵 2;buttons 反過來,右鍵 2、中鍵 4。

工具只替這五顆鍵取名字。其他 button 值一律照實列在「其他按鍵代碼」底下,不去猜它是什麼鍵。

Device Tester 按鍵測試畫面:左鍵與中鍵顯示已測過,右鍵顯示按下中,兩顆側鍵顯示未偵測,下方列出最近的瀏覽器事件

圖:按過左鍵和中鍵、右鍵還按著的畫面。事件紀錄的「按鍵位元遮罩」就是 buttons:中鍵按下時是 4,右鍵是 2,跟上面的表一樣。

坑一:兩鍵同按時,第二顆鍵沒有 pointerdown ​

這個坑是我讓 AI agent 用程式操作 Chrome、做上線前的自動測試時抓到的。我照這個順序按:先按住左鍵,再加按右鍵,接著放開左鍵,最後放開右鍵。實際收到的事件是:

text
pointerdown  button=0  buttons=1   ← 按下左鍵
pointermove  button=2  buttons=3   ← 加按右鍵(不是 pointerdown)
pointermove  button=0  buttons=2   ← 放開左鍵(不是 pointerup)
pointerup    button=2  buttons=0   ← 放開右鍵

pointermove 本來是「滑鼠移動了」的事件,這裡卻用來通知按鍵的變化。這不是 Chrome 的 bug。瀏覽器處理滑鼠、觸控筆和手指,有一套共同的標準,叫 Pointer Events 規格。規格對多鍵同按本來就這樣規定:從「一顆鍵都沒按」變成「有鍵按著」,才送 pointerdown;全部放開了,才送 pointerup。中間多按一顆或先放一顆,都藏在 pointermove 裡。

我的第一版只理會 pointerdown 和 pointerup,所以兩顆鍵一起按時,畫面上只有左鍵會亮。

兩鍵同按的事件時間軸:按下左鍵送出 pointerdown,加按右鍵與先放開左鍵都只送出 pointermove,放開右鍵才送出 pointerup,每一步的 buttons 分別是 1、3、2、0

圖:兩顆鍵一起按時,中間兩步只送出 pointermove,要看 buttons 的數字才知道哪些鍵還按著。

修法是:每收到一次 pointermove,就拿 buttons 重新對一次「現在按住哪些鍵」。滑鼠一動,pointermove 就會連續送來一大串,所以只要 buttons 沒變,程式就直接沿用原本的狀態,畫面也不必跟著重畫(這個工具的畫面是用 Vue 做的)。pointermove 也不寫進事件紀錄、不送任何統計,它只負責校正按鍵狀態。

也因為這樣,工具的「最近的瀏覽器事件」清單只記按下、放開和點擊。兩鍵同按時,清單可能少了第二顆鍵的「按下」,或是多出一筆「放開」,卻找不到跟它配對的「按下」。這點我也寫進了工具頁面的「結果判讀」。

細節:在測試區外面放開按鍵 ​

還有一種情況:在測試區按下,拖到外面才放開。為了不漏掉這一下,按下的當下,我會替測試區呼叫 setPointerCapture。意思是「這個指標接下來的事件,就算游標跑出去了,也都先交給我」,等所有按鍵都放開才交還。

另外,我也讓整個視窗(window)接收 pointerup 和 pointercancel,當作保險:萬一測試區漏接,視窗還接得到。pointercancel 是瀏覽器中途取消這次操作時送來的事件。它不會告訴你是哪顆鍵(button 會是 -1),而且在它之後,瀏覽器也不會再送這個指標的事件。所以一收到它,就把所有按住的鍵一起清掉,免得畫面上某顆鍵永遠停在「按下中」。

坑二:click 不一定是滑鼠點的 ​

手機上用手指點一下螢幕,會觸發 click。用鍵盤選到按鈕(例如按 Tab 移過去)再按 Enter,也會觸發 click。如果照單全收,手指點螢幕、鍵盤按 Enter,都會被當成滑鼠左鍵。所以我訂了三條規則:

  1. detail 記的是「連續點到第幾下」。鍵盤觸發的 click,這個數字會是 0,所以 detail 是 0 的 click 不算。
  2. 現在的瀏覽器送來的 click 會附上 pointerType,有附就只認 mouse。
  3. 有些瀏覽器送來的 click 沒有 pointerType,這時就看同一個測試區上一次按下(pointerdown)是什麼裝置。

這樣做有個代價:完全不支援 Pointer Events 的瀏覽器,在雙擊測試區會一直沒有數字。我寧可它「沒有資料」,也不要它「把觸控當成滑鼠」。這也跟頁面上「只記錄實體滑鼠輸入」的說明一致。

點擊速度(CPS)測試更嚴格:只算滑鼠左鍵「按下」的那一刻(pointerType 是 mouse、button 是 0 的 pointerdown),不看 click。

看不到的:這幾件事網頁測不出來 ​

作業系統的雙擊速度 ​

Windows 和 macOS 都能設定「兩下要多快才算雙擊」。網頁讀不到這個設定,也就沒辦法照系統的標準,判斷這兩下算不算雙擊。所以雙擊測試區把兩件事分開顯示:

  • 自己算的間隔:同一顆鍵前後兩次點擊隔了幾毫秒,最新的排最前面。
  • 瀏覽器的 dblclick 次數:瀏覽器依照系統設定,判斷前後兩下夠快、算成一次雙擊時,會另外送出一個 dblclick,這個數字才會加一。

Device Tester 雙擊測試畫面:瀏覽器 dblclick 事件顯示 2,最近的同按鍵間隔是 181 毫秒,下方依序列出每次的點擊間隔

圖:在雙擊測試區點了幾下。每次的間隔排成一列,瀏覽器的 dblclick 次數另外計算。

如果你明明只按一下,卻多了一個間隔很短的新紀錄,或 dblclick 次數增加了,代表這一下讓瀏覽器收到了兩次點擊。這很像微動開關(滑鼠按鍵底下的小開關)彈跳造成的連點:按一下,開關卻接觸了兩次。但網頁沒辦法確認,因為瀏覽器、擴充套件和系統的輸入設定都可能影響結果。

所以工具只把事件列出來,不替硬體下結論。它會建議你:換個瀏覽器比較、檢查系統的雙擊速度、暫時停用滑鼠相關的擴充套件,或把滑鼠接到另一台電腦試試。

上一頁、下一頁側鍵 ​

很多滑鼠側邊有「上一頁」「下一頁」兩顆鍵。瀏覽器和作業系統常把它們拿來做換頁之類的事,滑鼠附的驅動軟體也可能改掉按鍵設定。所以按下去,網頁不一定收得到。側鍵顯示「未偵測」,意思是「這個頁面還沒收到它的事件」,不是「它壞了」。

滾輪到底滾了幾格 ​

滾輪的 deltaY 很容易被當成「滾了幾格」。其實它的單位要看 deltaMode:0 是像素、1 是行、2 是頁。數字本身也是瀏覽器和系統處理過的結果,不同裝置、不同平台給的差很多。所以工具照原樣顯示數字和單位,方向則看橫向和直向哪邊滾的量比較大(不管正負號),就判斷成那個方向。滾輪測試區也不攔截捲動,頁面照樣可以捲,不會把人困在測試區裡。

Device Tester 滾輪測試畫面:事件清單照原樣列出每一筆的方向、deltaX、deltaY 與單位(像素)

圖:滾輪測試區照原樣列出 deltaX、deltaY 和單位。負數代表往左或往上,方向看橫向、直向哪邊滾的量比較大。

DPI、回報率與硬體延遲 ​

同樣的道理,DPI、回報率和硬體延遲,網頁也都讀不到。DPI 是滑鼠每移動一英吋回報幾個點,很多人叫它靈敏度;回報率是滑鼠每秒向電腦回報幾次;硬體延遲是從你按下或移動滑鼠,到訊號送進電腦,中間花的時間。拿回報率來說,瀏覽器通常會把密集的移動事件合併,配合畫面更新的節奏才交給網頁,所以網頁數到的 pointermove 次數,不等於滑鼠實際回報的次數。與其給一個看起來很專業、其實不準的數字,我乾脆不顯示這些項目,並在說明裡寫清楚原因。

點擊速度怎麼算才不灌水 ​

CPS 就是每秒點幾下。測試從你點第一下開始計時,這一下也算在內。時間可以選 1、5、10、30 秒,也可以自己輸入 1 到 60 之間的整數秒數。

剛開始的一瞬間,經過的時間太短,算出來的即時速度會暴衝。例如才過 0.05 秒就點了兩下,換算起來就是每秒 40 下。所以前 250 毫秒先不顯示即時速度,畫面停在 0.00,點擊還是照算。時間到了之後,成績一律用「總點擊數 ÷ 完整秒數」計算。

Device Tester 點擊速度測試畫面:5 秒測試完成,點擊次數 28,剩餘時間 0.0 秒,CPS 與本機最佳紀錄都是 5.60

圖:5 秒測試結束的畫面。28 下除以 5 秒,CPS 是 5.60。

最佳成績存在 localStorage。這是瀏覽器內建的一小塊儲存空間,資料只會留在你用的這個瀏覽器裡。每種測試時間各留一筆最高分,一個按鈕就能清掉。

隱私:事件不離開你的瀏覽器 ​

滑鼠測試看起來無害,但事件資料其實很詳細:每一次按鍵的時間、間隔、滾輪數值都有。所以規則訂得很嚴:

  • 只用標準的 Pointer、Mouse 與 Wheel 事件,不要求相機、麥克風或任何裝置權限。
  • 按鍵代碼、座標、事件時間、點擊間隔、滾輪數值和成績,都不會送到分析服務(Google Analytics)。
  • 工具自己送出的分析事件只有幾種固定的:開始了哪一項測試,以及「完成」「重設」「清除本機紀錄」這幾個動作,另外附上用的是哪個語言。
  • 「頁面瀏覽」事件(page_view)和站上其他工具一樣,照 Google Analytics 的預設記錄:打開頁面時記一筆,在站內切換工具時(例如從滑鼠測試換到鍵盤測試)也各記一筆。記的網址不含 # 之後的片段,所以在滑鼠測試裡切換四種模式不會另記。
  • Google Signals(Google 利用使用者登入的帳號,把不同裝置的造訪串起來統計的功能)和廣告個人化,我都關掉了。
  • 原始事件只放在記憶體裡,離開或重新整理頁面就會消失。

小結 ​

  1. 網頁只看得到事件:滑鼠硬體、驅動程式和作業系統設定,網頁都碰不到。
  2. 兩鍵同按藏在 pointermove 裡:要用 buttons 的總和對帳,不能只看按下和放開。
  3. 先排除不是滑鼠的輸入:鍵盤觸發的 click 和手指觸控都不算。
  4. 測不到的就不假裝測得到:系統的雙擊速度設定、DPI、回報率測不到,就老實寫出來,比硬給一個數字有用。

工具在這裡:Device Tester 裝置測試 ↗,打開瀏覽器就能測,不用安裝。各項測試的用法,可以看 Device Tester 工具介紹。

口袋工具哪裡怪怪的? 回報問題(另開分頁)