34
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[JavaScript]日本語IME入力中か判定する方法

Last updated at Posted at 2022-06-02

概要

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.isComposing

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判定例

isComposingkeyはブラウザによって値が異なるため、現状、deprecatedのkeyCodeを判定に使わざるをえません。
しかし、keyCodeが削除されても動くように、isComposingkeyも使って以下のように判定するのが良いんじゃないでしょうか。

keydownでの判定イメージ
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判定例

keydownでの判定イメージ
window.addEventListener('input', e => {
  const imeTypes = ['insertCompositionText', 'deleteCompositionText', 'insertFromComposition', 'deleteByComposition'];
  if (imeTypes.includes(e.inputType)) {
     // IME入力中
  } else {
     // IME入力中でない
  }
});

compositionstartとcompositionendを使った判定

beforeinput は調べた全てのパターンで compositionstartcompositionendの間に発生するので、compositionstartcompositionendでフラグ管理してIME入力中かどうかを判定することもできます。

beforeinputでの判定イメージ
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の後に発生するので同じ方法を使えません。

34
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?