/
x11_xinput.c
331 lines (259 loc) · 8.37 KB
1
2
3
4
5
6
7
8
/*
* Support for the X11 XInput extension.
*
* Please see the file LICENSE in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "manymouse.h"
/* Try to use this on everything but Windows and Mac OS by default... */
#ifndef SUPPORT_XINPUT
#if ( (defined(_WIN32) || defined(__CYGWIN__)) )
#define SUPPORT_XINPUT 0
#elif ( (defined(__MACH__)) && (defined(__APPLE__)) )
#define SUPPORT_XINPUT 0
#else
#define SUPPORT_XINPUT 1
#endif
#endif
22
23
#if SUPPORT_XINPUT
24
//#error this code is incomplete. Do not use unless you are fixing it.
25
26
27
28
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
29
#include <dlfcn.h>
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <X11/extensions/XInput.h>
/* 32 is good enough for now. */
#define MAX_MICE 32
typedef struct
{
XDevice *device;
int min_x;
int min_y;
int max_x;
int max_y;
char name[64];
} MouseStruct;
static MouseStruct mice[MAX_MICE];
static unsigned int available_mice = 0;
static Display *display = NULL;
static XExtensionVersion *extver = NULL;
static XDeviceInfo *device_list = NULL;
static int device_count = 0;
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*
* You _probably_ have Xlib on your system if you're on a Unix box where you
* are planning to plug in multiple mice. That being said, we don't want
* to force a project to add Xlib to their builds, or force the end-user to
* have Xlib installed if they are otherwise running a console app that the
* evdev driver would handle.
*
* We load all Xlib symbols at runtime, and fail gracefully if they aren't
* available for some reason...ManyMouse might be able to use the evdev
* driver or at least return a zero.
*
* On Linux (and probably others), you'll need to add -ldl to your link line,
* but it's part of glibc, so this is pretty much going to be there.
*/
static void *libx11 = NULL;
static void *libxext = NULL;
static void *libxi = NULL;
typedef int (*XExtErrHandler)(Display *, _Xconst char *, _Xconst char *);
static XExtErrHandler (*pXSetExtensionErrorHandler)(XExtErrHandler h) = 0;
static Display* (*pXOpenDisplay)(_Xconst char*) = 0;
static int (*pXCloseDisplay)(Display*) = 0;
static int (*pXFree)(void*) = 0;
static XExtensionVersion* (*pXGetExtensionVersion)(Display*,_Xconst char*) = 0;
static XDeviceInfo* (*pXListInputDevices)(Display*,int*) = 0;
static void (*pXFreeDeviceList)(XDeviceInfo*) = 0;
static XDevice* (*pXOpenDevice)(Display*,XID) = 0;
static int (*pXCloseDevice)(Display*,XDevice*) = 0;
static int symlookup(void *dll, void **addr, const char *sym)
{
*addr = dlsym(dll, sym);
if (*addr == NULL)
return(0);
return(1);
} /* symlookup */
static int find_api_symbols(void)
{
void *dll = NULL;
#define LOOKUP(x) { if (!symlookup(dll, (void **) &p##x, #x)) return(0); }
dll = libx11 = dlopen("libX11.so.6", RTLD_GLOBAL | RTLD_LAZY);
if (dll == NULL)
return(0);
LOOKUP(XOpenDisplay);
LOOKUP(XCloseDisplay);
LOOKUP(XFree);
dll = libxext = dlopen("libXext.so.6", RTLD_GLOBAL | RTLD_LAZY);
if (dll == NULL)
return(0);
LOOKUP(XSetExtensionErrorHandler);
dll = libxi = dlopen("libXi.so.6", RTLD_GLOBAL | RTLD_LAZY);
if (dll == NULL)
return(0);
LOOKUP(XGetExtensionVersion);
LOOKUP(XListInputDevices);
LOOKUP(XFreeDeviceList);
LOOKUP(XOpenDevice);
LOOKUP(XCloseDevice);
#undef LOOKUP
return(1);
} /* find_api_symbols */
125
126
127
128
129
130
131
132
133
static void xinput_cleanup(void)
{
int i;
if (display != NULL)
{
for (i = 0; i < available_mice; i++)
{
if (mice[i].device)
134
pXCloseDevice(display, mice[i].device);
135
136
137
138
139
} /* for */
} /* if */
if (extver != NULL)
{
140
pXFree(extver);
141
142
143
144
145
extver = NULL;
} /* if */
if (device_list != NULL)
{
146
pXFreeDeviceList(device_list);
147
148
149
150
151
device_list = NULL;
} /* if */
if (display != NULL)
{
152
pXCloseDisplay(display);
153
154
155
156
157
display = NULL;
} /* if */
memset(mice, '\0', sizeof (mice));
available_mice = 0;
158
159
160
161
162
163
#define LIBCLOSE(lib) { if (lib != NULL) { dlclose(lib); lib = NULL; } }
LIBCLOSE(libxi);
LIBCLOSE(libxext);
LIBCLOSE(libx11);
#undef LIBCLOSE
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
} /* xinput_cleanup */
/* Just in case this is compiled as a C++ module... */
static XID get_x11_any_class(const XAnyClassPtr anyclass)
{
#if defined(__cplusplus) || defined(c_plusplus)
return anyclass->c_class;
#else
return anyclass->class;
#endif
} /* get_x11_any_class */
static int init_mouse(MouseStruct *mouse, const XDeviceInfo *devinfo)
{
int i;
int has_axes = 0;
int has_buttons = 0;
XAnyClassPtr any = devinfo->inputclassinfo;
185
186
187
188
189
190
if (devinfo->use == IsXPointer)
return(0); /* sucks! Can't open a mouse that is the system pointer! */
if (devinfo->use == IsXKeyboard)
return(0); /* definitely not a mouse. :) */
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
for (i = 0; i < devinfo->num_classes; i++)
{
XID cls = get_x11_any_class(any);
if (cls == KeyClass)
return(0); /* a keyboard? */
else if (cls == ButtonClass)
{
const XButtonInfo *info = (const XButtonInfo *) any;
if (info->num_buttons > 0)
has_buttons = 1;
} /* else if */
else if (cls == ValuatorClass)
{
const XValuatorInfo *info = (const XValuatorInfo *) any;
208
if (info->num_axes != 2) /* joystick? */ /* !!! FIXME: this isn't right! */
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
return 0;
has_axes = 1;
mouse->min_x = info->axes[0].min_value;
mouse->max_x = info->axes[0].max_value;
mouse->min_y = info->axes[1].min_value;
mouse->max_y = info->axes[1].max_value;
} /* else if */
any = (XAnyClassPtr) ((char *) any + any->length);
} /* for */
if ((!has_axes) || (!has_buttons))
return(0); /* probably not a mouse. */
224
mouse->device = pXOpenDevice(display, devinfo->id);
225
226
227
228
229
230
231
232
233
if (mouse->device == NULL)
return(0);
strncpy(mouse->name, devinfo->name, sizeof (mouse->name));
mouse->name[sizeof (mouse->name) - 1] = '\0';
return(1);
} /* init_mouse */
234
235
236
237
238
239
240
241
242
243
244
245
static int (*Xext_handler)(Display *, _Xconst char *, _Xconst char *) = NULL;
static int xext_errhandler(Display *d, _Xconst char *ext, _Xconst char *reason)
{
/* Don't do anything (write an error to stderr) if extension is missing */
if (strcmp(reason, "missing") == 0)
return 0;
return Xext_handler(d, ext, reason);
}
static int x11_xinput_init_internal(void)
246
247
248
249
250
{
int i;
xinput_cleanup(); /* just in case... */
251
252
253
254
255
256
257
if (getenv("MANYMOUSE_NO_XINPUT") != NULL)
return(-1);
if (!find_api_symbols())
return(-1); /* couldn't find all needed symbols. */
display = pXOpenDisplay(NULL);
258
if (display == NULL)
259
260
261
262
263
264
265
return(-1); /* no X server at all */
/* Stop stderr output in case XInput extension is missing... */
Xext_handler = pXSetExtensionErrorHandler(xext_errhandler);
extver = pXGetExtensionVersion(display, INAME);
pXSetExtensionErrorHandler(Xext_handler);
Xext_handler = NULL;
266
267
if ((extver == NULL) || (extver == (XExtensionVersion *) NoSuchExtension))
268
return(-1); /* no such extension */
269
270
if (extver->present == XI_Absent)
271
return(-1); /* extension not available. */
272
273
device_list = pXListInputDevices(display, &device_count);
274
if (device_list == NULL)
275
return(-1);
276
277
278
279
280
281
282
283
284
for (i = 0; i < device_count; i++)
{
MouseStruct *mouse = &mice[available_mice];
if (init_mouse(mouse, &device_list[i]))
available_mice++;
} /* for */
return(available_mice);
285
} /* x11_xinput_init_internal */
286
287
288
289
290
291
292
293
static int x11_xinput_init(void)
{
int retval = x11_xinput_init_internal();
if (retval < 0)
xinput_cleanup();
return(retval);
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
} /* x11_xinput_init */
static void x11_xinput_quit(void)
{
xinput_cleanup();
} /* x11_xinput_quit */
static const char *x11_xinput_name(unsigned int index)
{
if (index < available_mice)
return(mice[index].name);
return(NULL);
} /* x11_xinput_name */
static int x11_xinput_poll(ManyMouseEvent *event)
{
return(0); /* !!! FIXME */
} /* x11_xinput_poll */
316
static const ManyMouseDriver ManyMouseDriver_interface =
317
318
319
320
321
322
323
{
x11_xinput_init,
x11_xinput_quit,
x11_xinput_name,
x11_xinput_poll
};
324
325
326
327
328
329
const ManyMouseDriver *ManyMouseDriver_xinput = &ManyMouseDriver_interface;
#else
const ManyMouseDriver *ManyMouseDriver_xinput = 0;
#endif /* SUPPORT_XINPUT blocker */
330
/* end of x11_xinput.c ... */