src/video/x11/SDL_x11xinput2.c
changeset 6316 a89c79a3f0cd
child 6318 49b2cb56db6e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/video/x11/SDL_x11xinput2.c	Thu May 31 13:37:02 2012 +0300
     1.3 @@ -0,0 +1,249 @@
     1.4 +/*
     1.5 +  Simple DirectMedia Layer
     1.6 +  Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     1.7 +
     1.8 +  This software is provided 'as-is', without any express or implied
     1.9 +  warranty.  In no event will the authors be held liable for any damages
    1.10 +  arising from the use of this software.
    1.11 +
    1.12 +  Permission is granted to anyone to use this software for any purpose,
    1.13 +  including commercial applications, and to alter it and redistribute it
    1.14 +  freely, subject to the following restrictions:
    1.15 +
    1.16 +  1. The origin of this software must not be misrepresented; you must not
    1.17 +     claim that you wrote the original software. If you use this software
    1.18 +     in a product, an acknowledgment in the product documentation would be
    1.19 +     appreciated but is not required.
    1.20 +  2. Altered source versions must be plainly marked as such, and must not be
    1.21 +     misrepresented as being the original software.
    1.22 +  3. This notice may not be removed or altered from any source distribution.
    1.23 +*/
    1.24 +#include "SDL_config.h"
    1.25 +
    1.26 +#if SDL_VIDEO_DRIVER_X11
    1.27 +
    1.28 +#include "SDL_x11video.h"
    1.29 +#include "SDL_x11xinput2.h"
    1.30 +#include "../../events/SDL_mouse_c.h"
    1.31 +#include "../../events/SDL_touch_c.h"
    1.32 +
    1.33 +#define MAX_AXIS 16
    1.34 +
    1.35 +static int xinput2_initialized = 0;
    1.36 +static int xinput2_multitouch_supported = 0;
    1.37 +/* Opcode returned XQueryExtension 
    1.38 + * It will be used in event processing
    1.39 + * to know that the event came from
    1.40 + * this extension */ 
    1.41 +static int xinput2_opcode;
    1.42 +
    1.43 +
    1.44 +#if SDL_VIDEO_DRIVER_X11_XINPUT2
    1.45 +static void parse_valuators(const double *input_values,unsigned char *mask,int mask_len,
    1.46 +                            double *output_values,int output_values_len) {
    1.47 +    int i = 0,z = 0;
    1.48 +    int top = mask_len * 8;
    1.49 +    if (top > MAX_AXIS)
    1.50 +        top = MAX_AXIS;
    1.51 +
    1.52 +    SDL_memset(output_values,0,output_values_len * sizeof(double));
    1.53 +    for (; i < top && z < output_values_len; i++) {
    1.54 +        if (XIMaskIsSet(mask, i)) {
    1.55 +            const int value = (int) *input_values;
    1.56 +            output_values[z] = value;
    1.57 +            input_values++;
    1.58 +        }
    1.59 +        z++;
    1.60 +    }
    1.61 +}
    1.62 +#endif /* SDL_VIDEO_DRIVER_X11_XINPUT2 */
    1.63 +
    1.64 +void 
    1.65 +X11_InitXinput2(_THIS) {
    1.66 +#if SDL_VIDEO_DRIVER_X11_XINPUT2
    1.67 +    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    1.68 +
    1.69 +    XIEventMask eventmask;
    1.70 +    unsigned char mask[3] = { 0,0,0 };
    1.71 +    int event, err;
    1.72 +    int major = 2, minor = 0;
    1.73 +    int outmajor,outminor;
    1.74 +#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
    1.75 +    minor = 2;
    1.76 +#endif
    1.77 +    /*
    1.78 +    * Initialize XInput 2
    1.79 +    * According to http://who-t.blogspot.com/2009/05/xi2-recipes-part-1.html its better
    1.80 +    * to inform Xserver what version of Xinput we support.The server will store the version we support. 
    1.81 +    * "As XI2 progresses it becomes important that you use this call as the server may treat the client 
    1.82 +    * differently depending on the supported version".
    1.83 +    *
    1.84 +    * FIXME:event and err are not needed but if not passed XQueryExtension returns SegmentationFault
    1.85 +    */
    1.86 +    if (!XQueryExtension(data->display, "XInputExtension", &xinput2_opcode, &event, &err)) {
    1.87 +        return;
    1.88 +    }
    1.89 +
    1.90 +    outmajor = major;
    1.91 +    outminor = minor;
    1.92 +    if (XIQueryVersion(data->display, &outmajor, &outminor) != Success) {
    1.93 +        return;
    1.94 +    }
    1.95 +
    1.96 +    /*Check supported version*/
    1.97 +    if(outmajor * 1000 + outminor < major * 1000 + minor) {
    1.98 +        /*X server does not support the version we want*/
    1.99 +        return;
   1.100 +    }
   1.101 +    xinput2_initialized = 1;
   1.102 +#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   1.103 +    /*XInput 2.2*/
   1.104 +    if(outmajor * 1000 + outminor >= major * 1000 + minor) {
   1.105 +        xinput2_multitouch_supported = 1;
   1.106 +    }
   1.107 +#endif
   1.108 +
   1.109 +    /*Enable  Raw motion events for this display*/
   1.110 +    eventmask.deviceid = XIAllMasterDevices;
   1.111 +    eventmask.mask_len = sizeof(mask);
   1.112 +    eventmask.mask = mask;
   1.113 +
   1.114 +    XISetMask(mask, XI_RawMotion);
   1.115 +         
   1.116 +    if (XISelectEvents(data->display,DefaultRootWindow(data->display),&eventmask,1) != Success) {
   1.117 +        return;     
   1.118 +    }
   1.119 +#endif
   1.120 +}
   1.121 +
   1.122 +
   1.123 +
   1.124 +int 
   1.125 +X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie) {
   1.126 +#if SDL_VIDEO_DRIVER_X11_XINPUT2
   1.127 +    if(cookie->extension != xinput2_opcode) {
   1.128 +        return 0;
   1.129 +    }
   1.130 +    switch(cookie->evtype) {
   1.131 +        case XI_RawMotion: {
   1.132 +            const XIRawEvent *rawev = (const XIRawEvent*)cookie->data;
   1.133 +            SDL_Mouse *mouse = SDL_GetMouse();
   1.134 +            double relative_cords[2];
   1.135 +
   1.136 +            if (!mouse->relative_mode) {
   1.137 +                return 0;
   1.138 +            }
   1.139 +
   1.140 +            parse_valuators(rawev->raw_values,rawev->valuators.mask,
   1.141 +                            rawev->valuators.mask_len,relative_cords,2);
   1.142 +            SDL_SendMouseMotion(mouse->focus,1,(int)relative_cords[0],(int)relative_cords[1]);
   1.143 +            return 1;
   1.144 +            }
   1.145 +            break;
   1.146 +#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   1.147 +        case XI_TouchBegin: {
   1.148 +            const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
   1.149 +            SDL_SendFingerDown(xev->sourceid,xev->detail,
   1.150 +                      SDL_TRUE, (int)xev->event_x, (int)xev->event_y,
   1.151 +		    		  1.0);
   1.152 +            return 1;
   1.153 +            }
   1.154 +            break;
   1.155 +        case XI_TouchEnd: {
   1.156 +            const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
   1.157 +            SDL_SendFingerDown(xev->sourceid,xev->detail,
   1.158 +                      SDL_FALSE, (int)xev->event_x, (int)xev->event_y,
   1.159 +		    		  1.0);
   1.160 +            return 1;
   1.161 +            }
   1.162 +            break;
   1.163 +        case XI_TouchUpdate: {
   1.164 +            const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
   1.165 +            SDL_SendTouchMotion(xev->sourceid,xev->detail,
   1.166 +                      SDL_FALSE, (int)xev->event_x, (int)xev->event_y,
   1.167 +		    		  1.0);
   1.168 +            return 1;
   1.169 +            }
   1.170 +            break;
   1.171 +#endif
   1.172 +    }
   1.173 +#endif
   1.174 +    return 0;
   1.175 +}
   1.176 +
   1.177 +void 
   1.178 +X11_InitXinput2Multitouch(_THIS) {
   1.179 +#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   1.180 +    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   1.181 +    XIDeviceInfo *info;
   1.182 +    int ndevices,i,j;
   1.183 +    info = XIQueryDevice(data->display, XIAllMasterDevices, &ndevices);
   1.184 +
   1.185 +    for (i = 0; i < ndevices; i++) {
   1.186 +        XIDeviceInfo *dev = &info[i];
   1.187 +        for (j = 0; j < dev->num_classes; j++) {
   1.188 +            SDL_TouchID touchId;
   1.189 +            XIAnyClassInfo *class = dev->classes[j];
   1.190 +            XITouchClassInfo *t = (XITouchClassInfo*)class;
   1.191 +
   1.192 +            /*Only touch devices*/
   1.193 +            if (class->type != XITouchClass)
   1.194 +                continue;
   1.195 +
   1.196 +            touchId = t->sourceid;
   1.197 +            /*Add the touch*/
   1.198 +            if (!SDL_GetTouch(touchId)) {
   1.199 +                SDL_Touch touch;
   1.200 +
   1.201 +                touch.id = touchId;
   1.202 +                touch.x_min = 0;
   1.203 +                touch.x_max = 1;
   1.204 +                touch.native_xres = touch.x_max - touch.x_min;
   1.205 +                touch.y_min = 0;
   1.206 +                touch.y_max = 1;
   1.207 +                touch.native_yres = touch.y_max - touch.y_min;
   1.208 +                touch.pressure_min = 0;
   1.209 +                touch.pressure_max = 1;
   1.210 +                touch.native_pressureres = touch.pressure_max - touch.pressure_min;
   1.211 +
   1.212 +                SDL_AddTouch(&touch,dev->name);
   1.213 +            }
   1.214 +        }
   1.215 +    }
   1.216 +#endif
   1.217 +}
   1.218 +
   1.219 +void 
   1.220 +X11_Xinput2SelectTouch(_THIS, SDL_Window *window) {
   1.221 +#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   1.222 +    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   1.223 +    XIEventMask eventmask;
   1.224 +    unsigned char mask[3] = { 0,0,0 };
   1.225 +    SDL_WindowData *window_data = (SDL_WindowData*)window->driverdata;
   1.226 +
   1.227 +    eventmask.deviceid = XIAllMasterDevices;
   1.228 +    eventmask.mask_len = sizeof(mask);
   1.229 +    eventmask.mask = mask;
   1.230 +
   1.231 +    XISetMask(mask, XI_TouchBegin);
   1.232 +    XISetMask(mask, XI_TouchUpdate);
   1.233 +    XISetMask(mask, XI_TouchEnd);
   1.234 +         
   1.235 +    XISelectEvents(data->display,window_data->xwindow,&eventmask,1);
   1.236 +#endif
   1.237 +}
   1.238 +
   1.239 +
   1.240 +int 
   1.241 +X11_Xinput2IsInitialized() {
   1.242 +    return xinput2_initialized;
   1.243 +}
   1.244 +
   1.245 +int
   1.246 +X11_Xinput2IsMutitouchSupported() {
   1.247 +    return xinput2_initialized && xinput2_multitouch_supported;
   1.248 +}
   1.249 +
   1.250 +#endif /* SDL_VIDEO_DRIVER_X11 */
   1.251 +
   1.252 +/* vi: set ts=4 sw=4 expandtab: */