summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac9
-rw-r--r--src/Makefile.am4
-rw-r--r--src/hierarchy.c96
-rw-r--r--src/list.c198
-rw-r--r--src/property.c301
-rw-r--r--src/setcp.c13
-rw-r--r--src/test_xi2.c359
-rw-r--r--src/xinput.c61
-rw-r--r--src/xinput.h9
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;
}
diff --git a/src/list.c b/src/list.c
index bd71a5c..daebf3f 100644
--- a/src/list.c
+++ b/src/list.c
@@ -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 */