| // Copyright 2011 The Chromium Authors |
| // 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 <algorithm> |
| #include <utility> |
| |
| #include "base/i18n/rtl.h" |
| #include "base/mac/mac_util.h" |
| #include "base/memory/singleton.h" |
| #include "build/branding_buildflags.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 { |
| |
| bool is_for_pwa = false; |
| bool singleton_exists = false; |
| |
| const struct AcceleratorMapping { |
| int command_id; |
| int modifiers; // The ui::EventFlag modifiers |
| ui::KeyboardCode key_code; // The key used for cross-platform compatibility. |
| } kAcceleratorMap[] = { |
| // Accelerators used in the toolbar menu. |
| {IDC_CLEAR_BROWSING_DATA, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, |
| ui::VKEY_BACK}, |
| {IDC_COPY, ui::EF_COMMAND_DOWN, ui::VKEY_C}, |
| {IDC_CUT, ui::EF_COMMAND_DOWN, ui::VKEY_X}, |
| {IDC_DEV_TOOLS, ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::VKEY_I}, |
| {IDC_DEV_TOOLS_CONSOLE, ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::VKEY_J}, |
| {IDC_DEV_TOOLS_INSPECT, ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::VKEY_C}, |
| {IDC_FIND, ui::EF_COMMAND_DOWN, ui::VKEY_F}, |
| {IDC_NEW_INCOGNITO_WINDOW, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, |
| ui::VKEY_N}, |
| {IDC_NEW_TAB, ui::EF_COMMAND_DOWN, ui::VKEY_T}, |
| {IDC_NEW_WINDOW, ui::EF_COMMAND_DOWN, ui::VKEY_N}, |
| {IDC_PASTE, ui::EF_COMMAND_DOWN, ui::VKEY_V}, |
| {IDC_PRINT, ui::EF_COMMAND_DOWN, ui::VKEY_P}, |
| {IDC_RESTORE_TAB, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, ui::VKEY_T}, |
| {IDC_SAVE_PAGE, ui::EF_COMMAND_DOWN, ui::VKEY_S}, |
| {IDC_SHOW_BOOKMARK_BAR, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, |
| ui::VKEY_B}, |
| {IDC_SHOW_BOOKMARK_MANAGER, ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, |
| ui::VKEY_B}, |
| {IDC_BOOKMARK_THIS_TAB, ui::EF_COMMAND_DOWN, ui::VKEY_D}, |
| {IDC_SHOW_DOWNLOADS, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, ui::VKEY_J}, |
| {IDC_SHOW_HISTORY, ui::EF_COMMAND_DOWN, ui::VKEY_Y}, |
| {IDC_VIEW_SOURCE, ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::VKEY_U}, |
| {IDC_ZOOM_MINUS, ui::EF_COMMAND_DOWN, ui::VKEY_OEM_MINUS}, |
| // The following entry also enables "Cmd =" on US keyboards to invoke View |
| // -> Zoom In. |
| {IDC_ZOOM_PLUS, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, ui::VKEY_OEM_PLUS}, |
| |
| // Accelerators used in the Main Menu, but not the toolbar menu. |
| {IDC_OPTIONS, ui::EF_COMMAND_DOWN, ui::VKEY_OEM_COMMA}, |
| {IDC_WEB_APP_SETTINGS, ui::EF_COMMAND_DOWN, ui::VKEY_OEM_COMMA}, |
| {IDC_HIDE_APP, ui::EF_COMMAND_DOWN, ui::VKEY_H}, |
| {IDC_EXIT, ui::EF_COMMAND_DOWN, ui::VKEY_Q}, |
| {IDC_OPEN_FILE, ui::EF_COMMAND_DOWN, ui::VKEY_O}, |
| {IDC_FOCUS_LOCATION, ui::EF_COMMAND_DOWN, ui::VKEY_L}, |
| |
| // The key combinations for IDC_CLOSE_WINDOW and IDC_CLOSE_TAB are context |
| // dependent. A static mapping doesn't make sense. :( |
| // We used to define IDC_CLOSE_WINDOW here. Instead, see |
| // AcceleratorForCloseWindow(). |
| {IDC_CLOSE_TAB, ui::EF_COMMAND_DOWN, ui::VKEY_W}, |
| |
| {IDC_EMAIL_PAGE_LOCATION, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, |
| ui::VKEY_I}, |
| #if BUILDFLAG(ENABLE_PRINTING) |
| {IDC_BASIC_PRINT, ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::VKEY_P}, |
| #endif // ENABLE_PRINTING |
| {IDC_CONTENT_CONTEXT_UNDO, ui::EF_COMMAND_DOWN, ui::VKEY_Z}, |
| {IDC_CONTENT_CONTEXT_REDO, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, |
| ui::VKEY_Z}, |
| {IDC_CONTENT_CONTEXT_CUT, ui::EF_COMMAND_DOWN, ui::VKEY_X}, |
| {IDC_CONTENT_CONTEXT_COPY, ui::EF_COMMAND_DOWN, ui::VKEY_C}, |
| {IDC_CONTENT_CONTEXT_PASTE, ui::EF_COMMAND_DOWN, ui::VKEY_V}, |
| {IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE, |
| ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, ui::VKEY_V}, |
| {IDC_CONTENT_CONTEXT_SELECTALL, ui::EF_COMMAND_DOWN, ui::VKEY_A}, |
| {IDC_FOCUS_SEARCH, ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::VKEY_F}, |
| {IDC_FIND_NEXT, ui::EF_COMMAND_DOWN, ui::VKEY_G}, |
| {IDC_FIND_PREVIOUS, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, ui::VKEY_G}, |
| {IDC_STOP, ui::EF_COMMAND_DOWN, ui::VKEY_OEM_PERIOD}, |
| {IDC_RELOAD, ui::EF_COMMAND_DOWN, ui::VKEY_R}, |
| {IDC_RELOAD_BYPASSING_CACHE, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, |
| ui::VKEY_R}, |
| {IDC_ZOOM_NORMAL, ui::EF_COMMAND_DOWN, ui::VKEY_0}, |
| {IDC_HOME, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, ui::VKEY_H}, |
| {IDC_BACK, ui::EF_COMMAND_DOWN, ui::VKEY_OEM_4}, |
| {IDC_FORWARD, ui::EF_COMMAND_DOWN, ui::VKEY_OEM_6}, |
| {IDC_BOOKMARK_ALL_TABS, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, |
| ui::VKEY_D}, |
| {IDC_MINIMIZE_WINDOW, ui::EF_COMMAND_DOWN, ui::VKEY_M}, |
| {IDC_SELECT_NEXT_TAB, ui::EF_CONTROL_DOWN, ui::VKEY_TAB}, |
| {IDC_SELECT_PREVIOUS_TAB, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, |
| ui::VKEY_TAB}, |
| {IDC_HELP_PAGE_VIA_MENU, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, |
| ui::VKEY_OEM_2}, |
| {IDC_TOGGLE_FULLSCREEN_TOOLBAR, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, |
| ui::VKEY_F}, |
| #if BUILDFLAG(GOOGLE_CHROME_BRANDING) |
| {IDC_FEEDBACK, ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN, |
| ui::VKEY_I}, |
| #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) |
| {IDC_TAB_SEARCH, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, ui::VKEY_A}, |
| }; |
| |
| ui::Accelerator AcceleratorForCloseWindow() { |
| int modifiers = ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN; |
| |
| if (is_for_pwa) { |
| modifiers = ui::EF_COMMAND_DOWN; |
| } |
| |
| return ui::Accelerator(ui::VKEY_W, modifiers); |
| } |
| |
| ui::Accelerator AcceleratorForEnterFullscreen() { |
| return ui::Accelerator(ui::VKEY_F, ui::EF_COMMAND_DOWN | ui::EF_CONTROL_DOWN | |
| ui::EF_FUNCTION_DOWN); |
| } |
| |
| } // namespace |
| |
| AcceleratorsCocoa::AcceleratorsCocoa() { |
| for (const AcceleratorMapping& entry : kAcceleratorMap) { |
| ui::Accelerator accelerator(entry.key_code, entry.modifiers); |
| |
| auto result = |
| accelerators_.insert(std::make_pair(entry.command_id, accelerator)); |
| DCHECK(result.second); |
| } |
| |
| accelerators_[IDC_CLOSE_WINDOW] = AcceleratorForCloseWindow(); |
| |
| auto result = accelerators_.insert( |
| std::make_pair(IDC_FULLSCREEN, AcceleratorForEnterFullscreen())); |
| DCHECK(result.second); |
| |
| if (!base::i18n::IsRTL()) { |
| return; |
| } |
| |
| // If running in RTL, swap the keyboard shortcuts for History -> Forward |
| // and Back. |
| ui::Accelerator history_forward = accelerators_[IDC_FORWARD]; |
| ui::Accelerator history_back = accelerators_[IDC_BACK]; |
| |
| accelerators_[IDC_FORWARD] = history_back; |
| accelerators_[IDC_BACK] = history_forward; |
| } |
| |
| AcceleratorsCocoa::~AcceleratorsCocoa() {} |
| |
| // static |
| void AcceleratorsCocoa::CreateForPWA(bool flag) { |
| is_for_pwa = flag; |
| |
| if (singleton_exists) { |
| GetInstance()->accelerators_[IDC_CLOSE_WINDOW] = |
| AcceleratorForCloseWindow(); |
| } |
| } |
| |
| AcceleratorsCocoa* AcceleratorsCocoa::GetInstance() { |
| singleton_exists = true; |
| |
| return base::Singleton<AcceleratorsCocoa>::get(); |
| } |
| |
| const ui::Accelerator* AcceleratorsCocoa::GetAcceleratorForCommand( |
| int command_id) { |
| AcceleratorMap::iterator it = accelerators_.find(command_id); |
| return it != accelerators_.end() ? &it->second : NULL; |
| } |