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