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