[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