property.c revision d3263506
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
37static void
38print_property(Display *dpy, XDevice* dev, Atom property)
39{
40    Atom                act_type;
41    char                *name;
42    int                 act_format;
43    unsigned long       nitems, bytes_after;
44    unsigned char       *data, *ptr;
45    int                 j, done = False, size;
46
47    name = XGetAtomName(dpy, property);
48    printf("\t%s (%ld):\t", name, property);
49
50    if (XGetDeviceProperty(dpy, dev, property, 0, 1000, False,
51                           AnyPropertyType, &act_type, &act_format,
52                           &nitems, &bytes_after, &data) == Success)
53    {
54        Atom float_atom = XInternAtom(dpy, "FLOAT", True);
55
56        ptr = data;
57
58        switch(act_format)
59        {
60            case 8: size = sizeof(char); break;
61            case 16: size = sizeof(short); break;
62            case 32: size = sizeof(long); break;
63        }
64
65        for (j = 0; j < nitems; j++)
66        {
67            switch(act_type)
68            {
69                case XA_INTEGER:
70                    switch(act_format)
71                    {
72                        case 8:
73                            printf("%d", *((char*)ptr));
74                            break;
75                        case 16:
76                            printf("%d", *((short*)ptr));
77                            break;
78                        case 32:
79                            printf("%ld", *((long*)ptr));
80                            break;
81                    }
82                    break;
83                case XA_STRING:
84                    if (act_format != 8)
85                    {
86                        printf("Unknown string format.\n");
87                        done = True;
88                        break;
89                    }
90                    printf("\"%s\"", ptr);
91                    j += strlen((char*)ptr); /* The loop's j++ jumps over the
92                                                terminating 0 */
93                    ptr += strlen((char*)ptr); /* ptr += size below jumps over
94                                                  the terminating 0 */
95                    break;
96                case XA_ATOM:
97                    printf("\"%s\"", XGetAtomName(dpy, *(Atom*)ptr));
98                    break;
99                default:
100                    if (float_atom != None && act_type == float_atom)
101                    {
102                        printf("%f", *((float*)ptr));
103                        break;
104                    }
105
106                    printf("\t... of unknown type %s\n",
107                            XGetAtomName(dpy, act_type));
108                    done = True;
109                    break;
110            }
111
112            ptr += size;
113
114            if (j < nitems - 1)
115                printf(", ");
116            if (done == True)
117                break;
118        }
119        printf("\n");
120        XFree(data);
121    } else
122        printf("\tFetch failure\n");
123
124}
125
126int list_props(Display *dpy, int argc, char** argv, char* name, char *desc)
127{
128    XDeviceInfo *info;
129    XDevice     *dev;
130    int          i;
131    int         nprops;
132    Atom        *props;
133
134    if (argc == 0)
135    {
136        fprintf(stderr, "Usage: xinput %s %s\n", name, desc);
137        return EXIT_FAILURE;
138    }
139
140    for (i = 0; i < argc; i++)
141    {
142        info = find_device_info(dpy, argv[i], False);
143        if (!info)
144        {
145            fprintf(stderr, "unable to find device %s\n", argv[i]);
146            continue;
147        }
148
149        dev = XOpenDevice(dpy, info->id);
150        if (!dev)
151        {
152            fprintf(stderr, "unable to open device '%s'\n", info->name);
153            continue;
154        }
155
156        props = XListDeviceProperties(dpy, dev, &nprops);
157        if (!nprops)
158        {
159            printf("Device '%s' does not report any properties.\n", info->name);
160            continue;
161        }
162
163        printf("Device '%s':\n", info->name);
164        while(nprops--)
165        {
166            print_property(dpy, dev, props[nprops]);
167        }
168
169        XFree(props);
170        XCloseDevice(dpy, dev);
171    }
172    return EXIT_SUCCESS;
173}
174
175int
176set_int_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
177{
178    XDeviceInfo *info;
179    XDevice     *dev;
180    Atom         prop;
181    char        *name;
182    int          i;
183    Bool         is_atom = True;
184    char        *data;
185    int          format, nelements =  0;
186
187    if (argc < 3)
188    {
189        fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
190        return EXIT_FAILURE;
191    }
192
193    info = find_device_info(dpy, argv[0], False);
194    if (!info)
195    {
196        fprintf(stderr, "unable to find device %s\n", argv[0]);
197        return EXIT_FAILURE;
198    }
199
200    dev = XOpenDevice(dpy, info->id);
201    if (!dev)
202    {
203        fprintf(stderr, "unable to open device %s\n", argv[0]);
204        return EXIT_FAILURE;
205    }
206
207    name = argv[1];
208
209    for(i = 0; i < strlen(name); i++) {
210	if (!isdigit(name[i])) {
211            is_atom = False;
212	    break;
213	}
214    }
215
216    if (!is_atom)
217        prop = XInternAtom(dpy, name, False);
218    else
219        prop = atoi(name);
220
221    nelements = argc - 3;
222    format    = atoi(argv[2]);
223    if (format != 8 && format != 16 && format != 32)
224    {
225        fprintf(stderr, "Invalid format %d\n", format);
226        return EXIT_FAILURE;
227    }
228
229    data = calloc(nelements, sizeof(long));
230    for (i = 0; i < nelements; i++)
231    {
232        switch(format)
233        {
234            case 8:
235                *(((char*)data) + i) = atoi(argv[3 + i]);
236                break;
237            case 16:
238                *(((short*)data) + i) = atoi(argv[3 + i]);
239                break;
240            case 32:
241                *(((long*)data) + i) = atoi(argv[3 + i]);
242                break;
243        }
244    }
245
246    XChangeDeviceProperty(dpy, dev, prop, XA_INTEGER, format, PropModeReplace,
247                          (unsigned char*)data, nelements);
248
249    free(data);
250    XCloseDevice(dpy, dev);
251    return EXIT_SUCCESS;
252}
253
254int
255set_float_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
256{
257    XDeviceInfo *info;
258    XDevice     *dev;
259    Atom         prop, float_atom;
260    char        *name;
261    int          i;
262    Bool         is_atom = True;
263    long        *data;
264    int          nelements =  0;
265    char*        endptr;
266
267    if (argc < 2)
268    {
269        fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
270        return EXIT_FAILURE;
271    }
272
273    info = find_device_info(dpy, argv[0], False);
274    if (!info)
275    {
276        fprintf(stderr, "unable to find device %s\n", argv[0]);
277        return EXIT_FAILURE;
278    }
279
280    dev = XOpenDevice(dpy, info->id);
281    if (!dev)
282    {
283        fprintf(stderr, "unable to open device %s\n", argv[0]);
284        return EXIT_FAILURE;
285    }
286
287    name = argv[1];
288
289    for(i = 0; i < strlen(name); i++) {
290	if (!isdigit(name[i])) {
291            is_atom = False;
292	    break;
293	}
294    }
295
296    if (!is_atom)
297        prop = XInternAtom(dpy, name, False);
298    else
299        prop = atoi(name);
300
301    nelements = argc - 2;
302
303    float_atom = XInternAtom(dpy, "FLOAT", False);
304
305    if (float_atom == (Atom)0)
306    {
307	fprintf(stderr, "no FLOAT atom present in server\n");
308	return EXIT_FAILURE;
309    }
310
311    if (sizeof(float) != 4)
312    {
313	fprintf(stderr, "sane FP required\n");
314	return EXIT_FAILURE;
315    }
316
317    data = calloc(nelements, sizeof(long));
318    for (i = 0; i < nelements; i++)
319    {
320        *((float*)(data + i)) = strtod(argv[2 + i], &endptr);
321	if(endptr == argv[2 + i]){
322	    fprintf(stderr, "argument %s could not be parsed\n", argv[2 + i]);
323	    return EXIT_FAILURE;
324	}
325    }
326
327    XChangeDeviceProperty(dpy, dev, prop, float_atom, 32, PropModeReplace,
328                          (unsigned char*)data, nelements);
329
330    free(data);
331    XCloseDevice(dpy, dev);
332    return EXIT_SUCCESS;
333}
334
335
336int watch_props(Display *dpy, int argc, char** argv, char* n, char *desc)
337{
338    XDevice     *dev;
339    XDeviceInfo *info;
340    XEvent      ev;
341    XDevicePropertyNotifyEvent *dpev;
342    char        *name;
343    int         type_prop;
344    XEventClass cls_prop;
345
346    if (list_props(dpy, argc, argv, n, desc) != EXIT_SUCCESS)
347        return EXIT_FAILURE;
348
349    info = find_device_info(dpy, argv[0], False);
350    if (!info)
351    {
352        fprintf(stderr, "unable to find device %s\n", argv[0]);
353        return EXIT_FAILURE;
354    }
355
356    dev = XOpenDevice(dpy, info->id);
357    if (!dev)
358    {
359        fprintf(stderr, "unable to open device '%s'\n", info->name);
360        return EXIT_FAILURE;
361    }
362
363    DevicePropertyNotify(dev, type_prop, cls_prop);
364    XSelectExtensionEvent(dpy, DefaultRootWindow(dpy), &cls_prop, 1);
365
366    while(1)
367    {
368        XNextEvent(dpy, &ev);
369
370        dpev = (XDevicePropertyNotifyEvent*)&ev;
371        if (dpev->type != type_prop)
372            continue;
373
374        name = XGetAtomName(dpy, dpev->atom);
375        printf("Property '%s' changed.\n", name);
376        print_property(dpy, dev, dpev->atom);
377    }
378
379    XCloseDevice(dpy, dev);
380}
381
382int delete_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
383{
384    XDevice     *dev;
385    XDeviceInfo *info;
386    char        *name;
387    int         i;
388    Bool        is_atom = True;
389    Atom        prop;
390
391    info = find_device_info(dpy, argv[0], False);
392    if (!info)
393    {
394        fprintf(stderr, "unable to find device %s\n", argv[0]);
395        return EXIT_FAILURE;
396    }
397
398    dev = XOpenDevice(dpy, info->id);
399    if (!dev)
400    {
401        fprintf(stderr, "unable to open device '%s'\n", info->name);
402        return EXIT_FAILURE;
403    }
404
405    name = argv[1];
406
407    for(i = 0; i < strlen(name); i++) {
408	if (!isdigit(name[i])) {
409            is_atom = False;
410	    break;
411	}
412    }
413
414    if (!is_atom)
415        prop = XInternAtom(dpy, name, False);
416    else
417        prop = atoi(name);
418
419    XDeleteDeviceProperty(dpy, dev, prop);
420
421    XCloseDevice(dpy, dev);
422    return EXIT_SUCCESS;
423}
424
425int
426set_atom_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
427{
428    XDeviceInfo *info;
429    XDevice     *dev;
430    Atom         prop;
431    char        *name;
432    int          i, j;
433    Bool         is_atom = True;
434    Atom        *data;
435    int          nelements =  0;
436
437    if (argc < 3)
438    {
439        fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
440        return EXIT_FAILURE;
441    }
442
443    info = find_device_info(dpy, argv[0], False);
444    if (!info)
445    {
446        fprintf(stderr, "unable to find device %s\n", argv[0]);
447        return EXIT_FAILURE;
448    }
449
450    dev = XOpenDevice(dpy, info->id);
451    if (!dev)
452    {
453        fprintf(stderr, "unable to open device %s\n", argv[0]);
454        return EXIT_FAILURE;
455    }
456
457    name = argv[1];
458
459    for(i = 0; i < strlen(name); i++) {
460	if (!isdigit(name[i])) {
461            is_atom = False;
462	    break;
463	}
464    }
465
466    if (!is_atom)
467        prop = XInternAtom(dpy, name, False);
468    else
469        prop = atoi(name);
470
471    nelements = argc - 2;
472    data = calloc(nelements, sizeof(Atom));
473    for (i = 0; i < nelements; i++)
474    {
475        is_atom = True;
476        name = argv[2 + i];
477        for(j = 0; j < strlen(name); j++) {
478            if (!isdigit(name[j])) {
479                is_atom = False;
480                break;
481            }
482        }
483
484        if (!is_atom)
485            data[i] = XInternAtom(dpy, name, False);
486        else
487        {
488            data[i] = atoi(name);
489            XFree(XGetAtomName(dpy, data[i]));
490        }
491    }
492
493    XChangeDeviceProperty(dpy, dev, prop, XA_ATOM, 32, PropModeReplace,
494                          (unsigned char*)data, nelements);
495
496    free(data);
497    XCloseDevice(dpy, dev);
498    return EXIT_SUCCESS;
499}
500
501
502