diff options
| author | JJ Liebig <jonathan.liebig@gmail.com> | 2026-09-17 00:07:58 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-17 00:07:58 +0200 |
| commit | 20c15dd7c8e516753a09e74d400b0637f5fd5682 (patch) | |
| tree | ed56565d7851b986071ec453eee757c94478e724 /src | |
| parent | 5f3763dda88e0fefbce14afab7cc2c7232a5e2a8 (diff) | |
fix(windows): preserve VT input during mouse refresh (#4257)
refs #4251
Diffstat (limited to 'src')
| -rw-r--r-- | src/client/input.rs | 2 | ||||
| -rw-r--r-- | src/client/input/windows_vti.rs | 10 | ||||
| -rw-r--r-- | src/client/terminal_setup.rs | 27 | ||||
| -rw-r--r-- | src/platform/windows.rs | 14 |
4 files changed, 36 insertions, 17 deletions
diff --git a/src/client/input.rs b/src/client/input.rs index c86f0878..e77d51fa 100644 --- a/src/client/input.rs +++ b/src/client/input.rs @@ -330,7 +330,7 @@ fn windows_stdin_reader_loop( windows_crossterm_reader_loop(event_tx, should_quit); } else { match windows_vti::console_input_handle() { - Ok(handle) if windows_vti::virtual_terminal_input_enabled(handle) => { + Ok(handle) if crate::platform::windows_virtual_terminal_input_active() => { windows_vti::raw_console_reader_loop(handle, event_tx, should_quit); } _ => windows_crossterm_reader_loop(event_tx, should_quit), diff --git a/src/client/input/windows_vti.rs b/src/client/input/windows_vti.rs index 95e01d4b..e9cfa4e6 100644 --- a/src/client/input/windows_vti.rs +++ b/src/client/input/windows_vti.rs @@ -97,16 +97,6 @@ pub(super) fn console_input_handle() -> std::io::Result<windows_sys::Win32::Foun } #[cfg(windows)] -pub(super) fn virtual_terminal_input_enabled( - handle: windows_sys::Win32::Foundation::HANDLE, -) -> bool { - use windows_sys::Win32::System::Console::{GetConsoleMode, ENABLE_VIRTUAL_TERMINAL_INPUT}; - - let mut mode = 0; - (unsafe { GetConsoleMode(handle, &mut mode) } != 0) && mode & ENABLE_VIRTUAL_TERMINAL_INPUT != 0 -} - -#[cfg(windows)] enum WindowsInputItems { Items(Vec<PlatformInputItem>), Idle, diff --git a/src/client/terminal_setup.rs b/src/client/terminal_setup.rs index 44f6fbaa..e42c5ec8 100644 --- a/src/client/terminal_setup.rs +++ b/src/client/terminal_setup.rs @@ -280,9 +280,15 @@ fn set_windows_native_mouse_capture<W: io::Write>( Ok(()) } +#[cfg(windows)] +fn windows_uses_vt_mouse_reporting() -> bool { + windows_vti_input_backend_enabled() + && (is_ssh_session() || crate::platform::windows_virtual_terminal_input_active()) +} + pub(super) fn set_mouse_capture(enabled: bool, sgr_pixels: bool) -> io::Result<()> { #[cfg(windows)] - if is_ssh_session() && windows_vti_input_backend_enabled() { + if windows_uses_vt_mouse_reporting() { crate::terminal_modes::clear_host_mouse_reporting(&mut io::stdout())?; return crate::terminal_modes::set_windows_mouse_reporting( &mut io::stdout(), @@ -295,11 +301,7 @@ pub(super) fn set_mouse_capture(enabled: bool, sgr_pixels: bool) -> io::Result<( if enabled { execute!(io::stdout(), EnableMouseCapture) } else { - match execute!(io::stdout(), DisableMouseCapture) { - Ok(()) => Ok(()), - Err(err) if err.to_string() == "Initial console modes not set" => Ok(()), - Err(err) => Err(err), - } + disable_windows_native_mouse_capture() } }); #[cfg(not(windows))] @@ -320,6 +322,15 @@ pub(super) fn set_mouse_capture(enabled: bool, sgr_pixels: bool) -> io::Result<( } } +#[cfg(windows)] +fn disable_windows_native_mouse_capture() -> io::Result<()> { + match execute!(io::stdout(), DisableMouseCapture) { + Ok(()) => Ok(()), + Err(err) if err.to_string() == "Initial console modes not set" => Ok(()), + Err(err) => Err(err), + } +} + fn restore_terminal_state_once( restore_claimed: &AtomicBool, reset_keyboard_enhancements: bool, @@ -368,6 +379,10 @@ fn restore_terminal_state( if let Some(mode) = restore_windows_input_mode { restore_windows_input_mode_value(mode); } + #[cfg(windows)] + if !is_ssh_session() { + let _ = disable_windows_native_mouse_capture(); + } let restore_result = ratatui::try_restore(); let postlude_result = diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 9742b52c..9e39a715 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -16,6 +16,20 @@ use std::{ mod clipboard_image; mod config_backup; +pub(crate) fn windows_virtual_terminal_input_active() -> bool { + use windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE; + use windows_sys::Win32::System::Console::{ + GetConsoleMode, GetStdHandle, ENABLE_VIRTUAL_TERMINAL_INPUT, STD_INPUT_HANDLE, + }; + + let handle = unsafe { GetStdHandle(STD_INPUT_HANDLE) }; + if handle.is_null() || handle == INVALID_HANDLE_VALUE { + return false; + } + let mut mode = 0; + (unsafe { GetConsoleMode(handle, &mut mode) } != 0) && mode & ENABLE_VIRTUAL_TERMINAL_INPUT != 0 +} + pub(crate) fn classify_child_exit(status: &portable_pty::ExitStatus) -> super::ChildExitReason { // STATUS_CONTROL_C_EXIT is reported without a Unix signal by portable-pty. if status.exit_code() == 0xC000013A { |
