diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 5d167e125da85..9029dcaf62348 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1267,7 +1267,6 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/initialization.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/js_interop/js_loader.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/js_interop/js_promise.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/key_map.g.dart -FILE: ../../../flutter/lib/web_ui/lib/src/engine/keyboard.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/keyboard_binding.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/mouse_cursor.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/navigation.dart @@ -1285,6 +1284,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/plugins.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/pointer_binding.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/pointer_converter.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/profiler.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/raw_keyboard.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/renderer.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/rrect_renderer.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/safe_browser_api.dart diff --git a/lib/web_ui/lib/src/engine.dart b/lib/web_ui/lib/src/engine.dart index 6249cc7994e95..54464dd4dba7e 100644 --- a/lib/web_ui/lib/src/engine.dart +++ b/lib/web_ui/lib/src/engine.dart @@ -108,7 +108,6 @@ export 'engine/initialization.dart'; export 'engine/js_interop/js_loader.dart'; export 'engine/js_interop/js_promise.dart'; export 'engine/key_map.g.dart'; -export 'engine/keyboard.dart'; export 'engine/keyboard_binding.dart'; export 'engine/mouse_cursor.dart'; export 'engine/navigation/history.dart'; @@ -125,6 +124,7 @@ export 'engine/plugins.dart'; export 'engine/pointer_binding.dart'; export 'engine/pointer_converter.dart'; export 'engine/profiler.dart'; +export 'engine/raw_keyboard.dart'; export 'engine/renderer.dart'; export 'engine/rrect_renderer.dart'; export 'engine/safe_browser_api.dart'; diff --git a/lib/web_ui/lib/src/engine/embedder.dart b/lib/web_ui/lib/src/engine/embedder.dart index 7c2b0ffaf6787..44677dbbefaf9 100644 --- a/lib/web_ui/lib/src/engine/embedder.dart +++ b/lib/web_ui/lib/src/engine/embedder.dart @@ -324,7 +324,7 @@ class FlutterViewEmbedder { } PointerBinding.initInstance(glassPaneElement); - KeyboardBinding.initInstance(glassPaneElement); + KeyboardBinding.initInstance(); if (domWindow.visualViewport == null && isWebKit) { // Older Safari versions sometimes give us bogus innerWidth/innerHeight diff --git a/lib/web_ui/lib/src/engine/initialization.dart b/lib/web_ui/lib/src/engine/initialization.dart index 025b1399f78b1..00ecdd3ac1ee6 100644 --- a/lib/web_ui/lib/src/engine/initialization.dart +++ b/lib/web_ui/lib/src/engine/initialization.dart @@ -8,12 +8,12 @@ import 'dart:developer' as developer; import 'package:ui/src/engine/assets.dart'; import 'package:ui/src/engine/browser_detection.dart'; import 'package:ui/src/engine/embedder.dart'; -import 'package:ui/src/engine/keyboard.dart'; import 'package:ui/src/engine/mouse_cursor.dart'; import 'package:ui/src/engine/navigation.dart'; import 'package:ui/src/engine/platform_dispatcher.dart'; import 'package:ui/src/engine/platform_views/content_manager.dart'; import 'package:ui/src/engine/profiler.dart'; +import 'package:ui/src/engine/raw_keyboard.dart'; import 'package:ui/src/engine/renderer.dart'; import 'package:ui/src/engine/safe_browser_api.dart'; import 'package:ui/src/engine/window.dart'; @@ -234,7 +234,7 @@ Future initializeEngineUi() async { } _initializationState = DebugEngineInitializationState.initializingUi; - Keyboard.initialize(onMacOs: operatingSystem == OperatingSystem.macOs); + RawKeyboard.initialize(onMacOs: operatingSystem == OperatingSystem.macOs); MouseCursor.initialize(); ensureFlutterViewEmbedderInitialized(); _initializationState = DebugEngineInitializationState.initialized; diff --git a/lib/web_ui/lib/src/engine/keyboard_binding.dart b/lib/web_ui/lib/src/engine/keyboard_binding.dart index 9a500efea9311..74e0fa5f7d050 100644 --- a/lib/web_ui/lib/src/engine/keyboard_binding.dart +++ b/lib/web_ui/lib/src/engine/keyboard_binding.dart @@ -88,7 +88,7 @@ Duration _eventTimeStampToDuration(num milliseconds) { } class KeyboardBinding { - KeyboardBinding._(this.glassPaneElement) { + KeyboardBinding._() { _setup(); } @@ -96,9 +96,9 @@ class KeyboardBinding { static KeyboardBinding? get instance => _instance; static KeyboardBinding? _instance; - static void initInstance(DomElement glassPaneElement) { + static void initInstance() { if (_instance == null) { - _instance = KeyboardBinding._(glassPaneElement); + _instance = KeyboardBinding._(); assert(() { registerHotRestartListener(_instance!._reset); return true; @@ -106,8 +106,7 @@ class KeyboardBinding { } } - final DomElement glassPaneElement; - late KeyboardConverter _converter; + late final KeyboardConverter _converter; final Map _listeners = {}; void _addEventListener(String eventName, DomEventListener handler) { @@ -179,6 +178,7 @@ class FlutterHtmlKeyboardEvent { String get type => _event.type; String? get code => _event.code; String? get key => _event.key; + int get keyCode => _event.keyCode; bool? get repeat => _event.repeat; int? get location => _event.location; num? get timeStamp => _event.timeStamp; @@ -189,6 +189,7 @@ class FlutterHtmlKeyboardEvent { bool getModifierState(String key) => _event.getModifierState(key); void preventDefault() => _event.preventDefault(); + bool get defaultPrevented => _event.defaultPrevented; } // Reads [DomKeyboardEvent], then [dispatches ui.KeyData] accordingly. diff --git a/lib/web_ui/lib/src/engine/keyboard.dart b/lib/web_ui/lib/src/engine/raw_keyboard.dart similarity index 88% rename from lib/web_ui/lib/src/engine/keyboard.dart rename to lib/web_ui/lib/src/engine/raw_keyboard.dart index 440f249850e83..57d16116e7c2d 100644 --- a/lib/web_ui/lib/src/engine/keyboard.dart +++ b/lib/web_ui/lib/src/engine/raw_keyboard.dart @@ -7,13 +7,14 @@ import 'dart:typed_data'; import '../engine.dart' show registerHotRestartListener; import 'dom.dart'; +import 'keyboard_binding.dart'; import 'platform_dispatcher.dart'; import 'safe_browser_api.dart'; import 'services.dart'; /// Provides keyboard bindings, such as the `flutter/keyevent` channel. -class Keyboard { - Keyboard._(this._onMacOs) { +class RawKeyboard { + RawKeyboard._(this._onMacOs) { _keydownListener = allowInterop((DomEvent event) { _handleHtmlEvent(event); }); @@ -28,16 +29,16 @@ class Keyboard { }); } - /// Initializes the [Keyboard] singleton. + /// Initializes the [RawKeyboard] singleton. /// /// Use the [instance] getter to get the singleton after calling this method. static void initialize({bool onMacOs = false}) { - _instance ??= Keyboard._(onMacOs); + _instance ??= RawKeyboard._(onMacOs); } - /// The [Keyboard] singleton. - static Keyboard? get instance => _instance; - static Keyboard? _instance; + /// The [RawKeyboard] singleton. + static RawKeyboard? get instance => _instance; + static RawKeyboard? _instance; /// A mapping of [KeyboardEvent.code] to [Timer]. /// @@ -48,7 +49,7 @@ class Keyboard { DomEventListener? _keydownListener; DomEventListener? _keyupListener; - /// Uninitializes the [Keyboard] singleton. + /// Uninitializes the [RawKeyboard] singleton. /// /// After calling this method this object becomes unusable and [instance] /// becomes `null`. Call [initialize] again to initialize a new singleton. @@ -87,13 +88,13 @@ class Keyboard { return _onMacOs; } - void _handleHtmlEvent(DomEvent event) { - if (!domInstanceOfString(event, 'KeyboardEvent')) { + void _handleHtmlEvent(DomEvent domEvent) { + if (!domInstanceOfString(domEvent, 'KeyboardEvent')) { return; } - final DomKeyboardEvent keyboardEvent = event as DomKeyboardEvent; - final String timerKey = keyboardEvent.code!; + final FlutterHtmlKeyboardEvent event = FlutterHtmlKeyboardEvent(domEvent as DomKeyboardEvent); + final String timerKey = event.code!; // Don't handle synthesizing a keyup event for modifier keys if (!_isModifierKey(event) && _shouldDoKeyGuard()) { @@ -126,11 +127,11 @@ class Keyboard { final Map eventData = { 'type': event.type, 'keymap': 'web', - 'code': keyboardEvent.code, - 'key': keyboardEvent.key, - 'location': keyboardEvent.location, + 'code': event.code, + 'key': event.key, + 'location': event.location, 'metaState': _lastMetaState, - 'keyCode': keyboardEvent.keyCode, + 'keyCode': event.keyCode, }; EnginePlatformDispatcher.instance.invokeOnPlatformMessage('flutter/keyevent', @@ -147,7 +148,7 @@ class Keyboard { ); } - void _synthesizeKeyup(DomKeyboardEvent event) { + void _synthesizeKeyup(FlutterHtmlKeyboardEvent event) { final Map eventData = { 'type': 'keyup', 'keymap': 'web', @@ -180,7 +181,7 @@ const int modifierCapsLock = 0x20; const int modifierScrollLock = 0x40; /// Creates a bitmask representing the meta state of the [event]. -int _getMetaState(DomKeyboardEvent event) { +int _getMetaState(FlutterHtmlKeyboardEvent event) { int metaState = _modifierNone; if (event.getModifierState('Shift')) { metaState |= _modifierShift; @@ -212,7 +213,7 @@ int _getMetaState(DomKeyboardEvent event) { /// /// Modifier keys are shift, alt, ctrl and meta/cmd/win. These are the keys used /// to perform keyboard shortcuts (e.g. `cmd+c`, `cmd+l`). -bool _isModifierKey(DomKeyboardEvent event) { +bool _isModifierKey(FlutterHtmlKeyboardEvent event) { final String key = event.key!; return key == 'Meta' || key == 'Shift' || key == 'Alt' || key == 'Control'; } @@ -220,7 +221,7 @@ bool _isModifierKey(DomKeyboardEvent event) { /// Returns true if the [event] is been affects by any of the modifiers key /// /// This is a strong indication that this key is been used for a shortcut -bool _isAffectedByModifiers(DomKeyboardEvent event) { +bool _isAffectedByModifiers(FlutterHtmlKeyboardEvent event) { return event.ctrlKey || event.shiftKey || event.altKey || event.metaKey; } diff --git a/lib/web_ui/test/canvaskit/initialization_services_vs_ui_test.dart b/lib/web_ui/test/canvaskit/initialization_services_vs_ui_test.dart index 31820129fb49b..8f6d74cc09469 100644 --- a/lib/web_ui/test/canvaskit/initialization_services_vs_ui_test.dart +++ b/lib/web_ui/test/canvaskit/initialization_services_vs_ui_test.dart @@ -16,7 +16,7 @@ void testMain() { expect(windowFlutterCanvasKit, isNull); expect(findGlassPane(), isNull); - expect(Keyboard.instance, isNull); + expect(RawKeyboard.instance, isNull); expect(MouseCursor.instance, isNull); expect(KeyboardBinding.instance, isNull); expect(PointerBinding.instance, isNull); @@ -27,7 +27,7 @@ void testMain() { expect(windowFlutterCanvasKit, isNotNull); expect(findGlassPane(), isNull); - expect(Keyboard.instance, isNull); + expect(RawKeyboard.instance, isNull); expect(MouseCursor.instance, isNull); expect(KeyboardBinding.instance, isNull); expect(PointerBinding.instance, isNull); @@ -35,7 +35,7 @@ void testMain() { // Now UI should be taken over by Flutter. await initializeEngineUi(); expect(findGlassPane(), isNotNull); - expect(Keyboard.instance, isNotNull); + expect(RawKeyboard.instance, isNotNull); expect(MouseCursor.instance, isNotNull); expect(KeyboardBinding.instance, isNotNull); expect(PointerBinding.instance, isNotNull); diff --git a/lib/web_ui/test/keyboard_converter_test.dart b/lib/web_ui/test/keyboard_converter_test.dart index 0af85815dcf37..53dba7f2e8d7a 100644 --- a/lib/web_ui/test/keyboard_converter_test.dart +++ b/lib/web_ui/test/keyboard_converter_test.dart @@ -9,6 +9,8 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; +import 'keyboard_test_common.dart'; + const int kLocationStandard = 0; const int kLocationLeft = 1; const int kLocationRight = 2; @@ -84,13 +86,8 @@ void testMain() { // Only handle down events return key.type == ui.KeyEventType.down; }); - bool preventedDefault = false; - void onPreventDefault() { preventedDefault = true; } - converter.handleEvent(keyDownEvent('KeyA', 'a') - ..timeStamp = 1 - ..onPreventDefault = onPreventDefault - ); + converter.handleEvent(keyDownEvent('KeyA', 'a')..timeStamp = 1); expectKeyData(keyDataList.last, timeStamp: const Duration(milliseconds: 1), type: ui.KeyEventType.down, @@ -98,13 +95,9 @@ void testMain() { logical: kLogicalKeyA, character: 'a', ); - expect(preventedDefault, isTrue); - preventedDefault = false; + expect(MockKeyboardEvent.lastDefaultPrevented, isTrue); - converter.handleEvent(keyRepeatedDownEvent('KeyA', 'a') - ..timeStamp = 1.5 - ..onPreventDefault = onPreventDefault - ); + converter.handleEvent(keyRepeatedDownEvent('KeyA', 'a')..timeStamp = 1.5); expectKeyData(keyDataList.last, timeStamp: const Duration(milliseconds: 1, microseconds: 500), type: ui.KeyEventType.repeat, @@ -112,12 +105,9 @@ void testMain() { logical: kLogicalKeyA, character: 'a', ); - expect(preventedDefault, isFalse); + expect(MockKeyboardEvent.lastDefaultPrevented, isFalse); - converter.handleEvent(keyRepeatedDownEvent('KeyA', 'a') - ..timeStamp = 1500 - ..onPreventDefault = onPreventDefault - ); + converter.handleEvent(keyRepeatedDownEvent('KeyA', 'a')..timeStamp = 1500); expectKeyData(keyDataList.last, timeStamp: const Duration(seconds: 1, milliseconds: 500), type: ui.KeyEventType.repeat, @@ -125,12 +115,9 @@ void testMain() { logical: kLogicalKeyA, character: 'a', ); - expect(preventedDefault, isFalse); + expect(MockKeyboardEvent.lastDefaultPrevented, isFalse); - converter.handleEvent(keyUpEvent('KeyA', 'a') - ..timeStamp = 2000.5 - ..onPreventDefault = onPreventDefault - ); + converter.handleEvent(keyUpEvent('KeyA', 'a')..timeStamp = 2000.5); expectKeyData(keyDataList.last, timeStamp: const Duration(seconds: 2, microseconds: 500), type: ui.KeyEventType.up, @@ -138,7 +125,7 @@ void testMain() { logical: kLogicalKeyA, character: null, ); - expect(preventedDefault, isFalse); + expect(MockKeyboardEvent.lastDefaultPrevented, isFalse); }); test('Release modifier during a repeated sequence', () { @@ -148,76 +135,60 @@ void testMain() { // Only handle down events return key.type == ui.KeyEventType.down; }); - bool preventedDefault = false; - void onPreventDefault() { preventedDefault = true; } - converter.handleEvent(keyDownEvent('ShiftLeft', 'Shift', kShift, kLocationLeft) - ..onPreventDefault = onPreventDefault - ); + converter.handleEvent(keyDownEvent('ShiftLeft', 'Shift', kShift, kLocationLeft)); expectKeyData(keyDataList.last, type: ui.KeyEventType.down, physical: kPhysicalShiftLeft, logical: kLogicalShiftLeft, character: null, ); - expect(preventedDefault, isTrue); - preventedDefault = false; + expect(MockKeyboardEvent.lastDefaultPrevented, isTrue); - converter.handleEvent(keyDownEvent('KeyA', 'A', kShift) - ..onPreventDefault = onPreventDefault - ); + converter.handleEvent(keyDownEvent('KeyA', 'A', kShift)); expectKeyData(keyDataList.last, type: ui.KeyEventType.down, physical: kPhysicalKeyA, logical: kLogicalKeyA, character: 'A', ); - expect(preventedDefault, isTrue); - preventedDefault = false; + expect(MockKeyboardEvent.lastDefaultPrevented, isTrue); - converter.handleEvent(keyRepeatedDownEvent('KeyA', 'A', kShift) - ..onPreventDefault = onPreventDefault - ); + converter.handleEvent(keyRepeatedDownEvent('KeyA', 'A', kShift)); expectKeyData(keyDataList.last, type: ui.KeyEventType.repeat, physical: kPhysicalKeyA, logical: kLogicalKeyA, character: 'A', ); - expect(preventedDefault, isFalse); + expect(MockKeyboardEvent.lastDefaultPrevented, isFalse); - converter.handleEvent(keyUpEvent('ShiftLeft', 'Shift', 0, kLocationLeft) - ..onPreventDefault = onPreventDefault - ); + converter.handleEvent(keyUpEvent('ShiftLeft', 'Shift', 0, kLocationLeft)); expectKeyData(keyDataList.last, type: ui.KeyEventType.up, physical: kPhysicalShiftLeft, logical: kLogicalShiftLeft, character: null, ); - expect(preventedDefault, isFalse); + expect(MockKeyboardEvent.lastDefaultPrevented, isFalse); - converter.handleEvent(keyRepeatedDownEvent('KeyA', 'a') - ..onPreventDefault = onPreventDefault - ); + converter.handleEvent(keyRepeatedDownEvent('KeyA', 'a')); expectKeyData(keyDataList.last, type: ui.KeyEventType.repeat, physical: kPhysicalKeyA, logical: kLogicalKeyA, character: 'a', ); - expect(preventedDefault, isFalse); + expect(MockKeyboardEvent.lastDefaultPrevented, isFalse); - converter.handleEvent(keyRepeatedDownEvent('KeyA', 'a') - ..onPreventDefault = onPreventDefault - ); + converter.handleEvent(keyRepeatedDownEvent('KeyA', 'a')); expectKeyData(keyDataList.last, type: ui.KeyEventType.repeat, physical: kPhysicalKeyA, logical: kLogicalKeyA, character: 'a', ); - expect(preventedDefault, isFalse); + expect(MockKeyboardEvent.lastDefaultPrevented, isFalse); converter.handleEvent(keyUpEvent('KeyA', 'a')); expectKeyData(keyDataList.last, @@ -226,7 +197,7 @@ void testMain() { logical: kLogicalKeyA, character: null, ); - expect(preventedDefault, isFalse); + expect(MockKeyboardEvent.lastDefaultPrevented, isFalse); }); test('Distinguish between left and right modifiers', () { @@ -461,20 +432,13 @@ void testMain() { keyDataList.add(key); return true; }); - bool preventedDefault = false; - void onPreventDefault() { preventedDefault = true; } - converter.handleEvent(keyDownEvent('ShiftLeft', 'Shift', kShift, kLocationLeft) - ..onPreventDefault = onPreventDefault - ); - expect(preventedDefault, isTrue); - preventedDefault = false; + converter.handleEvent(keyDownEvent('ShiftLeft', 'Shift', kShift, kLocationLeft)); + expect(MockKeyboardEvent.lastDefaultPrevented, isTrue); // A KeyUp of ShiftLeft is missed. keyDataList.clear(); - converter.handleEvent(keyDownEvent('ShiftLeft', 'Shift', kShift, kLocationLeft) - ..onPreventDefault = onPreventDefault - ); + converter.handleEvent(keyDownEvent('ShiftLeft', 'Shift', kShift, kLocationLeft)); expect(keyDataList, hasLength(2)); expectKeyData(keyDataList.first, type: ui.KeyEventType.up, @@ -489,12 +453,10 @@ void testMain() { logical: kLogicalShiftLeft, character: null, ); - expect(preventedDefault, isTrue); + expect(MockKeyboardEvent.lastDefaultPrevented, isTrue); keyDataList.clear(); - converter.handleEvent(keyUpEvent('ShiftLeft', 'Shift', 0, kLocationLeft) - ..onPreventDefault = onPreventDefault - ); + converter.handleEvent(keyUpEvent('ShiftLeft', 'Shift', 0, kLocationLeft)); expect(keyDataList, hasLength(1)); expectKeyData(keyDataList.last, type: ui.KeyEventType.up, @@ -502,7 +464,7 @@ void testMain() { logical: kLogicalShiftLeft, character: null, ); - expect(preventedDefault, isTrue); + expect(MockKeyboardEvent.lastDefaultPrevented, isTrue); }); test('Duplicate ups are skipped', () { @@ -511,17 +473,13 @@ void testMain() { keyDataList.add(key); return true; }); - bool preventedDefault = false; - void onPreventDefault() { preventedDefault = true; } // A KeyDown of ShiftRight is missed due to loss of focus. - converter.handleEvent(keyUpEvent('ShiftRight', 'Shift', 0, kLocationRight) - ..onPreventDefault = onPreventDefault - ); + converter.handleEvent(keyUpEvent('ShiftRight', 'Shift', 0, kLocationRight)); expect(keyDataList, hasLength(1)); expect(keyDataList[0].physical, 0); expect(keyDataList[0].logical, 0); - expect(preventedDefault, isTrue); + expect(MockKeyboardEvent.lastDefaultPrevented, isTrue); }); test('Conflict from multiple keyboards do not crash', () { @@ -568,13 +526,9 @@ void testMain() { keyDataList.add(key); return true; }, onMacOs: true); - bool preventedDefault = false; - void onPreventDefault() { preventedDefault = true; } // A KeyDown of ShiftRight is missed due to loss of focus. - converter.handleEvent(keyDownEvent('CapsLock', 'CapsLock') - ..onPreventDefault = onPreventDefault - ); + converter.handleEvent(keyDownEvent('CapsLock', 'CapsLock')); expect(keyDataList, hasLength(1)); expectKeyData(keyDataList.last, type: ui.KeyEventType.down, @@ -582,9 +536,8 @@ void testMain() { logical: kLogicalCapsLock, character: null, ); - expect(preventedDefault, isTrue); + expect(MockKeyboardEvent.lastDefaultPrevented, isTrue); keyDataList.clear(); - preventedDefault = false; async.elapse(const Duration(microseconds: 1)); expect(keyDataList, hasLength(1)); @@ -595,12 +548,10 @@ void testMain() { character: null, synthesized: true, ); - expect(preventedDefault, isFalse); + expect(MockKeyboardEvent.lastDefaultPrevented, isTrue); keyDataList.clear(); - converter.handleEvent(keyUpEvent('CapsLock', 'CapsLock') - ..onPreventDefault = onPreventDefault - ); + converter.handleEvent(keyUpEvent('CapsLock', 'CapsLock')); expect(keyDataList, hasLength(1)); expectKeyData(keyDataList.last, type: ui.KeyEventType.down, @@ -608,9 +559,8 @@ void testMain() { logical: kLogicalCapsLock, character: null, ); - expect(preventedDefault, isTrue); + expect(MockKeyboardEvent.lastDefaultPrevented, isTrue); keyDataList.clear(); - preventedDefault = false; async.elapse(const Duration(microseconds: 1)); expect(keyDataList, hasLength(1)); @@ -621,7 +571,7 @@ void testMain() { character: null, synthesized: true, ); - expect(preventedDefault, isFalse); + expect(MockKeyboardEvent.lastDefaultPrevented, isTrue); keyDataList.clear(); // Another key down works @@ -647,7 +597,7 @@ void testMain() { final KeyboardConverter converter = KeyboardConverter((ui.KeyData key) { keyDataList.add(key); return true; - }); + }); // onMacOs: false converter.handleEvent(keyDownEvent('CapsLock', 'CapsLock')); expect(keyDataList, hasLength(1)); @@ -881,7 +831,7 @@ void testMain() { final KeyboardConverter converter = KeyboardConverter((ui.KeyData key) { keyDataList.add(key); return true; - }); + }); // onMacOs: false converter.handleEvent(keyDownEvent('MetaLeft', 'Meta', kMeta, kLocationLeft)..timeStamp = 100); async.elapse(const Duration(milliseconds: 100)); @@ -905,7 +855,7 @@ void testMain() { final KeyboardConverter converter = KeyboardConverter((ui.KeyData key) { keyDataList.add(key); return true; - }); + }); // onMacOs: false converter.handleEvent(keyDownEvent('ScrollLock', 'ScrollLock')); expect(keyDataList, hasLength(1)); @@ -952,7 +902,7 @@ void testMain() { final KeyboardConverter converter = KeyboardConverter((ui.KeyData key) { keyDataList.add(key); return true; - }); + }); // onMacOs: false converter.handleEvent(keyDownEvent('ShiftRight', 'Shift', kShift, kLocationRight)); expectKeyData(keyDataList.last, @@ -1008,7 +958,7 @@ void testMain() { final KeyboardConverter converter = KeyboardConverter((ui.KeyData key) { keyDataList.add(key); return true; - }); + }); // onMacOs: false converter.handleEvent(keyDownEvent('ShiftLeft', 'Shift', kShift, kLocationLeft)); expectKeyData(keyDataList.last, @@ -1052,60 +1002,6 @@ void testMain() { }); } -class MockKeyboardEvent implements FlutterHtmlKeyboardEvent { - MockKeyboardEvent({ - required this.type, - required this.code, - required this.key, - this.timeStamp = 0, - this.repeat = false, - this.altKey = false, - this.ctrlKey = false, - this.shiftKey = false, - this.metaKey = false, - this.location = 0, - this.onPreventDefault, - }); - - @override - String type; - - @override - String? code; - - @override - String? key; - - @override - bool? repeat; - - @override - num? timeStamp; - - @override - bool altKey; - - @override - bool ctrlKey; - - @override - bool shiftKey; - - @override - bool metaKey; - - @override - int? location; - - @override - bool getModifierState(String key) => modifierState.contains(key); - final Set modifierState = {}; - - @override - void preventDefault() { onPreventDefault?.call(); } - VoidCallback? onPreventDefault; -} - // Flags used for the `modifiers` argument of `key***Event` functions. const int kAlt = 0x1; const int kCtrl = 0x2; @@ -1114,7 +1010,7 @@ const int kMeta = 0x8; // Utility functions to make code more concise. // -// To add timeStamp or onPreventDefault, use syntax like `..timeStamp = `. +// To add timeStamp , use syntax `..timeStamp = `. MockKeyboardEvent keyDownEvent(String code, String key, [int modifiers = 0, int location = 0]) { return MockKeyboardEvent( type: 'keydown', diff --git a/lib/web_ui/test/keyboard_test_common.dart b/lib/web_ui/test/keyboard_test_common.dart new file mode 100644 index 0000000000000..b4b2113731ea8 --- /dev/null +++ b/lib/web_ui/test/keyboard_test_common.dart @@ -0,0 +1,85 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:ui/src/engine.dart'; + +typedef VoidCallback = void Function(); + +class MockKeyboardEvent implements FlutterHtmlKeyboardEvent { + MockKeyboardEvent({ + required this.type, + required this.code, + required this.key, + this.timeStamp = 0, + this.repeat = false, + this.keyCode = 0, + bool altKey = false, + bool ctrlKey = false, + bool shiftKey = false, + bool metaKey = false, + bool altGrKey = false, + this.location = 0, + this.onPreventDefault, + }) : modifierState = + { + if (altKey) 'Alt', + if (ctrlKey) 'Control', + if (shiftKey) 'Shift', + if (metaKey) 'Meta', + if (altGrKey) 'AltGraph', + } { + _lastEvent = this; + } + + @override + String type; + + @override + String? code; + + @override + String? key; + + @override + bool? repeat; + + @override + int keyCode; + + @override + num? timeStamp; + + @override + bool get altKey => modifierState.contains('Alt'); + + @override + bool get ctrlKey => modifierState.contains('Control'); + + @override + bool get shiftKey => modifierState.contains('Shift'); + + @override + bool get metaKey => modifierState.contains('Meta'); + + @override + int? location; + + @override + bool getModifierState(String key) => modifierState.contains(key); + final Set modifierState; + + @override + void preventDefault() { + onPreventDefault?.call(); + _defaultPrevented = true; + } + VoidCallback? onPreventDefault; + + @override + bool get defaultPrevented => _defaultPrevented; + bool _defaultPrevented = false; + + static bool get lastDefaultPrevented => _lastEvent?.defaultPrevented ?? false; + static MockKeyboardEvent? _lastEvent; +} diff --git a/lib/web_ui/test/keyboard_test.dart b/lib/web_ui/test/raw_keyboard_test.dart similarity index 93% rename from lib/web_ui/test/keyboard_test.dart rename to lib/web_ui/test/raw_keyboard_test.dart index a560281824099..bb490b60fb8f7 100644 --- a/lib/web_ui/test/keyboard_test.dart +++ b/lib/web_ui/test/raw_keyboard_test.dart @@ -9,7 +9,7 @@ import 'package:quiver/testing/async.dart'; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine/dom.dart'; -import 'package:ui/src/engine/keyboard.dart'; +import 'package:ui/src/engine/raw_keyboard.dart'; import 'package:ui/src/engine/services.dart'; import 'package:ui/src/engine/text_editing/text_editing.dart'; import 'package:ui/ui.dart' as ui; @@ -19,7 +19,7 @@ void main() { } void testMain() { - group('Keyboard', () { + group('RawKeyboard', () { /// Used to save and restore [ui.window.onPlatformMessage] after each test. ui.PlatformMessageCallback? savedCallback; @@ -32,15 +32,15 @@ void testMain() { }); test('initializes and disposes', () { - expect(Keyboard.instance, isNull); - Keyboard.initialize(); - expect(Keyboard.instance, isA()); - Keyboard.instance!.dispose(); - expect(Keyboard.instance, isNull); + expect(RawKeyboard.instance, isNull); + RawKeyboard.initialize(); + expect(RawKeyboard.instance, isA()); + RawKeyboard.instance!.dispose(); + expect(RawKeyboard.instance, isNull); }); test('dispatches keyup to flutter/keyevent channel', () { - Keyboard.initialize(); + RawKeyboard.initialize(); String? channelReceived; Map? dataReceived; @@ -66,11 +66,11 @@ void testMain() { 'keyCode': 1, }); - Keyboard.instance!.dispose(); + RawKeyboard.instance!.dispose(); }); test('dispatches keydown to flutter/keyevent channel', () { - Keyboard.initialize(); + RawKeyboard.initialize(); String? channelReceived; Map? dataReceived; @@ -97,11 +97,11 @@ void testMain() { }); expect(event.defaultPrevented, isFalse); - Keyboard.instance!.dispose(); + RawKeyboard.instance!.dispose(); }); test('dispatches correct meta state', () { - Keyboard.initialize(); + RawKeyboard.initialize(); Map? dataReceived; ui.window.onPlatformMessage = (String channel, ByteData? data, @@ -149,11 +149,11 @@ void testMain() { 'keyCode': 0, }); - Keyboard.instance!.dispose(); + RawKeyboard.instance!.dispose(); }); test('dispatches repeat events', () { - Keyboard.initialize(); + RawKeyboard.initialize(); final List> messages = >[]; ui.window.onPlatformMessage = (String channel, ByteData? data, @@ -202,11 +202,11 @@ void testMain() { expectedMessage, ]); - Keyboard.instance!.dispose(); + RawKeyboard.instance!.dispose(); }); test('stops dispatching events after dispose', () { - Keyboard.initialize(); + RawKeyboard.initialize(); int count = 0; ui.window.onPlatformMessage = (String channel, ByteData? data, @@ -219,8 +219,8 @@ void testMain() { dispatchKeyboardEvent('keyup'); expect(count, 2); - Keyboard.instance!.dispose(); - expect(Keyboard.instance, isNull); + RawKeyboard.instance!.dispose(); + expect(RawKeyboard.instance, isNull); // No more event dispatching. dispatchKeyboardEvent('keydown'); @@ -230,7 +230,7 @@ void testMain() { }); test('prevents default when key is handled by the framework', () { - Keyboard.initialize(); + RawKeyboard.initialize(); int count = 0; ui.window.onPlatformMessage = (String channel, ByteData? data, @@ -249,11 +249,11 @@ void testMain() { expect(event.defaultPrevented, isTrue); expect(count, 1); - Keyboard.instance!.dispose(); + RawKeyboard.instance!.dispose(); }); test("Doesn't prevent default when key is not handled by the framework", () { - Keyboard.initialize(); + RawKeyboard.initialize(); int count = 0; ui.window.onPlatformMessage = (String channel, ByteData? data, @@ -272,11 +272,11 @@ void testMain() { expect(event.defaultPrevented, isFalse); expect(count, 1); - Keyboard.instance!.dispose(); + RawKeyboard.instance!.dispose(); }); test('keyboard events should be triggered on text fields', () { - Keyboard.initialize(); + RawKeyboard.initialize(); int count = 0; ui.window.onPlatformMessage = (String channel, ByteData? data, @@ -296,11 +296,11 @@ void testMain() { expect(count, 1); }); - Keyboard.instance!.dispose(); + RawKeyboard.instance!.dispose(); }); test('the "Tab" key should never be ignored', () { - Keyboard.initialize(); + RawKeyboard.initialize(); int count = 0; ui.window.onPlatformMessage = (String channel, ByteData? data, @@ -322,7 +322,7 @@ void testMain() { expect(count, 1); }); - Keyboard.instance!.dispose(); + RawKeyboard.instance!.dispose(); }); testFakeAsync( @@ -335,7 +335,7 @@ void testMain() { // // There's no `keyup(i)`. The web engine is expected to synthesize a // `keyup(i)` event. - Keyboard.initialize(onMacOs: true); + RawKeyboard.initialize(onMacOs: true); final List> messages = >[]; ui.window.onPlatformMessage = (String channel, ByteData? data, @@ -451,14 +451,14 @@ void testMain() { } ]); - Keyboard.instance!.dispose(); + RawKeyboard.instance!.dispose(); }, ); testFakeAsync( 'On macOS, do not synthesize keyup when we receive repeat events', (FakeAsync async) { - Keyboard.initialize(onMacOs: true); + RawKeyboard.initialize(onMacOs: true); final List> messages = >[]; ui.window.onPlatformMessage = (String channel, ByteData? data, @@ -533,14 +533,14 @@ void testMain() { } messages.clear(); - Keyboard.instance!.dispose(); + RawKeyboard.instance!.dispose(); }, ); testFakeAsync( 'On macOS, do not synthesize keyup when keys are not affected by meta modifiers', (FakeAsync async) { - Keyboard.initialize(); + RawKeyboard.initialize(); final List> messages = >[]; ui.window.onPlatformMessage = (String channel, ByteData? data, @@ -565,12 +565,12 @@ void testMain() { async.elapse(const Duration(seconds: 3)); expect(messages, hasLength(0)); - Keyboard.instance!.dispose(); + RawKeyboard.instance!.dispose(); }, ); testFakeAsync('On macOS, do not synthesize keyup for meta keys', (FakeAsync async) { - Keyboard.initialize(onMacOs: true); + RawKeyboard.initialize(onMacOs: true); final List> messages = >[]; ui.window.onPlatformMessage = (String channel, ByteData? data, @@ -628,13 +628,13 @@ void testMain() { } ]); - Keyboard.instance!.dispose(); + RawKeyboard.instance!.dispose(); }); testFakeAsync( 'On non-macOS, do not synthesize keyup for shortcuts', (FakeAsync async) { - Keyboard.initialize(); + RawKeyboard.initialize(); // onMacOs: false final List> messages = >[]; ui.window.onPlatformMessage = (String channel, ByteData? data, @@ -687,7 +687,7 @@ void testMain() { async.elapse(const Duration(seconds: 3)); expect(messages, isEmpty); - Keyboard.instance!.dispose(); + RawKeyboard.instance!.dispose(); }, );