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