Windows Terminal focus events [O/[I are inserted into TUI prompt on 0.134.0
What version of Codex CLI is running?
codex-cli 0.134.0
Installed via winget:
Codex CLI OpenAI.Codex 0.134.0 winget
codex doctor --summary reports:
Codex Doctor v0.134.0 - windows-x86_64
13 ok - 1 idle - 0 warn - 0 fail ok
What platform is your computer?
Microsoft Windows [Version 10.0.26200.8457]
What terminal emulator and version are you using?
Windows Terminal:
Microsoft.WindowsTerminal 1.24.11321.0
Shell:
Windows PowerShell 5.1.26100.8457
What issue are you seeing?
On Windows Terminal + Windows PowerShell, the Codex TUI prompt inserts raw focus-reporting control sequences into the input buffer whenever the Windows Terminal window loses or regains focus.
When I switch focus between Windows Terminal and another app with the mouse, the prompt receives visible text like:
[O[I[O[I[O[I
These appear to be terminal focus out / focus in events (ESC [ O and ESC [ I) that should be consumed by the TUI instead of being inserted into the prompt.
This makes slash commands fail because the control-sequence text becomes part of the command, for example:
Unrecognized command '/update[O[I[O[I[O[I'
The same failure mode was also observed with Backspace not working while the prompt is in this bad input state.
Steps to reproduce
- Open Windows Terminal.
- Start Windows PowerShell 5.1.
- Run:
``powershell``
codex
- Wait for the Codex TUI prompt to appear.
- Click another application so Windows Terminal loses focus.
- Click back into Windows Terminal.
- Repeat a few times.
Expected behavior
The TUI should consume terminal focus events and not insert [O / [I into the prompt.
Actual behavior
The prompt receives visible [O / [I text every time focus changes, so the input buffer becomes polluted with raw terminal control sequences.
Additional context
This still reproduces after upgrading from codex-cli 0.133.0 to 0.134.0 via winget.
This may be related to the Windows TUI/raw control sequence regressions discussed in #23740, but the specific symptom here is focus-reporting input leakage on 0.134.0.
6 Comments
Root cause:
set_modes()enables terminal focus reporting (?1004h) unconditionally, but crossterm's Windows console input backend doesn't translate the focus replies into focus events, so they leak into the composer asESC[O/ESC[I.codex-rs/tui/src/tui.rs,set_modes()(around L187 on56958f2) enables focus reporting with no platform guard:EnableFocusChangemakes the terminal emitESC[I(focus in) /ESC[O(focus out) on each focus transition. On the Unix/ANSI path crossterm parses these intoEvent::FocusGained/Event::FocusLost, which the loop consumes without inserting text (tui/src/tui/event_stream.rsL249/L254):On Windows,
ensure_virtual_terminal_processing()enables VT output processing, but crossterm still reads input through the Windows console backend, which does not turn theESC[I/ESC[Ofocus replies intoFocusGained/FocusLost. They arrive as raw bytes and get inserted into the composer — exactly the/update[O[I…corruption (and the repeated[O[I[O[Ion multiple focus switches) in the report.This is the only mode in
set_modes()enabled without accounting for the Windows backend; the file already cfg-gates Windows-specific behavior elsewhere (e.g.EnableAlternateScroll::execute_winapi). The teardownDisableFocusChangeat L259 is likewise unconditional.Suggested fix (outline): gate
EnableFocusChange(L187) andDisableFocusChange(L259) behind#[cfg(not(windows))], or only enable focus reporting when the active input backend actually emits Focus events. The only thing lost on Windows is the focus-triggered palette requery/redraw (a minor cosmetic refresh), which is a good trade for not corrupting input. Likely the same root cause as #23740.Happy to put up a PR with this + a guard test if a maintainer wants to take it (noting code contributions here are invitation-only).
Additional data point on 0.137.0: I am seeing the same focus-report tail leakage in Windows Terminal, and it also shows up around an interactive WSL2 handoff.
Environment, generalized to avoid machine-specific details:
TERM=xterm-256colorwsl.exe/ WSL interactive shellObserved behavior:
[O[I.[3~instead of deleting forward.The visible fragments line up with VT sequence tails whose leading ESC byte is missing:
ESC [ I-> focus-in report, visible tail[IESC [ O-> focus-out report, visible tail[OESC [ 3 ~-> Delete key, visible tail[3~The WSL shell can handle complete sequences, but it cannot handle orphaned tails after the ESC byte is no longer present. In this environment, complete sequences such as
ESC[3~,ESC[I, andESC[Owere handled inside the shell, yet tails such as[3~,[I, and[Ostill reached the Codex composer after returning to Codex.In Codex CLI 0.137.0 source, the relevant code still appears to be in the same area:
codex-rs/tui/src/tui.rs:set_modes()enables bracketed paste, raw mode, keyboard enhancement, andEnableFocusChange.codex-rs/tui/src/tui/keyboard_modes.rs: keyboard enhancement enablesDISAMBIGUATE_ESCAPE_CODES,REPORT_EVENT_TYPES, andREPORT_ALTERNATE_KEYS.codex-rs/tui/src/tui.rs: the external-program handoff restores terminal mode, pauses terminal stderr, runs the external program, resumes, callsset_modes(), then callsflush_terminal_input_buffer().codex-rs/tui/src/keymap.rsandcodex-rs/tui/src/bottom_pane/textarea.rs: Delete is already bound and handled when it arrives asKeyCode::Delete.Given that Delete is handled when parsed correctly, seeing literal
[3~is consistent with the input event parser receiving ordinary characters rather than a parsed Delete key event. This may be the same root cause described above, with the WSL2 interactive handoff adding another timing boundary where focus reports or keyboard-enhancement sequences can cross terminal mode transitions.Areas that seem worth checking:
flush_terminal_input_buffer()runs after all terminal-mode transitions that can emit focus reports.I have another data point and a more precise repro from debugging this locally.
Environment:
Findings:
Injecting
ESC [ I/ESC [ Oas a continuous sequence is parsed by crossterm asEvent::FocusGained/Event::FocusLost.For example, sending
ESC, waiting briefly, then sending[Iis reported as:``
text
``Key(Esc)
Key(Char('['))
Key(Char('I'))
The same happens for
[O:``
text
``Key(Esc)
Key(Char('['))
Key(Char('O'))
This exactly matches the visible composer pollution: the leading ESC is consumed separately, and the remaining
[I/[Otail is inserted as text.Patch direction tested locally:
I also tested a Windows-only defensive filter in
tui/event_stream.rsthat suppresses splitESC+[I/[Otails and maps them back to focus gained/lost behavior.Validation:
My read is that the primary fix should be to stop enabling xterm focus reporting on Windows. A split-tail filter is useful defense-in-depth for stale queued reports or terminal/external-program handoff boundaries. This also lines up with the later report above about
[3~Delete tails: complete sequences can be handled, but orphaned CSI tails still reach the composer once the leading ESC has been separated.I have a local patch with tests if maintainers want the full diff.
Additional data point: this still reproduces on Codex CLI 0.140.0.
Environment:
codex-cli 0.140.0Microsoft Windows NT 10.0.22631.01.24.11321.07.5.5codex doctor --summary:17 ok · 1 idle · 0 warn · 0 fail ok; terminal reported asunknownObserved behavior:
[I[O[I[O...before the user's text.ESC [ I/ESC [ Ofocus in/out tail leakage described in this issue.I am not attaching the screenshot because it includes local paths, but it clearly shows the Codex TUI prompt containing repeated
[I/[Ofragments immediately before user text on0.140.0.Still reproducible on Codex CLI 0.141.0.
Environment:
This is a shot in the dark as I have this happen in only ONE of my terminal tabs consistently and reproducibly. It's the only workspace folder that has a hyphen in it. Could it be some weird regEx parsing error somewhere? I'm still trying to figure out what else makes that working directory special.