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 
45 static const char *
core(DMXInputAttributes * iinf)46 core(DMXInputAttributes * iinf)
47 {
48     if (iinf->isCore)
49         return "core";
50     else if (iinf->sendsCore)
51         return "extension (sends core events)";
52     else
53         return "extension";
54 }
55 
56 static void
printdmxinfo(Display * display,int id)57 printdmxinfo(Display * display, int id)
58 {
59     int event_base;
60     int error_base;
61     int major_version, minor_version, patch_version;
62     DMXInputAttributes iinf;
63     Display *backend;
64     char *backendname = NULL;
65 
66     if (!DMXQueryExtension(display, &event_base, &error_base))
67         return;
68     if (!DMXQueryVersion(display, &major_version, &minor_version,
69                          &patch_version))
70         return;
71     if (major_version == 1 && minor_version == 0)
72         return;                 /* too old */
73     if (!DMXGetInputAttributes(display, id, &iinf))
74         return;
75 
76     printf("   DMX Information: ");
77     if (iinf.detached)
78         printf("detached ");
79     else
80         printf("active   ");
81     switch (iinf.inputType) {
82     case DMXLocalInputType:
83         printf("local, %s", core(&iinf));
84         break;
85     case DMXConsoleInputType:
86         printf("console %s, %s", iinf.name, core(&iinf));
87         break;
88     case DMXBackendInputType:
89         if (iinf.physicalId >= 0) {
90             if ((backend = XOpenDisplay(iinf.name))) {
91                 XExtensionVersion *ext = XGetExtensionVersion(backend, INAME);
92 
93                 if (ext && ext != (XExtensionVersion *) NoSuchExtension) {
94                     int count, i;
95                     XDeviceInfo *devInfo = XListInputDevices(backend, &count);
96 
97                     if (devInfo) {
98                         for (i = 0; i < count; i++) {
99                             if ((unsigned) iinf.physicalId == devInfo[i].id
100                                 && devInfo[i].name) {
101                                 backendname = strdup(devInfo[i].name);
102                                 break;
103                             }
104                         }
105                         XFreeDeviceList(devInfo);
106                     }
107                 }
108                 XCloseDisplay(backend);
109             }
110         }
111         printf("backend o%d/%s", iinf.physicalScreen, iinf.name);
112         if (iinf.physicalId >= 0)
113             printf("/id%d", iinf.physicalId);
114         if (backendname) {
115             printf("=%s", backendname);
116             free(backendname);
117         }
118         printf(" %s", core(&iinf));
119         break;
120     }
121     printf("\n");
122 }
123 
124 int
main(int argc,char ** argv)125 main(int argc, char **argv)
126 {
127     Display *display = NULL;
128     int device = -1;
129     int newmouse = -1;
130     int newkbd = -1;
131     int count;
132     int i, j;
133     XDeviceInfo *devInfo;
134     XExtensionVersion *ext;
135 
136     if (argc == 2 || argc == 3 || argc == 4 || argc == 5) {
137         if (!(display = XOpenDisplay(argv[1]))) {
138             printf("Cannot open display %s\n", argv[1]);
139             return -1;
140         }
141         if (argc >= 3)
142             device = strtol(argv[2], NULL, 0);
143         if (argc >= 4)
144             newmouse = strtol(argv[3], NULL, 0);
145         if (argc >= 5)
146             newkbd = strtol(argv[4], NULL, 0);
147     }
148     else {
149         printf("Usage: %s display [device] [newmouse] [newkbd]\n", argv[0]);
150         return -1;
151     }
152 
153     if (!display && !(display = XOpenDisplay(NULL))) {
154         printf("Cannot open default display\n");
155         return -1;
156     }
157 
158     ext = XGetExtensionVersion(display, INAME);
159     if (!ext || ext == (XExtensionVersion *) NoSuchExtension) {
160         printf("No XInputExtension\n");
161         return -1;
162     }
163     printf("%s version %d.%d\n", INAME, ext->major_version, ext->minor_version);
164 
165     if (!(devInfo = XListInputDevices(display, &count)) || !count) {
166         printf("Cannot list devices\n");
167         return -1;
168     }
169 
170     for (i = 0; i < count; i++) {
171         XAnyClassPtr any;
172         const char *kind = "Unknown";
173         int has_key = 0;
174 
175         switch (devInfo[i].use) {
176         case IsXPointer:
177             kind = "XPointer";
178             break;
179         case IsXKeyboard:
180             kind = "XKeyboard";
181             break;
182         case IsXExtensionDevice:
183             kind = "XExtensionDevice";
184             break;
185         }
186         printf("%2lu %-20.20s %-16.16s",
187                (long unsigned) devInfo[i].id,
188                devInfo[i].name ? devInfo[i].name : "", kind);
189 
190         for (j = 0, any = devInfo[i].inputclassinfo;
191              j < devInfo[i].num_classes;
192              any = (XAnyClassPtr) ((char *) any + any->length), j++) {
193             const char *class = "unk";
194 
195             switch (any->class) {
196             case KeyClass:
197                 class = "key";
198                 ++has_key;
199                 break;
200             case ButtonClass:
201                 class = "btn";
202                 break;
203             case ValuatorClass:
204                 class = "val";
205                 break;
206             case FeedbackClass:
207                 class = "fdb";
208                 break;
209             case ProximityClass:
210                 class = "prx";
211                 break;
212             case FocusClass:
213                 class = "foc";
214                 break;
215             case OtherClass:
216                 class = "oth";
217                 break;
218             }
219             printf(" %s", class);
220         }
221         printf("\n");
222         printdmxinfo(display, i);
223 
224         if (has_key) {
225             XkbDescPtr xkb;
226 
227             if ((xkb = XkbGetKeyboard(display,
228                                       XkbAllComponentsMask, devInfo[i].id))) {
229                 printf("   Xkb Information:\n");
230                 printf("      Device id = %d\n", xkb->device_spec);
231                 printf("      Min keycode = 0x%02x\n", xkb->min_key_code);
232                 printf("      Max keycode = 0x%02x\n", xkb->max_key_code);
233 #define PRINTNAME(x)                                                     \
234     printf("      %s = %s\n",                                            \
235            #x, xkb->names->x ? XGetAtomName(display, xkb->names->x) : "")
236                 PRINTNAME(keycodes);
237                 PRINTNAME(geometry);
238                 PRINTNAME(symbols);
239                 PRINTNAME(types);
240                 PRINTNAME(compat);
241             }
242         }
243     }
244 
245     if (newmouse >= 0) {
246         XDevice *dev;
247 
248         printf("Trying to make device %d core mouse\n", newmouse);
249         dev = XOpenDevice(display, devInfo[newmouse].id);
250         printf("Status = %d\n", XChangePointerDevice(display, dev, 0, 1));
251         return 0;
252     }
253 
254     if (newkbd >= 0) {
255         XDevice *dev;
256 
257         printf("Trying to make device %d core keyboard\n", newkbd);
258         dev = XOpenDevice(display, devInfo[newkbd].id);
259         printf("Status = %d\n", XChangeKeyboardDevice(display, dev));
260         return 0;
261     }
262 
263     if (device >= 0) {
264 #define MAX_EVENTS 100
265         int cnt = 0;
266         XDevice *dev;
267         XEventClass event_list[MAX_EVENTS];
268         int event_type[MAX_EVENTS];
269         const char *names[MAX_EVENTS];
270         int total = 0;
271 
272 #define ADD(type)                                     \
273         if (cnt >= MAX_EVENTS) abort();             \
274         names[cnt] = #type;                           \
275         type(dev, event_type[cnt], event_list[cnt]);  \
276         if (event_type[cnt]) ++cnt
277 
278         dev = XOpenDevice(display, devInfo[device].id);
279         ADD(DeviceKeyPress);
280         ADD(DeviceKeyRelease);
281         ADD(DeviceButtonPress);
282         ADD(DeviceButtonRelease);
283         ADD(DeviceMotionNotify);
284         ADD(DeviceFocusIn);
285         ADD(DeviceFocusOut);
286         ADD(ProximityIn);
287         ADD(ProximityOut);
288         ADD(DeviceStateNotify);
289         ADD(DeviceMappingNotify);
290         ADD(ChangeDeviceNotify);
291 
292         for (i = 0; i < cnt; i++) {
293             printf("Waiting for %s events of type %d (%lu) on 0x%08lx\n",
294                    names[i],
295                    event_type[i], (unsigned long) event_list[i],
296                    (long unsigned) DefaultRootWindow(display));
297         }
298         XSelectExtensionEvent(display, DefaultRootWindow(display),
299                               event_list, cnt);
300 
301         for (;;) {
302             XEvent event;
303 
304             XNextEvent(display, &event);
305             for (i = 0; i < cnt; i++) {
306                 XDeviceMotionEvent *e = (XDeviceMotionEvent *) &event;
307                 XDeviceButtonEvent *b = (XDeviceButtonEvent *) &event;
308 
309                 if (event.type == event_type[i]) {
310                     printf("%s id=%lu (%d @ %d,%d; s=0x%04x, d=%d, t=%lu)"
311                            " axes_count=%d first=%d %d %d %d %d %d %d\n",
312                            names[i],
313                            (long unsigned) e->deviceid,
314                            e->type,
315                            e->x, e->y,
316                            e->device_state,
317                            b->button,
318                            (long unsigned) b->time,
319                            e->axes_count,
320                            e->first_axis,
321                            e->axis_data[0],
322                            e->axis_data[1],
323                            e->axis_data[2],
324                            e->axis_data[3], e->axis_data[4], e->axis_data[5]);
325                 }
326             }
327             ++total;
328 #if 0
329             /* Used to check motion history for
330              * extension devices. */
331             if (!(total % 10)) {
332                 XDeviceTimeCoord *tc;
333                 int n, m, a;
334                 struct timeval tv;
335                 unsigned long ms;
336 
337                 gettimeofday(&tv, NULL);
338                 ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
339                 tc = XGetDeviceMotionEvents(display, dev, ms - 1000, ms,
340                                             &n, &m, &a);
341                 printf("Got %d events of mode %s with %d axes\n",
342                        n, m == Absolute ? "Absolute" : "Relative", a);
343                 for (i = 0; i < n && i < 10; i++) {
344                     printf("  %d: %lu %d %d\n",
345                            i, tc[i].time, tc[i].data[0], tc[i].data[1]);
346                 }
347                 XFreeDeviceMotionEvents(tc);
348             }
349 #endif
350         }
351     }
352 
353     XCloseDisplay(display);
354     return 0;
355 }
356