Thanks Peter (I also cross send to the right mailing list address as I made a mistake the first time I send these patches)

Le 01/06/2010 03:35, Peter Hutterer a écrit :
On Sun, May 30, 2010 at 03:08:58PM +0200, Benjamin Tissoires wrote:
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.
             ^^ typos, but at least they're consistent ;)


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<tisso...@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++) {

As Henrik pointed out this is a problematic assumption. Any reason we can't
just take the currently highest known MT define and use it? we'll simply
update when a new kernel comes out with new defines.

You're right, as usual. As you mention after, I'll put 2 define EVDEV_FIRST_MT_AXIS and EVDEV_LAST_MT_AXIS. But when the patches Henrik send will be upstream, we will use them of course.


+        if (!TestBit(axis, pEvdev->abs_bitmask))
+            continue;
+        pEvdev->mt_num_valuators++;

this is misusing continue, you might as well just do a if (TestBit))
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

I think it'd be good to use other numbers than starting with 0. we're pretty
much guaranteed that the device has other axes as valuators 0, 1 ...

no problem

+ */
+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
                    ^^ this should be "defined", I think
+ * 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++) {

same assumption here again, might be best to abstract this with an evdev
specific define for highest ABS_MT supported.

+        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

no indentation for #ifdef's please.

+                                       atoms[axnum],
+    #endif
+                                       pEvdev->absinfo[axis].minimum,
+                                       pEvdev->absinfo[axis].maximum,
+                                       10000, 0, 10000);

use the kernel resolution here please (see 7bbbce9a834).

oops, that's due to my long time to answer...

Cheers,
Benjamin



+            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))) {

align the two TestBits please.

+            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";

this should probably be a define, so we can add it to XI in due time.

Cheers,
   Peter

        } 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

_______________________________________________
xorg-devel@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to