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