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