X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fxkbcomp%2Fkeymap.c;h=087815927797ff406cfb5ff9fe79a3942e3d6ae4;hb=a83d745b62ea8ec89e939b00bb3754ad54280942;hp=f3bf82137a0bc76e19f1515dd73272655a208daf;hpb=75ff2cefdaf03008dcbe5d721315851eb46dfabc;p=platform%2Fupstream%2Flibxkbcommon.git diff --git a/src/xkbcomp/keymap.c b/src/xkbcomp/keymap.c index f3bf821..0878159 100644 --- a/src/xkbcomp/keymap.c +++ b/src/xkbcomp/keymap.c @@ -1,185 +1,301 @@ -/************************************************************ - Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc. - - Permission to use, copy, modify, and distribute this - software and its documentation for any purpose and without - fee is hereby granted, provided that the above copyright - notice appear in all copies and that both that copyright - notice and this permission notice appear in supporting - documentation, and that the name of Silicon Graphics not be - used in advertising or publicity pertaining to distribution - of the software without specific prior written permission. - Silicon Graphics makes no representation about the suitability - of this software for any purpose. It is provided "as is" - without any express or implied warranty. - - SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS - SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON - GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL - DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH - THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ********************************************************/ +/* + * Copyright © 2009 Dan Nicholson + * Copyright © 2012 Intel Corporation + * Copyright © 2012 Ran Benita + * + * 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 (including the next + * paragraph) 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 OR COPYRIGHT HOLDERS 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. + * + * Author: Dan Nicholson + * Daniel Stone + * Ran Benita + */ + +#include "config.h" #include "xkbcomp-priv.h" -#include "indicators.h" -/** - * Compile the given file and store the output in xkb. - * @param file A list of XkbFiles, each denoting one type (e.g. - * XkmKeyNamesIdx, etc.) - */ -struct xkb_keymap * -CompileKeymap(struct xkb_context *ctx, XkbFile *file) +static void +ComputeEffectiveMask(struct xkb_keymap *keymap, struct xkb_mods *mods) { - unsigned have; - bool ok; - unsigned required, legal; - unsigned mainType; - const char *mainName; - LEDInfo *unbound = NULL, *next; - struct xkb_keymap *keymap = XkbcAllocKeyboard(ctx); - struct { - XkbFile *keycodes; - XkbFile *types; - XkbFile *compat; - XkbFile *symbols; - } sections; - - if (!keymap) - return NULL; + mods->mask = mod_mask_get_effective(keymap, mods->mods); +} - memset(§ions, 0, sizeof(sections)); - mainType = file->type; - mainName = file->name ? file->name : "(unnamed)"; - switch (mainType) - { - case XkmKeymapFile: - required = XkmKeyNamesIndex | XkmTypesIndex | XkmSymbolsIndex | - XkmCompatMapIndex; - legal = XkmKeymapLegal; +static void +UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act, + xkb_mod_mask_t modmap) +{ + switch (act->type) { + case ACTION_TYPE_MOD_SET: + case ACTION_TYPE_MOD_LATCH: + case ACTION_TYPE_MOD_LOCK: + if (act->mods.flags & ACTION_MODS_LOOKUP_MODMAP) + act->mods.mods.mods = modmap; + ComputeEffectiveMask(keymap, &act->mods.mods); break; default: - ERROR("Cannot compile %s alone into an XKM file\n", - XkbcConfigText(mainType)); - return false; + break; } - have = 0; - - /* Check for duplicate entries in the input file */ - for (file = (XkbFile *) file->defs; file; file = (XkbFile *) file->common.next) - { - if ((have & (1 << file->type)) != 0) - { - ERROR("More than one %s section in a %s file\n", - XkbcConfigText(file->type), XkbcConfigText(mainType)); - ACTION("All sections after the first ignored\n"); - continue; - } - else if ((1 << file->type) & (~legal)) - { - ERROR("Cannot define %s in a %s file\n", - XkbcConfigText(file->type), XkbcConfigText(mainType)); +} + +static const struct xkb_sym_interpret default_interpret = { + .sym = XKB_KEY_NoSymbol, + .repeat = true, + .match = MATCH_ANY_OR_NONE, + .mods = 0, + .virtual_mod = XKB_MOD_INVALID, + .action = { .type = ACTION_TYPE_NONE }, +}; + +/** + * 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 const struct xkb_sym_interpret * +FindInterpForKey(struct xkb_keymap *keymap, const struct xkb_key *key, + xkb_layout_index_t group, xkb_level_index_t level) +{ + const xkb_keysym_t *syms; + int num_syms; + + num_syms = xkb_keymap_key_get_syms_by_level(keymap, key->keycode, group, + level, &syms); + if (num_syms == 0) + return NULL; + + /* + * There may be multiple matchings interprets; we should always return + * the most specific. Here we rely on compat.c to set up the + * sym_interprets array from the most specific to the least specific, + * such that when we find a match we return immediately. + */ + for (unsigned i = 0; i < keymap->num_sym_interprets; i++) { + const struct xkb_sym_interpret *interp = &keymap->sym_interprets[i]; + + xkb_mod_mask_t mods; + bool found = false; + + if ((num_syms > 1 || interp->sym != syms[0]) && + interp->sym != XKB_KEY_NoSymbol) continue; - } - switch (file->type) - { - case XkmKeyNamesIndex: - sections.keycodes = file; + if (interp->level_one_only && level != 0) + mods = 0; + else + mods = key->modmap; + + switch (interp->match) { + case MATCH_NONE: + found = !(interp->mods & mods); break; - case XkmTypesIndex: - sections.types = file; + case MATCH_ANY_OR_NONE: + found = (!mods || (interp->mods & mods)); break; - case XkmSymbolsIndex: - sections.symbols = file; + case MATCH_ANY: + found = (interp->mods & mods); break; - case XkmCompatMapIndex: - sections.compat = file; + case MATCH_ALL: + found = ((interp->mods & mods) == interp->mods); + break; + case MATCH_EXACTLY: + found = (interp->mods == mods); break; - case XkmGeometryIndex: - continue; - default: - WSGO("Unknown file type %d\n", file->type); - ACTION("Ignored\n"); - continue; - case XkmKeymapFile: - WSGO("Illegal %s configuration in a %s file\n", - XkbcConfigText(file->type), XkbcConfigText(mainType)); - ACTION("Ignored\n"); - continue; } - if (!file->topName || strcmp(file->topName, mainName) != 0) { - free(file->topName); - file->topName = strdup(mainName); + if (found) + return interp; + } + + return &default_interpret; +} + +static bool +ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key) +{ + xkb_mod_mask_t vmodmap = 0; + xkb_layout_index_t group; + xkb_level_index_t level; + + /* If we've been told not to bind interps to this key, then don't. */ + if (key->explicit & EXPLICIT_INTERP) + return true; + + for (group = 0; group < key->num_groups; group++) { + for (level = 0; level < XkbKeyNumLevels(key, group); level++) { + const struct xkb_sym_interpret *interp; + + interp = FindInterpForKey(keymap, key, group, level); + if (!interp) + continue; + + /* Infer default key behaviours from the base level. */ + if (group == 0 && level == 0) + if (!(key->explicit & EXPLICIT_REPEAT) && interp->repeat) + key->repeats = true; + + if ((group == 0 && level == 0) || !interp->level_one_only) + if (interp->virtual_mod != XKB_MOD_INVALID) + vmodmap |= (1u << interp->virtual_mod); + + if (interp->action.type != ACTION_TYPE_NONE) + key->groups[group].levels[level].action = interp->action; } + } + + if (!(key->explicit & EXPLICIT_VMODMAP)) + key->vmodmap = vmodmap; + + return true; +} + +/** + * 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) +{ + struct xkb_key *key; + struct xkb_mod *mod; + struct xkb_led *led; + unsigned int i, j; + + /* Find all the interprets for the key and bind them to actions, + * which will also update the vmodmap. */ + xkb_keys_foreach(key, keymap) + if (!ApplyInterpsToKey(keymap, key)) + return false; - have |= (1 << file->type); + /* Update keymap->mods, the virtual -> real mod mapping. */ + xkb_keys_foreach(key, keymap) + xkb_mods_enumerate(i, mod, &keymap->mods) + if (key->vmodmap & (1u << i)) + mod->mapping |= 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].entries[j].mods); + ComputeEffectiveMask(keymap, &keymap->types[i].entries[j].preserve); + } } - if (required & (~have)) - { - int i, bit; - unsigned missing; - missing = required & (~have); - for (i = 0, bit = 1; missing != 0; i++, bit <<= 1) - { - if (missing & bit) - { - ERROR("Required section %s missing from keymap\n", XkbcConfigText(i)); - missing &= ~bit; + /* Update action modifiers. */ + xkb_keys_foreach(key, keymap) + for (i = 0; i < key->num_groups; i++) + for (j = 0; j < XkbKeyNumLevels(key, i); j++) + UpdateActionMods(keymap, &key->groups[i].levels[j].action, + key->modmap); + + /* Update vmod -> led maps. */ + xkb_leds_foreach(led, keymap) + ComputeEffectiveMask(keymap, &led->mods); + + /* Find maximum number of groups out of all keys in the keymap. */ + xkb_keys_foreach(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; + XkbFile *files[LAST_KEYMAP_FILE_TYPE + 1] = { NULL }; + enum xkb_file_type type; + struct xkb_context *ctx = keymap->ctx; + + /* 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) { + if (file->file_type == FILE_TYPE_GEOMETRY) { + log_vrb(ctx, 1, + XKB_WARNING_UNSUPPORTED_GEOMETRY_SECTION, + "Geometry sections are not supported; ignoring\n"); + } else { + log_err(ctx, "Cannot define %s in a keymap file\n", + xkb_file_type_to_string(file->file_type)); } + continue; } - goto err; - } - /* compile the sections we have in the file one-by-one, or fail. */ - if (sections.keycodes == NULL || - !CompileKeycodes(sections.keycodes, keymap, MergeOverride)) - { - ERROR("Failed to compile keycodes\n"); - goto err; - } - if (sections.types == NULL || - !CompileKeyTypes(sections.types, keymap, MergeOverride)) - { - ERROR("Failed to compile key types\n"); - goto err; - } - if (sections.compat == NULL || - !CompileCompatMap(sections.compat, keymap, MergeOverride, &unbound)) - { - ERROR("Failed to compile compat map\n"); - goto err; - } - if (sections.symbols == NULL || - !CompileSymbols(sections.symbols, keymap, MergeOverride)) - { - ERROR("Failed to compile symbols\n"); - goto err; - } + 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; + } - ok = BindIndicators(keymap, true, unbound, NULL); - if (!ok) - goto err; + files[file->file_type] = file; + } - ok = UpdateModifiersFromCompat(keymap); + /* + * 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) - goto err; + return false; - return keymap; + /* 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]->name); -err: - ACTION("Failed to compile keymap\n"); - xkb_map_unref(keymap); - while (unbound) { - next = (LEDInfo *) unbound->defs.next; - free(unbound); - unbound = next; + 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 NULL; + + return UpdateDerivedKeymapFields(keymap); }