Flutter Engine
 
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 342 of file FlutterTextInputPlugin.mm.

626 :(NSEvent*)event {
627 if (event.type == NSEventTypeKeyUp ||
628 (event.type == NSEventTypeFlagsChanged && event.modifierFlags < _previouslyPressedFlags)) {
629 return NO;
630 }
631 _previouslyPressedFlags = event.modifierFlags;
632 if (!_shown) {
633 return NO;
634 }
635
636 _eventProducedOutput = NO;
637 BOOL res = [_textInputContext handleEvent:event];
638 // NSTextInputContext#handleEvent returns YES if the context handles the event. One of the reasons
639 // the event is handled is because it's a key equivalent. But a key equivalent might produce a
640 // text command (indicated by calling doCommandBySelector) or might not (for example, Cmd+Q). In
641 // the latter case, this command somehow has not been executed yet and Flutter must dispatch it to
642 // the next responder. See https://github.com/flutter/flutter/issues/106354 .
643 // The event is also not redispatched if there is IME composition active, because it might be
644 // handled by the IME. See https://github.com/flutter/flutter/issues/134699
645
646 // both NSEventModifierFlagNumericPad and NSEventModifierFlagFunction are set for arrow keys.
647 bool is_navigation = event.modifierFlags & NSEventModifierFlagFunction &&
648 event.modifierFlags & NSEventModifierFlagNumericPad;
649 bool is_navigation_in_ime = is_navigation && self.hasMarkedText;
650
651 if (event.isKeyEquivalent && !is_navigation_in_ime && !_eventProducedOutput) {
652 return NO;
653 }
654 return res;
655}
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 2515 of file FlutterTextInputPlugin.mm.

2564 :(FlutterMethodCall*)call result:(FlutterResult)result {
2565 NSString* method = call.method;
2566 id args = call.arguments;
2567 if ([method isEqualToString:kShowMethod]) {
2568 [self showTextInput];
2569 result(nil);
2570 } else if ([method isEqualToString:kHideMethod]) {
2571 [self hideTextInput];
2572 result(nil);
2573 } else if ([method isEqualToString:kSetClientMethod]) {
2574 [self setTextInputClient:[args[0] intValue] withConfiguration:args[1]];
2575 result(nil);
2576 } else if ([method isEqualToString:kSetPlatformViewClientMethod]) {
2577 // This method call has a `platformViewId` argument, but we do not need it for iOS for now.
2578 [self setPlatformViewTextInputClient];
2579 result(nil);
2580 } else if ([method isEqualToString:kSetEditingStateMethod]) {
2581 [self setTextInputEditingState:args];
2582 result(nil);
2583 } else if ([method isEqualToString:kClearClientMethod]) {
2584 [self clearTextInputClient];
2585 result(nil);
2586 } else if ([method isEqualToString:kSetEditableSizeAndTransformMethod]) {
2587 [self setEditableSizeAndTransform:args];
2588 result(nil);
2589 } else if ([method isEqualToString:kSetMarkedTextRectMethod]) {
2590 [self updateMarkedRect:args];
2591 result(nil);
2592 } else if ([method isEqualToString:kFinishAutofillContextMethod]) {
2593 [self triggerAutofillSave:[args boolValue]];
2594 result(nil);
2595 // TODO(justinmc): Remove the TextInput method constant when the framework has
2596 // finished transitioning to using the Scribble channel.
2597 // https://github.com/flutter/flutter/pull/104128
2598 } else if ([method isEqualToString:kDeprecatedSetSelectionRectsMethod]) {
2599 [self setSelectionRects:args];
2600 result(nil);
2601 } else if ([method isEqualToString:kSetSelectionRectsMethod]) {
2602 [self setSelectionRects:args];
2603 result(nil);
2604 } else if ([method isEqualToString:kStartLiveTextInputMethod]) {
2605 [self startLiveTextInput];
2606 result(nil);
2607 } else if ([method isEqualToString:kUpdateConfigMethod]) {
2608 [self updateConfig:args];
2609 result(nil);
2610 } else if ([method isEqualToString:kOnInteractiveKeyboardPointerMoveMethod]) {
2611 CGFloat pointerY = (CGFloat)[args[@"pointerY"] doubleValue];
2612 [self handlePointerMove:pointerY];
2613 result(nil);
2614 } else if ([method isEqualToString:kOnInteractiveKeyboardPointerUpMethod]) {
2615 CGFloat pointerY = (CGFloat)[args[@"pointerY"] doubleValue];
2616 [self handlePointerUp:pointerY];
2617 result(nil);
2618 } else {
2620 }
2621}
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(), and flutter::testing::TEST().

◆ initWithDelegate: [1/2]

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

Definition at line 2515 of file FlutterTextInputPlugin.mm.

