action: s/hndlrType/handler_type
[platform/upstream/libxkbcommon.git] / src / xkbcomp / action.c
index eaaacd4..22762c6 100644 (file)
 /************************************************************
- Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
-
- Permission to use, copy, modify, and distribute this
- software and its documentation for any purpose and without
- fee is hereby granted, provided that the above copyright
- notice appear in all copies and that both that copyright
- notice and this permission notice appear in supporting
- documentation, and that the name of Silicon Graphics not be
- used in advertising or publicity pertaining to distribution
- of the software without specific prior written permission.
- Silicon Graphics makes no representation about the suitability
- of this software for any purpose. It is provided "as is"
- without any express or implied warranty.
-
- SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
- SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
- GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
- DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
- THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
+ *
Permission to use, copy, modify, and distribute this
software and its documentation for any purpose and without
fee is hereby granted, provided that the above copyright
notice appear in all copies and that both that copyright
notice and this permission notice appear in supporting
documentation, and that the name of Silicon Graphics not be
used in advertising or publicity pertaining to distribution
of the software without specific prior written permission.
Silicon Graphics makes no representation about the suitability
of this software for any purpose. It is provided "as is"
without any express or implied warranty.
+ *
SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
  ********************************************************/
 
-#include "xkbcomp.h"
-#include "xkbmisc.h"
-#include "tokens.h"
+/*
+ * Copyright © 2012 Intel Corporation
+ * Copyright © 2012 Ran Benita <ran234@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Daniel Stone <daniel@fooishbar.org>
+ *         Ran Benita <ran234@gmail.com>
+ */
+
+#include "xkbcomp-priv.h"
+#include "text.h"
 #include "expr.h"
-
-#include "keycodes.h"
-#include "vmod.h"
-#include "misc.h"
 #include "action.h"
-#include "misc.h"
+#include "keycodes.h"
 
-static Bool actionsInitialized;
-static ExprDef constTrue;
-static ExprDef constFalse;
+static const ExprDef constTrue = {
+    .common = { .type = STMT_EXPR, .next = NULL },
+    .op = EXPR_VALUE,
+    .value_type = EXPR_TYPE_BOOLEAN,
+    .value = { .ival = 1 },
+};
 
-/***====================================================================***/
+static const ExprDef constFalse = {
+    .common = { .type = STMT_EXPR, .next = NULL },
+    .op = EXPR_VALUE,
+    .value_type = EXPR_TYPE_BOOLEAN,
+    .value = { .ival = 0 },
+};
 
-static Bool
-stringToAction(const char *str, unsigned *type_rtrn)
+enum action_field {
+    ACTION_FIELD_CLEAR_LOCKS,
+    ACTION_FIELD_LATCH_TO_LOCK,
+    ACTION_FIELD_GEN_KEY_EVENT,
+    ACTION_FIELD_REPORT,
+    ACTION_FIELD_DEFAULT,
+    ACTION_FIELD_AFFECT,
+    ACTION_FIELD_INCREMENT,
+    ACTION_FIELD_MODIFIERS,
+    ACTION_FIELD_GROUP,
+    ACTION_FIELD_X,
+    ACTION_FIELD_Y,
+    ACTION_FIELD_ACCEL,
+    ACTION_FIELD_BUTTON,
+    ACTION_FIELD_VALUE,
+    ACTION_FIELD_CONTROLS,
+    ACTION_FIELD_TYPE,
+    ACTION_FIELD_COUNT,
+    ACTION_FIELD_SCREEN,
+    ACTION_FIELD_SAME,
+    ACTION_FIELD_DATA,
+    ACTION_FIELD_DEVICE,
+    ACTION_FIELD_KEYCODE,
+    ACTION_FIELD_MODS_TO_CLEAR,
+};
+
+ActionsInfo *
+NewActionsInfo(void)
 {
-    if (str == NULL)
-        return False;
-
-    if (uStrCaseCmp(str, "noaction") == 0)
-        *type_rtrn = XkbSA_NoAction;
-    else if (uStrCaseCmp(str, "setmods") == 0)
-        *type_rtrn = XkbSA_SetMods;
-    else if (uStrCaseCmp(str, "latchmods") == 0)
-        *type_rtrn = XkbSA_LatchMods;
-    else if (uStrCaseCmp(str, "lockmods") == 0)
-        *type_rtrn = XkbSA_LockMods;
-    else if (uStrCaseCmp(str, "setgroup") == 0)
-        *type_rtrn = XkbSA_SetGroup;
-    else if (uStrCaseCmp(str, "latchgroup") == 0)
-        *type_rtrn = XkbSA_LatchGroup;
-    else if (uStrCaseCmp(str, "lockgroup") == 0)
-        *type_rtrn = XkbSA_LockGroup;
-    else if (uStrCaseCmp(str, "moveptr") == 0)
-        *type_rtrn = XkbSA_MovePtr;
-    else if (uStrCaseCmp(str, "movepointer") == 0)
-        *type_rtrn = XkbSA_MovePtr;
-    else if (uStrCaseCmp(str, "ptrbtn") == 0)
-        *type_rtrn = XkbSA_PtrBtn;
-    else if (uStrCaseCmp(str, "pointerbutton") == 0)
-        *type_rtrn = XkbSA_PtrBtn;
-    else if (uStrCaseCmp(str, "lockptrbtn") == 0)
-        *type_rtrn = XkbSA_LockPtrBtn;
-    else if (uStrCaseCmp(str, "lockpointerbutton") == 0)
-        *type_rtrn = XkbSA_LockPtrBtn;
-    else if (uStrCaseCmp(str, "lockptrbutton") == 0)
-        *type_rtrn = XkbSA_LockPtrBtn;
-    else if (uStrCaseCmp(str, "lockpointerbtn") == 0)
-        *type_rtrn = XkbSA_LockPtrBtn;
-    else if (uStrCaseCmp(str, "setptrdflt") == 0)
-        *type_rtrn = XkbSA_SetPtrDflt;
-    else if (uStrCaseCmp(str, "setpointerdefault") == 0)
-        *type_rtrn = XkbSA_SetPtrDflt;
-    else if (uStrCaseCmp(str, "isolock") == 0)
-        *type_rtrn = XkbSA_ISOLock;
-    else if (uStrCaseCmp(str, "terminate") == 0)
-        *type_rtrn = XkbSA_Terminate;
-    else if (uStrCaseCmp(str, "terminateserver") == 0)
-        *type_rtrn = XkbSA_Terminate;
-    else if (uStrCaseCmp(str, "switchscreen") == 0)
-        *type_rtrn = XkbSA_SwitchScreen;
-    else if (uStrCaseCmp(str, "setcontrols") == 0)
-        *type_rtrn = XkbSA_SetControls;
-    else if (uStrCaseCmp(str, "lockcontrols") == 0)
-        *type_rtrn = XkbSA_LockControls;
-    else if (uStrCaseCmp(str, "actionmessage") == 0)
-        *type_rtrn = XkbSA_ActionMessage;
-    else if (uStrCaseCmp(str, "messageaction") == 0)
-        *type_rtrn = XkbSA_ActionMessage;
-    else if (uStrCaseCmp(str, "message") == 0)
-        *type_rtrn = XkbSA_ActionMessage;
-    else if (uStrCaseCmp(str, "redirect") == 0)
-        *type_rtrn = XkbSA_RedirectKey;
-    else if (uStrCaseCmp(str, "redirectkey") == 0)
-        *type_rtrn = XkbSA_RedirectKey;
-    else if (uStrCaseCmp(str, "devbtn") == 0)
-        *type_rtrn = XkbSA_DeviceBtn;
-    else if (uStrCaseCmp(str, "devicebtn") == 0)
-        *type_rtrn = XkbSA_DeviceBtn;
-    else if (uStrCaseCmp(str, "devbutton") == 0)
-        *type_rtrn = XkbSA_DeviceBtn;
-    else if (uStrCaseCmp(str, "devicebutton") == 0)
-        *type_rtrn = XkbSA_DeviceBtn;
-    else if (uStrCaseCmp(str, "lockdevbtn") == 0)
-        *type_rtrn = XkbSA_DeviceBtn;
-    else if (uStrCaseCmp(str, "lockdevicebtn") == 0)
-        *type_rtrn = XkbSA_LockDeviceBtn;
-    else if (uStrCaseCmp(str, "lockdevbutton") == 0)
-        *type_rtrn = XkbSA_LockDeviceBtn;
-    else if (uStrCaseCmp(str, "lockdevicebutton") == 0)
-        *type_rtrn = XkbSA_LockDeviceBtn;
-    else if (uStrCaseCmp(str, "devval") == 0)
-        *type_rtrn = XkbSA_DeviceValuator;
-    else if (uStrCaseCmp(str, "deviceval") == 0)
-        *type_rtrn = XkbSA_DeviceValuator;
-    else if (uStrCaseCmp(str, "devvaluator") == 0)
-        *type_rtrn = XkbSA_DeviceValuator;
-    else if (uStrCaseCmp(str, "devicevaluator") == 0)
-        *type_rtrn = XkbSA_DeviceValuator;
-    else if (uStrCaseCmp(str, "private") == 0)
-        *type_rtrn = PrivateAction;
-    else
-        return False;
-    return True;
+    unsigned type;
+    ActionsInfo *info;
+
+    info = calloc(1, sizeof(*info));
+    if (!info)
+        return NULL;
+
+    for (type = 0; type < _ACTION_TYPE_NUM_ENTRIES; type++)
+        info->actions[type].type = type;
+
+    /* Apply some "factory defaults". */
+
+    /* Increment default button. */
+    info->actions[ACTION_TYPE_PTR_DEFAULT].dflt.flags = 0;
+    info->actions[ACTION_TYPE_PTR_DEFAULT].dflt.value = 1;
+
+    return info;
 }
 
-static Bool
-stringToField(char *str, unsigned *field_rtrn)
+void
+FreeActionsInfo(ActionsInfo *info)
 {
+    free(info);
+}
 
