[PATCH 7/9] evdev: queue events and process them only at EV_SYN time

Tiago Vignatti tiago.vignatti at intel.com
Mon Oct 24 07:42:20 PDT 2011


it fix a bug of buttons events being queuing up before motion ones, which
caused the behaviour of taps/clicks not being caught in the needed time. This
was tested with direct and indirect input devices.

Tested-by: Tiago Vignatti <tiago.vignatti at intel.com>
Signed-off-by: Tiago Vignatti <tiago.vignatti at intel.com>
---
 compositor/evdev.c |  188 +++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 165 insertions(+), 23 deletions(-)

diff --git a/compositor/evdev.c b/compositor/evdev.c
index 72247a6..b81e513 100644
--- a/compositor/evdev.c
+++ b/compositor/evdev.c
@@ -30,10 +30,23 @@
 
 #include "compositor.h"
 
+#define EVDEV_MAXQUEUE 32
+
 struct evdev_input {
 	struct wlsc_input_device base;
 };
 
+/* Event queue used to defer keyboard/button events until EV_SYN time. */
+struct evdev_event_queue {
+	enum {
+		EV_QUEUE_KEY,
+		EV_QUEUE_BTN,
+		EV_QUEUE_PROXIMITY,
+	} type;
+	int key;	/* May be either a key code or button number. */
+	int val;	/* State of the key/button; pressed or released. */
+};
+
 struct evdev_input_device {
 	struct evdev_input *master;
 	struct wl_event_source *source;
@@ -50,17 +63,122 @@ struct evdev_input_device {
 	int is_touchpad, old_x_value, old_y_value, reset_x_value, reset_y_value;
 	uint32_t time;
 
+	/* Event queue used to defer keyboard/button events until EV_SYN time */
+	int num_queue;
+	struct evdev_event_queue queue[EVDEV_MAXQUEUE];
+
 	uint32_t abs_queued, rel_queued;
 };
 
-static inline void
+static struct evdev_event_queue *
+evdev_next_in_queue(struct evdev_input_device *device)
+{
+	if (device->num_queue >= EVDEV_MAXQUEUE)
+	{
+		fprintf(stderr, "dropping event due to full queue!\n");
+		return NULL;
+	}
+
+	device->num_queue++;
+	return &device->queue[device->num_queue - 1];
+}
+
+static void
+evdev_queue_kbd(struct evdev_input_device *device, struct input_event *ev,
+		int value)
+{
+	struct evdev_event_queue *queue;
+
+	/* Filter all repeated events from device */
+	if (value == 2)
+		return;
+
+	if ((queue = evdev_next_in_queue(device)))
+	{
+		queue->type = EV_QUEUE_KEY;
+		queue->key = ev->code;
+		queue->val = value;
+	}
+}
+
+static void
+evdev_queue_button(struct evdev_input_device *device, int button, int value)
+{
+	struct evdev_event_queue *queue;
+
+	if ((queue = evdev_next_in_queue(device)))
+	{
+		queue->type = EV_QUEUE_BTN;
+		queue->key = button;
+		queue->val = value;
+	}
+}
+
+/* Return an index value for a given button event code and returns 0 on
+ * non-button event.
+ */
+static unsigned int
+evdev_button_event_to_number(int code)
+{
+	switch (code) {
+	/* Mouse buttons */
+	case BTN_LEFT:
+		return 1;
+	case BTN_MIDDLE:
+		return 2;
+	case BTN_RIGHT:
+		return 3;
+	case BTN_SIDE ... BTN_JOYSTICK - 1:
+		return 8 + code - BTN_SIDE;
+
+	/* Generic buttons */
+	case BTN_0 ... BTN_2:
+		return 1 + code - BTN_0;
+	case BTN_3 ... BTN_MOUSE - 1:
+		return 8 + code - BTN_3;
+
+	/* Tablet stylus buttons */
+	case BTN_TOUCH ... BTN_STYLUS2:
+		return 1 + code - BTN_TOUCH;
+
+	/* The rest */
+	default:
+		/* Ignore */
+		return 0;
+	}
+}
+
+/**
+ * Take a button input event and process it accordingly.
+ */
+static void
+evdev_process_button_event(struct evdev_input_device *device,
+			   struct input_event *ev)
+{
+	unsigned int button;
+	int value;
+
+	button = evdev_button_event_to_number(ev->code);
+
+	/* Get the signed value, earlier kernels had this as unsigned */
+	value = ev->value;
+
+	if (button)
+		evdev_queue_button(device, ev->code, value);
+	else
+		evdev_queue_kbd(device, ev, value);
+}
+
+static void
 evdev_process_key(struct evdev_input_device *device, struct input_event *e)
 {
 	/* Get the signed value, earlier kernels had this as unsigned */
 	int value = e->value;
 
-	if (value == 2)
-		return;
+	/* don't repeat mouse buttons */
+	if (e->code >= BTN_MOUSE && e->code < KEY_OK)
+		if (value == 2)
+			return;
 
 	switch (e->code) {
 	case BTN_TOOL_PEN:
@@ -83,21 +201,8 @@ evdev_process_key(struct evdev_input_device *device, struct input_event *e)
 		 * BTN_LEFT */
 		e->code = BTN_LEFT;
 		/* Intentional fallthrough! */
-	case BTN_LEFT:
-	case BTN_RIGHT:
-	case BTN_MIDDLE:
-	case BTN_SIDE:
-	case BTN_EXTRA:
-	case BTN_FORWARD:
-	case BTN_BACK:
-	case BTN_TASK:
-		notify_button(&device->master->base.input_device,
-			      device->time, e->code, value);
-		break;
-
 	default:
-		notify_key(&device->master->base.input_device,
-			   device->time, e->code, value);
+		evdev_process_button_event(device, e);
 		break;
 	}
 }
@@ -181,8 +286,35 @@ evdev_process_relative_motion(struct evdev_input_device *device,
 	device->rel_queued = 1;
 }
 
-static inline void
-evdev_notify(struct evdev_input_device *device, struct input_event *e)
+static void
+evdev_process_queued(struct evdev_input_device *device)
+{
+	int i;
+
+	for (i = 0; i < device->num_queue; i++) {
+		switch (device->queue[i].type) {
+		case EV_QUEUE_KEY:
+			notify_key(&device->master->base.input_device,
+				   device->time, device->queue[i].key,
+				   device->queue[i].val);
+			break;
+		case EV_QUEUE_BTN:
+			notify_button(&device->master->base.input_device,
+				      device->time, device->queue[i].key,
+				      device->queue[i].val);
+			break;
+		case EV_QUEUE_PROXIMITY:
+			break;
+		}
+	}
+}
+
+/**
+ * Take the synchronization input event and process it accordingly; the motion
+ * notify events are sent first, then any button/key press/release events.
+ */
+static void
+evdev_process_sync(struct evdev_input_device *device, struct input_event *e)
 {
 	if (device->rel_queued)
                notify_motion(&device->master->base.input_device,
@@ -193,11 +325,19 @@ evdev_notify(struct evdev_input_device *device, struct input_event *e)
 		notify_motion(&device->master->base.input_device,
 			      device->time, device->x, device->y);
 
+	evdev_process_queued(device);
 
+	device->num_queue = 0;
 	device->rel_queued = 0;
 	device->abs_queued = 0;
+	device->dx = 0;
+	device->dy = 0;
 }
 
+/**
+ * Process the events from the device; nothing is actually posted to the server
+ * until an EV_SYN event is received.
+ */
 static void
 evdev_process_event(struct evdev_input_device *device, struct input_event *e)
 {
@@ -216,9 +356,10 @@ evdev_process_event(struct evdev_input_device *device, struct input_event *e)
 	case EV_KEY:
 		evdev_process_key(device, e);
 		break;
+	case EV_SYN:
+		evdev_process_sync(device, e);
+		break;
 	}
-
-	evdev_notify(device, e);
 }
 
 #define NUM_EVENTS 16
@@ -236,8 +377,6 @@ evdev_input_device_data(int fd, uint32_t mask, void *data)
 	if (!ec->focus)
 		return 1;
 
-	device->dx = 0;
-	device->dy = 0;
 	device->x = device->master->base.input_device.x;
 	device->y = device->master->base.input_device.y;
 
@@ -331,6 +470,9 @@ evdev_input_device_create(struct evdev_input *master,
 	device = malloc(sizeof *device);
 	if (device == NULL)
 		return NULL;
+	device->dx = 0;
+	device->dy = 0;
+	device->num_queue = 0;
 
 	ec = (struct wlsc_compositor *) master->base.input_device.compositor;
 	device->output = 
-- 
1.7.5.4



More information about the wayland-devel mailing list