src/video/x11/SDL_x11xinput2.c
author Dimitris Zenios <dimitris.zenios@gmail.com>
Thu, 31 May 2012 19:23:30 +0300
changeset 6318 49b2cb56db6e
parent 6316 a89c79a3f0cd
child 6375 93f9a24d1c02
permissions -rw-r--r--
1.Fixed a memory leak inside XInput2 code
2.Replaced XKeycodeToKeysym with XkbKeycodeToKeysym since XKeycodeToKeysym is deprecated in newer X11 version
3.Rewrote testime.c since it was disabled after SDL_compat.c removal
4.Take into account common arguments also in testrelative.c
dimitris@6316
     1
/*
dimitris@6316
     2
  Simple DirectMedia Layer
dimitris@6316
     3
  Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
dimitris@6316
     4
dimitris@6316
     5
  This software is provided 'as-is', without any express or implied
dimitris@6316
     6
  warranty.  In no event will the authors be held liable for any damages
dimitris@6316
     7
  arising from the use of this software.
dimitris@6316
     8
dimitris@6316
     9
  Permission is granted to anyone to use this software for any purpose,
dimitris@6316
    10
  including commercial applications, and to alter it and redistribute it
dimitris@6316
    11
  freely, subject to the following restrictions:
dimitris@6316
    12
dimitris@6316
    13
  1. The origin of this software must not be misrepresented; you must not
dimitris@6316
    14
     claim that you wrote the original software. If you use this software
dimitris@6316
    15
     in a product, an acknowledgment in the product documentation would be
dimitris@6316
    16
     appreciated but is not required.
dimitris@6316
    17
  2. Altered source versions must be plainly marked as such, and must not be
dimitris@6316
    18
     misrepresented as being the original software.
dimitris@6316
    19
  3. This notice may not be removed or altered from any source distribution.
dimitris@6316
    20
*/
dimitris@6316
    21
#include "SDL_config.h"
dimitris@6316
    22
dimitris@6316
    23
#if SDL_VIDEO_DRIVER_X11
dimitris@6316
    24
dimitris@6316
    25
#include "SDL_x11video.h"
dimitris@6316
    26
#include "SDL_x11xinput2.h"
dimitris@6316
    27
#include "../../events/SDL_mouse_c.h"
dimitris@6316
    28
#include "../../events/SDL_touch_c.h"
dimitris@6316
    29
dimitris@6316
    30
#define MAX_AXIS 16
dimitris@6316
    31
dimitris@6316
    32
static int xinput2_initialized = 0;
dimitris@6316
    33
static int xinput2_multitouch_supported = 0;
dimitris@6316
    34
/* Opcode returned XQueryExtension 
dimitris@6316
    35
 * It will be used in event processing
dimitris@6316
    36
 * to know that the event came from
dimitris@6316
    37
 * this extension */ 
dimitris@6316
    38
static int xinput2_opcode;
dimitris@6316
    39
dimitris@6316
    40
dimitris@6316
    41
#if SDL_VIDEO_DRIVER_X11_XINPUT2
dimitris@6316
    42
static void parse_valuators(const double *input_values,unsigned char *mask,int mask_len,
dimitris@6316
    43
                            double *output_values,int output_values_len) {
dimitris@6316
    44
    int i = 0,z = 0;
dimitris@6316
    45
    int top = mask_len * 8;
dimitris@6316
    46
    if (top > MAX_AXIS)
dimitris@6316
    47
        top = MAX_AXIS;
dimitris@6316
    48
dimitris@6316
    49
    SDL_memset(output_values,0,output_values_len * sizeof(double));
dimitris@6316
    50
    for (; i < top && z < output_values_len; i++) {
dimitris@6316
    51
        if (XIMaskIsSet(mask, i)) {
dimitris@6316
    52
            const int value = (int) *input_values;
dimitris@6316
    53
            output_values[z] = value;
dimitris@6316
    54
            input_values++;
dimitris@6316
    55
        }
dimitris@6316
    56
        z++;
dimitris@6316
    57
    }
dimitris@6316
    58
}
dimitris@6316
    59
#endif /* SDL_VIDEO_DRIVER_X11_XINPUT2 */
dimitris@6316
    60
dimitris@6316
    61
void 
dimitris@6316
    62
