summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/cocoa/chrome_browser_window.h10
-rw-r--r--chrome/browser/cocoa/chrome_browser_window.mm32
-rw-r--r--chrome/browser/global_keyboard_shortcuts_mac.h29
-rw-r--r--chrome/browser/global_keyboard_shortcuts_mac.mm41
-rw-r--r--chrome/browser/global_keyboard_shortcuts_mac_unittest.cc37
-rw-r--r--chrome/browser/tab_contents/tab_contents_view_mac.mm15
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)