[RFC XI 2.1 - xf86-input-evdev 2/3] Add experimental XI 2.1 multitouch support

Chase Douglas chase.douglas at canonical.com
Fri Nov 12 14:35:12 PST 2010


From: Chase Douglas <chase.douglas at ubuntu.com>

This multitouch addition only supports slotted MT evdev protocol
devices. Support must be enabled at configure time using
--enable-multitouch. It is built on the masked valuator support in
XInput ABI 12, so do not attempt to build it for an earlier ABI.

Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
---
 configure.ac |   11 ++++
 src/evdev.c  |  159 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 src/evdev.h  |    5 ++
 3 files changed, 167 insertions(+), 8 deletions(-)

diff --git a/configure.ac b/configure.ac
index 07cd64e..cc9e721 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 4984019..8b13e9f 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",
@@ -743,6 +751,60 @@ EvdevProcessRelativeMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
     }
 }
 
+#ifdef MULTITOUCH
+static void
+EvdevProcessTouch(InputInfoPtr pInfo)
+{
+    EvdevPtr pEvdev = pInfo->private;
+    int map = pEvdev->axis_map[ABS_MT_TRACKING_ID] - pEvdev->num_vals;
+
+    if (pEvdev->cur_slot < 0 || !pEvdev->mtMask)
+        return;
+
+    if (valuator_mask_isset(pEvdev->mtMask, map) &&
+        valuator_mask_get(pEvdev->mtMask, map) < 0) {
+        valuator_mask_set(pEvdev->mtMask, map,
+                          pEvdev->mt_slot_map[pEvdev->cur_slot]);
+        xf86PostTouchEvent(pInfo->dev, pEvdev->mtMask, 1);
+        pEvdev->mt_slot_map[pEvdev->cur_slot] = -1;
+    } else {
+        if (pEvdev->mt_slot_map[pEvdev->cur_slot] < 0)
+            if (!valuator_mask_isset(pEvdev->mtMask, map))
+                xf86Msg(X_WARNING, "%s: New touch without tracking ID.\n",
+                        pInfo->dev->name);
+            else {
+                int tracking_id = valuator_mask_get(pEvdev->mtMask, map);
+                pEvdev->mt_slot_map[pEvdev->cur_slot] = tracking_id;
+            }
+        else if (!valuator_mask_isset(pEvdev->mtMask, map))
+            valuator_mask_set(pEvdev->mtMask, map,
+                              pEvdev->mt_slot_map[pEvdev->cur_slot]);
+
+        xf86PostTouchEvent(pInfo->dev, pEvdev->mtMask, 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 {
+        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.
  */
@@ -766,11 +828,16 @@ EvdevProcessAbsoluteMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
     if (EvdevWheelEmuFilterMotion(pInfo, ev))
         return;
 
-    map = pEvdev->axis_map[ev->code];
 #ifdef HAVE_MASKED_VALUATORS
-    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;
+    }
 #else
+    map = pEvdev->axis_map[ev->code];
     pEvdev->vals[map] = value;
     if (ev->code == ABS_X)
         pEvdev->abs_queued |= ABS_X_VALUE;
@@ -936,6 +1003,7 @@ EvdevProcessSyncEvent(InputInfoPtr pInfo, struct input_event *ev)
 
 #ifdef HAVE_MASKED_VALUATORS
     EvdevProcessValuators(pInfo);
+    EvdevProcessTouch(pInfo);
 #else
     EvdevProcessValuators(pInfo, v, &num_v, &first_v);
 #endif
@@ -1416,7 +1484,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;
@@ -1425,7 +1493,13 @@ EvdevAddAbsClass(DeviceIntPtr device)
     if (!TestBit(EV_ABS, pEvdev->bitmask))
             return !Success;
 
+#ifdef HAVE_MASKED_VALUATORS
+    num_axes = CountBits((uint8_t *)pEvdev->abs_bitmask, ABS_MT_SLOT);
+    num_mt_axes = CountBits((uint8_t *)pEvdev->abs_bitmask, ABS_MAX) - num_axes;
+#else
     num_axes = EvdevCountBits(pEvdev->abs_bitmask, NLONGS(ABS_MAX));
+    num_mt_axes = 0;
+#endif
     if (num_axes < 1)
         return !Success;
 
@@ -1434,6 +1508,13 @@ EvdevAddAbsClass(DeviceIntPtr device)
         num_axes = MAX_VALUATORS;
     }
 
+#ifdef MULTITOUCH
+    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
+
     pEvdev->num_vals = num_axes;
 #ifdef HAVE_MASKED_VALUATORS
     if (num_axes > 0) {
@@ -1444,21 +1525,28 @@ EvdevAddAbsClass(DeviceIntPtr device)
         if (!pEvdev->oldMask)
             goto out;
     }
+#ifdef MULTITOUCH
+    if (num_mt_axes > 0) {
+        pEvdev->mtMask = valuator_mask_new(num_mt_axes);
+        if (!pEvdev->mtMask)
+            goto out;
+    }
+#endif
 #else
     memset(pEvdev->vals, 0, num_axes * sizeof(int));
     memset(pEvdev->old_vals, -1, num_axes * sizeof(int));
 #endif
-    atoms = malloc(pEvdev->num_vals * sizeof(Atom));
+    atoms = malloc((pEvdev->num_vals + num_mt_axes) * sizeof(Atom));
 
     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)
             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
@@ -1470,7 +1558,29 @@ EvdevAddAbsClass(DeviceIntPtr device)
                                        GetMotionHistorySize(), Absolute))
         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;
