Hook up event processing to libevdev

This gives us the ability to handle SYN_DROPPED transparently to the caller.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Jonas Ådahl <jadahl@gmail.com>
This commit is contained in:
Peter Hutterer 2013-12-06 13:09:18 +10:00
parent f925cee8df
commit 0fea6226f1

View file

@ -29,7 +29,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <mtdev.h> #include <mtdev-plumbing.h>
#include <assert.h> #include <assert.h>
#include "libinput.h" #include "libinput.h"
@ -438,56 +438,83 @@ fallback_dispatch_create(void)
return dispatch; return dispatch;
} }
static void static inline void
evdev_process_events(struct evdev_device *device, evdev_process_event(struct evdev_device *device, struct input_event *e)
struct input_event *ev, int count)
{ {
struct evdev_dispatch *dispatch = device->dispatch; struct evdev_dispatch *dispatch = device->dispatch;
struct input_event *e, *end; uint32_t time = e->time.tv_sec * 1000 + e->time.tv_usec / 1000;
uint32_t time = 0;
e = ev; dispatch->interface->process(dispatch, device, e, time);
end = e + count; }
for (e = ev; e < end; e++) {
time = e->time.tv_sec * 1000 + e->time.tv_usec / 1000;
dispatch->interface->process(dispatch, device, e, time); static inline void
evdev_device_dispatch_one(struct evdev_device *device,
struct input_event *ev)
{
if (!device->mtdev) {
evdev_process_event(device, ev);
} else {
mtdev_put_event(device->mtdev, ev);
if (libevdev_event_is_code(ev, EV_SYN, SYN_REPORT)) {
while (!mtdev_empty(device->mtdev)) {
struct input_event e;
mtdev_get_event(device->mtdev, &e);
evdev_process_event(device, &e);
}
}
} }
} }
static int
evdev_sync_device(struct evdev_device *device)
{
struct input_event ev;
int rc;
do {
rc = libevdev_next_event(device->evdev,
LIBEVDEV_READ_FLAG_SYNC, &ev);
if (rc < 0)
break;
evdev_device_dispatch_one(device, &ev);
} while (rc == LIBEVDEV_READ_STATUS_SYNC);
return rc == -EAGAIN ? 0 : rc;
}
static void static void
evdev_device_dispatch(void *data) evdev_device_dispatch(void *data)
{ {
struct evdev_device *device = data; struct evdev_device *device = data;
struct libinput *libinput = device->base.seat->libinput; struct libinput *libinput = device->base.seat->libinput;
int fd = device->fd; struct input_event ev;
struct input_event ev[32]; int rc;
int len;
/* If the compositor is repainting, this function is called only once /* If the compositor is repainting, this function is called only once
* per frame and we have to process all the events available on the * per frame and we have to process all the events available on the
* fd, otherwise there will be input lag. */ * fd, otherwise there will be input lag. */
do { do {
if (device->mtdev) rc = libevdev_next_event(device->evdev,
len = mtdev_get(device->mtdev, fd, ev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
ARRAY_LENGTH(ev)) * if (rc == LIBEVDEV_READ_STATUS_SYNC) {
sizeof (struct input_event); /* send one more sync event so we handle all
else currently pending events before we sync up
len = read(fd, &ev, sizeof ev); to the current state */
ev.code = SYN_REPORT;
evdev_device_dispatch_one(device, &ev);
if (len < 0 || len % sizeof ev[0] != 0) { rc = evdev_sync_device(device);
if (len < 0 && errno != EAGAIN && errno != EINTR) { if (rc == 0)
libinput_remove_source(libinput, rc = LIBEVDEV_READ_STATUS_SUCCESS;
device->source); } else if (rc == LIBEVDEV_READ_STATUS_SUCCESS) {
device->source = NULL; evdev_device_dispatch_one(device, &ev);
}
return;
} }
} while (rc == LIBEVDEV_READ_STATUS_SUCCESS);
evdev_process_events(device, ev, len / sizeof ev[0]); if (rc != -EAGAIN && rc != -EINTR) {
libinput_remove_source(libinput, device->source);
} while (len > 0); device->source = NULL;
}
} }
static int static int