<input>要素の日本語入力・カーソル挙動と Android での onKeyDown の制御
「Applibot Advent Calendar 2024」 19日目の記事になります。
はじめに
<input>
は一見シンプルですが、日本語入力 (IME) やモバイル環境、特にAndroid では独特の挙動があり、開発者を悩ませることがあります
実際に私もかなり苦しみました😢
この記事では、これらの課題と解決策を、実際のコード例とともに解説します
対象読者:
- Web 開発経験者 (HTML, CSS, JavaScript, TypeScript などの基礎知識がある方)
- 日本語入力周りの処理で困っている方
- <input> 要素のカーソル位置制御を理解したい方
- Android での入力関連の問題を解決したい方
日本語入力の制御
CompositionEvent
日本語入力で発火する以下のようなキーボードで入力を行った時に input
で発火するイベントが CompositionEvent
です。
CompositionEvent
には、以下の3つの種類があります。
onCompositionStart
入力開始時に発火する
compositionstart
イベントは、 IME などのテキスト変換システムが新しい変換セッションを開始した時に発生します。例えば、このイベントはユーザーがピン音 IME を使用して漢字の入力を開始した後に発生します。
onCompositionUpdate
入力値変更時に発火する
compositionupdate
イベントは、 IME などのテキスト変換システムによって制御されているテキスト変換セッションに新しい文字が入力されたときに発生します。例えば、このイベントは、ユーザーがピン音 IME を使用して漢字の入力をしている最中に発生します。
onCompositionEnd
入力値確定時に発火する
compositionend
イベントは、 IME などのテキスト編集システムが現在の編集セッションを完了またはキャンセルした時に発生します。例えば、このイベントは、ユーザーが ピン音 IME を使用して漢字の入力を完了した後に発生します。
CompositionEvent を利用する上での注意点:
単純に値を入力するだけであれば特に問題はないです
しかし値のフォーマットを行うような場合には、変換確定前の文字列は未確定であることによって onChange
イベントがうまく動かない場合があります
また、onChange
イベントでのフォーマットによってカーソル位置が末尾に移動してしまう可能性もあるので、カーソル位置の制御も考える必要がある場合もあります
カーソル位置の制御
<input> 要素のカーソル位置は、selectionStart
と selectionEnd
プロパティで取得でき、 input.setSelectionRange
で設定できます
const start = inputElement.selectionStart;
const end = inputElement.selectionEnd;
console.log(`カーソル位置/選択範囲: ${start} から ${end}`);
// カーソルを位置 5 に移動
inputElement.setSelectionRange(5, 5);
// 位置 3 から 6 までを選択
inputElement.setSelectionRange(3, 6);
カーソル位置の取得
input.selectionStart
selectionStart
はHTMLInputElement
インターフェイスのプロパティで、選択テキストの先頭インデックスを表す数値です。何も選択されていない場合は、<input>
要素内のテキスト入力カーソル(キャレット)の位置を返します。
input.selectionEnd
selectionEnd
はHTMLInputElement
インターフェイスのプロパティで、選択テキストの末尾のインデックスを表す数値です。選択がない場合、これは現在のテキスト入力カーソル位置の直後の文字のオフセットを返します。
カーソル位置の設定
input.setSelectionRange
HTMLInputElement.setSelectionRange()
メソッドは、<input>
または<textarea>
要素の中で現在のテキストの選択範囲の開始位置と終了位置を設定します。
Android 特有の挙動と対策
Android では、イベントの挙動が他の環境と異なり onKeyDown
の event.key
が Unidentified
になります
This is a known bug in Chrome on Android. See this other question and the official bug report. I wish I had better news for you, but it looks like you can't rely on keyboard triggers in web apps on Android if you need to capture the individual key values.
これによって onKeyDown
で特定のキーが押下された時に特定の処理をすることができなくなります。
例えば、削除キーが押下された時に特定の関数を走らせたくてもできない と言う問題があります。
対策
削除キー(Backspace, Delete)を押下した時の onChange
の event.nativeEvent.data
が null
になることを利用して特定の関数を実行する
まとめ
<input> 要素での日本語入力処理は、CompositionEvent、カーソル位置制御、Android への対応など、いくつか注意点があります
本記事で紹介したテクニックを活用することで、より快適なユーザー体験を提供できるWeb アプリケーションを開発できます
Discussion