property.c revision a570218a
1/* 2 * Copyright © 2007 Peter Hutterer 3 * Copyright © 2009 Red Hat, Inc. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 */ 24 25#include <ctype.h> 26#include <string.h> 27#include <stdlib.h> 28#include <stdint.h> 29#include <X11/Xatom.h> 30#include <X11/extensions/XIproto.h> 31 32#include "xinput.h" 33 34static Atom parse_atom(Display *dpy, char *name) { 35 Bool is_atom = True; 36 int i; 37 38 for (i = 0; name[i] != '\0'; i++) { 39 if (!isdigit(name[i])) { 40 is_atom = False; 41 break; 42 } 43 } 44 45 if (is_atom) 46 return atoi(name); 47 else 48 return XInternAtom(dpy, name, False); 49} 50 51static void 52print_property(Display *dpy, XDevice* dev, Atom property) 53{ 54 Atom act_type; 55 char *name; 56 int act_format; 57 unsigned long nitems, bytes_after; 58 unsigned char *data, *ptr; 59 int j, done = False, size = 0; 60 61 name = XGetAtomName(dpy, property); 62 printf("\t%s (%ld):\t", name, property); 63 XFree(name); 64 65 if (XGetDeviceProperty(dpy, dev, property, 0, 1000, False, 66 AnyPropertyType, &act_type, &act_format, 67 &nitems, &bytes_after, &data) == Success) 68 { 69 Atom float_atom = XInternAtom(dpy, "FLOAT", True); 70 71 ptr = data; 72 73 if (nitems == 0) 74 printf("<no items>"); 75 76 switch(act_format) 77 { 78 case 8: size = sizeof(char); break; 79 case 16: size = sizeof(short); break; 80 case 32: size = sizeof(long); break; 81 } 82 83 for (j = 0; j < nitems; j++) 84 { 85 switch(act_type) 86 { 87 case XA_INTEGER: 88 switch(act_format) 89 { 90 case 8: 91 printf("%d", *((char*)ptr)); 92 break; 93 case 16: 94 printf("%d", *((short*)ptr)); 95 break; 96 case 32: 97 printf("%ld", *((long*)ptr)); 98 break; 99 } 100 break; 101 case XA_CARDINAL: 102 switch(act_format) 103 { 104 case 8: 105 printf("%u", *((unsigned char*)ptr)); 106 break; 107 case 16: 108 printf("%u", *((unsigned short*)ptr)); 109 break; 110 case 32: 111 printf("%lu", *((unsigned long*)ptr)); 112 break; 113 } 114 break; 115 case XA_STRING: 116 if (act_format != 8) 117 { 118 printf("Unknown string format.\n"); 119 done = True; 120 break; 121 } 122 printf("\"%s\"", ptr); 123 j += strlen((char*)ptr); /* The loop's j++ jumps over the 124 terminating 0 */ 125 ptr += strlen((char*)ptr); /* ptr += size below jumps over 126 the terminating 0 */ 127 break; 128 case XA_ATOM: 129 { 130 Atom a = *(Atom*)ptr; 131 name = (a) ? XGetAtomName(dpy, a) : NULL; 132 printf("\"%s\" (%d)", name ? name : "None", (int)a); 133 XFree(name); 134 break; 135 } 136 default: 137 if (float_atom != None && act_type == float_atom) 138 { 139 printf("%f", *((float*)ptr)); 140 break; 141 } 142 143 name = XGetAtomName(dpy, act_type); 144 printf("\t... of unknown type '%s'\n", name); 145 XFree(name); 146 done = True; 147 break; 148 } 149 150 ptr += size; 151 152 if (done == True) 153 break; 154 if (j < nitems - 1) 155 printf(", "); 156 } 157 printf("\n"); 158 XFree(data); 159 } else 160 printf("\tFetch failure\n"); 161 162} 163 164static int 165list_props_xi1(Display *dpy, int argc, char** argv, char* name, char *desc) 166{ 167 XDeviceInfo *info; 168 XDevice *dev; 169 int i; 170 int nprops; 171 Atom *props; 172 int rc = EXIT_SUCCESS; 173 174 if (argc == 0) 175 { 176 fprintf(stderr, "Usage: xinput %s %s\n", name, desc); 177 return EXIT_FAILURE; 178 } 179 180 for (i = 0; i < argc; i++) 181 { 182 info = find_device_info(dpy, argv[i], False); 183 if (!info) 184 { 185 fprintf(stderr, "unable to find device '%s'\n", argv[i]); 186 rc = EXIT_FAILURE; 187 continue; 188 } 189 190 dev = XOpenDevice(dpy, info->id); 191 if (!dev) 192 { 193 fprintf(stderr, "unable to open device '%s'\n", info->name); 194 rc = EXIT_FAILURE; 195 continue; 196 } 197 198 props = XListDeviceProperties(dpy, dev, &nprops); 199 if (!nprops) 200 { 201 printf("Device '%s' does not report any properties.\n", info->name); 202 continue; 203 } 204 205 printf("Device '%s':\n", info->name); 206 while(nprops--) 207 { 208 print_property(dpy, dev, props[nprops]); 209 } 210 211 XFree(props); 212 XCloseDevice(dpy, dev); 213 } 214 return rc; 215} 216 217 218int watch_props(Display *dpy, int argc, char** argv, char* n, char *desc) 219{ 220 XDevice *dev; 221 XDeviceInfo *info; 222 XEvent ev; 223 XDevicePropertyNotifyEvent *dpev; 224 char *name; 225 int type_prop; 226 XEventClass cls_prop; 227 228 if (list_props(dpy, argc, argv, n, desc) != EXIT_SUCCESS) 229 return EXIT_FAILURE; 230 231 info = find_device_info(dpy, argv[0], False); 232 if (!info) 233 { 234 fprintf(stderr, "unable to find device '%s'\n", argv[0]); 235 return EXIT_FAILURE; 236 } 237 238 dev = XOpenDevice(dpy, info->id); 239 if (!dev) 240 { 241 fprintf(stderr, "unable to open device '%s'\n", info->name); 242 return EXIT_FAILURE; 243 } 244 245 DevicePropertyNotify(dev, type_prop, cls_prop); 246 XSelectExtensionEvent(dpy, DefaultRootWindow(dpy), &cls_prop, 1); 247 248 while(1) 249 { 250 XNextEvent(dpy, &ev); 251 252 dpev = (XDevicePropertyNotifyEvent*)&ev; 253 if (dpev->type != type_prop) 254 continue; 255 256 name = XGetAtomName(dpy, dpev->atom); 257 printf("Property '%s' changed.\n", name); 258 XFree(name); 259 print_property(dpy, dev, dpev->atom); 260 } 261 262 XCloseDevice(dpy, dev); 263} 264 265static int 266delete_prop_xi1(Display *dpy, int argc, char** argv, char* n, char *desc) 267{ 268 XDevice *dev; 269 XDeviceInfo *info; 270 char *name; 271 Atom prop; 272 273 info = find_device_info(dpy, argv[0], False); 274 if (!info) 275 { 276 fprintf(stderr, "unable to find device '%s'\n", argv[0]); 277 return EXIT_FAILURE; 278 } 279 280 dev = XOpenDevice(dpy, info->id); 281 if (!dev) 282 { 283 fprintf(stderr, "unable to open device '%s'\n", info->name); 284 return EXIT_FAILURE; 285 } 286 287 name = argv[1]; 288 289 prop = parse_atom(dpy, name); 290 291 XDeleteDeviceProperty(dpy, dev, prop); 292 293 XCloseDevice(dpy, dev); 294 return EXIT_SUCCESS; 295} 296 297static int 298do_set_prop_xi1(Display *dpy, Atom type, int format, int argc, char **argv, char *n, char *desc) 299{ 300 XDeviceInfo *info; 301 XDevice *dev; 302 Atom prop; 303 Atom old_type; 304 char *name; 305 int i; 306 Atom float_atom; 307 int old_format, nelements = 0; 308 unsigned long act_nitems, bytes_after; 309 char *endptr; 310 union { 311 unsigned char *c; 312 short *s; 313 long *l; 314 Atom *a; 315 } data; 316 317 if (argc < 3) 318 { 319 fprintf(stderr, "Usage: xinput %s %s\n", n, desc); 320 return EXIT_FAILURE; 321 } 322 323 info = find_device_info(dpy, argv[0], False); 324 if (!info) 325 { 326 fprintf(stderr, "unable to find device '%s'\n", argv[0]); 327 return EXIT_FAILURE; 328 } 329 330 dev = XOpenDevice(dpy, info->id); 331 if (!dev) 332 { 333 fprintf(stderr, "unable to open device '%s'\n", argv[0]); 334 return EXIT_FAILURE; 335 } 336 337 name = argv[1]; 338 339 prop = parse_atom(dpy, name); 340 341 if (prop == None) { 342 fprintf(stderr, "invalid property '%s'\n", name); 343 return EXIT_FAILURE; 344 } 345 346 float_atom = XInternAtom(dpy, "FLOAT", False); 347 348 nelements = argc - 2; 349 if (type == None || format == 0) { 350 if (XGetDeviceProperty(dpy, dev, prop, 0, 0, False, AnyPropertyType, 351 &old_type, &old_format, &act_nitems, 352 &bytes_after, &data.c) != Success) { 353 fprintf(stderr, "failed to get property type and format for '%s'\n", 354 name); 355 return EXIT_FAILURE; 356 } else { 357 if (type == None) 358 type = old_type; 359 if (format == 0) 360 format = old_format; 361 } 362 363 XFree(data.c); 364 } 365 366 if (type == None) { 367 fprintf(stderr, "property '%s' doesn't exist, you need to specify " 368 "its type and format\n", name); 369 return EXIT_FAILURE; 370 } 371 372 data.c = calloc(nelements, sizeof(long)); 373 374 for (i = 0; i < nelements; i++) 375 { 376 if (type == XA_INTEGER || type == XA_CARDINAL) { 377 switch (format) 378 { 379 case 8: 380 data.c[i] = atoi(argv[2 + i]); 381 break; 382 case 16: 383 data.s[i] = atoi(argv[2 + i]); 384 break; 385 case 32: 386 data.l[i] = atoi(argv[2 + i]); 387 break; 388 default: 389 fprintf(stderr, "unexpected size for property '%s'", name); 390 return EXIT_FAILURE; 391 } 392 } else if (type == float_atom) { 393 if (format != 32) { 394 fprintf(stderr, "unexpected format %d for property '%s'\n", 395 format, name); 396 return EXIT_FAILURE; 397 } 398 *(float *)(data.l + i) = strtod(argv[2 + i], &endptr); 399 if (endptr == argv[2 + i]) { 400 fprintf(stderr, "argument '%s' could not be parsed\n", argv[2 + i]); 401 return EXIT_FAILURE; 402 } 403 } else if (type == XA_ATOM) { 404 if (format != 32) { 405 fprintf(stderr, "unexpected format %d for property '%s'\n", 406 format, name); 407 return EXIT_FAILURE; 408 } 409 data.a[i] = parse_atom(dpy, argv[2 + i]); 410 } else { 411 fprintf(stderr, "unexpected type for property '%s'\n", name); 412 return EXIT_FAILURE; 413 } 414 } 415 416 XChangeDeviceProperty(dpy, dev, prop, type, format, PropModeReplace, 417 data.c, nelements); 418 free(data.c); 419 XCloseDevice(dpy, dev); 420 return EXIT_SUCCESS; 421} 422 423#if HAVE_XI2 424static void 425print_property_xi2(Display *dpy, int deviceid, Atom property) 426{ 427 Atom act_type; 428 char *name; 429 int act_format; 430 unsigned long nitems, bytes_after; 431 unsigned char *data, *ptr; 432 int j, done = False; 433 434 name = XGetAtomName(dpy, property); 435 printf("\t%s (%ld):\t", name, property); 436 XFree(name); 437 438 if (XIGetProperty(dpy, deviceid, property, 0, 1000, False, 439 AnyPropertyType, &act_type, &act_format, 440 &nitems, &bytes_after, &data) == Success) 441 { 442 Atom float_atom = XInternAtom(dpy, "FLOAT", True); 443 444 ptr = data; 445 446 if (nitems == 0) 447 printf("<no items>"); 448 449 for (j = 0; j < nitems; j++) 450 { 451 switch(act_type) 452 { 453 case XA_INTEGER: 454 switch(act_format) 455 { 456 case 8: 457 printf("%d", *((int8_t*)ptr)); 458 break; 459 case 16: 460 printf("%d", *((int16_t*)ptr)); 461 break; 462 case 32: 463 printf("%d", *((int32_t*)ptr)); 464 break; 465 } 466 break; 467 case XA_CARDINAL: 468 switch(act_format) 469 { 470 case 8: 471 printf("%u", *((uint8_t*)ptr)); 472 break; 473 case 16: 474 printf("%u", *((uint16_t*)ptr)); 475 break; 476 case 32: 477 printf("%u", *((uint32_t*)ptr)); 478 break; 479 } 480 break; 481 case XA_STRING: 482 if (act_format != 8) 483 { 484 printf("Unknown string format.\n"); 485 done = True; 486 break; 487 } 488 printf("\"%s\"", ptr); 489 j += strlen((char*)ptr); /* The loop's j++ jumps over the 490 terminating 0 */ 491 ptr += strlen((char*)ptr); /* ptr += size below jumps over 492 the terminating 0 */ 493 break; 494 case XA_ATOM: 495 { 496 Atom a = *(uint32_t*)ptr; 497 name = (a) ? XGetAtomName(dpy, a) : NULL; 498 printf("\"%s\" (%ld)", name ? name : "None", a); 499 XFree(name); 500 break; 501 } 502 break; 503 default: 504 if (float_atom != None && act_type == float_atom) 505 { 506 printf("%f", *((float*)ptr)); 507 break; 508 } 509 510 name = XGetAtomName(dpy, act_type); 511 printf("\t... of unknown type %s\n", name); 512 XFree(name); 513 done = True; 514 break; 515 } 516 517 ptr += act_format/8; 518 519 if (done == True) 520 break; 521 if (j < nitems - 1) 522 printf(", "); 523 } 524 printf("\n"); 525 XFree(data); 526 } else 527 printf("\tFetch failure\n"); 528 529} 530 531static int 532list_props_xi2(Display *dpy, int argc, char** argv, char* name, char *desc) 533{ 534 XIDeviceInfo *info; 535 int i; 536 int nprops; 537 Atom *props; 538 int rc = EXIT_SUCCESS; 539 540 if (argc == 0) 541 { 542 fprintf(stderr, "Usage: xinput %s %s\n", name, desc); 543 return EXIT_FAILURE; 544 } 545 546 for (i = 0; i < argc; i++) 547 { 548 info = xi2_find_device_info(dpy, argv[i]); 549 if (!info) 550 { 551 fprintf(stderr, "unable to find device %s\n", argv[i]); 552 rc = EXIT_FAILURE; 553 continue; 554 } 555 556 props = XIListProperties(dpy, info->deviceid, &nprops); 557 if (!nprops) 558 { 559 printf("Device '%s' does not report any properties.\n", info->name); 560 continue; 561 } 562 563 printf("Device '%s':\n", info->name); 564 while(nprops--) 565 { 566 print_property_xi2(dpy, info->deviceid, props[nprops]); 567 } 568 569 XFree(props); 570 } 571 return rc; 572} 573 574static int 575delete_prop_xi2(Display *dpy, int argc, char** argv, char* n, char *desc) 576{ 577 XIDeviceInfo *info; 578 char *name; 579 Atom prop; 580 581 info = xi2_find_device_info(dpy, argv[0]); 582 if (!info) 583 { 584 fprintf(stderr, "unable to find device %s\n", argv[0]); 585 return EXIT_FAILURE; 586 } 587 588 name = argv[1]; 589 590 prop = parse_atom(dpy, name); 591 592 XIDeleteProperty(dpy, info->deviceid, prop); 593 594 return EXIT_SUCCESS; 595} 596 597static int 598do_set_prop_xi2(Display *dpy, Atom type, int format, int argc, char **argv, char *n, char *desc) 599{ 600 XIDeviceInfo *info; 601 Atom prop; 602 Atom old_type; 603 char *name; 604 int i; 605 Atom float_atom; 606 int old_format, nelements = 0; 607 unsigned long act_nitems, bytes_after; 608 char *endptr; 609 union { 610 unsigned char *c; 611 int16_t *s; 612 int32_t *l; 613 } data = { NULL }; 614 int rc = EXIT_FAILURE; 615 616 if (argc < 3) 617 { 618 fprintf(stderr, "Usage: xinput %s %s\n", n, desc); 619 goto out; 620 } 621 622 info = xi2_find_device_info(dpy, argv[0]); 623 if (!info) 624 { 625 fprintf(stderr, "unable to find device %s\n", argv[0]); 626 goto out; 627 } 628 629 name = argv[1]; 630 631 prop = parse_atom(dpy, name); 632 633 if (prop == None) { 634 fprintf(stderr, "invalid property '%s'\n", name); 635 goto out; 636 } 637 638 float_atom = XInternAtom(dpy, "FLOAT", False); 639 640 nelements = argc - 2; 641 if (type == None || format == 0) { 642 if (XIGetProperty(dpy, info->deviceid, prop, 0, 0, False, 643 AnyPropertyType, &old_type, &old_format, &act_nitems, 644 &bytes_after, &data.c) != Success) { 645 fprintf(stderr, "failed to get property type and format for '%s'\n", 646 name); 647 goto out; 648 } else { 649 if (type == None) 650 type = old_type; 651 if (format == 0) 652 format = old_format; 653 } 654 655 XFree(data.c); 656 } 657 658 if (type == None) { 659 fprintf(stderr, "property '%s' doesn't exist, you need to specify " 660 "its type and format\n", name); 661 goto out; 662 } 663 664 data.c = calloc(nelements, sizeof(int32_t)); 665 666 for (i = 0; i < nelements; i++) 667 { 668 if (type == XA_INTEGER || type == XA_CARDINAL) { 669 switch (format) 670 { 671 case 8: 672 data.c[i] = atoi(argv[2 + i]); 673 break; 674 case 16: 675 data.s[i] = atoi(argv[2 + i]); 676 break; 677 case 32: 678 data.l[i] = atoi(argv[2 + i]); 679 break; 680 default: 681 fprintf(stderr, "unexpected size for property %s", name); 682 goto out; 683 } 684 } else if (type == float_atom) { 685 if (format != 32) { 686 fprintf(stderr, "unexpected format %d for property '%s'\n", 687 format, name); 688 goto out; 689 } 690 *(float *)(data.l + i) = strtod(argv[2 + i], &endptr); 691 if (endptr == argv[2 + i]) { 692 fprintf(stderr, "argument %s could not be parsed\n", argv[2 + i]); 693 goto out; 694 } 695 } else if (type == XA_ATOM) { 696 if (format != 32) { 697 fprintf(stderr, "unexpected format %d for property '%s'\n", 698 format, name); 699 goto out; 700 } 701 data.l[i] = parse_atom(dpy, argv[2 + i]); 702 } else { 703 fprintf(stderr, "unexpected type for property '%s'\n", name); 704 goto out; 705 } 706 } 707 708 XIChangeProperty(dpy, info->deviceid, prop, type, format, PropModeReplace, 709 data.c, nelements); 710 rc = EXIT_SUCCESS; 711out: 712 free(data.c); 713 return rc; 714} 715#endif 716 717int list_props(Display *display, int argc, char *argv[], char *name, 718 char *desc) 719{ 720#if HAVE_XI2 721 if (xinput_version(display) == XI_2_Major) 722 return list_props_xi2(display, argc, argv, name, desc); 723#endif 724 return list_props_xi1(display, argc, argv, name, desc); 725 726} 727 728int delete_prop(Display *display, int argc, char *argv[], char *name, 729 char *desc) 730{ 731#if HAVE_XI2 732 if (xinput_version(display) == XI_2_Major) 733 return delete_prop_xi2(display, argc, argv, name, desc); 734#endif 735 return delete_prop_xi1(display, argc, argv, name, desc); 736 737} 738 739static int 740do_set_prop(Display *display, Atom type, int format, int argc, char *argv[], char *name, char *desc) 741{ 742#if HAVE_XI2 743 if (xinput_version(display) == XI_2_Major) 744 return do_set_prop_xi2(display, type, format, argc, argv, name, desc); 745#endif 746 return do_set_prop_xi1(display, type, format, argc, argv, name, desc); 747} 748 749int 750set_atom_prop(Display *dpy, int argc, char** argv, char* n, char *desc) 751{ 752 return do_set_prop(dpy, XA_ATOM, 32, argc, argv, n, desc); 753} 754 755int 756set_int_prop(Display *dpy, int argc, char** argv, char* n, char *desc) 757{ 758 int i; 759 int format; 760 761 if (argc < 3) 762 { 763 fprintf(stderr, "Usage: xinput %s %s\n", n, desc); 764 return EXIT_FAILURE; 765 } 766 767 format = atoi(argv[2]); 768 if (format != 8 && format != 16 && format != 32) 769 { 770 fprintf(stderr, "Invalid format %d\n", format); 771 return EXIT_FAILURE; 772 } 773 774 for (i = 3; i < argc; i++) 775 argv[i - 1] = argv[i]; 776 777 return do_set_prop(dpy, XA_INTEGER, format, argc - 1, argv, n, desc); 778} 779 780int 781set_float_prop(Display *dpy, int argc, char** argv, char* n, char *desc) 782{ 783 Atom float_atom = XInternAtom(dpy, "FLOAT", False); 784 785 if (sizeof(float) != 4) 786 { 787 fprintf(stderr, "sane FP required\n"); 788 return EXIT_FAILURE; 789 } 790 791 return do_set_prop(dpy, float_atom, 32, argc, argv, n, desc); 792} 793 794int set_prop(Display *display, int argc, char *argv[], char *name, 795 char *desc) 796{ 797 Atom type = None; 798 int format = 0; 799 int i = 0, j; 800 801 while (i < argc) { 802 char *option = strchr(argv[i], '='); 803 /* skip non-option arguments */ 804 if (strncmp(argv[i], "--", 2) || !option) { 805 i++; 806 continue; 807 } 808 809 if (!strncmp(argv[i], "--type=", strlen("--type="))) { 810 if (!strcmp(option + 1, "int")) { 811 type = XA_INTEGER; 812 } else if (!strcmp(option + 1, "float")) { 813 type = XInternAtom(display, "FLOAT", False); 814 format = 32; 815 } else if (!strcmp(option + 1, "atom")) { 816 type = XA_ATOM; 817 format = 32; 818 } else { 819 fprintf(stderr, "unknown property type %s\n", option + 1); 820 return EXIT_FAILURE; 821 } 822 } else if (!strncmp(argv[i], "--format=", strlen("--format="))) { 823 format = atoi(option + 1); 824 if (format != 8 && format != 16 && format != 32) { 825 fprintf(stderr, "invalid property format '%s'\n", option + 1); 826 return EXIT_FAILURE; 827 } 828 } else { 829 fprintf(stderr, "invalid option '%s'\n", argv[i]); 830 return EXIT_FAILURE; 831 } 832 833 for (j = i; j + 1 < argc; j++) 834 argv[j] = argv[j + 1]; 835 argc--; 836 } 837 838 return do_set_prop(display, type, format, argc, argv, name, desc); 839} 840 841int disable(Display *display, int argc, char *argv[], char *name, char *desc) 842{ 843 char *new_argv[3] = { NULL, "Device Enabled", "0" }; 844 845 if (argc != 1) { 846 fprintf(stderr, "Usage: xinput %s %s\n", name, desc); 847 return EXIT_FAILURE; 848 } 849 850 new_argv[0] = argv[0]; 851 852 return set_prop(display, 3, new_argv, name, desc); 853} 854 855int enable(Display *display, int argc, char *argv[], char *name, char *desc) 856{ 857 char *new_argv[3] = { NULL, "Device Enabled", "1" }; 858 859 if (argc != 1) { 860 fprintf(stderr, "Usage: xinput %s %s\n", name, desc); 861 return EXIT_FAILURE; 862 } 863 864 new_argv[0] = argv[0]; 865 866 return set_prop(display, 3, new_argv, name, desc); 867} 868