From 050bca91a1e8dd2e46c219c0b282092cb053166c Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 7 Apr 2014 15:16:28 +1000 Subject: Drain all events before synchronizing after SYN_DROPPED The kernel ring buffer drops all events on SYN_DROPPED, but then continues to fill up again. So by the time we read the events, the kernel's client buffer is essentially like this: SYN_DROPPED, ev1, ev2, ev3, ...., evN The kernel's device state represents the device after evN, and that is what the ioctls return. For EV_KEY, EV_SND, EV_LED and EV_SW the kernel removes potential duplicates from the client buffer [1], it doesn't do so for EV_ABS. So we can't actually sync while there are events on the wire because the events represent an earlier state. So simply discard all events in the kernel buffer, synchronize, and then start processing again. We lose some granularity but at least the events are correct. [1] http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/drivers/input/evdev.c?id=483180281f0ac60d1138710eb21f4b9961901294 Signed-off-by: Peter Hutterer --- libevdev/libevdev.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'libevdev/libevdev.h') diff --git a/libevdev/libevdev.h b/libevdev/libevdev.h index 9ec1cb8..ef142ea 100644 --- a/libevdev/libevdev.h +++ b/libevdev/libevdev.h @@ -368,6 +368,51 @@ extern "C" { * The axis events do not reflect the position of a current touch point, a * client must take care not to generate a new touch point based on those * updates. + * + * Discarding events before synchronizing + * ===================================== + * + * The kernel implements the client buffer as a ring buffer. SYN_DROPPED + * events are handled when the buffer is full and a new event is received + * from a device. All existing events are discarded, a SYN_DROPPED is added + * to the buffer followed by the actual device event. Further events will be + * appended to the buffer until it is either read by the client, or filled + * again, at which point the sequence repeats. + * + * When the client reads the buffer, the buffer will thus always consist of + * exactly one SYN_DROPPED event followed by an unspecified number of real + * events. The data the ioctls return is the current state of the device, + * i.e. the state after all these events have been processed. For example, + * assume the buffer contains the following sequence: + * + * @code + EV_SYN SYN_DROPPED + EV_ABS ABS_X 1 + EV_SYN SYN_REPORT 0 + EV_ABS ABS_X 2 + EV_SYN SYN_REPORT 0 + EV_ABS ABS_X 3 + EV_SYN SYN_REPORT 0 + EV_ABS ABS_X 4 + EV_SYN SYN_REPORT 0 + EV_ABS ABS_X 5 + EV_SYN SYN_REPORT 0 + EV_ABS ABS_X 6 + EV_SYN SYN_REPORT 0 + * @endcode + * An ioctl at any time in this sequence will return a value of 6 for ABS_X. + * + * libevdev discards all events after a SYN_DROPPED to ensure the events + * during @ref LIBEVDEV_READ_FLAG_SYNC represent the last known state of the + * device. This loses some granularity of the events especially as the time + * between the SYN_DROPPED and the sync process increases. It does however + * avoid spurious cursor movements. In the above example, the event sequence + * by libevdev is: + * @code + EV_SYN SYN_DROPPED + EV_ABS ABS_X 6 + EV_SYN SYN_REPORT 0 + @endcode */ /** -- cgit v1.2.1