Skip to content

Commit

Permalink
Add isLogicalKeyPressed to KeyEvent (#136856)
Browse files Browse the repository at this point in the history
## Description

Adds some convenience methods to `KeyEvent` that allow testing to see if a logical or physical key is pressed from the event object. These are similar to the ones already on `RawKeyEvent`, and will make migration the to `KeyEvent` easier (so it could more easily be a `flutter fix` migration).

Added:

- `bool isLogicalKeyPressed(LogicalKeyboardKey key)`
- `bool isPhysicalKeyPressed(PhysicalKeyboardKey key)`
- `bool get isControlPressed`
- `bool get isShiftPressed`
- `bool get isAltPressed`
- `bool get isMetaPressed`

## Related Issues
 - flutter/flutter#136419

## Tests
 - Added tests for the new methods.
  • Loading branch information
gspencergoog authored Oct 27, 2023
1 parent 4cae1af commit 5907c97
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 2 deletions.
47 changes: 47 additions & 0 deletions packages/flutter/lib/src/services/hardware_keyboard.dart
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,53 @@ class HardwareKeyboard {
/// of the event.
Set<KeyboardLockMode> get lockModesEnabled => _lockModes;

/// Returns true if the given [LogicalKeyboardKey] is pressed, according to
/// the [HardwareKeyboard].
bool isLogicalKeyPressed(LogicalKeyboardKey key) => _pressedKeys.values.contains(key);

/// Returns true if the given [PhysicalKeyboardKey] is pressed, according to
/// the [HardwareKeyboard].
bool isPhysicalKeyPressed(PhysicalKeyboardKey key) => _pressedKeys.containsKey(key);

/// Returns true if a logical CTRL modifier key is pressed, regardless of
/// which side of the keyboard it is on.
///
/// Use [isLogicalKeyPressed] if you need to know which control key was
/// pressed.
bool get isControlPressed {
return isLogicalKeyPressed(LogicalKeyboardKey.controlLeft) || isLogicalKeyPressed(LogicalKeyboardKey.controlRight);
}

/// Returns true if a logical SHIFT modifier key is pressed, regardless of
/// which side of the keyboard it is on.
///
/// Use [isLogicalKeyPressed] if you need to know which shift key was pressed.
bool get isShiftPressed {
return isLogicalKeyPressed(LogicalKeyboardKey.shiftLeft) || isLogicalKeyPressed(LogicalKeyboardKey.shiftRight);
}

/// Returns true if a logical ALT modifier key is pressed, regardless of which
/// side of the keyboard it is on.
///
/// The `AltGr` key that appears on some keyboards is considered to be the
/// same as [LogicalKeyboardKey.altRight] on some platforms (notably Android).
/// On platforms that can distinguish between `altRight` and `altGr`, a press
/// of `AltGr` will not return true here, and will need to be tested for
/// separately.
///
/// Use [isLogicalKeyPressed] if you need to know which alt key was pressed.
bool get isAltPressed {
return isLogicalKeyPressed(LogicalKeyboardKey.altLeft) || isLogicalKeyPressed(LogicalKeyboardKey.altRight);
}

/// Returns true if a logical META modifier key is pressed, regardless of
/// which side of the keyboard it is on.
///
/// Use [isLogicalKeyPressed] if you need to know which meta key was pressed.
bool get isMetaPressed {
return isLogicalKeyPressed(LogicalKeyboardKey.metaLeft) || isLogicalKeyPressed(LogicalKeyboardKey.metaRight);
}

void _assertEventIsRegular(KeyEvent event) {
assert(() {
const String common = 'If this occurs in real application, please report this '
Expand Down
3 changes: 1 addition & 2 deletions packages/flutter/lib/src/services/raw_keyboard.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import 'package:flutter/foundation.dart';

import 'binding.dart';
import 'hardware_keyboard.dart';
import 'keyboard_key.g.dart';
import 'raw_keyboard_android.dart';
import 'raw_keyboard_fuchsia.dart';
import 'raw_keyboard_ios.dart';
Expand Down Expand Up @@ -407,7 +406,7 @@ abstract class RawKeyEvent with Diagnosticable {
}
}

/// Returns true if the given [KeyboardKey] is pressed.
/// Returns true if the given [LogicalKeyboardKey] is pressed.
bool isKeyPressed(LogicalKeyboardKey key) => RawKeyboard.instance.keysPressed.contains(key);

/// Returns true if a CTRL modifier key is pressed, regardless of which side
Expand Down
34 changes: 34 additions & 0 deletions packages/flutter/test/services/hardware_keyboard_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,40 @@ void main() {
equals(<KeyboardLockMode>{}));
}, variant: KeySimulatorTransitModeVariant.keyDataThenRawKeyData());

testWidgetsWithLeakTracking('KeyEvent can tell which keys are pressed', (WidgetTester tester) async {
await tester.pumpWidget(const Focus(autofocus: true, child: SizedBox()));
await tester.pump();

await simulateKeyDownEvent(LogicalKeyboardKey.numLock, platform: 'windows');

expect(HardwareKeyboard.instance.isPhysicalKeyPressed(PhysicalKeyboardKey.numLock), isTrue);
expect(HardwareKeyboard.instance.isLogicalKeyPressed(LogicalKeyboardKey.numLock), isTrue);

await simulateKeyDownEvent(LogicalKeyboardKey.numpad1, platform: 'windows');
expect(HardwareKeyboard.instance.isPhysicalKeyPressed(PhysicalKeyboardKey.numpad1), isTrue);
expect(HardwareKeyboard.instance.isLogicalKeyPressed(LogicalKeyboardKey.numpad1), isTrue);

await simulateKeyRepeatEvent(LogicalKeyboardKey.numpad1, platform: 'windows');
expect(HardwareKeyboard.instance.isPhysicalKeyPressed(PhysicalKeyboardKey.numpad1), isTrue);
expect(HardwareKeyboard.instance.isLogicalKeyPressed(LogicalKeyboardKey.numpad1), isTrue);

await simulateKeyUpEvent(LogicalKeyboardKey.numLock);
expect(HardwareKeyboard.instance.isPhysicalKeyPressed(PhysicalKeyboardKey.numpad1), isTrue);
expect(HardwareKeyboard.instance.isLogicalKeyPressed(LogicalKeyboardKey.numpad1), isTrue);

await simulateKeyDownEvent(LogicalKeyboardKey.numLock, platform: 'windows');
expect(HardwareKeyboard.instance.isPhysicalKeyPressed(PhysicalKeyboardKey.numLock), isTrue);
expect(HardwareKeyboard.instance.isLogicalKeyPressed(LogicalKeyboardKey.numLock), isTrue);

await simulateKeyUpEvent(LogicalKeyboardKey.numpad1, platform: 'windows');
expect(HardwareKeyboard.instance.isPhysicalKeyPressed(PhysicalKeyboardKey.numpad1), isFalse);
expect(HardwareKeyboard.instance.isLogicalKeyPressed(LogicalKeyboardKey.numpad1), isFalse);

await simulateKeyUpEvent(LogicalKeyboardKey.numLock, platform: 'windows');
expect(HardwareKeyboard.instance.isPhysicalKeyPressed(PhysicalKeyboardKey.numLock), isFalse);
expect(HardwareKeyboard.instance.isLogicalKeyPressed(LogicalKeyboardKey.numLock), isFalse);
}, variant: KeySimulatorTransitModeVariant.keyDataThenRawKeyData());

testWidgetsWithLeakTracking('KeyboardManager synthesizes modifier keys in rawKeyData mode', (WidgetTester tester) async {
final List<KeyEvent> events = <KeyEvent>[];
HardwareKeyboard.instance.addHandler((KeyEvent event) {
Expand Down

0 comments on commit 5907c97

Please sign in to comment.