3 つのプロパティ、3 つの異なる問い
KeyboardEvent はキーを識別する方法をいくつも公開していますが、それぞれが答えている問いは本当に異なります。event.key は、キーボードレイアウトと修飾キーが適用された後にキー押下が生み出す文字または名前付きの値です。物理的な A キーを押すと a、Shift を押しながらなら A、Dvorak や AZERTY のレイアウトではまったく別の文字になります。名前付きのキーは Enter、Escape、ArrowLeft、F5 といった説明的な文字列として届きます。
一方 event.code は物理的なキー位置を識別し、仮想的な US キーボードに由来するレイアウト非依存の名前を使います。A の位置にあるキーはユーザーのレイアウトが何を出力しようと常に KeyA です。最上段の数字は Digit1 から Digit0、テンキーは Numpad1 などを報告するため、2 列の数字を区別できます。
event.keyCode とその双子である event.which はレガシーな数値識別子です。どちらも仕様上は非推奨ですが、いまだにすべてのブラウザで実装されており、記号類についてはブラウザ間で値が一致しません。古いコードを保守する際には読む価値がありますが、新しいショートカット処理では key か code を使うべきです。
key と code のどちらを選ぶか
目安は単純です。位置が重要なら code、意味が重要なら key を使います。移動を WASD に割り当てるゲームは code を使うべきです。プレイヤーの左手の下にある物理的なキーの塊は、AZERTY キーボードで ZQSD を出力するとしても同じ位置にあるべきだからです。保存を Ctrl+S に割り当てるテキストエディタは key を使うべきです。ユーザーが考えているのは A の隣のキーではなく文字 S だからです。
修飾キーは独立した真偽値です:ctrlKey、shiftKey、altKey、metaKey。key から推測せず明示的に判定し、主要なショートカット修飾キーが macOS では Command、それ以外では Control であることを覚えておいてください。よくある書き方は event.metaKey || event.ctrlKey を受け入れ、1 つのハンドラで両プラットフォームをカバーする方法です。
event.location は重複するキーを区別します。標準キーは 0、左 Shift のような対になるキーの左側は 1、右側は 2、テンキー上のキーは 3 です。
実務上の落とし穴
すべてのキーが期待どおりのイベントを生成するわけではありません。ブラウザは一部の組み合わせを自分用に予約しています。Ctrl+W、Ctrl+T、Command+Q は通常、ページが見る前にタブを閉じたりアプリを終了したりし、preventDefault でも取り戻せません。ショートカットはハンドラに届くと決めつけず、実際のブラウザウィンドウで必ず試してください。
キーを押し続けると最初のイベントの後に event.repeat が true のリピートイベントが連続して発生します。一度だけ発火させたいショートカットではリピートを無視し、スクロールやカーソル移動のように連続的な動作では受け入れてください。
最後に、keydown と keyup はキーを、削除された keypress は文字を表していました。テキスト入力では input イベントを購読するか beforeinput を読む方が望ましく、IME の変換、オートコンプリート、モバイルキーボードをキーレベルのイベントよりはるかに確実に扱えます。