SDL 2.0
SDL_evdev.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 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#define ABS_MT_PRESSURE 0x3a
59#endif
60
61typedef struct SDL_evdevlist_item
62{
63 char *path;
64 int fd;
65
66 /* TODO: use this for every device, not just touchscreen */
67 int out_of_sync;
68
69 /* TODO: expand on this to have data for every possible class (mouse,
70 keyboard, touchpad, etc.). Also there's probably some things in here we
71 can pull out to the SDL_evdevlist_item i.e. name */
72 int is_touchscreen;
73 struct {
74 char* name;
75
76 int min_x, max_x, range_x;
77 int min_y, max_y, range_y;
78 int min_pressure, max_pressure, range_pressure;
79
80 int max_slots;
81 int current_slot;
82 struct {
83 enum {
84 EVDEV_TOUCH_SLOTDELTA_NONE = 0,
85 EVDEV_TOUCH_SLOTDELTA_DOWN,
86 EVDEV_TOUCH_SLOTDELTA_UP,
87 EVDEV_TOUCH_SLOTDELTA_MOVE
88 } delta;
89 int tracking_id;
90 int x, y, pressure;
91 } * slots;
92
93 } * touchscreen_data;
94
95 struct SDL_evdevlist_item *next;
96} SDL_evdevlist_item;
97
98typedef struct SDL_EVDEV_PrivateData
99{
100 int ref_count;
101 int num_devices;
102 SDL_evdevlist_item *first;
103 SDL_evdevlist_item *last;
105} SDL_EVDEV_PrivateData;
106
107#undef _THIS
108#define _THIS SDL_EVDEV_PrivateData *_this
109static _THIS = NULL;
110
111static SDL_Scancode SDL_EVDEV_translate_keycode(int keycode);
112static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item);
113static int SDL_EVDEV_device_removed(const char *dev_path);
114
115#if SDL_USE_LIBUDEV
116static int SDL_EVDEV_device_added(const char *dev_path, int udev_class);
117static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class,
118 const char *dev_path);
119#endif /* SDL_USE_LIBUDEV */
120
121static Uint8 EVDEV_MouseButtons[] = {
122 SDL_BUTTON_LEFT, /* BTN_LEFT 0x110 */
123 SDL_BUTTON_RIGHT, /* BTN_RIGHT 0x111 */
124 SDL_BUTTON_MIDDLE, /* BTN_MIDDLE 0x112 */
125 SDL_BUTTON_X1, /* BTN_SIDE 0x113 */
126 SDL_BUTTON_X2, /* BTN_EXTRA 0x114 */
127 SDL_BUTTON_X2 + 1, /* BTN_FORWARD 0x115 */
128 SDL_BUTTON_X2 + 2, /* BTN_BACK 0x116 */
129 SDL_BUTTON_X2 + 3 /* BTN_TASK 0x117 */
130};
131
132static int
133SDL_EVDEV_SetRelativeMouseMode(SDL_bool enabled)
134{
135 /* Mice already send relative events through this interface */
136 return 0;
137}
138
139
140int
141SDL_EVDEV_Init(void)
142{
143 if (_this == NULL) {
144 _this = (SDL_EVDEV_PrivateData*)SDL_calloc(1, sizeof(*_this));
145 if (_this == NULL) {
146 return SDL_OutOfMemory();
147 }
148
149#if SDL_USE_LIBUDEV
150 if (SDL_UDEV_Init() < 0) {
152 _this = NULL;
153 return -1;
154 }
155
156 /* Set up the udev callback */
157 if (SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) {
158 SDL_UDEV_Quit();
160 _this = NULL;
161 return -1;
162 }
163
164 /* Force a scan to build the initial device list */
165 SDL_UDEV_Scan();
166#else
167 /* TODO: Scan the devices manually, like a caveman */
168#endif /* SDL_USE_LIBUDEV */
169
170 _this->kbd = SDL_EVDEV_kbd_init();
171 }
172
173 SDL_GetMouse()->SetRelativeMouseMode = SDL_EVDEV_SetRelativeMouseMode;
174
175 _this->ref_count += 1;
176
177 return 0;
178}
179
180void
181SDL_EVDEV_Quit(void)
182{
183 if (_this == NULL) {
184 return;
185 }
186
187 _this->ref_count -= 1;
188
189 if (_this->ref_count < 1) {
190#if SDL_USE_LIBUDEV
191 SDL_UDEV_DelCallback(SDL_EVDEV_udev_callback);
192 SDL_UDEV_Quit();
193#endif /* SDL_USE_LIBUDEV */
194
196
197 /* Remove existing devices */
198 while(_this->first != NULL) {
199 SDL_EVDEV_device_removed(_this->first->path);
200 }
201
202 SDL_assert(_this->first == NULL);
203 SDL_assert(_this->last == NULL);
204 SDL_assert(_this->num_devices == 0);
205
207 _this = NULL;
208 }
209}
210
211#if SDL_USE_LIBUDEV
212static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event, int udev_class,
213 const char* dev_path)
214{
215 if (dev_path == NULL) {
216 return;
217 }
218
219 switch(udev_event) {
220 case SDL_UDEV_DEVICEADDED:
221 if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD |
222 SDL_UDEV_DEVICE_TOUCHSCREEN)))
223 return;
224
225 SDL_EVDEV_device_added(dev_path, udev_class);
226 break;
227 case SDL_UDEV_DEVICEREMOVED:
228 SDL_EVDEV_device_removed(dev_path);
229 break;
230 default:
231 break;
232 }
233}
234#endif /* SDL_USE_LIBUDEV */
235
236void
237SDL_EVDEV_Poll(void)
238{
239 struct input_event events[32];
240 int i, j, len;
241 SDL_evdevlist_item *item;
242 SDL_Scancode scan_code;
243 int mouse_button;
244 SDL_Mouse *mouse;
245 float norm_x, norm_y, norm_pressure;
246
247 if (!_this) {
248 return;
249 }
250
251#if SDL_USE_LIBUDEV
252 SDL_UDEV_Poll();
253#endif
254
255 mouse = SDL_GetMouse();
256
257 for (item = _this->first; item != NULL; item = item->next) {
258 while ((len = read(item->fd, events, (sizeof events))) > 0) {
259 len /= sizeof(events[0]);
260 for (i = 0; i < len; ++i) {
261 /* special handling for touchscreen, that should eventually be
262 used for all devices */
263 if (item->out_of_sync && item->is_touchscreen &&
264 events[i].type == EV_SYN && events[i].code != SYN_REPORT) {
265 break;
266 }
267
268 switch (events[i].type) {
269 case EV_KEY:
270 if (events[i].code >= BTN_MOUSE && events[i].code < BTN_MOUSE + SDL_arraysize(EVDEV_MouseButtons)) {
271 mouse_button = events[i].code - BTN_MOUSE;
272 if (events[i].value == 0) {
273 SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, EVDEV_MouseButtons[mouse_button]);
274 } else if (events[i].value == 1) {
275 SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, EVDEV_MouseButtons[mouse_button]);
276 }
277 break;
278 }
279
280 /* BTH_TOUCH event value 1 indicates there is contact with
281 a touchscreen or trackpad (earlist finger's current
282 position is sent in EV_ABS ABS_X/ABS_Y, switching to
283 next finger after earlist is released) */
284 if (item->is_touchscreen && events[i].code == BTN_TOUCH) {
285 if (item->touchscreen_data->max_slots == 1) {
286 if (events[i].value)
287 item->touchscreen_data->slots[0].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
288 else
289 item->touchscreen_data->slots[0].delta = EVDEV_TOUCH_SLOTDELTA_UP;
290 }
291 break;
292 }
293
294 /* Probably keyboard */
295 scan_code = SDL_EVDEV_translate_keycode(events[i].code);
296 if (scan_code != SDL_SCANCODE_UNKNOWN) {
297 if (events[i].value == 0) {
299 } else if (events[i].value == 1 || events[i].value == 2 /* key repeated */) {
301 }
302 }
303 SDL_EVDEV_kbd_keycode(_this->kbd, events[i].code, events[i].value);
304 break;
305 case EV_ABS:
306 switch(events[i].code) {
307 case ABS_MT_SLOT:
308 if (!item->is_touchscreen) /* FIXME: temp hack */
309 break;
310 item->touchscreen_data->current_slot = events[i].value;
311 break;
312 case ABS_MT_TRACKING_ID:
313 if (!item->is_touchscreen) /* FIXME: temp hack */
314 break;
315 if (events[i].value >= 0) {
316 item->touchscreen_data->slots[item->touchscreen_data->current_slot].tracking_id = events[i].value;
317 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
318 } else {
319 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_UP;
320 }
321 break;
322 case ABS_MT_POSITION_X:
323 if (!item->is_touchscreen) /* FIXME: temp hack */
324 break;
325 item->touchscreen_data->slots[item->touchscreen_data->current_slot].x = events[i].value;
326 if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
327 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
328 }
329 break;
330 case ABS_MT_POSITION_Y:
331 if (!item->is_touchscreen) /* FIXME: temp hack */
332 break;
333 item->touchscreen_data->slots[item->touchscreen_data->current_slot].y = events[i].value;
334 if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
335 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
336 }
337 break;
338 case ABS_MT_PRESSURE:
339 if (!item->is_touchscreen) /* FIXME: temp hack */
340 break;
341 item->touchscreen_data->slots[item->touchscreen_data->current_slot].pressure = events[i].value;
342 if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
343 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
344 }
345 break;
346 case ABS_X:
347 if (item->is_touchscreen) {
348 if (item->touchscreen_data->max_slots != 1)
349 break;
350 item->touchscreen_data->slots[0].x = events[i].value;
351 } else
352 SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y);
353 break;
354 case ABS_Y:
355 if (item->is_touchscreen) {
356 if (item->touchscreen_data->max_slots != 1)
357 break;
358 item->touchscreen_data->slots[0].y = events[i].value;
359 } else
360 SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value);
361 break;
362 default:
363 break;
364 }
365 break;
366 case EV_REL:
367 switch(events[i].code) {
368 case REL_X:
369 SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, events[i].value, 0);
370 break;
371 case REL_Y:
372 SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, 0, events[i].value);
373 break;
374 case REL_WHEEL:
375 SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value, SDL_MOUSEWHEEL_NORMAL);
376 break;
377 case REL_HWHEEL:
378 SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0, SDL_MOUSEWHEEL_NORMAL);
379 break;
380 default:
381 break;
382 }
383 break;
384 case EV_SYN:
385 switch (events[i].code) {
386 case SYN_REPORT:
387 if (!item->is_touchscreen) /* FIXME: temp hack */
388 break;
389
390 for(j = 0; j < item->touchscreen_data->max_slots; j++) {
391 norm_x = (float)(item->touchscreen_data->slots[j].x - item->touchscreen_data->min_x) /
392 (float)item->touchscreen_data->range_x;
393 norm_y = (float)(item->touchscreen_data->slots[j].y - item->touchscreen_data->min_y) /
394 (float)item->touchscreen_data->range_y;
395
396 if (item->touchscreen_data->range_pressure > 0) {
397 norm_pressure = (float)(item->touchscreen_data->slots[j].pressure - item->touchscreen_data->min_pressure) /
398 (float)item->touchscreen_data->range_pressure;
399 } else {
400 /* This touchscreen does not support pressure */
401 norm_pressure = 1.0f;
402 }
403
404 switch(item->touchscreen_data->slots[j].delta) {
405 case EVDEV_TOUCH_SLOTDELTA_DOWN:
406 SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_TRUE, norm_x, norm_y, norm_pressure);
407 item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
408 break;
409 case EVDEV_TOUCH_SLOTDELTA_UP:
410 SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_FALSE, norm_x, norm_y, norm_pressure);
411 item->touchscreen_data->slots[j].tracking_id = -1;
412 item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
413 break;
414 case EVDEV_TOUCH_SLOTDELTA_MOVE:
415 SDL_SendTouchMotion(item->fd, item->touchscreen_data->slots[j].tracking_id, norm_x, norm_y, norm_pressure);
416 item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
417 break;
418 default:
419 break;
420 }
421 }
422
423 if (item->out_of_sync)
424 item->out_of_sync = 0;
425 break;
426 case SYN_DROPPED:
427 if (item->is_touchscreen)
428 item->out_of_sync = 1;
429 SDL_EVDEV_sync_device(item);
430 break;
431 default:
432 break;
433 }
434 break;
435 }
436 }
437 }
438 }
439}
440
441static SDL_Scancode
442SDL_EVDEV_translate_keycode(int keycode)
443{
445
446 if (keycode < SDL_arraysize(linux_scancode_table))
447 scancode = linux_scancode_table[keycode];
448
449 if (scancode == SDL_SCANCODE_UNKNOWN) {
450 /* BTN_TOUCH is handled elsewhere, but we might still end up here if
451 you get an unexpected BTN_TOUCH from something SDL believes is not
452 a touch device. In this case, we'd rather not get a misleading
453 SDL_Log message about an unknown key. */
454 if (keycode != BTN_TOUCH) {
455 SDL_Log("The key you just pressed is not recognized by SDL. To help "
456 "get this fixed, please report this to the SDL forums/mailing list "
457 "<https://discourse.libsdl.org/> EVDEV KeyCode %d", keycode);
458 }
459 }
460
461 return scancode;
462}
463
464#ifdef SDL_USE_LIBUDEV
465static int
466SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
467{
468 int ret, i;
469 unsigned long xreq, yreq;
470 char name[64];
471 struct input_absinfo abs_info;
472
473 if (!item->is_touchscreen)
474 return 0;
475
476 item->touchscreen_data = SDL_calloc(1, sizeof(*item->touchscreen_data));
477 if (item->touchscreen_data == NULL)
478 return SDL_OutOfMemory();
479
480 ret = ioctl(item->fd, EVIOCGNAME(sizeof(name)), name);
481 if (ret < 0) {
482 SDL_free(item->touchscreen_data);
483 return SDL_SetError("Failed to get evdev touchscreen name");
484 }
485
486 item->touchscreen_data->name = SDL_strdup(name);
487 if (item->touchscreen_data->name == NULL) {
488 SDL_free(item->touchscreen_data);
489 return SDL_OutOfMemory();
490 }
491
492 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
493 if (ret < 0) {
494 SDL_free(item->touchscreen_data->name);
495 SDL_free(item->touchscreen_data);
496 return SDL_SetError("Failed to get evdev touchscreen limits");
497 }
498
499 if (abs_info.maximum == 0) {
500 item->touchscreen_data->max_slots = 1;
501 xreq = EVIOCGABS(ABS_X);
502 yreq = EVIOCGABS(ABS_Y);
503 } else {
504 item->touchscreen_data->max_slots = abs_info.maximum + 1;
505 xreq = EVIOCGABS(ABS_MT_POSITION_X);
506 yreq = EVIOCGABS(ABS_MT_POSITION_Y);
507 }
508
509 ret = ioctl(item->fd, xreq, &abs_info);
510 if (ret < 0) {
511 SDL_free(item->touchscreen_data->name);
512 SDL_free(item->touchscreen_data);
513 return SDL_SetError("Failed to get evdev touchscreen limits");
514 }
515 item->touchscreen_data->min_x = abs_info.minimum;
516 item->touchscreen_data->max_x = abs_info.maximum;
517 item->touchscreen_data->range_x = abs_info.maximum - abs_info.minimum;
518
519 ret = ioctl(item->fd, yreq, &abs_info);
520 if (ret < 0) {
521 SDL_free(item->touchscreen_data->name);
522 SDL_free(item->touchscreen_data);
523 return SDL_SetError("Failed to get evdev touchscreen limits");
524 }
525 item->touchscreen_data->min_y = abs_info.minimum;
526 item->touchscreen_data->max_y = abs_info.maximum;
527 item->touchscreen_data->range_y = abs_info.maximum - abs_info.minimum;
528
529 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_PRESSURE), &abs_info);
530 if (ret < 0) {
531 SDL_free(item->touchscreen_data->name);
532 SDL_free(item->touchscreen_data);
533 return SDL_SetError("Failed to get evdev touchscreen limits");
534 }
535 item->touchscreen_data->min_pressure = abs_info.minimum;
536 item->touchscreen_data->max_pressure = abs_info.maximum;
537 item->touchscreen_data->range_pressure = abs_info.maximum - abs_info.minimum;
538
539 item->touchscreen_data->slots = SDL_calloc(
540 item->touchscreen_data->max_slots,
541 sizeof(*item->touchscreen_data->slots));
542 if (item->touchscreen_data->slots == NULL) {
543 SDL_free(item->touchscreen_data->name);
544 SDL_free(item->touchscreen_data);
545 return SDL_OutOfMemory();
546 }
547
548 for(i = 0; i < item->touchscreen_data->max_slots; i++) {
549 item->touchscreen_data->slots[i].tracking_id = -1;
550 }
551
552 ret = SDL_AddTouch(item->fd, /* I guess our fd is unique enough */
554 item->touchscreen_data->name);
555 if (ret < 0) {
556 SDL_free(item->touchscreen_data->slots);
557 SDL_free(item->touchscreen_data->name);
558 SDL_free(item->touchscreen_data);
559 return ret;
560 }
561
562 return 0;
563}
564#endif /* SDL_USE_LIBUDEV */
565
566static void
567SDL_EVDEV_destroy_touchscreen(SDL_evdevlist_item* item) {
568 if (!item->is_touchscreen)
569 return;
570
571 SDL_DelTouch(item->fd);
572 SDL_free(item->touchscreen_data->slots);
573 SDL_free(item->touchscreen_data->name);
574 SDL_free(item->touchscreen_data);
575}
576
577static void
578SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
579{
580#ifdef EVIOCGMTSLOTS
581 int i, ret;
582 struct input_absinfo abs_info;
583 /*
584 * struct input_mt_request_layout {
585 * __u32 code;
586 * __s32 values[num_slots];
587 * };
588 *
589 * this is the structure we're trying to emulate
590 */
591 Uint32* mt_req_code;
592 Sint32* mt_req_values;
593 size_t mt_req_size;
594
595 /* TODO: sync devices other than touchscreen */
596 if (!item->is_touchscreen)
597 return;
598
599 mt_req_size = sizeof(*mt_req_code) +
600 sizeof(*mt_req_values) * item->touchscreen_data->max_slots;
601
602 mt_req_code = SDL_calloc(1, mt_req_size);
603 if (mt_req_code == NULL) {
604 return;
605 }
606
607 mt_req_values = (Sint32*)mt_req_code + 1;
608
609 *mt_req_code = ABS_MT_TRACKING_ID;
610 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
611 if (ret < 0) {
612 SDL_free(mt_req_code);
613 return;
614 }
615 for(i = 0; i < item->touchscreen_data->max_slots; i++) {
616 /*
617 * This doesn't account for the very edge case of the user removing their
618 * finger and replacing it on the screen during the time we're out of sync,
619 * which'll mean that we're not going from down -> up or up -> down, we're
620 * going from down -> down but with a different tracking id, meaning we'd
621 * have to tell SDL of the two events, but since we wait till SYN_REPORT in
622 * SDL_EVDEV_Poll to tell SDL, the current structure of this code doesn't
623 * allow it. Lets just pray to God it doesn't happen.
624 */
625 if (item->touchscreen_data->slots[i].tracking_id < 0 &&
626 mt_req_values[i] >= 0) {
627 item->touchscreen_data->slots[i].tracking_id = mt_req_values[i];
628 item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
629 } else if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
630 mt_req_values[i] < 0) {
631 item->touchscreen_data->slots[i].tracking_id = -1;
632 item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_UP;
633 }
634 }
635
636 *mt_req_code = ABS_MT_POSITION_X;
637 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
638 if (ret < 0) {
639 SDL_free(mt_req_code);
640 return;
641 }
642 for(i = 0; i < item->touchscreen_data->max_slots; i++) {
643 if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
644 item->touchscreen_data->slots[i].x != mt_req_values[i]) {
645 item->touchscreen_data->slots[i].x = mt_req_values[i];
646 if (item->touchscreen_data->slots[i].delta ==
647 EVDEV_TOUCH_SLOTDELTA_NONE) {
648 item->touchscreen_data->slots[i].delta =
649 EVDEV_TOUCH_SLOTDELTA_MOVE;
650 }
651 }
652 }
653
654 *mt_req_code = ABS_MT_POSITION_Y;
655 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
656 if (ret < 0) {
657 SDL_free(mt_req_code);
658 return;
659 }
660 for(i = 0; i < item->touchscreen_data->max_slots; i++) {
661 if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
662 item->touchscreen_data->slots[i].y != mt_req_values[i]) {
663 item->touchscreen_data->slots[i].y = mt_req_values[i];
664 if (item->touchscreen_data->slots[i].delta ==
665 EVDEV_TOUCH_SLOTDELTA_NONE) {
666 item->touchscreen_data->slots[i].delta =
667 EVDEV_TOUCH_SLOTDELTA_MOVE;
668 }
669 }
670 }
671
672 *mt_req_code = ABS_MT_PRESSURE;
673 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
674 if (ret < 0) {
675 SDL_free(mt_req_code);
676 return;
677 }
678 for(i = 0; i < item->touchscreen_data->max_slots; i++) {
679 if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
680 item->touchscreen_data->slots[i].pressure != mt_req_values[i]) {
681 item->touchscreen_data->slots[i].pressure = mt_req_values[i];
682 if (item->touchscreen_data->slots[i].delta ==
683 EVDEV_TOUCH_SLOTDELTA_NONE) {
684 item->touchscreen_data->slots[i].delta =
685 EVDEV_TOUCH_SLOTDELTA_MOVE;
686 }
687 }
688 }
689
690 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
691 if (ret < 0) {
692 SDL_free(mt_req_code);
693 return;
694 }
695 item->touchscreen_data->current_slot = abs_info.value;
696
697 SDL_free(mt_req_code);
698
699#endif /* EVIOCGMTSLOTS */
700}
701
702#if SDL_USE_LIBUDEV
703static int
704SDL_EVDEV_device_added(const char *dev_path, int udev_class)
705{
706 int ret;
707 SDL_evdevlist_item *item;
708
709 /* Check to make sure it's not already in list. */
710 for (item = _this->first; item != NULL; item = item->next) {
711 if (SDL_strcmp(dev_path, item->path) == 0) {
712 return -1; /* already have this one */
713 }
714 }
715
716 item = (SDL_evdevlist_item *) SDL_calloc(1, sizeof (SDL_evdevlist_item));
717 if (item == NULL) {
718 return SDL_OutOfMemory();
719 }
720
721 item->fd = open(dev_path, O_RDONLY | O_NONBLOCK);
722 if (item->fd < 0) {
723 SDL_free(item);
724 return SDL_SetError("Unable to open %s", dev_path);
725 }
726
727 item->path = SDL_strdup(dev_path);
728 if (item->path == NULL) {
729 close(item->fd);
730 SDL_free(item);
731 return SDL_OutOfMemory();
732 }
733
734 if (udev_class & SDL_UDEV_DEVICE_TOUCHSCREEN) {
735 item->is_touchscreen = 1;
736
737 if ((ret = SDL_EVDEV_init_touchscreen(item)) < 0) {
738 close(item->fd);
739 SDL_free(item);
740 return ret;
741 }
742 }
743
744 if (_this->last == NULL) {
745 _this->first = _this->last = item;
746 } else {
747 _this->last->next = item;
748 _this->last = item;
749 }
750
751 SDL_EVDEV_sync_device(item);
752
753 return _this->num_devices++;
754}
755#endif /* SDL_USE_LIBUDEV */
756
757static int
758SDL_EVDEV_device_removed(const char *dev_path)
759{
760 SDL_evdevlist_item *item;
761 SDL_evdevlist_item *prev = NULL;
762
763 for (item = _this->first; item != NULL; item = item->next) {
764 /* found it, remove it. */
765 if (SDL_strcmp(dev_path, item->path) == 0) {
766 if (prev != NULL) {
767 prev->next = item->next;
768 } else {
769 SDL_assert(_this->first == item);
770 _this->first = item->next;
771 }
772 if (item == _this->last) {
773 _this->last = prev;
774 }
775 if (item->is_touchscreen) {
776 SDL_EVDEV_destroy_touchscreen(item);
777 }
778 close(item->fd);
779 SDL_free(item->path);
780 SDL_free(item);
781 _this->num_devices--;
782 return 0;
783 }
784 prev = item;
785 }
786
787 return -1;
788}
789
790
791#endif /* SDL_INPUT_LINUXEV */
792
793/* vi: set ts=4 sw=4 expandtab: */
#define _THIS
#define SDL_assert(condition)
Definition: SDL_assert.h:169
#define SDL_SetError
#define SDL_free
#define SDL_strdup
#define SDL_strcmp
#define SDL_Log
#define SDL_calloc
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
void SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state)
void SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down)
SDL_EVDEV_keyboard_state * SDL_EVDEV_kbd_init(void)
struct SDL_EVDEV_keyboard_state SDL_EVDEV_keyboard_state
Definition: SDL_evdev_kbd.h:26
#define SDL_RELEASED
Definition: SDL_events.h:49
#define SDL_PRESSED
Definition: SDL_events.h:50
int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
Definition: SDL_keyboard.c:679
int SDL_SendMouseButton(SDL_Window *window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
Definition: SDL_mouse.c:605
SDL_Mouse * SDL_GetMouse(void)
Definition: SDL_mouse.c:178
int SDL_SendMouseWheel(SDL_Window *window, SDL_MouseID mouseID, float x, float y, SDL_MouseWheelDirection direction)
Definition: SDL_mouse.c:611
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
Definition: SDL_mouse.c:301
#define SDL_BUTTON_X1
Definition: SDL_mouse.h:285
#define SDL_BUTTON_X2
Definition: SDL_mouse.h:286
#define SDL_BUTTON_MIDDLE
Definition: SDL_mouse.h:283
#define SDL_BUTTON_RIGHT
Definition: SDL_mouse.h:284
#define SDL_BUTTON_LEFT
Definition: SDL_mouse.h:282
@ SDL_MOUSEWHEEL_NORMAL
Definition: SDL_mouse.h:68
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLenum GLsizei len
GLuint const GLchar * name
GLsizei const GLchar *const * path
GLsizei const GLfloat * value
const GLint * first
SDL_Scancode
The SDL keyboard scancode representation.
Definition: SDL_scancode.h:44
@ SDL_SCANCODE_UNKNOWN
Definition: SDL_scancode.h:45
SDL_bool
Definition: SDL_stdinc.h:162
@ SDL_TRUE
Definition: SDL_stdinc.h:164
@ SDL_FALSE
Definition: SDL_stdinc.h:163
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:115
uint32_t Uint32
Definition: SDL_stdinc.h:203
int32_t Sint32
Definition: SDL_stdinc.h:197
uint8_t Uint8
Definition: SDL_stdinc.h:179
void SDL_DelTouch(SDL_TouchID id)
Definition: SDL_touch.c:449
int SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_bool down, float x, float y, float pressure)
Definition: SDL_touch.c:242
int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, float x, float y, float pressure)
Definition: SDL_touch.c:364
int SDL_AddTouch(SDL_TouchID touchID, SDL_TouchDeviceType type, const char *name)
Definition: SDL_touch.c:155
@ SDL_TOUCH_DEVICE_DIRECT
Definition: SDL_touch.h:47
static SDL_VideoDevice * _this
Definition: SDL_video.c:118
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int int in j)
Definition: SDL_x11sym.h:50
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:167
EGLDeviceEXT EGLint * num_devices
Definition: eglext.h:621
GLuint64 GLenum GLint fd
Definition: gl2ext.h:1508
static SDL_Scancode const linux_scancode_table[]
int(* SetRelativeMouseMode)(SDL_bool enabled)
Definition: SDL_mouse_c.h:67
SDL_MouseID mouseID
Definition: SDL_mouse_c.h:76
SDL_Window * focus
Definition: SDL_mouse_c.h:77
static SDL_Event events[EVENT_BUF_SIZE]
Definition: testgesture.c:39
Uint32 type
Definition: SDL_events.h:559