cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_x11xinput2.c (7980B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 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
     33static int xinput2_initialized = 0;
     34
     35#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
     36static 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 */
     43static int xinput2_opcode;
     44
     45static 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
     63static int
     64query_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
     71static SDL_bool
     72xinput2_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
     78void
     79X11_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
    122    if (X11_XISelectEvents(data->display,DefaultRootWindow(data->display),&eventmask,1) != Success) {
    123        return;
    124    }
    125#endif
    126}
    127
    128int
    129X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie)
    130{
    131#if SDL_VIDEO_DRIVER_X11_XINPUT2
    132    if(cookie->extension != xinput2_opcode) {
    133        return 0;
    134    }
    135    switch(cookie->evtype) {
    136        case XI_RawMotion: {
    137            const XIRawEvent *rawev = (const XIRawEvent*)cookie->data;
    138            SDL_Mouse *mouse = SDL_GetMouse();
    139            double relative_cords[2];
    140
    141            if (!mouse->relative_mode || mouse->relative_mode_warp) {
    142                return 0;
    143            }
    144
    145            parse_valuators(rawev->raw_values,rawev->valuators.mask,
    146                            rawev->valuators.mask_len,relative_cords,2);
    147            SDL_SendMouseMotion(mouse->focus,mouse->mouseID,1,(int)relative_cords[0],(int)relative_cords[1]);
    148            return 1;
    149            }
    150            break;
    151#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
    152        case XI_TouchBegin: {
    153            const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
    154            SDL_SendTouch(xev->sourceid,xev->detail,
    155                      SDL_TRUE, xev->event_x, xev->event_y, 1.0);
    156            return 1;
    157            }
    158            break;
    159        case XI_TouchEnd: {
    160            const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
    161            SDL_SendTouch(xev->sourceid,xev->detail,
    162                      SDL_FALSE, xev->event_x, xev->event_y, 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                                xev->event_x, xev->event_y, 1.0);
    170            return 1;
    171            }
    172            break;
    173#endif
    174    }
    175#endif
    176    return 0;
    177}
    178
    179void
    180X11_InitXinput2Multitouch(_THIS)
    181{
    182#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
    183    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    184    XIDeviceInfo *info;
    185    int ndevices,i,j;
    186    info = X11_XIQueryDevice(data->display, XIAllMasterDevices, &ndevices);
    187
    188    for (i = 0; i < ndevices; i++) {
    189        XIDeviceInfo *dev = &info[i];
    190        for (j = 0; j < dev->num_classes; j++) {
    191            SDL_TouchID touchId;
    192            XIAnyClassInfo *class = dev->classes[j];
    193            XITouchClassInfo *t = (XITouchClassInfo*)class;
    194
    195            /* Only touch devices */
    196            if (class->type != XITouchClass)
    197                continue;
    198
    199            touchId = t->sourceid;
    200            if (!SDL_GetTouch(touchId)) {
    201                SDL_AddTouch(touchId, dev->name);
    202            }
    203        }
    204    }
    205    X11_XIFreeDeviceInfo(info);
    206#endif
    207}
    208
    209void
    210X11_Xinput2SelectTouch(_THIS, SDL_Window *window)
    211{
    212#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
    213    SDL_VideoData *data = NULL;
    214    XIEventMask eventmask;
    215    unsigned char mask[3] = { 0,0,0 };
    216    SDL_WindowData *window_data = NULL;
    217    
    218    if (!X11_Xinput2IsMultitouchSupported()) {
    219        return;
    220    }
    221
    222    data = (SDL_VideoData *) _this->driverdata;
    223    window_data = (SDL_WindowData*)window->driverdata;
    224
    225    eventmask.deviceid = XIAllMasterDevices;
    226    eventmask.mask_len = sizeof(mask);
    227    eventmask.mask = mask;
    228
    229    XISetMask(mask, XI_TouchBegin);
    230    XISetMask(mask, XI_TouchUpdate);
    231    XISetMask(mask, XI_TouchEnd);
    232
    233    X11_XISelectEvents(data->display,window_data->xwindow,&eventmask,1);
    234#endif
    235}
    236
    237
    238int
    239X11_Xinput2IsInitialized()
    240{
    241#if SDL_VIDEO_DRIVER_X11_XINPUT2
    242    return xinput2_initialized;
    243#else
    244    return 0;
    245#endif
    246}
    247
    248int
    249X11_Xinput2IsMultitouchSupported()
    250{
    251#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
    252    return xinput2_initialized && xinput2_multitouch_supported;
    253#else
    254    return 0;
    255#endif
    256}
    257
    258#endif /* SDL_VIDEO_DRIVER_X11 */
    259
    260/* vi: set ts=4 sw=4 expandtab: */