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);
6333734831Smrg    XFree(name);
645b944e2aSmrg
655b944e2aSmrg    if (XGetDeviceProperty(dpy, dev, property, 0, 1000, False,
665b944e2aSmrg                           AnyPropertyType, &act_type, &act_format,
675b944e2aSmrg                           &nitems, &bytes_after, &data) == Success)
685b944e2aSmrg    {
69d3263506Smrg        Atom float_atom = XInternAtom(dpy, "FLOAT", True);
705b944e2aSmrg
715b944e2aSmrg        ptr = data;
72d3263506Smrg
7353719b08Smrg        if (nitems == 0)
7453719b08Smrg            printf("<no items>");
7553719b08Smrg
76d3263506Smrg        switch(act_format)
77d3263506Smrg        {
78d3263506Smrg            case 8: size = sizeof(char); break;
79d3263506Smrg            case 16: size = sizeof(short); break;
80d3263506Smrg            case 32: size = sizeof(long); break;
81d3263506Smrg        }
825b944e2aSmrg
835b944e2aSmrg        for (j = 0; j < nitems; j++)
845b944e2aSmrg        {
855b944e2aSmrg            switch(act_type)
865b944e2aSmrg            {
875b944e2aSmrg                case XA_INTEGER:
885b944e2aSmrg                    switch(act_format)
895b944e2aSmrg                    {
905b944e2aSmrg                        case 8:
91d3263506Smrg                            printf("%d", *((char*)ptr));
925b944e2aSmrg                            break;
935b944e2aSmrg                        case 16:
94d3263506Smrg                            printf("%d", *((short*)ptr));
955b944e2aSmrg                            break;
965b944e2aSmrg                        case 32:
97d3263506Smrg                            printf("%ld", *((long*)ptr));
985b944e2aSmrg                            break;
995b944e2aSmrg                    }
1005b944e2aSmrg                    break;
1010309d3b3Smrg                case XA_CARDINAL:
1020309d3b3Smrg                    switch(act_format)
1030309d3b3Smrg                    {
1040309d3b3Smrg                        case 8:
1050309d3b3Smrg                            printf("%u", *((unsigned char*)ptr));
1060309d3b3Smrg                            break;
1070309d3b3Smrg                        case 16:
1080309d3b3Smrg                            printf("%u", *((unsigned short*)ptr));
1090309d3b3Smrg                            break;
1100309d3b3Smrg                        case 32:
1110309d3b3Smrg                            printf("%lu", *((unsigned long*)ptr));
1120309d3b3Smrg                            break;
1130309d3b3Smrg                    }
1140309d3b3Smrg                    break;
1155b944e2aSmrg                case XA_STRING:
116d3263506Smrg                    if (act_format != 8)
117d3263506Smrg                    {
118d3263506Smrg                        printf("Unknown string format.\n");
119d3263506Smrg                        done = True;
120d3263506Smrg                        break;
121d3263506Smrg                    }
122d3263506Smrg                    printf("\"%s\"", ptr);
123d3263506Smrg                    j += strlen((char*)ptr); /* The loop's j++ jumps over the
124d3263506Smrg                                                terminating 0 */
125d3263506Smrg                    ptr += strlen((char*)ptr); /* ptr += size below jumps over
126d3263506Smrg                                                  the terminating 0 */
1275b944e2aSmrg                    break;
1285b944e2aSmrg                case XA_ATOM:
12953719b08Smrg                    {
13053719b08Smrg                        Atom a = *(Atom*)ptr;
13133734831Smrg                        name = (a) ? XGetAtomName(dpy, a) : NULL;
13233734831Smrg                        printf("\"%s\" (%d)", name ? name : "None", (int)a);
13333734831Smrg                        XFree(name);
13453719b08Smrg                        break;
13553719b08Smrg                    }
1365b944e2aSmrg                default:
1375b944e2aSmrg                    if (float_atom != None && act_type == float_atom)
1385b944e2aSmrg                    {
139d3263506Smrg                        printf("%f", *((float*)ptr));
1405b944e2aSmrg                        break;
1415b944e2aSmrg                    }
1425b944e2aSmrg
14333734831Smrg                    name = XGetAtomName(dpy, act_type);
14433734831Smrg                    printf("\t... of unknown type '%s'\n", name);
14533734831Smrg                    XFree(name);
146d3263506Smrg                    done = True;
1475b944e2aSmrg                    break;
1485b944e2aSmrg            }
1495b944e2aSmrg
150d3263506Smrg            ptr += size;
1515b944e2aSmrg
152d3263506Smrg            if (done == True)
1535b944e2aSmrg                break;
15453719b08Smrg            if (j < nitems - 1)
15553719b08Smrg                printf(", ");
1565b944e2aSmrg        }
1575b944e2aSmrg        printf("\n");
1585b944e2aSmrg        XFree(data);
1595b944e2aSmrg    } else
1605b944e2aSmrg        printf("\tFetch failure\n");
1615b944e2aSmrg
1625b944e2aSmrg}
1635b944e2aSmrg
16453719b08Smrgstatic int
16553719b08Smrglist_props_xi1(Display *dpy, int argc, char** argv, char* name, char *desc)
1665b944e2aSmrg{
1675b944e2aSmrg    XDeviceInfo *info;
1685b944e2aSmrg    XDevice     *dev;
1695b944e2aSmrg    int          i;
1705b944e2aSmrg    int         nprops;
1715b944e2aSmrg    Atom        *props;
172e73734d1Smrg    int         rc = EXIT_SUCCESS;
1735b944e2aSmrg
1745b944e2aSmrg    if (argc == 0)
1755b944e2aSmrg    {
1765b944e2aSmrg        fprintf(stderr, "Usage: xinput %s %s\n", name, desc);
1775b944e2aSmrg        return EXIT_FAILURE;
1785b944e2aSmrg    }
1795b944e2aSmrg
1805b944e2aSmrg    for (i = 0; i < argc; i++)
1815b944e2aSmrg    {
1825b944e2aSmrg        info = find_device_info(dpy, argv[i], False);
1835b944e2aSmrg        if (!info)
1845b944e2aSmrg        {
1850309d3b3Smrg            fprintf(stderr, "unable to find device '%s'\n", argv[i]);
186e73734d1Smrg            rc = EXIT_FAILURE;
1875b944e2aSmrg            continue;
1885b944e2aSmrg        }
1895b944e2aSmrg
1905b944e2aSmrg        dev = XOpenDevice(dpy, info->id);
1915b944e2aSmrg        if (!dev)
1925b944e2aSmrg        {
1935b944e2aSmrg            fprintf(stderr, "unable to open device '%s'\n", info->name);
194e73734d1Smrg            rc = EXIT_FAILURE;
1955b944e2aSmrg            continue;
1965b944e2aSmrg        }
1975b944e2aSmrg
1985b944e2aSmrg        props = XListDeviceProperties(dpy, dev, &nprops);
1995b944e2aSmrg        if (!nprops)
2005b944e2aSmrg        {
2015b944e2aSmrg            printf("Device '%s' does not report any properties.\n", info->name);
2025b944e2aSmrg            continue;
2035b944e2aSmrg        }
2045b944e2aSmrg
2055b944e2aSmrg        printf("Device '%s':\n", info->name);
2065b944e2aSmrg        while(nprops--)
2075b944e2aSmrg        {
2085b944e2aSmrg            print_property(dpy, dev, props[nprops]);
2095b944e2aSmrg        }
2105b944e2aSmrg
2115b944e2aSmrg        XFree(props);
2125b944e2aSmrg        XCloseDevice(dpy, dev);
2135b944e2aSmrg    }
214e73734d1Smrg    return rc;
2155b944e2aSmrg}
2165b944e2aSmrg
21753719b08Smrg
21853719b08Smrgint watch_props(Display *dpy, int argc, char** argv, char* n, char *desc)
2195b944e2aSmrg{
2205b944e2aSmrg    XDevice     *dev;
22153719b08Smrg    XDeviceInfo *info;
22253719b08Smrg    XEvent      ev;
22353719b08Smrg    XDevicePropertyNotifyEvent *dpev;
2245b944e2aSmrg    char        *name;
22553719b08Smrg    int         type_prop;
22653719b08Smrg    XEventClass cls_prop;
2275b944e2aSmrg
22853719b08Smrg    if (list_props(dpy, argc, argv, n, desc) != EXIT_SUCCESS)
2295b944e2aSmrg        return EXIT_FAILURE;
2305b944e2aSmrg
2315b944e2aSmrg    info = find_device_info(dpy, argv[0], False);
2325b944e2aSmrg    if (!info)
2335b944e2aSmrg    {
2340309d3b3Smrg        fprintf(stderr, "unable to find device '%s'\n", argv[0]);
2355b944e2aSmrg        return EXIT_FAILURE;
2365b944e2aSmrg    }
2375b944e2aSmrg
2385b944e2aSmrg    dev = XOpenDevice(dpy, info->id);
2395b944e2aSmrg    if (!dev)
2405b944e2aSmrg    {
24153719b08Smrg        fprintf(stderr, "unable to open device '%s'\n", info->name);
2425b944e2aSmrg        return EXIT_FAILURE;
2435b944e2aSmrg    }
2445b944e2aSmrg
24553719b08Smrg    DevicePropertyNotify(dev, type_prop, cls_prop);
24653719b08Smrg    XSelectExtensionEvent(dpy, DefaultRootWindow(dpy), &cls_prop, 1);
2475b944e2aSmrg
24853719b08Smrg    while(1)
24953719b08Smrg    {
25053719b08Smrg        XNextEvent(dpy, &ev);
25153719b08Smrg
25253719b08Smrg        dpev = (XDevicePropertyNotifyEvent*)&ev;
25353719b08Smrg        if (dpev->type != type_prop)
25453719b08Smrg            continue;
25553719b08Smrg
25653719b08Smrg        name = XGetAtomName(dpy, dpev->atom);
25753719b08Smrg        printf("Property '%s' changed.\n", name);
25833734831Smrg        XFree(name);
25953719b08Smrg        print_property(dpy, dev, dpev->atom);
2605b944e2aSmrg    }
2615b944e2aSmrg
26253719b08Smrg    XCloseDevice(dpy, dev);
26353719b08Smrg}
2645b944e2aSmrg
26553719b08Smrgstatic int
26653719b08Smrgdelete_prop_xi1(Display *dpy, int argc, char** argv, char* n, char *desc)
26753719b08Smrg{
26853719b08Smrg    XDevice     *dev;
26953719b08Smrg    XDeviceInfo *info;
27053719b08Smrg    char        *name;
27153719b08Smrg    Atom        prop;
27253719b08Smrg
27320f5670eSmrg    if (argc < 2)
27420f5670eSmrg    {
27520f5670eSmrg        fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
27620f5670eSmrg        return EXIT_FAILURE;
27720f5670eSmrg    }
27820f5670eSmrg
27953719b08Smrg    info = find_device_info(dpy, argv[0], False);
28053719b08Smrg    if (!info)
2815b944e2aSmrg    {
2820309d3b3Smrg        fprintf(stderr, "unable to find device '%s'\n", argv[0]);
2835b944e2aSmrg        return EXIT_FAILURE;
2845b944e2aSmrg    }
2855b944e2aSmrg
28653719b08Smrg    dev = XOpenDevice(dpy, info->id);
28753719b08Smrg    if (!dev)
2885b944e2aSmrg    {
28953719b08Smrg        fprintf(stderr, "unable to open device '%s'\n", info->name);
29053719b08Smrg        return EXIT_FAILURE;
2915b944e2aSmrg    }
2925b944e2aSmrg
29353719b08Smrg    name = argv[1];
29453719b08Smrg
29553719b08Smrg    prop = parse_atom(dpy, name);
29653719b08Smrg
29753719b08Smrg    XDeleteDeviceProperty(dpy, dev, prop);
2985b944e2aSmrg
2995b944e2aSmrg    XCloseDevice(dpy, dev);
3005b944e2aSmrg    return EXIT_SUCCESS;
3015b944e2aSmrg}
3025b944e2aSmrg
30353719b08Smrgstatic int
30453719b08Smrgdo_set_prop_xi1(Display *dpy, Atom type, int format, int argc, char **argv, char *n, char *desc)
3055b944e2aSmrg{
30653719b08Smrg    XDeviceInfo  *info;
30753719b08Smrg    XDevice      *dev;
30853719b08Smrg    Atom          prop;
30953719b08Smrg    Atom          old_type;
31053719b08Smrg    char         *name;
31153719b08Smrg    int           i;
31253719b08Smrg    Atom          float_atom;
31353719b08Smrg    int           old_format, nelements = 0;
31453719b08Smrg    unsigned long act_nitems, bytes_after;
31553719b08Smrg    char         *endptr;
31653719b08Smrg    union {
31753719b08Smrg        unsigned char *c;
31853719b08Smrg        short *s;
31953719b08Smrg        long *l;
32053719b08Smrg        Atom *a;
32153719b08Smrg    } data;
3225b944e2aSmrg
32353719b08Smrg    if (argc < 3)
3245b944e2aSmrg    {
3255b944e2aSmrg        fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
3265b944e2aSmrg        return EXIT_FAILURE;
3275b944e2aSmrg    }
3285b944e2aSmrg
3295b944e2aSmrg    info = find_device_info(dpy, argv[0], False);
3305b944e2aSmrg    if (!info)
3315b944e2aSmrg    {
3320309d3b3Smrg        fprintf(stderr, "unable to find device '%s'\n", argv[0]);
3335b944e2aSmrg        return EXIT_FAILURE;
3345b944e2aSmrg    }
3355b944e2aSmrg
3365b944e2aSmrg    dev = XOpenDevice(dpy, info->id);
3375b944e2aSmrg    if (!dev)
3385b944e2aSmrg    {
3390309d3b3Smrg        fprintf(stderr, "unable to open device '%s'\n", argv[0]);
3405b944e2aSmrg        return EXIT_FAILURE;
3415b944e2aSmrg    }
3425b944e2aSmrg
3435b944e2aSmrg    name = argv[1];
3445b944e2aSmrg
34553719b08Smrg    prop = parse_atom(dpy, name);
34653719b08Smrg
34753719b08Smrg    if (prop == None) {
3480309d3b3Smrg        fprintf(stderr, "invalid property '%s'\n", name);
34953719b08Smrg        return EXIT_FAILURE;
3505b944e2aSmrg    }
3515b944e2aSmrg
35253719b08Smrg    float_atom = XInternAtom(dpy, "FLOAT", False);
3535b944e2aSmrg
3545b944e2aSmrg    nelements = argc - 2;
35553719b08Smrg    if (type == None || format == 0) {
35653719b08Smrg        if (XGetDeviceProperty(dpy, dev, prop, 0, 0, False, AnyPropertyType,
35753719b08Smrg                               &old_type, &old_format, &act_nitems,
35853719b08Smrg                               &bytes_after, &data.c) != Success) {
3590309d3b3Smrg            fprintf(stderr, "failed to get property type and format for '%s'\n",
36053719b08Smrg                    name);
36153719b08Smrg            return EXIT_FAILURE;
36253719b08Smrg        } else {
36353719b08Smrg            if (type == None)
36453719b08Smrg                type = old_type;
36553719b08Smrg            if (format == 0)
36653719b08Smrg                format = old_format;
36753719b08Smrg        }
3685b944e2aSmrg
36953719b08Smrg        XFree(data.c);
3705b944e2aSmrg    }
3715b944e2aSmrg
37253719b08Smrg    if (type == None) {
3730309d3b3Smrg        fprintf(stderr, "property '%s' doesn't exist, you need to specify "
37453719b08Smrg                "its type and format\n", name);
37553719b08Smrg        return EXIT_FAILURE;
3765b944e2aSmrg    }
3775b944e2aSmrg
37853719b08Smrg    data.c = calloc(nelements, sizeof(long));
37953719b08Smrg
3805b944e2aSmrg    for (i = 0; i < nelements; i++)
3815b944e2aSmrg    {
3820309d3b3Smrg        if (type == XA_INTEGER || type == XA_CARDINAL) {
38353719b08Smrg            switch (format)
38453719b08Smrg            {
38553719b08Smrg                case 8:
38653719b08Smrg                    data.c[i] = atoi(argv[2 + i]);
38753719b08Smrg                    break;
38853719b08Smrg                case 16:
38953719b08Smrg                    data.s[i] = atoi(argv[2 + i]);
39053719b08Smrg                    break;
39153719b08Smrg                case 32:
39253719b08Smrg                    data.l[i] = atoi(argv[2 + i]);
39353719b08Smrg                    break;
39453719b08Smrg                default:
3950309d3b3Smrg                    fprintf(stderr, "unexpected size for property '%s'", name);
39653719b08Smrg                    return EXIT_FAILURE;
39753719b08Smrg            }
39853719b08Smrg        } else if (type == float_atom) {
39953719b08Smrg            if (format != 32) {
4000309d3b3Smrg                fprintf(stderr, "unexpected format %d for property '%s'\n",
40153719b08Smrg                        format, name);
40253719b08Smrg                return EXIT_FAILURE;
40353719b08Smrg            }
40453719b08Smrg            *(float *)(data.l + i) = strtod(argv[2 + i], &endptr);
40553719b08Smrg            if (endptr == argv[2 + i]) {
4060309d3b3Smrg                fprintf(stderr, "argument '%s' could not be parsed\n", argv[2 + i]);
40753719b08Smrg                return EXIT_FAILURE;
40853719b08Smrg            }
40953719b08Smrg        } else if (type == XA_ATOM) {
41053719b08Smrg            if (format != 32) {
4110309d3b3Smrg                fprintf(stderr, "unexpected format %d for property '%s'\n",
41253719b08Smrg                        format, name);
41353719b08Smrg                return EXIT_FAILURE;
41453719b08Smrg            }
41553719b08Smrg            data.a[i] = parse_atom(dpy, argv[2 + i]);
41653719b08Smrg        } else {
4170309d3b3Smrg            fprintf(stderr, "unexpected type for property '%s'\n", name);
41853719b08Smrg            return EXIT_FAILURE;
41953719b08Smrg        }
4205b944e2aSmrg    }
4215b944e2aSmrg
42253719b08Smrg    XChangeDeviceProperty(dpy, dev, prop, type, format, PropModeReplace,
42353719b08Smrg                          data.c, nelements);
42453719b08Smrg    free(data.c);
4255b944e2aSmrg    XCloseDevice(dpy, dev);
4265b944e2aSmrg    return EXIT_SUCCESS;
4275b944e2aSmrg}
4285b944e2aSmrg
42953719b08Smrg#if HAVE_XI2
43053719b08Smrgstatic void
43153719b08Smrgprint_property_xi2(Display *dpy, int deviceid, Atom property)
4325b944e2aSmrg{
43353719b08Smrg    Atom                act_type;
43453719b08Smrg    char                *name;
43553719b08Smrg    int                 act_format;
43653719b08Smrg    unsigned long       nitems, bytes_after;
43753719b08Smrg    unsigned char       *data, *ptr;
43853719b08Smrg    int                 j, done = False;
4395b944e2aSmrg
44053719b08Smrg    name = XGetAtomName(dpy, property);
44153719b08Smrg    printf("\t%s (%ld):\t", name, property);
44233734831Smrg    XFree(name);
4435b944e2aSmrg
44453719b08Smrg    if (XIGetProperty(dpy, deviceid, property, 0, 1000, False,
44553719b08Smrg                           AnyPropertyType, &act_type, &act_format,
44653719b08Smrg                           &nitems, &bytes_after, &data) == Success)
4475b944e2aSmrg    {
44853719b08Smrg        Atom float_atom = XInternAtom(dpy, "FLOAT", True);
4495b944e2aSmrg
45053719b08Smrg        ptr = data;
45153719b08Smrg
45253719b08Smrg        if (nitems == 0)
45353719b08Smrg            printf("<no items>");
45453719b08Smrg
45553719b08Smrg        for (j = 0; j < nitems; j++)
45653719b08Smrg        {
45753719b08Smrg            switch(act_type)
45853719b08Smrg            {
45953719b08Smrg                case XA_INTEGER:
46053719b08Smrg                    switch(act_format)
46153719b08Smrg                    {
46253719b08Smrg                        case 8:
46353719b08Smrg                            printf("%d", *((int8_t*)ptr));
46453719b08Smrg                            break;
46553719b08Smrg                        case 16:
46653719b08Smrg                            printf("%d", *((int16_t*)ptr));
46753719b08Smrg                            break;
46853719b08Smrg                        case 32:
46953719b08Smrg                            printf("%d", *((int32_t*)ptr));
47053719b08Smrg                            break;
47153719b08Smrg                    }
47253719b08Smrg                    break;
4730309d3b3Smrg                case XA_CARDINAL:
4740309d3b3Smrg                    switch(act_format)
4750309d3b3Smrg                    {
4760309d3b3Smrg                        case 8:
4770309d3b3Smrg                            printf("%u", *((uint8_t*)ptr));
4780309d3b3Smrg                            break;
4790309d3b3Smrg                        case 16:
4800309d3b3Smrg                            printf("%u", *((uint16_t*)ptr));
4810309d3b3Smrg                            break;
4820309d3b3Smrg                        case 32:
4830309d3b3Smrg                            printf("%u", *((uint32_t*)ptr));
4840309d3b3Smrg                            break;
4850309d3b3Smrg                    }
4860309d3b3Smrg                    break;
48753719b08Smrg                case XA_STRING:
48853719b08Smrg                    if (act_format != 8)
48953719b08Smrg                    {
49053719b08Smrg                        printf("Unknown string format.\n");
49153719b08Smrg                        done = True;
49253719b08Smrg                        break;
49353719b08Smrg                    }
49453719b08Smrg                    printf("\"%s\"", ptr);
49553719b08Smrg                    j += strlen((char*)ptr); /* The loop's j++ jumps over the
49653719b08Smrg                                                terminating 0 */
49753719b08Smrg                    ptr += strlen((char*)ptr); /* ptr += size below jumps over
49853719b08Smrg                                                  the terminating 0 */
49953719b08Smrg                    break;
50053719b08Smrg                case XA_ATOM:
50153719b08Smrg                    {
502cea37944Smrg                        Atom a = *(uint32_t*)ptr;
50333734831Smrg                        name = (a) ? XGetAtomName(dpy, a) : NULL;
50433734831Smrg                        printf("\"%s\" (%ld)", name ? name : "None", a);
50533734831Smrg                        XFree(name);
50653719b08Smrg                        break;
50753719b08Smrg                    }
50853719b08Smrg                    break;
50953719b08Smrg                default:
51053719b08Smrg                    if (float_atom != None && act_type == float_atom)
51153719b08Smrg                    {
51253719b08Smrg                        printf("%f", *((float*)ptr));
51353719b08Smrg                        break;
51453719b08Smrg                    }
51553719b08Smrg
51633734831Smrg                    name = XGetAtomName(dpy, act_type);
51733734831Smrg                    printf("\t... of unknown type %s\n", name);
51833734831Smrg                    XFree(name);
51953719b08Smrg                    done = True;
52053719b08Smrg                    break;
52153719b08Smrg            }
52253719b08Smrg
52353719b08Smrg            ptr += act_format/8;
52453719b08Smrg
52553719b08Smrg            if (done == True)
52653719b08Smrg                break;
52753719b08Smrg            if (j < nitems - 1)
52853719b08Smrg                printf(", ");
52953719b08Smrg        }
53053719b08Smrg        printf("\n");
53153719b08Smrg        XFree(data);
53253719b08Smrg    } else
53353719b08Smrg        printf("\tFetch failure\n");
53453719b08Smrg
53553719b08Smrg}
53653719b08Smrg
53753719b08Smrgstatic int
53853719b08Smrglist_props_xi2(Display *dpy, int argc, char** argv, char* name, char *desc)
53953719b08Smrg{
54053719b08Smrg    XIDeviceInfo *info;
54153719b08Smrg    int         i;
54253719b08Smrg    int         nprops;
54353719b08Smrg    Atom        *props;
544e73734d1Smrg    int         rc = EXIT_SUCCESS;
54553719b08Smrg
54653719b08Smrg    if (argc == 0)
5475b944e2aSmrg    {
54853719b08Smrg        fprintf(stderr, "Usage: xinput %s %s\n", name, desc);
5495b944e2aSmrg        return EXIT_FAILURE;
5505b944e2aSmrg    }
5515b944e2aSmrg
55253719b08Smrg    for (i = 0; i < argc; i++)
5535b944e2aSmrg    {
55453719b08Smrg        info = xi2_find_device_info(dpy, argv[i]);
55553719b08Smrg        if (!info)
55653719b08Smrg        {
55753719b08Smrg            fprintf(stderr, "unable to find device %s\n", argv[i]);
558e73734d1Smrg            rc = EXIT_FAILURE;
55953719b08Smrg            continue;
56053719b08Smrg        }
5615b944e2aSmrg
56253719b08Smrg        props = XIListProperties(dpy, info->deviceid, &nprops);
56353719b08Smrg        if (!nprops)
56453719b08Smrg        {
56553719b08Smrg            printf("Device '%s' does not report any properties.\n", info->name);
5665b944e2aSmrg            continue;
56753719b08Smrg        }
5685b944e2aSmrg
56953719b08Smrg        printf("Device '%s':\n", info->name);
57053719b08Smrg        while(nprops--)
57153719b08Smrg        {
57253719b08Smrg            print_property_xi2(dpy, info->deviceid, props[nprops]);
57353719b08Smrg        }
5745b944e2aSmrg
57553719b08Smrg        XFree(props);
57653719b08Smrg    }
577e73734d1Smrg    return rc;
5785b944e2aSmrg}
5795b944e2aSmrg
58053719b08Smrgstatic int
58153719b08Smrgdelete_prop_xi2(Display *dpy, int argc, char** argv, char* n, char *desc)
5825b944e2aSmrg{
58353719b08Smrg    XIDeviceInfo *info;
5845b944e2aSmrg    char        *name;
5855b944e2aSmrg    Atom        prop;
5865b944e2aSmrg
58720f5670eSmrg    if (argc < 2)
58820f5670eSmrg    {
58920f5670eSmrg        fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
59020f5670eSmrg        return EXIT_FAILURE;
59120f5670eSmrg    }
59220f5670eSmrg
59353719b08Smrg    info = xi2_find_device_info(dpy, argv[0]);
5945b944e2aSmrg    if (!info)
5955b944e2aSmrg    {
5965b944e2aSmrg        fprintf(stderr, "unable to find device %s\n", argv[0]);
5975b944e2aSmrg        return EXIT_FAILURE;
5985b944e2aSmrg    }
5995b944e2aSmrg
6005b944e2aSmrg    name = argv[1];
6015b944e2aSmrg
60253719b08Smrg    prop = parse_atom(dpy, name);
6035b944e2aSmrg
60453719b08Smrg    XIDeleteProperty(dpy, info->deviceid, prop);
6055b944e2aSmrg
6065b944e2aSmrg    return EXIT_SUCCESS;
6075b944e2aSmrg}
6085b944e2aSmrg
60953719b08Smrgstatic int
61053719b08Smrgdo_set_prop_xi2(Display *dpy, Atom type, int format, int argc, char **argv, char *n, char *desc)
6115b944e2aSmrg{
61253719b08Smrg    XIDeviceInfo *info;
61353719b08Smrg    Atom          prop;
61453719b08Smrg    Atom          old_type;
61553719b08Smrg    char         *name;
61653719b08Smrg    int           i;
61753719b08Smrg    Atom          float_atom;
61853719b08Smrg    int           old_format, nelements = 0;
61953719b08Smrg    unsigned long act_nitems, bytes_after;
62053719b08Smrg    char         *endptr;
62153719b08Smrg    union {
62253719b08Smrg        unsigned char *c;
62353719b08Smrg        int16_t *s;
62453719b08Smrg        int32_t *l;
625a570218aSmrg    } data = { NULL };
626a570218aSmrg    int rc = EXIT_FAILURE;
6275b944e2aSmrg
6285b944e2aSmrg    if (argc < 3)
6295b944e2aSmrg    {
6305b944e2aSmrg        fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
631a570218aSmrg        goto out;
6325b944e2aSmrg    }
6335b944e2aSmrg
63453719b08Smrg    info = xi2_find_device_info(dpy, argv[0]);
6355b944e2aSmrg    if (!info)
6365b944e2aSmrg    {
6375b944e2aSmrg        fprintf(stderr, "unable to find device %s\n", argv[0]);
638a570218aSmrg        goto out;
6395b944e2aSmrg    }
6405b944e2aSmrg
64153719b08Smrg    name = argv[1];
64253719b08Smrg
64353719b08Smrg    prop = parse_atom(dpy, name);
64453719b08Smrg
64553719b08Smrg    if (prop == None) {
6460309d3b3Smrg        fprintf(stderr, "invalid property '%s'\n", name);
647a570218aSmrg        goto out;
6485b944e2aSmrg    }
6495b944e2aSmrg
65053719b08Smrg    float_atom = XInternAtom(dpy, "FLOAT", False);
6515b944e2aSmrg
65253719b08Smrg    nelements = argc - 2;
65353719b08Smrg    if (type == None || format == 0) {
65453719b08Smrg        if (XIGetProperty(dpy, info->deviceid, prop, 0, 0, False,
65553719b08Smrg                          AnyPropertyType, &old_type, &old_format, &act_nitems,
65653719b08Smrg                          &bytes_after, &data.c) != Success) {
6570309d3b3Smrg            fprintf(stderr, "failed to get property type and format for '%s'\n",
65853719b08Smrg                    name);
659a570218aSmrg            goto out;
66053719b08Smrg        } else {
66153719b08Smrg            if (type == None)
66253719b08Smrg                type = old_type;
66353719b08Smrg            if (format == 0)
66453719b08Smrg                format = old_format;
66553719b08Smrg        }
66653719b08Smrg
66753719b08Smrg        XFree(data.c);
6685b944e2aSmrg    }
6695b944e2aSmrg
67053719b08Smrg    if (type == None) {
6710309d3b3Smrg        fprintf(stderr, "property '%s' doesn't exist, you need to specify "
67253719b08Smrg                "its type and format\n", name);
673a570218aSmrg        goto out;
67453719b08Smrg    }
67553719b08Smrg
67653719b08Smrg    data.c = calloc(nelements, sizeof(int32_t));
6775b944e2aSmrg
6785b944e2aSmrg    for (i = 0; i < nelements; i++)
6795b944e2aSmrg    {
6800309d3b3Smrg        if (type == XA_INTEGER || type == XA_CARDINAL) {
68153719b08Smrg            switch (format)
68253719b08Smrg            {
68353719b08Smrg                case 8:
68453719b08Smrg                    data.c[i] = atoi(argv[2 + i]);
68553719b08Smrg                    break;
68653719b08Smrg                case 16:
68753719b08Smrg                    data.s[i] = atoi(argv[2 + i]);
68853719b08Smrg                    break;
68953719b08Smrg                case 32:
69053719b08Smrg                    data.l[i] = atoi(argv[2 + i]);
69153719b08Smrg                    break;
69253719b08Smrg                default:
69353719b08Smrg                    fprintf(stderr, "unexpected size for property %s", name);
694a570218aSmrg                    goto out;
69553719b08Smrg            }
69653719b08Smrg        } else if (type == float_atom) {
69753719b08Smrg            if (format != 32) {
6980309d3b3Smrg                fprintf(stderr, "unexpected format %d for property '%s'\n",
69953719b08Smrg                        format, name);
700a570218aSmrg                goto out;
70153719b08Smrg            }
70253719b08Smrg            *(float *)(data.l + i) = strtod(argv[2 + i], &endptr);
70353719b08Smrg            if (endptr == argv[2 + i]) {
70453719b08Smrg                fprintf(stderr, "argument %s could not be parsed\n", argv[2 + i]);
705a570218aSmrg                goto out;
7065b944e2aSmrg            }
70753719b08Smrg        } else if (type == XA_ATOM) {
70853719b08Smrg            if (format != 32) {
7090309d3b3Smrg                fprintf(stderr, "unexpected format %d for property '%s'\n",
71053719b08Smrg                        format, name);
711a570218aSmrg                goto out;
71253719b08Smrg            }
71353719b08Smrg            data.l[i] = parse_atom(dpy, argv[2 + i]);
71453719b08Smrg        } else {
7150309d3b3Smrg            fprintf(stderr, "unexpected type for property '%s'\n", name);
716a570218aSmrg            goto out;
7175b944e2aSmrg        }
71853719b08Smrg    }
7195b944e2aSmrg
72053719b08Smrg    XIChangeProperty(dpy, info->deviceid, prop, type, format, PropModeReplace,
72153719b08Smrg                          data.c, nelements);
722a570218aSmrg    rc = EXIT_SUCCESS;
723a570218aSmrgout:
72453719b08Smrg    free(data.c);
725a570218aSmrg    return rc;
72653719b08Smrg}
72753719b08Smrg#endif
72853719b08Smrg
72953719b08Smrgint list_props(Display *display, int argc, char *argv[], char *name,
73053719b08Smrg               char *desc)
73153719b08Smrg{
732a570218aSmrg#if HAVE_XI2
73353719b08Smrg    if (xinput_version(display) == XI_2_Major)
73453719b08Smrg        return list_props_xi2(display, argc, argv, name, desc);
73553719b08Smrg#endif
73653719b08Smrg    return list_props_xi1(display, argc, argv, name, desc);
73753719b08Smrg
73853719b08Smrg}
73953719b08Smrg
74053719b08Smrgint delete_prop(Display *display, int argc, char *argv[], char *name,
74153719b08Smrg                char *desc)
74253719b08Smrg{
743a570218aSmrg#if HAVE_XI2
74453719b08Smrg    if (xinput_version(display) == XI_2_Major)
74553719b08Smrg        return delete_prop_xi2(display, argc, argv, name, desc);
74653719b08Smrg#endif
74753719b08Smrg    return delete_prop_xi1(display, argc, argv, name, desc);
74853719b08Smrg
74953719b08Smrg}
75053719b08Smrg
75153719b08Smrgstatic int
75253719b08Smrgdo_set_prop(Display *display, Atom type, int format, int argc, char *argv[], char *name, char *desc)
75353719b08Smrg{
754a570218aSmrg#if HAVE_XI2
75553719b08Smrg    if (xinput_version(display) == XI_2_Major)
75653719b08Smrg        return do_set_prop_xi2(display, type, format, argc, argv, name, desc);
75753719b08Smrg#endif
75853719b08Smrg    return do_set_prop_xi1(display, type, format, argc, argv, name, desc);
75953719b08Smrg}
76053719b08Smrg
76153719b08Smrgint
76253719b08Smrgset_atom_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
76353719b08Smrg{
76453719b08Smrg    return do_set_prop(dpy, XA_ATOM, 32, argc, argv, n, desc);
76553719b08Smrg}
76653719b08Smrg
76753719b08Smrgint
76853719b08Smrgset_int_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
76953719b08Smrg{
77053719b08Smrg    int          i;
77153719b08Smrg    int          format;
77253719b08Smrg
77353719b08Smrg    if (argc < 3)
77453719b08Smrg    {
77553719b08Smrg        fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
77653719b08Smrg        return EXIT_FAILURE;
7775b944e2aSmrg    }
7785b944e2aSmrg
77953719b08Smrg    format    = atoi(argv[2]);
78053719b08Smrg    if (format != 8 && format != 16 && format != 32)
78153719b08Smrg    {
78253719b08Smrg        fprintf(stderr, "Invalid format %d\n", format);
78353719b08Smrg        return EXIT_FAILURE;
78453719b08Smrg    }
7855b944e2aSmrg
78653719b08Smrg    for (i = 3; i < argc; i++)
78753719b08Smrg        argv[i - 1] = argv[i];
78853719b08Smrg
78953719b08Smrg    return do_set_prop(dpy, XA_INTEGER, format, argc - 1, argv, n, desc);
7905b944e2aSmrg}
7915b944e2aSmrg
79253719b08Smrgint
79353719b08Smrgset_float_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
79453719b08Smrg{
79553719b08Smrg    Atom float_atom = XInternAtom(dpy, "FLOAT", False);
79653719b08Smrg
79753719b08Smrg    if (sizeof(float) != 4)
79853719b08Smrg    {
79953719b08Smrg	fprintf(stderr, "sane FP required\n");
80053719b08Smrg	return EXIT_FAILURE;
80153719b08Smrg    }
80253719b08Smrg
80353719b08Smrg    return do_set_prop(dpy, float_atom, 32, argc, argv, n, desc);
80453719b08Smrg}
8055b944e2aSmrg
80653719b08Smrgint set_prop(Display *display, int argc, char *argv[], char *name,
80753719b08Smrg             char *desc)
80853719b08Smrg{
80953719b08Smrg    Atom type = None;
81053719b08Smrg    int format = 0;
81153719b08Smrg    int i = 0, j;
81253719b08Smrg
81353719b08Smrg    while (i < argc) {
81453719b08Smrg        char *option = strchr(argv[i], '=');
81553719b08Smrg        /* skip non-option arguments */
81653719b08Smrg        if (strncmp(argv[i], "--", 2) || !option) {
81753719b08Smrg            i++;
81853719b08Smrg            continue;
81953719b08Smrg        }
82053719b08Smrg
82153719b08Smrg        if (!strncmp(argv[i], "--type=", strlen("--type="))) {
82253719b08Smrg            if (!strcmp(option + 1, "int")) {
82353719b08Smrg                type = XA_INTEGER;
82453719b08Smrg            } else if (!strcmp(option + 1, "float")) {
82553719b08Smrg                type = XInternAtom(display, "FLOAT", False);
82653719b08Smrg                format = 32;
82753719b08Smrg            } else if (!strcmp(option + 1, "atom")) {
82853719b08Smrg                type = XA_ATOM;
82953719b08Smrg                format = 32;
83053719b08Smrg            } else {
83153719b08Smrg                fprintf(stderr, "unknown property type %s\n", option + 1);
83253719b08Smrg                return EXIT_FAILURE;
83353719b08Smrg            }
83453719b08Smrg        } else if (!strncmp(argv[i], "--format=", strlen("--format="))) {
83553719b08Smrg            format = atoi(option + 1);
83653719b08Smrg            if (format != 8 && format != 16 && format != 32) {
8370309d3b3Smrg                fprintf(stderr, "invalid property format '%s'\n", option + 1);
83853719b08Smrg                return EXIT_FAILURE;
83953719b08Smrg            }
84053719b08Smrg        } else {
8410309d3b3Smrg            fprintf(stderr, "invalid option '%s'\n", argv[i]);
84253719b08Smrg            return EXIT_FAILURE;
84353719b08Smrg        }
84453719b08Smrg
84553719b08Smrg        for (j = i; j + 1 < argc; j++)
84653719b08Smrg            argv[j] = argv[j + 1];
84753719b08Smrg        argc--;
84853719b08Smrg    }
84953719b08Smrg
85053719b08Smrg    return do_set_prop(display, type, format, argc, argv, name, desc);
85153719b08Smrg}
8520309d3b3Smrg
8530309d3b3Smrgint disable(Display *display, int argc, char *argv[], char *name, char *desc)
8540309d3b3Smrg{
855e73734d1Smrg    char *new_argv[3] = { NULL, "Device Enabled", "0" };
856e73734d1Smrg
857e73734d1Smrg    if (argc != 1) {
858e73734d1Smrg        fprintf(stderr, "Usage: xinput %s %s\n", name, desc);
859e73734d1Smrg        return EXIT_FAILURE;
860e73734d1Smrg    }
861e73734d1Smrg
862e73734d1Smrg    new_argv[0] = argv[0];
863e73734d1Smrg
8640309d3b3Smrg    return set_prop(display, 3, new_argv, name, desc);
8650309d3b3Smrg}
8660309d3b3Smrg
8670309d3b3Smrgint enable(Display *display, int argc, char *argv[], char *name, char *desc)
8680309d3b3Smrg{
869e73734d1Smrg    char *new_argv[3] = { NULL, "Device Enabled", "1" };
870e73734d1Smrg
871e73734d1Smrg    if (argc != 1) {
872e73734d1Smrg        fprintf(stderr, "Usage: xinput %s %s\n", name, desc);
873e73734d1Smrg        return EXIT_FAILURE;
874e73734d1Smrg    }
875e73734d1Smrg
876e73734d1Smrg    new_argv[0] = argv[0];
877e73734d1Smrg
8780309d3b3Smrg    return set_prop(display, 3, new_argv, name, desc);
8790309d3b3Smrg}
880