]> diplodocus.org Git - xorg-xinput/blob - src/property.c
b5f11079dc09c9303ff484279eca61bb2b46ca8c
[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 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 printf("\"%s\"", XGetAtomName(dpy, *(Atom*)ptr));
115 break;
116 default:
117 if (float_atom != None && act_type == float_atom)
118 {
119 printf("%f", *((float*)ptr));
120 break;
121 }
122
123 printf("\t... of unknown type %s\n",
124 XGetAtomName(dpy, act_type));
125 done = True;
126 break;
127 }
128
129 ptr += size;
130
131 if (done == True)
132 break;
133 if (j < nitems - 1)
134 printf(", ");
135 }
136 printf("\n");
137 XFree(data);
138 } else
139 printf("\tFetch failure\n");
140
141 }
142
143 int list_props(Display *dpy, int argc, char** argv, char* name, char *desc)
144 {
145 XDeviceInfo *info;
146 XDevice *dev;
147 int i;
148 int nprops;
149 Atom *props;
150
151 if (argc == 0)
152 {
153 fprintf(stderr, "Usage: xinput %s %s\n", name, desc);
154 return EXIT_FAILURE;
155 }
156
157 for (i = 0; i < argc; i++)
158 {
159 info = find_device_info(dpy, argv[i], False);
160 if (!info)
161 {
162 fprintf(stderr, "unable to find device %s\n", argv[i]);
163 continue;
164 }
165
166 dev = XOpenDevice(dpy, info->id);
167 if (!dev)
168 {
169 fprintf(stderr, "unable to open device '%s'\n", info->name);
170 continue;
171 }
172
173 props = XListDeviceProperties(dpy, dev, &nprops);
174 if (!nprops)
175 {
176 printf("Device '%s' does not report any properties.\n", info->name);
177 continue;
178 }
179
180 printf("Device '%s':\n", info->name);
181 while(nprops--)
182 {
183 print_property(dpy, dev, props[nprops]);
184 }
185
186 XFree(props);
187 XCloseDevice(dpy, dev);
188 }
189 return EXIT_SUCCESS;
190 }
191
192 int
193 set_int_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
194 {
195 XDeviceInfo *info;
196 XDevice *dev;
197 Atom prop;
198 char *name;
199 int i;
200 char *data;
201 int format, nelements = 0;
202
203 if (argc < 3)
204 {
205 fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
206 return EXIT_FAILURE;
207 }
208
209 info = find_device_info(dpy, argv[0], False);
210 if (!info)
211 {
212 fprintf(stderr, "unable to find device %s\n", argv[0]);
213 return EXIT_FAILURE;
214 }
215
216 dev = XOpenDevice(dpy, info->id);
217 if (!dev)
218 {
219 fprintf(stderr, "unable to open device %s\n", argv[0]);
220 return EXIT_FAILURE;
221 }
222
223 name = argv[1];
224
225 prop = parse_atom(dpy, name);
226
227 nelements = argc - 3;
228 format = atoi(argv[2]);
229 if (format != 8 && format != 16 && format != 32)
230 {
231 fprintf(stderr, "Invalid format %d\n", format);
232 return EXIT_FAILURE;
233 }
234
235 data = calloc(nelements, sizeof(long));
236 for (i = 0; i < nelements; i++)
237 {
238 switch(format)
239 {
240 case 8:
241 *(((char*)data) + i) = atoi(argv[3 + i]);
242 break;
243 case 16:
244 *(((short*)data) + i) = atoi(argv[3 + i]);
245 break;
246 case 32:
247 *(((long*)data) + i) = atoi(argv[3 + i]);
248 break;
249 }
250 }
251
252 XChangeDeviceProperty(dpy, dev, prop, XA_INTEGER, format, PropModeReplace,
253 (unsigned char*)data, nelements);
254
255 free(data);
256 XCloseDevice(dpy, dev);
257 return EXIT_SUCCESS;
258 }
259
260 int
261 set_float_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
262 {
263 XDeviceInfo *info;
264 XDevice *dev;
265 Atom prop, float_atom;
266 char *name;
267 int i;
268 long *data;
269 int nelements = 0;
270 char* endptr;
271
272 if (argc < 2)
273 {
274 fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
275 return EXIT_FAILURE;
276 }
277
278 info = find_device_info(dpy, argv[0], False);
279 if (!info)
280 {
281 fprintf(stderr, "unable to find device %s\n", argv[0]);
282 return EXIT_FAILURE;
283 }
284
285 dev = XOpenDevice(dpy, info->id);
286 if (!dev)
287 {
288 fprintf(stderr, "unable to open device %s\n", argv[0]);
289 return EXIT_FAILURE;
290 }
291
292 name = argv[1];
293
294 prop = parse_atom(dpy, name);
295
296 nelements = argc - 2;
297
298 float_atom = XInternAtom(dpy, "FLOAT", False);
299
300 if (float_atom == (Atom)0)
301 {
302 fprintf(stderr, "no FLOAT atom present in server\n");
303 return EXIT_FAILURE;
304 }
305
306 if (sizeof(float) != 4)
307 {
308 fprintf(stderr, "sane FP required\n");
309 return EXIT_FAILURE;
310 }
311
312 data = calloc(nelements, sizeof(long));
313 for (i = 0; i < nelements; i++)
314 {
315 *((float*)(data + i)) = strtod(argv[2 + i], &endptr);
316 if(endptr == argv[2 + i]){
317 fprintf(stderr, "argument %s could not be parsed\n", argv[2 + i]);
318 return EXIT_FAILURE;
319 }
320 }
321
322 XChangeDeviceProperty(dpy, dev, prop, float_atom, 32, PropModeReplace,
323 (unsigned char*)data, nelements);
324
325 free(data);
326 XCloseDevice(dpy, dev);
327 return EXIT_SUCCESS;
328 }
329
330
331 int watch_props(Display *dpy, int argc, char** argv, char* n, char *desc)
332 {
333 XDevice *dev;
334 XDeviceInfo *info;
335 XEvent ev;
336 XDevicePropertyNotifyEvent *dpev;
337 char *name;
338 int type_prop;
339 XEventClass cls_prop;
340
341 if (list_props(dpy, argc, argv, n, desc) != EXIT_SUCCESS)
342 return EXIT_FAILURE;
343
344 info = find_device_info(dpy, argv[0], False);
345 if (!info)
346 {
347 fprintf(stderr, "unable to find device %s\n", argv[0]);
348 return EXIT_FAILURE;
349 }
350
351 dev = XOpenDevice(dpy, info->id);
352 if (!dev)
353 {
354 fprintf(stderr, "unable to open device '%s'\n", info->name);
355 return EXIT_FAILURE;
356 }
357
358 DevicePropertyNotify(dev, type_prop, cls_prop);
359 XSelectExtensionEvent(dpy, DefaultRootWindow(dpy), &cls_prop, 1);
360
361 while(1)
362 {
363 XNextEvent(dpy, &ev);
364
365 dpev = (XDevicePropertyNotifyEvent*)&ev;
366 if (dpev->type != type_prop)
367 continue;
368
369 name = XGetAtomName(dpy, dpev->atom);
370 printf("Property '%s' changed.\n", name);
371 print_property(dpy, dev, dpev->atom);
372 }
373
374 XCloseDevice(dpy, dev);
375 }
376
377 int delete_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
378 {
379 XDevice *dev;
380 XDeviceInfo *info;
381 char *name;
382 Atom prop;
383
384 info = find_device_info(dpy, argv[0], False);
385 if (!info)
386 {
387 fprintf(stderr, "unable to find device %s\n", argv[0]);
388 return EXIT_FAILURE;
389 }
390
391 dev = XOpenDevice(dpy, info->id);
392 if (!dev)
393 {
394 fprintf(stderr, "unable to open device '%s'\n", info->name);
395 return EXIT_FAILURE;
396 }
397
398 name = argv[1];
399
400 prop = parse_atom(dpy, name);
401
402 XDeleteDeviceProperty(dpy, dev, prop);
403
404 XCloseDevice(dpy, dev);
405 return EXIT_SUCCESS;
406 }
407
408 int
409 set_atom_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
410 {
411 XDeviceInfo *info;
412 XDevice *dev;
413 Atom prop;
414 char *name;
415 int i, j;
416 Bool is_atom;
417 Atom *data;
418 int nelements = 0;
419
420 if (argc < 3)
421 {
422 fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
423 return EXIT_FAILURE;
424 }
425
426 info = find_device_info(dpy, argv[0], False);
427 if (!info)
428 {
429 fprintf(stderr, "unable to find device %s\n", argv[0]);
430 return EXIT_FAILURE;
431 }
432
433 dev = XOpenDevice(dpy, info->id);
434 if (!dev)
435 {
436 fprintf(stderr, "unable to open device %s\n", argv[0]);
437 return EXIT_FAILURE;
438 }
439
440 name = argv[1];
441
442 prop = parse_atom(dpy, name);
443
444 nelements = argc - 2;
445 data = calloc(nelements, sizeof(Atom));
446 for (i = 0; i < nelements; i++)
447 {
448 is_atom = True;
449 name = argv[2 + i];
450 for(j = 0; j < strlen(name); j++) {
451 if (!isdigit(name[j])) {
452 is_atom = False;
453 break;
454 }
455 }
456
457 if (!is_atom)
458 data[i] = XInternAtom(dpy, name, False);
459 else
460 {
461 data[i] = atoi(name);
462 XFree(XGetAtomName(dpy, data[i]));
463 }
464 }
465
466 XChangeDeviceProperty(dpy, dev, prop, XA_ATOM, 32, PropModeReplace,
467 (unsigned char*)data, nelements);
468
469 free(data);
470 XCloseDevice(dpy, dev);
471 return EXIT_SUCCESS;
472 }
473
474 int
475 set_prop(Display *dpy, int argc, char **argv, char *n, char *desc)
476 {
477 XDeviceInfo *info;
478 XDevice *dev;
479 Atom prop;
480 Atom type;
481 char *name;
482 int i;
483 Atom float_atom;
484 int format, nelements = 0;
485 unsigned long act_nitems, bytes_after;
486 char *endptr;
487 union {
488 unsigned char *c;
489 short *s;
490 long *l;
491 Atom *a;
492 } data;
493
494 if (argc < 3)
495 {
496 fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
497 return EXIT_FAILURE;
498 }
499
500 info = find_device_info(dpy, argv[0], False);
501 if (!info)
502 {
503 fprintf(stderr, "unable to find device %s\n", argv[0]);
504 return EXIT_FAILURE;
505 }
506
507 dev = XOpenDevice(dpy, info->id);
508 if (!dev)
509 {
510 fprintf(stderr, "unable to open device %s\n", argv[0]);
511 return EXIT_FAILURE;
512 }
513
514 name = argv[1];
515
516 prop = parse_atom(dpy, name);
517
518 if (prop == None) {
519 fprintf(stderr, "invalid property %s\n", name);
520 return EXIT_FAILURE;
521 }
522
523 float_atom = XInternAtom(dpy, "FLOAT", False);
524
525 nelements = argc - 2;
526 if (XGetDeviceProperty(dpy, dev, prop, 0, 0, False, AnyPropertyType,
527 &type, &format, &act_nitems, &bytes_after, &data.c)
528 != Success) {
529 fprintf(stderr, "failed to get property type and format for %s\n", name);
530 return EXIT_FAILURE;
531 }
532
533 XFree(data.c);
534
535 if (type == None) {
536 fprintf(stderr, "property %s doesn't exist\n", name);
537 return EXIT_FAILURE;
538 }
539
540 data.c = calloc(nelements, sizeof(long));
541
542 for (i = 0; i < nelements; i++)
543 {
544 if (type == XA_INTEGER) {
545 switch (format)
546 {
547 case 8:
548 data.c[i] = atoi(argv[2 + i]);
549 break;
550 case 16:
551 data.s[i] = atoi(argv[2 + i]);
552 break;
553 case 32:
554 data.l[i] = atoi(argv[2 + i]);
555 break;
556 default:
557 fprintf(stderr, "unexpected size for property %s", name);
558 return EXIT_FAILURE;
559 }
560 } else if (type == float_atom) {
561 if (format != 32) {
562 fprintf(stderr, "unexpected format %d for property %s\n",
563 format, name);
564 return EXIT_FAILURE;
565 }
566 *(float *)(data.l + i) = strtod(argv[2 + i], &endptr);
567 if (endptr == argv[2 + i]) {
568 fprintf(stderr, "argument %s could not be parsed\n", argv[2 + i]);
569 return EXIT_FAILURE;
570 }
571 } else if (type == XA_ATOM) {
572 if (format != 32) {
573 fprintf(stderr, "unexpected format %d for property %s\n",
574 format, name);
575 return EXIT_FAILURE;
576 }
577 data.a[i] = parse_atom(dpy, argv[2 + i]);
578 } else {
579 fprintf(stderr, "unexpected type for property %s\n", name);
580 return EXIT_FAILURE;
581 }
582 }
583
584 XChangeDeviceProperty(dpy, dev, prop, type, format, PropModeReplace,
585 data.c, nelements);
586 free(data.c);
587 XCloseDevice(dpy, dev);
588 return EXIT_SUCCESS;
589 }