KeyboardEvent: key プロパティ
========================

`KeyboardEvent` インターフェイスの **`key`** プロパティは読み取り専用で、ユーザーが押したキーの値を、 `Shift` キーなどの修飾キーやキーボードのロケールやレイアウトを考慮した値で返します。

値
-

文字列です。

この値は、以下のように決定されます。

* 押されたキーが表示可能なものである場合、返される値は、そのキーの表示可能な表現を含む空でない Unicode 文字列になります。
* 押されたキーが制御文字や特殊文字の場合、返される値は事前に定義されたキー値のいずれかになります。
* もし `KeyboardEvent` がデッドキーが押されたことを表している場合は、キー値は "`Dead`" になります。
* 一部の特殊なキーボードのキー（マルチメディアキーボードでメディアを制御するための拡張キーなど）は、 Windows ではキーコードを生成しません。その代わりに、 `WM_APPCOMMAND` イベントが発生します。これらのイベントは DOM キーボードイベントにマッピングされ、 Windows の「仮想キーコード」にリストアップされます（実際にはキーコードではありませんが）。
* キーを特定できない場合、返される値は `Unidentified` になります。

キー値の完全なリストをご覧ください。

KeyboardEvent の順序
-----------------

それぞれの `KeyboardEvent` はあらかじめ定められた順序で発生します。キーが押された場合、発生する一連の `KeyboardEvent` は `Event.preventDefault` が呼び出されないと仮定すれば次のようになります。

1. 最初に `keydown` イベントが発生します。キーがそれ以上押され続けてそのキーが文字を入力する場合は、イベントはプラットフォームの実装に依存した間隔で発生し続け、読み取り専用の `KeyboardEvent.repeat` プロパティが `true` に設定されます。
2. もしキー入力が `<input>`、`<textarea>`もしくは`HTMLElement.contentEditable` が `true` の要素に文字を挿入する場合は、 `beforeinput` と `input` イベント型がその順番で発生します。一部の他の実装では、 `keypress` イベントを実装していれば発生する可能性があることに注意してください。イベントはキーが押されている間、連続で発生します。
3. キーを離した際に `keyup` イベントが発生します。これで一連の処理は終わりです。

1 と 3 の処理で、 `KeyboardEvent.key` 属性が定義され、先ほど定義したルールに則って値が設定されます。

一連の KeyboardEvent の例
--------------------

米国キーボードレイアウトで `Shift` キーと `2` キーを使用した場合と、英国キーボードレイアウトで使用した場合のイベントシーケンスについて考えてみましょう。

以下の 2 つのテストケースを使用して実験してみてください。

1. `Shift` キーを押しながら、 `2` キーを押して離します。次に `Shift` キーを離します。
2. `Shift` キーを押しながら、 `2` を押し続けます。 `Shift` キーを離します。最後に `2` を離します。
### HTML


```html
<div class="fx">
  <div>
    <textarea rows="5" name="test-target" id="test-target"></textarea>
    <button type="button" name="btn-reset" id="btn-reset">Reset</button>
  </div>
  <div class="flex">
    <pre id="console-log"></pre>
  </div>
</div>
```

### CSS


```css
.fx {
  -webkit-display: flex;
  display: flex;
  margin-left: -20px;
  margin-right: -20px;
}

.fx > div {
  padding-left: 20px;
  padding-right: 20px;
}

.fx > div:first-child {
  width: 30%;
}

.flex {
  -webkit-flex: 1;
  flex: 1;
}

#test-target {
  display: block;
  width: 100%;
  margin-bottom: 10px;
}
```

### JavaScript


```js
let textarea = document.getElementById("test-target"),
  consoleLog = document.getElementById("console-log"),
  btnReset = document.getElementById("btn-reset");

function logMessage(message) {
  consoleLog.innerHTML += `${message}<br>`;
}

textarea.addEventListener("keydown", (e) => {
  if (!e.repeat) {
    logMessage(`Key "${e.key}" pressed [event: keydown]`);
  } else {
    logMessage(`Key "${e.key}" repeating [event: keydown]`);
  }
});

textarea.addEventListener("beforeinput", (e) => {
  logMessage(`Key "${e.data}" about to be input [event: beforeinput]`);
});

textarea.addEventListener("input", (e) => {
  logMessage(`Key "${e.data}" input [event: input]`);
});

textarea.addEventListener("keyup", (e) => {
  logMessage(`Key "${e.key}" released [event: keyup]`);
});

btnReset.addEventListener("click", (e) => {
  let child = consoleLog.firstChild;
  while (child) {
    consoleLog.removeChild(child);
    child = consoleLog.firstChild;
  }
  textarea.value = "";
});
```

