[PATCH evdev 2/3] Add the new valuators for multitouch (rev2)

Benjamin Tissoires tissoire at cena.fr
Sun May 30 06:11:13 PDT 2010


The step one in implementing multitouch in evdev is to report all the
touches in different valuators.
This patch detects multitouch devices and creates the extra valuators
required for multitouch.

Bonus point: this patch also sort the multitouch valuators to have
ABS_MT_POSISTION_X and ABS_MT_POSISTION_Y at their first position.

Note that I currently assume that all definitions above ABS_MT_TOUCH_MAJOR
and below ABS_MAX are MT-related.

Signed-off-by: Benjamin Tissoires <tissoire at cena.fr>
---
 src/evdev.c |  177 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/evdev.h |    6 ++-
 2 files changed, 181 insertions(+), 2 deletions(-)

diff --git a/src/evdev.c b/src/evdev.c
index 0cf1d3e..10fe81b 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -339,6 +339,8 @@ EvdevQueueButtonClicks(InputInfoPtr pInfo, int button, int count)
 #define ABS_X_VALUE 0x1
 #define ABS_Y_VALUE 0x2
 #define ABS_VALUE   0x4
+#define ABS_MT_X_VALUE   0x8
+#define ABS_MT_Y_VALUE   0x16
 /**
  * Take the valuators and process them accordingly.
  */
@@ -543,6 +545,10 @@ EvdevProcessAbsoluteMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
         pEvdev->abs |= ABS_X_VALUE;
     else if (ev->code == ABS_Y)
         pEvdev->abs |= ABS_Y_VALUE;
+    else if (ev->code == ABS_MT_POSITION_X)
+        pEvdev->abs |= ABS_MT_X_VALUE;
+    else if (ev->code == ABS_MT_POSITION_Y)
+        pEvdev->abs |= ABS_MT_Y_VALUE;
     else
         pEvdev->abs |= ABS_VALUE;
 }
@@ -704,6 +710,8 @@ EvdevProcessEvent(InputInfoPtr pInfo, struct input_event *ev)
 #undef ABS_X_VALUE
 #undef ABS_Y_VALUE
 #undef ABS_VALUE
+#undef ABS_MT_X_VALUE
+#undef ABS_MT_Y_VALUE
 
 /* just a magic number to reduce the number of reads */
 #define NUM_EVENTS 16
@@ -1132,6 +1140,154 @@ EvdevAddKeyClass(DeviceIntPtr device)
     return Success;
 }
 
