1 /************************************************************
2 * Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
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.
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.
25 ********************************************************/
27 #include "xkbcomp-priv.h"
33 #define PrivateAction (XkbSA_LastAction + 1)
35 static const ExprDef constTrue = {
36 .common = { .type = STMT_EXPR, .next = NULL },
38 .value_type = EXPR_TYPE_BOOLEAN,
39 .value = { .ival = 1 },
42 static const ExprDef constFalse = {
43 .common = { .type = STMT_EXPR, .next = NULL },
45 .value_type = EXPR_TYPE_BOOLEAN,
46 .value = { .ival = 0 },
50 ACTION_FIELD_CLEAR_LOCKS,
51 ACTION_FIELD_LATCH_TO_LOCK,
52 ACTION_FIELD_GEN_KEY_EVENT,
56 ACTION_FIELD_INCREMENT,
57 ACTION_FIELD_MODIFIERS,
64 ACTION_FIELD_CONTROLS,
72 ACTION_FIELD_MODS_TO_CLEAR,
81 info = calloc(1, sizeof(*info));
85 /* This includes PrivateAction. */
86 for (type = 0; type < XkbSA_NumActions + 1; type++)
87 info->actions[type].type = type;
89 /* Apply some "factory defaults". */
91 /* Increment default button. */
92 info->actions[XkbSA_SetPtrDflt].dflt.affect = XkbSA_AffectDfltBtn;
93 info->actions[XkbSA_SetPtrDflt].dflt.flags = 0;
94 info->actions[XkbSA_SetPtrDflt].dflt.value = 1;
96 info->actions[XkbSA_ISOLock].iso.mods.mods =
97 (1 << ModNameToIndex(XKB_MOD_NAME_CAPS));
103 FreeActionsInfo(ActionsInfo *info)
108 static const LookupEntry actionStrings[] = {
109 { "noaction", XkbSA_NoAction },
110 { "setmods", XkbSA_SetMods },
111 { "latchmods", XkbSA_LatchMods },
112 { "lockmods", XkbSA_LockMods },
113 { "setgroup", XkbSA_SetGroup },
114 { "latchgroup", XkbSA_LatchGroup },
115 { "lockgroup", XkbSA_LockGroup },
116 { "moveptr", XkbSA_MovePtr },
117 { "movepointer", XkbSA_MovePtr },
118 { "ptrbtn", XkbSA_PtrBtn },
119 { "pointerbutton", XkbSA_PtrBtn },
120 { "lockptrbtn", XkbSA_LockPtrBtn },
121 { "lockpointerbutton", XkbSA_LockPtrBtn },
122 { "lockptrbutton", XkbSA_LockPtrBtn },
123 { "lockpointerbtn", XkbSA_LockPtrBtn },
124 { "setptrdflt", XkbSA_SetPtrDflt },
125 { "setpointerdefault", XkbSA_SetPtrDflt },
126 { "isolock", XkbSA_ISOLock },
127 { "terminate", XkbSA_Terminate },
128 { "terminateserver", XkbSA_Terminate },
129 { "switchscreen", XkbSA_SwitchScreen },
130 { "setcontrols", XkbSA_SetControls },
131 { "lockcontrols", XkbSA_LockControls },
132 { "actionmessage", XkbSA_ActionMessage },
133 { "messageaction", XkbSA_ActionMessage },
134 { "message", XkbSA_ActionMessage },
135 { "redirect", XkbSA_RedirectKey },
136 { "redirectkey", XkbSA_RedirectKey },
137 { "devbtn", XkbSA_DeviceBtn },
138 { "devicebtn", XkbSA_DeviceBtn },
139 { "devbutton", XkbSA_DeviceBtn },
140 { "devicebutton", XkbSA_DeviceBtn },
141 { "lockdevbtn", XkbSA_DeviceBtn },
142 { "lockdevicebtn", XkbSA_LockDeviceBtn },
143 { "lockdevbutton", XkbSA_LockDeviceBtn },
144 { "lockdevicebutton", XkbSA_LockDeviceBtn },
145 { "devval", XkbSA_DeviceValuator },
146 { "deviceval", XkbSA_DeviceValuator },
147 { "devvaluator", XkbSA_DeviceValuator },
148 { "devicevaluator", XkbSA_DeviceValuator },
149 { "private", PrivateAction },
153 static const LookupEntry fieldStrings[] = {
154 { "clearLocks", ACTION_FIELD_CLEAR_LOCKS },
155 { "latchToLock", ACTION_FIELD_LATCH_TO_LOCK },
156 { "genKeyEvent", ACTION_FIELD_GEN_KEY_EVENT },
157 { "generateKeyEvent", ACTION_FIELD_GEN_KEY_EVENT },
158 { "report", ACTION_FIELD_REPORT },
159 { "default", ACTION_FIELD_DEFAULT },
160 { "affect", ACTION_FIELD_AFFECT },
161 { "increment", ACTION_FIELD_INCREMENT },
162 { "modifiers", ACTION_FIELD_MODIFIERS },
163 { "mods", ACTION_FIELD_MODIFIERS },
164 { "group", ACTION_FIELD_GROUP },
165 { "x", ACTION_FIELD_X },
166 { "y", ACTION_FIELD_Y },
167 { "accel", ACTION_FIELD_ACCEL },
168 { "accelerate", ACTION_FIELD_ACCEL },
169 { "repeat", ACTION_FIELD_ACCEL },
170 { "button", ACTION_FIELD_BUTTON },
171 { "value", ACTION_FIELD_VALUE },
172 { "controls", ACTION_FIELD_CONTROLS },
173 { "ctrls", ACTION_FIELD_CONTROLS },
174 { "type", ACTION_FIELD_TYPE },
175 { "count", ACTION_FIELD_COUNT },
176 { "screen", ACTION_FIELD_SCREEN },
177 { "same", ACTION_FIELD_SAME },
178 { "sameServer", ACTION_FIELD_SAME },
179 { "data", ACTION_FIELD_DATA },
180 { "device", ACTION_FIELD_DEVICE },
181 { "dev", ACTION_FIELD_DEVICE },
182 { "key", ACTION_FIELD_KEYCODE },
183 { "keycode", ACTION_FIELD_KEYCODE },
184 { "kc", ACTION_FIELD_KEYCODE },
185 { "clearmods", ACTION_FIELD_MODS_TO_CLEAR },
186 { "clearmodifiers", ACTION_FIELD_MODS_TO_CLEAR },
191 stringToValue(const LookupEntry tab[], const char *string,
192 unsigned int *value_rtrn)
194 const LookupEntry *entry;
199 for (entry = tab; entry->name; entry++) {
200 if (istreq(entry->name, string)) {
201 *value_rtrn = entry->value;
210 valueToString(const LookupEntry tab[], unsigned int value)
212 const LookupEntry *entry;
214 for (entry = tab; entry->name; entry++)
215 if (entry->value == value)
222 stringToAction(const char *str, unsigned *type_rtrn)
224 return stringToValue(actionStrings, str, type_rtrn);
228 stringToField(const char *str, enum action_field *field_rtrn)
230 return stringToValue(fieldStrings, str, field_rtrn);
234 fieldText(enum action_field field)
236 return valueToString(fieldStrings, field);
239 /***====================================================================***/
242 ReportMismatch(struct xkb_keymap *keymap, unsigned action,
243 enum action_field field, const char *type)
246 "Value of %s field must be of type %s; "
247 "Action %s definition ignored\n",
248 fieldText(field), type, ActionTypeText(action));
253 ReportIllegal(struct xkb_keymap *keymap, unsigned action,
254 enum action_field field)
257 "Field %s is not defined for an action of type %s; "
258 "Action definition ignored\n",
259 fieldText(field), ActionTypeText(action));
264 ReportActionNotArray(struct xkb_keymap *keymap, unsigned action,
265 enum action_field field)
268 "The %s field in the %s action is not an array; "
269 "Action definition ignored\n",
270 fieldText(field), ActionTypeText(action));
275 ReportNotFound(struct xkb_keymap *keymap, unsigned action,
276 enum action_field field, const char *what, const char *bad)
279 "%s named %s not found; "
280 "Ignoring the %s field of an %s action\n",
281 what, bad, fieldText(field), ActionTypeText(action));
286 HandleNoAction(struct xkb_keymap *keymap, union xkb_action *action,
287 enum action_field field, const ExprDef *array_ndx,
288 const ExprDef *value)
291 return ReportIllegal(keymap, action->type, field);
295 CheckLatchLockFlags(struct xkb_keymap *keymap, unsigned action,
296 enum action_field field, const ExprDef * value,
297 unsigned *flags_inout)
302 if (field == ACTION_FIELD_CLEAR_LOCKS)
303 tmp = XkbSA_ClearLocks;
304 else if (field == ACTION_FIELD_LATCH_TO_LOCK)
305 tmp = XkbSA_LatchToLock;
307 return false; /* WSGO! */
309 if (!ExprResolveBoolean(keymap->ctx, value, &result))
310 return ReportMismatch(keymap, action, field, "boolean");
315 *flags_inout &= ~tmp;
321 CheckModifierField(struct xkb_keymap *keymap, unsigned action,
322 const ExprDef *value, unsigned *flags_inout,
323 xkb_mod_mask_t *mods_rtrn)
325 if (value->op == EXPR_IDENT) {
327 valStr = xkb_atom_text(keymap->ctx, value->value.str);
328 if (valStr && (istreq(valStr, "usemodmapmods") ||
329 istreq(valStr, "modmapmods"))) {
332 *flags_inout |= XkbSA_UseModMapMods;
337 if (!ExprResolveVModMask(keymap, value, mods_rtrn))
338 return ReportMismatch(keymap, action,
339 ACTION_FIELD_MODIFIERS, "modifier mask");
341 *flags_inout &= ~XkbSA_UseModMapMods;
346 HandleSetLatchMods(struct xkb_keymap *keymap, union xkb_action *action,
347 enum action_field field, const ExprDef *array_ndx,
348 const ExprDef *value)
350 struct xkb_mod_action *act = &action->mods;
355 if (array_ndx != NULL) {
357 case ACTION_FIELD_CLEAR_LOCKS:
358 case ACTION_FIELD_LATCH_TO_LOCK:
359 case ACTION_FIELD_MODIFIERS:
360 return ReportActionNotArray(keymap, action->type, field);
367 case ACTION_FIELD_CLEAR_LOCKS:
368 case ACTION_FIELD_LATCH_TO_LOCK:
370 if (CheckLatchLockFlags(keymap, action->type, field, value, &rtrn)) {
376 case ACTION_FIELD_MODIFIERS:
378 if (CheckModifierField(keymap, action->type, value, &t1, &t2)) {
389 return ReportIllegal(keymap, action->type, field);
393 HandleLockMods(struct xkb_keymap *keymap, union xkb_action *action,
394 enum action_field field, const ExprDef *array_ndx,
395 const ExprDef *value)
397 struct xkb_mod_action *act = &action->mods;
401 if (array_ndx && field == ACTION_FIELD_MODIFIERS)
402 return ReportActionNotArray(keymap, action->type, field);
405 case ACTION_FIELD_MODIFIERS:
407 if (CheckModifierField(keymap, action->type, value, &t1, &t2)) {
418 return ReportIllegal(keymap, action->type, field);
422 CheckGroupField(struct xkb_keymap *keymap, unsigned action,
423 const ExprDef *value, unsigned *flags_inout,
424 xkb_group_index_t *grp_rtrn)
428 if (value->op == EXPR_NEGATE || value->op == EXPR_UNARY_PLUS) {
429 *flags_inout &= ~XkbSA_GroupAbsolute;
430 spec = value->value.child;
433 *flags_inout |= XkbSA_GroupAbsolute;
437 if (!ExprResolveGroup(keymap->ctx, spec, grp_rtrn))
438 return ReportMismatch(keymap, action, ACTION_FIELD_GROUP,
439 "integer (range 1..8)");
441 if (value->op == EXPR_NEGATE)
442 *grp_rtrn = -*grp_rtrn;
443 else if (value->op != EXPR_UNARY_PLUS)
450 HandleSetLatchGroup(struct xkb_keymap *keymap, union xkb_action *action,
451 enum action_field field, const ExprDef *array_ndx,
452 const ExprDef *value)
454 struct xkb_group_action *act = &action->group;
457 xkb_group_index_t t2;
459 if (array_ndx != NULL) {
461 case ACTION_FIELD_CLEAR_LOCKS:
462 case ACTION_FIELD_LATCH_TO_LOCK:
463 case ACTION_FIELD_GROUP:
464 return ReportActionNotArray(keymap, action->type, field);
472 case ACTION_FIELD_CLEAR_LOCKS:
473 case ACTION_FIELD_LATCH_TO_LOCK:
475 if (CheckLatchLockFlags(keymap, action->type, field, value, &rtrn)) {
481 case ACTION_FIELD_GROUP:
483 if (CheckGroupField(keymap, action->type, value, &t1, &t2)) {
494 return ReportIllegal(keymap, action->type, field);
498 HandleLockGroup(struct xkb_keymap *keymap, union xkb_action *action,
499 enum action_field field, const ExprDef *array_ndx,
500 const ExprDef *value)
502 struct xkb_group_action *act = &action->group;
504 xkb_group_index_t t2;
506 if ((array_ndx != NULL) && (field == ACTION_FIELD_GROUP))
507 return ReportActionNotArray(keymap, action->type, field);
508 if (field == ACTION_FIELD_GROUP) {
510 if (CheckGroupField(keymap, action->type, value, &t1, &t2)) {
517 return ReportIllegal(keymap, action->type, field);
521 HandleMovePtr(struct xkb_keymap *keymap, union xkb_action *action,
522 enum action_field field, const ExprDef *array_ndx,
523 const ExprDef *value)
525 struct xkb_pointer_action *act = &action->ptr;
528 if (array_ndx && (field == ACTION_FIELD_X || field == ACTION_FIELD_Y))
529 return ReportActionNotArray(keymap, action->type, field);
531 if (field == ACTION_FIELD_X || field == ACTION_FIELD_Y) {
534 if (value->op == EXPR_NEGATE || value->op == EXPR_UNARY_PLUS)
539 if (!ExprResolveInteger(keymap->ctx, value, &val))
540 return ReportMismatch(keymap, action->type, field, "integer");
542 if (field == ACTION_FIELD_X) {
544 act->flags |= XkbSA_MoveAbsoluteX;
549 act->flags |= XkbSA_MoveAbsoluteY;
555 else if (field == ACTION_FIELD_ACCEL) {
558 if (!ExprResolveBoolean(keymap->ctx, value, &set))
559 return ReportMismatch(keymap, action->type, field, "boolean");
562 act->flags &= ~XkbSA_NoAcceleration;
564 act->flags |= XkbSA_NoAcceleration;
567 return ReportIllegal(keymap, action->type, field);
570 static const LookupEntry lockWhich[] = {
572 { "lock", XkbSA_LockNoUnlock },
573 { "neither", (XkbSA_LockNoLock | XkbSA_LockNoUnlock) },
574 { "unlock", XkbSA_LockNoLock },
579 HandlePtrBtn(struct xkb_keymap *keymap, union xkb_action *action,
580 enum action_field field, const ExprDef *array_ndx,
581 const ExprDef *value)
583 struct xkb_pointer_button_action *act = &action->btn;
585 if (field == ACTION_FIELD_BUTTON) {
589 return ReportActionNotArray(keymap, action->type, field);
591 if (!ExprResolveButton(keymap->ctx, value, &btn))
592 return ReportMismatch(keymap, action->type, field,
593 "integer (range 1..5)");
595 if (btn < 0 || btn > 5) {
597 "Button must specify default or be in the range 1..5; "
598 "Illegal button value %d ignored\n", btn);
605 else if (action->type == XkbSA_LockPtrBtn &&
606 field == ACTION_FIELD_AFFECT) {
610 return ReportActionNotArray(keymap, action->type, field);
612 if (!ExprResolveEnum(keymap->ctx, value, &val, lockWhich))
613 return ReportMismatch(keymap, action->type, field,
616 act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock);
620 else if (field == ACTION_FIELD_COUNT) {
624 return ReportActionNotArray(keymap, action->type, field);
626 /* XXX: Should this actually be ResolveButton? */
627 if (!ExprResolveButton(keymap->ctx, value, &btn))
628 return ReportMismatch(keymap, action->type, field, "integer");
630 if (btn < 0 || btn > 255) {
632 "The count field must have a value in the range 0..255; "
633 "Illegal count %d ignored\n", btn);
640 return ReportIllegal(keymap, action->type, field);
643 static const LookupEntry ptrDflts[] = {
644 { "dfltbtn", XkbSA_AffectDfltBtn },
645 { "defaultbutton", XkbSA_AffectDfltBtn },
646 { "button", XkbSA_AffectDfltBtn },
651 HandleSetPtrDflt(struct xkb_keymap *keymap, union xkb_action *action,
652 enum action_field field, const ExprDef *array_ndx,
653 const ExprDef *value)
655 struct xkb_pointer_default_action *act = &action->dflt;
657 if (field == ACTION_FIELD_AFFECT) {
661 return ReportActionNotArray(keymap, action->type, field);
663 if (!ExprResolveEnum(keymap->ctx, value, &val, ptrDflts))
664 return ReportMismatch(keymap, action->type, field,
665 "pointer component");
669 else if (field == ACTION_FIELD_BUTTON || field == ACTION_FIELD_VALUE) {
670 const ExprDef *button;
674 return ReportActionNotArray(keymap, action->type, field);
676 if (value->op == EXPR_NEGATE || value->op == EXPR_UNARY_PLUS) {
677 act->flags &= ~XkbSA_DfltBtnAbsolute;
678 button = value->value.child;
681 act->flags |= XkbSA_DfltBtnAbsolute;
685 if (!ExprResolveButton(keymap->ctx, button, &btn))
686 return ReportMismatch(keymap, action->type, field,
687 "integer (range 1..5)");
689 if (btn < 0 || btn > 5) {
691 "New default button value must be in the range 1..5; "
692 "Illegal default button value %d ignored\n", btn);
697 "Cannot set default pointer button to \"default\"; "
698 "Illegal default button setting ignored\n");
702 act->value = (value->op == EXPR_NEGATE ? -btn: btn);
706 return ReportIllegal(keymap, action->type, field);
709 static const LookupEntry isoNames[] = {
710 { "mods", XkbSA_ISONoAffectMods },
711 { "modifiers", XkbSA_ISONoAffectMods },
712 { "group", XkbSA_ISONoAffectGroup },
713 { "groups", XkbSA_ISONoAffectGroup },
714 { "ptr", XkbSA_ISONoAffectPtr },
715 { "pointer", XkbSA_ISONoAffectPtr },
716 { "ctrls", XkbSA_ISONoAffectCtrls },
717 { "controls", XkbSA_ISONoAffectCtrls },
718 { "all", ~((unsigned) 0) },
724 HandleISOLock(struct xkb_keymap *keymap, union xkb_action *action,
725 enum action_field field, const ExprDef *array_ndx,
726 const ExprDef *value)
728 struct xkb_iso_action *act = &action->iso;
730 if (field == ACTION_FIELD_MODIFIERS) {
735 return ReportActionNotArray(keymap, action->type, field);
738 if (!CheckModifierField(keymap, action->type, value, &flags, &mods))
741 act->flags = flags & (~XkbSA_ISODfltIsGroup);
742 act->mods.mods = mods;
745 else if (field == ACTION_FIELD_GROUP) {
746 xkb_group_index_t group;
750 return ReportActionNotArray(keymap, action->type, field);
753 if (!CheckGroupField(keymap, action->type, value, &flags, &group))
756 act->flags = flags | XkbSA_ISODfltIsGroup;
759 } else if (ACTION_FIELD_AFFECT) {
763 return ReportActionNotArray(keymap, action->type, field);
765 if (!ExprResolveMask(keymap->ctx, value, &mask, isoNames))
766 return ReportMismatch(keymap, action->type, field,
767 "keyboard component");
769 act->affect = (~mask) & XkbSA_ISOAffectMask;
773 return ReportIllegal(keymap, action->type, field);
777 HandleSwitchScreen(struct xkb_keymap *keymap, union xkb_action *action,
778 enum action_field field, const ExprDef *array_ndx,
779 const ExprDef *value)
781 struct xkb_switch_screen_action *act = &action->screen;
783 if (field == ACTION_FIELD_SCREEN) {
788 return ReportActionNotArray(keymap, action->type, field);
790 if (value->op == EXPR_NEGATE || value->op == EXPR_UNARY_PLUS) {
791 act->flags &= ~XkbSA_SwitchAbsolute;
792 scrn = value->value.child;
795 act->flags |= XkbSA_SwitchAbsolute;
799 if (!ExprResolveInteger(keymap->ctx, scrn, &val))
800 return ReportMismatch(keymap, action->type, field,
803 if (val < 0 || val > 255) {
805 "Screen index must be in the range 1..255; "
806 "Illegal screen value %d ignored\n", val);
810 act->screen = (value->op == EXPR_NEGATE ? -val : val);
813 else if (field == ACTION_FIELD_SAME) {
817 return ReportActionNotArray(keymap, action->type, field);
819 if (!ExprResolveBoolean(keymap->ctx, value, &set))
820 return ReportMismatch(keymap, action->type, field, "boolean");
823 act->flags &= ~XkbSA_SwitchApplication;
825 act->flags |= XkbSA_SwitchApplication;
830 return ReportIllegal(keymap, action->type, field);
833 const LookupEntry ctrlNames[] = {
834 { "repeatkeys", XkbRepeatKeysMask },
835 { "repeat", XkbRepeatKeysMask },
836 { "autorepeat", XkbRepeatKeysMask },
837 { "slowkeys", XkbSlowKeysMask },
838 { "bouncekeys", XkbBounceKeysMask },
839 { "stickykeys", XkbStickyKeysMask },
840 { "mousekeys", XkbMouseKeysMask },
841 { "mousekeysaccel", XkbMouseKeysAccelMask },
842 { "accessxkeys", XkbAccessXKeysMask },
843 { "accessxtimeout", XkbAccessXTimeoutMask },
844 { "accessxfeedback", XkbAccessXFeedbackMask },
845 { "audiblebell", XkbAudibleBellMask },
846 { "ignoregrouplock", XkbIgnoreGroupLockMask },
847 { "all", XkbAllBooleanCtrlsMask },
855 HandleSetLockControls(struct xkb_keymap *keymap, union xkb_action *action,
856 enum action_field field, const ExprDef *array_ndx,
857 const ExprDef *value)
859 struct xkb_controls_action *act = &action->ctrls;
861 if (field == ACTION_FIELD_CONTROLS) {
865 return ReportActionNotArray(keymap, action->type, field);
867 if (!ExprResolveMask(keymap->ctx, value, &mask, ctrlNames))
868 return ReportMismatch(keymap, action->type, field,
875 return ReportIllegal(keymap, action->type, field);
878 static const LookupEntry evNames[] = {
879 { "press", XkbSA_MessageOnPress },
880 { "keypress", XkbSA_MessageOnPress },
881 { "release", XkbSA_MessageOnRelease },
882 { "keyrelease", XkbSA_MessageOnRelease },
883 { "all", XkbSA_MessageOnPress | XkbSA_MessageOnRelease },
889 HandleActionMessage(struct xkb_keymap *keymap, union xkb_action *action,
890 enum action_field field, const ExprDef *array_ndx,
891 const ExprDef *value)
893 struct xkb_message_action *act = &action->msg;
895 if (field == ACTION_FIELD_REPORT) {
899 return ReportActionNotArray(keymap, action->type, field);
901 if (!ExprResolveMask(keymap->ctx, value, &mask, evNames))
902 return ReportMismatch(keymap, action->type, field,
905 /* FIXME: Something seems wrong here... */
906 act->flags &= ~(XkbSA_MessageOnPress | XkbSA_MessageOnRelease);
907 act->flags = mask & (XkbSA_MessageOnPress | XkbSA_MessageOnRelease);
910 else if (field == ACTION_FIELD_GEN_KEY_EVENT) {
914 return ReportActionNotArray(keymap, action->type, field);
916 if (!ExprResolveBoolean(keymap->ctx, value, &set))
917 return ReportMismatch(keymap, action->type, field, "boolean");
920 act->flags |= XkbSA_MessageGenKeyEvent;
922 act->flags &= ~XkbSA_MessageGenKeyEvent;
926 else if (field == ACTION_FIELD_DATA && !array_ndx) {
930 if (!ExprResolveString(keymap->ctx, value, &str))
931 return ReportMismatch(keymap, action->type, field, "string");
934 if (len < 1 || len > 6) {
935 log_warn(keymap->ctx,
936 "An action message can hold only 6 bytes; "
937 "Extra %d bytes ignored\n", len - 6);
940 strncpy((char *) act->message, str, 6);
943 else if (field == ACTION_FIELD_DATA && array_ndx) {
946 if (!ExprResolveInteger(keymap->ctx, array_ndx, &ndx)) {
948 "Array subscript must be integer; "
949 "Illegal subscript ignored\n");
953 if (ndx < 0 || ndx > 5) {
955 "An action message is at most 6 bytes long; "
956 "Attempt to use data[%d] ignored\n", ndx);
960 if (!ExprResolveInteger(keymap->ctx, value, &datum))
961 return ReportMismatch(keymap, action->type, field, "integer");
963 if (datum < 0 || datum > 255) {
965 "Message data must be in the range 0..255; "
966 "Illegal datum %d ignored\n", datum);
970 act->message[ndx] = (uint8_t) datum;
974 return ReportIllegal(keymap, action->type, field);
978 HandleRedirectKey(struct xkb_keymap *keymap, union xkb_action *action,
979 enum action_field field, const ExprDef *array_ndx,
980 const ExprDef *value)
983 struct xkb_redirect_key_action *act = &action->redirect;
987 char key_name[XkbKeyNameLength];
989 if (array_ndx != NULL)
990 return ReportActionNotArray(keymap, action->type, field);
993 case ACTION_FIELD_KEYCODE:
994 if (!ExprResolveKeyName(keymap->ctx, value, key_name))
995 return ReportMismatch(keymap, action->type, field, "key name");
997 tmp = KeyNameToLong(key_name);
998 key = FindNamedKey(keymap, tmp, true, 0);
1000 return ReportNotFound(keymap, action->type, field, "Key",
1001 KeyNameText(key_name));
1002 act->new_kc = XkbKeyGetKeycode(keymap, key);
1005 case ACTION_FIELD_MODS_TO_CLEAR:
1006 case ACTION_FIELD_MODIFIERS:
1008 if (CheckModifierField(keymap, action->type, value, &t1, &t2)) {
1009 act->mods_mask |= (t2 & 0xff);
1010 if (field == ACTION_FIELD_MODIFIERS)
1011 act->mods |= (t2 & 0xff);
1013 act->mods &= ~(t2 & 0xff);
1015 t2 = (t2 >> XkbNumModifiers) & 0xffff;
1016 act->vmods_mask |= t2;
1017 if (field == ACTION_FIELD_MODIFIERS)
1029 return ReportIllegal(keymap, action->type, field);
1033 HandleDeviceBtn(struct xkb_keymap *keymap, union xkb_action *action,
1034 enum action_field field, const ExprDef *array_ndx,
1035 const ExprDef *value)
1037 struct xkb_device_button_action *act = &action->devbtn;
1039 if (field == ACTION_FIELD_BUTTON) {
1043 return ReportActionNotArray(keymap, action->type, field);
1045 if (!ExprResolveInteger(keymap->ctx, value, &val))
1046 return ReportMismatch(keymap, action->type, field,
1047 "integer (range 1..255)");
1049 if (val < 0 || val > 255) {
1050 log_err(keymap->ctx,
1051 "Button must specify default or be in the range 1..255; "
1052 "Illegal button value %d ignored\n", val);
1059 else if (action->type == XkbSA_LockDeviceBtn &&
1060 field == ACTION_FIELD_AFFECT) {
1064 return ReportActionNotArray(keymap, action->type, field);
1066 if (!ExprResolveEnum(keymap->ctx, value, &val, lockWhich))
1067 return ReportMismatch(keymap, action->type, field,
1070 act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock);
1074 else if (field == ACTION_FIELD_COUNT) {
1078 return ReportActionNotArray(keymap, action->type, field);
1080 /* XXX: Should this actually be ResolveButton? */
1081 if (!ExprResolveButton(keymap->ctx, value, &btn))
1082 return ReportMismatch(keymap, action->type, field, "integer");
1084 if (btn < 0 || btn > 255) {
1085 log_err(keymap->ctx,
1086 "The count field must have a value in the range 0..255; "
1087 "Illegal count %d ignored\n", btn);
1094 else if (field == ACTION_FIELD_DEVICE) {
1098 return ReportActionNotArray(keymap, action->type, field);
1100 if (!ExprResolveInteger(keymap->ctx, value, &val))
1101 return ReportMismatch(keymap, action->type, field,
1102 "integer (range 1..255)");
1104 if (val < 0 || val > 255) {
1105 log_err(keymap->ctx,
1106 "Device must specify default or be in the range 1..255; "
1107 "Illegal device value %d ignored\n", val);
1115 return ReportIllegal(keymap, action->type, field);
1119 HandleDeviceValuator(struct xkb_keymap *keymap, union xkb_action *action,
1120 enum action_field field, const ExprDef *array_ndx,
1121 const ExprDef *value)
1123 struct xkb_device_valuator_action *act = &action->devval;
1126 /* XXX - Not yet implemented */
1131 HandlePrivate(struct xkb_keymap *keymap, union xkb_action *action,
1132 enum action_field field, const ExprDef *array_ndx,
1133 const ExprDef *value)
1135 struct xkb_private_action *act = &action->priv;
1137 if (field == ACTION_FIELD_TYPE) {
1140 if (!ExprResolveInteger(keymap->ctx, value, &type))
1141 return ReportMismatch(keymap, PrivateAction, field, "integer");
1143 if (type < 0 || type > 255) {
1144 log_err(keymap->ctx,
1145 "Private action type must be in the range 0..255; "
1146 "Illegal type %d ignored\n", type);
1150 act->type = (uint8_t) type;
1153 else if (field == ACTION_FIELD_DATA) {
1154 if (array_ndx == NULL) {
1158 if (!ExprResolveString(keymap->ctx, value, &str))
1159 return ReportMismatch(keymap, action->type, field, "string");
1162 if (len < 1 || len > 7) {
1163 log_warn(keymap->ctx,
1164 "A private action has 7 data bytes; "
1165 "Extra %d bytes ignored\n", len - 6);
1169 strncpy((char *) act->data, str, sizeof(act->data));
1175 if (!ExprResolveInteger(keymap->ctx, array_ndx, &ndx)) {
1176 log_err(keymap->ctx,
1177 "Array subscript must be integer; "
1178 "Illegal subscript ignored\n");
1182 if (ndx < 0 || ndx >= sizeof(act->data)) {
1183 log_err(keymap->ctx,
1184 "The data for a private action is %zu bytes long; "
1185 "Attempt to use data[%d] ignored\n",
1186 sizeof(act->data), ndx);
1190 if (!ExprResolveInteger(keymap->ctx, value, &datum))
1191 return ReportMismatch(keymap, act->type, field, "integer");
1193 if (datum < 0 || datum > 255) {
1194 log_err(keymap->ctx,
1195 "All data for a private action must be 0..255; "
1196 "Illegal datum %d ignored\n", datum);
1200 act->data[ndx] = (uint8_t) datum;
1205 return ReportIllegal(keymap, PrivateAction, field);
1208 typedef bool (*actionHandler)(struct xkb_keymap *keymap,
1209 union xkb_action *action,
1210 enum action_field field,
1211 const ExprDef *array_ndx,
1212 const ExprDef *value);
1214 static const actionHandler handleAction[XkbSA_NumActions + 1] = {
1215 [XkbSA_NoAction] = HandleNoAction,
1216 [XkbSA_SetMods] = HandleSetLatchMods,
1217 [XkbSA_LatchMods] = HandleSetLatchMods,
1218 [XkbSA_LockMods] = HandleLockMods,
1219 [XkbSA_SetGroup] = HandleSetLatchGroup,
1220 [XkbSA_LatchGroup] = HandleSetLatchGroup,
1221 [XkbSA_LockGroup] = HandleLockGroup,
1222 [XkbSA_MovePtr] = HandleMovePtr,
1223 [XkbSA_PtrBtn] = HandlePtrBtn,
1224 [XkbSA_LockPtrBtn] = HandlePtrBtn,
1225 [XkbSA_SetPtrDflt] = HandleSetPtrDflt,
1226 [XkbSA_ISOLock] = HandleISOLock,
1227 [XkbSA_Terminate] = HandleNoAction,
1228 [XkbSA_SwitchScreen] = HandleSwitchScreen,
1229 [XkbSA_SetControls] = HandleSetLockControls,
1230 [XkbSA_LockControls] = HandleSetLockControls,
1231 [XkbSA_ActionMessage] = HandleActionMessage,
1232 [XkbSA_RedirectKey] = HandleRedirectKey,
1233 [XkbSA_DeviceBtn] = HandleDeviceBtn,
1234 [XkbSA_LockDeviceBtn] = HandleDeviceBtn,
1235 [XkbSA_DeviceValuator] = HandleDeviceValuator,
1236 [PrivateAction] = HandlePrivate,
1239 /***====================================================================***/
1242 HandleActionDef(ExprDef *def, struct xkb_keymap *keymap,
1243 union xkb_action *action, ActionsInfo *info)
1249 if (def->op != EXPR_ACTION_DECL) {
1250 log_err(keymap->ctx, "Expected an action definition, found %s\n",
1251 expr_op_type_to_string(def->op));
1255 str = xkb_atom_text(keymap->ctx, def->value.action.name);
1256 if (!stringToAction(str, &hndlrType)) {
1257 log_err(keymap->ctx, "Unknown action %s\n", str);
1262 * Get the default values for this action type, as modified by
1263 * statements such as:
1264 * latchMods.clearLocks = True;
1266 *action = info->actions[hndlrType];
1269 * Now change the action properties as specified for this
1270 * particular instance, e.g. "modifiers" and "clearLocks" in:
1271 * SetMods(modifiers=Alt,clearLocks);
1273 for (arg = def->value.action.args; arg != NULL;
1274 arg = (ExprDef *) arg->common.next) {
1275 const ExprDef *value;
1276 ExprDef *field, *arrayRtrn;
1277 const char *elemRtrn, *fieldRtrn;
1278 enum action_field fieldNdx;
1280 if (arg->op == EXPR_ASSIGN) {
1281 field = arg->value.binary.left;
1282 value = arg->value.binary.right;
1284 else if (arg->op == EXPR_NOT || arg->op == EXPR_INVERT) {
1285 field = arg->value.child;
1286 value = &constFalse;
1293 if (!ExprResolveLhs(keymap->ctx, field, &elemRtrn, &fieldRtrn,
1298 log_err(keymap->ctx,
1299 "Cannot change defaults in an action definition; "
1300 "Ignoring attempt to change %s.%s\n",
1301 elemRtrn, fieldRtrn);
1305 if (!stringToField(fieldRtrn, &fieldNdx)) {
1306 log_err(keymap->ctx, "Unknown field name %s\n", fieldRtrn);
1310 if (!handleAction[hndlrType](keymap, action, fieldNdx, arrayRtrn,
1320 SetActionField(struct xkb_keymap *keymap, const char *elem, const char *field,
1321 ExprDef *array_ndx, ExprDef *value, ActionsInfo *info)
1324 enum action_field action_field;
1326 if (!stringToAction(elem, &action))
1329 if (!stringToField(field, &action_field)) {
1330 log_err(keymap->ctx, "\"%s\" is not a legal field name\n", field);
1334 return handleAction[action](keymap, &info->actions[action],
1335 action_field, array_ndx, value);