#include "xkbcomp.h"
#include "tokens.h"
#include "expr.h"
#include "keycodes.h"
#include "vmod.h"
#include "misc.h"
#include "action.h"
#include "misc.h"
static Bool actionsInitialized;
static ExprDef constTrue;
static ExprDef constFalse;
static Bool
stringToAction(char *str,unsigned *type_rtrn)
{
if (str==NULL)
return False;
if (uStrCaseCmp(str,"noaction")==0) *type_rtrn= XkbSA_NoAction;
else if (uStrCaseCmp(str,"setmods")==0) *type_rtrn= XkbSA_SetMods;
else if (uStrCaseCmp(str,"latchmods")==0) *type_rtrn= XkbSA_LatchMods;
else if (uStrCaseCmp(str,"lockmods")==0) *type_rtrn= XkbSA_LockMods;
else if (uStrCaseCmp(str,"setgroup")==0) *type_rtrn= XkbSA_SetGroup;
else if (uStrCaseCmp(str,"latchgroup")==0) *type_rtrn= XkbSA_LatchGroup;
else if (uStrCaseCmp(str,"lockgroup")==0) *type_rtrn= XkbSA_LockGroup;
else if (uStrCaseCmp(str,"moveptr")==0) *type_rtrn= XkbSA_MovePtr;
else if (uStrCaseCmp(str,"movepointer")==0) *type_rtrn= XkbSA_MovePtr;
else if (uStrCaseCmp(str,"ptrbtn")==0) *type_rtrn= XkbSA_PtrBtn;
else if (uStrCaseCmp(str,"pointerbutton")==0)
*type_rtrn= XkbSA_PtrBtn;
else if (uStrCaseCmp(str,"lockptrbtn")==0) *type_rtrn= XkbSA_LockPtrBtn;
else if (uStrCaseCmp(str,"lockpointerbutton")==0)
*type_rtrn= XkbSA_LockPtrBtn;
else if (uStrCaseCmp(str,"lockptrbutton")==0)
*type_rtrn= XkbSA_LockPtrBtn;
else if (uStrCaseCmp(str,"lockpointerbtn")==0)
*type_rtrn= XkbSA_LockPtrBtn;
else if (uStrCaseCmp(str,"setptrdflt")==0) *type_rtrn= XkbSA_SetPtrDflt;
else if (uStrCaseCmp(str,"setpointerdefault")==0)
*type_rtrn= XkbSA_SetPtrDflt;
else if (uStrCaseCmp(str,"isolock")==0) *type_rtrn= XkbSA_ISOLock;
else if (uStrCaseCmp(str,"terminate")==0) *type_rtrn= XkbSA_Terminate;
else if (uStrCaseCmp(str,"terminateserver")==0)
*type_rtrn= XkbSA_Terminate;
else if (uStrCaseCmp(str,"switchscreen")==0)*type_rtrn= XkbSA_SwitchScreen;
else if (uStrCaseCmp(str,"setcontrols")==0) *type_rtrn= XkbSA_SetControls;
else if (uStrCaseCmp(str,"lockcontrols")==0)*type_rtrn= XkbSA_LockControls;
else if (uStrCaseCmp(str,"actionmessage")==0)*type_rtrn= XkbSA_ActionMessage;
else if (uStrCaseCmp(str,"messageaction")==0)*type_rtrn= XkbSA_ActionMessage;
else if (uStrCaseCmp(str,"message")==0) *type_rtrn= XkbSA_ActionMessage;
else if (uStrCaseCmp(str,"redirect")==0) *type_rtrn= XkbSA_RedirectKey;
else if (uStrCaseCmp(str,"redirectkey")==0) *type_rtrn= XkbSA_RedirectKey;
else if (uStrCaseCmp(str,"devbtn")==0) *type_rtrn= XkbSA_DeviceBtn;
else if (uStrCaseCmp(str,"devicebtn")==0) *type_rtrn= XkbSA_DeviceBtn;
else if (uStrCaseCmp(str,"devbutton")==0) *type_rtrn= XkbSA_DeviceBtn;
else if (uStrCaseCmp(str,"devicebutton")==0)*type_rtrn= XkbSA_DeviceBtn;
else if (uStrCaseCmp(str,"lockdevbtn")==0) *type_rtrn= XkbSA_DeviceBtn;
else if (uStrCaseCmp(str,"lockdevicebtn")==0)
*type_rtrn= XkbSA_LockDeviceBtn;
else if (uStrCaseCmp(str,"lockdevbutton")==0)
*type_rtrn= XkbSA_LockDeviceBtn;
else if (uStrCaseCmp(str,"lockdevicebutton")==0)
*type_rtrn= XkbSA_LockDeviceBtn;
else if (uStrCaseCmp(str,"devval")==0) *type_rtrn=XkbSA_DeviceValuator;
else if (uStrCaseCmp(str,"deviceval")==0) *type_rtrn=XkbSA_DeviceValuator;
else if (uStrCaseCmp(str,"devvaluator")==0) *type_rtrn=XkbSA_DeviceValuator;
else if (uStrCaseCmp(str,"devicevaluator")==0)
*type_rtrn=XkbSA_DeviceValuator;
else if (uStrCaseCmp(str,"private")==0) *type_rtrn= PrivateAction;
else return False;
return True;
}
static Bool
stringToField(char *str,unsigned *field_rtrn)
{
if (str==NULL)
return False;
if (uStrCaseCmp(str,"clearlocks")==0) *field_rtrn= F_ClearLocks;
else if (uStrCaseCmp(str,"latchtolock")==0) *field_rtrn= F_LatchToLock;
else if (uStrCaseCmp(str,"genkeyevent")==0) *field_rtrn= F_GenKeyEvent;
else if (uStrCaseCmp(str,"generatekeyevent")==0)
*field_rtrn= F_GenKeyEvent;
else if (uStrCaseCmp(str,"report")==0) *field_rtrn= F_Report;
else if (uStrCaseCmp(str,"default")==0) *field_rtrn= F_Default;
else if (uStrCaseCmp(str,"affect")==0) *field_rtrn= F_Affect;
else if (uStrCaseCmp(str,"increment")==0) *field_rtrn= F_Increment;
else if (uStrCaseCmp(str,"mods")==0) *field_rtrn= F_Modifiers;
else if (uStrCaseCmp(str,"modifiers")==0) *field_rtrn= F_Modifiers;
else if (uStrCaseCmp(str,"group")==0) *field_rtrn= F_Group;
else if (uStrCaseCmp(str,"x")==0) *field_rtrn= F_X;
else if (uStrCaseCmp(str,"y")==0) *field_rtrn= F_Y;
else if (uStrCaseCmp(str,"accel")==0) *field_rtrn= F_Accel;
else if (uStrCaseCmp(str,"accelerate")==0) *field_rtrn= F_Accel;
else if (uStrCaseCmp(str,"repeat")==0) *field_rtrn= F_Accel;
else if (uStrCaseCmp(str,"button")==0) *field_rtrn= F_Button;
else if (uStrCaseCmp(str,"value")==0) *field_rtrn= F_Value;
else if (uStrCaseCmp(str,"controls")==0) *field_rtrn= F_Controls;
else if (uStrCaseCmp(str,"ctrls")==0) *field_rtrn= F_Controls;
else if (uStrCaseCmp(str,"type")==0) *field_rtrn= F_Type;
else if (uStrCaseCmp(str,"count")==0) *field_rtrn= F_Count;
else if (uStrCaseCmp(str,"screen")==0) *field_rtrn= F_Screen;
else if (uStrCaseCmp(str,"same")==0) *field_rtrn= F_Same;
else if (uStrCaseCmp(str,"sameserver")==0) *field_rtrn= F_Same;
else if (uStrCaseCmp(str,"data")==0) *field_rtrn= F_Data;
else if (uStrCaseCmp(str,"device")==0) *field_rtrn= F_Device;
else if (uStrCaseCmp(str,"dev")==0) *field_rtrn= F_Device;
else if (uStrCaseCmp(str,"key")==0) *field_rtrn= F_Keycode;
else if (uStrCaseCmp(str,"keycode")==0) *field_rtrn= F_Keycode;
else if (uStrCaseCmp(str,"kc")==0) *field_rtrn= F_Keycode;
else if (uStrCaseCmp(str,"clearmods")==0) *field_rtrn= F_ModsToClear;
else if (uStrCaseCmp(str,"clearmodifiers")==0) *field_rtrn= F_ModsToClear;
else return False;
return True;
}
static char *
fieldText(unsigned field)
{
static char buf[32];
switch (field) {
case F_ClearLocks: strcpy(buf,"clearLocks"); break;
case F_LatchToLock: strcpy(buf,"latchToLock"); break;
case F_GenKeyEvent: strcpy(buf,"genKeyEvent"); break;
case F_Report: strcpy(buf,"report"); break;
case F_Default: strcpy(buf,"default"); break;
case F_Affect: strcpy(buf,"affect"); break;
case F_Increment: strcpy(buf,"increment"); break;
case F_Modifiers: strcpy(buf,"modifiers"); break;
case F_Group: strcpy(buf,"group"); break;
case F_X: strcpy(buf,"x"); break;
case F_Y: strcpy(buf,"y"); break;
case F_Accel: strcpy(buf,"accel"); break;
case F_Button: strcpy(buf,"button"); break;
case F_Value: strcpy(buf,"value"); break;
case F_Controls: strcpy(buf,"controls"); break;
case F_Type: strcpy(buf,"type"); break;
case F_Count: strcpy(buf,"count"); break;
case F_Screen: strcpy(buf,"screen"); break;
case F_Same: strcpy(buf,"sameServer"); break;
case F_Data: strcpy(buf,"data"); break;
case F_Device: strcpy(buf,"device"); break;
case F_Keycode: strcpy(buf,"keycode"); break;
case F_ModsToClear: strcpy(buf,"clearmods"); break;
default: strcpy(buf,"unknown"); break;
}
return buf;
}
static Bool
ReportMismatch(unsigned action,unsigned field,char *type)
{
ERROR2("Value of %s field must be of type %s\n",fieldText(field),type);
ACTION1("Action %s definition ignored\n",
XkbActionTypeText(action,XkbMessage));
return False;
}
static Bool
ReportIllegal(unsigned action,unsigned field)
{
ERROR2("Field %s is not defined for an action of type %s\n",
fieldText(field),
XkbActionTypeText(action,XkbMessage));
ACTION("Action definition ignored\n");
return False;
}
static Bool
ReportActionNotArray(unsigned action,unsigned field)
{
ERROR2("The %s field in the %s action is not an array\n",
fieldText(field),
XkbActionTypeText(action,XkbMessage));
ACTION("Action definition ignored\n");
return False;
}
static Bool
ReportNotFound(unsigned action,unsigned field,char *what,char *bad)
{
ERROR2("%s named %s not found\n",what,bad);
ACTION2("Ignoring the %s field of an %s action\n",fieldText(field),
XkbActionTypeText(action,XkbMessage));
return False;
}
static Bool
HandleNoAction( XkbDescPtr xkb,
XkbAnyAction * action,
unsigned field,
ExprDef * array_ndx,
ExprDef * value)
{
return ReportIllegal(action->type,field);
}
static Bool
CheckLatchLockFlags( unsigned action,
unsigned field,
ExprDef * value,
unsigned * flags_inout)
{
unsigned tmp;
ExprResult result;
if (field==F_ClearLocks) tmp= XkbSA_ClearLocks;
else if (field==F_LatchToLock) tmp= XkbSA_LatchToLock;
else return False;
if (!ExprResolveBoolean(value,&result,NULL,NULL))
return ReportMismatch(action,field,"boolean");
if (result.uval) *flags_inout|= tmp;
else *flags_inout&= ~tmp;
return True;
}
static Bool
CheckModifierField( XkbDescPtr xkb,
unsigned action,
ExprDef * value,
unsigned * flags_inout,
unsigned * mods_rtrn)
{
ExprResult rtrn;
if (value->op==ExprIdent) {
register char *valStr;
valStr= XkbAtomGetString(NULL,value->value.str);
if (valStr&&((uStrCaseCmp(valStr,"usemodmapmods")==0)||
(uStrCaseCmp(valStr,"modmapmods")==0))) {
*mods_rtrn= 0;
*flags_inout|= XkbSA_UseModMapMods;
return True;
}
}
if (!ExprResolveModMask(value,&rtrn,LookupVModMask,(XPointer)xkb))
return ReportMismatch(action,F_Modifiers,"modifier mask");
*mods_rtrn= rtrn.uval;
*flags_inout&= ~XkbSA_UseModMapMods;
return True;
}
static Bool
HandleSetLatchMods( XkbDescPtr xkb,
XkbAnyAction * action,
unsigned field,
ExprDef * array_ndx,
ExprDef * value)
{
XkbModAction * act;
unsigned rtrn;
unsigned t1,t2;
act= (XkbModAction *)action;
if (array_ndx!=NULL) {
switch (field) {
case F_ClearLocks: case F_LatchToLock:
case F_Modifiers:
return ReportActionNotArray(action->type,field);
}
}
switch (field) {
case F_ClearLocks:
case F_LatchToLock:
rtrn= act->flags;
if (CheckLatchLockFlags(action->type,field,value,&rtrn)) {
act->flags= rtrn;
return True;
}
return False;
case F_Modifiers:
t1= act->flags;
if (CheckModifierField(xkb,action->type,value,&t1,&t2)) {
act->flags= t1;
act->real_mods= act->mask= (t2&0xff);
t2= (t2>>8)&0xffff;
XkbSetModActionVMods(act,t2);
return True;
}
return False;
}
return ReportIllegal(action->type,field);
}
static Bool
HandleLockMods( XkbDescPtr xkb,
XkbAnyAction * action,
unsigned field,
ExprDef * array_ndx,
ExprDef * value)
{
XkbModAction * act;
unsigned t1,t2;
act= (XkbModAction *)action;
if ((array_ndx!=NULL)&&(field==F_Modifiers))
return ReportActionNotArray(action->type,field);
switch (field) {
case F_Modifiers:
t1= act->flags;
if (CheckModifierField(xkb,action->type,value,&t1,&t2)) {
act->flags= t1;
act->real_mods= act->mask= (t2&0xff);
t2= (t2>>8)&0xffff;
XkbSetModActionVMods(act,t2);
return True;
}
return False;
}
return ReportIllegal(action->type,field);
}
static LookupEntry groupNames[] = {
{ "group1", 1 },
{ "group2", 2 },
{ "group3", 3 },
{ "group4", 4 },
{ "group5", 5 },
{ "group6", 6 },
{ "group7", 7 },
{ "group8", 8 },
{ NULL, 0 },
};
static Bool
CheckGroupField( unsigned action,
ExprDef * value,
unsigned * flags_inout,
int * grp_rtrn)
{
ExprDef * spec;
ExprResult rtrn;
if ((value->op==OpNegate)||(value->op==OpUnaryPlus)) {
*flags_inout&= ~XkbSA_GroupAbsolute;
spec= value->value.child;
}
else {
*flags_inout|= XkbSA_GroupAbsolute;
spec= value;
}
if (!ExprResolveInteger(spec,&rtrn,SimpleLookup,(XPointer)groupNames))
return ReportMismatch(action,F_Group,"integer (range 1..8)");
if ((rtrn.ival<1)||(rtrn.ival>XkbNumKbdGroups)) {
ERROR2("Illegal group %d (must be in the range 1..%d)\n",rtrn.ival,
XkbNumKbdGroups);
ACTION1("Action %s definition ignored\n",
XkbActionTypeText(action,XkbMessage));
return False;
}
if (value->op==OpNegate) *grp_rtrn= -rtrn.ival;
else if (value->op==OpUnaryPlus) *grp_rtrn= rtrn.ival;
else *grp_rtrn= rtrn.ival-1;
return True;
}
static Bool
HandleSetLatchGroup( XkbDescPtr xkb,
XkbAnyAction * action,
unsigned field,
ExprDef * array_ndx,
ExprDef * value)
{
XkbGroupAction * act;
unsigned rtrn;
unsigned t1;
int t2;
act= (XkbGroupAction *)action;
if (array_ndx!=NULL) {
switch (field) {
case F_ClearLocks: case F_LatchToLock:
case F_Group:
return ReportActionNotArray(action->type,field);
}
}
switch (field) {
case F_ClearLocks:
case F_LatchToLock:
rtrn= act->flags;
if (CheckLatchLockFlags(action->type,field,value,&rtrn)) {
act->flags= rtrn;
return True;
}
return False;
case F_Group:
t1= act->flags;
if (CheckGroupField(action->type,value,&t1,&t2)) {
act->flags= t1;
XkbSASetGroup(act,t2);
return True;
}
return False;
}
return ReportIllegal(action->type,field);
}
static Bool
HandleLockGroup( XkbDescPtr xkb,
XkbAnyAction * action,
unsigned field,
ExprDef * array_ndx,
ExprDef * value)
{
XkbGroupAction * act;
unsigned t1;
int t2;
act= (XkbGroupAction *)action;
if ((array_ndx!=NULL) && (field==F_Group))
return ReportActionNotArray(action->type,field);
if (field==F_Group) {
t1= act->flags;
if (CheckGroupField(action->type,value,&t1,&t2)) {
act->flags= t1;
XkbSASetGroup(act,t2);
return True;
}
return False;
}
return ReportIllegal(action->type,field);
}
static Bool
HandleMovePtr( XkbDescPtr xkb,
XkbAnyAction * action,
unsigned field,
ExprDef * array_ndx,
ExprDef * value)
{
ExprResult rtrn;
XkbPtrAction * act;
Bool absolute;
act= (XkbPtrAction *)action;
if ((array_ndx!=NULL)&&((field==F_X)||(field==F_Y)))
return ReportActionNotArray(action->type,field);
if ((field==F_X)||(field==F_Y)) {
if ((value->op==OpNegate)||(value->op==OpUnaryPlus))
absolute= False;
else absolute= True;
if (!ExprResolveInteger(value,&rtrn,NULL,NULL))
return ReportMismatch(action->type,field,"integer");
if (field==F_X) {
if (absolute)
act->flags|= XkbSA_MoveAbsoluteX;
XkbSetPtrActionX(act,rtrn.ival);
}
else {
if (absolute)
act->flags|= XkbSA_MoveAbsoluteY;
XkbSetPtrActionY(act,rtrn.ival);
}
return True;
}
else if (field==F_Accel) {
if (!ExprResolveBoolean(value,&rtrn,NULL,NULL))
return ReportMismatch(action->type,field,"boolean");
if (rtrn.uval) act->flags&= ~XkbSA_NoAcceleration;
else act->flags|= XkbSA_NoAcceleration;
}
return ReportIllegal(action->type,field);
}
static LookupEntry btnNames[] = {
{ "button1", 1 },
{ "button2", 2 },
{ "button3", 3 },
{ "button4", 4 },
{ "button5", 5 },
{ "default", 0 },
{ NULL, 0 }
};
static LookupEntry lockWhich[] = {
{ "both", 0 },
{ "lock", XkbSA_LockNoUnlock },
{ "neither", (XkbSA_LockNoLock|XkbSA_LockNoUnlock) },
{ "unlock", XkbSA_LockNoLock },
{ NULL, 0 }
};
static Bool
HandlePtrBtn( XkbDescPtr xkb,
XkbAnyAction * action,
unsigned field,
ExprDef * array_ndx,
ExprDef * value)
{
ExprResult rtrn;
XkbPtrBtnAction * act;
act= (XkbPtrBtnAction *)action;
if (field==F_Button) {
if (array_ndx!=NULL)
return ReportActionNotArray(action->type,field);
if (!ExprResolveInteger(value,&rtrn,SimpleLookup,(XPointer)btnNames))
return ReportMismatch(action->type,field,"integer (range 1..5)");
if ((rtrn.ival<0)||(rtrn.ival>5)) {
ERROR("Button must specify default or be in the range 1..5\n");
ACTION1("Illegal button value %d ignored\n",rtrn.ival);
return False;
}
act->button= rtrn.ival;
return True;
}
else if ((action->type==XkbSA_LockPtrBtn)&&(field==F_Affect)) {
if (array_ndx!=NULL)
return ReportActionNotArray(action->type,field);
if (!ExprResolveEnum(value,&rtrn,lockWhich))
return ReportMismatch(action->type,field,"lock or unlock");
act->flags&= ~(XkbSA_LockNoLock|XkbSA_LockNoUnlock);
act->flags|= rtrn.ival;
return True;
}
else if (field==F_Count) {
if (array_ndx!=NULL)
return ReportActionNotArray(action->type,field);
if (!ExprResolveInteger(value,&rtrn,SimpleLookup,(XPointer)btnNames))
return ReportMismatch(action->type,field,"integer");
if ((rtrn.ival<0)||(rtrn.ival>255)) {
ERROR("The count field must have a value in the range 0..255\n");
ACTION1("Illegal count %d ignored\n",rtrn.ival);
return False;
}
act->count= rtrn.ival;
return True;
}
return ReportIllegal(action->type,field);
}
static LookupEntry ptrDflts[] = {
{ "dfltbtn", XkbSA_AffectDfltBtn },
{ "defaultbutton", XkbSA_AffectDfltBtn },
{ "button", XkbSA_AffectDfltBtn },
{ NULL, 0 }
};
static Bool
HandleSetPtrDflt( XkbDescPtr xkb,
XkbAnyAction * action,
unsigned field,
ExprDef * array_ndx,
ExprDef * value)
{
ExprResult rtrn;
XkbPtrDfltAction * act;
act= (XkbPtrDfltAction *)action;
if (field==F_Affect) {
if (array_ndx!=NULL)
return ReportActionNotArray(action->type,field);
if (!ExprResolveEnum(value,&rtrn,ptrDflts))
return ReportMismatch(action->type,field,"pointer component");
act->affect= rtrn.uval;
return True;
}
else if ((field==F_Button)||(field==F_Value)) {
ExprDef *btn;
if (array_ndx!=NULL)
return ReportActionNotArray(action->type,field);
if ((value->op==OpNegate)||(value->op==OpUnaryPlus)) {
act->flags&= ~XkbSA_DfltBtnAbsolute;
btn= value->value.child;
}
else {
act->flags|= XkbSA_DfltBtnAbsolute;
btn= value;
}
if (!ExprResolveInteger(btn,&rtrn,SimpleLookup,(XPointer)btnNames))
return ReportMismatch(action->type,field,"integer (range 1..5)");
if ((rtrn.ival<0)||(rtrn.ival>5)) {
ERROR("New default button value must be in the range 1..5\n");
ACTION1("Illegal default button value %d ignored\n",rtrn.ival);
return False;
}
if (rtrn.ival==0) {
ERROR("Cannot set default pointer button to \"default\"\n");
ACTION("Illegal default button setting ignored\n");
return False;
}
if (value->op==OpNegate)
XkbSASetPtrDfltValue(act,-rtrn.ival);
else XkbSASetPtrDfltValue(act,rtrn.ival);
return True;
}
return ReportIllegal(action->type,field);
}
static LookupEntry isoNames[] = {
{ "mods", XkbSA_ISONoAffectMods },
{ "modifiers", XkbSA_ISONoAffectMods },
{ "group", XkbSA_ISONoAffectGroup },
{ "groups", XkbSA_ISONoAffectGroup },
{ "ptr", XkbSA_ISONoAffectPtr },
{ "pointer", XkbSA_ISONoAffectPtr },
{ "ctrls", XkbSA_ISONoAffectCtrls },
{ "controls", XkbSA_ISONoAffectCtrls },
{ "all", ~((unsigned)0) },
{ "none", 0 },
{ NULL, 0 },
};
static Bool
HandleISOLock( XkbDescPtr xkb,
XkbAnyAction * action,
unsigned field,
ExprDef * array_ndx,
ExprDef * value)
{
ExprResult rtrn;
XkbISOAction * act;
unsigned flags,mods;
int group;
act= (XkbISOAction *)action;
switch (field) {
case F_Modifiers:
if (array_ndx!=NULL)
return ReportActionNotArray(action->type,field);
flags= act->flags;
if (CheckModifierField(xkb,action->type,value,&flags,&mods)) {
act->flags= flags&(~XkbSA_ISODfltIsGroup);
act->real_mods= mods&0xff;
mods= (mods>>8)&0xff;
XkbSetModActionVMods(act,mods);
return True;
}
return False;
case F_Group:
if (array_ndx!=NULL)
return ReportActionNotArray(action->type,field);
flags= act->flags;
if (CheckGroupField(action->type,value,&flags,&group)) {
act->flags= flags|XkbSA_ISODfltIsGroup;
XkbSASetGroup(act,group);
return True;
}
return False;
case F_Affect:
if (array_ndx!=NULL)
return ReportActionNotArray(action->type,field);
if (!ExprResolveMask(value,&rtrn,SimpleLookup,(XPointer)isoNames))
return ReportMismatch(action->type,field,"keyboard component");
act->affect= (~rtrn.uval)&XkbSA_ISOAffectMask;
return True;
}
return ReportIllegal(action->type,field);
}
static Bool
HandleSwitchScreen( XkbDescPtr xkb,
XkbAnyAction * action,
unsigned field,
ExprDef * array_ndx,
ExprDef * value)
{
ExprResult rtrn;
XkbSwitchScreenAction * act;
act= (XkbSwitchScreenAction *)action;
if (field==F_Screen) {
ExprDef *scrn;
if (array_ndx!=NULL)
return ReportActionNotArray(action->type,field);
if ((value->op==OpNegate)||(value->op==OpUnaryPlus)) {
act->flags&= ~XkbSA_SwitchAbsolute;
scrn= value->value.child;
}
else {
act->flags|= XkbSA_SwitchAbsolute;
scrn= value;
}
if (!ExprResolveInteger(scrn,&rtrn,NULL,NULL))
return ReportMismatch(action->type,field,"integer (0..255)");
if ((rtrn.ival<0)||(rtrn.ival>255)) {
ERROR("Screen index must be in the range 1..255\n");
ACTION1("Illegal screen value %d ignored\n",rtrn.ival);
return False;
}
if (value->op==OpNegate)
XkbSASetScreen(act,-rtrn.ival);
else XkbSASetScreen(act,rtrn.ival);
return True;
}
else if (field==F_Same) {
if (array_ndx!=NULL)
return ReportActionNotArray(action->type,field);
if (!ExprResolveBoolean(value,&rtrn,NULL,NULL))
return ReportMismatch(action->type,field,"boolean");
if (rtrn.uval) act->flags&= ~XkbSA_SwitchApplication;
else act->flags|= XkbSA_SwitchApplication;
return True;
}
return ReportIllegal(action->type,field);
}
LookupEntry ctrlNames[]= {
{ "repeatkeys", XkbRepeatKeysMask },
{ "repeat", XkbRepeatKeysMask },
{ "autorepeat", XkbRepeatKeysMask },
{ "slowkeys", XkbSlowKeysMask },
{ "bouncekeys", XkbBounceKeysMask },
{ "stickykeys", XkbStickyKeysMask },
{ "mousekeys", XkbMouseKeysMask },
{ "mousekeysaccel", XkbMouseKeysAccelMask },
{ "accessxkeys", XkbAccessXKeysMask },
{ "accessxtimeout", XkbAccessXTimeoutMask },
{ "accessxfeedback", XkbAccessXFeedbackMask },
{ "audiblebell", XkbAudibleBellMask },
{ "overlay1", XkbOverlay1Mask },
{ "overlay2", XkbOverlay2Mask },
{ "ignoregrouplock", XkbIgnoreGroupLockMask },
{ "all", XkbAllBooleanCtrlsMask },
{ "none", 0 },
{ NULL, 0 }
};
static Bool
HandleSetLockControls( XkbDescPtr xkb,
XkbAnyAction * action,
unsigned field,
ExprDef * array_ndx,
ExprDef * value)
{
ExprResult rtrn;
XkbCtrlsAction * act;
act= (XkbCtrlsAction *)action;
if (field==F_Controls) {
if (array_ndx!=NULL)
return ReportActionNotArray(action->type,field);
if (!ExprResolveMask(value,&rtrn,SimpleLookup,(XPointer)ctrlNames))
return ReportMismatch(action->type,field,"controls mask");
XkbActionSetCtrls(act,rtrn.uval);
return True;
}
return ReportIllegal(action->type,field);
}
static LookupEntry evNames[]= {
{ "press", XkbSA_MessageOnPress },
{ "keypress", XkbSA_MessageOnPress },
{ "release", XkbSA_MessageOnRelease },
{ "keyrelease", XkbSA_MessageOnRelease },
{ "all", XkbSA_MessageOnPress|XkbSA_MessageOnRelease },
{ "none", 0 },
{ NULL, 0 }
};
static Bool
HandleActionMessage( XkbDescPtr xkb,
XkbAnyAction * action,
unsigned field,
ExprDef * array_ndx,
ExprDef * value)
{
ExprResult rtrn;
XkbMessageAction * act;
act= (XkbMessageAction *)action;
switch (field) {
case F_Report:
if (array_ndx!=NULL)
return ReportActionNotArray(action->type,field);
if (!ExprResolveMask(value,&rtrn,SimpleLookup,(XPointer)evNames))
return ReportMismatch(action->type,field,"key event mask");
act->flags&= ~(XkbSA_MessageOnPress|XkbSA_MessageOnRelease);
act->flags= rtrn.uval&(XkbSA_MessageOnPress|XkbSA_MessageOnRelease);
return True;
case F_GenKeyEvent:
if (array_ndx!=NULL)
return ReportActionNotArray(action->type,field);
if (!ExprResolveBoolean(value,&rtrn,NULL,NULL))
return ReportMismatch(action->type,field,"boolean");
if (rtrn.uval) act->flags|= XkbSA_MessageGenKeyEvent;
else act->flags&= ~XkbSA_MessageGenKeyEvent;
return True;
case F_Data:
if (array_ndx==NULL) {
if (!ExprResolveString(value,&rtrn,NULL,NULL))
return ReportMismatch(action->type,field,"string");
else {
int len= strlen(rtrn.str);
if ((len<1)||(len>6)) {
WARN("An action message can hold only 6 bytes\n");
ACTION1("Extra %d bytes ignored\n",len-6);
}
strncpy((char *)act->message,rtrn.str,6);
}
return True;
}
else {
unsigned ndx;
if (!ExprResolveInteger(array_ndx,&rtrn,NULL,NULL)) {
ERROR("Array subscript must be integer\n");
ACTION("Illegal subscript ignored\n");
return False;
}
ndx= rtrn.uval;
if (ndx>5) {
ERROR("An action message is at most 6 bytes long\n");
ACTION1("Attempt to use data[%d] ignored\n",ndx);
return False;
}
if (!ExprResolveInteger(value,&rtrn,NULL,NULL))
return ReportMismatch(action->type,field,"integer");
if ((rtrn.ival<0)||(rtrn.ival>255)) {
ERROR("Message data must be in the range 0..255\n");
ACTION1("Illegal datum %d ignored\n",rtrn.ival);
return False;
}
act->message[ndx]= rtrn.uval;
}
return True;
}
return ReportIllegal(action->type,field);
}
static Bool
HandleRedirectKey( XkbDescPtr xkb,
XkbAnyAction * action,
unsigned field,
ExprDef * array_ndx,
ExprDef * value)
{
ExprResult rtrn;
XkbRedirectKeyAction * act;
unsigned t1,t2,vmods,vmask;
unsigned long tmp;
if (array_ndx!=NULL)
return ReportActionNotArray(action->type,field);
act= (XkbRedirectKeyAction *)action;
switch (field) {
case F_Keycode:
if (!ExprResolveKeyName(value,&rtrn,NULL,NULL))
return ReportMismatch(action->type,field,"key name");
tmp= KeyNameToLong(rtrn.keyName.name);
if (!FindNamedKey(xkb,tmp,&t1,True,CreateKeyNames(xkb),0)) {
return ReportNotFound(action->type,field,"Key",
XkbKeyNameText(rtrn.keyName.name,XkbMessage));
}
act->new_key= t1;
return True;
case F_ModsToClear:
case F_Modifiers:
t1= 0;
if (CheckModifierField(xkb,action->type,value,&t1,&t2)) {
act->mods_mask|= (t2&0xff);
if (field==F_Modifiers)
act->mods|= (t2&0xff);
else act->mods&= ~(t2&0xff);
t2= (t2>>8)&0xffff;
vmods= XkbSARedirectVMods(act);
vmask= XkbSARedirectVModsMask(act);
vmask|= t2;
if (field==F_Modifiers)
vmods|= t2;
else vmods&= ~t2;
XkbSARedirectSetVMods(act,vmods);
XkbSARedirectSetVModsMask(act,vmask);
return True;
}
return True;
}
return ReportIllegal(action->type,field);
}
static Bool
HandleDeviceBtn( XkbDescPtr xkb,
XkbAnyAction * action,
unsigned field,
ExprDef * array_ndx,
ExprDef * value)
{
ExprResult rtrn;
XkbDeviceBtnAction * act;
act= (XkbDeviceBtnAction *)action;
if (field==F_Button) {
if (array_ndx!=NULL)
return ReportActionNotArray(action->type,field);
if (!ExprResolveInteger(value,&rtrn,NULL,NULL))
return ReportMismatch(action->type,field,"integer (range 1..255)");
if ((rtrn.ival<0)||(rtrn.ival>255)) {
ERROR("Button must specify default or be in the range 1..255\n");
ACTION1("Illegal button value %d ignored\n",rtrn.ival);
return False;
}
act->button= rtrn.ival;
return True;
}
else if ((action->type==XkbSA_LockDeviceBtn)&&(field==F_Affect)) {
if (array_ndx!=NULL)
return ReportActionNotArray(action->type,field);
if (!ExprResolveEnum(value,&rtrn,lockWhich))
return ReportMismatch(action->type,field,"lock or unlock");
act->flags&= ~(XkbSA_LockNoLock|XkbSA_LockNoUnlock);
act->flags|= rtrn.ival;
return True;
}
else if (field==F_Count) {
if (array_ndx!=NULL)
return ReportActionNotArray(action->type,field);
if (!ExprResolveInteger(value,&rtrn,SimpleLookup,(XPointer)btnNames))
return ReportMismatch(action->type,field,"integer");
if ((rtrn.ival<0)||(rtrn.ival>255)) {
ERROR("The count field must have a value in the range 0..255\n");
ACTION1("Illegal count %d ignored\n",rtrn.ival);
return False;
}
act->count= rtrn.ival;
return True;
}
else if (field==F_Device) {
if (array_ndx!=NULL)
return ReportActionNotArray(action->type,field);
if (!ExprResolveInteger(value,&rtrn,NULL,NULL))
return ReportMismatch(action->type,field,"integer (range 1..255)");
if ((rtrn.ival<0)||(rtrn.ival>255)) {
ERROR("Device must specify default or be in the range 1..255\n");
ACTION1("Illegal device value %d ignored\n",rtrn.ival);
return False;
}
act->device= rtrn.ival;
return True;
}
return ReportIllegal(action->type,field);
}
static Bool
HandleDeviceValuator( XkbDescPtr xkb,
XkbAnyAction * action,
unsigned field,
ExprDef * array_ndx,
ExprDef * value)
{
#if 0
ExprResult rtrn;
XkbDeviceValuatorAction * act;
act= (XkbDeviceValuatorAction *)action;
#endif
return False;
}
static Bool
HandlePrivate( XkbDescPtr xkb,
XkbAnyAction * action,
unsigned field,
ExprDef * array_ndx,
ExprDef * value)
{
ExprResult rtrn;
switch (field) {
case F_Type:
if (!ExprResolveInteger(value,&rtrn,NULL,NULL))
return ReportMismatch(PrivateAction,field,"integer");
if ((rtrn.ival<0)||(rtrn.ival>255)) {
ERROR("Private action type must be in the range 0..255\n");
ACTION1("Illegal type %d ignored\n",rtrn.ival);
return False;
}
action->type= rtrn.uval;
return True;
case F_Data:
if (array_ndx==NULL) {
if (!ExprResolveString(value,&rtrn,NULL,NULL))
return ReportMismatch(action->type,field,"string");
else {
int len= strlen(rtrn.str);
if ((len<1)||(len>7)) {
WARN("A private action has 7 data bytes\n");
ACTION1("Extra %d bytes ignored\n",len-6);
return False;
}
strncpy((char *)action->data,rtrn.str,7);
}
return True;
}
else {
unsigned ndx;
if (!ExprResolveInteger(array_ndx,&rtrn,NULL,NULL)) {
ERROR("Array subscript must be integer\n");
ACTION("Illegal subscript ignored\n");
return False;
}
ndx= rtrn.uval;
if (ndx>6) {
ERROR("The data for a private action is 7 bytes long\n");
ACTION1("Attempt to use data[%d] ignored\n",ndx);
return False;
}
if (!ExprResolveInteger(value,&rtrn,NULL,NULL))
return ReportMismatch(action->type,field,"integer");
if ((rtrn.ival<0)||(rtrn.ival>255)) {
ERROR("All data for a private action must be 0..255\n");
ACTION1("Illegal datum %d ignored\n",rtrn.ival);
return False;
}
action->data[ndx]= rtrn.uval;
return True;
}
}
return ReportIllegal(PrivateAction,field);
}
typedef Bool (*actionHandler)(
XkbDescPtr ,
XkbAnyAction * ,
unsigned ,
ExprDef * ,
ExprDef *
);
static actionHandler handleAction[XkbSA_NumActions+1] = {
HandleNoAction ,
HandleSetLatchMods ,
HandleSetLatchMods ,
HandleLockMods ,
HandleSetLatchGroup ,
HandleSetLatchGroup ,
HandleLockGroup ,
HandleMovePtr ,
HandlePtrBtn ,
HandlePtrBtn ,
HandleSetPtrDflt ,
HandleISOLock ,
HandleNoAction ,
HandleSwitchScreen ,
HandleSetLockControls ,
HandleSetLockControls ,
HandleActionMessage ,
HandleRedirectKey ,
HandleDeviceBtn ,
HandleDeviceBtn ,
HandleDeviceValuator ,
HandlePrivate
};
static void
ApplyActionFactoryDefaults(XkbAction *action)
{
if (action->type==XkbSA_SetPtrDflt) {
action->dflt.affect= XkbSA_AffectDfltBtn;
action->dflt.flags= 0;
XkbSASetPtrDfltValue(&action->dflt,1);
}
else if (action->type==XkbSA_ISOLock) {
action->iso.real_mods= LockMask;
}
return;
}
int
HandleActionDef( ExprDef * def,
XkbDescPtr xkb,
XkbAnyAction * action,
unsigned mergeMode,
ActionInfo * info)
{
ExprDef * arg;
register char * str;
unsigned tmp,hndlrType;
if (!actionsInitialized)
ActionsInit();
if (def->op!=ExprActionDecl) {
ERROR1("Expected an action definition, found %s\n",exprOpText(def->op));
return False;
}
str= XkbAtomGetString(NULL,def->value.action.name);
if (!str) {
WSGO("Missing name in action definition!!\n");
return False;
}
if (!stringToAction(str,&tmp)) {
ERROR1("Unknown action %s\n",str);
return False;
}
action->type= hndlrType= tmp;
if (action->type!=XkbSA_NoAction) {
ApplyActionFactoryDefaults((XkbAction *)action);
while (info) {
if ((info->action==XkbSA_NoAction)||(info->action==hndlrType)) {
if (!(*handleAction[hndlrType])(xkb,action,
info->field,info->array_ndx,
info->value)) {
return False;
}
}
info= info->next;
}
}
for (arg=def->value.action.args;arg!=NULL;arg=(ExprDef*)arg->common.next) {
ExprDef *field,*value,*arrayRtrn;
ExprResult elemRtrn,fieldRtrn;
unsigned fieldNdx;
if (arg->op==OpAssign) {
field= arg->value.binary.left;
value= arg->value.binary.right;
}
else {
if ((arg->op==OpNot)||(arg->op==OpInvert)) {
field= arg->value.child;
value= &constFalse;
}
else {
field= arg;
value= &constTrue;
}
}
if (!ExprResolveLhs(field,&elemRtrn,&fieldRtrn,&arrayRtrn))
return False;
if (elemRtrn.str!=NULL) {
ERROR("Cannot change defaults in an action definition\n");
ACTION2("Ignoring attempt to change %s.%s\n",elemRtrn.str,
fieldRtrn.str);
return False;
}
if (!stringToField(fieldRtrn.str,&fieldNdx)) {
ERROR1("Unknown field name %s\n",uStringText(fieldRtrn.str));
return False;
}
if (!(*handleAction[hndlrType])(xkb,action,fieldNdx,arrayRtrn,value)) {
return False;
}
}
return True;
}
int
SetActionField( XkbDescPtr xkb,
char * elem,
char * field,
ExprDef * array_ndx,
ExprDef * value,
ActionInfo ** info_rtrn)
{
ActionInfo *new,*old;
if (!actionsInitialized)
ActionsInit();
new= uTypedAlloc(ActionInfo);
if (new==NULL) {
WSGO("Couldn't allocate space for action default\n");
return False;
}
if (uStrCaseCmp(elem,"action")==0)
new->action= XkbSA_NoAction;
else {
if (!stringToAction(elem,&new->action))
return False;
if (new->action==XkbSA_NoAction) {
ERROR1("\"%s\" is not a valid field in a NoAction action\n",field);
return False;
}
}
if (!stringToField(field,&new->field)) {
ERROR1("\"%s\" is not a legal field name\n",field);
return False;
}
new->array_ndx= array_ndx;
new->value= value;
new->next= NULL;
old= *info_rtrn;
while ((old)&&(old->next))
old= old->next;
if (old==NULL) *info_rtrn= new;
else old->next= new;
return True;
}
void
ActionsInit(void)
{
if (!actionsInitialized) {
bzero((char *)&constTrue,sizeof(constTrue));
bzero((char *)&constFalse,sizeof(constFalse));
constTrue.common.stmtType= StmtExpr;
constTrue.common.next= NULL;
constTrue.op= ExprIdent;
constTrue.type= TypeBoolean;
constTrue.value.str= XkbInternAtom(NULL,"true",False);
constFalse.common.stmtType= StmtExpr;
constFalse.common.next= NULL;
constFalse.op= ExprIdent;
constFalse.type= TypeBoolean;
constFalse.value.str= XkbInternAtom(NULL,"false",False);
actionsInitialized= 1;
}
return;
}