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