actions: Remove PointerDefault affect field
[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 "xkbcomp-priv.h"
28 #include "text.h"
29 #include "expr.h"
30 #include "action.h"
31 #include "keycodes.h"
32
33 static const ExprDef constTrue = {
34     .common = { .type = STMT_EXPR, .next = NULL },
35     .op = EXPR_VALUE,
36     .value_type = EXPR_TYPE_BOOLEAN,
37     .value = { .ival = 1 },
38 };
39
40 static const ExprDef constFalse = {
41     .common = { .type = STMT_EXPR, .next = NULL },
42     .op = EXPR_VALUE,
43     .value_type = EXPR_TYPE_BOOLEAN,
44     .value = { .ival = 0 },
45 };
46
47 enum action_field {
48     ACTION_FIELD_CLEAR_LOCKS,
49     ACTION_FIELD_LATCH_TO_LOCK,
50     ACTION_FIELD_GEN_KEY_EVENT,
51     ACTION_FIELD_REPORT,
52     ACTION_FIELD_DEFAULT,
53     ACTION_FIELD_AFFECT,
54     ACTION_FIELD_INCREMENT,
55     ACTION_FIELD_MODIFIERS,
56     ACTION_FIELD_GROUP,
57     ACTION_FIELD_X,
58     ACTION_FIELD_Y,
59     ACTION_FIELD_ACCEL,
60     ACTION_FIELD_BUTTON,
61     ACTION_FIELD_VALUE,
62     ACTION_FIELD_CONTROLS,
63     ACTION_FIELD_TYPE,
64     ACTION_FIELD_COUNT,
65     ACTION_FIELD_SCREEN,
66     ACTION_FIELD_SAME,
67     ACTION_FIELD_DATA,
68     ACTION_FIELD_DEVICE,
69     ACTION_FIELD_KEYCODE,
70     ACTION_FIELD_MODS_TO_CLEAR,
71 };
72
73 ActionsInfo *
74 NewActionsInfo(void)
75 {
76     unsigned type;
77     ActionsInfo *info;
78
79     info = calloc(1, sizeof(*info));
80     if (!info)
81         return NULL;
82
83     /* This includes PrivateAction. */
84     for (type = 0; type < ACTION_TYPE_LAST; type++)
85         info->actions[type].type = type;
86
87     /* Apply some "factory defaults". */
88
89     /* Increment default button. */
90     info->actions[ACTION_TYPE_PTR_DEFAULT].dflt.flags = 0;
91     info->actions[ACTION_TYPE_PTR_DEFAULT].dflt.value = 1;
92
93     return info;
94 }
95
96 void
97 FreeActionsInfo(ActionsInfo *info)
98 {
99     free(info);
100 }
101
102 static const LookupEntry fieldStrings[] = {
103     { "clearLocks",       ACTION_FIELD_CLEAR_LOCKS   },
104     { "latchToLock",      ACTION_FIELD_LATCH_TO_LOCK },
105     { "genKeyEvent",      ACTION_FIELD_GEN_KEY_EVENT },
106     { "generateKeyEvent", ACTION_FIELD_GEN_KEY_EVENT },
107     { "report",           ACTION_FIELD_REPORT        },
108     { "default",          ACTION_FIELD_DEFAULT       },
109     { "affect",           ACTION_FIELD_AFFECT        },
110     { "increment",        ACTION_FIELD_INCREMENT     },
111     { "modifiers",        ACTION_FIELD_MODIFIERS     },
112     { "mods",             ACTION_FIELD_MODIFIERS     },
113     { "group",            ACTION_FIELD_GROUP         },
114     { "x",                ACTION_FIELD_X             },
115     { "y",                ACTION_FIELD_Y             },
116     { "accel",            ACTION_FIELD_ACCEL         },
117     { "accelerate",       ACTION_FIELD_ACCEL         },
118     { "repeat",           ACTION_FIELD_ACCEL         },
119     { "button",           ACTION_FIELD_BUTTON        },
120     { "value",            ACTION_FIELD_VALUE         },
121     { "controls",         ACTION_FIELD_CONTROLS      },
122     { "ctrls",            ACTION_FIELD_CONTROLS      },
123     { "type",             ACTION_FIELD_TYPE          },
124     { "count",            ACTION_FIELD_COUNT         },
125     { "screen",           ACTION_FIELD_SCREEN        },
126     { "same",             ACTION_FIELD_SAME          },
127     { "sameServer",       ACTION_FIELD_SAME          },
128     { "data",             ACTION_FIELD_DATA          },
129     { "device",           ACTION_FIELD_DEVICE        },
130     { "dev",              ACTION_FIELD_DEVICE        },
131     { "key",              ACTION_FIELD_KEYCODE       },
132     { "keycode",          ACTION_FIELD_KEYCODE       },
133     { "kc",               ACTION_FIELD_KEYCODE       },
134     { "clearmods",        ACTION_FIELD_MODS_TO_CLEAR },
135     { "clearmodifiers",   ACTION_FIELD_MODS_TO_CLEAR },
136     { NULL,               0                          }
137 };
138
139 static bool
140 stringToAction(const char *str, unsigned *type_rtrn)
141 {
142     return LookupString(actionTypeNames, str, type_rtrn);
143 }
144
145 static bool
146 stringToField(const char *str, enum action_field *field_rtrn)
147 {
148     return LookupString(fieldStrings, str, field_rtrn);
149 }
150
151 static const char *
152 fieldText(enum action_field field)
153 {
154     return LookupValue(fieldStrings, field);
155 }
156
157 /***====================================================================***/
158
159 static inline bool
160 ReportMismatch(struct xkb_keymap *keymap, enum xkb_action_type action,
161                enum action_field field, const char *type)
162 {
163     log_err(keymap->ctx,
164             "Value of %s field must be of type %s; "
165             "Action %s definition ignored\n",
166             fieldText(field), type, ActionTypeText(action));
167     return false;
168 }
169
170 static inline bool
171 ReportIllegal(struct xkb_keymap *keymap, enum xkb_action_type action,
172               enum action_field field)
173 {
174     log_err(keymap->ctx,
175             "Field %s is not defined for an action of type %s; "
176             "Action definition ignored\n",
177             fieldText(field), ActionTypeText(action));
178     return false;
179 }
180
181 static inline bool
182 ReportActionNotArray(struct xkb_keymap *keymap, enum xkb_action_type action,
183                      enum action_field field)
184 {
185     log_err(keymap->ctx,
186             "The %s field in the %s action is not an array; "
187             "Action definition ignored\n",
188             fieldText(field), ActionTypeText(action));
189     return false;
190 }
191
192 static inline bool
193 ReportNotFound(struct xkb_keymap *keymap, enum xkb_action_type action,
194                enum action_field field, const char *what, const char *bad)
195 {
196     log_err(keymap->ctx,
197             "%s named %s not found; "
198             "Ignoring the %s field of an %s action\n",
199             what, bad, fieldText(field), ActionTypeText(action));
200     return false;
201 }
202
203 static bool
204 HandleNoAction(struct xkb_keymap *keymap, union xkb_action *action,
205                enum action_field field, const ExprDef *array_ndx,
206                const ExprDef *value)
207
208 {
209     return true;
210 }
211
212 static bool
213 CheckLatchLockFlags(struct xkb_keymap *keymap, enum xkb_action_type action,
214                     enum action_field field, const ExprDef * value,
215                     enum xkb_action_flags *flags_inout)
216 {
217     enum xkb_action_flags tmp;
218     bool result;
219
220     if (field == ACTION_FIELD_CLEAR_LOCKS)
221         tmp = ACTION_LOCK_CLEAR;
222     else if (field == ACTION_FIELD_LATCH_TO_LOCK)
223         tmp = ACTION_LATCH_TO_LOCK;
224     else
225         return false;           /* WSGO! */
226
227     if (!ExprResolveBoolean(keymap->ctx, value, &result))
228         return ReportMismatch(keymap, action, field, "boolean");
229
230     if (result)
231         *flags_inout |= tmp;
232     else
233         *flags_inout &= ~tmp;
234
235     return true;
236 }
237
238 static bool
239 CheckModifierField(struct xkb_keymap *keymap, enum xkb_action_type action,
240                    const ExprDef *value, enum xkb_action_flags *flags_inout,
241                    xkb_mod_mask_t *mods_rtrn)
242 {
243     if (value->op == EXPR_IDENT) {
244         const char *valStr;
245         valStr = xkb_atom_text(keymap->ctx, value->value.str);
246         if (valStr && (istreq(valStr, "usemodmapmods") ||
247                        istreq(valStr, "modmapmods"))) {
248
249             *mods_rtrn = 0;
250             *flags_inout |= ACTION_MODS_LOOKUP_MODMAP;
251             return true;
252         }
253     }
254
255     if (!ExprResolveVModMask(keymap, value, mods_rtrn))
256         return ReportMismatch(keymap, action,
257                               ACTION_FIELD_MODIFIERS, "modifier mask");
258
259     *flags_inout &= ~ACTION_MODS_LOOKUP_MODMAP;
260     return true;
261 }
262
263 static bool
264 HandleSetLatchMods(struct xkb_keymap *keymap, union xkb_action *action,
265                    enum action_field field, const ExprDef *array_ndx,
266                    const ExprDef *value)
267 {
268     struct xkb_mod_action *act = &action->mods;
269     enum xkb_action_flags rtrn, t1;
270     xkb_mod_mask_t t2;
271
272     if (array_ndx != NULL) {
273         switch (field) {
274         case ACTION_FIELD_CLEAR_LOCKS:
275         case ACTION_FIELD_LATCH_TO_LOCK:
276         case ACTION_FIELD_MODIFIERS:
277             return ReportActionNotArray(keymap, action->type, field);
278         default:
279             break;
280         }
281     }
282
283     switch (field) {
284     case ACTION_FIELD_CLEAR_LOCKS:
285     case ACTION_FIELD_LATCH_TO_LOCK:
286         rtrn = act->flags;
287         if (CheckLatchLockFlags(keymap, action->type, field, value, &rtrn)) {
288             act->flags = rtrn;
289             return true;
290         }
291         return false;
292
293     case ACTION_FIELD_MODIFIERS:
294         t1 = act->flags;
295         if (CheckModifierField(keymap, action->type, value, &t1, &t2)) {
296             act->flags = t1;
297             act->mods.mods = t2;
298             return true;
299         }
300         return false;
301
302     default:
303         break;
304     }
305
306     return ReportIllegal(keymap, action->type, field);
307 }
308
309 static bool
310 HandleLockMods(struct xkb_keymap *keymap, union xkb_action *action,
311                enum action_field field, const ExprDef *array_ndx,
312                const ExprDef *value)
313 {
314     struct xkb_mod_action *act = &action->mods;
315     enum xkb_action_flags t1;
316     xkb_mod_mask_t t2;
317
318     if (array_ndx && field == ACTION_FIELD_MODIFIERS)
319         return ReportActionNotArray(keymap, action->type, field);
320
321     switch (field) {
322     case ACTION_FIELD_MODIFIERS:
323         t1 = act->flags;
324         if (CheckModifierField(keymap, action->type, value, &t1, &t2)) {
325             act->flags = t1;
326             act->mods.mods = t2;
327             return true;
328         }
329         return false;
330
331     default:
332         break;
333     }
334
335     return ReportIllegal(keymap, action->type, field);
336 }
337
338 static bool
339 CheckGroupField(struct xkb_keymap *keymap, unsigned action,
340                 const ExprDef *value, enum xkb_action_flags *flags_inout,
341                 xkb_group_index_t *grp_rtrn)
342 {
343     const ExprDef *spec;
344
345     if (value->op == EXPR_NEGATE || value->op == EXPR_UNARY_PLUS) {
346         *flags_inout &= ~ACTION_ABSOLUTE_SWITCH;
347         spec = value->value.child;
348     }
349     else {
350         *flags_inout |= ACTION_ABSOLUTE_SWITCH;
351         spec = value;
352     }
353
354     if (!ExprResolveGroup(keymap->ctx, spec, grp_rtrn))
355         return ReportMismatch(keymap, action, ACTION_FIELD_GROUP,
356                               "integer (range 1..8)");
357
358     if (value->op == EXPR_NEGATE)
359         *grp_rtrn = -*grp_rtrn;
360     else if (value->op != EXPR_UNARY_PLUS)
361         (*grp_rtrn)--;
362
363     return true;
364 }
365
366 static bool
367 HandleSetLatchGroup(struct xkb_keymap *keymap, union xkb_action *action,
368                     enum action_field field, const ExprDef *array_ndx,
369                     const ExprDef *value)
370 {
371     struct xkb_group_action *act = &action->group;
372     enum xkb_action_flags rtrn, t1;
373     xkb_group_index_t t2;
374
375     if (array_ndx != NULL) {
376         switch (field) {
377         case ACTION_FIELD_CLEAR_LOCKS:
378         case ACTION_FIELD_LATCH_TO_LOCK:
379         case ACTION_FIELD_GROUP:
380             return ReportActionNotArray(keymap, action->type, field);
381
382         default:
383             break;
384         }
385     }
386
387     switch (field) {
388     case ACTION_FIELD_CLEAR_LOCKS:
389     case ACTION_FIELD_LATCH_TO_LOCK:
390         rtrn = act->flags;
391         if (CheckLatchLockFlags(keymap, action->type, field, value, &rtrn)) {
392             act->flags = rtrn;
393             return true;
394         }
395         return false;
396
397     case ACTION_FIELD_GROUP:
398         t1 = act->flags;
399         if (CheckGroupField(keymap, action->type, value, &t1, &t2)) {
400             act->flags = t1;
401             act->group = t2;
402             return true;
403         }
404         return false;
405
406     default:
407         break;
408     }
409
410     return ReportIllegal(keymap, action->type, field);
411 }
412
413 static bool
414 HandleLockGroup(struct xkb_keymap *keymap, union xkb_action *action,
415                 enum action_field field, const ExprDef *array_ndx,
416                 const ExprDef *value)
417 {
418     struct xkb_group_action *act = &action->group;
419     enum xkb_action_flags t1;
420     xkb_group_index_t t2;
421
422     if ((array_ndx != NULL) && (field == ACTION_FIELD_GROUP))
423         return ReportActionNotArray(keymap, action->type, field);
424     if (field == ACTION_FIELD_GROUP) {
425         t1 = act->flags;
426         if (CheckGroupField(keymap, action->type, value, &t1, &t2)) {
427             act->flags = t1;
428             act->group = t2;
429             return true;
430         }
431         return false;
432     }
433     return ReportIllegal(keymap, action->type, field);
434 }
435
436 static bool
437 HandleMovePtr(struct xkb_keymap *keymap, union xkb_action *action,
438               enum action_field field, const ExprDef *array_ndx,
439               const ExprDef *value)
440 {
441     struct xkb_pointer_action *act = &action->ptr;
442     bool absolute;
443
444     if (array_ndx && (field == ACTION_FIELD_X || field == ACTION_FIELD_Y))
445         return ReportActionNotArray(keymap, action->type, field);
446
447     if (field == ACTION_FIELD_X || field == ACTION_FIELD_Y) {
448         int val;
449
450         if (value->op == EXPR_NEGATE || value->op == EXPR_UNARY_PLUS)
451             absolute = false;
452         else
453             absolute = true;
454
455         if (!ExprResolveInteger(keymap->ctx, value, &val))
456             return ReportMismatch(keymap, action->type, field, "integer");
457
458         if (field == ACTION_FIELD_X) {
459             if (absolute)
460                 act->flags |= ACTION_ABSOLUTE_X;
461             act->x = val;
462         }
463         else {
464             if (absolute)
465                 act->flags |= ACTION_ABSOLUTE_Y;
466             act->y = val;
467         }
468
469         return true;
470     }
471     else if (field == ACTION_FIELD_ACCEL) {
472         bool set;
473
474         if (!ExprResolveBoolean(keymap->ctx, value, &set))
475             return ReportMismatch(keymap, action->type, field, "boolean");
476
477         if (set)
478             act->flags &= ~ACTION_NO_ACCEL;
479         else
480             act->flags |= ACTION_NO_ACCEL;
481     }
482
483     return ReportIllegal(keymap, action->type, field);
484 }
485
486 static const LookupEntry lockWhich[] = {
487     { "both", 0 },
488     { "lock", ACTION_LOCK_NO_UNLOCK },
489     { "neither", (ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK) },
490     { "unlock", ACTION_LOCK_NO_LOCK },
491     { NULL, 0 }
492 };
493
494 static bool
495 HandlePtrBtn(struct xkb_keymap *keymap, union xkb_action *action,
496              enum action_field field, const ExprDef *array_ndx,
497              const ExprDef *value)
498 {
499     struct xkb_pointer_button_action *act = &action->btn;
500
501     if (field == ACTION_FIELD_BUTTON) {
502         int btn;
503
504         if (array_ndx)
505             return ReportActionNotArray(keymap, action->type, field);
506
507         if (!ExprResolveButton(keymap->ctx, value, &btn))
508             return ReportMismatch(keymap, action->type, field,
509                                   "integer (range 1..5)");
510
511         if (btn < 0 || btn > 5) {
512             log_err(keymap->ctx,
513                     "Button must specify default or be in the range 1..5; "
514                     "Illegal button value %d ignored\n", btn);
515             return false;
516         }
517
518         act->button = btn;
519         return true;
520     }
521     else if (action->type == ACTION_TYPE_PTR_LOCK &&
522              field == ACTION_FIELD_AFFECT) {
523         enum xkb_action_flags val;
524
525         if (array_ndx)
526             return ReportActionNotArray(keymap, action->type, field);
527
528         if (!ExprResolveEnum(keymap->ctx, value, &val, lockWhich))
529             return ReportMismatch(keymap, action->type, field,
530                                   "lock or unlock");
531
532         act->flags &= ~(ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK);
533         act->flags |= val;
534         return true;
535     }
536     else if (field == ACTION_FIELD_COUNT) {
537         int btn;
538
539         if (array_ndx)
540             return ReportActionNotArray(keymap, action->type, field);
541
542         /* XXX: Should this actually be ResolveButton? */
543         if (!ExprResolveButton(keymap->ctx, value, &btn))
544             return ReportMismatch(keymap, action->type, field, "integer");
545
546         if (btn < 0 || btn > 255) {
547             log_err(keymap->ctx,
548                     "The count field must have a value in the range 0..255; "
549                     "Illegal count %d ignored\n", btn);
550             return false;
551         }
552
553         act->count = btn;
554         return true;
555     }
556     return ReportIllegal(keymap, action->type, field);
557 }
558
559 static const LookupEntry ptrDflts[] = {
560     { "dfltbtn", 1 },
561     { "defaultbutton", 1 },
562     { "button", 1 },
563     { NULL, 0 }
564 };
565
566 static bool
567 HandleSetPtrDflt(struct xkb_keymap *keymap, union xkb_action *action,
568                  enum action_field field, const ExprDef *array_ndx,
569                  const ExprDef *value)
570 {
571     struct xkb_pointer_default_action *act = &action->dflt;
572
573     if (field == ACTION_FIELD_AFFECT) {
574         unsigned int val;
575
576         if (array_ndx)
577             return ReportActionNotArray(keymap, action->type, field);
578
579         if (!ExprResolveEnum(keymap->ctx, value, &val, ptrDflts))
580             return ReportMismatch(keymap, action->type, field,
581                                   "pointer component");
582         return true;
583     }
584     else if (field == ACTION_FIELD_BUTTON || field == ACTION_FIELD_VALUE) {
585         const ExprDef *button;
586         int btn;
587
588         if (array_ndx)
589             return ReportActionNotArray(keymap, action->type, field);
590
591         if (value->op == EXPR_NEGATE || value->op == EXPR_UNARY_PLUS) {
592             act->flags &= ~ACTION_ABSOLUTE_SWITCH;
593             button = value->value.child;
594         }
595         else {
596             act->flags |= ACTION_ABSOLUTE_SWITCH;
597             button = value;
598         }
599
600         if (!ExprResolveButton(keymap->ctx, button, &btn))
601             return ReportMismatch(keymap, action->type, field,
602                                   "integer (range 1..5)");
603
604         if (btn < 0 || btn > 5) {
605             log_err(keymap->ctx,
606                     "New default button value must be in the range 1..5; "
607                     "Illegal default button value %d ignored\n", btn);
608             return false;
609         }
610         if (btn == 0) {
611             log_err(keymap->ctx,
612                     "Cannot set default pointer button to \"default\"; "
613                     "Illegal default button setting ignored\n");
614             return false;
615         }
616
617         act->value = (value->op == EXPR_NEGATE ? -btn: btn);
618         return true;
619     }
620
621     return ReportIllegal(keymap, action->type, field);
622 }
623
624 static bool
625 HandleSwitchScreen(struct xkb_keymap *keymap, union xkb_action *action,
626                    enum action_field field, const ExprDef *array_ndx,
627                    const ExprDef *value)
628 {
629     struct xkb_switch_screen_action *act = &action->screen;
630
631     if (field == ACTION_FIELD_SCREEN) {
632         const ExprDef *scrn;
633         int val;
634
635         if (array_ndx)
636             return ReportActionNotArray(keymap, action->type, field);
637
638         if (value->op == EXPR_NEGATE || value->op == EXPR_UNARY_PLUS) {
639             act->flags &= ~ACTION_ABSOLUTE_SWITCH;
640             scrn = value->value.child;
641         }
642         else {
643             act->flags |= ACTION_ABSOLUTE_SWITCH;
644             scrn = value;
645         }
646
647         if (!ExprResolveInteger(keymap->ctx, scrn, &val))
648             return ReportMismatch(keymap, action->type, field,
649                                   "integer (0..255)");
650
651         if (val < 0 || val > 255) {
652             log_err(keymap->ctx,
653                     "Screen index must be in the range 1..255; "
654                     "Illegal screen value %d ignored\n", val);
655             return false;
656         }
657
658         act->screen = (value->op == EXPR_NEGATE ? -val : val);
659         return true;
660     }
661     else if (field == ACTION_FIELD_SAME) {
662         bool set;
663
664         if (array_ndx)
665             return ReportActionNotArray(keymap, action->type, field);
666
667         if (!ExprResolveBoolean(keymap->ctx, value, &set))
668             return ReportMismatch(keymap, action->type, field, "boolean");
669
670         if (set)
671             act->flags &= ~ACTION_SAME_SCREEN;
672         else
673             act->flags |= ACTION_SAME_SCREEN;
674
675         return true;
676     }
677
678     return ReportIllegal(keymap, action->type, field);
679 }
680
681 static bool
682 HandleSetLockControls(struct xkb_keymap *keymap, union xkb_action *action,
683                       enum action_field field, const ExprDef *array_ndx,
684                       const ExprDef *value)
685 {
686     struct xkb_controls_action *act = &action->ctrls;
687
688     if (field == ACTION_FIELD_CONTROLS) {
689         unsigned int mask;
690
691         if (array_ndx)
692             return ReportActionNotArray(keymap, action->type, field);
693
694         if (!ExprResolveMask(keymap->ctx, value, &mask, ctrlMaskNames))
695             return ReportMismatch(keymap, action->type, field,
696                                   "controls mask");
697
698         act->ctrls = mask;
699         return true;
700     }
701
702     return ReportIllegal(keymap, action->type, field);
703 }
704
705 static bool
706 HandlePrivate(struct xkb_keymap *keymap, union xkb_action *action,
707               enum action_field field, const ExprDef *array_ndx,
708               const ExprDef *value)
709 {
710     struct xkb_private_action *act = &action->priv;
711
712     if (field == ACTION_FIELD_TYPE) {
713         int type;
714
715         if (!ExprResolveInteger(keymap->ctx, value, &type))
716             return ReportMismatch(keymap, ACTION_TYPE_PRIVATE, field, "integer");
717
718         if (type < 0 || type > 255) {
719             log_err(keymap->ctx,
720                     "Private action type must be in the range 0..255; "
721                     "Illegal type %d ignored\n", type);
722             return false;
723         }
724
725         act->type = (uint8_t) type;
726         return true;
727     }
728     else if (field == ACTION_FIELD_DATA) {
729         if (array_ndx == NULL) {
730             xkb_atom_t val;
731             const char *str;
732             int len;
733
734             if (!ExprResolveString(keymap->ctx, value, &val))
735                 return ReportMismatch(keymap, action->type, field, "string");
736
737             str = xkb_atom_text(keymap->ctx, val);
738             len = strlen(str);
739             if (len < 1 || len > 7) {
740                 log_warn(keymap->ctx,
741                          "A private action has 7 data bytes; "
742                          "Extra %d bytes ignored\n", len - 6);
743                 return false;
744             }
745
746             strncpy((char *) act->data, str, sizeof(act->data));
747             return true;
748         }
749         else {
750             int ndx, datum;
751
752             if (!ExprResolveInteger(keymap->ctx, array_ndx, &ndx)) {
753                 log_err(keymap->ctx,
754                         "Array subscript must be integer; "
755                         "Illegal subscript ignored\n");
756                 return false;
757             }
758
759             if (ndx < 0 || ndx >= sizeof(act->data)) {
760                 log_err(keymap->ctx,
761                         "The data for a private action is %zu bytes long; "
762                         "Attempt to use data[%d] ignored\n",
763                         sizeof(act->data), ndx);
764                 return false;
765             }
766
767             if (!ExprResolveInteger(keymap->ctx, value, &datum))
768                 return ReportMismatch(keymap, act->type, field, "integer");
769
770             if (datum < 0 || datum > 255) {
771                 log_err(keymap->ctx,
772                         "All data for a private action must be 0..255; "
773                         "Illegal datum %d ignored\n", datum);
774                 return false;
775             }
776
777             act->data[ndx] = (uint8_t) datum;
778             return true;
779         }
780     }
781
782     return ReportIllegal(keymap, ACTION_TYPE_NONE, field);
783 }
784
785 typedef bool (*actionHandler)(struct xkb_keymap *keymap,
786                               union xkb_action *action,
787                               enum action_field field,
788                               const ExprDef *array_ndx,
789                               const ExprDef *value);
790
791 static const actionHandler handleAction[ACTION_TYPE_LAST] = {
792     [ACTION_TYPE_NONE] = HandleNoAction,
793     [ACTION_TYPE_MOD_SET] = HandleSetLatchMods,
794     [ACTION_TYPE_MOD_LATCH] = HandleSetLatchMods,
795     [ACTION_TYPE_MOD_LOCK] = HandleLockMods,
796     [ACTION_TYPE_GROUP_SET] = HandleSetLatchGroup,
797     [ACTION_TYPE_GROUP_LATCH] = HandleSetLatchGroup,
798     [ACTION_TYPE_GROUP_LOCK] = HandleLockGroup,
799     [ACTION_TYPE_PTR_MOVE] = HandleMovePtr,
800     [ACTION_TYPE_PTR_BUTTON] = HandlePtrBtn,
801     [ACTION_TYPE_PTR_LOCK] = HandlePtrBtn,
802     [ACTION_TYPE_PTR_DEFAULT] = HandleSetPtrDflt,
803     [ACTION_TYPE_TERMINATE] = HandleNoAction,
804     [ACTION_TYPE_SWITCH_VT] = HandleSwitchScreen,
805     [ACTION_TYPE_CTRL_SET] = HandleSetLockControls,
806     [ACTION_TYPE_CTRL_LOCK] = HandleSetLockControls,
807     [ACTION_TYPE_PRIVATE] = HandlePrivate,
808 };
809
810 /***====================================================================***/
811
812 bool
813 HandleActionDef(ExprDef *def, struct xkb_keymap *keymap,
814                 union xkb_action *action, ActionsInfo *info)
815 {
816     ExprDef *arg;
817     const char *str;
818     unsigned hndlrType;
819
820     if (def->op != EXPR_ACTION_DECL) {
821         log_err(keymap->ctx, "Expected an action definition, found %s\n",
822                 expr_op_type_to_string(def->op));
823         return false;
824     }
825
826     str = xkb_atom_text(keymap->ctx, def->value.action.name);
827     if (!stringToAction(str, &hndlrType)) {
828         log_err(keymap->ctx, "Unknown action %s\n", str);
829         return false;
830     }
831
832     /*
833      * Get the default values for this action type, as modified by
834      * statements such as:
835      *     latchMods.clearLocks = True;
836      */
837     *action = info->actions[hndlrType];
838
839     /*
840      * Now change the action properties as specified for this
841      * particular instance, e.g. "modifiers" and "clearLocks" in:
842      *     SetMods(modifiers=Alt,clearLocks);
843      */
844     for (arg = def->value.action.args; arg != NULL;
845          arg = (ExprDef *) arg->common.next) {
846         const ExprDef *value;
847         ExprDef *field, *arrayRtrn;
848         const char *elemRtrn, *fieldRtrn;
849         enum action_field fieldNdx;
850
851         if (arg->op == EXPR_ASSIGN) {
852             field = arg->value.binary.left;
853             value = arg->value.binary.right;
854         }
855         else if (arg->op == EXPR_NOT || arg->op == EXPR_INVERT) {
856             field = arg->value.child;
857             value = &constFalse;
858         }
859         else {
860             field = arg;
861             value = &constTrue;
862         }
863
864         if (!ExprResolveLhs(keymap->ctx, field, &elemRtrn, &fieldRtrn,
865                             &arrayRtrn))
866             return false;
867
868         if (elemRtrn) {
869             log_err(keymap->ctx,
870                     "Cannot change defaults in an action definition; "
871                     "Ignoring attempt to change %s.%s\n",
872                     elemRtrn, fieldRtrn);
873             return false;
874         }
875
876         if (!stringToField(fieldRtrn, &fieldNdx)) {
877             log_err(keymap->ctx, "Unknown field name %s\n", fieldRtrn);
878             return false;
879         }
880
881         if (!handleAction[hndlrType](keymap, action, fieldNdx, arrayRtrn,
882                                      value))
883             return false;
884     }
885
886     return true;
887 }
888
889
890 bool
891 SetActionField(struct xkb_keymap *keymap, const char *elem, const char *field,
892                ExprDef *array_ndx, ExprDef *value, ActionsInfo *info)
893 {
894     unsigned action;
895     enum action_field action_field;
896
897     if (!stringToAction(elem, &action))
898         return false;
899
900     if (!stringToField(field, &action_field)) {
901         log_err(keymap->ctx, "\"%s\" is not a legal field name\n", field);
902         return false;
903     }
904
905     return handleAction[action](keymap, &info->actions[action],
906                                 action_field, array_ndx, value);
907 }