Cover terminal mouse input filtering
ci / test (push) Has been cancelled
ci / fuzz-smoke (push) Has been cancelled
ci / windows-client (push) Has been cancelled
ci / package-release (linux-x86_64, ubuntu-latest) (push) Has been cancelled
ci / package-release (macos-aarch64, macos-14) (push) Has been cancelled
ci / package-release (macos-x86_64, macos-13) (push) Has been cancelled
ci / package-release (windows-x86_64, windows-latest) (push) Has been cancelled
ci / remote-bench (push) Has been cancelled

This commit is contained in:
DuProcess
2026-07-12 01:08:38 -04:00
parent 70650e221b
commit 818b481154
+67 -12
View File
@@ -5634,13 +5634,14 @@ async fn run_terminal(
if bytes.is_empty() {
continue;
}
if should_strip_unowned_terminal_reports(
let before_mouse_strip = bytes.len();
let (stripped_bytes, stripped_unowned_mouse) = strip_unowned_terminal_reports(
bytes,
predictor.alternate_screen,
predictor.mouse_tracking,
) {
let before_mouse_strip = bytes.len();
bytes = strip_stale_mouse_reports(&bytes);
if before_mouse_strip != bytes.len() {
);
bytes = stripped_bytes;
if stripped_unowned_mouse {
dosh::trace::event(
"client.unowned_mouse_stripped",
&[
@@ -5649,7 +5650,6 @@ async fn run_terminal(
("summary", dosh::trace::bytes_summary(&bytes)),
],
);
}
if bytes.is_empty() {
continue;
}
@@ -6983,6 +6983,20 @@ fn should_strip_unowned_terminal_reports(alternate_screen: bool, mouse_tracking:
!alternate_screen && !mouse_tracking
}
fn strip_unowned_terminal_reports(
bytes: Vec<u8>,
alternate_screen: bool,
mouse_tracking: bool,
) -> (Vec<u8>, bool) {
if !should_strip_unowned_terminal_reports(alternate_screen, mouse_tracking) {
return (bytes, false);
}
let before = bytes.len();
let stripped = strip_stale_mouse_reports(&bytes);
let changed = stripped.len() != before;
(stripped, changed)
}
fn input_contains_focus_in(bytes: &[u8]) -> bool {
contains_bytes(bytes, b"\x1b[I") || contains_bytes(bytes, b"\x9bI")
}
@@ -8969,8 +8983,8 @@ mod tests {
native_proxy_udp_warning, parse_dynamic_forward, parse_escape_key, parse_local_forward,
parse_remote_forward, parse_ssh_config, parse_trace_line, parse_trace_options,
parse_trace_report_options, parse_trace_summary, parse_update_options,
post_submit_hold_duration, queue_pending_user_input, raw_contains_host_table,
recv_response_until, refresh_live_addr, release_tag_download_url,
post_submit_hold_duration, queue_pending_user_input, queue_stale_pending_user_input,
raw_contains_host_table, recv_response_until, refresh_live_addr, release_tag_download_url,
release_tag_from_effective_url, release_version_from_tag, render_status_clear,
render_status_overlay, requested_env, resolved_startup_command, retire_stream_state,
retransmit_stream_opens, rewrite_forward_command, sanitize_trace_name,
@@ -8980,10 +8994,10 @@ mod tests {
should_strip_unowned_terminal_reports, split_after_command_submit, split_trace_tokens,
ssh_command_target, ssh_config_uses_proxy, ssh_destination_host, ssh_username,
ssh_with_user, startup_command, status_ssh_target, strip_stale_mouse_reports,
strip_terminal_focus_reports, summarize_trace_file, terminal_private_mode_transition,
toml_bare_key_or_quoted, top_trace_events, trace_report_warnings, unix_update_script,
update_installer_url, update_version_status, upsert_managed_block, valid_forward_host,
vscode_safe_alias, windows_update_script,
strip_terminal_focus_reports, strip_unowned_terminal_reports, summarize_trace_file,
terminal_private_mode_transition, toml_bare_key_or_quoted, top_trace_events,
trace_report_warnings, unix_update_script, update_installer_url, update_version_status,
upsert_managed_block, valid_forward_host, vscode_safe_alias, windows_update_script,
};
use dosh::config::{ClientConfig, CommandExtension, HostConfig};
use dosh::native::EnvVar;
@@ -10817,6 +10831,47 @@ mod tests {
assert_eq!(pending_bytes, MAX_PENDING_USER_INPUT_BYTES);
}
#[test]
fn stale_pending_user_input_is_marked_for_mouse_stripping() {
let mut pending = VecDeque::new();
let mut pending_bytes = 0usize;
queue_pending_user_input(&mut pending, &mut pending_bytes, b"\x1b[<35;10;1M".to_vec())
.unwrap();
queue_stale_pending_user_input(
&mut pending,
&mut pending_bytes,
b"\x1b[<35;11;1M".to_vec(),
)
.unwrap();
let normal = pending.pop_front().unwrap();
assert!(!normal.strip_mouse_reports);
assert_eq!(strip_stale_mouse_reports(&normal.bytes), b"");
let stale = pending.pop_front().unwrap();
assert!(stale.strip_mouse_reports);
assert_eq!(strip_stale_mouse_reports(&stale.bytes), b"");
}
#[test]
fn unowned_terminal_mouse_reports_strip_only_without_mouse_owner() {
let input = b"\x1b[<35;10;1Mcmd\r".to_vec();
let (stripped, changed) = strip_unowned_terminal_reports(input.clone(), false, false);
assert!(changed);
assert_eq!(stripped, b"cmd\r");
let (preserved, changed) = strip_unowned_terminal_reports(input.clone(), false, true);
assert!(!changed);
assert_eq!(preserved, input);
let (preserved, changed) =
strip_unowned_terminal_reports(b"\x1b[<35;10;1M".to_vec(), true, false);
assert!(!changed);
assert_eq!(preserved, b"\x1b[<35;10;1M");
}
#[test]
fn transient_udp_send_errors_are_not_terminal_fatal() {
#[cfg(unix)]