mirror of
https://github.com/libretro/RetroArch
synced 2025-01-30 21:32:45 +00:00
Add "absolute" mouse support
This commit is contained in:
parent
032109512a
commit
135b636bd4
@ -1,7 +1,7 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2015 - Hans-Kristian Arntzen
|
||||
* Copyright (C) 2011-2017 - Daniel De Matteis
|
||||
*
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
@ -82,18 +82,17 @@ static const char *g_dev_type_str[] =
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int16_t x, y, dlt_x, dlt_y;
|
||||
/* If device is "absolute" coords will be in device specific units
|
||||
and axis min value will be less than max, otherwise coords will be
|
||||
relative to full viewport and min and max values will be zero. */
|
||||
__s32 x_abs, y_abs;
|
||||
__s32 x_min, y_min;
|
||||
__s32 x_max, y_max;
|
||||
__s32 x_rel, y_rel;
|
||||
bool l, r, m;
|
||||
bool wu, wd, whu, whd;
|
||||
} udev_input_mouse_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct input_absinfo info_x;
|
||||
struct input_absinfo info_y;
|
||||
udev_input_mouse_t mouse; /* touch-pad will be presented to RA/core as mouse */
|
||||
} udev_input_touchpad_t;
|
||||
|
||||
struct udev_input_device
|
||||
{
|
||||
int fd;
|
||||
@ -103,11 +102,7 @@ struct udev_input_device
|
||||
char devnode[PATH_MAX_LENGTH];
|
||||
enum udev_input_dev_type type;
|
||||
|
||||
union
|
||||
{
|
||||
udev_input_mouse_t mouse;
|
||||
udev_input_touchpad_t touchpad;
|
||||
} state;
|
||||
udev_input_mouse_t mouse;
|
||||
};
|
||||
|
||||
typedef void (*device_handle_cb)(void *data,
|
||||
@ -129,6 +124,10 @@ struct udev_input
|
||||
#ifdef UDEV_XKB_HANDLING
|
||||
bool xkb_handling;
|
||||
#endif
|
||||
|
||||
/* OS pointer coords (zeros if we don't have X11) */
|
||||
int pointer_x;
|
||||
int pointer_y;
|
||||
};
|
||||
|
||||
#ifdef UDEV_XKB_HANDLING
|
||||
@ -216,10 +215,7 @@ static udev_input_mouse_t *udev_get_mouse(struct udev_input *udev, unsigned port
|
||||
|
||||
if (mouse_index == settings->uints.input_mouse_index[port])
|
||||
{
|
||||
if (udev->devices[i]->type == UDEV_INPUT_MOUSE)
|
||||
mouse = &udev->devices[i]->state.mouse;
|
||||
else
|
||||
mouse = &udev->devices[i]->state.touchpad.mouse;
|
||||
mouse = &udev->devices[i]->mouse;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -229,54 +225,166 @@ static udev_input_mouse_t *udev_get_mouse(struct udev_input *udev, unsigned port
|
||||
return mouse;
|
||||
}
|
||||
|
||||
static void udev_handle_touchpad(void *data,
|
||||
const struct input_event *event, udev_input_device_t *dev)
|
||||
static void udev_mouse_set_x(udev_input_mouse_t *mouse, __s32 x, bool abs)
|
||||
{
|
||||
int16_t pos;
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
udev_input_touchpad_t *touchpad = &dev->state.touchpad;
|
||||
udev_input_mouse_t *mouse = &dev->state.touchpad.mouse;
|
||||
video_viewport_t vp;
|
||||
|
||||
switch (event->type)
|
||||
if (abs)
|
||||
{
|
||||
case EV_ABS:
|
||||
video_driver_get_size(&width, &height);
|
||||
switch (event->code)
|
||||
{
|
||||
case ABS_X:
|
||||
pos = (float)(event->value - touchpad->info_x.minimum) /
|
||||
(touchpad->info_x.maximum - touchpad->info_x.minimum) * width;
|
||||
mouse->dlt_x += pos - mouse->x;
|
||||
mouse->x = pos;
|
||||
break;
|
||||
case ABS_Y:
|
||||
pos = (float)(event->value - touchpad->info_y.minimum) /
|
||||
(touchpad->info_y.maximum - touchpad->info_y.minimum) * height;
|
||||
mouse->dlt_y += pos - mouse->y;
|
||||
mouse->y = pos;
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_KEY:
|
||||
switch (event->code)
|
||||
{
|
||||
case BTN_LEFT:
|
||||
mouse->l = event->value;
|
||||
break;
|
||||
case BTN_MIDDLE:
|
||||
mouse->m = event->value;
|
||||
break;
|
||||
case BTN_RIGHT:
|
||||
mouse->r = event->value;
|
||||
}
|
||||
mouse->x_rel += x - mouse->x_abs;
|
||||
mouse->x_abs = x;
|
||||
}
|
||||
else
|
||||
{
|
||||
mouse->x_rel += x;
|
||||
if (video_driver_get_viewport_info(&vp))
|
||||
{
|
||||
mouse->x_abs += x;
|
||||
|
||||
if (mouse->x_abs < vp.x)
|
||||
mouse->x_abs = vp.x;
|
||||
else if (mouse->x_abs >= vp.x + vp.full_width)
|
||||
mouse->x_abs = vp.x + vp.full_width - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int16_t udev_mouse_get_x(const udev_input_mouse_t *mouse)
|
||||
{
|
||||
video_viewport_t vp;
|
||||
double src_width;
|
||||
double x;
|
||||
|
||||
if (!video_driver_get_viewport_info(&vp))
|
||||
return 0;
|
||||
|
||||
if (mouse->x_min < mouse->x_max) /* mouse coords are absolute */
|
||||
src_width = mouse->x_max - mouse->x_min + 1;
|
||||
else
|
||||
src_width = vp.full_width;
|
||||
|
||||
x = (double)vp.width / src_width * mouse->x_rel;
|
||||
|
||||
return x + (x < 0 ? -0.5 : 0.5);
|
||||
}
|
||||
|
||||
static void udev_mouse_set_y(udev_input_mouse_t *mouse, __s32 y, bool abs)
|
||||
{
|
||||
video_viewport_t vp;
|
||||
|
||||
if (abs)
|
||||
{
|
||||
mouse->y_rel += y - mouse->y_abs;
|
||||
mouse->y_abs = y;
|
||||
}
|
||||
else
|
||||
{
|
||||
mouse->y_rel += y;
|
||||
if (video_driver_get_viewport_info(&vp))
|
||||
{
|
||||
mouse->y_abs += y;
|
||||
|
||||
if (mouse->y_abs < vp.y)
|
||||
mouse->y_abs = vp.y;
|
||||
else if (mouse->y_abs >= vp.y + vp.full_height)
|
||||
mouse->y_abs = vp.y + vp.full_height - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int16_t udev_mouse_get_y(const udev_input_mouse_t *mouse)
|
||||
{
|
||||
video_viewport_t vp;
|
||||
double src_height;
|
||||
double y;
|
||||
|
||||
if (!video_driver_get_viewport_info(&vp))
|
||||
return 0;
|
||||
|
||||
if (mouse->y_min < mouse->y_max) /* mouse coords are absolute */
|
||||
src_height = mouse->y_max - mouse->y_min + 1;
|
||||
else
|
||||
src_height = vp.full_height;
|
||||
|
||||
y = (double)vp.height / src_height * mouse->y_rel;
|
||||
|
||||
return y + (y < 0 ? -0.5 : 0.5);
|
||||
}
|
||||
|
||||
static int16_t udev_mouse_get_pointer_x(const udev_input_mouse_t *mouse, bool screen)
|
||||
{
|
||||
video_viewport_t vp;
|
||||
double src_min;
|
||||
double src_width;
|
||||
int32_t x;
|
||||
|
||||
if (!video_driver_get_viewport_info(&vp))
|
||||
return 0;
|
||||
|
||||
if (mouse->x_min < mouse->x_max) /* mouse coords are absolute */
|
||||
{
|
||||
src_min = mouse->x_min;
|
||||
src_width = mouse->x_max - mouse->x_min + 1;
|
||||
}
|
||||
else /* mouse coords are viewport relative */
|
||||
{
|
||||
src_min = vp.x;
|
||||
if (screen)
|
||||
src_width = vp.full_width;
|
||||
else
|
||||
src_width = vp.width;
|
||||
}
|
||||
|
||||
x = -32767.0 + 65535.0 / src_width * (mouse->x_abs - src_min);
|
||||
x += (x < 0 ? -0.5 : 0.5);
|
||||
|
||||
if (x < -0x7fff)
|
||||
x = -0x7fff;
|
||||
else if(x > 0x7fff)
|
||||
x = 0x7fff;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static int16_t udev_mouse_get_pointer_y(const udev_input_mouse_t *mouse, bool screen)
|
||||
{
|
||||
video_viewport_t vp;
|
||||
double src_min;
|
||||
double src_height;
|
||||
int32_t y;
|
||||
|
||||
if (!video_driver_get_viewport_info(&vp))
|
||||
return 0;
|
||||
|
||||
if (mouse->y_min < mouse->y_max) /* mouse coords are absolute */
|
||||
{
|
||||
src_min = mouse->y_min;
|
||||
src_height = mouse->y_max - mouse->y_min + 1;
|
||||
}
|
||||
else /* mouse coords are viewport relative */
|
||||
{
|
||||
src_min = vp.y;
|
||||
if (screen)
|
||||
src_height = vp.full_height;
|
||||
else
|
||||
src_height = vp.height;
|
||||
}
|
||||
|
||||
y = -32767.0 + 65535.0 / src_height * (mouse->y_abs - src_min);
|
||||
y += (y < 0 ? -0.5 : 0.5);
|
||||
|
||||
if (y < -0x7fff)
|
||||
y = -0x7fff;
|
||||
else if(y > 0x7fff)
|
||||
y = 0x7fff;
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
static void udev_handle_mouse(void *data,
|
||||
const struct input_event *event, udev_input_device_t *dev)
|
||||
{
|
||||
udev_input_mouse_t *mouse = &dev->state.mouse;
|
||||
udev_input_mouse_t *mouse = &dev->mouse;
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
@ -303,10 +411,10 @@ static void udev_handle_mouse(void *data,
|
||||
switch (event->code)
|
||||
{
|
||||
case REL_X:
|
||||
mouse->dlt_x += event->value;
|
||||
udev_mouse_set_x(mouse, event->value, false);
|
||||
break;
|
||||
case REL_Y:
|
||||
mouse->dlt_y += event->value;
|
||||
udev_mouse_set_y(mouse, event->value, false);
|
||||
break;
|
||||
case REL_WHEEL:
|
||||
if (event->value == 1)
|
||||
@ -321,6 +429,19 @@ static void udev_handle_mouse(void *data,
|
||||
mouse->whd = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_ABS:
|
||||
switch (event->code)
|
||||
{
|
||||
case ABS_X:
|
||||
udev_mouse_set_x(mouse, event->value, true);
|
||||
break;
|
||||
case ABS_Y:
|
||||
udev_mouse_set_y(mouse, event->value, true);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -330,6 +451,7 @@ static bool udev_input_add_device(udev_input_t *udev,
|
||||
int fd;
|
||||
struct stat st;
|
||||
struct epoll_event event;
|
||||
struct input_absinfo absinfo;
|
||||
udev_input_device_t **tmp;
|
||||
udev_input_device_t *device = NULL;
|
||||
|
||||
@ -354,10 +476,38 @@ static bool udev_input_add_device(udev_input_t *udev,
|
||||
strlcpy(device->devnode, devnode, sizeof(device->devnode));
|
||||
|
||||
/* Touchpads report in absolute coords. */
|
||||
if (type == UDEV_INPUT_TOUCHPAD &&
|
||||
(ioctl(fd, EVIOCGABS(ABS_X), &device->state.touchpad.info_x) < 0 ||
|
||||
ioctl(fd, EVIOCGABS(ABS_Y), &device->state.touchpad.info_y) < 0))
|
||||
goto error;
|
||||
if (type == UDEV_INPUT_TOUCHPAD)
|
||||
{
|
||||
if (ioctl(fd, EVIOCGABS(ABS_X), &absinfo) < 0 ||
|
||||
absinfo.minimum >= absinfo.maximum)
|
||||
goto error;
|
||||
|
||||
device->mouse.x_min = absinfo.minimum;
|
||||
device->mouse.x_max = absinfo.maximum;
|
||||
|
||||
if (ioctl(fd, EVIOCGABS(ABS_Y), &absinfo) < 0 ||
|
||||
absinfo.minimum >= absinfo.maximum)
|
||||
goto error;
|
||||
|
||||
device->mouse.y_min = absinfo.minimum;
|
||||
device->mouse.y_max = absinfo.maximum;
|
||||
}
|
||||
/* UDEV_INPUT_MOUSE may report in absolute coords too */
|
||||
else if (type == UDEV_INPUT_MOUSE && ioctl(fd, EVIOCGABS(ABS_X), &absinfo) >= 0)
|
||||
{
|
||||
if (absinfo.minimum >= absinfo.maximum)
|
||||
goto error;
|
||||
|
||||
device->mouse.x_min = absinfo.minimum;
|
||||
device->mouse.x_max = absinfo.maximum;
|
||||
|
||||
if (ioctl(fd, EVIOCGABS(ABS_Y), &absinfo) < 0 ||
|
||||
absinfo.minimum >= absinfo.maximum)
|
||||
goto error;
|
||||
|
||||
device->mouse.y_min = absinfo.minimum;
|
||||
device->mouse.y_max = absinfo.maximum;
|
||||
}
|
||||
|
||||
tmp = ( udev_input_device_t**)realloc(udev->devices,
|
||||
(udev->num_devices + 1) * sizeof(*udev->devices));
|
||||
@ -440,7 +590,7 @@ static void udev_input_handle_hotplug(udev_input_t *udev)
|
||||
else if (val_touchpad && string_is_equal_fast(val_touchpad, "1", 1) && devnode)
|
||||
{
|
||||
dev_type = UDEV_INPUT_TOUCHPAD;
|
||||
cb = udev_handle_touchpad;
|
||||
cb = udev_handle_mouse;
|
||||
}
|
||||
else
|
||||
goto end;
|
||||
@ -477,11 +627,11 @@ static void udev_input_get_pointer_position(int *x, int *y)
|
||||
|
||||
static bool udev_input_poll_hotplug_available(struct udev_monitor *dev)
|
||||
{
|
||||
struct pollfd fds;
|
||||
struct pollfd fds;
|
||||
|
||||
fds.fd = udev_monitor_get_fd(dev);
|
||||
fds.events = POLLIN;
|
||||
fds.revents = 0;
|
||||
fds.fd = udev_monitor_get_fd(dev);
|
||||
fds.events = POLLIN;
|
||||
fds.revents = 0;
|
||||
|
||||
return (poll(&fds, 1, 0) == 1) && (fds.revents & POLLIN);
|
||||
}
|
||||
@ -491,30 +641,22 @@ static void udev_input_poll(void *data)
|
||||
int i, ret;
|
||||
struct epoll_event events[32];
|
||||
udev_input_mouse_t *mouse = NULL;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
udev_input_t *udev = (udev_input_t*)data;
|
||||
|
||||
#ifdef HAVE_X11
|
||||
if (video_driver_display_type_get() == RARCH_DISPLAY_X11)
|
||||
udev_input_get_pointer_position(&x, &y);
|
||||
udev_input_get_pointer_position(&udev->pointer_x, &udev->pointer_y);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < udev->num_devices; ++i)
|
||||
{
|
||||
if (udev->devices[i]->type == UDEV_INPUT_MOUSE)
|
||||
{
|
||||
mouse = &udev->devices[i]->state.mouse;
|
||||
mouse->x = x;
|
||||
mouse->y = y;
|
||||
}
|
||||
else if (udev->devices[i]->type == UDEV_INPUT_TOUCHPAD)
|
||||
mouse = &udev->devices[i]->state.touchpad.mouse;
|
||||
else
|
||||
if (udev->devices[i]->type == UDEV_INPUT_KEYBOARD)
|
||||
continue;
|
||||
|
||||
mouse->dlt_x = 0;
|
||||
mouse->dlt_y = 0;
|
||||
mouse = &udev->devices[i]->mouse;
|
||||
|
||||
mouse->x_rel = 0;
|
||||
mouse->y_rel = 0;
|
||||
mouse->wu = false;
|
||||
mouse->wd = false;
|
||||
mouse->whu = false;
|
||||
@ -548,18 +690,22 @@ static void udev_input_poll(void *data)
|
||||
udev->joypad->poll();
|
||||
}
|
||||
|
||||
static bool udev_pointer_is_off_window(udev_input_mouse_t *mouse)
|
||||
static bool udev_pointer_is_off_window(const udev_input_t *udev)
|
||||
{
|
||||
#ifdef HAVE_X11
|
||||
struct video_viewport view;
|
||||
bool r = video_driver_get_viewport_info(&view);
|
||||
|
||||
if (r)
|
||||
r = mouse->x < view.x ||
|
||||
mouse->x >= view.x + view.width ||
|
||||
mouse->y < view.y ||
|
||||
mouse->y >= view.y + view.height;
|
||||
r = udev->pointer_x < view.x ||
|
||||
udev->pointer_x >= view.x + view.width ||
|
||||
udev->pointer_y < view.y ||
|
||||
udev->pointer_y >= view.y + view.height;
|
||||
|
||||
return r;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int16_t udev_mouse_state(udev_input_t *udev,
|
||||
@ -571,15 +717,15 @@ static int16_t udev_mouse_state(udev_input_t *udev,
|
||||
return 0;
|
||||
|
||||
if (id != RETRO_DEVICE_ID_MOUSE_X && id != RETRO_DEVICE_ID_MOUSE_Y &&
|
||||
udev_pointer_is_off_window(mouse))
|
||||
udev_pointer_is_off_window(udev))
|
||||
return 0;
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case RETRO_DEVICE_ID_MOUSE_X:
|
||||
return screen ? mouse->x : mouse->dlt_x;
|
||||
return screen ? udev->pointer_x : udev_mouse_get_x(mouse);
|
||||
case RETRO_DEVICE_ID_MOUSE_Y:
|
||||
return screen ? mouse->y : mouse->dlt_y;
|
||||
return screen ? udev->pointer_y : udev_mouse_get_y(mouse);
|
||||
case RETRO_DEVICE_ID_MOUSE_LEFT:
|
||||
return mouse->l;
|
||||
case RETRO_DEVICE_ID_MOUSE_RIGHT:
|
||||
@ -610,9 +756,9 @@ static int16_t udev_lightgun_state(udev_input_t *udev,
|
||||
switch (id)
|
||||
{
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_X:
|
||||
return mouse->dlt_x;
|
||||
return udev_mouse_get_x(mouse);
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_Y:
|
||||
return mouse->dlt_y;
|
||||
return udev_mouse_get_y(mouse);
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_TRIGGER:
|
||||
return mouse->l;
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_CURSOR:
|
||||
@ -638,11 +784,11 @@ static int16_t udev_analog_pressed(const struct retro_keybind *binds,
|
||||
|
||||
input_conv_analog_id_to_bind_id(idx, id, &id_minus, &id_plus);
|
||||
|
||||
if ( binds[id_minus].valid
|
||||
if ( binds[id_minus].valid
|
||||
&& BIT_GET(udev_key_state,
|
||||
rarch_keysym_lut[binds[id_minus].key]))
|
||||
pressed_minus = -0x7fff;
|
||||
if ( binds[id_plus].valid
|
||||
if ( binds[id_plus].valid
|
||||
&& BIT_GET(udev_key_state,
|
||||
rarch_keysym_lut[binds[id_plus].key]))
|
||||
pressed_plus = 0x7fff;
|
||||
@ -653,45 +799,17 @@ static int16_t udev_analog_pressed(const struct retro_keybind *binds,
|
||||
static int16_t udev_pointer_state(udev_input_t *udev,
|
||||
unsigned port, unsigned id, bool screen)
|
||||
{
|
||||
struct video_viewport vp;
|
||||
bool inside = false;
|
||||
int16_t res_x = 0;
|
||||
int16_t res_y = 0;
|
||||
int16_t res_screen_x = 0;
|
||||
int16_t res_screen_y = 0;
|
||||
udev_input_mouse_t *mouse = udev_get_mouse(udev, port);
|
||||
|
||||
vp.x = 0;
|
||||
vp.y = 0;
|
||||
vp.width = 0;
|
||||
vp.height = 0;
|
||||
vp.full_width = 0;
|
||||
vp.full_height = 0;
|
||||
udev_input_mouse_t *mouse = udev_get_mouse(udev, port);
|
||||
|
||||
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;
|
||||
|
||||
if (screen)
|
||||
{
|
||||
res_x = res_screen_x;
|
||||
res_y = res_screen_y;
|
||||
}
|
||||
|
||||
inside = (res_x >= -0x7fff) && (res_y >= -0x7fff);
|
||||
|
||||
if (!inside)
|
||||
return 0;
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case RETRO_DEVICE_ID_POINTER_X:
|
||||
return res_x;
|
||||
return udev_mouse_get_pointer_x(mouse, screen);
|
||||
case RETRO_DEVICE_ID_POINTER_Y:
|
||||
return res_y;
|
||||
return udev_mouse_get_pointer_y(mouse, screen);
|
||||
case RETRO_DEVICE_ID_POINTER_PRESSED:
|
||||
return mouse->l;
|
||||
}
|
||||
@ -878,13 +996,13 @@ static void *udev_input_init(const char *joypad_driver)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!open_devices(udev, UDEV_INPUT_TOUCHPAD, udev_handle_touchpad))
|
||||
if (!open_devices(udev, UDEV_INPUT_TOUCHPAD, udev_handle_mouse))
|
||||
{
|
||||
RARCH_ERR("Failed to open touchpads.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* If using KMS and we forgot this,
|
||||
/* If using KMS and we forgot this,
|
||||
* we could lock ourselves out completely. */
|
||||
if (!udev->num_devices)
|
||||
RARCH_WARN("[udev]: Couldn't open any keyboard, mouse or touchpad. Are permissions set correctly for /dev/input/event*?\n");
|
||||
|
Loading…
x
Reference in New Issue
Block a user