diff --git a/src/bin/dosh-client.rs b/src/bin/dosh-client.rs index d50aa20..5a8cd72 100644 --- a/src/bin/dosh-client.rs +++ b/src/bin/dosh-client.rs @@ -10540,8 +10540,15 @@ fn windows_vt_output_mode(mode: u32) -> u32 { mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING } +#[cfg_attr(not(any(test, windows)), allow(dead_code))] +fn windows_vt_input_mode(mode: u32) -> u32 { + const ENABLE_VIRTUAL_TERMINAL_INPUT: u32 = 0x0200; + mode | ENABLE_VIRTUAL_TERMINAL_INPUT +} + #[cfg(windows)] struct WindowsConsoleModeGuard { + input: Option<(windows_sys::Win32::Foundation::HANDLE, u32)>, output: Option<(windows_sys::Win32::Foundation::HANDLE, u32)>, } @@ -10551,28 +10558,53 @@ impl WindowsConsoleModeGuard { unsafe { use windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE; use windows_sys::Win32::System::Console::{ - GetConsoleMode, GetStdHandle, STD_OUTPUT_HANDLE, SetConsoleMode, + GetConsoleMode, GetStdHandle, STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, SetConsoleMode, }; - let handle = GetStdHandle(STD_OUTPUT_HANDLE); - if handle.is_null() || handle == INVALID_HANDLE_VALUE { - return Self { output: None }; - } - let mut original = 0u32; - if GetConsoleMode(handle, &mut original) == 0 { - return Self { output: None }; - } - let desired = windows_vt_output_mode(original); - if desired != original { - let _ = SetConsoleMode(handle, desired); - } - Self { - output: Some((handle, original)), - } + let input_handle = GetStdHandle(STD_INPUT_HANDLE); + let input = if input_handle.is_null() || input_handle == INVALID_HANDLE_VALUE { + None + } else { + let mut original = 0u32; + if GetConsoleMode(input_handle, &mut original) == 0 { + None + } else { + let desired = windows_vt_input_mode(original); + if desired != original { + let _ = SetConsoleMode(input_handle, desired); + } + Some((input_handle, original)) + } + }; + + let output_handle = GetStdHandle(STD_OUTPUT_HANDLE); + let output = if output_handle.is_null() || output_handle == INVALID_HANDLE_VALUE { + None + } else { + let mut original = 0u32; + if GetConsoleMode(output_handle, &mut original) == 0 { + None + } else { + let desired = windows_vt_output_mode(original); + if desired != original { + let _ = SetConsoleMode(output_handle, desired); + } + Some((output_handle, original)) + } + }; + + Self { input, output } } } fn restore(&self) { + if let Some((handle, mode)) = self.input { + unsafe { + use windows_sys::Win32::System::Console::SetConsoleMode; + + let _ = SetConsoleMode(handle, mode); + } + } if let Some((handle, mode)) = self.output { unsafe { use windows_sys::Win32::System::Console::SetConsoleMode; @@ -10714,7 +10746,7 @@ mod tests { wake_repaint_retry_deadline, windows_command_word, windows_deferred_update_script, windows_effective_url_script, windows_mode_from_readonly, windows_powershell_command_candidates, windows_readonly_from_mode, windows_update_script, - windows_url_reachable_script, windows_vt_output_mode, + windows_url_reachable_script, windows_vt_input_mode, windows_vt_output_mode, }; use dosh::config::{ClientConfig, CommandExtension, HostConfig}; use dosh::native::EnvVar; @@ -10846,6 +10878,13 @@ mod tests { assert_eq!(windows_vt_output_mode(0x0005), 0x0005); } + #[test] + fn windows_vt_input_mode_enables_escape_sequence_input() { + assert_eq!(windows_vt_input_mode(0), 0x0200); + assert_eq!(windows_vt_input_mode(0x0001), 0x0201); + assert_eq!(windows_vt_input_mode(0x0201), 0x0201); + } + #[test] fn cleanup_stream_state_removes_all_per_stream_state_only_for_target() { let stream_id = 42;