Skip to content

Latest commit

 

History

History
873 lines (750 loc) · 28.8 KB

SDL_evdev.c

File metadata and controls

873 lines (750 loc) · 28.8 KB
 
1
2
/*
Simple DirectMedia Layer
Jan 2, 2016
Jan 2, 2016
3
Copyright (C) 1997-2016 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>
Oct 1, 2016
Oct 1, 2016
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"
Oct 1, 2016
Oct 1, 2016
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
Oct 1, 2016
Oct 1, 2016
60
61
62
63
64
65
66
67
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
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;
int kb_mode;
} SDL_EVDEV_PrivateData;
#define _THIS SDL_EVDEV_PrivateData *_this
static _THIS = NULL;
108
109
static SDL_Scancode SDL_EVDEV_translate_keycode(int keycode);
static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item);
Oct 1, 2016
Oct 1, 2016
110
static int SDL_EVDEV_device_removed(const char *dev_path);
111
112
#if SDL_USE_LIBUDEV
Oct 1, 2016
Oct 1, 2016
113
114
115
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);
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#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 */
};
static const char* EVDEV_consoles[] = {
Oct 1, 2016
Oct 1, 2016
130
/* "/proc/self/fd/0",
Oct 1, 2016
Oct 1, 2016
132
"/dev/tty0", */ /* the tty ioctl's prohibit these */
133
134
135
136
137
138
"/dev/tty1",
"/dev/tty2",
"/dev/tty3",
"/dev/tty4",
"/dev/tty5",
"/dev/tty6",
Oct 1, 2016
Oct 1, 2016
139
"/dev/tty7", /* usually X is spawned in tty7 */
140
141
142
143
"/dev/vc/0",
"/dev/console"
};
Oct 1, 2016
Oct 1, 2016
144
static int SDL_EVDEV_is_console(int fd) {
Oct 1, 2016
Oct 1, 2016
145
int type;
Oct 1, 2016
Oct 1, 2016
147
148
return isatty(fd) && ioctl(fd, KDGKBTYPE, &type) == 0 &&
(type == KB_101 || type == KB_84);
149
150
151
}
/* Prevent keystrokes from reaching the tty */
Oct 1, 2016
Oct 1, 2016
152
static int SDL_EVDEV_mute_keyboard(int tty_fd, int* old_kb_mode)
Oct 1, 2016
Oct 1, 2016
154
155
if (!SDL_EVDEV_is_console(tty_fd)) {
return SDL_SetError("Tried to mute an invalid tty");
Oct 1, 2016
Oct 1, 2016
156
}
Oct 1, 2016
Oct 1, 2016
158
159
if (ioctl(tty_fd, KDGKBMODE, old_kb_mode) < 0) {
return SDL_SetError("Failed to get keyboard mode during muting");
Oct 1, 2016
Oct 1, 2016
161
162
163
164
/* FIXME: atm this absolutely ruins the vt, and KDSKBMUTE isn't implemented
in the kernel */
/*
Oct 1, 2016
Oct 1, 2016
165
166
if (ioctl(tty_fd, KDSKBMODE, K_OFF) < 0) {
return SDL_SetError("Failed to set keyboard mode during muting");
Oct 1, 2016
Oct 1, 2016
168
*/
169
170
171
172
173
return 0;
}
/* Restore the keyboard mode for given tty */
Oct 1, 2016
Oct 1, 2016
174
static void SDL_EVDEV_unmute_keyboard(int tty_fd, int kb_mode)
Oct 1, 2016
Oct 1, 2016
176
177
/* read above */
/*
Oct 1, 2016
Oct 1, 2016
178
179
if (ioctl(tty_fd, KDSKBMODE, kb_mode) < 0) {
SDL_Log("Failed to unmute keyboard");
Oct 1, 2016
Oct 1, 2016
181
*/
182
183
184
}
static int SDL_EVDEV_get_active_tty()
Oct 1, 2016
Oct 1, 2016
185
186
187
188
189
{
int i, fd, ret, tty = 0;
char tiocl;
struct vt_stat vt_state;
char path[PATH_MAX + 1];
Oct 1, 2016
Oct 1, 2016
191
192
for(i = 0; i < SDL_arraysize(EVDEV_consoles); i++) {
fd = open(EVDEV_consoles[i], O_RDONLY);
Oct 1, 2016
Oct 1, 2016
193
Oct 1, 2016
Oct 1, 2016
194
if (fd < 0 && !SDL_EVDEV_is_console(fd))
Oct 1, 2016
Oct 1, 2016
195
196
197
break;
tiocl = TIOCL_GETFGCONSOLE;
Oct 1, 2016
Oct 1, 2016
198
if ((ret = ioctl(fd, TIOCLINUX, &tiocl)) >= 0)
Oct 1, 2016
Oct 1, 2016
199
tty = ret + 1;
Oct 1, 2016
Oct 1, 2016
200
else if (ioctl(fd, VT_GETSTATE, &vt_state) == 0)
Oct 1, 2016
Oct 1, 2016
201
202
tty = vt_state.v_active;
Oct 1, 2016
Oct 1, 2016
203
close(fd);
Oct 1, 2016
Oct 1, 2016
204
Oct 1, 2016
Oct 1, 2016
205
206
207
208
if (tty) {
sprintf(path, "/dev/tty%u", tty);
fd = open(path, O_RDONLY);
if (fd >= 0 && SDL_EVDEV_is_console(fd))
Oct 1, 2016
Oct 1, 2016
209
210
return fd;
}
Oct 1, 2016
Oct 1, 2016
213
return SDL_SetError("Failed to determine active tty");
214
215
216
217
218
}
int
SDL_EVDEV_Init(void)
{
Oct 1, 2016
Oct 1, 2016
219
220
221
if (_this == NULL) {
_this = (SDL_EVDEV_PrivateData*)SDL_calloc(1, sizeof(*_this));
if (_this == NULL) {
222
223
224
225
return SDL_OutOfMemory();
}
#if SDL_USE_LIBUDEV
Oct 1, 2016
Oct 1, 2016
226
227
if (SDL_UDEV_Init() < 0) {
SDL_free(_this);
228
229
230
231
232
_this = NULL;
return -1;
}
/* Set up the udev callback */
Jun 25, 2015
Jun 25, 2015
233
if (SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) {
Oct 1, 2016
Oct 1, 2016
234
SDL_UDEV_Quit();
Oct 1, 2016
Oct 1, 2016
235
SDL_free(_this);
Oct 1, 2016
Oct 1, 2016
236
_this = NULL;
237
238
239
240
241
242
243
244
245
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 */
Oct 1, 2016
Oct 1, 2016
246
247
248
/* We need a physical terminal (not PTS) to be able to translate key
code to symbols via the kernel tables */
_this->console_fd = SDL_EVDEV_get_active_tty();
Oct 1, 2016
Oct 1, 2016
250
251
/* Mute the keyboard so keystrokes only generate evdev events and do not
leak through to the console */
Oct 1, 2016
Oct 1, 2016
252
SDL_EVDEV_mute_keyboard(_this->console_fd, &_this->kb_mode);
253
254
255
256
}
_this->ref_count += 1;
Oct 1, 2016
Oct 1, 2016
257
return 0;
258
259
260
261
262
}
void
SDL_EVDEV_Quit(void)
{
Oct 1, 2016
Oct 1, 2016
263
if (_this == NULL) {
264
265
266
267
268
return;
}
_this->ref_count -= 1;
Oct 1, 2016
Oct 1, 2016
269
if (_this->ref_count < 1) {
Oct 1, 2016
Oct 1, 2016
271
SDL_UDEV_DelCallback(SDL_EVDEV_udev_callback);
272
273
274
SDL_UDEV_Quit();
#endif /* SDL_USE_LIBUDEV */
Oct 1, 2016
Oct 1, 2016
275
276
277
if (_this->console_fd >= 0) {
SDL_EVDEV_unmute_keyboard(_this->console_fd, _this->kb_mode);
close(_this->console_fd);
278
279
280
281
}
/* Remove existing devices */
while(_this->first != NULL) {
Oct 1, 2016
Oct 1, 2016
282
SDL_EVDEV_device_removed(_this->first->path);
Oct 1, 2016
Oct 1, 2016
285
286
287
SDL_assert(_this->first == NULL);
SDL_assert(_this->last == NULL);
SDL_assert(_this->num_devices == 0);
Oct 1, 2016
Oct 1, 2016
289
SDL_free(_this);
290
291
292
293
294
_this = NULL;
}
}
#if SDL_USE_LIBUDEV
Oct 1, 2016
Oct 1, 2016
295
296
void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event, int udev_class,
const char* dev_path)
Oct 1, 2016
Oct 1, 2016
298
if (dev_path == NULL) {
Oct 1, 2016
Oct 1, 2016
302
switch(udev_event) {
303
case SDL_UDEV_DEVICEADDED:
Oct 1, 2016
Oct 1, 2016
304
305
if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD |
SDL_UDEV_DEVICE_TOUCHSCREEN)))
Jun 25, 2015
Jun 25, 2015
306
return;
Oct 1, 2016
Oct 1, 2016
307
Oct 1, 2016
Oct 1, 2016
308
SDL_EVDEV_device_added(dev_path, udev_class);
Oct 1, 2016
Oct 1, 2016
309
break;
310
case SDL_UDEV_DEVICEREMOVED:
Oct 1, 2016
Oct 1, 2016
311
SDL_EVDEV_device_removed(dev_path);
312
313
314
315
316
317
318
break;
default:
break;
}
}
#endif /* SDL_USE_LIBUDEV */
Oct 1, 2016
Oct 1, 2016
319
320
321
#ifdef SDL_INPUT_LINUXKD
/* this logic is pulled from kbd_keycode() in drivers/tty/vt/keyboard.c in the
Linux kernel source */
Oct 1, 2016
Oct 1, 2016
322
static void SDL_EVDEV_do_text_input(unsigned short keycode) {
Oct 1, 2016
Oct 1, 2016
323
324
325
326
327
328
char shift_state;
int locks_state;
struct kbentry kbe;
unsigned char type;
char text[2] = { 0 };
Oct 1, 2016
Oct 1, 2016
329
if (_this->console_fd < 0)
Oct 1, 2016
Oct 1, 2016
330
331
332
return;
shift_state = TIOCL_GETSHIFTSTATE;
Oct 1, 2016
Oct 1, 2016
333
if (ioctl(_this->console_fd, TIOCLINUX, &shift_state) < 0) {
Oct 1, 2016
Oct 1, 2016
334
335
336
337
338
339
340
/* TODO: error */
return;
}
kbe.kb_table = shift_state;
kbe.kb_index = keycode;
Oct 1, 2016
Oct 1, 2016
341
if (ioctl(_this->console_fd, KDGKBENT, &kbe) < 0) {
Oct 1, 2016
Oct 1, 2016
342
343
344
345
/* TODO: error */
return;
}
Oct 1, 2016
Oct 1, 2016
346
type = KTYP(kbe.kb_value);
Oct 1, 2016
Oct 1, 2016
347
Oct 1, 2016
Oct 1, 2016
348
if (type < 0xf0) {
Oct 1, 2016
Oct 1, 2016
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
/*
* 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 */
Oct 1, 2016
Oct 1, 2016
368
if (type == KT_LETTER) {
Oct 1, 2016
Oct 1, 2016
369
370
type = KT_LATIN;
Oct 1, 2016
Oct 1, 2016
371
if (ioctl(_this->console_fd, KDGKBLED, &locks_state) < 0) {
Oct 1, 2016
Oct 1, 2016
372
373
374
375
/* TODO: error */
return;
}
Oct 1, 2016
Oct 1, 2016
376
377
if (locks_state & K_CAPSLOCK) {
kbe.kb_table = shift_state ^ (1 << KG_SHIFT);
Oct 1, 2016
Oct 1, 2016
378
Oct 1, 2016
Oct 1, 2016
379
if (ioctl(_this->console_fd, KDGKBENT, &kbe) < 0) {
Oct 1, 2016
Oct 1, 2016
380
381
382
383
384
385
386
/* TODO: error */
return;
}
}
}
/* TODO: convert values >= 0x80 from ISO-8859-1? to UTF-8 */
Oct 1, 2016
Oct 1, 2016
387
if (type != KT_LATIN || KVAL(kbe.kb_value) >= 0x80)
Oct 1, 2016
Oct 1, 2016
388
389
return;
Oct 1, 2016
Oct 1, 2016
390
391
*text = KVAL(kbe.kb_value);
SDL_SendKeyboardText(text);
Oct 1, 2016
Oct 1, 2016
392
393
394
}
#endif /* SDL_INPUT_LINUXKD */
395
396
397
398
void
SDL_EVDEV_Poll(void)
{
struct input_event events[32];
Oct 1, 2016
Oct 1, 2016
399
int i, j, len;
400
401
402
403
SDL_evdevlist_item *item;
SDL_Scancode scan_code;
int mouse_button;
SDL_Mouse *mouse;
Oct 1, 2016
Oct 1, 2016
404
float norm_x, norm_y;
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
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) {
Oct 1, 2016
Oct 1, 2016
420
421
/* special handling for touchscreen, that should eventually be
used for all devices */
Oct 1, 2016
Oct 1, 2016
422
423
if (item->out_of_sync && item->is_touchscreen &&
events[i].type == EV_SYN && events[i].code != SYN_REPORT) {
Oct 1, 2016
Oct 1, 2016
424
425
426
break;
}
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
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);
Oct 1, 2016
Oct 1, 2016
444
} else if (events[i].value == 1 || events[i].value == 2 /* key repeated */) {
445
446
SDL_SendKeyboardKey(SDL_PRESSED, scan_code);
#ifdef SDL_INPUT_LINUXKD
Oct 1, 2016
Oct 1, 2016
447
SDL_EVDEV_do_text_input(events[i].code);
448
449
450
451
452
453
#endif /* SDL_INPUT_LINUXKD */
}
}
break;
case EV_ABS:
switch(events[i].code) {
Oct 1, 2016
Oct 1, 2016
454
case ABS_MT_SLOT:
Oct 1, 2016
Oct 1, 2016
455
if (!item->is_touchscreen) /* FIXME: temp hack */
Oct 1, 2016
Oct 1, 2016
456
457
458
459
break;
item->touchscreen_data->current_slot = events[i].value;
break;
case ABS_MT_TRACKING_ID:
Oct 1, 2016
Oct 1, 2016
460
if (!item->is_touchscreen) /* FIXME: temp hack */
Oct 1, 2016
Oct 1, 2016
461
break;
Oct 1, 2016
Oct 1, 2016
462
if (events[i].value >= 0) {
Oct 1, 2016
Oct 1, 2016
463
464
465
466
467
468
469
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:
Oct 1, 2016
Oct 1, 2016
470
if (!item->is_touchscreen) /* FIXME: temp hack */
Oct 1, 2016
Oct 1, 2016
471
472
break;
item->touchscreen_data->slots[item->touchscreen_data->current_slot].x = events[i].value;
Oct 1, 2016
Oct 1, 2016
473
if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
Oct 1, 2016
Oct 1, 2016
474
475
476
477
item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
}
break;
case ABS_MT_POSITION_Y:
Oct 1, 2016
Oct 1, 2016
478
if (!item->is_touchscreen) /* FIXME: temp hack */
Oct 1, 2016
Oct 1, 2016
479
480
break;
item->touchscreen_data->slots[item->touchscreen_data->current_slot].y = events[i].value;
Oct 1, 2016
Oct 1, 2016
481
if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
Oct 1, 2016
Oct 1, 2016
482
483
484
item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
}
break;
Oct 1, 2016
Oct 1, 2016
486
if (item->is_touchscreen) /* FIXME: temp hack */
Oct 1, 2016
Oct 1, 2016
487
break;
488
489
490
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y);
break;
case ABS_Y:
Oct 1, 2016
Oct 1, 2016
491
if (item->is_touchscreen) /* FIXME: temp hack */
Oct 1, 2016
Oct 1, 2016
492
break;
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
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) {
Oct 1, 2016
Oct 1, 2016
519
case SYN_REPORT:
Oct 1, 2016
Oct 1, 2016
520
if (!item->is_touchscreen) /* FIXME: temp hack */
Oct 1, 2016
Oct 1, 2016
521
522
break;
Oct 1, 2016
Oct 1, 2016
523
for(j = 0; j < item->touchscreen_data->max_slots; j++) {
Oct 1, 2016
Oct 1, 2016
524
525
526
527
528
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;
Oct 1, 2016
Oct 1, 2016
529
switch(item->touchscreen_data->slots[j].delta) {
Oct 1, 2016
Oct 1, 2016
530
case EVDEV_TOUCH_SLOTDELTA_DOWN:
Oct 1, 2016
Oct 1, 2016
531
SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_TRUE, norm_x, norm_y, 1.0f);
Oct 1, 2016
Oct 1, 2016
532
533
534
item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
break;
case EVDEV_TOUCH_SLOTDELTA_UP:
Oct 1, 2016
Oct 1, 2016
535
SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_FALSE, norm_x, norm_y, 1.0f);
Oct 1, 2016
Oct 1, 2016
536
537
538
539
item->touchscreen_data->slots[j].tracking_id = -1;
item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
break;
case EVDEV_TOUCH_SLOTDELTA_MOVE:
Oct 1, 2016
Oct 1, 2016
540
SDL_SendTouchMotion(item->fd, item->touchscreen_data->slots[j].tracking_id, norm_x, norm_y, 1.0f);
Oct 1, 2016
Oct 1, 2016
541
542
543
544
545
546
547
item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
break;
default:
break;
}
}
Oct 1, 2016
Oct 1, 2016
548
if (item->out_of_sync)
Oct 1, 2016
Oct 1, 2016
549
550
item->out_of_sync = 0;
break;
Oct 1, 2016
Oct 1, 2016
552
if (item->is_touchscreen)
Oct 1, 2016
Oct 1, 2016
553
item->out_of_sync = 1;
554
555
556
557
558
559
560
561
562
563
564
565
566
SDL_EVDEV_sync_device(item);
break;
default:
break;
}
break;
}
}
}
}
}
static SDL_Scancode
Oct 1, 2016
Oct 1, 2016
567
SDL_EVDEV_translate_keycode(int keycode)
568
569
570
{
SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
Oct 1, 2016
Oct 1, 2016
571
if (keycode < SDL_arraysize(linux_scancode_table))
Oct 1, 2016
Oct 1, 2016
572
573
scancode = linux_scancode_table[keycode];
Oct 1, 2016
Oct 1, 2016
574
575
if (scancode == SDL_SCANCODE_UNKNOWN) {
SDL_Log("The key you just pressed is not recognized by SDL. To help "
Oct 1, 2016
Oct 1, 2016
576
"get this fixed, please report this to the SDL mailing list "
Oct 1, 2016
Oct 1, 2016
577
"<sdl@libsdl.org> EVDEV KeyCode %d\n", keycode);
Oct 1, 2016
Oct 1, 2016
579
580
581
582
return scancode;
}
Oct 1, 2016
Oct 1, 2016
583
#ifdef SDL_USE_LIBUDEV
Oct 1, 2016
Oct 1, 2016
584
static int
Oct 1, 2016
Oct 1, 2016
585
586
SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
{
Oct 1, 2016
Oct 1, 2016
587
588
589
590
int ret, i;
char name[64];
struct input_absinfo abs_info;
Oct 1, 2016
Oct 1, 2016
591
if (!item->is_touchscreen)
Oct 1, 2016
Oct 1, 2016
592
593
return 0;
Oct 1, 2016
Oct 1, 2016
594
595
item->touchscreen_data = SDL_calloc(1, sizeof(*item->touchscreen_data));
if (item->touchscreen_data == NULL)
Oct 1, 2016
Oct 1, 2016
596
597
return SDL_OutOfMemory();
Oct 1, 2016
Oct 1, 2016
598
599
600
601
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");
Oct 1, 2016
Oct 1, 2016
602
603
}
Oct 1, 2016
Oct 1, 2016
604
605
606
item->touchscreen_data->name = SDL_strdup(name);
if (item->touchscreen_data->name == NULL) {
SDL_free(item->touchscreen_data);
Oct 1, 2016
Oct 1, 2016
607
608
609
return SDL_OutOfMemory();
}
Oct 1, 2016
Oct 1, 2016
610
611
612
613
614
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");
Oct 1, 2016
Oct 1, 2016
615
616
617
618
619
}
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;
Oct 1, 2016
Oct 1, 2016
620
621
622
623
624
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");
Oct 1, 2016
Oct 1, 2016
625
626
627
628
629
}
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;
Oct 1, 2016
Oct 1, 2016
630
631
632
633
634
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");
Oct 1, 2016
Oct 1, 2016
635
636
637
638
639
}
item->touchscreen_data->max_slots = abs_info.maximum + 1;
item->touchscreen_data->slots = SDL_calloc(
item->touchscreen_data->max_slots,
Oct 1, 2016
Oct 1, 2016
640
641
642
643
sizeof(*item->touchscreen_data->slots));
if (item->touchscreen_data->slots == NULL) {
SDL_free(item->touchscreen_data->name);
SDL_free(item->touchscreen_data);
Oct 1, 2016
Oct 1, 2016
644
645
646
return SDL_OutOfMemory();
}
Oct 1, 2016
Oct 1, 2016
647
for(i = 0; i < item->touchscreen_data->max_slots; i++) {
Oct 1, 2016
Oct 1, 2016
648
649
650
item->touchscreen_data->slots[i].tracking_id = -1;
}
Oct 1, 2016
Oct 1, 2016
651
652
653
654
655
656
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);
Oct 1, 2016
Oct 1, 2016
657
658
659
660
661
return ret;
}
return 0;
}
Oct 1, 2016
Oct 1, 2016
662
#endif /* SDL_USE_LIBUDEV */
Oct 1, 2016
Oct 1, 2016
663
664
static void
Oct 1, 2016
Oct 1, 2016
665
666
SDL_EVDEV_destroy_touchscreen(SDL_evdevlist_item* item) {
if (!item->is_touchscreen)
Oct 1, 2016
Oct 1, 2016
667
668
return;
Oct 1, 2016
Oct 1, 2016
669
670
671
672
SDL_DelTouch(item->fd);
SDL_free(item->touchscreen_data->slots);
SDL_free(item->touchscreen_data->name);
SDL_free(item->touchscreen_data);
Oct 1, 2016
Oct 1, 2016
673
674
}
675
676
677
static void
SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
{
Oct 1, 2016
Oct 1, 2016
678
#ifdef EVIOCGMTSLOTS
Oct 1, 2016
Oct 1, 2016
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
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 */
Oct 1, 2016
Oct 1, 2016
694
if (!item->is_touchscreen)
Oct 1, 2016
Oct 1, 2016
695
696
return;
Oct 1, 2016
Oct 1, 2016
697
698
mt_req_size = sizeof(*mt_req_code) +
sizeof(*mt_req_values) * item->touchscreen_data->max_slots;
Oct 1, 2016
Oct 1, 2016
699
Oct 1, 2016
Oct 1, 2016
700
701
mt_req_code = SDL_calloc(1, mt_req_size);
if (mt_req_code == NULL) {
Oct 1, 2016
Oct 1, 2016
702
703
704
705
706
707
return;
}
mt_req_values = (__s32*)mt_req_code + 1;
*mt_req_code = ABS_MT_TRACKING_ID;
Oct 1, 2016
Oct 1, 2016
708
709
710
ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
if (ret < 0) {
SDL_free(mt_req_code);
Oct 1, 2016
Oct 1, 2016
711
712
return;
}
Oct 1, 2016
Oct 1, 2016
713
for(i = 0; i < item->touchscreen_data->max_slots; i++) {
Oct 1, 2016
Oct 1, 2016
714
715
716
717
718
719
720
721
722
/*
* 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.
*/
Oct 1, 2016
Oct 1, 2016
723
724
if (item->touchscreen_data->slots[i].tracking_id < 0 &&
mt_req_values[i] >= 0) {
Oct 1, 2016
Oct 1, 2016
725
726
item->touchscreen_data->slots[i].tracking_id = mt_req_values[i];
item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
Oct 1, 2016
Oct 1, 2016
727
728
} else if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
mt_req_values[i] < 0) {
Oct 1, 2016
Oct 1, 2016
729
730
731
732
733
734
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;
Oct 1, 2016
Oct 1, 2016
735
736
737
ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
if (ret < 0) {
SDL_free(mt_req_code);
Oct 1, 2016
Oct 1, 2016
738
739
return;
}
Oct 1, 2016
Oct 1, 2016
740
741
742
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]) {
Oct 1, 2016
Oct 1, 2016
743
item->touchscreen_data->slots[i].x = mt_req_values[i];
Oct 1, 2016
Oct 1, 2016
744
745
if (item->touchscreen_data->slots[i].delta ==
EVDEV_TOUCH_SLOTDELTA_NONE) {
Oct 1, 2016
Oct 1, 2016
746
747
748
749
750
751
752
item->touchscreen_data->slots[i].delta =
EVDEV_TOUCH_SLOTDELTA_MOVE;
}
}
}
*mt_req_code = ABS_MT_POSITION_Y;
Oct 1, 2016
Oct 1, 2016
753
754
755
ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
if (ret < 0) {
SDL_free(mt_req_code);
Oct 1, 2016
Oct 1, 2016
756
757
return;
}
Oct 1, 2016
Oct 1, 2016
758
759
760
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]) {
Oct 1, 2016
Oct 1, 2016
761
item->touchscreen_data->slots[i].y = mt_req_values[i];
Oct 1, 2016
Oct 1, 2016
762
763
if (item->touchscreen_data->slots[i].delta ==
EVDEV_TOUCH_SLOTDELTA_NONE) {
Oct 1, 2016
Oct 1, 2016
764
765
766
767
768
769
item->touchscreen_data->slots[i].delta =
EVDEV_TOUCH_SLOTDELTA_MOVE;
}
}
}
Oct 1, 2016
Oct 1, 2016
770
771
772
ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
if (ret < 0) {
SDL_free(mt_req_code);
Oct 1, 2016
Oct 1, 2016
773
774
775
776
return;
}
item->touchscreen_data->current_slot = abs_info.value;
Oct 1, 2016
Oct 1, 2016
777
SDL_free(mt_req_code);
Oct 1, 2016
Oct 1, 2016
778
779
#endif /* EVIOCGMTSLOTS */
780
781
782
783
}
#if SDL_USE_LIBUDEV
static int
Oct 1, 2016
Oct 1, 2016
784
SDL_EVDEV_device_added(const char *dev_path, int udev_class)
Oct 1, 2016
Oct 1, 2016
786
int ret;
787
788
789
790
SDL_evdevlist_item *item;
/* Check to make sure it's not already in list. */
for (item = _this->first; item != NULL; item = item->next) {
Oct 1, 2016
Oct 1, 2016
791
if (SDL_strcmp(dev_path, item->path) == 0) {
792
793
794
795
796
797
798
799
800
return -1; /* already have this one */
}
}
item = (SDL_evdevlist_item *) SDL_calloc(1, sizeof (SDL_evdevlist_item));
if (item == NULL) {
return SDL_OutOfMemory();
}
Oct 1, 2016
Oct 1, 2016
801
item->fd = open(dev_path, O_RDONLY | O_NONBLOCK);
802
803
if (item->fd < 0) {
SDL_free(item);
Oct 1, 2016
Oct 1, 2016
804
return SDL_SetError("Unable to open %s", dev_path);
Oct 1, 2016
Oct 1, 2016
807
item->path = SDL_strdup(dev_path);
808
809
810
811
812
813
if (item->path == NULL) {
close(item->fd);
SDL_free(item);
return SDL_OutOfMemory();
}
Oct 1, 2016
Oct 1, 2016
814
if (udev_class & SDL_UDEV_DEVICE_TOUCHSCREEN) {
Oct 1, 2016
Oct 1, 2016
815
816
item->is_touchscreen = 1;
Oct 1, 2016
Oct 1, 2016
817
if ((ret = SDL_EVDEV_init_touchscreen(item)) < 0) {
Oct 1, 2016
Oct 1, 2016
818
819
820
821
822
close(item->fd);
SDL_free(item);
return ret;
}
}
823
824
825
826
827
828
829
830
831
832
if (_this->last == NULL) {
_this->first = _this->last = item;
} else {
_this->last->next = item;
_this->last = item;
}
SDL_EVDEV_sync_device(item);
Oct 1, 2016
Oct 1, 2016
833
return _this->num_devices++;
834
835
836
837
}
#endif /* SDL_USE_LIBUDEV */
static int
Oct 1, 2016
Oct 1, 2016
838
SDL_EVDEV_device_removed(const char *dev_path)
839
840
841
842
843
844
{
SDL_evdevlist_item *item;
SDL_evdevlist_item *prev = NULL;
for (item = _this->first; item != NULL; item = item->next) {
/* found it, remove it. */
Oct 1, 2016
Oct 1, 2016
845
if (SDL_strcmp(dev_path, item->path) == 0) {
846
847
848
849
850
851
852
853
854
if (prev != NULL) {
prev->next = item->next;
} else {
SDL_assert(_this->first == item);
_this->first = item->next;
}
if (item == _this->last) {
_this->last = prev;
}
Oct 1, 2016
Oct 1, 2016
855
856
if (item->is_touchscreen) {
SDL_EVDEV_destroy_touchscreen(item);
Oct 1, 2016
Oct 1, 2016
857
}
858
859
860
close(item->fd);
SDL_free(item->path);
SDL_free(item);
Oct 1, 2016
Oct 1, 2016
861
_this->num_devices--;
862
863
864
865
866
867
868
869
870
871
872
873
return 0;
}
prev = item;
}
return -1;
}
#endif /* SDL_INPUT_LINUXEV */
/* vi: set ts=4 sw=4 expandtab: */