Flutter Engine
FlutterTextInputPlugin.mm File Reference
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.h"
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#include "flutter/fml/logging.h"
#include "flutter/fml/platform/darwin/string_range_sanitization.h"

Go to the source code of this file.

Classes

class  FlutterSecureTextInputView
 
class  FlutterTextInputViewAccessibilityHider
 
class  FlutterTimerProxy
 

Functions

static BOOL shouldShowSystemKeyboard (NSDictionary *type)
 
static UIKeyboardType ToUIKeyboardType (NSDictionary *type)
 
static UITextAutocapitalizationType ToUITextAutoCapitalizationType (NSDictionary *type)
 
static UIReturnKeyType ToUIReturnKeyType (NSString *inputType)
 
static UITextContentType ToUITextContentType (NSArray< NSString *> *hints)
 
static NSString * autofillIdFromDictionary (NSDictionary *dictionary)
 
typedef NS_ENUM (NSInteger, FlutterAutofillType)
 
static BOOL isFieldPasswordRelated (NSDictionary *configuration)
 
static FlutterAutofillType autofillTypeOf (NSDictionary *configuration)
 

Variables

static const char _kTextAffinityDownstream [] = "TextAffinity.downstream"
 
static const char _kTextAffinityUpstream [] = "TextAffinity.upstream"
 
static constexpr double kUITextInputAccessibilityEnablingDelaySeconds = 0.5
 
const CGRect kInvalidFirstRect = {{-1, -1}, {9999, 9999}}
 
const CGRect kSpacePanBounds = {{-2500, -2500}, {5000, 5000}}
 
static NSString *const kShowMethod = @"@"TextInput.show"
 
static NSString *const kHideMethod = @"@"TextInput.hide"
 
static NSString *const kSetClientMethod = @"@"TextInput.setClient"
 
static NSString *const kSetEditingStateMethod = @"@"TextInput.setEditingState"
 
static NSString *const kClearClientMethod = @"@"TextInput.clearClient"
 
static NSString *const kSetEditableSizeAndTransformMethod
 
static NSString *const kSetMarkedTextRectMethod = @"@"TextInput.setMarkedTextRect"
 
static NSString *const kFinishAutofillContextMethod = @"@"TextInput.finishAutofillContext"
 
static NSString *const kSecureTextEntry = @"@"obscureText"
 
static NSString *const kKeyboardType = @"@"inputType"
 
static NSString *const kKeyboardAppearance = @"@"keyboardAppearance"
 
static NSString *const kInputAction = @"@"inputAction"
 
static NSString *const kEnableDeltaModel = @"@"enableDeltaModel"
 
static NSString *const kSmartDashesType = @"@"smartDashesType"
 
static NSString *const kSmartQuotesType = @"@"smartQuotesType"
 
static NSString *const kAssociatedAutofillFields = @"@"fields"
 
static NSString *const kAutofillProperties = @"@"autofill"
 
static NSString *const kAutofillId = @"@"uniqueIdentifier"
 
static NSString *const kAutofillEditingValue = @"@"editingValue"
 
static NSString *const kAutofillHints = @"@"hints"
 
static NSString *const kAutocorrectionType = @"@"autocorrect"
 
const char * _selectionAffinity
 
FlutterTextRange_selectedTextRange
 
UIInputViewController * _inputViewController
 
CGRect _cachedFirstRect
 
bool _isSystemKeyboardEnabled
 
bool _isFloatingCursorActive
 
BOOL _decommissioned
 

Function Documentation

◆ autofillIdFromDictionary()

static NSString* autofillIdFromDictionary ( NSDictionary *  dictionary)
static

Definition at line 280 of file FlutterTextInputPlugin.mm.

References kAutofillId, kAutofillProperties, and kSecureTextEntry.

Referenced by FlutterTextInputPlugin(TestMethods)::handleMethodCall:result:, and isFieldPasswordRelated().

280  {
281  NSDictionary* autofill = dictionary[kAutofillProperties];
282  if (autofill) {
283  return autofill[kAutofillId];
284  }
285 
286  // When autofill is nil, the field may still need an autofill id
287  // if the field is for password.
288  return [dictionary[kSecureTextEntry] boolValue] ? @"password" : nil;
289 }
static NSString *const kSecureTextEntry
static NSString *const kAutofillId
static NSString *const kAutofillProperties

◆ autofillTypeOf()

