efl-wl: create and maintain xserver-based keymap and keyboard states under x11

when run in a non-wayland environment, it's necessary to do some extra work
in order to guarantee that the keymap remains the same in the compositor as
in the xserver and to also guarantee that modifier states are accurately
applied even when the compositor is not actively focused

fix T6631
This commit is contained in:
Mike Blumenkrantz 2018-01-24 16:16:17 -05:00
parent 6e4c3b0445
commit a32735e9a7
4 changed files with 201 additions and 25 deletions

View File

@ -3807,6 +3807,7 @@ EFL_OPTIONAL_INTERNAL_DEPEND_PKG([EFL_WL], [${want_x11_any}], [ecore_x])
EFL_DEPEND_PKG([EFL_WL], [WAYLAND],
[wayland-server >= 1.11.0 xkbcommon >= 0.6.0])
EFL_OPTIONAL_DEPEND_PKG([EFL_WL], [${want_x11_any}], [XKBCOMMONX11], [xkbcommon-x11])
EFL_EVAL_PKGS([EFL_WL])

View File

@ -356,3 +356,53 @@ drag_grab_button(Comp_Seat *s,
#endif
}
}
#ifdef HAVE_ECORE_X
static xkb_mod_index_t x11_kbd_shift_mod;
static xkb_mod_index_t x11_kbd_caps_mod;
static xkb_mod_index_t x11_kbd_ctrl_mod;
static xkb_mod_index_t x11_kbd_alt_mod;
static xkb_mod_index_t x11_kbd_mod2_mod;
static xkb_mod_index_t x11_kbd_mod3_mod;
static xkb_mod_index_t x11_kbd_super_mod;
static xkb_mod_index_t x11_kbd_mod5_mod;
static void
keymap_mods_init(struct xkb_keymap *keymap)
{
x11_kbd_shift_mod = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT);
x11_kbd_caps_mod = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS);
x11_kbd_ctrl_mod = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL);
x11_kbd_alt_mod = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_ALT);
x11_kbd_mod2_mod = xkb_keymap_mod_get_index(keymap, "Mod2");
x11_kbd_mod3_mod = xkb_keymap_mod_get_index(keymap, "Mod3");
x11_kbd_super_mod = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_LOGO);
x11_kbd_mod5_mod = xkb_keymap_mod_get_index(keymap, "Mod5");
}
static uint32_t
get_xkb_mod_mask(uint32_t in)
{
uint32_t ret = 0;
if ((in & ECORE_X_MODIFIER_SHIFT) && x11_kbd_shift_mod != XKB_MOD_INVALID)
ret |= (1 << x11_kbd_shift_mod);
if ((in & ECORE_X_LOCK_CAPS) && x11_kbd_caps_mod != XKB_MOD_INVALID)
ret |= (1 << x11_kbd_caps_mod);
if ((in & ECORE_X_MODIFIER_CTRL) && x11_kbd_ctrl_mod != XKB_MOD_INVALID)
ret |= (1 << x11_kbd_ctrl_mod);
if ((in & ECORE_X_MODIFIER_ALT) && x11_kbd_alt_mod != XKB_MOD_INVALID)
ret |= (1 << x11_kbd_alt_mod);
if ((in & ECORE_X_LOCK_NUM) && x11_kbd_mod2_mod != XKB_MOD_INVALID)
ret |= (1 << x11_kbd_mod2_mod);
if ((in & ECORE_X_LOCK_SCROLL) && x11_kbd_mod3_mod != XKB_MOD_INVALID)
ret |= (1 << x11_kbd_mod3_mod);
if ((in & ECORE_X_MODIFIER_WIN) && x11_kbd_super_mod != XKB_MOD_INVALID)
ret |= (1 << x11_kbd_super_mod);
if ((in & ECORE_X_MODIFIER_ALTGR) && x11_kbd_mod5_mod != XKB_MOD_INVALID)
ret |= (1 << x11_kbd_mod5_mod);
return ret;
}
#endif

View File

