From a073305c9669e9a76db294148e6eef1e5ceb2d5e Mon Sep 17 00:00:00 2001 From: John Scipione Date: Wed, 19 Feb 2014 20:38:01 -0500 Subject: [PATCH] keymap: limit set of left/right swap options For Shift, Control, Option, and Command assume that you want to shift on the same side, left-for-left, right-for-right. The Menu key is available on either the left or right side, and lock keys can be swapped with any other modifier left or right. If we have multiple unmapped modifiers we need to do a little extra work to figure out which of the unmapped modifiers to swap with. Convert private class member methods to static functions. Also update copyright info --- src/preferences/keymap/KeyboardLayoutView.cpp | 313 +++++++++++------- src/preferences/keymap/KeyboardLayoutView.h | 10 +- src/preferences/keymap/KeymapWindow.cpp | 37 ++- src/preferences/keymap/KeymapWindow.h | 9 +- 4 files changed, 221 insertions(+), 148 deletions(-) diff --git a/src/preferences/keymap/KeyboardLayoutView.cpp b/src/preferences/keymap/KeyboardLayoutView.cpp index 3705faf1e8..2cb77f0bef 100644 --- a/src/preferences/keymap/KeyboardLayoutView.cpp +++ b/src/preferences/keymap/KeyboardLayoutView.cpp @@ -1,6 +1,11 @@ /* * Copyright 2009-2010, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2013-2014 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + * John Scipione, jscipione@gmail.com */ @@ -33,6 +38,116 @@ static const rgb_color kDeadKeyColor = {152, 203, 255, 255}; static const rgb_color kLitIndicatorColor = {116, 212, 83, 255}; +static const char* +name_for_modifier(uint32 modifier, bool pretty) +{ + if (modifier == B_CAPS_LOCK) + return pretty ? B_TRANSLATE("Caps lock") : "caps_key"; + else if (modifier == B_NUM_LOCK) + return pretty ? B_TRANSLATE("Num lock") : "num_key"; + else if (modifier == B_SCROLL_LOCK) + return pretty ? B_TRANSLATE("Scroll lock") : "scroll_key"; + else if (modifier == B_SHIFT_KEY) { + return pretty ? B_TRANSLATE_COMMENT("Shift", "Shift key") + : "shift_key"; + } else if (modifier == B_LEFT_SHIFT_KEY) + return pretty ? B_TRANSLATE("Left shift") : "left_shift_key"; + else if (modifier == B_RIGHT_SHIFT_KEY) + return pretty ? B_TRANSLATE("Right shift") : "right_shift_key"; + else if (modifier == B_COMMAND_KEY) { + return pretty ? B_TRANSLATE_COMMENT("Command", "Command key") + : "command_key"; + } else if (modifier == B_LEFT_COMMAND_KEY) + return pretty ? B_TRANSLATE("Left command") : "left_command_key"; + else if (modifier == B_RIGHT_COMMAND_KEY) + return pretty ? B_TRANSLATE("Right command") : "right_command_key"; + else if (modifier == B_CONTROL_KEY) { + return pretty ? B_TRANSLATE_COMMENT("Control", "Control key") + : "control_key"; + } else if (modifier == B_LEFT_CONTROL_KEY) + return pretty ? B_TRANSLATE("Left control") : "left_control_key"; + else if (modifier == B_RIGHT_CONTROL_KEY) + return pretty ? B_TRANSLATE("Right control") : "right_control_key"; + else if (modifier == B_OPTION_KEY) { + return pretty ? B_TRANSLATE_COMMENT("Option", "Option key") + : "option_key"; + } else if (modifier == B_LEFT_OPTION_KEY) + return pretty ? B_TRANSLATE("Left option") : "left_option_key"; + else if (modifier == B_RIGHT_OPTION_KEY) + return pretty ? B_TRANSLATE("Right option") : "right_option_key"; + else if (modifier == B_MENU_KEY) + return pretty ? B_TRANSLATE_COMMENT("Menu", "Menu key") : "menu_key"; + + return NULL; +} + + +static BMenuItem* +swap_modifiers_menu_item(Keymap* map, uint32 modifier, uint32 displayModifier, + uint32 oldCode, uint32 newCode) +{ + int32 mask = B_SHIFT_KEY | B_COMMAND_KEY | B_CONTROL_KEY | B_OPTION_KEY; + const char* oldName = name_for_modifier(oldCode == 0x00 ? modifier + : map->Modifier(oldCode) & ~mask, false); + const char* newName = name_for_modifier(newCode == 0x00 ? modifier + : map->Modifier(newCode) & ~mask, false); + + BMessage* message = new BMessage(kMsgUpdateModifierKeys); + if (newName != NULL) + message->AddUInt32(newName, oldCode); + + if (oldName != NULL) + message->AddUInt32(oldName, newCode); + + if (oldCode == newCode) + message->AddBool("unset", true); + + return new BMenuItem(name_for_modifier(displayModifier, true), message); +} + + +static bool +is_left_modifier_key(uint32 keyCode) +{ + return keyCode == 0x4b // left shift + || keyCode == 0x5d // left command + || keyCode == 0x5c // left control + || keyCode == 0x66; // left option +} + + +static bool +is_right_modifier_key(uint32 keyCode) +{ + return keyCode == 0x56 // right shift + || keyCode == 0x5f // right command + || keyCode == 0x60 // right control + || keyCode == 0x67 // right option + || keyCode == 0x68; // menu +} + + +static bool +is_lock_key(uint32 keyCode) +{ + return keyCode == 0x3b // caps lock + || keyCode == 0x22 // num lock + || keyCode == 0x0f; // scroll lock +} + + +static bool +is_mappable_to_modifier(uint32 keyCode) +{ + return is_left_modifier_key(keyCode) + || is_right_modifier_key(keyCode) + || is_lock_key(keyCode); +} + + +// #pragma mark - KeyboardLayoutView + + KeyboardLayoutView::KeyboardLayoutView(const char* name) : BView(name, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS), @@ -164,96 +279,119 @@ KeyboardLayoutView::MouseDown(BPoint point) } if ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0 - || ((buttons & B_PRIMARY_MOUSE_BUTTON) != 0 - && (modifiers() & B_CONTROL_KEY) != 0)) { - if (_IsMappableToModifierKey(key->code)) { - // pop up the modifier keys menu - BPopUpMenu* modifiersPopUp = new BPopUpMenu("Modifiers pop up", - true, true, B_ITEMS_IN_COLUMN); - const key_map& map = fKeymap->Map(); - BMenuItem* item = NULL; + || ((buttons & B_PRIMARY_MOUSE_BUTTON) != 0 + && (modifiers() & B_CONTROL_KEY) != 0)) { + // secondary mouse button, pop up a swap context menu + if (!is_mappable_to_modifier(key->code)) { + // ToDo: pop up a list of alternative characters + fButtons = buttons; + return; + } - item = _SwapModifiersMenuItem(B_LEFT_SHIFT_KEY, key->code, - map.left_shift_key); + // pop up the modifier keys menu + BPopUpMenu* modifiersPopUp = new BPopUpMenu("Modifiers pop up", + true, true, B_ITEMS_IN_COLUMN); + const key_map& map = fKeymap->Map(); + bool isLockKey = is_lock_key(key->code); + BMenuItem* item = NULL; + + if (is_left_modifier_key(key->code) || isLockKey) { + item = swap_modifiers_menu_item(fKeymap, B_LEFT_SHIFT_KEY, + isLockKey ? B_LEFT_SHIFT_KEY : B_SHIFT_KEY, + map.left_shift_key, key->code); modifiersPopUp->AddItem(item); if (key->code == map.left_shift_key) item->SetMarked(true); - item = _SwapModifiersMenuItem(B_LEFT_CONTROL_KEY, key->code, - map.left_control_key); + item = swap_modifiers_menu_item(fKeymap, B_LEFT_CONTROL_KEY, + isLockKey ? B_LEFT_CONTROL_KEY : B_CONTROL_KEY, + map.left_control_key, key->code); modifiersPopUp->AddItem(item); if (key->code == map.left_control_key) item->SetMarked(true); - item = _SwapModifiersMenuItem(B_LEFT_OPTION_KEY, key->code, - map.left_option_key); + item = swap_modifiers_menu_item(fKeymap, B_LEFT_OPTION_KEY, + isLockKey ? B_LEFT_OPTION_KEY : B_OPTION_KEY, + map.left_option_key, key->code); modifiersPopUp->AddItem(item); if (key->code == map.left_option_key) item->SetMarked(true); - item = _SwapModifiersMenuItem(B_LEFT_COMMAND_KEY, key->code, - map.left_command_key); + item = swap_modifiers_menu_item(fKeymap, B_LEFT_COMMAND_KEY, + isLockKey ? B_LEFT_COMMAND_KEY : B_COMMAND_KEY, + map.left_command_key, key->code); modifiersPopUp->AddItem(item); if (key->code == map.left_command_key) item->SetMarked(true); + } - modifiersPopUp->AddSeparatorItem(); + if (is_right_modifier_key(key->code) || isLockKey) { + if (isLockKey) + modifiersPopUp->AddSeparatorItem(); - item = _SwapModifiersMenuItem(B_RIGHT_SHIFT_KEY, - key->code, map.right_shift_key); + item = swap_modifiers_menu_item(fKeymap, B_RIGHT_SHIFT_KEY, + isLockKey ? B_RIGHT_SHIFT_KEY : B_SHIFT_KEY, + map.right_shift_key, key->code); modifiersPopUp->AddItem(item); if (key->code == map.right_shift_key) item->SetMarked(true); - item = _SwapModifiersMenuItem(B_RIGHT_CONTROL_KEY, - key->code, map.right_control_key); + item = swap_modifiers_menu_item(fKeymap, B_RIGHT_CONTROL_KEY, + isLockKey ? B_RIGHT_CONTROL_KEY : B_CONTROL_KEY, + map.right_control_key, key->code); modifiersPopUp->AddItem(item); if (key->code == map.right_control_key) item->SetMarked(true); + } - item = _SwapModifiersMenuItem(B_MENU_KEY, key->code, map.menu_key); - modifiersPopUp->AddItem(item); - if (key->code == map.menu_key) - item->SetMarked(true); + item = swap_modifiers_menu_item(fKeymap, B_MENU_KEY, B_MENU_KEY, + map.menu_key, key->code); + modifiersPopUp->AddItem(item); + if (key->code == map.menu_key) + item->SetMarked(true); - item = _SwapModifiersMenuItem(B_RIGHT_OPTION_KEY, key->code, - map.right_option_key); + if (is_right_modifier_key(key->code) || isLockKey) { + item = swap_modifiers_menu_item(fKeymap, B_RIGHT_OPTION_KEY, + isLockKey ? B_RIGHT_OPTION_KEY : B_OPTION_KEY, + map.right_option_key, key->code); modifiersPopUp->AddItem(item); if (key->code == map.right_option_key) item->SetMarked(true); - item = _SwapModifiersMenuItem(B_RIGHT_COMMAND_KEY, key->code, - map.right_command_key); + item = swap_modifiers_menu_item(fKeymap, B_RIGHT_COMMAND_KEY, + isLockKey ? B_RIGHT_COMMAND_KEY : B_COMMAND_KEY, + map.right_command_key, key->code); modifiersPopUp->AddItem(item); if (key->code == map.right_command_key) item->SetMarked(true); - - modifiersPopUp->AddSeparatorItem(); - - item = _SwapModifiersMenuItem(B_CAPS_LOCK, key->code, - map.caps_key); - modifiersPopUp->AddItem(item); - if (key->code == map.caps_key) - item->SetMarked(true); - - item = _SwapModifiersMenuItem(B_NUM_LOCK, key->code, map.num_key); - modifiersPopUp->AddItem(item); - if (key->code == map.num_key) - item->SetMarked(true); - - item = _SwapModifiersMenuItem(B_SCROLL_LOCK, key->code, - map.scroll_key); - modifiersPopUp->AddItem(item); - if (key->code == map.scroll_key) - item->SetMarked(true); - - modifiersPopUp->SetAsyncAutoDestruct(true); - if (modifiersPopUp->SetTargetForItems(Window()) == B_OK) - modifiersPopUp->Go(ConvertToScreen(point), true); } + + modifiersPopUp->AddSeparatorItem(); + + item = swap_modifiers_menu_item(fKeymap, B_CAPS_LOCK, B_CAPS_LOCK, + map.caps_key, key->code); + modifiersPopUp->AddItem(item); + if (key->code == map.caps_key) + item->SetMarked(true); + + item = swap_modifiers_menu_item(fKeymap, B_NUM_LOCK, B_NUM_LOCK, + map.num_key, key->code); + modifiersPopUp->AddItem(item); + if (key->code == map.num_key) + item->SetMarked(true); + + item = swap_modifiers_menu_item(fKeymap, B_SCROLL_LOCK, B_SCROLL_LOCK, + map.scroll_key, key->code); + modifiersPopUp->AddItem(item); + if (key->code == map.scroll_key) + item->SetMarked(true); + + modifiersPopUp->SetAsyncAutoDestruct(true); + if (modifiersPopUp->SetTargetForItems(Window()) == B_OK) + modifiersPopUp->Go(ConvertToScreen(point), true); } else if ((buttons & B_TERTIARY_MOUSE_BUTTON) != 0 && (fButtons & B_TERTIARY_MOUSE_BUTTON) == 0) { - // toggle the "deadness" of dead keys via middle mouse button + // tertiary mouse button, toggle the "deadness" of dead keys bool isEnabled = false; uint8 deadKey = fKeymap->DeadKey(key->code, fModifiers, &isEnabled); if (deadKey > 0) { @@ -1276,72 +1414,3 @@ KeyboardLayoutView::_SendFakeKeyDown(const Key* key) fTarget.SendMessage(&message); } - - -BMenuItem* -KeyboardLayoutView::_SwapModifiersMenuItem(uint32 modifier, uint32 oldCode, - uint32 newCode) -{ - int32 mask = B_SHIFT_KEY | B_COMMAND_KEY | B_CONTROL_KEY | B_OPTION_KEY; - const char* oldName = _NameForModifier(fKeymap->Modifier(oldCode) & ~mask); - const char* newName = _NameForModifier(fKeymap->Modifier(newCode) & ~mask); - - BMessage* message = new BMessage(kMsgUpdateModifierKeys); - message->AddUInt32(newName, oldCode); - message->AddUInt32(oldName, newCode); - - if (oldCode == newCode) - message->AddBool("unset", true); - - return new BMenuItem(_NameForModifier(modifier, true), message); -} - - -const char* -KeyboardLayoutView::_NameForModifier(uint32 modifier, bool pretty) const -{ - if (modifier == B_CAPS_LOCK) - return pretty ? B_TRANSLATE("Caps lock") : "caps_key"; - else if (modifier == B_NUM_LOCK) - return pretty ? B_TRANSLATE("Num lock") : "num_key"; - else if (modifier == B_SCROLL_LOCK) - return pretty ? B_TRANSLATE("Scroll lock") : "scroll_key"; - else if (modifier == B_LEFT_SHIFT_KEY) - return pretty ? B_TRANSLATE("Left shift") : "left_shift_key"; - else if (modifier == B_RIGHT_SHIFT_KEY) - return pretty ? B_TRANSLATE("Right shift") : "right_shift_key"; - else if (modifier == B_LEFT_COMMAND_KEY) - return pretty ? B_TRANSLATE("Left command") : "left_command_key"; - else if (modifier == B_RIGHT_COMMAND_KEY) - return pretty ? B_TRANSLATE("Right command") : "right_command_key"; - else if (modifier == B_LEFT_CONTROL_KEY) - return pretty ? B_TRANSLATE("Left control") : "left_control_key"; - else if (modifier == B_RIGHT_CONTROL_KEY) - return pretty ? B_TRANSLATE("Right control") : "right_control_key"; - else if (modifier == B_LEFT_OPTION_KEY) - return pretty ? B_TRANSLATE("Left option") : "left_option_key"; - else if (modifier == B_RIGHT_OPTION_KEY) - return pretty ? B_TRANSLATE("Right option") : "right_option_key"; - else if (modifier == B_MENU_KEY) - return pretty ? B_TRANSLATE_COMMENT("Menu", "Menu key") : "menu_key"; - - return NULL; -} - - -bool -KeyboardLayoutView::_IsMappableToModifierKey(uint32 keyCode) const -{ - return keyCode == 0x3b // caps lock - || keyCode == 0x22 // num lock - || keyCode == 0x0f // scroll lock - || keyCode == 0x4b // left shift - || keyCode == 0x56 // right shift - || keyCode == 0x5d // left command - || keyCode == 0x5f // right command - || keyCode == 0x5c // left control - || keyCode == 0x60 // right control - || keyCode == 0x66 // left option - || keyCode == 0x67 // right option - || keyCode == 0x68; // menu -} diff --git a/src/preferences/keymap/KeyboardLayoutView.h b/src/preferences/keymap/KeyboardLayoutView.h index bae153e031..738dbd8352 100644 --- a/src/preferences/keymap/KeyboardLayoutView.h +++ b/src/preferences/keymap/KeyboardLayoutView.h @@ -1,6 +1,11 @@ /* * Copyright 2009, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2013-2014 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + * John Scipione, jscipione@gmail.com */ #ifndef KEYBOARD_LAYOUT_VIEW_H #define KEYBOARD_LAYOUT_VIEW_H @@ -92,11 +97,6 @@ private: void _SetFontSize(BView* view, key_kind keyKind); void _EvaluateDropTarget(BPoint point); void _SendFakeKeyDown(const Key* key); - BMenuItem* _SwapModifiersMenuItem(uint32 modifier, - uint32 oldCode, uint32 newCode); - const char* _NameForModifier(uint32 modifier, - bool pretty = false) const; - bool _IsMappableToModifierKey(uint32 keyCode) const; BBitmap* fOffscreenBitmap; BView* fOffscreenView; diff --git a/src/preferences/keymap/KeymapWindow.cpp b/src/preferences/keymap/KeymapWindow.cpp index 8a855460fa..bee9325d5e 100644 --- a/src/preferences/keymap/KeymapWindow.cpp +++ b/src/preferences/keymap/KeymapWindow.cpp @@ -1,12 +1,13 @@ /* - * Copyright 2004-2010 Haiku Inc. All rights reserved. + * Copyright 2004-2014 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: - * Sandor Vroemisse - * Jérôme Duval * Alexandre Deckner, alex@zappotek.com - * Axel Dörfler, axeld@pinc-software.de. + * Axel Dörfler, axeld@pinc-software.de + * Jérôme Duval + * John Scipione, jscipione@gmai.com + * Sandor Vroemisse */ @@ -325,55 +326,57 @@ KeymapWindow::MessageReceived(BMessage* message) if (message->FindBool("unset", &unset) != B_OK) unset = false; - if (message->FindUInt32("left_shift_key", &keyCode) == B_OK) - fCurrentMap.SetModifier(unset ? 0 : keyCode, B_LEFT_SHIFT_KEY); + if (message->FindUInt32("left_shift_key", &keyCode) == B_OK) { + fCurrentMap.SetModifier(unset ? 0x00 : keyCode, + B_LEFT_SHIFT_KEY); + } if (message->FindUInt32("right_shift_key", &keyCode) == B_OK) { - fCurrentMap.SetModifier(unset ? 0 : keyCode, + fCurrentMap.SetModifier(unset ? 0x00 : keyCode, B_RIGHT_SHIFT_KEY); } if (message->FindUInt32("left_control_key", &keyCode) == B_OK) { - fCurrentMap.SetModifier(unset ? 0 : keyCode, + fCurrentMap.SetModifier(unset ? 0x00 : keyCode, B_LEFT_CONTROL_KEY); } if (message->FindUInt32("right_control_key", &keyCode) == B_OK) { - fCurrentMap.SetModifier(unset ? 0 : keyCode, + fCurrentMap.SetModifier(unset ? 0x00 : keyCode, B_RIGHT_CONTROL_KEY); } if (message->FindUInt32("left_option_key", &keyCode) == B_OK) { - fCurrentMap.SetModifier(unset ? 0 : keyCode, + fCurrentMap.SetModifier(unset ? 0x00 : keyCode, B_LEFT_OPTION_KEY); } if (message->FindUInt32("right_option_key", &keyCode) == B_OK) { - fCurrentMap.SetModifier(unset ? 0 : keyCode, + fCurrentMap.SetModifier(unset ? 0x00 : keyCode, B_RIGHT_OPTION_KEY); } if (message->FindUInt32("left_command_key", &keyCode) == B_OK) { - fCurrentMap.SetModifier(unset ? 0 : keyCode, + fCurrentMap.SetModifier(unset ? 0x00 : keyCode, B_LEFT_COMMAND_KEY); } if (message->FindUInt32("right_command_key", &keyCode) == B_OK) { - fCurrentMap.SetModifier(unset ? 0 : keyCode, + fCurrentMap.SetModifier(unset ? 0x00 : keyCode, B_RIGHT_COMMAND_KEY); } if (message->FindUInt32("menu_key", &keyCode) == B_OK) - fCurrentMap.SetModifier(unset ? 0 : keyCode, B_MENU_KEY); + fCurrentMap.SetModifier(unset ? 0x00 : keyCode, B_MENU_KEY); if (message->FindUInt32("caps_key", &keyCode) == B_OK) - fCurrentMap.SetModifier(unset ? 0 : keyCode, B_CAPS_LOCK); + fCurrentMap.SetModifier(unset ? 0x00 : keyCode, B_CAPS_LOCK); if (message->FindUInt32("num_key", &keyCode) == B_OK) - fCurrentMap.SetModifier(unset ? 0 : keyCode, B_NUM_LOCK); + fCurrentMap.SetModifier(unset ? 0x00 : keyCode, B_NUM_LOCK); if (message->FindUInt32("scroll_key", &keyCode) == B_OK) - fCurrentMap.SetModifier(unset ? 0 : keyCode, B_SCROLL_LOCK); + fCurrentMap.SetModifier(unset ? 0x00 : keyCode, B_SCROLL_LOCK); _UpdateButtons(); fKeyboardLayoutView->SetKeymap(&fCurrentMap); diff --git a/src/preferences/keymap/KeymapWindow.h b/src/preferences/keymap/KeymapWindow.h index 1ef7dc5839..366ba0756f 100644 --- a/src/preferences/keymap/KeymapWindow.h +++ b/src/preferences/keymap/KeymapWindow.h @@ -1,12 +1,13 @@ /* - * Copyright 2004-2009 Haiku Inc. All rights reserved. + * Copyright 2004-2014 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: - * Sandor Vroemisse - * Jérôme Duval * Alexandre Deckner, alex@zappotek.com - * Axel Dörfler, axeld@pinc-software.de. + * Axel Dörfler, axeld@pinc-software.de + * Jérôme Duval + * John Scipione, jscipione@gmai.com + * Sandor Vroemisse */ #ifndef KEYMAP_WINDOW_H #define KEYMAP_WINDOW_H