Skip to content

Commit 061e899

Browse files
Support all keyboard actions. (flutter#11344) (flutter#5620)
* Support all keyboard actions. (flutter#11344)
1 parent bc6b250 commit 061e899

File tree

5 files changed

+173
-13
lines changed

5 files changed

+173
-13
lines changed

shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,36 @@ public boolean sendKeyEvent(KeyEvent event) {
172172

173173
@Override
174174
public boolean performEditorAction(int actionCode) {
175-
// TODO(abarth): Support more actions.
176175
switch (actionCode) {
176+
// TODO(mattcarroll): is newline an appropriate action for "none"?
177177
case EditorInfo.IME_ACTION_NONE:
178178
mFlutterChannel.invokeMethod("TextInputClient.performAction",
179179
Arrays.asList(mClient, "TextInputAction.newline"));
180180
break;
181+
case EditorInfo.IME_ACTION_UNSPECIFIED:
182+
mFlutterChannel.invokeMethod("TextInputClient.performAction",
183+
Arrays.asList(mClient, "TextInputAction.unspecified"));
184+
break;
185+
case EditorInfo.IME_ACTION_GO:
186+
mFlutterChannel.invokeMethod("TextInputClient.performAction",
187+
Arrays.asList(mClient, "TextInputAction.go"));
188+
break;
189+
case EditorInfo.IME_ACTION_SEARCH:
190+
mFlutterChannel.invokeMethod("TextInputClient.performAction",
191+
Arrays.asList(mClient, "TextInputAction.search"));
192+
break;
193+
case EditorInfo.IME_ACTION_SEND:
194+
mFlutterChannel.invokeMethod("TextInputClient.performAction",
195+
Arrays.asList(mClient, "TextInputAction.send"));
196+
break;
197+
case EditorInfo.IME_ACTION_NEXT:
198+
mFlutterChannel.invokeMethod("TextInputClient.performAction",
199+
Arrays.asList(mClient, "TextInputAction.next"));
200+
break;
201+
case EditorInfo.IME_ACTION_PREVIOUS:
202+
mFlutterChannel.invokeMethod("TextInputClient.performAction",
203+
Arrays.asList(mClient, "TextInputAction.previous"));
204+
break;
181205
default:
182206
case EditorInfo.IME_ACTION_DONE:
183207
mFlutterChannel.invokeMethod("TextInputClient.performAction",

shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,29 @@ else if (inputType.equals("TextInputType.url"))
115115
}
116116

117117
private static int inputActionFromTextInputAction(String inputAction) {
118-
if (inputAction.equals("TextInputAction.newline"))
119-
return EditorInfo.IME_ACTION_NONE;
120-
return EditorInfo.IME_ACTION_DONE;
118+
switch (inputAction) {
119+
case "TextInputAction.newline":
120+
return EditorInfo.IME_ACTION_NONE;
121+
case "TextInputAction.none":
122+
return EditorInfo.IME_ACTION_NONE;
123+
case "TextInputAction.unspecified":
124+
return EditorInfo.IME_ACTION_UNSPECIFIED;
125+
case "TextInputAction.done":
126+
return EditorInfo.IME_ACTION_DONE;
127+
case "TextInputAction.go":
128+
return EditorInfo.IME_ACTION_GO;
129+
case "TextInputAction.search":
130+
return EditorInfo.IME_ACTION_SEARCH;
131+
case "TextInputAction.send":
132+
return EditorInfo.IME_ACTION_SEND;
133+
case "TextInputAction.next":
134+
return EditorInfo.IME_ACTION_NEXT;
135+
case "TextInputAction.previous":
136+
return EditorInfo.IME_ACTION_PREVIOUS;
137+
default:
138+
// Present default key if bad input type is given.
139+
return EditorInfo.IME_ACTION_UNSPECIFIED;
140+
}
121141
}
122142

123143
public InputConnection createInputConnection(FlutterView view, EditorInfo outAttrs)

shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,16 @@
88
#import <Foundation/Foundation.h>
99

1010
typedef NS_ENUM(NSInteger, FlutterTextInputAction) {
11+
FlutterTextInputActionUnspecified,
1112
FlutterTextInputActionDone,
13+
FlutterTextInputActionGo,
14+
FlutterTextInputActionSend,
15+
FlutterTextInputActionSearch,
16+
FlutterTextInputActionNext,
17+
FlutterTextInputActionContinue,
18+
FlutterTextInputActionJoin,
19+
FlutterTextInputActionRoute,
20+
FlutterTextInputActionEmergencyCall,
1221
FlutterTextInputActionNewline,
1322
};
1423

shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm

Lines changed: 85 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.h"
66

77
#include <UIKit/UIKit.h>
8+
#include <Foundation/Foundation.h>
89

910
static const char _kTextAffinityDownstream[] = "TextAffinity.downstream";
1011
static const char _kTextAffinityUpstream[] = "TextAffinity.upstream";
@@ -30,9 +31,46 @@ static UIKeyboardType ToUIKeyboardType(NSDictionary* type) {
3031
}
3132

3233
static UIReturnKeyType ToUIReturnKeyType(NSString* inputType) {
33-
if ([inputType isEqualToString:@"TextInputType.multiline"])
34+
// Where did the term "unspecified" come from? iOS has a "default" and Android
35+
// has "unspecified." These 2 terms seem to mean the same thing but we need
36+
// to pick just one. "unspecified" was chosen because "default" is often a
37+
// reserved word in languages with switch statements (dart, java, etc).
38+
if ([inputType isEqualToString:@"TextInputAction.unspecified"])
39+
return UIReturnKeyDefault;
40+
41+
if ([inputType isEqualToString:@"TextInputAction.done"])
42+
return UIReturnKeyDone;
43+
44+
if ([inputType isEqualToString:@"TextInputAction.go"])
45+
return UIReturnKeyGo;
46+
47+
if ([inputType isEqualToString:@"TextInputAction.send"])
48+
return UIReturnKeySend;
49+
50+
if ([inputType isEqualToString:@"TextInputAction.search"])
51+
return UIReturnKeySearch;
52+
53+
if ([inputType isEqualToString:@"TextInputAction.next"])
54+
return UIReturnKeyNext;
55+
56+
if (@available(iOS 9.0, *))
57+
if ([inputType isEqualToString:@"TextInputAction.continueAction"])
58+
return UIReturnKeyContinue;
59+
60+
if ([inputType isEqualToString:@"TextInputAction.join"])
61+
return UIReturnKeyJoin;
62+
63+
if ([inputType isEqualToString:@"TextInputAction.route"])
64+
return UIReturnKeyRoute;
65+
66+
if ([inputType isEqualToString:@"TextInputAction.emergencyCall"])
67+
return UIReturnKeyEmergencyCall;
68+
69+
if ([inputType isEqualToString:@"TextInputAction.newline"])
3470
return UIReturnKeyDefault;
35-
return UIReturnKeyDone;
71+
72+
// Present default key if bad input type is given.
73+
return UIReturnKeyDefault;
3674
}
3775

3876
static UITextAutocapitalizationType ToUITextAutocapitalizationType(NSString* inputType) {
@@ -277,14 +315,52 @@ - (void)replaceRange:(UITextRange*)range withText:(NSString*)text {
277315
}
278316

279317
- (BOOL)shouldChangeTextInRange:(UITextRange*)range replacementText:(NSString*)text {
280-
if (self.returnKeyType == UIReturnKeyDone && [text isEqualToString:@"\n"]) {
281-
[self resignFirstResponder];
282-
[self removeFromSuperview];
283-
[_textInputDelegate performAction:FlutterTextInputActionDone withClient:_textInputClient];
318+
if (self.returnKeyType == UIReturnKeyDefault && [text isEqualToString:@"\n"]) {
319+
[_textInputDelegate performAction:FlutterTextInputActionNewline withClient:_textInputClient];
320+
return YES;
321+
}
322+
323+
if ([text isEqualToString:@"\n"]) {
324+
FlutterTextInputAction action;
325+
switch (self.returnKeyType) {
326+
case UIReturnKeyDefault:
327+
action = FlutterTextInputActionUnspecified;
328+
break;
329+
case UIReturnKeyDone:
330+
action = FlutterTextInputActionDone;
331+
break;
332+
case UIReturnKeyGo:
333+
action = FlutterTextInputActionGo;
334+
break;
335+
case UIReturnKeySend:
336+
action = FlutterTextInputActionSend;
337+
break;
338+
case UIReturnKeySearch:
339+
case UIReturnKeyGoogle:
340+
case UIReturnKeyYahoo:
341+
action = FlutterTextInputActionSearch;
342+
break;
343+
case UIReturnKeyNext:
344+
action = FlutterTextInputActionNext;
345+
break;
346+
case UIReturnKeyContinue:
347+
action = FlutterTextInputActionContinue;
348+
break;
349+
case UIReturnKeyJoin:
350+
action = FlutterTextInputActionJoin;
351+
break;
352+
case UIReturnKeyRoute:
353+
action = FlutterTextInputActionRoute;
354+
break;
355+
case UIReturnKeyEmergencyCall:
356+
action = FlutterTextInputActionEmergencyCall;
357+
break;
358+
}
359+
360+
[_textInputDelegate performAction:action withClient:_textInputClient];
284361
return NO;
285362
}
286-
if (self.returnKeyType == UIReturnKeyDefault && [text isEqualToString:@"\n"])
287-
[_textInputDelegate performAction:FlutterTextInputActionNewline withClient:_textInputClient];
363+
288364
return YES;
289365
}
290366

@@ -612,7 +688,7 @@ - (void)hideTextInput {
612688
- (void)setTextInputClient:(int)client withConfiguration:(NSDictionary*)configuration {
613689
NSDictionary* inputType = configuration[@"inputType"];
614690
_view.keyboardType = ToUIKeyboardType(inputType);
615-
_view.returnKeyType = ToUIReturnKeyType(inputType[@"name"]);
691+
_view.returnKeyType = ToUIReturnKeyType(configuration[@"inputAction"]);
616692
_view.autocapitalizationType = ToUITextAutocapitalizationType(inputType[@"name"]);
617693
_view.secureTextEntry = [configuration[@"obscureText"] boolValue];
618694
NSString* autocorrect = configuration[@"autocorrect"];

shell/platform/darwin/ios/framework/Source/FlutterViewController.mm

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,9 +717,40 @@ - (void)updateEditingClient:(int)client withState:(NSDictionary*)state {
717717
- (void)performAction:(FlutterTextInputAction)action withClient:(int)client {
718718
NSString* actionString;
719719
switch (action) {
720+
case FlutterTextInputActionUnspecified:
721+
// Where did the term "unspecified" come from? iOS has a "default" and Android
722+
// has "unspecified." These 2 terms seem to mean the same thing but we need
723+
// to pick just one. "unspecified" was chosen because "default" is often a
724+
// reserved word in languages with switch statements (dart, java, etc).
725+
actionString = @"TextInputAction.unspecified";
726+
break;
720727
case FlutterTextInputActionDone:
721728
actionString = @"TextInputAction.done";
722729
break;
730+
case FlutterTextInputActionGo:
731+
actionString = @"TextInputAction.go";
732+
break;
733+
case FlutterTextInputActionSend:
734+
actionString = @"TextInputAction.send";
735+
break;
736+
case FlutterTextInputActionSearch:
737+
actionString = @"TextInputAction.search";
738+
break;
739+
case FlutterTextInputActionNext:
740+
actionString = @"TextInputAction.next";
741+
break;
742+
case FlutterTextInputActionContinue:
743+
actionString = @"TextInputAction.continue";
744+
break;
745+
case FlutterTextInputActionJoin:
746+
actionString = @"TextInputAction.join";
747+
break;
748+
case FlutterTextInputActionRoute:
749+
actionString = @"TextInputAction.route";
750+
break;
751+
case FlutterTextInputActionEmergencyCall:
752+
actionString = @"TextInputAction.emergencyCall";
753+
break;
723754
case FlutterTextInputActionNewline:
724755
actionString = @"TextInputAction.newline";
725756
break;

0 commit comments

Comments
 (0)