Reactのキーボードイベントをクロスブラウザで確認する

React の `onKeyDown` / `onKeyPress` / `onKeyUp` / `onChange` の挙動が、クロスブラウザでどのように変わるのかを調査しました。


## 調査方法・内容

- それらのイベントに `event.key` / `event.keyCode` / `event.target.value` の値を記録するハンドラを設定し、ひとつの `<input type="text"/>` に全イベントを付与する。
- 下記の「キーボードの操作」をクロスOS/ブラウザ環境で行って、その履歴を保存する。

具体的には、[CodePen に書いた簡単な自作ツール](http://codepen.io/kjirou/full/XNoJag/) で行いました。


## 環境について

- 使用したハードウェアは、日本語キーボードの Mac Book Pro です。
- Win 仮想環境は VirtualBox で構築しており、また（参考記事が見つかりませんが） Mac のキーボードと連動する設定をした上で行っています。


## キーボードの操作
1. 「かな」を押す
2. 「A」を押す
3. 「K」を押す
4. 「A」を押す
5. 「スペース」を一度押して「赤」に変換する
6. 「Enter」を押して変換を確定する


## Mac/Chrome

| Event name | key   | keyCode | target.value |
|------------|-------|---------|--------------|
| onKeyDown  | a     | 229     |              |
| onChange   |       |         | あ           |
| onKeyUp    | a     | 65      | あ           |
| onKeyDown  | k     | 229     | あ           |
| onChange   |       |         | あｋ         |
| onKeyUp    | k     | 75      | あｋ         |
| onKeyDown  | a     | 229     | あｋ         |
| onChange   |       |         | あか         |
| onKeyUp    | a     | 65      | あか         |
| onKeyDown  |       | 229     | あか         |
| onChange   |       |         | 赤           |
| onKeyUp    |       | 32      | 赤           |
| onKeyDown  | Enter | 229     | 赤           |
| onChange   |       |         | 赤           |
| onKeyUp    | Enter | 13      | 赤           |


## Mac/Safari

| Event name | key          | keyCode | target.value |
|------------|--------------|---------|--------------|
| onKeyUp    | Unidentified | 0       |              |
| onChange   |              |         | あ           |
| onKeyDown  | Unidentified | 229     | あ           |
| onKeyUp    | Unidentified | 65      | あ           |
| onChange   |              |         | あｋ         |
| onKeyDown  | Unidentified | 229     | あｋ         |
| onKeyUp    | Unidentified | 75      | あｋ         |
| onChange   |              |         | あか         |
| onKeyDown  | Unidentified | 229     | あか         |
| onKeyUp    | Unidentified | 65      | あか         |
| onChange   |              |         | 赤           |
| onKeyDown  | Unidentified | 229     | 赤           |
| onKeyUp    |              | 32      | 赤           |
| onChange   |              |         | 赤           |
| onKeyDown  | Unidentified | 229     | 赤           |
| onKeyUp    | Enter        | 13      | 赤           |

- 最初の keyCode=0 の onKeyUp は、「かな」に対応しています。
- ~~`event.key` が `Unidentified` である~~点については、facebook/react の以下の Issue が参考になります。
  - [SyntheticEvent.key property is "unidentified" in Safari on Mac OS X](https://github.com/facebook/react/issues/7897)
  - 2017/08/01 に Mac OS X/Safari で確認したところ、正常に取得できていました
- なお、`event.key` が返す文字列の一覧は [getEventKey.js](https://github.com/facebook/react/blob/master/src/renderers/dom/shared/utils/getEventKey.js) にあります。


## Mac/Firefox

| Event name | key       | keyCode | target.value |
|------------|-----------|---------|--------------|
| onKeyUp    | KanjiMode | 21      |              |
| onKeyDown  | a         | 65      |              |
| onChange   |           |         | あ           |
| onChange   |           |         | あｋ         |
| onChange   |           |         | あか         |
| onChange   |           |         | 赤           |
| onChange   |           |         | 赤           |
| onKeyUp    | Enter     | 13      | 赤           |

- 大分少ないです。これは変換中のキー操作が一律フックできないためです。


## 仮想 Win8.1/IE11
| Event name | key         | keyCode | target.value |
|-----------|--------------|-----|------|
| onKeyUp   | Unidentified | 243 |      |
| onKeyDown | a            | 229 |      |
| onChange  |              |     | あ   |
| onKeyDown | k            | 229 | あ   |
| onChange  |              |     | あｋ |
| onKeyDown | a            | 229 | あｋ |
| onChange  |              |     | あか |
| onKeyDown |              | 229 | あか |
| onChange  |              |     | 赤   |
| onKeyDown | Enter        | 229 | 赤   |
| onKeyUp   | Enter        | 13  | 赤   |
| onKeyUp   | Enter        | 13  | 赤   |

- 変換確定時の onKeyUp で Enter が 2 回飛んでいます。
  - これは仮想環境であるが故なのだろうか・・・？


## 番外: `document.querySelector('input').value = "a"`

全環境で、`onChange` は反応しませんでした。


## まとめ
頑張りたくない人は `onChange` だけで過ごした方が良い。


## その他の参考サイト
- [Markdown Tables Generator](http://www.tablesgenerator.com/markdown_tables)
  - table タグをコピペして Markdown 形式に変換してくれるツール


----

折角なので、埋まってなかった [React Advent Calendar 2016](http://qiita.com/advent-calendar/2016/react) の 12 日目を乗っ取ってみたんですが、意外と精神にくるのでやらなければ良かったと思ってます・・・。