X11_InitXinput2(_THIS) {
dimitris@6316
    63
#if SDL_VIDEO_DRIVER_X11_XINPUT2
dimitris@6316
    64
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
dimitris@6316
    65
dimitris@6316
    66
    XIEventMask eventmask;
dimitris@6316
    67
    unsigned char mask[3] = { 0,0,0 };
dimitris@6316
    68
    int event, err;
dimitris@6316
    69
    int major = 2, minor = 0;
dimitris@6316
    70
    int outmajor,outminor;
dimitris@6316
    71
#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
dimitris@6316
    72
    minor = 2;
dimitris@6316
    73
#endif
dimitris@6316
    74
    /*
dimitris@6316
    75
    * Initialize XInput 2
dimitris@6316
    76
    * According to http://who-t.blogspot.com/2009/05/xi2-recipes-part-1.html its better
dimitris@6316
    77
    * to inform Xserver what version of Xinput we support.The server will store the version we support. 
dimitris@6316
    78
    * "As XI2 progresses it becomes important that you use this call as the server may treat the client 
dimitris@6316
    79
    * differently depending on the supported version".
dimitris@6316
    80
    *
dimitris@6316
    81
    * FIXME:event and err are not needed but if not passed XQueryExtension returns SegmentationFault
dimitris@6316
    82
    */
dimitris@6316
    83
    if (!XQueryExtension(data->display, "XInputExtension", &xinput2_opcode, &event, &err)) {
dimitris@6316
    84
        return;
dimitris@6316
    85
    }
dimitris@6316
    86
dimitris@6316
    87
    outmajor = major;
dimitris@6316
    88
    outminor = minor;
dimitris@6316
    89
    if (XIQueryVersion(data->display, &outmajor, &outminor) != Success) {
dimitris@6316
    90
        return;
dimitris@6316
    91
    }
dimitris@6316
    92
dimitris@6316
    93
    /*Check supported version*/
dimitris@6316
    94
    if(outmajor * 1000 + outminor < major * 1000 + minor) {
dimitris@6316
    95
        /*X server does not support the version we want*/
dimitris@6316
    96
        return;
dimitris@6316
    97
    }
dimitris@6316
    98
    xinput2_initialized = 1;
dimitris@6316
    99
#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
dimitris@6316
   100
    /*XInput 2.2*/
dimitris@6316
   101
    if(outmajor * 1000 + outminor >= major * 1000 + minor) {
dimitris@6316
   102
        xinput2_multitouch_supported = 1;
dimitris@6316
   103
    }
dimitris@6316
   104
#endif
dimitris@6316
   105
dimitris@6316
   106
    /*Enable  Raw motion events for this display*/
dimitris@6316
   107
    eventmask.deviceid = XIAllMasterDevices;
dimitris@6316
   108
    eventmask.mask_len = sizeof(mask);
dimitris@6316
   109
    eventmask.mask = mask;
dimitris@6316
   110
dimitris@6316
   111
    XISetMask(mask, XI_RawMotion);
dimitris@6316
   112
         
dimitris@6316
   113
    if (XISelectEvents(data->display,DefaultRootWindow(data->display),&eventmask,1) != Success) {
dimitris@6316
   114
        return;     
dimitris@6316
   115
    }
dimitris@6316
   116
#endif
dimitris@6316
   117
}
dimitris@6316
   118
dimitris@6316
   119
dimitris@6316
   120
dimitris@6316
   121
int 
dimitris@6316
   122
X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie) {
dimitris@6316
   123
#if SDL_VIDEO_DRIVER_X11_XINPUT2
dimitris@6316
   124
    if(cookie->extension != xinput2_opcode) {
dimitris@6316
   125
        return 0;
dimitris@6316
   126
    }
dimitris@6316
   127
    switch(cookie->evtype) {
dimitris@6316
   128
        case XI_RawMotion: {
dimitris@6316
   129
            const XIRawEvent *rawev = (const XIRawEvent*)cookie->data;
dimitris@6316
   130
            SDL_Mouse *mouse = SDL_GetMouse();
dimitris@6316
   131
            double relative_cords[2];
dimitris@6316
   132
dimitris@6316
   133
            if (!mouse->relative_mode) {
dimitris@6316
   134
                return 0;
dimitris@6316
   135
            }
dimitris@6316
   136
dimitris@6316
   137
            parse_valuators(rawev->raw_values,rawev->valuators.mask,
dimitris@6316
   138
                            rawev->valuators.mask_len,relative_cords,2);
dimitris@6316
   139
            SDL_SendMouseMotion(mouse->focus,1,(int)relative_cords[0],(int)relative_cords[1]);
dimitris@6316
   140
            return 1;
dimitris@6316
   141
            }
dimitris@6316
   142
            break;
dimitris@6316
   143
#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
dimitris@6316
   144
        case XI_TouchBegin: {
dimitris@6316
   145
            const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
dimitris@6316
   146
            SDL_SendFingerDown(xev->sourceid,xev->detail,
dimitris@6316
   147
                      SDL_TRUE, (int)xev->event_x, (int)xev->event_y,
dimitris@6316
   148
		    		  1.0);
dimitris@6316
   149
            return 1;
dimitris@6316
   150
            }
dimitris@6316
   151
            break;
dimitris@6316
   152
        case XI_TouchEnd: {
dimitris@6316
   153
            const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
dimitris@6316
   154
            SDL_SendFingerDown(xev->sourceid,xev->detail,
dimitris@6316
   155
                      SDL_FALSE, (int)xev->event_x, (int)xev->event_y,
dimitris@6316
   156
		    		  1.0);
dimitris@6316
   157
            return 1;
dimitris@6316
   158
            }
dimitris@6316
   159
            break;
dimitris@6316
   160
        case XI_TouchUpdate: {
dimitris@6316
   161
            const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
dimitris@6316
   162
            SDL_SendTouchMotion(xev->sourceid,xev->detail,
dimitris@6316
   163
                      SDL_FALSE, (int)xev->event_x, (int)xev->event_y,
dimitris@6316
   164
		    		  1.0);
dimitris@6316
   165
            return 1;
dimitris@6316
   166
            }
dimitris@6316
   167
            break;
dimitris@6316
   168
#endif
dimitris@6316
   169
    }
dimitris@6316
   170
#endif
dimitris@6316
   171
    return 0;
dimitris@6316
   172
}
dimitris@6316
   173
