SDL  2.0
SDL_x11xinput2.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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
33 static int xinput2_initialized = 0;
34 
35 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
36 static 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 */
43 static int xinput2_opcode;
44 
45 static void parse_valuators(const double *input_values, const 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 
63 static int
64 query_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 
71 static SDL_bool
72 xinput2_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
78 static SDL_Window *
79 xinput2_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 
91 static void
92 xinput2_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 
115 void
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 
167 int
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, window, 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, window, 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, window, x, y, 1.0);
252  return 1;
253  }
254  break;
255 #endif
256  }
257 #endif
258  return 0;
259 }
260 
261 void
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 
296 void
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 
326 int
328 {
329 #if SDL_VIDEO_DRIVER_X11_XINPUT2
330  return xinput2_initialized;
331 #else
332  return 0;
333 #endif
334 }
335 
336 int
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: */
SDL_GetMouse
SDL_Mouse * SDL_GetMouse(void)
Definition: SDL_mouse.c:170
SDL_TOUCH_DEVICE_DIRECT
@ SDL_TOUCH_DEVICE_DIRECT
Definition: SDL_touch.h:47
SDL_memset
#define SDL_memset
Definition: SDL_dynapi_overrides.h:386
SDL_VideoDevice::driverdata
void * driverdata
Definition: SDL_sysvideo.h:389
SDL_x11video.h
mask
GLenum GLint GLuint mask
Definition: SDL_opengl_glext.h:660
X11_InitXinput2Multitouch
void X11_InitXinput2Multitouch(_THIS)
NULL
#define NULL
Definition: begin_code.h:167
SDL_WindowData
Definition: SDL_androidwindow.h:38
SDL_SendTouch
int SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window *window, SDL_bool down, float x, float y, float pressure)
Definition: SDL_touch.c:242
SDL_TouchID
Sint64 SDL_TouchID
Definition: SDL_touch.h:41
top
GLdouble GLdouble GLdouble GLdouble top
Definition: SDL_opengl_glext.h:6106
z
GLdouble GLdouble z
Definition: SDL_opengl_glext.h:407
SDL_TOUCH_DEVICE_INDIRECT_RELATIVE
@ SDL_TOUCH_DEVICE_INDIRECT_RELATIVE
Definition: SDL_touch.h:49
SDL_VideoData::global_mouse_changed
SDL_bool global_mouse_changed
Definition: SDL_x11video.h:133
SDL_VideoData::windowlist
SDL_WindowData ** windowlist
Definition: SDL_x11video.h:83
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
SDL_Window
The type used to identify a window.
Definition: SDL_sysvideo.h:74
SDL_TouchDeviceType
SDL_TouchDeviceType
Definition: SDL_touch.h:44
event
struct _cl_event * event
Definition: SDL_opengl_glext.h:2652
SDL_FALSE
@ SDL_FALSE
Definition: SDL_stdinc.h:163
SDL_VideoData::numwindows
int numwindows
Definition: SDL_x11video.h:82
SDL_AddTouch
int SDL_AddTouch(SDL_TouchID touchID, SDL_TouchDeviceType type, const char *name)
Definition: SDL_touch.c:155
SDL_Mouse::relative_mode
SDL_bool relative_mode
Definition: SDL_mouse_c.h:87
SDL_WindowData::xwindow
Window xwindow
Definition: SDL_x11window.h:46
_this
static SDL_VideoDevice * _this
Definition: SDL_video.c:121
x
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
window
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
t
GLdouble GLdouble t
Definition: SDL_opengl.h:2071
SDL_SendMouseMotion
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
Definition: SDL_mouse.c:293
X11_Xinput2IsMultitouchSupported
int X11_Xinput2IsMultitouchSupported(void)
SDL_VideoData::int
int
Definition: SDL_windowsvideo.h:135
_THIS
#define _THIS
Definition: SDL_alsa_audio.h:31
SDL_Mouse
Definition: SDL_mouse_c.h:43
SDL_Mouse::relative_mode_warp
SDL_bool relative_mode_warp
Definition: SDL_mouse_c.h:88
y
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
SDL_VideoData::display
struct wl_display * display
Definition: SDL_waylandvideo.h:50
SDL_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
value
GLsizei const GLfloat * value
Definition: SDL_opengl_glext.h:701
SDL_x11xinput2.h
SDL_SendTouchMotion
int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window *window, float x, float y, float pressure)
Definition: SDL_touch.c:356
X11_HandleXinput2Event
int X11_HandleXinput2Event(SDL_VideoData *videodata, XGenericEventCookie *cookie)
j
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
X11_InitXinput2
void X11_InitXinput2(_THIS)
XGenericEventCookie
struct XGenericEventCookie XGenericEventCookie
Definition: SDL_x11xinput2.h:30
X11_Xinput2IsInitialized
int X11_Xinput2IsInitialized(void)
X11_Xinput2SelectTouch
void X11_Xinput2SelectTouch(_THIS, SDL_Window *window)
i
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
SDL_VideoData
Definition: SDL_androidvideo.h:36
d
const SDL_PRINTF_FORMAT_STRING char int const SDL_PRINTF_FORMAT_STRING char int const SDL_PRINTF_FORMAT_STRING char int const SDL_PRINTF_FORMAT_STRING char const char const SDL_SCANF_FORMAT_STRING 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
Definition: SDL_dynapi_procs.h:117
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:161