1706f2543Smrg/*
2706f2543Smrg * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
3706f2543Smrg *
4706f2543Smrg * All Rights Reserved.
5706f2543Smrg *
6706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining
7706f2543Smrg * a copy of this software and associated documentation files (the
8706f2543Smrg * "Software"), to deal in the Software without restriction, including
9706f2543Smrg * without limitation on the rights to use, copy, modify, merge,
10706f2543Smrg * publish, distribute, sublicense, and/or sell copies of the Software,
11706f2543Smrg * and to permit persons to whom the Software is furnished to do so,
12706f2543Smrg * subject to the following conditions:
13706f2543Smrg *
14706f2543Smrg * The above copyright notice and this permission notice (including the
15706f2543Smrg * next paragraph) shall be included in all copies or substantial
16706f2543Smrg * portions of the Software.
17706f2543Smrg *
18706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19706f2543Smrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20706f2543Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21706f2543Smrg * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22706f2543Smrg * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23706f2543Smrg * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24706f2543Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25706f2543Smrg * SOFTWARE.
26706f2543Smrg */
27706f2543Smrg
28706f2543Smrg/*
29706f2543Smrg * Authors:
30706f2543Smrg *   Rickard E. (Rik) Faith <faith@redhat.com>
31706f2543Smrg *
32706f2543Smrg */
33706f2543Smrg
34706f2543Smrg#include <stdio.h>
35706f2543Smrg#include <stdlib.h>
36706f2543Smrg#include <string.h>
37706f2543Smrg#include <X11/Xlib.h>
38706f2543Smrg#include <X11/XKBlib.h>
39706f2543Smrg#include <X11/extensions/XInput.h>
40706f2543Smrg#include <X11/extensions/XKB.h>
41706f2543Smrg#include <X11/extensions/XKBstr.h>
42706f2543Smrg#include <X11/extensions/dmxext.h>
43706f2543Smrg#include <sys/time.h>
44706f2543Smrg
45706f2543Smrgstatic const char *core(DMXInputAttributes *iinf)
46706f2543Smrg{
47706f2543Smrg    if (iinf->isCore)         return "core";
48706f2543Smrg    else if (iinf->sendsCore) return "extension (sends core events)";
49706f2543Smrg    else                      return "extension";
50706f2543Smrg}
51706f2543Smrg
52706f2543Smrgstatic void printdmxinfo(Display *display, int id)
53706f2543Smrg{
54706f2543Smrg    int                  event_base;
55706f2543Smrg    int                  error_base;
56706f2543Smrg    int                  major_version, minor_version, patch_version;
57706f2543Smrg    DMXInputAttributes   iinf;
58706f2543Smrg    Display              *backend;
59706f2543Smrg    char                 *backendname = NULL;
60706f2543Smrg
61706f2543Smrg    if (!DMXQueryExtension(display, &event_base, &error_base)) return;
62706f2543Smrg    if (!DMXQueryVersion(display, &major_version, &minor_version,
63706f2543Smrg                         &patch_version)) return;
64706f2543Smrg    if (major_version == 1 && minor_version == 0) return; /* too old */
65706f2543Smrg    if (!DMXGetInputAttributes(display, id, &iinf)) return;
66706f2543Smrg
67706f2543Smrg    printf("   DMX Information: ");
68706f2543Smrg    if (iinf.detached) printf("detached ");
69706f2543Smrg    else               printf("active   ");
70706f2543Smrg    switch (iinf.inputType) {
71706f2543Smrg    case DMXLocalInputType:
72706f2543Smrg        printf("local, %s", core(&iinf));
73706f2543Smrg        break;
74706f2543Smrg    case DMXConsoleInputType:
75706f2543Smrg        printf("console %s, %s", iinf.name, core(&iinf));
76706f2543Smrg        break;
77706f2543Smrg    case DMXBackendInputType:
78706f2543Smrg        if (iinf.physicalId >= 0) {
79706f2543Smrg            if ((backend = XOpenDisplay(iinf.name))) {
80706f2543Smrg                XExtensionVersion *ext = XGetExtensionVersion(backend, INAME);
81706f2543Smrg                if (ext && ext != (XExtensionVersion *)NoSuchExtension) {
82706f2543Smrg                    int count, i;
83706f2543Smrg                    XDeviceInfo *devInfo = XListInputDevices(backend, &count);
84706f2543Smrg                    if (devInfo) {
85706f2543Smrg                        for (i = 0; i < count; i++) {
86706f2543Smrg                            if ((unsigned)iinf.physicalId == devInfo[i].id
87706f2543Smrg                                && devInfo[i].name) {
88706f2543Smrg                                backendname = strdup(devInfo[i].name);
89706f2543Smrg                                break;
90706f2543Smrg                            }
91706f2543Smrg                        }
92706f2543Smrg                        XFreeDeviceList(devInfo);
93706f2543Smrg                    }
94706f2543Smrg                }
95706f2543Smrg                XCloseDisplay(backend);
96706f2543Smrg            }
97706f2543Smrg        }
98706f2543Smrg        printf("backend o%d/%s",iinf.physicalScreen,  iinf.name);
99706f2543Smrg        if (iinf.physicalId >= 0) printf("/id%d", iinf.physicalId);
100706f2543Smrg        if (backendname) {
101706f2543Smrg            printf("=%s", backendname);
102706f2543Smrg            free(backendname);
103706f2543Smrg        }
104706f2543Smrg        printf(" %s", core(&iinf));
105706f2543Smrg        break;
106706f2543Smrg    }
107706f2543Smrg    printf("\n");
108706f2543Smrg}
109706f2543Smrg
110706f2543Smrgint main(int argc, char **argv)
111706f2543Smrg{
112706f2543Smrg    Display              *display = NULL;
113706f2543Smrg    int                  device   = -1;
114706f2543Smrg    int                  newmouse = -1;
115706f2543Smrg    int                  newkbd   = -1;
116706f2543Smrg    int                  count;
117706f2543Smrg    int                  i, j;
118706f2543Smrg    XDeviceInfo          *devInfo;
119706f2543Smrg    XExtensionVersion    *ext;
120706f2543Smrg
121706f2543Smrg    if (argc == 2 || argc == 3 || argc == 4 || argc == 5) {
122706f2543Smrg        if (!(display = XOpenDisplay(argv[1]))) {
123706f2543Smrg            printf("Cannot open display %s\n", argv[1]);
124706f2543Smrg            return -1;
125706f2543Smrg        }
126706f2543Smrg        if (argc >= 3) device   = strtol(argv[2], NULL, 0);
127706f2543Smrg        if (argc >= 4) newmouse = strtol(argv[3], NULL, 0);
128706f2543Smrg        if (argc >= 5) newkbd   = strtol(argv[4], NULL, 0);
129706f2543Smrg    } else {
130706f2543Smrg        printf("Usage: %s display [device] [newmouse] [newkbd]\n", argv[0]);
131706f2543Smrg        return -1;
132706f2543Smrg    }
133706f2543Smrg
134706f2543Smrg    if (!display && !(display = XOpenDisplay(NULL))) {
135706f2543Smrg        printf("Cannot open default display\n");
136706f2543Smrg        return -1;
137706f2543Smrg    }
138706f2543Smrg
139706f2543Smrg    ext = XGetExtensionVersion(display, INAME);
140706f2543Smrg    if (!ext || ext == (XExtensionVersion *)NoSuchExtension) {
141706f2543Smrg        printf("No XInputExtension\n");
142706f2543Smrg        return -1;
143706f2543Smrg    }
144706f2543Smrg    printf("%s version %d.%d\n",
145706f2543Smrg           INAME, ext->major_version, ext->minor_version);
146706f2543Smrg
147706f2543Smrg    if (!(devInfo = XListInputDevices(display, &count)) || !count) {
148706f2543Smrg        printf("Cannot list devices\n");
149706f2543Smrg        return -1;
150706f2543Smrg    }
151706f2543Smrg
152706f2543Smrg    for (i = 0; i < count; i++) {
153706f2543Smrg        XAnyClassPtr any;
154706f2543Smrg        const char   *kind   = "Unknown";
155706f2543Smrg        int          has_key = 0;
156706f2543Smrg
157706f2543Smrg        switch (devInfo[i].use) {
158706f2543Smrg        case IsXPointer:         kind = "XPointer";         break;
159706f2543Smrg        case IsXKeyboard:        kind = "XKeyboard";        break;
160706f2543Smrg        case IsXExtensionDevice: kind = "XExtensionDevice"; break;
161706f2543Smrg        }
162706f2543Smrg        printf("%2lu %-20.20s %-16.16s",
163706f2543Smrg               (long unsigned)devInfo[i].id,
164706f2543Smrg               devInfo[i].name ? devInfo[i].name : "", kind);
165706f2543Smrg
166706f2543Smrg        for (j = 0, any = devInfo[i].inputclassinfo;
167706f2543Smrg             j < devInfo[i].num_classes;
168706f2543Smrg             any = (XAnyClassPtr)((char *)any + any->length), j++) {
169706f2543Smrg            const char   *class = "unk";
170706f2543Smrg            switch (any->class) {
171706f2543Smrg            case KeyClass:       class = "key"; ++has_key; break;
172706f2543Smrg            case ButtonClass:    class = "btn"; break;
173706f2543Smrg            case ValuatorClass:  class = "val"; break;
174706f2543Smrg            case FeedbackClass:  class = "fdb"; break;
175706f2543Smrg            case ProximityClass: class = "prx"; break;
176706f2543Smrg            case FocusClass:     class = "foc"; break;
177706f2543Smrg            case OtherClass:     class = "oth"; break;
178706f2543Smrg            }
179706f2543Smrg            printf(" %s", class);
180706f2543Smrg        }
181706f2543Smrg        printf("\n");
182706f2543Smrg        printdmxinfo(display, i);
183706f2543Smrg
184706f2543Smrg        if (has_key) {
185706f2543Smrg            XkbDescPtr           xkb;
186706f2543Smrg            if ((xkb = XkbGetKeyboard(display,
187706f2543Smrg                                      XkbAllComponentsMask,
188706f2543Smrg                                      devInfo[i].id))) {
189706f2543Smrg                printf("   Xkb Information:\n");
190706f2543Smrg                printf("      Device id = %d\n", xkb->device_spec);
191706f2543Smrg                printf("      Min keycode = 0x%02x\n", xkb->min_key_code);
192706f2543Smrg                printf("      Max keycode = 0x%02x\n", xkb->max_key_code);
193706f2543Smrg#define PRINTNAME(x)                                                     \
194706f2543Smrg    printf("      %s = %s\n",                                            \
195706f2543Smrg           #x, xkb->names->x ? XGetAtomName(display, xkb->names->x) : "")
196706f2543Smrg                PRINTNAME(keycodes);
197706f2543Smrg                PRINTNAME(geometry);
198706f2543Smrg                PRINTNAME(symbols);
199706f2543Smrg                PRINTNAME(types);
200706f2543Smrg                PRINTNAME(compat);
201706f2543Smrg            }
202706f2543Smrg        }
203706f2543Smrg    }
204706f2543Smrg
205706f2543Smrg    if (newmouse >= 0) {
206706f2543Smrg        XDevice     *dev;
207706f2543Smrg
208706f2543Smrg        printf("Trying to make device %d core mouse\n", newmouse);
209706f2543Smrg        dev = XOpenDevice(display, devInfo[newmouse].id);
210706f2543Smrg        printf("Status = %d\n",
211706f2543Smrg               XChangePointerDevice(display, dev, 0, 1));
212706f2543Smrg        return 0;
213706f2543Smrg    }
214706f2543Smrg
215706f2543Smrg    if (newkbd >= 0) {
216706f2543Smrg        XDevice     *dev;
217706f2543Smrg
218706f2543Smrg        printf("Trying to make device %d core keyboard\n", newkbd);
219706f2543Smrg        dev = XOpenDevice(display, devInfo[newkbd].id);
220706f2543Smrg        printf("Status = %d\n",
221706f2543Smrg               XChangeKeyboardDevice(display, dev));
222706f2543Smrg        return 0;
223706f2543Smrg    }
224706f2543Smrg
225706f2543Smrg
226706f2543Smrg    if (device >=0){
227706f2543Smrg#define MAX_EVENTS 100
228706f2543Smrg        int         cnt = 0;
229706f2543Smrg        XDevice     *dev;
230706f2543Smrg        XEventClass event_list[MAX_EVENTS];
231706f2543Smrg        int         event_type[MAX_EVENTS];
232706f2543Smrg        const char  *names[MAX_EVENTS];
233706f2543Smrg        int         total = 0;
234706f2543Smrg
235706f2543Smrg#define ADD(type)                                     \
236706f2543Smrg        if (cnt >= MAX_EVENTS) abort();             \
237706f2543Smrg        names[cnt] = #type;                           \
238706f2543Smrg        type(dev, event_type[cnt], event_list[cnt]);  \
239706f2543Smrg        if (event_type[cnt]) ++cnt
240706f2543Smrg
241706f2543Smrg
242706f2543Smrg        dev = XOpenDevice(display, devInfo[device].id);
243706f2543Smrg        ADD(DeviceKeyPress);
244706f2543Smrg        ADD(DeviceKeyRelease);
245706f2543Smrg        ADD(DeviceButtonPress);
246706f2543Smrg        ADD(DeviceButtonRelease);
247706f2543Smrg        ADD(DeviceMotionNotify);
248706f2543Smrg        ADD(DeviceFocusIn);
249706f2543Smrg        ADD(DeviceFocusOut);
250706f2543Smrg        ADD(ProximityIn);
251706f2543Smrg        ADD(ProximityOut);
252706f2543Smrg        ADD(DeviceStateNotify);
253706f2543Smrg        ADD(DeviceMappingNotify);
254706f2543Smrg        ADD(ChangeDeviceNotify);
255706f2543Smrg
256706f2543Smrg        for (i = 0; i < cnt; i++) {
257706f2543Smrg            printf("Waiting for %s events of type %d (%lu) on 0x%08lx\n",
258706f2543Smrg                   names[i],
259706f2543Smrg                   event_type[i], (unsigned long)event_list[i],
260706f2543Smrg                   (long unsigned)DefaultRootWindow(display));
261706f2543Smrg        }
262706f2543Smrg        XSelectExtensionEvent(display, DefaultRootWindow(display),
263706f2543Smrg                              event_list, cnt);
264706f2543Smrg
265706f2543Smrg        for (;;) {
266706f2543Smrg            XEvent event;
267706f2543Smrg            XNextEvent(display, &event);
268706f2543Smrg            for (i = 0; i < cnt; i++) {
269706f2543Smrg                XDeviceMotionEvent *e = (XDeviceMotionEvent *)&event;
270706f2543Smrg                XDeviceButtonEvent *b = (XDeviceButtonEvent *)&event;
271706f2543Smrg                if (event.type == event_type[i]) {
272706f2543Smrg                    printf("%s id=%lu (%d @ %d,%d; s=0x%04x, d=%d, t=%lu)"
273706f2543Smrg                           " axes_count=%d first=%d %d %d %d %d %d %d\n",
274706f2543Smrg                           names[i],
275706f2543Smrg                           (long unsigned)e->deviceid,
276706f2543Smrg                           e->type,
277706f2543Smrg                           e->x, e->y,
278706f2543Smrg                           e->device_state,
279706f2543Smrg                           b->button,
280706f2543Smrg                           (long unsigned)b->time,
281706f2543Smrg                           e->axes_count,
282706f2543Smrg                           e->first_axis,
283706f2543Smrg                           e->axis_data[0],
284706f2543Smrg                           e->axis_data[1],
285706f2543Smrg                           e->axis_data[2],
286706f2543Smrg                           e->axis_data[3],
287706f2543Smrg                           e->axis_data[4],
288706f2543Smrg                           e->axis_data[5]);
289706f2543Smrg                }
290706f2543Smrg            }
291706f2543Smrg            ++total;
292706f2543Smrg#if 0
293706f2543Smrg                                /* Used to check motion history for
294706f2543Smrg                                 * extension devices. */
295706f2543Smrg            if (!(total % 10)) {
296706f2543Smrg                XDeviceTimeCoord *tc;
297706f2543Smrg                int              n, m, a;
298706f2543Smrg                struct timeval   tv;
299706f2543Smrg                unsigned long    ms;
300706f2543Smrg                gettimeofday(&tv, NULL);
301706f2543Smrg                ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
302706f2543Smrg                tc = XGetDeviceMotionEvents(display, dev, ms-1000, ms,
303706f2543Smrg                                            &n, &m, &a);
304706f2543Smrg                printf("Got %d events of mode %s with %d axes\n",
305706f2543Smrg                       n, m == Absolute ? "Absolute" : "Relative", a);
306706f2543Smrg                for (i = 0; i < n && i < 10; i++) {
307706f2543Smrg                    printf("  %d: %lu %d %d\n",
308706f2543Smrg                           i, tc[i].time, tc[i].data[0], tc[i].data[1]);
309706f2543Smrg                }
310706f2543Smrg                XFreeDeviceMotionEvents(tc);
311706f2543Smrg            }
312706f2543Smrg#endif
313706f2543Smrg        }
314706f2543Smrg    }
315706f2543Smrg
316706f2543Smrg    XCloseDisplay(display);
317706f2543Smrg    return 0;
318706f2543Smrg}
319