Update modifiers after building keymap
The server used to have to go and do this on our own, but we can do better than that: after we've compiled the keymap, go through and bind virtual modifiers to everything that needs it. Signed-off-by: Daniel Stone <daniel@fooishbar.org>master
parent
62444a117c
commit
0e0b5b00af
|
@ -849,3 +849,257 @@ CompileCompatMap(XkbFile *file, struct xkb_desc * xkb, unsigned merge,
|
|||
free(info.interps);
|
||||
return False;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
VModsToReal(struct xkb_desc *xkb, uint32_t vmodmask)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
int i;
|
||||
|
||||
if (!vmodmask)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < XkbNumVirtualMods; i++) {
|
||||
if (!(vmodmask & (1 << i)))
|
||||
continue;
|
||||
ret |= xkb->server->vmods[i];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
UpdateActionMods(struct xkb_desc *xkb, union xkb_action *act, uint32_t rmodmask)
|
||||
{
|
||||
uint32_t vmodmask; /* actually real mods, inferred from vmods */
|
||||
|
||||
switch (act->type) {
|
||||
case XkbSA_SetMods:
|
||||
case XkbSA_LatchMods:
|
||||
case XkbSA_LockMods:
|
||||
if (act->mods.flags & XkbSA_UseModMapMods) {
|
||||
act->mods.real_mods = rmodmask;
|
||||
act->mods.mask = act->mods.real_mods;
|
||||
}
|
||||
vmodmask = VModsToReal(xkb, act->mods.vmods);
|
||||
act->mods.mask |= vmodmask;
|
||||
break;
|
||||
case XkbSA_ISOLock:
|
||||
if (act->iso.flags & XkbSA_UseModMapMods) {
|
||||
act->iso.real_mods = rmodmask;
|
||||
act->iso.mask = act->iso.real_mods;
|
||||
}
|
||||
vmodmask = VModsToReal(xkb, act->iso.vmods);
|
||||
act->iso.mask |= vmodmask;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an interpretation which applies to this particular level, either by
|
||||
* finding an exact match for the symbol and modifier combination, or a
|
||||
* generic NoSymbol match.
|
||||
*/
|
||||
static struct xkb_sym_interpret *
|
||||
FindInterpForKey(struct xkb_desc *xkb, xkb_keycode_t key, uint32_t group, uint32_t level)
|
||||
{
|
||||
struct xkb_sym_interpret *ret = NULL;
|
||||
xkb_keysym_t *syms;
|
||||
int num_syms;
|
||||
int i;
|
||||
|
||||
num_syms = xkb_key_get_syms_by_level(xkb, key, group, level, &syms);
|
||||
if (num_syms == 0)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < xkb->compat->num_si; i++) {
|
||||
struct xkb_sym_interpret *interp = &xkb->compat->sym_interpret[i];
|
||||
uint32_t mods;
|
||||
Bool found;
|
||||
|
||||
if ((num_syms != 1 || interp->sym != syms[0]) &&
|
||||
interp->sym != NoSymbol)
|
||||
continue;
|
||||
|
||||
if (level == 0 || !(interp->match & XkbSI_LevelOneOnly))
|
||||
mods = xkb->map->modmap[key];
|
||||
else
|
||||
mods = 0;
|
||||
|
||||
switch (interp->match & XkbSI_OpMask) {
|
||||
case XkbSI_NoneOf:
|
||||
found = !(interp->mods & mods);
|
||||
break;
|
||||
case XkbSI_AnyOfOrNone:
|
||||
found = (!mods || (interp->mods & mods));
|
||||
break;
|
||||
case XkbSI_AnyOf:
|
||||
found = !!(interp->mods & mods);
|
||||
break;
|
||||
case XkbSI_AllOf:
|
||||
found = ((interp->mods & mods) == mods);
|
||||
break;
|
||||
case XkbSI_Exactly:
|
||||
found = (interp->mods == mods);
|
||||
break;
|
||||
default:
|
||||
found = False;
|
||||
break;
|
||||
}
|
||||
|
||||
if (found && interp->sym != NoSymbol)
|
||||
return interp;
|
||||
else if (found && !ret)
|
||||
ret = interp;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static Bool
|
||||
ApplyInterpsToKey(struct xkb_desc *xkb, xkb_keycode_t key)
|
||||
{
|
||||
#define INTERP_SIZE (8 * 4)
|
||||
struct xkb_sym_interpret *interps[INTERP_SIZE];
|
||||
union xkb_action *acts;
|
||||
uint32_t vmodmask = 0;
|
||||
int num_acts = 0;
|
||||
int group, level;
|
||||
int width = XkbKeyGroupsWidth(xkb, key);
|
||||
int i;
|
||||
|
||||
/* If we've been told not to bind interps to this key, then don't. */
|
||||
if (xkb->server->explicit[key] & XkbExplicitInterpretMask)
|
||||
return True;
|
||||
|
||||
for (i = 0; i < INTERP_SIZE; i++)
|
||||
interps[i] = NULL;
|
||||
|
||||
for (group = 0; group < XkbKeyNumGroups(xkb, key); group++) {
|
||||
for (level = 0; level < XkbKeyGroupWidth(xkb, key, group); level++) {
|
||||
i = (group * width) + level;
|
||||
if (i >= INTERP_SIZE) /* XXX FIXME */
|
||||
return False;
|
||||
interps[i] = FindInterpForKey(xkb, key, group, level);
|
||||
if (interps[i])
|
||||
num_acts++;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_acts)
|
||||
num_acts = XkbKeyNumGroups(xkb, key) * width;
|
||||
acts = XkbcResizeKeyActions(xkb, key, num_acts);
|
||||
if (!num_acts)
|
||||
return True;
|
||||
else if (!acts)
|
||||
return False;
|
||||
|
||||
for (group = 0; group < XkbKeyNumGroups(xkb, key); group++) {
|
||||
for (level = 0; level < XkbKeyGroupWidth(xkb, key, group); level++) {
|
||||
struct xkb_sym_interpret *interp;
|
||||
|
||||
i = (group * width) + level;
|
||||
interp = interps[i];
|
||||
|
||||
/* Infer default key behaviours from the base level. */
|
||||
if (group == 0 && level == 0) {
|
||||
if (!(xkb->server->explicit[key] & XkbExplicitAutoRepeatMask) &&
|
||||
(!interp || interp->flags & XkbSI_AutoRepeat))
|
||||
xkb->ctrls->per_key_repeat[key / 8] |= (1 << (key % 8));
|
||||
if (!(xkb->server->explicit[key] & XkbExplicitBehaviorMask) &&
|
||||
interp && (interp->flags & XkbSI_LockingKey))
|
||||
xkb->server->behaviors[key].type = XkbKB_Lock;
|
||||
}
|
||||
|
||||
if (!interp)
|
||||
continue;
|
||||
|
||||
if ((group == 0 && level == 0) ||
|
||||
!(interp->match & XkbSI_LevelOneOnly)) {
|
||||
if (interp->virtual_mod != XkbNoModifier)
|
||||
vmodmask |= (1 << interp->virtual_mod);
|
||||
}
|
||||
acts[i] = interp->act;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(xkb->server->explicit[key] & XkbExplicitVModMapMask))
|
||||
xkb->server->vmodmap[key] = vmodmask;
|
||||
|
||||
return True;
|
||||
#undef INTERP_SIZE
|
||||
}
|
||||
|
||||
/**
|
||||
* This collects a bunch of disparate functions which was done in the server
|
||||
* at various points that really should've been done within xkbcomp. Turns out
|
||||
* your actions and types are a lot more useful when any of your modifiers
|
||||
* other than Shift actually do something ...
|
||||
*/
|
||||
Bool
|
||||
UpdateModifiersFromCompat(struct xkb_desc *xkb)
|
||||
{
|
||||
xkb_keycode_t key;
|
||||
int i;
|
||||
|
||||
/* Find all the interprets for the key and bind them to actions,
|
||||
* which will also update the vmodmap. */
|
||||
for (key = xkb->min_key_code; key <= xkb->max_key_code; key++)
|
||||
if (!ApplyInterpsToKey(xkb, key))
|
||||
return False;
|
||||
|
||||
/* Update xkb->server->vmods, the virtual -> real mod mapping. */
|
||||
for (i = 0; i < XkbNumVirtualMods; i++)
|
||||
xkb->server->vmods[i] = 0;
|
||||
for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
|
||||
if (!xkb->server->vmodmap[key])
|
||||
continue;
|
||||
for (i = 0; i < XkbNumVirtualMods; i++) {
|
||||
if (!(xkb->server->vmodmap[key] & (1 << i)))
|
||||
continue;
|
||||
xkb->server->vmods[i] |= xkb->map->modmap[key];
|
||||
}
|
||||
}
|
||||
|
||||
/* Now update the level masks for all the types to reflect the vmods. */
|
||||
for (i = 0; i < xkb->map->num_types; i++) {
|
||||
struct xkb_key_type *type = &xkb->map->types[i];
|
||||
uint32_t mask = 0;
|
||||
int j;
|
||||
type->mods.mask = type->mods.real_mods;
|
||||
type->mods.mask |= VModsToReal(xkb, type->mods.vmods);
|
||||
for (j = 0; j < XkbNumVirtualMods; j++) {
|
||||
if (!(type->mods.vmods & (1 << j)))
|
||||
continue;
|
||||
mask |= xkb->server->vmods[j];
|
||||
}
|
||||
for (j = 0; j < type->map_count; j++) {
|
||||
struct xkb_mods *mods = &type->map[j].mods;
|
||||
mods->mask = mods->real_mods | VModsToReal(xkb, mods->vmods);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update action modifiers. */
|
||||
for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
|
||||
union xkb_action *acts = XkbKeyActionsPtr(xkb, key);
|
||||
for (i = 0; i < XkbKeyNumActions(xkb, key); i++) {
|
||||
if (acts[i].any.type == XkbSA_NoAction)
|
||||
continue;
|
||||
UpdateActionMods(xkb, &acts[i], xkb->map->modmap[key]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update group modifiers. */
|
||||
for (i = 0; i < XkbNumKbdGroups; i++) {
|
||||
struct xkb_mods *group = &xkb->compat->groups[i];
|
||||
group->mask = group->real_mods | VModsToReal(xkb, group->vmods);
|
||||
}
|
||||
|
||||
/* Update vmod -> indicator maps. */
|
||||
|
||||
return True;
|
||||
}
|
||||
|
|
|
@ -190,6 +190,10 @@ CompileKeymap(XkbFile *file, unsigned merge)
|
|||
if (!ok)
|
||||
goto err;
|
||||
|
||||
ok = UpdateModifiersFromCompat(xkb);
|
||||
if (!ok)
|
||||
goto err;
|
||||
|
||||
return xkb;
|
||||
|
||||
err:
|
||||
|
|
|
@ -285,4 +285,7 @@ CompileCompatMap(XkbFile *file, struct xkb_desc * xkb, unsigned merge,
|
|||
extern Bool
|
||||
CompileSymbols(XkbFile *file, struct xkb_desc * xkb, unsigned merge);
|
||||
|
||||
extern Bool
|
||||
UpdateModifiersFromCompat(struct xkb_desc *xkb);
|
||||
|
||||
#endif /* XKBCOMP_H */
|
||||
|
|
Loading…
Reference in New Issue