static FlutterAutofillType autofillTypeOf ( NSDictionary *  configuration)
static

Definition at line 379 of file FlutterTextInputPlugin.mm.

References isFieldPasswordRelated(), kAssociatedAutofillFields, kAutofillHints, kAutofillProperties, and ToUITextContentType().

Referenced by FlutterTextInputPlugin(TestMethods)::handleMethodCall:result:.

379  {
380  for (NSDictionary* field in configuration[kAssociatedAutofillFields]) {
381  if (isFieldPasswordRelated(field)) {
382  return FlutterAutofillTypePassword;
383  }
384  }
385 
386  if (isFieldPasswordRelated(configuration)) {
387  return FlutterAutofillTypePassword;
388  }
389 
390  if (@available(iOS 10.0, *)) {
391  NSDictionary* autofill = configuration[kAutofillProperties];
392  UITextContentType contentType = ToUITextContentType(autofill[kAutofillHints]);
393  return !autofill || [contentType isEqualToString:@""] ? FlutterAutofillTypeNone
394  : FlutterAutofillTypeRegular;
395  }
396 
397  return FlutterAutofillTypeNone;
398 }
static BOOL isFieldPasswordRelated(NSDictionary *configuration)
static NSString *const kAssociatedAutofillFields
static NSString *const kAutofillProperties
static NSString *const kAutofillHints
static UITextContentType ToUITextContentType(NSArray< NSString *> *hints)

◆ isFieldPasswordRelated()

static BOOL isFieldPasswordRelated ( NSDictionary *  configuration)
static

Definition at line 349 of file FlutterTextInputPlugin.mm.

References autofillIdFromDictionary(), kAutofillHints, kAutofillProperties, kSecureTextEntry, and ToUITextContentType().

Referenced by autofillTypeOf().

349  {
350  if (@available(iOS 10.0, *)) {
351  // Autofill is explicitly disabled if the id isn't present.
352  if (!autofillIdFromDictionary(configuration)) {
353  return NO;
354  }
355 
356  BOOL isSecureTextEntry = [configuration[kSecureTextEntry] boolValue];
357  if (isSecureTextEntry)
358  return YES;
359 
360  NSDictionary* autofill = configuration[kAutofillProperties];
361  UITextContentType contentType = ToUITextContentType(autofill[kAutofillHints]);
362 
363  if (@available(iOS 11.0, *)) {
364  if ([contentType isEqualToString:UITextContentTypePassword] ||
365  [contentType isEqualToString:UITextContentTypeUsername]) {
366  return YES;
367  }
368  }
369 
370  if (@available(iOS 12.0, *)) {
371  if ([contentType isEqualToString:UITextContentTypeNewPassword]) {
372  return YES;
373  }
374  }
375  }
376  return NO;
377 }
static NSString *const kSecureTextEntry
int BOOL
Definition: windows_types.h:37
static NSString *const kAutofillProperties
static NSString * autofillIdFromDictionary(NSDictionary *dictionary)
static NSString *const kAutofillHints
static UITextContentType ToUITextContentType(NSArray< NSString *> *hints)

◆ NS_ENUM()

typedef NS_ENUM ( NSInteger  ,
FlutterAutofillType   
)

Definition at line 340 of file FlutterTextInputPlugin.mm.

340  {
341  // The field does not have autofillable content. Additionally if
342  // the field is currently in the autofill context, it will be
343  // removed from the context without triggering autofill save.
344  FlutterAutofillTypeNone,
345  FlutterAutofillTypeRegular,
346  FlutterAutofillTypePassword,
347 };

◆ shouldShowSystemKeyboard()

static BOOL shouldShowSystemKeyboard ( NSDictionary *  type)
static

Definition at line 75 of file FlutterTextInputPlugin.mm.

75  {
76  NSString* inputType = type[@"name"];
77  return ![inputType isEqualToString:@"TextInputType.none"];
78 }
KeyCallType type

◆ ToUIKeyboardType()

static UIKeyboardType ToUIKeyboardType ( NSDictionary *  type)
static

Definition at line 79 of file FlutterTextInputPlugin.mm.