+/**
+ * Count the number of mt-related valuators.
+ * assume that mt values are in the range
+ * ABS_MT_TOUCH_MAJOR..ABS_MAX
+ */
+static int
+EvdevMTCountValuators(EvdevPtr pEvdev)
+{
+    int axis;
+
+    pEvdev->mt_num_valuators = 0;
+
+    if (!(pEvdev->flags & EVDEV_MULTITOUCH))
+        return 0;
+
+    for (axis = ABS_MT_TOUCH_MAJOR; axis <= ABS_MAX; axis++) {
+        if (!TestBit(axis, pEvdev->abs_bitmask))
+            continue;
+        pEvdev->mt_num_valuators++;
+    }
+
+    return pEvdev->mt_num_valuators;
+}
+
+/**
+ * This function counts the number of valuators the device has.
+ * In case of multitouch device, it adds to this number a set of
+ * valuators to handle more than one touch.
+ *
+ * For instance, two touches can be received as:
+ *
+ * Valuator 0: x0
+ * Valuator 1: y0
+ * Valuator 2: pressure0
+ * Valuator 3: x1
+ * Valuator 4: y1
+ * Valuator 5: pressure1
+ */
+static int
+EvdevMTAddExtraValuators(EvdevPtr pEvdev, int total_num_axes)
+{
+    int num_axes = 0;
+    int mt_num_valuators = 0;
+
+    if (!(pEvdev->flags & EVDEV_MULTITOUCH))
+        return total_num_axes;
+
+    mt_num_valuators = EvdevMTCountValuators(pEvdev);
+
+    /* substract the mt-valuators to total_num_axes
+     * to have only the non-mt valuators */
+    num_axes = total_num_axes - mt_num_valuators;
+
+    /* count the maximum number of touchpoints the device can support */
+    pEvdev->mt_max_touchpoints = (MAX_VALUATORS - num_axes)
+                                                / mt_num_valuators;
+
+    /* check if the device tells the number of touchpoints
+     * it can support. */
+    if (TestBit(ABS_MT_TRACKING_ID, pEvdev->abs_bitmask)) {
+        int max_id = pEvdev->absinfo[ABS_MT_TRACKING_ID].maximum;
+        if (max_id < pEvdev->mt_max_touchpoints)
+            pEvdev->mt_max_touchpoints = max_id;
+    }
+
+    num_axes += pEvdev->mt_max_touchpoints * mt_num_valuators;
+
+    return num_axes;
+}
+
+/**
+ * As the first declared mt valuator is ABS_MT_TOUCH_MAJOR, it is then
+ * the first mt-related valuator.
+ * This function puts ABS_MT_POSITION_X and ABS_MT_POSITION_Y at places
+ * 0 and 1 in the set of multitouch valuators.
+ */
+static void
+EvdevMTSortValuators(EvdevPtr pEvdev)
+{
+    int axis, tmp_axis_value;
+    int first_axis = 0;
+    int second_axis = 0;
+
+    if (!(pEvdev->flags & EVDEV_MULTITOUCH))
+        return;
+
+    /* find the first and second mt axes */
+    for (axis = ABS_MT_TOUCH_MAJOR; axis <= ABS_MAX; axis++) {
+        if (pEvdev->axis_map[axis] == -1)
+            continue;
+
+        if (!first_axis)
+            first_axis = axis;
+        else if (!second_axis) {
+            second_axis = axis;
+            break;
+        }
+    }
+
+    /* do the actual swap */
+    tmp_axis_value = pEvdev->axis_map[first_axis];
+    pEvdev->axis_map[first_axis] = pEvdev->axis_map[ABS_MT_POSITION_X];
+    pEvdev->axis_map[ABS_MT_POSITION_X] = tmp_axis_value;
+
+    tmp_axis_value = pEvdev->axis_map[second_axis];
+    pEvdev->axis_map[second_axis] = pEvdev->axis_map[ABS_MT_POSITION_Y];
+    pEvdev->axis_map[ABS_MT_POSITION_Y] = tmp_axis_value;
+}
+
+/**
+ * As multitouch devices contains extra axes to enable multitouch,
+ * they are not initialized in the first init pass. This function
+ * does the init for those extra valuators.
+ */
+static void
+EvdevMTInitValuators(DeviceIntPtr device, Atom *atoms)
+{
+    InputInfoPtr pInfo;
+    EvdevPtr pEvdev;
+    int axis, j;
+
+    pInfo = device->public.devicePrivate;
+    pEvdev = pInfo->private;
+
+    if (!(pEvdev->flags & EVDEV_MULTITOUCH))
+        return;
+
+    /* Here j starts at 1 as one set of mt-valuators has already been
+     * registered */
+    for (j = 1; j < pEvdev->mt_max_touchpoints; j++) {
+        for (axis = ABS_MT_TOUCH_MAJOR; axis <= ABS_MAX; axis++) {
+            int axnum = pEvdev->axis_map[axis];
+            int real_axnum = axnum + j * pEvdev->mt_num_valuators;
+            if (axnum == -1)
+                continue;
+            xf86InitValuatorAxisStruct(device, real_axnum,
+    #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+                                       atoms[axnum],
+    #endif
+                                       pEvdev->absinfo[axis].minimum,
+                                       pEvdev->absinfo[axis].maximum,
+                                       10000, 0, 10000);
+            xf86InitValuatorDefaults(device, real_axnum);
+            pEvdev->old_vals[real_axnum] = -1;
+        }
+    }
+}
+
 static int
 EvdevAddAbsClass(DeviceIntPtr device)
 {
@@ -1149,6 +1305,9 @@ EvdevAddAbsClass(DeviceIntPtr device)
     num_axes = CountBits(pEvdev->abs_bitmask, NLONGS(ABS_MAX));
     if (num_axes < 1)
         return !Success;
+
+    num_axes = EvdevMTAddExtraValuators(pEvdev, num_axes);
+
     pEvdev->num_vals = num_axes;
     memset(pEvdev->vals, 0, num_axes * sizeof(int));
     memset(pEvdev->old_vals, -1, num_axes * sizeof(int));
@@ -1162,6 +1321,8 @@ EvdevAddAbsClass(DeviceIntPtr device)
         i++;
     }
 
