blob: 36390efd6ab1c291a39cb8e43bf8c39c6b225d58 [file] [log] [blame]
// 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@@@
};
}