-    if (str == NULL)
-        return False;
-
-    if (uStrCaseCmp(str, "clearlocks") == 0)
-        *field_rtrn = F_ClearLocks;
-    else if (uStrCaseCmp(str, "latchtolock") == 0)
-        *field_rtrn = F_LatchToLock;
-    else if (uStrCaseCmp(str, "genkeyevent") == 0)
-        *field_rtrn = F_GenKeyEvent;
-    else if (uStrCaseCmp(str, "generatekeyevent") == 0)
-        *field_rtrn = F_GenKeyEvent;
-    else if (uStrCaseCmp(str, "report") == 0)
-        *field_rtrn = F_Report;
-    else if (uStrCaseCmp(str, "default") == 0)
-        *field_rtrn = F_Default;
-    else if (uStrCaseCmp(str, "affect") == 0)
-        *field_rtrn = F_Affect;
-    else if (uStrCaseCmp(str, "increment") == 0)
-        *field_rtrn = F_Increment;
-    else if (uStrCaseCmp(str, "mods") == 0)
-        *field_rtrn = F_Modifiers;
-    else if (uStrCaseCmp(str, "modifiers") == 0)
-        *field_rtrn = F_Modifiers;
-    else if (uStrCaseCmp(str, "group") == 0)
-        *field_rtrn = F_Group;
-    else if (uStrCaseCmp(str, "x") == 0)
-        *field_rtrn = F_X;
-    else if (uStrCaseCmp(str, "y") == 0)
-        *field_rtrn = F_Y;
-    else if (uStrCaseCmp(str, "accel") == 0)
-        *field_rtrn = F_Accel;
-    else if (uStrCaseCmp(str, "accelerate") == 0)
-        *field_rtrn = F_Accel;
-    else if (uStrCaseCmp(str, "repeat") == 0)
-        *field_rtrn = F_Accel;
-    else if (uStrCaseCmp(str, "button") == 0)
-        *field_rtrn = F_Button;
-    else if (uStrCaseCmp(str, "value") == 0)
-        *field_rtrn = F_Value;
-    else if (uStrCaseCmp(str, "controls") == 0)
-        *field_rtrn = F_Controls;
-    else if (uStrCaseCmp(str, "ctrls") == 0)
-        *field_rtrn = F_Controls;
-    else if (uStrCaseCmp(str, "type") == 0)
-        *field_rtrn = F_Type;
-    else if (uStrCaseCmp(str, "count") == 0)
-        *field_rtrn = F_Count;
-    else if (uStrCaseCmp(str, "screen") == 0)
-        *field_rtrn = F_Screen;
-    else if (uStrCaseCmp(str, "same") == 0)
-        *field_rtrn = F_Same;
-    else if (uStrCaseCmp(str, "sameserver") == 0)
-        *field_rtrn = F_Same;
-    else if (uStrCaseCmp(str, "data") == 0)
-        *field_rtrn = F_Data;
-    else if (uStrCaseCmp(str, "device") == 0)
-        *field_rtrn = F_Device;
-    else if (uStrCaseCmp(str, "dev") == 0)
-        *field_rtrn = F_Device;
-    else if (uStrCaseCmp(str, "key") == 0)
-        *field_rtrn = F_Keycode;
-    else if (uStrCaseCmp(str, "keycode") == 0)
-        *field_rtrn = F_Keycode;
-    else if (uStrCaseCmp(str, "kc") == 0)
-        *field_rtrn = F_Keycode;
-    else if (uStrCaseCmp(str, "clearmods") == 0)
-        *field_rtrn = F_ModsToClear;
-    else if (uStrCaseCmp(str, "clearmodifiers") == 0)
-        *field_rtrn = F_ModsToClear;
-    else
-        return False;
-    return True;
+static const LookupEntry fieldStrings[] = {
+    { "clearLocks",       ACTION_FIELD_CLEAR_LOCKS   },
+    { "latchToLock",      ACTION_FIELD_LATCH_TO_LOCK },
+    { "genKeyEvent",      ACTION_FIELD_GEN_KEY_EVENT },
+    { "generateKeyEvent", ACTION_FIELD_GEN_KEY_EVENT },
+    { "report",           ACTION_FIELD_REPORT        },
+    { "default",          ACTION_FIELD_DEFAULT       },
+    { "affect",           ACTION_FIELD_AFFECT        },
+    { "increment",        ACTION_FIELD_INCREMENT     },
+    { "modifiers",        ACTION_FIELD_MODIFIERS     },
+    { "mods",             ACTION_FIELD_MODIFIERS     },
+    { "group",            ACTION_FIELD_GROUP         },
+    { "x",                ACTION_FIELD_X             },
+    { "y",                ACTION_FIELD_Y             },
+    { "accel",            ACTION_FIELD_ACCEL         },
+    { "accelerate",       ACTION_FIELD_ACCEL         },
+    { "repeat",           ACTION_FIELD_ACCEL         },
+    { "button",           ACTION_FIELD_BUTTON        },
+    { "value",            ACTION_FIELD_VALUE         },
+    { "controls",         ACTION_FIELD_CONTROLS      },
+    { "ctrls",            ACTION_FIELD_CONTROLS      },
+    { "type",             ACTION_FIELD_TYPE          },
+    { "count",            ACTION_FIELD_COUNT         },
+    { "screen",           ACTION_FIELD_SCREEN        },
+    { "same",             ACTION_FIELD_SAME          },
+    { "sameServer",       ACTION_FIELD_SAME          },
+    { "data",             ACTION_FIELD_DATA          },
+    { "device",           ACTION_FIELD_DEVICE        },
+    { "dev",              ACTION_FIELD_DEVICE        },
+    { "key",              ACTION_FIELD_KEYCODE       },
+    { "keycode",          ACTION_FIELD_KEYCODE       },
+    { "kc",               ACTION_FIELD_KEYCODE       },
+    { "clearmods",        ACTION_FIELD_MODS_TO_CLEAR },
+    { "clearmodifiers",   ACTION_FIELD_MODS_TO_CLEAR },
+    { NULL,               0                          }
+};
+
+static bool
+stringToAction(const char *str, unsigned *type_rtrn)
+{
+    return LookupString(actionTypeNames, str, type_rtrn);
 }
 
-static char *
-fieldText(unsigned field)
+static bool
+stringToField(const char *str, enum action_field *field_rtrn)
 {
-    static char buf[32];
+    return LookupString(fieldStrings, str, field_rtrn);
+}
 
-    switch (field)
-    {
-    case F_ClearLocks:
-        strcpy(buf, "clearLocks");
-        break;
-    case F_LatchToLock:
-        strcpy(buf, "latchToLock");
-        break;
-    case F_GenKeyEvent:
-        strcpy(buf, "genKeyEvent");
-        break;
-    case F_Report:
-        strcpy(buf, "report");
-        break;
-    case F_Default:
-        strcpy(buf, "default");
-        break;
-    case F_Affect:
-        strcpy(buf, "affect");
-        break;
-    case F_Increment:
-        strcpy(buf, "increment");
-        break;
-    case F_Modifiers:
-        strcpy(buf, "modifiers");
-        break;
-    case F_Group:
-        strcpy(buf, "group");
-        break;
-    case F_X:
-        strcpy(buf, "x");
-        break;
-    case F_Y:
-        strcpy(buf, "y");
-        break;
-    case F_Accel:
-        strcpy(buf, "accel");
-        break;
-    case F_Button:
-        strcpy(buf, "button");
-        break;
-    case F_Value:
-        strcpy(buf, "value");
-        break;
-    case F_Controls:
-        strcpy(buf, "controls");
-        break;
-    case F_Type:
-        strcpy(buf, "type");
-        break;
-    case F_Count:
-        strcpy(buf, "count");
-        break;
-    case F_Screen:
-        strcpy(buf, "screen");
-        break;
-    case F_Same:
-        strcpy(buf, "sameServer");
-        break;
-    case F_Data:
-        strcpy(buf, "data");
-        break;
-    case F_Device:
-        strcpy(buf, "device");
-        break;
-    case F_Keycode:
-        strcpy(buf, "keycode");
-        break;
-    case F_ModsToClear:
-        strcpy(buf, "clearmods");
-        break;
-    default:
-        strcpy(buf, "unknown");
-        break;
-    }
-    return buf;
+static const char *
+fieldText(enum action_field field)
+{
+    return LookupValue(fieldStrings, field);
 }
 
 /***====================================================================***/
 
-static Bool
-ReportMismatch(unsigned action, unsigned field, const char *type)
+static inline bool
+ReportMismatch(struct xkb_keymap *keymap, enum xkb_action_type action,
+               enum action_field field, const char *type)
 {
-    ERROR("Value of %s field must be of type %s\n", fieldText(field), type);
-    ACTION("Action %s definition ignored\n", XkbcActionTypeText(action));
-    return False;
+    log_err(keymap->ctx,
+            "Value of %s field must be of type %s; "
+            "Action %s definition ignored\n",
+            fieldText(field), type, ActionTypeText(action));
+    return false;
 }
 
-static Bool
-ReportIllegal(unsigned action, unsigned field)
+static inline bool
+ReportIllegal(struct xkb_keymap *keymap, enum xkb_action_type action,
+              enum action_field field)
 {
-    ERROR("Field %s is not defined for an action of type %s\n",
-           fieldText(field), XkbcActionTypeText(action));
-    ACTION("Action definition ignored\n");
-    return False;
+    log_err(keymap->ctx,
+            "Field %s is not defined for an action of type %s; "
+            "Action definition ignored\n",
+            fieldText(field), ActionTypeText(action));
+    return false;
 }
 
-static Bool
-ReportActionNotArray(unsigned action, unsigned field)
+static inline bool
+ReportActionNotArray(struct xkb_keymap *keymap, enum xkb_action_type action,
+                     enum action_field field)
 {
-    ERROR("The %s field in the %s action is not an array\n",
-           fieldText(field), XkbcActionTypeText(action));
-    ACTION("Action definition ignored\n");
-    return False;
+    log_err(keymap->ctx,
+            "The %s field in the %s action is not an array; "
+            "Action definition ignored\n",
+            fieldText(field), ActionTypeText(action));
+    return false;
 }
 
