mirror of
https://github.com/libretro/RetroArch.git
synced 2025-02-25 20:32:22 +00:00
Add workaround to fix keyboard input when using x11+udev (#12981)
This commit is contained in:
parent
3c6bdfd0d8
commit
12f787547c
@ -79,6 +79,10 @@ static Atom g_x11_quit_atom;
|
||||
static XIM g_x11_xim;
|
||||
static XIC g_x11_xic;
|
||||
|
||||
static enum retro_key x11_keysym_lut[RETROK_LAST];
|
||||
static unsigned *x11_keysym_rlut = NULL;
|
||||
static unsigned x11_keysym_rlut_size = 0;
|
||||
|
||||
static void x11_hide_mouse(Display *dpy, Window win)
|
||||
{
|
||||
Cursor no_ptr;
|
||||
@ -352,9 +356,39 @@ void x11_exit_fullscreen(Display *dpy)
|
||||
XF86VidModeSetViewPort(dpy, DefaultScreen(dpy), 0, 0);
|
||||
}
|
||||
|
||||
static void x11_init_keyboard_lut(void)
|
||||
{
|
||||
const struct rarch_key_map *map = rarch_key_map_x11;
|
||||
const struct rarch_key_map *map_start = rarch_key_map_x11;
|
||||
|
||||
memset(x11_keysym_lut, 0, sizeof(x11_keysym_lut));
|
||||
x11_keysym_rlut_size = 0;
|
||||
|
||||
for (; map->rk != RETROK_UNKNOWN; map++)
|
||||
{
|
||||
x11_keysym_lut[map->rk] = (enum retro_key)map->sym;
|
||||
if (map->sym > x11_keysym_rlut_size)
|
||||
x11_keysym_rlut_size = map->sym;
|
||||
}
|
||||
|
||||
if (x11_keysym_rlut_size < 65536)
|
||||
{
|
||||
if (x11_keysym_rlut)
|
||||
free(x11_keysym_rlut);
|
||||
|
||||
x11_keysym_rlut = (unsigned*)calloc(++x11_keysym_rlut_size, sizeof(unsigned));
|
||||
|
||||
for (map = map_start; map->rk != RETROK_UNKNOWN; map++)
|
||||
x11_keysym_rlut[map->sym] = (enum retro_key)map->rk;
|
||||
}
|
||||
else
|
||||
x11_keysym_rlut_size = 0;
|
||||
}
|
||||
|
||||
bool x11_create_input_context(Display *dpy, Window win, XIM *xim, XIC *xic)
|
||||
{
|
||||
x11_destroy_input_context(xim, xic);
|
||||
x11_init_keyboard_lut();
|
||||
|
||||
g_x11_has_focus = true;
|
||||
*xim = XOpenIM(dpy, NULL, NULL, NULL);
|
||||
@ -391,6 +425,14 @@ void x11_destroy_input_context(XIM *xim, XIC *xic)
|
||||
XCloseIM(*xim);
|
||||
*xim = NULL;
|
||||
}
|
||||
|
||||
memset(x11_keysym_lut, 0, sizeof(x11_keysym_lut));
|
||||
if (x11_keysym_rlut)
|
||||
{
|
||||
free(x11_keysym_rlut);
|
||||
x11_keysym_rlut = NULL;
|
||||
}
|
||||
x11_keysym_rlut_size = 0;
|
||||
}
|
||||
|
||||
bool x11_get_metrics(void *data,
|
||||
@ -433,6 +475,26 @@ bool x11_get_metrics(void *data,
|
||||
return true;
|
||||
}
|
||||
|
||||
static enum retro_key x11_translate_keysym_to_rk(unsigned sym)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
/* Fast path */
|
||||
if (x11_keysym_rlut && sym < x11_keysym_rlut_size)
|
||||
return (enum retro_key)x11_keysym_rlut[sym];
|
||||
|
||||
/* Slow path */
|
||||
for (i = 0; i < ARRAY_SIZE(x11_keysym_lut); i++)
|
||||
{
|
||||
if (x11_keysym_lut[i] != sym)
|
||||
continue;
|
||||
|
||||
return (enum retro_key)i;
|
||||
}
|
||||
|
||||
return RETROK_UNKNOWN;
|
||||
}
|
||||
|
||||
static void x11_handle_key_event(unsigned keycode, XEvent *event, XIC ic, bool filter)
|
||||
{
|
||||
int i;
|
||||
@ -486,7 +548,7 @@ static void x11_handle_key_event(unsigned keycode, XEvent *event, XIC ic, bool f
|
||||
|
||||
/* Get the real keycode,
|
||||
that correctly ignores international layouts as windows code does. */
|
||||
key = input_keymaps_translate_keysym_to_rk(keycode);
|
||||
key = x11_translate_keysym_to_rk(keycode);
|
||||
|
||||
if (state & ShiftMask)
|
||||
mod |= RETROKMOD_SHIFT;
|
||||
|
@ -196,14 +196,41 @@ static void udev_handle_keyboard(void *data,
|
||||
else
|
||||
BIT_CLEAR(udev->state, keysym);
|
||||
|
||||
#ifdef UDEV_XKB_HANDLING
|
||||
if (udev->xkb_handling && handle_xkb(keysym, event->value) == 0)
|
||||
return;
|
||||
#endif
|
||||
/* TODO/FIXME: The udev driver is incomplete.
|
||||
* When calling input_keyboard_event() the
|
||||
* following parameters are omitted:
|
||||
* - character: the localised Unicode/UTF-8
|
||||
* value of the pressed key
|
||||
* - mod: the current keyboard modifier
|
||||
* bitmask
|
||||
* Without these values, input_keyboard_event()
|
||||
* does not function correctly (e.g. it is
|
||||
* impossible to use text entry in the menu).
|
||||
* I cannot find any usable reference for
|
||||
* converting a udev-returned key code into a
|
||||
* localised Unicode/UTF-8 value, so for the
|
||||
* time being we must rely on other sources:
|
||||
* - If we are using an X11-based context driver,
|
||||
* input_keyboard_event() is handled correctly
|
||||
* in x11_common:x11_check_window()
|
||||
* - If we are using KMS, input_keyboard_event()
|
||||
* is handled correctly in
|
||||
* keyboard_event_xkb:handle_xkb()
|
||||
* If neither are available, then just call
|
||||
* input_keyboard_event() without character and
|
||||
* mod, and hope for the best... */
|
||||
|
||||
if (video_driver_display_type_get() != RARCH_DISPLAY_X11)
|
||||
{
|
||||
#ifdef UDEV_XKB_HANDLING
|
||||
if (udev->xkb_handling && handle_xkb(keysym, event->value) == 0)
|
||||
return;
|
||||
#endif
|
||||
input_keyboard_event(event->value,
|
||||
input_keymaps_translate_keysym_to_rk(keysym),
|
||||
0, 0, RETRO_DEVICE_KEYBOARD);
|
||||
}
|
||||
|
||||
input_keyboard_event(event->value,
|
||||
input_keymaps_translate_keysym_to_rk(keysym),
|
||||
0, 0, RETRO_DEVICE_KEYBOARD);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -486,35 +513,32 @@ static void udev_handle_mouse(void *data,
|
||||
static int udev_input_add_device(udev_input_t *udev,
|
||||
enum udev_input_dev_type type, const char *devnode, device_handle_cb cb)
|
||||
{
|
||||
unsigned char keycaps[(KEY_MAX / 8) + 1];
|
||||
unsigned char abscaps[(ABS_MAX / 8) + 1];
|
||||
int has_absolutes = 0;
|
||||
int fd;
|
||||
unsigned char keycaps[(KEY_MAX / 8) + 1] = {'\0'};
|
||||
unsigned char abscaps[(ABS_MAX / 8) + 1] = {'\0'};
|
||||
udev_input_device_t **tmp = NULL;
|
||||
udev_input_device_t *device = NULL;
|
||||
int has_absolutes = 0;
|
||||
int fd = -1;
|
||||
int ret = 0;
|
||||
struct stat st;
|
||||
#if defined(HAVE_EPOLL)
|
||||
struct epoll_event event;
|
||||
#elif defined(HAVE_KQUEUE)
|
||||
struct kevent event;
|
||||
#endif
|
||||
struct input_absinfo absinfo;
|
||||
udev_input_device_t **tmp;
|
||||
udev_input_device_t *device = NULL;
|
||||
|
||||
memset(keycaps, '\0', sizeof (keycaps));
|
||||
memset(keycaps, '\0', sizeof (abscaps));
|
||||
|
||||
st.st_dev = 0;
|
||||
st.st_dev = 0;
|
||||
|
||||
if (stat(devnode, &st) < 0)
|
||||
return false;
|
||||
goto end;
|
||||
|
||||
fd = open(devnode, O_RDONLY | O_NONBLOCK);
|
||||
if (fd < 0)
|
||||
return false;
|
||||
goto end;
|
||||
|
||||
device = (udev_input_device_t*)calloc(1, sizeof(*device));
|
||||
if (!device)
|
||||
goto error;
|
||||
goto end;
|
||||
|
||||
device->fd = fd;
|
||||
device->dev = st.st_dev;
|
||||
@ -526,46 +550,51 @@ static int udev_input_add_device(udev_input_t *udev,
|
||||
/* UDEV_INPUT_MOUSE may report in absolute coords too */
|
||||
if (type == UDEV_INPUT_MOUSE || type == UDEV_INPUT_TOUCHPAD )
|
||||
{
|
||||
/* gotta have some buttons! return -1 to skip error logging for this:) */
|
||||
if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof (keycaps)), keycaps) == -1)
|
||||
return -1; /* gotta have some buttons! return -1 to skip error logging for this:) */
|
||||
|
||||
|
||||
{
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof (abscaps)), abscaps) != -1)
|
||||
{
|
||||
if ( (test_bit(abscaps, ABS_X)) && (test_bit(abscaps, ABS_Y)) )
|
||||
{
|
||||
/* might be a touchpad... */
|
||||
if (test_bit(keycaps, BTN_TOUCH))
|
||||
{
|
||||
/* touchpad, touchscreen, or tablet. */
|
||||
has_absolutes = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
device->mouse.x_min = device->mouse.y_min = device->mouse.x_max = device->mouse.y_max = 0;
|
||||
if ( (test_bit(abscaps, ABS_X)) && (test_bit(abscaps, ABS_Y)) )
|
||||
{
|
||||
/* might be a touchpad... */
|
||||
if (test_bit(keycaps, BTN_TOUCH))
|
||||
{
|
||||
/* touchpad, touchscreen, or tablet. */
|
||||
has_absolutes = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
device->mouse.x_min = 0;
|
||||
device->mouse.y_min = 0;
|
||||
device->mouse.x_max = 0;
|
||||
device->mouse.y_max = 0;
|
||||
|
||||
if (has_absolutes)
|
||||
{
|
||||
struct input_absinfo absinfo;
|
||||
if (ioctl(fd, EVIOCGABS(ABS_X), &absinfo) == -1)
|
||||
return 0;
|
||||
device->mouse.x_min = absinfo.minimum;
|
||||
device->mouse.x_max = absinfo.maximum;
|
||||
struct input_absinfo absinfo;
|
||||
if (ioctl(fd, EVIOCGABS(ABS_X), &absinfo) == -1)
|
||||
goto end;
|
||||
device->mouse.x_min = absinfo.minimum;
|
||||
device->mouse.x_max = absinfo.maximum;
|
||||
|
||||
if (ioctl(fd, EVIOCGABS(ABS_Y), &absinfo) == -1)
|
||||
return 0;
|
||||
device->mouse.y_min = absinfo.minimum;
|
||||
device->mouse.y_max = absinfo.maximum;
|
||||
if (ioctl(fd, EVIOCGABS(ABS_Y), &absinfo) == -1)
|
||||
goto end;
|
||||
device->mouse.y_min = absinfo.minimum;
|
||||
device->mouse.y_max = absinfo.maximum;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
tmp = ( udev_input_device_t**)realloc(udev->devices,
|
||||
tmp = (udev_input_device_t**)realloc(udev->devices,
|
||||
(udev->num_devices + 1) * sizeof(*udev->devices));
|
||||
|
||||
if (!tmp)
|
||||
goto error;
|
||||
goto end;
|
||||
|
||||
tmp[udev->num_devices++] = device;
|
||||
udev->devices = tmp;
|
||||
@ -589,14 +618,20 @@ static int udev_input_add_device(udev_input_t *udev,
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
ret = 1;
|
||||
|
||||
error:
|
||||
close(fd);
|
||||
if (device)
|
||||
free(device);
|
||||
end:
|
||||
/* Free resources in the event of
|
||||
* an error */
|
||||
if (ret != 1)
|
||||
{
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
if (device)
|
||||
free(device);
|
||||
}
|
||||
|
||||
return false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void udev_input_remove_device(udev_input_t *udev, const char *devnode)
|
||||
|
Loading…
x
Reference in New Issue
Block a user