2518 :(id<FlutterTextInputDelegate>)textInputDelegate {
2519 self = [super init];
2520 if (self) {
2521 // `_textInputDelegate` is a weak reference because it should retain FlutterTextInputPlugin.
2522 _textInputDelegate = textInputDelegate;
2523 _autofillContext = [[NSMutableDictionary alloc] init];
2524 _inputHider = [[FlutterTextInputViewAccessibilityHider alloc] init];
2525 _scribbleElements = [[NSMutableDictionary alloc] init];
2526 _keyboardViewContainer = [[UIView alloc] init];
2527
2528 [[NSNotificationCenter defaultCenter] addObserver:self
2529 selector:@selector(handleKeyboardWillShow:)
2530 name:UIKeyboardWillShowNotification
2531 object:nil];
2532 }
2533
2534 return self;
2535}

◆ initWithDelegate: [2/2]

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

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

Definition at line 342 of file FlutterTextInputPlugin.mm.

350 :(id<FlutterTextInputPluginDelegate>)delegate {
351 // The view needs an empty frame otherwise it is visible on dark background.
352 // https://github.com/flutter/flutter/issues/118504
353 self = [super initWithFrame:NSZeroRect];
354 self.clipsToBounds = YES;
355 if (self != nil) {
356 _delegate = delegate;
358 binaryMessenger:_delegate.binaryMessenger
359 codec:[FlutterJSONMethodCodec sharedInstance]];
360 _shown = FALSE;
361 // NSTextView does not support _weak reference, so this class has to
362 // use __unsafe_unretained and manage the reference by itself.
363 //
364 // Since the dealloc removes the handler, the pointer should
365 // be valid if the handler is ever called.
366 __unsafe_unretained FlutterTextInputPlugin* unsafeSelf = self;
367 [_channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
368 [unsafeSelf handleMethodCall:call result:result];
369 }];
370 _textInputContext = [[NSTextInputContext alloc] initWithClient:unsafeSelf];
371 _previouslyPressedFlags = 0;
372
373 // Initialize with the zero matrix which is not
374 // an affine transform.
375 _editableTransform = CATransform3D();
376 _caretRect = CGRectNull;
377 }
378 return self;
379}
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 342 of file FlutterTextInputPlugin.mm.

381 {
382 if (!_currentViewController.viewLoaded) {
383 return false;
384 }
385 return [_currentViewController.view.window firstResponder] == self;
386}

◆ 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 2515 of file FlutterTextInputPlugin.mm.

2558 {
2559 [_autofillContext removeAllObjects];
2560 [self clearTextInputClient];
2561 [self hideTextInput];
2562}

◆ resetViewResponder

- (void) resetViewResponder

Definition at line 2515 of file FlutterTextInputPlugin.mm.

3235 {
3236 _viewResponder = nil;
3237}

◆ setUpIndirectScribbleInteraction:

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

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

Definition at line 2515 of file FlutterTextInputPlugin.mm.

3221 :(id<FlutterViewResponder>)viewResponder {
3222 if (_viewResponder != viewResponder) {
3223 if (@available(iOS 14.0, *)) {
3224 UIView* parentView = viewResponder.view;
3225 if (parentView != nil) {
3226 UIIndirectScribbleInteraction* scribbleInteraction = [[UIIndirectScribbleInteraction alloc]
3227 initWithDelegate:(id<UIIndirectScribbleInteractionDelegate>)self];
3228 [parentView addInteraction:scribbleInteraction];
3229 }
3230 }
3231 }
3232 _viewResponder = viewResponder;
3233}
id< FlutterViewResponder > viewResponder

◆ showEditMenu:

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

Definition at line 2515 of file FlutterTextInputPlugin.mm.

2735 :(NSDictionary*)args API_AVAILABLE(ios(16.0)) {
2736 if (!self.activeView.isFirstResponder) {
2737 return NO;
2738 }
2739 NSDictionary<NSString*, NSNumber*>* encodedTargetRect = args[@"targetRect"];
2740 CGRect globalTargetRect = CGRectMake(
2741 [encodedTargetRect[@"x"] doubleValue], [encodedTargetRect[@"y"] doubleValue],
2742 [encodedTargetRect[@"width"] doubleValue], [encodedTargetRect[@"height"] doubleValue]);
2743 CGRect localTargetRect = [self.hostView convertRect:globalTargetRect toView:self.activeView];
2744 [self.activeView showEditMenuWithTargetRect:localTargetRect items:args[@"items"]];
2745 return YES;
2746}

◆ 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 2515 of file FlutterTextInputPlugin.mm.

2554 {
2555 return _activeView;
2556}

Member Data Documentation

◆ __pad0__

- __pad0__
protected

Definition at line 186 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.

Definition at line 54 of file FlutterTextInputPlugin.h.

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

◆ customRunLoopMode

- (NSString*) customRunLoopMode
readwritenonatomicassign

Provided by category FlutterTextInputPlugin(TestMethods).

Definition at line 91 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 90 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: