src/core/linux/SDL_evdev.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 01 Oct 2016 13:51:56 -0700
changeset 10433 0f79dd727ed6
parent 9998 f67cf37e9cd4
child 10445 d18516d69e7f
permissions -rw-r--r--
Fixed bug 3157 - Rudimentary touchscreen support in SDL_evdev (supports Raspberry Pi)

tvc

I've spent the last few days implementing touchscreen support in core/linux/SDL_evdev.c. It's fairly rudimentary at the moment, as can be seen from the multiple TODO's and FIXME's littered throughout, but I'm mainly submitting this patch for review. I've tested this patch on my Raspberry Pi 2 with the official touchscreen and it works fantastically, reporting all 10 multitouch points. I'm happy to work on this further, the evdev logic also needs a bit of a cleanup I think (I may have included a few changes). But if it's good enough in its current state to be committed then I'm sure there'd be plenty of people pleased, as currently the only other framework/library that supports touchscreens on the Raspberry Pi is Kivy.
gabomdq@7753
     1
/*
gabomdq@7753
     2
  Simple DirectMedia Layer
slouken@9998
     3
  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
gabomdq@7753
     4
gabomdq@7753
     5
  This software is provided 'as-is', without any express or implied
gabomdq@7753
     6
  warranty.  In no event will the authors be held liable for any damages
gabomdq@7753
     7
  arising from the use of this software.
gabomdq@7753
     8
gabomdq@7753
     9
  Permission is granted to anyone to use this software for any purpose,
gabomdq@7753
    10
  including commercial applications, and to alter it and redistribute it
gabomdq@7753
    11
  freely, subject to the following restrictions:
gabomdq@7753
    12
gabomdq@7753
    13
  1. The origin of this software must not be misrepresented; you must not
gabomdq@7753
    14
     claim that you wrote the original software. If you use this software
gabomdq@7753
    15
     in a product, an acknowledgment in the product documentation would be
gabomdq@7753
    16
     appreciated but is not required.
gabomdq@7753
    17
  2. Altered source versions must be plainly marked as such, and must not be
gabomdq@7753
    18
     misrepresented as being the original software.
gabomdq@7753
    19
  3. This notice may not be removed or altered from any source distribution.
gabomdq@7753
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
gabomdq@7753
    22
gabomdq@7753
    23
#ifdef SDL_INPUT_LINUXEV
gabomdq@7753
    24
gabomdq@7753
    25
/* This is based on the linux joystick driver */
gabomdq@7753
    26
/* References: https://www.kernel.org/doc/Documentation/input/input.txt 
gabomdq@7753
    27
 *             https://www.kernel.org/doc/Documentation/input/event-codes.txt
gabomdq@7753
    28
 *             /usr/include/linux/input.h
gabomdq@7753
    29
 *             The evtest application is also useful to debug the protocol
gabomdq@7753
    30
 */
gabomdq@7753
    31
gabomdq@7753
    32
#include "SDL_evdev.h"
gabomdq@7753
    33
gabomdq@7753
    34
#include <sys/stat.h>
gabomdq@7753
    35
#include <unistd.h>
gabomdq@7753
    36
#include <fcntl.h>
gabomdq@7753
    37
#include <sys/ioctl.h>
gabomdq@7753
    38
#include <limits.h>             /* For the definition of PATH_MAX */
gabomdq@7778
    39
#include <linux/input.h>
gabomdq@7778
    40
#ifdef SDL_INPUT_LINUXKD
gabomdq@7778
    41
#include <linux/kd.h>
gabomdq@7778
    42
#include <linux/keyboard.h>
slouken@10433
    43
#include <linux/vt.h>
slouken@10433
    44
#include <linux/tiocl.h> /* for TIOCL_GETSHIFTSTATE */
gabomdq@7809
    45
#endif
gabomdq@7809
    46
gabomdq@7753
    47
#include "SDL.h"
gabomdq@7753
    48
#include "SDL_assert.h"
gabomdq@7753
    49
#include "SDL_endian.h"
gabomdq@7753
    50
#include "../../core/linux/SDL_udev.h"
gabomdq@7753
    51
#include "SDL_scancode.h"
gabomdq@7753
    52
#include "../../events/SDL_events_c.h"
slouken@10433
    53
#include "../../events/scancodes_linux.h" /* adds linux_scancode_table */
gabomdq@7753
    54
gabomdq@7753
    55
/* This isn't defined in older Linux kernel headers */
gabomdq@7753
    56
#ifndef SYN_DROPPED
gabomdq@7753
    57
#define SYN_DROPPED 3
gabomdq@7753
    58
#endif
gabomdq@7753
    59
slouken@10433
    60
typedef struct SDL_evdevlist_item
slouken@10433
    61
{
slouken@10433
    62
    char *path;
slouken@10433
    63
    int fd;
slouken@10433
    64
    
slouken@10433
    65
    /* TODO: use this for every device, not just touchscreen */
slouken@10433
    66
    int out_of_sync;
slouken@10433
    67
    
slouken@10433
    68
    /* TODO: expand on this to have data for every possible class (mouse,
slouken@10433
    69
       keyboard, touchpad, etc.). Also there's probably some things in here we
slouken@10433
    70
       can pull out to the SDL_evdevlist_item i.e. name */
slouken@10433
    71
    int is_touchscreen;
slouken@10433
    72
    struct {
slouken@10433
    73
        char* name;
slouken@10433
    74
        
slouken@10433
    75
        int min_x, max_x, range_x;
slouken@10433
    76
        int min_y, max_y, range_y;
slouken@10433
    77
        
slouken@10433
    78
        int max_slots;
slouken@10433
    79
        int current_slot;
slouken@10433
    80
        struct {
slouken@10433
    81
            enum {
slouken@10433
    82
                EVDEV_TOUCH_SLOTDELTA_NONE = 0,
slouken@10433
    83
                EVDEV_TOUCH_SLOTDELTA_DOWN,
slouken@10433
    84
                EVDEV_TOUCH_SLOTDELTA_UP,
slouken@10433
    85
                EVDEV_TOUCH_SLOTDELTA_MOVE
slouken@10433
    86
            } delta;
slouken@10433
    87
            int tracking_id;
slouken@10433
    88
            int x, y;
slouken@10433
    89
        } * slots;
slouken@10433
    90
    } * touchscreen_data;
slouken@10433
    91
    
slouken@10433
    92
    struct SDL_evdevlist_item *next;
slouken@10433
    93
} SDL_evdevlist_item;
slouken@10433
    94
slouken@10433
    95
