Claude Media
Claude CodeでxtermのCtrl+Enterを改行に割り当てられない理由

Claude CodeでxtermのCtrl+Enterを改行に割り当てられない理由

xtermやVTE系の端末では、keybindingsに書いたctrl+enterが効かず送信されます。modifyOtherKeysが有効にならない条件と、Ctrl+Jなど今すぐ使える改行の手段を載せます。

xtermやVTE系の端末でkeybindings.jsonに"ctrl+enter": "chat:newline"を書いても、Ctrl+Enterは改行にならず、メッセージが送信されます。原因は設定の書き間違いではありません。Claude Codeがxtermのmodifyotherkeys(修飾キー付きキーを区別して送る拡張モード)を、限られた端末でしか有効にしないためです。

この仕様はGitHubのissue #96526で報告されており、openのままです。直るまでの間は、設定なしで動く改行キーに切り替えるのが近道です。

症状: ctrl+enterのバインドが一度も発火しない

再現条件は単純です。modifyOtherKeysには対応しているが、kitty keyboard protocol(kittyが提唱したキー入力の拡張規格)には答えない端末で、次の設定を入れます。

{
  "context": "Chat",
  "bindings": {
    "ctrl+enter": "chat:newline"
  }
}

claudeを起動し、文字を打ってCtrl+Enterを押すと、期待する「改行」ではなく「送信」になります。報告者の環境は次のとおりです。

  • Claude Code 2.1.281、Linux(Fedora)
  • modifyOtherKeysに対応するようパッチを当てたVTE系の端末(VTE_VERSION=8401)
  • TERM=xterm-256colorで、TERM_PROGRAMは未設定(Claude Codeからはvte-basedとして見える)

端末が悪いわけでも、keybindingsの書式が悪いわけでもありません。Ctrl+Enterの押下が、Claude Codeに届く時点で素のEnter(CR)になっているのです。

なぜ有効にならないのか: modifyOtherKeysがkittyに相乗りしている

issueの本文とコメントによると、Claude Codeの拡張キーモードは1つのスイッチで管理されています。このスイッチがオンになる条件は次の2つだけです。

条件内容
許可リストにある端末内容iTerm.app、kitty、WezTerm、ghostty、tmux、windows-terminal、WarpTerminal
kittyプロトコルへの応答内容起動時の問い合わせCSI ? uに端末が答える

スイッチがオンのときだけ、kittyのキー入力モードを要求する列に続けて、modifyOtherKeysを有効にするCSI > 4 ; 2 mが送られます。つまりmodifyOtherKeysは、kittyプロトコルと必ずセットで有効になります。単独で有効にする経路はなく、xterm本体や、modifyOtherKeysだけに対応した端末は、どちらの条件にも当たりません。

端末の名前はTERM_PROGRAMが設定されていればその値、なければvte-basedやxtermのような値で判定されます。

逆側の処理は実装済みです。TERM_PROGRAM=WezTerm claudeで許可リストに乗せて起動すると、Claude CodeはCSI > 4 ; 2 mを送り、Ctrl+Enterは設定どおり改行になります。足りないのは、有効にするかどうかを決める入口のゲートだけだと報告されています。

公式ドキュメントの記述との対応

keybindingsのドキュメントは、拡張キーを報告しない端末ではCtrl+Enterが素のEnterとして届くと書いています。cmd系の修飾キーが使えるのも、kittyプロトコルかxtermのmodifyOtherKeysに対応した端末に限られます。Ctrl+Enterが効かない状況の説明として、issueの内容と同じ向きです。

自分の環境が当たるかを確かめる

次のコマンドで、Claude Codeに端末がどう見えているかの目安を取れます。

echo "TERM_PROGRAM=$TERM_PROGRAM"
echo "TERM=$TERM"
echo "VTE_VERSION=$VTE_VERSION"
echo "XTERM_VERSION=$XTERM_VERSION"

