Skip to content

Latest commit

 

History

History
830 lines (715 loc) · 27.7 KB

SDL_evdev.c

File metadata and controls

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