From 0cd36225d73e609647208c0b3201769ac921a3ee Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 6 May 2015 19:41:25 -0400 Subject: [PATCH] touchpad: add support for per-finger hovering information When the device supports true hovering, it reports this information through ABS_MT_DISTANCE. When this axis is available, we should rely on it to (un)hover the touches as BTN_TOUCH is most of the time unreliable (generated by the mouse emulation in the kernel). Signed-off-by: Benjamin Tissoires Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad.c | 41 ++++++++++- src/evdev-mt-touchpad.h | 2 + test/Makefile.am | 1 + test/litest-atmel-hover.c | 149 ++++++++++++++++++++++++++++++++++++++ test/litest.c | 156 ++++++++++++++++++++++++++++++++++++---- test/litest.h | 24 ++++++- test/touchpad.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 537 insertions(+), 16 deletions(-) create mode 100644 test/litest-atmel-hover.c diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index e017559..79177fb 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -300,6 +300,9 @@ 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); @@ -520,7 +523,29 @@ tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) } static void -tp_unhover_touches(struct tp_dispatch *tp, uint64_t time) +tp_unhover_abs_distance(struct tp_dispatch *tp, uint64_t time) +{ + struct tp_touch *t; + unsigned int i; + + for (i = 0; i < tp->ntouches; i++) { + t = tp_get_touch(tp, i); + + 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); + } + } else { + if (t->distance > 0) + tp_end_touch(tp, t, time); + } + } +} + +static void +tp_unhover_fake_touches(struct tp_dispatch *tp, uint64_t time) { struct tp_touch *t; unsigned int nfake_touches; @@ -579,6 +604,16 @@ tp_unhover_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); + else + tp_unhover_fake_touches(tp, time); + +} + +static void tp_process_state(struct tp_dispatch *tp, uint64_t time) { struct tp_touch *t; @@ -1191,6 +1226,10 @@ tp_init(struct tp_dispatch *tp, device->abs.absinfo_y->minimum); diagonal = sqrt(width*width + height*height); + tp->reports_distance = libevdev_has_event_code(device->evdev, + EV_ABS, + ABS_MT_DISTANCE); + tp->hysteresis_margin.x = diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR; tp->hysteresis_margin.y = diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index d4f5874..3711375 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -129,6 +129,7 @@ struct tp_touch { bool dirty; struct device_coords point; uint64_t millis; + int distance; /* distance == 0 means touch */ struct { struct device_coords samples[TOUCHPAD_HISTORY_LENGTH]; @@ -183,6 +184,7 @@ struct tp_dispatch { unsigned int slot; /* current slot */ bool has_mt; bool semi_mt; + bool reports_distance; /* does the device support true hovering */ enum touchpad_model model; unsigned int num_slots; /* number of slots */ diff --git a/test/Makefile.am b/test/Makefile.am index be0c5d9..a90fa78 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -14,6 +14,7 @@ liblitest_la_SOURCES = \ litest.h \ litest-int.h \ litest-alps-semi-mt.c \ + litest-atmel-hover.c \ litest-bcm5974.c \ litest-generic-singletouch.c \ litest-keyboard.c \ diff --git a/test/litest-atmel-hover.c b/test/litest-atmel-hover.c new file mode 100644 index 0000000..7da0901 --- /dev/null +++ b/test/litest-atmel-hover.c @@ -0,0 +1,149 @@ +/* + * Copyright © 2015 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 +atmel_hover_create(struct litest_device *d); + +static void +litest_atmel_hover_setup(void) +{ + struct litest_device *d = litest_create_device(LITEST_ATMEL_HOVER); + litest_set_current_device(d); +} + +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_ABS, .code = ABS_MT_DISTANCE, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; + +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_ABS, .code = ABS_MT_DISTANCE, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; + +static 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_DISTANCE, .value = 1 }, + { .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = 0 }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; + +static struct litest_device_interface interface = { + .touch_down_events = down, + .touch_move_events = move, + .touch_up_events = up, +}; + +static struct input_id input_id = { + .bustype = 0x18, + .vendor = 0x0, + .product = 0x0, +}; + +static int events[] = { + EV_KEY, BTN_LEFT, + EV_KEY, BTN_TOOL_FINGER, + EV_KEY, BTN_TOUCH, + EV_KEY, BTN_TOOL_DOUBLETAP, + EV_KEY, BTN_TOOL_TRIPLETAP, + EV_KEY, BTN_TOOL_QUADTAP, + EV_KEY, BTN_TOOL_QUINTTAP, + INPUT_PROP_MAX, INPUT_PROP_POINTER, + INPUT_PROP_MAX, INPUT_PROP_BUTTONPAD, + -1, -1, +}; + +static struct input_absinfo absinfo[] = { + { ABS_X, 0, 960, 0, 0, 10 }, + { ABS_Y, 0, 540, 0, 0, 10 }, + { ABS_PRESSURE, 0, 255, 0, 0, 0 }, + { ABS_MT_SLOT, 0, 9, 0, 0, 0 }, + { ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0, 0 }, + { ABS_MT_ORIENTATION, 0, 255, 0, 0, 0 }, + { ABS_MT_POSITION_X, 0, 960, 0, 0, 10 }, + { ABS_MT_POSITION_Y, 0, 540, 0, 0, 10 }, + { ABS_MT_TOOL_TYPE, 0, 2, 0, 0, 0 }, + { ABS_MT_TRACKING_ID, 0, 65535, 0, 0, 0 }, + { ABS_MT_PRESSURE, 0, 255, 0, 0, 0 }, + { ABS_MT_DISTANCE, 0, 1, 0, 0, 0 }, + { .value = -1 } +}; + +struct litest_test_device litest_atmel_hover_device = { + .type = LITEST_ATMEL_HOVER, + .features = LITEST_TOUCHPAD | LITEST_BUTTON | LITEST_CLICKPAD | LITEST_HOVER, + .shortname = "atmel hover", + .setup = litest_atmel_hover_setup, + .interface = &interface, + .create = atmel_hover_create, + + .name = "Atmel maXTouch Touchpad", + .id = &input_id, + .events = events, + .absinfo = absinfo, +}; + +static void +atmel_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_atmel_hover_device.name, + litest_atmel_hover_device.id, + absinfo, + events); + d->interface = &interface; +} diff --git a/test/litest.c b/test/litest.c index d0043da..21ddca2 100644 --- a/test/litest.c +++ b/test/litest.c @@ -103,6 +103,7 @@ extern struct litest_test_device litest_wheel_only_device; extern struct litest_test_device litest_mouse_roccat_device; extern struct litest_test_device litest_ms_surface_cover_device; extern struct litest_test_device litest_logitech_trackball_device; +extern struct litest_test_device litest_atmel_hover_device; struct litest_test_device* devices[] = { &litest_synaptics_clickpad_device, @@ -127,6 +128,7 @@ struct litest_test_device* devices[] = { &litest_mouse_roccat_device, &litest_ms_surface_cover_device, &litest_logitech_trackball_device, + &litest_atmel_hover_device, NULL, }; @@ -795,7 +797,8 @@ litest_event(struct litest_device *d, unsigned int type, int litest_auto_assign_value(struct litest_device *d, const struct input_event *ev, - int slot, double x, double y) + int slot, double x, double y, + bool touching) { static int tracking_id; int value = ev->value; @@ -818,6 +821,9 @@ litest_auto_assign_value(struct litest_device *d, case ABS_MT_SLOT: value = slot; break; + case ABS_MT_DISTANCE: + value = touching ? 0 : 1; + break; } return value; @@ -834,9 +840,9 @@ send_btntool(struct litest_device *d) litest_event(d, EV_KEY, BTN_TOOL_QUINTTAP, d->ntouches_down == 5); } -void -litest_touch_down(struct litest_device *d, unsigned int slot, - double x, double y) +static void +litest_slot_start(struct litest_device *d, unsigned int slot, + double x, double y, bool touching) { struct input_event *ev; @@ -852,13 +858,26 @@ litest_touch_down(struct litest_device *d, unsigned int slot, ev = d->interface->touch_down_events; while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) { - int value = litest_auto_assign_value(d, ev, slot, x, y); + int value = litest_auto_assign_value(d, + ev, + slot, + x, + y, + touching); + litest_event(d, ev->type, ev->code, value); ev++; } } void +litest_touch_down(struct litest_device *d, unsigned int slot, + double x, double y) +{ + litest_slot_start(d, slot, x, y, 1); +} + +void litest_touch_up(struct litest_device *d, unsigned int slot) { struct input_event *ev; @@ -883,15 +902,20 @@ litest_touch_up(struct litest_device *d, unsigned int slot) ev = up; while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) { - int value = litest_auto_assign_value(d, ev, slot, 0, 0); + int value = litest_auto_assign_value(d, + ev, + slot, + 0, + 0, + false); litest_event(d, ev->type, ev->code, value); ev++; } } -void -litest_touch_move(struct litest_device *d, unsigned int slot, - double x, double y) +static void +litest_slot_move(struct litest_device *d, unsigned int slot, + double x, double y, bool touching) { struct input_event *ev; @@ -902,13 +926,25 @@ litest_touch_move(struct litest_device *d, unsigned int slot, ev = d->interface->touch_move_events; while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) { - int value = litest_auto_assign_value(d, ev, slot, x, y); + int value = litest_auto_assign_value(d, + ev, + slot, + x, + y, + touching); litest_event(d, ev->type, ev->code, value); ev++; } } void +litest_touch_move(struct litest_device *d, unsigned int slot, + double x, double y) +{ + litest_slot_move(d, slot, x, y, true); +} + +void litest_touch_move_to(struct litest_device *d, unsigned int slot, double x_from, double y_from, @@ -951,6 +987,98 @@ litest_touch_move_two_touches(struct litest_device *d, } void +litest_hover_start(struct litest_device *d, unsigned int slot, + double x, double y) +{ + litest_slot_start(d, slot, x, y, 0); +} + +void +litest_hover_end(struct litest_device *d, unsigned int slot) +{ + struct input_event *ev; + struct input_event up[] = { + { .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_DISTANCE, .value = 1 }, + { .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = -1 }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 } + }; + + assert(d->ntouches_down > 0); + d->ntouches_down--; + + send_btntool(d); + + if (d->interface->touch_up) { + d->interface->touch_up(d, slot); + return; + } else if (d->interface->touch_up_events) { + ev = d->interface->touch_up_events; + } else + ev = up; + + while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) { + int value = litest_auto_assign_value(d, ev, slot, 0, 0, 0); + litest_event(d, ev->type, ev->code, value); + ev++; + } +} + +void +litest_hover_move(struct litest_device *d, unsigned int slot, + double x, double y) +{ + litest_slot_move(d, slot, x, y, false); +} + +void +litest_hover_move_to(struct litest_device *d, + unsigned int slot, + double x_from, double y_from, + double x_to, double y_to, + int steps, int sleep_ms) +{ + for (int i = 0; i < steps - 1; i++) { + litest_hover_move(d, slot, + x_from + (x_to - x_from)/steps * i, + y_from + (y_to - y_from)/steps * i); + if (sleep_ms) { + libinput_dispatch(d->libinput); + msleep(sleep_ms); + libinput_dispatch(d->libinput); + } + } + litest_hover_move(d, slot, x_to, y_to); +} + +void +litest_hover_move_two_touches(struct litest_device *d, + double x0, double y0, + double x1, double y1, + double dx, double dy, + int steps, int sleep_ms) +{ + for (int i = 0; i < steps - 1; i++) { + litest_push_event_frame(d); + litest_hover_move(d, 0, x0 + dx / steps * i, + y0 + dy / steps * i); + litest_hover_move(d, 1, x1 + dx / steps * i, + y1 + dy / steps * i); + litest_pop_event_frame(d); + if (sleep_ms) { + libinput_dispatch(d->libinput); + msleep(sleep_ms); + libinput_dispatch(d->libinput); + } + } + litest_push_event_frame(d); + litest_hover_move(d, 0, x0 + dx, y0 + dy); + litest_hover_move(d, 1, x1 + dx, y1 + dy); + litest_pop_event_frame(d); +} + +void litest_button_click(struct litest_device *d, unsigned int button, bool is_press) { @@ -1490,11 +1618,11 @@ send_abs_xy(struct litest_device *d, double x, double y) e.type = EV_ABS; e.code = ABS_X; e.value = LITEST_AUTO_ASSIGN; - val = litest_auto_assign_value(d, &e, 0, x, y); + val = litest_auto_assign_value(d, &e, 0, x, y, true); litest_event(d, EV_ABS, ABS_X, val); e.code = ABS_Y; - val = litest_auto_assign_value(d, &e, 0, x, y); + val = litest_auto_assign_value(d, &e, 0, x, y, true); litest_event(d, EV_ABS, ABS_Y, val); } @@ -1507,12 +1635,12 @@ send_abs_mt_xy(struct litest_device *d, double x, double y) 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); + val = litest_auto_assign_value(d, &e, 0, x, y, true); 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); + val = litest_auto_assign_value(d, &e, 0, x, y, true); litest_event(d, EV_ABS, ABS_MT_POSITION_Y, val); } diff --git a/test/litest.h b/test/litest.h index f1a720c..23a8e87 100644 --- a/test/litest.h +++ b/test/litest.h @@ -57,6 +57,7 @@ enum litest_device_type { LITEST_WHEEL_ONLY = -21, LITEST_MOUSE_ROCCAT = -22, LITEST_LOGITECH_TRACKBALL = -23, + LITEST_ATMEL_HOVER = -24, }; enum litest_device_feature { @@ -77,6 +78,7 @@ enum litest_device_feature { LITEST_FAKE_MT = 1 << 12, LITEST_ABSOLUTE = 1 << 13, LITEST_PROTOCOL_A = 1 << 14, + LITEST_HOVER = 1 << 15, }; struct litest_device { @@ -141,7 +143,8 @@ void litest_event(struct litest_device *t, int value); int litest_auto_assign_value(struct litest_device *d, const struct input_event *ev, - int slot, double x, double y); + int slot, double x, double y, + bool touching); void litest_touch_up(struct litest_device *d, unsigned int slot); void litest_touch_move(struct litest_device *d, unsigned int slot, @@ -161,6 +164,25 @@ void litest_touch_move_two_touches(struct litest_device *d, double x1, double y1, double dx, double dy, int steps, int sleep_ms); +void litest_hover_start(struct litest_device *d, + unsigned int slot, + double x, + double y); +void litest_hover_end(struct litest_device *d, unsigned int slot); +void litest_hover_move(struct litest_device *d, + unsigned int slot, + double x, + double y); +void litest_hover_move_to(struct litest_device *d, + unsigned int slot, + double x_from, double y_from, + double x_to, double y_to, + int steps, int sleep_ms); +void litest_hover_move_two_touches(struct litest_device *d, + double x0, double y0, + double x1, double y1, + double dx, double dy, + int steps, int sleep_ms); void litest_button_click(struct litest_device *d, unsigned int button, bool is_press); diff --git a/test/touchpad.c b/test/touchpad.c index 450409e..c482d8d 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -3835,6 +3835,179 @@ START_TEST(touchpad_semi_mt_hover_2fg_1fg_down) } END_TEST +START_TEST(touchpad_hover_noevent) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_drain_events(li); + + litest_hover_start(dev, 0, 50, 50); + litest_hover_move_to(dev, 0, 50, 50, 70, 70, 10, 10); + litest_hover_end(dev, 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; + + litest_drain_events(li); + + /* hover the finger */ + litest_hover_start(dev, 0, 50, 50); + + litest_hover_move_to(dev, 0, 50, 50, 70, 70, 10, 10); + + litest_assert_empty_queue(li); + + /* touch the finger on the sensor */ + litest_touch_move_to(dev, 0, 70, 70, 50, 50, 10, 10); + + libinput_dispatch(li); + + litest_assert_only_typed_events(li, + LIBINPUT_EVENT_POINTER_MOTION); + + /* go back to hover */ + litest_hover_move_to(dev, 0, 50, 50, 70, 70, 10, 10); + litest_hover_end(dev, 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; + int i; + + litest_drain_events(li); + + litest_hover_start(dev, 0, 50, 50); + + for (i = 0; i < 3; i++) { + + /* hover the finger */ + litest_hover_move_to(dev, 0, 50, 50, 70, 70, 10, 10); + + litest_assert_empty_queue(li); + + /* touch the finger */ + litest_touch_move_to(dev, 0, 70, 70, 50, 50, 10, 10); + + libinput_dispatch(li); + + litest_assert_only_typed_events(li, + LIBINPUT_EVENT_POINTER_MOTION); + } + + litest_hover_end(dev, 0); + + /* 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); + + litest_assert_only_typed_events(li, + LIBINPUT_EVENT_POINTER_MOTION); +} +END_TEST + +START_TEST(touchpad_hover_down_up) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_drain_events(li); + + /* hover two fingers, and a touch */ + litest_push_event_frame(dev); + litest_hover_start(dev, 0, 50, 50); + litest_hover_start(dev, 1, 50, 50); + litest_touch_down(dev, 2, 50, 50); + litest_pop_event_frame(dev);; + + litest_assert_empty_queue(li); + + /* hover first finger, end second and third in same frame */ + litest_push_event_frame(dev); + litest_hover_move(dev, 0, 70, 70); + litest_hover_end(dev, 1); + litest_touch_up(dev, 2); + litest_pop_event_frame(dev);; + + litest_assert_empty_queue(li); + + /* now move the finger */ + litest_touch_move_to(dev, 0, 50, 50, 70, 70, 10, 10); + + litest_touch_up(dev, 0); + + litest_assert_only_typed_events(li, + LIBINPUT_EVENT_POINTER_MOTION); +} +END_TEST + +START_TEST(touchpad_hover_2fg_noevent) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_drain_events(li); + + /* hover two fingers */ + litest_push_event_frame(dev); + litest_hover_start(dev, 0, 25, 25); + litest_hover_start(dev, 1, 50, 50); + litest_pop_event_frame(dev);; + + litest_hover_move_two_touches(dev, 25, 25, 50, 50, 50, 50, 10, 0); + + litest_push_event_frame(dev); + litest_hover_end(dev, 0); + litest_hover_end(dev, 1); + litest_pop_event_frame(dev);; + + 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; + int i; + + litest_drain_events(li); + + /* hover two fingers */ + litest_push_event_frame(dev); + litest_hover_start(dev, 0, 25, 25); + litest_touch_down(dev, 1, 50, 50); + litest_pop_event_frame(dev);; + + for (i = 0; i < 10; i++) { + litest_push_event_frame(dev); + litest_hover_move(dev, 0, 25 + 5 * i, 25 + 5 * i); + litest_touch_move(dev, 1, 50 + 5 * i, 50 - 5 * i); + litest_pop_event_frame(dev);; + } + + litest_push_event_frame(dev); + litest_hover_end(dev, 0); + litest_touch_up(dev, 1); + litest_pop_event_frame(dev);; + + litest_assert_only_typed_events(li, + LIBINPUT_EVENT_POINTER_MOTION); +} +END_TEST + static void assert_btnevent_from_device(struct litest_device *device, unsigned int button, @@ -4242,6 +4415,13 @@ int main(int argc, char **argv) litest_add_for_device("touchpad:semi-mt-hover", touchpad_semi_mt_hover_2fg_noevent, LITEST_SYNAPTICS_HOVER_SEMI_MT); litest_add_for_device("touchpad:semi-mt-hover", touchpad_semi_mt_hover_2fg_1fg_down, LITEST_SYNAPTICS_HOVER_SEMI_MT); + litest_add("touchpad:hover", touchpad_hover_noevent, LITEST_TOUCHPAD|LITEST_HOVER, LITEST_ANY); + litest_add("touchpad:hover", touchpad_hover_down, LITEST_TOUCHPAD|LITEST_HOVER, LITEST_ANY); + litest_add("touchpad:hover", touchpad_hover_down_up, LITEST_TOUCHPAD|LITEST_HOVER, LITEST_ANY); + 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_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); litest_add_for_device("touchpad:trackpoint", touchpad_trackpoint_mb_click, LITEST_SYNAPTICS_TRACKPOINT_BUTTONS); -- 2.7.4