Flutter macOS Embedder
FlutterTextInputPlugin Class Reference

#import <FlutterTextInputPlugin.h>

Inheritance diagram for FlutterTextInputPlugin:

Instance Methods

(instancetype) - initWithDelegate:
 
(BOOL) - isFirstResponder
 
(BOOL) - handleKeyEvent:
 
(void) - handleMethodCall:result:
 
(NSRect) - firstRectForCharacterRange:actualRange:
 
(NSDictionary *) - editingState
 

Properties

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 41 of file FlutterTextInputPlugin.h.

Method Documentation

◆ editingState

- (NSDictionary*) editingState

Provided by category FlutterTextInputPlugin(TestMethods).

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

◆ 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 }

References FlutterMethodChannel::methodChannelWithName:binaryMessenger:codec:.

◆ handleMethodCall:result:

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

Provided by category FlutterTextInputPlugin(TestMethods).

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

◆ initWithDelegate:

- (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;
364  _channel = [FlutterMethodChannel methodChannelWithName:kTextInputChannel
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 }
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 }

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().

◆ customRunLoopMode

- (NSString*) customRunLoopMode
readwritenonatomicassign

Provided by category FlutterTextInputPlugin(TestMethods).

Definition at line 94 of file FlutterTextInputPlugin.h.

◆ textInputContext

- (NSTextInputContext*) textInputContext
readwritenonatomicassign

Provided by category FlutterTextInputPlugin(TestMethods).

Definition at line 93 of file FlutterTextInputPlugin.h.


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