-static Bool
-ReportNotFound(unsigned action, unsigned field, const char *what, char *bad)
+static inline bool
+ReportNotFound(struct xkb_keymap *keymap, enum xkb_action_type action,
+               enum action_field field, const char *what, const char *bad)
 {
-    ERROR("%s named %s not found\n", what, bad);
-    ACTION("Ignoring the %s field of an %s action\n", fieldText(field),
-            XkbcActionTypeText(action));
-    return False;
+    log_err(keymap->ctx,
+            "%s named %s not found; "
+            "Ignoring the %s field of an %s action\n",
+            what, bad, fieldText(field), ActionTypeText(action));
+    return false;
 }
 
-static Bool
-HandleNoAction(struct xkb_desc * xkb,
-               struct xkb_any_action * action,
-               unsigned field, ExprDef * array_ndx, ExprDef * value)
+static bool
+HandleNoAction(struct xkb_keymap *keymap, union xkb_action *action,
+               enum action_field field, const ExprDef *array_ndx,
+               const ExprDef *value)
+
 {
-    return ReportIllegal(action->type, field);
+    return true;
 }
 
-static Bool
-CheckLatchLockFlags(unsigned action,
-                    unsigned field, ExprDef * value, unsigned *flags_inout)
+static bool
+CheckLatchLockFlags(struct xkb_keymap *keymap, enum xkb_action_type action,
+                    enum action_field field, const ExprDef * value,
+                    enum xkb_action_flags *flags_inout)
 {
-    unsigned tmp;
-    ExprResult result;
+    enum xkb_action_flags tmp;
+    bool result;
 
-    if (field == F_ClearLocks)
-        tmp = XkbSA_ClearLocks;
-    else if (field == F_LatchToLock)
-        tmp = XkbSA_LatchToLock;
+    if (field == ACTION_FIELD_CLEAR_LOCKS)
+        tmp = ACTION_LOCK_CLEAR;
+    else if (field == ACTION_FIELD_LATCH_TO_LOCK)
+        tmp = ACTION_LATCH_TO_LOCK;
     else
-        return False;           /* WSGO! */
-    if (!ExprResolveBoolean(value, &result))
-        return ReportMismatch(action, field, "boolean");
-    if (result.uval)
+        return false;           /* WSGO! */
+
+    if (!ExprResolveBoolean(keymap->ctx, value, &result))
+        return ReportMismatch(keymap, action, field, "boolean");
+
+    if (result)
         *flags_inout |= tmp;
     else
         *flags_inout &= ~tmp;
-    return True;
+
+    return true;
 }
 
