xinput.c revision 1b180c10
1/* 2 * Copyright 1996 by Frederic Lepied, France. <Frederic.Lepied@sugix.frmug.org> 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that 7 * copyright notice and this permission notice appear in supporting 8 * documentation, and that the name of the authors not be used in 9 * advertising or publicity pertaining to distribution of the software without 10 * specific, written prior permission. The authors make no 11 * representations about the suitability of this software for any purpose. It 12 * is provided "as is" without express or implied warranty. 13 * 14 * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20 * PERFORMANCE OF THIS SOFTWARE. 21 * 22 */ 23 24#include "xinput.h" 25#include <ctype.h> 26#include <string.h> 27 28int xi_opcode; 29 30typedef int (*prog)(Display* display, int argc, char *argv[], 31 char *prog_name, char *prog_desc); 32 33typedef struct 34{ 35 char *func_name; 36 char *arg_desc; 37 prog func; 38} entry; 39 40static entry drivers[] = 41{ 42 {"get-feedbacks", 43 "<device name>", 44 get_feedbacks 45 }, 46 {"set-ptr-feedback", 47 "<device name> <threshold> <num> <denom>", 48 set_ptr_feedback 49 }, 50 {"set-integer-feedback", 51 "<device name> <feedback id> <value>", 52 set_integer_feedback 53 }, 54 {"get-button-map", 55 "<device name>", 56 get_button_map 57 }, 58 {"set-button-map", 59 "<device name> <map button 1> [<map button 2> [...]]", 60 set_button_map 61 }, 62 {"set-pointer", 63 "<device name> [<x index> <y index>]", 64 set_pointer 65 }, 66 {"set-mode", 67 "<device name> ABSOLUTE|RELATIVE", 68 set_mode 69 }, 70 {"list", 71 "[--short || --long || --name-only || --id-only] [<device name>...]", 72 list 73 }, 74 {"query-state", 75 "<device name>", 76 query_state 77 }, 78 {"test", 79 "[-proximity] <device name>", 80 test 81 }, 82#if HAVE_XI2 83 { "create-master", 84 "<id> [<sendCore (dflt:1)>] [<enable (dflt:1)>]", 85 create_master 86 }, 87 { "remove-master", 88 "<id> [Floating|AttachToMaster (dflt:Floating)] [<returnPointer>] [<returnKeyboard>]", 89 remove_master 90 }, 91 { "reattach", 92 "<id> <master>", 93 change_attachment 94 }, 95 { "float", 96 "<id>", 97 float_device 98 }, 99 { "set-cp", 100 "<window> <device>", 101 set_clientpointer 102 }, 103 { "test-xi2", 104 "<device>", 105 test_xi2, 106 }, 107 { "map-to-output", 108 "<device> <output name>", 109 map_to_output, 110 }, 111#endif 112 { "list-props", 113 "<device> [<device> ...]", 114 list_props 115 }, 116 { "set-int-prop", 117 "<device> <property> <format (8, 16, 32)> <val> [<val> ...]", 118 set_int_prop 119 }, 120 { "set-float-prop", 121 "<device> <property> <val> [<val> ...]", 122 set_float_prop 123 }, 124 { "set-atom-prop", 125 "<device> <property> <val> [<val> ...]", 126 set_atom_prop 127 }, 128 { "watch-props", 129 "<device>", 130 watch_props 131 }, 132 { "delete-prop", 133 "<device> <property>", 134 delete_prop 135 }, 136 { "set-prop", 137 "<device> [--type=atom|float|int] [--format=8|16|32] <property> <val> [<val> ...]", 138 set_prop 139 }, 140 { 141 "disable", 142 "<device>", 143 disable, 144 }, 145 { 146 "enable", 147 "<device>", 148 enable, 149 }, 150 {NULL, NULL, NULL 151 } 152}; 153 154static const char version_id[] = VERSION; 155 156static int 157print_version(void) 158{ 159 XExtensionVersion *version; 160 Display *display; 161 162 printf("xinput version %s\n", version_id); 163 164 display = XOpenDisplay(NULL); 165 166 printf("XI version on server: "); 167 168 if (display == NULL) 169 printf("Failed to open display.\n"); 170 else { 171 version = XGetExtensionVersion(display, INAME); 172 if (!version || (version == (XExtensionVersion*) NoSuchExtension)) 173 printf(" Extension not supported.\n"); 174 else { 175 printf("%d.%d\n", version->major_version, 176 version->minor_version); 177 XFree(version); 178 return 0; 179 } 180 } 181 182 return 1; 183} 184 185int 186xinput_version(Display *display) 187{ 188 XExtensionVersion *version; 189 static int vers = -1; 190 191 if (vers != -1) 192 return vers; 193 194 version = XGetExtensionVersion(display, INAME); 195 196 if (version && (version != (XExtensionVersion*) NoSuchExtension)) { 197 vers = version->major_version; 198 XFree(version); 199 } 200 201#if HAVE_XI2 202 /* Announce our supported version so the server treats us correctly. */ 203 if (vers >= XI_2_Major) 204 { 205 int maj = 2, 206 min = 0; 207 208#if HAVE_XI21 209 min = 1; 210#elif HAVE_XI22 211 min = 2; 212#endif 213 214 XIQueryVersion(display, &maj, &min); 215 } 216#endif 217 218 return vers; 219} 220 221XDeviceInfo* 222find_device_info(Display *display, 223 char *name, 224 Bool only_extended) 225{ 226 XDeviceInfo *devices; 227 XDeviceInfo *found = NULL; 228 int loop; 229 int num_devices; 230 int len = strlen(name); 231 Bool is_id = True; 232 XID id = (XID)-1; 233 234 for(loop=0; loop<len; loop++) { 235 if (!isdigit(name[loop])) { 236 is_id = False; 237 break; 238 } 239 } 240 241 if (is_id) { 242 id = atoi(name); 243 } 244 245 devices = XListInputDevices(display, &num_devices); 246 247 for(loop=0; loop<num_devices; loop++) { 248 if ((!only_extended || (devices[loop].use >= IsXExtensionDevice)) && 249 ((!is_id && strcmp(devices[loop].name, name) == 0) || 250 (is_id && devices[loop].id == id))) { 251 if (found) { 252 fprintf(stderr, 253 "Warning: There are multiple devices named '%s'.\n" 254 "To ensure the correct one is selected, please use " 255 "the device ID instead.\n\n", name); 256 return NULL; 257 } else { 258 found = &devices[loop]; 259 } 260 } 261 } 262 return found; 263} 264 265#ifdef HAVE_XI2 266Bool is_pointer(int use) 267{ 268 return use == XIMasterPointer || use == XISlavePointer; 269} 270 271Bool is_keyboard(int use) 272{ 273 return use == XIMasterKeyboard || use == XISlaveKeyboard; 274} 275 276Bool device_matches(XIDeviceInfo *info, char *name) 277{ 278 if (strcmp(info->name, name) == 0) { 279 return True; 280 } 281 282 if (strncmp(name, "pointer:", strlen("pointer:")) == 0 && 283 strcmp(info->name, name + strlen("pointer:")) == 0 && 284 is_pointer(info->use)) { 285 return True; 286 } 287 288 if (strncmp(name, "keyboard:", strlen("keyboard:")) == 0 && 289 strcmp(info->name, name + strlen("keyboard:")) == 0 && 290 is_keyboard(info->use)) { 291 return True; 292 } 293 294 return False; 295} 296 297XIDeviceInfo* 298xi2_find_device_info(Display *display, char *name) 299{ 300 XIDeviceInfo *info; 301 XIDeviceInfo *found = NULL; 302 int ndevices; 303 Bool is_id = True; 304 int i, id = -1; 305 306 for(i = 0; i < strlen(name); i++) { 307 if (!isdigit(name[i])) { 308 is_id = False; 309 break; 310 } 311 } 312 313 if (is_id) { 314 id = atoi(name); 315 } 316 317 info = XIQueryDevice(display, XIAllDevices, &ndevices); 318 for(i = 0; i < ndevices; i++) 319 { 320 if (is_id ? info[i].deviceid == id : device_matches (&info[i], name)) { 321 if (found) { 322 fprintf(stderr, 323 "Warning: There are multiple devices matching '%s'.\n" 324 "To ensure the correct one is selected, please use " 325 "the device ID, or prefix the\ndevice name with " 326 "'pointer:' or 'keyboard:' as appropriate.\n\n", name); 327 XIFreeDeviceInfo(info); 328 return NULL; 329 } else { 330 found = &info[i]; 331 } 332 } 333 } 334 335 return found; 336} 337#endif 338 339static void 340usage(void) 341{ 342 entry *pdriver = drivers; 343 344 fprintf(stderr, "usage :\n"); 345 346 while(pdriver->func_name) { 347 fprintf(stderr, "\txinput %s %s\n", pdriver->func_name, 348 pdriver->arg_desc); 349 pdriver++; 350 } 351} 352 353int 354main(int argc, char * argv[]) 355{ 356 Display *display; 357 entry *driver = drivers; 358 char *func; 359 int event, error; 360 361 if (argc > 1) { 362 func = argv[1]; 363 while(func[0] == '-') func++; 364 } else { 365 func = "list"; 366 } 367 368 if (strcmp("version", func) == 0) { 369 return print_version(); 370 } 371 372 if (strcmp("help", func) == 0) { 373 usage(); 374 return 0; 375 } 376 377 display = XOpenDisplay(NULL); 378 379 if (display == NULL) { 380 fprintf(stderr, "Unable to connect to X server\n"); 381 goto out; 382 } 383 384 if (!XQueryExtension(display, "XInputExtension", &xi_opcode, &event, &error)) { 385 printf("X Input extension not available.\n"); 386 goto out; 387 } 388 389 if (!xinput_version(display)) { 390 fprintf(stderr, "%s extension not available\n", INAME); 391 goto out; 392 } 393 394 while(driver->func_name) { 395 if (strcmp(driver->func_name, func) == 0) { 396 int r = (*driver->func)(display, argc-2, argv+2, 397 driver->func_name, driver->arg_desc); 398 XSync(display, False); 399 XCloseDisplay(display); 400 return r; 401 } 402 driver++; 403 } 404 405 usage(); 406 407out: 408 if (display) 409 XCloseDisplay(display); 410 return EXIT_FAILURE; 411} 412 413/* end of xinput.c */ 414