types: don't use canonical/required types

Xkb required every keymap to have at least the four following canonical
types: ONE_LEVEL, TWO_LEVEL, ALPHABETIC, KEYPAD. This is specified in
e.g. the kbproto spec and XkbKeyTypesForCoreSymbols(3) man page.

If these types are not specified in the keymap, the code specifically
checks for them and adds them to the 4 first places in the types array,
such that they exist in every keymap. These are also the types (along
with some non-required 4-level ones) that are automatically assigned to
keys which do not explicitly declare a type (see FindAutomaticType in
symbols.c, this commit doesn't touch these heuristics, whcih are also not
very nice but necessary).

The xkeyboard-config does not rely on the builtin xkbcomp definitions of
these types and does specify them explicitly, in types/basic and
types/numpad, which are virtually always included.

This commit removes the special behavior:
- The code is ugly and makes keytypes.c harder to read.
- The code practically never gets run - everyone who uses
  xkeyboard-config or a keymap based upon it (i.e. everyone) doesn't need
  it. So it doesn't get tested.
- It mixes policy with implementation for not very good reasons, it
  seems mostly for default compatibility with X11 core.
- And of course we don't need to remain compatible with Xkb ABI neither.

Instead, if we read a keymap with no types specified at all, we simply
assign all keys a default one-level type (like ONE_LEVEL), and issue
plenty of warnings to make it clear (with verbosity >= 3). Note that
this default can actually be changed from within the keymap, by writing
something like
    type.modifier = Shift
    type.whatever_field = value
in the top level of the xkb_types section. (This functionality is
completely unused as well today, BTW, but makes some sense).

This change means that if someone writes a keymap from scratch and
doesn't add say ALPHABETIC, then something like <AE11> = { [ q Q ]; }; will
ignore the second level. But as stated above this should never happen.

Signed-off-by: Ran Benita <ran234@gmail.com>
master
Ran Benita 2012-08-02 00:29:07 +03:00
parent be82f08221
commit b0b11c4e2e
7 changed files with 1059 additions and 286 deletions

View File

