// 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'; export 'package:flutter/foundation.dart' show DiagnosticPropertiesBuilder; // DO NOT EDIT -- DO NOT EDIT -- DO NOT EDIT // This file is generated by dev/tools/gen_keycodes/bin/gen_keycodes.dart and // should not be edited directly. // // Edit the template dev/tools/gen_keycodes/data/keyboard_key.tmpl instead. // See dev/tools/gen_keycodes/README.md for more information. /// A base class for all keyboard key types. /// /// See also: /// /// * [PhysicalKeyboardKey], a class with static values that describe the keys /// that are returned from [RawKeyEvent.physicalKey]. /// * [LogicalKeyboardKey], a class with static values that describe the keys /// that are returned from [RawKeyEvent.logicalKey]. abstract class KeyboardKey with Diagnosticable { /// Abstract const constructor. This constructor enables subclasses to provide /// const constructors so that they can be used in const expressions. const KeyboardKey(); } /// A class with static values that describe the keys that are returned from /// [RawKeyEvent.logicalKey]. /// /// These represent *logical* keys, which are keys which are interpreted in the /// context of any modifiers, modes, or keyboard layouts which may be in effect. /// /// This is contrast to [PhysicalKeyboardKey], which represents a physical key /// in a particular location on the keyboard, without regard for the modifier /// state, mode, or keyboard layout. /// /// As an example, if you wanted to implement an app where the "Q" key "quit" /// something, you'd want to look at the logical key to detect this, since you /// would like to have it match the key with "Q" on it, instead of always /// looking for "the key next to the TAB key", since on a French keyboard, /// the key next to the TAB key has an "A" on it. /// /// Conversely, if you wanted a game where the key next to the CAPS LOCK (the /// "A" key on a QWERTY keyboard) moved the player to the left, you'd want to /// look at the physical key to make sure that regardless of the character the /// key produces, you got the key that is in that location on the keyboard. /// /// {@tool dartpad} /// This example shows how to detect if the user has selected the logical "Q" /// key and handle the key if they have. /// /// ** See code in examples/api/lib/services/keyboard_key/logical_keyboard_key.0.dart ** /// {@end-tool} /// See also: /// /// * [RawKeyEvent], the keyboard event object received by widgets that listen /// to keyboard events. /// * [Focus.onKey], the handler on a widget that lets you handle key events. /// * [RawKeyboardListener], a widget used to listen to keyboard events (but /// not handle them). @immutable class LogicalKeyboardKey extends KeyboardKey { /// Creates a new LogicalKeyboardKey object for a key ID. const LogicalKeyboardKey(this.keyId); /// A unique code representing this key. /// /// This is an opaque code. It should not be unpacked to derive information /// from it, as the representation of the code could change at any time. final int keyId; // Returns the bits that are not included in [valueMask], shifted to the // right. // // For example, if the input is 0x12abcdabcd, then the result is 0x12. // // This is mostly equivalent to a right shift, resolving the problem that // JavaScript only support 32-bit bitwise operation and needs to use division // instead. static int _nonValueBits(int n) { // `n >> valueMaskWidth` is equivalent to `n / divisorForValueMask`. const int divisorForValueMask = valueMask + 1; const int valueMaskWidth = 32; // Equivalent to assert(divisorForValueMask == (1 << valueMaskWidth)). const int firstDivisorWidth = 28; assert(divisorForValueMask == (1 << firstDivisorWidth) * (1 << (valueMaskWidth - firstDivisorWidth))); // JS only supports up to 2^53 - 1, therefore non-value bits can only // contain (maxSafeIntegerWidth - valueMaskWidth) bits. const int maxSafeIntegerWidth = 52; const int nonValueMask = (1 << (maxSafeIntegerWidth - valueMaskWidth)) - 1; if (kIsWeb) { return (n / divisorForValueMask).floor() & nonValueMask; } else { return (n >> valueMaskWidth) & nonValueMask; } } static String? _unicodeKeyLabel(int keyId) { if (_nonValueBits(keyId) == 0) { return String.fromCharCode(keyId).toUpperCase(); } return null; } /// A description representing the character produced by a [RawKeyEvent]. /// /// This value is useful for providing readable strings for keys or keyboard /// shortcuts. Do not use this value to compare equality of keys; compare /// [keyId] instead. /// /// For printable keys, this is usually the printable character in upper case /// ignoring modifiers or combining keys, such as 'A', '1', or '/'. This /// might also return accented letters (such as 'Ù') for keys labeled as so, /// but not if such character is a result from preceding combining keys ('`̀' /// followed by key U). /// /// For other keys, [keyLabel] looks up the full key name from a predefined /// map, such as 'F1', 'Shift Left', or 'Media Down'. This value is an empty /// string if there's no key label data for a key. /// /// For the printable representation that takes into consideration the /// modifiers and combining keys, see [RawKeyEvent.character]. /// /// {@macro flutter.services.RawKeyEventData.keyLabel} String get keyLabel { return _unicodeKeyLabel(keyId) ?? _keyLabels[keyId] ?? ''; } /// The debug string to print for this keyboard key, which will be null in /// release mode. /// /// For printable keys, this is usually a more descriptive name related to /// [keyLabel], such as 'Key A', 'Digit 1', 'Backslash'. This might /// also return accented letters (such as 'Key Ù') for keys labeled as so. /// /// For other keys, this looks up the full key name from a predefined map (the /// same value as [keyLabel]), such as 'F1', 'Shift Left', or 'Media Down'. If /// there's no key label data for a key, this returns a name that explains the /// ID (such as 'Key with ID 0x00100012345'). String? get debugName { String? result; assert(() { result = _keyLabels[keyId]; if (result == null) { final String? unicodeKeyLabel = _unicodeKeyLabel(keyId); if (unicodeKeyLabel != null) { result = 'Key $unicodeKeyLabel'; } else { result = 'Key with ID 0x${keyId.toRadixString(16).padLeft(11, '0')}'; } } return true; }()); return result; } @override int get hashCode => keyId.hashCode; @override bool operator ==(Object other) { if (identical(this, other)) { return true; } if (other.runtimeType != runtimeType) { return false; } return other is LogicalKeyboardKey && other.keyId == keyId; } /// Returns the [LogicalKeyboardKey] constant that matches the given ID, or /// null, if not found. static LogicalKeyboardKey? findKeyByKeyId(int keyId) => _knownLogicalKeys[keyId]; /// Returns true if the given label represents a Unicode control character. /// /// Examples of control characters are characters like "U+000A LINE FEED (LF)" /// or "U+001B ESCAPE (ESC)". /// /// See <https://en.wikipedia.org/wiki/Unicode_control_characters> for more /// information. /// /// Used by [RawKeyEvent] subclasses to help construct IDs. static bool isControlCharacter(String label) { if (label.length != 1) { return false; } final int codeUnit = label.codeUnitAt(0); return (codeUnit <= 0x1f && codeUnit >= 0x00) || (codeUnit >= 0x7f && codeUnit <= 0x9f); } /// Returns true if the [keyId] of this object is one that is auto-generated by /// Flutter. /// /// Auto-generated key IDs are generated in response to platform key codes /// which Flutter doesn't recognize, and their IDs shouldn't be used in a /// persistent way. /// /// Auto-generated IDs should be a rare occurrence: Flutter supports most keys. /// /// Keys that generate Unicode characters (even if unknown to Flutter) will /// not return true for [isAutogenerated], since they will be assigned a /// Unicode-based code that will remain stable. /// /// If Flutter adds support for a previously unsupported key code, the ID it /// reports will change, but the ID will remain stable on the platform it is /// produced on until Flutter adds support for recognizing it. /// /// So, hypothetically, if Android added a new key code of 0xffff, /// representing a new "do what I mean" key, then the auto-generated code /// would be 0x1020000ffff, but once Flutter added the "doWhatIMean" key to /// the definitions below, the new code would be 0x0020000ffff for all /// platforms that had a "do what I mean" key from then on. bool get isAutogenerated => (keyId & planeMask) >= startOfPlatformPlanes; /// Returns a set of pseudo-key synonyms for the given `key`. /// /// This allows finding the pseudo-keys that also represents a concrete /// `key` so that a class with a key map can match pseudo-keys as well as the /// actual generated keys. /// /// The pseudo-keys returned in the set are typically used to represent keys /// which appear in multiple places on the keyboard, such as the [shift], /// [alt], [control], and [meta] keys. The keys in the returned set won't ever /// be generated directly, but if a more specific key event is received, then /// this set can be used to find the more general pseudo-key. For example, if /// this is a [shiftLeft] key, this accessor will return the set /// `<LogicalKeyboardKey>{ shift }`. Set<LogicalKeyboardKey> get synonyms { final LogicalKeyboardKey? result = _synonyms[this]; return result == null ? <LogicalKeyboardKey>{} : <LogicalKeyboardKey>{result}; } /// Takes a set of keys, and returns the same set, but with any keys that have /// synonyms replaced. /// /// It is used, for example, to make sets of keys with members like /// [controlRight] and [controlLeft] and convert that set to contain just /// [control], so that the question "is any control key down?" can be asked. static Set<LogicalKeyboardKey> collapseSynonyms(Set<LogicalKeyboardKey> input) { final Set<LogicalKeyboardKey> result = <LogicalKeyboardKey>{}; for (final LogicalKeyboardKey key in input) { final LogicalKeyboardKey? synonym = _synonyms[key]; result.add(synonym ?? key); } return result; } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(StringProperty('keyId', '0x${keyId.toRadixString(16).padLeft(8, '0')}')); properties.add(StringProperty('keyLabel', keyLabel)); properties.add(StringProperty('debugName', debugName, defaultValue: null)); } @@@MASK_CONSTANTS@@@ @@@LOGICAL_KEY_DEFINITIONS@@@ /// A list of all predefined constant [LogicalKeyboardKey]s. static Iterable<LogicalKeyboardKey> get knownLogicalKeys => _knownLogicalKeys.values; // A list of all predefined constant LogicalKeyboardKeys so they can be // searched. static const Map<int, LogicalKeyboardKey> _knownLogicalKeys = <int, LogicalKeyboardKey>{ @@@LOGICAL_KEY_MAP@@@ }; // A map of keys to the pseudo-key synonym for that key. Used by getSynonyms. static final Map<LogicalKeyboardKey, LogicalKeyboardKey> _synonyms = <LogicalKeyboardKey, LogicalKeyboardKey>{ @@@LOGICAL_KEY_SYNONYMS@@@ }; static const Map<int, String> _keyLabels = <int, String>{ @@@LOGICAL_KEY_KEY_LABELS@@@ }; } /// A class with static values that describe the keys that are returned from /// [RawKeyEvent.physicalKey]. /// /// These represent *physical* keys, which are keys which represent a particular /// key location on a QWERTY keyboard. It ignores any modifiers, modes, or /// keyboard layouts which may be in effect. This is contrast to /// [LogicalKeyboardKey], which represents a logical key interpreted in the /// context of modifiers, modes, and/or keyboard layouts. /// /// As an example, if you wanted a game where the key next to the CAPS LOCK (the /// "A" key on a QWERTY keyboard) moved the player to the left, you'd want to /// look at the physical key to make sure that regardless of the character the /// key produces, you got the key that is in that location on the keyboard. /// /// Conversely, if you wanted to implement an app where the "Q" key "quit" /// something, you'd want to look at the logical key to detect this, since you /// would like to have it match the key with "Q" on it, instead of always /// looking for "the key next to the TAB key", since on a French keyboard, /// the key next to the TAB key has an "A" on it. /// /// {@tool dartpad} /// This example shows how to detect if the user has selected the physical key /// to the right of the CAPS LOCK key. /// /// ** See code in examples/api/lib/services/keyboard_key/physical_keyboard_key.0.dart ** /// {@end-tool} /// /// See also: /// /// * [RawKeyEvent], the keyboard event object received by widgets that listen /// to keyboard events. /// * [Focus.onKey], the handler on a widget that lets you handle key events. /// * [RawKeyboardListener], a widget used to listen to keyboard events (but /// not handle them). @immutable class PhysicalKeyboardKey extends KeyboardKey { /// Creates a new PhysicalKeyboardKey object for a USB HID usage. const PhysicalKeyboardKey(this.usbHidUsage); /// The unique USB HID usage ID of this physical key on the keyboard. /// /// Due to the variations in platform APIs, this may not be the actual HID /// usage code from the hardware, but a value derived from available /// information on the platform. /// /// See <https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf> /// for the HID usage values and their meanings. final int usbHidUsage; /// The debug string to print for this keyboard key, which will be null in /// release mode. String? get debugName { String? result; assert(() { result = _debugNames[usbHidUsage] ?? 'Key with ID 0x${usbHidUsage.toRadixString(16).padLeft(8, '0')}'; return true; }()); return result; } @override int get hashCode => usbHidUsage.hashCode; @override bool operator ==(Object other) { if (identical(this, other)) { return true; } if (other.runtimeType != runtimeType) { return false; } return other is PhysicalKeyboardKey && other.usbHidUsage == usbHidUsage; } /// Finds a known [PhysicalKeyboardKey] that matches the given USB HID usage /// code. static PhysicalKeyboardKey? findKeyByCode(int usageCode) => _knownPhysicalKeys[usageCode]; @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(StringProperty('usbHidUsage', '0x${usbHidUsage.toRadixString(16).padLeft(8, '0')}')); properties.add(StringProperty('debugName', debugName, defaultValue: null)); } // Key constants for all keyboard keys in the USB HID specification at the // time Flutter was built. @@@PHYSICAL_KEY_DEFINITIONS@@@ /// A list of all predefined constant [PhysicalKeyboardKey]s. static Iterable<PhysicalKeyboardKey> get knownPhysicalKeys => _knownPhysicalKeys.values; // A list of all the predefined constant PhysicalKeyboardKeys so that they // can be searched. static const Map<int, PhysicalKeyboardKey> _knownPhysicalKeys = <int, PhysicalKeyboardKey>{ @@@PHYSICAL_KEY_MAP@@@ }; static const Map<int, String> _debugNames = kReleaseMode ? <int, String>{} : <int, String>{ @@@PHYSICAL_KEY_DEBUG_NAMES@@@ }; }