test_xi2.c revision a570218a
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("    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
100static 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
108static 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
154static 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
180static 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
230static 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}
247void
248test_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
291static 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
326int
327test_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