+    EvdevMTSortValuators(pEvdev);
+
     EvdevInitAxesLabels(pEvdev, pEvdev->num_vals, atoms);
 
     if (!InitValuatorClassDeviceStruct(device, num_axes,
@@ -1200,6 +1361,8 @@ EvdevAddAbsClass(DeviceIntPtr device)
 
     free(atoms);
 
+    EvdevMTInitValuators(device, atoms);
+
     if (!InitPtrFeedbackClassDeviceStruct(device, EvdevPtrCtrlProc))
         return !Success;
 
@@ -1503,7 +1666,7 @@ EvdevInit(DeviceIntPtr device)
 
     if (pEvdev->flags & (EVDEV_UNIGNORE_RELATIVE | EVDEV_UNIGNORE_ABSOLUTE))
         EvdevInitAnyClass(device, pEvdev);
-    else if (pEvdev->flags & (EVDEV_TOUCHPAD | EVDEV_TOUCHSCREEN | EVDEV_TABLET))
+    else if (pEvdev->flags & (EVDEV_TOUCHPAD | EVDEV_TOUCHSCREEN | EVDEV_TABLET | EVDEV_MULTITOUCH))
         EvdevInitTouchDevice(device, pEvdev);
     else if (pEvdev->flags & EVDEV_RELATIVE_EVENTS)
         EvdevInitRelClass(device, pEvdev);
@@ -1875,6 +2038,15 @@ EvdevProbe(InputInfoPtr pInfo)
         xf86Msg(X_PROBED, "%s: Found absolute axes\n", pInfo->name);
         pEvdev->flags |= EVDEV_ABSOLUTE_EVENTS;
 
+        if ((TestBit(ABS_MT_POSITION_X, pEvdev->abs_bitmask) &&
+                        TestBit(ABS_MT_POSITION_Y, pEvdev->abs_bitmask))) {
+            xf86Msg(X_INFO, "%s: Found absolute multitouch device.\n", pInfo->name);
+            pEvdev->flags |= EVDEV_MULTITOUCH;
+            if (!pEvdev->num_buttons) {
+                pEvdev->num_buttons = 7; /* LMR + scroll wheels */
+                pEvdev->flags |= EVDEV_BUTTON_EVENTS;
+            }
+        }
         if ((TestBit(ABS_X, pEvdev->abs_bitmask) &&
              TestBit(ABS_Y, pEvdev->abs_bitmask))) {
             xf86Msg(X_PROBED, "%s: Found x and y absolute axes\n", pInfo->name);
@@ -1947,6 +2119,9 @@ EvdevProbe(InputInfoPtr pInfo)
         } else if (pEvdev->flags & EVDEV_TOUCHSCREEN) {
             xf86Msg(X_INFO, "%s: Configuring as touchscreen\n", pInfo->name);
             pInfo->type_name = XI_TOUCHSCREEN;
+	} else if (pEvdev->flags & EVDEV_MULTITOUCH) {
+	    xf86Msg(X_INFO, "%s: Configuring as multitouch device\n", pInfo->name);
+	    pInfo->type_name = "MULTITOUCHDEVICE";
 	} else {
 	    xf86Msg(X_INFO, "%s: Configuring as mouse\n", pInfo->name);
 	    pInfo->type_name = XI_MOUSE;
diff --git a/src/evdev.h b/src/evdev.h
index 8c89f83..852f06c 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -71,6 +71,7 @@
 #define EVDEV_UNIGNORE_ABSOLUTE (1 << 9) /* explicitly unignore abs axes */
 #define EVDEV_UNIGNORE_RELATIVE (1 << 10) /* explicitly unignore rel axes */
 #define EVDEV_RELATIVE_MODE	(1 << 11) /* Force relative events for devices with absolute axes */
+#define EVDEV_MULTITOUCH	(1 << 12) /* device looks like a multi-touch screen? */
 
 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 3
 #define HAVE_PROPERTIES 1
@@ -80,7 +81,6 @@
 #define MAX_VALUATORS 36
 #endif
 
-
 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 5
 typedef struct {
     char *rules;
@@ -193,6 +193,10 @@ typedef struct {
     /* Event queue used to defer keyboard/button events until EV_SYN time. */
     int                     num_queue;
     EventQueueRec           queue[EVDEV_MAXQUEUE];
+
+    unsigned int mt_num_valuators;
+    unsigned int mt_max_touchpoints; /* the number of simultaneous touchpoints
+                                      * the device can support */
 } EvdevRec, *EvdevPtr;
 
 /* Event posting functions */
-- 
1.7.0.1



More information about the xorg-devel mailing list