Introduce our own evdev_event struct

In addition to the evdev_frame this struct is what contains our actual
events instead of a struct input_event. The goal of this is twofold:
slightly better memory usage per frame since we can skip the timestamp
and refer to the evdev frame's timestamp only. This also improves
handling a frame since we no longer need to care about updating
all events when the timestamp changes during appending events.

Secondly it merges the evdev type + code into a single "usage"
(term obviously and shamelessly stolen from HID). Those usages
are the same as the code names but with an extra EVDEV_ prepended,
i.e.  EV_SYN / SYN_REPORT becomes EVDEV_SYN_REPORT.

And they are wrapped in a newtype so passing it around provides
some typesafety.

This only switches one part of the processing over, the dispatch
interfaces still use a struct input_event

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1215>
This commit is contained in:
Peter Hutterer 2025-06-05 13:28:23 +10:00
parent 540605f8e4
commit 41e988c99e
5 changed files with 299 additions and 119 deletions

View file

@ -303,6 +303,7 @@ foreach h: util_headers
executable('test-build-@0@'.format(h),
testfile,
include_directories : [includes_src, includes_include],
dependencies: [dep_libevdev],
install : false)
endforeach

View file

@ -28,10 +28,223 @@
#include "util-mem.h"
#include "util-input-event.h"
#include "util-newtype.h"
#include <stdbool.h>
#include <linux/input.h>
#define _evbit(t_, c_) ((t_) << 16 | (c_))
/**
* This is an enum to have the compiler help us a bit.
* The enum doesn't need to contain all event codes, only
* the ones we use in libinput - add to here as required.
*
* The order doesn't matter either since each enum value
* is just the type | code value anyway, keep it in somewhat
* logical groups where possible.
*/
enum evdev_usage {
EVDEV_SYN_REPORT = _evbit(EV_SYN, SYN_REPORT),
EVDEV_KEY_RESERVED = _evbit(EV_KEY, KEY_RESERVED),
EVDEV_KEY_ESC= _evbit(EV_KEY, KEY_ESC),
EVDEV_KEY_MICMUTE = _evbit(EV_KEY, KEY_MICMUTE),
EVDEV_KEY_OK = _evbit(EV_KEY, KEY_OK),
EVDEV_KEY_LIGHTS_TOGGLE = _evbit(EV_KEY, KEY_LIGHTS_TOGGLE),
EVDEV_KEY_ALS_TOGGLE = _evbit(EV_KEY, KEY_ALS_TOGGLE),
EVDEV_KEY_MAX = _evbit(EV_KEY, KEY_MAX),
EVDEV_BTN_LEFT = _evbit(EV_KEY, BTN_LEFT),
EVDEV_BTN_RIGHT = _evbit(EV_KEY, BTN_RIGHT),
EVDEV_BTN_MIDDLE = _evbit(EV_KEY, BTN_MIDDLE),
EVDEV_BTN_SIDE = _evbit(EV_KEY, BTN_SIDE),
EVDEV_BTN_EXTRA = _evbit(EV_KEY, BTN_EXTRA),
EVDEV_BTN_FORWARD = _evbit(EV_KEY, BTN_FORWARD),
EVDEV_BTN_BACK = _evbit(EV_KEY, BTN_BACK),
EVDEV_BTN_TASK = _evbit(EV_KEY, BTN_TASK),
EVDEV_BTN_JOYSTICK = _evbit(EV_KEY, BTN_JOYSTICK),
EVDEV_BTN_0 = _evbit(EV_KEY, BTN_0),
EVDEV_BTN_1 = _evbit(EV_KEY, BTN_1),
EVDEV_BTN_2 = _evbit(EV_KEY, BTN_2),
EVDEV_BTN_STYLUS = _evbit(EV_KEY, BTN_STYLUS),
EVDEV_BTN_STYLUS2 = _evbit(EV_KEY, BTN_STYLUS2),
EVDEV_BTN_STYLUS3 = _evbit(EV_KEY, BTN_STYLUS3),
EVDEV_BTN_TOUCH = _evbit(EV_KEY, BTN_TOUCH),
EVDEV_BTN_TOOL_PEN = _evbit(EV_KEY, BTN_TOOL_PEN),
EVDEV_BTN_TOOL_RUBBER = _evbit(EV_KEY, BTN_TOOL_RUBBER),
EVDEV_BTN_TOOL_BRUSH = _evbit(EV_KEY, BTN_TOOL_BRUSH),
EVDEV_BTN_TOOL_PENCIL = _evbit(EV_KEY, BTN_TOOL_PENCIL),
EVDEV_BTN_TOOL_AIRBRUSH = _evbit(EV_KEY, BTN_TOOL_AIRBRUSH),
EVDEV_BTN_TOOL_MOUSE = _evbit(EV_KEY, BTN_TOOL_MOUSE),
EVDEV_BTN_TOOL_LENS = _evbit(EV_KEY, BTN_TOOL_LENS),
EVDEV_BTN_TOOL_QUINTTAP = _evbit(EV_KEY, BTN_TOOL_QUINTTAP),
EVDEV_BTN_TOOL_DOUBLETAP = _evbit(EV_KEY, BTN_TOOL_DOUBLETAP),
EVDEV_BTN_TOOL_TRIPLETAP = _evbit(EV_KEY, BTN_TOOL_TRIPLETAP),
EVDEV_BTN_TOOL_QUADTAP = _evbit(EV_KEY, BTN_TOOL_QUADTAP),
EVDEV_BTN_TOOL_FINGER = _evbit(EV_KEY, BTN_TOOL_FINGER),
EVDEV_BTN_MISC = _evbit(EV_KEY, BTN_MISC),
EVDEV_BTN_GEAR_UP = _evbit(EV_KEY, BTN_GEAR_UP),
EVDEV_BTN_DPAD_UP = _evbit(EV_KEY, BTN_DPAD_UP),
EVDEV_BTN_DPAD_RIGHT = _evbit(EV_KEY, BTN_DPAD_RIGHT),
EVDEV_BTN_TRIGGER_HAPPY = _evbit(EV_KEY, BTN_TRIGGER_HAPPY),
EVDEV_BTN_TRIGGER_HAPPY40 = _evbit(EV_KEY, BTN_TRIGGER_HAPPY40),
EVDEV_REL_X = _evbit(EV_REL, REL_X),
EVDEV_REL_Y = _evbit(EV_REL, REL_Y),
EVDEV_REL_WHEEL = _evbit(EV_REL, REL_WHEEL),
EVDEV_REL_WHEEL_HI_RES = _evbit(EV_REL, REL_WHEEL_HI_RES),
EVDEV_REL_HWHEEL = _evbit(EV_REL, REL_HWHEEL),
EVDEV_REL_HWHEEL_HI_RES = _evbit(EV_REL, REL_HWHEEL_HI_RES),
EVDEV_REL_DIAL = _evbit(EV_REL, REL_DIAL),
EVDEV_REL_MAX = _evbit(EV_REL, REL_MAX),
EVDEV_ABS_X = _evbit(EV_ABS, ABS_X),
EVDEV_ABS_Y = _evbit(EV_ABS, ABS_Y),
EVDEV_ABS_Z = _evbit(EV_ABS, ABS_Z),
EVDEV_ABS_RX = _evbit(EV_ABS, ABS_RX),
EVDEV_ABS_RY = _evbit(EV_ABS, ABS_RY),
EVDEV_ABS_RZ = _evbit(EV_ABS, ABS_RZ),
EVDEV_ABS_PRESSURE = _evbit(EV_ABS, ABS_PRESSURE),
EVDEV_ABS_DISTANCE = _evbit(EV_ABS, ABS_DISTANCE),
EVDEV_ABS_THROTTLE = _evbit(EV_ABS, ABS_THROTTLE),
EVDEV_ABS_RUDDER = _evbit(EV_ABS, ABS_RUDDER),
EVDEV_ABS_WHEEL = _evbit(EV_ABS, ABS_WHEEL),
EVDEV_ABS_MISC = _evbit(EV_ABS, ABS_MISC),
EVDEV_ABS_TILT_X = _evbit(EV_ABS, ABS_TILT_X),
EVDEV_ABS_TILT_Y = _evbit(EV_ABS, ABS_TILT_Y),
EVDEV_ABS_MT_SLOT = _evbit(EV_ABS, ABS_MT_SLOT),
EVDEV_ABS_MT_POSITION_X = _evbit(EV_ABS, ABS_MT_POSITION_X),
EVDEV_ABS_MT_POSITION_Y = _evbit(EV_ABS, ABS_MT_POSITION_Y),
EVDEV_ABS_MT_TOOL_TYPE = _evbit(EV_ABS, ABS_MT_TOOL_TYPE),
EVDEV_ABS_MT_TRACKING_ID = _evbit(EV_ABS, ABS_MT_TRACKING_ID),
EVDEV_ABS_MT_TOUCH_MAJOR = _evbit(EV_ABS, ABS_MT_TOUCH_MAJOR),
EVDEV_ABS_MT_TOUCH_MINOR = _evbit(EV_ABS, ABS_MT_TOUCH_MINOR),
EVDEV_ABS_MT_ORIENTATION = _evbit(EV_ABS, ABS_MT_ORIENTATION),
EVDEV_ABS_MT_PRESSURE = _evbit(EV_ABS, ABS_MT_PRESSURE),
EVDEV_ABS_MT_DISTANCE = _evbit(EV_ABS, ABS_MT_DISTANCE),
EVDEV_ABS_MAX = _evbit(EV_ABS, ABS_MAX),
EVDEV_SW_LID = _evbit(EV_SW, SW_LID),
EVDEV_SW_TABLET_MODE = _evbit(EV_SW, SW_TABLET_MODE),
EVDEV_SW_MAX = _evbit(EV_SW, SW_MAX),
EVDEV_MSC_SCAN = _evbit(EV_MSC, MSC_SCAN),
EVDEV_MSC_SERIAL = _evbit(EV_MSC, MSC_SERIAL),
EVDEV_MSC_TIMESTAMP = _evbit(EV_MSC, MSC_TIMESTAMP),
};
/**
* Declares evdev_usage_t as uint32_t wrapper that we
* use for passing event codes around.
*
* This way we can't accidentally mix up a code vs
* type or a random integer with what needs to be a usage.
*/
DECLARE_NEWTYPE(evdev_usage, uint32_t);
static inline evdev_usage_t
evdev_usage_from(enum evdev_usage usage)
{
return evdev_usage_from_uint32_t((uint32_t)usage);
}
static inline enum evdev_usage
evdev_usage_enum(evdev_usage_t usage)
{
return (enum evdev_usage)evdev_usage_as_uint32_t(usage);
}
static inline evdev_usage_t
evdev_usage_from_code(unsigned int type, unsigned int code)
{
return evdev_usage_from_uint32_t(_evbit(type, code));
}
static inline uint16_t
evdev_usage_type(evdev_usage_t usage)
{
return evdev_usage_as_uint32_t(usage) >> 16;
}
static inline uint16_t
evdev_usage_code(evdev_usage_t usage)
{
return evdev_usage_as_uint32_t(usage) & 0xFFFF;
}
static inline const char *
evdev_usage_code_name(evdev_usage_t usage)
{
return libevdev_event_code_get_name(evdev_usage_type(usage),
evdev_usage_code(usage));
}
static inline const char *
evdev_usage_type_name(evdev_usage_t usage)
{
return libevdev_event_type_get_name(evdev_usage_type(usage));
}
struct evdev_event {
/* this may be a value outside the known usages above but it's just an int */
evdev_usage_t usage;
int32_t value;
};
static inline uint16_t
evdev_event_type(const struct evdev_event *e)
{
return evdev_usage_type(e->usage);
}
static inline uint16_t
evdev_event_code(const struct evdev_event *e)
{
return evdev_usage_code(e->usage);
}
static inline const char *
evdev_event_get_type_name(const struct evdev_event *e)
{
return evdev_usage_type_name(e->usage);
}
static inline const char *
evdev_event_get_code_name(const struct evdev_event *e)
{
return evdev_usage_code_name(e->usage);
}
static inline struct input_event
evdev_event_to_input_event(const struct evdev_event *e, uint64_t time)
{
struct timeval tv = us2tv(time);
return (struct input_event) {
.type = evdev_event_type(e),
.code = evdev_event_code(e),
.value = e->value,
.input_event_sec = tv.tv_sec,
.input_event_usec = tv.tv_usec,
};
}
static inline struct evdev_event
evdev_event_from_input_event(const struct input_event *e, uint64_t *time)
{
if (time)
*time = input_event_time(e);
return (struct evdev_event) {
.usage = evdev_usage_from_code(e->type, e->code),
.value = e->value,
};
}
/**
* A wrapper around a SYN_REPORT-terminated set of input events.
*
@ -49,7 +262,8 @@ struct evdev_frame {
int refcount;
size_t max_size;
size_t count;
struct input_event events[];
uint64_t time;
struct evdev_event events[];
};
static inline struct evdev_frame *
@ -88,7 +302,7 @@ evdev_frame_get_count(const struct evdev_frame *frame)
return frame->count;
}
static inline struct input_event *
static inline struct evdev_event *
evdev_frame_get_events(struct evdev_frame *frame, size_t *nevents)
{
if (nevents)
@ -103,24 +317,19 @@ evdev_frame_get_events(struct evdev_frame *frame, size_t *nevents)
static inline void
evdev_frame_set_time(struct evdev_frame *frame, uint64_t time)
{
assert(frame->count > 0);
for (size_t i = 0; i < frame->count; i++)
input_event_set_time(&frame->events[i], time);
frame->time = time;
}
static inline uint64_t
evdev_frame_get_time(const struct evdev_frame *frame)
{
assert(frame->count > 0);
return input_event_time(&frame->events[frame->count - 1]);
return frame->time;
}
static inline int
evdev_frame_reset(struct evdev_frame *frame)
{
memset(frame->events, 0, frame->max_size * sizeof(struct input_event));
memset(frame->events, 0, frame->max_size * sizeof(*frame->events));
frame->count = 1; /* SYN_REPORT is always there */
return 0;
@ -129,7 +338,7 @@ evdev_frame_reset(struct evdev_frame *frame)
static inline struct evdev_frame *
evdev_frame_new(size_t max_size)
{
struct evdev_frame *frame = zalloc(max_size * sizeof(struct input_event) + sizeof(*frame));
struct evdev_frame *frame = zalloc(max_size * sizeof(sizeof(*frame->events)) + sizeof(*frame));
frame->refcount = 1;
frame->max_size = max_size;
@ -142,12 +351,12 @@ static inline struct evdev_frame *
evdev_frame_new_on_stack(size_t max_size)
{
assert(max_size <= 64);
struct evdev_frame *frame = alloca(max_size * sizeof(struct input_event) + sizeof(*frame));
struct evdev_frame *frame = alloca(max_size * sizeof(*frame->events) + sizeof(*frame));
frame->refcount = 1;
frame->max_size = max_size;
frame->count = 1; /* SYN_REPORT is always there */
memset(frame->events, 0, max_size * sizeof(struct input_event));
memset(frame->events, 0, max_size * sizeof(*frame->events));
return frame;
}
@ -178,35 +387,41 @@ evdev_frame_new_on_stack(size_t max_size)
*/
static inline int
evdev_frame_append(struct evdev_frame *frame,
const struct input_event *events,
const struct evdev_event *events,
size_t nevents)
{
assert(nevents > 0);
uint64_t time = 0;
for (size_t i = 0; i < nevents; i++) {
if (events[i].type == EV_SYN && events[i].code == SYN_REPORT) {
if (evdev_usage_eq(events[i].usage, EVDEV_SYN_REPORT)) {
nevents = i;
time = input_event_time(&events[i]);
break;
}
time = max(time, input_event_time(&events[i]));
}
if (nevents > 0) {
if (frame->count + nevents > frame->max_size)
return -ENOMEM;
memcpy(frame->events + frame->count - 1, events, nevents * sizeof(struct input_event));
memcpy(frame->events + frame->count - 1, events, nevents * sizeof(*events));
frame->count += nevents;
}
if (time)
evdev_frame_set_time(frame, time);
return 0;
}
static inline int
evdev_frame_append_input_event(struct evdev_frame *frame,
const struct input_event *event)
{
struct evdev_event e = evdev_event_from_input_event(event, NULL);
if (evdev_usage_as_uint32_t(e.usage) == EVDEV_SYN_REPORT) {
uint64_t time = input_event_time(event);
evdev_frame_set_time(frame, time);
}
return evdev_frame_append(frame, &e, 1);
}
/**
* Behaves like evdev_frame_append() but resets the frame before appending.
*
@ -216,7 +431,7 @@ evdev_frame_append(struct evdev_frame *frame,
*/
static inline int
evdev_frame_set(struct evdev_frame *frame,
const struct input_event *events,
const struct evdev_event *events,
size_t nevents)
{
assert(nevents > 0);
@ -224,7 +439,7 @@ evdev_frame_set(struct evdev_frame *frame,
size_t count = nevents;
for (size_t i = 0; i < nevents; i++) {
if (events[i].type == EV_SYN && events[i].code == SYN_REPORT) {
if (evdev_usage_as_uint32_t(events[i].usage) == EVDEV_SYN_REPORT) {
count = i;
break;
}
@ -241,7 +456,7 @@ static inline struct evdev_frame *
evdev_frame_clone(struct evdev_frame *frame)
{
size_t nevents;
struct input_event *events = evdev_frame_get_events(frame, &nevents);
struct evdev_event *events = evdev_frame_get_events(frame, &nevents);
struct evdev_frame *clone = evdev_frame_new(nevents);
evdev_frame_append(clone, events, nevents);

View file

@ -1027,11 +1027,12 @@ evdev_read_switch_reliability_prop(struct evdev_device *device)
_unused_
static inline void
evdev_print_event(struct evdev_device *device,
const struct input_event *e)
const struct evdev_event *e,
uint64_t time_in_us)
{
static uint32_t offset = 0;
static uint32_t last_time = 0;
uint32_t time = us2ms(input_event_time(e));
uint32_t time = us2ms(time_in_us);
if (offset == 0) {
offset = time;
@ -1040,7 +1041,8 @@ evdev_print_event(struct evdev_device *device,
time -= offset;
if (libevdev_event_is_code(e, EV_SYN, SYN_REPORT)) {
switch (evdev_usage_enum(e->usage)) {
case EVDEV_SYN_REPORT:
evdev_log_debug(device,
"%u.%03u ----------------- EV_SYN ----------------- +%ums\n",
time / 1000,
@ -1048,53 +1050,63 @@ evdev_print_event(struct evdev_device *device,
time - last_time);
last_time = time;
} else if (libevdev_event_is_code(e, EV_MSC, MSC_SERIAL)) {
break;
case EVDEV_MSC_SERIAL:
evdev_log_debug(device,
"%u.%03u %-16s %-16s %#010x\n",
time / 1000,
time % 1000,
libevdev_event_type_get_name(e->type),
libevdev_event_code_get_name(e->type, e->code),
evdev_event_get_type_name(e),
evdev_event_get_code_name(e),
e->value);
} else {
break;
default:
evdev_log_debug(device,
"%u.%03u %-16s %-20s %4d\n",
time / 1000,
time % 1000,
libevdev_event_type_get_name(e->type),
libevdev_event_code_get_name(e->type, e->code),
evdev_event_get_type_name(e),
evdev_event_get_code_name(e),
e->value);
break;
}
}
static inline void
evdev_process_event(struct evdev_device *device, struct input_event *e)
evdev_process_event(struct evdev_device *device,
struct evdev_event *e,
uint64_t time)
{
struct evdev_dispatch *dispatch = device->dispatch;
uint64_t time = input_event_time(e);
#if EVENT_DEBUGGING
evdev_print_event(device, e);
evdev_print_event(device, e, time);
#endif
libinput_timer_flush(evdev_libinput_context(device), time);
dispatch->interface->process(dispatch, device, e, time);
struct input_event ev = evdev_event_to_input_event(e, time);
dispatch->interface->process(dispatch, device, &ev, time);
}
static inline void
evdev_device_dispatch_one(struct evdev_device *device,
struct input_event *ev)
struct evdev_event *ev,
uint64_t time)
{
if (!device->mtdev) {
evdev_process_event(device, ev);
evdev_process_event(device, ev, time);
} else {
mtdev_put_event(device->mtdev, ev);
if (libevdev_event_is_code(ev, EV_SYN, SYN_REPORT)) {
struct input_event e = evdev_event_to_input_event(ev, time);
mtdev_put_event(device->mtdev, &e);
if (evdev_usage_eq(ev->usage, EVDEV_SYN_REPORT)) {
while (!mtdev_empty(device->mtdev)) {
struct input_event e;
mtdev_get_event(device->mtdev, &e);
evdev_process_event(device, &e);
uint64_t time;
struct evdev_event ev = evdev_event_from_input_event(&e, &time);
evdev_process_event(device, &ev, time);
}
}
}
@ -1105,10 +1117,10 @@ evdev_device_dispatch_frame(struct evdev_device *device,
struct evdev_frame *frame)
{
size_t nevents;
struct input_event *events = evdev_frame_get_events(frame, &nevents);
struct evdev_event *events = evdev_frame_get_events(frame, &nevents);
for (size_t i = 0; i < nevents; i++) {
evdev_device_dispatch_one(device, &events[i]);
evdev_device_dispatch_one(device, &events[i], evdev_frame_get_time(frame));
}
}
@ -1127,7 +1139,7 @@ evdev_sync_device(struct evdev_device *device)
break;
/* No ENOMEM check here because >maxevents really should never happen */
evdev_frame_append(frame, &ev, 1);
evdev_frame_append_input_event(frame, &ev);
} while (rc == LIBEVDEV_READ_STATUS_SYNC);
evdev_device_dispatch_frame(device, frame);
@ -1188,7 +1200,7 @@ evdev_device_dispatch(void *data)
to the current state */
ev.code = SYN_REPORT;
if (evdev_frame_append(frame, &ev, 1) == -ENOMEM) {
if (evdev_frame_append_input_event(frame, &ev) == -ENOMEM) {
evdev_log_bug_libinput(device,
"event frame overflow, discarding events.\n");
}
@ -1204,7 +1216,7 @@ evdev_device_dispatch(void *data)
once = true;
}
if (evdev_frame_append(frame, &ev, 1) == -ENOMEM) {
if (evdev_frame_append_input_event(frame, &ev) == -ENOMEM) {
evdev_log_bug_libinput(device,
"event frame overflow, discarding events.\n");
}

View file

@ -27,9 +27,11 @@
#include "util-time.h"
#include "util-mem.h"
#include "util-newtype.h"
#include <string.h>
#include <stdbool.h>
#include <linux/input.h>
#include <libevdev/libevdev.h>
static inline struct input_event
input_event_init(uint64_t time,

View file

@ -2562,6 +2562,7 @@ END_TEST
START_TEST(evdev_frames)
{
#define U(u_) evdev_usage_from_uint32_t(u_)
{
evdev_frame_unref(NULL); /* unref on NULL is permitted */
}
@ -2574,21 +2575,21 @@ START_TEST(evdev_frames)
}
{
_unref_(evdev_frame) *frame = evdev_frame_new(3);
struct input_event toobig[] = {
{ .type = EV_ABS, .code = ABS_X, .value = 1, },
{ .type = EV_ABS, .code = ABS_Y, .value = 2, },
{ .type = EV_ABS, .code = ABS_Z, .value = 3, },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0, },
struct evdev_event toobig[] = {
{ .usage = U(EVDEV_ABS_X), .value = 1, },
{ .usage = U(EVDEV_ABS_Y), .value = 2, },
{ .usage = U(EVDEV_ABS_Z), .value = 3, },
{ .usage = U(EVDEV_SYN_REPORT), .value = 0, },
};
int rc = evdev_frame_set(frame, toobig, ARRAY_LENGTH(toobig));
litest_assert_int_eq(rc, -ENOMEM);
}
{
struct input_event events[] = {
{ .type = EV_ABS, .code = ABS_X, .value = 1, },
{ .type = EV_ABS, .code = ABS_Y, .value = 2, },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0, },
struct evdev_event events[] = {
{ .usage = U(EVDEV_ABS_X), .value = 1, },
{ .usage = U(EVDEV_ABS_Y), .value = 2, },
{ .usage = U(EVDEV_SYN_REPORT), .value = 0, },
};
_unref_(evdev_frame) *frame = evdev_frame_new(3);
@ -2607,10 +2608,10 @@ START_TEST(evdev_frames)
litest_assert_int_eq(rc, -ENOMEM);
}
{
struct input_event events[] = {
{ .type = EV_ABS, .code = ABS_X, .value = 1, },
{ .type = EV_ABS, .code = ABS_Y, .value = 2, },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0, },
struct evdev_event events[] = {
{ .usage = U(EVDEV_ABS_X), .value = 1, },
{ .usage = U(EVDEV_ABS_Y), .value = 2, },
{ .usage = U(EVDEV_SYN_REPORT), .value = 0, },
};
_unref_(evdev_frame) *frame = evdev_frame_new(3);
@ -2625,13 +2626,13 @@ START_TEST(evdev_frames)
litest_assert_int_eq(evdev_frame_get_count(frame), 3U); /* SYN_REPORT already there */
}
{
struct input_event interrupted[] = {
{ .type = EV_ABS, .code = ABS_X, .value = 1, },
{ .type = EV_ABS, .code = ABS_Y, .value = 2, },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0, },
{ .type = EV_ABS, .code = ABS_RX, .value = 1, },
{ .type = EV_ABS, .code = ABS_RY, .value = 2, },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0, },
struct evdev_event interrupted[] = {
{ .usage = U(EVDEV_ABS_X), .value = 1, },
{ .usage = U(EVDEV_ABS_Y), .value = 2, },
{ .usage = U(EVDEV_SYN_REPORT), .value = 0, },
{ .usage = U(EVDEV_ABS_RX), .value = 1, },
{ .usage = U(EVDEV_ABS_RY), .value = 2, },
{ .usage = U(EVDEV_SYN_REPORT), .value = 0, },
};
_unref_(evdev_frame) *frame = evdev_frame_new(5);
@ -2650,57 +2651,6 @@ START_TEST(evdev_frames)
/* We never appended a timestamp */
litest_assert_int_eq(evdev_frame_get_time(frame), 0U);
}
{
struct input_event e = {
.type = EV_ABS,
.code = ABS_X,
.value = 1,
.input_event_sec = 1234,
.input_event_usec = 567,
};
_unref_(evdev_frame) *frame = evdev_frame_new(3);
litest_assert_int_eq(evdev_frame_get_time(frame), 0U);
evdev_frame_append(frame, &e, 1);
litest_assert_int_eq(evdev_frame_get_time(frame), 1234000567U);
evdev_frame_append(frame, &e, 1);
litest_assert_int_eq(evdev_frame_get_time(frame), 1234000567U);
struct input_event syn = {
.type = EV_SYN,
.code = SYN_REPORT,
.value = 0,
.input_event_sec = 111,
.input_event_usec = 333,
};
litest_assert_neg_errno_success(evdev_frame_append(frame, &syn, 1));
litest_assert_int_eq(evdev_frame_get_time(frame), 111000333U);
/* SYN_REPORT overwrites lower timestamp */
syn.input_event_usec = 111;
litest_assert_neg_errno_success(evdev_frame_append(frame, &syn, 1));
litest_assert_int_eq(evdev_frame_get_time(frame), 111000111U);
}
{
/* Expect highest timestamp */
_unref_(evdev_frame) *frame = evdev_frame_new(4);
struct input_event mixed_times[] = {
{ .type = EV_ABS, .code = ABS_X, .value = 1, .input_event_sec = 12, .input_event_usec = 700, },
{ .type = EV_ABS, .code = ABS_Y, .value = 2, .input_event_sec = 56, .input_event_usec = 800, },
{ .type = EV_ABS, .code = ABS_Z, .value = 3, .input_event_sec = 34, .input_event_usec = 900, },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0, .input_event_sec = 0, .input_event_usec = 1, },
};
evdev_frame_set(frame, mixed_times, 3);
litest_assert_int_eq(evdev_frame_get_time(frame), 56000800U);
/* but SYN_REPORT overwrites any other timestamp */
evdev_frame_set(frame, mixed_times, 4);
litest_assert_int_eq(evdev_frame_get_time(frame), 1U);
}
}
END_TEST