typedef struct SDL_EVDEV_PrivateData
slouken@10433
    96
{
slouken@10433
    97
    SDL_evdevlist_item *first;
slouken@10433
    98
    SDL_evdevlist_item *last;
slouken@10433
    99
    int num_devices;
slouken@10433
   100
    int ref_count;
slouken@10433
   101
    int console_fd;
slouken@10433
   102
    int kb_mode;
slouken@10433
   103
} SDL_EVDEV_PrivateData;
slouken@10433
   104
slouken@10433
   105
#define _THIS SDL_EVDEV_PrivateData *_this
slouken@10433
   106
static _THIS = NULL;
slouken@10433
   107
gabomdq@7755
   108
static SDL_Scancode SDL_EVDEV_translate_keycode(int keycode);
gabomdq@7755
   109
static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item);
slouken@10433
   110
static int SDL_EVDEV_device_removed(const char *dev_path);
gabomdq@7753
   111
gabomdq@7755
   112
#if SDL_USE_LIBUDEV
slouken@10433
   113
static int SDL_EVDEV_device_added( const char *dev_path, int udev_class );
slouken@10433
   114
void SDL_EVDEV_udev_callback( SDL_UDEV_deviceevent udev_type, int udev_class,
slouken@10433
   115
    const char *dev_path );
gabomdq@7755
   116
#endif /* SDL_USE_LIBUDEV */
gabomdq@7753
   117
gabomdq@7753
   118
static Uint8 EVDEV_MouseButtons[] = {
gabomdq@7753
   119
    SDL_BUTTON_LEFT,            /*  BTN_LEFT        0x110 */
gabomdq@7753
   120
    SDL_BUTTON_RIGHT,           /*  BTN_RIGHT       0x111 */
gabomdq@7753
   121
    SDL_BUTTON_MIDDLE,          /*  BTN_MIDDLE      0x112 */
gabomdq@7753
   122
    SDL_BUTTON_X1,              /*  BTN_SIDE        0x113 */
gabomdq@7753
   123
    SDL_BUTTON_X2,              /*  BTN_EXTRA       0x114 */
gabomdq@7753
   124
    SDL_BUTTON_X2 + 1,          /*  BTN_FORWARD     0x115 */
gabomdq@7753
   125
    SDL_BUTTON_X2 + 2,          /*  BTN_BACK        0x116 */
gabomdq@7753
   126
    SDL_BUTTON_X2 + 3           /*  BTN_TASK        0x117 */
gabomdq@7753
   127
};
gabomdq@7753
   128
icculus@9729
   129
static const char* EVDEV_consoles[] = {
slouken@10433
   130
    /* "/proc/self/fd/0",
gabomdq@7778
   131
    "/dev/tty",
slouken@10433
   132
    "/dev/tty0", */ /* the tty ioctl's prohibit these */
gabomdq@7778
   133
    "/dev/tty1",
gabomdq@7778
   134
    "/dev/tty2",
gabomdq@7778
   135
    "/dev/tty3",
gabomdq@7778
   136
    "/dev/tty4",
gabomdq@7778
   137
    "/dev/tty5",
gabomdq@7778
   138
    "/dev/tty6",
slouken@10433
   139
    "/dev/tty7", /* usually X is spawned in tty7 */
gabomdq@7778
   140
    "/dev/vc/0",
gabomdq@7778
   141
    "/dev/console"
gabomdq@7778
   142
};
gabomdq@7778
   143
slouken@10433
   144
static int SDL_EVDEV_is_console( int fd ) {
slouken@10433
   145
    int type;
gabomdq@7778
   146
    
slouken@10433
   147
    return isatty( fd ) && ioctl( fd, KDGKBTYPE, &type ) == 0 &&
slouken@10433
   148
        ( type == KB_101 || type == KB_84 );
gabomdq@7778
   149
}
gabomdq@7778
   150
gabomdq@7809
   151
/* Prevent keystrokes from reaching the tty */
slouken@10433
   152
static int SDL_EVDEV_mute_keyboard( int tty_fd, int* old_kb_mode )
gabomdq@7809
   153
{
slouken@10433
   154
    if( !SDL_EVDEV_is_console( tty_fd ) ) {
slouken@10433
   155
        return SDL_SetError( "Tried to mute an invalid tty" );
slouken@10433
   156
    }
gabomdq@7809
   157
    
slouken@10433
   158
    if( ioctl( tty_fd, KDGKBMODE, old_kb_mode ) < 0 ) {
slouken@10433
   159
        return SDL_SetError( "Failed to get keyboard mode during muting" );
gabomdq@7809
   160
    }
slouken@10433
   161
    
slouken@10433
   162
    /* FIXME: atm this absolutely ruins the vt, and KDSKBMUTE isn't implemented
slouken@10433
   163
       in the kernel */
slouken@10433
   164
    /*
slouken@10433
   165
    if( ioctl( tty_fd, KDSKBMODE, K_OFF ) < 0 ) {
slouken@10433
   166
        return SDL_SetError( "Failed to set keyboard mode during muting" );
gabomdq@7809
   167
    }
slouken@10433
   168
    */
gabomdq@7809
   169
    
gabomdq@7809
   170
    return 0;  
gabomdq@7809
   171
}
gabomdq@7809
   172
gabomdq@7809
   173
/* Restore the keyboard mode for given tty */
slouken@10433
   174
static void SDL_EVDEV_unmute_keyboard( int tty_fd, int kb_mode )
gabomdq@7809
   175
{
slouken@10433
   176
    /* read above */
slouken@10433
   177
    /*
slouken@10433
   178
    if( ioctl( tty_fd, KDSKBMODE, kb_mode ) < 0 ) {
slouken@10433
   179
        SDL_Log( "Failed to unmute keyboard" );
gabomdq@7809
   180
    }
slouken@10433
   181
    */
gabomdq@7809
   182
}
gabomdq@7809
   183
gabomdq@7809
   184
static int SDL_EVDEV_get_active_tty()
slouken@10433
   185
{  
slouken@10433
   186
    int i, fd, ret, tty = 0;
slouken@10433
   187
    char tiocl;
slouken@10433
   188
    struct vt_stat vt_state;
slouken@10433
   189
    char path[PATH_MAX + 1];
gabomdq@7809
   190
    
slouken@10433
   191
    for( i = 0; i < SDL_arraysize( EVDEV_consoles ); i++ ) {
slouken@10433
   192
        fd = open( EVDEV_consoles[i], O_RDONLY );
slouken@10433
   193
        
slouken@10433
   194
        if( fd < 0 && !SDL_EVDEV_is_console( fd ) )
slouken@10433
   195
            break;
slouken@10433
   196
        
slouken@10433
   197
        tiocl = TIOCL_GETFGCONSOLE;
slouken@10433
   198
        if( ( ret = ioctl( fd, TIOCLINUX, &tiocl ) ) >= 0 )
slouken@10433
   199
            tty = ret + 1;
slouken@10433
   200
        else if( ioctl( fd, VT_GETSTATE, &vt_state ) == 0 )
slouken@10433
   201
            tty = vt_state.v_active;
slouken@10433
   202
        
slouken@10433
   203
        close( fd );
slouken@10433
   204
        
slouken@10433
   205
        if( tty ) {
slouken@10433
   206
            sprintf( path, "/dev/tty%u", tty );
slouken@10433
   207
            fd = open( path, O_RDONLY );
slouken@10433
   208
            if( fd >= 0 && SDL_EVDEV_is_console( fd ) )
slouken@10433
   209
                return fd;
slouken@10433
   210
        }
gabomdq@7809
   211
    }
gabomdq@7809
   212
    
slouken@10433
   213
    return SDL_SetError( "Failed to determine active tty" );
gabomdq@7809
   214
}
gabomdq@7809
   215
