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
);
65 if (XGetDeviceProperty(dpy
, dev
, property
, 0, 1000, False
,
66 AnyPropertyType
, &act_type
, &act_format
,
67 &nitems
, &bytes_after
, &data
) == Success
)
69 Atom float_atom
= XInternAtom(dpy
, "FLOAT", True
);
78 case 8: size
= sizeof(char); break;
79 case 16: size
= sizeof(short); break;
80 case 32: size
= sizeof(long); break;
83 for (j
= 0; j
< nitems
; j
++)
91 printf("%d", *((char*)ptr
));
94 printf("%d", *((short*)ptr
));
97 printf("%ld", *((long*)ptr
));
105 printf("%u", *((unsigned char*)ptr
));
108 printf("%u", *((unsigned short*)ptr
));
111 printf("%lu", *((unsigned long*)ptr
));
118 printf("Unknown string format.\n");
122 printf("\"%s\"", ptr
);
123 j
+= strlen((char*)ptr
); /* The loop's j++ jumps over the
125 ptr
+= strlen((char*)ptr
); /* ptr += size below jumps over
130 Atom a
= *(Atom
*)ptr
;
131 name
= (a
) ? XGetAtomName(dpy
, a
) : NULL
;
132 printf("\"%s\" (%d)", name
? name
: "None", (int)a
);
137 if (float_atom
!= None
&& act_type
== float_atom
)
139 printf("%f", *((float*)ptr
));
143 name
= XGetAtomName(dpy
, act_type
);
144 printf("\t... of unknown type '%s'\n", name
);
160 printf("\tFetch failure\n");
165 list_props_xi1(Display
*dpy
, int argc
, char** argv
, char* name
, char *desc
)
172 int rc
= EXIT_SUCCESS
;
176 fprintf(stderr
, "Usage: xinput %s %s\n", name
, desc
);
180 for (i
= 0; i
< argc
; i
++)
182 info
= find_device_info(dpy
, argv
[i
], False
);
185 fprintf(stderr
, "unable to find device '%s'\n", argv
[i
]);
190 dev
= XOpenDevice(dpy
, info
->id
);
193 fprintf(stderr
, "unable to open device '%s'\n", info
->name
);
198 props
= XListDeviceProperties(dpy
, dev
, &nprops
);
201 printf("Device '%s' does not report any properties.\n", info
->name
);
205 printf("Device '%s':\n", info
->name
);
208 print_property(dpy
, dev
, props
[nprops
]);
212 XCloseDevice(dpy
, dev
);
218 int watch_props(Display
*dpy
, int argc
, char** argv
, char* n
, char *desc
)
223 XDevicePropertyNotifyEvent
*dpev
;
226 XEventClass cls_prop
;
228 if (list_props(dpy
, argc
, argv
, n
, desc
) != EXIT_SUCCESS
)
231 info
= find_device_info(dpy
, argv
[0], False
);
234 fprintf(stderr
, "unable to find device '%s'\n", argv
[0]);
238 dev
= XOpenDevice(dpy
, info
->id
);
241 fprintf(stderr
, "unable to open device '%s'\n", info
->name
);
245 DevicePropertyNotify(dev
, type_prop
, cls_prop
);
246 XSelectExtensionEvent(dpy
, DefaultRootWindow(dpy
), &cls_prop
, 1);
250 XNextEvent(dpy
, &ev
);
252 dpev
= (XDevicePropertyNotifyEvent
*)&ev
;
253 if (dpev
->type
!= type_prop
)
256 name
= XGetAtomName(dpy
, dpev
->atom
);
257 printf("Property '%s' changed.\n", name
);
259 print_property(dpy
, dev
, dpev
->atom
);
262 XCloseDevice(dpy
, dev
);
266 delete_prop_xi1(Display
*dpy
, int argc
, char** argv
, char* n
, char *desc
)
273 info
= find_device_info(dpy
, argv
[0], False
);
276 fprintf(stderr
, "unable to find device '%s'\n", argv
[0]);
280 dev
= XOpenDevice(dpy
, info
->id
);
283 fprintf(stderr
, "unable to open device '%s'\n", info
->name
);
289 prop
= parse_atom(dpy
, name
);
291 XDeleteDeviceProperty(dpy
, dev
, prop
);
293 XCloseDevice(dpy
, dev
);
298 do_set_prop_xi1(Display
*dpy
, Atom type
, int format
, int argc
, char **argv
, char *n
, char *desc
)
307 int old_format
, nelements
= 0;
308 unsigned long act_nitems
, bytes_after
;
319 fprintf(stderr
, "Usage: xinput %s %s\n", n
, desc
);
323 info
= find_device_info(dpy
, argv
[0], False
);
326 fprintf(stderr
, "unable to find device '%s'\n", argv
[0]);
330 dev
= XOpenDevice(dpy
, info
->id
);
333 fprintf(stderr
, "unable to open device '%s'\n", argv
[0]);
339 prop
= parse_atom(dpy
, name
);
342 fprintf(stderr
, "invalid property '%s'\n", name
);
346 float_atom
= XInternAtom(dpy
, "FLOAT", False
);
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",
367 fprintf(stderr
, "property '%s' doesn't exist, you need to specify "
368 "its type and format\n", name
);
372 data
.c
= calloc(nelements
, sizeof(long));
374 for (i
= 0; i
< nelements
; i
++)
376 if (type
== XA_INTEGER
|| type
== XA_CARDINAL
) {
380 data
.c
[i
] = atoi(argv
[2 + i
]);
383 data
.s
[i
] = atoi(argv
[2 + i
]);
386 data
.l
[i
] = atoi(argv
[2 + i
]);
389 fprintf(stderr
, "unexpected size for property '%s'", name
);
392 } else if (type
== float_atom
) {
394 fprintf(stderr
, "unexpected format %d for property '%s'\n",
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
]);
403 } else if (type
== XA_ATOM
) {
405 fprintf(stderr
, "unexpected format %d for property '%s'\n",
409 data
.a
[i
] = parse_atom(dpy
, argv
[2 + i
]);
411 fprintf(stderr
, "unexpected type for property '%s'\n", name
);
416 XChangeDeviceProperty(dpy
, dev
, prop
, type
, format
, PropModeReplace
,
419 XCloseDevice(dpy
, dev
);
425 print_property_xi2(Display
*dpy
, int deviceid
, Atom property
)
430 unsigned long nitems
, bytes_after
;
431 unsigned char *data
, *ptr
;
434 name
= XGetAtomName(dpy
, property
);
435 printf("\t%s (%ld):\t", name
, property
);
438 if (XIGetProperty(dpy
, deviceid
, property
, 0, 1000, False
,
439 AnyPropertyType
, &act_type
, &act_format
,
440 &nitems
, &bytes_after
, &data
) == Success
)
442 Atom float_atom
= XInternAtom(dpy
, "FLOAT", True
);
447 printf("<no items>");
449 for (j
= 0; j
< nitems
; j
++)
457 printf("%d", *((int8_t*)ptr
));
460 printf("%d", *((int16_t*)ptr
));
463 printf("%d", *((int32_t*)ptr
));
471 printf("%u", *((uint8_t*)ptr
));
474 printf("%u", *((uint16_t*)ptr
));
477 printf("%u", *((uint32_t*)ptr
));
484 printf("Unknown string format.\n");
488 printf("\"%s\"", ptr
);
489 j
+= strlen((char*)ptr
); /* The loop's j++ jumps over the
491 ptr
+= strlen((char*)ptr
); /* ptr += size below jumps over
496 Atom a
= *(uint32_t*)ptr
;
497 name
= (a
) ? XGetAtomName(dpy
, a
) : NULL
;
498 printf("\"%s\" (%ld)", name
? name
: "None", a
);
504 if (float_atom
!= None
&& act_type
== float_atom
)
506 printf("%f", *((float*)ptr
));
510 name
= XGetAtomName(dpy
, act_type
);
511 printf("\t... of unknown type %s\n", name
);
527 printf("\tFetch failure\n");
532 list_props_xi2(Display
*dpy
, int argc
, char** argv
, char* name
, char *desc
)
538 int rc
= EXIT_SUCCESS
;
542 fprintf(stderr
, "Usage: xinput %s %s\n", name
, desc
);
546 for (i
= 0; i
< argc
; i
++)
548 info
= xi2_find_device_info(dpy
, argv
[i
]);
551 fprintf(stderr
, "unable to find device %s\n", argv
[i
]);
556 props
= XIListProperties(dpy
, info
->deviceid
, &nprops
);
559 printf("Device '%s' does not report any properties.\n", info
->name
);
563 printf("Device '%s':\n", info
->name
);
566 print_property_xi2(dpy
, info
->deviceid
, props
[nprops
]);
575 delete_prop_xi2(Display
*dpy
, int argc
, char** argv
, char* n
, char *desc
)
581 info
= xi2_find_device_info(dpy
, argv
[0]);
584 fprintf(stderr
, "unable to find device %s\n", argv
[0]);
590 prop
= parse_atom(dpy
, name
);
592 XIDeleteProperty(dpy
, info
->deviceid
, prop
);
598 do_set_prop_xi2(Display
*dpy
, Atom type
, int format
, int argc
, char **argv
, char *n
, char *desc
)
606 int old_format
, nelements
= 0;
607 unsigned long act_nitems
, bytes_after
;
614 int rc
= EXIT_FAILURE
;
618 fprintf(stderr
, "Usage: xinput %s %s\n", n
, desc
);
622 info
= xi2_find_device_info(dpy
, argv
[0]);
625 fprintf(stderr
, "unable to find device %s\n", argv
[0]);
631 prop
= parse_atom(dpy
, name
);
634 fprintf(stderr
, "invalid property '%s'\n", name
);
638 float_atom
= XInternAtom(dpy
, "FLOAT", False
);
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",
659 fprintf(stderr
, "property '%s' doesn't exist, you need to specify "
660 "its type and format\n", name
);
664 data
.c
= calloc(nelements
, sizeof(int32_t));
666 for (i
= 0; i
< nelements
; i
++)
668 if (type
== XA_INTEGER
|| type
== XA_CARDINAL
) {
672 data
.c
[i
] = atoi(argv
[2 + i
]);
675 data
.s
[i
] = atoi(argv
[2 + i
]);
678 data
.l
[i
] = atoi(argv
[2 + i
]);
681 fprintf(stderr
, "unexpected size for property %s", name
);
684 } else if (type
== float_atom
) {
686 fprintf(stderr
, "unexpected format %d for property '%s'\n",
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
]);
695 } else if (type
== XA_ATOM
) {
697 fprintf(stderr
, "unexpected format %d for property '%s'\n",
701 data
.l
[i
] = parse_atom(dpy
, argv
[2 + i
]);
703 fprintf(stderr
, "unexpected type for property '%s'\n", name
);
708 XIChangeProperty(dpy
, info
->deviceid
, prop
, type
, format
, PropModeReplace
,
717 int list_props(Display
*display
, int argc
, char *argv
[], char *name
,
721 if (xinput_version(display
) == XI_2_Major
)
722 return list_props_xi2(display
, argc
, argv
, name
, desc
);
724 return list_props_xi1(display
, argc
, argv
, name
, desc
);
728 int delete_prop(Display
*display
, int argc
, char *argv
[], char *name
,
732 if (xinput_version(display
) == XI_2_Major
)
733 return delete_prop_xi2(display
, argc
, argv
, name
, desc
);
735 return delete_prop_xi1(display
, argc
, argv
, name
, desc
);
740 do_set_prop(Display
*display
, Atom type
, int format
, int argc
, char *argv
[], char *name
, char *desc
)
743 if (xinput_version(display
) == XI_2_Major
)
744 return do_set_prop_xi2(display
, type
, format
, argc
, argv
, name
, desc
);
746 return do_set_prop_xi1(display
, type
, format
, argc
, argv
, name
, desc
);
750 set_atom_prop(Display
*dpy
, int argc
, char** argv
, char* n
, char *desc
)
752 return do_set_prop(dpy
, XA_ATOM
, 32, argc
, argv
, n
, desc
);
756 set_int_prop(Display
*dpy
, int argc
, char** argv
, char* n
, char *desc
)
763 fprintf(stderr
, "Usage: xinput %s %s\n", n
, desc
);
767 format
= atoi(argv
[2]);
768 if (format
!= 8 && format
!= 16 && format
!= 32)
770 fprintf(stderr
, "Invalid format %d\n", format
);
774 for (i
= 3; i
< argc
; i
++)
775 argv
[i
- 1] = argv
[i
];
777 return do_set_prop(dpy
, XA_INTEGER
, format
, argc
- 1, argv
, n
, desc
);
781 set_float_prop(Display
*dpy
, int argc
, char** argv
, char* n
, char *desc
)
783 Atom float_atom
= XInternAtom(dpy
, "FLOAT", False
);
785 if (sizeof(float) != 4)
787 fprintf(stderr
, "sane FP required\n");
791 return do_set_prop(dpy
, float_atom
, 32, argc
, argv
, n
, desc
);
794 int set_prop(Display
*display
, int argc
, char *argv
[], char *name
,
802 char *option
= strchr(argv
[i
], '=');
803 /* skip non-option arguments */
804 if (strncmp(argv
[i
], "--", 2) || !option
) {
809 if (!strncmp(argv
[i
], "--type=", strlen("--type="))) {
810 if (!strcmp(option
+ 1, "int")) {
812 } else if (!strcmp(option
+ 1, "float")) {
813 type
= XInternAtom(display
, "FLOAT", False
);
815 } else if (!strcmp(option
+ 1, "atom")) {
819 fprintf(stderr
, "unknown property type %s\n", option
+ 1);
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);
829 fprintf(stderr
, "invalid option '%s'\n", argv
[i
]);
833 for (j
= i
; j
+ 1 < argc
; j
++)
834 argv
[j
] = argv
[j
+ 1];
838 return do_set_prop(display
, type
, format
, argc
, argv
, name
, desc
);
841 int disable(Display
*display
, int argc
, char *argv
[], char *name
, char *desc
)
843 char *new_argv
[3] = { NULL
, "Device Enabled", "0" };
846 fprintf(stderr
, "Usage: xinput %s %s\n", name
, desc
);
850 new_argv
[0] = argv
[0];
852 return set_prop(display
, 3, new_argv
, name
, desc
);
855 int enable(Display
*display
, int argc
, char *argv
[], char *name
, char *desc
)
857 char *new_argv
[3] = { NULL
, "Device Enabled", "1" };
860 fprintf(stderr
, "Usage: xinput %s %s\n", name
, desc
);
864 new_argv
[0] = argv
[0];
866 return set_prop(display
, 3, new_argv
, name
, desc
);