blob: 63e6487368270077bd30de807e9bf0aa518949fb [file] [log] [blame]
// Copyright 2013 The Flutter 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 "flutter/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.h"
@interface FlutterKeyboardManager ()
/**
* The owner set by initWithOwner.
*/
@property(nonatomic, weak) NSResponder* owner;
/**
* The primary responders added by addPrimaryResponder.
*/
@property(nonatomic) NSMutableArray<id<FlutterKeyPrimaryResponder>>* primaryResponders;
/**
* The secondary responders added by addSecondaryResponder.
*/
@property(nonatomic) NSMutableArray<id<FlutterKeySecondaryResponder>>* secondaryResponders;
- (void)dispatchToSecondaryResponders:(NSEvent*)event;
@end
@implementation FlutterKeyboardManager
- (nonnull instancetype)initWithOwner:(NSResponder*)weakOwner {
self = [super init];
if (self != nil) {
_owner = weakOwner;
_primaryResponders = [[NSMutableArray alloc] init];
_secondaryResponders = [[NSMutableArray alloc] init];
}
return self;
}
- (void)addPrimaryResponder:(nonnull id<FlutterKeyPrimaryResponder>)responder {
[_primaryResponders addObject:responder];
}
- (void)addSecondaryResponder:(nonnull id<FlutterKeySecondaryResponder>)responder {
[_secondaryResponders addObject:responder];
}
- (void)handleEvent:(nonnull NSEvent*)event {
// Be sure to add a handling method in propagateKeyEvent when allowing more
// event types here.
if (event.type != NSEventTypeKeyDown && event.type != NSEventTypeKeyUp &&
event.type != NSEventTypeFlagsChanged) {
return;
}
// Having no primary responders require extra logic, but Flutter hard-codes
// all primary responders, so this is a situation that Flutter will never
// encounter.
NSAssert([_primaryResponders count] >= 0, @"At least one primary responder must be added.");
__weak __typeof__(self) weakSelf = self;
__block int unreplied = [_primaryResponders count];
__block BOOL anyHandled = false;
FlutterAsyncKeyCallback replyCallback = ^(BOOL handled) {
unreplied -= 1;
NSAssert(unreplied >= 0, @"More primary responders replied than possible.");
anyHandled = anyHandled || handled;
if (unreplied == 0 && !anyHandled) {
[weakSelf dispatchToSecondaryResponders:event];
}
};
for (id<FlutterKeyPrimaryResponder> responder in _primaryResponders) {
[responder handleEvent:event callback:replyCallback];
}
}
#pragma mark - Private
- (void)dispatchToSecondaryResponders:(NSEvent*)event {
for (id<FlutterKeySecondaryResponder> responder in _secondaryResponders) {
if ([responder handleKeyEvent:event]) {
return;
}
}
switch (event.type) {
case NSEventTypeKeyDown:
if ([_owner.nextResponder respondsToSelector:@selector(keyDown:)]) {
[_owner.nextResponder keyDown:event];
}
break;
case NSEventTypeKeyUp:
if ([_owner.nextResponder respondsToSelector:@selector(keyUp:)]) {
[_owner.nextResponder keyUp:event];
}
break;
case NSEventTypeFlagsChanged:
if ([_owner.nextResponder respondsToSelector:@selector(flagsChanged:)]) {
[_owner.nextResponder flagsChanged:event];
}
break;
default:
NSAssert(false, @"Unexpected key event type (got %lu).", event.type);
}
}
@end