gabomdq@7753
   216
int
gabomdq@7753
   217
SDL_EVDEV_Init(void)
gabomdq@7753
   218
{
slouken@10433
   219
    if( _this == NULL ) {
slouken@10433
   220
        _this = (SDL_EVDEV_PrivateData*)SDL_calloc( 1, sizeof( *_this ) );
slouken@10433
   221
        if( _this == NULL ) {
gabomdq@7753
   222
            return SDL_OutOfMemory();
gabomdq@7753
   223
        }
gabomdq@7753
   224
gabomdq@7753
   225
#if SDL_USE_LIBUDEV
slouken@10433
   226
        if( SDL_UDEV_Init() < 0 ) {
slouken@10433
   227
            SDL_free( _this );
gabomdq@7753
   228
            _this = NULL;
gabomdq@7753
   229
            return -1;
gabomdq@7753
   230
        }
gabomdq@7753
   231
gabomdq@7753
   232
        /* Set up the udev callback */
slouken@9780
   233
        if (SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) {
slouken@10433
   234
            SDL_UDEV_Quit();
slouken@10433
   235
            SDL_free( _this );
slouken@10433
   236
            _this = NULL;
gabomdq@7753
   237
            return -1;
gabomdq@7753
   238
        }
gabomdq@7753
   239
        
gabomdq@7753
   240
        /* Force a scan to build the initial device list */
gabomdq@7753
   241
        SDL_UDEV_Scan();
gabomdq@7753
   242
#else
gabomdq@7753
   243
        /* TODO: Scan the devices manually, like a caveman */
gabomdq@7753
   244
#endif /* SDL_USE_LIBUDEV */
gabomdq@7778
   245
        
slouken@10433
   246
        /* We need a physical terminal (not PTS) to be able to translate key
slouken@10433
   247
           code to symbols via the kernel tables */
slouken@10433
   248
        _this->console_fd = SDL_EVDEV_get_active_tty();
gabomdq@7809
   249
        
slouken@10433
   250
        /* Mute the keyboard so keystrokes only generate evdev events and do not
slouken@10433
   251
           leak through to the console */
slouken@10433
   252
        SDL_EVDEV_mute_keyboard( _this->console_fd, &_this->kb_mode );
gabomdq@7753
   253
    }
gabomdq@7753
   254
    
gabomdq@7753
   255
    _this->ref_count += 1;
gabomdq@7753
   256
    
slouken@10433
   257
    return 0;
gabomdq@7753
   258
}
gabomdq@7753
   259
gabomdq@7753
   260
void
gabomdq@7753
   261
SDL_EVDEV_Quit(void)
gabomdq@7753
   262
{
slouken@10433
   263
    if( _this == NULL ) {
gabomdq@7753
   264
        return;
gabomdq@7753
   265
    }
gabomdq@7753
   266
    
gabomdq@7753
   267
    _this->ref_count -= 1;
gabomdq@7753
   268
    
slouken@10433
   269
    if( _this->ref_count < 1 ) {
gabomdq@7753
   270
#if SDL_USE_LIBUDEV
slouken@10433
   271
        SDL_UDEV_DelCallback( SDL_EVDEV_udev_callback );
gabomdq@7753
   272
        SDL_UDEV_Quit();
gabomdq@7753
   273
#endif /* SDL_USE_LIBUDEV */
gabomdq@7753
   274
       
slouken@10433
   275
        if( _this->console_fd >= 0 ) {
slouken@10433
   276
            SDL_EVDEV_unmute_keyboard( _this->console_fd, _this->kb_mode );
slouken@10433
   277
            close( _this->console_fd );
gabomdq@7809
   278
        }
gabomdq@7809
   279
        
gabomdq@7753
   280
        /* Remove existing devices */
gabomdq@7753
   281
        while(_this->first != NULL) {
slouken@10433
   282
            SDL_EVDEV_device_removed( _this->first->path );
gabomdq@7753
   283
        }
gabomdq@7753
   284
        
slouken@10433
   285
        SDL_assert( _this->first == NULL );
slouken@10433
   286
        SDL_assert( _this->last == NULL );
slouken@10433
   287
        SDL_assert( _this->num_devices == 0 );
gabomdq@7753
   288
        
slouken@10433
   289
        SDL_free( _this );
gabomdq@7753
   290
        _this = NULL;
gabomdq@7753
   291
    }
gabomdq@7753
   292
}
gabomdq@7753
   293
gabomdq@7755
   294
#if SDL_USE_LIBUDEV
slouken@10433
   295
void SDL_EVDEV_udev_callback( SDL_UDEV_deviceevent udev_event, int udev_class,
slouken@10433
   296
    const char* dev_path )
gabomdq@7753
   297
{
slouken@10433
   298
    if( dev_path == NULL ) {
gabomdq@7753
   299
        return;
gabomdq@7753
   300
    }
gabomdq@7753
   301
    
slouken@10433
   302
    switch( udev_event ) {
slouken@7788
   303
    case SDL_UDEV_DEVICEADDED:
slouken@10433
   304
        if( !( udev_class & ( SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD |
slouken@10433
   305
            SDL_UDEV_DEVICE_TOUCHSCREEN ) ) )
slouken@9779
   306
            return;
slouken@10433
   307
slouken@10433
   308
        SDL_EVDEV_device_added( dev_path, udev_class );
slouken@10433
   309
        break;  
slouken@10433
   310
    case SDL_UDEV_DEVICEREMOVED:
slouken@10433
   311
        SDL_EVDEV_device_removed( dev_path );
slouken@7788
   312
        break;
slouken@7788
   313
    default:
slouken@7788
   314
        break;
gabomdq@7753
   315
    }
gabomdq@7753
   316
}
slouken@10433
   317
#endif /* SDL_USE_LIBUDEV */
gabomdq@7753
   318
slouken@10433
   319
