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

Peter Hutterer peter.hutterer at who-t.net
Tue Dec 21 18:56:48 PST 2010


On Fri, Dec 17, 2010 at 05:14:49PM +0000, Daniel Stone wrote:
> From: Chase Douglas <chase.douglas at canonical.com>
> 
> This patch adds experimental support for listening to touch streams
> (TouchBegin, TouchMotion and TouchEnd) with test-xi2, as well as showing
> TouchClass information with list.
> 
> Based on an initial patch by Daniel Stone.
> 
> Signed-off-by: Daniel Stone <daniel at fooishbar.org>
> Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
> ---
>  configure.ac   |    6 ++++
>  src/list.c     |   28 ++++++++++++++++++++
>  src/test_xi2.c |   76 +++++++++++++++++++++++++++++++++++++++++++++++---------
>  3 files changed, 98 insertions(+), 12 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 8633c62..8920cad 100644
> --- a/src/list.c
> +++ b/src/list.c
> @@ -24,6 +24,9 @@
>  #include "xinput.h"
>  #include <string.h>
>  #include <X11/extensions/XIproto.h> /* for XI_Device***ChangedNotify */
> +#ifdef HAVE_XI2_1
> +#include <X11/extensions/XI2proto.h> /* for XITouch* */
> +#endif

this strikes me as odd. a client should never have to include the protocol
header unless it's doing something special (and most likely wrong).
I just checked the XIproto.h include and it still builds fine without it.
the line was added in 2007 when XI2 was still a bit too much in flux.

>  static void
>  print_info(Display* dpy, XDeviceInfo	*info, Bool shortformat)
> @@ -178,6 +181,31 @@ 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);
> +                }

not that it really matters, but free(name) would close the leak.

> +                break;
> +#endif /* HAVE_XI2_1 */
>          }
>      }
>  
> diff --git a/src/test_xi2.c b/src/test_xi2.c
> index 5b56397..443bbd8 100644
> --- a/src/test_xi2.c
> +++ b/src/test_xi2.c
> @@ -29,26 +29,41 @@
>  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;

thong or flip-flop? this may be a source of much confusion.

>      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:

indentation inside the switch please.

> +    case XI_KeyRelease:
> +        printf("    flags: %s\n", (event->flags & XIKeyRepeat) ? "repeat" : "");
> +        break;
> +    case XI_TouchBegin:
> +    case XI_TouchMotion:
> +    case XI_TouchEnd:
> +        printf("    flags: %s%s%s\n",
> +                (event->flags & XITouchOwner) ? "owner " : "",
> +                (event->flags & XITouchOwnerAccepted) ? "owner accepted " : "",
> +                (event->flags & XITouchPendingFinish) ? "pending finish " : "");
> +        break;
> +    }
>  
>      printf("    root: %.2f/%.2f\n", event->root_x, event->root_y);
>      printf("    event: %.2f/%.2f\n", event->event_x, event->event_y);
> @@ -74,6 +89,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)
> +        touch_events_received = 0;
> +    else if (event->evtype == XI_TouchMotion && event->event != event->child &&
> +             (event->flags & XITouchOwner) && ++touch_events_received == 5)
> +        XIAllowTouchEvents(event->display, event->sourceid, event->detail,
> +                           (thong ^= 1) ? XITouchOwnerAccept :
>  
> +                                          XITouchOwnerReject);

some comment about what the effect of this is would be nice. afaict, it
releases the touch after 5 events, once with accept, once with reject?

Any specific reason for this? xinput isn't a demo app but more to test the
event stream from a device for debugging. not sure how the above behaviour
will help with this. 

>  }
>  
>  static void print_devicechangedevent(Display *dpy, XIDeviceChangedEvent *event)
> @@ -279,6 +302,11 @@ 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_TouchEnd:         name = "TouchEnd";            break;
> +        case XI_TouchMotion:      name = "TouchMotion";         break;
> +#endif
>          default:
>                                    name = "unknown event type"; break;
>      }
> @@ -294,14 +322,18 @@ 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;
> +#ifdef HAVE_XI2_1
> +    mask.mask_len = XIMaskLen(XI_TouchMotion);
> +#else
>      mask.mask_len = XIMaskLen(XI_RawMotion);
> +#endif

XI_LASTEVENT to avoid the ifdef?

Cheers,
  Peter

>      mask.mask = calloc(mask.mask_len, sizeof(char));
>      XISetMask(mask.mask, XI_ButtonPress);
>      XISetMask(mask.mask, XI_ButtonRelease);
> @@ -316,9 +348,17 @@ 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_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 +377,18 @@ 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_TouchEnd);
> +        XIGrabTouchBegin(display, XIAllMasterDevices, win, False, &mask,
> +                         1, &mods);
> +    }
> +#endif
>  
>      mask.deviceid = XIAllMasterDevices;
>      memset(mask.mask, 0, mask.mask_len);
> -- 
> 1.7.2.3



More information about the xorg-devel mailing list