@ -3710,26 +3710,32 @@ seat_keymap_update(Comp_Seat *s)
Eina_Tmpstr *file;
xkb_mod_mask_t latched = 0, locked = 0;
if (s->kbd.keymap_mem) munmap(s->kbd.keymap_mem, s->kbd.keymap_mem_size);
if (s->kbd.keymap_fd > -1) close(s->kbd.keymap_fd);
if (s->kbd.state)
#ifdef HAVE_ECORE_X
if (!x11_kbd_keymap)
{
latched = xkb_state_serialize_mods(s->kbd.state, XKB_STATE_MODS_LATCHED);
locked = xkb_state_serialize_mods(s->kbd.state, XKB_STATE_MODS_LOCKED);
xkb_state_unref(s->kbd.state);
}
if (!s->kbd.keymap)
{
s->kbd.state = NULL;
s->kbd.keymap_fd = -1;
s->kbd.keymap_mem = NULL;
return;
}
#endif
if (s->kbd.keymap_mem) munmap(s->kbd.keymap_mem, s->kbd.keymap_mem_size);
if (s->kbd.keymap_fd > -1) close(s->kbd.keymap_fd);
s->kbd.state = xkb_state_new(s->kbd.keymap);
xkb_state_update_mask(s->kbd.state, 0, latched, locked, 0, 0, 0);
if (s->kbd.state)
{
latched = xkb_state_serialize_mods(s->kbd.state, XKB_STATE_MODS_LATCHED);
locked = xkb_state_serialize_mods(s->kbd.state, XKB_STATE_MODS_LOCKED);
xkb_state_unref(s->kbd.state);
}
if (!s->kbd.keymap)
{
s->kbd.state = NULL;
s->kbd.keymap_fd = -1;
s->kbd.keymap_mem = NULL;
return;
}
s->kbd.state = xkb_state_new(s->kbd.keymap);
xkb_state_update_mask(s->kbd.state, 0, latched, locked, 0, 0, 0);
#ifdef HAVE_ECORE_X
}
#endif
str = xkb_map_get_as_string(s->kbd.keymap);
s->kbd.keymap_mem_size = strlen(str) + 1;
s->kbd.keymap_fd = eina_file_mkstemp("comp-keymapXXXXXX", &file);
@ -4395,6 +4401,11 @@ comp_device_caps_update(Comp_Seat *s)
{
if (s->keyboard)
{
#ifdef HAVE_ECORE_X
if ((!s->c->parent_disp) && ecore_x_display_get())
x11_kbd_apply(s);
else
#endif
seat_keymap_create(s);
seat_kbd_repeat_rate_update(s);
}
@ -4462,9 +4473,16 @@ comp_seats_proxy(Comp *c)
if (s->kbd.keymap) xkb_keymap_ref(s->kbd.keymap);
}
else
seat_keymap_create(s);
seat_kbd_repeat_rate_update(s);
{
#ifdef HAVE_ECORE_X
if ((!s->c->parent_disp) && ecore_x_display_get())
x11_kbd_apply(s);
else
#endif
seat_keymap_create(s);
}
seat_keymap_update(s);
seat_kbd_repeat_rate_update(s);
s->keyboard = !!s->kbd.state;
}
}
@ -5339,6 +5357,7 @@ comp_smart_add(Evas_Object *obj)
#ifdef HAVE_ECORE_X
if (ecore_x_display_get())
{
ecore_x_xkb_track_state();
// if proxiedallowed
ecore_x_dnd_aware_set(ecore_evas_window_get(ecore_evas_ecore_evas_get(c->evas)), EINA_TRUE);
if (!comps) x11_init();

View File

@ -1,3 +1,5 @@
#include "xkbcommon/xkbcommon-x11.h"
#define WL_TEXT_STR "text/plain;charset=utf-8"
#define INCR_CHUNK_SIZE 1 << 17
@ -562,6 +564,99 @@ x11_dnd_move(void *data, Ecore_X_Xdnd_Position *pos)
evas_object_move(data, pos->position.x, pos->position.y);
}
static int32_t x11_core_device = -1;
static struct xkb_context *x11_kbd_context;
static struct xkb_keymap *x11_kbd_keymap;
static struct xkb_state *x11_kbd_state;
static Eina_Bool seat_kbd_mods_update(Comp_Seat *s);
static void comp_seat_send_modifiers(Comp_Seat *s, struct wl_resource *res, uint32_t serial);
static Eina_Bool
x11_xkb_state(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_X_Event_Xkb *ev)
{
Comp *c;
Eina_List *l;
Comp_Seat *s;
if (!xkb_state_update_mask(x11_kbd_state,
get_xkb_mod_mask(ev->base_mods),
get_xkb_mod_mask(ev->latched_mods),
get_xkb_mod_mask(ev->locked_mods),
0,
0,
ev->group)) return ECORE_CALLBACK_RENEW;
EINA_LIST_FOREACH(comps, l, c)
EINA_INLIST_FOREACH(c->seats, s)
{
Eina_List *ll, *lll;
uint32_t serial;
struct wl_resource *res;
seat_kbd_mods_update(s);
ll = seat_kbd_active_resources_get(s);
if (!ll) continue;
serial = wl_display_next_serial(s->c->display);
EINA_LIST_FOREACH(ll, lll, res)
comp_seat_send_modifiers(s, res, serial);
}
return ECORE_CALLBACK_RENEW;
}
static void
x11_kbd_destroy(void)
{
if (x11_kbd_state) xkb_state_unref(x11_kbd_state);
x11_kbd_state = NULL;
if (x11_kbd_keymap) xkb_keymap_unref(x11_kbd_keymap);
x11_kbd_keymap = NULL;
if (x11_kbd_context) xkb_context_unref(x11_kbd_context);
x11_kbd_context = NULL;
}
static void
x11_kbd_create(void)
{
Ecore_X_Connection *conn = ecore_x_connection_get();
x11_kbd_destroy();
x11_kbd_context = xkb_context_new(0);
x11_core_device = xkb_x11_get_core_keyboard_device_id(conn);
x11_kbd_keymap = xkb_x11_keymap_new_from_device(x11_kbd_context, conn, x11_core_device, 0);
x11_kbd_state = xkb_x11_state_new_from_device(x11_kbd_keymap, conn, x11_core_device);
keymap_mods_init(x11_kbd_keymap);
}
static void
x11_kbd_apply(Comp_Seat *s)
{
if (!x11_kbd_state) x11_kbd_create();
s->kbd.context = x11_kbd_context;
s->kbd.keymap = x11_kbd_keymap;
s->kbd.state = x11_kbd_state;
}
static void seat_keymap_update(Comp_Seat *s);
static Eina_Bool
x11_xkb_refresh()
{
Eina_List *l;
Comp *c;
Comp_Seat *s;
x11_kbd_create();
EINA_LIST_FOREACH(comps, l, c)
EINA_INLIST_FOREACH(c->seats, s)
{
if (!s->keyboard) continue;
x11_kbd_apply(s);
seat_keymap_update(s);
}
return ECORE_CALLBACK_RENEW;
}
static void
x11_init(void)
{
@ -589,18 +684,29 @@ x11_init(void)
handlers = eina_list_append(handlers, h);
h = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, (Ecore_Event_Handler_Cb)x11_dnd_mouse_up, NULL);
handlers = eina_list_append(handlers, h);
xconvertselection = dlsym(NULL, "XConvertSelection");
string_atom = ecore_x_atom_get("UTF8_STRING");
timestamp_atom = ecore_x_atom_get("TIMESTAMP");
int_atom = ecore_x_atom_get("INTEGER");
incr_atom = ecore_x_atom_get("TIMESTAMP");
comp_dnd_atom = ecore_x_atom_get("SIRCMPWIDG_ATOM");
h = ecore_event_handler_add(ECORE_X_EVENT_XKB_STATE_NOTIFY, (Ecore_Event_Handler_Cb)x11_xkb_state, NULL);
handlers = eina_list_append(handlers, h);
h = ecore_event_handler_add(ECORE_X_EVENT_XKB_NEWKBD_NOTIFY, (Ecore_Event_Handler_Cb)x11_xkb_refresh, NULL);
handlers = eina_list_append(handlers, h);
if (!xconvertselection)
{
xconvertselection = dlsym(NULL, "XConvertSelection");
string_atom = ecore_x_atom_get("UTF8_STRING");
timestamp_atom = ecore_x_atom_get("TIMESTAMP");
int_atom = ecore_x_atom_get("INTEGER");
incr_atom = ecore_x_atom_get("TIMESTAMP");
comp_dnd_atom = ecore_x_atom_get("SIRCMPWIDG_ATOM");
ecore_x_xkb_track_state();
}
pipes = eina_hash_int32_new((Eina_Free_Cb)_pipe_free);
}
static void
x11_shutdown(void)
{
x11_core_device = -1;
x11_kbd_destroy();
eina_hash_free(pipes);
pipes = NULL;
}