キーボードに入る前に、現代のデバイスには「何かを入力する」ための他の方法があることに注意してください。たとえば、人々は音声認識(特にモバイルデバイスで)や、マウスによるコピー/ペーストを使用します。
したがって、<input>
フィールドへの入力を追跡したい場合、キーボードイベントだけでは十分ではありません。<input>
フィールドの変更をあらゆる手段で追跡するためのinput
という名前の別のイベントがあります。また、それはそのようなタスクにとってより良い選択肢かもしれません。それについては、後の章イベント: change, input, cut, copy, pasteで説明します。
キーボードイベントは、キーボードアクション(仮想キーボードもカウントします)を処理したい場合に使用する必要があります。たとえば、矢印キー↑と↓やホットキー(キーの組み合わせを含む)に反応する場合です。
テストスタンド
キーボードイベントをよりよく理解するために、以下のテストスタンドを使用できます。
テキストフィールドで異なるキーの組み合わせを試してください。
kinput.onkeydown = kinput.onkeyup = kinput.onkeypress = handle;
let lastTime = Date.now();
function handle(e) {
if (form.elements[e.type + 'Ignore'].checked) return;
area.scrollTop = 1e6;
let text = e.type +
' key=' + e.key +
' code=' + e.code +
(e.shiftKey ? ' shiftKey' : '') +
(e.ctrlKey ? ' ctrlKey' : '') +
(e.altKey ? ' altKey' : '') +
(e.metaKey ? ' metaKey' : '') +
(e.repeat ? ' (repeat)' : '') +
"\n";
if (area.value && Date.now() - lastTime > 250) {
area.value += new Array(81).join('-') + '\n';
}
lastTime = Date.now();
area.value += text;
if (form.elements[e.type + 'Stop'].checked) {
e.preventDefault();
}
}
#kinput {
font-size: 150%;
box-sizing: border-box;
width: 95%;
}
#area {
width: 95%;
box-sizing: border-box;
height: 250px;
border: 1px solid black;
display: block;
}
form label {
display: inline;
white-space: nowrap;
}
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
<form id="form" onsubmit="return false">
Prevent default for:
<label>
<input type="checkbox" name="keydownStop" value="1"> keydown</label>
<label>
<input type="checkbox" name="keyupStop" value="1"> keyup</label>
<p>
Ignore:
<label>
<input type="checkbox" name="keydownIgnore" value="1"> keydown</label>
<label>
<input type="checkbox" name="keyupIgnore" value="1"> keyup</label>
</p>
<p>Focus on the input field and press a key.</p>
<input type="text" placeholder="Press keys here" id="kinput">
<textarea id="area" readonly></textarea>
<input type="button" value="Clear" onclick="area.value = ''" />
</form>
<script src="script.js"></script>
</body>
</html>
keydownとkeyup
keydown
イベントはキーが押されたときに発生し、keyup
イベントはキーが離されたときに発生します。
event.codeとevent.key
イベントオブジェクトのkey
プロパティを使用すると文字を取得でき、イベントオブジェクトのcode
プロパティを使用すると「物理キーコード」を取得できます。
たとえば、同じキーZはShiftキーと組み合わせて、または単独で押すことができます。これにより、小文字のz
と大文字のZ
という2つの異なる文字が得られます。
event.key
は正確に文字であり、異なる値になります。しかし、event.code
は同じ値になります。
キー | event.key |
event.code |
---|---|---|
Z | z (小文字) |
KeyZ |
Shift+Z | Z (大文字) |
KeyZ |
ユーザーが異なる言語を使用している場合、別の言語に切り替えると、"Z"
の代わりにまったく異なる文字になります。それがevent.key
の値になりますが、event.code
は常に同じ"KeyZ"
になります。
すべてのキーには、キーボード上の場所によって異なるコードがあります。キーコードはUI Events code specificationに記述されています。
たとえば
- 文字キーには
"Key<文字>"
というコードがあります。例:"KeyA"
,"KeyB"
など - 数字キーには
"Digit<数字>"
というコードがあります。例:"Digit0"
,"Digit1"
など - 特殊キーは名前でコード化されています。例:
"Enter"
,"Backspace"
,"Tab"
など
いくつかの普及したキーボードレイアウトがあり、仕様ではそれらのそれぞれにキーコードが提供されています。
その他のコードについては、仕様の英数字セクションを読むか、上記のテストスタンドでキーを押してください。
"KeyZ"
, "keyZ"
ではない明白に見えますが、人々はまだミスをします。
タイプミスを避けてください。keyZ
ではなく、KeyZ
です。event.code=="keyZ"
のようなチェックは機能しません。"Key"
の最初の文字は大文字である必要があります。
キーが文字を生成しない場合はどうなりますか?たとえば、ShiftやF1などです。これらのキーの場合、event.key
はevent.code
とほぼ同じです。
キー | event.key |
event.code |
---|---|---|
F1 | F1 |
F1 |
バックスペース | バックスペース |
バックスペース |
Shift | Shift |
ShiftRight またはShiftLeft |
event.code
は、どのキーが押されたかを正確に指定することに注意してください。たとえば、ほとんどのキーボードには、左側と右側に2つのShiftキーがあります。event.code
は、どのキーが押されたかを正確に示し、event.key
はキーの「意味」を担当します: それが何であるか("Shift")。
たとえば、ホットキーを処理したいとします: Ctrl+Z (またはMacの場合はCmd+Z)。ほとんどのテキストエディタは、それに「元に戻す」アクションをフックします。keydown
でリスナーを設定し、どのキーが押されているかを確認できます。
ここにはジレンマがあります。このようなリスナーでは、event.key
とevent.code
のどちらの値を確認する必要がありますか?
一方、event.key
の値は文字であり、言語によって変化します。訪問者のOSに複数の言語があり、それらを切り替える場合、同じキーで異なる文字が生成されます。したがって、常に同じであるevent.code
を確認するのが理にかなっています。
このように。
document.addEventListener('keydown', function(event) {
if (event.code == 'KeyZ' && (event.ctrlKey || event.metaKey)) {
alert('Undo!')
}
});
他方、event.code
には問題があります。異なるキーボードレイアウトでは、同じキーで異なる文字になる場合があります。
たとえば、ここに米国レイアウト("QWERTY")とその下のドイツレイアウト("QWERTZ")があります(Wikipediaより)
同じキーの場合、米国レイアウトには"Z"があり、ドイツレイアウトには"Y"があります(文字が入れ替わっています)。
文字通り、ドイツレイアウトを使用している人がYを押すと、event.code
はKeyZ
と等しくなります。
コードでevent.code == 'KeyZ'
をチェックすると、ドイツレイアウトを使用している人がYを押したときに、そのようなテストに合格します。
それは非常に奇妙に聞こえますが、その通りです。仕様では、このような動作を明示的に述べています。
そのため、event.code
は、予期しないレイアウトに対して誤った文字と一致する場合があります。異なるレイアウトの同じ文字が異なる物理キーにマップされ、異なるコードになる可能性があります。幸いなことに、それはいくつかのコード(例: keyA
, keyQ
, keyZ
(これまで見てきたように))でのみ発生し、Shift
などの特殊キーでは発生しません。 仕様でリストを見つけることができます。
レイアウトに依存する文字を確実に追跡するには、event.key
の方が良い方法かもしれません。
一方、event.code
には、物理的なキーの位置に常に同じままになるという利点があります。したがって、それに依存するホットキーは、言語を切り替えた場合でも正常に機能します。
レイアウトに依存するキーを処理したいですか? その場合は、event.key
を使用するのが良いでしょう。
それとも、言語を切り替えた後でもホットキーを機能させたいですか? その場合は、event.code
の方が良いかもしれません。
自動反復
キーが十分に長い時間押されている場合、キーは「自動反復」を開始します: keydown
が何度もトリガーされ、離されたときに最終的にkeyup
が発生します。したがって、多くのkeydown
と1つのkeyup
を持つのが正常です。
自動反復によってトリガーされたイベントの場合、イベントオブジェクトにはevent.repeat
プロパティがtrue
に設定されています。
デフォルトアクション
キーボードで開始できることがたくさんあるため、デフォルトアクションは異なります。
たとえば
- 文字が画面に表示されます(最も明らかな結果)。
- 文字が削除されます(Deleteキー)。
- ページがスクロールされます(PageDownキー)。
- ブラウザが「ページを保存」ダイアログを開きます(Ctrl+S)。
- …など。
keydown
でデフォルトアクションを防止すると、OSベースの特殊キーを除いて、ほとんどのアクションをキャンセルできます。たとえば、Windowsでは、Alt+F4で現在のブラウザウィンドウが閉じられます。そして、JavaScriptでデフォルトアクションを防止しても、それを止めることはできません。
たとえば、以下の<input>
は電話番号を想定しているため、数字、+
、()
、または-
以外のキーを受け入れません。
<script>
function checkPhoneKey(key) {
return (key >= '0' && key <= '9') || ['+','(',')','-'].includes(key);
}
</script>
<input onkeydown="return checkPhoneKey(event.key)" placeholder="Phone, please" type="tel">
ここでのonkeydown
ハンドラーは、checkPhoneKey
を使用して押されたキーをチェックします。それが有効(0..9
、または+-()
のいずれか)の場合、true
を返し、それ以外の場合はfalse
を返します。
上記のように、DOMプロパティまたは属性を使用して割り当てられたイベントハンドラーから返されたfalse
値は、デフォルトのアクションを防止するため、テストに合格しないキーの場合、<input>
には何も表示されないことがわかります。(返されたtrue
値は何も影響しません。false
を返すことのみが重要です)
Backspace, ←, →などの特殊キーが入力で機能しないことに注意してください。これは、厳密なフィルターcheckPhoneKey
の副作用です。これらのキーは、false
を返すようにします。
←, →の矢印キーと、Delete, Backspaceを許可して、フィルターを少し緩和しましょう。
<script>
function checkPhoneKey(key) {
return (key >= '0' && key <= '9') ||
['+','(',')','-','ArrowLeft','ArrowRight','Delete','Backspace'].includes(key);
}
</script>
<input onkeydown="return checkPhoneKey(event.key)" placeholder="Phone, please" type="tel">
これで、矢印と削除が正常に機能します。
キーフィルターがあっても、マウスと右クリック+貼り付けを使用して何でも入力できます。モバイルデバイスには、値を入力するための他の手段があります。したがって、フィルターは100%信頼できるとは限りません。
別の方法は、oninput
イベントを追跡することです。これは、変更後にトリガーされます。ここで、新しいinput.value
をチェックし、無効な場合は<input>
を変更/強調表示できます。または、両方のイベントハンドラーを一緒に使用することもできます。
レガシー
過去には、keypress
イベントと、イベントオブジェクトのkeyCode
, charCode
, which
プロパティがありました。
それらを扱うときに多くのブラウザの非互換性があったため、仕様の開発者は、それらすべてを廃止し、新しい最新のイベント(この章で上記に説明)を作成する以外に方法がありませんでした。古いコードは、ブラウザがサポートを継続しているため、まだ機能しますが、それらをもう使用する必要はまったくありません。
モバイルキーボード
IME (Input-Method Editor)として正式に知られている仮想/モバイルキーボードを使用する場合、W3C標準では、KeyboardEventのe.keyCode
は229
で、e.key
は"Unidentified"
である必要があると述べています。
これらのキーボードの中には、矢印キーやバックスペースキーなどの特定のキーを押したときに、e.key
、e.code
、e.keyCode
に正しい値が設定されるものもありますが、保証はありません。そのため、キーボードのロジックがモバイルデバイスで常に動作するとは限りません。
まとめ
キーを押すと、シンボルキーでも、ShiftやCtrlなどの特殊キーでも、常にキーボードイベントが発生します。唯一の例外は、ラップトップのキーボードにあることがあるFnキーです。これはOSよりも低いレベルで実装されていることが多いため、キーボードイベントは発生しません。
キーボードイベント
keydown
– キーを押したとき (キーを長く押すと自動的に繰り返される)、keyup
– キーを離したとき。
主なキーボードイベントプロパティ
code
– 「キーコード」("KeyA"
、"ArrowLeft"
など)。キーボード上のキーの物理的な位置に固有。key
– 文字 ("A"
、"a"
など)。Escなどの非文字キーの場合、通常はcode
と同じ値を持ちます。
以前は、キーボードイベントがフォームフィールドでのユーザー入力を追跡するために使用されることがありました。しかし、入力はさまざまなソースから来る可能性があるため、信頼性がありません。あらゆる入力 (コピー&ペーストや音声認識を含む) を処理するために、input
イベントと change
イベントがあります (この章の後半にある「イベント: change, input, cut, copy, paste」で説明します)。
キーボードイベントは、本当にキーボードが必要な場合に使用する必要があります。たとえば、ホットキーや特殊キーに反応する場合などです。
コメント
<code>
タグを使用し、複数行の場合は<pre>
タグで囲み、10行を超える場合はサンドボックス (plnkr, jsbin, codepen…) を使用してください。