Compare commits

...

1 Commits

Author SHA1 Message Date
Felipe Coury
0441bc180e fix(tui): disable keyboard enhancements in wsl vscode
Centralize the keyboard-enhancement decision in
`codex-terminal-detection` and use it from both the main
TUI and `codex-cloud-tasks`. This also keeps the main
composer from advertising enhanced-key behavior when the
flags are intentionally disabled.

WSL users running inside the VS Code integrated terminal
can hit dead-key composition failures when Codex pushes
progressive keyboard enhancement flags. Disable those
flags in that environment and add coverage for the shared
policy.
2026-04-03 13:06:33 -03:00
4 changed files with 121 additions and 17 deletions

View File

@@ -763,6 +763,7 @@ pub async fn run_main(cli: Cli, _codex_linux_sandbox_exe: Option<PathBuf>) -> an
let backend = backend;
// Terminal setup
use codex_tui::should_enable_keyboard_enhancement;
use crossterm::ExecutableCommand;
use crossterm::event::DisableBracketedPaste;
use crossterm::event::EnableBracketedPaste;
@@ -781,14 +782,16 @@ pub async fn run_main(cli: Cli, _codex_linux_sandbox_exe: Option<PathBuf>) -> an
stdout.execute(EnableBracketedPaste)?;
// Enable enhanced key reporting so Shift+Enter is distinguishable from Enter.
// Some terminals may not support these flags; ignore errors if enabling fails.
let _ = crossterm::execute!(
std::io::stdout(),
PushKeyboardEnhancementFlags(
KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES
| KeyboardEnhancementFlags::REPORT_EVENT_TYPES
| KeyboardEnhancementFlags::REPORT_ALTERNATE_KEYS
)
);
if should_enable_keyboard_enhancement() {
let _ = crossterm::execute!(
std::io::stdout(),
PushKeyboardEnhancementFlags(
KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES
| KeyboardEnhancementFlags::REPORT_EVENT_TYPES
| KeyboardEnhancementFlags::REPORT_ALTERNATE_KEYS
)
);
}
let backend_ui = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend_ui)?;
terminal.clear()?;

View File

@@ -0,0 +1,94 @@
use codex_terminal_detection::TerminalInfo;
use codex_terminal_detection::TerminalName;
use codex_terminal_detection::terminal_info;
/// Returns whether Codex should enable progressive keyboard enhancement flags.
///
/// We currently disable them for the VS Code integrated terminal under WSL
/// because that terminal stack partially supports the protocol and breaks
/// dead-key composition for some keyboard layouts.
pub fn should_enable_keyboard_enhancement() -> bool {
should_enable_keyboard_enhancement_for(terminal_info(), process_is_wsl())
}
/// Pure-logic helper for [`should_enable_keyboard_enhancement`], separated so
/// tests can inject terminal identity and WSL status without touching the
/// process environment or filesystem.
///
/// The rule is a denylist: disable enhancement only for known-broken
/// combinations. Today, the only entry is VS Code under WSL, where the
/// terminal's partial protocol support corrupts dead-key composition sequences
/// for layouts that rely on them (e.g. Portuguese, French, Spanish).
fn should_enable_keyboard_enhancement_for(terminal: TerminalInfo, is_wsl: bool) -> bool {
!(is_wsl && matches!(terminal.name, TerminalName::VsCode))
}
/// Detects whether the current process is running inside Windows Subsystem for Linux.
///
/// Uses a three-tier heuristic (checked only on Linux; returns `false` on all other targets):
/// 1. `WSL_DISTRO_NAME` environment variable (set by WSL 2).
/// 2. `WSL_INTEROP` environment variable (set by WSL 1 and some WSL 2 configurations).
/// 3. `/proc/version` containing "microsoft" (fallback for minimal WSL images that
/// strip environment variables).
fn process_is_wsl() -> bool {
#[cfg(target_os = "linux")]
{
if std::env::var_os("WSL_DISTRO_NAME").is_some()
|| std::env::var_os("WSL_INTEROP").is_some()
{
return true;
}
match std::fs::read_to_string("/proc/version") {
Ok(version) => version.to_lowercase().contains("microsoft"),
Err(_) => false,
}
}
#[cfg(not(target_os = "linux"))]
{
false
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn disables_keyboard_enhancement_for_vscode_under_wsl() {
assert!(!should_enable_keyboard_enhancement_for(
TerminalInfo {
name: TerminalName::VsCode,
term_program: None,
version: None,
term: None,
multiplexer: None,
},
/*is_wsl*/ true,
));
}
#[test]
fn keeps_keyboard_enhancement_enabled_outside_wsl_vscode() {
assert!(should_enable_keyboard_enhancement_for(
TerminalInfo {
name: TerminalName::VsCode,
term_program: None,
version: None,
term: None,
multiplexer: None,
},
/*is_wsl*/ false,
));
assert!(should_enable_keyboard_enhancement_for(
TerminalInfo {
name: TerminalName::AppleTerminal,
term_program: None,
version: None,
term: None,
multiplexer: None,
},
/*is_wsl*/ true,
));
}
}

View File

@@ -115,6 +115,7 @@ mod get_git_diff;
mod history_cell;
pub mod insert_history;
mod key_hint;
mod keyboard_enhancement;
mod line_truncation;
pub mod live_wrap;
mod local_chatgpt_auth;
@@ -216,6 +217,8 @@ pub mod test_backend;
#[cfg(test)]
pub(crate) mod test_support;
pub use keyboard_enhancement::should_enable_keyboard_enhancement;
use crate::onboarding::onboarding_screen::OnboardingScreenArgs;
use crate::onboarding::onboarding_screen::run_onboarding_app;
use crate::tui::Tui;

View File

@@ -42,6 +42,7 @@ use crate::custom_terminal;
use crate::custom_terminal::Terminal as CustomTerminal;
use crate::notifications::DesktopNotificationBackend;
use crate::notifications::detect_backend;
use crate::should_enable_keyboard_enhancement;
use crate::tui::event_stream::EventBroker;
use crate::tui::event_stream::TuiEventStream;
#[cfg(unix)]
@@ -70,14 +71,16 @@ pub fn set_modes() -> Result<()> {
// Some terminals (notably legacy Windows consoles) do not support
// keyboard enhancement flags. Attempt to enable them, but continue
// gracefully if unsupported.
let _ = execute!(
stdout(),
PushKeyboardEnhancementFlags(
KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES
| KeyboardEnhancementFlags::REPORT_EVENT_TYPES
| KeyboardEnhancementFlags::REPORT_ALTERNATE_KEYS
)
);
if should_enable_keyboard_enhancement() {
let _ = execute!(
stdout(),
PushKeyboardEnhancementFlags(
KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES
| KeyboardEnhancementFlags::REPORT_EVENT_TYPES
| KeyboardEnhancementFlags::REPORT_ALTERNATE_KEYS
)
);
}
let _ = execute!(stdout(), EnableFocusChange);
Ok(())
@@ -266,7 +269,8 @@ impl Tui {
// Detect keyboard enhancement support before any EventStream is created so the
// crossterm poller can acquire its lock without contention.
let enhanced_keys_supported = supports_keyboard_enhancement().unwrap_or(false);
let enhanced_keys_supported = should_enable_keyboard_enhancement()
&& supports_keyboard_enhancement().unwrap_or(false);
// Cache this to avoid contention with the event reader.
supports_color::on_cached(supports_color::Stream::Stdout);
let _ = crate::terminal_palette::default_colors();