19@property(nonatomic, copy, readonly)
20 NSMutableArray<id<FlutterKeyPrimaryResponder>>* primaryResponders;
25@property(nonatomic, copy, readonly)
26 NSMutableArray<id<FlutterKeySecondaryResponder>>* secondaryResponders;
28- (void)dispatchToSecondaryResponders:(nonnull FlutterUIPressProxy*)press
30 API_AVAILABLE(ios(13.4));
36- (nonnull instancetype)init {
39 _primaryResponders = [[NSMutableArray alloc] init];
40 _secondaryResponders = [[NSMutableArray alloc] init];
45- (void)addPrimaryResponder:(nonnull
id<FlutterKeyPrimaryResponder>)responder {
46 [_primaryResponders addObject:responder];
49- (void)addSecondaryResponder:(nonnull
id<FlutterKeySecondaryResponder>)responder {
50 [_secondaryResponders addObject:responder];
53- (void)handlePress:(nonnull FlutterUIPressProxy*)press
54 nextAction:(nonnull
void (^)())next API_AVAILABLE(ios(13.4)) {
55 if (@available(iOS 13.4, *)) {
61 bool __block wasHandled =
false;
64 CFRunLoopStop(CFRunLoopGetCurrent());
66 switch (press.phase) {
67 case UIPressPhaseBegan:
68 case UIPressPhaseEnded: {
72 NSAssert([_primaryResponders count] >= 0,
@"At least one primary responder must be added.");
74 __block __weak __typeof(
self) weakSelf =
self;
75 __block NSUInteger unreplied = [
self.primaryResponders count];
76 __block
BOOL anyHandled =
false;
79 NSAssert(unreplied >= 0,
@"More primary responders replied than expected.");
80 anyHandled = anyHandled || handled;
82 if (!anyHandled && weakSelf) {
83 [weakSelf dispatchToSecondaryResponders:press complete:completeCallback];
85 completeCallback(
true, press);
89 for (id<FlutterKeyPrimaryResponder> responder in _primaryResponders) {
90 [responder handlePress:press callback:replyCallback];
102 case UIPressPhaseChanged:
103 case UIPressPhaseCancelled:
104 case UIPressPhaseStationary:
112#pragma mark - Private
114- (void)dispatchToSecondaryResponders:(nonnull FlutterUIPressProxy*)press
116 API_AVAILABLE(ios(13.4)) {
117 if (@available(iOS 13.4, *)) {
124 for (id<FlutterKeySecondaryResponder> responder in _secondaryResponders) {
125 if ([responder handlePress:press]) {
static CFStringRef kMessageLoopCFRunLoopMode
FlutterDesktopBinaryReply callback
void(^ FlutterAsyncKeyCallback)(BOOL handled)
void(^ KeyEventCompleteCallback)(bool, FlutterUIPressProxy *_Nonnull) API_AVAILABLE(ios(13.4))
static FLUTTER_ASSERT_ARC constexpr CFTimeInterval kDistantFuture