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
This commit is contained in:
Jonas Ådahl 2017-09-01 18:41:44 +08:00
parent 8b060342bd
commit 487b8a0430
2 changed files with 117 additions and 4 deletions

View File

@ -116,8 +116,8 @@ typedef struct
int n_iso_next_group_combos; int n_iso_next_group_combos;
/* /*
* A primary layout, and an optional secondary layout that is * A primary layout, and an optional secondary layout for when the
* not yet used. * primary layout does not use the latin alphabet.
*/ */
MetaKeyBindingKeyboardLayout active_layouts[2]; MetaKeyBindingKeyboardLayout active_layouts[2];

View File

@ -622,6 +622,86 @@ binding_reload_combos_foreach (gpointer key,
index_binding (keys, binding); 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 static void
clear_active_keyboard_layouts (MetaKeyBindingManager *keys) 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 static void
reload_active_keyboard_layouts (MetaKeyBindingManager *keys) reload_active_keyboard_layouts (MetaKeyBindingManager *keys)
{ {
struct xkb_keymap *keymap; struct xkb_keymap *keymap;
xkb_layout_index_t layout_index; xkb_layout_index_t layout_index;
MetaKeyBindingKeyboardLayout primary_layout;
clear_active_keyboard_layouts (keys); clear_active_keyboard_layouts (keys);
keymap = meta_backend_get_keymap (keys->backend); keymap = meta_backend_get_keymap (keys->backend);
layout_index = meta_backend_get_keymap_layout_group (keys->backend); layout_index = meta_backend_get_keymap_layout_group (keys->backend);
primary_layout = (MetaKeyBindingKeyboardLayout) {
keys->active_layouts[META_KEY_BINDING_PRIMARY_LAYOUT] = (MetaKeyBindingKeyboardLayout) {
.keymap = xkb_keymap_ref (keymap), .keymap = xkb_keymap_ref (keymap),
.index = layout_index, .index = layout_index,
.n_levels = calculate_n_layout_levels (keymap, 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 static void