diff --git a/src/libeis-device.c b/src/libeis-device.c index 4510ef1..a2345fb 100644 --- a/src/libeis-device.c +++ b/src/libeis-device.c @@ -749,8 +749,10 @@ client_msg_touch_up(struct eis_touchscreen *touchscreen, uint32_t touchid) "Touch up event for non-touch device"); } - if (device->state == EIS_DEVICE_STATE_EMULATING) { - if (release_touch(device, touchid)) + /* End the touch locally even if we're not emulating, but + * silently ignore touch end/cancel for non-existing touches */ + if (release_touch(device, touchid)) { + if (device->state == EIS_DEVICE_STATE_EMULATING) eis_queue_touch_up_event(device, touchid); return NULL; } @@ -776,8 +778,10 @@ client_msg_touch_cancel(struct eis_touchscreen *touchscreen, uint32_t touchid) "Touch cancel event for touchscreen version v1"); } - if (device->state == EIS_DEVICE_STATE_EMULATING) { - if (release_touch(device, touchid)) + /* End the touch locally even if we're not emulating, but + * silently ignore touch end/cancel for non-existing touches */ + if (release_touch(device, touchid)) { + if (device->state == EIS_DEVICE_STATE_EMULATING) eis_queue_touch_cancel_event(device, touchid); return NULL; } diff --git a/test/test-ei-device.c b/test/test-ei-device.c index df24604..782b8e4 100644 --- a/test/test-ei-device.c +++ b/test/test-ei-device.c @@ -1523,6 +1523,96 @@ MUNIT_TEST(test_ei_device_multitouch) return MUNIT_OK; } +MUNIT_TEST(test_ei_device_touch_up_after_paused) +{ + _unref_(peck) *peck = peck_new(); + _unref_(ei_device) *device = NULL; + _unref_(eis_device) *eis_device = NULL; + + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ADD_TOUCH); + peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTODEVICES); + peck_dispatch_until_stable(peck); + + _unref_(ei_touch) *t1 = NULL; + _unref_(ei_touch) *t2 = NULL; + + with_client(peck) { + device = ei_device_ref(peck_ei_get_default_touch(peck)); + t1 = ei_device_touch_new(device); + t2 = ei_device_touch_new(device); + ei_touch_down(t1, 1, 2); + ei_touch_down(t2, 3, 4); + ei_device_frame(device, peck_ei_now(peck)); + } + + peck_dispatch_until_stable(peck); + + with_server(peck) { + _unref_(eis_event) *down1 = peck_eis_touch_down(eis, 1, 2); + _unref_(eis_event) *down2 = peck_eis_touch_down(eis, 3, 4); + + peck_assert_no_eis_events(eis); /* drain the frame */ + + eis_device = eis_device_ref(eis_event_get_device(down1)); + eis_device_pause(eis_device); + } + + /* No ei dispatch here */ + peck_dispatch_eis(peck); + + with_client(peck) { + /* These events will arrive when the device is paused and + * are discarded by EIS */ + ei_touch_up(t1); + ei_touch_up(t2); + ei_device_frame(device, peck_ei_now(peck)); + ei_touch_unref(t1); + ei_touch_unref(t2); + } + + peck_dispatch_until_stable(peck); + + with_client(peck) { + _unref_(ei_event) *pause = peck_ei_next_event(ei, EI_EVENT_DEVICE_PAUSED); + } + + with_server(peck) { + /* touch up and empty frame were discarded */ + peck_assert_no_eis_events(eis); + eis_device_resume(eis_device); + } + + peck_dispatch_until_stable(peck); + + with_client(peck) { + ei_device_start_emulating(device, 123); + + /* The C API doesn't allow us to set a touch id + * so we can't really test for the correct behavior. + * All we can do is exercise most of the code by creating + * new touches and hope. + */ + t1 = ei_device_touch_new(device); + t2 = ei_device_touch_new(device); + ei_touch_down(t1, 1, 2); + ei_touch_down(t2, 3, 4); + ei_device_frame(device, peck_ei_now(peck)); + } + + peck_dispatch_until_stable(peck); + + with_server(peck) { + _unref_(eis_event) *down1 = peck_eis_touch_down(eis, 1, 2); + _unref_(eis_event) *down2 = peck_eis_touch_down(eis, 3, 4); + peck_assert_no_eis_events(eis); /* drain the frame */ + } + + peck_dispatch_until_stable(peck); + + return MUNIT_OK; +} + #if HAVE_MEMFD_CREATE MUNIT_TEST(test_ei_keymap_invalid) {