From 82bfceccf681801c041251541a1f4b53c13fe187 Mon Sep 17 00:00:00 2001 From: Florian Didron Date: Tue, 9 Sep 2025 09:49:55 +0700 Subject: [PATCH 1/3] fix(automouse): make sure KC_NO do not fire layer 0 mappings on automouse layer (#419) --- quantum/pointing_device/pointing_device_auto_mouse.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quantum/pointing_device/pointing_device_auto_mouse.c b/quantum/pointing_device/pointing_device_auto_mouse.c index 0f227d8435..41df31f976 100644 --- a/quantum/pointing_device/pointing_device_auto_mouse.c +++ b/quantum/pointing_device/pointing_device_auto_mouse.c @@ -343,7 +343,8 @@ bool process_auto_mouse(uint16_t keycode, keyrecord_t* record) { if (!(AUTO_MOUSE_ENABLED)) return true; switch (keycode) { - // Skip Mod keys and layer lock to avoid layer reset + // Skip Mod keys, KC_NO, and layer lock to avoid layer reset + case KC_NO: case KC_LEFT_CTRL ... KC_RIGHT_GUI: case QK_MODS ... QK_MODS_MAX: case QK_LLCK: From 1f95d83f68571b5dd398313cf502235d48fbb0ec Mon Sep 17 00:00:00 2001 From: Florian Didron Date: Tue, 9 Sep 2025 09:50:13 +0700 Subject: [PATCH 2/3] fix(automouse): prevent mouse keys to trigger auto mouse on other layers (#418) --- quantum/pointing_device/pointing_device_auto_mouse.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/quantum/pointing_device/pointing_device_auto_mouse.c b/quantum/pointing_device/pointing_device_auto_mouse.c index 41df31f976..2b8cfdbf68 100644 --- a/quantum/pointing_device/pointing_device_auto_mouse.c +++ b/quantum/pointing_device/pointing_device_auto_mouse.c @@ -443,7 +443,14 @@ bool process_auto_mouse(uint16_t keycode, keyrecord_t* record) { */ static bool is_mouse_record(uint16_t keycode, keyrecord_t* record) { // allow for keyboard to hook in and override if need be - if (is_mouse_record_kb(keycode, record) || IS_MOUSEKEY(keycode)) return true; + if (is_mouse_record_kb(keycode, record)) return true; + + // if it's a mouse key, only treat it as a mouse record if we're currently on the auto mouse target layer + // this prevents mouse keys from activating the auto mouse layer when pressed on other layers + if (IS_MOUSEKEY(keycode)) { + return layer_state_is((AUTO_MOUSE_TARGET_LAYER)); + } + return false; } From e87a3e6949719612b6444faddaed2463ed03f250 Mon Sep 17 00:00:00 2001 From: Florian Didron Date: Fri, 12 Sep 2025 16:15:34 +0700 Subject: [PATCH 3/3] Feat/smoother scrolling (#420) * feat(navigator): a smoother scrolling experience at slower speed * doc(navigator): Fix scrolling docs, tweak defaults * chore(navigator): remove unused include * fix(trackball) inverted default horizontal scrolling --- drivers/sensors/navigator.c | 96 ++++++++++++++++++++++++++++++++++--- drivers/sensors/navigator.h | 13 +++++ 2 files changed, 103 insertions(+), 6 deletions(-) diff --git a/drivers/sensors/navigator.c b/drivers/sensors/navigator.c index 90ca16709a..596d7ae4ad 100644 --- a/drivers/sensors/navigator.c +++ b/drivers/sensors/navigator.c @@ -1,6 +1,31 @@ // Copyright 2025 ZSA Technology Labs, Inc // SPDX-License-Identifier: GPL-2.0-or-later +/* + * Navigator Trackball Smooth Scrolling + * + * Enhanced scrolling algorithm that eliminates deadzones and provides natural, + * responsive scrolling for both slow and fast movements. + * + * Key Features: + * - No initial deadzone - scrolling starts immediately with any movement + * - Smooth acceleration - speed increases naturally with faster movement + * - Fractional accumulation - sub-pixel movements accumulate until triggering scroll + * - Reduced jitter - consistent consumption prevents oscillation + * + * Configuration Parameters (add to keymap config.h): + * - NAVIGATOR_SCROLL_DIVIDER: Lower = more sensitive (default: 10) + * - NAVIGATOR_SCROLL_THRESHOLD: Minimum to scroll (default: 0f) + * - NAVIGATOR_SCROLL_ACCELERATION: Speed multiplier (default: 1.5f) + * - NAVIGATOR_SCROLL_MAX_SPEED: Maximum speed limit (default: 8.0f) + * + * Algorithm: + * 1. Accumulate input as floating-point values + * 2. When accumulated >= 1.0, trigger scrolling with acceleration + * 3. Subtract exactly 1.0 from accumulation regardless of output + * 4. Gentle decay (2% per frame) only after 20 frames of inactivity + */ + #include "quantum.h" #include "navigator.h" @@ -25,17 +50,76 @@ report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) { mouse_report.y /= NAVIGATOR_AIM_DIVIDER; } if (set_scrolling) { + // Accumulate scroll movement scroll_accumulated_h += (float)mouse_report.x / NAVIGATOR_SCROLL_DIVIDER; scroll_accumulated_v += (float)mouse_report.y / NAVIGATOR_SCROLL_DIVIDER; - mouse_report.h = (int8_t)scroll_accumulated_h; -#ifdef NAVIGATOR_SCROLL_INVERT - mouse_report.v = (int8_t)-scroll_accumulated_v; + + // This allows fractional accumulation to build up before triggering scroll + float abs_h = (scroll_accumulated_h < 0) ? -scroll_accumulated_h : scroll_accumulated_h; + float abs_v = (scroll_accumulated_v < 0) ? -scroll_accumulated_v : scroll_accumulated_v; + + float scroll_h = 0.0f; + float scroll_v = 0.0f; + + if (abs_h >= 1.0f) { + // Simple acceleration for faster movements + float speed_h = 1.0f + ((abs_h - 1.0f) * NAVIGATOR_SCROLL_ACCELERATION); + if (speed_h > NAVIGATOR_SCROLL_MAX_SPEED) { + speed_h = NAVIGATOR_SCROLL_MAX_SPEED; + } + scroll_h = (scroll_accumulated_h > 0) ? speed_h : -speed_h; + } + + if (abs_v >= 1.0f) { + float speed_v = 1.0f + ((abs_v - 1.0f) * NAVIGATOR_SCROLL_ACCELERATION); + if (speed_v > NAVIGATOR_SCROLL_MAX_SPEED) { + speed_v = NAVIGATOR_SCROLL_MAX_SPEED; + } + scroll_v = (scroll_accumulated_v > 0) ? speed_v : -speed_v; + } + +#ifdef NAVIGATOR_SCROLL_INVERT_X + mouse_report.h = (int8_t)scroll_h; #else - mouse_report.v = (int8_t)scroll_accumulated_v; + mouse_report.h = (int8_t)-scroll_h; #endif - scroll_accumulated_h -= (int8_t)scroll_accumulated_h; - scroll_accumulated_v -= (int8_t)scroll_accumulated_v; +#ifdef NAVIGATOR_SCROLL_INVERT_Y + mouse_report.v = (int8_t)-scroll_v; +#else + mouse_report.v = (int8_t)scroll_v; +#endif + + + // Subtract proportional to the base scroll (before acceleration) to prevent jitter + if (abs_h >= 1.0f) { + scroll_accumulated_h -= (scroll_accumulated_h > 0) ? 1.0f : -1.0f; + } + if (abs_v >= 1.0f) { + scroll_accumulated_v -= (scroll_accumulated_v > 0) ? 1.0f : -1.0f; + } + + + // Much gentler decay and only after longer idle periods + static uint8_t idle_counter_h = 0, idle_counter_v = 0; + + if (mouse_report.x == 0 && mouse_report.h == 0) { + idle_counter_h++; + if (idle_counter_h > 20) { // Only decay after 20 frames of no input + scroll_accumulated_h *= 0.98f; // Very gentle decay + } + } else { + idle_counter_h = 0; + } + + if (mouse_report.y == 0 && mouse_report.v == 0) { + idle_counter_v++; + if (idle_counter_v > 20) { + scroll_accumulated_v *= 0.98f; + } + } else { + idle_counter_v = 0; + } mouse_report.x = 0; mouse_report.y = 0; diff --git a/drivers/sensors/navigator.h b/drivers/sensors/navigator.h index 73e809715b..dc0fbe0214 100644 --- a/drivers/sensors/navigator.h +++ b/drivers/sensors/navigator.h @@ -6,6 +6,19 @@ #define NAVIGATOR_SCROLL_DIVIDER 10 #endif +#ifndef NAVIGATOR_SCROLL_THRESHOLD + #define NAVIGATOR_SCROLL_THRESHOLD 0f +#endif + +#ifndef NAVIGATOR_SCROLL_ACCELERATION + #define NAVIGATOR_SCROLL_ACCELERATION 1.5f +#endif + +#ifndef NAVIGATOR_SCROLL_MAX_SPEED + #define NAVIGATOR_SCROLL_MAX_SPEED 8.0f +#endif + + #ifdef POINTING_DEVICE_DRIVER_navigator_trackball #define NAVIGATOR_TURBO_MULTIPLIER 3 #define NAVIGATOR_AIM_DIVIDER 3