IME有効時の入力イベントを調べる


PC/Android/iOSでIME有効時に入力イベントが結構違ったので調べました。
調べた環境は以下の通りです。

OS ブラウザ
PC (Linux Mint 19.1 MATE) Chrome Ver.73.0
Android 8.0.0 (Galaxy S8) Chrome Ver.73.0
iOS 12.2 (iPhone 6) Safari 12.1

テキストボックスに文字を入力した際のイベントを調べました。
調べたイベントはkeydown, keyup, keypress, textInput, inputです。

(Androidはブラウザ以外にもキーボードアプリも影響あるのかな?)

IME有効 入力中(未確定)

ひらがなで文字を1文字ずつ入力している時のイベントです。

イベント PC Android iOS 取れる値
keydown 今回入力前の文字列
keyup ※OSにより違う
keypress 今回入力前の文字列
textInput
input 今回入力後の文字列

※keyupで取れる値は以下の通りでした。
PC: 前回確定済みの文字列
スマホ: 今回入力後の文字列

Androidは2文字目以降はなぜか上記イベントが2周走りました。
しかも2周目はkeydownでも今回入力後の文字列が取れてます。

IME有効 確定時

入力した文字を確定した時のイベントです。
PCであればEnterキーを押したタイミングの事ですね。

なお、スマホでは半角英数を入力していても確定処理はあり、
挙動は以下と同じでした。

イベント PC Android iOS 取れる値
keydown ※OSにより違う
keyup 今回確定後の文字列
keypress
textInput ※OSにより違う
input 今回確定後の文字列

※keydownで取れる値は以下の通りでした。
PC: 前回確定済みの文字列
Android: 今回確定後の文字列

※textInputで取れる値は以下の通りでした。
PC, iOS: 前回確定済みの文字列
Android: 今回確定後の文字列

iOSはなぜかinputイベントが3回走ります。
しかも、うち1回は前回確定済みの文字列がとれ、
2回は今回確定後の文字列が取れていました。

IME無効 入力時

IMEを無効にして半角英数字などを入力した時のイベントです。
スマホではIMEという概念がないので、IME有効時で書いた結果と同じです。
ただし、Androidのイベントが2周走る件は発生しません。

イベント PC Android iOS 取れる値
keydown 入力する前の文字列
keyup 入力した後の文字列
keypress 入力する前の文字列
textInput 入力する前の文字列
input 入力した後の文字列

文字削除時

BackspaceやDeleteで文字を削除した際のイベントです。
これはOSによる差分はなさそうです。

イベント PC Android iOS 取れる値
keydown 削除する前の文字列
keyup 削除した後の文字列
keypress
textInput
input 削除した後の文字列

文字列切り取り(カット)時のイベント

PCだと右クリック、スマホだと長押しして文字列の切り取りをした時のイベントです。
こちらもOSによる差分はなさそうです。

なお、PCでCtrl+xで文字を切り取った場合は
文字削除時の挙動と同じでした。
(たぶんキー入力による文字削除という点で同じなのかと)

イベント PC Android iOS 取れる値
keydown
keyup
keypress
textInput
input 削除した後の文字列

文字列貼り付け(ペースト)時のイベント

PCだと右クリック、スマホだと長押しして
文字列を貼り付けした時のイベントです。
こちらもOSによる差分はなさそうです。

イベント PC Android iOS 取れる値
keydown
keyup
keypress
textInput 貼り付けする前の文字列
input 貼り付けした後の文字列

なお、PCでCtrl+vで貼り付けした場合は以下でした。

イベント PC 取れる値
keydown 貼り付けする前の文字列
keyup 貼り付けした後の文字列
keypress
textInput 貼り付けする前の文字列
input 貼り付けした後の文字列

総評

レスポンシブなサイトを作るのであれば、OSにより差分のあるイベントはフックに使わない方が安全かもしれません。
使うのであれば差分をしっかり把握した上で使わないと事故りそうです。

取れる値が各イベント操作前の状態だったり操作後の状態だったりしますが
このへんはsetTimeoutをうまく使えば全て操作後の状態を取れる気がします。