1/* 2 * Copyright © 2009 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 * 23 */ 24 25 26#include "xinput.h" 27#include <string.h> 28 29extern void print_classes_xi2(Display*, XIAnyClassInfo **classes, 30 int num_classes); 31 32static Window create_win(Display *dpy) 33{ 34 Window win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 200, 35 200, 0, 0, WhitePixel(dpy, 0)); 36 Window subwindow = XCreateSimpleWindow(dpy, win, 50, 50, 50, 50, 0, 0, 37 BlackPixel(dpy, 0)); 38 39 XMapWindow(dpy, subwindow); 40 XSelectInput(dpy, win, ExposureMask); 41 return win; 42} 43 44static void print_deviceevent(XIDeviceEvent* event) 45{ 46 double *val; 47 int i; 48 49 printf(" device: %d (%d)\n", event->deviceid, event->sourceid); 50 printf(" time: %ld\n", event->time); 51 printf(" detail: %d\n", event->detail); 52 switch(event->evtype) { 53 case XI_KeyPress: 54 case XI_KeyRelease: 55 printf(" flags: %s\n", (event->flags & XIKeyRepeat) ? "repeat" : ""); 56 break; 57#if HAVE_XI21 58 case XI_ButtonPress: 59 case XI_ButtonRelease: 60 case XI_Motion: 61 printf(" flags: %s\n", (event->flags & XIPointerEmulated) ? "emulated" : ""); 62 break; 63#endif 64#if HAVE_XI22 65 case XI_TouchBegin: 66 case XI_TouchUpdate: 67 case XI_TouchEnd: 68 printf(" flags:%s%s\n", 69 (event->flags & XITouchPendingEnd) ? " pending_end" : "", 70 (event->flags & XITouchEmulatingPointer) ? " emulating" : ""); 71 break; 72#endif 73 } 74 75 printf(" root: %.2f/%.2f\n", event->root_x, event->root_y); 76 printf(" event: %.2f/%.2f\n", event->event_x, event->event_y); 77 78 printf(" buttons:"); 79 for (i = 0; i < event->buttons.mask_len * 8; i++) 80 if (XIMaskIsSet(event->buttons.mask, i)) 81 printf(" %d", i); 82 printf("\n"); 83 84 printf(" modifiers: locked %#x latched %#x base %#x effective: %#x\n", 85 event->mods.locked, event->mods.latched, 86 event->mods.base, event->mods.effective); 87 printf(" group: locked %#x latched %#x base %#x effective: %#x\n", 88 event->group.locked, event->group.latched, 89 event->group.base, event->group.effective); 90 printf(" valuators:\n"); 91 92 val = event->valuators.values; 93 for (i = 0; i < event->valuators.mask_len * 8; i++) 94 if (XIMaskIsSet(event->valuators.mask, i)) 95 printf(" %i: %.2f\n", i, *val++); 96 97 printf(" windows: root 0x%lx event 0x%lx child 0x%lx\n", 98 event->root, event->event, event->child); 99} 100 101static void print_devicechangedevent(Display *dpy, XIDeviceChangedEvent *event) 102{ 103 printf(" device: %d (%d)\n", event->deviceid, event->sourceid); 104 printf(" time: %ld\n", event->time); 105 printf(" reason: %s\n", (event->reason == XISlaveSwitch) ? "SlaveSwitch" : 106 "DeviceChanged"); 107 print_classes_xi2(dpy, event->classes, event->num_classes); 108} 109 110static void print_hierarchychangedevent(XIHierarchyEvent *event) 111{ 112 int i; 113 printf(" time: %ld\n", event->time); 114 printf(" Changes happened: %s %s %s %s %s %s %s %s\n", 115 (event->flags & XIMasterAdded) ? "[new master]" : "", 116 (event->flags & XIMasterRemoved) ? "[master removed]" : "", 117 (event->flags & XISlaveAdded) ? "[new slave]" : "", 118 (event->flags & XISlaveRemoved) ? "[slave removed]" : "", 119 (event->flags & XISlaveAttached) ? "[slave attached]" : "", 120 (event->flags & XISlaveDetached) ? "[slave detached]" : "", 121 (event->flags & XIDeviceEnabled) ? "[device enabled]" : "", 122 (event->flags & XIDeviceDisabled) ? "[device disabled]" : ""); 123 124 for (i = 0; i < event->num_info; i++) 125 { 126 char *use = "<undefined>"; 127 switch(event->info[i].use) 128 { 129 case XIMasterPointer: use = "master pointer"; break; 130 case XIMasterKeyboard: use = "master keyboard"; break; 131 case XISlavePointer: use = "slave pointer"; break; 132 case XISlaveKeyboard: use = "slave keyboard"; break; 133 case XIFloatingSlave: use = "floating slave"; break; 134 break; 135 } 136 137 printf(" device %d [%s (%d)] is %s\n", 138 event->info[i].deviceid, 139 use, 140 event->info[i].attachment, 141 (event->info[i].enabled) ? "enabled" : "disabled"); 142 if (event->info[i].flags) 143 { 144 printf(" changes: %s %s %s %s %s %s %s %s\n", 145 (event->info[i].flags & XIMasterAdded) ? "[new master]" : "", 146 (event->info[i].flags & XIMasterRemoved) ? "[master removed]" : "", 147 (event->info[i].flags & XISlaveAdded) ? "[new slave]" : "", 148 (event->info[i].flags & XISlaveRemoved) ? "[slave removed]" : "", 149 (event->info[i].flags & XISlaveAttached) ? "[slave attached]" : "", 150 (event->info[i].flags & XISlaveDetached) ? "[slave detached]" : "", 151 (event->info[i].flags & XIDeviceEnabled) ? "[device enabled]" : "", 152 (event->info[i].flags & XIDeviceDisabled) ? "[device disabled]" : ""); 153 } 154 } 155} 156 157static void print_rawevent(XIRawEvent *event) 158{ 159 int i; 160 double *val, *raw_val; 161 162 printf(" device: %d (%d)\n", event->deviceid, event->sourceid); 163 printf(" time: %ld\n", event->time); 164 printf(" detail: %d\n", event->detail); 165#if HAVE_XI21 166 switch(event->evtype) { 167 case XI_RawButtonPress: 168 case XI_RawButtonRelease: 169 case XI_RawMotion: 170 printf(" flags: %s\n", (event->flags & XIPointerEmulated) ? "emulated" : ""); 171 break; 172 } 173#endif 174 175 printf(" valuators:\n"); 176 val = event->valuators.values; 177 raw_val = event->raw_values; 178 for (i = 0; i < event->valuators.mask_len * 8; i++) 179 if (XIMaskIsSet(event->valuators.mask, i)) 180 printf(" %2d: %.2f (%.2f)\n", i, *val++, *raw_val++); 181 printf("\n"); 182} 183 184static void print_enterleave(XILeaveEvent* event) 185{ 186 char *mode = "<undefined>", 187 *detail = "<undefined>"; 188 int i; 189 190 printf(" device: %d (%d)\n", event->deviceid, event->sourceid); 191 printf(" time: %ld\n", event->time); 192 printf(" windows: root 0x%lx event 0x%lx child 0x%ld\n", 193 event->root, event->event, event->child); 194 switch(event->mode) 195 { 196 case XINotifyNormal: mode = "NotifyNormal"; break; 197 case XINotifyGrab: mode = "NotifyGrab"; break; 198 case XINotifyUngrab: mode = "NotifyUngrab"; break; 199 case XINotifyWhileGrabbed: mode = "NotifyWhileGrabbed"; break; 200 case XINotifyPassiveGrab: mode = "NotifyPassiveGrab"; break; 201 case XINotifyPassiveUngrab:mode = "NotifyPassiveUngrab"; break; 202 } 203 switch (event->detail) 204 { 205 case XINotifyAncestor: detail = "NotifyAncestor"; break; 206 case XINotifyVirtual: detail = "NotifyVirtual"; break; 207 case XINotifyInferior: detail = "NotifyInferior"; break; 208 case XINotifyNonlinear: detail = "NotifyNonlinear"; break; 209 case XINotifyNonlinearVirtual: detail = "NotifyNonlinearVirtual"; break; 210 case XINotifyPointer: detail = "NotifyPointer"; break; 211 case XINotifyPointerRoot: detail = "NotifyPointerRoot"; break; 212 case XINotifyDetailNone: detail = "NotifyDetailNone"; break; 213 } 214 printf(" mode: %s (detail %s)\n", mode, detail); 215 printf(" flags: %s %s\n", event->focus ? "[focus]" : "", 216 event->same_screen ? "[same screen]" : ""); 217 printf(" buttons:"); 218 for (i = 0; i < event->buttons.mask_len * 8; i++) 219 if (XIMaskIsSet(event->buttons.mask, i)) 220 printf(" %d", i); 221 printf("\n"); 222 223 printf(" modifiers: locked %#x latched %#x base %#x effective: %#x\n", 224 event->mods.locked, event->mods.latched, 225 event->mods.base, event->mods.effective); 226 printf(" group: locked %#x latched %#x base %#x effective: %#x\n", 227 event->group.locked, event->group.latched, 228 event->group.base, event->group.effective); 229 230 printf(" root x/y: %.2f / %.2f\n", event->root_x, event->root_y); 231 printf(" event x/y: %.2f / %.2f\n", event->event_x, event->event_y); 232 233} 234 235static void print_propertyevent(Display *display, XIPropertyEvent* event) 236{ 237 char *changed; 238 char *name; 239 240 if (event->what == XIPropertyDeleted) 241 changed = "deleted"; 242 else if (event->what == XIPropertyCreated) 243 changed = "created"; 244 else 245 changed = "modified"; 246 name = XGetAtomName(display, event->property); 247 printf(" time: %ld\n", event->time); 248 printf(" property: %ld '%s'\n", event->property, name); 249 printf(" changed: %s\n", changed); 250 251 XFree(name); 252} 253void 254test_sync_grab(Display *display, Window win) 255{ 256 int loop = 3; 257 int rc; 258 XIEventMask mask; 259 260 /* Select for motion events */ 261 mask.deviceid = XIAllDevices; 262 mask.mask_len = 2; 263 mask.mask = calloc(2, sizeof(char)); 264 XISetMask(mask.mask, XI_ButtonPress); 265 266 if ((rc = XIGrabDevice(display, 2, win, CurrentTime, None, GrabModeSync, 267 GrabModeAsync, False, &mask)) != GrabSuccess) 268 { 269 fprintf(stderr, "Grab failed with %d\n", rc); 270 return; 271 } 272 free(mask.mask); 273 274 XSync(display, True); 275 XIAllowEvents(display, 2, SyncPointer, CurrentTime); 276 XFlush(display); 277 278 printf("Holding sync grab for %d button presses.\n", loop); 279 280 while(loop--) 281 { 282 XIEvent ev; 283 284 XNextEvent(display, (XEvent*)&ev); 285 if (ev.type == GenericEvent && ev.extension == xi_opcode ) 286 { 287 XIDeviceEvent *event = (XIDeviceEvent*)&ev; 288 print_deviceevent(event); 289 XIAllowEvents(display, 2, SyncPointer, CurrentTime); 290 } 291 } 292 293 XIUngrabDevice(display, 2, CurrentTime); 294 printf("Done\n"); 295} 296 297static const char* type_to_name(int evtype) 298{ 299 const char *name; 300 301 switch(evtype) { 302 case XI_DeviceChanged: name = "DeviceChanged"; break; 303 case XI_KeyPress: name = "KeyPress"; break; 304 case XI_KeyRelease: name = "KeyRelease"; break; 305 case XI_ButtonPress: name = "ButtonPress"; break; 306 case XI_ButtonRelease: name = "ButtonRelease"; break; 307 case XI_Motion: name = "Motion"; break; 308 case XI_Enter: name = "Enter"; break; 309 case XI_Leave: name = "Leave"; break; 310 case XI_FocusIn: name = "FocusIn"; break; 311 case XI_FocusOut: name = "FocusOut"; break; 312 case XI_HierarchyChanged: name = "HierarchyChanged"; break; 313 case XI_PropertyEvent: name = "PropertyEvent"; break; 314 case XI_RawKeyPress: name = "RawKeyPress"; break; 315 case XI_RawKeyRelease: name = "RawKeyRelease"; break; 316 case XI_RawButtonPress: name = "RawButtonPress"; break; 317 case XI_RawButtonRelease: name = "RawButtonRelease"; break; 318 case XI_RawMotion: name = "RawMotion"; break; 319 case XI_TouchBegin: name = "TouchBegin"; break; 320 case XI_TouchUpdate: name = "TouchUpdate"; break; 321 case XI_TouchEnd: name = "TouchEnd"; break; 322 case XI_RawTouchBegin: name = "RawTouchBegin"; break; 323 case XI_RawTouchUpdate: name = "RawTouchUpdate"; break; 324 case XI_RawTouchEnd: name = "RawTouchEnd"; break; 325 default: 326 name = "unknown event type"; break; 327 } 328 return name; 329} 330 331 332int 333test_xi2(Display *display, 334 int argc, 335 char *argv[], 336 char *name, 337 char *desc) 338{ 339 XIEventMask mask[2]; 340 XIEventMask *m; 341 Window win; 342 int deviceid = -1; 343 int use_root = 0; 344 int rc; 345 346 setvbuf(stdout, NULL, _IOLBF, 0); 347 348 if (argc >= 1 && strcmp(argv[0], "--root") == 0) { 349 use_root = 1; 350 351 argc--; 352 argv++; 353 } 354 355 rc = list(display, argc, argv, name, desc); 356 if (rc != EXIT_SUCCESS) 357 return rc; 358 359 if (use_root) 360 win = DefaultRootWindow(display); 361 else 362 win = create_win(display); 363 364 if (argc >= 1) { 365 XIDeviceInfo *info; 366 info = xi2_find_device_info(display, argv[0]); 367 /* info is alway valid, the list() call exits if the device 368 cannot be found, but let's shut up coverity */ 369 if (!info) 370 return EXIT_FAILURE; 371 deviceid = info->deviceid; 372 } 373 374 /* Select for motion events */ 375 m = &mask[0]; 376 m->deviceid = (deviceid == -1) ? XIAllDevices : deviceid; 377 m->mask_len = XIMaskLen(XI_LASTEVENT); 378 m->mask = calloc(m->mask_len, sizeof(char)); 379 XISetMask(m->mask, XI_ButtonPress); 380 XISetMask(m->mask, XI_ButtonRelease); 381 XISetMask(m->mask, XI_KeyPress); 382 XISetMask(m->mask, XI_KeyRelease); 383 XISetMask(m->mask, XI_Motion); 384 XISetMask(m->mask, XI_DeviceChanged); 385 XISetMask(m->mask, XI_Enter); 386 XISetMask(m->mask, XI_Leave); 387 XISetMask(m->mask, XI_FocusIn); 388 XISetMask(m->mask, XI_FocusOut); 389#if HAVE_XI22 390 XISetMask(m->mask, XI_TouchBegin); 391 XISetMask(m->mask, XI_TouchUpdate); 392 XISetMask(m->mask, XI_TouchEnd); 393#endif 394 if (m->deviceid == XIAllDevices) 395 XISetMask(m->mask, XI_HierarchyChanged); 396 XISetMask(m->mask, XI_PropertyEvent); 397 398 m = &mask[1]; 399 m->deviceid = (deviceid == -1) ? XIAllMasterDevices : deviceid; 400 m->mask_len = XIMaskLen(XI_LASTEVENT); 401 m->mask = calloc(m->mask_len, sizeof(char)); 402 XISetMask(m->mask, XI_RawKeyPress); 403 XISetMask(m->mask, XI_RawKeyRelease); 404 XISetMask(m->mask, XI_RawButtonPress); 405 XISetMask(m->mask, XI_RawButtonRelease); 406 XISetMask(m->mask, XI_RawMotion); 407#if HAVE_XI22 408 XISetMask(m->mask, XI_RawTouchBegin); 409 XISetMask(m->mask, XI_RawTouchUpdate); 410 XISetMask(m->mask, XI_RawTouchEnd); 411#endif 412 413 XISelectEvents(display, win, &mask[0], use_root ? 2 : 1); 414 if (!use_root) { 415 XISelectEvents(display, DefaultRootWindow(display), &mask[1], 1); 416 XMapWindow(display, win); 417 } 418 XSync(display, False); 419 420 free(mask[0].mask); 421 free(mask[1].mask); 422 423 if (!use_root) { 424 XEvent event; 425 XMaskEvent(display, ExposureMask, &event); 426 XSelectInput(display, win, 0); 427 } 428 429 /* 430 test_sync_grab(display, win); 431 */ 432 433 while(1) 434 { 435 XEvent ev; 436 XGenericEventCookie *cookie = (XGenericEventCookie*)&ev.xcookie; 437 XNextEvent(display, (XEvent*)&ev); 438 439 if (XGetEventData(display, cookie) && 440 cookie->type == GenericEvent && 441 cookie->extension == xi_opcode) 442 { 443 printf("EVENT type %d (%s)\n", cookie->evtype, type_to_name(cookie->evtype)); 444 switch (cookie->evtype) 445 { 446 case XI_DeviceChanged: 447 print_devicechangedevent(display, cookie->data); 448 break; 449 case XI_HierarchyChanged: 450 print_hierarchychangedevent(cookie->data); 451 break; 452 case XI_RawKeyPress: 453 case XI_RawKeyRelease: 454 case XI_RawButtonPress: 455 case XI_RawButtonRelease: 456 case XI_RawMotion: 457 case XI_RawTouchBegin: 458 case XI_RawTouchUpdate: 459 case XI_RawTouchEnd: 460 print_rawevent(cookie->data); 461 break; 462 case XI_Enter: 463 case XI_Leave: 464 case XI_FocusIn: 465 case XI_FocusOut: 466 print_enterleave(cookie->data); 467 break; 468 case XI_PropertyEvent: 469 print_propertyevent(display, cookie->data); 470 break; 471 default: 472 print_deviceevent(cookie->data); 473 break; 474 } 475 } 476 477 XFreeEventData(display, cookie); 478 } 479 480 XDestroyWindow(display, win); 481 482 return EXIT_SUCCESS; 483} 484