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
parent
be82f08221
commit
b0b11c4e2e
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
@ -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"));
|
||||
|
|
Loading…
Reference in New Issue