Merge pull request #5010 from casdevel/udev

Add multiple mice support to udev input driver
This commit is contained in:
Twinaphex 2017-06-02 16:45:13 +02:00 committed by GitHub
commit a8f1831a62
2 changed files with 195 additions and 100 deletions

View File

@ -36,6 +36,9 @@
#endif #endif
#include <string/stdstring.h>
#include "../../configuration.h"
#include "../../frontend/frontend_driver.h" #include "../../frontend/frontend_driver.h"
#include "../common/gl_common.h" #include "../common/gl_common.h"
#include "../common/x11_common.h" #include "../common/x11_common.h"
@ -900,8 +903,21 @@ static void gfx_ctx_x_input_driver(void *data,
const char *joypad_name, const char *joypad_name,
const input_driver_t **input, void **input_data) const input_driver_t **input, void **input_data)
{ {
void *xinput = input_x.init(joypad_name); #ifdef HAVE_UDEV
settings_t *settings = config_get_ptr();
if (string_is_equal_fast(settings->arrays.input_driver, "udev", 5))
{
*input_data = input_udev.init(joypad_name);
if (*input_data)
{
*input = &input_udev;
return;
}
}
#endif
void *xinput = input_x.init(joypad_name);
*input = xinput ? &input_x : NULL; *input = xinput ? &input_x : NULL;
*input_data = xinput; *input_data = xinput;
} }

View File

