@kyanny's blog

My thoughts, my life. Views/opinions are my own.

キーイベント (keydown, keypress) の、ブラウザ/OS による微妙な違い

忘れないうちにメモ。時間できたらコードとかリファレンスの記載とかいろいろまとめたい。

onkeydown イベントでキーリピートが発生するかどうかはプラットフォームに依存する

キー操作可能なカスタム DHTML ウィジェット | MDNの一番下経由で、91592 - Inconsistent keydown repeat behavior across platformsの8番目のコメント。

Here's what IE does:
To start with, the only keys that get keypress in IE are printable keys.
So right developers need to use onkeydown if they want the convenience of
declarative syntax instead of using addEventListener.

IE repeats onkeydown. For onkeypress. it also repeats if it is getting fired
(again, it onkeypress is only fired for printable keys).

Here's what Mozilla does:
We fire onkeypress for all keys, not just printable keys.
We repeat both onkeydown and onkeypress on Windows, but not on all platforms. On
some platforms we only repeat onkeypress. I haven't gone through and
test/analyzed code to see where we differ and where we don't.
https://bugzilla.mozilla.org/show_bug.cgi?id=91592#c8

ちゃんと訳せないけど要するに、

  • IE では onkeypress イベントで印字可能なキー(英数記号くらい?)しか拾えないので onkeydown イベントを使え
  • IE では onkeydown イベントが繰り返される(キーリピートが発生する)
  • Mozilla ではすべてのキーで onkeypress イベントが発生する
  • Windows では onkeydown も onkeypress もキーリピートが発生するが他のプラットフォームだと onkeypress しかリピートしないこともある (Mac はたぶんこれ)

ということで、例えば LDRize 的なものを実装したくなった場合は、 IE か mozilla かで onkeypress と onkeydown を使い分ける必要がある。同じイベントハンドラが違うイベントで発火するように同じキーを割り当てる。めんどい。

onkeypress で押されたキーの ASCII コードが得られないことがある (0 になってしまう)

たぶんこのページかJavaScript - Detecting keystrokesこのページEvents - keydown, keypress, keyupに書いてあった。

えーとかなり複雑なので頭がパンクしそうだけど、

  • keydown/keyup と keypress イベントで keyCode/charCode が返す値が違う
  • さらにそれにブラウザとプラットフォームの組み合わせによる違いが加わる

ので非常にややこしいことになっていて、具体的には Firefox で左右アローキーの onkeypress イベントを拾うと event.which とかでキーの ASCII コードが得られなくて 0 になってしまう。のでキーボードショートカット的な用途には使えない。なのでここも onkeydown イベントを使ったりする必要がある。とてもめんどい。

Opera が onkeydown イベントの e.preventDefault() を無視する

ultra blue:JavaScript : Opera と Firefox でのキーイベントの違いに詳しい。左右アローキーの例だと、横スクロールが出てるときに右アローキー押してイベントハンドラが fire すると同時にスクロールもしちゃうとださい、みたいなときにイベントハンドラの中で e.preventDefault() すると思うけど、 Opera の場合 onkeydown イベントの中で preventDefault() しても無視されちゃうので onkeypress イベントでハンドラを設定しておかないと同じ挙動にならない。ちょっとめんどい。