From 77af8d47606020857f1df7e1d04d52684216d85e Mon Sep 17 00:00:00 2001 From: ziasquinn <56662076+ziasquinn@users.noreply.github.com> Date: Tue, 13 Jan 2026 00:24:43 -0500 Subject: [PATCH 1/6] Adjust TAP_TIME and HOLD_TIME for touchpad Increased HOLD_TIME from aggressive 20ms, to more forgiving 150ms. Since TAP_TIME default, without defining, is 150ms, also decrease this appropriately. Before, they were confusing each other. --- keyboards/svalboard/azoteq/config.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/keyboards/svalboard/azoteq/config.h b/keyboards/svalboard/azoteq/config.h index b6aa3abb00d..3f7de93773b 100644 --- a/keyboards/svalboard/azoteq/config.h +++ b/keyboards/svalboard/azoteq/config.h @@ -7,8 +7,14 @@ #define AZOTEQ_IQS5XX_TPS43 #define AZOTEQ_IQS5XX_TIMEOUT_MS 10 #define AZOTEQ_IQS5XX_PRESS_AND_HOLD_ENABLE true -//This decreases the required 'wait' time to activate dragging/selecting on a touchpad from default 300ms to 20ms. Big QoL. -#define AZOTEQ_IQS5XX_HOLD_TIME 20 + +#define AZOTEQ_IQS5XX_TAP_TIME 75 +// TAP_TIME default is 150ms +#define AZOTEQ_IQS5XX_HOLD_TIME 150 +// HOLD_TIME default is 300ms +// Here, we decrease the TAP_TIME to account for the reduced in HOLD_TIME so they aren't confused with each other. +// HOLD_TIME being reduced from 300ms to 150ms decreases the required 'wait' time to activate dragging/selecting on a touchpad, less sensitive than 20ms, but not tedious like 300ms. + //#define POINTING_DEVICE_MOTION_PIN GP18 #define SPLIT_POINTING_ENABLE From d93f039e6c7b420970c42af6f310b8a4c5886fbb Mon Sep 17 00:00:00 2001 From: ziasquinn <56662076+ziasquinn@users.noreply.github.com> Date: Sun, 18 Jan 2026 11:01:58 -0500 Subject: [PATCH 2/6] Reverting azoteq changes to state before september Azo PR Removed TAP_TIME and HOLD_TIME definitions to return behavior to baseline, longer 300ms hold-to-tap for dragging/selecting is the price for a consistent and intuitive interface. --- keyboards/svalboard/azoteq/config.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/keyboards/svalboard/azoteq/config.h b/keyboards/svalboard/azoteq/config.h index 3f7de93773b..18cdf82aa97 100644 --- a/keyboards/svalboard/azoteq/config.h +++ b/keyboards/svalboard/azoteq/config.h @@ -8,13 +8,6 @@ #define AZOTEQ_IQS5XX_TIMEOUT_MS 10 #define AZOTEQ_IQS5XX_PRESS_AND_HOLD_ENABLE true -#define AZOTEQ_IQS5XX_TAP_TIME 75 -// TAP_TIME default is 150ms -#define AZOTEQ_IQS5XX_HOLD_TIME 150 -// HOLD_TIME default is 300ms -// Here, we decrease the TAP_TIME to account for the reduced in HOLD_TIME so they aren't confused with each other. -// HOLD_TIME being reduced from 300ms to 150ms decreases the required 'wait' time to activate dragging/selecting on a touchpad, less sensitive than 20ms, but not tedious like 300ms. - //#define POINTING_DEVICE_MOTION_PIN GP18 #define SPLIT_POINTING_ENABLE From bafa629e1f37ffc53c6b4f8f37642cca849474f0 Mon Sep 17 00:00:00 2001 From: ziasquinn <56662076+ziasquinn@users.noreply.github.com> Date: Wed, 21 Jan 2026 20:14:51 -0500 Subject: [PATCH 3/6] Adjust TAP_TIME and HOLD_TIME for touchpad settings Increased HOLD_TIME from aggressive 20ms, to more forgiving 150ms. Since TAP_TIME (when default/without defining), is 150ms, also decrease this appropriately. Before, they were confusing each other. --- keyboards/svalboard/azoteq/config.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/keyboards/svalboard/azoteq/config.h b/keyboards/svalboard/azoteq/config.h index 18cdf82aa97..3f7de93773b 100644 --- a/keyboards/svalboard/azoteq/config.h +++ b/keyboards/svalboard/azoteq/config.h @@ -8,6 +8,13 @@ #define AZOTEQ_IQS5XX_TIMEOUT_MS 10 #define AZOTEQ_IQS5XX_PRESS_AND_HOLD_ENABLE true +#define AZOTEQ_IQS5XX_TAP_TIME 75 +// TAP_TIME default is 150ms +#define AZOTEQ_IQS5XX_HOLD_TIME 150 +// HOLD_TIME default is 300ms +// Here, we decrease the TAP_TIME to account for the reduced in HOLD_TIME so they aren't confused with each other. +// HOLD_TIME being reduced from 300ms to 150ms decreases the required 'wait' time to activate dragging/selecting on a touchpad, less sensitive than 20ms, but not tedious like 300ms. + //#define POINTING_DEVICE_MOTION_PIN GP18 #define SPLIT_POINTING_ENABLE From 875eac1e489f93a6e10b9eb58e5f1f471c593448 Mon Sep 17 00:00:00 2001 From: ziasquinn <56662076+ziasquinn@users.noreply.github.com> Date: Wed, 21 Jan 2026 22:57:04 -0500 Subject: [PATCH 4/6] Update build-firmware.yml --- .github/workflows/build-firmware.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-firmware.yml b/.github/workflows/build-firmware.yml index f6d69d33503..3c2dd40ff90 100644 --- a/.github/workflows/build-firmware.yml +++ b/.github/workflows/build-firmware.yml @@ -16,7 +16,7 @@ on: jobs: build: runs-on: ubuntu-latest - container: ghcr.io/qmk/qmk_cli + container: ghcr.io/qmk/qmk_cli@sha256:2dc05fc9f32efebd6b05c2b8676ee548358bc7e151e9dbf4dac6b6eed4513b07 steps: - name: Checkout code - Non PR @@ -79,9 +79,8 @@ jobs: shell: bash - name: Release - uses: softprops/action-gh-release@v2 + uses: ncipollo/release-action@v1.11.2 if: ${{ startsWith(github.ref, 'refs/tags/') }} with: - files: | - ${{ steps.move_file.outputs.file_name }} - + allowUpdates: True + artifacts: "${{ steps.move_file.outputs.file_name }}" From e236f535f2b8c503a7cc0e939cfd52d12f0f82f8 Mon Sep 17 00:00:00 2001 From: ziasquinn <56662076+ziasquinn@users.noreply.github.com> Date: Wed, 21 Jan 2026 23:08:28 -0500 Subject: [PATCH 5/6] Testing out a split of default and the halving AZOTEQ config.h changes: TAP_TIME = 100ms (default 150ms) HOLD_TIME = 200ms (default 300ms) --- keyboards/svalboard/azoteq/config.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/keyboards/svalboard/azoteq/config.h b/keyboards/svalboard/azoteq/config.h index 3f7de93773b..aade727ef28 100644 --- a/keyboards/svalboard/azoteq/config.h +++ b/keyboards/svalboard/azoteq/config.h @@ -8,12 +8,11 @@ #define AZOTEQ_IQS5XX_TIMEOUT_MS 10 #define AZOTEQ_IQS5XX_PRESS_AND_HOLD_ENABLE true -#define AZOTEQ_IQS5XX_TAP_TIME 75 +#define AZOTEQ_IQS5XX_TAP_TIME 100 // TAP_TIME default is 150ms -#define AZOTEQ_IQS5XX_HOLD_TIME 150 +#define AZOTEQ_IQS5XX_HOLD_TIME 200 // HOLD_TIME default is 300ms // Here, we decrease the TAP_TIME to account for the reduced in HOLD_TIME so they aren't confused with each other. -// HOLD_TIME being reduced from 300ms to 150ms decreases the required 'wait' time to activate dragging/selecting on a touchpad, less sensitive than 20ms, but not tedious like 300ms. //#define POINTING_DEVICE_MOTION_PIN GP18 From 21a46a0982c0e741666cc745aa7d86ad8aa954e1 Mon Sep 17 00:00:00 2001 From: Richard Newman Date: Wed, 25 Mar 2026 22:47:31 -0600 Subject: [PATCH 6/6] Overhaul Azoteq IQS5XX touchpad scroll and drag behavior MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is, in general, impossible for a QMK keyboard to implement smooth touchpad scrolling on macOS: it ignores supplied resolution multipliers, doesn't ask for reports, and seemingly only allows Magic Touchpads to deliver a good experience. The recommended configuration is to use an app like SmoothScroll or Mos to convert mouse wheel-style scrolls into smooth scroll; the work expected of the firmware itself is to supply a reasonable range of scroll values. This commit does so, though you might still wish to adjust configured values. It includes three major changes to improve touchpad usability on macOS: 1. Configurable scroll speed reduction via `axis_scale`: replace naive integer division (which truncated small per-report values to zero, causing a "dead zone then jump" effect) with a remainder-preserving accumulator. Uses `CONSTRAIN_HID_HV` (new macro) instead of `CONSTRAIN_HID`: clamps to the proper HV range (`int16` when `WHEEL_EXTENDED_REPORT` is defined, `int8` otherwise). 2. Natural scrolling by default: invert the Y axis for two-finger scroll gestures so that content follows finger direction (swipe down = scroll down), matching macOS trackpad convention. 3. Replace press_and_hold drag with tap-to-drag: Problem: press_and_hold fired BUTTON1 whenever a finger lingered on the pad beyond HOLD_TIME, making it impossible to move the cursor without accidentally drag-selecting. Disabling press_and_hold at the IQS5XX hardware level caused the gesture engine to stall and stop detecting taps entirely. Solution (two parts): a) Decouple hardware gesture detection from click behavior. A new `AZOTEQ_IQS5XX_PRESS_AND_HOLD_AS_CLICK` define (defaulting to `PRESS_AND_HOLD_ENABLE` for backward compat) controls whether press_and_hold events produce BUTTON1 in the report handler. The hardware gesture stays enabled so the IQS5XX state machine remains healthy, but we simply ignore the event. b) Implement macOS-style tap-to-drag: after a single_tap, BUTTON1 is held continuously for a configurable window (`TAP_DRAG_WINDOW_MS`, default 200ms). If a finger touches the pad again within that window, drag mode engages and BUTTON1 remains held until the finger lifts. The continuous hold during the window is critical — an earlier implementation that released BUTTON1 between tap and drag worked for text selection but failed for macOS window dragging, which requires an unbroken button press from the initial click on the title bar. `TAP_TIME` raised from 100ms to 200ms since there is no longer a need to keep it short to disambiguate taps from press_and_hold. `HOLD_TIME` remains at default 300ms. New configurable defines (all with backward-compatible defaults): - AZOTEQ_IQS5XX_SCROLL_DIVISOR (default 1, configured to 8 for Svalboard) - AZOTEQ_IQS5XX_PRESS_AND_HOLD_AS_CLICK (default matches ENABLE) - AZOTEQ_IQS5XX_TAP_DRAG_ENABLE (default false) - AZOTEQ_IQS5XX_TAP_DRAG_WINDOW_MS (default 200) --- drivers/sensors/azoteq_iqs5xx.c | 62 +++++++++++++++++++++-- keyboards/svalboard/azoteq/config.h | 16 ++++-- quantum/pointing_device/pointing_device.h | 1 + 3 files changed, 72 insertions(+), 7 deletions(-) diff --git a/drivers/sensors/azoteq_iqs5xx.c b/drivers/sensors/azoteq_iqs5xx.c index ae26ee60cfd..0538e9caeac 100644 --- a/drivers/sensors/azoteq_iqs5xx.c +++ b/drivers/sensors/azoteq_iqs5xx.c @@ -3,7 +3,9 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "azoteq_iqs5xx.h" +#include "axis_scale.h" #include "pointing_device_internal.h" +#include "timer.h" #include "wait.h" #ifndef AZOTEQ_IQS5XX_ADDRESS @@ -78,6 +80,15 @@ #ifndef AZOTEQ_IQS5XX_ZOOM_CONSECUTIVE_DISTANCE # define AZOTEQ_IQS5XX_ZOOM_CONSECUTIVE_DISTANCE 0x19 #endif +#ifndef AZOTEQ_IQS5XX_SCROLL_DIVISOR +# define AZOTEQ_IQS5XX_SCROLL_DIVISOR 1 +#endif +#ifndef AZOTEQ_IQS5XX_TAP_DRAG_ENABLE +# define AZOTEQ_IQS5XX_TAP_DRAG_ENABLE false +#endif +#ifndef AZOTEQ_IQS5XX_TAP_DRAG_WINDOW_MS +# define AZOTEQ_IQS5XX_TAP_DRAG_WINDOW_MS 200 +#endif #ifndef AZOTEQ_IQS5XX_EVENT_MODE // Event mode can't be used until the pointing code has changed (stuck buttons) # define AZOTEQ_IQS5XX_EVENT_MODE false @@ -351,6 +362,15 @@ void azoteq_iqs5xx_init(void) { } }; +static axis_scale_t scroll_scale_h = { .mult = 1, .div = AZOTEQ_IQS5XX_SCROLL_DIVISOR, .remainder = 0 }; +static axis_scale_t scroll_scale_v = { .mult = 1, .div = AZOTEQ_IQS5XX_SCROLL_DIVISOR, .remainder = 0 }; + +#if AZOTEQ_IQS5XX_TAP_DRAG_ENABLE +static bool tap_drag_armed = false; +static bool tap_drag_active = false; +static uint16_t tap_drag_timer = 0; +#endif + report_mouse_t azoteq_iqs5xx_get_report(report_mouse_t mouse_report) { report_mouse_t temp_report = {0}; @@ -365,7 +385,14 @@ report_mouse_t azoteq_iqs5xx_get_report(report_mouse_t mouse_report) { pd_dprintf("IQS5XX - previous cycle time missed, took: %dms\n", base_data.previous_cycle_time); } #endif - if (base_data.gesture_events_0.single_tap || base_data.gesture_events_0.press_and_hold) { +#ifndef AZOTEQ_IQS5XX_PRESS_AND_HOLD_AS_CLICK +# define AZOTEQ_IQS5XX_PRESS_AND_HOLD_AS_CLICK AZOTEQ_IQS5XX_PRESS_AND_HOLD_ENABLE +#endif + if (base_data.gesture_events_0.single_tap +#if AZOTEQ_IQS5XX_PRESS_AND_HOLD_AS_CLICK + || base_data.gesture_events_0.press_and_hold +#endif + ) { pd_dprintf("IQS5XX - Single tap/hold.\n"); temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON1); } else if (base_data.gesture_events_1.two_finger_tap) { @@ -397,9 +424,38 @@ report_mouse_t azoteq_iqs5xx_get_report(report_mouse_t mouse_report) { } } else if (base_data.gesture_events_1.scroll) { pd_dprintf("IQS5XX - Scroll.\n"); - temp_report.h = CONSTRAIN_HID(AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.x.h, base_data.x.l)); - temp_report.v = CONSTRAIN_HID(AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.y.h, base_data.y.l)); + temp_report.h = CONSTRAIN_HID_HV(add_to_axis(&scroll_scale_h, AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.x.h, base_data.x.l))); + temp_report.v = CONSTRAIN_HID_HV(add_to_axis(&scroll_scale_v, -AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.y.h, base_data.y.l))); + } else { + clear_remainder_axis(&scroll_scale_h); + clear_remainder_axis(&scroll_scale_v); + } +#if AZOTEQ_IQS5XX_TAP_DRAG_ENABLE + // Tap-to-drag: tap, lift, quickly touch again to drag. + // BUTTON1 is held throughout the drag window so macOS sees + // one continuous press (required for window dragging, etc.). + if (base_data.gesture_events_0.single_tap) { + tap_drag_armed = true; + tap_drag_active = false; + tap_drag_timer = timer_read(); + } else if (tap_drag_active) { + if (base_data.number_of_fingers >= 1) { + temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON1); + } else { + tap_drag_active = false; + } + } else if (tap_drag_armed) { + // Keep BUTTON1 held during the window so there's no gap. + temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON1); + if (timer_elapsed(tap_drag_timer) >= AZOTEQ_IQS5XX_TAP_DRAG_WINDOW_MS) { + tap_drag_armed = false; + // Release — finger didn't come back in time. + } else if (base_data.number_of_fingers == 1) { + tap_drag_active = true; + tap_drag_armed = false; + } } +#endif if (base_data.number_of_fingers == 1 && !ignore_movement) { temp_report.x = CONSTRAIN_HID_XY(AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.x.h, base_data.x.l)); temp_report.y = CONSTRAIN_HID_XY(AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.y.h, base_data.y.l)); diff --git a/keyboards/svalboard/azoteq/config.h b/keyboards/svalboard/azoteq/config.h index aade727ef28..331f8b1dd9b 100644 --- a/keyboards/svalboard/azoteq/config.h +++ b/keyboards/svalboard/azoteq/config.h @@ -6,13 +6,21 @@ #define AZOTEQ_IQS5XX_TPS43 #define AZOTEQ_IQS5XX_TIMEOUT_MS 10 +// Keep press_and_hold enabled in hardware to avoid gesture engine stalls, +// but don't act on it — see AZOTEQ_IQS5XX_PRESS_AND_HOLD_AS_CLICK below. #define AZOTEQ_IQS5XX_PRESS_AND_HOLD_ENABLE true +#define AZOTEQ_IQS5XX_PRESS_AND_HOLD_AS_CLICK false -#define AZOTEQ_IQS5XX_TAP_TIME 100 -// TAP_TIME default is 150ms -#define AZOTEQ_IQS5XX_HOLD_TIME 200 +#define AZOTEQ_IQS5XX_TAP_DRAG_ENABLE true +#define AZOTEQ_IQS5XX_TAP_DRAG_WINDOW_MS 200 + +#define AZOTEQ_IQS5XX_SCROLL_DIVISOR 8 + +#define AZOTEQ_IQS5XX_TAP_TIME 200 +// TAP_TIME default is 150ms. Raised since we no longer act on press_and_hold, +// so there's no need to keep TAP_TIME short to disambiguate the two. +#define AZOTEQ_IQS5XX_HOLD_TIME 300 // HOLD_TIME default is 300ms -// Here, we decrease the TAP_TIME to account for the reduced in HOLD_TIME so they aren't confused with each other. //#define POINTING_DEVICE_MOTION_PIN GP18 diff --git a/quantum/pointing_device/pointing_device.h b/quantum/pointing_device/pointing_device.h index 0186ad1992a..176cb3b15f7 100644 --- a/quantum/pointing_device/pointing_device.h +++ b/quantum/pointing_device/pointing_device.h @@ -108,6 +108,7 @@ typedef int16_t hv_clamp_range_t; #define CONSTRAIN_HID(amt) ((amt) < INT8_MIN ? INT8_MIN : ((amt) > INT8_MAX ? INT8_MAX : (amt))) #define CONSTRAIN_HID_XY(amt) ((amt) < MOUSE_REPORT_XY_MIN ? MOUSE_REPORT_XY_MIN : ((amt) > MOUSE_REPORT_XY_MAX ? MOUSE_REPORT_XY_MAX : (amt))) +#define CONSTRAIN_HID_HV(amt) ((amt) < MOUSE_REPORT_HV_MIN ? MOUSE_REPORT_HV_MIN : ((amt) > MOUSE_REPORT_HV_MAX ? MOUSE_REPORT_HV_MAX : (amt))) void pointing_device_init(void); bool pointing_device_task(void);