2009-03-27 07:55:32 -06:00
|
|
|
/************************************************************
|
|
|
|
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
|
2009-04-04 10:19:51 -06:00
|
|
|
documentation, and that the name of Silicon Graphics not be
|
|
|
|
used in advertising or publicity pertaining to distribution
|
2009-03-27 07:55:32 -06:00
|
|
|
of the software without specific prior written permission.
|
2009-04-04 10:19:51 -06:00
|
|
|
Silicon Graphics makes no representation about the suitability
|
2009-03-27 07:55:32 -06:00
|
|
|
of this software for any purpose. It is provided "as is"
|
|
|
|
without any express or implied warranty.
|
2009-04-04 10:19:51 -06:00
|
|
|
|
|
|
|
SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
|
|
|
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
2009-03-27 07:55:32 -06:00
|
|
|
AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
|
2009-04-04 10:19:51 -06:00
|
|
|
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
|
2009-03-27 07:55:32 -06:00
|
|
|
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
|
|
|
|
THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
|
|
|
********************************************************/
|
|
|
|
|
2012-05-08 04:57:07 -06:00
|
|
|
#include "xkbcomp-priv.h"
|
2010-06-21 07:27:58 -06:00
|
|
|
#include "parseutils.h"
|
2012-05-08 04:57:07 -06:00
|
|
|
#include "action.h"
|
|
|
|
#include "indicators.h"
|
|
|
|
#include "vmod.h"
|
2009-03-27 07:55:32 -06:00
|
|
|
|
|
|
|
typedef struct _SymInterpInfo
|
|
|
|
{
|
|
|
|
CommonInfo defs;
|
2010-07-01 12:35:24 -06:00
|
|
|
struct xkb_sym_interpret interp;
|
2009-03-27 07:55:32 -06:00
|
|
|
} SymInterpInfo;
|
|
|
|
|
|
|
|
#define _SI_VirtualMod (1<<0)
|
|
|
|
#define _SI_Action (1<<1)
|
|
|
|
#define _SI_AutoRepeat (1<<2)
|
|
|
|
#define _SI_LockingKey (1<<3)
|
|
|
|
#define _SI_LevelOneOnly (1<<4)
|
|
|
|
|
|
|
|
typedef struct _GroupCompatInfo
|
|
|
|
{
|
|
|
|
unsigned char fileID;
|
|
|
|
unsigned char merge;
|
2012-04-05 18:38:55 -06:00
|
|
|
bool defined;
|
2009-03-27 07:55:32 -06:00
|
|
|
unsigned char real_mods;
|
2012-03-09 12:09:25 -07:00
|
|
|
xkb_atom_t vmods;
|
2009-03-27 07:55:32 -06:00
|
|
|
} GroupCompatInfo;
|
|
|
|
|
|
|
|
typedef struct _CompatInfo
|
|
|
|
{
|
|
|
|
char *name;
|
|
|
|
unsigned fileID;
|
|
|
|
int errorCount;
|
|
|
|
int nInterps;
|
|
|
|
SymInterpInfo *interps;
|
|
|
|
SymInterpInfo dflt;
|
|
|
|
LEDInfo ledDflt;
|
|
|
|
GroupCompatInfo groupCompat[XkbNumKbdGroups];
|
|
|
|
LEDInfo *leds;
|
|
|
|
VModInfo vmods;
|
|
|
|
ActionInfo *act;
|
2012-04-03 08:14:16 -06:00
|
|
|
struct xkb_keymap * xkb;
|
2009-03-27 07:55:32 -06:00
|
|
|
} CompatInfo;
|
|
|
|
|
|
|
|
/***====================================================================***/
|
|
|
|
|
|
|
|
#define ReportSINotArray(si,f,i) \
|
|
|
|
ReportNotArray("symbol interpretation",(f),siText((si),(i)))
|
|
|
|
#define ReportSIBadType(si,f,w,i) \
|
|
|
|
ReportBadType("symbol interpretation",(f),siText((si),(i)),(w))
|
|
|
|
|
|
|
|
/***====================================================================***/
|
|
|
|
|
2012-03-02 13:31:29 -07:00
|
|
|
static const char *
|
2009-03-27 07:55:32 -06:00
|
|
|
siText(SymInterpInfo * si, CompatInfo * info)
|
|
|
|
{
|
|
|
|
static char buf[128];
|
|
|
|
|
|
|
|
if (si == &info->dflt)
|
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf), "default");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-03-28 15:06:26 -06:00
|
|
|
snprintf(buf, sizeof(buf), "%s+%s(%s)",
|
|
|
|
XkbcKeysymText(si->interp.sym),
|
|
|
|
XkbcSIMatchText(si->interp.match),
|
2012-04-05 18:38:55 -06:00
|
|
|
XkbcModMaskText(si->interp.mods, false));
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-04-03 08:14:16 -06:00
|
|
|
InitCompatInfo(CompatInfo * info, struct xkb_keymap * xkb)
|
2009-03-27 07:55:32 -06:00
|
|
|
{
|
2012-03-23 18:36:11 -06:00
|
|
|
unsigned int i;
|
2009-03-27 07:55:32 -06:00
|
|
|
|
|
|
|
info->xkb = xkb;
|
|
|
|
info->name = NULL;
|
|
|
|
info->fileID = 0;
|
|
|
|
info->errorCount = 0;
|
|
|
|
info->nInterps = 0;
|
|
|
|
info->interps = NULL;
|
|
|
|
info->act = NULL;
|
|
|
|
info->dflt.defs.fileID = info->fileID;
|
|
|
|
info->dflt.defs.defined = 0;
|
|
|
|
info->dflt.defs.merge = MergeOverride;
|
|
|
|
info->dflt.interp.flags = 0;
|
|
|
|
info->dflt.interp.virtual_mod = XkbNoModifier;
|
|
|
|
info->dflt.interp.act.type = XkbSA_NoAction;
|
2012-03-14 11:06:09 -06:00
|
|
|
for (i = 0; i < sizeof(info->dflt.interp.act.any.data); i++)
|
|
|
|
info->dflt.interp.act.any.data[i] = 0;
|
2009-03-28 15:09:36 -06:00
|
|
|
ClearIndicatorMapInfo(&info->ledDflt);
|
2009-03-27 07:55:32 -06:00
|
|
|
info->ledDflt.defs.fileID = info->fileID;
|
|
|
|
info->ledDflt.defs.defined = 0;
|
|
|
|
info->ledDflt.defs.merge = MergeOverride;
|
2012-02-29 11:50:17 -07:00
|
|
|
memset(&info->groupCompat[0], 0,
|
|
|
|
XkbNumKbdGroups * sizeof(GroupCompatInfo));
|
2009-03-27 07:55:32 -06:00
|
|
|
info->leds = NULL;
|
|
|
|
InitVModInfo(&info->vmods, xkb);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-04-03 08:14:16 -06:00
|
|
|
ClearCompatInfo(CompatInfo * info, struct xkb_keymap * xkb)
|
2009-03-27 07:55:32 -06:00
|
|
|
{
|
2012-03-23 18:36:11 -06:00
|
|
|
unsigned int i;
|
2012-03-01 10:25:37 -07:00
|
|
|
ActionInfo *next;
|
2009-03-27 07:55:32 -06:00
|
|
|
|
2012-02-29 10:56:39 -07:00
|
|
|
free(info->name);
|
2009-03-27 07:55:32 -06:00
|
|
|
info->name = NULL;
|
|
|
|
info->dflt.defs.defined = 0;
|
|
|
|
info->dflt.defs.merge = MergeAugment;
|
|
|
|
info->dflt.interp.flags = 0;
|
|
|
|
info->dflt.interp.virtual_mod = XkbNoModifier;
|
|
|
|
info->dflt.interp.act.type = XkbSA_NoAction;
|
2012-03-14 11:06:09 -06:00
|
|
|
for (i = 0; i < sizeof(info->dflt.interp.act.any.data); i++)
|
|
|
|
info->dflt.interp.act.any.data[i] = 0;
|
2009-03-28 15:09:36 -06:00
|
|
|
ClearIndicatorMapInfo(&info->ledDflt);
|
2009-03-27 07:55:32 -06:00
|
|
|
info->nInterps = 0;
|
|
|
|
info->interps = (SymInterpInfo *) ClearCommonInfo(&info->interps->defs);
|
2012-02-29 11:50:17 -07:00
|
|
|
memset(&info->groupCompat[0], 0,
|
|
|
|
XkbNumKbdGroups * sizeof(GroupCompatInfo));
|
2009-03-27 07:55:32 -06:00
|
|
|
info->leds = (LEDInfo *) ClearCommonInfo(&info->leds->defs);
|
2012-03-01 10:25:37 -07:00
|
|
|
while (info->act) {
|
|
|
|
next = info->act->next;
|
|
|
|
free(info->act);
|
|
|
|
info->act = next;
|
|
|
|
}
|
2009-03-27 07:55:32 -06:00
|
|
|
ClearVModInfo(&info->vmods, xkb);
|
|
|
|
}
|
|
|
|
|
|
|
|
static SymInterpInfo *
|
|
|
|
NextInterp(CompatInfo * info)
|
|
|
|
{
|
|
|
|
SymInterpInfo *si;
|
|
|
|
|
|
|
|
si = uTypedAlloc(SymInterpInfo);
|
|
|
|
if (si)
|
|
|
|
{
|
2012-02-29 11:50:17 -07:00
|
|
|
memset(si, 0, sizeof(SymInterpInfo));
|
2009-03-27 07:55:32 -06:00
|
|
|
info->interps =
|
|
|
|
(SymInterpInfo *) AddCommonInfo(&info->interps->defs,
|
|
|
|
(CommonInfo *) si);
|
|
|
|
info->nInterps++;
|
|
|
|
}
|
|
|
|
return si;
|
|
|
|
}
|
|
|
|
|
|
|
|
static SymInterpInfo *
|
|
|
|
FindMatchingInterp(CompatInfo * info, SymInterpInfo * new)
|
|
|
|
{
|
|
|
|
SymInterpInfo *old;
|
|
|
|
|
|
|
|
for (old = info->interps; old != NULL;
|
|
|
|
old = (SymInterpInfo *) old->defs.next)
|
|
|
|
{
|
|
|
|
if ((old->interp.sym == new->interp.sym) &&
|
|
|
|
(old->interp.mods == new->interp.mods) &&
|
|
|
|
(old->interp.match == new->interp.match))
|
|
|
|
{
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-04-05 18:38:55 -06:00
|
|
|
static bool
|
2009-03-27 07:55:32 -06:00
|
|
|
AddInterp(CompatInfo * info, SymInterpInfo * new)
|
|
|
|
{
|
|
|
|
unsigned collide;
|
|
|
|
SymInterpInfo *old;
|
|
|
|
|
|
|
|
collide = 0;
|
|
|
|
old = FindMatchingInterp(info, new);
|
|
|
|
if (old != NULL)
|
|
|
|
{
|
|
|
|
if (new->defs.merge == MergeReplace)
|
|
|
|
{
|
|
|
|
SymInterpInfo *next = (SymInterpInfo *) old->defs.next;
|
|
|
|
if (((old->defs.fileID == new->defs.fileID)
|
|
|
|
&& (warningLevel > 0)) || (warningLevel > 9))
|
|
|
|
{
|
2009-03-31 08:21:20 -06:00
|
|
|
WARN("Multiple definitions for \"%s\"\n", siText(new, info));
|
2009-03-27 07:55:32 -06:00
|
|
|
ACTION("Earlier interpretation ignored\n");
|
|
|
|
}
|
|
|
|
*old = *new;
|
|
|
|
old->defs.next = &next->defs;
|
2012-04-05 18:38:55 -06:00
|
|
|
return true;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
if (UseNewField(_SI_VirtualMod, &old->defs, &new->defs, &collide))
|
|
|
|
{
|
|
|
|
old->interp.virtual_mod = new->interp.virtual_mod;
|
|
|
|
old->defs.defined |= _SI_VirtualMod;
|
|
|
|
}
|
|
|
|
if (UseNewField(_SI_Action, &old->defs, &new->defs, &collide))
|
|
|
|
{
|
|
|
|
old->interp.act = new->interp.act;
|
|
|
|
old->defs.defined |= _SI_Action;
|
|
|
|
}
|
|
|
|
if (UseNewField(_SI_AutoRepeat, &old->defs, &new->defs, &collide))
|
|
|
|
{
|
|
|
|
old->interp.flags &= ~XkbSI_AutoRepeat;
|
|
|
|
old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat);
|
|
|
|
old->defs.defined |= _SI_AutoRepeat;
|
|
|
|
}
|
|
|
|
if (UseNewField(_SI_LockingKey, &old->defs, &new->defs, &collide))
|
|
|
|
{
|
|
|
|
old->interp.flags &= ~XkbSI_LockingKey;
|
|
|
|
old->interp.flags |= (new->interp.flags & XkbSI_LockingKey);
|
|
|
|
old->defs.defined |= _SI_LockingKey;
|
|
|
|
}
|
|
|
|
if (UseNewField(_SI_LevelOneOnly, &old->defs, &new->defs, &collide))
|
|
|
|
{
|
|
|
|
old->interp.match &= ~XkbSI_LevelOneOnly;
|
|
|
|
old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly);
|
|
|
|
old->defs.defined |= _SI_LevelOneOnly;
|
|
|
|
}
|
|
|
|
if (collide)
|
|
|
|
{
|
2009-03-31 08:21:20 -06:00
|
|
|
WARN("Multiple interpretations of \"%s\"\n", siText(new, info));
|
|
|
|
ACTION("Using %s definition for duplicate fields\n",
|
2009-03-27 07:55:32 -06:00
|
|
|
(new->defs.merge != MergeAugment ? "last" : "first"));
|
|
|
|
}
|
2012-04-05 18:38:55 -06:00
|
|
|
return true;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
old = new;
|
|
|
|
if ((new = NextInterp(info)) == NULL)
|
2012-04-05 18:38:55 -06:00
|
|
|
return false;
|
2009-03-27 07:55:32 -06:00
|
|
|
*new = *old;
|
|
|
|
new->defs.next = NULL;
|
2012-04-05 18:38:55 -06:00
|
|
|
return true;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
|
2012-04-05 18:38:55 -06:00
|
|
|
static bool
|
2009-03-27 07:55:32 -06:00
|
|
|
AddGroupCompat(CompatInfo * info, unsigned group, GroupCompatInfo * newGC)
|
|
|
|
{
|
|
|
|
GroupCompatInfo *gc;
|
|
|
|
unsigned merge;
|
|
|
|
|
|
|
|
merge = newGC->merge;
|
|
|
|
gc = &info->groupCompat[group];
|
|
|
|
if (((gc->real_mods == newGC->real_mods) && (gc->vmods == newGC->vmods)))
|
|
|
|
{
|
2012-04-05 18:38:55 -06:00
|
|
|
return true;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
if (((gc->fileID == newGC->fileID) && (warningLevel > 0))
|
|
|
|
|| (warningLevel > 9))
|
|
|
|
{
|
2009-03-31 08:21:20 -06:00
|
|
|
WARN("Compat map for group %d redefined\n", group + 1);
|
|
|
|
ACTION("Using %s definition\n",
|
2009-03-27 07:55:32 -06:00
|
|
|
(merge == MergeAugment ? "old" : "new"));
|
|
|
|
}
|
2012-04-03 06:44:21 -06:00
|
|
|
if (newGC->defined && (merge != MergeAugment || !gc->defined))
|
2009-03-27 07:55:32 -06:00
|
|
|
*gc = *newGC;
|
2012-04-05 18:38:55 -06:00
|
|
|
return true;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/***====================================================================***/
|
|
|
|
|
2012-04-05 18:38:55 -06:00
|
|
|
static bool
|
2009-03-27 07:55:32 -06:00
|
|
|
ResolveStateAndPredicate(ExprDef * expr,
|
|
|
|
unsigned *pred_rtrn,
|
|
|
|
unsigned *mods_rtrn, CompatInfo * info)
|
|
|
|
{
|
|
|
|
ExprResult result;
|
|
|
|
|
|
|
|
if (expr == NULL)
|
|
|
|
{
|
|
|
|
*pred_rtrn = XkbSI_AnyOfOrNone;
|
|
|
|
*mods_rtrn = ~0;
|
2012-04-05 18:38:55 -06:00
|
|
|
return true;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
*pred_rtrn = XkbSI_Exactly;
|
|
|
|
if (expr->op == ExprActionDecl)
|
|
|
|
{
|
2010-06-30 15:20:56 -06:00
|
|
|
const char *pred_txt = XkbcAtomText(expr->value.action.name);
|
2012-03-23 16:26:12 -06:00
|
|
|
if (strcasecmp(pred_txt, "noneof") == 0)
|
2009-03-27 07:55:32 -06:00
|
|
|
*pred_rtrn = XkbSI_NoneOf;
|
2012-03-23 16:26:12 -06:00
|
|
|
else if (strcasecmp(pred_txt, "anyofornone") == 0)
|
2009-03-27 07:55:32 -06:00
|
|
|
*pred_rtrn = XkbSI_AnyOfOrNone;
|
2012-03-23 16:26:12 -06:00
|
|
|
else if (strcasecmp(pred_txt, "anyof") == 0)
|
2009-03-27 07:55:32 -06:00
|
|
|
*pred_rtrn = XkbSI_AnyOf;
|
2012-03-23 16:26:12 -06:00
|
|
|
else if (strcasecmp(pred_txt, "allof") == 0)
|
2009-03-27 07:55:32 -06:00
|
|
|
*pred_rtrn = XkbSI_AllOf;
|
2012-03-23 16:26:12 -06:00
|
|
|
else if (strcasecmp(pred_txt, "exactly") == 0)
|
2009-03-27 07:55:32 -06:00
|
|
|
*pred_rtrn = XkbSI_Exactly;
|
|
|
|
else
|
|
|
|
{
|
2009-03-31 08:21:20 -06:00
|
|
|
ERROR("Illegal modifier predicate \"%s\"\n", pred_txt);
|
2009-03-27 07:55:32 -06:00
|
|
|
ACTION("Ignored\n");
|
2012-04-05 18:38:55 -06:00
|
|
|
return false;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
expr = expr->value.action.args;
|
|
|
|
}
|
|
|
|
else if (expr->op == ExprIdent)
|
|
|
|
{
|
2010-06-30 15:20:56 -06:00
|
|
|
const char *pred_txt = XkbcAtomText(expr->value.str);
|
2012-03-23 16:26:12 -06:00
|
|
|
if ((pred_txt) && (strcasecmp(pred_txt, "any") == 0))
|
2009-03-27 07:55:32 -06:00
|
|
|
{
|
|
|
|
*pred_rtrn = XkbSI_AnyOf;
|
|
|
|
*mods_rtrn = 0xff;
|
2012-04-05 18:38:55 -06:00
|
|
|
return true;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-20 06:34:36 -07:00
|
|
|
if (ExprResolveModMask(expr, &result))
|
2009-03-27 07:55:32 -06:00
|
|
|
{
|
|
|
|
*mods_rtrn = result.uval;
|
2012-04-05 18:38:55 -06:00
|
|
|
return true;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
2012-04-05 18:38:55 -06:00
|
|
|
return false;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/***====================================================================***/
|
|
|
|
|
|
|
|
static void
|
|
|
|
MergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from, unsigned merge)
|
|
|
|
{
|
|
|
|
SymInterpInfo *si;
|
|
|
|
LEDInfo *led, *rtrn, *next;
|
|
|
|
GroupCompatInfo *gcm;
|
2012-02-29 11:25:11 -07:00
|
|
|
int i;
|
2009-03-27 07:55:32 -06:00
|
|
|
|
|
|
|
if (from->errorCount > 0)
|
|
|
|
{
|
|
|
|
into->errorCount += from->errorCount;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (into->name == NULL)
|
|
|
|
{
|
|
|
|
into->name = from->name;
|
|
|
|
from->name = NULL;
|
|
|
|
}
|
|
|
|
for (si = from->interps; si; si = (SymInterpInfo *) si->defs.next)
|
|
|
|
{
|
|
|
|
if (merge != MergeDefault)
|
|
|
|
si->defs.merge = merge;
|
|
|
|
if (!AddInterp(into, si))
|
|
|
|
into->errorCount++;
|
|
|
|
}
|
|
|
|
for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups; i++, gcm++)
|
|
|
|
{
|
|
|
|
if (merge != MergeDefault)
|
|
|
|
gcm->merge = merge;
|
|
|
|
if (!AddGroupCompat(into, i, gcm))
|
|
|
|
into->errorCount++;
|
|
|
|
}
|
|
|
|
for (led = from->leds; led != NULL; led = next)
|
|
|
|
{
|
|
|
|
next = (LEDInfo *) led->defs.next;
|
|
|
|
if (merge != MergeDefault)
|
|
|
|
led->defs.merge = merge;
|
|
|
|
rtrn = AddIndicatorMap(into->leds, led);
|
|
|
|
if (rtrn != NULL)
|
|
|
|
into->leds = rtrn;
|
|
|
|
else
|
|
|
|
into->errorCount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-05 02:24:39 -06:00
|
|
|
typedef void (*FileHandler) (XkbFile *rtrn, struct xkb_keymap *xkb,
|
|
|
|
unsigned merge, CompatInfo *info);
|
2009-03-27 07:55:32 -06:00
|
|
|
|
2012-04-05 18:38:55 -06:00
|
|
|
static bool
|
2009-03-27 07:55:32 -06:00
|
|
|
HandleIncludeCompatMap(IncludeStmt * stmt,
|
2012-04-03 08:14:16 -06:00
|
|
|
struct xkb_keymap * xkb, CompatInfo * info, FileHandler hndlr)
|
2009-03-27 07:55:32 -06:00
|
|
|
{
|
|
|
|
unsigned newMerge;
|
|
|
|
XkbFile *rtrn;
|
|
|
|
CompatInfo included;
|
2012-04-05 18:38:55 -06:00
|
|
|
bool haveSelf;
|
2009-03-27 07:55:32 -06:00
|
|
|
|
2012-04-05 18:38:55 -06:00
|
|
|
haveSelf = false;
|
2009-03-27 07:55:32 -06:00
|
|
|
if ((stmt->file == NULL) && (stmt->map == NULL))
|
|
|
|
{
|
2012-04-05 18:38:55 -06:00
|
|
|
haveSelf = true;
|
2009-03-27 07:55:32 -06:00
|
|
|
included = *info;
|
2012-02-29 11:50:17 -07:00
|
|
|
memset(info, 0, sizeof(CompatInfo));
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
2012-03-27 10:22:35 -06:00
|
|
|
else if (ProcessIncludeFile(xkb->context, stmt, XkmCompatMapIndex, &rtrn,
|
|
|
|
&newMerge))
|
2009-03-27 07:55:32 -06:00
|
|
|
{
|
|
|
|
InitCompatInfo(&included, xkb);
|
|
|
|
included.fileID = rtrn->id;
|
|
|
|
included.dflt = info->dflt;
|
|
|
|
included.dflt.defs.fileID = rtrn->id;
|
|
|
|
included.dflt.defs.merge = newMerge;
|
|
|
|
included.ledDflt.defs.fileID = rtrn->id;
|
|
|
|
included.ledDflt.defs.merge = newMerge;
|
|
|
|
included.act = info->act;
|
|
|
|
(*hndlr) (rtrn, xkb, MergeOverride, &included);
|
|
|
|
if (stmt->stmt != NULL)
|
|
|
|
{
|
2012-02-29 10:56:39 -07:00
|
|
|
free(included.name);
|
2009-03-27 07:55:32 -06:00
|
|
|
included.name = stmt->stmt;
|
|
|
|
stmt->stmt = NULL;
|
|
|
|
}
|
2012-03-01 10:25:37 -07:00
|
|
|
if (info->act != NULL)
|
|
|
|
included.act = NULL;
|
2012-03-02 05:49:36 -07:00
|
|
|
FreeXKBFile(rtrn);
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
info->errorCount += 10;
|
2012-04-05 18:38:55 -06:00
|
|
|
return false;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
if ((stmt->next != NULL) && (included.errorCount < 1))
|
|
|
|
{
|
|
|
|
IncludeStmt *next;
|
|
|
|
unsigned op;
|
|
|
|
CompatInfo next_incl;
|
|
|
|
|
|
|
|
for (next = stmt->next; next != NULL; next = next->next)
|
|
|
|
{
|
|
|
|
if ((next->file == NULL) && (next->map == NULL))
|
|
|
|
{
|
2012-04-05 18:38:55 -06:00
|
|
|
haveSelf = true;
|
2009-03-27 07:55:32 -06:00
|
|
|
MergeIncludedCompatMaps(&included, info, next->merge);
|
|
|
|
ClearCompatInfo(info, xkb);
|
|
|
|
}
|
2012-03-27 10:22:35 -06:00
|
|
|
else if (ProcessIncludeFile(xkb->context, next, XkmCompatMapIndex,
|
|
|
|
&rtrn, &op))
|
2009-03-27 07:55:32 -06:00
|
|
|
{
|
|
|
|
InitCompatInfo(&next_incl, xkb);
|
|
|
|
next_incl.fileID = rtrn->id;
|
|
|
|
next_incl.dflt = info->dflt;
|
|
|
|
next_incl.dflt.defs.fileID = rtrn->id;
|
|
|
|
next_incl.dflt.defs.merge = op;
|
|
|
|
next_incl.ledDflt.defs.fileID = rtrn->id;
|
|
|
|
next_incl.ledDflt.defs.merge = op;
|
|
|
|
next_incl.act = info->act;
|
|
|
|
(*hndlr) (rtrn, xkb, MergeOverride, &next_incl);
|
|
|
|
MergeIncludedCompatMaps(&included, &next_incl, op);
|
2012-03-01 10:25:37 -07:00
|
|
|
if (info->act != NULL)
|
|
|
|
next_incl.act = NULL;
|
2009-03-27 07:55:32 -06:00
|
|
|
ClearCompatInfo(&next_incl, xkb);
|
2012-03-02 05:49:36 -07:00
|
|
|
FreeXKBFile(rtrn);
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
info->errorCount += 10;
|
2012-04-05 18:38:55 -06:00
|
|
|
return false;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (haveSelf)
|
|
|
|
*info = included;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MergeIncludedCompatMaps(info, &included, newMerge);
|
|
|
|
ClearCompatInfo(&included, xkb);
|
|
|
|
}
|
|
|
|
return (info->errorCount == 0);
|
|
|
|
}
|
|
|
|
|
2012-03-02 08:40:19 -07:00
|
|
|
static const LookupEntry useModMapValues[] = {
|
2009-03-27 07:55:32 -06:00
|
|
|
{"levelone", 1},
|
|
|
|
{"level1", 1},
|
|
|
|
{"anylevel", 0},
|
|
|
|
{"any", 0},
|
|
|
|
{NULL, 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
SetInterpField(SymInterpInfo * si,
|
2012-04-03 08:14:16 -06:00
|
|
|
struct xkb_keymap * xkb,
|
2009-03-27 07:55:32 -06:00
|
|
|
char *field,
|
|
|
|
ExprDef * arrayNdx, ExprDef * value, CompatInfo * info)
|
|
|
|
{
|
|
|
|
int ok = 1;
|
|
|
|
ExprResult tmp;
|
|
|
|
|
2012-03-23 16:26:12 -06:00
|
|
|
if (strcasecmp(field, "action") == 0)
|
2009-03-27 07:55:32 -06:00
|
|
|
{
|
|
|
|
if (arrayNdx != NULL)
|
|
|
|
return ReportSINotArray(si, field, info);
|
2012-04-10 16:55:50 -06:00
|
|
|
ok = HandleActionDef(value, xkb, &si->interp.act.any, info->act);
|
2009-03-27 07:55:32 -06:00
|
|
|
if (ok)
|
|
|
|
si->defs.defined |= _SI_Action;
|
|
|
|
}
|
2012-03-23 16:26:12 -06:00
|
|
|
else if ((strcasecmp(field, "virtualmodifier") == 0) ||
|
|
|
|
(strcasecmp(field, "virtualmod") == 0))
|
2009-03-27 07:55:32 -06:00
|
|
|
{
|
|
|
|
if (arrayNdx != NULL)
|
|
|
|
return ReportSINotArray(si, field, info);
|
2012-02-15 08:58:14 -07:00
|
|
|
ok = ResolveVirtualModifier(value, xkb, &tmp, &info->vmods);
|
2009-03-27 07:55:32 -06:00
|
|
|
if (ok)
|
|
|
|
{
|
|
|
|
si->interp.virtual_mod = tmp.uval;
|
|
|
|
si->defs.defined |= _SI_VirtualMod;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return ReportSIBadType(si, field, "virtual modifier", info);
|
|
|
|
}
|
2012-03-23 16:26:12 -06:00
|
|
|
else if (strcasecmp(field, "repeat") == 0)
|
2009-03-27 07:55:32 -06:00
|
|
|
{
|
|
|
|
if (arrayNdx != NULL)
|
|
|
|
return ReportSINotArray(si, field, info);
|
2012-02-20 06:44:27 -07:00
|
|
|
ok = ExprResolveBoolean(value, &tmp);
|
2009-03-27 07:55:32 -06:00
|
|
|
if (ok)
|
|
|
|
{
|
|
|
|
if (tmp.uval)
|
|
|
|
si->interp.flags |= XkbSI_AutoRepeat;
|
|
|
|
else
|
|
|
|
si->interp.flags &= ~XkbSI_AutoRepeat;
|
|
|
|
si->defs.defined |= _SI_AutoRepeat;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return ReportSIBadType(si, field, "boolean", info);
|
|
|
|
}
|
2012-03-23 16:26:12 -06:00
|
|
|
else if (strcasecmp(field, "locking") == 0)
|
2009-03-27 07:55:32 -06:00
|
|
|
{
|
|
|
|
if (arrayNdx != NULL)
|
|
|
|
return ReportSINotArray(si, field, info);
|
2012-02-20 06:44:27 -07:00
|
|
|
ok = ExprResolveBoolean(value, &tmp);
|
2009-03-27 07:55:32 -06:00
|
|
|
if (ok)
|
|
|
|
{
|
|
|
|
if (tmp.uval)
|
|
|
|
si->interp.flags |= XkbSI_LockingKey;
|
|
|
|
else
|
|
|
|
si->interp.flags &= ~XkbSI_LockingKey;
|
|
|
|
si->defs.defined |= _SI_LockingKey;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return ReportSIBadType(si, field, "boolean", info);
|
|
|
|
}
|
2012-03-23 16:26:12 -06:00
|
|
|
else if ((strcasecmp(field, "usemodmap") == 0) ||
|
|
|
|
(strcasecmp(field, "usemodmapmods") == 0))
|
2009-03-27 07:55:32 -06:00
|
|
|
{
|
|
|
|
if (arrayNdx != NULL)
|
|
|
|
return ReportSINotArray(si, field, info);
|
|
|
|
ok = ExprResolveEnum(value, &tmp, useModMapValues);
|
|
|
|
if (ok)
|
|
|
|
{
|
|
|
|
if (tmp.uval)
|
|
|
|
si->interp.match |= XkbSI_LevelOneOnly;
|
|
|
|
else
|
|
|
|
si->interp.match &= ~XkbSI_LevelOneOnly;
|
|
|
|
si->defs.defined |= _SI_LevelOneOnly;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return ReportSIBadType(si, field, "level specification", info);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ok = ReportBadField("symbol interpretation", field, siText(si, info));
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-04-03 08:14:16 -06:00
|
|
|
HandleInterpVar(VarDef * stmt, struct xkb_keymap * xkb, CompatInfo * info)
|
2009-03-27 07:55:32 -06:00
|
|
|
{
|
|
|
|
ExprResult elem, field;
|
|
|
|
ExprDef *ndx;
|
2010-06-15 08:20:32 -06:00
|
|
|
int ret;
|
2009-03-27 07:55:32 -06:00
|
|
|
|
|
|
|
if (ExprResolveLhs(stmt->name, &elem, &field, &ndx) == 0)
|
2010-06-15 08:20:32 -06:00
|
|
|
ret = 0; /* internal error, already reported */
|
2012-03-23 16:26:12 -06:00
|
|
|
else if (elem.str && (strcasecmp(elem.str, "interpret") == 0))
|
2010-06-15 08:20:32 -06:00
|
|
|
ret = SetInterpField(&info->dflt, xkb, field.str, ndx, stmt->value,
|
2009-03-27 07:55:32 -06:00
|
|
|
info);
|
2012-03-23 16:26:12 -06:00
|
|
|
else if (elem.str && (strcasecmp(elem.str, "indicator") == 0))
|
2010-06-15 08:20:32 -06:00
|
|
|
ret = SetIndicatorMapField(&info->ledDflt, xkb, field.str, ndx,
|
|
|
|
stmt->value);
|
|
|
|
else
|
|
|
|
ret = SetActionField(xkb, elem.str, field.str, ndx, stmt->value,
|
|
|
|
&info->act);
|
|
|
|
free(elem.str);
|
|
|
|
free(field.str);
|
|
|
|
return ret;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-04-03 08:14:16 -06:00
|
|
|
HandleInterpBody(VarDef * def, struct xkb_keymap * xkb, SymInterpInfo * si,
|
2009-03-27 07:55:32 -06:00
|
|
|
CompatInfo * info)
|
|
|
|
{
|
|
|
|
int ok = 1;
|
|
|
|
ExprResult tmp, field;
|
|
|
|
ExprDef *arrayNdx;
|
|
|
|
|
|
|
|
for (; def != NULL; def = (VarDef *) def->common.next)
|
|
|
|
{
|
|
|
|
if ((def->name) && (def->name->type == ExprFieldRef))
|
|
|
|
{
|
|
|
|
ok = HandleInterpVar(def, xkb, info);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ok = ExprResolveLhs(def->name, &tmp, &field, &arrayNdx);
|
2012-02-15 17:22:11 -07:00
|
|
|
if (ok) {
|
2009-03-27 07:55:32 -06:00
|
|
|
ok = SetInterpField(si, xkb, field.str, arrayNdx, def->value,
|
|
|
|
info);
|
2012-02-15 17:22:11 -07:00
|
|
|
free(field.str);
|
|
|
|
}
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-04-03 08:14:16 -06:00
|
|
|
HandleInterpDef(InterpDef * def, struct xkb_keymap * xkb, unsigned merge,
|
2009-03-27 07:55:32 -06:00
|
|
|
CompatInfo * info)
|
|
|
|
{
|
|
|
|
unsigned pred, mods;
|
|
|
|
SymInterpInfo si;
|
|
|
|
|
|
|
|
if (!ResolveStateAndPredicate(def->match, &pred, &mods, info))
|
|
|
|
{
|
|
|
|
ERROR("Couldn't determine matching modifiers\n");
|
|
|
|
ACTION("Symbol interpretation ignored\n");
|
2012-04-05 18:38:55 -06:00
|
|
|
return false;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
if (def->merge != MergeDefault)
|
|
|
|
merge = def->merge;
|
|
|
|
|
|
|
|
si = info->dflt;
|
|
|
|
si.defs.merge = merge;
|
2010-06-21 07:27:58 -06:00
|
|
|
if (!LookupKeysym(def->sym, &si.interp.sym))
|
|
|
|
{
|
2012-03-16 08:22:04 -06:00
|
|
|
ERROR("Could not resolve keysym %s\n", def->sym);
|
|
|
|
ACTION("Symbol interpretation ignored\n");
|
2012-04-05 18:38:55 -06:00
|
|
|
return false;
|
2010-06-21 07:27:58 -06:00
|
|
|
}
|
2009-03-27 07:55:32 -06:00
|
|
|
si.interp.match = pred & XkbSI_OpMask;
|
|
|
|
si.interp.mods = mods;
|
|
|
|
if (!HandleInterpBody(def->def, xkb, &si, info))
|
|
|
|
{
|
|
|
|
info->errorCount++;
|
2012-04-05 18:38:55 -06:00
|
|
|
return false;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!AddInterp(info, &si))
|
|
|
|
{
|
|
|
|
info->errorCount++;
|
2012-04-05 18:38:55 -06:00
|
|
|
return false;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
2012-04-05 18:38:55 -06:00
|
|
|
return true;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
HandleGroupCompatDef(GroupCompatDef * def,
|
2012-04-03 08:14:16 -06:00
|
|
|
struct xkb_keymap * xkb, unsigned merge, CompatInfo * info)
|
2009-03-27 07:55:32 -06:00
|
|
|
{
|
|
|
|
ExprResult val;
|
|
|
|
GroupCompatInfo tmp;
|
|
|
|
|
|
|
|
if (def->merge != MergeDefault)
|
|
|
|
merge = def->merge;
|
|
|
|
if (!XkbIsLegalGroup(def->group - 1))
|
|
|
|
{
|
2009-03-31 08:21:20 -06:00
|
|
|
ERROR("Keyboard group must be in the range 1..%d\n",
|
2009-03-27 07:55:32 -06:00
|
|
|
XkbNumKbdGroups + 1);
|
2009-03-31 08:21:20 -06:00
|
|
|
ACTION("Compatibility map for illegal group %d ignored\n",
|
2009-03-27 07:55:32 -06:00
|
|
|
def->group);
|
2012-04-05 18:38:55 -06:00
|
|
|
return false;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
tmp.fileID = info->fileID;
|
|
|
|
tmp.merge = merge;
|
2012-02-20 06:32:09 -07:00
|
|
|
if (!ExprResolveVModMask(def->def, &val, xkb))
|
2009-03-27 07:55:32 -06:00
|
|
|
{
|
|
|
|
ERROR("Expected a modifier mask in group compatibility definition\n");
|
2009-03-31 08:21:20 -06:00
|
|
|
ACTION("Ignoring illegal compatibility map for group %d\n",
|
2009-03-27 07:55:32 -06:00
|
|
|
def->group);
|
2012-04-05 18:38:55 -06:00
|
|
|
return false;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
tmp.real_mods = val.uval & 0xff;
|
|
|
|
tmp.vmods = (val.uval >> 8) & 0xffff;
|
2012-04-05 18:38:55 -06:00
|
|
|
tmp.defined = true;
|
2009-03-27 07:55:32 -06:00
|
|
|
return AddGroupCompat(info, def->group - 1, &tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
HandleCompatMapFile(XkbFile * file,
|
2012-04-03 08:14:16 -06:00
|
|
|
struct xkb_keymap * xkb, unsigned merge, CompatInfo * info)
|
2009-03-27 07:55:32 -06:00
|
|
|
{
|
|
|
|
ParseCommon *stmt;
|
|
|
|
|
|
|
|
if (merge == MergeDefault)
|
|
|
|
merge = MergeAugment;
|
2012-03-01 12:26:25 -07:00
|
|
|
free(info->name);
|
2012-03-23 16:12:08 -06:00
|
|
|
info->name = uDupString(file->name);
|
2009-03-27 07:55:32 -06:00
|
|
|
stmt = file->defs;
|
|
|
|
while (stmt)
|
|
|
|
{
|
|
|
|
switch (stmt->stmtType)
|
|
|
|
{
|
|
|
|
case StmtInclude:
|
|
|
|
if (!HandleIncludeCompatMap((IncludeStmt *) stmt, xkb, info,
|
|
|
|
HandleCompatMapFile))
|
|
|
|
info->errorCount++;
|
|
|
|
break;
|
|
|
|
case StmtInterpDef:
|
|
|
|
if (!HandleInterpDef((InterpDef *) stmt, xkb, merge, info))
|
|
|
|
info->errorCount++;
|
|
|
|
break;
|
|
|
|
case StmtGroupCompatDef:
|
|
|
|
if (!HandleGroupCompatDef
|
|
|
|
((GroupCompatDef *) stmt, xkb, merge, info))
|
|
|
|
info->errorCount++;
|
|
|
|
break;
|
|
|
|
case StmtIndicatorMapDef:
|
|
|
|
{
|
|
|
|
LEDInfo *rtrn;
|
|
|
|
rtrn = HandleIndicatorMapDef((IndicatorMapDef *) stmt, xkb,
|
|
|
|
&info->ledDflt, info->leds, merge);
|
|
|
|
if (rtrn != NULL)
|
|
|
|
info->leds = rtrn;
|
|
|
|
else
|
|
|
|
info->errorCount++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case StmtVarDef:
|
|
|
|
if (!HandleInterpVar((VarDef *) stmt, xkb, info))
|
|
|
|
info->errorCount++;
|
|
|
|
break;
|
|
|
|
case StmtVModDef:
|
2012-02-15 08:58:14 -07:00
|
|
|
if (!HandleVModDef((VModDef *) stmt, xkb, merge, &info->vmods))
|
2009-03-27 07:55:32 -06:00
|
|
|
info->errorCount++;
|
|
|
|
break;
|
|
|
|
case StmtKeycodeDef:
|
|
|
|
ERROR("Interpretation files may not include other types\n");
|
|
|
|
ACTION("Ignoring definition of key name\n");
|
|
|
|
info->errorCount++;
|
|
|
|
break;
|
|
|
|
default:
|
2009-03-31 08:21:20 -06:00
|
|
|
WSGO("Unexpected statement type %d in HandleCompatMapFile\n",
|
2009-03-27 07:55:32 -06:00
|
|
|
stmt->stmtType);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
stmt = stmt->next;
|
|
|
|
if (info->errorCount > 10)
|
|
|
|
{
|
|
|
|
#ifdef NOISY
|
|
|
|
ERROR("Too many errors\n");
|
|
|
|
#endif
|
2009-03-31 08:21:20 -06:00
|
|
|
ACTION("Abandoning compatibility map \"%s\"\n", file->topName);
|
2009-03-27 07:55:32 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
CopyInterps(CompatInfo * info,
|
2012-04-05 18:38:55 -06:00
|
|
|
struct xkb_compat_map * compat, bool needSymbol, unsigned pred)
|
2009-03-27 07:55:32 -06:00
|
|
|
{
|
|
|
|
SymInterpInfo *si;
|
|
|
|
|
|
|
|
for (si = info->interps; si; si = (SymInterpInfo *) si->defs.next)
|
|
|
|
{
|
|
|
|
if (((si->interp.match & XkbSI_OpMask) != pred) ||
|
2012-03-24 05:27:48 -06:00
|
|
|
(needSymbol && (si->interp.sym == XKB_KEYSYM_NO_SYMBOL)) ||
|
|
|
|
((!needSymbol) && (si->interp.sym != XKB_KEYSYM_NO_SYMBOL)))
|
2009-03-27 07:55:32 -06:00
|
|
|
continue;
|
|
|
|
if (compat->num_si >= compat->size_si)
|
|
|
|
{
|
|
|
|
WSGO("No room to merge symbol interpretations\n");
|
|
|
|
ACTION("Symbol interpretations lost\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
compat->sym_interpret[compat->num_si++] = si->interp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-05 18:38:55 -06:00
|
|
|
bool
|
2012-05-07 16:08:07 -06:00
|
|
|
CompileCompatMap(XkbFile *file, struct xkb_keymap *xkb, unsigned merge,
|
2009-03-27 20:54:50 -06:00
|
|
|
LEDInfoPtr *unboundLEDs)
|
2009-03-27 07:55:32 -06:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
CompatInfo info;
|
|
|
|
GroupCompatInfo *gcm;
|
|
|
|
|
|
|
|
InitCompatInfo(&info, xkb);
|
|
|
|
info.dflt.defs.merge = merge;
|
|
|
|
info.ledDflt.defs.merge = merge;
|
2012-05-07 16:08:07 -06:00
|
|
|
|
2009-03-27 07:55:32 -06:00
|
|
|
HandleCompatMapFile(file, xkb, merge, &info);
|
|
|
|
|
2012-05-07 16:08:07 -06:00
|
|
|
if (info.errorCount != 0)
|
|
|
|
goto err_info;
|
|
|
|
|
|
|
|
if (XkbcAllocCompatMap(xkb, info.nInterps) != Success) {
|
|
|
|
WSGO("Couldn't allocate compatibility map\n");
|
|
|
|
goto err_info;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info.nInterps > 0) {
|
|
|
|
CopyInterps(&info, xkb->compat, true, XkbSI_Exactly);
|
|
|
|
CopyInterps(&info, xkb->compat, true, XkbSI_AllOf | XkbSI_NoneOf);
|
|
|
|
CopyInterps(&info, xkb->compat, true, XkbSI_AnyOf);
|
|
|
|
CopyInterps(&info, xkb->compat, true, XkbSI_AnyOfOrNone);
|
|
|
|
CopyInterps(&info, xkb->compat, false, XkbSI_Exactly);
|
|
|
|
CopyInterps(&info, xkb->compat, false, XkbSI_AllOf | XkbSI_NoneOf);
|
|
|
|
CopyInterps(&info, xkb->compat, false, XkbSI_AnyOf);
|
|
|
|
CopyInterps(&info, xkb->compat, false, XkbSI_AnyOfOrNone);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups; i++, gcm++) {
|
|
|
|
if ((gcm->fileID != 0) || (gcm->real_mods != 0) || (gcm->vmods != 0)) {
|
|
|
|
xkb->compat->groups[i].mask = gcm->real_mods;
|
|
|
|
xkb->compat->groups[i].real_mods = gcm->real_mods;
|
|
|
|
xkb->compat->groups[i].vmods = gcm->vmods;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
|
|
|
}
|
2012-05-07 16:08:07 -06:00
|
|
|
|
|
|
|
if (info.leds != NULL) {
|
|
|
|
if (!CopyIndicatorMapDefs(xkb, info.leds, unboundLEDs))
|
|
|
|
info.errorCount++;
|
|
|
|
info.leds = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ClearCompatInfo(&info, xkb);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
err_info:
|
|
|
|
ClearCompatInfo(&info, xkb);
|
2012-04-05 18:38:55 -06:00
|
|
|
return false;
|
2009-03-27 07:55:32 -06:00
|
|
|
}
|
2012-03-14 12:24:37 -06:00
|
|
|
|
|
|
|
static uint32_t
|
2012-04-03 08:14:16 -06:00
|
|
|
VModsToReal(struct xkb_keymap *xkb, uint32_t vmodmask)
|
2012-03-14 12:24:37 -06:00
|
|
|
{
|
|
|
|
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
|
2012-04-03 08:14:16 -06:00
|
|
|
UpdateActionMods(struct xkb_keymap *xkb, union xkb_action *act, uint32_t rmodmask)
|
2012-03-14 12:24:37 -06:00
|
|
|
{
|
|
|
|
switch (act->type) {
|
|
|
|
case XkbSA_SetMods:
|
|
|
|
case XkbSA_LatchMods:
|
|
|
|
case XkbSA_LockMods:
|
2012-03-20 20:17:58 -06:00
|
|
|
if (act->mods.flags & XkbSA_UseModMapMods)
|
2012-03-14 12:24:37 -06:00
|
|
|
act->mods.real_mods = rmodmask;
|
2012-03-20 20:17:58 -06:00
|
|
|
act->mods.mask = act->mods.real_mods;
|
2012-03-16 07:59:24 -06:00
|
|
|
act->mods.mask |= VModsToReal(xkb, act->mods.vmods);
|
2012-03-14 12:24:37 -06:00
|
|
|
break;
|
|
|
|
case XkbSA_ISOLock:
|
2012-03-20 20:17:58 -06:00
|
|
|
if (act->iso.flags & XkbSA_UseModMapMods)
|
2012-03-14 12:24:37 -06:00
|
|
|
act->iso.real_mods = rmodmask;
|
2012-03-20 20:17:58 -06:00
|
|
|
act->iso.mask = act->iso.real_mods;
|
2012-03-16 07:59:24 -06:00
|
|
|
act->iso.mask |= VModsToReal(xkb, act->iso.vmods);
|
2012-03-14 12:24:37 -06:00
|
|
|
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
|
2012-03-24 05:27:48 -06:00
|
|
|
* generic XKB_KEYSYM_NO_SYMBOL match.
|
2012-03-14 12:24:37 -06:00
|
|
|
*/
|
|
|
|
static struct xkb_sym_interpret *
|
2012-04-03 08:14:16 -06:00
|
|
|
FindInterpForKey(struct xkb_keymap *xkb, xkb_keycode_t key, uint32_t group, uint32_t level)
|
2012-03-14 12:24:37 -06:00
|
|
|
{
|
|
|
|
struct xkb_sym_interpret *ret = NULL;
|
2012-04-08 06:40:12 -06:00
|
|
|
const xkb_keysym_t *syms;
|
2012-03-14 12:24:37 -06:00
|
|
|
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;
|
2012-04-05 18:38:55 -06:00
|
|
|
bool found;
|
2012-03-14 12:24:37 -06:00
|
|
|
|
2012-03-29 09:31:09 -06:00
|
|
|
if ((num_syms > 1 || interp->sym != syms[0]) &&
|
2012-03-24 05:27:48 -06:00
|
|
|
interp->sym != XKB_KEYSYM_NO_SYMBOL)
|
2012-03-14 12:24:37 -06:00
|
|
|
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:
|
2012-04-05 18:38:55 -06:00
|
|
|
found = false;
|
2012-03-14 12:24:37 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-03-24 05:27:48 -06:00
|
|
|
if (found && interp->sym != XKB_KEYSYM_NO_SYMBOL)
|
2012-03-14 12:24:37 -06:00
|
|
|
return interp;
|
|
|
|
else if (found && !ret)
|
|
|
|
ret = interp;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*/
|
2012-04-05 18:38:55 -06:00
|
|
|
static bool
|
2012-04-03 08:14:16 -06:00
|
|
|
ApplyInterpsToKey(struct xkb_keymap *xkb, xkb_keycode_t key)
|
2012-03-14 12:24:37 -06:00
|
|
|
{
|
|
|
|
#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)
|
2012-04-05 18:38:55 -06:00
|
|
|
return true;
|
2012-03-14 12:24:37 -06:00
|
|
|
|
|
|
|
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 */
|
2012-04-05 18:38:55 -06:00
|
|
|
return false;
|
2012-03-14 12:24:37 -06:00
|
|
|
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)
|
2012-04-05 18:38:55 -06:00
|
|
|
return true;
|
2012-03-14 12:24:37 -06:00
|
|
|
else if (!acts)
|
2012-04-05 18:38:55 -06:00
|
|
|
return false;
|
2012-03-14 12:24:37 -06:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2012-04-05 18:38:55 -06:00
|
|
|
return true;
|
2012-03-14 12:24:37 -06:00
|
|
|
#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 ...
|
|
|
|
*/
|
2012-04-05 18:38:55 -06:00
|
|
|
bool
|
2012-04-03 08:14:16 -06:00
|
|
|
UpdateModifiersFromCompat(struct xkb_keymap *xkb)
|
2012-03-14 12:24:37 -06:00
|
|
|
{
|
|
|
|
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))
|
2012-04-05 18:38:55 -06:00
|
|
|
return false;
|
2012-03-14 12:24:37 -06:00
|
|
|
|
|
|
|
/* 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. */
|
2012-03-15 02:36:09 -06:00
|
|
|
for (i = 0; i < XkbNumIndicators; i++) {
|
|
|
|
struct xkb_mods *led = &xkb->indicators->maps[i].mods;
|
|
|
|
led->mask = led->real_mods | VModsToReal(xkb, led->vmods);
|
|
|
|
}
|
2012-03-14 12:24:37 -06:00
|
|
|
|
2012-04-05 18:38:55 -06:00
|
|
|
return true;
|
2012-03-14 12:24:37 -06:00
|
|
|
}
|