SDL 2.0
SDL_x11xinput2.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "../../SDL_internal.h"
22
23#if SDL_VIDEO_DRIVER_X11
24
25#include "SDL_x11video.h"
26#include "SDL_x11xinput2.h"
27#include "../../events/SDL_mouse_c.h"
28#include "../../events/SDL_touch_c.h"
29
30#define MAX_AXIS 16
31
32#if SDL_VIDEO_DRIVER_X11_XINPUT2
33static int xinput2_initialized = 0;
34
35#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
36static int xinput2_multitouch_supported = 0;
37#endif
38
39/* Opcode returned X11_XQueryExtension
40 * It will be used in event processing
41 * to know that the event came from
42 * this extension */
43static int xinput2_opcode;
44
45static void parse_valuators(const double *input_values,unsigned char *mask,int mask_len,
46 double *output_values,int output_values_len) {
47 int i = 0,z = 0;
48 int top = mask_len * 8;
49 if (top > MAX_AXIS)
50 top = MAX_AXIS;
51
52 SDL_memset(output_values,0,output_values_len * sizeof(double));
53 for (; i < top && z < output_values_len; i++) {
54 if (XIMaskIsSet(mask, i)) {
55 const int value = (int) *input_values;
56 output_values[z] = value;
57 input_values++;
58 }
59 z++;
60 }
61}
62
63static int
64query_xinput2_version(Display *display, int major, int minor)
65{
66 /* We don't care if this fails, so long as it sets major/minor on it's way out the door. */
67 X11_XIQueryVersion(display, &major, &minor);
68 return ((major * 1000) + minor);
69}
70
71static SDL_bool
72xinput2_version_atleast(const int version, const int wantmajor, const int wantminor)
73{
74 return ( version >= ((wantmajor * 1000) + wantminor) );
75}
76
77#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
78static SDL_Window *
79xinput2_get_sdlwindow(SDL_VideoData *videodata, Window window)
80{
81 int i;
82 for (i = 0; i < videodata->numwindows; i++) {
83 SDL_WindowData *d = videodata->windowlist[i];
84 if (d->xwindow == window) {
85 return d->window;
86 }
87 }
88 return NULL;
89}
90
91static void
92xinput2_normalize_touch_coordinates(SDL_Window *window, double in_x, double in_y, float *out_x, float *out_y)
93{
94 if (window) {
95 if (window->w == 1) {
96 *out_x = 0.5f;
97 } else {
98 *out_x = in_x / (window->w - 1);
99 }
100 if (window->h == 1) {
101 *out_y = 0.5f;
102 } else {
103 *out_y = in_y / (window->h - 1);
104 }
105 } else {
106 // couldn't find the window...
107 *out_x = in_x;
108 *out_y = in_y;
109 }
110}
111#endif /* SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH */
112
113#endif /* SDL_VIDEO_DRIVER_X11_XINPUT2 */
114
115void
117{
118#if SDL_VIDEO_DRIVER_X11_XINPUT2
120
121 int version = 0;
122 XIEventMask eventmask;
123 unsigned char mask[3] = { 0,0,0 };
124 int event, err;
125
126 /*
127 * Initialize XInput 2
128 * According to http://who-t.blogspot.com/2009/05/xi2-recipes-part-1.html its better
129 * to inform Xserver what version of Xinput we support.The server will store the version we support.
130 * "As XI2 progresses it becomes important that you use this call as the server may treat the client
131 * differently depending on the supported version".
132 *
133 * FIXME:event and err are not needed but if not passed X11_XQueryExtension returns SegmentationFault
134 */
135 if (!SDL_X11_HAVE_XINPUT2 ||
136 !X11_XQueryExtension(data->display, "XInputExtension", &xinput2_opcode, &event, &err)) {
137 return; /* X server does not have XInput at all */
138 }
139
140 /* We need at least 2.2 for Multitouch, 2.0 otherwise. */
141 version = query_xinput2_version(data->display, 2, 2);
142 if (!xinput2_version_atleast(version, 2, 0)) {
143 return; /* X server does not support the version we want at all. */
144 }
145
146 xinput2_initialized = 1;
147
148#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH /* Multitouch needs XInput 2.2 */
149 xinput2_multitouch_supported = xinput2_version_atleast(version, 2, 2);
150#endif
151
152 /* Enable Raw motion events for this display */
153 eventmask.deviceid = XIAllMasterDevices;
154 eventmask.mask_len = sizeof(mask);
155 eventmask.mask = mask;
156
157 XISetMask(mask, XI_RawMotion);
158 XISetMask(mask, XI_RawButtonPress);
159 XISetMask(mask, XI_RawButtonRelease);
160
161 if (X11_XISelectEvents(data->display,DefaultRootWindow(data->display),&eventmask,1) != Success) {
162 return;
163 }
164#endif
165}
166
167int
169{
170#if SDL_VIDEO_DRIVER_X11_XINPUT2
171 if(cookie->extension != xinput2_opcode) {
172 return 0;
173 }
174 switch(cookie->evtype) {
175 case XI_RawMotion: {
176 const XIRawEvent *rawev = (const XIRawEvent*)cookie->data;
177 SDL_Mouse *mouse = SDL_GetMouse();
178 double relative_coords[2];
179 static Time prev_time = 0;
180 static double prev_rel_coords[2];
181
182 videodata->global_mouse_changed = SDL_TRUE;
183
184 if (!mouse->relative_mode || mouse->relative_mode_warp) {
185 return 0;
186 }
187
188 parse_valuators(rawev->raw_values,rawev->valuators.mask,
189 rawev->valuators.mask_len,relative_coords,2);
190
191 if ((rawev->time == prev_time) && (relative_coords[0] == prev_rel_coords[0]) && (relative_coords[1] == prev_rel_coords[1])) {
192 return 0; /* duplicate event, drop it. */
193 }
194
195 SDL_SendMouseMotion(mouse->focus,mouse->mouseID,1,(int)relative_coords[0],(int)relative_coords[1]);
196 prev_rel_coords[0] = relative_coords[0];
197 prev_rel_coords[1] = relative_coords[1];
198 prev_time = rawev->time;
199 return 1;
200 }
201 break;
202
203 case XI_RawButtonPress:
204 case XI_RawButtonRelease:
205 videodata->global_mouse_changed = SDL_TRUE;
206 break;
207
208#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
209 /* With multitouch, register to receive XI_Motion (which desctivates MotionNotify),
210 * so that we can distinguish real mouse motions from synthetic one. */
211 case XI_Motion: {
212 const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
213 int pointer_emulated = (xev->flags & XIPointerEmulated);
214
215 if (! pointer_emulated) {
216 SDL_Mouse *mouse = SDL_GetMouse();
217 if(!mouse->relative_mode || mouse->relative_mode_warp) {
218 SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event);
219 if (window) {
220 SDL_SendMouseMotion(window, 0, 0, xev->event_x, xev->event_y);
221 }
222 }
223 }
224 return 1;
225 }
226 break;
227
228 case XI_TouchBegin: {
229 const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
230 float x, y;
231 SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event);
232 xinput2_normalize_touch_coordinates(window, xev->event_x, xev->event_y, &x, &y);
233 SDL_SendTouch(xev->sourceid,xev->detail, SDL_TRUE, x, y, 1.0);
234 return 1;
235 }
236 break;
237 case XI_TouchEnd: {
238 const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
239 float x, y;
240 SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event);
241 xinput2_normalize_touch_coordinates(window, xev->event_x, xev->event_y, &x, &y);
242 SDL_SendTouch(xev->sourceid,xev->detail, SDL_FALSE, x, y, 1.0);
243 return 1;
244 }
245 break;
246 case XI_TouchUpdate: {
247 const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
248 float x, y;
249 SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event);
250 xinput2_normalize_touch_coordinates(window, xev->event_x, xev->event_y, &x, &y);
251 SDL_SendTouchMotion(xev->sourceid,xev->detail, x, y, 1.0);
252 return 1;
253 }
254 break;
255#endif
256 }
257#endif
258 return 0;
259}
260
261void
263{
264#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
266 XIDeviceInfo *info;
267 int ndevices,i,j;
268 info = X11_XIQueryDevice(data->display, XIAllDevices, &ndevices);
269
270 for (i = 0; i < ndevices; i++) {
271 XIDeviceInfo *dev = &info[i];
272 for (j = 0; j < dev->num_classes; j++) {
273 SDL_TouchID touchId;
274 SDL_TouchDeviceType touchType;
275 XIAnyClassInfo *class = dev->classes[j];
276 XITouchClassInfo *t = (XITouchClassInfo*)class;
277
278 /* Only touch devices */
279 if (class->type != XITouchClass)
280 continue;
281
282 if (t->mode == XIDependentTouch) {
284 } else { /* XIDirectTouch */
285 touchType = SDL_TOUCH_DEVICE_DIRECT;
286 }
287
288 touchId = t->sourceid;
289 SDL_AddTouch(touchId, touchType, dev->name);
290 }
291 }
292 X11_XIFreeDeviceInfo(info);
293#endif
294}
295
296void
298{
299#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
301 XIEventMask eventmask;
302 unsigned char mask[4] = { 0, 0, 0, 0 };
303 SDL_WindowData *window_data = NULL;
304
306 return;
307 }
308
310 window_data = (SDL_WindowData*)window->driverdata;
311
312 eventmask.deviceid = XIAllMasterDevices;
313 eventmask.mask_len = sizeof(mask);
314 eventmask.mask = mask;
315
316 XISetMask(mask, XI_TouchBegin);
317 XISetMask(mask, XI_TouchUpdate);
318 XISetMask(mask, XI_TouchEnd);
319 XISetMask(mask, XI_Motion);
320
321 X11_XISelectEvents(data->display,window_data->xwindow,&eventmask,1);
322#endif
323}
324
325
326int
328{
329#if SDL_VIDEO_DRIVER_X11_XINPUT2
330 return xinput2_initialized;
331#else
332 return 0;
333#endif
334}
335
336int
338{
339#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
340 return xinput2_initialized && xinput2_multitouch_supported;
341#else
342 return 0;
343#endif
344}
345
346#endif /* SDL_VIDEO_DRIVER_X11 */
347
348/* vi: set ts=4 sw=4 expandtab: */
#define _THIS
#define SDL_memset
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 ** d
SDL_Mouse * SDL_GetMouse(void)
Definition: SDL_mouse.c:178
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
Definition: SDL_mouse.c:301
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
GLdouble GLdouble t
Definition: SDL_opengl.h:2071
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
struct _cl_event * event
GLdouble GLdouble GLdouble GLdouble top
GLdouble GLdouble z
GLsizei const GLfloat * value
GLenum GLint GLuint mask
SDL_bool
Definition: SDL_stdinc.h:162
@ SDL_TRUE
Definition: SDL_stdinc.h:164
@ SDL_FALSE
Definition: SDL_stdinc.h:163
int SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_bool down, float x, float y, float pressure)
Definition: SDL_touch.c:242
int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, float x, float y, float pressure)
Definition: SDL_touch.c:364
int SDL_AddTouch(SDL_TouchID touchID, SDL_TouchDeviceType type, const char *name)
Definition: SDL_touch.c:155
SDL_TouchDeviceType
Definition: SDL_touch.h:45
@ SDL_TOUCH_DEVICE_DIRECT
Definition: SDL_touch.h:47
@ SDL_TOUCH_DEVICE_INDIRECT_RELATIVE
Definition: SDL_touch.h:49
Sint64 SDL_TouchID
Definition: SDL_touch.h:41
static SDL_VideoDevice * _this
Definition: SDL_video.c:118
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int int in j)
Definition: SDL_x11sym.h:50
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
int X11_Xinput2IsMultitouchSupported(void)
int X11_HandleXinput2Event(SDL_VideoData *videodata, XGenericEventCookie *cookie)
int X11_Xinput2IsInitialized(void)
void X11_InitXinput2(_THIS)
struct XGenericEventCookie XGenericEventCookie
void X11_InitXinput2Multitouch(_THIS)
void X11_Xinput2SelectTouch(_THIS, SDL_Window *window)
#define NULL
Definition: begin_code.h:167
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
SDL_bool relative_mode
Definition: SDL_mouse_c.h:87
SDL_bool relative_mode_warp
Definition: SDL_mouse_c.h:88
SDL_WindowData ** windowlist
Definition: SDL_x11video.h:83
SDL_bool global_mouse_changed
Definition: SDL_x11video.h:133
The type used to identify a window.
Definition: SDL_sysvideo.h:74