TERM_PROGRAMが空で、TERMがxterm-256color、VTE_VERSIONかXTERM_VERSIONが入っていれば、この記事の条件に近い環境です。ただしfootやAlacritty 0.16以降のように、kittyプロトコルに応答する端末なら、同じ表示でも拡張キーは有効になります。

自分の端末で効く改行キーの早見表

terminal-configのShift+Enter対応表から、xterm系・VTE系の環境で当たりそうな行を抜き出すと次のとおりです。

端末Shift+Enter備考
foot、Alacritty 0.16以降Shift+Enter設定なしで動く備考kittyプロトコル対応。Claude Code v2.1.269以降が必要
Alacritty 0.16より前Shift+Enter/terminal-setupを1回実行備考端末の設定ファイルにバインドが書き込まれる
gnome-terminal(VTE系)Shift+Enter使えない備考Ctrl+Jか\+Enterを使う
xtermそのもの、KonsoleShift+Enter表に載っていない備考まずCtrl+Jで確かめる

表に載っていない端末の動作は、ここでは断定しません。Ctrl+Jと\+Enterは端末を選ばないので、迷ったらこの2つが確実です。/terminal-setupは、tmuxやscreenの中ではなく、外側の端末で直接実行します。

今すぐ使える改行の手段

直るまでの回避策は、ctrl+enterに頼らないことです。

回避策

設定なしで使える改行

  • Ctrl+J

    どの端末でも設定なしで動きます。chat:newlineの既定の割り当ても、Ctrl+Jです。

  • バックスラッシュ + Enter

    行末に\を打ってからEnterを押します。こちらも端末を選びません。

  • Shift+Enter

    kittyプロトコルに対応した端末では設定なしで動きます。gnome-terminalのように「使えない」と書かれた端末もあります。

terminal-configは、Ctrl+Jと\+Enterを「どの端末でも設定なしで動く」手段として挙げています。Shift+Enterは端末ごとに差があり、gnome-terminalとJetBrains系IDEは「利用不可。Ctrl+Jか\+Enterを使う」と書かれています。Shift+Enterの対応表全体と/terminal-setupの使い分けは、terminal-setupでShift+Enterが改行にならないときの対処にまとめています。

Enterの役割を入れ替える

改行を「Ctrl+Enterで」にこだわる理由が、Enterを送信にしたくないだけなら、役割を入れ替える手もあります。terminal-configには、chat:newlineとchat:submitを割り当て直せば、Enterで改行、別のキーで送信にできると書かれています。端末が確実に送れるキーを選んでください。

入れ替えの前に、keybindingsの表で既定の割り当てと、拡張キーに頼るかどうかを見比べておきます。

アクション既定のキー拡張キーへの依存
chat:newline既定のキーCtrl+J拡張キーへの依存不要(どの端末でも動く)
chat:submit既定のキーEnter拡張キーへの依存記載なし
chat:queueSubmit既定のキーCtrl+X Enter拡張キーへの依存記載なし
chat:sendNow既定のキーCtrl+Enter、Ctrl+X Ctrl+S拡張キーへの依存Ctrl+Enterは必要。Ctrl+X Ctrl+Sはどの端末でも動く

chat:sendNowのCtrl+Enterは、拡張キーを報告しない端末では素のEnterとして届きます。xterm系でCtrl+Enterが効かない原因は、改行でも送信でも同じです。

ChatコンテキストでEnterをchat:newlineやchat:queueSubmitに割り当て直しても、エージェントパネルの行のようなフッター項目を選択している間は、Enterがその項目を開く動作のままです。入れ替えたあとにEnterが想定どおり動かないときは、プロンプト側にフォーカスがあるかを先に見てください。

{
  "context": "Chat",
  "bindings": {
    "enter": "chat:newline",
    "ctrl+j": "chat:submit"
  }
}

上は書式の例です。ほかのバインドとぶつからないかは、実際に入力して確かめてから使ってください。

どうしてもCtrl+Enterを使いたいとき

issueのコメントには、許可リストの値をTERM_PROGRAMに与えて起動する回避策が載っています。

TERM_PROGRAM=WarpTerminal claude

