src/video/x11/SDL_x11xinput2.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Sun, 30 Oct 2016 21:01:33 +0100
changeset 10563 e3d84016cb79
parent 10018 3c1384edf9fa
child 10737 3406a0f8b041
permissions -rw-r--r--
Fixed outdated info in README.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2016 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_internal.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 X11_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 
    63 static int
    64 query_xinput2_version(Display *display, int major, int minor)
    65 {
    66     /* We don't care if this fails, so long as it sets major/minor on it's way out the door. */
    67     X11_XIQueryVersion(display, &major, &minor);
    68     return ((major * 1000) + minor);
    69 }
    70 
    71 static SDL_bool
    72 xinput2_version_atleast(const int version, const int wantmajor, const int wantminor)
    73 {
    74     return ( version >= ((wantmajor * 1000) + wantminor) );
    75 }
    76 #endif /* SDL_VIDEO_DRIVER_X11_XINPUT2 */
    77 
    78 void
    79 X11_InitXinput2(_THIS)
    80 {
    81 #if SDL_VIDEO_DRIVER_X11_XINPUT2
    82     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    83 
    84     int version = 0;
    85     XIEventMask eventmask;
    86     unsigned char mask[3] = { 0,0,0 };
    87     int event, err;
    88 
    89     /*
    90     * Initialize XInput 2
    91     * According to http://who-t.blogspot.com/2009/05/xi2-recipes-part-1.html its better
    92     * to inform Xserver what version of Xinput we support.The server will store the version we support.
    93     * "As XI2 progresses it becomes important that you use this call as the server may treat the client
    94     * differently depending on the supported version".
    95     *
    96     * FIXME:event and err are not needed but if not passed X11_XQueryExtension returns SegmentationFault
    97     */
    98     if (!SDL_X11_HAVE_XINPUT2 ||
    99         !X11_XQueryExtension(data->display, "XInputExtension", &xinput2_opcode, &event, &err)) {
   100         return; /* X server does not have XInput at all */
   101     }
   102 
   103     /* We need at least 2.2 for Multitouch, 2.0 otherwise. */
   104     version = query_xinput2_version(data->display, 2, 2);
   105     if (!xinput2_version_atleast(version, 2, 0)) {
   106         return; /* X server does not support the version we want at all. */
   107     }
   108 
   109     xinput2_initialized = 1;
   110 
   111 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH  /* Multitouch needs XInput 2.2 */
   112     xinput2_multitouch_supported = xinput2_version_atleast(version, 2, 2);
   113 #endif
   114 
   115     /* Enable  Raw motion events for this display */
   116     eventmask.deviceid = XIAllMasterDevices;
   117     eventmask.mask_len = sizeof(mask);
   118     eventmask.mask = mask;
   119 
   120     XISetMask(mask, XI_RawMotion);
   121     XISetMask(mask, XI_RawButtonPress);
   122     XISetMask(mask, XI_RawButtonRelease);
   123 
   124     if (X11_XISelectEvents(data->display,DefaultRootWindow(data->display),&eventmask,1) != Success) {
   125         return;
   126     }
   127 #endif
   128 }
   129 
   130 int
   131 X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie)
   132 {
   133 #if SDL_VIDEO_DRIVER_X11_XINPUT2
   134     if(cookie->extension != xinput2_opcode) {
   135         return 0;
   136     }
   137     switch(cookie->evtype) {
   138         case XI_RawMotion: {
   139             const XIRawEvent *rawev = (const XIRawEvent*)cookie->data;
   140             SDL_Mouse *mouse = SDL_GetMouse();
   141             double relative_coords[2];
   142             static Time prev_time = 0;
   143             static double prev_rel_coords[2];
   144 
   145             videodata->global_mouse_changed = SDL_TRUE;
   146 
   147             if (!mouse->relative_mode || mouse->relative_mode_warp) {
   148                 return 0;
   149             }
   150 
   151             parse_valuators(rawev->raw_values,rawev->valuators.mask,
   152                             rawev->valuators.mask_len,relative_coords,2);
   153 
   154             if ((rawev->time == prev_time) && (relative_coords[0] == prev_rel_coords[0]) && (relative_coords[1] == prev_rel_coords[1])) {
   155                 return 0;  /* duplicate event, drop it. */
   156             }
   157 
   158             SDL_SendMouseMotion(mouse->focus,mouse->mouseID,1,(int)relative_coords[0],(int)relative_coords[1]);
   159             prev_rel_coords[0] = relative_coords[0];
   160             prev_rel_coords[1] = relative_coords[1];
   161             prev_time = rawev->time;
   162             return 1;
   163             }
   164             break;
   165 
   166         case XI_RawButtonPress:
   167         case XI_RawButtonRelease:
   168             videodata->global_mouse_changed = SDL_TRUE;
   169             break;
   170 
   171 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   172         case XI_TouchBegin: {
   173             const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
   174             SDL_SendTouch(xev->sourceid,xev->detail,
   175                       SDL_TRUE, xev->event_x, xev->event_y, 1.0);
   176             return 1;
   177             }
   178             break;
   179         case XI_TouchEnd: {
   180             const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
   181             SDL_SendTouch(xev->sourceid,xev->detail,
   182                       SDL_FALSE, xev->event_x, xev->event_y, 1.0);
   183             return 1;
   184             }
   185             break;
   186         case XI_TouchUpdate: {
   187             const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
   188             SDL_SendTouchMotion(xev->sourceid,xev->detail,
   189                                 xev->event_x, xev->event_y, 1.0);
   190             return 1;
   191             }
   192             break;
   193 #endif
   194     }
   195 #endif
   196     return 0;
   197 }
   198 
   199 void
   200 X11_InitXinput2Multitouch(_THIS)
   201 {
   202 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   203     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   204     XIDeviceInfo *info;
   205     int ndevices,i,j;
   206     info = X11_XIQueryDevice(data->display, XIAllDevices, &ndevices);
   207 
   208     for (i = 0; i < ndevices; i++) {
   209         XIDeviceInfo *dev = &info[i];
   210         for (j = 0; j < dev->num_classes; j++) {
   211             SDL_TouchID touchId;
   212             XIAnyClassInfo *class = dev->classes[j];
   213             XITouchClassInfo *t = (XITouchClassInfo*)class;
   214 
   215             /* Only touch devices */
   216             if (class->type != XITouchClass)
   217                 continue;
   218 
   219             touchId = t->sourceid;
   220             SDL_AddTouch(touchId, dev->name);
   221         }
   222     }
   223     X11_XIFreeDeviceInfo(info);
   224 #endif
   225 }
   226 
   227 void
   228 X11_Xinput2SelectTouch(_THIS, SDL_Window *window)
   229 {
   230 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   231     SDL_VideoData *data = NULL;
   232     XIEventMask eventmask;
   233     unsigned char mask[3] = { 0,0,0 };
   234     SDL_WindowData *window_data = NULL;
   235     
   236     if (!X11_Xinput2IsMultitouchSupported()) {
   237         return;
   238     }
   239 
   240     data = (SDL_VideoData *) _this->driverdata;
   241     window_data = (SDL_WindowData*)window->driverdata;
   242 
   243     eventmask.deviceid = XIAllMasterDevices;
   244     eventmask.mask_len = sizeof(mask);
   245     eventmask.mask = mask;
   246 
   247     XISetMask(mask, XI_TouchBegin);
   248     XISetMask(mask, XI_TouchUpdate);
   249     XISetMask(mask, XI_TouchEnd);
   250 
   251     X11_XISelectEvents(data->display,window_data->xwindow,&eventmask,1);
   252 #endif
   253 }
   254 
   255 
   256 int
   257 X11_Xinput2IsInitialized()
   258 {
   259 #if SDL_VIDEO_DRIVER_X11_XINPUT2
   260     return xinput2_initialized;
   261 #else
   262     return 0;
   263 #endif
   264 }
   265 
   266 int
   267 X11_Xinput2IsMultitouchSupported()
   268 {
   269 #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   270     return xinput2_initialized && xinput2_multitouch_supported;
   271 #else
   272     return 0;
   273 #endif
   274 }
   275 
   276 #endif /* SDL_VIDEO_DRIVER_X11 */
   277 
   278 /* vi: set ts=4 sw=4 expandtab: */