94
37

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 3 years have passed since last update.

ブラウザでIME確定時のEnterキー入力をハンドリングしない

Last updated at Posted at 2019-07-29

IMEまわりのキー入力制御ではDeprecatedなAPIを使わなくちゃいけない、悲しいね。というお話です。

背景

入力フォームでEnterキー押下時に、フォームの内容を確定したいことがあります。

素朴に実装すると次のようなソースコードです。

<input id="input">
<span id="message">
<script>
input.addEventListener('keydown', (e) => {
  if(e.key === 'Enter') {
    message.innerText = '確定'
  }
})
</script>

keydownイベントを監視し、イベントのkeyEnterであれば確定とします。

問題

このコードには問題があります。

Firefox(68.0.1)とWindowsのGoogle Chromee(75.0.3770.142)では期待通りに動作します。
MacのGoogle Chrome(75.0.3770.142)とSafari(12.1.2)では、日本語を入力するとき、期待通りに動作しません。
変換確定のEnterを、フォームの確定として扱ってしまいます。

https://codepen.io/ledsun/pen/bXggJN に動作サンプルがあるので試してみてください。

原因

前述の2ブラウザでは、IMEの確定時にkeydownイベントのkeyプロパティがEnterになります。

対策

必要なのはIME確定時のEnterとそれ以外のEnterを見分ける方法です。

次の作戦はどちらか一方を採用すればよいです。
両方やる必要はありません。

作戦1 keyプロパティの代わりにkeyCodeプロパティを使う

keydownイベントのKeyboardEvent.keyCodeプロパティは、

If an Input Method Editor is processing key input and the event is keydown, return 229.

とあるように、IME確定時のEnterは229に、それ以外のEnterのときは13になります。
keyCodeプロパティの値は、IME確定時のEnterとそれ以外のEnterで変ります。

これを使うと次のようなソースコードになります。

<input id="input">
<span id="message">
<script>
input.addEventListener('keydown', (e) => {
  if(e.keyCode === 13) {
    message.innerText = '確定'
  }
})
</script>

気になる点は、keyCodeプロパティがDeprecatedなところです1。 

作戦2 keydownイベントの代わりにkeypressイベントを使う

keypressイベントは、

a key that produces a character value is pressed down

とあるように、文字入力がある場合のみ発火します。このため、IME確定時には発火しません。

これを使うと次のようなソースコードになります。

<input id="input">
<span id="message">
<script>
input.addEventListener('keypress', (e) => {
  if(e.key === 'Enter') {
    message.innerText = '確定'
  }
})
</script>

やはり、気になる点は、keypressイベントがDeprecatedなところです2

その他の補足(恨み言)

keyプロパティ

FirefoxとWindowsのGoogle Chromeは、IMEの確定時にkeydownイベントのkeyプロパティがProcessです。MacのGoogle ChromeとSafariも同じように、keyプロパティがProcessになってくれればいいのに😩

isComposingプロパティ

isComposingというプロパティがあります。

the event is fired after compositionstart and before compositionend

compositionstartからcompositionendの間、つまりIMEの候補が表示されてから確定されるまでの間trueになります。
すごく良さそうです。

Safariでは、IME確定時のEnter入力のkeydownイベントcompositionendの後に発火します。
つまり、IME確定時のEnter入力のKeyboardEventのisComposingfalseです😩

参考資料

  1. KeyboardEvent.keyCodeとは何か - WebStudioによれば、keyCodeプロパティがDeprecatedなのは、ブラウザごとにキーマッピングの扱いが違い、どのキーが押されたのか特定するのが困難なためのようです。もしそうであれば、Enterキーの判定に使う分には問題がないかもしれません。

  2. MDNでは、keypressイベントの代わりにbeforeinputまたはkeydownイベントを使うように書かれています。しかし、beforeinputはEnterキーの押下では発火しません。keydownイベントでは、当初の問題のようにkeyプロパティでEnterキー押下がIME確定のためのものかどうか判定できません。

94
37
4

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
94
37

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?