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