diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-09-15 17:24:35 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-15 17:24:35 +0300 |
| commit | ee064a0c798dd5617d253be7d26aa41f924bab96 (patch) | |
| tree | ac63fa4f16002c83f3931fc8085bb80923778f96 /src | |
| parent | 963f78f46c8f10d0bfc869f0ea13223892a1f0ef (diff) | |
fix(windows): preserve sgr mouse encoding after native capture (#4195)
refs #4155
Diffstat (limited to 'src')
| -rw-r--r-- | src/client/terminal_setup.rs | 50 | ||||
| -rw-r--r-- | src/terminal_modes.rs | 12 |
2 files changed, 54 insertions, 8 deletions
diff --git a/src/client/terminal_setup.rs b/src/client/terminal_setup.rs index cc13bcdd..44f6fbaa 100644 --- a/src/client/terminal_setup.rs +++ b/src/client/terminal_setup.rs @@ -476,6 +476,54 @@ impl Drop for TerminalGuard { mod tests { use super::*; + #[derive(Clone, Default)] + struct SharedOutput(std::rc::Rc<std::cell::RefCell<Vec<u8>>>); + + impl io::Write for SharedOutput { + fn write(&mut self, bytes: &[u8]) -> io::Result<usize> { + self.0.borrow_mut().extend_from_slice(bytes); + Ok(bytes.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + } + + #[test] + fn windows_native_mouse_capture_never_resets_encoding_after_native_enable() { + let mut output = SharedOutput::default(); + for sgr_pixels in [false, false, true, false] { + let start = output.0.borrow().len(); + let native_output = output.clone(); + let native_boundary = std::cell::Cell::new(0); + set_windows_native_mouse_capture(&mut output, true, sgr_pixels, |enabled| { + assert!(enabled); + // ConPTY enables host SGR during native capture, before our VT requests. + native_output + .0 + .borrow_mut() + .extend_from_slice(b"\x1b[?1003h\x1b[?1006h"); + native_boundary.set(native_output.0.borrow().len()); + Ok(()) + }) + .unwrap(); + + 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!( + !after.contains(reset), + "mouse format reset after native capture (sgr_pixels={sgr_pixels}): {after:?}" + ); + } + assert!(after.contains("\x1b[?1003h\x1b[?1006h")); + assert_eq!(after.contains("\x1b[?1016h"), sgr_pixels); + } + } + #[test] fn windows_native_mouse_capture_restores_reporting_after_reset() { let mut output = Vec::new(); @@ -488,7 +536,7 @@ mod tests { 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\x1b[?1016l" + 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" ); } } diff --git a/src/terminal_modes.rs b/src/terminal_modes.rs index 810fa871..11bf56fc 100644 --- a/src/terminal_modes.rs +++ b/src/terminal_modes.rs @@ -26,12 +26,10 @@ pub(crate) fn set_windows_mouse_reporting<W: Write>( } else { WINDOWS_MOUSE_REPORTING_DISABLE_SEQUENCE })?; - if enabled { - writer.write_all(if sgr_pixels { - b"\x1b[?1016h" - } else { - b"\x1b[?1016l" - })?; + // 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.flush() } @@ -197,7 +195,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[?1016l\x1b[?1006l\x1b[?1003l\x1b[?1002l\x1b[?1000l" + 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" ); } } |
