mirror of
https://github.com/openai/codex.git
synced 2026-09-11 20:36:49 +00:00
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.
This commit is contained in:
@@ -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()?;
|
||||
|
||||
94
codex-rs/tui/src/keyboard_enhancement.rs
Normal file
94
codex-rs/tui/src/keyboard_enhancement.rs
Normal 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,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user