Change all global shortcuts to use virtual keycodes.
The original logic to make two shortcuts cmd + '{' and cmd + '}' use key
characters instead of virtual keycodes was done to match behavior of terminal
and Safari back in 2009 for international keyboards. Both of those apps have
since changed their behavior, but Chrome was not updated.
Bug: 851095
Change-Id: I3414ca784419b81bb8aacd53aa6cc2a1a8ec8c19
Reviewed-on: https://chromium-review.googlesource.com/1093696
Commit-Queue: Erik Chen <[email protected]>
Reviewed-by: Nico Weber <[email protected]>
Cr-Commit-Position: refs/heads/master@{#565849}
diff --git a/chrome/browser/global_keyboard_shortcuts_mac.mm b/chrome/browser/global_keyboard_shortcuts_mac.mm
index f548f85..6f05681 100644
--- a/chrome/browser/global_keyboard_shortcuts_mac.mm
+++ b/chrome/browser/global_keyboard_shortcuts_mac.mm
@@ -76,110 +76,15 @@
return -1;
}
-// Returns a keyboard event character for the given |event|. In most cases
-// this returns the first character of [NSEvent charactersIgnoringModifiers],
-// but when [NSEvent character] has different printable ascii character
-// we may return the first character of [NSEvent characters] instead.
-// (E.g. for dvorak-qwerty layout we want [NSEvent characters] rather than
-// [charactersIgnoringModifiers] for command keys. Similarly, on german
-// layout we want '{' character rather than '8' for opt-8.)
-unichar KeyCharacterForEvent(NSEvent* event) {
- NSString* eventString = [event charactersIgnoringModifiers];
- NSString* characters = [event characters];
-
- if ([eventString length] != 1)
- return 0;
-
- if ([characters length] != 1)
- return [eventString characterAtIndex:0];
-
- // Some characters are BiDi mirrored. The mirroring is different
- // for different OS versions. Instead of having a mirror table, map
- // raw/processed pairs to desired outputs.
- const struct {
- unichar rawChar;
- unichar unmodChar;
- unichar targetChar;
- } kCharMapping[] = {
- // OSX 10.8 mirrors certain chars.
- {'{', '}', '{'},
- {'}', '{', '}'},
- {'(', ')', '('},
- {')', '(', ')'},
-
- // OSX 10.9 has the unshifted raw char.
- {'[', '}', '{'},
- {']', '{', '}'},
- {'9', ')', '('},
- {'0', '(', ')'},
-
- // These are the same either way.
- {'[', ']', '['},
- {']', '[', ']'},
- };
-
- unichar noModifiersChar = [eventString characterAtIndex:0];
- unichar rawChar = [characters characterAtIndex:0];
-
- // Only apply transformation table for ascii.
- if (isascii(noModifiersChar) && isascii(rawChar)) {
- // Alphabetic characters aren't mirrored, go with the raw character.
- // [A previous partial comment said something about Dvorak?]
- if (isalpha(rawChar))
- return rawChar;
-
- // http://crbug.com/42517
- // http://crbug.com/315379
- // In RTL keyboard layouts, Cocoa mirrors characters in the string
- // returned by [event charactersIgnoringModifiers]. In this case, return
- // the raw (unmirrored) char.
- for (size_t i = 0; i < base::size(kCharMapping); ++i) {
- if (rawChar == kCharMapping[i].rawChar &&
- noModifiersChar == kCharMapping[i].unmodChar) {
- return kCharMapping[i].targetChar;
- }
- }
-
- // opt/alt modifier is set (e.g. on german layout we want '{' for opt-8).
- if ([event modifierFlags] & NSAlternateKeyMask)
- return rawChar;
- }
-
- return noModifiersChar;
-}
-
bool MatchesEventForKeyboardShortcut(const KeyboardShortcutData& shortcut,
bool command_key,
bool shift_key,
bool cntrl_key,
bool opt_key,
- int vkey_code,
- unichar key_char) {
- // Expects that one of |key_char| or |vkey_code| is 0.
- DCHECK((shortcut.key_char == 0) ^ (shortcut.vkey_code == 0));
- if (shortcut.key_char) {
- // Shortcuts that have a |key_char| and have |opt_key| set are mistakes,
- // since |opt_key| is not checked when there is a |key_char|.
- DCHECK(!shortcut.opt_key);
- // The given shortcut key is to be matched by a keyboard character.
- // In this case we ignore shift and opt (alt) key modifiers, because
- // the character may be generated by a combination with those keys.
- if (shortcut.command_key == command_key &&
- shortcut.cntrl_key == cntrl_key && shortcut.key_char == key_char) {
- return true;
- }
- } else if (shortcut.vkey_code) {
- // The given shortcut key is to be matched by a virtual key code.
- if (shortcut.command_key == command_key &&
- shortcut.shift_key == shift_key &&
- shortcut.cntrl_key == cntrl_key &&
- shortcut.opt_key == opt_key &&
- shortcut.vkey_code == vkey_code)
- return true;
- } else {
- NOTREACHED(); // Shouldn't happen.
- }
- return false;
+ int vkey_code) {
+ return shortcut.command_key == command_key &&
+ shortcut.shift_key == shift_key && shortcut.cntrl_key == cntrl_key &&
+ shortcut.opt_key == opt_key && shortcut.vkey_code == vkey_code;
}
} // namespace
@@ -187,46 +92,40 @@
const std::vector<KeyboardShortcutData>& GetShortcutsNotPresentInMainMenu() {
// clang-format off
static base::NoDestructor<std::vector<KeyboardShortcutData>> keys({
- //cmd shift cntrl option vkeycode char command
- //--- ----- ----- ------ -------- ---- -------
- // '{' / '}' characters should be matched earlier than virtual key codes
- // (so we can match alt-8 as '{' on German keyboards).
- {true, false, false, false, 0, '}', IDC_SELECT_NEXT_TAB},
- {true, false, false, false, 0, '{', IDC_SELECT_PREVIOUS_TAB},
- {true, true, false, false, kVK_ANSI_RightBracket, 0, IDC_SELECT_NEXT_TAB},
- {true, true, false, false, kVK_ANSI_LeftBracket, 0, IDC_SELECT_PREVIOUS_TAB},
- {false, false, true, false, kVK_PageDown, 0, IDC_SELECT_NEXT_TAB},
- {false, false, true, false, kVK_Tab, 0, IDC_SELECT_NEXT_TAB},
- {false, false, true, false, kVK_PageUp, 0, IDC_SELECT_PREVIOUS_TAB},
- {false, true, true, false, kVK_Tab, 0, IDC_SELECT_PREVIOUS_TAB},
+ //cmd shift cntrl option vkeycode command
+ //--- ----- ----- ------ -------- -------
+ {true, true, false, false, kVK_ANSI_RightBracket, IDC_SELECT_NEXT_TAB},
+ {true, true, false, false, kVK_ANSI_LeftBracket, IDC_SELECT_PREVIOUS_TAB},
+ {false, false, true, false, kVK_PageDown, IDC_SELECT_NEXT_TAB},
+ {false, false, true, false, kVK_Tab, IDC_SELECT_NEXT_TAB},
+ {false, false, true, false, kVK_PageUp, IDC_SELECT_PREVIOUS_TAB},
+ {false, true, true, false, kVK_Tab, IDC_SELECT_PREVIOUS_TAB},
- //cmd shift cntrl option vkeycode char command
- //--- ----- ----- ------ -------- ---- -------
// Cmd-0..8 select the nth tab, with cmd-9 being "last tab".
- {true, false, false, false, kVK_ANSI_1, 0, IDC_SELECT_TAB_0},
- {true, false, false, false, kVK_ANSI_Keypad1, 0, IDC_SELECT_TAB_0},
- {true, false, false, false, kVK_ANSI_2, 0, IDC_SELECT_TAB_1},
- {true, false, false, false, kVK_ANSI_Keypad2, 0, IDC_SELECT_TAB_1},
- {true, false, false, false, kVK_ANSI_3, 0, IDC_SELECT_TAB_2},
- {true, false, false, false, kVK_ANSI_Keypad3, 0, IDC_SELECT_TAB_2},
- {true, false, false, false, kVK_ANSI_4, 0, IDC_SELECT_TAB_3},
- {true, false, false, false, kVK_ANSI_Keypad4, 0, IDC_SELECT_TAB_3},
- {true, false, false, false, kVK_ANSI_5, 0, IDC_SELECT_TAB_4},
- {true, false, false, false, kVK_ANSI_Keypad5, 0, IDC_SELECT_TAB_4},
- {true, false, false, false, kVK_ANSI_6, 0, IDC_SELECT_TAB_5},
- {true, false, false, false, kVK_ANSI_Keypad6, 0, IDC_SELECT_TAB_5},
- {true, false, false, false, kVK_ANSI_7, 0, IDC_SELECT_TAB_6},
- {true, false, false, false, kVK_ANSI_Keypad7, 0, IDC_SELECT_TAB_6},
- {true, false, false, false, kVK_ANSI_8, 0, IDC_SELECT_TAB_7},
- {true, false, false, false, kVK_ANSI_Keypad8, 0, IDC_SELECT_TAB_7},
- {true, false, false, false, kVK_ANSI_9, 0, IDC_SELECT_LAST_TAB},
- {true, false, false, false, kVK_ANSI_Keypad9, 0, IDC_SELECT_LAST_TAB},
- {true, true, false, false, kVK_ANSI_M, 0, IDC_SHOW_AVATAR_MENU},
- {true, false, false, true, kVK_ANSI_L, 0, IDC_SHOW_DOWNLOADS},
+ {true, false, false, false, kVK_ANSI_1, IDC_SELECT_TAB_0},
+ {true, false, false, false, kVK_ANSI_Keypad1, IDC_SELECT_TAB_0},
+ {true, false, false, false, kVK_ANSI_2, IDC_SELECT_TAB_1},
+ {true, false, false, false, kVK_ANSI_Keypad2, IDC_SELECT_TAB_1},
+ {true, false, false, false, kVK_ANSI_3, IDC_SELECT_TAB_2},
+ {true, false, false, false, kVK_ANSI_Keypad3, IDC_SELECT_TAB_2},
+ {true, false, false, false, kVK_ANSI_4, IDC_SELECT_TAB_3},
+ {true, false, false, false, kVK_ANSI_Keypad4, IDC_SELECT_TAB_3},
+ {true, false, false, false, kVK_ANSI_5, IDC_SELECT_TAB_4},
+ {true, false, false, false, kVK_ANSI_Keypad5, IDC_SELECT_TAB_4},
+ {true, false, false, false, kVK_ANSI_6, IDC_SELECT_TAB_5},
+ {true, false, false, false, kVK_ANSI_Keypad6, IDC_SELECT_TAB_5},
+ {true, false, false, false, kVK_ANSI_7, IDC_SELECT_TAB_6},
+ {true, false, false, false, kVK_ANSI_Keypad7, IDC_SELECT_TAB_6},
+ {true, false, false, false, kVK_ANSI_8, IDC_SELECT_TAB_7},
+ {true, false, false, false, kVK_ANSI_Keypad8, IDC_SELECT_TAB_7},
+ {true, false, false, false, kVK_ANSI_9, IDC_SELECT_LAST_TAB},
+ {true, false, false, false, kVK_ANSI_Keypad9, IDC_SELECT_LAST_TAB},
+ {true, true, false, false, kVK_ANSI_M, IDC_SHOW_AVATAR_MENU},
+ {true, false, false, true, kVK_ANSI_L, IDC_SHOW_DOWNLOADS},
- {true, false, false, false, kVK_LeftArrow, 0, IDC_BACK},
- {true, false, false, false, kVK_RightArrow, 0, IDC_FORWARD},
- {true, true, false, false, kVK_ANSI_C, 0, IDC_DEV_TOOLS_INSPECT},
+ {true, false, false, false, kVK_LeftArrow, IDC_BACK},
+ {true, false, false, false, kVK_RightArrow, IDC_FORWARD},
+ {true, true, false, false, kVK_ANSI_C, IDC_DEV_TOOLS_INSPECT},
});
// clang-format on
return *keys;
@@ -248,13 +147,12 @@
const bool cntrlKey = (modifiers & NSControlKeyMask) != 0;
const bool optKey = (modifiers & NSAlternateKeyMask) != 0;
const int keyCode = [event keyCode];
- const unichar keyChar = KeyCharacterForEvent(event);
// Scan through keycodes and see if it corresponds to one of the non-menu
// shortcuts.
for (const auto& shortcut : GetShortcutsNotPresentInMainMenu()) {
if (MatchesEventForKeyboardShortcut(shortcut, cmdKey, shiftKey, cntrlKey,
- optKey, keyCode, keyChar)) {
+ optKey, keyCode)) {
return shortcut.chrome_command;
}
}
@@ -279,9 +177,7 @@
ui::Accelerator* accelerator) {
// See if it corresponds to one of the non-menu shortcuts.
for (const auto& shortcut : GetShortcutsNotPresentInMainMenu()) {
- // TODO(erikchen): If necessary, add support for shortcuts that do not have
- // a vkey_code. https://crbug.com/846893.
- if (shortcut.chrome_command == command_id && shortcut.vkey_code != 0) {
+ if (shortcut.chrome_command == command_id) {
NSUInteger cocoa_modifiers = 0;
if (shortcut.command_key)
cocoa_modifiers |= NSEventModifierFlagCommand;