#ifdef SDL_INPUT_LINUXKD
slouken@10433
   320
/* this logic is pulled from kbd_keycode() in drivers/tty/vt/keyboard.c in the
slouken@10433
   321
   Linux kernel source */
slouken@10433
   322
static void SDL_EVDEV_do_text_input( unsigned short keycode ) {
slouken@10433
   323
    char shift_state;
slouken@10433
   324
    int locks_state;
slouken@10433
   325
    struct kbentry kbe;
slouken@10433
   326
    unsigned char type;
slouken@10433
   327
    char text[2] = { 0 };
slouken@10433
   328
    
slouken@10433
   329
    if( _this->console_fd < 0 )
slouken@10433
   330
        return;
slouken@10433
   331
    
slouken@10433
   332
    shift_state = TIOCL_GETSHIFTSTATE;
slouken@10433
   333
    if( ioctl( _this->console_fd, TIOCLINUX, &shift_state ) < 0 ) {
slouken@10433
   334
        /* TODO: error */
slouken@10433
   335
        return;
slouken@10433
   336
    }
slouken@10433
   337
slouken@10433
   338
    kbe.kb_table = shift_state;
slouken@10433
   339
    kbe.kb_index = keycode;
slouken@10433
   340
    
slouken@10433
   341
    if( ioctl( _this->console_fd, KDGKBENT, &kbe ) < 0 ) {
slouken@10433
   342
        /* TODO: error */
slouken@10433
   343
        return;
slouken@10433
   344
    }
slouken@10433
   345
    
slouken@10433
   346
    type = KTYP( kbe.kb_value );
slouken@10433
   347
    
slouken@10433
   348
    if( type < 0xf0 ) {
slouken@10433
   349
        /* 
slouken@10433
   350
         * FIXME: keysyms with a type below 0xf0 represent a unicode character
slouken@10433
   351
         * which requires special handling due to dead characters, diacritics,
slouken@10433
   352
         * etc. For perfect input a proper way to deal with such characters
slouken@10433
   353
         * should be implemented.
slouken@10433
   354
         *
slouken@10433
   355
         * For reference, the only place I was able to find out about this
slouken@10433
   356
         * special 0xf0 value was in an unused? couple of patches listed below.
slouken@10433
   357
         *
slouken@10433
   358
         * http://ftp.tc.edu.tw/pub/docs/Unicode/utf8/linux-2.3.12-keyboard.diff
slouken@10433
   359
         * http://ftp.tc.edu.tw/pub/docs/Unicode/utf8/linux-2.3.12-console.diff
slouken@10433
   360
         */
slouken@10433
   361
        
slouken@10433
   362
        return;
slouken@10433
   363
    }
slouken@10433
   364
    
slouken@10433
   365
    type -= 0xf0;
slouken@10433
   366
    
slouken@10433
   367
    /* if type is KT_LETTER then it can be affected by Caps Lock */
slouken@10433
   368
    if( type == KT_LETTER ) {
slouken@10433
   369
        type = KT_LATIN;
slouken@10433
   370
    
slouken@10433
   371
        if( ioctl( _this->console_fd, KDGKBLED, &locks_state ) < 0 ) {
slouken@10433
   372
            /* TODO: error */
slouken@10433
   373
            return;
slouken@10433
   374
        }
slouken@10433
   375
        
slouken@10433
   376
        if( locks_state & K_CAPSLOCK ) {
slouken@10433
   377
            kbe.kb_table = shift_state ^ ( 1 << KG_SHIFT );
slouken@10433
   378
            
slouken@10433
   379
            if( ioctl( _this->console_fd, KDGKBENT, &kbe ) < 0 ) {
slouken@10433
   380
                /* TODO: error */
slouken@10433
   381
                return;
slouken@10433
   382
            }
slouken@10433
   383
        }
slouken@10433
   384
    }
slouken@10433
   385
    
slouken@10433
   386
    /* TODO: convert values >= 0x80 from ISO-8859-1? to UTF-8 */
slouken@10433
   387
    if( type != KT_LATIN || KVAL( kbe.kb_value ) >= 0x80 )
slouken@10433
   388
        return;
slouken@10433
   389
    
slouken@10433
   390
    *text = KVAL( kbe.kb_value );
slouken@10433
   391
    SDL_SendKeyboardText( text );
slouken@10433
   392
}
slouken@10433
   393
#endif /* SDL_INPUT_LINUXKD */
gabomdq@7755
   394
gabomdq@7753
   395
void 
gabomdq@7753
   396
