マガジン

日本語入力でEnterを押すと送信されてしまう:変換確定とフォーム送信の切り分け

AIを使いこなす

Claudeで執筆し、GPTで自動校閲・修正しています。

入力の確定と送信をノート上の二分岐で区別するイラスト
記事の内容をもとに制作したAI生成イメージです。実際の製品画面や検証結果の写真ではありません。

チャット欄や投稿フォームで、変換を確定するつもりで押したEnterがそのまま送信になってしまう。この現象は、多くの場合「Enterで送信する」処理をkeydownイベントに書いたとき、そのEnterが変換確定のためのものか、送信の合図なのかを区別していないことで起きます。 直し方の考え方は次の一点です。keydownの中で「いま変換中(IMEが入力を組み立てている最中)かどうか」を調べ、変換中なら何もせず、変換中でないEnterだけを送信として扱います。ブラウザによってイベントの順序が違うため、判定は1つでは足りません。この記事では、その判定、AIに修正を頼むときの依頼文、直ったかを確かめる表を順に示します。

この記事の目次
  1. なぜ変換確定のEnterが送信になるのか
  2. 変換中かどうかを判定する2つの手がかり
  3. 修正の考え方と例
  4. 再現手順の書き方
  5. AIに修正を頼むときの依頼文
  6. 修正後の確認表
  7. 切り分けの判断表

なぜ変換確定のEnterが送信になるのか

日本語入力では、「にほんご」と打ってから変換し、Enterで確定します。このEnterも、ブラウザから見るとふつうのキー操作です。MDNのkeydownイベントの解説によると、IMEで入力を組み立てている最中(composition)でもkeydownとkeyupは発火します(MDN: keydown event)。つまり次のような処理は、変換確定のEnterにも反応します。

js
// 問題のある書き方(説明用の例)
textarea.addEventListener("keydown", (e) => {
  if (e.key === "Enter") send();
});

e.key === "Enter" だけでは、変換確定のEnterと送信したいEnterを見分けられません。

変換中かどうかを判定する2つの手がかり

isComposing

KeyboardEvent.isComposing は、イベントが入力の組み立てセッションの中で起きたかを示す真偽値です。MDNでは、compositionstartの後からcompositionendの前までがtrueになる範囲と説明されています(MDN: KeyboardEvent.isComposing)。MDNは、一部の広く使われているブラウザでは動作しないとして、この機能の対応状況に注意を促しています。

keyCode 229

もう1つの手がかりが keyCode === 229 です。IMEが処理したキーイベントに付く特別な値です。keyCode自体は古い仕組みですが、MDNのkeydownの解説は、IME中のイベントを除外するコードとして event.isComposing || event.keyCode === 229 を挙げています。

両方を使う理由

同じMDNの解説には、IMEを開く最初の文字ではcompositionstartがkeydownより後に発火することがあり、IMEを閉じる最後の文字ではcompositionendがkeydownより前に発火することがあると書かれています。後者の場合、確定のEnterがkeydownに届く時点ではcompositionはすでに終わっており、isComposing が false になっていることがあります。それでも keyCode は229のままなので、2つを組み合わせます。

修正の考え方と例

方針は「変換中のEnterは素通しにして、送信処理に入れない」です。

js
// 説明用の例(未実行)。Enterで送信、Shift+Enterで改行
const textarea = document.querySelector("#message");

textarea.addEventListener("keydown", (e) => {
  if (e.key !== "Enter") return;
  if (e.shiftKey) return;                          // 改行は通常動作
  if (e.isComposing || e.keyCode === 229) return;  // 変換中は何もしない

  e.preventDefault();  // 送信を自前で行う場合のみ
  send();
});

ポイントは3つです。

  • 変換中の判定を、送信に進む前の早い段階に置く
  • e.preventDefault() は、変換中の分岐より後ろに置く。前に置くと、変換確定そのものを妨げる可能性がある
  • <form> の送信イベントではなく、Enterのkeydownに書いた処理を直す。送信ボタンのクリックには影響しない

