aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJJ Liebig <jonathan.liebig@gmail.com>2026-09-18 02:42:37 +0200
committerGitHub <noreply@github.com>2026-09-18 02:42:37 +0200
commitda6bcd5969779bfe0396bcf89a8025d4375d611e (patch)
treeaece03633c003ba0fce01bc2564ad14e0fe9cac9 /src
parentb88e8116e9e1f7e2f6e8b211536311cd17feca9a (diff)
fix(windows): preserve mouse capture during refresh (#4319)
* fix(windows): preserve mouse capture during refresh refs #4284 * test(windows): fix default input gauntlet invocation * fix(windows): preserve pixel mouse transitions refs #4284
Diffstat (limited to 'src')
-rw-r--r--src/client/terminal_setup.rs25
-rw-r--r--src/terminal_modes.rs21
2 files changed, 28 insertions, 18 deletions
diff --git a/src/client/terminal_setup.rs b/src/client/terminal_setup.rs
index e888305d..3bb5c281 100644
--- a/src/client/terminal_setup.rs
+++ b/src/client/terminal_setup.rs
@@ -348,7 +348,9 @@ fn set_windows_native_mouse_capture<W: io::Write>(
sgr_pixels: bool,
set_console_capture: impl FnOnce(bool) -> io::Result<()>,
) -> io::Result<()> {
- crate::terminal_modes::clear_host_mouse_reporting(writer)?;
+ if !enabled {
+ crate::terminal_modes::clear_host_mouse_reporting(writer)?;
+ }
set_console_capture(enabled)?;
if enabled {
crate::terminal_modes::set_windows_mouse_reporting(writer, true, sgr_pixels)?;
@@ -365,7 +367,9 @@ fn windows_uses_vt_mouse_reporting() -> bool {
pub(super) fn set_mouse_capture(enabled: bool, sgr_pixels: bool) -> io::Result<()> {
#[cfg(windows)]
if windows_uses_vt_mouse_reporting() {
- crate::terminal_modes::clear_host_mouse_reporting(&mut io::stdout())?;
+ if !enabled {
+ crate::terminal_modes::clear_host_mouse_reporting(&mut io::stdout())?;
+ }
return crate::terminal_modes::set_windows_mouse_reporting(
&mut io::stdout(),
enabled,
@@ -642,7 +646,7 @@ mod tests {
}
#[test]
- fn windows_native_mouse_capture_never_resets_encoding_after_native_enable() {
+ fn windows_native_mouse_capture_reasserts_final_encoding_after_native_enable() {
let mut output = SharedOutput::default();
for sgr_pixels in [false, false, true, false] {
let start = output.0.borrow().len();
@@ -663,8 +667,8 @@ mod tests {
let bytes = output.0.borrow();
let before = std::str::from_utf8(&bytes[start..native_boundary.get()]).unwrap();
let after = std::str::from_utf8(&bytes[native_boundary.get()..]).unwrap();
- assert!(before.contains("\x1b[?1016l"));
- for reset in ["\x1b[?1005l", "\x1b[?1006l", "\x1b[?1016l"] {
+ assert!(!before.contains("\x1b[?1016l"));
+ for reset in ["\x1b[?1005l", "\x1b[?1006l"] {
assert!(
!after.contains(reset),
"mouse format reset after native capture (sgr_pixels={sgr_pixels}): {after:?}"
@@ -672,22 +676,25 @@ mod tests {
}
assert!(after.contains("\x1b[?1003h\x1b[?1006h"));
assert_eq!(after.contains("\x1b[?1016h"), sgr_pixels);
+ if !sgr_pixels {
+ assert!(after.starts_with("\x1b[?1016l"));
+ }
}
}
#[test]
- fn windows_native_mouse_capture_restores_reporting_after_reset() {
+ fn windows_native_mouse_capture_disable_clears_reporting() {
let mut output = Vec::new();
- set_windows_native_mouse_capture(&mut output, true, false, |enabled| {
- assert!(enabled);
+ set_windows_native_mouse_capture(&mut output, false, false, |enabled| {
+ assert!(!enabled);
Ok(())
})
.unwrap();
assert_eq!(
output,
- b"\x1b[?1006l\x1b[?1016l\x1b[?1015l\x1b[?1005l\x1b[?1003l\x1b[?1002l\x1b[?1000l\x1b[?9l\x1b[?1000h\x1b[?1002h\x1b[?1003h\x1b[?1006h"
+ b"\x1b[?1006l\x1b[?1016l\x1b[?1015l\x1b[?1005l\x1b[?1003l\x1b[?1002l\x1b[?1000l\x1b[?9l"
);
}
}
diff --git a/src/terminal_modes.rs b/src/terminal_modes.rs
index 11bf56fc..b3973209 100644
--- a/src/terminal_modes.rs
+++ b/src/terminal_modes.rs
@@ -21,15 +21,18 @@ pub(crate) fn set_windows_mouse_reporting<W: Write>(
enabled: bool,
sgr_pixels: bool,
) -> io::Result<()> {
- writer.write_all(if enabled {
- WINDOWS_MOUSE_REPORTING_ENABLE_SEQUENCE
+ if enabled {
+ // Keep a true-to-false pixel transition in the same buffered reassertion,
+ // before the final SGR enable, so refresh never exposes a disabled gap.
+ if !sgr_pixels {
+ writer.write_all(b"\x1b[?1016l")?;
+ }
+ writer.write_all(WINDOWS_MOUSE_REPORTING_ENABLE_SEQUENCE)?;
+ if sgr_pixels {
+ writer.write_all(b"\x1b[?1016h")?;
+ }
} else {
- WINDOWS_MOUSE_REPORTING_DISABLE_SEQUENCE
- })?;
- // The caller clears modes before native capture. Resetting 1016 here can
- // undo the SGR encoding that ConPTY has already enabled on the host.
- if enabled && sgr_pixels {
- writer.write_all(b"\x1b[?1016h")?;
+ writer.write_all(WINDOWS_MOUSE_REPORTING_DISABLE_SEQUENCE)?;
}
writer.flush()
}
@@ -195,7 +198,7 @@ mod tests {
assert_eq!(
output,
- b"\x1b[?1000h\x1b[?1002h\x1b[?1003h\x1b[?1006h\x1b[?1016h\x1b[?1000h\x1b[?1002h\x1b[?1003h\x1b[?1006h\x1b[?1016l\x1b[?1006l\x1b[?1003l\x1b[?1002l\x1b[?1000l"
+ b"\x1b[?1000h\x1b[?1002h\x1b[?1003h\x1b[?1006h\x1b[?1016h\x1b[?1016l\x1b[?1000h\x1b[?1002h\x1b[?1003h\x1b[?1006h\x1b[?1016l\x1b[?1006l\x1b[?1003l\x1b[?1002l\x1b[?1000l"
);
}
}