+
+        pEvdev->mt_slot_map = malloc(num_touches * sizeof(int));
+        if (!pEvdev->mt_slot_map)
+            goto out;
+
+        for (i = 0; i < num_touches; i++)
+            pEvdev->mt_slot_map[i] = -1;
+
+        if (!InitTouchClassDeviceStruct(device, num_touches, mode, num_mt_axes))
+            goto out;
+    }
+#endif
+
+    for (axis = ABS_X; axis < ABS_MT_SLOT; axis++) {
         int axnum = pEvdev->axis_map[axis];
         int resolution = 10000;
 
@@ -1500,6 +1610,25 @@ EvdevAddAbsClass(DeviceIntPtr device)
 #endif
     }
 
+#ifdef MULTITOUCH
+    for (axis = ABS_MT_SLOT; 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++)
@@ -1539,6 +1668,12 @@ EvdevAddAbsClass(DeviceIntPtr device)
 
 out:
 #ifdef HAVE_MASKED_VALUATORS
+#ifdef MULTITOUCH
+    free(pEvdev->mtMask);
+    pEvdev->mtMask = NULL;
+    free(pEvdev->mt_slot_map);
+    pEvdev->mt_slot_map = NULL;
+#endif
     free(pEvdev->mask);
     pEvdev->mask = NULL;
     free(pEvdev->oldMask);
@@ -1923,6 +2058,10 @@ EvdevProc(DeviceIntPtr device, int what)
         free(pEvdev->mask);
         free(pEvdev->oldMask);
         free(pEvdev->proxMask);
+#ifdef MULTITOUCH
+        free(pEvdev->mt_slot_map);
+        free(pEvdev->mtMask);
+#endif
         EvdevRemoveDevice(pInfo);
         pEvdev->min_maj = 0;
 	break;
@@ -2439,6 +2578,10 @@ EvdevPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
     if (!EvdevOpenDevice(pInfo))
         goto error;
 
+#ifdef MULTITOUCH
+    pEvdev->cur_slot = -1;
+#endif
+
     /*
      * We initialize pEvdev->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 bd5cb16..63c75a3 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -129,6 +129,11 @@ typedef struct {
     ValuatorMask *mask;
     ValuatorMask *oldMask;
     ValuatorMask *proxMask;
+#ifdef MULTITOUCH
+    ValuatorMask *mtMask;
+    int *mt_slot_map;
+    int cur_slot;
+#endif
 #else
     int vals[MAX_VALUATORS];
     int old_vals[MAX_VALUATORS]; /* Translate absolute inputs to relative */
-- 
1.7.1



More information about the xorg-devel mailing list