1 /* 2 * Copyright 2004-2009 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Sandor Vroemisse 7 * Jérôme Duval 8 * Axel Dörfler, axeld@pinc-software.de. 9 */ 10 11 #include "Keymap.h" 12 13 #include <new> 14 #include <stdio.h> 15 #include <string.h> 16 17 #include <ByteOrder.h> 18 #include <File.h> 19 20 #include <input_globals.h> 21 22 23 static const uint32 kModifierKeys = B_SHIFT_KEY | B_COMMAND_KEY | B_CONTROL_KEY 24 | B_CAPS_LOCK | B_OPTION_KEY | B_MENU_KEY; 25 26 27 static void 28 print_key(char *chars, int32 offset) 29 { 30 int size = chars[offset++]; 31 32 switch (size) { 33 case 0: 34 // Not mapped 35 printf("N/A"); 36 break; 37 38 case 1: 39 // 1-byte UTF-8/ASCII character 40 printf("%c", chars[offset]); 41 break; 42 43 default: 44 { 45 // 2-, 3-, or 4-byte UTF-8 character 46 char *str = new char[size + 1]; 47 strncpy(str, &chars[offset], size); 48 str[size] = 0; 49 printf("%s", str); 50 delete[] str; 51 break; 52 } 53 } 54 55 printf("\t"); 56 } 57 58 59 // #pragma mark - 60 61 62 Keymap::Keymap() 63 : 64 fChars(NULL), 65 fCharsSize(0), 66 fModificationMessage(NULL) 67 { 68 } 69 70 71 Keymap::~Keymap() 72 { 73 delete fModificationMessage; 74 } 75 76 77 void 78 Keymap::SetTarget(BMessenger target, BMessage* modificationMessage) 79 { 80 delete fModificationMessage; 81 82 fTarget = target; 83 fModificationMessage = modificationMessage; 84 } 85 86 87 void 88 Keymap::SetName(const char* name) 89 { 90 strlcpy(fName, name, sizeof(fName)); 91 } 92 93 94 void 95 Keymap::DumpKeymap() 96 { 97 // Print a chart of the normal, shift, option, and option+shift 98 // keys. 99 printf("Key #\tNormal\tShift\tCaps\tC+S\tOption\tO+S\tO+C\tO+C+S\tControl\n"); 100 for (int i = 0; i < 128; i++) { 101 printf(" 0x%x\t", i); 102 print_key(fChars, fKeys.normal_map[i]); 103 print_key(fChars, fKeys.shift_map[i]); 104 print_key(fChars, fKeys.caps_map[i]); 105 print_key(fChars, fKeys.caps_shift_map[i]); 106 print_key(fChars, fKeys.option_map[i]); 107 print_key(fChars, fKeys.option_shift_map[i]); 108 print_key(fChars, fKeys.option_caps_map[i]); 109 print_key(fChars, fKeys.option_caps_shift_map[i]); 110 print_key(fChars, fKeys.control_map[i]); 111 printf("\n"); 112 } 113 } 114 115 116 /* 117 file format in big endian : 118 struct key_map 119 uint32 size of following charset 120 charset (offsets go into this with size of character followed by character) 121 */ 122 // we load a map from a file 123 status_t 124 Keymap::Load(entry_ref &ref) 125 { 126 status_t err; 127 BEntry entry(&ref, true); 128 if ((err = entry.InitCheck()) != B_OK) { 129 fprintf(stderr, "error loading keymap: %s\n", strerror(err)); 130 return err; 131 } 132 133 BFile file(&entry, B_READ_ONLY); 134 if ((err = file.InitCheck()) != B_OK) { 135 fprintf(stderr, "error loading keymap: %s\n", strerror(err)); 136 return err; 137 } 138 139 if ((err = file.Read(&fKeys, sizeof(fKeys))) < (ssize_t)sizeof(fKeys)) { 140 fprintf(stderr, "error reading keymap keys: %s\n", strerror(err)); 141 return B_BAD_VALUE; 142 } 143 144 for (uint32 i = 0; i < sizeof(fKeys) / 4; i++) 145 ((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]); 146 147 if ((err = file.Read(&fCharsSize, sizeof(uint32))) < (ssize_t)sizeof(uint32)) { 148 fprintf(stderr, "error reading keymap size: %s\n", strerror(err)); 149 return B_BAD_VALUE; 150 } 151 152 fCharsSize = B_BENDIAN_TO_HOST_INT32(fCharsSize); 153 delete[] fChars; 154 155 fChars = new char[fCharsSize]; 156 157 ssize_t bytesRead = file.Read(fChars, fCharsSize); 158 if (bytesRead < 0) { 159 fprintf(stderr, "error reading keymap chars: %s\n", strerror(err)); 160 return (status_t)bytesRead; 161 } 162 163 // fetch name from attribute and fall back to filename 164 165 bytesRead = file.ReadAttr("keymap:name", B_STRING_TYPE, 0, fName, 166 sizeof(fName)); 167 if (bytesRead > 0) 168 fName[bytesRead] = '\0'; 169 else 170 strlcpy(fName, ref.name, sizeof(fName)); 171 return B_OK; 172 } 173 174 175 //! We save a map to a file 176 status_t 177 Keymap::Save(entry_ref& ref) 178 { 179 BFile file; 180 status_t status = file.SetTo(&ref, 181 B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 182 if (status != B_OK) { 183 printf("error %s\n", strerror(status)); 184 return status; 185 } 186 187 for (uint32 i = 0; i < sizeof(fKeys) / 4; i++) 188 ((uint32*)&fKeys)[i] = B_HOST_TO_BENDIAN_INT32(((uint32*)&fKeys)[i]); 189 190 ssize_t bytesWritten = file.Write(&fKeys, sizeof(fKeys)); 191 if (bytesWritten < (ssize_t)sizeof(fKeys)) 192 status = bytesWritten < 0 ? bytesWritten : B_IO_ERROR; 193 194 for (uint32 i = 0; i < sizeof(fKeys) / 4; i++) 195 ((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]); 196 197 if (status == B_OK) { 198 fCharsSize = B_HOST_TO_BENDIAN_INT32(fCharsSize); 199 200 bytesWritten = file.Write(&fCharsSize, sizeof(uint32)); 201 if (bytesWritten < (ssize_t)sizeof(uint32)) 202 status = bytesWritten < 0 ? bytesWritten : B_IO_ERROR; 203 204 fCharsSize = B_BENDIAN_TO_HOST_INT32(fCharsSize); 205 } 206 207 if (status == B_OK) { 208 bytesWritten = file.Write(fChars, fCharsSize); 209 if (bytesWritten < (ssize_t)fCharsSize) 210 status = bytesWritten < 0 ? bytesWritten : B_IO_ERROR; 211 } 212 213 if (status == B_OK) { 214 file.WriteAttr("keymap:name", B_STRING_TYPE, 0, fName, strlen(fName)); 215 // Failing would be non-fatal 216 } 217 218 return status; 219 } 220 221 222 bool 223 Keymap::Equals(const Keymap& other) const 224 { 225 // not really efficient but this is the only way i found 226 // to reliably compare keymaps (used only for apply and revert) 227 return fCharsSize == other.fCharsSize 228 && !memcmp(&other.fKeys, &fKeys, sizeof(key_map)) 229 && !memcmp(other.fChars, fChars, fCharsSize); 230 } 231 232 233 /*! We need to know if a key is a modifier key to choose 234 a valid key when several are pressed together. 235 */ 236 bool 237 Keymap::IsModifierKey(uint32 keyCode) 238 { 239 return keyCode == fKeys.caps_key 240 || keyCode == fKeys.num_key 241 || keyCode == fKeys.scroll_key 242 || keyCode == fKeys.left_shift_key 243 || keyCode == fKeys.right_shift_key 244 || keyCode == fKeys.left_command_key 245 || keyCode == fKeys.right_command_key 246 || keyCode == fKeys.left_control_key 247 || keyCode == fKeys.right_control_key 248 || keyCode == fKeys.left_option_key 249 || keyCode == fKeys.right_option_key 250 || keyCode == fKeys.menu_key; 251 } 252 253 254 //! We need to know a modifier for a key 255 uint32 256 Keymap::Modifier(uint32 keyCode) 257 { 258 if (keyCode == fKeys.caps_key) 259 return B_CAPS_LOCK; 260 if (keyCode == fKeys.num_key) 261 return B_NUM_LOCK; 262 if (keyCode == fKeys.scroll_key) 263 return B_SCROLL_LOCK; 264 if (keyCode == fKeys.left_shift_key) 265 return B_LEFT_SHIFT_KEY | B_SHIFT_KEY; 266 if (keyCode == fKeys.right_shift_key) 267 return B_RIGHT_SHIFT_KEY | B_SHIFT_KEY; 268 if (keyCode == fKeys.left_command_key) 269 return B_LEFT_COMMAND_KEY | B_COMMAND_KEY; 270 if (keyCode == fKeys.right_command_key) 271 return B_RIGHT_COMMAND_KEY | B_COMMAND_KEY; 272 if (keyCode == fKeys.left_control_key) 273 return B_LEFT_CONTROL_KEY | B_CONTROL_KEY; 274 if (keyCode == fKeys.right_control_key) 275 return B_RIGHT_CONTROL_KEY | B_CONTROL_KEY; 276 if (keyCode == fKeys.left_option_key) 277 return B_LEFT_OPTION_KEY | B_OPTION_KEY; 278 if (keyCode == fKeys.right_option_key) 279 return B_RIGHT_OPTION_KEY | B_OPTION_KEY; 280 if (keyCode == fKeys.menu_key) 281 return B_MENU_KEY; 282 283 return 0; 284 } 285 286 287 uint32 288 Keymap::KeyForModifier(uint32 modifier) 289 { 290 if (modifier == B_CAPS_LOCK) 291 return fKeys.caps_key; 292 if (modifier == B_NUM_LOCK) 293 return fKeys.num_key; 294 if (modifier == B_SCROLL_LOCK) 295 return fKeys.scroll_key; 296 if (modifier == B_LEFT_SHIFT_KEY || modifier == B_SHIFT_KEY) 297 return fKeys.left_shift_key; 298 if (modifier == B_RIGHT_SHIFT_KEY) 299 return fKeys.right_shift_key; 300 if (modifier == B_LEFT_COMMAND_KEY || modifier == B_COMMAND_KEY) 301 return fKeys.left_command_key; 302 if (modifier == B_RIGHT_COMMAND_KEY) 303 return fKeys.right_command_key; 304 if (modifier == B_LEFT_CONTROL_KEY || modifier == B_CONTROL_KEY) 305 return fKeys.left_control_key; 306 if (modifier == B_RIGHT_CONTROL_KEY) 307 return fKeys.right_control_key; 308 if (modifier == B_LEFT_OPTION_KEY || modifier == B_OPTION_KEY) 309 return fKeys.left_option_key; 310 if (modifier == B_RIGHT_OPTION_KEY) 311 return fKeys.right_option_key; 312 if (modifier == B_MENU_KEY) 313 return fKeys.menu_key; 314 315 return 0; 316 } 317 318 319 status_t 320 Keymap::SetModifier(uint32 keyCode, uint32 modifier) 321 { 322 const uint32 kSingleKeys = B_LEFT_SHIFT_KEY | B_RIGHT_SHIFT_KEY 323 | B_LEFT_COMMAND_KEY | B_RIGHT_COMMAND_KEY | B_LEFT_CONTROL_KEY 324 | B_RIGHT_CONTROL_KEY | B_LEFT_OPTION_KEY | B_RIGHT_OPTION_KEY; 325 326 if ((modifier & kSingleKeys) != 0) 327 modifier &= kSingleKeys; 328 else if ((modifier & kModifierKeys) != 0) 329 modifier &= kModifierKeys; 330 331 if (modifier == B_CAPS_LOCK) 332 fKeys.caps_key = keyCode; 333 else if (modifier == B_NUM_LOCK) 334 fKeys.num_key = keyCode; 335 else if (modifier == B_SCROLL_LOCK) 336 fKeys.scroll_key = keyCode; 337 else if (modifier == B_LEFT_SHIFT_KEY) 338 fKeys.left_shift_key = keyCode; 339 else if (modifier == B_RIGHT_SHIFT_KEY) 340 fKeys.right_shift_key = keyCode; 341 else if (modifier == B_LEFT_COMMAND_KEY) 342 fKeys.left_command_key = keyCode; 343 else if (modifier == B_RIGHT_COMMAND_KEY) 344 fKeys.right_command_key = keyCode; 345 else if (modifier == B_LEFT_CONTROL_KEY) 346 fKeys.left_control_key = keyCode; 347 else if (modifier == B_RIGHT_CONTROL_KEY) 348 fKeys.right_control_key = keyCode; 349 else if (modifier == B_LEFT_OPTION_KEY) 350 fKeys.left_option_key = keyCode; 351 else if (modifier == B_RIGHT_OPTION_KEY) 352 fKeys.right_option_key = keyCode; 353 else if (modifier == B_MENU_KEY) 354 fKeys.menu_key = keyCode; 355 else 356 return B_BAD_VALUE; 357 358 if (fModificationMessage != NULL) 359 fTarget.SendMessage(fModificationMessage); 360 361 return B_OK; 362 } 363 364 365 /*! Checks whether a key is a dead key. 366 If it is, the enabled/disabled state of that dead key will be passed 367 out via isEnabled (isEnabled is not touched for non-dead keys). 368 */ 369 uint8 370 Keymap::IsDeadKey(uint32 keyCode, uint32 modifiers, bool* isEnabled) 371 { 372 uint32 tableMask = 0; 373 int32 offset = _Offset(keyCode, modifiers, &tableMask); 374 uint8 deadKeyIndex = _GetDeadKeyIndex(offset); 375 if (deadKeyIndex > 0 && isEnabled != NULL) { 376 uint32 deadTables[] = { 377 fKeys.acute_tables, 378 fKeys.grave_tables, 379 fKeys.circumflex_tables, 380 fKeys.dieresis_tables, 381 fKeys.tilde_tables 382 }; 383 *isEnabled = (deadTables[deadKeyIndex - 1] & tableMask) != 0; 384 } 385 386 return deadKeyIndex; 387 } 388 389 390 //! Tell if a key is a dead second key, needed for draw a dead second key. 391 bool 392 Keymap::IsDeadSecondKey(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey) 393 { 394 if (!activeDeadKey) 395 return false; 396 397 int32 offset = _Offset(keyCode, modifiers); 398 if (offset < 0) 399 return false; 400 401 uint32 numBytes = fChars[offset]; 402 if (!numBytes) 403 return false; 404 405 int32* deadOffsets[] = { 406 fKeys.acute_dead_key, 407 fKeys.grave_dead_key, 408 fKeys.circumflex_dead_key, 409 fKeys.dieresis_dead_key, 410 fKeys.tilde_dead_key 411 }; 412 413 int32 *deadOffset = deadOffsets[activeDeadKey - 1]; 414 415 for (int32 i=0; i<32; i++) { 416 if (offset == deadOffset[i]) 417 return true; 418 419 uint32 deadNumBytes = fChars[deadOffset[i]]; 420 421 if (!deadNumBytes) 422 continue; 423 424 if (strncmp(&fChars[offset + 1], &fChars[deadOffset[i] + 1], 425 deadNumBytes) == 0) 426 return true; 427 i++; 428 } 429 return false; 430 } 431 432 433 //! Enables/disables the "deadness" of the given keycode/modifier combo. 434 void 435 Keymap::SetDeadKeyEnabled(uint32 keyCode, uint32 modifiers, bool enabled) 436 { 437 uint32 tableMask = 0; 438 int32 offset = _Offset(keyCode, modifiers, &tableMask); 439 uint8 deadKeyIndex = _GetDeadKeyIndex(offset); 440 if (deadKeyIndex > 0) { 441 uint32* deadTables[] = { 442 &fKeys.acute_tables, 443 &fKeys.grave_tables, 444 &fKeys.circumflex_tables, 445 &fKeys.dieresis_tables, 446 &fKeys.tilde_tables 447 }; 448 449 if (enabled) 450 (*deadTables[deadKeyIndex - 1]) |= tableMask; 451 else 452 (*deadTables[deadKeyIndex - 1]) &= ~tableMask; 453 454 if (fModificationMessage != NULL) 455 fTarget.SendMessage(fModificationMessage); 456 } 457 } 458 459 460 /*! Returns the trigger character string that is currently set for the dead 461 key with the given index (which is 1..5). 462 */ 463 void 464 Keymap::GetDeadKeyTrigger(dead_key_index deadKeyIndex, BString& outTrigger) 465 { 466 outTrigger = ""; 467 if (deadKeyIndex < 1 || deadKeyIndex > 5) 468 return; 469 470 int32 deadOffsets[] = { 471 fKeys.acute_dead_key[1], 472 fKeys.grave_dead_key[1], 473 fKeys.circumflex_dead_key[1], 474 fKeys.dieresis_dead_key[1], 475 fKeys.tilde_dead_key[1] 476 }; 477 478 int32 offset = deadOffsets[deadKeyIndex - 1]; 479 if (offset < 0 || offset >= (int32)fCharsSize) 480 return; 481 482 uint32 deadNumBytes = fChars[offset]; 483 if (!deadNumBytes) 484 return; 485 486 outTrigger.SetTo(&fChars[offset + 1], deadNumBytes); 487 } 488 489 490 /*! Sets the trigger character string that shall be used for the dead key 491 with the given index (which is 1..5). 492 */ 493 void 494 Keymap::SetDeadKeyTrigger(dead_key_index deadKeyIndex, const BString& trigger) 495 { 496 if (deadKeyIndex < 1 || deadKeyIndex > 5) 497 return; 498 499 int32 deadOffsets[] = { 500 fKeys.acute_dead_key[1], 501 fKeys.grave_dead_key[1], 502 fKeys.circumflex_dead_key[1], 503 fKeys.dieresis_dead_key[1], 504 fKeys.tilde_dead_key[1] 505 }; 506 507 int32 offset = deadOffsets[deadKeyIndex - 1]; 508 if (offset < 0 || offset >= (int32)fCharsSize) 509 return; 510 511 if (_SetChars(offset, trigger.String(), trigger.Length())) { 512 // reset modifier table such that new dead key is enabled wherever 513 // it is available 514 uint32* deadTables[] = { 515 &fKeys.acute_tables, 516 &fKeys.grave_tables, 517 &fKeys.circumflex_tables, 518 &fKeys.dieresis_tables, 519 &fKeys.tilde_tables 520 }; 521 *deadTables[deadKeyIndex - 1] 522 = B_CONTROL_TABLE | B_OPTION_CAPS_SHIFT_TABLE | B_OPTION_CAPS_TABLE 523 | B_OPTION_SHIFT_TABLE | B_OPTION_TABLE | B_CAPS_SHIFT_TABLE 524 | B_CAPS_TABLE | B_SHIFT_TABLE | B_NORMAL_TABLE; 525 526 if (fModificationMessage != NULL) 527 fTarget.SendMessage(fModificationMessage); 528 } 529 } 530 531 532 //! Get the char for a key given modifiers and active dead key 533 void 534 Keymap::GetChars(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey, 535 char** chars, int32* numBytes) 536 { 537 *numBytes = 0; 538 *chars = NULL; 539 540 if (keyCode > 128 || fChars == NULL) 541 return; 542 543 // here we take NUMLOCK into account 544 if ((modifiers & B_NUM_LOCK) != 0) { 545 switch (keyCode) { 546 case 0x37: 547 case 0x38: 548 case 0x39: 549 case 0x48: 550 case 0x49: 551 case 0x4a: 552 case 0x58: 553 case 0x59: 554 case 0x5a: 555 case 0x64: 556 case 0x65: 557 modifiers ^= B_SHIFT_KEY; 558 } 559 } 560 561 int32 offset = _Offset(keyCode, modifiers); 562 if (offset < 0) 563 return; 564 565 // here we get the char size 566 *numBytes = fChars[offset]; 567 if (!*numBytes) 568 return; 569 570 // here we take an potential active dead key 571 int32 *deadKey; 572 switch (activeDeadKey) { 573 case kDeadKeyAcute: 574 deadKey = fKeys.acute_dead_key; 575 break; 576 case kDeadKeyGrave: 577 deadKey = fKeys.grave_dead_key; 578 break; 579 case kDeadKeyCircumflex: 580 deadKey = fKeys.circumflex_dead_key; 581 break; 582 case kDeadKeyDiaeresis: 583 deadKey = fKeys.dieresis_dead_key; 584 break; 585 case kDeadKeyTilde: 586 deadKey = fKeys.tilde_dead_key; 587 break; 588 default: 589 { 590 // if not dead, we copy and return the char 591 char *str = *chars = new char[*numBytes + 1]; 592 strncpy(str, &fChars[offset + 1], *numBytes); 593 str[*numBytes] = 0; 594 return; 595 } 596 } 597 598 // if dead key, we search for our current offset char in the dead key 599 // offset table string comparison is needed 600 for (int32 i = 0; i < 32; i++) { 601 if (strncmp(&fChars[offset + 1], &fChars[deadKey[i] + 1], *numBytes) 602 == 0) { 603 *numBytes = fChars[deadKey[i + 1]]; 604 605 switch (*numBytes) { 606 case 0: 607 // Not mapped 608 *chars = NULL; 609 break; 610 default: 611 { 612 // 1-, 2-, 3-, or 4-byte UTF-8 character 613 char *str = *chars = new char[*numBytes + 1]; 614 strncpy(str, &fChars[deadKey[i + 1] + 1], *numBytes); 615 str[*numBytes] = 0; 616 break; 617 } 618 } 619 return; 620 } 621 i++; 622 } 623 624 // if not found we return the current char mapped 625 *chars = new char[*numBytes + 1]; 626 strncpy(*chars, &fChars[offset + 1], *numBytes); 627 (*chars)[*numBytes] = 0; 628 } 629 630 631 //! We make our input server use the map in /boot/home/config/settings/Keymap 632 status_t 633 Keymap::Use() 634 { 635 return _restore_key_map_(); 636 } 637 638 639 void 640 Keymap::SetKey(uint32 keyCode, uint32 modifiers, int8 deadKey, 641 const char* bytes, int32 numBytes) 642 { 643 int32 offset = _Offset(keyCode, modifiers); 644 if (offset < 0) 645 return; 646 647 if (numBytes == -1) 648 numBytes = strlen(bytes); 649 if (numBytes > 6) 650 return; 651 652 if (_SetChars(offset, bytes, numBytes)) { 653 if (fModificationMessage != NULL) 654 fTarget.SendMessage(fModificationMessage); 655 } 656 } 657 658 659 Keymap& 660 Keymap::operator=(const Keymap& other) 661 { 662 if (this == &other) 663 return *this; 664 665 delete[] fChars; 666 delete fModificationMessage; 667 668 fChars = new(std::nothrow) char[other.fCharsSize]; 669 if (fChars != NULL) { 670 memcpy(fChars, other.fChars, other.fCharsSize); 671 fCharsSize = other.fCharsSize; 672 } else 673 fCharsSize = 0; 674 675 memcpy(&fKeys, &other.fKeys, sizeof(key_map)); 676 strlcpy(fName, other.fName, sizeof(fName)); 677 678 fTarget = other.fTarget; 679 680 if (other.fModificationMessage != NULL) 681 fModificationMessage = new BMessage(*other.fModificationMessage); 682 683 return *this; 684 } 685 686 687 int32 688 Keymap::_Offset(uint32 keyCode, uint32 modifiers, uint32* _table) 689 { 690 int32 offset; 691 uint32 table; 692 693 if (keyCode >= 128) 694 return -1; 695 696 switch (modifiers & kModifierKeys) { 697 case B_SHIFT_KEY: 698 offset = fKeys.shift_map[keyCode]; 699 table = B_SHIFT_TABLE; 700 break; 701 case B_CAPS_LOCK: 702 offset = fKeys.caps_map[keyCode]; 703 table = B_CAPS_TABLE; 704 break; 705 case B_CAPS_LOCK | B_SHIFT_KEY: 706 offset = fKeys.caps_shift_map[keyCode]; 707 table = B_CAPS_SHIFT_TABLE; 708 break; 709 case B_OPTION_KEY: 710 offset = fKeys.option_map[keyCode]; 711 table = B_OPTION_TABLE; 712 break; 713 case B_OPTION_KEY | B_SHIFT_KEY: 714 offset = fKeys.option_shift_map[keyCode]; 715 table = B_OPTION_SHIFT_TABLE; 716 break; 717 case B_OPTION_KEY | B_CAPS_LOCK: 718 offset = fKeys.option_caps_map[keyCode]; 719 table = B_OPTION_CAPS_TABLE; 720 break; 721 case B_OPTION_KEY | B_SHIFT_KEY | B_CAPS_LOCK: 722 offset = fKeys.option_caps_shift_map[keyCode]; 723 table = B_OPTION_CAPS_SHIFT_TABLE; 724 break; 725 case B_CONTROL_KEY: 726 offset = fKeys.control_map[keyCode]; 727 table = B_CONTROL_TABLE; 728 break; 729 default: 730 offset = fKeys.normal_map[keyCode]; 731 table = B_NORMAL_TABLE; 732 break; 733 } 734 735 if (_table != NULL) 736 *_table = table; 737 738 if (offset >= (int32)fCharsSize) 739 return -1; 740 741 return offset; 742 } 743 744 745 bool 746 Keymap::_SetChars(int32 offset, const char* bytes, int32 numBytes) 747 { 748 int32 oldNumBytes = fChars[offset]; 749 750 if (oldNumBytes == numBytes 751 && !memcmp(&fChars[offset + 1], bytes, numBytes)) { 752 // nothing to do 753 return false; 754 } 755 756 int32 diff = numBytes - oldNumBytes; 757 if (diff != 0) { 758 fCharsSize += diff; 759 760 if (diff > 0) { 761 // make space for the new data 762 char* chars = new(std::nothrow) char[fCharsSize]; 763 if (chars != NULL) { 764 memcpy(chars, fChars, offset + oldNumBytes + 1); 765 memcpy(&chars[offset + 1 + numBytes], 766 &fChars[offset + 1 + oldNumBytes], 767 fCharsSize - 2 - offset - diff); 768 delete[] fChars; 769 fChars = chars; 770 } else 771 return false; 772 } else if (diff < 0) { 773 // shrink table 774 memmove(&fChars[offset + numBytes], &fChars[offset + oldNumBytes], 775 fCharsSize - offset - 2 - diff); 776 } 777 778 // update offsets 779 int32* data = fKeys.control_map; 780 int32 size = sizeof(fKeys.control_map) / 4 * 9 781 + sizeof(fKeys.acute_dead_key) / 4 * 5; 782 for (int32 i = 0; i < size; i++) { 783 if (data[i] > offset) 784 data[i] += diff; 785 } 786 } 787 788 memcpy(&fChars[offset + 1], bytes, numBytes); 789 fChars[offset] = numBytes; 790 791 return true; 792 } 793 794 795 uint8 796 Keymap::_GetDeadKeyIndex(int32 offset) 797 { 798 if (fChars == NULL || offset <= 0) 799 return 0; 800 801 uint32 numBytes = fChars[offset]; 802 if (!numBytes) 803 return 0; 804 805 char chars[4]; 806 strncpy(chars, &fChars[offset + 1], numBytes); 807 chars[numBytes] = 0; 808 809 int32 deadOffsets[] = { 810 fKeys.acute_dead_key[1], 811 fKeys.grave_dead_key[1], 812 fKeys.circumflex_dead_key[1], 813 fKeys.dieresis_dead_key[1], 814 fKeys.tilde_dead_key[1] 815 }; 816 817 uint8 result = 0; 818 for (int32 i = 0; i < 5; i++) { 819 if (offset == deadOffsets[i]) { 820 result = i + 1; 821 break; 822 } 823 824 uint32 deadNumBytes = fChars[deadOffsets[i]]; 825 if (!deadNumBytes) 826 continue; 827 828 if (strncmp(chars, &fChars[deadOffsets[i] + 1], deadNumBytes) == 0) { 829 result = i + 1; 830 break; 831 } 832 } 833 834 return result; 835 } 836