mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

* Fix typos * lowercase animated & opacity * Undo typo fix --------- Co-authored-by: Michael Goderbauer <goderbauer@google.com>
351 lines
16 KiB
Dart
351 lines
16 KiB
Dart
// Copyright 2014 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:flutter/foundation.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
const List<String> platforms = <String>['linux', 'macos', 'android', 'fuchsia'];
|
|
|
|
void _verifyKeyEvent<T extends KeyEvent>(KeyEvent event, PhysicalKeyboardKey physical, LogicalKeyboardKey logical, String? character) {
|
|
expect(event, isA<T>());
|
|
expect(event.physicalKey, physical);
|
|
expect(event.logicalKey, logical);
|
|
expect(event.character, character);
|
|
expect(event.synthesized, false);
|
|
}
|
|
|
|
void _verifyRawKeyEvent<T extends RawKeyEvent>(RawKeyEvent event, PhysicalKeyboardKey physical, LogicalKeyboardKey logical, String? character) {
|
|
expect(event, isA<T>());
|
|
expect(event.physicalKey, physical);
|
|
expect(event.logicalKey, logical);
|
|
expect(event.character, character);
|
|
}
|
|
|
|
Future<void> _shouldThrow<T extends Error>(AsyncValueGetter<void> func) async {
|
|
bool hasError = false;
|
|
try {
|
|
await func();
|
|
} catch (e) {
|
|
expect(e, isA<T>());
|
|
hasError = true;
|
|
} finally {
|
|
expect(hasError, true);
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
testWidgets('simulates keyboard events (RawEvent)', (WidgetTester tester) async {
|
|
debugKeyEventSimulatorTransitModeOverride = KeyDataTransitMode.rawKeyData;
|
|
|
|
final List<RawKeyEvent> events = <RawKeyEvent>[];
|
|
|
|
final FocusNode focusNode = FocusNode();
|
|
|
|
await tester.pumpWidget(
|
|
RawKeyboardListener(
|
|
focusNode: focusNode,
|
|
onKey: events.add,
|
|
child: Container(),
|
|
),
|
|
);
|
|
|
|
focusNode.requestFocus();
|
|
await tester.idle();
|
|
|
|
for (final String platform in platforms) {
|
|
await tester.sendKeyEvent(LogicalKeyboardKey.shiftLeft, platform: platform);
|
|
await tester.sendKeyEvent(LogicalKeyboardKey.shift, platform: platform);
|
|
await tester.sendKeyDownEvent(LogicalKeyboardKey.keyA, platform: platform);
|
|
await tester.sendKeyUpEvent(LogicalKeyboardKey.keyA, platform: platform);
|
|
await tester.sendKeyDownEvent(LogicalKeyboardKey.numpad1, platform: platform);
|
|
await tester.sendKeyUpEvent(LogicalKeyboardKey.numpad1, platform: platform);
|
|
await tester.idle();
|
|
|
|
expect(events.length, 8);
|
|
for (int i = 0; i < events.length; ++i) {
|
|
final bool isEven = i.isEven;
|
|
if (isEven) {
|
|
expect(events[i].runtimeType, equals(RawKeyDownEvent));
|
|
} else {
|
|
expect(events[i].runtimeType, equals(RawKeyUpEvent));
|
|
}
|
|
if (i < 4) {
|
|
expect(events[i].data.isModifierPressed(ModifierKey.shiftModifier, side: KeyboardSide.left), equals(isEven));
|
|
}
|
|
}
|
|
events.clear();
|
|
}
|
|
|
|
await tester.pumpWidget(Container());
|
|
focusNode.dispose();
|
|
|
|
debugKeyEventSimulatorTransitModeOverride = null;
|
|
});
|
|
|
|
testWidgets('simulates keyboard events (KeyData then RawKeyEvent)', (WidgetTester tester) async {
|
|
debugKeyEventSimulatorTransitModeOverride = KeyDataTransitMode.keyDataThenRawKeyData;
|
|
|
|
final List<KeyEvent> events = <KeyEvent>[];
|
|
|
|
final FocusNode focusNode = FocusNode();
|
|
|
|
await tester.pumpWidget(
|
|
KeyboardListener(
|
|
focusNode: focusNode,
|
|
onKeyEvent: events.add,
|
|
child: Container(),
|
|
),
|
|
);
|
|
|
|
focusNode.requestFocus();
|
|
await tester.idle();
|
|
|
|
// Key press shiftLeft
|
|
await tester.sendKeyDownEvent(LogicalKeyboardKey.shiftLeft);
|
|
expect(events.length, 1);
|
|
_verifyKeyEvent<KeyDownEvent>(events[0], PhysicalKeyboardKey.shiftLeft, LogicalKeyboardKey.shiftLeft, null);
|
|
expect(HardwareKeyboard.instance.physicalKeysPressed, equals(<PhysicalKeyboardKey>{PhysicalKeyboardKey.shiftLeft}));
|
|
expect(HardwareKeyboard.instance.logicalKeysPressed, equals(<LogicalKeyboardKey>{LogicalKeyboardKey.shiftLeft}));
|
|
expect(HardwareKeyboard.instance.lockModesEnabled, isEmpty);
|
|
events.clear();
|
|
|
|
await tester.sendKeyRepeatEvent(LogicalKeyboardKey.shiftLeft);
|
|
expect(events.length, 1);
|
|
_verifyKeyEvent<KeyRepeatEvent>(events[0], PhysicalKeyboardKey.shiftLeft, LogicalKeyboardKey.shiftLeft, null);
|
|
expect(HardwareKeyboard.instance.physicalKeysPressed, equals(<PhysicalKeyboardKey>{PhysicalKeyboardKey.shiftLeft}));
|
|
expect(HardwareKeyboard.instance.logicalKeysPressed, equals(<LogicalKeyboardKey>{LogicalKeyboardKey.shiftLeft}));
|
|
expect(HardwareKeyboard.instance.lockModesEnabled, isEmpty);
|
|
events.clear();
|
|
|
|
await tester.sendKeyUpEvent(LogicalKeyboardKey.shiftLeft);
|
|
expect(events.length, 1);
|
|
_verifyKeyEvent<KeyUpEvent>(events[0], PhysicalKeyboardKey.shiftLeft, LogicalKeyboardKey.shiftLeft, null);
|
|
expect(HardwareKeyboard.instance.physicalKeysPressed, isEmpty);
|
|
expect(HardwareKeyboard.instance.logicalKeysPressed, isEmpty);
|
|
expect(HardwareKeyboard.instance.lockModesEnabled, isEmpty);
|
|
events.clear();
|
|
|
|
// Key press keyA
|
|
await tester.sendKeyDownEvent(LogicalKeyboardKey.keyA);
|
|
expect(events.length, 1);
|
|
_verifyKeyEvent<KeyDownEvent>(events[0], PhysicalKeyboardKey.keyA, LogicalKeyboardKey.keyA, 'a');
|
|
expect(HardwareKeyboard.instance.physicalKeysPressed, equals(<PhysicalKeyboardKey>{PhysicalKeyboardKey.keyA}));
|
|
expect(HardwareKeyboard.instance.logicalKeysPressed, equals(<LogicalKeyboardKey>{LogicalKeyboardKey.keyA}));
|
|
expect(HardwareKeyboard.instance.lockModesEnabled, isEmpty);
|
|
events.clear();
|
|
|
|
await tester.sendKeyRepeatEvent(LogicalKeyboardKey.keyA);
|
|
_verifyKeyEvent<KeyRepeatEvent>(events[0], PhysicalKeyboardKey.keyA, LogicalKeyboardKey.keyA, 'a');
|
|
expect(HardwareKeyboard.instance.physicalKeysPressed, equals(<PhysicalKeyboardKey>{PhysicalKeyboardKey.keyA}));
|
|
expect(HardwareKeyboard.instance.logicalKeysPressed, equals(<LogicalKeyboardKey>{LogicalKeyboardKey.keyA}));
|
|
expect(HardwareKeyboard.instance.lockModesEnabled, isEmpty);
|
|
events.clear();
|
|
|
|
await tester.sendKeyUpEvent(LogicalKeyboardKey.keyA);
|
|
_verifyKeyEvent<KeyUpEvent>(events[0], PhysicalKeyboardKey.keyA, LogicalKeyboardKey.keyA, null);
|
|
expect(HardwareKeyboard.instance.physicalKeysPressed, isEmpty);
|
|
expect(HardwareKeyboard.instance.logicalKeysPressed, isEmpty);
|
|
expect(HardwareKeyboard.instance.lockModesEnabled, isEmpty);
|
|
events.clear();
|
|
|
|
// Key press keyA with physical keyQ
|
|
await tester.sendKeyDownEvent(LogicalKeyboardKey.keyA, physicalKey: PhysicalKeyboardKey.keyQ);
|
|
expect(events.length, 1);
|
|
_verifyKeyEvent<KeyDownEvent>(events[0], PhysicalKeyboardKey.keyQ, LogicalKeyboardKey.keyA, 'a');
|
|
expect(HardwareKeyboard.instance.physicalKeysPressed, equals(<PhysicalKeyboardKey>{PhysicalKeyboardKey.keyQ}));
|
|
expect(HardwareKeyboard.instance.logicalKeysPressed, equals(<LogicalKeyboardKey>{LogicalKeyboardKey.keyA}));
|
|
expect(HardwareKeyboard.instance.lockModesEnabled, isEmpty);
|
|
events.clear();
|
|
|
|
await tester.sendKeyRepeatEvent(LogicalKeyboardKey.keyA, physicalKey: PhysicalKeyboardKey.keyQ);
|
|
_verifyKeyEvent<KeyRepeatEvent>(events[0], PhysicalKeyboardKey.keyQ, LogicalKeyboardKey.keyA, 'a');
|
|
expect(HardwareKeyboard.instance.physicalKeysPressed, equals(<PhysicalKeyboardKey>{PhysicalKeyboardKey.keyQ}));
|
|
expect(HardwareKeyboard.instance.logicalKeysPressed, equals(<LogicalKeyboardKey>{LogicalKeyboardKey.keyA}));
|
|
expect(HardwareKeyboard.instance.lockModesEnabled, isEmpty);
|
|
events.clear();
|
|
|
|
await tester.sendKeyUpEvent(LogicalKeyboardKey.keyA, physicalKey: PhysicalKeyboardKey.keyQ);
|
|
_verifyKeyEvent<KeyUpEvent>(events[0], PhysicalKeyboardKey.keyQ, LogicalKeyboardKey.keyA, null);
|
|
expect(HardwareKeyboard.instance.physicalKeysPressed, isEmpty);
|
|
expect(HardwareKeyboard.instance.logicalKeysPressed, isEmpty);
|
|
expect(HardwareKeyboard.instance.lockModesEnabled, isEmpty);
|
|
events.clear();
|
|
|
|
// Key press numpad1
|
|
await tester.sendKeyDownEvent(LogicalKeyboardKey.numpad1);
|
|
_verifyKeyEvent<KeyDownEvent>(events[0], PhysicalKeyboardKey.numpad1, LogicalKeyboardKey.numpad1, null);
|
|
expect(HardwareKeyboard.instance.physicalKeysPressed, equals(<PhysicalKeyboardKey>{PhysicalKeyboardKey.numpad1}));
|
|
expect(HardwareKeyboard.instance.logicalKeysPressed, equals(<LogicalKeyboardKey>{LogicalKeyboardKey.numpad1}));
|
|
expect(HardwareKeyboard.instance.lockModesEnabled, isEmpty);
|
|
events.clear();
|
|
|
|
await tester.sendKeyRepeatEvent(LogicalKeyboardKey.numpad1);
|
|
_verifyKeyEvent<KeyRepeatEvent>(events[0], PhysicalKeyboardKey.numpad1, LogicalKeyboardKey.numpad1, null);
|
|
expect(HardwareKeyboard.instance.physicalKeysPressed, equals(<PhysicalKeyboardKey>{PhysicalKeyboardKey.numpad1}));
|
|
expect(HardwareKeyboard.instance.logicalKeysPressed, equals(<LogicalKeyboardKey>{LogicalKeyboardKey.numpad1}));
|
|
expect(HardwareKeyboard.instance.lockModesEnabled, isEmpty);
|
|
events.clear();
|
|
|
|
await tester.sendKeyUpEvent(LogicalKeyboardKey.numpad1);
|
|
_verifyKeyEvent<KeyUpEvent>(events[0], PhysicalKeyboardKey.numpad1, LogicalKeyboardKey.numpad1, null);
|
|
expect(HardwareKeyboard.instance.physicalKeysPressed, isEmpty);
|
|
expect(HardwareKeyboard.instance.logicalKeysPressed, isEmpty);
|
|
expect(HardwareKeyboard.instance.lockModesEnabled, isEmpty);
|
|
events.clear();
|
|
|
|
// Key press numLock (1st time)
|
|
await tester.sendKeyDownEvent(LogicalKeyboardKey.numLock);
|
|
_verifyKeyEvent<KeyDownEvent>(events[0], PhysicalKeyboardKey.numLock, LogicalKeyboardKey.numLock, null);
|
|
expect(HardwareKeyboard.instance.physicalKeysPressed, equals(<PhysicalKeyboardKey>{PhysicalKeyboardKey.numLock}));
|
|
expect(HardwareKeyboard.instance.logicalKeysPressed, equals(<LogicalKeyboardKey>{LogicalKeyboardKey.numLock}));
|
|
expect(HardwareKeyboard.instance.lockModesEnabled, equals(<KeyboardLockMode>{KeyboardLockMode.numLock}));
|
|
events.clear();
|
|
|
|
await tester.sendKeyRepeatEvent(LogicalKeyboardKey.numLock);
|
|
_verifyKeyEvent<KeyRepeatEvent>(events[0], PhysicalKeyboardKey.numLock, LogicalKeyboardKey.numLock, null);
|
|
expect(HardwareKeyboard.instance.physicalKeysPressed, equals(<PhysicalKeyboardKey>{PhysicalKeyboardKey.numLock}));
|
|
expect(HardwareKeyboard.instance.logicalKeysPressed, equals(<LogicalKeyboardKey>{LogicalKeyboardKey.numLock}));
|
|
expect(HardwareKeyboard.instance.lockModesEnabled, equals(<KeyboardLockMode>{KeyboardLockMode.numLock}));
|
|
events.clear();
|
|
|
|
await tester.sendKeyUpEvent(LogicalKeyboardKey.numLock);
|
|
_verifyKeyEvent<KeyUpEvent>(events[0], PhysicalKeyboardKey.numLock, LogicalKeyboardKey.numLock, null);
|
|
expect(HardwareKeyboard.instance.physicalKeysPressed, isEmpty);
|
|
expect(HardwareKeyboard.instance.logicalKeysPressed, isEmpty);
|
|
expect(HardwareKeyboard.instance.lockModesEnabled, equals(<KeyboardLockMode>{KeyboardLockMode.numLock}));
|
|
events.clear();
|
|
|
|
// Key press numLock (2nd time)
|
|
await tester.sendKeyDownEvent(LogicalKeyboardKey.numLock);
|
|
_verifyKeyEvent<KeyDownEvent>(events[0], PhysicalKeyboardKey.numLock, LogicalKeyboardKey.numLock, null);
|
|
expect(HardwareKeyboard.instance.physicalKeysPressed, equals(<PhysicalKeyboardKey>{PhysicalKeyboardKey.numLock}));
|
|
expect(HardwareKeyboard.instance.logicalKeysPressed, equals(<LogicalKeyboardKey>{LogicalKeyboardKey.numLock}));
|
|
expect(HardwareKeyboard.instance.lockModesEnabled, isEmpty);
|
|
events.clear();
|
|
|
|
await tester.sendKeyRepeatEvent(LogicalKeyboardKey.numLock);
|
|
_verifyKeyEvent<KeyRepeatEvent>(events[0], PhysicalKeyboardKey.numLock, LogicalKeyboardKey.numLock, null);
|
|
expect(HardwareKeyboard.instance.physicalKeysPressed, equals(<PhysicalKeyboardKey>{PhysicalKeyboardKey.numLock}));
|
|
expect(HardwareKeyboard.instance.logicalKeysPressed, equals(<LogicalKeyboardKey>{LogicalKeyboardKey.numLock}));
|
|
expect(HardwareKeyboard.instance.lockModesEnabled, isEmpty);
|
|
events.clear();
|
|
|
|
await tester.sendKeyUpEvent(LogicalKeyboardKey.numLock);
|
|
_verifyKeyEvent<KeyUpEvent>(events[0], PhysicalKeyboardKey.numLock, LogicalKeyboardKey.numLock, null);
|
|
expect(HardwareKeyboard.instance.physicalKeysPressed, isEmpty);
|
|
expect(HardwareKeyboard.instance.logicalKeysPressed, isEmpty);
|
|
expect(HardwareKeyboard.instance.lockModesEnabled, isEmpty);
|
|
events.clear();
|
|
|
|
await tester.idle();
|
|
|
|
await tester.pumpWidget(Container());
|
|
focusNode.dispose();
|
|
|
|
debugKeyEventSimulatorTransitModeOverride = null;
|
|
});
|
|
|
|
testWidgets('simulates using the correct transit mode: rawKeyData', (WidgetTester tester) async {
|
|
debugKeyEventSimulatorTransitModeOverride = KeyDataTransitMode.rawKeyData;
|
|
|
|
final List<Object> events = <Object>[];
|
|
|
|
final FocusNode focusNode = FocusNode();
|
|
await tester.pumpWidget(
|
|
Focus(
|
|
focusNode: focusNode,
|
|
onKey: (FocusNode node, RawKeyEvent event) {
|
|
events.add(event);
|
|
return KeyEventResult.ignored;
|
|
},
|
|
onKeyEvent: (FocusNode node, KeyEvent event) {
|
|
events.add(event);
|
|
return KeyEventResult.ignored;
|
|
},
|
|
child: Container(),
|
|
),
|
|
);
|
|
|
|
focusNode.requestFocus();
|
|
await tester.idle();
|
|
|
|
// A (physical keyA, logical keyA) is pressed.
|
|
await simulateKeyDownEvent(LogicalKeyboardKey.keyA);
|
|
expect(events.length, 2);
|
|
expect(events[0], isA<KeyEvent>());
|
|
_verifyKeyEvent<KeyDownEvent>(events[0] as KeyEvent, PhysicalKeyboardKey.keyA, LogicalKeyboardKey.keyA, 'a');
|
|
expect(events[1], isA<RawKeyEvent>());
|
|
_verifyRawKeyEvent<RawKeyDownEvent>(events[1] as RawKeyEvent, PhysicalKeyboardKey.keyA, LogicalKeyboardKey.keyA, 'a');
|
|
events.clear();
|
|
|
|
// A (physical keyA, logical keyB) is released.
|
|
//
|
|
// Since this event was synthesized and regularized before being sent to
|
|
// HardwareKeyboard, this event will be accepted.
|
|
await simulateKeyUpEvent(LogicalKeyboardKey.keyB, physicalKey: PhysicalKeyboardKey.keyA);
|
|
expect(events.length, 2);
|
|
expect(events[0], isA<KeyEvent>());
|
|
_verifyKeyEvent<KeyUpEvent>(events[0] as KeyEvent, PhysicalKeyboardKey.keyA, LogicalKeyboardKey.keyA, null);
|
|
expect(events[1], isA<RawKeyEvent>());
|
|
_verifyRawKeyEvent<RawKeyUpEvent>(events[1] as RawKeyEvent, PhysicalKeyboardKey.keyA, LogicalKeyboardKey.keyB, null);
|
|
events.clear();
|
|
|
|
// Manually switch the transit mode to `keyDataThenRawKeyData`. This will
|
|
// never happen in real applications so the assertion error can verify that
|
|
// the transit mode is correctly applied.
|
|
debugKeyEventSimulatorTransitModeOverride = KeyDataTransitMode.keyDataThenRawKeyData;
|
|
|
|
await _shouldThrow<AssertionError>(() =>
|
|
simulateKeyUpEvent(LogicalKeyboardKey.keyB, physicalKey: PhysicalKeyboardKey.keyA));
|
|
|
|
debugKeyEventSimulatorTransitModeOverride = null;
|
|
});
|
|
|
|
testWidgets('simulates using the correct transit mode: keyDataThenRawKeyData', (WidgetTester tester) async {
|
|
debugKeyEventSimulatorTransitModeOverride = KeyDataTransitMode.keyDataThenRawKeyData;
|
|
|
|
final List<Object> events = <Object>[];
|
|
|
|
final FocusNode focusNode = FocusNode();
|
|
await tester.pumpWidget(
|
|
Focus(
|
|
focusNode: focusNode,
|
|
onKey: (FocusNode node, RawKeyEvent event) {
|
|
events.add(event);
|
|
return KeyEventResult.ignored;
|
|
},
|
|
onKeyEvent: (FocusNode node, KeyEvent event) {
|
|
events.add(event);
|
|
return KeyEventResult.ignored;
|
|
},
|
|
child: Container(),
|
|
),
|
|
);
|
|
|
|
focusNode.requestFocus();
|
|
await tester.idle();
|
|
|
|
// A (physical keyA, logical keyA) is pressed.
|
|
await simulateKeyDownEvent(LogicalKeyboardKey.keyA);
|
|
expect(events.length, 2);
|
|
expect(events[0], isA<KeyEvent>());
|
|
_verifyKeyEvent<KeyDownEvent>(events[0] as KeyEvent, PhysicalKeyboardKey.keyA, LogicalKeyboardKey.keyA, 'a');
|
|
expect(events[1], isA<RawKeyEvent>());
|
|
_verifyRawKeyEvent<RawKeyDownEvent>(events[1] as RawKeyEvent, PhysicalKeyboardKey.keyA, LogicalKeyboardKey.keyA, 'a');
|
|
events.clear();
|
|
|
|
// A (physical keyA, logical keyB) is released.
|
|
//
|
|
// Since this event is transmitted to HardwareKeyboard as-is, it will be rejected due to
|
|
// inconsistent logical key. This does not indicate behavioral difference,
|
|
// since KeyData is will never send malformed data sequence in real applications.
|
|
await _shouldThrow<AssertionError>(() =>
|
|
simulateKeyUpEvent(LogicalKeyboardKey.keyB, physicalKey: PhysicalKeyboardKey.keyA));
|
|
|
|
debugKeyEventSimulatorTransitModeOverride = null;
|
|
});
|
|
}
|