2 * Copyright © 2007 Peter Hutterer
3 * Copyright © 2009 Red Hat, Inc.
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:
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
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.
29 #include <X11/Xatom.h>
30 #include <X11/extensions/XIproto.h>
34 static Atom
parse_atom(Display
*dpy
, char *name
) {
38 for (i
= 0; name
[i
] != '\0'; i
++) {
39 if (!isdigit(name
[i
])) {
48 return XInternAtom(dpy
, name
, False
);
52 print_property(Display
*dpy
, XDevice
* dev
, Atom property
)
57 unsigned long nitems
, bytes_after
;
58 unsigned char *data
, *ptr
;
59 int j
, done
= False
, size
= 0;
61 name
= XGetAtomName(dpy
, property
);
62 printf("\t%s (%ld):\t", name
, property
);
64 if (XGetDeviceProperty(dpy
, dev
, property
, 0, 1000, False
,
65 AnyPropertyType
, &act_type
, &act_format
,
66 &nitems
, &bytes_after
, &data
) == Success
)
68 Atom float_atom
= XInternAtom(dpy
, "FLOAT", True
);
77 case 8: size
= sizeof(char); break;
78 case 16: size
= sizeof(short); break;
79 case 32: size
= sizeof(long); break;
82 for (j
= 0; j
< nitems
; j
++)
90 printf("%d", *((char*)ptr
));
93 printf("%d", *((short*)ptr
));
96 printf("%ld", *((long*)ptr
));
104 printf("%u", *((unsigned char*)ptr
));
107 printf("%u", *((unsigned short*)ptr
));
110 printf("%lu", *((unsigned long*)ptr
));
117 printf("Unknown string format.\n");
121 printf("\"%s\"", ptr
);
122 j
+= strlen((char*)ptr
); /* The loop's j++ jumps over the
124 ptr
+= strlen((char*)ptr
); /* ptr += size below jumps over
129 Atom a
= *(Atom
*)ptr
;
130 printf("\"%s\" (%d)",
131 (a
) ? XGetAtomName(dpy
, a
) : "None",
136 if (float_atom
!= None
&& act_type
== float_atom
)
138 printf("%f", *((float*)ptr
));
142 printf("\t... of unknown type '%s'\n",
143 XGetAtomName(dpy
, act_type
));
158 printf("\tFetch failure\n");
163 list_props_xi1(Display
*dpy
, int argc
, char** argv
, char* name
, char *desc
)
173 fprintf(stderr
, "Usage: xinput %s %s\n", name
, desc
);
177 for (i
= 0; i
< argc
; i
++)
179 info
= find_device_info(dpy
, argv
[i
], False
);
182 fprintf(stderr
, "unable to find device '%s'\n", argv
[i
]);
186 dev
= XOpenDevice(dpy
, info
->id
);
189 fprintf(stderr
, "unable to open device '%s'\n", info
->name
);
193 props
= XListDeviceProperties(dpy
, dev
, &nprops
);
196 printf("Device '%s' does not report any properties.\n", info
->name
);
200 printf("Device '%s':\n", info
->name
);
203 print_property(dpy
, dev
, props
[nprops
]);
207 XCloseDevice(dpy
, dev
);
213 int watch_props(Display
*dpy
, int argc
, char** argv
, char* n
, char *desc
)
218 XDevicePropertyNotifyEvent
*dpev
;
221 XEventClass cls_prop
;
223 if (list_props(dpy
, argc
, argv
, n
, desc
) != EXIT_SUCCESS
)
226 info
= find_device_info(dpy
, argv
[0], False
);
229 fprintf(stderr
, "unable to find device '%s'\n", argv
[0]);
233 dev
= XOpenDevice(dpy
, info
->id
);
236 fprintf(stderr
, "unable to open device '%s'\n", info
->name
);
240 DevicePropertyNotify(dev
, type_prop
, cls_prop
);
241 XSelectExtensionEvent(dpy
, DefaultRootWindow(dpy
), &cls_prop
, 1);
245 XNextEvent(dpy
, &ev
);
247 dpev
= (XDevicePropertyNotifyEvent
*)&ev
;
248 if (dpev
->type
!= type_prop
)
251 name
= XGetAtomName(dpy
, dpev
->atom
);
252 printf("Property '%s' changed.\n", name
);
253 print_property(dpy
, dev
, dpev
->atom
);
256 XCloseDevice(dpy
, dev
);
260 delete_prop_xi1(Display
*dpy
, int argc
, char** argv
, char* n
, char *desc
)
267 info
= find_device_info(dpy
, argv
[0], False
);
270 fprintf(stderr
, "unable to find device '%s'\n", argv
[0]);
274 dev
= XOpenDevice(dpy
, info
->id
);
277 fprintf(stderr
, "unable to open device '%s'\n", info
->name
);
283 prop
= parse_atom(dpy
, name
);
285 XDeleteDeviceProperty(dpy
, dev
, prop
);
287 XCloseDevice(dpy
, dev
);
292 do_set_prop_xi1(Display
*dpy
, Atom type
, int format
, int argc
, char **argv
, char *n
, char *desc
)
301 int old_format
, nelements
= 0;
302 unsigned long act_nitems
, bytes_after
;
313 fprintf(stderr
, "Usage: xinput %s %s\n", n
, desc
);
317 info
= find_device_info(dpy
, argv
[0], False
);
320 fprintf(stderr
, "unable to find device '%s'\n", argv
[0]);
324 dev
= XOpenDevice(dpy
, info
->id
);
327 fprintf(stderr
, "unable to open device '%s'\n", argv
[0]);
333 prop
= parse_atom(dpy
, name
);
336 fprintf(stderr
, "invalid property '%s'\n", name
);
340 float_atom
= XInternAtom(dpy
, "FLOAT", False
);
342 nelements
= argc
- 2;
343 if (type
== None
|| format
== 0) {
344 if (XGetDeviceProperty(dpy
, dev
, prop
, 0, 0, False
, AnyPropertyType
,
345 &old_type
, &old_format
, &act_nitems
,
346 &bytes_after
, &data
.c
) != Success
) {
347 fprintf(stderr
, "failed to get property type and format for '%s'\n",
361 fprintf(stderr
, "property '%s' doesn't exist, you need to specify "
362 "its type and format\n", name
);
366 data
.c
= calloc(nelements
, sizeof(long));
368 for (i
= 0; i
< nelements
; i
++)
370 if (type
== XA_INTEGER
|| type
== XA_CARDINAL
) {
374 data
.c
[i
] = atoi(argv
[2 + i
]);
377 data
.s
[i
] = atoi(argv
[2 + i
]);
380 data
.l
[i
] = atoi(argv
[2 + i
]);
383 fprintf(stderr
, "unexpected size for property '%s'", name
);
386 } else if (type
== float_atom
) {
388 fprintf(stderr
, "unexpected format %d for property '%s'\n",
392 *(float *)(data
.l
+ i
) = strtod(argv
[2 + i
], &endptr
);
393 if (endptr
== argv
[2 + i
]) {
394 fprintf(stderr
, "argument '%s' could not be parsed\n", argv
[2 + i
]);
397 } else if (type
== XA_ATOM
) {
399 fprintf(stderr
, "unexpected format %d for property '%s'\n",
403 data
.a
[i
] = parse_atom(dpy
, argv
[2 + i
]);
405 fprintf(stderr
, "unexpected type for property '%s'\n", name
);
410 XChangeDeviceProperty(dpy
, dev
, prop
, type
, format
, PropModeReplace
,
413 XCloseDevice(dpy
, dev
);
419 print_property_xi2(Display
*dpy
, int deviceid
, Atom property
)
424 unsigned long nitems
, bytes_after
;
425 unsigned char *data
, *ptr
;
428 name
= XGetAtomName(dpy
, property
);
429 printf("\t%s (%ld):\t", name
, property
);
431 if (XIGetProperty(dpy
, deviceid
, property
, 0, 1000, False
,
432 AnyPropertyType
, &act_type
, &act_format
,
433 &nitems
, &bytes_after
, &data
) == Success
)
435 Atom float_atom
= XInternAtom(dpy
, "FLOAT", True
);
440 printf("<no items>");
442 for (j
= 0; j
< nitems
; j
++)
450 printf("%d", *((int8_t*)ptr
));
453 printf("%d", *((int16_t*)ptr
));
456 printf("%d", *((int32_t*)ptr
));
464 printf("%u", *((uint8_t*)ptr
));
467 printf("%u", *((uint16_t*)ptr
));
470 printf("%u", *((uint32_t*)ptr
));
477 printf("Unknown string format.\n");
481 printf("\"%s\"", ptr
);
482 j
+= strlen((char*)ptr
); /* The loop's j++ jumps over the
484 ptr
+= strlen((char*)ptr
); /* ptr += size below jumps over
489 Atom a
= *(uint32_t*)ptr
;
490 printf("\"%s\" (%ld)",
491 (a
) ? XGetAtomName(dpy
, a
) : "None",
497 if (float_atom
!= None
&& act_type
== float_atom
)
499 printf("%f", *((float*)ptr
));
503 printf("\t... of unknown type %s\n",
504 XGetAtomName(dpy
, act_type
));
519 printf("\tFetch failure\n");
524 list_props_xi2(Display
*dpy
, int argc
, char** argv
, char* name
, char *desc
)
533 fprintf(stderr
, "Usage: xinput %s %s\n", name
, desc
);
537 for (i
= 0; i
< argc
; i
++)
539 info
= xi2_find_device_info(dpy
, argv
[i
]);
542 fprintf(stderr
, "unable to find device %s\n", argv
[i
]);
546 props
= XIListProperties(dpy
, info
->deviceid
, &nprops
);
549 printf("Device '%s' does not report any properties.\n", info
->name
);
553 printf("Device '%s':\n", info
->name
);
556 print_property_xi2(dpy
, info
->deviceid
, props
[nprops
]);
565 delete_prop_xi2(Display
*dpy
, int argc
, char** argv
, char* n
, char *desc
)
571 info
= xi2_find_device_info(dpy
, argv
[0]);
574 fprintf(stderr
, "unable to find device %s\n", argv
[0]);
580 prop
= parse_atom(dpy
, name
);
582 XIDeleteProperty(dpy
, info
->deviceid
, prop
);
588 do_set_prop_xi2(Display
*dpy
, Atom type
, int format
, int argc
, char **argv
, char *n
, char *desc
)
596 int old_format
, nelements
= 0;
597 unsigned long act_nitems
, bytes_after
;
607 fprintf(stderr
, "Usage: xinput %s %s\n", n
, desc
);
611 info
= xi2_find_device_info(dpy
, argv
[0]);
614 fprintf(stderr
, "unable to find device %s\n", argv
[0]);
620 prop
= parse_atom(dpy
, name
);
623 fprintf(stderr
, "invalid property '%s'\n", name
);
627 float_atom
= XInternAtom(dpy
, "FLOAT", False
);
629 nelements
= argc
- 2;
630 if (type
== None
|| format
== 0) {
631 if (XIGetProperty(dpy
, info
->deviceid
, prop
, 0, 0, False
,
632 AnyPropertyType
, &old_type
, &old_format
, &act_nitems
,
633 &bytes_after
, &data
.c
) != Success
) {
634 fprintf(stderr
, "failed to get property type and format for '%s'\n",
648 fprintf(stderr
, "property '%s' doesn't exist, you need to specify "
649 "its type and format\n", name
);
653 data
.c
= calloc(nelements
, sizeof(int32_t));
655 for (i
= 0; i
< nelements
; i
++)
657 if (type
== XA_INTEGER
|| type
== XA_CARDINAL
) {
661 data
.c
[i
] = atoi(argv
[2 + i
]);
664 data
.s
[i
] = atoi(argv
[2 + i
]);
667 data
.l
[i
] = atoi(argv
[2 + i
]);
670 fprintf(stderr
, "unexpected size for property %s", name
);
673 } else if (type
== float_atom
) {
675 fprintf(stderr
, "unexpected format %d for property '%s'\n",
679 *(float *)(data
.l
+ i
) = strtod(argv
[2 + i
], &endptr
);
680 if (endptr
== argv
[2 + i
]) {
681 fprintf(stderr
, "argument %s could not be parsed\n", argv
[2 + i
]);
684 } else if (type
== XA_ATOM
) {
686 fprintf(stderr
, "unexpected format %d for property '%s'\n",
690 data
.l
[i
] = parse_atom(dpy
, argv
[2 + i
]);
692 fprintf(stderr
, "unexpected type for property '%s'\n", name
);
697 XIChangeProperty(dpy
, info
->deviceid
, prop
, type
, format
, PropModeReplace
,
704 int list_props(Display
*display
, int argc
, char *argv
[], char *name
,
708 if (xinput_version(display
) == XI_2_Major
)
709 return list_props_xi2(display
, argc
, argv
, name
, desc
);
711 return list_props_xi1(display
, argc
, argv
, name
, desc
);
715 int delete_prop(Display
*display
, int argc
, char *argv
[], char *name
,
719 if (xinput_version(display
) == XI_2_Major
)
720 return delete_prop_xi2(display
, argc
, argv
, name
, desc
);
722 return delete_prop_xi1(display
, argc
, argv
, name
, desc
);
727 do_set_prop(Display
*display
, Atom type
, int format
, int argc
, char *argv
[], char *name
, char *desc
)
730 if (xinput_version(display
) == XI_2_Major
)
731 return do_set_prop_xi2(display
, type
, format
, argc
, argv
, name
, desc
);
733 return do_set_prop_xi1(display
, type
, format
, argc
, argv
, name
, desc
);
737 set_atom_prop(Display
*dpy
, int argc
, char** argv
, char* n
, char *desc
)
739 return do_set_prop(dpy
, XA_ATOM
, 32, argc
, argv
, n
, desc
);
743 set_int_prop(Display
*dpy
, int argc
, char** argv
, char* n
, char *desc
)
750 fprintf(stderr
, "Usage: xinput %s %s\n", n
, desc
);
754 format
= atoi(argv
[2]);
755 if (format
!= 8 && format
!= 16 && format
!= 32)
757 fprintf(stderr
, "Invalid format %d\n", format
);
761 for (i
= 3; i
< argc
; i
++)
762 argv
[i
- 1] = argv
[i
];
764 return do_set_prop(dpy
, XA_INTEGER
, format
, argc
- 1, argv
, n
, desc
);
768 set_float_prop(Display
*dpy
, int argc
, char** argv
, char* n
, char *desc
)
770 Atom float_atom
= XInternAtom(dpy
, "FLOAT", False
);
772 if (sizeof(float) != 4)
774 fprintf(stderr
, "sane FP required\n");
778 return do_set_prop(dpy
, float_atom
, 32, argc
, argv
, n
, desc
);
781 int set_prop(Display
*display
, int argc
, char *argv
[], char *name
,
789 char *option
= strchr(argv
[i
], '=');
790 /* skip non-option arguments */
791 if (strncmp(argv
[i
], "--", 2) || !option
) {
796 if (!strncmp(argv
[i
], "--type=", strlen("--type="))) {
797 if (!strcmp(option
+ 1, "int")) {
799 } else if (!strcmp(option
+ 1, "float")) {
800 type
= XInternAtom(display
, "FLOAT", False
);
802 } else if (!strcmp(option
+ 1, "atom")) {
806 fprintf(stderr
, "unknown property type %s\n", option
+ 1);
809 } else if (!strncmp(argv
[i
], "--format=", strlen("--format="))) {
810 format
= atoi(option
+ 1);
811 if (format
!= 8 && format
!= 16 && format
!= 32) {
812 fprintf(stderr
, "invalid property format '%s'\n", option
+ 1);
816 fprintf(stderr
, "invalid option '%s'\n", argv
[i
]);
820 for (j
= i
; j
+ 1 < argc
; j
++)
821 argv
[j
] = argv
[j
+ 1];
825 return do_set_prop(display
, type
, format
, argc
, argv
, name
, desc
);
828 int disable(Display
*display
, int argc
, char *argv
[], char *name
, char *desc
)
830 char *new_argv
[3] = { argv
[0], "Device Enabled", "0" };
831 return set_prop(display
, 3, new_argv
, name
, desc
);
834 int enable(Display
*display
, int argc
, char *argv
[], char *name
, char *desc
)
836 char *new_argv
[3] = { argv
[0], "Device Enabled", "1" };
837 return set_prop(display
, 3, new_argv
, name
, desc
);