Chromium Code Reviews| 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 |