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