From e91bf807ec4680f78f9c8c2e6471399d164b15fa Mon Sep 17 00:00:00 2001 From: Mattias Eriksson Date: Wed, 31 Jan 2024 15:43:20 +0100 Subject: [PATCH] Improve SGR Scroll Wheel support --- src/mouse_reporter.rs | 47 ++++++++++++++++++++++++++++++++++++++++--- src/terminal.rs | 34 ++++++++++++++++++++++++------- src/terminal_box.rs | 9 +++++++-- 3 files changed, 78 insertions(+), 12 deletions(-) diff --git a/src/mouse_reporter.rs b/src/mouse_reporter.rs index 77c2a6d..d9a339a 100644 --- a/src/mouse_reporter.rs +++ b/src/mouse_reporter.rs @@ -172,9 +172,50 @@ impl MouseReporter { } } + pub fn report_sgr_mouse_wheel_scroll( + &self, + terminal: &Terminal, + term_cell_width: f32, + term_cell_height: f32, + delta: ScrollDelta, + modifiers: &Modifiers, + x: u32, + y: u32, + ) { + let (delta_x, delta_y) = match delta { + ScrollDelta::Lines { x, y } => (x, y), + ScrollDelta::Pixels { x, y } => (x / term_cell_width, y / term_cell_height), + }; + let (mut button_no, amount) = if delta_y > 0.0 { + (64, delta_y.abs()) //Wheel UP + } else if delta_y < 0.0 { + (65, delta_y.abs()) //Wheel Down + } else if delta_x < 0.0 { + (66, delta_x.abs()) //Wheel Left + } else if delta_x > 0.0 { + (67, delta_x.abs()) //Wheel Right + } else { + return; + }; + + if modifiers.shift() { + button_no += 4; + } + if modifiers.alt() { + button_no += 8; + } + if modifiers.control() { + button_no += 16; + } + let term_code = format!("\x1b[<{};{};{}M", button_no, x + 1, y + 1); + for _ in 0..amount as u32 { + terminal.input_no_scroll(term_code.as_bytes().to_vec()); + } + } + //Emulate mouse wheel scroll with up/down arrows. Using mouse spec uses //scroll-back and scroll-forw actions, which moves whole windows like page up/page down. - pub fn report_mouse_wheel_scroll( + pub fn report_mouse_wheel_as_arrows( &self, terminal: &Terminal, term_cell_width: f32, @@ -188,9 +229,9 @@ impl MouseReporter { //Send delta_y * SCROLL_SPEED number of Up/Down arrows for _ in 0..(delta_y.abs() as u32 * SCROLL_SPEED) { if delta_y > 0.0 { - terminal.input_no_scroll(b"\x1B[1;3A".as_slice()) + terminal.input_no_scroll(b"\x1B[A".as_slice()) } else if delta_y < 0.0 { - terminal.input_no_scroll(b"\x1B[1;3B".as_slice()) + terminal.input_no_scroll(b"\x1B[B".as_slice()) } } } diff --git a/src/terminal.rs b/src/terminal.rs index 322abfa..25f6f99 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -805,13 +805,33 @@ impl Terminal { } } } - pub fn scroll_mouse(&mut self, delta: ScrollDelta) { - self.mouse_reporter.report_mouse_wheel_scroll( - self, - self.size().cell_width, - self.size().cell_height, - delta, - ); + pub fn scroll_mouse( + &mut self, + delta: ScrollDelta, + modifiers: &cosmic::iced::keyboard::Modifiers, + x: u32, + y: u32, + ) { + let term_lock = self.term.lock(); + let mode = term_lock.mode(); + if mode.contains(TermMode::SGR_MOUSE) { + self.mouse_reporter.report_sgr_mouse_wheel_scroll( + self, + self.size().cell_width, + self.size().cell_height, + delta, + modifiers, + x, + y, + ); + } else { + self.mouse_reporter.report_mouse_wheel_as_arrows( + self, + self.size().cell_width, + self.size().cell_height, + delta, + ); + } } } diff --git a/src/terminal_box.rs b/src/terminal_box.rs index d55874d..181d162 100644 --- a/src/terminal_box.rs +++ b/src/terminal_box.rs @@ -1191,9 +1191,14 @@ where } } Event::Mouse(MouseEvent::WheelScrolled { delta }) => { - if let Some(_p) = cursor_position.position_in(layout.bounds()) { + if let Some(p) = cursor_position.position_in(layout.bounds()) { if is_mouse_mode { - terminal.scroll_mouse(delta); + let x = (p.x - layout.bounds().x) - self.padding.left; + let y = (p.y - layout.bounds().y) - self.padding.top; + //TODO: better calculation of position + let col = x / terminal.size().cell_width; + let row = y / terminal.size().cell_height; + terminal.scroll_mouse(delta, &state.modifiers, col as u32, row as u32); } else { match delta { ScrollDelta::Lines { x: _, y } => {