79  {
80  NSString* inputType = type[@"name"];
81  if ([inputType isEqualToString:@"TextInputType.address"])
82  return UIKeyboardTypeDefault;
83  if ([inputType isEqualToString:@"TextInputType.datetime"])
84  return UIKeyboardTypeNumbersAndPunctuation;
85  if ([inputType isEqualToString:@"TextInputType.emailAddress"])
86  return UIKeyboardTypeEmailAddress;
87  if ([inputType isEqualToString:@"TextInputType.multiline"])
88  return UIKeyboardTypeDefault;
89  if ([inputType isEqualToString:@"TextInputType.name"])
90  return UIKeyboardTypeNamePhonePad;
91  if ([inputType isEqualToString:@"TextInputType.number"]) {
92  if ([type[@"signed"] boolValue])
93  return UIKeyboardTypeNumbersAndPunctuation;
94  if ([type[@"decimal"] boolValue])
95  return UIKeyboardTypeDecimalPad;
96  return UIKeyboardTypeNumberPad;
97  }
98  if ([inputType isEqualToString:@"TextInputType.phone"])
99  return UIKeyboardTypePhonePad;
100  if ([inputType isEqualToString:@"TextInputType.text"])
101  return UIKeyboardTypeDefault;
102  if ([inputType isEqualToString:@"TextInputType.url"])
103  return UIKeyboardTypeURL;
104  return UIKeyboardTypeDefault;
105 }
KeyCallType type

◆ ToUIReturnKeyType()

static UIReturnKeyType ToUIReturnKeyType ( NSString *  inputType)
static

Definition at line 119 of file FlutterTextInputPlugin.mm.

119  {
120  // Where did the term "unspecified" come from? iOS has a "default" and Android
121  // has "unspecified." These 2 terms seem to mean the same thing but we need
122  // to pick just one. "unspecified" was chosen because "default" is often a
123  // reserved word in languages with switch statements (dart, java, etc).
124  if ([inputType isEqualToString:@"TextInputAction.unspecified"])
125  return UIReturnKeyDefault;
126 
127  if ([inputType isEqualToString:@"TextInputAction.done"])
128  return UIReturnKeyDone;
129 
130  if ([inputType isEqualToString:@"TextInputAction.go"])
131  return UIReturnKeyGo;
132 
133  if ([inputType isEqualToString:@"TextInputAction.send"])
134  return UIReturnKeySend;
135 
136  if ([inputType isEqualToString:@"TextInputAction.search"])
137  return UIReturnKeySearch;
138 
139  if ([inputType isEqualToString:@"TextInputAction.next"])
140  return UIReturnKeyNext;
141 
142  if (@available(iOS 9.0, *))
143  if ([inputType isEqualToString:@"TextInputAction.continueAction"])
144  return UIReturnKeyContinue;
145 
146  if ([inputType isEqualToString:@"TextInputAction.join"])
147  return UIReturnKeyJoin;
148 
149  if ([inputType isEqualToString:@"TextInputAction.route"])
150  return UIReturnKeyRoute;
151 
152  if ([inputType isEqualToString:@"TextInputAction.emergencyCall"])
153  return UIReturnKeyEmergencyCall;
154 
155  if ([inputType isEqualToString:@"TextInputAction.newline"])
156  return UIReturnKeyDefault;
157 
158  // Present default key if bad input type is given.
159  return UIReturnKeyDefault;
160 }

◆ ToUITextAutoCapitalizationType()

static UITextAutocapitalizationType ToUITextAutoCapitalizationType ( NSDictionary *  type)
static

Definition at line 107 of file FlutterTextInputPlugin.mm.

107  {
108  NSString* textCapitalization = type[@"textCapitalization"];
109  if ([textCapitalization isEqualToString:@"TextCapitalization.characters"]) {
110  return UITextAutocapitalizationTypeAllCharacters;
111  } else if ([textCapitalization isEqualToString:@"TextCapitalization.sentences"]) {
112  return UITextAutocapitalizationTypeSentences;
113  } else if ([textCapitalization isEqualToString:@"TextCapitalization.words"]) {
114  return UITextAutocapitalizationTypeWords;
115  }
116  return UITextAutocapitalizationTypeNone;
117 }
KeyCallType type

◆ ToUITextContentType()

static UITextContentType ToUITextContentType ( NSArray< NSString *> *  hints)
static

Definition at line 162 of file FlutterTextInputPlugin.mm.

Referenced by autofillTypeOf(), and isFieldPasswordRelated().

