property.c revision 0309d3b3
15b944e2aSmrg/*
20309d3b3Smrg * Copyright © 2007 Peter Hutterer
30309d3b3Smrg * Copyright © 2009 Red Hat, Inc.
45b944e2aSmrg *
50309d3b3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
60309d3b3Smrg * copy of this software and associated documentation files (the "Software"),
70309d3b3Smrg * to deal in the Software without restriction, including without limitation
80309d3b3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
90309d3b3Smrg * and/or sell copies of the Software, and to permit persons to whom the
100309d3b3Smrg * Software is furnished to do so, subject to the following conditions:
115b944e2aSmrg *
120309d3b3Smrg * The above copyright notice and this permission notice (including the next
130309d3b3Smrg * paragraph) shall be included in all copies or substantial portions of the
140309d3b3Smrg * Software.
155b944e2aSmrg *
160309d3b3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
170309d3b3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
180309d3b3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
190309d3b3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
200309d3b3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
210309d3b3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
220309d3b3Smrg * DEALINGS IN THE SOFTWARE.
235b944e2aSmrg */
245b944e2aSmrg
255b944e2aSmrg#include <ctype.h>
265b944e2aSmrg#include <string.h>
275b944e2aSmrg#include <stdlib.h>
285b944e2aSmrg#include <stdint.h>
295b944e2aSmrg#include <X11/Xatom.h>
305b944e2aSmrg#include <X11/extensions/XIproto.h>
315b944e2aSmrg
325b944e2aSmrg#include "xinput.h"
335b944e2aSmrg
3453719b08Smrgstatic Atom parse_atom(Display *dpy, char *name) {
3553719b08Smrg    Bool is_atom = True;
3653719b08Smrg    int i;
3753719b08Smrg
3853719b08Smrg    for (i = 0; name[i] != '\0'; i++) {
3953719b08Smrg        if (!isdigit(name[i])) {
4053719b08Smrg            is_atom = False;
4153719b08Smrg            break;
4253719b08Smrg        }
4353719b08Smrg    }
4453719b08Smrg
4553719b08Smrg    if (is_atom)
4653719b08Smrg        return atoi(name);
4753719b08Smrg    else
4853719b08Smrg        return XInternAtom(dpy, name, False);
4953719b08Smrg}
5053719b08Smrg
515b944e2aSmrgstatic void
525b944e2aSmrgprint_property(Display *dpy, XDevice* dev, Atom property)
535b944e2aSmrg{
545b944e2aSmrg    Atom                act_type;
555b944e2aSmrg    char                *name;
565b944e2aSmrg    int                 act_format;
575b944e2aSmrg    unsigned long       nitems, bytes_after;
585b944e2aSmrg    unsigned char       *data, *ptr;
590309d3b3Smrg    int                 j, done = False, size = 0;
605b944e2aSmrg
615b944e2aSmrg    name = XGetAtomName(dpy, property);
625b944e2aSmrg    printf("\t%s (%ld):\t", name, property);
635b944e2aSmrg
645b944e2aSmrg    if (XGetDeviceProperty(dpy, dev, property, 0, 1000, False,
655b944e2aSmrg                           AnyPropertyType, &act_type, &act_format,
665b944e2aSmrg                           &nitems, &bytes_after, &data) == Success)
675b944e2aSmrg    {
68d3263506Smrg        Atom float_atom = XInternAtom(dpy, "FLOAT", True);
695b944e2aSmrg
705b944e2aSmrg        ptr = data;
71d3263506Smrg
7253719b08Smrg        if (nitems == 0)
7353719b08Smrg            printf("<no items>");
7453719b08Smrg
75d3263506Smrg        switch(act_format)
76d3263506Smrg        {
77d3263506Smrg            case 8: size = sizeof(char); break;
78d3263506Smrg            case 16: size = sizeof(short); break;
79d3263506Smrg            case 32: size = sizeof(long); break;
80d3263506Smrg        }
815b944e2aSmrg
825b944e2aSmrg        for (j = 0; j < nitems; j++)
835b944e2aSmrg        {
845b944e2aSmrg            switch(act_type)
855b944e2aSmrg            {
865b944e2aSmrg                case XA_INTEGER:
875b944e2aSmrg                    switch(act_format)
885b944e2aSmrg                    {
895b944e2aSmrg                        case 8:
90d3263506Smrg                            printf("%d", *((char*)ptr));
915b944e2aSmrg                            break;
925b944e2aSmrg                        case 16:
93d3263506Smrg                            printf("%d", *((short*)ptr));
945b944e2aSmrg                            break;
955b944e2aSmrg                        case 32:
96d3263506Smrg                            printf("%ld", *((long*)ptr));
975b944e2aSmrg                            break;
985b944e2aSmrg                    }
995b944e2aSmrg                    break;
1000309d3b3Smrg                case XA_CARDINAL:
1010309d3b3Smrg                    switch(act_format)
1020309d3b3Smrg                    {
1030309d3b3Smrg                        case 8:
1040309d3b3Smrg                            printf("%u", *((unsigned char*)ptr));
1050309d3b3Smrg                            break;
1060309d3b3Smrg                        case 16:
1070309d3b3Smrg                            printf("%u", *((unsigned short*)ptr));
1080309d3b3Smrg                            break;
1090309d3b3Smrg                        case 32:
1100309d3b3Smrg                            printf("%lu", *((unsigned long*)ptr));
1110309d3b3Smrg                            break;
1120309d3b3Smrg                    }
1130309d3b3Smrg                    break;
1145b944e2aSmrg                case XA_STRING:
115d3263506Smrg                    if (act_format != 8)
116d3263506Smrg                    {
117d3263506Smrg                        printf("Unknown string format.\n");
118d3263506Smrg                        done = True;
119d3263506Smrg                        break;
120d3263506Smrg                    }
121d3263506Smrg                    printf("\"%s\"", ptr);
122d3263506Smrg                    j += strlen((char*)ptr); /* The loop's j++ jumps over the
123d3263506Smrg                                                terminating 0 */
124d3263506Smrg                    ptr += strlen((char*)ptr); /* ptr += size below jumps over
125d3263506Smrg                                                  the terminating 0 */
1265b944e2aSmrg                    break;
1275b944e2aSmrg                case XA_ATOM:
12853719b08Smrg                    {
12953719b08Smrg                        Atom a = *(Atom*)ptr;
13053719b08Smrg                        printf("\"%s\" (%d)",
13153719b08Smrg                                (a) ? XGetAtomName(dpy, a) : "None",
13253719b08Smrg                                (int)a);
13353719b08Smrg                        break;
13453719b08Smrg                    }
1355b944e2aSmrg                default:
1365b944e2aSmrg                    if (float_atom != None && act_type == float_atom)
1375b944e2aSmrg                    {
138d3263506Smrg                        printf("%f", *((float*)ptr));
1395b944e2aSmrg                        break;
1405b944e2aSmrg                    }
1415b944e2aSmrg
1420309d3b3Smrg                    printf("\t... of unknown type '%s'\n",
1435b944e2aSmrg                            XGetAtomName(dpy, act_type));
144d3263506Smrg                    done = True;
1455b944e2aSmrg                    break;
1465b944e2aSmrg            }
1475b944e2aSmrg
148d3263506Smrg            ptr += size;
1495b944e2aSmrg
150d3263506Smrg            if (done == True)
1515b944e2aSmrg                break;
15253719b08Smrg            if (j < nitems - 1)
15353719b08Smrg                printf(", ");
1545b944e2aSmrg        }
1555b944e2aSmrg        printf("\n");
1565b944e2aSmrg        XFree(data);
1575b944e2aSmrg    } else
1585b944e2aSmrg        printf("\tFetch failure\n");
1595b944e2aSmrg
1605b944e2aSmrg}
1615b944e2aSmrg
16253719b08Smrgstatic int
16353719b08Smrglist_props_xi1(Display *dpy, int argc, char** argv, char* name, char *desc)
1645b944e2aSmrg{
1655b944e2aSmrg    XDeviceInfo *info;
1665b944e2aSmrg    XDevice     *dev;
1675b944e2aSmrg    int          i;
1685b944e2aSmrg    int         nprops;
1695b944e2aSmrg    Atom        *props;
1705b944e2aSmrg
1715b944e2aSmrg    if (argc == 0)
1725b944e2aSmrg    {
1735b944e2aSmrg        fprintf(stderr, "Usage: xinput %s %s\n", name, desc);
1745b944e2aSmrg        return EXIT_FAILURE;
1755b944e2aSmrg    }
1765b944e2aSmrg
1775b944e2aSmrg    for (i = 0; i < argc; i++)
1785b944e2aSmrg    {
1795b944e2aSmrg        info = find_device_info(dpy, argv[i], False);
1805b944e2aSmrg        if (!info)
1815b944e2aSmrg        {
1820309d3b3Smrg            fprintf(stderr, "unable to find device '%s'\n", argv[i]);
1835b944e2aSmrg            continue;
1845b944e2aSmrg        }
1855b944e2aSmrg
1865b944e2aSmrg        dev = XOpenDevice(dpy, info->id);
1875b944e2aSmrg        if (!dev)
1885b944e2aSmrg        {
1895b944e2aSmrg            fprintf(stderr, "unable to open device '%s'\n", info->name);
1905b944e2aSmrg            continue;
1915b944e2aSmrg        }
1925b944e2aSmrg
1935b944e2aSmrg        props = XListDeviceProperties(dpy, dev, &nprops);
1945b944e2aSmrg        if (!nprops)
1955b944e2aSmrg        {
1965b944e2aSmrg            printf("Device '%s' does not report any properties.\n", info->name);
1975b944e2aSmrg            continue;
1985b944e2aSmrg        }
1995b944e2aSmrg
2005b944e2aSmrg        printf("Device '%s':\n", info->name);
2015b944e2aSmrg        while(nprops--)
2025b944e2aSmrg        {
2035b944e2aSmrg            print_property(dpy, dev, props[nprops]);
2045b944e2aSmrg        }
2055b944e2aSmrg
2065b944e2aSmrg        XFree(props);
2075b944e2aSmrg        XCloseDevice(dpy, dev);
2085b944e2aSmrg    }
2095b944e2aSmrg    return EXIT_SUCCESS;
2105b944e2aSmrg}
2115b944e2aSmrg
21253719b08Smrg
21353719b08Smrgint watch_props(Display *dpy, int argc, char** argv, char* n, char *desc)
2145b944e2aSmrg{
2155b944e2aSmrg    XDevice     *dev;
21653719b08Smrg    XDeviceInfo *info;
21753719b08Smrg    XEvent      ev;
21853719b08Smrg    XDevicePropertyNotifyEvent *dpev;
2195b944e2aSmrg    char        *name;
22053719b08Smrg    int         type_prop;
22153719b08Smrg    XEventClass cls_prop;
2225b944e2aSmrg
22353719b08Smrg    if (list_props(dpy, argc, argv, n, desc) != EXIT_SUCCESS)
2245b944e2aSmrg        return EXIT_FAILURE;
2255b944e2aSmrg
2265b944e2aSmrg    info = find_device_info(dpy, argv[0], False);
2275b944e2aSmrg    if (!info)
2285b944e2aSmrg    {
2290309d3b3Smrg        fprintf(stderr, "unable to find device '%s'\n", argv[0]);
2305b944e2aSmrg        return EXIT_FAILURE;
2315b944e2aSmrg    }
2325b944e2aSmrg
2335b944e2aSmrg    dev = XOpenDevice(dpy, info->id);
2345b944e2aSmrg    if (!dev)
2355b944e2aSmrg    {
23653719b08Smrg        fprintf(stderr, "unable to open device '%s'\n", info->name);
2375b944e2aSmrg        return EXIT_FAILURE;
2385b944e2aSmrg    }
2395b944e2aSmrg
24053719b08Smrg    DevicePropertyNotify(dev, type_prop, cls_prop);
24153719b08Smrg    XSelectExtensionEvent(dpy, DefaultRootWindow(dpy), &cls_prop, 1);
2425b944e2aSmrg
24353719b08Smrg    while(1)
24453719b08Smrg    {
24553719b08Smrg        XNextEvent(dpy, &ev);
24653719b08Smrg
24753719b08Smrg        dpev = (XDevicePropertyNotifyEvent*)&ev;
24853719b08Smrg        if (dpev->type != type_prop)
24953719b08Smrg            continue;
25053719b08Smrg
25153719b08Smrg        name = XGetAtomName(dpy, dpev->atom);
25253719b08Smrg        printf("Property '%s' changed.\n", name);
25353719b08Smrg        print_property(dpy, dev, dpev->atom);
2545b944e2aSmrg    }
2555b944e2aSmrg
25653719b08Smrg    XCloseDevice(dpy, dev);
25753719b08Smrg}
2585b944e2aSmrg
25953719b08Smrgstatic int
26053719b08Smrgdelete_prop_xi1(Display *dpy, int argc, char** argv, char* n, char *desc)
26153719b08Smrg{
26253719b08Smrg    XDevice     *dev;
26353719b08Smrg    XDeviceInfo *info;
26453719b08Smrg    char        *name;
26553719b08Smrg    Atom        prop;
26653719b08Smrg
26753719b08Smrg    info = find_device_info(dpy, argv[0], False);
26853719b08Smrg    if (!info)
2695b944e2aSmrg    {
2700309d3b3Smrg        fprintf(stderr, "unable to find device '%s'\n", argv[0]);
2715b944e2aSmrg        return EXIT_FAILURE;
2725b944e2aSmrg    }
2735b944e2aSmrg
27453719b08Smrg    dev = XOpenDevice(dpy, info->id);
27553719b08Smrg    if (!dev)
2765b944e2aSmrg    {
27753719b08Smrg        fprintf(stderr, "unable to open device '%s'\n", info->name);
27853719b08Smrg        return EXIT_FAILURE;
2795b944e2aSmrg    }
2805b944e2aSmrg
28153719b08Smrg    name = argv[1];
28253719b08Smrg
28353719b08Smrg    prop = parse_atom(dpy, name);
28453719b08Smrg
28553719b08Smrg    XDeleteDeviceProperty(dpy, dev, prop);
2865b944e2aSmrg
2875b944e2aSmrg    XCloseDevice(dpy, dev);
2885b944e2aSmrg    return EXIT_SUCCESS;
2895b944e2aSmrg}
2905b944e2aSmrg
29153719b08Smrgstatic int
29253719b08Smrgdo_set_prop_xi1(Display *dpy, Atom type, int format, int argc, char **argv, char *n, char *desc)
2935b944e2aSmrg{
29453719b08Smrg    XDeviceInfo  *info;
29553719b08Smrg    XDevice      *dev;
29653719b08Smrg    Atom          prop;
29753719b08Smrg    Atom          old_type;
29853719b08Smrg    char         *name;
29953719b08Smrg    int           i;
30053719b08Smrg    Atom          float_atom;
30153719b08Smrg    int           old_format, nelements = 0;
30253719b08Smrg    unsigned long act_nitems, bytes_after;
30353719b08Smrg    char         *endptr;
30453719b08Smrg    union {
30553719b08Smrg        unsigned char *c;
30653719b08Smrg        short *s;
30753719b08Smrg        long *l;
30853719b08Smrg        Atom *a;
30953719b08Smrg    } data;
3105b944e2aSmrg
31153719b08Smrg    if (argc < 3)
3125b944e2aSmrg    {
3135b944e2aSmrg        fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
3145b944e2aSmrg        return EXIT_FAILURE;
3155b944e2aSmrg    }
3165b944e2aSmrg
3175b944e2aSmrg    info = find_device_info(dpy, argv[0], False);
3185b944e2aSmrg    if (!info)
3195b944e2aSmrg    {
3200309d3b3Smrg        fprintf(stderr, "unable to find device '%s'\n", argv[0]);
3215b944e2aSmrg        return EXIT_FAILURE;
3225b944e2aSmrg    }
3235b944e2aSmrg
3245b944e2aSmrg    dev = XOpenDevice(dpy, info->id);
3255b944e2aSmrg    if (!dev)
3265b944e2aSmrg    {
3270309d3b3Smrg        fprintf(stderr, "unable to open device '%s'\n", argv[0]);
3285b944e2aSmrg        return EXIT_FAILURE;
3295b944e2aSmrg    }
3305b944e2aSmrg
3315b944e2aSmrg    name = argv[1];
3325b944e2aSmrg
33353719b08Smrg    prop = parse_atom(dpy, name);
33453719b08Smrg
33553719b08Smrg    if (prop == None) {
3360309d3b3Smrg        fprintf(stderr, "invalid property '%s'\n", name);
33753719b08Smrg        return EXIT_FAILURE;
3385b944e2aSmrg    }
3395b944e2aSmrg
34053719b08Smrg    float_atom = XInternAtom(dpy, "FLOAT", False);
3415b944e2aSmrg
3425b944e2aSmrg    nelements = argc - 2;
34353719b08Smrg    if (type == None || format == 0) {
34453719b08Smrg        if (XGetDeviceProperty(dpy, dev, prop, 0, 0, False, AnyPropertyType,
34553719b08Smrg                               &old_type, &old_format, &act_nitems,
34653719b08Smrg                               &bytes_after, &data.c) != Success) {
3470309d3b3Smrg            fprintf(stderr, "failed to get property type and format for '%s'\n",
34853719b08Smrg                    name);
34953719b08Smrg            return EXIT_FAILURE;
35053719b08Smrg        } else {
35153719b08Smrg            if (type == None)
35253719b08Smrg                type = old_type;
35353719b08Smrg            if (format == 0)
35453719b08Smrg                format = old_format;
35553719b08Smrg        }
3565b944e2aSmrg
35753719b08Smrg        XFree(data.c);
3585b944e2aSmrg    }
3595b944e2aSmrg
36053719b08Smrg    if (type == None) {
3610309d3b3Smrg        fprintf(stderr, "property '%s' doesn't exist, you need to specify "
36253719b08Smrg                "its type and format\n", name);
36353719b08Smrg        return EXIT_FAILURE;
3645b944e2aSmrg    }
3655b944e2aSmrg
36653719b08Smrg    data.c = calloc(nelements, sizeof(long));
36753719b08Smrg
3685b944e2aSmrg    for (i = 0; i < nelements; i++)
3695b944e2aSmrg    {
3700309d3b3Smrg        if (type == XA_INTEGER || type == XA_CARDINAL) {
37153719b08Smrg            switch (format)
37253719b08Smrg            {
37353719b08Smrg                case 8:
37453719b08Smrg                    data.c[i] = atoi(argv[2 + i]);
37553719b08Smrg                    break;
37653719b08Smrg                case 16:
37753719b08Smrg                    data.s[i] = atoi(argv[2 + i]);
37853719b08Smrg                    break;
37953719b08Smrg                case 32:
38053719b08Smrg                    data.l[i] = atoi(argv[2 + i]);
38153719b08Smrg                    break;
38253719b08Smrg                default:
3830309d3b3Smrg                    fprintf(stderr, "unexpected size for property '%s'", name);
38453719b08Smrg                    return EXIT_FAILURE;
38553719b08Smrg            }
38653719b08Smrg        } else if (type == float_atom) {
38753719b08Smrg            if (format != 32) {
3880309d3b3Smrg                fprintf(stderr, "unexpected format %d for property '%s'\n",
38953719b08Smrg                        format, name);
39053719b08Smrg                return EXIT_FAILURE;
39153719b08Smrg            }
39253719b08Smrg            *(float *)(data.l + i) = strtod(argv[2 + i], &endptr);
39353719b08Smrg            if (endptr == argv[2 + i]) {
3940309d3b3Smrg                fprintf(stderr, "argument '%s' could not be parsed\n", argv[2 + i]);
39553719b08Smrg                return EXIT_FAILURE;
39653719b08Smrg            }
39753719b08Smrg        } else if (type == XA_ATOM) {
39853719b08Smrg            if (format != 32) {
3990309d3b3Smrg                fprintf(stderr, "unexpected format %d for property '%s'\n",
40053719b08Smrg                        format, name);
40153719b08Smrg                return EXIT_FAILURE;
40253719b08Smrg            }
40353719b08Smrg            data.a[i] = parse_atom(dpy, argv[2 + i]);
40453719b08Smrg        } else {
4050309d3b3Smrg            fprintf(stderr, "unexpected type for property '%s'\n", name);
40653719b08Smrg            return EXIT_FAILURE;
40753719b08Smrg        }
4085b944e2aSmrg    }
4095b944e2aSmrg
41053719b08Smrg    XChangeDeviceProperty(dpy, dev, prop, type, format, PropModeReplace,
41153719b08Smrg                          data.c, nelements);
41253719b08Smrg    free(data.c);
4135b944e2aSmrg    XCloseDevice(dpy, dev);
4145b944e2aSmrg    return EXIT_SUCCESS;
4155b944e2aSmrg}
4165b944e2aSmrg
41753719b08Smrg#if HAVE_XI2
41853719b08Smrgstatic void
41953719b08Smrgprint_property_xi2(Display *dpy, int deviceid, Atom property)
4205b944e2aSmrg{
42153719b08Smrg    Atom                act_type;
42253719b08Smrg    char                *name;
42353719b08Smrg    int                 act_format;
42453719b08Smrg    unsigned long       nitems, bytes_after;
42553719b08Smrg    unsigned char       *data, *ptr;
42653719b08Smrg    int                 j, done = False;
4275b944e2aSmrg
42853719b08Smrg    name = XGetAtomName(dpy, property);
42953719b08Smrg    printf("\t%s (%ld):\t", name, property);
4305b944e2aSmrg
43153719b08Smrg    if (XIGetProperty(dpy, deviceid, property, 0, 1000, False,
43253719b08Smrg                           AnyPropertyType, &act_type, &act_format,
43353719b08Smrg                           &nitems, &bytes_after, &data) == Success)
4345b944e2aSmrg    {
43553719b08Smrg        Atom float_atom = XInternAtom(dpy, "FLOAT", True);
4365b944e2aSmrg
43753719b08Smrg        ptr = data;
43853719b08Smrg
43953719b08Smrg        if (nitems == 0)
44053719b08Smrg            printf("<no items>");
44153719b08Smrg
44253719b08Smrg        for (j = 0; j < nitems; j++)
44353719b08Smrg        {
44453719b08Smrg            switch(act_type)
44553719b08Smrg            {
44653719b08Smrg                case XA_INTEGER:
44753719b08Smrg                    switch(act_format)
44853719b08Smrg                    {
44953719b08Smrg                        case 8:
45053719b08Smrg                            printf("%d", *((int8_t*)ptr));
45153719b08Smrg                            break;
45253719b08Smrg                        case 16:
45353719b08Smrg                            printf("%d", *((int16_t*)ptr));
45453719b08Smrg                            break;
45553719b08Smrg                        case 32:
45653719b08Smrg                            printf("%d", *((int32_t*)ptr));
45753719b08Smrg                            break;
45853719b08Smrg                    }
45953719b08Smrg                    break;
4600309d3b3Smrg                case XA_CARDINAL:
4610309d3b3Smrg                    switch(act_format)
4620309d3b3Smrg                    {
4630309d3b3Smrg                        case 8:
4640309d3b3Smrg                            printf("%u", *((uint8_t*)ptr));
4650309d3b3Smrg                            break;
4660309d3b3Smrg                        case 16:
4670309d3b3Smrg                            printf("%u", *((uint16_t*)ptr));
4680309d3b3Smrg                            break;
4690309d3b3Smrg                        case 32:
4700309d3b3Smrg                            printf("%u", *((uint32_t*)ptr));
4710309d3b3Smrg                            break;
4720309d3b3Smrg                    }
4730309d3b3Smrg                    break;
47453719b08Smrg                case XA_STRING:
47553719b08Smrg                    if (act_format != 8)
47653719b08Smrg                    {
47753719b08Smrg                        printf("Unknown string format.\n");
47853719b08Smrg                        done = True;
47953719b08Smrg                        break;
48053719b08Smrg                    }
48153719b08Smrg                    printf("\"%s\"", ptr);
48253719b08Smrg                    j += strlen((char*)ptr); /* The loop's j++ jumps over the
48353719b08Smrg                                                terminating 0 */
48453719b08Smrg                    ptr += strlen((char*)ptr); /* ptr += size below jumps over
48553719b08Smrg                                                  the terminating 0 */
48653719b08Smrg                    break;
48753719b08Smrg                case XA_ATOM:
48853719b08Smrg                    {
489cea37944Smrg                        Atom a = *(uint32_t*)ptr;
490cea37944Smrg                        printf("\"%s\" (%ld)",
49153719b08Smrg                                (a) ? XGetAtomName(dpy, a) : "None",
492cea37944Smrg                                a);
49353719b08Smrg                        break;
49453719b08Smrg                    }
49553719b08Smrg                    break;
49653719b08Smrg                default:
49753719b08Smrg                    if (float_atom != None && act_type == float_atom)
49853719b08Smrg                    {
49953719b08Smrg                        printf("%f", *((float*)ptr));
50053719b08Smrg                        break;
50153719b08Smrg                    }
50253719b08Smrg
50353719b08Smrg                    printf("\t... of unknown type %s\n",
50453719b08Smrg                            XGetAtomName(dpy, act_type));
50553719b08Smrg                    done = True;
50653719b08Smrg                    break;
50753719b08Smrg            }
50853719b08Smrg
50953719b08Smrg            ptr += act_format/8;
51053719b08Smrg
51153719b08Smrg            if (done == True)
51253719b08Smrg                break;
51353719b08Smrg            if (j < nitems - 1)
51453719b08Smrg                printf(", ");
51553719b08Smrg        }
51653719b08Smrg        printf("\n");
51753719b08Smrg        XFree(data);
51853719b08Smrg    } else
51953719b08Smrg        printf("\tFetch failure\n");
52053719b08Smrg
52153719b08Smrg}
52253719b08Smrg
52353719b08Smrgstatic int
52453719b08Smrglist_props_xi2(Display *dpy, int argc, char** argv, char* name, char *desc)
52553719b08Smrg{
52653719b08Smrg    XIDeviceInfo *info;
52753719b08Smrg    int         i;
52853719b08Smrg    int         nprops;
52953719b08Smrg    Atom        *props;
53053719b08Smrg
53153719b08Smrg    if (argc == 0)
5325b944e2aSmrg    {
53353719b08Smrg        fprintf(stderr, "Usage: xinput %s %s\n", name, desc);
5345b944e2aSmrg        return EXIT_FAILURE;
5355b944e2aSmrg    }
5365b944e2aSmrg
53753719b08Smrg    for (i = 0; i < argc; i++)
5385b944e2aSmrg    {
53953719b08Smrg        info = xi2_find_device_info(dpy, argv[i]);
54053719b08Smrg        if (!info)
54153719b08Smrg        {
54253719b08Smrg            fprintf(stderr, "unable to find device %s\n", argv[i]);
54353719b08Smrg            continue;
54453719b08Smrg        }
5455b944e2aSmrg
54653719b08Smrg        props = XIListProperties(dpy, info->deviceid, &nprops);
54753719b08Smrg        if (!nprops)
54853719b08Smrg        {
54953719b08Smrg            printf("Device '%s' does not report any properties.\n", info->name);
5505b944e2aSmrg            continue;
55153719b08Smrg        }
5525b944e2aSmrg
55353719b08Smrg        printf("Device '%s':\n", info->name);
55453719b08Smrg        while(nprops--)
55553719b08Smrg        {
55653719b08Smrg            print_property_xi2(dpy, info->deviceid, props[nprops]);
55753719b08Smrg        }
5585b944e2aSmrg
55953719b08Smrg        XFree(props);
56053719b08Smrg    }
56153719b08Smrg    return EXIT_SUCCESS;
5625b944e2aSmrg}
5635b944e2aSmrg
56453719b08Smrgstatic int
56553719b08Smrgdelete_prop_xi2(Display *dpy, int argc, char** argv, char* n, char *desc)
5665b944e2aSmrg{
56753719b08Smrg    XIDeviceInfo *info;
5685b944e2aSmrg    char        *name;
5695b944e2aSmrg    Atom        prop;
5705b944e2aSmrg
57153719b08Smrg    info = xi2_find_device_info(dpy, argv[0]);
5725b944e2aSmrg    if (!info)
5735b944e2aSmrg    {
5745b944e2aSmrg        fprintf(stderr, "unable to find device %s\n", argv[0]);
5755b944e2aSmrg        return EXIT_FAILURE;
5765b944e2aSmrg    }
5775b944e2aSmrg
5785b944e2aSmrg    name = argv[1];
5795b944e2aSmrg
58053719b08Smrg    prop = parse_atom(dpy, name);
5815b944e2aSmrg
58253719b08Smrg    XIDeleteProperty(dpy, info->deviceid, prop);
5835b944e2aSmrg
5845b944e2aSmrg    return EXIT_SUCCESS;
5855b944e2aSmrg}
5865b944e2aSmrg
58753719b08Smrgstatic int
58853719b08Smrgdo_set_prop_xi2(Display *dpy, Atom type, int format, int argc, char **argv, char *n, char *desc)
5895b944e2aSmrg{
59053719b08Smrg    XIDeviceInfo *info;
59153719b08Smrg    Atom          prop;
59253719b08Smrg    Atom          old_type;
59353719b08Smrg    char         *name;
59453719b08Smrg    int           i;
59553719b08Smrg    Atom          float_atom;
59653719b08Smrg    int           old_format, nelements = 0;
59753719b08Smrg    unsigned long act_nitems, bytes_after;
59853719b08Smrg    char         *endptr;
59953719b08Smrg    union {
60053719b08Smrg        unsigned char *c;
60153719b08Smrg        int16_t *s;
60253719b08Smrg        int32_t *l;
60353719b08Smrg    } data;
6045b944e2aSmrg
6055b944e2aSmrg    if (argc < 3)
6065b944e2aSmrg    {
6075b944e2aSmrg        fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
6085b944e2aSmrg        return EXIT_FAILURE;
6095b944e2aSmrg    }
6105b944e2aSmrg
61153719b08Smrg    info = xi2_find_device_info(dpy, argv[0]);
6125b944e2aSmrg    if (!info)
6135b944e2aSmrg    {
6145b944e2aSmrg        fprintf(stderr, "unable to find device %s\n", argv[0]);
6155b944e2aSmrg        return EXIT_FAILURE;
6165b944e2aSmrg    }
6175b944e2aSmrg
61853719b08Smrg    name = argv[1];
61953719b08Smrg
62053719b08Smrg    prop = parse_atom(dpy, name);
62153719b08Smrg
62253719b08Smrg    if (prop == None) {
6230309d3b3Smrg        fprintf(stderr, "invalid property '%s'\n", name);
6245b944e2aSmrg        return EXIT_FAILURE;
6255b944e2aSmrg    }
6265b944e2aSmrg
62753719b08Smrg    float_atom = XInternAtom(dpy, "FLOAT", False);
6285b944e2aSmrg
62953719b08Smrg    nelements = argc - 2;
63053719b08Smrg    if (type == None || format == 0) {
63153719b08Smrg        if (XIGetProperty(dpy, info->deviceid, prop, 0, 0, False,
63253719b08Smrg                          AnyPropertyType, &old_type, &old_format, &act_nitems,
63353719b08Smrg                          &bytes_after, &data.c) != Success) {
6340309d3b3Smrg            fprintf(stderr, "failed to get property type and format for '%s'\n",
63553719b08Smrg                    name);
63653719b08Smrg            return EXIT_FAILURE;
63753719b08Smrg        } else {
63853719b08Smrg            if (type == None)
63953719b08Smrg                type = old_type;
64053719b08Smrg            if (format == 0)
64153719b08Smrg                format = old_format;
64253719b08Smrg        }
64353719b08Smrg
64453719b08Smrg        XFree(data.c);
6455b944e2aSmrg    }
6465b944e2aSmrg
64753719b08Smrg    if (type == None) {
6480309d3b3Smrg        fprintf(stderr, "property '%s' doesn't exist, you need to specify "
64953719b08Smrg                "its type and format\n", name);
65053719b08Smrg        return EXIT_FAILURE;
65153719b08Smrg    }
65253719b08Smrg
65353719b08Smrg    data.c = calloc(nelements, sizeof(int32_t));
6545b944e2aSmrg
6555b944e2aSmrg    for (i = 0; i < nelements; i++)
6565b944e2aSmrg    {
6570309d3b3Smrg        if (type == XA_INTEGER || type == XA_CARDINAL) {
65853719b08Smrg            switch (format)
65953719b08Smrg            {
66053719b08Smrg                case 8:
66153719b08Smrg                    data.c[i] = atoi(argv[2 + i]);
66253719b08Smrg                    break;
66353719b08Smrg                case 16:
66453719b08Smrg                    data.s[i] = atoi(argv[2 + i]);
66553719b08Smrg                    break;
66653719b08Smrg                case 32:
66753719b08Smrg                    data.l[i] = atoi(argv[2 + i]);
66853719b08Smrg                    break;
66953719b08Smrg                default:
67053719b08Smrg                    fprintf(stderr, "unexpected size for property %s", name);
67153719b08Smrg                    return EXIT_FAILURE;
67253719b08Smrg            }
67353719b08Smrg        } else if (type == float_atom) {
67453719b08Smrg            if (format != 32) {
6750309d3b3Smrg                fprintf(stderr, "unexpected format %d for property '%s'\n",
67653719b08Smrg                        format, name);
67753719b08Smrg                return EXIT_FAILURE;
67853719b08Smrg            }
67953719b08Smrg            *(float *)(data.l + i) = strtod(argv[2 + i], &endptr);
68053719b08Smrg            if (endptr == argv[2 + i]) {
68153719b08Smrg                fprintf(stderr, "argument %s could not be parsed\n", argv[2 + i]);
68253719b08Smrg                return EXIT_FAILURE;
6835b944e2aSmrg            }
68453719b08Smrg        } else if (type == XA_ATOM) {
68553719b08Smrg            if (format != 32) {
6860309d3b3Smrg                fprintf(stderr, "unexpected format %d for property '%s'\n",
68753719b08Smrg                        format, name);
68853719b08Smrg                return EXIT_FAILURE;
68953719b08Smrg            }
69053719b08Smrg            data.l[i] = parse_atom(dpy, argv[2 + i]);
69153719b08Smrg        } else {
6920309d3b3Smrg            fprintf(stderr, "unexpected type for property '%s'\n", name);
69353719b08Smrg            return EXIT_FAILURE;
6945b944e2aSmrg        }
69553719b08Smrg    }
6965b944e2aSmrg
69753719b08Smrg    XIChangeProperty(dpy, info->deviceid, prop, type, format, PropModeReplace,
69853719b08Smrg                          data.c, nelements);
69953719b08Smrg    free(data.c);
70053719b08Smrg    return EXIT_SUCCESS;
70153719b08Smrg}
70253719b08Smrg#endif
70353719b08Smrg
70453719b08Smrgint list_props(Display *display, int argc, char *argv[], char *name,
70553719b08Smrg               char *desc)
70653719b08Smrg{
70753719b08Smrg#ifdef HAVE_XI2
70853719b08Smrg    if (xinput_version(display) == XI_2_Major)
70953719b08Smrg        return list_props_xi2(display, argc, argv, name, desc);
71053719b08Smrg#endif
71153719b08Smrg    return list_props_xi1(display, argc, argv, name, desc);
71253719b08Smrg
71353719b08Smrg}
71453719b08Smrg
71553719b08Smrgint delete_prop(Display *display, int argc, char *argv[], char *name,
71653719b08Smrg                char *desc)
71753719b08Smrg{
71853719b08Smrg#ifdef HAVE_XI2
71953719b08Smrg    if (xinput_version(display) == XI_2_Major)
72053719b08Smrg        return delete_prop_xi2(display, argc, argv, name, desc);
72153719b08Smrg#endif
72253719b08Smrg    return delete_prop_xi1(display, argc, argv, name, desc);
72353719b08Smrg
72453719b08Smrg}
72553719b08Smrg
72653719b08Smrgstatic int
72753719b08Smrgdo_set_prop(Display *display, Atom type, int format, int argc, char *argv[], char *name, char *desc)
72853719b08Smrg{
72953719b08Smrg#ifdef HAVE_XI2
73053719b08Smrg    if (xinput_version(display) == XI_2_Major)
73153719b08Smrg        return do_set_prop_xi2(display, type, format, argc, argv, name, desc);
73253719b08Smrg#endif
73353719b08Smrg    return do_set_prop_xi1(display, type, format, argc, argv, name, desc);
73453719b08Smrg}
73553719b08Smrg
73653719b08Smrgint
73753719b08Smrgset_atom_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
73853719b08Smrg{
73953719b08Smrg    return do_set_prop(dpy, XA_ATOM, 32, argc, argv, n, desc);
74053719b08Smrg}
74153719b08Smrg
74253719b08Smrgint
74353719b08Smrgset_int_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
74453719b08Smrg{
74553719b08Smrg    int          i;
74653719b08Smrg    int          format;
74753719b08Smrg
74853719b08Smrg    if (argc < 3)
74953719b08Smrg    {
75053719b08Smrg        fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
75153719b08Smrg        return EXIT_FAILURE;
7525b944e2aSmrg    }
7535b944e2aSmrg
75453719b08Smrg    format    = atoi(argv[2]);
75553719b08Smrg    if (format != 8 && format != 16 && format != 32)
75653719b08Smrg    {
75753719b08Smrg        fprintf(stderr, "Invalid format %d\n", format);
75853719b08Smrg        return EXIT_FAILURE;
75953719b08Smrg    }
7605b944e2aSmrg
76153719b08Smrg    for (i = 3; i < argc; i++)
76253719b08Smrg        argv[i - 1] = argv[i];
76353719b08Smrg
76453719b08Smrg    return do_set_prop(dpy, XA_INTEGER, format, argc - 1, argv, n, desc);
7655b944e2aSmrg}
7665b944e2aSmrg
76753719b08Smrgint
76853719b08Smrgset_float_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
76953719b08Smrg{
77053719b08Smrg    Atom float_atom = XInternAtom(dpy, "FLOAT", False);
77153719b08Smrg
77253719b08Smrg    if (sizeof(float) != 4)
77353719b08Smrg    {
77453719b08Smrg	fprintf(stderr, "sane FP required\n");
77553719b08Smrg	return EXIT_FAILURE;
77653719b08Smrg    }
77753719b08Smrg
77853719b08Smrg    return do_set_prop(dpy, float_atom, 32, argc, argv, n, desc);
77953719b08Smrg}
7805b944e2aSmrg
78153719b08Smrgint set_prop(Display *display, int argc, char *argv[], char *name,
78253719b08Smrg             char *desc)
78353719b08Smrg{
78453719b08Smrg    Atom type = None;
78553719b08Smrg    int format = 0;
78653719b08Smrg    int i = 0, j;
78753719b08Smrg
78853719b08Smrg    while (i < argc) {
78953719b08Smrg        char *option = strchr(argv[i], '=');
79053719b08Smrg        /* skip non-option arguments */
79153719b08Smrg        if (strncmp(argv[i], "--", 2) || !option) {
79253719b08Smrg            i++;
79353719b08Smrg            continue;
79453719b08Smrg        }
79553719b08Smrg
79653719b08Smrg        if (!strncmp(argv[i], "--type=", strlen("--type="))) {
79753719b08Smrg            if (!strcmp(option + 1, "int")) {
79853719b08Smrg                type = XA_INTEGER;
79953719b08Smrg            } else if (!strcmp(option + 1, "float")) {
80053719b08Smrg                type = XInternAtom(display, "FLOAT", False);
80153719b08Smrg                format = 32;
80253719b08Smrg            } else if (!strcmp(option + 1, "atom")) {
80353719b08Smrg                type = XA_ATOM;
80453719b08Smrg                format = 32;
80553719b08Smrg            } else {
80653719b08Smrg                fprintf(stderr, "unknown property type %s\n", option + 1);
80753719b08Smrg                return EXIT_FAILURE;
80853719b08Smrg            }
80953719b08Smrg        } else if (!strncmp(argv[i], "--format=", strlen("--format="))) {
81053719b08Smrg            format = atoi(option + 1);
81153719b08Smrg            if (format != 8 && format != 16 && format != 32) {
8120309d3b3Smrg                fprintf(stderr, "invalid property format '%s'\n", option + 1);
81353719b08Smrg                return EXIT_FAILURE;
81453719b08Smrg            }
81553719b08Smrg        } else {
8160309d3b3Smrg            fprintf(stderr, "invalid option '%s'\n", argv[i]);
81753719b08Smrg            return EXIT_FAILURE;
81853719b08Smrg        }
81953719b08Smrg
82053719b08Smrg        for (j = i; j + 1 < argc; j++)
82153719b08Smrg            argv[j] = argv[j + 1];
82253719b08Smrg        argc--;
82353719b08Smrg    }
82453719b08Smrg
82553719b08Smrg    return do_set_prop(display, type, format, argc, argv, name, desc);
82653719b08Smrg}
8270309d3b3Smrg
8280309d3b3Smrgint disable(Display *display, int argc, char *argv[], char *name, char *desc)
8290309d3b3Smrg{
8300309d3b3Smrg    char *new_argv[3] = { argv[0], "Device Enabled", "0" };
8310309d3b3Smrg    return set_prop(display, 3, new_argv, name, desc);
8320309d3b3Smrg}
8330309d3b3Smrg
8340309d3b3Smrgint enable(Display *display, int argc, char *argv[], char *name, char *desc)
8350309d3b3Smrg{
8360309d3b3Smrg    char *new_argv[3] = { argv[0], "Device Enabled", "1" };
8370309d3b3Smrg    return set_prop(display, 3, new_argv, name, desc);
8380309d3b3Smrg}
839