forked from NotAShelf/beer
config: add [mouse] table with scroll multiplier and alternate-scroll
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I58d4f2cb0010c167c7c317bf10dea99b6a6a6964
This commit is contained in:
parent
1b8138fc4f
commit
15a4a97033
2 changed files with 56 additions and 3 deletions
|
|
@ -16,6 +16,7 @@ pub struct Config {
|
||||||
pub cursor: Cursor,
|
pub cursor: Cursor,
|
||||||
pub scrollback: Scrollback,
|
pub scrollback: Scrollback,
|
||||||
pub bell: Bell,
|
pub bell: Bell,
|
||||||
|
pub mouse: Mouse,
|
||||||
/// Chord → action, e.g. `"Ctrl+Shift+C" = "copy"`. Merged over the defaults;
|
/// Chord → action, e.g. `"Ctrl+Shift+C" = "copy"`. Merged over the defaults;
|
||||||
/// a value of `"none"` unbinds.
|
/// a value of `"none"` unbinds.
|
||||||
pub key_bindings: std::collections::HashMap<String, String>,
|
pub key_bindings: std::collections::HashMap<String, String>,
|
||||||
|
|
@ -41,6 +42,27 @@ pub struct Bell {
|
||||||
pub visual: bool,
|
pub visual: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `[mouse]`: pointer and wheel behaviour.
|
||||||
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
|
#[serde(default, rename_all = "kebab-case")]
|
||||||
|
pub struct Mouse {
|
||||||
|
/// Multiplier applied to the lines scrolled per wheel notch.
|
||||||
|
pub scroll_multiplier: f64,
|
||||||
|
/// On the alternate screen, translate the wheel into arrow-key presses so
|
||||||
|
/// full-screen apps that did not request mouse reporting (less, man, …)
|
||||||
|
/// still scroll.
|
||||||
|
pub alternate_scroll: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Mouse {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
scroll_multiplier: 1.0,
|
||||||
|
alternate_scroll: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// `[colors]`: foreground/background, the 16 base palette entries, and accents.
|
/// `[colors]`: foreground/background, the 16 base palette entries, and accents.
|
||||||
/// Each value is an X11 colour spec (`#rrggbb` or `rgb:rr/gg/bb`); unset entries
|
/// Each value is an X11 colour spec (`#rrggbb` or `rgb:rr/gg/bb`); unset entries
|
||||||
/// keep the built-in default.
|
/// keep the built-in default.
|
||||||
|
|
|
||||||
|
|
@ -641,6 +641,24 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send `count` cursor-up/down keys to the shell for alternate-scroll,
|
||||||
|
/// honouring the application cursor-key mode (DECCKM).
|
||||||
|
fn alternate_scroll(&mut self, up: bool, count: isize) {
|
||||||
|
let app_cursor = self
|
||||||
|
.session
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|s| s.term.grid().app_cursor());
|
||||||
|
let seq: &[u8] = match (up, app_cursor) {
|
||||||
|
(true, false) => b"\x1b[A",
|
||||||
|
(true, true) => b"\x1bOA",
|
||||||
|
(false, false) => b"\x1b[B",
|
||||||
|
(false, true) => b"\x1bOB",
|
||||||
|
};
|
||||||
|
for _ in 0..count {
|
||||||
|
self.write_to_pty(seq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Scroll the viewport one page back (`up`) or toward the live screen.
|
/// Scroll the viewport one page back (`up`) or toward the live screen.
|
||||||
fn scroll_page(&mut self, up: bool) {
|
fn scroll_page(&mut self, up: bool) {
|
||||||
if let Some(session) = self.session.as_mut() {
|
if let Some(session) = self.session.as_mut() {
|
||||||
|
|
@ -1955,19 +1973,32 @@ impl PointerHandler for App {
|
||||||
if raw == 0.0 {
|
if raw == 0.0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let lines = (raw.abs() * scale).ceil().max(1.0) as isize;
|
let mult = self.config.mouse.scroll_multiplier.max(0.0);
|
||||||
|
let lines = (raw.abs() * scale * mult).ceil().max(1.0) as isize;
|
||||||
|
let up = raw < 0.0;
|
||||||
// Reporting apps get wheel buttons (64 up / 65 down) as
|
// Reporting apps get wheel buttons (64 up / 65 down) as
|
||||||
// presses, one per line, capped so a flick cannot flood.
|
// presses, one per line, capped so a flick cannot flood.
|
||||||
if self.mouse_reporting() {
|
if self.mouse_reporting() {
|
||||||
let code = if raw < 0.0 { 64 } else { 65 };
|
let code = if up { 64 } else { 65 };
|
||||||
for _ in 0..lines.clamp(1, 8) {
|
for _ in 0..lines.clamp(1, 8) {
|
||||||
self.try_report_button(code, true);
|
self.try_report_button(code, true);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// On the alternate screen there is no scrollback to move, so
|
||||||
|
// (when enabled) translate the wheel into cursor-key presses
|
||||||
|
// for apps that did not request mouse reporting.
|
||||||
|
let alt = self
|
||||||
|
.session
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|s| s.term.grid().alt_active());
|
||||||
|
if alt && self.config.mouse.alternate_scroll {
|
||||||
|
self.alternate_scroll(up, lines.clamp(1, 8));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// Positive axis = scroll down (toward live); the viewport
|
// Positive axis = scroll down (toward live); the viewport
|
||||||
// scrolls the opposite way (negative offset delta).
|
// scrolls the opposite way (negative offset delta).
|
||||||
let delta = if raw < 0.0 { lines } else { -lines };
|
let delta = if up { lines } else { -lines };
|
||||||
if let Some(session) = self.session.as_mut() {
|
if let Some(session) = self.session.as_mut() {
|
||||||
session.term.scroll_view(delta);
|
session.term.scroll_view(delta);
|
||||||
self.needs_draw = true;
|
self.needs_draw = true;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue