diff options
-rw-r--r-- | configure.ac | 9 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/hierarchy.c | 96 | ||||
-rw-r--r-- | src/list.c | 198 | ||||
-rw-r--r-- | src/property.c | 301 | ||||
-rw-r--r-- | src/setcp.c | 13 | ||||
-rw-r--r-- | src/test_xi2.c | 359 | ||||
-rw-r--r-- | src/xinput.c | 61 | ||||
-rw-r--r-- | src/xinput.h | 9 |
9 files changed, 904 insertions, 146 deletions
diff --git a/configure.ac b/configure.ac index e973c22..8314a6b 100644 --- a/configure.ac +++ b/configure.ac @@ -20,11 +20,12 @@ XORG_CWARNFLAGS # Checks for pkg-config packages PKG_CHECK_MODULES(XINPUT, x11 xext [xi >= 1.2] [inputproto >= 1.5]) -LIBS="$XINPUT_LIBS $LIBS" -AC_CHECK_FUNC(XSetClientPointer,AC_DEFINE(HAVE_XI2,1,[XInput Version 2 Enabled])) -AM_CONDITIONAL(HAVE_XI2, [test "x$ac_cv_func_XSetClientPointer" = "xyes"] ) +# XI2 support +PKG_CHECK_MODULES(XI2, [xi >= 1.2.99], + HAVE_XI2="yes"; AC_DEFINE(HAVE_XI2, 1, "foo"), + HAVE_XI2="no"); +AM_CONDITIONAL(HAVE_XI2, [ test "$HAVE_XI2" = "yes" ]) -XINPUT_CFLAGS="$CWARNFLAGS $XINPUT_CFLAGS" AC_SUBST(XINPUT_CFLAGS) AC_SUBST(XINPUT_LIBS) AC_SUBST(HAVE_XI2) diff --git a/src/Makefile.am b/src/Makefile.am index 1efddb8..a6dedb7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -26,8 +26,8 @@ xinput_LDADD = $(XINPUT_LIBS) if HAVE_XI2 - xinput2_files = hierarchy.c setcp.c -endif # HAVE_XI2 +xinput2_files = hierarchy.c setcp.c test_xi2.c +endif xinput_SOURCES = \ buttonmap.c \ diff --git a/src/hierarchy.c b/src/hierarchy.c index 869c3fd..9f0cc8f 100644 --- a/src/hierarchy.c +++ b/src/hierarchy.c @@ -40,7 +40,7 @@ int create_master(Display* dpy, int argc, char** argv, char* name, char *desc) { - XCreateMasterInfo c; + XICreateMasterInfo c; if (argc == 0) { @@ -48,12 +48,12 @@ create_master(Display* dpy, int argc, char** argv, char* name, char *desc) return EXIT_FAILURE; } - c.type = CH_CreateMasterDevice; + c.type = XICreateMasterDevice; c.name = argv[0]; c.sendCore = (argc >= 2) ? atoi(argv[1]) : 1; c.enable = (argc >= 3) ? atoi(argv[2]) : 1; - return XChangeDeviceHierarchy(dpy, (XAnyHierarchyChangeInfo*)&c, 1); + return XIChangeDeviceHierarchy(dpy, (XIAnyHierarchyChangeInfo*)&c, 1); } /** @@ -64,9 +64,8 @@ create_master(Display* dpy, int argc, char** argv, char* name, char *desc) int remove_master(Display* dpy, int argc, char** argv, char *name, char *desc) { - XDeviceInfo *info; - XRemoveMasterInfo r; - XDevice* master = NULL, *ptr = NULL, *keybd = NULL; + XIRemoveMasterInfo r; + XIDeviceInfo *info; int ret; if (argc == 0) @@ -75,45 +74,33 @@ remove_master(Display* dpy, int argc, char** argv, char *name, char *desc) return EXIT_FAILURE; } - info = find_device_info(dpy, argv[0], False); + info = xi2_find_device_info(dpy, argv[0]); if (!info) { fprintf(stderr, "unable to find device %s\n", argv[0]); return EXIT_FAILURE; } - master = XOpenDevice(dpy, info->id); - if (!master) - Error(BadValue, "Unable to open device %s.\n", argv[0]); - - r.type = CH_RemoveMasterDevice; - r.device = master; + r.type = XIRemoveMasterDevice; + r.device = info->deviceid; if (argc >= 2) { if (!strcmp(argv[1], "Floating")) - r.returnMode = Floating; + r.returnMode = XIFloating; else if (!strcmp(argv[1], "AttachToMaster")) - r.returnMode = AttachToMaster; + r.returnMode = XIAttachToMaster; else Error(BadValue, "Invalid returnMode.\n"); } else - r.returnMode = Floating; + r.returnMode = XIFloating; - if (r.returnMode == AttachToMaster) + if (r.returnMode == XIAttachToMaster) { - ptr = XOpenDevice(dpy, atoi(argv[2])); - keybd = XOpenDevice(dpy, atoi(argv[3])); - if (!ptr || !keybd) - Error(BadValue, "Invalid fallback master.\n"); - r.returnPointer = ptr; - r.returnKeyboard = keybd; + r.returnPointer = atoi(argv[2]); + r.returnKeyboard = atoi(argv[3]); } - ret = XChangeDeviceHierarchy(dpy, (XAnyHierarchyChangeInfo*)&r, 1); - if (ptr) - XCloseDevice(dpy, ptr); - if (keybd) - XCloseDevice(dpy, keybd); + ret = XIChangeDeviceHierarchy(dpy, (XIAnyHierarchyChangeInfo*)&r, 1); return ret; } @@ -123,9 +110,8 @@ remove_master(Display* dpy, int argc, char** argv, char *name, char *desc) int change_attachment(Display* dpy, int argc, char** argv, char *name, char* desc) { - XDeviceInfo *info_sd, *info_md; - XChangeAttachmentInfo c; - XDevice *slave, *master; + XIDeviceInfo *sd_info, *md_info; + XIAttachSlaveInfo c; int ret; if (argc < 2) @@ -134,36 +120,24 @@ change_attachment(Display* dpy, int argc, char** argv, char *name, char* desc) return EXIT_FAILURE; } - info_sd = find_device_info(dpy, argv[0], True); - info_md = find_device_info(dpy, argv[1], False); + sd_info = xi2_find_device_info(dpy, argv[0]); + md_info= xi2_find_device_info(dpy, argv[1]); - if (!info_sd) { + if (!sd_info) { fprintf(stderr, "unable to find device %s\n", argv[0]); return EXIT_FAILURE; } - if (!info_md) { + if (!md_info) { fprintf(stderr, "unable to find device %s\n", argv[1]); return EXIT_FAILURE; } - slave = XOpenDevice(dpy, info_sd->id); - master = XOpenDevice(dpy, info_md->id); - - if (!slave) - Error(BadValue, "Invalid slave device given %d\n", atoi(argv[0])); - - if (!master) - Error(BadValue, "Invalid master device given %d\n", atoi(argv[1])); + c.type = XIAttachSlave; + c.device = sd_info->deviceid; + c.newMaster = md_info->deviceid; - c.type = CH_ChangeAttachment; - c.changeMode = AttachToMaster; - c.device = slave; - c.newMaster = master; - - ret = XChangeDeviceHierarchy(dpy, (XAnyHierarchyChangeInfo*)&c, 1); - XCloseDevice(dpy, slave); - XCloseDevice(dpy, master); + ret = XIChangeDeviceHierarchy(dpy, (XIAnyHierarchyChangeInfo*)&c, 1); return ret; } @@ -173,9 +147,8 @@ change_attachment(Display* dpy, int argc, char** argv, char *name, char* desc) int float_device(Display* dpy, int argc, char** argv, char* name, char* desc) { - XDeviceInfo *info; - XChangeAttachmentInfo c; - XDevice *slave; + XIDeviceInfo *info; + XIDetachSlaveInfo c; int ret; if (argc < 1) @@ -184,24 +157,17 @@ float_device(Display* dpy, int argc, char** argv, char* name, char* desc) return EXIT_FAILURE; } - info = find_device_info(dpy, argv[0], True); + info = xi2_find_device_info(dpy, argv[0]); if (!info) { fprintf(stderr, "unable to find device %s\n", argv[0]); return EXIT_FAILURE; } - slave = XOpenDevice(dpy, info->id); - - if (!slave) - return BadValue; - - c.type = CH_ChangeAttachment; - c.changeMode = Floating; - c.device = slave; + c.type = XIDetachSlave; + c.device = info->deviceid; - ret = XChangeDeviceHierarchy(dpy, (XAnyHierarchyChangeInfo*)&c, 1); - XCloseDevice(dpy, slave); + ret = XIChangeDeviceHierarchy(dpy, (XIAnyHierarchyChangeInfo*)&c, 1); return ret; } @@ -34,9 +34,6 @@ print_info(Display* dpy, XDeviceInfo *info, Bool shortformat) XButtonInfoPtr b; XValuatorInfoPtr v; XAxisInfoPtr a; -#if HAVE_XI2 - XAttachInfoPtr att; -#endif printf("\"%s\"\tid=%ld\t[", info->name, info->id); @@ -98,12 +95,6 @@ print_info(Display* dpy, XDeviceInfo *info, Bool shortformat) printf ("\t\tResolution is %d\n", a->resolution); } break; -#if HAVE_XI2 - case AttachClass: - att = (XAttachInfoPtr)any; - printf("\tAttached to %d\n", att->attached); - break; -#endif default: printf ("unknown class\n"); } @@ -112,12 +103,11 @@ print_info(Display* dpy, XDeviceInfo *info, Bool shortformat) } } -int -list(Display *display, - int argc, - char *argv[], - char *name, - char *desc) +static int list_xi1(Display *display, + int argc, + char *argv[], + char *name, + char *desc) { XDeviceInfo *info; int loop; @@ -129,44 +119,12 @@ list(Display *display, if (argc == 0 || shortformat || daemon) { int num_devices; - XEvent ev; - -#if HAVE_XI2 - if (daemon) - { - XiSelectEvent(display, DefaultRootWindow(display), NULL, - XI_DeviceHierarchyChangedMask | - XI_DeviceClassesChangedMask); - } -#endif do { info = XListInputDevices(display, &num_devices); for(loop=0; loop<num_devices; loop++) { print_info(display, info+loop, shortformat); } - -#if HAVE_XI2 - /* just wait for the next generic event to come along */ - while (daemon && !XNextEvent(display, &ev)) - { - if (ev.type == GenericEvent) - { - XGenericEvent* gev = (XGenericEvent*)&ev; - /* we just assume that extension is IReqCode, pretty save - since we don't register for other events. */ - if (gev->evtype == XI_DeviceHierarchyChangedNotify) - { - printf("Hierarchy change.\n"); - } else if (gev->evtype == XI_DeviceClassesChangedNotify) - { - printf("Device classes changed.\n"); - free(((XDeviceClassesChangedEvent*)&ev)->inputclassinfo); - } - break; - } - } -#endif } while(daemon); } else { int ret = EXIT_SUCCESS; @@ -186,4 +144,150 @@ list(Display *display, return EXIT_SUCCESS; } +#ifdef HAVE_XI2 +/* also used from test_xi2.c */ +void +print_classes_xi2(Display* display, XIAnyClassInfo **classes, + int num_classes) +{ + int i; + + printf("\tReporting %d classes:\n", num_classes); + for (i = 0; i < num_classes; i++) + { + switch(classes[i]->type) + { + case ButtonClass: + { + XIButtonClassInfo *b = (XIButtonClassInfo*)classes[i]; + printf("\t\tButtons supported: %d\n", b->num_buttons); + + } + break; + case KeyClass: + { + XIKeyClassInfo *k = (XIKeyClassInfo*)classes[i]; + printf("\t\tKeycodes supported: %d\n", k->num_keycodes); + } + break; + case ValuatorClass: + { + XIValuatorClassInfo *v = (XIValuatorClassInfo*)classes[i]; + printf("\t\tDetail for Valuator %d:\n", v->number); + printf("\t\t Name: %s\n", XGetAtomName(display, v->name)); + printf("\t\t Range: %f - %f\n", v->min, v->max); + printf("\t\t Resolution: %d units/m\n", v->resolution); + printf("\t\t Mode: %s\n", v->mode == Absolute ? "absolute" : + "relative"); + } + break; + } + } + + printf("\n"); +} + +static void +print_info_xi2(Display* display, XIDeviceInfo *dev, Bool shortformat) +{ + printf("%-40s\tid=%d\t[", dev->name, dev->deviceid); + switch(dev->use) + { + case XIMasterPointer: + printf("master pointer (%d)]\n", dev->attachment); + break; + case XIMasterKeyboard: + printf("master keyboard (%d)]\n", dev->attachment); + break; + case XISlavePointer: + printf("slave pointer (%d)]\n", dev->attachment); + break; + case XISlaveKeyboard: + printf("slave keyboard (%d)]\n", dev->attachment); + break; + case XIFloatingSlave: + printf("floating slave]\n"); + break; + } + + if (shortformat) + return; + + if (!dev->enabled) + printf("\tThis device is disabled\n"); + + print_classes_xi2(display, dev->classes, dev->num_classes); +} + + +int +list_xi2(Display *display, + int argc, + char *argv[], + char *name, + char *desc) +{ + int major = XI_2_Major, + minor = XI_2_Minor; + int ndevices; + int i, j, shortformat; + XIDeviceInfo *info, *dev; + + shortformat = (argc == 1 && strcmp(argv[0], "--short") == 0); + + if (XIQueryVersion(display, &major, &minor) != Success || + (major * 1000 + minor) < (XI_2_Major * 1000 + XI_2_Minor)) + { + fprintf(stderr, "XI2 not supported.\n"); + return EXIT_FAILURE; + } + + info = XIQueryDevice(display, XIAllDevices, &ndevices); + dev = info; + + for(i = 0; i < ndevices; i++) + { + dev = &info[i]; + if (dev->use == XIMasterPointer || dev->use == XIMasterKeyboard) + { + if (dev->use == XIMasterPointer) + printf("⎡ "); + else + printf("⎣ "); + + print_info_xi2(display, dev, shortformat); + for (j = 0; j < ndevices; j++) + { + XIDeviceInfo* sd = &info[j]; + + if ((sd->use == XISlavePointer || sd->use == XISlaveKeyboard) && + (sd->attachment == dev->deviceid)) + { + printf("%s ↳ ", dev->use == XIMasterPointer ? "⎜" : " "); + print_info_xi2(display, sd, shortformat); + } + } + } + } + + + XIFreeDeviceInfo(info); + return EXIT_SUCCESS; +} +#endif + +int +list(Display *display, + int argc, + char *argv[], + char *name, + char *desc) +{ +#ifdef HAVE_XI2 + if (xinput_version(display) == XI_2_Major) + return list_xi2(display, argc, argv, name, desc); +#endif + return list_xi1(display, argc, argv, name, desc); +} + /* end of list.c */ diff --git a/src/property.c b/src/property.c index db46059..2b402a9 100644 --- a/src/property.c +++ b/src/property.c @@ -128,10 +128,10 @@ print_property(Display *dpy, XDevice* dev, Atom property) ptr += size; - if (j < nitems - 1) - printf(", "); if (done == True) break; + if (j < nitems - 1) + printf(", "); } printf("\n"); XFree(data); @@ -140,7 +140,8 @@ print_property(Display *dpy, XDevice* dev, Atom property) } -int list_props(Display *dpy, int argc, char** argv, char* name, char *desc) +static int +list_props_xi1(Display *dpy, int argc, char** argv, char* name, char *desc) { XDeviceInfo *info; XDevice *dev; @@ -374,7 +375,8 @@ int watch_props(Display *dpy, int argc, char** argv, char* n, char *desc) XCloseDevice(dpy, dev); } -int delete_prop(Display *dpy, int argc, char** argv, char* n, char *desc) +static int +delete_prop_xi1(Display *dpy, int argc, char** argv, char* n, char *desc) { XDevice *dev; XDeviceInfo *info; @@ -471,8 +473,8 @@ set_atom_prop(Display *dpy, int argc, char** argv, char* n, char *desc) return EXIT_SUCCESS; } -int -set_prop(Display *dpy, int argc, char **argv, char *n, char *desc) +static int +set_prop_xi1(Display *dpy, int argc, char **argv, char *n, char *desc) { XDeviceInfo *info; XDevice *dev; @@ -587,3 +589,290 @@ set_prop(Display *dpy, int argc, char **argv, char *n, char *desc) XCloseDevice(dpy, dev); return EXIT_SUCCESS; } + +#if HAVE_XI2 +static void +print_property_xi2(Display *dpy, int deviceid, Atom property) +{ + Atom act_type; + char *name; + int act_format; + unsigned long nitems, bytes_after; + unsigned char *data, *ptr; + int j, done = False; + + name = XGetAtomName(dpy, property); + printf("\t%s (%ld):\t", name, property); + + if (XIGetProperty(dpy, deviceid, property, 0, 1000, False, + AnyPropertyType, &act_type, &act_format, + &nitems, &bytes_after, &data) == Success) + { + Atom float_atom = XInternAtom(dpy, "FLOAT", True); + + ptr = data; + + for (j = 0; j < nitems; j++) + { + switch(act_type) + { + case XA_INTEGER: + switch(act_format) + { + case 8: + printf("%d", *((int8_t*)ptr)); + break; + case 16: + printf("%d", *((int16_t*)ptr)); + break; + case 32: + printf("%d", *((int32_t*)ptr)); + break; + } + break; + case XA_STRING: + if (act_format != 8) + { + printf("Unknown string format.\n"); + done = True; + break; + } + printf("\"%s\"", ptr); + j += strlen((char*)ptr); /* The loop's j++ jumps over the + terminating 0 */ + ptr += strlen((char*)ptr); /* ptr += size below jumps over + the terminating 0 */ + break; + case XA_ATOM: + printf("\"%s\"", XGetAtomName(dpy, *(Atom*)ptr)); + break; + default: + if (float_atom != None && act_type == float_atom) + { + printf("%f", *((float*)ptr)); + break; + } + + printf("\t... of unknown type %s\n", + XGetAtomName(dpy, act_type)); + done = True; + break; + } + + ptr += act_format/8; + + if (done == True) + break; + if (j < nitems - 1) + printf(", "); + } + printf("\n"); + XFree(data); + } else + printf("\tFetch failure\n"); + +} + +static int +list_props_xi2(Display *dpy, int argc, char** argv, char* name, char *desc) +{ + XIDeviceInfo *info; + int i; + int nprops; + Atom *props; + + if (argc == 0) + { + fprintf(stderr, "Usage: xinput %s %s\n", name, desc); + return EXIT_FAILURE; + } + + for (i = 0; i < argc; i++) + { + info = xi2_find_device_info(dpy, argv[i]); + if (!info) + { + fprintf(stderr, "unable to find device %s\n", argv[i]); + continue; + } + + props = XIListProperties(dpy, info->deviceid, &nprops); + if (!nprops) + { + printf("Device '%s' does not report any properties.\n", info->name); + continue; + } + + printf("Device '%s':\n", info->name); + while(nprops--) + { + print_property_xi2(dpy, info->deviceid, props[nprops]); + } + + XFree(props); + } + return EXIT_SUCCESS; +} + +static int +delete_prop_xi2(Display *dpy, int argc, char** argv, char* n, char *desc) +{ + XIDeviceInfo *info; + char *name; + Atom prop; + + info = xi2_find_device_info(dpy, argv[0]); + if (!info) + { + fprintf(stderr, "unable to find device %s\n", argv[0]); + return EXIT_FAILURE; + } + + name = argv[1]; + + prop = parse_atom(dpy, name); + + XIDeleteProperty(dpy, info->deviceid, prop); + + return EXIT_SUCCESS; +} + +static int +set_prop_xi2(Display *dpy, int argc, char **argv, char *n, char *desc) +{ + XIDeviceInfo *info; + Atom prop; + Atom type; + char *name; + int i; + Atom float_atom; + int format, nelements = 0; + unsigned long act_nitems, bytes_after; + char *endptr; + union { + unsigned char *c; + int16_t *s; + int32_t *l; + } data; + + if (argc < 3) + { + fprintf(stderr, "Usage: xinput %s %s\n", n, desc); + return EXIT_FAILURE; + } + + info = xi2_find_device_info(dpy, argv[0]); + if (!info) + { + fprintf(stderr, "unable to find device %s\n", argv[0]); + return EXIT_FAILURE; + } + + name = argv[1]; + + prop = parse_atom(dpy, name); + + if (prop == None) { + fprintf(stderr, "invalid property %s\n", name); + return EXIT_FAILURE; + } + + float_atom = XInternAtom(dpy, "FLOAT", False); + + nelements = argc - 2; + if (XIGetProperty(dpy, info->deviceid, prop, 0, 0, False, AnyPropertyType, + &type, &format, &act_nitems, &bytes_after, &data.c) + != Success) { + fprintf(stderr, "failed to get property type and format for %s\n", name); + return EXIT_FAILURE; + } + + XFree(data.c); + + if (type == None) { + fprintf(stderr, "property %s doesn't exist\n", name); + return EXIT_FAILURE; + } + + data.c = calloc(nelements, sizeof(int32_t)); + + for (i = 0; i < nelements; i++) + { + if (type == XA_INTEGER) { + switch (format) + { + case 8: + data.c[i] = atoi(argv[2 + i]); + break; + case 16: + data.s[i] = atoi(argv[2 + i]); + break; + case 32: + data.l[i] = atoi(argv[2 + i]); + break; + default: + fprintf(stderr, "unexpected size for property %s", name); + return EXIT_FAILURE; + } + } else if (type == float_atom) { + if (format != 32) { + fprintf(stderr, "unexpected format %d for property %s\n", + format, name); + return EXIT_FAILURE; + } + *(float *)(data.l + i) = strtod(argv[2 + i], &endptr); + if (endptr == argv[2 + i]) { + fprintf(stderr, "argument %s could not be parsed\n", argv[2 + i]); + return EXIT_FAILURE; + } + } else if (type == XA_ATOM) { + if (format != 32) { + fprintf(stderr, "unexpected format %d for property %s\n", + format, name); + return EXIT_FAILURE; + } + data.l[i] = parse_atom(dpy, argv[2 + i]); + } else { + fprintf(stderr, "unexpected type for property %s\n", name); + return EXIT_FAILURE; + } + } + + XIChangeProperty(dpy, info->deviceid, prop, type, format, PropModeReplace, + data.c, nelements); + free(data.c); + return EXIT_SUCCESS; +} +#endif + +int list_props(Display *display, int argc, char *argv[], char *name, + char *desc) +{ +#ifdef HAVE_XI2 + if (xinput_version(display) == XI_2_Major) + return list_props_xi2(display, argc, argv, name, desc); +#endif + return list_props_xi1(display, argc, argv, name, desc); + +} + +int delete_prop(Display *display, int argc, char *argv[], char *name, + char *desc) +{ +#ifdef HAVE_XI2 + if (xinput_version(display) == XI_2_Major) + return delete_prop_xi2(display, argc, argv, name, desc); +#endif + return delete_prop_xi1(display, argc, argv, name, desc); + +} + +int set_prop(Display *display, int argc, char *argv[], char *name, + char *desc) +{ +#ifdef HAVE_XI2 + if (xinput_version(display) == XI_2_Major) + return set_prop_xi2(display, argc, argv, name, desc); +#endif + return set_prop_xi1(display, argc, argv, name, desc); +} diff --git a/src/setcp.c b/src/setcp.c index e44bb00..7a28644 100644 --- a/src/setcp.c +++ b/src/setcp.c @@ -32,9 +32,8 @@ int set_clientpointer(Display* dpy, int argc, char** argv, char* name, char *desc) { - XDeviceInfo* info; + XIDeviceInfo *info; XID window; - XDevice* dev = NULL; char* id; char* dummy; @@ -50,19 +49,13 @@ set_clientpointer(Display* dpy, int argc, char** argv, char* name, char *desc) window = strtol(argv[0], &dummy, (*id == 'x') ? 16 : 10); - info = find_device_info(dpy, argv[1], False); + info = xi2_find_device_info(dpy, argv[1]); if (!info) { fprintf(stderr, "unable to find device %s\n", argv[1]); return EXIT_FAILURE; } - dev = XOpenDevice(dpy, info->id); - - if (!dev) - { - fprintf(stderr, "Cannot open device %s.\n", argv[1]); - } else - XSetClientPointer(dpy, window, dev); + XISetClientPointer(dpy, window, info->deviceid); return 0; } diff --git a/src/test_xi2.c b/src/test_xi2.c new file mode 100644 index 0000000..ba5bee6 --- /dev/null +++ b/src/test_xi2.c @@ -0,0 +1,359 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + + +#include "xinput.h" +#include <string.h> + +extern void print_classes_xi2(Display*, XIAnyClassInfo **classes, + int num_classes); + +#define BitIsOn(ptr, bit) (((unsigned char *) (ptr))[(bit)>>3] & (1 << ((bit) & 7))) +#define SetBit(ptr, bit) (((unsigned char *) (ptr))[(bit)>>3] |= (1 << ((bit) & 7))) + +static Window create_win(Display *dpy) +{ + 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)); + + XSelectInput(dpy, win, ExposureMask); + XMapWindow(dpy, subwindow); + XMapWindow(dpy, win); + XFlush(dpy); + return win; +} + +static void print_deviceevent(XIDeviceEvent* event) +{ + double *val; + int i; + + printf(" device: %d (%d)\n", event->deviceid, event->sourceid); + printf(" detail: %d\n", event->detail); + + printf(" root: %.2f/%.2f\n", event->root_x, event->root_y); + printf(" event: %.2f/%.2f\n", event->event_x, event->event_x); + + printf(" buttons:"); + for (i = 0; i < event->buttons->mask_len * 8; i++) + if (BitIsOn(event->buttons->mask, i)) + printf(" %d", i); + printf("\n"); + + printf(" modifiers: locked 0x%x latched 0x%x base 0x%x\n", + event->mods->locked, event->mods->latched, + event->mods->base); + printf(" group: locked 0x%x latched 0x%x base 0x%x\n", + event->group->locked, event->group->latched, + event->group->base); + printf(" valuators:"); + + val = event->valuators->values; + for (i = 0; i < event->valuators->mask_len * 8; i++) + if (BitIsOn(event->valuators->mask, i)) + printf(" %.2f", *val++); + printf("\n"); + + printf(" windows: root 0x%lx event 0x%lx child 0x%ld\n", + event->root, event->event, event->child); +} + +static void print_devicechangedevent(Display *dpy, XIDeviceChangedEvent *event) +{ + printf(" device: %d (%d)\n", event->deviceid, event->sourceid); + printf(" reason: %s\n", (event->reason == XISlaveSwitch) ? "SlaveSwitch" : + "DeviceChanged"); + print_classes_xi2(dpy, event->classes, event->num_classes); +} + +static void print_hierarchychangedevent(XIDeviceHierarchyEvent *event) +{ + int i; + printf(" Changes happened: %s %s %s %s %s %s %s\n", + (event->flags & XIMasterAdded) ? "[new master]" : "", + (event->flags & XIMasterRemoved) ? "[master removed]" : "", + (event->flags & XISlaveAdded) ? "[new slave]" : "", + (event->flags & XISlaveRemoved) ? "[slave removed]" : "", + (event->flags & XISlaveAttached) ? "[slave attached]" : "", + (event->flags & XIDeviceEnabled) ? "[device enabled]" : "", + (event->flags & XIDeviceDisabled) ? "[device disabled]" : ""); + + for (i = 0; i < event->num_devices; i++) + { + char *use; + switch(event->info[i].use) + { + case XIMasterPointer: use = "master pointer"; + case XIMasterKeyboard: use = "master keyboard"; break; + case XISlavePointer: use = "slave pointer"; + case XISlaveKeyboard: use = "slave keyboard"; break; + case XIFloatingSlave: use = "floating slave"; break; + break; + } + + printf(" device %d [%s (%d)] is %s\n", + event->info[i].deviceid, + use, + event->info[i].attachment, + (event->info[i].enabled) ? "enabled" : "disabled"); + } +} + +static void print_rawevent(XIRawDeviceEvent *event) +{ + int i; + double *val, *raw_val; + + printf(" device: %d\n", event->deviceid); + printf(" detail: %d\n", event->detail); + printf(" valuators:\n"); + + val = event->valuators->values; + raw_val = event->raw_values; + for (i = 0; i < event->valuators->mask_len * 8; i++) + if (BitIsOn(event->valuators->mask, i)) + printf(" %2d: %.2f (%.2f)\n", i, *val++, *raw_val++); + printf("\n"); +} + +static void print_enterleave(XILeaveEvent* event) +{ + char *mode, *detail; + int i; + + printf(" windows: root 0x%lx event 0x%lx child 0x%ld\n", + event->root, event->event, event->child); + switch(event->mode) + { + case NotifyNormal: mode = "NotifyNormal"; break; + case NotifyGrab: mode = "NotifyGrab"; break; + case NotifyUngrab: mode = "NotifyUngrab"; break; + case NotifyWhileGrabbed: mode = "NotifyWhileGrabbed"; break; + } + switch (event->detail) + { + case NotifyAncestor: detail = "NotifyAncestor"; break; + case NotifyVirtual: detail = "NotifyVirtual"; break; + case NotifyInferior: detail = "NotifyInferior"; break; + case NotifyNonlinear: detail = "NotifyNonlinear"; break; + case NotifyNonlinearVirtual: detail = "NotifyNonlinearVirtual"; break; + case NotifyPointer: detail = "NotifyPointer"; break; + case NotifyPointerRoot: detail = "NotifyPointerRoot"; break; + case NotifyDetailNone: detail = "NotifyDetailNone"; break; + } + printf(" mode: %s (detail %s)\n", mode, detail); + printf(" flags: %s %s\n", event->focus ? "[focus]" : "", + event->same_screen ? "[same screen]" : ""); + printf(" buttons:"); + for (i = 0; i < event->buttons->mask_len * 8; i++) + if (BitIsOn(event->buttons->mask, i)) + printf(" %d", i); + printf("\n"); + + printf(" modifiers: locked 0x%x latched 0x%x base 0x%x\n", + event->mods->locked, event->mods->latched, + event->mods->base); + printf(" group: locked 0x%x latched 0x%x base 0x%x\n", + event->group->locked, event->group->latched, + event->group->base); + + printf(" root x/y: %.2f / %.2f\n", event->root_x, event->root_y); + printf(" event x/y: %.2f / %.2f\n", event->event_x, event->event_y); + +} + +static void print_propertyevent(Display *display, XIPropertyEvent* event) +{ + char *changed; + + if (event->what == XIPropertyDeleted) + changed = "deleted"; + else if (event->what == XIPropertyCreated) + changed = "created"; + else + changed = "modified"; + + printf(" property: %ld '%s'\n", event->property, XGetAtomName(display, event->property)); + printf(" changed: %s\n", changed); + +} +void +test_sync_grab(Display *display, Window win) +{ + int loop = 3; + int rc; + XIDeviceEventMask mask; + + /* Select for motion events */ + mask.deviceid = XIAllDevices; + mask.mask_len = 2; + mask.mask = calloc(2, sizeof(char)); + SetBit(mask.mask, XI_ButtonPress); + + if ((rc = XIGrabDevice(display, 2, win, CurrentTime, None, GrabModeSync, + GrabModeAsync, False, &mask)) != GrabSuccess) + { + fprintf(stderr, "Grab failed with %d\n", rc); + return; + } + free(mask.mask); + + XSync(display, True); + XIAllowEvents(display, 2, SyncPointer, CurrentTime); + XFlush(display); + + printf("Holding sync grab for %d button presses.\n", loop); + + while(loop--) + { + XIEvent ev; + + XNextEvent(display, (XEvent*)&ev); + if (ev.type == GenericEvent) + { + XIDeviceEvent *event = (XIDeviceEvent*)&ev; + print_deviceevent(event); + XIAllowEvents(display, 2, SyncPointer, CurrentTime); + XIFreeEventData(&ev); + } + } + + XIUngrabDevice(display, 2, CurrentTime); + printf("Done\n"); +} + +int +test_xi2(Display *display, + int argc, + char *argv[], + char *name, + char *desc) +{ + XIDeviceEventMask mask; + Window win; + + list(display, argc, argv, name, desc); + win = create_win(display); + + XSync(display, False); + + /* Select for motion events */ + mask.deviceid = XIAllDevices; + mask.mask_len = 2; + mask.mask = calloc(mask.mask_len, sizeof(char)); + SetBit(mask.mask, XI_ButtonPress); + SetBit(mask.mask, XI_ButtonRelease); + SetBit(mask.mask, XI_KeyPress); + SetBit(mask.mask, XI_KeyRelease); + SetBit(mask.mask, XI_Motion); + SetBit(mask.mask, XI_DeviceChanged); + SetBit(mask.mask, XI_Enter); + SetBit(mask.mask, XI_Leave); + SetBit(mask.mask, XI_FocusIn); + SetBit(mask.mask, XI_FocusOut); + SetBit(mask.mask, XI_HierarchyChanged); + SetBit(mask.mask, XI_PropertyEvent); + XISelectEvent(display, win, &mask, 1); + XSync(display, False); + + { + int modifiers[] = {0, 0x10, 0x1, 0x11}; + int nmods = sizeof(modifiers)/sizeof(modifiers[0]); + + mask.deviceid = 2; + memset(mask.mask, 0, 2); + SetBit(mask.mask, XI_KeyPress); + SetBit(mask.mask, XI_KeyRelease); + SetBit(mask.mask, XI_ButtonPress); + SetBit(mask.mask, XI_Motion); + XIGrabButton(display, 2, 1, win, None, GrabModeAsync, GrabModeAsync, + False, &mask, nmods, modifiers); + XIGrabKeysym(display, 3, 0x71, win, GrabModeAsync, GrabModeAsync, + False, &mask, nmods, modifiers); + XIUngrabButton(display, 3, 1, win, nmods - 2, &modifiers[2]); + XIUngrabKeysym(display, 3, 0x71, win, nmods - 2, &modifiers[2]); + } + + mask.deviceid = XIAllMasterDevices; + memset(mask.mask, 0, 2); + SetBit(mask.mask, XI_RawEvent); + XISelectEvent(display, DefaultRootWindow(display), &mask, 1); + + free(mask.mask); + + { + XEvent event; + XMaskEvent(display, ExposureMask, &event); + XSelectInput(display, win, 0); + } + + /* + test_sync_grab(display, win); + */ + + while(1) + { + XIEvent ev; + XNextEvent(display, (XEvent*)&ev); + if (ev.type == GenericEvent) + { + XIDeviceEvent *event = (XIDeviceEvent*)&ev; + + printf("EVENT type %d\n", event->evtype); + switch (event->evtype) + { + case XI_DeviceChanged: + print_devicechangedevent(display, + (XIDeviceChangedEvent*)event); + break; + case XI_HierarchyChanged: + print_hierarchychangedevent((XIDeviceHierarchyEvent*)event); + break; + case XI_RawEvent: + print_rawevent((XIRawDeviceEvent*)event); + break; + case XI_Enter: + case XI_Leave: + case XI_FocusIn: + case XI_FocusOut: + print_enterleave((XILeaveEvent*)event); + break; + case XI_PropertyEvent: + print_propertyevent(display, (XIPropertyEvent*)event); + break; + default: + print_deviceevent(event); + break; + } + } + + XIFreeEventData(&ev); + } + + XDestroyWindow(display, win); + + return EXIT_SUCCESS; +} diff --git a/src/xinput.c b/src/xinput.c index 2a9df6a..007fe2c 100644 --- a/src/xinput.c +++ b/src/xinput.c @@ -102,6 +102,10 @@ static entry drivers[] = "<window> <device>", set_clientpointer }, + { "test-xi2", + "<device>", + test_xi2, + }, #endif { "list-props", "<device> [<device> ...]", @@ -135,25 +139,23 @@ static entry drivers[] = } }; -static Bool -is_xinput_present(Display *display) +int +xinput_version(Display *display) { XExtensionVersion *version; - Bool present; + static int vers = -1; + + if (vers != -1) + return vers; -#if HAVE_XI2 - version = XQueryInputVersion(display, XI_2_Major, XI_2_Minor); -#else version = XGetExtensionVersion(display, INAME); -#endif if (version && (version != (XExtensionVersion*) NoSuchExtension)) { - present = version->present; + vers = version->major_version; XFree(version); - return present; - } else { - return False; } + + return vers; } XDeviceInfo* @@ -200,6 +202,41 @@ find_device_info(Display *display, return found; } +#ifdef HAVE_XI2 +XIDeviceInfo* +xi2_find_device_info(Display *display, char *name) +{ + XIDeviceInfo *info; + int ndevices; + Bool is_id = True; + int i, id = -1; + + for(i = 0; i < strlen(name); i++) { + if (!isdigit(name[i])) { + is_id = False; + break; + } + } + + if (is_id) { + id = atoi(name); + } + + info = XIQueryDevice(display, XIAllDevices, &ndevices); + for(i = 0; i < ndevices; i++) + { + if ((is_id && info[i].deviceid == id) || + (!is_id && strcmp(info[i].name, name) == 0)) + { + return &info[i]; + } + } + + XIFreeDeviceInfo(info); + return NULL; +} +#endif + static void usage(void) { @@ -236,7 +273,7 @@ main(int argc, char * argv[]) func = argv[1]; while((*func) == '-') func++; - if (!is_xinput_present(display)) { + if (!xinput_version(display)) { fprintf(stderr, "%s extension not available\n", INAME); return EXIT_FAILURE; } diff --git a/src/xinput.h b/src/xinput.h index c4a6f8f..fd468b0 100644 --- a/src/xinput.h +++ b/src/xinput.h @@ -27,6 +27,9 @@ #include <X11/Xlib.h> #include <X11/extensions/XInput.h> +#ifdef HAVE_XI2 +#include <X11/extensions/XInput2.h> +#endif #include <X11/Xutil.h> #include <stdio.h> #include <stdlib.h> @@ -39,6 +42,10 @@ #endif XDeviceInfo* find_device_info( Display *display, char *name, Bool only_extended); +#if HAVE_XI2 +XIDeviceInfo* xi2_find_device_info(Display *display, char *name); +int xinput_version(Display* display); +#endif int get_feedbacks( Display* display, int argc, char *argv[], char *prog_name, char *prog_desc); int set_ptr_feedback( Display* display, int argc, char *argv[], char *prog_name, char *prog_desc); @@ -68,4 +75,6 @@ int remove_master( Display* display, int argc, char *argv[], char *prog_name, ch int change_attachment( Display* display, int argc, char *argv[], char *prog_name, char *prog_desc); int float_device( Display* display, int argc, char *argv[], char *prog_name, char *prog_desc); int set_clientpointer( Display* display, int argc, char *argv[], char *prog_name, char *prog_desc); +int test_xi2( Display* display, int argc, char *argv[], char *prog_name, char *prog_desc); + /* end of xinput.h */ |