[PATCH xf86-input-evdev v3 2/2] Copy last valuator values into new touch valuator masks

Chase Douglas chase.douglas at canonical.com
Thu Jan 12 07:00:33 PST 2012


Evdev is a 100% stateful protocol. The following represents three
touches. Two touches begin and end at the same time at (500, 500) and
(1000, 1000). The third touch begins after the first two end, and is at
(500, 500).

ABS_MT_SLOT		0	/* Set touch slot */
ABS_MT_TRACKING_ID	0	/* New touch with ID 0 in slot 0 */
ABS_MT_POSITION_X	500	/* Initial X position */
ABS_MT_POSITION_Y	500	/* Initial Y position */
ABS_MT_SLOT		1	/* Set touch slot */
ABS_MT_TRACKING_ID	1	/* New touch with ID 1 in slot 1 */
ABS_MT_POSITION_X	1000	/* Initial X position */
ABS_MT_POSITION_Y	1000	/* Initial Y position */
SYNC				/* End of frame */
ABS_MT_SLOT		0	/* Go back to slot 0 */
ABS_MT_TRACKING_ID	-1	/* Touch in slot 0 ended */
ABS_MT_SLOT		1	/* Go to slot 1 */
ABS_MT_TRACKING_ID	-1	/* Touch in slot 1 ended */
SYNC				/* End of frame */
ABS_MT_SLOT		0	/* Go back to slot 0 */
ABS_MT_TRACKING_ID	2	/* New touch in slot 0 with ID 2 */
SYNC				/* End of frame */
ABS_MT_TRACKING_ID	-1	/* Touch in last slot (0) ended */
SYNC				/* End of frame */

Note that touch 2 has the same X and Y position as touch 0. This is
implied because no new value was emitted for slot 0. In fact, Linux will
not emit an event in the same slot with the same event type and code
unless the value has changed. Thus, we can only assume that all the MT
valuators have the same values as they were when they were last sent for
the given slot.

This change adds an array of valuator mask to hold all the last valuator
values that came from evdev for each slot. When a new touch begins, all
the last values are copied into it.

This patch assumes initial axis values of 0 in each slot. Linux and
mtdev do not provide a facility to query the current values of axes in
each slot yet. This may cause spurious incorrect touch valuator values
at the beginning of an X session, but there's nothing we can do about it
right now.

Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
---
Changes from v2:
* Indentation fixes
* Use xf86IDrvMsg instead of xf86Msg
* Split out valuator mask freeing to a separate function

 src/evdev.c |  124 +++++++++++++++++++++++++++++++++++++++++++++++------------
 src/evdev.h |    1 +
 2 files changed, 100 insertions(+), 25 deletions(-)

diff --git a/src/evdev.c b/src/evdev.c
index 47b9652..991a712 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -766,6 +766,24 @@ EvdevProcessTouch(InputInfoPtr pInfo)
     valuator_mask_zero(pEvdev->mt_mask);
 }
 
+static int
+num_slots(EvdevPtr pEvdev)
+{
+    int value = pEvdev->absinfo[ABS_MT_SLOT].maximum -
+                pEvdev->absinfo[ABS_MT_SLOT].minimum + 1;
+
+    /* If we don't know how many slots there are, assume at least 10 */
+    return value > 1 ? value : 10;
+}
+
+static int
+last_mt_vals_slot(EvdevPtr pEvdev)
+{
+    int value = pEvdev->cur_slot - pEvdev->absinfo[ABS_MT_SLOT].minimum;
+
+    return value < num_slots(pEvdev) ? value : -1;
+}
+
 static void
 EvdevProcessTouchEvent(InputInfoPtr pInfo, struct input_event *ev)
 {
@@ -778,18 +796,32 @@ EvdevProcessTouchEvent(InputInfoPtr pInfo, struct input_event *ev)
         pEvdev->cur_slot = ev->value;
     } else
     {
+        int slot_index = last_mt_vals_slot(pEvdev);
+
         if (pEvdev->slot_state == SLOTSTATE_EMPTY)
             pEvdev->slot_state = SLOTSTATE_UPDATE;
         if (ev->code == ABS_MT_TRACKING_ID)
         {
-        if (ev->value >= 0)
-            pEvdev->slot_state = SLOTSTATE_OPEN;
-        else
-            pEvdev->slot_state = SLOTSTATE_CLOSE;
+            if (ev->value >= 0)
+            {
+                pEvdev->slot_state = SLOTSTATE_OPEN;
+
+                if (slot_index >= 0)
+                    valuator_mask_copy(pEvdev->mt_mask,
+                                       pEvdev->last_mt_vals[slot_index]);
+                else
+                    xf86IDrvMsg(pInfo, X_WARNING,
+                                "Attempted to copy values from out-of-range "
+                                "slot, touch events may be incorrect.\n");
+            } else
+                pEvdev->slot_state = SLOTSTATE_CLOSE;
         } else
         {
             map = pEvdev->axis_map[ev->code];
             valuator_mask_set(pEvdev->mt_mask, map, ev->value);
+            if (slot_index >= 0)
+                valuator_mask_set(pEvdev->last_mt_vals[slot_index], map,
+                                  ev->value);
         }
     }
 }
