概要
JavaScriptでキーボード押下時などに日本語IME入力中かを判定する方法のまとめです。
日本語入力周りのイベントは、2022年現在主だったブラウザでも挙動に差異があり面倒です。
IME(全角)入力におけるjsイベント現状調査
こちらの方の記事とだいぶ内容が被っていますが、私の調査結果と微妙に異なるところもあり、改めて自分なりにまとめています。
調査対象ブラウザ
- Chrome 99 (Mac)
- Firefox 98 (Mac)
- Safari 15 (Mac)
- Chrome 99 (Windows)
- Firefox 98(Windows)
- Edge 99(Windows)
※ Edgeはバージョン79からChromiumエンジンに変わっており、それ以前は挙動が全く異なると思われるので注意
日本語入力時に発生するイベントの流れ
まず、日本語入力時に発生するイベントとその発生順序を確認しました。
OSによる差はなかったので、ブラウザ種別だけで分けて記載しています。
日本語IMEが有効な状態で1文字目を入力
Chrome / Edge / Firefoxはkeydown
から始まりますが、Safariはkeydown
で終わるという真逆の挙動になります。
# | Chrome/Edge | Firefox | Safari |
---|---|---|---|
1 | keydown | keydown | compositionstart |
2 | compositionstart | compositionstart | compositionupdate |
3 | beforeinput | compositionupdate | beforeinput |
4 | compositionupdate | beforeinput | input |
5 | input | input | keydown |
2文字目を入力
こちらもkeydown
の位置がSafariとそれ以外で真逆です。
# | Chrome/Edge | Firefox | Safari |
---|---|---|---|
1 | keydown | keydown | compositionupdate |
2 | beforeinput | compositionupdate | beforeinput |
3 | compositionupdate | beforeinput | input |
4 | input | input | keydown |
EnterでIMEの変換を確定
Safariは2回input
が発生します。
後述しますが、この2回は1回目のinputTypeがdeleteCompositionText
、2回目のinputTypeがinsertFromComposition
になっており、一度テキストが消えて再挿入されるようなイベントの流れになっています。
# | Chrome/Edge | Firefox | Safari |
---|---|---|---|
1 | keydown | keydown | beforeinput |
2 | beforeinput | beforeinput | input |
3 | compositionupdate | compositionend | beforeinput |
4 | input | input | input |
5 | compositionend | compositionend | |
6 | keydown |
マウスクリックでIMEを終了
IME変換中に画面などをクリックするとIMEが終了しますが、その際Firefoxだけinput
が発生します。
# | Chrome/Edge | Firefox | Safari |
---|---|---|---|
1 | compositionend | beforeinput | compositionend |
2 | compositionend | ||
3 | input |
keydownイベントで日本語IME入力中か判定する
keydownイベントはSafari以外では文字入力の一番最初に発生するイベントなので、この時点で判定に使えるのは、keydownイベントで取得できるKeyboardEvent
オブジェクトだけになります。
具体的にはKeyboardEvent
の以下のプロパティを日本語IME入力の判定に使うことができます。
KeyboardEvent.isComposing
IMEなどテキスト変換システムが動作中であるかを示すboolean変数です。
この値で判定できれば良いのですが、この値はSafari以外ではIME入力の一文字目でfalseになります。
KeyboardEvent.key
IME入力中は値がProcess
になるという仕様があるのですが、MacのChromeとSafariはその仕様に対応していませんでした。
KeyboardEvent.key
IME and composition keys
"Process" [3]: The Process key. Instructs the IME to process the conversion.
[3] The Process key currently returns "Unidentified" in Firefox and Internet Explorer. Google Chrome returns the value of the key as if IME were not in use.
上記のMDNの説明だとFirefoxはUnidentified
を返すと書いていますが、実際に確認したらProcess
になっていたので、最近対応されたのかもしれません。
KeyboardEvent.keyCode
IME入力中は値が229
になります。
確認した全てのブラウザで共通でしたが、このプロパティはdeprecatedなのでそのうちなくなる可能性が高いです。
keydownイベントでの日本語IME判定例
isComposing
とkey
はブラウザによって値が異なるため、現状、deprecatedのkeyCode
を判定に使わざるをえません。
しかし、keyCode
が削除されても動くように、isComposing
とkey
も使って以下のように判定するのが良いんじゃないでしょうか。
window.addEventListener('keydown', e => {
if (e.isComposing || e.key === 'Process' || e.keyCode === 229) {
// IME入力中
} else {
// IME入力中でない
}
});
beforeinputとinputイベントでIME入力中か判定する
beforeinputとinputイベントではInputEvent
オブジェクトが取得でき、InputEventの以下のプロパティが日本語入力の判定に使えます。
InputEvent.isComposing
この値がtrueならIME入力中と判断できますが、このプロパティはまだSafariにサポートされていません。
InputEvent.inputType
Safari以外のブラウザでは、日本語入力中はどのタイミングでも(変換確定時も)insertCompositionText
になりました。
しかし、Safariのみ変換確定時の値が異なり、以下のようになります。
SafariのinputTypeの値
# | イベント | inputTypeの値 |
---|---|---|
文字入力 | beforeinut | insertCompositionText |
input | insertCompositionText | |
Enterで変換確定 | beforeinut | deleteCompositionText |
input | deleteCompositionText | |
beforeinut | insertFromComposition | |
input | insertFromComposition |
Safariも合わせると日本語入力中はinsertCompositionText、deleteCompositionText、insertFromCompositionの3つのinputTypeが発生しましたが、こちらの資料を見ると、deleteByComposition
という値もあるようです。
remove a part of the DOM in order to recompose this part using IME
との説明があります。
いまいちどういう状況で発生するものなのかわかりませんが、using IMEとあるのでこの値もIME入力中とみなすことにします。
beforeinputとinputイベントでの日本語IME判定例
window.addEventListener('input', e => {
const imeTypes = ['insertCompositionText', 'deleteCompositionText', 'insertFromComposition', 'deleteByComposition'];
if (imeTypes.includes(e.inputType)) {
// IME入力中
} else {
// IME入力中でない
}
});
compositionstartとcompositionendを使った判定
beforeinput
は調べた全てのパターンで compositionstart
と compositionend
の間に発生するので、compositionstart
と compositionend
でフラグ管理してIME入力中かどうかを判定することもできます。
var isComposing = false;
window.addEventListener('compositionstart', e => {
isComposing = true;
});
window.addEventListener('compositionend', e => {
isComposing = false;
});
window.addEventListener('beforeinput', e => {
if (isComposing) {
// IME入力中
} else {
// IME入力中でない
}
});
ただし、input
イベントについては、Firefoxのみ変換確定時compositionend
の後に発生するので同じ方法を使えません。