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