diff options
author | Frediano Ziglio <fziglio@redhat.com> | 2015-08-03 10:45:42 +0100 |
---|---|---|
committer | Frediano Ziglio <fziglio@redhat.com> | 2015-08-03 10:45:42 +0100 |
commit | c8c9be4a8ef46ae54c31cbb44ffa58734c0c90fa (patch) | |
tree | 3e941808002239e851da033da277bbecb964d70c | |
parent | 37b92905cb4f2110ce564810f019b609d815e8fc (diff) |
Add XInput events
Allows to get any keypress/mouse events.
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | global.h | 13 | ||||
-rw-r--r-- | spice-replay.c | 26 | ||||
-rw-r--r-- | test_xi2.c | 355 | ||||
-rw-r--r-- | xev.c | 4 |
5 files changed, 240 insertions, 161 deletions
diff --git a/Makefile.am b/Makefile.am index d66a082..0cf181c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -26,4 +26,5 @@ spice_replay_LDADD = $(REPLAY_LIBS) spice_replay_SOURCES = \ spice-replay.c \ - xev.c + xev.c \ + test_xi2.c @@ -1,5 +1,18 @@ extern Display *dpy; +/* standard events */ void xev_init(Window w); void xev_dump(XEvent *event); + +/* XInput */ +extern int xi_opcode; + +void xinput_init(Display *display, Window win); +void xinput_dump(Display *display, XGenericEventCookie *cookie); + +static inline int +is_xinput_event(XEvent *event) +{ + return event->type == GenericEvent && event->xgeneric.extension == xi_opcode; +} diff --git a/spice-replay.c b/spice-replay.c index 59ca8f5..151adfa 100644 --- a/spice-replay.c +++ b/spice-replay.c @@ -60,7 +60,7 @@ version(void) int main(int argc, char **argv) { - Window w; + Window w = 0; const char *fn_out = NULL; const char *display = NULL; @@ -105,6 +105,16 @@ int main(int argc, char **argv) if (optind >= argc || mode == MODE_UNKNOWN) usage(stderr); + if (mode == MODE_PLAY) { + fprintf (stderr, "playback mode still not supported\n"); + return EXIT_FAILURE; + } + + if (mode == MODE_RECORD && w == 0) { + fprintf (stderr, "record mode require a window to be specified\n"); + return EXIT_FAILURE; + } + fn_out = argv[optind]; dpy = XOpenDisplay (display); @@ -114,14 +124,24 @@ int main(int argc, char **argv) } xev_init(w); + xinput_init(dpy, w); while(1) { XEvent event; XNextEvent (dpy, &event); - if (verbose) - xev_dump(&event); + if (is_xinput_event(&event)) { + XGenericEventCookie *cookie = &event.xcookie; + if (XGetEventData(dpy, cookie)) { + if (verbose) + xinput_dump(dpy, cookie); + XFreeEventData(dpy, cookie); + } + } else { + if (verbose) + xev_dump(&event); + } } XCloseDisplay (dpy); @@ -22,24 +22,24 @@ * */ +#include <config.h> -#include "xinput.h" +#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> #include <string.h> -extern void print_classes_xi2(Display*, XIAnyClassInfo **classes, - int num_classes); +#include "global.h" -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)); - - XMapWindow(dpy, subwindow); - XSelectInput(dpy, win, ExposureMask); - return win; -} +int xi_opcode; + +static void print_classes_xi2(Display*, XIAnyClassInfo **classes, + int num_classes); static void print_deviceevent(XIDeviceEvent* event) { @@ -88,12 +88,12 @@ static void print_deviceevent(XIDeviceEvent* event) event->root, event->event, event->child); } -static void print_devicechangedevent(Display *dpy, XIDeviceChangedEvent *event) +static void print_devicechangedevent(Display *display, 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); + print_classes_xi2(display, event->classes, event->num_classes); } static void print_hierarchychangedevent(XIHierarchyEvent *event) @@ -235,49 +235,6 @@ static void print_propertyevent(Display *display, XIPropertyEvent* event) XFree(name); } -void -test_sync_grab(Display *display, Window win) -{ - int loop = 3; - int rc; - XIEventMask mask; - - /* Select for motion events */ - mask.deviceid = XIAllDevices; - mask.mask_len = 2; - mask.mask = calloc(2, sizeof(char)); - XISetMask(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 && ev.extension == xi_opcode ) - { - XIDeviceEvent *event = (XIDeviceEvent*)&ev; - print_deviceevent(event); - XIAllowEvents(display, 2, SyncPointer, CurrentTime); - } - } - - XIUngrabDevice(display, 2, CurrentTime); - printf("Done\n"); -} static const char* type_to_name(int evtype) { @@ -313,48 +270,167 @@ static const char* type_to_name(int evtype) return name; } +static void +print_classes_xi2(Display* display, XIAnyClassInfo **classes, + int num_classes) +{ + int i, j; + + printf("\tReporting %d classes:\n", num_classes); + for (i = 0; i < num_classes; i++) + { + printf("\t\tClass originated from: %d. Type: ", classes[i]->sourceid); + switch(classes[i]->type) + { + case XIButtonClass: + { + XIButtonClassInfo *b = (XIButtonClassInfo*)classes[i]; + char *name; + printf("XIButtonClass\n"); + printf("\t\tButtons supported: %d\n", b->num_buttons); + printf("\t\tButton labels:"); + for (j = 0; j < b->num_buttons; j++) + { + name = (b->labels[j]) ? XGetAtomName(display, b->labels[j]) : NULL; + if (name) + printf(" \"%s\"", name); + else + printf(" None"); + XFree(name); + } + printf("\n"); + printf("\t\tButton state:"); + for (j = 0; j < b->state.mask_len * 8; j++) + if (XIMaskIsSet(b->state.mask, j)) + printf(" %d", j); + printf("\n"); + + } + break; + case XIKeyClass: + { + XIKeyClassInfo *k = (XIKeyClassInfo*)classes[i]; + printf("XIKeyClass\n"); + printf("\t\tKeycodes supported: %d\n", k->num_keycodes); + } + break; + case XIValuatorClass: + { + XIValuatorClassInfo *v = (XIValuatorClassInfo*)classes[i]; + char *name = v->label ? XGetAtomName(display, v->label) : NULL; + + /* Bug in X servers 1.7..1.8.1, mode was | OutOfProximity */ + v->mode &= DeviceMode; + + printf("XIValuatorClass\n"); + printf("\t\tDetail for Valuator %d:\n", v->number); + printf("\t\t Label: %s\n", (name) ? name : "None"); + 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"); + if (v->mode == Absolute) + printf("\t\t Current value: %f\n", v->value); + XFree(name); + } + break; +#if HAVE_XI21 + case XIScrollClass: + { + XIScrollClassInfo *s = (XIScrollClassInfo*)classes[i]; + + printf("XIScrollClass\n"); + printf("\t\tScroll info for Valuator %d\n", s->number); + printf("\t\t type: %d (%s)\n", s->scroll_type, + (s->scroll_type == XIScrollTypeHorizontal) ? "horizontal" : + (s->scroll_type == XIScrollTypeVertical) ? "vertical" : "unknown"); + printf("\t\t increment: %f\n", s->increment); + printf("\t\t flags: 0x%x", s->flags); + if (s->flags) { + printf(" ("); + if (s->flags & XIScrollFlagNoEmulation) + printf(" no-emulation "); + if (s->flags & XIScrollFlagPreferred) + printf(" preferred "); + printf(")"); + } + printf("\n"); + } + break; +#endif +#if HAVE_XI22 + case XITouchClass: + { + XITouchClassInfo *t = (XITouchClassInfo*)classes[i]; + + printf("XITouchClass\n"); + printf("\t\tTouch mode: %s\n", + (t->mode == XIDirectTouch) ? "direct" : "dependent"); + printf("\t\tMax number of touches: %d\n", t->num_touches); + } +#endif + } + } + + printf("\n"); +} -int -test_xi2(Display *display, - int argc, - char *argv[], - char *name, - char *desc) +static int +xinput_version(Display *display) { - XIEventMask mask[2]; - XIEventMask *m; - Window win; - int deviceid = -1; - int use_root = 0; - int rc; + XExtensionVersion *version; + int vers = 0; + + version = XGetExtensionVersion(display, INAME); + + if (version && (version != (XExtensionVersion*) NoSuchExtension)) { + vers = version->major_version; + XFree(version); + } - setvbuf(stdout, NULL, _IOLBF, 0); +#if HAVE_XI2 + /* Announce our supported version so the server treats us correctly. */ + if (vers >= XI_2_Major) + { + int maj = 2, + min = 0; - if (argc >= 1 && strcmp(argv[0], "--root") == 0) { - use_root = 1; +#if HAVE_XI22 + min = 2; +#elif HAVE_XI21 + min = 1; +#endif - argc--; - argv++; + XIQueryVersion(display, &maj, &min); } +#endif - rc = list(display, argc, argv, name, desc); - if (rc != EXIT_SUCCESS) - return rc; + return vers; +} - if (use_root) - win = DefaultRootWindow(display); - else - win = create_win(display); - if (argc >= 1) { - XIDeviceInfo *info; - info = xi2_find_device_info(display, argv[0]); - deviceid = info->deviceid; +void +xinput_init(Display *display, Window win) +{ + XIEventMask mask[2]; + XIEventMask *m; + int event, error; + + if (!XQueryExtension(display, "XInputExtension", &xi_opcode, &event, &error)) { + fprintf(stderr, "X Input extension not available.\n"); + exit(EXIT_FAILURE); + } + + if (!xinput_version(display)) { + fprintf(stderr, "%s extension not available\n", INAME); + exit(EXIT_FAILURE); } + win = DefaultRootWindow(display); + /* Select for motion events */ m = &mask[0]; - m->deviceid = (deviceid == -1) ? XIAllDevices : deviceid; + m->deviceid = XIAllDevices; m->mask_len = XIMaskLen(XI_LASTEVENT); m->mask = calloc(m->mask_len, sizeof(char)); XISetMask(m->mask, XI_ButtonPress); @@ -372,12 +448,11 @@ test_xi2(Display *display, XISetMask(m->mask, XI_TouchUpdate); XISetMask(m->mask, XI_TouchEnd); #endif - if (m->deviceid == XIAllDevices) - XISetMask(m->mask, XI_HierarchyChanged); + XISetMask(m->mask, XI_HierarchyChanged); XISetMask(m->mask, XI_PropertyEvent); m = &mask[1]; - m->deviceid = (deviceid == -1) ? XIAllMasterDevices : deviceid; + m->deviceid = XIAllMasterDevices; m->mask_len = XIMaskLen(XI_LASTEVENT); m->mask = calloc(m->mask_len, sizeof(char)); XISetMask(m->mask, XI_RawKeyPress); @@ -391,74 +466,46 @@ test_xi2(Display *display, XISetMask(m->mask, XI_RawTouchEnd); #endif - XISelectEvents(display, win, &mask[0], use_root ? 2 : 1); - if (!use_root) { - XISelectEvents(display, DefaultRootWindow(display), &mask[1], 1); - XMapWindow(display, win); - } + XISelectEvents(display, win, &mask[0], 2); XSync(display, False); free(mask[0].mask); free(mask[1].mask); +} - if (!use_root) { - XEvent event; - XMaskEvent(display, ExposureMask, &event); - XSelectInput(display, win, 0); - } - - /* - test_sync_grab(display, win); - */ - - while(1) +void +xinput_dump(Display *display, XGenericEventCookie *cookie) +{ + printf("EVENT type %d (%s)\n", cookie->evtype, type_to_name(cookie->evtype)); + switch (cookie->evtype) { - XEvent ev; - XGenericEventCookie *cookie = (XGenericEventCookie*)&ev.xcookie; - XNextEvent(display, (XEvent*)&ev); - - if (XGetEventData(display, cookie) && - cookie->type == GenericEvent && - cookie->extension == xi_opcode) - { - printf("EVENT type %d (%s)\n", cookie->evtype, type_to_name(cookie->evtype)); - switch (cookie->evtype) - { - case XI_DeviceChanged: - print_devicechangedevent(display, cookie->data); - break; - case XI_HierarchyChanged: - print_hierarchychangedevent(cookie->data); - break; - case XI_RawKeyPress: - case XI_RawKeyRelease: - case XI_RawButtonPress: - case XI_RawButtonRelease: - case XI_RawMotion: - case XI_RawTouchBegin: - case XI_RawTouchUpdate: - case XI_RawTouchEnd: - print_rawevent(cookie->data); - break; - case XI_Enter: - case XI_Leave: - case XI_FocusIn: - case XI_FocusOut: - print_enterleave(cookie->data); - break; - case XI_PropertyEvent: - print_propertyevent(display, cookie->data); - break; - default: - print_deviceevent(cookie->data); - break; - } - } - - XFreeEventData(display, cookie); + case XI_DeviceChanged: + print_devicechangedevent(display, cookie->data); + break; + case XI_HierarchyChanged: + print_hierarchychangedevent(cookie->data); + break; + case XI_RawKeyPress: + case XI_RawKeyRelease: + case XI_RawButtonPress: + case XI_RawButtonRelease: + case XI_RawMotion: + case XI_RawTouchBegin: + case XI_RawTouchUpdate: + case XI_RawTouchEnd: + print_rawevent(cookie->data); + break; + case XI_Enter: + case XI_Leave: + case XI_FocusIn: + case XI_FocusOut: + print_enterleave(cookie->data); + break; + case XI_PropertyEvent: + print_propertyevent(display, cookie->data); + break; + default: + print_deviceevent(cookie->data); + break; } - - XDestroyWindow(display, win); - - return EXIT_SUCCESS; } @@ -866,10 +866,8 @@ xev_dump(XEvent *event) prologue (event, "MappingNotify"); do_MappingNotify (event); break; -#if 0 default: - printf ("Unknown event type %d\n", event.type); + printf ("Unknown event type %d\n", event->type); break; -#endif } } |