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