From 7c8cecdb022b7c29890c84f3bab89149348d3309 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 11 Jan 2017 14:48:11 +1000 Subject: [PATCH 01/11] test: add two more touch..._extended functions So we can set pressure during touch sequences Signed-off-by: Peter Hutterer --- test/litest.c | 22 ++++++++++++++++++++++ test/litest.h | 8 ++++++++ 2 files changed, 30 insertions(+) diff --git a/test/litest.c b/test/litest.c index b3e7ba3d..1bb18dde 100644 --- a/test/litest.c +++ b/test/litest.c @@ -1643,6 +1643,28 @@ litest_touch_move_to(struct litest_device *d, litest_touch_move(d, slot, x_to, y_to); } +void +litest_touch_move_to_extended(struct litest_device *d, + unsigned int slot, + double x_from, double y_from, + double x_to, double y_to, + struct axis_replacement *axes, + int steps, int sleep_ms) +{ + for (int i = 1; i < steps - 1; i++) { + litest_touch_move_extended(d, slot, + x_from + (x_to - x_from)/steps * i, + y_from + (y_to - y_from)/steps * i, + axes); + if (sleep_ms) { + libinput_dispatch(d->libinput); + msleep(sleep_ms); + libinput_dispatch(d->libinput); + } + } + litest_touch_move_extended(d, slot, x_to, y_to, axes); +} + static int auto_assign_tablet_value(struct litest_device *d, const struct input_event *ev, diff --git a/test/litest.h b/test/litest.h index e6d35a90..886337ba 100644 --- a/test/litest.h +++ b/test/litest.h @@ -437,6 +437,14 @@ litest_touch_move_to(struct litest_device *d, double x_to, double y_to, int steps, int sleep_ms); +void +litest_touch_move_to_extended(struct litest_device *d, + unsigned int slot, + double x_from, double y_from, + double x_to, double y_to, + struct axis_replacement *axes, + int steps, int sleep_ms); + void litest_touch_move_two_touches(struct litest_device *d, double x0, double y0, From 618ee6ac9495297a74059f95ad140928b2ea1fb7 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 11 Jan 2017 09:49:37 +1000 Subject: [PATCH 02/11] test: force a pressure of 0 when we hover a touch As we switch to pressure-based touch detection, we need for all pressure-capable touchpads to send pressure values. They'll do so by filling in an axis default but that breaks our current hover code. Make sure the hover litest helpers force a pressure of 0. Signed-off-by: Peter Hutterer --- test/litest.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/test/litest.c b/test/litest.c index 1bb18dde..21afaf9b 100644 --- a/test/litest.c +++ b/test/litest.c @@ -1799,7 +1799,13 @@ litest_hover_start(struct litest_device *d, double x, double y) { - litest_slot_start(d, slot, x, y, NULL, 0); + struct axis_replacement axes[] = { + {ABS_MT_PRESSURE, 0 }, + {ABS_PRESSURE, 0 }, + {-1, -1 }, + }; + + litest_slot_start(d, slot, x, y, axes, 0); } void @@ -1838,7 +1844,13 @@ void litest_hover_move(struct litest_device *d, unsigned int slot, double x, double y) { - litest_slot_move(d, slot, x, y, NULL, false); + struct axis_replacement axes[] = { + {ABS_MT_PRESSURE, 0 }, + {ABS_PRESSURE, 0 }, + {-1, -1 }, + }; + + litest_slot_move(d, slot, x, y, axes, false); } void From 3170b3519b869dcd4e304822b0b12a5b31d9deb9 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 11 Jan 2017 16:12:47 +1000 Subject: [PATCH 03/11] touchpad: ignore hovering touches when tapping We need to remember whether a tap was down or just hovering, otherwise we mess up the state machine when we send tap release events for taps that never switched to TOUCH_BEGIN. This is quick fix, really we should have a new state here, but that's a lot harder to implement. Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad-tap.c | 6 +++++- src/evdev-mt-touchpad.c | 2 ++ src/evdev-mt-touchpad.h | 3 +++ test/test-touchpad.c | 19 +++++++++++++++++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index 9fba521f..c163599d 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -774,6 +774,9 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time) if (t->tap.is_thumb) continue; + if (t->state == TOUCH_HOVERING) + continue; + if (t->state == TOUCH_BEGIN) { /* The simple version: if a touch is a thumb on * begin we ignore it. All other thumb touches @@ -795,7 +798,8 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time) tp_tap_handle_event(tp, t, TAP_EVENT_MOTION, time); } else if (t->state == TOUCH_END) { - tp_tap_handle_event(tp, t, TAP_EVENT_RELEASE, time); + if (t->was_down) + tp_tap_handle_event(tp, t, TAP_EVENT_RELEASE, time); t->tap.state = TAP_TOUCH_STATE_IDLE; } else if (tp->tap.state != TAP_STATE_IDLE && tp_tap_exceeds_motion_threshold(tp, t)) { diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 56822df2..a47c59f5 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -214,6 +214,7 @@ tp_new_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) tp_motion_history_reset(t); t->dirty = true; t->has_ended = false; + t->was_down = false; t->state = TOUCH_HOVERING; t->pinned.is_pinned = false; t->millis = time; @@ -226,6 +227,7 @@ tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) t->dirty = true; t->state = TOUCH_BEGIN; t->millis = time; + t->was_down = true; tp->nfingers_down++; t->palm.time = time; t->thumb.state = THUMB_STATE_MAYBE; diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index fb15956f..abe885f3 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -156,6 +156,9 @@ struct tp_touch { int distance; /* distance == 0 means touch */ int pressure; + bool was_down; /* if distance == 0, false for pure hovering + touches */ + struct { /* A quirk mostly used on Synaptics touchpads. In a transition to/from fake touches > num_slots, the current diff --git a/test/test-touchpad.c b/test/test-touchpad.c index ee8cd7f7..b8ca0b97 100644 --- a/test/test-touchpad.c +++ b/test/test-touchpad.c @@ -2152,6 +2152,24 @@ START_TEST(touchpad_hover_2fg_1fg_down) } END_TEST +START_TEST(touchpad_hover_1fg_tap) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_enable_tap(dev->libinput_device); + + litest_drain_events(li); + + litest_hover_start(dev, 0, 50, 50); + litest_hover_end(dev, 0); + + libinput_dispatch(li); + litest_assert_empty_queue(li); + +} +END_TEST + static void assert_btnevent_from_device(struct litest_device *device, unsigned int button, @@ -4740,6 +4758,7 @@ litest_setup_tests_touchpad(void) litest_add("touchpad:hover", touchpad_hover_down_hover_down, LITEST_TOUCHPAD|LITEST_HOVER, LITEST_ANY); litest_add("touchpad:hover", touchpad_hover_2fg_noevent, LITEST_TOUCHPAD|LITEST_HOVER, LITEST_ANY); litest_add("touchpad:hover", touchpad_hover_2fg_1fg_down, LITEST_TOUCHPAD|LITEST_HOVER, LITEST_ANY); + litest_add("touchpad:hover", touchpad_hover_1fg_tap, LITEST_TOUCHPAD|LITEST_HOVER, LITEST_ANY); litest_add_for_device("touchpad:trackpoint", touchpad_trackpoint_buttons, LITEST_SYNAPTICS_TRACKPOINT_BUTTONS); litest_add_for_device("touchpad:trackpoint", touchpad_trackpoint_mb_scroll, LITEST_SYNAPTICS_TRACKPOINT_BUTTONS); From 11b37080df0f197991cbb9646b3fc78655f5a8a1 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 19 Jan 2017 17:20:19 +1000 Subject: [PATCH 04/11] test: allow nesting of litest_push_event_frame() Right now, we fail if we call litest_push_event_frame() when already inside a frame. For the semi-mt handling we need to do exactly that though, so turn it into a counting semaphore instead. Signed-off-by: Peter Hutterer --- test/litest.c | 13 ++++++++----- test/litest.h | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/test/litest.c b/test/litest.c index 21afaf9b..3bc58d99 100644 --- a/test/litest.c +++ b/test/litest.c @@ -1384,6 +1384,8 @@ litest_delete_device(struct litest_device *d) if (!d) return; + litest_assert_int_eq(d->skip_ev_syn, 0); + libinput_device_unref(d->libinput_device); libinput_path_remove_device(d->libinput_device); if (d->owns_context) @@ -3042,16 +3044,17 @@ litest_timeout_trackpoint(void) void litest_push_event_frame(struct litest_device *dev) { - litest_assert(!dev->skip_ev_syn); - dev->skip_ev_syn = true; + litest_assert(dev->skip_ev_syn >= 0); + dev->skip_ev_syn++; } void litest_pop_event_frame(struct litest_device *dev) { - litest_assert(dev->skip_ev_syn); - dev->skip_ev_syn = false; - litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_assert(dev->skip_ev_syn > 0); + dev->skip_ev_syn--; + if (dev->skip_ev_syn == 0) + litest_event(dev, EV_SYN, SYN_REPORT, 0); } static void diff --git a/test/litest.h b/test/litest.h index 886337ba..60757dc5 100644 --- a/test/litest.h +++ b/test/litest.h @@ -270,7 +270,7 @@ struct litest_device { struct litest_device_interface *interface; int ntouches_down; - bool skip_ev_syn; + int skip_ev_syn; void *private; /* device-specific data */ }; From 72ac3c1aee081293f7c44d3fc6498cd88535bdf0 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 19 Jan 2017 16:52:04 +1000 Subject: [PATCH 05/11] test: convert event handling while loops into for loops No functional changes, just enables us to use 'continue' instead of piling up negated conditions. Signed-off-by: Peter Hutterer --- test/litest.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/test/litest.c b/test/litest.c index 3bc58d99..ff65587b 100644 --- a/test/litest.c +++ b/test/litest.c @@ -1505,8 +1505,9 @@ litest_slot_start(struct litest_device *d, return; } - ev = d->interface->touch_down_events; - while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) { + for (ev = d->interface->touch_down_events; + ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1; + ev++) { int value = litest_auto_assign_value(d, ev, slot, @@ -1514,9 +1515,10 @@ litest_slot_start(struct litest_device *d, y, axes, touching); - if (value != LITEST_AUTO_ASSIGN) - litest_event(d, ev->type, ev->code, value); - ev++; + if (value == LITEST_AUTO_ASSIGN) + continue; + + litest_event(d, ev->type, ev->code, value); } } @@ -1563,7 +1565,9 @@ litest_touch_up(struct litest_device *d, unsigned int slot) } else ev = up; - while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) { + for ( /* */; + ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1; + ev++) { int value = litest_auto_assign_value(d, ev, slot, @@ -1572,7 +1576,6 @@ litest_touch_up(struct litest_device *d, unsigned int slot) NULL, false); litest_event(d, ev->type, ev->code, value); - ev++; } } @@ -1591,8 +1594,9 @@ litest_slot_move(struct litest_device *d, return; } - ev = d->interface->touch_move_events; - while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) { + for (ev = d->interface->touch_move_events; + ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1; + ev++) { int value = litest_auto_assign_value(d, ev, slot, @@ -1600,9 +1604,10 @@ litest_slot_move(struct litest_device *d, y, axes, touching); - if (value != LITEST_AUTO_ASSIGN) - litest_event(d, ev->type, ev->code, value); - ev++; + if (value == LITEST_AUTO_ASSIGN) + continue; + + litest_event(d, ev->type, ev->code, value); } } From cef3a8705ec52d69a323ded2bc22f2450383cad6 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 19 Jan 2017 15:58:13 +1000 Subject: [PATCH 06/11] test: handle semi-mt devices in litest Don't rely on the devices to handle themselves, just handle it globally Signed-off-by: Peter Hutterer --- test/litest.c | 230 +++++++++++++++++++++++++++++++++++++++++--------- test/litest.h | 33 ++++---- 2 files changed, 207 insertions(+), 56 deletions(-) diff --git a/test/litest.c b/test/litest.c index ff65587b..42d97d67 100644 --- a/test/litest.c +++ b/test/litest.c @@ -1199,7 +1199,7 @@ litest_create(enum litest_device_type which, const char *name; const struct input_id *id; struct input_absinfo *abs; - int *events; + int *events, *e; dev = devices; while (*dev) { @@ -1234,6 +1234,18 @@ litest_create(enum litest_device_type which, abs, events); d->interface = (*dev)->interface; + + for (e = events; *e != -1; e += 2) { + unsigned int type = *e, + code = *(e + 1); + + if (type == INPUT_PROP_MAX && + code == INPUT_PROP_SEMI_MT) { + d->semi_mt.is_semi_mt = true; + break; + } + } + free(abs); free(events); @@ -1486,12 +1498,13 @@ send_btntool(struct litest_device *d, bool hover) } static void -litest_slot_start(struct litest_device *d, - unsigned int slot, - double x, - double y, - struct axis_replacement *axes, - bool touching) +slot_start(struct litest_device *d, + unsigned int slot, + double x, + double y, + struct axis_replacement *axes, + bool touching, + bool filter_abs_xy) { struct input_event *ev; @@ -1518,31 +1531,53 @@ litest_slot_start(struct litest_device *d, if (value == LITEST_AUTO_ASSIGN) continue; + if (filter_abs_xy && ev->type == EV_ABS && + (ev->code == ABS_X || ev->code == ABS_Y)) + continue; + litest_event(d, ev->type, ev->code, value); } } -void -litest_touch_down(struct litest_device *d, - unsigned int slot, - double x, - double y) +static void +slot_move(struct litest_device *d, + unsigned int slot, + double x, + double y, + struct axis_replacement *axes, + bool touching, + bool filter_abs_xy) { - litest_slot_start(d, slot, x, y, NULL, true); + struct input_event *ev; + + if (d->interface->touch_move) { + d->interface->touch_move(d, slot, x, y); + return; + } + + for (ev = d->interface->touch_move_events; + ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1; + ev++) { + int value = litest_auto_assign_value(d, + ev, + slot, + x, + y, + axes, + touching); + if (value == LITEST_AUTO_ASSIGN) + continue; + + if (filter_abs_xy && ev->type == EV_ABS && + (ev->code == ABS_X || ev->code == ABS_Y)) + continue; + + litest_event(d, ev->type, ev->code, value); + } } -void -litest_touch_down_extended(struct litest_device *d, - unsigned int slot, - double x, - double y, - struct axis_replacement *axes) -{ - litest_slot_start(d, slot, x, y, axes, true); -} - -void -litest_touch_up(struct litest_device *d, unsigned int slot) +static void +touch_up(struct litest_device *d, unsigned int slot) { struct input_event *ev; struct input_event up[] = { @@ -1579,6 +1614,74 @@ litest_touch_up(struct litest_device *d, unsigned int slot) } } +static void +litest_slot_start(struct litest_device *d, + unsigned int slot, + double x, + double y, + struct axis_replacement *axes, + bool touching) +{ + double t, l, r = 0, b = 0; /* top, left, right, bottom */ + bool filter_abs_xy = false; + + if (!d->semi_mt.is_semi_mt) { + slot_start(d, slot, x, y, axes, touching, filter_abs_xy); + return; + } + + if (d->ntouches_down >= 2 || slot > 1) + return; + + slot = d->ntouches_down; + + if (d->ntouches_down == 0) { + l = x; + t = y; + } else { + int other = (slot + 1) % 2; + l = min(x, d->semi_mt.touches[other].x); + t = min(y, d->semi_mt.touches[other].y); + r = max(x, d->semi_mt.touches[other].x); + b = max(y, d->semi_mt.touches[other].y); + } + + litest_push_event_frame(d); + if (d->ntouches_down == 0) + slot_start(d, 0, l, t, axes, touching, filter_abs_xy); + else + slot_move(d, 0, l, t, axes, touching, filter_abs_xy); + + if (slot == 1) { + filter_abs_xy = true; + slot_start(d, 1, r, b, axes, touching, filter_abs_xy); + } + + litest_pop_event_frame(d); + + d->semi_mt.touches[slot].x = x; + d->semi_mt.touches[slot].y = y; +} + +void +litest_touch_down(struct litest_device *d, + unsigned int slot, + double x, + double y) +{ + litest_slot_start(d, slot, x, y, NULL, true); +} + +void +litest_touch_down_extended(struct litest_device *d, + unsigned int slot, + double x, + double y, + struct axis_replacement *axes) +{ + litest_slot_start(d, slot, x, y, axes, true); +} + static void litest_slot_move(struct litest_device *d, unsigned int slot, @@ -1587,28 +1690,73 @@ litest_slot_move(struct litest_device *d, struct axis_replacement *axes, bool touching) { - struct input_event *ev; + double t, l, r = 0, b = 0; /* top, left, right, bottom */ + bool filter_abs_xy = false; - if (d->interface->touch_move) { - d->interface->touch_move(d, slot, x, y); + if (!d->semi_mt.is_semi_mt) { + slot_move(d, slot, x, y, axes, touching, filter_abs_xy); return; } - for (ev = d->interface->touch_move_events; - ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1; - ev++) { - int value = litest_auto_assign_value(d, - ev, - slot, - x, - y, - axes, - touching); - if (value == LITEST_AUTO_ASSIGN) - continue; + if (d->ntouches_down > 2 || slot > 1) + return; - litest_event(d, ev->type, ev->code, value); + if (d->ntouches_down == 1) { + l = x; + t = y; + } else { + int other = (slot + 1) % 2; + l = min(x, d->semi_mt.touches[other].x); + t = min(y, d->semi_mt.touches[other].y); + r = max(x, d->semi_mt.touches[other].x); + b = max(y, d->semi_mt.touches[other].y); } + + litest_push_event_frame(d); + slot_move(d, 0, l, t, axes, touching, filter_abs_xy); + + if (d->ntouches_down == 2) { + filter_abs_xy = true; + slot_move(d, 1, r, b, axes, touching, filter_abs_xy); + } + + litest_pop_event_frame(d); + + d->semi_mt.touches[slot].x = x; + d->semi_mt.touches[slot].y = y; +} + +void +litest_touch_up(struct litest_device *d, unsigned int slot) +{ + if (!d->semi_mt.is_semi_mt) { + touch_up(d, slot); + return; + } + + if (d->ntouches_down > 2 || slot > 1) + return; + + litest_push_event_frame(d); + touch_up(d, d->ntouches_down - 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) { + bool touching = true; + bool filter_abs_xy = false; + + int other = (slot + 1) % 2; + slot_move(d, + 0, + d->semi_mt.touches[other].x, + d->semi_mt.touches[other].y, + NULL, + touching, + filter_abs_xy); + } + + litest_pop_event_frame(d); } void diff --git a/test/litest.h b/test/litest.h index 60757dc5..a13d6cdb 100644 --- a/test/litest.h +++ b/test/litest.h @@ -261,6 +261,23 @@ enum litest_device_feature { LITEST_LEDS = 1 << 25, }; +/* 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 { + bool is_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]; +}; + struct litest_device { struct libevdev *evdev; struct libevdev_uinput *uinput; @@ -271,6 +288,7 @@ struct litest_device { int ntouches_down; int skip_ev_syn; + struct litest_semi_mt semi_mt; /** only used for semi-mt device */ void *private; /* device-specific data */ }; @@ -677,21 +695,6 @@ 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, From 8dfdf6b76fcaf88a88dd3e2b9ad9a0c0e3f9794d Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 19 Jan 2017 17:35:04 +1000 Subject: [PATCH 07/11] test: switch the semi-mt devices to use the litest semi-mt handling Signed-off-by: Peter Hutterer --- test/litest-device-alps-dualpoint.c | 66 ++++++++++----------------- test/litest-device-alps-semi-mt.c | 66 ++++++++++----------------- test/litest-device-synaptics-hover.c | 68 ++++++++++------------------ 3 files changed, 69 insertions(+), 131 deletions(-) diff --git a/test/litest-device-alps-dualpoint.c b/test/litest-device-alps-dualpoint.c index fe8cf967..de025e59 100644 --- a/test/litest-device-alps-dualpoint.c +++ b/test/litest-device-alps-dualpoint.c @@ -30,8 +30,6 @@ #include "litest.h" #include "litest-int.h" -static void alps_dualpoint_create(struct litest_device *d); - static void litest_alps_dualpoint_setup(void) { @@ -39,34 +37,32 @@ litest_alps_dualpoint_setup(void) litest_set_current_device(d); } -static void -alps_dualpoint_touch_down(struct litest_device *d, unsigned int slot, double x, double y) -{ - struct litest_semi_mt *semi_mt = d->private; +static struct input_event down[] = { + { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; - litest_semi_mt_touch_down(d, semi_mt, slot, x, y); -} - -static void -alps_dualpoint_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 -alps_dualpoint_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 input_event move[] = { + { .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; static struct litest_device_interface interface = { - .touch_down = alps_dualpoint_touch_down, - .touch_move = alps_dualpoint_touch_move, - .touch_up = alps_dualpoint_touch_up, + .touch_down_events = down, + .touch_move_events = move, }; static struct input_id input_id = { @@ -116,7 +112,6 @@ struct litest_test_device litest_alps_dualpoint_device = { .shortname = "alps dualpoint", .setup = litest_alps_dualpoint_setup, .interface = &interface, - .create = alps_dualpoint_create, .name = "AlpsPS/2 ALPS DualPoint TouchPad", .id = &input_id, @@ -124,18 +119,3 @@ struct litest_test_device litest_alps_dualpoint_device = { .absinfo = absinfo, .udev_rule = udev_rule, }; - -static void -alps_dualpoint_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_alps_dualpoint_device.name, - litest_alps_dualpoint_device.id, - absinfo, - events); - d->interface = &interface; -} diff --git a/test/litest-device-alps-semi-mt.c b/test/litest-device-alps-semi-mt.c index 7325a429..d78adcab 100644 --- a/test/litest-device-alps-semi-mt.c +++ b/test/litest-device-alps-semi-mt.c @@ -30,8 +30,6 @@ #include "litest.h" #include "litest-int.h" -static void alps_create(struct litest_device *d); - static void litest_alps_setup(void) { @@ -39,34 +37,32 @@ litest_alps_setup(void) litest_set_current_device(d); } -static void -alps_touch_down(struct litest_device *d, unsigned int slot, double x, double y) -{ - struct litest_semi_mt *semi_mt = d->private; +static struct input_event down[] = { + { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; - 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 litest_semi_mt *semi_mt = d->private; - - litest_semi_mt_touch_move(d, semi_mt, slot, x, y); -} - -static void -alps_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 input_event move[] = { + { .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; static struct litest_device_interface interface = { - .touch_down = alps_touch_down, - .touch_move = alps_touch_move, - .touch_up = alps_touch_up, + .touch_down_events = down, + .touch_move_events = move, }; static struct input_id input_id = { @@ -106,25 +102,9 @@ struct litest_test_device litest_alps_device = { .shortname = "alps semi-mt", .setup = litest_alps_setup, .interface = &interface, - .create = alps_create, .name = "AlpsPS/2 ALPS GlidePoint", .id = &input_id, .events = events, .absinfo = absinfo, }; - -static void -alps_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_alps_device.name, - litest_alps_device.id, - absinfo, - events); - d->interface = &interface; -} diff --git a/test/litest-device-synaptics-hover.c b/test/litest-device-synaptics-hover.c index 6184ff63..8439f10f 100644 --- a/test/litest-device-synaptics-hover.c +++ b/test/litest-device-synaptics-hover.c @@ -30,9 +30,6 @@ #include "litest.h" #include "litest-int.h" -static void -synaptics_hover_create(struct litest_device *d); - static void litest_synaptics_hover_setup(void) { @@ -40,34 +37,32 @@ litest_synaptics_hover_setup(void) 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; +static struct input_event down[] = { + { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; - 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 input_event move[] = { + { .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; static struct litest_device_interface interface = { - .touch_down = synaptics_hover_touch_down, - .touch_move = synaptics_hover_touch_move, - .touch_up = synaptics_hover_touch_up, + .touch_down_events = down, + .touch_move_events = move, }; static struct input_id input_id = { @@ -115,7 +110,6 @@ struct litest_test_device litest_synaptics_hover_device = { .shortname = "synaptics hover", .setup = litest_synaptics_hover_setup, .interface = &interface, - .create = synaptics_hover_create, .name = "SynPS/2 Synaptics TouchPad", .id = &input_id, @@ -123,19 +117,3 @@ struct litest_test_device litest_synaptics_hover_device = { .absinfo = absinfo, .udev_rule = udev_rule, }; - -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; -} From c27f9afffc19f5a259e026df912a6a283cb69a4b Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 23 Jan 2017 12:04:20 +1000 Subject: [PATCH 08/11] test: make sure touch up resets pressure Should be overridden by the test devices where something more fine-grained is needed. Signed-off-by: Peter Hutterer --- test/litest.c | 1 + 1 file changed, 1 insertion(+) diff --git a/test/litest.c b/test/litest.c index 42d97d67..c1177b8f 100644 --- a/test/litest.c +++ b/test/litest.c @@ -1583,6 +1583,7 @@ touch_up(struct litest_device *d, unsigned int slot) struct input_event up[] = { { .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN }, { .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = -1 }, + { .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = 0 }, { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, { .type = -1, .code = -1 } }; From 2b3fe1a73ebbea1f051869ac9abfa3e8f4bcfab5 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 12 Jan 2017 13:30:08 +1000 Subject: [PATCH 09/11] test: add the right pressure bits. Signed-off-by: Peter Hutterer --- test/test-touchpad.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/test-touchpad.c b/test/test-touchpad.c index b8ca0b97..75750332 100644 --- a/test/test-touchpad.c +++ b/test/test-touchpad.c @@ -1686,6 +1686,7 @@ START_TEST(touchpad_semi_mt_hover_down) litest_event(dev, EV_ABS, ABS_X, x + 100); litest_event(dev, EV_ABS, ABS_Y, y + 100); + litest_event(dev, EV_ABS, ABS_PRESSURE, 50); litest_event(dev, EV_KEY, BTN_TOUCH, 1); litest_event(dev, EV_SYN, SYN_REPORT, 0); libinput_dispatch(li); @@ -1712,6 +1713,7 @@ START_TEST(touchpad_semi_mt_hover_down) /* go back to hover */ hover_continue(dev, 0, x, y); + litest_event(dev, EV_ABS, ABS_PRESSURE, 0); litest_event(dev, EV_KEY, BTN_TOUCH, 0); litest_event(dev, EV_SYN, SYN_REPORT, 0); @@ -1752,6 +1754,7 @@ START_TEST(touchpad_semi_mt_hover_down_hover_down) /* touch */ litest_event(dev, EV_ABS, ABS_X, x + 100); litest_event(dev, EV_ABS, ABS_Y, y + 100); + litest_event(dev, EV_ABS, ABS_PRESSURE, 50); litest_event(dev, EV_KEY, BTN_TOUCH, 1); litest_event(dev, EV_SYN, SYN_REPORT, 0); libinput_dispatch(li); @@ -1773,6 +1776,7 @@ START_TEST(touchpad_semi_mt_hover_down_hover_down) /* go back to hover */ hover_continue(dev, 0, x, y); + litest_event(dev, EV_ABS, ABS_PRESSURE, 0); litest_event(dev, EV_KEY, BTN_TOUCH, 0); litest_event(dev, EV_SYN, SYN_REPORT, 0); @@ -1796,7 +1800,10 @@ START_TEST(touchpad_semi_mt_hover_down_hover_down) litest_assert_empty_queue(li); /* start a new touch to be sure */ + litest_push_event_frame(dev); litest_touch_down(dev, 0, 50, 50); + litest_event(dev, EV_ABS, ABS_PRESSURE, 50); + litest_pop_event_frame(dev); litest_touch_move_to(dev, 0, 50, 50, 70, 70, 10, 10); litest_touch_up(dev, 0); @@ -1845,6 +1852,7 @@ START_TEST(touchpad_semi_mt_hover_down_up) litest_assert_empty_queue(li); + litest_event(dev, EV_ABS, ABS_PRESSURE, 50); litest_event(dev, EV_KEY, BTN_TOUCH, 1); litest_event(dev, EV_SYN, SYN_REPORT, 0); libinput_dispatch(li); @@ -1930,6 +1938,7 @@ START_TEST(touchpad_semi_mt_hover_2fg_1fg_down) /* 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_ABS, ABS_PRESSURE, 50); 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); @@ -1948,6 +1957,7 @@ START_TEST(touchpad_semi_mt_hover_2fg_1fg_down) litest_event(dev, EV_SYN, SYN_REPORT, 0); } + litest_event(dev, EV_ABS, ABS_PRESSURE, 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); @@ -1969,6 +1979,7 @@ START_TEST(touchpad_semi_mt_hover_2fg_up) litest_push_event_frame(dev); litest_touch_move(dev, 0, 72, 50); litest_touch_move(dev, 1, 52, 50); + litest_event(dev, EV_ABS, ABS_PRESSURE, 0); litest_event(dev, EV_KEY, BTN_TOUCH, 0); litest_pop_event_frame(dev); From 568d527caa4d0564b765ac082e948e19d1d22e13 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 10 Jan 2017 15:58:21 +1000 Subject: [PATCH 10/11] touchpad: use pressure values for touch is-down decision Don't rely on BTN_TOUCH for "finger down", the value for that is hardcoded in the kernel and not always suitable. Some devices need a different value to avoid reacting to accidental touches or hovering fingers. Implement a basic Schmitt trigger, same as we have in the synaptics driver. We also take the default values from there but these will likely see some updates. A special case is when we have more fingers down than slots. Since we can't detect the pressure on fake fingers (we only get a bit for 'is down') we assume that *all* fingers are down with sufficient pressure. It's too much of a niche case to have this work any other way. This patch drops the handling of ABS_DISTANCE because it's simply not needed anymore. Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad.c | 131 ++++++++++++++++++++++----- src/evdev-mt-touchpad.h | 10 +- test/litest-device-alps-dualpoint.c | 14 +++ test/litest-device-alps-semi-mt.c | 14 +++ test/litest-device-atmel-hover.c | 14 +++ test/litest-device-synaptics-hover.c | 14 +++ test/litest-device-synaptics-st.c | 15 ++- 7 files changed, 186 insertions(+), 26 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index a47c59f5..ff9ec41a 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -322,9 +322,6 @@ tp_process_absolute(struct tp_dispatch *tp, case ABS_MT_SLOT: tp->slot = e->value; break; - case ABS_MT_DISTANCE: - t->distance = e->value; - break; case ABS_MT_TRACKING_ID: if (e->value != -1) tp_new_touch(tp, t, time); @@ -365,6 +362,11 @@ tp_process_absolute_st(struct tp_dispatch *tp, t->dirty = true; tp->queued |= TOUCHPAD_EVENT_MOTION; break; + case ABS_PRESSURE: + t->pressure = e->value; + t->dirty = true; + tp->queued |= TOUCHPAD_EVENT_OTHERAXIS; + break; } } @@ -795,26 +797,72 @@ out: } static void -tp_unhover_abs_distance(struct tp_dispatch *tp, uint64_t time) +tp_unhover_pressure(struct tp_dispatch *tp, uint64_t time) { struct tp_touch *t; - unsigned int i; + int i; + unsigned int nfake_touches; + unsigned int real_fingers_down = 0; - for (i = 0; i < tp->ntouches; i++) { + nfake_touches = tp_fake_finger_count(tp); + if (nfake_touches == FAKE_FINGER_OVERFLOW) + nfake_touches = 0; + + for (i = 0; i < (int)tp->num_slots; i++) { t = tp_get_touch(tp, i); - if (!t->dirty) - continue; - - if (t->state == TOUCH_HOVERING) { - if (t->distance == 0) { - /* avoid jumps when landing a finger */ - tp_motion_history_reset(t); - tp_begin_touch(tp, t, time); + if (t->dirty) { + if (t->state == TOUCH_HOVERING) { + if (t->pressure >= tp->pressure.high) { + /* avoid jumps when landing a finger */ + tp_motion_history_reset(t); + tp_begin_touch(tp, t, time); + } + } else { + if (t->pressure < tp->pressure.low) + tp_end_touch(tp, t, time); } - } else { - if (t->distance > 0) - tp_end_touch(tp, t, time); + } + + if (t->state == TOUCH_BEGIN || + t->state == TOUCH_UPDATE) + real_fingers_down++; + } + + if (nfake_touches <= tp->num_slots || + tp->nfingers_down == 0) + return; + + /* if we have more fake fingers down than slots, we assume + * _all_ fingers have enough pressure, even if some of the slotted + * ones don't. Anything else gets insane quickly. + */ + for (i = 0; i < (int)tp->ntouches; i++) { + t = tp_get_touch(tp, i); + if (t->state == TOUCH_HOVERING) { + /* avoid jumps when landing a finger */ + tp_motion_history_reset(t); + tp_begin_touch(tp, t, time); + + if (tp->nfingers_down >= nfake_touches) + break; + } + } + + if (tp->nfingers_down > nfake_touches || + real_fingers_down == 0) { + for (i = tp->ntouches - 1; i >= 0; i--) { + t = tp_get_touch(tp, i); + + if (t->state == TOUCH_HOVERING || + t->state == TOUCH_NONE) + continue; + + tp_end_touch(tp, t, time); + + if (real_fingers_down > 0 && + tp->nfingers_down == nfake_touches) + break; } } } @@ -881,8 +929,8 @@ tp_unhover_fake_touches(struct tp_dispatch *tp, uint64_t time) static void tp_unhover_touches(struct tp_dispatch *tp, uint64_t time) { - if (tp->reports_distance) - tp_unhover_abs_distance(tp, time); + if (tp->pressure.use_pressure) + tp_unhover_pressure(tp, time); else tp_unhover_fake_touches(tp, time); @@ -926,6 +974,7 @@ tp_position_fake_touches(struct tp_dispatch *tp) continue; t->point = topmost->point; + t->pressure = topmost->pressure; if (!t->dirty) t->dirty = topmost->dirty; } @@ -1747,7 +1796,13 @@ tp_sync_touch(struct tp_dispatch *tp, &t->point.y)) t->point.y = libevdev_get_event_value(evdev, EV_ABS, ABS_Y); - libevdev_fetch_slot_value(evdev, slot, ABS_MT_DISTANCE, &t->distance); + if (!libevdev_fetch_slot_value(evdev, + slot, + ABS_MT_PRESSURE, + &t->pressure)) + t->pressure = libevdev_get_event_value(evdev, + EV_ABS, + ABS_PRESSURE); } static inline void @@ -2271,6 +2326,38 @@ tp_init_hysteresis(struct tp_dispatch *tp) return; } +static void +tp_init_pressure(struct tp_dispatch *tp, + struct evdev_device *device) +{ + const struct input_absinfo *abs; + unsigned int range; + unsigned int code = ABS_PRESSURE; + + if (tp->has_mt) + code = ABS_MT_PRESSURE; + + if (!libevdev_has_event_code(device->evdev, EV_ABS, code)) { + tp->pressure.use_pressure = false; + return; + } + + tp->pressure.use_pressure = true; + + abs = libevdev_get_abs_info(device->evdev, code); + assert(abs); + + range = abs->maximum - abs->minimum; + + /* Approximately the synaptics defaults */ + tp->pressure.high = abs->minimum + 0.12 * range; + tp->pressure.low = abs->minimum + 0.10 * range; + + log_debug(evdev_libinput_context(device), + "%s: using pressure-based touch detection\n", + device->devname); +} + static int tp_init(struct tp_dispatch *tp, struct evdev_device *device) @@ -2288,9 +2375,7 @@ tp_init(struct tp_dispatch *tp, evdev_device_init_abs_range_warnings(device); - tp->reports_distance = libevdev_has_event_code(device->evdev, - EV_ABS, - ABS_MT_DISTANCE); + tp_init_pressure(tp, device); /* Set the dpi to that of the x axis, because that's what we normalize to when needed*/ diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index abe885f3..eae0af99 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -153,7 +153,6 @@ struct tp_touch { bool dirty; struct device_coords point; uint64_t millis; - int distance; /* distance == 0 means touch */ int pressure; bool was_down; /* if distance == 0, false for pure hovering @@ -232,7 +231,6 @@ struct tp_dispatch { unsigned int slot; /* current slot */ bool has_mt; bool semi_mt; - bool reports_distance; /* does the device support true hovering */ /* true if we're reading events (i.e. not suspended) but we're * ignoring them */ @@ -248,6 +246,14 @@ struct tp_dispatch { */ unsigned int fake_touches; + /* if pressure goes above high -> touch down, + if pressure then goes below low -> touch up */ + struct { + bool use_pressure; + int high; + int low; + } pressure; + struct device_coords hysteresis_margin; struct { diff --git a/test/litest-device-alps-dualpoint.c b/test/litest-device-alps-dualpoint.c index de025e59..90fdbcaf 100644 --- a/test/litest-device-alps-dualpoint.c +++ b/test/litest-device-alps-dualpoint.c @@ -60,9 +60,23 @@ static struct input_event move[] = { { .type = -1, .code = -1 }, }; +static int +get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value) +{ + switch (evcode) { + case ABS_PRESSURE: + case ABS_MT_PRESSURE: + *value = 30; + return 0; + } + return 1; +} + static struct litest_device_interface interface = { .touch_down_events = down, .touch_move_events = move, + + .get_axis_default = get_axis_default, }; static struct input_id input_id = { diff --git a/test/litest-device-alps-semi-mt.c b/test/litest-device-alps-semi-mt.c index d78adcab..de0eb3ab 100644 --- a/test/litest-device-alps-semi-mt.c +++ b/test/litest-device-alps-semi-mt.c @@ -60,9 +60,23 @@ static struct input_event move[] = { { .type = -1, .code = -1 }, }; +static int +get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value) +{ + switch (evcode) { + case ABS_PRESSURE: + case ABS_MT_PRESSURE: + *value = 30; + return 0; + } + return 1; +} + static struct litest_device_interface interface = { .touch_down_events = down, .touch_move_events = move, + + .get_axis_default = get_axis_default, }; static struct input_id input_id = { diff --git a/test/litest-device-atmel-hover.c b/test/litest-device-atmel-hover.c index c856d081..942744e2 100644 --- a/test/litest-device-atmel-hover.c +++ b/test/litest-device-atmel-hover.c @@ -76,10 +76,24 @@ static struct input_event up[] = { { .type = -1, .code = -1 }, }; +static int +get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value) +{ + switch (evcode) { + case ABS_PRESSURE: + case ABS_MT_PRESSURE: + *value = 30; + return 0; + } + return 1; +} + static struct litest_device_interface interface = { .touch_down_events = down, .touch_move_events = move, .touch_up_events = up, + + .get_axis_default = get_axis_default, }; static struct input_id input_id = { diff --git a/test/litest-device-synaptics-hover.c b/test/litest-device-synaptics-hover.c index 8439f10f..9c0c7bda 100644 --- a/test/litest-device-synaptics-hover.c +++ b/test/litest-device-synaptics-hover.c @@ -60,9 +60,23 @@ static struct input_event move[] = { { .type = -1, .code = -1 }, }; +static int +get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value) +{ + switch (evcode) { + case ABS_PRESSURE: + case ABS_MT_PRESSURE: + *value = 30; + return 0; + } + return 1; +} + static struct litest_device_interface interface = { .touch_down_events = down, .touch_move_events = move, + + .get_axis_default = get_axis_default, }; static struct input_id input_id = { diff --git a/test/litest-device-synaptics-st.c b/test/litest-device-synaptics-st.c index 7e45d564..bbde1ef0 100644 --- a/test/litest-device-synaptics-st.c +++ b/test/litest-device-synaptics-st.c @@ -36,7 +36,7 @@ litest_synaptics_touchpad_setup(void) static struct input_event down[] = { { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN }, { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN }, - { .type = EV_ABS, .code = ABS_PRESSURE, .value = 30 }, + { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN }, { .type = EV_ABS, .code = ABS_TOOL_WIDTH, .value = 7 }, { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, { .type = -1, .code = -1 }, @@ -54,10 +54,23 @@ struct input_event up[] = { { .type = -1, .code = -1 }, }; +static int +get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value) +{ + switch (evcode) { + case ABS_PRESSURE: + *value = 30; + return 0; + } + return 1; +} + static struct litest_device_interface interface = { .touch_down_events = down, .touch_move_events = move, .touch_up_events = up, + + .get_axis_default = get_axis_default, }; static struct input_absinfo absinfo[] = { From 9e8f6bd1d655d277f6f4d1cb1525d169b41c0aa7 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 11 Jan 2017 14:48:39 +1000 Subject: [PATCH 11/11] test: add touchpad pressure tests Signed-off-by: Peter Hutterer --- test/test-touchpad.c | 223 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) diff --git a/test/test-touchpad.c b/test/test-touchpad.c index 75750332..ec738e90 100644 --- a/test/test-touchpad.c +++ b/test/test-touchpad.c @@ -4698,6 +4698,222 @@ START_TEST(touchpad_disabled_double_mouse_one_suspended) } END_TEST +static inline bool +touchpad_has_pressure(struct litest_device *dev) +{ + struct libevdev *evdev = dev->evdev; + + if (libevdev_has_event_code(evdev, EV_ABS, ABS_MT_PRESSURE)) + return true; + + if (libevdev_has_event_code(evdev, EV_ABS, ABS_PRESSURE) && + !libevdev_has_event_code(evdev, EV_ABS, ABS_MT_SLOT)) + return true; + + return false; +} + +START_TEST(touchpad_pressure) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct axis_replacement axes[] = { + { ABS_MT_PRESSURE, 1 }, + { ABS_PRESSURE, 1 }, + { -1, 0 } + }; + double pressure; /* in percent */ + double threshold = 12.0; + + if (!touchpad_has_pressure(dev)) + return; + + litest_drain_events(li); + + for (pressure = 1; pressure <= threshold + 1; pressure++) { + litest_axis_set_value(axes, ABS_MT_PRESSURE, pressure); + litest_axis_set_value(axes, ABS_PRESSURE, pressure); + litest_touch_down_extended(dev, 0, 50, 50, axes); + litest_touch_move_to_extended(dev, 0, + 50, 50, + 80, 80, + axes, 10, 1); + litest_touch_up(dev, 0); + if (pressure < threshold) + litest_assert_empty_queue(li); + else + litest_assert_only_typed_events(li, + LIBINPUT_EVENT_POINTER_MOTION); + + } +} +END_TEST + +START_TEST(touchpad_pressure_2fg) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct axis_replacement axes[] = { + { ABS_MT_PRESSURE, 5 }, + { ABS_PRESSURE, 5 }, + { -1, 0 } + }; + + if (!touchpad_has_pressure(dev)) + return; + + litest_drain_events(li); + + litest_touch_down(dev, 0, 30, 50); + litest_touch_down_extended(dev, 1, 50, 50, axes); + libinput_dispatch(li); + litest_touch_move_to(dev, 0, 50, 50, 80, 80, 10, 1); + libinput_dispatch(li); + litest_assert_only_typed_events(li, + LIBINPUT_EVENT_POINTER_MOTION); + litest_touch_move_to_extended(dev, 1, + 50, 50, + 80, 80, + axes, 10, 1); + litest_assert_empty_queue(li); + litest_touch_move_to(dev, 0, 80, 80, 20, 50, 10, 1); + litest_touch_move_to_extended(dev, 1, + 80, 80, + 50, 50, + axes, 10, 1); + litest_assert_only_typed_events(li, + LIBINPUT_EVENT_POINTER_MOTION); +} +END_TEST + +START_TEST(touchpad_pressure_2fg_st) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct axis_replacement axes[] = { + { ABS_MT_PRESSURE, 5 }, + { ABS_PRESSURE, 5 }, + { -1, 0 } + }; + + if (!touchpad_has_pressure(dev)) + return; + + /* This is a bit of a weird test. We expect two fingers to be down as + * soon as doubletap is set, regardless of pressure. But we don't + * have 2fg scrolling on st devices and 2 fingers down on a touchpad + * without 2fg scrolling simply does not generate events. But that's + * the same result as if the fingers were ignored because of + * pressure and we cannot know the difference. + * So this test only keeps your CPU warm, not much else. + */ + litest_drain_events(li); + + litest_touch_down_extended(dev, 0, 50, 50, axes); + libinput_dispatch(li); + 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); + libinput_dispatch(li); + litest_touch_move_to_extended(dev, 0, + 50, 50, + 80, 80, + axes, 10, 1); + litest_assert_empty_queue(li); +} +END_TEST + +START_TEST(touchpad_pressure_tap) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct axis_replacement axes[] = { + { ABS_MT_PRESSURE, 5 }, + { ABS_PRESSURE, 5 }, + { -1, 0 } + }; + + if (!touchpad_has_pressure(dev)) + return; + + litest_enable_tap(dev->libinput_device); + litest_drain_events(li); + + litest_touch_down_extended(dev, 0, 50, 50, axes); + libinput_dispatch(li); + litest_touch_up(dev, 0); + litest_assert_empty_queue(li); +} +END_TEST + +START_TEST(touchpad_pressure_tap_2fg) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct axis_replacement axes[] = { + { ABS_MT_PRESSURE, 5 }, + { ABS_PRESSURE, 5 }, + { -1, 0 } + }; + + if (!touchpad_has_pressure(dev)) + return; + + litest_enable_tap(dev->libinput_device); + litest_drain_events(li); + + /* tap but too light */ + litest_touch_down_extended(dev, 0, 40, 50, axes); + litest_touch_down_extended(dev, 1, 50, 50, axes); + libinput_dispatch(li); + litest_touch_up(dev, 0); + litest_touch_up(dev, 1); + litest_assert_empty_queue(li); +} +END_TEST + +START_TEST(touchpad_pressure_tap_2fg_1fg_light) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct axis_replacement axes[] = { + { ABS_MT_PRESSURE, 5 }, + { ABS_PRESSURE, 5 }, + { -1, 0 } + }; + + if (!touchpad_has_pressure(dev)) + return; + + litest_enable_tap(dev->libinput_device); + litest_drain_events(li); + + /* double-tap with one finger too light */ + litest_touch_down(dev, 0, 40, 50); + litest_touch_down_extended(dev, 1, 50, 50, axes); + libinput_dispatch(li); + litest_touch_up(dev, 0); + litest_touch_up(dev, 1); + libinput_dispatch(li); + + event = libinput_get_event(li); + litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + libinput_event_destroy(event); + + litest_timeout_tap(); + libinput_dispatch(li); + + event = libinput_get_event(li); + litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_RELEASED); + libinput_event_destroy(event); +} +END_TEST + void litest_setup_tests_touchpad(void) { @@ -4838,4 +5054,11 @@ litest_setup_tests_touchpad(void) litest_add_for_device("touchpad:sendevents", touchpad_disabled_on_mouse_suspend_mouse, LITEST_SYNAPTICS_CLICKPAD_X220); litest_add_for_device("touchpad:sendevents", touchpad_disabled_double_mouse, LITEST_SYNAPTICS_CLICKPAD_X220); litest_add_for_device("touchpad:sendevents", touchpad_disabled_double_mouse_one_suspended, LITEST_SYNAPTICS_CLICKPAD_X220); + + litest_add("touchpad:pressure", touchpad_pressure, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:pressure", touchpad_pressure_2fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("touchpad:pressure", touchpad_pressure_2fg_st, LITEST_TOUCHPAD|LITEST_SINGLE_TOUCH, LITEST_ANY); + litest_add("touchpad:pressure", touchpad_pressure_tap, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:pressure", touchpad_pressure_tap_2fg, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:pressure", touchpad_pressure_tap_2fg_1fg_light, LITEST_TOUCHPAD, LITEST_ANY); }