SDL_EVDEV_Poll(void)
gabomdq@7753
   397
{
gabomdq@7753
   398
    struct input_event events[32];
slouken@10433
   399
    int i, j, len;
gabomdq@7753
   400
    SDL_evdevlist_item *item;
gabomdq@7753
   401
    SDL_Scancode scan_code;
gabomdq@7753
   402
    int mouse_button;
gabomdq@7753
   403
    SDL_Mouse *mouse;
slouken@10433
   404
    float norm_x, norm_y;
gabomdq@7778
   405
slouken@9159
   406
    if (!_this) {
slouken@9159
   407
        return;
slouken@9159
   408
    }
slouken@9159
   409
gabomdq@7753
   410
#if SDL_USE_LIBUDEV
gabomdq@7753
   411
    SDL_UDEV_Poll();
gabomdq@7753
   412
#endif
gabomdq@7778
   413
slouken@7788
   414
    mouse = SDL_GetMouse();
slouken@7788
   415
gabomdq@7753
   416
    for (item = _this->first; item != NULL; item = item->next) {
gabomdq@7753
   417
        while ((len = read(item->fd, events, (sizeof events))) > 0) {
gabomdq@7753
   418
            len /= sizeof(events[0]);
gabomdq@7753
   419
            for (i = 0; i < len; ++i) {
slouken@10433
   420
                /* special handling for touchscreen, that should eventually be
slouken@10433
   421
                   used for all devices */
slouken@10433
   422
                if( item->out_of_sync && item->is_touchscreen &&
slouken@10433
   423
                    events[i].type == EV_SYN && events[i].code != SYN_REPORT ) {
slouken@10433
   424
                    break;
slouken@10433
   425
                }
slouken@10433
   426
                
slouken@7788
   427
                switch (events[i].type) {
slouken@7788
   428
                case EV_KEY:
slouken@7788
   429
                    if (events[i].code >= BTN_MOUSE && events[i].code < BTN_MOUSE + SDL_arraysize(EVDEV_MouseButtons)) {
slouken@7788
   430
                        mouse_button = events[i].code - BTN_MOUSE;
slouken@7788
   431
                        if (events[i].value == 0) {
slouken@7788
   432
                            SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, EVDEV_MouseButtons[mouse_button]);
slouken@7788
   433
                        } else if (events[i].value == 1) {
slouken@7788
   434
                            SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, EVDEV_MouseButtons[mouse_button]);
slouken@7788
   435
                        }
slouken@7788
   436
                        break;
slouken@7788
   437
                    }
slouken@7788
   438
slouken@7788
   439
                    /* Probably keyboard */
slouken@7788
   440
                    scan_code = SDL_EVDEV_translate_keycode(events[i].code);
slouken@7788
   441
                    if (scan_code != SDL_SCANCODE_UNKNOWN) {
slouken@7788
   442
                        if (events[i].value == 0) {
slouken@7788
   443
                            SDL_SendKeyboardKey(SDL_RELEASED, scan_code);
slouken@10433
   444
                        } else if( events[i].value == 1 || events[i].value == 2 /* key repeated */ ) {
slouken@7788
   445
                            SDL_SendKeyboardKey(SDL_PRESSED, scan_code);
gabomdq@7778
   446
#ifdef SDL_INPUT_LINUXKD
slouken@10433
   447
                            SDL_EVDEV_do_text_input( events[i].code );
slouken@7788
   448
#endif /* SDL_INPUT_LINUXKD */
gabomdq@7753
   449
                        }
slouken@7788
   450
                    }
slouken@7788
   451
                    break;
slouken@7788
   452
                case EV_ABS:
slouken@7788
   453
                    switch(events[i].code) {
slouken@10433
   454
                    case ABS_MT_SLOT:
slouken@10433
   455
                        if( !item->is_touchscreen ) /* FIXME: temp hack */
slouken@10433
   456
                            break;
slouken@10433
   457
                        item->touchscreen_data->current_slot = events[i].value;
slouken@10433
   458
                        break;
slouken@10433
   459
                    case ABS_MT_TRACKING_ID:
slouken@10433
   460
                        if( !item->is_touchscreen ) /* FIXME: temp hack */
slouken@10433
   461
                            break;
slouken@10433
   462
                        if( events[i].value >= 0 ) {
slouken@10433
   463
                            item->touchscreen_data->slots[item->touchscreen_data->current_slot].tracking_id = events[i].value;
slouken@10433
   464
                            item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
slouken@10433
   465
                        } else {
slouken@10433
   466
                            item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_UP;
slouken@10433
   467
                        }
slouken@10433
   468
                        break;
slouken@10433
   469
                    case ABS_MT_POSITION_X:
slouken@10433
   470
                        if( !item->is_touchscreen ) /* FIXME: temp hack */
slouken@10433
   471
                            break;
slouken@10433
   472
                        item->touchscreen_data->slots[item->touchscreen_data->current_slot].x = events[i].value;
slouken@10433
   473
                        if( item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE ) {
slouken@10433
   474
                            item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
slouken@10433
   475
                        }
slouken@10433
   476
                        break;
slouken@10433
   477
                    case ABS_MT_POSITION_Y:
slouken@10433
   478
                        if( !item->is_touchscreen ) /* FIXME: temp hack */
slouken@10433
   479
                            break;
slouken@10433
   480
                        item->touchscreen_data->slots[item->touchscreen_data->current_slot].y = events[i].value;
slouken@10433
   481
                        if( item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE ) {
slouken@10433
   482
                            item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
slouken@10433
   483
                        }
slouken@10433
   484
                        break;
slouken@7788
   485
                    case ABS_X:
slouken@10433
   486
                        if( item->is_touchscreen ) /* FIXME: temp hack */
slouken@10433
   487
                            break;
slouken@7788
   488
                        SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y);
slouken@7788
   489
                        break;
slouken@7788
   490
                    case ABS_Y:
slouken@10433
   491
                        if( item->is_touchscreen ) /* FIXME: temp hack */
slouken@10433
   492
                            break;
slouken@7788
   493
                        SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value);
slouken@7788
   494
                        break;
gabomdq@7753
   495
                    default:
gabomdq@7753
   496
                        break;
slouken@7788
   497
                    }
slouken@7788
   498
                    break;
slouken@7788
   499
                case EV_REL:
slouken@7788
   500
                    switch(events[i].code) {
slouken@7788
   501
                    case REL_X:
slouken@7788
   502
                        SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, events[i].value, 0);
slouken@7788
   503
                        break;
slouken@7788
   504
                    case REL_Y:
slouken@7788
   505
                        SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, 0, events[i].value);
slouken@7788
   506
                        break;
slouken@7788
   507
                    case REL_WHEEL:
urkle@9257
   508
                        SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value, SDL_MOUSEWHEEL_NORMAL);
slouken@7788
   509
                        break;
slouken@7788
   510
                    case REL_HWHEEL:
urkle@9257
   511
                        SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0, SDL_MOUSEWHEEL_NORMAL);
slouken@7788
   512
                        break;
slouken@7788
   513
                    default:
slouken@7788
   514
                        break;
slouken@7788
   515
                    }
slouken@7788
   516
                    break;
slouken@7788
   517
                case EV_SYN:
slouken@7788
   518
                    switch (events[i].code) {
slouken@10433
   519
                    case SYN_REPORT:
slouken@10433
   520
                        if( !item->is_touchscreen ) /* FIXME: temp hack */
slouken@10433
   521
                            break;
slouken@10433
   522
                            
slouken@10433
   523
                        for( j = 0; j < item->touchscreen_data->max_slots; j++ ) {
slouken@10433
   524
                            norm_x = (float)(item->touchscreen_data->slots[j].x - item->touchscreen_data->min_x) /
slouken@10433
   525
                                (float)item->touchscreen_data->range_x;
slouken@10433
   526
                            norm_y = (float)(item->touchscreen_data->slots[j].y - item->touchscreen_data->min_y) /
slouken@10433
   527
                                (float)item->touchscreen_data->range_y;
slouken@10433
   528
                        
slouken@10433
   529
                            switch( item->touchscreen_data->slots[j].delta ) {
slouken@10433
   530
                            case EVDEV_TOUCH_SLOTDELTA_DOWN:
slouken@10433
   531
                                SDL_SendTouch( item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_TRUE, norm_x, norm_y, 1.0f );
slouken@10433
   532
                                item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
slouken@10433
   533
                                break;
slouken@10433
   534
                            case EVDEV_TOUCH_SLOTDELTA_UP:
slouken@10433
   535
                                SDL_SendTouch( item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_FALSE, norm_x, norm_y, 1.0f );
slouken@10433
   536
                                item->touchscreen_data->slots[j].tracking_id = -1;
slouken@10433
   537
                                item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
slouken@10433
   538
                                break;
slouken@10433
   539
                            case EVDEV_TOUCH_SLOTDELTA_MOVE:
slouken@10433
   540
                                SDL_SendTouchMotion( item->fd, item->touchscreen_data->slots[j].tracking_id, norm_x, norm_y, 1.0f );
slouken@10433
   541
                                item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
slouken@10433
   542
                                break;
slouken@10433
   543
                            default:
slouken@10433
   544
                                break;
slouken@10433
   545
                            }
slouken@10433
   546
                        }
slouken@10433
   547
                        
slouken@10433
   548
                        if( item->out_of_sync )
slouken@10433
   549
                            item->out_of_sync = 0;
slouken@10433
   550
                        break;
slouken@7788
   551
                    case SYN_DROPPED:
slouken@10433
   552
                        if( item->is_touchscreen )
slouken@10433
   553
                            item->out_of_sync = 1;
slouken@7788
   554
                        SDL_EVDEV_sync_device(item);
slouken@7788
   555
                        break;
slouken@7788
   556
                    default:
slouken@7788
   557
                        break;
slouken@7788
   558
                    }
