diff options
Diffstat (limited to 'xkbcomp/keycodes.c')
-rw-r--r-- | xkbcomp/keycodes.c | 1794 |
1 files changed, 896 insertions, 898 deletions
diff --git a/xkbcomp/keycodes.c b/xkbcomp/keycodes.c index 8f73268b9..0cffa8131 100644 --- a/xkbcomp/keycodes.c +++ b/xkbcomp/keycodes.c @@ -1,898 +1,896 @@ -/************************************************************ - 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 "tokens.h" -#include "expr.h" -#include "keycodes.h" -#include "misc.h" -#include "alias.h" - -char * -longText(unsigned long val, unsigned format) -{ - char buf[4]; - - LongToKeyName(val, buf); - return XkbKeyNameText(buf, format); -} - -/***====================================================================***/ - -void -LongToKeyName(unsigned long val, char *name) -{ - name[0] = ((val >> 24) & 0xff); - name[1] = ((val >> 16) & 0xff); - name[2] = ((val >> 8) & 0xff); - name[3] = (val & 0xff); - return; -} - -/***====================================================================***/ - -typedef struct _IndicatorNameInfo -{ - CommonInfo defs; - int ndx; - Atom name; - Bool virtual; -} IndicatorNameInfo; - -typedef struct _KeyNamesInfo -{ - char *name; /* e.g. evdev+aliases(qwerty) */ - int errorCount; - unsigned fileID; - unsigned merge; - int computedMin; /* lowest keycode stored */ - int computedMax; /* highest keycode stored */ - int explicitMin; - int explicitMax; - int effectiveMin; - int effectiveMax; - unsigned long names[XkbMaxLegalKeyCode + 1]; /* 4-letter name of key, keycode is the index */ - unsigned files[XkbMaxLegalKeyCode + 1]; - unsigned char has_alt_forms[XkbMaxLegalKeyCode + 1]; - IndicatorNameInfo *leds; - AliasInfo *aliases; -} KeyNamesInfo; - -static void HandleKeycodesFile(XkbFile * file, - XkbDescPtr xkb, - unsigned merge, - KeyNamesInfo * info); - -static void -InitIndicatorNameInfo(IndicatorNameInfo * ii, KeyNamesInfo * info) -{ - ii->defs.defined = 0; - ii->defs.merge = info->merge; - ii->defs.fileID = info->fileID; - ii->defs.next = NULL; - ii->ndx = 0; - ii->name = None; - ii->virtual = False; - return; -} - -static void -ClearIndicatorNameInfo(IndicatorNameInfo * ii, KeyNamesInfo * info) -{ - if (ii == info->leds) - { - ClearCommonInfo(&ii->defs); - info->leds = NULL; - } - return; -} - -static IndicatorNameInfo * -NextIndicatorName(KeyNamesInfo * info) -{ - IndicatorNameInfo *ii; - - ii = uTypedAlloc(IndicatorNameInfo); - if (ii) - { - InitIndicatorNameInfo(ii, info); - info->leds = (IndicatorNameInfo *) AddCommonInfo(&info->leds->defs, - (CommonInfo *) ii); - } - return ii; -} - -static IndicatorNameInfo * -FindIndicatorByIndex(KeyNamesInfo * info, int ndx) -{ - IndicatorNameInfo *old; - - for (old = info->leds; old != NULL; - old = (IndicatorNameInfo *) old->defs.next) - { - if (old->ndx == ndx) - return old; - } - return NULL; -} - -static IndicatorNameInfo * -FindIndicatorByName(KeyNamesInfo * info, Atom name) -{ - IndicatorNameInfo *old; - - for (old = info->leds; old != NULL; - old = (IndicatorNameInfo *) old->defs.next) - { - if (old->name == name) - return old; - } - return NULL; -} - -static Bool -AddIndicatorName(KeyNamesInfo * info, IndicatorNameInfo * new) -{ - IndicatorNameInfo *old; - Bool replace; - const char *action; - - replace = (new->defs.merge == MergeReplace) || - (new->defs.merge == MergeOverride); - old = FindIndicatorByName(info, new->name); - if (old) - { - if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0)) - || (warningLevel > 9)) - { - WARN1("Multiple indicators named %s\n", - XkbAtomText(NULL, new->name, XkbMessage)); - if (old->ndx == new->ndx) - { - if (old->virtual != new->virtual) - { - if (replace) - old->virtual = new->virtual; - action = "Using %s instead of %s\n"; - } - else - { - action = "Identical definitions ignored\n"; - } - ACTION2(action, (old->virtual ? "virtual" : "real"), - (old->virtual ? "real" : "virtual")); - return True; - } - else - { - if (replace) - action = "Ignoring %d, using %d\n"; - else - action = "Using %d, ignoring %d\n"; - ACTION2(action, old->ndx, new->ndx); - } - if (replace) - { - if (info->leds == old) - info->leds = (IndicatorNameInfo *) old->defs.next; - else - { - IndicatorNameInfo *tmp; - tmp = info->leds; - for (; tmp != NULL; - tmp = (IndicatorNameInfo *) tmp->defs.next) - { - if (tmp->defs.next == (CommonInfo *) old) - { - tmp->defs.next = old->defs.next; - break; - } - } - } - uFree(old); - } - } - } - old = FindIndicatorByIndex(info, new->ndx); - if (old) - { - if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0)) - || (warningLevel > 9)) - { - WARN1("Multiple names for indicator %d\n", new->ndx); - if ((old->name == new->name) && (old->virtual == new->virtual)) - action = "Identical definitions ignored\n"; - else - { - const char *oldType, *newType; - Atom using, ignoring; - if (old->virtual) - oldType = "virtual indicator"; - else - oldType = "real indicator"; - if (new->virtual) - newType = "virtual indicator"; - else - newType = "real indicator"; - if (replace) - { - using = new->name; - ignoring = old->name; - } - else - { - using = old->name; - ignoring = new->name; - } - ACTION4("Using %s %s, ignoring %s %s\n", - oldType, XkbAtomText(NULL, using, XkbMessage), - newType, XkbAtomText(NULL, ignoring, XkbMessage)); - } - } - if (replace) - { - old->name = new->name; - old->virtual = new->virtual; - } - return True; - } - old = new; - new = NextIndicatorName(info); - if (!new) - { - WSGO1("Couldn't allocate name for indicator %d\n", new->ndx); - ACTION("Ignored\n"); - return False; - } - new->name = old->name; - new->ndx = old->ndx; - new->virtual = old->virtual; - return True; -} - -static void -ClearKeyNamesInfo(KeyNamesInfo * info) -{ - if (info->name != NULL) - uFree(info->name); - info->name = NULL; - info->computedMax = info->explicitMax = info->explicitMin = -1; - info->computedMin = 256; - info->effectiveMin = 8; - info->effectiveMax = 255; - bzero((char *) info->names, sizeof(info->names)); - bzero((char *) info->files, sizeof(info->files)); - bzero((char *) info->has_alt_forms, sizeof(info->has_alt_forms)); - if (info->leds) - ClearIndicatorNameInfo(info->leds, info); - if (info->aliases) - ClearAliases(&info->aliases); - return; -} - -static void -InitKeyNamesInfo(KeyNamesInfo * info) -{ - info->name = NULL; - info->leds = NULL; - info->aliases = NULL; - info->fileID=-1; - info->merge=0; - ClearKeyNamesInfo(info); - info->errorCount = 0; - return; -} - -static int -FindKeyByLong(KeyNamesInfo * info, unsigned long name) -{ - register int i; - - for (i = info->effectiveMin; i <= info->effectiveMax; i++) - { - if (info->names[i] == name) - return i; - } - return 0; -} - -/** - * Store the name of the key as a long in the info struct under the given - * keycode. If the same keys is referred to twice, print a warning. - * Note that the key's name is stored as a long, the keycode is the index. - */ -static Bool -AddKeyName(KeyNamesInfo * info, - int kc, - char *name, unsigned merge, unsigned fileID, Bool reportCollisions) -{ - int old; - unsigned long lval; - - if ((kc < info->effectiveMin) || (kc > info->effectiveMax)) - { - ERROR2("Illegal keycode %d for name <%s>\n", kc, name); - ACTION2("Must be in the range %d-%d inclusive\n", - info->effectiveMin, info->effectiveMax); - return False; - } - if (kc < info->computedMin) - info->computedMin = kc; - if (kc > info->computedMax) - info->computedMax = kc; - lval = KeyNameToLong(name); - - if (reportCollisions) - { - reportCollisions = ((warningLevel > 7) || - ((warningLevel > 0) - && (fileID == info->files[kc]))); - } - - if (info->names[kc] != 0) - { - char buf[6]; - - LongToKeyName(info->names[kc], buf); - buf[4] = '\0'; - if (info->names[kc] == lval) - { - if (info->has_alt_forms[kc] || (merge == MergeAltForm)) - { - info->has_alt_forms[kc] = True; - } - else if (reportCollisions) - { - WARN("Multiple identical key name definitions\n"); - ACTION2("Later occurences of \"<%s> = %d\" ignored\n", - buf, kc); - } - return True; - } - if (merge == MergeAugment) - { - if (reportCollisions) - { - WARN1("Multiple names for keycode %d\n", kc); - ACTION2("Using <%s>, ignoring <%s>\n", buf, name); - } - return True; - } - else - { - if (reportCollisions) - { - WARN1("Multiple names for keycode %d\n", kc); - ACTION2("Using <%s>, ignoring <%s>\n", name, buf); - } - info->names[kc] = 0; - info->files[kc] = 0; - } - } - old = FindKeyByLong(info, lval); - if ((old != 0) && (old != kc)) - { - if (merge == MergeOverride) - { - info->names[old] = 0; - info->files[old] = 0; - info->has_alt_forms[old] = True; - if (reportCollisions) - { - WARN1("Key name <%s> assigned to multiple keys\n", name); - ACTION2("Using %d, ignoring %d\n", kc, old); - } - } - else if (merge != MergeAltForm) - { - if ((reportCollisions) && (warningLevel > 3)) - { - WARN1("Key name <%s> assigned to multiple keys\n", name); - ACTION2("Using %d, ignoring %d\n", old, kc); - ACTION - ("Use 'alternate' keyword to assign the same name to multiple keys\n"); - } - return True; - } - else - { - info->has_alt_forms[old] = True; - } - } - info->names[kc] = lval; - info->files[kc] = fileID; - info->has_alt_forms[kc] = (merge == MergeAltForm); - return True; -} - -/***====================================================================***/ - -static void -MergeIncludedKeycodes(KeyNamesInfo * into, KeyNamesInfo * from, - unsigned merge) -{ - register int i; - char buf[5]; - - if (from->errorCount > 0) - { - into->errorCount += from->errorCount; - return; - } - if (into->name == NULL) - { - into->name = from->name; - from->name = NULL; - } - for (i = from->computedMin; i <= from->computedMax; i++) - { - unsigned thisMerge; - if (from->names[i] == 0) - continue; - LongToKeyName(from->names[i], buf); - buf[4] = '\0'; - if (from->has_alt_forms[i]) - thisMerge = MergeAltForm; - else - thisMerge = merge; - if (!AddKeyName(into, i, buf, thisMerge, from->fileID, False)) - into->errorCount++; - } - if (from->leds) - { - IndicatorNameInfo *led, *next; - for (led = from->leds; led != NULL; led = next) - { - if (merge != MergeDefault) - led->defs.merge = merge; - if (!AddIndicatorName(into, led)) - into->errorCount++; - next = (IndicatorNameInfo *) led->defs.next; - } - } - if (!MergeAliases(&into->aliases, &from->aliases, merge)) - into->errorCount++; - if (from->explicitMin > 0) - { - if ((into->explicitMin < 0) - || (into->explicitMin > from->explicitMin)) - into->effectiveMin = into->explicitMin = from->explicitMin; - } - if (from->explicitMax > 0) - { - if ((into->explicitMax < 0) - || (into->explicitMax < from->explicitMax)) - into->effectiveMax = into->explicitMax = from->explicitMax; - } - return; -} - -/** - * Handle the given include statement (e.g. "include "evdev+aliases(qwerty)"). - * - * @param stmt The include statement from the keymap file. - * @param xkb Unused for all but the xkb->flags. - * @param info Struct to store the key info in. - */ -static Bool -HandleIncludeKeycodes(IncludeStmt * stmt, XkbDescPtr xkb, KeyNamesInfo * info) -{ - unsigned newMerge; - XkbFile *rtrn; - KeyNamesInfo included = {NULL}; - Bool haveSelf; - - haveSelf = False; - if ((stmt->file == NULL) && (stmt->map == NULL)) - { - haveSelf = True; - included = *info; - bzero(info, sizeof(KeyNamesInfo)); - } - else if (strcmp(stmt->file, "computed") == 0) - { - xkb->flags |= AutoKeyNames; - info->explicitMin = XkbMinLegalKeyCode; - info->explicitMax = XkbMaxLegalKeyCode; - return (info->errorCount == 0); - } /* parse file, store returned info in the xkb struct */ - else if (ProcessIncludeFile(stmt, XkmKeyNamesIndex, &rtrn, &newMerge)) - { - InitKeyNamesInfo(&included); - HandleKeycodesFile(rtrn, xkb, MergeOverride, &included); - if (stmt->stmt != NULL) - { - if (included.name != NULL) - uFree(included.name); - included.name = stmt->stmt; - stmt->stmt = NULL; - } - } - else - { - info->errorCount += 10; /* XXX: why 10?? */ - return False; - } - /* Do we have more than one include statement? */ - if ((stmt->next != NULL) && (included.errorCount < 1)) - { - IncludeStmt *next; - unsigned op; - KeyNamesInfo next_incl; - - for (next = stmt->next; next != NULL; next = next->next) - { - if ((next->file == NULL) && (next->map == NULL)) - { - haveSelf = True; - MergeIncludedKeycodes(&included, info, next->merge); - ClearKeyNamesInfo(info); - } - else if (ProcessIncludeFile(next, XkmKeyNamesIndex, &rtrn, &op)) - { - InitKeyNamesInfo(&next_incl); - HandleKeycodesFile(rtrn, xkb, MergeOverride, &next_incl); - MergeIncludedKeycodes(&included, &next_incl, op); - ClearKeyNamesInfo(&next_incl); - } - else - { - info->errorCount += 10; /* XXX: Why 10?? */ - return False; - } - } - } - if (haveSelf) - *info = included; - else - { - MergeIncludedKeycodes(info, &included, newMerge); - ClearKeyNamesInfo(&included); - } - return (info->errorCount == 0); -} - -/** - * Parse the given statement and store the output in the info struct. - * e.g. <ESC> = 9 - */ -static int -HandleKeycodeDef(KeycodeDef * stmt, unsigned merge, KeyNamesInfo * info) -{ - int code; - ExprResult result; - - if (!ExprResolveInteger(stmt->value, &result, NULL, NULL)) - { - ACTION1("No value keycode assigned to name <%s>\n", stmt->name); - return 0; - } - code = result.ival; - if ((code < info->effectiveMin) || (code > info->effectiveMax)) - { - ERROR2("Illegal keycode %d for name <%s>\n", code, stmt->name); - ACTION2("Must be in the range %d-%d inclusive\n", - info->effectiveMin, info->effectiveMax); - return 0; - } - if (stmt->merge != MergeDefault) - { - if (stmt->merge == MergeReplace) - merge = MergeOverride; - else - merge = stmt->merge; - } - return AddKeyName(info, code, stmt->name, merge, info->fileID, True); -} - -#define MIN_KEYCODE_DEF 0 -#define MAX_KEYCODE_DEF 1 - -/** - * Handle the minimum/maximum statement of the xkb file. - * Sets explicitMin/Max and effectiveMin/Max of the info struct. - * - * @return 1 on success, 0 otherwise. - */ -static int -HandleKeyNameVar(VarDef * stmt, KeyNamesInfo * info) -{ - ExprResult tmp, field; - ExprDef *arrayNdx; - int which; - - if (ExprResolveLhs(stmt->name, &tmp, &field, &arrayNdx) == 0) - return 0; /* internal error, already reported */ - - if (tmp.str != NULL) - { - ERROR1("Unknown element %s encountered\n", tmp.str); - ACTION1("Default for field %s ignored\n", field.str); - return 0; - } - if (uStrCaseCmp(field.str, "minimum") == 0) - which = MIN_KEYCODE_DEF; - else if (uStrCaseCmp(field.str, "maximum") == 0) - which = MAX_KEYCODE_DEF; - else - { - ERROR("Unknown field encountered\n"); - ACTION1("Assigment to field %s ignored\n", field.str); - return 0; - } - if (arrayNdx != NULL) - { - ERROR1("The %s setting is not an array\n", field.str); - ACTION("Illegal array reference ignored\n"); - return 0; - } - - if (ExprResolveInteger(stmt->value, &tmp, NULL, NULL) == 0) - { - ACTION1("Assignment to field %s ignored\n", field.str); - return 0; - } - if ((tmp.ival < XkbMinLegalKeyCode) || (tmp.ival > XkbMaxLegalKeyCode)) - { - ERROR3 - ("Illegal keycode %d (must be in the range %d-%d inclusive)\n", - tmp.ival, XkbMinLegalKeyCode, XkbMaxLegalKeyCode); - ACTION1("Value of \"%s\" not changed\n", field.str); - return 0; - } - if (which == MIN_KEYCODE_DEF) - { - if ((info->explicitMax > 0) && (info->explicitMax < tmp.ival)) - { - ERROR2 - ("Minimum key code (%d) must be <= maximum key code (%d)\n", - tmp.ival, info->explicitMax); - ACTION("Minimum key code value not changed\n"); - return 0; - } - if ((info->computedMax > 0) && (info->computedMin < tmp.ival)) - { - ERROR2 - ("Minimum key code (%d) must be <= lowest defined key (%d)\n", - tmp.ival, info->computedMin); - ACTION("Minimum key code value not changed\n"); - return 0; - } - info->explicitMin = tmp.ival; - info->effectiveMin = tmp.ival; - } - if (which == MAX_KEYCODE_DEF) - { - if ((info->explicitMin > 0) && (info->explicitMin > tmp.ival)) - { - ERROR2("Maximum code (%d) must be >= minimum key code (%d)\n", - tmp.ival, info->explicitMin); - ACTION("Maximum code value not changed\n"); - return 0; - } - if ((info->computedMax > 0) && (info->computedMax > tmp.ival)) - { - ERROR2 - ("Maximum code (%d) must be >= highest defined key (%d)\n", - tmp.ival, info->computedMax); - ACTION("Maximum code value not changed\n"); - return 0; - } - info->explicitMax = tmp.ival; - info->effectiveMax = tmp.ival; - } - return 1; -} - -static int -HandleIndicatorNameDef(IndicatorNameDef * def, - unsigned merge, KeyNamesInfo * info) -{ - IndicatorNameInfo ii; - ExprResult tmp; - - if ((def->ndx < 1) || (def->ndx > XkbNumIndicators)) - { - info->errorCount++; - ERROR1("Name specified for illegal indicator index %d\n", def->ndx); - ACTION("Ignored\n"); - return False; - } - InitIndicatorNameInfo(&ii, info); - ii.ndx = def->ndx; - if (!ExprResolveString(def->name, &tmp, NULL, NULL)) - { - char buf[20]; - snprintf(buf, sizeof(buf), "%d", def->ndx); - info->errorCount++; - return ReportBadType("indicator", "name", buf, "string"); - } - ii.name = XkbInternAtom(NULL, tmp.str, False); - ii.virtual = def->virtual; - if (!AddIndicatorName(info, &ii)) - return False; - return True; -} - -/** - * Handle the xkb_keycodes section of a xkb file. - * All information about parsed keys is stored in the info struct. - * - * Such a section may have include statements, in which case this function is - * semi-recursive (it calls HandleIncludeKeycodes, which may call - * HandleKeycodesFile again). - * - * @param file The input file (parsed xkb_keycodes section) - * @param xkb Necessary to pass down, may have flags changed. - * @param merge Merge strategy (MergeOverride, etc.) - * @param info Struct to contain the fully parsed key information. - */ -static void -HandleKeycodesFile(XkbFile * file, - XkbDescPtr xkb, unsigned merge, KeyNamesInfo * info) -{ - ParseCommon *stmt; - - info->name = uStringDup(file->name); - stmt = file->defs; - while (stmt) - { - switch (stmt->stmtType) - { - case StmtInclude: /* e.g. include "evdev+aliases(qwerty)" */ - if (!HandleIncludeKeycodes((IncludeStmt *) stmt, xkb, info)) - info->errorCount++; - break; - case StmtKeycodeDef: /* e.g. <ESC> = 9; */ - if (!HandleKeycodeDef((KeycodeDef *) stmt, merge, info)) - info->errorCount++; - break; - case StmtKeyAliasDef: /* e.g. alias <MENU> = <COMP>; */ - if (!HandleAliasDef((KeyAliasDef *) stmt, - merge, info->fileID, &info->aliases)) - info->errorCount++; - break; - case StmtVarDef: /* e.g. minimum, maximum */ - if (!HandleKeyNameVar((VarDef *) stmt, info)) - info->errorCount++; - break; - case StmtIndicatorNameDef: /* e.g. indicator 1 = "Caps Lock"; */ - if (!HandleIndicatorNameDef((IndicatorNameDef *) stmt, - merge, info)) - { - info->errorCount++; - } - break; - case StmtInterpDef: - case StmtVModDef: - ERROR("Keycode files may define key and indicator names only\n"); - ACTION1("Ignoring definition of %s\n", - ((stmt->stmtType == - StmtInterpDef) ? "a symbol interpretation" : - "virtual modifiers")); - info->errorCount++; - break; - default: - WSGO1("Unexpected statement type %d in HandleKeycodesFile\n", - stmt->stmtType); - break; - } - stmt = stmt->next; - if (info->errorCount > 10) - { -#ifdef NOISY - ERROR("Too many errors\n"); -#endif - ACTION1("Abandoning keycodes file \"%s\"\n", file->topName); - break; - } - } - return; -} - -/** - * Compile the xkb_keycodes section, parse it's output, return the results. - * - * @param file The parsed XKB file (may have include statements requiring - * further parsing) - * @param result The effective keycodes, as gathered from the file. - * @param merge Merge strategy. - * - * @return True on success, False otherwise. - */ -Bool -CompileKeycodes(XkbFile * file, XkbFileInfo * result, unsigned merge) -{ - KeyNamesInfo info; /* contains all the info after parsing */ - XkbDescPtr xkb; - - xkb = result->xkb; - InitKeyNamesInfo(&info); - HandleKeycodesFile(file, xkb, merge, &info); - - /* all the keys are now stored in info */ - - if (info.errorCount == 0) - { - if (info.explicitMin > 0) /* if "minimum" statement was present */ - xkb->min_key_code = info.effectiveMin; - else - xkb->min_key_code = info.computedMin; - if (info.explicitMax > 0) /* if "maximum" statement was present */ - xkb->max_key_code = info.effectiveMax; - else - xkb->max_key_code = info.computedMax; - if (XkbAllocNames(xkb, XkbKeyNamesMask | XkbIndicatorNamesMask, 0, 0) - == Success) - { - register int i; - xkb->names->keycodes = XkbInternAtom(xkb->dpy, info.name, False); - uDEBUG2(1, "key range: %d..%d\n", xkb->min_key_code, - xkb->max_key_code); - for (i = info.computedMin; i <= info.computedMax; i++) - { - LongToKeyName(info.names[i], xkb->names->keys[i].name); - uDEBUG2(2, "key %d = %s\n", i, - XkbKeyNameText(xkb->names->keys[i].name, XkbMessage)); - } - } - else - { - WSGO("Cannot create XkbNamesRec in CompileKeycodes\n"); - return False; - } - if (info.leds) - { - IndicatorNameInfo *ii; - if (XkbAllocIndicatorMaps(xkb) != Success) - { - WSGO("Couldn't allocate IndicatorRec in CompileKeycodes\n"); - ACTION("Physical indicators not set\n"); - } - for (ii = info.leds; ii != NULL; - ii = (IndicatorNameInfo *) ii->defs.next) - { - xkb->names->indicators[ii->ndx - 1] = - XkbInternAtom(xkb->dpy, - XkbAtomGetString(NULL, ii->name), False); - if (xkb->indicators != NULL) - { - register unsigned bit; - bit = 1 << (ii->ndx - 1); - if (ii->virtual) - xkb->indicators->phys_indicators &= ~bit; - else - xkb->indicators->phys_indicators |= bit; - } - } - } - if (info.aliases) - ApplyAliases(xkb, False, &info.aliases); - return True; - } - ClearKeyNamesInfo(&info); - return False; -} +/************************************************************
+ 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 "tokens.h"
+#include "expr.h"
+#include "keycodes.h"
+#include "misc.h"
+#include "alias.h"
+
+char *
+longText(unsigned long val, unsigned format)
+{
+ char buf[4];
+
+ LongToKeyName(val, buf);
+ return XkbKeyNameText(buf, format);
+}
+
+/***====================================================================***/
+
+void
+LongToKeyName(unsigned long val, char *name)
+{
+ name[0] = ((val >> 24) & 0xff);
+ name[1] = ((val >> 16) & 0xff);
+ name[2] = ((val >> 8) & 0xff);
+ name[3] = (val & 0xff);
+ return;
+}
+
+/***====================================================================***/
+
+typedef struct _IndicatorNameInfo
+{
+ CommonInfo defs;
+ int ndx;
+ Atom name;
+ Bool virtual;
+} IndicatorNameInfo;
+
+typedef struct _KeyNamesInfo
+{
+ char *name; /* e.g. evdev+aliases(qwerty) */
+ int errorCount;
+ unsigned fileID;
+ unsigned merge;
+ int computedMin; /* lowest keycode stored */
+ int computedMax; /* highest keycode stored */
+ int explicitMin;
+ int explicitMax;
+ int effectiveMin;
+ int effectiveMax;
+ unsigned long names[XkbMaxLegalKeyCode + 1]; /* 4-letter name of key, keycode is the index */
+ unsigned files[XkbMaxLegalKeyCode + 1];
+ unsigned char has_alt_forms[XkbMaxLegalKeyCode + 1];
+ IndicatorNameInfo *leds;
+ AliasInfo *aliases;
+} KeyNamesInfo;
+
+static void HandleKeycodesFile(XkbFile * file,
+ XkbDescPtr xkb,
+ unsigned merge,
+ KeyNamesInfo * info);
+
+static void
+InitIndicatorNameInfo(IndicatorNameInfo * ii, KeyNamesInfo * info)
+{
+ ii->defs.defined = 0;
+ ii->defs.merge = info->merge;
+ ii->defs.fileID = info->fileID;
+ ii->defs.next = NULL;
+ ii->ndx = 0;
+ ii->name = None;
+ ii->virtual = False;
+ return;
+}
+
+static void
+ClearIndicatorNameInfo(IndicatorNameInfo * ii, KeyNamesInfo * info)
+{
+ if (ii == info->leds)
+ {
+ ClearCommonInfo(&ii->defs);
+ info->leds = NULL;
+ }
+ return;
+}
+
+static IndicatorNameInfo *
+NextIndicatorName(KeyNamesInfo * info)
+{
+ IndicatorNameInfo *ii;
+
+ ii = uTypedAlloc(IndicatorNameInfo);
+ if (ii)
+ {
+ InitIndicatorNameInfo(ii, info);
+ info->leds = (IndicatorNameInfo *) AddCommonInfo(&info->leds->defs,
+ (CommonInfo *) ii);
+ }
+ return ii;
+}
+
+static IndicatorNameInfo *
+FindIndicatorByIndex(KeyNamesInfo * info, int ndx)
+{
+ IndicatorNameInfo *old;
+
+ for (old = info->leds; old != NULL;
+ old = (IndicatorNameInfo *) old->defs.next)
+ {
+ if (old->ndx == ndx)
+ return old;
+ }
+ return NULL;
+}
+
+static IndicatorNameInfo *
+FindIndicatorByName(KeyNamesInfo * info, Atom name)
+{
+ IndicatorNameInfo *old;
+
+ for (old = info->leds; old != NULL;
+ old = (IndicatorNameInfo *) old->defs.next)
+ {
+ if (old->name == name)
+ return old;
+ }
+ return NULL;
+}
+
+static Bool
+AddIndicatorName(KeyNamesInfo * info, IndicatorNameInfo * new)
+{
+ IndicatorNameInfo *old;
+ Bool replace;
+
+ replace = (new->defs.merge == MergeReplace) ||
+ (new->defs.merge == MergeOverride);
+ old = FindIndicatorByName(info, new->name);
+ if (old)
+ {
+ if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
+ || (warningLevel > 9))
+ {
+ WARN1("Multiple indicators named %s\n",
+ XkbAtomText(NULL, new->name, XkbMessage));
+ if (old->ndx == new->ndx)
+ {
+ if (old->virtual != new->virtual)
+ {
+ if (replace)
+ old->virtual = new->virtual;
+ ACTION2("Using %s instead of %s\n",
+ (old->virtual ? "virtual" : "real"),
+ (old->virtual ? "real" : "virtual"));
+ }
+ else
+ {
+ ACTION("Identical definitions ignored\n");
+ }
+ return True;
+ }
+ else
+ {
+ if (replace)
+ ACTION2("Ignoring %d, using %d\n", old->ndx, new->ndx);
+ else
+ ACTION2("Using %d, ignoring %d\n", old->ndx, new->ndx);
+ }
+ if (replace)
+ {
+ if (info->leds == old)
+ info->leds = (IndicatorNameInfo *) old->defs.next;
+ else
+ {
+ IndicatorNameInfo *tmp;
+ tmp = info->leds;
+ for (; tmp != NULL;
+ tmp = (IndicatorNameInfo *) tmp->defs.next)
+ {
+ if (tmp->defs.next == (CommonInfo *) old)
+ {
+ tmp->defs.next = old->defs.next;
+ break;
+ }
+ }
+ }
+ uFree(old);
+ }
+ }
+ }
+ old = FindIndicatorByIndex(info, new->ndx);
+ if (old)
+ {
+ if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
+ || (warningLevel > 9))
+ {
+ WARN1("Multiple names for indicator %d\n", new->ndx);
+ if ((old->name == new->name) && (old->virtual == new->virtual))
+ ACTION("Identical definitions ignored\n");
+ else
+ {
+ const char *oldType, *newType;
+ Atom using, ignoring;
+ if (old->virtual)
+ oldType = "virtual indicator";
+ else
+ oldType = "real indicator";
+ if (new->virtual)
+ newType = "virtual indicator";
+ else
+ newType = "real indicator";
+ if (replace)
+ {
+ using = new->name;
+ ignoring = old->name;
+ }
+ else
+ {
+ using = old->name;
+ ignoring = new->name;
+ }
+ ACTION4("Using %s %s, ignoring %s %s\n",
+ oldType, XkbAtomText(NULL, using, XkbMessage),
+ newType, XkbAtomText(NULL, ignoring, XkbMessage));
+ }
+ }
+ if (replace)
+ {
+ old->name = new->name;
+ old->virtual = new->virtual;
+ }
+ return True;
+ }
+ old = new;
+ new = NextIndicatorName(info);
+ if (!new)
+ {
+ WSGO1("Couldn't allocate name for indicator %d\n", new->ndx);
+ ACTION("Ignored\n");
+ return False;
+ }
+ new->name = old->name;
+ new->ndx = old->ndx;
+ new->virtual = old->virtual;
+ return True;
+}
+
+static void
+ClearKeyNamesInfo(KeyNamesInfo * info)
+{
+ if (info->name != NULL)
+ uFree(info->name);
+ info->name = NULL;
+ info->computedMax = info->explicitMax = info->explicitMin = -1;
+ info->computedMin = 256;
+ info->effectiveMin = 8;
+ info->effectiveMax = 255;
+ bzero((char *) info->names, sizeof(info->names));
+ bzero((char *) info->files, sizeof(info->files));
+ bzero((char *) info->has_alt_forms, sizeof(info->has_alt_forms));
+ if (info->leds)
+ ClearIndicatorNameInfo(info->leds, info);
+ if (info->aliases)
+ ClearAliases(&info->aliases);
+ return;
+}
+
+static void
+InitKeyNamesInfo(KeyNamesInfo * info)
+{
+ info->name = NULL;
+ info->leds = NULL;
+ info->aliases = NULL;
+ info->fileID=-1;
+ info->merge=0;
+ ClearKeyNamesInfo(info);
+ info->errorCount = 0;
+ return;
+}
+
+static int
+FindKeyByLong(KeyNamesInfo * info, unsigned long name)
+{
+ register int i;
+
+ for (i = info->effectiveMin; i <= info->effectiveMax; i++)
+ {
+ if (info->names[i] == name)
+ return i;
+ }
+ return 0;
+}
+
+/**
+ * Store the name of the key as a long in the info struct under the given
+ * keycode. If the same keys is referred to twice, print a warning.
+ * Note that the key's name is stored as a long, the keycode is the index.
+ */
+static Bool
+AddKeyName(KeyNamesInfo * info,
+ int kc,
+ char *name, unsigned merge, unsigned fileID, Bool reportCollisions)
+{
+ int old;
+ unsigned long lval;
+
+ if ((kc < info->effectiveMin) || (kc > info->effectiveMax))
+ {
+ ERROR2("Illegal keycode %d for name <%s>\n", kc, name);
+ ACTION2("Must be in the range %d-%d inclusive\n",
+ info->effectiveMin, info->effectiveMax);
+ return False;
+ }
+ if (kc < info->computedMin)
+ info->computedMin = kc;
+ if (kc > info->computedMax)
+ info->computedMax = kc;
+ lval = KeyNameToLong(name);
+
+ if (reportCollisions)
+ {
+ reportCollisions = ((warningLevel > 7) ||
+ ((warningLevel > 0)
+ && (fileID == info->files[kc])));
+ }
+
+ if (info->names[kc] != 0)
+ {
+ char buf[6];
+
+ LongToKeyName(info->names[kc], buf);
+ buf[4] = '\0';
+ if (info->names[kc] == lval)
+ {
+ if (info->has_alt_forms[kc] || (merge == MergeAltForm))
+ {
+ info->has_alt_forms[kc] = True;
+ }
+ else if (reportCollisions)
+ {
+ WARN("Multiple identical key name definitions\n");
+ ACTION2("Later occurences of \"<%s> = %d\" ignored\n",
+ buf, kc);
+ }
+ return True;
+ }
+ if (merge == MergeAugment)
+ {
+ if (reportCollisions)
+ {
+ WARN1("Multiple names for keycode %d\n", kc);
+ ACTION2("Using <%s>, ignoring <%s>\n", buf, name);
+ }
+ return True;
+ }
+ else
+ {
+ if (reportCollisions)
+ {
+ WARN1("Multiple names for keycode %d\n", kc);
+ ACTION2("Using <%s>, ignoring <%s>\n", name, buf);
+ }
+ info->names[kc] = 0;
+ info->files[kc] = 0;
+ }
+ }
+ old = FindKeyByLong(info, lval);
+ if ((old != 0) && (old != kc))
+ {
+ if (merge == MergeOverride)
+ {
+ info->names[old] = 0;
+ info->files[old] = 0;
+ info->has_alt_forms[old] = True;
+ if (reportCollisions)
+ {
+ WARN1("Key name <%s> assigned to multiple keys\n", name);
+ ACTION2("Using %d, ignoring %d\n", kc, old);
+ }
+ }
+ else if (merge != MergeAltForm)
+ {
+ if ((reportCollisions) && (warningLevel > 3))
+ {
+ WARN1("Key name <%s> assigned to multiple keys\n", name);
+ ACTION2("Using %d, ignoring %d\n", old, kc);
+ ACTION
+ ("Use 'alternate' keyword to assign the same name to multiple keys\n");
+ }
+ return True;
+ }
+ else
+ {
+ info->has_alt_forms[old] = True;
+ }
+ }
+ info->names[kc] = lval;
+ info->files[kc] = fileID;
+ info->has_alt_forms[kc] = (merge == MergeAltForm);
+ return True;
+}
+
+/***====================================================================***/
+
+static void
+MergeIncludedKeycodes(KeyNamesInfo * into, KeyNamesInfo * from,
+ unsigned merge)
+{
+ register int i;
+ char buf[5];
+
+ if (from->errorCount > 0)
+ {
+ into->errorCount += from->errorCount;
+ return;
+ }
+ if (into->name == NULL)
+ {
+ into->name = from->name;
+ from->name = NULL;
+ }
+ for (i = from->computedMin; i <= from->computedMax; i++)
+ {
+ unsigned thisMerge;
+ if (from->names[i] == 0)
+ continue;
+ LongToKeyName(from->names[i], buf);
+ buf[4] = '\0';
+ if (from->has_alt_forms[i])
+ thisMerge = MergeAltForm;
+ else
+ thisMerge = merge;
+ if (!AddKeyName(into, i, buf, thisMerge, from->fileID, False))
+ into->errorCount++;
+ }
+ if (from->leds)
+ {
+ IndicatorNameInfo *led, *next;
+ for (led = from->leds; led != NULL; led = next)
+ {
+ if (merge != MergeDefault)
+ led->defs.merge = merge;
+ if (!AddIndicatorName(into, led))
+ into->errorCount++;
+ next = (IndicatorNameInfo *) led->defs.next;
+ }
+ }
+ if (!MergeAliases(&into->aliases, &from->aliases, merge))
+ into->errorCount++;
+ if (from->explicitMin > 0)
+ {
+ if ((into->explicitMin < 0)
+ || (into->explicitMin > from->explicitMin))
+ into->effectiveMin = into->explicitMin = from->explicitMin;
+ }
+ if (from->explicitMax > 0)
+ {
+ if ((into->explicitMax < 0)
+ || (into->explicitMax < from->explicitMax))
+ into->effectiveMax = into->explicitMax = from->explicitMax;
+ }
+ return;
+}
+
+/**
+ * Handle the given include statement (e.g. "include "evdev+aliases(qwerty)").
+ *
+ * @param stmt The include statement from the keymap file.
+ * @param xkb Unused for all but the xkb->flags.
+ * @param info Struct to store the key info in.
+ */
+static Bool
+HandleIncludeKeycodes(IncludeStmt * stmt, XkbDescPtr xkb, KeyNamesInfo * info)
+{
+ unsigned newMerge;
+ XkbFile *rtrn;
+ KeyNamesInfo included = {NULL};
+ Bool haveSelf;
+
+ haveSelf = False;
+ if ((stmt->file == NULL) && (stmt->map == NULL))
+ {
+ haveSelf = True;
+ included = *info;
+ bzero(info, sizeof(KeyNamesInfo));
+ }
+ else if (strcmp(stmt->file, "computed") == 0)
+ {
+ xkb->flags |= AutoKeyNames;
+ info->explicitMin = XkbMinLegalKeyCode;
+ info->explicitMax = XkbMaxLegalKeyCode;
+ return (info->errorCount == 0);
+ } /* parse file, store returned info in the xkb struct */
+ else if (ProcessIncludeFile(stmt, XkmKeyNamesIndex, &rtrn, &newMerge))
+ {
+ InitKeyNamesInfo(&included);
+ HandleKeycodesFile(rtrn, xkb, MergeOverride, &included);
+ if (stmt->stmt != NULL)
+ {
+ if (included.name != NULL)
+ uFree(included.name);
+ included.name = stmt->stmt;
+ stmt->stmt = NULL;
+ }
+ }
+ else
+ {
+ info->errorCount += 10; /* XXX: why 10?? */
+ return False;
+ }
+ /* Do we have more than one include statement? */
+ if ((stmt->next != NULL) && (included.errorCount < 1))
+ {
+ IncludeStmt *next;
+ unsigned op;
+ KeyNamesInfo next_incl;
+
+ for (next = stmt->next; next != NULL; next = next->next)
+ {
+ if ((next->file == NULL) && (next->map == NULL))
+ {
+ haveSelf = True;
+ MergeIncludedKeycodes(&included, info, next->merge);
+ ClearKeyNamesInfo(info);
+ }
+ else if (ProcessIncludeFile(next, XkmKeyNamesIndex, &rtrn, &op))
+ {
+ InitKeyNamesInfo(&next_incl);
+ HandleKeycodesFile(rtrn, xkb, MergeOverride, &next_incl);
+ MergeIncludedKeycodes(&included, &next_incl, op);
+ ClearKeyNamesInfo(&next_incl);
+ }
+ else
+ {
+ info->errorCount += 10; /* XXX: Why 10?? */
+ return False;
+ }
+ }
+ }
+ if (haveSelf)
+ *info = included;
+ else
+ {
+ MergeIncludedKeycodes(info, &included, newMerge);
+ ClearKeyNamesInfo(&included);
+ }
+ return (info->errorCount == 0);
+}
+
+/**
+ * Parse the given statement and store the output in the info struct.
+ * e.g. <ESC> = 9
+ */
+static int
+HandleKeycodeDef(KeycodeDef * stmt, unsigned merge, KeyNamesInfo * info)
+{
+ int code;
+ ExprResult result;
+
+ if (!ExprResolveInteger(stmt->value, &result, NULL, NULL))
+ {
+ ACTION1("No value keycode assigned to name <%s>\n", stmt->name);
+ return 0;
+ }
+ code = result.ival;
+ if ((code < info->effectiveMin) || (code > info->effectiveMax))
+ {
+ ERROR2("Illegal keycode %d for name <%s>\n", code, stmt->name);
+ ACTION2("Must be in the range %d-%d inclusive\n",
+ info->effectiveMin, info->effectiveMax);
+ return 0;
+ }
+ if (stmt->merge != MergeDefault)
+ {
+ if (stmt->merge == MergeReplace)
+ merge = MergeOverride;
+ else
+ merge = stmt->merge;
+ }
+ return AddKeyName(info, code, stmt->name, merge, info->fileID, True);
+}
+
+#define MIN_KEYCODE_DEF 0
+#define MAX_KEYCODE_DEF 1
+
+/**
+ * Handle the minimum/maximum statement of the xkb file.
+ * Sets explicitMin/Max and effectiveMin/Max of the info struct.
+ *
+ * @return 1 on success, 0 otherwise.
+ */
+static int
+HandleKeyNameVar(VarDef * stmt, KeyNamesInfo * info)
+{
+ ExprResult tmp, field;
+ ExprDef *arrayNdx;
+ int which;
+
+ if (ExprResolveLhs(stmt->name, &tmp, &field, &arrayNdx) == 0)
+ return 0; /* internal error, already reported */
+
+ if (tmp.str != NULL)
+ {
+ ERROR1("Unknown element %s encountered\n", tmp.str);
+ ACTION1("Default for field %s ignored\n", field.str);
+ return 0;
+ }
+ if (uStrCaseCmp(field.str, "minimum") == 0)
+ which = MIN_KEYCODE_DEF;
+ else if (uStrCaseCmp(field.str, "maximum") == 0)
+ which = MAX_KEYCODE_DEF;
+ else
+ {
+ ERROR("Unknown field encountered\n");
+ ACTION1("Assigment to field %s ignored\n", field.str);
+ return 0;
+ }
+ if (arrayNdx != NULL)
+ {
+ ERROR1("The %s setting is not an array\n", field.str);
+ ACTION("Illegal array reference ignored\n");
+ return 0;
+ }
+
+ if (ExprResolveInteger(stmt->value, &tmp, NULL, NULL) == 0)
+ {
+ ACTION1("Assignment to field %s ignored\n", field.str);
+ return 0;
+ }
+ if ((tmp.ival < XkbMinLegalKeyCode) || (tmp.ival > XkbMaxLegalKeyCode))
+ {
+ ERROR3
+ ("Illegal keycode %d (must be in the range %d-%d inclusive)\n",
+ tmp.ival, XkbMinLegalKeyCode, XkbMaxLegalKeyCode);
+ ACTION1("Value of \"%s\" not changed\n", field.str);
+ return 0;
+ }
+ if (which == MIN_KEYCODE_DEF)
+ {
+ if ((info->explicitMax > 0) && (info->explicitMax < tmp.ival))
+ {
+ ERROR2
+ ("Minimum key code (%d) must be <= maximum key code (%d)\n",
+ tmp.ival, info->explicitMax);
+ ACTION("Minimum key code value not changed\n");
+ return 0;
+ }
+ if ((info->computedMax > 0) && (info->computedMin < tmp.ival))
+ {
+ ERROR2
+ ("Minimum key code (%d) must be <= lowest defined key (%d)\n",
+ tmp.ival, info->computedMin);
+ ACTION("Minimum key code value not changed\n");
+ return 0;
+ }
+ info->explicitMin = tmp.ival;
+ info->effectiveMin = tmp.ival;
+ }
+ if (which == MAX_KEYCODE_DEF)
+ {
+ if ((info->explicitMin > 0) && (info->explicitMin > tmp.ival))
+ {
+ ERROR2("Maximum code (%d) must be >= minimum key code (%d)\n",
+ tmp.ival, info->explicitMin);
+ ACTION("Maximum code value not changed\n");
+ return 0;
+ }
+ if ((info->computedMax > 0) && (info->computedMax > tmp.ival))
+ {
+ ERROR2
+ ("Maximum code (%d) must be >= highest defined key (%d)\n",
+ tmp.ival, info->computedMax);
+ ACTION("Maximum code value not changed\n");
+ return 0;
+ }
+ info->explicitMax = tmp.ival;
+ info->effectiveMax = tmp.ival;
+ }
+ return 1;
+}
+
+static int
+HandleIndicatorNameDef(IndicatorNameDef * def,
+ unsigned merge, KeyNamesInfo * info)
+{
+ IndicatorNameInfo ii;
+ ExprResult tmp;
+
+ if ((def->ndx < 1) || (def->ndx > XkbNumIndicators))
+ {
+ info->errorCount++;
+ ERROR1("Name specified for illegal indicator index %d\n", def->ndx);
+ ACTION("Ignored\n");
+ return False;
+ }
+ InitIndicatorNameInfo(&ii, info);
+ ii.ndx = def->ndx;
+ if (!ExprResolveString(def->name, &tmp, NULL, NULL))
+ {
+ char buf[20];
+ snprintf(buf, sizeof(buf), "%d", def->ndx);
+ info->errorCount++;
+ return ReportBadType("indicator", "name", buf, "string");
+ }
+ ii.name = XkbInternAtom(NULL, tmp.str, False);
+ ii.virtual = def->virtual;
+ if (!AddIndicatorName(info, &ii))
+ return False;
+ return True;
+}
+
+/**
+ * Handle the xkb_keycodes section of a xkb file.
+ * All information about parsed keys is stored in the info struct.
+ *
+ * Such a section may have include statements, in which case this function is
+ * semi-recursive (it calls HandleIncludeKeycodes, which may call
+ * HandleKeycodesFile again).
+ *
+ * @param file The input file (parsed xkb_keycodes section)
+ * @param xkb Necessary to pass down, may have flags changed.
+ * @param merge Merge strategy (MergeOverride, etc.)
+ * @param info Struct to contain the fully parsed key information.
+ */
+static void
+HandleKeycodesFile(XkbFile * file,
+ XkbDescPtr xkb, unsigned merge, KeyNamesInfo * info)
+{
+ ParseCommon *stmt;
+
+ info->name = uStringDup(file->name);
+ stmt = file->defs;
+ while (stmt)
+ {
+ switch (stmt->stmtType)
+ {
+ case StmtInclude: /* e.g. include "evdev+aliases(qwerty)" */
+ if (!HandleIncludeKeycodes((IncludeStmt *) stmt, xkb, info))
+ info->errorCount++;
+ break;
+ case StmtKeycodeDef: /* e.g. <ESC> = 9; */
+ if (!HandleKeycodeDef((KeycodeDef *) stmt, merge, info))
+ info->errorCount++;
+ break;
+ case StmtKeyAliasDef: /* e.g. alias <MENU> = <COMP>; */
+ if (!HandleAliasDef((KeyAliasDef *) stmt,
+ merge, info->fileID, &info->aliases))
+ info->errorCount++;
+ break;
+ case StmtVarDef: /* e.g. minimum, maximum */
+ if (!HandleKeyNameVar((VarDef *) stmt, info))
+ info->errorCount++;
+ break;
+ case StmtIndicatorNameDef: /* e.g. indicator 1 = "Caps Lock"; */
+ if (!HandleIndicatorNameDef((IndicatorNameDef *) stmt,
+ merge, info))
+ {
+ info->errorCount++;
+ }
+ break;
+ case StmtInterpDef:
+ case StmtVModDef:
+ ERROR("Keycode files may define key and indicator names only\n");
+ ACTION1("Ignoring definition of %s\n",
+ ((stmt->stmtType ==
+ StmtInterpDef) ? "a symbol interpretation" :
+ "virtual modifiers"));
+ info->errorCount++;
+ break;
+ default:
+ WSGO1("Unexpected statement type %d in HandleKeycodesFile\n",
+ stmt->stmtType);
+ break;
+ }
+ stmt = stmt->next;
+ if (info->errorCount > 10)
+ {
+#ifdef NOISY
+ ERROR("Too many errors\n");
+#endif
+ ACTION1("Abandoning keycodes file \"%s\"\n", file->topName);
+ break;
+ }
+ }
+ return;
+}
+
+/**
+ * Compile the xkb_keycodes section, parse it's output, return the results.
+ *
+ * @param file The parsed XKB file (may have include statements requiring
+ * further parsing)
+ * @param result The effective keycodes, as gathered from the file.
+ * @param merge Merge strategy.
+ *
+ * @return True on success, False otherwise.
+ */
+Bool
+CompileKeycodes(XkbFile * file, XkbFileInfo * result, unsigned merge)
+{
+ KeyNamesInfo info; /* contains all the info after parsing */
+ XkbDescPtr xkb;
+
+ xkb = result->xkb;
+ InitKeyNamesInfo(&info);
+ HandleKeycodesFile(file, xkb, merge, &info);
+
+ /* all the keys are now stored in info */
+
+ if (info.errorCount == 0)
+ {
+ if (info.explicitMin > 0) /* if "minimum" statement was present */
+ xkb->min_key_code = info.effectiveMin;
+ else
+ xkb->min_key_code = info.computedMin;
+ if (info.explicitMax > 0) /* if "maximum" statement was present */
+ xkb->max_key_code = info.effectiveMax;
+ else
+ xkb->max_key_code = info.computedMax;
+ if (XkbAllocNames(xkb, XkbKeyNamesMask | XkbIndicatorNamesMask, 0, 0)
+ == Success)
+ {
+ register int i;
+ xkb->names->keycodes = XkbInternAtom(xkb->dpy, info.name, False);
+ uDEBUG2(1, "key range: %d..%d\n", xkb->min_key_code,
+ xkb->max_key_code);
+ for (i = info.computedMin; i <= info.computedMax; i++)
+ {
+ LongToKeyName(info.names[i], xkb->names->keys[i].name);
+ uDEBUG2(2, "key %d = %s\n", i,
+ XkbKeyNameText(xkb->names->keys[i].name, XkbMessage));
+ }
+ }
+ else
+ {
+ WSGO("Cannot create XkbNamesRec in CompileKeycodes\n");
+ return False;
+ }
+ if (info.leds)
+ {
+ IndicatorNameInfo *ii;
+ if (XkbAllocIndicatorMaps(xkb) != Success)
+ {
+ WSGO("Couldn't allocate IndicatorRec in CompileKeycodes\n");
+ ACTION("Physical indicators not set\n");
+ }
+ for (ii = info.leds; ii != NULL;
+ ii = (IndicatorNameInfo *) ii->defs.next)
+ {
+ xkb->names->indicators[ii->ndx - 1] =
+ XkbInternAtom(xkb->dpy,
+ XkbAtomGetString(NULL, ii->name), False);
+ if (xkb->indicators != NULL)
+ {
+ register unsigned bit;
+ bit = 1 << (ii->ndx - 1);
+ if (ii->virtual)
+ xkb->indicators->phys_indicators &= ~bit;
+ else
+ xkb->indicators->phys_indicators |= bit;
+ }
+ }
+ }
+ if (info.aliases)
+ ApplyAliases(xkb, False, &info.aliases);
+ return True;
+ }
+ ClearKeyNamesInfo(&info);
+ return False;
+}
|