diff options
Diffstat (limited to 'xkbcomp/keycodes.c')
-rw-r--r-- | xkbcomp/keycodes.c | 749 |
1 files changed, 749 insertions, 0 deletions
diff --git a/xkbcomp/keycodes.c b/xkbcomp/keycodes.c new file mode 100644 index 000000000..a86592e4d --- /dev/null +++ b/xkbcomp/keycodes.c @@ -0,0 +1,749 @@ +/* $Xorg: keycodes.c,v 1.4 2000/08/17 19:54:32 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$ */ + +#include "xkbcomp.h" +#include "tokens.h" +#include "expr.h" +#include "keycodes.h" +#include "misc.h" +#include "alias.h" + +char * +longText(unsigned long val,unsigned format) +{ +char buf[4]; + + LongToKeyName(val,buf); + return XkbKeyNameText(buf,format); +} + +/***====================================================================***/ + +void +LongToKeyName(unsigned long val,char *name) +{ + name[0]= ((val>>24)&0xff); + name[1]= ((val>>16)&0xff); + name[2]= ((val>>8)&0xff); + name[3]= (val&0xff); + return; +} + +/***====================================================================***/ + +typedef struct _IndicatorNameInfo { + CommonInfo defs; + int ndx; + Atom name; + Bool virtual; +} IndicatorNameInfo; + +typedef struct _KeyNamesInfo { + char * name; + int errorCount; + unsigned fileID; + unsigned merge; + int computedMin; + int computedMax; + int explicitMin; + int explicitMax; + int effectiveMin; + int effectiveMax; + unsigned long names[XkbMaxLegalKeyCode+1]; + unsigned files[XkbMaxLegalKeyCode+1]; + unsigned char has_alt_forms[XkbMaxLegalKeyCode+1]; + IndicatorNameInfo * leds; + AliasInfo * aliases; +} KeyNamesInfo; + +static void +InitIndicatorNameInfo(IndicatorNameInfo *ii,KeyNamesInfo *info) +{ + ii->defs.defined= 0; + ii->defs.merge= info->merge; + ii->defs.fileID= info->fileID; + ii->defs.next= NULL; + ii->ndx= 0; + ii->name= None; + ii->virtual= False; + return; +} + +static void +ClearIndicatorNameInfo(IndicatorNameInfo *ii,KeyNamesInfo *info) +{ + if (ii==info->leds) { + ClearCommonInfo(&ii->defs); + info->leds= NULL; + } + return; +} + +static IndicatorNameInfo * +NextIndicatorName(KeyNamesInfo *info) +{ +IndicatorNameInfo * ii; + + ii= uTypedAlloc(IndicatorNameInfo); + if (ii) { + InitIndicatorNameInfo(ii,info); + info->leds= (IndicatorNameInfo *)AddCommonInfo(&info->leds->defs, + (CommonInfo *)ii); + } + return ii; +} + +static IndicatorNameInfo * +FindIndicatorByIndex(KeyNamesInfo *info,int ndx) +{ +IndicatorNameInfo * old; + + for (old= info->leds;old!=NULL;old=(IndicatorNameInfo *)old->defs.next) { + if (old->ndx==ndx) + return old; + } + return NULL; +} + +static IndicatorNameInfo * +FindIndicatorByName(KeyNamesInfo *info,Atom name) +{ +IndicatorNameInfo * old; + + for (old= info->leds;old!=NULL;old=(IndicatorNameInfo *)old->defs.next) { + if (old->name==name) + return old; + } + return NULL; +} + +static Bool +AddIndicatorName(KeyNamesInfo *info,IndicatorNameInfo *new) +{ +IndicatorNameInfo *old; +Bool replace; +const char *action; + + replace= (new->defs.merge==MergeReplace)|| + (new->defs.merge==MergeOverride); + old= FindIndicatorByName(info,new->name); + if (old) { + if (((old->defs.fileID==new->defs.fileID)&&(warningLevel>0))|| + (warningLevel>9)) { + WARN1("Multiple indicators named %s\n", + XkbAtomText(NULL,new->name,XkbMessage)); + if (old->ndx==new->ndx) { + if (old->virtual!=new->virtual) { + if (replace) + old->virtual= new->virtual; + action= "Using %s instead of %s\n"; + } + else { + action= "Identical definitions ignored\n"; + } + ACTION2(action,(old->virtual?"virtual":"real"), + (old->virtual?"real":"virtual")); + return True; + } + else { + if (replace) action= "Ignoring %d, using %d\n"; + else action= "Using %d, ignoring %d\n"; + ACTION2(action,old->ndx,new->ndx); + } + if (replace) { + if (info->leds==old) + info->leds= (IndicatorNameInfo *)old->defs.next; + else { + IndicatorNameInfo *tmp; + tmp= info->leds; + for (;tmp!=NULL;tmp=(IndicatorNameInfo *)tmp->defs.next) { + if (tmp->defs.next==(CommonInfo *)old) { + tmp->defs.next= old->defs.next; + break; + } + } + } + uFree(old); + } + } + } + old= FindIndicatorByIndex(info,new->ndx); + if (old) { + if (((old->defs.fileID==new->defs.fileID)&&(warningLevel>0))|| + (warningLevel>9)) { + WARN1("Multiple names for indicator %d\n",new->ndx); + if ((old->name==new->name)&&(old->virtual==new->virtual)) + action= "Identical definitions ignored\n"; + else { + const char *oldType,*newType; + Atom using,ignoring; + if (old->virtual) oldType= "virtual indicator"; + else oldType= "real indicator"; + if (new->virtual) newType= "virtual indicator"; + else newType= "real indicator"; + if (replace) { + using= new->name; + ignoring= old->name; + } + else { + using= old->name; + ignoring= new->name; + } + ACTION4("Using %s %s, ignoring %s %s\n", + oldType,XkbAtomText(NULL,using,XkbMessage), + newType,XkbAtomText(NULL,ignoring,XkbMessage)); + } + } + if (replace) { + old->name= new->name; + old->virtual= new->virtual; + } + return True; + } + old= new; + new= NextIndicatorName(info); + if (!new) { + WSGO1("Couldn't allocate name for indicator %d\n",new->ndx); + ACTION("Ignored\n"); + return False; + } + new->name= old->name; + new->ndx= old->ndx; + new->virtual= old->virtual; + return True; +} + +static void +ClearKeyNamesInfo(KeyNamesInfo *info) +{ + if (info->name!=NULL) + uFree(info->name); + info->name= NULL; + info->computedMax= info->explicitMax= info->explicitMin= -1; + info->computedMin= 256; + info->effectiveMin= 8; + info->effectiveMax= 255; + bzero((char *)info->names,sizeof(info->names)); + bzero((char *)info->files,sizeof(info->files)); + bzero((char *)info->has_alt_forms,sizeof(info->has_alt_forms)); + if (info->leds) + ClearIndicatorNameInfo(info->leds,info); + if (info->aliases) + ClearAliases(&info->aliases); + return; +} + +static void +InitKeyNamesInfo(KeyNamesInfo *info) +{ + info->name= NULL; + info->leds= NULL; + info->aliases= NULL; + ClearKeyNamesInfo(info); + info->errorCount= 0; + return; +} + +static int +FindKeyByLong(KeyNamesInfo *info,unsigned long name) +{ +register int i; + + for (i=info->effectiveMin;i<=info->effectiveMax;i++) { + if (info->names[i]==name) + return i; + } + return 0; +} + +static Bool +AddKeyName( KeyNamesInfo * info, + int kc, + char * name, + unsigned merge, + unsigned fileID, + Bool reportCollisions) +{ +int old; +unsigned long lval; + + if ((kc<info->effectiveMin)||(kc>info->effectiveMax)) { + ERROR2("Illegal keycode %d for name <%s>\n",kc,name); + ACTION2("Must be in the range %d-%d inclusive\n",info->effectiveMin, + info->effectiveMax); + return False; + } + if (kc<info->computedMin) info->computedMin= kc; + if (kc>info->computedMax) info->computedMax= kc; + lval= KeyNameToLong(name); + + if (reportCollisions) { + reportCollisions= ((warningLevel>7)|| + ((warningLevel>0)&&(fileID==info->files[kc]))); + } + + if (info->names[kc]!=0) { + char buf[6]; + + LongToKeyName(info->names[kc],buf); + buf[4]= '\0'; + if (info->names[kc]==lval) { + if (info->has_alt_forms[kc] || (merge==MergeAltForm)) { + info->has_alt_forms[kc]= True; + } + else if (reportCollisions) { + WARN("Multiple identical key name definitions\n"); + ACTION2("Later occurences of \"<%s> = %d\" ignored\n",buf,kc); + } + return True; + } + if (merge==MergeAugment) { + if (reportCollisions) { + WARN1("Multiple names for keycode %d\n",kc); + ACTION2("Using <%s>, ignoring <%s>\n",buf,name); + } + return True; + } + else { + if (reportCollisions) { + WARN1("Multiple names for keycode %d\n",kc); + ACTION2("Using <%s>, ignoring <%s>\n",name,buf); + } + info->names[kc]= 0; + info->files[kc]= 0; + } + } + old= FindKeyByLong(info,lval); + if ((old!=0)&&(old!=kc)) { + if (merge==MergeOverride) { + info->names[old]= 0; + info->files[old]= 0; + info->has_alt_forms[old]= True; + if (reportCollisions) { + WARN1("Key name <%s> assigned to multiple keys\n",name); + ACTION2("Using %d, ignoring %d\n",kc,old); + } + } + else if (merge!=MergeAltForm) { + if ((reportCollisions)&&(warningLevel>3)) { + WARN1("Key name <%s> assigned to multiple keys\n",name); + ACTION2("Using %d, ignoring %d\n",old,kc); + ACTION("Use 'alternate' keyword to assign the same name to multiple keys\n"); + } + return True; + } + else { + info->has_alt_forms[old]= True; + } + } + info->names[kc]= lval; + info->files[kc]= fileID; + info->has_alt_forms[kc]= (merge==MergeAltForm); + return True; +} + +/***====================================================================***/ + +static void +MergeIncludedKeycodes(KeyNamesInfo *into,KeyNamesInfo *from,unsigned merge) +{ +register int i; +char buf[5]; + + if (from->errorCount>0) { + into->errorCount+= from->errorCount; + return; + } + if (into->name==NULL) { + into->name= from->name; + from->name= NULL; + } + for (i=from->computedMin;i<=from->computedMax;i++) { + unsigned thisMerge; + if (from->names[i]==0) + continue; + LongToKeyName(from->names[i],buf); + buf[4]= '\0'; + if (from->has_alt_forms[i]) + thisMerge= MergeAltForm; + else thisMerge= merge; + if (!AddKeyName(into,i,buf,thisMerge,from->fileID,False)) + into->errorCount++; + } + if (from->leds) { + IndicatorNameInfo *led,*next; + for (led=from->leds;led!=NULL;led=next) { + if (merge!=MergeDefault) + led->defs.merge= merge; + if (!AddIndicatorName(into,led)) + into->errorCount++; + next= (IndicatorNameInfo *)led->defs.next; + } + } + if (!MergeAliases(&into->aliases,&from->aliases,merge)) + into->errorCount++; + if (from->explicitMin>0) { + if ((into->explicitMin<0)||(into->explicitMin>from->explicitMin)) + into->effectiveMin= into->explicitMin= from->explicitMin; + } + if (from->explicitMax>0) { + if ((into->explicitMax<0)||(into->explicitMax<from->explicitMax)) + into->effectiveMax= into->explicitMax= from->explicitMax; + } + return; +} + +typedef void (*FileHandler)( + XkbFile * /* rtrn */, + XkbDescPtr /* xkb */, + unsigned /* merge */, + KeyNamesInfo * /* included */ +); + +static Bool +HandleIncludeKeycodes( IncludeStmt * stmt, + XkbDescPtr xkb, + KeyNamesInfo * info, + FileHandler hndlr) +{ +unsigned newMerge; +XkbFile * rtrn; +KeyNamesInfo included; +Bool haveSelf; + + haveSelf= False; + if ((stmt->file==NULL)&&(stmt->map==NULL)) { + haveSelf= True; + included= *info; + bzero(info,sizeof(KeyNamesInfo)); + } + else if (strcmp(stmt->file,"computed")==0) { + xkb->flags|= AutoKeyNames; + info->explicitMin= XkbMinLegalKeyCode; + info->explicitMax= XkbMaxLegalKeyCode; + return (info->errorCount==0); + } + else if (ProcessIncludeFile(stmt,XkmKeyNamesIndex,&rtrn,&newMerge)) { + InitKeyNamesInfo(&included); + (*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; + KeyNamesInfo next_incl; + + for (next=stmt->next;next!=NULL;next=next->next) { + if ((next->file==NULL)&&(next->map==NULL)) { + haveSelf= True; + MergeIncludedKeycodes(&included,info,next->merge); + ClearKeyNamesInfo(info); + } + else if (ProcessIncludeFile(next,XkmKeyNamesIndex,&rtrn,&op)) { + InitKeyNamesInfo(&next_incl); + (*hndlr)(rtrn,xkb,MergeOverride,&next_incl); + MergeIncludedKeycodes(&included,&next_incl,op); + ClearKeyNamesInfo(&next_incl); + } + else { + info->errorCount+= 10; + return False; + } + } + } + if (haveSelf) + *info= included; + else { + MergeIncludedKeycodes(info,&included,newMerge); + ClearKeyNamesInfo(&included); + } + return (info->errorCount==0); +} + +static int +HandleKeycodeDef( KeycodeDef * stmt, + XkbDescPtr xkb, + unsigned merge, + KeyNamesInfo * info) +{ +int code; +ExprResult result; + + if (!ExprResolveInteger(stmt->value,&result,NULL,NULL)) { + ACTION1("No value keycode assigned to name <%s>\n",stmt->name); + return 0; + } + code= result.ival; + if ((code<info->effectiveMin)||(code>info->effectiveMax)) { + ERROR2("Illegal keycode %d for name <%s>\n",code,stmt->name); + ACTION2("Must be in the range %d-%d inclusive\n",info->effectiveMin, + info->effectiveMax); + return 0; + } + if (stmt->merge!=MergeDefault) { + if (stmt->merge==MergeReplace) + merge= MergeOverride; + else merge= stmt->merge; + } + return AddKeyName(info,code,stmt->name,merge,info->fileID,True); +} + +#define MIN_KEYCODE_DEF 0 +#define MAX_KEYCODE_DEF 1 + +static int +HandleKeyNameVar(VarDef *stmt,XkbDescPtr xkb,unsigned merge,KeyNamesInfo *info) +{ +ExprResult tmp,field; +ExprDef * arrayNdx; +int which; + + if (ExprResolveLhs(stmt->name,&tmp,&field,&arrayNdx)==0) + return 0; /* internal error, already reported */ + + if (tmp.str!=NULL) { + ERROR1("Unknown element %s encountered\n",tmp.str); + ACTION1("Default for field %s ignored\n",field.str); + return 0; + } + if (uStrCaseCmp(field.str,"minimum")==0) which= MIN_KEYCODE_DEF; + else if (uStrCaseCmp(field.str,"maximum")==0) which= MAX_KEYCODE_DEF; + else { + ERROR("Unknown field encountered\n"); + ACTION1("Assigment to field %s ignored\n",field.str); + return 0; + } + if (arrayNdx!=NULL) { + ERROR1("The %s setting is not an array\n",field.str); + ACTION("Illegal array reference ignored\n"); + return 0; + } + + if (ExprResolveInteger(stmt->value,&tmp,NULL,NULL)==0) { + ACTION1("Assignment to field %s ignored\n",field.str); + return 0; + } + if ((tmp.ival<XkbMinLegalKeyCode)||(tmp.ival>XkbMaxLegalKeyCode)) { + ERROR3("Illegal keycode %d (must be in the range %d-%d inclusive)\n", + tmp.ival,XkbMinLegalKeyCode,XkbMaxLegalKeyCode); + ACTION1("Value of \"%s\" not changed\n",field.str); + return 0; + } + if (which==MIN_KEYCODE_DEF) { + if ((info->explicitMax>0)&&(info->explicitMax<tmp.ival)) { + ERROR2("Minimum key code (%d) must be <= maximum key code (%d)\n", + tmp.ival,info->explicitMax); + ACTION("Minimum key code value not changed\n"); + return 0; + } + if ((info->computedMax>0)&&(info->computedMin<tmp.ival)) { + ERROR2("Minimum key code (%d) must be <= lowest defined key (%d)\n", + tmp.ival,info->computedMin); + ACTION("Minimum key code value not changed\n"); + return 0; + } + info->explicitMin= tmp.ival; + info->effectiveMin= tmp.ival; + } + if (which==MAX_KEYCODE_DEF) { + if ((info->explicitMin>0)&&(info->explicitMin>tmp.ival)) { + ERROR2("Maximum code (%d) must be >= minimum key code (%d)\n", + tmp.ival,info->explicitMin); + ACTION("Maximum code value not changed\n"); + return 0; + } + if ((info->computedMax>0)&&(info->computedMax>tmp.ival)) { + ERROR2("Maximum code (%d) must be >= highest defined key (%d)\n", + tmp.ival,info->computedMax); + ACTION("Maximum code value not changed\n"); + return 0; + } + info->explicitMax= tmp.ival; + info->effectiveMax= tmp.ival; + } + return 1; +} + +static int +HandleIndicatorNameDef( IndicatorNameDef * def, + XkbDescPtr xkb, + unsigned merge, + KeyNamesInfo * info) +{ +IndicatorNameInfo ii; +ExprResult tmp; + + if ((def->ndx<1)||(def->ndx>XkbNumIndicators)) { + info->errorCount++; + ERROR1("Name specified for illegal indicator index %d\n",def->ndx); + ACTION("Ignored\n"); + return False; + } + InitIndicatorNameInfo(&ii,info); + ii.ndx= def->ndx; + if (!ExprResolveString(def->name,&tmp,NULL,NULL)) { + char buf[20]; + sprintf(buf,"%d",def->ndx); + info->errorCount++; + return ReportBadType("indicator","name",buf,"string"); + } + ii.name= XkbInternAtom(NULL,tmp.str,False); + ii.virtual= def->virtual; + if (!AddIndicatorName(info,&ii)) + return False; + return True; +} + +static void +HandleKeycodesFile( XkbFile * file, + XkbDescPtr xkb, + unsigned merge, + KeyNamesInfo * info) +{ +ParseCommon *stmt; + + info->name= uStringDup(file->name); + stmt= file->defs; + while (stmt) { + switch (stmt->stmtType) { + case StmtInclude: + if (!HandleIncludeKeycodes((IncludeStmt *)stmt,xkb,info, + HandleKeycodesFile)) + info->errorCount++; + break; + case StmtKeycodeDef: + if (!HandleKeycodeDef((KeycodeDef *)stmt,xkb,merge,info)) + info->errorCount++; + break; + case StmtKeyAliasDef: + if (!HandleAliasDef((KeyAliasDef *)stmt, + merge,info->fileID,&info->aliases)) + info->errorCount++; + break; + case StmtVarDef: + if (!HandleKeyNameVar((VarDef *)stmt,xkb,merge,info)) + info->errorCount++; + break; + case StmtIndicatorNameDef: + if (!HandleIndicatorNameDef((IndicatorNameDef *)stmt,xkb, + merge,info)) { + info->errorCount++; + } + break; + case StmtInterpDef: + case StmtVModDef: + ERROR("Keycode files may define key and indicator names only\n"); + ACTION1("Ignoring definition of %s\n", + ((stmt->stmtType==StmtInterpDef)? + "a symbol interpretation": + "virtual modifiers")); + info->errorCount++; + break; + default: + WSGO1("Unexpected statement type %d in HandleKeycodesFile\n", + stmt->stmtType); + break; + } + stmt= stmt->next; + if (info->errorCount>10) { +#ifdef NOISY + ERROR("Too many errors\n"); +#endif + ACTION1("Abandoning keycodes file \"%s\"\n",file->topName); + break; + } + } + return; +} + +Bool +CompileKeycodes(XkbFile *file,XkbFileInfo *result,unsigned merge) +{ +KeyNamesInfo info; +XkbDescPtr xkb; + + xkb= result->xkb; + InitKeyNamesInfo(&info); + HandleKeycodesFile(file,xkb,merge,&info); + + if (info.errorCount==0) { + if (info.explicitMin>0) + xkb->min_key_code= info.effectiveMin; + else xkb->min_key_code= info.computedMin; + if (info.explicitMax>0) + xkb->max_key_code= info.effectiveMax; + else xkb->max_key_code= info.computedMax; + if (XkbAllocNames(xkb,XkbKeyNamesMask|XkbIndicatorNamesMask,0,0)==Success) { + register int i; + xkb->names->keycodes= XkbInternAtom(xkb->dpy,info.name,False); + uDEBUG2(1,"key range: %d..%d\n",xkb->min_key_code,xkb->max_key_code); + for (i=info.computedMin;i<=info.computedMax;i++) { + LongToKeyName(info.names[i],xkb->names->keys[i].name); + uDEBUG2(2,"key %d = %s\n",i, + XkbKeyNameText(xkb->names->keys[i].name,XkbMessage)); + } + } + else { + WSGO("Cannot create XkbNamesRec in CompileKeycodes\n"); + return False; + } + if (info.leds) { + IndicatorNameInfo *ii; + if (XkbAllocIndicatorMaps(xkb)!=Success) { + WSGO("Couldn't allocate IndicatorRec in CompileKeycodes\n"); + ACTION("Physical indicators not set\n"); + } + for (ii=info.leds;ii!=NULL;ii=(IndicatorNameInfo *)ii->defs.next){ + xkb->names->indicators[ii->ndx-1]= + XkbInternAtom(xkb->dpy, + XkbAtomGetString(NULL,ii->name),False); + if (xkb->indicators!=NULL) { + register unsigned bit; + bit= 1<<(ii->ndx-1); + if (ii->virtual) + xkb->indicators->phys_indicators&= ~bit; + else xkb->indicators->phys_indicators|= bit; + } + } + } + if (info.aliases) + ApplyAliases(xkb,False,&info.aliases); + return True; + } + ClearKeyNamesInfo(&info); + return False; +} |