Home | History | Annotate | Download | only in cocoa
      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 
     16 namespace {
     17 
     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},
     32 };
     33 
     34 const 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|.
    105 scoped_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|.
    121 ui::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 
    134 AcceleratorsCocoa::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 
    150 AcceleratorsCocoa::~AcceleratorsCocoa() {}
    151 
    152 // static
    153 AcceleratorsCocoa* AcceleratorsCocoa::GetInstance() {
    154   return Singleton<AcceleratorsCocoa>::get();
    155 }
    156 
    157 const 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 
    165 const 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