Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

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プロパティは、

http://lists.w3.org/Archives/Public/www-dom/2010JulSep/att-0182/keyCode-spec.html

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確定のためのものかどうか判定できません。 

ledsun
編集リクエスト、コメント大歓迎です。
luxiar
Ruby on Rails専門のWebアプリケーション開発に特化した町田の受託開発企業です
http://www.luxiar.com/index.html
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした