1
0
Fork 0
mirror of https://github.com/alacritty/alacritty.git synced 2024-11-11 13:51:01 -05:00

Add support for horizontal scrolling

This adds support for horizontal mouse scrolling in mouse mode
and alternative scrolling modes.

Fixes #2185.
This commit is contained in:
Kirill Chibisov 2023-01-16 20:22:01 +03:00 committed by GitHub
parent 5a3280e8e0
commit ed67aa3c08
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 60 additions and 19 deletions

View file

@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added ### Added
- Uppercase `-T` short form for `--title` - Uppercase `-T` short form for `--title`
- Support for horizontal scrolling in mouse mode and alternative scrolling modes
### Changed ### Changed

View file

@ -1033,7 +1033,7 @@ pub struct Mouse {
pub last_click_timestamp: Instant, pub last_click_timestamp: Instant,
pub last_click_button: MouseButton, pub last_click_button: MouseButton,
pub click_state: ClickState, pub click_state: ClickState,
pub scroll_px: f64, pub accumulated_scroll: AccumulatedScroll,
pub cell_side: Side, pub cell_side: Side,
pub lines_scrolled: f32, pub lines_scrolled: f32,
pub block_hint_launcher: bool, pub block_hint_launcher: bool,
@ -1057,7 +1057,7 @@ impl Default for Mouse {
block_hint_launcher: Default::default(), block_hint_launcher: Default::default(),
inside_text_area: Default::default(), inside_text_area: Default::default(),
lines_scrolled: Default::default(), lines_scrolled: Default::default(),
scroll_px: Default::default(), accumulated_scroll: Default::default(),
x: Default::default(), x: Default::default(),
y: Default::default(), y: Default::default(),
} }
@ -1081,6 +1081,16 @@ impl Mouse {
} }
} }
/// The amount of scroll accumulated from the pointer events.
#[derive(Default, Debug)]
pub struct AccumulatedScroll {
/// Scroll we should perform along `x` axis.
pub x: f64,
/// Scroll we should perform along `y` axis.
pub y: f64,
}
impl input::Processor<EventProxy, ActionContext<'_, Notifier, EventProxy>> { impl input::Processor<EventProxy, ActionContext<'_, Notifier, EventProxy>> {
/// Handle events from winit. /// Handle events from winit.
pub fn handle_event(&mut self, event: WinitEvent<'_, Event>) { pub fn handle_event(&mut self, event: WinitEvent<'_, Event>) {

View file

@ -631,18 +631,19 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
pub fn mouse_wheel_input(&mut self, delta: MouseScrollDelta, phase: TouchPhase) { pub fn mouse_wheel_input(&mut self, delta: MouseScrollDelta, phase: TouchPhase) {
match delta { match delta {
MouseScrollDelta::LineDelta(_columns, lines) => { MouseScrollDelta::LineDelta(columns, lines) => {
let new_scroll_px = lines * self.ctx.size_info().cell_height(); let new_scroll_px_x = columns * self.ctx.size_info().cell_width();
self.scroll_terminal(f64::from(new_scroll_px)); let new_scroll_px_y = lines * self.ctx.size_info().cell_height();
self.scroll_terminal(new_scroll_px_x as f64, new_scroll_px_y as f64);
}, },
MouseScrollDelta::PixelDelta(lpos) => { MouseScrollDelta::PixelDelta(lpos) => {
match phase { match phase {
TouchPhase::Started => { TouchPhase::Started => {
// Reset offset to zero. // Reset offset to zero.
self.ctx.mouse_mut().scroll_px = 0.; self.ctx.mouse_mut().accumulated_scroll = Default::default();
}, },
TouchPhase::Moved => { TouchPhase::Moved => {
self.scroll_terminal(lpos.y); self.scroll_terminal(lpos.x, lpos.y);
}, },
_ => (), _ => (),
} }
@ -650,18 +651,32 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
} }
} }
fn scroll_terminal(&mut self, new_scroll_px: f64) { fn scroll_terminal(&mut self, new_scroll_x_px: f64, new_scroll_y_px: f64) {
const MOUSE_WHEEL_UP: u8 = 64;
const MOUSE_WHEEL_DOWN: u8 = 65;
const MOUSE_WHEEL_LEFT: u8 = 66;
const MOUSE_WHEEL_RIGHT: u8 = 67;
let width = f64::from(self.ctx.size_info().cell_width());
let height = f64::from(self.ctx.size_info().cell_height()); let height = f64::from(self.ctx.size_info().cell_height());
if self.ctx.mouse_mode() { if self.ctx.mouse_mode() {
self.ctx.mouse_mut().scroll_px += new_scroll_px; self.ctx.mouse_mut().accumulated_scroll.x += new_scroll_x_px;
self.ctx.mouse_mut().accumulated_scroll.y += new_scroll_y_px;
let code = if new_scroll_px > 0. { 64 } else { 65 }; let code = if new_scroll_y_px > 0. { MOUSE_WHEEL_UP } else { MOUSE_WHEEL_DOWN };
let lines = (self.ctx.mouse().scroll_px / height).abs() as i32; let lines = (self.ctx.mouse().accumulated_scroll.y / height).abs() as i32;
for _ in 0..lines { for _ in 0..lines {
self.mouse_report(code, ElementState::Pressed); self.mouse_report(code, ElementState::Pressed);
} }
let code = if new_scroll_x_px > 0. { MOUSE_WHEEL_LEFT } else { MOUSE_WHEEL_RIGHT };
let columns = (self.ctx.mouse().accumulated_scroll.x / width).abs() as i32;
for _ in 0..columns {
self.mouse_report(code, ElementState::Pressed);
}
} else if self } else if self
.ctx .ctx
.terminal() .terminal()
@ -670,30 +685,45 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
&& !self.ctx.modifiers().shift() && !self.ctx.modifiers().shift()
{ {
let multiplier = f64::from(self.ctx.config().terminal_config.scrolling.multiplier); let multiplier = f64::from(self.ctx.config().terminal_config.scrolling.multiplier);
self.ctx.mouse_mut().scroll_px += new_scroll_px * multiplier;
let cmd = if new_scroll_px > 0. { b'A' } else { b'B' }; self.ctx.mouse_mut().accumulated_scroll.x += new_scroll_x_px * multiplier;
let lines = (self.ctx.mouse().scroll_px / height).abs() as i32; self.ctx.mouse_mut().accumulated_scroll.y += new_scroll_y_px * multiplier;
// The chars here are the same as for the respective arrow keys.
let line_cmd = if new_scroll_y_px > 0. { b'A' } else { b'B' };
let column_cmd = if new_scroll_x_px > 0. { b'D' } else { b'C' };
let lines = (self.ctx.mouse().accumulated_scroll.y / height).abs() as usize;
let columns = (self.ctx.mouse().accumulated_scroll.x / width).abs() as usize;
let mut content = Vec::with_capacity(3 * (lines + columns));
let mut content = Vec::with_capacity(lines as usize * 3);
for _ in 0..lines { for _ in 0..lines {
content.push(0x1b); content.push(0x1b);
content.push(b'O'); content.push(b'O');
content.push(cmd); content.push(line_cmd);
} }
for _ in 0..columns {
content.push(0x1b);
content.push(b'O');
content.push(column_cmd);
}
self.ctx.write_to_pty(content); self.ctx.write_to_pty(content);
} else { } else {
let multiplier = f64::from(self.ctx.config().terminal_config.scrolling.multiplier); let multiplier = f64::from(self.ctx.config().terminal_config.scrolling.multiplier);
self.ctx.mouse_mut().scroll_px += new_scroll_px * multiplier; self.ctx.mouse_mut().accumulated_scroll.y += new_scroll_y_px * multiplier;
let lines = (self.ctx.mouse().scroll_px / height) as i32; let lines = (self.ctx.mouse().accumulated_scroll.y / height) as i32;
if lines != 0 { if lines != 0 {
self.ctx.scroll(Scroll::Delta(lines)); self.ctx.scroll(Scroll::Delta(lines));
} }
} }
self.ctx.mouse_mut().scroll_px %= height; self.ctx.mouse_mut().accumulated_scroll.x %= width;
self.ctx.mouse_mut().accumulated_scroll.y %= height;
} }
pub fn on_focus_change(&mut self, is_focused: bool) { pub fn on_focus_change(&mut self, is_focused: bool) {