action.c revision bfe6082c
11.11Sskrll/************************************************************
21.4Schristos Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
31.1Schristos
41.1Schristos Permission to use, copy, modify, and distribute this
51.1Schristos software and its documentation for any purpose and without
61.1Schristos fee is hereby granted, provided that the above copyright
71.1Schristos notice appear in all copies and that both that copyright
81.1Schristos notice and this permission notice appear in supporting
91.1Schristos documentation, and that the name of Silicon Graphics not be
101.1Schristos used in advertising or publicity pertaining to distribution
111.1Schristos of the software without specific prior written permission.
121.1Schristos Silicon Graphics makes no representation about the suitability
131.1Schristos of this software for any purpose. It is provided "as is"
141.1Schristos without any express or implied warranty.
151.1Schristos
161.1Schristos SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
171.1Schristos SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
181.1Schristos AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
191.1Schristos GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
201.1Schristos DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
211.1Schristos DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
221.1Schristos OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
231.1Schristos THE USE OR PERFORMANCE OF THIS SOFTWARE.
241.1Schristos
251.1Schristos ********************************************************/
261.1Schristos
271.1Schristos#include "xkbcomp.h"
281.1Schristos#include "tokens.h"
291.1Schristos#include "expr.h"
301.1Schristos
311.1Schristos#include "keycodes.h"
321.1Schristos#include "vmod.h"
331.1Schristos#include "misc.h"
341.1Schristos#include "action.h"
351.1Schristos#include "misc.h"
361.1Schristos
371.1Schristosstatic Bool actionsInitialized;
381.5Schristosstatic ExprDef constTrue;
391.5Schristosstatic ExprDef constFalse;
401.5Schristos
411.5Schristos/***====================================================================***/
421.11Sskrll
431.5Schristosstatic Bool
441.5SchristosstringToAction(const char *str, unsigned *type_rtrn)
451.11Sskrll{
461.5Schristos    if (str == NULL)
471.5Schristos        return False;
481.5Schristos
491.11Sskrll    if (uStrCaseCmp(str, "noaction") == 0)
501.11Sskrll        *type_rtrn = XkbSA_NoAction;
511.5Schristos    else if (uStrCaseCmp(str, "setmods") == 0)
521.5Schristos        *type_rtrn = XkbSA_SetMods;
531.5Schristos    else if (uStrCaseCmp(str, "latchmods") == 0)
541.5Schristos        *type_rtrn = XkbSA_LatchMods;
551.5Schristos    else if (uStrCaseCmp(str, "lockmods") == 0)
561.1Schristos        *type_rtrn = XkbSA_LockMods;
571.1Schristos    else if (uStrCaseCmp(str, "setgroup") == 0)
581.1Schristos        *type_rtrn = XkbSA_SetGroup;
591.1Schristos    else if (uStrCaseCmp(str, "latchgroup") == 0)
601.1Schristos        *type_rtrn = XkbSA_LatchGroup;
611.3Schristos    else if (uStrCaseCmp(str, "lockgroup") == 0)
621.3Schristos        *type_rtrn = XkbSA_LockGroup;
631.3Schristos    else if (uStrCaseCmp(str, "moveptr") == 0)
641.3Schristos        *type_rtrn = XkbSA_MovePtr;
651.1Schristos    else if (uStrCaseCmp(str, "movepointer") == 0)
661.1Schristos        *type_rtrn = XkbSA_MovePtr;
671.1Schristos    else if (uStrCaseCmp(str, "ptrbtn") == 0)
681.1Schristos        *type_rtrn = XkbSA_PtrBtn;
691.1Schristos    else if (uStrCaseCmp(str, "pointerbutton") == 0)
701.1Schristos        *type_rtrn = XkbSA_PtrBtn;
711.1Schristos    else if (uStrCaseCmp(str, "lockptrbtn") == 0)
721.1Schristos        *type_rtrn = XkbSA_LockPtrBtn;
731.1Schristos    else if (uStrCaseCmp(str, "lockpointerbutton") == 0)
741.1Schristos        *type_rtrn = XkbSA_LockPtrBtn;
751.1Schristos    else if (uStrCaseCmp(str, "lockptrbutton") == 0)
761.1Schristos        *type_rtrn = XkbSA_LockPtrBtn;
771.1Schristos    else if (uStrCaseCmp(str, "lockpointerbtn") == 0)
781.1Schristos        *type_rtrn = XkbSA_LockPtrBtn;
791.1Schristos    else if (uStrCaseCmp(str, "setptrdflt") == 0)
801.1Schristos        *type_rtrn = XkbSA_SetPtrDflt;
811.1Schristos    else if (uStrCaseCmp(str, "setpointerdefault") == 0)
821.1Schristos        *type_rtrn = XkbSA_SetPtrDflt;
831.1Schristos    else if (uStrCaseCmp(str, "isolock") == 0)
841.1Schristos        *type_rtrn = XkbSA_ISOLock;
851.1Schristos    else if (uStrCaseCmp(str, "terminate") == 0)
861.1Schristos        *type_rtrn = XkbSA_Terminate;
871.1Schristos    else if (uStrCaseCmp(str, "terminateserver") == 0)
881.1Schristos        *type_rtrn = XkbSA_Terminate;
891.1Schristos    else if (uStrCaseCmp(str, "switchscreen") == 0)
901.1Schristos        *type_rtrn = XkbSA_SwitchScreen;
911.1Schristos    else if (uStrCaseCmp(str, "setcontrols") == 0)
921.1Schristos        *type_rtrn = XkbSA_SetControls;
931.1Schristos    else if (uStrCaseCmp(str, "lockcontrols") == 0)
941.1Schristos        *type_rtrn = XkbSA_LockControls;
951.1Schristos    else if (uStrCaseCmp(str, "actionmessage") == 0)
961.1Schristos        *type_rtrn = XkbSA_ActionMessage;
971.1Schristos    else if (uStrCaseCmp(str, "messageaction") == 0)
981.1Schristos        *type_rtrn = XkbSA_ActionMessage;
991.1Schristos    else if (uStrCaseCmp(str, "message") == 0)
1001.1Schristos        *type_rtrn = XkbSA_ActionMessage;
1011.1Schristos    else if (uStrCaseCmp(str, "redirect") == 0)
1021.1Schristos        *type_rtrn = XkbSA_RedirectKey;
1031.1Schristos    else if (uStrCaseCmp(str, "redirectkey") == 0)
1041.1Schristos        *type_rtrn = XkbSA_RedirectKey;
1051.1Schristos    else if (uStrCaseCmp(str, "devbtn") == 0)
1061.1Schristos        *type_rtrn = XkbSA_DeviceBtn;
1071.1Schristos    else if (uStrCaseCmp(str, "devicebtn") == 0)
1081.1Schristos        *type_rtrn = XkbSA_DeviceBtn;
1091.1Schristos    else if (uStrCaseCmp(str, "devbutton") == 0)
1101.1Schristos        *type_rtrn = XkbSA_DeviceBtn;
1111.1Schristos    else if (uStrCaseCmp(str, "devicebutton") == 0)
1121.1Schristos        *type_rtrn = XkbSA_DeviceBtn;
1131.1Schristos    else if (uStrCaseCmp(str, "lockdevbtn") == 0)
1141.1Schristos        *type_rtrn = XkbSA_LockDeviceBtn;
1151.1Schristos    else if (uStrCaseCmp(str, "lockdevicebtn") == 0)
1161.1Schristos        *type_rtrn = XkbSA_LockDeviceBtn;
1171.1Schristos    else if (uStrCaseCmp(str, "lockdevbutton") == 0)
1181.1Schristos        *type_rtrn = XkbSA_LockDeviceBtn;
1191.1Schristos    else if (uStrCaseCmp(str, "lockdevicebutton") == 0)
1201.1Schristos        *type_rtrn = XkbSA_LockDeviceBtn;
1211.1Schristos    else if (uStrCaseCmp(str, "devval") == 0)
1221.1Schristos        *type_rtrn = XkbSA_DeviceValuator;
1231.1Schristos    else if (uStrCaseCmp(str, "deviceval") == 0)
1241.1Schristos        *type_rtrn = XkbSA_DeviceValuator;
1251.1Schristos    else if (uStrCaseCmp(str, "devvaluator") == 0)
1261.6Schristos        *type_rtrn = XkbSA_DeviceValuator;
1271.6Schristos    else if (uStrCaseCmp(str, "devicevaluator") == 0)
1281.9Smrg        *type_rtrn = XkbSA_DeviceValuator;
1291.9Smrg    else if (uStrCaseCmp(str, "private") == 0)
1301.9Smrg        *type_rtrn = PrivateAction;
1311.9Smrg    else
1321.9Smrg        return False;
1331.9Smrg    return True;
1341.10Swiz}
1351.10Swiz
1361.1Schristosstatic Bool
1371.3SchristosstringToField(const char *str, unsigned *field_rtrn)
1381.8Schristos{
1391.1Schristos
1401.1Schristos    if (str == NULL)
1411.5Schristos        return False;
142
143    if (uStrCaseCmp(str, "clearlocks") == 0)
144        *field_rtrn = F_ClearLocks;
145    else if (uStrCaseCmp(str, "latchtolock") == 0)
146        *field_rtrn = F_LatchToLock;
147    else if (uStrCaseCmp(str, "genkeyevent") == 0)
148        *field_rtrn = F_GenKeyEvent;
149    else if (uStrCaseCmp(str, "generatekeyevent") == 0)
150        *field_rtrn = F_GenKeyEvent;
151    else if (uStrCaseCmp(str, "report") == 0)
152        *field_rtrn = F_Report;
153    else if (uStrCaseCmp(str, "default") == 0)
154        *field_rtrn = F_Default;
155    else if (uStrCaseCmp(str, "affect") == 0)
156        *field_rtrn = F_Affect;
157    else if (uStrCaseCmp(str, "increment") == 0)
158        *field_rtrn = F_Increment;
159    else if (uStrCaseCmp(str, "mods") == 0)
160        *field_rtrn = F_Modifiers;
161    else if (uStrCaseCmp(str, "modifiers") == 0)
162        *field_rtrn = F_Modifiers;
163    else if (uStrCaseCmp(str, "group") == 0)
164        *field_rtrn = F_Group;
165    else if (uStrCaseCmp(str, "x") == 0)
166        *field_rtrn = F_X;
167    else if (uStrCaseCmp(str, "y") == 0)
168        *field_rtrn = F_Y;
169    else if (uStrCaseCmp(str, "accel") == 0)
170        *field_rtrn = F_Accel;
171    else if (uStrCaseCmp(str, "accelerate") == 0)
172        *field_rtrn = F_Accel;
173    else if (uStrCaseCmp(str, "repeat") == 0)
174        *field_rtrn = F_Accel;
175    else if (uStrCaseCmp(str, "button") == 0)
176        *field_rtrn = F_Button;
177    else if (uStrCaseCmp(str, "value") == 0)
178        *field_rtrn = F_Value;
179    else if (uStrCaseCmp(str, "controls") == 0)
180        *field_rtrn = F_Controls;
181    else if (uStrCaseCmp(str, "ctrls") == 0)
182        *field_rtrn = F_Controls;
183    else if (uStrCaseCmp(str, "type") == 0)
184        *field_rtrn = F_Type;
185    else if (uStrCaseCmp(str, "count") == 0)
186        *field_rtrn = F_Count;
187    else if (uStrCaseCmp(str, "screen") == 0)
188        *field_rtrn = F_Screen;
189    else if (uStrCaseCmp(str, "same") == 0)
190        *field_rtrn = F_Same;
191    else if (uStrCaseCmp(str, "sameserver") == 0)
192        *field_rtrn = F_Same;
193    else if (uStrCaseCmp(str, "data") == 0)
194        *field_rtrn = F_Data;
195    else if (uStrCaseCmp(str, "device") == 0)
196        *field_rtrn = F_Device;
197    else if (uStrCaseCmp(str, "dev") == 0)
198        *field_rtrn = F_Device;
199    else if (uStrCaseCmp(str, "key") == 0)
200        *field_rtrn = F_Keycode;
201    else if (uStrCaseCmp(str, "keycode") == 0)
202        *field_rtrn = F_Keycode;
203    else if (uStrCaseCmp(str, "kc") == 0)
204        *field_rtrn = F_Keycode;
205    else if (uStrCaseCmp(str, "clearmods") == 0)
206        *field_rtrn = F_ModsToClear;
207    else if (uStrCaseCmp(str, "clearmodifiers") == 0)
208        *field_rtrn = F_ModsToClear;
209    else
210        return False;
211    return True;
212}
213
214static char *
215fieldText(unsigned field)
216{
217    static char buf[32];
218
219    switch (field)
220    {
221    case F_ClearLocks:
222        strcpy(buf, "clearLocks");
223        break;
224    case F_LatchToLock:
225        strcpy(buf, "latchToLock");
226        break;
227    case F_GenKeyEvent:
228        strcpy(buf, "genKeyEvent");
229        break;
230    case F_Report:
231        strcpy(buf, "report");
232        break;
233    case F_Default:
234        strcpy(buf, "default");
235        break;
236    case F_Affect:
237        strcpy(buf, "affect");
238        break;
239    case F_Increment:
240        strcpy(buf, "increment");
241        break;
242    case F_Modifiers:
243        strcpy(buf, "modifiers");
244        break;
245    case F_Group:
246        strcpy(buf, "group");
247        break;
248    case F_X:
249        strcpy(buf, "x");
250        break;
251    case F_Y:
252        strcpy(buf, "y");
253        break;
254    case F_Accel:
255        strcpy(buf, "accel");
256        break;
257    case F_Button:
258        strcpy(buf, "button");
259        break;
260    case F_Value:
261        strcpy(buf, "value");
262        break;
263    case F_Controls:
264        strcpy(buf, "controls");
265        break;
266    case F_Type:
267        strcpy(buf, "type");
268        break;
269    case F_Count:
270        strcpy(buf, "count");
271        break;
272    case F_Screen:
273        strcpy(buf, "screen");
274        break;
275    case F_Same:
276        strcpy(buf, "sameServer");
277        break;
278    case F_Data:
279        strcpy(buf, "data");
280        break;
281    case F_Device:
282        strcpy(buf, "device");
283        break;
284    case F_Keycode:
285        strcpy(buf, "keycode");
286        break;
287    case F_ModsToClear:
288        strcpy(buf, "clearmods");
289        break;
290    default:
291        strcpy(buf, "unknown");
292        break;
293    }
294    return buf;
295}
296
297/***====================================================================***/
298
299static Bool
300ReportMismatch(unsigned action, unsigned field, const char *type)
301{
302    ERROR("Value of %s field must be of type %s\n", fieldText(field), type);
303    ACTION("Action %s definition ignored\n",
304            XkbActionTypeText(action, XkbMessage));
305    return False;
306}
307
308static Bool
309ReportIllegal(unsigned action, unsigned field)
310{
311    ERROR("Field %s is not defined for an action of type %s\n",
312           fieldText(field), XkbActionTypeText(action, XkbMessage));
313    ACTION("Action definition ignored\n");
314    return False;
315}
316
317static Bool
318ReportActionNotArray(unsigned action, unsigned field)
319{
320    ERROR("The %s field in the %s action is not an array\n",
321           fieldText(field), XkbActionTypeText(action, XkbMessage));
322    ACTION("Action definition ignored\n");
323    return False;
324}
325
326static Bool
327ReportNotFound(unsigned action, unsigned field, const char *what, char *bad)
328{
329    ERROR("%s named %s not found\n", what, bad);
330    ACTION("Ignoring the %s field of an %s action\n", fieldText(field),
331            XkbActionTypeText(action, XkbMessage));
332    return False;
333}
334
335static Bool
336HandleNoAction(XkbDescPtr xkb,
337               XkbAnyAction * action,
338               unsigned field, ExprDef * array_ndx, ExprDef * value)
339{
340    return ReportIllegal(action->type, field);
341}
342
343static Bool
344CheckLatchLockFlags(unsigned action,
345                    unsigned field, ExprDef * value, unsigned *flags_inout)
346{
347    unsigned tmp;
348    ExprResult result;
349
350    if (field == F_ClearLocks)
351        tmp = XkbSA_ClearLocks;
352    else if (field == F_LatchToLock)
353        tmp = XkbSA_LatchToLock;
354    else
355        return False;           /* WSGO! */
356    if (!ExprResolveBoolean(value, &result, NULL, NULL))
357        return ReportMismatch(action, field, "boolean");
358    if (result.uval)
359        *flags_inout |= tmp;
360    else
361        *flags_inout &= ~tmp;
362    return True;
363}
364
365static Bool
366CheckModifierField(XkbDescPtr xkb,
367                   unsigned action,
368                   ExprDef * value,
369                   unsigned *flags_inout, unsigned *mods_rtrn)
370{
371    ExprResult rtrn;
372
373    if (value->op == ExprIdent)
374    {
375        register char *valStr;
376        valStr = XkbAtomGetString(NULL, value->value.str);
377        if (valStr && ((uStrCaseCmp(valStr, "usemodmapmods") == 0) ||
378                       (uStrCaseCmp(valStr, "modmapmods") == 0)))
379        {
380
381            *mods_rtrn = 0;
382            *flags_inout |= XkbSA_UseModMapMods;
383            return True;
384        }
385    }
386    if (!ExprResolveModMask(value, &rtrn, LookupVModMask, (XPointer) xkb))
387        return ReportMismatch(action, F_Modifiers, "modifier mask");
388    *mods_rtrn = rtrn.uval;
389    *flags_inout &= ~XkbSA_UseModMapMods;
390    return True;
391}
392
393static Bool
394HandleSetLatchMods(XkbDescPtr xkb,
395                   XkbAnyAction * action,
396                   unsigned field, ExprDef * array_ndx, ExprDef * value)
397{
398    XkbModAction *act;
399    unsigned rtrn;
400    unsigned t1, t2;
401
402    act = (XkbModAction *) action;
403    if (array_ndx != NULL)
404    {
405        switch (field)
406        {
407        case F_ClearLocks:
408        case F_LatchToLock:
409        case F_Modifiers:
410            return ReportActionNotArray(action->type, field);
411        }
412    }
413    switch (field)
414    {
415    case F_ClearLocks:
416    case F_LatchToLock:
417        rtrn = act->flags;
418        if (CheckLatchLockFlags(action->type, field, value, &rtrn))
419        {
420            act->flags = rtrn;
421            return True;
422        }
423        return False;
424    case F_Modifiers:
425        t1 = act->flags;
426        if (CheckModifierField(xkb, action->type, value, &t1, &t2))
427        {
428            act->flags = t1;
429            act->real_mods = act->mask = (t2 & 0xff);
430            t2 = (t2 >> 8) & 0xffff;
431            XkbSetModActionVMods(act, t2);
432            return True;
433        }
434        return False;
435    }
436    return ReportIllegal(action->type, field);
437}
438
439static LookupEntry lockWhich[] = {
440    {"both", 0},
441    {"lock", XkbSA_LockNoUnlock},
442    {"neither", (XkbSA_LockNoLock | XkbSA_LockNoUnlock)},
443    {"unlock", XkbSA_LockNoLock},
444    {NULL, 0}
445};
446
447static Bool
448HandleLockMods(XkbDescPtr xkb,
449               XkbAnyAction * action,
450               unsigned field, ExprDef * array_ndx, ExprDef * value)
451{
452    XkbModAction *act;
453    unsigned t1, t2;
454    ExprResult rtrn;
455
456    act = (XkbModAction *) action;
457    if ((array_ndx != NULL) && (field == F_Modifiers || field == F_Affect))
458        return ReportActionNotArray(action->type, field);
459    switch (field)
460    {
461    case F_Affect:
462        if (!ExprResolveEnum(value, &rtrn, lockWhich))
463            return ReportMismatch(action->type, field, "lock or unlock");
464        act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock);
465        act->flags |= rtrn.uval;
466        return True;
467    case F_Modifiers:
468        t1 = act->flags;
469        if (CheckModifierField(xkb, action->type, value, &t1, &t2))
470        {
471            act->flags = t1;
472            act->real_mods = act->mask = (t2 & 0xff);
473            t2 = (t2 >> 8) & 0xffff;
474            XkbSetModActionVMods(act, t2);
475            return True;
476        }
477        return False;
478    }
479    return ReportIllegal(action->type, field);
480}
481
482static LookupEntry groupNames[] = {
483    {"group1", 1},
484    {"group2", 2},
485    {"group3", 3},
486    {"group4", 4},
487    {"group5", 5},
488    {"group6", 6},
489    {"group7", 7},
490    {"group8", 8},
491    {NULL, 0},
492};
493
494static Bool
495CheckGroupField(unsigned action,
496                ExprDef * value, unsigned *flags_inout, int *grp_rtrn)
497{
498    ExprDef *spec;
499    ExprResult rtrn;
500
501    if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
502    {
503        *flags_inout &= ~XkbSA_GroupAbsolute;
504        spec = value->value.child;
505    }
506    else
507    {
508        *flags_inout |= XkbSA_GroupAbsolute;
509        spec = value;
510    }
511
512    if (!ExprResolveInteger(spec, &rtrn, SimpleLookup, (XPointer) groupNames))
513        return ReportMismatch(action, F_Group, "integer (range 1..8)");
514    if ((rtrn.ival < 1) || (rtrn.ival > XkbNumKbdGroups))
515    {
516        ERROR("Illegal group %d (must be in the range 1..%d)\n", rtrn.ival,
517               XkbNumKbdGroups);
518        ACTION("Action %s definition ignored\n",
519                XkbActionTypeText(action, XkbMessage));
520        return False;
521    }
522    if (value->op == OpNegate)
523        *grp_rtrn = -rtrn.ival;
524    else if (value->op == OpUnaryPlus)
525        *grp_rtrn = rtrn.ival;
526    else
527        *grp_rtrn = rtrn.ival - 1;
528    return True;
529}
530
531static Bool
532HandleSetLatchGroup(XkbDescPtr xkb,
533                    XkbAnyAction * action,
534                    unsigned field, ExprDef * array_ndx, ExprDef * value)
535{
536    XkbGroupAction *act;
537    unsigned rtrn;
538    unsigned t1;
539    int t2;
540
541    act = (XkbGroupAction *) action;
542    if (array_ndx != NULL)
543    {
544        switch (field)
545        {
546        case F_ClearLocks:
547        case F_LatchToLock:
548        case F_Group:
549            return ReportActionNotArray(action->type, field);
550        }
551    }
552    switch (field)
553    {
554    case F_ClearLocks:
555    case F_LatchToLock:
556        rtrn = act->flags;
557        if (CheckLatchLockFlags(action->type, field, value, &rtrn))
558        {
559            act->flags = rtrn;
560            return True;
561        }
562        return False;
563    case F_Group:
564        t1 = act->flags;
565        if (CheckGroupField(action->type, value, &t1, &t2))
566        {
567            act->flags = t1;
568            XkbSASetGroup(act, t2);
569            return True;
570        }
571        return False;
572    }
573    return ReportIllegal(action->type, field);
574}
575
576static Bool
577HandleLockGroup(XkbDescPtr xkb,
578                XkbAnyAction * action,
579                unsigned field, ExprDef * array_ndx, ExprDef * value)
580{
581    XkbGroupAction *act;
582    unsigned t1;
583    int t2;
584
585    act = (XkbGroupAction *) action;
586    if ((array_ndx != NULL) && (field == F_Group))
587        return ReportActionNotArray(action->type, field);
588    if (field == F_Group)
589    {
590        t1 = act->flags;
591        if (CheckGroupField(action->type, value, &t1, &t2))
592        {
593            act->flags = t1;
594            XkbSASetGroup(act, t2);
595            return True;
596        }
597        return False;
598    }
599    return ReportIllegal(action->type, field);
600}
601
602static Bool
603HandleMovePtr(XkbDescPtr xkb,
604              XkbAnyAction * action,
605              unsigned field, ExprDef * array_ndx, ExprDef * value)
606{
607    ExprResult rtrn;
608    XkbPtrAction *act;
609    Bool absolute;
610
611    act = (XkbPtrAction *) action;
612    if ((array_ndx != NULL) && ((field == F_X) || (field == F_Y)))
613        return ReportActionNotArray(action->type, field);
614
615    if ((field == F_X) || (field == F_Y))
616    {
617        if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
618            absolute = False;
619        else
620            absolute = True;
621        if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
622            return ReportMismatch(action->type, field, "integer");
623        if (field == F_X)
624        {
625            if (absolute)
626                act->flags |= XkbSA_MoveAbsoluteX;
627            XkbSetPtrActionX(act, rtrn.ival);
628        }
629        else
630        {
631            if (absolute)
632                act->flags |= XkbSA_MoveAbsoluteY;
633            XkbSetPtrActionY(act, rtrn.ival);
634        }
635        return True;
636    }
637    else if (field == F_Accel)
638    {
639        if (!ExprResolveBoolean(value, &rtrn, NULL, NULL))
640            return ReportMismatch(action->type, field, "boolean");
641        if (rtrn.uval)
642            act->flags &= ~XkbSA_NoAcceleration;
643        else
644            act->flags |= XkbSA_NoAcceleration;
645        return True;
646    }
647    return ReportIllegal(action->type, field);
648}
649
650static LookupEntry btnNames[] = {
651    {"button1", 1},
652    {"button2", 2},
653    {"button3", 3},
654    {"button4", 4},
655    {"button5", 5},
656    {"default", 0},
657    {NULL, 0}
658};
659
660static Bool
661HandlePtrBtn(XkbDescPtr xkb,
662             XkbAnyAction * action,
663             unsigned field, ExprDef * array_ndx, ExprDef * value)
664{
665    ExprResult rtrn;
666    XkbPtrBtnAction *act;
667
668    act = (XkbPtrBtnAction *) action;
669    if (field == F_Button)
670    {
671        if (array_ndx != NULL)
672            return ReportActionNotArray(action->type, field);
673        if (!ExprResolveInteger
674            (value, &rtrn, SimpleLookup, (XPointer) btnNames))
675            return ReportMismatch(action->type, field,
676                                  "integer (range 1..5)");
677        if ((rtrn.ival < 0) || (rtrn.ival > 5))
678        {
679            ERROR("Button must specify default or be in the range 1..5\n");
680            ACTION("Illegal button value %d ignored\n", rtrn.ival);
681            return False;
682        }
683        act->button = rtrn.ival;
684        return True;
685    }
686    else if ((action->type == XkbSA_LockPtrBtn) && (field == F_Affect))
687    {
688        if (array_ndx != NULL)
689            return ReportActionNotArray(action->type, field);
690        if (!ExprResolveEnum(value, &rtrn, lockWhich))
691            return ReportMismatch(action->type, field, "lock or unlock");
692        act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock);
693        act->flags |= rtrn.uval;
694        return True;
695    }
696    else if (field == F_Count)
697    {
698        if (array_ndx != NULL)
699            return ReportActionNotArray(action->type, field);
700        if (!ExprResolveInteger
701            (value, &rtrn, SimpleLookup, (XPointer) btnNames))
702            return ReportMismatch(action->type, field, "integer");
703        if ((rtrn.ival < 0) || (rtrn.ival > 255))
704        {
705            ERROR("The count field must have a value in the range 0..255\n");
706            ACTION("Illegal count %d ignored\n", rtrn.ival);
707            return False;
708        }
709        act->count = rtrn.ival;
710        return True;
711    }
712    return ReportIllegal(action->type, field);
713}
714
715static LookupEntry ptrDflts[] = {
716    {"dfltbtn", XkbSA_AffectDfltBtn},
717    {"defaultbutton", XkbSA_AffectDfltBtn},
718    {"button", XkbSA_AffectDfltBtn},
719    {NULL, 0}
720};
721
722static Bool
723HandleSetPtrDflt(XkbDescPtr xkb,
724                 XkbAnyAction * action,
725                 unsigned field, ExprDef * array_ndx, ExprDef * value)
726{
727    ExprResult rtrn;
728    XkbPtrDfltAction *act;
729
730    act = (XkbPtrDfltAction *) action;
731    if (field == F_Affect)
732    {
733        if (array_ndx != NULL)
734            return ReportActionNotArray(action->type, field);
735        if (!ExprResolveEnum(value, &rtrn, ptrDflts))
736            return ReportMismatch(action->type, field, "pointer component");
737        act->affect = rtrn.uval;
738        return True;
739    }
740    else if ((field == F_Button) || (field == F_Value))
741    {
742        ExprDef *btn;
743        if (array_ndx != NULL)
744            return ReportActionNotArray(action->type, field);
745        if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
746        {
747            act->flags &= ~XkbSA_DfltBtnAbsolute;
748            btn = value->value.child;
749        }
750        else
751        {
752            act->flags |= XkbSA_DfltBtnAbsolute;
753            btn = value;
754        }
755
756        if (!ExprResolveInteger
757            (btn, &rtrn, SimpleLookup, (XPointer) btnNames))
758            return ReportMismatch(action->type, field,
759                                  "integer (range 1..5)");
760        if ((rtrn.ival < 0) || (rtrn.ival > 5))
761        {
762            ERROR("New default button value must be in the range 1..5\n");
763            ACTION("Illegal default button value %d ignored\n", rtrn.ival);
764            return False;
765        }
766        if (rtrn.ival == 0)
767        {
768            ERROR("Cannot set default pointer button to \"default\"\n");
769            ACTION("Illegal default button setting ignored\n");
770            return False;
771        }
772        if (value->op == OpNegate)
773            XkbSASetPtrDfltValue(act, -rtrn.ival);
774        else
775            XkbSASetPtrDfltValue(act, rtrn.ival);
776        return True;
777    }
778    return ReportIllegal(action->type, field);
779}
780
781static LookupEntry isoNames[] = {
782    {"mods", XkbSA_ISONoAffectMods},
783    {"modifiers", XkbSA_ISONoAffectMods},
784    {"group", XkbSA_ISONoAffectGroup},
785    {"groups", XkbSA_ISONoAffectGroup},
786    {"ptr", XkbSA_ISONoAffectPtr},
787    {"pointer", XkbSA_ISONoAffectPtr},
788    {"ctrls", XkbSA_ISONoAffectCtrls},
789    {"controls", XkbSA_ISONoAffectCtrls},
790    {"all", XkbSA_ISOAffectMask},
791    {"none", 0},
792    {"both", 0},
793    {"lock", XkbSA_LockNoUnlock},
794    {"neither", (XkbSA_LockNoLock | XkbSA_LockNoUnlock)},
795    {"unlock", XkbSA_LockNoLock},
796    {NULL, 0},
797};
798
799static Bool
800HandleISOLock(XkbDescPtr xkb,
801              XkbAnyAction * action,
802              unsigned field, ExprDef * array_ndx, ExprDef * value)
803{
804    ExprResult rtrn;
805    XkbISOAction *act;
806    unsigned flags, mods;
807    int group;
808
809    act = (XkbISOAction *) action;
810    switch (field)
811    {
812    case F_Modifiers:
813        if (array_ndx != NULL)
814            return ReportActionNotArray(action->type, field);
815        flags = act->flags;
816        if (CheckModifierField(xkb, action->type, value, &flags, &mods))
817        {
818            act->flags = flags & (~XkbSA_ISODfltIsGroup);
819            act->real_mods = act->mask = (mods & 0xff);
820            mods = (mods >> 8) & 0xffff;
821            XkbSetModActionVMods(act, mods);
822            return True;
823        }
824        return False;
825    case F_Group:
826        if (array_ndx != NULL)
827            return ReportActionNotArray(action->type, field);
828        flags = act->flags;
829        if (CheckGroupField(action->type, value, &flags, &group))
830        {
831            act->flags = flags | XkbSA_ISODfltIsGroup;
832            XkbSASetGroup(act, group);
833            return True;
834        }
835        return False;
836    case F_Affect:
837        if (array_ndx != NULL)
838            return ReportActionNotArray(action->type, field);
839        if (!ExprResolveMask(value, &rtrn, SimpleLookup, (XPointer) isoNames))
840            return ReportMismatch(action->type, field, "keyboard component");
841        act->affect = (~rtrn.uval) & XkbSA_ISOAffectMask;
842        act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock);
843        act->flags |= rtrn.uval & (XkbSA_LockNoLock | XkbSA_LockNoUnlock);
844        return True;
845    }
846    return ReportIllegal(action->type, field);
847}
848
849static Bool
850HandleSwitchScreen(XkbDescPtr xkb,
851                   XkbAnyAction * action,
852                   unsigned field, ExprDef * array_ndx, ExprDef * value)
853{
854    ExprResult rtrn;
855    XkbSwitchScreenAction *act;
856
857    act = (XkbSwitchScreenAction *) action;
858    if (field == F_Screen)
859    {
860        ExprDef *scrn;
861        if (array_ndx != NULL)
862            return ReportActionNotArray(action->type, field);
863        if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
864        {
865            act->flags &= ~XkbSA_SwitchAbsolute;
866            scrn = value->value.child;
867        }
868        else
869        {
870            act->flags |= XkbSA_SwitchAbsolute;
871            scrn = value;
872        }
873
874        if (!ExprResolveInteger(scrn, &rtrn, NULL, NULL))
875            return ReportMismatch(action->type, field, "integer (0..255)");
876        if ((rtrn.ival < 0) || (rtrn.ival > 255))
877        {
878            ERROR("Screen index must be in the range 1..255\n");
879            ACTION("Illegal screen value %d ignored\n", rtrn.ival);
880            return False;
881        }
882        if (value->op == OpNegate)
883            XkbSASetScreen(act, -rtrn.ival);
884        else
885            XkbSASetScreen(act, rtrn.ival);
886        return True;
887    }
888    else if (field == F_Same)
889    {
890        if (array_ndx != NULL)
891            return ReportActionNotArray(action->type, field);
892        if (!ExprResolveBoolean(value, &rtrn, NULL, NULL))
893            return ReportMismatch(action->type, field, "boolean");
894        if (rtrn.uval)
895            act->flags &= ~XkbSA_SwitchApplication;
896        else
897            act->flags |= XkbSA_SwitchApplication;
898        return True;
899    }
900    return ReportIllegal(action->type, field);
901}
902
903LookupEntry ctrlNames[] = {
904    {"repeatkeys", XkbRepeatKeysMask}
905    ,
906    {"repeat", XkbRepeatKeysMask}
907    ,
908    {"autorepeat", XkbRepeatKeysMask}
909    ,
910    {"slowkeys", XkbSlowKeysMask}
911    ,
912    {"bouncekeys", XkbBounceKeysMask}
913    ,
914    {"stickykeys", XkbStickyKeysMask}
915    ,
916    {"mousekeys", XkbMouseKeysMask}
917    ,
918    {"mousekeysaccel", XkbMouseKeysAccelMask}
919    ,
920    {"accessxkeys", XkbAccessXKeysMask}
921    ,
922    {"accessxtimeout", XkbAccessXTimeoutMask}
923    ,
924    {"accessxfeedback", XkbAccessXFeedbackMask}
925    ,
926    {"audiblebell", XkbAudibleBellMask}
927    ,
928    {"overlay1", XkbOverlay1Mask}
929    ,
930    {"overlay2", XkbOverlay2Mask}
931    ,
932    {"ignoregrouplock", XkbIgnoreGroupLockMask}
933    ,
934    {"all", XkbAllBooleanCtrlsMask}
935    ,
936    {"none", 0}
937    ,
938    {NULL, 0}
939};
940
941static Bool
942HandleSetLockControls(XkbDescPtr xkb,
943                      XkbAnyAction * action,
944                      unsigned field, ExprDef * array_ndx, ExprDef * value)
945{
946    ExprResult rtrn;
947    XkbCtrlsAction *act;
948
949    act = (XkbCtrlsAction *) action;
950    if (field == F_Controls)
951    {
952        if (array_ndx != NULL)
953            return ReportActionNotArray(action->type, field);
954        if (!ExprResolveMask
955            (value, &rtrn, SimpleLookup, (XPointer) ctrlNames))
956            return ReportMismatch(action->type, field, "controls mask");
957        XkbActionSetCtrls(act, rtrn.uval);
958        return True;
959    }
960    else if (field == F_Affect && action->type == XkbSA_LockControls) {
961        if (array_ndx != NULL)
962            return ReportActionNotArray(action->type, field);
963        if (!ExprResolveEnum(value, &rtrn, lockWhich))
964            return ReportMismatch(action->type, field, "lock or unlock");
965        act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock);
966        act->flags |= rtrn.uval;
967        return True;
968    }
969    return ReportIllegal(action->type, field);
970}
971
972static LookupEntry evNames[] = {
973    {"press", XkbSA_MessageOnPress},
974    {"keypress", XkbSA_MessageOnPress},
975    {"release", XkbSA_MessageOnRelease},
976    {"keyrelease", XkbSA_MessageOnRelease},
977    {"all", XkbSA_MessageOnPress | XkbSA_MessageOnRelease},
978    {"none", 0},
979    {NULL, 0}
980};
981
982static Bool
983HandleActionMessage(XkbDescPtr xkb,
984                    XkbAnyAction * action,
985                    unsigned field, ExprDef * array_ndx, ExprDef * value)
986{
987    ExprResult rtrn;
988    XkbMessageAction *act;
989
990    act = (XkbMessageAction *) action;
991    switch (field)
992    {
993    case F_Report:
994        if (array_ndx != NULL)
995            return ReportActionNotArray(action->type, field);
996        if (!ExprResolveMask(value, &rtrn, SimpleLookup, (XPointer) evNames))
997            return ReportMismatch(action->type, field, "key event mask");
998        act->flags &= ~(XkbSA_MessageOnPress | XkbSA_MessageOnRelease);
999        act->flags =
1000            rtrn.uval & (XkbSA_MessageOnPress | XkbSA_MessageOnRelease);
1001        return True;
1002    case F_GenKeyEvent:
1003        if (array_ndx != NULL)
1004            return ReportActionNotArray(action->type, field);
1005        if (!ExprResolveBoolean(value, &rtrn, NULL, NULL))
1006            return ReportMismatch(action->type, field, "boolean");
1007        if (rtrn.uval)
1008            act->flags |= XkbSA_MessageGenKeyEvent;
1009        else
1010            act->flags &= ~XkbSA_MessageGenKeyEvent;
1011        return True;
1012    case F_Data:
1013        if (array_ndx == NULL)
1014        {
1015            if (!ExprResolveString(value, &rtrn, NULL, NULL))
1016                return ReportMismatch(action->type, field, "string");
1017            else
1018            {
1019                int len = strlen(rtrn.str);
1020                if ((len < 1) || (len > 6))
1021                {
1022                    WARN("An action message can hold only 6 bytes\n");
1023                    ACTION("Extra %d bytes ignored\n", len - 6);
1024                }
1025                strncpy((char *) act->message, rtrn.str, 6);
1026            }
1027            return True;
1028        }
1029        else
1030        {
1031            unsigned ndx;
1032            if (!ExprResolveInteger(array_ndx, &rtrn, NULL, NULL))
1033            {
1034                ERROR("Array subscript must be integer\n");
1035                ACTION("Illegal subscript ignored\n");
1036                return False;
1037            }
1038            ndx = rtrn.uval;
1039            if (ndx > 5)
1040            {
1041                ERROR("An action message is at most 6 bytes long\n");
1042                ACTION("Attempt to use data[%d] ignored\n", ndx);
1043                return False;
1044            }
1045            if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1046                return ReportMismatch(action->type, field, "integer");
1047            if ((rtrn.ival < 0) || (rtrn.ival > 255))
1048            {
1049                ERROR("Message data must be in the range 0..255\n");
1050                ACTION("Illegal datum %d ignored\n", rtrn.ival);
1051                return False;
1052            }
1053            act->message[ndx] = rtrn.uval;
1054        }
1055        return True;
1056    }
1057    return ReportIllegal(action->type, field);
1058}
1059
1060static Bool
1061HandleRedirectKey(XkbDescPtr xkb,
1062                  XkbAnyAction * action,
1063                  unsigned field, ExprDef * array_ndx, ExprDef * value)
1064{
1065    ExprResult rtrn;
1066    XkbRedirectKeyAction *act;
1067    unsigned t1, t2, vmods, vmask;
1068    unsigned long tmp;
1069
1070    if (array_ndx != NULL)
1071        return ReportActionNotArray(action->type, field);
1072
1073    act = (XkbRedirectKeyAction *) action;
1074    switch (field)
1075    {
1076    case F_Keycode:
1077        if (!ExprResolveKeyName(value, &rtrn, NULL, NULL))
1078            return ReportMismatch(action->type, field, "key name");
1079        tmp = KeyNameToLong(rtrn.keyName.name);
1080        if (!FindNamedKey(xkb, tmp, &t1, True, CreateKeyNames(xkb), 0))
1081        {
1082            return ReportNotFound(action->type, field, "Key",
1083                                  XkbKeyNameText(rtrn.keyName.name,
1084                                                 XkbMessage));
1085        }
1086        act->new_key = t1;
1087        return True;
1088    case F_ModsToClear:
1089    case F_Modifiers:
1090        t1 = 0;
1091        if (CheckModifierField(xkb, action->type, value, &t1, &t2))
1092        {
1093            act->mods_mask |= (t2 & 0xff);
1094            if (field == F_Modifiers)
1095                act->mods |= (t2 & 0xff);
1096            else
1097                act->mods &= ~(t2 & 0xff);
1098
1099            t2 = (t2 >> 8) & 0xffff;
1100            vmods = XkbSARedirectVMods(act);
1101            vmask = XkbSARedirectVModsMask(act);
1102            vmask |= t2;
1103            if (field == F_Modifiers)
1104                vmods |= t2;
1105            else
1106                vmods &= ~t2;
1107            XkbSARedirectSetVMods(act, vmods);
1108            XkbSARedirectSetVModsMask(act, vmask);
1109            return True;
1110        }
1111        return True;
1112    }
1113    return ReportIllegal(action->type, field);
1114}
1115
1116static Bool
1117HandleDeviceBtn(XkbDescPtr xkb,
1118                XkbAnyAction * action,
1119                unsigned field, ExprDef * array_ndx, ExprDef * value)
1120{
1121    ExprResult rtrn;
1122    XkbDeviceBtnAction *act;
1123
1124    act = (XkbDeviceBtnAction *) action;
1125    if (field == F_Button)
1126    {
1127        if (array_ndx != NULL)
1128            return ReportActionNotArray(action->type, field);
1129        if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1130            return ReportMismatch(action->type, field,
1131                                  "integer (range 1..255)");
1132        if ((rtrn.ival < 0) || (rtrn.ival > 255))
1133        {
1134            ERROR("Button must specify default or be in the range 1..255\n");
1135            ACTION("Illegal button value %d ignored\n", rtrn.ival);
1136            return False;
1137        }
1138        act->button = rtrn.ival;
1139        return True;
1140    }
1141    else if ((action->type == XkbSA_LockDeviceBtn) && (field == F_Affect))
1142    {
1143        if (array_ndx != NULL)
1144            return ReportActionNotArray(action->type, field);
1145        if (!ExprResolveEnum(value, &rtrn, lockWhich))
1146            return ReportMismatch(action->type, field, "lock or unlock");
1147        act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock);
1148        act->flags |= rtrn.uval;
1149        return True;
1150    }
1151    else if (field == F_Count)
1152    {
1153        if (array_ndx != NULL)
1154            return ReportActionNotArray(action->type, field);
1155        if (!ExprResolveInteger
1156            (value, &rtrn, SimpleLookup, (XPointer) btnNames))
1157            return ReportMismatch(action->type, field, "integer");
1158        if ((rtrn.ival < 0) || (rtrn.ival > 255))
1159        {
1160            ERROR("The count field must have a value in the range 0..255\n");
1161            ACTION("Illegal count %d ignored\n", rtrn.ival);
1162            return False;
1163        }
1164        act->count = rtrn.ival;
1165        return True;
1166    }
1167    else if (field == F_Device)
1168    {
1169        if (array_ndx != NULL)
1170            return ReportActionNotArray(action->type, field);
1171        if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1172            return ReportMismatch(action->type, field,
1173                                  "integer (range 1..255)");
1174        if ((rtrn.ival < 0) || (rtrn.ival > 255))
1175        {
1176            ERROR("Device must specify default or be in the range 1..255\n");
1177            ACTION("Illegal device value %d ignored\n", rtrn.ival);
1178            return False;
1179        }
1180        act->device = rtrn.ival;
1181        return True;
1182    }
1183    return ReportIllegal(action->type, field);
1184}
1185
1186static Bool
1187HandleDeviceValuator(XkbDescPtr xkb,
1188                     XkbAnyAction * action,
1189                     unsigned field, ExprDef * array_ndx, ExprDef * value)
1190{
1191#if 0
1192    ExprResult rtrn;
1193    XkbDeviceValuatorAction *act;
1194
1195    act = (XkbDeviceValuatorAction *) action;
1196    /*  XXX - Not yet implemented */
1197#endif
1198    return False;
1199}
1200
1201static Bool
1202HandlePrivate(XkbDescPtr xkb,
1203              XkbAnyAction * action,
1204              unsigned field, ExprDef * array_ndx, ExprDef * value)
1205{
1206    ExprResult rtrn;
1207
1208    switch (field)
1209    {
1210    case F_Type:
1211        if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1212            return ReportMismatch(PrivateAction, field, "integer");
1213        if ((rtrn.ival < 0) || (rtrn.ival > 255))
1214        {
1215            ERROR("Private action type must be in the range 0..255\n");
1216            ACTION("Illegal type %d ignored\n", rtrn.ival);
1217            return False;
1218        }
1219        action->type = rtrn.uval;
1220        return True;
1221    case F_Data:
1222        if (array_ndx == NULL)
1223        {
1224            if (!ExprResolveString(value, &rtrn, NULL, NULL))
1225                return ReportMismatch(action->type, field, "string");
1226            else
1227            {
1228                int len = strlen(rtrn.str);
1229                if ((len < 1) || (len > 7))
1230                {
1231                    WARN("A private action has 7 data bytes\n");
1232                    ACTION("Extra %d bytes ignored\n", len - 6);
1233                    return False;
1234                }
1235                strncpy((char *) action->data, rtrn.str, 7);
1236            }
1237            return True;
1238        }
1239        else
1240        {
1241            unsigned ndx;
1242            if (!ExprResolveInteger(array_ndx, &rtrn, NULL, NULL))
1243            {
1244                ERROR("Array subscript must be integer\n");
1245                ACTION("Illegal subscript ignored\n");
1246                return False;
1247            }
1248            ndx = rtrn.uval;
1249            if (ndx > 6)
1250            {
1251                ERROR("The data for a private action is 7 bytes long\n");
1252                ACTION("Attempt to use data[%d] ignored\n", ndx);
1253                return False;
1254            }
1255            if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
1256                return ReportMismatch(action->type, field, "integer");
1257            if ((rtrn.ival < 0) || (rtrn.ival > 255))
1258            {
1259                ERROR("All data for a private action must be 0..255\n");
1260                ACTION("Illegal datum %d ignored\n", rtrn.ival);
1261                return False;
1262            }
1263            action->data[ndx] = rtrn.uval;
1264            return True;
1265        }
1266    }
1267    return ReportIllegal(PrivateAction, field);
1268}
1269
1270typedef Bool(*actionHandler) (XkbDescPtr /* xkb */ ,
1271                              XkbAnyAction * /* action */ ,
1272                              unsigned /* field */ ,
1273                              ExprDef * /* array_ndx */ ,
1274                              ExprDef * /* value */
1275    );
1276
1277static actionHandler handleAction[XkbSA_NumActions + 1] = {
1278    HandleNoAction /* NoAction     */ ,
1279    HandleSetLatchMods /* SetMods      */ ,
1280    HandleSetLatchMods /* LatchMods    */ ,
1281    HandleLockMods /* LockMods     */ ,
1282    HandleSetLatchGroup /* SetGroup     */ ,
1283    HandleSetLatchGroup /* LatchGroup   */ ,
1284    HandleLockGroup /* LockGroup    */ ,
1285    HandleMovePtr /* MovePtr      */ ,
1286    HandlePtrBtn /* PtrBtn       */ ,
1287    HandlePtrBtn /* LockPtrBtn   */ ,
1288    HandleSetPtrDflt /* SetPtrDflt   */ ,
1289    HandleISOLock /* ISOLock      */ ,
1290    HandleNoAction /* Terminate    */ ,
1291    HandleSwitchScreen /* SwitchScreen */ ,
1292    HandleSetLockControls /* SetControls  */ ,
1293    HandleSetLockControls /* LockControls */ ,
1294    HandleActionMessage /* ActionMessage */ ,
1295    HandleRedirectKey /* RedirectKey  */ ,
1296    HandleDeviceBtn /* DeviceBtn    */ ,
1297    HandleDeviceBtn /* LockDeviceBtn */ ,
1298    HandleDeviceValuator /* DeviceValuatr */ ,
1299    HandlePrivate               /* Private      */
1300};
1301
1302/***====================================================================***/
1303
1304static void
1305ApplyActionFactoryDefaults(XkbAction * action)
1306{
1307    if (action->type == XkbSA_SetPtrDflt)
1308    {                           /* increment default button */
1309        action->dflt.affect = XkbSA_AffectDfltBtn;
1310        action->dflt.flags = 0;
1311        XkbSASetPtrDfltValue(&action->dflt, 1);
1312    }
1313    else if (action->type == XkbSA_ISOLock)
1314    {
1315        action->iso.real_mods = action->iso.mask = LockMask;
1316    }
1317    return;
1318}
1319
1320
1321int
1322HandleActionDef(ExprDef * def,
1323                XkbDescPtr xkb,
1324                XkbAnyAction * action, unsigned mergeMode, ActionInfo * info)
1325{
1326    ExprDef *arg;
1327    register char *str;
1328    unsigned tmp, hndlrType;
1329
1330    if (!actionsInitialized)
1331        ActionsInit();
1332
1333    if (def->op != ExprActionDecl)
1334    {
1335        ERROR("Expected an action definition, found %s\n",
1336               exprOpText(def->op));
1337        return False;
1338    }
1339    str = XkbAtomGetString(NULL, def->value.action.name);
1340    if (!str)
1341    {
1342        WSGO("Missing name in action definition!!\n");
1343        return False;
1344    }
1345    if (!stringToAction(str, &tmp))
1346    {
1347        ERROR("Unknown action %s\n", str);
1348        return False;
1349    }
1350    action->type = hndlrType = tmp;
1351    if (action->type != XkbSA_NoAction)
1352    {
1353        ApplyActionFactoryDefaults((XkbAction *) action);
1354        while (info)
1355        {
1356            if ((info->action == XkbSA_NoAction)
1357                || (info->action == hndlrType))
1358            {
1359                if (!(*handleAction[hndlrType]) (xkb, action,
1360                                                 info->field,
1361                                                 info->array_ndx,
1362                                                 info->value))
1363                {
1364                    return False;
1365                }
1366            }
1367            info = info->next;
1368        }
1369    }
1370    for (arg = def->value.action.args; arg != NULL;
1371         arg = (ExprDef *) arg->common.next)
1372    {
1373        ExprDef *field, *value, *arrayRtrn;
1374        ExprResult elemRtrn, fieldRtrn;
1375        unsigned fieldNdx;
1376
1377        if (arg->op == OpAssign)
1378        {
1379            field = arg->value.binary.left;
1380            value = arg->value.binary.right;
1381        }
1382        else
1383        {
1384            if ((arg->op == OpNot) || (arg->op == OpInvert))
1385            {
1386                field = arg->value.child;
1387                value = &constFalse;
1388            }
1389            else
1390            {
1391                field = arg;
1392                value = &constTrue;
1393            }
1394        }
1395        if (!ExprResolveLhs(field, &elemRtrn, &fieldRtrn, &arrayRtrn))
1396            return False;       /* internal error -- already reported */
1397
1398        if (elemRtrn.str != NULL)
1399        {
1400            ERROR("Cannot change defaults in an action definition\n");
1401            ACTION("Ignoring attempt to change %s.%s\n", elemRtrn.str,
1402                    fieldRtrn.str);
1403            return False;
1404        }
1405        if (!stringToField(fieldRtrn.str, &fieldNdx))
1406        {
1407            ERROR("Unknown field name %s\n", uStringText(fieldRtrn.str));
1408            return False;
1409        }
1410        if (!(*handleAction[hndlrType])
1411            (xkb, action, fieldNdx, arrayRtrn, value))
1412        {
1413            return False;
1414        }
1415    }
1416    return True;
1417}
1418
1419/***====================================================================***/
1420
1421int
1422SetActionField(XkbDescPtr xkb,
1423               const char *elem,
1424               const char *field,
1425               ExprDef * array_ndx, ExprDef * value, ActionInfo ** info_rtrn)
1426{
1427    ActionInfo *new, *old;
1428
1429    if (!actionsInitialized)
1430        ActionsInit();
1431
1432    new = uTypedAlloc(ActionInfo);
1433    if (new == NULL)
1434    {
1435        WSGO("Couldn't allocate space for action default\n");
1436        return False;
1437    }
1438    if (uStrCaseCmp(elem, "action") == 0)
1439        new->action = XkbSA_NoAction;
1440    else
1441    {
1442        if (!stringToAction(elem, &new->action))
1443            return False;
1444        if (new->action == XkbSA_NoAction)
1445        {
1446            ERROR("\"%s\" is not a valid field in a NoAction action\n",
1447                   field);
1448            return False;
1449        }
1450    }
1451    if (!stringToField(field, &new->field))
1452    {
1453        ERROR("\"%s\" is not a legal field name\n", field);
1454        return False;
1455    }
1456    new->array_ndx = array_ndx;
1457    new->value = value;
1458    new->next = NULL;
1459    old = *info_rtrn;
1460    while ((old) && (old->next))
1461        old = old->next;
1462    if (old == NULL)
1463        *info_rtrn = new;
1464    else
1465        old->next = new;
1466    return True;
1467}
1468
1469/***====================================================================***/
1470
1471void
1472ActionsInit(void)
1473{
1474    if (!actionsInitialized)
1475    {
1476        bzero((char *) &constTrue, sizeof(constTrue));
1477        bzero((char *) &constFalse, sizeof(constFalse));
1478        constTrue.common.stmtType = StmtExpr;
1479        constTrue.common.next = NULL;
1480        constTrue.op = ExprIdent;
1481        constTrue.type = TypeBoolean;
1482        constTrue.value.str = XkbInternAtom(NULL, "true", False);
1483        constFalse.common.stmtType = StmtExpr;
1484        constFalse.common.next = NULL;
1485        constFalse.op = ExprIdent;
1486        constFalse.type = TypeBoolean;
1487        constFalse.value.str = XkbInternAtom(NULL, "false", False);
1488        actionsInitialized = 1;
1489    }
1490    return;
1491}
1492