slouken@7788
   559
                    break;
gabomdq@7753
   560
                }
gabomdq@7753
   561
            }
gabomdq@7753
   562
        }    
gabomdq@7753
   563
    }
gabomdq@7753
   564
}
gabomdq@7753
   565
gabomdq@7753
   566
static SDL_Scancode
slouken@10433
   567
SDL_EVDEV_translate_keycode( int keycode )
gabomdq@7753
   568
{
gabomdq@7753
   569
    SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
gabomdq@7753
   570
slouken@10433
   571
    if( keycode < SDL_arraysize( linux_scancode_table ) )
slouken@10433
   572
        scancode = linux_scancode_table[keycode];
slouken@10433
   573
slouken@10433
   574
    if( scancode == SDL_SCANCODE_UNKNOWN ) {
slouken@10433
   575
        SDL_Log( "The key you just pressed is not recognized by SDL. To help "
slouken@10433
   576
            "get this fixed, please report this to the SDL mailing list "
slouken@10433
   577
            "<sdl@libsdl.org> EVDEV KeyCode %d\n", keycode );
gabomdq@7753
   578
    }
slouken@10433
   579
slouken@10433
   580
    return scancode;
slouken@10433
   581
}
slouken@10433
   582
slouken@10433
   583
static int
slouken@10433
   584
SDL_EVDEV_init_touchscreen( SDL_evdevlist_item* item ) {
slouken@10433
   585
    int ret, i;
slouken@10433
   586
    char name[64];
slouken@10433
   587
    struct input_absinfo abs_info;
slouken@10433
   588
    
slouken@10433
   589
    if( !item->is_touchscreen )
slouken@10433
   590
        return 0;
slouken@10433
   591
    
slouken@10433
   592
    item->touchscreen_data = SDL_calloc( 1, sizeof( *item->touchscreen_data ) );
slouken@10433
   593
    if( item->touchscreen_data == NULL )
slouken@10433
   594
        return SDL_OutOfMemory();
slouken@10433
   595
    
slouken@10433
   596
    ret = ioctl( item->fd, EVIOCGNAME( sizeof( name ) ), name );
slouken@10433
   597
    if( ret < 0 ) {
slouken@10433
   598
        SDL_free( item->touchscreen_data );
slouken@10433
   599
        return SDL_SetError( "Failed to get evdev touchscreen name" );
gabomdq@7753
   600
    }
slouken@10433
   601
    
slouken@10433
   602
    item->touchscreen_data->name = SDL_strdup( name );
slouken@10433
   603
    if( item->touchscreen_data->name == NULL ) {
slouken@10433
   604
        SDL_free( item->touchscreen_data );
slouken@10433
   605
        return SDL_OutOfMemory();
slouken@10433
   606
    }
slouken@10433
   607
    
slouken@10433
   608
    ret = ioctl( item->fd, EVIOCGABS( ABS_MT_POSITION_X ), &abs_info );
slouken@10433
   609
    if( ret < 0 ) {
slouken@10433
   610
        SDL_free( item->touchscreen_data->name );
slouken@10433
   611
        SDL_free( item->touchscreen_data );
slouken@10433
   612
        return SDL_SetError( "Failed to get evdev touchscreen limits" );
slouken@10433
   613
    }
slouken@10433
   614
    item->touchscreen_data->min_x = abs_info.minimum;
slouken@10433
   615
    item->touchscreen_data->max_x = abs_info.maximum;
slouken@10433
   616
    item->touchscreen_data->range_x = abs_info.maximum - abs_info.minimum;
slouken@10433
   617
        
slouken@10433
   618
    ret = ioctl( item->fd, EVIOCGABS( ABS_MT_POSITION_Y ), &abs_info );
slouken@10433
   619
    if( ret < 0 ) {
slouken@10433
   620
        SDL_free( item->touchscreen_data->name );
slouken@10433
   621
        SDL_free( item->touchscreen_data );
slouken@10433
   622
        return SDL_SetError( "Failed to get evdev touchscreen limits" );
slouken@10433
   623
    }
slouken@10433
   624
    item->touchscreen_data->min_y = abs_info.minimum;
slouken@10433
   625
    item->touchscreen_data->max_y = abs_info.maximum;
slouken@10433
   626
    item->touchscreen_data->range_y = abs_info.maximum - abs_info.minimum;
slouken@10433
   627
    
slouken@10433
   628
    ret = ioctl( item->fd, EVIOCGABS( ABS_MT_SLOT ), &abs_info );
slouken@10433
   629
    if( ret < 0 ) {
slouken@10433
   630
        SDL_free( item->touchscreen_data->name );
slouken@10433
   631
        SDL_free( item->touchscreen_data );
slouken@10433
   632
        return SDL_SetError( "Failed to get evdev touchscreen limits" );
slouken@10433
   633
    }
slouken@10433
   634
    item->touchscreen_data->max_slots = abs_info.maximum + 1;
slouken@10433
   635
    
slouken@10433
   636
    item->touchscreen_data->slots = SDL_calloc(
slouken@10433
   637
        item->touchscreen_data->max_slots,
slouken@10433
   638
        sizeof( *item->touchscreen_data->slots ) );
slouken@10433
   639
    if( item->touchscreen_data->slots == NULL ) {
slouken@10433
   640
        SDL_free( item->touchscreen_data->name );
slouken@10433
   641
        SDL_free( item->touchscreen_data );
slouken@10433
   642
        return SDL_OutOfMemory();
slouken@10433
   643
    }
slouken@10433
   644
    
slouken@10433
   645
    for( i = 0; i < item->touchscreen_data->max_slots; i++ ) {
slouken@10433
   646
        item->touchscreen_data->slots[i].tracking_id = -1;
slouken@10433
   647
    }
slouken@10433
   648
    
slouken@10433
   649
    ret = SDL_AddTouch( item->fd, /* I guess our fd is unique enough */
slouken@10433
   650
        item->touchscreen_data->name );
slouken@10433
   651
    if( ret < 0 ) {
slouken@10433
   652
        SDL_free( item->touchscreen_data->slots );
slouken@10433
   653
        SDL_free( item->touchscreen_data->name );
slouken@10433
   654
        SDL_free( item->touchscreen_data );
slouken@10433
   655
        return ret;
slouken@10433
   656
    }
slouken@10433
   657
    
slouken@10433
   658
    return 0;
slouken@10433
   659
}
slouken@10433
   660
