2017-11-23 11:01:45 +10:00
|
|
|
/*
|
|
|
|
|
* Copyright © 2018 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.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
|
|
#include <errno.h>
|
2018-05-02 10:50:20 +10:00
|
|
|
#include <inttypes.h>
|
2017-11-23 11:01:45 +10:00
|
|
|
#include <linux/input.h>
|
|
|
|
|
#include <libevdev/libevdev.h>
|
2018-03-08 09:31:02 +10:00
|
|
|
#include <libudev.h>
|
2017-11-23 11:01:45 +10:00
|
|
|
#include <sys/signalfd.h>
|
|
|
|
|
#include <sys/utsname.h>
|
2018-03-08 09:31:02 +10:00
|
|
|
#include <sys/stat.h>
|
2017-11-23 11:01:45 +10:00
|
|
|
#include <string.h>
|
|
|
|
|
#include <dirent.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <getopt.h>
|
|
|
|
|
#include <poll.h>
|
2018-03-08 09:31:02 +10:00
|
|
|
#include <unistd.h>
|
2017-11-23 11:01:45 +10:00
|
|
|
#include <signal.h>
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
|
2018-07-10 13:49:26 +03:00
|
|
|
#include "libinput-versionsort.h"
|
2017-11-23 11:01:45 +10:00
|
|
|
#include "libinput-util.h"
|
|
|
|
|
#include "libinput-version.h"
|
2018-02-28 21:29:38 +10:00
|
|
|
#include "libinput-git-version.h"
|
2018-06-22 16:39:01 +10:00
|
|
|
#include "shared.h"
|
2017-11-23 11:01:45 +10:00
|
|
|
|
|
|
|
|
static const int FILE_VERSION_NUMBER = 1;
|
|
|
|
|
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
/* 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 {
|
2018-05-02 10:50:20 +10:00
|
|
|
char msg[256];
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum event_type {
|
|
|
|
|
NONE,
|
|
|
|
|
EVDEV,
|
|
|
|
|
LIBINPUT,
|
2018-03-12 13:36:54 +10:00
|
|
|
COMMENT,
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct event {
|
|
|
|
|
enum event_type type;
|
|
|
|
|
uint64_t time;
|
|
|
|
|
union {
|
|
|
|
|
struct input_event evdev;
|
|
|
|
|
struct li_event libinput;
|
2018-03-12 13:36:54 +10:00
|
|
|
char comment[200];
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
} u;
|
|
|
|
|
};
|
|
|
|
|
|
2017-11-23 11:01:45 +10:00
|
|
|
struct record_device {
|
|
|
|
|
struct list link;
|
|
|
|
|
char *devnode; /* device node of the source device */
|
|
|
|
|
struct libevdev *evdev;
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
struct libinput_device *device;
|
2017-11-23 11:01:45 +10:00
|
|
|
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
struct event *events;
|
2017-11-23 11:01:45 +10:00
|
|
|
size_t nevents;
|
|
|
|
|
size_t events_sz;
|
2018-03-12 13:36:54 +10:00
|
|
|
|
|
|
|
|
struct {
|
|
|
|
|
bool is_touch_device;
|
|
|
|
|
uint16_t slot_state;
|
|
|
|
|
uint16_t last_slot_state;
|
|
|
|
|
} touch;
|
2017-11-23 11:01:45 +10:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct record_context {
|
|
|
|
|
int timeout;
|
|
|
|
|
bool show_keycodes;
|
|
|
|
|
|
|
|
|
|
uint64_t offset;
|
|
|
|
|
|
|
|
|
|
struct list devices;
|
|
|
|
|
int ndevices;
|
|
|
|
|
|
|
|
|
|
char *outfile; /* file name given on cmdline */
|
|
|
|
|
char *output_file; /* full file name with suffix */
|
|
|
|
|
|
|
|
|
|
int out_fd;
|
|
|
|
|
unsigned int indent;
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
|
|
|
|
|
struct libinput *libinput;
|
2017-11-23 11:01:45 +10:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
|
obfuscate_keycode(struct input_event *ev)
|
|
|
|
|
{
|
|
|
|
|
switch (ev->type) {
|
|
|
|
|
case EV_KEY:
|
|
|
|
|
if (ev->code >= KEY_ESC && ev->code < KEY_ZENKAKUHANKAKU) {
|
|
|
|
|
ev->code = KEY_A;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case EV_MSC:
|
|
|
|
|
if (ev->code == MSC_SCAN) {
|
|
|
|
|
ev->value = 30; /* KEY_A scancode */
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
indent_push(struct record_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
ctx->indent += 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
indent_pop(struct record_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
assert(ctx->indent >= 2);
|
|
|
|
|
ctx->indent -= 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Indented dprintf, indentation is given as second parameter.
|
|
|
|
|
*/
|
|
|
|
|
static inline void
|
|
|
|
|
iprintf(const struct record_context *ctx, const char *format, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list args;
|
|
|
|
|
char fmt[1024];
|
|
|
|
|
static const char space[] = " ";
|
|
|
|
|
static const size_t len = sizeof(space);
|
|
|
|
|
unsigned int indent = ctx->indent;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
assert(indent < len);
|
|
|
|
|
assert(strlen(format) > 1);
|
|
|
|
|
|
|
|
|
|
/* Special case: if we're printing a new list item, we want less
|
|
|
|
|
* indentation because the '- ' takes up one level of indentation
|
|
|
|
|
*
|
|
|
|
|
* This is only needed because I don't want to deal with open/close
|
|
|
|
|
* lists statements.
|
|
|
|
|
*/
|
|
|
|
|
if (format[0] == '-')
|
|
|
|
|
indent -= 2;
|
|
|
|
|
|
|
|
|
|
snprintf(fmt, sizeof(fmt), "%s%s", &space[len - indent - 1], format);
|
|
|
|
|
va_start(args, format);
|
|
|
|
|
rc = vdprintf(ctx->out_fd, fmt, args);
|
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
|
|
assert(rc != -1 && (unsigned int)rc > indent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Normal printf, just wrapped for the context
|
|
|
|
|
*/
|
|
|
|
|
static inline void
|
|
|
|
|
noiprintf(const struct record_context *ctx, const char *format, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list args;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
va_start(args, format);
|
|
|
|
|
rc = vdprintf(ctx->out_fd, format, args);
|
|
|
|
|
va_end(args);
|
|
|
|
|
assert(rc != -1 && (unsigned int)rc > 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
print_evdev_event(struct record_context *ctx, struct input_event *ev)
|
|
|
|
|
{
|
|
|
|
|
const char *cname;
|
|
|
|
|
bool was_modified = false;
|
|
|
|
|
char desc[1024];
|
|
|
|
|
|
|
|
|
|
ev->time = us2tv(tv2us(&ev->time) - ctx->offset);
|
|
|
|
|
|
|
|
|
|
/* Don't leak passwords unless the user wants to */
|
|
|
|
|
if (!ctx->show_keycodes)
|
|
|
|
|
was_modified = obfuscate_keycode(ev);
|
|
|
|
|
|
|
|
|
|
cname = libevdev_event_code_get_name(ev->type, ev->code);
|
|
|
|
|
|
|
|
|
|
if (ev->type == EV_SYN && ev->code == SYN_MT_REPORT) {
|
|
|
|
|
snprintf(desc,
|
|
|
|
|
sizeof(desc),
|
|
|
|
|
"++++++++++++ %s (%d) ++++++++++",
|
|
|
|
|
cname,
|
|
|
|
|
ev->value);
|
|
|
|
|
} else if (ev->type == EV_SYN) {
|
|
|
|
|
static unsigned long last_ms = 0;
|
|
|
|
|
unsigned long time, dt;
|
|
|
|
|
|
|
|
|
|
time = us2ms(tv2us(&ev->time));
|
|
|
|
|
if (last_ms == 0)
|
|
|
|
|
last_ms = time;
|
|
|
|
|
dt = time - last_ms;
|
|
|
|
|
last_ms = time;
|
|
|
|
|
|
|
|
|
|
snprintf(desc,
|
|
|
|
|
sizeof(desc),
|
|
|
|
|
"------------ %s (%d) ---------- %+ldms",
|
|
|
|
|
cname,
|
|
|
|
|
ev->value,
|
|
|
|
|
dt);
|
|
|
|
|
} else {
|
|
|
|
|
const char *tname = libevdev_event_type_get_name(ev->type);
|
|
|
|
|
|
|
|
|
|
snprintf(desc,
|
|
|
|
|
sizeof(desc),
|
|
|
|
|
"%s / %-20s %4d%s",
|
|
|
|
|
tname,
|
|
|
|
|
cname,
|
|
|
|
|
ev->value,
|
|
|
|
|
was_modified ? " (obfuscated)" : "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iprintf(ctx,
|
|
|
|
|
"- [%3lu, %6u, %3d, %3d, %5d] # %s\n",
|
|
|
|
|
ev->time.tv_sec,
|
|
|
|
|
(unsigned int)ev->time.tv_usec,
|
|
|
|
|
ev->type,
|
|
|
|
|
ev->code,
|
|
|
|
|
ev->value,
|
|
|
|
|
desc);
|
|
|
|
|
}
|
|
|
|
|
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
#define resize(array_, sz_) \
|
|
|
|
|
{ \
|
|
|
|
|
size_t new_size = (sz_) + 1000; \
|
|
|
|
|
void *tmp = realloc((array_), new_size * sizeof(*(array_))); \
|
|
|
|
|
assert(tmp); \
|
|
|
|
|
(array_) = tmp; \
|
|
|
|
|
(sz_) = new_size; \
|
2017-11-23 11:01:45 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline size_t
|
2018-03-08 10:53:57 +10:00
|
|
|
handle_evdev_frame(struct record_context *ctx, struct record_device *d)
|
2017-11-23 11:01:45 +10:00
|
|
|
{
|
|
|
|
|
struct libevdev *evdev = d->evdev;
|
|
|
|
|
struct input_event e;
|
|
|
|
|
size_t count = 0;
|
2018-03-12 13:36:54 +10:00
|
|
|
uint32_t last_time = 0;
|
|
|
|
|
struct event *event;
|
2017-11-23 11:01:45 +10:00
|
|
|
|
|
|
|
|
while (libevdev_next_event(evdev,
|
|
|
|
|
LIBEVDEV_READ_FLAG_NORMAL,
|
|
|
|
|
&e) == LIBEVDEV_READ_STATUS_SUCCESS) {
|
|
|
|
|
|
2018-05-03 12:18:22 +10:00
|
|
|
if (ctx->offset == 0)
|
|
|
|
|
ctx->offset = tv2us(&e.time);
|
|
|
|
|
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
if (d->nevents == d->events_sz)
|
|
|
|
|
resize(d->events, d->events_sz);
|
2017-11-23 11:01:45 +10:00
|
|
|
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
event = &d->events[d->nevents++];
|
|
|
|
|
event->type = EVDEV;
|
|
|
|
|
event->time = tv2us(&e.time) - ctx->offset;
|
|
|
|
|
event->u.evdev = e;
|
2017-11-23 11:01:45 +10:00
|
|
|
count++;
|
|
|
|
|
|
2018-03-12 13:36:54 +10:00
|
|
|
if (d->touch.is_touch_device &&
|
|
|
|
|
e.type == EV_ABS &&
|
|
|
|
|
e.code == ABS_MT_TRACKING_ID) {
|
|
|
|
|
unsigned int slot = libevdev_get_current_slot(evdev);
|
|
|
|
|
assert(slot < sizeof(d->touch.slot_state) * 8);
|
|
|
|
|
|
|
|
|
|
if (e.value != -1)
|
|
|
|
|
d->touch.slot_state |= 1 << slot;
|
|
|
|
|
else
|
|
|
|
|
d->touch.slot_state &= ~(1 << slot);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
last_time = event->time;
|
|
|
|
|
|
2017-11-23 11:01:45 +10:00
|
|
|
if (e.type == EV_SYN && e.code == SYN_REPORT)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-12 13:36:54 +10:00
|
|
|
if (d->touch.slot_state != d->touch.last_slot_state) {
|
|
|
|
|
d->touch.last_slot_state = d->touch.slot_state;
|
|
|
|
|
if (d->nevents == d->events_sz)
|
|
|
|
|
resize(d->events, d->events_sz);
|
|
|
|
|
|
|
|
|
|
if (d->touch.slot_state == 0) {
|
|
|
|
|
event = &d->events[d->nevents++];
|
|
|
|
|
event->type = COMMENT;
|
|
|
|
|
event->time = last_time;
|
|
|
|
|
snprintf(event->u.comment,
|
|
|
|
|
sizeof(event->u.comment),
|
|
|
|
|
" # Touch device in neutral state\n");
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-23 11:01:45 +10:00
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
static void
|
|
|
|
|
buffer_device_notify(struct record_context *ctx,
|
|
|
|
|
struct libinput_event *e,
|
|
|
|
|
struct event *event)
|
|
|
|
|
{
|
|
|
|
|
struct libinput_device *dev = libinput_event_get_device(e);
|
|
|
|
|
struct libinput_seat *seat = libinput_device_get_seat(dev);
|
|
|
|
|
const char *type = NULL;
|
|
|
|
|
|
|
|
|
|
switch(libinput_event_get_type(e)) {
|
|
|
|
|
case LIBINPUT_EVENT_DEVICE_ADDED:
|
|
|
|
|
type = "DEVICE_ADDED";
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_DEVICE_REMOVED:
|
|
|
|
|
type = "DEVICE_REMOVED";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
buffer_key_event(struct record_context *ctx,
|
|
|
|
|
struct libinput_event *e,
|
|
|
|
|
struct event *event)
|
|
|
|
|
{
|
|
|
|
|
struct libinput_event_keyboard *k = libinput_event_get_keyboard_event(e);
|
|
|
|
|
enum libinput_key_state state;
|
|
|
|
|
uint32_t key;
|
|
|
|
|
uint64_t time;
|
|
|
|
|
const char *type;
|
|
|
|
|
|
|
|
|
|
switch(libinput_event_get_type(e)) {
|
|
|
|
|
case LIBINPUT_EVENT_KEYBOARD_KEY:
|
|
|
|
|
type = "KEYBOARD_KEY";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
time = ctx->offset ?
|
|
|
|
|
libinput_event_keyboard_get_time_usec(k) - ctx->offset : 0;
|
|
|
|
|
|
|
|
|
|
state = libinput_event_keyboard_get_key_state(k);
|
|
|
|
|
|
|
|
|
|
key = libinput_event_keyboard_get_key(k);
|
|
|
|
|
if (!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}",
|
|
|
|
|
time / (int)1e6,
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
struct libinput_event_pointer *p = libinput_event_get_pointer_event(e);
|
|
|
|
|
double x = libinput_event_pointer_get_dx(p),
|
|
|
|
|
y = libinput_event_pointer_get_dy(p);
|
|
|
|
|
double uax = libinput_event_pointer_get_dx_unaccelerated(p),
|
|
|
|
|
uay = libinput_event_pointer_get_dy_unaccelerated(p);
|
|
|
|
|
uint64_t time;
|
|
|
|
|
const char *type;
|
|
|
|
|
|
|
|
|
|
switch(libinput_event_get_type(e)) {
|
|
|
|
|
case LIBINPUT_EVENT_POINTER_MOTION:
|
|
|
|
|
type = "POINTER_MOTION";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
time = ctx->offset ?
|
|
|
|
|
libinput_event_pointer_get_time_usec(p) - ctx->offset : 0;
|
|
|
|
|
|
|
|
|
|
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]}",
|
|
|
|
|
time / (int)1e6,
|
|
|
|
|
time % (int)1e6,
|
|
|
|
|
type,
|
|
|
|
|
x, y,
|
|
|
|
|
uax, uay);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
buffer_absmotion_event(struct record_context *ctx,
|
|
|
|
|
struct libinput_event *e,
|
|
|
|
|
struct event *event)
|
|
|
|
|
{
|
|
|
|
|
struct libinput_event_pointer *p = libinput_event_get_pointer_event(e);
|
|
|
|
|
double x = libinput_event_pointer_get_absolute_x(p),
|
|
|
|
|
y = libinput_event_pointer_get_absolute_y(p);
|
|
|
|
|
double tx = libinput_event_pointer_get_absolute_x_transformed(p, 100),
|
|
|
|
|
ty = libinput_event_pointer_get_absolute_y_transformed(p, 100);
|
|
|
|
|
uint64_t time;
|
|
|
|
|
const char *type;
|
|
|
|
|
|
|
|
|
|
switch(libinput_event_get_type(e)) {
|
|
|
|
|
case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
|
|
|
|
|
type = "POINTER_MOTION_ABSOLUTE";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
time = ctx->offset ?
|
|
|
|
|
libinput_event_pointer_get_time_usec(p) - ctx->offset : 0;
|
|
|
|
|
|
|
|
|
|
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]}",
|
|
|
|
|
time / (int)1e6,
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
struct libinput_event_pointer *p = libinput_event_get_pointer_event(e);
|
|
|
|
|
enum libinput_button_state state;
|
|
|
|
|
int button;
|
|
|
|
|
uint64_t time;
|
|
|
|
|
const char *type;
|
|
|
|
|
|
|
|
|
|
switch(libinput_event_get_type(e)) {
|
|
|
|
|
case LIBINPUT_EVENT_POINTER_BUTTON:
|
|
|
|
|
type = "POINTER_BUTTON";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
time = ctx->offset ?
|
|
|
|
|
libinput_event_pointer_get_time_usec(p) - ctx->offset : 0;
|
|
|
|
|
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}",
|
|
|
|
|
time / (int)1e6,
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
struct libinput_event_pointer *p = libinput_event_get_pointer_event(e);
|
|
|
|
|
uint64_t time;
|
|
|
|
|
const char *type, *source;
|
|
|
|
|
double h = 0, v = 0;
|
|
|
|
|
int hd = 0, vd = 0;
|
|
|
|
|
|
|
|
|
|
switch(libinput_event_get_type(e)) {
|
|
|
|
|
case LIBINPUT_EVENT_POINTER_AXIS:
|
|
|
|
|
type = "POINTER_AXIS";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
time = ctx->offset ?
|
|
|
|
|
libinput_event_pointer_get_time_usec(p) - ctx->offset : 0;
|
|
|
|
|
if (libinput_event_pointer_has_axis(p,
|
|
|
|
|
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) {
|
|
|
|
|
h = libinput_event_pointer_get_axis_value(p,
|
|
|
|
|
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
|
|
|
|
|
hd = libinput_event_pointer_get_axis_value_discrete(p,
|
|
|
|
|
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
|
|
|
|
|
}
|
|
|
|
|
if (libinput_event_pointer_has_axis(p,
|
|
|
|
|
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) {
|
|
|
|
|
v = libinput_event_pointer_get_axis_value(p,
|
|
|
|
|
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
|
|
|
|
|
vd = libinput_event_pointer_get_axis_value_discrete(p,
|
|
|
|
|
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
|
|
|
|
|
}
|
|
|
|
|
switch(libinput_event_pointer_get_axis_source(p)) {
|
|
|
|
|
case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL: source = "wheel"; break;
|
|
|
|
|
case LIBINPUT_POINTER_AXIS_SOURCE_FINGER: source = "finger"; break;
|
|
|
|
|
case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS: source = "continuous"; break;
|
|
|
|
|
case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL_TILT: source = "wheel-tilt"; break;
|
|
|
|
|
default:
|
|
|
|
|
source = "unknown";
|
|
|
|
|
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}",
|
|
|
|
|
time / (int)1e6,
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
enum libinput_event_type etype = libinput_event_get_type(e);
|
|
|
|
|
struct libinput_event_touch *t = libinput_event_get_touch_event(e);
|
|
|
|
|
const char *type;
|
|
|
|
|
double x, y;
|
|
|
|
|
double tx, ty;
|
|
|
|
|
uint64_t time;
|
|
|
|
|
int32_t slot, seat_slot;
|
|
|
|
|
|
|
|
|
|
switch(etype) {
|
|
|
|
|
case LIBINPUT_EVENT_TOUCH_DOWN:
|
|
|
|
|
type = "TOUCH_DOWN";
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_TOUCH_UP:
|
|
|
|
|
type = "TOUCH_UP";
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_TOUCH_MOTION:
|
|
|
|
|
type = "TOUCH_MOTION";
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_TOUCH_CANCEL:
|
|
|
|
|
type = "TOUCH_CANCEL";
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_TOUCH_FRAME:
|
|
|
|
|
type = "TOUCH_FRAME";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
time = ctx->offset ?
|
|
|
|
|
libinput_event_touch_get_time_usec(t) - ctx->offset : 0;
|
|
|
|
|
|
|
|
|
|
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}",
|
|
|
|
|
time / (int)1e6,
|
|
|
|
|
time % (int)1e6,
|
|
|
|
|
type);
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_TOUCH_DOWN:
|
|
|
|
|
case LIBINPUT_EVENT_TOUCH_MOTION:
|
|
|
|
|
x = libinput_event_touch_get_x(t);
|
|
|
|
|
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]}",
|
|
|
|
|
time / (int)1e6,
|
|
|
|
|
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}",
|
|
|
|
|
time / (int)1e6,
|
|
|
|
|
time % (int)1e6,
|
|
|
|
|
type,
|
|
|
|
|
slot,
|
|
|
|
|
seat_slot);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-19 13:48:25 +10:00
|
|
|
static void
|
|
|
|
|
buffer_gesture_event(struct record_context *ctx,
|
|
|
|
|
struct libinput_event *e,
|
|
|
|
|
struct event *event)
|
|
|
|
|
{
|
|
|
|
|
enum libinput_event_type etype = libinput_event_get_type(e);
|
|
|
|
|
struct libinput_event_gesture *g = libinput_event_get_gesture_event(e);
|
|
|
|
|
const char *type;
|
|
|
|
|
uint64_t time;
|
|
|
|
|
|
|
|
|
|
switch(etype) {
|
|
|
|
|
case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN:
|
|
|
|
|
type = "GESTURE_PINCH_BEGIN";
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE:
|
|
|
|
|
type = "GESTURE_PINCH_UPDATE";
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_GESTURE_PINCH_END:
|
|
|
|
|
type = "GESTURE_PINCH_END";
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN:
|
|
|
|
|
type = "GESTURE_SWIPE_BEGIN";
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
|
|
|
|
|
type = "GESTURE_SWIPE_UPDATE";
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_GESTURE_SWIPE_END:
|
|
|
|
|
type = "GESTURE_SWIPE_END";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
time = ctx->offset ?
|
|
|
|
|
libinput_event_gesture_get_time_usec(g) - ctx->offset : 0;
|
|
|
|
|
event->time = time;
|
|
|
|
|
|
|
|
|
|
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}",
|
|
|
|
|
time / (int)1e6,
|
|
|
|
|
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]}",
|
|
|
|
|
time / (int)1e6,
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-02 10:50:20 +10:00
|
|
|
static char *
|
|
|
|
|
buffer_tablet_axes(struct libinput_event_tablet_tool *t)
|
|
|
|
|
{
|
2018-06-11 11:20:09 +10:00
|
|
|
const int MAX_AXES = 10;
|
2018-05-02 10:50:20 +10:00
|
|
|
struct libinput_tablet_tool *tool;
|
|
|
|
|
char *s = NULL;
|
|
|
|
|
int idx = 0;
|
|
|
|
|
int len;
|
|
|
|
|
double x, y;
|
|
|
|
|
char **strv;
|
|
|
|
|
|
|
|
|
|
tool = libinput_event_tablet_tool_get_tool(t);
|
|
|
|
|
|
2018-06-11 11:20:09 +10:00
|
|
|
strv = zalloc(MAX_AXES * sizeof *strv);
|
2018-05-02 10:50:20 +10:00
|
|
|
|
|
|
|
|
x = libinput_event_tablet_tool_get_x(t);
|
|
|
|
|
y = libinput_event_tablet_tool_get_y(t);
|
|
|
|
|
len = xasprintf(&strv[idx++], "point: [%.2f, %.2f]", x, y);
|
|
|
|
|
if (len <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
if (libinput_tablet_tool_has_tilt(tool)) {
|
|
|
|
|
x = libinput_event_tablet_tool_get_tilt_x(t);
|
|
|
|
|
y = libinput_event_tablet_tool_get_tilt_y(t);
|
|
|
|
|
len = xasprintf(&strv[idx++], "tilt: [%.2f, %.2f]", x, y);
|
|
|
|
|
if (len <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (libinput_tablet_tool_has_distance(tool) ||
|
|
|
|
|
libinput_tablet_tool_has_pressure(tool)) {
|
|
|
|
|
double dist, pressure;
|
|
|
|
|
|
|
|
|
|
dist = libinput_event_tablet_tool_get_distance(t);
|
|
|
|
|
pressure = libinput_event_tablet_tool_get_pressure(t);
|
|
|
|
|
if (dist)
|
|
|
|
|
len = xasprintf(&strv[idx++], "distance: %.2f", dist);
|
|
|
|
|
else
|
|
|
|
|
len = xasprintf(&strv[idx++], "pressure: %.2f", pressure);
|
|
|
|
|
if (len <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (libinput_tablet_tool_has_rotation(tool)) {
|
|
|
|
|
double rotation;
|
|
|
|
|
|
|
|
|
|
rotation = libinput_event_tablet_tool_get_rotation(t);
|
|
|
|
|
len = xasprintf(&strv[idx++], "rotation: %.2f", rotation);
|
|
|
|
|
if (len <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (libinput_tablet_tool_has_slider(tool)) {
|
|
|
|
|
double slider;
|
|
|
|
|
|
|
|
|
|
slider = libinput_event_tablet_tool_get_slider_position(t);
|
|
|
|
|
len = xasprintf(&strv[idx++], "slider: %.2f", slider);
|
|
|
|
|
if (len <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (libinput_tablet_tool_has_wheel(tool)) {
|
|
|
|
|
double wheel;
|
|
|
|
|
int delta;
|
|
|
|
|
|
|
|
|
|
wheel = libinput_event_tablet_tool_get_wheel_delta(t);
|
|
|
|
|
len = xasprintf(&strv[idx++], "wheel: %.2f", wheel);
|
|
|
|
|
if (len <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
delta = libinput_event_tablet_tool_get_wheel_delta_discrete(t);
|
|
|
|
|
len = xasprintf(&strv[idx++], "wheel-discrete: %d", delta);
|
|
|
|
|
if (len <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-11 11:20:09 +10:00
|
|
|
assert(idx < MAX_AXES);
|
|
|
|
|
|
2018-05-02 10:50:20 +10:00
|
|
|
s = strv_join(strv, ", ");
|
|
|
|
|
out:
|
|
|
|
|
strv_free(strv);
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
buffer_tablet_tool_proximity_event(struct record_context *ctx,
|
|
|
|
|
struct libinput_event *e,
|
|
|
|
|
struct event *event)
|
|
|
|
|
{
|
|
|
|
|
struct libinput_event_tablet_tool *t =
|
|
|
|
|
libinput_event_get_tablet_tool_event(e);
|
|
|
|
|
struct libinput_tablet_tool *tool =
|
|
|
|
|
libinput_event_tablet_tool_get_tool(t);
|
|
|
|
|
uint64_t time;
|
|
|
|
|
const char *type, *tool_type;
|
|
|
|
|
char *axes;
|
|
|
|
|
char caps[10] = {0};
|
|
|
|
|
enum libinput_tablet_tool_proximity_state prox;
|
|
|
|
|
size_t idx;
|
|
|
|
|
|
|
|
|
|
switch (libinput_event_get_type(e)) {
|
|
|
|
|
case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
|
|
|
|
|
type = "TABLET_TOOL_PROXIMITY";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (libinput_tablet_tool_get_type(tool)) {
|
|
|
|
|
case LIBINPUT_TABLET_TOOL_TYPE_PEN:
|
|
|
|
|
tool_type = "pen";
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_TABLET_TOOL_TYPE_ERASER:
|
|
|
|
|
tool_type = "eraser";
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_TABLET_TOOL_TYPE_BRUSH:
|
|
|
|
|
tool_type = "brush";
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_TABLET_TOOL_TYPE_PENCIL:
|
|
|
|
|
tool_type = "brush";
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH:
|
|
|
|
|
tool_type = "airbrush";
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_TABLET_TOOL_TYPE_MOUSE:
|
|
|
|
|
tool_type = "mouse";
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_TABLET_TOOL_TYPE_LENS:
|
|
|
|
|
tool_type = "lens";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
tool_type = "unknown";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
prox = libinput_event_tablet_tool_get_proximity_state(t);
|
|
|
|
|
|
|
|
|
|
time = ctx->offset ?
|
|
|
|
|
libinput_event_tablet_tool_get_time_usec(t) - ctx->offset : 0;
|
|
|
|
|
|
|
|
|
|
axes = buffer_tablet_axes(t);
|
|
|
|
|
|
|
|
|
|
idx = 0;
|
|
|
|
|
if (libinput_tablet_tool_has_pressure(tool))
|
|
|
|
|
caps[idx++] = 'p';
|
|
|
|
|
if (libinput_tablet_tool_has_distance(tool))
|
|
|
|
|
caps[idx++] = 'd';
|
|
|
|
|
if (libinput_tablet_tool_has_tilt(tool))
|
|
|
|
|
caps[idx++] = 't';
|
|
|
|
|
if (libinput_tablet_tool_has_rotation(tool))
|
|
|
|
|
caps[idx++] = 'r';
|
|
|
|
|
if (libinput_tablet_tool_has_slider(tool))
|
|
|
|
|
caps[idx++] = 's';
|
|
|
|
|
if (libinput_tablet_tool_has_wheel(tool))
|
|
|
|
|
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}",
|
|
|
|
|
time / (int)1e6,
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
struct libinput_event_tablet_tool *t =
|
|
|
|
|
libinput_event_get_tablet_tool_event(e);
|
|
|
|
|
uint64_t time;
|
|
|
|
|
const char *type;
|
|
|
|
|
uint32_t button;
|
|
|
|
|
enum libinput_button_state state;
|
|
|
|
|
|
|
|
|
|
switch(libinput_event_get_type(e)) {
|
|
|
|
|
case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
|
|
|
|
|
type = "TABLET_TOOL_BUTTON";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
button = libinput_event_tablet_tool_get_button(t);
|
|
|
|
|
state = libinput_event_tablet_tool_get_button_state(t);
|
|
|
|
|
|
|
|
|
|
time = ctx->offset ?
|
|
|
|
|
libinput_event_tablet_tool_get_time_usec(t) - ctx->offset : 0;
|
|
|
|
|
|
|
|
|
|
event->time = time;
|
|
|
|
|
snprintf(event->u.libinput.msg,
|
|
|
|
|
sizeof(event->u.libinput.msg),
|
|
|
|
|
"{time: %ld.%06ld, type: %s, button: %d, state: %s}",
|
|
|
|
|
time / (int)1e6,
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
struct libinput_event_tablet_tool *t =
|
|
|
|
|
libinput_event_get_tablet_tool_event(e);
|
|
|
|
|
uint64_t time;
|
|
|
|
|
const char *type;
|
|
|
|
|
char *axes;
|
|
|
|
|
enum libinput_tablet_tool_tip_state tip;
|
|
|
|
|
char btn_buffer[30] = {0};
|
|
|
|
|
|
|
|
|
|
switch(libinput_event_get_type(e)) {
|
|
|
|
|
case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
|
|
|
|
|
type = "TABLET_TOOL_AXIS";
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_TABLET_TOOL_TIP:
|
|
|
|
|
type = "TABLET_TOOL_TIP";
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
|
|
|
|
|
type = "TABLET_TOOL_BUTTON";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (libinput_event_get_type(e) == LIBINPUT_EVENT_TABLET_TOOL_BUTTON) {
|
|
|
|
|
uint32_t button;
|
|
|
|
|
enum libinput_button_state state;
|
|
|
|
|
|
|
|
|
|
button = libinput_event_tablet_tool_get_button(t);
|
|
|
|
|
state = libinput_event_tablet_tool_get_button_state(t);
|
|
|
|
|
snprintf(btn_buffer, sizeof(btn_buffer),
|
|
|
|
|
", button: %d, state: %s\n",
|
|
|
|
|
button,
|
|
|
|
|
state ? "pressed" : "released");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tip = libinput_event_tablet_tool_get_tip_state(t);
|
|
|
|
|
|
|
|
|
|
time = ctx->offset ?
|
|
|
|
|
libinput_event_tablet_tool_get_time_usec(t) - ctx->offset : 0;
|
|
|
|
|
|
|
|
|
|
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}",
|
|
|
|
|
time / (int)1e6,
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
struct libinput_event_tablet_pad *p =
|
|
|
|
|
libinput_event_get_tablet_pad_event(e);
|
|
|
|
|
struct libinput_tablet_pad_mode_group *group;
|
|
|
|
|
enum libinput_button_state state;
|
|
|
|
|
unsigned int button, mode;
|
|
|
|
|
const char *type;
|
|
|
|
|
uint64_t time;
|
|
|
|
|
|
|
|
|
|
switch(libinput_event_get_type(e)) {
|
|
|
|
|
case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
|
|
|
|
|
type = "TABLET_PAD_BUTTON";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
time = ctx->offset ?
|
|
|
|
|
libinput_event_tablet_pad_get_time_usec(p) - ctx->offset : 0;
|
|
|
|
|
|
|
|
|
|
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}",
|
|
|
|
|
time / (int)1e6,
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
struct libinput_event_tablet_pad *p =
|
|
|
|
|
libinput_event_get_tablet_pad_event(e);
|
|
|
|
|
const char *source = NULL;
|
|
|
|
|
unsigned int mode, number;
|
|
|
|
|
const char *type;
|
|
|
|
|
uint64_t time;
|
|
|
|
|
double pos;
|
|
|
|
|
|
|
|
|
|
switch(libinput_event_get_type(e)) {
|
|
|
|
|
case LIBINPUT_EVENT_TABLET_PAD_RING:
|
|
|
|
|
type = "TABLET_PAD_RING";
|
|
|
|
|
number = libinput_event_tablet_pad_get_ring_number(p);
|
|
|
|
|
pos = libinput_event_tablet_pad_get_ring_position(p);
|
|
|
|
|
|
|
|
|
|
switch (libinput_event_tablet_pad_get_ring_source(p)) {
|
|
|
|
|
case LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER:
|
|
|
|
|
source = "finger";
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_TABLET_PAD_RING_SOURCE_UNKNOWN:
|
|
|
|
|
source = "unknown";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_TABLET_PAD_STRIP:
|
|
|
|
|
type = "TABLET_PAD_STRIP";
|
|
|
|
|
number = libinput_event_tablet_pad_get_strip_number(p);
|
|
|
|
|
pos = libinput_event_tablet_pad_get_strip_position(p);
|
|
|
|
|
|
|
|
|
|
switch (libinput_event_tablet_pad_get_strip_source(p)) {
|
|
|
|
|
case LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER:
|
|
|
|
|
source = "finger";
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_TABLET_PAD_STRIP_SOURCE_UNKNOWN:
|
|
|
|
|
source = "unknown";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
time = ctx->offset ?
|
|
|
|
|
libinput_event_tablet_pad_get_time_usec(p) - ctx->offset : 0;
|
|
|
|
|
|
|
|
|
|
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}",
|
|
|
|
|
time / (int)1e6,
|
|
|
|
|
time % (int)1e6,
|
|
|
|
|
type,
|
|
|
|
|
number,
|
|
|
|
|
pos,
|
|
|
|
|
source,
|
|
|
|
|
mode);
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-03 13:51:00 +10:00
|
|
|
static void
|
|
|
|
|
buffer_switch_event(struct record_context *ctx,
|
|
|
|
|
struct libinput_event *e,
|
|
|
|
|
struct event *event)
|
|
|
|
|
{
|
|
|
|
|
struct libinput_event_switch *s = libinput_event_get_switch_event(e);
|
|
|
|
|
enum libinput_switch_state state;
|
|
|
|
|
uint32_t sw;
|
|
|
|
|
const char *type;
|
|
|
|
|
uint64_t time;
|
|
|
|
|
|
|
|
|
|
switch(libinput_event_get_type(e)) {
|
|
|
|
|
case LIBINPUT_EVENT_SWITCH_TOGGLE:
|
|
|
|
|
type = "SWITCH_TOGGLE";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
time = ctx->offset ?
|
|
|
|
|
libinput_event_switch_get_time_usec(s) - ctx->offset : 0;
|
|
|
|
|
|
|
|
|
|
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}",
|
|
|
|
|
time / (int)1e6,
|
|
|
|
|
time % (int)1e6,
|
|
|
|
|
type,
|
|
|
|
|
sw,
|
|
|
|
|
state == LIBINPUT_SWITCH_STATE_ON ? "on" : "off");
|
|
|
|
|
}
|
|
|
|
|
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
static void
|
|
|
|
|
buffer_libinput_event(struct record_context *ctx,
|
|
|
|
|
struct libinput_event *e,
|
|
|
|
|
struct event *event)
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_KEYBOARD_KEY:
|
|
|
|
|
buffer_key_event(ctx, e, event);
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_POINTER_MOTION:
|
|
|
|
|
buffer_motion_event(ctx, e, event);
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
|
|
|
|
|
buffer_absmotion_event(ctx, e, event);
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_POINTER_BUTTON:
|
|
|
|
|
buffer_pointer_button_event(ctx, e, event);
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_POINTER_AXIS:
|
|
|
|
|
buffer_pointer_axis_event(ctx, e, event);
|
|
|
|
|
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);
|
|
|
|
|
break;
|
2018-04-19 13:48:25 +10:00
|
|
|
case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN:
|
|
|
|
|
case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE:
|
|
|
|
|
case LIBINPUT_EVENT_GESTURE_PINCH_END:
|
|
|
|
|
case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN:
|
|
|
|
|
case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
|
|
|
|
|
case LIBINPUT_EVENT_GESTURE_SWIPE_END:
|
|
|
|
|
buffer_gesture_event(ctx, e, event);
|
|
|
|
|
break;
|
2018-05-02 10:50:20 +10:00
|
|
|
case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
|
|
|
|
|
buffer_tablet_tool_proximity_event(ctx, e, event);
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
|
|
|
|
|
case LIBINPUT_EVENT_TABLET_TOOL_TIP:
|
|
|
|
|
buffer_tablet_tool_event(ctx, e, event);
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
|
|
|
|
|
buffer_tablet_tool_button_event(ctx, e, event);
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
|
|
|
|
|
buffer_tablet_pad_button_event(ctx, e, event);
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT_EVENT_TABLET_PAD_RING:
|
|
|
|
|
case LIBINPUT_EVENT_TABLET_PAD_STRIP:
|
|
|
|
|
buffer_tablet_pad_ringstrip_event(ctx, e, event);
|
|
|
|
|
break;
|
2018-05-03 13:51:00 +10:00
|
|
|
case LIBINPUT_EVENT_SWITCH_TOGGLE:
|
|
|
|
|
buffer_switch_event(ctx, e, event);
|
|
|
|
|
break;
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
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;
|
|
|
|
|
indent_push(ctx);
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
indent_pop(ctx);
|
|
|
|
|
|
|
|
|
|
switch(e->type) {
|
|
|
|
|
case EVDEV:
|
|
|
|
|
if (new_frame)
|
|
|
|
|
iprintf(ctx, "- evdev:\n");
|
|
|
|
|
else
|
|
|
|
|
iprintf(ctx, "evdev:\n");
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT:
|
|
|
|
|
if (new_frame)
|
|
|
|
|
iprintf(ctx, "- libinput:\n");
|
|
|
|
|
else
|
|
|
|
|
iprintf(ctx, "libinput:\n");
|
|
|
|
|
break;
|
2018-03-12 13:36:54 +10:00
|
|
|
case COMMENT:
|
|
|
|
|
break;
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
default:
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
indent_push(ctx);
|
|
|
|
|
|
|
|
|
|
last_type = e->type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (e->type) {
|
|
|
|
|
case EVDEV:
|
|
|
|
|
print_evdev_event(ctx, &e->u.evdev);
|
|
|
|
|
break;
|
|
|
|
|
case LIBINPUT:
|
|
|
|
|
iprintf(ctx, "- %s\n", e->u.libinput.msg);
|
|
|
|
|
break;
|
2018-03-12 13:36:54 +10:00
|
|
|
case COMMENT:
|
|
|
|
|
iprintf(ctx, "%s", e->u.comment);
|
|
|
|
|
break;
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
default:
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
last_time = e->time;
|
|
|
|
|
}
|
|
|
|
|
indent_pop(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline size_t
|
|
|
|
|
handle_libinput_events(struct record_context *ctx,
|
|
|
|
|
struct record_device *d)
|
|
|
|
|
{
|
|
|
|
|
struct libinput_event *e;
|
|
|
|
|
size_t count = 0;
|
|
|
|
|
struct record_device *current = d;
|
|
|
|
|
|
|
|
|
|
libinput_dispatch(ctx->libinput);
|
|
|
|
|
|
|
|
|
|
while ((e = libinput_get_event(ctx->libinput)) != NULL) {
|
|
|
|
|
struct libinput_device *device = libinput_event_get_device(e);
|
|
|
|
|
struct event *event;
|
|
|
|
|
|
|
|
|
|
if (device != current->device) {
|
|
|
|
|
struct record_device *tmp;
|
|
|
|
|
bool found = false;
|
|
|
|
|
list_for_each(tmp, &ctx->devices, link) {
|
|
|
|
|
if (device == tmp->device) {
|
|
|
|
|
current = tmp;
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
assert(found);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (current->nevents == current->events_sz)
|
|
|
|
|
resize(current->events, current->events_sz);
|
|
|
|
|
|
|
|
|
|
event = ¤t->events[current->nevents++];
|
|
|
|
|
event->type = LIBINPUT;
|
|
|
|
|
buffer_libinput_event(ctx, e, event);
|
|
|
|
|
|
|
|
|
|
if (current == d)
|
|
|
|
|
count++;
|
|
|
|
|
libinput_event_destroy(e);
|
|
|
|
|
}
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-23 11:01:45 +10:00
|
|
|
static inline void
|
|
|
|
|
handle_events(struct record_context *ctx, struct record_device *d, bool print)
|
|
|
|
|
{
|
|
|
|
|
while(true) {
|
|
|
|
|
size_t first_idx = d->nevents;
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
size_t evcount = 0,
|
|
|
|
|
licount = 0;
|
2017-11-23 11:01:45 +10:00
|
|
|
|
2018-03-08 10:53:57 +10:00
|
|
|
evcount = handle_evdev_frame(ctx, d);
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
|
|
|
|
|
if (ctx->libinput)
|
|
|
|
|
licount = handle_libinput_events(ctx, d);
|
|
|
|
|
|
|
|
|
|
if (evcount == 0 && licount == 0)
|
2017-11-23 11:01:45 +10:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (!print)
|
|
|
|
|
continue;
|
|
|
|
|
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
print_cached_events(ctx, d, first_idx, evcount + licount);
|
2017-11-23 11:01:45 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
print_libinput_header(struct record_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
iprintf(ctx, "libinput:\n");
|
|
|
|
|
indent_push(ctx);
|
|
|
|
|
iprintf(ctx, "version: \"%s\"\n", LIBINPUT_VERSION);
|
2018-02-28 21:29:38 +10:00
|
|
|
iprintf(ctx, "git: \"%s\"\n", LIBINPUT_GIT_VERSION);
|
2017-11-23 11:01:45 +10:00
|
|
|
if (ctx->timeout > 0)
|
|
|
|
|
iprintf(ctx, "autorestart: %d\n", ctx->timeout);
|
|
|
|
|
indent_pop(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
print_system_header(struct record_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
struct utsname u;
|
|
|
|
|
const char *kernel = "unknown";
|
|
|
|
|
FILE *dmi;
|
|
|
|
|
char modalias[2048] = "unknown";
|
|
|
|
|
|
|
|
|
|
if (uname(&u) != -1)
|
|
|
|
|
kernel = u.release;
|
|
|
|
|
|
|
|
|
|
dmi = fopen("/sys/class/dmi/id/modalias", "r");
|
|
|
|
|
if (dmi) {
|
|
|
|
|
if (fgets(modalias, sizeof(modalias), dmi)) {
|
|
|
|
|
modalias[strlen(modalias) - 1] = '\0'; /* linebreak */
|
|
|
|
|
} else {
|
|
|
|
|
sprintf(modalias, "unknown");
|
|
|
|
|
}
|
|
|
|
|
fclose(dmi);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iprintf(ctx, "system:\n");
|
|
|
|
|
indent_push(ctx);
|
|
|
|
|
iprintf(ctx, "kernel: \"%s\"\n", kernel);
|
|
|
|
|
iprintf(ctx, "dmi: \"%s\"\n", modalias);
|
|
|
|
|
indent_pop(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
print_header(struct record_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
iprintf(ctx, "version: %d\n", FILE_VERSION_NUMBER);
|
|
|
|
|
iprintf(ctx, "ndevices: %d\n", ctx->ndevices);
|
|
|
|
|
print_libinput_header(ctx);
|
|
|
|
|
print_system_header(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
print_description_abs(struct record_context *ctx,
|
|
|
|
|
struct libevdev *dev,
|
|
|
|
|
unsigned int code)
|
|
|
|
|
{
|
|
|
|
|
const struct input_absinfo *abs;
|
|
|
|
|
|
|
|
|
|
abs = libevdev_get_abs_info(dev, code);
|
|
|
|
|
assert(abs);
|
|
|
|
|
|
|
|
|
|
iprintf(ctx, "# Value %6d\n", abs->value);
|
|
|
|
|
iprintf(ctx, "# Min %6d\n", abs->minimum);
|
|
|
|
|
iprintf(ctx, "# Max %6d\n", abs->maximum);
|
|
|
|
|
iprintf(ctx, "# Fuzz %6d\n", abs->fuzz);
|
|
|
|
|
iprintf(ctx, "# Flat %6d\n", abs->flat);
|
|
|
|
|
iprintf(ctx, "# Resolution %6d\n", abs->resolution);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
print_description_state(struct record_context *ctx,
|
|
|
|
|
struct libevdev *dev,
|
|
|
|
|
unsigned int type,
|
|
|
|
|
unsigned int code)
|
|
|
|
|
{
|
|
|
|
|
int state = libevdev_get_event_value(dev, type, code);
|
|
|
|
|
iprintf(ctx, "# State %d\n", state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
print_description_codes(struct record_context *ctx,
|
|
|
|
|
struct libevdev *dev,
|
|
|
|
|
unsigned int type)
|
|
|
|
|
{
|
|
|
|
|
int max;
|
|
|
|
|
|
|
|
|
|
max = libevdev_event_type_get_max(type);
|
|
|
|
|
if (max == -1)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
iprintf(ctx,
|
|
|
|
|
"# Event type %d (%s)\n",
|
|
|
|
|
type,
|
|
|
|
|
libevdev_event_type_get_name(type));
|
|
|
|
|
|
|
|
|
|
if (type == EV_SYN)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
for (unsigned int code = 0; code <= (unsigned int)max; code++) {
|
|
|
|
|
if (!libevdev_has_event_code(dev, type, code))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
iprintf(ctx,
|
|
|
|
|
"# Event code %d (%s)\n",
|
|
|
|
|
code,
|
|
|
|
|
libevdev_event_code_get_name(type,
|
|
|
|
|
code));
|
|
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
|
case EV_ABS:
|
|
|
|
|
print_description_abs(ctx, dev, code);
|
|
|
|
|
break;
|
|
|
|
|
case EV_LED:
|
|
|
|
|
case EV_SW:
|
|
|
|
|
print_description_state(ctx, dev, type, code);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
print_description(struct record_context *ctx, struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
const struct input_absinfo *x, *y;
|
|
|
|
|
|
|
|
|
|
iprintf(ctx, "# Name: %s\n", libevdev_get_name(dev));
|
|
|
|
|
iprintf(ctx,
|
|
|
|
|
"# ID: bus %#02x vendor %#02x product %#02x version %#02x\n",
|
|
|
|
|
libevdev_get_id_bustype(dev),
|
|
|
|
|
libevdev_get_id_vendor(dev),
|
|
|
|
|
libevdev_get_id_product(dev),
|
|
|
|
|
libevdev_get_id_version(dev));
|
|
|
|
|
|
|
|
|
|
x = libevdev_get_abs_info(dev, ABS_X);
|
|
|
|
|
y = libevdev_get_abs_info(dev, ABS_Y);
|
|
|
|
|
if (x && y) {
|
2018-03-01 12:48:37 +10:00
|
|
|
if (x->resolution && y->resolution) {
|
2017-11-23 11:01:45 +10:00
|
|
|
int w, h;
|
|
|
|
|
|
|
|
|
|
w = (x->maximum - x->minimum)/x->resolution;
|
|
|
|
|
h = (y->maximum - y->minimum)/y->resolution;
|
|
|
|
|
iprintf(ctx, "# Size in mm: %dx%d\n", w, h);
|
|
|
|
|
} else {
|
|
|
|
|
iprintf(ctx,
|
|
|
|
|
"# Size in mm: unknown, missing resolution\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iprintf(ctx, "# 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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iprintf(ctx, "# Properties:\n");
|
|
|
|
|
|
|
|
|
|
for (unsigned int prop = 0; prop < INPUT_PROP_CNT; prop++) {
|
|
|
|
|
if (libevdev_has_property(dev, prop)) {
|
|
|
|
|
iprintf(ctx,
|
|
|
|
|
"# Property %d (%s)\n",
|
|
|
|
|
prop,
|
|
|
|
|
libevdev_property_get_name(prop));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
print_bits_info(struct record_context *ctx, struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
iprintf(ctx, "name: \"%s\"\n", libevdev_get_name(dev));
|
|
|
|
|
iprintf(ctx,
|
|
|
|
|
"id: [%d, %d, %d, %d]\n",
|
|
|
|
|
libevdev_get_id_bustype(dev),
|
|
|
|
|
libevdev_get_id_vendor(dev),
|
|
|
|
|
libevdev_get_id_product(dev),
|
|
|
|
|
libevdev_get_id_version(dev));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
print_bits_absinfo(struct record_context *ctx, struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
const struct input_absinfo *abs;
|
|
|
|
|
|
|
|
|
|
if (!libevdev_has_event_type(dev, EV_ABS))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
iprintf(ctx, "absinfo:\n");
|
|
|
|
|
indent_push(ctx);
|
|
|
|
|
|
|
|
|
|
for (unsigned int code = 0; code < ABS_CNT; code++) {
|
|
|
|
|
abs = libevdev_get_abs_info(dev, code);
|
|
|
|
|
if (!abs)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
iprintf(ctx,
|
|
|
|
|
"%d: [%d, %d, %d, %d, %d]\n",
|
|
|
|
|
code,
|
|
|
|
|
abs->minimum,
|
|
|
|
|
abs->maximum,
|
|
|
|
|
abs->fuzz,
|
|
|
|
|
abs->flat,
|
|
|
|
|
abs->resolution);
|
|
|
|
|
}
|
|
|
|
|
indent_pop(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
print_bits_codes(struct record_context *ctx,
|
|
|
|
|
struct libevdev *dev,
|
|
|
|
|
unsigned int type)
|
|
|
|
|
{
|
|
|
|
|
int max;
|
|
|
|
|
bool first = true;
|
|
|
|
|
|
|
|
|
|
max = libevdev_event_type_get_max(type);
|
|
|
|
|
if (max == -1)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
iprintf(ctx, "%d: [", type);
|
|
|
|
|
|
|
|
|
|
for (unsigned int code = 0; code <= (unsigned int)max; code++) {
|
|
|
|
|
if (!libevdev_has_event_code(dev, type, code))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
noiprintf(ctx, "%s%d", first ? "" : ", ", code);
|
|
|
|
|
first = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
noiprintf(ctx, "] # %s\n", libevdev_event_type_get_name(type));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
print_bits_types(struct record_context *ctx, struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
iprintf(ctx, "codes:\n");
|
|
|
|
|
indent_push(ctx);
|
|
|
|
|
for (unsigned int type = 0; type < EV_CNT; type++) {
|
|
|
|
|
if (!libevdev_has_event_type(dev, type))
|
|
|
|
|
continue;
|
|
|
|
|
print_bits_codes(ctx, dev, type);
|
|
|
|
|
}
|
|
|
|
|
indent_pop(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
print_bits_props(struct record_context *ctx, struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
bool first = true;
|
|
|
|
|
|
|
|
|
|
iprintf(ctx, "properties: [");
|
|
|
|
|
for (unsigned int prop = 0; prop < INPUT_PROP_CNT; prop++) {
|
|
|
|
|
if (libevdev_has_property(dev, prop)) {
|
|
|
|
|
noiprintf(ctx, "%s%d", first ? "" : ", ", prop);
|
|
|
|
|
first = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
noiprintf(ctx, "]\n"); /* last entry, no comma */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
print_evdev_description(struct record_context *ctx, struct record_device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct libevdev *evdev = dev->evdev;
|
|
|
|
|
|
|
|
|
|
iprintf(ctx, "evdev:\n");
|
|
|
|
|
indent_push(ctx);
|
|
|
|
|
|
|
|
|
|
print_description(ctx, evdev);
|
|
|
|
|
print_bits_info(ctx, evdev);
|
|
|
|
|
print_bits_types(ctx, evdev);
|
|
|
|
|
print_bits_absinfo(ctx, evdev);
|
|
|
|
|
print_bits_props(ctx, evdev);
|
|
|
|
|
|
|
|
|
|
indent_pop(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-08 09:31:02 +10:00
|
|
|
static inline void
|
|
|
|
|
print_udev_properties(struct record_context *ctx, struct record_device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct udev *udev = NULL;
|
|
|
|
|
struct udev_device *udev_device = NULL;
|
|
|
|
|
struct udev_list_entry *entry;
|
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
|
|
if (stat(dev->devnode, &st) < 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
udev = udev_new();
|
|
|
|
|
if (!udev)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
udev_device = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
|
|
|
|
|
if (!udev_device)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
iprintf(ctx, "udev:\n");
|
|
|
|
|
indent_push(ctx);
|
|
|
|
|
|
|
|
|
|
iprintf(ctx, "properties:\n");
|
|
|
|
|
indent_push(ctx);
|
|
|
|
|
|
|
|
|
|
entry = udev_device_get_properties_list_entry(udev_device);
|
|
|
|
|
while (entry) {
|
|
|
|
|
const char *key, *value;
|
|
|
|
|
|
|
|
|
|
key = udev_list_entry_get_name(entry);
|
|
|
|
|
|
|
|
|
|
if (strneq(key, "ID_INPUT", 8) ||
|
|
|
|
|
strneq(key, "LIBINPUT", 8) ||
|
2018-03-20 13:51:06 +10:00
|
|
|
strneq(key, "EV_ABS", 6) ||
|
|
|
|
|
strneq(key, "MOUSE_DPI", 9) ||
|
|
|
|
|
strneq(key, "POINTINGSTICK_", 14)) {
|
2018-03-08 09:31:02 +10:00
|
|
|
value = udev_list_entry_get_value(entry);
|
|
|
|
|
iprintf(ctx, "- %s=%s\n", key, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
entry = udev_list_entry_get_next(entry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
indent_pop(ctx);
|
|
|
|
|
indent_pop(ctx);
|
|
|
|
|
out:
|
|
|
|
|
udev_device_unref(udev_device);
|
|
|
|
|
udev_unref(udev);
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-22 16:39:01 +10:00
|
|
|
static void
|
|
|
|
|
quirks_log_handler(struct libinput *this_is_null,
|
|
|
|
|
enum libinput_log_priority priority,
|
|
|
|
|
const char *format,
|
|
|
|
|
va_list args)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
list_print(void *userdata, const char *val)
|
|
|
|
|
{
|
|
|
|
|
struct record_context *ctx = userdata;
|
|
|
|
|
|
|
|
|
|
iprintf(ctx, "- %s\n", val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
print_device_quirks(struct record_context *ctx, struct record_device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct udev *udev = NULL;
|
|
|
|
|
struct udev_device *udev_device = NULL;
|
|
|
|
|
struct stat st;
|
|
|
|
|
struct quirks_context *quirks;
|
2018-07-13 12:57:02 +10:00
|
|
|
const char *data_path = LIBINPUT_QUIRKS_DIR;
|
|
|
|
|
const char *override_file = LIBINPUT_QUIRKS_OVERRIDE_FILE;
|
2018-06-22 16:39:01 +10:00
|
|
|
|
|
|
|
|
if (stat(dev->devnode, &st) < 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
quirks = quirks_init_subsystem(data_path,
|
|
|
|
|
override_file,
|
|
|
|
|
quirks_log_handler,
|
|
|
|
|
NULL,
|
|
|
|
|
QLOG_CUSTOM_LOG_PRIORITIES);
|
|
|
|
|
if (!quirks) {
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"Failed to initialize the device quirks. "
|
|
|
|
|
"Please see the above errors "
|
|
|
|
|
"and/or re-run with --verbose for more details\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
udev = udev_new();
|
|
|
|
|
if (!udev)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
udev_device = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
|
|
|
|
|
if (!udev_device)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
iprintf(ctx, "quirks:\n");
|
|
|
|
|
indent_push(ctx);
|
|
|
|
|
|
|
|
|
|
tools_list_device_quirks(quirks, udev_device, list_print, ctx);
|
|
|
|
|
|
|
|
|
|
indent_pop(ctx);
|
|
|
|
|
out:
|
|
|
|
|
udev_device_unref(udev_device);
|
|
|
|
|
udev_unref(udev);
|
|
|
|
|
}
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
static inline void
|
|
|
|
|
print_libinput_description(struct record_context *ctx,
|
|
|
|
|
struct record_device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct libinput_device *device = dev->device;
|
|
|
|
|
double w, h;
|
|
|
|
|
struct cap {
|
|
|
|
|
enum libinput_device_capability cap;
|
|
|
|
|
const char *name;
|
|
|
|
|
} caps[] = {
|
|
|
|
|
{LIBINPUT_DEVICE_CAP_KEYBOARD, "keyboard"},
|
|
|
|
|
{LIBINPUT_DEVICE_CAP_POINTER, "pointer"},
|
|
|
|
|
{LIBINPUT_DEVICE_CAP_TOUCH, "touch"},
|
|
|
|
|
{LIBINPUT_DEVICE_CAP_TABLET_TOOL, "tablet"},
|
|
|
|
|
{LIBINPUT_DEVICE_CAP_TABLET_PAD, "pad"},
|
|
|
|
|
{LIBINPUT_DEVICE_CAP_GESTURE, "gesture"},
|
|
|
|
|
{LIBINPUT_DEVICE_CAP_SWITCH, "switch"},
|
|
|
|
|
};
|
|
|
|
|
struct cap *cap;
|
|
|
|
|
bool is_first;
|
|
|
|
|
|
|
|
|
|
if (!device)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
iprintf(ctx, "libinput:\n");
|
|
|
|
|
indent_push(ctx);
|
|
|
|
|
|
|
|
|
|
if (libinput_device_get_size(device, &w, &h) == 0)
|
|
|
|
|
iprintf(ctx, "size: [%.f, %.f]\n", w, h);
|
|
|
|
|
|
|
|
|
|
iprintf(ctx, "capabilities: [");
|
|
|
|
|
is_first = true;
|
|
|
|
|
ARRAY_FOR_EACH(caps, cap) {
|
|
|
|
|
if (!libinput_device_has_capability(device, cap->cap))
|
|
|
|
|
continue;
|
|
|
|
|
noiprintf(ctx, "%s%s", is_first ? "" : ", ", cap->name);
|
|
|
|
|
is_first = false;
|
|
|
|
|
}
|
|
|
|
|
noiprintf(ctx, "]\n");
|
|
|
|
|
|
|
|
|
|
/* Configuration options should be printed here, but since they
|
|
|
|
|
* don't reflect the user-configured ones their usefulness is
|
|
|
|
|
* questionable. We need the ability to specify the options like in
|
|
|
|
|
* debug-events.
|
|
|
|
|
*/
|
|
|
|
|
indent_pop(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-23 11:01:45 +10:00
|
|
|
static inline void
|
|
|
|
|
print_device_description(struct record_context *ctx, struct record_device *dev)
|
|
|
|
|
{
|
|
|
|
|
iprintf(ctx, "- node: %s\n", dev->devnode);
|
|
|
|
|
|
|
|
|
|
print_evdev_description(ctx, dev);
|
2018-03-08 09:31:02 +10:00
|
|
|
print_udev_properties(ctx, dev);
|
2018-06-22 16:39:01 +10:00
|
|
|
print_device_quirks(ctx, dev);
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
print_libinput_description(ctx, dev);
|
2017-11-23 11:01:45 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int is_event_node(const struct dirent *dir) {
|
|
|
|
|
return strneq(dir->d_name, "event", 5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline char *
|
|
|
|
|
select_device(void)
|
|
|
|
|
{
|
|
|
|
|
struct dirent **namelist;
|
|
|
|
|
int ndev, selected_device;
|
|
|
|
|
int rc;
|
|
|
|
|
char *device_path;
|
|
|
|
|
|
|
|
|
|
ndev = scandir("/dev/input", &namelist, is_event_node, versionsort);
|
|
|
|
|
if (ndev <= 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
fprintf(stderr, "Available devices:\n");
|
|
|
|
|
for (int i = 0; i < ndev; i++) {
|
|
|
|
|
struct libevdev *device;
|
|
|
|
|
char path[PATH_MAX];
|
|
|
|
|
int fd = -1;
|
|
|
|
|
|
|
|
|
|
snprintf(path,
|
|
|
|
|
sizeof(path),
|
|
|
|
|
"/dev/input/%s",
|
|
|
|
|
namelist[i]->d_name);
|
|
|
|
|
fd = open(path, O_RDONLY);
|
|
|
|
|
if (fd < 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
rc = libevdev_new_from_fd(fd, &device);
|
|
|
|
|
close(fd);
|
|
|
|
|
if (rc != 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
fprintf(stderr, "%s: %s\n", path, libevdev_get_name(device));
|
|
|
|
|
libevdev_free(device);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < ndev; i++)
|
|
|
|
|
free(namelist[i]);
|
|
|
|
|
free(namelist);
|
|
|
|
|
|
|
|
|
|
fprintf(stderr, "Select the device event number: ");
|
|
|
|
|
rc = scanf("%d", &selected_device);
|
|
|
|
|
|
|
|
|
|
if (rc != 1 || selected_device < 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
rc = xasprintf(&device_path, "/dev/input/event%d", selected_device);
|
|
|
|
|
if (rc == -1)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return device_path;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-27 14:25:43 +10:00
|
|
|
static inline char **
|
|
|
|
|
all_devices(void)
|
|
|
|
|
{
|
|
|
|
|
struct dirent **namelist;
|
|
|
|
|
int ndev;
|
|
|
|
|
int rc;
|
|
|
|
|
char **devices = NULL;
|
|
|
|
|
|
|
|
|
|
ndev = scandir("/dev/input", &namelist, is_event_node, versionsort);
|
|
|
|
|
if (ndev <= 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
devices = zalloc((ndev + 1)* sizeof *devices); /* NULL-terminated */
|
|
|
|
|
for (int i = 0; i < ndev; i++) {
|
|
|
|
|
char *device_path;
|
|
|
|
|
|
|
|
|
|
rc = xasprintf(&device_path,
|
|
|
|
|
"/dev/input/%s",
|
|
|
|
|
namelist[i]->d_name);
|
|
|
|
|
if (rc == -1)
|
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
devices[i] = device_path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return devices;
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
if (devices)
|
|
|
|
|
strv_free(devices);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-23 11:01:45 +10:00
|
|
|
static char *
|
|
|
|
|
init_output_file(const char *file, bool is_prefix)
|
|
|
|
|
{
|
|
|
|
|
char name[PATH_MAX];
|
|
|
|
|
|
|
|
|
|
assert(file != NULL);
|
|
|
|
|
|
|
|
|
|
if (is_prefix) {
|
|
|
|
|
struct tm *tm;
|
|
|
|
|
time_t t;
|
|
|
|
|
char suffix[64];
|
|
|
|
|
|
|
|
|
|
t = time(NULL);
|
|
|
|
|
tm = localtime(&t);
|
|
|
|
|
strftime(suffix, sizeof(suffix), "%F-%T", tm);
|
|
|
|
|
snprintf(name,
|
|
|
|
|
sizeof(name),
|
|
|
|
|
"%s.%s",
|
|
|
|
|
file,
|
|
|
|
|
suffix);
|
|
|
|
|
} else {
|
|
|
|
|
snprintf(name, sizeof(name), "%s", file);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return strdup(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
open_output_file(struct record_context *ctx, bool is_prefix)
|
|
|
|
|
{
|
|
|
|
|
int out_fd;
|
|
|
|
|
|
|
|
|
|
if (ctx->outfile) {
|
|
|
|
|
char *fname = init_output_file(ctx->outfile, is_prefix);
|
|
|
|
|
ctx->output_file = fname;
|
|
|
|
|
out_fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
|
|
|
|
|
if (out_fd < 0)
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
ctx->output_file = safe_strdup("stdout");
|
|
|
|
|
out_fd = STDOUT_FILENO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx->out_fd = out_fd;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-15 08:44:19 +10:00
|
|
|
static inline void
|
|
|
|
|
print_progress_bar(void)
|
|
|
|
|
{
|
|
|
|
|
static uint8_t foo = 0;
|
|
|
|
|
|
|
|
|
|
if (!isatty(STDERR_FILENO))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (++foo > 20)
|
|
|
|
|
foo = 1;
|
|
|
|
|
fprintf(stderr, "\rReceiving events: [%*s%*s]", foo, "*", 21 - foo, " ");
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-23 11:01:45 +10:00
|
|
|
static int
|
|
|
|
|
mainloop(struct record_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
bool autorestart = (ctx->timeout > 0);
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
struct pollfd fds[ctx->ndevices + 2];
|
|
|
|
|
unsigned int nfds = 0;
|
2017-11-23 11:01:45 +10:00
|
|
|
struct record_device *d = NULL;
|
2018-03-08 11:01:10 +10:00
|
|
|
struct record_device *first_device = NULL;
|
2017-11-23 11:01:45 +10:00
|
|
|
struct timespec ts;
|
|
|
|
|
sigset_t mask;
|
|
|
|
|
|
|
|
|
|
assert(ctx->timeout != 0);
|
|
|
|
|
assert(!list_empty(&ctx->devices));
|
|
|
|
|
|
|
|
|
|
sigemptyset(&mask);
|
|
|
|
|
sigaddset(&mask, SIGINT);
|
|
|
|
|
sigaddset(&mask, SIGQUIT);
|
|
|
|
|
sigprocmask(SIG_BLOCK, &mask, NULL);
|
|
|
|
|
|
|
|
|
|
fds[0].fd = signalfd(-1, &mask, SFD_NONBLOCK);
|
|
|
|
|
fds[0].events = POLLIN;
|
|
|
|
|
fds[0].revents = 0;
|
|
|
|
|
assert(fds[0].fd != -1);
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
nfds++;
|
|
|
|
|
|
|
|
|
|
if (ctx->libinput) {
|
|
|
|
|
fds[1].fd = libinput_get_fd(ctx->libinput);
|
|
|
|
|
fds[1].events = POLLIN;
|
|
|
|
|
fds[1].revents = 0;
|
|
|
|
|
nfds++;
|
|
|
|
|
assert(nfds == 2);
|
|
|
|
|
}
|
2017-11-23 11:01:45 +10:00
|
|
|
|
|
|
|
|
list_for_each(d, &ctx->devices, link) {
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
fds[nfds].fd = libevdev_get_fd(d->evdev);
|
|
|
|
|
fds[nfds].events = POLLIN;
|
|
|
|
|
fds[nfds].revents = 0;
|
|
|
|
|
assert(fds[nfds].fd != -1);
|
|
|
|
|
nfds++;
|
2017-11-23 11:01:45 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If we have more than one device, the time starts at recording
|
|
|
|
|
* start time. Otherwise, the first event starts the recording time.
|
|
|
|
|
*/
|
|
|
|
|
if (ctx->ndevices > 1) {
|
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
|
|
|
ctx->offset = s2us(ts.tv_sec) + ns2us(ts.tv_nsec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
int rc;
|
|
|
|
|
bool had_events = false; /* we delete files without events */
|
|
|
|
|
|
|
|
|
|
if (!open_output_file(ctx, autorestart)) {
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"Failed to open '%s'\n",
|
|
|
|
|
ctx->output_file);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2018-03-15 08:44:19 +10:00
|
|
|
fprintf(stderr, "Recording to '%s'.\n", ctx->output_file);
|
2017-11-23 11:01:45 +10:00
|
|
|
|
|
|
|
|
print_header(ctx);
|
|
|
|
|
if (autorestart)
|
|
|
|
|
iprintf(ctx,
|
|
|
|
|
"# Autorestart timeout: %d\n",
|
|
|
|
|
ctx->timeout);
|
|
|
|
|
|
|
|
|
|
iprintf(ctx, "devices:\n");
|
|
|
|
|
indent_push(ctx);
|
|
|
|
|
|
|
|
|
|
/* we only print the first device's description, the
|
|
|
|
|
* rest is assembled after CTRL+C */
|
2018-03-08 11:01:10 +10:00
|
|
|
first_device = list_first_entry(&ctx->devices,
|
|
|
|
|
first_device,
|
|
|
|
|
link);
|
|
|
|
|
print_device_description(ctx, first_device);
|
2017-11-23 11:01:45 +10:00
|
|
|
|
|
|
|
|
iprintf(ctx, "events:\n");
|
|
|
|
|
indent_push(ctx);
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
|
|
|
|
|
if (ctx->libinput) {
|
|
|
|
|
size_t count;
|
|
|
|
|
libinput_dispatch(ctx->libinput);
|
|
|
|
|
count = handle_libinput_events(ctx, first_device);
|
|
|
|
|
print_cached_events(ctx, first_device, 0, count);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-23 11:01:45 +10:00
|
|
|
while (true) {
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
rc = poll(fds, nfds, ctx->timeout);
|
2017-11-23 11:01:45 +10:00
|
|
|
if (rc == -1) { /* error */
|
|
|
|
|
fprintf(stderr, "Error: %m\n");
|
|
|
|
|
autorestart = false;
|
|
|
|
|
break;
|
|
|
|
|
} else if (rc == 0) {
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
" ... timeout%s\n",
|
|
|
|
|
had_events ? "" : " (file is empty)");
|
|
|
|
|
break;
|
|
|
|
|
} else if (fds[0].revents != 0) { /* signal */
|
|
|
|
|
autorestart = false;
|
|
|
|
|
break;
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Pull off the evdev events first since they cause
|
|
|
|
|
* libinput events.
|
|
|
|
|
* handle_events de-queues libinput events so by the
|
|
|
|
|
* time we finish that, we hopefully have all evdev
|
|
|
|
|
* events and libinput events roughly in sync.
|
|
|
|
|
*/
|
|
|
|
|
had_events = true;
|
|
|
|
|
list_for_each(d, &ctx->devices, link)
|
|
|
|
|
handle_events(ctx, d, d == first_device);
|
|
|
|
|
|
|
|
|
|
/* This shouldn't pull any events off unless caused
|
|
|
|
|
* by libinput-internal timeouts (e.g. tapping) */
|
|
|
|
|
if (ctx->libinput && fds[1].revents) {
|
|
|
|
|
size_t count, offset;
|
|
|
|
|
|
|
|
|
|
libinput_dispatch(ctx->libinput);
|
|
|
|
|
offset = first_device->nevents;
|
|
|
|
|
count = handle_libinput_events(ctx,
|
|
|
|
|
first_device);
|
|
|
|
|
if (count) {
|
|
|
|
|
print_cached_events(ctx,
|
|
|
|
|
first_device,
|
|
|
|
|
offset,
|
|
|
|
|
count);
|
2017-11-23 11:01:45 +10:00
|
|
|
}
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
rc--;
|
2017-11-23 11:01:45 +10:00
|
|
|
}
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
|
2018-03-15 08:44:19 +10:00
|
|
|
if (ctx->out_fd != STDOUT_FILENO)
|
|
|
|
|
print_progress_bar();
|
|
|
|
|
|
2017-11-23 11:01:45 +10:00
|
|
|
}
|
|
|
|
|
indent_pop(ctx); /* events: */
|
|
|
|
|
|
|
|
|
|
if (autorestart) {
|
|
|
|
|
noiprintf(ctx,
|
|
|
|
|
"# 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))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
print_device_description(ctx, d);
|
|
|
|
|
iprintf(ctx, "events:\n");
|
|
|
|
|
indent_push(ctx);
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
print_cached_events(ctx, d, 0, -1);
|
2017-11-23 11:01:45 +10:00
|
|
|
indent_pop(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
indent_pop(ctx); /* devices: */
|
|
|
|
|
assert(ctx->indent == 0);
|
|
|
|
|
|
|
|
|
|
fsync(ctx->out_fd);
|
|
|
|
|
|
|
|
|
|
/* If we didn't have events, delete the file. */
|
|
|
|
|
if (!isatty(ctx->out_fd)) {
|
|
|
|
|
if (!had_events && ctx->output_file) {
|
|
|
|
|
fprintf(stderr, "No events recorded, deleting '%s'\n", ctx->output_file);
|
|
|
|
|
unlink(ctx->output_file);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
close(ctx->out_fd);
|
|
|
|
|
ctx->out_fd = -1;
|
|
|
|
|
}
|
|
|
|
|
free(ctx->output_file);
|
|
|
|
|
ctx->output_file = NULL;
|
|
|
|
|
} while (autorestart);
|
|
|
|
|
|
|
|
|
|
close(fds[0].fd);
|
|
|
|
|
|
|
|
|
|
sigprocmask(SIG_UNBLOCK, &mask, NULL);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
|
init_device(struct record_context *ctx, char *path)
|
|
|
|
|
{
|
|
|
|
|
struct record_device *d;
|
|
|
|
|
int fd, rc;
|
|
|
|
|
|
|
|
|
|
d = zalloc(sizeof(*d));
|
|
|
|
|
d->devnode = 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) {
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"Failed to open device %s (%m)\n",
|
|
|
|
|
d->devnode);
|
2018-05-11 15:04:22 +10:00
|
|
|
goto error;
|
2017-11-23 11:01:45 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = libevdev_new_from_fd(fd, &d->evdev);
|
|
|
|
|
if (rc != 0) {
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"Failed to create context for %s (%s)\n",
|
|
|
|
|
d->devnode,
|
|
|
|
|
strerror(-rc));
|
2018-05-11 15:04:22 +10:00
|
|
|
goto error;
|
2017-11-23 11:01:45 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
libevdev_set_clock_id(d->evdev, CLOCK_MONOTONIC);
|
|
|
|
|
|
2018-03-12 13:36:54 +10:00
|
|
|
if (libevdev_get_num_slots(d->evdev) > 0)
|
|
|
|
|
d->touch.is_touch_device = true;
|
|
|
|
|
|
2017-11-23 11:01:45 +10:00
|
|
|
list_insert(&ctx->devices, &d->link);
|
|
|
|
|
ctx->ndevices++;
|
|
|
|
|
|
|
|
|
|
return true;
|
2018-05-11 15:04:22 +10:00
|
|
|
error:
|
|
|
|
|
close(fd);
|
|
|
|
|
free(d);
|
|
|
|
|
return false;
|
|
|
|
|
|
2017-11-23 11:01:45 +10:00
|
|
|
}
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
static int
|
|
|
|
|
open_restricted(const char *path, int flags, void *user_data)
|
|
|
|
|
{
|
|
|
|
|
int fd = open(path, flags);
|
|
|
|
|
return fd == -1 ? -errno : fd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void close_restricted(int fd, void *user_data)
|
|
|
|
|
{
|
|
|
|
|
close(fd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const struct libinput_interface interface = {
|
|
|
|
|
.open_restricted = open_restricted,
|
|
|
|
|
.close_restricted = close_restricted,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
|
init_libinput(struct record_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
struct record_device *dev;
|
|
|
|
|
struct libinput *li;
|
|
|
|
|
|
|
|
|
|
li = libinput_path_create_context(&interface, NULL);
|
|
|
|
|
if (li == NULL) {
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"Failed to create libinput context\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx->libinput = li;
|
|
|
|
|
|
|
|
|
|
list_for_each(dev, &ctx->devices, link) {
|
|
|
|
|
struct libinput_device *d;
|
|
|
|
|
|
|
|
|
|
d = libinput_path_add_device(li, dev->devnode);
|
|
|
|
|
if (!d) {
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"Failed to add device %s\n",
|
|
|
|
|
dev->devnode);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
dev->device = libinput_device_ref(d);
|
|
|
|
|
/* FIXME: this needs to be a commandline option */
|
|
|
|
|
libinput_device_config_tap_set_enabled(d,
|
|
|
|
|
LIBINPUT_CONFIG_TAP_ENABLED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2017-11-23 11:01:45 +10:00
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
usage(void)
|
|
|
|
|
{
|
2018-02-27 14:25:43 +10:00
|
|
|
printf("Usage: %s [--help] [--multiple|--all] [--autorestart] [--output-file filename] [/dev/input/event0] [...]\n"
|
2017-11-23 11:01:45 +10:00
|
|
|
"Common use-cases:\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" sudo %s -o recording.yml\n"
|
|
|
|
|
" Then select the device to record and it Ctrl+C to stop.\n"
|
|
|
|
|
" The recorded data is in recording.yml and can be attached to a bug report.\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" sudo %s -o recording.yml --autorestart 2\n"
|
|
|
|
|
" As above, but restarts after 2s of inactivity on the device.\n"
|
|
|
|
|
" Note, the output file is only the prefix.\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" sudo %s --multiple -o recording.yml /dev/input/event3 /dev/input/event4\n"
|
|
|
|
|
" Records the two devices into the same recordings file.\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"For more information, see the %s(1) man page\n",
|
|
|
|
|
program_invocation_short_name,
|
|
|
|
|
program_invocation_short_name,
|
|
|
|
|
program_invocation_short_name,
|
|
|
|
|
program_invocation_short_name,
|
|
|
|
|
program_invocation_short_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum options {
|
|
|
|
|
OPT_AUTORESTART,
|
|
|
|
|
OPT_HELP,
|
|
|
|
|
OPT_OUTFILE,
|
|
|
|
|
OPT_KEYCODES,
|
|
|
|
|
OPT_MULTIPLE,
|
2018-02-27 14:25:43 +10:00
|
|
|
OPT_ALL,
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
OPT_LIBINPUT,
|
2017-11-23 11:01:45 +10:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
main(int argc, char **argv)
|
|
|
|
|
{
|
|
|
|
|
struct record_context ctx = {
|
|
|
|
|
.timeout = -1,
|
|
|
|
|
.show_keycodes = false,
|
|
|
|
|
};
|
|
|
|
|
struct option opts[] = {
|
|
|
|
|
{ "autorestart", required_argument, 0, OPT_AUTORESTART },
|
|
|
|
|
{ "output-file", required_argument, 0, OPT_OUTFILE },
|
|
|
|
|
{ "show-keycodes", no_argument, 0, OPT_KEYCODES },
|
|
|
|
|
{ "multiple", no_argument, 0, OPT_MULTIPLE },
|
2018-02-27 14:25:43 +10:00
|
|
|
{ "all", no_argument, 0, OPT_ALL },
|
2017-11-23 11:01:45 +10:00
|
|
|
{ "help", no_argument, 0, OPT_HELP },
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
{ "with-libinput", no_argument, 0, OPT_LIBINPUT },
|
2017-11-23 11:01:45 +10:00
|
|
|
{ 0, 0, 0, 0 },
|
|
|
|
|
};
|
|
|
|
|
struct record_device *d, *tmp;
|
|
|
|
|
const char *output_arg = NULL;
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
bool multiple = false, all = false, with_libinput = false;
|
2017-11-23 11:01:45 +10:00
|
|
|
int ndevices;
|
|
|
|
|
int rc = 1;
|
|
|
|
|
|
|
|
|
|
list_init(&ctx.devices);
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
int c;
|
|
|
|
|
int option_index = 0;
|
|
|
|
|
|
|
|
|
|
c = getopt_long(argc, argv, "ho:", opts, &option_index);
|
|
|
|
|
if (c == -1)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
|
case 'h':
|
|
|
|
|
case OPT_HELP:
|
|
|
|
|
usage();
|
|
|
|
|
rc = 0;
|
|
|
|
|
goto out;
|
|
|
|
|
case OPT_AUTORESTART:
|
|
|
|
|
if (!safe_atoi(optarg, &ctx.timeout) ||
|
|
|
|
|
ctx.timeout <= 0) {
|
|
|
|
|
usage();
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
ctx.timeout = ctx.timeout * 1000;
|
|
|
|
|
break;
|
|
|
|
|
case 'o':
|
|
|
|
|
case OPT_OUTFILE:
|
|
|
|
|
output_arg = optarg;
|
|
|
|
|
break;
|
|
|
|
|
case OPT_KEYCODES:
|
|
|
|
|
ctx.show_keycodes = true;
|
|
|
|
|
break;
|
|
|
|
|
case OPT_MULTIPLE:
|
|
|
|
|
multiple = true;
|
|
|
|
|
break;
|
2018-02-27 14:25:43 +10:00
|
|
|
case OPT_ALL:
|
|
|
|
|
all = true;
|
|
|
|
|
break;
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
case OPT_LIBINPUT:
|
|
|
|
|
with_libinput = true;
|
|
|
|
|
break;
|
2017-11-23 11:01:45 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-27 14:25:43 +10:00
|
|
|
if (all && multiple) {
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"Only one of --multiple and --all allowed.\n");
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-23 11:01:45 +10:00
|
|
|
if (ctx.timeout > 0 && output_arg == NULL) {
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"Option --autorestart requires --output-file\n");
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx.outfile = safe_strdup(output_arg);
|
|
|
|
|
|
|
|
|
|
ndevices = argc - optind;
|
|
|
|
|
|
|
|
|
|
if (multiple) {
|
|
|
|
|
if (output_arg == NULL) {
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"Option --multiple requires --output-file\n");
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ndevices <= 1) {
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"Option --multiple requires all device nodes on the commandline\n");
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = ndevices; i > 0; i -= 1) {
|
|
|
|
|
char *devnode = safe_strdup(argv[optind + i - 1]);
|
|
|
|
|
|
|
|
|
|
if (!init_device(&ctx, devnode))
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2018-02-27 14:25:43 +10:00
|
|
|
} else if (all) {
|
|
|
|
|
char **devices; /* NULL-terminated */
|
|
|
|
|
char **d;
|
|
|
|
|
|
|
|
|
|
if (output_arg == NULL) {
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"Option --all requires --output-file\n");
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
devices = all_devices();
|
|
|
|
|
d = devices;
|
|
|
|
|
|
|
|
|
|
while (*d) {
|
|
|
|
|
if (!init_device(&ctx, safe_strdup(*d))) {
|
|
|
|
|
strv_free(devices);
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
d++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
strv_free(devices);
|
2017-11-23 11:01:45 +10:00
|
|
|
} else {
|
|
|
|
|
char *path;
|
|
|
|
|
|
|
|
|
|
if (ndevices > 1) {
|
|
|
|
|
fprintf(stderr, "More than one device, do you want --multiple?\n");
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
path = ndevices <= 0 ? select_device() : safe_strdup(argv[optind++]);
|
|
|
|
|
if (path == NULL) {
|
|
|
|
|
fprintf(stderr, "Invalid device path\n");
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!init_device(&ctx, path))
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
if (with_libinput && !init_libinput(&ctx))
|
|
|
|
|
goto out;
|
|
|
|
|
|
2017-11-23 11:01:45 +10:00
|
|
|
rc = mainloop(&ctx);
|
|
|
|
|
out:
|
|
|
|
|
list_for_each_safe(d, tmp, &ctx.devices, link) {
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
libinput_device_unref(d->device);
|
|
|
|
|
free(d->events);
|
2017-11-23 11:01:45 +10:00
|
|
|
free(d->devnode);
|
|
|
|
|
libevdev_free(d->evdev);
|
|
|
|
|
}
|
|
|
|
|
|
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-03-01 10:04:11 +10:00
|
|
|
libinput_unref(ctx.libinput);
|
|
|
|
|
|
2017-11-23 11:01:45 +10:00
|
|
|
return rc;
|
|
|
|
|
}
|