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