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;
-}
--- /dev/null
+/*
+ * 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);
+}
#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;
}