### 結果

**メモ:** `beforeinput` と `input` イベントで使用されている `InputEvent` インターフェイスを完全に実装していないブラウザーでは、誤ったログ出力をする可能性があります。

### ケース 1

Shift キーが押されると、まず `keydown` イベントが発行され、 `key` プロパティの値として文字列 `Shift` が設定されます。このキーを押し続けても、文字が発生しないので `keydown` イベントが繰り返し発行され続けるわけではありません。

`2 キー`が押されると、この新しいキー押下に対して別の `keydown` イベントが発行され、修飾キー `shift` が有効なので、このイベントの `key` プロパティ値には米国のキーボード型の場合は `@` 、英国のキーボード型の場合は `"` という文字列が設定されます。文字キーが生成されたので、次に `beforeinput` と `input` イベントが発行されます。

`2 キー`を離すと、`keyup` イベントが発行され、`key` プロパティにはそれぞれ異なるキーボードレイアウト用の `@` と `"` という文字列が保持されるようになります。

最後に `shift` キーを離すと、別の `keyup` イベントが発行され、 key 属性の値は `Shift` のまま残ります。

### ケース 2

Shift キーが押されると、まず `keydown` イベントが発行され、`key` プロパティの値として文字列 `Shift` がセットされます。このキーを押し続けても、文字キーは生成されないので、 keydown イベントは繰り返し発行され続けることはありません。

`2 キー`が押されると、この新しいキー押下に対して別の `keydown` イベントが発行され、修飾キー `shift` が有効になっているので、そのイベントの `key` プロパティの値は、米国キーボード型の場合は `@` 、英国キーボード型の場合は `"` という文字列に設定されています。文字が生成されたので、次に `beforeinput` と `input` イベントが発行されています。キーを押し続けると、`keydown` イベントが繰り返し発行され、`KeyboardEvent.repeat`プロパティは `true` にセットされています。同様に `beforeinput` と `input` イベントが繰り返し発行されています。

`Shift` キーを離すと、それに対して `keyup` イベントが発行され、キー属性の値は `Shift` のままとなります。このとき、修飾キー `shift` は有効ではなくなるので、`2 キー`を押したときの keydown イベントを繰り返すための `key` プロパティの値が "2" になっていることに注目してください。同じことが `beforeinput` と `input` イベントの `InputEvent.data` プロパティにも当てはまります。

最後に `2 キー`を離すと、`keyup` イベントが発行されますが、修飾キー `shift` はもはやアクティブではないので、`key` プロパティはどちらのキーボードレイアウトでも、文字列値 `2` に設定されます。

例
-

この例では `EventTarget.addEventListener()` を使用して `keydown` イベントを待ち受けています。イベントが発生すると、キーの値がチェックされ、コードが関心を持つキーの一つであるかどうかが確認され、もしそうであれば、何らかの方法で処理されます（宇宙船の操縦や、スプレッドシートの選択セルの変更など）。


```js
window.addEventListener(
  "keydown",
  (event) => {
    if (event.defaultPrevented) {
      return; // Do nothing if the event was already processed
    }

    switch (event.key) {
      case "ArrowDown":
        // Do something for "down arrow" key press.
        break;
      case "ArrowUp":
        // Do something for "up arrow" key press.
        break;
      case "ArrowLeft":
        // Do something for "left arrow" key press.
        break;
      case "ArrowRight":
        // Do something for "right arrow" key press.
        break;
      case "Enter":
        // Do something for "enter" or "return" key press.
        break;
      case "Escape":
        // Do something for "esc" key press.
        break;
      default:
        return; // Quit when this doesn't handle the key event.
    }

    // Cancel the default action to avoid it being handled twice
    event.preventDefault();
  },
  true,
);
```

仕様書
---

| Specification |
| --- |
| UI Events # dom-keyboardevent-key |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.