SDL  2.0
SDL_x11xinput2.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2016 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 
122  if (X11_XISelectEvents(data->display,DefaultRootWindow(data->display),&eventmask,1) != Success) {
123  return;
124  }
125 #endif
126 }
127 
128 int
130 {
131 #if SDL_VIDEO_DRIVER_X11_XINPUT2
132  if(cookie->extension != xinput2_opcode) {
133  return 0;
134  }
135  switch(cookie->evtype) {
136  case XI_RawMotion: {
137  const XIRawEvent *rawev = (const XIRawEvent*)cookie->data;
138  SDL_Mouse *mouse = SDL_GetMouse();
139  double relative_coords[2];
140  static Time prev_time = 0;
141  static double prev_rel_coords[2];
142 
143  if (!mouse->relative_mode || mouse->relative_mode_warp) {
144  return 0;
145  }
146 
147  parse_valuators(rawev->raw_values,rawev->valuators.mask,
148  rawev->valuators.mask_len,relative_coords,2);
149 
150  if ((rawev->time == prev_time) && (relative_coords[0] == prev_rel_coords[0]) && (relative_coords[1] == prev_rel_coords[1])) {
151  return 0; /* duplicate event, drop it. */
152  }
153 
154  SDL_SendMouseMotion(mouse->focus,mouse->mouseID,1,(int)relative_coords[0],(int)relative_coords[1]);
155  prev_rel_coords[0] = relative_coords[0];
156  prev_rel_coords[1] = relative_coords[1];
157  prev_time = rawev->time;
158  return 1;
159  }
160  break;
161 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
162  case XI_TouchBegin: {
163  const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
164  SDL_SendTouch(xev->sourceid,xev->detail,
165  SDL_TRUE, xev->event_x, xev->event_y, 1.0);
166  return 1;
167  }
168  break;
169  case XI_TouchEnd: {
170  const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
171  SDL_SendTouch(xev->sourceid,xev->detail,
172  SDL_FALSE, xev->event_x, xev->event_y, 1.0);
173  return 1;
174  }
175  break;
176  case XI_TouchUpdate: {
177  const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
178  SDL_SendTouchMotion(xev->sourceid,xev->detail,
179  xev->event_x, xev->event_y, 1.0);
180  return 1;
181  }
182  break;
183 #endif
184  }
185 #endif
186  return 0;
187 }
188 
189 void
191 {
192 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
194  XIDeviceInfo *info;
195  int ndevices,i,j;
196  info = X11_XIQueryDevice(data->display, XIAllDevices, &ndevices);
197 
198  for (i = 0; i < ndevices; i++) {
199  XIDeviceInfo *dev = &info[i];
200  for (j = 0; j < dev->num_classes; j++) {
201  SDL_TouchID touchId;
202  XIAnyClassInfo *class = dev->classes[j];
203  XITouchClassInfo *t = (XITouchClassInfo*)class;
204 
205  /* Only touch devices */
206  if (class->type != XITouchClass)
207  continue;
208 
209  touchId = t->sourceid;
210  SDL_AddTouch(touchId, dev->name);
211  }
212  }
213  X11_XIFreeDeviceInfo(info);
214 #endif
215 }
216 
217 void
219 {
220 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
221  SDL_VideoData *data = NULL;
222  XIEventMask eventmask;
223  unsigned char mask[3] = { 0,0,0 };
224  SDL_WindowData *window_data = NULL;
225 
227  return;
228  }
229 
230  data = (SDL_VideoData *) _this->driverdata;
231  window_data = (SDL_WindowData*)window->driverdata;
232 
233  eventmask.deviceid = XIAllMasterDevices;
234  eventmask.mask_len = sizeof(mask);
235  eventmask.mask = mask;
236 
237  XISetMask(mask, XI_TouchBegin);
238  XISetMask(mask, XI_TouchUpdate);
239  XISetMask(mask, XI_TouchEnd);
240 
241  X11_XISelectEvents(data->display,window_data->xwindow,&eventmask,1);
242 #endif
243 }
244 
245 
246 int
248 {
249 #if SDL_VIDEO_DRIVER_X11_XINPUT2
250  return xinput2_initialized;
251 #else
252  return 0;
253 #endif
254 }
255 
256 int
258 {
259 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
260  return xinput2_initialized && xinput2_multitouch_supported;
261 #else
262  return 0;
263 #endif
264 }
265 
266 #endif /* SDL_VIDEO_DRIVER_X11 */
267 
268 /* vi: set ts=4 sw=4 expandtab: */
SDL_Mouse * SDL_GetMouse(void)
Definition: SDL_mouse.c:66
void X11_InitXinput2(_THIS)
struct wl_display * display
SDL_Window * window
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
int SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_bool down, float x, float y, float pressure)
Definition: SDL_touch.c:216
int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, float x, float y, float pressure)
Definition: SDL_touch.c:278
static SDL_VideoDevice * _this
Definition: SDL_video.c:114
SDL_bool
Definition: SDL_stdinc.h:126
void X11_InitXinput2Multitouch(_THIS)
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
Definition: SDL_mouse.c:188
GLsizei const GLfloat * value
#define _THIS
struct _cl_event * event
int X11_Xinput2IsMultitouchSupported(void)
GLdouble GLdouble t
Definition: SDL_opengl.h:2064
Sint64 SDL_TouchID
Definition: SDL_touch.h:41
int SDL_AddTouch(SDL_TouchID touchID, const char *name)
Definition: SDL_touch.c:130
GLenum GLint GLuint mask
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:42
#define NULL
Definition: begin_code.h:143
GLdouble GLdouble z
The type used to identify a window.
Definition: SDL_sysvideo.h:71
int X11_HandleXinput2Event(SDL_VideoData *videodata, XGenericEventCookie *cookie)
void * driverdata
Definition: SDL_sysvideo.h:106
int X11_Xinput2IsInitialized(void)
struct XGenericEventCookie XGenericEventCookie
GLdouble GLdouble GLdouble GLdouble top
#define SDL_memset
void X11_Xinput2SelectTouch(_THIS, SDL_Window *window)
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:42