mirror of
https://github.com/openai/codex.git
synced 2026-11-13 06:45:07 +00:00
[codex] fix Windows ConPTY input handling (#29734)
## Why Windows unified-exec TTY input did not behave like the non-Windows PTY path. ConPTY sessions could receive the wrong line ending or mishandle backspace, especially when sending input to a foreground program through PowerShell or cmd. The local, legacy restricted, and elevated paths also handled this normalization separately. ## What changed - share one stateful Windows TTY input normalizer across local, legacy restricted, and elevated runner paths - translate LF and split CRLF into one Windows terminal Enter, encode backspace as DEL, and preserve UTF-8 and control bytes such as Ctrl-C - add Windows integration coverage for Unicode input, backspace, Enter, and PowerShell foreground-child Ctrl-C behavior ## Validation - `just test -p codex-utils-pty` (13 tests passed; the Unicode integration test retried once) - the Unicode integration test passed five consecutive runs with retries disabled - integration coverage sends `cafeé 漢字` through cmd and PowerShell and verifies that Ctrl-C interrupts a running PowerShell foreground child
This commit is contained in:
1 parent
8a6a34be75
commit
a781761eda
8 files changed
+226
-23
No files matched your search
@@ -1,5 +1,4 @@
|
||||
use super::windows_common::finish_driver_spawn;
|
||||
use super::windows_common::normalize_windows_tty_input;
|
||||
use crate::conpty::ConptyInstance;
|
||||
use crate::conpty::spawn_conpty_process_as_user;
|
||||
use crate::desktop::LaunchDesktop;
|
||||
@@ -22,6 +21,7 @@ use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use codex_utils_pty::ProcessDriver;
|
||||
use codex_utils_pty::SpawnedProcess;
|
||||
use codex_utils_pty::TerminalSize;
|
||||
use codex_utils_pty::WindowsTtyInputNormalizer;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::ptr;
|
||||
@@ -153,13 +153,13 @@ fn spawn_input_writer(
|
||||
normalize_newlines: bool,
|
||||
) -> tokio::task::JoinHandle<()> {
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let mut previous_was_cr = false;
|
||||
let mut windows_input = WindowsTtyInputNormalizer::default();
|
||||
while let Some(bytes) = writer_rx.blocking_recv() {
|
||||
let Some(handle) = input_write else {
|
||||
continue;
|
||||
};
|
||||
let bytes = if normalize_newlines {
|
||||
normalize_windows_tty_input(&bytes, &mut previous_was_cr)
|
||||
windows_input.normalize(&bytes)
|
||||
} else {
|
||||
bytes
|
||||
};
|
||||
|
||||
@@ -11,6 +11,7 @@ use anyhow::Result;
|
||||
use codex_utils_pty::ProcessDriver;
|
||||
use codex_utils_pty::SpawnedProcess;
|
||||
use codex_utils_pty::TerminalSize;
|
||||
use codex_utils_pty::WindowsTtyInputNormalizer;
|
||||
use codex_utils_pty::spawn_from_driver;
|
||||
use std::fs::File;
|
||||
use tokio::sync::broadcast;
|
||||
@@ -25,23 +26,6 @@ pub(crate) fn finish_driver_spawn(driver: ProcessDriver, stdin_open: bool) -> Sp
|
||||
spawned
|
||||
}
|
||||
|
||||
pub(crate) fn normalize_windows_tty_input(bytes: &[u8], previous_was_cr: &mut bool) -> Vec<u8> {
|
||||
let mut normalized = Vec::with_capacity(bytes.len());
|
||||
for &byte in bytes {
|
||||
if byte == b'\n' {
|
||||
if !*previous_was_cr {
|
||||
normalized.push(b'\r');
|
||||
}
|
||||
normalized.push(b'\n');
|
||||
*previous_was_cr = false;
|
||||
} else {
|
||||
normalized.push(byte);
|
||||
*previous_was_cr = byte == b'\r';
|
||||
}
|
||||
}
|
||||
normalized
|
||||
}
|
||||
|
||||
pub(crate) fn start_runner_pipe_writer(
|
||||
mut pipe_write: File,
|
||||
) -> std::sync::mpsc::Sender<FramedMessage> {
|
||||
@@ -63,10 +47,10 @@ pub(crate) fn start_runner_stdin_writer(
|
||||
stdin_open: bool,
|
||||
) -> tokio::task::JoinHandle<()> {
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let mut previous_was_cr = false;
|
||||
let mut windows_input = WindowsTtyInputNormalizer::default();
|
||||
while let Some(bytes) = writer_rx.blocking_recv() {
|
||||
let bytes = if normalize_newlines {
|
||||
normalize_windows_tty_input(&bytes, &mut previous_was_cr)
|
||||
windows_input.normalize(&bytes)
|
||||
} else {
|
||||
bytes
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user