Opera で擬似的に composition events を実装する場合、様々な処理を最終的に keyup ハンドラ内で行うことになる。これはひとつ奇妙な振る舞いを引き起こす。キー入力は、基本的には keydown -> keypress -> input -> keyup の流れでイベントを発生させるのだが、しかし高速にキーボードを捌いたりすると、複数のキー入力の各サイクルがオーバーラップしてしまうことがある。
といっても Opera に問題があるわけではなく、つまりキーボードの打ち方の問題で、例えばあるキーを離す前に次のキーを押したりした場合だ。そうすると keydown -> keydown -> keyup -> keyup みたいな感じでイベントが発生する。
これを考慮しないと、正しく composition を認識できない。ので、考慮するようにした。
* * *
keydown および input イベントの引数 e を蓄えておくキュー、keyup イベントの引数 e を蓄えておくキューを保持する。前者のキューの 1 項目は、
{
keyDownEvent: { ... },
currentString: '',
inputEvent: [ ... ]
}
てな具合。keydown イベントハンドラで、keyCode が 229 だったら IME に対する入力とみなし、ハンドラ本体の本来の処理はせず、キューに必要な情報を埋めるだけにする。keyup イベントハンドラで、keydown キューの長さ – 1 == keyup キューの長さではない場合、つまり keydown イベントが複数回連続して発生した状況である場合は、keyup キューに必要な情報を埋めるだけにする。
keydown キューと keyup キューのバランスが正しい場合は keyup ハンドラ本来の処理を行うが、それに先駆けて溜まったキューを処理する。イベントの引数 e をもって keydown、input イベントハンドラを直接呼ぶ。
* * *
composition 文字列が更新されるごとに直前の文字列の長さを覚えておくようにし、暗黙的確定のようであれば直前の compositon 文字列のほうを採るようにした。つまり暗黙的確定にも対応した。
しかしだからといって Opera でも IME に対応しました! とはとても言えない。だいたい IME に対する入力時の keyCode、229 って何なのかさっぱりわからない(IE に準じているっぽいが)し、明示的確定では input イベントが連続して 2 回、暗黙的確定では 3 回とかどこにも文書化されてもおらずそもそもバグの産物なのかも知れず未来のバージョンでもそれが維持されるかもおぼつかない。ダメダメすぎる。Opera が悪い。