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

Peter Hutterer peter.hutterer at who-t.net
Thu Jan 20 21:03:16 PST 2011


On Wed, Jan 19, 2011 at 11:12:02PM +0000, Daniel Stone wrote:
> 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.

if this will be removed from the final revision anyway, couldn't you just
split it up into the part that'll be committed and the testing part on top
of it?

Cheers,
  Peter

> 
> 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
> 
> _______________________________________________
> xorg-devel at lists.x.org: X.Org development
> Archives: http://lists.x.org/archives/xorg-devel
> Info: http://lists.x.org/mailman/listinfo/xorg-devel
> 


More information about the xorg-devel mailing list