dwi2的碎念

不能只是曬網

JavaScript KeyboardEvent 2

| Comments

之前介紹過JavaScript的KeyboardEvent, 經過這兩週我又有了一些新的血淚控訴心得跟大家分享!!

特殊鍵(modifier keys)的處理

特殊鍵指的是ctrl, alt, windows鍵(或是Mac的command鍵), capslock等等. 這些鍵沒有character對應(ASCII), 所以大部分瀏覽器不會送出特殊鍵的keypress事件, 因此寫程式時只能用keydown/keyup事件偵測處理這些特殊鍵, 大部分瀏覽器不會送出特殊鍵的keypress事件.

在Firefox 15以上版本處理keydown/keyup事件時可以用getModfierState()取得特殊鍵狀態, 例如取得capslock作用與否可以用以下的code取得capslock狀態

1
2
3
4
function (evt) {
  var capslockOn = evt.getModifierState('Capslock');
  ...
}

如果capslock on, 回傳值為true.

getModifierState()是DOM level 3的API, IE 9和Firefox 15以上均有實作, Chrome目前尚無實作.

Chrome或是其他沒有getModifierState的瀏覽器該怎麼辦? 所幸大部分瀏覽器的KeyboardEvent都有下列這些屬性

event.shiftKey
event.ctrlKey
event.altKey
event.metaKey

分別可以取得shift, ctrl, alt, windows/command鍵是否被按下, 當然這只有在keydown/keyup事件裡面才可以取得, 因為大部分瀏覽器不會送出特殊鍵的keypress事件.

比較麻煩的特殊鍵就是Capslock或是Numlock這類在KeyboardEvent上沒有屬性可以取值的, 所幸現在有用Numlock的人不多了(很多筆電上甚至找不到Numlock在哪裡XDD), 所以忽略Numlock應該還算情有可原. 但Capslock的用量就大到無法忽略, 偵測Capslock時需要一些小技巧

偵測Capslock的目的通常只是為了要知道使用者輸入的英文字母是否為大寫, 例如在密碼輸入框偵測Capslock on時提示使用者目前輸入的都是大寫, 因此在無法取得getModifierState()的狀況下, 偵測Capslock on/off最直接的方式就是用keypress事件.

Keypress事件的keyCode代表的是ASCII值, 因此我們可以利用英文字母的大小寫ASCII值不同, 加上event.shiftKey為true/false, 來判斷keypress事件發生時Capslock是on還是off:

1
2
3
4
5
6
7
$('#some_input').keypress(function (e) {
  var s = String.fromCharCode(e.which);
  if (s.toUpperCase() === s && s.toLowerCase() !== s && !e.shiftKey) {
    // Capslock is on
    ...
  }
});

Stackoverflow上有一些範例可供參考.

event.preventDefault() 的影響

JavaScript Madness: Keyboard Events一文有提到, 通常我們會用event.preventDefault()取消event預設的處理動作, 但在某些瀏覽器中, 取消keydown事件預設處理動作會有副作用

副作用比較大的就是IE和Chrome, 在這兩個瀏覽器裡面, 如果把keydown事件的預設處理取消掉:

1
2
3
$('#some_input').keydown(function (e) {
  e.preventDefault(); // 取消keydown預設處理
});

Keypress事件就不會出現了!! 這點要特別注意, 當面臨要取消keydown事件的預設處理時, 請記得IE和Chrome有這個副作用 (我之前才為了這個問題卡關半天之久)

更好的Keyboard Event - DOM Level 3 Events

從上一篇到這篇一路看下來, 應該可以發現, 現在各家瀏覽器對於KeyboardEvent有著千變萬化的實作 Orz…

其實不只是KeyboardEvent, MouseEvent和WheelEvent(這個更誇張, 滾輪事件在各瀏覽器的class命名都不太一樣)也是充斥著數種差異甚大的實作, 讓現在的前端開發人員苦不堪言, 所幸W3C已經在訂定DOM Level 3 Events的draft了, 相信未來的前端開發人員(?)應該可以不用再寫一堆feature detection和為了提高相容性而寫的扭曲if-else判斷.

DOM Level 3: event.key和event.char

DOM Level 3的KeyboardEvent屬性中有char和key兩個屬性, 把原先的keycode/which/charCode的混亂狀況統一. char屬性帶的是按鍵的character (string type), 例如按下a鍵時event.char會是’a’, 但請勿把char和以前的charCode搞混, 因為charCode是該按鍵代表字串的ASCII數值(number type). 此外如果是特殊鍵的keyup/keydown事件, 由於特殊鍵沒有對應的character, DOM level 3規定此時event.char必須為empty string.

DOM Level 3 KeyboardEvent的key屬性代表的就是按鍵的key value(也是string type), 例如Capslock的event.key就會是’CapsLock’. 但目前DOM Level 3 只有列出部分key values, 仍在等待補完中.

DOM Level 3: 取消keydown的預設處理

之前有提到在Chrome和IE,取消keydown事件會讓keypress事件消失! 這件事也被寫入DOM Level 3的KeyboardEvent裡面. 所以IE和Chrome在這方面倒是挺領先的…

DOM Level 3: 特殊鍵處理

DOM Level 3也把getModifierState寫進去(), 因此以後偵測特殊鍵的狀況就更方便, 只要看event.getModifierState()就知道特殊鍵有沒有被按下, 例如以shift鍵來說

1
event.getModifierState('shift');

回傳值若為true就表示shift鍵此時已按下, false則相反. 目前Firefox 15以上版本已經有實作getModifierState().

小結

這陣子寫KeyboardEvent處理下來, 我覺得這實在是太血汗了, 套句暗黑3名言: “我也曾經當過JavaScript KeyboardEvent的冒險者呀! 但那不合我的胃口. 痛苦太多, 收穫太少!”, W3C還是趕快把DOM Level 3定稿下來逼(寫瀏覽器的)大家實作吧!

Comments