From f14d24542c3ceda3b508c707eb79cf2fe2a04bd1 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Fri, 10 Apr 2020 21:23:50 +0300 Subject: [PATCH] Fix various mouse mode + vi mode interactions This commit fixes some issues introduced by 1a8cd172e520e493bacc9c6a2ae6f80de086eaa3: 1. Vi cursor not moving properly on double/triple click 2. URL not launching via mouse click in vi mode + mouse mode 3. Ability to select in mouse mode with double/triple click regardless of shift modifier --- alacritty/src/display.rs | 3 +- alacritty/src/event.rs | 6 +- alacritty/src/input.rs | 184 +++++++++++++++++++-------------------- 3 files changed, 94 insertions(+), 99 deletions(-) diff --git a/alacritty/src/display.rs b/alacritty/src/display.rs index 6d5d810d..c456fda8 100644 --- a/alacritty/src/display.rs +++ b/alacritty/src/display.rs @@ -364,7 +364,8 @@ impl Display { let size_info = self.size_info; let selection = !terminal.selection().as_ref().map(Selection::is_empty).unwrap_or(true); - let mouse_mode = terminal.mode().intersects(TermMode::MOUSE_MODE); + let mouse_mode = terminal.mode().intersects(TermMode::MOUSE_MODE) + && !terminal.mode().contains(TermMode::VI); let vi_mode_cursor = if terminal.mode().contains(TermMode::VI) { Some(terminal.vi_mode_cursor) diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs index 89aa8be6..e532ac12 100644 --- a/alacritty/src/event.rs +++ b/alacritty/src/event.rs @@ -12,7 +12,7 @@ use std::sync::Arc; use std::time::Instant; use glutin::dpi::PhysicalSize; -use glutin::event::{ElementState, Event as GlutinEvent, ModifiersState, MouseButton, WindowEvent}; +use glutin::event::{ElementState, Event as GlutinEvent, ModifiersState, WindowEvent}; use glutin::event_loop::{ControlFlow, EventLoop, EventLoopProxy, EventLoopWindowTarget}; use glutin::platform::desktop::EventLoopExtDesktop; #[cfg(not(any(target_os = "macos", windows)))] @@ -295,7 +295,7 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext for ActionCon } } -#[derive(Debug)] +#[derive(Debug, Eq, PartialEq)] pub enum ClickState { None, Click, @@ -319,7 +319,6 @@ pub struct Mouse { pub cell_side: Side, pub lines_scrolled: f32, pub block_url_launcher: bool, - pub last_button: MouseButton, pub inside_grid: bool, } @@ -339,7 +338,6 @@ impl Default for Mouse { cell_side: Side::Left, lines_scrolled: 0., block_url_launcher: false, - last_button: MouseButton::Other(0), inside_grid: false, } } diff --git a/alacritty/src/input.rs b/alacritty/src/input.rs index 7c2a1f8b..b84c9a53 100644 --- a/alacritty/src/input.rs +++ b/alacritty/src/input.rs @@ -455,89 +455,79 @@ impl<'a, T: EventListener, A: ActionContext> Processor<'a, T, A> { } } - fn on_mouse_double_click(&mut self, button: MouseButton, point: Point) { - if button == MouseButton::Left { - let side = self.ctx.mouse().cell_side; - self.ctx.start_selection(SelectionType::Semantic, point, side); - } - } - - fn on_mouse_triple_click(&mut self, button: MouseButton, point: Point) { - if button == MouseButton::Left { - let side = self.ctx.mouse().cell_side; - self.ctx.start_selection(SelectionType::Lines, point, side); - } - } - fn on_mouse_press(&mut self, button: MouseButton) { - let now = Instant::now(); - let elapsed = self.ctx.mouse().last_click_timestamp.elapsed(); - self.ctx.mouse_mut().last_click_timestamp = now; + // Handle mouse mode + if !self.ctx.modifiers().shift() && self.ctx.mouse_mode() { + self.ctx.mouse_mut().click_state = ClickState::None; - let button_changed = self.ctx.mouse().last_button != button; + let code = match button { + MouseButton::Left => 0, + MouseButton::Middle => 1, + MouseButton::Right => 2, + // Can't properly report more than three buttons. + MouseButton::Other(_) => return, + }; + + self.mouse_report(code, ElementState::Pressed); + } else if button == MouseButton::Left { + self.on_left_click(); + } else { + // Do nothing when using buttons other than LMB + self.ctx.mouse_mut().click_state = ClickState::None; + } + } + + /// Handle left click selection and vi mode cursor movement. + fn on_left_click(&mut self) { + // Calculate time since the last click to handle double/triple clicks in normal mode + let now = Instant::now(); + let elapsed = now - self.ctx.mouse().last_click_timestamp; + self.ctx.mouse_mut().last_click_timestamp = now; // Load mouse point, treating message bar and padding as closest cell let mouse = self.ctx.mouse(); let mut point = self.ctx.size_info().pixels_to_coords(mouse.x, mouse.y); point.line = min(point.line, self.ctx.terminal().grid().num_lines() - 1); + let side = self.ctx.mouse().cell_side; + self.ctx.mouse_mut().click_state = match self.ctx.mouse().click_state { ClickState::Click - if !button_changed - && elapsed < self.ctx.config().ui_config.mouse.double_click.threshold => + if elapsed < self.ctx.config().ui_config.mouse.double_click.threshold => { self.ctx.mouse_mut().block_url_launcher = true; - self.on_mouse_double_click(button, point); + self.ctx.start_selection(SelectionType::Semantic, point, side); ClickState::DoubleClick } ClickState::DoubleClick - if !button_changed - && elapsed < self.ctx.config().ui_config.mouse.triple_click.threshold => + if elapsed < self.ctx.config().ui_config.mouse.triple_click.threshold => { self.ctx.mouse_mut().block_url_launcher = true; - self.on_mouse_triple_click(button, point); + self.ctx.start_selection(SelectionType::Lines, point, side); ClickState::TripleClick } _ => { - if button == MouseButton::Left - && (self.ctx.modifiers().shift() - || !self.ctx.terminal().mode().intersects(TermMode::MOUSE_MODE)) - { - // Don't launch URLs if this click cleared the selection - self.ctx.mouse_mut().block_url_launcher = !self.ctx.selection_is_empty(); + // Don't launch URLs if this click cleared the selection + self.ctx.mouse_mut().block_url_launcher = !self.ctx.selection_is_empty(); - self.ctx.clear_selection(); + self.ctx.clear_selection(); - // Start new empty selection - let side = self.ctx.mouse().cell_side; - if self.ctx.modifiers().ctrl() { - self.ctx.start_selection(SelectionType::Block, point, side); - } else { - self.ctx.start_selection(SelectionType::Simple, point, side); - } - - // Move vi mode cursor to mouse position - if self.ctx.terminal().mode().contains(TermMode::VI) { - // Update vi mode cursor position on click - self.ctx.terminal_mut().vi_mode_cursor.point = point; - } - } - - if !self.ctx.modifiers().shift() && self.ctx.mouse_mode() { - let code = match button { - MouseButton::Left => 0, - MouseButton::Middle => 1, - MouseButton::Right => 2, - // Can't properly report more than three buttons. - MouseButton::Other(_) => return, - }; - self.mouse_report(code, ElementState::Pressed); - return; + // Start new empty selection + if self.ctx.modifiers().ctrl() { + self.ctx.start_selection(SelectionType::Block, point, side); + } else { + self.ctx.start_selection(SelectionType::Simple, point, side); } ClickState::Click }, }; + + // Move vi mode cursor to mouse position + if self.ctx.terminal().mode().contains(TermMode::VI) { + // Update Vi mode cursor position on click + self.ctx.terminal_mut().vi_mode_cursor.point = point; + } } fn on_mouse_release(&mut self, button: MouseButton) { @@ -695,8 +685,6 @@ impl<'a, T: EventListener, A: ActionContext> Processor<'a, T, A> { ElementState::Released => self.on_mouse_release(button), } } - - self.ctx.mouse_mut().last_button = button; } /// Process key input. @@ -910,20 +898,12 @@ mod tests { fn send_event(&self, _event: TerminalEvent) {} } - #[derive(Debug, PartialEq)] - enum MultiClick { - DoubleClick, - TripleClick, - None, - } - struct ActionContext<'a, T> { pub terminal: &'a mut Term, pub selection: &'a mut Option, pub size_info: &'a SizeInfo, pub mouse: &'a mut Mouse, pub message_buffer: &'a mut MessageBuffer, - pub last_action: MultiClick, pub received_count: usize, pub suppress_chars: bool, pub modifiers: ModifiersState, @@ -935,13 +915,7 @@ mod tests { fn update_selection(&mut self, _point: Point, _side: Side) {} - fn start_selection(&mut self, ty: SelectionType, _point: Point, _side: Side) { - match ty { - SelectionType::Semantic => self.last_action = MultiClick::DoubleClick, - SelectionType::Lines => self.last_action = MultiClick::TripleClick, - _ => (), - } - } + fn start_selection(&mut self, _ty: SelectionType, _point: Point, _side: Side) {} fn toggle_selection(&mut self, _ty: SelectionType, _point: Point, _side: Side) {} @@ -1051,8 +1025,7 @@ mod tests { initial_state: $initial_state:expr, initial_button: $initial_button:expr, input: $input:expr, - end_state: $end_state:pat, - last_action: $last_action:expr + end_state: $end_state:expr, } => { #[test] fn $name() { @@ -1082,7 +1055,6 @@ mod tests { let mut mouse = Mouse::default(); mouse.click_state = $initial_state; - mouse.last_button = $initial_button; let mut selection = None; @@ -1093,7 +1065,6 @@ mod tests { selection: &mut selection, mouse: &mut mouse, size_info: &size, - last_action: MultiClick::None, received_count: 0, suppress_chars: false, modifiers: Default::default(), @@ -1116,10 +1087,7 @@ mod tests { processor.mouse_input(state, button); }; - assert!(match processor.ctx.mouse.click_state { - $end_state => processor.ctx.last_action == $last_action, - _ => false - }); + assert_eq!(processor.ctx.mouse.click_state, $end_state); } } } @@ -1151,13 +1119,44 @@ mod tests { event: WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left, - device_id: unsafe { ::std::mem::transmute_copy(&0) }, + device_id: unsafe { std::mem::transmute_copy(&0) }, modifiers: ModifiersState::default(), }, - window_id: unsafe { ::std::mem::transmute_copy(&0) }, + window_id: unsafe { std::mem::transmute_copy(&0) }, }, end_state: ClickState::Click, - last_action: MultiClick::None + } + + test_clickstate! { + name: single_right_click, + initial_state: ClickState::None, + initial_button: MouseButton::Other(0), + input: Event::WindowEvent { + event: WindowEvent::MouseInput { + state: ElementState::Pressed, + button: MouseButton::Right, + device_id: unsafe { std::mem::transmute_copy(&0) }, + modifiers: ModifiersState::default(), + }, + window_id: unsafe { std::mem::transmute_copy(&0) }, + }, + end_state: ClickState::None, + } + + test_clickstate! { + name: single_middle_click, + initial_state: ClickState::None, + initial_button: MouseButton::Other(0), + input: Event::WindowEvent { + event: WindowEvent::MouseInput { + state: ElementState::Pressed, + button: MouseButton::Middle, + device_id: unsafe { std::mem::transmute_copy(&0) }, + modifiers: ModifiersState::default(), + }, + window_id: unsafe { std::mem::transmute_copy(&0) }, + }, + end_state: ClickState::None, } test_clickstate! { @@ -1168,13 +1167,12 @@ mod tests { event: WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left, - device_id: unsafe { ::std::mem::transmute_copy(&0) }, + device_id: unsafe { std::mem::transmute_copy(&0) }, modifiers: ModifiersState::default(), }, - window_id: unsafe { ::std::mem::transmute_copy(&0) }, + window_id: unsafe { std::mem::transmute_copy(&0) }, }, end_state: ClickState::DoubleClick, - last_action: MultiClick::DoubleClick } test_clickstate! { @@ -1185,13 +1183,12 @@ mod tests { event: WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left, - device_id: unsafe { ::std::mem::transmute_copy(&0) }, + device_id: unsafe { std::mem::transmute_copy(&0) }, modifiers: ModifiersState::default(), }, - window_id: unsafe { ::std::mem::transmute_copy(&0) }, + window_id: unsafe { std::mem::transmute_copy(&0) }, }, end_state: ClickState::TripleClick, - last_action: MultiClick::TripleClick } test_clickstate! { @@ -1202,13 +1199,12 @@ mod tests { event: WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Right, - device_id: unsafe { ::std::mem::transmute_copy(&0) }, + device_id: unsafe { std::mem::transmute_copy(&0) }, modifiers: ModifiersState::default(), }, - window_id: unsafe { ::std::mem::transmute_copy(&0) }, + window_id: unsafe { std::mem::transmute_copy(&0) }, }, - end_state: ClickState::Click, - last_action: MultiClick::None + end_state: ClickState::None, } test_process_binding! {