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::DumpKeymap() 89 { 90 // Print a chart of the normal, shift, option, and option+shift 91 // keys. 92 printf("Key #\tNormal\tShift\tCaps\tC+S\tOption\tO+S\tO+C\tO+C+S\tControl\n"); 93 for (int i = 0; i < 128; i++) { 94 printf(" 0x%x\t", i); 95 print_key(fChars, fKeys.normal_map[i]); 96 print_key(fChars, fKeys.shift_map[i]); 97 print_key(fChars, fKeys.caps_map[i]); 98 print_key(fChars, fKeys.caps_shift_map[i]); 99 print_key(fChars, fKeys.option_map[i]); 100 print_key(fChars, fKeys.option_shift_map[i]); 101 print_key(fChars, fKeys.option_caps_map[i]); 102 print_key(fChars, fKeys.option_caps_shift_map[i]); 103 print_key(fChars, fKeys.control_map[i]); 104 printf("\n"); 105 } 106 } 107 108 109 /* 110 file format in big endian : 111 struct key_map 112 uint32 size of following charset 113 charset (offsets go into this with size of character followed by character) 114 */ 115 // we load a map from a file 116 status_t 117 Keymap::Load(entry_ref &ref) 118 { 119 status_t err; 120 BEntry entry(&ref, true); 121 if ((err = entry.InitCheck()) != B_OK) { 122 fprintf(stderr, "error loading keymap: %s\n", strerror(err)); 123 return err; 124 } 125 126 BFile file(&entry, B_READ_ONLY); 127 if ((err = file.InitCheck()) != B_OK) { 128 fprintf(stderr, "error loading keymap: %s\n", strerror(err)); 129 return err; 130 } 131 132 if ((err = file.Read(&fKeys, sizeof(fKeys))) < (ssize_t)sizeof(fKeys)) { 133 fprintf(stderr, "error reading keymap keys: %s\n", strerror(err)); 134 return B_BAD_VALUE; 135 } 136 137 for (uint32 i=0; i<sizeof(fKeys)/4; i++) 138 ((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]); 139 140 if ((err = file.Read(&fCharsSize, sizeof(uint32))) < (ssize_t)sizeof(uint32)) { 141 fprintf(stderr, "error reading keymap size: %s\n", strerror(err)); 142 return B_BAD_VALUE; 143 } 144 145 fCharsSize = B_BENDIAN_TO_HOST_INT32(fCharsSize); 146 delete[] fChars; 147 148 fChars = new char[fCharsSize]; 149 150 err = file.Read(fChars, fCharsSize); 151 if (err < B_OK) { 152 fprintf(stderr, "error reading keymap chars: %s\n", strerror(err)); 153 } 154 strlcpy(fName, ref.name, sizeof(fName)); 155 return err; 156 } 157 158 159 //! We save a map to a file 160 status_t 161 Keymap::Save(entry_ref& ref) 162 { 163 BFile file; 164 status_t status = file.SetTo(&ref, 165 B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 166 if (status != B_OK) { 167 printf("error %s\n", strerror(status)); 168 return status; 169 } 170 171 for (uint32 i = 0; i < sizeof(fKeys) / 4; i++) { 172 ((uint32*)&fKeys)[i] = B_HOST_TO_BENDIAN_INT32(((uint32*)&fKeys)[i]); 173 } 174 175 ssize_t bytesWritten = file.Write(&fKeys, sizeof(fKeys)); 176 if (bytesWritten < (ssize_t)sizeof(fKeys)) { 177 if (bytesWritten < 0) 178 return bytesWritten; 179 return B_IO_ERROR; 180 } 181 182 for (uint32 i = 0; i < sizeof(fKeys) / 4; i++) { 183 ((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]); 184 } 185 186 fCharsSize = B_HOST_TO_BENDIAN_INT32(fCharsSize); 187 188 bytesWritten = file.Write(&fCharsSize, sizeof(uint32)); 189 if (bytesWritten < (ssize_t)sizeof(uint32)) { 190 if (bytesWritten < 0) 191 return bytesWritten; 192 return B_IO_ERROR; 193 } 194 195 fCharsSize = B_BENDIAN_TO_HOST_INT32(fCharsSize); 196 197 bytesWritten = file.Write(fChars, fCharsSize); 198 if (bytesWritten < (ssize_t)fCharsSize) { 199 if (bytesWritten < 0) 200 return bytesWritten; 201 return B_IO_ERROR; 202 } 203 204 file.WriteAttr("keymap:name", B_STRING_TYPE, 0, fName, strlen(fName)); 205 // Failing would be non-fatal 206 207 return B_OK; 208 } 209 210 211 bool 212 Keymap::Equals(const Keymap& other) const 213 { 214 // not really efficient but this is the only way i found 215 // to reliably compare keymaps (used only for apply and revert) 216 return fCharsSize == other.fCharsSize 217 && !memcmp(&other.fKeys, &fKeys, sizeof(key_map)) 218 && !memcmp(other.fChars, fChars, fCharsSize); 219 } 220 221 222 /*! We need to know if a key is a modifier key to choose 223 a valid key when several are pressed together. 224 */ 225 bool 226 Keymap::IsModifierKey(uint32 keyCode) 227 { 228 return keyCode == fKeys.caps_key 229 || keyCode == fKeys.num_key 230 || keyCode == fKeys.scroll_key 231 || keyCode == fKeys.left_shift_key 232 || keyCode == fKeys.right_shift_key 233 || keyCode == fKeys.left_command_key 234 || keyCode == fKeys.right_command_key 235 || keyCode == fKeys.left_control_key 236 || keyCode == fKeys.right_control_key 237 || keyCode == fKeys.left_option_key 238 || keyCode == fKeys.right_option_key 239 || keyCode == fKeys.menu_key; 240 } 241 242 243 //! We need to know a modifier for a key 244 uint32 245 Keymap::Modifier(uint32 keyCode) 246 { 247 if (keyCode == fKeys.caps_key) 248 return B_CAPS_LOCK; 249 if (keyCode == fKeys.num_key) 250 return B_NUM_LOCK; 251 if (keyCode == fKeys.scroll_key) 252 return B_SCROLL_LOCK; 253 if (keyCode == fKeys.left_shift_key) 254 return B_LEFT_SHIFT_KEY | B_SHIFT_KEY; 255 if (keyCode == fKeys.right_shift_key) 256 return B_RIGHT_SHIFT_KEY | B_SHIFT_KEY; 257 if (keyCode == fKeys.left_command_key) 258 return B_LEFT_COMMAND_KEY | B_COMMAND_KEY; 259 if (keyCode == fKeys.right_command_key) 260 return B_RIGHT_COMMAND_KEY | B_COMMAND_KEY; 261 if (keyCode == fKeys.left_control_key) 262 return B_LEFT_CONTROL_KEY | B_CONTROL_KEY; 263 if (keyCode == fKeys.right_control_key) 264 return B_RIGHT_CONTROL_KEY | B_CONTROL_KEY; 265 if (keyCode == fKeys.left_option_key) 266 return B_LEFT_OPTION_KEY | B_OPTION_KEY; 267 if (keyCode == fKeys.right_option_key) 268 return B_RIGHT_OPTION_KEY | B_OPTION_KEY; 269 if (keyCode == fKeys.menu_key) 270 return B_MENU_KEY; 271 272 return 0; 273 } 274 275 276 uint32 277 Keymap::KeyForModifier(uint32 modifier) 278 { 279 if (modifier == B_CAPS_LOCK) 280 return fKeys.caps_key; 281 if (modifier == B_NUM_LOCK) 282 return fKeys.num_key; 283 if (modifier == B_SCROLL_LOCK) 284 return fKeys.scroll_key; 285 if (modifier == B_LEFT_SHIFT_KEY || modifier == B_SHIFT_KEY) 286 return fKeys.left_shift_key; 287 if (modifier == B_RIGHT_SHIFT_KEY) 288 return fKeys.right_shift_key; 289 if (modifier == B_LEFT_COMMAND_KEY || modifier == B_COMMAND_KEY) 290 return fKeys.left_command_key; 291 if (modifier == B_RIGHT_COMMAND_KEY) 292 return fKeys.right_command_key; 293 if (modifier == B_LEFT_CONTROL_KEY || modifier == B_CONTROL_KEY) 294 return fKeys.left_control_key; 295 if (modifier == B_RIGHT_CONTROL_KEY) 296 return fKeys.right_control_key; 297 if (modifier == B_LEFT_OPTION_KEY || modifier == B_OPTION_KEY) 298 return fKeys.left_option_key; 299 if (modifier == B_RIGHT_OPTION_KEY) 300 return fKeys.right_option_key; 301 if (modifier == B_MENU_KEY) 302 return fKeys.menu_key; 303 304 return 0; 305 } 306 307 308 status_t 309 Keymap::SetModifier(uint32 keyCode, uint32 modifier) 310 { 311 const uint32 kSingleKeys = B_LEFT_SHIFT_KEY | B_RIGHT_SHIFT_KEY 312 | B_LEFT_COMMAND_KEY | B_RIGHT_COMMAND_KEY | B_LEFT_CONTROL_KEY 313 | B_RIGHT_CONTROL_KEY | B_LEFT_OPTION_KEY | B_RIGHT_OPTION_KEY; 314 315 if ((modifier & kSingleKeys) != 0) 316 modifier &= kSingleKeys; 317 else if ((modifier & kModifierKeys) != 0) 318 modifier &= kModifierKeys; 319 320 if (modifier == B_CAPS_LOCK) 321 fKeys.caps_key = keyCode; 322 else if (modifier == B_NUM_LOCK) 323 fKeys.num_key = keyCode; 324 else if (modifier == B_SCROLL_LOCK) 325 fKeys.scroll_key = keyCode; 326 else if (modifier == B_LEFT_SHIFT_KEY) 327 fKeys.left_shift_key = keyCode; 328 else if (modifier == B_RIGHT_SHIFT_KEY) 329 fKeys.right_shift_key = keyCode; 330 else if (modifier == B_LEFT_COMMAND_KEY) 331 fKeys.left_command_key = keyCode; 332 else if (modifier == B_RIGHT_COMMAND_KEY) 333 fKeys.right_command_key = keyCode; 334 else if (modifier == B_LEFT_CONTROL_KEY) 335 fKeys.left_control_key = keyCode; 336 else if (modifier == B_RIGHT_CONTROL_KEY) 337 fKeys.right_control_key = keyCode; 338 else if (modifier == B_LEFT_OPTION_KEY) 339 fKeys.left_option_key = keyCode; 340 else if (modifier == B_RIGHT_OPTION_KEY) 341 fKeys.right_option_key = keyCode; 342 else if (modifier == B_MENU_KEY) 343 fKeys.menu_key = keyCode; 344 else 345 return B_BAD_VALUE; 346 347 if (fModificationMessage != NULL) 348 fTarget.SendMessage(fModificationMessage); 349 350 return B_OK; 351 } 352 353 354 //! Checks whether a key is a dead key. 355 uint8 356 Keymap::IsDeadKey(uint32 keyCode, uint32 modifiers) 357 { 358 if (fChars == NULL) 359 return 0; 360 361 uint32 tableMask = 0; 362 int32 offset = _Offset(keyCode, modifiers, &tableMask); 363 if (offset <= 0) 364 return 0; 365 366 uint32 numBytes = fChars[offset]; 367 if (!numBytes) 368 return 0; 369 370 char chars[4]; 371 strncpy(chars, &fChars[offset + 1], numBytes); 372 chars[numBytes] = 0; 373 374 int32 deadOffsets[] = { 375 fKeys.acute_dead_key[1], 376 fKeys.grave_dead_key[1], 377 fKeys.circumflex_dead_key[1], 378 fKeys.dieresis_dead_key[1], 379 fKeys.tilde_dead_key[1] 380 }; 381 382 uint32 deadTables[] = { 383 fKeys.acute_tables, 384 fKeys.grave_tables, 385 fKeys.circumflex_tables, 386 fKeys.dieresis_tables, 387 fKeys.tilde_tables 388 }; 389 390 for (int32 i = 0; i < 5; i++) { 391 if ((deadTables[i] & tableMask) == 0) 392 continue; 393 394 if (offset == deadOffsets[i]) 395 return i + 1; 396 397 uint32 deadNumBytes = fChars[deadOffsets[i]]; 398 if (!deadNumBytes) 399 continue; 400 401 if (strncmp(chars, &fChars[deadOffsets[i] + 1], deadNumBytes) == 0) 402 return i + 1; 403 } 404 return 0; 405 } 406 407 408 //! Tell if a key is a dead second key, needed for draw a dead second key. 409 bool 410 Keymap::IsDeadSecondKey(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey) 411 { 412 if (!activeDeadKey) 413 return false; 414 415 int32 offset = _Offset(keyCode, modifiers); 416 if (offset < 0) 417 return false; 418 419 uint32 numBytes = fChars[offset]; 420 if (!numBytes) 421 return false; 422 423 int32* deadOffsets[] = { 424 fKeys.acute_dead_key, 425 fKeys.grave_dead_key, 426 fKeys.circumflex_dead_key, 427 fKeys.dieresis_dead_key, 428 fKeys.tilde_dead_key 429 }; 430 431 int32 *deadOffset = deadOffsets[activeDeadKey - 1]; 432 433 for (int32 i=0; i<32; i++) { 434 if (offset == deadOffset[i]) 435 return true; 436 437 uint32 deadNumBytes = fChars[deadOffset[i]]; 438 439 if (!deadNumBytes) 440 continue; 441 442 if (strncmp(&fChars[offset + 1], &fChars[deadOffset[i] + 1], 443 deadNumBytes) == 0) 444 return true; 445 i++; 446 } 447 return false; 448 } 449 450 451 //! Get the char for a key given modifiers and active dead key 452 void 453 Keymap::GetChars(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey, 454 char** chars, int32* numBytes) 455 { 456 *numBytes = 0; 457 *chars = NULL; 458 459 if (keyCode > 128 || fChars == NULL) 460 return; 461 462 // here we take NUMLOCK into account 463 if ((modifiers & B_NUM_LOCK) != 0) { 464 switch (keyCode) { 465 case 0x37: 466 case 0x38: 467 case 0x39: 468 case 0x48: 469 case 0x49: 470 case 0x4a: 471 case 0x58: 472 case 0x59: 473 case 0x5a: 474 case 0x64: 475 case 0x65: 476 modifiers ^= B_SHIFT_KEY; 477 } 478 } 479 480 int32 offset = _Offset(keyCode, modifiers); 481 if (offset < 0) 482 return; 483 484 // here we get the char size 485 *numBytes = fChars[offset]; 486 if (!*numBytes) 487 return; 488 489 // here we take an potential active dead key 490 int32 *deadKey; 491 switch (activeDeadKey) { 492 case 1: deadKey = fKeys.acute_dead_key; break; 493 case 2: deadKey = fKeys.grave_dead_key; break; 494 case 3: deadKey = fKeys.circumflex_dead_key; break; 495 case 4: deadKey = fKeys.dieresis_dead_key; break; 496 case 5: deadKey = fKeys.tilde_dead_key; break; 497 default: 498 { 499 // if not dead, we copy and return the char 500 char *str = *chars = new char[*numBytes + 1]; 501 strncpy(str, &fChars[offset + 1], *numBytes); 502 str[*numBytes] = 0; 503 return; 504 } 505 } 506 507 // if dead key, we search for our current offset char in the dead key 508 // offset table string comparison is needed 509 for (int32 i = 0; i < 32; i++) { 510 if (strncmp(&fChars[offset + 1], &fChars[deadKey[i] + 1], *numBytes) 511 == 0) { 512 *numBytes = fChars[deadKey[i + 1]]; 513 514 switch (*numBytes) { 515 case 0: 516 // Not mapped 517 *chars = NULL; 518 break; 519 default: 520 { 521 // 1-, 2-, 3-, or 4-byte UTF-8 character 522 char *str = *chars = new char[*numBytes + 1]; 523 strncpy(str, &fChars[deadKey[i + 1] + 1], *numBytes); 524 str[*numBytes] = 0; 525 break; 526 } 527 } 528 return; 529 } 530 i++; 531 } 532 533 // if not found we return the current char mapped 534 *chars = new char[*numBytes + 1]; 535 strncpy(*chars, &fChars[offset + 1], *numBytes); 536 (*chars)[*numBytes] = 0; 537 } 538 539 540 //! We make our input server use the map in /boot/home/config/settings/Keymap 541 status_t 542 Keymap::Use() 543 { 544 return _restore_key_map_(); 545 } 546 547 548 void 549 Keymap::SetKey(uint32 keyCode, uint32 modifiers, int8 deadKey, 550 const char* bytes, int32 numBytes) 551 { 552 int32 offset = _Offset(keyCode, modifiers); 553 if (offset < 0) 554 return; 555 556 if (numBytes == -1) 557 numBytes = strlen(bytes); 558 if (numBytes > 6) 559 return; 560 561 int32 oldNumBytes = fChars[offset]; 562 563 if (oldNumBytes == numBytes 564 && !memcmp(&fChars[offset + 1], bytes, numBytes)) { 565 // nothing to do 566 return; 567 } 568 569 // TODO: handle dead keys! 570 571 int32 diff = numBytes - oldNumBytes; 572 if (diff != 0) { 573 fCharsSize += diff; 574 575 if (diff > 0) { 576 // make space for the new data 577 char* chars = new(std::nothrow) char[fCharsSize]; 578 if (chars != NULL) { 579 memcpy(chars, fChars, offset + oldNumBytes + 1); 580 memcpy(&chars[offset + 1 + numBytes], 581 &fChars[offset + 1 + oldNumBytes], 582 fCharsSize - 2 - offset - diff); 583 delete[] fChars; 584 fChars = chars; 585 } else 586 return; 587 } else if (diff < 0) { 588 // shrink table 589 memmove(&fChars[offset + numBytes], &fChars[offset + oldNumBytes], 590 fCharsSize - offset - 2 - diff); 591 } 592 593 // update offsets 594 595 int32* data = fKeys.control_map; 596 int32 size = sizeof(fKeys.control_map) / 4 * 9 597 + sizeof(fKeys.acute_dead_key) / 4 * 5; 598 for (int32 i = 0; i < size; i++) { 599 if (data[i] > offset) 600 data[i] += diff; 601 } 602 } 603 604 memcpy(&fChars[offset + 1], bytes, numBytes); 605 fChars[offset] = numBytes; 606 607 if (fModificationMessage != NULL) 608 fTarget.SendMessage(fModificationMessage); 609 } 610 611 612 Keymap& 613 Keymap::operator=(const Keymap& other) 614 { 615 if (this == &other) 616 return *this; 617 618 delete[] fChars; 619 delete fModificationMessage; 620 621 fChars = new(std::nothrow) char[other.fCharsSize]; 622 if (fChars != NULL) { 623 memcpy(fChars, other.fChars, other.fCharsSize); 624 fCharsSize = other.fCharsSize; 625 } else 626 fCharsSize = 0; 627 628 memcpy(&fKeys, &other.fKeys, sizeof(key_map)); 629 strlcpy(fName, other.fName, sizeof(fName)); 630 631 fTarget = other.fTarget; 632 633 if (other.fModificationMessage != NULL) 634 fModificationMessage = new BMessage(*other.fModificationMessage); 635 636 return *this; 637 } 638 639 640 int32 641 Keymap::_Offset(uint32 keyCode, uint32 modifiers, uint32* _table) 642 { 643 int32 offset; 644 uint32 table; 645 646 if (keyCode >= 128) 647 return -1; 648 649 switch (modifiers & kModifierKeys) { 650 case B_SHIFT_KEY: 651 offset = fKeys.shift_map[keyCode]; 652 table = B_SHIFT_TABLE; 653 break; 654 case B_CAPS_LOCK: 655 offset = fKeys.caps_map[keyCode]; 656 table = B_CAPS_TABLE; 657 break; 658 case B_CAPS_LOCK | B_SHIFT_KEY: 659 offset = fKeys.caps_shift_map[keyCode]; 660 table = B_CAPS_SHIFT_TABLE; 661 break; 662 case B_OPTION_KEY: 663 offset = fKeys.option_map[keyCode]; 664 table = B_OPTION_TABLE; 665 break; 666 case B_OPTION_KEY | B_SHIFT_KEY: 667 offset = fKeys.option_shift_map[keyCode]; 668 table = B_OPTION_SHIFT_TABLE; 669 break; 670 case B_OPTION_KEY | B_CAPS_LOCK: 671 offset = fKeys.option_caps_map[keyCode]; 672 table = B_OPTION_CAPS_TABLE; 673 break; 674 case B_OPTION_KEY | B_SHIFT_KEY | B_CAPS_LOCK: 675 offset = fKeys.option_caps_shift_map[keyCode]; 676 table = B_OPTION_CAPS_SHIFT_TABLE; 677 break; 678 case B_CONTROL_KEY: 679 offset = fKeys.control_map[keyCode]; 680 table = B_CONTROL_TABLE; 681 break; 682 default: 683 offset = fKeys.normal_map[keyCode]; 684 table = B_NORMAL_TABLE; 685 break; 686 } 687 688 if (_table != NULL) 689 *_table = table; 690 691 if (offset >= (int32)fCharsSize) 692 return -1; 693 694 return offset; 695 } 696