diff options
4 files changed, 52 insertions, 49 deletions
diff --git a/chrome/browser/chrome_browser_application_mac.mm b/chrome/browser/chrome_browser_application_mac.mm index 57c6fab..48bef43 100644 --- a/chrome/browser/chrome_browser_application_mac.mm +++ b/chrome/browser/chrome_browser_application_mac.mm @@ -9,7 +9,6 @@ #import "base/scoped_nsobject.h" #import "base/sys_string_conversions.h" #import "chrome/app/breakpad_mac.h" -#import "chrome/browser/cocoa/chrome_event_processing_window.h" #import "chrome/browser/cocoa/objc_method_swizzle.h" // The implementation of NSExceptions break various assumptions in the @@ -243,22 +242,6 @@ BOOL SwizzleNSExceptionInit() { return [super sendAction:anAction to:aTarget from:sender]; } -- (void)sendEvent:(NSEvent*)event { - chrome_application_mac::ScopedSendingEvent scoper(self); - // The superclass's |sendEvent:| sends keyboard events to the menu and the key - // view loop before dispatching them to |keyDown:|. Since we want to send keys - // to the renderer before sending them to the menu, and we never want them to - // the kev view loop when the web is focussed, we change this behavior. - if ([[self keyWindow] - isKindOfClass:[ChromeEventProcessingWindow class]]) { - if ([static_cast<ChromeEventProcessingWindow*>([self keyWindow]) - shortcircuitEvent:event]) - return; - } - - [super sendEvent:event]; -} - // NSExceptions which are caught by the event loop are logged here. // NSException uses setjmp/longjmp, which can be very bad for C++, so // we attempt to track and report them. diff --git a/chrome/browser/cocoa/chrome_event_processing_window.h b/chrome/browser/cocoa/chrome_event_processing_window.h index 4f13c27..78cc747 100644 --- a/chrome/browser/cocoa/chrome_event_processing_window.h +++ b/chrome/browser/cocoa/chrome_event_processing_window.h @@ -18,10 +18,6 @@ BOOL eventHandled_; } -// Returns |YES| if |event| has been shortcircuited and should not be processed -// further. -- (BOOL)shortcircuitEvent:(NSEvent*)event; - // Sends an event to |NSApp sendEvent:|, but also makes sure that it's not // short-circuited to the RWHV. This is used to send keyboard events to the menu // and the cmd-` handler if a keyboard event comes back unhandled from the diff --git a/chrome/browser/cocoa/chrome_event_processing_window.mm b/chrome/browser/cocoa/chrome_event_processing_window.mm index e70113a..99ed6af 100644 --- a/chrome/browser/cocoa/chrome_event_processing_window.mm +++ b/chrome/browser/cocoa/chrome_event_processing_window.mm @@ -49,37 +49,19 @@ typedef int (*KeyToCommandMapper)(bool, bool, bool, bool, int); fromTable:CommandForBrowserKeyboardShortcut]; } -- (BOOL)shortcircuitEvent:(NSEvent*)event { - if (!redispatchingEvent_ && - ([event type] == NSKeyDown || [event type] == NSKeyUp)) { - if ([[self firstResponder] - isKindOfClass:[RenderWidgetHostViewCocoa class]]) { - // No other mac browser sends keyup() for keyboard equivalents, so let's - // suppress this. - if (([event modifierFlags] & NSCommandKeyMask) && [event type] == NSKeyUp) - return YES; - - RenderWidgetHostViewCocoa* rwhv = static_cast<RenderWidgetHostViewCocoa*>( - [self firstResponder]); - [rwhv keyEvent:event]; - return YES; - } - } - return NO; -} - - (BOOL)performKeyEquivalent:(NSEvent*)event { if (redispatchingEvent_) return NO; - // |shortcircuitEvent:| should handle all events directed to the RWHV. - DCHECK(![[self firstResponder] - isKindOfClass:[RenderWidgetHostViewCocoa class]]); + // Give the web site a chance to handle the event. If it doesn't want to + // handle it, it will call us back with one of the |handle*| methods above. + NSResponder* r = [self firstResponder]; + if ([r isKindOfClass:[RenderWidgetHostViewCocoa class]]) + return [r performKeyEquivalent:event]; // Handle per-window shortcuts like cmd-1, but do not handle browser-level // shortcuts like cmd-left (else, cmd-left would do history navigation even - // if e.g. the Omnibox has focus). If the web has focus, don't do this here, - // since the web needs to get a chance at swallowing the event first. + // if e.g. the Omnibox has focus). if ([self handleExtraWindowKeyboardShortcut:event]) return YES; return [super performKeyEquivalent:event]; diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm index 69a5620..2824592 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm @@ -29,6 +29,7 @@ using WebKit::WebMouseWheelEvent; @interface RenderWidgetHostViewCocoa (Private) + (BOOL)shouldAutohideCursorForEvent:(NSEvent*)event; - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r; +- (void)keyEvent:(NSEvent *)theEvent wasKeyEquivalent:(BOOL)equiv; - (void)cancelChildPopups; @end @@ -557,16 +558,57 @@ void RenderWidgetHostViewMac::SetBackground(const SkBitmap& background) { if (ignoreKeyEvents_) return NO; - // We have some magic in |CrApplication sendEvent:| that always sends key - // events to |keyEvent:| so that cocoa doesn't have a chance to intercept it. - DCHECK([[self window] firstResponder] != self); - return NO; + // |performKeyEquivalent:| is sent to all views of a window, not only down the + // responder chain (cf. "Handling Key Equivalents" in + // http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/EventOverview/HandlingKeyEvents/HandlingKeyEvents.html + // ). We only want to handle key equivalents if we're first responder. + if ([[self window] firstResponder] != self) + return NO; + + // If we return |NO| from this function, cocoa will send the key event to + // the menu and only if the menu does not process the event to |keyDown:|. We + // want to send the event to a renderer _before_ sending it to the menu, so + // we need to return |YES| for all events that might be swallowed by the menu. + // We do not return |YES| for every keypress because we don't get |keyDown:| + // events for keys that we handle this way. + NSUInteger modifierFlags = [theEvent modifierFlags]; + if ((modifierFlags & NSCommandKeyMask) == 0) { + // Make sure the menu does not contain key equivalents that don't + // contain cmd. + DCHECK(![[NSApp mainMenu] performKeyEquivalent:theEvent]); + return NO; + } + + // Command key combinations are sent via performKeyEquivalent rather than + // keyDown:. We just forward this on and if WebCore doesn't want to handle + // it, we let the TabContentsView figure out how to reinject it. + [self keyEvent:theEvent wasKeyEquivalent:YES]; + return YES; +} + +- (BOOL)_wantsKeyDownForEvent:(NSEvent*)event { + // This is a SPI that AppKit apparently calls after |performKeyEquivalent:| + // returned NO. If this function returns |YES|, Cocoa sends the event to + // |keyDown:| instead of doing other things with it. Ctrl-tab will be sent + // to us instead of doing key view loop control, ctrl-left/right get handled + // correctly, etc. + // (However, there are still some keys that Cocoa swallows, e.g. the key + // equivalent that Cocoa uses for toggling the input langauge. In this case, + // that's actually a good thing, though -- see http://crbug.com/26115 .) + return YES; } - (void)keyEvent:(NSEvent*)theEvent { + [self keyEvent:theEvent wasKeyEquivalent:NO]; +} + +- (void)keyEvent:(NSEvent *)theEvent wasKeyEquivalent:(BOOL)equiv { if (ignoreKeyEvents_) return; + DCHECK([theEvent type] != NSKeyDown || + !equiv == !([theEvent modifierFlags] & NSCommandKeyMask)); + scoped_nsobject<RenderWidgetHostViewCocoa> keepSelfAlive([self retain]); // Don't cancel child popups; the key events are probably what's triggering |