xinput.c revision 41667cea
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 "[--root] <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 const char *forced_version; 206 int maj = 2, 207 min = 0; 208 209#if HAVE_XI22 210 min = 2; 211#elif HAVE_XI21 212 min = 1; 213#endif 214 215 forced_version = getenv("XINPUT_XI2_VERSION"); 216 if (forced_version) { 217 if (sscanf(forced_version, "%d.%d", &maj, &min) != 2) { 218 fprintf(stderr, "Invalid format of XINPUT_XI2_VERSION " 219 "environment variable. Need major.minor\n"); 220 exit(1); 221 } 222 printf("Overriding XI2 version to: %d.%d\n", maj, min); 223 } 224 225 XIQueryVersion(display, &maj, &min); 226 } 227#endif 228 229 return vers; 230} 231 232XDeviceInfo* 233find_device_info(Display *display, 234 char *name, 235 Bool only_extended) 236{ 237 XDeviceInfo *devices; 238 XDeviceInfo *found = NULL; 239 int loop; 240 int num_devices; 241 int len = strlen(name); 242 Bool is_id = True; 243 XID id = (XID)-1; 244 245 for(loop=0; loop<len; loop++) { 246 if (!isdigit(name[loop])) { 247 is_id = False; 248 break; 249 } 250 } 251 252 if (is_id) { 253 id = atoi(name); 254 } 255 256 devices = XListInputDevices(display, &num_devices); 257 258 for(loop=0; loop<num_devices; loop++) { 259 if ((!only_extended || (devices[loop].use >= IsXExtensionDevice)) && 260 ((!is_id && strcmp(devices[loop].name, name) == 0) || 261 (is_id && devices[loop].id == id))) { 262 if (found) { 263 fprintf(stderr, 264 "Warning: There are multiple devices named '%s'.\n" 265 "To ensure the correct one is selected, please use " 266 "the device ID instead.\n\n", name); 267 return NULL; 268 } else { 269 found = &devices[loop]; 270 } 271 } 272 } 273 return found; 274} 275 276#ifdef HAVE_XI2 277Bool is_pointer(int use) 278{ 279 return use == XIMasterPointer || use == XISlavePointer; 280} 281 282Bool is_keyboard(int use) 283{ 284 return use == XIMasterKeyboard || use == XISlaveKeyboard; 285} 286 287Bool device_matches(XIDeviceInfo *info, char *name) 288{ 289 if (strcmp(info->name, name) == 0) { 290 return True; 291 } 292 293 if (strncmp(name, "pointer:", strlen("pointer:")) == 0 && 294 strcmp(info->name, name + strlen("pointer:")) == 0 && 295 is_pointer(info->use)) { 296 return True; 297 } 298 299 if (strncmp(name, "keyboard:", strlen("keyboard:")) == 0 && 300 strcmp(info->name, name + strlen("keyboard:")) == 0 && 301 is_keyboard(info->use)) { 302 return True; 303 } 304 305 return False; 306} 307 308XIDeviceInfo* 309xi2_find_device_info(Display *display, char *name) 310{ 311 XIDeviceInfo *info; 312 XIDeviceInfo *found = NULL; 313 int ndevices; 314 Bool is_id = True; 315 int i, id = -1; 316 317 for(i = 0; i < strlen(name); i++) { 318 if (!isdigit(name[i])) { 319 is_id = False; 320 break; 321 } 322 } 323 324 if (is_id) { 325 id = atoi(name); 326 } 327 328 info = XIQueryDevice(display, XIAllDevices, &ndevices); 329 for(i = 0; i < ndevices; i++) 330 { 331 if (is_id ? info[i].deviceid == id : device_matches (&info[i], name)) { 332 if (found) { 333 fprintf(stderr, 334 "Warning: There are multiple devices matching '%s'.\n" 335 "To ensure the correct one is selected, please use " 336 "the device ID, or prefix the\ndevice name with " 337 "'pointer:' or 'keyboard:' as appropriate.\n\n", name); 338 XIFreeDeviceInfo(info); 339 return NULL; 340 } else { 341 found = &info[i]; 342 } 343 } 344 } 345 346 return found; 347} 348#endif 349 350static void 351usage(void) 352{ 353 entry *pdriver = drivers; 354 355 fprintf(stderr, "usage :\n"); 356 357 while(pdriver->func_name) { 358 fprintf(stderr, "\txinput %s %s\n", pdriver->func_name, 359 pdriver->arg_desc); 360 pdriver++; 361 } 362} 363 364int 365main(int argc, char * argv[]) 366{ 367 Display *display; 368 entry *driver = drivers; 369 char *func; 370 int event, error; 371 372 if (argc > 1) { 373 func = argv[1]; 374 while(func[0] == '-') func++; 375 } else { 376 func = "list"; 377 } 378 379 if (strcmp("version", func) == 0) { 380 return print_version(); 381 } 382 383 if (strcmp("help", func) == 0) { 384 usage(); 385 return 0; 386 } 387 388 display = XOpenDisplay(NULL); 389 390 if (display == NULL) { 391 fprintf(stderr, "Unable to connect to X server\n"); 392 goto out; 393 } 394 395 if (!XQueryExtension(display, "XInputExtension", &xi_opcode, &event, &error)) { 396 printf("X Input extension not available.\n"); 397 goto out; 398 } 399 400 if (!xinput_version(display)) { 401 fprintf(stderr, "%s extension not available\n", INAME); 402 goto out; 403 } 404 405 while(driver->func_name) { 406 if (strcmp(driver->func_name, func) == 0) { 407 int r = (*driver->func)(display, argc-2, argv+2, 408 driver->func_name, driver->arg_desc); 409 XSync(display, False); 410 XCloseDisplay(display); 411 return r; 412 } 413 driver++; 414 } 415 416 usage(); 417 418out: 419 if (display) 420 XCloseDisplay(display); 421 return EXIT_FAILURE; 422} 423 424/* end of xinput.c */ 425