src/video/x11/SDL_x11xinput2.c
author Gabriel Jacobo <gabomdq@gmail.com>
Wed, 21 Aug 2013 09:47:10 -0300
changeset 7678 286c42d7c5ed
parent 7677 871d43c6968a
child 7679 b1fe132bc6a4
permissions -rw-r--r--
OCD fixes: Adds a space after /* (glory to regular expressions!)
     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 int
   125 X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie)
   126 {
   127 #if SDL_VIDEO_DRIVER_X11_XINPUT2
   128     if(cookie->extension != xinput2_opcode) {
   129         return 0;
   130     }
   131     switch(cookie->evtype) {
   132         case XI_RawMotion: {
   133             const XIRawEvent *rawev = (const XIRawEvent*)cookie->data;
   134             SDL_Mouse *mouse = SDL_GetMouse();
   135             double relative_cords[2];
   136 
   137             if (!mouse->relative_mode) {
   138                 return 0;
   139             }
   140 
   141             parse_valuators(rawev->raw_values,rawev->valuators.mask,
   142                             rawev->valuators.mask_len,relative_cords,2);
   143             SDL_SendMouseMotion(mouse->focus,mouse->mouseID,1,(int)relative_cords[0],(int)relative_cords[1]);
   144             return 1;
   145             }
   146             break;
   147 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   148         case XI_TouchBegin: {
   149             const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
   150             SDL_SendTouch(xev->sourceid,xev->detail,
   151                       SDL_TRUE, xev->event_x, xev->event_y, 1.0);
   152             return 1;
   153             }
   154             break;
   155         case XI_TouchEnd: {
   156             const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
   157             SDL_SendTouch(xev->sourceid,xev->detail,
   158                       SDL_FALSE, xev->event_x, xev->event_y, 1.0);
   159             return 1;
   160             }
   161             break;
   162         case XI_TouchUpdate: {
   163             const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
   164             SDL_SendTouchMotion(xev->sourceid,xev->detail,
   165                                 xev->event_x, xev->event_y, 1.0);
   166             return 1;
   167             }
   168             break;
   169 #endif
   170     }
   171 #endif
   172     return 0;
   173 }
   174 
   175 void
   176 X11_InitXinput2Multitouch(_THIS)
   177 {
   178 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   179     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   180     XIDeviceInfo *info;
   181     int ndevices,i,j;
   182     info = XIQueryDevice(data->display, XIAllMasterDevices, &ndevices);
   183 
   184     for (i = 0; i < ndevices; i++) {
   185         XIDeviceInfo *dev = &info[i];
   186         for (j = 0; j < dev->num_classes; j++) {
   187             SDL_TouchID touchId;
   188             XIAnyClassInfo *class = dev->classes[j];
   189             XITouchClassInfo *t = (XITouchClassInfo*)class;
   190 
   191             /* Only touch devices */
   192             if (class->type != XITouchClass)
   193                 continue;
   194 
   195             touchId = t->sourceid;
   196             if (!SDL_GetTouch(touchId)) {
   197                 SDL_AddTouch(touchId, dev->name);
   198             }
   199         }
   200     }
   201     XIFreeDeviceInfo(info);
   202 #endif
   203 }
   204 
   205 void
   206 X11_Xinput2SelectTouch(_THIS, SDL_Window *window)
   207 {
   208 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   209     if (!X11_Xinput2IsMultitouchSupported()) {
   210         return;
   211     }
   212 
   213     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   214     XIEventMask eventmask;
   215     unsigned char mask[3] = { 0,0,0 };
   216     SDL_WindowData *window_data = (SDL_WindowData*)window->driverdata;
   217 
   218     eventmask.deviceid = XIAllMasterDevices;
   219     eventmask.mask_len = sizeof(mask);
   220     eventmask.mask = mask;
   221 
   222     XISetMask(mask, XI_TouchBegin);
   223     XISetMask(mask, XI_TouchUpdate);
   224     XISetMask(mask, XI_TouchEnd);
   225 
   226     XISelectEvents(data->display,window_data->xwindow,&eventmask,1);
   227 #endif
   228 }
   229 
   230 
   231 int
   232 X11_Xinput2IsInitialized()
   233 {
   234 #if SDL_VIDEO_DRIVER_X11_XINPUT2
   235     return xinput2_initialized;
   236 #else
   237     return 0;
   238 #endif
   239 }
   240 
   241 int
   242 X11_Xinput2IsMultitouchSupported()
   243 {
   244 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   245     return xinput2_initialized && xinput2_multitouch_supported;
   246 #else
   247     return 0;
   248 #endif
   249 }
   250 
   251 #endif /* SDL_VIDEO_DRIVER_X11 */
   252 
   253 /* vi: set ts=4 sw=4 expandtab: */