1a46c0ec8Sopenharmony_ci/* 2a46c0ec8Sopenharmony_ci * Copyright © 2018 Red Hat, Inc. 3a46c0ec8Sopenharmony_ci * 4a46c0ec8Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5a46c0ec8Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6a46c0ec8Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7a46c0ec8Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8a46c0ec8Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9a46c0ec8Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10a46c0ec8Sopenharmony_ci * 11a46c0ec8Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12a46c0ec8Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13a46c0ec8Sopenharmony_ci * Software. 14a46c0ec8Sopenharmony_ci * 15a46c0ec8Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16a46c0ec8Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17a46c0ec8Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18a46c0ec8Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19a46c0ec8Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20a46c0ec8Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21a46c0ec8Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 22a46c0ec8Sopenharmony_ci */ 23a46c0ec8Sopenharmony_ci 24a46c0ec8Sopenharmony_ci#include "config.h" 25a46c0ec8Sopenharmony_ci 26a46c0ec8Sopenharmony_ci#include <errno.h> 27a46c0ec8Sopenharmony_ci#include <sys/epoll.h> 28a46c0ec8Sopenharmony_ci#include <inttypes.h> 29a46c0ec8Sopenharmony_ci#include <linux/input.h> 30a46c0ec8Sopenharmony_ci#include <libevdev/libevdev.h> 31a46c0ec8Sopenharmony_ci#include <libudev.h> 32a46c0ec8Sopenharmony_ci#include <sys/signalfd.h> 33a46c0ec8Sopenharmony_ci#include <sys/timerfd.h> 34a46c0ec8Sopenharmony_ci#include <sys/utsname.h> 35a46c0ec8Sopenharmony_ci#include <sys/stat.h> 36a46c0ec8Sopenharmony_ci#include <string.h> 37a46c0ec8Sopenharmony_ci#include <dirent.h> 38a46c0ec8Sopenharmony_ci#include <fcntl.h> 39a46c0ec8Sopenharmony_ci#include <getopt.h> 40a46c0ec8Sopenharmony_ci#include <poll.h> 41a46c0ec8Sopenharmony_ci#include <unistd.h> 42a46c0ec8Sopenharmony_ci#include <signal.h> 43a46c0ec8Sopenharmony_ci#include <stdbool.h> 44a46c0ec8Sopenharmony_ci#include <time.h> 45a46c0ec8Sopenharmony_ci 46a46c0ec8Sopenharmony_ci#include "libinput-versionsort.h" 47a46c0ec8Sopenharmony_ci#include "libinput-version.h" 48a46c0ec8Sopenharmony_ci#include "libinput-git-version.h" 49a46c0ec8Sopenharmony_ci#include "shared.h" 50a46c0ec8Sopenharmony_ci#include "builddir.h" 51a46c0ec8Sopenharmony_ci#include "util-bits.h" 52a46c0ec8Sopenharmony_ci#include "util-list.h" 53a46c0ec8Sopenharmony_ci#include "util-time.h" 54a46c0ec8Sopenharmony_ci#include "util-input-event.h" 55a46c0ec8Sopenharmony_ci#include "util-macros.h" 56a46c0ec8Sopenharmony_ci 57a46c0ec8Sopenharmony_cistatic const int FILE_VERSION_NUMBER = 1; 58a46c0ec8Sopenharmony_ci 59a46c0ec8Sopenharmony_ci/* Indentation levels for the various data nodes */ 60a46c0ec8Sopenharmony_cienum indent { 61a46c0ec8Sopenharmony_ci I_NONE = 0, 62a46c0ec8Sopenharmony_ci I_TOPLEVEL = 0, 63a46c0ec8Sopenharmony_ci I_LIBINPUT = 2, /* nodes inside libinput: */ 64a46c0ec8Sopenharmony_ci I_SYSTEM = 2, /* nodes inside system: */ 65a46c0ec8Sopenharmony_ci I_DEVICE = 2, /* nodes inside devices: */ 66a46c0ec8Sopenharmony_ci I_EVDEV = 4, /* nodes inside evdev: */ 67a46c0ec8Sopenharmony_ci I_EVDEV_DATA = 6, /* nodes below evdev: */ 68a46c0ec8Sopenharmony_ci I_UDEV = 4, /* nodes inside udev: */ 69a46c0ec8Sopenharmony_ci I_UDEV_DATA = 6, /* nodes below udev: */ 70a46c0ec8Sopenharmony_ci I_QUIRKS = 4, /* nodes inside quirks: */ 71a46c0ec8Sopenharmony_ci I_LIBINPUTDEV = 4, /* nodes inside libinput: (the 72a46c0ec8Sopenharmony_ci device description */ 73a46c0ec8Sopenharmony_ci I_EVENTTYPE = 4, /* event type (evdev:, libinput:, 74a46c0ec8Sopenharmony_ci hidraw:) */ 75a46c0ec8Sopenharmony_ci I_EVENT = 6, /* event data */ 76a46c0ec8Sopenharmony_ci}; 77a46c0ec8Sopenharmony_ci 78a46c0ec8Sopenharmony_cistruct record_device { 79a46c0ec8Sopenharmony_ci struct record_context *ctx; 80a46c0ec8Sopenharmony_ci struct list link; 81a46c0ec8Sopenharmony_ci char *devnode; /* device node of the source device */ 82a46c0ec8Sopenharmony_ci struct libevdev *evdev; 83a46c0ec8Sopenharmony_ci struct libevdev *evdev_prev; /* previous value, used for EV_ABS 84a46c0ec8Sopenharmony_ci deltas */ 85a46c0ec8Sopenharmony_ci struct libinput_device *device; 86a46c0ec8Sopenharmony_ci struct list hidraw_devices; 87a46c0ec8Sopenharmony_ci 88a46c0ec8Sopenharmony_ci struct { 89a46c0ec8Sopenharmony_ci bool is_touch_device; 90a46c0ec8Sopenharmony_ci uint16_t slot_state; 91a46c0ec8Sopenharmony_ci uint16_t last_slot_state; 92a46c0ec8Sopenharmony_ci } touch; 93a46c0ec8Sopenharmony_ci 94a46c0ec8Sopenharmony_ci FILE *fp; 95a46c0ec8Sopenharmony_ci}; 96a46c0ec8Sopenharmony_ci 97a46c0ec8Sopenharmony_cistruct hidraw { 98a46c0ec8Sopenharmony_ci struct list link; 99a46c0ec8Sopenharmony_ci struct record_device *device; 100a46c0ec8Sopenharmony_ci int fd; 101a46c0ec8Sopenharmony_ci char *name; 102a46c0ec8Sopenharmony_ci}; 103a46c0ec8Sopenharmony_ci 104a46c0ec8Sopenharmony_cistruct record_context { 105a46c0ec8Sopenharmony_ci int timeout; 106a46c0ec8Sopenharmony_ci bool show_keycodes; 107a46c0ec8Sopenharmony_ci 108a46c0ec8Sopenharmony_ci uint64_t offset; 109a46c0ec8Sopenharmony_ci 110a46c0ec8Sopenharmony_ci /* The first device to be added */ 111a46c0ec8Sopenharmony_ci struct record_device *first_device; 112a46c0ec8Sopenharmony_ci 113a46c0ec8Sopenharmony_ci struct list devices; 114a46c0ec8Sopenharmony_ci int ndevices; 115a46c0ec8Sopenharmony_ci 116a46c0ec8Sopenharmony_ci struct { 117a46c0ec8Sopenharmony_ci char *name; /* file name given on cmdline */ 118a46c0ec8Sopenharmony_ci char *name_with_suffix; /* full file name with suffix */ 119a46c0ec8Sopenharmony_ci } output_file; 120a46c0ec8Sopenharmony_ci 121a46c0ec8Sopenharmony_ci struct libinput *libinput; 122a46c0ec8Sopenharmony_ci 123a46c0ec8Sopenharmony_ci int epoll_fd; 124a46c0ec8Sopenharmony_ci struct list sources; 125a46c0ec8Sopenharmony_ci 126a46c0ec8Sopenharmony_ci struct { 127a46c0ec8Sopenharmony_ci bool had_events_since_last_time; 128a46c0ec8Sopenharmony_ci bool skipped_timer_print; 129a46c0ec8Sopenharmony_ci } timestamps; 130a46c0ec8Sopenharmony_ci 131a46c0ec8Sopenharmony_ci bool had_events; 132a46c0ec8Sopenharmony_ci bool stop; 133a46c0ec8Sopenharmony_ci}; 134a46c0ec8Sopenharmony_ci 135a46c0ec8Sopenharmony_ci#define resize(array_, sz_) \ 136a46c0ec8Sopenharmony_ci{ \ 137a46c0ec8Sopenharmony_ci size_t new_size = (sz_) + 1000; \ 138a46c0ec8Sopenharmony_ci void *tmp = realloc((array_), new_size * sizeof(*(array_))); \ 139a46c0ec8Sopenharmony_ci assert(tmp); \ 140a46c0ec8Sopenharmony_ci (array_) = tmp; \ 141a46c0ec8Sopenharmony_ci (sz_) = new_size; \ 142a46c0ec8Sopenharmony_ci} 143a46c0ec8Sopenharmony_ci 144a46c0ec8Sopenharmony_citypedef void (*source_dispatch_t)(struct record_context *ctx, 145a46c0ec8Sopenharmony_ci int fd, 146a46c0ec8Sopenharmony_ci void *user_data); 147a46c0ec8Sopenharmony_ci 148a46c0ec8Sopenharmony_cistruct source { 149a46c0ec8Sopenharmony_ci source_dispatch_t dispatch; 150a46c0ec8Sopenharmony_ci void *user_data; 151a46c0ec8Sopenharmony_ci int fd; 152a46c0ec8Sopenharmony_ci struct list link; 153a46c0ec8Sopenharmony_ci}; 154a46c0ec8Sopenharmony_ci 155a46c0ec8Sopenharmony_cistatic bool 156a46c0ec8Sopenharmony_ciobfuscate_keycode(struct input_event *ev) 157a46c0ec8Sopenharmony_ci{ 158a46c0ec8Sopenharmony_ci switch (ev->type) { 159a46c0ec8Sopenharmony_ci case EV_KEY: 160a46c0ec8Sopenharmony_ci switch (ev->code) { 161a46c0ec8Sopenharmony_ci case KEY_ESC: 162a46c0ec8Sopenharmony_ci case KEY_TAB: 163a46c0ec8Sopenharmony_ci case KEY_ENTER: 164a46c0ec8Sopenharmony_ci case KEY_LEFTCTRL: 165a46c0ec8Sopenharmony_ci break; 166a46c0ec8Sopenharmony_ci default: 167a46c0ec8Sopenharmony_ci if ((ev->code > KEY_ESC && ev->code < KEY_CAPSLOCK) || 168a46c0ec8Sopenharmony_ci (ev->code >= KEY_KP7 && ev->code <= KEY_KPDOT)) { 169a46c0ec8Sopenharmony_ci ev->code = KEY_A; 170a46c0ec8Sopenharmony_ci return true; 171a46c0ec8Sopenharmony_ci } 172a46c0ec8Sopenharmony_ci } 173a46c0ec8Sopenharmony_ci break; 174a46c0ec8Sopenharmony_ci case EV_MSC: 175a46c0ec8Sopenharmony_ci if (ev->code == MSC_SCAN) { 176a46c0ec8Sopenharmony_ci ev->value = 30; /* KEY_A scancode */ 177a46c0ec8Sopenharmony_ci return true; 178a46c0ec8Sopenharmony_ci } 179a46c0ec8Sopenharmony_ci break; 180a46c0ec8Sopenharmony_ci } 181a46c0ec8Sopenharmony_ci 182a46c0ec8Sopenharmony_ci return false; 183a46c0ec8Sopenharmony_ci} 184a46c0ec8Sopenharmony_ci 185a46c0ec8Sopenharmony_ci/** 186a46c0ec8Sopenharmony_ci * Indented dprintf, indentation is in the context 187a46c0ec8Sopenharmony_ci */ 188a46c0ec8Sopenharmony_ciLIBINPUT_ATTRIBUTE_PRINTF(3, 4) 189a46c0ec8Sopenharmony_cistatic void 190a46c0ec8Sopenharmony_ciiprintf(FILE *fp, 191a46c0ec8Sopenharmony_ci enum indent indent, 192a46c0ec8Sopenharmony_ci const char *format, ...) 193a46c0ec8Sopenharmony_ci{ 194a46c0ec8Sopenharmony_ci va_list args; 195a46c0ec8Sopenharmony_ci char fmt[1024]; 196a46c0ec8Sopenharmony_ci static const char space[] = " "; 197a46c0ec8Sopenharmony_ci static const size_t len = sizeof(space); 198a46c0ec8Sopenharmony_ci int rc; 199a46c0ec8Sopenharmony_ci 200a46c0ec8Sopenharmony_ci assert(indent < len); 201a46c0ec8Sopenharmony_ci assert(strlen(format) >= 1); 202a46c0ec8Sopenharmony_ci 203a46c0ec8Sopenharmony_ci /* Special case: if we're printing a new list item, we want less 204a46c0ec8Sopenharmony_ci * indentation because the '- ' takes up one level of indentation 205a46c0ec8Sopenharmony_ci * 206a46c0ec8Sopenharmony_ci * This is only needed because I don't want to deal with open/close 207a46c0ec8Sopenharmony_ci * lists statements. 208a46c0ec8Sopenharmony_ci */ 209a46c0ec8Sopenharmony_ci if (format[0] == '-' && indent > 0) 210a46c0ec8Sopenharmony_ci indent -= 2; 211a46c0ec8Sopenharmony_ci 212a46c0ec8Sopenharmony_ci snprintf(fmt, sizeof(fmt), "%s%s", &space[len - indent - 1], format); 213a46c0ec8Sopenharmony_ci va_start(args, format); 214a46c0ec8Sopenharmony_ci#pragma GCC diagnostic push 215a46c0ec8Sopenharmony_ci#pragma GCC diagnostic ignored "-Wformat-nonliteral" 216a46c0ec8Sopenharmony_ci rc = vfprintf(fp, fmt, args); 217a46c0ec8Sopenharmony_ci#pragma GCC diagnostic pop 218a46c0ec8Sopenharmony_ci va_end(args); 219a46c0ec8Sopenharmony_ci 220a46c0ec8Sopenharmony_ci assert(rc != -1 && (unsigned int)rc > indent); 221a46c0ec8Sopenharmony_ci} 222a46c0ec8Sopenharmony_ci 223a46c0ec8Sopenharmony_cistatic uint64_t 224a46c0ec8Sopenharmony_citime_offset(struct record_context *ctx, uint64_t time) 225a46c0ec8Sopenharmony_ci{ 226a46c0ec8Sopenharmony_ci return ctx->offset ? time - ctx->offset : 0; 227a46c0ec8Sopenharmony_ci} 228a46c0ec8Sopenharmony_ci 229a46c0ec8Sopenharmony_cistatic void 230a46c0ec8Sopenharmony_ciprint_evdev_event(struct record_device *dev, 231a46c0ec8Sopenharmony_ci struct input_event *ev) 232a46c0ec8Sopenharmony_ci{ 233a46c0ec8Sopenharmony_ci const char *tname, *cname; 234a46c0ec8Sopenharmony_ci bool was_modified = false; 235a46c0ec8Sopenharmony_ci char desc[1024]; 236a46c0ec8Sopenharmony_ci uint64_t time = input_event_time(ev) - dev->ctx->offset; 237a46c0ec8Sopenharmony_ci 238a46c0ec8Sopenharmony_ci input_event_set_time(ev, time); 239a46c0ec8Sopenharmony_ci 240a46c0ec8Sopenharmony_ci /* Don't leak passwords unless the user wants to */ 241a46c0ec8Sopenharmony_ci if (!dev->ctx->show_keycodes) 242a46c0ec8Sopenharmony_ci was_modified = obfuscate_keycode(ev); 243a46c0ec8Sopenharmony_ci 244a46c0ec8Sopenharmony_ci tname = libevdev_event_type_get_name(ev->type); 245a46c0ec8Sopenharmony_ci cname = libevdev_event_code_get_name(ev->type, ev->code); 246a46c0ec8Sopenharmony_ci 247a46c0ec8Sopenharmony_ci if (ev->type == EV_SYN && ev->code == SYN_MT_REPORT) { 248a46c0ec8Sopenharmony_ci snprintf(desc, 249a46c0ec8Sopenharmony_ci sizeof(desc), 250a46c0ec8Sopenharmony_ci "++++++++++++ %s (%d) ++++++++++", 251a46c0ec8Sopenharmony_ci cname, 252a46c0ec8Sopenharmony_ci ev->value); 253a46c0ec8Sopenharmony_ci } else if (ev->type == EV_SYN) { 254a46c0ec8Sopenharmony_ci static unsigned long last_ms = 0; 255a46c0ec8Sopenharmony_ci unsigned long time, dt; 256a46c0ec8Sopenharmony_ci 257a46c0ec8Sopenharmony_ci time = us2ms(input_event_time(ev)); 258a46c0ec8Sopenharmony_ci dt = time - last_ms; 259a46c0ec8Sopenharmony_ci last_ms = time; 260a46c0ec8Sopenharmony_ci 261a46c0ec8Sopenharmony_ci snprintf(desc, 262a46c0ec8Sopenharmony_ci sizeof(desc), 263a46c0ec8Sopenharmony_ci "------------ %s (%d) ---------- %+ldms", 264a46c0ec8Sopenharmony_ci cname, 265a46c0ec8Sopenharmony_ci ev->value, 266a46c0ec8Sopenharmony_ci dt); 267a46c0ec8Sopenharmony_ci } else if (ev->type == EV_ABS) { 268a46c0ec8Sopenharmony_ci int oldval = 0; 269a46c0ec8Sopenharmony_ci enum { DELTA, SLOT_DELTA, NO_DELTA } want = DELTA; 270a46c0ec8Sopenharmony_ci int delta = 0; 271a46c0ec8Sopenharmony_ci 272a46c0ec8Sopenharmony_ci /* We want to print deltas for abs axes but there are a few 273a46c0ec8Sopenharmony_ci * that we don't care about for actual deltas because 274a46c0ec8Sopenharmony_ci * they're meaningless. 275a46c0ec8Sopenharmony_ci * 276a46c0ec8Sopenharmony_ci * Also, any slotted axis needs to be printed per slot 277a46c0ec8Sopenharmony_ci */ 278a46c0ec8Sopenharmony_ci switch (ev->code) { 279a46c0ec8Sopenharmony_ci case ABS_MT_SLOT: 280a46c0ec8Sopenharmony_ci libevdev_set_event_value(dev->evdev_prev, 281a46c0ec8Sopenharmony_ci ev->type, 282a46c0ec8Sopenharmony_ci ev->code, 283a46c0ec8Sopenharmony_ci ev->value); 284a46c0ec8Sopenharmony_ci want = NO_DELTA; 285a46c0ec8Sopenharmony_ci break; 286a46c0ec8Sopenharmony_ci case ABS_MT_TRACKING_ID: 287a46c0ec8Sopenharmony_ci case ABS_MT_BLOB_ID: 288a46c0ec8Sopenharmony_ci want = NO_DELTA; 289a46c0ec8Sopenharmony_ci break; 290a46c0ec8Sopenharmony_ci case ABS_MT_TOUCH_MAJOR ... ABS_MT_POSITION_Y: 291a46c0ec8Sopenharmony_ci case ABS_MT_PRESSURE ... ABS_MT_TOOL_Y: 292a46c0ec8Sopenharmony_ci if (libevdev_get_num_slots(dev->evdev_prev) > 0) 293a46c0ec8Sopenharmony_ci want = SLOT_DELTA; 294a46c0ec8Sopenharmony_ci break; 295a46c0ec8Sopenharmony_ci default: 296a46c0ec8Sopenharmony_ci break; 297a46c0ec8Sopenharmony_ci } 298a46c0ec8Sopenharmony_ci 299a46c0ec8Sopenharmony_ci switch (want) { 300a46c0ec8Sopenharmony_ci case DELTA: 301a46c0ec8Sopenharmony_ci oldval = libevdev_get_event_value(dev->evdev_prev, 302a46c0ec8Sopenharmony_ci ev->type, 303a46c0ec8Sopenharmony_ci ev->code); 304a46c0ec8Sopenharmony_ci libevdev_set_event_value(dev->evdev_prev, 305a46c0ec8Sopenharmony_ci ev->type, 306a46c0ec8Sopenharmony_ci ev->code, 307a46c0ec8Sopenharmony_ci ev->value); 308a46c0ec8Sopenharmony_ci break; 309a46c0ec8Sopenharmony_ci case SLOT_DELTA: { 310a46c0ec8Sopenharmony_ci int slot = libevdev_get_current_slot(dev->evdev_prev); 311a46c0ec8Sopenharmony_ci oldval = libevdev_get_slot_value(dev->evdev_prev, 312a46c0ec8Sopenharmony_ci slot, 313a46c0ec8Sopenharmony_ci ev->code); 314a46c0ec8Sopenharmony_ci libevdev_set_slot_value(dev->evdev_prev, 315a46c0ec8Sopenharmony_ci slot, 316a46c0ec8Sopenharmony_ci ev->code, 317a46c0ec8Sopenharmony_ci ev->value); 318a46c0ec8Sopenharmony_ci break; 319a46c0ec8Sopenharmony_ci } 320a46c0ec8Sopenharmony_ci case NO_DELTA: 321a46c0ec8Sopenharmony_ci break; 322a46c0ec8Sopenharmony_ci 323a46c0ec8Sopenharmony_ci } 324a46c0ec8Sopenharmony_ci 325a46c0ec8Sopenharmony_ci delta = ev->value - oldval; 326a46c0ec8Sopenharmony_ci 327a46c0ec8Sopenharmony_ci switch (want) { 328a46c0ec8Sopenharmony_ci case DELTA: 329a46c0ec8Sopenharmony_ci case SLOT_DELTA: 330a46c0ec8Sopenharmony_ci snprintf(desc, 331a46c0ec8Sopenharmony_ci sizeof(desc), 332a46c0ec8Sopenharmony_ci "%s / %-20s %6d (%+d)", 333a46c0ec8Sopenharmony_ci tname, 334a46c0ec8Sopenharmony_ci cname, 335a46c0ec8Sopenharmony_ci ev->value, 336a46c0ec8Sopenharmony_ci delta); 337a46c0ec8Sopenharmony_ci break; 338a46c0ec8Sopenharmony_ci case NO_DELTA: 339a46c0ec8Sopenharmony_ci snprintf(desc, 340a46c0ec8Sopenharmony_ci sizeof(desc), 341a46c0ec8Sopenharmony_ci "%s / %-20s %6d", 342a46c0ec8Sopenharmony_ci tname, 343a46c0ec8Sopenharmony_ci cname, 344a46c0ec8Sopenharmony_ci ev->value); 345a46c0ec8Sopenharmony_ci break; 346a46c0ec8Sopenharmony_ci } 347a46c0ec8Sopenharmony_ci } else { 348a46c0ec8Sopenharmony_ci snprintf(desc, 349a46c0ec8Sopenharmony_ci sizeof(desc), 350a46c0ec8Sopenharmony_ci "%s / %-20s %6d%s", 351a46c0ec8Sopenharmony_ci tname, 352a46c0ec8Sopenharmony_ci cname, 353a46c0ec8Sopenharmony_ci ev->value, 354a46c0ec8Sopenharmony_ci was_modified ? " (obfuscated)" : ""); 355a46c0ec8Sopenharmony_ci } 356a46c0ec8Sopenharmony_ci 357a46c0ec8Sopenharmony_ci iprintf(dev->fp, 358a46c0ec8Sopenharmony_ci I_EVENT, 359a46c0ec8Sopenharmony_ci "- [%3lu, %6u, %3d, %3d, %7d] # %s\n", 360a46c0ec8Sopenharmony_ci ev->input_event_sec, 361a46c0ec8Sopenharmony_ci (unsigned int)ev->input_event_usec, 362a46c0ec8Sopenharmony_ci ev->type, 363a46c0ec8Sopenharmony_ci ev->code, 364a46c0ec8Sopenharmony_ci ev->value, 365a46c0ec8Sopenharmony_ci desc); 366a46c0ec8Sopenharmony_ci} 367a46c0ec8Sopenharmony_ci 368a46c0ec8Sopenharmony_cistatic bool 369a46c0ec8Sopenharmony_cihandle_evdev_frame(struct record_device *d) 370a46c0ec8Sopenharmony_ci{ 371a46c0ec8Sopenharmony_ci struct libevdev *evdev = d->evdev; 372a46c0ec8Sopenharmony_ci struct input_event e; 373a46c0ec8Sopenharmony_ci 374a46c0ec8Sopenharmony_ci if (libevdev_next_event(evdev, LIBEVDEV_READ_FLAG_NORMAL, &e) != 375a46c0ec8Sopenharmony_ci LIBEVDEV_READ_STATUS_SUCCESS) 376a46c0ec8Sopenharmony_ci return false; 377a46c0ec8Sopenharmony_ci 378a46c0ec8Sopenharmony_ci iprintf(d->fp, I_EVENTTYPE, "- evdev:\n"); 379a46c0ec8Sopenharmony_ci do { 380a46c0ec8Sopenharmony_ci 381a46c0ec8Sopenharmony_ci if (d->ctx->offset == 0) { 382a46c0ec8Sopenharmony_ci uint64_t time = input_event_time(&e); 383a46c0ec8Sopenharmony_ci d->ctx->offset = time; 384a46c0ec8Sopenharmony_ci } 385a46c0ec8Sopenharmony_ci 386a46c0ec8Sopenharmony_ci print_evdev_event(d, &e); 387a46c0ec8Sopenharmony_ci 388a46c0ec8Sopenharmony_ci if (d->touch.is_touch_device && 389a46c0ec8Sopenharmony_ci e.type == EV_ABS && 390a46c0ec8Sopenharmony_ci e.code == ABS_MT_TRACKING_ID) { 391a46c0ec8Sopenharmony_ci unsigned int slot = libevdev_get_current_slot(evdev); 392a46c0ec8Sopenharmony_ci assert(slot < sizeof(d->touch.slot_state) * 8); 393a46c0ec8Sopenharmony_ci 394a46c0ec8Sopenharmony_ci if (e.value != -1) 395a46c0ec8Sopenharmony_ci d->touch.slot_state |= bit(slot); 396a46c0ec8Sopenharmony_ci else 397a46c0ec8Sopenharmony_ci d->touch.slot_state &= ~bit(slot); 398a46c0ec8Sopenharmony_ci } 399a46c0ec8Sopenharmony_ci 400a46c0ec8Sopenharmony_ci if (e.type == EV_SYN && e.code == SYN_REPORT) 401a46c0ec8Sopenharmony_ci break; 402a46c0ec8Sopenharmony_ci } while (libevdev_next_event(evdev, 403a46c0ec8Sopenharmony_ci LIBEVDEV_READ_FLAG_NORMAL, 404a46c0ec8Sopenharmony_ci &e) == LIBEVDEV_READ_STATUS_SUCCESS); 405a46c0ec8Sopenharmony_ci 406a46c0ec8Sopenharmony_ci if (d->touch.slot_state != d->touch.last_slot_state) { 407a46c0ec8Sopenharmony_ci d->touch.last_slot_state = d->touch.slot_state; 408a46c0ec8Sopenharmony_ci if (d->touch.slot_state == 0) { 409a46c0ec8Sopenharmony_ci iprintf(d->fp, 410a46c0ec8Sopenharmony_ci I_EVENT, 411a46c0ec8Sopenharmony_ci " # Touch device in neutral state\n"); 412a46c0ec8Sopenharmony_ci } 413a46c0ec8Sopenharmony_ci } 414a46c0ec8Sopenharmony_ci 415a46c0ec8Sopenharmony_ci return true; 416a46c0ec8Sopenharmony_ci} 417a46c0ec8Sopenharmony_ci 418a46c0ec8Sopenharmony_cistatic void 419a46c0ec8Sopenharmony_ciprint_device_notify(struct record_device *dev, struct libinput_event *e) 420a46c0ec8Sopenharmony_ci{ 421a46c0ec8Sopenharmony_ci struct libinput_device *d = libinput_event_get_device(e); 422a46c0ec8Sopenharmony_ci struct libinput_seat *seat = libinput_device_get_seat(d); 423a46c0ec8Sopenharmony_ci const char *type = NULL; 424a46c0ec8Sopenharmony_ci 425a46c0ec8Sopenharmony_ci switch(libinput_event_get_type(e)) { 426a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_DEVICE_ADDED: 427a46c0ec8Sopenharmony_ci type = "DEVICE_ADDED"; 428a46c0ec8Sopenharmony_ci break; 429a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_DEVICE_REMOVED: 430a46c0ec8Sopenharmony_ci type = "DEVICE_REMOVED"; 431a46c0ec8Sopenharmony_ci break; 432a46c0ec8Sopenharmony_ci default: 433a46c0ec8Sopenharmony_ci abort(); 434a46c0ec8Sopenharmony_ci } 435a46c0ec8Sopenharmony_ci 436a46c0ec8Sopenharmony_ci iprintf(dev->fp, 437a46c0ec8Sopenharmony_ci I_EVENT, 438a46c0ec8Sopenharmony_ci "- {type: %s, seat: %5s, logical_seat: %7s}\n", 439a46c0ec8Sopenharmony_ci type, 440a46c0ec8Sopenharmony_ci libinput_seat_get_physical_name(seat), 441a46c0ec8Sopenharmony_ci libinput_seat_get_logical_name(seat)); 442a46c0ec8Sopenharmony_ci} 443a46c0ec8Sopenharmony_ci 444a46c0ec8Sopenharmony_cistatic void 445a46c0ec8Sopenharmony_ciprint_key_event(struct record_device *dev, struct libinput_event *e) 446a46c0ec8Sopenharmony_ci{ 447a46c0ec8Sopenharmony_ci struct libinput_event_keyboard *k = libinput_event_get_keyboard_event(e); 448a46c0ec8Sopenharmony_ci enum libinput_key_state state; 449a46c0ec8Sopenharmony_ci uint32_t key; 450a46c0ec8Sopenharmony_ci uint64_t time; 451a46c0ec8Sopenharmony_ci const char *type; 452a46c0ec8Sopenharmony_ci 453a46c0ec8Sopenharmony_ci switch(libinput_event_get_type(e)) { 454a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_KEYBOARD_KEY: 455a46c0ec8Sopenharmony_ci type = "KEYBOARD_KEY"; 456a46c0ec8Sopenharmony_ci break; 457a46c0ec8Sopenharmony_ci default: 458a46c0ec8Sopenharmony_ci abort(); 459a46c0ec8Sopenharmony_ci } 460a46c0ec8Sopenharmony_ci 461a46c0ec8Sopenharmony_ci time = time_offset(dev->ctx, libinput_event_keyboard_get_time_usec(k)); 462a46c0ec8Sopenharmony_ci state = libinput_event_keyboard_get_key_state(k); 463a46c0ec8Sopenharmony_ci 464a46c0ec8Sopenharmony_ci key = libinput_event_keyboard_get_key(k); 465a46c0ec8Sopenharmony_ci if (!dev->ctx->show_keycodes && 466a46c0ec8Sopenharmony_ci (key >= KEY_ESC && key < KEY_ZENKAKUHANKAKU)) 467a46c0ec8Sopenharmony_ci key = -1; 468a46c0ec8Sopenharmony_ci 469a46c0ec8Sopenharmony_ci iprintf(dev->fp, 470a46c0ec8Sopenharmony_ci I_EVENT, 471a46c0ec8Sopenharmony_ci "- {time: %ld.%06ld, type: %s, key: %d, state: %s}\n", 472a46c0ec8Sopenharmony_ci (long)(time / (int)1e6), 473a46c0ec8Sopenharmony_ci (long)(time % (int)1e6), 474a46c0ec8Sopenharmony_ci type, 475a46c0ec8Sopenharmony_ci key, 476a46c0ec8Sopenharmony_ci state == LIBINPUT_KEY_STATE_PRESSED ? "pressed" : "released"); 477a46c0ec8Sopenharmony_ci} 478a46c0ec8Sopenharmony_ci 479a46c0ec8Sopenharmony_cistatic void 480a46c0ec8Sopenharmony_ciprint_motion_event(struct record_device *dev, struct libinput_event *e) 481a46c0ec8Sopenharmony_ci{ 482a46c0ec8Sopenharmony_ci struct libinput_event_pointer *p = libinput_event_get_pointer_event(e); 483a46c0ec8Sopenharmony_ci double x = libinput_event_pointer_get_dx(p), 484a46c0ec8Sopenharmony_ci y = libinput_event_pointer_get_dy(p); 485a46c0ec8Sopenharmony_ci double uax = libinput_event_pointer_get_dx_unaccelerated(p), 486a46c0ec8Sopenharmony_ci uay = libinput_event_pointer_get_dy_unaccelerated(p); 487a46c0ec8Sopenharmony_ci uint64_t time; 488a46c0ec8Sopenharmony_ci const char *type; 489a46c0ec8Sopenharmony_ci 490a46c0ec8Sopenharmony_ci switch(libinput_event_get_type(e)) { 491a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_POINTER_MOTION: 492a46c0ec8Sopenharmony_ci type = "POINTER_MOTION"; 493a46c0ec8Sopenharmony_ci break; 494a46c0ec8Sopenharmony_ci default: 495a46c0ec8Sopenharmony_ci abort(); 496a46c0ec8Sopenharmony_ci } 497a46c0ec8Sopenharmony_ci 498a46c0ec8Sopenharmony_ci time = time_offset(dev->ctx, libinput_event_pointer_get_time_usec(p)); 499a46c0ec8Sopenharmony_ci iprintf(dev->fp, 500a46c0ec8Sopenharmony_ci I_EVENT, 501a46c0ec8Sopenharmony_ci "- {time: %ld.%06ld, type: %s, delta: [%6.2f, %6.2f], unaccel: [%6.2f, %6.2f]}\n", 502a46c0ec8Sopenharmony_ci (long)(time / (int)1e6), 503a46c0ec8Sopenharmony_ci (long)(time % (int)1e6), 504a46c0ec8Sopenharmony_ci type, 505a46c0ec8Sopenharmony_ci x, y, 506a46c0ec8Sopenharmony_ci uax, uay); 507a46c0ec8Sopenharmony_ci} 508a46c0ec8Sopenharmony_ci 509a46c0ec8Sopenharmony_cistatic void 510a46c0ec8Sopenharmony_ciprint_absmotion_event(struct record_device *dev, struct libinput_event *e) 511a46c0ec8Sopenharmony_ci{ 512a46c0ec8Sopenharmony_ci struct libinput_event_pointer *p = libinput_event_get_pointer_event(e); 513a46c0ec8Sopenharmony_ci double x = libinput_event_pointer_get_absolute_x(p), 514a46c0ec8Sopenharmony_ci y = libinput_event_pointer_get_absolute_y(p); 515a46c0ec8Sopenharmony_ci double tx = libinput_event_pointer_get_absolute_x_transformed(p, 100), 516a46c0ec8Sopenharmony_ci ty = libinput_event_pointer_get_absolute_y_transformed(p, 100); 517a46c0ec8Sopenharmony_ci uint64_t time; 518a46c0ec8Sopenharmony_ci const char *type; 519a46c0ec8Sopenharmony_ci 520a46c0ec8Sopenharmony_ci switch(libinput_event_get_type(e)) { 521a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: 522a46c0ec8Sopenharmony_ci type = "POINTER_MOTION_ABSOLUTE"; 523a46c0ec8Sopenharmony_ci break; 524a46c0ec8Sopenharmony_ci default: 525a46c0ec8Sopenharmony_ci abort(); 526a46c0ec8Sopenharmony_ci } 527a46c0ec8Sopenharmony_ci 528a46c0ec8Sopenharmony_ci time = time_offset(dev->ctx, libinput_event_pointer_get_time_usec(p)); 529a46c0ec8Sopenharmony_ci 530a46c0ec8Sopenharmony_ci iprintf(dev->fp, 531a46c0ec8Sopenharmony_ci I_EVENT, 532a46c0ec8Sopenharmony_ci "- {time: %ld.%06ld, type: %s, point: [%6.2f, %6.2f], transformed: [%6.2f, %6.2f]}\n", 533a46c0ec8Sopenharmony_ci (long)(time / (int)1e6), 534a46c0ec8Sopenharmony_ci (long)(time % (int)1e6), 535a46c0ec8Sopenharmony_ci type, 536a46c0ec8Sopenharmony_ci x, y, 537a46c0ec8Sopenharmony_ci tx, ty); 538a46c0ec8Sopenharmony_ci} 539a46c0ec8Sopenharmony_ci 540a46c0ec8Sopenharmony_cistatic void 541a46c0ec8Sopenharmony_ciprint_pointer_button_event(struct record_device *dev, struct libinput_event *e) 542a46c0ec8Sopenharmony_ci{ 543a46c0ec8Sopenharmony_ci struct libinput_event_pointer *p = libinput_event_get_pointer_event(e); 544a46c0ec8Sopenharmony_ci enum libinput_button_state state; 545a46c0ec8Sopenharmony_ci int button; 546a46c0ec8Sopenharmony_ci uint64_t time; 547a46c0ec8Sopenharmony_ci const char *type; 548a46c0ec8Sopenharmony_ci 549a46c0ec8Sopenharmony_ci switch(libinput_event_get_type(e)) { 550a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_POINTER_BUTTON: 551a46c0ec8Sopenharmony_ci type = "POINTER_BUTTON"; 552a46c0ec8Sopenharmony_ci break; 553a46c0ec8Sopenharmony_ci default: 554a46c0ec8Sopenharmony_ci abort(); 555a46c0ec8Sopenharmony_ci } 556a46c0ec8Sopenharmony_ci 557a46c0ec8Sopenharmony_ci time = time_offset(dev->ctx, libinput_event_pointer_get_time_usec(p)); 558a46c0ec8Sopenharmony_ci button = libinput_event_pointer_get_button(p); 559a46c0ec8Sopenharmony_ci state = libinput_event_pointer_get_button_state(p); 560a46c0ec8Sopenharmony_ci 561a46c0ec8Sopenharmony_ci iprintf(dev->fp, 562a46c0ec8Sopenharmony_ci I_EVENT, 563a46c0ec8Sopenharmony_ci "- {time: %ld.%06ld, type: %s, button: %d, state: %s, seat_count: %u}\n", 564a46c0ec8Sopenharmony_ci (long)(time / (int)1e6), 565a46c0ec8Sopenharmony_ci (long)(time % (int)1e6), 566a46c0ec8Sopenharmony_ci type, 567a46c0ec8Sopenharmony_ci button, 568a46c0ec8Sopenharmony_ci state == LIBINPUT_BUTTON_STATE_PRESSED ? "pressed" : "released", 569a46c0ec8Sopenharmony_ci libinput_event_pointer_get_seat_button_count(p)); 570a46c0ec8Sopenharmony_ci} 571a46c0ec8Sopenharmony_ci 572a46c0ec8Sopenharmony_cistatic void 573a46c0ec8Sopenharmony_ciprint_pointer_axis_event(struct record_device *dev, struct libinput_event *e) 574a46c0ec8Sopenharmony_ci{ 575a46c0ec8Sopenharmony_ci struct libinput_event_pointer *p = libinput_event_get_pointer_event(e); 576a46c0ec8Sopenharmony_ci uint64_t time; 577a46c0ec8Sopenharmony_ci const char *type, *source; 578a46c0ec8Sopenharmony_ci double h = 0, v = 0; 579a46c0ec8Sopenharmony_ci int hd = 0, vd = 0; 580a46c0ec8Sopenharmony_ci 581a46c0ec8Sopenharmony_ci switch(libinput_event_get_type(e)) { 582a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_POINTER_AXIS: 583a46c0ec8Sopenharmony_ci type = "POINTER_AXIS"; 584a46c0ec8Sopenharmony_ci break; 585a46c0ec8Sopenharmony_ci default: 586a46c0ec8Sopenharmony_ci abort(); 587a46c0ec8Sopenharmony_ci } 588a46c0ec8Sopenharmony_ci 589a46c0ec8Sopenharmony_ci time = time_offset(dev->ctx, libinput_event_pointer_get_time_usec(p)); 590a46c0ec8Sopenharmony_ci if (libinput_event_pointer_has_axis(p, 591a46c0ec8Sopenharmony_ci LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) { 592a46c0ec8Sopenharmony_ci h = libinput_event_pointer_get_axis_value(p, 593a46c0ec8Sopenharmony_ci LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL); 594a46c0ec8Sopenharmony_ci hd = libinput_event_pointer_get_axis_value_discrete(p, 595a46c0ec8Sopenharmony_ci LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL); 596a46c0ec8Sopenharmony_ci } 597a46c0ec8Sopenharmony_ci if (libinput_event_pointer_has_axis(p, 598a46c0ec8Sopenharmony_ci LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) { 599a46c0ec8Sopenharmony_ci v = libinput_event_pointer_get_axis_value(p, 600a46c0ec8Sopenharmony_ci LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); 601a46c0ec8Sopenharmony_ci vd = libinput_event_pointer_get_axis_value_discrete(p, 602a46c0ec8Sopenharmony_ci LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); 603a46c0ec8Sopenharmony_ci } 604a46c0ec8Sopenharmony_ci switch(libinput_event_pointer_get_axis_source(p)) { 605a46c0ec8Sopenharmony_ci case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL: source = "wheel"; break; 606a46c0ec8Sopenharmony_ci case LIBINPUT_POINTER_AXIS_SOURCE_FINGER: source = "finger"; break; 607a46c0ec8Sopenharmony_ci case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS: source = "continuous"; break; 608a46c0ec8Sopenharmony_ci case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL_TILT: source = "wheel-tilt"; break; 609a46c0ec8Sopenharmony_ci default: 610a46c0ec8Sopenharmony_ci source = "unknown"; 611a46c0ec8Sopenharmony_ci break; 612a46c0ec8Sopenharmony_ci } 613a46c0ec8Sopenharmony_ci 614a46c0ec8Sopenharmony_ci iprintf(dev->fp, 615a46c0ec8Sopenharmony_ci I_EVENT, 616a46c0ec8Sopenharmony_ci "- {time: %ld.%06ld, type: %s, axes: [%2.2f, %2.2f], discrete: [%d, %d], source: %s}\n", 617a46c0ec8Sopenharmony_ci (long)(time / (int)1e6), 618a46c0ec8Sopenharmony_ci (long)(time % (int)1e6), 619a46c0ec8Sopenharmony_ci type, 620a46c0ec8Sopenharmony_ci h, v, 621a46c0ec8Sopenharmony_ci hd, vd, 622a46c0ec8Sopenharmony_ci source); 623a46c0ec8Sopenharmony_ci} 624a46c0ec8Sopenharmony_ci 625a46c0ec8Sopenharmony_cistatic void 626a46c0ec8Sopenharmony_ciprint_touch_event(struct record_device *dev, struct libinput_event *e) 627a46c0ec8Sopenharmony_ci{ 628a46c0ec8Sopenharmony_ci enum libinput_event_type etype = libinput_event_get_type(e); 629a46c0ec8Sopenharmony_ci struct libinput_event_touch *t = libinput_event_get_touch_event(e); 630a46c0ec8Sopenharmony_ci const char *type; 631a46c0ec8Sopenharmony_ci double x, y; 632a46c0ec8Sopenharmony_ci double tx, ty; 633a46c0ec8Sopenharmony_ci uint64_t time; 634a46c0ec8Sopenharmony_ci int32_t slot, seat_slot; 635a46c0ec8Sopenharmony_ci 636a46c0ec8Sopenharmony_ci switch(etype) { 637a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_DOWN: 638a46c0ec8Sopenharmony_ci type = "TOUCH_DOWN"; 639a46c0ec8Sopenharmony_ci break; 640a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_UP: 641a46c0ec8Sopenharmony_ci type = "TOUCH_UP"; 642a46c0ec8Sopenharmony_ci break; 643a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_MOTION: 644a46c0ec8Sopenharmony_ci type = "TOUCH_MOTION"; 645a46c0ec8Sopenharmony_ci break; 646a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_CANCEL: 647a46c0ec8Sopenharmony_ci type = "TOUCH_CANCEL"; 648a46c0ec8Sopenharmony_ci break; 649a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_FRAME: 650a46c0ec8Sopenharmony_ci type = "TOUCH_FRAME"; 651a46c0ec8Sopenharmony_ci break; 652a46c0ec8Sopenharmony_ci default: 653a46c0ec8Sopenharmony_ci abort(); 654a46c0ec8Sopenharmony_ci } 655a46c0ec8Sopenharmony_ci 656a46c0ec8Sopenharmony_ci time = time_offset(dev->ctx, libinput_event_touch_get_time_usec(t)); 657a46c0ec8Sopenharmony_ci 658a46c0ec8Sopenharmony_ci if (etype != LIBINPUT_EVENT_TOUCH_FRAME) { 659a46c0ec8Sopenharmony_ci slot = libinput_event_touch_get_slot(t); 660a46c0ec8Sopenharmony_ci seat_slot = libinput_event_touch_get_seat_slot(t); 661a46c0ec8Sopenharmony_ci } 662a46c0ec8Sopenharmony_ci 663a46c0ec8Sopenharmony_ci switch (etype) { 664a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_FRAME: 665a46c0ec8Sopenharmony_ci iprintf(dev->fp, 666a46c0ec8Sopenharmony_ci I_EVENT, 667a46c0ec8Sopenharmony_ci "- {time: %ld.%06ld, type: %s}\n", 668a46c0ec8Sopenharmony_ci (long)(time / (int)1e6), 669a46c0ec8Sopenharmony_ci (long)(time % (int)1e6), 670a46c0ec8Sopenharmony_ci type); 671a46c0ec8Sopenharmony_ci break; 672a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_DOWN: 673a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_MOTION: 674a46c0ec8Sopenharmony_ci x = libinput_event_touch_get_x(t); 675a46c0ec8Sopenharmony_ci y = libinput_event_touch_get_y(t); 676a46c0ec8Sopenharmony_ci tx = libinput_event_touch_get_x_transformed(t, 100); 677a46c0ec8Sopenharmony_ci ty = libinput_event_touch_get_y_transformed(t, 100); 678a46c0ec8Sopenharmony_ci iprintf(dev->fp, 679a46c0ec8Sopenharmony_ci I_EVENT, 680a46c0ec8Sopenharmony_ci "- {time: %ld.%06ld, type: %s, slot: %d, seat_slot: %d, " 681a46c0ec8Sopenharmony_ci "point: [%6.2f, %6.2f], transformed: [%6.2f, %6.2f]}\n", 682a46c0ec8Sopenharmony_ci (long)(time / (int)1e6), 683a46c0ec8Sopenharmony_ci (long)(time % (int)1e6), 684a46c0ec8Sopenharmony_ci type, 685a46c0ec8Sopenharmony_ci slot, 686a46c0ec8Sopenharmony_ci seat_slot, 687a46c0ec8Sopenharmony_ci x, y, 688a46c0ec8Sopenharmony_ci tx, ty); 689a46c0ec8Sopenharmony_ci break; 690a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_UP: 691a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_CANCEL: 692a46c0ec8Sopenharmony_ci iprintf(dev->fp, 693a46c0ec8Sopenharmony_ci I_EVENT, 694a46c0ec8Sopenharmony_ci "- {time: %ld.%06ld, type: %s, slot: %d, seat_slot: %d}\n", 695a46c0ec8Sopenharmony_ci (long)(time / (int)1e6), 696a46c0ec8Sopenharmony_ci (long)(time % (int)1e6), 697a46c0ec8Sopenharmony_ci type, 698a46c0ec8Sopenharmony_ci slot, 699a46c0ec8Sopenharmony_ci seat_slot); 700a46c0ec8Sopenharmony_ci break; 701a46c0ec8Sopenharmony_ci default: 702a46c0ec8Sopenharmony_ci abort(); 703a46c0ec8Sopenharmony_ci } 704a46c0ec8Sopenharmony_ci} 705a46c0ec8Sopenharmony_ci 706a46c0ec8Sopenharmony_cistatic void 707a46c0ec8Sopenharmony_ciprint_gesture_event(struct record_device *dev, struct libinput_event *e) 708a46c0ec8Sopenharmony_ci{ 709a46c0ec8Sopenharmony_ci enum libinput_event_type etype = libinput_event_get_type(e); 710a46c0ec8Sopenharmony_ci struct libinput_event_gesture *g = libinput_event_get_gesture_event(e); 711a46c0ec8Sopenharmony_ci const char *type; 712a46c0ec8Sopenharmony_ci uint64_t time; 713a46c0ec8Sopenharmony_ci 714a46c0ec8Sopenharmony_ci switch(etype) { 715a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: 716a46c0ec8Sopenharmony_ci type = "GESTURE_PINCH_BEGIN"; 717a46c0ec8Sopenharmony_ci break; 718a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: 719a46c0ec8Sopenharmony_ci type = "GESTURE_PINCH_UPDATE"; 720a46c0ec8Sopenharmony_ci break; 721a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_PINCH_END: 722a46c0ec8Sopenharmony_ci type = "GESTURE_PINCH_END"; 723a46c0ec8Sopenharmony_ci break; 724a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: 725a46c0ec8Sopenharmony_ci type = "GESTURE_SWIPE_BEGIN"; 726a46c0ec8Sopenharmony_ci break; 727a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: 728a46c0ec8Sopenharmony_ci type = "GESTURE_SWIPE_UPDATE"; 729a46c0ec8Sopenharmony_ci break; 730a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_SWIPE_END: 731a46c0ec8Sopenharmony_ci type = "GESTURE_SWIPE_END"; 732a46c0ec8Sopenharmony_ci break; 733a46c0ec8Sopenharmony_ci default: 734a46c0ec8Sopenharmony_ci abort(); 735a46c0ec8Sopenharmony_ci } 736a46c0ec8Sopenharmony_ci 737a46c0ec8Sopenharmony_ci time = time_offset(dev->ctx, libinput_event_gesture_get_time_usec(g)); 738a46c0ec8Sopenharmony_ci 739a46c0ec8Sopenharmony_ci switch (etype) { 740a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: 741a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: 742a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_PINCH_END: 743a46c0ec8Sopenharmony_ci iprintf(dev->fp, 744a46c0ec8Sopenharmony_ci I_EVENT, 745a46c0ec8Sopenharmony_ci "- {time: %ld.%06ld, type: %s, nfingers: %d, " 746a46c0ec8Sopenharmony_ci "delta: [%6.2f, %6.2f], unaccel: [%6.2f, %6.2f], " 747a46c0ec8Sopenharmony_ci "angle_delta: %6.2f, scale: %6.2f}\n", 748a46c0ec8Sopenharmony_ci (long)(time / (int)1e6), 749a46c0ec8Sopenharmony_ci (long)(time % (int)1e6), 750a46c0ec8Sopenharmony_ci type, 751a46c0ec8Sopenharmony_ci libinput_event_gesture_get_finger_count(g), 752a46c0ec8Sopenharmony_ci libinput_event_gesture_get_dx(g), 753a46c0ec8Sopenharmony_ci libinput_event_gesture_get_dy(g), 754a46c0ec8Sopenharmony_ci libinput_event_gesture_get_dx_unaccelerated(g), 755a46c0ec8Sopenharmony_ci libinput_event_gesture_get_dy_unaccelerated(g), 756a46c0ec8Sopenharmony_ci libinput_event_gesture_get_angle_delta(g), 757a46c0ec8Sopenharmony_ci libinput_event_gesture_get_scale(g) 758a46c0ec8Sopenharmony_ci ); 759a46c0ec8Sopenharmony_ci break; 760a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: 761a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: 762a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_SWIPE_END: 763a46c0ec8Sopenharmony_ci iprintf(dev->fp, 764a46c0ec8Sopenharmony_ci I_EVENT, 765a46c0ec8Sopenharmony_ci "- {time: %ld.%06ld, type: %s, nfingers: %d, " 766a46c0ec8Sopenharmony_ci "delta: [%6.2f, %6.2f], unaccel: [%6.2f, %6.2f]}\n", 767a46c0ec8Sopenharmony_ci (long)(time / (int)1e6), 768a46c0ec8Sopenharmony_ci (long)(time % (int)1e6), 769a46c0ec8Sopenharmony_ci type, 770a46c0ec8Sopenharmony_ci libinput_event_gesture_get_finger_count(g), 771a46c0ec8Sopenharmony_ci libinput_event_gesture_get_dx(g), 772a46c0ec8Sopenharmony_ci libinput_event_gesture_get_dy(g), 773a46c0ec8Sopenharmony_ci libinput_event_gesture_get_dx_unaccelerated(g), 774a46c0ec8Sopenharmony_ci libinput_event_gesture_get_dy_unaccelerated(g) 775a46c0ec8Sopenharmony_ci ); 776a46c0ec8Sopenharmony_ci break; 777a46c0ec8Sopenharmony_ci default: 778a46c0ec8Sopenharmony_ci abort(); 779a46c0ec8Sopenharmony_ci } 780a46c0ec8Sopenharmony_ci} 781a46c0ec8Sopenharmony_ci 782a46c0ec8Sopenharmony_cistatic char * 783a46c0ec8Sopenharmony_cibuffer_tablet_axes(struct libinput_event_tablet_tool *t) 784a46c0ec8Sopenharmony_ci{ 785a46c0ec8Sopenharmony_ci const int MAX_AXES = 10; 786a46c0ec8Sopenharmony_ci struct libinput_tablet_tool *tool; 787a46c0ec8Sopenharmony_ci char *s = NULL; 788a46c0ec8Sopenharmony_ci int idx = 0; 789a46c0ec8Sopenharmony_ci int len; 790a46c0ec8Sopenharmony_ci double x, y; 791a46c0ec8Sopenharmony_ci char **strv; 792a46c0ec8Sopenharmony_ci 793a46c0ec8Sopenharmony_ci tool = libinput_event_tablet_tool_get_tool(t); 794a46c0ec8Sopenharmony_ci 795a46c0ec8Sopenharmony_ci strv = zalloc(MAX_AXES * sizeof *strv); 796a46c0ec8Sopenharmony_ci 797a46c0ec8Sopenharmony_ci x = libinput_event_tablet_tool_get_x(t); 798a46c0ec8Sopenharmony_ci y = libinput_event_tablet_tool_get_y(t); 799a46c0ec8Sopenharmony_ci len = xasprintf(&strv[idx++], "point: [%.2f, %.2f]", x, y); 800a46c0ec8Sopenharmony_ci if (len <= 0) 801a46c0ec8Sopenharmony_ci goto out; 802a46c0ec8Sopenharmony_ci 803a46c0ec8Sopenharmony_ci if (libinput_tablet_tool_has_tilt(tool)) { 804a46c0ec8Sopenharmony_ci x = libinput_event_tablet_tool_get_tilt_x(t); 805a46c0ec8Sopenharmony_ci y = libinput_event_tablet_tool_get_tilt_y(t); 806a46c0ec8Sopenharmony_ci len = xasprintf(&strv[idx++], "tilt: [%.2f, %.2f]", x, y); 807a46c0ec8Sopenharmony_ci if (len <= 0) 808a46c0ec8Sopenharmony_ci goto out; 809a46c0ec8Sopenharmony_ci } 810a46c0ec8Sopenharmony_ci 811a46c0ec8Sopenharmony_ci if (libinput_tablet_tool_has_distance(tool) || 812a46c0ec8Sopenharmony_ci libinput_tablet_tool_has_pressure(tool)) { 813a46c0ec8Sopenharmony_ci double dist, pressure; 814a46c0ec8Sopenharmony_ci 815a46c0ec8Sopenharmony_ci dist = libinput_event_tablet_tool_get_distance(t); 816a46c0ec8Sopenharmony_ci pressure = libinput_event_tablet_tool_get_pressure(t); 817a46c0ec8Sopenharmony_ci if (dist) 818a46c0ec8Sopenharmony_ci len = xasprintf(&strv[idx++], "distance: %.2f", dist); 819a46c0ec8Sopenharmony_ci else 820a46c0ec8Sopenharmony_ci len = xasprintf(&strv[idx++], "pressure: %.2f", pressure); 821a46c0ec8Sopenharmony_ci if (len <= 0) 822a46c0ec8Sopenharmony_ci goto out; 823a46c0ec8Sopenharmony_ci } 824a46c0ec8Sopenharmony_ci 825a46c0ec8Sopenharmony_ci if (libinput_tablet_tool_has_rotation(tool)) { 826a46c0ec8Sopenharmony_ci double rotation; 827a46c0ec8Sopenharmony_ci 828a46c0ec8Sopenharmony_ci rotation = libinput_event_tablet_tool_get_rotation(t); 829a46c0ec8Sopenharmony_ci len = xasprintf(&strv[idx++], "rotation: %.2f", rotation); 830a46c0ec8Sopenharmony_ci if (len <= 0) 831a46c0ec8Sopenharmony_ci goto out; 832a46c0ec8Sopenharmony_ci } 833a46c0ec8Sopenharmony_ci 834a46c0ec8Sopenharmony_ci if (libinput_tablet_tool_has_slider(tool)) { 835a46c0ec8Sopenharmony_ci double slider; 836a46c0ec8Sopenharmony_ci 837a46c0ec8Sopenharmony_ci slider = libinput_event_tablet_tool_get_slider_position(t); 838a46c0ec8Sopenharmony_ci len = xasprintf(&strv[idx++], "slider: %.2f", slider); 839a46c0ec8Sopenharmony_ci if (len <= 0) 840a46c0ec8Sopenharmony_ci goto out; 841a46c0ec8Sopenharmony_ci 842a46c0ec8Sopenharmony_ci } 843a46c0ec8Sopenharmony_ci 844a46c0ec8Sopenharmony_ci if (libinput_tablet_tool_has_wheel(tool)) { 845a46c0ec8Sopenharmony_ci double wheel; 846a46c0ec8Sopenharmony_ci int delta; 847a46c0ec8Sopenharmony_ci 848a46c0ec8Sopenharmony_ci wheel = libinput_event_tablet_tool_get_wheel_delta(t); 849a46c0ec8Sopenharmony_ci len = xasprintf(&strv[idx++], "wheel: %.2f", wheel); 850a46c0ec8Sopenharmony_ci if (len <= 0) 851a46c0ec8Sopenharmony_ci goto out; 852a46c0ec8Sopenharmony_ci 853a46c0ec8Sopenharmony_ci delta = libinput_event_tablet_tool_get_wheel_delta_discrete(t); 854a46c0ec8Sopenharmony_ci len = xasprintf(&strv[idx++], "wheel-discrete: %d", delta); 855a46c0ec8Sopenharmony_ci if (len <= 0) 856a46c0ec8Sopenharmony_ci goto out; 857a46c0ec8Sopenharmony_ci } 858a46c0ec8Sopenharmony_ci 859a46c0ec8Sopenharmony_ci assert(idx < MAX_AXES); 860a46c0ec8Sopenharmony_ci 861a46c0ec8Sopenharmony_ci s = strv_join(strv, ", "); 862a46c0ec8Sopenharmony_ciout: 863a46c0ec8Sopenharmony_ci strv_free(strv); 864a46c0ec8Sopenharmony_ci return s; 865a46c0ec8Sopenharmony_ci} 866a46c0ec8Sopenharmony_ci 867a46c0ec8Sopenharmony_cistatic void 868a46c0ec8Sopenharmony_ciprint_tablet_tool_proximity_event(struct record_device *dev, struct libinput_event *e) 869a46c0ec8Sopenharmony_ci{ 870a46c0ec8Sopenharmony_ci struct libinput_event_tablet_tool *t = 871a46c0ec8Sopenharmony_ci libinput_event_get_tablet_tool_event(e); 872a46c0ec8Sopenharmony_ci struct libinput_tablet_tool *tool = 873a46c0ec8Sopenharmony_ci libinput_event_tablet_tool_get_tool(t); 874a46c0ec8Sopenharmony_ci uint64_t time; 875a46c0ec8Sopenharmony_ci const char *type, *tool_type; 876a46c0ec8Sopenharmony_ci char *axes; 877a46c0ec8Sopenharmony_ci char caps[10] = {0}; 878a46c0ec8Sopenharmony_ci enum libinput_tablet_tool_proximity_state prox; 879a46c0ec8Sopenharmony_ci size_t idx; 880a46c0ec8Sopenharmony_ci 881a46c0ec8Sopenharmony_ci switch (libinput_event_get_type(e)) { 882a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY: 883a46c0ec8Sopenharmony_ci type = "TABLET_TOOL_PROXIMITY"; 884a46c0ec8Sopenharmony_ci break; 885a46c0ec8Sopenharmony_ci default: 886a46c0ec8Sopenharmony_ci abort(); 887a46c0ec8Sopenharmony_ci } 888a46c0ec8Sopenharmony_ci 889a46c0ec8Sopenharmony_ci switch (libinput_tablet_tool_get_type(tool)) { 890a46c0ec8Sopenharmony_ci case LIBINPUT_TABLET_TOOL_TYPE_PEN: 891a46c0ec8Sopenharmony_ci tool_type = "pen"; 892a46c0ec8Sopenharmony_ci break; 893a46c0ec8Sopenharmony_ci case LIBINPUT_TABLET_TOOL_TYPE_ERASER: 894a46c0ec8Sopenharmony_ci tool_type = "eraser"; 895a46c0ec8Sopenharmony_ci break; 896a46c0ec8Sopenharmony_ci case LIBINPUT_TABLET_TOOL_TYPE_BRUSH: 897a46c0ec8Sopenharmony_ci tool_type = "brush"; 898a46c0ec8Sopenharmony_ci break; 899a46c0ec8Sopenharmony_ci case LIBINPUT_TABLET_TOOL_TYPE_PENCIL: 900a46c0ec8Sopenharmony_ci tool_type = "brush"; 901a46c0ec8Sopenharmony_ci break; 902a46c0ec8Sopenharmony_ci case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH: 903a46c0ec8Sopenharmony_ci tool_type = "airbrush"; 904a46c0ec8Sopenharmony_ci break; 905a46c0ec8Sopenharmony_ci case LIBINPUT_TABLET_TOOL_TYPE_MOUSE: 906a46c0ec8Sopenharmony_ci tool_type = "mouse"; 907a46c0ec8Sopenharmony_ci break; 908a46c0ec8Sopenharmony_ci case LIBINPUT_TABLET_TOOL_TYPE_LENS: 909a46c0ec8Sopenharmony_ci tool_type = "lens"; 910a46c0ec8Sopenharmony_ci break; 911a46c0ec8Sopenharmony_ci default: 912a46c0ec8Sopenharmony_ci tool_type = "unknown"; 913a46c0ec8Sopenharmony_ci break; 914a46c0ec8Sopenharmony_ci } 915a46c0ec8Sopenharmony_ci 916a46c0ec8Sopenharmony_ci prox = libinput_event_tablet_tool_get_proximity_state(t); 917a46c0ec8Sopenharmony_ci time = time_offset(dev->ctx, libinput_event_tablet_tool_get_time_usec(t)); 918a46c0ec8Sopenharmony_ci axes = buffer_tablet_axes(t); 919a46c0ec8Sopenharmony_ci 920a46c0ec8Sopenharmony_ci idx = 0; 921a46c0ec8Sopenharmony_ci if (libinput_tablet_tool_has_pressure(tool)) 922a46c0ec8Sopenharmony_ci caps[idx++] = 'p'; 923a46c0ec8Sopenharmony_ci if (libinput_tablet_tool_has_distance(tool)) 924a46c0ec8Sopenharmony_ci caps[idx++] = 'd'; 925a46c0ec8Sopenharmony_ci if (libinput_tablet_tool_has_tilt(tool)) 926a46c0ec8Sopenharmony_ci caps[idx++] = 't'; 927a46c0ec8Sopenharmony_ci if (libinput_tablet_tool_has_rotation(tool)) 928a46c0ec8Sopenharmony_ci caps[idx++] = 'r'; 929a46c0ec8Sopenharmony_ci if (libinput_tablet_tool_has_slider(tool)) 930a46c0ec8Sopenharmony_ci caps[idx++] = 's'; 931a46c0ec8Sopenharmony_ci if (libinput_tablet_tool_has_wheel(tool)) 932a46c0ec8Sopenharmony_ci caps[idx++] = 'w'; 933a46c0ec8Sopenharmony_ci assert(idx <= ARRAY_LENGTH(caps)); 934a46c0ec8Sopenharmony_ci 935a46c0ec8Sopenharmony_ci iprintf(dev->fp, 936a46c0ec8Sopenharmony_ci I_EVENT, 937a46c0ec8Sopenharmony_ci "- {time: %ld.%06ld, type: %s, proximity: %s, tool-type: %s, serial: %" PRIu64 ", axes: %s, %s}\n", 938a46c0ec8Sopenharmony_ci (long)(time / (int)1e6), 939a46c0ec8Sopenharmony_ci (long)(time % (int)1e6), 940a46c0ec8Sopenharmony_ci type, 941a46c0ec8Sopenharmony_ci prox ? "in" : "out", 942a46c0ec8Sopenharmony_ci tool_type, 943a46c0ec8Sopenharmony_ci libinput_tablet_tool_get_serial(tool), 944a46c0ec8Sopenharmony_ci caps, 945a46c0ec8Sopenharmony_ci axes); 946a46c0ec8Sopenharmony_ci free(axes); 947a46c0ec8Sopenharmony_ci} 948a46c0ec8Sopenharmony_ci 949a46c0ec8Sopenharmony_cistatic void 950a46c0ec8Sopenharmony_ciprint_tablet_tool_button_event(struct record_device *dev, 951a46c0ec8Sopenharmony_ci struct libinput_event *e) 952a46c0ec8Sopenharmony_ci{ 953a46c0ec8Sopenharmony_ci struct libinput_event_tablet_tool *t = 954a46c0ec8Sopenharmony_ci libinput_event_get_tablet_tool_event(e); 955a46c0ec8Sopenharmony_ci uint64_t time; 956a46c0ec8Sopenharmony_ci const char *type; 957a46c0ec8Sopenharmony_ci uint32_t button; 958a46c0ec8Sopenharmony_ci enum libinput_button_state state; 959a46c0ec8Sopenharmony_ci 960a46c0ec8Sopenharmony_ci switch(libinput_event_get_type(e)) { 961a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_TOOL_BUTTON: 962a46c0ec8Sopenharmony_ci type = "TABLET_TOOL_BUTTON"; 963a46c0ec8Sopenharmony_ci break; 964a46c0ec8Sopenharmony_ci default: 965a46c0ec8Sopenharmony_ci abort(); 966a46c0ec8Sopenharmony_ci } 967a46c0ec8Sopenharmony_ci 968a46c0ec8Sopenharmony_ci button = libinput_event_tablet_tool_get_button(t); 969a46c0ec8Sopenharmony_ci state = libinput_event_tablet_tool_get_button_state(t); 970a46c0ec8Sopenharmony_ci time = time_offset(dev->ctx, libinput_event_tablet_tool_get_time_usec(t)); 971a46c0ec8Sopenharmony_ci 972a46c0ec8Sopenharmony_ci iprintf(dev->fp, 973a46c0ec8Sopenharmony_ci I_EVENT, 974a46c0ec8Sopenharmony_ci "- {time: %ld.%06ld, type: %s, button: %d, state: %s}\n", 975a46c0ec8Sopenharmony_ci (long)(time / (int)1e6), 976a46c0ec8Sopenharmony_ci (long)(time % (int)1e6), 977a46c0ec8Sopenharmony_ci type, 978a46c0ec8Sopenharmony_ci button, 979a46c0ec8Sopenharmony_ci state ? "pressed" : "released"); 980a46c0ec8Sopenharmony_ci} 981a46c0ec8Sopenharmony_ci 982a46c0ec8Sopenharmony_cistatic void 983a46c0ec8Sopenharmony_ciprint_tablet_tool_event(struct record_device *dev, struct libinput_event *e) 984a46c0ec8Sopenharmony_ci{ 985a46c0ec8Sopenharmony_ci struct libinput_event_tablet_tool *t = 986a46c0ec8Sopenharmony_ci libinput_event_get_tablet_tool_event(e); 987a46c0ec8Sopenharmony_ci uint64_t time; 988a46c0ec8Sopenharmony_ci const char *type; 989a46c0ec8Sopenharmony_ci char *axes; 990a46c0ec8Sopenharmony_ci enum libinput_tablet_tool_tip_state tip; 991a46c0ec8Sopenharmony_ci char btn_buffer[30] = {0}; 992a46c0ec8Sopenharmony_ci 993a46c0ec8Sopenharmony_ci switch(libinput_event_get_type(e)) { 994a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_TOOL_AXIS: 995a46c0ec8Sopenharmony_ci type = "TABLET_TOOL_AXIS"; 996a46c0ec8Sopenharmony_ci break; 997a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_TOOL_TIP: 998a46c0ec8Sopenharmony_ci type = "TABLET_TOOL_TIP"; 999a46c0ec8Sopenharmony_ci break; 1000a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_TOOL_BUTTON: 1001a46c0ec8Sopenharmony_ci type = "TABLET_TOOL_BUTTON"; 1002a46c0ec8Sopenharmony_ci break; 1003a46c0ec8Sopenharmony_ci default: 1004a46c0ec8Sopenharmony_ci abort(); 1005a46c0ec8Sopenharmony_ci } 1006a46c0ec8Sopenharmony_ci 1007a46c0ec8Sopenharmony_ci if (libinput_event_get_type(e) == LIBINPUT_EVENT_TABLET_TOOL_BUTTON) { 1008a46c0ec8Sopenharmony_ci uint32_t button; 1009a46c0ec8Sopenharmony_ci enum libinput_button_state state; 1010a46c0ec8Sopenharmony_ci 1011a46c0ec8Sopenharmony_ci button = libinput_event_tablet_tool_get_button(t); 1012a46c0ec8Sopenharmony_ci state = libinput_event_tablet_tool_get_button_state(t); 1013a46c0ec8Sopenharmony_ci snprintf(btn_buffer, sizeof(btn_buffer), 1014a46c0ec8Sopenharmony_ci ", button: %d, state: %s\n", 1015a46c0ec8Sopenharmony_ci button, 1016a46c0ec8Sopenharmony_ci state ? "pressed" : "released"); 1017a46c0ec8Sopenharmony_ci } 1018a46c0ec8Sopenharmony_ci 1019a46c0ec8Sopenharmony_ci tip = libinput_event_tablet_tool_get_tip_state(t); 1020a46c0ec8Sopenharmony_ci time = time_offset(dev->ctx, libinput_event_tablet_tool_get_time_usec(t)); 1021a46c0ec8Sopenharmony_ci axes = buffer_tablet_axes(t); 1022a46c0ec8Sopenharmony_ci 1023a46c0ec8Sopenharmony_ci iprintf(dev->fp, 1024a46c0ec8Sopenharmony_ci I_EVENT, 1025a46c0ec8Sopenharmony_ci "- {time: %ld.%06ld, type: %s%s, tip: %s, %s}\n", 1026a46c0ec8Sopenharmony_ci (long)(time / (int)1e6), 1027a46c0ec8Sopenharmony_ci (long)(time % (int)1e6), 1028a46c0ec8Sopenharmony_ci type, 1029a46c0ec8Sopenharmony_ci btn_buffer, /* may be empty string */ 1030a46c0ec8Sopenharmony_ci tip ? "down" : "up", 1031a46c0ec8Sopenharmony_ci axes); 1032a46c0ec8Sopenharmony_ci free(axes); 1033a46c0ec8Sopenharmony_ci} 1034a46c0ec8Sopenharmony_ci 1035a46c0ec8Sopenharmony_cistatic void 1036a46c0ec8Sopenharmony_ciprint_tablet_pad_button_event(struct record_device *dev, 1037a46c0ec8Sopenharmony_ci struct libinput_event *e) 1038a46c0ec8Sopenharmony_ci{ 1039a46c0ec8Sopenharmony_ci struct libinput_event_tablet_pad *p = 1040a46c0ec8Sopenharmony_ci libinput_event_get_tablet_pad_event(e); 1041a46c0ec8Sopenharmony_ci struct libinput_tablet_pad_mode_group *group; 1042a46c0ec8Sopenharmony_ci enum libinput_button_state state; 1043a46c0ec8Sopenharmony_ci unsigned int button, mode; 1044a46c0ec8Sopenharmony_ci const char *type; 1045a46c0ec8Sopenharmony_ci uint64_t time; 1046a46c0ec8Sopenharmony_ci 1047a46c0ec8Sopenharmony_ci switch(libinput_event_get_type(e)) { 1048a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_PAD_BUTTON: 1049a46c0ec8Sopenharmony_ci type = "TABLET_PAD_BUTTON"; 1050a46c0ec8Sopenharmony_ci break; 1051a46c0ec8Sopenharmony_ci default: 1052a46c0ec8Sopenharmony_ci abort(); 1053a46c0ec8Sopenharmony_ci } 1054a46c0ec8Sopenharmony_ci 1055a46c0ec8Sopenharmony_ci time = time_offset(dev->ctx, libinput_event_tablet_pad_get_time_usec(p)); 1056a46c0ec8Sopenharmony_ci button = libinput_event_tablet_pad_get_button_number(p), 1057a46c0ec8Sopenharmony_ci state = libinput_event_tablet_pad_get_button_state(p); 1058a46c0ec8Sopenharmony_ci mode = libinput_event_tablet_pad_get_mode(p); 1059a46c0ec8Sopenharmony_ci group = libinput_event_tablet_pad_get_mode_group(p); 1060a46c0ec8Sopenharmony_ci 1061a46c0ec8Sopenharmony_ci iprintf(dev->fp, 1062a46c0ec8Sopenharmony_ci I_EVENT, 1063a46c0ec8Sopenharmony_ci "- {time: %ld.%06ld, type: %s, button: %d, state: %s, mode: %d, is-toggle: %s}\n", 1064a46c0ec8Sopenharmony_ci (long)(time / (int)1e6), 1065a46c0ec8Sopenharmony_ci (long)(time % (int)1e6), 1066a46c0ec8Sopenharmony_ci type, 1067a46c0ec8Sopenharmony_ci button, 1068a46c0ec8Sopenharmony_ci state == LIBINPUT_BUTTON_STATE_PRESSED ? "pressed" : "released", 1069a46c0ec8Sopenharmony_ci mode, 1070a46c0ec8Sopenharmony_ci libinput_tablet_pad_mode_group_button_is_toggle(group, button) ? "true" : "false" 1071a46c0ec8Sopenharmony_ci ); 1072a46c0ec8Sopenharmony_ci 1073a46c0ec8Sopenharmony_ci} 1074a46c0ec8Sopenharmony_ci 1075a46c0ec8Sopenharmony_cistatic void 1076a46c0ec8Sopenharmony_ciprint_tablet_pad_ringstrip_event(struct record_device *dev, struct libinput_event *e) 1077a46c0ec8Sopenharmony_ci{ 1078a46c0ec8Sopenharmony_ci struct libinput_event_tablet_pad *p = 1079a46c0ec8Sopenharmony_ci libinput_event_get_tablet_pad_event(e); 1080a46c0ec8Sopenharmony_ci const char *source = NULL; 1081a46c0ec8Sopenharmony_ci unsigned int mode, number; 1082a46c0ec8Sopenharmony_ci const char *type; 1083a46c0ec8Sopenharmony_ci uint64_t time; 1084a46c0ec8Sopenharmony_ci double pos; 1085a46c0ec8Sopenharmony_ci 1086a46c0ec8Sopenharmony_ci switch(libinput_event_get_type(e)) { 1087a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_PAD_RING: 1088a46c0ec8Sopenharmony_ci type = "TABLET_PAD_RING"; 1089a46c0ec8Sopenharmony_ci number = libinput_event_tablet_pad_get_ring_number(p); 1090a46c0ec8Sopenharmony_ci pos = libinput_event_tablet_pad_get_ring_position(p); 1091a46c0ec8Sopenharmony_ci 1092a46c0ec8Sopenharmony_ci switch (libinput_event_tablet_pad_get_ring_source(p)) { 1093a46c0ec8Sopenharmony_ci case LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER: 1094a46c0ec8Sopenharmony_ci source = "finger"; 1095a46c0ec8Sopenharmony_ci break; 1096a46c0ec8Sopenharmony_ci case LIBINPUT_TABLET_PAD_RING_SOURCE_UNKNOWN: 1097a46c0ec8Sopenharmony_ci source = "unknown"; 1098a46c0ec8Sopenharmony_ci break; 1099a46c0ec8Sopenharmony_ci } 1100a46c0ec8Sopenharmony_ci break; 1101a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_PAD_STRIP: 1102a46c0ec8Sopenharmony_ci type = "TABLET_PAD_STRIP"; 1103a46c0ec8Sopenharmony_ci number = libinput_event_tablet_pad_get_strip_number(p); 1104a46c0ec8Sopenharmony_ci pos = libinput_event_tablet_pad_get_strip_position(p); 1105a46c0ec8Sopenharmony_ci 1106a46c0ec8Sopenharmony_ci switch (libinput_event_tablet_pad_get_strip_source(p)) { 1107a46c0ec8Sopenharmony_ci case LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER: 1108a46c0ec8Sopenharmony_ci source = "finger"; 1109a46c0ec8Sopenharmony_ci break; 1110a46c0ec8Sopenharmony_ci case LIBINPUT_TABLET_PAD_STRIP_SOURCE_UNKNOWN: 1111a46c0ec8Sopenharmony_ci source = "unknown"; 1112a46c0ec8Sopenharmony_ci break; 1113a46c0ec8Sopenharmony_ci } 1114a46c0ec8Sopenharmony_ci break; 1115a46c0ec8Sopenharmony_ci default: 1116a46c0ec8Sopenharmony_ci abort(); 1117a46c0ec8Sopenharmony_ci } 1118a46c0ec8Sopenharmony_ci 1119a46c0ec8Sopenharmony_ci time = time_offset(dev->ctx, libinput_event_tablet_pad_get_time_usec(p)); 1120a46c0ec8Sopenharmony_ci mode = libinput_event_tablet_pad_get_mode(p); 1121a46c0ec8Sopenharmony_ci 1122a46c0ec8Sopenharmony_ci iprintf(dev->fp, 1123a46c0ec8Sopenharmony_ci I_EVENT, 1124a46c0ec8Sopenharmony_ci "- {time: %ld.%06ld, type: %s, number: %d, position: %.2f, source: %s, mode: %d}\n", 1125a46c0ec8Sopenharmony_ci (long)(time / (int)1e6), 1126a46c0ec8Sopenharmony_ci (long)(time % (int)1e6), 1127a46c0ec8Sopenharmony_ci type, 1128a46c0ec8Sopenharmony_ci number, 1129a46c0ec8Sopenharmony_ci pos, 1130a46c0ec8Sopenharmony_ci source, 1131a46c0ec8Sopenharmony_ci mode); 1132a46c0ec8Sopenharmony_ci} 1133a46c0ec8Sopenharmony_ci 1134a46c0ec8Sopenharmony_cistatic void 1135a46c0ec8Sopenharmony_ciprint_switch_event(struct record_device *dev, struct libinput_event *e) 1136a46c0ec8Sopenharmony_ci{ 1137a46c0ec8Sopenharmony_ci struct libinput_event_switch *s = libinput_event_get_switch_event(e); 1138a46c0ec8Sopenharmony_ci enum libinput_switch_state state; 1139a46c0ec8Sopenharmony_ci uint32_t sw; 1140a46c0ec8Sopenharmony_ci const char *type; 1141a46c0ec8Sopenharmony_ci uint64_t time; 1142a46c0ec8Sopenharmony_ci 1143a46c0ec8Sopenharmony_ci switch(libinput_event_get_type(e)) { 1144a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_SWITCH_TOGGLE: 1145a46c0ec8Sopenharmony_ci type = "SWITCH_TOGGLE"; 1146a46c0ec8Sopenharmony_ci break; 1147a46c0ec8Sopenharmony_ci default: 1148a46c0ec8Sopenharmony_ci abort(); 1149a46c0ec8Sopenharmony_ci } 1150a46c0ec8Sopenharmony_ci 1151a46c0ec8Sopenharmony_ci time = time_offset(dev->ctx, libinput_event_switch_get_time_usec(s)); 1152a46c0ec8Sopenharmony_ci sw = libinput_event_switch_get_switch(s); 1153a46c0ec8Sopenharmony_ci state = libinput_event_switch_get_switch_state(s); 1154a46c0ec8Sopenharmony_ci 1155a46c0ec8Sopenharmony_ci iprintf(dev->fp, 1156a46c0ec8Sopenharmony_ci I_EVENT, 1157a46c0ec8Sopenharmony_ci "- {time: %ld.%06ld, type: %s, switch: %d, state: %s}\n", 1158a46c0ec8Sopenharmony_ci (long)(time / (int)1e6), 1159a46c0ec8Sopenharmony_ci (long)(time % (int)1e6), 1160a46c0ec8Sopenharmony_ci type, 1161a46c0ec8Sopenharmony_ci sw, 1162a46c0ec8Sopenharmony_ci state == LIBINPUT_SWITCH_STATE_ON ? "on" : "off"); 1163a46c0ec8Sopenharmony_ci} 1164a46c0ec8Sopenharmony_ci 1165a46c0ec8Sopenharmony_cistatic void 1166a46c0ec8Sopenharmony_ciprint_libinput_event(struct record_device *dev, struct libinput_event *e) 1167a46c0ec8Sopenharmony_ci{ 1168a46c0ec8Sopenharmony_ci switch (libinput_event_get_type(e)) { 1169a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_NONE: 1170a46c0ec8Sopenharmony_ci abort(); 1171a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_DEVICE_ADDED: 1172a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_DEVICE_REMOVED: 1173a46c0ec8Sopenharmony_ci print_device_notify(dev, e); 1174a46c0ec8Sopenharmony_ci break; 1175a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_KEYBOARD_KEY: 1176a46c0ec8Sopenharmony_ci print_key_event(dev, e); 1177a46c0ec8Sopenharmony_ci break; 1178a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_POINTER_MOTION: 1179a46c0ec8Sopenharmony_ci print_motion_event(dev, e); 1180a46c0ec8Sopenharmony_ci break; 1181a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: 1182a46c0ec8Sopenharmony_ci print_absmotion_event(dev, e); 1183a46c0ec8Sopenharmony_ci break; 1184a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_POINTER_BUTTON: 1185a46c0ec8Sopenharmony_ci print_pointer_button_event(dev, e); 1186a46c0ec8Sopenharmony_ci break; 1187a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_POINTER_AXIS: 1188a46c0ec8Sopenharmony_ci print_pointer_axis_event(dev, e); 1189a46c0ec8Sopenharmony_ci break; 1190a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_DOWN: 1191a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_UP: 1192a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_MOTION: 1193a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_CANCEL: 1194a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TOUCH_FRAME: 1195a46c0ec8Sopenharmony_ci print_touch_event(dev, e); 1196a46c0ec8Sopenharmony_ci break; 1197a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: 1198a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: 1199a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_PINCH_END: 1200a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: 1201a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: 1202a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_GESTURE_SWIPE_END: 1203a46c0ec8Sopenharmony_ci print_gesture_event(dev, e); 1204a46c0ec8Sopenharmony_ci break; 1205a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY: 1206a46c0ec8Sopenharmony_ci print_tablet_tool_proximity_event(dev, e); 1207a46c0ec8Sopenharmony_ci break; 1208a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_TOOL_AXIS: 1209a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_TOOL_TIP: 1210a46c0ec8Sopenharmony_ci print_tablet_tool_event(dev, e); 1211a46c0ec8Sopenharmony_ci break; 1212a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_TOOL_BUTTON: 1213a46c0ec8Sopenharmony_ci print_tablet_tool_button_event(dev, e); 1214a46c0ec8Sopenharmony_ci break; 1215a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_PAD_BUTTON: 1216a46c0ec8Sopenharmony_ci print_tablet_pad_button_event(dev, e); 1217a46c0ec8Sopenharmony_ci break; 1218a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_PAD_RING: 1219a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_TABLET_PAD_STRIP: 1220a46c0ec8Sopenharmony_ci print_tablet_pad_ringstrip_event(dev, e); 1221a46c0ec8Sopenharmony_ci break; 1222a46c0ec8Sopenharmony_ci case LIBINPUT_EVENT_SWITCH_TOGGLE: 1223a46c0ec8Sopenharmony_ci print_switch_event(dev, e); 1224a46c0ec8Sopenharmony_ci break; 1225a46c0ec8Sopenharmony_ci default: 1226a46c0ec8Sopenharmony_ci break; 1227a46c0ec8Sopenharmony_ci } 1228a46c0ec8Sopenharmony_ci} 1229a46c0ec8Sopenharmony_ci 1230a46c0ec8Sopenharmony_cistatic bool 1231a46c0ec8Sopenharmony_cihandle_hidraw(struct hidraw *hidraw) 1232a46c0ec8Sopenharmony_ci{ 1233a46c0ec8Sopenharmony_ci struct record_device *d = hidraw->device; 1234a46c0ec8Sopenharmony_ci unsigned char report[4096]; 1235a46c0ec8Sopenharmony_ci const char *sep = ""; 1236a46c0ec8Sopenharmony_ci struct timespec ts; 1237a46c0ec8Sopenharmony_ci struct timeval tv; 1238a46c0ec8Sopenharmony_ci uint64_t time; 1239a46c0ec8Sopenharmony_ci 1240a46c0ec8Sopenharmony_ci int rc = read(hidraw->fd, report, sizeof(report)); 1241a46c0ec8Sopenharmony_ci if (rc <= 0) 1242a46c0ec8Sopenharmony_ci return false; 1243a46c0ec8Sopenharmony_ci 1244a46c0ec8Sopenharmony_ci /* hidraw doesn't give us a timestamps, we have to make them up */ 1245a46c0ec8Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &ts); 1246a46c0ec8Sopenharmony_ci time = s2us(ts.tv_sec) + ns2us(ts.tv_nsec); 1247a46c0ec8Sopenharmony_ci 1248a46c0ec8Sopenharmony_ci /* The first evdev event is guaranteed to have an event time earlier 1249a46c0ec8Sopenharmony_ci than now, so we don't set the offset here, we rely on the evdev 1250a46c0ec8Sopenharmony_ci events to do so. This potentially leaves us with multiple hidraw 1251a46c0ec8Sopenharmony_ci events at timestap 0 but it's too niche to worry about. */ 1252a46c0ec8Sopenharmony_ci if (d->ctx->offset == 0) 1253a46c0ec8Sopenharmony_ci time = 0; 1254a46c0ec8Sopenharmony_ci else 1255a46c0ec8Sopenharmony_ci time = time_offset(d->ctx, time); 1256a46c0ec8Sopenharmony_ci 1257a46c0ec8Sopenharmony_ci tv = us2tv(time); 1258a46c0ec8Sopenharmony_ci 1259a46c0ec8Sopenharmony_ci iprintf(d->fp, I_EVENTTYPE, "- hid:\n"); 1260a46c0ec8Sopenharmony_ci iprintf(d->fp, I_EVENT, "time: [%3lu, %6lu]\n", tv.tv_sec, tv.tv_usec); 1261a46c0ec8Sopenharmony_ci iprintf(d->fp, I_EVENT, "%s: [", hidraw->name); 1262a46c0ec8Sopenharmony_ci 1263a46c0ec8Sopenharmony_ci for (int byte = 0; byte < rc; byte++) { 1264a46c0ec8Sopenharmony_ci if (byte % 16 == 0) { 1265a46c0ec8Sopenharmony_ci iprintf(d->fp, I_NONE, "%s\n", sep); 1266a46c0ec8Sopenharmony_ci iprintf(d->fp, I_EVENT, " "); 1267a46c0ec8Sopenharmony_ci iprintf(d->fp, I_NONE, "0x%02x", report[byte]); 1268a46c0ec8Sopenharmony_ci } else { 1269a46c0ec8Sopenharmony_ci iprintf(d->fp, I_NONE, "%s0x%02x", sep, report[byte]); 1270a46c0ec8Sopenharmony_ci } 1271a46c0ec8Sopenharmony_ci sep = ", "; 1272a46c0ec8Sopenharmony_ci } 1273a46c0ec8Sopenharmony_ci iprintf(d->fp, I_NONE, "\n"); 1274a46c0ec8Sopenharmony_ci iprintf(d->fp, I_EVENT, "]\n"); 1275a46c0ec8Sopenharmony_ci 1276a46c0ec8Sopenharmony_ci return true; 1277a46c0ec8Sopenharmony_ci} 1278a46c0ec8Sopenharmony_ci 1279a46c0ec8Sopenharmony_cistatic bool 1280a46c0ec8Sopenharmony_cihandle_libinput_events(struct record_context *ctx, 1281a46c0ec8Sopenharmony_ci struct record_device *d, 1282a46c0ec8Sopenharmony_ci bool start_frame) 1283a46c0ec8Sopenharmony_ci{ 1284a46c0ec8Sopenharmony_ci struct libinput_event *e; 1285a46c0ec8Sopenharmony_ci struct record_device *current = d; 1286a46c0ec8Sopenharmony_ci 1287a46c0ec8Sopenharmony_ci libinput_dispatch(ctx->libinput); 1288a46c0ec8Sopenharmony_ci e = libinput_get_event(ctx->libinput); 1289a46c0ec8Sopenharmony_ci if (!e) 1290a46c0ec8Sopenharmony_ci return false; 1291a46c0ec8Sopenharmony_ci 1292a46c0ec8Sopenharmony_ci if (start_frame) 1293a46c0ec8Sopenharmony_ci iprintf(d->fp, I_EVENTTYPE, "- libinput:\n"); 1294a46c0ec8Sopenharmony_ci else 1295a46c0ec8Sopenharmony_ci iprintf(d->fp, I_EVENTTYPE, "libinput:\n"); 1296a46c0ec8Sopenharmony_ci do { 1297a46c0ec8Sopenharmony_ci struct libinput_device *device = libinput_event_get_device(e); 1298a46c0ec8Sopenharmony_ci 1299a46c0ec8Sopenharmony_ci if (device != current->device) { 1300a46c0ec8Sopenharmony_ci struct record_device *tmp; 1301a46c0ec8Sopenharmony_ci bool found = false; 1302a46c0ec8Sopenharmony_ci list_for_each(tmp, &ctx->devices, link) { 1303a46c0ec8Sopenharmony_ci if (device == tmp->device) { 1304a46c0ec8Sopenharmony_ci current = tmp; 1305a46c0ec8Sopenharmony_ci found = true; 1306a46c0ec8Sopenharmony_ci break; 1307a46c0ec8Sopenharmony_ci } 1308a46c0ec8Sopenharmony_ci } 1309a46c0ec8Sopenharmony_ci assert(found); 1310a46c0ec8Sopenharmony_ci } 1311a46c0ec8Sopenharmony_ci 1312a46c0ec8Sopenharmony_ci print_libinput_event(current, e); 1313a46c0ec8Sopenharmony_ci libinput_event_destroy(e); 1314a46c0ec8Sopenharmony_ci } while ((e = libinput_get_event(ctx->libinput)) != NULL); 1315a46c0ec8Sopenharmony_ci 1316a46c0ec8Sopenharmony_ci return true; 1317a46c0ec8Sopenharmony_ci} 1318a46c0ec8Sopenharmony_ci 1319a46c0ec8Sopenharmony_cistatic void 1320a46c0ec8Sopenharmony_cihandle_events(struct record_context *ctx, struct record_device *d) 1321a46c0ec8Sopenharmony_ci{ 1322a46c0ec8Sopenharmony_ci bool has_events = true; 1323a46c0ec8Sopenharmony_ci 1324a46c0ec8Sopenharmony_ci while (has_events) { 1325a46c0ec8Sopenharmony_ci has_events = handle_evdev_frame(d); 1326a46c0ec8Sopenharmony_ci 1327a46c0ec8Sopenharmony_ci if (ctx->libinput) 1328a46c0ec8Sopenharmony_ci has_events |= handle_libinput_events(ctx, 1329a46c0ec8Sopenharmony_ci d, 1330a46c0ec8Sopenharmony_ci !has_events); 1331a46c0ec8Sopenharmony_ci } 1332a46c0ec8Sopenharmony_ci 1333a46c0ec8Sopenharmony_ci fflush(d->fp); 1334a46c0ec8Sopenharmony_ci} 1335a46c0ec8Sopenharmony_ci 1336a46c0ec8Sopenharmony_cistatic void 1337a46c0ec8Sopenharmony_ciprint_libinput_header(FILE *fp, int timeout) 1338a46c0ec8Sopenharmony_ci{ 1339a46c0ec8Sopenharmony_ci iprintf(fp, I_TOPLEVEL, "libinput:\n"); 1340a46c0ec8Sopenharmony_ci iprintf(fp, I_LIBINPUT, "version: \"%s\"\n", LIBINPUT_VERSION); 1341a46c0ec8Sopenharmony_ci iprintf(fp, I_LIBINPUT, "git: \"%s\"\n", LIBINPUT_GIT_VERSION); 1342a46c0ec8Sopenharmony_ci if (timeout > 0) 1343a46c0ec8Sopenharmony_ci iprintf(fp, I_LIBINPUT, "autorestart: %d\n", timeout); 1344a46c0ec8Sopenharmony_ci} 1345a46c0ec8Sopenharmony_ci 1346a46c0ec8Sopenharmony_cistatic void 1347a46c0ec8Sopenharmony_ciprint_system_header(FILE *fp) 1348a46c0ec8Sopenharmony_ci{ 1349a46c0ec8Sopenharmony_ci struct utsname u; 1350a46c0ec8Sopenharmony_ci const char *kernel = "unknown"; 1351a46c0ec8Sopenharmony_ci FILE *dmi, *osrelease; 1352a46c0ec8Sopenharmony_ci char dmistr[2048] = "unknown"; 1353a46c0ec8Sopenharmony_ci 1354a46c0ec8Sopenharmony_ci iprintf(fp, I_TOPLEVEL, "system:\n"); 1355a46c0ec8Sopenharmony_ci 1356a46c0ec8Sopenharmony_ci /* /etc/os-release version and distribution name */ 1357a46c0ec8Sopenharmony_ci osrelease = fopen("/etc/os-release", "r"); 1358a46c0ec8Sopenharmony_ci if (!osrelease) 1359a46c0ec8Sopenharmony_ci osrelease = fopen("/usr/lib/os-release", "r"); 1360a46c0ec8Sopenharmony_ci if (osrelease) { 1361a46c0ec8Sopenharmony_ci char *distro = NULL, *version = NULL; 1362a46c0ec8Sopenharmony_ci char osrstr[256] = "unknown"; 1363a46c0ec8Sopenharmony_ci 1364a46c0ec8Sopenharmony_ci while (fgets(osrstr, sizeof(osrstr), osrelease)) { 1365a46c0ec8Sopenharmony_ci osrstr[strlen(osrstr) - 1] = '\0'; /* linebreak */ 1366a46c0ec8Sopenharmony_ci 1367a46c0ec8Sopenharmony_ci if (!distro && strneq(osrstr, "ID=", 3)) 1368a46c0ec8Sopenharmony_ci distro = strstrip(&osrstr[3], "\"'"); 1369a46c0ec8Sopenharmony_ci else if (!version && strneq(osrstr, "VERSION_ID=", 11)) 1370a46c0ec8Sopenharmony_ci version = strstrip(&osrstr[11], "\"'"); 1371a46c0ec8Sopenharmony_ci 1372a46c0ec8Sopenharmony_ci if (distro && version) { 1373a46c0ec8Sopenharmony_ci iprintf(fp, 1374a46c0ec8Sopenharmony_ci I_SYSTEM, 1375a46c0ec8Sopenharmony_ci "os: \"%s:%s\"\n", 1376a46c0ec8Sopenharmony_ci distro, 1377a46c0ec8Sopenharmony_ci version); 1378a46c0ec8Sopenharmony_ci break; 1379a46c0ec8Sopenharmony_ci } 1380a46c0ec8Sopenharmony_ci } 1381a46c0ec8Sopenharmony_ci free(distro); 1382a46c0ec8Sopenharmony_ci free(version); 1383a46c0ec8Sopenharmony_ci fclose(osrelease); 1384a46c0ec8Sopenharmony_ci } 1385a46c0ec8Sopenharmony_ci 1386a46c0ec8Sopenharmony_ci /* kernel version */ 1387a46c0ec8Sopenharmony_ci if (uname(&u) != -1) 1388a46c0ec8Sopenharmony_ci kernel = u.release; 1389a46c0ec8Sopenharmony_ci iprintf(fp, I_SYSTEM, "kernel: \"%s\"\n", kernel); 1390a46c0ec8Sopenharmony_ci 1391a46c0ec8Sopenharmony_ci /* dmi modalias */ 1392a46c0ec8Sopenharmony_ci dmi = fopen("/sys/class/dmi/id/modalias", "r"); 1393a46c0ec8Sopenharmony_ci if (dmi) { 1394a46c0ec8Sopenharmony_ci if (fgets(dmistr, sizeof(dmistr), dmi)) { 1395a46c0ec8Sopenharmony_ci dmistr[strlen(dmistr) - 1] = '\0'; /* linebreak */ 1396a46c0ec8Sopenharmony_ci } else { 1397a46c0ec8Sopenharmony_ci sprintf(dmistr, "unknown"); 1398a46c0ec8Sopenharmony_ci } 1399a46c0ec8Sopenharmony_ci fclose(dmi); 1400a46c0ec8Sopenharmony_ci } 1401a46c0ec8Sopenharmony_ci iprintf(fp, I_SYSTEM, "dmi: \"%s\"\n", dmistr); 1402a46c0ec8Sopenharmony_ci} 1403a46c0ec8Sopenharmony_ci 1404a46c0ec8Sopenharmony_cistatic void 1405a46c0ec8Sopenharmony_ciprint_header(FILE *fp, struct record_context *ctx) 1406a46c0ec8Sopenharmony_ci{ 1407a46c0ec8Sopenharmony_ci iprintf(fp, I_TOPLEVEL, "# libinput record\n"); 1408a46c0ec8Sopenharmony_ci iprintf(fp, I_TOPLEVEL, "version: %d\n", FILE_VERSION_NUMBER); 1409a46c0ec8Sopenharmony_ci iprintf(fp, I_TOPLEVEL, "ndevices: %d\n", ctx->ndevices); 1410a46c0ec8Sopenharmony_ci print_libinput_header(fp, ctx->timeout); 1411a46c0ec8Sopenharmony_ci print_system_header(fp); 1412a46c0ec8Sopenharmony_ci} 1413a46c0ec8Sopenharmony_ci 1414a46c0ec8Sopenharmony_cistatic void 1415a46c0ec8Sopenharmony_ciprint_description_abs(FILE *fp, 1416a46c0ec8Sopenharmony_ci struct libevdev *dev, 1417a46c0ec8Sopenharmony_ci unsigned int code) 1418a46c0ec8Sopenharmony_ci{ 1419a46c0ec8Sopenharmony_ci const struct input_absinfo *abs; 1420a46c0ec8Sopenharmony_ci 1421a46c0ec8Sopenharmony_ci abs = libevdev_get_abs_info(dev, code); 1422a46c0ec8Sopenharmony_ci assert(abs); 1423a46c0ec8Sopenharmony_ci 1424a46c0ec8Sopenharmony_ci iprintf(fp, I_EVDEV, "# Value %6d\n", abs->value); 1425a46c0ec8Sopenharmony_ci iprintf(fp, I_EVDEV, "# Min %6d\n", abs->minimum); 1426a46c0ec8Sopenharmony_ci iprintf(fp, I_EVDEV, "# Max %6d\n", abs->maximum); 1427a46c0ec8Sopenharmony_ci iprintf(fp, I_EVDEV, "# Fuzz %6d\n", abs->fuzz); 1428a46c0ec8Sopenharmony_ci iprintf(fp, I_EVDEV, "# Flat %6d\n", abs->flat); 1429a46c0ec8Sopenharmony_ci iprintf(fp, I_EVDEV, "# Resolution %6d\n", abs->resolution); 1430a46c0ec8Sopenharmony_ci} 1431a46c0ec8Sopenharmony_ci 1432a46c0ec8Sopenharmony_cistatic void 1433a46c0ec8Sopenharmony_ciprint_description_state(FILE *fp, 1434a46c0ec8Sopenharmony_ci struct libevdev *dev, 1435a46c0ec8Sopenharmony_ci unsigned int type, 1436a46c0ec8Sopenharmony_ci unsigned int code) 1437a46c0ec8Sopenharmony_ci{ 1438a46c0ec8Sopenharmony_ci int state = libevdev_get_event_value(dev, type, code); 1439a46c0ec8Sopenharmony_ci iprintf(fp, I_EVDEV, "# State %d\n", state); 1440a46c0ec8Sopenharmony_ci} 1441a46c0ec8Sopenharmony_ci 1442a46c0ec8Sopenharmony_cistatic void 1443a46c0ec8Sopenharmony_ciprint_description_codes(FILE *fp, 1444a46c0ec8Sopenharmony_ci struct libevdev *dev, 1445a46c0ec8Sopenharmony_ci unsigned int type) 1446a46c0ec8Sopenharmony_ci{ 1447a46c0ec8Sopenharmony_ci int max; 1448a46c0ec8Sopenharmony_ci 1449a46c0ec8Sopenharmony_ci max = libevdev_event_type_get_max(type); 1450a46c0ec8Sopenharmony_ci if (max == -1) 1451a46c0ec8Sopenharmony_ci return; 1452a46c0ec8Sopenharmony_ci 1453a46c0ec8Sopenharmony_ci iprintf(fp, 1454a46c0ec8Sopenharmony_ci I_EVDEV, 1455a46c0ec8Sopenharmony_ci "# Event type %d (%s)\n", 1456a46c0ec8Sopenharmony_ci type, 1457a46c0ec8Sopenharmony_ci libevdev_event_type_get_name(type)); 1458a46c0ec8Sopenharmony_ci 1459a46c0ec8Sopenharmony_ci if (type == EV_SYN) 1460a46c0ec8Sopenharmony_ci return; 1461a46c0ec8Sopenharmony_ci 1462a46c0ec8Sopenharmony_ci for (unsigned int code = 0; code <= (unsigned int)max; code++) { 1463a46c0ec8Sopenharmony_ci if (!libevdev_has_event_code(dev, type, code)) 1464a46c0ec8Sopenharmony_ci continue; 1465a46c0ec8Sopenharmony_ci 1466a46c0ec8Sopenharmony_ci iprintf(fp, 1467a46c0ec8Sopenharmony_ci I_EVDEV, 1468a46c0ec8Sopenharmony_ci "# Event code %d (%s)\n", 1469a46c0ec8Sopenharmony_ci code, 1470a46c0ec8Sopenharmony_ci libevdev_event_code_get_name(type, 1471a46c0ec8Sopenharmony_ci code)); 1472a46c0ec8Sopenharmony_ci 1473a46c0ec8Sopenharmony_ci switch (type) { 1474a46c0ec8Sopenharmony_ci case EV_ABS: 1475a46c0ec8Sopenharmony_ci print_description_abs(fp, dev, code); 1476a46c0ec8Sopenharmony_ci break; 1477a46c0ec8Sopenharmony_ci case EV_LED: 1478a46c0ec8Sopenharmony_ci case EV_SW: 1479a46c0ec8Sopenharmony_ci print_description_state(fp, dev, type, code); 1480a46c0ec8Sopenharmony_ci break; 1481a46c0ec8Sopenharmony_ci } 1482a46c0ec8Sopenharmony_ci } 1483a46c0ec8Sopenharmony_ci} 1484a46c0ec8Sopenharmony_ci 1485a46c0ec8Sopenharmony_cistatic void 1486a46c0ec8Sopenharmony_ciprint_description(FILE *fp, struct libevdev *dev) 1487a46c0ec8Sopenharmony_ci{ 1488a46c0ec8Sopenharmony_ci const struct input_absinfo *x, *y; 1489a46c0ec8Sopenharmony_ci int bustype; 1490a46c0ec8Sopenharmony_ci const char *busname; 1491a46c0ec8Sopenharmony_ci 1492a46c0ec8Sopenharmony_ci bustype = libevdev_get_id_bustype(dev); 1493a46c0ec8Sopenharmony_ci switch (bustype) { 1494a46c0ec8Sopenharmony_ci case BUS_USB: 1495a46c0ec8Sopenharmony_ci busname = " (usb) "; 1496a46c0ec8Sopenharmony_ci break; 1497a46c0ec8Sopenharmony_ci case BUS_BLUETOOTH: 1498a46c0ec8Sopenharmony_ci busname = " (bluetooth) "; 1499a46c0ec8Sopenharmony_ci break; 1500a46c0ec8Sopenharmony_ci case BUS_I2C: 1501a46c0ec8Sopenharmony_ci busname = " (i2c) "; 1502a46c0ec8Sopenharmony_ci break; 1503a46c0ec8Sopenharmony_ci case BUS_SPI: 1504a46c0ec8Sopenharmony_ci busname = " (spi) "; 1505a46c0ec8Sopenharmony_ci break; 1506a46c0ec8Sopenharmony_ci case BUS_RMI: 1507a46c0ec8Sopenharmony_ci busname = " (rmi) "; 1508a46c0ec8Sopenharmony_ci break; 1509a46c0ec8Sopenharmony_ci default: 1510a46c0ec8Sopenharmony_ci busname = " "; 1511a46c0ec8Sopenharmony_ci break; 1512a46c0ec8Sopenharmony_ci } 1513a46c0ec8Sopenharmony_ci 1514a46c0ec8Sopenharmony_ci iprintf(fp, I_EVDEV, "# Name: %s\n", libevdev_get_name(dev)); 1515a46c0ec8Sopenharmony_ci iprintf(fp, 1516a46c0ec8Sopenharmony_ci I_EVDEV, 1517a46c0ec8Sopenharmony_ci "# ID: bus 0x%04x%svendor 0x%04x product 0x%04x version 0x%04x\n", 1518a46c0ec8Sopenharmony_ci bustype, 1519a46c0ec8Sopenharmony_ci busname, 1520a46c0ec8Sopenharmony_ci libevdev_get_id_vendor(dev), 1521a46c0ec8Sopenharmony_ci libevdev_get_id_product(dev), 1522a46c0ec8Sopenharmony_ci libevdev_get_id_version(dev)); 1523a46c0ec8Sopenharmony_ci 1524a46c0ec8Sopenharmony_ci x = libevdev_get_abs_info(dev, ABS_X); 1525a46c0ec8Sopenharmony_ci y = libevdev_get_abs_info(dev, ABS_Y); 1526a46c0ec8Sopenharmony_ci if (x && y) { 1527a46c0ec8Sopenharmony_ci if (x->resolution && y->resolution) { 1528a46c0ec8Sopenharmony_ci int w, h; 1529a46c0ec8Sopenharmony_ci 1530a46c0ec8Sopenharmony_ci w = (x->maximum - x->minimum)/x->resolution; 1531a46c0ec8Sopenharmony_ci h = (y->maximum - y->minimum)/y->resolution; 1532a46c0ec8Sopenharmony_ci iprintf(fp, I_EVDEV, "# Size in mm: %dx%d\n", w, h); 1533a46c0ec8Sopenharmony_ci } else { 1534a46c0ec8Sopenharmony_ci iprintf(fp, 1535a46c0ec8Sopenharmony_ci I_EVDEV, 1536a46c0ec8Sopenharmony_ci "# Size in mm: unknown, missing resolution\n"); 1537a46c0ec8Sopenharmony_ci } 1538a46c0ec8Sopenharmony_ci } 1539a46c0ec8Sopenharmony_ci 1540a46c0ec8Sopenharmony_ci iprintf(fp, I_EVDEV, "# Supported Events:\n"); 1541a46c0ec8Sopenharmony_ci 1542a46c0ec8Sopenharmony_ci for (unsigned int type = 0; type < EV_CNT; type++) { 1543a46c0ec8Sopenharmony_ci if (!libevdev_has_event_type(dev, type)) 1544a46c0ec8Sopenharmony_ci continue; 1545a46c0ec8Sopenharmony_ci 1546a46c0ec8Sopenharmony_ci print_description_codes(fp, dev, type); 1547a46c0ec8Sopenharmony_ci } 1548a46c0ec8Sopenharmony_ci 1549a46c0ec8Sopenharmony_ci iprintf(fp, I_EVDEV, "# Properties:\n"); 1550a46c0ec8Sopenharmony_ci 1551a46c0ec8Sopenharmony_ci for (unsigned int prop = 0; prop < INPUT_PROP_CNT; prop++) { 1552a46c0ec8Sopenharmony_ci if (libevdev_has_property(dev, prop)) { 1553a46c0ec8Sopenharmony_ci iprintf(fp, 1554a46c0ec8Sopenharmony_ci I_EVDEV, 1555a46c0ec8Sopenharmony_ci "# Property %d (%s)\n", 1556a46c0ec8Sopenharmony_ci prop, 1557a46c0ec8Sopenharmony_ci libevdev_property_get_name(prop)); 1558a46c0ec8Sopenharmony_ci } 1559a46c0ec8Sopenharmony_ci } 1560a46c0ec8Sopenharmony_ci} 1561a46c0ec8Sopenharmony_ci 1562a46c0ec8Sopenharmony_cistatic void 1563a46c0ec8Sopenharmony_ciprint_bits_info(FILE *fp, struct libevdev *dev) 1564a46c0ec8Sopenharmony_ci{ 1565a46c0ec8Sopenharmony_ci iprintf(fp, I_EVDEV, "name: \"%s\"\n", libevdev_get_name(dev)); 1566a46c0ec8Sopenharmony_ci iprintf(fp, 1567a46c0ec8Sopenharmony_ci I_EVDEV, 1568a46c0ec8Sopenharmony_ci "id: [%d, %d, %d, %d]\n", 1569a46c0ec8Sopenharmony_ci libevdev_get_id_bustype(dev), 1570a46c0ec8Sopenharmony_ci libevdev_get_id_vendor(dev), 1571a46c0ec8Sopenharmony_ci libevdev_get_id_product(dev), 1572a46c0ec8Sopenharmony_ci libevdev_get_id_version(dev)); 1573a46c0ec8Sopenharmony_ci} 1574a46c0ec8Sopenharmony_ci 1575a46c0ec8Sopenharmony_cistatic void 1576a46c0ec8Sopenharmony_ciprint_bits_absinfo(FILE *fp, struct libevdev *dev) 1577a46c0ec8Sopenharmony_ci{ 1578a46c0ec8Sopenharmony_ci const struct input_absinfo *abs; 1579a46c0ec8Sopenharmony_ci 1580a46c0ec8Sopenharmony_ci if (!libevdev_has_event_type(dev, EV_ABS)) 1581a46c0ec8Sopenharmony_ci return; 1582a46c0ec8Sopenharmony_ci 1583a46c0ec8Sopenharmony_ci iprintf(fp, I_EVDEV, "absinfo:\n"); 1584a46c0ec8Sopenharmony_ci for (unsigned int code = 0; code < ABS_CNT; code++) { 1585a46c0ec8Sopenharmony_ci abs = libevdev_get_abs_info(dev, code); 1586a46c0ec8Sopenharmony_ci if (!abs) 1587a46c0ec8Sopenharmony_ci continue; 1588a46c0ec8Sopenharmony_ci 1589a46c0ec8Sopenharmony_ci iprintf(fp, 1590a46c0ec8Sopenharmony_ci I_EVDEV_DATA, 1591a46c0ec8Sopenharmony_ci "%d: [%d, %d, %d, %d, %d]\n", 1592a46c0ec8Sopenharmony_ci code, 1593a46c0ec8Sopenharmony_ci abs->minimum, 1594a46c0ec8Sopenharmony_ci abs->maximum, 1595a46c0ec8Sopenharmony_ci abs->fuzz, 1596a46c0ec8Sopenharmony_ci abs->flat, 1597a46c0ec8Sopenharmony_ci abs->resolution); 1598a46c0ec8Sopenharmony_ci } 1599a46c0ec8Sopenharmony_ci} 1600a46c0ec8Sopenharmony_ci 1601a46c0ec8Sopenharmony_cistatic void 1602a46c0ec8Sopenharmony_ciprint_bits_codes(FILE *fp, struct libevdev *dev, unsigned int type) 1603a46c0ec8Sopenharmony_ci{ 1604a46c0ec8Sopenharmony_ci int max; 1605a46c0ec8Sopenharmony_ci const char *sep = ""; 1606a46c0ec8Sopenharmony_ci 1607a46c0ec8Sopenharmony_ci max = libevdev_event_type_get_max(type); 1608a46c0ec8Sopenharmony_ci if (max == -1) 1609a46c0ec8Sopenharmony_ci return; 1610a46c0ec8Sopenharmony_ci 1611a46c0ec8Sopenharmony_ci iprintf(fp, I_EVDEV_DATA, "%d: [", type); 1612a46c0ec8Sopenharmony_ci 1613a46c0ec8Sopenharmony_ci for (unsigned int code = 0; code <= (unsigned int)max; code++) { 1614a46c0ec8Sopenharmony_ci if (!libevdev_has_event_code(dev, type, code)) 1615a46c0ec8Sopenharmony_ci continue; 1616a46c0ec8Sopenharmony_ci 1617a46c0ec8Sopenharmony_ci iprintf(fp, I_NONE, "%s%d", sep, code); 1618a46c0ec8Sopenharmony_ci sep = ", "; 1619a46c0ec8Sopenharmony_ci } 1620a46c0ec8Sopenharmony_ci 1621a46c0ec8Sopenharmony_ci iprintf(fp, I_NONE, "] # %s\n", libevdev_event_type_get_name(type)); 1622a46c0ec8Sopenharmony_ci} 1623a46c0ec8Sopenharmony_ci 1624a46c0ec8Sopenharmony_cistatic void 1625a46c0ec8Sopenharmony_ciprint_bits_types(FILE *fp, struct libevdev *dev) 1626a46c0ec8Sopenharmony_ci{ 1627a46c0ec8Sopenharmony_ci iprintf(fp, I_EVDEV, "codes:\n"); 1628a46c0ec8Sopenharmony_ci for (unsigned int type = 0; type < EV_CNT; type++) { 1629a46c0ec8Sopenharmony_ci if (!libevdev_has_event_type(dev, type)) 1630a46c0ec8Sopenharmony_ci continue; 1631a46c0ec8Sopenharmony_ci print_bits_codes(fp, dev, type); 1632a46c0ec8Sopenharmony_ci } 1633a46c0ec8Sopenharmony_ci} 1634a46c0ec8Sopenharmony_ci 1635a46c0ec8Sopenharmony_cistatic void 1636a46c0ec8Sopenharmony_ciprint_bits_props(FILE *fp, struct libevdev *dev) 1637a46c0ec8Sopenharmony_ci{ 1638a46c0ec8Sopenharmony_ci const char *sep = ""; 1639a46c0ec8Sopenharmony_ci 1640a46c0ec8Sopenharmony_ci iprintf(fp, I_EVDEV, "properties: ["); 1641a46c0ec8Sopenharmony_ci for (unsigned int prop = 0; prop < INPUT_PROP_CNT; prop++) { 1642a46c0ec8Sopenharmony_ci if (libevdev_has_property(dev, prop)) { 1643a46c0ec8Sopenharmony_ci iprintf(fp, I_NONE, "%s%d", sep, prop); 1644a46c0ec8Sopenharmony_ci sep = ", "; 1645a46c0ec8Sopenharmony_ci } 1646a46c0ec8Sopenharmony_ci } 1647a46c0ec8Sopenharmony_ci iprintf(fp, I_NONE, "]\n"); /* last entry, no comma */ 1648a46c0ec8Sopenharmony_ci} 1649a46c0ec8Sopenharmony_ci 1650a46c0ec8Sopenharmony_cistatic void 1651a46c0ec8Sopenharmony_ciprint_evdev_description(struct record_device *dev) 1652a46c0ec8Sopenharmony_ci{ 1653a46c0ec8Sopenharmony_ci struct libevdev *evdev = dev->evdev; 1654a46c0ec8Sopenharmony_ci 1655a46c0ec8Sopenharmony_ci iprintf(dev->fp, I_DEVICE, "evdev:\n"); 1656a46c0ec8Sopenharmony_ci 1657a46c0ec8Sopenharmony_ci print_description(dev->fp, evdev); 1658a46c0ec8Sopenharmony_ci print_bits_info(dev->fp, evdev); 1659a46c0ec8Sopenharmony_ci print_bits_types(dev->fp, evdev); 1660a46c0ec8Sopenharmony_ci print_bits_absinfo(dev->fp, evdev); 1661a46c0ec8Sopenharmony_ci print_bits_props(dev->fp, evdev); 1662a46c0ec8Sopenharmony_ci} 1663a46c0ec8Sopenharmony_ci 1664a46c0ec8Sopenharmony_cistatic void 1665a46c0ec8Sopenharmony_ciprint_hid_report_descriptor(struct record_device *dev) 1666a46c0ec8Sopenharmony_ci{ 1667a46c0ec8Sopenharmony_ci const char *prefix = "/dev/input/event"; 1668a46c0ec8Sopenharmony_ci char syspath[PATH_MAX]; 1669a46c0ec8Sopenharmony_ci unsigned char buf[1024]; 1670a46c0ec8Sopenharmony_ci int len; 1671a46c0ec8Sopenharmony_ci int fd; 1672a46c0ec8Sopenharmony_ci const char *sep = ""; 1673a46c0ec8Sopenharmony_ci 1674a46c0ec8Sopenharmony_ci /* we take the shortcut rather than the proper udev approach, the 1675a46c0ec8Sopenharmony_ci report_descriptor is available in sysfs and two devices up from 1676a46c0ec8Sopenharmony_ci our device. 1677a46c0ec8Sopenharmony_ci This approach won't work for /dev/input/by-id devices. */ 1678a46c0ec8Sopenharmony_ci if (!strstartswith(dev->devnode, prefix)) 1679a46c0ec8Sopenharmony_ci return; 1680a46c0ec8Sopenharmony_ci 1681a46c0ec8Sopenharmony_ci len = snprintf(syspath, 1682a46c0ec8Sopenharmony_ci sizeof(syspath), 1683a46c0ec8Sopenharmony_ci "/sys/class/input/%s/device/device/report_descriptor", 1684a46c0ec8Sopenharmony_ci safe_basename(dev->devnode)); 1685a46c0ec8Sopenharmony_ci if (len <= 0) 1686a46c0ec8Sopenharmony_ci return; 1687a46c0ec8Sopenharmony_ci 1688a46c0ec8Sopenharmony_ci fd = open(syspath, O_RDONLY); 1689a46c0ec8Sopenharmony_ci if (fd == -1) 1690a46c0ec8Sopenharmony_ci return; 1691a46c0ec8Sopenharmony_ci 1692a46c0ec8Sopenharmony_ci iprintf(dev->fp, I_DEVICE, "hid: ["); 1693a46c0ec8Sopenharmony_ci 1694a46c0ec8Sopenharmony_ci while ((len = read(fd, buf, sizeof(buf))) > 0) { 1695a46c0ec8Sopenharmony_ci for (int i = 0; i < len; i++) { 1696a46c0ec8Sopenharmony_ci /* We can't have a trailing comma, so our line-break 1697a46c0ec8Sopenharmony_ci * handling is awkward. 1698a46c0ec8Sopenharmony_ci * For a linebreak: print the comma, break, indent, 1699a46c0ec8Sopenharmony_ci * then just the hex code. 1700a46c0ec8Sopenharmony_ci * For the other values: print the comma plus the 1701a46c0ec8Sopenharmony_ci * hex code, unindented. 1702a46c0ec8Sopenharmony_ci */ 1703a46c0ec8Sopenharmony_ci if (i % 16 == 0) { 1704a46c0ec8Sopenharmony_ci iprintf(dev->fp, I_NONE, "%s\n", sep); 1705a46c0ec8Sopenharmony_ci iprintf(dev->fp, I_DEVICE, " "); 1706a46c0ec8Sopenharmony_ci iprintf(dev->fp, I_NONE, "0x%02x", buf[i]); 1707a46c0ec8Sopenharmony_ci } else { 1708a46c0ec8Sopenharmony_ci iprintf(dev->fp, I_NONE, "%s0x%02x", sep, buf[i]); 1709a46c0ec8Sopenharmony_ci } 1710a46c0ec8Sopenharmony_ci sep = ", "; 1711a46c0ec8Sopenharmony_ci } 1712a46c0ec8Sopenharmony_ci } 1713a46c0ec8Sopenharmony_ci iprintf(dev->fp, I_NONE, "\n"); 1714a46c0ec8Sopenharmony_ci iprintf(dev->fp, I_DEVICE, "]\n"); 1715a46c0ec8Sopenharmony_ci 1716a46c0ec8Sopenharmony_ci close(fd); 1717a46c0ec8Sopenharmony_ci} 1718a46c0ec8Sopenharmony_ci 1719a46c0ec8Sopenharmony_cistatic void 1720a46c0ec8Sopenharmony_ciprint_udev_properties(struct record_device *dev) 1721a46c0ec8Sopenharmony_ci{ 1722a46c0ec8Sopenharmony_ci struct udev *udev = NULL; 1723a46c0ec8Sopenharmony_ci struct udev_device *udev_device = NULL; 1724a46c0ec8Sopenharmony_ci struct udev_list_entry *entry; 1725a46c0ec8Sopenharmony_ci struct stat st; 1726a46c0ec8Sopenharmony_ci 1727a46c0ec8Sopenharmony_ci if (stat(dev->devnode, &st) < 0) 1728a46c0ec8Sopenharmony_ci return; 1729a46c0ec8Sopenharmony_ci 1730a46c0ec8Sopenharmony_ci udev = udev_new(); 1731a46c0ec8Sopenharmony_ci if (!udev) 1732a46c0ec8Sopenharmony_ci goto out; 1733a46c0ec8Sopenharmony_ci 1734a46c0ec8Sopenharmony_ci udev_device = udev_device_new_from_devnum(udev, 'c', st.st_rdev); 1735a46c0ec8Sopenharmony_ci if (!udev_device) 1736a46c0ec8Sopenharmony_ci goto out; 1737a46c0ec8Sopenharmony_ci 1738a46c0ec8Sopenharmony_ci iprintf(dev->fp, I_DEVICE, "udev:\n"); 1739a46c0ec8Sopenharmony_ci 1740a46c0ec8Sopenharmony_ci iprintf(dev->fp, I_UDEV, "properties:\n"); 1741a46c0ec8Sopenharmony_ci 1742a46c0ec8Sopenharmony_ci entry = udev_device_get_properties_list_entry(udev_device); 1743a46c0ec8Sopenharmony_ci while (entry) { 1744a46c0ec8Sopenharmony_ci const char *key, *value; 1745a46c0ec8Sopenharmony_ci 1746a46c0ec8Sopenharmony_ci key = udev_list_entry_get_name(entry); 1747a46c0ec8Sopenharmony_ci 1748a46c0ec8Sopenharmony_ci if (strneq(key, "ID_INPUT", 8) || 1749a46c0ec8Sopenharmony_ci strneq(key, "LIBINPUT", 8) || 1750a46c0ec8Sopenharmony_ci strneq(key, "EVDEV_ABS", 9) || 1751a46c0ec8Sopenharmony_ci strneq(key, "MOUSE_DPI", 9) || 1752a46c0ec8Sopenharmony_ci strneq(key, "POINTINGSTICK_", 14)) { 1753a46c0ec8Sopenharmony_ci value = udev_list_entry_get_value(entry); 1754a46c0ec8Sopenharmony_ci iprintf(dev->fp, I_UDEV_DATA, "- %s=%s\n", key, value); 1755a46c0ec8Sopenharmony_ci } 1756a46c0ec8Sopenharmony_ci 1757a46c0ec8Sopenharmony_ci entry = udev_list_entry_get_next(entry); 1758a46c0ec8Sopenharmony_ci } 1759a46c0ec8Sopenharmony_ci 1760a46c0ec8Sopenharmony_ciout: 1761a46c0ec8Sopenharmony_ci udev_device_unref(udev_device); 1762a46c0ec8Sopenharmony_ci udev_unref(udev); 1763a46c0ec8Sopenharmony_ci} 1764a46c0ec8Sopenharmony_ci 1765a46c0ec8Sopenharmony_cistatic void 1766a46c0ec8Sopenharmony_ciquirks_log_handler(struct libinput *this_is_null, 1767a46c0ec8Sopenharmony_ci enum libinput_log_priority priority, 1768a46c0ec8Sopenharmony_ci const char *format, 1769a46c0ec8Sopenharmony_ci va_list args) 1770a46c0ec8Sopenharmony_ci{ 1771a46c0ec8Sopenharmony_ci} 1772a46c0ec8Sopenharmony_ci 1773a46c0ec8Sopenharmony_cistatic void 1774a46c0ec8Sopenharmony_cilist_print(void *userdata, const char *val) 1775a46c0ec8Sopenharmony_ci{ 1776a46c0ec8Sopenharmony_ci FILE *fp = userdata; 1777a46c0ec8Sopenharmony_ci 1778a46c0ec8Sopenharmony_ci iprintf(fp, I_QUIRKS, "- %s\n", val); 1779a46c0ec8Sopenharmony_ci} 1780a46c0ec8Sopenharmony_ci 1781a46c0ec8Sopenharmony_cistatic void 1782a46c0ec8Sopenharmony_ciprint_device_quirks(struct record_device *dev) 1783a46c0ec8Sopenharmony_ci{ 1784a46c0ec8Sopenharmony_ci struct udev *udev = NULL; 1785a46c0ec8Sopenharmony_ci struct udev_device *udev_device = NULL; 1786a46c0ec8Sopenharmony_ci struct stat st; 1787a46c0ec8Sopenharmony_ci struct quirks_context *quirks; 1788a46c0ec8Sopenharmony_ci const char *data_path = LIBINPUT_QUIRKS_DIR; 1789a46c0ec8Sopenharmony_ci const char *override_file = LIBINPUT_QUIRKS_OVERRIDE_FILE; 1790a46c0ec8Sopenharmony_ci char *builddir = NULL; 1791a46c0ec8Sopenharmony_ci 1792a46c0ec8Sopenharmony_ci if (stat(dev->devnode, &st) < 0) 1793a46c0ec8Sopenharmony_ci return; 1794a46c0ec8Sopenharmony_ci 1795a46c0ec8Sopenharmony_ci if ((builddir = builddir_lookup())) { 1796a46c0ec8Sopenharmony_ci setenv("LIBINPUT_QUIRKS_DIR", LIBINPUT_QUIRKS_SRCDIR, 0); 1797a46c0ec8Sopenharmony_ci data_path = LIBINPUT_QUIRKS_SRCDIR; 1798a46c0ec8Sopenharmony_ci override_file = NULL; 1799a46c0ec8Sopenharmony_ci } 1800a46c0ec8Sopenharmony_ci 1801a46c0ec8Sopenharmony_ci free(builddir); 1802a46c0ec8Sopenharmony_ci 1803a46c0ec8Sopenharmony_ci quirks = quirks_init_subsystem(data_path, 1804a46c0ec8Sopenharmony_ci override_file, 1805a46c0ec8Sopenharmony_ci quirks_log_handler, 1806a46c0ec8Sopenharmony_ci NULL, 1807a46c0ec8Sopenharmony_ci QLOG_CUSTOM_LOG_PRIORITIES); 1808a46c0ec8Sopenharmony_ci if (!quirks) { 1809a46c0ec8Sopenharmony_ci fprintf(stderr, 1810a46c0ec8Sopenharmony_ci "Failed to load the device quirks from %s%s%s. " 1811a46c0ec8Sopenharmony_ci "This will negatively affect device behavior. " 1812a46c0ec8Sopenharmony_ci "See %s/device-quirks.html for details.\n", 1813a46c0ec8Sopenharmony_ci data_path, 1814a46c0ec8Sopenharmony_ci override_file ? " and " : "", 1815a46c0ec8Sopenharmony_ci override_file ? override_file : "", 1816a46c0ec8Sopenharmony_ci HTTP_DOC_LINK); 1817a46c0ec8Sopenharmony_ci return; 1818a46c0ec8Sopenharmony_ci } 1819a46c0ec8Sopenharmony_ci 1820a46c0ec8Sopenharmony_ci udev = udev_new(); 1821a46c0ec8Sopenharmony_ci if (!udev) 1822a46c0ec8Sopenharmony_ci goto out; 1823a46c0ec8Sopenharmony_ci 1824a46c0ec8Sopenharmony_ci udev_device = udev_device_new_from_devnum(udev, 'c', st.st_rdev); 1825a46c0ec8Sopenharmony_ci if (!udev_device) 1826a46c0ec8Sopenharmony_ci goto out; 1827a46c0ec8Sopenharmony_ci 1828a46c0ec8Sopenharmony_ci iprintf(dev->fp, I_DEVICE, "quirks:\n"); 1829a46c0ec8Sopenharmony_ci tools_list_device_quirks(quirks, udev_device, list_print, dev->fp); 1830a46c0ec8Sopenharmony_ciout: 1831a46c0ec8Sopenharmony_ci udev_device_unref(udev_device); 1832a46c0ec8Sopenharmony_ci udev_unref(udev); 1833a46c0ec8Sopenharmony_ci quirks_context_unref(quirks); 1834a46c0ec8Sopenharmony_ci} 1835a46c0ec8Sopenharmony_ci 1836a46c0ec8Sopenharmony_cistatic void 1837a46c0ec8Sopenharmony_ciprint_libinput_description(struct record_device *dev) 1838a46c0ec8Sopenharmony_ci{ 1839a46c0ec8Sopenharmony_ci struct libinput_device *device = dev->device; 1840a46c0ec8Sopenharmony_ci double w, h; 1841a46c0ec8Sopenharmony_ci struct cap { 1842a46c0ec8Sopenharmony_ci enum libinput_device_capability cap; 1843a46c0ec8Sopenharmony_ci const char *name; 1844a46c0ec8Sopenharmony_ci } caps[] = { 1845a46c0ec8Sopenharmony_ci {LIBINPUT_DEVICE_CAP_KEYBOARD, "keyboard"}, 1846a46c0ec8Sopenharmony_ci {LIBINPUT_DEVICE_CAP_POINTER, "pointer"}, 1847a46c0ec8Sopenharmony_ci {LIBINPUT_DEVICE_CAP_TOUCH, "touch"}, 1848a46c0ec8Sopenharmony_ci {LIBINPUT_DEVICE_CAP_TABLET_TOOL, "tablet"}, 1849a46c0ec8Sopenharmony_ci {LIBINPUT_DEVICE_CAP_TABLET_PAD, "pad"}, 1850a46c0ec8Sopenharmony_ci {LIBINPUT_DEVICE_CAP_GESTURE, "gesture"}, 1851a46c0ec8Sopenharmony_ci {LIBINPUT_DEVICE_CAP_SWITCH, "switch"}, 1852a46c0ec8Sopenharmony_ci }; 1853a46c0ec8Sopenharmony_ci const char *sep = ""; 1854a46c0ec8Sopenharmony_ci 1855a46c0ec8Sopenharmony_ci if (!device) 1856a46c0ec8Sopenharmony_ci return; 1857a46c0ec8Sopenharmony_ci 1858a46c0ec8Sopenharmony_ci iprintf(dev->fp, I_DEVICE, "libinput:\n"); 1859a46c0ec8Sopenharmony_ci if (libinput_device_get_size(device, &w, &h) == 0) 1860a46c0ec8Sopenharmony_ci iprintf(dev->fp, I_LIBINPUTDEV, "size: [%.f, %.f]\n", w, h); 1861a46c0ec8Sopenharmony_ci 1862a46c0ec8Sopenharmony_ci iprintf(dev->fp, I_LIBINPUTDEV, "capabilities: ["); 1863a46c0ec8Sopenharmony_ci ARRAY_FOR_EACH(caps, cap) { 1864a46c0ec8Sopenharmony_ci if (!libinput_device_has_capability(device, cap->cap)) 1865a46c0ec8Sopenharmony_ci continue; 1866a46c0ec8Sopenharmony_ci iprintf(dev->fp, I_NONE, "%s%s", sep, cap->name); 1867a46c0ec8Sopenharmony_ci sep = ", "; 1868a46c0ec8Sopenharmony_ci } 1869a46c0ec8Sopenharmony_ci iprintf(dev->fp, I_NONE, "]\n"); 1870a46c0ec8Sopenharmony_ci 1871a46c0ec8Sopenharmony_ci /* Configuration options should be printed here, but since they 1872a46c0ec8Sopenharmony_ci * don't reflect the user-configured ones their usefulness is 1873a46c0ec8Sopenharmony_ci * questionable. We need the ability to specify the options like in 1874a46c0ec8Sopenharmony_ci * debug-events. 1875a46c0ec8Sopenharmony_ci */ 1876a46c0ec8Sopenharmony_ci} 1877a46c0ec8Sopenharmony_ci 1878a46c0ec8Sopenharmony_cistatic void 1879a46c0ec8Sopenharmony_ciprint_device_description(struct record_device *dev) 1880a46c0ec8Sopenharmony_ci{ 1881a46c0ec8Sopenharmony_ci iprintf(dev->fp, I_DEVICE, "- node: %s\n", dev->devnode); 1882a46c0ec8Sopenharmony_ci 1883a46c0ec8Sopenharmony_ci print_evdev_description(dev); 1884a46c0ec8Sopenharmony_ci print_hid_report_descriptor(dev); 1885a46c0ec8Sopenharmony_ci print_udev_properties(dev); 1886a46c0ec8Sopenharmony_ci print_device_quirks(dev); 1887a46c0ec8Sopenharmony_ci print_libinput_description(dev); 1888a46c0ec8Sopenharmony_ci} 1889a46c0ec8Sopenharmony_ci 1890a46c0ec8Sopenharmony_cistatic int is_event_node(const struct dirent *dir) { 1891a46c0ec8Sopenharmony_ci return strneq(dir->d_name, "event", 5); 1892a46c0ec8Sopenharmony_ci} 1893a46c0ec8Sopenharmony_ci 1894a46c0ec8Sopenharmony_cistatic char * 1895a46c0ec8Sopenharmony_ciselect_device(void) 1896a46c0ec8Sopenharmony_ci{ 1897a46c0ec8Sopenharmony_ci struct dirent **namelist; 1898a46c0ec8Sopenharmony_ci int ndev, selected_device; 1899a46c0ec8Sopenharmony_ci int rc; 1900a46c0ec8Sopenharmony_ci char *device_path; 1901a46c0ec8Sopenharmony_ci bool has_eaccess = false; 1902a46c0ec8Sopenharmony_ci int available_devices = 0; 1903a46c0ec8Sopenharmony_ci const char *prefix = ""; 1904a46c0ec8Sopenharmony_ci 1905a46c0ec8Sopenharmony_ci if (!isatty(STDERR_FILENO)) 1906a46c0ec8Sopenharmony_ci prefix = "# "; 1907a46c0ec8Sopenharmony_ci 1908a46c0ec8Sopenharmony_ci ndev = scandir("/dev/input", &namelist, is_event_node, versionsort); 1909a46c0ec8Sopenharmony_ci if (ndev <= 0) 1910a46c0ec8Sopenharmony_ci return NULL; 1911a46c0ec8Sopenharmony_ci 1912a46c0ec8Sopenharmony_ci fprintf(stderr, "%sAvailable devices:\n", prefix); 1913a46c0ec8Sopenharmony_ci for (int i = 0; i < ndev; i++) { 1914a46c0ec8Sopenharmony_ci struct libevdev *device; 1915a46c0ec8Sopenharmony_ci char path[PATH_MAX]; 1916a46c0ec8Sopenharmony_ci int fd = -1; 1917a46c0ec8Sopenharmony_ci 1918a46c0ec8Sopenharmony_ci snprintf(path, 1919a46c0ec8Sopenharmony_ci sizeof(path), 1920a46c0ec8Sopenharmony_ci "/dev/input/%s", 1921a46c0ec8Sopenharmony_ci namelist[i]->d_name); 1922a46c0ec8Sopenharmony_ci fd = open(path, O_RDONLY); 1923a46c0ec8Sopenharmony_ci if (fd < 0) { 1924a46c0ec8Sopenharmony_ci if (errno == EACCES) 1925a46c0ec8Sopenharmony_ci has_eaccess = true; 1926a46c0ec8Sopenharmony_ci continue; 1927a46c0ec8Sopenharmony_ci } 1928a46c0ec8Sopenharmony_ci 1929a46c0ec8Sopenharmony_ci rc = libevdev_new_from_fd(fd, &device); 1930a46c0ec8Sopenharmony_ci close(fd); 1931a46c0ec8Sopenharmony_ci if (rc != 0) 1932a46c0ec8Sopenharmony_ci continue; 1933a46c0ec8Sopenharmony_ci 1934a46c0ec8Sopenharmony_ci fprintf(stderr, "%s%s: %s\n", prefix, path, libevdev_get_name(device)); 1935a46c0ec8Sopenharmony_ci libevdev_free(device); 1936a46c0ec8Sopenharmony_ci available_devices++; 1937a46c0ec8Sopenharmony_ci } 1938a46c0ec8Sopenharmony_ci 1939a46c0ec8Sopenharmony_ci for (int i = 0; i < ndev; i++) 1940a46c0ec8Sopenharmony_ci free(namelist[i]); 1941a46c0ec8Sopenharmony_ci free(namelist); 1942a46c0ec8Sopenharmony_ci 1943a46c0ec8Sopenharmony_ci if (available_devices == 0) { 1944a46c0ec8Sopenharmony_ci fprintf(stderr, 1945a46c0ec8Sopenharmony_ci "No devices available.%s\n", 1946a46c0ec8Sopenharmony_ci has_eaccess ? " Please re-run as root." : ""); 1947a46c0ec8Sopenharmony_ci return NULL; 1948a46c0ec8Sopenharmony_ci } 1949a46c0ec8Sopenharmony_ci 1950a46c0ec8Sopenharmony_ci fprintf(stderr, "%sSelect the device event number: ", prefix); 1951a46c0ec8Sopenharmony_ci rc = scanf("%d", &selected_device); 1952a46c0ec8Sopenharmony_ci 1953a46c0ec8Sopenharmony_ci if (rc != 1 || selected_device < 0) 1954a46c0ec8Sopenharmony_ci return NULL; 1955a46c0ec8Sopenharmony_ci 1956a46c0ec8Sopenharmony_ci rc = xasprintf(&device_path, "/dev/input/event%d", selected_device); 1957a46c0ec8Sopenharmony_ci if (rc == -1) 1958a46c0ec8Sopenharmony_ci return NULL; 1959a46c0ec8Sopenharmony_ci 1960a46c0ec8Sopenharmony_ci return device_path; 1961a46c0ec8Sopenharmony_ci} 1962a46c0ec8Sopenharmony_ci 1963a46c0ec8Sopenharmony_cistatic char ** 1964a46c0ec8Sopenharmony_ciall_devices(void) 1965a46c0ec8Sopenharmony_ci{ 1966a46c0ec8Sopenharmony_ci struct dirent **namelist; 1967a46c0ec8Sopenharmony_ci int ndev; 1968a46c0ec8Sopenharmony_ci char **devices = NULL; 1969a46c0ec8Sopenharmony_ci 1970a46c0ec8Sopenharmony_ci ndev = scandir("/dev/input", &namelist, is_event_node, versionsort); 1971a46c0ec8Sopenharmony_ci if (ndev <= 0) 1972a46c0ec8Sopenharmony_ci return NULL; 1973a46c0ec8Sopenharmony_ci 1974a46c0ec8Sopenharmony_ci devices = zalloc((ndev + 1)* sizeof *devices); /* NULL-terminated */ 1975a46c0ec8Sopenharmony_ci for (int i = 0; i < ndev; i++) { 1976a46c0ec8Sopenharmony_ci char *device_path; 1977a46c0ec8Sopenharmony_ci 1978a46c0ec8Sopenharmony_ci int rc = xasprintf(&device_path, 1979a46c0ec8Sopenharmony_ci "/dev/input/%s", 1980a46c0ec8Sopenharmony_ci namelist[i]->d_name); 1981a46c0ec8Sopenharmony_ci if (rc == -1) 1982a46c0ec8Sopenharmony_ci goto error; 1983a46c0ec8Sopenharmony_ci 1984a46c0ec8Sopenharmony_ci devices[i] = device_path; 1985a46c0ec8Sopenharmony_ci } 1986a46c0ec8Sopenharmony_ci 1987a46c0ec8Sopenharmony_ci return devices; 1988a46c0ec8Sopenharmony_ci 1989a46c0ec8Sopenharmony_cierror: 1990a46c0ec8Sopenharmony_ci for (int i = 0; i < ndev; i++) 1991a46c0ec8Sopenharmony_ci free(namelist[i]); 1992a46c0ec8Sopenharmony_ci free(namelist); 1993a46c0ec8Sopenharmony_ci if (devices) 1994a46c0ec8Sopenharmony_ci strv_free(devices); 1995a46c0ec8Sopenharmony_ci return NULL; 1996a46c0ec8Sopenharmony_ci} 1997a46c0ec8Sopenharmony_ci 1998a46c0ec8Sopenharmony_cistatic char * 1999a46c0ec8Sopenharmony_ciinit_output_file(const char *file, bool is_prefix) 2000a46c0ec8Sopenharmony_ci{ 2001a46c0ec8Sopenharmony_ci char name[PATH_MAX]; 2002a46c0ec8Sopenharmony_ci 2003a46c0ec8Sopenharmony_ci assert(file != NULL); 2004a46c0ec8Sopenharmony_ci 2005a46c0ec8Sopenharmony_ci if (is_prefix) { 2006a46c0ec8Sopenharmony_ci struct tm *tm; 2007a46c0ec8Sopenharmony_ci time_t t; 2008a46c0ec8Sopenharmony_ci char suffix[64]; 2009a46c0ec8Sopenharmony_ci 2010a46c0ec8Sopenharmony_ci t = time(NULL); 2011a46c0ec8Sopenharmony_ci tm = localtime(&t); 2012a46c0ec8Sopenharmony_ci strftime(suffix, sizeof(suffix), "%F-%T", tm); 2013a46c0ec8Sopenharmony_ci snprintf(name, 2014a46c0ec8Sopenharmony_ci sizeof(name), 2015a46c0ec8Sopenharmony_ci "%s.%s", 2016a46c0ec8Sopenharmony_ci file, 2017a46c0ec8Sopenharmony_ci suffix); 2018a46c0ec8Sopenharmony_ci } else { 2019a46c0ec8Sopenharmony_ci snprintf(name, sizeof(name), "%s", file); 2020a46c0ec8Sopenharmony_ci } 2021a46c0ec8Sopenharmony_ci 2022a46c0ec8Sopenharmony_ci return safe_strdup(name); 2023a46c0ec8Sopenharmony_ci} 2024a46c0ec8Sopenharmony_ci 2025a46c0ec8Sopenharmony_cistatic bool 2026a46c0ec8Sopenharmony_ciopen_output_files(struct record_context *ctx, bool is_prefix) 2027a46c0ec8Sopenharmony_ci{ 2028a46c0ec8Sopenharmony_ci FILE *out_file; 2029a46c0ec8Sopenharmony_ci struct record_device *d; 2030a46c0ec8Sopenharmony_ci 2031a46c0ec8Sopenharmony_ci if (ctx->output_file.name) { 2032a46c0ec8Sopenharmony_ci char *fname = init_output_file(ctx->output_file.name, is_prefix); 2033a46c0ec8Sopenharmony_ci ctx->output_file.name_with_suffix = fname; 2034a46c0ec8Sopenharmony_ci out_file = fopen(fname, "w"); 2035a46c0ec8Sopenharmony_ci if (!out_file) 2036a46c0ec8Sopenharmony_ci return false; 2037a46c0ec8Sopenharmony_ci } else { 2038a46c0ec8Sopenharmony_ci ctx->output_file.name_with_suffix = safe_strdup("stdout"); 2039a46c0ec8Sopenharmony_ci out_file = stdout; 2040a46c0ec8Sopenharmony_ci } 2041a46c0ec8Sopenharmony_ci 2042a46c0ec8Sopenharmony_ci ctx->first_device->fp = out_file; 2043a46c0ec8Sopenharmony_ci 2044a46c0ec8Sopenharmony_ci list_for_each(d, &ctx->devices, link) { 2045a46c0ec8Sopenharmony_ci if (d->fp) 2046a46c0ec8Sopenharmony_ci continue; 2047a46c0ec8Sopenharmony_ci d->fp = tmpfile(); 2048a46c0ec8Sopenharmony_ci } 2049a46c0ec8Sopenharmony_ci 2050a46c0ec8Sopenharmony_ci return true; 2051a46c0ec8Sopenharmony_ci} 2052a46c0ec8Sopenharmony_ci 2053a46c0ec8Sopenharmony_cistatic void 2054a46c0ec8Sopenharmony_ciprint_progress_bar(void) 2055a46c0ec8Sopenharmony_ci{ 2056a46c0ec8Sopenharmony_ci static uint8_t foo = 0; 2057a46c0ec8Sopenharmony_ci 2058a46c0ec8Sopenharmony_ci if (!isatty(STDERR_FILENO)) 2059a46c0ec8Sopenharmony_ci return; 2060a46c0ec8Sopenharmony_ci 2061a46c0ec8Sopenharmony_ci if (++foo > 20) 2062a46c0ec8Sopenharmony_ci foo = 1; 2063a46c0ec8Sopenharmony_ci fprintf(stderr, "\rReceiving events: [%*s%*s]", foo, "*", 21 - foo, " "); 2064a46c0ec8Sopenharmony_ci} 2065a46c0ec8Sopenharmony_ci 2066a46c0ec8Sopenharmony_cistatic void 2067a46c0ec8Sopenharmony_ciprint_wall_time(struct record_context *ctx) 2068a46c0ec8Sopenharmony_ci{ 2069a46c0ec8Sopenharmony_ci time_t t = time(NULL); 2070a46c0ec8Sopenharmony_ci struct tm tm; 2071a46c0ec8Sopenharmony_ci struct record_device *d; 2072a46c0ec8Sopenharmony_ci 2073a46c0ec8Sopenharmony_ci localtime_r(&t, &tm); 2074a46c0ec8Sopenharmony_ci 2075a46c0ec8Sopenharmony_ci list_for_each(d, &ctx->devices, link) { 2076a46c0ec8Sopenharmony_ci iprintf(d->fp, 2077a46c0ec8Sopenharmony_ci I_DEVICE, 2078a46c0ec8Sopenharmony_ci "# Current time is %02d:%02d:%02d\n", 2079a46c0ec8Sopenharmony_ci tm.tm_hour, tm.tm_min, tm.tm_sec); 2080a46c0ec8Sopenharmony_ci fflush(d->fp); 2081a46c0ec8Sopenharmony_ci } 2082a46c0ec8Sopenharmony_ci} 2083a46c0ec8Sopenharmony_ci 2084a46c0ec8Sopenharmony_cistatic void 2085a46c0ec8Sopenharmony_ciarm_timer(int timerfd) 2086a46c0ec8Sopenharmony_ci{ 2087a46c0ec8Sopenharmony_ci time_t t = time(NULL); 2088a46c0ec8Sopenharmony_ci struct tm tm; 2089a46c0ec8Sopenharmony_ci struct itimerspec interval = { 2090a46c0ec8Sopenharmony_ci .it_value = { 0, 0 }, 2091a46c0ec8Sopenharmony_ci .it_interval = { 5, 0 }, 2092a46c0ec8Sopenharmony_ci }; 2093a46c0ec8Sopenharmony_ci 2094a46c0ec8Sopenharmony_ci localtime_r(&t, &tm); 2095a46c0ec8Sopenharmony_ci interval.it_value.tv_sec = 5 - (tm.tm_sec % 5); 2096a46c0ec8Sopenharmony_ci timerfd_settime(timerfd, 0, &interval, NULL); 2097a46c0ec8Sopenharmony_ci} 2098a46c0ec8Sopenharmony_ci 2099a46c0ec8Sopenharmony_cistatic struct source * 2100a46c0ec8Sopenharmony_ciadd_source(struct record_context *ctx, 2101a46c0ec8Sopenharmony_ci int fd, 2102a46c0ec8Sopenharmony_ci source_dispatch_t dispatch, 2103a46c0ec8Sopenharmony_ci void *user_data) 2104a46c0ec8Sopenharmony_ci{ 2105a46c0ec8Sopenharmony_ci struct source *source; 2106a46c0ec8Sopenharmony_ci struct epoll_event ep; 2107a46c0ec8Sopenharmony_ci 2108a46c0ec8Sopenharmony_ci assert(fd != -1); 2109a46c0ec8Sopenharmony_ci 2110a46c0ec8Sopenharmony_ci source = zalloc(sizeof *source); 2111a46c0ec8Sopenharmony_ci source->dispatch = dispatch; 2112a46c0ec8Sopenharmony_ci source->user_data = user_data; 2113a46c0ec8Sopenharmony_ci source->fd = fd; 2114a46c0ec8Sopenharmony_ci list_append(&ctx->sources, &source->link); 2115a46c0ec8Sopenharmony_ci 2116a46c0ec8Sopenharmony_ci memset(&ep, 0, sizeof ep); 2117a46c0ec8Sopenharmony_ci ep.events = EPOLLIN; 2118a46c0ec8Sopenharmony_ci ep.data.ptr = source; 2119a46c0ec8Sopenharmony_ci 2120a46c0ec8Sopenharmony_ci if (epoll_ctl(ctx->epoll_fd, EPOLL_CTL_ADD, fd, &ep) < 0) { 2121a46c0ec8Sopenharmony_ci free(source); 2122a46c0ec8Sopenharmony_ci return NULL; 2123a46c0ec8Sopenharmony_ci } 2124a46c0ec8Sopenharmony_ci 2125a46c0ec8Sopenharmony_ci return source; 2126a46c0ec8Sopenharmony_ci} 2127a46c0ec8Sopenharmony_ci 2128a46c0ec8Sopenharmony_cistatic void 2129a46c0ec8Sopenharmony_cidestroy_source(struct record_context *ctx, struct source *source) 2130a46c0ec8Sopenharmony_ci{ 2131a46c0ec8Sopenharmony_ci list_remove(&source->link); 2132a46c0ec8Sopenharmony_ci epoll_ctl(ctx->epoll_fd, EPOLL_CTL_DEL, source->fd, NULL); 2133a46c0ec8Sopenharmony_ci close(source->fd); 2134a46c0ec8Sopenharmony_ci free(source); 2135a46c0ec8Sopenharmony_ci} 2136a46c0ec8Sopenharmony_ci 2137a46c0ec8Sopenharmony_cistatic void 2138a46c0ec8Sopenharmony_cisignalfd_dispatch(struct record_context *ctx, int fd, void *data) 2139a46c0ec8Sopenharmony_ci{ 2140a46c0ec8Sopenharmony_ci struct signalfd_siginfo fdsi; 2141a46c0ec8Sopenharmony_ci 2142a46c0ec8Sopenharmony_ci (void)read(fd, &fdsi, sizeof(fdsi)); 2143a46c0ec8Sopenharmony_ci 2144a46c0ec8Sopenharmony_ci ctx->stop = true; 2145a46c0ec8Sopenharmony_ci} 2146a46c0ec8Sopenharmony_ci 2147a46c0ec8Sopenharmony_cistatic void 2148a46c0ec8Sopenharmony_citimefd_dispatch(struct record_context *ctx, int fd, void *data) 2149a46c0ec8Sopenharmony_ci{ 2150a46c0ec8Sopenharmony_ci char discard[64]; 2151a46c0ec8Sopenharmony_ci 2152a46c0ec8Sopenharmony_ci (void)read(fd, discard, sizeof(discard)); 2153a46c0ec8Sopenharmony_ci 2154a46c0ec8Sopenharmony_ci if (ctx->timestamps.had_events_since_last_time) { 2155a46c0ec8Sopenharmony_ci print_wall_time(ctx); 2156a46c0ec8Sopenharmony_ci ctx->timestamps.had_events_since_last_time = false; 2157a46c0ec8Sopenharmony_ci ctx->timestamps.skipped_timer_print = false; 2158a46c0ec8Sopenharmony_ci } else { 2159a46c0ec8Sopenharmony_ci ctx->timestamps.skipped_timer_print = true; 2160a46c0ec8Sopenharmony_ci } 2161a46c0ec8Sopenharmony_ci} 2162a46c0ec8Sopenharmony_ci 2163a46c0ec8Sopenharmony_cistatic void 2164a46c0ec8Sopenharmony_cievdev_dispatch(struct record_context *ctx, int fd, void *data) 2165a46c0ec8Sopenharmony_ci{ 2166a46c0ec8Sopenharmony_ci struct record_device *this_device = data; 2167a46c0ec8Sopenharmony_ci 2168a46c0ec8Sopenharmony_ci if (ctx->timestamps.skipped_timer_print) { 2169a46c0ec8Sopenharmony_ci print_wall_time(ctx); 2170a46c0ec8Sopenharmony_ci ctx->timestamps.skipped_timer_print = false; 2171a46c0ec8Sopenharmony_ci } 2172a46c0ec8Sopenharmony_ci 2173a46c0ec8Sopenharmony_ci ctx->had_events = true; 2174a46c0ec8Sopenharmony_ci ctx->timestamps.had_events_since_last_time = true; 2175a46c0ec8Sopenharmony_ci 2176a46c0ec8Sopenharmony_ci handle_events(ctx, this_device); 2177a46c0ec8Sopenharmony_ci} 2178a46c0ec8Sopenharmony_ci 2179a46c0ec8Sopenharmony_cistatic void 2180a46c0ec8Sopenharmony_cilibinput_ctx_dispatch(struct record_context *ctx, int fd, void *data) 2181a46c0ec8Sopenharmony_ci{ 2182a46c0ec8Sopenharmony_ci /* This function should only handle events caused by internal 2183a46c0ec8Sopenharmony_ci * timeouts etc. The real input events caused by the evdev devices 2184a46c0ec8Sopenharmony_ci * are already processed in handle_events */ 2185a46c0ec8Sopenharmony_ci libinput_dispatch(ctx->libinput); 2186a46c0ec8Sopenharmony_ci handle_libinput_events(ctx, ctx->first_device, true); 2187a46c0ec8Sopenharmony_ci} 2188a46c0ec8Sopenharmony_ci 2189a46c0ec8Sopenharmony_cistatic void 2190a46c0ec8Sopenharmony_cihidraw_dispatch(struct record_context *ctx, int fd, void *data) 2191a46c0ec8Sopenharmony_ci{ 2192a46c0ec8Sopenharmony_ci struct hidraw *hidraw = data; 2193a46c0ec8Sopenharmony_ci 2194a46c0ec8Sopenharmony_ci ctx->had_events = true; 2195a46c0ec8Sopenharmony_ci ctx->timestamps.had_events_since_last_time = true; 2196a46c0ec8Sopenharmony_ci handle_hidraw(hidraw); 2197a46c0ec8Sopenharmony_ci} 2198a46c0ec8Sopenharmony_ci 2199a46c0ec8Sopenharmony_cistatic int 2200a46c0ec8Sopenharmony_cidispatch_sources(struct record_context *ctx) 2201a46c0ec8Sopenharmony_ci{ 2202a46c0ec8Sopenharmony_ci struct source *source; 2203a46c0ec8Sopenharmony_ci struct epoll_event ep[64]; 2204a46c0ec8Sopenharmony_ci int i, count; 2205a46c0ec8Sopenharmony_ci 2206a46c0ec8Sopenharmony_ci count = epoll_wait(ctx->epoll_fd, ep, ARRAY_LENGTH(ep), ctx->timeout); 2207a46c0ec8Sopenharmony_ci if (count < 0) 2208a46c0ec8Sopenharmony_ci return -errno; 2209a46c0ec8Sopenharmony_ci 2210a46c0ec8Sopenharmony_ci for (i = 0; i < count; ++i) { 2211a46c0ec8Sopenharmony_ci source = ep[i].data.ptr; 2212a46c0ec8Sopenharmony_ci if (source->fd == -1) 2213a46c0ec8Sopenharmony_ci continue; 2214a46c0ec8Sopenharmony_ci source->dispatch(ctx, source->fd, source->user_data); 2215a46c0ec8Sopenharmony_ci } 2216a46c0ec8Sopenharmony_ci 2217a46c0ec8Sopenharmony_ci return count; 2218a46c0ec8Sopenharmony_ci} 2219a46c0ec8Sopenharmony_ci 2220a46c0ec8Sopenharmony_cistatic int 2221a46c0ec8Sopenharmony_cimainloop(struct record_context *ctx) 2222a46c0ec8Sopenharmony_ci{ 2223a46c0ec8Sopenharmony_ci bool autorestart = (ctx->timeout > 0); 2224a46c0ec8Sopenharmony_ci struct source *source; 2225a46c0ec8Sopenharmony_ci struct record_device *d = NULL; 2226a46c0ec8Sopenharmony_ci sigset_t mask; 2227a46c0ec8Sopenharmony_ci int sigfd, timerfd; 2228a46c0ec8Sopenharmony_ci 2229a46c0ec8Sopenharmony_ci assert(ctx->timeout != 0); 2230a46c0ec8Sopenharmony_ci assert(!list_empty(&ctx->devices)); 2231a46c0ec8Sopenharmony_ci 2232a46c0ec8Sopenharmony_ci ctx->epoll_fd = epoll_create1(0); 2233a46c0ec8Sopenharmony_ci assert(ctx->epoll_fd >= 0); 2234a46c0ec8Sopenharmony_ci 2235a46c0ec8Sopenharmony_ci sigemptyset(&mask); 2236a46c0ec8Sopenharmony_ci sigaddset(&mask, SIGINT); 2237a46c0ec8Sopenharmony_ci sigaddset(&mask, SIGQUIT); 2238a46c0ec8Sopenharmony_ci sigprocmask(SIG_BLOCK, &mask, NULL); 2239a46c0ec8Sopenharmony_ci 2240a46c0ec8Sopenharmony_ci sigfd = signalfd(-1, &mask, SFD_NONBLOCK); 2241a46c0ec8Sopenharmony_ci add_source(ctx, sigfd, signalfd_dispatch, NULL); 2242a46c0ec8Sopenharmony_ci 2243a46c0ec8Sopenharmony_ci timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC|TFD_NONBLOCK); 2244a46c0ec8Sopenharmony_ci add_source(ctx, timerfd, timefd_dispatch, NULL); 2245a46c0ec8Sopenharmony_ci arm_timer(timerfd); 2246a46c0ec8Sopenharmony_ci 2247a46c0ec8Sopenharmony_ci list_for_each(d, &ctx->devices, link) { 2248a46c0ec8Sopenharmony_ci struct hidraw *hidraw; 2249a46c0ec8Sopenharmony_ci 2250a46c0ec8Sopenharmony_ci add_source(ctx, libevdev_get_fd(d->evdev), evdev_dispatch, d); 2251a46c0ec8Sopenharmony_ci 2252a46c0ec8Sopenharmony_ci list_for_each(hidraw, &d->hidraw_devices, link) { 2253a46c0ec8Sopenharmony_ci add_source(ctx, hidraw->fd, hidraw_dispatch, hidraw); 2254a46c0ec8Sopenharmony_ci } 2255a46c0ec8Sopenharmony_ci } 2256a46c0ec8Sopenharmony_ci 2257a46c0ec8Sopenharmony_ci if (ctx->libinput) { 2258a46c0ec8Sopenharmony_ci /* See the note in the dispatch function */ 2259a46c0ec8Sopenharmony_ci add_source(ctx, 2260a46c0ec8Sopenharmony_ci libinput_get_fd(ctx->libinput), 2261a46c0ec8Sopenharmony_ci libinput_ctx_dispatch, 2262a46c0ec8Sopenharmony_ci NULL); 2263a46c0ec8Sopenharmony_ci } 2264a46c0ec8Sopenharmony_ci 2265a46c0ec8Sopenharmony_ci /* If we have more than one device, the time starts at recording 2266a46c0ec8Sopenharmony_ci * start time. Otherwise, the first event starts the recording time. 2267a46c0ec8Sopenharmony_ci */ 2268a46c0ec8Sopenharmony_ci if (ctx->ndevices > 1) { 2269a46c0ec8Sopenharmony_ci struct timespec ts; 2270a46c0ec8Sopenharmony_ci 2271a46c0ec8Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &ts); 2272a46c0ec8Sopenharmony_ci ctx->offset = s2us(ts.tv_sec) + ns2us(ts.tv_nsec); 2273a46c0ec8Sopenharmony_ci } 2274a46c0ec8Sopenharmony_ci 2275a46c0ec8Sopenharmony_ci do { 2276a46c0ec8Sopenharmony_ci struct record_device *d; 2277a46c0ec8Sopenharmony_ci 2278a46c0ec8Sopenharmony_ci if (!open_output_files(ctx, autorestart)) { 2279a46c0ec8Sopenharmony_ci fprintf(stderr, 2280a46c0ec8Sopenharmony_ci "Failed to open '%s'\n", 2281a46c0ec8Sopenharmony_ci ctx->output_file.name_with_suffix); 2282a46c0ec8Sopenharmony_ci break; 2283a46c0ec8Sopenharmony_ci } 2284a46c0ec8Sopenharmony_ci fprintf(stderr, "%sRecording to '%s'.\n", 2285a46c0ec8Sopenharmony_ci isatty(STDERR_FILENO) ? "" : "# ", 2286a46c0ec8Sopenharmony_ci ctx->output_file.name_with_suffix); 2287a46c0ec8Sopenharmony_ci 2288a46c0ec8Sopenharmony_ci ctx->had_events = false; 2289a46c0ec8Sopenharmony_ci 2290a46c0ec8Sopenharmony_ci print_header(ctx->first_device->fp, ctx); 2291a46c0ec8Sopenharmony_ci if (autorestart) 2292a46c0ec8Sopenharmony_ci iprintf(ctx->first_device->fp, 2293a46c0ec8Sopenharmony_ci I_NONE, 2294a46c0ec8Sopenharmony_ci "# Autorestart timeout: %d\n", 2295a46c0ec8Sopenharmony_ci ctx->timeout); 2296a46c0ec8Sopenharmony_ci 2297a46c0ec8Sopenharmony_ci iprintf(ctx->first_device->fp, I_TOPLEVEL, "devices:\n"); 2298a46c0ec8Sopenharmony_ci 2299a46c0ec8Sopenharmony_ci /* we only print the first device's description, the 2300a46c0ec8Sopenharmony_ci * rest is assembled after CTRL+C */ 2301a46c0ec8Sopenharmony_ci list_for_each(d, &ctx->devices, link) { 2302a46c0ec8Sopenharmony_ci print_device_description(d); 2303a46c0ec8Sopenharmony_ci iprintf(d->fp, I_DEVICE, "events:\n"); 2304a46c0ec8Sopenharmony_ci } 2305a46c0ec8Sopenharmony_ci print_wall_time(ctx); 2306a46c0ec8Sopenharmony_ci 2307a46c0ec8Sopenharmony_ci if (ctx->libinput) { 2308a46c0ec8Sopenharmony_ci libinput_dispatch(ctx->libinput); 2309a46c0ec8Sopenharmony_ci handle_libinput_events(ctx, ctx->first_device, true); 2310a46c0ec8Sopenharmony_ci } 2311a46c0ec8Sopenharmony_ci 2312a46c0ec8Sopenharmony_ci while (true) { 2313a46c0ec8Sopenharmony_ci int rc = dispatch_sources(ctx); 2314a46c0ec8Sopenharmony_ci if (rc < 0) { /* error */ 2315a46c0ec8Sopenharmony_ci fprintf(stderr, "Error: %s\n", strerror(-rc)); 2316a46c0ec8Sopenharmony_ci ctx->stop = true; 2317a46c0ec8Sopenharmony_ci break; 2318a46c0ec8Sopenharmony_ci } 2319a46c0ec8Sopenharmony_ci 2320a46c0ec8Sopenharmony_ci /* set by the signalfd handler */ 2321a46c0ec8Sopenharmony_ci if (ctx->stop) 2322a46c0ec8Sopenharmony_ci break; 2323a46c0ec8Sopenharmony_ci 2324a46c0ec8Sopenharmony_ci if (rc == 0) { 2325a46c0ec8Sopenharmony_ci fprintf(stderr, 2326a46c0ec8Sopenharmony_ci " ... timeout%s\n", 2327a46c0ec8Sopenharmony_ci ctx->had_events ? "" : " (file is empty)"); 2328a46c0ec8Sopenharmony_ci break; 2329a46c0ec8Sopenharmony_ci 2330a46c0ec8Sopenharmony_ci } 2331a46c0ec8Sopenharmony_ci 2332a46c0ec8Sopenharmony_ci if (ctx->first_device->fp != stdout) 2333a46c0ec8Sopenharmony_ci print_progress_bar(); 2334a46c0ec8Sopenharmony_ci 2335a46c0ec8Sopenharmony_ci } 2336a46c0ec8Sopenharmony_ci 2337a46c0ec8Sopenharmony_ci if (autorestart) { 2338a46c0ec8Sopenharmony_ci list_for_each(d, &ctx->devices, link) { 2339a46c0ec8Sopenharmony_ci iprintf(d->fp, 2340a46c0ec8Sopenharmony_ci I_NONE, 2341a46c0ec8Sopenharmony_ci "# Closing after %ds inactivity", 2342a46c0ec8Sopenharmony_ci ctx->timeout/1000); 2343a46c0ec8Sopenharmony_ci } 2344a46c0ec8Sopenharmony_ci } 2345a46c0ec8Sopenharmony_ci 2346a46c0ec8Sopenharmony_ci /* First device is printed, now append all the data from the 2347a46c0ec8Sopenharmony_ci * other devices, if any */ 2348a46c0ec8Sopenharmony_ci list_for_each(d, &ctx->devices, link) { 2349a46c0ec8Sopenharmony_ci char buf[4096]; 2350a46c0ec8Sopenharmony_ci size_t n; 2351a46c0ec8Sopenharmony_ci 2352a46c0ec8Sopenharmony_ci if (d == ctx->first_device) 2353a46c0ec8Sopenharmony_ci continue; 2354a46c0ec8Sopenharmony_ci 2355a46c0ec8Sopenharmony_ci rewind(d->fp); 2356a46c0ec8Sopenharmony_ci do { 2357a46c0ec8Sopenharmony_ci 2358a46c0ec8Sopenharmony_ci n = fread(buf, 1, sizeof(buf), d->fp); 2359a46c0ec8Sopenharmony_ci if (n > 0) 2360a46c0ec8Sopenharmony_ci fwrite(buf, 1, n, ctx->first_device->fp); 2361a46c0ec8Sopenharmony_ci } while (n == sizeof(buf)); 2362a46c0ec8Sopenharmony_ci 2363a46c0ec8Sopenharmony_ci fclose(d->fp); 2364a46c0ec8Sopenharmony_ci d->fp = NULL; 2365a46c0ec8Sopenharmony_ci } 2366a46c0ec8Sopenharmony_ci 2367a46c0ec8Sopenharmony_ci /* If we didn't have events, delete the file. */ 2368a46c0ec8Sopenharmony_ci if (!isatty(fileno(ctx->first_device->fp))) { 2369a46c0ec8Sopenharmony_ci struct record_device *d; 2370a46c0ec8Sopenharmony_ci 2371a46c0ec8Sopenharmony_ci if (!ctx->had_events && ctx->output_file.name_with_suffix) { 2372a46c0ec8Sopenharmony_ci fprintf(stderr, 2373a46c0ec8Sopenharmony_ci "No events recorded, deleting '%s'\n", 2374a46c0ec8Sopenharmony_ci ctx->output_file.name_with_suffix); 2375a46c0ec8Sopenharmony_ci unlink(ctx->output_file.name_with_suffix); 2376a46c0ec8Sopenharmony_ci } 2377a46c0ec8Sopenharmony_ci 2378a46c0ec8Sopenharmony_ci list_for_each(d, &ctx->devices, link) { 2379a46c0ec8Sopenharmony_ci if (d->fp && d->fp != stdout) { 2380a46c0ec8Sopenharmony_ci fclose(d->fp); 2381a46c0ec8Sopenharmony_ci d->fp = NULL; 2382a46c0ec8Sopenharmony_ci } 2383a46c0ec8Sopenharmony_ci } 2384a46c0ec8Sopenharmony_ci } 2385a46c0ec8Sopenharmony_ci free(ctx->output_file.name_with_suffix); 2386a46c0ec8Sopenharmony_ci ctx->output_file.name_with_suffix = NULL; 2387a46c0ec8Sopenharmony_ci } while (autorestart && !ctx->stop); 2388a46c0ec8Sopenharmony_ci 2389a46c0ec8Sopenharmony_ci sigprocmask(SIG_UNBLOCK, &mask, NULL); 2390a46c0ec8Sopenharmony_ci 2391a46c0ec8Sopenharmony_ci list_for_each_safe(source, &ctx->sources, link) { 2392a46c0ec8Sopenharmony_ci destroy_source(ctx, source); 2393a46c0ec8Sopenharmony_ci } 2394a46c0ec8Sopenharmony_ci close(ctx->epoll_fd); 2395a46c0ec8Sopenharmony_ci 2396a46c0ec8Sopenharmony_ci return 0; 2397a46c0ec8Sopenharmony_ci} 2398a46c0ec8Sopenharmony_ci 2399a46c0ec8Sopenharmony_cistatic bool 2400a46c0ec8Sopenharmony_ciinit_device(struct record_context *ctx, const char *path, bool grab) 2401a46c0ec8Sopenharmony_ci{ 2402a46c0ec8Sopenharmony_ci struct record_device *d; 2403a46c0ec8Sopenharmony_ci int fd, rc; 2404a46c0ec8Sopenharmony_ci 2405a46c0ec8Sopenharmony_ci d = zalloc(sizeof(*d)); 2406a46c0ec8Sopenharmony_ci d->ctx = ctx; 2407a46c0ec8Sopenharmony_ci d->devnode = safe_strdup(path); 2408a46c0ec8Sopenharmony_ci 2409a46c0ec8Sopenharmony_ci list_init(&d->hidraw_devices); 2410a46c0ec8Sopenharmony_ci 2411a46c0ec8Sopenharmony_ci fd = open(d->devnode, O_RDONLY|O_NONBLOCK); 2412a46c0ec8Sopenharmony_ci if (fd < 0) { 2413a46c0ec8Sopenharmony_ci fprintf(stderr, 2414a46c0ec8Sopenharmony_ci "Failed to open device %s (%m)\n", 2415a46c0ec8Sopenharmony_ci d->devnode); 2416a46c0ec8Sopenharmony_ci goto error; 2417a46c0ec8Sopenharmony_ci } 2418a46c0ec8Sopenharmony_ci 2419a46c0ec8Sopenharmony_ci rc = libevdev_new_from_fd(fd, &d->evdev); 2420a46c0ec8Sopenharmony_ci if (rc == 0) 2421a46c0ec8Sopenharmony_ci rc = libevdev_new_from_fd(fd, &d->evdev_prev); 2422a46c0ec8Sopenharmony_ci if (rc != 0) { 2423a46c0ec8Sopenharmony_ci fprintf(stderr, 2424a46c0ec8Sopenharmony_ci "Failed to create context for %s (%s)\n", 2425a46c0ec8Sopenharmony_ci d->devnode, 2426a46c0ec8Sopenharmony_ci strerror(-rc)); 2427a46c0ec8Sopenharmony_ci goto error; 2428a46c0ec8Sopenharmony_ci } 2429a46c0ec8Sopenharmony_ci 2430a46c0ec8Sopenharmony_ci if (grab) { 2431a46c0ec8Sopenharmony_ci rc = libevdev_grab(d->evdev, LIBEVDEV_GRAB); 2432a46c0ec8Sopenharmony_ci if (rc != 0) { 2433a46c0ec8Sopenharmony_ci fprintf(stderr, 2434a46c0ec8Sopenharmony_ci "Grab failed on %s: %s\n", 2435a46c0ec8Sopenharmony_ci path, 2436a46c0ec8Sopenharmony_ci strerror(-rc)); 2437a46c0ec8Sopenharmony_ci goto error; 2438a46c0ec8Sopenharmony_ci } 2439a46c0ec8Sopenharmony_ci } 2440a46c0ec8Sopenharmony_ci 2441a46c0ec8Sopenharmony_ci libevdev_set_clock_id(d->evdev, CLOCK_MONOTONIC); 2442a46c0ec8Sopenharmony_ci 2443a46c0ec8Sopenharmony_ci if (libevdev_get_num_slots(d->evdev) > 0) 2444a46c0ec8Sopenharmony_ci d->touch.is_touch_device = true; 2445a46c0ec8Sopenharmony_ci 2446a46c0ec8Sopenharmony_ci list_append(&ctx->devices, &d->link); 2447a46c0ec8Sopenharmony_ci if (!ctx->first_device) 2448a46c0ec8Sopenharmony_ci ctx->first_device = d; 2449a46c0ec8Sopenharmony_ci ctx->ndevices++; 2450a46c0ec8Sopenharmony_ci 2451a46c0ec8Sopenharmony_ci return true; 2452a46c0ec8Sopenharmony_cierror: 2453a46c0ec8Sopenharmony_ci close(fd); 2454a46c0ec8Sopenharmony_ci free(d); 2455a46c0ec8Sopenharmony_ci return false; 2456a46c0ec8Sopenharmony_ci 2457a46c0ec8Sopenharmony_ci} 2458a46c0ec8Sopenharmony_cistatic int 2459a46c0ec8Sopenharmony_ciopen_restricted(const char *path, int flags, void *user_data) 2460a46c0ec8Sopenharmony_ci{ 2461a46c0ec8Sopenharmony_ci int fd = open(path, flags); 2462a46c0ec8Sopenharmony_ci return fd == -1 ? -errno : fd; 2463a46c0ec8Sopenharmony_ci} 2464a46c0ec8Sopenharmony_ci 2465a46c0ec8Sopenharmony_cistatic void close_restricted(int fd, void *user_data) 2466a46c0ec8Sopenharmony_ci{ 2467a46c0ec8Sopenharmony_ci close(fd); 2468a46c0ec8Sopenharmony_ci} 2469a46c0ec8Sopenharmony_ci 2470a46c0ec8Sopenharmony_cistatic const struct libinput_interface interface = { 2471a46c0ec8Sopenharmony_ci .open_restricted = open_restricted, 2472a46c0ec8Sopenharmony_ci .close_restricted = close_restricted, 2473a46c0ec8Sopenharmony_ci}; 2474a46c0ec8Sopenharmony_ci 2475a46c0ec8Sopenharmony_cistatic bool 2476a46c0ec8Sopenharmony_ciinit_libinput(struct record_context *ctx) 2477a46c0ec8Sopenharmony_ci{ 2478a46c0ec8Sopenharmony_ci struct record_device *dev; 2479a46c0ec8Sopenharmony_ci struct libinput *li; 2480a46c0ec8Sopenharmony_ci 2481a46c0ec8Sopenharmony_ci li = libinput_path_create_context(&interface, NULL); 2482a46c0ec8Sopenharmony_ci if (li == NULL) { 2483a46c0ec8Sopenharmony_ci fprintf(stderr, 2484a46c0ec8Sopenharmony_ci "Failed to create libinput context\n"); 2485a46c0ec8Sopenharmony_ci return false; 2486a46c0ec8Sopenharmony_ci } 2487a46c0ec8Sopenharmony_ci 2488a46c0ec8Sopenharmony_ci ctx->libinput = li; 2489a46c0ec8Sopenharmony_ci 2490a46c0ec8Sopenharmony_ci list_for_each(dev, &ctx->devices, link) { 2491a46c0ec8Sopenharmony_ci struct libinput_device *d; 2492a46c0ec8Sopenharmony_ci 2493a46c0ec8Sopenharmony_ci d = libinput_path_add_device(li, dev->devnode); 2494a46c0ec8Sopenharmony_ci if (!d) { 2495a46c0ec8Sopenharmony_ci fprintf(stderr, 2496a46c0ec8Sopenharmony_ci "Failed to add device %s\n", 2497a46c0ec8Sopenharmony_ci dev->devnode); 2498a46c0ec8Sopenharmony_ci continue; 2499a46c0ec8Sopenharmony_ci } 2500a46c0ec8Sopenharmony_ci dev->device = libinput_device_ref(d); 2501a46c0ec8Sopenharmony_ci /* FIXME: this needs to be a commandline option */ 2502a46c0ec8Sopenharmony_ci libinput_device_config_tap_set_enabled(d, 2503a46c0ec8Sopenharmony_ci LIBINPUT_CONFIG_TAP_ENABLED); 2504a46c0ec8Sopenharmony_ci } 2505a46c0ec8Sopenharmony_ci 2506a46c0ec8Sopenharmony_ci return true; 2507a46c0ec8Sopenharmony_ci} 2508a46c0ec8Sopenharmony_ci 2509a46c0ec8Sopenharmony_cistatic bool 2510a46c0ec8Sopenharmony_ciinit_hidraw(struct record_context *ctx) 2511a46c0ec8Sopenharmony_ci{ 2512a46c0ec8Sopenharmony_ci struct record_device *dev; 2513a46c0ec8Sopenharmony_ci 2514a46c0ec8Sopenharmony_ci list_for_each(dev, &ctx->devices, link) { 2515a46c0ec8Sopenharmony_ci char syspath[PATH_MAX]; 2516a46c0ec8Sopenharmony_ci DIR *dir; 2517a46c0ec8Sopenharmony_ci struct dirent *entry; 2518a46c0ec8Sopenharmony_ci 2519a46c0ec8Sopenharmony_ci snprintf(syspath, 2520a46c0ec8Sopenharmony_ci sizeof(syspath), 2521a46c0ec8Sopenharmony_ci "/sys/class/input/%s/device/device/hidraw", 2522a46c0ec8Sopenharmony_ci safe_basename(dev->devnode)); 2523a46c0ec8Sopenharmony_ci dir = opendir(syspath); 2524a46c0ec8Sopenharmony_ci if (!dir) 2525a46c0ec8Sopenharmony_ci continue; 2526a46c0ec8Sopenharmony_ci 2527a46c0ec8Sopenharmony_ci while ((entry = readdir(dir))) { 2528a46c0ec8Sopenharmony_ci char hidraw_node[PATH_MAX]; 2529a46c0ec8Sopenharmony_ci int fd; 2530a46c0ec8Sopenharmony_ci struct hidraw *hidraw = NULL; 2531a46c0ec8Sopenharmony_ci 2532a46c0ec8Sopenharmony_ci if (!strstartswith(entry->d_name, "hidraw")) 2533a46c0ec8Sopenharmony_ci continue; 2534a46c0ec8Sopenharmony_ci 2535a46c0ec8Sopenharmony_ci snprintf(hidraw_node, 2536a46c0ec8Sopenharmony_ci sizeof(hidraw_node), 2537a46c0ec8Sopenharmony_ci "/dev/%s", 2538a46c0ec8Sopenharmony_ci entry->d_name); 2539a46c0ec8Sopenharmony_ci fd = open(hidraw_node, O_RDONLY|O_NONBLOCK); 2540a46c0ec8Sopenharmony_ci if (fd == -1) 2541a46c0ec8Sopenharmony_ci continue; 2542a46c0ec8Sopenharmony_ci 2543a46c0ec8Sopenharmony_ci hidraw = zalloc(sizeof(*hidraw)); 2544a46c0ec8Sopenharmony_ci hidraw->fd = fd; 2545a46c0ec8Sopenharmony_ci hidraw->name = safe_strdup(entry->d_name); 2546a46c0ec8Sopenharmony_ci hidraw->device = dev; 2547a46c0ec8Sopenharmony_ci list_insert(&dev->hidraw_devices, &hidraw->link); 2548a46c0ec8Sopenharmony_ci } 2549a46c0ec8Sopenharmony_ci closedir(dir); 2550a46c0ec8Sopenharmony_ci } 2551a46c0ec8Sopenharmony_ci 2552a46c0ec8Sopenharmony_ci return true; 2553a46c0ec8Sopenharmony_ci} 2554a46c0ec8Sopenharmony_ci 2555a46c0ec8Sopenharmony_cistatic void 2556a46c0ec8Sopenharmony_ciusage(void) 2557a46c0ec8Sopenharmony_ci{ 2558a46c0ec8Sopenharmony_ci printf("Usage: %s [--help] [--all] [--autorestart] [--output-file filename] [/dev/input/event0] [...]\n" 2559a46c0ec8Sopenharmony_ci "Common use-cases:\n" 2560a46c0ec8Sopenharmony_ci "\n" 2561a46c0ec8Sopenharmony_ci " sudo %s -o recording.yml\n" 2562a46c0ec8Sopenharmony_ci " Then select the device to record and it Ctrl+C to stop.\n" 2563a46c0ec8Sopenharmony_ci " The recorded data is in recording.yml and can be attached to a bug report.\n" 2564a46c0ec8Sopenharmony_ci "\n" 2565a46c0ec8Sopenharmony_ci " sudo %s -o recording.yml --autorestart 2\n" 2566a46c0ec8Sopenharmony_ci " As above, but restarts after 2s of inactivity on the device.\n" 2567a46c0ec8Sopenharmony_ci " Note, the output file is only the prefix.\n" 2568a46c0ec8Sopenharmony_ci "\n" 2569a46c0ec8Sopenharmony_ci " sudo %s -o recording.yml /dev/input/event3 /dev/input/event4\n" 2570a46c0ec8Sopenharmony_ci " Records the two devices into the same recordings file.\n" 2571a46c0ec8Sopenharmony_ci "\n" 2572a46c0ec8Sopenharmony_ci "For more information, see the %s(1) man page\n", 2573a46c0ec8Sopenharmony_ci program_invocation_short_name, 2574a46c0ec8Sopenharmony_ci program_invocation_short_name, 2575a46c0ec8Sopenharmony_ci program_invocation_short_name, 2576a46c0ec8Sopenharmony_ci program_invocation_short_name, 2577a46c0ec8Sopenharmony_ci program_invocation_short_name); 2578a46c0ec8Sopenharmony_ci} 2579a46c0ec8Sopenharmony_ci 2580a46c0ec8Sopenharmony_cienum ftype { 2581a46c0ec8Sopenharmony_ci F_FILE = 8, 2582a46c0ec8Sopenharmony_ci F_DEVICE, 2583a46c0ec8Sopenharmony_ci F_NOEXIST, 2584a46c0ec8Sopenharmony_ci}; 2585a46c0ec8Sopenharmony_ci 2586a46c0ec8Sopenharmony_cistatic enum ftype 2587a46c0ec8Sopenharmony_ciis_char_dev(const char *path) 2588a46c0ec8Sopenharmony_ci{ 2589a46c0ec8Sopenharmony_ci struct stat st; 2590a46c0ec8Sopenharmony_ci 2591a46c0ec8Sopenharmony_ci if (strneq(path, "/dev", 4)) 2592a46c0ec8Sopenharmony_ci return F_DEVICE; 2593a46c0ec8Sopenharmony_ci 2594a46c0ec8Sopenharmony_ci if (stat(path, &st) != 0) { 2595a46c0ec8Sopenharmony_ci if (errno == ENOENT) 2596a46c0ec8Sopenharmony_ci return F_NOEXIST; 2597a46c0ec8Sopenharmony_ci return F_FILE; 2598a46c0ec8Sopenharmony_ci } 2599a46c0ec8Sopenharmony_ci 2600a46c0ec8Sopenharmony_ci return S_ISCHR(st.st_mode) ? F_DEVICE : F_FILE; 2601a46c0ec8Sopenharmony_ci} 2602a46c0ec8Sopenharmony_ci 2603a46c0ec8Sopenharmony_cienum fposition { 2604a46c0ec8Sopenharmony_ci ERROR, 2605a46c0ec8Sopenharmony_ci NO_FILE, 2606a46c0ec8Sopenharmony_ci FIRST, 2607a46c0ec8Sopenharmony_ci LAST, 2608a46c0ec8Sopenharmony_ci}; 2609a46c0ec8Sopenharmony_ci 2610a46c0ec8Sopenharmony_cistatic enum fposition 2611a46c0ec8Sopenharmony_cifind_output_file(int argc, char *argv[], const char **output_file) 2612a46c0ec8Sopenharmony_ci{ 2613a46c0ec8Sopenharmony_ci char *first, *last; 2614a46c0ec8Sopenharmony_ci enum ftype ftype_first, ftype_last; 2615a46c0ec8Sopenharmony_ci 2616a46c0ec8Sopenharmony_ci first = argv[0]; 2617a46c0ec8Sopenharmony_ci 2618a46c0ec8Sopenharmony_ci ftype_first = is_char_dev(first); 2619a46c0ec8Sopenharmony_ci if (argc == 1) { 2620a46c0ec8Sopenharmony_ci /* arg is *not* a char device, so let's assume it's 2621a46c0ec8Sopenharmony_ci * the output file */ 2622a46c0ec8Sopenharmony_ci if (ftype_first != F_DEVICE) { 2623a46c0ec8Sopenharmony_ci *output_file = first; 2624a46c0ec8Sopenharmony_ci return FIRST; 2625a46c0ec8Sopenharmony_ci } 2626a46c0ec8Sopenharmony_ci } 2627a46c0ec8Sopenharmony_ci 2628a46c0ec8Sopenharmony_ci /* multiple arguments, yay */ 2629a46c0ec8Sopenharmony_ci last = argv[argc - 1]; 2630a46c0ec8Sopenharmony_ci ftype_last = is_char_dev(last); 2631a46c0ec8Sopenharmony_ci /* 2632a46c0ec8Sopenharmony_ci first is device, last is file -> last 2633a46c0ec8Sopenharmony_ci first is device, last is device -> noop 2634a46c0ec8Sopenharmony_ci first is device, last !exist -> last 2635a46c0ec8Sopenharmony_ci first is file, last is device -> first 2636a46c0ec8Sopenharmony_ci first is file, last is file -> error 2637a46c0ec8Sopenharmony_ci first is file, last !exist -> error 2638a46c0ec8Sopenharmony_ci first !exist, last is device -> first 2639a46c0ec8Sopenharmony_ci first !exist, last is file -> error 2640a46c0ec8Sopenharmony_ci first !exit, last !exist -> error 2641a46c0ec8Sopenharmony_ci */ 2642a46c0ec8Sopenharmony_ci#define _m(f, l) (((f) << 8) | (l)) 2643a46c0ec8Sopenharmony_ci switch (_m(ftype_first, ftype_last)) { 2644a46c0ec8Sopenharmony_ci case _m(F_FILE, F_DEVICE): 2645a46c0ec8Sopenharmony_ci case _m(F_FILE, F_NOEXIST): 2646a46c0ec8Sopenharmony_ci case _m(F_NOEXIST, F_DEVICE): 2647a46c0ec8Sopenharmony_ci *output_file = first; 2648a46c0ec8Sopenharmony_ci return FIRST; 2649a46c0ec8Sopenharmony_ci case _m(F_DEVICE, F_FILE): 2650a46c0ec8Sopenharmony_ci case _m(F_DEVICE, F_NOEXIST): 2651a46c0ec8Sopenharmony_ci *output_file = last; 2652a46c0ec8Sopenharmony_ci return LAST; 2653a46c0ec8Sopenharmony_ci case _m(F_DEVICE, F_DEVICE): 2654a46c0ec8Sopenharmony_ci break; 2655a46c0ec8Sopenharmony_ci case _m(F_FILE, F_FILE): 2656a46c0ec8Sopenharmony_ci case _m(F_NOEXIST, F_FILE): 2657a46c0ec8Sopenharmony_ci case _m(F_NOEXIST, F_NOEXIST): 2658a46c0ec8Sopenharmony_ci return ERROR; 2659a46c0ec8Sopenharmony_ci } 2660a46c0ec8Sopenharmony_ci#undef _m 2661a46c0ec8Sopenharmony_ci return NO_FILE; 2662a46c0ec8Sopenharmony_ci} 2663a46c0ec8Sopenharmony_ci 2664a46c0ec8Sopenharmony_cienum options { 2665a46c0ec8Sopenharmony_ci OPT_AUTORESTART, 2666a46c0ec8Sopenharmony_ci OPT_HELP, 2667a46c0ec8Sopenharmony_ci OPT_OUTFILE, 2668a46c0ec8Sopenharmony_ci OPT_KEYCODES, 2669a46c0ec8Sopenharmony_ci OPT_MULTIPLE, 2670a46c0ec8Sopenharmony_ci OPT_ALL, 2671a46c0ec8Sopenharmony_ci OPT_LIBINPUT, 2672a46c0ec8Sopenharmony_ci OPT_HIDRAW, 2673a46c0ec8Sopenharmony_ci OPT_GRAB, 2674a46c0ec8Sopenharmony_ci}; 2675a46c0ec8Sopenharmony_ci 2676a46c0ec8Sopenharmony_ciint 2677a46c0ec8Sopenharmony_cimain(int argc, char **argv) 2678a46c0ec8Sopenharmony_ci{ 2679a46c0ec8Sopenharmony_ci struct record_context ctx = { 2680a46c0ec8Sopenharmony_ci .timeout = -1, 2681a46c0ec8Sopenharmony_ci .show_keycodes = false, 2682a46c0ec8Sopenharmony_ci }; 2683a46c0ec8Sopenharmony_ci struct option opts[] = { 2684a46c0ec8Sopenharmony_ci { "autorestart", required_argument, 0, OPT_AUTORESTART }, 2685a46c0ec8Sopenharmony_ci { "output-file", required_argument, 0, OPT_OUTFILE }, 2686a46c0ec8Sopenharmony_ci { "show-keycodes", no_argument, 0, OPT_KEYCODES }, 2687a46c0ec8Sopenharmony_ci { "multiple", no_argument, 0, OPT_MULTIPLE }, 2688a46c0ec8Sopenharmony_ci { "all", no_argument, 0, OPT_ALL }, 2689a46c0ec8Sopenharmony_ci { "help", no_argument, 0, OPT_HELP }, 2690a46c0ec8Sopenharmony_ci { "with-libinput", no_argument, 0, OPT_LIBINPUT }, 2691a46c0ec8Sopenharmony_ci { "with-hidraw", no_argument, 0, OPT_HIDRAW }, 2692a46c0ec8Sopenharmony_ci { "grab", no_argument, 0, OPT_GRAB }, 2693a46c0ec8Sopenharmony_ci { 0, 0, 0, 0 }, 2694a46c0ec8Sopenharmony_ci }; 2695a46c0ec8Sopenharmony_ci struct record_device *d; 2696a46c0ec8Sopenharmony_ci const char *output_arg = NULL; 2697a46c0ec8Sopenharmony_ci bool all = false, 2698a46c0ec8Sopenharmony_ci with_libinput = false, 2699a46c0ec8Sopenharmony_ci with_hidraw = false, 2700a46c0ec8Sopenharmony_ci grab = false; 2701a46c0ec8Sopenharmony_ci int ndevices; 2702a46c0ec8Sopenharmony_ci int rc = EXIT_FAILURE; 2703a46c0ec8Sopenharmony_ci char **paths = NULL; 2704a46c0ec8Sopenharmony_ci 2705a46c0ec8Sopenharmony_ci list_init(&ctx.devices); 2706a46c0ec8Sopenharmony_ci list_init(&ctx.sources); 2707a46c0ec8Sopenharmony_ci 2708a46c0ec8Sopenharmony_ci while (1) { 2709a46c0ec8Sopenharmony_ci int c; 2710a46c0ec8Sopenharmony_ci int option_index = 0; 2711a46c0ec8Sopenharmony_ci 2712a46c0ec8Sopenharmony_ci c = getopt_long(argc, argv, "ho:", opts, &option_index); 2713a46c0ec8Sopenharmony_ci if (c == -1) 2714a46c0ec8Sopenharmony_ci break; 2715a46c0ec8Sopenharmony_ci 2716a46c0ec8Sopenharmony_ci switch (c) { 2717a46c0ec8Sopenharmony_ci case 'h': 2718a46c0ec8Sopenharmony_ci case OPT_HELP: 2719a46c0ec8Sopenharmony_ci usage(); 2720a46c0ec8Sopenharmony_ci rc = EXIT_SUCCESS; 2721a46c0ec8Sopenharmony_ci goto out; 2722a46c0ec8Sopenharmony_ci case OPT_AUTORESTART: 2723a46c0ec8Sopenharmony_ci if (!safe_atoi(optarg, &ctx.timeout) || 2724a46c0ec8Sopenharmony_ci ctx.timeout <= 0) { 2725a46c0ec8Sopenharmony_ci usage(); 2726a46c0ec8Sopenharmony_ci rc = EXIT_INVALID_USAGE; 2727a46c0ec8Sopenharmony_ci goto out; 2728a46c0ec8Sopenharmony_ci } 2729a46c0ec8Sopenharmony_ci ctx.timeout = ctx.timeout * 1000; 2730a46c0ec8Sopenharmony_ci break; 2731a46c0ec8Sopenharmony_ci case 'o': 2732a46c0ec8Sopenharmony_ci case OPT_OUTFILE: 2733a46c0ec8Sopenharmony_ci output_arg = optarg; 2734a46c0ec8Sopenharmony_ci break; 2735a46c0ec8Sopenharmony_ci case OPT_KEYCODES: 2736a46c0ec8Sopenharmony_ci ctx.show_keycodes = true; 2737a46c0ec8Sopenharmony_ci break; 2738a46c0ec8Sopenharmony_ci case OPT_MULTIPLE: /* deprecated */ 2739a46c0ec8Sopenharmony_ci break; 2740a46c0ec8Sopenharmony_ci case OPT_ALL: 2741a46c0ec8Sopenharmony_ci all = true; 2742a46c0ec8Sopenharmony_ci break; 2743a46c0ec8Sopenharmony_ci case OPT_LIBINPUT: 2744a46c0ec8Sopenharmony_ci with_libinput = true; 2745a46c0ec8Sopenharmony_ci break; 2746a46c0ec8Sopenharmony_ci case OPT_HIDRAW: 2747a46c0ec8Sopenharmony_ci with_hidraw = true; 2748a46c0ec8Sopenharmony_ci fprintf(stderr, "# WARNING: do not type passwords while recording HID reports\n"); 2749a46c0ec8Sopenharmony_ci break; 2750a46c0ec8Sopenharmony_ci case OPT_GRAB: 2751a46c0ec8Sopenharmony_ci grab = true; 2752a46c0ec8Sopenharmony_ci break; 2753a46c0ec8Sopenharmony_ci default: 2754a46c0ec8Sopenharmony_ci usage(); 2755a46c0ec8Sopenharmony_ci rc = EXIT_INVALID_USAGE; 2756a46c0ec8Sopenharmony_ci goto out; 2757a46c0ec8Sopenharmony_ci } 2758a46c0ec8Sopenharmony_ci } 2759a46c0ec8Sopenharmony_ci 2760a46c0ec8Sopenharmony_ci ndevices = argc - optind; 2761a46c0ec8Sopenharmony_ci 2762a46c0ec8Sopenharmony_ci /* We allow for multiple arguments after the options, *one* of which 2763a46c0ec8Sopenharmony_ci * may be the output file. That one must be the first or the last to 2764a46c0ec8Sopenharmony_ci * prevent users from running 2765a46c0ec8Sopenharmony_ci * libinput record /dev/input/event0 output.yml /dev/input/event1 2766a46c0ec8Sopenharmony_ci * because this will only backfire anyway. 2767a46c0ec8Sopenharmony_ci */ 2768a46c0ec8Sopenharmony_ci if (ndevices >= 1 && output_arg == NULL) { 2769a46c0ec8Sopenharmony_ci enum fposition pos = find_output_file(argc - optind, 2770a46c0ec8Sopenharmony_ci &argv[optind], 2771a46c0ec8Sopenharmony_ci &output_arg); 2772a46c0ec8Sopenharmony_ci if (pos == ERROR) { 2773a46c0ec8Sopenharmony_ci fprintf(stderr, 2774a46c0ec8Sopenharmony_ci "Ambiguous device vs output file list. " 2775a46c0ec8Sopenharmony_ci "Please use --output-file.\n"); 2776a46c0ec8Sopenharmony_ci return EXIT_INVALID_USAGE; 2777a46c0ec8Sopenharmony_ci } 2778a46c0ec8Sopenharmony_ci 2779a46c0ec8Sopenharmony_ci if (pos == FIRST || pos == LAST) 2780a46c0ec8Sopenharmony_ci ndevices--; 2781a46c0ec8Sopenharmony_ci if (pos == FIRST) 2782a46c0ec8Sopenharmony_ci optind++; 2783a46c0ec8Sopenharmony_ci } 2784a46c0ec8Sopenharmony_ci 2785a46c0ec8Sopenharmony_ci if (ctx.timeout > 0 && output_arg == NULL) { 2786a46c0ec8Sopenharmony_ci fprintf(stderr, 2787a46c0ec8Sopenharmony_ci "Option --autorestart requires --output-file\n"); 2788a46c0ec8Sopenharmony_ci rc = EXIT_INVALID_USAGE; 2789a46c0ec8Sopenharmony_ci goto out; 2790a46c0ec8Sopenharmony_ci } 2791a46c0ec8Sopenharmony_ci 2792a46c0ec8Sopenharmony_ci ctx.output_file.name = safe_strdup(output_arg); 2793a46c0ec8Sopenharmony_ci 2794a46c0ec8Sopenharmony_ci if (output_arg == NULL && (all || ndevices > 1)) { 2795a46c0ec8Sopenharmony_ci fprintf(stderr, 2796a46c0ec8Sopenharmony_ci "Recording multiple devices requires an output file\n"); 2797a46c0ec8Sopenharmony_ci rc = EXIT_INVALID_USAGE; 2798a46c0ec8Sopenharmony_ci goto out; 2799a46c0ec8Sopenharmony_ci } 2800a46c0ec8Sopenharmony_ci 2801a46c0ec8Sopenharmony_ci /* Now collect all device paths and init our device struct */ 2802a46c0ec8Sopenharmony_ci if (all) { 2803a46c0ec8Sopenharmony_ci paths = all_devices(); 2804a46c0ec8Sopenharmony_ci } else if (ndevices >= 1) { 2805a46c0ec8Sopenharmony_ci paths = strv_from_argv(ndevices, &argv[optind]); 2806a46c0ec8Sopenharmony_ci } else { 2807a46c0ec8Sopenharmony_ci char *path = select_device(); 2808a46c0ec8Sopenharmony_ci if (path == NULL) { 2809a46c0ec8Sopenharmony_ci goto out; 2810a46c0ec8Sopenharmony_ci } 2811a46c0ec8Sopenharmony_ci 2812a46c0ec8Sopenharmony_ci paths = strv_from_argv(1, &path); 2813a46c0ec8Sopenharmony_ci free(path); 2814a46c0ec8Sopenharmony_ci } 2815a46c0ec8Sopenharmony_ci 2816a46c0ec8Sopenharmony_ci for (char **p = paths; *p; p++) { 2817a46c0ec8Sopenharmony_ci if (!init_device(&ctx, *p, grab)) { 2818a46c0ec8Sopenharmony_ci goto out; 2819a46c0ec8Sopenharmony_ci } 2820a46c0ec8Sopenharmony_ci } 2821a46c0ec8Sopenharmony_ci 2822a46c0ec8Sopenharmony_ci if (with_libinput && !init_libinput(&ctx)) 2823a46c0ec8Sopenharmony_ci goto out; 2824a46c0ec8Sopenharmony_ci 2825a46c0ec8Sopenharmony_ci if (with_hidraw && !init_hidraw(&ctx)) 2826a46c0ec8Sopenharmony_ci goto out; 2827a46c0ec8Sopenharmony_ci 2828a46c0ec8Sopenharmony_ci rc = mainloop(&ctx); 2829a46c0ec8Sopenharmony_ciout: 2830a46c0ec8Sopenharmony_ci strv_free(paths); 2831a46c0ec8Sopenharmony_ci list_for_each_safe(d, &ctx.devices, link) { 2832a46c0ec8Sopenharmony_ci struct hidraw *hidraw; 2833a46c0ec8Sopenharmony_ci 2834a46c0ec8Sopenharmony_ci list_for_each_safe(hidraw, &d->hidraw_devices, link) { 2835a46c0ec8Sopenharmony_ci close(hidraw->fd); 2836a46c0ec8Sopenharmony_ci list_remove(&hidraw->link); 2837a46c0ec8Sopenharmony_ci free(hidraw->name); 2838a46c0ec8Sopenharmony_ci free(hidraw); 2839a46c0ec8Sopenharmony_ci } 2840a46c0ec8Sopenharmony_ci 2841a46c0ec8Sopenharmony_ci if (d->device) 2842a46c0ec8Sopenharmony_ci libinput_device_unref(d->device); 2843a46c0ec8Sopenharmony_ci free(d->devnode); 2844a46c0ec8Sopenharmony_ci libevdev_free(d->evdev); 2845a46c0ec8Sopenharmony_ci } 2846a46c0ec8Sopenharmony_ci 2847a46c0ec8Sopenharmony_ci libinput_unref(ctx.libinput); 2848a46c0ec8Sopenharmony_ci 2849a46c0ec8Sopenharmony_ci return rc; 2850a46c0ec8Sopenharmony_ci} 2851