dimitris@6316
   174
void 
dimitris@6316
   175
X11_InitXinput2Multitouch(_THIS) {
dimitris@6316
   176
#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
dimitris@6316
   177
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
dimitris@6316
   178
    XIDeviceInfo *info;
dimitris@6316
   179
    int ndevices,i,j;
dimitris@6316
   180
    info = XIQueryDevice(data->display, XIAllMasterDevices, &ndevices);
dimitris@6316
   181
dimitris@6316
   182
    for (i = 0; i < ndevices; i++) {
dimitris@6316
   183
        XIDeviceInfo *dev = &info[i];
dimitris@6316
   184
        for (j = 0; j < dev->num_classes; j++) {
dimitris@6316
   185
            SDL_TouchID touchId;
dimitris@6316
   186
            XIAnyClassInfo *class = dev->classes[j];
dimitris@6316
   187
            XITouchClassInfo *t = (XITouchClassInfo*)class;
dimitris@6316
   188
dimitris@6316
   189
            /*Only touch devices*/
dimitris@6316
   190
            if (class->type != XITouchClass)
dimitris@6316
   191
                continue;
dimitris@6316
   192
dimitris@6316
   193
            touchId = t->sourceid;
dimitris@6316
   194
            /*Add the touch*/
dimitris@6316
   195
            if (!SDL_GetTouch(touchId)) {
dimitris@6316
   196
                SDL_Touch touch;
dimitris@6316
   197
dimitris@6316
   198
                touch.id = touchId;
dimitris@6316
   199
                touch.x_min = 0;
dimitris@6316
   200
                touch.x_max = 1;
dimitris@6316
   201
                touch.native_xres = touch.x_max - touch.x_min;
dimitris@6316
   202
                touch.y_min = 0;
dimitris@6316
   203
                touch.y_max = 1;
dimitris@6316
   204
                touch.native_yres = touch.y_max - touch.y_min;
dimitris@6316
   205
                touch.pressure_min = 0;
dimitris@6316
   206
                touch.pressure_max = 1;
dimitris@6316
   207
                touch.native_pressureres = touch.pressure_max - touch.pressure_min;
dimitris@6316
   208
dimitris@6316
   209
                SDL_AddTouch(&touch,dev->name);
dimitris@6316
   210
            }
dimitris@6316
   211
        }
dimitris@6316
   212
    }
dimitris@6318
   213
    XIFreeDeviceInfo(info);
dimitris@6316
   214
#endif
dimitris@6316
   215
}
dimitris@6316
   216
dimitris@6316
   217
void 
dimitris@6316
   218
X11_Xinput2SelectTouch(_THIS, SDL_Window *window) {
dimitris@6316
   219
#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
dimitris@6316
   220
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
dimitris@6316
   221
    XIEventMask eventmask;
dimitris@6316
   222
    unsigned char mask[3] = { 0,0,0 };
dimitris@6316
   223
    SDL_WindowData *window_data = (SDL_WindowData*)window->driverdata;
dimitris@6316
   224
dimitris@6316
   225
    eventmask.deviceid = XIAllMasterDevices;
dimitris@6316
   226
    eventmask.mask_len = sizeof(mask);
dimitris@6316
   227
    eventmask.mask = mask;
dimitris@6316
   228
dimitris@6316
   229
    XISetMask(mask, XI_TouchBegin);
dimitris@6316
   230
    XISetMask(mask, XI_TouchUpdate);
dimitris@6316
   231
    XISetMask(mask, XI_TouchEnd);
dimitris@6316
   232
         
dimitris@6316
   233
    XISelectEvents(data->display,window_data->xwindow,&eventmask,1);
dimitris@6316
   234
#endif
dimitris@6316
   235
}
dimitris@6316
   236
dimitris@6316
   237
dimitris@6316
   238
int 
dimitris@6316
   239
X11_Xinput2IsInitialized() {
dimitris@6316
   240
    return xinput2_initialized;
dimitris@6316
   241
}
dimitris@6316
   242
dimitris@6316
   243
int
dimitris@6316
   244
X11_Xinput2IsMutitouchSupported() {
dimitris@6316
   245
    return xinput2_initialized && xinput2_multitouch_supported;
dimitris@6316
   246
}
dimitris@6316
   247
dimitris@6316
   248
#endif /* SDL_VIDEO_DRIVER_X11 */
dimitris@6316
   249
dimitris@6316
   250
/* vi: set ts=4 sw=4 expandtab: */