From 20b820866973186d6caa7a2ec22af2b2bc5a2f04 Mon Sep 17 00:00:00 2001 From: Florian Didron Date: Mon, 24 Nov 2025 17:56:32 +0700 Subject: [PATCH] feat(scrolling): inertia --- drivers/sensors/navigator_trackpad.c | 80 +++++++++++++++++++ drivers/sensors/navigator_trackpad.h | 31 +++++++ .../ergodox_ez/keymaps/default/keymap.json | 6 ++ .../zsa/ergodox_ez/keymaps/default/rules.mk | 7 ++ 4 files changed, 124 insertions(+) create mode 100644 keyboards/zsa/ergodox_ez/keymaps/default/keymap.json create mode 100644 keyboards/zsa/ergodox_ez/keymaps/default/rules.mk diff --git a/drivers/sensors/navigator_trackpad.c b/drivers/sensors/navigator_trackpad.c index a45e3ded41..2ecac09385 100644 --- a/drivers/sensors/navigator_trackpad.c +++ b/drivers/sensors/navigator_trackpad.c @@ -29,6 +29,9 @@ bool trackpad_init; #if defined(NAVIGATOR_TRACKPAD_PTP_MODE) cgen6_report_t ptp_report; trackpad_gesture_t gesture = {0}; +# ifdef NAVIGATOR_TRACKPAD_SCROLL_INERTIA_ENABLE +scroll_inertia_t scroll_inertia = {0}; +# endif #endif // Helper functions to parse ptp reports @@ -385,6 +388,53 @@ report_mouse_t navigator_trackpad_get_report(report_mouse_t mouse_report) { mouse_report.buttons = 0; return mouse_report; } + +# ifdef NAVIGATOR_TRACKPAD_SCROLL_INERTIA_ENABLE + // Process scroll inertia when active + if (scroll_inertia.active && timer_elapsed(scroll_inertia.timer) >= NAVIGATOR_TRACKPAD_SCROLL_INERTIA_INTERVAL) { + scroll_inertia.timer = timer_read(); + + // Apply friction to velocity (Q8 fixed point math) + // Friction reduces velocity towards zero + int16_t friction_x = (scroll_inertia.vx * NAVIGATOR_TRACKPAD_SCROLL_INERTIA_FRICTION) / 256; + int16_t friction_y = (scroll_inertia.vy * NAVIGATOR_TRACKPAD_SCROLL_INERTIA_FRICTION) / 256; + + // Ensure we always reduce by at least 1 if not zero + if (scroll_inertia.vx > 0 && friction_x < 1) friction_x = 1; + if (scroll_inertia.vx < 0 && friction_x > -1) friction_x = -1; + if (scroll_inertia.vy > 0 && friction_y < 1) friction_y = 1; + if (scroll_inertia.vy < 0 && friction_y > -1) friction_y = -1; + + scroll_inertia.vx -= friction_x; + scroll_inertia.vy -= friction_y; + + // Convert Q8 velocity to scroll value + int16_t scroll_x = (scroll_inertia.vx * NAVIGATOR_TRACKPAD_SCROLL_MULTIPLIER) / 256; + int16_t scroll_y = (scroll_inertia.vy * NAVIGATOR_TRACKPAD_SCROLL_MULTIPLIER) / 256; + + // Clamp to int8_t range + scroll_x = (scroll_x > 127) ? 127 : ((scroll_x < -127) ? -127 : scroll_x); + scroll_y = (scroll_y > 127) ? 127 : ((scroll_y < -127) ? -127 : scroll_y); + + // Check if velocity is too low to continue + int16_t abs_vx = scroll_inertia.vx < 0 ? -scroll_inertia.vx : scroll_inertia.vx; + int16_t abs_vy = scroll_inertia.vy < 0 ? -scroll_inertia.vy : scroll_inertia.vy; + if (abs_vx < 64 && abs_vy < 64) { // Threshold in Q8 (0.25 in real units) + scroll_inertia.active = false; +# ifdef NAVIGATOR_TRACKPAD_GESTURE_DEBUG + printf("INERTIA STOP\n"); +# endif + } else { +# ifdef NAVIGATOR_TRACKPAD_GESTURE_DEBUG + printf("INERTIA: vx=%d vy=%d -> h=%d v=%d\n", + scroll_inertia.vx, scroll_inertia.vy, -scroll_x, scroll_y); +# endif + mouse_report.h = -scroll_x; // Invert for natural scrolling + mouse_report.v = scroll_y; + return mouse_report; + } + } +# endif #endif if (!has_motion || !trackpad_init) { @@ -414,6 +464,12 @@ report_mouse_t navigator_trackpad_get_report(report_mouse_t mouse_report) { gesture.settled = false; gesture.max_finger_count = fingers; gesture.state = TP_MOVING; +# ifdef NAVIGATOR_TRACKPAD_SCROLL_INERTIA_ENABLE + // Stop any ongoing scroll inertia when finger touches + scroll_inertia.active = false; + scroll_inertia.last_dx = 0; + scroll_inertia.last_dy = 0; +# endif } // Handle finger up - evaluate tap at lift time (libinput style) @@ -469,6 +525,24 @@ report_mouse_t navigator_trackpad_get_report(report_mouse_t mouse_report) { } # endif +# ifdef NAVIGATOR_TRACKPAD_SCROLL_INERTIA_ENABLE + // Start scroll inertia if we were scrolling and have enough velocity + if (gesture.state == TP_SCROLLING) { + int16_t abs_vx = scroll_inertia.last_dx < 0 ? -scroll_inertia.last_dx : scroll_inertia.last_dx; + int16_t abs_vy = scroll_inertia.last_dy < 0 ? -scroll_inertia.last_dy : scroll_inertia.last_dy; + if (abs_vx >= NAVIGATOR_TRACKPAD_SCROLL_INERTIA_TRIGGER || + abs_vy >= NAVIGATOR_TRACKPAD_SCROLL_INERTIA_TRIGGER) { + scroll_inertia.vx = scroll_inertia.last_dx * 256; // Q8 fixed point + scroll_inertia.vy = scroll_inertia.last_dy * 256; + scroll_inertia.timer = timer_read(); + scroll_inertia.active = true; +# ifdef NAVIGATOR_TRACKPAD_GESTURE_DEBUG + printf("INERTIA START: vx=%d vy=%d\n", scroll_inertia.vx, scroll_inertia.vy); +# endif + } + } +# endif + gesture.state = TP_IDLE; set_scrolling = false; } @@ -518,6 +592,12 @@ report_mouse_t navigator_trackpad_get_report(report_mouse_t mouse_report) { int16_t scroll_x = delta_x * NAVIGATOR_TRACKPAD_SCROLL_MULTIPLIER; int16_t scroll_y = delta_y * NAVIGATOR_TRACKPAD_SCROLL_MULTIPLIER; +# ifdef NAVIGATOR_TRACKPAD_SCROLL_INERTIA_ENABLE + // Track velocity for inertia (store pre-multiplied deltas) + scroll_inertia.last_dx = delta_x; + scroll_inertia.last_dy = delta_y; +# endif + // Clamp to int8_t range for the report scroll_x = (scroll_x > 127) ? 127 : ((scroll_x < -127) ? -127 : scroll_x); scroll_y = (scroll_y > 127) ? 127 : ((scroll_y < -127) ? -127 : scroll_y); diff --git a/drivers/sensors/navigator_trackpad.h b/drivers/sensors/navigator_trackpad.h index 05ed951cd6..4145815e76 100644 --- a/drivers/sensors/navigator_trackpad.h +++ b/drivers/sensors/navigator_trackpad.h @@ -104,6 +104,37 @@ # define NAVIGATOR_TRACKPAD_SCROLL_MULTIPLIER 4 #endif +// Scroll inertia configuration +/* +To enable, add to your config.h: +#define NAVIGATOR_TRACKPAD_SCROLL_INERTIA_ENABLE + +Configurable values (all optional): +- NAVIGATOR_TRACKPAD_SCROLL_INERTIA_FRICTION - Higher = stops faster (default: 50, range 1-255) +- NAVIGATOR_TRACKPAD_SCROLL_INERTIA_INTERVAL - Time between glide reports in ms (default: 15) +- NAVIGATOR_TRACKPAD_SCROLL_INERTIA_TRIGGER - Minimum velocity to trigger glide (default: 3) +*/ +#ifdef NAVIGATOR_TRACKPAD_SCROLL_INERTIA_ENABLE +# ifndef NAVIGATOR_TRACKPAD_SCROLL_INERTIA_FRICTION +# define NAVIGATOR_TRACKPAD_SCROLL_INERTIA_FRICTION 50 // Higher = stops faster (1-255) +# endif +# ifndef NAVIGATOR_TRACKPAD_SCROLL_INERTIA_INTERVAL +# define NAVIGATOR_TRACKPAD_SCROLL_INERTIA_INTERVAL 15 // Glide report interval in ms +# endif +# ifndef NAVIGATOR_TRACKPAD_SCROLL_INERTIA_TRIGGER +# define NAVIGATOR_TRACKPAD_SCROLL_INERTIA_TRIGGER 3 // Min velocity to trigger glide +# endif + +typedef struct { + int16_t vx; // Current X velocity (Q8 fixed point) + int16_t vy; // Current Y velocity (Q8 fixed point) + int16_t last_dx; // Last scroll delta X + int16_t last_dy; // Last scroll delta Y + uint16_t timer; // Timer for interval tracking + bool active; // Is glide currently active +} scroll_inertia_t; +#endif + #if defined(NAVIGATOR_TRACKPAD_PTP_MODE) # ifndef MOUSE_EXTENDED_REPORT # define MOUSE_EXTENDED_REPORT diff --git a/keyboards/zsa/ergodox_ez/keymaps/default/keymap.json b/keyboards/zsa/ergodox_ez/keymaps/default/keymap.json new file mode 100644 index 0000000000..1c0aeaf99a --- /dev/null +++ b/keyboards/zsa/ergodox_ez/keymaps/default/keymap.json @@ -0,0 +1,6 @@ +{ + "modules": [ + "zsa/oryx", + "zsa/defaults" + ] +} diff --git a/keyboards/zsa/ergodox_ez/keymaps/default/rules.mk b/keyboards/zsa/ergodox_ez/keymaps/default/rules.mk new file mode 100644 index 0000000000..2a2dea3ca5 --- /dev/null +++ b/keyboards/zsa/ergodox_ez/keymaps/default/rules.mk @@ -0,0 +1,7 @@ +CONSOLE_ENABLE = yes +COMMAND_ENABLE = no +ORYX_ENABLE = yes +SPACE_CADET_ENABLE = no +CAPS_WORD_ENABLE = yes +RGBLIGHT_ENABLE = no +LTO_ENABLE = yes