[PATCH (v5) xinput 1/1] Add experimental multitouch support from XI 2.1

Daniel Stone daniel at fooishbar.org
Wed Jan 19 15:12:02 PST 2011


From: Chase Douglas <chase.douglas at canonical.com>

This patch adds experimental support for listening to touch streams
(TouchBegin, TouchMotion, TouchMotionUnowned, TouchOwnership, and
TouchEnd) with test-xi2, as well as showing TouchClass information
with list.

NOTE: This patch stlil contains experimental grab-testing code (the TouchBegin
      grab, as well as 'thong' and the associated XIAllowTouchEvents), which
      will be removed from the final revision.  For the time being, it's
      useful for testing.

Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
Co-authored-by: Daniel Stone <daniel at fooishbar.org>
---

v5: Updated for TouchMotionUnowned and TouchOwnership events.
    Fix buglet with 'thong' where it reset touch_events_received twice.

 configure.ac   |    6 +++
 src/list.c     |   26 +++++++++++++++
 src/test_xi2.c |   98 ++++++++++++++++++++++++++++++++++++++++++++++++-------
 3 files changed, 117 insertions(+), 13 deletions(-)

diff --git a/configure.ac b/configure.ac
index 1dc2ce2..d657a59 100644
--- a/configure.ac
+++ b/configure.ac
@@ -28,6 +28,12 @@ PKG_CHECK_MODULES(XI2, [xi >= 1.2.99.2] [inputproto >= 1.9.99.15],
                   HAVE_XI2="no");
 AM_CONDITIONAL(HAVE_XI2, [ test "$HAVE_XI2" = "yes" ])
 
+# XI2.1 support
+PKG_CHECK_MODULES(XI2_1, [xi >= 1.4.99.1] [inputproto >= 2.0.99.1],
+                  HAVE_XI2_1="yes"; AC_DEFINE(HAVE_XI2_1, 1, [XI2_1 available]),
+                  HAVE_XI2_1="no");
+AM_CONDITIONAL(HAVE_XI2_1, [ test "$HAVE_XI2_1" = "yes" ])
+
 AC_SUBST(XINPUT_CFLAGS)
 AC_SUBST(XINPUT_LIBS)
 AC_SUBST(HAVE_XI2)
diff --git a/src/list.c b/src/list.c
index aa88b28..48a74c2 100644
--- a/src/list.c
+++ b/src/list.c
@@ -177,6 +177,32 @@ print_classes_xi2(Display* display, XIAnyClassInfo **classes,
                     XFree(name);
                 }
                 break;
+#ifdef HAVE_XI2_1
+            case XITouchClass:
+                {
+                    XITouchClassInfo *t = (XITouchClassInfo *)classes[i];
+
+                    printf("\t\tMultitouch capable (max %d touches):\n",
+                           t->num_touches);
+                    printf("\t\t  Mode: %s\n",
+                           t->mode == XIDirectTouch ? "direct" : "dependent");
+                }
+                break;
+            case XITouchValuatorClass:
+                {
+                    XITouchValuatorClassInfo *tv =
+                        (XITouchValuatorClassInfo *)classes[i];
+                    char *name = tv->label ?
+                        XGetAtomName(display, tv->label) : NULL;
+
+                    printf("\t\tDetail for Touch Valuator %d:\n", tv->number);
+                    printf("\t\t  Label: %s\n",  (name) ? name : "None");
+                    printf("\t\t  Range: %f - %f\n", tv->min, tv->max);
+                    printf("\t\t  Resolution: %d units/m\n", tv->resolution);
+                    XFree(name);
+                }
+                break;
+#endif /* HAVE_XI2_1 */
         }
     }
 
diff --git a/src/test_xi2.c b/src/test_xi2.c
index 5b56397..2708c71 100644
--- a/src/test_xi2.c
+++ b/src/test_xi2.c
@@ -29,26 +29,46 @@
 extern void print_classes_xi2(Display*, XIAnyClassInfo **classes,
                               int num_classes);
 
-static Window create_win(Display *dpy)
+static void create_win(Display *dpy, Window *win, Window *subwin)
 {
-    Window win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 200,
-            200, 0, 0, WhitePixel(dpy, 0));
-    Window subwindow = XCreateSimpleWindow(dpy, win, 50, 50, 50, 50, 0, 0,
-            BlackPixel(dpy, 0));
-
-    XMapWindow(dpy, subwindow);
-    XSelectInput(dpy, win, ExposureMask);
-    return win;
+    *win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 200,
+                               200, 0, 0, WhitePixel(dpy, 0));
+    *subwin = XCreateSimpleWindow(dpy, *win, 50, 50, 50, 50, 0, 0,
+                                  BlackPixel(dpy, 0));
+    XMapWindow(dpy, *subwin);
+    XSelectInput(dpy, *win, ExposureMask);
 }
 
 static void print_deviceevent(XIDeviceEvent* event)
 {
     double *val;
     int i;
+    static int touch_events_received = 0;
+    static int thong = 0;
 
     printf("    device: %d (%d)\n", event->deviceid, event->sourceid);
     printf("    detail: %d\n", event->detail);
-    printf("    flags: %s\n", (event->flags & XIKeyRepeat) ? "repeat" : "");
+
+    switch (event->evtype)
+    {
+        case XI_KeyPress:
+        case XI_KeyRelease:
+            printf("    flags: %s\n",
+                   (event->flags & XIKeyRepeat) ? "repeat" : "");
+            break;
+#ifdef HAVE_XI2_1
+        case XI_TouchBegin:
+        case XI_TouchMotion:
+        case XI_TouchMotionUnowned:
+        case XI_TouchEnd:
+            printf("    flags: %s%s\n",
+                   (event->flags & XITouchOwnerAccepted) ?
+                    "owner accepted " : "",
+                   (event->flags & XITouchPendingFinish) ?
+                    "pending finish " : "");
+            break;
+#endif
+    }
 
     printf("    root: %.2f/%.2f\n", event->root_x, event->root_y);
     printf("    event: %.2f/%.2f\n", event->event_x, event->event_y);
@@ -74,6 +94,14 @@ static void print_deviceevent(XIDeviceEvent* event)
 
     printf("    windows: root 0x%lx event 0x%lx child 0x%lx\n",
             event->root, event->event, event->child);
+
+    if (event->evtype == XI_TouchBegin && event->event != event->child)
+        touch_events_received = 0;
+    else if (event->evtype == XI_TouchMotion && event->event != event->child &&
+             ++touch_events_received == 5)
+        XIAllowTouchEvents(event->display, event->sourceid, event->detail,
+                           (thong ^= 1) ? XITouchOwnerAccept :
+                                          XITouchOwnerReject);
 }
 
 static void print_devicechangedevent(Display *dpy, XIDeviceChangedEvent *event)
