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 XIM g_x11_xim;
|
||||||
static XIC g_x11_xic;
|
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)
|
static void x11_hide_mouse(Display *dpy, Window win)
|
||||||
{
|
{
|
||||||
Cursor no_ptr;
|
Cursor no_ptr;
|
||||||
|
@ -352,9 +356,39 @@ void x11_exit_fullscreen(Display *dpy)
|
||||||
XF86VidModeSetViewPort(dpy, DefaultScreen(dpy), 0, 0);
|
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)
|
bool x11_create_input_context(Display *dpy, Window win, XIM *xim, XIC *xic)
|
||||||
{
|
{
|
||||||
x11_destroy_input_context(xim, xic);
|
x11_destroy_input_context(xim, xic);
|
||||||
|
x11_init_keyboard_lut();
|
||||||
|
|
||||||
g_x11_has_focus = true;
|
g_x11_has_focus = true;
|
||||||
*xim = XOpenIM(dpy, NULL, NULL, NULL);
|
*xim = XOpenIM(dpy, NULL, NULL, NULL);
|
||||||
|
@ -391,6 +425,14 @@ void x11_destroy_input_context(XIM *xim, XIC *xic)
|
||||||
XCloseIM(*xim);
|
XCloseIM(*xim);
|
||||||
*xim = NULL;
|
*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,
|
bool x11_get_metrics(void *data,
|
||||||
|
@ -433,6 +475,26 @@ bool x11_get_metrics(void *data,
|
||||||
return true;
|
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)
|
static void x11_handle_key_event(unsigned keycode, XEvent *event, XIC ic, bool filter)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -486,7 +548,7 @@ static void x11_handle_key_event(unsigned keycode, XEvent *event, XIC ic, bool f
|
||||||
|
|
||||||
/* Get the real keycode,
|
/* Get the real keycode,
|
||||||
that correctly ignores international layouts as windows code does. */
|
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)
|
if (state & ShiftMask)
|
||||||
mod |= RETROKMOD_SHIFT;
|
mod |= RETROKMOD_SHIFT;
|
||||||
|
|
|
@ -196,14 +196,41 @@ static void udev_handle_keyboard(void *data,
|
||||||
else
|
else
|
||||||
BIT_CLEAR(udev->state, keysym);
|
BIT_CLEAR(udev->state, keysym);
|
||||||
|
|
||||||
|
/* 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
|
#ifdef UDEV_XKB_HANDLING
|
||||||
if (udev->xkb_handling && handle_xkb(keysym, event->value) == 0)
|
if (udev->xkb_handling && handle_xkb(keysym, event->value) == 0)
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
input_keyboard_event(event->value,
|
input_keyboard_event(event->value,
|
||||||
input_keymaps_translate_keysym_to_rk(keysym),
|
input_keymaps_translate_keysym_to_rk(keysym),
|
||||||
0, 0, RETRO_DEVICE_KEYBOARD);
|
0, 0, RETRO_DEVICE_KEYBOARD);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -486,35 +513,32 @@ static void udev_handle_mouse(void *data,
|
||||||
static int udev_input_add_device(udev_input_t *udev,
|
static int udev_input_add_device(udev_input_t *udev,
|
||||||
enum udev_input_dev_type type, const char *devnode, device_handle_cb cb)
|
enum udev_input_dev_type type, const char *devnode, device_handle_cb cb)
|
||||||
{
|
{
|
||||||
unsigned char keycaps[(KEY_MAX / 8) + 1];
|
unsigned char keycaps[(KEY_MAX / 8) + 1] = {'\0'};
|
||||||
unsigned char abscaps[(ABS_MAX / 8) + 1];
|
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 has_absolutes = 0;
|
||||||
int fd;
|
int fd = -1;
|
||||||
|
int ret = 0;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
#if defined(HAVE_EPOLL)
|
#if defined(HAVE_EPOLL)
|
||||||
struct epoll_event event;
|
struct epoll_event event;
|
||||||
#elif defined(HAVE_KQUEUE)
|
#elif defined(HAVE_KQUEUE)
|
||||||
struct kevent event;
|
struct kevent event;
|
||||||
#endif
|
#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)
|
if (stat(devnode, &st) < 0)
|
||||||
return false;
|
goto end;
|
||||||
|
|
||||||
fd = open(devnode, O_RDONLY | O_NONBLOCK);
|
fd = open(devnode, O_RDONLY | O_NONBLOCK);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return false;
|
goto end;
|
||||||
|
|
||||||
device = (udev_input_device_t*)calloc(1, sizeof(*device));
|
device = (udev_input_device_t*)calloc(1, sizeof(*device));
|
||||||
if (!device)
|
if (!device)
|
||||||
goto error;
|
goto end;
|
||||||
|
|
||||||
device->fd = fd;
|
device->fd = fd;
|
||||||
device->dev = st.st_dev;
|
device->dev = st.st_dev;
|
||||||
|
@ -526,10 +550,12 @@ static int udev_input_add_device(udev_input_t *udev,
|
||||||
/* UDEV_INPUT_MOUSE may report in absolute coords too */
|
/* UDEV_INPUT_MOUSE may report in absolute coords too */
|
||||||
if (type == UDEV_INPUT_MOUSE || type == UDEV_INPUT_TOUCHPAD )
|
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)
|
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 (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof (abscaps)), abscaps) != -1)
|
||||||
{
|
{
|
||||||
|
@ -543,29 +569,32 @@ static int udev_input_add_device(udev_input_t *udev,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
device->mouse.x_min = device->mouse.y_min = device->mouse.x_max = device->mouse.y_max = 0;
|
|
||||||
|
device->mouse.x_min = 0;
|
||||||
|
device->mouse.y_min = 0;
|
||||||
|
device->mouse.x_max = 0;
|
||||||
|
device->mouse.y_max = 0;
|
||||||
|
|
||||||
if (has_absolutes)
|
if (has_absolutes)
|
||||||
{
|
{
|
||||||
struct input_absinfo absinfo;
|
struct input_absinfo absinfo;
|
||||||
if (ioctl(fd, EVIOCGABS(ABS_X), &absinfo) == -1)
|
if (ioctl(fd, EVIOCGABS(ABS_X), &absinfo) == -1)
|
||||||
return 0;
|
goto end;
|
||||||
device->mouse.x_min = absinfo.minimum;
|
device->mouse.x_min = absinfo.minimum;
|
||||||
device->mouse.x_max = absinfo.maximum;
|
device->mouse.x_max = absinfo.maximum;
|
||||||
|
|
||||||
if (ioctl(fd, EVIOCGABS(ABS_Y), &absinfo) == -1)
|
if (ioctl(fd, EVIOCGABS(ABS_Y), &absinfo) == -1)
|
||||||
return 0;
|
goto end;
|
||||||
device->mouse.y_min = absinfo.minimum;
|
device->mouse.y_min = absinfo.minimum;
|
||||||
device->mouse.y_max = absinfo.maximum;
|
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));
|
(udev->num_devices + 1) * sizeof(*udev->devices));
|
||||||
|
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
goto error;
|
goto end;
|
||||||
|
|
||||||
tmp[udev->num_devices++] = device;
|
tmp[udev->num_devices++] = device;
|
||||||
udev->devices = tmp;
|
udev->devices = tmp;
|
||||||
|
@ -589,14 +618,20 @@ static int udev_input_add_device(udev_input_t *udev,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
ret = 1;
|
||||||
|
|
||||||
error:
|
end:
|
||||||
|
/* Free resources in the event of
|
||||||
|
* an error */
|
||||||
|
if (ret != 1)
|
||||||
|
{
|
||||||
|
if (fd >= 0)
|
||||||
close(fd);
|
close(fd);
|
||||||
if (device)
|
if (device)
|
||||||
free(device);
|
free(device);
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void udev_input_remove_device(udev_input_t *udev, const char *devnode)
|
static void udev_input_remove_device(udev_input_t *udev, const char *devnode)
|
||||||
|
|
Loading…
Reference in New Issue