diff options
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/cocoa/chrome_browser_window.h | 10 | ||||
-rw-r--r-- | chrome/browser/cocoa/chrome_browser_window.mm | 32 | ||||
-rw-r--r-- | chrome/browser/global_keyboard_shortcuts_mac.h | 29 | ||||
-rw-r--r-- | chrome/browser/global_keyboard_shortcuts_mac.mm | 41 | ||||
-rw-r--r-- | chrome/browser/global_keyboard_shortcuts_mac_unittest.cc | 37 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents_view_mac.mm | 15 |
6 files changed, 145 insertions, 19 deletions
diff --git a/chrome/browser/cocoa/chrome_browser_window.h b/chrome/browser/cocoa/chrome_browser_window.h index fb14b28..9130616 100644 --- a/chrome/browser/cocoa/chrome_browser_window.h +++ b/chrome/browser/cocoa/chrome_browser_window.h @@ -15,6 +15,16 @@ BOOL shouldHideTitle_; } +// See global_keyboard_shortcuts_mac.h for details on the next two functions. + +// Checks if |event| is a window keyboard shortcut. If so, dispatches it to the +// window controller's |executeCommand:| and returns |YES|. +- (BOOL)handleExtraWindowKeyboardShortcut:(NSEvent*)event; + +// Checks if |event| is a browser keyboard shortcut. If so, dispatches it to the +// window controller's |executeCommand:| and returns |YES|. +- (BOOL)handleExtraBrowserKeyboardShortcut:(NSEvent*)event; + // Override, so we can handle global keyboard events. - (BOOL)performKeyEquivalent:(NSEvent*)theEvent; diff --git a/chrome/browser/cocoa/chrome_browser_window.mm b/chrome/browser/cocoa/chrome_browser_window.mm index 4f2f859..a6df8d5 100644 --- a/chrome/browser/cocoa/chrome_browser_window.mm +++ b/chrome/browser/cocoa/chrome_browser_window.mm @@ -6,11 +6,15 @@ #include "base/logging.h" #import "chrome/browser/cocoa/browser_window_controller.h" +#import "chrome/browser/renderer_host/render_widget_host_view_mac.h" #include "chrome/browser/global_keyboard_shortcuts_mac.h" +typedef int (*KeyToCommandMapper)(bool, bool, bool, int); + @implementation ChromeBrowserWindow -- (BOOL)performKeyEquivalent:(NSEvent*)event { +- (BOOL)handleExtraKeyboardShortcut:(NSEvent*)event fromTable: + (KeyToCommandMapper)commandForKeyboardShortcut { // Extract info from |event|. NSUInteger modifers = [event modifierFlags]; const bool cmdKey = modifers & NSCommandKeyMask; @@ -18,7 +22,7 @@ const bool cntrlKey = modifers & NSControlKeyMask; const int keyCode = [event keyCode]; - int cmdNum = CommandForKeyboardShortcut(cmdKey, shiftKey, cntrlKey, + int cmdNum = commandForKeyboardShortcut(cmdKey, shiftKey, cntrlKey, keyCode); BrowserWindowController* controller = @@ -31,7 +35,31 @@ [controller executeCommand:cmdNum]; return YES; } + return NO; +} + +- (BOOL)handleExtraWindowKeyboardShortcut:(NSEvent*)event { + return [self handleExtraKeyboardShortcut:event + fromTable:CommandForWindowKeyboardShortcut]; +} +- (BOOL)handleExtraBrowserKeyboardShortcut:(NSEvent*)event { + return [self handleExtraKeyboardShortcut:event + fromTable:CommandForBrowserKeyboardShortcut]; +} + +- (BOOL)performKeyEquivalent:(NSEvent*)event { + // Give the web site a chance to handle the event. If it doesn't want to + // handle it, it will call us back with one of the |handle*| methods above. + NSResponder* r = [self firstResponder]; + if ([r isKindOfClass:[RenderWidgetHostViewCocoa class]]) + return [r performKeyEquivalent:event]; + + // Handle per-window shortcuts like cmd-1, but do not handle browser-level + // shortcuts like cmd-left (else, cmd-left would do history navigation even + // if e.g. the Omnibox has focus). + if ([self handleExtraWindowKeyboardShortcut:event]) + return YES; return [super performKeyEquivalent:event]; } diff --git a/chrome/browser/global_keyboard_shortcuts_mac.h b/chrome/browser/global_keyboard_shortcuts_mac.h index f9a287c..41d26e4 100644 --- a/chrome/browser/global_keyboard_shortcuts_mac.h +++ b/chrome/browser/global_keyboard_shortcuts_mac.h @@ -18,10 +18,33 @@ struct KeyboardShortcutData { // Check if a given keycode + modifiers correspond to a given Chrome command. // returns: Command number (as passed to Browser::ExecuteCommand) or -1 if there // was no match. -int CommandForKeyboardShortcut(bool command_key, bool shift_key, bool cntrl_key, - int vkey_code); +// +// |performKeyEquivalent:| bubbles events up from the window to the views. +// If we let it bubble up to the Omnibox, then the Omnibox handles +// cmd-left/right just fine, but it swallows cmd-1 and doesn't give us a chance +// to intercept this. Hence, we need to types of keyboard shortcuts. +// +// This means cmd-left doesn't work if you hit cmd-l tab, which focusses +// something that's neither omnibox nor tab contents. This behavior is +// consistent with safari and camino, and I think it's the best we can do +// without rewriting event dispatching ( http://crbug.com/251069 ). + +// This returns shortcuts that should work no matter what component of the +// browser is focused. They are executed by the window, before any view has the +// opportunity to override the shortcut (with the exception of the tab contents, +// which first checks if the current web page wants to handle the shortcut). +int CommandForWindowKeyboardShortcut( + bool command_key, bool shift_key, bool cntrl_key, int vkey_code); + +// This returns shortcuts that should work only if the tab contents have focus +// (e.g. cmd-left, which shouldn't do history navigation if e.g. the omnibox has +// focus). +int CommandForBrowserKeyboardShortcut( + bool command_key, bool shift_key, bool cntrl_key, int vkey_code); // For testing purposes. -const KeyboardShortcutData* GetKeyboardShortCutTable(size_t* num_entries); +const KeyboardShortcutData* GetWindowKeyboardShortcutTable(size_t* num_entries); +const KeyboardShortcutData* + GetBrowserKeyboardShortcutTable(size_t* num_entries); #endif // #ifndef CHROME_BROWSER_GLOBAL_KEYBOARD_SHORTCUTS_MAC_H_ diff --git a/chrome/browser/global_keyboard_shortcuts_mac.mm b/chrome/browser/global_keyboard_shortcuts_mac.mm index 63982ef..d74f935 100644 --- a/chrome/browser/global_keyboard_shortcuts_mac.mm +++ b/chrome/browser/global_keyboard_shortcuts_mac.mm @@ -9,7 +9,8 @@ #include "base/basictypes.h" #include "chrome/app/chrome_dll_resource.h" -const KeyboardShortcutData* GetKeyboardShortCutTable(size_t* num_entries) { +const KeyboardShortcutData* GetWindowKeyboardShortcutTable + (size_t* num_entries) { static const KeyboardShortcutData keyboard_shortcuts[] = { {true, true, false, kVK_ANSI_RightBracket, IDC_SELECT_NEXT_TAB}, {false, false, true, kVK_PageDown, IDC_SELECT_NEXT_TAB}, @@ -27,11 +28,6 @@ const KeyboardShortcutData* GetKeyboardShortCutTable(size_t* num_entries) { {true, false, false, kVK_ANSI_7, IDC_SELECT_TAB_6}, {true, false, false, kVK_ANSI_8, IDC_SELECT_TAB_7}, {true, false, false, kVK_ANSI_9, IDC_SELECT_LAST_TAB}, - // TODO(pinkerton): These can't live here yet, they need to be plumbed - // through the renderer first so it can override if in a text field. - // http://crbug.com/12557 - // {true, false, false, kVK_LeftArrow, IDC_BACK}, - // {true, false, false, kVK_RightArrow, IDC_FORWARD}, }; *num_entries = arraysize(keyboard_shortcuts); @@ -39,8 +35,21 @@ const KeyboardShortcutData* GetKeyboardShortCutTable(size_t* num_entries) { return keyboard_shortcuts; } -int CommandForKeyboardShortcut(bool command_key, bool shift_key, bool cntrl_key, - int vkey_code) { +const KeyboardShortcutData* GetBrowserKeyboardShortcutTable + (size_t* num_entries) { + static const KeyboardShortcutData keyboard_shortcuts[] = { + {true, false, false, kVK_LeftArrow, IDC_BACK}, + {true, false, false, kVK_RightArrow, IDC_FORWARD}, + }; + + *num_entries = arraysize(keyboard_shortcuts); + + return keyboard_shortcuts; +} + +static int CommandForKeyboardShortcut( + const KeyboardShortcutData* (*get_keyboard_shortcut_table)(size_t*), + bool command_key, bool shift_key, bool cntrl_key, int vkey_code) { // Scan through keycodes and see if it corresponds to one of the global // shortcuts on file. @@ -48,7 +57,7 @@ int CommandForKeyboardShortcut(bool command_key, bool shift_key, bool cntrl_key, // TODO(jeremy): Change this into a hash table once we get enough // entries in the array to make a difference. size_t num_shortcuts = 0; - const KeyboardShortcutData *it = GetKeyboardShortCutTable(&num_shortcuts); + const KeyboardShortcutData *it = get_keyboard_shortcut_table(&num_shortcuts); for (size_t i = 0; i < num_shortcuts; ++i, ++it) { if (it->command_key == command_key && it->shift_key == shift_key && @@ -60,3 +69,17 @@ int CommandForKeyboardShortcut(bool command_key, bool shift_key, bool cntrl_key, return -1; } + +int CommandForWindowKeyboardShortcut( + bool command_key, bool shift_key, bool cntrl_key, int vkey_code) { + return CommandForKeyboardShortcut(GetWindowKeyboardShortcutTable, + command_key, shift_key, + cntrl_key, vkey_code); +} + +int CommandForBrowserKeyboardShortcut( + bool command_key, bool shift_key, bool cntrl_key, int vkey_code) { + return CommandForKeyboardShortcut(GetBrowserKeyboardShortcutTable, + command_key, shift_key, + cntrl_key, vkey_code); +} diff --git a/chrome/browser/global_keyboard_shortcuts_mac_unittest.cc b/chrome/browser/global_keyboard_shortcuts_mac_unittest.cc index 0b13e00..8ab7237 100644 --- a/chrome/browser/global_keyboard_shortcuts_mac_unittest.cc +++ b/chrome/browser/global_keyboard_shortcuts_mac_unittest.cc @@ -2,21 +2,48 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <Carbon/Carbon.h> + #include "chrome/browser/global_keyboard_shortcuts_mac.h" #include "testing/gtest/include/gtest/gtest.h" -TEST(GlobalKeyboardShortcuts, ShortCutsToCommand) { +TEST(GlobalKeyboardShortcuts, ShortcutsToWindowCommand) { + // Test that an invalid shortcut translates into an invalid command id. + ASSERT_EQ(-1, CommandForWindowKeyboardShortcut(false, false, false, 0)); + + // Check that all known keyboard shortcuts return valid results. + size_t num_shortcuts = 0; + const KeyboardShortcutData *it = + GetWindowKeyboardShortcutTable(&num_shortcuts); + ASSERT_GT(num_shortcuts, 0U); + for (size_t i = 0; i < num_shortcuts; ++i, ++it) { + int cmd_num = CommandForWindowKeyboardShortcut( + it->command_key, it->shift_key, it->cntrl_key, it->vkey_code); + ASSERT_EQ(cmd_num, it->chrome_command); + } + + // Test that cmd-left and backspace are not window-level commands (else they + // would be invoked even if e.g. the omnibox had focus, where they really + // should have text editing functionality). + ASSERT_EQ(-1, CommandForWindowKeyboardShortcut( + true, false, false, kVK_LeftArrow)); + ASSERT_EQ(-1, CommandForWindowKeyboardShortcut( + false, false, false, kVK_Delete)); +} + +TEST(GlobalKeyboardShortcuts, ShortcutsToBrowserCommand) { // Test that an invalid shortcut translates into an invalid command id. - ASSERT_EQ(CommandForKeyboardShortcut(false, false, false, 0), -1); + ASSERT_EQ(-1, CommandForBrowserKeyboardShortcut(false, false, false, 0)); // Check that all known keyboard shortcuts return valid results. size_t num_shortcuts = 0; - const KeyboardShortcutData *it = GetKeyboardShortCutTable(&num_shortcuts); + const KeyboardShortcutData *it = + GetBrowserKeyboardShortcutTable(&num_shortcuts); ASSERT_GT(num_shortcuts, 0U); for (size_t i = 0; i < num_shortcuts; ++i, ++it) { - int cmd_num = CommandForKeyboardShortcut(it->command_key, it->shift_key, - it->cntrl_key, it->vkey_code); + int cmd_num = CommandForBrowserKeyboardShortcut( + it->command_key, it->shift_key, it->cntrl_key, it->vkey_code); ASSERT_EQ(cmd_num, it->chrome_command); } } diff --git a/chrome/browser/tab_contents/tab_contents_view_mac.mm b/chrome/browser/tab_contents/tab_contents_view_mac.mm index 5a9638c..52e18b9 100644 --- a/chrome/browser/tab_contents/tab_contents_view_mac.mm +++ b/chrome/browser/tab_contents/tab_contents_view_mac.mm @@ -8,6 +8,9 @@ #include "chrome/browser/browser.h" // TODO(beng): this dependency is awful. #import "chrome/browser/cocoa/focus_tracker.h" +#import "chrome/browser/cocoa/chrome_browser_window.h" +#import "chrome/browser/cocoa/browser_window_controller.h" +#include "chrome/browser/global_keyboard_shortcuts_mac.h" #include "chrome/browser/cocoa/sad_tab_view.h" #import "chrome/browser/cocoa/web_drag_source.h" #import "chrome/browser/cocoa/web_drop_target.h" @@ -291,6 +294,18 @@ void TabContentsViewMac::Observe(NotificationType type, } - (void)processKeyboardEvent:(NSEvent*)event { + // If this tab is no longer active, it's window will be |nil|. In that case, + // best ignore the event. + if (![self window]) + return; + + ChromeBrowserWindow* window = (ChromeBrowserWindow*)[self window]; + DCHECK([window isKindOfClass:[ChromeBrowserWindow class]]); + if ([window handleExtraBrowserKeyboardShortcut:event]) + return; + if ([window handleExtraWindowKeyboardShortcut:event]) + return; + if ([event type] == NSKeyDown) [super keyDown:event]; else if ([event type] == NSKeyUp) |