Index: ui/base/cocoa/command_dispatcher.mm |
diff --git a/ui/base/cocoa/command_dispatcher.mm b/ui/base/cocoa/command_dispatcher.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..86c368659286728ce1a3422f626ec0c227d66b8b |
--- /dev/null |
+++ b/ui/base/cocoa/command_dispatcher.mm |
@@ -0,0 +1,125 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
tapted
2015/08/26 03:04:49
Maybe we can even trick `git cl upload` to diff th
jackhou1
2015/08/26 06:24:43
Done.
|
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#import "ui/base/cocoa/command_dispatcher.h" |
+ |
+#include "base/logging.h" |
+ |
+namespace { |
+ |
+// Duplicate the given key event, but changing the associated window. |
+NSEvent* KeyEventForWindow(NSWindow* window, NSEvent* event) { |
+ NSEventType event_type = [event type]; |
+ |
+ // Convert the event's location from the original window's coordinates into |
+ // our own. |
+ NSPoint location = [event locationInWindow]; |
+ location = [[event window] convertBaseToScreen:location]; |
+ location = [window convertScreenToBase:location]; |
+ |
+ // Various things *only* apply to key down/up. |
+ bool is_a_repeat = false; |
+ NSString* characters = nil; |
+ NSString* charactors_ignoring_modifiers = nil; |
+ if (event_type == NSKeyDown || event_type == NSKeyUp) { |
+ is_a_repeat = [event isARepeat]; |
+ characters = [event characters]; |
+ charactors_ignoring_modifiers = [event charactersIgnoringModifiers]; |
+ } |
+ |
+ // This synthesis may be slightly imperfect: we provide nil for the context, |
+ // since I (viettrungluu) am sceptical that putting in the original context |
+ // (if one is given) is valid. |
+ return [NSEvent keyEventWithType:event_type |
+ location:location |
+ modifierFlags:[event modifierFlags] |
+ timestamp:[event timestamp] |
+ windowNumber:[window windowNumber] |
+ context:nil |
+ characters:characters |
+ charactersIgnoringModifiers:charactors_ignoring_modifiers |
+ isARepeat:is_a_repeat |
+ keyCode:[event keyCode]]; |
+} |
+ |
+} // namespace |
+ |
+@implementation CommandDispatcherImpl |
+ |
+- (id)initWithOwner:(NSWindow<CommandDispatcher>*)owner { |
+ if ((self = [super init])) { |
+ owner_ = owner; |
+ } |
+ return self; |
+} |
+ |
+- (void)setDelegate:(id<CommandDispatcherDelegate>)delegate { |
+ delegate_.reset([delegate retain]); |
+} |
+ |
+- (BOOL)performKeyEquivalent:(NSEvent*)event { |
+ if ([delegate_ handledByExtensionCommand:event |
+ isRedispatch:redispatchingEvent_]) |
+ return YES; |
+ |
+ if (redispatchingEvent_) |
+ return NO; |
+ |
+ // Give the web site a chance to handle the event. If it doesn't want to |
tapted
2015/08/26 03:04:49
the web site -> a CommandDispatcherTarget (e.g. a
jackhou1
2015/08/26 06:24:43
Done.
|
+ // handle it, it will call us back with one of the |handle*| methods above. |
+ NSResponder* r = [owner_ firstResponder]; |
+ if ([r conformsToProtocol:@protocol(CommandDispatcherTarget)]) |
+ return [r performKeyEquivalent:event]; |
+ |
+ if ([delegate_ prePerformKeyEquivalent:event window:owner_]) |
+ return YES; |
+ |
+ if ([owner_ defaultPerformKeyEquivalent:event]) |
+ return YES; |
+ |
+ return [delegate_ postPerformKeyEquivalent:event window:owner_]; |
+} |
+ |
+- (BOOL)redispatchKeyEvent:(NSEvent*)event { |
+ DCHECK(event); |
+ NSEventType eventType = [event type]; |
+ if (eventType != NSKeyDown && eventType != NSKeyUp && |
+ eventType != NSFlagsChanged) { |
+ NOTREACHED(); |
+ return YES; // Pretend it's been handled in an effort to limit damage. |
+ } |
+ |
+ // Ordinarily, the event's window should be this window. However, when |
tapted
2015/08/26 03:04:49
this window -> |owner_|
jackhou1
2015/08/26 06:24:43
Done.
|
+ // switching between normal and fullscreen mode, we switch out the window, and |
+ // the event's window might be the previous window (or even an earlier one if |
+ // the renderer is running slowly and several mode switches occur). In this |
+ // rare case, we synthesize a new key event so that its associate window |
+ // (number) is our own. |
tapted
2015/08/26 03:04:49
our own -> our |owner_|'s
jackhou1
2015/08/26 06:24:43
Done.
|
+ if ([event window] != owner_) |
+ event = KeyEventForWindow(owner_, event); |
+ |
+ // Redispatch the event. |
+ eventHandled_ = YES; |
+ redispatchingEvent_ = YES; |
+ [NSApp sendEvent:event]; |
+ redispatchingEvent_ = NO; |
+ |
+ // If the event was not handled by [NSApp sendEvent:], the sendEvent: |
+ // method below will be called, and because |redispatchingEvent_| is YES, |
+ // |eventHandled_| will be set to NO. |
+ return eventHandled_; |
+} |
+ |
+- (BOOL)preSendEvent:(NSEvent*)event { |
+ if (redispatchingEvent_) { |
+ // If we get here, then the event was not handled by NSApplication. |
+ eventHandled_ = NO; |
+ // Return YES to stop native -sendEvent handling. |
+ return YES; |
+ } |
+ |
+ return NO; |
+} |
+ |
+@end |