mirror of
https://github.com/openai/codex.git
synced 2026-09-09 15:58:47 +00:00
## 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
36 lines
1.2 KiB
Rust
36 lines
1.2 KiB
Rust
/// Stateful normalizer for bytes written to a Windows pseudoconsole.
|
|
///
|
|
/// ConPTY accepts UTF-8 input, but an Enter key is represented by a carriage
|
|
/// return on Windows. This converts line feeds and collapses existing CRLF
|
|
/// sequences, including when the two bytes arrive in separate writes, so each
|
|
/// requested newline submits exactly one line. Backspace is encoded as DEL,
|
|
/// which ConPTY translates to `VK_BACK`. All other bytes, including UTF-8 and
|
|
/// terminal control characters, pass through unchanged.
|
|
#[derive(Default)]
|
|
pub struct WindowsTtyInputNormalizer {
|
|
previous_was_cr: bool,
|
|
}
|
|
|
|
impl WindowsTtyInputNormalizer {
|
|
pub fn normalize(&mut self, bytes: &[u8]) -> Vec<u8> {
|
|
let mut normalized = Vec::with_capacity(bytes.len());
|
|
for &byte in bytes {
|
|
match byte {
|
|
b'\x08' => normalized.push(b'\x7f'),
|
|
b'\n' => {
|
|
if !self.previous_was_cr {
|
|
normalized.push(b'\r');
|
|
}
|
|
}
|
|
_ => normalized.push(byte),
|
|
}
|
|
self.previous_was_cr = byte == b'\r';
|
|
}
|
|
normalized
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "windows_input_tests.rs"]
|
|
mod tests;
|