blob: ab4ebf24e2aef9f64cb85ad18559895e1670ae4b [file] [log] [blame]
// Copyright (c) 2011 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.
#include "chrome/browser/ui/cocoa/accelerators_cocoa.h"
#import <Cocoa/Cocoa.h>
#include <stddef.h>
#include <utility>
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/stl_util.h"
#include "chrome/app/chrome_command_ids.h"
#include "printing/buildflags/buildflags.h"
#import "ui/base/accelerators/platform_accelerator_cocoa.h"
#import "ui/events/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;
NSUInteger modifiers; // The Cocoa modifiers.
ui::KeyboardCode key_code; // The key used for cross-platform compatibility.
} kAcceleratorMap[] = {
// 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},
#if BUILDFLAG(ENABLE_PRINTING)
{IDC_BASIC_PRINT, NSCommandKeyMask | NSAlternateKeyMask, ui::VKEY_P},
#endif // ENABLE_PRINTING
{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_BYPASSING_CACHE, NSCommandKeyMask | NSShiftKeyMask, ui::VKEY_R},
{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, NSControlKeyMask, ui::VKEY_TAB},
{IDC_SELECT_PREVIOUS_TAB, NSControlKeyMask | NSShiftKeyMask, ui::VKEY_TAB},
{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|.
std::unique_ptr<ui::PlatformAccelerator> PlatformAcceleratorFromKeyCode(
ui::KeyboardCode key_code,
NSUInteger cocoa_modifiers) {
unichar shifted_character;
int result = ui::MacKeyCodeForWindowsKeyCode(key_code, cocoa_modifiers,
&shifted_character, nullptr);
DCHECK(result != -1);
NSString* key_equivalent =
[NSString stringWithFormat:@"%C", shifted_character];
return std::unique_ptr<ui::PlatformAccelerator>(
new ui::PlatformAcceleratorCocoa(key_equivalent, cocoa_modifiers));
}
} // namespace
// static
ui::Accelerator AcceleratorsCocoa::AcceleratorFromKeyCode(
ui::KeyboardCode key_code,
NSUInteger cocoa_modifiers) {
int cross_platform_modifiers = ui::EventFlagsFromModifiers(cocoa_modifiers);
ui::Accelerator accelerator(key_code, cross_platform_modifiers);
std::unique_ptr<ui::PlatformAccelerator> platform_accelerator =
PlatformAcceleratorFromKeyCode(key_code, cocoa_modifiers);
accelerator.set_platform_accelerator(std::move(platform_accelerator));
return accelerator;
}
AcceleratorsCocoa::AcceleratorsCocoa() {
for (size_t i = 0; i < base::size(kAcceleratorMap); ++i) {
const AcceleratorMapping& entry = kAcceleratorMap[i];
ui::Accelerator accelerator =
AcceleratorFromKeyCode(entry.key_code, entry.modifiers);
accelerators_.insert(std::make_pair(entry.command_id, accelerator));
}
for (size_t i = 0; i < base::size(kAcceleratorList); ++i) {
const AcceleratorListing& entry = kAcceleratorList[i];
ui::Accelerator accelerator =
AcceleratorFromKeyCode(entry.key_code, entry.modifiers);
accelerator_vector_.push_back(accelerator);
}
}
AcceleratorsCocoa::~AcceleratorsCocoa() {}
// static
AcceleratorsCocoa* AcceleratorsCocoa::GetInstance() {
return base::Singleton<AcceleratorsCocoa>::get();
}
const ui::Accelerator* AcceleratorsCocoa::GetAcceleratorForCommand(
int command_id) {
AcceleratorMap::iterator it = accelerators_.find(command_id);
if (it == accelerators_.end())
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 shifted_character;
int result = ui::MacKeyCodeForWindowsKeyCode(
accelerator.key_code(), platform_accelerator->modifier_mask(),
&shifted_character, nullptr);
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", shifted_character];
if ([string isEqual:key_equivalent] && maskEqual)
return &*it;
}
return NULL;
}