1/*
2 * Copyright 1996 by Frederic Lepied, France. <Frederic.Lepied@sugix.frmug.org>
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, and that   the  name of  the authors  not  be  used  in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific,  written      prior  permission.     The authors  make  no
11 * representations about the suitability of this software for any purpose.  It
12 * is provided "as is" without express or implied warranty.
13 *
14 * THE AUTHORS DISCLAIM ALL   WARRANTIES WITH REGARD  TO  THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED   WARRANTIES OF MERCHANTABILITY  AND   FITNESS, IN NO
16 * EVENT  SHALL THE AUTHORS  BE   LIABLE   FOR ANY  SPECIAL, INDIRECT   OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA  OR PROFITS, WHETHER  IN  AN ACTION OF  CONTRACT,  NEGLIGENCE OR OTHER
19 * TORTIOUS  ACTION, ARISING    OUT OF OR   IN  CONNECTION  WITH THE USE    OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 *
22 */
23
24#include "xinput.h"
25#include <string.h>
26
27enum print_format {
28    FORMAT_NONE,
29    FORMAT_SHORT,
30    FORMAT_LONG,
31    FORMAT_NAME,
32    FORMAT_ID,
33};
34
35
36static void
37print_info(Display* dpy, XDeviceInfo	*info, enum print_format format)
38{
39    int			i,j;
40    XAnyClassPtr	any;
41    XKeyInfoPtr		k;
42    XButtonInfoPtr	b;
43    XValuatorInfoPtr	v;
44    XAxisInfoPtr	a;
45
46    if (format == FORMAT_NAME)
47    {
48        printf("%s\n", info->name);
49        return;
50    } else if (format == FORMAT_ID)
51    {
52        printf("%ld\n", info->id);
53        return;
54    }
55
56    printf("\"%s\"\tid=%ld\t[", info->name, info->id);
57
58    switch (info->use) {
59    case IsXPointer:
60       printf("XPointer");
61       break;
62    case IsXKeyboard:
63       printf("XKeyboard");
64       break;
65    case IsXExtensionDevice:
66       printf("XExtensionDevice");
67       break;
68    case IsXExtensionKeyboard:
69       printf("XExtensionKeyboard");
70       break;
71    case IsXExtensionPointer:
72       printf("XExtensionPointer");
73       break;
74    default:
75       printf("Unknown class");
76       break;
77    }
78    printf("]\n");
79
80    if (format == FORMAT_SHORT)
81        return;
82
83    if (info->type != None) {
84	char *type = XGetAtomName(dpy, info->type);
85	printf("\tType is %s\n", type);
86	XFree(type);
87    }
88
89    if (info->num_classes > 0) {
90	any = (XAnyClassPtr) (info->inputclassinfo);
91	for (i=0; i<info->num_classes; i++) {
92	    switch (any->class) {
93	    case KeyClass:
94		k = (XKeyInfoPtr) any;
95		printf("\tNum_keys is %d\n", k->num_keys);
96		printf("\tMin_keycode is %d\n", k->min_keycode);
97		printf("\tMax_keycode is %d\n", k->max_keycode);
98		break;
99
100	    case ButtonClass:
101		b = (XButtonInfoPtr) any;
102		printf("\tNum_buttons is %d\n", b->num_buttons);
103		break;
104
105	    case ValuatorClass:
106		v = (XValuatorInfoPtr) any;
107		a = (XAxisInfoPtr) ((char *) v +
108				    sizeof (XValuatorInfo));
109		printf("\tNum_axes is %d\n", v->num_axes);
110		printf("\tMode is %s\n", (v->mode == Absolute) ? "Absolute" : "Relative");
111		printf("\tMotion_buffer is %ld\n", v->motion_buffer);
112		for (j=0; j<v->num_axes; j++, a++) {
113		    printf("\tAxis %d :\n", j);
114		    printf("\t\tMin_value is %d\n", a->min_value);
115		    printf("\t\tMax_value is %d\n", a->max_value);
116		    printf ("\t\tResolution is %d\n", a->resolution);
117		}
118		break;
119	    default:
120		printf ("unknown class\n");
121	    }
122	    any = (XAnyClassPtr) ((char *) any + any->length);
123	}
124    }
125}
126
127static int list_xi1(Display     *display,
128                    enum print_format format)
129{
130    XDeviceInfo		*info;
131    int			loop;
132    int                 num_devices;
133
134    info = XListInputDevices(display, &num_devices);
135    for(loop=0; loop<num_devices; loop++) {
136        print_info(display, info+loop, format);
137    }
138    return EXIT_SUCCESS;
139}
140
141#if HAVE_XI2
142/* also used from test_xi2.c */
143void
144print_classes_xi2(Display* display, XIAnyClassInfo **classes,
145                  int num_classes)
146{
147    int i, j;
148
149    printf("\tReporting %d classes:\n", num_classes);
150    for (i = 0; i < num_classes; i++)
151    {
152        printf("\t\tClass originated from: %d. Type: ", classes[i]->sourceid);
153        switch(classes[i]->type)
154        {
155            case XIButtonClass:
156                {
157                    XIButtonClassInfo *b = (XIButtonClassInfo*)classes[i];
158                    char *name;
159                    printf("XIButtonClass\n");
160                    printf("\t\tButtons supported: %d\n", b->num_buttons);
161                    printf("\t\tButton labels:");
162                    for (j = 0; j < b->num_buttons; j++)
163                    {
164                        name = (b->labels[j]) ? XGetAtomName(display, b->labels[j]) : NULL;
165                        if (name)
166                            printf(" \"%s\"", name);
167                        else
168                            printf(" None");
169                        XFree(name);
170                    }
171                    printf("\n");
172                    printf("\t\tButton state:");
173                    for (j = 0; j < b->state.mask_len * 8; j++)
174                        if (XIMaskIsSet(b->state.mask, j))
175                            printf(" %d", j);
176                    printf("\n");
177
178                }
179                break;
180            case XIKeyClass:
181                {
182                    XIKeyClassInfo *k = (XIKeyClassInfo*)classes[i];
183                    printf("XIKeyClass\n");
184                    printf("\t\tKeycodes supported: %d\n", k->num_keycodes);
185                }
186                break;
187            case XIValuatorClass:
188                {
189                    XIValuatorClassInfo *v = (XIValuatorClassInfo*)classes[i];
190                    char *name = v->label ?  XGetAtomName(display, v->label) : NULL;
191
192                    /* Bug in X servers 1.7..1.8.1, mode was | OutOfProximity */
193                    v->mode &= DeviceMode;
194
195                    printf("XIValuatorClass\n");
196                    printf("\t\tDetail for Valuator %d:\n", v->number);
197                    printf("\t\t  Label: %s\n",  (name) ? name : "None");
198                    printf("\t\t  Range: %f - %f\n", v->min, v->max);
199                    printf("\t\t  Resolution: %d units/m\n", v->resolution);
200                    printf("\t\t  Mode: %s\n", v->mode == Absolute ? "absolute" :
201                            "relative");
202                    if (v->mode == Absolute)
203                        printf("\t\t  Current value: %f\n", v->value);
204                    XFree(name);
205                }
206                break;
207#if HAVE_XI21
208            case XIScrollClass:
209                {
210                    XIScrollClassInfo *s = (XIScrollClassInfo*)classes[i];
211
212                    printf("XIScrollClass\n");
213                    printf("\t\tScroll info for Valuator %d\n", s->number);
214                    printf("\t\t  type: %d (%s)\n", s->scroll_type,
215                           (s->scroll_type == XIScrollTypeHorizontal) ? "horizontal" :
216                              (s->scroll_type == XIScrollTypeVertical) ? "vertical" : "unknown");
217                    printf("\t\t  increment: %f\n", s->increment);
218                    printf("\t\t  flags: 0x%x", s->flags);
219                    if (s->flags) {
220                        printf(" (");
221                        if (s->flags & XIScrollFlagNoEmulation)
222                            printf(" no-emulation ");
223                        if (s->flags & XIScrollFlagPreferred)
224                            printf(" preferred ");
225                        printf(")");
226                    }
227                    printf("\n");
228                }
229                break;
230#endif
231#if HAVE_XI22
232            case XITouchClass:
233                {
234                    XITouchClassInfo *t = (XITouchClassInfo*)classes[i];
235
236                    printf("XITouchClass\n");
237                    printf("\t\tTouch mode: %s\n",
238                           (t->mode == XIDirectTouch) ? "direct" : "dependent");
239                    printf("\t\tMax number of touches: %d\n", t->num_touches);
240                }
241#endif
242        }
243    }
244
245    printf("\n");
246}
247
248static void
249print_info_xi2(Display* display, XIDeviceInfo *dev, enum print_format format)
250{
251    if (format == FORMAT_NAME)
252    {
253        printf("%s\n", dev->name);
254        return;
255    } else if (format == FORMAT_ID)
256    {
257        printf("%d\n", dev->deviceid);
258        return;
259    }
260
261    printf("%-40s\tid=%d\t[", dev->name, dev->deviceid);
262    switch(dev->use)
263    {
264        case XIMasterPointer:
265            printf("master pointer  (%d)]\n", dev->attachment);
266            break;
267        case XIMasterKeyboard:
268            printf("master keyboard (%d)]\n", dev->attachment);
269            break;
270        case XISlavePointer:
271            printf("slave  pointer  (%d)]\n", dev->attachment);
272            break;
273        case XISlaveKeyboard:
274            printf("slave  keyboard (%d)]\n", dev->attachment);
275            break;
276        case XIFloatingSlave:
277            printf("floating slave]\n");
278            break;
279    }
280
281    if (format == FORMAT_SHORT)
282        return;
283
284    if (!dev->enabled)
285        printf("\tThis device is disabled\n");
286
287    print_classes_xi2(display, dev->classes, dev->num_classes);
288}
289
290
291static int
292list_xi2(Display *display,
293         enum print_format format)
294{
295    int ndevices;
296    int i, j;
297    XIDeviceInfo *info, *dev;
298
299    info = XIQueryDevice(display, XIAllDevices, &ndevices);
300
301    for(i = 0; i < ndevices; i++)
302    {
303        dev = &info[i];
304        if (dev->use == XIMasterPointer || dev->use == XIMasterKeyboard)
305        {
306            if (format == FORMAT_SHORT || format == FORMAT_LONG)
307            {
308                if (dev->use == XIMasterPointer)
309                    printf("⎡ ");
310                else
311                    printf("⎣ ");
312            }
313
314            print_info_xi2(display, dev, format);
315            for (j = 0; j < ndevices; j++)
316            {
317                XIDeviceInfo* sd = &info[j];
318
319                if ((sd->use == XISlavePointer || sd->use == XISlaveKeyboard) &&
320                     (sd->attachment == dev->deviceid))
321                {
322                    if (format == FORMAT_SHORT || format == FORMAT_LONG)
323                        printf("%s   ↳ ", dev->use == XIMasterPointer ? "⎜" : " ");
324                    print_info_xi2(display, sd, format);
325                }
326            }
327        }
328    }
329
330    for (i = 0; i < ndevices; i++)
331    {
332        dev = &info[i];
333        if (dev->use == XIFloatingSlave)
334        {
335            printf("∼ ");
336            print_info_xi2(display, dev, format);
337        }
338    }
339
340
341    XIFreeDeviceInfo(info);
342    return EXIT_SUCCESS;
343}
344#endif
345
346int
347list(Display	*display,
348     int	argc,
349     char	*argv[],
350     char	*name,
351     char	*desc)
352{
353    enum print_format format = FORMAT_NONE;
354    int arg_dev = 1;
355
356    if (argc >= 1)
357    {
358        if (strcmp(argv[0], "--short") == 0)
359            format = FORMAT_SHORT;
360        else if (strcmp(argv[0], "--long") == 0)
361            format = FORMAT_LONG;
362        else if (strcmp(argv[0], "--name-only") == 0)
363            format = FORMAT_NAME;
364        else if (strcmp(argv[0], "--id-only") == 0)
365            format = FORMAT_ID;
366        else
367            arg_dev--;
368    }
369
370    if (argc > arg_dev)
371    {
372        if (format == FORMAT_NONE)
373            format = FORMAT_LONG;
374#if HAVE_XI2
375        if (xinput_version(display) == XI_2_Major)
376        {
377            XIDeviceInfo *info = xi2_find_device_info(display, argv[arg_dev]);
378
379            if (!info) {
380                fprintf(stderr, "unable to find device %s\n", argv[arg_dev]);
381                return EXIT_FAILURE;
382            } else {
383                print_info_xi2(display, info, format);
384                return EXIT_SUCCESS;
385            }
386        } else
387#endif
388        {
389            XDeviceInfo *info = find_device_info(display, argv[arg_dev], False);
390
391            if (!info) {
392                fprintf(stderr, "unable to find device %s\n", argv[arg_dev]);
393                return EXIT_FAILURE;
394            } else {
395                print_info(display, info, format);
396                return EXIT_SUCCESS;
397            }
398        }
399    } else {
400        if (format == FORMAT_NONE)
401            format = FORMAT_SHORT;
402#if HAVE_XI2
403        if (xinput_version(display) == XI_2_Major)
404            return list_xi2(display, format);
405#endif
406        return list_xi1(display, format);
407    }
408}
409
410/* end of list.c */
411