@ -159,17 +159,11 @@ typedef struct _KeyTypesInfo {
char *name;
int errorCount;
unsigned file_id;
unsigned stdPresent;
unsigned nTypes;
struct list types;
KeyTypeInfo dflt;
VModInfo vmods;
struct xkb_keymap *keymap;
xkb_atom_t tok_ONE_LEVEL;
xkb_atom_t tok_TWO_LEVEL;
xkb_atom_t tok_ALPHABETIC;
xkb_atom_t tok_KEYPAD;
} KeyTypesInfo;
/***====================================================================***/
@ -239,20 +233,15 @@ InitKeyTypesInfo(KeyTypesInfo *info, struct xkb_keymap *keymap,
{
PreserveInfo *old, *new;
info->tok_ONE_LEVEL = xkb_atom_intern(keymap->ctx, "ONE_LEVEL");
info->tok_TWO_LEVEL = xkb_atom_intern(keymap->ctx, "TWO_LEVEL");
info->tok_ALPHABETIC = xkb_atom_intern(keymap->ctx, "ALPHABETIC");
info->tok_KEYPAD = xkb_atom_intern(keymap->ctx, "KEYPAD");
info->name = strdup("default");
info->errorCount = 0;
info->stdPresent = 0;
info->nTypes = 0;
list_init(&info->types);
info->file_id = file_id;
info->dflt.defined = 0;
info->dflt.file_id = file_id;
info->dflt.merge = MERGE_OVERRIDE;
info->dflt.name = XKB_ATOM_NONE;
info->dflt.name = xkb_atom_intern(keymap->ctx, "DEFAULT");
info->dflt.mask = 0;
info->dflt.vmask = 0;
info->dflt.numLevels = 1;
@ -341,33 +330,6 @@ AddKeyType(KeyTypesInfo *info, KeyTypeInfo *new)
struct list type_entry, preserves_entry;
int verbosity = xkb_get_log_verbosity(info->keymap->ctx);
if (new->name == info->tok_ONE_LEVEL) {
if (new->numLevels > 1)
return ReportTypeBadWidth(info, "ONE_LEVEL", new->numLevels, 1);
info->stdPresent |= XkbOneLevelMask;
}
else if (new->name == info->tok_TWO_LEVEL) {
if (new->numLevels > 2)
return ReportTypeBadWidth(info, "TWO_LEVEL", new->numLevels, 2);
else if (new->numLevels < 2)
new->numLevels = 2;
info->stdPresent |= XkbTwoLevelMask;
}
else if (new->name == info->tok_ALPHABETIC) {
if (new->numLevels > 2)
return ReportTypeBadWidth(info, "ALPHABETIC", new->numLevels, 2);
else if (new->numLevels < 2)
new->numLevels = 2;
info->stdPresent |= XkbAlphabeticMask;
}
else if (new->name == info->tok_KEYPAD) {
if (new->numLevels > 2)
return ReportTypeBadWidth(info, "KEYPAD", new->numLevels, 2);
else if (new->numLevels < 2)
new->numLevels = 2;
info->stdPresent |= XkbKeypadMask;
}
old = FindMatchingKeyType(info, new);
if (old) {
if (new->merge == MERGE_REPLACE || new->merge == MERGE_OVERRIDE) {
@ -437,8 +399,6 @@ MergeIncludedKeyTypes(KeyTypesInfo *into, KeyTypesInfo *from,
if (!AddKeyType(into, type))
into->errorCount++;
}
into->stdPresent |= from->stdPresent;
}
static void
@ -1104,176 +1064,12 @@ CopyDefToKeyType(KeyTypesInfo *info, KeyTypeInfo *def,
return ComputeEffectiveMap(keymap, type);
}
static struct xkb_kt_map_entry map2Level[] = {
{
.level = ShiftMask,
.mods = { .mask = 1, .vmods = ShiftMask, .real_mods = 0 }
}
};
static struct xkb_kt_map_entry mapAlpha[] = {
{
.level = ShiftMask,
.mods = { .mask = 1, .vmods = ShiftMask, .real_mods = 0 }
},
{
.level = LockMask,
.mods = { .mask = 0, .vmods = LockMask, .real_mods = 0 }
}
};
static struct xkb_mods preAlpha[] = {
{ .mask = 0, .vmods = 0, .real_mods = 0 },
{ .mask = LockMask, .vmods = LockMask, .real_mods = 0 }
};
static struct xkb_kt_map_entry mapKeypad[] = {
{
.level = ShiftMask,
.mods = { .mask = 1, .vmods = ShiftMask, .real_mods = 0 }
},
{
.level = 0,
.mods = { .mask = 1, .vmods = 0, .real_mods = 0 }
}
};
static const struct xkb_key_type canonicalTypes[XkbNumRequiredTypes] = {
[XkbOneLevelIndex] = {
.mods = { .mask = 0, .vmods = 0, .real_mods = 0 },
.num_levels = 1,
.preserve = NULL,
.name = NULL,
.level_names = NULL
},
[XkbTwoLevelIndex] = {
.mods = { .mask = ShiftMask, .vmods = ShiftMask, .real_mods = 0 },
.num_levels = 2,
.map = darray_lit(map2Level),
.preserve = NULL,
.name = NULL,
.level_names = NULL
},
[XkbAlphabeticIndex] = {
.mods = {
.mask = ShiftMask | LockMask,
.vmods = ShiftMask | LockMask,
.real_mods = 0
},
.num_levels = 2,
.map = darray_lit(mapAlpha),
.preserve = preAlpha,
.name = NULL,
.level_names = NULL
},
[XkbKeypadIndex] = {
.mods = { .mask = ShiftMask, .vmods = ShiftMask, .real_mods = 0 },
.num_levels = 2,
.map = darray_lit(mapKeypad),
.preserve = NULL,
.name = NULL,
.level_names = NULL
}
};
static int
CopyKeyType(const struct xkb_key_type *from, struct xkb_key_type *into)
{
int i;
darray_free(into->map);
free(into->preserve);
free(into->level_names);
*into = *from;
darray_init(into->map);
darray_copy(into->map, from->map);
if (from->preserve && !darray_empty(into->map)) {
into->preserve = calloc(darray_size(into->map),
sizeof(*into->preserve));
if (!into->preserve)
return BadAlloc;
memcpy(into->preserve, from->preserve,
darray_size(into->map) * sizeof(*into->preserve));
}
if (from->level_names && into->num_levels > 0) {
into->level_names = calloc(into->num_levels,
sizeof(*into->level_names));
if (!into->level_names)
return BadAlloc;
for (i = 0; i < into->num_levels; i++)
into->level_names[i] = strdup(from->level_names[i]);
}
return Success;
}
static int
InitCanonicalKeyTypes(struct xkb_keymap *keymap, unsigned which,
int keypadVMod)
{
const struct xkb_key_type *from;
int rtrn;
darray_growalloc(keymap->types, XkbNumRequiredTypes);
if ((which & XkbAllRequiredTypes) == 0)
return Success;
rtrn = Success;
from = canonicalTypes;
if (which & XkbOneLevelMask)
rtrn = CopyKeyType(&from[XkbOneLevelIndex],
&darray_item(keymap->types, XkbOneLevelIndex));
if ((which & XkbTwoLevelMask) && rtrn == Success)
rtrn = CopyKeyType(&from[XkbTwoLevelIndex],
&darray_item(keymap->types, XkbTwoLevelIndex));
if ((which & XkbAlphabeticMask) && rtrn == Success)
rtrn = CopyKeyType(&from[XkbAlphabeticIndex],
&darray_item(keymap->types, XkbAlphabeticIndex));
if ((which & XkbKeypadMask) && rtrn == Success) {
struct xkb_key_type *type;
rtrn = CopyKeyType(&from[XkbKeypadIndex],
&darray_item(keymap->types, XkbKeypadIndex));
type = &darray_item(keymap->types, XkbKeypadIndex);
if (keypadVMod >= 0 && keypadVMod < XkbNumVirtualMods &&
rtrn == Success) {
struct xkb_kt_map_entry *entry;
type->mods.vmods = (1 << keypadVMod);
entry = &darray_item(type->map, 0);
entry->mods.mask = ShiftMask;
entry->mods.real_mods = ShiftMask;
entry->mods.vmods = 0;
entry->level = 1;
entry = &darray_item(type->map, 1);
entry->mods.mask = 0;
entry->mods.real_mods = 0;
entry->mods.vmods = (1 << keypadVMod);
entry->level = 1;
}
}
return Success;
}
bool
CompileKeyTypes(XkbFile *file, struct xkb_keymap *keymap,
enum merge_mode merge)
{
unsigned int i;
struct xkb_key_type *type, *next;
struct xkb_key_type *type;
KeyTypesInfo info;
KeyTypeInfo *def;
@ -1287,56 +1083,11 @@ CompileKeyTypes(XkbFile *file, struct xkb_keymap *keymap,
if (info.name)
keymap->types_section_name = strdup(info.name);
i = info.nTypes;
if ((info.stdPresent & XkbOneLevelMask) == 0)
i++;
if ((info.stdPresent & XkbTwoLevelMask) == 0)
i++;
if ((info.stdPresent & XkbKeypadMask) == 0)
i++;
if ((info.stdPresent & XkbAlphabeticMask) == 0)
i++;
darray_resize0(keymap->types, info.nTypes ? info.nTypes : 1);
darray_resize0(keymap->types, i);
if (XkbAllRequiredTypes & (~info.stdPresent)) {
unsigned missing, keypadVMod;
missing = XkbAllRequiredTypes & (~info.stdPresent);
keypadVMod = FindKeypadVMod(keymap);
if (InitCanonicalKeyTypes(keymap, missing, keypadVMod) != Success) {
log_wsgo(info.keymap->ctx,
"Couldn't initialize canonical key types\n");
goto err_info;
}
if (missing & XkbOneLevelMask)
darray_item(keymap->types, XkbOneLevelIndex).name =
xkb_atom_text(keymap->ctx, info.tok_ONE_LEVEL);
if (missing & XkbTwoLevelMask)
darray_item(keymap->types, XkbTwoLevelIndex).name =
xkb_atom_text(keymap->ctx, info.tok_TWO_LEVEL);
if (missing & XkbAlphabeticMask)
darray_item(keymap->types, XkbAlphabeticIndex).name =
xkb_atom_text(keymap->ctx, info.tok_ALPHABETIC);
if (missing & XkbKeypadMask)
darray_item(keymap->types, XkbKeypadIndex).name =
xkb_atom_text(keymap->ctx, info.tok_KEYPAD);
}
next = &darray_item(keymap->types, XkbLastRequiredType + 1);
i = 0;
list_foreach(def, &info.types, entry) {
if (def->name == info.tok_ONE_LEVEL)
type = &darray_item(keymap->types, XkbOneLevelIndex);
else if (def->name == info.tok_TWO_LEVEL)
type = &darray_item(keymap->types, XkbTwoLevelIndex);
else if (def->name == info.tok_ALPHABETIC)
type = &darray_item(keymap->types, XkbAlphabeticIndex);
else if (def->name == info.tok_KEYPAD)
type = &darray_item(keymap->types, XkbKeypadIndex);
else
type = next++;
type = &darray_item(keymap->types, i++);
DeleteLevel1MapEntries(def);
@ -1344,6 +1095,15 @@ CompileKeyTypes(XkbFile *file, struct xkb_keymap *keymap,
goto err_info;
}
/*
* If no types were specified, the default unnamed one-level type is
* used for all keys.
*/
if (i == 0) {
if (!CopyDefToKeyType(&info, &info.dflt, &darray_item(keymap->types, 0)))
goto err_info;
}
FreeKeyTypesInfo(&info);
return true;

View File

@ -1488,15 +1488,14 @@ FindNamedType(struct xkb_keymap *keymap, xkb_atom_t atom, unsigned *type_rtrn)
const char *name = xkb_atom_text(keymap->ctx, atom);
struct xkb_key_type *type;
if (keymap) {
darray_foreach(type, keymap->types) {
if (streq(type->name, name)) {
*type_rtrn = n;
return true;
}
n++;
darray_foreach(type, keymap->types) {
if (streq(type->name, name)) {
*type_rtrn = n;
return true;
}
n++;
}
return false;
}
@ -1743,10 +1742,14 @@ CopySymbolsDef(SymbolsInfo *info, KeyInfo *keyi,
else {
log_lvl(info->keymap->ctx, 3,
"Type \"%s\" is not defined; "
"Using TWO_LEVEL for the %s key (keycode %d)\n",
"Using default type for the %s key (keycode %d)\n",
xkb_atom_text(keymap->ctx, keyi->types[i]),
LongKeyNameText(keyi->name), kc);
types[i] = XkbTwoLevelIndex;
/*
* Index 0 is guaranteed to contain something, usually
* ONE_LEVEL or at least some default one-level type.
*/
types[i] = 0;
}
/* if the type specifies fewer levels than the key has, shrink the key */

View File

@ -205,19 +205,6 @@ LookupVModMask(struct xkb_context *ctx, const void *priv, xkb_atom_t field,
return false;
}
xkb_mod_index_t
FindKeypadVMod(struct xkb_keymap *keymap)
{
xkb_atom_t name;
xkb_mod_index_t ndx;
name = xkb_atom_intern(keymap->ctx, "NumLock");
if (LookupVModIndex(keymap, name, EXPR_TYPE_INT, &ndx))
return ndx;
return -1;
}
bool
ResolveVirtualModifier(ExprDef *def, struct xkb_keymap *keymap,
xkb_mod_index_t *ndx_rtrn, VModInfo *info)

View File

@ -45,9 +45,6 @@ extern bool
HandleVModDef(VModDef *stmt, struct xkb_keymap *keymap,
enum merge_mode mergeMode, VModInfo *info);
xkb_mod_index_t
FindKeypadVMod(struct xkb_keymap *keymap);
bool
ResolveVirtualModifier(ExprDef *def, struct xkb_keymap *keymap,
xkb_mod_index_t *ndx_rtrn, VModInfo *info);

View File

@ -316,13 +316,6 @@ xkb_keymap {
level_name[Level1]= "Base";
level_name[Level2]= "Caps";
};
type "KEYPAD" {
modifiers= Shift+NumLock;
map[Shift]= Level2;
map[NumLock]= Level2;
level_name[Level1]= "Base";
level_name[Level2]= "Number";
};
type "SHIFT+ALT" {
modifiers= Shift+Alt;
map[Shift+Alt]= Level2;
@ -577,6 +570,13 @@ xkb_keymap {
level_name[Level4]= "Shift Alt";
level_name[Level5]= "Lock";
};
type "KEYPAD" {
modifiers= Shift+NumLock;
map[Shift]= Level2;
map[NumLock]= Level2;
level_name[Level1]= "Base";
level_name[Level2]= "Number";
};
type "FOUR_LEVEL_KEYPAD" {
modifiers= Shift+NumLock+LevelThree;
map[Shift]= Level2;

File diff suppressed because it is too large Load Diff

View File

@ -54,6 +54,7 @@ main(void)
/* XXX check we actually get qwertz here ... */
assert(test_file(ctx, "keymaps/default.xkb"));
assert(test_file(ctx, "keymaps/comprehensive-plus-geom.xkb"));
assert(test_file(ctx, "keymaps/no-types.xkb"));
assert(!test_file(ctx, "keymaps/divide-by-zero.xkb"));
assert(!test_file(ctx, "keymaps/bad.xkb"));