slouken@10433
   661
static void
slouken@10433
   662
SDL_EVDEV_destroy_touchscreen( SDL_evdevlist_item* item ) {
slouken@10433
   663
    if( !item->is_touchscreen )
slouken@10433
   664
        return;
slouken@10433
   665
    
slouken@10433
   666
    SDL_DelTouch( item->fd );
slouken@10433
   667
    SDL_free( item->touchscreen_data->slots );
slouken@10433
   668
    SDL_free( item->touchscreen_data->name );
slouken@10433
   669
    SDL_free( item->touchscreen_data );
gabomdq@7753
   670
}
gabomdq@7753
   671
gabomdq@7753
   672
static void
gabomdq@7753
   673
SDL_EVDEV_sync_device(SDL_evdevlist_item *item) 
gabomdq@7753
   674
{
slouken@10433
   675
    int i, ret;
slouken@10433
   676
    struct input_absinfo abs_info;
slouken@10433
   677
    /*
slouken@10433
   678
     * struct input_mt_request_layout {
slouken@10433
   679
     *     __u32 code;
slouken@10433
   680
     *     __s32 values[num_slots];
slouken@10433
   681
     * };
slouken@10433
   682
     *
slouken@10433
   683
     * this is the structure we're trying to emulate
slouken@10433
   684
     */
slouken@10433
   685
    __u32* mt_req_code;
slouken@10433
   686
    __s32* mt_req_values;
slouken@10433
   687
    size_t mt_req_size;
slouken@10433
   688
    
slouken@10433
   689
    /* TODO: sync devices other than touchscreen */
slouken@10433
   690
    if( !item->is_touchscreen )
slouken@10433
   691
        return;
slouken@10433
   692
    
slouken@10433
   693
    mt_req_size = sizeof( *mt_req_code ) +
slouken@10433
   694
        sizeof( *mt_req_values ) * item->touchscreen_data->max_slots;
slouken@10433
   695
    
slouken@10433
   696
    mt_req_code = SDL_calloc( 1, mt_req_size );
slouken@10433
   697
    if( mt_req_code == NULL ) {
slouken@10433
   698
        SDL_Log( "Failed to sync device" );
slouken@10433
   699
        return;
slouken@10433
   700
    }
slouken@10433
   701
    
slouken@10433
   702
    mt_req_values = (__s32*)mt_req_code + 1;
slouken@10433
   703
    
slouken@10433
   704
    *mt_req_code = ABS_MT_TRACKING_ID;
slouken@10433
   705
    ret = ioctl( item->fd, EVIOCGMTSLOTS( mt_req_size ), mt_req_code );
slouken@10433
   706
    if( ret < 0 ) {
slouken@10433
   707
        SDL_free( mt_req_code );
slouken@10433
   708
        SDL_Log( "Failed to sync device" );
slouken@10433
   709
        return;
slouken@10433
   710
    }
slouken@10433
   711
    for( i = 0; i < item->touchscreen_data->max_slots; i++ ) {
slouken@10433
   712
        /*
slouken@10433
   713
         * This doesn't account for the very edge case of the user removing their
slouken@10433
   714
         * finger and replacing it on the screen during the time we're out of sync,
slouken@10433
   715
         * which'll mean that we're not going from down -> up or up -> down, we're
slouken@10433
   716
         * going from down -> down but with a different tracking id, meaning we'd
slouken@10433
   717
         * have to tell SDL of the two events, but since we wait till SYN_REPORT in
slouken@10433
   718
         * SDL_EVDEV_Poll to tell SDL, the current structure of this code doesn't
slouken@10433
   719
         * allow it. Lets just pray to God it doesn't happen.
slouken@10433
   720
         */
slouken@10433
   721
        if( item->touchscreen_data->slots[i].tracking_id < 0 &&
slouken@10433
   722
            mt_req_values[i] >= 0 ) {
slouken@10433
   723
            item->touchscreen_data->slots[i].tracking_id = mt_req_values[i];
slouken@10433
   724
            item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
slouken@10433
   725
        } else if( item->touchscreen_data->slots[i].tracking_id >= 0 &&
slouken@10433
   726
            mt_req_values[i] < 0 ) {
slouken@10433
   727
            item->touchscreen_data->slots[i].tracking_id = -1;
slouken@10433
   728
            item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_UP;
slouken@10433
   729
        }
slouken@10433
   730
    }
slouken@10433
   731
    
slouken@10433
   732
    *mt_req_code = ABS_MT_POSITION_X;
slouken@10433
   733
    ret = ioctl( item->fd, EVIOCGMTSLOTS( mt_req_size ), mt_req_code );
slouken@10433
   734
    if( ret < 0 ) {
slouken@10433
   735
        SDL_free( mt_req_code );
slouken@10433
   736
        SDL_Log( "Failed to sync device" );
slouken@10433
   737
        return;
slouken@10433
   738
    }
slouken@10433
   739
    for( i = 0; i < item->touchscreen_data->max_slots; i++ ) {
slouken@10433
   740
        if( item->touchscreen_data->slots[i].tracking_id >= 0 &&
slouken@10433
   741
            item->touchscreen_data->slots[i].x != mt_req_values[i] ) {
slouken@10433
   742
            item->touchscreen_data->slots[i].x = mt_req_values[i];
slouken@10433
   743
            if( item->touchscreen_data->slots[i].delta ==
slouken@10433
   744
                EVDEV_TOUCH_SLOTDELTA_NONE ) {
slouken@10433
   745
                item->touchscreen_data->slots[i].delta =
slouken@10433
   746
                    EVDEV_TOUCH_SLOTDELTA_MOVE;
slouken@10433
   747
            }
slouken@10433
   748
        }
slouken@10433
   749
    }
slouken@10433
   750
    
slouken@10433
   751
    *mt_req_code = ABS_MT_POSITION_Y;
slouken@10433
   752
    ret = ioctl( item->fd, EVIOCGMTSLOTS( mt_req_size ), mt_req_code );
slouken@10433
   753
    if( ret < 0 ) {
slouken@10433
   754
        SDL_free( mt_req_code );
slouken@10433
   755
        SDL_Log( "Failed to sync device" );
slouken@10433
   756
        return;
slouken@10433
   757
    }
slouken@10433
   758
    for( i = 0; i < item->touchscreen_data->max_slots; i++ ) {
slouken@10433
   759
        if( item->touchscreen_data->slots[i].tracking_id >= 0 &&
slouken@10433
   760
            item->touchscreen_data->slots[i].y != mt_req_values[i] ) {
slouken@10433
   761
            item->touchscreen_data->slots[i].y = mt_req_values[i];
slouken@10433
   762
            if( item->touchscreen_data->slots[i].delta ==
slouken@10433
   763
                EVDEV_TOUCH_SLOTDELTA_NONE ) {
slouken@10433
   764
                item->touchscreen_data->slots[i].delta =
slouken@10433
   765
                    EVDEV_TOUCH_SLOTDELTA_MOVE;
slouken@10433
   766
            }
slouken@10433
   767
        }
slouken@10433
   768
    }
slouken@10433
   769
    
slouken@10433
   770
    ret = ioctl( item->fd, EVIOCGABS( ABS_MT_SLOT ), &abs_info );
slouken@10433
   771
    if( ret < 0 ) {
slouken@10433
   772
        SDL_free( mt_req_code );
slouken@10433
   773
        SDL_Log( "Failed to sync device" );
slouken@10433
   774
        return;
slouken@10433
   775
    }
slouken@10433
   776
    item->touchscreen_data->current_slot = abs_info.value;
slouken@10433
   777
    
slouken@10433
   778
    SDL_free( mt_req_code );
gabomdq@7753
   779
}
gabomdq@7753
   780
