fix(inject/libei): emit the continuous scroll axis so small scrolls register
ci / rust (push) Failing after 40s
ci / web (push) Failing after 37s
apple / swift (push) Successful in 1m23s
ci / docs-site (push) Failing after 41s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 7s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 6s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 5s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 3s
deb / build-publish (push) Successful in 3m0s
docker / deploy-docs (push) Successful in 19s
rpm / build-publish (push) Successful in 4m18s

The libei backend forwarded mouse wheel only via scroll_discrete (120-per-detent).
Mutter floors a sub-detent delta — a trackpad, a precise/high-res wheel, or a
fractional smooth-scroll event — to zero whole clicks, so small scrolls never land and
you have to spin the wheel a lot before anything moves. Emit the continuous `scroll`
axis (logical px, ~15 px/detent) alongside the discrete steps, matching the wlroots
backend's 15-px/notch behaviour, so every delta moves proportionally while full
detents still drive line/page scrolling.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-13 12:37:07 +00:00
parent 55dfb4800f
commit 7ecf2d8dfd
+14 -5
View File
@@ -615,15 +615,24 @@ impl EiState {
} }
InputKind::MouseScroll => match slot.interface::<ei::Scroll>() { InputKind::MouseScroll => match slot.interface::<ei::Scroll>() {
Some(s) => { Some(s) => {
// GameStream sends WHEEL_DELTA(120)-scaled deltas in `x`; ei scroll_discrete // Wire deltas are WHEEL_DELTA(120)-scaled in `x`. Emit BOTH ei scroll axes
// uses the same 120-per-detent unit. Positive GameStream = up (vertical), // from it: `scroll_discrete` (120-per-detent — drives line/page scrolling)
// which is negative on the ei axis, but = RIGHT (horizontal), which is // AND the continuous `scroll` axis in logical px (≈15 px/detent). Without
// already positive there (moonlight-qt/Sunshine pass horizontal through // the continuous axis Mutter floors a sub-detent delta (trackpad / precise
// unnegated) — only the vertical axis flips. // wheel / fractional smooth scroll) to zero whole clicks, so small scrolls
// never register and you have to spin the wheel a lot — emitting the pixel
// axis too makes every delta move proportionally (matches the wlr backend's
// 15 px/notch). Positive wire = up (vertical, negated on the ei axis) /
// RIGHT (horizontal, already positive — moonlight-qt/Sunshine pass it
// through unnegated); only the vertical axis flips.
const PX_PER_DETENT: f32 = 15.0;
let px = ev.x as f32 / 120.0 * PX_PER_DETENT;
if ev.code == SCROLL_HORIZONTAL { if ev.code == SCROLL_HORIZONTAL {
s.scroll_discrete(ev.x, 0); s.scroll_discrete(ev.x, 0);
s.scroll(px, 0.0);
} else { } else {
s.scroll_discrete(0, -ev.x); s.scroll_discrete(0, -ev.x);
s.scroll(0.0, -px);
} }
} }
None => emitted = false, None => emitted = false,