| 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.
|
| +// 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
|
| + // 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
|
| + // 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.
|
| + 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
|
|
|