From e8fe0bcc47ff44a5afaf8442407248887f716b89 Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Fri, 26 May 2017 16:34:10 -0400 Subject: [PATCH] elput/drm: redo xkb context/keymap setting context and keymap need to be set at the same time in order to effectively update keyboard state, and active group should be accessible through api as well preserve old function ABI to ensure old binaries don't crash --- src/lib/ecore_drm2/Ecore_Drm2.h | 16 +-- src/lib/ecore_drm2/ecore_drm2_device.c | 12 ++- src/lib/elput/Elput.h | 16 +-- src/lib/elput/elput_evdev.c | 134 +++++++++++++++++-------- src/lib/elput/elput_input.c | 28 ++++-- src/lib/elput/elput_logind.c | 2 + src/lib/elput/elput_private.h | 8 +- 7 files changed, 148 insertions(+), 68 deletions(-) diff --git a/src/lib/ecore_drm2/Ecore_Drm2.h b/src/lib/ecore_drm2/Ecore_Drm2.h index 7d52d3aa00..d62f4e8f4c 100644 --- a/src/lib/ecore_drm2/Ecore_Drm2.h +++ b/src/lib/ecore_drm2/Ecore_Drm2.h @@ -285,26 +285,28 @@ EAPI void ecore_drm2_device_window_set(Ecore_Drm2_Device *device, unsigned int w EAPI void ecore_drm2_device_pointer_max_set(Ecore_Drm2_Device *device, int w, int h); /** - * Set a cached context to be used on keyboards + * Set info to be used on keyboards * * @param device * @param context + * @param keymap + * @param group * * @ingroup Ecore_Drm2_Device_Group - * @since 1.18 + * @since 1.20 */ -EAPI void ecore_drm2_device_keyboard_cached_context_set(Ecore_Drm2_Device *device, void *context); +EAPI void ecore_drm2_device_keyboard_info_set(Ecore_Drm2_Device *device, void *context, void *keymap, int group); /** - * Set a cached keymap to be used on keyboards + * Set a group layout to be used on keyboards * * @param device - * @param keymap + * @param group * * @ingroup Ecore_Drm2_Device_Group - * @since 1.18 + * @since 1.20 */ -EAPI void ecore_drm2_device_keyboard_cached_keymap_set(Ecore_Drm2_Device *device, void *keymap); +EAPI void ecore_drm2_device_keyboard_group_set(Ecore_Drm2_Device *device, int group); /** * Get the crtcs of a given device diff --git a/src/lib/ecore_drm2/ecore_drm2_device.c b/src/lib/ecore_drm2/ecore_drm2_device.c index dbd95fe465..f225ad8129 100644 --- a/src/lib/ecore_drm2/ecore_drm2_device.c +++ b/src/lib/ecore_drm2/ecore_drm2_device.c @@ -777,19 +777,19 @@ ecore_drm2_device_pointer_max_set(Ecore_Drm2_Device *device, int w, int h) } EAPI void -ecore_drm2_device_keyboard_cached_context_set(Ecore_Drm2_Device *device, void *context) +ecore_drm2_device_keyboard_info_set(Ecore_Drm2_Device *device, void *context, void *keymap, int group) { EINA_SAFETY_ON_NULL_RETURN(device); - elput_input_keyboard_cached_context_set(device->em, context); + elput_input_keyboard_info_set(device->em, context, keymap, group); } EAPI void -ecore_drm2_device_keyboard_cached_keymap_set(Ecore_Drm2_Device *device, void *keymap) +ecore_drm2_device_keyboard_group_set(Ecore_Drm2_Device *device, int group) { EINA_SAFETY_ON_NULL_RETURN(device); - elput_input_keyboard_cached_keymap_set(device->em, keymap); + elput_input_keyboard_group_set(device->em, group); } EAPI unsigned int * @@ -848,3 +848,7 @@ ecore_drm2_device_prefer_shadow(Ecore_Drm2_Device *device) else return EINA_FALSE; } + +/* prevent crashing with old apps compiled against these functions */ +EAPI void ecore_drm2_device_keyboard_cached_context_set(){}; +EAPI void ecore_drm2_device_keyboard_cached_keymap_set(){}; diff --git a/src/lib/elput/Elput.h b/src/lib/elput/Elput.h index 378912eb90..f9e950c821 100644 --- a/src/lib/elput/Elput.h +++ b/src/lib/elput/Elput.h @@ -395,26 +395,28 @@ EAPI Eina_Bool elput_input_key_remap_enable(Elput_Manager *manager, Eina_Bool en EAPI Eina_Bool elput_input_key_remap_set(Elput_Manager *manager, int *from_keys, int *to_keys, int num); /** - * Set a cached context to be used for keyboards + * Set info to be used for keyboards * * @param manager * @param context + * @param keymap + * @param group * * @ingroup Elput_Input_Group - * @since 1.18 + * @since 1.20 */ -EAPI void elput_input_keyboard_cached_context_set(Elput_Manager *manager, void *context); +EAPI void elput_input_keyboard_info_set(Elput_Manager *manager, void *context, void *keymap, int group); /** - * Set a cached keymap to be used for keyboards + * Set group layout to be used for keyboards * * @param manager - * @param keymap + * @param group * * @ingroup Elput_Input_Group - * @since 1.18 + * @since 1.20 */ -EAPI void elput_input_keyboard_cached_keymap_set(Elput_Manager *manager, void *keymap); +EAPI void elput_input_keyboard_group_set(Elput_Manager *manager, int group); /** * Return the output name associated with a given device diff --git a/src/lib/elput/elput_evdev.c b/src/lib/elput/elput_evdev.c index 3c6243bc1a..46f8068f79 100644 --- a/src/lib/elput/elput_evdev.c +++ b/src/lib/elput/elput_evdev.c @@ -89,7 +89,7 @@ _keyboard_fd_get(off_t size) } static Elput_Keyboard_Info * -_keyboard_info_create(struct xkb_keymap *keymap, Eina_Bool external) +_keyboard_info_create(struct xkb_keymap *keymap) { Elput_Keyboard_Info *info; char *str; @@ -113,9 +113,6 @@ _keyboard_info_create(struct xkb_keymap *keymap, Eina_Bool external) info->mods.altgr = 1 << xkb_keymap_mod_get_index(info->keymap.map, "ISO_Level3_Shift"); - /* if we are using an external keymap then we do not need go further */ - if (external) return info; - str = xkb_keymap_get_as_string(info->keymap.map, XKB_KEYMAP_FORMAT_TEXT_V1); if (!str) goto err; @@ -145,17 +142,14 @@ err: } static void -_keyboard_info_destroy(Elput_Keyboard_Info *info, Eina_Bool external) +_keyboard_info_destroy(Elput_Keyboard_Info *info) { if (--info->refs > 0) return; xkb_keymap_unref(info->keymap.map); - if (!external) - { - if (info->keymap.area) munmap(info->keymap.area, info->keymap.size); - if (info->keymap.fd >= 0) close(info->keymap.fd); - } + if (info->keymap.area) munmap(info->keymap.area, info->keymap.size); + if (info->keymap.fd >= 0) close(info->keymap.fd); free(info); } @@ -175,7 +169,7 @@ _keyboard_global_build(Elput_Keyboard *kbd) keymap = xkb_keymap_new_from_names(kbd->context, &kbd->names, 0); if (!keymap) return EINA_FALSE; - kbd->info = _keyboard_info_create(keymap, EINA_FALSE); + kbd->info = _keyboard_info_create(keymap); xkb_keymap_unref(keymap); if (!kbd->info) return EINA_FALSE; @@ -231,7 +225,9 @@ _keyboard_init(Elput_Seat *seat, struct xkb_keymap *keymap) if (keymap) { - kbd->info = _keyboard_info_create(keymap, EINA_TRUE); + if (seat->manager->cached.keymap == keymap) + kbd->context = xkb_context_ref(seat->manager->cached.context); + kbd->info = _keyboard_info_create(keymap); if (!kbd->info) goto err; } else @@ -254,7 +250,7 @@ _keyboard_init(Elput_Seat *seat, struct xkb_keymap *keymap) return EINA_TRUE; err: - if (kbd->info) _keyboard_info_destroy(kbd->info, kbd->external_map); + if (kbd->info) _keyboard_info_destroy(kbd->info); free(kbd); return EINA_FALSE; } @@ -346,39 +342,91 @@ _keyboard_modifiers_send(Elput_Keyboard *kbd) ecore_event_add(ELPUT_EVENT_MODIFIERS_SEND, ev, NULL, NULL); } -static void +static Eina_Bool +_keyboard_state_update(Elput_Keyboard *kbd, struct xkb_keymap *map, xkb_mod_mask_t *latched, xkb_mod_mask_t *locked) +{ + struct xkb_state *state, *maskless_state; + + state = xkb_state_new(map); + if (!state) return EINA_FALSE; + maskless_state = xkb_state_new(map); + if (!maskless_state) + { + xkb_state_unref(state); + return EINA_FALSE; + } + + *latched = xkb_state_serialize_mods(kbd->state, XKB_STATE_MODS_LATCHED); + *locked = xkb_state_serialize_mods(kbd->state, XKB_STATE_MODS_LOCKED); + xkb_state_update_mask(state, 0, *latched, *locked, kbd->seat->manager->cached.group, 0, 0); + + xkb_state_unref(kbd->state); + kbd->state = state; + xkb_state_unref(kbd->maskless_state); + kbd->maskless_state = maskless_state; + return EINA_TRUE; +} + +void _keyboard_keymap_update(Elput_Seat *seat) { Elput_Keyboard *kbd; - Elput_Keyboard_Info *info; - struct xkb_state *state; + Elput_Keyboard_Info *info = NULL; xkb_mod_mask_t latched, locked; + Eina_Bool state = EINA_TRUE; + + kbd = _evdev_keyboard_get(seat); + if (!kbd) return; + kbd->pending_keymap = 1; + if (kbd->key_count) return; + + if (kbd->seat->manager->cached.keymap) + { + if (kbd->context) xkb_context_unref(kbd->context); + kbd->context = xkb_context_ref(kbd->seat->manager->cached.context); + info = _keyboard_info_create(kbd->seat->manager->cached.keymap); + if (!info) return; + state = _keyboard_state_update(kbd, info->keymap.map, &latched, &locked); + } + else if (!_keyboard_global_build(kbd)) return; + else + state = _keyboard_state_update(kbd, kbd->info->keymap.map, &latched, &locked); + kbd->pending_keymap = 0; + if (!state) + { + if (info) _keyboard_info_destroy(info); + return; + } + + if (info) + { + _keyboard_info_destroy(kbd->info); + kbd->info = info; + } + + _keyboard_compose_init(kbd); + + _keyboard_modifiers_update(kbd, seat); + _keyboard_keymap_send(kbd->info); + + if ((!latched) && (!locked)) return; + + _keyboard_modifiers_send(kbd); +} + +void +_keyboard_group_update(Elput_Seat *seat) +{ + Elput_Keyboard *kbd; + xkb_mod_mask_t latched, locked; + Eina_Bool state; kbd = _evdev_keyboard_get(seat); if (!kbd) return; - info = _keyboard_info_create(kbd->pending_map, kbd->external_map); - xkb_keymap_unref(kbd->pending_map); - kbd->pending_map = NULL; - - if (!info) return; - - state = xkb_state_new(info->keymap.map); - if (!state) - { - _keyboard_info_destroy(info, kbd->external_map); - return; - } - - latched = xkb_state_serialize_mods(kbd->state, XKB_STATE_MODS_LATCHED); - locked = xkb_state_serialize_mods(kbd->state, XKB_STATE_MODS_LOCKED); - xkb_state_update_mask(state, 0, latched, locked, 0, 0, 0); - - _keyboard_info_destroy(kbd->info, kbd->external_map); - kbd->info = info; - - xkb_state_unref(kbd->state); - kbd->state = state; + state = _keyboard_state_update(kbd, kbd->info->keymap.map, &latched, &locked); + if (!state) return; + _keyboard_compose_init(kbd); _keyboard_modifiers_update(kbd, seat); _keyboard_keymap_send(kbd->info); @@ -568,7 +616,7 @@ _keyboard_key(struct libinput_device *idevice, struct libinput_event_keyboard *e if (!kbd) return; state = libinput_event_keyboard_get_key_state(event); - count = libinput_event_keyboard_get_seat_key_count(event); + kbd->key_count = count = libinput_event_keyboard_get_seat_key_count(event); /* Ignore key events that are not seat wide state changes. */ if (((state == LIBINPUT_KEY_STATE_PRESSED) && (count != 1)) || @@ -610,7 +658,7 @@ _keyboard_key(struct libinput_device *idevice, struct libinput_event_keyboard *e _keyboard_keysym_translate(sym, dev->seat->modifiers, compose, sizeof(compose)); _keyboard_key_send(dev, state, keyname, key, compose, code, timestamp); - if ((kbd->pending_map) && (count == 0)) + if ((kbd->pending_keymap) && (count == 0)) _keyboard_keymap_update(dev->seat); if (state == LIBINPUT_KEY_STATE_PRESSED) @@ -1588,12 +1636,14 @@ _evdev_keyboard_destroy(Elput_Keyboard *kbd) free((char *)kbd->names.variant); free((char *)kbd->names.options); + if (kbd->compose_table) xkb_compose_table_unref(kbd->compose_table); + if (kbd->compose_state) xkb_compose_state_unref(kbd->compose_state); + if (kbd->state) xkb_state_unref(kbd->state); - if (kbd->info) _keyboard_info_destroy(kbd->info, kbd->external_map); if (kbd->maskless_state) xkb_state_unref(kbd->maskless_state); + if (kbd->info) _keyboard_info_destroy(kbd->info); xkb_context_unref(kbd->context); - xkb_keymap_unref(kbd->pending_map); free(kbd); } diff --git a/src/lib/elput/elput_input.c b/src/lib/elput/elput_input.c index f46f26d246..a5afe74fd9 100644 --- a/src/lib/elput/elput_input.c +++ b/src/lib/elput/elput_input.c @@ -654,21 +654,37 @@ elput_input_key_remap_set(Elput_Manager *manager, int *from_keys, int *to_keys, } EAPI void -elput_input_keyboard_cached_context_set(Elput_Manager *manager, void *context) +elput_input_keyboard_info_set(Elput_Manager *manager, void *context, void *keymap, int group) { - EINA_SAFETY_ON_NULL_RETURN(manager); + Eina_List *l; + Elput_Seat *seat; - if ((context) && (manager->cached.context == context)) return; + EINA_SAFETY_ON_NULL_RETURN(manager); + EINA_SAFETY_ON_FALSE_RETURN((!!context) == (!!keymap)); + + if ((manager->cached.context == context) && (manager->cached.keymap == keymap)) return; + if (context) xkb_context_ref(context); + if (keymap) xkb_keymap_ref(keymap); + if (manager->cached.context) xkb_context_unref(manager->cached.context); + if (manager->cached.keymap) xkb_keymap_unref(manager->cached.keymap); manager->cached.context = context; + manager->cached.keymap = keymap; + manager->cached.group = group; + EINA_LIST_FOREACH(manager->input.seats, l, seat) + _keyboard_keymap_update(seat); } EAPI void -elput_input_keyboard_cached_keymap_set(Elput_Manager *manager, void *keymap) +elput_input_keyboard_group_set(Elput_Manager *manager, int group) { + Eina_List *l; + Elput_Seat *seat; EINA_SAFETY_ON_NULL_RETURN(manager); - if ((keymap) && (manager->cached.keymap == keymap)) return; - manager->cached.keymap = keymap; + if (manager->cached.group == group) return; + manager->cached.group = group; + EINA_LIST_FOREACH(manager->input.seats, l, seat) + _keyboard_group_update(seat); } EAPI Eina_Stringshare * diff --git a/src/lib/elput/elput_logind.c b/src/lib/elput/elput_logind.c index 25034480d2..cfce90e3aa 100644 --- a/src/lib/elput/elput_logind.c +++ b/src/lib/elput/elput_logind.c @@ -527,6 +527,8 @@ _logind_disconnect(Elput_Manager *em) _logind_dbus_close(em->dbus.conn); eina_stringshare_del(em->seat); free(em->sid); + if (em->cached.context) xkb_context_unref(em->cached.context); + if (em->cached.keymap) xkb_keymap_unref(em->cached.keymap); free(em); } diff --git a/src/lib/elput/elput_private.h b/src/lib/elput/elput_private.h index c6e3c81d83..4c7881e0ef 100644 --- a/src/lib/elput/elput_private.h +++ b/src/lib/elput/elput_private.h @@ -135,9 +135,9 @@ struct _Elput_Keyboard } grab; Elput_Keyboard_Info *info; + unsigned int key_count; struct xkb_state *state; - struct xkb_keymap *pending_map; struct xkb_state *maskless_state; struct xkb_context *context; struct xkb_rule_names names; @@ -146,7 +146,7 @@ struct _Elput_Keyboard Elput_Seat *seat; - Eina_Bool external_map : 1; + Eina_Bool pending_keymap : 1; }; struct _Elput_Pointer @@ -261,6 +261,7 @@ struct _Elput_Manager { struct xkb_keymap *keymap; struct xkb_context *context; + int group; } cached; Elput_Input input; @@ -292,4 +293,7 @@ Elput_Touch *_evdev_touch_get(Elput_Seat *seat); extern Elput_Interface _logind_interface; +void _keyboard_keymap_update(Elput_Seat *seat); +void _keyboard_group_update(Elput_Seat *seat); + #endif