750 lines
20 KiB
C
750 lines
20 KiB
C
|
/* $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;
|
||
|
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 {
|
||
|
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;
|
||
|
}
|