[PATCH (v5) evdev 2/4] Add experimental XI 2.1 multitouch support
Peter Hutterer
peter.hutterer at who-t.net
Thu Jan 20 21:34:59 PST 2011
On Wed, Jan 19, 2011 at 11:11:55PM +0000, Daniel Stone wrote:
> From: Chase Douglas <chase.douglas at canonical.com>
>
> This multitouch addition only supports slotted MT evdev protocol
> devices. Support must be enabled at configure time using
> --enable-multitouch.
>
> Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
> ---
>
> v5: Fixed merge conflicts.
> Updated to new xf86PostTouchEvent API, including explicitly tracking
> touchpoint creation and destruction, rather than relying on the server to
> do it for us.
> Removed mt_slot_map, as we no longer need to hand the server monotonic
> touch IDs: it does that for us.
>
> configure.ac | 11 +++
> src/evdev.c | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----
> src/evdev.h | 25 ++++++-
> 3 files changed, 233 insertions(+), 20 deletions(-)
>
> diff --git a/configure.ac b/configure.ac
> index 887021c..02ab67a 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -47,6 +47,17 @@ XORG_DEFAULT_OPTIONS
> # Obtain compiler/linker options from server and required extensions
> PKG_CHECK_MODULES(XORG, xorg-server xproto inputproto)
>
> +# Whether to include support for experimental XI 2.1 multitouch
> +AC_ARG_ENABLE(multitouch,
> + AC_HELP_STRING([--enable-multitouch],
> + [Enable experimental XI 2.1 multitouch support [[default: disabled]]]),
> + [MULTITOUCH=$enableval],
> + [MULTITOUCH=no])
> +
> +if test "x$MULTITOUCH" = xyes; then
> + AC_DEFINE(MULTITOUCH, 1, [Enable experimental multitouch code])
> +fi
> +
default enabled if the server version is high enough please.
come to think of it, I don't see the need for this at all, might as well
build it in unconditionally. there's nothing controversial in here either,
it's pretty much the already existing framework extended.
> # Define a configure option for an alternate input module directory
> AC_ARG_WITH(xorg-module-dir,
> AC_HELP_STRING([--with-xorg-module-dir=DIR],
> diff --git a/src/evdev.c b/src/evdev.c
> index 393f443..32d9109 100644
> --- a/src/evdev.c
> +++ b/src/evdev.c
> @@ -87,6 +87,14 @@
> #define MODEFLAG 8
> #define COMPOSEFLAG 16
>
> +#ifndef ABS_MT_SLOT
> +#define ABS_MT_SLOT 0x2f
> +#endif
> +
> +#ifndef ABS_MT_TRACKING_ID
> +#define ABS_MT_TRACKING_ID 0x39
> +#endif
if you define those two, you might want to also define ABS_MT_TOUCH_MAJOR
> +
> static char *evdevDefaults[] = {
> "XkbRules", "evdev",
> "XkbModel", "evdev",
> @@ -317,7 +325,7 @@ EvdevQueueKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value)
> if ((pQueue = EvdevNextInQueue(pInfo)))
> {
> pQueue->type = EV_QUEUE_KEY;
> - pQueue->key = code;
> + pQueue->detail.key = code;
> pQueue->val = value;
> }
> }
> @@ -330,7 +338,7 @@ EvdevQueueButtonEvent(InputInfoPtr pInfo, int button, int value)
> if ((pQueue = EvdevNextInQueue(pInfo)))
> {
> pQueue->type = EV_QUEUE_BTN;
> - pQueue->key = button;
> + pQueue->detail.key = button;
> pQueue->val = value;
> }
> }
> @@ -342,11 +350,27 @@ EvdevQueueProximityEvent(InputInfoPtr pInfo, int value)
> if ((pQueue = EvdevNextInQueue(pInfo)))
> {
> pQueue->type = EV_QUEUE_PROXIMITY;
> - pQueue->key = 0;
> + pQueue->detail.key = 0;
> pQueue->val = value;
> }
> }
>
> +#ifdef MULTITOUCH
> +void
> +EvdevQueueTouchEvent(InputInfoPtr pInfo, unsigned int touch, ValuatorMask *mask,
> + uint16_t evtype)
> +{
> + EventQueuePtr pQueue;
> + if ((pQueue = EvdevNextInQueue(pInfo)))
> + {
> + pQueue->type = EV_QUEUE_TOUCH;
> + pQueue->detail.touch = touch;
> + valuator_mask_copy(pQueue->touchMask, mask);
> + pQueue->val = evtype;
> + }
> +}
> +#endif
> +
> /**
> * Post button event right here, right now.
> * Interface for MB emulation since these need to post immediately.
> @@ -615,6 +639,53 @@ EvdevProcessRelativeMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
> }
> }
>
> +#ifdef MULTITOUCH
> +static void
> +EvdevProcessTouch(InputInfoPtr pInfo)
> +{
> + EvdevPtr pEvdev = pInfo->private;
> +
> + if (pEvdev->cur_slot < 0 || !pEvdev->mtMask)
> + return;
> +
> + if (pEvdev->close_slot) {
> + EvdevQueueTouchEvent(pInfo, pEvdev->cur_slot, pEvdev->mtMask,
> + XI_TouchEnd);
> + pEvdev->close_slot = 0;
> + } else {
> + EvdevQueueTouchEvent(pInfo, pEvdev->cur_slot, pEvdev->mtMask,
> + pEvdev->open_slot ? XI_TouchBegin :
> + XI_TouchMotion);
> + pEvdev->open_slot = 0;
> + }
> +
> + valuator_mask_zero(pEvdev->mtMask);
> +}
> +
> +static void
> +EvdevProcessTouchEvent(InputInfoPtr pInfo, struct input_event *ev)
> +{
> + EvdevPtr pEvdev = pInfo->private;
> + int map;
> +
> + if (ev->code == ABS_MT_SLOT) {
> + EvdevProcessTouch(pInfo);
> + pEvdev->cur_slot = ev->value;
> + } else if (ev->code == ABS_MT_TRACKING_ID) {
> + if (ev->value >= 0)
> + pEvdev->open_slot = 1;
> + else
> + pEvdev->close_slot = 1;
> + } else {
> + map = pEvdev->axis_map[ev->code] - pEvdev->num_vals;
not sure if i've asked this before, but what's the deal with - num_vals
here?
> + valuator_mask_set(pEvdev->mtMask, map, ev->value);
> + }
> +}
> +#else
> +#define EvdevProcessTouch(pInfo)
> +#define EvdevProcessTouchEvent(pInfo, ev)
> +#endif /* MULTITOUCH */
> +
> /**
> * Take the absolute motion input event and process it accordingly.
> */
> @@ -638,9 +709,13 @@ EvdevProcessAbsoluteMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
> if (EvdevWheelEmuFilterMotion(pInfo, ev))
> return;
>
> - map = pEvdev->axis_map[ev->code];
> - valuator_mask_set(pEvdev->mask, map, value);
> - pEvdev->abs_queued = 1;
> + if (ev->code >= ABS_MT_SLOT)
> + EvdevProcessTouchEvent(pInfo, ev);
> + else {
> + map = pEvdev->axis_map[ev->code];
> + valuator_mask_set(pEvdev->mask, map, value);
> + pEvdev->abs_queued = 1;
> + }
> }
>
> /**
> @@ -736,6 +811,9 @@ EvdevPostProximityEvents(InputInfoPtr pInfo, int which, int num_v, int first_v,
> switch (pEvdev->queue[i].type) {
> case EV_QUEUE_KEY:
> case EV_QUEUE_BTN:
> +#ifdef MULTITOUCH
> + case EV_QUEUE_TOUCH:
> +#endif
> break;
> case EV_QUEUE_PROXIMITY:
> if (pEvdev->queue[i].val == which)
> @@ -758,23 +836,30 @@ static void EvdevPostQueuedEvents(InputInfoPtr pInfo, int num_v, int first_v,
> for (i = 0; i < pEvdev->num_queue; i++) {
> switch (pEvdev->queue[i].type) {
> case EV_QUEUE_KEY:
> - xf86PostKeyboardEvent(pInfo->dev, pEvdev->queue[i].key,
> + xf86PostKeyboardEvent(pInfo->dev, pEvdev->queue[i].detail.key,
> pEvdev->queue[i].val);
> break;
> case EV_QUEUE_BTN:
> #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 11
> if (pEvdev->abs_queued && pEvdev->in_proximity) {
> - xf86PostButtonEventP(pInfo->dev, 1, pEvdev->queue[i].key,
> + xf86PostButtonEventP(pInfo->dev, 1, pEvdev->queue[i].detail.key,
> pEvdev->queue[i].val, first_v, num_v,
> v + first_v);
>
> } else
> #endif
> - xf86PostButtonEvent(pInfo->dev, 0, pEvdev->queue[i].key,
> + xf86PostButtonEvent(pInfo->dev, 0, pEvdev->queue[i].detail.key,
> pEvdev->queue[i].val, 0, 0);
> break;
> case EV_QUEUE_PROXIMITY:
> break;
> +#ifdef MULTITOUCH
> + case EV_QUEUE_TOUCH:
> + xf86PostTouchEvent(pInfo->dev, pEvdev->queue[i].detail.touch,
> + pEvdev->queue[i].val, 0,
> + pEvdev->queue[i].touchMask);
> + break;
> +#endif
> }
> }
> }
> @@ -793,6 +878,7 @@ EvdevProcessSyncEvent(InputInfoPtr pInfo, struct input_event *ev)
> EvdevProcessProximityState(pInfo);
>
> EvdevProcessValuators(pInfo);
> + EvdevProcessTouch(pInfo);
>
> EvdevPostProximityEvents(pInfo, TRUE, num_v, first_v, v);
> EvdevPostRelativeMotionEvents(pInfo, num_v, first_v, v);
> @@ -801,7 +887,6 @@ EvdevProcessSyncEvent(InputInfoPtr pInfo, struct input_event *ev)
> EvdevPostProximityEvents(pInfo, FALSE, num_v, first_v, v);
>
> memset(pEvdev->delta, 0, sizeof(pEvdev->delta));
> - memset(pEvdev->queue, 0, sizeof(pEvdev->queue));
> if (pEvdev->mask)
> valuator_mask_zero(pEvdev->mask);
> pEvdev->num_queue = 0;
> @@ -1268,7 +1353,7 @@ EvdevAddAbsClass(DeviceIntPtr device)
> {
> InputInfoPtr pInfo;
> EvdevPtr pEvdev;
> - int num_axes, axis, i = 0;
> + int num_axes, num_mt_axes, axis, i = 0;
> Atom *atoms;
>
> pInfo = device->public.devicePrivate;
> @@ -1277,15 +1362,32 @@ EvdevAddAbsClass(DeviceIntPtr device)
> if (!TestBit(EV_ABS, pEvdev->bitmask))
> return !Success;
>
> - num_axes = EvdevCountBits(pEvdev->abs_bitmask, NLONGS(ABS_MAX));
> - if (num_axes < 1)
> - return !Success;
> + num_axes = CountBits((uint8_t *)pEvdev->abs_bitmask, ABS_MT_SLOT);
> + num_mt_axes = CountBits((uint8_t *)pEvdev->abs_bitmask, ABS_MAX) - num_axes;
>
> if (num_axes > MAX_VALUATORS) {
> xf86Msg(X_WARNING, "%s: found %d axes, limiting to %d.\n", device->name, num_axes, MAX_VALUATORS);
> num_axes = MAX_VALUATORS;
> }
>
> +#ifdef MULTITOUCH
> + if (TestBit(ABS_MT_SLOT, pEvdev->abs_bitmask))
> + num_mt_axes--;
> + if (TestBit(ABS_MT_TRACKING_ID, pEvdev->abs_bitmask))
> + num_mt_axes--;
> +
> + if (num_mt_axes > MAX_VALUATORS) {
> + xf86Msg(X_WARNING, "%s: found %d MT axes, limiting to %d.\n", device->name, num_axes, MAX_VALUATORS);
> + num_mt_axes = MAX_VALUATORS;
shouldn't this be num_mt_axes + num_axes?
> + }
> +#endif
> +
> + if (num_axes < 1 && num_mt_axes < 1) {
> + xf86Msg(X_WARNING, "%s: no absolute or touch axes found.\n",
> + device->name);
> + return !Success;
can we mkae this a goto out; as well?
> + }
> +
> pEvdev->num_vals = num_axes;
> if (num_axes > 0) {
> pEvdev->mask = valuator_mask_new(num_axes);
> @@ -1301,17 +1403,39 @@ EvdevAddAbsClass(DeviceIntPtr device)
> goto out;
> }
> }
> - atoms = malloc(pEvdev->num_vals * sizeof(Atom));
> +#ifdef MULTITOUCH
> + if (num_mt_axes > 0) {
> + pEvdev->mtMask = valuator_mask_new(num_mt_axes);
> + if (!pEvdev->mtMask) {
> + xf86Msg(X_ERROR, "%s: failed to allocate MT valuator mask.\n",
> + device->name);
> + goto out;
> + }
>
> + for (i = 0; i < EVDEV_MAXQUEUE; i++) {
> + pEvdev->queue[i].touchMask =
> + valuator_mask_new(num_mt_axes);
> + if (!pEvdev->queue[i].touchMask) {
> + xf86Msg(X_ERROR, "%s: failed to allocate MT valuator masks for "
> + "evdev event queue.\n", device->name);
> + goto out;
> + }
> + }
> + }
> +#endif
> + atoms = malloc((pEvdev->num_vals + num_mt_axes) * sizeof(Atom));
> +
> + i = 0;
> for (axis = ABS_X; i < MAX_VALUATORS && axis <= ABS_MAX; axis++) {
> pEvdev->axis_map[axis] = -1;
> - if (!TestBit(axis, pEvdev->abs_bitmask))
> + if (!TestBit(axis, pEvdev->abs_bitmask) || axis == ABS_MT_SLOT ||
> + axis == ABS_MT_TRACKING_ID)
> continue;
> pEvdev->axis_map[axis] = i;
> i++;
> }
>
> - EvdevInitAxesLabels(pEvdev, pEvdev->num_vals, atoms);
> + EvdevInitAxesLabels(pEvdev, pEvdev->num_vals + num_mt_axes, atoms);
>
> if (!InitValuatorClassDeviceStruct(device, num_axes,
> #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
> @@ -1326,7 +1450,26 @@ EvdevAddAbsClass(DeviceIntPtr device)
> goto out;
> }
>
> - for (axis = ABS_X; axis <= ABS_MAX; axis++) {
> +#ifdef MULTITOUCH
> + if (num_mt_axes > 0)
> + {
> + int num_touches = 10;
a #define for this please
> + int mode = pEvdev->flags & EVDEV_TOUCHPAD ?
> + XIDependentTouch : XIDirectTouch;
some extra () would be nice, plus some more indentation on the second line.
> +
> + if (pEvdev->absinfo[ABS_MT_SLOT].maximum > 0)
> + num_touches = pEvdev->absinfo[ABS_MT_SLOT].maximum;
> +
> + if (!InitTouchClassDeviceStruct(device, num_touches, mode,
> + num_mt_axes)) {
> + xf86Msg(X_ERROR, "%s: failed to initialize touch class device.\n",
> + device->name);
> + goto out;
> + }
> + }
> +#endif
> +
> + for (axis = ABS_X; axis < ABS_MT_SLOT; axis++) {
> int axnum = pEvdev->axis_map[axis];
> int resolution = 10000;
>
> @@ -1353,6 +1496,25 @@ EvdevAddAbsClass(DeviceIntPtr device)
> xf86InitValuatorDefaults(device, axnum);
> }
>
> +#ifdef MULTITOUCH
> + for (axis = ABS_MT_TOUCH_MAJOR; axis <= ABS_MAX; axis++) {
> + int axnum = pEvdev->axis_map[axis] - pEvdev->num_vals;
> + int resolution = 10000;
> +
> + if (axnum < 0)
> + continue;
> +
> + if (pEvdev->absinfo[axis].resolution)
> + resolution = pEvdev->absinfo[axis].resolution * 1000;
> +
> + xf86InitTouchValuatorAxisStruct(device, axnum,
> + atoms[axnum + pEvdev->num_vals],
> + pEvdev->absinfo[axis].minimum,
> + pEvdev->absinfo[axis].maximum,
> + pEvdev->absinfo[axis].resolution);
> + }
> +#endif
> +
> free(atoms);
>
> for (i = 0; i < ArrayLength(proximity_bits); i++)
> @@ -1400,6 +1562,13 @@ EvdevAddAbsClass(DeviceIntPtr device)
> return Success;
>
> out:
> +#ifdef MULTITOUCH
> + free(pEvdev->mtMask);
> + pEvdev->mtMask = NULL;
> + for (i = 0; i < EVDEV_MAXQUEUE; i++)
> + free(pEvdev->queue[i].touchMask);
> + pEvdev->queue[i].touchMask = NULL;
> +#endif
> free(pEvdev->mask);
> pEvdev->mask = NULL;
> free(pEvdev->oldMask);
> @@ -1749,6 +1918,9 @@ EvdevProc(DeviceIntPtr device, int what)
> {
> InputInfoPtr pInfo;
> EvdevPtr pEvdev;
> +#ifdef MULTITOUCH
> + int i;
> +#endif
>
> pInfo = device->public.devicePrivate;
> pEvdev = pInfo->private;
> @@ -1785,6 +1957,11 @@ EvdevProc(DeviceIntPtr device, int what)
> free(pEvdev->mask);
> free(pEvdev->oldMask);
> free(pEvdev->proxMask);
> +#ifdef MULTITOUCH
> + free(pEvdev->mtMask);
> + for (i = 0; i < EVDEV_MAXQUEUE; i++)
> + free(pEvdev->queue[i].touchMask);
valuator_mask_free() here as well
> +#endif
> EvdevRemoveDevice(pInfo);
> pEvdev->min_maj = 0;
> break;
> @@ -2250,6 +2427,10 @@ EvdevPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
> if (rc != Success)
> goto error;
>
> +#ifdef MULTITOUCH
> + pEvdev->cur_slot = -1;
> +#endif
> +
> /*
> * We initialize pEvdev->in_proximity to 1 so that device that doesn't use
> * proximity will still report events.
> diff --git a/src/evdev.h b/src/evdev.h
> index 6af145f..62619dd 100644
> --- a/src/evdev.h
> +++ b/src/evdev.h
> @@ -110,9 +110,20 @@ typedef struct {
> EV_QUEUE_KEY, /* xf86PostKeyboardEvent() */
> EV_QUEUE_BTN, /* xf86PostButtonEvent() */
> EV_QUEUE_PROXIMITY, /* xf86PostProximityEvent() */
> +#ifdef MULTITOUCH
> + EV_QUEUE_TOUCH, /*xf86PostTouchEvent() */
> +#endif
> } type;
> - int key; /* May be either a key code or button number. */
> - int val; /* State of the key/button; pressed or released. */
> + union {
> + int key; /* May be either a key code or button number. */
> +#ifdef MULTITOUCH
> + unsigned int touch; /* Touch ID */
> +#endif
> + } detail;
we hardly ever see negative button numbers or keys, so you can just leave
that as detail and make it uint.
Cheers,
Peter
> + int val; /* State of the key/button/touch; pressed or released. */
> +#ifdef MULTITOUCH
> + ValuatorMask *touchMask;
> +#endif
> } EventQueueRec, *EventQueuePtr;
>
> typedef struct {
> @@ -124,6 +135,12 @@ typedef struct {
> ValuatorMask *mask;
> ValuatorMask *oldMask;
> ValuatorMask *proxMask;
> +#ifdef MULTITOUCH
> + ValuatorMask *mtMask;
> + int cur_slot;
> + BOOL close_slot;
> + BOOL open_slot;
> +#endif
>
> int flags;
> int in_proximity; /* device in proximity */
> @@ -202,6 +219,10 @@ typedef struct {
> void EvdevQueueKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value);
> void EvdevQueueButtonEvent(InputInfoPtr pInfo, int button, int value);
> void EvdevQueueProximityEvent(InputInfoPtr pInfo, int value);
> +#ifdef MULTITOUCH
> +void EvdevQueueTouchEvent(InputInfoPtr pInfo, unsigned int touch,
> + ValuatorMask *mask, uint16_t type);
> +#endif
> void EvdevPostButtonEvent(InputInfoPtr pInfo, int button, int value);
> void EvdevQueueButtonClicks(InputInfoPtr pInfo, int button, int count);
> void EvdevPostRelativeMotionEvents(InputInfoPtr pInfo, int num_v, int first_v,
> --
> 1.7.2.3
More information about the xorg-devel
mailing list