2015-06-21 17:33:46 +02:00
|
|
|
/*
|
|
|
|
Simple DirectMedia Layer
|
2017-01-02 03:33:28 +01:00
|
|
|
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
2015-06-21 17:33:46 +02:00
|
|
|
|
|
|
|
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>
|
2016-10-01 22:51:56 +02:00
|
|
|
#include <linux/vt.h>
|
|
|
|
#include <linux/tiocl.h> /* for TIOCL_GETSHIFTSTATE */
|
2015-06-21 17:33:46 +02:00
|
|
|
#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"
|
2016-10-01 22:51:56 +02:00
|
|
|
#include "../../events/scancodes_linux.h" /* adds linux_scancode_table */
|
2015-06-21 17:33:46 +02:00
|
|
|
|
2017-01-08 19:15:22 +01:00
|
|
|
/* These are not defined in older Linux kernel headers */
|
2015-06-21 17:33:46 +02:00
|
|
|
#ifndef SYN_DROPPED
|
|
|
|
#define SYN_DROPPED 3
|
|
|
|
#endif
|
2016-11-01 18:33:44 +01:00
|
|
|
#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
|
2017-01-08 19:15:22 +01:00
|
|
|
#ifndef K_OFF
|
|
|
|
#define K_OFF 0x04
|
|
|
|
#endif
|
2016-11-01 18:33:44 +01:00
|
|
|
|
2016-10-01 22:51:56 +02:00
|
|
|
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;
|
2017-01-07 19:13:04 +01:00
|
|
|
int old_kb_mode;
|
2016-10-01 22:51:56 +02:00
|
|
|
} SDL_EVDEV_PrivateData;
|
|
|
|
|
|
|
|
#define _THIS SDL_EVDEV_PrivateData *_this
|
|
|
|
static _THIS = NULL;
|
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
static SDL_Scancode SDL_EVDEV_translate_keycode(int keycode);
|
|
|
|
static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item);
|
2016-10-01 22:51:56 +02:00
|
|
|
static int SDL_EVDEV_device_removed(const char *dev_path);
|
2015-06-21 17:33:46 +02:00
|
|
|
|
|
|
|
#if SDL_USE_LIBUDEV
|
2016-10-01 23:56:53 +02:00
|
|
|
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);
|
2015-06-21 17:33:46 +02:00
|
|
|
#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 */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Prevent keystrokes from reaching the tty */
|
2016-10-01 23:56:53 +02:00
|
|
|
static int SDL_EVDEV_mute_keyboard(int tty_fd, int* old_kb_mode)
|
2015-06-21 17:33:46 +02:00
|
|
|
{
|
2016-10-01 23:56:53 +02:00
|
|
|
if (ioctl(tty_fd, KDGKBMODE, old_kb_mode) < 0) {
|
|
|
|
return SDL_SetError("Failed to get keyboard mode during muting");
|
2015-06-21 17:33:46 +02:00
|
|
|
}
|
2016-10-01 22:51:56 +02:00
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
if (ioctl(tty_fd, KDSKBMODE, K_OFF) < 0) {
|
|
|
|
return SDL_SetError("Failed to set keyboard mode during muting");
|
2015-06-21 17:33:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Restore the keyboard mode for given tty */
|
2017-01-07 19:13:04 +01:00
|
|
|
static void SDL_EVDEV_unmute_keyboard(int tty_fd, int old_kb_mode)
|
2015-06-21 17:33:46 +02:00
|
|
|
{
|
2017-01-07 19:13:04 +01:00
|
|
|
if (ioctl(tty_fd, KDSKBMODE, old_kb_mode) < 0) {
|
2017-01-09 04:04:38 +01:00
|
|
|
SDL_SetError("Failed to set keyboard mode during unmuting");
|
2015-06-21 17:33:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
SDL_EVDEV_Init(void)
|
|
|
|
{
|
2016-10-01 23:56:53 +02:00
|
|
|
if (_this == NULL) {
|
|
|
|
_this = (SDL_EVDEV_PrivateData*)SDL_calloc(1, sizeof(*_this));
|
|
|
|
if (_this == NULL) {
|
2015-06-21 17:33:46 +02:00
|
|
|
return SDL_OutOfMemory();
|
|
|
|
}
|
|
|
|
|
|
|
|
#if SDL_USE_LIBUDEV
|
2016-10-01 23:56:53 +02:00
|
|
|
if (SDL_UDEV_Init() < 0) {
|
|
|
|
SDL_free(_this);
|
2015-06-21 17:33:46 +02:00
|
|
|
_this = NULL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set up the udev callback */
|
2015-06-25 02:55:38 +02:00
|
|
|
if (SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) {
|
2016-10-01 22:51:56 +02:00
|
|
|
SDL_UDEV_Quit();
|
2016-10-01 23:56:53 +02:00
|
|
|
SDL_free(_this);
|
2016-10-01 22:51:56 +02:00
|
|
|
_this = NULL;
|
2015-06-21 17:33:46 +02:00
|
|
|
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 */
|
2017-01-08 01:49:23 +01:00
|
|
|
|
|
|
|
/* This might fail if we're not connected to a tty (e.g. on the Steam Link) */
|
2017-01-07 19:13:04 +01:00
|
|
|
_this->console_fd = open("/dev/tty", O_RDONLY);
|
2017-01-08 01:49:23 +01:00
|
|
|
|
2016-10-01 22:51:56 +02:00
|
|
|
/* Mute the keyboard so keystrokes only generate evdev events and do not
|
|
|
|
leak through to the console */
|
2017-01-08 01:49:23 +01:00
|
|
|
if (_this->console_fd >= 0) {
|
|
|
|
SDL_EVDEV_mute_keyboard(_this->console_fd, &_this->old_kb_mode);
|
|
|
|
}
|
2015-06-21 17:33:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
_this->ref_count += 1;
|
|
|
|
|
2016-10-01 22:51:56 +02:00
|
|
|
return 0;
|
2015-06-21 17:33:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SDL_EVDEV_Quit(void)
|
|
|
|
{
|
2016-10-01 23:56:53 +02:00
|
|
|
if (_this == NULL) {
|
2015-06-21 17:33:46 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_this->ref_count -= 1;
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
if (_this->ref_count < 1) {
|
2015-06-21 17:33:46 +02:00
|
|
|
#if SDL_USE_LIBUDEV
|
2016-10-01 23:56:53 +02:00
|
|
|
SDL_UDEV_DelCallback(SDL_EVDEV_udev_callback);
|
2015-06-21 17:33:46 +02:00
|
|
|
SDL_UDEV_Quit();
|
|
|
|
#endif /* SDL_USE_LIBUDEV */
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
if (_this->console_fd >= 0) {
|
2017-01-07 19:13:04 +01:00
|
|
|
SDL_EVDEV_unmute_keyboard(_this->console_fd, _this->old_kb_mode);
|
2016-10-01 23:56:53 +02:00
|
|
|
close(_this->console_fd);
|
2015-06-21 17:33:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove existing devices */
|
|
|
|
while(_this->first != NULL) {
|
2016-10-01 23:56:53 +02:00
|
|
|
SDL_EVDEV_device_removed(_this->first->path);
|
2015-06-21 17:33:46 +02:00
|
|
|
}
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
SDL_assert(_this->first == NULL);
|
|
|
|
SDL_assert(_this->last == NULL);
|
|
|
|
SDL_assert(_this->num_devices == 0);
|
2015-06-21 17:33:46 +02:00
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
SDL_free(_this);
|
2015-06-21 17:33:46 +02:00
|
|
|
_this = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if SDL_USE_LIBUDEV
|
2016-10-01 23:56:53 +02:00
|
|
|
void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event, int udev_class,
|
|
|
|
const char* dev_path)
|
2015-06-21 17:33:46 +02:00
|
|
|
{
|
2016-10-01 23:56:53 +02:00
|
|
|
if (dev_path == NULL) {
|
2015-06-21 17:33:46 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
switch(udev_event) {
|
2015-06-21 17:33:46 +02:00
|
|
|
case SDL_UDEV_DEVICEADDED:
|
2016-10-01 23:56:53 +02:00
|
|
|
if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD |
|
|
|
|
SDL_UDEV_DEVICE_TOUCHSCREEN)))
|
2015-06-25 02:54:39 +02:00
|
|
|
return;
|
2016-10-01 22:51:56 +02:00
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
SDL_EVDEV_device_added(dev_path, udev_class);
|
2016-10-01 22:51:56 +02:00
|
|
|
break;
|
2015-06-21 17:33:46 +02:00
|
|
|
case SDL_UDEV_DEVICEREMOVED:
|
2016-10-01 23:56:53 +02:00
|
|
|
SDL_EVDEV_device_removed(dev_path);
|
2015-06-21 17:33:46 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* SDL_USE_LIBUDEV */
|
|
|
|
|
2016-10-01 22:51:56 +02:00
|
|
|
#ifdef SDL_INPUT_LINUXKD
|
|
|
|
/* this logic is pulled from kbd_keycode() in drivers/tty/vt/keyboard.c in the
|
|
|
|
Linux kernel source */
|
2017-01-08 01:49:23 +01:00
|
|
|
static void SDL_EVDEV_do_text_input(unsigned short keycode)
|
|
|
|
{
|
2016-10-01 22:51:56 +02:00
|
|
|
char shift_state;
|
|
|
|
int locks_state;
|
|
|
|
struct kbentry kbe;
|
|
|
|
unsigned char type;
|
|
|
|
char text[2] = { 0 };
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
if (_this->console_fd < 0)
|
2016-10-01 22:51:56 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
shift_state = TIOCL_GETSHIFTSTATE;
|
2016-10-01 23:56:53 +02:00
|
|
|
if (ioctl(_this->console_fd, TIOCLINUX, &shift_state) < 0) {
|
2016-10-01 22:51:56 +02:00
|
|
|
/* TODO: error */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
kbe.kb_table = shift_state;
|
|
|
|
kbe.kb_index = keycode;
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
if (ioctl(_this->console_fd, KDGKBENT, &kbe) < 0) {
|
2016-10-01 22:51:56 +02:00
|
|
|
/* TODO: error */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-01-09 05:03:18 +01:00
|
|
|
if (kbe.kb_value == K_HOLE || kbe.kb_value == K_NOSUCHMAP) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
kbe.kb_value ^= 0xf000;
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
type = KTYP(kbe.kb_value);
|
2016-10-01 22:51:56 +02:00
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
if (type < 0xf0) {
|
2016-10-01 22:51:56 +02:00
|
|
|
/*
|
|
|
|
* 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 */
|
2016-10-01 23:56:53 +02:00
|
|
|
if (type == KT_LETTER) {
|
2016-10-01 22:51:56 +02:00
|
|
|
type = KT_LATIN;
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
if (ioctl(_this->console_fd, KDGKBLED, &locks_state) < 0) {
|
2016-10-01 22:51:56 +02:00
|
|
|
/* TODO: error */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
if (locks_state & K_CAPSLOCK) {
|
|
|
|
kbe.kb_table = shift_state ^ (1 << KG_SHIFT);
|
2016-10-01 22:51:56 +02:00
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
if (ioctl(_this->console_fd, KDGKBENT, &kbe) < 0) {
|
2016-10-01 22:51:56 +02:00
|
|
|
/* TODO: error */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: convert values >= 0x80 from ISO-8859-1? to UTF-8 */
|
2016-10-01 23:56:53 +02:00
|
|
|
if (type != KT_LATIN || KVAL(kbe.kb_value) >= 0x80)
|
2016-10-01 22:51:56 +02:00
|
|
|
return;
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
*text = KVAL(kbe.kb_value);
|
|
|
|
SDL_SendKeyboardText(text);
|
2016-10-01 22:51:56 +02:00
|
|
|
}
|
|
|
|
#endif /* SDL_INPUT_LINUXKD */
|
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
void
|
|
|
|
SDL_EVDEV_Poll(void)
|
|
|
|
{
|
|
|
|
struct input_event events[32];
|
2016-10-01 22:51:56 +02:00
|
|
|
int i, j, len;
|
2015-06-21 17:33:46 +02:00
|
|
|
SDL_evdevlist_item *item;
|
|
|
|
SDL_Scancode scan_code;
|
|
|
|
int mouse_button;
|
|
|
|
SDL_Mouse *mouse;
|
2016-10-01 22:51:56 +02:00
|
|
|
float norm_x, norm_y;
|
2015-06-21 17:33:46 +02:00
|
|
|
|
|
|
|
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) {
|
2016-10-01 22:51:56 +02:00
|
|
|
/* special handling for touchscreen, that should eventually be
|
|
|
|
used for all devices */
|
2016-10-01 23:56:53 +02:00
|
|
|
if (item->out_of_sync && item->is_touchscreen &&
|
|
|
|
events[i].type == EV_SYN && events[i].code != SYN_REPORT) {
|
2016-10-01 22:51:56 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
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);
|
2016-10-01 23:56:53 +02:00
|
|
|
} else if (events[i].value == 1 || events[i].value == 2 /* key repeated */) {
|
2015-06-21 17:33:46 +02:00
|
|
|
SDL_SendKeyboardKey(SDL_PRESSED, scan_code);
|
|
|
|
#ifdef SDL_INPUT_LINUXKD
|
2016-10-01 23:56:53 +02:00
|
|
|
SDL_EVDEV_do_text_input(events[i].code);
|
2015-06-21 17:33:46 +02:00
|
|
|
#endif /* SDL_INPUT_LINUXKD */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EV_ABS:
|
|
|
|
switch(events[i].code) {
|
2016-10-01 22:51:56 +02:00
|
|
|
case ABS_MT_SLOT:
|
2016-10-01 23:56:53 +02:00
|
|
|
if (!item->is_touchscreen) /* FIXME: temp hack */
|
2016-10-01 22:51:56 +02:00
|
|
|
break;
|
|
|
|
item->touchscreen_data->current_slot = events[i].value;
|
|
|
|
break;
|
|
|
|
case ABS_MT_TRACKING_ID:
|
2016-10-01 23:56:53 +02:00
|
|
|
if (!item->is_touchscreen) /* FIXME: temp hack */
|
2016-10-01 22:51:56 +02:00
|
|
|
break;
|
2016-10-01 23:56:53 +02:00
|
|
|
if (events[i].value >= 0) {
|
2016-10-01 22:51:56 +02:00
|
|
|
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:
|
2016-10-01 23:56:53 +02:00
|
|
|
if (!item->is_touchscreen) /* FIXME: temp hack */
|
2016-10-01 22:51:56 +02:00
|
|
|
break;
|
|
|
|
item->touchscreen_data->slots[item->touchscreen_data->current_slot].x = events[i].value;
|
2016-10-01 23:56:53 +02:00
|
|
|
if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
|
2016-10-01 22:51:56 +02:00
|
|
|
item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ABS_MT_POSITION_Y:
|
2016-10-01 23:56:53 +02:00
|
|
|
if (!item->is_touchscreen) /* FIXME: temp hack */
|
2016-10-01 22:51:56 +02:00
|
|
|
break;
|
|
|
|
item->touchscreen_data->slots[item->touchscreen_data->current_slot].y = events[i].value;
|
2016-10-01 23:56:53 +02:00
|
|
|
if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
|
2016-10-01 22:51:56 +02:00
|
|
|
item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
|
|
|
|
}
|
|
|
|
break;
|
2015-06-21 17:33:46 +02:00
|
|
|
case ABS_X:
|
2016-10-01 23:56:53 +02:00
|
|
|
if (item->is_touchscreen) /* FIXME: temp hack */
|
2016-10-01 22:51:56 +02:00
|
|
|
break;
|
2015-06-21 17:33:46 +02:00
|
|
|
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y);
|
|
|
|
break;
|
|
|
|
case ABS_Y:
|
2016-10-01 23:56:53 +02:00
|
|
|
if (item->is_touchscreen) /* FIXME: temp hack */
|
2016-10-01 22:51:56 +02:00
|
|
|
break;
|
2015-06-21 17:33:46 +02:00
|
|
|
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) {
|
2016-10-01 22:51:56 +02:00
|
|
|
case SYN_REPORT:
|
2016-10-01 23:56:53 +02:00
|
|
|
if (!item->is_touchscreen) /* FIXME: temp hack */
|
2016-10-01 22:51:56 +02:00
|
|
|
break;
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
for(j = 0; j < item->touchscreen_data->max_slots; j++) {
|
2016-10-01 22:51:56 +02:00
|
|
|
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;
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
switch(item->touchscreen_data->slots[j].delta) {
|
2016-10-01 22:51:56 +02:00
|
|
|
case EVDEV_TOUCH_SLOTDELTA_DOWN:
|
2016-10-01 23:56:53 +02:00
|
|
|
SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_TRUE, norm_x, norm_y, 1.0f);
|
2016-10-01 22:51:56 +02:00
|
|
|
item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
|
|
|
|
break;
|
|
|
|
case EVDEV_TOUCH_SLOTDELTA_UP:
|
2016-10-01 23:56:53 +02:00
|
|
|
SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_FALSE, norm_x, norm_y, 1.0f);
|
2016-10-01 22:51:56 +02:00
|
|
|
item->touchscreen_data->slots[j].tracking_id = -1;
|
|
|
|
item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
|
|
|
|
break;
|
|
|
|
case EVDEV_TOUCH_SLOTDELTA_MOVE:
|
2016-10-01 23:56:53 +02:00
|
|
|
SDL_SendTouchMotion(item->fd, item->touchscreen_data->slots[j].tracking_id, norm_x, norm_y, 1.0f);
|
2016-10-01 22:51:56 +02:00
|
|
|
item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
if (item->out_of_sync)
|
2016-10-01 22:51:56 +02:00
|
|
|
item->out_of_sync = 0;
|
|
|
|
break;
|
2015-06-21 17:33:46 +02:00
|
|
|
case SYN_DROPPED:
|
2016-10-01 23:56:53 +02:00
|
|
|
if (item->is_touchscreen)
|
2016-10-01 22:51:56 +02:00
|
|
|
item->out_of_sync = 1;
|
2015-06-21 17:33:46 +02:00
|
|
|
SDL_EVDEV_sync_device(item);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static SDL_Scancode
|
2016-10-01 23:56:53 +02:00
|
|
|
SDL_EVDEV_translate_keycode(int keycode)
|
2015-06-21 17:33:46 +02:00
|
|
|
{
|
|
|
|
SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
if (keycode < SDL_arraysize(linux_scancode_table))
|
2016-10-01 22:51:56 +02:00
|
|
|
scancode = linux_scancode_table[keycode];
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
if (scancode == SDL_SCANCODE_UNKNOWN) {
|
|
|
|
SDL_Log("The key you just pressed is not recognized by SDL. To help "
|
2016-10-01 22:51:56 +02:00
|
|
|
"get this fixed, please report this to the SDL mailing list "
|
2016-10-01 23:56:53 +02:00
|
|
|
"<sdl@libsdl.org> EVDEV KeyCode %d\n", keycode);
|
2015-06-21 17:33:46 +02:00
|
|
|
}
|
2016-10-01 22:51:56 +02:00
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
return scancode;
|
|
|
|
}
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
#ifdef SDL_USE_LIBUDEV
|
2016-10-01 22:51:56 +02:00
|
|
|
static int
|
2016-10-01 23:56:53 +02:00
|
|
|
SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
|
|
|
|
{
|
2016-10-01 22:51:56 +02:00
|
|
|
int ret, i;
|
|
|
|
char name[64];
|
|
|
|
struct input_absinfo abs_info;
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
if (!item->is_touchscreen)
|
2016-10-01 22:51:56 +02:00
|
|
|
return 0;
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
item->touchscreen_data = SDL_calloc(1, sizeof(*item->touchscreen_data));
|
|
|
|
if (item->touchscreen_data == NULL)
|
2016-10-01 22:51:56 +02:00
|
|
|
return SDL_OutOfMemory();
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
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");
|
2016-10-01 22:51:56 +02:00
|
|
|
}
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
item->touchscreen_data->name = SDL_strdup(name);
|
|
|
|
if (item->touchscreen_data->name == NULL) {
|
|
|
|
SDL_free(item->touchscreen_data);
|
2016-10-01 22:51:56 +02:00
|
|
|
return SDL_OutOfMemory();
|
|
|
|
}
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
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");
|
2016-10-01 22:51:56 +02:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
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");
|
2016-10-01 22:51:56 +02:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
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");
|
2016-10-01 22:51:56 +02:00
|
|
|
}
|
|
|
|
item->touchscreen_data->max_slots = abs_info.maximum + 1;
|
|
|
|
|
|
|
|
item->touchscreen_data->slots = SDL_calloc(
|
|
|
|
item->touchscreen_data->max_slots,
|
2016-10-01 23:56:53 +02:00
|
|
|
sizeof(*item->touchscreen_data->slots));
|
|
|
|
if (item->touchscreen_data->slots == NULL) {
|
|
|
|
SDL_free(item->touchscreen_data->name);
|
|
|
|
SDL_free(item->touchscreen_data);
|
2016-10-01 22:51:56 +02:00
|
|
|
return SDL_OutOfMemory();
|
|
|
|
}
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
for(i = 0; i < item->touchscreen_data->max_slots; i++) {
|
2016-10-01 22:51:56 +02:00
|
|
|
item->touchscreen_data->slots[i].tracking_id = -1;
|
|
|
|
}
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
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);
|
2016-10-01 22:51:56 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2016-10-01 23:56:53 +02:00
|
|
|
#endif /* SDL_USE_LIBUDEV */
|
2016-10-01 22:51:56 +02:00
|
|
|
|
|
|
|
static void
|
2016-10-01 23:56:53 +02:00
|
|
|
SDL_EVDEV_destroy_touchscreen(SDL_evdevlist_item* item) {
|
|
|
|
if (!item->is_touchscreen)
|
2016-10-01 22:51:56 +02:00
|
|
|
return;
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
SDL_DelTouch(item->fd);
|
|
|
|
SDL_free(item->touchscreen_data->slots);
|
|
|
|
SDL_free(item->touchscreen_data->name);
|
|
|
|
SDL_free(item->touchscreen_data);
|
2016-10-01 22:51:56 +02:00
|
|
|
}
|
|
|
|
|
2015-06-21 17:33:46 +02:00
|
|
|
static void
|
|
|
|
SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
|
|
|
|
{
|
2016-10-02 00:04:13 +02:00
|
|
|
#ifdef EVIOCGMTSLOTS
|
2016-10-01 22:51:56 +02:00
|
|
|
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 */
|
2016-10-01 23:56:53 +02:00
|
|
|
if (!item->is_touchscreen)
|
2016-10-01 22:51:56 +02:00
|
|
|
return;
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
mt_req_size = sizeof(*mt_req_code) +
|
|
|
|
sizeof(*mt_req_values) * item->touchscreen_data->max_slots;
|
2016-10-01 22:51:56 +02:00
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
mt_req_code = SDL_calloc(1, mt_req_size);
|
|
|
|
if (mt_req_code == NULL) {
|
2016-10-01 22:51:56 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mt_req_values = (__s32*)mt_req_code + 1;
|
|
|
|
|
|
|
|
*mt_req_code = ABS_MT_TRACKING_ID;
|
2016-10-01 23:56:53 +02:00
|
|
|
ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
|
|
|
|
if (ret < 0) {
|
|
|
|
SDL_free(mt_req_code);
|
2016-10-01 22:51:56 +02:00
|
|
|
return;
|
|
|
|
}
|
2016-10-01 23:56:53 +02:00
|
|
|
for(i = 0; i < item->touchscreen_data->max_slots; i++) {
|
2016-10-01 22:51:56 +02:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2016-10-01 23:56:53 +02:00
|
|
|
if (item->touchscreen_data->slots[i].tracking_id < 0 &&
|
|
|
|
mt_req_values[i] >= 0) {
|
2016-10-01 22:51:56 +02:00
|
|
|
item->touchscreen_data->slots[i].tracking_id = mt_req_values[i];
|
|
|
|
item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
|
2016-10-01 23:56:53 +02:00
|
|
|
} else if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
|
|
|
|
mt_req_values[i] < 0) {
|
2016-10-01 22:51:56 +02:00
|
|
|
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;
|
2016-10-01 23:56:53 +02:00
|
|
|
ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
|
|
|
|
if (ret < 0) {
|
|
|
|
SDL_free(mt_req_code);
|
2016-10-01 22:51:56 +02:00
|
|
|
return;
|
|
|
|
}
|
2016-10-01 23:56:53 +02:00
|
|
|
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]) {
|
2016-10-01 22:51:56 +02:00
|
|
|
item->touchscreen_data->slots[i].x = mt_req_values[i];
|
2016-10-01 23:56:53 +02:00
|
|
|
if (item->touchscreen_data->slots[i].delta ==
|
|
|
|
EVDEV_TOUCH_SLOTDELTA_NONE) {
|
2016-10-01 22:51:56 +02:00
|
|
|
item->touchscreen_data->slots[i].delta =
|
|
|
|
EVDEV_TOUCH_SLOTDELTA_MOVE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*mt_req_code = ABS_MT_POSITION_Y;
|
2016-10-01 23:56:53 +02:00
|
|
|
ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
|
|
|
|
if (ret < 0) {
|
|
|
|
SDL_free(mt_req_code);
|
2016-10-01 22:51:56 +02:00
|
|
|
return;
|
|
|
|
}
|
2016-10-01 23:56:53 +02:00
|
|
|
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]) {
|
2016-10-01 22:51:56 +02:00
|
|
|
item->touchscreen_data->slots[i].y = mt_req_values[i];
|
2016-10-01 23:56:53 +02:00
|
|
|
if (item->touchscreen_data->slots[i].delta ==
|
|
|
|
EVDEV_TOUCH_SLOTDELTA_NONE) {
|
2016-10-01 22:51:56 +02:00
|
|
|
item->touchscreen_data->slots[i].delta =
|
|
|
|
EVDEV_TOUCH_SLOTDELTA_MOVE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
|
|
|
|
if (ret < 0) {
|
|
|
|
SDL_free(mt_req_code);
|
2016-10-01 22:51:56 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
item->touchscreen_data->current_slot = abs_info.value;
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
SDL_free(mt_req_code);
|
2016-10-02 00:04:13 +02:00
|
|
|
|
|
|
|
#endif /* EVIOCGMTSLOTS */
|
2015-06-21 17:33:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#if SDL_USE_LIBUDEV
|
|
|
|
static int
|
2016-10-01 22:51:56 +02:00
|
|
|
SDL_EVDEV_device_added(const char *dev_path, int udev_class)
|
2015-06-21 17:33:46 +02:00
|
|
|
{
|
2016-10-01 22:51:56 +02:00
|
|
|
int ret;
|
2015-06-21 17:33:46 +02:00
|
|
|
SDL_evdevlist_item *item;
|
|
|
|
|
|
|
|
/* Check to make sure it's not already in list. */
|
|
|
|
for (item = _this->first; item != NULL; item = item->next) {
|
2016-10-01 22:51:56 +02:00
|
|
|
if (SDL_strcmp(dev_path, item->path) == 0) {
|
2015-06-21 17:33:46 +02:00
|
|
|
return -1; /* already have this one */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
item = (SDL_evdevlist_item *) SDL_calloc(1, sizeof (SDL_evdevlist_item));
|
|
|
|
if (item == NULL) {
|
|
|
|
return SDL_OutOfMemory();
|
|
|
|
}
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
item->fd = open(dev_path, O_RDONLY | O_NONBLOCK);
|
2015-06-21 17:33:46 +02:00
|
|
|
if (item->fd < 0) {
|
|
|
|
SDL_free(item);
|
2016-10-01 22:51:56 +02:00
|
|
|
return SDL_SetError("Unable to open %s", dev_path);
|
2015-06-21 17:33:46 +02:00
|
|
|
}
|
|
|
|
|
2016-10-01 22:51:56 +02:00
|
|
|
item->path = SDL_strdup(dev_path);
|
2015-06-21 17:33:46 +02:00
|
|
|
if (item->path == NULL) {
|
|
|
|
close(item->fd);
|
|
|
|
SDL_free(item);
|
|
|
|
return SDL_OutOfMemory();
|
|
|
|
}
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
if (udev_class & SDL_UDEV_DEVICE_TOUCHSCREEN) {
|
2016-10-01 22:51:56 +02:00
|
|
|
item->is_touchscreen = 1;
|
|
|
|
|
2016-10-01 23:56:53 +02:00
|
|
|
if ((ret = SDL_EVDEV_init_touchscreen(item)) < 0) {
|
2016-10-01 22:51:56 +02:00
|
|
|
close(item->fd);
|
|
|
|
SDL_free(item);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
2015-06-21 17:33:46 +02:00
|
|
|
|
|
|
|
if (_this->last == NULL) {
|
|
|
|
_this->first = _this->last = item;
|
|
|
|
} else {
|
|
|
|
_this->last->next = item;
|
|
|
|
_this->last = item;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_EVDEV_sync_device(item);
|
|
|
|
|
2016-10-01 22:51:56 +02:00
|
|
|
return _this->num_devices++;
|
2015-06-21 17:33:46 +02:00
|
|
|
}
|
|
|
|
#endif /* SDL_USE_LIBUDEV */
|
|
|
|
|
|
|
|
static int
|
2016-10-01 22:51:56 +02:00
|
|
|
SDL_EVDEV_device_removed(const char *dev_path)
|
2015-06-21 17:33:46 +02:00
|
|
|
{
|
|
|
|
SDL_evdevlist_item *item;
|
|
|
|
SDL_evdevlist_item *prev = NULL;
|
|
|
|
|
|
|
|
for (item = _this->first; item != NULL; item = item->next) {
|
|
|
|
/* found it, remove it. */
|
2016-10-01 22:51:56 +02:00
|
|
|
if (SDL_strcmp(dev_path, item->path) == 0) {
|
2015-06-21 17:33:46 +02:00
|
|
|
if (prev != NULL) {
|
|
|
|
prev->next = item->next;
|
|
|
|
} else {
|
|
|
|
SDL_assert(_this->first == item);
|
|
|
|
_this->first = item->next;
|
|
|
|
}
|
|
|
|
if (item == _this->last) {
|
|
|
|
_this->last = prev;
|
|
|
|
}
|
2016-10-01 23:56:53 +02:00
|
|
|
if (item->is_touchscreen) {
|
|
|
|
SDL_EVDEV_destroy_touchscreen(item);
|
2016-10-01 22:51:56 +02:00
|
|
|
}
|
2015-06-21 17:33:46 +02:00
|
|
|
close(item->fd);
|
|
|
|
SDL_free(item->path);
|
|
|
|
SDL_free(item);
|
2016-10-01 22:51:56 +02:00
|
|
|
_this->num_devices--;
|
2015-06-21 17:33:46 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
prev = item;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endif /* SDL_INPUT_LINUXEV */
|
|
|
|
|
|
|
|
/* vi: set ts=4 sw=4 expandtab: */
|