From 48c86a275bf8f07fbd1ed2f9ca100c109aae846c Mon Sep 17 00:00:00 2001 From: suraj Date: Wed, 4 Mar 2026 20:52:21 +0530 Subject: [PATCH 1/4] Implements Edge motion Hook into the tap-and-drag state machine to emit pointer events when the finger reaches the touchpad edge. This allows continued motion when dragging beyond the physical boundary. Signed-off-by: suraj --- meson.build | 1 + src/evdev-mt-touchpad-edge-motion.c | 246 ++++++++++++++++++++++++++++ src/evdev-mt-touchpad-tap.c | 4 + src/evdev-mt-touchpad.h | 12 +- 4 files changed, 262 insertions(+), 1 deletion(-) create mode 100644 src/evdev-mt-touchpad-edge-motion.c diff --git a/meson.build b/meson.build index 235a67a5..2192a196 100644 --- a/meson.build +++ b/meson.build @@ -436,6 +436,7 @@ src_libinput = src_libfilter + [ 'src/evdev-mt-touchpad-thumb.c', 'src/evdev-mt-touchpad-buttons.c', 'src/evdev-mt-touchpad-edge-scroll.c', + 'src/evdev-mt-touchpad-edge-motion.c', 'src/evdev-mt-touchpad-gestures.c', 'src/evdev-tablet.c', 'src/evdev-tablet-pad.c', diff --git a/src/evdev-mt-touchpad-edge-motion.c b/src/evdev-mt-touchpad-edge-motion.c new file mode 100644 index 00000000..2a40b570 --- /dev/null +++ b/src/evdev-mt-touchpad-edge-motion.c @@ -0,0 +1,246 @@ +/* + * Copyright © 2014-2015 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* + * TOUCHPAD EDGE MOTION + * + * This module implements automatic cursor motion when performing tap-and-drag + * operations near the edges of a touchpad. When a user starts dragging content + * and reaches the edge of the touchpad, the system automatically continues + * moving the cursor in that direction to allow selection/dragging of content + * that extends beyond the physical touchpad boundaries. + */ + +#include "config.h" + +#include +#include + +#include "evdev-mt-touchpad.h" + +void +tp_edge_motion_init(struct tp_dispatch *tp); + +enum edge_motion_state { STATE_IDLE, STATE_DRAG_ACTIVE, STATE_EDGE_MOTION }; + +struct edge_motion_fsm { + enum edge_motion_state current_state; + usec_t last_motion_time; + uint32_t current_edge; + double motion_dx; + double motion_dy; + uint32_t continuous_motion_count; + struct tp_dispatch *tp; + struct libinput_timer timer; +}; + +static struct edge_motion_fsm fsm = { + .current_state = STATE_IDLE, + .tp = NULL, +}; + +#define EDGE_MOTION_CONFIG_SPEED_MM_S 70.0 +#define EDGE_MOTION_CONFIG_MIN_INTERVAL_US 8000 +#define EDGE_MOTION_CONFIG_EDGE_THRESHOLD_MM 5.0 + +static void +calculate_motion_vector(uint32_t edge, double *dx, double *dy) +{ + *dx = 0.0; + *dy = 0.0; + + if (edge & EDGE_LEFT) + *dx = -1.0; + else if (edge & EDGE_RIGHT) + *dx = 1.0; + + if (edge & EDGE_TOP) + *dy = -1.0; + else if (edge & EDGE_BOTTOM) + *dy = 1.0; + + double mag = sqrt((*dx) * (*dx) + (*dy) * (*dy)); + if (mag > 0) { + *dx /= mag; + *dy /= mag; + } +} + +static void +inject_accumulated_motion(struct tp_dispatch *tp, usec_t time) +{ + if (usec_is_zero(fsm.last_motion_time)) { + fsm.last_motion_time = time; + return; + } + + usec_t time_since_last = usec_sub(time, fsm.last_motion_time); + double dist_mm = + EDGE_MOTION_CONFIG_SPEED_MM_S * ((double)usec_as_uint64_t(time_since_last) / 1000000.0); + + if (dist_mm < 0.001) + return; + + struct device_float_coords raw = { + .x = fsm.motion_dx * dist_mm * tp->accel.x_scale_coeff, + .y = fsm.motion_dy * dist_mm * tp->accel.y_scale_coeff + }; + + struct normalized_coords delta = + filter_dispatch(tp->device->pointer.filter, &raw, tp, time); + + pointer_notify_motion(&tp->device->base, time, &delta, &raw); + + fsm.last_motion_time = time; + fsm.continuous_motion_count++; +} + +static uint32_t +detect_touch_edge(const struct tp_dispatch *tp, const struct tp_touch *t) +{ + uint32_t edge = EDGE_NONE; + struct phys_coords mm = { EDGE_MOTION_CONFIG_EDGE_THRESHOLD_MM, + EDGE_MOTION_CONFIG_EDGE_THRESHOLD_MM }; + struct device_coords threshold = evdev_device_mm_to_units(tp->device, &mm); + + if (t->point.x < threshold.x) + edge |= EDGE_LEFT; + if (t->point.x > tp->device->abs.absinfo_x->maximum - threshold.x) + edge |= EDGE_RIGHT; + if (t->point.y < threshold.y) + edge |= EDGE_TOP; + if (t->point.y > tp->device->abs.absinfo_y->maximum - threshold.y) + edge |= EDGE_BOTTOM; + + return edge; +} + +static void +tp_edge_motion_handle_timeout(usec_t now, void *data) +{ + struct edge_motion_fsm *fsm_ptr = data; + + if (fsm_ptr->current_state != STATE_EDGE_MOTION) + return; + + inject_accumulated_motion(fsm_ptr->tp, now); + libinput_timer_set(&fsm_ptr->timer, usec_add(now, usec_from_uint64_t(EDGE_MOTION_CONFIG_MIN_INTERVAL_US))); +} + +void +tp_edge_motion_init(struct tp_dispatch *tp) +{ + if (fsm.tp) + return; + + memset(&fsm, 0, sizeof(fsm)); + fsm.current_state = STATE_IDLE; + fsm.tp = tp; + + libinput_timer_init(&fsm.timer, + tp_libinput_context(tp), + "edge drag motion", + tp_edge_motion_handle_timeout, + &fsm); +} + +void +tp_edge_motion_cleanup(void) +{ + if (fsm.tp) + libinput_timer_destroy(&fsm.timer); + + memset(&fsm, 0, sizeof(fsm)); + fsm.current_state = STATE_IDLE; +} + +int +tp_edge_motion_handle_drag_state(struct tp_dispatch *tp, usec_t time) +{ + if (!fsm.tp) + tp_edge_motion_init(tp); + + bool drag_active = false; + + switch (tp->tap.state) { + case TAP_STATE_1FGTAP_DRAGGING: + case TAP_STATE_1FGTAP_DRAGGING_2: + case TAP_STATE_1FGTAP_DRAGGING_WAIT: + case TAP_STATE_1FGTAP_DRAGGING_OR_TAP: + case TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP: + drag_active = true; + break; + default: + drag_active = false; + break; + } + + uint32_t detected_edge = EDGE_NONE; + struct tp_touch *t; + + if (drag_active) { + tp_for_each_touch(tp, t) { + if (t->state != TOUCH_NONE && t->state != TOUCH_HOVERING) { + detected_edge = detect_touch_edge(tp, t); + break; + } + } + } + + enum edge_motion_state next_state = STATE_IDLE; + if (drag_active) { + next_state = (detected_edge != EDGE_NONE) ? STATE_EDGE_MOTION + : STATE_DRAG_ACTIVE; + } + + if (next_state != fsm.current_state) { + fsm.current_state = next_state; + fsm.current_edge = detected_edge; + + if (fsm.current_state != STATE_EDGE_MOTION) + fsm.continuous_motion_count = 0; + + switch (fsm.current_state) { + case STATE_IDLE: + case STATE_DRAG_ACTIVE: + libinput_timer_cancel(&fsm.timer); + break; + + case STATE_EDGE_MOTION: + calculate_motion_vector(fsm.current_edge, + &fsm.motion_dx, + &fsm.motion_dy); + fsm.last_motion_time = time; + tp_edge_motion_handle_timeout(time, &fsm); + break; + } + } else if (fsm.current_state == STATE_EDGE_MOTION && + detected_edge != fsm.current_edge) { + fsm.current_edge = detected_edge; + calculate_motion_vector(fsm.current_edge, + &fsm.motion_dx, + &fsm.motion_dy); + } + + return (fsm.current_state == STATE_EDGE_MOTION); +} diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index 596ba944..ebde0ab8 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -1292,6 +1292,9 @@ tp_tap_handle_state(struct tp_dispatch *tp, usec_t time) } } + /* Log 1-finger drag state changes */ + filter_motion = tp_edge_motion_handle_drag_state(tp, time); + /** * In any state where motion exceeding the move threshold would * move to the next state, filter that motion until we actually @@ -1594,6 +1597,7 @@ void tp_remove_tap(struct tp_dispatch *tp) { libinput_timer_cancel(&tp->tap.timer); + tp_edge_motion_cleanup(); } void diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 7e85baf7..6331d2d5 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -140,11 +140,13 @@ enum tp_tap_touch_state { TAP_TOUCH_STATE_DEAD, /**< exceeded motion/timeout */ }; -/* For edge scrolling, so we only care about right and bottom */ +/* For edge scrolling, so we only care about right and bottom. For edge motion, we require all four edges */ enum tp_edge { EDGE_NONE = 0, EDGE_RIGHT = bit(0), EDGE_BOTTOM = bit(1), + EDGE_LEFT = bit(2), + EDGE_TOP = bit(3), }; enum tp_edge_scroll_touch_state { @@ -421,6 +423,8 @@ struct tp_dispatch { enum libinput_config_scroll_method method; int32_t right_edge; /* in device coordinates */ int32_t bottom_edge; /* in device coordinates */ + int32_t left_edge; /* in device coordinates */ + int32_t upper_edge; /* in device coordinates */ struct { bool h, v; } active; @@ -721,6 +725,12 @@ tp_edge_scroll_touch_active(const struct tp_dispatch *tp, const struct tp_touch uint32_t tp_touch_get_edge(const struct tp_dispatch *tp, const struct tp_touch *t); +int +tp_edge_motion_handle_drag_state(struct tp_dispatch *tp, usec_t time); + +void +tp_edge_motion_cleanup(void); + void tp_init_gesture(struct tp_dispatch *tp); From 07337e906b4c941392dd7830df4bd7d9636110b6 Mon Sep 17 00:00:00 2001 From: suraj Date: Wed, 4 Mar 2026 21:07:37 +0530 Subject: [PATCH 2/4] style: apply clang-format --- src/evdev-mt-touchpad-edge-motion.c | 8 +++++--- src/evdev-mt-touchpad.h | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/evdev-mt-touchpad-edge-motion.c b/src/evdev-mt-touchpad-edge-motion.c index 2a40b570..4ae28ab5 100644 --- a/src/evdev-mt-touchpad-edge-motion.c +++ b/src/evdev-mt-touchpad-edge-motion.c @@ -95,8 +95,8 @@ inject_accumulated_motion(struct tp_dispatch *tp, usec_t time) } usec_t time_since_last = usec_sub(time, fsm.last_motion_time); - double dist_mm = - EDGE_MOTION_CONFIG_SPEED_MM_S * ((double)usec_as_uint64_t(time_since_last) / 1000000.0); + double dist_mm = EDGE_MOTION_CONFIG_SPEED_MM_S * + ((double)usec_as_uint64_t(time_since_last) / 1000000.0); if (dist_mm < 0.001) return; @@ -144,7 +144,9 @@ tp_edge_motion_handle_timeout(usec_t now, void *data) return; inject_accumulated_motion(fsm_ptr->tp, now); - libinput_timer_set(&fsm_ptr->timer, usec_add(now, usec_from_uint64_t(EDGE_MOTION_CONFIG_MIN_INTERVAL_US))); + libinput_timer_set( + &fsm_ptr->timer, + usec_add(now, usec_from_uint64_t(EDGE_MOTION_CONFIG_MIN_INTERVAL_US))); } void diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 6331d2d5..059fac3e 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -140,7 +140,8 @@ enum tp_tap_touch_state { TAP_TOUCH_STATE_DEAD, /**< exceeded motion/timeout */ }; -/* For edge scrolling, so we only care about right and bottom. For edge motion, we require all four edges */ +/* For edge scrolling, so we only care about right and bottom. For edge motion, we + * require all four edges */ enum tp_edge { EDGE_NONE = 0, EDGE_RIGHT = bit(0), From 7c5cdadcda8daf8cbd422ca0b266d4d36e8f5f37 Mon Sep 17 00:00:00 2001 From: suraj Date: Tue, 10 Mar 2026 22:41:59 +0530 Subject: [PATCH 3/4] fsm now per device instead of a global struct --- src/evdev-mt-touchpad-edge-motion.c | 124 +++++++++++----------------- src/evdev-mt-touchpad-tap.c | 3 +- src/evdev-mt-touchpad.c | 2 + src/evdev-mt-touchpad.h | 26 +++++- 4 files changed, 77 insertions(+), 78 deletions(-) diff --git a/src/evdev-mt-touchpad-edge-motion.c b/src/evdev-mt-touchpad-edge-motion.c index 4ae28ab5..573d2cd2 100644 --- a/src/evdev-mt-touchpad-edge-motion.c +++ b/src/evdev-mt-touchpad-edge-motion.c @@ -38,27 +38,6 @@ #include "evdev-mt-touchpad.h" -void -tp_edge_motion_init(struct tp_dispatch *tp); - -enum edge_motion_state { STATE_IDLE, STATE_DRAG_ACTIVE, STATE_EDGE_MOTION }; - -struct edge_motion_fsm { - enum edge_motion_state current_state; - usec_t last_motion_time; - uint32_t current_edge; - double motion_dx; - double motion_dy; - uint32_t continuous_motion_count; - struct tp_dispatch *tp; - struct libinput_timer timer; -}; - -static struct edge_motion_fsm fsm = { - .current_state = STATE_IDLE, - .tp = NULL, -}; - #define EDGE_MOTION_CONFIG_SPEED_MM_S 70.0 #define EDGE_MOTION_CONFIG_MIN_INTERVAL_US 8000 #define EDGE_MOTION_CONFIG_EDGE_THRESHOLD_MM 5.0 @@ -89,12 +68,12 @@ calculate_motion_vector(uint32_t edge, double *dx, double *dy) static void inject_accumulated_motion(struct tp_dispatch *tp, usec_t time) { - if (usec_is_zero(fsm.last_motion_time)) { - fsm.last_motion_time = time; + if (usec_is_zero(tp->edge_motion.last_motion_time)) { + tp->edge_motion.last_motion_time = time; return; } - usec_t time_since_last = usec_sub(time, fsm.last_motion_time); + usec_t time_since_last = usec_sub(time, tp->edge_motion.last_motion_time); double dist_mm = EDGE_MOTION_CONFIG_SPEED_MM_S * ((double)usec_as_uint64_t(time_since_last) / 1000000.0); @@ -102,8 +81,8 @@ inject_accumulated_motion(struct tp_dispatch *tp, usec_t time) return; struct device_float_coords raw = { - .x = fsm.motion_dx * dist_mm * tp->accel.x_scale_coeff, - .y = fsm.motion_dy * dist_mm * tp->accel.y_scale_coeff + .x = tp->edge_motion.motion_dx * dist_mm * tp->accel.x_scale_coeff, + .y = tp->edge_motion.motion_dy * dist_mm * tp->accel.y_scale_coeff }; struct normalized_coords delta = @@ -111,8 +90,8 @@ inject_accumulated_motion(struct tp_dispatch *tp, usec_t time) pointer_notify_motion(&tp->device->base, time, &delta, &raw); - fsm.last_motion_time = time; - fsm.continuous_motion_count++; + tp->edge_motion.last_motion_time = time; + tp->edge_motion.continuous_motion_count++; } static uint32_t @@ -138,50 +117,44 @@ detect_touch_edge(const struct tp_dispatch *tp, const struct tp_touch *t) static void tp_edge_motion_handle_timeout(usec_t now, void *data) { - struct edge_motion_fsm *fsm_ptr = data; + struct tp_dispatch *tp = data; - if (fsm_ptr->current_state != STATE_EDGE_MOTION) + if (tp->edge_motion.state != EDGE_MOTION_STATE_EDGE_MOTION) return; - inject_accumulated_motion(fsm_ptr->tp, now); + inject_accumulated_motion(tp, now); libinput_timer_set( - &fsm_ptr->timer, + &tp->edge_motion.timer, usec_add(now, usec_from_uint64_t(EDGE_MOTION_CONFIG_MIN_INTERVAL_US))); } void -tp_edge_motion_init(struct tp_dispatch *tp) +tp_init_edge_motion(struct tp_dispatch *tp) { - if (fsm.tp) - return; + tp->edge_motion.state = EDGE_MOTION_STATE_IDLE; + tp->edge_motion.last_motion_time = usec_from_uint64_t(0); + tp->edge_motion.current_edge = EDGE_NONE; + tp->edge_motion.motion_dx = 0.0; + tp->edge_motion.motion_dy = 0.0; + tp->edge_motion.continuous_motion_count = 0; - memset(&fsm, 0, sizeof(fsm)); - fsm.current_state = STATE_IDLE; - fsm.tp = tp; - - libinput_timer_init(&fsm.timer, + libinput_timer_init(&tp->edge_motion.timer, tp_libinput_context(tp), "edge drag motion", tp_edge_motion_handle_timeout, - &fsm); + tp); } void -tp_edge_motion_cleanup(void) +tp_remove_edge_motion(struct tp_dispatch *tp) { - if (fsm.tp) - libinput_timer_destroy(&fsm.timer); - - memset(&fsm, 0, sizeof(fsm)); - fsm.current_state = STATE_IDLE; + libinput_timer_cancel(&tp->edge_motion.timer); + libinput_timer_destroy(&tp->edge_motion.timer); } int tp_edge_motion_handle_drag_state(struct tp_dispatch *tp, usec_t time) { - if (!fsm.tp) - tp_edge_motion_init(tp); - bool drag_active = false; switch (tp->tap.state) { @@ -209,40 +182,41 @@ tp_edge_motion_handle_drag_state(struct tp_dispatch *tp, usec_t time) } } - enum edge_motion_state next_state = STATE_IDLE; + enum tp_edge_motion_state next_state = EDGE_MOTION_STATE_IDLE; if (drag_active) { - next_state = (detected_edge != EDGE_NONE) ? STATE_EDGE_MOTION - : STATE_DRAG_ACTIVE; + next_state = (detected_edge != EDGE_NONE) ? EDGE_MOTION_STATE_EDGE_MOTION + : EDGE_MOTION_STATE_DRAG_ACTIVE; } - if (next_state != fsm.current_state) { - fsm.current_state = next_state; - fsm.current_edge = detected_edge; + if (next_state != tp->edge_motion.state) { + tp->edge_motion.state = next_state; + tp->edge_motion.current_edge = detected_edge; - if (fsm.current_state != STATE_EDGE_MOTION) - fsm.continuous_motion_count = 0; + if (tp->edge_motion.state != EDGE_MOTION_STATE_EDGE_MOTION) + tp->edge_motion.continuous_motion_count = 0; - switch (fsm.current_state) { - case STATE_IDLE: - case STATE_DRAG_ACTIVE: - libinput_timer_cancel(&fsm.timer); + switch (tp->edge_motion.state) { + case EDGE_MOTION_STATE_IDLE: + case EDGE_MOTION_STATE_DRAG_ACTIVE: + libinput_timer_cancel(&tp->edge_motion.timer); + tp->edge_motion.current_edge = EDGE_NONE; break; - case STATE_EDGE_MOTION: - calculate_motion_vector(fsm.current_edge, - &fsm.motion_dx, - &fsm.motion_dy); - fsm.last_motion_time = time; - tp_edge_motion_handle_timeout(time, &fsm); + case EDGE_MOTION_STATE_EDGE_MOTION: + calculate_motion_vector(tp->edge_motion.current_edge, + &tp->edge_motion.motion_dx, + &tp->edge_motion.motion_dy); + tp->edge_motion.last_motion_time = time; + tp_edge_motion_handle_timeout(time, tp); break; } - } else if (fsm.current_state == STATE_EDGE_MOTION && - detected_edge != fsm.current_edge) { - fsm.current_edge = detected_edge; - calculate_motion_vector(fsm.current_edge, - &fsm.motion_dx, - &fsm.motion_dy); + } else if (tp->edge_motion.state == EDGE_MOTION_STATE_EDGE_MOTION && + detected_edge != tp->edge_motion.current_edge) { + tp->edge_motion.current_edge = detected_edge; + calculate_motion_vector(tp->edge_motion.current_edge, + &tp->edge_motion.motion_dx, + &tp->edge_motion.motion_dy); } - return (fsm.current_state == STATE_EDGE_MOTION); + return (tp->edge_motion.state == EDGE_MOTION_STATE_EDGE_MOTION); } diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index ebde0ab8..5449ecd8 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -1293,7 +1293,7 @@ tp_tap_handle_state(struct tp_dispatch *tp, usec_t time) } /* Log 1-finger drag state changes */ - filter_motion = tp_edge_motion_handle_drag_state(tp, time); + filter_motion |= tp_edge_motion_handle_drag_state(tp, time); /** * In any state where motion exceeding the move threshold would @@ -1597,7 +1597,6 @@ void tp_remove_tap(struct tp_dispatch *tp) { libinput_timer_cancel(&tp->tap.timer); - tp_edge_motion_cleanup(); } void diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index e60ced9b..247cb695 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -1960,6 +1960,7 @@ tp_interface_remove(struct evdev_dispatch *dispatch) tp_remove_buttons(tp); tp_remove_sendevents(tp); tp_remove_edge_scroll(tp); + tp_remove_edge_motion(tp); tp_remove_gesture(tp); } @@ -3783,6 +3784,7 @@ tp_init(struct tp_dispatch *tp, struct evdev_device *device) tp_init_palmdetect(tp, device); tp_init_sendevents(tp, device); tp_init_scroll(tp, device); + tp_init_edge_motion(tp); tp_init_gesture(tp); tp_init_thumb(tp); diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 059fac3e..d86ee7a7 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -140,6 +140,12 @@ enum tp_tap_touch_state { TAP_TOUCH_STATE_DEAD, /**< exceeded motion/timeout */ }; +enum tp_edge_motion_state { + EDGE_MOTION_STATE_IDLE, + EDGE_MOTION_STATE_DRAG_ACTIVE, + EDGE_MOTION_STATE_EDGE_MOTION, +}; + /* For edge scrolling, so we only care about right and bottom. For edge motion, we * require all four edges */ enum tp_edge { @@ -565,6 +571,21 @@ struct tp_dispatch { struct evdev_device *tablet_device; bool tablet_left_handed_state; } left_handed; + + struct { + enum tp_edge_motion_state state; + + usec_t last_motion_time; + + uint32_t current_edge; + + double motion_dx; + double motion_dy; + + uint32_t continuous_motion_count; + + struct libinput_timer timer; + } edge_motion; }; static inline struct tp_dispatch * @@ -726,11 +747,14 @@ tp_edge_scroll_touch_active(const struct tp_dispatch *tp, const struct tp_touch uint32_t tp_touch_get_edge(const struct tp_dispatch *tp, const struct tp_touch *t); +void +tp_init_edge_motion(struct tp_dispatch *tp); + int tp_edge_motion_handle_drag_state(struct tp_dispatch *tp, usec_t time); void -tp_edge_motion_cleanup(void); +tp_remove_edge_motion(struct tp_dispatch *tp); void tp_init_gesture(struct tp_dispatch *tp); From 70c6df12a58f81e53d1b22cd1f88ffe7c734e0e1 Mon Sep 17 00:00:00 2001 From: suraj Date: Wed, 11 Mar 2026 21:53:36 +0530 Subject: [PATCH 4/4] finished changes except the for_each_touch function suggestion --- src/evdev-mt-touchpad-edge-motion.c | 48 ++++++++++++++--------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/evdev-mt-touchpad-edge-motion.c b/src/evdev-mt-touchpad-edge-motion.c index 573d2cd2..29ec128d 100644 --- a/src/evdev-mt-touchpad-edge-motion.c +++ b/src/evdev-mt-touchpad-edge-motion.c @@ -1,5 +1,5 @@ /* - * Copyright © 2014-2015 Red Hat, Inc. + * Copyright © 2014-2015 Nobody, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -58,13 +58,24 @@ calculate_motion_vector(uint32_t edge, double *dx, double *dy) else if (edge & EDGE_BOTTOM) *dy = 1.0; - double mag = sqrt((*dx) * (*dx) + (*dy) * (*dy)); + double mag = hypot(*dx, *dy); if (mag > 0) { *dx /= mag; *dy /= mag; } } +static struct device_float_coords +edge_motion_calculate_raw(struct tp_dispatch *tp, double dx, double dy, double dist_mm) +{ + struct device_float_coords raw = { + .x = dx * dist_mm * tp->accel.x_scale_coeff, + .y = dy * dist_mm * tp->accel.y_scale_coeff, + }; + + return raw; +} + static void inject_accumulated_motion(struct tp_dispatch *tp, usec_t time) { @@ -74,16 +85,17 @@ inject_accumulated_motion(struct tp_dispatch *tp, usec_t time) } usec_t time_since_last = usec_sub(time, tp->edge_motion.last_motion_time); - double dist_mm = EDGE_MOTION_CONFIG_SPEED_MM_S * - ((double)usec_as_uint64_t(time_since_last) / 1000000.0); + double dist_mm = + EDGE_MOTION_CONFIG_SPEED_MM_S * usec_to_seconds(time_since_last); if (dist_mm < 0.001) return; - struct device_float_coords raw = { - .x = tp->edge_motion.motion_dx * dist_mm * tp->accel.x_scale_coeff, - .y = tp->edge_motion.motion_dy * dist_mm * tp->accel.y_scale_coeff - }; + struct device_float_coords raw = + edge_motion_calculate_raw(tp, + tp->edge_motion.motion_dx, + tp->edge_motion.motion_dy, + dist_mm); struct normalized_coords delta = filter_dispatch(tp->device->pointer.filter, &raw, tp, time); @@ -155,20 +167,7 @@ tp_remove_edge_motion(struct tp_dispatch *tp) int tp_edge_motion_handle_drag_state(struct tp_dispatch *tp, usec_t time) { - bool drag_active = false; - - switch (tp->tap.state) { - case TAP_STATE_1FGTAP_DRAGGING: - case TAP_STATE_1FGTAP_DRAGGING_2: - case TAP_STATE_1FGTAP_DRAGGING_WAIT: - case TAP_STATE_1FGTAP_DRAGGING_OR_TAP: - case TAP_STATE_1FGTAP_DRAGGING_OR_DOUBLETAP: - drag_active = true; - break; - default: - drag_active = false; - break; - } + bool drag_active = tp_tap_dragging(tp); uint32_t detected_edge = EDGE_NONE; struct tp_touch *t; @@ -184,8 +183,9 @@ tp_edge_motion_handle_drag_state(struct tp_dispatch *tp, usec_t time) enum tp_edge_motion_state next_state = EDGE_MOTION_STATE_IDLE; if (drag_active) { - next_state = (detected_edge != EDGE_NONE) ? EDGE_MOTION_STATE_EDGE_MOTION - : EDGE_MOTION_STATE_DRAG_ACTIVE; + next_state = (detected_edge != EDGE_NONE) + ? EDGE_MOTION_STATE_EDGE_MOTION + : EDGE_MOTION_STATE_DRAG_ACTIVE; } if (next_state != tp->edge_motion.state) {