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 ********************************************************/
30 static bool actionsInitialized;
31 static ExprDef constTrue;
32 static ExprDef constFalse;
34 /***====================================================================***/
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 },
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 },
96 { "accelerate", F_Accel },
97 { "repeat", F_Accel },
98 { "button", F_Button },
100 { "controls", F_Controls },
101 { "ctrls", F_Controls },
103 { "count", F_Count },
104 { "screen", F_Screen },
106 { "sameServer", F_Same },
108 { "device", F_Device },
110 { "key", F_Keycode },
111 { "keycode", F_Keycode },
113 { "clearmods", F_ModsToClear },
114 { "clearmodifiers", F_ModsToClear },
119 stringToValue(const LookupEntry tab[], const char *string,
120 unsigned *value_rtrn)
122 const LookupEntry *entry;
127 for (entry = tab; entry->name != NULL; entry++) {
128 if (strcasecmp(entry->name, string) == 0) {
129 *value_rtrn = entry->result;
138 valueToString(const LookupEntry tab[], unsigned value)
140 const LookupEntry *entry;
142 for (entry = tab; entry->name != NULL; entry++)
143 if (entry->result == value)
150 stringToAction(const char *str, unsigned *type_rtrn)
152 return stringToValue(actionStrings, str, type_rtrn);
156 stringToField(const char *str, unsigned *field_rtrn)
158 return stringToValue(fieldStrings, str, field_rtrn);
162 fieldText(unsigned field)
164 return valueToString(fieldStrings, field);
167 /***====================================================================***/
170 ReportMismatch(unsigned action, unsigned field, const char *type)
172 ERROR("Value of %s field must be of type %s\n", fieldText(field), type);
173 ACTION("Action %s definition ignored\n", XkbcActionTypeText(action));
178 ReportIllegal(unsigned action, unsigned field)
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");
187 ReportActionNotArray(unsigned action, unsigned field)
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");
196 ReportNotFound(unsigned action, unsigned field, const char *what,
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));
206 HandleNoAction(struct xkb_keymap *keymap, struct xkb_any_action *action,
207 unsigned field, ExprDef *array_ndx, ExprDef *value)
209 return ReportIllegal(action->type, field);
213 CheckLatchLockFlags(struct xkb_keymap *keymap, unsigned action,
214 unsigned field, ExprDef * value, unsigned *flags_inout)
219 if (field == F_ClearLocks)
220 tmp = XkbSA_ClearLocks;
221 else if (field == F_LatchToLock)
222 tmp = XkbSA_LatchToLock;
224 return false; /* WSGO! */
225 if (!ExprResolveBoolean(keymap->ctx, value, &result))
226 return ReportMismatch(action, field, "boolean");
230 *flags_inout &= ~tmp;
235 CheckModifierField(struct xkb_keymap *keymap, unsigned action, ExprDef *value,
236 unsigned *flags_inout, unsigned *mods_rtrn)
240 if (value->op == ExprIdent)
243 valStr = xkb_atom_text(keymap->ctx, value->value.str);
244 if (valStr && ((strcasecmp(valStr, "usemodmapmods") == 0) ||
245 (strcasecmp(valStr, "modmapmods") == 0)))
249 *flags_inout |= XkbSA_UseModMapMods;
253 if (!ExprResolveVModMask(value, &rtrn, keymap))
254 return ReportMismatch(action, F_Modifiers, "modifier mask");
255 *mods_rtrn = rtrn.uval;
256 *flags_inout &= ~XkbSA_UseModMapMods;
261 HandleSetLatchMods(struct xkb_keymap *keymap, struct xkb_any_action *action,
262 unsigned field, ExprDef *array_ndx, ExprDef *value)
264 struct xkb_mod_action *act;
268 act = (struct xkb_mod_action *) action;
269 if (array_ndx != NULL)
276 return ReportActionNotArray(action->type, field);
284 if (CheckLatchLockFlags(keymap, action->type, field, value, &rtrn))
292 if (CheckModifierField(keymap, action->type, value, &t1, &t2))
295 act->real_mods = act->mask = (t2 & 0xff);
296 act->vmods = (t2 >> 8) & 0xffff;
301 return ReportIllegal(action->type, field);
305 HandleLockMods(struct xkb_keymap *keymap, struct xkb_any_action *action,
306 unsigned field, ExprDef *array_ndx, ExprDef *value)
308 struct xkb_mod_action *act;
311 act = (struct xkb_mod_action *) action;
312 if ((array_ndx != NULL) && (field == F_Modifiers))
313 return ReportActionNotArray(action->type, field);
318 if (CheckModifierField(keymap, action->type, value, &t1, &t2))
321 act->real_mods = act->mask = (t2 & 0xff);
322 act->vmods = (t2 >> 8) & 0xffff;
327 return ReportIllegal(action->type, field);
331 CheckGroupField(struct xkb_keymap *keymap, unsigned action,
332 ExprDef * value, unsigned *flags_inout, int *grp_rtrn)
337 if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
339 *flags_inout &= ~XkbSA_GroupAbsolute;
340 spec = value->value.child;
344 *flags_inout |= XkbSA_GroupAbsolute;
348 if (!ExprResolveGroup(keymap->ctx, spec, &rtrn))
349 return ReportMismatch(action, F_Group, "integer (range 1..8)");
350 if (value->op == OpNegate)
351 *grp_rtrn = -rtrn.ival;
352 else if (value->op == OpUnaryPlus)
353 *grp_rtrn = rtrn.ival;
355 *grp_rtrn = rtrn.ival - 1;
360 HandleSetLatchGroup(struct xkb_keymap *keymap, struct xkb_any_action *action,
361 unsigned field, ExprDef *array_ndx, ExprDef *value)
363 struct xkb_group_action *act;
368 act = (struct xkb_group_action *) action;
369 if (array_ndx != NULL)
376 return ReportActionNotArray(action->type, field);
384 if (CheckLatchLockFlags(keymap, action->type, field, value, &rtrn))
392 if (CheckGroupField(keymap, action->type, value, &t1, &t2))
400 return ReportIllegal(action->type, field);
404 HandleLockGroup(struct xkb_keymap *keymap, struct xkb_any_action *action,
405 unsigned field, ExprDef *array_ndx, ExprDef *value)
407 struct xkb_group_action *act;
411 act = (struct xkb_group_action *) action;
412 if ((array_ndx != NULL) && (field == F_Group))
413 return ReportActionNotArray(action->type, field);
414 if (field == F_Group)
417 if (CheckGroupField(keymap, action->type, value, &t1, &t2))
425 return ReportIllegal(action->type, field);
429 HandleMovePtr(struct xkb_keymap *keymap, struct xkb_any_action *action,
430 unsigned field, ExprDef *array_ndx, ExprDef *value)
433 struct xkb_pointer_action *act;
436 act = (struct xkb_pointer_action *) action;
437 if ((array_ndx != NULL) && ((field == F_X) || (field == F_Y)))
438 return ReportActionNotArray(action->type, field);
440 if ((field == F_X) || (field == F_Y))
442 if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
446 if (!ExprResolveInteger(keymap->ctx, value, &rtrn))
447 return ReportMismatch(action->type, field, "integer");
451 act->flags |= XkbSA_MoveAbsoluteX;
457 act->flags |= XkbSA_MoveAbsoluteY;
462 else if (field == F_Accel)
464 if (!ExprResolveBoolean(keymap->ctx, value, &rtrn))
465 return ReportMismatch(action->type, field, "boolean");
467 act->flags &= ~XkbSA_NoAcceleration;
469 act->flags |= XkbSA_NoAcceleration;
471 return ReportIllegal(action->type, field);
474 static const LookupEntry lockWhich[] = {
476 {"lock", XkbSA_LockNoUnlock},
477 {"neither", (XkbSA_LockNoLock | XkbSA_LockNoUnlock)},
478 {"unlock", XkbSA_LockNoLock},
483 HandlePtrBtn(struct xkb_keymap *keymap, struct xkb_any_action *action,
484 unsigned field, ExprDef *array_ndx, ExprDef *value)
487 struct xkb_pointer_button_action *act;
489 act = (struct xkb_pointer_button_action *) action;
490 if (field == F_Button)
492 if (array_ndx != NULL)
493 return ReportActionNotArray(action->type, field);
494 if (!ExprResolveButton(keymap->ctx, value, &rtrn))
495 return ReportMismatch(action->type, field,
496 "integer (range 1..5)");
497 if ((rtrn.ival < 0) || (rtrn.ival > 5))
499 ERROR("Button must specify default or be in the range 1..5\n");
500 ACTION("Illegal button value %d ignored\n", rtrn.ival);
503 act->button = rtrn.ival;
506 else if ((action->type == XkbSA_LockPtrBtn) && (field == F_Affect))
508 if (array_ndx != NULL)
509 return ReportActionNotArray(action->type, field);
510 if (!ExprResolveEnum(keymap->ctx, value, &rtrn, lockWhich))
511 return ReportMismatch(action->type, field, "lock or unlock");
512 act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock);
513 act->flags |= rtrn.ival;
516 else if (field == F_Count)
518 if (array_ndx != NULL)
519 return ReportActionNotArray(action->type, field);
520 if (!ExprResolveButton(keymap->ctx, value, &rtrn))
521 return ReportMismatch(action->type, field, "integer");
522 if ((rtrn.ival < 0) || (rtrn.ival > 255))
524 ERROR("The count field must have a value in the range 0..255\n");
525 ACTION("Illegal count %d ignored\n", rtrn.ival);
528 act->count = rtrn.ival;
531 return ReportIllegal(action->type, field);
534 static const LookupEntry ptrDflts[] = {
535 {"dfltbtn", XkbSA_AffectDfltBtn},
536 {"defaultbutton", XkbSA_AffectDfltBtn},
537 {"button", XkbSA_AffectDfltBtn},
542 HandleSetPtrDflt(struct xkb_keymap *keymap, struct xkb_any_action *action,
543 unsigned field, ExprDef *array_ndx, ExprDef *value)
546 struct xkb_pointer_default_action *act;
548 act = (struct xkb_pointer_default_action *) action;
549 if (field == F_Affect)
551 if (array_ndx != NULL)
552 return ReportActionNotArray(action->type, field);
553 if (!ExprResolveEnum(keymap->ctx, value, &rtrn, ptrDflts))
554 return ReportMismatch(action->type, field, "pointer component");
555 act->affect = rtrn.uval;
558 else if ((field == F_Button) || (field == F_Value))
561 if (array_ndx != NULL)
562 return ReportActionNotArray(action->type, field);
563 if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
565 act->flags &= ~XkbSA_DfltBtnAbsolute;
566 btn = value->value.child;
570 act->flags |= XkbSA_DfltBtnAbsolute;
574 if (!ExprResolveButton(keymap->ctx, btn, &rtrn))
575 return ReportMismatch(action->type, field,
576 "integer (range 1..5)");
577 if ((rtrn.ival < 0) || (rtrn.ival > 5))
579 ERROR("New default button value must be in the range 1..5\n");
580 ACTION("Illegal default button value %d ignored\n", rtrn.ival);
585 ERROR("Cannot set default pointer button to \"default\"\n");
586 ACTION("Illegal default button setting ignored\n");
589 if (value->op == OpNegate)
590 act->value = -rtrn.ival;
592 act->value = rtrn.ival;
595 return ReportIllegal(action->type, field);
598 static const LookupEntry isoNames[] = {
599 {"mods", XkbSA_ISONoAffectMods},
600 {"modifiers", XkbSA_ISONoAffectMods},
601 {"group", XkbSA_ISONoAffectGroup},
602 {"groups", XkbSA_ISONoAffectGroup},
603 {"ptr", XkbSA_ISONoAffectPtr},
604 {"pointer", XkbSA_ISONoAffectPtr},
605 {"ctrls", XkbSA_ISONoAffectCtrls},
606 {"controls", XkbSA_ISONoAffectCtrls},
607 {"all", ~((unsigned) 0)},
613 HandleISOLock(struct xkb_keymap *keymap, struct xkb_any_action *action,
614 unsigned field, ExprDef *array_ndx, ExprDef *value)
617 struct xkb_iso_action *act;
618 unsigned flags, mods;
621 act = (struct xkb_iso_action *) action;
625 if (array_ndx != NULL)
626 return ReportActionNotArray(action->type, field);
628 if (CheckModifierField(keymap, action->type, value, &flags, &mods))
630 act->flags = flags & (~XkbSA_ISODfltIsGroup);
631 act->real_mods = mods & 0xff;
632 act->vmods = (mods >> 8) & 0xff;
637 if (array_ndx != NULL)
638 return ReportActionNotArray(action->type, field);
640 if (CheckGroupField(keymap, action->type, value, &flags, &group))
642 act->flags = flags | XkbSA_ISODfltIsGroup;
648 if (array_ndx != NULL)
649 return ReportActionNotArray(action->type, field);
650 if (!ExprResolveMask(keymap->ctx, value, &rtrn, isoNames))
651 return ReportMismatch(action->type, field, "keyboard component");
652 act->affect = (~rtrn.uval) & XkbSA_ISOAffectMask;
655 return ReportIllegal(action->type, field);
659 HandleSwitchScreen(struct xkb_keymap *keymap, struct xkb_any_action *action,
660 unsigned field, ExprDef *array_ndx, ExprDef *value)
663 struct xkb_switch_screen_action *act;
665 act = (struct xkb_switch_screen_action *) action;
666 if (field == F_Screen)
669 if (array_ndx != NULL)
670 return ReportActionNotArray(action->type, field);
671 if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
673 act->flags &= ~XkbSA_SwitchAbsolute;
674 scrn = value->value.child;
678 act->flags |= XkbSA_SwitchAbsolute;
682 if (!ExprResolveInteger(keymap->ctx, scrn, &rtrn))
683 return ReportMismatch(action->type, field, "integer (0..255)");
684 if ((rtrn.ival < 0) || (rtrn.ival > 255))
686 ERROR("Screen index must be in the range 1..255\n");
687 ACTION("Illegal screen value %d ignored\n", rtrn.ival);
690 if (value->op == OpNegate)
691 act->screen = -rtrn.ival;
693 act->screen = rtrn.ival;
696 else if (field == F_Same)
698 if (array_ndx != NULL)
699 return ReportActionNotArray(action->type, field);
700 if (!ExprResolveBoolean(keymap->ctx, value, &rtrn))
701 return ReportMismatch(action->type, field, "boolean");
703 act->flags &= ~XkbSA_SwitchApplication;
705 act->flags |= XkbSA_SwitchApplication;
708 return ReportIllegal(action->type, field);
711 const LookupEntry ctrlNames[] = {
712 {"repeatkeys", XkbRepeatKeysMask},
713 {"repeat", XkbRepeatKeysMask},
714 {"autorepeat", XkbRepeatKeysMask},
715 {"slowkeys", XkbSlowKeysMask},
716 {"bouncekeys", XkbBounceKeysMask},
717 {"stickykeys", XkbStickyKeysMask},
718 {"mousekeys", XkbMouseKeysMask},
719 {"mousekeysaccel", XkbMouseKeysAccelMask},
720 {"accessxkeys", XkbAccessXKeysMask},
721 {"accessxtimeout", XkbAccessXTimeoutMask},
722 {"accessxfeedback", XkbAccessXFeedbackMask},
723 {"audiblebell", XkbAudibleBellMask},
724 {"ignoregrouplock", XkbIgnoreGroupLockMask},
725 {"all", XkbAllBooleanCtrlsMask},
733 HandleSetLockControls(struct xkb_keymap *keymap, struct xkb_any_action *action,
734 unsigned field, ExprDef *array_ndx, ExprDef *value)
737 struct xkb_controls_action *act;
739 act = (struct xkb_controls_action *) action;
740 if (field == F_Controls)
742 if (array_ndx != NULL)
743 return ReportActionNotArray(action->type, field);
744 if (!ExprResolveMask(keymap->ctx, value, &rtrn, ctrlNames))
745 return ReportMismatch(action->type, field, "controls mask");
746 act->ctrls = rtrn.uval;
749 return ReportIllegal(action->type, field);
752 static const LookupEntry evNames[] = {
753 {"press", XkbSA_MessageOnPress},
754 {"keypress", XkbSA_MessageOnPress},
755 {"release", XkbSA_MessageOnRelease},
756 {"keyrelease", XkbSA_MessageOnRelease},
757 {"all", XkbSA_MessageOnPress | XkbSA_MessageOnRelease},
763 HandleActionMessage(struct xkb_keymap *keymap, struct xkb_any_action *action,
764 unsigned field, ExprDef *array_ndx, ExprDef *value)
767 struct xkb_message_action *act;
769 act = (struct xkb_message_action *) action;
773 if (array_ndx != NULL)
774 return ReportActionNotArray(action->type, field);
775 if (!ExprResolveMask(keymap->ctx, value, &rtrn, evNames))
776 return ReportMismatch(action->type, field, "key event mask");
777 act->flags &= ~(XkbSA_MessageOnPress | XkbSA_MessageOnRelease);
779 rtrn.uval & (XkbSA_MessageOnPress | XkbSA_MessageOnRelease);
782 if (array_ndx != NULL)
783 return ReportActionNotArray(action->type, field);
784 if (!ExprResolveBoolean(keymap->ctx, value, &rtrn))
785 return ReportMismatch(action->type, field, "boolean");
787 act->flags |= XkbSA_MessageGenKeyEvent;
789 act->flags &= ~XkbSA_MessageGenKeyEvent;
792 if (array_ndx == NULL)
794 if (!ExprResolveString(keymap->ctx, value, &rtrn))
795 return ReportMismatch(action->type, field, "string");
798 int len = strlen(rtrn.str);
799 if ((len < 1) || (len > 6))
801 WARN("An action message can hold only 6 bytes\n");
802 ACTION("Extra %d bytes ignored\n", len - 6);
804 strncpy((char *) act->message, rtrn.str, 6);
811 if (!ExprResolveInteger(keymap->ctx, array_ndx, &rtrn))
813 ERROR("Array subscript must be integer\n");
814 ACTION("Illegal subscript ignored\n");
820 ERROR("An action message is at most 6 bytes long\n");
821 ACTION("Attempt to use data[%d] ignored\n", ndx);
824 if (!ExprResolveInteger(keymap->ctx, value, &rtrn))
825 return ReportMismatch(action->type, field, "integer");
826 if ((rtrn.ival < 0) || (rtrn.ival > 255))
828 ERROR("Message data must be in the range 0..255\n");
829 ACTION("Illegal datum %d ignored\n", rtrn.ival);
832 act->message[ndx] = rtrn.uval;
836 return ReportIllegal(action->type, field);
840 HandleRedirectKey(struct xkb_keymap *keymap, struct xkb_any_action *action,
841 unsigned field, ExprDef *array_ndx, ExprDef *value)
844 struct xkb_redirect_key_action *act;
849 if (array_ndx != NULL)
850 return ReportActionNotArray(action->type, field);
852 act = (struct xkb_redirect_key_action *) action;
856 if (!ExprResolveKeyName(keymap->ctx, value, &rtrn))
857 return ReportMismatch(action->type, field, "key name");
858 tmp = KeyNameToLong(rtrn.keyName.name);
859 if (!FindNamedKey(keymap, tmp, &kc, true, CreateKeyNames(keymap), 0))
861 return ReportNotFound(action->type, field, "Key",
862 XkbcKeyNameText(rtrn.keyName.name));
869 if (CheckModifierField(keymap, action->type, value, &t1, &t2))
871 act->mods_mask |= (t2 & 0xff);
872 if (field == F_Modifiers)
873 act->mods |= (t2 & 0xff);
875 act->mods &= ~(t2 & 0xff);
877 t2 = (t2 >> 8) & 0xffff;
878 act->vmods_mask |= t2;
879 if (field == F_Modifiers)
887 return ReportIllegal(action->type, field);
891 HandleDeviceBtn(struct xkb_keymap *keymap, struct xkb_any_action *action,
892 unsigned field, ExprDef *array_ndx, ExprDef *value)
895 struct xkb_device_button_action *act;
897 act = (struct xkb_device_button_action *) action;
898 if (field == F_Button)
900 if (array_ndx != NULL)
901 return ReportActionNotArray(action->type, field);
902 if (!ExprResolveInteger(keymap->ctx, value, &rtrn))
903 return ReportMismatch(action->type, field,
904 "integer (range 1..255)");
905 if ((rtrn.ival < 0) || (rtrn.ival > 255))
907 ERROR("Button must specify default or be in the range 1..255\n");
908 ACTION("Illegal button value %d ignored\n", rtrn.ival);
911 act->button = rtrn.ival;
914 else if ((action->type == XkbSA_LockDeviceBtn) && (field == F_Affect))
916 if (array_ndx != NULL)
917 return ReportActionNotArray(action->type, field);
918 if (!ExprResolveEnum(keymap->ctx, value, &rtrn, lockWhich))
919 return ReportMismatch(action->type, field, "lock or unlock");
920 act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock);
921 act->flags |= rtrn.ival;
924 else if (field == F_Count)
926 if (array_ndx != NULL)
927 return ReportActionNotArray(action->type, field);
928 if (!ExprResolveButton(keymap->ctx, value, &rtrn))
929 return ReportMismatch(action->type, field, "integer");
930 if ((rtrn.ival < 0) || (rtrn.ival > 255))
932 ERROR("The count field must have a value in the range 0..255\n");
933 ACTION("Illegal count %d ignored\n", rtrn.ival);
936 act->count = rtrn.ival;
939 else if (field == F_Device)
941 if (array_ndx != NULL)
942 return ReportActionNotArray(action->type, field);
943 if (!ExprResolveInteger(keymap->ctx, value, &rtrn))
944 return ReportMismatch(action->type, field,
945 "integer (range 1..255)");
946 if ((rtrn.ival < 0) || (rtrn.ival > 255))
948 ERROR("Device must specify default or be in the range 1..255\n");
949 ACTION("Illegal device value %d ignored\n", rtrn.ival);
952 act->device = rtrn.ival;
955 return ReportIllegal(action->type, field);
959 HandleDeviceValuator(struct xkb_keymap *keymap, struct xkb_any_action *action,
960 unsigned field, ExprDef *array_ndx, ExprDef *value)
964 struct xkb_device_valuator_action *act;
966 act = (struct xkb_device_valuator_action *) action;
967 /* XXX - Not yet implemented */
973 HandlePrivate(struct xkb_keymap *keymap, struct xkb_any_action *action,
974 unsigned field, ExprDef *array_ndx, ExprDef *value)
981 if (!ExprResolveInteger(keymap->ctx, value, &rtrn))
982 return ReportMismatch(PrivateAction, field, "integer");
983 if ((rtrn.ival < 0) || (rtrn.ival > 255))
985 ERROR("Private action type must be in the range 0..255\n");
986 ACTION("Illegal type %d ignored\n", rtrn.ival);
989 action->type = rtrn.uval;
992 if (array_ndx == NULL)
994 if (!ExprResolveString(keymap->ctx, value, &rtrn))
995 return ReportMismatch(action->type, field, "string");
998 int len = strlen(rtrn.str);
999 if ((len < 1) || (len > 7))
1001 WARN("A private action has 7 data bytes\n");
1002 ACTION("Extra %d bytes ignored\n", len - 6);
1005 strncpy((char *) action->data, rtrn.str, sizeof action->data);
1013 if (!ExprResolveInteger(keymap->ctx, array_ndx, &rtrn))
1015 ERROR("Array subscript must be integer\n");
1016 ACTION("Illegal subscript ignored\n");
1020 if (ndx >= sizeof action->data)
1022 ERROR("The data for a private action is 18 bytes long\n");
1023 ACTION("Attempt to use data[%d] ignored\n", ndx);
1026 if (!ExprResolveInteger(keymap->ctx, value, &rtrn))
1027 return ReportMismatch(action->type, field, "integer");
1028 if ((rtrn.ival < 0) || (rtrn.ival > 255))
1030 ERROR("All data for a private action must be 0..255\n");
1031 ACTION("Illegal datum %d ignored\n", rtrn.ival);
1034 action->data[ndx] = rtrn.uval;
1038 return ReportIllegal(PrivateAction, field);
1041 typedef bool (*actionHandler) (struct xkb_keymap *keymap,
1042 struct xkb_any_action *action, unsigned field,
1043 ExprDef *array_ndx, ExprDef *value);
1045 static const actionHandler handleAction[XkbSA_NumActions + 1] = {
1046 [XkbSA_NoAction] = HandleNoAction,
1047 [XkbSA_SetMods] = HandleSetLatchMods,
1048 [XkbSA_LatchMods] = HandleSetLatchMods,
1049 [XkbSA_LockMods] = HandleLockMods,
1050 [XkbSA_SetGroup] = HandleSetLatchGroup,
1051 [XkbSA_LatchGroup] = HandleSetLatchGroup,
1052 [XkbSA_LockGroup] = HandleLockGroup,
1053 [XkbSA_MovePtr] = HandleMovePtr,
1054 [XkbSA_PtrBtn] = HandlePtrBtn,
1055 [XkbSA_LockPtrBtn] = HandlePtrBtn,
1056 [XkbSA_SetPtrDflt] = HandleSetPtrDflt,
1057 [XkbSA_ISOLock] = HandleISOLock,
1058 [XkbSA_Terminate] = HandleNoAction,
1059 [XkbSA_SwitchScreen] = HandleSwitchScreen,
1060 [XkbSA_SetControls] = HandleSetLockControls,
1061 [XkbSA_LockControls] = HandleSetLockControls,
1062 [XkbSA_ActionMessage] = HandleActionMessage,
1063 [XkbSA_RedirectKey] = HandleRedirectKey,
1064 [XkbSA_DeviceBtn] = HandleDeviceBtn,
1065 [XkbSA_LockDeviceBtn] = HandleDeviceBtn,
1066 [XkbSA_DeviceValuator] = HandleDeviceValuator,
1067 [PrivateAction] = HandlePrivate,
1070 /***====================================================================***/
1073 ApplyActionFactoryDefaults(union xkb_action * action)
1075 if (action->type == XkbSA_SetPtrDflt)
1076 { /* increment default button */
1077 action->dflt.affect = XkbSA_AffectDfltBtn;
1078 action->dflt.flags = 0;
1079 action->dflt.value = 1;
1081 else if (action->type == XkbSA_ISOLock)
1083 action->iso.real_mods = LockMask;
1088 ActionsInit(struct xkb_context *ctx);
1091 HandleActionDef(ExprDef * def,
1092 struct xkb_keymap *keymap,
1093 struct xkb_any_action *action, ActionInfo *info)
1097 unsigned tmp, hndlrType;
1099 if (!actionsInitialized)
1100 ActionsInit(keymap->ctx);
1102 if (def->op != ExprActionDecl)
1104 ERROR("Expected an action definition, found %s\n",
1105 exprOpText(def->op));
1108 str = xkb_atom_text(keymap->ctx, def->value.action.name);
1111 WSGO("Missing name in action definition!!\n");
1114 if (!stringToAction(str, &tmp))
1116 ERROR("Unknown action %s\n", str);
1119 action->type = hndlrType = tmp;
1120 if (action->type != XkbSA_NoAction)
1122 ApplyActionFactoryDefaults((union xkb_action *) action);
1125 if ((info->action == XkbSA_NoAction)
1126 || (info->action == hndlrType))
1128 if (!(*handleAction[hndlrType]) (keymap, action,
1139 for (arg = def->value.action.args; arg != NULL;
1140 arg = (ExprDef *) arg->common.next)
1142 ExprDef *field, *value, *arrayRtrn;
1143 ExprResult elemRtrn, fieldRtrn;
1146 if (arg->op == OpAssign)
1148 field = arg->value.binary.left;
1149 value = arg->value.binary.right;
1153 if ((arg->op == OpNot) || (arg->op == OpInvert))
1155 field = arg->value.child;
1156 constFalse.value.str = xkb_atom_intern(keymap->ctx, "false");
1157 value = &constFalse;
1162 constTrue.value.str = xkb_atom_intern(keymap->ctx, "true");
1166 if (!ExprResolveLhs(keymap, field, &elemRtrn, &fieldRtrn, &arrayRtrn))
1167 return false; /* internal error -- already reported */
1169 if (elemRtrn.str != NULL)
1171 ERROR("Cannot change defaults in an action definition\n");
1172 ACTION("Ignoring attempt to change %s.%s\n", elemRtrn.str,
1175 free(fieldRtrn.str);
1178 if (!stringToField(fieldRtrn.str, &fieldNdx))
1180 ERROR("Unknown field name %s\n", uStringText(fieldRtrn.str));
1182 free(fieldRtrn.str);
1186 free(fieldRtrn.str);
1187 if (!(*handleAction[hndlrType])(keymap, action, fieldNdx, arrayRtrn,
1194 /***====================================================================***/
1197 SetActionField(struct xkb_keymap *keymap,
1200 ExprDef * array_ndx, ExprDef * value, ActionInfo ** info_rtrn)
1202 ActionInfo *new, *old;
1204 if (!actionsInitialized)
1205 ActionsInit(keymap->ctx);
1207 new = uTypedAlloc(ActionInfo);
1210 WSGO("Couldn't allocate space for action default\n");
1213 if (strcasecmp(elem, "action") == 0)
1214 new->action = XkbSA_NoAction;
1217 if (!stringToAction(elem, &new->action))
1222 if (new->action == XkbSA_NoAction)
1224 ERROR("\"%s\" is not a valid field in a NoAction action\n",
1230 if (!stringToField(field, &new->field))
1232 ERROR("\"%s\" is not a legal field name\n", field);
1236 new->array_ndx = array_ndx;
1240 while ((old) && (old->next))
1249 /***====================================================================***/
1252 ActionsInit(struct xkb_context *ctx)
1254 if (!actionsInitialized)
1256 memset(&constTrue, 0, sizeof(constTrue));
1257 memset(&constFalse, 0, sizeof(constFalse));
1258 constTrue.common.stmtType = StmtExpr;
1259 constTrue.common.next = NULL;
1260 constTrue.op = ExprIdent;
1261 constTrue.type = TypeBoolean;
1262 constTrue.value.str = xkb_atom_intern(ctx, "true");
1263 constFalse.common.stmtType = StmtExpr;
1264 constFalse.common.next = NULL;
1265 constFalse.op = ExprIdent;
1266 constFalse.type = TypeBoolean;
1267 constFalse.value.str = xkb_atom_intern(ctx, "false");
1268 actionsInitialized = 1;