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 
parse_atom(Display * dpy,char * name)34 static 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 
51 static void
print_property(Display * dpy,XDevice * dev,Atom property)52 print_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 
164 static int
list_props_xi1(Display * dpy,int argc,char ** argv,char * name,char * desc)165 list_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 
watch_props(Display * dpy,int argc,char ** argv,char * n,char * desc)218 int 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 
265 static int
delete_prop_xi1(Display * dpy,int argc,char ** argv,char * n,char * desc)266 delete_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 
297 static int
do_set_prop_xi1(Display * dpy,Atom type,int format,int argc,char ** argv,char * n,char * desc)298 do_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
424 static void
print_property_xi2(Display * dpy,int deviceid,Atom property)425 print_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 
531 static int
list_props_xi2(Display * dpy,int argc,char ** argv,char * name,char * desc)532 list_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 
574 static int
delete_prop_xi2(Display * dpy,int argc,char ** argv,char * n,char * desc)575 delete_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 
597 static int
do_set_prop_xi2(Display * dpy,Atom type,int format,int argc,char ** argv,char * n,char * desc)598 do_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;
711 out:
712     free(data.c);
713     return rc;
714 }
715 #endif
716 
list_props(Display * display,int argc,char * argv[],char * name,char * desc)717 int 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 
delete_prop(Display * display,int argc,char * argv[],char * name,char * desc)728 int 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 
739 static int
do_set_prop(Display * display,Atom type,int format,int argc,char * argv[],char * name,char * desc)740 do_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 
749 int
set_atom_prop(Display * dpy,int argc,char ** argv,char * n,char * desc)750 set_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 
755 int
set_int_prop(Display * dpy,int argc,char ** argv,char * n,char * desc)756 set_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 
780 int
set_float_prop(Display * dpy,int argc,char ** argv,char * n,char * desc)781 set_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 
set_prop(Display * display,int argc,char * argv[],char * name,char * desc)794 int 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 
disable(Display * display,int argc,char * argv[],char * name,char * desc)841 int 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 
enable(Display * display,int argc,char * argv[],char * name,char * desc)855 int 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