src/video/x11/SDL_x11xinput2.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 15 Feb 2013 08:47:44 -0800
changeset 6885 700f1b25f77f
parent 6877 7287d385e6b3
child 6950 1ddb72193079
permissions -rw-r--r--
Happy New Year!
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 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 #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 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 #endif /* SDL_VIDEO_DRIVER_X11_XINPUT2 */
    63 
    64 void 
    65 X11_InitXinput2(_THIS)
    66 {
    67 #if SDL_VIDEO_DRIVER_X11_XINPUT2
    68     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    69 
    70     XIEventMask eventmask;
    71     unsigned char mask[3] = { 0,0,0 };
    72     int event, err;
    73     int major = 2, minor = 0;
    74     int outmajor,outminor;
    75 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
    76     minor = 2;
    77 #endif
    78     /*
    79     * Initialize XInput 2
    80     * According to http://who-t.blogspot.com/2009/05/xi2-recipes-part-1.html its better
    81     * to inform Xserver what version of Xinput we support.The server will store the version we support. 
    82     * "As XI2 progresses it becomes important that you use this call as the server may treat the client 
    83     * differently depending on the supported version".
    84     *
    85     * FIXME:event and err are not needed but if not passed XQueryExtension returns SegmentationFault
    86     */
    87     if (!SDL_X11_HAVE_XINPUT2 ||
    88         !XQueryExtension(data->display, "XInputExtension", &xinput2_opcode, &event, &err)) {
    89         return;
    90     }
    91 
    92     outmajor = major;
    93     outminor = minor;
    94     if (XIQueryVersion(data->display, &outmajor, &outminor) != Success) {
    95         return;
    96     }
    97 
    98     /*Check supported version*/
    99     if(outmajor * 1000 + outminor < major * 1000 + minor) {
   100         /*X server does not support the version we want*/
   101         return;
   102     }
   103     xinput2_initialized = 1;
   104 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   105     /*XInput 2.2*/
   106     if(outmajor * 1000 + outminor >= major * 1000 + minor) {
   107         xinput2_multitouch_supported = 1;
   108     }
   109 #endif
   110 
   111     /*Enable  Raw motion events for this display*/
   112     eventmask.deviceid = XIAllMasterDevices;
   113     eventmask.mask_len = sizeof(mask);
   114     eventmask.mask = mask;
   115 
   116     XISetMask(mask, XI_RawMotion);
   117          
   118     if (XISelectEvents(data->display,DefaultRootWindow(data->display),&eventmask,1) != Success) {
   119         return;     
   120     }
   121 #endif
   122 }
   123 
   124 
   125 
   126 int 
   127 X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie)
   128 {
   129 #if SDL_VIDEO_DRIVER_X11_XINPUT2
   130     if(cookie->extension != xinput2_opcode) {
   131         return 0;
   132     }
   133     switch(cookie->evtype) {
   134         case XI_RawMotion: {
   135             const XIRawEvent *rawev = (const XIRawEvent*)cookie->data;
   136             SDL_Mouse *mouse = SDL_GetMouse();
   137             double relative_cords[2];
   138 
   139             if (!mouse->relative_mode) {
   140                 return 0;
   141             }
   142 
   143             parse_valuators(rawev->raw_values,rawev->valuators.mask,
   144                             rawev->valuators.mask_len,relative_cords,2);
   145             SDL_SendMouseMotion(mouse->focus,1,(int)relative_cords[0],(int)relative_cords[1]);
   146             return 1;
   147             }
   148             break;
   149 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   150         case XI_TouchBegin: {
   151             const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
   152             SDL_SendFingerDown(xev->sourceid,xev->detail,
   153                       SDL_TRUE, (int)xev->event_x, (int)xev->event_y,
   154 		    		  1.0);
   155             return 1;
   156             }
   157             break;
   158         case XI_TouchEnd: {
   159             const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
   160             SDL_SendFingerDown(xev->sourceid,xev->detail,
   161                       SDL_FALSE, (int)xev->event_x, (int)xev->event_y,
   162 		    		  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                       SDL_FALSE, (int)xev->event_x, (int)xev->event_y,
   170 		    		  1.0);
   171             return 1;
   172             }
   173             break;
   174 #endif
   175     }
   176 #endif
   177     return 0;
   178 }
   179 
   180 void 
   181 X11_InitXinput2Multitouch(_THIS)
   182 {
   183 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   184     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   185     XIDeviceInfo *info;
   186     int ndevices,i,j;
   187     info = XIQueryDevice(data->display, XIAllMasterDevices, &ndevices);
   188 
   189     for (i = 0; i < ndevices; i++) {
   190         XIDeviceInfo *dev = &info[i];
   191         for (j = 0; j < dev->num_classes; j++) {
   192             SDL_TouchID touchId;
   193             XIAnyClassInfo *class = dev->classes[j];
   194             XITouchClassInfo *t = (XITouchClassInfo*)class;
   195 
   196             /*Only touch devices*/
   197             if (class->type != XITouchClass)
   198                 continue;
   199 
   200             touchId = t->sourceid;
   201             /*Add the touch*/
   202             if (!SDL_GetTouch(touchId)) {
   203                 SDL_Touch touch;
   204 
   205                 touch.id = touchId;
   206                 touch.x_min = 0;
   207                 touch.x_max = 1;
   208                 touch.native_xres = touch.x_max - touch.x_min;
   209                 touch.y_min = 0;
   210                 touch.y_max = 1;
   211                 touch.native_yres = touch.y_max - touch.y_min;
   212                 touch.pressure_min = 0;
   213                 touch.pressure_max = 1;
   214                 touch.native_pressureres = touch.pressure_max - touch.pressure_min;
   215 
   216                 SDL_AddTouch(&touch,dev->name);
   217             }
   218         }
   219     }
   220     XIFreeDeviceInfo(info);
   221 #endif
   222 }
   223 
   224 void 
   225 X11_Xinput2SelectTouch(_THIS, SDL_Window *window)
   226 {
   227 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   228     if (!X11_Xinput2IsMultitouchSupported()) {
   229         return;
   230     }
   231 
   232     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   233     XIEventMask eventmask;
   234     unsigned char mask[3] = { 0,0,0 };
   235     SDL_WindowData *window_data = (SDL_WindowData*)window->driverdata;
   236 
   237     eventmask.deviceid = XIAllMasterDevices;
   238     eventmask.mask_len = sizeof(mask);
   239     eventmask.mask = mask;
   240 
   241     XISetMask(mask, XI_TouchBegin);
   242     XISetMask(mask, XI_TouchUpdate);
   243     XISetMask(mask, XI_TouchEnd);
   244          
   245     XISelectEvents(data->display,window_data->xwindow,&eventmask,1);
   246 #endif
   247 }
   248 
   249 
   250 int 
   251 X11_Xinput2IsInitialized()
   252 {
   253 #if SDL_VIDEO_DRIVER_X11_XINPUT2
   254     return xinput2_initialized;
   255 #else
   256     return 0;
   257 #endif
   258 }
   259 
   260 int
   261 X11_Xinput2IsMultitouchSupported()
   262 {
   263 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   264     return xinput2_initialized && xinput2_multitouch_supported;
   265 #else
   266     return 0;
   267 #endif
   268 }
   269 
   270 #endif /* SDL_VIDEO_DRIVER_X11 */
   271 
   272 /* vi: set ts=4 sw=4 expandtab: */