From e0706883cbe123cabf464bd5730d885138b71c78 Mon Sep 17 00:00:00 2001 From: Angelo Silvestre Date: Sun, 1 Oct 2023 20:16:04 -0300 Subject: [PATCH] Simulate IME messages when pressing ENTER (Resolves #19) (#20) --- lib/src/keyboard.dart | 93 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/lib/src/keyboard.dart b/lib/src/keyboard.dart index 08305d7..433666b 100644 --- a/lib/src/keyboard.dart +++ b/lib/src/keyboard.dart @@ -1,6 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_test_robots/src/input_method_engine.dart'; /// Simulates keyboard input in your Flutter app. /// @@ -61,7 +62,7 @@ extension KeyboardInput on WidgetTester { /// key simulations leads to unexpected results. By always using methods in this package, instead of /// standard Flutter methods, the simulated platform is guaranteed to match across calls, and also /// match the platform that's simulated within the surrounding test, i.e., [defaultTargetPlatform]. - /// @{endtemplate} + /// {@endtemplate} Future pressKey(LogicalKeyboardKey key) => sendKeyEvent(key, platform: _keyEventPlatform); /// Runs [simulateKeyDownEvent], using the current [defaultTargetPlatform] as the key simulators `platform` value. @@ -84,6 +85,54 @@ extension KeyboardInput on WidgetTester { await pumpAndSettle(); } + /// Simulates the user pressing ENTER in a widget attached to the IME. + /// + /// Instead of key events, this method generates a "\n" insertion followed by a TextInputAction.newline. + /// + /// {@template ime_client_getter} + /// The given [finder] must find a [StatefulWidget] whose [State] implements + /// [DeltaTextInputClient]. + /// + /// If the [DeltaTextInputClient] currently has selected text, that text is first deleted, + /// which is the standard behavior when typing new characters with an existing selection. + /// {@endtemplate} + Future pressEnterWithIme({ + Finder? finder, + GetDeltaTextInputClient? getter, + }) async { + if (!testTextInput.hasAnyClients) { + // There isn't any IME connections. + return; + } + + await ime.typeText('\n', finder: finder, getter: getter); + await pump(); + await testTextInput.receiveAction(TextInputAction.newline); + await pump(); + } + + /// Simulates pressing an ENTER button, either as a keyboard key, or as a software keyboard action button. + /// + /// First, this method simulates pressing the ENTER key on a physical keyboard. If that key event goes unhandled + /// then this method simulates pressing the newline action button on a software keyboard, which inserts "/n" + /// into the text, and also sends a NEWLINE action to the IME client. + /// + /// {@macro ime_client_getter} + Future pressEnterAdaptive({ + Finder? finder, + GetDeltaTextInputClient? getter, + }) async { + final handled = await sendKeyEvent(LogicalKeyboardKey.enter, platform: _keyEventPlatform); + if (handled) { + // The textfield handled the key event. + // It won't bubble up to the OS to generate text deltas or input actions. + await pumpAndSettle(); + return; + } + + await pressEnterWithIme(); + } + Future pressShiftEnter() async { await sendKeyDownEvent(LogicalKeyboardKey.shift, platform: _keyEventPlatform); await sendKeyDownEvent(LogicalKeyboardKey.enter, platform: _keyEventPlatform); @@ -113,6 +162,48 @@ extension KeyboardInput on WidgetTester { await pumpAndSettle(); } + /// Simulates the user pressing NUMPAD ENTER in a widget attached to the IME. + /// + /// Instead of key events, this method generates a "\n" insertion followed by a TextInputAction.newline. + /// Does nothing if there isn't an active IME connection. + /// + /// {@macro ime_client_getter} + Future pressNumpadEnterWithIme({ + Finder? finder, + GetDeltaTextInputClient? getter, + }) async { + if (!testTextInput.hasAnyClients) { + // There isn't any IME connections. + return; + } + + await ime.typeText('\n', finder: finder, getter: getter); + await testTextInput.receiveAction(TextInputAction.newline); + await pump(); + } + + /// Simulates pressing an NUMPAD ENTER button, either as a keyboard key, or as a software keyboard action button. + /// + /// First, this method simulates pressing the NUMPAD ENTER key on a physical keyboard. If that key event goes unhandled + /// then this method simulates pressing the newline action button on a software keyboard, which inserts "/n" + /// into the text, and also sends a NEWLINE action to the IME client. + /// + /// {@macro ime_client_getter} + Future pressNumpadEnterAdaptive({ + Finder? finder, + GetDeltaTextInputClient? getter, + }) async { + final handled = await sendKeyEvent(LogicalKeyboardKey.numpadEnter, platform: _keyEventPlatform); + if (handled) { + // The textfield handled the key event. + // It won't bubble up to the OS to generate text deltas or input actions. + await pumpAndSettle(); + return; + } + + await pressNumpadEnterWithIme(); + } + Future pressShiftNumpadEnter() async { await sendKeyDownEvent(LogicalKeyboardKey.shift, platform: _keyEventPlatform); await sendKeyDownEvent(LogicalKeyboardKey.numpadEnter, platform: _keyEventPlatform);