/************************************************************
- 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 (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 © 2012 Ran Benita <ran234@gmail.com>
+ *
+ * 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.
+ */
+
#include "xkbcomp-priv.h"
-#include "parseutils.h"
+#include "text.h"
+#include "expr.h"
#include "action.h"
-#include "indicators.h"
#include "vmod.h"
+#include "include.h"
+
+/*
+ * The xkb_compat section
+ * =====================
+ * This section is the third to be processesed, after xkb_keycodes and
+ * xkb_types.
+ *
+ * Interpret statements
+ * --------------------
+ * Statements of the form:
+ * interpret Num_Lock+Any { ... }
+ *
+ * The body of the statment may include statements of the following
+ * forms:
+ *
+ * - action statement:
+ * action = LockMods(modifiers=NumLock);
+ *
+ * - virtual modifier statement:
+ * virtualModifier = NumLock;
+ *
+ * - repeat statement:
+ * repeat = True;
+ *
+ * - useModMapMods statement:
+ * useModMapMods = level1;
+ *
+ * Indicator map statements
+ * ------------------------
+ * Statements of the form:
+ * indicator "Shift Lock" { ... }
+ *
+ * This statement specifies the behavior and binding of the indicator
+ * with the given name ("Shift Lock" above). The name should have been
+ * declared previously in the xkb_keycodes section (see Indicator name
+ * statement), and given an index there. If it wasn't, it is created
+ * with the next free index.
+ * The body of the statement describes the conditions of the keyboard
+ * state which will cause the indicator to be lit. It may include the
+ * following statements:
+ *
+ * - modifiers statment:
+ * modifiers = ScrollLock;
+ *
+ * If the given modifiers are in the required state (see below), the
+ * led is lit.
+ *
+ * - whichModifierState statment:
+ * whichModState = Latched + Locked;
+ *
+ * Can be any combination of:
+ * base, latched, locked, effective
+ * any (i.e. all of the above)
+ * none (i.e. none of the above)
+ * compat (this is legal, but unused)
+ * This will cause the respective portion of the modifer state (see
+ * struct xkb_state) to be matched against the modifiers given in the
+ * "modifiers" statement.
+ *
+ * Here's a simple example:
+ * indicator "Num Lock" {
+ * modifiers = NumLock;
+ * whichModState = Locked;
+ * };
+ * Whenever the NumLock modifier is locked, the Num Lock indicator
+ * will light up.
+ *
+ * - groups statment:
+ * groups = All - group1;
+ *
+ * If the given groups are in the required state (see below), the led
+ * is lit.
+ *
+ * - whichGroupState statment:
+ * whichGroupState = Effective;
+ *
+ * Can be any combination of:
+ * base, latched, locked, effective
+ * any (i.e. all of the above)
+ * none (i.e. none of the above)
+ * This will cause the respective portion of the group state (see
+ * struct xkb_state) to be matched against the groups given in the
+ * "groups" statement.
+ *
+ * Note: the above conditions are disjunctive, i.e. if any of them are
+ * satisfied the led is lit.
+ *
+ * Virtual modifier statements
+ * ---------------------------
+ * Statements of the form:
+ * virtual_modifiers LControl;
+ *
+ * Can appear in the xkb_types, xkb_compat, xkb_symbols sections.
+ * TODO
+ *
+ * Effect on keymap
+ * ----------------
+ * After all of the xkb_compat sections have been compiled, the following
+ * members of struct xkb_keymap are finalized:
+ * darray(struct xkb_sym_interpret) sym_interpret;
+ * struct xkb_indicator_map indicators[XKB_NUM_INDICATORS];
+ * char *compat_section_name;
+ * TODO: virtual modifiers.
+ */
+
+enum si_field {
+ SI_FIELD_VIRTUAL_MOD = (1 << 0),
+ SI_FIELD_ACTION = (1 << 1),
+ SI_FIELD_AUTO_REPEAT = (1 << 2),
+ SI_FIELD_LEVEL_ONE_ONLY = (1 << 3),
+};
+
+typedef struct {
+ enum si_field defined;
+ unsigned file_id;
+ enum merge_mode merge;
-typedef struct _SymInterpInfo
-{
- CommonInfo defs;
struct xkb_sym_interpret interp;
} SymInterpInfo;
-#define _SI_VirtualMod (1<<0)
-#define _SI_Action (1<<1)
-#define _SI_AutoRepeat (1<<2)
-#define _SI_LockingKey (1<<3)
-#define _SI_LevelOneOnly (1<<4)
+enum led_field {
+ LED_FIELD_MODS = (1 << 0),
+ LED_FIELD_GROUPS = (1 << 1),
+ LED_FIELD_CTRLS = (1 << 2),
+};
-typedef struct _GroupCompatInfo
-{
- unsigned char fileID;
- unsigned char merge;
- bool defined;
- unsigned char real_mods;
- xkb_atom_t vmods;
-} GroupCompatInfo;
-
-typedef struct _CompatInfo
-{
+typedef struct {
+ enum led_field defined;
+ unsigned file_id;
+ enum merge_mode merge;
+
+ struct xkb_indicator_map im;
+} LEDInfo;
+
+typedef struct {
char *name;
- unsigned fileID;
+ unsigned file_id;
int errorCount;
- int nInterps;
- SymInterpInfo *interps;
SymInterpInfo dflt;
+ darray(SymInterpInfo) interps;
LEDInfo ledDflt;
- GroupCompatInfo groupCompat[XkbNumKbdGroups];
- LEDInfo *leds;
- VModInfo vmods;
- ActionInfo *act;
+ darray(LEDInfo) leds;
+ ActionsInfo *actions;
struct xkb_keymap *keymap;
} CompatInfo;
-/***====================================================================***/
-
-#define ReportSINotArray(si,f,i) \
- ReportNotArray("symbol interpretation",(f),siText((si),(i)))
-#define ReportSIBadType(si,f,w,i) \
- ReportBadType("symbol interpretation",(f),siText((si),(i)),(w))
-
-/***====================================================================***/
-
static const char *
-siText(SymInterpInfo * si, CompatInfo * info)
+siText(SymInterpInfo *si, CompatInfo *info)
{
static char buf[128];
if (si == &info->dflt)
- {
- snprintf(buf, sizeof(buf), "default");
- }
- else
- {
- snprintf(buf, sizeof(buf), "%s+%s(%s)",
- XkbcKeysymText(si->interp.sym),
- XkbcSIMatchText(si->interp.match),
- XkbcModMaskText(si->interp.mods, false));
- }
+ return "default";
+
+ snprintf(buf, sizeof(buf), "%s+%s(%s)",
+ KeysymText(si->interp.sym),
+ SIMatchText(si->interp.match),
+ ModMaskText(info->keymap, si->interp.mods, MOD_REAL));
return buf;
}
-static void
-InitCompatInfo(CompatInfo *info, struct xkb_keymap *keymap)
+static inline bool
+ReportSINotArray(CompatInfo *info, SymInterpInfo *si, const char *field)
{
- unsigned int i;
+ return ReportNotArray(info->keymap, "symbol interpretation", field,
+ siText(si, info));
+}
- info->keymap = keymap;
- info->name = NULL;
- info->fileID = 0;
- info->errorCount = 0;
- info->nInterps = 0;
- info->interps = NULL;
- info->act = NULL;
- info->dflt.defs.fileID = info->fileID;
- info->dflt.defs.defined = 0;
- info->dflt.defs.merge = MERGE_OVERRIDE;
- info->dflt.interp.flags = 0;
- info->dflt.interp.virtual_mod = XkbNoModifier;
- info->dflt.interp.act.type = XkbSA_NoAction;
- for (i = 0; i < sizeof(info->dflt.interp.act.any.data); i++)
- info->dflt.interp.act.any.data[i] = 0;
- ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt);
- info->ledDflt.defs.fileID = info->fileID;
- info->ledDflt.defs.defined = 0;
- info->ledDflt.defs.merge = MERGE_OVERRIDE;
- memset(&info->groupCompat[0], 0,
- XkbNumKbdGroups * sizeof(GroupCompatInfo));
- info->leds = NULL;
- InitVModInfo(&info->vmods, keymap);
+static inline bool
+ReportSIBadType(CompatInfo *info, SymInterpInfo *si, const char *field,
+ const char *wanted)
+{
+ return ReportBadType(info->keymap->ctx, "symbol interpretation", field,
+ siText(si, info), wanted);
}
-static void
-ClearCompatInfo(CompatInfo *info, struct xkb_keymap *keymap)
+static inline bool
+ReportIndicatorBadType(CompatInfo *info, LEDInfo *led,
+ const char *field, const char *wanted)
{
- unsigned int i;
- ActionInfo *next;
+ return ReportBadType(info->keymap->ctx, "indicator map", field,
+ xkb_atom_text(info->keymap->ctx, led->im.name),
+ wanted);
+}
- free(info->name);
- info->name = NULL;
- info->dflt.defs.defined = 0;
- info->dflt.defs.merge = MERGE_AUGMENT;
- info->dflt.interp.flags = 0;
- info->dflt.interp.virtual_mod = XkbNoModifier;
- info->dflt.interp.act.type = XkbSA_NoAction;
- for (i = 0; i < sizeof(info->dflt.interp.act.any.data); i++)
- info->dflt.interp.act.any.data[i] = 0;
- ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt);
- info->nInterps = 0;
- info->interps = ClearCommonInfo(&info->interps->defs);
- memset(&info->groupCompat[0], 0,
- XkbNumKbdGroups * sizeof(GroupCompatInfo));
- info->leds = ClearCommonInfo(&info->leds->defs);
- while (info->act) {
- next = info->act->next;
- free(info->act);
- info->act = next;
- }
- ClearVModInfo(&info->vmods, keymap);
+static inline bool
+ReportIndicatorNotArray(CompatInfo *info, LEDInfo *led,
+ const char *field)
+{
+ return ReportNotArray(info->keymap, "indicator map", field,
+ xkb_atom_text(info->keymap->ctx, led->im.name));
}
-static SymInterpInfo *
-NextInterp(CompatInfo * info)
+static void
+InitCompatInfo(CompatInfo *info, struct xkb_keymap *keymap, unsigned file_id,
+ ActionsInfo *actions)
{
- SymInterpInfo *si;
+ memset(info, 0, sizeof(*info));
+ info->keymap = keymap;
+ info->file_id = file_id;
+ info->actions = actions;
+ info->dflt.file_id = file_id;
+ info->dflt.merge = MERGE_OVERRIDE;
+ info->dflt.interp.virtual_mod = XKB_MOD_INVALID;
+ info->ledDflt.file_id = file_id;
+ info->ledDflt.merge = MERGE_OVERRIDE;
+}
- si = uTypedAlloc(SymInterpInfo);
- if (si)
- {
- memset(si, 0, sizeof(SymInterpInfo));
- info->interps = AddCommonInfo(&info->interps->defs, &si->defs);
- info->nInterps++;
- }
- return si;
+static void
+ClearCompatInfo(CompatInfo *info)
+{
+ free(info->name);
+ darray_free(info->interps);
+ darray_free(info->leds);
}
static SymInterpInfo *
-FindMatchingInterp(CompatInfo * info, SymInterpInfo * new)
+FindMatchingInterp(CompatInfo *info, SymInterpInfo *new)
{
SymInterpInfo *old;
- for (old = info->interps; old != NULL;
- old = (SymInterpInfo *) old->defs.next)
- {
- if ((old->interp.sym == new->interp.sym) &&
- (old->interp.mods == new->interp.mods) &&
- (old->interp.match == new->interp.match))
- {
+ darray_foreach(old, info->interps)
+ if (old->interp.sym == new->interp.sym &&
+ old->interp.mods == new->interp.mods &&
+ old->interp.match == new->interp.match)
return old;
- }
- }
+
return NULL;
}
static bool
-AddInterp(CompatInfo * info, SymInterpInfo * new)
+UseNewInterpField(enum si_field field, SymInterpInfo *old, SymInterpInfo *new,
+ bool report, enum si_field *collide)
{
- unsigned collide;
+ if (!(old->defined & field))
+ return true;
+
+ if (new->defined & field) {
+ if (report)
+ *collide |= field;
+
+ if (new->merge != MERGE_AUGMENT)
+ return true;
+ }
+
+ return false;
+}
+
+static bool
+AddInterp(CompatInfo *info, SymInterpInfo *new)
+{
+ enum si_field collide = 0;
SymInterpInfo *old;
- collide = 0;
old = FindMatchingInterp(info, new);
- if (old != NULL)
- {
- if (new->defs.merge == MERGE_REPLACE)
- {
- SymInterpInfo *next = (SymInterpInfo *) old->defs.next;
- if (((old->defs.fileID == new->defs.fileID)
- && (warningLevel > 0)) || (warningLevel > 9))
- {
- WARN("Multiple definitions for \"%s\"\n", siText(new, info));
- ACTION("Earlier interpretation ignored\n");
- }
+ if (old) {
+ int verbosity = xkb_context_get_log_verbosity(info->keymap->ctx);
+ bool report = ((old->file_id == new->file_id && verbosity > 0) ||
+ verbosity > 9);
+
+ if (new->merge == MERGE_REPLACE) {
+ if (report)
+ log_warn(info->keymap->ctx,
+ "Multiple definitions for \"%s\"; "
+ "Earlier interpretation ignored\n",
+ siText(new, info));
*old = *new;
- old->defs.next = &next->defs;
return true;
}
- if (UseNewField(_SI_VirtualMod, &old->defs, &new->defs, &collide))
- {
+
+ if (UseNewInterpField(SI_FIELD_VIRTUAL_MOD, old, new, report,
+ &collide)) {
old->interp.virtual_mod = new->interp.virtual_mod;
- old->defs.defined |= _SI_VirtualMod;
+ old->defined |= SI_FIELD_VIRTUAL_MOD;
}
- if (UseNewField(_SI_Action, &old->defs, &new->defs, &collide))
- {
+ if (UseNewInterpField(SI_FIELD_ACTION, old, new, report,
+ &collide)) {
old->interp.act = new->interp.act;
- old->defs.defined |= _SI_Action;
- }
- if (UseNewField(_SI_AutoRepeat, &old->defs, &new->defs, &collide))
- {
- old->interp.flags &= ~XkbSI_AutoRepeat;
- old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat);
- old->defs.defined |= _SI_AutoRepeat;
- }
- if (UseNewField(_SI_LockingKey, &old->defs, &new->defs, &collide))
- {
- old->interp.flags &= ~XkbSI_LockingKey;
- old->interp.flags |= (new->interp.flags & XkbSI_LockingKey);
- old->defs.defined |= _SI_LockingKey;
+ old->defined |= SI_FIELD_ACTION;
}
- if (UseNewField(_SI_LevelOneOnly, &old->defs, &new->defs, &collide))
- {
- old->interp.match &= ~XkbSI_LevelOneOnly;
- old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly);
- old->defs.defined |= _SI_LevelOneOnly;
+ if (UseNewInterpField(SI_FIELD_AUTO_REPEAT, old, new, report,
+ &collide)) {
+ old->interp.repeat = new->interp.repeat;
+ old->defined |= SI_FIELD_AUTO_REPEAT;
}
- if (collide)
- {
- WARN("Multiple interpretations of \"%s\"\n", siText(new, info));
- ACTION("Using %s definition for duplicate fields\n",
- (new->defs.merge != MERGE_AUGMENT ? "last" : "first"));
+ if (UseNewInterpField(SI_FIELD_LEVEL_ONE_ONLY, old, new, report,
+ &collide)) {
+ old->interp.match &= ~MATCH_LEVEL_ONE_ONLY;
+ old->interp.match |= (new->interp.match & MATCH_LEVEL_ONE_ONLY);
+ old->defined |= SI_FIELD_LEVEL_ONE_ONLY;
}
- return true;
- }
- old = new;
- if ((new = NextInterp(info)) == NULL)
- return false;
- *new = *old;
- new->defs.next = NULL;
- return true;
-}
-static bool
-AddGroupCompat(CompatInfo * info, unsigned group, GroupCompatInfo * newGC)
-{
- GroupCompatInfo *gc;
- enum merge_mode merge;
+ if (collide) {
+ log_warn(info->keymap->ctx,
+ "Multiple interpretations of \"%s\"; "
+ "Using %s definition for duplicate fields\n",
+ siText(new, info),
+ (new->merge != MERGE_AUGMENT ? "last" : "first"));
+ }
- merge = newGC->merge;
- gc = &info->groupCompat[group];
- if (((gc->real_mods == newGC->real_mods) && (gc->vmods == newGC->vmods)))
- {
return true;
}
- if (((gc->fileID == newGC->fileID) && (warningLevel > 0))
- || (warningLevel > 9))
- {
- WARN("Compat map for group %d redefined\n", group + 1);
- ACTION("Using %s definition\n",
- (merge == MERGE_AUGMENT ? "old" : "new"));
- }
- if (newGC->defined && (merge != MERGE_AUGMENT || !gc->defined))
- *gc = *newGC;
+
+ darray_append(info->interps, *new);
return true;
}
+
/***====================================================================***/
static bool
-ResolveStateAndPredicate(ExprDef * expr,
- unsigned *pred_rtrn,
- unsigned *mods_rtrn, CompatInfo * info)
+ResolveStateAndPredicate(ExprDef *expr, enum xkb_match_operation *pred_rtrn,
+ xkb_mod_mask_t *mods_rtrn, CompatInfo *info)
{
- ExprResult result;
-
- if (expr == NULL)
- {
- *pred_rtrn = XkbSI_AnyOfOrNone;
+ if (expr == NULL) {
+ *pred_rtrn = MATCH_ANY_OR_NONE;
*mods_rtrn = ~0;
return true;
}
- *pred_rtrn = XkbSI_Exactly;
- if (expr->op == ExprActionDecl)
- {
+ *pred_rtrn = MATCH_EXACTLY;
+ if (expr->op == EXPR_ACTION_DECL) {
const char *pred_txt = xkb_atom_text(info->keymap->ctx,
expr->value.action.name);
- if (strcasecmp(pred_txt, "noneof") == 0)
- *pred_rtrn = XkbSI_NoneOf;
- else if (strcasecmp(pred_txt, "anyofornone") == 0)
- *pred_rtrn = XkbSI_AnyOfOrNone;
- else if (strcasecmp(pred_txt, "anyof") == 0)
- *pred_rtrn = XkbSI_AnyOf;
- else if (strcasecmp(pred_txt, "allof") == 0)
- *pred_rtrn = XkbSI_AllOf;
- else if (strcasecmp(pred_txt, "exactly") == 0)
- *pred_rtrn = XkbSI_Exactly;
- else
- {
- ERROR("Illegal modifier predicate \"%s\"\n", pred_txt);
- ACTION("Ignored\n");
+ if (!LookupString(symInterpretMatchMaskNames, pred_txt, pred_rtrn)) {
+ log_err(info->keymap->ctx,
+ "Illegal modifier predicate \"%s\"; Ignored\n", pred_txt);
return false;
}
expr = expr->value.action.args;
}
- else if (expr->op == ExprIdent)
- {
+ else if (expr->op == EXPR_IDENT) {
const char *pred_txt = xkb_atom_text(info->keymap->ctx,
expr->value.str);
- if ((pred_txt) && (strcasecmp(pred_txt, "any") == 0))
- {
- *pred_rtrn = XkbSI_AnyOf;
+ if (pred_txt && istreq(pred_txt, "any")) {
+ *pred_rtrn = MATCH_ANY;
*mods_rtrn = 0xff;
return true;
}
}
- if (ExprResolveModMask(info->keymap->ctx, expr, &result))
- {
- *mods_rtrn = result.uval;
+ return ExprResolveModMask(info->keymap, expr, mods_rtrn);
+}
+
+/***====================================================================***/
+
+static bool
+UseNewLEDField(enum led_field field, LEDInfo *old, LEDInfo *new,
+ bool report, enum led_field *collide)
+{
+ if (!(old->defined & field))
return true;
+
+ if (new->defined & field) {
+ if (report)
+ *collide |= field;
+
+ if (new->merge != MERGE_AUGMENT)
+ return true;
}
+
return false;
}
-/***====================================================================***/
+static bool
+AddIndicatorMap(CompatInfo *info, LEDInfo *new)
+{
+ LEDInfo *old;
+ enum led_field collide;
+ struct xkb_context *ctx = info->keymap->ctx;
+ int verbosity = xkb_context_get_log_verbosity(ctx);
+
+ darray_foreach(old, info->leds) {
+ bool report;
+
+ if (old->im.name != new->im.name)
+ continue;
+
+ if (old->im.mods.mods == new->im.mods.mods &&
+ old->im.groups == new->im.groups &&
+ old->im.ctrls == new->im.ctrls &&
+ old->im.which_mods == new->im.which_mods &&
+ old->im.which_groups == new->im.which_groups) {
+ old->defined |= new->defined;
+ return true;
+ }
+
+ report = ((old->file_id == new->file_id && verbosity > 0) ||
+ verbosity > 9);
+
+ if (new->merge == MERGE_REPLACE) {
+ if (report)
+ log_warn(info->keymap->ctx,
+ "Map for indicator %s redefined; "
+ "Earlier definition ignored\n",
+ xkb_atom_text(ctx, old->im.name));
+ *old = *new;
+ return true;
+ }
+
+ collide = 0;
+ if (UseNewLEDField(LED_FIELD_MODS, old, new, report, &collide)) {
+ old->im.which_mods = new->im.which_mods;
+ old->im.mods = new->im.mods;
+ old->defined |= LED_FIELD_MODS;
+ }
+ if (UseNewLEDField(LED_FIELD_GROUPS, old, new, report, &collide)) {
+ old->im.which_groups = new->im.which_groups;
+ old->im.groups = new->im.groups;
+ old->defined |= LED_FIELD_GROUPS;
+ }
+ if (UseNewLEDField(LED_FIELD_CTRLS, old, new, report, &collide)) {
+ old->im.ctrls = new->im.ctrls;
+ old->defined |= LED_FIELD_CTRLS;
+ }
+
+ if (collide) {
+ log_warn(info->keymap->ctx,
+ "Map for indicator %s redefined; "
+ "Using %s definition for duplicate fields\n",
+ xkb_atom_text(ctx, old->im.name),
+ (new->merge == MERGE_AUGMENT ? "first" : "last"));
+ }
+
+ return true;
+ }
+
+ darray_append(info->leds, *new);
+ return true;
+}
static void
-MergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from, enum merge_mode merge)
+MergeIncludedCompatMaps(CompatInfo *into, CompatInfo *from,
+ enum merge_mode merge)
{
SymInterpInfo *si;
- LEDInfo *led, *rtrn, *next;
- GroupCompatInfo *gcm;
- int i;
+ LEDInfo *led;
- if (from->errorCount > 0)
- {
+ if (from->errorCount > 0) {
into->errorCount += from->errorCount;
return;
}
- if (into->name == NULL)
- {
+
+ if (into->name == NULL) {
into->name = from->name;
from->name = NULL;
}
- for (si = from->interps; si; si = (SymInterpInfo *) si->defs.next)
- {
- if (merge != MERGE_DEFAULT)
- si->defs.merge = merge;
+
+ darray_foreach(si, from->interps) {
+ si->merge = (merge == MERGE_DEFAULT ? si->merge : merge);
if (!AddInterp(into, si))
into->errorCount++;
}
- for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups; i++, gcm++)
- {
- if (merge != MERGE_DEFAULT)
- gcm->merge = merge;
- if (!AddGroupCompat(into, i, gcm))
- into->errorCount++;
- }
- for (led = from->leds; led != NULL; led = next)
- {
- next = (LEDInfo *) led->defs.next;
- if (merge != MERGE_DEFAULT)
- led->defs.merge = merge;
- rtrn = AddIndicatorMap(from->keymap, into->leds, led);
- if (rtrn != NULL)
- into->leds = rtrn;
- else
+
+ darray_foreach(led, from->leds) {
+ led->merge = (merge == MERGE_DEFAULT ? led->merge : merge);
+ if (!AddIndicatorMap(into, led))
into->errorCount++;
}
}
static void
-HandleCompatMapFile(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge,
- CompatInfo *info);
+HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge);
static bool
-HandleIncludeCompatMap(IncludeStmt *stmt, struct xkb_keymap *keymap,
- CompatInfo *info)
+HandleIncludeCompatMap(CompatInfo *info, IncludeStmt *stmt)
{
- unsigned newMerge;
+ enum merge_mode merge = MERGE_DEFAULT;
XkbFile *rtrn;
- CompatInfo included;
- bool haveSelf;
-
- haveSelf = false;
- if ((stmt->file == NULL) && (stmt->map == NULL))
- {
- haveSelf = true;
- included = *info;
- memset(info, 0, sizeof(CompatInfo));
+ CompatInfo included, next_incl;
+
+ InitCompatInfo(&included, info->keymap, info->file_id, info->actions);
+ if (stmt->stmt) {
+ free(included.name);
+ included.name = stmt->stmt;
+ stmt->stmt = NULL;
}
- else if (ProcessIncludeFile(keymap->ctx, stmt, FILE_TYPE_COMPAT, &rtrn,
- &newMerge))
- {
- InitCompatInfo(&included, keymap);
- included.fileID = rtrn->id;
- included.dflt = info->dflt;
- included.dflt.defs.fileID = rtrn->id;
- included.dflt.defs.merge = newMerge;
- included.ledDflt.defs.fileID = rtrn->id;
- included.ledDflt.defs.merge = newMerge;
- included.act = info->act;
- HandleCompatMapFile(rtrn, keymap, MERGE_OVERRIDE, &included);
- if (stmt->stmt != NULL)
- {
- free(included.name);
- included.name = stmt->stmt;
- stmt->stmt = NULL;
+
+ for (; stmt; stmt = stmt->next_incl) {
+ if (!ProcessIncludeFile(info->keymap->ctx, stmt, FILE_TYPE_COMPAT,
+ &rtrn, &merge)) {
+ info->errorCount += 10;
+ ClearCompatInfo(&included);
+ return false;
}
- if (info->act != NULL)
- included.act = NULL;
- FreeXKBFile(rtrn);
+
+ InitCompatInfo(&next_incl, info->keymap, rtrn->id, info->actions);
+ next_incl.file_id = rtrn->id;
+ next_incl.dflt = info->dflt;
+ next_incl.dflt.file_id = rtrn->id;
+ next_incl.dflt.merge = merge;
+ next_incl.ledDflt.file_id = rtrn->id;
+ next_incl.ledDflt.merge = merge;
+
+ HandleCompatMapFile(&next_incl, rtrn, MERGE_OVERRIDE);
+
+ MergeIncludedCompatMaps(&included, &next_incl, merge);
+
+ ClearCompatInfo(&next_incl);
+ FreeXkbFile(rtrn);
}
- else
- {
- info->errorCount += 10;
- return false;
+
+ MergeIncludedCompatMaps(info, &included, merge);
+ ClearCompatInfo(&included);
+
+ return (info->errorCount == 0);
+}
+
+static bool
+SetInterpField(CompatInfo *info, SymInterpInfo *si, const char *field,
+ ExprDef *arrayNdx, ExprDef *value)
+{
+ struct xkb_keymap *keymap = info->keymap;
+ xkb_mod_index_t ndx;
+
+ if (istreq(field, "action")) {
+ if (arrayNdx)
+ return ReportSINotArray(info, si, field);
+
+ if (!HandleActionDef(value, keymap, &si->interp.act, info->actions))
+ return false;
+
+ si->defined |= SI_FIELD_ACTION;
}
- if ((stmt->next != NULL) && (included.errorCount < 1))
- {
- IncludeStmt *next;
- unsigned op;
- CompatInfo next_incl;
-
- for (next = stmt->next; next != NULL; next = next->next)
- {
- if ((next->file == NULL) && (next->map == NULL))
- {
- haveSelf = true;
- MergeIncludedCompatMaps(&included, info, next->merge);
- ClearCompatInfo(info, keymap);
- }
- else if (ProcessIncludeFile(keymap->ctx, next, FILE_TYPE_COMPAT,
- &rtrn, &op))
- {
- InitCompatInfo(&next_incl, keymap);
- next_incl.fileID = rtrn->id;
- next_incl.dflt = info->dflt;
- next_incl.dflt.defs.fileID = rtrn->id;
- next_incl.dflt.defs.merge = op;
- next_incl.ledDflt.defs.fileID = rtrn->id;
- next_incl.ledDflt.defs.merge = op;
- next_incl.act = info->act;
- HandleCompatMapFile(rtrn, keymap, MERGE_OVERRIDE, &next_incl);
- MergeIncludedCompatMaps(&included, &next_incl, op);
- if (info->act != NULL)
- next_incl.act = NULL;
- ClearCompatInfo(&next_incl, keymap);
- FreeXKBFile(rtrn);
- }
- else
- {
- info->errorCount += 10;
- return false;
- }
- }
+ else if (istreq(field, "virtualmodifier") ||
+ istreq(field, "virtualmod")) {
+ if (arrayNdx)
+ return ReportSINotArray(info, si, field);
+
+ if (!ExprResolveVMod(keymap, value, &ndx))
+ return ReportSIBadType(info, si, field, "virtual modifier");
+
+ si->interp.virtual_mod = ndx;
+ si->defined |= SI_FIELD_VIRTUAL_MOD;
}
- if (haveSelf)
- *info = included;
- else
- {
- MergeIncludedCompatMaps(info, &included, newMerge);
- ClearCompatInfo(&included, keymap);
+ else if (istreq(field, "repeat")) {
+ bool set;
+
+ if (arrayNdx)
+ return ReportSINotArray(info, si, field);
+
+ if (!ExprResolveBoolean(keymap->ctx, value, &set))
+ return ReportSIBadType(info, si, field, "boolean");
+
+ si->interp.repeat = set;
+
+ si->defined |= SI_FIELD_AUTO_REPEAT;
}
- return (info->errorCount == 0);
-}
+ else if (istreq(field, "locking")) {
+ log_dbg(info->keymap->ctx,
+ "The \"locking\" field in symbol interpretation is unsupported; "
+ "Ignored\n");
+ }
+ else if (istreq(field, "usemodmap") ||
+ istreq(field, "usemodmapmods")) {
+ unsigned int val;
-static const LookupEntry useModMapValues[] = {
- {"levelone", 1},
- {"level1", 1},
- {"anylevel", 0},
- {"any", 0},
- {NULL, 0}
-};
+ if (arrayNdx)
+ return ReportSINotArray(info, si, field);
+
+ if (!ExprResolveEnum(keymap->ctx, value, &val, useModMapValueNames))
+ return ReportSIBadType(info, si, field, "level specification");
+
+ if (val)
+ si->interp.match |= MATCH_LEVEL_ONE_ONLY;
+ else
+ si->interp.match &= ~MATCH_LEVEL_ONE_ONLY;
+
+ si->defined |= SI_FIELD_LEVEL_ONE_ONLY;
+ }
+ else {
+ return ReportBadField(keymap, "symbol interpretation", field,
+ siText(si, info));
+ }
+
+ return true;
+}
-static int
-SetInterpField(SymInterpInfo *si, struct xkb_keymap *keymap, char *field,
- ExprDef *arrayNdx, ExprDef *value, CompatInfo *info)
+static bool
+SetIndicatorMapField(CompatInfo *info, LEDInfo *led,
+ const char *field, ExprDef *arrayNdx, ExprDef *value)
{
- int ok = 1;
- ExprResult tmp;
-
- if (strcasecmp(field, "action") == 0)
- {
- if (arrayNdx != NULL)
- return ReportSINotArray(si, field, info);
- ok = HandleActionDef(value, keymap, &si->interp.act.any, info->act);
- if (ok)
- si->defs.defined |= _SI_Action;
+ bool ok = true;
+ struct xkb_keymap *keymap = info->keymap;
+
+ if (istreq(field, "modifiers") || istreq(field, "mods")) {
+ if (arrayNdx)
+ return ReportIndicatorNotArray(info, led, field);
+
+ if (!ExprResolveVModMask(keymap, value, &led->im.mods.mods))
+ return ReportIndicatorBadType(info, led, field, "modifier mask");
+
+ led->defined |= LED_FIELD_MODS;
}
- else if ((strcasecmp(field, "virtualmodifier") == 0) ||
- (strcasecmp(field, "virtualmod") == 0))
- {
- if (arrayNdx != NULL)
- return ReportSINotArray(si, field, info);
- ok = ResolveVirtualModifier(value, keymap, &tmp, &info->vmods);
- if (ok)
- {
- si->interp.virtual_mod = tmp.uval;
- si->defs.defined |= _SI_VirtualMod;
- }
- else
- return ReportSIBadType(si, field, "virtual modifier", info);
+ else if (istreq(field, "groups")) {
+ unsigned int mask;
+
+ if (arrayNdx)
+ return ReportIndicatorNotArray(info, led, field);
+
+ if (!ExprResolveMask(keymap->ctx, value, &mask, groupMaskNames))
+ return ReportIndicatorBadType(info, led, field, "group mask");
+
+ led->im.groups = mask;
+ led->defined |= LED_FIELD_GROUPS;
}
- else if (strcasecmp(field, "repeat") == 0)
- {
- if (arrayNdx != NULL)
- return ReportSINotArray(si, field, info);
- ok = ExprResolveBoolean(keymap->ctx, value, &tmp);
- if (ok)
- {
- if (tmp.uval)
- si->interp.flags |= XkbSI_AutoRepeat;
- else
- si->interp.flags &= ~XkbSI_AutoRepeat;
- si->defs.defined |= _SI_AutoRepeat;
- }
- else
- return ReportSIBadType(si, field, "boolean", info);
+ else if (istreq(field, "controls") || istreq(field, "ctrls")) {
+ unsigned int mask;
+
+ if (arrayNdx)
+ return ReportIndicatorNotArray(info, led, field);
+
+ if (!ExprResolveMask(keymap->ctx, value, &mask, ctrlMaskNames))
+ return ReportIndicatorBadType(info, led, field,
+ "controls mask");
+
+ led->im.ctrls = mask;
+ led->defined |= LED_FIELD_CTRLS;
}
- else if (strcasecmp(field, "locking") == 0)
- {
- if (arrayNdx != NULL)
- return ReportSINotArray(si, field, info);
- ok = ExprResolveBoolean(keymap->ctx, value, &tmp);
- if (ok)
- {
- if (tmp.uval)
- si->interp.flags |= XkbSI_LockingKey;
- else
- si->interp.flags &= ~XkbSI_LockingKey;
- si->defs.defined |= _SI_LockingKey;
- }
- else
- return ReportSIBadType(si, field, "boolean", info);
+ else if (istreq(field, "allowexplicit")) {
+ log_dbg(info->keymap->ctx,
+ "The \"allowExplicit\" field in indicator statements is unsupported; "
+ "Ignored\n");
}
- else if ((strcasecmp(field, "usemodmap") == 0) ||
- (strcasecmp(field, "usemodmapmods") == 0))
- {
- if (arrayNdx != NULL)
- return ReportSINotArray(si, field, info);
- ok = ExprResolveEnum(keymap->ctx, value, &tmp, useModMapValues);
- if (ok)
- {
- if (tmp.uval)
- si->interp.match |= XkbSI_LevelOneOnly;
- else
- si->interp.match &= ~XkbSI_LevelOneOnly;
- si->defs.defined |= _SI_LevelOneOnly;
- }
- else
- return ReportSIBadType(si, field, "level specification", info);
+ else if (istreq(field, "whichmodstate") ||
+ istreq(field, "whichmodifierstate")) {
+ unsigned int mask;
+
+ if (arrayNdx)
+ return ReportIndicatorNotArray(info, led, field);
+
+ if (!ExprResolveMask(keymap->ctx, value, &mask,
+ modComponentMaskNames))
+ return ReportIndicatorBadType(info, led, field,
+ "mask of modifier state components");
+
+ led->im.which_mods = mask;
}
- else
- {
- ok = ReportBadField("symbol interpretation", field, siText(si, info));
+ else if (istreq(field, "whichgroupstate")) {
+ unsigned mask;
+
+ if (arrayNdx)
+ return ReportIndicatorNotArray(info, led, field);
+
+ if (!ExprResolveMask(keymap->ctx, value, &mask,
+ groupComponentMaskNames))
+ return ReportIndicatorBadType(info, led, field,
+ "mask of group state components");
+
+ led->im.which_groups = mask;
+ }
+ else if (istreq(field, "driveskbd") ||
+ istreq(field, "driveskeyboard") ||
+ istreq(field, "leddriveskbd") ||
+ istreq(field, "leddriveskeyboard") ||
+ istreq(field, "indicatordriveskbd") ||
+ istreq(field, "indicatordriveskeyboard")) {
+ log_dbg(info->keymap->ctx,
+ "The \"%s\" field in indicator statements is unsupported; "
+ "Ignored\n", field);
+ }
+ else if (istreq(field, "index")) {
+ /* Users should see this, it might cause unexpected behavior. */
+ log_err(info->keymap->ctx,
+ "The \"index\" field in indicator statements is unsupported; "
+ "Ignored\n");
}
+ else {
+ log_err(info->keymap->ctx,
+ "Unknown field %s in map for %s indicator; "
+ "Definition ignored\n",
+ field, xkb_atom_text(keymap->ctx, led->im.name));
+ ok = false;
+ }
+
return ok;
}
-static int
-HandleInterpVar(VarDef * stmt, struct xkb_keymap *keymap, CompatInfo * info)
+static bool
+HandleGlobalVar(CompatInfo *info, VarDef *stmt)
{
- ExprResult elem, field;
+ const char *elem, *field;
ExprDef *ndx;
- int ret;
-
- if (ExprResolveLhs(keymap, stmt->name, &elem, &field, &ndx) == 0)
- ret = 0; /* internal error, already reported */
- else if (elem.str && (strcasecmp(elem.str, "interpret") == 0))
- ret = SetInterpField(&info->dflt, keymap, field.str, ndx, stmt->value,
- info);
- else if (elem.str && (strcasecmp(elem.str, "indicator") == 0))
- ret = SetIndicatorMapField(&info->ledDflt, keymap, field.str, ndx,
- stmt->value);
+ bool ret;
+
+ if (!ExprResolveLhs(info->keymap->ctx, stmt->name, &elem, &field, &ndx))
+ ret = false;
+ else if (elem && istreq(elem, "interpret"))
+ ret = SetInterpField(info, &info->dflt, field, ndx, stmt->value);
+ else if (elem && istreq(elem, "indicator"))
+ ret = SetIndicatorMapField(info, &info->ledDflt, field, ndx,
+ stmt->value);
else
- ret = SetActionField(keymap, elem.str, field.str, ndx, stmt->value,
- &info->act);
- free(elem.str);
- free(field.str);
+ ret = SetActionField(info->keymap, elem, field, ndx, stmt->value,
+ info->actions);
return ret;
}
-static int
-HandleInterpBody(VarDef *def, struct xkb_keymap *keymap, SymInterpInfo *si,
- CompatInfo *info)
+static bool
+HandleInterpBody(CompatInfo *info, VarDef *def, SymInterpInfo *si)
{
- int ok = 1;
- ExprResult tmp, field;
+ bool ok = true;
+ const char *elem, *field;
ExprDef *arrayNdx;
- for (; def != NULL; def = (VarDef *) def->common.next)
- {
- if ((def->name) && (def->name->type == ExprFieldRef))
- {
- ok = HandleInterpVar(def, keymap, info);
+ for (; def; def = (VarDef *) def->common.next) {
+ if (def->name && def->name->op == EXPR_FIELD_REF) {
+ log_err(info->keymap->ctx,
+ "Cannot set a global default value from within an interpret statement; "
+ "Move statements to the global file scope\n");
+ ok = false;
continue;
}
- ok = ExprResolveLhs(keymap, def->name, &tmp, &field, &arrayNdx);
- if (ok) {
- ok = SetInterpField(si, keymap, field.str, arrayNdx, def->value,
- info);
- free(field.str);
- }
+
+ ok = ExprResolveLhs(info->keymap->ctx, def->name, &elem, &field,
+ &arrayNdx);
+ if (!ok)
+ continue;
+
+ ok = SetInterpField(info, si, field, arrayNdx, def->value);
}
+
return ok;
}
-static int
-HandleInterpDef(InterpDef *def, struct xkb_keymap *keymap, enum merge_mode merge,
- CompatInfo *info)
+static bool
+HandleInterpDef(CompatInfo *info, InterpDef *def, enum merge_mode merge)
{
- unsigned pred, mods;
+ enum xkb_match_operation pred;
+ xkb_mod_mask_t mods;
SymInterpInfo si;
- if (!ResolveStateAndPredicate(def->match, &pred, &mods, info))
- {
- ERROR("Couldn't determine matching modifiers\n");
- ACTION("Symbol interpretation ignored\n");
+ if (!ResolveStateAndPredicate(def->match, &pred, &mods, info)) {
+ log_err(info->keymap->ctx,
+ "Couldn't determine matching modifiers; "
+ "Symbol interpretation ignored\n");
return false;
}
- if (def->merge != MERGE_DEFAULT)
- merge = def->merge;
si = info->dflt;
- si.defs.merge = merge;
- if (!LookupKeysym(def->sym, &si.interp.sym))
- {
- ERROR("Could not resolve keysym %s\n", def->sym);
- ACTION("Symbol interpretation ignored\n");
+
+ si.merge = merge = (def->merge == MERGE_DEFAULT ? merge : def->merge);
+
+ if (!LookupKeysym(def->sym, &si.interp.sym)) {
+ log_err(info->keymap->ctx,
+ "Could not resolve keysym %s; "
+ "Symbol interpretation ignored\n",
+ def->sym);
return false;
}
- si.interp.match = pred & XkbSI_OpMask;
+
+ si.interp.match = pred & MATCH_OP_MASK;
+
si.interp.mods = mods;
- if (!HandleInterpBody(def->def, keymap, &si, info))
- {
+
+ if (!HandleInterpBody(info, def->def, &si)) {
info->errorCount++;
return false;
}
- if (!AddInterp(info, &si))
- {
+ if (!AddInterp(info, &si)) {
info->errorCount++;
return false;
}
+
return true;
}
-static int
-HandleGroupCompatDef(GroupCompatDef *def, struct xkb_keymap *keymap,
- enum merge_mode merge, CompatInfo *info)
+static bool
+HandleIndicatorMapDef(CompatInfo *info, IndicatorMapDef *def,
+ enum merge_mode merge)
{
- ExprResult val;
- GroupCompatInfo tmp;
+ LEDInfo led;
+ VarDef *var;
+ bool ok;
if (def->merge != MERGE_DEFAULT)
merge = def->merge;
- if (!XkbIsLegalGroup(def->group - 1))
- {
- ERROR("Keyboard group must be in the range 1..%d\n",
- XkbNumKbdGroups + 1);
- ACTION("Compatibility map for illegal group %d ignored\n",
- def->group);
- return false;
- }
- tmp.fileID = info->fileID;
- tmp.merge = merge;
- if (!ExprResolveVModMask(def->def, &val, keymap))
- {
- ERROR("Expected a modifier mask in group compatibility definition\n");
- ACTION("Ignoring illegal compatibility map for group %d\n",
- def->group);
- return false;
+
+ led = info->ledDflt;
+ led.merge = merge;
+ led.im.name = def->name;
+
+ ok = true;
+ for (var = def->body; var != NULL; var = (VarDef *) var->common.next) {
+ const char *elem, *field;
+ ExprDef *arrayNdx;
+ if (!ExprResolveLhs(info->keymap->ctx, var->name, &elem, &field,
+ &arrayNdx)) {
+ ok = false;
+ continue;
+ }
+
+ if (elem) {
+ log_err(info->keymap->ctx,
+ "Cannot set defaults for \"%s\" element in indicator map; "
+ "Assignment to %s.%s ignored\n", elem, elem, field);
+ ok = false;
+ }
+ else {
+ ok = SetIndicatorMapField(info, &led, field, arrayNdx,
+ var->value) && ok;
+ }
}
- tmp.real_mods = val.uval & 0xff;
- tmp.vmods = (val.uval >> 8) & 0xffff;
- tmp.defined = true;
- return AddGroupCompat(info, def->group - 1, &tmp);
+
+ if (ok)
+ return AddIndicatorMap(info, &led);
+
+ return false;
}
static void
-HandleCompatMapFile(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge,
- CompatInfo *info)
+HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge)
{
+ bool ok;
ParseCommon *stmt;
- if (merge == MERGE_DEFAULT)
- merge = MERGE_AUGMENT;
+ merge = (merge == MERGE_DEFAULT ? MERGE_AUGMENT : merge);
+
free(info->name);
- info->name = uDupString(file->name);
- stmt = file->defs;
- while (stmt)
- {
- switch (stmt->stmtType)
- {
- case StmtInclude:
- if (!HandleIncludeCompatMap((IncludeStmt *) stmt, keymap, info))
- info->errorCount++;
+ info->name = strdup_safe(file->name);
+
+ for (stmt = file->defs; stmt; stmt = stmt->next) {
+ switch (stmt->type) {
+ case STMT_INCLUDE:
+ ok = HandleIncludeCompatMap(info, (IncludeStmt *) stmt);
break;
- case StmtInterpDef:
- if (!HandleInterpDef((InterpDef *) stmt, keymap, merge, info))
- info->errorCount++;
+ case STMT_INTERP:
+ ok = HandleInterpDef(info, (InterpDef *) stmt, merge);
break;
- case StmtGroupCompatDef:
- if (!HandleGroupCompatDef
- ((GroupCompatDef *) stmt, keymap, merge, info))
- info->errorCount++;
+ case STMT_GROUP_COMPAT:
+ log_dbg(info->keymap->ctx,
+ "The \"group\" statement in compat is unsupported; "
+ "Ignored\n");
+ ok = true;
break;
- case StmtIndicatorMapDef:
- {
- LEDInfo *rtrn;
- rtrn = HandleIndicatorMapDef((IndicatorMapDef *) stmt, keymap,
- &info->ledDflt, info->leds, merge);
- if (rtrn != NULL)
- info->leds = rtrn;
- else
- info->errorCount++;
- }
+ case STMT_INDICATOR_MAP:
+ ok = HandleIndicatorMapDef(info, (IndicatorMapDef *) stmt, merge);
break;
- case StmtVarDef:
- if (!HandleInterpVar((VarDef *) stmt, keymap, info))
- info->errorCount++;
+ case STMT_VAR:
+ ok = HandleGlobalVar(info, (VarDef *) stmt);
break;
- case StmtVModDef:
- if (!HandleVModDef((VModDef *) stmt, keymap, merge, &info->vmods))
- info->errorCount++;
- break;
- case StmtKeycodeDef:
- ERROR("Interpretation files may not include other types\n");
- ACTION("Ignoring definition of key name\n");
- info->errorCount++;
+ case STMT_VMOD:
+ ok = HandleVModDef(info->keymap, (VModDef *) stmt);
break;
default:
- WSGO("Unexpected statement type %d in HandleCompatMapFile\n",
- stmt->stmtType);
+ log_err(info->keymap->ctx,
+ "Interpretation files may not include other types; "
+ "Ignoring %s\n", stmt_type_to_string(stmt->type));
+ ok = false;
break;
}
- stmt = stmt->next;
- if (info->errorCount > 10)
- {
-#ifdef NOISY
- ERROR("Too many errors\n");
-#endif
- ACTION("Abandoning compatibility map \"%s\"\n", file->topName);
+
+ if (!ok)
+ info->errorCount++;
+
+ if (info->errorCount > 10) {
+ log_err(info->keymap->ctx,
+ "Abandoning compatibility map \"%s\"\n", file->topName);
break;
}
}
}
static void
-CopyInterps(CompatInfo * info,
- struct xkb_compat_map * compat, bool needSymbol, unsigned pred)
+CopyInterps(CompatInfo *info, bool needSymbol, enum xkb_match_operation pred)
{
SymInterpInfo *si;
- for (si = info->interps; si; si = (SymInterpInfo *) si->defs.next)
- {
- if (((si->interp.match & XkbSI_OpMask) != pred) ||
- (needSymbol && (si->interp.sym == XKB_KEY_NoSymbol)) ||
- ((!needSymbol) && (si->interp.sym != XKB_KEY_NoSymbol)))
+ darray_foreach(si, info->interps) {
+ if (((si->interp.match & MATCH_OP_MASK) != pred) ||
+ (needSymbol && si->interp.sym == XKB_KEY_NoSymbol) ||
+ (!needSymbol && si->interp.sym != XKB_KEY_NoSymbol))
continue;
- darray_append(compat->sym_interpret, si->interp);
- }
-}
-
-bool
-CompileCompatMap(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge)
-{
- int i;
- CompatInfo info;
- GroupCompatInfo *gcm;
- LEDInfo *unbound = NULL, *next;
-
- InitCompatInfo(&info, keymap);
- info.dflt.defs.merge = merge;
- info.ledDflt.defs.merge = merge;
-
- HandleCompatMapFile(file, keymap, merge, &info);
-
- if (info.errorCount != 0)
- goto err_info;
-
- if (XkbcAllocCompatMap(keymap, info.nInterps) != Success) {
- WSGO("Couldn't allocate compatibility map\n");
- goto err_info;
- }
-
- if (info.nInterps > 0) {
- CopyInterps(&info, keymap->compat, true, XkbSI_Exactly);
- CopyInterps(&info, keymap->compat, true, XkbSI_AllOf | XkbSI_NoneOf);
- CopyInterps(&info, keymap->compat, true, XkbSI_AnyOf);
- CopyInterps(&info, keymap->compat, true, XkbSI_AnyOfOrNone);
- CopyInterps(&info, keymap->compat, false, XkbSI_Exactly);
- CopyInterps(&info, keymap->compat, false, XkbSI_AllOf | XkbSI_NoneOf);
- CopyInterps(&info, keymap->compat, false, XkbSI_AnyOf);
- CopyInterps(&info, keymap->compat, false, XkbSI_AnyOfOrNone);
- }
-
- for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups; i++, gcm++) {
- if ((gcm->fileID != 0) || (gcm->real_mods != 0) || (gcm->vmods != 0)) {
- keymap->compat->groups[i].mask = gcm->real_mods;
- keymap->compat->groups[i].real_mods = gcm->real_mods;
- keymap->compat->groups[i].vmods = gcm->vmods;
- }
- }
-
- if (info.leds != NULL) {
- if (!CopyIndicatorMapDefs(keymap, info.leds, &unbound))
- info.errorCount++;
- info.leds = NULL;
- }
- if (!BindIndicators(keymap, unbound)) {
- while (unbound) {
- next = (LEDInfo *) unbound->defs.next;
- free(unbound);
- unbound = next;
- }
-
- goto err_info;
+ darray_append(info->keymap->sym_interpret, si->interp);
}
-
- ClearCompatInfo(&info, keymap);
- return true;
-
-err_info:
- ClearCompatInfo(&info, keymap);
- return false;
-}
-
-static uint32_t
-VModsToReal(struct xkb_keymap *keymap, uint32_t vmodmask)
-{
- uint32_t ret = 0;
- int i;
-
- if (!vmodmask)
- return 0;
-
- for (i = 0; i < XkbNumVirtualMods; i++) {
- if (!(vmodmask & (1 << i)))
- continue;
- ret |= keymap->server->vmods[i];
- }
-
- return ret;
}
static void
-UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act,
- uint32_t rmodmask)
+CopyIndicatorMapDefs(CompatInfo *info)
{
- switch (act->type) {
- case XkbSA_SetMods:
- case XkbSA_LatchMods:
- case XkbSA_LockMods:
- if (act->mods.flags & XkbSA_UseModMapMods)
- act->mods.real_mods = rmodmask;
- act->mods.mask = act->mods.real_mods;
- act->mods.mask |= VModsToReal(keymap, act->mods.vmods);
- break;
- case XkbSA_ISOLock:
- if (act->iso.flags & XkbSA_UseModMapMods)
- act->iso.real_mods = rmodmask;
- act->iso.mask = act->iso.real_mods;
- act->iso.mask |= VModsToReal(keymap, act->iso.vmods);
- break;
- default:
- break;
- }
-}
-
-/**
- * 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, xkb_keycode_t key,
- uint32_t group, uint32_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->compat->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 = keymap->map->modmap[key];
- 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) == mods);
- break;
- case XkbSI_Exactly:
- found = (interp->mods == mods);
- break;
- default:
- found = false;
- break;
+ LEDInfo *led;
+ xkb_led_index_t i;
+ struct xkb_indicator_map *im;
+ struct xkb_keymap *keymap = info->keymap;
+
+ darray_foreach(led, info->leds) {
+ /*
+ * Find the indicator with the given name, if it was already
+ * declared in keycodes.
+ */
+ for (i = 0; i < XKB_NUM_INDICATORS; i++)
+ if (keymap->indicators[i].name == led->im.name)
+ break;
+
+ /* Not previously declared; create it with next free index. */
+ if (i >= XKB_NUM_INDICATORS) {
+ log_dbg(keymap->ctx,
+ "Indicator name \"%s\" was not declared in the keycodes section; "
+ "Adding new indicator\n",
+ xkb_atom_text(keymap->ctx, led->im.name));
+
+ for (i = 0; i < XKB_NUM_INDICATORS; i++)
+ if (keymap->indicators[i].name == XKB_ATOM_NONE)
+ break;
+
+ /* Not place to put it; ignore. */
+ if (i >= XKB_NUM_INDICATORS) {
+ log_err(keymap->ctx,
+ "Too many indicators (maximum is %d); "
+ "Indicator name \"%s\" ignored\n",
+ XKB_NUM_INDICATORS,
+ xkb_atom_text(keymap->ctx, led->im.name));
+ continue;
+ }
}
- if (found && interp->sym != XKB_KEY_NoSymbol)
- return interp;
- else if (found && !ret)
- ret = interp;
+ im = &keymap->indicators[i];
+ *im = led->im;
+ if (im->groups != 0 && im->which_groups == 0)
+ im->which_groups = XKB_STATE_EFFECTIVE;
+ if (im->mods.mods != 0 && im->which_mods == 0)
+ im->which_mods = XKB_STATE_EFFECTIVE;
}
-
- return ret;
}
-/**
- */
static bool
-ApplyInterpsToKey(struct xkb_keymap *keymap, xkb_keycode_t key)
+CopyCompatToKeymap(struct xkb_keymap *keymap, CompatInfo *info)
{
-#define INTERP_SIZE (8 * 4)
- struct xkb_sym_interpret *interps[INTERP_SIZE];
- union xkb_action *acts;
- uint32_t vmodmask = 0;
- int num_acts = 0;
- int group, level;
- int width = XkbKeyGroupsWidth(keymap, key);
- int i;
-
- /* If we've been told not to bind interps to this key, then don't. */
- if (keymap->server->explicit[key] & XkbExplicitInterpretMask)
- return true;
-
- for (i = 0; i < INTERP_SIZE; i++)
- interps[i] = NULL;
-
- for (group = 0; group < XkbKeyNumGroups(keymap, key); group++) {
- for (level = 0; level < XkbKeyGroupWidth(keymap, key, group); level++) {
- i = (group * 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)
- num_acts = XkbKeyNumGroups(keymap, key) * width;
- acts = XkbcResizeKeyActions(keymap, key, num_acts);
- if (num_acts && !acts)
- return false;
-
- for (group = 0; group < XkbKeyNumGroups(keymap, key); group++) {
- for (level = 0; level < XkbKeyGroupWidth(keymap, key, group); level++) {
- struct xkb_sym_interpret *interp;
-
- i = (group * width) + level;
- interp = interps[i];
-
- /* Infer default key behaviours from the base level. */
- if (group == 0 && level == 0) {
- if (!(keymap->server->explicit[key] & XkbExplicitAutoRepeatMask) &&
- (!interp || interp->flags & XkbSI_AutoRepeat))
- keymap->ctrls->per_key_repeat[key / 8] |= (1 << (key % 8));
- if (!(keymap->server->explicit[key] & XkbExplicitBehaviorMask) &&
- interp && (interp->flags & XkbSI_LockingKey))
- keymap->server->behaviors[key].type = XkbKB_Lock;
- }
-
- if (!interp)
- continue;
-
- if ((group == 0 && level == 0) ||
- !(interp->match & XkbSI_LevelOneOnly)) {
- if (interp->virtual_mod != XkbNoModifier)
- vmodmask |= (1 << interp->virtual_mod);
- }
- acts[i] = interp->act;
- }
+ keymap->compat_section_name = strdup_safe(info->name);
+
+ if (!darray_empty(info->interps)) {
+ /* Most specific to least specific. */
+ CopyInterps(info, true, MATCH_EXACTLY);
+ CopyInterps(info, true, MATCH_ALL);
+ CopyInterps(info, true, MATCH_ANY);
+ CopyInterps(info, true, MATCH_ANY_OR_NONE);
+ CopyInterps(info, false, MATCH_EXACTLY);
+ CopyInterps(info, false, MATCH_ALL);
+ CopyInterps(info, false, MATCH_ANY);
+ CopyInterps(info, false, MATCH_ANY_OR_NONE);
}
- if (!(keymap->server->explicit[key] & XkbExplicitVModMapMask))
- keymap->server->vmodmap[key] = vmodmask;
+ CopyIndicatorMapDefs(info);
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)
+CompileCompatMap(XkbFile *file, struct xkb_keymap *keymap,
+ enum merge_mode merge)
{
- xkb_keycode_t key;
- int i;
- struct xkb_key_type *type;
- struct xkb_kt_map_entry *entry;
-
- /* Find all the interprets for the key and bind them to actions,
- * which will also update the vmodmap. */
- for (key = keymap->min_key_code; key <= keymap->max_key_code; key++)
- if (!ApplyInterpsToKey(keymap, key))
- return false;
-
- /* Update keymap->server->vmods, the virtual -> real mod mapping. */
- for (i = 0; i < XkbNumVirtualMods; i++)
- keymap->server->vmods[i] = 0;
- for (key = keymap->min_key_code; key <= keymap->max_key_code; key++) {
- if (!keymap->server->vmodmap[key])
- continue;
- for (i = 0; i < XkbNumVirtualMods; i++) {
- if (!(keymap->server->vmodmap[key] & (1 << i)))
- continue;
- keymap->server->vmods[i] |= keymap->map->modmap[key];
- }
- }
-
- /* Now update the level masks for all the types to reflect the vmods. */
- darray_foreach(type, keymap->map->types) {
- uint32_t mask = 0;
- int j;
- type->mods.mask = type->mods.real_mods;
- type->mods.mask |= VModsToReal(keymap, type->mods.vmods);
- for (j = 0; j < XkbNumVirtualMods; j++) {
- if (!(type->mods.vmods & (1 << j)))
- continue;
- mask |= keymap->server->vmods[j];
- }
+ CompatInfo info;
+ ActionsInfo *actions;
- darray_foreach(entry, type->map)
- entry->mods.mask = entry->mods.real_mods |
- VModsToReal(keymap, entry->mods.vmods);
- }
+ actions = NewActionsInfo();
+ if (!actions)
+ return false;
- /* Update action modifiers. */
- for (key = keymap->min_key_code; key <= keymap->max_key_code; key++) {
- union xkb_action *acts = XkbKeyActionsPtr(keymap, key);
- for (i = 0; i < XkbKeyNumActions(keymap, key); i++) {
- if (acts[i].any.type == XkbSA_NoAction)
- continue;
- UpdateActionMods(keymap, &acts[i], keymap->map->modmap[key]);
- }
- }
+ InitCompatInfo(&info, keymap, file->id, actions);
+ info.dflt.merge = merge;
+ info.ledDflt.merge = merge;
- /* Update group modifiers. */
- for (i = 0; i < XkbNumKbdGroups; i++) {
- struct xkb_mods *group = &keymap->compat->groups[i];
- group->mask = group->real_mods | VModsToReal(keymap, group->vmods);
- }
+ HandleCompatMapFile(&info, file, merge);
+ if (info.errorCount != 0)
+ goto err_info;
- /* Update vmod -> indicator maps. */
- for (i = 0; i < XkbNumIndicators; i++) {
- struct xkb_mods *led = &keymap->indicators->maps[i].mods;
- led->mask = led->real_mods | VModsToReal(keymap, led->vmods);
- }
+ if (!CopyCompatToKeymap(keymap, &info))
+ goto err_info;
+ ClearCompatInfo(&info);
+ FreeActionsInfo(actions);
return true;
+
+err_info:
+ ClearCompatInfo(&info);
+ FreeActionsInfo(actions);
+ return false;
}