Thanks for the patch. it looks good, I have a few minor changes though, mostly style.
On Mon, Jul 20, 2009 at 10:15:55AM +0300, [email protected] wrote: > From: Oliver McFadden <[email protected]> > > Instead of just posting the button/key press/release events to the > server as soon as they arrive, add them to an internal queue and post > them once we receive an EV_SYN synchronization event. > > The motion events are always sent first, followed by the queued events. > There will be one motion event and possibly many queued button/key > events posted every EV_SYN event. > > Note that the size of the event queue (EVDEV_MAXQUEUE) is arbitrary and > you may change it. If we receive more events than the queue can handle, > those events are dropped and a warning message printed. > > Tested on my Lenovo T400 using evdev for all input devices; keyboard, > touchpad, and trackpoint. > --- > src/evdev.c | 563 > +++++++++++++++++++++++++++++++++++++++-------------------- > src/evdev.h | 17 ++ > 2 files changed, 389 insertions(+), 191 deletions(-) > > diff --git a/src/evdev.c b/src/evdev.c > index ecca94a..2b1d3d8 100644 > --- a/src/evdev.c > +++ b/src/evdev.c > @@ -249,21 +249,12 @@ static int wheel_left_button = 6; > static int wheel_right_button = 7; > > static void > -PostButtonClicks(InputInfoPtr pInfo, int button, int count) > -{ > - int i; > - > - for (i = 0; i < count; i++) { > - xf86PostButtonEvent(pInfo->dev, 0, button, 1, 0, 0); > - xf86PostButtonEvent(pInfo->dev, 0, button, 0, 0, 0); > - } > -} > - > -static void > PostKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value) > { > int code = ev->code + MIN_KEYCODE; > static char warned[KEY_CNT]; > + EventQueuePtr event; the word 'event' is a bit overloaded, especially here where you have an input_event and a EventQueuePtr. I'd prefer something like "eq" or "queue_event". Looks awkward, but at least it's more obvious. Better naming suggestions are welcome. > + EvdevPtr pEvdev = pInfo->private; > > /* Filter all repeated events from device. > We'll do softrepeat in the server, but only since 1.6 */ > @@ -292,7 +283,51 @@ PostKbdEvent(InputInfoPtr pInfo, struct input_event *ev, > int value) > return; > } > > - xf86PostKeyboardEvent(pInfo->dev, code, value); > + if (pEvdev->num_queue >= EVDEV_MAXQUEUE) > + { > + xf86Msg(X_WARNING, We can't use X_WARNING here. the server may allocate memory for anything but X_NONE and this is called in the signal handler. This has been fixed in the server, but for now it's better to use X_NONE. > + "%s: dropping event due to full queue! (Consider increasing > EVDEV_MAXQUEUE)\n", Remove the (Consider ...) stuff. It becomes obvious when looking at the code and there's no reason to have that in the log. > + pInfo->name); > + return; > + } > + > + event = &pEvdev->queue[pEvdev->num_queue]; > + event->type = EV_QUEUE_KEY; > + event->key = code; > + event->val = value; > + pEvdev->num_queue++; > +} > + > +static void > +PostButtonEvent(InputInfoPtr pInfo, struct input_event *ev, int value) > +{ > + EventQueuePtr event; > + EvdevPtr pEvdev = pInfo->private; > + > + if (pEvdev->num_queue >= EVDEV_MAXQUEUE) > + { > + xf86Msg(X_WARNING, > + "%s: dropping event due to full queue! (Consider increasing > EVDEV_MAXQUEUE)\n", same as above, X_NONE, drop the (...). > + pInfo->name); > + return; > + } > + > + event = &pEvdev->queue[pEvdev->num_queue]; > + event->type = EV_QUEUE_BTN; > + event->key = EvdevUtilButtonEventToButtonNumber(pEvdev, ev->code); > + event->val = value; > + pEvdev->num_queue++; > +} > + > +static void > +PostButtonClicks(InputInfoPtr pInfo, struct input_event *ev, int button, int > count) > +{ > + int i; > + > + for (i = 0; i < count; i++) { > + PostButtonEvent(pInfo, ev, 1); > + PostButtonEvent(pInfo, ev, 0); > + } > } > > /** > @@ -349,212 +384,358 @@ EvdevReopenTimer(OsTimerPtr timer, CARD32 time, > pointer arg) > #define ABS_Y_VALUE 0x2 > #define ABS_VALUE 0x4 > /** > - * Take one input event and process it accordingly. > + * Take the valuators and process them accordingly. > */ > static void > -EvdevProcessEvent(InputInfoPtr pInfo, struct input_event *ev) > +EvdevProcessValuators(InputInfoPtr pInfo, int v[MAX_VALUATORS], int *num_v, > + int *first_v) > +{ > + int tmp; > + EvdevPtr pEvdev = pInfo->private; > + > + *num_v = *first_v = 0; > + > + /* convert to relative motion for touchpads */ > + if (pEvdev->abs && (pEvdev->flags & EVDEV_TOUCHPAD)) { > + if (pEvdev->tool) { /* meaning, touch is active */ > + if (pEvdev->old_vals[0] != -1) > + pEvdev->delta[REL_X] = pEvdev->vals[0] - pEvdev->old_vals[0]; > + if (pEvdev->old_vals[1] != -1) > + pEvdev->delta[REL_Y] = pEvdev->vals[1] - pEvdev->old_vals[1]; > + if (pEvdev->abs & ABS_X_VALUE) > + pEvdev->old_vals[0] = pEvdev->vals[0]; > + if (pEvdev->abs & ABS_Y_VALUE) > + pEvdev->old_vals[1] = pEvdev->vals[1]; > + } else { > + pEvdev->old_vals[0] = pEvdev->old_vals[1] = -1; > + } > + pEvdev->abs = 0; > + pEvdev->rel = 1; > + } > + > + if (pEvdev->rel) { > + int first = REL_CNT, last = 0; > + int i; > + > + if (pEvdev->swap_axes) { > + tmp = pEvdev->delta[REL_X]; > + pEvdev->delta[REL_X] = pEvdev->delta[REL_Y]; > + pEvdev->delta[REL_Y] = tmp; > + } > + if (pEvdev->invert_x) > + pEvdev->delta[REL_X] *= -1; > + if (pEvdev->invert_y) > + pEvdev->delta[REL_Y] *= -1; > + > + for (i = 0; i < REL_CNT; i++) > + { > + int map = pEvdev->axis_map[i]; > + if (pEvdev->delta[i] && map != -1) > + { > + v[map] = pEvdev->delta[i]; > + if (map < first) > + first = map; > + if (map > last) > + last = map; > + } > + } > + > + *num_v = (last - first + 1); > + *first_v = first; > + } > + /* > + * Some devices only generate valid abs coords when BTN_DIGI is > + * pressed. On wacom tablets, this means that the pen is in > + * proximity of the tablet. After the pen is removed, BTN_DIGI is > + * released, and a (0, 0) absolute event is generated. Checking > + * pEvdev->digi here, lets us ignore that event. pEvdev is > + * initialized to 1 so devices that doesn't use this scheme still > + * just works. > + */ > + else if (pEvdev->abs && pEvdev->tool) { > + memcpy(v, pEvdev->vals, sizeof(int) * pEvdev->num_vals); > + if (pEvdev->flags & EVDEV_CALIBRATED) > + { > + v[0] = xf86ScaleAxis(v[0], > + pEvdev->absinfo[ABS_X].maximum, > + pEvdev->absinfo[ABS_X].minimum, > + pEvdev->calibration.max_x, pEvdev->calibration.min_x); > + v[1] = xf86ScaleAxis(v[1], > + pEvdev->absinfo[ABS_Y].maximum, > + pEvdev->absinfo[ABS_Y].minimum, > + pEvdev->calibration.max_y, pEvdev->calibration.min_y); > + } > + > + if (pEvdev->swap_axes) { > + int tmp = v[0]; > + v[0] = v[1]; > + v[1] = tmp; > + } > + > + if (pEvdev->invert_x) > + v[0] = (pEvdev->absinfo[ABS_X].maximum - v[0] + > + pEvdev->absinfo[ABS_X].minimum); > + if (pEvdev->invert_y) > + v[1] = (pEvdev->absinfo[ABS_Y].maximum - v[1] + > + pEvdev->absinfo[ABS_Y].minimum); > + > + *num_v = pEvdev->num_vals; > + *first_v = 0; > + } > +} > + > +/** > + * Take a button input event and process it accordingly. > + */ > +static void > +EvdevProcessButtonEvent(InputInfoPtr pInfo, struct input_event *ev) > { > - static int delta[REL_CNT]; > - static int tmp, value; > - static unsigned int abs, rel; > unsigned int button; > + int value; > EvdevPtr pEvdev = pInfo->private; > > + button = EvdevUtilButtonEventToButtonNumber(pEvdev, ev->code); > + > /* Get the signed value, earlier kernels had this as unsigned */ > value = ev->value; > > - switch (ev->type) { > - case EV_REL: > - /* Ignore EV_REL events if we never set up for them. */ > - if (!(pEvdev->flags & EVDEV_RELATIVE_EVENTS)) > - break; > + /* Handle drag lock */ > + if (EvdevDragLockFilterEvent(pInfo, button, value)) > + return; > > - /* Handle mouse wheel emulation */ > - if (EvdevWheelEmuFilterMotion(pInfo, ev)) > - break; > + if (EvdevWheelEmuFilterButton(pInfo, button, value)) > + return; > > - rel = 1; > - > - switch (ev->code) { > - case REL_WHEEL: > - if (value > 0) > - PostButtonClicks(pInfo, wheel_up_button, value); > - else if (value < 0) > - PostButtonClicks(pInfo, wheel_down_button, -value); > - break; > - > - case REL_DIAL: > - case REL_HWHEEL: > - if (value > 0) > - PostButtonClicks(pInfo, wheel_right_button, value); > - else if (value < 0) > - PostButtonClicks(pInfo, wheel_left_button, -value); > - break; > - > - /* We don't post wheel events as axis motion. */ > - default: > - delta[ev->code] += value; > - break; > - } > + if (EvdevMBEmuFilterEvent(pInfo, button, value)) > + return; > + > + if (button) > + PostButtonEvent(pInfo, ev, value); > + else > + PostKbdEvent(pInfo, ev, value); > +} > + > +/** > + * Take the relative motion input event and process it accordingly. > + */ > +static void > +EvdevProcessRelativeMotionEvent(InputInfoPtr pInfo, struct input_event *ev) > +{ > + static int value; > + EvdevPtr pEvdev = pInfo->private; > + > + /* Get the signed value, earlier kernels had this as unsigned */ > + value = ev->value; > + > + /* Ignore EV_REL events if we never set up for them. */ > + if (!(pEvdev->flags & EVDEV_RELATIVE_EVENTS)) > + return; > + > + /* Handle mouse wheel emulation */ > + if (EvdevWheelEmuFilterMotion(pInfo, ev)) > + return; > + > + pEvdev->rel = 1; > + > + switch (ev->code) { > + case REL_WHEEL: > + if (value > 0) > + PostButtonClicks(pInfo, ev, wheel_up_button, value); > + else if (value < 0) > + PostButtonClicks(pInfo, ev, wheel_down_button, -value); > break; > > - case EV_ABS: > - /* Ignore EV_ABS events if we never set up for them. */ > - if (!(pEvdev->flags & EVDEV_ABSOLUTE_EVENTS)) > - break; > + case REL_DIAL: > + case REL_HWHEEL: > + if (value > 0) > + PostButtonClicks(pInfo, ev, wheel_right_button, value); > + else if (value < 0) > + PostButtonClicks(pInfo, ev, wheel_left_button, -value); > + break; > > - if (ev->code > ABS_MAX) > - break; > - pEvdev->vals[pEvdev->axis_map[ev->code]] = value; > - if (ev->code == ABS_X) > - abs |= ABS_X_VALUE; > - else if (ev->code == ABS_Y) > - abs |= ABS_Y_VALUE; > - else > - abs |= ABS_VALUE; > + /* We don't post wheel events as axis motion. */ > + default: > + pEvdev->delta[ev->code] += value; > break; > + } > +} > > - case EV_KEY: > - /* don't repeat mouse buttons */ > - if (ev->code >= BTN_MOUSE && ev->code < KEY_OK) > - if (value == 2) > - break; > - > - switch (ev->code) { > - case BTN_TOUCH: > - case BTN_TOOL_PEN: > - case BTN_TOOL_RUBBER: > - case BTN_TOOL_BRUSH: > - case BTN_TOOL_PENCIL: > - case BTN_TOOL_AIRBRUSH: > - case BTN_TOOL_FINGER: > - case BTN_TOOL_MOUSE: > - case BTN_TOOL_LENS: > - pEvdev->tool = value ? ev->code : 0; > - if (!(pEvdev->flags & EVDEV_TOUCHSCREEN)) > - break; > - /* Treat BTN_TOUCH from devices that only have BTN_TOUCH > as > - * BTN_LEFT. */ > - ev->code = BTN_LEFT; > - /* Intentional fallthrough! */ > - > - default: > - button = EvdevUtilButtonEventToButtonNumber(pEvdev, > ev->code); > - > - /* Handle drag lock */ > - if (EvdevDragLockFilterEvent(pInfo, button, value)) > - break; > - > - if (EvdevWheelEmuFilterButton(pInfo, button, value)) > - break; > - > - if (EvdevMBEmuFilterEvent(pInfo, button, value)) > - break; > - > - if (button) > - xf86PostButtonEvent(pInfo->dev, 0, button, value, 0, > 0); > - else > - PostKbdEvent(pInfo, ev, value); > - break; > - } > +/** > + * Take the absolute motion input event and process it accordingly. > + */ > +static void > +EvdevProcessAbsoluteMotionEvent(InputInfoPtr pInfo, struct input_event *ev) > +{ > + static int value; > + EvdevPtr pEvdev = pInfo->private; > + > + /* Get the signed value, earlier kernels had this as unsigned */ > + value = ev->value; > + > + /* Ignore EV_ABS events if we never set up for them. */ > + if (!(pEvdev->flags & EVDEV_ABSOLUTE_EVENTS)) > + return; > + > + if (ev->code > ABS_MAX) > + return; > + > + pEvdev->vals[pEvdev->axis_map[ev->code]] = value; > + if (ev->code == ABS_X) > + pEvdev->abs |= ABS_X_VALUE; > + else if (ev->code == ABS_Y) > + pEvdev->abs |= ABS_Y_VALUE; > + else > + pEvdev->abs |= ABS_VALUE; > +} > + > +/** > + * Take the key press/release input event and process it accordingly. > + */ > +static void > +EvdevProcessKeyEvent(InputInfoPtr pInfo, struct input_event *ev) > +{ > + static int value; > + EvdevPtr pEvdev = pInfo->private; > + > + /* Get the signed value, earlier kernels had this as unsigned */ > + value = ev->value; > + > + /* don't repeat mouse buttons */ > + if (ev->code >= BTN_MOUSE && ev->code < KEY_OK) > + if (value == 2) > + return; > + > + switch (ev->code) { > + case BTN_TOUCH: > + case BTN_TOOL_PEN: > + case BTN_TOOL_RUBBER: > + case BTN_TOOL_BRUSH: > + case BTN_TOOL_PENCIL: > + case BTN_TOOL_AIRBRUSH: > + case BTN_TOOL_FINGER: > + case BTN_TOOL_MOUSE: > + case BTN_TOOL_LENS: > + pEvdev->tool = value ? ev->code : 0; > + if (!(pEvdev->flags & EVDEV_TOUCHSCREEN)) > + break; > + /* Treat BTN_TOUCH from devices that only have BTN_TOUCH as > + * BTN_LEFT. */ > + ev->code = BTN_LEFT; > + /* Intentional fallthrough! */ > + > + default: > + EvdevProcessButtonEvent(pInfo, ev); > break; > + } > +} > > - case EV_SYN: > - /* convert to relative motion for touchpads */ > - if (abs && (pEvdev->flags & EVDEV_TOUCHPAD)) { > - if (pEvdev->tool) { /* meaning, touch is active */ > - if (pEvdev->old_vals[0] != -1) > - delta[REL_X] = pEvdev->vals[0] - pEvdev->old_vals[0]; > - if (pEvdev->old_vals[1] != -1) > - delta[REL_Y] = pEvdev->vals[1] - pEvdev->old_vals[1]; > - if (abs & ABS_X_VALUE) > - pEvdev->old_vals[0] = pEvdev->vals[0]; > - if (abs & ABS_Y_VALUE) > - pEvdev->old_vals[1] = pEvdev->vals[1]; > - } else { > - pEvdev->old_vals[0] = pEvdev->old_vals[1] = -1; > - } > - abs = 0; > - rel = 1; > - } > +/** > + * Post the relative motion events. > + */ > +static void > +EvdevPostRelativeMotionEvents(InputInfoPtr pInfo, int *num_v, int *first_v, > + int v[MAX_VALUATORS]) > +{ > + EvdevPtr pEvdev = pInfo->private; > > - if (rel) { > - int post_deltas[REL_CNT] = {0}; /* axis-mapped deltas */ > - int first = REL_CNT, last = 0; > - int i; > + if (pEvdev->rel) { > + xf86PostMotionEventP(pInfo->dev, FALSE, *first_v, *num_v, v + > *first_v); > + } > +} > > - if (pEvdev->swap_axes) { > - tmp = delta[REL_X]; > - delta[REL_X] = delta[REL_Y]; > - delta[REL_Y] = tmp; > - } > - if (pEvdev->invert_x) > - delta[REL_X] *= -1; > - if (pEvdev->invert_y) > - delta[REL_Y] *= -1; > +/** > + * Post the absolute motion events. > + */ > +static void > +EvdevPostAbsoluteMotionEvents(InputInfoPtr pInfo, int *num_v, int *first_v, > + int v[MAX_VALUATORS]) > +{ > + EvdevPtr pEvdev = pInfo->private; > > - for (i = 0; i < REL_CNT; i++) > - { > - int map = pEvdev->axis_map[i]; > - if (delta[i] && map != -1) > - { > - post_deltas[map] = delta[i]; > - if (map < first) > - first = map; > - if (map > last) > - last = map; > - } > - } > + /* > + * Some devices only generate valid abs coords when BTN_DIGI is > + * pressed. On wacom tablets, this means that the pen is in > + * proximity of the tablet. After the pen is removed, BTN_DIGI is > + * released, and a (0, 0) absolute event is generated. Checking > + * pEvdev->digi here, lets us ignore that event. pEvdev is > + * initialized to 1 so devices that doesn't use this scheme still > + * just works. > + */ > + if (pEvdev->abs && pEvdev->tool) { > + xf86PostMotionEventP(pInfo->dev, TRUE, *first_v, *num_v, v); > + } > +} > > - xf86PostMotionEventP(pInfo->dev, FALSE, first, > - (last - first + 1), > &post_deltas[first]); > - } > +/** > + * Post the queued key/button events. > + */ > +static void EvdevPostQueuedEvents(InputInfoPtr pInfo, int *num_v, int > *first_v, > + int v[MAX_VALUATORS]) > +{ > + int i; > + EvdevPtr pEvdev = pInfo->private; > > - /* > - * Some devices only generate valid abs coords when BTN_DIGI is > - * pressed. On wacom tablets, this means that the pen is in > - * proximity of the tablet. After the pen is removed, BTN_DIGI > is > - * released, and a (0, 0) absolute event is generated. Checking > - * pEvdev->digi here, lets us ignore that event. pEvdev is > - * initialized to 1 so devices that doesn't use this scheme still > - * just works. > - */ > - if (abs && pEvdev->tool) { > - int v[MAX_VALUATORS]; > - > - memcpy(v, pEvdev->vals, sizeof(int) * pEvdev->num_vals); > - if (pEvdev->flags & EVDEV_CALIBRATED) > - { > - v[0] = xf86ScaleAxis(v[0], > - pEvdev->absinfo[ABS_X].maximum, > - pEvdev->absinfo[ABS_X].minimum, > - pEvdev->calibration.max_x, > pEvdev->calibration.min_x); > - v[1] = xf86ScaleAxis(v[1], > - pEvdev->absinfo[ABS_Y].maximum, > - pEvdev->absinfo[ABS_Y].minimum, > - pEvdev->calibration.max_y, > pEvdev->calibration.min_y); > - } > + for (i = 0; i < pEvdev->num_queue; i++) { > + switch (pEvdev->queue[i].type) { > + case EV_QUEUE_KEY: > + xf86PostKeyboardEvent(pInfo->dev, pEvdev->queue[i].key, > + pEvdev->queue[i].val); > + break; > + case EV_QUEUE_BTN: > + /* FIXME: Add xf86PostButtonEventP to the X server so that we may > + * pass the valuators on ButtonPress/Release events, too. > Currently > + * only MotionNotify events contain the pointer position. */ > + xf86PostButtonEvent(pInfo->dev, 0, pEvdev->queue[i].key, > + pEvdev->queue[i].val, 0, 0); > + break; > + } > + } > +} > > - if (pEvdev->swap_axes) { > - int tmp = v[0]; > - v[0] = v[1]; > - v[1] = tmp; > - } > +/** > + * 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 > +EvdevProcessSyncEvent(InputInfoPtr pInfo, struct input_event *ev) > +{ > + int num_v = 0, first_v = 0; > + int v[MAX_VALUATORS]; > + EvdevPtr pEvdev = pInfo->private; > > - if (pEvdev->invert_x) > - v[0] = (pEvdev->absinfo[ABS_X].maximum - v[0] + > - pEvdev->absinfo[ABS_X].minimum); > - if (pEvdev->invert_y) > - v[1] = (pEvdev->absinfo[ABS_Y].maximum - v[1] + > - pEvdev->absinfo[ABS_Y].minimum); > + EvdevProcessValuators(pInfo, v, &num_v, &first_v); > > - xf86PostMotionEventP(pInfo->dev, TRUE, 0, pEvdev->num_vals, > v); > - } > + EvdevPostRelativeMotionEvents(pInfo, &num_v, &first_v, v); > + EvdevPostAbsoluteMotionEvents(pInfo, &num_v, &first_v, v); > + EvdevPostQueuedEvents(pInfo, &num_v, &first_v, v); > + > + memset(pEvdev->delta, 0, sizeof(pEvdev->delta)); > + memset(pEvdev->queue, 0, sizeof(pEvdev->queue)); > + pEvdev->abs = 0; > + pEvdev->rel = 0; > + pEvdev->num_queue = 0; nitpick: it's good practice to group the memset for pEvdev->queue and pEvdev->num_queue together. Just move it up by two lines and that'll do. > +} > > - memset(delta, 0, sizeof(delta)); > - tmp = 0; > - abs = 0; > - rel = 0; > +/** > + * Process the events from the server; nothing is actually posted to the > server > + * until an EV_SYN event is received. > + */ > +static void > +EvdevProcessEvent(InputInfoPtr pInfo, struct input_event *ev) > +{ > + switch (ev->type) { > + case EV_REL: > + EvdevProcessRelativeMotionEvent(pInfo, ev); > + break; > + case EV_ABS: > + EvdevProcessAbsoluteMotionEvent(pInfo, ev); > + break; > + case EV_KEY: > + EvdevProcessKeyEvent(pInfo, ev); > + break; > + case EV_SYN: > + EvdevProcessSyncEvent(pInfo, ev); > + break; > } > } > > diff --git a/src/evdev.h b/src/evdev.h > index 5b95369..4cf0be6 100644 > --- a/src/evdev.h > +++ b/src/evdev.h > @@ -54,6 +54,7 @@ > #endif > > #define EVDEV_MAXBUTTONS 32 > +#define EVDEV_MAXQUEUE 32 > > #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 3 > #define HAVE_PROPERTIES 1 > @@ -88,6 +89,15 @@ typedef struct { > } WheelAxis, *WheelAxisPtr; > > typedef struct { > + enum { > + EV_QUEUE_KEY, /* xf86PostKeyboardEvent() */ > + EV_QUEUE_BTN, /* xf86PostButtonEvent() */ > + } type; > + int key; > + int val; > +} EventQueueRec, *EventQueuePtr; > + please add a description of the EQ and how it is used in the driver. I want to be able to look at the EventQueueRec and immediately understand what it is used for. > +typedef struct { > const char *device; > int grabDevice; /* grab the event device? */ > > @@ -103,6 +113,9 @@ typedef struct { > BOOL invert_x; > BOOL invert_y; > > + int delta[REL_CNT]; > + unsigned int abs, rel; > + > /* XKB stuff has to be per-device rather than per-driver */ > #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 5 > XkbComponentNamesRec xkbnames; > @@ -159,6 +172,10 @@ typedef struct { > > /* minor/major number */ > dev_t min_maj; > + > + /* event queue used for button/key events between EV_SYN events */ > + int num_queue; > + EventQueueRec queue[EVDEV_MAXQUEUE]; > } EvdevRec, *EvdevPtr; > > unsigned int EvdevUtilButtonEventToButtonNumber(EvdevPtr pEvdev, int code); > -- > 1.6.1 Cheers, Peter _______________________________________________ xorg-devel mailing list [email protected] http://lists.x.org/mailman/listinfo/xorg-devel
