diff options
Diffstat (limited to 'src/input.rs')
-rw-r--r-- | src/input.rs | 153 |
1 files changed, 99 insertions, 54 deletions
diff --git a/src/input.rs b/src/input.rs index 52775678..cccb3bb4 100644 --- a/src/input.rs +++ b/src/input.rs @@ -28,6 +28,7 @@ use copypasta::{Clipboard, Load, Buffer}; use glutin::{ElementState, VirtualKeyCode, MouseButton, TouchPhase, MouseScrollDelta, ModifiersState}; use config; +use grid::Scroll; use event::{ClickState, Mouse}; use index::{Line, Column, Side, Point}; use term::SizeInfo; @@ -46,6 +47,7 @@ pub struct Processor<'a, A: 'a> { pub key_bindings: &'a [KeyBinding], pub mouse_bindings: &'a [MouseBinding], pub mouse_config: &'a config::Mouse, + pub scrolling_config: &'a config::Scrolling, pub ctx: A, } @@ -66,6 +68,7 @@ pub trait ActionContext { fn last_modifiers(&mut self) -> &mut ModifiersState; fn change_font_size(&mut self, delta: f32); fn reset_font_size(&mut self); + fn scroll(&mut self, scroll: Scroll); fn hide_window(&mut self); } @@ -168,6 +171,18 @@ pub enum Action { /// Reset font size to the config value ResetFontSize, + /// Scroll exactly one page up + ScrollPageUp, + + /// Scroll exactly one page down + ScrollPageDown, + + /// Scroll all the way to the top + ScrollToTop, + + /// Scroll all the way to the bottom + ScrollToBottom, + /// Run given command Command(String, Vec<String>), @@ -183,6 +198,7 @@ impl Action { fn execute<A: ActionContext>(&self, ctx: &mut A) { match *self { Action::Esc(ref s) => { + ctx.scroll(Scroll::Bottom); ctx.write_to_pty(s.clone().into_bytes()) }, Action::Copy => { @@ -243,7 +259,19 @@ impl Action { } Action::ResetFontSize => { ctx.reset_font_size(); - } + }, + Action::ScrollPageUp => { + ctx.scroll(Scroll::PageUp); + }, + Action::ScrollPageDown => { + ctx.scroll(Scroll::PageDown); + }, + Action::ScrollToTop => { + ctx.scroll(Scroll::Top); + }, + Action::ScrollToBottom => { + ctx.scroll(Scroll::Bottom); + }, } } @@ -272,52 +300,54 @@ impl From<&'static str> for Action { impl<'a, A: ActionContext + 'a> Processor<'a, A> { #[inline] - pub fn mouse_moved(&mut self, x: u32, y: u32, modifiers: ModifiersState) { + pub fn mouse_moved(&mut self, x: usize, y: usize, modifiers: ModifiersState) { self.ctx.mouse_mut().x = x; self.ctx.mouse_mut().y = y; let size_info = self.ctx.size_info(); - if let Some(point) = size_info.pixels_to_coords(x as usize, y as usize) { - let prev_line = mem::replace(&mut self.ctx.mouse_mut().line, point.line); - let prev_col = mem::replace(&mut self.ctx.mouse_mut().column, point.col); + let point = size_info.pixels_to_coords(x, y); - let cell_x = (x as usize - size_info.padding_x as usize) % size_info.cell_width as usize; - let half_cell_width = (size_info.cell_width / 2.0) as usize; + let prev_line = mem::replace(&mut self.ctx.mouse_mut().line, point.line); + let prev_col = mem::replace(&mut self.ctx.mouse_mut().column, point.col); - let cell_side = if cell_x > half_cell_width { - Side::Right - } else { - Side::Left - }; - self.ctx.mouse_mut().cell_side = cell_side; - - let motion_mode = TermMode::MOUSE_MOTION | TermMode::MOUSE_DRAG; - if self.ctx.mouse_mut().left_button_state == ElementState::Pressed - && ( - modifiers.shift - || !self.ctx.terminal_mode().intersects(TermMode::MOUSE_REPORT_CLICK | motion_mode) - ) - { - self.ctx.update_selection(Point { - line: point.line, - col: point.col - }, cell_side); - } else if self.ctx.terminal_mode().intersects(motion_mode) - // Only report motion when changing cells - && ( - prev_line != self.ctx.mouse_mut().line - || prev_col != self.ctx.mouse_mut().column - ) - { - if self.ctx.mouse_mut().left_button_state == ElementState::Pressed { - self.mouse_report(32, ElementState::Pressed, modifiers); - } else if self.ctx.mouse_mut().middle_button_state == ElementState::Pressed { - self.mouse_report(33, ElementState::Pressed, modifiers); - } else if self.ctx.mouse_mut().right_button_state == ElementState::Pressed { - self.mouse_report(34, ElementState::Pressed, modifiers); - } else if self.ctx.terminal_mode().contains(TermMode::MOUSE_MOTION) { - self.mouse_report(35, ElementState::Pressed, modifiers); - } + let cell_x = x.saturating_sub(size_info.padding_x as usize) % size_info.cell_width as usize; + let half_cell_width = (size_info.cell_width / 2.0) as usize; + + let additional_padding = (size_info.width - size_info.padding_x * 2.) % size_info.cell_width; + let end_of_grid = size_info.width - size_info.padding_x - additional_padding; + let cell_side = if cell_x > half_cell_width + // Edge case when mouse leaves the window + || x as f32 >= end_of_grid + { + Side::Right + } else { + Side::Left + }; + self.ctx.mouse_mut().cell_side = cell_side; + + let motion_mode = TermMode::MOUSE_MOTION | TermMode::MOUSE_DRAG; + let report_mode = TermMode::MOUSE_REPORT_CLICK | motion_mode; + + if self.ctx.mouse_mut().left_button_state == ElementState::Pressed && + ( modifiers.shift || !self.ctx.terminal_mode().intersects(report_mode)) + { + self.ctx.update_selection(Point { + line: point.line, + col: point.col + }, cell_side); + } else if self.ctx.terminal_mode().intersects(motion_mode) + // Only report motion when changing cells + && (prev_line != self.ctx.mouse_mut().line || prev_col != self.ctx.mouse_mut().column) + && size_info.contains_point(x, y) + { + if self.ctx.mouse_mut().left_button_state == ElementState::Pressed { + self.mouse_report(32, ElementState::Pressed, modifiers); + } else if self.ctx.mouse_mut().middle_button_state == ElementState::Pressed { + self.mouse_report(33, ElementState::Pressed, modifiers); + } else if self.ctx.mouse_mut().right_button_state == ElementState::Pressed { + self.mouse_report(34, ElementState::Pressed, modifiers); + } else if self.ctx.terminal_mode().contains(TermMode::MOUSE_MOTION) { + self.mouse_report(35, ElementState::Pressed, modifiers); } } } @@ -436,11 +466,6 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { } pub fn on_mouse_wheel(&mut self, delta: MouseScrollDelta, phase: TouchPhase, modifiers: ModifiersState) { - let mouse_modes = TermMode::MOUSE_REPORT_CLICK | TermMode::MOUSE_DRAG | TermMode::MOUSE_MOTION; - if !self.ctx.terminal_mode().intersects(mouse_modes | TermMode::ALT_SCREEN) { - return; - } - match delta { MouseScrollDelta::LineDelta(_columns, lines) => { let to_scroll = self.ctx.mouse_mut().lines_scrolled + lines; @@ -450,8 +475,9 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { 65 }; + let scrolling_multiplier = self.scrolling_config.multiplier; for _ in 0..(to_scroll.abs() as usize) { - self.scroll_terminal(code, modifiers) + self.scroll_terminal(code, modifiers, scrolling_multiplier) } self.ctx.mouse_mut().lines_scrolled = to_scroll % 1.0; @@ -475,7 +501,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { 65 }; - self.scroll_terminal(code, modifiers) + self.scroll_terminal(code, modifiers, 1) } }, _ => (), @@ -484,23 +510,35 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { } } - fn scroll_terminal(&mut self, code: u8, modifiers: ModifiersState) { + fn scroll_terminal(&mut self, code: u8, modifiers: ModifiersState, scroll_multiplier: u8) { debug_assert!(code == 64 || code == 65); - let faux_scrollback_lines = self.mouse_config.faux_scrollback_lines; let mouse_modes = TermMode::MOUSE_REPORT_CLICK | TermMode::MOUSE_DRAG | TermMode::MOUSE_MOTION; + + // Make sure the new and deprecated setting are both allowed + let faux_scrolling_lines = self.mouse_config + .faux_scrollback_lines + .unwrap_or(self.scrolling_config.faux_multiplier as usize); + if self.ctx.terminal_mode().intersects(mouse_modes) { self.mouse_report(code, ElementState::Pressed, modifiers); - } else if faux_scrollback_lines > 0 { + } else if self.ctx.terminal_mode().contains(TermMode::ALT_SCREEN) + && faux_scrolling_lines > 0 && !modifiers.shift + { // Faux scrolling let cmd = code + 1; // 64 + 1 = A, 65 + 1 = B - let mut content = Vec::with_capacity(faux_scrollback_lines * 3); - for _ in 0..faux_scrollback_lines { + let mut content = Vec::with_capacity(faux_scrolling_lines as usize * 3); + for _ in 0..faux_scrolling_lines { content.push(0x1b); content.push(b'O'); content.push(cmd); } self.ctx.write_to_pty(content); + } else { + for _ in 0..scroll_multiplier { + // Transform the reported button codes 64 and 65 into 1 and -1 lines to scroll + self.ctx.scroll(Scroll::Lines(-(code as isize * 2 - 129))); + } } } @@ -569,6 +607,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { /// Process a received character pub fn received_char(&mut self, c: char) { if !*self.ctx.suppress_chars() { + self.ctx.scroll(Scroll::Bottom); self.ctx.clear_selection(); let utf8_len = c.len_utf8(); @@ -637,6 +676,7 @@ mod tests { use config::{self, Config, ClickHandler}; use index::{Point, Side}; use selection::Selection; + use grid::Scroll; use super::{Action, Binding, Processor}; @@ -691,6 +731,10 @@ mod tests { self.last_action = MultiClick::TripleClick; } + fn scroll(&mut self, scroll: Scroll) { + self.terminal.scroll_display(scroll); + } + fn mouse_coords(&self) -> Option<Point> { self.terminal.pixels_to_coords(self.mouse.x as usize, self.mouse.y as usize) } @@ -764,8 +808,9 @@ mod tests { triple_click: ClickHandler { threshold: Duration::from_millis(1000), }, - faux_scrollback_lines: 1, + faux_scrollback_lines: None, }, + scrolling_config: &config::Scrolling::default(), key_bindings: &config.key_bindings()[..], mouse_bindings: &config.mouse_bindings()[..], }; |