Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
FlutterTextInputPlugin Class Reference

#include <FlutterTextInputPlugin.h>

Inheritance diagram for FlutterTextInputPlugin:

Instance Methods

(instancetype) - NS_UNAVAILABLE
 
(instancetype) - initWithDelegate:
 
(void) - handleMethodCall:result:
 
(void) - reset
 
(UIView< UITextInput > *) - textInputView
 
(void) - setUpIndirectScribbleInteraction:
 
(void) - resetViewResponder
 
(BOOL- showEditMenu:
 
(ios(16.0) - API_AVAILABLE
 
(instancetype) - initWithDelegate:
 
(BOOL- isFirstResponder
 
(BOOL- handleKeyEvent:
 
(NSRect) - firstRectForCharacterRange:actualRange:
 
(NSDictionary *) - editingState
 

Class Methods

(instancetype) + NS_UNAVAILABLE
 

Protected Attributes

 : NSObject <FlutterKeySecondaryResponder
 

Properties

UIIndirectScribbleInteractionDelegate UIViewController * viewController
 
id< FlutterIndirectScribbleDelegateindirectScribbleDelegate
 
NSMutableDictionary< UIScribbleElementIdentifier, NSValue * > * scribbleElements
 
FlutterTextFieldclient
 
FlutterViewControllercurrentViewController
 
NSTextInputContext * textInputContext
 
NSString * customRunLoopMode
 

Detailed Description

A plugin to handle text input.

Responsible for bridging the native macOS text input system with the Flutter framework text editing classes, via system channels.

This is not an FlutterPlugin since it needs access to FlutterViewController internals, so needs to be managed differently.

When accessibility is on, accessibility bridge creates a NSTextField, i.e. FlutterTextField, for every text field in the Flutter. This plugin acts as a field editor for those NSTextField[s].

Definition at line 33 of file FlutterTextInputPlugin.h.

Method Documentation

◆ API_AVAILABLE

- (ios(16.0) API_AVAILABLE

◆ editingState

- (NSDictionary *) editingState

◆ firstRectForCharacterRange:actualRange:

- (NSRect) firstRectForCharacterRange: (NSRange)  range
actualRange: (NSRangePointer)  actualRange 

Provided by category FlutterTextInputPlugin(TestMethods).

◆ handleKeyEvent:

- (BOOL) handleKeyEvent: (NSEvent*)  event

Handles key down events received from the view controller, responding YES if the event was handled.

Note, the Apple docs suggest that clients should override essentially all the mouse and keyboard event-handling methods of NSResponder. However, experimentation indicates that only key events are processed by the native layer; Flutter processes mouse events. Additionally, processing both keyUp and keyDown results in duplicate processing of the same keys.

Definition at line 349 of file FlutterTextInputPlugin.mm.

647 :(NSEvent*)event {
648 if (event.type == NSEventTypeKeyUp ||
649 (event.type == NSEventTypeFlagsChanged && event.modifierFlags < _previouslyPressedFlags)) {
650 return NO;
651 }
652 _previouslyPressedFlags = event.modifierFlags;
653 if (!_shown) {
654 return NO;
655 }
656
657 _eventProducedOutput = NO;
658 BOOL res = [_textInputContext handleEvent:event];
659 // NSTextInputContext#handleEvent returns YES if the context handles the event. One of the reasons
660 // the event is handled is because it's a key equivalent. But a key equivalent might produce a
661 // text command (indicated by calling doCommandBySelector) or might not (for example, Cmd+Q). In
662 // the latter case, this command somehow has not been executed yet and Flutter must dispatch it to
663 // the next responder. See https://github.com/flutter/flutter/issues/106354 .
664 // The event is also not redispatched if there is IME composition active, because it might be
665 // handled by the IME. See https://github.com/flutter/flutter/issues/134699
666
667 // both NSEventModifierFlagNumericPad and NSEventModifierFlagFunction are set for arrow keys.
668 bool is_navigation = event.modifierFlags & NSEventModifierFlagFunction &&
669 event.modifierFlags & NSEventModifierFlagNumericPad;
670 bool is_navigation_in_ime = is_navigation && self.hasMarkedText;
671
672 if (event.isKeyEquivalent && !is_navigation_in_ime && !_eventProducedOutput) {
673 return NO;
674 }
675 return res;
676}
int BOOL

References _channel, FlutterMethodChannel::methodChannelWithName:binaryMessenger:codec:, and self.

◆ handleMethodCall:result:

- (void) handleMethodCall: (FlutterMethodCall*)  call
result: (FlutterResult result 

Provided by category FlutterTextInputPlugin(TestMethods).

Definition at line 2546 of file FlutterTextInputPlugin.mm.

2595 :(FlutterMethodCall*)call result:(FlutterResult)result {
2596 NSString* method = call.method;
2597 id args = call.arguments;
2598 if ([method isEqualToString:kShowMethod]) {
2599 [self showTextInput];
2600 result(nil);
2601 } else if ([method isEqualToString:kHideMethod]) {
2602 [self hideTextInput];
2603 result(nil);
2604 } else if ([method isEqualToString:kSetClientMethod]) {
2605 [self setTextInputClient:[args[0] intValue] withConfiguration:args[1]];
2606 result(nil);
2607 } else if ([method isEqualToString:kSetPlatformViewClientMethod]) {
2608 // This method call has a `platformViewId` argument, but we do not need it for iOS for now.
2609 [self setPlatformViewTextInputClient];
2610 result(nil);
2611 } else if ([method isEqualToString:kSetEditingStateMethod]) {
2612 [self setTextInputEditingState:args];
2613 result(nil);
2614 } else if ([method isEqualToString:kClearClientMethod]) {
2615 [self clearTextInputClient];
2616 result(nil);
2617 } else if ([method isEqualToString:kSetEditableSizeAndTransformMethod]) {
2618 [self setEditableSizeAndTransform:args];
2619 result(nil);
2620 } else if ([method isEqualToString:kSetMarkedTextRectMethod]) {
2621 [self updateMarkedRect:args];
2622 result(nil);
2623 } else if ([method isEqualToString:kFinishAutofillContextMethod]) {
2624 [self triggerAutofillSave:[args boolValue]];
2625 result(nil);
2626 // TODO(justinmc): Remove the TextInput method constant when the framework has
2627 // finished transitioning to using the Scribble channel.
2628 // https://github.com/flutter/flutter/pull/104128
2629 } else if ([method isEqualToString:kDeprecatedSetSelectionRectsMethod]) {
2630 [self setSelectionRects:args];
2631 result(nil);
2632 } else if ([method isEqualToString:kSetSelectionRectsMethod]) {
2633 [self setSelectionRects:args];
2634 result(nil);
2635 } else if ([method isEqualToString:kStartLiveTextInputMethod]) {
2636 [self startLiveTextInput];
2637 result(nil);
2638 } else if ([method isEqualToString:kUpdateConfigMethod]) {
2639 [self updateConfig:args];
2640 result(nil);
2641 } else if ([method isEqualToString:kOnInteractiveKeyboardPointerMoveMethod]) {
2642 CGFloat pointerY = (CGFloat)[args[@"pointerY"] doubleValue];
2643 [self handlePointerMove:pointerY];
2644 result(nil);
2645 } else if ([method isEqualToString:kOnInteractiveKeyboardPointerUpMethod]) {
2646 CGFloat pointerY = (CGFloat)[args[@"pointerY"] doubleValue];
2647 [self handlePointerUp:pointerY];
2648 result(nil);
2649 } else {
2651 }
2652}
void(^ FlutterResult)(id _Nullable result)
FLUTTER_DARWIN_EXPORT NSObject const * FlutterMethodNotImplemented
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
static NSString *const kSetMarkedTextRectMethod
static NSString *const kFinishAutofillContextMethod
static NSString *const kShowMethod
static NSString *const kUpdateConfigMethod
static NSString *const kSetSelectionRectsMethod
static NSString *const kSetPlatformViewClientMethod
static NSString *const kSetEditingStateMethod
static NSString *const kOnInteractiveKeyboardPointerUpMethod
static NSString *const kClearClientMethod
static NSString *const kSetClientMethod
static NSString *const kStartLiveTextInputMethod
static NSString *const kDeprecatedSetSelectionRectsMethod
static NSString *const kHideMethod
static NSString *const kSetEditableSizeAndTransformMethod
static NSString *const kOnInteractiveKeyboardPointerMoveMethod

Referenced by flutter::testing::TEST(), flutter::testing::TEST(), flutter::testing::TEST(), flutter::testing::TEST(), and flutter::testing::TEST().

◆ initWithDelegate: [1/2]

- (instancetype) initWithDelegate: (id<FlutterTextInputDelegate>)  NS_DESIGNATED_INITIALIZER

Definition at line 2546 of file FlutterTextInputPlugin.mm.

2549 :(id<FlutterTextInputDelegate>)textInputDelegate {
2550 self = [super init];
2551 if (self) {
2552 // `_textInputDelegate` is a weak reference because it should retain FlutterTextInputPlugin.
2553 _textInputDelegate = textInputDelegate;
2554 _autofillContext = [[NSMutableDictionary alloc] init];
2555 _inputHider = [[FlutterTextInputViewAccessibilityHider alloc] init];
2556 _scribbleElements = [[NSMutableDictionary alloc] init];
2557 _keyboardViewContainer = [[UIView alloc] init];
2558
2559 [[NSNotificationCenter defaultCenter] addObserver:self
2560 selector:@selector(handleKeyboardWillShow:)
2561 name:UIKeyboardWillShowNotification
2562 object:nil];
2563 }
2564
2565 return self;
2566}

◆ initWithDelegate: [2/2]

- (instancetype) initWithDelegate: (id<FlutterTextInputPluginDelegate>)  delegate

Initializes a text input plugin that coordinates key event handling with |viewController|.

Definition at line 349 of file FlutterTextInputPlugin.mm.

357 :(id<FlutterTextInputPluginDelegate>)delegate {
358 // The view needs an empty frame otherwise it is visible on dark background.
359 // https://github.com/flutter/flutter/issues/118504
360 self = [super initWithFrame:NSZeroRect];
361 self.clipsToBounds = YES;
362 if (self != nil) {
363 _delegate = delegate;
365 binaryMessenger:_delegate.binaryMessenger
366 codec:[FlutterJSONMethodCodec sharedInstance]];
367 _shown = FALSE;
368 // NSTextView does not support _weak reference, so this class has to
369 // use __unsafe_unretained and manage the reference by itself.
370 //
371 // Since the dealloc removes the handler, the pointer should
372 // be valid if the handler is ever called.
373 __unsafe_unretained FlutterTextInputPlugin* unsafeSelf = self;
374 [_channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
375 [unsafeSelf handleMethodCall:call result:result];
376 }];
377 _textInputContext = [[NSTextInputContext alloc] initWithClient:unsafeSelf];
378 _previouslyPressedFlags = 0;
379
380 // Initialize with the zero matrix which is not
381 // an affine transform.
382 _editableTransform = CATransform3D();
383 _caretRect = CGRectNull;
384 }
385 return self;
386}
FlutterMethodChannel * _channel
instancetype methodChannelWithName:binaryMessenger:codec:(NSString *name,[binaryMessenger] NSObject< FlutterBinaryMessenger > *messenger,[codec] NSObject< FlutterMethodCodec > *codec)

◆ isFirstResponder

- (BOOL) isFirstResponder

Whether this plugin is the first responder of this NSWindow.

When accessibility is on, this plugin is set as the first responder to act as the field editor for FlutterTextFields.

Returns false if accessibility is off.

Definition at line 349 of file FlutterTextInputPlugin.mm.

388 {
389 if (!_currentViewController.viewLoaded) {
390 return false;
391 }
392 return [_currentViewController.view.window firstResponder] == self;
393}

◆ NS_UNAVAILABLE [1/2]

- (instancetype) NS_UNAVAILABLE

◆ NS_UNAVAILABLE [2/2]

+ (instancetype) NS_UNAVAILABLE

◆ reset

- (void) reset

Reset the text input plugin to prepare for a hot restart.

This hides the software keyboard and text editing context menu.

Definition at line 2546 of file FlutterTextInputPlugin.mm.

2589 {
2590 [_autofillContext removeAllObjects];
2591 [self clearTextInputClient];
2592 [self hideTextInput];
2593}

◆ resetViewResponder

- (void) resetViewResponder

Definition at line 2546 of file FlutterTextInputPlugin.mm.

3299 {
3300 _viewResponder = nil;
3301}

◆ setUpIndirectScribbleInteraction:

- (void) setUpIndirectScribbleInteraction: (id<FlutterViewResponder>)  viewResponder

These are used by the UIIndirectScribbleInteractionDelegate methods to handle focusing on the correct element.

Definition at line 2546 of file FlutterTextInputPlugin.mm.

3285 :(id<FlutterViewResponder>)viewResponder {
3286 if (_viewResponder != viewResponder) {
3287 if (@available(iOS 14.0, *)) {
3288 UIView* parentView = viewResponder.view;
3289 if (parentView != nil) {
3290 UIIndirectScribbleInteraction* scribbleInteraction = [[UIIndirectScribbleInteraction alloc]
3291 initWithDelegate:(id<UIIndirectScribbleInteractionDelegate>)self];
3292 [parentView addInteraction:scribbleInteraction];
3293 }
3294 }
3295 }
3296 _viewResponder = viewResponder;
3297}
id< FlutterViewResponder > viewResponder

◆ showEditMenu:

- (BOOL) showEditMenu: (ios(16.0))  API_AVAILABLE

Definition at line 2546 of file FlutterTextInputPlugin.mm.

2766 :(NSDictionary*)args API_AVAILABLE(ios(16.0)) {
2767 if (!self.activeView.isFirstResponder) {
2768 return NO;
2769 }
2770 NSDictionary<NSString*, NSNumber*>* encodedTargetRect = args[@"targetRect"];
2771 CGRect globalTargetRect = CGRectMake(
2772 [encodedTargetRect[@"x"] doubleValue], [encodedTargetRect[@"y"] doubleValue],
2773 [encodedTargetRect[@"width"] doubleValue], [encodedTargetRect[@"height"] doubleValue]);
2774 CGRect localTargetRect = [self.hostView convertRect:globalTargetRect toView:self.activeView];
2775 [self.activeView showEditMenuWithTargetRect:localTargetRect items:args[@"items"]];
2776 return YES;
2777}

◆ textInputView

- (UIView< UITextInput > *) textInputView

The UITextInput implementation used to control text entry.

This is used by AccessibilityBridge to forward interactions with iOS' accessibility system.

Definition at line 2546 of file FlutterTextInputPlugin.mm.

2585 {
2586 return _activeView;
2587}

Member Data Documentation

◆ __pad0__

- __pad0__
protected

Definition at line 187 of file FlutterTextInputPlugin.h.

Property Documentation

◆ client

- (FlutterTextField*) client
readwritenonatomicweak

The NSTextField that currently has this plugin as its field editor.

Must be nil if accessibility is off.

Definition at line 48 of file FlutterTextInputPlugin.h.

◆ currentViewController

- (FlutterViewController*) currentViewController
readnonatomicweak

Returns the view controller text input plugin is currently attached to, nil if not attached to any view controller.

In case of popup windows, this will be the view controller of the closest window in hierarchy above that can receive keyboard input.

Definition at line 57 of file FlutterTextInputPlugin.h.

Referenced by flutter::testing::TEST(), and flutter::testing::TEST().

◆ customRunLoopMode

- (NSString*) customRunLoopMode
readwritenonatomicassign

Provided by category FlutterTextInputPlugin(TestMethods).

Definition at line 94 of file FlutterTextInputPlugin.h.

◆ indirectScribbleDelegate

- (id<FlutterIndirectScribbleDelegate>) indirectScribbleDelegate
readwritenonatomicweak

Definition at line 37 of file FlutterTextInputPlugin.h.

◆ scribbleElements

- (NSMutableDictionary<UIScribbleElementIdentifier, NSValue*>*) scribbleElements
readwritenonatomicstrong

Definition at line 39 of file FlutterTextInputPlugin.h.

◆ textInputContext

- (NSTextInputContext*) textInputContext
readwritenonatomicassign

Provided by category FlutterTextInputPlugin(TestMethods).

Definition at line 93 of file FlutterTextInputPlugin.h.

◆ viewController

- (UIIndirectScribbleInteractionDelegate UIViewController*) viewController
readwritenonatomicweak

Definition at line 36 of file FlutterTextInputPlugin.h.


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