Add ICU message format support
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / chrome_event_processing_window.mm
blob4dd2c644a574850fc78ae54c78c0da9b3a7c252b
1 // Copyright (c) 2012 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 #import "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
7 #include "base/logging.h"
8 #include "chrome/browser/global_keyboard_shortcuts_mac.h"
9 #include "chrome/browser/ui/browser_commands.h"
10 #include "chrome/browser/ui/browser_finder.h"
11 #import "chrome/browser/ui/cocoa/browser_window_controller_private.h"
12 #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h"
13 #import "content/public/browser/render_widget_host_view_mac_base.h"
15 namespace {
17 // Type of functions listed in global_keyboard_shortcuts_mac.h.
18 typedef int (*KeyToCommandMapper)(bool, bool, bool, bool, int, unichar);
20 // If the event is for a Browser window, and the key combination has an
21 // associated command, execute the command.
22 bool HandleExtraKeyboardShortcut(
23     NSEvent* event,
24     NSWindow* window,
25     KeyToCommandMapper command_for_keyboard_shortcut) {
26   // Extract info from |event|.
27   NSUInteger modifers = [event modifierFlags];
28   const bool command = modifers & NSCommandKeyMask;
29   const bool shift = modifers & NSShiftKeyMask;
30   const bool control = modifers & NSControlKeyMask;
31   const bool option = modifers & NSAlternateKeyMask;
32   const int key_code = [event keyCode];
33   const unichar key_char = KeyCharacterForEvent(event);
35   int cmd = command_for_keyboard_shortcut(command, shift, control, option,
36                                           key_code, key_char);
38   if (cmd == -1)
39     return false;
41   // Only handle event if this is a browser window.
42   Browser* browser = chrome::FindBrowserWithWindow(window);
43   if (!browser)
44     return false;
46   chrome::ExecuteCommand(browser, cmd);
47   return true;
50 bool HandleExtraWindowKeyboardShortcut(NSEvent* event, NSWindow* window) {
51   return HandleExtraKeyboardShortcut(event, window,
52                                      CommandForWindowKeyboardShortcut);
55 bool HandleDelayedWindowKeyboardShortcut(NSEvent* event, NSWindow* window) {
56   return HandleExtraKeyboardShortcut(event, window,
57                                      CommandForDelayedWindowKeyboardShortcut);
60 bool HandleExtraBrowserKeyboardShortcut(NSEvent* event, NSWindow* window) {
61   return HandleExtraKeyboardShortcut(event, window,
62                                      CommandForBrowserKeyboardShortcut);
65 // Duplicate the given key event, but changing the associated window.
66 NSEvent* KeyEventForWindow(NSWindow* window, NSEvent* event) {
67   NSEventType event_type = [event type];
69   // Convert the event's location from the original window's coordinates into
70   // our own.
71   NSPoint location = [event locationInWindow];
72   location = [[event window] convertBaseToScreen:location];
73   location = [window convertScreenToBase:location];
75   // Various things *only* apply to key down/up.
76   bool is_a_repeat = false;
77   NSString* characters = nil;
78   NSString* charactors_ignoring_modifiers = nil;
79   if (event_type == NSKeyDown || event_type == NSKeyUp) {
80     is_a_repeat = [event isARepeat];
81     characters = [event characters];
82     charactors_ignoring_modifiers = [event charactersIgnoringModifiers];
83   }
85   // This synthesis may be slightly imperfect: we provide nil for the context,
86   // since I (viettrungluu) am sceptical that putting in the original context
87   // (if one is given) is valid.
88   return [NSEvent keyEventWithType:event_type
89                           location:location
90                      modifierFlags:[event modifierFlags]
91                          timestamp:[event timestamp]
92                       windowNumber:[window windowNumber]
93                            context:nil
94                         characters:characters
95        charactersIgnoringModifiers:charactors_ignoring_modifiers
96                          isARepeat:is_a_repeat
97                            keyCode:[event keyCode]];
100 }  // namespace
102 @implementation ChromeEventProcessingWindow
104 - (BOOL)handleExtraKeyboardShortcut:(NSEvent*)event {
105   return HandleExtraBrowserKeyboardShortcut(event, self) ||
106          HandleExtraWindowKeyboardShortcut(event, self) ||
107          HandleDelayedWindowKeyboardShortcut(event, self);
110 - (BOOL)performKeyEquivalent:(NSEvent*)event {
111   // Some extension commands have higher priority than web content, and some
112   // have lower priority. Regardless of whether the event is being
113   // redispatched, let the extension system try to handle the event.
114   NSWindow* window = event.window;
115   if (window) {
116     BrowserWindowController* controller = [window windowController];
117     if ([controller respondsToSelector:@selector(handledByExtensionCommand:
118                                                                   priority:)]) {
119       ui::AcceleratorManager::HandlerPriority priority =
120           redispatchingEvent_ ? ui::AcceleratorManager::kNormalPriority
121                               : ui::AcceleratorManager::kHighPriority;
122       if ([controller handledByExtensionCommand:event priority:priority])
123         return YES;
124     }
125   }
127   if (redispatchingEvent_)
128     return NO;
130   // Give the web site a chance to handle the event. If it doesn't want to
131   // handle it, it will call us back with one of the |handle*| methods above.
132   NSResponder* r = [self firstResponder];
133   if ([r conformsToProtocol:@protocol(RenderWidgetHostViewMacBase)])
134     return [r performKeyEquivalent:event];
136   // Handle per-window shortcuts like cmd-1, but do not handle browser-level
137   // shortcuts like cmd-left (else, cmd-left would do history navigation even
138   // if e.g. the Omnibox has focus).
139   if (HandleExtraWindowKeyboardShortcut(event, self))
140     return YES;
142   if ([super performKeyEquivalent:event])
143     return YES;
145   // Handle per-window shortcuts like Esc after giving everybody else a chance
146   // to handle them
147   return HandleDelayedWindowKeyboardShortcut(event, self);
150 - (BOOL)redispatchKeyEvent:(NSEvent*)event {
151   DCHECK(event);
152   NSEventType eventType = [event type];
153   if (eventType != NSKeyDown &&
154       eventType != NSKeyUp &&
155       eventType != NSFlagsChanged) {
156     NOTREACHED();
157     return YES;  // Pretend it's been handled in an effort to limit damage.
158   }
160   // Ordinarily, the event's window should be this window. However, when
161   // switching between normal and fullscreen mode, we switch out the window, and
162   // the event's window might be the previous window (or even an earlier one if
163   // the renderer is running slowly and several mode switches occur). In this
164   // rare case, we synthesize a new key event so that its associate window
165   // (number) is our own.
166   if ([event window] != self)
167     event = KeyEventForWindow(self, event);
169   // Redispatch the event.
170   eventHandled_ = YES;
171   redispatchingEvent_ = YES;
172   [NSApp sendEvent:event];
173   redispatchingEvent_ = NO;
175   // If the event was not handled by [NSApp sendEvent:], the sendEvent:
176   // method below will be called, and because |redispatchingEvent_| is YES,
177   // |eventHandled_| will be set to NO.
178   return eventHandled_;
181 - (void)sendEvent:(NSEvent*)event {
182   if (!redispatchingEvent_)
183     [super sendEvent:event];
184   else
185     eventHandled_ = NO;
188 @end  // ChromeEventProcessingWindow