Windows Terminal Preview duplicates non-ASCII input in Codex TUI under WSL

Open 💬 4 comments Opened Aug 17, 2026 by AspireOne

Environment

  • Codex CLI: 0.146.0
  • Platform: WSL 2 on Windows
  • Terminal: Windows Terminal Preview 1.25.1912.0
  • Shell: zsh
  • Keyboard layout: Czech

Reproduction

  1. Open Windows Terminal Preview and start a WSL shell.
  2. Run codex and focus the chat composer.
  3. Type a non-ASCII Czech-layout character, for example ě, š, č, ř, ž, ý, á, í, é, ú, ů, §, or '.

Actual behavior

Each affected character is inserted twice. One copy appears on key-down and the second appears when the key is released. This happens only in Codex's TUI composer; the same keyboard and terminal work correctly in the WSL shell and other TUI CLI applications.

Expected behavior

Each keypress should insert exactly one character.

Context

Windows Terminal Preview 1.25's Kitty Keyboard Protocol support fixes important input behavior in Codex, including Ctrl+Backspace word deletion and modifier-aware Enter handling. Disabling keyboard enhancement avoids this duplication, but gives up those improvements, so it is not a viable workaround.

This appears to match the already-written minimal fix in #30480, which removes REPORT_ALTERNATE_KEYS. Its PR description/comment explicitly notes that some Kitty-protocol terminals emit duplicate non-ASCII text when alternate keycodes are requested. That PR was automatically closed after 14 days without review activity, rather than rejected on technical grounds.

Relevant current code: https://github.com/openai/codex/blob/main/codex-rs/tui/src/tui/keyboard_modes.rs

View original on GitHub ↗

4 Comments

AspireOne · 11 days ago

Additional impact: this is not limited to writing Czech prose. On the Czech layout, affected keys also include programming punctuation such as quotes and / (and related layout-dependent symbols). Those characters are needed constantly for source code, commands, paths, JSON, and strings, so the current regression makes normal Codex use impractical rather than merely inconvenient for localized text.

The common trait appears to be layout-dependent/alternate-key reporting, not simply whether the final character is non-ASCII. The title and reproduction should therefore be read as covering duplicated printable input produced by this layout under the Kitty keyboard protocol.

AspireOne · 11 days ago

Confirmed workaround result from the affected setup:

  • Rewriting Codex's Kitty request from CSI > 7 u to CSI > 3 u (disable only REPORT_ALTERNATE_KEYS) did not stop the duplicated input.
  • Rewriting it from CSI > 7 u to CSI > 1 u (retain only DISAMBIGUATE_ESCAPE_CODES, disable both REPORT_EVENT_TYPES and REPORT_ALTERNATE_KEYS) does stop it.

This narrows the Windows Terminal Preview + WSL regression: REPORT_EVENT_TYPES is implicated as well, likely because the layout-dependent key-up event is not being handled correctly somewhere in the Codex/crossterm input path. Modifier disambiguation remains enabled, so the desired enhanced-key behavior can be retained without requesting event types.

Consequently, #30480's removal of alternate-key reporting alone is insufficient for this reproduction.

jdcodes1 · 11 days ago

Traced the codex side of this on main @ 1f41cc5d92. The composer's own event handling is correct, which — combined with @AspireOne's CSI > 1 u / CSI > 3 u experiment — narrows the defect to how the release events reach the parser, and there's a one-line-shaped fix location already designed for exactly this situation.

Codex already drops release events. The composer ignores KeyEventKind::Release (chat_composer.rs L1939, L3532). So a key-release can only insert a second character if it arrives parsed as a press.

Why a release can parse as a press. In the crossterm fork Codex pins (openai-oss-forks/crossterm @ 45fecb95), the kitty CSI‑u parser takes the event type from the sub-parameter of the modifier field and defaults to 1 (Press) when the sub-parameter is absent (spec-compliant — kitty defines absent = press). So if Windows Terminal Preview encodes the release of a layout-dependent text key either (a) as a CSI‑u sequence without the :3 event-type sub-param, or (b) as plain UTF-8 text bytes, crossterm emits a second Press carrying the character and the composer inserts it. That matches the reported timing exactly (first copy on key-down, second on release) and matches the flag experiment: with REPORT_EVENT_TYPES disabled (CSI > 1 u), the terminal never sends release events at all, so the malformed encoding never happens.

A 5-minute diagnostic that settles whether this is WT's encoder or crossterm's parser (runnable in the affected WSL setup, no Codex involved):

printf '\x1b[>7u'; cat -v; printf '\x1b[<u'   # type ě š č, one keystroke each, then Ctrl+D

If the release sequences printed by cat -v lack the :3 sub-param (or appear as bare text), it's Windows Terminal Preview's encoder and worth filing against microsoft/terminal with those bytes; if they do carry :3, the fork's parser is mishandling them and it's fixable in openai-oss-forks/crossterm.

Codex can defend regardless. keyboard_enhancement_flags already omits REPORT_EVENT_TYPES per terminal for exactly this class of problem — Ghostty and iTerm2 (leaky release events) and tmux's xterm format:

https://github.com/openai/codex/blob/1f41cc5d92722748e45cae9cecc6d883a4e7cbb1/codex-rs/tui/src/tui/keyboard_modes.rs#L152-L169

TerminalName::WindowsTerminal already exists in codex-terminal-detection (detected via WT_SESSION, which crosses into WSL), so adding it to that match arm suppresses event-type reporting for WT while keeping DISAMBIGUATE_ESCAPE_CODES + REPORT_ALTERNATE_KEYS — i.e. CSI > 5 u. One caveat worth a quick check on the affected setup: the experiments covered 7u (fails), 3u (fails), and 1u (works), but not 5u. If 5u also duplicates (i.e. alternate-key reporting alone also triggers the stray text), the same match arm can return bare DISAMBIGUATE_ESCAPE_CODES for Windows Terminal instead — that's the reporter-verified 1u configuration.

(For anyone else landing here meanwhile: CODEX_TUI_DISABLE_KEYBOARD_ENHANCEMENT=1 is the existing big-hammer escape hatch, with the known cost of losing Ctrl+Backspace/modified-Enter handling.)

AspireOne · 11 days ago

Additional narrowing from the reporter:

  • The duplication also reproduces in a new Windows Terminal Preview tab before Codex has ever run in that tab, using Neovim (reported version: NVIM v0.12.4) under WSL.
  • This rules out a keyboard-mode reset leak left by Codex. It shows that the affected input path is broader than Codex.
  • Neovim documents that it enables CSI > 3 u at startup. Codex requests CSI > 7 u; both requests include Kitty flag 2 (REPORT_EVENT_TYPES). The reporter has directly verified that changing Codex's request to CSI > 1 u removes the duplication while retaining the desired Ctrl+Backspace behavior.

This is correlation, not yet a claim that either application or Windows Terminal violates the protocol. The shared observation is that the failure appears whenever the report-event-types enhancement is requested in this Windows Terminal Preview + WSL + Czech-layout setup. We are checking Neovim's existing upstream report separately rather than filing a duplicate.

References: https://neovim.io/doc/user/tui/ and https://sw.kovidgoyal.net/kitty/keyboard-protocol/