-static Bool
-CheckModifierField(struct xkb_desc * xkb,
-                   unsigned action,
-                   ExprDef * value,
-                   unsigned *flags_inout, unsigned *mods_rtrn)
+static bool
+CheckModifierField(struct xkb_keymap *keymap, enum xkb_action_type action,
+                   const ExprDef *value, enum xkb_action_flags *flags_inout,
+                   xkb_mod_mask_t *mods_rtrn)
 {
-    ExprResult rtrn;
-
-    if (value->op == ExprIdent)
-    {
+    if (value->op == EXPR_IDENT) {
         const char *valStr;
-        valStr = XkbcAtomText(value->value.str);
-        if (valStr && ((uStrCaseCmp(valStr, "usemodmapmods") == 0) ||
-                       (uStrCaseCmp(valStr, "modmapmods") == 0)))
-        {
+        valStr = xkb_atom_text(keymap->ctx, value->value.str);
+        if (valStr && (istreq(valStr, "usemodmapmods") ||
+                       istreq(valStr, "modmapmods"))) {
 
             *mods_rtrn = 0;
-            *flags_inout |= XkbSA_UseModMapMods;
-            return True;
+            *flags_inout |= ACTION_MODS_LOOKUP_MODMAP;
+            return true;
         }
     }
-    if (!ExprResolveVModMask(value, &rtrn, xkb))
-        return ReportMismatch(action, F_Modifiers, "modifier mask");
-    *mods_rtrn = rtrn.uval;
-    *flags_inout &= ~XkbSA_UseModMapMods;
-    return True;
+
+    if (!ExprResolveModMask(keymap, value, MOD_BOTH, mods_rtrn))
+        return ReportMismatch(keymap, action,
+                              ACTION_FIELD_MODIFIERS, "modifier mask");
+
+    *flags_inout &= ~ACTION_MODS_LOOKUP_MODMAP;
+    return true;
 }
 
-static Bool
-HandleSetLatchMods(struct xkb_desc * xkb,
-                   struct xkb_any_action * action,
-                   unsigned field, ExprDef * array_ndx, ExprDef * value)
+static bool
+HandleSetLatchMods(struct xkb_keymap *keymap, union xkb_action *action,
+                   enum action_field field, const ExprDef *array_ndx,
+                   const ExprDef *value)
 {
-    struct xkb_mod_action *act;
-    unsigned rtrn;
-    unsigned t1, t2;
-
-    act = (struct xkb_mod_action *) action;
-    if (array_ndx != NULL)
-    {
-        switch (field)
-        {
-        case F_ClearLocks:
-        case F_LatchToLock:
-        case F_Modifiers:
-            return ReportActionNotArray(action->type, field);
+    struct xkb_mod_action *act = &action->mods;
+    enum xkb_action_flags rtrn, t1;
+    xkb_mod_mask_t t2;
+
+    if (array_ndx != NULL) {
+        switch (field) {
+        case ACTION_FIELD_CLEAR_LOCKS:
+        case ACTION_FIELD_LATCH_TO_LOCK:
+        case ACTION_FIELD_MODIFIERS:
+            return ReportActionNotArray(keymap, action->type, field);
+        default:
+            break;
         }
     }
-    switch (field)
-    {
-    case F_ClearLocks:
-    case F_LatchToLock:
+
+    switch (field) {
+    case ACTION_FIELD_CLEAR_LOCKS:
+    case ACTION_FIELD_LATCH_TO_LOCK:
         rtrn = act->flags;
-        if (CheckLatchLockFlags(action->type, field, value, &rtrn))
-        {
+        if (CheckLatchLockFlags(keymap, action->type, field, value, &rtrn)) {
             act->flags = rtrn;
-            return True;
+            return true;
         }
-        return False;
-    case F_Modifiers:
+        return false;
+
+    case ACTION_FIELD_MODIFIERS:
         t1 = act->flags;
-        if (CheckModifierField(xkb, action->type, value, &t1, &t2))
-        {
+        if (CheckModifierField(keymap, action->type, value, &t1, &t2)) {
             act->flags = t1;
-            act->real_mods = act->mask = (t2 & 0xff);
-            act->vmods = (t2 >> 8) & 0xffff;
-            return True;
+            act->mods.mods = t2;
+            return true;
         }
-        return False;
+        return false;
+
+    default:
+        break;
     }
-    return ReportIllegal(action->type, field);
+
+    return ReportIllegal(keymap, action->type, field);
 }
 
-static Bool
-HandleLockMods(struct xkb_desc * xkb,
-               struct xkb_any_action * action,
-               unsigned field, ExprDef * array_ndx, ExprDef * value)
+static bool
+HandleLockMods(struct xkb_keymap *keymap, union xkb_action *action,
+               enum action_field field, const ExprDef *array_ndx,
+               const ExprDef *value)
 {
-    struct xkb_mod_action *act;
-    unsigned t1, t2;
-
-    act = (struct xkb_mod_action *) action;
-    if ((array_ndx != NULL) && (field == F_Modifiers))
-        return ReportActionNotArray(action->type, field);
-    switch (field)
-    {
-    case F_Modifiers:
+    struct xkb_mod_action *act = &action->mods;
+    enum xkb_action_flags t1;
+    xkb_mod_mask_t t2;
+
+    if (array_ndx && field == ACTION_FIELD_MODIFIERS)
+        return ReportActionNotArray(keymap, action->type, field);
+
+    switch (field) {
+    case ACTION_FIELD_MODIFIERS:
         t1 = act->flags;
-        if (CheckModifierField(xkb, action->type, value, &t1, &t2))
-        {
+        if (CheckModifierField(keymap, action->type, value, &t1, &t2)) {
             act->flags = t1;
-            act->real_mods = act->mask = (t2 & 0xff);
-            act->vmods = (t2 >> 8) & 0xffff;
-            return True;
+            act->mods.mods = t2;
+            return true;
         }
-        return False;
+        return false;
+
+    default:
+        break;
     }
-    return ReportIllegal(action->type, field);
-}
 
-static LookupEntry groupNames[] = {
-    {"group1", 1},
-    {"group2", 2},
-    {"group3", 3},
-    {"group4", 4},
-    {"group5", 5},
-    {"group6", 6},
-    {"group7", 7},
-    {"group8", 8},
-    {NULL, 0},
-};
+    return ReportIllegal(keymap, action->type, field);
+}
 
-static Bool
-CheckGroupField(unsigned action,
-                ExprDef * value, unsigned *flags_inout, int *grp_rtrn)
+static bool
+CheckGroupField(struct xkb_keymap *keymap, unsigned action,
+                const ExprDef *value, enum xkb_action_flags *flags_inout,
+                xkb_layout_index_t *grp_rtrn)
 {
-    ExprDef *spec;
-    ExprResult rtrn;
+    const ExprDef *spec;
 
-    if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
-    {
-        *flags_inout &= ~XkbSA_GroupAbsolute;
+    if (value->op == EXPR_NEGATE || value->op == EXPR_UNARY_PLUS) {
+        *flags_inout &= ~ACTION_ABSOLUTE_SWITCH;
         spec = value->value.child;
     }
-    else
-    {
-        *flags_inout |= XkbSA_GroupAbsolute;
+    else {
+        *flags_inout |= ACTION_ABSOLUTE_SWITCH;
         spec = value;
     }
 
-    if (!ExprResolveInteger(spec, &rtrn, SimpleLookup, (char *) groupNames))
-        return ReportMismatch(action, F_Group, "integer (range 1..8)");
-    if ((rtrn.ival < 1) || (rtrn.ival > XkbNumKbdGroups))
-    {
-        ERROR("Illegal group %d (must be in the range 1..%d)\n", rtrn.ival,
-               XkbNumKbdGroups);
-        ACTION("Action %s definition ignored\n", XkbcActionTypeText(action));
-        return False;
-    }
-    if (value->op == OpNegate)
-        *grp_rtrn = -rtrn.ival;
-    else if (value->op == OpUnaryPlus)
-        *grp_rtrn = rtrn.ival;
-    else
-        *grp_rtrn = rtrn.ival - 1;
-    return True;
+    if (!ExprResolveGroup(keymap->ctx, spec, grp_rtrn))
+        return ReportMismatch(keymap, action, ACTION_FIELD_GROUP,
+                              "integer (range 1..8)");
+
+    if (value->op == EXPR_NEGATE)
+        *grp_rtrn = -*grp_rtrn;
+    else if (value->op != EXPR_UNARY_PLUS)
+        (*grp_rtrn)--;
+
+    return true;
 }
 
-static Bool
-HandleSetLatchGroup(struct xkb_desc * xkb,
-                    struct xkb_any_action * action,
-                    unsigned field, ExprDef * array_ndx, ExprDef * value)
+static bool
+HandleSetLatchGroup(struct xkb_keymap *keymap, union xkb_action *action,
+                    enum action_field field, const ExprDef *array_ndx,
+                    const ExprDef *value)
 {
-    struct xkb_group_action *act;
-    unsigned rtrn;
-    unsigned t1;
-    int t2;
-
-    act = (struct xkb_group_action *) action;
-    if (array_ndx != NULL)
-    {
-        switch (field)
-        {
-        case F_ClearLocks:
-        case F_LatchToLock:
-        case F_Group:
-            return ReportActionNotArray(action->type, field);
+    struct xkb_group_action *act = &action->group;
+    enum xkb_action_flags rtrn, t1;
+    xkb_layout_index_t t2;
+
+    if (array_ndx != NULL) {
+        switch (field) {
+        case ACTION_FIELD_CLEAR_LOCKS:
+        case ACTION_FIELD_LATCH_TO_LOCK:
+        case ACTION_FIELD_GROUP:
+            return ReportActionNotArray(keymap, action->type, field);
+
+        default:
+            break;
         }
     }
-    switch (field)
-    {
-    case F_ClearLocks:
-    case F_LatchToLock:
+
+    switch (field) {
+    case ACTION_FIELD_CLEAR_LOCKS:
+    case ACTION_FIELD_LATCH_TO_LOCK:
         rtrn = act->flags;
-        if (CheckLatchLockFlags(action->type, field, value, &rtrn))
-        {
+        if (CheckLatchLockFlags(keymap, action->type, field, value, &rtrn)) {
             act->flags = rtrn;
-            return True;
+            return true;
         }
-        return False;
-    case F_Group:
+        return false;
+
+    case ACTION_FIELD_GROUP:
         t1 = act->flags;
-        if (CheckGroupField(action->type, value, &t1, &t2))
-        {
+        if (CheckGroupField(keymap, action->type, value, &t1, &t2)) {
             act->flags = t1;
-           act->group = t2;
-            return True;
+            act->group = t2;
+            return true;
         }
-        return False;
+        return false;
+
+    default:
+        break;
     }
-    return ReportIllegal(action->type, field);
+
+    return ReportIllegal(keymap, action->type, field);
 }
 
-static Bool
-HandleLockGroup(struct xkb_desc * xkb,
-                struct xkb_any_action * action,
-                unsigned field, ExprDef * array_ndx, ExprDef * value)
+static bool
+HandleLockGroup(struct xkb_keymap *keymap, union xkb_action *action,
+                enum action_field field, const ExprDef *array_ndx,
+                const ExprDef *value)
 {
-    struct xkb_group_action *act;
-    unsigned t1;
-    int t2;
-
-    act = (struct xkb_group_action *) action;
-    if ((array_ndx != NULL) && (field == F_Group))
-        return ReportActionNotArray(action->type, field);
-    if (field == F_Group)
-    {
+    struct xkb_group_action *act = &action->group;
+    enum xkb_action_flags t1;
+    xkb_layout_index_t t2;
+
+    if ((array_ndx != NULL) && (field == ACTION_FIELD_GROUP))
+        return ReportActionNotArray(keymap, action->type, field);
+    if (field == ACTION_FIELD_GROUP) {
         t1 = act->flags;
-        if (CheckGroupField(action->type, value, &t1, &t2))
-        {
+        if (CheckGroupField(keymap, action->type, value, &t1, &t2)) {
             act->flags = t1;
-           act->group = t2;
-            return True;
+            act->group = t2;
+            return true;
         }
-        return False;
+        return false;
     }
-    return ReportIllegal(action->type, field);
+    return ReportIllegal(keymap, action->type, field);
 }
 
-static Bool
-HandleMovePtr(struct xkb_desc * xkb,
-              struct xkb_any_action * action,
-              unsigned field, ExprDef * array_ndx, ExprDef * value)
+static bool
+HandleMovePtr(struct xkb_keymap *keymap, union xkb_action *action,
+              enum action_field field, const ExprDef *array_ndx,
+              const ExprDef *value)
 {
-    ExprResult rtrn;
-    struct xkb_pointer_action *act;
-    Bool absolute;
-
-    act = (struct xkb_pointer_action *) action;
-    if ((array_ndx != NULL) && ((field == F_X) || (field == F_Y)))
-        return ReportActionNotArray(action->type, field);
-
-    if ((field == F_X) || (field == F_Y))
-    {
-        if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
-            absolute = False;
+    struct xkb_pointer_action *act = &action->ptr;
+    bool absolute;
+
+    if (array_ndx && (field == ACTION_FIELD_X || field == ACTION_FIELD_Y))
+        return ReportActionNotArray(keymap, action->type, field);
+
+    if (field == ACTION_FIELD_X || field == ACTION_FIELD_Y) {
+        int val;
+
+        if (value->op == EXPR_NEGATE || value->op == EXPR_UNARY_PLUS)
+            absolute = false;
         else
-            absolute = True;
-        if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
-            return ReportMismatch(action->type, field, "integer");
-        if (field == F_X)
-        {
+            absolute = true;
+
+        if (!ExprResolveInteger(keymap->ctx, value, &val))
+            return ReportMismatch(keymap, action->type, field, "integer");
+
+        if (field == ACTION_FIELD_X) {
             if (absolute)
-                act->flags |= XkbSA_MoveAbsoluteX;
-            act->x = rtrn.ival;
+                act->flags |= ACTION_ABSOLUTE_X;
+            act->x = val;
         }
-        else
-        {
+        else {
             if (absolute)
-                act->flags |= XkbSA_MoveAbsoluteY;
-            act->y = rtrn.ival;
+                act->flags |= ACTION_ABSOLUTE_Y;
+            act->y = val;
         }
-        return True;
+
+        return true;
     }
-    else if (field == F_Accel)
-    {
-        if (!ExprResolveBoolean(value, &rtrn))
-            return ReportMismatch(action->type, field, "boolean");
-        if (rtrn.uval)
-            act->flags &= ~XkbSA_NoAcceleration;
+    else if (field == ACTION_FIELD_ACCEL) {
+        bool set;
+
+        if (!ExprResolveBoolean(keymap->ctx, value, &set))
+            return ReportMismatch(keymap, action->type, field, "boolean");
+
+        if (set)
+            act->flags &= ~ACTION_NO_ACCEL;
         else
-            act->flags |= XkbSA_NoAcceleration;
+            act->flags |= ACTION_NO_ACCEL;
     }
-    return ReportIllegal(action->type, field);
-}
 
-static LookupEntry btnNames[] = {
-    {"button1", 1},
-    {"button2", 2},
-    {"button3", 3},
-    {"button4", 4},
-    {"button5", 5},
-    {"default", 0},
-    {NULL, 0}
-};
+    return ReportIllegal(keymap, action->type, field);
+}
 
-static LookupEntry lockWhich[] = {
-    {"both", 0},
-    {"lock", XkbSA_LockNoUnlock},
-    {"neither", (XkbSA_LockNoLock | XkbSA_LockNoUnlock)},
-    {"unlock", XkbSA_LockNoLock},
-    {NULL, 0}
+static const LookupEntry lockWhich[] = {
+    { "both", 0 },
+    { "lock", ACTION_LOCK_NO_UNLOCK },
+    { "neither", (ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK) },
+    { "unlock", ACTION_LOCK_NO_LOCK },
+    { NULL, 0 }
 };
 
-static Bool
-HandlePtrBtn(struct xkb_desc * xkb,
-             struct xkb_any_action * action,
-             unsigned field, ExprDef * array_ndx, ExprDef * value)
+static bool
+HandlePtrBtn(struct xkb_keymap *keymap, union xkb_action *action,
+             enum action_field field, const ExprDef *array_ndx,
+             const ExprDef *value)
 {
-    ExprResult rtrn;
-    struct xkb_pointer_button_action *act;
-
-    act = (struct xkb_pointer_button_action *) action;
-    if (field == F_Button)
-    {
-        if (array_ndx != NULL)
-            return ReportActionNotArray(action->type, field);
-        if (!ExprResolveInteger
-            (value, &rtrn, SimpleLookup, (char *) btnNames))
-            return ReportMismatch(action->type, field,
+    struct xkb_pointer_button_action *act = &action->btn;
+
+    if (field == ACTION_FIELD_BUTTON) {
+        int btn;
+
+        if (array_ndx)
+            return ReportActionNotArray(keymap, action->type, field);
+
+        if (!ExprResolveButton(keymap->ctx, value, &btn))
+            return ReportMismatch(keymap, action->type, field,
                                   "integer (range 1..5)");
-        if ((rtrn.ival < 0) || (rtrn.ival > 5))
-        {
-            ERROR("Button must specify default or be in the range 1..5\n");
-            ACTION("Illegal button value %d ignored\n", rtrn.ival);
-            return False;
+
+        if (btn < 0 || btn > 5) {
+            log_err(keymap->ctx,
+                    "Button must specify default or be in the range 1..5; "
+                    "Illegal button value %d ignored\n", btn);
+            return false;
         }
-        act->button = rtrn.ival;
-        return True;
+
+        act->button = btn;
+        return true;
     }
-    else if ((action->type == XkbSA_LockPtrBtn) && (field == F_Affect))
-    {
-        if (array_ndx != NULL)
-            return ReportActionNotArray(action->type, field);
-        if (!ExprResolveEnum(value, &rtrn, lockWhich))
-            return ReportMismatch(action->type, field, "lock or unlock");
-        act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock);
-        act->flags |= rtrn.ival;
-        return True;
+    else if (action->type == ACTION_TYPE_PTR_LOCK &&
+             field == ACTION_FIELD_AFFECT) {
+        enum xkb_action_flags val;
+
+        if (array_ndx)
+            return ReportActionNotArray(keymap, action->type, field);
+
+        if (!ExprResolveEnum(keymap->ctx, value, &val, lockWhich))
+            return ReportMismatch(keymap, action->type, field,
+                                  "lock or unlock");
+
+        act->flags &= ~(ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK);
+        act->flags |= val;
+        return true;
     }
-    else if (field == F_Count)
-    {
-        if (array_ndx != NULL)
-            return ReportActionNotArray(action->type, field);
-        if (!ExprResolveInteger
-            (value, &rtrn, SimpleLookup, (char *) btnNames))
-            return ReportMismatch(action->type, field, "integer");
-        if ((rtrn.ival < 0) || (rtrn.ival > 255))
-        {
-            ERROR("The count field must have a value in the range 0..255\n");
-            ACTION("Illegal count %d ignored\n", rtrn.ival);
-            return False;
+    else if (field == ACTION_FIELD_COUNT) {
+        int btn;
+
+        if (array_ndx)
+            return ReportActionNotArray(keymap, action->type, field);
+
+        /* XXX: Should this actually be ResolveButton? */
+        if (!ExprResolveButton(keymap->ctx, value, &btn))
+            return ReportMismatch(keymap, action->type, field, "integer");
+
+        if (btn < 0 || btn > 255) {
+            log_err(keymap->ctx,
+                    "The count field must have a value in the range 0..255; "
+                    "Illegal count %d ignored\n", btn);
+            return false;
         }
-        act->count = rtrn.ival;
-        return True;
+
+        act->count = btn;
+        return true;
     }
-    return ReportIllegal(action->type, field);
+    return ReportIllegal(keymap, action->type, field);
 }
 
-static LookupEntry ptrDflts[] = {
-    {"dfltbtn", XkbSA_AffectDfltBtn},
-    {"defaultbutton", XkbSA_AffectDfltBtn},
-    {"button", XkbSA_AffectDfltBtn},
-    {NULL, 0}
+static const LookupEntry ptrDflts[] = {
+    { "dfltbtn", 1 },
+    { "defaultbutton", 1 },
+    { "button", 1 },
+    { NULL, 0 }
 };
 
-static Bool
-HandleSetPtrDflt(struct xkb_desc * xkb,
-                 struct xkb_any_action * action,
-                 unsigned field, ExprDef * array_ndx, ExprDef * value)
+static bool
+HandleSetPtrDflt(struct xkb_keymap *keymap, union xkb_action *action,
+                 enum action_field field, const ExprDef *array_ndx,
+                 const ExprDef *value)
 {
-    ExprResult rtrn;
-    struct xkb_pointer_default_action *act;
-
-    act = (struct xkb_pointer_default_action *) action;
-    if (field == F_Affect)
-    {
-        if (array_ndx != NULL)
-            return ReportActionNotArray(action->type, field);
-        if (!ExprResolveEnum(value, &rtrn, ptrDflts))
-            return ReportMismatch(action->type, field, "pointer component");
-        act->affect = rtrn.uval;
-        return True;
+    struct xkb_pointer_default_action *act = &action->dflt;
+
+    if (field == ACTION_FIELD_AFFECT) {
+        unsigned int val;
+
+        if (array_ndx)
+            return ReportActionNotArray(keymap, action->type, field);
+
+        if (!ExprResolveEnum(keymap->ctx, value, &val, ptrDflts))
+            return ReportMismatch(keymap, action->type, field,
+                                  "pointer component");
+        return true;
     }
-    else if ((field == F_Button) || (field == F_Value))
-    {
-        ExprDef *btn;
-        if (array_ndx != NULL)
-            return ReportActionNotArray(action->type, field);
-        if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
-        {
-            act->flags &= ~XkbSA_DfltBtnAbsolute;
-            btn = value->value.child;
-        }
-        else
-        {
-            act->flags |= XkbSA_DfltBtnAbsolute;
-            btn = value;
-        }
+    else if (field == ACTION_FIELD_BUTTON || field == ACTION_FIELD_VALUE) {
+        const ExprDef *button;
+        int btn;
 
-        if (!ExprResolveInteger
-            (btn, &rtrn, SimpleLookup, (char *) btnNames))
-            return ReportMismatch(action->type, field,
-                                  "integer (range 1..5)");
-        if ((rtrn.ival < 0) || (rtrn.ival > 5))
-        {
-            ERROR("New default button value must be in the range 1..5\n");
-            ACTION("Illegal default button value %d ignored\n", rtrn.ival);
-            return False;
+        if (array_ndx)
+            return ReportActionNotArray(keymap, action->type, field);
+
+        if (value->op == EXPR_NEGATE || value->op == EXPR_UNARY_PLUS) {
+            act->flags &= ~ACTION_ABSOLUTE_SWITCH;
+            button = value->value.child;
         }
-        if (rtrn.ival == 0)
-        {
-            ERROR("Cannot set default pointer button to \"default\"\n");
-            ACTION("Illegal default button setting ignored\n");
-            return False;
+        else {
+            act->flags |= ACTION_ABSOLUTE_SWITCH;
+            button = value;
         }
-        if (value->op == OpNegate)
-           act->value = -rtrn.ival;
-        else
-           act->value = rtrn.ival;
-        return True;
-    }
-    return ReportIllegal(action->type, field);
-}
 
-static LookupEntry isoNames[] = {
-    {"mods", XkbSA_ISONoAffectMods},
-    {"modifiers", XkbSA_ISONoAffectMods},
-    {"group", XkbSA_ISONoAffectGroup},
-    {"groups", XkbSA_ISONoAffectGroup},
-    {"ptr", XkbSA_ISONoAffectPtr},
-    {"pointer", XkbSA_ISONoAffectPtr},
-    {"ctrls", XkbSA_ISONoAffectCtrls},
-    {"controls", XkbSA_ISONoAffectCtrls},
-    {"all", ~((unsigned) 0)},
-    {"none", 0},
-    {NULL, 0},
-};
+        if (!ExprResolveButton(keymap->ctx, button, &btn))
+            return ReportMismatch(keymap, action->type, field,
+                                  "integer (range 1..5)");
 
-static Bool
-HandleISOLock(struct xkb_desc * xkb,
-              struct xkb_any_action * action,
-              unsigned field, ExprDef * array_ndx, ExprDef * value)
-{
-    ExprResult rtrn;
-    struct xkb_iso_action *act;
-    unsigned flags, mods;
-    int group;
-
-    act = (struct xkb_iso_action *) action;
-    switch (field)
-    {
-    case F_Modifiers:
-        if (array_ndx != NULL)
-            return ReportActionNotArray(action->type, field);
-        flags = act->flags;
-        if (CheckModifierField(xkb, action->type, value, &flags, &mods))
-        {
-            act->flags = flags & (~XkbSA_ISODfltIsGroup);
-            act->real_mods = mods & 0xff;
-            act->vmods = (mods >> 8) & 0xff;
-            return True;
+        if (btn < 0 || btn > 5) {
+            log_err(keymap->ctx,
+                    "New default button value must be in the range 1..5; "
+                    "Illegal default button value %d ignored\n", btn);
+            return false;
         }
-        return False;
-    case F_Group:
-        if (array_ndx != NULL)
-            return ReportActionNotArray(action->type, field);
-        flags = act->flags;
-        if (CheckGroupField(action->type, value, &flags, &group))
-        {
-            act->flags = flags | XkbSA_ISODfltIsGroup;
-            act->group = group;
-            return True;
+        if (btn == 0) {
+            log_err(keymap->ctx,
+                    "Cannot set default pointer button to \"default\"; "
+                    "Illegal default button setting ignored\n");
+            return false;
         }
-        return False;
-    case F_Affect:
-        if (array_ndx != NULL)
-            return ReportActionNotArray(action->type, field);
-        if (!ExprResolveMask(value, &rtrn, SimpleLookup, (char *) isoNames))
-            return ReportMismatch(action->type, field, "keyboard component");
-        act->affect = (~rtrn.uval) & XkbSA_ISOAffectMask;
-        return True;
+
+        act->value = (value->op == EXPR_NEGATE ? -btn: btn);
+        return true;
     }
-    return ReportIllegal(action->type, field);
+
+    return ReportIllegal(keymap, action->type, field);
 }
 
-static Bool
-HandleSwitchScreen(struct xkb_desc * xkb,
-                   struct xkb_any_action * action,
-                   unsigned field, ExprDef * array_ndx, ExprDef * value)
+static bool
+HandleSwitchScreen(struct xkb_keymap *keymap, union xkb_action *action,
+                   enum action_field field, const ExprDef *array_ndx,
+                   const ExprDef *value)
 {
-    ExprResult rtrn;
-    struct xkb_switch_screen_action *act;
-
-    act = (struct xkb_switch_screen_action *) action;
-    if (field == F_Screen)
-    {
-        ExprDef *scrn;
-        if (array_ndx != NULL)
-            return ReportActionNotArray(action->type, field);
-        if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
-        {
-            act->flags &= ~XkbSA_SwitchAbsolute;
+    struct xkb_switch_screen_action *act = &action->screen;
+
+    if (field == ACTION_FIELD_SCREEN) {
+        const ExprDef *scrn;
+        int val;
+
+        if (array_ndx)
+            return ReportActionNotArray(keymap, action->type, field);
+
+        if (value->op == EXPR_NEGATE || value->op == EXPR_UNARY_PLUS) {
+            act->flags &= ~ACTION_ABSOLUTE_SWITCH;
             scrn = value->value.child;
         }
-        else
-        {
-            act->flags |= XkbSA_SwitchAbsolute;
+        else {
+            act->flags |= ACTION_ABSOLUTE_SWITCH;
             scrn = value;
         }
 
-        if (!ExprResolveInteger(scrn, &rtrn, NULL, NULL))
-            return ReportMismatch(action->type, field, "integer (0..255)");
-        if ((rtrn.ival < 0) || (rtrn.ival > 255))
-        {
-            ERROR("Screen index must be in the range 1..255\n");
-            ACTION("Illegal screen value %d ignored\n", rtrn.ival);
-            return False;
-        }
-        if (value->op == OpNegate)
-           act->screen = -rtrn.ival;
-        else
-           act->screen = rtrn.ival;
-        return True;
-    }
-    else if (field == F_Same)
-    {
-        if (array_ndx != NULL)
-            return ReportActionNotArray(action->type, field);
-        if (!ExprResolveBoolean(value, &rtrn))
-            return ReportMismatch(action->type, field, "boolean");
-        if (rtrn.uval)
-            act->flags &= ~XkbSA_SwitchApplication;
-        else
-            act->flags |= XkbSA_SwitchApplication;
-        return True;
-    }
-    return ReportIllegal(action->type, field);
-}
+        if (!ExprResolveInteger(keymap->ctx, scrn, &val))
+            return ReportMismatch(keymap, action->type, field,
+                                  "integer (0..255)");
 
-LookupEntry ctrlNames[] = {
-    {"repeatkeys", XkbRepeatKeysMask}
-    ,
-    {"repeat", XkbRepeatKeysMask}
-    ,
-    {"autorepeat", XkbRepeatKeysMask}
-    ,
-    {"slowkeys", XkbSlowKeysMask}
-    ,
-    {"bouncekeys", XkbBounceKeysMask}
-    ,
-    {"stickykeys", XkbStickyKeysMask}
-    ,
-    {"mousekeys", XkbMouseKeysMask}
-    ,
-    {"mousekeysaccel", XkbMouseKeysAccelMask}
-    ,
-    {"accessxkeys", XkbAccessXKeysMask}
-    ,
-    {"accessxtimeout", XkbAccessXTimeoutMask}
-    ,
-    {"accessxfeedback", XkbAccessXFeedbackMask}
-    ,
-    {"audiblebell", XkbAudibleBellMask}
-    ,
-    {"overlay1", XkbOverlay1Mask}
-    ,
-    {"overlay2", XkbOverlay2Mask}
-    ,
-    {"ignoregrouplock", XkbIgnoreGroupLockMask}
-    ,
-    {"all", XkbAllBooleanCtrlsMask}
-    ,
-    {"none", 0}
-    ,
-    {NULL, 0}
-};
+        if (val < 0 || val > 255) {
+            log_err(keymap->ctx,
+                    "Screen index must be in the range 1..255; "
+                    "Illegal screen value %d ignored\n", val);
+            return false;
+        }
 
-static Bool
-HandleSetLockControls(struct xkb_desc * xkb,
-                      struct xkb_any_action * action,
-                      unsigned field, ExprDef * array_ndx, ExprDef * value)
-{
-    ExprResult rtrn;
-    struct xkb_controls_action *act;
-
-    act = (struct xkb_controls_action *) action;
-    if (field == F_Controls)
-    {
-        if (array_ndx != NULL)
-            return ReportActionNotArray(action->type, field);
-        if (!ExprResolveMask
-            (value, &rtrn, SimpleLookup, (char *) ctrlNames))
-            return ReportMismatch(action->type, field, "controls mask");
-        act->ctrls = rtrn.uval;
-        return True;
+        act->screen = (value->op == EXPR_NEGATE ? -val : val);
+        return true;
     }
-    return ReportIllegal(action->type, field);
-}
+    else if (field == ACTION_FIELD_SAME) {
+        bool set;
 
-static LookupEntry evNames[] = {
-    {"press", XkbSA_MessageOnPress},
-    {"keypress", XkbSA_MessageOnPress},
-    {"release", XkbSA_MessageOnRelease},
-    {"keyrelease", XkbSA_MessageOnRelease},
-    {"all", XkbSA_MessageOnPress | XkbSA_MessageOnRelease},
-    {"none", 0},
-    {NULL, 0}
-};
+        if (array_ndx)
+            return ReportActionNotArray(keymap, action->type, field);
 
-static Bool
-HandleActionMessage(struct xkb_desc * xkb,
-                    struct xkb_any_action * action,
-                    unsigned field, ExprDef * array_ndx, ExprDef * value)
-{
-    ExprResult rtrn;
-    struct xkb_message_action *act;
-
-    act = (struct xkb_message_action *) action;
-    switch (field)
-    {
-    case F_Report:
-        if (array_ndx != NULL)
-            return ReportActionNotArray(action->type, field);
-        if (!ExprResolveMask(value, &rtrn, SimpleLookup, (char *) evNames))
-            return ReportMismatch(action->type, field, "key event mask");
-        act->flags &= ~(XkbSA_MessageOnPress | XkbSA_MessageOnRelease);
-        act->flags =
-            rtrn.uval & (XkbSA_MessageOnPress | XkbSA_MessageOnRelease);
-        return True;
-    case F_GenKeyEvent:
-        if (array_ndx != NULL)
-            return ReportActionNotArray(action->type, field);
-        if (!ExprResolveBoolean(value, &rtrn))
-            return ReportMismatch(action->type, field, "boolean");
-        if (rtrn.uval)
-            act->flags |= XkbSA_MessageGenKeyEvent;
-        else
-            act->flags &= ~XkbSA_MessageGenKeyEvent;
-        return True;
-    case F_Data:
-        if (array_ndx == NULL)
-        {
-            if (!ExprResolveString(value, &rtrn))
-                return ReportMismatch(action->type, field, "string");
-            else
-            {
-                int len = strlen(rtrn.str);
-                if ((len < 1) || (len > 6))
-                {
-                    WARN("An action message can hold only 6 bytes\n");
-                    ACTION("Extra %d bytes ignored\n", len - 6);
-                }
-                strncpy((char *) act->message, rtrn.str, 6);
-            }
-            return True;
-        }
+        if (!ExprResolveBoolean(keymap->ctx, value, &set))
+            return ReportMismatch(keymap, action->type, field, "boolean");
+
+        if (set)
+            act->flags &= ~ACTION_SAME_SCREEN;
         else
-        {
-            unsigned ndx;
-            if (!ExprResolveInteger(array_ndx, &rtrn, NULL, NULL))
-            {
-                ERROR("Array subscript must be integer\n");
-                ACTION("Illegal subscript ignored\n");
-                return False;
-            }
-            ndx = rtrn.uval;
-            if (ndx > 5)
-            {
-                ERROR("An action message is at most 6 bytes long\n");
-                ACTION("Attempt to use data[%d] ignored\n", ndx);
-                return False;
-            }
-            if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
-                return ReportMismatch(action->type, field, "integer");
-            if ((rtrn.ival < 0) || (rtrn.ival > 255))
-            {
-                ERROR("Message data must be in the range 0..255\n");
-                ACTION("Illegal datum %d ignored\n", rtrn.ival);
-                return False;
-            }
-            act->message[ndx] = rtrn.uval;
-        }
-        return True;
-    }
-    return ReportIllegal(action->type, field);
-}
+            act->flags |= ACTION_SAME_SCREEN;
 
-static Bool
-HandleRedirectKey(struct xkb_desc * xkb,
-                  struct xkb_any_action * action,
-                  unsigned field, ExprDef * array_ndx, ExprDef * value)
-{
-    ExprResult rtrn;
-    struct xkb_redirect_key_action *act;
-    unsigned t1, t2;
-    xkb_keycode_t kc;
-    unsigned long tmp;
-
-    if (array_ndx != NULL)
-        return ReportActionNotArray(action->type, field);
-
-    act = (struct xkb_redirect_key_action *) action;
-    switch (field)
-    {
-    case F_Keycode:
-        if (!ExprResolveKeyName(value, &rtrn))
-            return ReportMismatch(action->type, field, "key name");
-        tmp = KeyNameToLong(rtrn.keyName.name);
-        if (!FindNamedKey(xkb, tmp, &kc, True, CreateKeyNames(xkb), 0))
-        {
-            return ReportNotFound(action->type, field, "Key",
-                                  XkbcKeyNameText(rtrn.keyName.name));
-        }
-        act->new_key = kc;
-        return True;
-    case F_ModsToClear:
-    case F_Modifiers:
-        t1 = 0;
-        if (CheckModifierField(xkb, action->type, value, &t1, &t2))
-        {
-            act->mods_mask |= (t2 & 0xff);
-            if (field == F_Modifiers)
-                act->mods |= (t2 & 0xff);
-            else
-                act->mods &= ~(t2 & 0xff);
-
-            t2 = (t2 >> 8) & 0xffff;
-            act->vmods_mask |= t2;
-            if (field == F_Modifiers)
-                act->vmods |= t2;
-            else
-                act->vmods &= ~t2;
-            return True;
-        }
-        return True;
+        return true;
     }
-    return ReportIllegal(action->type, field);
+
+    return ReportIllegal(keymap, action->type, field);
 }
 
-static Bool
-HandleDeviceBtn(struct xkb_desc * xkb,
-                struct xkb_any_action * action,
-                unsigned field, ExprDef * array_ndx, ExprDef * value)
+static bool
+HandleSetLockControls(struct xkb_keymap *keymap, union xkb_action *action,
+                      enum action_field field, const ExprDef *array_ndx,
+                      const ExprDef *value)
 {
-    ExprResult rtrn;
-    struct xkb_device_button_action *act;
-
-    act = (struct xkb_device_button_action *) action;
-    if (field == F_Button)
-    {
-        if (array_ndx != NULL)
-            return ReportActionNotArray(action->type, field);
-        if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
-            return ReportMismatch(action->type, field,
-                                  "integer (range 1..255)");
-        if ((rtrn.ival < 0) || (rtrn.ival > 255))
-        {
-            ERROR("Button must specify default or be in the range 1..255\n");
-            ACTION("Illegal button value %d ignored\n", rtrn.ival);
-            return False;
-        }
-        act->button = rtrn.ival;
-        return True;
-    }
-    else if ((action->type == XkbSA_LockDeviceBtn) && (field == F_Affect))
-    {
-        if (array_ndx != NULL)
-            return ReportActionNotArray(action->type, field);
-        if (!ExprResolveEnum(value, &rtrn, lockWhich))
-            return ReportMismatch(action->type, field, "lock or unlock");
-        act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock);
-        act->flags |= rtrn.ival;
-        return True;
-    }
-    else if (field == F_Count)
-    {
-        if (array_ndx != NULL)
-            return ReportActionNotArray(action->type, field);
-        if (!ExprResolveInteger
-            (value, &rtrn, SimpleLookup, (char *) btnNames))
-            return ReportMismatch(action->type, field, "integer");
-        if ((rtrn.ival < 0) || (rtrn.ival > 255))
-        {
-            ERROR("The count field must have a value in the range 0..255\n");
-            ACTION("Illegal count %d ignored\n", rtrn.ival);
-            return False;
-        }
-        act->count = rtrn.ival;
-        return True;
-    }
-    else if (field == F_Device)
-    {
-        if (array_ndx != NULL)
-            return ReportActionNotArray(action->type, field);
-        if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
-            return ReportMismatch(action->type, field,
-                                  "integer (range 1..255)");
-        if ((rtrn.ival < 0) || (rtrn.ival > 255))
-        {
-            ERROR("Device must specify default or be in the range 1..255\n");
-            ACTION("Illegal device value %d ignored\n", rtrn.ival);
-            return False;
-        }
-        act->device = rtrn.ival;
-        return True;
+    struct xkb_controls_action *act = &action->ctrls;
+
+    if (field == ACTION_FIELD_CONTROLS) {
+        unsigned int mask;
+
+        if (array_ndx)
+            return ReportActionNotArray(keymap, action->type, field);
+
+        if (!ExprResolveMask(keymap->ctx, value, &mask, ctrlMaskNames))
+            return ReportMismatch(keymap, action->type, field,
+                                  "controls mask");
+
+        act->ctrls = mask;
+        return true;
     }
-    return ReportIllegal(action->type, field);
-}
 
-static Bool
-HandleDeviceValuator(struct xkb_desc * xkb,
-                     struct xkb_any_action * action,
-                     unsigned field, ExprDef * array_ndx, ExprDef * value)
-{
-#if 0
-    ExprResult rtrn;
-    struct xkb_device_valuator_action *act;
-
-    act = (struct xkb_device_valuator_action *) action;
-    /*  XXX - Not yet implemented */
-#endif
-    return False;
+    return ReportIllegal(keymap, action->type, field);
 }
 
-static Bool
-HandlePrivate(struct xkb_desc * xkb,
-              struct xkb_any_action * action,
-              unsigned field, ExprDef * array_ndx, ExprDef * value)
+static bool
+HandlePrivate(struct xkb_keymap *keymap, union xkb_action *action,
+              enum action_field field, const ExprDef *array_ndx,
+              const ExprDef *value)
 {
-    ExprResult rtrn;
-
-    switch (field)
-    {
-    case F_Type:
-        if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
-            return ReportMismatch(PrivateAction, field, "integer");
-        if ((rtrn.ival < 0) || (rtrn.ival > 255))
-        {
-            ERROR("Private action type must be in the range 0..255\n");
-            ACTION("Illegal type %d ignored\n", rtrn.ival);
-            return False;
-        }
-        action->type = rtrn.uval;
-        return True;
-    case F_Data:
-        if (array_ndx == NULL)
-        {
-            if (!ExprResolveString(value, &rtrn))
-                return ReportMismatch(action->type, field, "string");
-            else
-            {
-                int len = strlen(rtrn.str);
-                if ((len < 1) || (len > 7))
-                {
-                    WARN("A private action has 7 data bytes\n");
-                    ACTION("Extra %d bytes ignored\n", len - 6);
-                    return False;
-                }
-                strncpy((char *) action->data, rtrn.str, sizeof action->data);
+    struct xkb_private_action *act = &action->priv;
+
+    if (field == ACTION_FIELD_TYPE) {
+        int type;
+
+        if (!ExprResolveInteger(keymap->ctx, value, &type))
+            return ReportMismatch(keymap, ACTION_TYPE_PRIVATE, field, "integer");
+
+        if (type < 0 || type > 255) {
+            log_err(keymap->ctx,
+                    "Private action type must be in the range 0..255; "
+                    "Illegal type %d ignored\n", type);
+            return false;
+        }
+
+        /*
+         * It's possible for someone to write something like this:
+         *      actions = [ Private(type=3,data[0]=1,data[1]=3,data[2]=3) ]
+         * where the type refers to some existing action type, e.g. LockMods.
+         * This assumes that this action's struct is layed out in memory
+         * exactly as described in the XKB specification and libraries.
+         * We, however, have changed these structs in various ways, so this
+         * assumption is no longer true. Since this is a lousy "feature", we
+         * make actions like these no-ops for now.
+         */
+        if (type < ACTION_TYPE_PRIVATE) {
+            log_info(keymap->ctx,
+                     "Private actions of type %s are not supported; Ignored\n",
+                     ActionTypeText(type));
+            act->type = ACTION_TYPE_NONE;
+        }
+        else {
+            act->type = (enum xkb_action_type) type;
+        }
+
+        return true;
+    }
+    else if (field == ACTION_FIELD_DATA) {
+        if (array_ndx == NULL) {
+            xkb_atom_t val;
+            const char *str;
+            int len;
+
+            if (!ExprResolveString(keymap->ctx, value, &val))
+                return ReportMismatch(keymap, action->type, field, "string");
+
+            str = xkb_atom_text(keymap->ctx, val);
+            len = strlen(str);
+            if (len < 1 || len > 7) {
+                log_warn(keymap->ctx,
+                         "A private action has 7 data bytes; "
+                         "Extra %d bytes ignored\n", len - 6);
+                return false;
             }
-            free(rtrn.str);
-            return True;
+
+            strncpy((char *) act->data, str, sizeof(act->data));
+            return true;
         }
-        else
-        {
-            unsigned ndx;
-            if (!ExprResolveInteger(array_ndx, &rtrn, NULL, NULL))
-            {
-                ERROR("Array subscript must be integer\n");
-                ACTION("Illegal subscript ignored\n");
-                return False;
+        else {
+            int ndx, datum;
+
+            if (!ExprResolveInteger(keymap->ctx, array_ndx, &ndx)) {
+                log_err(keymap->ctx,
+                        "Array subscript must be integer; "
+                        "Illegal subscript ignored\n");
+                return false;
             }
-            ndx = rtrn.uval;
-            if (ndx >= sizeof action->data)
-            {
-                ERROR("The data for a private action is 18 bytes long\n");
-                ACTION("Attempt to use data[%d] ignored\n", ndx);
-                return False;
+
+            if (ndx < 0 || ndx >= sizeof(act->data)) {
+                log_err(keymap->ctx,
+                        "The data for a private action is %lu bytes long; "
+                        "Attempt to use data[%d] ignored\n",
+                        (unsigned long) sizeof(act->data), ndx);
+                return false;
             }
-            if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
-                return ReportMismatch(action->type, field, "integer");
-            if ((rtrn.ival < 0) || (rtrn.ival > 255))
-            {
-                ERROR("All data for a private action must be 0..255\n");
-                ACTION("Illegal datum %d ignored\n", rtrn.ival);
-                return False;
+
+            if (!ExprResolveInteger(keymap->ctx, value, &datum))
+                return ReportMismatch(keymap, act->type, field, "integer");
+
+            if (datum < 0 || datum > 255) {
+                log_err(keymap->ctx,
+                        "All data for a private action must be 0..255; "
+                        "Illegal datum %d ignored\n", datum);
+                return false;
             }
-            action->data[ndx] = rtrn.uval;
-            return True;
+
+            act->data[ndx] = (uint8_t) datum;
+            return true;
         }
     }
-    return ReportIllegal(PrivateAction, field);
+
+    return ReportIllegal(keymap, ACTION_TYPE_NONE, field);
 }
 
-typedef Bool(*actionHandler) (struct xkb_desc * /* xkb */ ,
-                              struct xkb_any_action * /* action */ ,
-                              unsigned /* field */ ,
-                              ExprDef * /* array_ndx */ ,
-                              ExprDef * /* value */
-    );
-
-static actionHandler handleAction[XkbSA_NumActions + 1] = {
-    HandleNoAction /* NoAction     */ ,
-    HandleSetLatchMods /* SetMods      */ ,
-    HandleSetLatchMods /* LatchMods    */ ,
-    HandleLockMods /* LockMods     */ ,
-    HandleSetLatchGroup /* SetGroup     */ ,
-    HandleSetLatchGroup /* LatchGroup   */ ,
-    HandleLockGroup /* LockGroup    */ ,
-    HandleMovePtr /* MovePtr      */ ,
-    HandlePtrBtn /* PtrBtn       */ ,
-    HandlePtrBtn /* LockPtrBtn   */ ,
-    HandleSetPtrDflt /* SetPtrDflt   */ ,
-    HandleISOLock /* ISOLock      */ ,
-    HandleNoAction /* Terminate    */ ,
-    HandleSwitchScreen /* SwitchScreen */ ,
-    HandleSetLockControls /* SetControls  */ ,
-    HandleSetLockControls /* LockControls */ ,
-    HandleActionMessage /* ActionMessage */ ,
-    HandleRedirectKey /* RedirectKey  */ ,
-    HandleDeviceBtn /* DeviceBtn    */ ,
-    HandleDeviceBtn /* LockDeviceBtn */ ,
-    HandleDeviceValuator /* DeviceValuatr */ ,
-    HandlePrivate               /* Private      */
+typedef bool (*actionHandler)(struct xkb_keymap *keymap,
+                              union xkb_action *action,
+                              enum action_field field,
+                              const ExprDef *array_ndx,
+                              const ExprDef *value);
+
+static const actionHandler handleAction[_ACTION_TYPE_NUM_ENTRIES] = {
+    [ACTION_TYPE_NONE] = HandleNoAction,
+    [ACTION_TYPE_MOD_SET] = HandleSetLatchMods,
+    [ACTION_TYPE_MOD_LATCH] = HandleSetLatchMods,
+    [ACTION_TYPE_MOD_LOCK] = HandleLockMods,
+    [ACTION_TYPE_GROUP_SET] = HandleSetLatchGroup,
+    [ACTION_TYPE_GROUP_LATCH] = HandleSetLatchGroup,
+    [ACTION_TYPE_GROUP_LOCK] = HandleLockGroup,
+    [ACTION_TYPE_PTR_MOVE] = HandleMovePtr,
+    [ACTION_TYPE_PTR_BUTTON] = HandlePtrBtn,
+    [ACTION_TYPE_PTR_LOCK] = HandlePtrBtn,
+    [ACTION_TYPE_PTR_DEFAULT] = HandleSetPtrDflt,
+    [ACTION_TYPE_TERMINATE] = HandleNoAction,
+    [ACTION_TYPE_SWITCH_VT] = HandleSwitchScreen,
+    [ACTION_TYPE_CTRL_SET] = HandleSetLockControls,
+    [ACTION_TYPE_CTRL_LOCK] = HandleSetLockControls,
+    [ACTION_TYPE_PRIVATE] = HandlePrivate,
 };
 
 /***====================================================================***/
 
-static void
-ApplyActionFactoryDefaults(union xkb_action * action)
-{
-    if (action->type == XkbSA_SetPtrDflt)
-    {                           /* increment default button */
-        action->dflt.affect = XkbSA_AffectDfltBtn;
-        action->dflt.flags = 0;
-        action->dflt.value = 1;
-    }
-    else if (action->type == XkbSA_ISOLock)
-    {
-        action->iso.real_mods = LockMask;
-    }
-    return;
-}
-
-static void
-ActionsInit(void);
-
-int
-HandleActionDef(ExprDef * def,
-                struct xkb_desc * xkb,
-                struct xkb_any_action * action, unsigned mergeMode, ActionInfo * info)
+bool
+HandleActionDef(ExprDef *def, struct xkb_keymap *keymap,
+                union xkb_action *action, ActionsInfo *info)
 {
     ExprDef *arg;
     const char *str;
-    unsigned tmp, hndlrType;
+    unsigned handler_type;
 
-    if (!actionsInitialized)
-        ActionsInit();
-
-    if (def->op != ExprActionDecl)
-    {
-        ERROR("Expected an action definition, found %s\n",
-               exprOpText(def->op));
-        return False;
-    }
-    str = XkbcAtomText(def->value.action.name);
-    if (!str)
-    {
-        WSGO("Missing name in action definition!!\n");
-        return False;
-    }
-    if (!stringToAction(str, &tmp))
-    {
-        ERROR("Unknown action %s\n", str);
-        return False;
+    if (def->op != EXPR_ACTION_DECL) {
+        log_err(keymap->ctx, "Expected an action definition, found %s\n",
+                expr_op_type_to_string(def->op));
+        return false;
     }
-    action->type = hndlrType = tmp;
-    if (action->type != XkbSA_NoAction)
-    {
-        ApplyActionFactoryDefaults((union xkb_action *) action);
-        while (info)
-        {
-            if ((info->action == XkbSA_NoAction)
-                || (info->action == hndlrType))
-            {
-                if (!(*handleAction[hndlrType]) (xkb, action,
-                                                 info->field,
-                                                 info->array_ndx,
-                                                 info->value))
-                {
-                    return False;
-                }
-            }
-            info = info->next;
-        }
+
+    str = xkb_atom_text(keymap->ctx, def->value.action.name);
+    if (!stringToAction(str, &handler_type)) {
+        log_err(keymap->ctx, "Unknown action %s\n", str);
+        return false;
     }
+
+    /*
+     * Get the default values for this action type, as modified by
+     * statements such as:
+     *     latchMods.clearLocks = True;
+     */
+    *action = info->actions[handler_type];
+
+    /*
+     * Now change the action properties as specified for this
+     * particular instance, e.g. "modifiers" and "clearLocks" in:
+     *     SetMods(modifiers=Alt,clearLocks);
+     */
     for (arg = def->value.action.args; arg != NULL;
-         arg = (ExprDef *) arg->common.next)
-    {
-        ExprDef *field, *value, *arrayRtrn;
-        ExprResult elemRtrn, fieldRtrn;
-        unsigned fieldNdx;
-
-        if (arg->op == OpAssign)
-        {
+         arg = (ExprDef *) arg->common.next) {
+        const ExprDef *value;
+        ExprDef *field, *arrayRtrn;
+        const char *elemRtrn, *fieldRtrn;
+        enum action_field fieldNdx;
+
+        if (arg->op == EXPR_ASSIGN) {
             field = arg->value.binary.left;
             value = arg->value.binary.right;
         }
-        else
-        {
-            if ((arg->op == OpNot) || (arg->op == OpInvert))
-            {
-                field = arg->value.child;
-                value = &constFalse;
-            }
-            else
-            {
-                field = arg;
-                value = &constTrue;
-            }
+        else if (arg->op == EXPR_NOT || arg->op == EXPR_INVERT) {
+            field = arg->value.child;
+            value = &constFalse;
         }
-        if (!ExprResolveLhs(field, &elemRtrn, &fieldRtrn, &arrayRtrn))
-            return False;       /* internal error -- already reported */
-
-        if (elemRtrn.str != NULL)
-        {
-            ERROR("Cannot change defaults in an action definition\n");
-            ACTION("Ignoring attempt to change %s.%s\n", elemRtrn.str,
-                    fieldRtrn.str);
-            free(elemRtrn.str);
-            free(fieldRtrn.str);
-            return False;
+        else {
+            field = arg;
+            value = &constTrue;
         }
-        if (!stringToField(fieldRtrn.str, &fieldNdx))
-        {
-            ERROR("Unknown field name %s\n", uStringText(fieldRtrn.str));
-            free(elemRtrn.str);
-            free(fieldRtrn.str);
-            return False;
+
+        if (!ExprResolveLhs(keymap->ctx, field, &elemRtrn, &fieldRtrn,
+                            &arrayRtrn))
+            return false;
+
+        if (elemRtrn) {
+            log_err(keymap->ctx,
+                    "Cannot change defaults in an action definition; "
+                    "Ignoring attempt to change %s.%s\n",
+                    elemRtrn, fieldRtrn);
+            return false;
         }
-        free(elemRtrn.str);
-        free(fieldRtrn.str);
-        if (!(*handleAction[hndlrType])
-            (xkb, action, fieldNdx, arrayRtrn, value))
-        {
-            return False;
+
+        if (!stringToField(fieldRtrn, &fieldNdx)) {
+            log_err(keymap->ctx, "Unknown field name %s\n", fieldRtrn);
+            return false;
         }
+
+        if (!handleAction[handler_type](keymap, action, fieldNdx, arrayRtrn,
+                                        value))
+            return false;
     }
-    return True;
+
+    return true;
 }
 
-/***====================================================================***/
 
-int
-SetActionField(struct xkb_desc * xkb,
-               char *elem,
-               char *field,
-               ExprDef * array_ndx, ExprDef * value, ActionInfo ** info_rtrn)
+bool
+SetActionField(struct xkb_keymap *keymap, const char *elem, const char *field,
+               ExprDef *array_ndx, ExprDef *value, ActionsInfo *info)
 {
-    ActionInfo *new, *old;
+    unsigned action;
+    enum action_field action_field;
 
-    if (!actionsInitialized)
-        ActionsInit();
+    if (!stringToAction(elem, &action))
+        return false;
 
-    new = uTypedAlloc(ActionInfo);
-    if (new == NULL)
-    {
-        WSGO("Couldn't allocate space for action default\n");
-        return False;
-    }
-    if (uStrCaseCmp(elem, "action") == 0)
-        new->action = XkbSA_NoAction;
-    else
-    {
-        if (!stringToAction(elem, &new->action))
-        {
-            free(new);
-            return False;
-        }
-        if (new->action == XkbSA_NoAction)
-        {
-            ERROR("\"%s\" is not a valid field in a NoAction action\n",
-                   field);
-            free(new);
-            return False;
-        }
-    }
-    if (!stringToField(field, &new->field))
-    {
-        ERROR("\"%s\" is not a legal field name\n", field);
-        free(new);
-        return False;
+    if (!stringToField(field, &action_field)) {
+        log_err(keymap->ctx, "\"%s\" is not a legal field name\n", field);
+        return false;
     }
-    new->array_ndx = array_ndx;
-    new->value = value;
-    new->next = NULL;
-    old = *info_rtrn;
-    while ((old) && (old->next))
-        old = old->next;
-    if (old == NULL)
-        *info_rtrn = new;
-    else
-        old->next = new;
-    return True;
-}
-
-/***====================================================================***/
 
-static void
-ActionsInit(void)
-{
-    if (!actionsInitialized)
-    {
-        bzero((char *) &constTrue, sizeof(constTrue));
-        bzero((char *) &constFalse, sizeof(constFalse));
-        constTrue.common.stmtType = StmtExpr;
-        constTrue.common.next = NULL;
-        constTrue.op = ExprIdent;
-        constTrue.type = TypeBoolean;
-        constTrue.value.str = xkb_intern_atom("true");
-        constFalse.common.stmtType = StmtExpr;
-        constFalse.common.next = NULL;
-        constFalse.op = ExprIdent;
-        constFalse.type = TypeBoolean;
-        constFalse.value.str = xkb_intern_atom("false");
-        actionsInitialized = 1;
-    }
-    return;
+    return handleAction[action](keymap, &info->actions[action],
+                                action_field, array_ndx, value);
 }