From fd7849f8898a2b4be913d06194477ef18dc5f92e Mon Sep 17 00:00:00 2001 From: DuProcess <273172371+DuProcess@users.noreply.github.com> Date: Thu, 11 Jun 2026 22:22:03 -0400 Subject: [PATCH] Forward terminal input bytes without cursor rewriting --- src/bin/dosh-client.rs | 75 +----------------------------------------- 1 file changed, 1 insertion(+), 74 deletions(-) diff --git a/src/bin/dosh-client.rs b/src/bin/dosh-client.rs index 46e40c9..dfd3721 100644 --- a/src/bin/dosh-client.rs +++ b/src/bin/dosh-client.rs @@ -605,7 +605,6 @@ async fn run_terminal( let mut status_tick = tokio::time::interval(Duration::from_secs(1)); let mut resize_tick = tokio::time::interval(Duration::from_millis(250)); let mut last_size = size().unwrap_or((80, 24)); - let mut input_normalizer = InputNormalizer::default(); if let Some(frame) = first_frame { render_frame(&frame)?; if frame.closed { @@ -642,7 +641,6 @@ async fn run_terminal( break; } if cred.mode != "view-only" { - let bytes = input_normalizer.normalize(&bytes); let body = protocol::to_body(&Input { bytes })?; let packet = protocol::encode_encrypted( PacketKind::Input, @@ -725,54 +723,6 @@ async fn run_terminal( Ok(()) } -#[derive(Default)] -struct InputNormalizer { - state: InputNormalizerState, -} - -#[derive(Default)] -enum InputNormalizerState { - #[default] - Ground, - Esc, - Ss3, -} - -impl InputNormalizer { - fn normalize(&mut self, bytes: &[u8]) -> Vec { - let mut out = Vec::with_capacity(bytes.len()); - for &byte in bytes { - match self.state { - InputNormalizerState::Ground => { - out.push(byte); - if byte == 0x1b { - self.state = InputNormalizerState::Esc; - } - } - InputNormalizerState::Esc => { - if byte == b'O' { - self.state = InputNormalizerState::Ss3; - } else { - out.push(byte); - self.state = InputNormalizerState::Ground; - } - } - InputNormalizerState::Ss3 => { - if matches!(byte, b'A'..=b'D') { - out.push(b'['); - out.push(byte); - } else { - out.push(b'O'); - out.push(byte); - } - self.state = InputNormalizerState::Ground; - } - } - } - out - } -} - async fn send_resize( socket: &UdpSocket, addr: SocketAddr, @@ -916,30 +866,7 @@ const TERMINAL_CLEANUP: &[u8] = concat!( #[cfg(test)] mod tests { - use super::{InputNormalizer, parse_ssh_config_hostname, ssh_destination_host}; - - #[test] - fn normalizes_ss3_cursor_keys_to_csi() { - let mut normalizer = InputNormalizer::default(); - assert_eq!(normalizer.normalize(b"\x1bOA"), b"\x1b[A"); - assert_eq!(normalizer.normalize(b"\x1bOB"), b"\x1b[B"); - assert_eq!(normalizer.normalize(b"\x1bOC"), b"\x1b[C"); - assert_eq!(normalizer.normalize(b"\x1bOD"), b"\x1b[D"); - } - - #[test] - fn preserves_split_ss3_cursor_state_between_reads() { - let mut normalizer = InputNormalizer::default(); - assert_eq!(normalizer.normalize(b"\x1b"), b"\x1b"); - assert_eq!(normalizer.normalize(b"O"), b""); - assert_eq!(normalizer.normalize(b"B"), b"[B"); - } - - #[test] - fn leaves_non_cursor_ss3_sequences_raw() { - let mut normalizer = InputNormalizer::default(); - assert_eq!(normalizer.normalize(b"\x1bOP"), b"\x1bOP"); - } + use super::{parse_ssh_config_hostname, ssh_destination_host}; #[test] fn parses_ssh_config_hostname() {