gabomdq@7755
   781
#if SDL_USE_LIBUDEV
gabomdq@7753
   782
static int
slouken@10433
   783
SDL_EVDEV_device_added(const char *dev_path, int udev_class)
gabomdq@7753
   784
{
slouken@10433
   785
    int ret;
gabomdq@7753
   786
    SDL_evdevlist_item *item;
gabomdq@7753
   787
gabomdq@7753
   788
    /* Check to make sure it's not already in list. */
gabomdq@7753
   789
    for (item = _this->first; item != NULL; item = item->next) {
slouken@10433
   790
        if (SDL_strcmp(dev_path, item->path) == 0) {
gabomdq@7753
   791
            return -1;  /* already have this one */
gabomdq@7753
   792
        }
gabomdq@7753
   793
    }
gabomdq@7753
   794
    
gabomdq@7753
   795
    item = (SDL_evdevlist_item *) SDL_calloc(1, sizeof (SDL_evdevlist_item));
gabomdq@7753
   796
    if (item == NULL) {
gabomdq@7753
   797
        return SDL_OutOfMemory();
gabomdq@7753
   798
    }
gabomdq@7753
   799
slouken@10433
   800
    item->fd = open( dev_path, O_RDONLY | O_NONBLOCK );
gabomdq@7753
   801
    if (item->fd < 0) {
gabomdq@7753
   802
        SDL_free(item);
slouken@10433
   803
        return SDL_SetError("Unable to open %s", dev_path);
gabomdq@7753
   804
    }
gabomdq@7753
   805
    
slouken@10433
   806
    item->path = SDL_strdup(dev_path);
gabomdq@7753
   807
    if (item->path == NULL) {
gabomdq@7753
   808
        close(item->fd);
gabomdq@7753
   809
        SDL_free(item);
gabomdq@7753
   810
        return SDL_OutOfMemory();
gabomdq@7753
   811
    }
gabomdq@7753
   812
    
slouken@10433
   813
    if( udev_class & SDL_UDEV_DEVICE_TOUCHSCREEN ) {
slouken@10433
   814
        item->is_touchscreen = 1;
slouken@10433
   815
        
slouken@10433
   816
        if( ( ret = SDL_EVDEV_init_touchscreen( item ) ) < 0 ) {
slouken@10433
   817
            close(item->fd);
slouken@10433
   818
            SDL_free(item);
slouken@10433
   819
            return ret;
slouken@10433
   820
        }
slouken@10433
   821
    }
gabomdq@7753
   822
    
gabomdq@7753
   823
    if (_this->last == NULL) {
gabomdq@7753
   824
        _this->first = _this->last = item;
gabomdq@7753
   825
    } else {
gabomdq@7753
   826
        _this->last->next = item;
gabomdq@7753
   827
        _this->last = item;
gabomdq@7753
   828
    }
gabomdq@7753
   829
    
gabomdq@7753
   830
    SDL_EVDEV_sync_device(item);
gabomdq@7753
   831
    
slouken@10433
   832
    return _this->num_devices++;
gabomdq@7753
   833
}
gabomdq@7767
   834
#endif /* SDL_USE_LIBUDEV */
gabomdq@7753
   835
gabomdq@7753
   836
static int
slouken@10433
   837
SDL_EVDEV_device_removed(const char *dev_path)
gabomdq@7753
   838
{
gabomdq@7753
   839
    SDL_evdevlist_item *item;
gabomdq@7753
   840
    SDL_evdevlist_item *prev = NULL;
gabomdq@7753
   841
gabomdq@7753
   842
    for (item = _this->first; item != NULL; item = item->next) {
gabomdq@7753
   843
        /* found it, remove it. */
slouken@10433
   844
        if (SDL_strcmp(dev_path, item->path) == 0) {
gabomdq@7753
   845
            if (prev != NULL) {
gabomdq@7753
   846
                prev->next = item->next;
gabomdq@7753
   847
            } else {
gabomdq@7753
   848
                SDL_assert(_this->first == item);
gabomdq@7753
   849
                _this->first = item->next;
gabomdq@7753
   850
            }
gabomdq@7753
   851
            if (item == _this->last) {
gabomdq@7753
   852
                _this->last = prev;
gabomdq@7753
   853
            }
slouken@10433
   854
            if( item->is_touchscreen ) {
slouken@10433
   855
                SDL_EVDEV_destroy_touchscreen( item );
slouken@10433
   856
            }
gabomdq@7753
   857
            close(item->fd);
gabomdq@7753
   858
            SDL_free(item->path);
gabomdq@7753
   859
            SDL_free(item);
slouken@10433
   860
            _this->num_devices--;
gabomdq@7753
   861
            return 0;
gabomdq@7753
   862
        }
gabomdq@7753
   863
        prev = item;
gabomdq@7753
   864
    }
gabomdq@7753
   865
gabomdq@7753
   866
    return -1;
gabomdq@7753
   867
}
gabomdq@7767
   868
gabomdq@7753
   869
gabomdq@7753
   870
#endif /* SDL_INPUT_LINUXEV */
gabomdq@7753
   871
gabomdq@7753
   872
/* vi: set ts=4 sw=4 expandtab: */