162  {
163  if (!hints || hints.count == 0) {
164  // If no hints are specified, use the default content type nil.
165  return nil;
166  }
167 
168  NSString* hint = hints[0];
169  if (@available(iOS 10.0, *)) {
170  if ([hint isEqualToString:@"addressCityAndState"]) {
171  return UITextContentTypeAddressCityAndState;
172  }
173 
174  if ([hint isEqualToString:@"addressState"]) {
175  return UITextContentTypeAddressState;
176  }
177 
178  if ([hint isEqualToString:@"addressCity"]) {
179  return UITextContentTypeAddressCity;
180  }
181 
182  if ([hint isEqualToString:@"sublocality"]) {
183  return UITextContentTypeSublocality;
184  }
185 
186  if ([hint isEqualToString:@"streetAddressLine1"]) {
187  return UITextContentTypeStreetAddressLine1;
188  }
189 
190  if ([hint isEqualToString:@"streetAddressLine2"]) {
191  return UITextContentTypeStreetAddressLine2;
192  }
193 
194  if ([hint isEqualToString:@"countryName"]) {
195  return UITextContentTypeCountryName;
196  }
197 
198  if ([hint isEqualToString:@"fullStreetAddress"]) {
199  return UITextContentTypeFullStreetAddress;
200  }
201 
202  if ([hint isEqualToString:@"postalCode"]) {
203  return UITextContentTypePostalCode;
204  }
205 
206  if ([hint isEqualToString:@"location"]) {
207  return UITextContentTypeLocation;
208  }
209 
210  if ([hint isEqualToString:@"creditCardNumber"]) {
211  return UITextContentTypeCreditCardNumber;
212  }
213 
214  if ([hint isEqualToString:@"email"]) {
215  return UITextContentTypeEmailAddress;
216  }
217 
218  if ([hint isEqualToString:@"jobTitle"]) {
219  return UITextContentTypeJobTitle;
220  }
221 
222  if ([hint isEqualToString:@"givenName"]) {
223  return UITextContentTypeGivenName;
224  }
225 
226  if ([hint isEqualToString:@"middleName"]) {
227  return UITextContentTypeMiddleName;
228  }
229 
230  if ([hint isEqualToString:@"familyName"]) {
231  return UITextContentTypeFamilyName;
232  }
233 
234  if ([hint isEqualToString:@"name"]) {
235  return UITextContentTypeName;
236  }
237 
238  if ([hint isEqualToString:@"namePrefix"]) {
239  return UITextContentTypeNamePrefix;
240  }
241 
242  if ([hint isEqualToString:@"nameSuffix"]) {
243  return UITextContentTypeNameSuffix;
244  }
245 
246  if ([hint isEqualToString:@"nickname"]) {
247  return UITextContentTypeNickname;
248  }
249 
250  if ([hint isEqualToString:@"organizationName"]) {
251  return UITextContentTypeOrganizationName;
252  }
253 
254  if ([hint isEqualToString:@"telephoneNumber"]) {
255  return UITextContentTypeTelephoneNumber;
256  }
257  }
258 
259  if (@available(iOS 11.0, *)) {
260  if ([hint isEqualToString:@"password"]) {
261  return UITextContentTypePassword;
262  }
263  }
264 
265  if (@available(iOS 12.0, *)) {
266  if ([hint isEqualToString:@"oneTimeCode"]) {
267  return UITextContentTypeOneTimeCode;
268  }
269 
270  if ([hint isEqualToString:@"newPassword"]) {
271  return UITextContentTypeNewPassword;
272  }
273  }
274 
275  return hints[0];
276 }

Variable Documentation

◆ _cachedFirstRect

CGRect _cachedFirstRect

Definition at line 582 of file FlutterTextInputPlugin.mm.

◆ _decommissioned

BOOL _decommissioned

Definition at line 590 of file FlutterTextInputPlugin.mm.

◆ _inputViewController

UIInputViewController* _inputViewController

Definition at line 581 of file FlutterTextInputPlugin.mm.

◆ _isFloatingCursorActive

bool _isFloatingCursorActive

Definition at line 587 of file FlutterTextInputPlugin.mm.

◆ _isSystemKeyboardEnabled

bool _isSystemKeyboardEnabled

Definition at line 586 of file FlutterTextInputPlugin.mm.

◆ _kTextAffinityDownstream

const char _kTextAffinityDownstream[] = "TextAffinity.downstream"
static

Definition at line 13 of file FlutterTextInputPlugin.mm.

◆ _kTextAffinityUpstream

const char _kTextAffinityUpstream[] = "TextAffinity.upstream"
static

