1922 lines
53 KiB
C
1922 lines
53 KiB
C
|
/* $Xorg: symbols.c,v 1.3 2000/08/17 19:54:33 cpqbld Exp $ */
|
||
|
/************************************************************
|
||
|
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
|
||
|
documentation, and that the name of Silicon Graphics not be
|
||
|
used in advertising or publicity pertaining to distribution
|
||
|
of the software without specific prior written permission.
|
||
|
Silicon Graphics makes no representation about the suitability
|
||
|
of this software for any purpose. It is provided "as is"
|
||
|
without any express or implied warranty.
|
||
|
|
||
|
SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||
|
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||
|
AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
|
||
|
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
|
||
|
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
|
||
|
THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||
|
|
||
|
********************************************************/
|
||
|
/* $XFree86: xc/programs/xkbcomp/symbols.c,v 3.15 2003/04/19 12:25:31 pascal Exp $ */
|
||
|
|
||
|
#include "xkbcomp.h"
|
||
|
#include "tokens.h"
|
||
|
#include "expr.h"
|
||
|
|
||
|
#include <X11/keysym.h>
|
||
|
#include <X11/Xutil.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#include "expr.h"
|
||
|
#include "vmod.h"
|
||
|
#include "action.h"
|
||
|
#include "keycodes.h"
|
||
|
#include "misc.h"
|
||
|
#include "alias.h"
|
||
|
|
||
|
extern Atom tok_ONE_LEVEL;
|
||
|
extern Atom tok_TWO_LEVEL;
|
||
|
extern Atom tok_KEYPAD;
|
||
|
|
||
|
/***====================================================================***/
|
||
|
|
||
|
#define RepeatYes 1
|
||
|
#define RepeatNo 0
|
||
|
#define RepeatUndefined ~((unsigned)0)
|
||
|
|
||
|
#define _Key_Syms (1<<0)
|
||
|
#define _Key_Acts (1<<1)
|
||
|
#define _Key_Repeat (1<<2)
|
||
|
#define _Key_Behavior (1<<3)
|
||
|
#define _Key_Type_Dflt (1<<4)
|
||
|
#define _Key_Types (1<<5)
|
||
|
#define _Key_GroupInfo (1<<6)
|
||
|
#define _Key_VModMap (1<<7)
|
||
|
|
||
|
typedef struct _KeyInfo {
|
||
|
CommonInfo defs;
|
||
|
unsigned long name;
|
||
|
unsigned char groupInfo;
|
||
|
unsigned char typesDefined;
|
||
|
unsigned char symsDefined;
|
||
|
unsigned char actsDefined;
|
||
|
short numLevels[XkbNumKbdGroups];
|
||
|
KeySym * syms[XkbNumKbdGroups];
|
||
|
XkbAction * acts[XkbNumKbdGroups];
|
||
|
Atom types[XkbNumKbdGroups];
|
||
|
unsigned repeat;
|
||
|
XkbBehavior behavior;
|
||
|
unsigned short vmodmap;
|
||
|
unsigned long nameForOverlayKey;
|
||
|
unsigned long allowNone;
|
||
|
Atom dfltType;
|
||
|
} KeyInfo;
|
||
|
|
||
|
static void
|
||
|
InitKeyInfo(KeyInfo *info)
|
||
|
{
|
||
|
register int i;
|
||
|
static char dflt[4]= "*";
|
||
|
|
||
|
info->defs.defined= 0;
|
||
|
info->defs.fileID= 0;
|
||
|
info->defs.merge= MergeOverride;
|
||
|
info->defs.next= NULL;
|
||
|
info->name= KeyNameToLong(dflt);
|
||
|
info->groupInfo= 0;
|
||
|
info->typesDefined= info->symsDefined= info->actsDefined= 0;
|
||
|
for (i=0;i<XkbNumKbdGroups;i++) {
|
||
|
info->numLevels[i]= 0;
|
||
|
info->types[i]= None;
|
||
|
info->syms[i]= NULL;
|
||
|
info->acts[i]= NULL;
|
||
|
}
|
||
|
info->dfltType= None;
|
||
|
info->behavior.type= XkbKB_Default;
|
||
|
info->behavior.data= 0;
|
||
|
info->vmodmap= 0;
|
||
|
info->nameForOverlayKey= 0;
|
||
|
info->repeat= RepeatUndefined;
|
||
|
info->allowNone= 0;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
FreeKeyInfo(KeyInfo *info)
|
||
|
{
|
||
|
register int i;
|
||
|
|
||
|
info->defs.defined= 0;
|
||
|
info->defs.fileID= 0;
|
||
|
info->defs.merge= MergeOverride;
|
||
|
info->defs.next= NULL;
|
||
|
info->groupInfo= 0;
|
||
|
info->typesDefined= info->symsDefined= info->actsDefined= 0;
|
||
|
for (i=0;i<XkbNumKbdGroups;i++) {
|
||
|
info->numLevels[i]= 0;
|
||
|
info->types[i]= None;
|
||
|
if (info->syms[i]!=NULL)
|
||
|
uFree(info->syms[i]);
|
||
|
info->syms[i]= NULL;
|
||
|
if (info->acts[i]!=NULL)
|
||
|
uFree(info->acts[i]);
|
||
|
info->acts[i]= NULL;
|
||
|
}
|
||
|
info->dfltType= None;
|
||
|
info->behavior.type= XkbKB_Default;
|
||
|
info->behavior.data= 0;
|
||
|
info->vmodmap= 0;
|
||
|
info->nameForOverlayKey= 0;
|
||
|
info->repeat= RepeatUndefined;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
CopyKeyInfo(KeyInfo *old,KeyInfo *new,Bool clearOld)
|
||
|
{
|
||
|
register int i;
|
||
|
|
||
|
*new= *old;
|
||
|
new->defs.next= NULL;
|
||
|
if (clearOld) {
|
||
|
for (i=0;i<XkbNumKbdGroups;i++) {
|
||
|
old->numLevels[i]= 0;
|
||
|
old->syms[i]= NULL;
|
||
|
old->acts[i]= NULL;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
int width;
|
||
|
for (i=0;i<XkbNumKbdGroups;i++) {
|
||
|
width= new->numLevels[i];
|
||
|
if (old->syms[i]!=NULL) {
|
||
|
new->syms[i]= uTypedCalloc(width,KeySym);
|
||
|
if (!new->syms[i]) {
|
||
|
new->syms[i]= NULL;
|
||
|
new->numLevels[i]= 0;
|
||
|
return False;
|
||
|
}
|
||
|
memcpy((char *)new->syms[i],(char *)old->syms[i],
|
||
|
width*sizeof(KeySym));
|
||
|
}
|
||
|
if (old->acts[i]!=NULL) {
|
||
|
new->acts[i]= uTypedCalloc(width,XkbAction);
|
||
|
if (!new->acts[i]) {
|
||
|
new->acts[i]= NULL;
|
||
|
return False;
|
||
|
}
|
||
|
memcpy((char *)new->acts[i],(char *)old->acts[i],
|
||
|
width*sizeof(XkbAction));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
/***====================================================================***/
|
||
|
|
||
|
typedef struct _ModMapEntry {
|
||
|
CommonInfo defs;
|
||
|
Bool haveSymbol;
|
||
|
int modifier;
|
||
|
union {
|
||
|
unsigned long keyName;
|
||
|
KeySym keySym;
|
||
|
} u;
|
||
|
} ModMapEntry;
|
||
|
|
||
|
#define SYMBOLS_INIT_SIZE 110
|
||
|
#define SYMBOLS_CHUNK 20
|
||
|
typedef struct _SymbolsInfo {
|
||
|
char * name;
|
||
|
int errorCount;
|
||
|
unsigned fileID;
|
||
|
unsigned merge;
|
||
|
unsigned explicit_group;
|
||
|
unsigned groupInfo;
|
||
|
unsigned szKeys;
|
||
|
unsigned nKeys;
|
||
|
KeyInfo * keys;
|
||
|
KeyInfo dflt;
|
||
|
VModInfo vmods;
|
||
|
ActionInfo * action;
|
||
|
Atom groupNames[XkbNumKbdGroups];
|
||
|
|
||
|
ModMapEntry * modMap;
|
||
|
AliasInfo * aliases;
|
||
|
} SymbolsInfo;
|
||
|
|
||
|
static void
|
||
|
InitSymbolsInfo(SymbolsInfo *info,XkbDescPtr xkb)
|
||
|
{
|
||
|
register int i;
|
||
|
|
||
|
tok_ONE_LEVEL= XkbInternAtom(NULL,"ONE_LEVEL",False);
|
||
|
tok_TWO_LEVEL= XkbInternAtom(NULL,"TWO_LEVEL",False);
|
||
|
tok_KEYPAD= XkbInternAtom(NULL,"KEYPAD",False);
|
||
|
info->name= NULL;
|
||
|
info->explicit_group= 0;
|
||
|
info->errorCount= 0;
|
||
|
info->fileID= 0;
|
||
|
info->merge= MergeOverride;
|
||
|
info->groupInfo= 0;
|
||
|
info->szKeys= SYMBOLS_INIT_SIZE;
|
||
|
info->nKeys= 0;
|
||
|
info->keys= uTypedCalloc(SYMBOLS_INIT_SIZE,KeyInfo);
|
||
|
info->modMap= NULL;
|
||
|
for (i=0;i<XkbNumKbdGroups;i++)
|
||
|
info->groupNames[i]= None;
|
||
|
InitKeyInfo(&info->dflt);
|
||
|
InitVModInfo(&info->vmods,xkb);
|
||
|
info->action= NULL;
|
||
|
info->aliases= NULL;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
FreeSymbolsInfo(SymbolsInfo *info)
|
||
|
{
|
||
|
register int i;
|
||
|
|
||
|
if (info->name)
|
||
|
uFree(info->name);
|
||
|
info->name= NULL;
|
||
|
if (info->keys) {
|
||
|
for (i=0;i<info->nKeys;i++) {
|
||
|
FreeKeyInfo(&info->keys[i]);
|
||
|
}
|
||
|
uFree(info->keys);
|
||
|
info->keys= NULL;
|
||
|
}
|
||
|
if (info->modMap) {
|
||
|
ClearCommonInfo(&info->modMap->defs);
|
||
|
info->modMap= NULL;
|
||
|
}
|
||
|
if (info->aliases) {
|
||
|
ClearAliases(&info->aliases);
|
||
|
info->aliases= NULL;
|
||
|
}
|
||
|
bzero((char *)info,sizeof(SymbolsInfo));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
ResizeKeyGroup( KeyInfo * key,
|
||
|
unsigned group,
|
||
|
unsigned atLeastSize,
|
||
|
Bool forceActions)
|
||
|
{
|
||
|
Bool tooSmall;
|
||
|
unsigned newWidth;
|
||
|
|
||
|
tooSmall= (key->numLevels[group]<atLeastSize);
|
||
|
if (tooSmall) newWidth= atLeastSize;
|
||
|
else newWidth= key->numLevels[group];
|
||
|
|
||
|
if ((key->syms[group]==NULL)||tooSmall) {
|
||
|
key->syms[group]= uTypedRecalloc(key->syms[group],
|
||
|
key->numLevels[group],newWidth,
|
||
|
KeySym);
|
||
|
if (!key->syms[group])
|
||
|
return False;
|
||
|
}
|
||
|
if (((forceActions)&&(tooSmall||(key->acts[group]==NULL)))||
|
||
|
(tooSmall&&(key->acts[group]!=NULL))) {
|
||
|
key->acts[group]= uTypedRecalloc(key->acts[group],
|
||
|
key->numLevels[group],newWidth,
|
||
|
XkbAction);
|
||
|
if (!key->acts[group])
|
||
|
return False;
|
||
|
}
|
||
|
key->numLevels[group]= newWidth;
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
MergeKeyGroups( SymbolsInfo * info,
|
||
|
KeyInfo * into,
|
||
|
KeyInfo * from,
|
||
|
unsigned group)
|
||
|
{
|
||
|
KeySym * resultSyms;
|
||
|
XkbAction * resultActs;
|
||
|
int resultWidth;
|
||
|
register int i;
|
||
|
Bool report,clobber;
|
||
|
|
||
|
clobber= (from->defs.merge!=MergeAugment);
|
||
|
report= (warningLevel>9)||
|
||
|
((into->defs.fileID==from->defs.fileID)&&(warningLevel>0));
|
||
|
if (into->numLevels[group]>=from->numLevels[group]) {
|
||
|
resultSyms= into->syms[group];
|
||
|
resultActs= into->acts[group];
|
||
|
resultWidth= into->numLevels[group];
|
||
|
}
|
||
|
else {
|
||
|
resultSyms= from->syms[group];
|
||
|
resultActs= from->acts[group];
|
||
|
resultWidth= from->numLevels[group];
|
||
|
}
|
||
|
if (resultSyms==NULL) {
|
||
|
resultSyms= uTypedCalloc(resultWidth,KeySym);
|
||
|
if (!resultSyms) {
|
||
|
WSGO("Could not allocate symbols for group merge\n");
|
||
|
ACTION2("Group %d of key %s not merged\n",group,
|
||
|
longText(into->name,XkbMessage));
|
||
|
return False;
|
||
|
}
|
||
|
}
|
||
|
if ((resultActs==NULL)&&(into->acts[group]||from->acts[group])) {
|
||
|
resultActs= uTypedCalloc(resultWidth,XkbAction);
|
||
|
if (!resultActs) {
|
||
|
WSGO("Could not allocate actions for group merge\n");
|
||
|
ACTION2("Group %d of key %s not merged\n",group,
|
||
|
longText(into->name,XkbMessage));
|
||
|
return False;
|
||
|
}
|
||
|
}
|
||
|
for (i=0;i<resultWidth;i++) {
|
||
|
KeySym fromSym,toSym;
|
||
|
if (from->syms[group] && (i<from->numLevels[group]))
|
||
|
fromSym= from->syms[group][i];
|
||
|
else fromSym= NoSymbol;
|
||
|
if (into->syms[group] && (i<into->numLevels[group]))
|
||
|
toSym= into->syms[group][i];
|
||
|
else toSym= NoSymbol;
|
||
|
if ((fromSym==NoSymbol)||(fromSym==toSym))
|
||
|
resultSyms[i]= toSym;
|
||
|
else if (toSym==NoSymbol)
|
||
|
resultSyms[i]= fromSym;
|
||
|
else {
|
||
|
KeySym use,ignore;
|
||
|
if (clobber) { use= fromSym; ignore= toSym; }
|
||
|
else { use= toSym; ignore= fromSym; }
|
||
|
if (report) {
|
||
|
WARN3("Multiple symbols for level %d/group %d on key %s\n",
|
||
|
i+1,group+1,longText(into->name,XkbMessage));
|
||
|
ACTION2("Using %s, ignoring %s\n",XkbKeysymText(use,XkbMessage),
|
||
|
XkbKeysymText(ignore,XkbMessage));
|
||
|
}
|
||
|
resultSyms[i]= use;
|
||
|
}
|
||
|
if (resultActs!=NULL) {
|
||
|
XkbAction *fromAct,*toAct;
|
||
|
fromAct= (from->acts[group]?&from->acts[group][i]:NULL);
|
||
|
toAct= (into->acts[group]?&into->acts[group][i]:NULL);
|
||
|
if (((fromAct==NULL)||(fromAct->type==XkbSA_NoAction))&&
|
||
|
(toAct!=NULL)) {
|
||
|
resultActs[i]= *toAct;
|
||
|
}
|
||
|
else if (((toAct==NULL)||(toAct->type==XkbSA_NoAction))&&
|
||
|
(fromAct!=NULL)) {
|
||
|
resultActs[i]= *fromAct;
|
||
|
}
|
||
|
else {
|
||
|
XkbAction *use,*ignore;
|
||
|
if (clobber) { use= fromAct; ignore= toAct; }
|
||
|
else { use= toAct; ignore= fromAct; }
|
||
|
if (report) {
|
||
|
WARN3("Multiple actions for level %d/group %d on key %s\n",
|
||
|
i+1,group+1,longText(into->name,XkbMessage));
|
||
|
ACTION2("Using %s, ignoring %s\n",
|
||
|
XkbActionTypeText(use->type,XkbMessage),
|
||
|
XkbActionTypeText(ignore->type,XkbMessage));
|
||
|
}
|
||
|
resultActs[i]= *use;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if ((into->syms[group]!=NULL)&&(resultSyms!=into->syms[group]))
|
||
|
uFree(into->syms[group]);
|
||
|
if ((from->syms[group]!=NULL)&&(resultSyms!=from->syms[group]))
|
||
|
uFree(from->syms[group]);
|
||
|
if ((into->acts[group]!=NULL)&&(resultActs!=into->acts[group]))
|
||
|
uFree(into->acts[group]);
|
||
|
if ((from->acts[group]!=NULL)&&(resultActs!=from->acts[group]))
|
||
|
uFree(from->acts[group]);
|
||
|
into->numLevels[group]= resultWidth;
|
||
|
into->syms[group]= resultSyms;
|
||
|
from->syms[group]= NULL;
|
||
|
into->acts[group]= resultActs;
|
||
|
from->acts[group]= NULL;
|
||
|
into->symsDefined|= (1<<group);
|
||
|
from->symsDefined&= ~(1<<group);
|
||
|
into->actsDefined|= (1<<group);
|
||
|
from->actsDefined&= ~(1<<group);
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
MergeKeys(SymbolsInfo *info,KeyInfo *into,KeyInfo *from)
|
||
|
{
|
||
|
register int i;
|
||
|
unsigned collide= 0;
|
||
|
Bool report;
|
||
|
|
||
|
if (from->defs.merge==MergeReplace) {
|
||
|
for (i=0;i<XkbNumKbdGroups;i++) {
|
||
|
if (into->numLevels[i]!=0) {
|
||
|
if (into->syms[i])
|
||
|
uFree(into->syms[i]);
|
||
|
if (into->acts[i])
|
||
|
uFree(into->acts[i]);
|
||
|
}
|
||
|
}
|
||
|
*into= *from;
|
||
|
bzero(from,sizeof(KeyInfo));
|
||
|
return True;
|
||
|
}
|
||
|
report= ((warningLevel>9)||
|
||
|
((into->defs.fileID==from->defs.fileID)&&(warningLevel>0)));
|
||
|
for (i=0;i<XkbNumKbdGroups;i++) {
|
||
|
if (from->numLevels[i]>0) {
|
||
|
if (into->numLevels[i]==0) {
|
||
|
into->numLevels[i]= from->numLevels[i];
|
||
|
into->syms[i]= from->syms[i];
|
||
|
into->acts[i]= from->acts[i];
|
||
|
into->symsDefined|= (1<<i);
|
||
|
from->syms[i]= NULL;
|
||
|
from->acts[i]= NULL;
|
||
|
from->numLevels[i]= 0;
|
||
|
from->symsDefined&= ~(1<<i);
|
||
|
if (into->syms[i]) into->defs.defined|= _Key_Syms;
|
||
|
if (into->acts[i]) into->defs.defined|= _Key_Acts;
|
||
|
}
|
||
|
else {
|
||
|
if (report) {
|
||
|
if (into->syms[i]) collide|= _Key_Syms;
|
||
|
if (into->acts[i]) collide|= _Key_Acts;
|
||
|
}
|
||
|
MergeKeyGroups(info,into,from,(unsigned)i);
|
||
|
}
|
||
|
}
|
||
|
if (from->types[i]!=None) {
|
||
|
if ((into->types[i]!=None)&&(report)&&
|
||
|
(into->types[i]!=from->types[i])) {
|
||
|
Atom use,ignore;
|
||
|
collide|= _Key_Types;
|
||
|
if (from->defs.merge!=MergeAugment) {
|
||
|
use= from->types[i];
|
||
|
ignore= into->types[i];
|
||
|
}
|
||
|
else {
|
||
|
use= into->types[i];
|
||
|
ignore= from->types[i];
|
||
|
}
|
||
|
WARN2("Multiple definitions for group %d type of key %s\n",
|
||
|
i,longText(into->name,XkbMessage));
|
||
|
ACTION2("Using %s, ignoring %s\n",
|
||
|
XkbAtomText(NULL,use,XkbMessage),
|
||
|
XkbAtomText(NULL,ignore,XkbMessage));
|
||
|
}
|
||
|
if ((from->defs.merge!=MergeAugment)||(into->types[i]==None)) {
|
||
|
into->types[i]= from->types[i];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (UseNewField(_Key_Behavior,&into->defs,&from->defs,&collide)) {
|
||
|
into->behavior= from->behavior;
|
||
|
into->nameForOverlayKey= from->nameForOverlayKey;
|
||
|
into->defs.defined|= _Key_Behavior;
|
||
|
}
|
||
|
if (UseNewField(_Key_VModMap,&into->defs,&from->defs,&collide)) {
|
||
|
into->vmodmap= from->vmodmap;
|
||
|
into->defs.defined|= _Key_VModMap;
|
||
|
}
|
||
|
if (UseNewField(_Key_Repeat,&into->defs,&from->defs,&collide)) {
|
||
|
into->repeat= from->repeat;
|
||
|
into->defs.defined|= _Key_Repeat;
|
||
|
}
|
||
|
if (UseNewField(_Key_Type_Dflt,&into->defs,&from->defs,&collide)) {
|
||
|
into->dfltType= from->dfltType;
|
||
|
into->defs.defined|= _Key_Type_Dflt;
|
||
|
}
|
||
|
if (UseNewField(_Key_GroupInfo,&into->defs,&from->defs,&collide)) {
|
||
|
into->groupInfo= from->groupInfo;
|
||
|
into->defs.defined|= _Key_GroupInfo;
|
||
|
}
|
||
|
if ( collide ) {
|
||
|
WARN1("Symbol map for key %s redefined\n",
|
||
|
longText(into->name,XkbMessage));
|
||
|
ACTION1("Using %s definition for conflicting fields\n",
|
||
|
(from->defs.merge==MergeAugment?"first":"last"));
|
||
|
}
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
AddKeySymbols(SymbolsInfo *info,KeyInfo *key,XkbDescPtr xkb)
|
||
|
{
|
||
|
register int i;
|
||
|
unsigned long real_name;
|
||
|
|
||
|
for (i=0;i<info->nKeys;i++) {
|
||
|
if (info->keys[i].name==key->name)
|
||
|
return MergeKeys(info,&info->keys[i],key);
|
||
|
}
|
||
|
if(FindKeyNameForAlias(xkb, key->name, &real_name)) {
|
||
|
for (i=0;i<info->nKeys;i++) {
|
||
|
if (info->keys[i].name==real_name)
|
||
|
return MergeKeys(info,&info->keys[i],key);
|
||
|
}
|
||
|
}
|
||
|
if (info->nKeys>=info->szKeys) {
|
||
|
info->szKeys+= SYMBOLS_CHUNK;
|
||
|
info->keys= uTypedRecalloc(info->keys,info->nKeys,info->szKeys,KeyInfo);
|
||
|
if (!info->keys) {
|
||
|
WSGO("Could not allocate key symbols descriptions\n");
|
||
|
ACTION("Some key symbols definitions may be lost\n");
|
||
|
return False;
|
||
|
}
|
||
|
}
|
||
|
return CopyKeyInfo(key,&info->keys[info->nKeys++],True);
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
AddModMapEntry(SymbolsInfo *info,ModMapEntry *new)
|
||
|
{
|
||
|
ModMapEntry * mm;
|
||
|
Bool clobber;
|
||
|
|
||
|
clobber= (new->defs.merge!=MergeAugment);
|
||
|
for (mm=info->modMap;mm!=NULL;mm= (ModMapEntry *)mm->defs.next) {
|
||
|
if (new->haveSymbol&&mm->haveSymbol&&(new->u.keySym==mm->u.keySym)) {
|
||
|
unsigned use,ignore;
|
||
|
if (mm->modifier!=new->modifier) {
|
||
|
if (clobber) {
|
||
|
use= new->modifier;
|
||
|
ignore= mm->modifier;
|
||
|
}
|
||
|
else {
|
||
|
use= mm->modifier;
|
||
|
ignore= new->modifier;
|
||
|
}
|
||
|
ERROR1("%s added to symbol map for multiple modifiers\n",
|
||
|
XkbKeysymText(new->u.keySym,XkbMessage));
|
||
|
ACTION2("Using %s, ignoring %s.\n",
|
||
|
XkbModIndexText(use,XkbMessage),
|
||
|
XkbModIndexText(ignore,XkbMessage));
|
||
|
mm->modifier= use;
|
||
|
}
|
||
|
return True;
|
||
|
}
|
||
|
if ((!new->haveSymbol)&&(!mm->haveSymbol)&&
|
||
|
(new->u.keyName==mm->u.keyName)) {
|
||
|
unsigned use,ignore;
|
||
|
if (mm->modifier!=new->modifier) {
|
||
|
if (clobber) {
|
||
|
use= new->modifier;
|
||
|
ignore= mm->modifier;
|
||
|
}
|
||
|
else {
|
||
|
use= mm->modifier;
|
||
|
ignore= new->modifier;
|
||
|
}
|
||
|
ERROR1("Key %s added to map for multiple modifiers\n",
|
||
|
longText(new->u.keyName,XkbMessage));
|
||
|
ACTION2("Using %s, ignoring %s.\n",
|
||
|
XkbModIndexText(use,XkbMessage),
|
||
|
XkbModIndexText(ignore,XkbMessage));
|
||
|
mm->modifier= use;
|
||
|
}
|
||
|
return True;
|
||
|
}
|
||
|
}
|
||
|
mm= uTypedAlloc(ModMapEntry);
|
||
|
if (mm==NULL) {
|
||
|
WSGO("Could not allocate modifier map entry\n");
|
||
|
ACTION1("Modifier map for %s will be incomplete\n",
|
||
|
XkbModIndexText(new->modifier,XkbMessage));
|
||
|
return False;
|
||
|
}
|
||
|
*mm= *new;
|
||
|
mm->defs.next= &info->modMap->defs;
|
||
|
info->modMap= mm;
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
/***====================================================================***/
|
||
|
|
||
|
static void
|
||
|
MergeIncludedSymbols(SymbolsInfo *into,SymbolsInfo *from,
|
||
|
unsigned merge,XkbDescPtr xkb)
|
||
|
{
|
||
|
register int i;
|
||
|
KeyInfo * key;
|
||
|
|
||
|
if (from->errorCount>0) {
|
||
|
into->errorCount+= from->errorCount;
|
||
|
return;
|
||
|
}
|
||
|
if (into->name==NULL) {
|
||
|
into->name= from->name;
|
||
|
from->name= NULL;
|
||
|
}
|
||
|
for (i=0;i<XkbNumKbdGroups;i++) {
|
||
|
if (from->groupNames[i]!=None) {
|
||
|
if ((merge!=MergeAugment)||(into->groupNames[i]==None))
|
||
|
into->groupNames[i]= from->groupNames[i];
|
||
|
}
|
||
|
}
|
||
|
for (i=0,key=from->keys;i<from->nKeys;i++,key++) {
|
||
|
if (merge!=MergeDefault)
|
||
|
key->defs.merge= merge;
|
||
|
if (!AddKeySymbols(into,key,xkb))
|
||
|
into->errorCount++;
|
||
|
}
|
||
|
if (from->modMap!=NULL) {
|
||
|
ModMapEntry *mm,*next;
|
||
|
for (mm=from->modMap;mm!=NULL;mm=next) {
|
||
|
if (merge!=MergeDefault)
|
||
|
mm->defs.merge= merge;
|
||
|
if (!AddModMapEntry(into,mm))
|
||
|
into->errorCount++;
|
||
|
next= (ModMapEntry *)mm->defs.next;
|
||
|
uFree(mm);
|
||
|
}
|
||
|
from->modMap= NULL;
|
||
|
}
|
||
|
if (!MergeAliases(&into->aliases,&from->aliases,merge))
|
||
|
into->errorCount++;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
typedef void (*FileHandler)(
|
||
|
XkbFile * /* rtrn */,
|
||
|
XkbDescPtr /* xkb */,
|
||
|
unsigned /* merge */,
|
||
|
SymbolsInfo * /* included */
|
||
|
);
|
||
|
|
||
|
static Bool
|
||
|
HandleIncludeSymbols( IncludeStmt * stmt,
|
||
|
XkbDescPtr xkb,
|
||
|
SymbolsInfo * info,
|
||
|
FileHandler hndlr)
|
||
|
{
|
||
|
unsigned newMerge;
|
||
|
XkbFile * rtrn;
|
||
|
SymbolsInfo included;
|
||
|
Bool haveSelf;
|
||
|
|
||
|
haveSelf= False;
|
||
|
if ((stmt->file==NULL)&&(stmt->map==NULL)) {
|
||
|
haveSelf= True;
|
||
|
included= *info;
|
||
|
bzero(info,sizeof(SymbolsInfo));
|
||
|
}
|
||
|
else if (ProcessIncludeFile(stmt,XkmSymbolsIndex,&rtrn,&newMerge)) {
|
||
|
InitSymbolsInfo(&included,xkb);
|
||
|
included.fileID= included.dflt.defs.fileID= rtrn->id;
|
||
|
included.merge= included.dflt.defs.merge= MergeOverride;
|
||
|
if (stmt->modifier) {
|
||
|
included.explicit_group= atoi(stmt->modifier) - 1;
|
||
|
} else {
|
||
|
included.explicit_group= info->explicit_group;
|
||
|
}
|
||
|
(*hndlr)(rtrn,xkb,MergeOverride,&included);
|
||
|
if (stmt->stmt!=NULL) {
|
||
|
if (included.name!=NULL)
|
||
|
uFree(included.name);
|
||
|
included.name= stmt->stmt;
|
||
|
stmt->stmt= NULL;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
info->errorCount+= 10;
|
||
|
return False;
|
||
|
}
|
||
|
if ((stmt->next!=NULL)&&(included.errorCount<1)) {
|
||
|
IncludeStmt * next;
|
||
|
unsigned op;
|
||
|
SymbolsInfo next_incl;
|
||
|
|
||
|
for (next=stmt->next;next!=NULL;next=next->next) {
|
||
|
if ((next->file==NULL)&&(next->map==NULL)) {
|
||
|
haveSelf= True;
|
||
|
MergeIncludedSymbols(&included,info,next->merge,xkb);
|
||
|
FreeSymbolsInfo(info);
|
||
|
}
|
||
|
else if (ProcessIncludeFile(next,XkmSymbolsIndex,&rtrn,&op)) {
|
||
|
InitSymbolsInfo(&next_incl,xkb);
|
||
|
next_incl.fileID= next_incl.dflt.defs.fileID= rtrn->id;
|
||
|
next_incl.merge= next_incl.dflt.defs.merge= MergeOverride;
|
||
|
if (next->modifier) {
|
||
|
next_incl.explicit_group= atoi(next->modifier) - 1;
|
||
|
} else {
|
||
|
next_incl.explicit_group= info->explicit_group;
|
||
|
}
|
||
|
(*hndlr)(rtrn,xkb,MergeOverride,&next_incl);
|
||
|
MergeIncludedSymbols(&included,&next_incl,op,xkb);
|
||
|
FreeSymbolsInfo(&next_incl);
|
||
|
}
|
||
|
else {
|
||
|
info->errorCount+= 10;
|
||
|
return False;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (haveSelf)
|
||
|
*info= included;
|
||
|
else {
|
||
|
MergeIncludedSymbols(info,&included,newMerge,xkb);
|
||
|
FreeSymbolsInfo(&included);
|
||
|
}
|
||
|
return (info->errorCount==0);
|
||
|
}
|
||
|
|
||
|
static LookupEntry groupNames[]= {
|
||
|
{ "group1", 1 },
|
||
|
{ "group2", 2 },
|
||
|
{ "group3", 3 },
|
||
|
{ "group4", 4 },
|
||
|
{ "group5", 5 },
|
||
|
{ "group6", 6 },
|
||
|
{ "group7", 7 },
|
||
|
{ "group8", 8 },
|
||
|
{ NULL, 0 }
|
||
|
};
|
||
|
|
||
|
|
||
|
#define SYMBOLS 1
|
||
|
#define ACTIONS 2
|
||
|
|
||
|
static Bool
|
||
|
GetGroupIndex( KeyInfo * key,
|
||
|
ExprDef * arrayNdx,
|
||
|
unsigned what,
|
||
|
unsigned * ndx_rtrn)
|
||
|
{
|
||
|
char * name;
|
||
|
ExprResult tmp;
|
||
|
|
||
|
if (what==SYMBOLS) name= "symbols";
|
||
|
else name= "actions";
|
||
|
|
||
|
if (arrayNdx==NULL) {
|
||
|
register int i;
|
||
|
unsigned defined;
|
||
|
if (what==SYMBOLS) defined= key->symsDefined;
|
||
|
else defined= key->actsDefined;
|
||
|
|
||
|
for (i=0;i<XkbNumKbdGroups;i++) {
|
||
|
if ((defined&(1<<i))==0) {
|
||
|
*ndx_rtrn= i;
|
||
|
return True;
|
||
|
}
|
||
|
}
|
||
|
ERROR3("Too many groups of %s for key %s (max %d)\n",name,
|
||
|
longText(key->name,XkbMessage),
|
||
|
XkbNumKbdGroups+1);
|
||
|
ACTION1("Ignoring %s defined for extra groups\n",name);
|
||
|
return False;
|
||
|
}
|
||
|
if (!ExprResolveInteger(arrayNdx,&tmp,SimpleLookup,(XPointer)groupNames)) {
|
||
|
ERROR2("Illegal group index for %s of key %s\n",name,
|
||
|
longText(key->name,XkbMessage));
|
||
|
ACTION("Definition with non-integer array index ignored\n");
|
||
|
return False;
|
||
|
}
|
||
|
if ((tmp.uval<1)||(tmp.uval>XkbNumKbdGroups)) {
|
||
|
ERROR3("Group index for %s of key %s is out of range (1..%d)\n",name,
|
||
|
longText(key->name,XkbMessage),
|
||
|
XkbNumKbdGroups+1);
|
||
|
ACTION2("Ignoring %s for group %d\n",name,tmp.uval);
|
||
|
return False;
|
||
|
}
|
||
|
*ndx_rtrn= tmp.uval-1;
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
AddSymbolsToKey( KeyInfo * key,
|
||
|
XkbDescPtr xkb,
|
||
|
char * field,
|
||
|
ExprDef * arrayNdx,
|
||
|
ExprDef * value,
|
||
|
SymbolsInfo * info)
|
||
|
{
|
||
|
unsigned ndx,nSyms;
|
||
|
int i;
|
||
|
|
||
|
if (!GetGroupIndex(key,arrayNdx,SYMBOLS,&ndx))
|
||
|
return False;
|
||
|
if (value==NULL) {
|
||
|
key->symsDefined|= (1<<ndx);
|
||
|
return True;
|
||
|
}
|
||
|
if (value->op!=ExprKeysymList) {
|
||
|
ERROR1("Expected a list of symbols, found %s\n",exprOpText(value->op));
|
||
|
ACTION2("Ignoring symbols for group %d of %s\n",ndx,
|
||
|
longText(key->name,XkbMessage));
|
||
|
return False;
|
||
|
}
|
||
|
if (key->syms[ndx]!=NULL) {
|
||
|
WSGO2("Symbols for key %s, group %d already defined\n",
|
||
|
longText(key->name,XkbMessage),
|
||
|
ndx);
|
||
|
return False;
|
||
|
}
|
||
|
nSyms= value->value.list.nSyms;
|
||
|
if (((key->numLevels[ndx]<nSyms)||(key->syms[ndx]==NULL))&&
|
||
|
(!ResizeKeyGroup(key,ndx,nSyms,False))) {
|
||
|
WSGO2("Could not resize group %d of key %s\n",ndx,
|
||
|
longText(key->name,XkbMessage));
|
||
|
ACTION("Symbols lost\n");
|
||
|
return False;
|
||
|
}
|
||
|
key->symsDefined|= (1<<ndx);
|
||
|
memcpy((char *)key->syms[ndx],(char *)value->value.list.syms,
|
||
|
nSyms*sizeof(KeySym));
|
||
|
for (i=key->numLevels[ndx]-1;(i>=0)&&(key->syms[ndx][i]==NoSymbol);i--) {
|
||
|
key->numLevels[ndx]--;
|
||
|
}
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
AddActionsToKey( KeyInfo * key,
|
||
|
XkbDescPtr xkb,
|
||
|
char * field,
|
||
|
ExprDef * arrayNdx,
|
||
|
ExprDef * value,
|
||
|
SymbolsInfo * info)
|
||
|
{
|
||
|
register int i;
|
||
|
unsigned ndx,nActs;
|
||
|
ExprDef * act;
|
||
|
XkbAnyAction * toAct;
|
||
|
|
||
|
if (!GetGroupIndex(key,arrayNdx,ACTIONS,&ndx))
|
||
|
return False;
|
||
|
|
||
|
if (value==NULL) {
|
||
|
key->actsDefined|= (1<<ndx);
|
||
|
return True;
|
||
|
}
|
||
|
if (value->op!=ExprActionList) {
|
||
|
WSGO1("Bad expression type (%d) for action list value\n",value->op);
|
||
|
ACTION2("Ignoring actions for group %d of %s\n",ndx,
|
||
|
longText(key->name,XkbMessage));
|
||
|
return False;
|
||
|
}
|
||
|
if (key->acts[ndx]!=NULL) {
|
||
|
WSGO2("Actions for key %s, group %d already defined\n",
|
||
|
longText(key->name,XkbMessage),
|
||
|
ndx);
|
||
|
return False;
|
||
|
}
|
||
|
for (nActs=0,act= value->value.child;act!=NULL;nActs++) {
|
||
|
act= (ExprDef *)act->common.next;
|
||
|
}
|
||
|
if (nActs<1) {
|
||
|
WSGO("Action list but not actions in AddActionsToKey\n");
|
||
|
return False;
|
||
|
}
|
||
|
if (((key->numLevels[ndx]<nActs)||(key->acts[ndx]==NULL))&&
|
||
|
(!ResizeKeyGroup(key,ndx,nActs,True))) {
|
||
|
WSGO2("Could not resize group %d of key %s\n",ndx,
|
||
|
longText(key->name,XkbMessage));
|
||
|
ACTION("Actions lost\n");
|
||
|
return False;
|
||
|
}
|
||
|
key->actsDefined|= (1<<ndx);
|
||
|
|
||
|
toAct= (XkbAnyAction *)key->acts[ndx];
|
||
|
act= value->value.child;
|
||
|
for (i=0;i<nActs;i++,toAct++) {
|
||
|
if (!HandleActionDef(act,xkb,toAct,MergeOverride,info->action)) {
|
||
|
ERROR1("Illegal action definition for %s\n",
|
||
|
longText(key->name,XkbMessage));
|
||
|
ACTION2("Action for group %d/level %d ignored\n",ndx+1,i+1);
|
||
|
}
|
||
|
act= (ExprDef *)act->common.next;
|
||
|
}
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
SetAllowNone(KeyInfo *key,ExprDef *arrayNdx,ExprDef *value)
|
||
|
{
|
||
|
ExprResult tmp;
|
||
|
unsigned radio_groups= 0;
|
||
|
|
||
|
if (arrayNdx==NULL) {
|
||
|
radio_groups= XkbAllRadioGroupsMask;
|
||
|
}
|
||
|
else {
|
||
|
if (!ExprResolveInteger(arrayNdx,&tmp,RadioLookup,NULL)){
|
||
|
ERROR("Illegal index in group name definition\n");
|
||
|
ACTION("Definition with non-integer array index ignored\n");
|
||
|
return False;
|
||
|
}
|
||
|
if ((tmp.uval<1)||(tmp.uval>XkbMaxRadioGroups)) {
|
||
|
ERROR1("Illegal radio group specified (must be 1..%d)\n",
|
||
|
XkbMaxRadioGroups+1);
|
||
|
ACTION1("Value of \"allow none\" for group %d ignored\n",tmp.uval);
|
||
|
return False;
|
||
|
}
|
||
|
radio_groups|= (1<<(tmp.uval-1));
|
||
|
}
|
||
|
if (!ExprResolveBoolean(value,&tmp,NULL,NULL)) {
|
||
|
ERROR1("Illegal \"allow none\" value for %s\n",
|
||
|
longText(key->name,XkbMessage));
|
||
|
ACTION("Non-boolean value ignored\n");
|
||
|
return False;
|
||
|
}
|
||
|
if (tmp.uval) key->allowNone|= radio_groups;
|
||
|
else key->allowNone&= ~radio_groups;
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
|
||
|
static LookupEntry lockingEntries[] = {
|
||
|
{ "true", XkbKB_Lock },
|
||
|
{ "yes", XkbKB_Lock },
|
||
|
{ "on", XkbKB_Lock },
|
||
|
{ "false", XkbKB_Default },
|
||
|
{ "no", XkbKB_Default },
|
||
|
{ "off", XkbKB_Default },
|
||
|
{ "permanent", XkbKB_Lock|XkbKB_Permanent },
|
||
|
{ NULL, 0 }
|
||
|
};
|
||
|
|
||
|
static LookupEntry repeatEntries[]= {
|
||
|
{ "true", RepeatYes },
|
||
|
{ "yes", RepeatYes },
|
||
|
{ "on", RepeatYes },
|
||
|
{ "false", RepeatNo },
|
||
|
{ "no", RepeatNo },
|
||
|
{ "off", RepeatNo },
|
||
|
{ "default", RepeatUndefined },
|
||
|
{ NULL, 0 }
|
||
|
};
|
||
|
|
||
|
static LookupEntry rgEntries[]= {
|
||
|
{ "none", 0 },
|
||
|
{ NULL, 0 }
|
||
|
};
|
||
|
|
||
|
static Bool
|
||
|
SetSymbolsField( KeyInfo * key,
|
||
|
XkbDescPtr xkb,
|
||
|
char * field,
|
||
|
ExprDef * arrayNdx,
|
||
|
ExprDef * value,
|
||
|
SymbolsInfo * info)
|
||
|
{
|
||
|
Bool ok= True;
|
||
|
ExprResult tmp;
|
||
|
|
||
|
if (uStrCaseCmp(field,"type")==0) {
|
||
|
ExprResult ndx;
|
||
|
if ((!ExprResolveString(value,&tmp,NULL,NULL))&&(warningLevel>0)) {
|
||
|
WARN("The type field of a key symbol map must be a string\n");
|
||
|
ACTION("Ignoring illegal type definition\n");
|
||
|
}
|
||
|
if (arrayNdx==NULL) {
|
||
|
key->dfltType= XkbInternAtom(NULL,tmp.str,False);
|
||
|
key->defs.defined|= _Key_Type_Dflt;
|
||
|
}
|
||
|
else if (!ExprResolveInteger(arrayNdx,&ndx,SimpleLookup,
|
||
|
(XPointer)groupNames)) {
|
||
|
ERROR1("Illegal group index for type of key %s\n",
|
||
|
longText(key->name,XkbMessage));
|
||
|
ACTION("Definition with non-integer array index ignored\n");
|
||
|
return False;
|
||
|
}
|
||
|
else if ((ndx.uval<1)||(ndx.uval>XkbNumKbdGroups)) {
|
||
|
ERROR2("Group index for type of key %s is out of range (1..%d)\n",
|
||
|
longText(key->name,XkbMessage),
|
||
|
XkbNumKbdGroups+1);
|
||
|
ACTION1("Ignoring type for group %d\n",ndx.uval);
|
||
|
return False;
|
||
|
}
|
||
|
else {
|
||
|
key->types[ndx.uval-1]= XkbInternAtom(NULL,tmp.str,False);
|
||
|
key->typesDefined|= (1<<(ndx.uval-1));
|
||
|
}
|
||
|
}
|
||
|
else if (uStrCaseCmp(field,"symbols")==0)
|
||
|
return AddSymbolsToKey(key,xkb,field,arrayNdx,value,info);
|
||
|
else if (uStrCaseCmp(field,"actions")==0)
|
||
|
return AddActionsToKey(key,xkb,field,arrayNdx,value,info);
|
||
|
else if ((uStrCaseCmp(field,"vmods")==0)||
|
||
|
(uStrCaseCmp(field,"virtualmods")==0)||
|
||
|
(uStrCaseCmp(field,"virtualmodifiers")==0)) {
|
||
|
ok= ExprResolveModMask(value,&tmp,LookupVModMask,(XPointer)xkb);
|
||
|
if (ok) {
|
||
|
key->vmodmap= (tmp.uval>>8);
|
||
|
key->defs.defined|= _Key_VModMap;
|
||
|
}
|
||
|
else {
|
||
|
ERROR1("Expected a virtual modifier mask, found %s\n",
|
||
|
exprOpText(value->op));
|
||
|
ACTION1("Ignoring virtual modifiers definition for key %s\n",
|
||
|
longText(key->name,XkbMessage));
|
||
|
}
|
||
|
}
|
||
|
else if ((uStrCaseCmp(field,"locking")==0)||(uStrCaseCmp(field,"lock")==0)||
|
||
|
(uStrCaseCmp(field,"locks")==0)) {
|
||
|
ok= ExprResolveEnum(value,&tmp,lockingEntries);
|
||
|
if (ok)
|
||
|
key->behavior.type= tmp.uval;
|
||
|
key->defs.defined|= _Key_Behavior;
|
||
|
}
|
||
|
else if ((uStrCaseCmp(field,"radiogroup")==0)||
|
||
|
(uStrCaseCmp(field,"permanentradiogroup")==0)) {
|
||
|
Bool permanent= False;
|
||
|
if (uStrCaseCmp(field,"permanentradiogroup")==0)
|
||
|
permanent= True;
|
||
|
ok= ExprResolveInteger(value,&tmp,SimpleLookup,(XPointer)rgEntries);
|
||
|
if (!ok) {
|
||
|
ERROR1("Illegal radio group specification for %s\n",
|
||
|
longText(key->name,XkbMessage));
|
||
|
ACTION("Non-integer radio group ignored\n");
|
||
|
return False;
|
||
|
}
|
||
|
if (tmp.uval==0) {
|
||
|
key->behavior.type= XkbKB_Default;
|
||
|
key->behavior.data= 0;
|
||
|
return ok;
|
||
|
}
|
||
|
if ((tmp.uval<1)||(tmp.uval>XkbMaxRadioGroups)) {
|
||
|
ERROR1("Radio group specification for %s out of range (1..32)\n",
|
||
|
longText(key->name,XkbMessage));
|
||
|
ACTION1("Illegal radio group %d ignored\n",tmp.uval);
|
||
|
return False;
|
||
|
}
|
||
|
key->behavior.type= XkbKB_RadioGroup|(permanent?XkbKB_Permanent:0);
|
||
|
key->behavior.data= tmp.uval-1;
|
||
|
if (key->allowNone&(1<<(tmp.uval-1)))
|
||
|
key->behavior.data|= XkbKB_RGAllowNone;
|
||
|
key->defs.defined|= _Key_Behavior;
|
||
|
}
|
||
|
else if (uStrCaseEqual(field,"allownone")) {
|
||
|
ok= SetAllowNone(key,arrayNdx,value);
|
||
|
}
|
||
|
else if (uStrCasePrefix("overlay",field)||
|
||
|
uStrCasePrefix("permanentoverlay",field)) {
|
||
|
Bool permanent= False;
|
||
|
char *which;
|
||
|
int overlayNdx;
|
||
|
if (uStrCasePrefix("permanent",field)) {
|
||
|
permanent= True;
|
||
|
which= &field[sizeof("permanentoverlay")-1];
|
||
|
}
|
||
|
else {
|
||
|
which= &field[sizeof("overlay")-1];
|
||
|
}
|
||
|
if (sscanf(which,"%d",&overlayNdx)==1) {
|
||
|
if (((overlayNdx<1)||(overlayNdx>2))&&(warningLevel>0)) {
|
||
|
ERROR2("Illegal overlay %d specified for %s\n",
|
||
|
overlayNdx,
|
||
|
longText(key->name,XkbMessage));
|
||
|
ACTION("Ignored\n");
|
||
|
return False;
|
||
|
}
|
||
|
}
|
||
|
else if (*which=='\0')
|
||
|
overlayNdx=1;
|
||
|
else if (warningLevel>0) {
|
||
|
ERROR2("Illegal overlay \"%s\" specified for %s\n",
|
||
|
which,
|
||
|
longText(key->name,XkbMessage));
|
||
|
ACTION("Ignored\n");
|
||
|
return False;
|
||
|
}
|
||
|
ok= ExprResolveKeyName(value,&tmp,NULL,NULL);
|
||
|
if (!ok) {
|
||
|
ERROR1("Illegal overlay key specification for %s\n",
|
||
|
longText(key->name,XkbMessage));
|
||
|
ACTION("Overlay key must be specified by name\n");
|
||
|
return False;
|
||
|
}
|
||
|
if (overlayNdx==1) key->behavior.type= XkbKB_Overlay1;
|
||
|
else key->behavior.type= XkbKB_Overlay2;
|
||
|
if (permanent)
|
||
|
key->behavior.type|= XkbKB_Permanent;
|
||
|
|
||
|
key->behavior.data= 0;
|
||
|
key->nameForOverlayKey= KeyNameToLong(tmp.keyName.name);
|
||
|
key->defs.defined|= _Key_Behavior;
|
||
|
}
|
||
|
else if ((uStrCaseCmp(field,"repeating")==0)||
|
||
|
(uStrCaseCmp(field,"repeats")==0)||
|
||
|
(uStrCaseCmp(field,"repeat")==0)){
|
||
|
ok= ExprResolveEnum(value,&tmp,repeatEntries);
|
||
|
if (!ok) {
|
||
|
ERROR1("Illegal repeat setting for %s\n",
|
||
|
longText(key->name,XkbMessage));
|
||
|
ACTION("Non-boolean repeat setting ignored\n");
|
||
|
return False;
|
||
|
}
|
||
|
key->repeat= tmp.uval;
|
||
|
key->defs.defined|= _Key_Repeat;
|
||
|
}
|
||
|
else if ((uStrCaseCmp(field,"groupswrap")==0)||
|
||
|
(uStrCaseCmp(field,"wrapgroups")==0)) {
|
||
|
ok= ExprResolveBoolean(value,&tmp,NULL,NULL);
|
||
|
if (!ok) {
|
||
|
ERROR1("Illegal groupsWrap setting for %s\n",
|
||
|
longText(key->name,XkbMessage));
|
||
|
ACTION("Non-boolean value ignored\n");
|
||
|
return False;
|
||
|
}
|
||
|
if (tmp.uval) key->groupInfo= XkbWrapIntoRange;
|
||
|
else key->groupInfo= XkbClampIntoRange;
|
||
|
key->defs.defined|= _Key_GroupInfo;
|
||
|
}
|
||
|
else if ((uStrCaseCmp(field,"groupsclamp")==0)||
|
||
|
(uStrCaseCmp(field,"clampgroups")==0)) {
|
||
|
ok= ExprResolveBoolean(value,&tmp,NULL,NULL);
|
||
|
if (!ok) {
|
||
|
ERROR1("Illegal groupsClamp setting for %s\n",
|
||
|
longText(key->name,XkbMessage));
|
||
|
ACTION("Non-boolean value ignored\n");
|
||
|
return False;
|
||
|
}
|
||
|
if (tmp.uval) key->groupInfo= XkbClampIntoRange;
|
||
|
else key->groupInfo= XkbWrapIntoRange;
|
||
|
key->defs.defined|= _Key_GroupInfo;
|
||
|
}
|
||
|
else if ((uStrCaseCmp(field,"groupsredirect")==0)||
|
||
|
(uStrCaseCmp(field,"redirectgroups")==0)) {
|
||
|
if (!ExprResolveInteger(value,&tmp,SimpleLookup,(XPointer)groupNames)) {
|
||
|
ERROR1("Illegal group index for redirect of key %s\n",
|
||
|
longText(key->name,XkbMessage));
|
||
|
ACTION("Definition with non-integer group ignored\n");
|
||
|
return False;
|
||
|
}
|
||
|
if ((tmp.uval<1)||(tmp.uval>XkbNumKbdGroups)) {
|
||
|
ERROR2("Out-of-range (1..%d) group for redirect of key %s\n",
|
||
|
XkbNumKbdGroups,
|
||
|
longText(key->name,XkbMessage));
|
||
|
ERROR1("Ignoring illegal group %d\n",tmp.uval);
|
||
|
return False;
|
||
|
}
|
||
|
key->groupInfo= XkbSetGroupInfo(0,XkbRedirectIntoRange,tmp.uval-1);
|
||
|
key->defs.defined|= _Key_GroupInfo;
|
||
|
}
|
||
|
else {
|
||
|
ERROR1("Unknown field %s in a symbol interpretation\n",field);
|
||
|
ACTION("Definition ignored\n");
|
||
|
ok= False;
|
||
|
}
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
SetGroupName(SymbolsInfo *info,ExprDef *arrayNdx,ExprDef *value)
|
||
|
{
|
||
|
ExprResult tmp,name;
|
||
|
|
||
|
if ((arrayNdx==NULL)&&(warningLevel>0)) {
|
||
|
WARN("You must specify an index when specifying a group name\n");
|
||
|
ACTION("Group name definition without array subscript ignored\n");
|
||
|
return False;
|
||
|
}
|
||
|
if (!ExprResolveInteger(arrayNdx,&tmp,SimpleLookup,(XPointer)groupNames)) {
|
||
|
ERROR("Illegal index in group name definition\n");
|
||
|
ACTION("Definition with non-integer array index ignored\n");
|
||
|
return False;
|
||
|
}
|
||
|
if ((tmp.uval<1)||(tmp.uval>XkbNumKbdGroups)) {
|
||
|
ERROR1("Attempt to specify name for illegal group (must be 1..%d)\n",
|
||
|
XkbNumKbdGroups+1);
|
||
|
ACTION1("Name for group %d ignored\n",tmp.uval);
|
||
|
return False;
|
||
|
}
|
||
|
if (!ExprResolveString(value,&name,NULL,NULL)) {
|
||
|
ERROR("Group name must be a string\n");
|
||
|
ACTION1("Illegal name for group %d ignored\n",tmp.uval);
|
||
|
return False;
|
||
|
}
|
||
|
info->groupNames[tmp.uval-1+info->explicit_group]=
|
||
|
XkbInternAtom(NULL,name.str,False);
|
||
|
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
HandleSymbolsVar(VarDef *stmt,XkbDescPtr xkb,SymbolsInfo *info)
|
||
|
{
|
||
|
ExprResult elem,field,tmp;
|
||
|
ExprDef * arrayNdx;
|
||
|
|
||
|
if (ExprResolveLhs(stmt->name,&elem,&field,&arrayNdx)==0)
|
||
|
return 0; /* internal error, already reported */
|
||
|
if (elem.str&&(uStrCaseCmp(elem.str,"key")==0)) {
|
||
|
return SetSymbolsField(&info->dflt,xkb,field.str,arrayNdx,stmt->value,
|
||
|
info);
|
||
|
}
|
||
|
else if ((elem.str==NULL)&&((uStrCaseCmp(field.str,"name")==0)||
|
||
|
(uStrCaseCmp(field.str,"groupname")==0))) {
|
||
|
return SetGroupName(info,arrayNdx,stmt->value);
|
||
|
}
|
||
|
else if ((elem.str==NULL)&&((uStrCaseCmp(field.str,"groupswrap")==0)||
|
||
|
(uStrCaseCmp(field.str,"wrapgroups")==0))) {
|
||
|
if (!ExprResolveBoolean(stmt->value,&tmp,NULL,NULL)) {
|
||
|
ERROR("Illegal setting for global groupsWrap\n");
|
||
|
ACTION("Non-boolean value ignored\n");
|
||
|
return False;
|
||
|
}
|
||
|
if (tmp.uval) info->groupInfo= XkbWrapIntoRange;
|
||
|
else info->groupInfo= XkbClampIntoRange;
|
||
|
return True;
|
||
|
}
|
||
|
else if ((elem.str==NULL)&&((uStrCaseCmp(field.str,"groupsclamp")==0)||
|
||
|
(uStrCaseCmp(field.str,"clampgroups")==0))) {
|
||
|
if (!ExprResolveBoolean(stmt->value,&tmp,NULL,NULL)) {
|
||
|
ERROR("Illegal setting for global groupsClamp\n");
|
||
|
ACTION("Non-boolean value ignored\n");
|
||
|
return False;
|
||
|
}
|
||
|
if (tmp.uval) info->groupInfo= XkbClampIntoRange;
|
||
|
else info->groupInfo= XkbWrapIntoRange;
|
||
|
return True;
|
||
|
}
|
||
|
else if ((elem.str==NULL)&&((uStrCaseCmp(field.str,"groupsredirect")==0)||
|
||
|
(uStrCaseCmp(field.str,"redirectgroups")==0))) {
|
||
|
if (!ExprResolveInteger(stmt->value,&tmp,
|
||
|
SimpleLookup,(XPointer)groupNames)) {
|
||
|
ERROR("Illegal group index for global groupsRedirect\n");
|
||
|
ACTION("Definition with non-integer group ignored\n");
|
||
|
return False;
|
||
|
}
|
||
|
if ((tmp.uval<1)||(tmp.uval>XkbNumKbdGroups)) {
|
||
|
ERROR1("Out-of-range (1..%d) group for global groupsRedirect\n",
|
||
|
XkbNumKbdGroups);
|
||
|
ACTION1("Ignoring illegal group %d\n",tmp.uval);
|
||
|
return False;
|
||
|
}
|
||
|
info->groupInfo= XkbSetGroupInfo(0,XkbRedirectIntoRange,tmp.uval);
|
||
|
return True;
|
||
|
}
|
||
|
else if ((elem.str==NULL)&&(uStrCaseCmp(field.str,"allownone")==0)) {
|
||
|
return SetAllowNone(&info->dflt,arrayNdx,stmt->value);
|
||
|
}
|
||
|
return SetActionField(xkb,elem.str,field.str,arrayNdx,stmt->value,
|
||
|
&info->action);
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
HandleSymbolsBody( VarDef * def,
|
||
|
XkbDescPtr xkb,
|
||
|
KeyInfo * key,
|
||
|
SymbolsInfo * info)
|
||
|
{
|
||
|
Bool ok= True;
|
||
|
ExprResult tmp,field;
|
||
|
ExprDef * arrayNdx;
|
||
|
|
||
|
for (;def!=NULL;def= (VarDef *)def->common.next) {
|
||
|
if ((def->name)&&(def->name->type==ExprFieldRef)) {
|
||
|
ok= HandleSymbolsVar(def,xkb,info);
|
||
|
continue;
|
||
|
}
|
||
|
else {
|
||
|
if (def->name==NULL) {
|
||
|
if ((def->value==NULL)||(def->value->op==ExprKeysymList))
|
||
|
field.str= "symbols";
|
||
|
else field.str= "actions";
|
||
|
arrayNdx= NULL;
|
||
|
}
|
||
|
else {
|
||
|
ok= ExprResolveLhs(def->name,&tmp,&field,&arrayNdx);
|
||
|
}
|
||
|
if (ok)
|
||
|
ok= SetSymbolsField(key,xkb,field.str,arrayNdx,def->value,info);
|
||
|
}
|
||
|
}
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
SetExplicitGroup( SymbolsInfo * info,
|
||
|
KeyInfo * key)
|
||
|
{
|
||
|
unsigned group = info->explicit_group;
|
||
|
|
||
|
if (group == 0)
|
||
|
return True;
|
||
|
|
||
|
if ((key->typesDefined|key->symsDefined|key->actsDefined) & ~1) {
|
||
|
int i;
|
||
|
WARN1("For the map %s an explicit group specified\n", info->name);
|
||
|
WARN1("but key %s has more than one group defined\n",
|
||
|
longText(key->name,XkbMessage));
|
||
|
ACTION("All groups except first one will be ignored\n");
|
||
|
for (i = 1; i < XkbNumKbdGroups ; i++) {
|
||
|
key->numLevels[i]= 0;
|
||
|
if (key->syms[i]!=NULL)
|
||
|
uFree(key->syms[i]);
|
||
|
key->syms[i]= (KeySym*) NULL;
|
||
|
if (key->acts[i]!=NULL)
|
||
|
uFree(key->acts[i]);
|
||
|
key->acts[i]= (XkbAction*) NULL;
|
||
|
key->types[i]= (Atom) 0;
|
||
|
}
|
||
|
}
|
||
|
key->typesDefined = key->symsDefined = key->actsDefined = 1 << group;
|
||
|
|
||
|
key->numLevels[group]= key->numLevels[0];
|
||
|
key->numLevels[0]= 0;
|
||
|
key->syms[group]= key->syms[0];
|
||
|
key->syms[0]= (KeySym*) NULL;
|
||
|
key->acts[group]= key->acts[0];
|
||
|
key->acts[0]= (XkbAction*) NULL;
|
||
|
key->types[group]= key->types[0];
|
||
|
key->types[0]= (Atom) 0;
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
HandleSymbolsDef( SymbolsDef * stmt,
|
||
|
XkbDescPtr xkb,
|
||
|
unsigned merge,
|
||
|
SymbolsInfo * info)
|
||
|
{
|
||
|
KeyInfo key;
|
||
|
|
||
|
InitKeyInfo(&key);
|
||
|
CopyKeyInfo(&info->dflt,&key,False);
|
||
|
key.defs.merge= stmt->merge;
|
||
|
key.name= KeyNameToLong(stmt->keyName);
|
||
|
if (!HandleSymbolsBody((VarDef *)stmt->symbols,xkb,&key,info)) {
|
||
|
info->errorCount++;
|
||
|
return False;
|
||
|
}
|
||
|
|
||
|
if (!SetExplicitGroup(info,&key)) {
|
||
|
info->errorCount++;
|
||
|
return False;
|
||
|
}
|
||
|
|
||
|
if (!AddKeySymbols(info,&key,xkb)) {
|
||
|
info->errorCount++;
|
||
|
return False;
|
||
|
}
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
HandleModMapDef( ModMapDef * def,
|
||
|
XkbDescPtr xkb,
|
||
|
unsigned merge,
|
||
|
SymbolsInfo * info)
|
||
|
{
|
||
|
ExprDef * key;
|
||
|
ModMapEntry tmp;
|
||
|
ExprResult rtrn;
|
||
|
Bool ok;
|
||
|
|
||
|
if (!LookupModIndex(NULL,None,def->modifier,TypeInt,&rtrn)) {
|
||
|
ERROR("Illegal modifier map definition\n");
|
||
|
ACTION1("Ignoring map for non-modifier \"%s\"\n",
|
||
|
XkbAtomText(NULL,def->modifier,XkbMessage));
|
||
|
return False;
|
||
|
}
|
||
|
ok= True;
|
||
|
tmp.modifier= rtrn.uval;
|
||
|
for (key=def->keys;key!=NULL;key=(ExprDef *)key->common.next) {
|
||
|
if ((key->op==ExprValue)&&(key->type==TypeKeyName)) {
|
||
|
tmp.haveSymbol= False;
|
||
|
tmp.u.keyName= KeyNameToLong(key->value.keyName);
|
||
|
}
|
||
|
else if (ExprResolveKeySym(key,&rtrn,NULL,NULL)) {
|
||
|
tmp.haveSymbol= True;
|
||
|
tmp.u.keySym= rtrn.uval;
|
||
|
}
|
||
|
else {
|
||
|
ERROR("Modmap entries may contain only key names or keysyms\n");
|
||
|
ACTION1("Illegal definition for %s modifier ignored\n",
|
||
|
XkbModIndexText(tmp.modifier,XkbMessage));
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
ok= AddModMapEntry(info,&tmp)&&ok;
|
||
|
}
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
HandleSymbolsFile( XkbFile * file,
|
||
|
XkbDescPtr xkb,
|
||
|
unsigned merge,
|
||
|
SymbolsInfo * info)
|
||
|
{
|
||
|
ParseCommon *stmt;
|
||
|
|
||
|
info->name= uStringDup(file->name);
|
||
|
stmt= file->defs;
|
||
|
while (stmt) {
|
||
|
switch (stmt->stmtType) {
|
||
|
case StmtInclude:
|
||
|
if (!HandleIncludeSymbols((IncludeStmt *)stmt,xkb,info,
|
||
|
HandleSymbolsFile))
|
||
|
info->errorCount++;
|
||
|
break;
|
||
|
case StmtSymbolsDef:
|
||
|
if (!HandleSymbolsDef((SymbolsDef *)stmt,xkb,merge,info))
|
||
|
info->errorCount++;
|
||
|
break;
|
||
|
case StmtVarDef:
|
||
|
if (!HandleSymbolsVar((VarDef *)stmt,xkb,info))
|
||
|
info->errorCount++;
|
||
|
break;
|
||
|
case StmtVModDef:
|
||
|
if (!HandleVModDef((VModDef *)stmt,merge,&info->vmods))
|
||
|
info->errorCount++;
|
||
|
break;
|
||
|
case StmtInterpDef:
|
||
|
ERROR("Interpretation files may not include other types\n");
|
||
|
ACTION("Ignoring definition of symbol interpretation\n");
|
||
|
info->errorCount++;
|
||
|
break;
|
||
|
case StmtKeycodeDef:
|
||
|
ERROR("Interpretation files may not include other types\n");
|
||
|
ACTION("Ignoring definition of key name\n");
|
||
|
info->errorCount++;
|
||
|
break;
|
||
|
case StmtModMapDef:
|
||
|
if (!HandleModMapDef((ModMapDef *)stmt,xkb,merge,info))
|
||
|
info->errorCount++;
|
||
|
break;
|
||
|
default:
|
||
|
WSGO1("Unexpected statement type %d in HandleSymbolsFile\n",
|
||
|
stmt->stmtType);
|
||
|
break;
|
||
|
}
|
||
|
stmt= stmt->next;
|
||
|
if (info->errorCount>10) {
|
||
|
#ifdef NOISY
|
||
|
ERROR("Too many errors\n");
|
||
|
#endif
|
||
|
ACTION1("Abandoning symbols file \"%s\"\n",file->topName);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
FindKeyForSymbol(XkbDescPtr xkb,KeySym sym,unsigned int *kc_rtrn)
|
||
|
{
|
||
|
register int i, j;
|
||
|
register Bool gotOne;
|
||
|
|
||
|
j= 0;
|
||
|
do {
|
||
|
gotOne= False;
|
||
|
for (i = xkb->min_key_code; i <= (int)xkb->max_key_code; i++) {
|
||
|
if ( j<(int)XkbKeyNumSyms(xkb,i) ) {
|
||
|
gotOne = True;
|
||
|
if ((XkbKeySym(xkb,i,j)==sym)) {
|
||
|
*kc_rtrn= i;
|
||
|
return True;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
j++;
|
||
|
} while (gotOne);
|
||
|
return False;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
FindNamedType(XkbDescPtr xkb,Atom name,unsigned *type_rtrn)
|
||
|
{
|
||
|
register unsigned n;
|
||
|
|
||
|
if (xkb&&xkb->map&&xkb->map->types) {
|
||
|
for (n=0;n<xkb->map->num_types;n++) {
|
||
|
if (xkb->map->types[n].name==(Atom)name) {
|
||
|
*type_rtrn= n;
|
||
|
return True;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return False;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
KSIsLower (KeySym ks)
|
||
|
{
|
||
|
KeySym lower, upper;
|
||
|
XConvertCase(ks, &lower, &upper);
|
||
|
|
||
|
if (lower == upper)
|
||
|
return False;
|
||
|
return (ks == lower ? True : False);
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
KSIsUpper (KeySym ks)
|
||
|
{
|
||
|
KeySym lower, upper;
|
||
|
XConvertCase(ks, &lower, &upper);
|
||
|
|
||
|
if (lower == upper)
|
||
|
return False;
|
||
|
return (ks == upper ? True : False);
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
FindAutomaticType(int width,KeySym *syms,Atom *typeNameRtrn, Bool *autoType)
|
||
|
{
|
||
|
*autoType = False;
|
||
|
if ((width==1)||(width==0)) {
|
||
|
*typeNameRtrn= XkbInternAtom(NULL,"ONE_LEVEL",False);
|
||
|
*autoType = True;
|
||
|
} else if (width == 2) {
|
||
|
if ( syms && KSIsLower(syms[0]) && KSIsUpper(syms[1]) ) {
|
||
|
*typeNameRtrn= XkbInternAtom(NULL,"ALPHABETIC",False);
|
||
|
} else if ( syms &&
|
||
|
(XkbKSIsKeypad(syms[0]) || XkbKSIsKeypad(syms[1])) ) {
|
||
|
*typeNameRtrn= XkbInternAtom(NULL,"KEYPAD",False);
|
||
|
*autoType = True;
|
||
|
} else {
|
||
|
*typeNameRtrn= XkbInternAtom(NULL,"TWO_LEVEL",False);
|
||
|
*autoType = True;
|
||
|
}
|
||
|
} else if (width <= 4 ) {
|
||
|
if ( syms && KSIsLower(syms[0]) && KSIsUpper(syms[1]) )
|
||
|
if ( KSIsLower(syms[2]) && KSIsUpper(syms[3]) )
|
||
|
*typeNameRtrn= XkbInternAtom(NULL,
|
||
|
"FOUR_LEVEL_ALPHABETIC",False);
|
||
|
else
|
||
|
*typeNameRtrn= XkbInternAtom(NULL,
|
||
|
"FOUR_LEVEL_SEMIALPHABETIC",False);
|
||
|
|
||
|
else if ( syms && (XkbKSIsKeypad(syms[0]) || XkbKSIsKeypad(syms[1])) )
|
||
|
*typeNameRtrn= XkbInternAtom(NULL,
|
||
|
"FOUR_LEVEL_KEYPAD",False);
|
||
|
else *typeNameRtrn= XkbInternAtom(NULL,"FOUR_LEVEL",False);
|
||
|
}
|
||
|
return ((width>=0)&&(width<=4));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
PrepareKeyDef(KeyInfo *key)
|
||
|
{
|
||
|
int i, j, width, defined, lastGroup;
|
||
|
Bool identical;
|
||
|
|
||
|
defined = key->symsDefined | key->actsDefined | key->typesDefined;
|
||
|
for (i = XkbNumKbdGroups - 1; i >= 0; i--) {
|
||
|
if (defined & (1<<i))
|
||
|
break;
|
||
|
}
|
||
|
lastGroup = i;
|
||
|
|
||
|
if (lastGroup == 0)
|
||
|
return;
|
||
|
|
||
|
/* If there are empty groups between non-empty ones fill them with data */
|
||
|
/* from the first group. */
|
||
|
/* We can make a wrong assumption here. But leaving gaps is worse. */
|
||
|
for (i = lastGroup; i > 0; i--) {
|
||
|
if (defined & (1<<i))
|
||
|
continue;
|
||
|
width = key->numLevels[0];
|
||
|
if (key->typesDefined & 1) {
|
||
|
for (j = 0; j < width; j++) {
|
||
|
key->types[i] = key->types[0];
|
||
|
}
|
||
|
key->typesDefined |= 1 << i;
|
||
|
}
|
||
|
if ((key->actsDefined & 1) && key->acts[0]) {
|
||
|
key->acts[i]= uTypedCalloc(width, XkbAction);
|
||
|
if (key->acts[i] == NULL)
|
||
|
continue;
|
||
|
memcpy((void *) key->acts[i], (void *) key->acts[0],
|
||
|
width * sizeof(XkbAction));
|
||
|
key->actsDefined |= 1 << i;
|
||
|
}
|
||
|
if ((key->symsDefined & 1) && key->syms[0]) {
|
||
|
key->syms[i]= uTypedCalloc(width, KeySym);
|
||
|
if (key->syms[i] == NULL)
|
||
|
continue;
|
||
|
memcpy((void *) key->syms[i], (void *) key->syms[0],
|
||
|
width * sizeof(KeySym));
|
||
|
key->symsDefined |= 1 << i;
|
||
|
}
|
||
|
if (defined & 1) {
|
||
|
key->numLevels[i] = key->numLevels[0];
|
||
|
}
|
||
|
}
|
||
|
/* If all groups are completely identical remove them all */
|
||
|
/* exept the first one. */
|
||
|
identical = True;
|
||
|
for (i = lastGroup; i > 0; i--) {
|
||
|
if ((key->numLevels[i] != key->numLevels[0]) ||
|
||
|
(key->types[i] != key->types[0])) {
|
||
|
identical = False;
|
||
|
break;
|
||
|
}
|
||
|
if ((key->syms[i] != key->syms[0]) &&
|
||
|
(key->syms[i] == NULL || key->syms[0] == NULL ||
|
||
|
memcmp((void*) key->syms[i], (void*) key->syms[0],
|
||
|
sizeof(KeySym) * key->numLevels[0])) ) {
|
||
|
identical = False;
|
||
|
break;
|
||
|
}
|
||
|
if ((key->acts[i] != key->acts[0]) &&
|
||
|
(key->acts[i] == NULL || key->acts[0] == NULL ||
|
||
|
memcmp((void*) key->acts[i], (void*) key->acts[0],
|
||
|
sizeof(XkbAction) * key->numLevels[0]))) {
|
||
|
identical = False;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (identical) {
|
||
|
for (i = lastGroup; i > 0; i--) {
|
||
|
key->numLevels[i]= 0;
|
||
|
if (key->syms[i] != NULL)
|
||
|
uFree(key->syms[i]);
|
||
|
key->syms[i]= (KeySym*) NULL;
|
||
|
if (key->acts[i] != NULL)
|
||
|
uFree(key->acts[i]);
|
||
|
key->acts[i]= (XkbAction*) NULL;
|
||
|
key->types[i]= (Atom) 0;
|
||
|
}
|
||
|
key->symsDefined &= 1;
|
||
|
key->actsDefined &= 1;
|
||
|
key->typesDefined &= 1;
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
CopySymbolsDef(XkbFileInfo *result,KeyInfo *key,int start_from)
|
||
|
{
|
||
|
register int i;
|
||
|
unsigned okc,kc,width,tmp,nGroups;
|
||
|
XkbKeyTypePtr type;
|
||
|
Bool haveActions,autoType,useAlias;
|
||
|
KeySym * outSyms;
|
||
|
XkbAction * outActs;
|
||
|
XkbDescPtr xkb;
|
||
|
unsigned types[XkbNumKbdGroups];
|
||
|
|
||
|
xkb= result->xkb;
|
||
|
useAlias= (start_from==0);
|
||
|
if (!FindNamedKey(xkb,key->name,&kc,useAlias,CreateKeyNames(xkb),
|
||
|
start_from)) {
|
||
|
if ((start_from==0)&&(warningLevel>=5)) {
|
||
|
WARN2("Key %s not found in %s keycodes\n",
|
||
|
longText(key->name,XkbMessage),
|
||
|
XkbAtomText(NULL,xkb->names->keycodes,XkbMessage));
|
||
|
ACTION("Symbols ignored\n");
|
||
|
}
|
||
|
return False;
|
||
|
}
|
||
|
|
||
|
haveActions= False;
|
||
|
for (i=width=nGroups=0;i<XkbNumKbdGroups;i++) {
|
||
|
if (((i+1)>nGroups)&&(((key->symsDefined|key->actsDefined)&(1<<i))||
|
||
|
(key->typesDefined)&(1<<i)))
|
||
|
nGroups= i+1;
|
||
|
if (key->acts[i])
|
||
|
haveActions= True;
|
||
|
autoType= False;
|
||
|
if (key->types[i]==None) {
|
||
|
if (key->dfltType!=None)
|
||
|
key->types[i]= key->dfltType;
|
||
|
else if (FindAutomaticType(key->numLevels[i],key->syms[i],
|
||
|
&key->types[i], &autoType)) {
|
||
|
}
|
||
|
else {
|
||
|
if (warningLevel>=5) {
|
||
|
WARN1("No automatic type for %d symbols\n",
|
||
|
(unsigned int)key->numLevels[i]);
|
||
|
ACTION3("Using %s for the %s key (keycode %d)\n",
|
||
|
XkbAtomText(NULL,key->types[i],XkbMessage),
|
||
|
longText(key->name,XkbMessage),kc);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (FindNamedType(xkb,key->types[i],&types[i])) {
|
||
|
if (!autoType || key->numLevels[i] > 2)
|
||
|
xkb->server->explicit[kc]|= (1<<i);
|
||
|
}
|
||
|
else {
|
||
|
if (warningLevel>=3) {
|
||
|
WARN1("Type \"%s\" is not defined\n",
|
||
|
XkbAtomText(NULL,key->types[i],XkbMessage));
|
||
|
ACTION2("Using TWO_LEVEL for the %s key (keycode %d)\n",
|
||
|
longText(key->name,XkbMessage),kc);
|
||
|
}
|
||
|
types[i]= XkbTwoLevelIndex;
|
||
|
}
|
||
|
type= &xkb->map->types[types[i]];
|
||
|
if (type->num_levels<key->numLevels[i]) {
|
||
|
if (warningLevel>0) {
|
||
|
WARN4("Type \"%s\" has %d levels, but %s has %d symbols\n",
|
||
|
XkbAtomText(NULL,type->name,XkbMessage),
|
||
|
(unsigned int)type->num_levels,
|
||
|
longText(key->name,XkbMessage),
|
||
|
(unsigned int)key->numLevels[i]);
|
||
|
ACTION("Ignoring extra symbols\n");
|
||
|
}
|
||
|
key->numLevels[i]= type->num_levels;
|
||
|
}
|
||
|
if (key->numLevels[i]>width)
|
||
|
width= key->numLevels[i];
|
||
|
if (type->num_levels>width)
|
||
|
width= type->num_levels;
|
||
|
}
|
||
|
|
||
|
i= width*nGroups;
|
||
|
outSyms= XkbResizeKeySyms(xkb,kc,i);
|
||
|
if (outSyms==NULL) {
|
||
|
WSGO2("Could not enlarge symbols for %s (keycode %d)\n",
|
||
|
longText(key->name,XkbMessage),kc);
|
||
|
return False;
|
||
|
}
|
||
|
if (haveActions) {
|
||
|
outActs= XkbResizeKeyActions(xkb,kc,i);
|
||
|
if (outActs==NULL) {
|
||
|
WSGO2("Could not enlarge actions for %s (key %d)\n",
|
||
|
longText(key->name,XkbMessage),kc);
|
||
|
return False;
|
||
|
}
|
||
|
xkb->server->explicit[kc]|= XkbExplicitInterpretMask;
|
||
|
}
|
||
|
else outActs= NULL;
|
||
|
if (key->defs.defined&_Key_GroupInfo)
|
||
|
i= key->groupInfo;
|
||
|
else i= xkb->map->key_sym_map[kc].group_info;
|
||
|
xkb->map->key_sym_map[kc].group_info= XkbSetNumGroups(i,nGroups);
|
||
|
xkb->map->key_sym_map[kc].width= width;
|
||
|
for (i=0;i<nGroups;i++) {
|
||
|
xkb->map->key_sym_map[kc].kt_index[i]= types[i];
|
||
|
if (key->syms[i]!=NULL) {
|
||
|
for (tmp=0;tmp<width;tmp++) {
|
||
|
if (tmp<key->numLevels[i])
|
||
|
outSyms[tmp]= key->syms[i][tmp];
|
||
|
else outSyms[tmp]= NoSymbol;
|
||
|
if ((outActs!=NULL)&&(key->acts[i]!=NULL)) {
|
||
|
if (tmp<key->numLevels[i])
|
||
|
outActs[tmp]= key->acts[i][tmp];
|
||
|
else outActs[tmp].type= XkbSA_NoAction;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
outSyms+= width;
|
||
|
if (outActs)
|
||
|
outActs+= width;
|
||
|
}
|
||
|
switch (key->behavior.type&XkbKB_OpMask) {
|
||
|
case XkbKB_Default:
|
||
|
break;
|
||
|
case XkbKB_Overlay1:
|
||
|
case XkbKB_Overlay2:
|
||
|
/* find key by name! */
|
||
|
if (!FindNamedKey(xkb,key->nameForOverlayKey,&okc,True,
|
||
|
CreateKeyNames(xkb),0)) {
|
||
|
if (warningLevel>=1) {
|
||
|
WARN2("Key %s not found in %s keycodes\n",
|
||
|
longText(key->nameForOverlayKey,XkbMessage),
|
||
|
XkbAtomText(NULL,xkb->names->keycodes,XkbMessage));
|
||
|
ACTION1("Not treating %s as an overlay key \n",
|
||
|
longText(key->name,XkbMessage));
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
key->behavior.data= okc;
|
||
|
default:
|
||
|
xkb->server->behaviors[kc]= key->behavior;
|
||
|
xkb->server->explicit[kc]|= XkbExplicitBehaviorMask;
|
||
|
break;
|
||
|
}
|
||
|
if (key->defs.defined&_Key_VModMap) {
|
||
|
xkb->server->vmodmap[kc]= key->vmodmap;
|
||
|
xkb->server->explicit[kc]|= XkbExplicitVModMapMask;
|
||
|
}
|
||
|
if (key->repeat!=RepeatUndefined) {
|
||
|
if (key->repeat==RepeatYes)
|
||
|
xkb->ctrls->per_key_repeat[kc/8]|= (1<<(kc%8));
|
||
|
else xkb->ctrls->per_key_repeat[kc/8]&= ~(1<<(kc%8));
|
||
|
xkb->server->explicit[kc]|= XkbExplicitAutoRepeatMask;
|
||
|
}
|
||
|
CopySymbolsDef(result,key,kc+1);
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
CopyModMapDef(XkbFileInfo *result,ModMapEntry *entry)
|
||
|
{
|
||
|
unsigned kc;
|
||
|
XkbDescPtr xkb;
|
||
|
|
||
|
xkb= result->xkb;
|
||
|
if ((!entry->haveSymbol)&&(!FindNamedKey(xkb,entry->u.keyName,&kc,True,
|
||
|
CreateKeyNames(xkb),0))) {
|
||
|
if (warningLevel>=5) {
|
||
|
WARN2("Key %s not found in %s keycodes\n",
|
||
|
longText(entry->u.keyName,XkbMessage),
|
||
|
XkbAtomText(NULL,xkb->names->keycodes,XkbMessage));
|
||
|
ACTION1("Modifier map entry for %s not updated\n",
|
||
|
XkbModIndexText(entry->modifier,XkbMessage));
|
||
|
}
|
||
|
return False;
|
||
|
}
|
||
|
else if (entry->haveSymbol&&(!FindKeyForSymbol(xkb,entry->u.keySym,&kc))) {
|
||
|
if (warningLevel>5) {
|
||
|
WARN2("Key \"%s\" not found in %s symbol map\n",
|
||
|
XkbKeysymText(entry->u.keySym,XkbMessage),
|
||
|
XkbAtomText(NULL,xkb->names->symbols,XkbMessage));
|
||
|
ACTION1("Modifier map entry for %s not updated\n",
|
||
|
XkbModIndexText(entry->modifier,XkbMessage));
|
||
|
}
|
||
|
return False;
|
||
|
}
|
||
|
xkb->map->modmap[kc]|= (1<<entry->modifier);
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
Bool
|
||
|
CompileSymbols(XkbFile *file,XkbFileInfo *result,unsigned merge)
|
||
|
{
|
||
|
register int i;
|
||
|
SymbolsInfo info;
|
||
|
XkbDescPtr xkb;
|
||
|
|
||
|
xkb= result->xkb;
|
||
|
InitSymbolsInfo(&info,xkb);
|
||
|
info.dflt.defs.fileID= file->id;
|
||
|
info.dflt.defs.merge= merge;
|
||
|
HandleSymbolsFile(file,xkb,merge,&info);
|
||
|
|
||
|
if (info.nKeys == 0)
|
||
|
return True;
|
||
|
if (info.errorCount==0) {
|
||
|
KeyInfo *key;
|
||
|
if (XkbAllocNames(xkb,XkbSymbolsNameMask|XkbGroupNamesMask,0,0)
|
||
|
!=Success) {
|
||
|
WSGO("Can not allocate names in CompileSymbols\n");
|
||
|
ACTION("Symbols not added\n");
|
||
|
return False;
|
||
|
}
|
||
|
if(XkbAllocClientMap(xkb,XkbKeySymsMask|XkbModifierMapMask,0)!=Success){
|
||
|
WSGO("Could not allocate client map in CompileSymbols\n");
|
||
|
ACTION("Symbols not added\n");
|
||
|
return False;
|
||
|
}
|
||
|
if (XkbAllocServerMap(xkb,XkbAllServerInfoMask,32)!=Success) {
|
||
|
WSGO("Could not allocate server map in CompileSymbols\n");
|
||
|
ACTION("Symbols not added\n");
|
||
|
return False;
|
||
|
}
|
||
|
if (XkbAllocControls(xkb,XkbPerKeyRepeatMask)!=Success) {
|
||
|
WSGO("Could not allocate controls in CompileSymbols\n");
|
||
|
ACTION("Symbols not added\n");
|
||
|
return False;
|
||
|
}
|
||
|
xkb->names->symbols= XkbInternAtom(xkb->dpy,info.name,False);
|
||
|
if (info.aliases)
|
||
|
ApplyAliases(xkb,False,&info.aliases);
|
||
|
for (i=0;i<XkbNumKbdGroups;i++) {
|
||
|
if (info.groupNames[i]!=None)
|
||
|
xkb->names->groups[i]= info.groupNames[i];
|
||
|
}
|
||
|
for (key=info.keys,i=0;i<info.nKeys;i++,key++) {
|
||
|
PrepareKeyDef(key);
|
||
|
}
|
||
|
for (key=info.keys,i=0;i<info.nKeys;i++,key++) {
|
||
|
if (!CopySymbolsDef(result,key,0))
|
||
|
info.errorCount++;
|
||
|
}
|
||
|
if (warningLevel>3) {
|
||
|
for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
|
||
|
if (xkb->names->keys[i].name[0]=='\0')
|
||
|
continue;
|
||
|
if (XkbKeyNumGroups(xkb,i)<1) {
|
||
|
char buf[5];
|
||
|
memcpy(buf,xkb->names->keys[i].name,4);
|
||
|
buf[4]= '\0';
|
||
|
WARN2("No symbols defined for <%s> (keycode %d)\n",buf,i);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (info.modMap) {
|
||
|
ModMapEntry *mm,*next;
|
||
|
for (mm=info.modMap;mm!=NULL;mm=next) {
|
||
|
if (!CopyModMapDef(result,mm))
|
||
|
info.errorCount++;
|
||
|
next= (ModMapEntry *)mm->defs.next;
|
||
|
}
|
||
|
}
|
||
|
return True;
|
||
|
}
|
||
|
return False;
|
||
|
}
|