Claude Media
Claude Codeの入力欄に[I・[Oが混ざる原因と回避策

Claude Codeの入力欄に[I・[Oが混ざる原因と回避策

入力欄に[Iや[Oが出る原因はフォーカスレポート(ANSI mode 1004)の漏れです。報告された条件と、シェル・statusLine・tmuxでの回避策を症状別に示します。

Claude Codeの入力欄で、マウスをクリックしたりウィンドウを切り替えたりしたあとに[Iや[Oという文字が勝手に入ることがあります。正体はターミナルが送るフォーカスレポート(ANSI mode 1004)のエスケープシーケンスで、Claude Codeの入力処理が文字として拾ってしまう現象です。anthropics/claude-codeのissue #10375で議論が続いており、このissueはまだopenです。

この記事では、何が起きているのかと、issueに寄せられた回避策を効く条件つきで並べます。シェルの設定ファイル、statusLine、tmux、Neovim側のどこで止めるかは環境で変わります。

入力欄に[I・[Oが混ざるのは何の文字か

[Iと[Oは、本来は画面に見えない制御シーケンスの後半です。先頭のESC(0x1b)が表示されず、続きの[Iだけが文字として見えています。

issueの本文によると、フォーカスレポートは次の仕組みです。

操作送られるシーケンス入力欄に見える形
有効化(アプリ側が送る)送られるシーケンスESC[?1004h入力欄に見える形見えない
ウィンドウがフォーカスを得る送られるシーケンスESC[I入力欄に見える形[I
ウィンドウがフォーカスを失う送られるシーケンスESC[O入力欄に見える形[O
無効化(アプリ側が送る)送られるシーケンスESC[?1004l入力欄に見える形見えない

ターミナルは、アプリが有効化を要求したときだけフォーカスの出入りを知らせます。Neovimなどはこの通知を使って、外部で変わったファイルを読み直します。通知そのものは正しい動作です。

問題は受け取る側です。入力処理がこの2つのシーケンスを読み捨てないと、ESCの後ろの[Iや[Oが打鍵と同じ扱いで入力欄に残ります。issueはこの点をClaude Code側の不具合と位置づけ、ESC[IとESC[Oを入力から除くよう求めています。

どの環境で報告されているか

最初の報告はmacOSのWezTermでした。クリックしたとき、またはCmdやShiftなどの修飾キーを押したときに[Iと[Oが出ると書かれています。

コメント欄には、同じ症状が別のターミナルでも出るという報告が並びます。

  • Kitty、iTerm2、Ghostty、Terminal.app
  • LinuxのPtyxis(別issueとして起票)
  • tmux上のAlacritty

tmuxの有無は決め手になっていません。ある報告者は、.zshrcを空にしても、tmuxの有無を変えても再現したと書いています。つまり、シェル設定が原因とは限りません。

出方にも差があります。報告されている条件を並べます。

条件

報告された出方の違い

  • クリックや修飾キー

    最初の報告はWezTermとmacOSです。マウスのクリックやCmd、Shiftの押下で[Iと[Oが入力欄に出ます。

  • バックグラウンドからの復帰

    Linuxの報告者は、Claude Codeを一度バックグラウンドに回してフォアグラウンドへ戻すたびに出ると書いています。

  • Vimモードの INSERT 中だけ

    tmuxとAlacrittyの報告者は、Claude CodeのvimモードがINSERTのときだけ出ると書いています。Claude Codeを終了した後も、そのペインで出続けたそうです。

なお、WezTermの記号入力が崩れる不具合は症状も原因も別です。Shiftを押した記号が出ない話はClaude CodeでWezTermの記号が入力できないときの対処法で扱っています。

誰が有効化しているのか — issueの本文とコメントで見立てが割れる

issue本文は、Vimなどの別アプリが有効化したまま終了し、モードが残ったターミナルにClaude Codeを起動したと見ています。Vimが終了時に無効化し損ねることがある、という説明です。

ところがコメントでは、別の見立てが出ています。ある報告者は、空の.zshrcでもKittyとTerminal.appで再現し、Claude CodeがESC[?1004hで有効化して無効化しないように見えると書いています。別の報告者は、Claude Codeを終了した後もペインに[Iが出続けた、またはフォーカスがウィンドウに固定されたと書いています。

この食い違いを決着させる説明は、issueの中にありません。どちらの場合も、ESC[?1004lでモードを落とせば止まるという点は共通しています。以降の回避策は、全部この無効化シーケンスを送る場所の違いです。

手元の端末でフォーカスレポートが有効か確かめる

まず、モードが入っているかを自分の目で見ます。次の手順は、自分でモードを有効化して、通知の見え方を確かめるものです。

手順

フォーカスレポートの挙動を見る

  1. 1

    有効化して入力を生のまま表示する

    Claude Codeを起動していないシェルで、次のコマンドを実行します。cat -vは、見えない制御文字を^[の形で表示します。

    printf '\e[?1004h'; cat -v
  2. 2

    ウィンドウを切り替える

    別のアプリへフォーカスを移し、戻ってきます。^[[Oと^[[Iが表示されるはずです。この2つが、Claude Codeの入力欄では[Oと[Iに見えているシーケンスです。

  3. 3

    Ctrl+Cで抜けて無効化する

    catを止めたあと、無効化のシーケンスを送ってモードを戻します。

    printf '\e[?1004l'

この確認は、issueの「有効化はESC[?1004h、フォーカス取得はESC[I、喪失はESC[O」という記述をなぞっただけのものです。Claude Code自体の挙動を調べるものではありません。

回避策1: 症状が出たペインで無効化する

最も手軽なのは、今出ているペインで無効化のシーケンスを送ることです。issueの本文がまず示している方法でもあります。

printf '\e[?1004l'

Claude Codeを終了した後に[Iが出続けるなら、この1行が候補です。1回送るだけなので、Claude Codeの実行中に再び有効化される場合は防げません。

回避策2: シェルの起動時に無効化する

issueの本文と、複数のコメントが挙げているのがシェルの設定ファイルです。bashとzshなら、~/.bashrcか~/.zshrcに次を足します。

# Claude Codeの入力欄に[I・[Oが出るのを避ける
printf '\e[?1004l'

fishは、対話シェルのときだけ実行する書き方がコメントで紹介されています。

if status is-interactive
  printf '\e[?1004l'
end

この方法には限界があります。ターミナルを開くたびに1回だけ実行されるので、Vimを使った後や、Claude Codeの実行中に有効化された場合は戻ってしまいます。実際に、.zshrcに入れても止まらなかった報告者がいます。

回避策3: statusLineのコマンドに無効化を前置する

シェル設定で止まらなかった報告者が見つけたのが、statusLineのコマンドの先頭にprintfを置く方法です。コメントでは、tmuxの内外を問わず効いたと追報されています。zshでの報告です。

Claude CodeはstatusLineのcommandを、画面の更新イベントごとに再実行します。更新は300msでまとめられます。そのたびに無効化が送られるので、実行中に有効化されても打ち消せる可能性があります。ただし、これが効く理由をissueは説明していません。

~/.claude/settings.jsonには、既存のステータスライン用スクリプトの前にprintfを置きます。JSONの文字列なので、バックスラッシュは2つ必要です。

{
  "statusLine": {
    "type": "command",
    "command": "printf '\\e[?1004l'; ~/.claude/statusline.sh",
    "padding": 0
  }
}

ステータスラインを使っていない場合は、commandにprintfだけを置く形になります。ステータスラインの設定項目の全体像はClaude Code statuslineの設定と表示項目の選び方にあります。

statusLineにはrefreshIntervalも用意されており、指定した秒数ごとにコマンドを再実行します。定期的な無効化に使えそうですが、これを使って[Iが止まったという報告はissueに出ていません。

回避策4: tmuxとNeovim側で止める

tmux上で出る場合は、tmux側の設定で通知を止めるやり方が報告されています。

tmux set -g focus-events off

この設定を試した報告者は、一時的な回避策と位置づけています。別のコメントが指摘するとおり、Neovimはフォーカスイベントを外部変更の再読み込みに使うので、Neovimも使うならonのままにしたい人もいます。

Neovimが原因と見立てるなら、終了時に無効化する書き方も共有されています。tmux内ではパススルー用のラッパーが必要で、素のエスケープを書くだけでは効かなかったと本人が書いています。

vim.api.nvim_create_autocmd("VimLeavePre", {
  callback = function()
    if vim.env.TMUX then
      io.stdout:write("\x1bPtmux;\x1b\x1b[?1004l\x1b\\")
    end
  end,
})

tmux全般の設定はClaude Code tmux設定に、Claude Code側のvimモードはClaude Code Vimモードの使い方とキー操作一覧にまとめています。

回避策5: 終了時にだけ無効化するラッパー

Hyprland上のGhosttyでは、Claude Codeを終了したあとウィンドウから出られなくなる別の症状が報告されました。マウスが外へ出ず、フォーカスも他のウィンドウへ移せなくなるというものです。この報告者は、フォーカスレポートが終了時に無効化されていないことが原因だと見ています。

対策として、claudeをシェル関数で包み、終了のたびに無効化を送る方法が書かれています。

claude() {
  command claude "$@"
  printf '\e[?1004l'
}

command claudeで本体を呼び、終了後に必ず無効化を送ります。正常終了でも異常終了でも実行されるのが利点です。実行中の入力欄には効かないので、[Iが入力中に出る症状は別の手を併用します。

症状別の選び方

どの回避策から試すかは、症状が出るタイミングで決まります。

症状が出る場面最初に試す方法補足
Claude Codeを終了した後も[Iが出る、フォーカスが固定される最初に試す方法回避策5の関数ラッパー補足終了のたびに無効化する
ターミナルを開いた直後から出る最初に試す方法回避策2のシェル設定補足Vimなど別アプリが原因の場合に効く
シェル設定でも実行中に出る最初に試す方法回避策3のstatusLine補足シェル設定で止まらなかった報告者が効いたと追報
tmux内のNeovim使用後に出る最初に試す方法回避策4のNeovim設定補足tmuxのパススルー形式で書く
tmux内で、Neovimを使わない最初に試す方法focus-events off補足Neovimの再読み込みは使えなくなる

回避策は1つで足りないこともあります。実際に、シェル設定の次にstatusLineへ進んだ報告者がいます。

changelogにある関連修正は2件だけ

changelogで、フォーカスレポートに触れている項目は2件あります。

  • v2.1.132: フォーカスイベントやマウスレポートがブラケットペーストに割り込んだとき、プロンプトにエスケープシーケンスが残る問題の修正
  • v2.1.268: セッションのrecap中にフォーカスレポートが続けて届いてもCPU使用率が高止まりしないようにする修正

どちらも入力欄への[Iの混入を直したとは書かれていません。ただし、Claude Code側がフォーカスレポートを受け取る経路を持っていること、そしてペースト時には混入を防ぐ処理が入ったことは読み取れます。通常の打鍵経路で同じ処理がまだ入っていないことが、issueで報告が続く背景と考えられます。

バージョンによる差も報告されています。ある報告者はv2.0.36で再現しなくなったと書きましたが、別の報告者がv2.0.47でprintfを外して1回目で再現しました。v2.0.58でも報告があります。バージョンを上げれば直るとは言えない状況です。

試さないほうがよい回避策

issueには、効く可能性はあっても副作用の大きい方法も載っています。

  • バックグラウンドで0.2秒ごとにprintf '\e[?1004l'を送り続けるシェルのループ。止まったという報告はありますが、常駐プロセスが残ります
  • 入力側でフォーカスイベントを取り除く自作のラッパー。第三者が公開している例があり、claudeの別名にして使う形です
  • バイナリ内の1004hの文字列を書き換える方法。自動更新のたびにやり直しになり、報告者自身も一時しのぎと書いています

上の回避策1〜5で止まる範囲なら、まずそちらを試すほうが後始末が少なく済みます。

まとめ

[Iと[Oは、フォーカスレポートの通知が入力欄に漏れた文字です。有効化したのがVimなのかClaude Code自身なのかはissueで見解が割れていますが、ESC[?1004lを送れば止まる点は共通しています。

実行中の入力に出るなら、statusLineのコマンドに前置するのが報告上の有力案です。終了後に残るだけなら、claudeを包む関数が手間の少ない選択になります。症状が出る場面を先に特定し、無効化を送る場所をそこに合わせるのが近道です。

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