1/************************************************************ 2 Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc. 3 4 Permission to use, copy, modify, and distribute this 5 software and its documentation for any purpose and without 6 fee is hereby granted, provided that the above copyright 7 notice appear in all copies and that both that copyright 8 notice and this permission notice appear in supporting 9 documentation, and that the name of Silicon Graphics not be 10 used in advertising or publicity pertaining to distribution 11 of the software without specific prior written permission. 12 Silicon Graphics makes no representation about the suitability 13 of this software for any purpose. It is provided "as is" 14 without any express or implied warranty. 15 16 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 17 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 18 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON 19 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 20 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 21 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 22 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH 23 THE USE OR PERFORMANCE OF THIS SOFTWARE. 24 25 ********************************************************/ 26 27#include "xkbcomp.h" 28#include "tokens.h" 29#include "expr.h" 30 31#include "keycodes.h" 32#include "vmod.h" 33#include "misc.h" 34#include "action.h" 35#include "misc.h" 36 37static Bool actionsInitialized; 38static ExprDef constTrue; 39static ExprDef constFalse; 40 41static void ActionsInit(void); 42 43/***====================================================================***/ 44 45static Bool 46stringToAction(const char *str, unsigned *type_rtrn) 47{ 48 if (str == NULL) 49 return False; 50 51 if (uStrCaseCmp(str, "noaction") == 0) 52 *type_rtrn = XkbSA_NoAction; 53 else if (uStrCaseCmp(str, "setmods") == 0) 54 *type_rtrn = XkbSA_SetMods; 55 else if (uStrCaseCmp(str, "latchmods") == 0) 56 *type_rtrn = XkbSA_LatchMods; 57 else if (uStrCaseCmp(str, "lockmods") == 0) 58 *type_rtrn = XkbSA_LockMods; 59 else if (uStrCaseCmp(str, "setgroup") == 0) 60 *type_rtrn = XkbSA_SetGroup; 61 else if (uStrCaseCmp(str, "latchgroup") == 0) 62 *type_rtrn = XkbSA_LatchGroup; 63 else if (uStrCaseCmp(str, "lockgroup") == 0) 64 *type_rtrn = XkbSA_LockGroup; 65 else if (uStrCaseCmp(str, "moveptr") == 0) 66 *type_rtrn = XkbSA_MovePtr; 67 else if (uStrCaseCmp(str, "movepointer") == 0) 68 *type_rtrn = XkbSA_MovePtr; 69 else if (uStrCaseCmp(str, "ptrbtn") == 0) 70 *type_rtrn = XkbSA_PtrBtn; 71 else if (uStrCaseCmp(str, "pointerbutton") == 0) 72 *type_rtrn = XkbSA_PtrBtn; 73 else if (uStrCaseCmp(str, "lockptrbtn") == 0) 74 *type_rtrn = XkbSA_LockPtrBtn; 75 else if (uStrCaseCmp(str, "lockpointerbutton") == 0) 76 *type_rtrn = XkbSA_LockPtrBtn; 77 else if (uStrCaseCmp(str, "lockptrbutton") == 0) 78 *type_rtrn = XkbSA_LockPtrBtn; 79 else if (uStrCaseCmp(str, "lockpointerbtn") == 0) 80 *type_rtrn = XkbSA_LockPtrBtn; 81 else if (uStrCaseCmp(str, "setptrdflt") == 0) 82 *type_rtrn = XkbSA_SetPtrDflt; 83 else if (uStrCaseCmp(str, "setpointerdefault") == 0) 84 *type_rtrn = XkbSA_SetPtrDflt; 85 else if (uStrCaseCmp(str, "isolock") == 0) 86 *type_rtrn = XkbSA_ISOLock; 87 else if (uStrCaseCmp(str, "terminate") == 0) 88 *type_rtrn = XkbSA_Terminate; 89 else if (uStrCaseCmp(str, "terminateserver") == 0) 90 *type_rtrn = XkbSA_Terminate; 91 else if (uStrCaseCmp(str, "switchscreen") == 0) 92 *type_rtrn = XkbSA_SwitchScreen; 93 else if (uStrCaseCmp(str, "setcontrols") == 0) 94 *type_rtrn = XkbSA_SetControls; 95 else if (uStrCaseCmp(str, "lockcontrols") == 0) 96 *type_rtrn = XkbSA_LockControls; 97 else if (uStrCaseCmp(str, "actionmessage") == 0) 98 *type_rtrn = XkbSA_ActionMessage; 99 else if (uStrCaseCmp(str, "messageaction") == 0) 100 *type_rtrn = XkbSA_ActionMessage; 101 else if (uStrCaseCmp(str, "message") == 0) 102 *type_rtrn = XkbSA_ActionMessage; 103 else if (uStrCaseCmp(str, "redirect") == 0) 104 *type_rtrn = XkbSA_RedirectKey; 105 else if (uStrCaseCmp(str, "redirectkey") == 0) 106 *type_rtrn = XkbSA_RedirectKey; 107 else if (uStrCaseCmp(str, "devbtn") == 0) 108 *type_rtrn = XkbSA_DeviceBtn; 109 else if (uStrCaseCmp(str, "devicebtn") == 0) 110 *type_rtrn = XkbSA_DeviceBtn; 111 else if (uStrCaseCmp(str, "devbutton") == 0) 112 *type_rtrn = XkbSA_DeviceBtn; 113 else if (uStrCaseCmp(str, "devicebutton") == 0) 114 *type_rtrn = XkbSA_DeviceBtn; 115 else if (uStrCaseCmp(str, "lockdevbtn") == 0) 116 *type_rtrn = XkbSA_LockDeviceBtn; 117 else if (uStrCaseCmp(str, "lockdevicebtn") == 0) 118 *type_rtrn = XkbSA_LockDeviceBtn; 119 else if (uStrCaseCmp(str, "lockdevbutton") == 0) 120 *type_rtrn = XkbSA_LockDeviceBtn; 121 else if (uStrCaseCmp(str, "lockdevicebutton") == 0) 122 *type_rtrn = XkbSA_LockDeviceBtn; 123 else if (uStrCaseCmp(str, "devval") == 0) 124 *type_rtrn = XkbSA_DeviceValuator; 125 else if (uStrCaseCmp(str, "deviceval") == 0) 126 *type_rtrn = XkbSA_DeviceValuator; 127 else if (uStrCaseCmp(str, "devvaluator") == 0) 128 *type_rtrn = XkbSA_DeviceValuator; 129 else if (uStrCaseCmp(str, "devicevaluator") == 0) 130 *type_rtrn = XkbSA_DeviceValuator; 131 else if (uStrCaseCmp(str, "private") == 0) 132 *type_rtrn = PrivateAction; 133 else 134 return False; 135 return True; 136} 137 138static Bool 139stringToField(const char *str, unsigned *field_rtrn) 140{ 141 142 if (str == NULL) 143 return False; 144 145 if (uStrCaseCmp(str, "clearlocks") == 0) 146 *field_rtrn = F_ClearLocks; 147 else if (uStrCaseCmp(str, "latchtolock") == 0) 148 *field_rtrn = F_LatchToLock; 149 else if (uStrCaseCmp(str, "genkeyevent") == 0) 150 *field_rtrn = F_GenKeyEvent; 151 else if (uStrCaseCmp(str, "generatekeyevent") == 0) 152 *field_rtrn = F_GenKeyEvent; 153 else if (uStrCaseCmp(str, "report") == 0) 154 *field_rtrn = F_Report; 155 else if (uStrCaseCmp(str, "default") == 0) 156 *field_rtrn = F_Default; 157 else if (uStrCaseCmp(str, "affect") == 0) 158 *field_rtrn = F_Affect; 159 else if (uStrCaseCmp(str, "increment") == 0) 160 *field_rtrn = F_Increment; 161 else if (uStrCaseCmp(str, "mods") == 0) 162 *field_rtrn = F_Modifiers; 163 else if (uStrCaseCmp(str, "modifiers") == 0) 164 *field_rtrn = F_Modifiers; 165 else if (uStrCaseCmp(str, "group") == 0) 166 *field_rtrn = F_Group; 167 else if (uStrCaseCmp(str, "x") == 0) 168 *field_rtrn = F_X; 169 else if (uStrCaseCmp(str, "y") == 0) 170 *field_rtrn = F_Y; 171 else if (uStrCaseCmp(str, "accel") == 0) 172 *field_rtrn = F_Accel; 173 else if (uStrCaseCmp(str, "accelerate") == 0) 174 *field_rtrn = F_Accel; 175 else if (uStrCaseCmp(str, "repeat") == 0) 176 *field_rtrn = F_Accel; 177 else if (uStrCaseCmp(str, "button") == 0) 178 *field_rtrn = F_Button; 179 else if (uStrCaseCmp(str, "value") == 0) 180 *field_rtrn = F_Value; 181 else if (uStrCaseCmp(str, "controls") == 0) 182 *field_rtrn = F_Controls; 183 else if (uStrCaseCmp(str, "ctrls") == 0) 184 *field_rtrn = F_Controls; 185 else if (uStrCaseCmp(str, "type") == 0) 186 *field_rtrn = F_Type; 187 else if (uStrCaseCmp(str, "count") == 0) 188 *field_rtrn = F_Count; 189 else if (uStrCaseCmp(str, "screen") == 0) 190 *field_rtrn = F_Screen; 191 else if (uStrCaseCmp(str, "same") == 0) 192 *field_rtrn = F_Same; 193 else if (uStrCaseCmp(str, "sameserver") == 0) 194 *field_rtrn = F_Same; 195 else if (uStrCaseCmp(str, "data") == 0) 196 *field_rtrn = F_Data; 197 else if (uStrCaseCmp(str, "device") == 0) 198 *field_rtrn = F_Device; 199 else if (uStrCaseCmp(str, "dev") == 0) 200 *field_rtrn = F_Device; 201 else if (uStrCaseCmp(str, "key") == 0) 202 *field_rtrn = F_Keycode; 203 else if (uStrCaseCmp(str, "keycode") == 0) 204 *field_rtrn = F_Keycode; 205 else if (uStrCaseCmp(str, "kc") == 0) 206 *field_rtrn = F_Keycode; 207 else if (uStrCaseCmp(str, "clearmods") == 0) 208 *field_rtrn = F_ModsToClear; 209 else if (uStrCaseCmp(str, "clearmodifiers") == 0) 210 *field_rtrn = F_ModsToClear; 211 else 212 return False; 213 return True; 214} 215 216static char * 217fieldText(unsigned field) 218{ 219 static char buf[32]; 220 221 switch (field) 222 { 223 case F_ClearLocks: 224 strcpy(buf, "clearLocks"); 225 break; 226 case F_LatchToLock: 227 strcpy(buf, "latchToLock"); 228 break; 229 case F_GenKeyEvent: 230 strcpy(buf, "genKeyEvent"); 231 break; 232 case F_Report: 233 strcpy(buf, "report"); 234 break; 235 case F_Default: 236 strcpy(buf, "default"); 237 break; 238 case F_Affect: 239 strcpy(buf, "affect"); 240 break; 241 case F_Increment: 242 strcpy(buf, "increment"); 243 break; 244 case F_Modifiers: 245 strcpy(buf, "modifiers"); 246 break; 247 case F_Group: 248 strcpy(buf, "group"); 249 break; 250 case F_X: 251 strcpy(buf, "x"); 252 break; 253 case F_Y: 254 strcpy(buf, "y"); 255 break; 256 case F_Accel: 257 strcpy(buf, "accel"); 258 break; 259 case F_Button: 260 strcpy(buf, "button"); 261 break; 262 case F_Value: 263 strcpy(buf, "value"); 264 break; 265 case F_Controls: 266 strcpy(buf, "controls"); 267 break; 268 case F_Type: 269 strcpy(buf, "type"); 270 break; 271 case F_Count: 272 strcpy(buf, "count"); 273 break; 274 case F_Screen: 275 strcpy(buf, "screen"); 276 break; 277 case F_Same: 278 strcpy(buf, "sameServer"); 279 break; 280 case F_Data: 281 strcpy(buf, "data"); 282 break; 283 case F_Device: 284 strcpy(buf, "device"); 285 break; 286 case F_Keycode: 287 strcpy(buf, "keycode"); 288 break; 289 case F_ModsToClear: 290 strcpy(buf, "clearmods"); 291 break; 292 default: 293 strcpy(buf, "unknown"); 294 break; 295 } 296 return buf; 297} 298 299/***====================================================================***/ 300 301static Bool 302ReportMismatch(unsigned action, unsigned field, const char *type) 303{ 304 ERROR("Value of %s field must be of type %s\n", fieldText(field), type); 305 ACTION("Action %s definition ignored\n", 306 XkbActionTypeText(action, XkbMessage)); 307 return False; 308} 309 310static Bool 311ReportIllegal(unsigned action, unsigned field) 312{ 313 ERROR("Field %s is not defined for an action of type %s\n", 314 fieldText(field), XkbActionTypeText(action, XkbMessage)); 315 ACTION("Action definition ignored\n"); 316 return False; 317} 318 319static Bool 320ReportActionNotArray(unsigned action, unsigned field) 321{ 322 ERROR("The %s field in the %s action is not an array\n", 323 fieldText(field), XkbActionTypeText(action, XkbMessage)); 324 ACTION("Action definition ignored\n"); 325 return False; 326} 327 328static Bool 329ReportNotFound(unsigned action, unsigned field, const char *what, char *bad) 330{ 331 ERROR("%s named %s not found\n", what, bad); 332 ACTION("Ignoring the %s field of an %s action\n", fieldText(field), 333 XkbActionTypeText(action, XkbMessage)); 334 return False; 335} 336 337static Bool 338HandleNoAction(XkbDescPtr xkb, XkbAnyAction *action, unsigned field, 339 const ExprDef *array_ndx, const ExprDef *value) 340{ 341 return ReportIllegal(action->type, field); 342} 343 344static Bool 345CheckLatchLockFlags(unsigned action, unsigned field, 346 const ExprDef *value, unsigned *flags_inout) 347{ 348 unsigned tmp; 349 ExprResult result; 350 351 if (field == F_ClearLocks) 352 tmp = XkbSA_ClearLocks; 353 else if (field == F_LatchToLock) 354 tmp = XkbSA_LatchToLock; 355 else 356 return False; /* WSGO! */ 357 if (!ExprResolveBoolean(value, &result, NULL, NULL)) 358 return ReportMismatch(action, field, "boolean"); 359 if (result.uval) 360 *flags_inout |= tmp; 361 else 362 *flags_inout &= ~tmp; 363 return True; 364} 365 366static Bool 367CheckModifierField(XkbDescPtr xkb, unsigned action, const ExprDef *value, 368 unsigned *flags_inout, unsigned *mods_rtrn) 369{ 370 ExprResult rtrn; 371 372 if (value->op == ExprIdent) 373 { 374 char *valStr; 375 valStr = XkbAtomGetString(NULL, value->value.str); 376 if (valStr && ((uStrCaseCmp(valStr, "usemodmapmods") == 0) || 377 (uStrCaseCmp(valStr, "modmapmods") == 0))) 378 { 379 380 *mods_rtrn = 0; 381 *flags_inout |= XkbSA_UseModMapMods; 382 return True; 383 } 384 } 385 if (!ExprResolveModMask(value, &rtrn, LookupVModMask, (XPointer) xkb)) 386 return ReportMismatch(action, F_Modifiers, "modifier mask"); 387 *mods_rtrn = rtrn.uval; 388 *flags_inout &= ~XkbSA_UseModMapMods; 389 return True; 390} 391 392static Bool 393HandleSetLatchMods(XkbDescPtr xkb, XkbAnyAction *action, unsigned field, 394 const ExprDef *array_ndx, const ExprDef *value) 395{ 396 XkbModAction *act; 397 398 act = (XkbModAction *) action; 399 if (array_ndx != NULL) 400 { 401 switch (field) 402 { 403 case F_ClearLocks: 404 case F_LatchToLock: 405 case F_Modifiers: 406 return ReportActionNotArray(action->type, field); 407 } 408 } 409 switch (field) 410 { 411 case F_ClearLocks: 412 case F_LatchToLock: 413 { 414 unsigned rtrn = act->flags; 415 if (CheckLatchLockFlags(action->type, field, value, &rtrn)) 416 { 417 act->flags = rtrn; 418 return True; 419 } 420 return False; 421 } 422 case F_Modifiers: 423 { 424 unsigned t1 = act->flags, t2; 425 if (CheckModifierField(xkb, action->type, value, &t1, &t2)) 426 { 427 act->flags = t1; 428 act->real_mods = act->mask = (t2 & 0xff); 429 t2 = (t2 >> 8) & 0xffff; 430 XkbSetModActionVMods(act, t2); 431 return True; 432 } 433 return False; 434 } 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, XkbAnyAction *action, unsigned field, 449 const ExprDef *array_ndx, const ExprDef *value) 450{ 451 XkbModAction *act; 452 453 act = (XkbModAction *) action; 454 if ((array_ndx != NULL) && (field == F_Modifiers || field == F_Affect)) 455 return ReportActionNotArray(action->type, field); 456 switch (field) 457 { 458 case F_Affect: 459 { 460 ExprResult rtrn; 461 if (!ExprResolveEnum(value, &rtrn, lockWhich)) 462 return ReportMismatch(action->type, field, "lock or unlock"); 463 act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock); 464 act->flags |= rtrn.uval; 465 return True; 466 } 467 case F_Modifiers: 468 { 469 unsigned t1 = act->flags, t2; 470 if (CheckModifierField(xkb, action->type, value, &t1, &t2)) 471 { 472 act->flags = t1; 473 act->real_mods = act->mask = (t2 & 0xff); 474 t2 = (t2 >> 8) & 0xffff; 475 XkbSetModActionVMods(act, t2); 476 return True; 477 } 478 return False; 479 } 480 } 481 return ReportIllegal(action->type, field); 482} 483 484static LookupEntry groupNames[] = { 485 {"group1", 1}, 486 {"group2", 2}, 487 {"group3", 3}, 488 {"group4", 4}, 489 {"group5", 5}, 490 {"group6", 6}, 491 {"group7", 7}, 492 {"group8", 8}, 493 {NULL, 0}, 494}; 495 496static Bool 497CheckGroupField(unsigned action, const ExprDef *value, 498 unsigned *flags_inout, int *grp_rtrn) 499{ 500 const ExprDef *spec; 501 ExprResult rtrn; 502 503 if ((value->op == OpNegate) || (value->op == OpUnaryPlus)) 504 { 505 *flags_inout &= ~XkbSA_GroupAbsolute; 506 spec = value->value.child; 507 } 508 else 509 { 510 *flags_inout |= XkbSA_GroupAbsolute; 511 spec = value; 512 } 513 514 if (!ExprResolveInteger(spec, &rtrn, SimpleLookup, (XPointer) groupNames)) 515 return ReportMismatch(action, F_Group, "integer (range 1..8)"); 516 if ((rtrn.ival < 1) || (rtrn.ival > XkbNumKbdGroups)) 517 { 518 ERROR("Illegal group %d (must be in the range 1..%d)\n", rtrn.ival, 519 XkbNumKbdGroups); 520 ACTION("Action %s definition ignored\n", 521 XkbActionTypeText(action, XkbMessage)); 522 return False; 523 } 524 if (value->op == OpNegate) 525 *grp_rtrn = -rtrn.ival; 526 else if (value->op == OpUnaryPlus) 527 *grp_rtrn = rtrn.ival; 528 else 529 *grp_rtrn = rtrn.ival - 1; 530 return True; 531} 532 533static Bool 534HandleSetLatchGroup(XkbDescPtr xkb, XkbAnyAction *action, unsigned field, 535 const ExprDef *array_ndx, const ExprDef *value) 536{ 537 XkbGroupAction *act; 538 539 act = (XkbGroupAction *) action; 540 if (array_ndx != NULL) 541 { 542 switch (field) 543 { 544 case F_ClearLocks: 545 case F_LatchToLock: 546 case F_Group: 547 return ReportActionNotArray(action->type, field); 548 } 549 } 550 switch (field) 551 { 552 case F_ClearLocks: 553 case F_LatchToLock: 554 { 555 unsigned rtrn = act->flags; 556 if (CheckLatchLockFlags(action->type, field, value, &rtrn)) 557 { 558 act->flags = rtrn; 559 return True; 560 } 561 return False; 562 } 563 case F_Group: 564 { 565 unsigned t1 = act->flags; 566 int t2; 567 if (CheckGroupField(action->type, value, &t1, &t2)) 568 { 569 act->flags = t1; 570 XkbSASetGroup(act, t2); 571 return True; 572 } 573 return False; 574 } 575 } 576 return ReportIllegal(action->type, field); 577} 578 579static Bool 580HandleLockGroup(XkbDescPtr xkb, XkbAnyAction *action, unsigned field, 581 const ExprDef * array_ndx, const ExprDef *value) 582{ 583 XkbGroupAction *act; 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 unsigned t1 = act->flags; 591 int t2; 592 if (CheckGroupField(action->type, value, &t1, &t2)) 593 { 594 act->flags = t1; 595 XkbSASetGroup(act, t2); 596 return True; 597 } 598 return False; 599 } 600 return ReportIllegal(action->type, field); 601} 602 603static Bool 604HandleMovePtr(XkbDescPtr xkb, XkbAnyAction *action, unsigned field, 605 const ExprDef *array_ndx, const ExprDef *value) 606{ 607 ExprResult rtrn; 608 XkbPtrAction *act; 609 610 act = (XkbPtrAction *) action; 611 if ((array_ndx != NULL) && ((field == F_X) || (field == F_Y))) 612 return ReportActionNotArray(action->type, field); 613 614 if ((field == F_X) || (field == F_Y)) 615 { 616 Bool absolute; 617 618 if ((value->op == OpNegate) || (value->op == OpUnaryPlus)) 619 absolute = False; 620 else 621 absolute = True; 622 if (!ExprResolveInteger(value, &rtrn, NULL, NULL)) 623 return ReportMismatch(action->type, field, "integer"); 624 if (field == F_X) 625 { 626 if (absolute) 627 act->flags |= XkbSA_MoveAbsoluteX; 628 XkbSetPtrActionX(act, rtrn.ival); 629 } 630 else 631 { 632 if (absolute) 633 act->flags |= XkbSA_MoveAbsoluteY; 634 XkbSetPtrActionY(act, rtrn.ival); 635 } 636 return True; 637 } 638 else if (field == F_Accel) 639 { 640 if (!ExprResolveBoolean(value, &rtrn, NULL, NULL)) 641 return ReportMismatch(action->type, field, "boolean"); 642 if (rtrn.uval) 643 act->flags &= ~XkbSA_NoAcceleration; 644 else 645 act->flags |= XkbSA_NoAcceleration; 646 return True; 647 } 648 return ReportIllegal(action->type, field); 649} 650 651static LookupEntry btnNames[] = { 652 {"button1", 1}, 653 {"button2", 2}, 654 {"button3", 3}, 655 {"button4", 4}, 656 {"button5", 5}, 657 {"default", 0}, 658 {NULL, 0} 659}; 660 661static Bool 662HandlePtrBtn(XkbDescPtr xkb, XkbAnyAction *action, unsigned field, 663 const ExprDef *array_ndx, const 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, XkbAnyAction *action, unsigned field, 724 const ExprDef *array_ndx, const ExprDef *value) 725{ 726 ExprResult rtrn; 727 XkbPtrDfltAction *act; 728 729 act = (XkbPtrDfltAction *) action; 730 if (field == F_Affect) 731 { 732 if (array_ndx != NULL) 733 return ReportActionNotArray(action->type, field); 734 if (!ExprResolveEnum(value, &rtrn, ptrDflts)) 735 return ReportMismatch(action->type, field, "pointer component"); 736 act->affect = rtrn.uval; 737 return True; 738 } 739 else if ((field == F_Button) || (field == F_Value)) 740 { 741 const ExprDef *btn; 742 if (array_ndx != NULL) 743 return ReportActionNotArray(action->type, field); 744 if ((value->op == OpNegate) || (value->op == OpUnaryPlus)) 745 { 746 act->flags &= ~XkbSA_DfltBtnAbsolute; 747 btn = value->value.child; 748 } 749 else 750 { 751 act->flags |= XkbSA_DfltBtnAbsolute; 752 btn = value; 753 } 754 755 if (!ExprResolveInteger 756 (btn, &rtrn, SimpleLookup, (XPointer) btnNames)) 757 return ReportMismatch(action->type, field, 758 "integer (range 1..5)"); 759 if ((rtrn.ival < 0) || (rtrn.ival > 5)) 760 { 761 ERROR("New default button value must be in the range 1..5\n"); 762 ACTION("Illegal default button value %d ignored\n", rtrn.ival); 763 return False; 764 } 765 if (rtrn.ival == 0) 766 { 767 ERROR("Cannot set default pointer button to \"default\"\n"); 768 ACTION("Illegal default button setting ignored\n"); 769 return False; 770 } 771 if (value->op == OpNegate) 772 XkbSASetPtrDfltValue(act, -rtrn.ival); 773 else 774 XkbSASetPtrDfltValue(act, rtrn.ival); 775 return True; 776 } 777 return ReportIllegal(action->type, field); 778} 779 780static LookupEntry isoNames[] = { 781 {"mods", XkbSA_ISONoAffectMods}, 782 {"modifiers", XkbSA_ISONoAffectMods}, 783 {"group", XkbSA_ISONoAffectGroup}, 784 {"groups", XkbSA_ISONoAffectGroup}, 785 {"ptr", XkbSA_ISONoAffectPtr}, 786 {"pointer", XkbSA_ISONoAffectPtr}, 787 {"ctrls", XkbSA_ISONoAffectCtrls}, 788 {"controls", XkbSA_ISONoAffectCtrls}, 789 {"all", XkbSA_ISOAffectMask}, 790 {"none", 0}, 791 {"both", 0}, 792 {"lock", XkbSA_LockNoUnlock}, 793 {"neither", (XkbSA_LockNoLock | XkbSA_LockNoUnlock)}, 794 {"unlock", XkbSA_LockNoLock}, 795 {NULL, 0}, 796}; 797 798static Bool 799HandleISOLock(XkbDescPtr xkb, XkbAnyAction *action, unsigned field, 800 const ExprDef *array_ndx, const ExprDef *value) 801{ 802 ExprResult rtrn; 803 XkbISOAction *act; 804 unsigned flags; 805 806 act = (XkbISOAction *) action; 807 switch (field) 808 { 809 case F_Modifiers: 810 { 811 unsigned mods; 812 if (array_ndx != NULL) 813 return ReportActionNotArray(action->type, field); 814 flags = act->flags; 815 if (CheckModifierField(xkb, action->type, value, &flags, &mods)) 816 { 817 act->flags = flags & (~XkbSA_ISODfltIsGroup); 818 act->real_mods = act->mask = (mods & 0xff); 819 mods = (mods >> 8) & 0xffff; 820 XkbSetModActionVMods(act, mods); 821 return True; 822 } 823 return False; 824 } 825 case F_Group: 826 { 827 int group; 828 if (array_ndx != NULL) 829 return ReportActionNotArray(action->type, field); 830 flags = act->flags; 831 if (CheckGroupField(action->type, value, &flags, &group)) 832 { 833 act->flags = flags | XkbSA_ISODfltIsGroup; 834 XkbSASetGroup(act, group); 835 return True; 836 } 837 return False; 838 } 839 case F_Affect: 840 if (array_ndx != NULL) 841 return ReportActionNotArray(action->type, field); 842 if (!ExprResolveMask(value, &rtrn, SimpleLookup, (XPointer) isoNames)) 843 return ReportMismatch(action->type, field, "keyboard component"); 844 act->affect = (~rtrn.uval) & XkbSA_ISOAffectMask; 845 act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock); 846 act->flags |= rtrn.uval & (XkbSA_LockNoLock | XkbSA_LockNoUnlock); 847 return True; 848 } 849 return ReportIllegal(action->type, field); 850} 851 852static Bool 853HandleSwitchScreen(XkbDescPtr xkb, XkbAnyAction *action, unsigned field, 854 const ExprDef *array_ndx, const ExprDef *value) 855{ 856 ExprResult rtrn; 857 XkbSwitchScreenAction *act; 858 859 act = (XkbSwitchScreenAction *) action; 860 if (field == F_Screen) 861 { 862 const ExprDef *scrn; 863 if (array_ndx != NULL) 864 return ReportActionNotArray(action->type, field); 865 if ((value->op == OpNegate) || (value->op == OpUnaryPlus)) 866 { 867 act->flags &= ~XkbSA_SwitchAbsolute; 868 scrn = value->value.child; 869 } 870 else 871 { 872 act->flags |= XkbSA_SwitchAbsolute; 873 scrn = value; 874 } 875 876 if (!ExprResolveInteger(scrn, &rtrn, NULL, NULL)) 877 return ReportMismatch(action->type, field, "integer (0..255)"); 878 if ((rtrn.ival < 0) || (rtrn.ival > 255)) 879 { 880 ERROR("Screen index must be in the range 1..255\n"); 881 ACTION("Illegal screen value %d ignored\n", rtrn.ival); 882 return False; 883 } 884 if (value->op == OpNegate) 885 XkbSASetScreen(act, -rtrn.ival); 886 else 887 XkbSASetScreen(act, rtrn.ival); 888 return True; 889 } 890 else if (field == F_Same) 891 { 892 if (array_ndx != NULL) 893 return ReportActionNotArray(action->type, field); 894 if (!ExprResolveBoolean(value, &rtrn, NULL, NULL)) 895 return ReportMismatch(action->type, field, "boolean"); 896 if (rtrn.uval) 897 act->flags &= ~XkbSA_SwitchApplication; 898 else 899 act->flags |= XkbSA_SwitchApplication; 900 return True; 901 } 902 return ReportIllegal(action->type, field); 903} 904 905LookupEntry ctrlNames[] = { 906 {"repeatkeys", XkbRepeatKeysMask} 907 , 908 {"repeat", XkbRepeatKeysMask} 909 , 910 {"autorepeat", XkbRepeatKeysMask} 911 , 912 {"slowkeys", XkbSlowKeysMask} 913 , 914 {"bouncekeys", XkbBounceKeysMask} 915 , 916 {"stickykeys", XkbStickyKeysMask} 917 , 918 {"mousekeys", XkbMouseKeysMask} 919 , 920 {"mousekeysaccel", XkbMouseKeysAccelMask} 921 , 922 {"accessxkeys", XkbAccessXKeysMask} 923 , 924 {"accessxtimeout", XkbAccessXTimeoutMask} 925 , 926 {"accessxfeedback", XkbAccessXFeedbackMask} 927 , 928 {"audiblebell", XkbAudibleBellMask} 929 , 930 {"overlay1", XkbOverlay1Mask} 931 , 932 {"overlay2", XkbOverlay2Mask} 933 , 934 {"ignoregrouplock", XkbIgnoreGroupLockMask} 935 , 936 {"all", XkbAllBooleanCtrlsMask} 937 , 938 {"none", 0} 939 , 940 {NULL, 0} 941}; 942 943static Bool 944HandleSetLockControls(XkbDescPtr xkb, XkbAnyAction *action, unsigned field, 945 const ExprDef *array_ndx, const ExprDef *value) 946{ 947 ExprResult rtrn; 948 XkbCtrlsAction *act; 949 950 act = (XkbCtrlsAction *) action; 951 if (field == F_Controls) 952 { 953 if (array_ndx != NULL) 954 return ReportActionNotArray(action->type, field); 955 if (!ExprResolveMask 956 (value, &rtrn, SimpleLookup, (XPointer) ctrlNames)) 957 return ReportMismatch(action->type, field, "controls mask"); 958 XkbActionSetCtrls(act, rtrn.uval); 959 return True; 960 } 961 else if (field == F_Affect && action->type == XkbSA_LockControls) { 962 if (array_ndx != NULL) 963 return ReportActionNotArray(action->type, field); 964 if (!ExprResolveEnum(value, &rtrn, lockWhich)) 965 return ReportMismatch(action->type, field, "lock or unlock"); 966 act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock); 967 act->flags |= rtrn.uval; 968 return True; 969 } 970 return ReportIllegal(action->type, field); 971} 972 973static LookupEntry evNames[] = { 974 {"press", XkbSA_MessageOnPress}, 975 {"keypress", XkbSA_MessageOnPress}, 976 {"release", XkbSA_MessageOnRelease}, 977 {"keyrelease", XkbSA_MessageOnRelease}, 978 {"all", XkbSA_MessageOnPress | XkbSA_MessageOnRelease}, 979 {"none", 0}, 980 {NULL, 0} 981}; 982 983static Bool 984HandleActionMessage(XkbDescPtr xkb, XkbAnyAction *action, unsigned field, 985 const ExprDef *array_ndx, const 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, XkbAnyAction *action, unsigned field, 1062 const ExprDef *array_ndx, const ExprDef *value) 1063{ 1064 ExprResult rtrn; 1065 XkbRedirectKeyAction *act; 1066 1067 if (array_ndx != NULL) 1068 return ReportActionNotArray(action->type, field); 1069 1070 act = (XkbRedirectKeyAction *) action; 1071 switch (field) 1072 { 1073 case F_Keycode: 1074 { 1075 unsigned int t1; 1076 unsigned long tmp; 1077 1078 if (!ExprResolveKeyName(value, &rtrn, NULL, NULL)) 1079 return ReportMismatch(action->type, field, "key name"); 1080 tmp = KeyNameToLong(rtrn.keyName.name); 1081 if (!FindNamedKey(xkb, tmp, &t1, True, CreateKeyNames(xkb), 0)) 1082 { 1083 return ReportNotFound(action->type, field, "Key", 1084 XkbKeyNameText(rtrn.keyName.name, 1085 XkbMessage)); 1086 } 1087 act->new_key = t1; 1088 return True; 1089 } 1090 case F_ModsToClear: 1091 case F_Modifiers: 1092 { 1093 unsigned t1 = 0, t2; 1094 1095 if (CheckModifierField(xkb, action->type, value, &t1, &t2)) 1096 { 1097 unsigned vmods, vmask; 1098 1099 act->mods_mask |= (t2 & 0xff); 1100 if (field == F_Modifiers) 1101 act->mods |= (t2 & 0xff); 1102 else 1103 act->mods &= ~(t2 & 0xff); 1104 1105 t2 = (t2 >> 8) & 0xffff; 1106 vmods = XkbSARedirectVMods(act); 1107 vmask = XkbSARedirectVModsMask(act); 1108 vmask |= t2; 1109 if (field == F_Modifiers) 1110 vmods |= t2; 1111 else 1112 vmods &= ~t2; 1113 XkbSARedirectSetVMods(act, vmods); 1114 XkbSARedirectSetVModsMask(act, vmask); 1115 return True; 1116 } 1117 return True; 1118 } 1119 } 1120 return ReportIllegal(action->type, field); 1121} 1122 1123static Bool 1124HandleDeviceBtn(XkbDescPtr xkb, XkbAnyAction *action, unsigned field, 1125 const ExprDef *array_ndx, const ExprDef *value) 1126{ 1127 ExprResult rtrn; 1128 XkbDeviceBtnAction *act; 1129 1130 act = (XkbDeviceBtnAction *) action; 1131 if (field == F_Button) 1132 { 1133 if (array_ndx != NULL) 1134 return ReportActionNotArray(action->type, field); 1135 if (!ExprResolveInteger(value, &rtrn, NULL, NULL)) 1136 return ReportMismatch(action->type, field, 1137 "integer (range 1..255)"); 1138 if ((rtrn.ival < 0) || (rtrn.ival > 255)) 1139 { 1140 ERROR("Button must specify default or be in the range 1..255\n"); 1141 ACTION("Illegal button value %d ignored\n", rtrn.ival); 1142 return False; 1143 } 1144 act->button = rtrn.ival; 1145 return True; 1146 } 1147 else if ((action->type == XkbSA_LockDeviceBtn) && (field == F_Affect)) 1148 { 1149 if (array_ndx != NULL) 1150 return ReportActionNotArray(action->type, field); 1151 if (!ExprResolveEnum(value, &rtrn, lockWhich)) 1152 return ReportMismatch(action->type, field, "lock or unlock"); 1153 act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock); 1154 act->flags |= rtrn.uval; 1155 return True; 1156 } 1157 else if (field == F_Count) 1158 { 1159 if (array_ndx != NULL) 1160 return ReportActionNotArray(action->type, field); 1161 if (!ExprResolveInteger 1162 (value, &rtrn, SimpleLookup, (XPointer) btnNames)) 1163 return ReportMismatch(action->type, field, "integer"); 1164 if ((rtrn.ival < 0) || (rtrn.ival > 255)) 1165 { 1166 ERROR("The count field must have a value in the range 0..255\n"); 1167 ACTION("Illegal count %d ignored\n", rtrn.ival); 1168 return False; 1169 } 1170 act->count = rtrn.ival; 1171 return True; 1172 } 1173 else if (field == F_Device) 1174 { 1175 if (array_ndx != NULL) 1176 return ReportActionNotArray(action->type, field); 1177 if (!ExprResolveInteger(value, &rtrn, NULL, NULL)) 1178 return ReportMismatch(action->type, field, 1179 "integer (range 1..255)"); 1180 if ((rtrn.ival < 0) || (rtrn.ival > 255)) 1181 { 1182 ERROR("Device must specify default or be in the range 1..255\n"); 1183 ACTION("Illegal device value %d ignored\n", rtrn.ival); 1184 return False; 1185 } 1186 act->device = rtrn.ival; 1187 return True; 1188 } 1189 return ReportIllegal(action->type, field); 1190} 1191 1192static Bool 1193HandleDeviceValuator(XkbDescPtr xkb, XkbAnyAction *action, unsigned field, 1194 const ExprDef *array_ndx, const ExprDef *value) 1195{ 1196#if 0 1197 ExprResult rtrn; 1198 XkbDeviceValuatorAction *act; 1199 1200 act = (XkbDeviceValuatorAction *) action; 1201 /* XXX - Not yet implemented */ 1202#endif 1203 return False; 1204} 1205 1206static Bool 1207HandlePrivate(XkbDescPtr xkb, XkbAnyAction *action, unsigned field, 1208 const ExprDef *array_ndx, const ExprDef *value) 1209{ 1210 ExprResult rtrn; 1211 1212 switch (field) 1213 { 1214 case F_Type: 1215 if (!ExprResolveInteger(value, &rtrn, NULL, NULL)) 1216 return ReportMismatch(PrivateAction, field, "integer"); 1217 if ((rtrn.ival < 0) || (rtrn.ival > 255)) 1218 { 1219 ERROR("Private action type must be in the range 0..255\n"); 1220 ACTION("Illegal type %d ignored\n", rtrn.ival); 1221 return False; 1222 } 1223 action->type = rtrn.uval; 1224 return True; 1225 case F_Data: 1226 if (array_ndx == NULL) 1227 { 1228 if (!ExprResolveString(value, &rtrn, NULL, NULL)) 1229 return ReportMismatch(action->type, field, "string"); 1230 else 1231 { 1232 int len = strlen(rtrn.str); 1233 if ((len < 1) || (len > 7)) 1234 { 1235 WARN("A private action has 7 data bytes\n"); 1236 ACTION("Extra %d bytes ignored\n", len - 6); 1237 return False; 1238 } 1239 strncpy((char *) action->data, rtrn.str, 7); 1240 } 1241 return True; 1242 } 1243 else 1244 { 1245 unsigned ndx; 1246 if (!ExprResolveInteger(array_ndx, &rtrn, NULL, NULL)) 1247 { 1248 ERROR("Array subscript must be integer\n"); 1249 ACTION("Illegal subscript ignored\n"); 1250 return False; 1251 } 1252 ndx = rtrn.uval; 1253 if (ndx > 6) 1254 { 1255 ERROR("The data for a private action is 7 bytes long\n"); 1256 ACTION("Attempt to use data[%d] ignored\n", ndx); 1257 return False; 1258 } 1259 if (!ExprResolveInteger(value, &rtrn, NULL, NULL)) 1260 return ReportMismatch(action->type, field, "integer"); 1261 if ((rtrn.ival < 0) || (rtrn.ival > 255)) 1262 { 1263 ERROR("All data for a private action must be 0..255\n"); 1264 ACTION("Illegal datum %d ignored\n", rtrn.ival); 1265 return False; 1266 } 1267 action->data[ndx] = rtrn.uval; 1268 return True; 1269 } 1270 } 1271 return ReportIllegal(PrivateAction, field); 1272} 1273 1274typedef Bool(*actionHandler) (XkbDescPtr /* xkb */ , 1275 XkbAnyAction * /* action */ , 1276 unsigned /* field */ , 1277 const ExprDef * /* array_ndx */ , 1278 const ExprDef * /* value */ 1279 ); 1280 1281static actionHandler handleAction[XkbSA_NumActions + 1] = { 1282 HandleNoAction /* NoAction */ , 1283 HandleSetLatchMods /* SetMods */ , 1284 HandleSetLatchMods /* LatchMods */ , 1285 HandleLockMods /* LockMods */ , 1286 HandleSetLatchGroup /* SetGroup */ , 1287 HandleSetLatchGroup /* LatchGroup */ , 1288 HandleLockGroup /* LockGroup */ , 1289 HandleMovePtr /* MovePtr */ , 1290 HandlePtrBtn /* PtrBtn */ , 1291 HandlePtrBtn /* LockPtrBtn */ , 1292 HandleSetPtrDflt /* SetPtrDflt */ , 1293 HandleISOLock /* ISOLock */ , 1294 HandleNoAction /* Terminate */ , 1295 HandleSwitchScreen /* SwitchScreen */ , 1296 HandleSetLockControls /* SetControls */ , 1297 HandleSetLockControls /* LockControls */ , 1298 HandleActionMessage /* ActionMessage */ , 1299 HandleRedirectKey /* RedirectKey */ , 1300 HandleDeviceBtn /* DeviceBtn */ , 1301 HandleDeviceBtn /* LockDeviceBtn */ , 1302 HandleDeviceValuator /* DeviceValuatr */ , 1303 HandlePrivate /* Private */ 1304}; 1305 1306/***====================================================================***/ 1307 1308static void 1309ApplyActionFactoryDefaults(XkbAction * action) 1310{ 1311 if (action->type == XkbSA_SetPtrDflt) 1312 { /* increment default button */ 1313 action->dflt.affect = XkbSA_AffectDfltBtn; 1314 action->dflt.flags = 0; 1315 XkbSASetPtrDfltValue(&action->dflt, 1); 1316 } 1317 else if (action->type == XkbSA_ISOLock) 1318 { 1319 action->iso.real_mods = action->iso.mask = LockMask; 1320 } 1321 return; 1322} 1323 1324 1325int 1326HandleActionDef(const ExprDef *def, XkbDescPtr xkb, XkbAnyAction *action, 1327 unsigned mergeMode, const ActionInfo *info) 1328{ 1329 ExprDef *arg; 1330 const char *str; 1331 unsigned tmp, hndlrType; 1332 1333 if (!actionsInitialized) 1334 ActionsInit(); 1335 1336 if (def->op != ExprActionDecl) 1337 { 1338 ERROR("Expected an action definition, found %s\n", 1339 exprOpText(def->op)); 1340 return False; 1341 } 1342 str = XkbAtomGetString(NULL, def->value.action.name); 1343 if (!str) 1344 { 1345 WSGO("Missing name in action definition!!\n"); 1346 return False; 1347 } 1348 if (!stringToAction(str, &tmp)) 1349 { 1350 ERROR("Unknown action %s\n", str); 1351 return False; 1352 } 1353 action->type = hndlrType = tmp; 1354 if (action->type != XkbSA_NoAction) 1355 { 1356 ApplyActionFactoryDefaults((XkbAction *) action); 1357 while (info) 1358 { 1359 if ((info->action == XkbSA_NoAction) 1360 || (info->action == hndlrType)) 1361 { 1362 if (!(*handleAction[hndlrType]) (xkb, action, 1363 info->field, 1364 info->array_ndx, 1365 info->value)) 1366 { 1367 return False; 1368 } 1369 } 1370 info = info->next; 1371 } 1372 } 1373 for (arg = def->value.action.args; arg != NULL; 1374 arg = (ExprDef *) arg->common.next) 1375 { 1376 ExprDef *field, *value, *arrayRtrn; 1377 ExprResult elemRtrn, fieldRtrn; 1378 unsigned fieldNdx; 1379 1380 if (arg->op == OpAssign) 1381 { 1382 field = arg->value.binary.left; 1383 value = arg->value.binary.right; 1384 } 1385 else 1386 { 1387 if ((arg->op == OpNot) || (arg->op == OpInvert)) 1388 { 1389 field = arg->value.child; 1390 value = &constFalse; 1391 } 1392 else 1393 { 1394 field = arg; 1395 value = &constTrue; 1396 } 1397 } 1398 if (!ExprResolveLhs(field, &elemRtrn, &fieldRtrn, &arrayRtrn)) 1399 return False; /* internal error -- already reported */ 1400 1401 if (elemRtrn.str != NULL) 1402 { 1403 ERROR("Cannot change defaults in an action definition\n"); 1404 ACTION("Ignoring attempt to change %s.%s\n", elemRtrn.str, 1405 fieldRtrn.str); 1406 return False; 1407 } 1408 if (!stringToField(fieldRtrn.str, &fieldNdx)) 1409 { 1410 ERROR("Unknown field name %s\n", uStringText(fieldRtrn.str)); 1411 return False; 1412 } 1413 if (!(*handleAction[hndlrType]) 1414 (xkb, action, fieldNdx, arrayRtrn, value)) 1415 { 1416 return False; 1417 } 1418 } 1419 return True; 1420} 1421 1422/***====================================================================***/ 1423 1424int 1425SetActionField(XkbDescPtr xkb, const char *elem, const char *field, 1426 ExprDef *array_ndx, ExprDef *value, ActionInfo **info_rtrn) 1427{ 1428 ActionInfo *new, *old; 1429 1430 if (!actionsInitialized) 1431 ActionsInit(); 1432 1433 new = malloc(sizeof(ActionInfo)); 1434 if (new == NULL) 1435 { 1436 WSGO("Couldn't allocate space for action default\n"); 1437 return False; 1438 } 1439 if (uStrCaseCmp(elem, "action") == 0) 1440 new->action = XkbSA_NoAction; 1441 else 1442 { 1443 if (!stringToAction(elem, &new->action)) 1444 return False; 1445 if (new->action == XkbSA_NoAction) 1446 { 1447 ERROR("\"%s\" is not a valid field in a NoAction action\n", 1448 field); 1449 return False; 1450 } 1451 } 1452 if (!stringToField(field, &new->field)) 1453 { 1454 ERROR("\"%s\" is not a legal field name\n", field); 1455 return False; 1456 } 1457 new->array_ndx = array_ndx; 1458 new->value = value; 1459 new->next = NULL; 1460 old = *info_rtrn; 1461 while ((old) && (old->next)) 1462 old = old->next; 1463 if (old == NULL) 1464 *info_rtrn = new; 1465 else 1466 old->next = new; 1467 return True; 1468} 1469 1470/***====================================================================***/ 1471 1472static void 1473ActionsInit(void) 1474{ 1475 if (!actionsInitialized) 1476 { 1477 bzero(&constTrue, sizeof(constTrue)); 1478 constTrue = (ExprDef) { 1479 .common.stmtType = StmtExpr, 1480 .common.next = NULL, 1481 .op = ExprIdent, 1482 .type = TypeBoolean, 1483 .value.str = XkbInternAtom(NULL, "true", False) 1484 }; 1485 bzero(&constFalse, sizeof(constFalse)); 1486 constFalse = (ExprDef) { 1487 .common.stmtType = StmtExpr, 1488 .common.next = NULL, 1489 .op = ExprIdent, 1490 .type = TypeBoolean, 1491 .value.str = XkbInternAtom(NULL, "false", False) 1492 }; 1493 actionsInitialized = 1; 1494 } 1495 return; 1496} 1497