From 99cb9087224a8e7b0b988b13d391a54524eec61c Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 12 Dec 2014 10:31:12 +1000 Subject: [PATCH 01/15] touchpad: factor out fake finger handling We need this for determining hovering touches on some semi-mt touchpads. This makes the fake_touches mask use bit 0 for BTN_TOUCH, and the other bits for BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP, etc. BTN_TOUCH is independent of the rest, the others are mutually exclusive in the kernel. Since the mask isn't a straightforward bitmask anymore, abstract it all through helper functions. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/evdev-mt-touchpad.c | 72 ++++++++++++++++++++++++++++++----------- src/evdev-mt-touchpad.h | 7 +++- 2 files changed, 59 insertions(+), 20 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 34b107e2..406ac39a 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -135,6 +135,57 @@ tp_get_touch(struct tp_dispatch *tp, unsigned int slot) return &tp->touches[slot]; } +static inline unsigned int +tp_fake_finger_count(struct tp_dispatch *tp) +{ + unsigned int fake_touches, nfake_touches; + + /* don't count BTN_TOUCH */ + fake_touches = tp->fake_touches >> 1; + nfake_touches = 0; + while (fake_touches) { + nfake_touches++; + fake_touches >>= 1; + } + + return nfake_touches; +} + +static inline bool +tp_fake_finger_is_touching(struct tp_dispatch *tp) +{ + return tp->fake_touches & 0x1; +} + +static inline void +tp_fake_finger_set(struct tp_dispatch *tp, + unsigned int code, + bool is_press) +{ + unsigned int shift; + + switch (code) { + case BTN_TOUCH: + shift = 0; + break; + case BTN_TOOL_FINGER: + shift = 1; + break; + case BTN_TOOL_DOUBLETAP: + case BTN_TOOL_TRIPLETAP: + case BTN_TOOL_QUADTAP: + shift = code - BTN_TOOL_DOUBLETAP + 2; + break; + default: + return; + } + + if (is_press) + tp->fake_touches |= 1 << shift; + else + tp->fake_touches &= ~(0x1 << shift); +} + static inline void tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) { @@ -253,30 +304,13 @@ tp_process_fake_touch(struct tp_dispatch *tp, uint64_t time) { struct tp_touch *t; - unsigned int fake_touches; unsigned int nfake_touches; unsigned int i, start; - unsigned int shift; - if (e->code != BTN_TOUCH && - (e->code < BTN_TOOL_DOUBLETAP || e->code > BTN_TOOL_QUADTAP)) - return; + tp_fake_finger_set(tp, e->code, e->value != 0); - shift = e->code == BTN_TOUCH ? 0 : (e->code - BTN_TOOL_DOUBLETAP + 1); + nfake_touches = tp_fake_finger_count(tp); - if (e->value) - tp->fake_touches |= 1 << shift; - else - tp->fake_touches &= ~(0x1 << shift); - - fake_touches = tp->fake_touches; - nfake_touches = 0; - while (fake_touches) { - nfake_touches++; - fake_touches >>= 1; - } - - /* For single touch tps we use BTN_TOUCH for begin / end of touch 0 */ start = tp->has_mt ? tp->real_touches : 0; for (i = start; i < tp->ntouches; i++) { t = tp_get_touch(tp, i); diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 5807f08c..1e6152ae 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -197,7 +197,12 @@ struct tp_dispatch { unsigned int real_touches; /* number of slots */ unsigned int ntouches; /* no slots inc. fakes */ struct tp_touch *touches; /* len == ntouches */ - unsigned int fake_touches; /* fake touch mask */ + /* bit 0: BTN_TOUCH + * bit 1: BTN_TOOL_FINGER + * bit 2: BTN_TOOL_DOUBLETAP + * ... + */ + unsigned int fake_touches; struct { int32_t margin_x; From dc3d9315fe5ed725d87a909c2eb2da13760c7840 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 12 Dec 2014 12:14:13 +1000 Subject: [PATCH 02/15] touchpad: use ffs instead of a manual count BTN_TOOL_FINGER, DOUBLETAP, etc. are mutually exclusive in the kernel, so we can use ffs here instead of manually counting. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/evdev-mt-touchpad.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 406ac39a..03d8d62e 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -138,17 +138,8 @@ tp_get_touch(struct tp_dispatch *tp, unsigned int slot) static inline unsigned int tp_fake_finger_count(struct tp_dispatch *tp) { - unsigned int fake_touches, nfake_touches; - /* don't count BTN_TOUCH */ - fake_touches = tp->fake_touches >> 1; - nfake_touches = 0; - while (fake_touches) { - nfake_touches++; - fake_touches >>= 1; - } - - return nfake_touches; + return ffs(tp->fake_touches >> 1); } static inline bool From a467ac32cf5e731d4c18f4cf2983cec8c9c2a6af Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 11 Dec 2014 16:39:04 +1000 Subject: [PATCH 03/15] touchpad: add a TOUCH_HOVERING state Some touchpads provide touch information while the finger hovers over the touchpad, i.e. before BTN_TOUCH. Add a touch state for those touchpads so we can ignore the touches until they actually start. The approach is now: instead of BEGIN we mark a new touch as HOVERING. Use the BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP information during tp_process_state() to mark any touches that are hovering as down or ended. i.e. provided BTN_TOUCH is down: if BTN_TOOL_FINGER is down, one hovering touch gets marked as down, if DOUBLETAP is down, two touches are marked as down, etc. When ending touches, switch them back into HOVERING if the BTN_TOOL_FINGER is still set, otherwise end them properly. https://bugs.freedesktop.org/show_bug.cgi?id=87197 Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad-edge-scroll.c | 1 + src/evdev-mt-touchpad.c | 132 ++++++++++++++++++++++++---- src/evdev-mt-touchpad.h | 2 + 3 files changed, 118 insertions(+), 17 deletions(-) diff --git a/src/evdev-mt-touchpad-edge-scroll.c b/src/evdev-mt-touchpad-edge-scroll.c index 26a86141..8d0a13e3 100644 --- a/src/evdev-mt-touchpad-edge-scroll.c +++ b/src/evdev-mt-touchpad-edge-scroll.c @@ -294,6 +294,7 @@ tp_edge_scroll_handle_state(struct tp_dispatch *tp, uint64_t time) switch (t->state) { case TOUCH_NONE: + case TOUCH_HOVERING: break; case TOUCH_BEGIN: tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_TOUCH); diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 03d8d62e..bdd8f9ef 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -178,26 +178,53 @@ tp_fake_finger_set(struct tp_dispatch *tp, } static inline void -tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) +tp_new_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) { - if (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) + if (t->state == TOUCH_BEGIN || + t->state == TOUCH_UPDATE || + t->state == TOUCH_HOVERING) return; + /* we begin the touch as hovering because until BTN_TOUCH happens we + * don't know if it's a touch down or not. And BTN_TOUCH may happen + * after ABS_MT_TRACKING_ID */ tp_motion_history_reset(t); t->dirty = true; - t->state = TOUCH_BEGIN; + t->has_ended = false; + t->state = TOUCH_HOVERING; t->pinned.is_pinned = false; t->millis = time; - tp->nfingers_down++; - assert(tp->nfingers_down >= 1); tp->queued |= TOUCHPAD_EVENT_MOTION; } +static inline void +tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) +{ + t->dirty = true; + t->state = TOUCH_BEGIN; + t->millis = time; + tp->nfingers_down++; + assert(tp->nfingers_down >= 1); +} + +/** + * End a touch, even if the touch sequence is still active. + */ static inline void tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) { - if (t->state == TOUCH_END || t->state == TOUCH_NONE) + switch (t->state) { + case TOUCH_HOVERING: + t->state = TOUCH_NONE; + /* fallthough */ + case TOUCH_NONE: + case TOUCH_END: return; + case TOUCH_BEGIN: + case TOUCH_UPDATE: + break; + + } t->dirty = true; t->is_pointer = false; @@ -210,6 +237,16 @@ tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) tp->queued |= TOUCHPAD_EVENT_MOTION; } +/** + * End the touch sequence on ABS_MT_TRACKING_ID -1 or when the BTN_TOOL_* 0 is received. + */ +static inline void +tp_end_sequence(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) +{ + t->has_ended = true; + tp_end_touch(tp, t, time); +} + static double tp_estimate_delta(int x0, int x1, int x2, int x3) { @@ -260,9 +297,9 @@ tp_process_absolute(struct tp_dispatch *tp, break; case ABS_MT_TRACKING_ID: if (e->value != -1) - tp_begin_touch(tp, t, time); + tp_new_touch(tp, t, time); else - tp_end_touch(tp, t, time); + tp_end_sequence(tp, t, time); } } @@ -306,13 +343,10 @@ tp_process_fake_touch(struct tp_dispatch *tp, for (i = start; i < tp->ntouches; i++) { t = tp_get_touch(tp, i); if (i < nfake_touches) - tp_begin_touch(tp, t, time); + tp_new_touch(tp, t, time); else - tp_end_touch(tp, t, time); + tp_end_sequence(tp, t, time); } - - /* On mt the actual touch info may arrive after BTN_TOOL_FOO */ - assert(tp->has_mt || tp->nfingers_down == nfake_touches); } static void @@ -327,6 +361,7 @@ tp_process_key(struct tp_dispatch *tp, tp_process_button(tp, e, time); break; case BTN_TOUCH: + case BTN_TOOL_FINGER: case BTN_TOOL_DOUBLETAP: case BTN_TOOL_TRIPLETAP: case BTN_TOOL_QUADTAP: @@ -579,6 +614,61 @@ tp_remove_scroll(struct tp_dispatch *tp) tp_remove_edge_scroll(tp); } +static void +tp_unhover_touches(struct tp_dispatch *tp, uint64_t time) +{ + struct tp_touch *t; + unsigned int nfake_touches; + int i; + + if (!tp->fake_touches && !tp->nfingers_down) + return; + + nfake_touches = tp_fake_finger_count(tp); + if (tp->nfingers_down == nfake_touches && + ((tp->nfingers_down == 0 && !tp_fake_finger_is_touching(tp)) || + (tp->nfingers_down > 0 && tp_fake_finger_is_touching(tp)))) + return; + + /* if BTN_TOUCH is set and we have less fingers down than fake + * touches, switch each hovering touch to BEGIN + * until nfingers_down matches nfake_touches + */ + if (tp_fake_finger_is_touching(tp) && + tp->nfingers_down < nfake_touches) { + for (i = 0; i < (int)tp->ntouches; i++) { + t = tp_get_touch(tp, i); + + if (t->state == TOUCH_HOVERING) { + tp_begin_touch(tp, t, time); + + if (tp->nfingers_down >= nfake_touches) + break; + } + } + } + + /* if BTN_TOUCH is unset end all touches, we're hovering now. If we + * have too many touches also end some of them. This is done in + * reverse order. + */ + if (tp->nfingers_down > nfake_touches || + !tp_fake_finger_is_touching(tp)) { + for (i = tp->ntouches - 1; i >= 0; i--) { + t = tp_get_touch(tp, i); + + if (t->state == TOUCH_HOVERING) + continue; + + tp_end_touch(tp, t, time); + + if (tp_fake_finger_is_touching(tp) && + tp->nfingers_down == nfake_touches) + break; + } + } +} + static void tp_process_state(struct tp_dispatch *tp, uint64_t time) { @@ -586,6 +676,8 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time) struct tp_touch *first = tp_get_touch(tp, 0); unsigned int i; + tp_unhover_touches(tp, time); + for (i = 0; i < tp->ntouches; i++) { t = tp_get_touch(tp, i); @@ -631,13 +723,18 @@ tp_post_process_state(struct tp_dispatch *tp, uint64_t time) struct tp_touch *t; tp_for_each_touch(tp, t) { + if (!t->dirty) continue; - if (t->state == TOUCH_END) - t->state = TOUCH_NONE; - else if (t->state == TOUCH_BEGIN) + if (t->state == TOUCH_END) { + if (t->has_ended) + t->state = TOUCH_NONE; + else + t->state = TOUCH_HOVERING; + } else if (t->state == TOUCH_BEGIN) { t->state = TOUCH_UPDATE; + } t->dirty = false; } @@ -818,7 +915,7 @@ tp_clear_state(struct tp_dispatch *tp) tp_release_all_taps(tp, now); tp_for_each_touch(tp, t) { - tp_end_touch(tp, t, now); + tp_end_sequence(tp, t, now); } tp_handle_state(tp, now); @@ -979,6 +1076,7 @@ tp_init_touch(struct tp_dispatch *tp, struct tp_touch *t) { t->tp = tp; + t->has_ended = true; } static int diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 1e6152ae..7fe152a3 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -53,6 +53,7 @@ enum touchpad_model { enum touch_state { TOUCH_NONE = 0, + TOUCH_HOVERING, TOUCH_BEGIN, TOUCH_UPDATE, TOUCH_END @@ -130,6 +131,7 @@ struct tp_motion { struct tp_touch { struct tp_dispatch *tp; enum touch_state state; + bool has_ended; /* TRACKING_ID == -1 */ bool dirty; bool is_pointer; /* the pointer-controlling touch */ int32_t x; From 3d0e4f66f76fb08d2eb44339fb4789a9a09b0252 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 16 Dec 2014 11:28:26 +1000 Subject: [PATCH 04/15] test: move semi-mt special tracking into the shared litest.c An upcoming synaptics semi-mt device needs the same code. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- test/litest-alps-semi-mt.c | 146 +++---------------------------------- test/litest.c | 141 +++++++++++++++++++++++++++++++++++ test/litest.h | 27 +++++++ 3 files changed, 177 insertions(+), 137 deletions(-) diff --git a/test/litest-alps-semi-mt.c b/test/litest-alps-semi-mt.c index 12b93b8c..4d95ac90 100644 --- a/test/litest-alps-semi-mt.c +++ b/test/litest-alps-semi-mt.c @@ -31,21 +31,6 @@ #include "litest.h" #include "litest-int.h" -static int tracking_id; - -/* this is a semi-mt device, so we keep track of the touches that the tests - * send and modify them so that the first touch is always slot 0 and sends - * the top-left of the bounding box, the second is always slot 1 and sends - * the bottom-right of the bounding box. - * Lifting any of two fingers terminates slot 1 - */ -struct alps { - /* The actual touches requested by the test for the two slots - * in the 0..100 range used by litest */ - struct { - double x, y; - } touches[2]; -}; static void alps_create(struct litest_device *d); @@ -56,141 +41,28 @@ litest_alps_setup(void) litest_set_current_device(d); } -static void -send_abs_xy(struct litest_device *d, double x, double y) -{ - struct input_event e; - int val; - - e.type = EV_ABS; - e.code = ABS_X; - e.value = LITEST_AUTO_ASSIGN; - val = litest_auto_assign_value(d, &e, 0, x, y); - litest_event(d, EV_ABS, ABS_X, val); - - e.code = ABS_Y; - val = litest_auto_assign_value(d, &e, 0, x, y); - litest_event(d, EV_ABS, ABS_Y, val); -} - -static void -send_abs_mt_xy(struct litest_device *d, double x, double y) -{ - struct input_event e; - int val; - - e.type = EV_ABS; - e.code = ABS_MT_POSITION_X; - e.value = LITEST_AUTO_ASSIGN; - val = litest_auto_assign_value(d, &e, 0, x, y); - litest_event(d, EV_ABS, ABS_MT_POSITION_X, val); - - e.code = ABS_MT_POSITION_Y; - e.value = LITEST_AUTO_ASSIGN; - val = litest_auto_assign_value(d, &e, 0, x, y); - litest_event(d, EV_ABS, ABS_MT_POSITION_Y, val); -} - static void alps_touch_down(struct litest_device *d, unsigned int slot, double x, double y) { - struct alps *alps = d->private; - double t, l, r = 0, b = 0; /* top, left, right, bottom */ + struct litest_semi_mt *semi_mt = d->private; - if (d->ntouches_down > 2 || slot > 1) - return; - - if (d->ntouches_down == 1) { - l = x; - t = y; - } else { - int other = (slot + 1) % 2; - l = min(x, alps->touches[other].x); - t = min(y, alps->touches[other].y); - r = max(x, alps->touches[other].x); - b = max(y, alps->touches[other].y); - } - - send_abs_xy(d, l, t); - - litest_event(d, EV_ABS, ABS_MT_SLOT, 0); - - if (d->ntouches_down == 1) - litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, ++tracking_id); - - send_abs_mt_xy(d, l, t); - - if (d->ntouches_down == 2) { - litest_event(d, EV_ABS, ABS_MT_SLOT, 1); - litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, ++tracking_id); - - send_abs_mt_xy(d, r, b); - } - - litest_event(d, EV_SYN, SYN_REPORT, 0); - - alps->touches[slot].x = x; - alps->touches[slot].y = y; + litest_semi_mt_touch_down(d, semi_mt, slot, x, y); } static void alps_touch_move(struct litest_device *d, unsigned int slot, double x, double y) { - struct alps *alps = d->private; - double t, l, r = 0, b = 0; /* top, left, right, bottom */ + struct litest_semi_mt *semi_mt = d->private; - if (d->ntouches_down > 2 || slot > 1) - return; - - if (d->ntouches_down == 1) { - l = x; - t = y; - } else { - int other = (slot + 1) % 2; - l = min(x, alps->touches[other].x); - t = min(y, alps->touches[other].y); - r = max(x, alps->touches[other].x); - b = max(y, alps->touches[other].y); - } - - send_abs_xy(d, l, t); - - litest_event(d, EV_ABS, ABS_MT_SLOT, 0); - send_abs_mt_xy(d, l, t); - - if (d->ntouches_down == 2) { - litest_event(d, EV_ABS, ABS_MT_SLOT, 1); - send_abs_mt_xy(d, r, b); - } - - litest_event(d, EV_SYN, SYN_REPORT, 0); - - alps->touches[slot].x = x; - alps->touches[slot].y = y; + litest_semi_mt_touch_move(d, semi_mt, slot, x, y); } static void alps_touch_up(struct litest_device *d, unsigned int slot) { - struct alps *alps = d->private; + struct litest_semi_mt *semi_mt = d->private; - /* note: ntouches_down is decreased before we get here */ - if (d->ntouches_down >= 2 || slot > 1) - return; - - litest_event(d, EV_ABS, ABS_MT_SLOT, d->ntouches_down); - litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, -1); - - /* if we have one finger left, send x/y coords for that finger left. - this is likely to happen with a real touchpad */ - if (d->ntouches_down == 1) { - int other = (slot + 1) % 2; - send_abs_xy(d, alps->touches[other].x, alps->touches[other].y); - litest_event(d, EV_ABS, ABS_MT_SLOT, 0); - send_abs_mt_xy(d, alps->touches[other].x, alps->touches[other].y); - } - - litest_event(d, EV_SYN, SYN_REPORT, 0); + litest_semi_mt_touch_up(d, semi_mt, slot); } static struct litest_device_interface interface = { @@ -247,10 +119,10 @@ struct litest_test_device litest_alps_device = { static void alps_create(struct litest_device *d) { - struct alps *alps = zalloc(sizeof(*alps)); - assert(alps); + struct litest_semi_mt *semi_mt = zalloc(sizeof(*semi_mt)); + assert(semi_mt); - d->private = alps; + d->private = semi_mt; d->uinput = litest_create_uinput_device_from_description(litest_alps_device.name, litest_alps_device.id, diff --git a/test/litest.c b/test/litest.c index 757f445d..adba4616 100644 --- a/test/litest.c +++ b/test/litest.c @@ -1277,3 +1277,144 @@ litest_pop_event_frame(struct litest_device *dev) dev->skip_ev_syn = false; litest_event(dev, EV_SYN, SYN_REPORT, 0); } + +static void +send_abs_xy(struct litest_device *d, double x, double y) +{ + struct input_event e; + int val; + + e.type = EV_ABS; + e.code = ABS_X; + e.value = LITEST_AUTO_ASSIGN; + val = litest_auto_assign_value(d, &e, 0, x, y); + litest_event(d, EV_ABS, ABS_X, val); + + e.code = ABS_Y; + val = litest_auto_assign_value(d, &e, 0, x, y); + litest_event(d, EV_ABS, ABS_Y, val); +} + +static void +send_abs_mt_xy(struct litest_device *d, double x, double y) +{ + struct input_event e; + int val; + + e.type = EV_ABS; + e.code = ABS_MT_POSITION_X; + e.value = LITEST_AUTO_ASSIGN; + val = litest_auto_assign_value(d, &e, 0, x, y); + litest_event(d, EV_ABS, ABS_MT_POSITION_X, val); + + e.code = ABS_MT_POSITION_Y; + e.value = LITEST_AUTO_ASSIGN; + val = litest_auto_assign_value(d, &e, 0, x, y); + litest_event(d, EV_ABS, ABS_MT_POSITION_Y, val); +} + +void +litest_semi_mt_touch_down(struct litest_device *d, + struct litest_semi_mt *semi_mt, + unsigned int slot, + double x, double y) +{ + double t, l, r = 0, b = 0; /* top, left, right, bottom */ + + if (d->ntouches_down > 2 || slot > 1) + return; + + if (d->ntouches_down == 1) { + l = x; + t = y; + } else { + int other = (slot + 1) % 2; + l = min(x, semi_mt->touches[other].x); + t = min(y, semi_mt->touches[other].y); + r = max(x, semi_mt->touches[other].x); + b = max(y, semi_mt->touches[other].y); + } + + send_abs_xy(d, l, t); + + litest_event(d, EV_ABS, ABS_MT_SLOT, 0); + + if (d->ntouches_down == 1) + litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, ++semi_mt->tracking_id); + + send_abs_mt_xy(d, l, t); + + if (d->ntouches_down == 2) { + litest_event(d, EV_ABS, ABS_MT_SLOT, 1); + litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, ++semi_mt->tracking_id); + + send_abs_mt_xy(d, r, b); + } + + litest_event(d, EV_SYN, SYN_REPORT, 0); + + semi_mt->touches[slot].x = x; + semi_mt->touches[slot].y = y; +} + +void +litest_semi_mt_touch_move(struct litest_device *d, + struct litest_semi_mt *semi_mt, + unsigned int slot, + double x, double y) +{ + double t, l, r = 0, b = 0; /* top, left, right, bottom */ + + if (d->ntouches_down > 2 || slot > 1) + return; + + if (d->ntouches_down == 1) { + l = x; + t = y; + } else { + int other = (slot + 1) % 2; + l = min(x, semi_mt->touches[other].x); + t = min(y, semi_mt->touches[other].y); + r = max(x, semi_mt->touches[other].x); + b = max(y, semi_mt->touches[other].y); + } + + send_abs_xy(d, l, t); + + litest_event(d, EV_ABS, ABS_MT_SLOT, 0); + send_abs_mt_xy(d, l, t); + + if (d->ntouches_down == 2) { + litest_event(d, EV_ABS, ABS_MT_SLOT, 1); + send_abs_mt_xy(d, r, b); + } + + litest_event(d, EV_SYN, SYN_REPORT, 0); + + semi_mt->touches[slot].x = x; + semi_mt->touches[slot].y = y; +} + +void +litest_semi_mt_touch_up(struct litest_device *d, + struct litest_semi_mt *semi_mt, + unsigned int slot) +{ + /* note: ntouches_down is decreased before we get here */ + if (d->ntouches_down >= 2 || slot > 1) + return; + + litest_event(d, EV_ABS, ABS_MT_SLOT, d->ntouches_down); + litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, -1); + + /* if we have one finger left, send x/y coords for that finger left. + this is likely to happen with a real touchpad */ + if (d->ntouches_down == 1) { + int other = (slot + 1) % 2; + send_abs_xy(d, semi_mt->touches[other].x, semi_mt->touches[other].y); + litest_event(d, EV_ABS, ABS_MT_SLOT, 0); + send_abs_mt_xy(d, semi_mt->touches[other].x, semi_mt->touches[other].y); + } + + litest_event(d, EV_SYN, SYN_REPORT, 0); +} diff --git a/test/litest.h b/test/litest.h index 31011a2b..5ac1003e 100644 --- a/test/litest.h +++ b/test/litest.h @@ -180,6 +180,33 @@ void litest_timeout_buttonscroll(void); void litest_push_event_frame(struct litest_device *dev); void litest_pop_event_frame(struct litest_device *dev); +/* this is a semi-mt device, so we keep track of the touches that the tests + * send and modify them so that the first touch is always slot 0 and sends + * the top-left of the bounding box, the second is always slot 1 and sends + * the bottom-right of the bounding box. + * Lifting any of two fingers terminates slot 1 + */ +struct litest_semi_mt { + int tracking_id; + /* The actual touches requested by the test for the two slots + * in the 0..100 range used by litest */ + struct { + double x, y; + } touches[2]; +}; + +void litest_semi_mt_touch_down(struct litest_device *d, + struct litest_semi_mt *semi_mt, + unsigned int slot, + double x, double y); +void litest_semi_mt_touch_move(struct litest_device *d, + struct litest_semi_mt *semi_mt, + unsigned int slot, + double x, double y); +void litest_semi_mt_touch_up(struct litest_device *d, + struct litest_semi_mt *semi_mt, + unsigned int slot); + #ifndef ck_assert_notnull #define ck_assert_notnull(ptr) ck_assert_ptr_ne(ptr, NULL) #endif From 62e4b144d24f4152449afb4750ec42659f37e207 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 11 Dec 2014 13:30:33 +1000 Subject: [PATCH 05/15] test: add a semi-mt + hover synaptics touchpad This device sends touch information before BTN_TOUCH https://bugs.freedesktop.org/show_bug.cgi?id=87197 Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- test/Makefile.am | 1 + test/litest-synaptics-hover.c | 132 ++++++++++++++++++++++++++++++++++ test/litest.c | 2 + test/litest.h | 1 + 4 files changed, 136 insertions(+) create mode 100644 test/litest-synaptics-hover.c diff --git a/test/Makefile.am b/test/Makefile.am index 2c36e3fc..1b7ba870 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -21,6 +21,7 @@ liblitest_la_SOURCES = \ litest-ms-surface-cover.c \ litest-qemu-usb-tablet.c \ litest-synaptics.c \ + litest-synaptics-hover.c \ litest-synaptics-st.c \ litest-synaptics-t440.c \ litest-trackpoint.c \ diff --git a/test/litest-synaptics-hover.c b/test/litest-synaptics-hover.c new file mode 100644 index 00000000..7ba56bc8 --- /dev/null +++ b/test/litest-synaptics-hover.c @@ -0,0 +1,132 @@ +/* + * Copyright © 2014 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "libinput-util.h" + +#include "litest.h" +#include "litest-int.h" + +static void +synaptics_hover_create(struct litest_device *d); + +static void +litest_synaptics_hover_setup(void) +{ + struct litest_device *d = litest_create_device(LITEST_SYNAPTICS_HOVER_SEMI_MT); + litest_set_current_device(d); +} + +static void +synaptics_hover_touch_down(struct litest_device *d, unsigned int slot, double x, double y) +{ + struct litest_semi_mt *semi_mt = d->private; + + litest_semi_mt_touch_down(d, semi_mt, slot, x, y); +} + +static void +synaptics_hover_touch_move(struct litest_device *d, unsigned int slot, double x, double y) +{ + struct litest_semi_mt *semi_mt = d->private; + + litest_semi_mt_touch_move(d, semi_mt, slot, x, y); +} + +static void +synaptics_hover_touch_up(struct litest_device *d, unsigned int slot) +{ + struct litest_semi_mt *semi_mt = d->private; + + litest_semi_mt_touch_up(d, semi_mt, slot); +} + +static struct litest_device_interface interface = { + .touch_down = synaptics_hover_touch_down, + .touch_move = synaptics_hover_touch_move, + .touch_up = synaptics_hover_touch_up, +}; + +static struct input_id input_id = { + .bustype = 0x11, + .vendor = 0x2, + .product = 0x7, +}; + +static int events[] = { + EV_KEY, BTN_LEFT, + EV_KEY, BTN_RIGHT, + EV_KEY, BTN_TOOL_FINGER, + EV_KEY, BTN_TOUCH, + EV_KEY, BTN_TOOL_DOUBLETAP, + EV_KEY, BTN_TOOL_TRIPLETAP, + INPUT_PROP_MAX, INPUT_PROP_POINTER, + INPUT_PROP_MAX, INPUT_PROP_SEMI_MT, + -1, -1, +}; + +static struct input_absinfo absinfo[] = { + { ABS_X, 1472, 5472, 0, 0, 60 }, + { ABS_Y, 1408, 4498, 0, 0, 85 }, + { ABS_PRESSURE, 0, 255, 0, 0, 0 }, + { ABS_TOOL_WIDTH, 0, 15, 0, 0, 0 }, + { ABS_MT_SLOT, 0, 1, 0, 0, 0 }, + { ABS_MT_POSITION_X, 1472, 5472, 0, 0, 60 }, + { ABS_MT_POSITION_Y, 1408, 4498, 0, 0, 85 }, + { ABS_MT_TRACKING_ID, 0, 65535, 0, 0, 0 }, + { .value = -1 } +}; + +struct litest_test_device litest_synaptics_hover_device = { + .type = LITEST_SYNAPTICS_HOVER_SEMI_MT, + .features = LITEST_TOUCHPAD | LITEST_SEMI_MT | LITEST_BUTTON, + .shortname = "synaptics hover", + .setup = litest_synaptics_hover_setup, + .interface = &interface, + .create = synaptics_hover_create, + + .name = "SynPS/2 Synaptics TouchPad", + .id = &input_id, + .events = events, + .absinfo = absinfo, +}; + +static void +synaptics_hover_create(struct litest_device *d) +{ + struct litest_semi_mt *semi_mt = zalloc(sizeof(*semi_mt)); + assert(semi_mt); + + d->private = semi_mt; + + d->uinput = litest_create_uinput_device_from_description( + litest_synaptics_hover_device.name, + litest_synaptics_hover_device.id, + absinfo, + events); + d->interface = &interface; +} diff --git a/test/litest.c b/test/litest.c index adba4616..7d482784 100644 --- a/test/litest.c +++ b/test/litest.c @@ -90,6 +90,7 @@ extern struct litest_test_device litest_generic_singletouch_device; extern struct litest_test_device litest_qemu_tablet_device; extern struct litest_test_device litest_xen_virtual_pointer_device; extern struct litest_test_device litest_vmware_virtmouse_device; +extern struct litest_test_device litest_synaptics_hover_device; struct litest_test_device* devices[] = { &litest_synaptics_clickpad_device, @@ -105,6 +106,7 @@ struct litest_test_device* devices[] = { &litest_qemu_tablet_device, &litest_xen_virtual_pointer_device, &litest_vmware_virtmouse_device, + &litest_synaptics_hover_device, NULL, }; diff --git a/test/litest.h b/test/litest.h index 5ac1003e..2d4b4d8b 100644 --- a/test/litest.h +++ b/test/litest.h @@ -49,6 +49,7 @@ enum litest_device_type { LITEST_QEMU_TABLET = -13, LITEST_XEN_VIRTUAL_POINTER = -14, LITEST_VMWARE_VIRTMOUSE = -15, + LITEST_SYNAPTICS_HOVER_SEMI_MT = -16, }; enum litest_device_feature { From 80fc33d66ccc345b7c470c3e74df12b33c658139 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 12 Dec 2014 10:02:15 +1000 Subject: [PATCH 06/15] test: add touchpad hover finger test Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- test/touchpad.c | 322 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 321 insertions(+), 1 deletion(-) diff --git a/test/touchpad.c b/test/touchpad.c index c5edecc8..3b3c64ee 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -2207,8 +2207,320 @@ START_TEST(touchpad_left_handed_clickpad_delayed) } END_TEST -int main(int argc, char **argv) { +static void +hover_continue(struct litest_device *dev, unsigned int slot, + int x, int y) +{ + litest_event(dev, EV_ABS, ABS_MT_SLOT, slot); + litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x); + litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y); + litest_event(dev, EV_ABS, ABS_X, x); + litest_event(dev, EV_ABS, ABS_Y, y); + litest_event(dev, EV_ABS, ABS_PRESSURE, 10); + litest_event(dev, EV_ABS, ABS_TOOL_WIDTH, 6); + /* WARNING: no SYN_REPORT! */ +} +static void +hover_start(struct litest_device *dev, unsigned int slot, + int x, int y) +{ + static unsigned int tracking_id; + + litest_event(dev, EV_ABS, ABS_MT_SLOT, slot); + litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, ++tracking_id); + hover_continue(dev, slot, x, y); + /* WARNING: no SYN_REPORT! */ +} + +START_TEST(touchpad_hover_noevent) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + int i; + int x = 2400, + y = 2400; + + litest_drain_events(li); + + hover_start(dev, 0, x, y); + litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + for (i = 0; i < 10; i++) { + x += 200; + y -= 200; + litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x); + litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y); + litest_event(dev, EV_ABS, ABS_X, x); + litest_event(dev, EV_ABS, ABS_Y, y); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + } + + litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + litest_assert_empty_queue(li); +} +END_TEST + +START_TEST(touchpad_hover_down) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + int i; + int x = 2400, + y = 2400; + + litest_drain_events(li); + + hover_start(dev, 0, x, y); + litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + for (i = 0; i < 10; i++) { + x += 200; + y -= 200; + litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x); + litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y); + litest_event(dev, EV_ABS, ABS_X, x); + litest_event(dev, EV_ABS, ABS_Y, y); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + } + + litest_assert_empty_queue(li); + + litest_event(dev, EV_ABS, ABS_X, x + 100); + litest_event(dev, EV_ABS, ABS_Y, y + 100); + litest_event(dev, EV_KEY, BTN_TOUCH, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + for (i = 0; i < 10; i++) { + x -= 200; + y += 200; + litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x); + litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y); + litest_event(dev, EV_ABS, ABS_X, x); + litest_event(dev, EV_ABS, ABS_Y, y); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + } + + libinput_dispatch(li); + + ck_assert_int_ne(libinput_next_event_type(li), + LIBINPUT_EVENT_NONE); + while ((event = libinput_get_event(li)) != NULL) { + ck_assert_int_eq(libinput_event_get_type(event), + LIBINPUT_EVENT_POINTER_MOTION); + libinput_event_destroy(event); + libinput_dispatch(li); + } + + /* go back to hover */ + hover_continue(dev, 0, x, y); + litest_event(dev, EV_KEY, BTN_TOUCH, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + for (i = 0; i < 10; i++) { + x += 200; + y -= 200; + litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x); + litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y); + litest_event(dev, EV_ABS, ABS_X, x); + litest_event(dev, EV_ABS, ABS_Y, y); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + } + + litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + litest_assert_empty_queue(li); +} +END_TEST + +START_TEST(touchpad_hover_down_hover_down) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + int i, j; + int x = 1400, + y = 1400; + + litest_drain_events(li); + + /* hover */ + hover_start(dev, 0, x, y); + litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_assert_empty_queue(li); + + for (i = 0; i < 3; i++) { + /* touch */ + litest_event(dev, EV_ABS, ABS_X, x + 100); + litest_event(dev, EV_ABS, ABS_Y, y + 100); + litest_event(dev, EV_KEY, BTN_TOUCH, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + + for (j = 0; j < 5; j++) { + x += 200; + y += 200; + litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x); + litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y); + litest_event(dev, EV_ABS, ABS_X, x); + litest_event(dev, EV_ABS, ABS_Y, y); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + } + + libinput_dispatch(li); + + ck_assert_int_ne(libinput_next_event_type(li), + LIBINPUT_EVENT_NONE); + while ((event = libinput_get_event(li)) != NULL) { + ck_assert_int_eq(libinput_event_get_type(event), + LIBINPUT_EVENT_POINTER_MOTION); + libinput_event_destroy(event); + libinput_dispatch(li); + } + + /* go back to hover */ + hover_continue(dev, 0, x, y); + litest_event(dev, EV_KEY, BTN_TOUCH, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + for (j = 0; j < 5; j++) { + x += 200; + y += 200; + litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x); + litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y); + litest_event(dev, EV_ABS, ABS_X, x); + litest_event(dev, EV_ABS, ABS_Y, y); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + } + + litest_assert_empty_queue(li); + } + + /* touch */ + litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + litest_assert_empty_queue(li); + + /* start a new touch to be sure */ + litest_touch_down(dev, 0, 50, 50); + litest_touch_move_to(dev, 0, 50, 50, 70, 70, 10, 10); + litest_touch_up(dev, 0); + + libinput_dispatch(li); + ck_assert_int_ne(libinput_next_event_type(li), + LIBINPUT_EVENT_NONE); + while ((event = libinput_get_event(li)) != NULL) { + ck_assert_int_eq(libinput_event_get_type(event), + LIBINPUT_EVENT_POINTER_MOTION); + libinput_event_destroy(event); + libinput_dispatch(li); + } +} +END_TEST + +START_TEST(touchpad_hover_2fg_noevent) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + int i; + int x = 2400, + y = 2400; + + litest_drain_events(li); + + hover_start(dev, 0, x, y); + litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + hover_start(dev, 1, x + 500, y + 500); + litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0); + litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + for (i = 0; i < 10; i++) { + x += 200; + y -= 200; + litest_event(dev, EV_ABS, ABS_MT_SLOT, 0); + litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x); + litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y); + litest_event(dev, EV_ABS, ABS_MT_SLOT, 1); + litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x + 500); + litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y + 500); + litest_event(dev, EV_ABS, ABS_X, x); + litest_event(dev, EV_ABS, ABS_Y, y); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + } + + litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + litest_assert_empty_queue(li); + + litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + litest_assert_empty_queue(li); +} +END_TEST + +START_TEST(touchpad_hover_2fg_1fg_down) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + int i; + int x = 2400, + y = 2400; + + litest_drain_events(li); + + /* two slots active, but BTN_TOOL_FINGER only */ + hover_start(dev, 0, x, y); + hover_start(dev, 1, x + 500, y + 500); + litest_event(dev, EV_KEY, BTN_TOUCH, 1); + litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + for (i = 0; i < 10; i++) { + x += 200; + y -= 200; + litest_event(dev, EV_ABS, ABS_MT_SLOT, 0); + litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x); + litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y); + litest_event(dev, EV_ABS, ABS_MT_SLOT, 1); + litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x + 500); + litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y + 500); + litest_event(dev, EV_ABS, ABS_X, x); + litest_event(dev, EV_ABS, ABS_Y, y); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + } + + litest_event(dev, EV_KEY, BTN_TOUCH, 0); + litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + libinput_dispatch(li); + + ck_assert_int_ne(libinput_next_event_type(li), + LIBINPUT_EVENT_NONE); + while ((event = libinput_get_event(li)) != NULL) { + ck_assert_int_eq(libinput_event_get_type(event), + LIBINPUT_EVENT_POINTER_MOTION); + libinput_event_destroy(event); + libinput_dispatch(li); + } +} +END_TEST + +int main(int argc, char **argv) { litest_add("touchpad:motion", touchpad_1fg_motion, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:motion", touchpad_2fg_no_motion, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); @@ -2295,5 +2607,13 @@ int main(int argc, char **argv) { litest_add("touchpad:left-handed", touchpad_left_handed_delayed, LITEST_TOUCHPAD, LITEST_CLICKPAD); litest_add("touchpad:left-handed", touchpad_left_handed_clickpad_delayed, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD); + /* Hover tests aren't generic, they only work on this device and + * ignore the semi-mt capability (it doesn't matter for the tests */ + litest_add_for_device("touchpad:hover", touchpad_hover_noevent, LITEST_SYNAPTICS_HOVER_SEMI_MT); + litest_add_for_device("touchpad:hover", touchpad_hover_down, LITEST_SYNAPTICS_HOVER_SEMI_MT); + litest_add_for_device("touchpad:hover", touchpad_hover_down_hover_down, LITEST_SYNAPTICS_HOVER_SEMI_MT); + litest_add_for_device("touchpad:hover", touchpad_hover_2fg_noevent, LITEST_SYNAPTICS_HOVER_SEMI_MT); + litest_add_for_device("touchpad:hover", touchpad_hover_2fg_1fg_down, LITEST_SYNAPTICS_HOVER_SEMI_MT); + return litest_run(argc, argv); } From 09d07d5634215d480df2716663d3b9c85f0b5b14 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 6 Jan 2015 13:33:38 +1000 Subject: [PATCH 07/15] test: add another hover test Release one touch point at the same time as a fake touch. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- test/touchpad.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/test/touchpad.c b/test/touchpad.c index 3b3c64ee..b8e2df81 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -2426,6 +2426,73 @@ START_TEST(touchpad_hover_down_hover_down) } END_TEST +START_TEST(touchpad_hover_down_up) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + int i; + int x = 1400, + y = 1400; + + litest_drain_events(li); + + /* hover two fingers, then touch */ + hover_start(dev, 0, x, y); + litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_assert_empty_queue(li); + + hover_start(dev, 1, x, y); + litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0); + litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_assert_empty_queue(li); + + litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0); + litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1); + litest_event(dev, EV_KEY, BTN_TOUCH, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + litest_assert_empty_queue(li); + + /* hover first finger, end second in same frame */ + litest_event(dev, EV_ABS, ABS_MT_SLOT, 1); + litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); + litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 0); + litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 1); + litest_event(dev, EV_KEY, BTN_TOUCH, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + litest_assert_empty_queue(li); + + litest_event(dev, EV_KEY, BTN_TOUCH, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + + /* now move the finger */ + for (i = 0; i < 10; i++) { + litest_event(dev, EV_ABS, ABS_MT_SLOT, 0); + litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x); + litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y); + litest_event(dev, EV_ABS, ABS_X, x); + litest_event(dev, EV_ABS, ABS_Y, y); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + x -= 100; + y -= 100; + } + + litest_assert_only_typed_events(li, + LIBINPUT_EVENT_POINTER_MOTION); + + litest_event(dev, EV_ABS, ABS_MT_SLOT, 0); + litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); + litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0); + litest_event(dev, EV_KEY, BTN_TOUCH, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); +} +END_TEST + START_TEST(touchpad_hover_2fg_noevent) { struct litest_device *dev = litest_current_device(); @@ -2611,6 +2678,7 @@ int main(int argc, char **argv) { * ignore the semi-mt capability (it doesn't matter for the tests */ litest_add_for_device("touchpad:hover", touchpad_hover_noevent, LITEST_SYNAPTICS_HOVER_SEMI_MT); litest_add_for_device("touchpad:hover", touchpad_hover_down, LITEST_SYNAPTICS_HOVER_SEMI_MT); + litest_add_for_device("touchpad:hover", touchpad_hover_down_up, LITEST_SYNAPTICS_HOVER_SEMI_MT); litest_add_for_device("touchpad:hover", touchpad_hover_down_hover_down, LITEST_SYNAPTICS_HOVER_SEMI_MT); litest_add_for_device("touchpad:hover", touchpad_hover_2fg_noevent, LITEST_SYNAPTICS_HOVER_SEMI_MT); litest_add_for_device("touchpad:hover", touchpad_hover_2fg_1fg_down, LITEST_SYNAPTICS_HOVER_SEMI_MT); From aee7ba8360ec9aa36a7a3880329d54c8105820e9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 14 Jan 2015 10:17:06 +0100 Subject: [PATCH 08/15] touchpad: Allow the center of pinned fingers to drift over time Allow the center of pinned fingers to drift over time, to avoid accidentally unpinning fingers. BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=86807 Signed-off-by: Hans de Goede Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index bdd8f9ef..53a0bf21 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -385,7 +385,12 @@ tp_unpin_finger(struct tp_dispatch *tp, struct tp_touch *t) tp->buttons.motion_dist * tp->buttons.motion_dist) { t->pinned.is_pinned = false; tp_set_pointer(tp, t); + return; } + + /* The finger may slowly drift, adjust the center */ + t->pinned.center_x = t->x + t->pinned.center_x / 2; + t->pinned.center_y = t->y + t->pinned.center_y / 2; } static void From c8ec33e72a5146b60485e72264d496aba3299752 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 3 Dec 2014 14:45:26 +1000 Subject: [PATCH 09/15] Add a config interface for click methods Two methods are provided: * button area - used on most clickpads, a click with a touch within a given area generates left/middle/right clicks * clickfinger - used on apple touchpads, a click with 1/2/3 fingers on the touchpad generates a left, right, middle click Both methods already exist in the touchpad code, this is just the configuration interface. Signed-off-by: Peter Hutterer --- src/libinput-private.h | 9 ++++ src/libinput.c | 50 ++++++++++++++++++++ src/libinput.h | 102 +++++++++++++++++++++++++++++++++++++++++ src/libinput.sym | 4 ++ 4 files changed, 165 insertions(+) diff --git a/src/libinput-private.h b/src/libinput-private.h index 012c82d0..b938ed09 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -146,6 +146,14 @@ struct libinput_device_config_scroll_method { uint32_t (*get_default_button)(struct libinput_device *device); }; +struct libinput_device_config_click_method { + uint32_t (*get_methods)(struct libinput_device *device); + enum libinput_config_status (*set_method)(struct libinput_device *device, + enum libinput_config_click_method method); + enum libinput_config_click_method (*get_method)(struct libinput_device *device); + enum libinput_config_click_method (*get_default_method)(struct libinput_device *device); +}; + struct libinput_device_config { struct libinput_device_config_tap *tap; struct libinput_device_config_calibration *calibration; @@ -154,6 +162,7 @@ struct libinput_device_config { struct libinput_device_config_natural_scroll *natural_scroll; struct libinput_device_config_left_handed *left_handed; struct libinput_device_config_scroll_method *scroll_method; + struct libinput_device_config_click_method *click_method; }; struct libinput_device { diff --git a/src/libinput.c b/src/libinput.c index 6f45405e..951698a0 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -1635,6 +1635,56 @@ libinput_device_config_left_handed_get_default(struct libinput_device *device) return device->config.left_handed->get_default(device); } +LIBINPUT_EXPORT uint32_t +libinput_device_config_click_get_methods(struct libinput_device *device) +{ + if (device->config.click_method) + return device->config.click_method->get_methods(device); + else + return 0; +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_click_set_method(struct libinput_device *device, + enum libinput_config_click_method method) +{ + if ((libinput_device_config_click_get_methods(device) & method) != method) + return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; + + /* Check method is a single valid method */ + switch (method) { + case LIBINPUT_CONFIG_CLICK_METHOD_NONE: + case LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS: + case LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER: + break; + default: + return LIBINPUT_CONFIG_STATUS_INVALID; + } + + if (device->config.click_method) + return device->config.click_method->set_method(device, method); + else /* method must be _NONE to get here */ + return LIBINPUT_CONFIG_STATUS_SUCCESS; +} + +LIBINPUT_EXPORT enum libinput_config_click_method +libinput_device_config_click_get_method(struct libinput_device *device) +{ + if (device->config.click_method) + return device->config.click_method->get_method(device); + else + return LIBINPUT_CONFIG_CLICK_METHOD_NONE; +} + +LIBINPUT_EXPORT enum libinput_config_click_method +libinput_device_config_click_get_default_method(struct libinput_device *device) +{ + if (device->config.click_method) + return device->config.click_method->get_default_method(device); + else + return LIBINPUT_CONFIG_CLICK_METHOD_NONE; +} + LIBINPUT_EXPORT uint32_t libinput_device_config_scroll_get_methods(struct libinput_device *device) { diff --git a/src/libinput.h b/src/libinput.h index dbc4b2e2..7b7a2dbf 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -2176,6 +2176,108 @@ libinput_device_config_left_handed_get(struct libinput_device *device); int libinput_device_config_left_handed_get_default(struct libinput_device *device); +/** + * @ingroup config + * + * The click method defines when to generate software-emulated + * buttons, usually on a device that does not have a specific physical + * button available. + */ +enum libinput_config_click_method { + /** + * Do not send software-emulated button events. This has no effect + * on physical button generations. + */ + LIBINPUT_CONFIG_CLICK_METHOD_NONE = 0, + /** + * Use software-button areas (see @ref clickfinger) to generate + * button events. + */ + LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS = (1 << 0), + /** + * The number of fingers decides which button press to generate. + */ + LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER = (1 << 1), +}; + +/** + * @ingroup config + * + * Check which button click methods a device supports. The button click + * method defines when to generate software-emulated buttons, usually on a + * device that does not have a specific physical button available. + * + * @param device The device to configure + * + * @return A bitmask of possible methods. + * + * @see libinput_device_config_click_get_methods + * @see libinput_device_config_click_set_method + * @see libinput_device_config_click_get_method + */ +uint32_t +libinput_device_config_click_get_methods(struct libinput_device *device); + +/** + * @ingroup config + * + * Set the button click method for this device. The button click + * method defines when to generate software-emulated buttons, usually on a + * device that does not have a specific physical button available. + * + * @note The selected click method may not take effect immediately. The + * device may require changing to a neutral state first before activating + * the new method. + * + * @param device The device to configure + * @param method The button click method + * + * @return A config status code + * + * @see libinput_device_config_click_get_methods + * @see libinput_device_config_click_get_method + * @see libinput_device_config_click_get_default_method + */ +enum libinput_config_status +libinput_device_config_click_set_method(struct libinput_device *device, + enum libinput_config_click_method method); +/** + * @ingroup config + * + * Get the button click method for this device. The button click + * method defines when to generate software-emulated buttons, usually on a + * device that does not have a specific physical button available. + * + * @param device The device to configure + * + * @return The current button click method for this device + * + * @see libinput_device_config_click_get_methods + * @see libinput_device_config_click_set_method + * @see libinput_device_config_click_get_default_method + */ +enum libinput_config_click_method +libinput_device_config_click_get_method(struct libinput_device *device); + +/** + * @ingroup config + * + * Get the default button click method for this device. The button click + * method defines when to generate software-emulated buttons, usually on a + * device that does not have a specific physical button available. + * + * @param device The device to configure + * + * @return The default button click method for this device + * + * @see libinput_device_config_click_get_methods + * @see libinput_device_config_click_set_method + * @see libinput_device_config_click_get_method + */ +enum libinput_config_click_method +libinput_device_config_click_get_default_method(struct libinput_device *device); + + /** * @ingroup config * diff --git a/src/libinput.sym b/src/libinput.sym index 018578d6..9be6cf4e 100644 --- a/src/libinput.sym +++ b/src/libinput.sym @@ -15,6 +15,10 @@ global: libinput_device_config_calibration_get_matrix; libinput_device_config_calibration_has_matrix; libinput_device_config_calibration_set_matrix; + libinput_device_config_click_get_default_method; + libinput_device_config_click_get_method; + libinput_device_config_click_get_methods; + libinput_device_config_click_set_method; libinput_device_config_scroll_get_button; libinput_device_config_scroll_get_default_button; libinput_device_config_scroll_get_default_method; From 0c50e186a05e831e1baaefa3889ef17b940504a8 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 14 Jan 2015 14:54:43 +0100 Subject: [PATCH 10/15] touchpad: hook up click method configuration Allow switching between softbuttons and clickfinger on any mt-capable clickpad. Signed-off-by: Peter Hutterer [hdegoede@redhat.com] Keep top softbuttons working when enabling clickfinger [hdegoede@redhat.com] Simply touchpad click method switching Signed-off-by: Hans de Goede --- doc/clickpad-softbuttons.dox | 6 + src/evdev-mt-touchpad-buttons.c | 216 ++++++++++++++++++++++---------- src/evdev-mt-touchpad.c | 4 +- src/evdev-mt-touchpad.h | 11 +- 4 files changed, 164 insertions(+), 73 deletions(-) diff --git a/doc/clickpad-softbuttons.dox b/doc/clickpad-softbuttons.dox index 2653c3b7..d9ebfbbc 100644 --- a/doc/clickpad-softbuttons.dox +++ b/doc/clickpad-softbuttons.dox @@ -66,6 +66,12 @@ The Xorg synaptics driver uses 30% of the touchpad dimensions as threshold, libinput does not have this restriction. If two fingers are on the pad while clicking, that is a two-finger click. +Clickfinger configuration can be enabled through the +libinput_device_config_click_set_method() call. If clickfingers are +enabled on a touchpad with top software buttons, the top area will keep +acting as softbuttons for use with the trackpoint. Clickfingers will be used +everywhere else on the touchpad. + @section special_clickpads Special Clickpads The Lenovo *40 series laptops have a clickpad that provides two software button sections, one at diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index 6af3fcf1..ca7495f8 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -494,10 +494,9 @@ tp_release_all_buttons(struct tp_dispatch *tp, } } -void +static void tp_init_softbuttons(struct tp_dispatch *tp, - struct evdev_device *device, - double topbutton_size_mult) + struct evdev_device *device) { int width, height; const struct input_absinfo *absinfo_x, *absinfo_y; @@ -523,6 +522,26 @@ tp_init_softbuttons(struct tp_dispatch *tp, } tp->buttons.bottom_area.rightbutton_left_edge = width/2 + xoffset; +} + +void +tp_init_top_softbuttons(struct tp_dispatch *tp, + struct evdev_device *device, + double topbutton_size_mult) +{ + int width, height; + const struct input_absinfo *absinfo_x, *absinfo_y; + int xoffset, yoffset; + int yres; + + absinfo_x = device->abs.absinfo_x; + absinfo_y = device->abs.absinfo_y; + + xoffset = absinfo_x->minimum, + yoffset = absinfo_y->minimum; + yres = absinfo_y->resolution; + width = abs(absinfo_x->maximum - absinfo_x->minimum); + height = abs(absinfo_y->maximum - absinfo_y->minimum); if (tp->buttons.has_topbuttons) { /* T440s has the top button line 5mm from the top, event @@ -545,6 +564,89 @@ tp_init_softbuttons(struct tp_dispatch *tp, } } +static inline uint32_t +tp_button_config_click_get_methods(struct libinput_device *device) +{ + struct evdev_device *evdev = (struct evdev_device*)device; + struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch; + uint32_t methods = LIBINPUT_CONFIG_CLICK_METHOD_NONE; + + if (tp->buttons.is_clickpad) { + methods |= LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; + if (tp->has_mt) + methods |= LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER; + } + + return methods; +} + +static void +tp_switch_click_method(struct tp_dispatch *tp) +{ + /* + * All we need to do when switching click methods is to change the + * bottom_area.top_edge so that when in clickfinger mode the bottom + * touchpad area is not dead wrt finger movement starting there. + * + * We do not need to take any state into account, fingers which are + * already down will simply keep the state / area they have assigned + * until they are released, and the post_button_events path is state + * agnostic. + */ + + switch (tp->buttons.click_method) { + case LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS: + tp_init_softbuttons(tp, tp->device); + break; + case LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER: + case LIBINPUT_CONFIG_CLICK_METHOD_NONE: + tp->buttons.bottom_area.top_edge = INT_MAX; + break; + } +} + +static enum libinput_config_status +tp_button_config_click_set_method(struct libinput_device *device, + enum libinput_config_click_method method) +{ + struct evdev_device *evdev = (struct evdev_device*)device; + struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch; + + tp->buttons.click_method = method; + tp_switch_click_method(tp); + + return LIBINPUT_CONFIG_STATUS_SUCCESS; +} + +static enum libinput_config_click_method +tp_button_config_click_get_method(struct libinput_device *device) +{ + struct evdev_device *evdev = (struct evdev_device*)device; + struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch; + + return tp->buttons.click_method; +} + +static enum libinput_config_click_method +tp_click_get_default_method(struct tp_dispatch *tp) +{ + if (!tp->buttons.is_clickpad) + return LIBINPUT_CONFIG_CLICK_METHOD_NONE; + else if (libevdev_get_id_vendor(tp->device->evdev) == VENDOR_ID_APPLE) + return LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER; + else + return LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; +} + +static enum libinput_config_click_method +tp_button_config_click_get_default_method(struct libinput_device *device) +{ + struct evdev_device *evdev = (struct evdev_device*)device; + struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch; + + return tp_click_get_default_method(tp); +} + int tp_init_buttons(struct tp_dispatch *tp, struct evdev_device *device) @@ -582,15 +684,16 @@ tp_init_buttons(struct tp_dispatch *tp, tp->buttons.motion_dist = diagonal * DEFAULT_BUTTON_MOTION_THRESHOLD; - if (libevdev_get_id_vendor(device->evdev) == VENDOR_ID_APPLE) - tp->buttons.use_clickfinger = true; + tp->buttons.config_method.get_methods = tp_button_config_click_get_methods; + tp->buttons.config_method.set_method = tp_button_config_click_set_method; + tp->buttons.config_method.get_method = tp_button_config_click_get_method; + tp->buttons.config_method.get_default_method = tp_button_config_click_get_default_method; + tp->device->base.config.click_method = &tp->buttons.config_method; - if (tp->buttons.is_clickpad && !tp->buttons.use_clickfinger) { - tp_init_softbuttons(tp, device, 1.0); - } else { - tp->buttons.bottom_area.top_edge = INT_MAX; - tp->buttons.top_area.bottom_edge = INT_MIN; - } + tp->buttons.click_method = tp_click_get_default_method(tp); + tp_switch_click_method(tp); + + tp_init_top_softbuttons(tp, device, 1.0); tp_for_each_touch(tp, t) { t->button.state = BUTTON_STATE_NONE; @@ -611,43 +714,6 @@ tp_remove_buttons(struct tp_dispatch *tp) libinput_timer_cancel(&t->button.timer); } -static int -tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint64_t time) -{ - uint32_t current, old, button; - enum libinput_button_state state; - - current = tp->buttons.state; - old = tp->buttons.old_state; - - if (current == old) - return 0; - - if (current) { - switch (tp->nfingers_down) { - case 1: button = BTN_LEFT; break; - case 2: button = BTN_RIGHT; break; - case 3: button = BTN_MIDDLE; break; - default: - return 0; - } - tp->buttons.active = button; - state = LIBINPUT_BUTTON_STATE_PRESSED; - } else { - button = tp->buttons.active; - tp->buttons.active = 0; - state = LIBINPUT_BUTTON_STATE_RELEASED; - } - - if (button) { - evdev_pointer_notify_button(tp->device, - time, - button, - state); - } - return 1; -} - static int tp_post_physical_buttons(struct tp_dispatch *tp, uint64_t time) { @@ -683,12 +749,12 @@ tp_post_physical_buttons(struct tp_dispatch *tp, uint64_t time) return 0; } -static void -tp_notify_softbutton(struct tp_dispatch *tp, - uint64_t time, - uint32_t button, - uint32_t is_topbutton, - enum libinput_button_state state) +static int +tp_notify_clickpadbutton(struct tp_dispatch *tp, + uint64_t time, + uint32_t button, + uint32_t is_topbutton, + enum libinput_button_state state) { /* If we've a trackpoint, send top buttons through the trackpoint */ if (is_topbutton && tp->buttons.trackpoint) { @@ -702,18 +768,38 @@ tp_notify_softbutton(struct tp_dispatch *tp, event.value = (state == LIBINPUT_BUTTON_STATE_PRESSED) ? 1 : 0; dispatch->interface->process(dispatch, tp->buttons.trackpoint, &event, time); - return; + return 1; } /* Ignore button events not for the trackpoint while suspended */ if (tp->device->suspended) - return; + return 0; + + /* + * If the user has requested clickfinger replace the button chosen + * by the softbutton code with one based on the number of fingers. + */ + if (tp->buttons.click_method == LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER && + state == LIBINPUT_BUTTON_STATE_PRESSED) { + switch (tp->nfingers_down) { + case 1: button = BTN_LEFT; break; + case 2: button = BTN_RIGHT; break; + case 3: button = BTN_MIDDLE; break; + default: + button = 0; + } + tp->buttons.active = button; + + if (!button) + return 0; + } evdev_pointer_notify_button(tp->device, time, button, state); + return 1; } static int -tp_post_softbutton_buttons(struct tp_dispatch *tp, uint64_t time) +tp_post_clickpadbutton_buttons(struct tp_dispatch *tp, uint64_t time) { uint32_t current, old, button, is_top; enum libinput_button_state state; @@ -783,22 +869,18 @@ tp_post_softbutton_buttons(struct tp_dispatch *tp, uint64_t time) tp->buttons.click_pending = false; if (button) - tp_notify_softbutton(tp, time, button, is_top, state); + return tp_notify_clickpadbutton(tp, time, button, is_top, state); - return 1; + return 0; } int tp_post_button_events(struct tp_dispatch *tp, uint64_t time) { - if (tp->buttons.is_clickpad) { - if (tp->buttons.use_clickfinger) - return tp_post_clickfinger_buttons(tp, time); - else - return tp_post_softbutton_buttons(tp, time); - } - - return tp_post_physical_buttons(tp, time); + if (tp->buttons.is_clickpad) + return tp_post_clickpadbutton_buttons(tp, time); + else + return tp_post_physical_buttons(tp, time); } int diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 53a0bf21..5221be60 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -938,7 +938,7 @@ tp_suspend(struct tp_dispatch *tp, struct evdev_device *device) if (tp->buttons.has_topbuttons) { evdev_notify_suspended_device(device); /* Enlarge topbutton area while suspended */ - tp_init_softbuttons(tp, device, 1.5); + tp_init_top_softbuttons(tp, device, 1.5); } else { evdev_device_suspend(device); } @@ -951,7 +951,7 @@ tp_resume(struct tp_dispatch *tp, struct evdev_device *device) /* tap state-machine is offline while suspended, reset state */ tp_clear_state(tp); /* restore original topbutton area size */ - tp_init_softbuttons(tp, device, 1.0); + tp_init_top_softbuttons(tp, device, 1.0); evdev_notify_resumed_device(device); } else { evdev_device_resume(device); diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 7fe152a3..3479e5ea 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -243,7 +243,10 @@ struct tp_dispatch { } top_area; struct evdev_device *trackpoint; - } buttons; /* physical buttons */ + + enum libinput_config_click_method click_method; + struct libinput_device_config_click_method config_method; + } buttons; struct { struct libinput_device_config_scroll_method config_method; @@ -306,9 +309,9 @@ int tp_init_buttons(struct tp_dispatch *tp, struct evdev_device *device); void -tp_init_softbuttons(struct tp_dispatch *tp, - struct evdev_device *device, - double topbutton_size_mult); +tp_init_top_softbuttons(struct tp_dispatch *tp, + struct evdev_device *device, + double topbutton_size_mult); void tp_remove_buttons(struct tp_dispatch *tp); From fb451d4816f5f1026e5e88a052214b4ada2430f8 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 4 Dec 2014 11:22:41 +1000 Subject: [PATCH 11/15] test: add tests for clickfinger defaults Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- test/touchpad.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/test/touchpad.c b/test/touchpad.c index b8e2df81..9cbf99e6 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -711,6 +711,87 @@ START_TEST(touchpad_3fg_tap_btntool_inverted) } END_TEST +START_TEST(touchpad_click_defaults_clickfinger) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_device *device = dev->libinput_device; + uint32_t methods, method; + enum libinput_config_status status; + + /* call this test for apple touchpads */ + + methods = libinput_device_config_click_get_methods(device); + ck_assert(methods & LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS); + ck_assert(methods & LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); + + method = libinput_device_config_click_get_method(device); + ck_assert_int_eq(method, LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); + method = libinput_device_config_click_get_default_method(device); + ck_assert_int_eq(method, LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); + + status = libinput_device_config_click_set_method(device, + LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + status = libinput_device_config_click_set_method(device, + LIBINPUT_CONFIG_CLICK_METHOD_NONE); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); +} +END_TEST + +START_TEST(touchpad_click_defaults_btnarea) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_device *device = dev->libinput_device; + uint32_t methods, method; + enum libinput_config_status status; + + /* call this test for non-apple clickpads */ + + methods = libinput_device_config_click_get_methods(device); + ck_assert(methods & LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); + ck_assert(methods & LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS); + + method = libinput_device_config_click_get_method(device); + ck_assert_int_eq(method, LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS); + method = libinput_device_config_click_get_default_method(device); + ck_assert_int_eq(method, LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS); + + status = libinput_device_config_click_set_method(device, + LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + status = libinput_device_config_click_set_method(device, + LIBINPUT_CONFIG_CLICK_METHOD_NONE); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); +} +END_TEST + +START_TEST(touchpad_click_defaults_none) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_device *device = dev->libinput_device; + uint32_t methods, method; + enum libinput_config_status status; + + /* call this test for non-clickpads */ + + methods = libinput_device_config_click_get_methods(device); + ck_assert_int_eq(methods, 0); + + method = libinput_device_config_click_get_method(device); + ck_assert_int_eq(method, LIBINPUT_CONFIG_CLICK_METHOD_NONE); + method = libinput_device_config_click_get_default_method(device); + ck_assert_int_eq(method, LIBINPUT_CONFIG_CLICK_METHOD_NONE); + + status = libinput_device_config_click_set_method(device, + LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED); + status = libinput_device_config_click_set_method(device, + LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED); +} +END_TEST + + START_TEST(touchpad_1fg_clickfinger) { struct litest_device *dev = litest_create_device(LITEST_BCM5974); @@ -2628,6 +2709,10 @@ int main(int argc, char **argv) { litest_add_no_device("touchpad:clickfinger", touchpad_1fg_clickfinger); litest_add_no_device("touchpad:clickfinger", touchpad_2fg_clickfinger); + litest_add("touchpad:click", touchpad_click_defaults_clickfinger, LITEST_APPLE_CLICKPAD, LITEST_ANY); + litest_add("touchpad:click", touchpad_click_defaults_btnarea, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD); + litest_add("touchpad:click", touchpad_click_defaults_none, LITEST_TOUCHPAD, LITEST_CLICKPAD); + litest_add("touchpad:click", touchpad_btn_left, LITEST_TOUCHPAD, 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); From 5adf0aa2ad75295a317d3e57a402f96d9ed5ed7b Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 4 Dec 2014 11:47:32 +1000 Subject: [PATCH 12/15] test: run clickfinger test for all clickpad-capable devices Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- test/touchpad.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/test/touchpad.c b/test/touchpad.c index 9cbf99e6..1b0e121e 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -794,8 +794,13 @@ END_TEST START_TEST(touchpad_1fg_clickfinger) { - struct litest_device *dev = litest_create_device(LITEST_BCM5974); + struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; + enum libinput_config_status status; + + status = libinput_device_config_click_set_method(dev->libinput_device, + LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); litest_drain_events(li); @@ -812,15 +817,18 @@ START_TEST(touchpad_1fg_clickfinger) LIBINPUT_BUTTON_STATE_PRESSED); litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_RELEASED); - - litest_delete_device(dev); } END_TEST START_TEST(touchpad_2fg_clickfinger) { - struct litest_device *dev = litest_create_device(LITEST_BCM5974); + struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; + enum libinput_config_status status; + + status = libinput_device_config_click_set_method(dev->libinput_device, + LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); litest_drain_events(li); @@ -839,8 +847,6 @@ START_TEST(touchpad_2fg_clickfinger) LIBINPUT_BUTTON_STATE_PRESSED); litest_assert_button_event(li, BTN_RIGHT, LIBINPUT_BUTTON_STATE_RELEASED); - - litest_delete_device(dev); } END_TEST @@ -2706,8 +2712,8 @@ int main(int argc, char **argv) { litest_add("touchpad:tap", clickpad_1fg_tap_click, LITEST_CLICKPAD, LITEST_ANY); litest_add("touchpad:tap", clickpad_2fg_tap_click, LITEST_CLICKPAD, LITEST_SINGLE_TOUCH|LITEST_APPLE_CLICKPAD); - litest_add_no_device("touchpad:clickfinger", touchpad_1fg_clickfinger); - litest_add_no_device("touchpad:clickfinger", touchpad_2fg_clickfinger); + litest_add("touchpad:clickfinger", touchpad_1fg_clickfinger, LITEST_CLICKPAD, LITEST_ANY); + litest_add("touchpad:clickfinger", touchpad_2fg_clickfinger, LITEST_CLICKPAD, LITEST_ANY); litest_add("touchpad:click", touchpad_click_defaults_clickfinger, LITEST_APPLE_CLICKPAD, LITEST_ANY); litest_add("touchpad:click", touchpad_click_defaults_btnarea, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD); From 5c7f2a19498de2ff18adb3144be684cb7fa2534f Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 4 Dec 2014 14:40:53 +1000 Subject: [PATCH 13/15] tests: add a few clickfinger tests Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- test/touchpad.c | 293 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 293 insertions(+) diff --git a/test/touchpad.c b/test/touchpad.c index 1b0e121e..ab9a12e0 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -850,6 +850,198 @@ START_TEST(touchpad_2fg_clickfinger) } END_TEST +START_TEST(touchpad_clickfinger_to_area_method) +{ + struct litest_device *dev = litest_current_device(); + enum libinput_config_status status; + struct libinput *li = dev->libinput; + + litest_drain_events(li); + + status = libinput_device_config_click_set_method(dev->libinput_device, + LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + + litest_touch_down(dev, 0, 90, 90); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_event(dev, EV_KEY, BTN_LEFT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_touch_up(dev, 0); + libinput_dispatch(li); + + litest_assert_button_event(li, BTN_RIGHT, + LIBINPUT_BUTTON_STATE_PRESSED); + litest_assert_button_event(li, BTN_RIGHT, + LIBINPUT_BUTTON_STATE_RELEASED); + + status = libinput_device_config_click_set_method(dev->libinput_device, + LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + + litest_drain_events(li); + + /* use bottom right corner to catch accidental softbutton right */ + litest_touch_down(dev, 0, 90, 90); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_event(dev, EV_KEY, BTN_LEFT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_touch_up(dev, 0); + libinput_dispatch(li); + + litest_assert_button_event(li, BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + litest_assert_button_event(li, BTN_LEFT, + LIBINPUT_BUTTON_STATE_RELEASED); + +} +END_TEST + +START_TEST(touchpad_clickfinger_to_area_method_while_down) +{ + struct litest_device *dev = litest_current_device(); + enum libinput_config_status status; + struct libinput *li = dev->libinput; + + litest_drain_events(li); + + status = libinput_device_config_click_set_method(dev->libinput_device, + LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + + litest_touch_down(dev, 0, 90, 90); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + litest_assert_button_event(li, BTN_RIGHT, + LIBINPUT_BUTTON_STATE_PRESSED); + + status = libinput_device_config_click_set_method(dev->libinput_device, + LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + + litest_event(dev, EV_KEY, BTN_LEFT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_touch_up(dev, 0); + libinput_dispatch(li); + + litest_assert_button_event(li, BTN_RIGHT, + LIBINPUT_BUTTON_STATE_RELEASED); + + + litest_drain_events(li); + + /* use bottom right corner to catch accidental softbutton right */ + litest_touch_down(dev, 0, 90, 90); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_event(dev, EV_KEY, BTN_LEFT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_touch_up(dev, 0); + libinput_dispatch(li); + + litest_assert_button_event(li, BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + litest_assert_button_event(li, BTN_LEFT, + LIBINPUT_BUTTON_STATE_RELEASED); + +} +END_TEST + +START_TEST(touchpad_area_to_clickfinger_method) +{ + struct litest_device *dev = litest_current_device(); + enum libinput_config_status status; + struct libinput *li = dev->libinput; + + status = libinput_device_config_click_set_method(dev->libinput_device, + LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + + litest_drain_events(li); + + /* use bottom right corner to catch accidental softbutton right */ + litest_touch_down(dev, 0, 90, 90); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_event(dev, EV_KEY, BTN_LEFT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_touch_up(dev, 0); + libinput_dispatch(li); + + litest_assert_button_event(li, BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + litest_assert_button_event(li, BTN_LEFT, + LIBINPUT_BUTTON_STATE_RELEASED); + + status = libinput_device_config_click_set_method(dev->libinput_device, + LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + + litest_touch_down(dev, 0, 90, 90); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_event(dev, EV_KEY, BTN_LEFT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_touch_up(dev, 0); + libinput_dispatch(li); + + litest_assert_button_event(li, BTN_RIGHT, + LIBINPUT_BUTTON_STATE_PRESSED); + litest_assert_button_event(li, BTN_RIGHT, + LIBINPUT_BUTTON_STATE_RELEASED); + +} +END_TEST + +START_TEST(touchpad_area_to_clickfinger_method_while_down) +{ + struct litest_device *dev = litest_current_device(); + enum libinput_config_status status; + struct libinput *li = dev->libinput; + + status = libinput_device_config_click_set_method(dev->libinput_device, + LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + + litest_drain_events(li); + + /* use bottom right corner to catch accidental softbutton right */ + litest_touch_down(dev, 0, 90, 90); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_assert_button_event(li, BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + + status = libinput_device_config_click_set_method(dev->libinput_device, + LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + + litest_event(dev, EV_KEY, BTN_LEFT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_touch_up(dev, 0); + libinput_dispatch(li); + + litest_assert_button_event(li, BTN_LEFT, + LIBINPUT_BUTTON_STATE_RELEASED); + + litest_touch_down(dev, 0, 90, 90); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_event(dev, EV_KEY, BTN_LEFT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_touch_up(dev, 0); + libinput_dispatch(li); + + litest_assert_button_event(li, BTN_RIGHT, + LIBINPUT_BUTTON_STATE_PRESSED); + litest_assert_button_event(li, BTN_RIGHT, + LIBINPUT_BUTTON_STATE_RELEASED); + +} +END_TEST + START_TEST(touchpad_btn_left) { struct litest_device *dev = litest_current_device(); @@ -1458,6 +1650,99 @@ START_TEST(clickpad_topsoftbuttons_move_out_ignore) } END_TEST +START_TEST(clickpad_topsoftbuttons_clickfinger) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + libinput_device_config_click_set_method(dev->libinput_device, + LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); + litest_drain_events(li); + + litest_touch_down(dev, 0, 90, 5); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_event(dev, EV_KEY, BTN_LEFT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + 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, 90, 5); + litest_touch_down(dev, 1, 10, 5); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_event(dev, EV_KEY, BTN_LEFT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_touch_up(dev, 0); + litest_touch_up(dev, 1); + + litest_assert_button_event(li, + BTN_RIGHT, + LIBINPUT_BUTTON_STATE_PRESSED); + litest_assert_button_event(li, + BTN_RIGHT, + LIBINPUT_BUTTON_STATE_RELEASED); +} +END_TEST + +START_TEST(clickpad_topsoftbuttons_clickfinger_dev_disabled) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct litest_device *trackpoint = litest_add_device(li, + LITEST_TRACKPOINT); + + libinput_device_config_click_set_method(dev->libinput_device, + LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); + libinput_device_config_send_events_set_mode(dev->libinput_device, + LIBINPUT_CONFIG_SEND_EVENTS_DISABLED); + litest_drain_events(li); + + litest_touch_down(dev, 0, 90, 5); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_event(dev, EV_KEY, BTN_LEFT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_touch_up(dev, 0); + + litest_assert_button_event(li, + BTN_RIGHT, + LIBINPUT_BUTTON_STATE_PRESSED); + litest_assert_button_event(li, + BTN_RIGHT, + LIBINPUT_BUTTON_STATE_RELEASED); + + litest_assert_empty_queue(li); + + litest_touch_down(dev, 0, 90, 5); + litest_touch_down(dev, 1, 10, 5); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_event(dev, EV_KEY, BTN_LEFT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_touch_up(dev, 0); + litest_touch_up(dev, 1); + + litest_assert_button_event(li, + BTN_MIDDLE, + LIBINPUT_BUTTON_STATE_PRESSED); + litest_assert_button_event(li, + BTN_MIDDLE, + LIBINPUT_BUTTON_STATE_RELEASED); + + litest_delete_device(trackpoint); +} +END_TEST + + static void test_2fg_scroll(struct litest_device *dev, double dx, double dy, int want_sleep) { @@ -2714,6 +2999,12 @@ int main(int argc, char **argv) { litest_add("touchpad:clickfinger", touchpad_1fg_clickfinger, LITEST_CLICKPAD, LITEST_ANY); litest_add("touchpad:clickfinger", touchpad_2fg_clickfinger, LITEST_CLICKPAD, LITEST_ANY); + litest_add("touchpad:clickfinger", touchpad_clickfinger_to_area_method, LITEST_CLICKPAD, LITEST_ANY); + litest_add("touchpad:clickfinger", + touchpad_clickfinger_to_area_method_while_down, LITEST_CLICKPAD, LITEST_ANY); + litest_add("touchpad:clickfinger", touchpad_area_to_clickfinger_method, LITEST_CLICKPAD, LITEST_ANY); + litest_add("touchpad:clickfinger", + touchpad_area_to_clickfinger_method_while_down, LITEST_CLICKPAD, LITEST_ANY); litest_add("touchpad:click", touchpad_click_defaults_clickfinger, LITEST_APPLE_CLICKPAD, LITEST_ANY); litest_add("touchpad:click", touchpad_click_defaults_btnarea, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD); @@ -2736,6 +3027,8 @@ int main(int argc, char **argv) { litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_right, LITEST_TOPBUTTONPAD, LITEST_ANY); litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_middle, LITEST_TOPBUTTONPAD, LITEST_ANY); litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_move_out_ignore, LITEST_TOPBUTTONPAD, LITEST_ANY); + litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_clickfinger, LITEST_TOPBUTTONPAD, LITEST_ANY); + litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_clickfinger_dev_disabled, LITEST_TOPBUTTONPAD, LITEST_ANY); litest_add("touchpad:scroll", touchpad_2fg_scroll, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add("touchpad:scroll", touchpad_2fg_scroll_slow_distance, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); From 7ce25592d9282e8435885416f46e98bb3d62807f Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 16 Jan 2015 10:16:47 +1000 Subject: [PATCH 14/15] tools: add click method config to the tools Signed-off-by: Peter Hutterer --- tools/shared.c | 26 ++++++++++++++++++++++++++ tools/shared.h | 1 + 2 files changed, 27 insertions(+) diff --git a/tools/shared.c b/tools/shared.c index b4f41d04..2cff52c4 100644 --- a/tools/shared.c +++ b/tools/shared.c @@ -43,6 +43,7 @@ enum options { OPT_NATURAL_SCROLL_DISABLE, OPT_LEFT_HANDED_ENABLE, OPT_LEFT_HANDED_DISABLE, + OPT_CLICK_METHOD, }; static void @@ -69,6 +70,7 @@ tools_usage() "--disable-natural-scrolling.... enable/disable natural scrolling\n" "--enable-left-handed\n" "--disable-left-handed.... enable/disable left-handed button configuration\n" + "--set-click-method=[none|clickfinger|buttonareas] .... set the desired click method\n" "\n" "These options apply to all applicable devices, if a feature\n" "is not explicitly specified it is left at each device's default.\n" @@ -86,6 +88,7 @@ tools_init_options(struct tools_options *options) options->tapping = -1; options->natural_scroll = -1; options->left_handed = -1; + options->click_method = -1; options->backend = BACKEND_UDEV; options->seat = "seat0"; } @@ -107,6 +110,7 @@ tools_parse_args(int argc, char **argv, struct tools_options *options) { "disable-natural-scrolling", 0, 0, OPT_NATURAL_SCROLL_DISABLE }, { "enable-left-handed", 0, 0, OPT_LEFT_HANDED_ENABLE }, { "disable-left-handed", 0, 0, OPT_LEFT_HANDED_DISABLE }, + { "set-click-method", 1, 0, OPT_CLICK_METHOD }, { 0, 0, 0, 0} }; @@ -153,6 +157,25 @@ tools_parse_args(int argc, char **argv, struct tools_options *options) case OPT_LEFT_HANDED_DISABLE: options->left_handed = 0; break; + case OPT_CLICK_METHOD: + if (!optarg) { + tools_usage(); + return 1; + } + if (strcmp(optarg, "none") == 0) { + options->click_method = + LIBINPUT_CONFIG_CLICK_METHOD_NONE; + } else if (strcmp(optarg, "clickfinger") == 0) { + options->click_method = + LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER; + } else if (strcmp(optarg, "buttonareas") == 0) { + options->click_method = + LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; + } else { + tools_usage(); + return 1; + } + break; default: tools_usage(); return 1; @@ -263,4 +286,7 @@ tools_device_apply_config(struct libinput_device *device, options->natural_scroll); if (options->left_handed != -1) libinput_device_config_left_handed_set(device, options->left_handed); + + if (options->click_method != -1) + libinput_device_config_click_set_method(device, options->click_method); } diff --git a/tools/shared.h b/tools/shared.h index 4388cea6..fcf748fd 100644 --- a/tools/shared.h +++ b/tools/shared.h @@ -39,6 +39,7 @@ struct tools_options { int tapping; int natural_scroll; int left_handed; + enum libinput_config_click_method click_method; }; void tools_init_options(struct tools_options *options); From 82c2b78313fb381ed2cf29ba30562de932cf4db1 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 19 Jan 2015 20:31:15 +1000 Subject: [PATCH 15/15] Move the new click method configuration tools to the right symbol version set Signed-off-by: Peter Hutterer --- src/libinput.sym | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libinput.sym b/src/libinput.sym index 9be6cf4e..cfbeabd8 100644 --- a/src/libinput.sym +++ b/src/libinput.sym @@ -15,10 +15,6 @@ global: libinput_device_config_calibration_get_matrix; libinput_device_config_calibration_has_matrix; libinput_device_config_calibration_set_matrix; - libinput_device_config_click_get_default_method; - libinput_device_config_click_get_method; - libinput_device_config_click_get_methods; - libinput_device_config_click_set_method; libinput_device_config_scroll_get_button; libinput_device_config_scroll_get_default_button; libinput_device_config_scroll_get_default_method; @@ -123,3 +119,11 @@ global: local: *; }; + +LIBINPUT_0.9.0 { +global: + libinput_device_config_click_get_default_method; + libinput_device_config_click_get_method; + libinput_device_config_click_get_methods; + libinput_device_config_click_set_method; +} LIBINPUT_0.8.0;