From 9d9abc12d407a7776fbd6a60880ee38115b5835f Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Jun 16 2015 03:36:06 +0000 Subject: Avoid erroneous finger movement after a physical click (#1230441) --- diff --git a/0001-touchpad-fix-pinned-finger-drifting.patch b/0001-touchpad-fix-pinned-finger-drifting.patch new file mode 100644 index 0000000..9b5af82 --- /dev/null +++ b/0001-touchpad-fix-pinned-finger-drifting.patch @@ -0,0 +1,32 @@ +From b48ecd186d8fb707e89bf04036a48600dc49125f Mon Sep 17 00:00:00 2001 +From: Peter Hutterer +Date: Fri, 12 Jun 2015 17:24:33 +1000 +Subject: [PATCH libinput] touchpad: fix pinned finger drifting + +This caused the finger to be unpinned on the first motion event after the +click, effectively disabling this feature. + +Signed-off-by: Peter Hutterer +Reviewed-by: Hans de Goede +--- + src/evdev-mt-touchpad.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c +index c82d733..ce79530 100644 +--- a/src/evdev-mt-touchpad.c ++++ b/src/evdev-mt-touchpad.c +@@ -440,8 +440,8 @@ tp_unpin_finger(struct tp_dispatch *tp, struct tp_touch *t) + } + + /* The finger may slowly drift, adjust the center */ +- t->pinned.center.x = t->point.x + t->pinned.center.x / 2; +- t->pinned.center.y = t->point.y + t->pinned.center.y / 2; ++ t->pinned.center.x = (t->point.x + t->pinned.center.x)/2; ++ t->pinned.center.y = (t->point.y + t->pinned.center.y)/2; + } + + static void +-- +2.4.3 + diff --git a/0001-touchpad-set-the-finger-pin-distance-to-5mm-where-po.patch b/0001-touchpad-set-the-finger-pin-distance-to-5mm-where-po.patch new file mode 100644 index 0000000..2257a8e --- /dev/null +++ b/0001-touchpad-set-the-finger-pin-distance-to-5mm-where-po.patch @@ -0,0 +1,194 @@ +From 8025b374d564f4a30b089e5cf6fd65e0c6af8da2 Mon Sep 17 00:00:00 2001 +From: Peter Hutterer +Date: Fri, 12 Jun 2015 17:29:41 +1000 +Subject: [PATCH libinput] touchpad: set the finger pin distance to 5mm where + possible + +On touchpads with resolutions, use a 5mm motion threshold before we unpin the +finger (allow motion events while a clickpad button is down). This should +remove any erroneous finger movements while clicking, at the cost of having to +move the finger a bit more for a single-finger click-and-drag (use two fingers +already!) + +And drop the finger drifting, it was per-event based rather than time-based. +So unless the motion threshold was hit in a single event it was possible to +move the finger around the whole touchpad without ever unpinning it. + +Drop the finger drifting altogether, if the touchpad drifts by more than 5mm +we have other issues. + +https://bugzilla.redhat.com/show_bug.cgi?id=1230462 + +Signed-off-by: Peter Hutterer +Reviewed-by: Hans de Goede +--- + src/evdev-mt-touchpad-buttons.c | 19 ++++++++++------ + src/evdev-mt-touchpad.c | 10 ++++----- + src/evdev-mt-touchpad.h | 5 ++++- + src/libinput-util.h | 6 ++++++ + test/touchpad.c | 48 +++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 75 insertions(+), 13 deletions(-) + +diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c +index 5786ea8..eb0ddcb 100644 +--- a/src/evdev-mt-touchpad-buttons.c ++++ b/src/evdev-mt-touchpad-buttons.c +@@ -31,7 +31,6 @@ + + #include "evdev-mt-touchpad.h" + +-#define DEFAULT_BUTTON_MOTION_THRESHOLD 0.02 /* 2% of size */ + #define DEFAULT_BUTTON_ENTER_TIMEOUT 100 /* ms */ + #define DEFAULT_BUTTON_LEAVE_TIMEOUT 300 /* ms */ + +@@ -709,11 +708,19 @@ tp_init_buttons(struct tp_dispatch *tp, + absinfo_x = device->abs.absinfo_x; + absinfo_y = device->abs.absinfo_y; + +- width = abs(absinfo_x->maximum - absinfo_x->minimum); +- height = abs(absinfo_y->maximum - absinfo_y->minimum); +- diagonal = sqrt(width*width + height*height); +- +- tp->buttons.motion_dist = diagonal * DEFAULT_BUTTON_MOTION_THRESHOLD; ++ /* pinned-finger motion threshold, see tp_unpin_finger. ++ The MAGIC for resolution-less touchpads ends up as 2% of the diagonal */ ++ if (device->abs.fake_resolution) { ++ const int BUTTON_MOTION_MAGIC = 0.007; ++ width = abs(absinfo_x->maximum - absinfo_x->minimum); ++ height = abs(absinfo_y->maximum - absinfo_y->minimum); ++ diagonal = sqrt(width*width + height*height); ++ tp->buttons.motion_dist.x_scale_coeff = diagonal * BUTTON_MOTION_MAGIC; ++ tp->buttons.motion_dist.y_scale_coeff = diagonal * BUTTON_MOTION_MAGIC; ++ } else { ++ tp->buttons.motion_dist.x_scale_coeff = 1.0/absinfo_x->resolution; ++ tp->buttons.motion_dist.y_scale_coeff = 1.0/absinfo_y->resolution; ++ } + + tp->buttons.config_method.get_methods = tp_button_config_click_get_methods; + tp->buttons.config_method.set_method = tp_button_config_click_set_method; +diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c +index ce79530..6f11599 100644 +--- a/src/evdev-mt-touchpad.c ++++ b/src/evdev-mt-touchpad.c +@@ -431,17 +431,15 @@ tp_unpin_finger(struct tp_dispatch *tp, struct tp_touch *t) + return; + + xdist = abs(t->point.x - t->pinned.center.x); ++ xdist *= tp->buttons.motion_dist.x_scale_coeff; + ydist = abs(t->point.y - t->pinned.center.y); ++ ydist *= tp->buttons.motion_dist.y_scale_coeff; + +- if (xdist * xdist + ydist * ydist >= +- tp->buttons.motion_dist * tp->buttons.motion_dist) { ++ /* 3mm movement -> unpin */ ++ if (vector_length(xdist, ydist) >= 3.0) { + t->pinned.is_pinned = false; + return; + } +- +- /* The finger may slowly drift, adjust the center */ +- t->pinned.center.x = (t->point.x + t->pinned.center.x)/2; +- t->pinned.center.y = (t->point.y + t->pinned.center.y)/2; + } + + static void +diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h +index fef5cb3..bd2d163 100644 +--- a/src/evdev-mt-touchpad.h ++++ b/src/evdev-mt-touchpad.h +@@ -223,7 +223,10 @@ struct tp_dispatch { + bool click_pending; + uint32_t state; + uint32_t old_state; +- uint32_t motion_dist; /* for pinned touches */ ++ struct { ++ double x_scale_coeff; ++ double y_scale_coeff; ++ } motion_dist; /* for pinned touches */ + unsigned int active; /* currently active button, for release event */ + bool active_is_topbutton; /* is active a top button? */ + +diff --git a/src/libinput-util.h b/src/libinput-util.h +index 910406c..224e4b6 100644 +--- a/src/libinput-util.h ++++ b/src/libinput-util.h +@@ -284,4 +284,10 @@ int parse_mouse_dpi_property(const char *prop); + int parse_mouse_wheel_click_angle_property(const char *prop); + double parse_trackpoint_accel_property(const char *prop); + ++static inline double ++vector_length(double x, double y) ++{ ++ return sqrt(x * x + y * y); ++} ++ + #endif /* LIBINPUT_UTIL_H */ +diff --git a/test/touchpad.c b/test/touchpad.c +index 692698c..1e5e97b 100644 +--- a/test/touchpad.c ++++ b/test/touchpad.c +@@ -2153,6 +2153,53 @@ START_TEST(clickpad_click_n_drag) + } + END_TEST + ++START_TEST(clickpad_finger_pin) ++{ ++ struct litest_device *dev = litest_current_device(); ++ struct libinput *li = dev->libinput; ++ struct libevdev *evdev = dev->evdev; ++ const struct input_absinfo *abs; ++ ++ abs = libevdev_get_abs_info(evdev, ABS_MT_POSITION_X); ++ ck_assert_notnull(abs); ++ if (abs->resolution == 0) ++ return; ++ ++ litest_drain_events(li); ++ ++ /* make sure the movement generates pointer events when ++ not pinned */ ++ litest_touch_down(dev, 0, 50, 50); ++ litest_touch_move_to(dev, 0, 50, 50, 52, 52, 10, 1); ++ litest_touch_move_to(dev, 0, 52, 52, 48, 48, 10, 1); ++ litest_touch_move_to(dev, 0, 48, 48, 50, 50, 10, 1); ++ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION); ++ ++ litest_button_click(dev, BTN_LEFT, true); ++ litest_drain_events(li); ++ ++ litest_touch_move_to(dev, 0, 50, 50, 52, 52, 10, 1); ++ litest_touch_move_to(dev, 0, 52, 52, 48, 48, 10, 1); ++ litest_touch_move_to(dev, 0, 48, 48, 50, 50, 10, 1); ++ ++ litest_assert_empty_queue(li); ++ ++ litest_button_click(dev, BTN_LEFT, false); ++ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON); ++ ++ /* still pinned after release */ ++ litest_touch_move_to(dev, 0, 50, 50, 52, 52, 10, 1); ++ litest_touch_move_to(dev, 0, 52, 52, 48, 48, 10, 1); ++ litest_touch_move_to(dev, 0, 48, 48, 50, 50, 10, 1); ++ ++ litest_assert_empty_queue(li); ++ ++ /* move to unpin */ ++ litest_touch_move_to(dev, 0, 50, 50, 70, 70, 10, 1); ++ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION); ++} ++END_TEST ++ + START_TEST(clickpad_softbutton_left) + { + struct litest_device *dev = litest_current_device(); +@@ -5144,6 +5191,7 @@ litest_setup_tests(void) + litest_add("touchpad:click", touchpad_btn_left, LITEST_TOUCHPAD|LITEST_BUTTON, LITEST_CLICKPAD); + litest_add("touchpad:click", clickpad_btn_left, LITEST_CLICKPAD, LITEST_ANY); + litest_add("touchpad:click", clickpad_click_n_drag, LITEST_CLICKPAD, LITEST_SINGLE_TOUCH); ++ litest_add("touchpad:click", clickpad_finger_pin, LITEST_CLICKPAD, LITEST_ANY); + + litest_add("touchpad:softbutton", clickpad_softbutton_left, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD); + litest_add("touchpad:softbutton", clickpad_softbutton_right, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD); +-- +2.4.3 + diff --git a/libinput.spec b/libinput.spec index db41e08..6a1b39c 100644 --- a/libinput.spec +++ b/libinput.spec @@ -5,7 +5,7 @@ Name: libinput Version: 0.17.0 -Release: 3%{?gitdate:.%{gitdate}git%{gitversion}}%{?dist} +Release: 4%{?gitdate:.%{gitdate}git%{gitversion}}%{?dist} Summary: Input device library License: MIT @@ -19,6 +19,8 @@ Source0: http://www.freedesktop.org/software/libinput/libinput-%{version} %endif Patch01: 0001-filter-require-minimum-acceleration-factor-of-0.3.patch +Patch02: 0001-touchpad-fix-pinned-finger-drifting.patch +Patch03: 0001-touchpad-set-the-finger-pin-distance-to-5mm-where-po.patch BuildRequires: git BuildRequires: autoconf automake libtool pkgconfig @@ -96,6 +98,9 @@ find $RPM_BUILD_ROOT -name '*.la' -delete %changelog +* Tue Jun 16 2015 Peter Hutterer 0.17.0-4 +- Avoid erroneous finger movement after a physical click (#1230441) + * Fri Jun 12 2015 Peter Hutterer 0.17.0-3 - Require udev.pc for the build