diff --git a/tools/libinput-record.c b/tools/libinput-record.c index d1472fe0..45fb02d7 100644 --- a/tools/libinput-record.c +++ b/tools/libinput-record.c @@ -74,32 +74,8 @@ enum indent { I_EVENT = 6, /* event data */ }; - -/* libinput is not designed to keep events past immediate use so we need to - * cache our events. Simplest way to do this is to just cache the printf - * output */ -struct li_event { - char msg[256]; -}; - -enum event_type { - NONE, - EVDEV, - LIBINPUT, - COMMENT, -}; - -struct event { - enum event_type type; - uint64_t time; - union { - struct input_event evdev; - struct li_event libinput; - char comment[200]; - } u; -}; - struct record_device { + struct record_context *ctx; struct list link; char *devnode; /* device node of the source device */ struct libevdev *evdev; @@ -107,15 +83,13 @@ struct record_device { deltas */ struct libinput_device *device; - struct event *events; - size_t nevents; - size_t events_sz; - struct { bool is_touch_device; uint16_t slot_state; uint16_t last_slot_state; } touch; + + FILE *fp; }; struct record_context { @@ -133,10 +107,8 @@ struct record_context { struct { char *name; /* file name given on cmdline */ char *name_with_suffix; /* full file name with suffix */ - FILE *fp; } output_file; - struct libinput *libinput; int epoll_fd; @@ -160,14 +132,6 @@ struct record_context { (sz_) = new_size; \ } -static struct event * -next_event(struct record_device *d) -{ - if (d->nevents == d->events_sz) - resize(d->events, d->events_sz); - return &d->events[d->nevents++]; -} - typedef void (*source_dispatch_t)(struct record_context *ctx, int fd, void *user_data); @@ -205,7 +169,7 @@ obfuscate_keycode(struct input_event *ev) */ LIBINPUT_ATTRIBUTE_PRINTF(3, 4) static void -iprintf(const struct record_context *ctx, +iprintf(FILE *fp, enum indent indent, const char *format, ...) { @@ -229,7 +193,7 @@ iprintf(const struct record_context *ctx, snprintf(fmt, sizeof(fmt), "%s%s", &space[len - indent - 1], format); va_start(args, format); - rc = vfprintf(ctx->output_file.fp, fmt, args); + rc = vfprintf(fp, fmt, args); va_end(args); assert(rc != -1 && (unsigned int)rc > indent); @@ -242,19 +206,18 @@ time_offset(struct record_context *ctx, uint64_t time) } static void -print_evdev_event(struct record_context *ctx, - struct record_device *dev, +print_evdev_event(struct record_device *dev, struct input_event *ev) { const char *tname, *cname; bool was_modified = false; char desc[1024]; - uint64_t time = input_event_time(ev) - ctx->offset; + uint64_t time = input_event_time(ev) - dev->ctx->offset; input_event_set_time(ev, time); /* Don't leak passwords unless the user wants to */ - if (!ctx->show_keycodes) + if (!dev->ctx->show_keycodes) was_modified = obfuscate_keycode(ev); tname = libevdev_event_type_get_name(ev->type); @@ -370,7 +333,7 @@ print_evdev_event(struct record_context *ctx, was_modified ? " (obfuscated)" : ""); } - iprintf(ctx, + iprintf(dev->fp, I_EVENT, "- [%3lu, %6u, %3d, %3d, %7d] # %s\n", ev->input_event_sec, @@ -381,30 +344,25 @@ print_evdev_event(struct record_context *ctx, desc); } -static size_t -handle_evdev_frame(struct record_context *ctx, struct record_device *d) +static bool +handle_evdev_frame(struct record_device *d) { struct libevdev *evdev = d->evdev; struct input_event e; - size_t count = 0; - uint32_t last_time = 0; - struct event *event; - while (libevdev_next_event(evdev, - LIBEVDEV_READ_FLAG_NORMAL, - &e) == LIBEVDEV_READ_STATUS_SUCCESS) { - uint64_t time = input_event_time(&e); + if (libevdev_next_event(evdev, LIBEVDEV_READ_FLAG_NORMAL, &e) != + LIBEVDEV_READ_STATUS_SUCCESS) + return false; - if (ctx->offset == 0) - ctx->offset = time; - else - time = time_offset(ctx, time); + iprintf(d->fp, I_EVENTTYPE, "- evdev:\n"); + do { - event = next_event(d); - event->type = EVDEV; - event->time = time; - event->u.evdev = e; - count++; + if (d->ctx->offset == 0) { + uint64_t time = input_event_time(&e); + d->ctx->offset = time; + } + + print_evdev_event(d, &e); if (d->touch.is_touch_device && e.type == EV_ABS && @@ -418,35 +376,29 @@ handle_evdev_frame(struct record_context *ctx, struct record_device *d) d->touch.slot_state &= ~(1 << slot); } - last_time = event->time; - if (e.type == EV_SYN && e.code == SYN_REPORT) break; - } + } while (libevdev_next_event(evdev, + LIBEVDEV_READ_FLAG_NORMAL, + &e) == LIBEVDEV_READ_STATUS_SUCCESS); if (d->touch.slot_state != d->touch.last_slot_state) { d->touch.last_slot_state = d->touch.slot_state; if (d->touch.slot_state == 0) { - event = next_event(d); - event->type = COMMENT; - event->time = last_time; - snprintf(event->u.comment, - sizeof(event->u.comment), + iprintf(d->fp, + I_EVENT, " # Touch device in neutral state\n"); - count++; } } - return count; + return true; } static void -buffer_device_notify(struct record_context *ctx, - struct libinput_event *e, - struct event *event) +print_device_notify(struct record_device *dev, struct libinput_event *e) { - struct libinput_device *dev = libinput_event_get_device(e); - struct libinput_seat *seat = libinput_device_get_seat(dev); + struct libinput_device *d = libinput_event_get_device(e); + struct libinput_seat *seat = libinput_device_get_seat(d); const char *type = NULL; switch(libinput_event_get_type(e)) { @@ -460,19 +412,16 @@ buffer_device_notify(struct record_context *ctx, abort(); } - event->time = 0; - snprintf(event->u.libinput.msg, - sizeof(event->u.libinput.msg), - "{type: %s, seat: %5s, logical_seat: %7s}", - type, - libinput_seat_get_physical_name(seat), - libinput_seat_get_logical_name(seat)); + iprintf(dev->fp, + I_EVENT, + "- {type: %s, seat: %5s, logical_seat: %7s}\n", + type, + libinput_seat_get_physical_name(seat), + libinput_seat_get_logical_name(seat)); } static void -buffer_key_event(struct record_context *ctx, - struct libinput_event *e, - struct event *event) +print_key_event(struct record_device *dev, struct libinput_event *e) { struct libinput_event_keyboard *k = libinput_event_get_keyboard_event(e); enum libinput_key_state state; @@ -488,29 +437,26 @@ buffer_key_event(struct record_context *ctx, abort(); } - time = time_offset(ctx, libinput_event_keyboard_get_time_usec(k)); + time = time_offset(dev->ctx, libinput_event_keyboard_get_time_usec(k)); state = libinput_event_keyboard_get_key_state(k); key = libinput_event_keyboard_get_key(k); - if (!ctx->show_keycodes && + if (!dev->ctx->show_keycodes && (key >= KEY_ESC && key < KEY_ZENKAKUHANKAKU)) key = -1; - event->time = time; - snprintf(event->u.libinput.msg, - sizeof(event->u.libinput.msg), - "{time: %ld.%06ld, type: %s, key: %d, state: %s}", - (long)(time / (int)1e6), - (long)(time % (int)1e6), - type, - key, - state == LIBINPUT_KEY_STATE_PRESSED ? "pressed" : "released"); + iprintf(dev->fp, + I_EVENT, + "- {time: %ld.%06ld, type: %s, key: %d, state: %s}\n", + (long)(time / (int)1e6), + (long)(time % (int)1e6), + type, + key, + state == LIBINPUT_KEY_STATE_PRESSED ? "pressed" : "released"); } static void -buffer_motion_event(struct record_context *ctx, - struct libinput_event *e, - struct event *event) +print_motion_event(struct record_device *dev, struct libinput_event *e) { struct libinput_event_pointer *p = libinput_event_get_pointer_event(e); double x = libinput_event_pointer_get_dx(p), @@ -528,22 +474,19 @@ buffer_motion_event(struct record_context *ctx, abort(); } - time = time_offset(ctx, libinput_event_pointer_get_time_usec(p)); - event->time = time; - snprintf(event->u.libinput.msg, - sizeof(event->u.libinput.msg), - "{time: %ld.%06ld, type: %s, delta: [%6.2f, %6.2f], unaccel: [%6.2f, %6.2f]}", - (long)(time / (int)1e6), - (long)(time % (int)1e6), - type, - x, y, - uax, uay); + time = time_offset(dev->ctx, libinput_event_pointer_get_time_usec(p)); + iprintf(dev->fp, + I_EVENT, + "- {time: %ld.%06ld, type: %s, delta: [%6.2f, %6.2f], unaccel: [%6.2f, %6.2f]}\n", + (long)(time / (int)1e6), + (long)(time % (int)1e6), + type, + x, y, + uax, uay); } static void -buffer_absmotion_event(struct record_context *ctx, - struct libinput_event *e, - struct event *event) +print_absmotion_event(struct record_device *dev, struct libinput_event *e) { struct libinput_event_pointer *p = libinput_event_get_pointer_event(e); double x = libinput_event_pointer_get_absolute_x(p), @@ -561,23 +504,20 @@ buffer_absmotion_event(struct record_context *ctx, abort(); } - time = time_offset(ctx, libinput_event_pointer_get_time_usec(p)); + time = time_offset(dev->ctx, libinput_event_pointer_get_time_usec(p)); - event->time = time; - snprintf(event->u.libinput.msg, - sizeof(event->u.libinput.msg), - "{time: %ld.%06ld, type: %s, point: [%6.2f, %6.2f], transformed: [%6.2f, %6.2f]}", - (long)(time / (int)1e6), - (long)(time % (int)1e6), - type, - x, y, - tx, ty); + iprintf(dev->fp, + I_EVENT, + "- {time: %ld.%06ld, type: %s, point: [%6.2f, %6.2f], transformed: [%6.2f, %6.2f]}\n", + (long)(time / (int)1e6), + (long)(time % (int)1e6), + type, + x, y, + tx, ty); } static void -buffer_pointer_button_event(struct record_context *ctx, - struct libinput_event *e, - struct event *event) +print_pointer_button_event(struct record_device *dev, struct libinput_event *e) { struct libinput_event_pointer *p = libinput_event_get_pointer_event(e); enum libinput_button_state state; @@ -593,26 +533,23 @@ buffer_pointer_button_event(struct record_context *ctx, abort(); } - time = time_offset(ctx, libinput_event_pointer_get_time_usec(p)); + time = time_offset(dev->ctx, libinput_event_pointer_get_time_usec(p)); button = libinput_event_pointer_get_button(p); state = libinput_event_pointer_get_button_state(p); - event->time = time; - snprintf(event->u.libinput.msg, - sizeof(event->u.libinput.msg), - "{time: %ld.%06ld, type: %s, button: %d, state: %s, seat_count: %u}", - (long)(time / (int)1e6), - (long)(time % (int)1e6), - type, - button, - state == LIBINPUT_BUTTON_STATE_PRESSED ? "pressed" : "released", - libinput_event_pointer_get_seat_button_count(p)); + iprintf(dev->fp, + I_EVENT, + "- {time: %ld.%06ld, type: %s, button: %d, state: %s, seat_count: %u}\n", + (long)(time / (int)1e6), + (long)(time % (int)1e6), + type, + button, + state == LIBINPUT_BUTTON_STATE_PRESSED ? "pressed" : "released", + libinput_event_pointer_get_seat_button_count(p)); } static void -buffer_pointer_axis_event(struct record_context *ctx, - struct libinput_event *e, - struct event *event) +print_pointer_axis_event(struct record_device *dev, struct libinput_event *e) { struct libinput_event_pointer *p = libinput_event_get_pointer_event(e); uint64_t time; @@ -628,7 +565,7 @@ buffer_pointer_axis_event(struct record_context *ctx, abort(); } - time = time_offset(ctx, libinput_event_pointer_get_time_usec(p)); + time = time_offset(dev->ctx, libinput_event_pointer_get_time_usec(p)); if (libinput_event_pointer_has_axis(p, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) { h = libinput_event_pointer_get_axis_value(p, @@ -653,22 +590,19 @@ buffer_pointer_axis_event(struct record_context *ctx, break; } - event->time = time; - snprintf(event->u.libinput.msg, - sizeof(event->u.libinput.msg), - "{time: %ld.%06ld, type: %s, axes: [%2.2f, %2.2f], discrete: [%d, %d], source: %s}", - (long)(time / (int)1e6), - (long)(time % (int)1e6), - type, - h, v, - hd, vd, - source); + iprintf(dev->fp, + I_EVENT, + "- {time: %ld.%06ld, type: %s, axes: [%2.2f, %2.2f], discrete: [%d, %d], source: %s}\n", + (long)(time / (int)1e6), + (long)(time % (int)1e6), + type, + h, v, + hd, vd, + source); } static void -buffer_touch_event(struct record_context *ctx, - struct libinput_event *e, - struct event *event) +print_touch_event(struct record_device *dev, struct libinput_event *e) { enum libinput_event_type etype = libinput_event_get_type(e); struct libinput_event_touch *t = libinput_event_get_touch_event(e); @@ -698,22 +632,21 @@ buffer_touch_event(struct record_context *ctx, abort(); } - time = time_offset(ctx, libinput_event_touch_get_time_usec(t)); + time = time_offset(dev->ctx, libinput_event_touch_get_time_usec(t)); if (etype != LIBINPUT_EVENT_TOUCH_FRAME) { slot = libinput_event_touch_get_slot(t); seat_slot = libinput_event_touch_get_seat_slot(t); } - event->time = time; switch (etype) { case LIBINPUT_EVENT_TOUCH_FRAME: - snprintf(event->u.libinput.msg, - sizeof(event->u.libinput.msg), - "{time: %ld.%06ld, type: %s}", - (long)(time / (int)1e6), - (long)(time % (int)1e6), - type); + iprintf(dev->fp, + I_EVENT, + "- {time: %ld.%06ld, type: %s}\n", + (long)(time / (int)1e6), + (long)(time % (int)1e6), + type); break; case LIBINPUT_EVENT_TOUCH_DOWN: case LIBINPUT_EVENT_TOUCH_MOTION: @@ -721,27 +654,28 @@ buffer_touch_event(struct record_context *ctx, y = libinput_event_touch_get_y(t); tx = libinput_event_touch_get_x_transformed(t, 100); ty = libinput_event_touch_get_y_transformed(t, 100); - snprintf(event->u.libinput.msg, - sizeof(event->u.libinput.msg), - "{time: %ld.%06ld, type: %s, slot: %d, seat_slot: %d, point: [%6.2f, %6.2f], transformed: [%6.2f, %6.2f]}", - (long)(time / (int)1e6), - (long)(time % (int)1e6), - type, - slot, - seat_slot, - x, y, - tx, ty); + iprintf(dev->fp, + I_EVENT, + "- {time: %ld.%06ld, type: %s, slot: %d, seat_slot: %d, " + "point: [%6.2f, %6.2f], transformed: [%6.2f, %6.2f]}\n", + (long)(time / (int)1e6), + (long)(time % (int)1e6), + type, + slot, + seat_slot, + x, y, + tx, ty); break; case LIBINPUT_EVENT_TOUCH_UP: case LIBINPUT_EVENT_TOUCH_CANCEL: - snprintf(event->u.libinput.msg, - sizeof(event->u.libinput.msg), - "{time: %ld.%06ld, type: %s, slot: %d, seat_slot: %d}", - (long)(time / (int)1e6), - (long)(time % (int)1e6), - type, - slot, - seat_slot); + iprintf(dev->fp, + I_EVENT, + "- {time: %ld.%06ld, type: %s, slot: %d, seat_slot: %d}\n", + (long)(time / (int)1e6), + (long)(time % (int)1e6), + type, + slot, + seat_slot); break; default: abort(); @@ -749,9 +683,7 @@ buffer_touch_event(struct record_context *ctx, } static void -buffer_gesture_event(struct record_context *ctx, - struct libinput_event *e, - struct event *event) +print_gesture_event(struct record_device *dev, struct libinput_event *e) { enum libinput_event_type etype = libinput_event_get_type(e); struct libinput_event_gesture *g = libinput_event_get_gesture_event(e); @@ -781,46 +713,45 @@ buffer_gesture_event(struct record_context *ctx, abort(); } - time = time_offset(ctx, libinput_event_gesture_get_time_usec(g)); - event->time = time; + time = time_offset(dev->ctx, libinput_event_gesture_get_time_usec(g)); switch (etype) { case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: case LIBINPUT_EVENT_GESTURE_PINCH_END: - snprintf(event->u.libinput.msg, - sizeof(event->u.libinput.msg), - "{time: %ld.%06ld, type: %s, nfingers: %d, " - "delta: [%6.2f, %6.2f], unaccel: [%6.2f, %6.2f], " - "angle_delta: %6.2f, scale: %6.2f}", - (long)(time / (int)1e6), - (long)(time % (int)1e6), - type, - libinput_event_gesture_get_finger_count(g), - libinput_event_gesture_get_dx(g), - libinput_event_gesture_get_dy(g), - libinput_event_gesture_get_dx_unaccelerated(g), - libinput_event_gesture_get_dy_unaccelerated(g), - libinput_event_gesture_get_angle_delta(g), - libinput_event_gesture_get_scale(g) - ); + iprintf(dev->fp, + I_EVENT, + "- {time: %ld.%06ld, type: %s, nfingers: %d, " + "delta: [%6.2f, %6.2f], unaccel: [%6.2f, %6.2f], " + "angle_delta: %6.2f, scale: %6.2f}\n", + (long)(time / (int)1e6), + (long)(time % (int)1e6), + type, + libinput_event_gesture_get_finger_count(g), + libinput_event_gesture_get_dx(g), + libinput_event_gesture_get_dy(g), + libinput_event_gesture_get_dx_unaccelerated(g), + libinput_event_gesture_get_dy_unaccelerated(g), + libinput_event_gesture_get_angle_delta(g), + libinput_event_gesture_get_scale(g) + ); break; case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: case LIBINPUT_EVENT_GESTURE_SWIPE_END: - snprintf(event->u.libinput.msg, - sizeof(event->u.libinput.msg), - "{time: %ld.%06ld, type: %s, nfingers: %d, " - "delta: [%6.2f, %6.2f], unaccel: [%6.2f, %6.2f]}", - (long)(time / (int)1e6), - (long)(time % (int)1e6), - type, - libinput_event_gesture_get_finger_count(g), - libinput_event_gesture_get_dx(g), - libinput_event_gesture_get_dy(g), - libinput_event_gesture_get_dx_unaccelerated(g), - libinput_event_gesture_get_dy_unaccelerated(g) - ); + iprintf(dev->fp, + I_EVENT, + "- {time: %ld.%06ld, type: %s, nfingers: %d, " + "delta: [%6.2f, %6.2f], unaccel: [%6.2f, %6.2f]}\n", + (long)(time / (int)1e6), + (long)(time % (int)1e6), + type, + libinput_event_gesture_get_finger_count(g), + libinput_event_gesture_get_dx(g), + libinput_event_gesture_get_dy(g), + libinput_event_gesture_get_dx_unaccelerated(g), + libinput_event_gesture_get_dy_unaccelerated(g) + ); break; default: abort(); @@ -913,9 +844,7 @@ out: } static void -buffer_tablet_tool_proximity_event(struct record_context *ctx, - struct libinput_event *e, - struct event *event) +print_tablet_tool_proximity_event(struct record_device *dev, struct libinput_event *e) { struct libinput_event_tablet_tool *t = libinput_event_get_tablet_tool_event(e); @@ -964,7 +893,7 @@ buffer_tablet_tool_proximity_event(struct record_context *ctx, } prox = libinput_event_tablet_tool_get_proximity_state(t); - time = time_offset(ctx, libinput_event_tablet_tool_get_time_usec(t)); + time = time_offset(dev->ctx, libinput_event_tablet_tool_get_time_usec(t)); axes = buffer_tablet_axes(t); idx = 0; @@ -982,25 +911,23 @@ buffer_tablet_tool_proximity_event(struct record_context *ctx, caps[idx++] = 'w'; assert(idx <= ARRAY_LENGTH(caps)); - event->time = time; - snprintf(event->u.libinput.msg, - sizeof(event->u.libinput.msg), - "{time: %ld.%06ld, type: %s, proximity: %s, tool-type: %s, serial: %" PRIu64 ", axes: %s, %s}", - (long)(time / (int)1e6), - (long)(time % (int)1e6), - type, - prox ? "in" : "out", - tool_type, - libinput_tablet_tool_get_serial(tool), - caps, - axes); + iprintf(dev->fp, + I_EVENT, + "- {time: %ld.%06ld, type: %s, proximity: %s, tool-type: %s, serial: %" PRIu64 ", axes: %s, %s}\n", + (long)(time / (int)1e6), + (long)(time % (int)1e6), + type, + prox ? "in" : "out", + tool_type, + libinput_tablet_tool_get_serial(tool), + caps, + axes); free(axes); } static void -buffer_tablet_tool_button_event(struct record_context *ctx, - struct libinput_event *e, - struct event *event) +print_tablet_tool_button_event(struct record_device *dev, + struct libinput_event *e) { struct libinput_event_tablet_tool *t = libinput_event_get_tablet_tool_event(e); @@ -1020,23 +947,20 @@ buffer_tablet_tool_button_event(struct record_context *ctx, button = libinput_event_tablet_tool_get_button(t); state = libinput_event_tablet_tool_get_button_state(t); - time = time_offset(ctx, libinput_event_tablet_tool_get_time_usec(t)); + time = time_offset(dev->ctx, libinput_event_tablet_tool_get_time_usec(t)); - event->time = time; - snprintf(event->u.libinput.msg, - sizeof(event->u.libinput.msg), - "{time: %ld.%06ld, type: %s, button: %d, state: %s}", - (long)(time / (int)1e6), - (long)(time % (int)1e6), - type, - button, - state ? "pressed" : "released"); + iprintf(dev->fp, + I_EVENT, + "- {time: %ld.%06ld, type: %s, button: %d, state: %s}\n", + (long)(time / (int)1e6), + (long)(time % (int)1e6), + type, + button, + state ? "pressed" : "released"); } static void -buffer_tablet_tool_event(struct record_context *ctx, - struct libinput_event *e, - struct event *event) +print_tablet_tool_event(struct record_device *dev, struct libinput_event *e) { struct libinput_event_tablet_tool *t = libinput_event_get_tablet_tool_event(e); @@ -1073,26 +997,24 @@ buffer_tablet_tool_event(struct record_context *ctx, } tip = libinput_event_tablet_tool_get_tip_state(t); - time = time_offset(ctx, libinput_event_tablet_tool_get_time_usec(t)); + time = time_offset(dev->ctx, libinput_event_tablet_tool_get_time_usec(t)); axes = buffer_tablet_axes(t); - event->time = time; - snprintf(event->u.libinput.msg, - sizeof(event->u.libinput.msg), - "{time: %ld.%06ld, type: %s%s, tip: %s, %s}", - (long)(time / (int)1e6), - (long)(time % (int)1e6), - type, - btn_buffer, /* may be empty string */ - tip ? "down" : "up", - axes); + iprintf(dev->fp, + I_EVENT, + "- {time: %ld.%06ld, type: %s%s, tip: %s, %s}\n", + (long)(time / (int)1e6), + (long)(time % (int)1e6), + type, + btn_buffer, /* may be empty string */ + tip ? "down" : "up", + axes); free(axes); } static void -buffer_tablet_pad_button_event(struct record_context *ctx, - struct libinput_event *e, - struct event *event) +print_tablet_pad_button_event(struct record_device *dev, + struct libinput_event *e) { struct libinput_event_tablet_pad *p = libinput_event_get_tablet_pad_event(e); @@ -1110,32 +1032,29 @@ buffer_tablet_pad_button_event(struct record_context *ctx, abort(); } - time = time_offset(ctx, libinput_event_tablet_pad_get_time_usec(p)); + time = time_offset(dev->ctx, libinput_event_tablet_pad_get_time_usec(p)); button = libinput_event_tablet_pad_get_button_number(p), state = libinput_event_tablet_pad_get_button_state(p); mode = libinput_event_tablet_pad_get_mode(p); group = libinput_event_tablet_pad_get_mode_group(p); - event->time = time; - snprintf(event->u.libinput.msg, - sizeof(event->u.libinput.msg), - "{time: %ld.%06ld, type: %s, button: %d, state: %s, mode: %d, is-toggle: %s}", - (long)(time / (int)1e6), - (long)(time % (int)1e6), - type, - button, - state == LIBINPUT_BUTTON_STATE_PRESSED ? "pressed" : "released", - mode, - libinput_tablet_pad_mode_group_button_is_toggle(group, button) ? "true" : "false" - ); + iprintf(dev->fp, + I_EVENT, + "- {time: %ld.%06ld, type: %s, button: %d, state: %s, mode: %d, is-toggle: %s}\n", + (long)(time / (int)1e6), + (long)(time % (int)1e6), + type, + button, + state == LIBINPUT_BUTTON_STATE_PRESSED ? "pressed" : "released", + mode, + libinput_tablet_pad_mode_group_button_is_toggle(group, button) ? "true" : "false" + ); } static void -buffer_tablet_pad_ringstrip_event(struct record_context *ctx, - struct libinput_event *e, - struct event *event) +print_tablet_pad_ringstrip_event(struct record_device *dev, struct libinput_event *e) { struct libinput_event_tablet_pad *p = libinput_event_get_tablet_pad_event(e); @@ -1178,26 +1097,23 @@ buffer_tablet_pad_ringstrip_event(struct record_context *ctx, abort(); } - time = time_offset(ctx, libinput_event_tablet_pad_get_time_usec(p)); + time = time_offset(dev->ctx, libinput_event_tablet_pad_get_time_usec(p)); mode = libinput_event_tablet_pad_get_mode(p); - event->time = time; - snprintf(event->u.libinput.msg, - sizeof(event->u.libinput.msg), - "{time: %ld.%06ld, type: %s, number: %d, position: %.2f, source: %s, mode: %d}", - (long)(time / (int)1e6), - (long)(time % (int)1e6), - type, - number, - pos, - source, - mode); + iprintf(dev->fp, + I_EVENT, + "- {time: %ld.%06ld, type: %s, number: %d, position: %.2f, source: %s, mode: %d}\n", + (long)(time / (int)1e6), + (long)(time % (int)1e6), + type, + number, + pos, + source, + mode); } static void -buffer_switch_event(struct record_context *ctx, - struct libinput_event *e, - struct event *event) +print_switch_event(struct record_device *dev, struct libinput_event *e) { struct libinput_event_switch *s = libinput_event_get_switch_event(e); enum libinput_switch_state state; @@ -1213,54 +1129,51 @@ buffer_switch_event(struct record_context *ctx, abort(); } - time = time_offset(ctx, libinput_event_switch_get_time_usec(s)); + time = time_offset(dev->ctx, libinput_event_switch_get_time_usec(s)); sw = libinput_event_switch_get_switch(s); state = libinput_event_switch_get_switch_state(s); - event->time = time; - snprintf(event->u.libinput.msg, - sizeof(event->u.libinput.msg), - "{time: %ld.%06ld, type: %s, switch: %d, state: %s}", - (long)(time / (int)1e6), - (long)(time % (int)1e6), - type, - sw, - state == LIBINPUT_SWITCH_STATE_ON ? "on" : "off"); + iprintf(dev->fp, + I_EVENT, + "- {time: %ld.%06ld, type: %s, switch: %d, state: %s}\n", + (long)(time / (int)1e6), + (long)(time % (int)1e6), + type, + sw, + state == LIBINPUT_SWITCH_STATE_ON ? "on" : "off"); } static void -buffer_libinput_event(struct record_context *ctx, - struct libinput_event *e, - struct event *event) +print_libinput_event(struct record_device *dev, struct libinput_event *e) { switch (libinput_event_get_type(e)) { case LIBINPUT_EVENT_NONE: abort(); case LIBINPUT_EVENT_DEVICE_ADDED: case LIBINPUT_EVENT_DEVICE_REMOVED: - buffer_device_notify(ctx, e, event); + print_device_notify(dev, e); break; case LIBINPUT_EVENT_KEYBOARD_KEY: - buffer_key_event(ctx, e, event); + print_key_event(dev, e); break; case LIBINPUT_EVENT_POINTER_MOTION: - buffer_motion_event(ctx, e, event); + print_motion_event(dev, e); break; case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: - buffer_absmotion_event(ctx, e, event); + print_absmotion_event(dev, e); break; case LIBINPUT_EVENT_POINTER_BUTTON: - buffer_pointer_button_event(ctx, e, event); + print_pointer_button_event(dev, e); break; case LIBINPUT_EVENT_POINTER_AXIS: - buffer_pointer_axis_event(ctx, e, event); + print_pointer_axis_event(dev, e); break; case LIBINPUT_EVENT_TOUCH_DOWN: case LIBINPUT_EVENT_TOUCH_UP: case LIBINPUT_EVENT_TOUCH_MOTION: case LIBINPUT_EVENT_TOUCH_CANCEL: case LIBINPUT_EVENT_TOUCH_FRAME: - buffer_touch_event(ctx, e, event); + print_touch_event(dev, e); break; case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: @@ -1268,119 +1181,49 @@ buffer_libinput_event(struct record_context *ctx, case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: case LIBINPUT_EVENT_GESTURE_SWIPE_END: - buffer_gesture_event(ctx, e, event); + print_gesture_event(dev, e); break; case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY: - buffer_tablet_tool_proximity_event(ctx, e, event); + print_tablet_tool_proximity_event(dev, e); break; case LIBINPUT_EVENT_TABLET_TOOL_AXIS: case LIBINPUT_EVENT_TABLET_TOOL_TIP: - buffer_tablet_tool_event(ctx, e, event); + print_tablet_tool_event(dev, e); break; case LIBINPUT_EVENT_TABLET_TOOL_BUTTON: - buffer_tablet_tool_button_event(ctx, e, event); + print_tablet_tool_button_event(dev, e); break; case LIBINPUT_EVENT_TABLET_PAD_BUTTON: - buffer_tablet_pad_button_event(ctx, e, event); + print_tablet_pad_button_event(dev, e); break; case LIBINPUT_EVENT_TABLET_PAD_RING: case LIBINPUT_EVENT_TABLET_PAD_STRIP: - buffer_tablet_pad_ringstrip_event(ctx, e, event); + print_tablet_pad_ringstrip_event(dev, e); break; case LIBINPUT_EVENT_SWITCH_TOGGLE: - buffer_switch_event(ctx, e, event); + print_switch_event(dev, e); break; default: break; } } -static void -print_cached_events(struct record_context *ctx, - struct record_device *d, - unsigned int offset, - int len) -{ - unsigned int idx; - enum event_type last_type; - uint64_t last_time; - - if (len == -1) - len = d->nevents - offset; - assert(offset + len <= d->nevents); - - if (offset == 0) { - last_type = NONE; - last_time = 0; - } else { - last_type = d->events[offset - 1].type; - last_time = d->events[offset - 1].time; - } - - idx = offset; - while (idx < offset + len) { - struct event *e; - - e = &d->events[idx++]; - if (e->type != last_type || e->time != last_time) { - bool new_frame = false; - - if (last_time == 0 || e->time != last_time) - new_frame = true; - - switch(e->type) { - case EVDEV: - if (new_frame) - iprintf(ctx, I_EVENTTYPE, "- evdev:\n"); - else - iprintf(ctx, I_EVENTTYPE, "evdev:\n"); - break; - case LIBINPUT: - if (new_frame) - iprintf(ctx, I_EVENTTYPE, "- libinput:\n"); - else - iprintf(ctx, I_EVENTTYPE, "libinput:\n"); - break; - case COMMENT: - break; - default: - abort(); - } - - last_type = e->type; - } - - switch (e->type) { - case EVDEV: - print_evdev_event(ctx, d, &e->u.evdev); - break; - case LIBINPUT: - iprintf(ctx, I_EVENT, "- %s\n", e->u.libinput.msg); - break; - case COMMENT: - iprintf(ctx, I_EVENT, "%s", e->u.comment); - break; - default: - abort(); - } - - last_time = e->time; - } -} - -static size_t +static bool handle_libinput_events(struct record_context *ctx, - struct record_device *d) + struct record_device *d, + bool start_frame) { struct libinput_event *e; - size_t count = 0; struct record_device *current = d; libinput_dispatch(ctx->libinput); + e = libinput_get_event(ctx->libinput); + if (!e) + return false; - while ((e = libinput_get_event(ctx->libinput)) != NULL) { + iprintf(d->fp, I_EVENTTYPE, "%slibinput:\n", start_frame ? "- " : ""); + do { struct libinput_device *device = libinput_event_get_device(e); - struct event *event; if (device != current->device) { struct record_device *tmp; @@ -1395,59 +1238,49 @@ handle_libinput_events(struct record_context *ctx, assert(found); } - event = next_event(current); - event->type = LIBINPUT; - buffer_libinput_event(ctx, e, event); - - if (current == d) - count++; + print_libinput_event(current, e); libinput_event_destroy(e); - } - return count; + } while ((e = libinput_get_event(ctx->libinput)) != NULL); + + return true; } static void -handle_events(struct record_context *ctx, struct record_device *d, bool print) +handle_events(struct record_context *ctx, struct record_device *d) { - while(true) { - size_t first_idx = d->nevents; - size_t evcount = 0, - licount = 0; + bool has_events = true; - evcount = handle_evdev_frame(ctx, d); + while (has_events) { + has_events = handle_evdev_frame(d); if (ctx->libinput) - licount = handle_libinput_events(ctx, d); - - if (evcount == 0 && licount == 0) - break; - - if (!print) - continue; - - print_cached_events(ctx, d, first_idx, evcount + licount); + has_events |= handle_libinput_events(ctx, + d, + !has_events); } + + fflush(d->fp); } static void -print_libinput_header(struct record_context *ctx) +print_libinput_header(FILE *fp, int timeout) { - iprintf(ctx, I_TOPLEVEL, "libinput:\n"); - iprintf(ctx, I_LIBINPUT, "version: \"%s\"\n", LIBINPUT_VERSION); - iprintf(ctx, I_LIBINPUT, "git: \"%s\"\n", LIBINPUT_GIT_VERSION); - if (ctx->timeout > 0) - iprintf(ctx, I_LIBINPUT, "autorestart: %d\n", ctx->timeout); + iprintf(fp, I_TOPLEVEL, "libinput:\n"); + iprintf(fp, I_LIBINPUT, "version: \"%s\"\n", LIBINPUT_VERSION); + iprintf(fp, I_LIBINPUT, "git: \"%s\"\n", LIBINPUT_GIT_VERSION); + if (timeout > 0) + iprintf(fp, I_LIBINPUT, "autorestart: %d\n", timeout); } static void -print_system_header(struct record_context *ctx) +print_system_header(FILE *fp) { struct utsname u; const char *kernel = "unknown"; FILE *dmi, *osrelease; char dmistr[2048] = "unknown"; - iprintf(ctx, I_TOPLEVEL, "system:\n"); + iprintf(fp, I_TOPLEVEL, "system:\n"); /* /etc/os-release version and distribution name */ osrelease = fopen("/etc/os-release", "r"); @@ -1466,7 +1299,7 @@ print_system_header(struct record_context *ctx) version = strstrip(&osrstr[11], "\"'"); if (distro && version) { - iprintf(ctx, + iprintf(fp, I_SYSTEM, "os: \"%s:%s\"\n", distro, @@ -1482,7 +1315,7 @@ print_system_header(struct record_context *ctx) /* kernel version */ if (uname(&u) != -1) kernel = u.release; - iprintf(ctx, I_SYSTEM, "kernel: \"%s\"\n", kernel); + iprintf(fp, I_SYSTEM, "kernel: \"%s\"\n", kernel); /* dmi modalias */ dmi = fopen("/sys/class/dmi/id/modalias", "r"); @@ -1494,21 +1327,21 @@ print_system_header(struct record_context *ctx) } fclose(dmi); } - iprintf(ctx, I_SYSTEM, "dmi: \"%s\"\n", dmistr); + iprintf(fp, I_SYSTEM, "dmi: \"%s\"\n", dmistr); } static void -print_header(struct record_context *ctx) +print_header(FILE *fp, struct record_context *ctx) { - iprintf(ctx, I_TOPLEVEL, "# libinput record\n"); - iprintf(ctx, I_TOPLEVEL, "version: %d\n", FILE_VERSION_NUMBER); - iprintf(ctx, I_TOPLEVEL, "ndevices: %d\n", ctx->ndevices); - print_libinput_header(ctx); - print_system_header(ctx); + iprintf(fp, I_TOPLEVEL, "# libinput record\n"); + iprintf(fp, I_TOPLEVEL, "version: %d\n", FILE_VERSION_NUMBER); + iprintf(fp, I_TOPLEVEL, "ndevices: %d\n", ctx->ndevices); + print_libinput_header(fp, ctx->timeout); + print_system_header(fp); } static void -print_description_abs(struct record_context *ctx, +print_description_abs(FILE *fp, struct libevdev *dev, unsigned int code) { @@ -1517,26 +1350,26 @@ print_description_abs(struct record_context *ctx, abs = libevdev_get_abs_info(dev, code); assert(abs); - iprintf(ctx, I_EVDEV, "# Value %6d\n", abs->value); - iprintf(ctx, I_EVDEV, "# Min %6d\n", abs->minimum); - iprintf(ctx, I_EVDEV, "# Max %6d\n", abs->maximum); - iprintf(ctx, I_EVDEV, "# Fuzz %6d\n", abs->fuzz); - iprintf(ctx, I_EVDEV, "# Flat %6d\n", abs->flat); - iprintf(ctx, I_EVDEV, "# Resolution %6d\n", abs->resolution); + iprintf(fp, I_EVDEV, "# Value %6d\n", abs->value); + iprintf(fp, I_EVDEV, "# Min %6d\n", abs->minimum); + iprintf(fp, I_EVDEV, "# Max %6d\n", abs->maximum); + iprintf(fp, I_EVDEV, "# Fuzz %6d\n", abs->fuzz); + iprintf(fp, I_EVDEV, "# Flat %6d\n", abs->flat); + iprintf(fp, I_EVDEV, "# Resolution %6d\n", abs->resolution); } static void -print_description_state(struct record_context *ctx, +print_description_state(FILE *fp, struct libevdev *dev, unsigned int type, unsigned int code) { int state = libevdev_get_event_value(dev, type, code); - iprintf(ctx, I_EVDEV, "# State %d\n", state); + iprintf(fp, I_EVDEV, "# State %d\n", state); } static void -print_description_codes(struct record_context *ctx, +print_description_codes(FILE *fp, struct libevdev *dev, unsigned int type) { @@ -1546,7 +1379,7 @@ print_description_codes(struct record_context *ctx, if (max == -1) return; - iprintf(ctx, + iprintf(fp, I_EVDEV, "# Event type %d (%s)\n", type, @@ -1559,7 +1392,7 @@ print_description_codes(struct record_context *ctx, if (!libevdev_has_event_code(dev, type, code)) continue; - iprintf(ctx, + iprintf(fp, I_EVDEV, "# Event code %d (%s)\n", code, @@ -1568,23 +1401,23 @@ print_description_codes(struct record_context *ctx, switch (type) { case EV_ABS: - print_description_abs(ctx, dev, code); + print_description_abs(fp, dev, code); break; case EV_LED: case EV_SW: - print_description_state(ctx, dev, type, code); + print_description_state(fp, dev, type, code); break; } } } static void -print_description(struct record_context *ctx, struct libevdev *dev) +print_description(FILE *fp, struct libevdev *dev) { const struct input_absinfo *x, *y; - iprintf(ctx, I_EVDEV, "# Name: %s\n", libevdev_get_name(dev)); - iprintf(ctx, + iprintf(fp, I_EVDEV, "# Name: %s\n", libevdev_get_name(dev)); + iprintf(fp, I_EVDEV, "# ID: bus %#02x vendor %#02x product %#02x version %#02x\n", libevdev_get_id_bustype(dev), @@ -1600,28 +1433,28 @@ print_description(struct record_context *ctx, struct libevdev *dev) w = (x->maximum - x->minimum)/x->resolution; h = (y->maximum - y->minimum)/y->resolution; - iprintf(ctx, I_EVDEV, "# Size in mm: %dx%d\n", w, h); + iprintf(fp, I_EVDEV, "# Size in mm: %dx%d\n", w, h); } else { - iprintf(ctx, + iprintf(fp, I_EVDEV, "# Size in mm: unknown, missing resolution\n"); } } - iprintf(ctx, I_EVDEV, "# Supported Events:\n"); + iprintf(fp, I_EVDEV, "# Supported Events:\n"); for (unsigned int type = 0; type < EV_CNT; type++) { if (!libevdev_has_event_type(dev, type)) continue; - print_description_codes(ctx, dev, type); + print_description_codes(fp, dev, type); } - iprintf(ctx, I_EVDEV, "# Properties:\n"); + iprintf(fp, I_EVDEV, "# Properties:\n"); for (unsigned int prop = 0; prop < INPUT_PROP_CNT; prop++) { if (libevdev_has_property(dev, prop)) { - iprintf(ctx, + iprintf(fp, I_EVDEV, "# Property %d (%s)\n", prop, @@ -1631,10 +1464,10 @@ print_description(struct record_context *ctx, struct libevdev *dev) } static void -print_bits_info(struct record_context *ctx, struct libevdev *dev) +print_bits_info(FILE *fp, struct libevdev *dev) { - iprintf(ctx, I_EVDEV, "name: \"%s\"\n", libevdev_get_name(dev)); - iprintf(ctx, + iprintf(fp, I_EVDEV, "name: \"%s\"\n", libevdev_get_name(dev)); + iprintf(fp, I_EVDEV, "id: [%d, %d, %d, %d]\n", libevdev_get_id_bustype(dev), @@ -1644,20 +1477,20 @@ print_bits_info(struct record_context *ctx, struct libevdev *dev) } static void -print_bits_absinfo(struct record_context *ctx, struct libevdev *dev) +print_bits_absinfo(FILE *fp, struct libevdev *dev) { const struct input_absinfo *abs; if (!libevdev_has_event_type(dev, EV_ABS)) return; - iprintf(ctx, I_EVDEV, "absinfo:\n"); + iprintf(fp, I_EVDEV, "absinfo:\n"); for (unsigned int code = 0; code < ABS_CNT; code++) { abs = libevdev_get_abs_info(dev, code); if (!abs) continue; - iprintf(ctx, + iprintf(fp, I_EVDEV_DATA, "%d: [%d, %d, %d, %d, %d]\n", code, @@ -1670,9 +1503,7 @@ print_bits_absinfo(struct record_context *ctx, struct libevdev *dev) } static void -print_bits_codes(struct record_context *ctx, - struct libevdev *dev, - unsigned int type) +print_bits_codes(FILE *fp, struct libevdev *dev, unsigned int type) { int max; const char *sep = ""; @@ -1681,62 +1512,61 @@ print_bits_codes(struct record_context *ctx, if (max == -1) return; - iprintf(ctx, I_EVDEV_DATA, "%d: [", type); + iprintf(fp, I_EVDEV_DATA, "%d: [", type); for (unsigned int code = 0; code <= (unsigned int)max; code++) { if (!libevdev_has_event_code(dev, type, code)) continue; - iprintf(ctx, I_NONE, "%s%d", sep, code); + iprintf(fp, I_NONE, "%s%d", sep, code); sep = ", "; } - iprintf(ctx, I_NONE, "] # %s\n", libevdev_event_type_get_name(type)); + iprintf(fp, I_NONE, "] # %s\n", libevdev_event_type_get_name(type)); } static void -print_bits_types(struct record_context *ctx, struct libevdev *dev) +print_bits_types(FILE *fp, struct libevdev *dev) { - iprintf(ctx, I_EVDEV, "codes:\n"); + iprintf(fp, I_EVDEV, "codes:\n"); for (unsigned int type = 0; type < EV_CNT; type++) { if (!libevdev_has_event_type(dev, type)) continue; - print_bits_codes(ctx, dev, type); + print_bits_codes(fp, dev, type); } } static void -print_bits_props(struct record_context *ctx, struct libevdev *dev) +print_bits_props(FILE *fp, struct libevdev *dev) { const char *sep = ""; - iprintf(ctx, I_EVDEV, "properties: ["); + iprintf(fp, I_EVDEV, "properties: ["); for (unsigned int prop = 0; prop < INPUT_PROP_CNT; prop++) { if (libevdev_has_property(dev, prop)) { - iprintf(ctx, I_NONE, "%s%d", sep, prop); + iprintf(fp, I_NONE, "%s%d", sep, prop); sep = ", "; } } - iprintf(ctx, I_NONE, "]\n"); /* last entry, no comma */ + iprintf(fp, I_NONE, "]\n"); /* last entry, no comma */ } static void -print_evdev_description(struct record_context *ctx, struct record_device *dev) +print_evdev_description(struct record_device *dev) { struct libevdev *evdev = dev->evdev; - iprintf(ctx, I_DEVICE, "evdev:\n"); + iprintf(dev->fp, I_DEVICE, "evdev:\n"); - print_description(ctx, evdev); - print_bits_info(ctx, evdev); - print_bits_types(ctx, evdev); - print_bits_absinfo(ctx, evdev); - print_bits_props(ctx, evdev); + print_description(dev->fp, evdev); + print_bits_info(dev->fp, evdev); + print_bits_types(dev->fp, evdev); + print_bits_absinfo(dev->fp, evdev); + print_bits_props(dev->fp, evdev); } static void -print_hid_report_descriptor(struct record_context *ctx, - struct record_device *dev) +print_hid_report_descriptor(struct record_device *dev) { const char *prefix = "/dev/input/event"; char syspath[PATH_MAX]; @@ -1763,22 +1593,22 @@ print_hid_report_descriptor(struct record_context *ctx, if (fd == -1) return; - iprintf(ctx, I_DEVICE, "hid: ["); + iprintf(dev->fp, I_DEVICE, "hid: ["); while ((len = read(fd, buf, sizeof(buf))) > 0) { for (int i = 0; i < len; i++) { /* YAML requires decimal */ - iprintf(ctx, I_NONE, "%s%u", sep, buf[i]); + iprintf(dev->fp, I_NONE, "%s%u", sep, buf[i]); sep = ", "; } } - iprintf(ctx, I_NONE, "]\n"); + iprintf(dev->fp, I_NONE, "]\n"); close(fd); } static void -print_udev_properties(struct record_context *ctx, struct record_device *dev) +print_udev_properties(struct record_device *dev) { struct udev *udev = NULL; struct udev_device *udev_device = NULL; @@ -1796,9 +1626,9 @@ print_udev_properties(struct record_context *ctx, struct record_device *dev) if (!udev_device) goto out; - iprintf(ctx, I_DEVICE, "udev:\n"); + iprintf(dev->fp, I_DEVICE, "udev:\n"); - iprintf(ctx, I_UDEV, "properties:\n"); + iprintf(dev->fp, I_UDEV, "properties:\n"); entry = udev_device_get_properties_list_entry(udev_device); while (entry) { @@ -1812,7 +1642,7 @@ print_udev_properties(struct record_context *ctx, struct record_device *dev) strneq(key, "MOUSE_DPI", 9) || strneq(key, "POINTINGSTICK_", 14)) { value = udev_list_entry_get_value(entry); - iprintf(ctx, I_UDEV_DATA, "- %s=%s\n", key, value); + iprintf(dev->fp, I_UDEV_DATA, "- %s=%s\n", key, value); } entry = udev_list_entry_get_next(entry); @@ -1834,13 +1664,13 @@ quirks_log_handler(struct libinput *this_is_null, static void list_print(void *userdata, const char *val) { - struct record_context *ctx = userdata; + FILE *fp = userdata; - iprintf(ctx, I_QUIRKS, "- %s\n", val); + iprintf(fp, I_QUIRKS, "- %s\n", val); } static void -print_device_quirks(struct record_context *ctx, struct record_device *dev) +print_device_quirks(struct record_device *dev) { struct udev *udev = NULL; struct udev_device *udev_device = NULL; @@ -1882,8 +1712,8 @@ print_device_quirks(struct record_context *ctx, struct record_device *dev) if (!udev_device) goto out; - iprintf(ctx, I_DEVICE, "quirks:\n"); - tools_list_device_quirks(quirks, udev_device, list_print, ctx); + iprintf(dev->fp, I_DEVICE, "quirks:\n"); + tools_list_device_quirks(quirks, udev_device, list_print, dev->fp); out: udev_device_unref(udev_device); udev_unref(udev); @@ -1891,8 +1721,7 @@ out: } static void -print_libinput_description(struct record_context *ctx, - struct record_device *dev) +print_libinput_description(struct record_device *dev) { struct libinput_device *device = dev->device; double w, h; @@ -1914,18 +1743,18 @@ print_libinput_description(struct record_context *ctx, if (!device) return; - iprintf(ctx, I_DEVICE, "libinput:\n"); + iprintf(dev->fp, I_DEVICE, "libinput:\n"); if (libinput_device_get_size(device, &w, &h) == 0) - iprintf(ctx, I_LIBINPUTDEV, "size: [%.f, %.f]\n", w, h); + iprintf(dev->fp, I_LIBINPUTDEV, "size: [%.f, %.f]\n", w, h); - iprintf(ctx, I_LIBINPUTDEV, "capabilities: ["); + iprintf(dev->fp, I_LIBINPUTDEV, "capabilities: ["); ARRAY_FOR_EACH(caps, cap) { if (!libinput_device_has_capability(device, cap->cap)) continue; - iprintf(ctx, I_NONE, "%s%s", sep, cap->name); + iprintf(dev->fp, I_NONE, "%s%s", sep, cap->name); sep = ", "; } - iprintf(ctx, I_NONE, "]\n"); + iprintf(dev->fp, I_NONE, "]\n"); /* Configuration options should be printed here, but since they * don't reflect the user-configured ones their usefulness is @@ -1935,15 +1764,15 @@ print_libinput_description(struct record_context *ctx, } static void -print_device_description(struct record_context *ctx, struct record_device *dev) +print_device_description(struct record_device *dev) { - iprintf(ctx, I_DEVICE, "- node: %s\n", dev->devnode); + iprintf(dev->fp, I_DEVICE, "- node: %s\n", dev->devnode); - print_evdev_description(ctx, dev); - print_hid_report_descriptor(ctx, dev); - print_udev_properties(ctx, dev); - print_device_quirks(ctx, dev); - print_libinput_description(ctx, dev); + print_evdev_description(dev); + print_hid_report_descriptor(dev); + print_udev_properties(dev); + print_device_quirks(dev); + print_libinput_description(dev); } static int is_event_node(const struct dirent *dir) { @@ -2082,9 +1911,10 @@ init_output_file(const char *file, bool is_prefix) } static bool -open_output_file(struct record_context *ctx, bool is_prefix) +open_output_files(struct record_context *ctx, bool is_prefix) { FILE *out_file; + struct record_device *d; if (ctx->output_file.name) { char *fname = init_output_file(ctx->output_file.name, is_prefix); @@ -2097,7 +1927,13 @@ open_output_file(struct record_context *ctx, bool is_prefix) out_file = stdout; } - ctx->output_file.fp = out_file; + ctx->first_device->fp = out_file; + + list_for_each(d, &ctx->devices, link) { + if (d->fp) + continue; + d->fp = tmpfile(); + } return true; } @@ -2120,12 +1956,17 @@ print_wall_time(struct record_context *ctx) { time_t t = time(NULL); struct tm tm; + struct record_device *d; localtime_r(&t, &tm); - iprintf(ctx, - I_NONE, - "# Current time is %02d:%02d:%02d\n", - tm.tm_hour, tm.tm_min, tm.tm_sec); + + list_for_each(d, &ctx->devices, link) { + iprintf(d->fp, + I_DEVICE, + "# Current time is %02d:%02d:%02d\n", + tm.tm_hour, tm.tm_min, tm.tm_sec); + fflush(d->fp); + } } static void @@ -2220,26 +2061,17 @@ evdev_dispatch(struct record_context *ctx, int fd, void *data) ctx->had_events = true; ctx->timestamps.had_events_since_last_time = true; - handle_events(ctx, this_device, this_device == ctx->first_device); + handle_events(ctx, this_device); } static void libinput_ctx_dispatch(struct record_context *ctx, int fd, void *data) { - size_t count, offset; - /* This function should only handle events caused by internal * timeouts etc. The real input events caused by the evdev devices * are already processed in handle_events */ libinput_dispatch(ctx->libinput); - offset = ctx->first_device->nevents; - count = handle_libinput_events(ctx, ctx->first_device); - if (count) { - print_cached_events(ctx, - ctx->first_device, - offset, - count); - } + handle_libinput_events(ctx, ctx->first_device, true); } static int @@ -2313,7 +2145,9 @@ mainloop(struct record_context *ctx) } do { - if (!open_output_file(ctx, autorestart)) { + struct record_device *d; + + if (!open_output_files(ctx, autorestart)) { fprintf(stderr, "Failed to open '%s'\n", ctx->output_file.name_with_suffix); @@ -2325,27 +2159,26 @@ mainloop(struct record_context *ctx) ctx->had_events = false; - print_header(ctx); + print_header(ctx->first_device->fp, ctx); if (autorestart) - iprintf(ctx, + iprintf(ctx->first_device->fp, I_NONE, "# Autorestart timeout: %d\n", ctx->timeout); - iprintf(ctx, I_TOPLEVEL, "devices:\n"); + iprintf(ctx->first_device->fp, I_TOPLEVEL, "devices:\n"); /* we only print the first device's description, the * rest is assembled after CTRL+C */ - print_device_description(ctx, ctx->first_device); - + list_for_each(d, &ctx->devices, link) { + print_device_description(d); + iprintf(d->fp, I_DEVICE, "events:\n"); + } print_wall_time(ctx); - iprintf(ctx, I_DEVICE, "events:\n"); if (ctx->libinput) { - size_t count; libinput_dispatch(ctx->libinput); - count = handle_libinput_events(ctx, ctx->first_device); - print_cached_events(ctx, ctx->first_device, 0, count); + handle_libinput_events(ctx, ctx->first_device, true); } while (true) { @@ -2368,31 +2201,45 @@ mainloop(struct record_context *ctx) } - if (ctx->output_file.fp != stdout) + if (ctx->first_device->fp != stdout) print_progress_bar(); } if (autorestart) { - iprintf(ctx, - I_NONE, - "# Closing after %ds inactivity", - ctx->timeout/1000); + list_for_each(d, &ctx->devices, link) { + iprintf(d->fp, + I_NONE, + "# Closing after %ds inactivity", + ctx->timeout/1000); + } } /* First device is printed, now append all the data from the * other devices, if any */ list_for_each(d, &ctx->devices, link) { - if (d == list_first_entry(&ctx->devices, d, link)) + char buf[4096]; + size_t n; + + if (d == ctx->first_device) continue; - print_device_description(ctx, d); - iprintf(ctx, I_DEVICE, "events:\n"); - print_cached_events(ctx, d, 0, -1); + rewind(d->fp); + do { + + n = fread(buf, 1, sizeof(buf), d->fp); + if (n > 0) + fwrite(buf, 1, n, ctx->first_device->fp); + } while (n == sizeof(buf)); + + fclose(d->fp); + d->fp = NULL; } /* If we didn't have events, delete the file. */ - if (!isatty(fileno(ctx->output_file.fp))) { + if (!isatty(fileno(ctx->first_device->fp))) { + struct record_device *d; + if (!ctx->had_events && ctx->output_file.name_with_suffix) { fprintf(stderr, "No events recorded, deleting '%s'\n", @@ -2400,8 +2247,12 @@ mainloop(struct record_context *ctx) unlink(ctx->output_file.name_with_suffix); } - fclose(ctx->output_file.fp); - ctx->output_file.fp = NULL; + list_for_each(d, &ctx->devices, link) { + if (d->fp && d->fp != stdout) { + fclose(d->fp); + d->fp = NULL; + } + } } free(ctx->output_file.name_with_suffix); ctx->output_file.name_with_suffix = NULL; @@ -2424,10 +2275,8 @@ init_device(struct record_context *ctx, const char *path, bool grab) int fd, rc; d = zalloc(sizeof(*d)); + d->ctx = ctx; d->devnode = safe_strdup(path); - d->nevents = 0; - d->events_sz = 5000; - d->events = zalloc(d->events_sz * sizeof(*d->events)); fd = open(d->devnode, O_RDONLY|O_NONBLOCK); if (fd < 0) { @@ -2794,7 +2643,6 @@ out: list_for_each_safe(d, &ctx.devices, link) { if (d->device) libinput_device_unref(d->device); - free(d->events); free(d->devnode); libevdev_free(d->evdev); }