From 6fc7d971f86af40eff188a7f2ea5c1d36907d62c Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 15 Jan 2016 11:48:19 +1000 Subject: [PATCH libinput] touchpad: fix elantech semi-mt three-finger bug When three fingers are on the touchpad, this touchpad opens another slot without setting coordinates. libinput interprets that as a 0/0 position and triggers palm detection for this finger. This causes a three-finger tap to be interpreted as a two-finger tap. https://bugs.freedesktop.org/show_bug.cgi?id=93583 Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/libinput-util.h | 1 + 2 files changed, 48 insertions(+) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 2de2539..ec1b728 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -391,6 +391,49 @@ tp_restore_synaptics_touches(struct tp_dispatch *tp, } } +static inline void +tp_update_elantech_touches(struct tp_dispatch *tp, + uint64_t time) +{ + struct tp_touch *first, *second; + + if (tp_fake_finger_count(tp) < 3) + return; + + /* Elantech semi-mt devices have garbage coordinates when three + * fingers are down. The second touch is started but doesn't have a + * coordinate, see the recording in + * https://bugs.freedesktop.org/show_bug.cgi?id=93583 + * + * E: 0.000001 0001 014a 0001 # EV_KEY / BTN_TOUCH 1 + * E: 0.000001 0003 0000 0800 # EV_ABS / ABS_X 800 + * E: 0.000001 0003 0001 0656 # EV_ABS / ABS_Y 656 + * E: 0.000001 0003 0039 0000 # EV_ABS / ABS_MT_TRACKING_ID 0 + * E: 0.000001 0003 0035 0800 # EV_ABS / ABS_MT_POSITION_X 800 + * E: 0.000001 0003 0036 0656 # EV_ABS / ABS_MT_POSITION_Y 656 + * E: 0.000001 0003 002f 0001 # EV_ABS / ABS_MT_SLOT 1 + * E: 0.000001 0003 0039 0001 # EV_ABS / ABS_MT_TRACKING_ID 1 + * E: 0.000001 0001 014e 0001 # EV_KEY / BTN_TOOL_TRIPLETAP 1 + * E: 0.000001 0003 0018 0165 # EV_ABS / ABS_PRESSURE 165 + * E: 0.000001 0003 001c 0009 # EV_ABS / ABS_TOOL_WIDTH 9 + * E: 0.000001 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +0ms + * + */ + first = tp_get_touch(tp, 0); + second = tp_get_touch(tp, 1); + + /* if neither is at 0/0, we're good */ + if ((first->point.x | first->point.y) != 0 && + (second->point.x | second->point.y) != 0) + return; + + if (first->point.x == 0 && first->point.y == 0) + swap(first, second); + + second->point.x = first->point.x; + second->point.y = first->point.y; +} + static void tp_process_fake_touches(struct tp_dispatch *tp, uint64_t time) @@ -406,6 +449,10 @@ tp_process_fake_touches(struct tp_dispatch *tp, if (tp->device->model_flags & EVDEV_MODEL_SYNAPTICS_SERIAL_TOUCHPAD) tp_restore_synaptics_touches(tp, time); + else if (tp->semi_mt && + tp->device->model_flags & + EVDEV_MODEL_ELANTECH_TOUCHPAD) + tp_update_elantech_touches(tp, time); start = tp->has_mt ? tp->num_slots : 0; for (i = start; i < tp->ntouches; i++) { diff --git a/src/libinput-util.h b/src/libinput-util.h index 25de8e5..ca63722 100644 --- a/src/libinput-util.h +++ b/src/libinput-util.h @@ -93,6 +93,7 @@ int list_empty(const struct list *list); #define min(a, b) (((a) < (b)) ? (a) : (b)) #define max(a, b) (((a) > (b)) ? (a) : (b)) +#define swap(a, b) { __typeof__(a) tmp_ = a; a = b; b = tmp_; } #define streq(s1, s2) (strcmp((s1), (s2)) == 0) #define strneq(s1, s2, n) (strncmp((s1), (s2), (n)) == 0) -- 2.5.0