src/video/x11/SDL_x11xinput2.c
author Dimitris Zenios <dimitris.zenios@gmail.com>
Thu, 31 May 2012 13:37:02 +0300
changeset 6316 a89c79a3f0cd
child 6318 49b2cb56db6e
permissions -rw-r--r--
1.Moved all xinput2 functionality to its own file
2.Implement touch events using Xinput2.Leave evtouch as a fallback when xinput2 is not supported
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 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_config.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 static int xinput2_initialized = 0;
    33 static int xinput2_multitouch_supported = 0;
    34 /* Opcode returned XQueryExtension 
    35  * It will be used in event processing
    36  * to know that the event came from
    37  * this extension */ 
    38 static int xinput2_opcode;
    39 
    40 
    41 #if SDL_VIDEO_DRIVER_X11_XINPUT2
    42 static void parse_valuators(const double *input_values,unsigned char *mask,int mask_len,
    43                             double *output_values,int output_values_len) {
    44     int i = 0,z = 0;
    45     int top = mask_len * 8;
    46     if (top > MAX_AXIS)
    47         top = MAX_AXIS;
    48 
    49     SDL_memset(output_values,0,output_values_len * sizeof(double));
    50     for (; i < top && z < output_values_len; i++) {
    51         if (XIMaskIsSet(mask, i)) {
    52             const int value = (int) *input_values;
    53             output_values[z] = value;
    54             input_values++;
    55         }
    56         z++;
    57     }
    58 }
    59 #endif /* SDL_VIDEO_DRIVER_X11_XINPUT2 */
    60 
    61 void 
    62 X11_InitXinput2(_THIS) {
    63 #if SDL_VIDEO_DRIVER_X11_XINPUT2
    64     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    65 
    66     XIEventMask eventmask;
    67     unsigned char mask[3] = { 0,0,0 };
    68     int event, err;
    69     int major = 2, minor = 0;
    70     int outmajor,outminor;
    71 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
    72     minor = 2;
    73 #endif
    74     /*
    75     * Initialize XInput 2
    76     * According to http://who-t.blogspot.com/2009/05/xi2-recipes-part-1.html its better
    77     * to inform Xserver what version of Xinput we support.The server will store the version we support. 
    78     * "As XI2 progresses it becomes important that you use this call as the server may treat the client 
    79     * differently depending on the supported version".
    80     *
    81     * FIXME:event and err are not needed but if not passed XQueryExtension returns SegmentationFault
    82     */
    83     if (!XQueryExtension(data->display, "XInputExtension", &xinput2_opcode, &event, &err)) {
    84         return;
    85     }
    86 
    87     outmajor = major;
    88     outminor = minor;
    89     if (XIQueryVersion(data->display, &outmajor, &outminor) != Success) {
    90         return;
    91     }
    92 
    93     /*Check supported version*/
    94     if(outmajor * 1000 + outminor < major * 1000 + minor) {
    95         /*X server does not support the version we want*/
    96         return;
    97     }
    98     xinput2_initialized = 1;
    99 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   100     /*XInput 2.2*/
   101     if(outmajor * 1000 + outminor >= major * 1000 + minor) {
   102         xinput2_multitouch_supported = 1;
   103     }
   104 #endif
   105 
   106     /*Enable  Raw motion events for this display*/
   107     eventmask.deviceid = XIAllMasterDevices;
   108     eventmask.mask_len = sizeof(mask);
   109     eventmask.mask = mask;
   110 
   111     XISetMask(mask, XI_RawMotion);
   112          
   113     if (XISelectEvents(data->display,DefaultRootWindow(data->display),&eventmask,1) != Success) {
   114         return;     
   115     }
   116 #endif
   117 }
   118 
   119 
   120 
   121 int 
   122 X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie) {
   123 #if SDL_VIDEO_DRIVER_X11_XINPUT2
   124     if(cookie->extension != xinput2_opcode) {
   125         return 0;
   126     }
   127     switch(cookie->evtype) {
   128         case XI_RawMotion: {
   129             const XIRawEvent *rawev = (const XIRawEvent*)cookie->data;
   130             SDL_Mouse *mouse = SDL_GetMouse();
   131             double relative_cords[2];
   132 
   133             if (!mouse->relative_mode) {
   134                 return 0;
   135             }
   136 
   137             parse_valuators(rawev->raw_values,rawev->valuators.mask,
   138                             rawev->valuators.mask_len,relative_cords,2);
   139             SDL_SendMouseMotion(mouse->focus,1,(int)relative_cords[0],(int)relative_cords[1]);
   140             return 1;
   141             }
   142             break;
   143 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   144         case XI_TouchBegin: {
   145             const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
   146             SDL_SendFingerDown(xev->sourceid,xev->detail,
   147                       SDL_TRUE, (int)xev->event_x, (int)xev->event_y,
   148 		    		  1.0);
   149             return 1;
   150             }
   151             break;
   152         case XI_TouchEnd: {
   153             const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
   154             SDL_SendFingerDown(xev->sourceid,xev->detail,
   155                       SDL_FALSE, (int)xev->event_x, (int)xev->event_y,
   156 		    		  1.0);
   157             return 1;
   158             }
   159             break;
   160         case XI_TouchUpdate: {
   161             const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
   162             SDL_SendTouchMotion(xev->sourceid,xev->detail,
   163                       SDL_FALSE, (int)xev->event_x, (int)xev->event_y,
   164 		    		  1.0);
   165             return 1;
   166             }
   167             break;
   168 #endif
   169     }
   170 #endif
   171     return 0;
   172 }
   173 
   174 void 
   175 X11_InitXinput2Multitouch(_THIS) {
   176 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   177     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   178     XIDeviceInfo *info;
   179     int ndevices,i,j;
   180     info = XIQueryDevice(data->display, XIAllMasterDevices, &ndevices);
   181 
   182     for (i = 0; i < ndevices; i++) {
   183         XIDeviceInfo *dev = &info[i];
   184         for (j = 0; j < dev->num_classes; j++) {
   185             SDL_TouchID touchId;
   186             XIAnyClassInfo *class = dev->classes[j];
   187             XITouchClassInfo *t = (XITouchClassInfo*)class;
   188 
   189             /*Only touch devices*/
   190             if (class->type != XITouchClass)
   191                 continue;
   192 
   193             touchId = t->sourceid;
   194             /*Add the touch*/
   195             if (!SDL_GetTouch(touchId)) {
   196                 SDL_Touch touch;
   197 
   198                 touch.id = touchId;
   199                 touch.x_min = 0;
   200                 touch.x_max = 1;
   201                 touch.native_xres = touch.x_max - touch.x_min;
   202                 touch.y_min = 0;
   203                 touch.y_max = 1;
   204                 touch.native_yres = touch.y_max - touch.y_min;
   205                 touch.pressure_min = 0;
   206                 touch.pressure_max = 1;
   207                 touch.native_pressureres = touch.pressure_max - touch.pressure_min;
   208 
   209                 SDL_AddTouch(&touch,dev->name);
   210             }
   211         }
   212     }
   213 #endif
   214 }
   215 
   216 void 
   217 X11_Xinput2SelectTouch(_THIS, SDL_Window *window) {
   218 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   219     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   220     XIEventMask eventmask;
   221     unsigned char mask[3] = { 0,0,0 };
   222     SDL_WindowData *window_data = (SDL_WindowData*)window->driverdata;
   223 
   224     eventmask.deviceid = XIAllMasterDevices;
   225     eventmask.mask_len = sizeof(mask);
   226     eventmask.mask = mask;
   227 
   228     XISetMask(mask, XI_TouchBegin);
   229     XISetMask(mask, XI_TouchUpdate);
   230     XISetMask(mask, XI_TouchEnd);
   231          
   232     XISelectEvents(data->display,window_data->xwindow,&eventmask,1);
   233 #endif
   234 }
   235 
   236 
   237 int 
   238 X11_Xinput2IsInitialized() {
   239     return xinput2_initialized;
   240 }
   241 
   242 int
   243 X11_Xinput2IsMutitouchSupported() {
   244     return xinput2_initialized && xinput2_multitouch_supported;
   245 }
   246 
   247 #endif /* SDL_VIDEO_DRIVER_X11 */
   248 
   249 /* vi: set ts=4 sw=4 expandtab: */