[PATCH evdev v2] Add proximity support.

Peter Hutterer peter.hutterer at who-t.net
Tue Oct 12 18:44:38 PDT 2010


When one of the tools comes into proximity, queue up a proximity event and
send it accordingly.

Includes special handling for tablets that do not send axes with tools
(#29645)

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.hutterer at who-t.net>
---
As Benjamin pointed out, patch 2/3 of the previous set was incorrect by
itself (rebase -i got the better of me). Because I can't be bothered to
untangle the two, fix up a commit just to undo half of it in the next one
anyway, I just squashed the two together.

 src/evdev.c |  118 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/evdev.h |    5 ++-
 2 files changed, 121 insertions(+), 2 deletions(-)

diff --git a/src/evdev.c b/src/evdev.c
index 9e1fb10..0ef7170 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -322,7 +322,18 @@ EvdevQueueButtonEvent(InputInfoPtr pInfo, int button, int value)
         pQueue->key = button;
         pQueue->val = value;
     }
+}
 
+void
+EvdevQueueProximityEvent(InputInfoPtr pInfo, int value)
+{
+    EventQueuePtr pQueue;
+    if ((pQueue = EvdevNextInQueue(pInfo)))
+    {
+        pQueue->type = EV_QUEUE_PROXIMITY;
+        pQueue->key = 0;
+        pQueue->val = value;
+    }
 }
 
 /**
@@ -459,6 +470,70 @@ EvdevProcessValuators(InputInfoPtr pInfo, int v[MAX_VALUATORS], int *num_v,
     }
 }
 
+static void
+EvdevProcessProximityEvent(InputInfoPtr pInfo, struct input_event *ev)
+{
+    EvdevPtr pEvdev = pInfo->private;
+
+    pEvdev->prox = 1;
+
+    EvdevQueueProximityEvent(pInfo, ev->value);
+}
+
+/**
+ * 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.
  */
@@ -583,6 +658,7 @@ EvdevProcessKeyEvent(InputInfoPtr pInfo, struct input_event *ev)
             return;
 
     switch (ev->code) {
+        /* keep this list in sync with InitProximityClassDeviceStruct */
         case BTN_TOOL_PEN:
         case BTN_TOOL_RUBBER:
         case BTN_TOOL_BRUSH:
@@ -591,7 +667,7 @@ EvdevProcessKeyEvent(InputInfoPtr pInfo, struct input_event *ev)
         case BTN_TOOL_FINGER:
         case BTN_TOOL_MOUSE:
         case BTN_TOOL_LENS:
-            pEvdev->proximity = value ? ev->code : 0;
+            EvdevProcessProximityEvent(pInfo, ev);
             break;
 
         case BTN_TOUCH:
@@ -645,6 +721,27 @@ EvdevPostAbsoluteMotionEvents(InputInfoPtr pInfo, int num_v, int first_v,
     }
 }
 
+static void
+EvdevPostProximityEvents(InputInfoPtr pInfo, int which, int num_v, int first_v,
+                                  int v[MAX_VALUATORS])
+{
+    int i;
+    EvdevPtr pEvdev = pInfo->private;
+
+    for (i = 0; pEvdev->prox && i < pEvdev->num_queue; i++) {
+        switch (pEvdev->queue[i].type) {
+            case EV_QUEUE_KEY:
+            case EV_QUEUE_BTN:
+                break;
+            case EV_QUEUE_PROXIMITY:
+                if (pEvdev->queue[i].val == which)
+                    xf86PostProximityEventP(pInfo->dev, which, first_v, num_v,
+                            v + first_v);
+                break;
+        }
+    }
+}
+
 /**
  * Post the queued key/button events.
  */
@@ -672,6 +769,8 @@ static void EvdevPostQueuedEvents(InputInfoPtr pInfo, int num_v, int first_v,
                 xf86PostButtonEvent(pInfo->dev, 0, pEvdev->queue[i].key,
                                     pEvdev->queue[i].val, 0, 0);
             break;
+        case EV_QUEUE_PROXIMITY:
+            break;
         }
     }
 }
@@ -687,17 +786,23 @@ 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);
     EvdevPostRelativeMotionEvents(pInfo, num_v, first_v, v);
     EvdevPostAbsoluteMotionEvents(pInfo, num_v, first_v, v);
     EvdevPostQueuedEvents(pInfo, num_v, first_v, v);
+    EvdevPostProximityEvents(pInfo, FALSE, num_v, first_v, v);
 
     memset(pEvdev->delta, 0, sizeof(pEvdev->delta));
     memset(pEvdev->queue, 0, sizeof(pEvdev->queue));
     pEvdev->num_queue = 0;
     pEvdev->abs = 0;
     pEvdev->rel = 0;
+    pEvdev->prox = 0;
+
 }
 
 /**
@@ -1226,6 +1331,17 @@ EvdevAddAbsClass(DeviceIntPtr device)
 
     free(atoms);
 
+    /* keep this list in sync with EvdevProcessKeyEvent */
+    if (TestBit(BTN_TOOL_PEN, pEvdev->key_bitmask) ||
+        TestBit(BTN_TOOL_RUBBER, pEvdev->key_bitmask) ||
+        TestBit(BTN_TOOL_BRUSH, pEvdev->key_bitmask) ||
+        TestBit(BTN_TOOL_PENCIL, pEvdev->key_bitmask) ||
+        TestBit(BTN_TOOL_AIRBRUSH, pEvdev->key_bitmask) ||
+        TestBit(BTN_TOOL_FINGER, pEvdev->key_bitmask) ||
+        TestBit(BTN_TOOL_MOUSE, pEvdev->key_bitmask) ||
+        TestBit(BTN_TOOL_LENS, pEvdev->key_bitmask))
+        InitProximityClassDeviceStruct(device);
+
     if (!InitPtrFeedbackClassDeviceStruct(device, EvdevPtrCtrlProc))
         return !Success;
 
diff --git a/src/evdev.h b/src/evdev.h
index b382670..af93d41 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -109,6 +109,7 @@ typedef struct {
     enum {
         EV_QUEUE_KEY,	/* xf86PostKeyboardEvent() */
         EV_QUEUE_BTN,	/* xf86PostButtonEvent() */
+        EV_QUEUE_PROXIMITY, /* xf86PostProximityEvent() */
     } type;
     int key;		/* May be either a key code or button number. */
     int val;		/* State of the key/button; pressed or released. */
@@ -131,7 +132,8 @@ typedef struct {
     BOOL invert_y;
 
     int delta[REL_CNT];
-    unsigned int abs, rel;
+    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
@@ -198,6 +200,7 @@ typedef struct {
 /* Event posting functions */
 void EvdevQueueKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value);
 void EvdevQueueButtonEvent(InputInfoPtr pInfo, int button, int value);
+void EvdevQueueProximityEvent(InputInfoPtr pInfo, int value);
 void EvdevPostButtonEvent(InputInfoPtr pInfo, int button, int value);
 void EvdevQueueButtonClicks(InputInfoPtr pInfo, int button, int count);
 void EvdevPostRelativeMotionEvents(InputInfoPtr pInfo, int num_v, int first_v,
-- 
1.7.2.3



More information about the xorg-devel mailing list