#include "expr.h"
#include "include.h"
-/*
- * The xkb_types section
- * =====================
- * This section is the second to be processesed, after xkb_keycodes.
- * However, it is completely independent and could have been the first
- * to be processed (it does not refer to specific keys as specified in
- * the xkb_keycodes section).
- *
- * This section defines key types, which, given a key and a keyboard
- * state (i.e. modifier state and group), determine the shift level to
- * be used in translating the key to keysyms. These types are assigned
- * to each group in each key, in the xkb_symbols section.
- *
- * Key types are called this way because, in a way, they really describe
- * the "type" of the key (or more correctly, a specific group of the
- * key). For example, an ordinary keymap will provide a type called
- * "KEYPAD", which consists of two levels, with the second level being
- * chosen according to the state of the Num Lock (or Shift) modifiers.
- * Another example is a type called "ONE_LEVEL", which is usually
- * assigned to keys such as Escape; these have just one level and are
- * not affected by the modifier state. Yet more common examples are
- * "TWO_LEVEL" (with Shift choosing the second level), "ALPHABETIC"
- * (where Caps Lock may also choose the second level), etc.
- *
- * Type definitions
- * ----------------
- * Statements of the form:
- * type "FOUR_LEVEL" { ... }
- *
- * The above would create a new type named "FOUR_LEVEL".
- * The body of the definition may include statements of the following
- * forms:
- *
- * - level_name statements (mandatory for each level in the type):
- * level_name[Level1] = "Base";
- *
- * Gives each level in this type a descriptive name. It isn't used
- * for any thing.
- * Note: A level may be specified as Level[1-8] or just a number (can
- * be more than 8).
- *
- * - modifiers statement (mandatory, should be specified only once):
- * modifiers = Shift+Lock+LevelThree;
- *
- * A mask of real and virtual modifiers. These are the only modifiers
- * being considered when matching the modifier state against the type.
- * The other modifiers, whether active or not, are masked out in the
- * calculation.
- *
- * - map entry statements (should have at least as many mappings as there
- * are levels in the type):
- * map[Shift+LevelThree] = Level4;
- *
- * If the active modifiers, masked with the type's modifiers (as stated
- * above), match (i.e. equal) the modifiers inside the map[] statement,
- * then the level in the right hand side is chosen. For example, in the
- * above, if in the current keyboard state the Shift and LevelThree
- * modifiers are active, while the Lock modifier is not, then the
- * keysym(s) in the 4th level of the group will be returned to the
- * user.
- *
- * - preserve statements:
- * map[Shift+Lock+LevelThree] = Level5;
- * preserve[Shift+Lock+LevelThree] = Lock;
- *
- * When a map entry matches the active modifiers and the level it
- * specified is chosen, then these modifiers are said to be "consumed";
- * for example, in a simple US keymap where the "g" key is assigned an
- * ordinary ALPHABETIC key type, if the Lock (Caps Lock) modifier is
- * active and the key is pressed, then a "G" keysym is produced (as
- * opposed to lower-case "g"). This is because the type definition has
- * a map entry like the following:
- * map[Lock] = Level2;
- * And as such the Lock modifier is consumed. This information is
- * relevant for applications which further process the modifiers,
- * since by then the consumed modifiers have already "done their part"
- * and should be masked out.
- *
- * However, sometimes even if a modifier is actually used to choose
- * the shift level (as Lock above), it should *not* be reported as
- * consumed, for various reasons. In this case, a preserve[] statement
- * can be used to augment the map entry. The modifiers inside the square
- * brackets should match one of the map[] statements in the type. The
- * right hand side should consists of modifiers from the left hand
- * side; these modifiers are then "preserved" and not reported as
- * consumed.
- *
- * 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_types sections have been compiled, the following
- * members of struct xkb_keymap are finalized:
- * struct xkb_key_type *types;
- * unsigned int num_types;
- * char *types_section_name;
- * TODO: virtual modifiers.
- */
-
enum type_field {
TYPE_FIELD_MASK = (1 << 0),
TYPE_FIELD_MAP = (1 << 1),
typedef struct {
enum type_field defined;
- unsigned file_id;
enum merge_mode merge;
xkb_atom_t name;
xkb_mod_mask_t mods;
xkb_level_index_t num_levels;
- darray(struct xkb_kt_map_entry) entries;
+ darray(struct xkb_key_type_entry) entries;
darray(xkb_atom_t) level_names;
} KeyTypeInfo;
typedef struct {
char *name;
int errorCount;
- unsigned file_id;
darray(KeyTypeInfo) types;
- VModInfo vmods;
struct xkb_keymap *keymap;
} KeyTypesInfo;
/***====================================================================***/
static inline const char *
-MapEntryTxt(KeyTypesInfo *info, struct xkb_kt_map_entry *entry)
+MapEntryTxt(KeyTypesInfo *info, struct xkb_key_type_entry *entry)
{
- return VModMaskText(info->keymap, entry->mods.mods);
+ return ModMaskText(info->keymap, entry->mods.mods);
}
static inline const char *
static inline const char *
TypeMaskTxt(KeyTypesInfo *info, KeyTypeInfo *type)
{
- return VModMaskText(info->keymap, type->mods);
+ return ModMaskText(info->keymap, type->mods);
}
static inline bool
ReportTypeShouldBeArray(KeyTypesInfo *info, KeyTypeInfo *type,
const char *field)
{
- return ReportShouldBeArray(info->keymap, "key type", field,
+ return ReportShouldBeArray(info->keymap->ctx, "key type", field,
TypeTxt(info, type));
}
TypeTxt(info, type), wanted);
}
-static inline bool
-ReportTypeBadWidth(KeyTypesInfo *info, const char *type, int has, int needs)
-{
- log_err(info->keymap->ctx,
- "Key type \"%s\" has %d levels, must have %d; "
- "Illegal type definition ignored\n",
- type, has, needs);
- return false;
-}
-
/***====================================================================***/
static void
-InitKeyTypesInfo(KeyTypesInfo *info, struct xkb_keymap *keymap,
- unsigned file_id)
+InitKeyTypesInfo(KeyTypesInfo *info, struct xkb_keymap *keymap)
{
memset(info, 0, sizeof(*info));
info->keymap = keymap;
- info->file_id = file_id;
- InitVModInfo(&info->vmods, keymap);
}
static void
}
static bool
-AddKeyType(KeyTypesInfo *info, KeyTypeInfo *new)
+AddKeyType(KeyTypesInfo *info, KeyTypeInfo *new, bool same_file)
{
KeyTypeInfo *old;
- int verbosity = xkb_context_get_log_verbosity(info->keymap->ctx);
+ const int verbosity = xkb_context_get_log_verbosity(info->keymap->ctx);
old = FindMatchingKeyType(info, new->name);
if (old) {
if (new->merge == MERGE_REPLACE || new->merge == MERGE_OVERRIDE) {
- if ((old->file_id == new->file_id && verbosity > 0) ||
- verbosity > 9) {
+ if ((same_file && verbosity > 0) || verbosity > 9) {
log_warn(info->keymap->ctx,
"Multiple definitions of the %s key type; "
"Earlier definition ignored\n",
return true;
}
- if (old->file_id == new->file_id)
+ if (same_file)
log_vrb(info->keymap->ctx, 4,
"Multiple definitions of the %s key type; "
"Later definition ignored\n",
return true;
}
- new->file_id = info->file_id;
darray_append(info->types, *new);
return true;
}
from->name = NULL;
}
- darray_foreach(type, from->types) {
- type->merge = (merge == MERGE_DEFAULT ? type->merge : merge);
- if (!AddKeyType(into, type))
- into->errorCount++;
+ if (darray_empty(into->types)) {
+ into->types = from->types;
+ darray_init(from->types);
+ }
+ else {
+ darray_foreach(type, from->types) {
+ type->merge = (merge == MERGE_DEFAULT ? type->merge : merge);
+ if (!AddKeyType(into, type, false))
+ into->errorCount++;
+ }
}
}
HandleKeyTypesFile(KeyTypesInfo *info, XkbFile *file, enum merge_mode merge);
static bool
-HandleIncludeKeyTypes(KeyTypesInfo *info, IncludeStmt *stmt)
+HandleIncludeKeyTypes(KeyTypesInfo *info, IncludeStmt *include)
{
- enum merge_mode merge = MERGE_DEFAULT;
- XkbFile *rtrn;
- KeyTypesInfo included, next_incl;
-
- InitKeyTypesInfo(&included, info->keymap, info->file_id);
- if (stmt->stmt) {
- free(included.name);
- included.name = stmt->stmt;
- stmt->stmt = NULL;
- }
+ KeyTypesInfo included;
+
+ InitKeyTypesInfo(&included, info->keymap);
+ included.name = include->stmt;
+ include->stmt = NULL;
- for (; stmt; stmt = stmt->next_incl) {
- if (!ProcessIncludeFile(info->keymap->ctx, stmt, FILE_TYPE_TYPES,
- &rtrn, &merge)) {
+ for (IncludeStmt *stmt = include; stmt; stmt = stmt->next_incl) {
+ KeyTypesInfo next_incl;
+ XkbFile *file;
+
+ file = ProcessIncludeFile(info->keymap->ctx, stmt, FILE_TYPE_TYPES);
+ if (!file) {
info->errorCount += 10;
ClearKeyTypesInfo(&included);
return false;
}
- InitKeyTypesInfo(&next_incl, info->keymap, rtrn->id);
+ InitKeyTypesInfo(&next_incl, info->keymap);
- HandleKeyTypesFile(&next_incl, rtrn, merge);
+ HandleKeyTypesFile(&next_incl, file, stmt->merge);
- MergeIncludedKeyTypes(&included, &next_incl, merge);
+ MergeIncludedKeyTypes(&included, &next_incl, stmt->merge);
ClearKeyTypesInfo(&next_incl);
- FreeXkbFile(rtrn);
+ FreeXkbFile(file);
}
- MergeIncludedKeyTypes(info, &included, merge);
+ MergeIncludedKeyTypes(info, &included, include->merge);
ClearKeyTypesInfo(&included);
return (info->errorCount == 0);
"The modifiers field of a key type is not an array; "
"Illegal array subscript ignored\n");
- /* get modifier mask for current type */
- if (!ExprResolveVModMask(info->keymap, value, &mods)) {
+ if (!ExprResolveModMask(info->keymap, value, MOD_BOTH, &mods)) {
log_err(info->keymap->ctx,
"Key type mask field must be a modifier mask; "
"Key type definition ignored\n");
"Using %s, ignoring %s\n",
xkb_atom_text(info->keymap->ctx, type->name),
TypeMaskTxt(info, type),
- VModMaskText(info->keymap, mods));
+ ModMaskText(info->keymap, mods));
return false;
}
/***====================================================================***/
-static struct xkb_kt_map_entry *
+static struct xkb_key_type_entry *
FindMatchingMapEntry(KeyTypeInfo *type, xkb_mod_mask_t mods)
{
- struct xkb_kt_map_entry *entry;
+ struct xkb_key_type_entry *entry;
darray_foreach(entry, type->entries)
if (entry->mods.mods == mods)
static bool
AddMapEntry(KeyTypesInfo *info, KeyTypeInfo *type,
- struct xkb_kt_map_entry *new, bool clobber, bool report)
+ struct xkb_key_type_entry *new, bool clobber, bool report)
{
- struct xkb_kt_map_entry * old;
+ struct xkb_key_type_entry *old;
old = FindMatchingMapEntry(type, new->mods.mods);
if (old) {
}
else {
log_vrb(info->keymap->ctx, 10,
- "Multiple occurences of map[%s]= %d in %s; Ignored\n",
+ "Multiple occurrences of map[%s]= %d in %s; Ignored\n",
MapEntryTxt(info, new), new->level + 1,
TypeTxt(info, type));
return true;
SetMapEntry(KeyTypesInfo *info, KeyTypeInfo *type, ExprDef *arrayNdx,
ExprDef *value)
{
- struct xkb_kt_map_entry entry;
+ struct xkb_key_type_entry entry;
if (arrayNdx == NULL)
return ReportTypeShouldBeArray(info, type, "map entry");
- if (!ExprResolveVModMask(info->keymap, arrayNdx, &entry.mods.mods))
+ if (!ExprResolveModMask(info->keymap, arrayNdx, MOD_BOTH, &entry.mods.mods))
return ReportTypeBadType(info, type, "map entry", "modifier mask");
if (entry.mods.mods & (~type->mods)) {
"Map entry for unused modifiers in %s; "
"Using %s instead of %s\n",
TypeTxt(info, type),
- VModMaskText(info->keymap, entry.mods.mods & type->mods),
+ ModMaskText(info->keymap, entry.mods.mods & type->mods),
MapEntryTxt(info, &entry));
entry.mods.mods &= type->mods;
}
AddPreserve(KeyTypesInfo *info, KeyTypeInfo *type,
xkb_mod_mask_t mods, xkb_mod_mask_t preserve_mods)
{
- struct xkb_kt_map_entry *entry;
- struct xkb_kt_map_entry new;
+ struct xkb_key_type_entry *entry;
+ struct xkb_key_type_entry new;
darray_foreach(entry, type->entries) {
if (entry->mods.mods != mods)
log_vrb(info->keymap->ctx, 10,
"Identical definitions for preserve[%s] in %s; "
"Ignored\n",
- VModMaskText(info->keymap, mods),
+ ModMaskText(info->keymap, mods),
TypeTxt(info, type));
return true;
}
log_vrb(info->keymap->ctx, 1,
"Multiple definitions for preserve[%s] in %s; "
"Using %s, ignoring %s\n",
- VModMaskText(info->keymap, mods),
+ ModMaskText(info->keymap, mods),
TypeTxt(info, type),
- VModMaskText(info->keymap, preserve_mods),
- VModMaskText(info->keymap, entry->preserve.mods));
+ ModMaskText(info->keymap, preserve_mods),
+ ModMaskText(info->keymap, entry->preserve.mods));
entry->preserve.mods = preserve_mods;
return true;
/*
* Map does not exist, i.e. preserve[] came before map[].
* Create a map with the specified mask mapping to Level1. The level
- * may be overriden later with an explicit map[] statement.
+ * may be overridden later with an explicit map[] statement.
*/
new.level = 0;
new.mods.mods = mods;
if (arrayNdx == NULL)
return ReportTypeShouldBeArray(info, type, "preserve entry");
- if (!ExprResolveVModMask(info->keymap, arrayNdx, &mods))
+ if (!ExprResolveModMask(info->keymap, arrayNdx, MOD_BOTH, &mods))
return ReportTypeBadType(info, type, "preserve entry",
"modifier mask");
if (mods & ~type->mods) {
const char *before, *after;
- before = VModMaskText(info->keymap, mods);
+ before = ModMaskText(info->keymap, mods);
mods &= type->mods;
- after = VModMaskText(info->keymap, mods);
+ after = ModMaskText(info->keymap, mods);
log_vrb(info->keymap->ctx, 1,
"Preserve for modifiers not used by the %s type; "
TypeTxt(info, type), before, after);
}
- if (!ExprResolveVModMask(info->keymap, value, &preserve_mods)) {
+ if (!ExprResolveModMask(info->keymap, value, MOD_BOTH, &preserve_mods)) {
log_err(info->keymap->ctx,
"Preserve value in a key type is not a modifier mask; "
"Ignoring preserve[%s] in type %s\n",
- VModMaskText(info->keymap, mods),
+ ModMaskText(info->keymap, mods),
TypeTxt(info, type));
return false;
}
if (preserve_mods & ~mods) {
const char *before, *after;
- before = VModMaskText(info->keymap, preserve_mods);
+ before = ModMaskText(info->keymap, preserve_mods);
preserve_mods &= mods;
- after = VModMaskText(info->keymap, preserve_mods);
+ after = ModMaskText(info->keymap, preserve_mods);
log_vrb(info->keymap->ctx, 1,
"Illegal value for preserve[%s] in type %s; "
"Converted %s to %s\n",
- VModMaskText(info->keymap, mods),
+ ModMaskText(info->keymap, mods),
TypeTxt(info, type), before, after);
}
{
KeyTypeInfo type = {
.defined = 0,
- .file_id = info->file_id,
.merge = (def->merge == MERGE_DEFAULT ? merge : def->merge),
.name = def->name,
.mods = 0,
return false;
}
- if (!AddKeyType(info, &type)) {
+ if (!AddKeyType(info, &type, true)) {
info->errorCount++;
return false;
}
HandleKeyTypesFile(KeyTypesInfo *info, XkbFile *file, enum merge_mode merge)
{
bool ok;
- ParseCommon *stmt;
free(info->name);
info->name = strdup_safe(file->name);
- for (stmt = file->defs; stmt; stmt = stmt->next) {
+ for (ParseCommon *stmt = file->defs; stmt; stmt = stmt->next) {
switch (stmt->type) {
case STMT_INCLUDE:
ok = HandleIncludeKeyTypes(info, (IncludeStmt *) stmt);
break;
- case STMT_TYPE: /* e.g. type "ONE_LEVEL" */
+ case STMT_TYPE:
ok = HandleKeyTypeDef(info, (KeyTypeDef *) stmt, merge);
break;
case STMT_VAR:
"Statement ignored\n");
ok = true;
break;
- case STMT_VMOD: /* virtual_modifiers NumLock, ... */
- ok = HandleVModDef((VModDef *) stmt, info->keymap, &info->vmods);
+ case STMT_VMOD:
+ ok = HandleVModDef(info->keymap, (VModDef *) stmt, merge);
break;
default:
log_err(info->keymap->ctx,
}
}
-static void
-CopyDefToKeyType(KeyTypeInfo *def, struct xkb_key_type *type)
-{
- type->mods.mods = def->mods;
- type->num_levels = def->num_levels;
- type->map = darray_mem(def->entries, 0);
- type->num_entries = darray_size(def->entries);
- darray_init(def->entries);
- type->name = def->name;
- type->level_names = darray_mem(def->level_names, 0);
- darray_init(def->level_names);
-}
+/***====================================================================***/
static bool
CopyKeyTypesToKeymap(struct xkb_keymap *keymap, KeyTypesInfo *info)
{
- unsigned int i;
- unsigned int num_types;
+ keymap->types_section_name = strdup_safe(info->name);
+ XkbEscapeMapName(keymap->types_section_name);
- num_types = darray_size(info->types) ? darray_size(info->types) : 1;
- keymap->types = calloc(num_types, sizeof(*keymap->types));
- if (!keymap->types)
- return false;
+ keymap->num_types = darray_size(info->types);
+ if (keymap->num_types == 0)
+ keymap->num_types = 1;
- keymap->num_types = num_types;
+ keymap->types = calloc(keymap->num_types, sizeof(*keymap->types));
/*
* If no types were specified, a default unnamed one-level type is
* used for all keys.
*/
if (darray_empty(info->types)) {
- KeyTypeInfo dflt = {
- .name = xkb_atom_intern(keymap->ctx, "default"),
- .mods = 0,
- .num_levels = 1,
- .entries = darray_new(),
- .level_names = darray_new(),
- };
-
- CopyDefToKeyType(&dflt, &keymap->types[0]);
- } else {
- for (i = 0; i < num_types; i++)
- CopyDefToKeyType(&darray_item(info->types, i), &keymap->types[i]);
+ struct xkb_key_type *type = &keymap->types[0];
+
+ type->mods.mods = 0;
+ type->num_levels = 1;
+ type->entries = NULL;
+ type->num_entries = 0;
+ type->name = xkb_atom_intern_literal(keymap->ctx, "default");
+ type->level_names = NULL;
+
+ return true;
}
- keymap->types_section_name = strdup_safe(info->name);
+ for (unsigned i = 0; i < keymap->num_types; i++) {
+ KeyTypeInfo *def = &darray_item(info->types, i);
+ struct xkb_key_type *type = &keymap->types[i];
+
+ type->mods.mods = def->mods;
+ type->num_levels = def->num_levels;
+ type->entries = darray_mem(def->entries, 0);
+ type->num_entries = darray_size(def->entries);
+ darray_init(def->entries);
+ type->name = def->name;
+ type->level_names = darray_mem(def->level_names, 0);
+ darray_init(def->level_names);
+ }
return true;
}
+/***====================================================================***/
+
bool
CompileKeyTypes(XkbFile *file, struct xkb_keymap *keymap,
enum merge_mode merge)
{
KeyTypesInfo info;
- InitKeyTypesInfo(&info, keymap, file->id);
+ InitKeyTypesInfo(&info, keymap);
HandleKeyTypesFile(&info, file, merge);
if (info.errorCount != 0)