Some tablets send axis values, then EV_SYN, and in the next event the
BTN_TOOL_PEN/BTN_TOUCH, etc. For these tablets, the cursor doesn't move as
coordinates while not in proximity are ignored.

Buffer coordinates received while out-of-proximity and if we get a proximity
event without other coordinates, re-use the last ones received.

X.Org Bug 29645 <http://bugs.freedesktop.org/show_bug.cgi?id=29645>

Signed-off-by: Peter Hutterer <peter.hutte...@who-t.net>
---
 src/evdev.c |   56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/evdev.h |    1 +
 2 files changed, 57 insertions(+), 0 deletions(-)

diff --git a/src/evdev.c b/src/evdev.c
index 634c174..0ef7170 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -481,6 +481,60 @@ EvdevProcessProximityEvent(InputInfoPtr pInfo, struct 
input_event *ev)
 }
 
 /**
+ * Proximity handling is rather weird because of tablet-specific issues.
+ * Some tablets, notably Wacoms, send a 0/0 coordinate in the same EV_SYN as
+ * the out-of-proximity notify. We need to ignore those, hence we only
+ * actually post valuator events when we're in proximity.
+ *
+ * Other tablets send the x/y coordinates, then EV_SYN, then the proximity
+ * event. For those, we need to remember x/y to post it when the proximity
+ * comes.
+ *
+ * If we're not in proximity and we get valuator events, remember that, they
+ * won't be posted though. If we move into proximity without valuators, use
+ * the last ones we got and let the rest of the code post them.
+ */
+static int
+EvdevProcessProximityState(InputInfoPtr pInfo)
+{
+    EvdevPtr pEvdev = pInfo->private;
+    int prox_state = 0;
+    int i;
+
+    /* no proximity change in the queue */
+    if (!pEvdev->prox)
+    {
+        if (pEvdev->abs && !pEvdev->proximity)
+            pEvdev->abs_prox = pEvdev->abs;
+        return 0;
+    }
+
+    for (i = 0; pEvdev->prox && i < pEvdev->num_queue; i++)
+    {
+        if (pEvdev->queue[i].type == EV_QUEUE_PROXIMITY)
+        {
+            prox_state = pEvdev->queue[i].val;
+            break;
+        }
+    }
+
+    if ((prox_state && !pEvdev->proximity) ||
+        (!prox_state && pEvdev->proximity))
+    {
+        /* We're about to go into/out of proximity but have no abs events
+         * within the EV_SYN. Use the last coordinates we have. */
+        if (!pEvdev->abs && pEvdev->abs_prox)
+        {
+            pEvdev->abs = pEvdev->abs_prox;
+            pEvdev->abs_prox = 0;
+        }
+    }
+
+    pEvdev->proximity = prox_state;
+    return 1;
+}
+
+/**
  * Take a button input event and process it accordingly.
  */
 static void
@@ -732,6 +786,8 @@ EvdevProcessSyncEvent(InputInfoPtr pInfo, struct 
input_event *ev)
     int v[MAX_VALUATORS] = {};
     EvdevPtr pEvdev = pInfo->private;
 
+    EvdevProcessProximityState(pInfo);
+
     EvdevProcessValuators(pInfo, v, &num_v, &first_v);
 
     EvdevPostProximityEvents(pInfo, TRUE, num_v, first_v, v);
diff --git a/src/evdev.h b/src/evdev.h
index 08f3c13..af93d41 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -133,6 +133,7 @@ typedef struct {
 
     int delta[REL_CNT];
     unsigned int abs, rel, prox;
+    unsigned int abs_prox;  /* valuators posted while out of prox? */
 
     /* XKB stuff has to be per-device rather than per-driver */
 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 5
-- 
1.7.2.3

_______________________________________________
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