From ff22c8ac3b6edff9231165bb06921a39ad273bf2 Mon Sep 17 00:00:00 2001 From: LynithDev <61880709+LynithDev@users.noreply.github.com> Date: Wed, 19 Aug 2026 15:07:15 +0200 Subject: [PATCH] fix(app): normalize trackpad scroll deltas on macOS (#694) --- .../src/components/scrollview.rs | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/packages/oneclient_app/src/components/scrollview.rs b/packages/oneclient_app/src/components/scrollview.rs index 8b573159..46978be6 100644 --- a/packages/oneclient_app/src/components/scrollview.rs +++ b/packages/oneclient_app/src/components/scrollview.rs @@ -5,6 +5,30 @@ use crate::theme::colors; const LAZY_OVERSCAN: i64 = 3; +pub(crate) fn normalize_wheel_delta(delta: f64, scale_factor: f64) -> f32 { + if delta == 0.0 { + return 0.0; + } + + const FREYA_LINE_SPEED: f64 = 53.0; + const FREYA_PIXEL_SPEED: f64 = 2.0; + const LINE_DELTA_TOLERANCE: f64 = 1e-6; + const LINE_SCROLL: f64 = 53.0; + const PIXEL_SCROLL: f64 = 1.0; + + let lines = (delta / FREYA_LINE_SPEED).round(); + if lines != 0.0 && (delta - lines * FREYA_LINE_SPEED).abs() <= LINE_DELTA_TOLERANCE { + return (lines * LINE_SCROLL) as f32; + } + + let scale_factor = if scale_factor > 0.0 { + scale_factor + } else { + 1.0 + }; + (delta / (FREYA_PIXEL_SPEED * scale_factor) * PIXEL_SCROLL) as f32 +} + pub(crate) fn scroll_pos_from_wheel(wheel: f32, inner: f32, viewport: f32, current: f32) -> i32 { if viewport >= inner { return 0; @@ -226,6 +250,8 @@ impl ScrollArea { let internal = use_scroll_controller(ScrollConfig::default); let mut controller = self.controller.unwrap_or(internal); + let scale_factor = Platform::get().scale_factor; + let mut viewport_h = use_state(|| 0f32); let mut viewport_w = use_state(|| 0f32); let mut viewport_top = use_state(|| 0f32); @@ -310,17 +336,21 @@ impl ScrollArea { let on_wheel = move |e: Event| { let shift = *shift_held.read(); + let scale = *scale_factor.peek(); + + let delta_x = normalize_wheel_delta(e.delta_x, scale); + let delta_y = normalize_wheel_delta(e.delta_y, scale); let h_delta = if horizontal { - if shift && e.delta_x == 0.0 { - e.delta_y + if shift && delta_x == 0.0 { + delta_y } else { - e.delta_x + delta_x } } else { 0.0 }; - let v_delta = if horizontal && shift { 0.0 } else { e.delta_y }; + let v_delta = if horizontal && shift { 0.0 } else { delta_y }; let do_h = h_delta != 0.0 && can_scroll_h; let do_v = v_delta != 0.0 && can_scroll_v; @@ -337,14 +367,14 @@ impl ScrollArea { if do_h { let cur_x = corrected_scroll(content_w, vp_w, *scroll_x.read()); - let new_x = scroll_pos_from_wheel(h_delta as f32, content_w, vp_w, cur_x); + let new_x = scroll_pos_from_wheel(h_delta, content_w, vp_w, cur_x); scroll_x.set(new_x as f32); } if do_v { let (_, cur_y) = controller.into(); let current = corrected_scroll(ct_h, vp_h, cur_y as f32); - let new_y = scroll_pos_from_wheel(v_delta as f32, ct_h, vp_h, current); + let new_y = scroll_pos_from_wheel(v_delta, ct_h, vp_h, current); if new_y != cur_y { controller.scroll_to_y(new_y); }