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