1 /* 2 * Copyright 2011-2014 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * John Scipione, jscipione@gmail.com 7 */ 8 9 10 #include "ModifierKeysWindow.h" 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 16 #include <Bitmap.h> 17 #include <Button.h> 18 #include <Catalog.h> 19 #include <CheckBox.h> 20 #include <FindDirectory.h> 21 #include <IconUtils.h> 22 #include <InterfaceDefs.h> 23 #include <LayoutBuilder.h> 24 #include <Locale.h> 25 #include <MenuField.h> 26 #include <MenuItem.h> 27 #include <Message.h> 28 #include <Path.h> 29 #include <PopUpMenu.h> 30 #include <Resources.h> 31 #include <SeparatorView.h> 32 #include <Size.h> 33 #include <StringView.h> 34 35 #include "KeymapApplication.h" 36 37 38 #ifdef DEBUG_ALERT 39 # define FTRACE(x) fprintf(x) 40 #else 41 # define FTRACE(x) /* nothing */ 42 #endif 43 44 45 enum { 46 SHIFT_KEY = 0x00000001, 47 CONTROL_KEY = 0x00000002, 48 OPTION_KEY = 0x00000004, 49 COMMAND_KEY = 0x00000008 50 }; 51 52 enum { 53 MENU_ITEM_SHIFT = 0, 54 MENU_ITEM_CONTROL, 55 MENU_ITEM_OPTION, 56 MENU_ITEM_COMMAND, 57 MENU_ITEM_SEPERATOR, 58 MENU_ITEM_DISABLED 59 }; 60 61 62 static const uint32 kMsgHideShowIcons = 'icon'; 63 static const uint32 kMsgUpdateModifier = 'upmd'; 64 static const uint32 kMsgApplyModifiers = 'apmd'; 65 static const uint32 kMsgRevertModifiers = 'rvmd'; 66 67 68 #undef B_TRANSLATION_CONTEXT 69 #define B_TRANSLATION_CONTEXT "Modifier keys window" 70 71 72 // #pragma mark - ConflictView 73 74 75 ConflictView::ConflictView(const char* name) 76 : 77 BView(BRect(0, 0, 15, 15), name, B_FOLLOW_NONE, B_WILL_DRAW), 78 fIcon(NULL), 79 fStopIcon(NULL), 80 fWarnIcon(NULL) 81 { 82 _FillIcons(); 83 } 84 85 86 ConflictView::~ConflictView() 87 { 88 delete fStopIcon; 89 delete fWarnIcon; 90 } 91 92 93 void 94 ConflictView::Draw(BRect updateRect) 95 { 96 // Draw background 97 if (Parent()) 98 SetLowColor(Parent()->ViewColor()); 99 else 100 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 101 102 FillRect(updateRect, B_SOLID_LOW); 103 104 if (fIcon == NULL) 105 return; 106 107 // Draw icon 108 SetDrawingMode(B_OP_ALPHA); 109 SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 110 DrawBitmapAsync(fIcon, BPoint(0, 0)); 111 } 112 113 114 // get the icon 115 BBitmap* 116 ConflictView::Icon() 117 { 118 return fIcon; 119 } 120 121 122 // show or hide the stop icon 123 void 124 ConflictView::SetStopIcon(bool show) 125 { 126 fIcon = show ? fStopIcon : NULL; 127 const char* tip = show ? B_TRANSLATE("Error: duplicate keys") 128 : NULL; 129 SetToolTip(tip); 130 } 131 132 133 // show or hide the warn icon 134 void 135 ConflictView::SetWarnIcon(bool show) 136 { 137 fIcon = show ? fWarnIcon : NULL; 138 const char* tip = show 139 ? B_TRANSLATE("Warning: left and right key roles do not match") 140 : NULL; 141 SetToolTip(tip); 142 } 143 144 145 // #pragma mark - ConflictView private methods 146 147 148 // fill out the icons with the stop and warn symbols from app_server 149 void 150 ConflictView::_FillIcons() 151 { 152 // return if the icons have already been filled out 153 if (fStopIcon != NULL && fStopIcon->InitCheck() == B_OK 154 && fWarnIcon != NULL && fWarnIcon->InitCheck() == B_OK) { 155 return; 156 } 157 158 BPath path; 159 status_t status = find_directory(B_BEOS_SERVERS_DIRECTORY, &path); 160 if (status < B_OK) { 161 FTRACE((stderr, 162 "_FillIcons() - find_directory failed: %s\n", 163 strerror(status))); 164 return; 165 } 166 167 path.Append("app_server"); 168 BFile file; 169 status = file.SetTo(path.Path(), B_READ_ONLY); 170 if (status < B_OK) { 171 FTRACE((stderr, 172 "_FillIcons() - BFile init failed: %s\n", 173 strerror(status))); 174 return; 175 } 176 177 BResources resources; 178 status = resources.SetTo(&file); 179 if (status < B_OK) { 180 FTRACE((stderr, 181 "_FillIcons() - BResources init failed: %s\n", 182 strerror(status))); 183 return; 184 } 185 186 size_t size = 0; 187 188 if (fStopIcon == NULL) { 189 // Allocate the fStopIcon bitmap 190 fStopIcon = new (std::nothrow) BBitmap(BRect(0, 0, 15, 15), 0, 191 B_RGBA32); 192 if (fStopIcon->InitCheck() != B_OK) { 193 FTRACE((stderr, "_FillIcons() - No memory for stop bitmap\n")); 194 delete fStopIcon; 195 fStopIcon = NULL; 196 return; 197 } 198 199 // load stop icon bitmap from app_server 200 const uint8* stopVector 201 = (const uint8*)resources.LoadResource(B_VECTOR_ICON_TYPE, "stop", 202 &size); 203 if (stopVector == NULL 204 || BIconUtils::GetVectorIcon(stopVector, size, fStopIcon) 205 != B_OK) { 206 delete fStopIcon; 207 fStopIcon = NULL; 208 } 209 } 210 211 if (fWarnIcon == NULL) { 212 // Allocate the fWarnIcon bitmap 213 fWarnIcon = new (std::nothrow) BBitmap(BRect(0, 0, 15, 15), 0, 214 B_RGBA32); 215 if (fWarnIcon->InitCheck() != B_OK) { 216 FTRACE((stderr, "_FillIcons() - No memory for warn bitmap\n")); 217 delete fWarnIcon; 218 fWarnIcon = NULL; 219 return; 220 } 221 222 // load warn icon bitmap from app_server 223 const uint8* warnVector 224 = (const uint8*)resources.LoadResource(B_VECTOR_ICON_TYPE, "warn", 225 &size); 226 if (warnVector == NULL 227 || BIconUtils::GetVectorIcon(warnVector, size, fWarnIcon) 228 != B_OK) { 229 delete fWarnIcon; 230 fWarnIcon = NULL; 231 } 232 } 233 } 234 235 236 // #pragma mark - ModifierKeysWindow 237 238 239 ModifierKeysWindow::ModifierKeysWindow() 240 : 241 BWindow(BRect(0, 0, 360, 220), B_TRANSLATE("Modifier keys"), 242 B_FLOATING_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE 243 | B_AUTO_UPDATE_SIZE_LIMITS) 244 { 245 get_key_map(&fCurrentMap, &fCurrentBuffer); 246 get_key_map(&fSavedMap, &fSavedBuffer); 247 248 BStringView* keyRole = new BStringView("key role", 249 B_TRANSLATE_COMMENT("Role", "As in the role of a modifier key")); 250 keyRole->SetAlignment(B_ALIGN_RIGHT); 251 keyRole->SetFont(be_bold_font); 252 253 BStringView* keyLabel = new BStringView("key label", 254 B_TRANSLATE_COMMENT("Key", "As in a computer keyboard key")); 255 keyLabel->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 256 keyLabel->SetFont(be_bold_font); 257 258 BMenuField* shiftMenuField = _CreateShiftMenuField(); 259 shiftMenuField->SetAlignment(B_ALIGN_RIGHT); 260 261 BMenuField* controlMenuField = _CreateControlMenuField(); 262 controlMenuField->SetAlignment(B_ALIGN_RIGHT); 263 264 BMenuField* optionMenuField = _CreateOptionMenuField(); 265 optionMenuField->SetAlignment(B_ALIGN_RIGHT); 266 267 BMenuField* commandMenuField = _CreateCommandMenuField(); 268 commandMenuField->SetAlignment(B_ALIGN_RIGHT); 269 270 fShiftConflictView = new ConflictView("shift warning view"); 271 fShiftConflictView->SetExplicitMaxSize(BSize(15, 15)); 272 273 fControlConflictView = new ConflictView("control warning view"); 274 fControlConflictView->SetExplicitMaxSize(BSize(15, 15)); 275 276 fOptionConflictView = new ConflictView("option warning view"); 277 fOptionConflictView->SetExplicitMaxSize(BSize(15, 15)); 278 279 fCommandConflictView = new ConflictView("command warning view"); 280 fCommandConflictView->SetExplicitMaxSize(BSize(15, 15)); 281 282 fCancelButton = new BButton("cancelButton", B_TRANSLATE("Cancel"), 283 new BMessage(B_QUIT_REQUESTED)); 284 285 fRevertButton = new BButton("revertButton", B_TRANSLATE("Revert"), 286 new BMessage(kMsgRevertModifiers)); 287 fRevertButton->SetEnabled(false); 288 289 fOkButton = new BButton("okButton", B_TRANSLATE("Set modifier keys"), 290 new BMessage(kMsgApplyModifiers)); 291 fOkButton->MakeDefault(true); 292 293 BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_DEFAULT_SPACING) 294 .AddGrid(B_USE_DEFAULT_SPACING, B_USE_SMALL_SPACING) 295 .Add(keyRole, 0, 0) 296 .Add(keyLabel, 1, 0) 297 298 .Add(shiftMenuField->CreateLabelLayoutItem(), 0, 1) 299 .AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 1, 1) 300 .Add(shiftMenuField->CreateMenuBarLayoutItem()) 301 .Add(fShiftConflictView) 302 .End() 303 304 .Add(controlMenuField->CreateLabelLayoutItem(), 0, 2) 305 .AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 1, 2) 306 .Add(controlMenuField->CreateMenuBarLayoutItem()) 307 .Add(fControlConflictView) 308 .End() 309 310 .Add(optionMenuField->CreateLabelLayoutItem(), 0, 3) 311 .AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 1, 3) 312 .Add(optionMenuField->CreateMenuBarLayoutItem()) 313 .Add(fOptionConflictView) 314 .End() 315 316 .Add(commandMenuField->CreateLabelLayoutItem(), 0, 4) 317 .AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 1, 4) 318 .Add(commandMenuField->CreateMenuBarLayoutItem()) 319 .Add(fCommandConflictView) 320 .End() 321 .End() 322 .AddGlue() 323 .AddGroup(B_HORIZONTAL) 324 .Add(fCancelButton) 325 .AddGlue() 326 .Add(fRevertButton) 327 .Add(fOkButton) 328 .End() 329 .SetInsets(B_USE_WINDOW_SPACING) 330 .End(); 331 332 _MarkMenuItems(); 333 _ValidateDuplicateKeys(); 334 335 PostMessage(kMsgHideShowIcons); 336 } 337 338 339 ModifierKeysWindow::~ModifierKeysWindow() 340 { 341 be_app->PostMessage(kMsgCloseModifierKeysWindow); 342 } 343 344 345 void 346 ModifierKeysWindow::MessageReceived(BMessage* message) 347 { 348 switch (message->what) { 349 case kMsgHideShowIcons: 350 _HideShowIcons(); 351 break; 352 353 case kMsgUpdateModifier: 354 { 355 int32 menuitem = MENU_ITEM_SHIFT; 356 int32 key = -1; 357 358 for (; menuitem <= MENU_ITEM_COMMAND; menuitem++) { 359 if (message->FindInt32(_KeyToString(menuitem), &key) == B_OK) 360 break; 361 } 362 363 if (key == -1) 364 return; 365 366 // menuitem contains the item we want to set 367 // key contains the item we want to set it to. 368 369 switch (menuitem) { 370 case MENU_ITEM_SHIFT: 371 fCurrentMap->left_shift_key = _KeyToKeyCode(key); 372 fCurrentMap->right_shift_key = _KeyToKeyCode(key, true); 373 break; 374 375 case MENU_ITEM_CONTROL: 376 fCurrentMap->left_control_key = _KeyToKeyCode(key); 377 fCurrentMap->right_control_key = _KeyToKeyCode(key, true); 378 break; 379 380 case MENU_ITEM_OPTION: 381 fCurrentMap->left_option_key = _KeyToKeyCode(key); 382 fCurrentMap->right_option_key = _KeyToKeyCode(key, true); 383 break; 384 385 case MENU_ITEM_COMMAND: 386 fCurrentMap->left_command_key = _KeyToKeyCode(key); 387 fCurrentMap->right_command_key = _KeyToKeyCode(key, true); 388 break; 389 } 390 391 _MarkMenuItems(); 392 _ValidateDuplicateKeys(); 393 _HideShowIcons(); 394 395 // enable/disable revert button 396 fRevertButton->SetEnabled( 397 memcmp(fCurrentMap, fSavedMap, sizeof(key_map))); 398 break; 399 } 400 401 // OK button 402 case kMsgApplyModifiers: 403 { 404 // if duplicate modifiers are found, don't update 405 if (_DuplicateKeys() != 0) 406 break; 407 408 BMessage* updateModifiers = new BMessage(kMsgUpdateModifierKeys); 409 410 if (fCurrentMap->left_shift_key != fSavedMap->left_shift_key) { 411 updateModifiers->AddUInt32("left_shift_key", 412 fCurrentMap->left_shift_key); 413 } 414 415 if (fCurrentMap->right_shift_key != fSavedMap->right_shift_key) { 416 updateModifiers->AddUInt32("right_shift_key", 417 fCurrentMap->right_shift_key); 418 } 419 420 if (fCurrentMap->left_control_key != fSavedMap->left_control_key) { 421 updateModifiers->AddUInt32("left_control_key", 422 fCurrentMap->left_control_key); 423 } 424 425 if (fCurrentMap->right_control_key 426 != fSavedMap->right_control_key) { 427 updateModifiers->AddUInt32("right_control_key", 428 fCurrentMap->right_control_key); 429 } 430 431 if (fCurrentMap->left_option_key != fSavedMap->left_option_key) { 432 updateModifiers->AddUInt32("left_option_key", 433 fCurrentMap->left_option_key); 434 } 435 436 if (fCurrentMap->right_option_key != fSavedMap->right_option_key) { 437 updateModifiers->AddUInt32("right_option_key", 438 fCurrentMap->right_option_key); 439 } 440 441 if (fCurrentMap->left_command_key != fSavedMap->left_command_key) { 442 updateModifiers->AddUInt32("left_command_key", 443 fCurrentMap->left_command_key); 444 } 445 446 if (fCurrentMap->right_command_key 447 != fSavedMap->right_command_key) { 448 updateModifiers->AddUInt32("right_command_key", 449 fCurrentMap->right_command_key); 450 } 451 452 // KeymapWindow updates the modifiers 453 be_app->PostMessage(updateModifiers); 454 455 // we are done here, close the window 456 this->PostMessage(B_QUIT_REQUESTED); 457 break; 458 } 459 460 // Revert button 461 case kMsgRevertModifiers: 462 memcpy(fCurrentMap, fSavedMap, sizeof(key_map)); 463 464 _MarkMenuItems(); 465 _ValidateDuplicateKeys(); 466 _HideShowIcons(); 467 468 fRevertButton->SetEnabled(false); 469 break; 470 471 default: 472 BWindow::MessageReceived(message); 473 } 474 } 475 476 477 // #pragma mark - ModifierKeysWindow private methods 478 479 480 BMenuField* 481 ModifierKeysWindow::_CreateShiftMenuField() 482 { 483 fShiftMenu = new BPopUpMenu( 484 B_TRANSLATE_NOCOLLECT(_KeyToString(MENU_ITEM_SHIFT)), true, true); 485 486 for (int32 key = MENU_ITEM_SHIFT; key <= MENU_ITEM_DISABLED; key++) { 487 if (key == MENU_ITEM_SEPERATOR) { 488 // add separator item 489 BSeparatorItem* separator = new BSeparatorItem; 490 fShiftMenu->AddItem(separator, MENU_ITEM_SEPERATOR); 491 continue; 492 } 493 494 BMessage* message = new BMessage(kMsgUpdateModifier); 495 message->AddInt32(_KeyToString(MENU_ITEM_SHIFT), key); 496 BMenuItem* item = new BMenuItem( 497 B_TRANSLATE_NOCOLLECT(_KeyToString(key)), message); 498 499 fShiftMenu->AddItem(item, key); 500 } 501 502 fShiftMenu->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH, 503 B_ALIGN_VERTICAL_UNSET)); 504 505 return new BMenuField(B_TRANSLATE_COMMENT("Shift:", "Shift key role name"), 506 fShiftMenu); 507 } 508 509 510 BMenuField* 511 ModifierKeysWindow::_CreateControlMenuField() 512 { 513 fControlMenu = new BPopUpMenu( 514 B_TRANSLATE_NOCOLLECT(_KeyToString(MENU_ITEM_CONTROL)), true, true); 515 516 for (int32 key = MENU_ITEM_SHIFT; key <= MENU_ITEM_DISABLED; key++) { 517 if (key == MENU_ITEM_SEPERATOR) { 518 // add separator item 519 BSeparatorItem* separator = new BSeparatorItem; 520 fControlMenu->AddItem(separator, MENU_ITEM_SEPERATOR); 521 continue; 522 } 523 524 BMessage* message = new BMessage(kMsgUpdateModifier); 525 message->AddInt32(_KeyToString(MENU_ITEM_CONTROL), key); 526 BMenuItem* item = new BMenuItem( 527 B_TRANSLATE_NOCOLLECT(_KeyToString(key)), message); 528 529 fControlMenu->AddItem(item, key); 530 } 531 532 fControlMenu->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH, 533 B_ALIGN_VERTICAL_UNSET)); 534 535 return new BMenuField(B_TRANSLATE_COMMENT("Control:", 536 "Control key role name"), fControlMenu); 537 } 538 539 540 BMenuField* 541 ModifierKeysWindow::_CreateOptionMenuField() 542 { 543 fOptionMenu = new BPopUpMenu( 544 B_TRANSLATE_NOCOLLECT(_KeyToString(MENU_ITEM_OPTION)), true, true); 545 546 for (int32 key = MENU_ITEM_SHIFT; key <= MENU_ITEM_DISABLED; key++) { 547 if (key == MENU_ITEM_SEPERATOR) { 548 // add separator item 549 BSeparatorItem* separator = new BSeparatorItem; 550 fOptionMenu->AddItem(separator, MENU_ITEM_SEPERATOR); 551 continue; 552 } 553 554 BMessage* message = new BMessage(kMsgUpdateModifier); 555 message->AddInt32(_KeyToString(MENU_ITEM_OPTION), key); 556 BMenuItem* item = new BMenuItem( 557 B_TRANSLATE_NOCOLLECT(_KeyToString(key)), message); 558 559 fOptionMenu->AddItem(item, key); 560 } 561 562 fOptionMenu->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH, 563 B_ALIGN_VERTICAL_UNSET)); 564 565 return new BMenuField(B_TRANSLATE_COMMENT("Option:", 566 "Option key role name"), fOptionMenu); 567 } 568 569 570 BMenuField* 571 ModifierKeysWindow::_CreateCommandMenuField() 572 { 573 fCommandMenu = new BPopUpMenu( 574 B_TRANSLATE_NOCOLLECT(_KeyToString(MENU_ITEM_COMMAND)), true, true); 575 576 for (int32 key = MENU_ITEM_SHIFT; key <= MENU_ITEM_DISABLED; key++) { 577 if (key == MENU_ITEM_SEPERATOR) { 578 // add separator item 579 BSeparatorItem* separator = new BSeparatorItem; 580 fCommandMenu->AddItem(separator, MENU_ITEM_SEPERATOR); 581 continue; 582 } 583 584 BMessage* message = new BMessage(kMsgUpdateModifier); 585 message->AddInt32(_KeyToString(MENU_ITEM_COMMAND), key); 586 BMenuItem* item = new BMenuItem( 587 B_TRANSLATE_NOCOLLECT(_KeyToString(key)), message); 588 fCommandMenu->AddItem(item, key); 589 } 590 591 fCommandMenu->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH, 592 B_ALIGN_VERTICAL_UNSET)); 593 594 return new BMenuField(B_TRANSLATE_COMMENT("Command:", 595 "Command key role name"), fCommandMenu); 596 } 597 598 599 void 600 ModifierKeysWindow::_MarkMenuItems() 601 { 602 for (int32 key = MENU_ITEM_SHIFT; key <= MENU_ITEM_DISABLED; key++) { 603 if (key == MENU_ITEM_SEPERATOR) 604 continue; 605 606 if (fCurrentMap->left_shift_key == _KeyToKeyCode(key) 607 && fCurrentMap->right_shift_key == _KeyToKeyCode(key, true)) { 608 fShiftMenu->ItemAt(key)->SetMarked(true); 609 } 610 611 if (fCurrentMap->left_control_key == _KeyToKeyCode(key) 612 && fCurrentMap->right_control_key == _KeyToKeyCode(key, true)) { 613 fControlMenu->ItemAt(key)->SetMarked(true); 614 } 615 616 if (fCurrentMap->left_option_key == _KeyToKeyCode(key) 617 && fCurrentMap->right_option_key == _KeyToKeyCode(key, true)) { 618 fOptionMenu->ItemAt(key)->SetMarked(true); 619 } 620 621 if (fCurrentMap->left_command_key == _KeyToKeyCode(key) 622 && fCurrentMap->right_command_key == _KeyToKeyCode(key, true)) { 623 fCommandMenu->ItemAt(key)->SetMarked(true); 624 } 625 } 626 627 // Set the warning icon if not marked 628 BBitmap* shiftIcon = fShiftConflictView->Icon(); 629 BBitmap* controlIcon = fControlConflictView->Icon(); 630 BBitmap* optionIcon = fOptionConflictView->Icon(); 631 BBitmap* commandIcon = fCommandConflictView->Icon(); 632 633 fShiftConflictView->SetWarnIcon(fShiftMenu->FindMarked() == NULL); 634 fControlConflictView->SetWarnIcon(fControlMenu->FindMarked() == NULL); 635 fOptionConflictView->SetWarnIcon(fOptionMenu->FindMarked() == NULL); 636 fCommandConflictView->SetWarnIcon(fCommandMenu->FindMarked() == NULL); 637 638 // if there was a change invalidate the view 639 if (shiftIcon != fShiftConflictView->Icon()) 640 fShiftConflictView->Invalidate(); 641 642 if (controlIcon != fControlConflictView->Icon()) 643 fControlConflictView->Invalidate(); 644 645 if (optionIcon != fOptionConflictView->Icon()) 646 fOptionConflictView->Invalidate(); 647 648 if (commandIcon != fCommandConflictView->Icon()) 649 fCommandConflictView->Invalidate(); 650 } 651 652 653 // get the string for a modifier key 654 const char* 655 ModifierKeysWindow::_KeyToString(int32 key) 656 { 657 switch (key) { 658 case MENU_ITEM_SHIFT: 659 return B_TRANSLATE_COMMENT("Shift key", 660 "Label of key above Ctrl, usually Shift"); 661 662 case MENU_ITEM_CONTROL: 663 return B_TRANSLATE_COMMENT("Ctrl key", 664 "Label of key farthest from the spacebar, usually Ctrl" 665 "e.g. Strg for German keyboard"); 666 667 case MENU_ITEM_OPTION: 668 return B_TRANSLATE_COMMENT("Win/Cmd key", 669 "Label of the \"Windows\" key (PC)/Command key (Mac)"); 670 671 case MENU_ITEM_COMMAND: 672 return B_TRANSLATE_COMMENT("Alt/Opt key", 673 "Label of Alt key (PC)/Option key (Mac)"); 674 675 case MENU_ITEM_DISABLED: 676 return B_TRANSLATE_COMMENT("Disabled", "Do nothing"); 677 } 678 679 return ""; 680 } 681 682 683 // get the keycode for a modifier key 684 uint32 685 ModifierKeysWindow::_KeyToKeyCode(int32 key, bool right) 686 { 687 switch (key) { 688 case MENU_ITEM_SHIFT: 689 if (right) 690 return 0x56; 691 return 0x4b; 692 693 case MENU_ITEM_CONTROL: 694 if (right) 695 return 0x60; 696 return 0x5c; 697 698 case MENU_ITEM_OPTION: 699 if (right) 700 return 0x67; 701 return 0x66; 702 703 case MENU_ITEM_COMMAND: 704 if (right) 705 return 0x5f; 706 return 0x5d; 707 708 case MENU_ITEM_DISABLED: 709 return 0; 710 } 711 712 return 0; 713 } 714 715 716 // validate duplicate keys 717 void 718 ModifierKeysWindow::_ValidateDuplicateKeys() 719 { 720 uint32 dupMask = _DuplicateKeys(); 721 722 BBitmap* shiftIcon = fShiftConflictView->Icon(); 723 BBitmap* controlIcon = fControlConflictView->Icon(); 724 BBitmap* optionIcon = fOptionConflictView->Icon(); 725 BBitmap* commandIcon = fCommandConflictView->Icon(); 726 727 if ((dupMask & SHIFT_KEY) != 0) 728 fShiftConflictView->SetStopIcon(true); 729 730 if ((dupMask & CONTROL_KEY) != 0) 731 fControlConflictView->SetStopIcon(true); 732 733 if ((dupMask & OPTION_KEY) != 0) 734 fOptionConflictView->SetStopIcon(true); 735 736 if ((dupMask & COMMAND_KEY) != 0) 737 fCommandConflictView->SetStopIcon(true); 738 739 fOkButton->SetEnabled(dupMask == 0); 740 741 // if there was a change invalidate the view 742 if (shiftIcon != fShiftConflictView->Icon()) 743 fShiftConflictView->Invalidate(); 744 745 if (controlIcon != fControlConflictView->Icon()) 746 fControlConflictView->Invalidate(); 747 748 if (optionIcon != fOptionConflictView->Icon()) 749 fOptionConflictView->Invalidate(); 750 751 if (commandIcon != fCommandConflictView->Icon()) 752 fCommandConflictView->Invalidate(); 753 } 754 755 756 // return a mask marking which keys are duplicates of each other for 757 // validation. Shift = 0, Control = 1, Option = 2, Command = 3 758 uint32 759 ModifierKeysWindow::_DuplicateKeys() 760 { 761 uint32 duplicateMask = 0; 762 763 for (int32 testKey = MENU_ITEM_SHIFT; testKey <= MENU_ITEM_COMMAND; 764 testKey++) { 765 uint32 testLeft = 0; 766 uint32 testRight = 0; 767 768 switch (testKey) { 769 case MENU_ITEM_SHIFT: 770 testLeft = fCurrentMap->left_shift_key; 771 testRight = fCurrentMap->right_shift_key; 772 break; 773 774 case MENU_ITEM_CONTROL: 775 testLeft = fCurrentMap->left_control_key; 776 testRight = fCurrentMap->right_control_key; 777 break; 778 779 case MENU_ITEM_OPTION: 780 testLeft = fCurrentMap->left_option_key; 781 testRight = fCurrentMap->right_option_key; 782 break; 783 784 case MENU_ITEM_COMMAND: 785 testLeft = fCurrentMap->left_command_key; 786 testRight = fCurrentMap->right_command_key; 787 break; 788 } 789 790 if (testLeft == 0 && testRight == 0) 791 continue; 792 793 for (int32 key = MENU_ITEM_SHIFT; key <= MENU_ITEM_COMMAND; key++) { 794 if (key == testKey) { 795 // skip over yourself 796 continue; 797 } 798 799 uint32 left = 0; 800 uint32 right = 0; 801 802 switch (key) { 803 case MENU_ITEM_SHIFT: 804 left = fCurrentMap->left_shift_key; 805 right = fCurrentMap->right_shift_key; 806 break; 807 808 case MENU_ITEM_CONTROL: 809 left = fCurrentMap->left_control_key; 810 right = fCurrentMap->right_control_key; 811 break; 812 813 case MENU_ITEM_OPTION: 814 left = fCurrentMap->left_option_key; 815 right = fCurrentMap->right_option_key; 816 break; 817 818 case MENU_ITEM_COMMAND: 819 left = fCurrentMap->left_command_key; 820 right = fCurrentMap->right_command_key; 821 break; 822 } 823 824 if (left == 0 && right == 0) 825 continue; 826 827 if (left == testLeft || right == testRight) { 828 duplicateMask |= 1 << testKey; 829 duplicateMask |= 1 << key; 830 } 831 } 832 } 833 834 return duplicateMask; 835 } 836 837 838 void 839 ModifierKeysWindow::_HideShowIcons() 840 { 841 if (fShiftConflictView->Icon() == NULL) { 842 while (!fShiftConflictView->IsHidden()) 843 fShiftConflictView->Hide(); 844 } else { 845 while (fShiftConflictView->IsHidden()) 846 fShiftConflictView->Show(); 847 } 848 849 if (fControlConflictView->Icon() == NULL) { 850 while (!fControlConflictView->IsHidden()) 851 fControlConflictView->Hide(); 852 } else { 853 while (fControlConflictView->IsHidden()) 854 fControlConflictView->Show(); 855 } 856 857 if (fOptionConflictView->Icon() == NULL) { 858 while (!fOptionConflictView->IsHidden()) 859 fOptionConflictView->Hide(); 860 } else { 861 while (fOptionConflictView->IsHidden()) 862 fOptionConflictView->Show(); 863 } 864 865 if (fCommandConflictView->Icon() == NULL) { 866 while (!fCommandConflictView->IsHidden()) 867 fCommandConflictView->Hide(); 868 } else { 869 while (fCommandConflictView->IsHidden()) 870 fCommandConflictView->Show(); 871 } 872 } 873