diff --git a/src/preferences/keymap/KeyboardLayoutView.cpp b/src/preferences/keymap/KeyboardLayoutView.cpp index a5763d3615..44efb7906c 100644 --- a/src/preferences/keymap/KeyboardLayoutView.cpp +++ b/src/preferences/keymap/KeyboardLayoutView.cpp @@ -26,6 +26,7 @@ KeyboardLayoutView::KeyboardLayoutView(const char* name) : BView(name, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS), fOffscreenBitmap(NULL), fKeymap(NULL), + fEditable(true), fModifiers(0), fDeadKey(0), fDragKey(NULL), @@ -180,16 +181,17 @@ KeyboardLayoutView::MouseMoved(BPoint point, uint32 transit, return; if (dragMessage != NULL) { - _InvalidateKey(fDropTarget); - fDropPoint = point; + if (fEditable) { + _InvalidateKey(fDropTarget); + fDropPoint = point; - _EvaluateDropTarget(point); + _EvaluateDropTarget(point); + } } else if (fDragKey == NULL && (fabs(point.x - fClickPoint.x) > 4 || fabs(point.y - fClickPoint.y) > 4)) { // start dragging Key* key = _KeyAt(fClickPoint); - // TODO: remove once we support moving modifier keys around - if (key == NULL || fKeymap->IsModifierKey(key->code)) + if (key == NULL) return; BRect frame = _FrameFor(key); @@ -294,7 +296,9 @@ KeyboardLayoutView::Draw(BRect updateRect) void KeyboardLayoutView::MessageReceived(BMessage* message) { - if (message->WasDropped() && fDropTarget != NULL && fKeymap != NULL) { + if (message->WasDropped() && fEditable && fDropTarget != NULL + && fKeymap != NULL) { + int32 keyCode; const char* data; ssize_t size; if (message->FindData("text/plain", B_MIME_DATA, @@ -303,7 +307,6 @@ KeyboardLayoutView::MessageReceived(BMessage* message) if (data[size - 1] == '\0') size--; - int32 keyCode; int32 buttons; if (!message->IsSourceRemote() && message->FindInt32("buttons", &buttons) == B_OK @@ -320,11 +323,18 @@ KeyboardLayoutView::MessageReceived(BMessage* message) fKeymap->GetChars(fDropTarget->code, fModifiers, fDeadKey, &string, &numBytes); if (string != NULL) { + // switch keys fKeymap->SetKey(fDropTarget->code, fModifiers, fDeadKey, (const char*)data, size); fKeymap->SetKey(key->code, fDragModifiers, fDeadKey, string, numBytes); delete[] string; + } else if (fKeymap->IsModifierKey(fDropTarget->code)) { + // switch key with modifier + fKeymap->SetModifier(key->code, + fKeymap->Modifier(fDropTarget->code)); + fKeymap->SetKey(fDropTarget->code, fModifiers, fDeadKey, + (const char*)data, size); } } else { // Send the old key to the target, so it's not lost entirely @@ -333,6 +343,32 @@ KeyboardLayoutView::MessageReceived(BMessage* message) fKeymap->SetKey(fDropTarget->code, fModifiers, fDeadKey, (const char*)data, size); } + } else if (!message->IsSourceRemote() + && message->FindInt32("key", &keyCode) == B_OK) { + // Switch an unmapped key + + Key* key = _KeyForCode(keyCode); + if (key != NULL && key == fDropTarget) + return; + + uint32 modifier = fKeymap->Modifier(keyCode); + + char* string; + int32 numBytes; + fKeymap->GetChars(fDropTarget->code, fModifiers, fDeadKey, + &string, &numBytes); + if (string != NULL) { + // switch key with modifier + fKeymap->SetModifier(fDropTarget->code, modifier); + fKeymap->SetKey(keyCode, fDragModifiers, fDeadKey, + string, numBytes); + delete[] string; + } else { + // switch modifier keys + fKeymap->SetModifier(keyCode, + fKeymap->Modifier(fDropTarget->code)); + fKeymap->SetModifier(fDropTarget->code, modifier); + } } _InvalidateKey(fDropTarget); diff --git a/src/preferences/keymap/KeyboardLayoutView.h b/src/preferences/keymap/KeyboardLayoutView.h index 4c7604334e..b94ae51c67 100644 --- a/src/preferences/keymap/KeyboardLayoutView.h +++ b/src/preferences/keymap/KeyboardLayoutView.h @@ -27,6 +27,8 @@ public: void SetFont(const BFont& font); + void SetEditable(bool editable); + protected: virtual void AttachedToWindow(); virtual void FrameResized(float width, float height); @@ -88,6 +90,7 @@ private: KeyboardLayout* fLayout; Keymap* fKeymap; BMessenger fTarget; + bool fEditable; uint8 fKeyState[16]; int32 fModifiers; diff --git a/src/preferences/keymap/Keymap.cpp b/src/preferences/keymap/Keymap.cpp index d121e2208e..3540eec2c9 100644 --- a/src/preferences/keymap/Keymap.cpp +++ b/src/preferences/keymap/Keymap.cpp @@ -305,6 +305,52 @@ Keymap::KeyForModifier(uint32 modifier) } +status_t +Keymap::SetModifier(uint32 keyCode, uint32 modifier) +{ + const uint32 kSingleKeys = B_LEFT_SHIFT_KEY | B_RIGHT_SHIFT_KEY + | B_LEFT_COMMAND_KEY | B_RIGHT_COMMAND_KEY | B_LEFT_CONTROL_KEY + | B_RIGHT_CONTROL_KEY | B_LEFT_OPTION_KEY | B_RIGHT_OPTION_KEY; + + if ((modifier & kSingleKeys) != 0) + modifier &= kSingleKeys; + else if ((modifier & kModifierKeys) != 0) + modifier &= kModifierKeys; + + if (modifier == B_CAPS_LOCK) + fKeys.caps_key = keyCode; + else if (modifier == B_NUM_LOCK) + fKeys.num_key = keyCode; + else if (modifier == B_SCROLL_LOCK) + fKeys.scroll_key = keyCode; + else if (modifier == B_LEFT_SHIFT_KEY) + fKeys.left_shift_key = keyCode; + else if (modifier == B_RIGHT_SHIFT_KEY) + fKeys.right_shift_key = keyCode; + else if (modifier == B_LEFT_COMMAND_KEY) + fKeys.left_command_key = keyCode; + else if (modifier == B_RIGHT_COMMAND_KEY) + fKeys.right_command_key = keyCode; + else if (modifier == B_LEFT_CONTROL_KEY) + fKeys.left_control_key = keyCode; + else if (modifier == B_RIGHT_CONTROL_KEY) + fKeys.right_control_key = keyCode; + else if (modifier == B_LEFT_OPTION_KEY) + fKeys.left_option_key = keyCode; + else if (modifier == B_RIGHT_OPTION_KEY) + fKeys.right_option_key = keyCode; + else if (modifier == B_MENU_KEY) + fKeys.menu_key = keyCode; + else + return B_BAD_VALUE; + + if (fModificationMessage != NULL) + fTarget.SendMessage(fModificationMessage); + + return B_OK; +} + + //! Checks whether a key is a dead key. uint8 Keymap::IsDeadKey(uint32 keyCode, uint32 modifiers) diff --git a/src/preferences/keymap/Keymap.h b/src/preferences/keymap/Keymap.h index 6746949674..28c3123b30 100644 --- a/src/preferences/keymap/Keymap.h +++ b/src/preferences/keymap/Keymap.h @@ -31,6 +31,7 @@ public: bool IsModifierKey(uint32 keyCode); uint32 Modifier(uint32 keyCode); uint32 KeyForModifier(uint32 modifier); + status_t SetModifier(uint32 keyCode, uint32 modifier); uint8 IsDeadKey(uint32 keyCode, uint32 modifiers); bool IsDeadSecondKey(uint32 keyCode, uint32 modifiers, @@ -46,6 +47,7 @@ public: int32 numBytes = -1); const key_map& Map() const { return fKeys; } + key_map& Map() { return fKeys; } private: int32 _Offset(uint32 keyCode, uint32 modifiers, diff --git a/src/preferences/keymap/KeymapWindow.cpp b/src/preferences/keymap/KeymapWindow.cpp index 6cd19be941..77bcf117d7 100644 --- a/src/preferences/keymap/KeymapWindow.cpp +++ b/src/preferences/keymap/KeymapWindow.cpp @@ -39,6 +39,8 @@ static const uint32 kMsgMenuFileSaveAs = 'mMFA'; static const uint32 kChangeKeyboardLayout = 'cKyL'; +static const uint32 kMsgSwitchShortcuts = 'swSc'; + static const uint32 kMsgMenuFontChanged = 'mMFC'; static const uint32 kMsgSystemMapSelected = 'SmST'; @@ -61,6 +63,9 @@ KeymapWindow::KeymapWindow() fTextControl = new BTextControl("Sample and Clipboard:", "", NULL); + fSwitchShortcutsButton = new BButton("switch", "", + new BMessage(kMsgSwitchShortcuts)); + fUseButton = new BButton("useButton", "Use", new BMessage(kMsgUseKeymap)); fRevertButton = new BButton("revertButton", "Revert", new BMessage(kMsgRevertKeymap)); @@ -73,7 +78,9 @@ KeymapWindow::KeymapWindow() .Add(BGroupLayoutBuilder(B_VERTICAL, 10) .Add(fKeyboardLayoutView) //.Add(new BStringView("text label", "Sample and Clipboard:")) - .Add(fTextControl) + .Add(BGroupLayoutBuilder(B_HORIZONTAL, 10) + .Add(fTextControl) + .Add(fSwitchShortcutsButton)) .AddGlue(0.0) .Add(BGroupLayoutBuilder(B_HORIZONTAL, 10) .AddGlue(0.0) @@ -146,6 +153,8 @@ KeymapWindow::KeymapWindow() fPreviousMap.Load(current->EntryRef()); fAppliedMap.Load(current->EntryRef()); + _UpdateShortcutButton(); + Unlock(); } @@ -229,6 +238,10 @@ KeymapWindow::MessageReceived(BMessage* message) break; } + case kMsgSwitchShortcuts: + _SwitchShortcutKeys(); + break; + case kMsgMenuFontChanged: { BMenuItem *item = fFontMenu->FindMarked(); @@ -428,11 +441,54 @@ KeymapWindow::_AddKeyboardLayouts(BMenu* menu) } -void +void +KeymapWindow::_UpdateShortcutButton() +{ + const char* label = "Switch Shortcut Keys"; + if (fCurrentMap.KeyForModifier(B_LEFT_COMMAND_KEY) == 0x5d + && fCurrentMap.KeyForModifier(B_LEFT_CONTROL_KEY) == 0x5c + && fCurrentMap.KeyForModifier(B_RIGHT_OPTION_KEY) == 0x5f + && fCurrentMap.KeyForModifier(B_RIGHT_CONTROL_KEY) == 0x60) { + label = "Switch Shortcut Keys To Windows/Linux Mode"; + } else if (fCurrentMap.KeyForModifier(B_LEFT_COMMAND_KEY) == 0x5c + && fCurrentMap.KeyForModifier(B_LEFT_CONTROL_KEY) == 0x5d + && fCurrentMap.KeyForModifier(B_RIGHT_OPTION_KEY) == 0x60 + && fCurrentMap.KeyForModifier(B_RIGHT_CONTROL_KEY) == 0x5f) { + label = "Switch Shortcut Keys To Haiku Mode"; + } + + fSwitchShortcutsButton->SetLabel(label); +} + + +void KeymapWindow::_UpdateButtons() { fUseButton->SetEnabled(!fCurrentMap.Equals(fAppliedMap)); fRevertButton->SetEnabled(!fCurrentMap.Equals(fPreviousMap)); + + _UpdateShortcutButton(); +} + + +void +KeymapWindow::_SwitchShortcutKeys() +{ + uint32 leftCommand = fCurrentMap.Map().left_command_key; + uint32 leftControl = fCurrentMap.Map().left_control_key; + uint32 rightOption = fCurrentMap.Map().right_option_key; + uint32 rightControl = fCurrentMap.Map().right_control_key; + + // switch left side + fCurrentMap.Map().left_command_key = leftControl; + fCurrentMap.Map().left_control_key = leftCommand; + + // switch right side + fCurrentMap.Map().right_option_key = rightControl; + fCurrentMap.Map().right_control_key = rightOption; + + fKeyboardLayoutView->SetKeymap(&fCurrentMap); + _UpdateButtons(); } diff --git a/src/preferences/keymap/KeymapWindow.h b/src/preferences/keymap/KeymapWindow.h index 746c5467ae..111085f095 100644 --- a/src/preferences/keymap/KeymapWindow.h +++ b/src/preferences/keymap/KeymapWindow.h @@ -39,7 +39,9 @@ protected: BView* _CreateMapLists(); void _AddKeyboardLayouts(BMenu* menu); + void _UpdateShortcutButton(); void _UpdateButtons(); + void _SwitchShortcutKeys(); void _UseKeymap(); void _RevertKeymap(); @@ -61,6 +63,7 @@ protected: BMenu* fFontMenu; KeyboardLayoutView* fKeyboardLayoutView; BTextControl* fTextControl; + BButton* fSwitchShortcutsButton; Keymap fCurrentMap; Keymap fPreviousMap;