diff --git a/src/evdev-mt-touchpad-edge-scroll.c b/src/evdev-mt-touchpad-edge-scroll.c index 28f29c2f..a7936b61 100644 --- a/src/evdev-mt-touchpad-edge-scroll.c +++ b/src/evdev-mt-touchpad-edge-scroll.c @@ -34,8 +34,7 @@ avoid accidentally locking in scrolling mode when trying to use the entire touchpad to move the pointer. The user can wait for the timeout to trigger to do a small scroll. */ -/* In mm for touchpads with valid resolution, see tp_init_accel() */ -#define DEFAULT_SCROLL_THRESHOLD 10.0 +#define DEFAULT_SCROLL_THRESHOLD TP_MM_TO_DPI_NORMALIZED(5) enum scroll_event { SCROLL_EVENT_TOUCH, @@ -74,15 +73,15 @@ tp_edge_scroll_set_state(struct tp_dispatch *tp, switch (state) { case EDGE_SCROLL_TOUCH_STATE_NONE: t->scroll.edge = EDGE_NONE; - t->scroll.threshold = DEFAULT_SCROLL_THRESHOLD; break; case EDGE_SCROLL_TOUCH_STATE_EDGE_NEW: t->scroll.edge = tp_touch_get_edge(tp, t); + t->scroll.initial_x = t->x; + t->scroll.initial_y = t->y; libinput_timer_set(&t->scroll.timer, t->millis + DEFAULT_SCROLL_LOCK_TIMEOUT); break; case EDGE_SCROLL_TOUCH_STATE_EDGE: - t->scroll.threshold = 0.01; /* Do not allow 0.0 events */ break; case EDGE_SCROLL_TOUCH_STATE_AREA: t->scroll.edge = EDGE_NONE; @@ -264,7 +263,6 @@ tp_edge_scroll_init(struct tp_dispatch *tp, struct evdev_device *device) tp_for_each_touch(tp, t) { t->scroll.direction = -1; - t->scroll.threshold = DEFAULT_SCROLL_THRESHOLD; libinput_timer_init(&t->scroll.timer, device->base.seat->libinput, tp_edge_scroll_handle_timeout, t); @@ -315,6 +313,7 @@ tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time) struct tp_touch *t; enum libinput_pointer_axis axis; double dx, dy, *delta; + double initial_dx, initial_dy, *initial_delta; if (tp->scroll.method != LIBINPUT_CONFIG_SCROLL_EDGE) return 0; @@ -338,10 +337,12 @@ tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time) case EDGE_RIGHT: axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL; delta = &dy; + initial_delta = &initial_dy; break; case EDGE_BOTTOM: axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL; delta = &dx; + initial_delta = &initial_dx; break; default: /* EDGE_RIGHT | EDGE_BOTTOM */ continue; /* Don't know direction yet, skip */ @@ -350,7 +351,32 @@ tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time) tp_get_delta(t, &dx, &dy); tp_filter_motion(tp, &dx, &dy, NULL, NULL, time); - if (fabs(*delta) < t->scroll.threshold) + switch (t->scroll.edge_state) { + case EDGE_SCROLL_TOUCH_STATE_NONE: + case EDGE_SCROLL_TOUCH_STATE_AREA: + log_bug_libinput(device->seat->libinput, + "unexpected scroll state %d\n", + t->scroll.edge_state); + break; + case EDGE_SCROLL_TOUCH_STATE_EDGE_NEW: + initial_dx = t->x - t->scroll.initial_x; + initial_dy = t->y - t->scroll.initial_y; + tp_normalize_delta(tp, + &initial_dx, + &initial_dy); + if (fabs(*initial_delta) < DEFAULT_SCROLL_THRESHOLD) { + dx = 0.0; + dy = 0.0; + } else { + dx = initial_dx; + dy = initial_dy; + } + break; + case EDGE_SCROLL_TOUCH_STATE_EDGE: + break; + } + + if (*delta == 0.0) continue; pointer_notify_axis(device, time, diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index 228eb842..c0475080 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -37,7 +37,7 @@ #define CASE_RETURN_STRING(a) case a: return #a; #define DEFAULT_TAP_TIMEOUT_PERIOD 180 -#define DEFAULT_TAP_MOVE_THRESHOLD 30 +#define DEFAULT_TAP_MOVE_THRESHOLD TP_MM_TO_DPI_NORMALIZED(3) enum tap_event { TAP_EVENT_TOUCH = 12, @@ -527,12 +527,15 @@ tp_tap_handle_event(struct tp_dispatch *tp, } static bool -tp_tap_exceeds_motion_threshold(struct tp_dispatch *tp, struct tp_touch *t) +tp_tap_exceeds_motion_threshold(struct tp_dispatch *tp, + struct tp_touch *t) { int threshold = DEFAULT_TAP_MOVE_THRESHOLD; double dx, dy; - tp_get_delta(t, &dx, &dy); + dx = abs(t->tap.initial_x - t->x); + dy = abs(t->tap.initial_y - t->y); + tp_normalize_delta(tp, &dx, &dy); return dx * dx + dy * dy > threshold * threshold; } @@ -568,6 +571,8 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time) if (t->state == TOUCH_BEGIN) { t->tap.state = TAP_TOUCH_STATE_TOUCH; + t->tap.initial_x = t->x; + t->tap.initial_y = t->y; tp_tap_handle_event(tp, t, TAP_EVENT_TOUCH, time); } else if (t->state == TOUCH_END) { tp_tap_handle_event(tp, t, TAP_EVENT_RELEASE, time); diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index b3a8b08c..274347fe 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -64,8 +64,8 @@ tp_filter_motion(struct tp_dispatch *tp, { struct motion_params motion; - motion.dx = *dx * tp->accel.x_scale_coeff; - motion.dy = *dy * tp->accel.y_scale_coeff; + motion.dx = *dx; + motion.dy = *dy; if (dx_unaccel) *dx_unaccel = motion.dx; @@ -269,6 +269,7 @@ tp_get_delta(struct tp_touch *t, double *dx, double *dy) tp_motion_history_offset(t, 1)->y, tp_motion_history_offset(t, 2)->y, tp_motion_history_offset(t, 3)->y); + tp_normalize_delta(t->tp, dx, dy); } static void @@ -994,9 +995,8 @@ tp_init_accel(struct tp_dispatch *tp, double diagonal) fixed in the actual filter code. */ { - const double MAGIC = 0.4; - tp->accel.x_scale_coeff *= MAGIC; - tp->accel.y_scale_coeff *= MAGIC; + tp->accel.x_scale_coeff *= TP_MAGIC_SLOWDOWN; + tp->accel.y_scale_coeff *= TP_MAGIC_SLOWDOWN; } } else { /* diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index f04cc112..aa6de69c 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -34,6 +34,11 @@ #define VENDOR_ID_APPLE 0x5ac +/* Touchpad slowdown factor, see the FIXME in tp_init_accel() */ +#define TP_MAGIC_SLOWDOWN 0.4 +/* Convert mm to a distance normalized to DEFAULT_MOUSE_DPI */ +#define TP_MM_TO_DPI_NORMALIZED(mm) (DEFAULT_MOUSE_DPI/25.4 * TP_MAGIC_SLOWDOWN * mm) + enum touchpad_event { TOUCHPAD_EVENT_NONE = 0, TOUCHPAD_EVENT_MOTION = (1 << 0), @@ -127,8 +132,8 @@ struct tp_touch { enum touch_state state; bool has_ended; /* TRACKING_ID == -1 */ bool dirty; - int32_t x; - int32_t y; + int32_t x; /* in device coordinates */ + int32_t y; /* in device coordinates */ uint64_t millis; struct { @@ -138,8 +143,8 @@ struct tp_touch { } history; struct { - int32_t center_x; - int32_t center_y; + int32_t center_x; /* in device coordinates */ + int32_t center_y; /* in device coordinates */ } hysteresis; /* A pinned touchpoint is the one that pressed the physical button @@ -148,8 +153,8 @@ struct tp_touch { */ struct { bool is_pinned; - int32_t center_x; - int32_t center_y; + int32_t center_x; /* in device coordinates */ + int32_t center_y; /* in device coordinates */ } pinned; /* Software-button state and timeout if applicable */ @@ -162,19 +167,22 @@ struct tp_touch { struct { enum tp_tap_touch_state state; + int32_t initial_x, initial_y; /* in device coordinates */ } tap; struct { enum tp_edge_scroll_touch_state edge_state; uint32_t edge; int direction; - double threshold; struct libinput_timer timer; + int32_t initial_x; /* in device coordinates */ + int32_t initial_y; /* in device coordinates */ } scroll; struct { bool is_palm; - int32_t x, y; /* first coordinates if is_palm == true */ + int32_t x, y; /* first coordinates if is_palm == true, + in device coordinates */ uint32_t time; /* first timestamp if is_palm == true */ } palm; }; @@ -200,8 +208,8 @@ struct tp_dispatch { unsigned int fake_touches; struct { - int32_t margin_x; - int32_t margin_y; + int32_t margin_x; /* in device coordiantes */ + int32_t margin_y; /* in device coordiantes */ } hysteresis; struct { @@ -232,14 +240,14 @@ struct tp_dispatch { * The buttons are split according to the edge settings. */ struct { - int32_t top_edge; - int32_t rightbutton_left_edge; + int32_t top_edge; /* in device coordinates */ + int32_t rightbutton_left_edge; /* in device coordinates */ } bottom_area; struct { - int32_t bottom_edge; - int32_t rightbutton_left_edge; - int32_t leftbutton_right_edge; + int32_t bottom_edge; /* in device coordinates */ + int32_t rightbutton_left_edge; /* in device coordinates */ + int32_t leftbutton_right_edge; /* in device coordinates */ } top_area; struct evdev_device *trackpoint; @@ -251,8 +259,8 @@ struct tp_dispatch { struct { struct libinput_device_config_scroll_method config_method; enum libinput_config_scroll_method method; - int32_t right_edge; - int32_t bottom_edge; + int32_t right_edge; /* in device coordinates */ + int32_t bottom_edge; /* in device coordinates */ } scroll; enum touchpad_event queued; @@ -267,8 +275,8 @@ struct tp_dispatch { } tap; struct { - int32_t right_edge; - int32_t left_edge; + int32_t right_edge; /* in device coordinates */ + int32_t left_edge; /* in device coordinates */ } palm; struct { @@ -283,6 +291,13 @@ struct tp_dispatch { #define tp_for_each_touch(_tp, _t) \ for (unsigned int _i = 0; _i < (_tp)->ntouches && (_t = &(_tp)->touches[_i]); _i++) +static inline void +tp_normalize_delta(struct tp_dispatch *tp, double *dx, double *dy) +{ + *dx = *dx * tp->accel.x_scale_coeff; + *dy = *dy * tp->accel.y_scale_coeff; +} + void tp_get_delta(struct tp_touch *t, double *dx, double *dy); diff --git a/src/evdev.h b/src/evdev.h index 26f321ef..21867e0c 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -33,6 +33,9 @@ #include "libinput-private.h" #include "timer.h" +/* The HW DPI rate we normalize to before calculating pointer acceleration */ +#define DEFAULT_MOUSE_DPI 1000 + enum evdev_event_type { EVDEV_NONE, EVDEV_ABSOLUTE_TOUCH_DOWN, diff --git a/src/filter.h b/src/filter.h index 9f6223d2..9e903303 100644 --- a/src/filter.h +++ b/src/filter.h @@ -28,9 +28,6 @@ #include #include -/* The HW DPI rate we normalize to before calculating pointer acceleration */ -#define DEFAULT_MOUSE_DPI 1000 - struct motion_params { double dx, dy; /* in units/ms @ DEFAULT_MOUSE_DPI resolution */ }; diff --git a/test/litest.c b/test/litest.c index 9119ac0c..94646fa2 100644 --- a/test/litest.c +++ b/test/litest.c @@ -1517,6 +1517,12 @@ litest_timeout_finger_switch(void) msleep(120); } +void +litest_timeout_edgescroll(void) +{ + msleep(300); +} + void litest_push_event_frame(struct litest_device *dev) { diff --git a/test/litest.h b/test/litest.h index 07738007..8c609144 100644 --- a/test/litest.h +++ b/test/litest.h @@ -221,6 +221,7 @@ struct libevdev_uinput * litest_create_uinput_abs_device(const char *name, void litest_timeout_tap(void); void litest_timeout_softbuttons(void); void litest_timeout_buttonscroll(void); +void litest_timeout_edgescroll(void); void litest_timeout_finger_switch(void); void litest_push_event_frame(struct litest_device *dev); diff --git a/test/touchpad.c b/test/touchpad.c index 8077f8e3..ff4edb04 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -2057,7 +2057,7 @@ START_TEST(touchpad_edge_scroll) } END_TEST -START_TEST(touchpad_edge_scroll_slow_distance) +START_TEST(touchpad_edge_scroll_timeout) { struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; @@ -2067,6 +2067,10 @@ START_TEST(touchpad_edge_scroll_slow_distance) litest_drain_events(li); litest_touch_down(dev, 0, 99, 20); + libinput_dispatch(li); + litest_timeout_edgescroll(); + libinput_dispatch(li); + litest_touch_move_to(dev, 0, 99, 20, 99, 80, 60, 10); litest_touch_up(dev, 0); libinput_dispatch(li); @@ -2074,6 +2078,8 @@ START_TEST(touchpad_edge_scroll_slow_distance) event = libinput_get_event(li); ck_assert_notnull(event); + litest_wait_for_event_of_type(li, LIBINPUT_EVENT_POINTER_AXIS, -1); + while (libinput_next_event_type(li) != LIBINPUT_EVENT_NONE) { double axisval; ck_assert_int_eq(libinput_event_get_type(event), @@ -2105,10 +2111,10 @@ START_TEST(touchpad_edge_scroll_no_motion) litest_drain_events(li); - litest_touch_down(dev, 0, 99, 20); - litest_touch_move_to(dev, 0, 99, 20, 99, 60, 10, 0); + litest_touch_down(dev, 0, 99, 10); + litest_touch_move_to(dev, 0, 99, 10, 99, 70, 10, 0); /* moving outside -> no motion event */ - litest_touch_move_to(dev, 0, 99, 60, 20, 80, 10, 0); + litest_touch_move_to(dev, 0, 99, 70, 20, 80, 10, 0); /* moving down outside edge once scrolling had started -> scroll */ litest_touch_move_to(dev, 0, 20, 80, 40, 99, 10, 0); litest_touch_up(dev, 0); @@ -2570,8 +2576,8 @@ START_TEST(touchpad_left_handed_tapping_2fg) litest_touch_down(dev, 0, 50, 50); litest_touch_down(dev, 1, 70, 50); - litest_touch_up(dev, 0); litest_touch_up(dev, 1); + litest_touch_up(dev, 0); libinput_dispatch(li); litest_timeout_tap(); @@ -3356,7 +3362,7 @@ int main(int argc, char **argv) { litest_add("touchpad:tap", touchpad_2fg_tap_n_drag, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add("touchpad:tap", touchpad_2fg_tap_n_drag_3fg_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_APPLE_CLICKPAD); litest_add("touchpad:tap", touchpad_2fg_tap_n_drag_3fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); - litest_add("touchpad:tap", touchpad_2fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("touchpad:tap", touchpad_2fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); litest_add("touchpad:tap", touchpad_2fg_tap_inverted, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add("touchpad:tap", touchpad_1fg_tap_click, LITEST_TOUCHPAD|LITEST_BUTTON, LITEST_CLICKPAD); litest_add("touchpad:tap", touchpad_2fg_tap_click, LITEST_TOUCHPAD|LITEST_BUTTON, LITEST_SINGLE_TOUCH|LITEST_CLICKPAD); @@ -3427,7 +3433,7 @@ int main(int argc, char **argv) { litest_add("touchpad:scroll", touchpad_edge_scroll, LITEST_TOUCHPAD|LITEST_SINGLE_TOUCH, LITEST_ANY); litest_add("touchpad:scroll", touchpad_edge_scroll_no_motion, LITEST_TOUCHPAD|LITEST_SINGLE_TOUCH, LITEST_ANY); litest_add("touchpad:scroll", touchpad_edge_scroll_no_edge_after_motion, LITEST_TOUCHPAD|LITEST_SINGLE_TOUCH, LITEST_ANY); - litest_add("touchpad:scroll", touchpad_edge_scroll_slow_distance, LITEST_TOUCHPAD|LITEST_SINGLE_TOUCH, LITEST_ANY); + litest_add("touchpad:scroll", touchpad_edge_scroll_timeout, LITEST_TOUCHPAD|LITEST_SINGLE_TOUCH, LITEST_ANY); litest_add("touchpad:scroll", touchpad_edge_scroll_source, LITEST_TOUCHPAD|LITEST_SINGLE_TOUCH, LITEST_ANY); litest_add("touchpad:palm", touchpad_palm_detect_at_edge, LITEST_TOUCHPAD, LITEST_ANY);