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