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
- Uppercase `-T` short form for `--title`
- Support for horizontal scrolling in mouse mode and alternative scrolling modes
### Changed

View File

@ -1033,7 +1033,7 @@ pub struct Mouse {
pub last_click_timestamp: Instant,
pub last_click_button: MouseButton,
pub click_state: ClickState,
pub scroll_px: f64,
pub accumulated_scroll: AccumulatedScroll,
pub cell_side: Side,
pub lines_scrolled: f32,
pub block_hint_launcher: bool,
@ -1057,7 +1057,7 @@ impl Default for Mouse {
block_hint_launcher: Default::default(),
inside_text_area: Default::default(),
lines_scrolled: Default::default(),
scroll_px: Default::default(),
accumulated_scroll: Default::default(),
x: 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>> {
/// Handle events from winit.
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) {
match delta {
MouseScrollDelta::LineDelta(_columns, lines) => {
let new_scroll_px = lines * self.ctx.size_info().cell_height();
self.scroll_terminal(f64::from(new_scroll_px));
MouseScrollDelta::LineDelta(columns, lines) => {
let new_scroll_px_x = columns * self.ctx.size_info().cell_width();
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) => {
match phase {
TouchPhase::Started => {
// Reset offset to zero.
self.ctx.mouse_mut().scroll_px = 0.;
self.ctx.mouse_mut().accumulated_scroll = Default::default();
},
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());
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 lines = (self.ctx.mouse().scroll_px / height).abs() as i32;
let code = if new_scroll_y_px > 0. { MOUSE_WHEEL_UP } else { MOUSE_WHEEL_DOWN };
let lines = (self.ctx.mouse().accumulated_scroll.y / height).abs() as i32;
for _ in 0..lines {
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
.ctx
.terminal()
@ -670,30 +685,45 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
&& !self.ctx.modifiers().shift()
{
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' };
let lines = (self.ctx.mouse().scroll_px / height).abs() as i32;
self.ctx.mouse_mut().accumulated_scroll.x += new_scroll_x_px * multiplier;
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 {
content.push(0x1b);
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);
} else {
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 {
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) {