@ -60,6 +60,28 @@ typedef struct udev_input udev_input_t;
typedef struct udev_input_device udev_input_device_t; typedef struct udev_input_device udev_input_device_t;
enum udev_input_dev_type
{
UDEV_INPUT_KEYBOARD,
UDEV_INPUT_MOUSE,
UDEV_INPUT_TOUCHPAD
};
/* NOTE: must be in sync with enum udev_input_dev_type */
static const char *g_dev_type_str[] =
{
"ID_INPUT_KEYBOARD",
"ID_INPUT_MOUSE",
"ID_INPUT_TOUCHPAD"
};
typedef struct
{
int16_t x, y;
bool l, r, m;
bool wu, wd, whu, whd;
} udev_input_mouse_t;
struct udev_input_device struct udev_input_device
{ {
int fd; int fd;
@ -67,13 +89,12 @@ struct udev_input_device
void (*handle_cb)(void *data, void (*handle_cb)(void *data,
const struct input_event *event, udev_input_device_t *dev); const struct input_event *event, udev_input_device_t *dev);
char devnode[PATH_MAX_LENGTH]; char devnode[PATH_MAX_LENGTH];
enum udev_input_dev_type type;
union union
{ {
/* udev_input_mouse_t mouse;
* keyboard
* mouse
*/
struct struct
{ {
float x, y; float x, y;
@ -100,10 +121,6 @@ struct udev_input
int epfd; int epfd;
udev_input_device_t **devices; udev_input_device_t **devices;
unsigned num_devices; unsigned num_devices;
int16_t mouse_x;
int16_t mouse_y;
bool mouse_l, mouse_r, mouse_m, mouse_wu, mouse_wd, mouse_whu, mouse_whd;
}; };
#ifdef HAVE_XKBCOMMON #ifdef HAVE_XKBCOMMON
@ -155,7 +172,18 @@ static void udev_input_kb_free(void)
static void udev_handle_touchpad(void *data, static void udev_handle_touchpad(void *data,
const struct input_event *event, udev_input_device_t *dev) const struct input_event *event, udev_input_device_t *dev)
{ {
udev_input_t *udev = (udev_input_t*)data; unsigned i;
udev_input_t *udev = (udev_input_t*)data;
udev_input_mouse_t *mouse = NULL;
for (i = 0; i < udev->num_devices; ++i)
{
if (udev->devices[i]->type == UDEV_INPUT_MOUSE)
{
mouse = &udev->devices[i]->state.mouse;
break;
}
}
switch (event->type) switch (event->type)
{ {
@ -170,9 +198,8 @@ static void udev_handle_touchpad(void *data,
float x_norm = (float)x / range; float x_norm = (float)x / range;
float rel_x = x_norm - dev->state.touchpad.x; float rel_x = x_norm - dev->state.touchpad.x;
if (dev->state.touchpad.touch) if (dev->state.touchpad.touch && mouse)
udev->mouse_x += (int16_t) mouse->x += (int16_t)roundf(dev->state.touchpad.mod_x * rel_x);
roundf(dev->state.touchpad.mod_x * rel_x);
dev->state.touchpad.x = x_norm; dev->state.touchpad.x = x_norm;
/* Some factor, not sure what's good to do here ... */ /* Some factor, not sure what's good to do here ... */
@ -188,8 +215,8 @@ static void udev_handle_touchpad(void *data,
float y_norm = (float)y / range; float y_norm = (float)y / range;
float rel_y = y_norm - dev->state.touchpad.y; float rel_y = y_norm - dev->state.touchpad.y;
if (dev->state.touchpad.touch) if (dev->state.touchpad.touch && mouse)
udev->mouse_y += (int16_t)roundf(dev->state.touchpad.mod_y * rel_y); mouse->y += (int16_t)roundf(dev->state.touchpad.mod_y * rel_y);
dev->state.touchpad.y = y_norm; dev->state.touchpad.y = y_norm;
@ -221,24 +248,23 @@ static void udev_handle_touchpad(void *data,
static void udev_handle_mouse(void *data, static void udev_handle_mouse(void *data,
const struct input_event *event, udev_input_device_t *dev) const struct input_event *event, udev_input_device_t *dev)
{ {
udev_input_t *udev = (udev_input_t*)data; udev_input_mouse_t *mouse = &dev->state.mouse;
switch (event->type) switch (event->type)
{ {
case EV_KEY: case EV_KEY:
/* TODO: mouse wheel up/down doesn't work */
switch (event->code) switch (event->code)
{ {
case BTN_LEFT: case BTN_LEFT:
udev->mouse_l = event->value; mouse->l = event->value;
break; break;
case BTN_RIGHT: case BTN_RIGHT:
udev->mouse_r = event->value; mouse->r = event->value;
break; break;
case BTN_MIDDLE: case BTN_MIDDLE:
udev->mouse_m = event->value; mouse->m = event->value;
break; break;
default: default:
break; break;
@ -249,36 +275,28 @@ static void udev_handle_mouse(void *data,
switch (event->code) switch (event->code)
{ {
case REL_X: case REL_X:
udev->mouse_x += event->value; mouse->x += event->value;
break; break;
case REL_Y: case REL_Y:
udev->mouse_y += event->value; mouse->y += event->value;
break; break;
case REL_WHEEL: case REL_WHEEL:
if (event->value == 1) if (event->value == 1)
udev->mouse_wu = 1; mouse->wu = 1;
else if (event->value == -1) else if (event->value == -1)
udev->mouse_wd = 1; mouse->wd = 1;
break; break;
case REL_HWHEEL: case REL_HWHEEL:
if (event->value == 1) if (event->value == 1)
udev->mouse_whu = 1; mouse->whu = 1;
else if (event->value == -1) else if (event->value == -1)
udev->mouse_whd = 1; mouse->whd = 1;
break;
default:
break;
} }
break;
default:
break;
} }
} }
static bool udev_input_add_device(udev_input_t *udev, static bool udev_input_add_device(udev_input_t *udev,
const char *devnode, device_handle_cb cb) enum udev_input_dev_type type, const char *devnode, device_handle_cb cb)
{ {
int fd; int fd;
udev_input_device_t **tmp; udev_input_device_t **tmp;
@ -299,11 +317,12 @@ static bool udev_input_add_device(udev_input_t *udev,
device->fd = fd; device->fd = fd;
device->dev = st.st_dev; device->dev = st.st_dev;
device->handle_cb = cb; device->handle_cb = cb;
device->type = type;
strlcpy(device->devnode, devnode, sizeof(device->devnode)); strlcpy(device->devnode, devnode, sizeof(device->devnode));
/* Touchpads report in absolute coords. */ /* Touchpads report in absolute coords. */
if (cb == udev_handle_touchpad && if (type == UDEV_INPUT_TOUCHPAD &&
(ioctl(fd, EVIOCGABS(ABS_X), &device->state.touchpad.info_x) < 0 || (ioctl(fd, EVIOCGABS(ABS_X), &device->state.touchpad.info_x) < 0 ||
ioctl(fd, EVIOCGABS(ABS_Y), &device->state.touchpad.info_y) < 0)) ioctl(fd, EVIOCGABS(ABS_Y), &device->state.touchpad.info_y) < 0))
goto error; goto error;
@ -348,12 +367,13 @@ static void udev_input_remove_device(udev_input_t *udev, const char *devnode)
static void udev_input_handle_hotplug(udev_input_t *udev) static void udev_input_handle_hotplug(udev_input_t *udev)
{ {
const char *devtype = NULL; const char *val_keyboard;
const char *val_keyboard = NULL; const char *val_mouse;
const char *val_mouse = NULL; const char *val_touchpad;
const char *val_touchpad = NULL; const char *action;
const char *action = NULL; const char *devnode;
const char *devnode = NULL; enum udev_input_dev_type dev_type;
device_handle_cb cb;
struct udev_device *dev = udev_monitor_receive_device(udev->monitor); struct udev_device *dev = udev_monitor_receive_device(udev->monitor);
if (!dev) if (!dev)
@ -366,33 +386,31 @@ static void udev_input_handle_hotplug(udev_input_t *udev)
devnode = udev_device_get_devnode(dev); devnode = udev_device_get_devnode(dev);
if (val_keyboard && string_is_equal_fast(val_keyboard, "1", 1) && devnode) if (val_keyboard && string_is_equal_fast(val_keyboard, "1", 1) && devnode)
devtype = "keyboard"; {
dev_type = UDEV_INPUT_KEYBOARD;
if (val_mouse && string_is_equal_fast(val_mouse, "1", 1) && devnode) cb = udev_handle_keyboard;
devtype = "mouse"; }
else if (val_mouse && string_is_equal_fast(val_mouse, "1", 1) && devnode)
if (val_touchpad && string_is_equal_fast(val_touchpad, "1", 1) && devnode) {
devtype = "touchpad"; dev_type = UDEV_INPUT_MOUSE;
cb = udev_handle_mouse;
if (!devtype) }
else if (val_touchpad && string_is_equal_fast(val_touchpad, "1", 1) && devnode)
{
dev_type = UDEV_INPUT_TOUCHPAD;
cb = udev_handle_touchpad;
}
else
goto end; goto end;
if (string_is_equal_fast(action, "add", 3)) if (string_is_equal_fast(action, "add", 3))
{ {
device_handle_cb cb = NULL; RARCH_LOG("[udev]: Hotplug add %s: %s.\n", g_dev_type_str[dev_type], devnode);
if (string_is_equal_fast(devtype, "keyboard", 8)) udev_input_add_device(udev, dev_type, devnode, cb);
cb = udev_handle_keyboard;
else if (string_is_equal_fast(devtype, "touchpad", 8))
cb = udev_handle_touchpad;
else if (string_is_equal_fast(devtype, "mouse", 5))
cb = udev_handle_mouse;
RARCH_LOG("[udev]: Hotplug add %s: %s.\n", devtype, devnode);
udev_input_add_device(udev, devnode, cb);
} }
else if (string_is_equal_fast(action, "remove", 6)) else if (string_is_equal_fast(action, "remove", 6))
{ {
RARCH_LOG("[udev]: Hotplug remove %s: %s.\n", devtype, devnode); RARCH_LOG("[udev]: Hotplug remove %s: %s.\n", g_dev_type_str[dev_type], devnode);
udev_input_remove_device(udev, devnode); udev_input_remove_device(udev, devnode);
} }
@ -404,14 +422,21 @@ static void udev_input_poll(void *data)
{ {
int i, ret; int i, ret;
struct epoll_event events[32]; struct epoll_event events[32];
udev_input_mouse_t *mouse;
udev_input_t *udev = (udev_input_t*)data; udev_input_t *udev = (udev_input_t*)data;
if (!udev) if (!udev)
return; return;
udev->mouse_x = udev->mouse_y = 0; for (i = 0; i < udev->num_devices; ++i)
udev->mouse_wu = udev->mouse_wd = 0; {
udev->mouse_whu = udev->mouse_whd = 0; if (udev->devices[i]->type == UDEV_INPUT_MOUSE)
{
mouse = &udev->devices[i]->state.mouse;
mouse->x = mouse->y = 0;
mouse->wu = mouse->wd = mouse->whu = mouse->whd = false;
}
}
while (udev->monitor && udev_hotplug_available(udev->monitor)) while (udev->monitor && udev_hotplug_available(udev->monitor))
udev_input_handle_hotplug(udev); udev_input_handle_hotplug(udev);
@ -439,51 +464,87 @@ static void udev_input_poll(void *data)
udev->joypad->poll(); udev->joypad->poll();
} }
static int16_t udev_mouse_state(udev_input_t *udev, unsigned id) static int16_t udev_mouse_state(udev_input_t *udev, unsigned port, unsigned id)
{ {
unsigned i, j;
udev_input_mouse_t *mouse = NULL;
for (i = j = 0; i < udev->num_devices; ++i)
{
if (udev->devices[i]->type != UDEV_INPUT_MOUSE)
continue;
if (j == port)
{
mouse = &udev->devices[i]->state.mouse;
break;
}
++j;
}
if (!mouse)
return 0;
switch (id) switch (id)
{ {
case RETRO_DEVICE_ID_MOUSE_X: case RETRO_DEVICE_ID_MOUSE_X:
return udev->mouse_x; return mouse->x;
case RETRO_DEVICE_ID_MOUSE_Y: case RETRO_DEVICE_ID_MOUSE_Y:
return udev->mouse_y; return mouse->y;
case RETRO_DEVICE_ID_MOUSE_LEFT: case RETRO_DEVICE_ID_MOUSE_LEFT:
return udev->mouse_l; return mouse->l;
case RETRO_DEVICE_ID_MOUSE_RIGHT: case RETRO_DEVICE_ID_MOUSE_RIGHT:
return udev->mouse_r; return mouse->r;
case RETRO_DEVICE_ID_MOUSE_MIDDLE: case RETRO_DEVICE_ID_MOUSE_MIDDLE:
return udev->mouse_m; return mouse->m;
case RETRO_DEVICE_ID_MOUSE_WHEELUP: case RETRO_DEVICE_ID_MOUSE_WHEELUP:
return udev->mouse_wu; return mouse->wu;
case RETRO_DEVICE_ID_MOUSE_WHEELDOWN: case RETRO_DEVICE_ID_MOUSE_WHEELDOWN:
return udev->mouse_wd; return mouse->wd;
case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP: case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP:
return udev->mouse_whu; return mouse->whu;
case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN: case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN:
return udev->mouse_whd; return mouse->whd;
} }
return 0; return 0;
} }
static int16_t udev_lightgun_state(udev_input_t *udev, unsigned id) static int16_t udev_lightgun_state(udev_input_t *udev, unsigned port, unsigned id)
{ {
unsigned i, j;
udev_input_mouse_t *mouse = NULL;
for (i = j = 0; i < udev->num_devices; ++i)
{
if (udev->devices[i]->type != UDEV_INPUT_MOUSE)
continue;
if (j == port)
{
mouse = &udev->devices[i]->state.mouse;
break;
}
++j;
}
if (!mouse)
return 0;
switch (id) switch (id)
{ {
case RETRO_DEVICE_ID_LIGHTGUN_X: case RETRO_DEVICE_ID_LIGHTGUN_X:
return udev->mouse_x; return mouse->x;
case RETRO_DEVICE_ID_LIGHTGUN_Y: case RETRO_DEVICE_ID_LIGHTGUN_Y:
return udev->mouse_y; return mouse->y;
case RETRO_DEVICE_ID_LIGHTGUN_TRIGGER: case RETRO_DEVICE_ID_LIGHTGUN_TRIGGER:
return udev->mouse_l; return mouse->l;
case RETRO_DEVICE_ID_LIGHTGUN_CURSOR: case RETRO_DEVICE_ID_LIGHTGUN_CURSOR:
return udev->mouse_m; return mouse->m;
case RETRO_DEVICE_ID_LIGHTGUN_TURBO: case RETRO_DEVICE_ID_LIGHTGUN_TURBO:
return udev->mouse_r; return mouse->r;
case RETRO_DEVICE_ID_LIGHTGUN_START: case RETRO_DEVICE_ID_LIGHTGUN_START:
return udev->mouse_m && udev->mouse_r; return mouse->m && mouse->r;
case RETRO_DEVICE_ID_LIGHTGUN_PAUSE: case RETRO_DEVICE_ID_LIGHTGUN_PAUSE:
return udev->mouse_m && udev->mouse_l; return mouse->m && mouse->l;
} }
return 0; return 0;
@ -509,9 +570,10 @@ static int16_t udev_analog_pressed(const struct retro_keybind *binds, unsigned i
} }
static int16_t udev_pointer_state(udev_input_t *udev, static int16_t udev_pointer_state(udev_input_t *udev,
unsigned idx, unsigned id, bool screen) unsigned port, unsigned id, bool screen)
{ {
struct video_viewport vp; struct video_viewport vp;
unsigned i, j;
bool inside = false; bool inside = false;
int16_t res_x = 0; int16_t res_x = 0;
int16_t res_y = 0; int16_t res_y = 0;
@ -525,8 +587,25 @@ static int16_t udev_pointer_state(udev_input_t *udev,
vp.full_width = 0; vp.full_width = 0;
vp.full_height = 0; vp.full_height = 0;
if (!(video_driver_translate_coord_viewport_wrap(&vp, udev->mouse_x, udev->mouse_y, udev_input_mouse_t *mouse = NULL;
&res_x, &res_y, &res_screen_x, &res_screen_y)))
for (i = j = 0; i < udev->num_devices; ++i)
{
if (udev->devices[i]->type != UDEV_INPUT_MOUSE)
continue;
if (j == port)
{
mouse = &udev->devices[i]->state.mouse;
break;
}
++j;
}
if (!mouse)
return 0;
if (!(video_driver_translate_coord_viewport_wrap(&vp,
mouse->x, mouse->y, &res_x, &res_y, &res_screen_x, &res_screen_y)))
return 0; return 0;
if (screen) if (screen)
@ -547,7 +626,7 @@ static int16_t udev_pointer_state(udev_input_t *udev,
case RETRO_DEVICE_ID_POINTER_Y: case RETRO_DEVICE_ID_POINTER_Y:
return res_y; return res_y;
case RETRO_DEVICE_ID_POINTER_PRESSED: case RETRO_DEVICE_ID_POINTER_PRESSED:
return udev->mouse_l; return mouse->l;
} }
return 0; return 0;
@ -582,16 +661,14 @@ static int16_t udev_input_state(void *data,
bit = input_keymaps_translate_rk_to_keysym((enum retro_key)id); bit = input_keymaps_translate_rk_to_keysym((enum retro_key)id);
return id < RETROK_LAST && BIT_GET(udev_key_state, bit); return id < RETROK_LAST && BIT_GET(udev_key_state, bit);
case RETRO_DEVICE_MOUSE: case RETRO_DEVICE_MOUSE:
return udev_mouse_state(udev, id); return udev_mouse_state(udev, port, id);
case RETRO_DEVICE_POINTER: case RETRO_DEVICE_POINTER:
return udev_pointer_state(udev, port, id, false);
case RARCH_DEVICE_POINTER_SCREEN: case RARCH_DEVICE_POINTER_SCREEN:
if (idx == 0) return udev_pointer_state(udev, port, id, true);
return udev_pointer_state(udev, idx, id,
device == RARCH_DEVICE_POINTER_SCREEN);
break;
case RETRO_DEVICE_LIGHTGUN: case RETRO_DEVICE_LIGHTGUN:
return udev_lightgun_state(udev, id); return udev_lightgun_state(udev, port, id);
} }
return 0; return 0;
@ -632,8 +709,10 @@ static void udev_input_free(void *data)
free(udev); free(udev);
} }
static bool open_devices(udev_input_t *udev, const char *type, device_handle_cb cb) static bool open_devices(udev_input_t *udev,
enum udev_input_dev_type type, device_handle_cb cb)
{ {
const char *type_str = g_dev_type_str[type];
struct udev_list_entry *devs = NULL; struct udev_list_entry *devs = NULL;
struct udev_list_entry *item = NULL; struct udev_list_entry *item = NULL;
struct udev_enumerate *enumerate = udev_enumerate_new(udev->udev); struct udev_enumerate *enumerate = udev_enumerate_new(udev->udev);
@ -641,7 +720,7 @@ static bool open_devices(udev_input_t *udev, const char *type, device_handle_cb
if (!enumerate) if (!enumerate)
return false; return false;
udev_enumerate_add_match_property(enumerate, type, "1"); udev_enumerate_add_match_property(enumerate, type_str, "1");
udev_enumerate_scan_devices(enumerate); udev_enumerate_scan_devices(enumerate);
devs = udev_enumerate_get_list_entry(enumerate); devs = udev_enumerate_get_list_entry(enumerate);
@ -658,8 +737,8 @@ static bool open_devices(udev_input_t *udev, const char *type, device_handle_cb
{ {
int fd = open(devnode, O_RDONLY | O_NONBLOCK); int fd = open(devnode, O_RDONLY | O_NONBLOCK);
RARCH_LOG("[udev] Adding device %s as type %s.\n", devnode, type); RARCH_LOG("[udev] Adding device %s as type %s.\n", devnode, type_str);
if (!udev_input_add_device(udev, devnode, cb)) if (!udev_input_add_device(udev, type, devnode, cb))
RARCH_ERR("[udev] Failed to open device: %s (%s).\n", devnode, strerror(errno)); RARCH_ERR("[udev] Failed to open device: %s (%s).\n", devnode, strerror(errno));
close(fd); close(fd);
} }
@ -703,19 +782,19 @@ static void *udev_input_init(const char *joypad_driver)
goto error; goto error;
} }
if (!open_devices(udev, "ID_INPUT_KEYBOARD", udev_handle_keyboard)) if (!open_devices(udev, UDEV_INPUT_KEYBOARD, udev_handle_keyboard))
{ {
RARCH_ERR("Failed to open keyboard.\n"); RARCH_ERR("Failed to open keyboard.\n");
goto error; goto error;
} }
if (!open_devices(udev, "ID_INPUT_MOUSE", udev_handle_mouse)) if (!open_devices(udev, UDEV_INPUT_MOUSE, udev_handle_mouse))
{ {
RARCH_ERR("Failed to open mouse.\n"); RARCH_ERR("Failed to open mouse.\n");
goto error; goto error;
} }
if (!open_devices(udev, "ID_INPUT_TOUCHPAD", udev_handle_touchpad)) if (!open_devices(udev, UDEV_INPUT_TOUCHPAD, udev_handle_touchpad))
{ {
RARCH_ERR("Failed to open touchpads.\n"); RARCH_ERR("Failed to open touchpads.\n");
goto error; goto error;