src/core/linux/SDL_evdev.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 01 Oct 2016 14:56:53 -0700
changeset 10445 d18516d69e7f
parent 10433 0f79dd727ed6
child 10446 d5cb09daa54b
permissions -rw-r--r--
Fixed warning and code style in SDL_evdev.c
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@10445
   113
static int SDL_EVDEV_device_added(const char *dev_path, int udev_class);
slouken@10445
   114
void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class,
slouken@10445
   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@10445
   144
static int SDL_EVDEV_is_console(int fd) {
slouken@10433
   145
    int type;
gabomdq@7778
   146
    
slouken@10445
   147
    return isatty(fd) && ioctl(fd, KDGKBTYPE, &type) == 0 &&
slouken@10445
   148
        (type == KB_101 || type == KB_84);
gabomdq@7778
   149
}
gabomdq@7778
   150
gabomdq@7809
   151
/* Prevent keystrokes from reaching the tty */
slouken@10445
   152
static int SDL_EVDEV_mute_keyboard(int tty_fd, int* old_kb_mode)
gabomdq@7809
   153
{
slouken@10445
   154
    if (!SDL_EVDEV_is_console(tty_fd)) {
slouken@10445
   155
        return SDL_SetError("Tried to mute an invalid tty");
slouken@10433
   156
    }
gabomdq@7809
   157
    
slouken@10445
   158
    if (ioctl(tty_fd, KDGKBMODE, old_kb_mode) < 0) {
slouken@10445
   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@10445
   165
    if (ioctl(tty_fd, KDSKBMODE, K_OFF) < 0) {
slouken@10445
   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@10445
   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@10445
   178
    if (ioctl(tty_fd, KDSKBMODE, kb_mode) < 0) {
slouken@10445
   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@10445
   191
    for(i = 0; i < SDL_arraysize(EVDEV_consoles); i++) {
slouken@10445
   192
        fd = open(EVDEV_consoles[i], O_RDONLY);
slouken@10433
   193
        
slouken@10445
   194
        if (fd < 0 && !SDL_EVDEV_is_console(fd))
slouken@10433
   195
            break;
slouken@10433
   196
        
slouken@10433
   197
        tiocl = TIOCL_GETFGCONSOLE;
slouken@10445
   198
        if ((ret = ioctl(fd, TIOCLINUX, &tiocl)) >= 0)
slouken@10433
   199
            tty = ret + 1;
slouken@10445
   200
        else if (ioctl(fd, VT_GETSTATE, &vt_state) == 0)
slouken@10433
   201
            tty = vt_state.v_active;
slouken@10433
   202
        
slouken@10445
   203
        close(fd);
slouken@10433
   204
        
slouken@10445
   205
        if (tty) {
slouken@10445
   206
            sprintf(path, "/dev/tty%u", tty);
slouken@10445
   207
            fd = open(path, O_RDONLY);
slouken@10445
   208
            if (fd >= 0 && SDL_EVDEV_is_console(fd))
slouken@10433
   209
                return fd;
slouken@10433
   210
        }
gabomdq@7809
   211
    }
gabomdq@7809
   212
    
slouken@10445
   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@10445
   219
    if (_this == NULL) {
slouken@10445
   220
        _this = (SDL_EVDEV_PrivateData*)SDL_calloc(1, sizeof(*_this));
slouken@10445
   221
        if (_this == NULL) {
gabomdq@7753
   222
            return SDL_OutOfMemory();
gabomdq@7753
   223
        }
gabomdq@7753
   224
gabomdq@7753
   225
#if SDL_USE_LIBUDEV
slouken@10445
   226
        if (SDL_UDEV_Init() < 0) {
slouken@10445
   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@10445
   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@10445
   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@10445
   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@10445
   269
    if (_this->ref_count < 1) {
gabomdq@7753
   270
#if SDL_USE_LIBUDEV
slouken@10445
   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@10445
   275
        if (_this->console_fd >= 0) {
slouken@10445
   276
            SDL_EVDEV_unmute_keyboard(_this->console_fd, _this->kb_mode);
slouken@10445
   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@10445
   282
            SDL_EVDEV_device_removed(_this->first->path);
gabomdq@7753
   283
        }
gabomdq@7753
   284
        
slouken@10445
   285
        SDL_assert(_this->first == NULL);
slouken@10445
   286
        SDL_assert(_this->last == NULL);
slouken@10445
   287
        SDL_assert(_this->num_devices == 0);
gabomdq@7753
   288
        
slouken@10445
   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@10445
   295
void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event, int udev_class,
slouken@10445
   296
    const char* dev_path)
gabomdq@7753
   297
{
slouken@10445
   298
    if (dev_path == NULL) {
gabomdq@7753
   299
        return;
gabomdq@7753
   300
    }
gabomdq@7753
   301
    
slouken@10445
   302
    switch(udev_event) {
slouken@7788
   303
    case SDL_UDEV_DEVICEADDED:
slouken@10445
   304
        if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD |
slouken@10445
   305
            SDL_UDEV_DEVICE_TOUCHSCREEN)))
slouken@9779
   306
            return;
slouken@10433
   307
slouken@10445
   308
        SDL_EVDEV_device_added(dev_path, udev_class);
slouken@10433
   309
        break;  
slouken@10433
   310
    case SDL_UDEV_DEVICEREMOVED:
slouken@10445
   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@10445
   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@10445
   329
    if (_this->console_fd < 0)
slouken@10433
   330
        return;
slouken@10433
   331
    
slouken@10433
   332
    shift_state = TIOCL_GETSHIFTSTATE;
slouken@10445
   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@10445
   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@10445
   346
    type = KTYP(kbe.kb_value);
slouken@10433
   347
    
slouken@10445
   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@10445
   368
    if (type == KT_LETTER) {
slouken@10433
   369
        type = KT_LATIN;
slouken@10433
   370
    
slouken@10445
   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@10445
   376
        if (locks_state & K_CAPSLOCK) {
slouken@10445
   377
            kbe.kb_table = shift_state ^ (1 << KG_SHIFT);
slouken@10433
   378
            
slouken@10445
   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@10445
   387
    if (type != KT_LATIN || KVAL(kbe.kb_value) >= 0x80)
slouken@10433
   388
        return;
slouken@10433
   389
    
slouken@10445
   390
    *text = KVAL(kbe.kb_value);
slouken@10445
   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@10445
   422
                if (item->out_of_sync && item->is_touchscreen &&
slouken@10445
   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@10445
   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@10445
   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@10445
   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@10445
   460
                        if (!item->is_touchscreen) /* FIXME: temp hack */
slouken@10433
   461
                            break;
slouken@10445
   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@10445
   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@10445
   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@10445
   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@10445
   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@10445
   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@10445
   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@10445
   520
                        if (!item->is_touchscreen) /* FIXME: temp hack */
slouken@10433
   521
                            break;
slouken@10433
   522
                            
slouken@10445
   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@10445
   529
                            switch(item->touchscreen_data->slots[j].delta) {
slouken@10433
   530
                            case EVDEV_TOUCH_SLOTDELTA_DOWN:
slouken@10445
   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@10445
   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@10445
   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@10445
   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@10445
   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@10445
   567
SDL_EVDEV_translate_keycode(int keycode)
gabomdq@7753
   568
{
gabomdq@7753
   569
    SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
gabomdq@7753
   570
slouken@10445
   571
    if (keycode < SDL_arraysize(linux_scancode_table))
slouken@10433
   572
        scancode = linux_scancode_table[keycode];
slouken@10433
   573
slouken@10445
   574
    if (scancode == SDL_SCANCODE_UNKNOWN) {
slouken@10445
   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@10445
   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@10445
   583
#ifdef SDL_USE_LIBUDEV
slouken@10433
   584
static int
slouken@10445
   585
SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
slouken@10445
   586
{
slouken@10433
   587
    int ret, i;
slouken@10433
   588
    char name[64];
slouken@10433
   589
    struct input_absinfo abs_info;
slouken@10433
   590
    
slouken@10445
   591
    if (!item->is_touchscreen)
slouken@10433
   592
        return 0;
slouken@10433
   593
    
slouken@10445
   594
    item->touchscreen_data = SDL_calloc(1, sizeof(*item->touchscreen_data));
slouken@10445
   595
    if (item->touchscreen_data == NULL)
slouken@10433
   596
        return SDL_OutOfMemory();
slouken@10433
   597
    
slouken@10445
   598
    ret = ioctl(item->fd, EVIOCGNAME(sizeof(name)), name);
slouken@10445
   599
    if (ret < 0) {
slouken@10445
   600
        SDL_free(item->touchscreen_data);
slouken@10445
   601
        return SDL_SetError("Failed to get evdev touchscreen name");
gabomdq@7753
   602
    }
slouken@10433
   603
    
slouken@10445
   604
    item->touchscreen_data->name = SDL_strdup(name);
slouken@10445
   605
    if (item->touchscreen_data->name == NULL) {
slouken@10445
   606
        SDL_free(item->touchscreen_data);
slouken@10433
   607
        return SDL_OutOfMemory();
slouken@10433
   608
    }
slouken@10433
   609
    
slouken@10445
   610
    ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_X), &abs_info);
slouken@10445
   611
    if (ret < 0) {
slouken@10445
   612
        SDL_free(item->touchscreen_data->name);
slouken@10445
   613
        SDL_free(item->touchscreen_data);
slouken@10445
   614
        return SDL_SetError("Failed to get evdev touchscreen limits");
slouken@10433
   615
    }
slouken@10433
   616
    item->touchscreen_data->min_x = abs_info.minimum;
slouken@10433
   617
    item->touchscreen_data->max_x = abs_info.maximum;
slouken@10433
   618
    item->touchscreen_data->range_x = abs_info.maximum - abs_info.minimum;
slouken@10433
   619
        
slouken@10445
   620
    ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_Y), &abs_info);
slouken@10445
   621
    if (ret < 0) {
slouken@10445
   622
        SDL_free(item->touchscreen_data->name);
slouken@10445
   623
        SDL_free(item->touchscreen_data);
slouken@10445
   624
        return SDL_SetError("Failed to get evdev touchscreen limits");
slouken@10433
   625
    }
slouken@10433
   626
    item->touchscreen_data->min_y = abs_info.minimum;
slouken@10433
   627
    item->touchscreen_data->max_y = abs_info.maximum;
slouken@10433
   628
    item->touchscreen_data->range_y = abs_info.maximum - abs_info.minimum;
slouken@10433
   629
    
slouken@10445
   630
    ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
slouken@10445
   631
    if (ret < 0) {
slouken@10445
   632
        SDL_free(item->touchscreen_data->name);
slouken@10445
   633
        SDL_free(item->touchscreen_data);
slouken@10445
   634
        return SDL_SetError("Failed to get evdev touchscreen limits");
slouken@10433
   635
    }
slouken@10433
   636
    item->touchscreen_data->max_slots = abs_info.maximum + 1;
slouken@10433
   637
    
slouken@10433
   638
    item->touchscreen_data->slots = SDL_calloc(
slouken@10433
   639
        item->touchscreen_data->max_slots,
slouken@10445
   640
        sizeof(*item->touchscreen_data->slots));
slouken@10445
   641
    if (item->touchscreen_data->slots == NULL) {
slouken@10445
   642
        SDL_free(item->touchscreen_data->name);
slouken@10445
   643
        SDL_free(item->touchscreen_data);
slouken@10433
   644
        return SDL_OutOfMemory();
slouken@10433
   645
    }
slouken@10433
   646
    
slouken@10445
   647
    for(i = 0; i < item->touchscreen_data->max_slots; i++) {
slouken@10433
   648
        item->touchscreen_data->slots[i].tracking_id = -1;
slouken@10433
   649
    }
slouken@10433
   650
    
slouken@10445
   651
    ret = SDL_AddTouch(item->fd, /* I guess our fd is unique enough */
slouken@10445
   652
        item->touchscreen_data->name);
slouken@10445
   653
    if (ret < 0) {
slouken@10445
   654
        SDL_free(item->touchscreen_data->slots);
slouken@10445
   655
        SDL_free(item->touchscreen_data->name);
slouken@10445
   656
        SDL_free(item->touchscreen_data);
slouken@10433
   657
        return ret;
slouken@10433
   658
    }
slouken@10433
   659
    
slouken@10433
   660
    return 0;
slouken@10433
   661
}
slouken@10445
   662
#endif /* SDL_USE_LIBUDEV */
slouken@10433
   663
slouken@10433
   664
static void
slouken@10445
   665
SDL_EVDEV_destroy_touchscreen(SDL_evdevlist_item* item) {
slouken@10445
   666
    if (!item->is_touchscreen)
slouken@10433
   667
        return;
slouken@10433
   668
    
slouken@10445
   669
    SDL_DelTouch(item->fd);
slouken@10445
   670
    SDL_free(item->touchscreen_data->slots);
slouken@10445
   671
    SDL_free(item->touchscreen_data->name);
slouken@10445
   672
    SDL_free(item->touchscreen_data);
gabomdq@7753
   673
}
gabomdq@7753
   674
gabomdq@7753
   675
static void
gabomdq@7753
   676
SDL_EVDEV_sync_device(SDL_evdevlist_item *item) 
gabomdq@7753
   677
{
slouken@10433
   678
    int i, ret;
slouken@10433
   679
    struct input_absinfo abs_info;
slouken@10433
   680
    /*
slouken@10433
   681
     * struct input_mt_request_layout {
slouken@10433
   682
     *     __u32 code;
slouken@10433
   683
     *     __s32 values[num_slots];
slouken@10433
   684
     * };
slouken@10433
   685
     *
slouken@10433
   686
     * this is the structure we're trying to emulate
slouken@10433
   687
     */
slouken@10433
   688
    __u32* mt_req_code;
slouken@10433
   689
    __s32* mt_req_values;
slouken@10433
   690
    size_t mt_req_size;
slouken@10433
   691
    
slouken@10433
   692
    /* TODO: sync devices other than touchscreen */
slouken@10445
   693
    if (!item->is_touchscreen)
slouken@10433
   694
        return;
slouken@10433
   695
    
slouken@10445
   696
    mt_req_size = sizeof(*mt_req_code) +
slouken@10445
   697
        sizeof(*mt_req_values) * item->touchscreen_data->max_slots;
slouken@10433
   698
    
slouken@10445
   699
    mt_req_code = SDL_calloc(1, mt_req_size);
slouken@10445
   700
    if (mt_req_code == NULL) {
slouken@10445
   701
        SDL_Log("Failed to sync device");
slouken@10433
   702
        return;
slouken@10433
   703
    }
slouken@10433
   704
    
slouken@10433
   705
    mt_req_values = (__s32*)mt_req_code + 1;
slouken@10433
   706
    
slouken@10433
   707
    *mt_req_code = ABS_MT_TRACKING_ID;
slouken@10445
   708
    ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
slouken@10445
   709
    if (ret < 0) {
slouken@10445
   710
        SDL_free(mt_req_code);
slouken@10445
   711
        SDL_Log("Failed to sync device");
slouken@10433
   712
        return;
slouken@10433
   713
    }
slouken@10445
   714
    for(i = 0; i < item->touchscreen_data->max_slots; i++) {
slouken@10433
   715
        /*
slouken@10433
   716
         * This doesn't account for the very edge case of the user removing their
slouken@10433
   717
         * finger and replacing it on the screen during the time we're out of sync,
slouken@10433
   718
         * which'll mean that we're not going from down -> up or up -> down, we're
slouken@10433
   719
         * going from down -> down but with a different tracking id, meaning we'd
slouken@10433
   720
         * have to tell SDL of the two events, but since we wait till SYN_REPORT in
slouken@10433
   721
         * SDL_EVDEV_Poll to tell SDL, the current structure of this code doesn't
slouken@10433
   722
         * allow it. Lets just pray to God it doesn't happen.
slouken@10433
   723
         */
slouken@10445
   724
        if (item->touchscreen_data->slots[i].tracking_id < 0 &&
slouken@10445
   725
            mt_req_values[i] >= 0) {
slouken@10433
   726
            item->touchscreen_data->slots[i].tracking_id = mt_req_values[i];
slouken@10433
   727
            item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
slouken@10445
   728
        } else if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
slouken@10445
   729
            mt_req_values[i] < 0) {
slouken@10433
   730
            item->touchscreen_data->slots[i].tracking_id = -1;
slouken@10433
   731
            item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_UP;
slouken@10433
   732
        }
slouken@10433
   733
    }
slouken@10433
   734
    
slouken@10433
   735
    *mt_req_code = ABS_MT_POSITION_X;
slouken@10445
   736
    ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
slouken@10445
   737
    if (ret < 0) {
slouken@10445
   738
        SDL_free(mt_req_code);
slouken@10445
   739
        SDL_Log("Failed to sync device");
slouken@10433
   740
        return;
slouken@10433
   741
    }
slouken@10445
   742
    for(i = 0; i < item->touchscreen_data->max_slots; i++) {
slouken@10445
   743
        if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
slouken@10445
   744
            item->touchscreen_data->slots[i].x != mt_req_values[i]) {
slouken@10433
   745
            item->touchscreen_data->slots[i].x = mt_req_values[i];
slouken@10445
   746
            if (item->touchscreen_data->slots[i].delta ==
slouken@10445
   747
                EVDEV_TOUCH_SLOTDELTA_NONE) {
slouken@10433
   748
                item->touchscreen_data->slots[i].delta =
slouken@10433
   749
                    EVDEV_TOUCH_SLOTDELTA_MOVE;
slouken@10433
   750
            }
slouken@10433
   751
        }
slouken@10433
   752
    }
slouken@10433
   753
    
slouken@10433
   754
    *mt_req_code = ABS_MT_POSITION_Y;
slouken@10445
   755
    ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
slouken@10445
   756
    if (ret < 0) {
slouken@10445
   757
        SDL_free(mt_req_code);
slouken@10445
   758
        SDL_Log("Failed to sync device");
slouken@10433
   759
        return;
slouken@10433
   760
    }
slouken@10445
   761
    for(i = 0; i < item->touchscreen_data->max_slots; i++) {
slouken@10445
   762
        if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
slouken@10445
   763
            item->touchscreen_data->slots[i].y != mt_req_values[i]) {
slouken@10433
   764
            item->touchscreen_data->slots[i].y = mt_req_values[i];
slouken@10445
   765
            if (item->touchscreen_data->slots[i].delta ==
slouken@10445
   766
                EVDEV_TOUCH_SLOTDELTA_NONE) {
slouken@10433
   767
                item->touchscreen_data->slots[i].delta =
slouken@10433
   768
                    EVDEV_TOUCH_SLOTDELTA_MOVE;
slouken@10433
   769
            }
slouken@10433
   770
        }
slouken@10433
   771
    }
slouken@10433
   772
    
slouken@10445
   773
    ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
slouken@10445
   774
    if (ret < 0) {
slouken@10445
   775
        SDL_free(mt_req_code);
slouken@10445
   776
        SDL_Log("Failed to sync device");
slouken@10433
   777
        return;
slouken@10433
   778
    }
slouken@10433
   779
    item->touchscreen_data->current_slot = abs_info.value;
slouken@10433
   780
    
slouken@10445
   781
    SDL_free(mt_req_code);
gabomdq@7753
   782
}
gabomdq@7753
   783
gabomdq@7755
   784
#if SDL_USE_LIBUDEV
gabomdq@7753
   785
static int
slouken@10433
   786
SDL_EVDEV_device_added(const char *dev_path, int udev_class)
gabomdq@7753
   787
{
slouken@10433
   788
    int ret;
gabomdq@7753
   789
    SDL_evdevlist_item *item;
gabomdq@7753
   790
gabomdq@7753
   791
    /* Check to make sure it's not already in list. */
gabomdq@7753
   792
    for (item = _this->first; item != NULL; item = item->next) {
slouken@10433
   793
        if (SDL_strcmp(dev_path, item->path) == 0) {
gabomdq@7753
   794
            return -1;  /* already have this one */
gabomdq@7753
   795
        }
gabomdq@7753
   796
    }
gabomdq@7753
   797
    
gabomdq@7753
   798
    item = (SDL_evdevlist_item *) SDL_calloc(1, sizeof (SDL_evdevlist_item));
gabomdq@7753
   799
    if (item == NULL) {
gabomdq@7753
   800
        return SDL_OutOfMemory();
gabomdq@7753
   801
    }
gabomdq@7753
   802
slouken@10445
   803
    item->fd = open(dev_path, O_RDONLY | O_NONBLOCK);
gabomdq@7753
   804
    if (item->fd < 0) {
gabomdq@7753
   805
        SDL_free(item);
slouken@10433
   806
        return SDL_SetError("Unable to open %s", dev_path);
gabomdq@7753
   807
    }
gabomdq@7753
   808
    
slouken@10433
   809
    item->path = SDL_strdup(dev_path);
gabomdq@7753
   810
    if (item->path == NULL) {
gabomdq@7753
   811
        close(item->fd);
gabomdq@7753
   812
        SDL_free(item);
gabomdq@7753
   813
        return SDL_OutOfMemory();
gabomdq@7753
   814
    }
gabomdq@7753
   815
    
slouken@10445
   816
    if (udev_class & SDL_UDEV_DEVICE_TOUCHSCREEN) {
slouken@10433
   817
        item->is_touchscreen = 1;
slouken@10433
   818
        
slouken@10445
   819
        if ((ret = SDL_EVDEV_init_touchscreen(item)) < 0) {
slouken@10433
   820
            close(item->fd);
slouken@10433
   821
            SDL_free(item);
slouken@10433
   822
            return ret;
slouken@10433
   823
        }
slouken@10433
   824
    }
gabomdq@7753
   825
    
gabomdq@7753
   826
    if (_this->last == NULL) {
gabomdq@7753
   827
        _this->first = _this->last = item;
gabomdq@7753
   828
    } else {
gabomdq@7753
   829
        _this->last->next = item;
gabomdq@7753
   830
        _this->last = item;
gabomdq@7753
   831
    }
gabomdq@7753
   832
    
gabomdq@7753
   833
    SDL_EVDEV_sync_device(item);
gabomdq@7753
   834
    
slouken@10433
   835
    return _this->num_devices++;
gabomdq@7753
   836
}
gabomdq@7767
   837
#endif /* SDL_USE_LIBUDEV */
gabomdq@7753
   838
gabomdq@7753
   839
static int
slouken@10433
   840
SDL_EVDEV_device_removed(const char *dev_path)
gabomdq@7753
   841
{
gabomdq@7753
   842
    SDL_evdevlist_item *item;
gabomdq@7753
   843
    SDL_evdevlist_item *prev = NULL;
gabomdq@7753
   844
gabomdq@7753
   845
    for (item = _this->first; item != NULL; item = item->next) {
gabomdq@7753
   846
        /* found it, remove it. */
slouken@10433
   847
        if (SDL_strcmp(dev_path, item->path) == 0) {
gabomdq@7753
   848
            if (prev != NULL) {
gabomdq@7753
   849
                prev->next = item->next;
gabomdq@7753
   850
            } else {
gabomdq@7753
   851
                SDL_assert(_this->first == item);
gabomdq@7753
   852
                _this->first = item->next;
gabomdq@7753
   853
            }
gabomdq@7753
   854
            if (item == _this->last) {
gabomdq@7753
   855
                _this->last = prev;
gabomdq@7753
   856
            }
slouken@10445
   857
            if (item->is_touchscreen) {
slouken@10445
   858
                SDL_EVDEV_destroy_touchscreen(item);
slouken@10433
   859
            }
gabomdq@7753
   860
            close(item->fd);
gabomdq@7753
   861
            SDL_free(item->path);
gabomdq@7753
   862
            SDL_free(item);
slouken@10433
   863
            _this->num_devices--;
gabomdq@7753
   864
            return 0;
gabomdq@7753
   865
        }
gabomdq@7753
   866
        prev = item;
gabomdq@7753
   867
    }
gabomdq@7753
   868
gabomdq@7753
   869
    return -1;
gabomdq@7753
   870
}
gabomdq@7767
   871
gabomdq@7753
   872
gabomdq@7753
   873
#endif /* SDL_INPUT_LINUXEV */
gabomdq@7753
   874
gabomdq@7753
   875
/* vi: set ts=4 sw=4 expandtab: */