コメントでは、WarpTerminalが副作用の最も少ない値だと書かれています。WezTermでも動きますが、TERM_PROGRAM_VERSIONも設定しない限りハイパーリンクが無効になり、OSC 133(シェルの統合用エスケープ)も切れるとされています。

この方法は、Claude Codeの端末判定をだましているだけです。Warp向けの挙動が他の機能に及ぶ可能性があり、公式の手順でもありません。シェルのaliasに入れるより、まず単発のコマンドで副作用を見てください。

落とし穴

tmuxの中では結果が変わる

tmuxは許可リストに入っています。一方、terminal-configには、tmux内でShift+Enterを使うにはextended-keysなどの追加設定が必要だと書かれています。外側の端末が対応していても、tmuxの設定が足りなければ素のEnterになります。tmuxを挟んでいる場合は、外側の端末の問題と切り分けて考えてください。

tmuxの設定は、~/.tmux.confに次の4行を足し、tmux source-file ~/.tmux.confで実行中のサーバーに反映します。

set -g allow-passthrough on
set -g focus-events on
set -s extended-keys on
set -as terminal-features 'xterm*:extkeys'

extended-keysの2行が、tmuxにShift+Enterと素のEnterを区別させる部分です。allow-passthroughは通知や進捗表示を外側の端末へ通すための行で、改行とは関係ありません。この設定を足しても、Ctrl+Enterが届くかどうかは別に確かめる必要があります。terminal-configが保証しているのはShift+Enterのほうです。

修正の見込み: issueが提案している3つの方向

報告者の提案は3つです。

  1. modifyOtherKeysを、kittyプロトコルから独立した別の機能として扱う
  2. 起動時の問い合わせに、modifyOtherKeysの状態を尋ねるXTQMODKEYS(CSI ? 4 m)を足す
  3. 同期出力のCLAUDE_CODE_FORCE_SYNC_OUTPUTのように、強制的にオンにする環境変数を用意する

xtermでXTERM_VERSIONが設定されていれば既定でオンにする案も添えられています。コメントでは、2.1.286のバンドルを読んだ投稿者が、これはenhancementではなくバグだと主張しています。同じ要望のissue #83491は、staleとして自動クローズされています。

issueはopenで、3件のコメントはいずれも報告の補足と進捗の問い合わせで、実装方針の回答は載っていません。修正が入るかどうか、入るならどの方式かは決まっていません。chat:newlineにctrl+enterを割り当てたままにしておいても害はありませんが、修正が入るまでは、xterm系ではこのバインドが発火しません。

症状別の切り分け

症状考えられる原因次に見るもの
xtermやVTE系でctrl+enterのバインドが発火せず送信になる考えられる原因modifyOtherKeysが有効になっていない(この記事)次に見るものCtrl+Jか\+Enterに切り替える
iTerm2でCtrl+Enterがメニューを開く考えられる原因端末側のショートカット次に見るものiTerm2のコンテキストメニュー回避策
Ctrl+Enterを「今すぐ送信」に使いたい考えられる原因chat:sendNowの割り当て次に見るものCtrl+Enterの送信挙動
組み合わせキーを自分で組みたい考えられる原因chordの書式次に見るものkeybindingsのchord

最後の逆向きの話も押さえておきます。Ctrl+Enterをchat:sendNow(キュー済みのメッセージを今すぐ送る)に使う場合も、拡張キーが届かない端末では同じ理由で素のEnterになります。keybindingsの表は、どの端末でも動く割り当てとしてCtrl+X Ctrl+Sを挙げています。

まとめ

xterm系でctrl+enterが改行にならないのは、Claude Codeがmodifyotherkeysをkittyプロトコルや許可リストの端末にしか有効にしないからで、設定側では直せません。issueがopenの間は、Ctrl+Jか\+Enterを改行の標準手段にし、どうしてもctrl+enterが必要なときだけTERM_PROGRAMの指定を、副作用を承知で試す流れになります。

この記事を共有:XはてブLinkedIn