[PATCH synaptics] Avoid erroneously handling two touchpoints in the same slot

Peter Hutterer peter.hutterer at who-t.net
Thu Mar 20 00:21:04 PDT 2014


If a slot's ABS_MT_TRACKING_ID event was received during SYN_DROPPED, the
driver isn't aware that a touchpoint has started or ended in that slot. When
the next ABS_MT_TRACKING_ID event arrives, the driver would unconditionally
close or open a new touchpoint. This could lead to two or more touchpoints
being opened in the same slot, the first of which is never terminated.
Or it could lead to a touchpoint being terminated that was never opened.

The event sequences that trigger this are:
    ABS_MT_TRACKING_ID 83
    ABS_MT_TRACKING_ID -1
    SYN_DROPPED             // new touchpoint started here
    ABS_MT_TRACKING_ID -1

and

    ABS_MT_TRACKING_ID 83
    SYN_DROPPED             // touchpoint ended here
    ABS_MT_TRACKING_ID 84
    ABS_MT_TRACKING_ID -1

We don't properly handle SYN_DROPPED, but we can avoid this by only starting a
new touchpoint when we transition between -1 and a valid tracking ID.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
This is for the 1.7 branch that doesn't use libevdev. There's a potential
for erroneous events like cursor jumps or missing tap, but that's still
better than the current situation.

 src/eventcomm.c | 34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/src/eventcomm.c b/src/eventcomm.c
index 27283ca..68e4f29 100644
--- a/src/eventcomm.c
+++ b/src/eventcomm.c
@@ -76,6 +76,7 @@ struct eventcomm_proto_data {
     int cur_slot;
     ValuatorMask **last_mt_vals;
     int num_touches;
+    int *tracking_ids;
 };
 
 struct eventcomm_proto_data *
@@ -125,6 +126,9 @@ UninitializeTouch(InputInfoPtr pInfo)
     mtdev_close_delete(proto_data->mtdev);
     proto_data->mtdev = NULL;
     proto_data->num_touches = 0;
+
+    free(proto_data->tracking_ids);
+    proto_data->tracking_ids = NULL;
 }
 
 static void
@@ -156,9 +160,18 @@ InitializeTouch(InputInfoPtr pInfo)
         return;
     }
 
+    proto_data->tracking_ids = calloc(priv->num_slots, sizeof(int));
+    if (!proto_data->tracking_ids) {
+        xf86IDrvMsg(pInfo, X_WARNING, "failed to allocate tracking ID array\n");
+        UninitializeTouch(pInfo);
+        return;
+    }
+
     for (i = 0; i < priv->num_slots; i++) {
         int j;
 
+        proto_data->tracking_ids[i] = -1;
+
         proto_data->last_mt_vals[i] = valuator_mask_new(4 + priv->num_mt_axes);
         if (!proto_data->last_mt_vals[i]) {
             xf86IDrvMsg(pInfo, X_WARNING,
@@ -555,7 +568,24 @@ EventProcessTouchEvent(InputInfoPtr pInfo, struct SynapticsHwState *hw,
         if (hw->slot_state[slot_index] == SLOTSTATE_OPEN_EMPTY)
             hw->slot_state[slot_index] = SLOTSTATE_UPDATE;
         if (ev->code == ABS_MT_TRACKING_ID) {
-            if (ev->value >= 0) {
+            int old_tracking_id = proto_data->tracking_ids[slot_index];
+
+            /* We don't have proper SYN_DROPPED handling in
+               synaptics < 1.8. This is a poor man's version that covers the
+               worst bug we're seeing: touch points starting/stopping during
+               SYN_DROPPED. There can only be one touchpoint per slot,
+               identified by the tracking ID. Make sure that we only ever
+               have a single touch point open per slot.
+             */
+            if (ev->value != -1 && old_tracking_id != -1) {
+                /* Our touch terminated during SYN_DROPPED, now we have a
+                   new touch starting in the same slot but ours is still
+                   open. Do nothing, just continue with the old touch */
+            } else if (ev->value == -1 && old_tracking_id == -1) {
+                /* A new touch started during SYN_DROPPED, now we have that
+                   touch terminating. Do nothing, we don't have that touch
+                   open */
+            } else if (ev->value >= 0) {
                 hw->slot_state[slot_index] = SLOTSTATE_OPEN;
                 proto_data->num_touches++;
                 valuator_mask_copy(hw->mt_mask[slot_index],
@@ -565,6 +595,8 @@ EventProcessTouchEvent(InputInfoPtr pInfo, struct SynapticsHwState *hw,
                 hw->slot_state[slot_index] = SLOTSTATE_CLOSE;
                 proto_data->num_touches--;
             }
+
+            proto_data->tracking_ids[slot_index] = ev->value;
         }
         else {
             ValuatorMask *mask = proto_data->last_mt_vals[slot_index];
-- 
1.8.5.3



More information about the xorg-devel mailing list