チャット欄が日本語を途中で送信してしまう理由
Enter キーで送信するチャット欄は、書きかけの日本語を送ってしまいます。日本語、中国語、韓国語を打つ人は IME を使っていて、Enter は単語の変換を確定するために押すもので、送信のためではありません。対策は、変換中は Enter を無視することです。event.isComposing を確認し、Safari 対策として keyCode === 229 も確認します。
私は東京に住んでいて、ほぼ毎日 4 つの言語で文字を打っています。アジアの外で作られた AI プロダクトで、いちばんよく出会うのがこのバグです。資金が潤沢なサービスでも起きます。ひらがなで少し打って、漢字にするために Enter を押すと、間違った文字のまま送信され、まだ言い終えていない質問にモデルがもう答え始めている。そんな状態です。
IME にとっての Enter キー
パソコンで日本語を打つには 2 つの段階があります。ローマ字で音を打つと、IME がそれを下線付きのひらがなで表示します。スペースで漢字の候補を切り替え、欲しいものが出たら Enter で確定します。確定してはじめて、文字が本当に入力欄に入ります。
この下線付きの段階をコンポジション(変換中)と呼びます。ブラウザは始まりに compositionstart、確定時に compositionend というイベントを出します。変換中の Enter は IME のものです。ふつうの長さの文でも、送信するまでに Enter を 5、6 回押すことは珍しくありません。
チャット型の UI がこれを悪化させました。10 年前のフォームは、たいてい送信ボタンをクリックする必要がありました。AI プロダクトはメッセージアプリの「Enter で送信、Shift と Enter で改行」というパターンを取り入れ、その処理の多くは英語だけで書かれ、英語だけでテストされました。
コードでの対策
MDN は keydown イベントのページでこのパターンをそのまま紹介しています。isComposing を確認し、さらに keyCode が 229 かどうかを確認します。229 は、IME が処理したキーイベントにブラウザが設定する値です。
textarea.addEventListener("keydown", (event) => {
if (event.isComposing || event.keyCode === 229) return
if (event.key === "Enter" && !event.shiftKey) {
event.preventDefault()
send()
}
})
2 つ目のチェックは必要です。MDN によると、IME を閉じるキーの keydown より前に compositionend が発生することがあり、そのとき isComposing は、まさに問題の Enter で false になります。keyCode は非推奨ですが、この場合でも 229 のままです。
Safari で追加のチェックが必要な理由
MDN の元になっているブラウザ互換性データでは、Safari の isComposing 対応は「部分的」とされています。注記によると、変換を確定するキー入力では keydown と input のイベントが compositionend の前ではなく後に送られるため、true であるはずの isComposing が false になります。Chrome と Firefox は期待どおりに動きます。
これは Mac でも、iPhone と iPad でも問題になります。iPhone と iPad では、Safari をはじめ多くのブラウザがいまも WebKit で動いているからです。Windows のノートパソコンと Chrome、日本語 IME でテストしたチームは、1 つ目のチェックが効くのを見てリリースします。それでも MacBook の Safari を使う日本のユーザーにはバグが出ます。
フレームワークを使っているなら、何をしてくれるかを確認してください。テキスト入力コンポーネントの中で処理してくれる UI ライブラリもあれば、任せてくるものもあります。React ではネイティブのイベントが event.nativeEvent で取れるので、同じ 2 つのチェックがそのまま使えます。
日本のユーザーと同じようにテストする
テストに日本語の知識は要りません。Mac か PC に日本語入力を追加して切り替え、チャット欄に konnichiha と打ち、スペースで変換し、Enter を 1 回押します。何も送信されなければ正解です。もう 1 回 Enter を押したら、メッセージが送られるはずです。
同じことを Safari、Chrome、日本語キーボードの iPhone で行います。スマートフォンでは中国語のピンインキーボードも試してください。中国語の入力にも同じ変換の段階があり、同じバグが起きます。
あと 2 つ、1 分ずつかける価値のあるケースがあります。日本語の文を貼り付けて Enter を押すと、変換中ではないので送信されるべきです。そして、まだ下線が付いた変換中の状態で送信ボタンを押したとき、文字を確定するのか待つのか、意図して決めておきましょう。
AI プロダクトにとってのもっと大きな教訓
いまの大規模言語モデルは日本語がうまい。だから、答えが自然な日本語で返ってくれば、プロダクトは日本でも使えると思い込みやすくなります。壊れるのは入力欄で、モデルが関わる前に壊れています。
これは私がよく書いているテーマにもつながります。日本の人は、小さなことをどれだけ丁寧に扱っているかでプロダクトを判断します。壊れた Enter キーは「自分たちのために作られていない」と受け取られます。全体のパターンは日本の UX は何が違うのかに、書かれたインターフェースがなぜこれほど重いのかは日本の英語ライティングのスコアについての記事に書きました。IME のチェックはコード 4 行です。そして日本のユーザーにとっては、誰かが自分の言語でテストしてくれたと感じる最初のサインになることが多いのです。