| // 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 'keyboard_maps.g.dart'; |
| import 'raw_keyboard.dart'; |
| |
| export 'package:flutter/foundation.dart' show DiagnosticPropertiesBuilder; |
| |
| export 'keyboard_key.g.dart' show LogicalKeyboardKey, PhysicalKeyboardKey; |
| export 'raw_keyboard.dart' show KeyboardSide, ModifierKey; |
| |
| String? _unicodeChar(String key) { |
| if (key.length == 1) { |
| return key.substring(0, 1); |
| } |
| return null; |
| } |
| |
| /// Platform-specific key event data for Web. |
| /// |
| /// See also: |
| /// |
| /// * [RawKeyboard], which uses this interface to expose key data. |
| @immutable |
| class RawKeyEventDataWeb extends RawKeyEventData { |
| /// Creates a key event data structure specific for Web. |
| const RawKeyEventDataWeb({ |
| required this.code, |
| required this.key, |
| this.location = 0, |
| this.metaState = modifierNone, |
| this.keyCode = 0, |
| }); |
| |
| /// The `KeyboardEvent.code` corresponding to this event. |
| /// |
| /// The [code] represents a physical key on the keyboard, a value that isn't |
| /// altered by keyboard layout or the state of the modifier keys. |
| /// |
| /// See <https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code> |
| /// for more information. |
| final String code; |
| |
| /// The `KeyboardEvent.key` corresponding to this event. |
| /// |
| /// The [key] represents the key pressed by the user, taking into |
| /// consideration the state of modifier keys such as Shift as well as the |
| /// keyboard locale and layout. |
| /// |
| /// See <https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key> |
| /// for more information. |
| final String key; |
| |
| /// The `KeyboardEvent.location` corresponding to this event. |
| /// |
| /// The [location] represents the location of the key on the keyboard or other |
| /// input device, such as left or right modifier keys, or Numpad keys. |
| /// |
| /// See <https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/location> |
| /// for more information. |
| final int location; |
| |
| /// The modifiers that were present when the key event occurred. |
| /// |
| /// See `lib/src/engine/keyboard.dart` in the web engine for the numerical |
| /// values of the [metaState]. These constants are also replicated as static |
| /// constants in this class. |
| /// |
| /// See also: |
| /// |
| /// * [modifiersPressed], which returns a Map of currently pressed modifiers |
| /// and their keyboard side. |
| /// * [isModifierPressed], to see if a specific modifier is pressed. |
| /// * [isControlPressed], to see if a CTRL key is pressed. |
| /// * [isShiftPressed], to see if a SHIFT key is pressed. |
| /// * [isAltPressed], to see if an ALT key is pressed. |
| /// * [isMetaPressed], to see if a META key is pressed. |
| final int metaState; |
| |
| /// The `KeyboardEvent.keyCode` corresponding to this event. |
| /// |
| /// See <https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode> |
| /// for more information. |
| final int keyCode; |
| |
| @override |
| String get keyLabel => key == 'Unidentified' ? '' : _unicodeChar(key) ?? ''; |
| |
| @override |
| PhysicalKeyboardKey get physicalKey { |
| return kWebToPhysicalKey[code] ?? PhysicalKeyboardKey(LogicalKeyboardKey.webPlane + code.hashCode); |
| } |
| |
| @override |
| LogicalKeyboardKey get logicalKey { |
| // Look to see if the keyCode is a key based on location. Typically they are |
| // numpad keys (versus main area keys) and left/right modifiers. |
| final LogicalKeyboardKey? maybeLocationKey = kWebLocationMap[key]?[location]; |
| if (maybeLocationKey != null) { |
| return maybeLocationKey; |
| } |
| |
| // Look to see if the [key] is one we know about and have a mapping for. |
| final LogicalKeyboardKey? newKey = kWebToLogicalKey[key]; |
| if (newKey != null) { |
| return newKey; |
| } |
| |
| final bool isPrintable = key.length == 1; |
| if (isPrintable) { |
| return LogicalKeyboardKey(key.toLowerCase().codeUnitAt(0)); |
| } |
| |
| // This is a non-printable key that we don't know about, so we mint a new |
| // key from `code`. Don't mint with `key`, because the `key` will always be |
| // "Unidentified" . |
| return LogicalKeyboardKey(code.hashCode + LogicalKeyboardKey.webPlane); |
| } |
| |
| @override |
| bool isModifierPressed( |
| ModifierKey key, { |
| KeyboardSide side = KeyboardSide.any, |
| }) { |
| switch (key) { |
| case ModifierKey.controlModifier: |
| return metaState & modifierControl != 0; |
| case ModifierKey.shiftModifier: |
| return metaState & modifierShift != 0; |
| case ModifierKey.altModifier: |
| return metaState & modifierAlt != 0; |
| case ModifierKey.metaModifier: |
| return metaState & modifierMeta != 0; |
| case ModifierKey.numLockModifier: |
| return metaState & modifierNumLock != 0; |
| case ModifierKey.capsLockModifier: |
| return metaState & modifierCapsLock != 0; |
| case ModifierKey.scrollLockModifier: |
| return metaState & modifierScrollLock != 0; |
| case ModifierKey.functionModifier: |
| case ModifierKey.symbolModifier: |
| // On Web, the browser doesn't report the state of the FN and SYM modifiers. |
| return false; |
| } |
| } |
| |
| @override |
| KeyboardSide getModifierSide(ModifierKey key) { |
| // On Web, we don't distinguish the sides of modifier keys. Both left shift |
| // and right shift, for example, are reported as the "Shift" modifier. |
| // |
| // See <https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/getModifierState> |
| // for more information. |
| return KeyboardSide.any; |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DiagnosticsProperty<String>('code', code)); |
| properties.add(DiagnosticsProperty<String>('key', key)); |
| properties.add(DiagnosticsProperty<int>('location', location)); |
| properties.add(DiagnosticsProperty<int>('metaState', metaState)); |
| properties.add(DiagnosticsProperty<int>('keyCode', keyCode)); |
| } |
| |
| @override |
| bool operator==(Object other) { |
| if (identical(this, other)) { |
| return true; |
| } |
| if (other.runtimeType != runtimeType) { |
| return false; |
| } |
| return other is RawKeyEventDataWeb |
| && other.code == code |
| && other.key == key |
| && other.location == location |
| && other.metaState == metaState |
| && other.keyCode == keyCode; |
| } |
| |
| @override |
| int get hashCode => Object.hash( |
| code, |
| key, |
| location, |
| metaState, |
| keyCode, |
| ); |
| |
| // Modifier key masks. |
| |
| /// No modifier keys are pressed in the [metaState] field. |
| /// |
| /// Use this value if you need to decode the [metaState] field yourself, but |
| /// it's much easier to use [isModifierPressed] if you just want to know if |
| /// a modifier is pressed. |
| static const int modifierNone = 0; |
| |
| /// This mask is used to check the [metaState] field to test whether one of |
| /// the SHIFT modifier keys is pressed. |
| /// |
| /// Use this value if you need to decode the [metaState] field yourself, but |
| /// it's much easier to use [isModifierPressed] if you just want to know if |
| /// a modifier is pressed. |
| static const int modifierShift = 0x01; |
| |
| /// This mask is used to check the [metaState] field to test whether one of |
| /// the ALT modifier keys is pressed. |
| /// |
| /// Use this value if you need to decode the [metaState] field yourself, but |
| /// it's much easier to use [isModifierPressed] if you just want to know if |
| /// a modifier is pressed. |
| static const int modifierAlt = 0x02; |
| |
| /// This mask is used to check the [metaState] field to test whether one of |
| /// the CTRL modifier keys is pressed. |
| /// |
| /// Use this value if you need to decode the [metaState] field yourself, but |
| /// it's much easier to use [isModifierPressed] if you just want to know if |
| /// a modifier is pressed. |
| static const int modifierControl = 0x04; |
| |
| /// This mask is used to check the [metaState] field to test whether one of |
| /// the META modifier keys is pressed. |
| /// |
| /// Use this value if you need to decode the [metaState] field yourself, but |
| /// it's much easier to use [isModifierPressed] if you just want to know if |
| /// a modifier is pressed. |
| static const int modifierMeta = 0x08; |
| |
| /// This mask is used to check the [metaState] field to test whether the NUM |
| /// LOCK modifier key is on. |
| /// |
| /// Use this value if you need to decode the [metaState] field yourself, but |
| /// it's much easier to use [isModifierPressed] if you just want to know if |
| /// a modifier is pressed. |
| static const int modifierNumLock = 0x10; |
| |
| /// This mask is used to check the [metaState] field to test whether the CAPS |
| /// LOCK modifier key is on. |
| /// |
| /// Use this value if you need to decode the [metaState] field yourself, but |
| /// it's much easier to use [isModifierPressed] if you just want to know if |
| /// a modifier is pressed. |
| static const int modifierCapsLock = 0x20; |
| |
| /// This mask is used to check the [metaState] field to test whether the |
| /// SCROLL LOCK modifier key is on. |
| /// |
| /// Use this value if you need to decode the [metaState] field yourself, but |
| /// it's much easier to use [isModifierPressed] if you just want to know if |
| /// a modifier is pressed. |
| static const int modifierScrollLock = 0x40; |
| } |