diff --git a/meson.build b/meson.build index f1c59cf..a0cea38 100644 --- a/meson.build +++ b/meson.build @@ -66,6 +66,7 @@ src_libutil = [ 'src/util-sources.c', 'src/util-strings.c', 'src/util-strings.h', + 'src/util-time.h', ] lib_util = static_library('util', src_libutil) diff --git a/proto/ei.proto b/proto/ei.proto index c561f6e..1bf66f7 100644 --- a/proto/ei.proto +++ b/proto/ei.proto @@ -150,6 +150,7 @@ message StopEmulating { message Frame { uint32 deviceid = 1; + uint64 timestamp = 2; } message Property { diff --git a/src/libei-device.c b/src/libei-device.c index 8193fc1..a2881dc 100644 --- a/src/libei-device.c +++ b/src/libei-device.c @@ -348,13 +348,21 @@ ei_device_has_capability(struct ei_device *device, return false; } +static void +ei_device_frame_now(struct ei_device *device) +{ + uint64_t now = ei_now(ei_device_get_context(device)); + + ei_device_frame(device, now); +} + static void _flush_frame(struct ei_device *device, const char *func) { if (device->send_frame_event) { log_bug_client(ei_device_get_context(device), "%s: missing call to ei_device_frame()\n", func); - ei_device_frame(device); + ei_device_frame_now(device); } } #define ei_device_flush_frame(d_) _flush_frame(d_, __func__) @@ -617,7 +625,7 @@ ei_touch_destroy(struct ei_touch *touch) ei_touch_up(touch); /* Enforce a frame, otherwise we're just pending. If the client * doesn't want this, it needs to ei_touch_up() */ - ei_device_frame(touch->device); + ei_device_frame_now(touch->device); ei_device_unref(touch->device); } @@ -723,12 +731,12 @@ ei_touch_up(struct ei_touch *touch) } _public_ void -ei_device_frame(struct ei_device *device) +ei_device_frame(struct ei_device *device, uint64_t time) { if (device->state != EI_DEVICE_STATE_EMULATING) return; - ei_send_frame(device); + ei_send_frame(device, time); } void @@ -770,12 +778,12 @@ ei_device_event_stop_emulating(struct ei_device *device) } int -ei_device_event_frame(struct ei_device *device) +ei_device_event_frame(struct ei_device *device, uint64_t time) { if (device->state != EI_DEVICE_STATE_EMULATING) return -EINVAL; - ei_queue_frame_event(device); + ei_queue_frame_event(device, time); return 0; } diff --git a/src/libei-event.c b/src/libei-event.c index 45f5d99..f594501 100644 --- a/src/libei-event.c +++ b/src/libei-event.c @@ -422,3 +422,11 @@ ei_event_touch_get_y(struct ei_event *event) return event->touch.y; } + +_public_ uint64_t +ei_event_get_time(struct ei_event *event) +{ + require_event_type(event, 0, EI_EVENT_FRAME); + + return event->timestamp; +} diff --git a/src/libei-private.h b/src/libei-private.h index f96f506..3469714 100644 --- a/src/libei-private.h +++ b/src/libei-private.h @@ -182,6 +182,8 @@ struct ei_event { struct ei_seat *seat; /* NULL if device is non-NULL */ struct ei_device *device; + uint64_t timestamp; + union { struct ei_xkb_modifiers modifiers; struct { @@ -274,7 +276,7 @@ int ei_send_stop_emulating(struct ei_device *device); int -ei_send_frame(struct ei_device *device); +ei_send_frame(struct ei_device *device, uint64_t time); void ei_queue_device_removed_event(struct ei_device *device); @@ -292,7 +294,7 @@ void ei_queue_device_stop_emulating_event(struct ei_device *device); void -ei_queue_frame_event(struct ei_device *device); +ei_queue_frame_event(struct ei_device *device, uint64_t time); void ei_queue_pointer_rel_event(struct ei_device *device, double x, double y); @@ -342,7 +344,7 @@ void ei_device_removed_by_server(struct ei_device *device); int -ei_device_event_frame(struct ei_device *device); +ei_device_event_frame(struct ei_device *device, uint64_t time); void ei_device_event_start_emulating(struct ei_device *device); diff --git a/src/libei-proto.c b/src/libei-proto.c index ec435ab..38f07b2 100644 --- a/src/libei-proto.c +++ b/src/libei-proto.c @@ -207,7 +207,7 @@ ei_proto_handle_message(struct ei *ei, proto->touch_up->touchid); break; case SERVER_MESSAGE__MSG_FRAME: - rc = call(frame, ei, proto->frame->deviceid); + rc = call(frame, ei, proto->frame->deviceid, proto->frame->timestamp); break; default: rc = -EBADMSG; @@ -515,11 +515,12 @@ ei_proto_send_touch_up(struct ei_device *device, uint32_t tid) } static int -ei_proto_send_frame(struct ei_device *device) +ei_proto_send_frame(struct ei_device *device, uint64_t time) { prepare_msg(FRAME, Frame, frame); frame.deviceid = device->id; + frame.timestamp = time; return ei_proto_send_msg(ei_device_get_context(device), &msg); } diff --git a/src/libei-proto.h b/src/libei-proto.h index 37bf193..c9feb8b 100644 --- a/src/libei-proto.h +++ b/src/libei-proto.h @@ -75,7 +75,7 @@ struct ei_proto_interface { int (*touch_motion)(struct ei *ei, uint32_t deviceid, uint32_t tid, double x, double y); int (*touch_up)(struct ei *ei, uint32_t deviceid, uint32_t tid); - int (*frame) (struct ei *ei, uint32_t deviceid); + int (*frame) (struct ei *ei, uint32_t deviceid, uint64_t time); }; struct ei_proto_requests { @@ -101,7 +101,7 @@ struct ei_proto_requests { int (*touch_motion)(struct ei_device *device, uint32_t tid, double x, double y); int (*touch_up)(struct ei_device *device, uint32_t tid); - int (*frame)(struct ei_device *device); + int (*frame)(struct ei_device *device, uint64_t time); int (*property)(struct ei *ei, const char *name, const char *value, uint32_t permissions); diff --git a/src/libei.c b/src/libei.c index c5a7f5c..06452ff 100644 --- a/src/libei.c +++ b/src/libei.c @@ -28,15 +28,16 @@ #include #include #include +#include #include #include - #include "util-io.h" #include "util-macros.h" #include "util-object.h" #include "util-sources.h" #include "util-strings.h" +#include "util-time.h" #include "libei.h" #include "libei-private.h" @@ -226,7 +227,7 @@ queue_event(struct ei *ei, struct ei_event *event) default: if (device) { if (device->queue_frame_event) - ei_queue_frame_event(device); + ei_queue_frame_event(device, ei_now(ei)); device->queue_frame_event = false; } break; @@ -378,11 +379,12 @@ queue_property_event(struct ei *ei, const char *name, } void -ei_queue_frame_event(struct ei_device *device) +ei_queue_frame_event(struct ei_device *device, uint64_t time) { struct ei_event *e = ei_event_new_for_device(device); e->type = EI_EVENT_FRAME; + e->timestamp = time; queue_event(ei_device_get_context(device), e); } @@ -872,7 +874,7 @@ ei_send_seat_bind(struct ei_seat *seat, uint32_t capabilities) } int -ei_send_frame(struct ei_device *device) +ei_send_frame(struct ei_device *device, uint64_t time) { struct ei *ei = ei_device_get_context(device); @@ -884,7 +886,7 @@ ei_send_frame(struct ei_device *device) device->send_frame_event = false; - int rc = ei->requests->frame(device); + int rc = ei->requests->frame(device, time); if (rc) ei_disconnect(ei); return rc; @@ -1131,14 +1133,14 @@ handle_msg_stop_emulating(struct ei *ei, uint32_t deviceid) } static int -handle_msg_frame(struct ei *ei, uint32_t deviceid) +handle_msg_frame(struct ei *ei, uint32_t deviceid, uint64_t time) { DISCONNECT_IF_SENDER_CONTEXT(ei); struct ei_device *device = ei_find_device(ei, deviceid); if (device) - return ei_device_event_frame(device); + return ei_device_event_frame(device, time); return 0; } @@ -1427,6 +1429,22 @@ ei_configure_name(struct ei *ei, const char *name) ei->name = xstrdup(name); } +_public_ uint64_t +ei_now(struct ei *ei) +{ + uint64_t ts = 0; + int rc = now(&ts); + + if (rc < 0) { + /* We should probably disconnect here but the chances of this + * happening are so slim it's not worth worrying about. Plus, + * if this fails we're likely to be inside eis_device_frame() + * so we should flush a frame event before disconnecting and... */ + log_error(ei, "clock_gettime failed: %s\n", strerror(-rc)); + } + return ts; +} + #ifdef _enable_tests_ #include "util-munit.h" diff --git a/src/libei.h b/src/libei.h index a996bd9..110fe02 100644 --- a/src/libei.h +++ b/src/libei.h @@ -762,6 +762,12 @@ struct ei_device * ei_event_get_device(struct ei_event *event); /** + * Return the time for the event of type @ref EI_EVENT_FRAME in microseconds. + * + * @note: This function is currently only implemented for events of type @ref + * EI_EVENT_FRAME. In the future, it may become available to other event types + * too. + * * @return the event time in microseconds */ uint64_t @@ -1153,9 +1159,16 @@ ei_device_stop_emulating(struct ei_device *device); * Generate a frame event to group the current set of events * into a logical hardware event. This function **must** be called after any * other event has been generated. + * + * The given timestamp applies to all events in the current frame. + * The timestamp must be in microseconds of CLOCK_MONOTONIC, use the return + * value of ei_now() to get a compatible timestamp. + * + * @note libei does not prevent a caller from passing in a future time but it + * is strongly recommended that this is avoided by the caller. */ void -ei_device_frame(struct ei_device *device); +ei_device_frame(struct ei_device *device, uint64_t time); /** * Generate a relative motion event on a device with @@ -1564,6 +1577,16 @@ ei_event_touch_get_x(struct ei_event *event); double ei_event_touch_get_y(struct ei_event *event); +/** + * @returns a timestamp in microseconds for the current time to pass into + * ei_device_frame(). + * + * In the current implementation, the returned timestamp is CLOCK_MONOTONIC + * for compatibility with evdev and libinput. + */ +uint64_t +ei_now(struct ei *ei); + /** * @} */ diff --git a/src/libeis-client.c b/src/libeis-client.c index 4700c58..bf74c7c 100644 --- a/src/libeis-client.c +++ b/src/libeis-client.c @@ -298,14 +298,14 @@ client_msg_stop_emulating(struct eis_client *client, uint32_t deviceid) } static int -client_msg_frame(struct eis_client *client, uint32_t deviceid) +client_msg_frame(struct eis_client *client, uint32_t deviceid, uint64_t time) { DISCONNECT_IF_RECEIVER_CONTEXT(client); struct eis_device *device = eis_client_find_device(client, deviceid); if (device) - return eis_device_event_frame(device); + return eis_device_event_frame(device, time); return 0; } diff --git a/src/libeis-device.c b/src/libeis-device.c index 679009b..b494492 100644 --- a/src/libeis-device.c +++ b/src/libeis-device.c @@ -308,13 +308,21 @@ eis_device_has_capability(struct eis_device *device, eis->requests->func_(device_, device->id, __VA_ARGS__); \ } +static void +eis_device_frame_now(struct eis_device *device) +{ + uint64_t now = eis_now(eis_device_get_context(device)); + + eis_device_frame(device, now); +} + static void _flush_frame(struct eis_device *device, const char *func) { if (device->send_frame_event) { log_bug_client(eis_device_get_context(device), "%s: missing call to eis_device_frame()\n", func); - eis_device_frame(device); + eis_device_frame_now(device); } } #define eis_device_flush_frame(d_) _flush_frame(d_, __func__) @@ -564,7 +572,7 @@ eis_touch_destroy(struct eis_touch *touch) eis_touch_up(touch); /* Enforce a frame, otherwise we're just pending. If the client * doesn't want this, it needs to eis_touch_up() */ - eis_device_frame(touch->device); + eis_device_frame_now(touch->device); eis_device_unref(touch->device); } @@ -654,7 +662,7 @@ eis_touch_up(struct eis_touch *touch) } _public_ void -eis_device_frame(struct eis_device *device) +eis_device_frame(struct eis_device *device, uint64_t time) { if (device->state != EIS_DEVICE_STATE_EMULATING) return; @@ -665,16 +673,16 @@ eis_device_frame(struct eis_device *device) device->send_frame_event = false; - handle_request_noargs(device, frame); + handle_request(device, frame, time); } int -eis_device_event_frame(struct eis_device *device) +eis_device_event_frame(struct eis_device *device, uint64_t time) { if (device->state != EIS_DEVICE_STATE_EMULATING) return -EINVAL; - eis_queue_frame_event(device); + eis_queue_frame_event(device, time); return 0; } diff --git a/src/libeis-event.c b/src/libeis-event.c index 2b9d648..eedb4db 100644 --- a/src/libeis-event.c +++ b/src/libeis-event.c @@ -172,6 +172,14 @@ check_event_type(struct eis_event *event, if (!check_event_type(event_, __func__, __VA_ARGS__, -1)) \ return retval_; \ +_public_ uint64_t +eis_event_get_time(struct eis_event *event) +{ + require_event_type(event, 0, EIS_EVENT_FRAME); + + return event->timestamp; +} + _public_ bool eis_event_seat_has_capability(struct eis_event *event, enum eis_device_capability cap) { diff --git a/src/libeis-private.h b/src/libeis-private.h index 154a53f..2e6c52f 100644 --- a/src/libeis-private.h +++ b/src/libeis-private.h @@ -174,6 +174,8 @@ struct eis_event { struct eis_seat *seat; struct eis_device *device; + uint64_t timestamp; + union { struct { uint32_t capabilities; @@ -286,7 +288,7 @@ eis_device_set_client_keymap(struct eis_device *device, enum eis_keymap_type type, int keymap_fd, size_t size); int -eis_device_event_frame(struct eis_device *device); +eis_device_event_frame(struct eis_device *device, uint64_t time); int eis_device_event_pointer_rel(struct eis_device *device, @@ -371,7 +373,7 @@ void eis_queue_device_closed_event(struct eis_device *device); void -eis_queue_frame_event(struct eis_device *device); +eis_queue_frame_event(struct eis_device *device, uint64_t time); void eis_queue_device_start_emulating_event(struct eis_device *device); diff --git a/src/libeis-proto.c b/src/libeis-proto.c index 285bb92..d4c30bb 100644 --- a/src/libeis-proto.c +++ b/src/libeis-proto.c @@ -440,11 +440,12 @@ eis_proto_send_touch_up(struct eis_device *device, uint32_t deviceid, uint32_t t } static int -eis_proto_send_frame(struct eis_device *device, uint32_t deviceid) +eis_proto_send_frame(struct eis_device *device, uint32_t deviceid, uint64_t time) { prepare_msg(FRAME, Frame, frame); frame.deviceid = device->id; + frame.timestamp = time; return eis_proto_send_msg(eis_device_get_client(device), &msg); } @@ -613,7 +614,7 @@ eis_proto_handle_message(struct eis_client *client, proto->touch_up->touchid); break; case CLIENT_MESSAGE__MSG_FRAME: - rc = call(frame, client, proto->frame->deviceid); + rc = call(frame, client, proto->frame->deviceid, proto->frame->timestamp); break; default: rc = -EBADMSG; diff --git a/src/libeis-proto.h b/src/libeis-proto.h index 9927588..ed856f1 100644 --- a/src/libeis-proto.h +++ b/src/libeis-proto.h @@ -61,7 +61,7 @@ struct eis_proto_interface { int (*touch_motion)(struct eis_client *client, uint32_t deviceid, uint32_t tid, double x, double y); int (*touch_up)(struct eis_client *client, uint32_t deviceid, uint32_t tid); - int (*frame) (struct eis_client *client, uint32_t deviceid); + int (*frame) (struct eis_client *client, uint32_t deviceid, uint64_t time); }; struct eis_proto_requests { @@ -97,7 +97,7 @@ struct eis_proto_requests { int (*touch_motion)(struct eis_device *device, uint32_t deviceid, uint32_t tid, double x, double y); int (*touch_up)(struct eis_device *device, uint32_t deviceid, uint32_t tid); - int (*frame) (struct eis_device *device, uint32_t deviceid); + int (*frame) (struct eis_device *device, uint32_t deviceid, uint64_t time); }; int diff --git a/src/libeis.c b/src/libeis.c index a224e7e..02b796e 100644 --- a/src/libeis.c +++ b/src/libeis.c @@ -33,6 +33,7 @@ #include "util-object.h" #include "util-sources.h" #include "util-strings.h" +#include "util-time.h" #include "libeis.h" #include "libeis-proto.h" @@ -164,7 +165,7 @@ eis_queue_event(struct eis_event *event) default: if (device) { if (device->queue_frame_event) - eis_queue_frame_event(device); + eis_queue_frame_event(device, eis_now(eis)); device->queue_frame_event = false; } break; @@ -222,10 +223,11 @@ eis_queue_device_closed_event(struct eis_device *device) } void -eis_queue_frame_event(struct eis_device *device) +eis_queue_frame_event(struct eis_device *device, uint64_t time) { struct eis_event *e = eis_event_new_for_device(device); e->type = EIS_EVENT_FRAME; + e->timestamp = time; eis_queue_event(e); } @@ -392,3 +394,19 @@ eis_add_client(struct eis *eis, struct eis_client *client) { list_append(&eis->clients, &client->link); } + +_public_ uint64_t +eis_now(struct eis *eis) +{ + uint64_t ts = 0; + int rc = now(&ts); + + if (rc < 0) { + /* We should probably disconnect here but the chances of this + * happening are so slim it's not worth worrying about. Plus, + * if this fails we're likely to be inside ei_device_frame() + * so we should flush a frame event before disconnecting and... */ + log_error(eis, "clock_gettime failed: %s\n", strerror(-rc)); + } + return ts; +} diff --git a/src/libeis.h b/src/libeis.h index 23283c0..37f9fd6 100644 --- a/src/libeis.h +++ b/src/libeis.h @@ -953,7 +953,7 @@ eis_device_stop_emulating(struct eis_device *device); /** see @ref ei_device_frame */ void -eis_device_frame(struct eis_device *device); +eis_device_frame(struct eis_device *device, uint64_t time); /** see @ref ei_device_pointer_motion */ void @@ -1044,6 +1044,18 @@ eis_event_seat_has_capability(struct eis_event *event, enum eis_device_capabilit struct eis_device * eis_event_get_device(struct eis_event *event); +/** + * Return the time for the event of type @ref EIS_EVENT_FRAME in microseconds. + * + * @note: This function is currently only implemented for events of type @ref + * EIS_EVENT_FRAME. In the future, it may become available to other event types + * too. + * + * @return the event time in microseconds + */ +uint64_t +eis_event_get_time(struct eis_event *event); + /** * For an event of type @ref EIS_EVENT_POINTER_MOTION return the relative x * movement in logical pixels or mm, depending on the device type. @@ -1177,6 +1189,16 @@ eis_event_touch_get_x(struct eis_event *event); double eis_event_touch_get_y(struct eis_event *event); +/** + * @returns a timestamp for the current time to pass into + * eis_device_frame(). + * + * In the current implementation, the returned timestamp is CLOCK_MONOTONIC + * for compatibility with evdev and libinput. + */ +uint64_t +eis_now(struct eis *ei); + /** * @} */ diff --git a/src/util-time.h b/src/util-time.h new file mode 100644 index 0000000..52de366 --- /dev/null +++ b/src/util-time.h @@ -0,0 +1,79 @@ + +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2020 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once + +#include "config.h" + +#include +#include +#include +#include + +/* Merely for code readability, e.g. timeout = us(100); */ +static inline uint64_t +us(uint64_t us) +{ + return us; +} + +static inline uint64_t +us2ms(uint64_t us) +{ + return us * 1000; +} + +static inline uint64_t +ns2us(uint64_t ns) +{ + return us(ns / 1000); +} + +static inline uint64_t +ms2us(uint64_t ms) +{ + return us(ms * 1000); +} + +static inline uint64_t +s2us(uint64_t s) +{ + return ms2us(s * 1000); +} + +static inline int +now(uint64_t *now_out) +{ + struct timespec ts = { 0, 0 }; + + assert(now_out != NULL); + + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { + *now_out = s2us(ts.tv_sec) + ns2us(ts.tv_nsec); + return 0; + } else { + return -errno; + } +} diff --git a/test/eierpecken.c b/test/eierpecken.c index 083c1c9..b47271c 100644 --- a/test/eierpecken.c +++ b/test/eierpecken.c @@ -40,6 +40,7 @@ #include "util-logger.h" #include "util-object.h" #include "util-strings.h" +#include "util-time.h" DEFINE_TRISTATE(yes, no, unset); @@ -64,6 +65,8 @@ struct peck { struct ei_device *ei_abs; struct ei_device *ei_touch; + uint64_t now; + struct eis_client *eis_client; uint32_t indent; @@ -212,6 +215,34 @@ peck_ei_get_default_touch(struct peck *peck) return peck->ei_touch; }; +/* Ensures that device frames in tests always have an ascending and fixed + * interval. We start with 30 * interval in the past, every event then goes + * forward by 10ms. + * + * Tests that have more than 30 events will run into the future with their + * timestamps, shouldn't be an issue for the test suite though. + */ +uint64_t +peck_ei_now(struct peck *peck) +{ + const uint32_t interval = ms2us(10); + const uint32_t past_offset = interval * 30; + + peck->now = peck->now == 0 ? ei_now(peck->ei) - past_offset : peck->now + interval; + + return peck->now; +} + +uint64_t +peck_eis_now(struct peck *peck) +{ + const uint32_t interval = ms2us(10); + const uint32_t past_offset = interval * 30; + + peck->now = peck->now == 0 ? eis_now(peck->eis) - past_offset : peck->now + interval; + + return peck->now; +} static void peck_ei_log_handler(struct ei *ei, enum ei_log_priority priority, @@ -655,6 +686,7 @@ _peck_dispatch_eis(struct peck *peck, int lineno) struct eis *eis = peck->eis; bool had_event = false; bool need_frame = false; + static uint64_t last_timestamp; log_debug(peck, "EIS Dispatch, line %d\n", lineno); peck_indent(peck); @@ -747,6 +779,16 @@ _peck_dispatch_eis(struct peck *peck, int lineno) case EIS_EVENT_DEVICE_CLOSED: peck_eis_device_remove(peck, eis_event_get_device(e)); break; + case EIS_EVENT_FRAME: { + uint64_t timestamp = eis_event_get_time(e); + uint64_t ts_now = 0; + + munit_assert_int(now(&ts_now), ==, 0); + munit_assert_int64(last_timestamp, <, timestamp); + munit_assert_int64(last_timestamp, <=, ts_now); + last_timestamp = timestamp; + break; + } default: break; } diff --git a/test/eierpecken.h b/test/eierpecken.h index 341b533..d7dcbfa 100644 --- a/test/eierpecken.h +++ b/test/eierpecken.h @@ -23,6 +23,7 @@ */ #include "config.h" +#include #pragma once @@ -194,6 +195,12 @@ peck_ei_get_default_pointer_absolute(struct peck *peck); struct ei_device * peck_ei_get_default_touch(struct peck *peck); +uint64_t +peck_ei_now(struct peck *peck); + +uint64_t +peck_eis_now(struct peck *peck); + /** * Dispatch all events according to the currently defined behavior. * When this function returns false, the connection is in a "stable" state diff --git a/test/test-ei-device.c b/test/test-ei-device.c index 6b4acf3..ee9cf06 100644 --- a/test/test-ei-device.c +++ b/test/test-ei-device.c @@ -283,9 +283,9 @@ MUNIT_TEST(test_ei_device_keyboard_key) with_client(peck) { struct ei_device *device = peck_ei_get_default_keyboard(peck); ei_device_keyboard_key(device, KEY_Q, true); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_device_keyboard_key(device, KEY_Q, false); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); } peck_dispatch_until_stable(peck); @@ -317,11 +317,11 @@ MUNIT_TEST(test_ei_device_pointer_rel) with_client(peck) { struct ei_device *device = peck_ei_get_default_pointer(peck); ei_device_pointer_motion(device, 1, 2); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_device_pointer_motion(device, 0.3, 1.4); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_device_pointer_motion(device, 100, 200); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); } peck_dispatch_until_stable(peck); @@ -498,7 +498,7 @@ MUNIT_TEST(test_ei_device_pointer_abs) for (int i = 0; i < 10; i++) { ei_device_pointer_motion_absolute(device, 1 * i , 2 + i); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); } } @@ -522,9 +522,9 @@ MUNIT_TEST(test_ei_device_pointer_abs) /* outside of pointer range, expect to be discarded */ ei_device_pointer_motion_absolute(device, maxx + 1, maxy/2); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_device_pointer_motion_absolute(device, maxx/2 , maxy + 1); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); } peck_dispatch_until_stable(peck); @@ -567,9 +567,9 @@ MUNIT_TEST(test_ei_device_pointer_scroll) with_client(peck) { struct ei_device *device = peck_ei_get_default_pointer(peck); ei_device_pointer_scroll(device, 1.1, 2.2); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_device_pointer_scroll_discrete(device, 3, 4); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); } peck_dispatch_until_stable(peck); @@ -601,26 +601,26 @@ MUNIT_TEST(test_ei_device_pointer_scroll_stop) with_client(peck) { struct ei_device *device = peck_ei_get_default_pointer(peck); ei_device_pointer_scroll(device, 1.1, 2.2); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_device_pointer_scroll_stop(device, true, false); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_device_pointer_scroll_stop(device, false, true); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); /* This should not generate an event */ ei_device_pointer_scroll_stop(device, true, true); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); /* But scrolling again will re-enable stopping */ ei_device_pointer_scroll(device, 3.3, 4.4); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_device_pointer_scroll_stop(device, true, true); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_device_pointer_scroll(device, 3.3, 4.4); /* This one is a client bug and shouldn't trigger an event */ ei_device_pointer_scroll_stop(device, false, false); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); } peck_dispatch_until_stable(peck); @@ -670,26 +670,26 @@ MUNIT_TEST(test_ei_device_pointer_scroll_cancel) with_client(peck) { struct ei_device *device = peck_ei_get_default_pointer(peck); ei_device_pointer_scroll(device, 1.1, 2.2); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_device_pointer_scroll_cancel(device, true, false); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_device_pointer_scroll_cancel(device, false, true); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); /* This should not generate an event */ ei_device_pointer_scroll_cancel(device, true, true); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); /* But scrolling again will re-enable stopping */ ei_device_pointer_scroll(device, 3.3, 4.4); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_device_pointer_scroll_cancel(device, true, true); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_device_pointer_scroll(device, 3.3, 4.4); /* This one is a client bug and shouldn't trigger an event */ ei_device_pointer_scroll_cancel(device, false, false); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); } peck_dispatch_until_stable(peck); @@ -740,17 +740,17 @@ MUNIT_TEST(test_ei_device_pointer_scroll_stop_cancel) with_client(peck) { struct ei_device *device = peck_ei_get_default_pointer(peck); ei_device_pointer_scroll(device, 1.1, 2.2); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_device_pointer_scroll_stop(device, true, false); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_device_pointer_scroll_cancel(device, true, false); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_device_pointer_scroll_cancel(device, false, true); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); /* This should not generate an event */ ei_device_pointer_scroll_stop(device, true, true); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); } peck_dispatch_until_stable(peck); @@ -802,11 +802,11 @@ MUNIT_TEST(test_ei_device_touch) _unref_(ei_touch) *t = ei_device_touch_new(device); ei_touch_down(t, 1, 2); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_touch_motion(t, 200, 500); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_touch_up(t); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); } peck_dispatch_until_stable(peck); @@ -828,19 +828,19 @@ MUNIT_TEST(test_ei_device_touch) _unref_(ei_touch) *t = ei_device_touch_new(device); /* outside clip range, expect touch to be dropped */ ei_touch_down(t, maxx + 1, maxy/2); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_touch_motion(t, maxx + 1, maxy/3); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_touch_up(t); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); /* outside clip range, expect touch to be dropped */ ei_touch_down(t, maxx/2, maxy + 1); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_touch_motion(t, maxx/3, maxy + 1); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_touch_up(t); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); } peck_dispatch_until_stable(peck); @@ -852,12 +852,12 @@ MUNIT_TEST(test_ei_device_touch) with_client(peck) { _unref_(ei_touch) *t = ei_device_touch_new(device); ei_touch_down(t, 100, 200); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); /* outside allowed range, generates a touch up */ ei_touch_motion(t, maxx + 1, 200); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_touch_up(t); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); } peck_dispatch_until_stable(peck); @@ -871,7 +871,7 @@ MUNIT_TEST(test_ei_device_touch) with_client(peck) { _unref_(ei_touch) *t = ei_device_touch_new(device); ei_touch_down(t, 100, 100); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); /* client forgets to touch up, touch_unref takes care of it */ } @@ -890,14 +890,14 @@ MUNIT_TEST(test_ei_device_touch) /* touch never set down */ _unref_(ei_touch) *t2 = ei_device_touch_new(device); ei_touch_up(t2); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); /* touch never set down */ _unref_(ei_touch) *t3 = ei_device_touch_new(device); ei_touch_motion(t3, 100, 200); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_touch_up(t3); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); } peck_dispatch_until_stable(peck); @@ -909,15 +909,15 @@ MUNIT_TEST(test_ei_device_touch) /* touch re-used */ _unref_(ei_touch) *t = ei_device_touch_new(device); ei_touch_down(t, 100, 200); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_touch_up(t); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_touch_down(t, 200, 300); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_touch_motion(t, 300, 400); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_touch_up(t); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); } peck_dispatch_until_stable(peck); @@ -932,15 +932,15 @@ MUNIT_TEST(test_ei_device_touch) /* double-down, double-up */ _unref_(ei_touch) *t = ei_device_touch_new(device); ei_touch_down(t, 100, 200); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_touch_down(t, 200, 300); /* ignored */ - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_touch_motion(t, 300, 400); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_touch_up(t); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_touch_up(t); /* ignored */ - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); } peck_dispatch_until_stable(peck); @@ -972,14 +972,14 @@ MUNIT_TEST(test_ei_device_multitouch) _unref_(ei_touch) *t1 = ei_device_touch_new(device); _unref_(ei_touch) *t2 = ei_device_touch_new(device); ei_touch_down(t1, 1, 2); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_touch_motion(t1, 2, 3); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_touch_down(t2, 3, 4); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_touch_motion(t2, 4, 5); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_touch_up(t2); ei_touch_up(t1); @@ -1153,6 +1153,53 @@ MUNIT_TEST(test_ei_keyboard_modifiers) return MUNIT_OK; } +MUNIT_TEST(test_ei_frame_timestamp) +{ + _unref_(peck) *peck = peck_new(); + uint64_t ts1 = 0, ts2 = 0; + + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_NONE); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_RESUME_DEVICE); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ADD_KEYBOARD); + peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTODEVICES); + peck_dispatch_until_stable(peck); + + with_client(peck) { + ts1 = peck_ei_now(peck); + struct ei_device *device = peck_ei_get_default_keyboard(peck); + ei_device_keyboard_key(device, KEY_Q, true); + ei_device_frame(device, ts1); + + ts2 = peck_ei_now(peck); + ei_device_keyboard_key(device, KEY_Q, false); + ei_device_frame(device, ts2); + } + + peck_dispatch_until_stable(peck); + + with_server(peck) { + _unref_(eis_event) *kbd1 = + peck_eis_next_event(eis, EIS_EVENT_KEYBOARD_KEY); + _unref_(eis_event) *frame1 = + peck_eis_next_event(eis, EIS_EVENT_FRAME); + _unref_(eis_event) *kbd2 = + peck_eis_next_event(eis, EIS_EVENT_KEYBOARD_KEY); + _unref_(eis_event) *frame2 = + peck_eis_next_event(eis, EIS_EVENT_FRAME); + + uint64_t timestamp = eis_event_get_time(frame1); + munit_assert_uint64(timestamp, ==, ts1); + + timestamp = eis_event_get_time(frame2); + munit_assert_uint64(timestamp, ==, ts2); + + peck_assert_no_eis_events(eis); + } + + return MUNIT_OK; +} + MUNIT_TEST(test_ei_no_empty_frames) { _unref_(peck) *peck = peck_new(); @@ -1166,10 +1213,10 @@ MUNIT_TEST(test_ei_no_empty_frames) with_client(peck) { struct ei_device *device = peck_ei_get_default_keyboard(peck); - ei_device_frame(device); /* Expect to be filtered */ + ei_device_frame(device, peck_ei_now(peck)); /* Expect to be filtered */ ei_device_keyboard_key(device, KEY_Q, true); - ei_device_frame(device); - ei_device_frame(device); /* Expect to be filtered */ + ei_device_frame(device, peck_ei_now(peck)); + ei_device_frame(device, peck_ei_now(peck)); /* Expect to be filtered */ } peck_dispatch_until_stable(peck); @@ -1317,9 +1364,9 @@ MUNIT_TEST(test_passive_ei_device_keyboard_key) with_server(peck) { struct eis_device *device = peck_eis_get_default_keyboard(peck); eis_device_keyboard_key(device, KEY_Q, true); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_device_keyboard_key(device, KEY_Q, false); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); } peck_dispatch_until_stable(peck); @@ -1364,11 +1411,11 @@ MUNIT_TEST(test_passive_ei_device_pointer_rel) with_server(peck) { struct eis_device *device = peck_eis_get_default_pointer(peck); eis_device_pointer_motion(device, 1, 2); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_device_pointer_motion(device, 0.3, 1.4); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_device_pointer_motion(device, 100, 200); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); } peck_dispatch_until_stable(peck); @@ -1421,7 +1468,7 @@ MUNIT_TEST(test_passive_ei_device_pointer_abs) for (int i = 0; i < 10; i++) { eis_device_pointer_motion_absolute(device, 1 * i , 2 + i); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); } } @@ -1445,9 +1492,9 @@ MUNIT_TEST(test_passive_ei_device_pointer_abs) /* outside of pointer range, expect to be discarded */ eis_device_pointer_motion_absolute(device, maxx + 1, maxy/2); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_device_pointer_motion_absolute(device, maxx/2 , maxy + 1); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); } peck_dispatch_until_stable(peck); @@ -1500,9 +1547,9 @@ MUNIT_TEST(test_passive_ei_device_pointer_scroll) with_server(peck) { struct eis_device *device = peck_eis_get_default_pointer(peck); eis_device_pointer_scroll(device, 1.1, 2.2); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_device_pointer_scroll_discrete(device, 3, 4); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); } peck_dispatch_until_stable(peck); @@ -1547,26 +1594,26 @@ MUNIT_TEST(test_passive_ei_device_pointer_scroll_stop) with_server(peck) { struct eis_device *device = peck_eis_get_default_pointer(peck); eis_device_pointer_scroll(device, 1.1, 2.2); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_device_pointer_scroll_stop(device, true, false); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_device_pointer_scroll_stop(device, false, true); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); /* This should not generate an event */ eis_device_pointer_scroll_stop(device, true, true); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); /* But scrolling again will re-enable stopping */ eis_device_pointer_scroll(device, 3.3, 4.4); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_device_pointer_scroll_stop(device, true, true); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_device_pointer_scroll(device, 3.3, 4.4); /* This one is a client bug and shouldn't trigger an event */ eis_device_pointer_scroll_stop(device, false, false); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); } peck_dispatch_until_stable(peck); @@ -1629,26 +1676,26 @@ MUNIT_TEST(test_passive_ei_device_pointer_scroll_cancel) with_server(peck) { struct eis_device *device = peck_eis_get_default_pointer(peck); eis_device_pointer_scroll(device, 1.1, 2.2); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_device_pointer_scroll_cancel(device, true, false); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_device_pointer_scroll_cancel(device, false, true); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); /* This should not generate an event */ eis_device_pointer_scroll_cancel(device, true, true); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); /* But scrolling again will re-enable stopping */ eis_device_pointer_scroll(device, 3.3, 4.4); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_device_pointer_scroll_cancel(device, true, true); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_device_pointer_scroll(device, 3.3, 4.4); /* This one is a client bug and shouldn't trigger an event */ eis_device_pointer_scroll_cancel(device, false, false); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); } peck_dispatch_until_stable(peck); @@ -1712,21 +1759,21 @@ MUNIT_TEST(test_passive_ei_device_pointer_scroll_stop_cancel) with_server(peck) { struct eis_device *device = peck_eis_get_default_pointer(peck); eis_device_pointer_scroll(device, 1.1, 2.2); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); peck_mark(peck); eis_device_pointer_scroll_stop(device, true, false); peck_mark(peck); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_device_pointer_scroll_cancel(device, true, false); peck_mark(peck); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_device_pointer_scroll_cancel(device, false, true); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); peck_mark(peck); /* This should not generate an event */ eis_device_pointer_scroll_stop(device, true, true); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); } peck_dispatch_until_stable(peck); @@ -1793,11 +1840,11 @@ MUNIT_TEST(test_passive_ei_device_touch) _unref_(eis_touch) *t = eis_device_touch_new(device); eis_touch_down(t, 1, 2); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_touch_motion(t, 200, 500); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_touch_up(t); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); } peck_dispatch_until_stable(peck); @@ -1818,19 +1865,19 @@ MUNIT_TEST(test_passive_ei_device_touch) _unref_(eis_touch) *t = eis_device_touch_new(device); /* outside clip range, expect touch to be dropped */ eis_touch_down(t, maxx + 1, maxy/2); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_touch_motion(t, maxx + 1, maxy/3); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_touch_up(t); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); /* outside clip range, expect touch to be dropped */ eis_touch_down(t, maxx/2, maxy + 1); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_touch_motion(t, maxx/3, maxy + 1); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_touch_up(t); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); } peck_dispatch_until_stable(peck); @@ -1842,12 +1889,12 @@ MUNIT_TEST(test_passive_ei_device_touch) with_server(peck) { _unref_(eis_touch) *t = eis_device_touch_new(device); eis_touch_down(t, 100, 200); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); /* outside allowed range, generates a touch up */ eis_touch_motion(t, maxx + 1, 200); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_touch_up(t); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); } peck_dispatch_until_stable(peck); @@ -1861,7 +1908,7 @@ MUNIT_TEST(test_passive_ei_device_touch) with_server(peck) { _unref_(eis_touch) *t = eis_device_touch_new(device); eis_touch_down(t, 100, 100); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); /* client forgets to touch up, touch_unref takes care of it */ } @@ -1880,14 +1927,14 @@ MUNIT_TEST(test_passive_ei_device_touch) /* touch never set down */ _unref_(eis_touch) *t2 = eis_device_touch_new(device); eis_touch_up(t2); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); /* touch never set down */ _unref_(eis_touch) *t3 = eis_device_touch_new(device); eis_touch_motion(t3, 100, 200); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_touch_up(t3); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); } peck_dispatch_until_stable(peck); @@ -1899,15 +1946,15 @@ MUNIT_TEST(test_passive_ei_device_touch) /* touch re-used */ _unref_(eis_touch) *t = eis_device_touch_new(device); eis_touch_down(t, 100, 200); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_touch_up(t); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_touch_down(t, 200, 300); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_touch_motion(t, 300, 400); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_touch_up(t); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); } peck_dispatch_until_stable(peck); @@ -1922,15 +1969,15 @@ MUNIT_TEST(test_passive_ei_device_touch) /* double-down, double-up */ _unref_(eis_touch) *t = eis_device_touch_new(device); eis_touch_down(t, 100, 200); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_touch_down(t, 200, 300); /* ignored */ - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_touch_motion(t, 300, 400); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_touch_up(t); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_touch_up(t); /* ignored */ - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); } peck_dispatch_until_stable(peck); @@ -1963,18 +2010,18 @@ MUNIT_TEST(test_passive_ei_device_multitouch) _unref_(eis_touch) *t2 = eis_device_touch_new(device); eis_device_start_emulating(device); eis_touch_down(t1, 1, 2); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_touch_motion(t1, 2, 3); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_touch_down(t2, 3, 4); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_touch_motion(t2, 4, 5); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_touch_up(t2); eis_touch_up(t1); - eis_device_frame(device); + eis_device_frame(device, peck_eis_now(peck)); eis_device_stop_emulating(device); } @@ -2011,6 +2058,60 @@ MUNIT_TEST(test_passive_ei_device_multitouch) return MUNIT_OK; } +MUNIT_TEST(test_passive_ei_frame_timestamp) +{ + _unref_(peck) *peck = peck_new_context(PECK_EI_RECEIVER); + uint64_t ts1 = 0, ts2 = 0; + + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_NONE); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_RESUME_DEVICE); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ADD_KEYBOARD); + peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE); + peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNECT); + peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTODEVICES); + peck_dispatch_until_stable(peck); + + with_server(peck) { + struct eis_device *device = peck_eis_get_default_keyboard(peck); + eis_device_start_emulating(device); + + ts1 = peck_eis_now(peck); + eis_device_keyboard_key(device, KEY_Q, true); + eis_device_frame(device, ts1); + + ts2 = peck_eis_now(peck); + eis_device_keyboard_key(device, KEY_Q, false); + eis_device_frame(device, ts2); + } + + peck_dispatch_until_stable(peck); + + with_client(peck) { + _unref_(ei_event) *start = + peck_ei_next_event(ei, EI_EVENT_DEVICE_START_EMULATING); + _unref_(ei_event) *kbd1 = + peck_ei_next_event(ei, EI_EVENT_KEYBOARD_KEY); + _unref_(ei_event) *frame1 = + peck_ei_next_event(ei, EI_EVENT_FRAME); + _unref_(ei_event) *kbd2 = + peck_ei_next_event(ei, EI_EVENT_KEYBOARD_KEY); + _unref_(ei_event) *frame2 = + peck_ei_next_event(ei, EI_EVENT_FRAME); + + uint64_t timestamp = ei_event_get_time(frame1); + munit_assert_uint64(timestamp, ==, ts1); + + timestamp = ei_event_get_time(frame2); + munit_assert_uint64(timestamp, ==, ts2); + + peck_assert_no_ei_events(ei); + } + + return MUNIT_OK; +} + + MUNIT_TEST(test_passive_ei_flush_frame) { _unref_(peck) *peck = peck_new_context(PECK_EI_RECEIVER); diff --git a/test/test-ei.c b/test/test-ei.c index 855fa7a..7953692 100644 --- a/test/test-ei.c +++ b/test/test-ei.c @@ -921,7 +921,7 @@ MUNIT_TEST(test_xdotool_rel_motion) with_client(peck) { struct ei_device *device = peck_ei_get_default_pointer(peck); ei_device_pointer_motion(device, -1, 10); - ei_device_frame(device); + ei_device_frame(device, peck_ei_now(peck)); ei_device_close(device); ei_unref(ei); peck_drop_ei(peck); diff --git a/tools/ei-demo-client.c b/tools/ei-demo-client.c index dd842c2..d64f6d3 100644 --- a/tools/ei-demo-client.c +++ b/tools/ei-demo-client.c @@ -58,6 +58,7 @@ #include "src/util-memfile.h" #include "src/util-color.h" #include "src/util-strings.h" +#include "src/util-time.h" DEFINE_UNREF_CLEANUP_FUNC(ei); DEFINE_UNREF_CLEANUP_FUNC(ei_device); @@ -445,29 +446,38 @@ int main(int argc, char **argv) } if (!receiver) { + uint64_t now = ei_now(ei); + uint32_t interval = us2ms(10); /* pretend events are 10ms apart */ + if (have_ptr) { colorprint("sending motion event\n"); ei_device_pointer_motion(ptr, -1, 1); /* BTN_LEFT */ colorprint("sending button event\n"); ei_device_pointer_button(ptr, BTN_LEFT, true); - ei_device_frame(ptr); + ei_device_frame(ptr, now); + now += interval; ei_device_pointer_button(ptr, BTN_LEFT, false); - ei_device_frame(ptr); + ei_device_frame(ptr, now); + now += interval; colorprint("sending scroll events\n"); ei_device_pointer_scroll(ptr, 1, 1); - ei_device_frame(ptr); + ei_device_frame(ptr, now); + now += interval; ei_device_pointer_scroll_discrete(ptr, 1, 1); - ei_device_frame(ptr); + ei_device_frame(ptr, now); + now += interval; } if (have_kbd) { static int key = 0; colorprint("sending key event\n"); ei_device_keyboard_key(kbd, KEY_Q + key, true); /* KEY_Q */ - ei_device_frame(kbd); + ei_device_frame(kbd, now); + now += interval; ei_device_keyboard_key(kbd, KEY_Q + key, false); /* KEY_Q */ - ei_device_frame(kbd); + ei_device_frame(kbd, now); + now += interval; key = (key + 1) % 6; } @@ -475,7 +485,8 @@ int main(int argc, char **argv) static int x, y; colorprint("sending abs event\n"); ei_device_pointer_motion_absolute(abs, 150 + ++x, 150 - ++y); - ei_device_frame(abs); + ei_device_frame(abs, now); + now += interval; } } } diff --git a/tools/eis-demo-server.c b/tools/eis-demo-server.c index 14cc2b9..ea23a7b 100644 --- a/tools/eis-demo-server.c +++ b/tools/eis-demo-server.c @@ -58,6 +58,7 @@ #include "src/util-mem.h" #include "src/util-memfile.h" #include "src/util-strings.h" +#include "src/util-time.h" #include "eis-demo-server.h" @@ -575,6 +576,9 @@ int main(int argc, char **argv) } struct eis_demo_client *democlient; + uint64_t now = eis_now(eis); + const int interval = ms2us(12); /* events are 12ms apart */ + list_for_each(democlient, &server.clients, link) { if (eis_client_is_sender(democlient->client)) continue; @@ -588,23 +592,29 @@ int main(int argc, char **argv) /* BTN_LEFT */ colorprint("sending button event\n"); eis_device_pointer_button(ptr, BTN_LEFT, true); - eis_device_frame(ptr); + eis_device_frame(ptr, now); + now += interval; eis_device_pointer_button(ptr, BTN_LEFT, false); - eis_device_frame(ptr); + eis_device_frame(ptr, now); + now += interval; colorprint("sending scroll events\n"); eis_device_pointer_scroll(ptr, 1, 1); - eis_device_frame(ptr); + eis_device_frame(ptr, now); + now += interval; eis_device_pointer_scroll_discrete(ptr, 1, 1); - eis_device_frame(ptr); + eis_device_frame(ptr, now); + now += interval; } if (kbd) { static int key = 0; colorprint("sending key event\n"); eis_device_keyboard_key(kbd, KEY_Q + key, true); /* KEY_Q */ - eis_device_frame(kbd); + eis_device_frame(kbd, now); + now += interval; eis_device_keyboard_key(kbd, KEY_Q + key, false); /* KEY_Q */ - eis_device_frame(kbd); + eis_device_frame(kbd, now); + now += interval; key = (key + 1) % 6; } @@ -612,7 +622,8 @@ int main(int argc, char **argv) static int x, y; colorprint("sending abs event\n"); eis_device_pointer_motion_absolute(abs, 150 + ++x, 150 - ++y); - eis_device_frame(abs); + eis_device_frame(abs, now); + now += interval; } } }