[PATCH (v5) evdev 2/4] Add experimental XI 2.1 multitouch support
Daniel Stone
daniel at fooishbar.org
Wed Jan 19 15:11:55 PST 2011
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
+
# 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
+
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;
+ 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;
+ }
+#endif
+
+ if (num_axes < 1 && num_mt_axes < 1) {
+ xf86Msg(X_WARNING, "%s: no absolute or touch axes found.\n",
+ device->name);
+ return !Success;
+ }
+
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;
+ int mode = pEvdev->flags & EVDEV_TOUCHPAD ?
+ XIDependentTouch : XIDirectTouch;
+
+ 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);
+#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;
+ 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