@@ -1061,6 +1093,34 @@ EvdevProcessEvent(InputInfoPtr pInfo, struct input_event *ev)
 #undef ABS_Y_VALUE
 #undef ABS_VALUE
 
+static void
+EvdevFreeMasks(EvdevPtr pEvdev)
+{
+    int i;
+
+    valuator_mask_free(&pEvdev->vals);
+    pEvdev->vals = NULL;
+    valuator_mask_free(&pEvdev->old_vals);
+    pEvdev->old_vals = NULL;
+    valuator_mask_free(&pEvdev->prox);
+    pEvdev->prox = NULL;
+#ifdef MULTITOUCH
+    valuator_mask_free(&pEvdev->mt_mask);
+    pEvdev->mt_mask = NULL;
+    if (pEvdev->last_mt_vals)
+    {
+        for (i = 0; i < num_slots(pEvdev); i++)
+            valuator_mask_free(&pEvdev->last_mt_vals[i]);
+        free(pEvdev->last_mt_vals);
+        pEvdev->last_mt_vals = NULL;
+    }
+    for (i = 0; i < EVDEV_MAXQUEUE; i++) {
+        valuator_mask_free(&pEvdev->queue[i].touchMask);
+        pEvdev->queue[i].touchMask = NULL;
+    }
+#endif
+}
+
 /* just a magic number to reduce the number of reads */
 #define NUM_EVENTS 16
 
@@ -1303,6 +1363,25 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device)
             goto out;
         }
 
+        pEvdev->last_mt_vals = calloc(num_slots(pEvdev), sizeof(ValuatorMask *));
+        if (!pEvdev->last_mt_vals)
+        {
+            xf86IDrvMsg(pInfo, X_ERROR,
+                        "failed to allocate MT last values mask array.\n");
+            goto out;
+        }
+
+        for (i = 0; i < num_slots(pEvdev); i++)
+        {
+            pEvdev->last_mt_vals[i] = valuator_mask_new(num_mt_axes_total);
+            if (!pEvdev->last_mt_vals[i])
+            {
+                xf86IDrvMsg(pInfo, X_ERROR,
+                            "failed to allocate MT last values mask.\n");
+                goto out;
+            }
+        }
+
         for (i = 0; i < EVDEV_MAXQUEUE; i++)
         {
             pEvdev->queue[i].touchMask =
@@ -1371,6 +1450,20 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device)
                     device->name);
             goto out;
         }
+
+        for (i = 0; i < num_slots(pEvdev); i++)
+        {
+            for (axis = ABS_MT_TOUCH_MAJOR; axis < ABS_MAX; axis++)
+            {
+                if (pEvdev->axis_map[axis] >= 0)
+                {
+                    /* XXX: read initial values from mtdev when it adds support
+                     *      for doing so. */
+                    valuator_mask_set(pEvdev->last_mt_vals[i],
+                                      pEvdev->axis_map[axis], 0);
+                }
+            }
+        }
     }
 #endif
 
@@ -1480,14 +1573,7 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device)
     return Success;
 
 out:
-    valuator_mask_free(&pEvdev->vals);
-    valuator_mask_free(&pEvdev->old_vals);
-    valuator_mask_free(&pEvdev->prox);
-#ifdef MULTITOUCH
-    valuator_mask_free(&pEvdev->mt_mask);
-    for (i = 0; i < EVDEV_MAXQUEUE; i++)
-        valuator_mask_free(&pEvdev->queue[i].touchMask);
-#endif
+    EvdevFreeMasks(pEvdev);
     return !Success;
 }
 
@@ -1831,9 +1917,6 @@ EvdevProc(DeviceIntPtr device, int what)
 {
     InputInfoPtr pInfo;
     EvdevPtr pEvdev;
-#ifdef MULTITOUCH
-    int i;
-#endif
 
     pInfo = device->public.devicePrivate;
     pEvdev = pInfo->private;
@@ -1871,16 +1954,7 @@ EvdevProc(DeviceIntPtr device, int what)
             close(pInfo->fd);
             pInfo->fd = -1;
         }
-        valuator_mask_free(&pEvdev->vals);
-        valuator_mask_free(&pEvdev->old_vals);
-        valuator_mask_free(&pEvdev->prox);
-#ifdef MULTITOUCH
-        valuator_mask_free(&pEvdev->mt_mask);
-        for (i = 0; i < EVDEV_MAXQUEUE; i++)
-            valuator_mask_free(&pEvdev->queue[i].touchMask);
-        if (pEvdev->mtdev)
-            mtdev_close(pEvdev->mtdev);
-#endif
+        EvdevFreeMasks(pEvdev);
         EvdevRemoveDevice(pInfo);
         pEvdev->min_maj = 0;
 	break;
diff --git a/src/evdev.h b/src/evdev.h
index 1713b89..309b215 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -158,6 +158,7 @@ typedef struct {
     ValuatorMask *old_vals; /* old values for calculating relative motion */
     ValuatorMask *prox;     /* last values set while not in proximity */
     ValuatorMask *mt_mask;
+    ValuatorMask **last_mt_vals;
     int cur_slot;
     enum SlotState slot_state;
 #ifdef MULTITOUCH
-- 
1.7.5.4



More information about the xorg-devel mailing list