src/core/linux/SDL_evdev.c
author Ozkan Sezer <sezeroz@gmail.com>
Wed, 29 Aug 2018 11:04:02 +0300
changeset 12160 c63903ab7150
parent 11811 5d94cb6b24d3
child 12404 eb60e952b13f
permissions -rw-r--r--
SDL_evdev.c: undefine _THIS before redefining it.

src/core/linux/SDL_evdev.c:104:1: warning: "_THIS" redefined
In file included from src/core/linux/../../events/SDL_events_c.h:26,
from src/core/linux/SDL_evdev.c:45:
src/core/linux/../../events/../video/SDL_sysvideo.h:146:1: warning: this is the location of the previous definition
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #ifdef SDL_INPUT_LINUXEV
    24 
    25 /* This is based on the linux joystick driver */
    26 /* References: https://www.kernel.org/doc/Documentation/input/input.txt 
    27  *             https://www.kernel.org/doc/Documentation/input/event-codes.txt
    28  *             /usr/include/linux/input.h
    29  *             The evtest application is also useful to debug the protocol
    30  */
    31 
    32 #include "SDL_evdev.h"
    33 #include "SDL_evdev_kbd.h"
    34 
    35 #include <sys/stat.h>
    36 #include <unistd.h>
    37 #include <fcntl.h>
    38 #include <sys/ioctl.h>
    39 #include <linux/input.h>
    40 
    41 #include "SDL.h"
    42 #include "SDL_assert.h"
    43 #include "SDL_endian.h"
    44 #include "SDL_scancode.h"
    45 #include "../../events/SDL_events_c.h"
    46 #include "../../events/scancodes_linux.h" /* adds linux_scancode_table */
    47 #include "../../core/linux/SDL_udev.h"
    48 
    49 /* These are not defined in older Linux kernel headers */
    50 #ifndef SYN_DROPPED
    51 #define SYN_DROPPED 3
    52 #endif
    53 #ifndef ABS_MT_SLOT
    54 #define ABS_MT_SLOT         0x2f
    55 #define ABS_MT_POSITION_X   0x35
    56 #define ABS_MT_POSITION_Y   0x36
    57 #define ABS_MT_TRACKING_ID  0x39
    58 #endif
    59 
    60 typedef struct SDL_evdevlist_item
    61 {
    62     char *path;
    63     int fd;
    64 
    65     /* TODO: use this for every device, not just touchscreen */
    66     int out_of_sync;
    67 
    68     /* TODO: expand on this to have data for every possible class (mouse,
    69        keyboard, touchpad, etc.). Also there's probably some things in here we
    70        can pull out to the SDL_evdevlist_item i.e. name */
    71     int is_touchscreen;
    72     struct {
    73         char* name;
    74 
    75         int min_x, max_x, range_x;
    76         int min_y, max_y, range_y;
    77 
    78         int max_slots;
    79         int current_slot;
    80         struct {
    81             enum {
    82                 EVDEV_TOUCH_SLOTDELTA_NONE = 0,
    83                 EVDEV_TOUCH_SLOTDELTA_DOWN,
    84                 EVDEV_TOUCH_SLOTDELTA_UP,
    85                 EVDEV_TOUCH_SLOTDELTA_MOVE
    86             } delta;
    87             int tracking_id;
    88             int x, y;
    89         } * slots;
    90     } * touchscreen_data;
    91 
    92     struct SDL_evdevlist_item *next;
    93 } SDL_evdevlist_item;
    94 
    95 typedef struct SDL_EVDEV_PrivateData
    96 {
    97     int ref_count;
    98     int num_devices;
    99     SDL_evdevlist_item *first;
   100     SDL_evdevlist_item *last;
   101     SDL_EVDEV_keyboard_state *kbd;
   102 } SDL_EVDEV_PrivateData;
   103 
   104 #undef _THIS
   105 #define _THIS SDL_EVDEV_PrivateData *_this
   106 static _THIS = NULL;
   107 
   108 static SDL_Scancode SDL_EVDEV_translate_keycode(int keycode);
   109 static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item);
   110 static int SDL_EVDEV_device_removed(const char *dev_path);
   111 
   112 #if SDL_USE_LIBUDEV
   113 static int SDL_EVDEV_device_added(const char *dev_path, int udev_class);
   114 static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class,
   115     const char *dev_path);
   116 #endif /* SDL_USE_LIBUDEV */
   117 
   118 static Uint8 EVDEV_MouseButtons[] = {
   119     SDL_BUTTON_LEFT,            /*  BTN_LEFT        0x110 */
   120     SDL_BUTTON_RIGHT,           /*  BTN_RIGHT       0x111 */
   121     SDL_BUTTON_MIDDLE,          /*  BTN_MIDDLE      0x112 */
   122     SDL_BUTTON_X1,              /*  BTN_SIDE        0x113 */
   123     SDL_BUTTON_X2,              /*  BTN_EXTRA       0x114 */
   124     SDL_BUTTON_X2 + 1,          /*  BTN_FORWARD     0x115 */
   125     SDL_BUTTON_X2 + 2,          /*  BTN_BACK        0x116 */
   126     SDL_BUTTON_X2 + 3           /*  BTN_TASK        0x117 */
   127 };
   128 
   129 int
   130 SDL_EVDEV_Init(void)
   131 {
   132     if (_this == NULL) {
   133         _this = (SDL_EVDEV_PrivateData*)SDL_calloc(1, sizeof(*_this));
   134         if (_this == NULL) {
   135             return SDL_OutOfMemory();
   136         }
   137 
   138 #if SDL_USE_LIBUDEV
   139         if (SDL_UDEV_Init() < 0) {
   140             SDL_free(_this);
   141             _this = NULL;
   142             return -1;
   143         }
   144 
   145         /* Set up the udev callback */
   146         if (SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) {
   147             SDL_UDEV_Quit();
   148             SDL_free(_this);
   149             _this = NULL;
   150             return -1;
   151         }
   152 
   153         /* Force a scan to build the initial device list */
   154         SDL_UDEV_Scan();
   155 #else
   156         /* TODO: Scan the devices manually, like a caveman */
   157 #endif /* SDL_USE_LIBUDEV */
   158 
   159         _this->kbd = SDL_EVDEV_kbd_init();
   160     }
   161 
   162     _this->ref_count += 1;
   163 
   164     return 0;
   165 }
   166 
   167 void
   168 SDL_EVDEV_Quit(void)
   169 {
   170     if (_this == NULL) {
   171         return;
   172     }
   173 
   174     _this->ref_count -= 1;
   175 
   176     if (_this->ref_count < 1) {
   177 #if SDL_USE_LIBUDEV
   178         SDL_UDEV_DelCallback(SDL_EVDEV_udev_callback);
   179         SDL_UDEV_Quit();
   180 #endif /* SDL_USE_LIBUDEV */
   181 
   182         SDL_EVDEV_kbd_quit(_this->kbd);
   183 
   184         /* Remove existing devices */
   185         while(_this->first != NULL) {
   186             SDL_EVDEV_device_removed(_this->first->path);
   187         }
   188 
   189         SDL_assert(_this->first == NULL);
   190         SDL_assert(_this->last == NULL);
   191         SDL_assert(_this->num_devices == 0);
   192 
   193         SDL_free(_this);
   194         _this = NULL;
   195     }
   196 }
   197 
   198 #if SDL_USE_LIBUDEV
   199 static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event, int udev_class,
   200     const char* dev_path)
   201 {
   202     if (dev_path == NULL) {
   203         return;
   204     }
   205 
   206     switch(udev_event) {
   207     case SDL_UDEV_DEVICEADDED:
   208         if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD |
   209             SDL_UDEV_DEVICE_TOUCHSCREEN)))
   210             return;
   211 
   212         SDL_EVDEV_device_added(dev_path, udev_class);
   213         break;  
   214     case SDL_UDEV_DEVICEREMOVED:
   215         SDL_EVDEV_device_removed(dev_path);
   216         break;
   217     default:
   218         break;
   219     }
   220 }
   221 #endif /* SDL_USE_LIBUDEV */
   222 
   223 void 
   224 SDL_EVDEV_Poll(void)
   225 {
   226     struct input_event events[32];
   227     int i, j, len;
   228     SDL_evdevlist_item *item;
   229     SDL_Scancode scan_code;
   230     int mouse_button;
   231     SDL_Mouse *mouse;
   232     float norm_x, norm_y;
   233 
   234     if (!_this) {
   235         return;
   236     }
   237 
   238 #if SDL_USE_LIBUDEV
   239     SDL_UDEV_Poll();
   240 #endif
   241 
   242     mouse = SDL_GetMouse();
   243 
   244     for (item = _this->first; item != NULL; item = item->next) {
   245         while ((len = read(item->fd, events, (sizeof events))) > 0) {
   246             len /= sizeof(events[0]);
   247             for (i = 0; i < len; ++i) {
   248                 /* special handling for touchscreen, that should eventually be
   249                    used for all devices */
   250                 if (item->out_of_sync && item->is_touchscreen &&
   251                     events[i].type == EV_SYN && events[i].code != SYN_REPORT) {
   252                     break;
   253                 }
   254 
   255                 switch (events[i].type) {
   256                 case EV_KEY:
   257                     if (events[i].code >= BTN_MOUSE && events[i].code < BTN_MOUSE + SDL_arraysize(EVDEV_MouseButtons)) {
   258                         mouse_button = events[i].code - BTN_MOUSE;
   259                         if (events[i].value == 0) {
   260                             SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, EVDEV_MouseButtons[mouse_button]);
   261                         } else if (events[i].value == 1) {
   262                             SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, EVDEV_MouseButtons[mouse_button]);
   263                         }
   264                         break;
   265                     }
   266 
   267                     /* Probably keyboard */
   268                     scan_code = SDL_EVDEV_translate_keycode(events[i].code);
   269                     if (scan_code != SDL_SCANCODE_UNKNOWN) {
   270                         if (events[i].value == 0) {
   271                             SDL_SendKeyboardKey(SDL_RELEASED, scan_code);
   272                         } else if (events[i].value == 1 || events[i].value == 2 /* key repeated */) {
   273                             SDL_SendKeyboardKey(SDL_PRESSED, scan_code);
   274                         }
   275                     }
   276                     SDL_EVDEV_kbd_keycode(_this->kbd, events[i].code, events[i].value);
   277                     break;
   278                 case EV_ABS:
   279                     switch(events[i].code) {
   280                     case ABS_MT_SLOT:
   281                         if (!item->is_touchscreen) /* FIXME: temp hack */
   282                             break;
   283                         item->touchscreen_data->current_slot = events[i].value;
   284                         break;
   285                     case ABS_MT_TRACKING_ID:
   286                         if (!item->is_touchscreen) /* FIXME: temp hack */
   287                             break;
   288                         if (events[i].value >= 0) {
   289                             item->touchscreen_data->slots[item->touchscreen_data->current_slot].tracking_id = events[i].value;
   290                             item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
   291                         } else {
   292                             item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_UP;
   293                         }
   294                         break;
   295                     case ABS_MT_POSITION_X:
   296                         if (!item->is_touchscreen) /* FIXME: temp hack */
   297                             break;
   298                         item->touchscreen_data->slots[item->touchscreen_data->current_slot].x = events[i].value;
   299                         if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
   300                             item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
   301                         }
   302                         break;
   303                     case ABS_MT_POSITION_Y:
   304                         if (!item->is_touchscreen) /* FIXME: temp hack */
   305                             break;
   306                         item->touchscreen_data->slots[item->touchscreen_data->current_slot].y = events[i].value;
   307                         if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
   308                             item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
   309                         }
   310                         break;
   311                     case ABS_X:
   312                         if (item->is_touchscreen) /* FIXME: temp hack */
   313                             break;
   314                         SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y);
   315                         break;
   316                     case ABS_Y:
   317                         if (item->is_touchscreen) /* FIXME: temp hack */
   318                             break;
   319                         SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value);
   320                         break;
   321                     default:
   322                         break;
   323                     }
   324                     break;
   325                 case EV_REL:
   326                     switch(events[i].code) {
   327                     case REL_X:
   328                         SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, events[i].value, 0);
   329                         break;
   330                     case REL_Y:
   331                         SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, 0, events[i].value);
   332                         break;
   333                     case REL_WHEEL:
   334                         SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value, SDL_MOUSEWHEEL_NORMAL);
   335                         break;
   336                     case REL_HWHEEL:
   337                         SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0, SDL_MOUSEWHEEL_NORMAL);
   338                         break;
   339                     default:
   340                         break;
   341                     }
   342                     break;
   343                 case EV_SYN:
   344                     switch (events[i].code) {
   345                     case SYN_REPORT:
   346                         if (!item->is_touchscreen) /* FIXME: temp hack */
   347                             break;
   348 
   349                         for(j = 0; j < item->touchscreen_data->max_slots; j++) {
   350                             norm_x = (float)(item->touchscreen_data->slots[j].x - item->touchscreen_data->min_x) /
   351                                 (float)item->touchscreen_data->range_x;
   352                             norm_y = (float)(item->touchscreen_data->slots[j].y - item->touchscreen_data->min_y) /
   353                                 (float)item->touchscreen_data->range_y;
   354 
   355                             switch(item->touchscreen_data->slots[j].delta) {
   356                             case EVDEV_TOUCH_SLOTDELTA_DOWN:
   357                                 SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_TRUE, norm_x, norm_y, 1.0f);
   358                                 item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
   359                                 break;
   360                             case EVDEV_TOUCH_SLOTDELTA_UP:
   361                                 SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_FALSE, norm_x, norm_y, 1.0f);
   362                                 item->touchscreen_data->slots[j].tracking_id = -1;
   363                                 item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
   364                                 break;
   365                             case EVDEV_TOUCH_SLOTDELTA_MOVE:
   366                                 SDL_SendTouchMotion(item->fd, item->touchscreen_data->slots[j].tracking_id, norm_x, norm_y, 1.0f);
   367                                 item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
   368                                 break;
   369                             default:
   370                                 break;
   371                             }
   372                         }
   373 
   374                         if (item->out_of_sync)
   375                             item->out_of_sync = 0;
   376                         break;
   377                     case SYN_DROPPED:
   378                         if (item->is_touchscreen)
   379                             item->out_of_sync = 1;
   380                         SDL_EVDEV_sync_device(item);
   381                         break;
   382                     default:
   383                         break;
   384                     }
   385                     break;
   386                 }
   387             }
   388         }    
   389     }
   390 }
   391 
   392 static SDL_Scancode
   393 SDL_EVDEV_translate_keycode(int keycode)
   394 {
   395     SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
   396 
   397     if (keycode < SDL_arraysize(linux_scancode_table))
   398         scancode = linux_scancode_table[keycode];
   399 
   400     if (scancode == SDL_SCANCODE_UNKNOWN) {
   401         SDL_Log("The key you just pressed is not recognized by SDL. To help "
   402             "get this fixed, please report this to the SDL forums/mailing list "
   403             "<https://discourse.libsdl.org/> EVDEV KeyCode %d", keycode);
   404     }
   405 
   406     return scancode;
   407 }
   408 
   409 #ifdef SDL_USE_LIBUDEV
   410 static int
   411 SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
   412 {
   413     int ret, i;
   414     char name[64];
   415     struct input_absinfo abs_info;
   416 
   417     if (!item->is_touchscreen)
   418         return 0;
   419 
   420     item->touchscreen_data = SDL_calloc(1, sizeof(*item->touchscreen_data));
   421     if (item->touchscreen_data == NULL)
   422         return SDL_OutOfMemory();
   423 
   424     ret = ioctl(item->fd, EVIOCGNAME(sizeof(name)), name);
   425     if (ret < 0) {
   426         SDL_free(item->touchscreen_data);
   427         return SDL_SetError("Failed to get evdev touchscreen name");
   428     }
   429 
   430     item->touchscreen_data->name = SDL_strdup(name);
   431     if (item->touchscreen_data->name == NULL) {
   432         SDL_free(item->touchscreen_data);
   433         return SDL_OutOfMemory();
   434     }
   435 
   436     ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_X), &abs_info);
   437     if (ret < 0) {
   438         SDL_free(item->touchscreen_data->name);
   439         SDL_free(item->touchscreen_data);
   440         return SDL_SetError("Failed to get evdev touchscreen limits");
   441     }
   442     item->touchscreen_data->min_x = abs_info.minimum;
   443     item->touchscreen_data->max_x = abs_info.maximum;
   444     item->touchscreen_data->range_x = abs_info.maximum - abs_info.minimum;
   445 
   446     ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_Y), &abs_info);
   447     if (ret < 0) {
   448         SDL_free(item->touchscreen_data->name);
   449         SDL_free(item->touchscreen_data);
   450         return SDL_SetError("Failed to get evdev touchscreen limits");
   451     }
   452     item->touchscreen_data->min_y = abs_info.minimum;
   453     item->touchscreen_data->max_y = abs_info.maximum;
   454     item->touchscreen_data->range_y = abs_info.maximum - abs_info.minimum;
   455 
   456     ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
   457     if (ret < 0) {
   458         SDL_free(item->touchscreen_data->name);
   459         SDL_free(item->touchscreen_data);
   460         return SDL_SetError("Failed to get evdev touchscreen limits");
   461     }
   462     item->touchscreen_data->max_slots = abs_info.maximum + 1;
   463 
   464     item->touchscreen_data->slots = SDL_calloc(
   465         item->touchscreen_data->max_slots,
   466         sizeof(*item->touchscreen_data->slots));
   467     if (item->touchscreen_data->slots == NULL) {
   468         SDL_free(item->touchscreen_data->name);
   469         SDL_free(item->touchscreen_data);
   470         return SDL_OutOfMemory();
   471     }
   472 
   473     for(i = 0; i < item->touchscreen_data->max_slots; i++) {
   474         item->touchscreen_data->slots[i].tracking_id = -1;
   475     }
   476 
   477     ret = SDL_AddTouch(item->fd, /* I guess our fd is unique enough */
   478         item->touchscreen_data->name);
   479     if (ret < 0) {
   480         SDL_free(item->touchscreen_data->slots);
   481         SDL_free(item->touchscreen_data->name);
   482         SDL_free(item->touchscreen_data);
   483         return ret;
   484     }
   485 
   486     return 0;
   487 }
   488 #endif /* SDL_USE_LIBUDEV */
   489 
   490 static void
   491 SDL_EVDEV_destroy_touchscreen(SDL_evdevlist_item* item) {
   492     if (!item->is_touchscreen)
   493         return;
   494 
   495     SDL_DelTouch(item->fd);
   496     SDL_free(item->touchscreen_data->slots);
   497     SDL_free(item->touchscreen_data->name);
   498     SDL_free(item->touchscreen_data);
   499 }
   500 
   501 static void
   502 SDL_EVDEV_sync_device(SDL_evdevlist_item *item) 
   503 {
   504 #ifdef EVIOCGMTSLOTS
   505     int i, ret;
   506     struct input_absinfo abs_info;
   507     /*
   508      * struct input_mt_request_layout {
   509      *     __u32 code;
   510      *     __s32 values[num_slots];
   511      * };
   512      *
   513      * this is the structure we're trying to emulate
   514      */
   515     __u32* mt_req_code;
   516     __s32* mt_req_values;
   517     size_t mt_req_size;
   518 
   519     /* TODO: sync devices other than touchscreen */
   520     if (!item->is_touchscreen)
   521         return;
   522 
   523     mt_req_size = sizeof(*mt_req_code) +
   524         sizeof(*mt_req_values) * item->touchscreen_data->max_slots;
   525 
   526     mt_req_code = SDL_calloc(1, mt_req_size);
   527     if (mt_req_code == NULL) {
   528         return;
   529     }
   530 
   531     mt_req_values = (__s32*)mt_req_code + 1;
   532 
   533     *mt_req_code = ABS_MT_TRACKING_ID;
   534     ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
   535     if (ret < 0) {
   536         SDL_free(mt_req_code);
   537         return;
   538     }
   539     for(i = 0; i < item->touchscreen_data->max_slots; i++) {
   540         /*
   541          * This doesn't account for the very edge case of the user removing their
   542          * finger and replacing it on the screen during the time we're out of sync,
   543          * which'll mean that we're not going from down -> up or up -> down, we're
   544          * going from down -> down but with a different tracking id, meaning we'd
   545          * have to tell SDL of the two events, but since we wait till SYN_REPORT in
   546          * SDL_EVDEV_Poll to tell SDL, the current structure of this code doesn't
   547          * allow it. Lets just pray to God it doesn't happen.
   548          */
   549         if (item->touchscreen_data->slots[i].tracking_id < 0 &&
   550             mt_req_values[i] >= 0) {
   551             item->touchscreen_data->slots[i].tracking_id = mt_req_values[i];
   552             item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
   553         } else if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
   554             mt_req_values[i] < 0) {
   555             item->touchscreen_data->slots[i].tracking_id = -1;
   556             item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_UP;
   557         }
   558     }
   559 
   560     *mt_req_code = ABS_MT_POSITION_X;
   561     ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
   562     if (ret < 0) {
   563         SDL_free(mt_req_code);
   564         return;
   565     }
   566     for(i = 0; i < item->touchscreen_data->max_slots; i++) {
   567         if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
   568             item->touchscreen_data->slots[i].x != mt_req_values[i]) {
   569             item->touchscreen_data->slots[i].x = mt_req_values[i];
   570             if (item->touchscreen_data->slots[i].delta ==
   571                 EVDEV_TOUCH_SLOTDELTA_NONE) {
   572                 item->touchscreen_data->slots[i].delta =
   573                     EVDEV_TOUCH_SLOTDELTA_MOVE;
   574             }
   575         }
   576     }
   577 
   578     *mt_req_code = ABS_MT_POSITION_Y;
   579     ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
   580     if (ret < 0) {
   581         SDL_free(mt_req_code);
   582         return;
   583     }
   584     for(i = 0; i < item->touchscreen_data->max_slots; i++) {
   585         if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
   586             item->touchscreen_data->slots[i].y != mt_req_values[i]) {
   587             item->touchscreen_data->slots[i].y = mt_req_values[i];
   588             if (item->touchscreen_data->slots[i].delta ==
   589                 EVDEV_TOUCH_SLOTDELTA_NONE) {
   590                 item->touchscreen_data->slots[i].delta =
   591                     EVDEV_TOUCH_SLOTDELTA_MOVE;
   592             }
   593         }
   594     }
   595 
   596     ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
   597     if (ret < 0) {
   598         SDL_free(mt_req_code);
   599         return;
   600     }
   601     item->touchscreen_data->current_slot = abs_info.value;
   602 
   603     SDL_free(mt_req_code);
   604 
   605 #endif /* EVIOCGMTSLOTS */
   606 }
   607 
   608 #if SDL_USE_LIBUDEV
   609 static int
   610 SDL_EVDEV_device_added(const char *dev_path, int udev_class)
   611 {
   612     int ret;
   613     SDL_evdevlist_item *item;
   614 
   615     /* Check to make sure it's not already in list. */
   616     for (item = _this->first; item != NULL; item = item->next) {
   617         if (SDL_strcmp(dev_path, item->path) == 0) {
   618             return -1;  /* already have this one */
   619         }
   620     }
   621 
   622     item = (SDL_evdevlist_item *) SDL_calloc(1, sizeof (SDL_evdevlist_item));
   623     if (item == NULL) {
   624         return SDL_OutOfMemory();
   625     }
   626 
   627     item->fd = open(dev_path, O_RDONLY | O_NONBLOCK);
   628     if (item->fd < 0) {
   629         SDL_free(item);
   630         return SDL_SetError("Unable to open %s", dev_path);
   631     }
   632 
   633     item->path = SDL_strdup(dev_path);
   634     if (item->path == NULL) {
   635         close(item->fd);
   636         SDL_free(item);
   637         return SDL_OutOfMemory();
   638     }
   639 
   640     if (udev_class & SDL_UDEV_DEVICE_TOUCHSCREEN) {
   641         item->is_touchscreen = 1;
   642 
   643         if ((ret = SDL_EVDEV_init_touchscreen(item)) < 0) {
   644             close(item->fd);
   645             SDL_free(item);
   646             return ret;
   647         }
   648     }
   649 
   650     if (_this->last == NULL) {
   651         _this->first = _this->last = item;
   652     } else {
   653         _this->last->next = item;
   654         _this->last = item;
   655     }
   656 
   657     SDL_EVDEV_sync_device(item);
   658 
   659     return _this->num_devices++;
   660 }
   661 #endif /* SDL_USE_LIBUDEV */
   662 
   663 static int
   664 SDL_EVDEV_device_removed(const char *dev_path)
   665 {
   666     SDL_evdevlist_item *item;
   667     SDL_evdevlist_item *prev = NULL;
   668 
   669     for (item = _this->first; item != NULL; item = item->next) {
   670         /* found it, remove it. */
   671         if (SDL_strcmp(dev_path, item->path) == 0) {
   672             if (prev != NULL) {
   673                 prev->next = item->next;
   674             } else {
   675                 SDL_assert(_this->first == item);
   676                 _this->first = item->next;
   677             }
   678             if (item == _this->last) {
   679                 _this->last = prev;
   680             }
   681             if (item->is_touchscreen) {
   682                 SDL_EVDEV_destroy_touchscreen(item);
   683             }
   684             close(item->fd);
   685             SDL_free(item->path);
   686             SDL_free(item);
   687             _this->num_devices--;
   688             return 0;
   689         }
   690         prev = item;
   691     }
   692 
   693     return -1;
   694 }
   695 
   696 
   697 #endif /* SDL_INPUT_LINUXEV */
   698 
   699 /* vi: set ts=4 sw=4 expandtab: */