Atlas - SDL_x11xinput2.c

Home / ext / SDL2 / src / video / x11 Lines: 1 | Size: 9835 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 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 void 79xinput2_normalize_touch_coordinates(SDL_VideoData *videodata, Window window, 80 double in_x, double in_y, float *out_x, float *out_y) 81{ 82 int i; 83 for (i = 0; i < videodata->numwindows; i++) { 84 SDL_WindowData *d = videodata->windowlist[i]; 85 if (d->xwindow == window) { 86 if (d->window->w == 1) { 87 *out_x = 0.5f; 88 } else { 89 *out_x = in_x / (d->window->w - 1); 90 } 91 if (d->window->h == 1) { 92 *out_y = 0.5f; 93 } else { 94 *out_y = in_y / (d->window->h - 1); 95 } 96 return; 97 } 98 } 99 // couldn't find the window... 100 *out_x = in_x; 101 *out_y = in_y; 102} 103#endif /* SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH */ 104 105#endif /* SDL_VIDEO_DRIVER_X11_XINPUT2 */ 106 107void 108X11_InitXinput2(_THIS) 109{ 110#if SDL_VIDEO_DRIVER_X11_XINPUT2 111 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 112 113 int version = 0; 114 XIEventMask eventmask; 115 unsigned char mask[3] = { 0,0,0 }; 116 int event, err; 117 118 /* 119 * Initialize XInput 2 120 * According to http://who-t.blogspot.com/2009/05/xi2-recipes-part-1.html its better 121 * to inform Xserver what version of Xinput we support.The server will store the version we support. 122 * "As XI2 progresses it becomes important that you use this call as the server may treat the client 123 * differently depending on the supported version". 124 * 125 * FIXME:event and err are not needed but if not passed X11_XQueryExtension returns SegmentationFault 126 */ 127 if (!SDL_X11_HAVE_XINPUT2 || 128 !X11_XQueryExtension(data->display, "XInputExtension", &xinput2_opcode, &event, &err)) { 129 return; /* X server does not have XInput at all */ 130 } 131 132 /* We need at least 2.2 for Multitouch, 2.0 otherwise. */ 133 version = query_xinput2_version(data->display, 2, 2); 134 if (!xinput2_version_atleast(version, 2, 0)) { 135 return; /* X server does not support the version we want at all. */ 136 } 137 138 xinput2_initialized = 1; 139 140#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH /* Multitouch needs XInput 2.2 */ 141 xinput2_multitouch_supported = xinput2_version_atleast(version, 2, 2); 142#endif 143 144 /* Enable Raw motion events for this display */ 145 eventmask.deviceid = XIAllMasterDevices; 146 eventmask.mask_len = sizeof(mask); 147 eventmask.mask = mask; 148 149 XISetMask(mask, XI_RawMotion); 150 XISetMask(mask, XI_RawButtonPress); 151 XISetMask(mask, XI_RawButtonRelease); 152 153 if (X11_XISelectEvents(data->display,DefaultRootWindow(data->display),&eventmask,1) != Success) { 154 return; 155 } 156#endif 157} 158 159int 160X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie) 161{ 162#if SDL_VIDEO_DRIVER_X11_XINPUT2 163 if(cookie->extension != xinput2_opcode) { 164 return 0; 165 } 166 switch(cookie->evtype) { 167 case XI_RawMotion: { 168 const XIRawEvent *rawev = (const XIRawEvent*)cookie->data; 169 SDL_Mouse *mouse = SDL_GetMouse(); 170 double relative_coords[2]; 171 static Time prev_time = 0; 172 static double prev_rel_coords[2]; 173 174 videodata->global_mouse_changed = SDL_TRUE; 175 176 if (!mouse->relative_mode || mouse->relative_mode_warp) { 177 return 0; 178 } 179 180 parse_valuators(rawev->raw_values,rawev->valuators.mask, 181 rawev->valuators.mask_len,relative_coords,2); 182 183 if ((rawev->time == prev_time) && (relative_coords[0] == prev_rel_coords[0]) && (relative_coords[1] == prev_rel_coords[1])) { 184 return 0; /* duplicate event, drop it. */ 185 } 186 187 SDL_SendMouseMotion(mouse->focus,mouse->mouseID,1,(int)relative_coords[0],(int)relative_coords[1]); 188 prev_rel_coords[0] = relative_coords[0]; 189 prev_rel_coords[1] = relative_coords[1]; 190 prev_time = rawev->time; 191 return 1; 192 } 193 break; 194 195 case XI_RawButtonPress: 196 case XI_RawButtonRelease: 197 videodata->global_mouse_changed = SDL_TRUE; 198 break; 199 200#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH 201 case XI_TouchBegin: { 202 const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data; 203 float x, y; 204 xinput2_normalize_touch_coordinates(videodata, xev->event, 205 xev->event_x, xev->event_y, &x, &y); 206 SDL_SendTouch(xev->sourceid,xev->detail, SDL_TRUE, x, y, 1.0); 207 return 1; 208 } 209 break; 210 case XI_TouchEnd: { 211 const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data; 212 float x, y; 213 xinput2_normalize_touch_coordinates(videodata, xev->event, 214 xev->event_x, xev->event_y, &x, &y); 215 SDL_SendTouch(xev->sourceid,xev->detail, SDL_FALSE, x, y, 1.0); 216 return 1; 217 } 218 break; 219 case XI_TouchUpdate: { 220 const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data; 221 float x, y; 222 xinput2_normalize_touch_coordinates(videodata, xev->event, 223 xev->event_x, xev->event_y, &x, &y); 224 SDL_SendTouchMotion(xev->sourceid,xev->detail, x, y, 1.0); 225 return 1; 226 } 227 break; 228#endif 229 } 230#endif 231 return 0; 232} 233 234void 235X11_InitXinput2Multitouch(_THIS) 236{ 237#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH 238 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 239 XIDeviceInfo *info; 240 int ndevices,i,j; 241 info = X11_XIQueryDevice(data->display, XIAllDevices, &ndevices); 242 243 for (i = 0; i < ndevices; i++) { 244 XIDeviceInfo *dev = &info[i]; 245 for (j = 0; j < dev->num_classes; j++) { 246 SDL_TouchID touchId; 247 XIAnyClassInfo *class = dev->classes[j]; 248 XITouchClassInfo *t = (XITouchClassInfo*)class; 249 250 /* Only touch devices */ 251 if (class->type != XITouchClass) 252 continue; 253 254 touchId = t->sourceid; 255 SDL_AddTouch(touchId, dev->name); 256 } 257 } 258 X11_XIFreeDeviceInfo(info); 259#endif 260} 261 262void 263X11_Xinput2SelectTouch(_THIS, SDL_Window *window) 264{ 265#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH 266 SDL_VideoData *data = NULL; 267 XIEventMask eventmask; 268 unsigned char mask[3] = { 0,0,0 }; 269 SDL_WindowData *window_data = NULL; 270 271 if (!X11_Xinput2IsMultitouchSupported()) { 272 return; 273 } 274 275 data = (SDL_VideoData *) _this->driverdata; 276 window_data = (SDL_WindowData*)window->driverdata; 277 278 eventmask.deviceid = XIAllMasterDevices; 279 eventmask.mask_len = sizeof(mask); 280 eventmask.mask = mask; 281 282 XISetMask(mask, XI_TouchBegin); 283 XISetMask(mask, XI_TouchUpdate); 284 XISetMask(mask, XI_TouchEnd); 285 286 X11_XISelectEvents(data->display,window_data->xwindow,&eventmask,1); 287#endif 288} 289 290 291int 292X11_Xinput2IsInitialized() 293{ 294#if SDL_VIDEO_DRIVER_X11_XINPUT2 295 return xinput2_initialized; 296#else 297 return 0; 298#endif 299} 300 301int 302X11_Xinput2IsMultitouchSupported() 303{ 304#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH 305 return xinput2_initialized && xinput2_multitouch_supported; 306#else 307 return 0; 308#endif 309} 310 311#endif /* SDL_VIDEO_DRIVER_X11 */ 312 313/* vi: set ts=4 sw=4 expandtab: */ 314
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.