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