Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Greg Spencer | 041a3ea | 2020-08-19 15:03:17 -0700 | [diff] [blame] | 5 | import 'package:flutter/foundation.dart'; |
Tong Mu | c177db1 | 2020-07-29 13:20:07 -0700 | [diff] [blame] | 6 | |
Alexandre Ardhuin | bbdf617 | 2022-06-28 22:26:06 +0200 | [diff] [blame] | 7 | export 'package:flutter/foundation.dart' show DiagnosticPropertiesBuilder; |
| 8 | |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 9 | // DO NOT EDIT -- DO NOT EDIT -- DO NOT EDIT |
| 10 | // This file is generated by dev/tools/gen_keycodes/bin/gen_keycodes.dart and |
| 11 | // should not be edited directly. |
| 12 | // |
| 13 | // Edit the template dev/tools/gen_keycodes/data/keyboard_key.tmpl instead. |
| 14 | // See dev/tools/gen_keycodes/README.md for more information. |
| 15 | |
Greg Spencer | 387e2b0 | 2019-06-04 11:30:24 -0700 | [diff] [blame] | 16 | /// A base class for all keyboard key types. |
| 17 | /// |
| 18 | /// See also: |
| 19 | /// |
| 20 | /// * [PhysicalKeyboardKey], a class with static values that describe the keys |
| 21 | /// that are returned from [RawKeyEvent.physicalKey]. |
| 22 | /// * [LogicalKeyboardKey], a class with static values that describe the keys |
| 23 | /// that are returned from [RawKeyEvent.logicalKey]. |
Francisco Magdaleno | a0f7f6c | 2020-04-08 10:07:02 -0700 | [diff] [blame] | 24 | abstract class KeyboardKey with Diagnosticable { |
Ian Hickson | 3419842 | 2021-02-17 19:46:04 -0800 | [diff] [blame] | 25 | /// Abstract const constructor. This constructor enables subclasses to provide |
| 26 | /// const constructors so that they can be used in const expressions. |
Greg Spencer | 387e2b0 | 2019-06-04 11:30:24 -0700 | [diff] [blame] | 27 | const KeyboardKey(); |
| 28 | } |
| 29 | |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 30 | /// A class with static values that describe the keys that are returned from |
| 31 | /// [RawKeyEvent.logicalKey]. |
| 32 | /// |
| 33 | /// These represent *logical* keys, which are keys which are interpreted in the |
| 34 | /// context of any modifiers, modes, or keyboard layouts which may be in effect. |
| 35 | /// |
| 36 | /// This is contrast to [PhysicalKeyboardKey], which represents a physical key |
| 37 | /// in a particular location on the keyboard, without regard for the modifier |
| 38 | /// state, mode, or keyboard layout. |
| 39 | /// |
Greg Spencer | 431cfda | 2019-02-08 12:42:34 -0800 | [diff] [blame] | 40 | /// As an example, if you wanted to implement an app where the "Q" key "quit" |
| 41 | /// something, you'd want to look at the logical key to detect this, since you |
| 42 | /// would like to have it match the key with "Q" on it, instead of always |
nt4f04uNd | 80a2b6b | 2021-05-21 03:19:09 +0300 | [diff] [blame] | 43 | /// looking for "the key next to the TAB key", since on a French keyboard, |
Greg Spencer | 431cfda | 2019-02-08 12:42:34 -0800 | [diff] [blame] | 44 | /// the key next to the TAB key has an "A" on it. |
| 45 | /// |
| 46 | /// Conversely, if you wanted a game where the key next to the CAPS LOCK (the |
| 47 | /// "A" key on a QWERTY keyboard) moved the player to the left, you'd want to |
| 48 | /// look at the physical key to make sure that regardless of the character the |
| 49 | /// key produces, you got the key that is in that location on the keyboard. |
| 50 | /// |
Tong Mu | 32d78ab | 2021-12-01 14:24:04 -0800 | [diff] [blame] | 51 | /// {@tool dartpad} |
Greg Spencer | 431cfda | 2019-02-08 12:42:34 -0800 | [diff] [blame] | 52 | /// This example shows how to detect if the user has selected the logical "Q" |
Tong Mu | a92f0ef | 2022-05-19 18:38:06 -0700 | [diff] [blame] | 53 | /// key and handle the key if they have. |
Greg Spencer | 431cfda | 2019-02-08 12:42:34 -0800 | [diff] [blame] | 54 | /// |
Tong Mu | 32d78ab | 2021-12-01 14:24:04 -0800 | [diff] [blame] | 55 | /// ** See code in examples/api/lib/services/keyboard_key/logical_keyboard_key.0.dart ** |
Greg Spencer | 431cfda | 2019-02-08 12:42:34 -0800 | [diff] [blame] | 56 | /// {@end-tool} |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 57 | /// See also: |
| 58 | /// |
| 59 | /// * [RawKeyEvent], the keyboard event object received by widgets that listen |
| 60 | /// to keyboard events. |
Tong Mu | a92f0ef | 2022-05-19 18:38:06 -0700 | [diff] [blame] | 61 | /// * [Focus.onKey], the handler on a widget that lets you handle key events. |
| 62 | /// * [RawKeyboardListener], a widget used to listen to keyboard events (but |
| 63 | /// not handle them). |
Tong Mu | c177db1 | 2020-07-29 13:20:07 -0700 | [diff] [blame] | 64 | @immutable |
Greg Spencer | 387e2b0 | 2019-06-04 11:30:24 -0700 | [diff] [blame] | 65 | class LogicalKeyboardKey extends KeyboardKey { |
Tong Mu | dbcac7f | 2021-04-01 16:39:02 -0700 | [diff] [blame] | 66 | /// Creates a new LogicalKeyboardKey object for a key ID. |
| 67 | const LogicalKeyboardKey(this.keyId); |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 68 | |
| 69 | /// A unique code representing this key. |
| 70 | /// |
Greg Spencer | 431cfda | 2019-02-08 12:42:34 -0800 | [diff] [blame] | 71 | /// This is an opaque code. It should not be unpacked to derive information |
| 72 | /// from it, as the representation of the code could change at any time. |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 73 | final int keyId; |
| 74 | |
Tong Mu | dbcac7f | 2021-04-01 16:39:02 -0700 | [diff] [blame] | 75 | // Returns the bits that are not included in [valueMask], shifted to the |
| 76 | // right. |
| 77 | // |
| 78 | // For example, if the input is 0x12abcdabcd, then the result is 0x12. |
| 79 | // |
| 80 | // This is mostly equivalent to a right shift, resolving the problem that |
| 81 | // JavaScript only support 32-bit bitwise operation and needs to use division |
| 82 | // instead. |
| 83 | static int _nonValueBits(int n) { |
| 84 | // `n >> valueMaskWidth` is equivalent to `n / divisorForValueMask`. |
| 85 | const int divisorForValueMask = valueMask + 1; |
| 86 | const int valueMaskWidth = 32; |
Tong Mu | a603714 | 2021-03-28 03:54:02 -0700 | [diff] [blame] | 87 | |
Tong Mu | dbcac7f | 2021-04-01 16:39:02 -0700 | [diff] [blame] | 88 | // Equivalent to assert(divisorForValueMask == (1 << valueMaskWidth)). |
Tong Mu | c5e3e1c | 2022-04-14 11:24:11 -0700 | [diff] [blame] | 89 | const int firstDivisorWidth = 28; |
Tong Mu | dbcac7f | 2021-04-01 16:39:02 -0700 | [diff] [blame] | 90 | assert(divisorForValueMask == |
Tong Mu | c5e3e1c | 2022-04-14 11:24:11 -0700 | [diff] [blame] | 91 | (1 << firstDivisorWidth) * (1 << (valueMaskWidth - firstDivisorWidth))); |
Tong Mu | dbcac7f | 2021-04-01 16:39:02 -0700 | [diff] [blame] | 92 | |
| 93 | // JS only supports up to 2^53 - 1, therefore non-value bits can only |
| 94 | // contain (maxSafeIntegerWidth - valueMaskWidth) bits. |
| 95 | const int maxSafeIntegerWidth = 52; |
| 96 | const int nonValueMask = (1 << (maxSafeIntegerWidth - valueMaskWidth)) - 1; |
| 97 | |
| 98 | if (kIsWeb) { |
| 99 | return (n / divisorForValueMask).floor() & nonValueMask; |
| 100 | } else { |
| 101 | return (n >> valueMaskWidth) & nonValueMask; |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | static String? _unicodeKeyLabel(int keyId) { |
| 106 | if (_nonValueBits(keyId) == 0) { |
| 107 | return String.fromCharCode(keyId).toUpperCase(); |
| 108 | } |
| 109 | return null; |
| 110 | } |
| 111 | |
| 112 | /// A description representing the character produced by a [RawKeyEvent]. |
Tong Mu | b60c855 | 2021-03-26 22:14:01 -0700 | [diff] [blame] | 113 | /// |
Tong Mu | dbcac7f | 2021-04-01 16:39:02 -0700 | [diff] [blame] | 114 | /// This value is useful for providing readable strings for keys or keyboard |
| 115 | /// shortcuts. Do not use this value to compare equality of keys; compare |
| 116 | /// [keyId] instead. |
Tong Mu | b60c855 | 2021-03-26 22:14:01 -0700 | [diff] [blame] | 117 | /// |
Tong Mu | dbcac7f | 2021-04-01 16:39:02 -0700 | [diff] [blame] | 118 | /// For printable keys, this is usually the printable character in upper case |
| 119 | /// ignoring modifiers or combining keys, such as 'A', '1', or '/'. This |
| 120 | /// might also return accented letters (such as 'Ù') for keys labeled as so, |
| 121 | /// but not if such character is a result from preceding combining keys ('`̀' |
| 122 | /// followed by key U). |
Tong Mu | a603714 | 2021-03-28 03:54:02 -0700 | [diff] [blame] | 123 | /// |
Tong Mu | dbcac7f | 2021-04-01 16:39:02 -0700 | [diff] [blame] | 124 | /// For other keys, [keyLabel] looks up the full key name from a predefined |
| 125 | /// map, such as 'F1', 'Shift Left', or 'Media Down'. This value is an empty |
| 126 | /// string if there's no key label data for a key. |
| 127 | /// |
| 128 | /// For the printable representation that takes into consideration the |
| 129 | /// modifiers and combining keys, see [RawKeyEvent.character]. |
Tong Mu | a603714 | 2021-03-28 03:54:02 -0700 | [diff] [blame] | 130 | /// |
| 131 | /// {@macro flutter.services.RawKeyEventData.keyLabel} |
Tong Mu | dbcac7f | 2021-04-01 16:39:02 -0700 | [diff] [blame] | 132 | String get keyLabel { |
| 133 | return _unicodeKeyLabel(keyId) |
| 134 | ?? _keyLabels[keyId] |
| 135 | ?? ''; |
| 136 | } |
| 137 | |
| 138 | /// The debug string to print for this keyboard key, which will be null in |
| 139 | /// release mode. |
| 140 | /// |
| 141 | /// For printable keys, this is usually a more descriptive name related to |
| 142 | /// [keyLabel], such as 'Key A', 'Digit 1', 'Backslash'. This might |
| 143 | /// also return accented letters (such as 'Key Ù') for keys labeled as so. |
| 144 | /// |
| 145 | /// For other keys, this looks up the full key name from a predefined map (the |
| 146 | /// same value as [keyLabel]), such as 'F1', 'Shift Left', or 'Media Down'. If |
| 147 | /// there's no key label data for a key, this returns a name that explains the |
| 148 | /// ID (such as 'Key with ID 0x00100012345'). |
| 149 | String? get debugName { |
| 150 | String? result; |
| 151 | assert(() { |
| 152 | result = _keyLabels[keyId]; |
| 153 | if (result == null) { |
| 154 | final String? unicodeKeyLabel = _unicodeKeyLabel(keyId); |
| 155 | if (unicodeKeyLabel != null) { |
| 156 | result = 'Key $unicodeKeyLabel'; |
| 157 | } else { |
| 158 | result = 'Key with ID 0x${keyId.toRadixString(16).padLeft(11, '0')}'; |
| 159 | } |
| 160 | } |
| 161 | return true; |
| 162 | }()); |
| 163 | return result; |
| 164 | } |
Tong Mu | a603714 | 2021-03-28 03:54:02 -0700 | [diff] [blame] | 165 | |
| 166 | @override |
| 167 | int get hashCode => keyId.hashCode; |
| 168 | |
| 169 | @override |
| 170 | bool operator ==(Object other) { |
Tong Mu | ddeb0b9 | 2022-06-16 13:53:23 -0700 | [diff] [blame] | 171 | if (identical(this, other)) { |
Tong Mu | dbcac7f | 2021-04-01 16:39:02 -0700 | [diff] [blame] | 172 | return true; |
Tong Mu | ddeb0b9 | 2022-06-16 13:53:23 -0700 | [diff] [blame] | 173 | } |
| 174 | if (other.runtimeType != runtimeType) { |
Tong Mu | a603714 | 2021-03-28 03:54:02 -0700 | [diff] [blame] | 175 | return false; |
Tong Mu | ddeb0b9 | 2022-06-16 13:53:23 -0700 | [diff] [blame] | 176 | } |
Tong Mu | a603714 | 2021-03-28 03:54:02 -0700 | [diff] [blame] | 177 | return other is LogicalKeyboardKey |
| 178 | && other.keyId == keyId; |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 179 | } |
| 180 | |
Greg Spencer | 431cfda | 2019-02-08 12:42:34 -0800 | [diff] [blame] | 181 | /// Returns the [LogicalKeyboardKey] constant that matches the given ID, or |
| 182 | /// null, if not found. |
Alexandre Ardhuin | 7884420 | 2020-07-31 20:20:00 +0200 | [diff] [blame] | 183 | static LogicalKeyboardKey? findKeyByKeyId(int keyId) => _knownLogicalKeys[keyId]; |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 184 | |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 185 | /// Returns true if the given label represents a Unicode control character. |
| 186 | /// |
| 187 | /// Examples of control characters are characters like "U+000A LINE FEED (LF)" |
| 188 | /// or "U+001B ESCAPE (ESC)". |
| 189 | /// |
| 190 | /// See <https://en.wikipedia.org/wiki/Unicode_control_characters> for more |
| 191 | /// information. |
| 192 | /// |
| 193 | /// Used by [RawKeyEvent] subclasses to help construct IDs. |
| 194 | static bool isControlCharacter(String label) { |
Greg Spencer | 041a3ea | 2020-08-19 15:03:17 -0700 | [diff] [blame] | 195 | if (label.length != 1) { |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 196 | return false; |
| 197 | } |
| 198 | final int codeUnit = label.codeUnitAt(0); |
| 199 | return (codeUnit <= 0x1f && codeUnit >= 0x00) || (codeUnit >= 0x7f && codeUnit <= 0x9f); |
| 200 | } |
| 201 | |
Greg Spencer | ccdd505 | 2019-02-28 15:37:19 -0800 | [diff] [blame] | 202 | /// Returns true if the [keyId] of this object is one that is auto-generated by |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 203 | /// Flutter. |
| 204 | /// |
Greg Spencer | ccdd505 | 2019-02-28 15:37:19 -0800 | [diff] [blame] | 205 | /// Auto-generated key IDs are generated in response to platform key codes |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 206 | /// which Flutter doesn't recognize, and their IDs shouldn't be used in a |
| 207 | /// persistent way. |
| 208 | /// |
Greg Spencer | ccdd505 | 2019-02-28 15:37:19 -0800 | [diff] [blame] | 209 | /// Auto-generated IDs should be a rare occurrence: Flutter supports most keys. |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 210 | /// |
| 211 | /// Keys that generate Unicode characters (even if unknown to Flutter) will |
| 212 | /// not return true for `isAutogenerated`, since they will be assigned a |
| 213 | /// Unicode-based code that will remain stable. |
| 214 | /// |
| 215 | /// If Flutter adds support for a previously unsupported key code, the ID it |
| 216 | /// reports will change, but the ID will remain stable on the platform it is |
| 217 | /// produced on until Flutter adds support for recognizing it. |
| 218 | /// |
| 219 | /// So, hypothetically, if Android added a new key code of 0xffff, |
Greg Spencer | ccdd505 | 2019-02-28 15:37:19 -0800 | [diff] [blame] | 220 | /// representing a new "do what I mean" key, then the auto-generated code |
| 221 | /// would be 0x1020000ffff, but once Flutter added the "doWhatIMean" key to |
| 222 | /// the definitions below, the new code would be 0x0020000ffff for all |
| 223 | /// platforms that had a "do what I mean" key from then on. |
Tong Mu | c8d0b1d | 2021-07-14 13:07:22 -0700 | [diff] [blame] | 224 | bool get isAutogenerated => (keyId & planeMask) >= startOfPlatformPlanes; |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 225 | |
Greg Spencer | a70b020 | 2019-06-03 18:41:04 -0700 | [diff] [blame] | 226 | /// Returns a set of pseudo-key synonyms for the given `key`. |
| 227 | /// |
| 228 | /// This allows finding the pseudo-keys that also represents a concrete |
| 229 | /// `key` so that a class with a key map can match pseudo-keys as well as the |
| 230 | /// actual generated keys. |
| 231 | /// |
| 232 | /// The pseudo-keys returned in the set are typically used to represent keys |
| 233 | /// which appear in multiple places on the keyboard, such as the [shift], |
| 234 | /// [alt], [control], and [meta] keys. The keys in the returned set won't ever |
| 235 | /// be generated directly, but if a more specific key event is received, then |
| 236 | /// this set can be used to find the more general pseudo-key. For example, if |
| 237 | /// this is a [shiftLeft] key, this accessor will return the set |
| 238 | /// `<LogicalKeyboardKey>{ shift }`. |
| 239 | Set<LogicalKeyboardKey> get synonyms { |
Alexandre Ardhuin | 7884420 | 2020-07-31 20:20:00 +0200 | [diff] [blame] | 240 | final LogicalKeyboardKey? result = _synonyms[this]; |
Greg Spencer | a70b020 | 2019-06-03 18:41:04 -0700 | [diff] [blame] | 241 | return result == null ? <LogicalKeyboardKey>{} : <LogicalKeyboardKey>{result}; |
| 242 | } |
| 243 | |
Greg Spencer | c921c5a | 2019-11-08 16:30:38 -0800 | [diff] [blame] | 244 | /// Takes a set of keys, and returns the same set, but with any keys that have |
| 245 | /// synonyms replaced. |
| 246 | /// |
| 247 | /// It is used, for example, to make sets of keys with members like |
| 248 | /// [controlRight] and [controlLeft] and convert that set to contain just |
| 249 | /// [control], so that the question "is any control key down?" can be asked. |
| 250 | static Set<LogicalKeyboardKey> collapseSynonyms(Set<LogicalKeyboardKey> input) { |
| 251 | final Set<LogicalKeyboardKey> result = <LogicalKeyboardKey>{}; |
Alexandre Ardhuin | 8061894 | 2020-01-31 21:58:51 +0100 | [diff] [blame] | 252 | for (final LogicalKeyboardKey key in input) { |
Alexandre Ardhuin | 7884420 | 2020-07-31 20:20:00 +0200 | [diff] [blame] | 253 | final LogicalKeyboardKey? synonym = _synonyms[key]; |
Greg Spencer | c921c5a | 2019-11-08 16:30:38 -0800 | [diff] [blame] | 254 | result.add(synonym ?? key); |
| 255 | } |
| 256 | return result; |
| 257 | } |
| 258 | |
Greg Spencer | a70b020 | 2019-06-03 18:41:04 -0700 | [diff] [blame] | 259 | @override |
| 260 | void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| 261 | super.debugFillProperties(properties); |
Tong Mu | 32d78ab | 2021-12-01 14:24:04 -0800 | [diff] [blame] | 262 | properties.add(StringProperty('keyId', '0x${keyId.toRadixString(16).padLeft(8, '0')}')); |
| 263 | properties.add(StringProperty('keyLabel', keyLabel)); |
| 264 | properties.add(StringProperty('debugName', debugName, defaultValue: null)); |
Greg Spencer | a70b020 | 2019-06-03 18:41:04 -0700 | [diff] [blame] | 265 | } |
| 266 | |
Tong Mu | c8d0b1d | 2021-07-14 13:07:22 -0700 | [diff] [blame] | 267 | @@@MASK_CONSTANTS@@@ |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 268 | |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 269 | @@@LOGICAL_KEY_DEFINITIONS@@@ |
Tong Mu | c8d0b1d | 2021-07-14 13:07:22 -0700 | [diff] [blame] | 270 | |
Tong Mu | caf876c | 2021-07-29 14:24:03 -0700 | [diff] [blame] | 271 | /// A list of all predefined constant [LogicalKeyboardKey]s. |
| 272 | static Iterable<LogicalKeyboardKey> get knownLogicalKeys => _knownLogicalKeys.values; |
| 273 | |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 274 | // A list of all predefined constant LogicalKeyboardKeys so they can be |
Greg Spencer | 431cfda | 2019-02-08 12:42:34 -0800 | [diff] [blame] | 275 | // searched. |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 276 | static const Map<int, LogicalKeyboardKey> _knownLogicalKeys = <int, LogicalKeyboardKey>{ |
| 277 | @@@LOGICAL_KEY_MAP@@@ |
| 278 | }; |
Greg Spencer | a70b020 | 2019-06-03 18:41:04 -0700 | [diff] [blame] | 279 | |
| 280 | // A map of keys to the pseudo-key synonym for that key. Used by getSynonyms. |
| 281 | static final Map<LogicalKeyboardKey, LogicalKeyboardKey> _synonyms = <LogicalKeyboardKey, LogicalKeyboardKey>{ |
| 282 | @@@LOGICAL_KEY_SYNONYMS@@@ }; |
Tong Mu | dbcac7f | 2021-04-01 16:39:02 -0700 | [diff] [blame] | 283 | |
| 284 | static const Map<int, String> _keyLabels = <int, String>{ |
Tong Mu | c8d0b1d | 2021-07-14 13:07:22 -0700 | [diff] [blame] | 285 | @@@LOGICAL_KEY_KEY_LABELS@@@ |
| 286 | }; |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 287 | } |
| 288 | |
| 289 | /// A class with static values that describe the keys that are returned from |
| 290 | /// [RawKeyEvent.physicalKey]. |
| 291 | /// |
Greg Spencer | 431cfda | 2019-02-08 12:42:34 -0800 | [diff] [blame] | 292 | /// These represent *physical* keys, which are keys which represent a particular |
| 293 | /// key location on a QWERTY keyboard. It ignores any modifiers, modes, or |
| 294 | /// keyboard layouts which may be in effect. This is contrast to |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 295 | /// [LogicalKeyboardKey], which represents a logical key interpreted in the |
| 296 | /// context of modifiers, modes, and/or keyboard layouts. |
| 297 | /// |
Greg Spencer | 431cfda | 2019-02-08 12:42:34 -0800 | [diff] [blame] | 298 | /// As an example, if you wanted a game where the key next to the CAPS LOCK (the |
| 299 | /// "A" key on a QWERTY keyboard) moved the player to the left, you'd want to |
| 300 | /// look at the physical key to make sure that regardless of the character the |
| 301 | /// key produces, you got the key that is in that location on the keyboard. |
| 302 | /// |
| 303 | /// Conversely, if you wanted to implement an app where the "Q" key "quit" |
| 304 | /// something, you'd want to look at the logical key to detect this, since you |
| 305 | /// would like to have it match the key with "Q" on it, instead of always |
nt4f04uNd | 80a2b6b | 2021-05-21 03:19:09 +0300 | [diff] [blame] | 306 | /// looking for "the key next to the TAB key", since on a French keyboard, |
Greg Spencer | 431cfda | 2019-02-08 12:42:34 -0800 | [diff] [blame] | 307 | /// the key next to the TAB key has an "A" on it. |
| 308 | /// |
Tong Mu | 32d78ab | 2021-12-01 14:24:04 -0800 | [diff] [blame] | 309 | /// {@tool dartpad} |
Greg Spencer | 431cfda | 2019-02-08 12:42:34 -0800 | [diff] [blame] | 310 | /// This example shows how to detect if the user has selected the physical key |
| 311 | /// to the right of the CAPS LOCK key. |
| 312 | /// |
Tong Mu | 32d78ab | 2021-12-01 14:24:04 -0800 | [diff] [blame] | 313 | /// ** See code in examples/api/lib/services/keyboard_key/physical_keyboard_key.0.dart ** |
Greg Spencer | 431cfda | 2019-02-08 12:42:34 -0800 | [diff] [blame] | 314 | /// {@end-tool} |
| 315 | /// |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 316 | /// See also: |
| 317 | /// |
| 318 | /// * [RawKeyEvent], the keyboard event object received by widgets that listen |
| 319 | /// to keyboard events. |
Tong Mu | a92f0ef | 2022-05-19 18:38:06 -0700 | [diff] [blame] | 320 | /// * [Focus.onKey], the handler on a widget that lets you handle key events. |
| 321 | /// * [RawKeyboardListener], a widget used to listen to keyboard events (but |
| 322 | /// not handle them). |
Tong Mu | c177db1 | 2020-07-29 13:20:07 -0700 | [diff] [blame] | 323 | @immutable |
Greg Spencer | 387e2b0 | 2019-06-04 11:30:24 -0700 | [diff] [blame] | 324 | class PhysicalKeyboardKey extends KeyboardKey { |
Tong Mu | dbcac7f | 2021-04-01 16:39:02 -0700 | [diff] [blame] | 325 | /// Creates a new PhysicalKeyboardKey object for a USB HID usage. |
| 326 | const PhysicalKeyboardKey(this.usbHidUsage); |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 327 | |
| 328 | /// The unique USB HID usage ID of this physical key on the keyboard. |
| 329 | /// |
| 330 | /// Due to the variations in platform APIs, this may not be the actual HID |
| 331 | /// usage code from the hardware, but a value derived from available |
| 332 | /// information on the platform. |
| 333 | /// |
| 334 | /// See <https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf> |
| 335 | /// for the HID usage values and their meanings. |
| 336 | final int usbHidUsage; |
| 337 | |
| 338 | /// The debug string to print for this keyboard key, which will be null in |
| 339 | /// release mode. |
Tong Mu | dbcac7f | 2021-04-01 16:39:02 -0700 | [diff] [blame] | 340 | String? get debugName { |
| 341 | String? result; |
| 342 | assert(() { |
| 343 | result = _debugNames[usbHidUsage] ?? |
| 344 | 'Key with ID 0x${usbHidUsage.toRadixString(16).padLeft(8, '0')}'; |
| 345 | return true; |
| 346 | }()); |
| 347 | return result; |
| 348 | } |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 349 | |
| 350 | @override |
Tong Mu | a603714 | 2021-03-28 03:54:02 -0700 | [diff] [blame] | 351 | int get hashCode => usbHidUsage.hashCode; |
| 352 | |
| 353 | @override |
| 354 | bool operator ==(Object other) { |
Tong Mu | ddeb0b9 | 2022-06-16 13:53:23 -0700 | [diff] [blame] | 355 | if (identical(this, other)) { |
Tong Mu | dbcac7f | 2021-04-01 16:39:02 -0700 | [diff] [blame] | 356 | return true; |
Tong Mu | ddeb0b9 | 2022-06-16 13:53:23 -0700 | [diff] [blame] | 357 | } |
| 358 | if (other.runtimeType != runtimeType) { |
Tong Mu | a603714 | 2021-03-28 03:54:02 -0700 | [diff] [blame] | 359 | return false; |
Tong Mu | ddeb0b9 | 2022-06-16 13:53:23 -0700 | [diff] [blame] | 360 | } |
Tong Mu | a603714 | 2021-03-28 03:54:02 -0700 | [diff] [blame] | 361 | return other is PhysicalKeyboardKey |
| 362 | && other.usbHidUsage == usbHidUsage; |
| 363 | } |
| 364 | |
Tong Mu | dbcac7f | 2021-04-01 16:39:02 -0700 | [diff] [blame] | 365 | /// Finds a known [PhysicalKeyboardKey] that matches the given USB HID usage |
| 366 | /// code. |
| 367 | static PhysicalKeyboardKey? findKeyByCode(int usageCode) => _knownPhysicalKeys[usageCode]; |
| 368 | |
Tong Mu | a603714 | 2021-03-28 03:54:02 -0700 | [diff] [blame] | 369 | @override |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 370 | void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| 371 | super.debugFillProperties(properties); |
Tong Mu | 32d78ab | 2021-12-01 14:24:04 -0800 | [diff] [blame] | 372 | properties.add(StringProperty('usbHidUsage', '0x${usbHidUsage.toRadixString(16).padLeft(8, '0')}')); |
| 373 | properties.add(StringProperty('debugName', debugName, defaultValue: null)); |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 374 | } |
| 375 | |
| 376 | // Key constants for all keyboard keys in the USB HID specification at the |
| 377 | // time Flutter was built. |
Tong Mu | c8d0b1d | 2021-07-14 13:07:22 -0700 | [diff] [blame] | 378 | |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 379 | @@@PHYSICAL_KEY_DEFINITIONS@@@ |
Tong Mu | c8d0b1d | 2021-07-14 13:07:22 -0700 | [diff] [blame] | 380 | |
Tong Mu | caf876c | 2021-07-29 14:24:03 -0700 | [diff] [blame] | 381 | /// A list of all predefined constant [PhysicalKeyboardKey]s. |
| 382 | static Iterable<PhysicalKeyboardKey> get knownPhysicalKeys => _knownPhysicalKeys.values; |
| 383 | |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 384 | // A list of all the predefined constant PhysicalKeyboardKeys so that they |
| 385 | // can be searched. |
| 386 | static const Map<int, PhysicalKeyboardKey> _knownPhysicalKeys = <int, PhysicalKeyboardKey>{ |
| 387 | @@@PHYSICAL_KEY_MAP@@@ |
| 388 | }; |
Tong Mu | dbcac7f | 2021-04-01 16:39:02 -0700 | [diff] [blame] | 389 | |
| 390 | static const Map<int, String> _debugNames = kReleaseMode ? |
| 391 | <int, String>{} : |
| 392 | <int, String>{ |
Tong Mu | c8d0b1d | 2021-07-14 13:07:22 -0700 | [diff] [blame] | 393 | @@@PHYSICAL_KEY_DEBUG_NAMES@@@ |
| 394 | }; |
Greg Spencer | 2aad593 | 2019-02-06 16:53:16 -0800 | [diff] [blame] | 395 | } |