Skip to content

Commit

Permalink
[iOS text input] do not forward press events to the engine (flutter#2…
Browse files Browse the repository at this point in the history
  • Loading branch information
LongCatIsLooong authored Nov 2, 2021
1 parent 5785bc4 commit 11b553b
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 89 deletions.
7 changes: 0 additions & 7 deletions shell/platform/darwin/ios/framework/Source/FlutterEngine.mm
Original file line number Diff line number Diff line change
Expand Up @@ -720,13 +720,6 @@ - (void)notifyLowMemory {

#pragma mark - Text input delegate

- (void)handlePressEvent:(FlutterUIPressProxy*)press
nextAction:(void (^)())next API_AVAILABLE(ios(13.4)) {
if (_viewController.get() != nullptr) {
[_viewController.get() handlePressEvent:press nextAction:next];
}
}

- (void)updateEditingClient:(int)client withState:(NSDictionary*)state {
[_textInputChannel.get() invokeMethod:@"TextInputClient.updateEditingState"
arguments:@[ @(client), state ]];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#define SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERTEXTINPUTDELEGATE_H_

#import <Foundation/Foundation.h>
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterUIPressProxy.h"

typedef NS_ENUM(NSInteger, FlutterTextInputAction) {
FlutterTextInputActionUnspecified,
Expand All @@ -29,8 +28,6 @@ typedef NS_ENUM(NSInteger, FlutterFloatingCursorDragState) {
};

@protocol FlutterTextInputDelegate <NSObject>
- (void)handlePressEvent:(FlutterUIPressProxy*)press
nextAction:(void (^)())next API_AVAILABLE(ios(13.4));
- (void)updateEditingClient:(int)client withState:(NSDictionary*)state;
- (void)updateEditingClient:(int)client withState:(NSDictionary*)state withTag:(NSString*)tag;
- (void)updateEditingClient:(int)client withDelta:(NSDictionary*)state;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -776,85 +776,6 @@ - (void)setTextInputState:(NSDictionary*)state {
}
}

// The documentation for presses* handlers (implemented below) is entirely
// unclear about how to handle the case where some, but not all, of the presses
// are handled here. I've elected to call super separately for each of the
// presses that aren't handled, but it's not clear if this is correct. It may be
// that iOS intends for us to either handle all or none of the presses, and pass
// the original set to super. I have not yet seen multiple presses in the set in
// the wild, however, so I suspect that the API is built for a tvOS remote or
// something, and perhaps only one ever appears in the set on iOS from a
// keyboard.

// If you substantially change these presses overrides, consider also changing
// the similar ones in FlutterViewController. They need to be overridden in both
// places to capture keys both inside and outside of a text field, but have
// slightly different implmentations.

- (void)pressesBegan:(NSSet<UIPress*>*)presses
withEvent:(UIPressesEvent*)event API_AVAILABLE(ios(9.0)) {
if (@available(iOS 13.4, *)) {
for (UIPress* press in presses) {
[_textInputDelegate
handlePressEvent:[[[FlutterUIPressProxy alloc] initWithPress:press
withEvent:event] autorelease]
nextAction:^() {
[super pressesBegan:[NSSet setWithObject:press] withEvent:event];
}];
}
} else {
[super pressesBegan:presses withEvent:event];
}
}

- (void)pressesChanged:(NSSet<UIPress*>*)presses
withEvent:(UIPressesEvent*)event API_AVAILABLE(ios(9.0)) {
if (@available(iOS 13.4, *)) {
for (UIPress* press in presses) {
[_textInputDelegate
handlePressEvent:[[[FlutterUIPressProxy alloc] initWithPress:press
withEvent:event] autorelease]
nextAction:^() {
[super pressesChanged:[NSSet setWithObject:press] withEvent:event];
}];
}
} else {
[super pressesChanged:presses withEvent:event];
}
}

- (void)pressesEnded:(NSSet<UIPress*>*)presses
withEvent:(UIPressesEvent*)event API_AVAILABLE(ios(9.0)) {
if (@available(iOS 13.4, *)) {
for (UIPress* press in presses) {
[_textInputDelegate
handlePressEvent:[[[FlutterUIPressProxy alloc] initWithPress:press
withEvent:event] autorelease]
nextAction:^() {
[super pressesEnded:[NSSet setWithObject:press] withEvent:event];
}];
}
} else {
[super pressesEnded:presses withEvent:event];
}
}

- (void)pressesCancelled:(NSSet<UIPress*>*)presses
withEvent:(UIPressesEvent*)event API_AVAILABLE(ios(9.0)) {
if (@available(iOS 13.4, *)) {
for (UIPress* press in presses) {
[_textInputDelegate
handlePressEvent:[[[FlutterUIPressProxy alloc] initWithPress:press
withEvent:event] autorelease]
nextAction:^() {
[super pressesCancelled:[NSSet setWithObject:press] withEvent:event];
}];
}
} else {
[super pressesCancelled:presses withEvent:event];
}
}

// Extracts the selection information from the editing state dictionary.
//
// The state may contain an invalid selection, such as when no selection was
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,21 @@ - (void)ensureOnlyActiveViewCanBecomeFirstResponder {
}
}

- (void)testPropagatePressEventsToNextResponder {
NSDictionary* config = self.mutableTemplateCopy;
[self setClientId:123 configuration:config];

FlutterTextInputView* currentView = textInputPlugin.activeView;
UIView* mockCurrentView = OCMPartialMock(currentView);

[mockCurrentView pressesBegan:[NSSet setWithObjects:OCMClassMock([UIPress class]), nil]
withEvent:OCMClassMock([UIPressesEvent class])];

// The event should be propagated to the next responder instead
// of the engine.
OCMVerify([mockCurrentView nextResponder]);
}

#pragma mark - TextEditingDelta tests
- (void)testTextEditingDeltasAreGeneratedOnTextInput {
FlutterTextInputView* inputView = [[FlutterTextInputView alloc] init];
Expand Down

0 comments on commit 11b553b

Please sign in to comment.