X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fxkbcomp%2Fkeymap.c;h=0aaed1f84874258eeceb89a35ba05f3c12487ee9;hb=e73599ee0ee7a5ee16cbdbac664872d0aa0cf2df;hp=9221852cbe5bdb25e1cd38a135c27e8f8858d580;hpb=ed18e65eacdabfeaeafee7c369891312af99c82d;p=platform%2Fupstream%2Flibxkbcommon.git diff --git a/src/xkbcomp/keymap.c b/src/xkbcomp/keymap.c index 9221852..0aaed1f 100644 --- a/src/xkbcomp/keymap.c +++ b/src/xkbcomp/keymap.c @@ -1,181 +1,305 @@ -/************************************************************ - 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. - - ********************************************************/ - -#include "xkbcomp.h" -#include "xkbmisc.h" -#include "expr.h" -#include "vmod.h" -#include "action.h" -#include "misc.h" -#include "indicators.h" - -#define KEYCODES 0 -#define GEOMETRY 1 -#define TYPES 2 -#define COMPAT 3 -#define SYMBOLS 4 -#define MAX_SECTIONS 5 - -/** - * Compile the given file and store the output in xkb. - * @param file A list of XkbFiles, each denoting one type (e.g. - * XkmKeyNamesIdx, etc.) +/* + * 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 */ -Bool -CompileKeymap(XkbFile *file, struct xkb_desc * xkb, unsigned merge) + +#include "config.h" + +#include "xkbcomp-priv.h" + +static void +ComputeEffectiveMask(struct xkb_keymap *keymap, struct xkb_mods *mods) { - unsigned have; - Bool ok; - unsigned required, legal; - unsigned mainType; - char *mainName; - LEDInfo *unbound = NULL; - XkbFile *sections[MAX_SECTIONS]; - - memset(sections, 0, sizeof(sections)); - mainType = file->type; - mainName = file->name; - switch (mainType) - { - case XkmSemanticsFile: - required = XkmSemanticsRequired; - legal = XkmSemanticsLegal; - break; - case XkmLayoutFile: /* standard type if setxkbmap -print */ - required = XkmLayoutRequired; - legal = XkmKeymapLegal; - break; - case XkmKeymapFile: - required = XkmKeymapRequired; - legal = XkmKeymapLegal; + mods->mask = mod_mask_get_effective(keymap, mods->mods); +} + +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; - ok = 1; - file = (XkbFile *) file->defs; - /* Check for duplicate entries in the input file */ - while ((file) && (ok)) - { - if (file->topName != mainName) { - free(file->topName); - file->topName = strdup(mainName); +} + +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; + + 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 MATCH_ANY_OR_NONE: + found = (!mods || (interp->mods & mods)); + break; + case MATCH_ANY: + found = (interp->mods & mods); + break; + case MATCH_ALL: + found = ((interp->mods & mods) == interp->mods); + break; + case MATCH_EXACTLY: + found = (interp->mods == mods); + break; } - 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"); - ok = False; + + 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; } - else if ((1 << file->type) & (~legal)) - { - ERROR("Cannot define %s in a %s file\n", - XkbcConfigText(file->type), XkbcConfigText(mainType)); - ok = False; + } + + 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; + + /* 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); } - else - switch (file->type) - { - case XkmSemanticsFile: - case XkmLayoutFile: - case XkmKeymapFile: - WSGO("Illegal %s configuration in a %s file\n", - XkbcConfigText(file->type), XkbcConfigText(mainType)); - ACTION("Ignored\n"); - ok = False; - break; - case XkmKeyNamesIndex: - sections[KEYCODES] = file; - break; - case XkmTypesIndex: - sections[TYPES] = file; - break; - case XkmSymbolsIndex: - sections[SYMBOLS] = file; - break; - case XkmCompatMapIndex: - sections[COMPAT] = file; - break; - case XkmGeometryIndex: - case XkmGeometryFile: - sections[GEOMETRY] = file; - break; - case XkmVirtualModsIndex: - case XkmIndicatorsIndex: - WSGO("Found an isolated %s section\n", - XkbcConfigText(file->type)); - break; - default: - WSGO("Unknown file type %d\n", file->type); - break; + } + + /* 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, XKB_LOG_MESSAGE_NO_ID, + "Cannot define %s in a keymap file\n", + xkb_file_type_to_string(file->file_type)); } - if (ok) - have |= (1 << file->type); - file = (XkbFile *) file->common.next; + continue; + } + + if (files[file->file_type]) { + log_err(ctx, XKB_LOG_MESSAGE_NO_ID, + "More than one %s section in keymap file; " + "All sections after the first ignored\n", + xkb_file_type_to_string(file->file_type)); + continue; + } + + files[file->file_type] = file; } - /* compile the sections we have in the file one-by-one, or fail. */ - if (ok) - { - if (ok && (sections[KEYCODES] != NULL)) - ok = CompileKeycodes(sections[KEYCODES], xkb, MergeOverride); - if (ok && (sections[GEOMETRY] != NULL)) - ok = CompileGeometry(sections[GEOMETRY], xkb, MergeOverride); - if (ok && (sections[TYPES] != NULL)) - ok = CompileKeyTypes(sections[TYPES], xkb, MergeOverride); - if (ok && (sections[COMPAT] != NULL)) - ok = CompileCompatMap(sections[COMPAT], xkb, MergeOverride, - &unbound); - if (ok && (sections[SYMBOLS] != NULL)) - ok = CompileSymbols(sections[SYMBOLS], xkb, MergeOverride); + + /* + * 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, XKB_LOG_MESSAGE_NO_ID, + "Required section %s missing from keymap\n", + xkb_file_type_to_string(type)); + ok = false; + } } if (!ok) - return False; - xkb->defined = have; - 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("Missing %s section in a %s file\n", - XkbcConfigText(i), XkbcConfigText(mainType)); - missing &= ~bit; - } + return false; + + /* Compile sections. */ + for (type = FIRST_KEYMAP_FILE_TYPE; + type <= LAST_KEYMAP_FILE_TYPE; + type++) { + log_dbg(ctx, XKB_LOG_MESSAGE_NO_ID, + "Compiling %s \"%s\"\n", + xkb_file_type_to_string(type), files[type]->name); + + ok = compile_file_fns[type](files[type], keymap, merge); + if (!ok) { + log_err(ctx, XKB_LOG_MESSAGE_NO_ID, + "Failed to compile %s\n", + xkb_file_type_to_string(type)); + return false; } - ACTION("Description of %s not compiled\n", - XkbcConfigText(mainType)); - return False; } - ok = BindIndicators(xkb, True, unbound, NULL); - return ok; + + return UpdateDerivedKeymapFields(keymap); }