/* * 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 #include #include #ifdef HAVE_XI2 #include #endif #include #include #include #include #include "global.h" int xi_opcode; static void print_classes_xi2(Display*, XIAnyClassInfo **classes, int num_classes); 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); switch(event->evtype) { case XI_KeyPress: case XI_KeyRelease: printf(" flags: %s\n", (event->flags & XIKeyRepeat) ? "repeat" : ""); break; #if HAVE_XI21 case XI_ButtonPress: case XI_ButtonRelease: case XI_Motion: printf(" flags: %s\n", (event->flags & XIPointerEmulated) ? "emulated" : ""); break; #endif } printf(" root: %.2f/%.2f\n", event->root_x, event->root_y); printf(" event: %.2f/%.2f\n", event->event_x, event->event_y); printf(" buttons:"); for (i = 0; i < event->buttons.mask_len * 8; i++) if (XIMaskIsSet(event->buttons.mask, i)) printf(" %d", i); printf("\n"); printf(" modifiers: locked %#x latched %#x base %#x effective: %#x\n", event->mods.locked, event->mods.latched, event->mods.base, event->mods.effective); printf(" group: locked %#x latched %#x base %#x effective: %#x\n", event->group.locked, event->group.latched, event->group.base, event->group.effective); printf(" valuators:\n"); val = event->valuators.values; for (i = 0; i < event->valuators.mask_len * 8; i++) if (XIMaskIsSet(event->valuators.mask, i)) printf(" %i: %.2f\n", i, *val++); printf(" windows: root 0x%lx event 0x%lx child 0x%lx\n", event->root, event->event, event->child); } 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(display, event->classes, event->num_classes); } static void print_hierarchychangedevent(XIHierarchyEvent *event) { int i; printf(" Changes happened: %s %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 & XISlaveDetached) ? "[slave detached]" : "", (event->flags & XIDeviceEnabled) ? "[device enabled]" : "", (event->flags & XIDeviceDisabled) ? "[device disabled]" : ""); for (i = 0; i < event->num_info; i++) { const char *use = ""; switch(event->info[i].use) { case XIMasterPointer: use = "master pointer"; break; case XIMasterKeyboard: use = "master keyboard"; break; case XISlavePointer: use = "slave pointer"; break; 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"); if (event->info[i].flags) { printf(" changes: %s %s %s %s %s %s %s %s\n", (event->info[i].flags & XIMasterAdded) ? "[new master]" : "", (event->info[i].flags & XIMasterRemoved) ? "[master removed]" : "", (event->info[i].flags & XISlaveAdded) ? "[new slave]" : "", (event->info[i].flags & XISlaveRemoved) ? "[slave removed]" : "", (event->info[i].flags & XISlaveAttached) ? "[slave attached]" : "", (event->info[i].flags & XISlaveDetached) ? "[slave detached]" : "", (event->info[i].flags & XIDeviceEnabled) ? "[device enabled]" : "", (event->info[i].flags & XIDeviceDisabled) ? "[device disabled]" : ""); } } } static void print_rawevent(XIRawEvent *event) { int i; double *val, *raw_val; printf(" device: %d (%d)\n", event->deviceid, event->sourceid); printf(" detail: %d\n", event->detail); printf(" valuators:\n"); #if HAVE_XI21 switch(event->evtype) { case XI_RawButtonPress: case XI_RawButtonRelease: case XI_RawMotion: printf(" flags: %s\n", (event->flags & XIPointerEmulated) ? "emulated" : ""); break; } #endif val = event->valuators.values; raw_val = event->raw_values; for (i = 0; i < event->valuators.mask_len * 8; i++) if (XIMaskIsSet(event->valuators.mask, i)) printf(" %2d: %.2f (%.2f)\n", i, *val++, *raw_val++); printf("\n"); } static void print_enterleave(XILeaveEvent* event) { const char *mode = "", *detail = ""; int i; printf(" device: %d (%d)\n", event->deviceid, event->sourceid); printf(" windows: root 0x%lx event 0x%lx child 0x%ld\n", event->root, event->event, event->child); switch(event->mode) { case XINotifyNormal: mode = "NotifyNormal"; break; case XINotifyGrab: mode = "NotifyGrab"; break; case XINotifyUngrab: mode = "NotifyUngrab"; break; case XINotifyWhileGrabbed: mode = "NotifyWhileGrabbed"; break; case XINotifyPassiveGrab: mode = "NotifyPassiveGrab"; break; case XINotifyPassiveUngrab:mode = "NotifyPassiveUngrab"; break; } switch (event->detail) { case XINotifyAncestor: detail = "NotifyAncestor"; break; case XINotifyVirtual: detail = "NotifyVirtual"; break; case XINotifyInferior: detail = "NotifyInferior"; break; case XINotifyNonlinear: detail = "NotifyNonlinear"; break; case XINotifyNonlinearVirtual: detail = "NotifyNonlinearVirtual"; break; case XINotifyPointer: detail = "NotifyPointer"; break; case XINotifyPointerRoot: detail = "NotifyPointerRoot"; break; case XINotifyDetailNone: 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 (XIMaskIsSet(event->buttons.mask, i)) printf(" %d", i); printf("\n"); printf(" modifiers: locked %#x latched %#x base %#x effective: %#x\n", event->mods.locked, event->mods.latched, event->mods.base, event->mods.effective); printf(" group: locked %#x latched %#x base %#x effective: %#x\n", event->group.locked, event->group.latched, event->group.base, event->group.effective); 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) { const char *changed; char *name; if (event->what == XIPropertyDeleted) changed = "deleted"; else if (event->what == XIPropertyCreated) changed = "created"; else changed = "modified"; name = XGetAtomName(display, event->property); printf(" property: %ld '%s'\n", event->property, name); printf(" changed: %s\n", changed); XFree(name); } static const char* type_to_name(int evtype) { const char *name; switch(evtype) { case XI_DeviceChanged: name = "DeviceChanged"; break; case XI_KeyPress: name = "KeyPress"; break; case XI_KeyRelease: name = "KeyRelease"; break; case XI_ButtonPress: name = "ButtonPress"; break; case XI_ButtonRelease: name = "ButtonRelease"; break; case XI_Motion: name = "Motion"; break; case XI_Enter: name = "Enter"; break; case XI_Leave: name = "Leave"; break; case XI_FocusIn: name = "FocusIn"; break; case XI_FocusOut: name = "FocusOut"; break; case XI_HierarchyChanged: name = "HierarchyChanged"; break; case XI_PropertyEvent: name = "PropertyEvent"; break; case XI_RawKeyPress: name = "RawKeyPress"; break; case XI_RawKeyRelease: name = "RawKeyRelease"; break; case XI_RawButtonPress: name = "RawButtonPress"; break; case XI_RawButtonRelease: name = "RawButtonRelease"; break; case XI_RawMotion: name = "RawMotion"; break; case XI_TouchBegin: name = "TouchBegin"; break; case XI_TouchUpdate: name = "TouchUpdate"; break; case XI_TouchEnd: name = "TouchEnd"; break; case XI_RawTouchBegin: name = "RawTouchBegin"; break; case XI_RawTouchUpdate: name = "RawTouchUpdate"; break; case XI_RawTouchEnd: name = "RawTouchEnd"; break; default: name = "unknown event type"; break; } 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"); } static int xinput_version(Display *display) { XExtensionVersion *version; int vers = 0; version = XGetExtensionVersion(display, INAME); if (version && (version != (XExtensionVersion*) NoSuchExtension)) { vers = version->major_version; XFree(version); } #if HAVE_XI2 /* Announce our supported version so the server treats us correctly. */ if (vers >= XI_2_Major) { int maj = 2, min = 0; #if HAVE_XI22 min = 2; #elif HAVE_XI21 min = 1; #endif XIQueryVersion(display, &maj, &min); } #endif return vers; } 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 = XIAllDevices; m->mask_len = XIMaskLen(XI_LASTEVENT); m->mask = calloc(m->mask_len, sizeof(char)); XISetMask(m->mask, XI_ButtonPress); XISetMask(m->mask, XI_ButtonRelease); XISetMask(m->mask, XI_KeyPress); XISetMask(m->mask, XI_KeyRelease); XISetMask(m->mask, XI_Motion); // XISetMask(m->mask, XI_DeviceChanged); // XISetMask(m->mask, XI_Enter); // XISetMask(m->mask, XI_Leave); // XISetMask(m->mask, XI_FocusIn); // XISetMask(m->mask, XI_FocusOut); #ifdef HAVE_XI22 XISetMask(m->mask, XI_TouchBegin); XISetMask(m->mask, XI_TouchUpdate); XISetMask(m->mask, XI_TouchEnd); #endif // XISetMask(m->mask, XI_HierarchyChanged); // XISetMask(m->mask, XI_PropertyEvent); m = &mask[1]; m->deviceid = XIAllMasterDevices; m->mask_len = XIMaskLen(XI_LASTEVENT); m->mask = calloc(m->mask_len, sizeof(char)); XISetMask(m->mask, XI_RawKeyPress); XISetMask(m->mask, XI_RawKeyRelease); XISetMask(m->mask, XI_RawButtonPress); XISetMask(m->mask, XI_RawButtonRelease); XISetMask(m->mask, XI_RawMotion); #ifdef HAVE_XI22 XISetMask(m->mask, XI_RawTouchBegin); XISetMask(m->mask, XI_RawTouchUpdate); XISetMask(m->mask, XI_RawTouchEnd); #endif XISelectEvents(display, win, &mask[0], 1); XSync(display, False); free(mask[0].mask); free(mask[1].mask); } void xinput_dump(Display *display, XGenericEventCookie *cookie) { 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; } }