blob: ce8f758e07b2cdbf35e7722d6d1edf23c649da83 [file] [log] [blame]
Ian Hickson449f4a62019-11-27 15:04:02 -08001// Copyright 2014 The Flutter Authors. All rights reserved.
Greg Spencer2aad5932019-02-06 16:53:16 -08002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Greg Spencer041a3ea2020-08-19 15:03:17 -07005import 'package:flutter/foundation.dart';
Tong Muc177db12020-07-29 13:20:07 -07006
Alexandre Ardhuinbbdf6172022-06-28 22:26:06 +02007export 'package:flutter/foundation.dart' show DiagnosticPropertiesBuilder;
8
Greg Spencer2aad5932019-02-06 16:53:16 -08009// 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 Spencer387e2b02019-06-04 11:30:24 -070016/// 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 Magdalenoa0f7f6c2020-04-08 10:07:02 -070024abstract class KeyboardKey with Diagnosticable {
Ian Hickson34198422021-02-17 19:46:04 -080025 /// Abstract const constructor. This constructor enables subclasses to provide
26 /// const constructors so that they can be used in const expressions.
Greg Spencer387e2b02019-06-04 11:30:24 -070027 const KeyboardKey();
28}
29
Greg Spencer2aad5932019-02-06 16:53:16 -080030/// 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 Spencer431cfda2019-02-08 12:42:34 -080040/// 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
nt4f04uNd80a2b6b2021-05-21 03:19:09 +030043/// looking for "the key next to the TAB key", since on a French keyboard,
Greg Spencer431cfda2019-02-08 12:42:34 -080044/// 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 Mu32d78ab2021-12-01 14:24:04 -080051/// {@tool dartpad}
Greg Spencer431cfda2019-02-08 12:42:34 -080052/// This example shows how to detect if the user has selected the logical "Q"
Tong Mua92f0ef2022-05-19 18:38:06 -070053/// key and handle the key if they have.
Greg Spencer431cfda2019-02-08 12:42:34 -080054///
Tong Mu32d78ab2021-12-01 14:24:04 -080055/// ** See code in examples/api/lib/services/keyboard_key/logical_keyboard_key.0.dart **
Greg Spencer431cfda2019-02-08 12:42:34 -080056/// {@end-tool}
Greg Spencer2aad5932019-02-06 16:53:16 -080057/// See also:
58///
59/// * [RawKeyEvent], the keyboard event object received by widgets that listen
60/// to keyboard events.
Tong Mua92f0ef2022-05-19 18:38:06 -070061/// * [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 Muc177db12020-07-29 13:20:07 -070064@immutable
Greg Spencer387e2b02019-06-04 11:30:24 -070065class LogicalKeyboardKey extends KeyboardKey {
Tong Mudbcac7f2021-04-01 16:39:02 -070066 /// Creates a new LogicalKeyboardKey object for a key ID.
67 const LogicalKeyboardKey(this.keyId);
Greg Spencer2aad5932019-02-06 16:53:16 -080068
69 /// A unique code representing this key.
70 ///
Greg Spencer431cfda2019-02-08 12:42:34 -080071 /// 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 Spencer2aad5932019-02-06 16:53:16 -080073 final int keyId;
74
Tong Mudbcac7f2021-04-01 16:39:02 -070075 // 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 Mua6037142021-03-28 03:54:02 -070087
Tong Mudbcac7f2021-04-01 16:39:02 -070088 // Equivalent to assert(divisorForValueMask == (1 << valueMaskWidth)).
Tong Muc5e3e1c2022-04-14 11:24:11 -070089 const int firstDivisorWidth = 28;
Tong Mudbcac7f2021-04-01 16:39:02 -070090 assert(divisorForValueMask ==
Tong Muc5e3e1c2022-04-14 11:24:11 -070091 (1 << firstDivisorWidth) * (1 << (valueMaskWidth - firstDivisorWidth)));
Tong Mudbcac7f2021-04-01 16:39:02 -070092
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 Mub60c8552021-03-26 22:14:01 -0700113 ///
Tong Mudbcac7f2021-04-01 16:39:02 -0700114 /// 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 Mub60c8552021-03-26 22:14:01 -0700117 ///
Tong Mudbcac7f2021-04-01 16:39:02 -0700118 /// 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 Mua6037142021-03-28 03:54:02 -0700123 ///
Tong Mudbcac7f2021-04-01 16:39:02 -0700124 /// 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 Mua6037142021-03-28 03:54:02 -0700130 ///
131 /// {@macro flutter.services.RawKeyEventData.keyLabel}
Tong Mudbcac7f2021-04-01 16:39:02 -0700132 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 Mua6037142021-03-28 03:54:02 -0700165
166 @override
167 int get hashCode => keyId.hashCode;
168
169 @override
170 bool operator ==(Object other) {
Tong Muddeb0b92022-06-16 13:53:23 -0700171 if (identical(this, other)) {
Tong Mudbcac7f2021-04-01 16:39:02 -0700172 return true;
Tong Muddeb0b92022-06-16 13:53:23 -0700173 }
174 if (other.runtimeType != runtimeType) {
Tong Mua6037142021-03-28 03:54:02 -0700175 return false;
Tong Muddeb0b92022-06-16 13:53:23 -0700176 }
Tong Mua6037142021-03-28 03:54:02 -0700177 return other is LogicalKeyboardKey
178 && other.keyId == keyId;
Greg Spencer2aad5932019-02-06 16:53:16 -0800179 }
180
Greg Spencer431cfda2019-02-08 12:42:34 -0800181 /// Returns the [LogicalKeyboardKey] constant that matches the given ID, or
182 /// null, if not found.
Alexandre Ardhuin78844202020-07-31 20:20:00 +0200183 static LogicalKeyboardKey? findKeyByKeyId(int keyId) => _knownLogicalKeys[keyId];
Greg Spencer2aad5932019-02-06 16:53:16 -0800184
Greg Spencer2aad5932019-02-06 16:53:16 -0800185 /// 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 Spencer041a3ea2020-08-19 15:03:17 -0700195 if (label.length != 1) {
Greg Spencer2aad5932019-02-06 16:53:16 -0800196 return false;
197 }
198 final int codeUnit = label.codeUnitAt(0);
199 return (codeUnit <= 0x1f && codeUnit >= 0x00) || (codeUnit >= 0x7f && codeUnit <= 0x9f);
200 }
201
Greg Spencerccdd5052019-02-28 15:37:19 -0800202 /// Returns true if the [keyId] of this object is one that is auto-generated by
Greg Spencer2aad5932019-02-06 16:53:16 -0800203 /// Flutter.
204 ///
Greg Spencerccdd5052019-02-28 15:37:19 -0800205 /// Auto-generated key IDs are generated in response to platform key codes
Greg Spencer2aad5932019-02-06 16:53:16 -0800206 /// which Flutter doesn't recognize, and their IDs shouldn't be used in a
207 /// persistent way.
208 ///
Greg Spencerccdd5052019-02-28 15:37:19 -0800209 /// Auto-generated IDs should be a rare occurrence: Flutter supports most keys.
Greg Spencer2aad5932019-02-06 16:53:16 -0800210 ///
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 Spencerccdd5052019-02-28 15:37:19 -0800220 /// 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 Muc8d0b1d2021-07-14 13:07:22 -0700224 bool get isAutogenerated => (keyId & planeMask) >= startOfPlatformPlanes;
Greg Spencer2aad5932019-02-06 16:53:16 -0800225
Greg Spencera70b0202019-06-03 18:41:04 -0700226 /// 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 Ardhuin78844202020-07-31 20:20:00 +0200240 final LogicalKeyboardKey? result = _synonyms[this];
Greg Spencera70b0202019-06-03 18:41:04 -0700241 return result == null ? <LogicalKeyboardKey>{} : <LogicalKeyboardKey>{result};
242 }
243
Greg Spencerc921c5a2019-11-08 16:30:38 -0800244 /// 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 Ardhuin80618942020-01-31 21:58:51 +0100252 for (final LogicalKeyboardKey key in input) {
Alexandre Ardhuin78844202020-07-31 20:20:00 +0200253 final LogicalKeyboardKey? synonym = _synonyms[key];
Greg Spencerc921c5a2019-11-08 16:30:38 -0800254 result.add(synonym ?? key);
255 }
256 return result;
257 }
258
Greg Spencera70b0202019-06-03 18:41:04 -0700259 @override
260 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
261 super.debugFillProperties(properties);
Tong Mu32d78ab2021-12-01 14:24:04 -0800262 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 Spencera70b0202019-06-03 18:41:04 -0700265 }
266
Tong Muc8d0b1d2021-07-14 13:07:22 -0700267@@@MASK_CONSTANTS@@@
Greg Spencer2aad5932019-02-06 16:53:16 -0800268
Greg Spencer2aad5932019-02-06 16:53:16 -0800269@@@LOGICAL_KEY_DEFINITIONS@@@
Tong Muc8d0b1d2021-07-14 13:07:22 -0700270
Tong Mucaf876c2021-07-29 14:24:03 -0700271 /// A list of all predefined constant [LogicalKeyboardKey]s.
272 static Iterable<LogicalKeyboardKey> get knownLogicalKeys => _knownLogicalKeys.values;
273
Greg Spencer2aad5932019-02-06 16:53:16 -0800274 // A list of all predefined constant LogicalKeyboardKeys so they can be
Greg Spencer431cfda2019-02-08 12:42:34 -0800275 // searched.
Greg Spencer2aad5932019-02-06 16:53:16 -0800276 static const Map<int, LogicalKeyboardKey> _knownLogicalKeys = <int, LogicalKeyboardKey>{
277@@@LOGICAL_KEY_MAP@@@
278 };
Greg Spencera70b0202019-06-03 18:41:04 -0700279
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 Mudbcac7f2021-04-01 16:39:02 -0700283
284 static const Map<int, String> _keyLabels = <int, String>{
Tong Muc8d0b1d2021-07-14 13:07:22 -0700285@@@LOGICAL_KEY_KEY_LABELS@@@
286 };
Greg Spencer2aad5932019-02-06 16:53:16 -0800287}
288
289/// A class with static values that describe the keys that are returned from
290/// [RawKeyEvent.physicalKey].
291///
Greg Spencer431cfda2019-02-08 12:42:34 -0800292/// 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 Spencer2aad5932019-02-06 16:53:16 -0800295/// [LogicalKeyboardKey], which represents a logical key interpreted in the
296/// context of modifiers, modes, and/or keyboard layouts.
297///
Greg Spencer431cfda2019-02-08 12:42:34 -0800298/// 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
nt4f04uNd80a2b6b2021-05-21 03:19:09 +0300306/// looking for "the key next to the TAB key", since on a French keyboard,
Greg Spencer431cfda2019-02-08 12:42:34 -0800307/// the key next to the TAB key has an "A" on it.
308///
Tong Mu32d78ab2021-12-01 14:24:04 -0800309/// {@tool dartpad}
Greg Spencer431cfda2019-02-08 12:42:34 -0800310/// 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 Mu32d78ab2021-12-01 14:24:04 -0800313/// ** See code in examples/api/lib/services/keyboard_key/physical_keyboard_key.0.dart **
Greg Spencer431cfda2019-02-08 12:42:34 -0800314/// {@end-tool}
315///
Greg Spencer2aad5932019-02-06 16:53:16 -0800316/// See also:
317///
318/// * [RawKeyEvent], the keyboard event object received by widgets that listen
319/// to keyboard events.
Tong Mua92f0ef2022-05-19 18:38:06 -0700320/// * [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 Muc177db12020-07-29 13:20:07 -0700323@immutable
Greg Spencer387e2b02019-06-04 11:30:24 -0700324class PhysicalKeyboardKey extends KeyboardKey {
Tong Mudbcac7f2021-04-01 16:39:02 -0700325 /// Creates a new PhysicalKeyboardKey object for a USB HID usage.
326 const PhysicalKeyboardKey(this.usbHidUsage);
Greg Spencer2aad5932019-02-06 16:53:16 -0800327
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 Mudbcac7f2021-04-01 16:39:02 -0700340 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 Spencer2aad5932019-02-06 16:53:16 -0800349
350 @override
Tong Mua6037142021-03-28 03:54:02 -0700351 int get hashCode => usbHidUsage.hashCode;
352
353 @override
354 bool operator ==(Object other) {
Tong Muddeb0b92022-06-16 13:53:23 -0700355 if (identical(this, other)) {
Tong Mudbcac7f2021-04-01 16:39:02 -0700356 return true;
Tong Muddeb0b92022-06-16 13:53:23 -0700357 }
358 if (other.runtimeType != runtimeType) {
Tong Mua6037142021-03-28 03:54:02 -0700359 return false;
Tong Muddeb0b92022-06-16 13:53:23 -0700360 }
Tong Mua6037142021-03-28 03:54:02 -0700361 return other is PhysicalKeyboardKey
362 && other.usbHidUsage == usbHidUsage;
363 }
364
Tong Mudbcac7f2021-04-01 16:39:02 -0700365 /// Finds a known [PhysicalKeyboardKey] that matches the given USB HID usage
366 /// code.
367 static PhysicalKeyboardKey? findKeyByCode(int usageCode) => _knownPhysicalKeys[usageCode];
368
Tong Mua6037142021-03-28 03:54:02 -0700369 @override
Greg Spencer2aad5932019-02-06 16:53:16 -0800370 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
371 super.debugFillProperties(properties);
Tong Mu32d78ab2021-12-01 14:24:04 -0800372 properties.add(StringProperty('usbHidUsage', '0x${usbHidUsage.toRadixString(16).padLeft(8, '0')}'));
373 properties.add(StringProperty('debugName', debugName, defaultValue: null));
Greg Spencer2aad5932019-02-06 16:53:16 -0800374 }
375
376 // Key constants for all keyboard keys in the USB HID specification at the
377 // time Flutter was built.
Tong Muc8d0b1d2021-07-14 13:07:22 -0700378
Greg Spencer2aad5932019-02-06 16:53:16 -0800379@@@PHYSICAL_KEY_DEFINITIONS@@@
Tong Muc8d0b1d2021-07-14 13:07:22 -0700380
Tong Mucaf876c2021-07-29 14:24:03 -0700381 /// A list of all predefined constant [PhysicalKeyboardKey]s.
382 static Iterable<PhysicalKeyboardKey> get knownPhysicalKeys => _knownPhysicalKeys.values;
383
Greg Spencer2aad5932019-02-06 16:53:16 -0800384 // 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 Mudbcac7f2021-04-01 16:39:02 -0700389
390 static const Map<int, String> _debugNames = kReleaseMode ?
391 <int, String>{} :
392 <int, String>{
Tong Muc8d0b1d2021-07-14 13:07:22 -0700393@@@PHYSICAL_KEY_DEBUG_NAMES@@@
394 };
Greg Spencer2aad5932019-02-06 16:53:16 -0800395}