@@ -856,6 +856,17 @@ abstract class TextInputClient {
856
856
///
857
857
/// [TextInputClient] should cleanup its connection and finalize editing.
858
858
void connectionClosed ();
859
+
860
+ /// Framework notified of a text input [source] that has been updated.
861
+ ///
862
+ /// [TextInputClient] should re-attach itself if it wants to show the text
863
+ /// input control from the new text input source.
864
+ ///
865
+ /// See also:
866
+ ///
867
+ /// * [TextInput.attach] , a method used to re-attach the client.
868
+ /// * [TextInput.setSource] , a method used to change the text input source.
869
+ void didUpdateInputSource (TextInputSource source);
859
870
}
860
871
861
872
/// An interface for interacting with a text input control.
@@ -864,12 +875,26 @@ abstract class TextInputClient {
864
875
/// over the [SystemChannels.textInput] method channel. See [SystemChannels.textInput]
865
876
/// for more details about the method channel messages.
866
877
///
878
+ /// ### Connect to a different input source
879
+ ///
880
+ /// The default [TextInputConnection] can be replaced by setting a custom
881
+ /// [TextInputSource] with [TextInput.setSource] . The text input source is used
882
+ /// to create [TextInputConnection] instances whenever a [TextInputClient] is
883
+ /// attached.
884
+ ///
885
+ /// A custom implementation of the [TextInputConnection] interface can override
886
+ /// the default method channel connection, and delegate text input calls from the
887
+ /// framework (i.e. the attached [TextInputClient] ), for example, to an in-app
888
+ /// virtual keyboard on platforms that don't have one provided by the system.
889
+ ///
867
890
/// See also:
868
891
///
869
892
/// * [TextInput.attach] , a method used to establish a [TextInputConnection]
870
893
/// between the system's text input and a [TextInputClient].
871
894
/// * [EditableText] , a [TextInputClient] that connects to and interacts with
872
895
/// the system's text input using a [TextInputConnection].
896
+ /// * [TextInput.setSource] , used to register a text input source for creating
897
+ /// creating [TextInputConnection] instances.
873
898
abstract class TextInputConnection {
874
899
/// Creates a connection for a [TextInputClient] .
875
900
TextInputConnection (this ._client)
@@ -1300,11 +1325,33 @@ class TextInput {
1300
1325
@visibleForTesting
1301
1326
static void setChannel (MethodChannel newChannel) {
1302
1327
assert (() {
1303
- _TextInputSource .setChannel (newChannel);
1328
+ _DefaultTextInputSource .setChannel (newChannel);
1304
1329
return true ;
1305
1330
}());
1306
1331
}
1307
1332
1333
+ /// Sets the [TextInputSource] used to attach and detach text input clients.
1334
+ /// The text input source is responsible for creating [TextInputConnection]
1335
+ /// instances that are used to communicate with the currently attached
1336
+ /// [TextInputClient] .
1337
+ ///
1338
+ /// The default text input source can be restored by passing
1339
+ /// [TextInput.defaultSource] .
1340
+ ///
1341
+ /// If there is a [TextInputClient] attached at the time of calling
1342
+ /// [TextInput.setSource] , the current text input client is notified via
1343
+ /// [TextInputClient.didUpdateInputSource] .
1344
+ ///
1345
+ /// See also:
1346
+ ///
1347
+ /// * [TextInput.defaultSource] , the default text input source instance.
1348
+ static void setSource (TextInputSource source) {
1349
+ _instance._currentSource.cleanup ();
1350
+ _instance._currentSource = source..init ();
1351
+ final TextInputClient ? client = _instance._currentConnection? ._client;
1352
+ client? .didUpdateInputSource (source);
1353
+ }
1354
+
1308
1355
static final TextInput _instance = TextInput ._();
1309
1356
1310
1357
static const List <TextInputAction > _androidSupportedInputActions = < TextInputAction > [
@@ -1384,7 +1431,20 @@ class TextInput {
1384
1431
return true ;
1385
1432
}
1386
1433
1387
- final _TextInputSource _currentSource = _TextInputSource ();
1434
+ /// The default instance of [TextInputSource] .
1435
+ ///
1436
+ /// The default text input source creates [TextInputConnection] instances that
1437
+ /// communicate with the platform text input plugin over the
1438
+ /// [SystemChannels.textInput] method channel. See [SystemChannels.textInput]
1439
+ /// for more details about the method channel messages.
1440
+ ///
1441
+ /// See also:
1442
+ ///
1443
+ /// * [TextInput.setSource] , a method to set the current text input source.
1444
+ static final TextInputSource defaultSource = _DefaultTextInputSource ();
1445
+
1446
+ TextInputSource _currentSource = defaultSource;
1447
+
1388
1448
TextInputConnection ? _currentConnection;
1389
1449
late TextInputConfiguration _currentConfiguration;
1390
1450
@@ -1501,28 +1561,84 @@ class TextInput {
1501
1561
}
1502
1562
}
1503
1563
1504
- class _TextInputSource {
1564
+ /// An interface for attaching and detaching [TextInputClient] .
1565
+ ///
1566
+ /// [TextInputSource] creates is responsible for creating [TextInputConnection]
1567
+ /// instances that are used to communicate with the currently attached
1568
+ /// [TextInputClient] .
1569
+ ///
1570
+ /// The default text input source, available via [TextInput.defaultSource] ,
1571
+ /// creates [TextInputConnection] instances that communicate with the platform
1572
+ /// text input plugin over the [SystemChannels.textInput] method channel. See
1573
+ /// [SystemChannels.textInput] for more details about the text input method
1574
+ /// channel messages.
1575
+ ///
1576
+ /// ### Custom text input sources
1577
+ ///
1578
+ /// A custom text input source can delegate text input calls from the framework
1579
+ /// (i.e. the attached [TextInputClient] ), for example, to an in-app virtual
1580
+ /// keyboard on platforms that don't have one provided by the system.
1581
+ ///
1582
+ /// See also:
1583
+ ///
1584
+ /// * [TextInput.setSource] , a method for setting the desired text input source.
1585
+ abstract class TextInputSource {
1586
+ /// TODO(jpnurmi)
1587
+ void init ();
1588
+
1589
+ /// TODO(jpnurmi)
1590
+ void cleanup ();
1591
+
1592
+ /// Attaches the current [TextInputClient] and creates a [TextInputConnection]
1593
+ /// used to interact with the text input control.
1594
+ ///
1595
+ /// This method is called by the framework when a [client] should be attached.
1596
+ ///
1597
+ /// See also:
1598
+ ///
1599
+ /// * [TextInput.attach]
1600
+ TextInputConnection attach (TextInputClient client);
1601
+
1602
+ /// Detaches the current [TextInputClient] from the text input control.
1603
+ ///
1604
+ /// This method is called by the framework when a [client] should be detached.
1605
+ ///
1606
+ /// See also:
1607
+ ///
1608
+ /// * [TextInput.attach]
1609
+ void detach (TextInputClient client);
1610
+
1611
+ /// TODO(jpnurmi)
1612
+ void finishAutofillContext ({bool shouldSave = true });
1613
+ }
1614
+
1615
+ class _DefaultTextInputSource implements TextInputSource {
1505
1616
static MethodChannel ? _channel;
1506
1617
1507
1618
static void setChannel (MethodChannel newChannel) {
1508
1619
_channel = newChannel..setMethodCallHandler (_handleTextInputInvocation);
1509
1620
}
1510
1621
1622
+ @override
1511
1623
void init () {
1512
1624
_channel ?? = SystemChannels .textInput;
1513
1625
_channel! .setMethodCallHandler (_handleTextInputInvocation);
1514
1626
}
1515
1627
1628
+ @override
1516
1629
void cleanup () {
1517
1630
_channel! .setMethodCallHandler ((MethodCall methodCall) async {});
1518
1631
}
1519
1632
1633
+ @override
1520
1634
TextInputConnection attach (TextInputClient client) {
1521
1635
return _TextInputChannelConnection (client, _channel! );
1522
1636
}
1523
1637
1638
+ @override
1524
1639
void detach (TextInputClient client) {}
1525
1640
1641
+ @override
1526
1642
void finishAutofillContext ({bool shouldSave = true }) {
1527
1643
_channel! .invokeMethod <void >(
1528
1644
'TextInput.finishAutofillContext' ,
0 commit comments