From 63a1cfe3a375556353d1c8ff76fab4fa217aa46f Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 11 Jun 2026 15:41:06 -0400 Subject: [PATCH] Use raw terminal input without cursor translation --- src/bin/dosh-client.rs | 104 +---------------------------------------- 1 file changed, 1 insertion(+), 103 deletions(-) diff --git a/src/bin/dosh-client.rs b/src/bin/dosh-client.rs index f9de696..e7430c1 100644 --- a/src/bin/dosh-client.rs +++ b/src/bin/dosh-client.rs @@ -555,10 +555,7 @@ 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 remote_terminal = vt100::Parser::new(last_size.1.max(1), last_size.0.max(1), 0); - let mut input_translator = UserInputTranslator::default(); if let Some(frame) = first_frame { - remote_terminal.process(&frame.bytes); render_frame(&frame)?; if frame.closed { return Ok(()); @@ -594,10 +591,6 @@ async fn run_terminal( break; } if cred.mode != "view-only" { - let bytes = input_translator.translate( - &bytes, - remote_terminal.screen().application_cursor(), - ); let body = protocol::to_body(&Input { bytes })?; let packet = protocol::encode_encrypted( PacketKind::Input, @@ -620,7 +613,6 @@ async fn run_terminal( && (cols, rows) != last_size { last_size = (cols, rows); - remote_terminal.set_size(rows.max(1), cols.max(1)); if cred.mode != "view-only" { send_resize(&socket, addr, &cred, &mut send_seq, cols, rows).await?; } @@ -638,7 +630,6 @@ async fn run_terminal( PacketKind::Frame | PacketKind::ResumeOk => { let plain = protocol::decrypt_body(&packet, &cred.session_key, SERVER_TO_CLIENT)?; let frame: Frame = protocol::from_body(&plain)?; - remote_terminal.process(&frame.bytes); render_frame(&frame)?; cred.last_rendered_seq = frame.output_seq; send_ack(&socket, addr, &cred, &mut send_seq).await?; @@ -682,54 +673,6 @@ async fn run_terminal( Ok(()) } -#[derive(Default)] -struct UserInputTranslator { - state: UserInputState, -} - -#[derive(Default)] -enum UserInputState { - #[default] - Ground, - Esc, - Ss3, -} - -impl UserInputTranslator { - fn translate(&mut self, bytes: &[u8], application_cursor: bool) -> Vec { - let mut out = Vec::with_capacity(bytes.len()); - for &byte in bytes { - match self.state { - UserInputState::Ground => { - if byte == 0x1b { - self.state = UserInputState::Esc; - } - out.push(byte); - } - UserInputState::Esc => { - if byte == b'O' { - self.state = UserInputState::Ss3; - } else { - self.state = UserInputState::Ground; - out.push(byte); - } - } - UserInputState::Ss3 => { - self.state = UserInputState::Ground; - if !application_cursor && matches!(byte, b'A'..=b'D') { - out.push(b'['); - out.push(byte); - } else { - out.push(b'O'); - out.push(byte); - } - } - } - } - out - } -} - async fn send_resize( socket: &UdpSocket, addr: SocketAddr, @@ -840,7 +783,7 @@ impl RawMode { fn enter() -> Result { enable_raw_mode()?; let mut stdout = std::io::stdout(); - stdout.write_all(TERMINAL_OPEN)?; + stdout.write_all(TERMINAL_CLEANUP)?; stdout.flush()?; Ok(Self) } @@ -855,23 +798,6 @@ impl Drop for RawMode { } } -const TERMINAL_OPEN: &[u8] = concat!( - "\x1b[?1l", - "\x1b[0m", - "\x1b[?25h", - "\x1b[?1003l", - "\x1b[?1002l", - "\x1b[?1001l", - "\x1b[?1000l", - "\x1b[?1015l", - "\x1b[?1006l", - "\x1b[?1005l", - "\x1b[?2004l", - "\x1b[?1049l", - "\x1b[?1h" -) -.as_bytes(); - const TERMINAL_CLEANUP: &[u8] = concat!( "\x1b[?1l", "\x1b[0m", @@ -887,31 +813,3 @@ const TERMINAL_CLEANUP: &[u8] = concat!( "\x1b[?1049l" ) .as_bytes(); - -#[cfg(test)] -mod tests { - use super::UserInputTranslator; - - #[test] - fn translates_application_cursor_arrows_for_normal_remote_mode() { - let mut translator = UserInputTranslator::default(); - assert_eq!(translator.translate(b"\x1bOA", false), b"\x1b[A"); - assert_eq!(translator.translate(b"\x1bOB", false), b"\x1b[B"); - assert_eq!(translator.translate(b"\x1bOC", false), b"\x1b[C"); - assert_eq!(translator.translate(b"\x1bOD", false), b"\x1b[D"); - } - - #[test] - fn preserves_application_cursor_arrows_for_remote_application_mode() { - let mut translator = UserInputTranslator::default(); - assert_eq!(translator.translate(b"\x1bOA", true), b"\x1bOA"); - } - - #[test] - fn preserves_split_escape_state_between_reads() { - let mut translator = UserInputTranslator::default(); - assert_eq!(translator.translate(b"\x1b", false), b"\x1b"); - assert_eq!(translator.translate(b"O", false), b""); - assert_eq!(translator.translate(b"A", false), b"[A"); - } -}