summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorerikchen@chromium.org <erikchen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-12 21:17:52 +0000
committererikchen@chromium.org <erikchen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-12 21:17:52 +0000
commit7326eb9a5cbc1acbd8831d9170beacb0d1a23a4f (patch)
tree1cdf365e32ad0a291ccd1c2e2d0d49ef9f4ca198
parentf93a6c6b376fe2ce3bb26698b6c4cb4cd0e36c28 (diff)
downloadchromium_src-7326eb9a5cbc1acbd8831d9170beacb0d1a23a4f.zip
chromium_src-7326eb9a5cbc1acbd8831d9170beacb0d1a23a4f.tar.gz
chromium_src-7326eb9a5cbc1acbd8831d9170beacb0d1a23a4f.tar.bz2
mac: Create a static mapping of accelerators in the main menu.
This change allows for two new functionalities: 1. Compare a mac accelerator with an extension accelerator. 2. Determine whether an accelerator is a standard main-menu accelerator without a dynamic query of the main menu. Accelerators generated from the extension manifest use cross-platform key_codes/modifiers. Previously, there was no canonical way to get an accelerator from the mac main menu. There was a mapping of accelerators from the toolbar menu, but those accelerators only included mac key_codes/modifiers, and not cross-platform key_codes/modifiers. This CL creates a static mapping of all accelerators used in the main menu and toolbar menu. The mapping includes the command_id, the cross-platform key_code, and the Cocoa modifiers. The cross-platform modifiers and the Cocoa keyEquivalent are generated on demand. BUG=342484 Review URL: https://codereview.chromium.org/152643007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@250793 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/ui/cocoa/accelerators_cocoa.h18
-rw-r--r--chrome/browser/ui/cocoa/accelerators_cocoa.mm180
-rw-r--r--chrome/browser/ui/cocoa/accelerators_cocoa_browsertest.mm133
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--ui/base/accelerators/platform_accelerator_cocoa.h3
-rw-r--r--ui/base/cocoa/cocoa_event_utils.h3
-rw-r--r--ui/base/cocoa/cocoa_event_utils.mm7
-rw-r--r--ui/events/keycodes/keyboard_code_conversion_mac.h4
-rw-r--r--ui/events/keycodes/keyboard_code_conversion_mac.mm12
9 files changed, 317 insertions, 44 deletions
diff --git a/chrome/browser/ui/cocoa/accelerators_cocoa.h b/chrome/browser/ui/cocoa/accelerators_cocoa.h
index cc1840c..e29eefb 100644
--- a/chrome/browser/ui/cocoa/accelerators_cocoa.h
+++ b/chrome/browser/ui/cocoa/accelerators_cocoa.h
@@ -5,8 +5,12 @@
#ifndef CHROME_BROWSER_UI_COCOA_ACCELERATORS_COCOA_H_
#define CHROME_BROWSER_UI_COCOA_ACCELERATORS_COCOA_H_
+#import <Cocoa/Cocoa.h>
+
#include <map>
+#include <vector>
+#include "base/gtest_prod_util.h"
#include "ui/base/accelerators/accelerator.h"
template <typename T> struct DefaultSingletonTraits;
@@ -26,6 +30,7 @@ template <typename T> struct DefaultSingletonTraits;
class AcceleratorsCocoa {
public:
typedef std::map<int, ui::Accelerator> AcceleratorMap;
+ typedef std::vector<ui::Accelerator> AcceleratorVector;
typedef AcceleratorMap::const_iterator const_iterator;
const_iterator const begin() { return accelerators_.begin(); }
@@ -33,17 +38,30 @@ class AcceleratorsCocoa {
// Returns NULL if there is no accelerator for the command.
const ui::Accelerator* GetAcceleratorForCommand(int command_id);
+ // Searches the list of accelerators without a command_id for an accelerator
+ // that matches the given |key_equivalent| and |modifiers|.
+ const ui::Accelerator* GetAcceleratorForHotKey(NSString* key_equivalent,
+ NSUInteger modifiers) const;
// Returns the singleton instance.
static AcceleratorsCocoa* GetInstance();
private:
friend struct DefaultSingletonTraits<AcceleratorsCocoa>;
+ FRIEND_TEST_ALL_PREFIXES(AcceleratorsCocoaBrowserTest,
+ MappingAcceleratorsInMainMenu);
AcceleratorsCocoa();
~AcceleratorsCocoa();
+ // A map from command_id to Accelerator. The accelerator is fully filled out,
+ // and its platform_accelerator is also fully filled out.
+ // Contains accelerators from both the wrench menu and the main menu.
AcceleratorMap accelerators_;
+ // A list of accelerators used in the main menu that have no associated
+ // command_id. The accelerator is fully filled out, and its
+ // platform_accelerator is also fully filled out.
+ AcceleratorVector accelerator_vector_;
DISALLOW_COPY_AND_ASSIGN(AcceleratorsCocoa);
};
diff --git a/chrome/browser/ui/cocoa/accelerators_cocoa.mm b/chrome/browser/ui/cocoa/accelerators_cocoa.mm
index 154be6f..b4ee271 100644
--- a/chrome/browser/ui/cocoa/accelerators_cocoa.mm
+++ b/chrome/browser/ui/cocoa/accelerators_cocoa.mm
@@ -6,53 +6,144 @@
#import <Cocoa/Cocoa.h>
+#include "base/logging.h"
#include "base/memory/singleton.h"
#include "chrome/app/chrome_command_ids.h"
#import "ui/base/accelerators/platform_accelerator_cocoa.h"
+#import "ui/base/cocoa/cocoa_event_utils.h"
+#import "ui/events/keycodes/keyboard_code_conversion_mac.h"
namespace {
+// These accelerators are not associated with a command_id.
+const struct AcceleratorListing {
+ NSUInteger modifiers; // The Cocoa modifiers.
+ ui::KeyboardCode key_code; // The key used for cross-platform compatibility.
+} kAcceleratorList [] = {
+ {NSCommandKeyMask | NSAlternateKeyMask, ui::VKEY_H},
+ {NSCommandKeyMask | NSAlternateKeyMask, ui::VKEY_W},
+ {NSCommandKeyMask | NSAlternateKeyMask | NSShiftKeyMask, ui::VKEY_V},
+ {NSCommandKeyMask, ui::VKEY_E},
+ {NSCommandKeyMask, ui::VKEY_J},
+ {NSCommandKeyMask, ui::VKEY_OEM_1},
+ {NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_OEM_1},
+ {NSCommandKeyMask, ui::VKEY_OEM_COMMA},
+ {NSCommandKeyMask | NSControlKeyMask, ui::VKEY_SPACE},
+};
+
const struct AcceleratorMapping {
int command_id;
- NSString* key;
- NSUInteger modifiers;
+ NSUInteger modifiers; // The Cocoa modifiers.
+ ui::KeyboardCode key_code; // The key used for cross-platform compatibility.
} kAcceleratorMap[] = {
- { IDC_CLEAR_BROWSING_DATA, @"\x8", NSCommandKeyMask | NSShiftKeyMask },
- { IDC_COPY, @"c", NSCommandKeyMask },
- { IDC_CUT, @"x", NSCommandKeyMask },
- { IDC_DEV_TOOLS, @"i", NSCommandKeyMask | NSAlternateKeyMask },
- { IDC_DEV_TOOLS_CONSOLE, @"j", NSCommandKeyMask | NSAlternateKeyMask },
- { IDC_FIND, @"f", NSCommandKeyMask },
- { IDC_FULLSCREEN, @"f", NSCommandKeyMask | NSShiftKeyMask },
- { IDC_NEW_INCOGNITO_WINDOW, @"n", NSCommandKeyMask | NSShiftKeyMask },
- { IDC_NEW_TAB, @"t", NSCommandKeyMask },
- { IDC_NEW_WINDOW, @"n", NSCommandKeyMask },
- { IDC_OPTIONS, @",", NSCommandKeyMask },
- { IDC_PASTE, @"v", NSCommandKeyMask },
- { IDC_PRINT, @"p", NSCommandKeyMask },
- { IDC_RESTORE_TAB, @"t", NSCommandKeyMask | NSShiftKeyMask },
- { IDC_SAVE_PAGE, @"s", NSCommandKeyMask },
- { IDC_SHOW_BOOKMARK_BAR, @"b", NSCommandKeyMask | NSShiftKeyMask },
- { IDC_SHOW_BOOKMARK_MANAGER, @"b", NSCommandKeyMask | NSAlternateKeyMask },
- { IDC_BOOKMARK_PAGE, @"d", NSCommandKeyMask },
- { IDC_SHOW_DOWNLOADS, @"j", NSCommandKeyMask | NSShiftKeyMask },
- { IDC_SHOW_HISTORY, @"y", NSCommandKeyMask },
- { IDC_VIEW_SOURCE, @"u", NSCommandKeyMask | NSAlternateKeyMask },
- { IDC_ZOOM_MINUS, @"-", NSCommandKeyMask },
- { IDC_ZOOM_PLUS, @"+", NSCommandKeyMask }
+ // Accelerators used in the toolbar menu.
+ {IDC_CLEAR_BROWSING_DATA, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_BACK},
+ {IDC_COPY, NSCommandKeyMask, ui::VKEY_C},
+ {IDC_CUT, NSCommandKeyMask, ui::VKEY_X},
+ {IDC_DEV_TOOLS, NSCommandKeyMask | NSAlternateKeyMask, ui::VKEY_I},
+ {IDC_DEV_TOOLS_CONSOLE, NSCommandKeyMask | NSAlternateKeyMask, ui::VKEY_J},
+ {IDC_FIND, NSCommandKeyMask, ui::VKEY_F},
+ {IDC_FULLSCREEN, NSCommandKeyMask | NSControlKeyMask, ui::VKEY_F},
+ {IDC_NEW_INCOGNITO_WINDOW, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_N},
+ {IDC_NEW_TAB, NSCommandKeyMask, ui::VKEY_T},
+ {IDC_NEW_WINDOW, NSCommandKeyMask, ui::VKEY_N},
+ {IDC_PASTE, NSCommandKeyMask, ui::VKEY_V},
+ {IDC_PRINT, NSCommandKeyMask, ui::VKEY_P},
+ {IDC_RESTORE_TAB, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_T},
+ {IDC_SAVE_PAGE, NSCommandKeyMask, ui::VKEY_S},
+ {IDC_SHOW_BOOKMARK_BAR, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_B},
+ {IDC_SHOW_BOOKMARK_MANAGER, NSCommandKeyMask | NSAlternateKeyMask,
+ ui::VKEY_B},
+ {IDC_BOOKMARK_PAGE, NSCommandKeyMask, ui::VKEY_D},
+ {IDC_SHOW_DOWNLOADS, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_J},
+ {IDC_SHOW_HISTORY, NSCommandKeyMask, ui::VKEY_Y},
+ {IDC_VIEW_SOURCE, NSCommandKeyMask | NSAlternateKeyMask, ui::VKEY_U},
+ {IDC_ZOOM_MINUS, NSCommandKeyMask, ui::VKEY_OEM_MINUS},
+ {IDC_ZOOM_PLUS, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_OEM_PLUS},
+
+ // Accelerators used in MainMenu.xib, but not the toolbar menu.
+ {IDC_HIDE_APP, NSCommandKeyMask, ui::VKEY_H},
+ {IDC_EXIT, NSCommandKeyMask, ui::VKEY_Q},
+ {IDC_OPEN_FILE, NSCommandKeyMask, ui::VKEY_O},
+ {IDC_FOCUS_LOCATION, NSCommandKeyMask, ui::VKEY_L},
+ {IDC_CLOSE_WINDOW, NSCommandKeyMask, ui::VKEY_W},
+ {IDC_EMAIL_PAGE_LOCATION, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_I},
+ {IDC_ADVANCED_PRINT, NSCommandKeyMask | NSAlternateKeyMask, ui::VKEY_P},
+ {IDC_CONTENT_CONTEXT_UNDO, NSCommandKeyMask, ui::VKEY_Z},
+ {IDC_CONTENT_CONTEXT_REDO, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_Z},
+ {IDC_CONTENT_CONTEXT_CUT, NSCommandKeyMask, ui::VKEY_X},
+ {IDC_CONTENT_CONTEXT_COPY, NSCommandKeyMask, ui::VKEY_C},
+ {IDC_CONTENT_CONTEXT_PASTE, NSCommandKeyMask, ui::VKEY_V},
+ {IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE,
+ NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_V},
+ {IDC_CONTENT_CONTEXT_SELECTALL, NSCommandKeyMask, ui::VKEY_A},
+ {IDC_FOCUS_SEARCH, NSCommandKeyMask | NSAlternateKeyMask, ui::VKEY_F},
+ {IDC_FIND_NEXT, NSCommandKeyMask, ui::VKEY_G},
+ {IDC_FIND_PREVIOUS, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_G},
+ {IDC_ZOOM_PLUS, NSCommandKeyMask, ui::VKEY_OEM_PLUS},
+ {IDC_ZOOM_MINUS, NSCommandKeyMask, ui::VKEY_OEM_MINUS},
+ {IDC_STOP, NSCommandKeyMask, ui::VKEY_OEM_PERIOD},
+ {IDC_RELOAD, NSCommandKeyMask, ui::VKEY_R},
+ {IDC_RELOAD_IGNORING_CACHE, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_R},
+ {IDC_PRESENTATION_MODE, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_F},
+ {IDC_ZOOM_NORMAL, NSCommandKeyMask, ui::VKEY_0},
+ {IDC_HOME, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_H},
+ {IDC_BACK, NSCommandKeyMask, ui::VKEY_OEM_4},
+ {IDC_FORWARD, NSCommandKeyMask, ui::VKEY_OEM_6},
+ {IDC_BOOKMARK_ALL_TABS, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_D},
+ {IDC_MINIMIZE_WINDOW, NSCommandKeyMask, ui::VKEY_M},
+ {IDC_SELECT_NEXT_TAB, NSCommandKeyMask | NSAlternateKeyMask, ui::VKEY_RIGHT},
+ {IDC_SELECT_PREVIOUS_TAB, NSCommandKeyMask | NSAlternateKeyMask,
+ ui::VKEY_LEFT},
+ {IDC_TABPOSE, NSCommandKeyMask | NSControlKeyMask, ui::VKEY_T},
+ {IDC_HELP_PAGE_VIA_MENU, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_OEM_2},
};
+// Create a Cocoa platform accelerator given a cross platform |key_code| and
+// the |cocoa_modifiers|.
+scoped_ptr<ui::PlatformAccelerator> PlatformAcceleratorFromKeyCode(
+ ui::KeyboardCode key_code,
+ NSUInteger cocoa_modifiers) {
+ unichar character;
+ unichar char_no_modifiers;
+ int result = ui::MacKeyCodeForWindowsKeyCode(
+ key_code, cocoa_modifiers, &character, &char_no_modifiers);
+ DCHECK(result != -1);
+ NSString* key_equivalent = [NSString stringWithFormat:@"%C", character];
+
+ return scoped_ptr<ui::PlatformAccelerator>(
+ new ui::PlatformAcceleratorCocoa(key_equivalent, cocoa_modifiers));
+}
+
+// Create a cross platform accelerator given a cross platform |key_code| and
+// the |cocoa_modifiers|.
+ui::Accelerator AcceleratorFromKeyCode(ui::KeyboardCode key_code,
+ NSUInteger cocoa_modifiers) {
+ int cross_platform_modifiers = ui::EventFlagsFromModifiers(cocoa_modifiers);
+ ui::Accelerator accelerator(key_code, cross_platform_modifiers);
+
+ scoped_ptr<ui::PlatformAccelerator> platform_accelerator =
+ PlatformAcceleratorFromKeyCode(key_code, cocoa_modifiers);
+ accelerator.set_platform_accelerator(platform_accelerator.Pass());
+ return accelerator;
+}
+
} // namespace
AcceleratorsCocoa::AcceleratorsCocoa() {
for (size_t i = 0; i < arraysize(kAcceleratorMap); ++i) {
const AcceleratorMapping& entry = kAcceleratorMap[i];
- ui::Accelerator accelerator(ui::VKEY_UNKNOWN, 0);
- scoped_ptr<ui::PlatformAccelerator> platform_accelerator(
- new ui::PlatformAcceleratorCocoa(entry.key, entry.modifiers));
- accelerator.set_platform_accelerator(platform_accelerator.Pass());
+ ui::Accelerator accelerator =
+ AcceleratorFromKeyCode(entry.key_code, entry.modifiers);
accelerators_.insert(std::make_pair(entry.command_id, accelerator));
}
+
+ for (size_t i = 0; i < arraysize(kAcceleratorList); ++i) {
+ const AcceleratorListing& entry = kAcceleratorList[i];
+ ui::Accelerator accelerator =
+ AcceleratorFromKeyCode(entry.key_code, entry.modifiers);
+ accelerator_vector_.push_back(accelerator);
+ }
}
AcceleratorsCocoa::~AcceleratorsCocoa() {}
@@ -69,3 +160,34 @@ const ui::Accelerator* AcceleratorsCocoa::GetAcceleratorForCommand(
return NULL;
return &it->second;
}
+
+const ui::Accelerator* AcceleratorsCocoa::GetAcceleratorForHotKey(
+ NSString* key_equivalent, NSUInteger modifiers) const {
+ for (AcceleratorVector::const_iterator it = accelerator_vector_.begin();
+ it != accelerator_vector_.end();
+ ++it) {
+ const ui::Accelerator& accelerator = *it;
+ const ui::PlatformAcceleratorCocoa* platform_accelerator =
+ static_cast<const ui::PlatformAcceleratorCocoa*>(
+ accelerator.platform_accelerator());
+ unichar character;
+ unichar char_no_modifiers;
+ int result =
+ ui::MacKeyCodeForWindowsKeyCode(accelerator.key_code(),
+ platform_accelerator->modifier_mask(),
+ &character,
+ &char_no_modifiers);
+ if (result == -1)
+ return NULL;
+
+ // Check for a match in the modifiers and key_equivalent.
+ NSUInteger mask = platform_accelerator->modifier_mask();
+ BOOL maskEqual =
+ (mask == modifiers) || ((mask & (~NSShiftKeyMask)) == modifiers);
+ NSString* string = [NSString stringWithFormat:@"%C", character];
+ if ([string isEqual:key_equivalent] && maskEqual)
+ return &*it;
+ }
+
+ return NULL;
+}
diff --git a/chrome/browser/ui/cocoa/accelerators_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/accelerators_cocoa_browsertest.mm
new file mode 100644
index 0000000..ce3f277
--- /dev/null
+++ b/chrome/browser/ui/cocoa/accelerators_cocoa_browsertest.mm
@@ -0,0 +1,133 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/logging.h"
+#import "chrome/browser/ui/cocoa/accelerators_cocoa.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "ui/base/accelerators/platform_accelerator_cocoa.h"
+#import "ui/events/keycodes/keyboard_code_conversion_mac.h"
+#include "testing/gtest_mac.h"
+
+typedef InProcessBrowserTest AcceleratorsCocoaBrowserTest;
+
+namespace {
+
+// Adds all NSMenuItems with an accelerator to the array.
+void AddAcceleratorItemsToArray(NSMenu* menu, NSMutableArray* array) {
+ for (NSMenuItem* item in [menu itemArray]) {
+ NSMenu* submenu = item.submenu;
+ if (submenu)
+ AddAcceleratorItemsToArray(submenu, array);
+
+ if (item.keyEquivalent.length > 0)
+ [array addObject:item];
+ }
+}
+
+// Returns the NSMenuItem that has the given keyEquivalent and modifiers, or
+// nil.
+NSMenuItem* MenuContainsAccelerator(NSMenu* menu,
+ NSString* key_equivalent,
+ NSUInteger modifiers) {
+ for (NSMenuItem* item in [menu itemArray]) {
+ NSMenu* submenu = item.submenu;
+ if (submenu) {
+ NSMenuItem* result =
+ MenuContainsAccelerator(submenu, key_equivalent, modifiers);
+ if (result)
+ return result;
+ }
+
+ if ([item.keyEquivalent isEqual:key_equivalent]) {
+ BOOL maskEqual =
+ (modifiers == item.keyEquivalentModifierMask) ||
+ ((modifiers & (~NSShiftKeyMask)) == item.keyEquivalentModifierMask);
+ if (maskEqual)
+ return item;
+ }
+ }
+ return nil;
+}
+
+} // namespace
+
+// Checks that each NSMenuItem in the main menu has a corresponding accelerator,
+// and the keyEquivalent/modifiers match.
+IN_PROC_BROWSER_TEST_F(AcceleratorsCocoaBrowserTest,
+ MainMenuAcceleratorsInMapping) {
+ NSMenu* menu = [NSApp mainMenu];
+ NSMutableArray* array = [NSMutableArray array];
+ AddAcceleratorItemsToArray(menu, array);
+
+ for (NSMenuItem* item in array) {
+ NSInteger command_id = item.tag;
+ AcceleratorsCocoa* keymap = AcceleratorsCocoa::GetInstance();
+ const ui::Accelerator* accelerator;
+
+ // If the tag is zero, then the NSMenuItem must use a custom selector.
+ // Check that the accelerator is present as an un-mapped accelerator.
+ if (command_id == 0) {
+ accelerator = keymap->GetAcceleratorForHotKey(
+ item.keyEquivalent, item.keyEquivalentModifierMask);
+
+ EXPECT_TRUE(accelerator);
+ return;
+ }
+
+ // If the tag isn't zero, then it must correspond to an IDC_* command.
+ accelerator = keymap->GetAcceleratorForCommand(command_id);
+ EXPECT_TRUE(accelerator);
+ if (!accelerator)
+ continue;
+
+ // Get the Cocoa key_equivalent associated with the accelerator.
+ const ui::PlatformAcceleratorCocoa* platform_accelerator =
+ static_cast<const ui::PlatformAcceleratorCocoa*>(
+ accelerator->platform_accelerator());
+ NSString* key_equivalent = platform_accelerator->characters();
+
+ // Check that the menu item's keyEquivalent matches the one from the
+ // Cocoa accelerator map.
+ EXPECT_NSEQ(key_equivalent, item.keyEquivalent);
+
+ // Check that the menu item's modifier mask matches the one stored in the
+ // accelerator. A mask that include NSShiftKeyMask may not include the
+ // relevant bit (the information is reflected in the keyEquivalent of the
+ // NSMenuItem).
+ NSUInteger mask = platform_accelerator->modifier_mask();
+ BOOL maskEqual =
+ (mask == item.keyEquivalentModifierMask) ||
+ ((mask & (~NSShiftKeyMask)) == item.keyEquivalentModifierMask);
+ EXPECT_TRUE(maskEqual);
+ }
+}
+
+// Check that each accelerator with a command_id has an associated NSMenuItem
+// in the main menu. If the selector is commandDispatch:, then the tag must
+// match the command_id.
+IN_PROC_BROWSER_TEST_F(AcceleratorsCocoaBrowserTest,
+ MappingAcceleratorsInMainMenu) {
+ AcceleratorsCocoa* keymap = AcceleratorsCocoa::GetInstance();
+ for (AcceleratorsCocoa::AcceleratorMap::iterator it =
+ keymap->accelerators_.begin();
+ it != keymap->accelerators_.end();
+ ++it) {
+ const ui::PlatformAcceleratorCocoa* platform_accelerator =
+ static_cast<const ui::PlatformAcceleratorCocoa*>(
+ it->second.platform_accelerator());
+
+ // Check that there exists a corresponding NSMenuItem.
+ NSMenuItem* item =
+ MenuContainsAccelerator([NSApp mainMenu],
+ platform_accelerator->characters(),
+ platform_accelerator->modifier_mask());
+ EXPECT_TRUE(item);
+
+ // If the menu uses a commandDispatch:, the tag must match the command id!
+ if (item.action == @selector(commandDispatch:))
+ EXPECT_EQ(item.tag, it->first);
+ }
+}
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 1831c23..42cf8c5 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1452,6 +1452,7 @@
'browser/ui/browser_navigator_browsertest.cc',
'browser/ui/browser_navigator_browsertest.h',
'browser/ui/browser_navigator_browsertest_chromeos.cc',
+ 'browser/ui/cocoa/accelerators_cocoa_browsertest.mm',
'browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm',
'browser/ui/cocoa/applescript/window_applescript_test.mm',
'browser/ui/cocoa/apps/app_shim_menu_controller_mac_browsertest.mm',
diff --git a/ui/base/accelerators/platform_accelerator_cocoa.h b/ui/base/accelerators/platform_accelerator_cocoa.h
index 926089a..3f72cac 100644
--- a/ui/base/accelerators/platform_accelerator_cocoa.h
+++ b/ui/base/accelerators/platform_accelerator_cocoa.h
@@ -23,7 +23,10 @@ class UI_BASE_EXPORT PlatformAcceleratorCocoa : public PlatformAccelerator {
virtual scoped_ptr<PlatformAccelerator> CreateCopy() const OVERRIDE;
virtual bool Equals(const PlatformAccelerator& rhs) const OVERRIDE;
+ // The keyEquivalent of the NSMenuItem associated with the accelerator.
NSString* characters() const { return characters_.get(); }
+ // The keyEquivalentModifierMask of the NSMenuItem associated with the
+ // accelerator.
NSUInteger modifier_mask() const { return modifier_mask_; }
private:
diff --git a/ui/base/cocoa/cocoa_event_utils.h b/ui/base/cocoa/cocoa_event_utils.h
index fda1448..e53930b 100644
--- a/ui/base/cocoa/cocoa_event_utils.h
+++ b/ui/base/cocoa/cocoa_event_utils.h
@@ -15,6 +15,9 @@ namespace ui {
// Retrieves a bitsum of ui::EventFlags represented by |event|,
UI_BASE_EXPORT int EventFlagsFromNSEvent(NSEvent* event);
+// Converts the Cocoa |modifiers| bitsum into a ui::EventFlags bitsum.
+UI_BASE_EXPORT int EventFlagsFromModifiers(NSUInteger modifiers);
+
// Retrieves a bitsum of ui::EventFlags represented by |event|,
// but instead use the modifier flags given by |modifiers|,
// which is the same format as |-NSEvent modifierFlags|. This allows
diff --git a/ui/base/cocoa/cocoa_event_utils.mm b/ui/base/cocoa/cocoa_event_utils.mm
index 55c885e..87165f4 100644
--- a/ui/base/cocoa/cocoa_event_utils.mm
+++ b/ui/base/cocoa/cocoa_event_utils.mm
@@ -43,13 +43,18 @@ int EventFlagsFromNSEvent(NSEvent* event) {
return EventFlagsFromNSEventWithModifiers(event, modifiers);
}
-int EventFlagsFromNSEventWithModifiers(NSEvent* event, NSUInteger modifiers) {
+int EventFlagsFromModifiers(NSUInteger modifiers) {
int flags = 0;
flags |= (modifiers & NSAlphaShiftKeyMask) ? ui::EF_CAPS_LOCK_DOWN : 0;
flags |= (modifiers & NSShiftKeyMask) ? ui::EF_SHIFT_DOWN : 0;
flags |= (modifiers & NSControlKeyMask) ? ui::EF_CONTROL_DOWN : 0;
flags |= (modifiers & NSAlternateKeyMask) ? ui::EF_ALT_DOWN : 0;
flags |= (modifiers & NSCommandKeyMask) ? ui::EF_COMMAND_DOWN : 0;
+ return flags;
+}
+
+int EventFlagsFromNSEventWithModifiers(NSEvent* event, NSUInteger modifiers) {
+ int flags = EventFlagsFromModifiers(modifiers);
flags |= isLeftButtonEvent(event) ? ui::EF_LEFT_MOUSE_BUTTON : 0;
flags |= isRightButtonEvent(event) ? ui::EF_RIGHT_MOUSE_BUTTON : 0;
flags |= isMiddleButtonEvent(event) ? ui::EF_MIDDLE_MOUSE_BUTTON : 0;
diff --git a/ui/events/keycodes/keyboard_code_conversion_mac.h b/ui/events/keycodes/keyboard_code_conversion_mac.h
index 719c922..fee3981 100644
--- a/ui/events/keycodes/keyboard_code_conversion_mac.h
+++ b/ui/events/keycodes/keyboard_code_conversion_mac.h
@@ -16,8 +16,8 @@ namespace ui {
// We use windows virtual keycodes throughout our keyboard event related code,
// including unit tests. But Mac uses a different set of virtual keycodes.
// This function converts a windows virtual keycode into Mac's virtual key code
-// and corresponding unicode character. |flags| is the modifiers mask such
-// as NSControlKeyMask, NSShiftKeyMask, etc.
+// and corresponding unicode character. |flags| is the Cocoa modifiers mask
+// such as NSControlKeyMask, NSShiftKeyMask, etc.
// When success, the corresponding Mac's virtual key code will be returned.
// The corresponding unicode character will be stored in |character|, and the
// corresponding unicode character ignoring the modifiers will be stored in
diff --git a/ui/events/keycodes/keyboard_code_conversion_mac.mm b/ui/events/keycodes/keyboard_code_conversion_mac.mm
index fdda790..e354e58 100644
--- a/ui/events/keycodes/keyboard_code_conversion_mac.mm
+++ b/ui/events/keycodes/keyboard_code_conversion_mac.mm
@@ -521,18 +521,6 @@ int MacKeyCodeForWindowsKeyCode(KeyboardCode keycode,
}
}
- // Control characters.
- if (flags & NSControlKeyMask) {
- if (keycode >= VKEY_A && keycode <= VKEY_Z)
- *character = 1 + keycode - VKEY_A;
- else if (macKeycode == kVK_ANSI_LeftBracket)
- *character = 27;
- else if (macKeycode == kVK_ANSI_Backslash)
- *character = 28;
- else if (macKeycode == kVK_ANSI_RightBracket)
- *character = 29;
- }
-
// TODO(suzhe): Support characters for Option key bindings.
return macKeycode;
}