@@ -213,6 +241,16 @@ static void print_propertyevent(Display *display, XIPropertyEvent* event)
 
     XFree(name);
 }
+
+static void print_touchownershipevent(Display *display,
+                                      XITouchOwnershipEvent *event)
+{
+    printf("    device: %d (%d)\n", event->deviceid, event->sourceid);
+    printf("    touch id: %lx\n", event->touchid);
+    printf("    reason: %x\n", event->reason);
+    printf("    flags: %lx\n", event->flags);
+}
+
 void
 test_sync_grab(Display *display, Window win)
 {
@@ -279,6 +317,13 @@ static const char* type_to_name(int evtype)
         case XI_RawButtonPress:   name = "RawButtonPress";      break;
         case XI_RawButtonRelease: name = "RawButtonRelease";    break;
         case XI_RawMotion:        name = "RawMotion";           break;
+#ifdef HAVE_XI2_1
+        case XI_TouchBegin:       name = "TouchBegin";          break;
+        case XI_TouchMotion:      name = "TouchMotion";         break;
+        case XI_TouchMotionUnowned: name = "TouchMotionUnowned"; break;
+        case XI_TouchOwnership:   name = "TouchOwnership";      break;
+        case XI_TouchEnd:         name = "TouchEnd";            break;
+#endif
         default:
                                   name = "unknown event type"; break;
     }
@@ -294,14 +339,14 @@ test_xi2(Display	*display,
          char	*desc)
 {
     XIEventMask mask;
-    Window win;
+    Window win, subwin;
 
     list(display, argc, argv, name, desc);
-    win = create_win(display);
+    create_win(display, &win, &subwin);
 
     /* Select for motion events */
     mask.deviceid = XIAllDevices;
-    mask.mask_len = XIMaskLen(XI_RawMotion);
+    mask.mask_len = XIMaskLen(XI_LASTEVENT);
     mask.mask = calloc(mask.mask_len, sizeof(char));
     XISetMask(mask.mask, XI_ButtonPress);
     XISetMask(mask.mask, XI_ButtonRelease);
@@ -316,9 +361,19 @@ test_xi2(Display	*display,
     XISetMask(mask.mask, XI_HierarchyChanged);
     XISetMask(mask.mask, XI_PropertyEvent);
     XISelectEvents(display, win, &mask, 1);
+#ifdef HAVE_XI2_1
+    memset(mask.mask, 0, mask.mask_len);
+    XISetMask(mask.mask, XI_TouchBegin);
+    XISetMask(mask.mask, XI_TouchMotion);
+    XISetMask(mask.mask, XI_TouchMotionUnowned);
+    XISetMask(mask.mask, XI_TouchOwnership);
+    XISetMask(mask.mask, XI_TouchEnd);
+    XISelectEvents(display, subwin, &mask, 1);
+#endif
     XMapWindow(display, win);
     XSync(display, False);
 
+#if 0
     {
         XIGrabModifiers modifiers[] = {{0, 0}, {0, 0x10}, {0, 0x1}, {0, 0x11}};
         int nmods = sizeof(modifiers)/sizeof(modifiers[0]);
@@ -337,6 +392,20 @@ test_xi2(Display	*display,
         XIUngrabButton(display, 3, 1, win, nmods - 2, &modifiers[2]);
         XIUngrabKeycode(display, 3, 24 /* q */, win, nmods - 2, &modifiers[2]);
     }
+#else
+    {
+        XIGrabModifiers mods = { XIAnyModifier, 0 };
+        mask.deviceid = XIAllMasterDevices;
+        memset(mask.mask, 0, mask.mask_len);
+        XISetMask(mask.mask, XI_TouchBegin);
+        XISetMask(mask.mask, XI_TouchMotion);
+        XISetMask(mask.mask, XI_TouchMotionUnowned);
+        XISetMask(mask.mask, XI_TouchOwnership);
+        XISetMask(mask.mask, XI_TouchEnd);
+        XIGrabTouchBegin(display, XIAllMasterDevices, win, False, &mask,
+                         1, &mods);
+    }
+#endif
 
     mask.deviceid = XIAllMasterDevices;
     memset(mask.mask, 0, mask.mask_len);
@@ -394,6 +463,9 @@ test_xi2(Display	*display,
                 case XI_PropertyEvent:
                     print_propertyevent(display, cookie->data);
                     break;
+                case XI_TouchOwnership:
+                    print_touchownershipevent(display, cookie->data);
+                    break;
                 default:
                     print_deviceevent(cookie->data);
                     break;
-- 
1.7.2.3



More information about the xorg-devel mailing list