フォームの submit イベント側で変換中を判定する方法はありません。submitの時点では、どのキーが原因か分からないためです。keydown側で止めます。

再現手順の書き方

直す前に、いつ起きるかを書き出します。AIに渡すときも、自分で後から確かめるときも、この手順書が基準になります。以下は書き方の雛形です。

【症状】変換確定のEnterで、メッセージが送信される
【環境】OS / ブラウザとバージョン / 日本語入力(例:OS標準のIME)
【手順】
1. 入力欄をクリックする
2. 「こんにちは」と入力する(変換候補が出ている状態、下線あり)
3. Enterを押す
【期待】文字が確定するだけで、送信されない
【実際】確定と同時に送信される
【補足】Enterを2回目に押したときは? 送信ボタンの場合は?

環境を書くのは、ブラウザごとにイベントの順序が違い得るためです。同じ手順をChrome、Safari、Firefoxなど使えるものすべてで試し、結果を環境別に残します。

AIに修正を頼むときの依頼文

AIには「該当コードの修正案」を任せ、人は「実機で確認する」役割を持ちます。渡すのは、症状、環境、Enterを扱っているコードの該当部分です。

次のJavaScriptで、日本語IMEの変換確定のEnterが送信になってしまいます。
変換中のEnterは無視し、変換していない状態のEnterだけ送信にしたいです。
Shift+Enterは改行のままにします。

条件:
- keydownでisComposingとkeyCode 229の両方を確認すること
- 変更する箇所と理由を短く説明すること
- 他の処理は変えないこと

[ここにEnterを扱っているコードを貼る]

パスワードやAPIキー、顧客の文章などが入っているコードは、そのまま貼らずにダミーの値へ置き換えてから渡してください。AIが返したコードは、そのまま信用せず、次の確認表で動作を確かめます。

修正後の確認表

次の表を、ブラウザごとに埋めてください。結果欄は自分で試した記録を書く場所で、この記事では実測していません。

  • 1、操作:変換中(下線あり)にEnter、期待する結果:確定のみ。送信されない、結果(自分で記入):
  • 2、操作:確定後、もう一度Enter、期待する結果:送信される、結果(自分で記入):
  • 3、操作:英数字を入力してEnter、期待する結果:送信される、結果(自分で記入):
  • 4、操作:変換中にShift+Enter、期待する結果:送信されない(挙動を記録)、結果(自分で記入):
  • 5、操作:確定後にShift+Enter、期待する結果:改行される、結果(自分で記入):
  • 6、操作:変換を途中でEscで取り消す、期待する結果:送信されない、結果(自分で記入):
  • 7、操作:送信ボタンをクリック、期待する結果:送信される、結果(自分で記入):

1や2で失敗する場合は、console.log(e.isComposing, e.keyCode, e.key) をkeydown内に一時的に入れて、確定のEnterでどんな値が届くか確認します。その値をAIに伝えれば、原因を絞りやすくなります。確認が終わったらログは消してください。

切り分けの判断表

直らないときは、どの層の問題かを見ます。

  • 変換確定で送信される。keydownの自前処理がある、疑う場所:変換中の判定が抜けている
  • 判定を入れても特定のブラウザだけ送信される、疑う場所:isComposingだけに頼っている。keyCode 229も確認する
  • 自前のkeydown処理がなく、ライブラリを使っている、疑う場所:ライブラリのEnter送信設定や、新しい版での対処を確認する
  • 英数字のEnterでも意図せず送信される、疑う場所:フォームの標準動作。送信の設計自体を見直す

keyCodeは古い仕組みなので、将来の仕様やブラウザで挙動が変わる可能性があります。コードを導入したあとも、ブラウザを更新したら確認表をもう一度回すと安心です。スマートフォンのソフトウェアキーボードなど、PCの物理キーボード以外の入力では結果が異なる場合があるため、使う予定の端末で試してください。

出典・参考資料