From f1e2a7fd36f7d7fd80621be44c072a22c2e786b4 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 16 Apr 2015 18:10:34 +1000 Subject: [PATCH] Reduce palm detection threshold to 70mm (#1209753) - Don't allow taps in the top part of the palm zone (#1209753) --- ...llow-taps-in-the-top-half-of-the-pal.patch | 456 ++++++++++++++++++ libinput.spec | 8 +- 2 files changed, 463 insertions(+), 1 deletion(-) create mode 100644 0001-touchpad-don-t-allow-taps-in-the-top-half-of-the-pal.patch diff --git a/0001-touchpad-don-t-allow-taps-in-the-top-half-of-the-pal.patch b/0001-touchpad-don-t-allow-taps-in-the-top-half-of-the-pal.patch new file mode 100644 index 0000000..f165425 --- /dev/null +++ b/0001-touchpad-don-t-allow-taps-in-the-top-half-of-the-pal.patch @@ -0,0 +1,456 @@ +From c03ce1cab3c19dabd12d7b0886a9ef98107a958e Mon Sep 17 00:00:00 2001 +From: Peter Hutterer +Date: Wed, 15 Apr 2015 15:21:08 +1000 +Subject: [PATCH] touchpad: don't allow taps in the top half of the palm + exclusion zone. + +Touches in the exclusion zone are ignored for palm detection and don't move +the cursor. Tapping however triggers before we know whether something is a +palm or not, so we get erroneous button clickst. + +If a tap happens in the top half of the touchpad, within the palm exclusion +zones, ignore it for tap purposes. To avoid further complicating the state +machine simply pretend there was a movement > threshold on that finger. This +advances the tap state machine properly that no button events are sent for +this finger. + +https://bugs.freedesktop.org/show_bug.cgi?id=89625 + +Signed-off-by: Peter Hutterer +Reviewed-by: Hans de Goede +--- + doc/palm-detection.dox | 9 ++ + doc/svg/palm-detection.svg | 213 ++++++++++++++++++++++++++++++++------------ + src/evdev-mt-touchpad-tap.c | 8 ++ + src/evdev-mt-touchpad.c | 24 ++++- + src/evdev-mt-touchpad.h | 4 + + test/touchpad.c | 44 +++++++++ + 6 files changed, 244 insertions(+), 58 deletions(-) + +diff --git a/doc/palm-detection.dox b/doc/palm-detection.dox +index 4e839e6..a5b578b 100644 +--- a/doc/palm-detection.dox ++++ b/doc/palm-detection.dox +@@ -23,6 +23,10 @@ screen, it is common for a finger to start inside an exclusion zone and move + rapidly across the touchpad. libinput detects such movements and avoids palm + detection on such touch sequences. + ++Each exclusion zone is divided into a top part and a bottom part. A touch ++starting in the top part of the exclusion zone does not trigger a ++tap (see @ref tapping). ++ + In the diagram below, the exclusion zones are painted red. + Touch 'A' starts inside the exclusion zone and moves + almost vertically. It is considered a palm and ignored for cursor movement, +@@ -31,6 +35,11 @@ despite moving out of the exclusion zone. + Touch 'B' starts inside the exclusion zone but moves horizontally out of the + zone. It is considered a valid touch and controls the cursor. + ++Touch 'C' occurs in the top part of the exclusion zone. Despite being a ++tapping motion, it does not generate an emulated button event. Touch 'D' ++likewise occurs within the exclusion zone but in the bottom half. libinput ++will generate a button event for this touch. ++ + @image html palm-detection.svg + + @section trackpoint-disabling Palm detection during trackpoint use +diff --git a/doc/svg/palm-detection.svg b/doc/svg/palm-detection.svg +index 9fb6077..c3e45f4 100644 +--- a/doc/svg/palm-detection.svg ++++ b/doc/svg/palm-detection.svg +@@ -2,15 +2,67 @@ + + + ++ id="svg2" ++ inkscape:version="0.91 r13725" ++ sodipodi:docname="palm-detection.svg"> ++ ++ ++ ++ image/svg+xml ++ ++ ++ ++ ++ + + ++ ++ ++ + + +- +- +- +- +- +- A +- B +- +- ++ ++ ++ ++ ++ ++ A ++ ++ B ++ + ++ C ++ D ++ ++ + +diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c +index 6bd7c58..ae66c22 100644 +--- a/src/evdev-mt-touchpad-tap.c ++++ b/src/evdev-mt-touchpad-tap.c +@@ -575,6 +575,14 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time) + t->tap.state = TAP_TOUCH_STATE_TOUCH; + t->tap.initial = t->point; + tp_tap_handle_event(tp, t, TAP_EVENT_TOUCH, time); ++ ++ /* If we think this is a palm, pretend there's a ++ * motion event which will prevent tap clicks ++ * without requiring extra states in the FSM. ++ */ ++ if (tp_palm_tap_is_palm(tp, t)) ++ tp_tap_handle_event(tp, t, TAP_EVENT_MOTION, time); ++ + } else if (t->state == TOUCH_END) { + tp_tap_handle_event(tp, t, TAP_EVENT_RELEASE, time); + t->tap.state = TAP_TOUCH_STATE_IDLE; +diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c +index 356133f..53d80b2 100644 +--- a/src/evdev-mt-touchpad.c ++++ b/src/evdev-mt-touchpad.c +@@ -458,6 +458,24 @@ tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t) + tp_edge_scroll_touch_active(tp, t); + } + ++bool ++tp_palm_tap_is_palm(struct tp_dispatch *tp, struct tp_touch *t) ++{ ++ if (t->state != TOUCH_BEGIN) ++ return false; ++ ++ if (t->point.x > tp->palm.left_edge && ++ t->point.x < tp->palm.right_edge) ++ return false; ++ ++ /* We're inside the left/right palm edge and in the northern half of ++ * the touchpad - this tap is a palm */ ++ if (t->point.y < tp->palm.vert_center) ++ return true; ++ ++ return false; ++} ++ + static void + tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) + { +@@ -1084,13 +1102,16 @@ static int + tp_init_palmdetect(struct tp_dispatch *tp, + struct evdev_device *device) + { +- int width; ++ int width, height; + + tp->palm.right_edge = INT_MAX; + tp->palm.left_edge = INT_MIN; ++ tp->palm.vert_center = INT_MIN; + + width = abs(device->abs.absinfo_x->maximum - + device->abs.absinfo_x->minimum); ++ height = abs(device->abs.absinfo_y->maximum - ++ device->abs.absinfo_y->minimum); + + /* Apple touchpads are always big enough to warrant palm detection */ + if (evdev_device_get_id_vendor(device) != VENDOR_ID_APPLE) { +@@ -1107,6 +1128,7 @@ tp_init_palmdetect(struct tp_dispatch *tp, + /* palm edges are 5% of the width on each side */ + tp->palm.right_edge = device->abs.absinfo_x->maximum - width * 0.05; + tp->palm.left_edge = device->abs.absinfo_x->minimum + width * 0.05; ++ tp->palm.vert_center = device->abs.absinfo_y->minimum + height/2; + + return 0; + } +diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h +index 9980f90..6de999f 100644 +--- a/src/evdev-mt-touchpad.h ++++ b/src/evdev-mt-touchpad.h +@@ -260,6 +260,7 @@ struct tp_dispatch { + struct { + int32_t right_edge; /* in device coordinates */ + int32_t left_edge; /* in device coordinates */ ++ int32_t vert_center; /* in device coordinates */ + } palm; + + struct { +@@ -385,4 +386,7 @@ tp_gesture_post_events(struct tp_dispatch *tp, uint64_t time); + void + tp_gesture_stop_twofinger_scroll(struct tp_dispatch *tp, uint64_t time); + ++bool ++tp_palm_tap_is_palm(struct tp_dispatch *tp, struct tp_touch *t); ++ + #endif +diff --git a/test/touchpad.c b/test/touchpad.c +index 6fa2301..882e689 100644 +--- a/test/touchpad.c ++++ b/test/touchpad.c +@@ -2399,6 +2399,49 @@ START_TEST(touchpad_palm_detect_no_palm_moving_into_edges) + } + END_TEST + ++START_TEST(touchpad_palm_detect_tap) ++{ ++ struct litest_device *dev = litest_current_device(); ++ struct libinput *li = dev->libinput; ++ ++ if (!touchpad_has_palm_detect_size(dev)) ++ return; ++ ++ libinput_device_config_tap_set_enabled(dev->libinput_device, ++ LIBINPUT_CONFIG_TAP_ENABLED); ++ ++ litest_drain_events(li); ++ ++ litest_touch_down(dev, 0, 95, 5); ++ litest_touch_up(dev, 0); ++ litest_assert_empty_queue(li); ++ ++ litest_touch_down(dev, 0, 5, 5); ++ litest_touch_up(dev, 0); ++ litest_assert_empty_queue(li); ++ ++ litest_touch_down(dev, 0, 5, 90); ++ litest_touch_up(dev, 0); ++ litest_assert_button_event(li, ++ BTN_LEFT, ++ LIBINPUT_BUTTON_STATE_PRESSED); ++ litest_assert_button_event(li, ++ BTN_LEFT, ++ LIBINPUT_BUTTON_STATE_RELEASED); ++ litest_assert_empty_queue(li); ++ ++ litest_touch_down(dev, 0, 95, 90); ++ litest_touch_up(dev, 0); ++ litest_assert_button_event(li, ++ BTN_LEFT, ++ LIBINPUT_BUTTON_STATE_PRESSED); ++ litest_assert_button_event(li, ++ BTN_LEFT, ++ LIBINPUT_BUTTON_STATE_RELEASED); ++ litest_assert_empty_queue(li); ++} ++END_TEST ++ + START_TEST(touchpad_left_handed) + { + struct litest_device *dev = litest_current_device(); +@@ -3448,6 +3491,7 @@ int main(int argc, char **argv) { + litest_add("touchpad:palm", touchpad_palm_detect_palm_becomes_pointer, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:palm", touchpad_palm_detect_palm_stays_palm, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:palm", touchpad_palm_detect_no_palm_moving_into_edges, LITEST_TOUCHPAD, LITEST_ANY); ++ litest_add("touchpad:palm", touchpad_palm_detect_tap, LITEST_TOUCHPAD, LITEST_ANY); + + litest_add("touchpad:left-handed", touchpad_left_handed, LITEST_TOUCHPAD|LITEST_BUTTON, LITEST_CLICKPAD); + litest_add("touchpad:left-handed", touchpad_left_handed_clickpad, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD); +-- +2.3.4 + diff --git a/libinput.spec b/libinput.spec index 1b85bcf..abf7c99 100644 --- a/libinput.spec +++ b/libinput.spec @@ -5,7 +5,7 @@ Name: libinput Version: 0.13.0 -Release: 4%{?gitdate:.%{gitdate}git%{gitversion}}%{?dist} +Release: 5%{?gitdate:.%{gitdate}git%{gitversion}}%{?dist} Summary: Input device library License: MIT @@ -22,6 +22,8 @@ Patch01: 0001-evdev-fix-crash-for-missing-ABS_X-Y.patch Patch02: 0002-evdev-fix-handling-of-fake-MT-devices-without-ABS_X-.patch Patch03: 0001-evdev-fix-inverted-mouse-normalization.patch Patch04: 0001-touchpad-delay-fake-finger-processing-until-the-EV_S.patch +Patch05: 0001-touchpad-Reduce-palm-detection-threshold-to-70mm.patch +Patch06: 0001-touchpad-don-t-allow-taps-in-the-top-half-of-the-pal.patch BuildRequires: git BuildRequires: autoconf automake libtool pkgconfig @@ -89,6 +91,10 @@ find $RPM_BUILD_ROOT -name '*.la' -delete %changelog +* Thu Apr 16 2015 Peter Hutterer 0.13.0-5 +- Reduce palm detection threshold to 70mm (#1209753) +- Don't allow taps in the top part of the palm zone (#1209753) + * Thu Apr 09 2015 Peter Hutterer 0.13.0-4 - Fix finger miscounts on single-touch touchpads (#1209151)