action.c revision f46a6179
1/* $Xorg: action.c,v 1.3 2000/08/17 19:54:30 cpqbld Exp $ */
2/************************************************************
3 Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
4
5 Permission to use, copy, modify, and distribute this
6 software and its documentation for any purpose and without
7 fee is hereby granted, provided that the above copyright
8 notice appear in all copies and that both that copyright
9 notice and this permission notice appear in supporting
10 documentation, and that the name of Silicon Graphics not be
11 used in advertising or publicity pertaining to distribution
12 of the software without specific prior written permission.
13 Silicon Graphics makes no representation about the suitability
14 of this software for any purpose. It is provided "as is"
15 without any express or implied warranty.
16
17 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
18 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
19 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
20 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
21 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
22 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
23 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
24 THE USE OR PERFORMANCE OF THIS SOFTWARE.
25
26 ********************************************************/
27/* $XFree86: xc/programs/xkbcomp/action.c,v 3.10tsi Exp $ */
28
29#include "xkbcomp.h"
30#include "tokens.h"
31#include "expr.h"
32
33#include "keycodes.h"
34#include "vmod.h"
35#include "misc.h"
36#include "action.h"
37#include "misc.h"
38
39static Bool	actionsInitialized;
40static ExprDef	constTrue;
41static ExprDef	constFalse;
42
43/***====================================================================***/
44
45static Bool
46stringToAction(char *str,unsigned *type_rtrn)
47{
48    if (str==NULL)
49	return False;
50
51    if (uStrCaseCmp(str,"noaction")==0)	 	*type_rtrn= XkbSA_NoAction;
52    else if (uStrCaseCmp(str,"setmods")==0)	*type_rtrn= XkbSA_SetMods;
53    else if (uStrCaseCmp(str,"latchmods")==0)	*type_rtrn= XkbSA_LatchMods;
54    else if (uStrCaseCmp(str,"lockmods")==0)	*type_rtrn= XkbSA_LockMods;
55    else if (uStrCaseCmp(str,"setgroup")==0)	*type_rtrn= XkbSA_SetGroup;
56    else if (uStrCaseCmp(str,"latchgroup")==0)	*type_rtrn= XkbSA_LatchGroup;
57    else if (uStrCaseCmp(str,"lockgroup")==0)	*type_rtrn= XkbSA_LockGroup;
58    else if (uStrCaseCmp(str,"moveptr")==0)	*type_rtrn= XkbSA_MovePtr;
59    else if (uStrCaseCmp(str,"movepointer")==0)	*type_rtrn= XkbSA_MovePtr;
60    else if (uStrCaseCmp(str,"ptrbtn")==0)	*type_rtrn= XkbSA_PtrBtn;
61    else if (uStrCaseCmp(str,"pointerbutton")==0)
62						*type_rtrn= XkbSA_PtrBtn;
63    else if (uStrCaseCmp(str,"lockptrbtn")==0)	*type_rtrn= XkbSA_LockPtrBtn;
64    else if (uStrCaseCmp(str,"lockpointerbutton")==0)
65						*type_rtrn= XkbSA_LockPtrBtn;
66    else if (uStrCaseCmp(str,"lockptrbutton")==0)
67						*type_rtrn= XkbSA_LockPtrBtn;
68    else if (uStrCaseCmp(str,"lockpointerbtn")==0)
69						*type_rtrn= XkbSA_LockPtrBtn;
70    else if (uStrCaseCmp(str,"setptrdflt")==0)	*type_rtrn= XkbSA_SetPtrDflt;
71    else if (uStrCaseCmp(str,"setpointerdefault")==0)
72						*type_rtrn= XkbSA_SetPtrDflt;
73    else if (uStrCaseCmp(str,"isolock")==0)	*type_rtrn= XkbSA_ISOLock;
74    else if (uStrCaseCmp(str,"terminate")==0)	*type_rtrn= XkbSA_Terminate;
75    else if (uStrCaseCmp(str,"terminateserver")==0)
76						*type_rtrn= XkbSA_Terminate;
77    else if (uStrCaseCmp(str,"switchscreen")==0)*type_rtrn= XkbSA_SwitchScreen;
78    else if (uStrCaseCmp(str,"setcontrols")==0)	*type_rtrn= XkbSA_SetControls;
79    else if (uStrCaseCmp(str,"lockcontrols")==0)*type_rtrn= XkbSA_LockControls;
80    else if (uStrCaseCmp(str,"actionmessage")==0)*type_rtrn= XkbSA_ActionMessage;
81    else if (uStrCaseCmp(str,"messageaction")==0)*type_rtrn= XkbSA_ActionMessage;
82    else if (uStrCaseCmp(str,"message")==0)	*type_rtrn= XkbSA_ActionMessage;
83    else if (uStrCaseCmp(str,"redirect")==0)	*type_rtrn= XkbSA_RedirectKey;
84    else if (uStrCaseCmp(str,"redirectkey")==0)	*type_rtrn= XkbSA_RedirectKey;
85    else if (uStrCaseCmp(str,"devbtn")==0)	*type_rtrn= XkbSA_DeviceBtn;
86    else if (uStrCaseCmp(str,"devicebtn")==0)	*type_rtrn= XkbSA_DeviceBtn;
87    else if (uStrCaseCmp(str,"devbutton")==0)	*type_rtrn= XkbSA_DeviceBtn;
88    else if (uStrCaseCmp(str,"devicebutton")==0)*type_rtrn= XkbSA_DeviceBtn;
89    else if (uStrCaseCmp(str,"lockdevbtn")==0)	*type_rtrn= XkbSA_DeviceBtn;
90    else if (uStrCaseCmp(str,"lockdevicebtn")==0)
91						*type_rtrn= XkbSA_LockDeviceBtn;
92    else if (uStrCaseCmp(str,"lockdevbutton")==0)
93						*type_rtrn= XkbSA_LockDeviceBtn;
94    else if (uStrCaseCmp(str,"lockdevicebutton")==0)
95						*type_rtrn= XkbSA_LockDeviceBtn;
96    else if (uStrCaseCmp(str,"devval")==0)	*type_rtrn=XkbSA_DeviceValuator;
97    else if (uStrCaseCmp(str,"deviceval")==0)	*type_rtrn=XkbSA_DeviceValuator;
98    else if (uStrCaseCmp(str,"devvaluator")==0)	*type_rtrn=XkbSA_DeviceValuator;
99    else if (uStrCaseCmp(str,"devicevaluator")==0)
100						*type_rtrn=XkbSA_DeviceValuator;
101    else if (uStrCaseCmp(str,"private")==0)	*type_rtrn= PrivateAction;
102    else return False;
103    return True;
104}
105
106static Bool
107stringToField(char *str,unsigned *field_rtrn)
108{
109
110    if (str==NULL)
111	return False;
112
113    if (uStrCaseCmp(str,"clearlocks")==0)	*field_rtrn= F_ClearLocks;
114    else if (uStrCaseCmp(str,"latchtolock")==0)	*field_rtrn= F_LatchToLock;
115    else if (uStrCaseCmp(str,"genkeyevent")==0)	*field_rtrn= F_GenKeyEvent;
116    else if (uStrCaseCmp(str,"generatekeyevent")==0)
117						*field_rtrn= F_GenKeyEvent;
118    else if (uStrCaseCmp(str,"report")==0)	*field_rtrn= F_Report;
119    else if (uStrCaseCmp(str,"default")==0)	*field_rtrn= F_Default;
120    else if (uStrCaseCmp(str,"affect")==0)	*field_rtrn= F_Affect;
121    else if (uStrCaseCmp(str,"increment")==0)	*field_rtrn= F_Increment;
122    else if (uStrCaseCmp(str,"mods")==0)	*field_rtrn= F_Modifiers;
123    else if (uStrCaseCmp(str,"modifiers")==0)	*field_rtrn= F_Modifiers;
124    else if (uStrCaseCmp(str,"group")==0)	*field_rtrn= F_Group;
125    else if (uStrCaseCmp(str,"x")==0)		*field_rtrn= F_X;
126    else if (uStrCaseCmp(str,"y")==0)		*field_rtrn= F_Y;
127    else if (uStrCaseCmp(str,"accel")==0)	*field_rtrn= F_Accel;
128    else if (uStrCaseCmp(str,"accelerate")==0)	*field_rtrn= F_Accel;
129    else if (uStrCaseCmp(str,"repeat")==0)	*field_rtrn= F_Accel;
130    else if (uStrCaseCmp(str,"button")==0)	*field_rtrn= F_Button;
131    else if (uStrCaseCmp(str,"value")==0)	*field_rtrn= F_Value;
132    else if (uStrCaseCmp(str,"controls")==0)	*field_rtrn= F_Controls;
133    else if (uStrCaseCmp(str,"ctrls")==0)	*field_rtrn= F_Controls;
134    else if (uStrCaseCmp(str,"type")==0)	*field_rtrn= F_Type;
135    else if (uStrCaseCmp(str,"count")==0)	*field_rtrn= F_Count;
136    else if (uStrCaseCmp(str,"screen")==0)	*field_rtrn= F_Screen;
137    else if (uStrCaseCmp(str,"same")==0)	*field_rtrn= F_Same;
138    else if (uStrCaseCmp(str,"sameserver")==0)	*field_rtrn= F_Same;
139    else if (uStrCaseCmp(str,"data")==0)	*field_rtrn= F_Data;
140    else if (uStrCaseCmp(str,"device")==0)	*field_rtrn= F_Device;
141    else if (uStrCaseCmp(str,"dev")==0)		*field_rtrn= F_Device;
142    else if (uStrCaseCmp(str,"key")==0)		*field_rtrn= F_Keycode;
143    else if (uStrCaseCmp(str,"keycode")==0)	*field_rtrn= F_Keycode;
144    else if (uStrCaseCmp(str,"kc")==0)		*field_rtrn= F_Keycode;
145    else if (uStrCaseCmp(str,"clearmods")==0)	*field_rtrn= F_ModsToClear;
146    else if (uStrCaseCmp(str,"clearmodifiers")==0) *field_rtrn= F_ModsToClear;
147    else return False;
148    return True;
149}
150
151static char *
152fieldText(unsigned field)
153{
154static char buf[32];
155
156    switch (field) {
157	case F_ClearLocks:	strcpy(buf,"clearLocks"); break;
158	case F_LatchToLock:	strcpy(buf,"latchToLock"); break;
159	case F_GenKeyEvent:	strcpy(buf,"genKeyEvent"); break;
160	case F_Report:		strcpy(buf,"report"); break;
161	case F_Default:		strcpy(buf,"default"); break;
162	case F_Affect:		strcpy(buf,"affect"); break;
163	case F_Increment:	strcpy(buf,"increment"); break;
164	case F_Modifiers:	strcpy(buf,"modifiers"); break;
165	case F_Group:		strcpy(buf,"group"); break;
166	case F_X:		strcpy(buf,"x"); break;
167	case F_Y:		strcpy(buf,"y"); break;
168	case F_Accel:		strcpy(buf,"accel"); break;
169	case F_Button:		strcpy(buf,"button"); break;
170	case F_Value:		strcpy(buf,"value"); break;
171	case F_Controls:	strcpy(buf,"controls"); break;
172	case F_Type:		strcpy(buf,"type"); break;
173	case F_Count:		strcpy(buf,"count"); break;
174	case F_Screen:		strcpy(buf,"screen"); break;
175	case F_Same:		strcpy(buf,"sameServer"); break;
176	case F_Data:		strcpy(buf,"data"); break;
177	case F_Device:		strcpy(buf,"device"); break;
178	case F_Keycode:		strcpy(buf,"keycode"); break;
179	case F_ModsToClear:	strcpy(buf,"clearmods"); break;
180	default:		strcpy(buf,"unknown"); break;
181    }
182    return buf;
183}
184
185/***====================================================================***/
186
187static Bool
188ReportMismatch(unsigned action, unsigned field, const char *type)
189{
190    ERROR2("Value of %s field must be of type %s\n",fieldText(field),type);
191    ACTION1("Action %s definition ignored\n",
192    					XkbActionTypeText(action,XkbMessage));
193    return False;
194}
195
196static Bool
197ReportIllegal(unsigned action,unsigned field)
198{
199    ERROR2("Field %s is not defined for an action of type %s\n",
200				fieldText(field),
201				XkbActionTypeText(action,XkbMessage));
202    ACTION("Action definition ignored\n");
203    return False;
204}
205
206static Bool
207ReportActionNotArray(unsigned action,unsigned field)
208{
209    ERROR2("The %s field in the %s action is not an array\n",
210				fieldText(field),
211				XkbActionTypeText(action,XkbMessage));
212    ACTION("Action definition ignored\n");
213    return False;
214}
215
216static Bool
217ReportNotFound(unsigned action, unsigned field, const char *what, char *bad)
218{
219    ERROR2("%s named %s not found\n",what,bad);
220    ACTION2("Ignoring the %s field of an %s action\n",fieldText(field),
221				XkbActionTypeText(action,XkbMessage));
222    return False;
223}
224
225static Bool
226HandleNoAction(	XkbDescPtr	xkb,
227		XkbAnyAction *	action,
228		unsigned	field,
229		ExprDef *	array_ndx,
230		ExprDef *	value)
231{
232    return ReportIllegal(action->type,field);
233}
234
235static Bool
236CheckLatchLockFlags(	unsigned	action,
237			unsigned	field,
238			ExprDef *	value,
239			unsigned *	flags_inout)
240{
241unsigned	tmp;
242ExprResult	result;
243
244    if (field==F_ClearLocks)		tmp= XkbSA_ClearLocks;
245    else if (field==F_LatchToLock)	tmp= XkbSA_LatchToLock;
246    else 				return False; /* WSGO! */
247    if (!ExprResolveBoolean(value,&result,NULL,NULL))
248	return ReportMismatch(action,field,"boolean");
249    if (result.uval)	*flags_inout|= tmp;
250    else		*flags_inout&= ~tmp;
251    return True;
252}
253
254static Bool
255CheckModifierField(	XkbDescPtr	xkb,
256			unsigned	action,
257			ExprDef *	value,
258			unsigned *	flags_inout,
259			unsigned *	mods_rtrn)
260{
261ExprResult	rtrn;
262
263    if (value->op==ExprIdent) {
264	register char *valStr;
265	valStr= XkbAtomGetString(NULL,value->value.str);
266	if (valStr&&((uStrCaseCmp(valStr,"usemodmapmods")==0)||
267		     (uStrCaseCmp(valStr,"modmapmods")==0))) {
268
269	    *mods_rtrn= 0;
270	    *flags_inout|= XkbSA_UseModMapMods;
271	    return True;
272	}
273    }
274    if (!ExprResolveModMask(value,&rtrn,LookupVModMask,(XPointer)xkb))
275	return ReportMismatch(action,F_Modifiers,"modifier mask");
276    *mods_rtrn= rtrn.uval;
277    *flags_inout&= ~XkbSA_UseModMapMods;
278    return True;
279}
280
281static Bool
282HandleSetLatchMods(	XkbDescPtr	xkb,
283			XkbAnyAction *	action,
284			unsigned	field,
285			ExprDef *	array_ndx,
286			ExprDef *	value)
287{
288XkbModAction *	act;
289unsigned	rtrn;
290unsigned	t1,t2;
291
292    act= (XkbModAction *)action;
293    if (array_ndx!=NULL) {
294	switch (field) {
295	    case F_ClearLocks: case F_LatchToLock:
296	    case F_Modifiers:
297		return ReportActionNotArray(action->type,field);
298	}
299    }
300    switch (field) {
301	case F_ClearLocks:
302	case F_LatchToLock:
303	    rtrn= act->flags;
304	    if (CheckLatchLockFlags(action->type,field,value,&rtrn)) {
305		act->flags= rtrn;
306		return True;
307	    }
308	    return False;
309	case F_Modifiers:
310	    t1= act->flags;
311	    if (CheckModifierField(xkb,action->type,value,&t1,&t2)) {
312		act->flags= t1;
313		act->real_mods= act->mask= (t2&0xff);
314		t2= (t2>>8)&0xffff;
315		XkbSetModActionVMods(act,t2);
316		return True;
317	    }
318	    return False;
319    }
320    return ReportIllegal(action->type,field);
321}
322
323static Bool
324HandleLockMods(	XkbDescPtr	xkb,
325		XkbAnyAction *	action,
326		unsigned	field,
327		ExprDef *	array_ndx,
328		ExprDef *	value)
329{
330XkbModAction *	act;
331unsigned	t1,t2;
332
333    act= (XkbModAction *)action;
334    if ((array_ndx!=NULL)&&(field==F_Modifiers))
335	return ReportActionNotArray(action->type,field);
336    switch (field) {
337	case F_Modifiers:
338	    t1= act->flags;
339	    if (CheckModifierField(xkb,action->type,value,&t1,&t2)) {
340		act->flags= t1;
341		act->real_mods= act->mask= (t2&0xff);
342		t2= (t2>>8)&0xffff;
343		XkbSetModActionVMods(act,t2);
344		return True;
345	    }
346	    return False;
347    }
348    return ReportIllegal(action->type,field);
349}
350
351static LookupEntry groupNames[] = {
352	{	"group1",	1	},
353	{	"group2",	2	},
354	{	"group3",	3	},
355	{	"group4",	4	},
356	{	"group5",	5	},
357	{	"group6",	6	},
358	{	"group7",	7	},
359	{	"group8",	8	},
360	{	NULL,		0	},
361};
362
363static Bool
364CheckGroupField(	unsigned	action,
365			ExprDef *	value,
366			unsigned *	flags_inout,
367			int *		grp_rtrn)
368{
369ExprDef *	spec;
370ExprResult 	rtrn;
371
372    if ((value->op==OpNegate)||(value->op==OpUnaryPlus)) {
373	*flags_inout&= ~XkbSA_GroupAbsolute;
374	spec= value->value.child;
375    }
376    else {
377	*flags_inout|= XkbSA_GroupAbsolute;
378	spec= value;
379    }
380
381    if (!ExprResolveInteger(spec,&rtrn,SimpleLookup,(XPointer)groupNames))
382	return ReportMismatch(action,F_Group,"integer (range 1..8)");
383    if ((rtrn.ival<1)||(rtrn.ival>XkbNumKbdGroups)) {
384	ERROR2("Illegal group %d (must be in the range 1..%d)\n",rtrn.ival,
385							XkbNumKbdGroups);
386	ACTION1("Action %s definition ignored\n",
387					XkbActionTypeText(action,XkbMessage));
388	return False;
389    }
390    if (value->op==OpNegate)		*grp_rtrn= -rtrn.ival;
391    else if (value->op==OpUnaryPlus)	*grp_rtrn= rtrn.ival;
392    else				*grp_rtrn= rtrn.ival-1;
393    return True;
394}
395
396static Bool
397HandleSetLatchGroup(	XkbDescPtr	xkb,
398			XkbAnyAction *	action,
399			unsigned	field,
400			ExprDef *	array_ndx,
401			ExprDef *	value)
402{
403XkbGroupAction *	act;
404unsigned		rtrn;
405unsigned		t1;
406int			t2;
407
408    act= (XkbGroupAction *)action;
409    if (array_ndx!=NULL) {
410	switch (field) {
411	    case F_ClearLocks: case F_LatchToLock:
412	    case F_Group:
413		return ReportActionNotArray(action->type,field);
414	}
415    }
416    switch (field) {
417	case F_ClearLocks:
418	case F_LatchToLock:
419	    rtrn= act->flags;
420	    if (CheckLatchLockFlags(action->type,field,value,&rtrn)) {
421		act->flags= rtrn;
422		return True;
423	    }
424	    return False;
425	case F_Group:
426	    t1= act->flags;
427	    if (CheckGroupField(action->type,value,&t1,&t2)) {
428		act->flags= t1;
429		XkbSASetGroup(act,t2);
430		return True;
431	    }
432	    return False;
433    }
434    return ReportIllegal(action->type,field);
435}
436
437static Bool
438HandleLockGroup(	XkbDescPtr	xkb,
439			XkbAnyAction *	action,
440			unsigned	field,
441			ExprDef *	array_ndx,
442			ExprDef *	value)
443{
444XkbGroupAction *	act;
445unsigned		t1;
446int			t2;
447
448    act= (XkbGroupAction *)action;
449    if ((array_ndx!=NULL) && (field==F_Group))
450	return ReportActionNotArray(action->type,field);
451    if (field==F_Group) {
452	t1= act->flags;
453	if (CheckGroupField(action->type,value,&t1,&t2)) {
454	    act->flags= t1;
455	    XkbSASetGroup(act,t2);
456	    return True;
457	}
458	return False;
459    }
460    return ReportIllegal(action->type,field);
461}
462
463static Bool
464HandleMovePtr(	XkbDescPtr 	xkb,
465		XkbAnyAction *	action,
466		unsigned	field,
467		ExprDef *	array_ndx,
468		ExprDef *	value)
469{
470ExprResult	rtrn;
471XkbPtrAction *	act;
472Bool		absolute;
473
474    act= (XkbPtrAction *)action;
475    if ((array_ndx!=NULL)&&((field==F_X)||(field==F_Y)))
476	return ReportActionNotArray(action->type,field);
477
478    if ((field==F_X)||(field==F_Y)) {
479	if ((value->op==OpNegate)||(value->op==OpUnaryPlus))
480	     absolute= False;
481	else absolute= True;
482	if (!ExprResolveInteger(value,&rtrn,NULL,NULL))
483	    return ReportMismatch(action->type,field,"integer");
484	if (field==F_X) {
485	    if (absolute)
486		act->flags|= XkbSA_MoveAbsoluteX;
487	    XkbSetPtrActionX(act,rtrn.ival);
488	}
489	else {
490	    if (absolute)
491		act->flags|= XkbSA_MoveAbsoluteY;
492	    XkbSetPtrActionY(act,rtrn.ival);
493	}
494	return True;
495    }
496    else if (field==F_Accel) {
497	if (!ExprResolveBoolean(value,&rtrn,NULL,NULL))
498	    return ReportMismatch(action->type,field,"boolean");
499	if (rtrn.uval)	act->flags&= ~XkbSA_NoAcceleration;
500	else 			act->flags|= XkbSA_NoAcceleration;
501    }
502    return ReportIllegal(action->type,field);
503}
504
505static LookupEntry btnNames[] = {
506	{	"button1",	1	},
507	{	"button2",	2	},
508	{	"button3",	3	},
509	{	"button4",	4	},
510	{	"button5",	5	},
511	{	"default",	0	},
512	{	NULL,		0	}
513};
514
515static LookupEntry lockWhich[] = {
516	{	"both",		0					},
517	{	"lock",		XkbSA_LockNoUnlock			},
518	{	"neither",	(XkbSA_LockNoLock|XkbSA_LockNoUnlock)	},
519	{	"unlock",	XkbSA_LockNoLock			},
520	{	NULL,		0	}
521};
522
523static Bool
524HandlePtrBtn(	XkbDescPtr 	xkb,
525		XkbAnyAction *	action,
526		unsigned	field,
527		ExprDef *	array_ndx,
528		ExprDef *	value)
529{
530ExprResult		rtrn;
531XkbPtrBtnAction	*	act;
532
533    act= (XkbPtrBtnAction *)action;
534    if (field==F_Button) {
535	if (array_ndx!=NULL)
536	    return ReportActionNotArray(action->type,field);
537	if (!ExprResolveInteger(value,&rtrn,SimpleLookup,(XPointer)btnNames))
538	    return ReportMismatch(action->type,field,"integer (range 1..5)");
539	if ((rtrn.ival<0)||(rtrn.ival>5)) {
540	    ERROR("Button must specify default or be in the range 1..5\n");
541	    ACTION1("Illegal button value %d ignored\n",rtrn.ival);
542	    return False;
543	}
544	act->button= rtrn.ival;
545	return True;
546    }
547    else if ((action->type==XkbSA_LockPtrBtn)&&(field==F_Affect)) {
548	if (array_ndx!=NULL)
549	    return ReportActionNotArray(action->type,field);
550	if (!ExprResolveEnum(value,&rtrn,lockWhich))
551	    return ReportMismatch(action->type,field,"lock or unlock");
552	act->flags&= ~(XkbSA_LockNoLock|XkbSA_LockNoUnlock);
553	act->flags|= rtrn.ival;
554	return True;
555    }
556    else if (field==F_Count) {
557	if (array_ndx!=NULL)
558	    return ReportActionNotArray(action->type,field);
559	if (!ExprResolveInteger(value,&rtrn,SimpleLookup,(XPointer)btnNames))
560	    return ReportMismatch(action->type,field,"integer");
561	if ((rtrn.ival<0)||(rtrn.ival>255)) {
562	    ERROR("The count field must have a value in the range 0..255\n");
563	    ACTION1("Illegal count %d ignored\n",rtrn.ival);
564	    return False;
565	}
566	act->count= rtrn.ival;
567	return True;
568    }
569    return ReportIllegal(action->type,field);
570}
571
572static LookupEntry ptrDflts[] = {
573	{	"dfltbtn",		XkbSA_AffectDfltBtn	},
574	{	"defaultbutton",	XkbSA_AffectDfltBtn	},
575	{	"button",		XkbSA_AffectDfltBtn	},
576	{ 	NULL,			0			}
577};
578
579static Bool
580HandleSetPtrDflt(	XkbDescPtr 	xkb,
581			XkbAnyAction *	action,
582			unsigned	field,
583			ExprDef *	array_ndx,
584			ExprDef *	value)
585{
586ExprResult		rtrn;
587XkbPtrDfltAction *	act;
588
589    act= (XkbPtrDfltAction *)action;
590    if (field==F_Affect) {
591	if (array_ndx!=NULL)
592	    return ReportActionNotArray(action->type,field);
593	if (!ExprResolveEnum(value,&rtrn,ptrDflts))
594	    return ReportMismatch(action->type,field,"pointer component");
595	act->affect= rtrn.uval;
596	return True;
597    }
598    else if ((field==F_Button)||(field==F_Value)) {
599	ExprDef *btn;
600	if (array_ndx!=NULL)
601	    return ReportActionNotArray(action->type,field);
602	if ((value->op==OpNegate)||(value->op==OpUnaryPlus))  {
603	    act->flags&= ~XkbSA_DfltBtnAbsolute;
604	    btn= value->value.child;
605	}
606	else {
607	    act->flags|= XkbSA_DfltBtnAbsolute;
608	    btn= value;
609	}
610
611	if (!ExprResolveInteger(btn,&rtrn,SimpleLookup,(XPointer)btnNames))
612	    return ReportMismatch(action->type,field,"integer (range 1..5)");
613	if ((rtrn.ival<0)||(rtrn.ival>5)) {
614	    ERROR("New default button value must be in the range 1..5\n");
615	    ACTION1("Illegal default button value %d ignored\n",rtrn.ival);
616	    return False;
617	}
618	if (rtrn.ival==0) {
619	    ERROR("Cannot set default pointer button to \"default\"\n");
620	    ACTION("Illegal default button setting ignored\n");
621	    return False;
622	}
623	if (value->op==OpNegate)
624	     XkbSASetPtrDfltValue(act,-rtrn.ival);
625	else XkbSASetPtrDfltValue(act,rtrn.ival);
626	return True;
627    }
628    return ReportIllegal(action->type,field);
629}
630
631static LookupEntry	isoNames[] = {
632	{	"mods",		XkbSA_ISONoAffectMods	},
633	{	"modifiers",	XkbSA_ISONoAffectMods	},
634	{	"group",	XkbSA_ISONoAffectGroup	},
635	{	"groups",	XkbSA_ISONoAffectGroup	},
636	{	"ptr",		XkbSA_ISONoAffectPtr	},
637	{	"pointer",	XkbSA_ISONoAffectPtr	},
638	{	"ctrls",	XkbSA_ISONoAffectCtrls	},
639	{	"controls",	XkbSA_ISONoAffectCtrls	},
640	{	"all",		~((unsigned)0)		},
641	{	"none",		0			},
642	{	NULL,		0			},
643};
644
645static Bool
646HandleISOLock(	XkbDescPtr 	xkb,
647		XkbAnyAction *	action,
648		unsigned	field,
649		ExprDef *	array_ndx,
650		ExprDef *	value)
651{
652ExprResult	rtrn;
653XkbISOAction *	act;
654unsigned	flags,mods;
655int		group;
656
657    act= (XkbISOAction *)action;
658    switch (field) {
659	case F_Modifiers:
660	    if (array_ndx!=NULL)
661		return ReportActionNotArray(action->type,field);
662	    flags= act->flags;
663	    if (CheckModifierField(xkb,action->type,value,&flags,&mods)) {
664		act->flags= flags&(~XkbSA_ISODfltIsGroup);
665		act->real_mods= mods&0xff;
666		mods= (mods>>8)&0xff;
667		XkbSetModActionVMods(act,mods);
668		return True;
669	    }
670	    return False;
671	case F_Group:
672	    if (array_ndx!=NULL)
673		return ReportActionNotArray(action->type,field);
674	    flags= act->flags;
675	    if (CheckGroupField(action->type,value,&flags,&group)) {
676		act->flags= flags|XkbSA_ISODfltIsGroup;
677		XkbSASetGroup(act,group);
678		return True;
679	    }
680	    return False;
681	case F_Affect:
682	    if (array_ndx!=NULL)
683		return ReportActionNotArray(action->type,field);
684	    if (!ExprResolveMask(value,&rtrn,SimpleLookup,(XPointer)isoNames))
685		return ReportMismatch(action->type,field,"keyboard component");
686	    act->affect= (~rtrn.uval)&XkbSA_ISOAffectMask;
687	    return True;
688    }
689    return ReportIllegal(action->type,field);
690}
691
692static Bool
693HandleSwitchScreen(	XkbDescPtr 	xkb,
694			XkbAnyAction *	action,
695			unsigned	field,
696			ExprDef *	array_ndx,
697			ExprDef *	value)
698{
699ExprResult		rtrn;
700XkbSwitchScreenAction *	act;
701
702    act= (XkbSwitchScreenAction *)action;
703    if (field==F_Screen) {
704	ExprDef *scrn;
705	if (array_ndx!=NULL)
706	    return ReportActionNotArray(action->type,field);
707	if ((value->op==OpNegate)||(value->op==OpUnaryPlus)) {
708	    act->flags&= ~XkbSA_SwitchAbsolute;
709	    scrn= value->value.child;
710	}
711	else {
712	    act->flags|= XkbSA_SwitchAbsolute;
713	    scrn= value;
714	}
715
716	if (!ExprResolveInteger(scrn,&rtrn,NULL,NULL))
717	    return ReportMismatch(action->type,field,"integer (0..255)");
718	if ((rtrn.ival<0)||(rtrn.ival>255)) {
719	    ERROR("Screen index must be in the range 1..255\n");
720	    ACTION1("Illegal screen value %d ignored\n",rtrn.ival);
721	    return False;
722	}
723	if (value->op==OpNegate)
724	     XkbSASetScreen(act,-rtrn.ival);
725	else XkbSASetScreen(act,rtrn.ival);
726	return True;
727    }
728    else if (field==F_Same) {
729	if (array_ndx!=NULL)
730	    return ReportActionNotArray(action->type,field);
731	if (!ExprResolveBoolean(value,&rtrn,NULL,NULL))
732	    return ReportMismatch(action->type,field,"boolean");
733	if (rtrn.uval)	act->flags&= ~XkbSA_SwitchApplication;
734	else		act->flags|= XkbSA_SwitchApplication;
735	return True;
736    }
737    return ReportIllegal(action->type,field);
738}
739
740LookupEntry	ctrlNames[]= {
741	{	"repeatkeys",		XkbRepeatKeysMask	},
742	{	"repeat",		XkbRepeatKeysMask	},
743	{	"autorepeat",		XkbRepeatKeysMask	},
744	{	"slowkeys",		XkbSlowKeysMask		},
745	{	"bouncekeys",		XkbBounceKeysMask	},
746	{	"stickykeys",		XkbStickyKeysMask	},
747	{	"mousekeys",		XkbMouseKeysMask	},
748	{	"mousekeysaccel",	XkbMouseKeysAccelMask	},
749	{	"accessxkeys",		XkbAccessXKeysMask	},
750	{	"accessxtimeout",	XkbAccessXTimeoutMask	},
751	{	"accessxfeedback",	XkbAccessXFeedbackMask	},
752	{	"audiblebell",		XkbAudibleBellMask	},
753	{	"overlay1",		XkbOverlay1Mask		},
754	{	"overlay2",		XkbOverlay2Mask		},
755	{	"ignoregrouplock",	XkbIgnoreGroupLockMask	},
756	{	"all",			XkbAllBooleanCtrlsMask	},
757	{	"none",			0			},
758	{	NULL,			0			}
759};
760
761static Bool
762HandleSetLockControls(	XkbDescPtr 	xkb,
763			XkbAnyAction *	action,
764			unsigned	field,
765			ExprDef *	array_ndx,
766			ExprDef *	value)
767{
768ExprResult		rtrn;
769XkbCtrlsAction *	act;
770
771    act= (XkbCtrlsAction *)action;
772    if (field==F_Controls) {
773	if (array_ndx!=NULL)
774	    return ReportActionNotArray(action->type,field);
775	if (!ExprResolveMask(value,&rtrn,SimpleLookup,(XPointer)ctrlNames))
776	    return ReportMismatch(action->type,field,"controls mask");
777	XkbActionSetCtrls(act,rtrn.uval);
778	return True;
779    }
780    return ReportIllegal(action->type,field);
781}
782
783static LookupEntry evNames[]= {
784	{	"press",	XkbSA_MessageOnPress	},
785	{	"keypress",	XkbSA_MessageOnPress	},
786	{	"release",	XkbSA_MessageOnRelease	},
787	{	"keyrelease",	XkbSA_MessageOnRelease	},
788	{	"all",		XkbSA_MessageOnPress|XkbSA_MessageOnRelease },
789	{	"none",		0			},
790	{	NULL,		0			}
791};
792
793static Bool
794HandleActionMessage(	XkbDescPtr 	xkb,
795			XkbAnyAction *	action,
796			unsigned	field,
797			ExprDef *	array_ndx,
798			ExprDef *	value)
799{
800ExprResult		rtrn;
801XkbMessageAction *	act;
802
803    act= (XkbMessageAction *)action;
804    switch (field) {
805	case F_Report:
806	    if (array_ndx!=NULL)
807		return ReportActionNotArray(action->type,field);
808	    if (!ExprResolveMask(value,&rtrn,SimpleLookup,(XPointer)evNames))
809		return ReportMismatch(action->type,field,"key event mask");
810	    act->flags&= ~(XkbSA_MessageOnPress|XkbSA_MessageOnRelease);
811	    act->flags= rtrn.uval&(XkbSA_MessageOnPress|XkbSA_MessageOnRelease);
812	    return True;
813	case F_GenKeyEvent:
814	    if (array_ndx!=NULL)
815		return ReportActionNotArray(action->type,field);
816	    if (!ExprResolveBoolean(value,&rtrn,NULL,NULL))
817		return ReportMismatch(action->type,field,"boolean");
818	    if (rtrn.uval)	act->flags|= XkbSA_MessageGenKeyEvent;
819	    else		act->flags&= ~XkbSA_MessageGenKeyEvent;
820	    return True;
821	case F_Data:
822	    if (array_ndx==NULL) {
823		if (!ExprResolveString(value,&rtrn,NULL,NULL))
824		    return ReportMismatch(action->type,field,"string");
825		else {
826		    int len= strlen(rtrn.str);
827		    if ((len<1)||(len>6)) {
828			WARN("An action message can hold only 6 bytes\n");
829			ACTION1("Extra %d bytes ignored\n",len-6);
830		    }
831		    strncpy((char *)act->message,rtrn.str,6);
832		}
833		return True;
834	    }
835	    else {
836		unsigned ndx;
837		if (!ExprResolveInteger(array_ndx,&rtrn,NULL,NULL)) {
838		    ERROR("Array subscript must be integer\n");
839		    ACTION("Illegal subscript ignored\n");
840		    return False;
841		}
842		ndx= rtrn.uval;
843		if (ndx>5) {
844		    ERROR("An action message is at most 6 bytes long\n");
845		    ACTION1("Attempt to use data[%d] ignored\n",ndx);
846		    return False;
847		}
848		if (!ExprResolveInteger(value,&rtrn,NULL,NULL))
849		    return ReportMismatch(action->type,field,"integer");
850		if ((rtrn.ival<0)||(rtrn.ival>255)) {
851		    ERROR("Message data must be in the range 0..255\n");
852		    ACTION1("Illegal datum %d ignored\n",rtrn.ival);
853		    return False;
854		}
855		act->message[ndx]= rtrn.uval;
856	    }
857	    return True;
858    }
859    return ReportIllegal(action->type,field);
860}
861
862static Bool
863HandleRedirectKey(	XkbDescPtr 	xkb,
864			XkbAnyAction *	action,
865			unsigned	field,
866			ExprDef *	array_ndx,
867			ExprDef *	value)
868{
869ExprResult		rtrn;
870XkbRedirectKeyAction *	act;
871unsigned		t1,t2,vmods,vmask;
872unsigned long 		tmp;
873
874    if (array_ndx!=NULL)
875	return ReportActionNotArray(action->type,field);
876
877    act= (XkbRedirectKeyAction *)action;
878    switch (field) {
879	case F_Keycode:
880	    if (!ExprResolveKeyName(value,&rtrn,NULL,NULL))
881		return ReportMismatch(action->type,field,"key name");
882	    tmp= KeyNameToLong(rtrn.keyName.name);
883	    if (!FindNamedKey(xkb,tmp,&t1,True,CreateKeyNames(xkb),0)) {
884		return ReportNotFound(action->type,field,"Key",
885				XkbKeyNameText(rtrn.keyName.name,XkbMessage));
886	    }
887	    act->new_key= t1;
888	    return True;
889	case F_ModsToClear:
890	case F_Modifiers:
891	    t1= 0;
892	    if (CheckModifierField(xkb,action->type,value,&t1,&t2)) {
893		act->mods_mask|= (t2&0xff);
894		if (field==F_Modifiers)
895		     act->mods|= (t2&0xff);
896		else act->mods&= ~(t2&0xff);
897
898		t2= (t2>>8)&0xffff;
899		vmods= XkbSARedirectVMods(act);
900		vmask= XkbSARedirectVModsMask(act);
901		vmask|= t2;
902		if (field==F_Modifiers)
903		     vmods|= t2;
904		else vmods&= ~t2;
905		XkbSARedirectSetVMods(act,vmods);
906		XkbSARedirectSetVModsMask(act,vmask);
907		return True;
908	    }
909	    return True;
910    }
911    return ReportIllegal(action->type,field);
912}
913
914static Bool
915HandleDeviceBtn(	XkbDescPtr 	xkb,
916			XkbAnyAction *	action,
917			unsigned	field,
918			ExprDef *	array_ndx,
919			ExprDef *	value)
920{
921ExprResult		rtrn;
922XkbDeviceBtnAction *	act;
923
924    act= (XkbDeviceBtnAction *)action;
925    if (field==F_Button) {
926	if (array_ndx!=NULL)
927	    return ReportActionNotArray(action->type,field);
928	if (!ExprResolveInteger(value,&rtrn,NULL,NULL))
929	    return ReportMismatch(action->type,field,"integer (range 1..255)");
930	if ((rtrn.ival<0)||(rtrn.ival>255)) {
931	    ERROR("Button must specify default or be in the range 1..255\n");
932	    ACTION1("Illegal button value %d ignored\n",rtrn.ival);
933	    return False;
934	}
935	act->button= rtrn.ival;
936	return True;
937    }
938    else if ((action->type==XkbSA_LockDeviceBtn)&&(field==F_Affect)) {
939	if (array_ndx!=NULL)
940	    return ReportActionNotArray(action->type,field);
941	if (!ExprResolveEnum(value,&rtrn,lockWhich))
942	    return ReportMismatch(action->type,field,"lock or unlock");
943	act->flags&= ~(XkbSA_LockNoLock|XkbSA_LockNoUnlock);
944	act->flags|= rtrn.ival;
945	return True;
946    }
947    else if (field==F_Count) {
948	if (array_ndx!=NULL)
949	    return ReportActionNotArray(action->type,field);
950	if (!ExprResolveInteger(value,&rtrn,SimpleLookup,(XPointer)btnNames))
951	    return ReportMismatch(action->type,field,"integer");
952	if ((rtrn.ival<0)||(rtrn.ival>255)) {
953	    ERROR("The count field must have a value in the range 0..255\n");
954	    ACTION1("Illegal count %d ignored\n",rtrn.ival);
955	    return False;
956	}
957	act->count= rtrn.ival;
958	return True;
959    }
960    else if (field==F_Device) {
961	if (array_ndx!=NULL)
962	    return ReportActionNotArray(action->type,field);
963	if (!ExprResolveInteger(value,&rtrn,NULL,NULL))
964	    return ReportMismatch(action->type,field,"integer (range 1..255)");
965	if ((rtrn.ival<0)||(rtrn.ival>255)) {
966	    ERROR("Device must specify default or be in the range 1..255\n");
967	    ACTION1("Illegal device value %d ignored\n",rtrn.ival);
968	    return False;
969	}
970	act->device= rtrn.ival;
971	return True;
972    }
973    return ReportIllegal(action->type,field);
974}
975
976static Bool
977HandleDeviceValuator(	XkbDescPtr 	xkb,
978			XkbAnyAction *	action,
979			unsigned	field,
980			ExprDef *	array_ndx,
981			ExprDef *	value)
982{
983#if 0
984ExprResult			rtrn;
985XkbDeviceValuatorAction *	act;
986
987    act= (XkbDeviceValuatorAction *)action;
988    /*  XXX - Not yet implemented */
989#endif
990    return False;
991}
992
993static Bool
994HandlePrivate(	XkbDescPtr 	xkb,
995		XkbAnyAction *	action,
996		unsigned	field,
997		ExprDef *	array_ndx,
998		ExprDef *	value)
999{
1000ExprResult	rtrn;
1001
1002    switch (field) {
1003	case F_Type:
1004	    if (!ExprResolveInteger(value,&rtrn,NULL,NULL))
1005		return ReportMismatch(PrivateAction,field,"integer");
1006	    if ((rtrn.ival<0)||(rtrn.ival>255)) {
1007		ERROR("Private action type must be in the range 0..255\n");
1008		ACTION1("Illegal type %d ignored\n",rtrn.ival);
1009		return False;
1010	    }
1011	    action->type= rtrn.uval;
1012	    return True;
1013	case F_Data:
1014	    if (array_ndx==NULL) {
1015		if (!ExprResolveString(value,&rtrn,NULL,NULL))
1016		    return ReportMismatch(action->type,field,"string");
1017		else {
1018		    int len= strlen(rtrn.str);
1019		    if ((len<1)||(len>7)) {
1020			WARN("A private action has 7 data bytes\n");
1021			ACTION1("Extra %d bytes ignored\n",len-6);
1022			return False;
1023		    }
1024		    strncpy((char *)action->data,rtrn.str,7);
1025		}
1026		return True;
1027	    }
1028	    else {
1029		unsigned ndx;
1030		if (!ExprResolveInteger(array_ndx,&rtrn,NULL,NULL)) {
1031		    ERROR("Array subscript must be integer\n");
1032		    ACTION("Illegal subscript ignored\n");
1033		    return False;
1034		}
1035		ndx= rtrn.uval;
1036		if (ndx>6) {
1037		    ERROR("The data for a private action is 7 bytes long\n");
1038		    ACTION1("Attempt to use data[%d] ignored\n",ndx);
1039		    return False;
1040		}
1041		if (!ExprResolveInteger(value,&rtrn,NULL,NULL))
1042		    return ReportMismatch(action->type,field,"integer");
1043		if ((rtrn.ival<0)||(rtrn.ival>255)) {
1044		    ERROR("All data for a private action must be 0..255\n");
1045		    ACTION1("Illegal datum %d ignored\n",rtrn.ival);
1046		    return False;
1047		}
1048		action->data[ndx]= rtrn.uval;
1049		return True;
1050	    }
1051    }
1052    return ReportIllegal(PrivateAction,field);
1053}
1054
1055typedef	Bool	(*actionHandler)(
1056	XkbDescPtr 	/* xkb */,
1057	XkbAnyAction *	/* action */,
1058	unsigned	/* field */,
1059	ExprDef *	/* array_ndx */,
1060	ExprDef *	/* value */
1061);
1062
1063static actionHandler	handleAction[XkbSA_NumActions+1] = {
1064	HandleNoAction			/* NoAction	*/,
1065	HandleSetLatchMods		/* SetMods	*/,
1066	HandleSetLatchMods		/* LatchMods	*/,
1067	HandleLockMods			/* LockMods	*/,
1068	HandleSetLatchGroup		/* SetGroup	*/,
1069	HandleSetLatchGroup		/* LatchGroup	*/,
1070	HandleLockGroup			/* LockGroup	*/,
1071	HandleMovePtr			/* MovePtr	*/,
1072	HandlePtrBtn			/* PtrBtn	*/,
1073	HandlePtrBtn			/* LockPtrBtn	*/,
1074	HandleSetPtrDflt		/* SetPtrDflt	*/,
1075	HandleISOLock			/* ISOLock	*/,
1076	HandleNoAction			/* Terminate	*/,
1077	HandleSwitchScreen		/* SwitchScreen	*/,
1078	HandleSetLockControls		/* SetControls	*/,
1079	HandleSetLockControls		/* LockControls	*/,
1080	HandleActionMessage		/* ActionMessage*/,
1081	HandleRedirectKey		/* RedirectKey	*/,
1082	HandleDeviceBtn			/* DeviceBtn	*/,
1083	HandleDeviceBtn			/* LockDeviceBtn*/,
1084	HandleDeviceValuator		/* DeviceValuatr*/,
1085	HandlePrivate			/* Private	*/
1086};
1087
1088/***====================================================================***/
1089
1090static void
1091ApplyActionFactoryDefaults(XkbAction *action)
1092{
1093    if (action->type==XkbSA_SetPtrDflt) { /* increment default button */
1094	action->dflt.affect= XkbSA_AffectDfltBtn;
1095	action->dflt.flags= 0;
1096	XkbSASetPtrDfltValue(&action->dflt,1);
1097    }
1098    else if (action->type==XkbSA_ISOLock) {
1099	action->iso.real_mods=  LockMask;
1100    }
1101    return;
1102}
1103
1104
1105int
1106HandleActionDef(	ExprDef *	def,
1107			XkbDescPtr	xkb,
1108			XkbAnyAction *	action,
1109			unsigned	mergeMode,
1110			ActionInfo *	info)
1111{
1112ExprDef *		arg;
1113register char *		str;
1114unsigned 		tmp,hndlrType;
1115
1116    if (!actionsInitialized)
1117	ActionsInit();
1118
1119    if (def->op!=ExprActionDecl) {
1120	ERROR1("Expected an action definition, found %s\n",exprOpText(def->op));
1121	return False;
1122    }
1123    str= XkbAtomGetString(NULL,def->value.action.name);
1124    if (!str) {
1125	WSGO("Missing name in action definition!!\n");
1126	return False;
1127    }
1128    if (!stringToAction(str,&tmp)) {
1129	ERROR1("Unknown action %s\n",str);
1130	return False;
1131    }
1132    action->type= hndlrType= tmp;
1133    if (action->type!=XkbSA_NoAction) {
1134	ApplyActionFactoryDefaults((XkbAction *)action);
1135	while (info) {
1136	    if ((info->action==XkbSA_NoAction)||(info->action==hndlrType)) {
1137		if (!(*handleAction[hndlrType])(xkb,action,
1138						info->field,info->array_ndx,
1139						info->value)) {
1140		    return False;
1141		}
1142	    }
1143	    info= info->next;
1144	}
1145    }
1146    for (arg=def->value.action.args;arg!=NULL;arg=(ExprDef*)arg->common.next) {
1147	ExprDef *field,*value,*arrayRtrn;
1148	ExprResult elemRtrn,fieldRtrn;
1149	unsigned fieldNdx;
1150
1151	if (arg->op==OpAssign) {
1152	    field= arg->value.binary.left;
1153	    value= arg->value.binary.right;
1154	}
1155	else {
1156	    if ((arg->op==OpNot)||(arg->op==OpInvert)) {
1157		field= arg->value.child;
1158		value= &constFalse;
1159	    }
1160	    else {
1161		field= arg;
1162		value= &constTrue;
1163	    }
1164	}
1165	if (!ExprResolveLhs(field,&elemRtrn,&fieldRtrn,&arrayRtrn))
1166	    return False;	/* internal error -- already reported */
1167
1168	if (elemRtrn.str!=NULL) {
1169	    ERROR("Cannot change defaults in an action definition\n");
1170	    ACTION2("Ignoring attempt to change %s.%s\n",elemRtrn.str,
1171							 fieldRtrn.str);
1172	    return False;
1173	}
1174	if (!stringToField(fieldRtrn.str,&fieldNdx)) {
1175	    ERROR1("Unknown field name %s\n",uStringText(fieldRtrn.str));
1176	    return False;
1177	}
1178	if (!(*handleAction[hndlrType])(xkb,action,fieldNdx,arrayRtrn,value)) {
1179	    return False;
1180	}
1181    }
1182    return True;
1183}
1184
1185/***====================================================================***/
1186
1187int
1188SetActionField(	XkbDescPtr	xkb,
1189		char *		elem,
1190		char *		field,
1191		ExprDef *	array_ndx,
1192		ExprDef *	value,
1193		ActionInfo **	info_rtrn)
1194{
1195ActionInfo *new,*old;
1196
1197    if (!actionsInitialized)
1198	ActionsInit();
1199
1200    new= uTypedAlloc(ActionInfo);
1201    if (new==NULL) {
1202	WSGO("Couldn't allocate space for action default\n");
1203	return False;
1204    }
1205    if (uStrCaseCmp(elem,"action")==0)
1206	new->action= XkbSA_NoAction;
1207    else {
1208	if (!stringToAction(elem,&new->action))
1209	    return False;
1210	if (new->action==XkbSA_NoAction) {
1211	    ERROR1("\"%s\" is not a valid field in a NoAction action\n",field);
1212	    return False;
1213	}
1214    }
1215    if (!stringToField(field,&new->field)) {
1216	ERROR1("\"%s\" is not a legal field name\n",field);
1217	return False;
1218    }
1219    new->array_ndx= array_ndx;
1220    new->value= value;
1221    new->next= NULL;
1222    old= *info_rtrn;
1223    while ((old)&&(old->next))
1224	old= old->next;
1225    if (old==NULL)	*info_rtrn= new;
1226    else		old->next= new;
1227    return True;
1228}
1229
1230/***====================================================================***/
1231
1232void
1233ActionsInit(void)
1234{
1235    if (!actionsInitialized) {
1236	bzero((char *)&constTrue,sizeof(constTrue));
1237	bzero((char *)&constFalse,sizeof(constFalse));
1238	constTrue.common.stmtType= StmtExpr;
1239	constTrue.common.next= NULL;
1240	constTrue.op= ExprIdent;
1241	constTrue.type= TypeBoolean;
1242	constTrue.value.str= XkbInternAtom(NULL,"true",False);
1243	constFalse.common.stmtType= StmtExpr;
1244	constFalse.common.next= NULL;
1245	constFalse.op= ExprIdent;
1246	constFalse.type= TypeBoolean;
1247	constFalse.value.str= XkbInternAtom(NULL,"false",False);
1248	actionsInitialized= 1;
1249    }
1250    return;
1251}
1252
1253