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 scrollback: Scrollback,
|
||||
pub bell: Bell,
|
||||
pub mouse: Mouse,
|
||||
/// Chord → action, e.g. `"Ctrl+Shift+C" = "copy"`. Merged over the defaults;
|
||||
/// a value of `"none"` unbinds.
|
||||
pub key_bindings: std::collections::HashMap<String, String>,
|
||||
|
|
@ -41,6 +42,27 @@ pub struct Bell {
|
|||
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.
|
||||
/// Each value is an X11 colour spec (`#rrggbb` or `rgb:rr/gg/bb`); unset entries
|
||||
/// 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.
|
||||
fn scroll_page(&mut self, up: bool) {
|
||||
if let Some(session) = self.session.as_mut() {
|
||||
|
|
@ -1955,19 +1973,32 @@ impl PointerHandler for App {
|
|||
if raw == 0.0 {
|
||||
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
|
||||
// presses, one per line, capped so a flick cannot flood.
|
||||
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) {
|
||||
self.try_report_button(code, true);
|
||||
}
|
||||
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
|
||||
// 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() {
|
||||
session.term.scroll_view(delta);
|
||||
self.needs_draw = true;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue