Skip to content

Commit 515ef91

Browse files
authored
Remove keyLabel and debugName from Logical/PhysicalKeyboardKey (flutter#78263)
- Remove `LogicalKeyboardKey.keyLabel` - Make `Physical/LogicalKeyboardKey.debugName` getters - Make `Physical/LogicalKeyboardKey()` factory constructors, which cache non-predefined instances.
1 parent 2f05751 commit 515ef91

18 files changed

+1499
-810
lines changed

dev/tools/gen_keycodes/bin/gen_keycodes.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import 'package:gen_keycodes/glfw_code_gen.dart';
1818
import 'package:gen_keycodes/gtk_code_gen.dart';
1919
import 'package:gen_keycodes/windows_code_gen.dart';
2020
import 'package:gen_keycodes/web_code_gen.dart';
21+
import 'package:gen_keycodes/key_labels_code_gen.dart';
2122
import 'package:gen_keycodes/keyboard_keys_code_gen.dart';
2223
import 'package:gen_keycodes/keyboard_maps_code_gen.dart';
2324
import 'package:gen_keycodes/key_data.dart';
@@ -253,6 +254,13 @@ Future<void> main(List<String> rawArguments) async {
253254
print('Writing ${'key maps'.padRight(15)}${mapsFile.absolute}');
254255
await mapsFile.writeAsString(KeyboardMapsCodeGenerator(data).generate());
255256

257+
final File keyLabelsFile = File(path.join(flutterRoot.path, 'packages', 'flutter_test', 'lib', 'src', 'key_labels.dart'));
258+
if (!keyLabelsFile.existsSync()) {
259+
mapsFile.createSync(recursive: true);
260+
}
261+
print('Writing ${'key labels'.padRight(15)}${mapsFile.absolute}');
262+
await keyLabelsFile.writeAsString(KeyLabelsCodeGenerator(data).generate());
263+
256264
for (final String platform in <String>['android', 'macos', 'ios', 'glfw', 'fuchsia', 'linux', 'windows', 'web']) {
257265
PlatformCodeGenerator codeGenerator;
258266
switch (platform) {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// DO NOT EDIT -- DO NOT EDIT -- DO NOT EDIT
6+
// This file is generated by dev/tools/gen_keycodes/bin/gen_keycodes.dart and
7+
// should not be edited directly.
8+
//
9+
// Edit the template dev/tools/gen_keycodes/data/key_labels.tmpl instead.
10+
// See dev/tools/gen_keycodes/README.md for more information.
11+
12+
/// The keyLabel corresponding to a logical key.
13+
///
14+
/// Used to generate simulated key events out of a logical key.
15+
const Map<int, String> logicalKeyLabels = <int, String>{
16+
@@@LOGICAL_KEY_LABELS@@@};

dev/tools/gen_keycodes/data/keyboard_key.tmpl

Lines changed: 82 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ abstract class KeyboardKey with Diagnosticable {
7676
/// _message = 'Pressed the "Q" key!';
7777
/// } else {
7878
/// if (kReleaseMode) {
79-
/// _message = 'Not a Q: Key label is "${event.logicalKey.keyLabel}"';
79+
/// _message = 'Not a Q: Pressed 0x${event.logicalKey.keyId.toRadixString(16)}';
8080
/// } else {
81-
/// // This will only print useful information in debug mode.
81+
/// // The debugName will only print useful information in debug mode.
8282
/// _message = 'Not a Q: Pressed ${event.logicalKey.debugName}';
8383
/// }
8484
/// }
@@ -124,59 +124,61 @@ abstract class KeyboardKey with Diagnosticable {
124124
/// keyboard events.
125125
@immutable
126126
class LogicalKeyboardKey extends KeyboardKey {
127-
/// Creates a LogicalKeyboardKey object with an optional key label and debug
128-
/// name.
127+
/// A LogicalKeyboardKey object for a key ID.
129128
///
130-
/// [keyId] must not be null.
131-
///
132-
/// {@tool snippet}
133-
/// To save executable size, it is recommended that the [debugName] be null in
134-
/// release mode. You can do this by using the [kReleaseMode] constant.
135-
///
136-
/// ```dart
137-
/// const LogicalKeyboardKey(0x0010000000a, debugName: kReleaseMode ? null : 'Special Key')
138-
/// ```
139-
/// {@end-tool}
140-
const LogicalKeyboardKey(this.keyId, {this.debugName, this.keyLabel = ''})
141-
: assert(keyId != null);
129+
/// This factory constructor ensures that the same `keyId` always results
130+
/// in the identical instance. It looks up an object from the predefined values
131+
/// if possible, or construct a new one and cache it.
132+
factory LogicalKeyboardKey(int keyId) {
133+
return findKeyByKeyId(keyId) ??
134+
_additionalKeyPool.putIfAbsent(keyId, () => LogicalKeyboardKey._(keyId));
135+
}
136+
137+
/// Creates a LogicalKeyboardKey object for a key ID.
138+
const LogicalKeyboardKey._(this.keyId);
142139

143140
/// A unique code representing this key.
144141
///
145142
/// This is an opaque code. It should not be unpacked to derive information
146143
/// from it, as the representation of the code could change at any time.
147144
final int keyId;
148145

146+
// Returns the bits that are not included in [valueMask], shifted to the
147+
// right.
148+
//
149+
// For example, if the input is 0x12abcdabcd, then the result is 0x12.
150+
//
151+
// This could have been a trivial shifting for non-Web environment, but in
152+
// order to support JavaScript, which only supports bitwise operation of up to
153+
// 32 bits, this function extracts them using division.
154+
//
155+
// It returns 0 for release mode.
156+
static int _debugNonValueBits(int numOf64Bits) {
157+
int result = 0;
158+
assert(() {
159+
const int kDivisorForValueMask = valueMask + 1;
160+
result = (numOf64Bits / kDivisorForValueMask).floor();
161+
return true;
162+
}());
163+
return result;
164+
}
165+
149166
/// The debug string to print for this keyboard key, which will be null in
150167
/// release mode.
151-
final String? debugName;
152-
153-
/// The Unicode string representing the character produced by a [RawKeyEvent].
154-
///
155-
/// This value is useful for describing or matching mnemonic keyboard
156-
/// shortcuts.
157-
///
158-
/// This value is an empty string if there's no key label data for a key.
159-
///
160-
/// On most platforms this is a single code point, but it could contain any
161-
/// Unicode string. The `keyLabel` differs from [RawKeyEvent.character]
162-
/// because `keyLabel` only takes into account the key being pressed, not any
163-
/// combining keys pressed before it, so, for example, an “o” that follows a
164-
/// combining dieresis (“¨”, COMBINING DIAERESIS (U+0308)) would just return
165-
/// “o” for [keyLabel], but would return “ö” for [RawKeyEvent.character].
166-
///
167-
/// {@macro flutter.services.RawKeyEventData.keyLabel}
168-
final String keyLabel;
169-
170-
@override
171-
int get hashCode => keyId.hashCode;
172-
173-
@override
174-
bool operator ==(Object other) {
175-
if (other.runtimeType != runtimeType) {
176-
return false;
177-
}
178-
return other is LogicalKeyboardKey
179-
&& other.keyId == keyId;
168+
String? get debugName {
169+
String? result;
170+
assert(() {
171+
result = _debugNames[keyId];
172+
if (result == null) {
173+
if (_debugNonValueBits(keyId) == 0) {
174+
result = 'Key ${String.fromCharCode(keyId)}';
175+
} else {
176+
result = 'Key with ID 0x${keyId.toRadixString(16).padLeft(11, '0')}';
177+
}
178+
}
179+
return true;
180+
}());
181+
return result;
180182
}
181183

182184
/// Returns the [LogicalKeyboardKey] constant that matches the given ID, or
@@ -261,10 +263,11 @@ class LogicalKeyboardKey extends KeyboardKey {
261263
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
262264
super.debugFillProperties(properties);
263265
properties.add(StringProperty('keyId', '0x${keyId.toRadixString(16).padLeft(8, '0')}', showName: true));
264-
properties.add(StringProperty('keyLabel', keyLabel, showName: true));
265266
properties.add(StringProperty('debugName', debugName, showName: true, defaultValue: null));
266267
}
267268

269+
static final Map<int, LogicalKeyboardKey> _additionalKeyPool = <int, LogicalKeyboardKey>{};
270+
268271
/// Mask for the 32-bit value portion of the key code.
269272
///
270273
/// This is used by platform-specific code to generate Flutter key codes.
@@ -313,6 +316,11 @@ class LogicalKeyboardKey extends KeyboardKey {
313316
// A map of keys to the pseudo-key synonym for that key. Used by getSynonyms.
314317
static final Map<LogicalKeyboardKey, LogicalKeyboardKey> _synonyms = <LogicalKeyboardKey, LogicalKeyboardKey>{
315318
@@@LOGICAL_KEY_SYNONYMS@@@ };
319+
320+
static const Map<int, String> _debugNames = kReleaseMode ?
321+
<int, String>{} :
322+
<int, String>{
323+
@@@LOGICAL_KEY_DEBUG_NAMES@@@ };
316324
}
317325

318326
/// A class with static values that describe the keys that are returned from
@@ -387,7 +395,7 @@ class LogicalKeyboardKey extends KeyboardKey {
387395
/// onTap: () {
388396
/// FocusScope.of(context).requestFocus(_focusNode);
389397
/// },
390-
/// child: Text('Tap to focus'),
398+
/// child: const Text('Tap to focus'),
391399
/// );
392400
/// }
393401
/// return Text(_message ?? 'Press a key');
@@ -408,20 +416,18 @@ class LogicalKeyboardKey extends KeyboardKey {
408416
/// keyboard events.
409417
@immutable
410418
class PhysicalKeyboardKey extends KeyboardKey {
411-
/// Creates a PhysicalKeyboardKey object with an optional debug name.
412-
///
413-
/// The [usbHidUsage] must not be null.
414-
///
415-
/// {@tool snippet}
416-
/// To save executable size, it is recommended that the [debugName] be null in
417-
/// release mode. You can do this using the [kReleaseMode] constant.
419+
/// A PhysicalKeyboardKey object for a USB HID usage.
418420
///
419-
/// ```dart
420-
/// const PhysicalKeyboardKey(0x0000ffff, debugName: kReleaseMode ? null : 'Special Key')
421-
/// ```
422-
/// {@end-tool}
423-
const PhysicalKeyboardKey(this.usbHidUsage, {this.debugName})
424-
: assert(usbHidUsage != null);
421+
/// This factory constructor ensures that the same `usbHidUsage` always results
422+
/// in the identical instance. It looks up an object from the predefined values
423+
/// if possible, or construct a new one and cache it.
424+
factory PhysicalKeyboardKey(int usbHidUsage) {
425+
return findKeyByCode(usbHidUsage) ??
426+
_additionalKeyPool.putIfAbsent(usbHidUsage, () => PhysicalKeyboardKey._(usbHidUsage));
427+
}
428+
429+
/// Creates a PhysicalKeyboardKey object for a USB HID usage.
430+
const PhysicalKeyboardKey._(this.usbHidUsage);
425431

426432
/// The unique USB HID usage ID of this physical key on the keyboard.
427433
///
@@ -435,31 +441,29 @@ class PhysicalKeyboardKey extends KeyboardKey {
435441

436442
/// The debug string to print for this keyboard key, which will be null in
437443
/// release mode.
438-
final String? debugName;
444+
String? get debugName {
445+
String? result;
446+
assert(() {
447+
result = _debugNames[usbHidUsage] ??
448+
'Key with ID 0x${usbHidUsage.toRadixString(16).padLeft(8, '0')}';
449+
return true;
450+
}());
451+
return result;
452+
}
439453

440454
/// Finds a known [PhysicalKeyboardKey] that matches the given USB HID usage
441455
/// code.
442456
static PhysicalKeyboardKey? findKeyByCode(int usageCode) => _knownPhysicalKeys[usageCode];
443457

444-
@override
445-
int get hashCode => usbHidUsage.hashCode;
446-
447-
@override
448-
bool operator ==(Object other) {
449-
if (other.runtimeType != runtimeType) {
450-
return false;
451-
}
452-
return other is PhysicalKeyboardKey
453-
&& other.usbHidUsage == usbHidUsage;
454-
}
455-
456458
@override
457459
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
458460
super.debugFillProperties(properties);
459461
properties.add(StringProperty('usbHidUsage', '0x${usbHidUsage.toRadixString(16).padLeft(8, '0')}', showName: true));
460462
properties.add(StringProperty('debugName', debugName, showName: true, defaultValue: null));
461463
}
462464

465+
static final Map<int, PhysicalKeyboardKey> _additionalKeyPool = <int, PhysicalKeyboardKey>{};
466+
463467
// Key constants for all keyboard keys in the USB HID specification at the
464468
// time Flutter was built.
465469
@@@PHYSICAL_KEY_DEFINITIONS@@@
@@ -468,4 +472,9 @@ class PhysicalKeyboardKey extends KeyboardKey {
468472
static const Map<int, PhysicalKeyboardKey> _knownPhysicalKeys = <int, PhysicalKeyboardKey>{
469473
@@@PHYSICAL_KEY_MAP@@@
470474
};
475+
476+
static const Map<int, String> _debugNames = kReleaseMode ?
477+
<int, String>{} :
478+
<int, String>{
479+
@@@PHYSICAL_KEY_DEBUG_NAMES@@@ };
471480
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:path/path.dart' as path;
6+
7+
import 'base_code_gen.dart';
8+
import 'key_data.dart';
9+
import 'utils.dart';
10+
11+
/// Generates the event_simulation_keylabels.dart based on the information in the
12+
/// key data structure given to it.
13+
class KeyLabelsCodeGenerator extends BaseCodeGenerator {
14+
KeyLabelsCodeGenerator(KeyData keyData) : super(keyData);
15+
16+
/// Gets the generated definitions of logicalKeyLabels.
17+
String get _logicalKeyLabels {
18+
String escapeLabel(String label) => label.contains("'") ? 'r"$label"' : "r'$label'";
19+
final StringBuffer result = StringBuffer();
20+
void printKey(int flutterId, String keyLabel) {
21+
if (keyLabel != null)
22+
result.write('''
23+
${toHex(flutterId, digits: 11)}: ${escapeLabel(keyLabel)},
24+
''');
25+
}
26+
27+
for (final Key entry in keyData.data) {
28+
printKey(entry.flutterId, entry.keyLabel);
29+
}
30+
for (final String name in Key.synonyms.keys) {
31+
// Use the first item in the synonyms as a template for the ID to use.
32+
// It won't end up being the same value because it'll be in the pseudo-key
33+
// plane.
34+
final Key entry = keyData.data.firstWhere((Key item) => item.name == Key.synonyms[name][0]);
35+
printKey(Key.synonymPlane | entry.flutterId, entry.keyLabel);
36+
}
37+
return result.toString();
38+
}
39+
40+
@override
41+
String get templatePath => path.join(flutterRoot.path, 'dev', 'tools', 'gen_keycodes', 'data', 'key_labels.tmpl');
42+
43+
@override
44+
Map<String, String> mappings() {
45+
return <String, String>{
46+
'LOGICAL_KEY_LABELS': _logicalKeyLabels,
47+
};
48+
}
49+
}

0 commit comments

Comments
 (0)