From c00a62dda169beb472fc2f386d0f673ca100dfa4 Mon Sep 17 00:00:00 2001 From: akbash Date: Sun, 20 Sep 2026 17:10:16 +0300 Subject: fix: preserve delayed mouse reports with confirmed keyboard input (#4247) * fix: preserve delayed mouse reports with confirmed keyboard input refs #3480 * fix: capture geometry before replaying buffered mouse input refs #3480 --------- Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> Co-authored-by: JJ Liebig --- src/client/input.rs | 85 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 25 deletions(-) (limited to 'src/client/input.rs') diff --git a/src/client/input.rs b/src/client/input.rs index 41850f96..45656f84 100644 --- a/src/client/input.rs +++ b/src/client/input.rs @@ -42,6 +42,8 @@ pub fn stdin_reader_loop( host_cell_size_query_sent: bool, host_mouse_capture_active: Arc, host_sgr_pixels_active: Arc, + host_escape_disambiguation_active: bool, + initial_host_input: Vec, #[cfg(unix)] direct_response: Arc>, #[cfg(unix)] direct_response_active: Arc, ) { @@ -53,6 +55,7 @@ pub fn stdin_reader_loop( host_mouse_capture_active, host_sgr_pixels_active, ); + let _ = (host_escape_disambiguation_active, initial_host_input); windows_stdin_reader_loop(event_tx, should_quit); } @@ -64,6 +67,8 @@ pub fn stdin_reader_loop( host_cell_size_query_sent, host_mouse_capture_active, host_sgr_pixels_active, + host_escape_disambiguation_active, + initial_host_input, direct_response, direct_response_active, ); @@ -77,6 +82,8 @@ fn unix_stdin_reader_loop( host_cell_size_query_sent: bool, host_mouse_capture_active: Arc, host_sgr_pixels_active: Arc, + host_escape_disambiguation_active: bool, + initial_host_input: Vec, direct_response: Arc>, direct_response_active: Arc, ) { @@ -84,6 +91,7 @@ fn unix_stdin_reader_loop( let mut reader = stdin.lock(); let mut scratch = [0u8; 4096]; let mut framer = crate::raw_input::RawInputByteFramer::for_host_input(); + framer.set_host_escape_disambiguation_active(host_escape_disambiguation_active); if host_color_query_sent { framer.host_color_query_sent(); framer.enable_host_color_scheme_change_tracking(); @@ -97,6 +105,57 @@ fn unix_stdin_reader_loop( let mut last_geometry = None; let mut direct_filter = super::direct_graphics::InputFilter::default(); + if !initial_host_input.is_empty() { + let sgr_pixels = host_sgr_pixels_active.load(Ordering::Acquire); + if sgr_pixels { + last_geometry = crate::input::mouse::HostGeometry::current(); + } + let chunks = framer.push(&initial_host_input); + if !send_unix_input_chunks( + chunks, + &event_tx, + &mut pending_palette, + sgr_pixels, + last_geometry, + ) { + return; + } + if (framer.has_pending_input() || !pending_palette.is_empty()) + && stdin_read_ready( + &reader, + idle_flush_timeout_ms(&framer, host_mouse_capture_active.load(Ordering::Acquire)), + ) == Some(false) + { + let had_pending = framer.has_pending_input(); + let chunks = framer.flush_timeout(); + let held_escape = had_pending && chunks.is_empty(); + if !send_unix_input_chunks( + chunks, + &event_tx, + &mut pending_palette, + sgr_pixels, + last_geometry, + ) || !flush_unix_palette_input(&event_tx, &mut pending_palette) + { + return; + } + if held_escape + && stdin_read_ready(&reader, crate::raw_input::RAW_INPUT_IDLE_FLUSH_TIMEOUT_MS) + == Some(false) + && !send_unix_input_chunks( + framer.flush_timeout(), + &event_tx, + &mut pending_palette, + sgr_pixels, + last_geometry, + ) + { + return; + } + } + pending_mode = framer.has_pending_input().then_some(sgr_pixels); + } + while !should_quit.load(Ordering::Acquire) { if direct_filter.has_pending() && stdin_read_ready(&reader, crate::raw_input::RAW_INPUT_IDLE_FLUSH_TIMEOUT_MS) @@ -593,31 +652,7 @@ fn stdin_read_ready(reader: &R, timeout_ms: i32) -> Option { #[cfg(unix)] fn poll_read_ready(fd: i32, timeout_ms: i32) -> Option { - #[repr(C)] - struct PollFd { - fd: i32, - events: i16, - revents: i16, - } - - unsafe extern "C" { - fn poll(fds: *mut PollFd, nfds: usize, timeout: i32) -> i32; - } - - const POLLIN: i16 = 0x0001; - - let mut pfd = PollFd { - fd, - events: POLLIN, - revents: 0, - }; - - let result = unsafe { poll(&mut pfd as *mut PollFd, 1, timeout_ms) }; - if result < 0 { - None - } else { - Some(result > 0) - } + crate::platform::poll_fd_readable(fd, timeout_ms).ok() } // --------------------------------------------------------------------------- -- cgit v1.2.3