touchpad: if a palm touch moves out of the edge zone within a timeout, unpalm
authorPeter Hutterer <peter.hutterer@who-t.net>
Mon, 14 Jul 2014 06:06:51 +0000 (16:06 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Sun, 20 Jul 2014 22:56:12 +0000 (08:56 +1000)
On small touchpads a touch that is intended to traverse much of the screen
width may start at the very edge, i.e. in the palm zone.
In that case, and if the touch moves out of the palm zone quickly enough, drop
the palm label and make it a normal touchpoint.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
src/evdev-mt-touchpad.c
src/evdev-mt-touchpad.h
test/touchpad.c

index 1325355c1d92733b46b0b4119af83bd893a6bd22..830e9feec242ce9ba8ff0d010ed07b2abc52e292 100644 (file)
@@ -148,7 +148,7 @@ tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t)
 
        t->dirty = true;
        t->is_pointer = false;
-       t->is_palm = false;
+       t->palm.is_palm = false;
        t->state = TOUCH_END;
        t->pinned.is_pinned = false;
        assert(tp->nfingers_down >= 1);
@@ -340,7 +340,7 @@ static int
 tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
 {
        return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) &&
-               !t->is_palm &&
+               !t->palm.is_palm &&
                !t->pinned.is_pinned && tp_button_touch_active(tp, t);
 }
 
@@ -360,11 +360,21 @@ tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t)
 }
 
 static void
-tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t)
+tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
 {
-       /* once a palm, always a palm */
-       if (t->is_palm)
+       const int PALM_TIMEOUT = 200; /* ms */
+
+       /* If labelled a touch as palm, we unlabel as palm when
+          we move out of the palm edge zone within the timeout.
+        */
+       if (t->palm.is_palm) {
+               if (time < t->palm.time + PALM_TIMEOUT &&
+                   (t->x > tp->palm.left_edge && t->x < tp->palm.right_edge)) {
+                       t->palm.is_palm = false;
+                       tp_set_pointer(tp, t);
+               }
                return;
+       }
 
        /* palm must start in exclusion zone, it's ok to move into
           the zone without being a palm */
@@ -379,7 +389,8 @@ tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t)
            tp_button_is_inside_softbutton_area(tp, t))
                return;
 
-       t->is_palm = true;
+       t->palm.is_palm = true;
+       t->palm.time = time;
 }
 
 static void
@@ -398,7 +409,7 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
                        continue;
                }
 
-               tp_palm_detect(tp, t);
+               tp_palm_detect(tp, t, time);
 
                tp_motion_hysteresis(tp, t);
                tp_motion_history_push(t);
index 689687ee203b7fcdb671bda073d18af471053843..8255a1cd266f33040df1d785c01d49b6724e57e9 100644 (file)
@@ -103,7 +103,6 @@ struct tp_touch {
        bool dirty;
        bool fake;                              /* a fake touch */
        bool is_pointer;                        /* the pointer-controlling touch */
-       bool is_palm;
        int32_t x;
        int32_t y;
        uint64_t millis;
@@ -140,6 +139,11 @@ struct tp_touch {
        struct {
                enum tp_tap_touch_state state;
        } tap;
+
+       struct {
+               bool is_palm;
+               uint32_t time; /* first timestamp if is_palm == true */
+       } palm;
 };
 
 struct tp_dispatch {
index 672cbf9b37bbcbfd1d976de234d8e209c67c41e8..18427c1aa1eeacf6690b48c8daed3a8a3f678ef8 100644 (file)
@@ -1302,17 +1302,31 @@ START_TEST(touchpad_palm_detect_at_top_corners)
 }
 END_TEST
 
-START_TEST(touchpad_palm_detect_palm_stays_palm)
+START_TEST(touchpad_palm_detect_palm_becomes_pointer)
 {
        struct litest_device *dev = litest_current_device();
        struct libinput *li = dev->libinput;
+       struct libinput_event *ev;
+       enum libinput_event_type type;
 
        litest_drain_events(li);
 
        litest_touch_down(dev, 0, 99, 50);
-       litest_touch_move_to(dev, 0, 99, 50, 0, 70, 5);
+       litest_touch_move_to(dev, 0, 99, 70, 0, 70, 5);
        litest_touch_up(dev, 0);
 
+       libinput_dispatch(li);
+
+       ev = libinput_get_event(li);
+       ck_assert_notnull(ev);
+       do {
+               type = libinput_event_get_type(ev);
+               ck_assert_int_eq(type, LIBINPUT_EVENT_POINTER_MOTION);
+
+               libinput_event_destroy(ev);
+               ev = libinput_get_event(li);
+       } while (ev);
+
        litest_assert_empty_queue(li);
 }
 END_TEST
@@ -1404,7 +1418,7 @@ int main(int argc, char **argv) {
        litest_add("touchpad:palm", touchpad_palm_detect_at_edge, LITEST_TOUCHPAD, LITEST_ANY);
        litest_add("touchpad:palm", touchpad_palm_detect_at_bottom_corners, LITEST_TOUCHPAD, LITEST_CLICKPAD);
        litest_add("touchpad:palm", touchpad_palm_detect_at_top_corners, LITEST_TOUCHPAD, LITEST_TOPBUTTONPAD);
-       litest_add("touchpad:palm", touchpad_palm_detect_palm_stays_palm, LITEST_TOUCHPAD, LITEST_ANY);
+       litest_add("touchpad:palm", touchpad_palm_detect_palm_becomes_pointer, LITEST_TOUCHPAD, LITEST_ANY);
        litest_add("touchpad:palm", touchpad_palm_detect_no_palm_moving_into_edges, LITEST_TOUCHPAD, LITEST_ANY);
 
        return litest_run(argc, argv);