From: Ran Benita Date: Wed, 29 Aug 2012 12:02:40 +0000 (+0300) Subject: Add xkbcomp/keymap.c and move some code there X-Git-Tag: xkbcommon-0.2.0~225 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8c1b1b0e9e52be18dbb42aa4765f886ace067f97;p=platform%2Fupstream%2Flibxkbcommon.git Add xkbcomp/keymap.c and move some code there Add CompileKeymap to do most of what compile_keymap_file does now, and move UpdateKeymapFromModifiers along with it from (mostly unrelated) compat.c. Also rename UpdateKeymapFromModifiers to UpdateDerivedKeymapFields, because it does more than update the modifiers. Signed-off-by: Ran Benita --- diff --git a/Makefile.am b/Makefile.am index ed96b66..011cbe2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -51,6 +51,7 @@ libxkbcommon_la_SOURCES = \ src/xkbcomp/include.h \ src/xkbcomp/keycodes.c \ src/xkbcomp/keycodes.h \ + src/xkbcomp/keymap.c \ src/xkbcomp/parser.y \ src/xkbcomp/parser-priv.h \ src/xkbcomp/rules.c \ diff --git a/src/xkbcomp/compat.c b/src/xkbcomp/compat.c index bcdc2ee..c387310 100644 --- a/src/xkbcomp/compat.c +++ b/src/xkbcomp/compat.c @@ -1113,249 +1113,3 @@ err_info: ClearCompatInfo(&info); return false; } - -static void -ComputeEffectiveMask(struct xkb_keymap *keymap, struct xkb_mods *mods) -{ - xkb_mod_index_t i; - xkb_mod_mask_t vmask = mods->mods >> XkbNumModifiers; - - /* The effective mask is only real mods for now. */ - mods->mask = mods->mods & 0xff; - - for (i = 0; i < XkbNumVirtualMods; i++) { - if (!(vmask & (1 << i))) - continue; - mods->mask |= keymap->vmods[i]; - } -} - -static void -UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act, - xkb_mod_mask_t rmodmask) -{ - unsigned int flags; - struct xkb_mods *mods; - - switch (act->type) { - case XkbSA_SetMods: - case XkbSA_LatchMods: - case XkbSA_LockMods: - flags = act->mods.flags; - mods = &act->mods.mods; - break; - - case XkbSA_ISOLock: - flags = act->iso.flags; - mods = &act->iso.mods; - break; - - default: - return; - } - - if (flags & XkbSA_UseModMapMods) { - /* XXX: what's that. */ - mods->mods &= 0xff; - mods->mods |= rmodmask; - } - ComputeEffectiveMask(keymap, mods); -} - -/** - * Find an interpretation which applies to this particular level, either by - * finding an exact match for the symbol and modifier combination, or a - * generic XKB_KEY_NoSymbol match. - */ -static struct xkb_sym_interpret * -FindInterpForKey(struct xkb_keymap *keymap, struct xkb_key *key, - xkb_group_index_t group, xkb_level_index_t level) -{ - struct xkb_sym_interpret *ret = NULL; - struct xkb_sym_interpret *interp; - const xkb_keysym_t *syms; - int num_syms; - - num_syms = xkb_key_get_syms_by_level(keymap, key, group, level, &syms); - if (num_syms == 0) - return NULL; - - darray_foreach(interp, keymap->sym_interpret) { - uint32_t mods; - bool found; - - if ((num_syms > 1 || interp->sym != syms[0]) && - interp->sym != XKB_KEY_NoSymbol) - continue; - - if (level == 0 || !(interp->match & XkbSI_LevelOneOnly)) - mods = key->modmap; - else - mods = 0; - - switch (interp->match & XkbSI_OpMask) { - case XkbSI_NoneOf: - found = !(interp->mods & mods); - break; - case XkbSI_AnyOfOrNone: - found = (!mods || (interp->mods & mods)); - break; - case XkbSI_AnyOf: - found = !!(interp->mods & mods); - break; - case XkbSI_AllOf: - found = ((interp->mods & mods) == interp->mods); - break; - case XkbSI_Exactly: - found = (interp->mods == mods); - break; - default: - found = false; - break; - } - - if (found && interp->sym != XKB_KEY_NoSymbol) - return interp; - else if (found && !ret) - ret = interp; - } - - return ret; -} - -static bool -ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key) -{ -#define INTERP_SIZE (8 * 4) - struct xkb_sym_interpret *interps[INTERP_SIZE]; - xkb_mod_mask_t vmodmask = 0; - int num_acts = 0; - xkb_group_index_t group; - xkb_level_index_t level; - unsigned int i; - - /* If we've been told not to bind interps to this key, then don't. */ - if (key->explicit & XkbExplicitInterpretMask) - return true; - - for (i = 0; i < INTERP_SIZE; i++) - interps[i] = NULL; - - for (group = 0; group < key->num_groups; group++) { - for (level = 0; level < XkbKeyGroupWidth(keymap, key, group); - level++) { - i = (group * key->width) + level; - if (i >= INTERP_SIZE) /* XXX FIXME */ - return false; - interps[i] = FindInterpForKey(keymap, key, group, level); - if (interps[i]) - num_acts++; - } - } - - if (num_acts && !key->actions) { - key->actions = calloc(key->num_groups * key->width, - sizeof(*key->actions)); - if (!key->actions) - return false; - } - - for (group = 0; group < key->num_groups; group++) { - for (level = 0; level < XkbKeyGroupWidth(keymap, key, group); - level++) { - struct xkb_sym_interpret *interp; - - i = (group * key->width) + level; - interp = interps[i]; - - /* Infer default key behaviours from the base level. */ - if (group == 0 && level == 0) { - if (!(key->explicit & XkbExplicitAutoRepeatMask) && - (!interp || (interp->flags & XkbSI_AutoRepeat))) - key->repeats = true; - } - - if (!interp) - continue; - - if ((group == 0 && level == 0) || - !(interp->match & XkbSI_LevelOneOnly)) { - if (interp->virtual_mod != XkbNoModifier) - vmodmask |= (1 << interp->virtual_mod); - } - - key->actions[i] = interp->act; - } - } - - if (!(key->explicit & XkbExplicitVModMapMask)) - key->vmodmap = vmodmask; - - return true; -#undef INTERP_SIZE -} - -/** - * This collects a bunch of disparate functions which was done in the server - * at various points that really should've been done within xkbcomp. Turns out - * your actions and types are a lot more useful when any of your modifiers - * other than Shift actually do something ... - */ -bool -UpdateModifiersFromCompat(struct xkb_keymap *keymap) -{ - xkb_mod_index_t vmod; - xkb_led_index_t led; - unsigned int i, j; - struct xkb_key *key; - - /* Find all the interprets for the key and bind them to actions, - * which will also update the vmodmap. */ - xkb_foreach_key(key, keymap) - if (!ApplyInterpsToKey(keymap, key)) - return false; - - /* Update keymap->vmods, the virtual -> real mod mapping. */ - for (vmod = 0; vmod < XkbNumVirtualMods; vmod++) - keymap->vmods[vmod] = 0; - - xkb_foreach_key(key, keymap) { - if (!key->vmodmap) - continue; - - for (vmod = 0; vmod < XkbNumVirtualMods; vmod++) { - if (!(key->vmodmap & (1 << vmod))) - continue; - keymap->vmods[vmod] |= key->modmap; - } - } - - /* Now update the level masks for all the types to reflect the vmods. */ - for (i = 0; i < keymap->num_types; i++) { - ComputeEffectiveMask(keymap, &keymap->types[i].mods); - - for (j = 0; j < keymap->types[i].num_entries; j++) { - ComputeEffectiveMask(keymap, &keymap->types[i].map[j].mods); - ComputeEffectiveMask(keymap, &keymap->types[i].map[j].preserve); - } - } - - /* Update action modifiers. */ - xkb_foreach_key(key, keymap) { - if (!key->actions) - continue; - - for (i = 0; i < key->num_groups * key->width; i++) - UpdateActionMods(keymap, &key->actions[i], key->modmap); - } - - /* Update vmod -> indicator maps. */ - for (led = 0; led < XkbNumIndicators; led++) - ComputeEffectiveMask(keymap, &keymap->indicators[led].mods); - - /* Find maximum number of groups out of all keys in the keymap. */ - xkb_foreach_key(key, keymap) - keymap->num_groups = MAX(keymap->num_groups, key->num_groups); - - return true; -} diff --git a/src/xkbcomp/keymap.c b/src/xkbcomp/keymap.c new file mode 100644 index 0000000..0cc1d58 --- /dev/null +++ b/src/xkbcomp/keymap.c @@ -0,0 +1,356 @@ +/* + * Copyright 2009 Dan Nicholson + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +#include "xkbcomp-priv.h" + +static void +ComputeEffectiveMask(struct xkb_keymap *keymap, struct xkb_mods *mods) +{ + xkb_mod_index_t i; + xkb_mod_mask_t vmask = mods->mods >> XkbNumModifiers; + + /* The effective mask is only real mods for now. */ + mods->mask = mods->mods & 0xff; + + for (i = 0; i < XkbNumVirtualMods; i++) { + if (!(vmask & (1 << i))) + continue; + mods->mask |= keymap->vmods[i]; + } +} + +static void +UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act, + xkb_mod_mask_t rmodmask) +{ + unsigned int flags; + struct xkb_mods *mods; + + switch (act->type) { + case XkbSA_SetMods: + case XkbSA_LatchMods: + case XkbSA_LockMods: + flags = act->mods.flags; + mods = &act->mods.mods; + break; + + case XkbSA_ISOLock: + flags = act->iso.flags; + mods = &act->iso.mods; + break; + + default: + return; + } + + if (flags & XkbSA_UseModMapMods) { + /* XXX: what's that. */ + mods->mods &= 0xff; + mods->mods |= rmodmask; + } + ComputeEffectiveMask(keymap, mods); +} + +/** + * Find an interpretation which applies to this particular level, either by + * finding an exact match for the symbol and modifier combination, or a + * generic XKB_KEY_NoSymbol match. + */ +static struct xkb_sym_interpret * +FindInterpForKey(struct xkb_keymap *keymap, struct xkb_key *key, + xkb_group_index_t group, xkb_level_index_t level) +{ + struct xkb_sym_interpret *ret = NULL; + struct xkb_sym_interpret *interp; + const xkb_keysym_t *syms; + int num_syms; + + num_syms = xkb_key_get_syms_by_level(keymap, key, group, level, &syms); + if (num_syms == 0) + return NULL; + + darray_foreach(interp, keymap->sym_interpret) { + uint32_t mods; + bool found; + + if ((num_syms > 1 || interp->sym != syms[0]) && + interp->sym != XKB_KEY_NoSymbol) + continue; + + if (level == 0 || !(interp->match & XkbSI_LevelOneOnly)) + mods = key->modmap; + else + mods = 0; + + switch (interp->match & XkbSI_OpMask) { + case XkbSI_NoneOf: + found = !(interp->mods & mods); + break; + case XkbSI_AnyOfOrNone: + found = (!mods || (interp->mods & mods)); + break; + case XkbSI_AnyOf: + found = !!(interp->mods & mods); + break; + case XkbSI_AllOf: + found = ((interp->mods & mods) == interp->mods); + break; + case XkbSI_Exactly: + found = (interp->mods == mods); + break; + default: + found = false; + break; + } + + if (found && interp->sym != XKB_KEY_NoSymbol) + return interp; + else if (found && !ret) + ret = interp; + } + + return ret; +} + +static bool +ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key) +{ +#define INTERP_SIZE (8 * 4) + struct xkb_sym_interpret *interps[INTERP_SIZE]; + xkb_mod_mask_t vmodmask = 0; + int num_acts = 0; + xkb_group_index_t group; + xkb_level_index_t level; + unsigned int i; + + /* If we've been told not to bind interps to this key, then don't. */ + if (key->explicit & XkbExplicitInterpretMask) + return true; + + for (i = 0; i < INTERP_SIZE; i++) + interps[i] = NULL; + + for (group = 0; group < key->num_groups; group++) { + for (level = 0; level < XkbKeyGroupWidth(keymap, key, group); + level++) { + i = (group * key->width) + level; + if (i >= INTERP_SIZE) /* XXX FIXME */ + return false; + interps[i] = FindInterpForKey(keymap, key, group, level); + if (interps[i]) + num_acts++; + } + } + + if (num_acts && !key->actions) { + key->actions = calloc(key->num_groups * key->width, + sizeof(*key->actions)); + if (!key->actions) + return false; + } + + for (group = 0; group < key->num_groups; group++) { + for (level = 0; level < XkbKeyGroupWidth(keymap, key, group); + level++) { + struct xkb_sym_interpret *interp; + + i = (group * key->width) + level; + interp = interps[i]; + + /* Infer default key behaviours from the base level. */ + if (group == 0 && level == 0) { + if (!(key->explicit & XkbExplicitAutoRepeatMask) && + (!interp || (interp->flags & XkbSI_AutoRepeat))) + key->repeats = true; + } + + if (!interp) + continue; + + if ((group == 0 && level == 0) || + !(interp->match & XkbSI_LevelOneOnly)) { + if (interp->virtual_mod != XkbNoModifier) + vmodmask |= (1 << interp->virtual_mod); + } + + key->actions[i] = interp->act; + } + } + + if (!(key->explicit & XkbExplicitVModMapMask)) + key->vmodmap = vmodmask; + + return true; +#undef INTERP_SIZE +} + +/** + * This collects a bunch of disparate functions which was done in the server + * at various points that really should've been done within xkbcomp. Turns out + * your actions and types are a lot more useful when any of your modifiers + * other than Shift actually do something ... + */ +static bool +UpdateDerivedKeymapFields(struct xkb_keymap *keymap) +{ + xkb_mod_index_t vmod; + xkb_led_index_t led; + unsigned int i, j; + struct xkb_key *key; + + /* Find all the interprets for the key and bind them to actions, + * which will also update the vmodmap. */ + xkb_foreach_key(key, keymap) + if (!ApplyInterpsToKey(keymap, key)) + return false; + + /* Update keymap->vmods, the virtual -> real mod mapping. */ + for (vmod = 0; vmod < XkbNumVirtualMods; vmod++) + keymap->vmods[vmod] = 0; + + xkb_foreach_key(key, keymap) { + if (!key->vmodmap) + continue; + + for (vmod = 0; vmod < XkbNumVirtualMods; vmod++) { + if (!(key->vmodmap & (1 << vmod))) + continue; + keymap->vmods[vmod] |= key->modmap; + } + } + + /* Now update the level masks for all the types to reflect the vmods. */ + for (i = 0; i < keymap->num_types; i++) { + ComputeEffectiveMask(keymap, &keymap->types[i].mods); + + for (j = 0; j < keymap->types[i].num_entries; j++) { + ComputeEffectiveMask(keymap, &keymap->types[i].map[j].mods); + ComputeEffectiveMask(keymap, &keymap->types[i].map[j].preserve); + } + } + + /* Update action modifiers. */ + xkb_foreach_key(key, keymap) { + if (!key->actions) + continue; + + for (i = 0; i < key->num_groups * key->width; i++) + UpdateActionMods(keymap, &key->actions[i], key->modmap); + } + + /* Update vmod -> indicator maps. */ + for (led = 0; led < XkbNumIndicators; led++) + ComputeEffectiveMask(keymap, &keymap->indicators[led].mods); + + /* Find maximum number of groups out of all keys in the keymap. */ + xkb_foreach_key(key, keymap) + keymap->num_groups = MAX(keymap->num_groups, key->num_groups); + + return true; +} + +typedef bool (*compile_file_fn)(XkbFile *file, + struct xkb_keymap *keymap, + enum merge_mode merge); + +static const compile_file_fn compile_file_fns[LAST_KEYMAP_FILE_TYPE + 1] = { + [FILE_TYPE_KEYCODES] = CompileKeycodes, + [FILE_TYPE_TYPES] = CompileKeyTypes, + [FILE_TYPE_COMPAT] = CompileCompatMap, + [FILE_TYPE_SYMBOLS] = CompileSymbols, +}; + +bool +CompileKeymap(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge) +{ + bool ok; + const char *main_name; + XkbFile *files[LAST_KEYMAP_FILE_TYPE + 1] = { NULL }; + enum xkb_file_type type; + struct xkb_context *ctx = keymap->ctx; + + main_name = file->name ? file->name : "(unnamed)"; + + /* Collect section files and check for duplicates. */ + for (file = (XkbFile *) file->defs; file; + file = (XkbFile *) file->common.next) { + if (file->file_type < FIRST_KEYMAP_FILE_TYPE || + file->file_type > LAST_KEYMAP_FILE_TYPE) { + log_err(ctx, "Cannot define %s in a keymap file\n", + xkb_file_type_to_string(file->file_type)); + continue; + } + + if (files[file->file_type]) { + log_err(ctx, + "More than one %s section in keymap file; " + "All sections after the first ignored\n", + xkb_file_type_to_string(file->file_type)); + continue; + } + + if (!file->topName) { + free(file->topName); + file->topName = strdup(main_name); + } + + files[file->file_type] = file; + } + + /* + * Check that all required section were provided. + * Report everything before failing. + */ + ok = true; + for (type = FIRST_KEYMAP_FILE_TYPE; + type <= LAST_KEYMAP_FILE_TYPE; + type++) { + if (files[type] == NULL) { + log_err(ctx, "Required section %s missing from keymap\n", + xkb_file_type_to_string(type)); + ok = false; + } + } + if (!ok) + return false; + + /* Compile sections. */ + for (type = FIRST_KEYMAP_FILE_TYPE; + type <= LAST_KEYMAP_FILE_TYPE; + type++) { + log_dbg(ctx, "Compiling %s \"%s\"\n", + xkb_file_type_to_string(type), files[type]->topName); + + ok = compile_file_fns[type](files[type], keymap, merge); + if (!ok) { + log_err(ctx, "Failed to compile %s\n", + xkb_file_type_to_string(type)); + return false; + } + } + + return UpdateDerivedKeymapFields(keymap); +} diff --git a/src/xkbcomp/xkbcomp-priv.h b/src/xkbcomp/xkbcomp-priv.h index 2bf2b51..6175f69 100644 --- a/src/xkbcomp/xkbcomp-priv.h +++ b/src/xkbcomp/xkbcomp-priv.h @@ -62,7 +62,8 @@ CompileSymbols(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge); bool -UpdateModifiersFromCompat(struct xkb_keymap *keymap); +CompileKeymap(XkbFile *file, struct xkb_keymap *keymap, + enum merge_mode merge); bool LookupKeysym(const char *str, xkb_keysym_t *sym_rtrn); diff --git a/src/xkbcomp/xkbcomp.c b/src/xkbcomp/xkbcomp.c index 9ceaa0c..722dc91 100644 --- a/src/xkbcomp/xkbcomp.c +++ b/src/xkbcomp/xkbcomp.c @@ -27,103 +27,29 @@ #include "xkbcomp-priv.h" #include "rules.h" -typedef bool (*compile_file_fn)(XkbFile *file, - struct xkb_keymap *keymap, - enum merge_mode merge); - -static const compile_file_fn compile_file_fns[LAST_KEYMAP_FILE_TYPE + 1] = { - [FILE_TYPE_KEYCODES] = CompileKeycodes, - [FILE_TYPE_TYPES] = CompileKeyTypes, - [FILE_TYPE_COMPAT] = CompileCompatMap, - [FILE_TYPE_SYMBOLS] = CompileSymbols, -}; - static struct xkb_keymap * compile_keymap_file(struct xkb_context *ctx, XkbFile *file) { - bool ok; - const char *main_name; struct xkb_keymap *keymap; - XkbFile *files[LAST_KEYMAP_FILE_TYPE + 1] = { NULL }; - enum xkb_file_type type; keymap = xkb_map_new(ctx); if (!keymap) goto err; - main_name = file->name ? file->name : "(unnamed)"; - if (file->file_type != FILE_TYPE_KEYMAP) { log_err(ctx, "Cannot compile a %s file alone into a keymap\n", xkb_file_type_to_string(file->file_type)); goto err; } - /* Collect section files and check for duplicates. */ - for (file = (XkbFile *) file->defs; file; - file = (XkbFile *) file->common.next) { - if (file->file_type < FIRST_KEYMAP_FILE_TYPE || - file->file_type > LAST_KEYMAP_FILE_TYPE) { - log_err(ctx, "Cannot define %s in a keymap file\n", - xkb_file_type_to_string(file->file_type)); - continue; - } - - if (files[file->file_type]) { - log_err(ctx, - "More than one %s section in keymap file; " - "All sections after the first ignored\n", - xkb_file_type_to_string(file->file_type)); - continue; - } - - if (!file->topName) { - free(file->topName); - file->topName = strdup(main_name); - } - - files[file->file_type] = file; - } - - /* - * Check that all required section were provided. - * Report everything before failing. - */ - ok = true; - for (type = FIRST_KEYMAP_FILE_TYPE; - type <= LAST_KEYMAP_FILE_TYPE; - type++) { - if (files[type] == NULL) { - log_err(ctx, "Required section %s missing from keymap\n", - xkb_file_type_to_string(type)); - ok = false; - } - } - if (!ok) + if (!CompileKeymap(file, keymap, MERGE_OVERRIDE)) { + log_err(ctx, "Failed to compile keymap\n"); goto err; - - /* Compile sections. */ - for (type = FIRST_KEYMAP_FILE_TYPE; - type <= LAST_KEYMAP_FILE_TYPE; - type++) { - log_dbg(ctx, "Compiling %s \"%s\"\n", - xkb_file_type_to_string(type), files[type]->topName); - ok = compile_file_fns[type](files[type], keymap, MERGE_OVERRIDE); - if (!ok) { - log_err(ctx, "Failed to compile %s\n", - xkb_file_type_to_string(type)); - goto err; - } } - ok = UpdateModifiersFromCompat(keymap); - if (!ok) - goto err; - return keymap; err: - log_err(ctx, "Failed to compile keymap\n"); xkb_map_unref(keymap); return NULL; }