Atlas - SDL_evdev.c
Home / ext / SDL2 / src / core / linux Lines: 1 | Size: 24222 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 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 60typedef 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 95typedef 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#define _THIS SDL_EVDEV_PrivateData *_this 105static _THIS = NULL; 106 107static SDL_Scancode SDL_EVDEV_translate_keycode(int keycode); 108static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item); 109static int SDL_EVDEV_device_removed(const char *dev_path); 110 111#if SDL_USE_LIBUDEV 112static int SDL_EVDEV_device_added(const char *dev_path, int udev_class); 113static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, 114 const char *dev_path); 115#endif /* SDL_USE_LIBUDEV */ 116 117static Uint8 EVDEV_MouseButtons[] = { 118 SDL_BUTTON_LEFT, /* BTN_LEFT 0x110 */ 119 SDL_BUTTON_RIGHT, /* BTN_RIGHT 0x111 */ 120 SDL_BUTTON_MIDDLE, /* BTN_MIDDLE 0x112 */ 121 SDL_BUTTON_X1, /* BTN_SIDE 0x113 */ 122 SDL_BUTTON_X2, /* BTN_EXTRA 0x114 */ 123 SDL_BUTTON_X2 + 1, /* BTN_FORWARD 0x115 */ 124 SDL_BUTTON_X2 + 2, /* BTN_BACK 0x116 */ 125 SDL_BUTTON_X2 + 3 /* BTN_TASK 0x117 */ 126}; 127 128int 129SDL_EVDEV_Init(void) 130{ 131 if (_this == NULL) { 132 _this = (SDL_EVDEV_PrivateData*)SDL_calloc(1, sizeof(*_this)); 133 if (_this == NULL) { 134 return SDL_OutOfMemory(); 135 } 136 137#if SDL_USE_LIBUDEV 138 if (SDL_UDEV_Init() < 0) { 139 SDL_free(_this); 140 _this = NULL; 141 return -1; 142 } 143 144 /* Set up the udev callback */ 145 if (SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) { 146 SDL_UDEV_Quit(); 147 SDL_free(_this); 148 _this = NULL; 149 return -1; 150 } 151 152 /* Force a scan to build the initial device list */ 153 SDL_UDEV_Scan(); 154#else 155 /* TODO: Scan the devices manually, like a caveman */ 156#endif /* SDL_USE_LIBUDEV */ 157 158 _this->kbd = SDL_EVDEV_kbd_init(); 159 } 160 161 _this->ref_count += 1; 162 163 return 0; 164} 165 166void 167SDL_EVDEV_Quit(void) 168{ 169 if (_this == NULL) { 170 return; 171 } 172 173 _this->ref_count -= 1; 174 175 if (_this->ref_count < 1) { 176#if SDL_USE_LIBUDEV 177 SDL_UDEV_DelCallback(SDL_EVDEV_udev_callback); 178 SDL_UDEV_Quit(); 179#endif /* SDL_USE_LIBUDEV */ 180 181 SDL_EVDEV_kbd_quit(_this->kbd); 182 183 /* Remove existing devices */ 184 while(_this->first != NULL) { 185 SDL_EVDEV_device_removed(_this->first->path); 186 } 187 188 SDL_assert(_this->first == NULL); 189 SDL_assert(_this->last == NULL); 190 SDL_assert(_this->num_devices == 0); 191 192 SDL_free(_this); 193 _this = NULL; 194 } 195} 196 197#if SDL_USE_LIBUDEV 198static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event, int udev_class, 199 const char* dev_path) 200{ 201 if (dev_path == NULL) { 202 return; 203 } 204 205 switch(udev_event) { 206 case SDL_UDEV_DEVICEADDED: 207 if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD | 208 SDL_UDEV_DEVICE_TOUCHSCREEN))) 209 return; 210 211 SDL_EVDEV_device_added(dev_path, udev_class); 212 break; 213 case SDL_UDEV_DEVICEREMOVED: 214 SDL_EVDEV_device_removed(dev_path); 215 break; 216 default: 217 break; 218 } 219} 220#endif /* SDL_USE_LIBUDEV */ 221 222void 223SDL_EVDEV_Poll(void) 224{ 225 struct input_event events[32]; 226 int i, j, len; 227 SDL_evdevlist_item *item; 228 SDL_Scancode scan_code; 229 int mouse_button; 230 SDL_Mouse *mouse; 231 float norm_x, norm_y; 232 233 if (!_this) { 234 return; 235 } 236 237#if SDL_USE_LIBUDEV 238 SDL_UDEV_Poll(); 239#endif 240 241 mouse = SDL_GetMouse(); 242 243 for (item = _this->first; item != NULL; item = item->next) { 244 while ((len = read(item->fd, events, (sizeof events))) > 0) { 245 len /= sizeof(events[0]); 246 for (i = 0; i < len; ++i) { 247 /* special handling for touchscreen, that should eventually be 248 used for all devices */ 249 if (item->out_of_sync && item->is_touchscreen && 250 events[i].type == EV_SYN && events[i].code != SYN_REPORT) { 251 break; 252 } 253 254 switch (events[i].type) { 255 case EV_KEY: 256 if (events[i].code >= BTN_MOUSE && events[i].code < BTN_MOUSE + SDL_arraysize(EVDEV_MouseButtons)) { 257 mouse_button = events[i].code - BTN_MOUSE; 258 if (events[i].value == 0) { 259 SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, EVDEV_MouseButtons[mouse_button]); 260 } else if (events[i].value == 1) { 261 SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, EVDEV_MouseButtons[mouse_button]); 262 } 263 break; 264 } 265 266 /* Probably keyboard */ 267 scan_code = SDL_EVDEV_translate_keycode(events[i].code); 268 if (scan_code != SDL_SCANCODE_UNKNOWN) { 269 if (events[i].value == 0) { 270 SDL_SendKeyboardKey(SDL_RELEASED, scan_code); 271 } else if (events[i].value == 1 || events[i].value == 2 /* key repeated */) { 272 SDL_SendKeyboardKey(SDL_PRESSED, scan_code); 273 } 274 } 275 SDL_EVDEV_kbd_keycode(_this->kbd, events[i].code, events[i].value); 276 break; 277 case EV_ABS: 278 switch(events[i].code) { 279 case ABS_MT_SLOT: 280 if (!item->is_touchscreen) /* FIXME: temp hack */ 281 break; 282 item->touchscreen_data->current_slot = events[i].value; 283 break; 284 case ABS_MT_TRACKING_ID: 285 if (!item->is_touchscreen) /* FIXME: temp hack */ 286 break; 287 if (events[i].value >= 0) { 288 item->touchscreen_data->slots[item->touchscreen_data->current_slot].tracking_id = events[i].value; 289 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_DOWN; 290 } else { 291 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_UP; 292 } 293 break; 294 case ABS_MT_POSITION_X: 295 if (!item->is_touchscreen) /* FIXME: temp hack */ 296 break; 297 item->touchscreen_data->slots[item->touchscreen_data->current_slot].x = events[i].value; 298 if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) { 299 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE; 300 } 301 break; 302 case ABS_MT_POSITION_Y: 303 if (!item->is_touchscreen) /* FIXME: temp hack */ 304 break; 305 item->touchscreen_data->slots[item->touchscreen_data->current_slot].y = events[i].value; 306 if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) { 307 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE; 308 } 309 break; 310 case ABS_X: 311 if (item->is_touchscreen) /* FIXME: temp hack */ 312 break; 313 SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y); 314 break; 315 case ABS_Y: 316 if (item->is_touchscreen) /* FIXME: temp hack */ 317 break; 318 SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value); 319 break; 320 default: 321 break; 322 } 323 break; 324 case EV_REL: 325 switch(events[i].code) { 326 case REL_X: 327 SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, events[i].value, 0); 328 break; 329 case REL_Y: 330 SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, 0, events[i].value); 331 break; 332 case REL_WHEEL: 333 SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value, SDL_MOUSEWHEEL_NORMAL); 334 break; 335 case REL_HWHEEL: 336 SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0, SDL_MOUSEWHEEL_NORMAL); 337 break; 338 default: 339 break; 340 } 341 break; 342 case EV_SYN: 343 switch (events[i].code) { 344 case SYN_REPORT: 345 if (!item->is_touchscreen) /* FIXME: temp hack */ 346 break; 347 348 for(j = 0; j < item->touchscreen_data->max_slots; j++) { 349 norm_x = (float)(item->touchscreen_data->slots[j].x - item->touchscreen_data->min_x) / 350 (float)item->touchscreen_data->range_x; 351 norm_y = (float)(item->touchscreen_data->slots[j].y - item->touchscreen_data->min_y) / 352 (float)item->touchscreen_data->range_y; 353 354 switch(item->touchscreen_data->slots[j].delta) { 355 case EVDEV_TOUCH_SLOTDELTA_DOWN: 356 SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_TRUE, norm_x, norm_y, 1.0f); 357 item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE; 358 break; 359 case EVDEV_TOUCH_SLOTDELTA_UP: 360 SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_FALSE, norm_x, norm_y, 1.0f); 361 item->touchscreen_data->slots[j].tracking_id = -1; 362 item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE; 363 break; 364 case EVDEV_TOUCH_SLOTDELTA_MOVE: 365 SDL_SendTouchMotion(item->fd, item->touchscreen_data->slots[j].tracking_id, norm_x, norm_y, 1.0f); 366 item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE; 367 break; 368 default: 369 break; 370 } 371 } 372 373 if (item->out_of_sync) 374 item->out_of_sync = 0; 375 break; 376 case SYN_DROPPED: 377 if (item->is_touchscreen) 378 item->out_of_sync = 1; 379 SDL_EVDEV_sync_device(item); 380 break; 381 default: 382 break; 383 } 384 break; 385 } 386 } 387 } 388 } 389} 390 391static SDL_Scancode 392SDL_EVDEV_translate_keycode(int keycode) 393{ 394 SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN; 395 396 if (keycode < SDL_arraysize(linux_scancode_table)) 397 scancode = linux_scancode_table[keycode]; 398 399 if (scancode == SDL_SCANCODE_UNKNOWN) { 400 SDL_Log("The key you just pressed is not recognized by SDL. To help " 401 "get this fixed, please report this to the SDL forums/mailing list " 402 "<https://discourse.libsdl.org/> EVDEV KeyCode %d", keycode); 403 } 404 405 return scancode; 406} 407 408#ifdef SDL_USE_LIBUDEV 409static int 410SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item) 411{ 412 int ret, i; 413 char name[64]; 414 struct input_absinfo abs_info; 415 416 if (!item->is_touchscreen) 417 return 0; 418 419 item->touchscreen_data = SDL_calloc(1, sizeof(*item->touchscreen_data)); 420 if (item->touchscreen_data == NULL) 421 return SDL_OutOfMemory(); 422 423 ret = ioctl(item->fd, EVIOCGNAME(sizeof(name)), name); 424 if (ret < 0) { 425 SDL_free(item->touchscreen_data); 426 return SDL_SetError("Failed to get evdev touchscreen name"); 427 } 428 429 item->touchscreen_data->name = SDL_strdup(name); 430 if (item->touchscreen_data->name == NULL) { 431 SDL_free(item->touchscreen_data); 432 return SDL_OutOfMemory(); 433 } 434 435 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_X), &abs_info); 436 if (ret < 0) { 437 SDL_free(item->touchscreen_data->name); 438 SDL_free(item->touchscreen_data); 439 return SDL_SetError("Failed to get evdev touchscreen limits"); 440 } 441 item->touchscreen_data->min_x = abs_info.minimum; 442 item->touchscreen_data->max_x = abs_info.maximum; 443 item->touchscreen_data->range_x = abs_info.maximum - abs_info.minimum; 444 445 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_Y), &abs_info); 446 if (ret < 0) { 447 SDL_free(item->touchscreen_data->name); 448 SDL_free(item->touchscreen_data); 449 return SDL_SetError("Failed to get evdev touchscreen limits"); 450 } 451 item->touchscreen_data->min_y = abs_info.minimum; 452 item->touchscreen_data->max_y = abs_info.maximum; 453 item->touchscreen_data->range_y = abs_info.maximum - abs_info.minimum; 454 455 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info); 456 if (ret < 0) { 457 SDL_free(item->touchscreen_data->name); 458 SDL_free(item->touchscreen_data); 459 return SDL_SetError("Failed to get evdev touchscreen limits"); 460 } 461 item->touchscreen_data->max_slots = abs_info.maximum + 1; 462 463 item->touchscreen_data->slots = SDL_calloc( 464 item->touchscreen_data->max_slots, 465 sizeof(*item->touchscreen_data->slots)); 466 if (item->touchscreen_data->slots == NULL) { 467 SDL_free(item->touchscreen_data->name); 468 SDL_free(item->touchscreen_data); 469 return SDL_OutOfMemory(); 470 } 471 472 for(i = 0; i < item->touchscreen_data->max_slots; i++) { 473 item->touchscreen_data->slots[i].tracking_id = -1; 474 } 475 476 ret = SDL_AddTouch(item->fd, /* I guess our fd is unique enough */ 477 item->touchscreen_data->name); 478 if (ret < 0) { 479 SDL_free(item->touchscreen_data->slots); 480 SDL_free(item->touchscreen_data->name); 481 SDL_free(item->touchscreen_data); 482 return ret; 483 } 484 485 return 0; 486} 487#endif /* SDL_USE_LIBUDEV */ 488 489static void 490SDL_EVDEV_destroy_touchscreen(SDL_evdevlist_item* item) { 491 if (!item->is_touchscreen) 492 return; 493 494 SDL_DelTouch(item->fd); 495 SDL_free(item->touchscreen_data->slots); 496 SDL_free(item->touchscreen_data->name); 497 SDL_free(item->touchscreen_data); 498} 499 500static void 501SDL_EVDEV_sync_device(SDL_evdevlist_item *item) 502{ 503#ifdef EVIOCGMTSLOTS 504 int i, ret; 505 struct input_absinfo abs_info; 506 /* 507 * struct input_mt_request_layout { 508 * __u32 code; 509 * __s32 values[num_slots]; 510 * }; 511 * 512 * this is the structure we're trying to emulate 513 */ 514 __u32* mt_req_code; 515 __s32* mt_req_values; 516 size_t mt_req_size; 517 518 /* TODO: sync devices other than touchscreen */ 519 if (!item->is_touchscreen) 520 return; 521 522 mt_req_size = sizeof(*mt_req_code) + 523 sizeof(*mt_req_values) * item->touchscreen_data->max_slots; 524 525 mt_req_code = SDL_calloc(1, mt_req_size); 526 if (mt_req_code == NULL) { 527 return; 528 } 529 530 mt_req_values = (__s32*)mt_req_code + 1; 531 532 *mt_req_code = ABS_MT_TRACKING_ID; 533 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code); 534 if (ret < 0) { 535 SDL_free(mt_req_code); 536 return; 537 } 538 for(i = 0; i < item->touchscreen_data->max_slots; i++) { 539 /* 540 * This doesn't account for the very edge case of the user removing their 541 * finger and replacing it on the screen during the time we're out of sync, 542 * which'll mean that we're not going from down -> up or up -> down, we're 543 * going from down -> down but with a different tracking id, meaning we'd 544 * have to tell SDL of the two events, but since we wait till SYN_REPORT in 545 * SDL_EVDEV_Poll to tell SDL, the current structure of this code doesn't 546 * allow it. Lets just pray to God it doesn't happen. 547 */ 548 if (item->touchscreen_data->slots[i].tracking_id < 0 && 549 mt_req_values[i] >= 0) { 550 item->touchscreen_data->slots[i].tracking_id = mt_req_values[i]; 551 item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_DOWN; 552 } else if (item->touchscreen_data->slots[i].tracking_id >= 0 && 553 mt_req_values[i] < 0) { 554 item->touchscreen_data->slots[i].tracking_id = -1; 555 item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_UP; 556 } 557 } 558 559 *mt_req_code = ABS_MT_POSITION_X; 560 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code); 561 if (ret < 0) { 562 SDL_free(mt_req_code); 563 return; 564 } 565 for(i = 0; i < item->touchscreen_data->max_slots; i++) { 566 if (item->touchscreen_data->slots[i].tracking_id >= 0 && 567 item->touchscreen_data->slots[i].x != mt_req_values[i]) { 568 item->touchscreen_data->slots[i].x = mt_req_values[i]; 569 if (item->touchscreen_data->slots[i].delta == 570 EVDEV_TOUCH_SLOTDELTA_NONE) { 571 item->touchscreen_data->slots[i].delta = 572 EVDEV_TOUCH_SLOTDELTA_MOVE; 573 } 574 } 575 } 576 577 *mt_req_code = ABS_MT_POSITION_Y; 578 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code); 579 if (ret < 0) { 580 SDL_free(mt_req_code); 581 return; 582 } 583 for(i = 0; i < item->touchscreen_data->max_slots; i++) { 584 if (item->touchscreen_data->slots[i].tracking_id >= 0 && 585 item->touchscreen_data->slots[i].y != mt_req_values[i]) { 586 item->touchscreen_data->slots[i].y = mt_req_values[i]; 587 if (item->touchscreen_data->slots[i].delta == 588 EVDEV_TOUCH_SLOTDELTA_NONE) { 589 item->touchscreen_data->slots[i].delta = 590 EVDEV_TOUCH_SLOTDELTA_MOVE; 591 } 592 } 593 } 594 595 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info); 596 if (ret < 0) { 597 SDL_free(mt_req_code); 598 return; 599 } 600 item->touchscreen_data->current_slot = abs_info.value; 601 602 SDL_free(mt_req_code); 603 604#endif /* EVIOCGMTSLOTS */ 605} 606 607#if SDL_USE_LIBUDEV 608static int 609SDL_EVDEV_device_added(const char *dev_path, int udev_class) 610{ 611 int ret; 612 SDL_evdevlist_item *item; 613 614 /* Check to make sure it's not already in list. */ 615 for (item = _this->first; item != NULL; item = item->next) { 616 if (SDL_strcmp(dev_path, item->path) == 0) { 617 return -1; /* already have this one */ 618 } 619 } 620 621 item = (SDL_evdevlist_item *) SDL_calloc(1, sizeof (SDL_evdevlist_item)); 622 if (item == NULL) { 623 return SDL_OutOfMemory(); 624 } 625 626 item->fd = open(dev_path, O_RDONLY | O_NONBLOCK); 627 if (item->fd < 0) { 628 SDL_free(item); 629 return SDL_SetError("Unable to open %s", dev_path); 630 } 631 632 item->path = SDL_strdup(dev_path); 633 if (item->path == NULL) { 634 close(item->fd); 635 SDL_free(item); 636 return SDL_OutOfMemory(); 637 } 638 639 if (udev_class & SDL_UDEV_DEVICE_TOUCHSCREEN) { 640 item->is_touchscreen = 1; 641 642 if ((ret = SDL_EVDEV_init_touchscreen(item)) < 0) { 643 close(item->fd); 644 SDL_free(item); 645 return ret; 646 } 647 } 648 649 if (_this->last == NULL) { 650 _this->first = _this->last = item; 651 } else { 652 _this->last->next = item; 653 _this->last = item; 654 } 655 656 SDL_EVDEV_sync_device(item); 657 658 return _this->num_devices++; 659} 660#endif /* SDL_USE_LIBUDEV */ 661 662static int 663SDL_EVDEV_device_removed(const char *dev_path) 664{ 665 SDL_evdevlist_item *item; 666 SDL_evdevlist_item *prev = NULL; 667 668 for (item = _this->first; item != NULL; item = item->next) { 669 /* found it, remove it. */ 670 if (SDL_strcmp(dev_path, item->path) == 0) { 671 if (prev != NULL) { 672 prev->next = item->next; 673 } else { 674 SDL_assert(_this->first == item); 675 _this->first = item->next; 676 } 677 if (item == _this->last) { 678 _this->last = prev; 679 } 680 if (item->is_touchscreen) { 681 SDL_EVDEV_destroy_touchscreen(item); 682 } 683 close(item->fd); 684 SDL_free(item->path); 685 SDL_free(item); 686 _this->num_devices--; 687 return 0; 688 } 689 prev = item; 690 } 691 692 return -1; 693} 694 695 696#endif /* SDL_INPUT_LINUXEV */ 697 698/* vi: set ts=4 sw=4 expandtab: */ 699[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.