summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Ådahl <jadahl@gmail.com>2017-09-01 18:41:44 +0800
committerJonas Ådahl <jadahl@gmail.com>2017-09-25 15:31:07 -0400
commit487b8a0430cac06535524133f34b6e95748fbb7a (patch)
tree11899af0081d56b471d977401a2e7e76727bda5c
parent8b060342bd8c8abc348d09b1b71c90a36bc57f05 (diff)
downloadmutter-487b8a0430cac06535524133f34b6e95748fbb7a.tar.gz
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
-rw-r--r--src/core/keybindings-private.h4
-rw-r--r--src/core/keybindings.c117
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