summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2014-07-10 17:34:08 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2014-07-21 08:56:12 +1000
commitec7fc30ae2176c7361c1eb26c4c53e98382cbb6d (patch)
tree36689d4c8d11bf2605dcd4934ffa5b57176b0a82
parent876a8959ab1abe8a231860703320bb5fcc43c603 (diff)
downloadlibinput-ec7fc30ae2176c7361c1eb26c4c53e98382cbb6d.tar.gz
touchpad: implement edge-based basic palm detection
A large part of palm events are situated on the far edges of the touchpad. In a test run on a T440s while typing a long email all but 2 touch points were located in the outer ~5% of the touchpad. Define a 5% exclusion zone on the left and right edges in which new touchpoint is automatically assigned to be a palm. A finger may move into that exclusion zone without being marked as palm, it just can't start in one. On clickpads, the exclusion zone does not extend into the software buttons. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r--src/evdev-mt-touchpad-buttons.c6
-rw-r--r--src/evdev-mt-touchpad.c47
-rw-r--r--src/evdev-mt-touchpad.h9
-rw-r--r--test/touchpad.c117
4 files changed, 179 insertions, 0 deletions
diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c
index 520a47f1..bd3c0e25 100644
--- a/src/evdev-mt-touchpad-buttons.c
+++ b/src/evdev-mt-touchpad-buttons.c
@@ -733,3 +733,9 @@ tp_button_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
{
return t->button.state == BUTTON_STATE_AREA;
}
+
+bool
+tp_button_is_inside_softbutton_area(struct tp_dispatch *tp, struct tp_touch *t)
+{
+ return is_inside_top_button_area(tp, t) || is_inside_bottom_button_area(tp, t);
+}
diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index c7fd3a12..1325355c 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -148,6 +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->state = TOUCH_END;
t->pinned.is_pinned = false;
assert(tp->nfingers_down >= 1);
@@ -339,6 +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->pinned.is_pinned && tp_button_touch_active(tp, t);
}
@@ -358,6 +360,29 @@ tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t)
}
static void
+tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t)
+{
+ /* once a palm, always a palm */
+ if (t->is_palm)
+ return;
+
+ /* palm must start in exclusion zone, it's ok to move into
+ the zone without being a palm */
+ if (t->state != TOUCH_BEGIN ||
+ (t->x > tp->palm.left_edge && t->x < tp->palm.right_edge))
+ return;
+
+ /* don't detect palm in software button areas, it's
+ likely that legitimate touches start in the area
+ covered by the exclusion zone */
+ if (tp->buttons.is_clickpad &&
+ tp_button_is_inside_softbutton_area(tp, t))
+ return;
+
+ t->is_palm = true;
+}
+
+static void
tp_process_state(struct tp_dispatch *tp, uint64_t time)
{
struct tp_touch *t;
@@ -373,6 +398,8 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
continue;
}
+ tp_palm_detect(tp, t);
+
tp_motion_hysteresis(tp, t);
tp_motion_history_push(t);
@@ -703,6 +730,23 @@ tp_init_scroll(struct tp_dispatch *tp)
}
static int
+tp_init_palmdetect(struct tp_dispatch *tp,
+ struct evdev_device *device)
+{
+ int width;
+
+ width = abs(device->abs.absinfo_x->maximum -
+ device->abs.absinfo_x->minimum);
+
+ /* 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;
+
+ return 0;
+}
+
+
+static int
tp_init(struct tp_dispatch *tp,
struct evdev_device *device)
{
@@ -738,6 +782,9 @@ tp_init(struct tp_dispatch *tp,
if (tp_init_buttons(tp, device) != 0)
return -1;
+ if (tp_init_palmdetect(tp, device) != 0)
+ return -1;
+
return 0;
}
diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
index 80f3f606..689687ee 100644
--- a/src/evdev-mt-touchpad.h
+++ b/src/evdev-mt-touchpad.h
@@ -103,6 +103,7 @@ 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;
@@ -202,6 +203,11 @@ struct tp_dispatch {
struct libinput_timer timer;
enum tp_tap_state state;
} tap;
+
+ struct {
+ int32_t right_edge;
+ int32_t left_edge;
+ } palm;
};
#define tp_for_each_touch(_tp, _t) \
@@ -242,4 +248,7 @@ tp_button_handle_state(struct tp_dispatch *tp, uint64_t time);
int
tp_button_touch_active(struct tp_dispatch *tp, struct tp_touch *t);
+bool
+tp_button_is_inside_softbutton_area(struct tp_dispatch *tp, struct tp_touch *t);
+
#endif
diff --git a/test/touchpad.c b/test/touchpad.c
index bd5d71eb..672cbf9b 100644
--- a/test/touchpad.c
+++ b/test/touchpad.c
@@ -1241,6 +1241,117 @@ START_TEST(touchpad_tap_default)
}
END_TEST
+START_TEST(touchpad_palm_detect_at_edge)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+
+ litest_drain_events(li);
+
+ litest_touch_down(dev, 0, 99, 50);
+ litest_touch_move_to(dev, 0, 99, 50, 99, 70, 5);
+ litest_touch_up(dev, 0);
+
+ litest_assert_empty_queue(li);
+
+ litest_touch_down(dev, 0, 5, 50);
+ litest_touch_move_to(dev, 0, 5, 50, 5, 70, 5);
+ litest_touch_up(dev, 0);
+}
+END_TEST
+
+START_TEST(touchpad_palm_detect_at_bottom_corners)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+
+ /* Run for non-clickpads only: make sure the bottom corners trigger
+ palm detection too */
+ litest_drain_events(li);
+
+ litest_touch_down(dev, 0, 99, 95);
+ litest_touch_move_to(dev, 0, 99, 95, 99, 99, 10);
+ litest_touch_up(dev, 0);
+
+ litest_assert_empty_queue(li);
+
+ litest_touch_down(dev, 0, 5, 95);
+ litest_touch_move_to(dev, 0, 5, 95, 5, 99, 5);
+ litest_touch_up(dev, 0);
+}
+END_TEST
+
+START_TEST(touchpad_palm_detect_at_top_corners)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+
+ /* Run for non-clickpads only: make sure the bottom corners trigger
+ palm detection too */
+ litest_drain_events(li);
+
+ litest_touch_down(dev, 0, 99, 5);
+ litest_touch_move_to(dev, 0, 99, 5, 99, 9, 10);
+ litest_touch_up(dev, 0);
+
+ litest_assert_empty_queue(li);
+
+ litest_touch_down(dev, 0, 5, 5);
+ litest_touch_move_to(dev, 0, 5, 5, 5, 9, 5);
+ litest_touch_up(dev, 0);
+}
+END_TEST
+
+START_TEST(touchpad_palm_detect_palm_stays_palm)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+
+ litest_drain_events(li);
+
+ litest_touch_down(dev, 0, 99, 50);
+ litest_touch_move_to(dev, 0, 99, 50, 0, 70, 5);
+ litest_touch_up(dev, 0);
+
+ litest_assert_empty_queue(li);
+}
+END_TEST
+
+START_TEST(touchpad_palm_detect_no_palm_moving_into_edges)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct libinput_event *ev;
+ enum libinput_event_type type;
+
+ /* moving non-palm into the edge does not label it as palm */
+ litest_drain_events(li);
+
+ litest_touch_down(dev, 0, 50, 50);
+ litest_touch_move_to(dev, 0, 50, 50, 99, 50, 5);
+
+ litest_drain_events(li);
+
+ litest_touch_move_to(dev, 0, 99, 50, 99, 90, 5);
+ libinput_dispatch(li);
+
+ type = libinput_next_event_type(li);
+ do {
+
+ ck_assert_int_eq(type, LIBINPUT_EVENT_POINTER_MOTION);
+ ev = libinput_get_event(li);
+ libinput_event_destroy(ev);
+
+ type = libinput_next_event_type(li);
+ libinput_dispatch(li);
+ } while (type != LIBINPUT_EVENT_NONE);
+
+ litest_touch_up(dev, 0);
+ libinput_dispatch(li);
+ litest_assert_empty_queue(li);
+}
+END_TEST
+
int main(int argc, char **argv) {
litest_add("touchpad:motion", touchpad_1fg_motion, LITEST_TOUCHPAD, LITEST_ANY);
@@ -1290,5 +1401,11 @@ int main(int argc, char **argv) {
litest_add("touchpad:scroll", touchpad_2fg_scroll, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
+ 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_no_palm_moving_into_edges, LITEST_TOUCHPAD, LITEST_ANY);
+
return litest_run(argc, argv);
}