1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/cocoa/accelerators_cocoa.h"
7 #import <Cocoa/Cocoa.h>
9 #include "base/logging.h"
10 #include "base/memory/singleton.h"
11 #include "chrome/app/chrome_command_ids.h"
12 #import "ui/base/accelerators/platform_accelerator_cocoa.h"
13 #import "ui/base/cocoa/cocoa_event_utils.h"
14 #import "ui/events/keycodes/keyboard_code_conversion_mac.h"
18 // These accelerators are not associated with a command_id.
19 const struct AcceleratorListing {
20 NSUInteger modifiers; // The Cocoa modifiers.
21 ui::KeyboardCode key_code; // The key used for cross-platform compatibility.
22 } kAcceleratorList [] = {
23 {NSCommandKeyMask | NSAlternateKeyMask, ui::VKEY_H},
24 {NSCommandKeyMask | NSAlternateKeyMask, ui::VKEY_W},
25 {NSCommandKeyMask | NSAlternateKeyMask | NSShiftKeyMask, ui::VKEY_V},
26 {NSCommandKeyMask, ui::VKEY_E},
27 {NSCommandKeyMask, ui::VKEY_J},
28 {NSCommandKeyMask, ui::VKEY_OEM_1},
29 {NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_OEM_1},
30 {NSCommandKeyMask, ui::VKEY_OEM_COMMA},
31 {NSCommandKeyMask | NSControlKeyMask, ui::VKEY_SPACE},
34 const struct AcceleratorMapping {
36 NSUInteger modifiers; // The Cocoa modifiers.
37 ui::KeyboardCode key_code; // The key used for cross-platform compatibility.
38 } kAcceleratorMap[] = {
39 // Accelerators used in the toolbar menu.
40 {IDC_CLEAR_BROWSING_DATA, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_BACK},
41 {IDC_COPY, NSCommandKeyMask, ui::VKEY_C},
42 {IDC_CUT, NSCommandKeyMask, ui::VKEY_X},
43 {IDC_DEV_TOOLS, NSCommandKeyMask | NSAlternateKeyMask, ui::VKEY_I},
44 {IDC_DEV_TOOLS_CONSOLE, NSCommandKeyMask | NSAlternateKeyMask, ui::VKEY_J},
45 {IDC_FIND, NSCommandKeyMask, ui::VKEY_F},
46 {IDC_FULLSCREEN, NSCommandKeyMask | NSControlKeyMask, ui::VKEY_F},
47 {IDC_NEW_INCOGNITO_WINDOW, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_N},
48 {IDC_NEW_TAB, NSCommandKeyMask, ui::VKEY_T},
49 {IDC_NEW_WINDOW, NSCommandKeyMask, ui::VKEY_N},
50 {IDC_PASTE, NSCommandKeyMask, ui::VKEY_V},
51 {IDC_PRINT, NSCommandKeyMask, ui::VKEY_P},
52 {IDC_RESTORE_TAB, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_T},
53 {IDC_SAVE_PAGE, NSCommandKeyMask, ui::VKEY_S},
54 {IDC_SHOW_BOOKMARK_BAR, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_B},
55 {IDC_SHOW_BOOKMARK_MANAGER, NSCommandKeyMask | NSAlternateKeyMask,
57 {IDC_BOOKMARK_PAGE, NSCommandKeyMask, ui::VKEY_D},
58 {IDC_SHOW_DOWNLOADS, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_J},
59 {IDC_SHOW_HISTORY, NSCommandKeyMask, ui::VKEY_Y},
60 {IDC_VIEW_SOURCE, NSCommandKeyMask | NSAlternateKeyMask, ui::VKEY_U},
61 {IDC_ZOOM_MINUS, NSCommandKeyMask, ui::VKEY_OEM_MINUS},
62 {IDC_ZOOM_PLUS, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_OEM_PLUS},
64 // Accelerators used in MainMenu.xib, but not the toolbar menu.
65 {IDC_HIDE_APP, NSCommandKeyMask, ui::VKEY_H},
66 {IDC_EXIT, NSCommandKeyMask, ui::VKEY_Q},
67 {IDC_OPEN_FILE, NSCommandKeyMask, ui::VKEY_O},
68 {IDC_FOCUS_LOCATION, NSCommandKeyMask, ui::VKEY_L},
69 {IDC_CLOSE_WINDOW, NSCommandKeyMask, ui::VKEY_W},
70 {IDC_EMAIL_PAGE_LOCATION, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_I},
71 {IDC_ADVANCED_PRINT, NSCommandKeyMask | NSAlternateKeyMask, ui::VKEY_P},
72 {IDC_CONTENT_CONTEXT_UNDO, NSCommandKeyMask, ui::VKEY_Z},
73 {IDC_CONTENT_CONTEXT_REDO, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_Z},
74 {IDC_CONTENT_CONTEXT_CUT, NSCommandKeyMask, ui::VKEY_X},
75 {IDC_CONTENT_CONTEXT_COPY, NSCommandKeyMask, ui::VKEY_C},
76 {IDC_CONTENT_CONTEXT_PASTE, NSCommandKeyMask, ui::VKEY_V},
77 {IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE,
78 NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_V},
79 {IDC_CONTENT_CONTEXT_SELECTALL, NSCommandKeyMask, ui::VKEY_A},
80 {IDC_FOCUS_SEARCH, NSCommandKeyMask | NSAlternateKeyMask, ui::VKEY_F},
81 {IDC_FIND_NEXT, NSCommandKeyMask, ui::VKEY_G},
82 {IDC_FIND_PREVIOUS, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_G},
83 {IDC_ZOOM_PLUS, NSCommandKeyMask, ui::VKEY_OEM_PLUS},
84 {IDC_ZOOM_MINUS, NSCommandKeyMask, ui::VKEY_OEM_MINUS},
85 {IDC_STOP, NSCommandKeyMask, ui::VKEY_OEM_PERIOD},
86 {IDC_RELOAD, NSCommandKeyMask, ui::VKEY_R},
87 {IDC_RELOAD_IGNORING_CACHE, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_R},
88 {IDC_PRESENTATION_MODE, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_F},
89 {IDC_ZOOM_NORMAL, NSCommandKeyMask, ui::VKEY_0},
90 {IDC_HOME, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_H},
91 {IDC_BACK, NSCommandKeyMask, ui::VKEY_OEM_4},
92 {IDC_FORWARD, NSCommandKeyMask, ui::VKEY_OEM_6},
93 {IDC_BOOKMARK_ALL_TABS, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_D},
94 {IDC_MINIMIZE_WINDOW, NSCommandKeyMask, ui::VKEY_M},
95 {IDC_SELECT_NEXT_TAB, NSCommandKeyMask | NSAlternateKeyMask, ui::VKEY_RIGHT},
96 {IDC_SELECT_PREVIOUS_TAB, NSCommandKeyMask | NSAlternateKeyMask,
98 {IDC_HELP_PAGE_VIA_MENU, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_OEM_2},
101 // Create a Cocoa platform accelerator given a cross platform |key_code| and
102 // the |cocoa_modifiers|.
103 scoped_ptr<ui::PlatformAccelerator> PlatformAcceleratorFromKeyCode(
104 ui::KeyboardCode key_code,
105 NSUInteger cocoa_modifiers) {
107 unichar char_no_modifiers;
108 int result = ui::MacKeyCodeForWindowsKeyCode(
109 key_code, cocoa_modifiers, &character, &char_no_modifiers);
110 DCHECK(result != -1);
111 NSString* key_equivalent = [NSString stringWithFormat:@"%C", character];
113 return scoped_ptr<ui::PlatformAccelerator>(
114 new ui::PlatformAcceleratorCocoa(key_equivalent, cocoa_modifiers));
117 // Create a cross platform accelerator given a cross platform |key_code| and
118 // the |cocoa_modifiers|.
119 ui::Accelerator AcceleratorFromKeyCode(ui::KeyboardCode key_code,
120 NSUInteger cocoa_modifiers) {
121 int cross_platform_modifiers = ui::EventFlagsFromModifiers(cocoa_modifiers);
122 ui::Accelerator accelerator(key_code, cross_platform_modifiers);
124 scoped_ptr<ui::PlatformAccelerator> platform_accelerator =
125 PlatformAcceleratorFromKeyCode(key_code, cocoa_modifiers);
126 accelerator.set_platform_accelerator(platform_accelerator.Pass());
132 AcceleratorsCocoa::AcceleratorsCocoa() {
133 for (size_t i = 0; i < arraysize(kAcceleratorMap); ++i) {
134 const AcceleratorMapping& entry = kAcceleratorMap[i];
135 ui::Accelerator accelerator =
136 AcceleratorFromKeyCode(entry.key_code, entry.modifiers);
137 accelerators_.insert(std::make_pair(entry.command_id, accelerator));
140 for (size_t i = 0; i < arraysize(kAcceleratorList); ++i) {
141 const AcceleratorListing& entry = kAcceleratorList[i];
142 ui::Accelerator accelerator =
143 AcceleratorFromKeyCode(entry.key_code, entry.modifiers);
144 accelerator_vector_.push_back(accelerator);
148 AcceleratorsCocoa::~AcceleratorsCocoa() {}
151 AcceleratorsCocoa* AcceleratorsCocoa::GetInstance() {
152 return Singleton<AcceleratorsCocoa>::get();
155 const ui::Accelerator* AcceleratorsCocoa::GetAcceleratorForCommand(
157 AcceleratorMap::iterator it = accelerators_.find(command_id);
158 if (it == accelerators_.end())
163 const ui::Accelerator* AcceleratorsCocoa::GetAcceleratorForHotKey(
164 NSString* key_equivalent, NSUInteger modifiers) const {
165 for (AcceleratorVector::const_iterator it = accelerator_vector_.begin();
166 it != accelerator_vector_.end();
168 const ui::Accelerator& accelerator = *it;
169 const ui::PlatformAcceleratorCocoa* platform_accelerator =
170 static_cast<const ui::PlatformAcceleratorCocoa*>(
171 accelerator.platform_accelerator());
173 unichar char_no_modifiers;
175 ui::MacKeyCodeForWindowsKeyCode(accelerator.key_code(),
176 platform_accelerator->modifier_mask(),
182 // Check for a match in the modifiers and key_equivalent.
183 NSUInteger mask = platform_accelerator->modifier_mask();
185 (mask == modifiers) || ((mask & (~NSShiftKeyMask)) == modifiers);
186 NSString* string = [NSString stringWithFormat:@"%C", character];
187 if ([string isEqual:key_equivalent] && maskEqual)