From 0a7572e9e9e96073ec7a529a41caae4c49c66c45 Mon Sep 17 00:00:00 2001 From: Georg Wechslberger Date: Mon, 16 Sep 2019 15:13:15 +0200 Subject: [PATCH 1/3] trigger TextInputAction on tab/enter keypresses --- lib/web_ui/lib/src/engine/text_editing.dart | 53 ++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/lib/web_ui/lib/src/engine/text_editing.dart b/lib/web_ui/lib/src/engine/text_editing.dart index 116401de8c609..bc920e4ab1f3a 100644 --- a/lib/web_ui/lib/src/engine/text_editing.dart +++ b/lib/web_ui/lib/src/engine/text_editing.dart @@ -42,6 +42,13 @@ void _setStaticStyleAttributes(html.HtmlElement domElement) { } } +enum _InputAction { + /// Procced to next Input Element + next, + /// Newline entered in Input Element + newline, +} + /// The current text and selection state of a text field. class EditingState { EditingState({this.text, this.baseOffset = 0, this.extentOffset = 0}); @@ -162,6 +169,7 @@ class InputConfiguration { } typedef _OnChangeCallback = void Function(EditingState editingState); +typedef _OnActionCallback = void Function(_InputAction inputAction); enum ElementType { /// The backing element is an ``. @@ -225,6 +233,7 @@ class TextEditingElement { html.HtmlElement domElement; EditingState _lastEditingState; _OnChangeCallback _onChange; + _OnActionCallback _onAction; final List> _subscriptions = >[]; @@ -268,12 +277,14 @@ class TextEditingElement { void enable( InputConfiguration inputConfig, { @required _OnChangeCallback onChange, + @required _OnActionCallback onAction, }) { assert(!_enabled); _initDomElement(inputConfig); _enabled = true; _onChange = onChange; + _onAction = onAction; // Chrome on Android will hide the onscreen keyboard when you tap outside // the text box. Instead, we want the framework to tell us to hide the @@ -304,7 +315,8 @@ class TextEditingElement { // Subscribe to text and selection changes. _subscriptions ..add(html.document.onSelectionChange.listen(_handleChange)) - ..add(domElement.onInput.listen(_handleChange)); + ..add(domElement.onInput.listen(_handleChange)) + ..add(domElement.onKeyDown.listen(_handleKeyDown)); } /// Disables the element so it's no longer used for text editing. @@ -440,6 +452,20 @@ class TextEditingElement { _onChange(_lastEditingState); } + // Map KeyboardEvent to InputAction + void _handleKeyDown(html.KeyboardEvent event) { + // Trigger newline action if enter key was pressed + if (event.which == 13) { + _onAction(_InputAction.newline); + } + // Trigger next action if tab key was pressed + if (event.which == 9) { + _onAction(_InputAction.next); + // prevent default action to avoid input element losing focus + event.preventDefault(); + } + } + @visibleForTesting EditingState calculateEditingState() { assert(domElement != null); @@ -700,6 +726,7 @@ class HybridTextEditing { editingElement.enable( InputConfiguration.fromFlutter(_configuration), onChange: _syncEditingStateToFlutter, + onAction: _sendInputActionToFlutter, ); } @@ -790,6 +817,30 @@ class HybridTextEditing { bool get doesKeyboardShiftInput => browserEngine == BrowserEngine.webkit && operatingSystem == OperatingSystem.iOs; + _InputActionToFlutter(_InputAction inputAction) { + switch(inputAction) { + case _InputAction.next: + return 'TextInputAction.next'; + break; + case _InputAction.newline: + return 'TextInputAction.newline'; + break; + } + return 'TextInputAction.unspecified'; + } + + void _sendInputActionToFlutter(_InputAction inputAction) { + ui.window.onPlatformMessage( + 'flutter/textinput', + const JSONMethodCodec().encodeMethodCall( + MethodCall('TextInputClient.performAction', [ + _clientId, + _InputActionToFlutter(inputAction), + ]), + ), + _emptyCallback, + ); + } /// These style attributes are dynamic throughout the life time of an input /// element. From 30a5c4b5d01b267024df0968c921ff34313deda1 Mon Sep 17 00:00:00 2001 From: Georg Wechslberger Date: Fri, 20 Sep 2019 17:30:33 +0200 Subject: [PATCH 2/3] trigger input action only for single line text input --- lib/web_ui/lib/src/engine/text_editing.dart | 31 +++++++++++++-------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/lib/web_ui/lib/src/engine/text_editing.dart b/lib/web_ui/lib/src/engine/text_editing.dart index bc920e4ab1f3a..ce5a6c8e524ba 100644 --- a/lib/web_ui/lib/src/engine/text_editing.dart +++ b/lib/web_ui/lib/src/engine/text_editing.dart @@ -43,9 +43,9 @@ void _setStaticStyleAttributes(html.HtmlElement domElement) { } enum _InputAction { - /// Procced to next Input Element + /// Procced to next enput element. next, - /// Newline entered in Input Element + /// Newline has been entered in current input element. newline, } @@ -452,17 +452,24 @@ class TextEditingElement { _onChange(_lastEditingState); } - // Map KeyboardEvent to InputAction + // Map KeyboardEvent to InputAction. void _handleKeyDown(html.KeyboardEvent event) { - // Trigger newline action if enter key was pressed - if (event.which == 13) { - _onAction(_InputAction.newline); - } - // Trigger next action if tab key was pressed - if (event.which == 9) { - _onAction(_InputAction.next); - // prevent default action to avoid input element losing focus - event.preventDefault(); + // Tab and enter key can only be mapped to actions for single line inputs. + if (_elementType == ElementType.input) { + // Trigger newline action if enter key was pressed. + if (event.which == 13) { + _onAction(_InputAction.newline); + } + // Trigger next action if tab key was pressed. + if (event.which == 9) { + _onAction(_InputAction.next); + // The default action of the browser is to focus the next element. + // As the browser is not able to focus flutter widgets, it will + // focus some part of its UI (e.g. the location bar). + // We prevent this action and leave it to the corresponding widget + // to change the focus. + event.preventDefault(); + } } } From 59640e863ef49d53a88958e858fbe1ce21b4e91e Mon Sep 17 00:00:00 2001 From: Georg Wechslberger Date: Fri, 20 Sep 2019 18:34:50 +0200 Subject: [PATCH 3/3] fixed formating --- lib/web_ui/lib/src/engine/text_editing.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/web_ui/lib/src/engine/text_editing.dart b/lib/web_ui/lib/src/engine/text_editing.dart index ce5a6c8e524ba..4049793ef457e 100644 --- a/lib/web_ui/lib/src/engine/text_editing.dart +++ b/lib/web_ui/lib/src/engine/text_editing.dart @@ -45,6 +45,7 @@ void _setStaticStyleAttributes(html.HtmlElement domElement) { enum _InputAction { /// Procced to next enput element. next, + /// Newline has been entered in current input element. newline, } @@ -464,9 +465,9 @@ class TextEditingElement { if (event.which == 9) { _onAction(_InputAction.next); // The default action of the browser is to focus the next element. - // As the browser is not able to focus flutter widgets, it will + // As the browser is not able to focus flutter widgets, it will // focus some part of its UI (e.g. the location bar). - // We prevent this action and leave it to the corresponding widget + // We prevent this action and leave it to the corresponding widget // to change the focus. event.preventDefault(); } @@ -825,7 +826,7 @@ class HybridTextEditing { browserEngine == BrowserEngine.webkit && operatingSystem == OperatingSystem.iOs; _InputActionToFlutter(_InputAction inputAction) { - switch(inputAction) { + switch (inputAction) { case _InputAction.next: return 'TextInputAction.next'; break;