| Flutter iOS Embedder |

Instance Methods | List of all members
FlutterKeyboardManager Class Reference

`#import <FlutterKeyboardManager.h>`

Inheritance diagram for FlutterKeyboardManager:

## Instance Methods
(void) | - addPrimaryResponder:
(void) | - addSecondaryResponder:
(void) | - handlePress:nextAction:

## Detailed Description

A hub that manages how key events are dispatched to various Flutter key responders, and propagates it to the superclass if the Flutter key responders do not handle it.

This class manages one or more primary responders, as well as zero or more secondary responders.

An event that is received by |handlePresses| is first dispatched to all primary responders. Each primary responder responds asynchronously with a boolean, indicating whether it handles the event.

An event that is not handled by any primary responders is then passed to to the first secondary responder (in the chronological order of addition), which responds synchronously with a boolean, indicating whether it handles the event. If not, the event is passed to the next secondary responder, and so on.

The event is then handed back to the |completeCallback| from the original call to |handlePresses| so that it can respond synchronously to the OS if the event was not handled by the responders. The |completeCallback| is called on the platform thread because the platform thread is blocked by a nested event loop while the response from the framework is being collected, and it needs to be called on the platform thread to unblock the thread by exiting the nested event loop.

Preventing primary responders from receiving events is not supported, because in reality this class only supports two hardcoded responders (FlutterChannelKeyResponder and FlutterEmbedderKeyResponder), where the only purpose of supporting two is to maintain the legacy channel API during the deprecation window, after which the channel responder should be removed, and only one primary responder will exist.

Definition at line 53 of file FlutterKeyboardManager.h.

## Method Documentation

## ◆ addPrimaryResponder:

- (void) addPrimaryResponder: |  | (nonnull id<FlutterKeyPrimaryResponder>) | responder |

Add a primary responder, which asynchronously decides whether to handle an event.

Definition at line 45 of file FlutterKeyboardManager.mm.

45 :(nonnull id<FlutterKeyPrimaryResponder>)responder {
46 [_primaryResponders addObject:responder];
47 }

## ◆ addSecondaryResponder:

- (void) addSecondaryResponder: |  | (nonnull id<FlutterKeySecondaryResponder>) | responder |

Add a secondary responder, which synchronously decides whether to handle an event in order if no earlier responders handle.

Definition at line 49 of file FlutterKeyboardManager.mm.

49 :(nonnull id<FlutterKeySecondaryResponder>)responder {
50 [_secondaryResponders addObject:responder];
51 }

## ◆ handlePress:nextAction:

- (void) handlePress: |  | (nonnull FlutterUIPressProxy*) | press
nextAction: |  | (ios(13.4)) | API_AVAILABLE

Dispatches a key press event to all responders, gathering their responses, and then calls the |nextAction| if the event was not handled.

Definition at line 71 of file FlutterKeyboardManager.mm.

71 :(nonnull FlutterUIPressProxy*)press
72 nextAction:(nonnull void (^)())next API_AVAILABLE(ios(13.4)) {
73 if (@available(iOS 13.4, *)) {
74 // no-op
75 } else {
76 return;
77 }
78
79 bool __block wasHandled = false;
80 KeyEventCompleteCallback completeCallback = ^void(bool handled, FlutterUIPressProxy* press) {
81 wasHandled = handled;
82 CFRunLoopStop(CFRunLoopGetCurrent());
83 };
84 switch (press.phase) {
85 case UIPressPhaseBegan:
86 case UIPressPhaseEnded: {
87 // Having no primary responders requires extra logic, but Flutter hard-codes
88 // all primary responders, so this is a situation that Flutter will never
89 // encounter.
90 NSAssert([_primaryResponders count] >= 0, @"At least one primary responder must be added.");
91
92 __block auto weakSelf = [self getWeakNSObject];
93 __block NSUInteger unreplied = [self.primaryResponders count];
94 __block BOOL anyHandled = false;
95 FlutterAsyncKeyCallback replyCallback = ^(BOOL handled) {
96 unreplied--;
97 NSAssert(unreplied >= 0, @"More primary responders replied than expected.");
98 anyHandled = anyHandled || handled;
99 if (unreplied == 0) {
100 if (!anyHandled && weakSelf) {
101 [weakSelf.get() dispatchToSecondaryResponders:press complete:completeCallback];
102 } else {
103 completeCallback(true, press);
104 }
105 }
106 };
107 for (id<FlutterKeyPrimaryResponder> responder in _primaryResponders) {
108 [responder handlePress:press callback:replyCallback];
109 }
110 // Create a nested run loop while we wait for a response from the
111 // framework. Once the completeCallback is called, this run loop will exit
112 // and the main one will resume. The completeCallback MUST be called, or
113 // the app will get stuck in this run loop indefinitely.
114 //
115 // We need to run in this mode so that UIKit doesn't give us new
116 // events until we are done processing this one.
117 CFRunLoopRunInMode(fml::MessageLoopDarwin::kMessageLoopCFRunLoopMode, kDistantFuture, NO);
118 break;
119 }
120 case UIPressPhaseChanged:
121 case UIPressPhaseCancelled:
122 case UIPressPhaseStationary:
123 break;
124 }
125 if (!wasHandled) {
126 next();
127 }
128 }

References kDistantFuture.

The documentation for this class was generated from the following files:

- shell/platform/darwin/ios/framework/Source/FlutterKeyboardManager.h
- shell/platform/darwin/ios/framework/Source/FlutterKeyboardManager.mm

API_AVAILABLE
UITextSmartQuotesType smartQuotesType API_AVAILABLE(ios(11.0))
FlutterAsyncKeyCallback
void(^ FlutterAsyncKeyCallback)(BOOL handled)
Definition: FlutterKeyPrimaryResponder.h:10
KeyEventCompleteCallback
void(^ KeyEventCompleteCallback)(bool, FlutterUIPressProxy *_Nonnull) API_AVAILABLE(ios(13.4))
Definition: FlutterKeyboardManager.h:17
FlutterUIPressProxy
Definition: FlutterUIPressProxy.h:17
kDistantFuture
static constexpr CFTimeInterval kDistantFuture
Definition: FlutterKeyboardManager.mm:9