From 487b8a0430cac06535524133f34b6e95748fbb7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 1 Sep 2017 18:41:44 +0800 Subject: [PATCH] keybindings: Resolve on us layout too if primary is not latin based If a non-latin based keyboard layout is active, for example Cyrillic, keybindings won't work unless we resolve the bound keysyms on a secondary latin based layout. So, to make keybindings work on non-latin based layouts, detect if a keymap doesn't have all of the basic latin letters (a-z) and resolve from an additional US layout as well. https://bugzilla.gnome.org/show_bug.cgi?id=787016 --- src/core/keybindings-private.h | 4 +- src/core/keybindings.c | 117 ++++++++++++++++++++++++++++++++- 2 files changed, 117 insertions(+), 4 deletions(-) diff --git a/src/core/keybindings-private.h b/src/core/keybindings-private.h index acfdf0158..7fc8d67d9 100644 --- a/src/core/keybindings-private.h +++ b/src/core/keybindings-private.h @@ -116,8 +116,8 @@ typedef struct int n_iso_next_group_combos; /* - * A primary layout, and an optional secondary layout that is - * not yet used. + * A primary layout, and an optional secondary layout for when the + * primary layout does not use the latin alphabet. */ MetaKeyBindingKeyboardLayout active_layouts[2]; diff --git a/src/core/keybindings.c b/src/core/keybindings.c index aa9ad570a..41becb632 100644 --- a/src/core/keybindings.c +++ b/src/core/keybindings.c @@ -622,6 +622,86 @@ binding_reload_combos_foreach (gpointer key, index_binding (keys, binding); } +typedef struct _FindLatinKeysymsState +{ + MetaKeyBindingKeyboardLayout *layout; + gboolean *required_keysyms_found; + int n_required_keysyms; +} FindLatinKeysymsState; + +static void +find_latin_keysym (struct xkb_keymap *keymap, + xkb_keycode_t key, + void *data) +{ + FindLatinKeysymsState *state = data; + int n_keysyms, i; + const xkb_keysym_t *keysyms; + + n_keysyms = xkb_keymap_key_get_syms_by_level (state->layout->keymap, + key, + state->layout->index, + 0, + &keysyms); + for (i = 0; i < n_keysyms; i++) + { + xkb_keysym_t keysym = keysyms[i]; + + if (keysym >= XKB_KEY_a && keysym <= XKB_KEY_z) + { + unsigned int keysym_index = keysym - XKB_KEY_a; + + if (!state->required_keysyms_found[keysym_index]) + { + state->required_keysyms_found[keysym_index] = TRUE; + state->n_required_keysyms--; + } + } + } +} + +static gboolean +needs_secondary_layout (MetaKeyBindingKeyboardLayout *layout) +{ + gboolean required_keysyms_found[] = { + FALSE, /* XKB_KEY_a */ + FALSE, /* XKB_KEY_b */ + FALSE, /* XKB_KEY_c */ + FALSE, /* XKB_KEY_d */ + FALSE, /* XKB_KEY_e */ + FALSE, /* XKB_KEY_f */ + FALSE, /* XKB_KEY_g */ + FALSE, /* XKB_KEY_h */ + FALSE, /* XKB_KEY_i */ + FALSE, /* XKB_KEY_j */ + FALSE, /* XKB_KEY_k */ + FALSE, /* XKB_KEY_l */ + FALSE, /* XKB_KEY_m */ + FALSE, /* XKB_KEY_n */ + FALSE, /* XKB_KEY_o */ + FALSE, /* XKB_KEY_p */ + FALSE, /* XKB_KEY_q */ + FALSE, /* XKB_KEY_r */ + FALSE, /* XKB_KEY_s */ + FALSE, /* XKB_KEY_t */ + FALSE, /* XKB_KEY_u */ + FALSE, /* XKB_KEY_v */ + FALSE, /* XKB_KEY_w */ + FALSE, /* XKB_KEY_x */ + FALSE, /* XKB_KEY_y */ + FALSE, /* XKB_KEY_z */ + }; + FindLatinKeysymsState state = { + .layout = layout, + .required_keysyms_found = required_keysyms_found, + .n_required_keysyms = G_N_ELEMENTS (required_keysyms_found), + }; + + xkb_keymap_key_for_each (layout->keymap, find_latin_keysym, &state); + + return state.n_required_keysyms != 0; +} + static void clear_active_keyboard_layouts (MetaKeyBindingManager *keys) { @@ -636,22 +716,55 @@ clear_active_keyboard_layouts (MetaKeyBindingManager *keys) } } +static MetaKeyBindingKeyboardLayout +create_us_layout (void) +{ + struct xkb_rule_names names; + struct xkb_keymap *keymap; + struct xkb_context *context; + + names.rules = DEFAULT_XKB_RULES_FILE; + names.model = DEFAULT_XKB_MODEL; + names.layout = "us"; + names.variant = ""; + names.options = ""; + + context = xkb_context_new (XKB_CONTEXT_NO_FLAGS); + keymap = xkb_keymap_new_from_names (context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS); + xkb_context_unref (context); + + return (MetaKeyBindingKeyboardLayout) { + .keymap = keymap, + .n_levels = calculate_n_layout_levels (keymap, 0), + }; +} + static void reload_active_keyboard_layouts (MetaKeyBindingManager *keys) { struct xkb_keymap *keymap; xkb_layout_index_t layout_index; + MetaKeyBindingKeyboardLayout primary_layout; clear_active_keyboard_layouts (keys); keymap = meta_backend_get_keymap (keys->backend); layout_index = meta_backend_get_keymap_layout_group (keys->backend); - - keys->active_layouts[META_KEY_BINDING_PRIMARY_LAYOUT] = (MetaKeyBindingKeyboardLayout) { + primary_layout = (MetaKeyBindingKeyboardLayout) { .keymap = xkb_keymap_ref (keymap), .index = layout_index, .n_levels = calculate_n_layout_levels (keymap, layout_index), }; + + keys->active_layouts[META_KEY_BINDING_PRIMARY_LAYOUT] = primary_layout; + + if (needs_secondary_layout (&primary_layout)) + { + MetaKeyBindingKeyboardLayout us_layout; + + us_layout = create_us_layout (); + keys->active_layouts[META_KEY_BINDING_SECONDARY_LAYOUT] = us_layout; + } } static void