SDL_x11xinput2.c (7980B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 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#endif /* SDL_VIDEO_DRIVER_X11_XINPUT2 */ 77 78void 79X11_InitXinput2(_THIS) 80{ 81#if SDL_VIDEO_DRIVER_X11_XINPUT2 82 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 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 128int 129X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie) 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_cords[2]; 140 141 if (!mouse->relative_mode || mouse->relative_mode_warp) { 142 return 0; 143 } 144 145 parse_valuators(rawev->raw_values,rawev->valuators.mask, 146 rawev->valuators.mask_len,relative_cords,2); 147 SDL_SendMouseMotion(mouse->focus,mouse->mouseID,1,(int)relative_cords[0],(int)relative_cords[1]); 148 return 1; 149 } 150 break; 151#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH 152 case XI_TouchBegin: { 153 const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data; 154 SDL_SendTouch(xev->sourceid,xev->detail, 155 SDL_TRUE, xev->event_x, xev->event_y, 1.0); 156 return 1; 157 } 158 break; 159 case XI_TouchEnd: { 160 const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data; 161 SDL_SendTouch(xev->sourceid,xev->detail, 162 SDL_FALSE, xev->event_x, xev->event_y, 1.0); 163 return 1; 164 } 165 break; 166 case XI_TouchUpdate: { 167 const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data; 168 SDL_SendTouchMotion(xev->sourceid,xev->detail, 169 xev->event_x, xev->event_y, 1.0); 170 return 1; 171 } 172 break; 173#endif 174 } 175#endif 176 return 0; 177} 178 179void 180X11_InitXinput2Multitouch(_THIS) 181{ 182#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH 183 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 184 XIDeviceInfo *info; 185 int ndevices,i,j; 186 info = X11_XIQueryDevice(data->display, XIAllMasterDevices, &ndevices); 187 188 for (i = 0; i < ndevices; i++) { 189 XIDeviceInfo *dev = &info[i]; 190 for (j = 0; j < dev->num_classes; j++) { 191 SDL_TouchID touchId; 192 XIAnyClassInfo *class = dev->classes[j]; 193 XITouchClassInfo *t = (XITouchClassInfo*)class; 194 195 /* Only touch devices */ 196 if (class->type != XITouchClass) 197 continue; 198 199 touchId = t->sourceid; 200 if (!SDL_GetTouch(touchId)) { 201 SDL_AddTouch(touchId, dev->name); 202 } 203 } 204 } 205 X11_XIFreeDeviceInfo(info); 206#endif 207} 208 209void 210X11_Xinput2SelectTouch(_THIS, SDL_Window *window) 211{ 212#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH 213 SDL_VideoData *data = NULL; 214 XIEventMask eventmask; 215 unsigned char mask[3] = { 0,0,0 }; 216 SDL_WindowData *window_data = NULL; 217 218 if (!X11_Xinput2IsMultitouchSupported()) { 219 return; 220 } 221 222 data = (SDL_VideoData *) _this->driverdata; 223 window_data = (SDL_WindowData*)window->driverdata; 224 225 eventmask.deviceid = XIAllMasterDevices; 226 eventmask.mask_len = sizeof(mask); 227 eventmask.mask = mask; 228 229 XISetMask(mask, XI_TouchBegin); 230 XISetMask(mask, XI_TouchUpdate); 231 XISetMask(mask, XI_TouchEnd); 232 233 X11_XISelectEvents(data->display,window_data->xwindow,&eventmask,1); 234#endif 235} 236 237 238int 239X11_Xinput2IsInitialized() 240{ 241#if SDL_VIDEO_DRIVER_X11_XINPUT2 242 return xinput2_initialized; 243#else 244 return 0; 245#endif 246} 247 248int 249X11_Xinput2IsMultitouchSupported() 250{ 251#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH 252 return xinput2_initialized && xinput2_multitouch_supported; 253#else 254 return 0; 255#endif 256} 257 258#endif /* SDL_VIDEO_DRIVER_X11 */ 259 260/* vi: set ts=4 sw=4 expandtab: */