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