SDL  2.0
SDL_x11xinput2.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2017 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,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 #endif /* SDL_VIDEO_DRIVER_X11_XINPUT2 */
77 
78 void
80 {
81 #if SDL_VIDEO_DRIVER_X11_XINPUT2
83 
84  int version = 0;
85  XIEventMask eventmask;
86  unsigned char mask[3] = { 0,0,0 };
87  int event, err;
88 
89  /*
90  * Initialize XInput 2
91  * According to http://who-t.blogspot.com/2009/05/xi2-recipes-part-1.html its better
92  * to inform Xserver what version of Xinput we support.The server will store the version we support.
93  * "As XI2 progresses it becomes important that you use this call as the server may treat the client
94  * differently depending on the supported version".
95  *
96  * FIXME:event and err are not needed but if not passed X11_XQueryExtension returns SegmentationFault
97  */
98  if (!SDL_X11_HAVE_XINPUT2 ||
99  !X11_XQueryExtension(data->display, "XInputExtension", &xinput2_opcode, &event, &err)) {
100  return; /* X server does not have XInput at all */
101  }
102 
103  /* We need at least 2.2 for Multitouch, 2.0 otherwise. */
104  version = query_xinput2_version(data->display, 2, 2);
105  if (!xinput2_version_atleast(version, 2, 0)) {
106  return; /* X server does not support the version we want at all. */
107  }
108 
109  xinput2_initialized = 1;
110 
111 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH /* Multitouch needs XInput 2.2 */
112  xinput2_multitouch_supported = xinput2_version_atleast(version, 2, 2);
113 #endif
114 
115  /* Enable Raw motion events for this display */
116  eventmask.deviceid = XIAllMasterDevices;
117  eventmask.mask_len = sizeof(mask);
118  eventmask.mask = mask;
119 
120  XISetMask(mask, XI_RawMotion);
121  XISetMask(mask, XI_RawButtonPress);
122  XISetMask(mask, XI_RawButtonRelease);
123 
124  if (X11_XISelectEvents(data->display,DefaultRootWindow(data->display),&eventmask,1) != Success) {
125  return;
126  }
127 #endif
128 }
129 
130 int
132 {
133 #if SDL_VIDEO_DRIVER_X11_XINPUT2
134  if(cookie->extension != xinput2_opcode) {
135  return 0;
136  }
137  switch(cookie->evtype) {
138  case XI_RawMotion: {
139  const XIRawEvent *rawev = (const XIRawEvent*)cookie->data;
140  SDL_Mouse *mouse = SDL_GetMouse();
141  double relative_coords[2];
142  static Time prev_time = 0;
143  static double prev_rel_coords[2];
144 
145  videodata->global_mouse_changed = SDL_TRUE;
146 
147  if (!mouse->relative_mode || mouse->relative_mode_warp) {
148  return 0;
149  }
150 
151  parse_valuators(rawev->raw_values,rawev->valuators.mask,
152  rawev->valuators.mask_len,relative_coords,2);
153 
154  if ((rawev->time == prev_time) && (relative_coords[0] == prev_rel_coords[0]) && (relative_coords[1] == prev_rel_coords[1])) {
155  return 0; /* duplicate event, drop it. */
156  }
157 
158  SDL_SendMouseMotion(mouse->focus,mouse->mouseID,1,(int)relative_coords[0],(int)relative_coords[1]);
159  prev_rel_coords[0] = relative_coords[0];
160  prev_rel_coords[1] = relative_coords[1];
161  prev_time = rawev->time;
162  return 1;
163  }
164  break;
165 
166  case XI_RawButtonPress:
167  case XI_RawButtonRelease:
168  videodata->global_mouse_changed = SDL_TRUE;
169  break;
170 
171 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
172  case XI_TouchBegin: {
173  const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
174  SDL_SendTouch(xev->sourceid,xev->detail,
175  SDL_TRUE, xev->event_x, xev->event_y, 1.0);
176  return 1;
177  }
178  break;
179  case XI_TouchEnd: {
180  const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
181  SDL_SendTouch(xev->sourceid,xev->detail,
182  SDL_FALSE, xev->event_x, xev->event_y, 1.0);
183  return 1;
184  }
185  break;
186  case XI_TouchUpdate: {
187  const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
188  SDL_SendTouchMotion(xev->sourceid,xev->detail,
189  xev->event_x, xev->event_y, 1.0);
190  return 1;
191  }
192  break;
193 #endif
194  }
195 #endif
196  return 0;
197 }
198 
199 void
201 {
202 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
204  XIDeviceInfo *info;
205  int ndevices,i,j;
206  info = X11_XIQueryDevice(data->display, XIAllDevices, &ndevices);
207 
208  for (i = 0; i < ndevices; i++) {
209  XIDeviceInfo *dev = &info[i];
210  for (j = 0; j < dev->num_classes; j++) {
211  SDL_TouchID touchId;
212  XIAnyClassInfo *class = dev->classes[j];
213  XITouchClassInfo *t = (XITouchClassInfo*)class;
214 
215  /* Only touch devices */
216  if (class->type != XITouchClass)
217  continue;
218 
219  touchId = t->sourceid;
220  SDL_AddTouch(touchId, dev->name);
221  }
222  }
223  X11_XIFreeDeviceInfo(info);
224 #endif
225 }
226 
227 void
229 {
230 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
231  SDL_VideoData *data = NULL;
232  XIEventMask eventmask;
233  unsigned char mask[3] = { 0,0,0 };
234  SDL_WindowData *window_data = NULL;
235 
237  return;
238  }
239 
240  data = (SDL_VideoData *) _this->driverdata;
241  window_data = (SDL_WindowData*)window->driverdata;
242 
243  eventmask.deviceid = XIAllMasterDevices;
244  eventmask.mask_len = sizeof(mask);
245  eventmask.mask = mask;
246 
247  XISetMask(mask, XI_TouchBegin);
248  XISetMask(mask, XI_TouchUpdate);
249  XISetMask(mask, XI_TouchEnd);
250 
251  X11_XISelectEvents(data->display,window_data->xwindow,&eventmask,1);
252 #endif
253 }
254 
255 
256 int
258 {
259 #if SDL_VIDEO_DRIVER_X11_XINPUT2
260  return xinput2_initialized;
261 #else
262  return 0;
263 #endif
264 }
265 
266 int
268 {
269 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
270  return xinput2_initialized && xinput2_multitouch_supported;
271 #else
272  return 0;
273 #endif
274 }
275 
276 #endif /* SDL_VIDEO_DRIVER_X11 */
277 
278 /* vi: set ts=4 sw=4 expandtab: */
SDL_Mouse * SDL_GetMouse(void)
Definition: SDL_mouse.c:110
GLdouble GLdouble z
void X11_InitXinput2(_THIS)
struct wl_display * display
int SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_bool down, float x, float y, float pressure)
Definition: SDL_touch.c:222
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLdouble GLdouble GLdouble GLdouble top
SDL_bool global_mouse_changed
Definition: SDL_x11video.h:133
int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, float x, float y, float pressure)
Definition: SDL_touch.c:284
static SDL_VideoDevice * _this
Definition: SDL_video.c:121
void X11_InitXinput2Multitouch(_THIS)
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
Definition: SDL_mouse.c:235
#define _THIS
struct _cl_event * event
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
GLenum GLint GLuint mask
int X11_Xinput2IsMultitouchSupported(void)
GLsizei const GLfloat * value
Sint64 SDL_TouchID
Definition: SDL_touch.h:41
int SDL_AddTouch(SDL_TouchID touchID, const char *name)
Definition: SDL_touch.c:136
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
#define NULL
Definition: begin_code.h:164
SDL_bool
Definition: SDL_stdinc.h:139
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
The type used to identify a window.
Definition: SDL_sysvideo.h:73
int X11_HandleXinput2Event(SDL_VideoData *videodata, XGenericEventCookie *cookie)
void * driverdata
Definition: SDL_sysvideo.h:111
int X11_Xinput2IsInitialized(void)
struct XGenericEventCookie XGenericEventCookie
GLdouble GLdouble t
Definition: SDL_opengl.h:2071
#define SDL_memset
void X11_Xinput2SelectTouch(_THIS, SDL_Window *window)