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 /* 28 * Copyright 2012 Intel Corporation 29 * Copyright 2012 Ran Benita <ran234 (at) gmail.com> 30 * 31 * Permission is hereby granted, free of charge, to any person obtaining a 32 * copy of this software and associated documentation files (the "Software"), 33 * to deal in the Software without restriction, including without limitation 34 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 35 * and/or sell copies of the Software, and to permit persons to whom the 36 * Software is furnished to do so, subject to the following conditions: 37 * 38 * The above copyright notice and this permission notice (including the next 39 * paragraph) shall be included in all copies or substantial portions of the 40 * Software. 41 * 42 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 43 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 44 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 45 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 46 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 47 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 48 * DEALINGS IN THE SOFTWARE. 49 * 50 * Author: Daniel Stone <daniel (at) fooishbar.org> 51 * Ran Benita <ran234 (at) gmail.com> 52 */ 53 54 #include "xkbcomp-priv.h" 55 #include "text.h" 56 #include "expr.h" 57 #include "action.h" 58 59 static const ExprBoolean constTrue = { 60 .expr = { 61 .common = { .type = STMT_EXPR, .next = NULL }, 62 .op = EXPR_VALUE, 63 .value_type = EXPR_TYPE_BOOLEAN, 64 }, 65 .set = true, 66 }; 67 68 static const ExprBoolean constFalse = { 69 .expr = { 70 .common = { .type = STMT_EXPR, .next = NULL }, 71 .op = EXPR_VALUE, 72 .value_type = EXPR_TYPE_BOOLEAN, 73 }, 74 .set = false, 75 }; 76 77 enum action_field { 78 ACTION_FIELD_CLEAR_LOCKS, 79 ACTION_FIELD_LATCH_TO_LOCK, 80 ACTION_FIELD_GEN_KEY_EVENT, 81 ACTION_FIELD_REPORT, 82 ACTION_FIELD_DEFAULT, 83 ACTION_FIELD_AFFECT, 84 ACTION_FIELD_INCREMENT, 85 ACTION_FIELD_MODIFIERS, 86 ACTION_FIELD_GROUP, 87 ACTION_FIELD_X, 88 ACTION_FIELD_Y, 89 ACTION_FIELD_ACCEL, 90 ACTION_FIELD_BUTTON, 91 ACTION_FIELD_VALUE, 92 ACTION_FIELD_CONTROLS, 93 ACTION_FIELD_TYPE, 94 ACTION_FIELD_COUNT, 95 ACTION_FIELD_SCREEN, 96 ACTION_FIELD_SAME, 97 ACTION_FIELD_DATA, 98 ACTION_FIELD_DEVICE, 99 ACTION_FIELD_KEYCODE, 100 ACTION_FIELD_MODS_TO_CLEAR, 101 }; 102 103 ActionsInfo * 104 NewActionsInfo(void) 105 { 106 enum xkb_action_type type; 107 ActionsInfo *info; 108 109 info = calloc(1, sizeof(*info)); 110 if (!info) 111 return NULL; 112 113 for (type = 0; type < _ACTION_TYPE_NUM_ENTRIES; type++) 114 info->actions[type].type = type; 115 116 /* Apply some "factory defaults". */ 117 118 /* Increment default button. */ 119 info->actions[ACTION_TYPE_PTR_DEFAULT].dflt.flags = 0; 120 info->actions[ACTION_TYPE_PTR_DEFAULT].dflt.value = 1; 121 info->actions[ACTION_TYPE_PTR_MOVE].ptr.flags = ACTION_ACCEL; 122 info->actions[ACTION_TYPE_SWITCH_VT].screen.flags = ACTION_SAME_SCREEN; 123 124 return info; 125 } 126 127 void 128 FreeActionsInfo(ActionsInfo *info) 129 { 130 free(info); 131 } 132 133 static const LookupEntry fieldStrings[] = { 134 { "clearLocks", ACTION_FIELD_CLEAR_LOCKS }, 135 { "latchToLock", ACTION_FIELD_LATCH_TO_LOCK }, 136 { "genKeyEvent", ACTION_FIELD_GEN_KEY_EVENT }, 137 { "generateKeyEvent", ACTION_FIELD_GEN_KEY_EVENT }, 138 { "report", ACTION_FIELD_REPORT }, 139 { "default", ACTION_FIELD_DEFAULT }, 140 { "affect", ACTION_FIELD_AFFECT }, 141 { "increment", ACTION_FIELD_INCREMENT }, 142 { "modifiers", ACTION_FIELD_MODIFIERS }, 143 { "mods", ACTION_FIELD_MODIFIERS }, 144 { "group", ACTION_FIELD_GROUP }, 145 { "x", ACTION_FIELD_X }, 146 { "y", ACTION_FIELD_Y }, 147 { "accel", ACTION_FIELD_ACCEL }, 148 { "accelerate", ACTION_FIELD_ACCEL }, 149 { "repeat", ACTION_FIELD_ACCEL }, 150 { "button", ACTION_FIELD_BUTTON }, 151 { "value", ACTION_FIELD_VALUE }, 152 { "controls", ACTION_FIELD_CONTROLS }, 153 { "ctrls", ACTION_FIELD_CONTROLS }, 154 { "type", ACTION_FIELD_TYPE }, 155 { "count", ACTION_FIELD_COUNT }, 156 { "screen", ACTION_FIELD_SCREEN }, 157 { "same", ACTION_FIELD_SAME }, 158 { "sameServer", ACTION_FIELD_SAME }, 159 { "data", ACTION_FIELD_DATA }, 160 { "device", ACTION_FIELD_DEVICE }, 161 { "dev", ACTION_FIELD_DEVICE }, 162 { "key", ACTION_FIELD_KEYCODE }, 163 { "keycode", ACTION_FIELD_KEYCODE }, 164 { "kc", ACTION_FIELD_KEYCODE }, 165 { "clearmods", ACTION_FIELD_MODS_TO_CLEAR }, 166 { "clearmodifiers", ACTION_FIELD_MODS_TO_CLEAR }, 167 { NULL, 0 } 168 }; 169 170 static bool 171 stringToAction(const char *str, enum xkb_action_type *type_rtrn) 172 { 173 return LookupString(actionTypeNames, str, type_rtrn); 174 } 175 176 static bool 177 stringToField(const char *str, enum action_field *field_rtrn) 178 { 179 return LookupString(fieldStrings, str, field_rtrn); 180 } 181 182 static const char * 183 fieldText(enum action_field field) 184 { 185 return LookupValue(fieldStrings, field); 186 } 187 188 /***====================================================================***/ 189 190 static inline bool 191 ReportMismatch(struct xkb_context *ctx, enum xkb_action_type action, 192 enum action_field field, const char *type) 193 { 194 log_err(ctx, 195 "Value of %s field must be of type %s; " 196 "Action %s definition ignored\n", 197 fieldText(field), type, ActionTypeText(action)); 198 return false; 199 } 200 201 static inline bool 202 ReportIllegal(struct xkb_context *ctx, enum xkb_action_type action, 203 enum action_field field) 204 { 205 log_err(ctx, 206 "Field %s is not defined for an action of type %s; " 207 "Action definition ignored\n", 208 fieldText(field), ActionTypeText(action)); 209 return false; 210 } 211 212 static inline bool 213 ReportActionNotArray(struct xkb_context *ctx, enum xkb_action_type action, 214 enum action_field field) 215 { 216 log_err(ctx, 217 "The %s field in the %s action is not an array; " 218 "Action definition ignored\n", 219 fieldText(field), ActionTypeText(action)); 220 return false; 221 } 222 223 static bool 224 HandleNoAction(struct xkb_context *ctx, const struct xkb_mod_set *mods, 225 union xkb_action *action, enum action_field field, 226 const ExprDef *array_ndx, const ExprDef *value) 227 228 { 229 return true; 230 } 231 232 static bool 233 CheckBooleanFlag(struct xkb_context *ctx, enum xkb_action_type action, 234 enum action_field field, enum xkb_action_flags flag, 235 const ExprDef *array_ndx, const ExprDef *value, 236 enum xkb_action_flags *flags_inout) 237 { 238 bool set; 239 240 if (array_ndx) 241 return ReportActionNotArray(ctx, action, field); 242 243 if (!ExprResolveBoolean(ctx, value, &set)) 244 return ReportMismatch(ctx, action, field, "boolean"); 245 246 if (set) 247 *flags_inout |= flag; 248 else 249 *flags_inout &= ~flag; 250 251 return true; 252 } 253 254 static bool 255 CheckModifierField(struct xkb_context *ctx, const struct xkb_mod_set *mods, 256 enum xkb_action_type action, const ExprDef *array_ndx, 257 const ExprDef *value, enum xkb_action_flags *flags_inout, 258 xkb_mod_mask_t *mods_rtrn) 259 { 260 if (array_ndx) 261 return ReportActionNotArray(ctx, action, ACTION_FIELD_MODIFIERS); 262 263 if (value->expr.op == EXPR_IDENT) { 264 const char *valStr; 265 valStr = xkb_atom_text(ctx, value->ident.ident); 266 if (valStr && (istreq(valStr, "usemodmapmods") || 267 istreq(valStr, "modmapmods"))) { 268 *mods_rtrn = 0; 269 *flags_inout |= ACTION_MODS_LOOKUP_MODMAP; 270 return true; 271 } 272 } 273 274 if (!ExprResolveModMask(ctx, value, MOD_BOTH, mods, mods_rtrn)) 275 return ReportMismatch(ctx, action, 276 ACTION_FIELD_MODIFIERS, "modifier mask"); 277 278 *flags_inout &= ~ACTION_MODS_LOOKUP_MODMAP; 279 return true; 280 } 281 282 static const LookupEntry lockWhich[] = { 283 { "both", 0 }, 284 { "lock", ACTION_LOCK_NO_UNLOCK }, 285 { "neither", (ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK) }, 286 { "unlock", ACTION_LOCK_NO_LOCK }, 287 { NULL, 0 } 288 }; 289 290 static bool 291 CheckAffectField(struct xkb_context *ctx, enum xkb_action_type action, 292 const ExprDef *array_ndx, const ExprDef *value, 293 enum xkb_action_flags *flags_inout) 294 { 295 enum xkb_action_flags flags; 296 297 if (array_ndx) 298 return ReportActionNotArray(ctx, action, ACTION_FIELD_AFFECT); 299 300 if (!ExprResolveEnum(ctx, value, &flags, lockWhich)) 301 return ReportMismatch(ctx, action, ACTION_FIELD_AFFECT, 302 "lock, unlock, both, neither"); 303 304 *flags_inout &= ~(ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK); 305 *flags_inout |= flags; 306 return true; 307 } 308 309 static bool 310 HandleSetLatchLockMods(struct xkb_context *ctx, const struct xkb_mod_set *mods, 311 union xkb_action *action, enum action_field field, 312 const ExprDef *array_ndx, const ExprDef *value) 313 { 314 struct xkb_mod_action *act = &action->mods; 315 const enum xkb_action_type type = action->type; 316 317 if (field == ACTION_FIELD_MODIFIERS) 318 return CheckModifierField(ctx, mods, action->type, array_ndx, value, 319 &act->flags, &act->mods.mods); 320 if ((type == ACTION_TYPE_MOD_SET || type == ACTION_TYPE_MOD_LATCH) && 321 field == ACTION_FIELD_CLEAR_LOCKS) 322 return CheckBooleanFlag(ctx, action->type, field, 323 ACTION_LOCK_CLEAR, array_ndx, value, 324 &act->flags); 325 if (type == ACTION_TYPE_MOD_LATCH && 326 field == ACTION_FIELD_LATCH_TO_LOCK) 327 return CheckBooleanFlag(ctx, action->type, field, 328 ACTION_LATCH_TO_LOCK, array_ndx, value, 329 &act->flags); 330 if (type == ACTION_TYPE_MOD_LOCK && 331 field == ACTION_FIELD_AFFECT) 332 return CheckAffectField(ctx, action->type, array_ndx, value, 333 &act->flags); 334 335 return ReportIllegal(ctx, action->type, field); 336 } 337 338 static bool 339 CheckGroupField(struct xkb_context *ctx, enum xkb_action_type action, 340 const ExprDef *array_ndx, const ExprDef *value, 341 enum xkb_action_flags *flags_inout, int32_t *group_rtrn) 342 { 343 const ExprDef *spec; 344 xkb_layout_index_t idx; 345 enum xkb_action_flags flags = *flags_inout; 346 347 if (array_ndx) 348 return ReportActionNotArray(ctx, action, ACTION_FIELD_GROUP); 349 350 if (value->expr.op == EXPR_NEGATE || value->expr.op == EXPR_UNARY_PLUS) { 351 flags &= ~ACTION_ABSOLUTE_SWITCH; 352 spec = value->unary.child; 353 } 354 else { 355 flags |= ACTION_ABSOLUTE_SWITCH; 356 spec = value; 357 } 358 359 if (!ExprResolveGroup(ctx, spec, &idx)) 360 return ReportMismatch(ctx, action, ACTION_FIELD_GROUP, 361 "integer (range 1..8)"); 362 363 /* +n, -n are relative, n is absolute. */ 364 if (value->expr.op == EXPR_NEGATE || value->expr.op == EXPR_UNARY_PLUS) { 365 *group_rtrn = (int32_t) idx; 366 if (value->expr.op == EXPR_NEGATE) 367 *group_rtrn = -*group_rtrn; 368 } 369 else { 370 *group_rtrn = (int32_t) (idx - 1); 371 } 372 *flags_inout = flags; 373 return true; 374 } 375 376 static bool 377 HandleSetLatchLockGroup(struct xkb_context *ctx, const struct xkb_mod_set *mods, 378 union xkb_action *action, enum action_field field, 379 const ExprDef *array_ndx, const ExprDef *value) 380 { 381 struct xkb_group_action *act = &action->group; 382 const enum xkb_action_type type = action->type; 383 384 if (field == ACTION_FIELD_GROUP) 385 return CheckGroupField(ctx, action->type, array_ndx, value, 386 &act->flags, &act->group); 387 if ((type == ACTION_TYPE_GROUP_SET || type == ACTION_TYPE_GROUP_LATCH) && 388 field == ACTION_FIELD_CLEAR_LOCKS) 389 return CheckBooleanFlag(ctx, action->type, field, 390 ACTION_LOCK_CLEAR, array_ndx, value, 391 &act->flags); 392 if (type == ACTION_TYPE_GROUP_LATCH && 393 field == ACTION_FIELD_LATCH_TO_LOCK) 394 return CheckBooleanFlag(ctx, action->type, field, 395 ACTION_LATCH_TO_LOCK, array_ndx, value, 396 &act->flags); 397 398 return ReportIllegal(ctx, action->type, field); 399 } 400 401 static bool 402 HandleMovePtr(struct xkb_context *ctx, const struct xkb_mod_set *mods, 403 union xkb_action *action, enum action_field field, 404 const ExprDef *array_ndx, const ExprDef *value) 405 { 406 struct xkb_pointer_action *act = &action->ptr; 407 408 if (field == ACTION_FIELD_X || field == ACTION_FIELD_Y) { 409 int val; 410 const bool absolute = (value->expr.op != EXPR_NEGATE && 411 value->expr.op != EXPR_UNARY_PLUS); 412 413 if (array_ndx) 414 return ReportActionNotArray(ctx, action->type, field); 415 416 if (!ExprResolveInteger(ctx, value, &val)) 417 return ReportMismatch(ctx, action->type, field, "integer"); 418 419 if (val < INT16_MIN || val > INT16_MAX) { 420 log_err(ctx, 421 "The %s field in the %s action must be in range %d..%d; " 422 "Action definition ignored\n", 423 fieldText(field), ActionTypeText(action->type), 424 INT16_MIN, INT16_MAX); 425 return false; 426 } 427 428 if (field == ACTION_FIELD_X) { 429 if (absolute) 430 act->flags |= ACTION_ABSOLUTE_X; 431 act->x = (int16_t) val; 432 } 433 else { 434 if (absolute) 435 act->flags |= ACTION_ABSOLUTE_Y; 436 act->y = (int16_t) val; 437 } 438 439 return true; 440 } 441 else if (field == ACTION_FIELD_ACCEL) { 442 return CheckBooleanFlag(ctx, action->type, field, 443 ACTION_ACCEL, array_ndx, value, &act->flags); 444 } 445 446 return ReportIllegal(ctx, action->type, field); 447 } 448 449 static bool 450 HandlePtrBtn(struct xkb_context *ctx, const struct xkb_mod_set *mods, 451 union xkb_action *action, enum action_field field, 452 const ExprDef *array_ndx, const ExprDef *value) 453 { 454 struct xkb_pointer_button_action *act = &action->btn; 455 456 if (field == ACTION_FIELD_BUTTON) { 457 int btn; 458 459 if (array_ndx) 460 return ReportActionNotArray(ctx, action->type, field); 461 462 if (!ExprResolveButton(ctx, value, &btn)) 463 return ReportMismatch(ctx, action->type, field, 464 "integer (range 1..5)"); 465 466 if (btn < 0 || btn > 5) { 467 log_err(ctx, 468 "Button must specify default or be in the range 1..5; " 469 "Illegal button value %d ignored\n", btn); 470 return false; 471 } 472 473 act->button = btn; 474 return true; 475 } 476 else if (action->type == ACTION_TYPE_PTR_LOCK && 477 field == ACTION_FIELD_AFFECT) { 478 return CheckAffectField(ctx, action->type, array_ndx, value, 479 &act->flags); 480 } 481 else if (field == ACTION_FIELD_COUNT) { 482 int val; 483 484 if (array_ndx) 485 return ReportActionNotArray(ctx, action->type, field); 486 487 if (!ExprResolveInteger(ctx, value, &val)) 488 return ReportMismatch(ctx, action->type, field, "integer"); 489 490 if (val < 0 || val > 255) { 491 log_err(ctx, 492 "The count field must have a value in the range 0..255; " 493 "Illegal count %d ignored\n", val); 494 return false; 495 } 496 497 act->count = (uint8_t) val; 498 return true; 499 } 500 501 return ReportIllegal(ctx, action->type, field); 502 } 503 504 static const LookupEntry ptrDflts[] = { 505 { "dfltbtn", 1 }, 506 { "defaultbutton", 1 }, 507 { "button", 1 }, 508 { NULL, 0 } 509 }; 510 511 static bool 512 HandleSetPtrDflt(struct xkb_context *ctx, const struct xkb_mod_set *mods, 513 union xkb_action *action, enum action_field field, 514 const ExprDef *array_ndx, const ExprDef *value) 515 { 516 struct xkb_pointer_default_action *act = &action->dflt; 517 518 if (field == ACTION_FIELD_AFFECT) { 519 unsigned int val; 520 521 if (array_ndx) 522 return ReportActionNotArray(ctx, action->type, field); 523 524 if (!ExprResolveEnum(ctx, value, &val, ptrDflts)) 525 return ReportMismatch(ctx, action->type, field, 526 "pointer component"); 527 return true; 528 } 529 else if (field == ACTION_FIELD_BUTTON || field == ACTION_FIELD_VALUE) { 530 const ExprDef *button; 531 int btn; 532 533 if (array_ndx) 534 return ReportActionNotArray(ctx, action->type, field); 535 536 if (value->expr.op == EXPR_NEGATE || 537 value->expr.op == EXPR_UNARY_PLUS) { 538 act->flags &= ~ACTION_ABSOLUTE_SWITCH; 539 button = value->unary.child; 540 } 541 else { 542 act->flags |= ACTION_ABSOLUTE_SWITCH; 543 button = value; 544 } 545 546 if (!ExprResolveButton(ctx, button, &btn)) 547 return ReportMismatch(ctx, action->type, field, 548 "integer (range 1..5)"); 549 550 if (btn < 0 || btn > 5) { 551 log_err(ctx, 552 "New default button value must be in the range 1..5; " 553 "Illegal default button value %d ignored\n", btn); 554 return false; 555 } 556 if (btn == 0) { 557 log_err(ctx, 558 "Cannot set default pointer button to \"default\"; " 559 "Illegal default button setting ignored\n"); 560 return false; 561 } 562 563 act->value = (value->expr.op == EXPR_NEGATE ? -btn: btn); 564 return true; 565 } 566 567 return ReportIllegal(ctx, action->type, field); 568 } 569 570 static bool 571 HandleSwitchScreen(struct xkb_context *ctx, const struct xkb_mod_set *mods, 572 union xkb_action *action, enum action_field field, 573 const ExprDef *array_ndx, const ExprDef *value) 574 { 575 struct xkb_switch_screen_action *act = &action->screen; 576 577 if (field == ACTION_FIELD_SCREEN) { 578 const ExprDef *scrn; 579 int val; 580 581 if (array_ndx) 582 return ReportActionNotArray(ctx, action->type, field); 583 584 if (value->expr.op == EXPR_NEGATE || 585 value->expr.op == EXPR_UNARY_PLUS) { 586 act->flags &= ~ACTION_ABSOLUTE_SWITCH; 587 scrn = value->unary.child; 588 } 589 else { 590 act->flags |= ACTION_ABSOLUTE_SWITCH; 591 scrn = value; 592 } 593 594 if (!ExprResolveInteger(ctx, scrn, &val)) 595 return ReportMismatch(ctx, action->type, field, 596 "integer (0..255)"); 597 598 if (val < 0 || val > 255) { 599 log_err(ctx, 600 "Screen index must be in the range 1..255; " 601 "Illegal screen value %d ignored\n", val); 602 return false; 603 } 604 605 act->screen = (value->expr.op == EXPR_NEGATE ? -val : val); 606 return true; 607 } 608 else if (field == ACTION_FIELD_SAME) { 609 return CheckBooleanFlag(ctx, action->type, field, 610 ACTION_SAME_SCREEN, array_ndx, value, 611 &act->flags); 612 } 613 614 return ReportIllegal(ctx, action->type, field); 615 } 616 617 static bool 618 HandleSetLockControls(struct xkb_context *ctx, const struct xkb_mod_set *mods, 619 union xkb_action *action, enum action_field field, 620 const ExprDef *array_ndx, const ExprDef *value) 621 { 622 struct xkb_controls_action *act = &action->ctrls; 623 624 if (field == ACTION_FIELD_CONTROLS) { 625 enum xkb_action_controls mask; 626 627 if (array_ndx) 628 return ReportActionNotArray(ctx, action->type, field); 629 630 if (!ExprResolveMask(ctx, value, &mask, ctrlMaskNames)) 631 return ReportMismatch(ctx, action->type, field, 632 "controls mask"); 633 634 act->ctrls = mask; 635 return true; 636 } 637 else if (field == ACTION_FIELD_AFFECT) { 638 return CheckAffectField(ctx, action->type, array_ndx, value, 639 &act->flags); 640 } 641 642 return ReportIllegal(ctx, action->type, field); 643 } 644 645 static bool 646 HandlePrivate(struct xkb_context *ctx, const struct xkb_mod_set *mods, 647 union xkb_action *action, enum action_field field, 648 const ExprDef *array_ndx, const ExprDef *value) 649 { 650 struct xkb_private_action *act = &action->priv; 651 652 if (field == ACTION_FIELD_TYPE) { 653 int type; 654 655 if (array_ndx) 656 return ReportActionNotArray(ctx, action->type, field); 657 658 if (!ExprResolveInteger(ctx, value, &type)) 659 return ReportMismatch(ctx, ACTION_TYPE_PRIVATE, field, "integer"); 660 661 if (type < 0 || type > 255) { 662 log_err(ctx, 663 "Private action type must be in the range 0..255; " 664 "Illegal type %d ignored\n", type); 665 return false; 666 } 667 668 /* 669 * It's possible for someone to write something like this: 670 * actions = [ Private(type=3,data[0]=1,data[1]=3,data[2]=3) ] 671 * where the type refers to some existing action type, e.g. LockMods. 672 * This assumes that this action's struct is laid out in memory 673 * exactly as described in the XKB specification and libraries. 674 * We, however, have changed these structs in various ways, so this 675 * assumption is no longer true. Since this is a lousy "feature", we 676 * make actions like these no-ops for now. 677 */ 678 if (type < ACTION_TYPE_PRIVATE) { 679 log_info(ctx, 680 "Private actions of type %s are not supported; Ignored\n", 681 ActionTypeText(type)); 682 act->type = ACTION_TYPE_NONE; 683 } 684 else { 685 act->type = (enum xkb_action_type) type; 686 } 687 688 return true; 689 } 690 else if (field == ACTION_FIELD_DATA) { 691 if (array_ndx == NULL) { 692 xkb_atom_t val; 693 const char *str; 694 size_t len; 695 696 if (!ExprResolveString(ctx, value, &val)) 697 return ReportMismatch(ctx, action->type, field, "string"); 698 699 str = xkb_atom_text(ctx, val); 700 len = strlen(str); 701 if (len < 1 || len > 7) { 702 log_warn(ctx, 703 "A private action has 7 data bytes; " 704 "Illegal data ignored\n"); 705 return false; 706 } 707 708 strncpy((char *) act->data, str, sizeof(act->data)); 709 return true; 710 } 711 else { 712 int ndx, datum; 713 714 if (!ExprResolveInteger(ctx, array_ndx, &ndx)) { 715 log_err(ctx, 716 "Array subscript must be integer; " 717 "Illegal subscript ignored\n"); 718 return false; 719 } 720 721 if (ndx < 0 || (size_t) ndx >= sizeof(act->data)) { 722 log_err(ctx, 723 "The data for a private action is %lu bytes long; " 724 "Attempt to use data[%d] ignored\n", 725 (unsigned long) sizeof(act->data), ndx); 726 return false; 727 } 728 729 if (!ExprResolveInteger(ctx, value, &datum)) 730 return ReportMismatch(ctx, act->type, field, "integer"); 731 732 if (datum < 0 || datum > 255) { 733 log_err(ctx, 734 "All data for a private action must be 0..255; " 735 "Illegal datum %d ignored\n", datum); 736 return false; 737 } 738 739 act->data[ndx] = (uint8_t) datum; 740 return true; 741 } 742 } 743 744 return ReportIllegal(ctx, ACTION_TYPE_NONE, field); 745 } 746 747 typedef bool (*actionHandler)(struct xkb_context *ctx, 748 const struct xkb_mod_set *mods, 749 union xkb_action *action, 750 enum action_field field, 751 const ExprDef *array_ndx, 752 const ExprDef *value); 753 754 static const actionHandler handleAction[_ACTION_TYPE_NUM_ENTRIES] = { 755 [ACTION_TYPE_NONE] = HandleNoAction, 756 [ACTION_TYPE_MOD_SET] = HandleSetLatchLockMods, 757 [ACTION_TYPE_MOD_LATCH] = HandleSetLatchLockMods, 758 [ACTION_TYPE_MOD_LOCK] = HandleSetLatchLockMods, 759 [ACTION_TYPE_GROUP_SET] = HandleSetLatchLockGroup, 760 [ACTION_TYPE_GROUP_LATCH] = HandleSetLatchLockGroup, 761 [ACTION_TYPE_GROUP_LOCK] = HandleSetLatchLockGroup, 762 [ACTION_TYPE_PTR_MOVE] = HandleMovePtr, 763 [ACTION_TYPE_PTR_BUTTON] = HandlePtrBtn, 764 [ACTION_TYPE_PTR_LOCK] = HandlePtrBtn, 765 [ACTION_TYPE_PTR_DEFAULT] = HandleSetPtrDflt, 766 [ACTION_TYPE_TERMINATE] = HandleNoAction, 767 [ACTION_TYPE_SWITCH_VT] = HandleSwitchScreen, 768 [ACTION_TYPE_CTRL_SET] = HandleSetLockControls, 769 [ACTION_TYPE_CTRL_LOCK] = HandleSetLockControls, 770 [ACTION_TYPE_PRIVATE] = HandlePrivate, 771 }; 772 773 /***====================================================================***/ 774 775 bool 776 HandleActionDef(struct xkb_context *ctx, ActionsInfo *info, 777 const struct xkb_mod_set *mods, ExprDef *def, 778 union xkb_action *action) 779 { 780 ExprDef *arg; 781 const char *str; 782 enum xkb_action_type handler_type; 783 784 if (def->expr.op != EXPR_ACTION_DECL) { 785 log_err(ctx, "Expected an action definition, found %s\n", 786 expr_op_type_to_string(def->expr.op)); 787 return false; 788 } 789 790 str = xkb_atom_text(ctx, def->action.name); 791 if (!stringToAction(str, &handler_type)) { 792 log_err(ctx, "Unknown action %s\n", str); 793 return false; 794 } 795 796 /* 797 * Get the default values for this action type, as modified by 798 * statements such as: 799 * latchMods.clearLocks = True; 800 */ 801 *action = info->actions[handler_type]; 802 803 /* 804 * Now change the action properties as specified for this 805 * particular instance, e.g. "modifiers" and "clearLocks" in: 806 * SetMods(modifiers=Alt,clearLocks); 807 */ 808 for (arg = def->action.args; arg != NULL; 809 arg = (ExprDef *) arg->common.next) { 810 const ExprDef *value; 811 ExprDef *field, *arrayRtrn; 812 const char *elemRtrn, *fieldRtrn; 813 enum action_field fieldNdx; 814 815 if (arg->expr.op == EXPR_ASSIGN) { 816 field = arg->binary.left; 817 value = arg->binary.right; 818 } 819 else if (arg->expr.op == EXPR_NOT || arg->expr.op == EXPR_INVERT) { 820 field = arg->unary.child; 821 value = (const ExprDef *) &constFalse; 822 } 823 else { 824 field = arg; 825 value = (const ExprDef *) &constTrue; 826 } 827 828 if (!ExprResolveLhs(ctx, field, &elemRtrn, &fieldRtrn, &arrayRtrn)) 829 return false; 830 831 if (elemRtrn) { 832 log_err(ctx, 833 "Cannot change defaults in an action definition; " 834 "Ignoring attempt to change %s.%s\n", 835 elemRtrn, fieldRtrn); 836 return false; 837 } 838 839 if (!stringToField(fieldRtrn, &fieldNdx)) { 840 log_err(ctx, "Unknown field name %s\n", fieldRtrn); 841 return false; 842 } 843 844 if (!handleAction[handler_type](ctx, mods, action, fieldNdx, 845 arrayRtrn, value)) 846 return false; 847 } 848 849 return true; 850 } 851 852 bool 853 SetActionField(struct xkb_context *ctx, ActionsInfo *info, 854 struct xkb_mod_set *mods, const char *elem, 855 const char *field, ExprDef *array_ndx, ExprDef *value) 856 { 857 enum xkb_action_type action; 858 enum action_field action_field; 859 860 if (!stringToAction(elem, &action)) 861 return false; 862 863 if (!stringToField(field, &action_field)) { 864 log_err(ctx, "\"%s\" is not a legal field name\n", field); 865 return false; 866 } 867 868 return handleAction[action](ctx, mods, &info->actions[action], 869 action_field, array_ndx, value); 870 } 871