Definition at line 14 of file FlutterTextInputPlugin.mm.

◆ _selectedTextRange

FlutterTextRange* _selectedTextRange

Definition at line 580 of file FlutterTextInputPlugin.mm.

◆ _selectionAffinity

const char* _selectionAffinity
Initial value:
{
int _textInputClient

Definition at line 577 of file FlutterTextInputPlugin.mm.

◆ kAssociatedAutofillFields

NSString* const kAssociatedAutofillFields = @"@"fields"
static

◆ kAutocorrectionType

NSString* const kAutocorrectionType = @"@"autocorrect"
static

Definition at line 67 of file FlutterTextInputPlugin.mm.

◆ kAutofillEditingValue

NSString* const kAutofillEditingValue = @"@"editingValue"
static

Definition at line 64 of file FlutterTextInputPlugin.mm.

◆ kAutofillHints

NSString* const kAutofillHints = @"@"hints"
static

Definition at line 65 of file FlutterTextInputPlugin.mm.

Referenced by autofillTypeOf(), and isFieldPasswordRelated().

◆ kAutofillId

NSString* const kAutofillId = @"@"uniqueIdentifier"
static

Definition at line 63 of file FlutterTextInputPlugin.mm.

Referenced by autofillIdFromDictionary().

◆ kAutofillProperties

NSString* const kAutofillProperties = @"@"autofill"
static

◆ kClearClientMethod

NSString* const kClearClientMethod = @"@"TextInput.clearClient"
static

◆ kEnableDeltaModel

NSString* const kEnableDeltaModel = @"@"enableDeltaModel"
static

Definition at line 54 of file FlutterTextInputPlugin.mm.

◆ kFinishAutofillContextMethod

NSString* const kFinishAutofillContextMethod = @"@"TextInput.finishAutofillContext"
static

◆ kHideMethod

NSString* const kHideMethod = @"@"TextInput.hide"
static

◆ kInputAction

NSString* const kInputAction = @"@"inputAction"
static

Definition at line 53 of file FlutterTextInputPlugin.mm.

◆ kInvalidFirstRect

const CGRect kInvalidFirstRect = {{-1, -1}, {9999, 9999}}

◆ kKeyboardAppearance

NSString* const kKeyboardAppearance = @"@"keyboardAppearance"
static

Definition at line 52 of file FlutterTextInputPlugin.mm.

◆ kKeyboardType

NSString* const kKeyboardType = @"@"inputType"
static

Definition at line 51 of file FlutterTextInputPlugin.mm.

◆ kSecureTextEntry

NSString* const kSecureTextEntry = @"@"obscureText"
static

Definition at line 50 of file FlutterTextInputPlugin.mm.

Referenced by autofillIdFromDictionary(), and isFieldPasswordRelated().

◆ kSetClientMethod

NSString* const kSetClientMethod = @"@"TextInput.setClient"
static

◆ kSetEditableSizeAndTransformMethod

NSString* const kSetEditableSizeAndTransformMethod
static
Initial value:
=
@"@"TextInput.setEditableSizeAndTransform"

Definition at line 44 of file FlutterTextInputPlugin.mm.

Referenced by FlutterTextInputPlugin(TestMethods)::handleMethodCall:result:.

◆ kSetEditingStateMethod

NSString* const kSetEditingStateMethod = @"@"TextInput.setEditingState"
static

◆ kSetMarkedTextRectMethod

NSString* const kSetMarkedTextRectMethod = @"@"TextInput.setMarkedTextRect"
static

◆ kShowMethod

NSString* const kShowMethod = @"@"TextInput.show"
static

◆ kSmartDashesType

NSString* const kSmartDashesType = @"@"smartDashesType"
static

Definition at line 56 of file FlutterTextInputPlugin.mm.

◆ kSmartQuotesType

NSString* const kSmartQuotesType = @"@"smartQuotesType"
static

Definition at line 57 of file FlutterTextInputPlugin.mm.

◆ kSpacePanBounds

const CGRect kSpacePanBounds = {{-2500, -2500}, {5000, 5000}}

Definition at line 35 of file FlutterTextInputPlugin.mm.

◆ kUITextInputAccessibilityEnablingDelaySeconds

constexpr double kUITextInputAccessibilityEnablingDelaySeconds = 0.5
static

Definition at line 17 of file FlutterTextInputPlugin.mm.