2 * Copyright 2007 Peter Hutterer
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
10 * The above copyright notice and this permission notice shall be included
11 * in all copies or substantial portions of the Software.
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.
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
32 #include <X11/Xatom.h>
33 #include <X11/extensions/XIproto.h>
37 static Atom
parse_atom(Display
*dpy
, char *name
) {
41 for (i
= 0; name
[i
] != '\0'; i
++) {
42 if (!isdigit(name
[i
])) {
51 return XInternAtom(dpy
, name
, False
);
55 print_property(Display
*dpy
, XDevice
* dev
, Atom property
)
60 unsigned long nitems
, bytes_after
;
61 unsigned char *data
, *ptr
;
62 int j
, done
= False
, size
;
64 name
= XGetAtomName(dpy
, property
);
65 printf("\t%s (%ld):\t", name
, property
);
67 if (XGetDeviceProperty(dpy
, dev
, property
, 0, 1000, False
,
68 AnyPropertyType
, &act_type
, &act_format
,
69 &nitems
, &bytes_after
, &data
) == Success
)
71 Atom float_atom
= XInternAtom(dpy
, "FLOAT", True
);
80 case 8: size
= sizeof(char); break;
81 case 16: size
= sizeof(short); break;
82 case 32: size
= sizeof(long); break;
85 for (j
= 0; j
< nitems
; j
++)
93 printf("%d", *((char*)ptr
));
96 printf("%d", *((short*)ptr
));
99 printf("%ld", *((long*)ptr
));
106 printf("Unknown string format.\n");
110 printf("\"%s\"", ptr
);
111 j
+= strlen((char*)ptr
); /* The loop's j++ jumps over the
113 ptr
+= strlen((char*)ptr
); /* ptr += size below jumps over
118 Atom a
= *(Atom
*)ptr
;
119 printf("\"%s\" (%d)",
120 (a
) ? XGetAtomName(dpy
, a
) : "None",
125 if (float_atom
!= None
&& act_type
== float_atom
)
127 printf("%f", *((float*)ptr
));
131 printf("\t... of unknown type %s\n",
132 XGetAtomName(dpy
, act_type
));
147 printf("\tFetch failure\n");
152 list_props_xi1(Display
*dpy
, int argc
, char** argv
, char* name
, char *desc
)
162 fprintf(stderr
, "Usage: xinput %s %s\n", name
, desc
);
166 for (i
= 0; i
< argc
; i
++)
168 info
= find_device_info(dpy
, argv
[i
], False
);
171 fprintf(stderr
, "unable to find device %s\n", argv
[i
]);
175 dev
= XOpenDevice(dpy
, info
->id
);
178 fprintf(stderr
, "unable to open device '%s'\n", info
->name
);
182 props
= XListDeviceProperties(dpy
, dev
, &nprops
);
185 printf("Device '%s' does not report any properties.\n", info
->name
);
189 printf("Device '%s':\n", info
->name
);
192 print_property(dpy
, dev
, props
[nprops
]);
196 XCloseDevice(dpy
, dev
);
202 set_int_prop(Display
*dpy
, int argc
, char** argv
, char* n
, char *desc
)
210 int format
, nelements
= 0;
214 fprintf(stderr
, "Usage: xinput %s %s\n", n
, desc
);
218 info
= find_device_info(dpy
, argv
[0], False
);
221 fprintf(stderr
, "unable to find device %s\n", argv
[0]);
225 dev
= XOpenDevice(dpy
, info
->id
);
228 fprintf(stderr
, "unable to open device %s\n", argv
[0]);
234 prop
= parse_atom(dpy
, name
);
236 nelements
= argc
- 3;
237 format
= atoi(argv
[2]);
238 if (format
!= 8 && format
!= 16 && format
!= 32)
240 fprintf(stderr
, "Invalid format %d\n", format
);
244 data
= calloc(nelements
, sizeof(long));
245 for (i
= 0; i
< nelements
; i
++)
250 *(((char*)data
) + i
) = atoi(argv
[3 + i
]);
253 *(((short*)data
) + i
) = atoi(argv
[3 + i
]);
256 *(((long*)data
) + i
) = atoi(argv
[3 + i
]);
261 XChangeDeviceProperty(dpy
, dev
, prop
, XA_INTEGER
, format
, PropModeReplace
,
262 (unsigned char*)data
, nelements
);
265 XCloseDevice(dpy
, dev
);
270 set_float_prop(Display
*dpy
, int argc
, char** argv
, char* n
, char *desc
)
274 Atom prop
, float_atom
;
283 fprintf(stderr
, "Usage: xinput %s %s\n", n
, desc
);
287 info
= find_device_info(dpy
, argv
[0], False
);
290 fprintf(stderr
, "unable to find device %s\n", argv
[0]);
294 dev
= XOpenDevice(dpy
, info
->id
);
297 fprintf(stderr
, "unable to open device %s\n", argv
[0]);
303 prop
= parse_atom(dpy
, name
);
305 nelements
= argc
- 2;
307 float_atom
= XInternAtom(dpy
, "FLOAT", False
);
309 if (float_atom
== (Atom
)0)
311 fprintf(stderr
, "no FLOAT atom present in server\n");
315 if (sizeof(float) != 4)
317 fprintf(stderr
, "sane FP required\n");
321 data
= calloc(nelements
, sizeof(long));
322 for (i
= 0; i
< nelements
; i
++)
324 *((float*)(data
+ i
)) = strtod(argv
[2 + i
], &endptr
);
325 if(endptr
== argv
[2 + i
]){
326 fprintf(stderr
, "argument %s could not be parsed\n", argv
[2 + i
]);
331 XChangeDeviceProperty(dpy
, dev
, prop
, float_atom
, 32, PropModeReplace
,
332 (unsigned char*)data
, nelements
);
335 XCloseDevice(dpy
, dev
);
340 int watch_props(Display
*dpy
, int argc
, char** argv
, char* n
, char *desc
)
345 XDevicePropertyNotifyEvent
*dpev
;
348 XEventClass cls_prop
;
350 if (list_props(dpy
, argc
, argv
, n
, desc
) != EXIT_SUCCESS
)
353 info
= find_device_info(dpy
, argv
[0], False
);
356 fprintf(stderr
, "unable to find device %s\n", argv
[0]);
360 dev
= XOpenDevice(dpy
, info
->id
);
363 fprintf(stderr
, "unable to open device '%s'\n", info
->name
);
367 DevicePropertyNotify(dev
, type_prop
, cls_prop
);
368 XSelectExtensionEvent(dpy
, DefaultRootWindow(dpy
), &cls_prop
, 1);
372 XNextEvent(dpy
, &ev
);
374 dpev
= (XDevicePropertyNotifyEvent
*)&ev
;
375 if (dpev
->type
!= type_prop
)
378 name
= XGetAtomName(dpy
, dpev
->atom
);
379 printf("Property '%s' changed.\n", name
);
380 print_property(dpy
, dev
, dpev
->atom
);
383 XCloseDevice(dpy
, dev
);
387 delete_prop_xi1(Display
*dpy
, int argc
, char** argv
, char* n
, char *desc
)
394 info
= find_device_info(dpy
, argv
[0], False
);
397 fprintf(stderr
, "unable to find device %s\n", argv
[0]);
401 dev
= XOpenDevice(dpy
, info
->id
);
404 fprintf(stderr
, "unable to open device '%s'\n", info
->name
);
410 prop
= parse_atom(dpy
, name
);
412 XDeleteDeviceProperty(dpy
, dev
, prop
);
414 XCloseDevice(dpy
, dev
);
419 set_atom_prop(Display
*dpy
, int argc
, char** argv
, char* n
, char *desc
)
432 fprintf(stderr
, "Usage: xinput %s %s\n", n
, desc
);
436 info
= find_device_info(dpy
, argv
[0], False
);
439 fprintf(stderr
, "unable to find device %s\n", argv
[0]);
443 dev
= XOpenDevice(dpy
, info
->id
);
446 fprintf(stderr
, "unable to open device %s\n", argv
[0]);
452 prop
= parse_atom(dpy
, name
);
454 nelements
= argc
- 2;
455 data
= calloc(nelements
, sizeof(Atom
));
456 for (i
= 0; i
< nelements
; i
++)
460 for(j
= 0; j
< strlen(name
); j
++) {
461 if (!isdigit(name
[j
])) {
468 data
[i
] = XInternAtom(dpy
, name
, False
);
471 data
[i
] = atoi(name
);
472 XFree(XGetAtomName(dpy
, data
[i
]));
476 XChangeDeviceProperty(dpy
, dev
, prop
, XA_ATOM
, 32, PropModeReplace
,
477 (unsigned char*)data
, nelements
);
480 XCloseDevice(dpy
, dev
);
485 do_set_prop_xi1(Display
*dpy
, Atom type
, int format
, int argc
, char **argv
, char *n
, char *desc
)
494 int old_format
, nelements
= 0;
495 unsigned long act_nitems
, bytes_after
;
506 fprintf(stderr
, "Usage: xinput %s %s\n", n
, desc
);
510 info
= find_device_info(dpy
, argv
[0], False
);
513 fprintf(stderr
, "unable to find device %s\n", argv
[0]);
517 dev
= XOpenDevice(dpy
, info
->id
);
520 fprintf(stderr
, "unable to open device %s\n", argv
[0]);
526 prop
= parse_atom(dpy
, name
);
529 fprintf(stderr
, "invalid property %s\n", name
);
533 float_atom
= XInternAtom(dpy
, "FLOAT", False
);
535 nelements
= argc
- 2;
536 if (type
== None
|| format
== 0) {
537 if (XGetDeviceProperty(dpy
, dev
, prop
, 0, 0, False
, AnyPropertyType
,
538 &old_type
, &old_format
, &act_nitems
,
539 &bytes_after
, &data
.c
) != Success
) {
540 fprintf(stderr
, "failed to get property type and format for %s\n",
554 fprintf(stderr
, "property %s doesn't exist, you need to specify "
555 "its type and format\n", name
);
559 data
.c
= calloc(nelements
, sizeof(long));
561 for (i
= 0; i
< nelements
; i
++)
563 if (type
== XA_INTEGER
) {
567 data
.c
[i
] = atoi(argv
[2 + i
]);
570 data
.s
[i
] = atoi(argv
[2 + i
]);
573 data
.l
[i
] = atoi(argv
[2 + i
]);
576 fprintf(stderr
, "unexpected size for property %s", name
);
579 } else if (type
== float_atom
) {
581 fprintf(stderr
, "unexpected format %d for property %s\n",
585 *(float *)(data
.l
+ i
) = strtod(argv
[2 + i
], &endptr
);
586 if (endptr
== argv
[2 + i
]) {
587 fprintf(stderr
, "argument %s could not be parsed\n", argv
[2 + i
]);
590 } else if (type
== XA_ATOM
) {
592 fprintf(stderr
, "unexpected format %d for property %s\n",
596 data
.a
[i
] = parse_atom(dpy
, argv
[2 + i
]);
598 fprintf(stderr
, "unexpected type for property %s\n", name
);
603 XChangeDeviceProperty(dpy
, dev
, prop
, type
, format
, PropModeReplace
,
606 XCloseDevice(dpy
, dev
);
612 print_property_xi2(Display
*dpy
, int deviceid
, Atom property
)
617 unsigned long nitems
, bytes_after
;
618 unsigned char *data
, *ptr
;
621 name
= XGetAtomName(dpy
, property
);
622 printf("\t%s (%ld):\t", name
, property
);
624 if (XIGetProperty(dpy
, deviceid
, property
, 0, 1000, False
,
625 AnyPropertyType
, &act_type
, &act_format
,
626 &nitems
, &bytes_after
, &data
) == Success
)
628 Atom float_atom
= XInternAtom(dpy
, "FLOAT", True
);
633 printf("<no items>");
635 for (j
= 0; j
< nitems
; j
++)
643 printf("%d", *((int8_t*)ptr
));
646 printf("%d", *((int16_t*)ptr
));
649 printf("%d", *((int32_t*)ptr
));
656 printf("Unknown string format.\n");
660 printf("\"%s\"", ptr
);
661 j
+= strlen((char*)ptr
); /* The loop's j++ jumps over the
663 ptr
+= strlen((char*)ptr
); /* ptr += size below jumps over
668 Atom a
= *(Atom
*)ptr
;
669 printf("\"%s\" (%d)",
670 (a
) ? XGetAtomName(dpy
, a
) : "None",
676 if (float_atom
!= None
&& act_type
== float_atom
)
678 printf("%f", *((float*)ptr
));
682 printf("\t... of unknown type %s\n",
683 XGetAtomName(dpy
, act_type
));
698 printf("\tFetch failure\n");
703 list_props_xi2(Display
*dpy
, int argc
, char** argv
, char* name
, char *desc
)
712 fprintf(stderr
, "Usage: xinput %s %s\n", name
, desc
);
716 for (i
= 0; i
< argc
; i
++)
718 info
= xi2_find_device_info(dpy
, argv
[i
]);
721 fprintf(stderr
, "unable to find device %s\n", argv
[i
]);
725 props
= XIListProperties(dpy
, info
->deviceid
, &nprops
);
728 printf("Device '%s' does not report any properties.\n", info
->name
);
732 printf("Device '%s':\n", info
->name
);
735 print_property_xi2(dpy
, info
->deviceid
, props
[nprops
]);
744 delete_prop_xi2(Display
*dpy
, int argc
, char** argv
, char* n
, char *desc
)
750 info
= xi2_find_device_info(dpy
, argv
[0]);
753 fprintf(stderr
, "unable to find device %s\n", argv
[0]);
759 prop
= parse_atom(dpy
, name
);
761 XIDeleteProperty(dpy
, info
->deviceid
, prop
);
767 do_set_prop_xi2(Display
*dpy
, Atom type
, int format
, int argc
, char **argv
, char *n
, char *desc
)
775 int old_format
, nelements
= 0;
776 unsigned long act_nitems
, bytes_after
;
786 fprintf(stderr
, "Usage: xinput %s %s\n", n
, desc
);
790 info
= xi2_find_device_info(dpy
, argv
[0]);
793 fprintf(stderr
, "unable to find device %s\n", argv
[0]);
799 prop
= parse_atom(dpy
, name
);
802 fprintf(stderr
, "invalid property %s\n", name
);
806 float_atom
= XInternAtom(dpy
, "FLOAT", False
);
808 nelements
= argc
- 2;
809 if (type
== None
|| format
== 0) {
810 if (XIGetProperty(dpy
, info
->deviceid
, prop
, 0, 0, False
,
811 AnyPropertyType
, &old_type
, &old_format
, &act_nitems
,
812 &bytes_after
, &data
.c
) != Success
) {
813 fprintf(stderr
, "failed to get property type and format for %s\n",
827 fprintf(stderr
, "property %s doesn't exist, you need to specify "
828 "its type and format\n", name
);
832 data
.c
= calloc(nelements
, sizeof(int32_t));
834 for (i
= 0; i
< nelements
; i
++)
836 if (type
== XA_INTEGER
) {
840 data
.c
[i
] = atoi(argv
[2 + i
]);
843 data
.s
[i
] = atoi(argv
[2 + i
]);
846 data
.l
[i
] = atoi(argv
[2 + i
]);
849 fprintf(stderr
, "unexpected size for property %s", name
);
852 } else if (type
== float_atom
) {
854 fprintf(stderr
, "unexpected format %d for property %s\n",
858 *(float *)(data
.l
+ i
) = strtod(argv
[2 + i
], &endptr
);
859 if (endptr
== argv
[2 + i
]) {
860 fprintf(stderr
, "argument %s could not be parsed\n", argv
[2 + i
]);
863 } else if (type
== XA_ATOM
) {
865 fprintf(stderr
, "unexpected format %d for property %s\n",
869 data
.l
[i
] = parse_atom(dpy
, argv
[2 + i
]);
871 fprintf(stderr
, "unexpected type for property %s\n", name
);
876 XIChangeProperty(dpy
, info
->deviceid
, prop
, type
, format
, PropModeReplace
,
883 int list_props(Display
*display
, int argc
, char *argv
[], char *name
,
887 if (xinput_version(display
) == XI_2_Major
)
888 return list_props_xi2(display
, argc
, argv
, name
, desc
);
890 return list_props_xi1(display
, argc
, argv
, name
, desc
);
894 int delete_prop(Display
*display
, int argc
, char *argv
[], char *name
,
898 if (xinput_version(display
) == XI_2_Major
)
899 return delete_prop_xi2(display
, argc
, argv
, name
, desc
);
901 return delete_prop_xi1(display
, argc
, argv
, name
, desc
);
906 do_set_prop(Display
*display
, Atom type
, int format
, int argc
, char *argv
[], char *name
, char *desc
)
909 if (xinput_version(display
) == XI_2_Major
)
910 return do_set_prop_xi2(display
, type
, format
, argc
, argv
, name
, desc
);
912 return do_set_prop_xi1(display
, type
, format
, argc
, argv
, name
, desc
);
915 int set_prop(Display
*display
, int argc
, char *argv
[], char *name
,
923 char *option
= strchr(argv
[i
], '=');
924 /* skip non-option arguments */
925 if (strncmp(argv
[i
], "--", 2) || !option
) {
930 if (!strncmp(argv
[i
], "--type=", strlen("--type="))) {
931 if (!strcmp(option
+ 1, "int")) {
933 } else if (!strcmp(option
+ 1, "float")) {
934 type
= XInternAtom(display
, "FLOAT", False
);
936 } else if (!strcmp(option
+ 1, "atom")) {
940 fprintf(stderr
, "unknown property type %s\n", option
+ 1);
943 } else if (!strncmp(argv
[i
], "--format=", strlen("--format="))) {
944 format
= atoi(option
+ 1);
945 if (format
!= 8 && format
!= 16 && format
!= 32) {
946 fprintf(stderr
, "invalid property format %s\n", option
+ 1);
950 fprintf(stderr
, "invalid option %s\n", argv
[i
]);
954 for (j
= i
; j
+ 1 < argc
; j
++)
955 argv
[j
] = argv
[j
+ 1];
959 return do_set_prop(display
, type
, format
, argc
, argv
, name
, desc
);