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. 4 5#include "chrome/browser/ui/cocoa/accelerators_cocoa.h" 6 7#import <Cocoa/Cocoa.h> 8 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/events/cocoa/cocoa_event_utils.h" 14#import "ui/events/keycodes/keyboard_code_conversion_mac.h" 15 16namespace { 17 18// These accelerators are not associated with a command_id. 19const 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}, 32}; 33 34const struct AcceleratorMapping { 35 int command_id; 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, 56 ui::VKEY_B}, 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}, 63 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#if !defined(DISABLE_BASIC_PRINTING) 72 {IDC_BASIC_PRINT, NSCommandKeyMask | NSAlternateKeyMask, ui::VKEY_P}, 73#endif // !DISABLE_BASIC_PRINTING 74 {IDC_CONTENT_CONTEXT_UNDO, NSCommandKeyMask, ui::VKEY_Z}, 75 {IDC_CONTENT_CONTEXT_REDO, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_Z}, 76 {IDC_CONTENT_CONTEXT_CUT, NSCommandKeyMask, ui::VKEY_X}, 77 {IDC_CONTENT_CONTEXT_COPY, NSCommandKeyMask, ui::VKEY_C}, 78 {IDC_CONTENT_CONTEXT_PASTE, NSCommandKeyMask, ui::VKEY_V}, 79 {IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE, 80 NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_V}, 81 {IDC_CONTENT_CONTEXT_SELECTALL, NSCommandKeyMask, ui::VKEY_A}, 82 {IDC_FOCUS_SEARCH, NSCommandKeyMask | NSAlternateKeyMask, ui::VKEY_F}, 83 {IDC_FIND_NEXT, NSCommandKeyMask, ui::VKEY_G}, 84 {IDC_FIND_PREVIOUS, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_G}, 85 {IDC_ZOOM_PLUS, NSCommandKeyMask, ui::VKEY_OEM_PLUS}, 86 {IDC_ZOOM_MINUS, NSCommandKeyMask, ui::VKEY_OEM_MINUS}, 87 {IDC_STOP, NSCommandKeyMask, ui::VKEY_OEM_PERIOD}, 88 {IDC_RELOAD, NSCommandKeyMask, ui::VKEY_R}, 89 {IDC_RELOAD_IGNORING_CACHE, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_R}, 90 {IDC_PRESENTATION_MODE, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_F}, 91 {IDC_ZOOM_NORMAL, NSCommandKeyMask, ui::VKEY_0}, 92 {IDC_HOME, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_H}, 93 {IDC_BACK, NSCommandKeyMask, ui::VKEY_OEM_4}, 94 {IDC_FORWARD, NSCommandKeyMask, ui::VKEY_OEM_6}, 95 {IDC_BOOKMARK_ALL_TABS, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_D}, 96 {IDC_MINIMIZE_WINDOW, NSCommandKeyMask, ui::VKEY_M}, 97 {IDC_SELECT_NEXT_TAB, NSCommandKeyMask | NSAlternateKeyMask, ui::VKEY_RIGHT}, 98 {IDC_SELECT_PREVIOUS_TAB, NSCommandKeyMask | NSAlternateKeyMask, 99 ui::VKEY_LEFT}, 100 {IDC_HELP_PAGE_VIA_MENU, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_OEM_2}, 101}; 102 103// Create a Cocoa platform accelerator given a cross platform |key_code| and 104// the |cocoa_modifiers|. 105scoped_ptr<ui::PlatformAccelerator> PlatformAcceleratorFromKeyCode( 106 ui::KeyboardCode key_code, 107 NSUInteger cocoa_modifiers) { 108 unichar character; 109 unichar char_no_modifiers; 110 int result = ui::MacKeyCodeForWindowsKeyCode( 111 key_code, cocoa_modifiers, &character, &char_no_modifiers); 112 DCHECK(result != -1); 113 NSString* key_equivalent = [NSString stringWithFormat:@"%C", character]; 114 115 return scoped_ptr<ui::PlatformAccelerator>( 116 new ui::PlatformAcceleratorCocoa(key_equivalent, cocoa_modifiers)); 117} 118 119// Create a cross platform accelerator given a cross platform |key_code| and 120// the |cocoa_modifiers|. 121ui::Accelerator AcceleratorFromKeyCode(ui::KeyboardCode key_code, 122 NSUInteger cocoa_modifiers) { 123 int cross_platform_modifiers = ui::EventFlagsFromModifiers(cocoa_modifiers); 124 ui::Accelerator accelerator(key_code, cross_platform_modifiers); 125 126 scoped_ptr<ui::PlatformAccelerator> platform_accelerator = 127 PlatformAcceleratorFromKeyCode(key_code, cocoa_modifiers); 128 accelerator.set_platform_accelerator(platform_accelerator.Pass()); 129 return accelerator; 130} 131 132} // namespace 133 134AcceleratorsCocoa::AcceleratorsCocoa() { 135 for (size_t i = 0; i < arraysize(kAcceleratorMap); ++i) { 136 const AcceleratorMapping& entry = kAcceleratorMap[i]; 137 ui::Accelerator accelerator = 138 AcceleratorFromKeyCode(entry.key_code, entry.modifiers); 139 accelerators_.insert(std::make_pair(entry.command_id, accelerator)); 140 } 141 142 for (size_t i = 0; i < arraysize(kAcceleratorList); ++i) { 143 const AcceleratorListing& entry = kAcceleratorList[i]; 144 ui::Accelerator accelerator = 145 AcceleratorFromKeyCode(entry.key_code, entry.modifiers); 146 accelerator_vector_.push_back(accelerator); 147 } 148} 149 150AcceleratorsCocoa::~AcceleratorsCocoa() {} 151 152// static 153AcceleratorsCocoa* AcceleratorsCocoa::GetInstance() { 154 return Singleton<AcceleratorsCocoa>::get(); 155} 156 157const ui::Accelerator* AcceleratorsCocoa::GetAcceleratorForCommand( 158 int command_id) { 159 AcceleratorMap::iterator it = accelerators_.find(command_id); 160 if (it == accelerators_.end()) 161 return NULL; 162 return &it->second; 163} 164 165const ui::Accelerator* AcceleratorsCocoa::GetAcceleratorForHotKey( 166 NSString* key_equivalent, NSUInteger modifiers) const { 167 for (AcceleratorVector::const_iterator it = accelerator_vector_.begin(); 168 it != accelerator_vector_.end(); 169 ++it) { 170 const ui::Accelerator& accelerator = *it; 171 const ui::PlatformAcceleratorCocoa* platform_accelerator = 172 static_cast<const ui::PlatformAcceleratorCocoa*>( 173 accelerator.platform_accelerator()); 174 unichar character; 175 unichar char_no_modifiers; 176 int result = 177 ui::MacKeyCodeForWindowsKeyCode(accelerator.key_code(), 178 platform_accelerator->modifier_mask(), 179 &character, 180 &char_no_modifiers); 181 if (result == -1) 182 return NULL; 183 184 // Check for a match in the modifiers and key_equivalent. 185 NSUInteger mask = platform_accelerator->modifier_mask(); 186 BOOL maskEqual = 187 (mask == modifiers) || ((mask & (~NSShiftKeyMask)) == modifiers); 188 NSString* string = [NSString stringWithFormat:@"%C", character]; 189 if ([string isEqual:key_equivalent] && maskEqual) 190 return &*it; 191 } 192 193 return NULL; 194} 195