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