1/*
2 * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
3 *
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation on the rights to use, copy, modify, merge,
10 * publish, distribute, sublicense, and/or sell copies of the Software,
11 * and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 */
27
28/*
29 * Authors:
30 *   Rickard E. (Rik) Faith <faith@redhat.com>
31 *
32 */
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <X11/Xlib.h>
38#include <X11/XKBlib.h>
39#include <X11/extensions/XInput.h>
40#include <X11/extensions/XKB.h>
41#include <X11/extensions/XKBstr.h>
42#include <X11/extensions/dmxext.h>
43#include <sys/time.h>
44
45static const char *core(DMXInputAttributes *iinf)
46{
47    if (iinf->isCore)         return "core";
48    else if (iinf->sendsCore) return "extension (sends core events)";
49    else                      return "extension";
50}
51
52static void printdmxinfo(Display *display, int id)
53{
54    int                  event_base;
55    int                  error_base;
56    int                  major_version, minor_version, patch_version;
57    DMXInputAttributes   iinf;
58    Display              *backend;
59    char                 *backendname = NULL;
60
61    if (!DMXQueryExtension(display, &event_base, &error_base)) return;
62    if (!DMXQueryVersion(display, &major_version, &minor_version,
63                         &patch_version)) return;
64    if (major_version == 1 && minor_version == 0) return; /* too old */
65    if (!DMXGetInputAttributes(display, id, &iinf)) return;
66
67    printf("   DMX Information: ");
68    if (iinf.detached) printf("detached ");
69    else               printf("active   ");
70    switch (iinf.inputType) {
71    case DMXLocalInputType:
72        printf("local, %s", core(&iinf));
73        break;
74    case DMXConsoleInputType:
75        printf("console %s, %s", iinf.name, core(&iinf));
76        break;
77    case DMXBackendInputType:
78        if (iinf.physicalId >= 0) {
79            if ((backend = XOpenDisplay(iinf.name))) {
80                XExtensionVersion *ext = XGetExtensionVersion(backend, INAME);
81                if (ext && ext != (XExtensionVersion *)NoSuchExtension) {
82                    int count, i;
83                    XDeviceInfo *devInfo = XListInputDevices(backend, &count);
84                    if (devInfo) {
85                        for (i = 0; i < count; i++) {
86                            if ((unsigned)iinf.physicalId == devInfo[i].id
87                                && devInfo[i].name) {
88                                backendname = strdup(devInfo[i].name);
89                                break;
90                            }
91                        }
92                        XFreeDeviceList(devInfo);
93                    }
94                }
95                XCloseDisplay(backend);
96            }
97        }
98        printf("backend o%d/%s",iinf.physicalScreen,  iinf.name);
99        if (iinf.physicalId >= 0) printf("/id%d", iinf.physicalId);
100        if (backendname) {
101            printf("=%s", backendname);
102            free(backendname);
103        }
104        printf(" %s", core(&iinf));
105        break;
106    }
107    printf("\n");
108}
109
110int main(int argc, char **argv)
111{
112    Display              *display = NULL;
113    int                  device   = -1;
114    int                  newmouse = -1;
115    int                  newkbd   = -1;
116    int                  count;
117    int                  i, j;
118    XDeviceInfo          *devInfo;
119    XExtensionVersion    *ext;
120
121    if (argc == 2 || argc == 3 || argc == 4 || argc == 5) {
122        if (!(display = XOpenDisplay(argv[1]))) {
123            printf("Cannot open display %s\n", argv[1]);
124            return -1;
125        }
126        if (argc >= 3) device   = strtol(argv[2], NULL, 0);
127        if (argc >= 4) newmouse = strtol(argv[3], NULL, 0);
128        if (argc >= 5) newkbd   = strtol(argv[4], NULL, 0);
129    } else {
130        printf("Usage: %s display [device] [newmouse] [newkbd]\n", argv[0]);
131        return -1;
132    }
133
134    if (!display && !(display = XOpenDisplay(NULL))) {
135        printf("Cannot open default display\n");
136        return -1;
137    }
138
139    ext = XGetExtensionVersion(display, INAME);
140    if (!ext || ext == (XExtensionVersion *)NoSuchExtension) {
141        printf("No XInputExtension\n");
142        return -1;
143    }
144    printf("%s version %d.%d\n",
145           INAME, ext->major_version, ext->minor_version);
146
147    if (!(devInfo = XListInputDevices(display, &count)) || !count) {
148        printf("Cannot list devices\n");
149        return -1;
150    }
151
152    for (i = 0; i < count; i++) {
153        XAnyClassPtr any;
154        const char   *kind   = "Unknown";
155        int          has_key = 0;
156
157        switch (devInfo[i].use) {
158        case IsXPointer:         kind = "XPointer";         break;
159        case IsXKeyboard:        kind = "XKeyboard";        break;
160        case IsXExtensionDevice: kind = "XExtensionDevice"; break;
161        }
162        printf("%2lu %-20.20s %-16.16s",
163               (long unsigned)devInfo[i].id,
164               devInfo[i].name ? devInfo[i].name : "", kind);
165
166        for (j = 0, any = devInfo[i].inputclassinfo;
167             j < devInfo[i].num_classes;
168             any = (XAnyClassPtr)((char *)any + any->length), j++) {
169            const char   *class = "unk";
170            switch (any->class) {
171            case KeyClass:       class = "key"; ++has_key; break;
172            case ButtonClass:    class = "btn"; break;
173            case ValuatorClass:  class = "val"; break;
174            case FeedbackClass:  class = "fdb"; break;
175            case ProximityClass: class = "prx"; break;
176            case FocusClass:     class = "foc"; break;
177            case OtherClass:     class = "oth"; break;
178            }
179            printf(" %s", class);
180        }
181        printf("\n");
182        printdmxinfo(display, i);
183
184        if (has_key) {
185            XkbDescPtr           xkb;
186            if ((xkb = XkbGetKeyboard(display,
187                                      XkbAllComponentsMask,
188                                      devInfo[i].id))) {
189                printf("   Xkb Information:\n");
190                printf("      Device id = %d\n", xkb->device_spec);
191                printf("      Min keycode = 0x%02x\n", xkb->min_key_code);
192                printf("      Max keycode = 0x%02x\n", xkb->max_key_code);
193#define PRINTNAME(x)                                                     \
194    printf("      %s = %s\n",                                            \
195           #x, xkb->names->x ? XGetAtomName(display, xkb->names->x) : "")
196                PRINTNAME(keycodes);
197                PRINTNAME(geometry);
198                PRINTNAME(symbols);
199                PRINTNAME(types);
200                PRINTNAME(compat);
201            }
202        }
203    }
204
205    if (newmouse >= 0) {
206        XDevice     *dev;
207
208        printf("Trying to make device %d core mouse\n", newmouse);
209        dev = XOpenDevice(display, devInfo[newmouse].id);
210        printf("Status = %d\n",
211               XChangePointerDevice(display, dev, 0, 1));
212        return 0;
213    }
214
215    if (newkbd >= 0) {
216        XDevice     *dev;
217
218        printf("Trying to make device %d core keyboard\n", newkbd);
219        dev = XOpenDevice(display, devInfo[newkbd].id);
220        printf("Status = %d\n",
221               XChangeKeyboardDevice(display, dev));
222        return 0;
223    }
224
225
226    if (device >=0){
227#define MAX_EVENTS 100
228        int         cnt = 0;
229        XDevice     *dev;
230        XEventClass event_list[MAX_EVENTS];
231        int         event_type[MAX_EVENTS];
232        const char  *names[MAX_EVENTS];
233        int         total = 0;
234
235#define ADD(type)                                     \
236        if (cnt >= MAX_EVENTS) abort();             \
237        names[cnt] = #type;                           \
238        type(dev, event_type[cnt], event_list[cnt]);  \
239        if (event_type[cnt]) ++cnt
240
241
242        dev = XOpenDevice(display, devInfo[device].id);
243        ADD(DeviceKeyPress);
244        ADD(DeviceKeyRelease);
245        ADD(DeviceButtonPress);
246        ADD(DeviceButtonRelease);
247        ADD(DeviceMotionNotify);
248        ADD(DeviceFocusIn);
249        ADD(DeviceFocusOut);
250        ADD(ProximityIn);
251        ADD(ProximityOut);
252        ADD(DeviceStateNotify);
253        ADD(DeviceMappingNotify);
254        ADD(ChangeDeviceNotify);
255
256        for (i = 0; i < cnt; i++) {
257            printf("Waiting for %s events of type %d (%lu) on 0x%08lx\n",
258                   names[i],
259                   event_type[i], (unsigned long)event_list[i],
260                   (long unsigned)DefaultRootWindow(display));
261        }
262        XSelectExtensionEvent(display, DefaultRootWindow(display),
263                              event_list, cnt);
264
265        for (;;) {
266            XEvent event;
267            XNextEvent(display, &event);
268            for (i = 0; i < cnt; i++) {
269                XDeviceMotionEvent *e = (XDeviceMotionEvent *)&event;
270                XDeviceButtonEvent *b = (XDeviceButtonEvent *)&event;
271                if (event.type == event_type[i]) {
272                    printf("%s id=%lu (%d @ %d,%d; s=0x%04x, d=%d, t=%lu)"
273                           " axes_count=%d first=%d %d %d %d %d %d %d\n",
274                           names[i],
275                           (long unsigned)e->deviceid,
276                           e->type,
277                           e->x, e->y,
278                           e->device_state,
279                           b->button,
280                           (long unsigned)b->time,
281                           e->axes_count,
282                           e->first_axis,
283                           e->axis_data[0],
284                           e->axis_data[1],
285                           e->axis_data[2],
286                           e->axis_data[3],
287                           e->axis_data[4],
288                           e->axis_data[5]);
289                }
290            }
291            ++total;
292#if 0
293                                /* Used to check motion history for
294                                 * extension devices. */
295            if (!(total % 10)) {
296                XDeviceTimeCoord *tc;
297                int              n, m, a;
298                struct timeval   tv;
299                unsigned long    ms;
300                gettimeofday(&tv, NULL);
301                ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
302                tc = XGetDeviceMotionEvents(display, dev, ms-1000, ms,
303                                            &n, &m, &a);
304                printf("Got %d events of mode %s with %d axes\n",
305                       n, m == Absolute ? "Absolute" : "Relative", a);
306                for (i = 0; i < n && i < 10; i++) {
307                    printf("  %d: %lu %d %d\n",
308                           i, tc[i].time, tc[i].data[0], tc[i].data[1]);
309                }
310                XFreeDeviceMotionEvents(tc);
311            }
312#endif
313        }
314    }
315
316    XCloseDisplay(display);
317    return 0;
318}
319