Unverified Commit 0ac05f1c authored by Tong Mu's avatar Tong Mu Committed by GitHub

[Keyboard, Web] Map from "Esc" to the Escape key (#106133)

* Impl

* Fix build

* Add test
parent df55dbb9
...@@ -1552,7 +1552,8 @@ ...@@ -1552,7 +1552,8 @@
"value": 4294967323, "value": 4294967323,
"names": { "names": {
"web": [ "web": [
"Escape" "Escape",
"Esc"
], ],
"macos": [ "macos": [
"Escape" "Escape"
......
...@@ -1192,6 +1192,9 @@ ...@@ -1192,6 +1192,9 @@
"name": "Escape", "name": "Escape",
"chromium": "Escape" "chromium": "Escape"
}, },
"otherWebCodes": [
"Esc"
],
"scanCodes": { "scanCodes": {
"android": [ "android": [
1 1
......
...@@ -50,6 +50,11 @@ ...@@ -50,6 +50,11 @@
DOM_CODE(0x05ff1e, 0x0000, 0x0000, 0x0000, 0xffff, "GameButtonY", BUTTON_Y), DOM_CODE(0x05ff1e, 0x0000, 0x0000, 0x0000, 0xffff, "GameButtonY", BUTTON_Y),
DOM_CODE(0x05ff1f, 0x0000, 0x0000, 0x0000, 0xffff, "GameButtonZ", BUTTON_Z), DOM_CODE(0x05ff1f, 0x0000, 0x0000, 0x0000, 0xffff, "GameButtonZ", BUTTON_Z),
// Sometimes the Escape key produces "Esc" instead of "Escape". This includes
// older IE and Firefox browsers, and the current Cobalt browser.
// See: https://github.com/flutter/flutter/issues/106062
DOM_CODE(0x070029, 0x0000, 0x0000, 0x0000, 0xffff, "Esc", ESCAPE),
// ============================================================ // ============================================================
// Fn key for Mac // Fn key for Mac
// ============================================================ // ============================================================
...@@ -58,4 +63,4 @@ ...@@ -58,4 +63,4 @@
// defined on other platforms. Chromium does define an "Fn" row, but doesn't // defined on other platforms. Chromium does define an "Fn" row, but doesn't
// give it a Mac keycode. This overrides their definition. // give it a Mac keycode. This overrides their definition.
// USB HID evdev XKB Win Mac DOMKey Code // USB HID evdev XKB Win Mac DOMKey Code
DOM_CODE(0x000012, 0x0000, 0x0000, 0x0000, 0x003f, "Fn", FN), DOM_CODE(0x000012, 0x0000, 0x0000, 0x0000, 0x003f, "Fn", FN),
...@@ -76,6 +76,16 @@ ...@@ -76,6 +76,16 @@
DOM_KEY_UNI("Tilde", TILDE, '~'), DOM_KEY_UNI("Tilde", TILDE, '~'),
DOM_KEY_UNI("Bar", BAR, '|'), DOM_KEY_UNI("Bar", BAR, '|'),
// ============================================================
// Unprintable keys (Unicode plane)
// ============================================================
// Key Enum Value
// Sometimes the Escape key produces "Esc" instead of "Escape". This includes
// older IE and Firefox browsers, and the current Cobalt browser.
// See: https://github.com/flutter/flutter/issues/106062
DOM_KEY_MAP("Esc", ESC, 0x1B),
// The following keys reside in the Flutter plane (0x0100000000). // The following keys reside in the Flutter plane (0x0100000000).
// ============================================================ // ============================================================
......
...@@ -78,7 +78,7 @@ $otherComments static const PhysicalKeyboardKey ${entry.constantName} = Physica ...@@ -78,7 +78,7 @@ $otherComments static const PhysicalKeyboardKey ${entry.constantName} = Physica
/// Gets the generated definitions of LogicalKeyboardKeys. /// Gets the generated definitions of LogicalKeyboardKeys.
String get _logicalDefinitions { String get _logicalDefinitions {
final OutputLines<int> lines = OutputLines<int>('Logical debug names'); final OutputLines<int> lines = OutputLines<int>('Logical debug names', behavior: DeduplicateBehavior.kSkip);
void printKey(int flutterId, String constantName, String commentName, {String? otherComments}) { void printKey(int flutterId, String constantName, String commentName, {String? otherComments}) {
final String firstComment = _wrapString('Represents the logical "$commentName" key on the keyboard.'); final String firstComment = _wrapString('Represents the logical "$commentName" key on the keyboard.');
otherComments ??= _wrapString('See the function [RawKeyEvent.logicalKey] for more information.'); otherComments ??= _wrapString('See the function [RawKeyEvent.logicalKey] for more information.');
...@@ -122,7 +122,7 @@ $otherComments static const LogicalKeyboardKey $constantName = LogicalKeyboardK ...@@ -122,7 +122,7 @@ $otherComments static const LogicalKeyboardKey $constantName = LogicalKeyboardK
} }
String get _logicalKeyLabels { String get _logicalKeyLabels {
final OutputLines<int> lines = OutputLines<int>('Logical key labels'); final OutputLines<int> lines = OutputLines<int>('Logical key labels', behavior: DeduplicateBehavior.kSkip);
for (final LogicalKeyEntry entry in logicalData.entries) { for (final LogicalKeyEntry entry in logicalData.entries) {
lines.add(entry.value, ''' lines.add(entry.value, '''
${toHex(entry.value, digits: 11)}: '${entry.commentName}','''); ${toHex(entry.value, digits: 11)}: '${entry.commentName}',''');
...@@ -141,7 +141,7 @@ $otherComments static const LogicalKeyboardKey $constantName = LogicalKeyboardK ...@@ -141,7 +141,7 @@ $otherComments static const LogicalKeyboardKey $constantName = LogicalKeyboardK
/// This generates the map of Flutter key codes to logical keys. /// This generates the map of Flutter key codes to logical keys.
String get _predefinedKeyCodeMap { String get _predefinedKeyCodeMap {
final OutputLines<int> lines = OutputLines<int>('Logical key map'); final OutputLines<int> lines = OutputLines<int>('Logical key map', behavior: DeduplicateBehavior.kSkip);
for (final LogicalKeyEntry entry in logicalData.entries) { for (final LogicalKeyEntry entry in logicalData.entries) {
lines.add(entry.value, ' ${toHex(entry.value, digits: 11)}: ${entry.constantName},'); lines.add(entry.value, ' ${toHex(entry.value, digits: 11)}: ${entry.constantName},');
} }
...@@ -149,7 +149,7 @@ $otherComments static const LogicalKeyboardKey $constantName = LogicalKeyboardK ...@@ -149,7 +149,7 @@ $otherComments static const LogicalKeyboardKey $constantName = LogicalKeyboardK
} }
String get _maskConstantVariables { String get _maskConstantVariables {
final OutputLines<int> lines = OutputLines<int>('Mask constants', checkDuplicate: false); final OutputLines<int> lines = OutputLines<int>('Mask constants', behavior: DeduplicateBehavior.kKeep);
for (final MaskConstant constant in _maskConstants) { for (final MaskConstant constant in _maskConstants) {
lines.add(constant.value, ''' lines.add(constant.value, '''
${_wrapString(constant.description)} /// ${_wrapString(constant.description)} ///
......
...@@ -303,7 +303,7 @@ class KeyboardMapsCodeGenerator extends BaseCodeGenerator { ...@@ -303,7 +303,7 @@ class KeyboardMapsCodeGenerator extends BaseCodeGenerator {
/// This generates the map of Web KeyboardEvent codes to physical keys. /// This generates the map of Web KeyboardEvent codes to physical keys.
String get _webPhysicalKeyMap { String get _webPhysicalKeyMap {
final OutputLines<String> lines = OutputLines<String>('Web physical key map'); final OutputLines<String> lines = OutputLines<String>('Web physical key map', behavior: DeduplicateBehavior.kKeep);
for (final PhysicalKeyEntry entry in keyData.entries) { for (final PhysicalKeyEntry entry in keyData.entries) {
for (final String webCodes in entry.webCodes()) { for (final String webCodes in entry.webCodes()) {
lines.add(entry.name, " '$webCodes': PhysicalKeyboardKey.${entry.constantName},"); lines.add(entry.name, " '$webCodes': PhysicalKeyboardKey.${entry.constantName},");
......
...@@ -53,8 +53,7 @@ class LogicalKeyData { ...@@ -53,8 +53,7 @@ class LogicalKeyData {
String glfwNameMap, String glfwNameMap,
PhysicalKeyData physicalKeyData, PhysicalKeyData physicalKeyData,
) { ) {
final Map<String, LogicalKeyEntry> data = <String, LogicalKeyEntry>{}; final Map<String, LogicalKeyEntry> data = _readKeyEntries(chromiumKeys);
_readKeyEntries(data, chromiumKeys);
_readWindowsKeyCodes(data, windowsKeyCodeHeader, parseMapOfListOfString(windowsNameMap)); _readWindowsKeyCodes(data, windowsKeyCodeHeader, parseMapOfListOfString(windowsNameMap));
_readGtkKeyCodes(data, gtkKeyCodeHeader, parseMapOfListOfString(gtkNameMap)); _readGtkKeyCodes(data, gtkKeyCodeHeader, parseMapOfListOfString(gtkNameMap));
_readAndroidKeyCodes(data, androidKeyCodeHeader, parseMapOfListOfString(androidNameMap)); _readAndroidKeyCodes(data, androidKeyCodeHeader, parseMapOfListOfString(androidNameMap));
...@@ -130,7 +129,8 @@ class LogicalKeyData { ...@@ -130,7 +129,8 @@ class LogicalKeyData {
/// The following format should be mapped to the Flutter plane. /// The following format should be mapped to the Flutter plane.
/// Key Enum Character /// Key Enum Character
/// FLUTTER_KEY_MAP("Lang4", LANG4, 0x00013), /// FLUTTER_KEY_MAP("Lang4", LANG4, 0x00013),
static void _readKeyEntries(Map<String, LogicalKeyEntry> data, String input) { static Map<String, LogicalKeyEntry> _readKeyEntries(String input) {
final Map<int, LogicalKeyEntry> dataByValue = <int, LogicalKeyEntry>{};
final RegExp domKeyRegExp = RegExp( final RegExp domKeyRegExp = RegExp(
r'(?<source>DOM|FLUTTER)_KEY_(?<kind>UNI|MAP)\s*\(\s*' r'(?<source>DOM|FLUTTER)_KEY_(?<kind>UNI|MAP)\s*\(\s*'
r'"(?<name>[^\s]+?)",\s*' r'"(?<name>[^\s]+?)",\s*'
...@@ -162,17 +162,23 @@ class LogicalKeyData { ...@@ -162,17 +162,23 @@ class LogicalKeyData {
} }
final bool isPrintable = keyLabel != null; final bool isPrintable = keyLabel != null;
data.putIfAbsent(name, () { final int entryValue = toPlane(value, _sourceToPlane(source, isPrintable));
final LogicalKeyEntry entry = LogicalKeyEntry.fromName( final LogicalKeyEntry entry = dataByValue.putIfAbsent(entryValue, () =>
value: toPlane(value, _sourceToPlane(source, isPrintable)), LogicalKeyEntry.fromName(
value: entryValue,
name: name, name: name,
keyLabel: keyLabel, keyLabel: keyLabel,
); ),
if (source == 'DOM' && !isPrintable) );
entry.webNames.add(webName); if (source == 'DOM' && !isPrintable) {
return entry; entry.webNames.add(webName);
}); }
} }
return Map<String, LogicalKeyEntry>.fromEntries(
dataByValue.values.map((LogicalKeyEntry entry) =>
MapEntry<String, LogicalKeyEntry>(entry.name, entry),
),
);
} }
static void _readMacOsKeyCodes( static void _readMacOsKeyCodes(
......
...@@ -171,6 +171,22 @@ class PhysicalKeyData { ...@@ -171,6 +171,22 @@ class PhysicalKeyData {
// Skip key that is not actually generated by any keyboard. // Skip key that is not actually generated by any keyboard.
continue; continue;
} }
final PhysicalKeyEntry? existing = entries[usbHidCode];
// Allow duplicate entries for Fn, which overwrites.
if (existing != null && existing.name != 'Fn') {
// If it's an existing entry, the only thing we currently support is
// to insert an extra DOMKey. The other entries must be empty.
assert(evdevCode == 0
&& xKbScanCode == 0
&& windowsScanCode == 0
&& macScanCode == 0xffff
&& chromiumCode != null
&& chromiumCode.isNotEmpty,
'Duplicate usbHidCode ${existing.usbHidCode} of key ${existing.name} '
'conflicts with existing ${entries[existing.usbHidCode]!.name}.');
existing.otherWebCodes.add(chromiumCode!);
continue;
}
final PhysicalKeyEntry newEntry = PhysicalKeyEntry( final PhysicalKeyEntry newEntry = PhysicalKeyEntry(
usbHidCode: usbHidCode, usbHidCode: usbHidCode,
androidScanCodes: nameToAndroidScanCodes[name] ?? <int>[], androidScanCodes: nameToAndroidScanCodes[name] ?? <int>[],
...@@ -182,15 +198,6 @@ class PhysicalKeyData { ...@@ -182,15 +198,6 @@ class PhysicalKeyData {
name: name, name: name,
chromiumCode: chromiumCode, chromiumCode: chromiumCode,
); );
// Remove duplicates: last one wins, so that supplemental codes
// override.
if (entries.containsKey(newEntry.usbHidCode)) {
// This is expected for Fn. Warn for other keys.
if (newEntry.name != 'Fn') {
print('Duplicate usbHidCode ${newEntry.usbHidCode} of key ${newEntry.name} '
'conflicts with existing ${entries[newEntry.usbHidCode]!.name}. Keeping the new one.');
}
}
entries[newEntry.usbHidCode] = newEntry; entries[newEntry.usbHidCode] = newEntry;
} }
return entries.map((int code, PhysicalKeyEntry entry) => return entries.map((int code, PhysicalKeyEntry entry) =>
...@@ -216,7 +223,8 @@ class PhysicalKeyEntry { ...@@ -216,7 +223,8 @@ class PhysicalKeyEntry {
required this.macOSScanCode, required this.macOSScanCode,
required this.iOSScanCode, required this.iOSScanCode,
required this.chromiumCode, required this.chromiumCode,
}); List<String>? otherWebCodes,
}) : otherWebCodes = otherWebCodes ?? <String>[];
/// Populates the key from a JSON map. /// Populates the key from a JSON map.
factory PhysicalKeyEntry.fromJsonMapEntry(Map<String, dynamic> map) { factory PhysicalKeyEntry.fromJsonMapEntry(Map<String, dynamic> map) {
...@@ -232,6 +240,7 @@ class PhysicalKeyEntry { ...@@ -232,6 +240,7 @@ class PhysicalKeyEntry {
windowsScanCode: scanCodes['windows'] as int?, windowsScanCode: scanCodes['windows'] as int?,
macOSScanCode: scanCodes['macos'] as int?, macOSScanCode: scanCodes['macos'] as int?,
iOSScanCode: scanCodes['ios'] as int?, iOSScanCode: scanCodes['ios'] as int?,
otherWebCodes: (map['otherWebCodes'] as List<dynamic>?)?.cast<String>(),
); );
} }
...@@ -258,11 +267,14 @@ class PhysicalKeyEntry { ...@@ -258,11 +267,14 @@ class PhysicalKeyEntry {
final String name; final String name;
/// The Chromium event code for the key. /// The Chromium event code for the key.
final String? chromiumCode; final String? chromiumCode;
/// Other codes used by Web besides chromiumCode.
final List<String> otherWebCodes;
Iterable<String> webCodes() sync* { Iterable<String> webCodes() sync* {
if (chromiumCode != null) { if (chromiumCode != null) {
yield chromiumCode!; yield chromiumCode!;
} }
yield* otherWebCodes;
} }
/// Creates a JSON map from the key data. /// Creates a JSON map from the key data.
...@@ -272,6 +284,7 @@ class PhysicalKeyEntry { ...@@ -272,6 +284,7 @@ class PhysicalKeyEntry {
'name': name, 'name': name,
'chromium': chromiumCode, 'chromium': chromiumCode,
}, },
'otherWebCodes': otherWebCodes,
'scanCodes': <String, dynamic>{ 'scanCodes': <String, dynamic>{
'android': androidScanCodes, 'android': androidScanCodes,
'usb': usbHidCode, 'usb': usbHidCode,
...@@ -323,11 +336,14 @@ class PhysicalKeyEntry { ...@@ -323,11 +336,14 @@ class PhysicalKeyEntry {
@override @override
String toString() { String toString() {
final String otherWebStr = otherWebCodes.isEmpty
? ''
: ', otherWebCodes: [${otherWebCodes.join(', ')}]';
return """'$constantName': (name: "$name", usbHidCode: ${toHex(usbHidCode)}, """ return """'$constantName': (name: "$name", usbHidCode: ${toHex(usbHidCode)}, """
'linuxScanCode: ${toHex(evdevCode)}, xKbScanCode: ${toHex(xKbScanCode)}, ' 'linuxScanCode: ${toHex(evdevCode)}, xKbScanCode: ${toHex(xKbScanCode)}, '
'windowsKeyCode: ${toHex(windowsScanCode)}, macOSScanCode: ${toHex(macOSScanCode)}, ' 'windowsKeyCode: ${toHex(windowsScanCode)}, macOSScanCode: ${toHex(macOSScanCode)}, '
'windowsScanCode: ${toHex(windowsScanCode)}, chromiumSymbolName: $chromiumCode ' 'windowsScanCode: ${toHex(windowsScanCode)}, chromiumSymbolName: $chromiumCode '
'iOSScanCode: ${toHex(iOSScanCode)})'; 'iOSScanCode: ${toHex(iOSScanCode)})$otherWebStr';
} }
static int compareByUsbHidCode(PhysicalKeyEntry a, PhysicalKeyEntry b) => static int compareByUsbHidCode(PhysicalKeyEntry a, PhysicalKeyEntry b) =>
......
...@@ -30,7 +30,7 @@ constexpr uint64_t kPhysical${_toUpperCammel(entry.constantName)} = ${toHex(entr ...@@ -30,7 +30,7 @@ constexpr uint64_t kPhysical${_toUpperCammel(entry.constantName)} = ${toHex(entr
/// Gets the generated definitions of PhysicalKeyboardKeys. /// Gets the generated definitions of PhysicalKeyboardKeys.
String get _logicalDefinitions { String get _logicalDefinitions {
final OutputLines<int> lines = OutputLines<int>('Logical Key list'); final OutputLines<int> lines = OutputLines<int>('Logical Key list', behavior: DeduplicateBehavior.kSkip);
for (final LogicalKeyEntry entry in logicalData.entries) { for (final LogicalKeyEntry entry in logicalData.entries) {
lines.add(entry.value, ''' lines.add(entry.value, '''
constexpr uint64_t kLogical${_toUpperCammel(entry.constantName)} = ${toHex(entry.value, digits: 11)};'''); constexpr uint64_t kLogical${_toUpperCammel(entry.constantName)} = ${toHex(entry.value, digits: 11)};''');
......
...@@ -42,7 +42,7 @@ class KeyCodesJavaGenerator extends BaseCodeGenerator { ...@@ -42,7 +42,7 @@ class KeyCodesJavaGenerator extends BaseCodeGenerator {
/// Gets the generated definitions of PhysicalKeyboardKeys. /// Gets the generated definitions of PhysicalKeyboardKeys.
String get _logicalDefinitions { String get _logicalDefinitions {
final OutputLines<int> lines = OutputLines<int>('Logical Key list'); final OutputLines<int> lines = OutputLines<int>('Logical Key list', behavior: DeduplicateBehavior.kSkip);
for (final LogicalKeyEntry entry in logicalData.entries) { for (final LogicalKeyEntry entry in logicalData.entries) {
lines.add(entry.value, ''' lines.add(entry.value, '''
public static final long LOGICAL_${_toUpperSnake(entry.constantName)} = ${toHex(entry.value, digits: 11)}L;'''); public static final long LOGICAL_${_toUpperSnake(entry.constantName)} = ${toHex(entry.value, digits: 11)}L;''');
......
...@@ -233,12 +233,24 @@ void addNameValue(List<String> names, List<int> values, String name, int value) ...@@ -233,12 +233,24 @@ void addNameValue(List<String> names, List<int> values, String name, int value)
} }
} }
enum DeduplicateBehavior {
// Warn the duplicate entry.
kWarn,
// Skip the latter duplicate entry.
kSkip,
// Keep all duplicate entries.
kKeep,
}
/// The information for a line used by [OutputLines]. /// The information for a line used by [OutputLines].
class OutputLine<T extends Comparable<Object>> { class OutputLine<T extends Comparable<Object>> {
const OutputLine(this.key, this.value); OutputLine(this.key, String value)
: values = <String>[value];
final T key; final T key;
final String value; final List<String> values;
} }
/// A utility class to build join a number of lines in a sorted order. /// A utility class to build join a number of lines in a sorted order.
...@@ -247,41 +259,43 @@ class OutputLine<T extends Comparable<Object>> { ...@@ -247,41 +259,43 @@ class OutputLine<T extends Comparable<Object>> {
/// get the joined string of these lines joined sorting them in the order of the /// get the joined string of these lines joined sorting them in the order of the
/// index. /// index.
class OutputLines<T extends Comparable<Object>> { class OutputLines<T extends Comparable<Object>> {
OutputLines(this.mapName, {this.checkDuplicate = true}); OutputLines(this.mapName, {this.behavior = DeduplicateBehavior.kWarn});
/// If true, then lines with duplicate keys will be warned and discarded. /// What to do if there are entries with the same key.
/// final DeduplicateBehavior behavior;
/// Default to true.
final bool checkDuplicate;
/// The name for this map. /// The name for this map.
/// ///
/// Used in warning messages. /// Used in warning messages.
final String mapName; final String mapName;
final Set<T> keys = <T>{}; final Map<T, OutputLine<T>> lines = <T, OutputLine<T>>{};
final List<OutputLine<T>> lines = <OutputLine<T>>[];
void add(T code, String line) { void add(T key, String line) {
if (checkDuplicate) { final OutputLine<T>? existing = lines[key];
if (keys.contains(code)) { if (existing != null) {
final OutputLine<T> existing = lines.firstWhere((OutputLine<T> line) => line.key == code); switch (behavior) {
print('Warn: $mapName is requested to add line $code as:\n $line\n but it already exists as:\n ${existing.value}'); case DeduplicateBehavior.kWarn:
return; print('Warn: Request to add $key to map "$mapName" as:\n $line\n but it already exists as:\n ${existing.values[0]}');
return;
case DeduplicateBehavior.kSkip:
return;
case DeduplicateBehavior.kKeep:
existing.values.add(line);
return;
} }
keys.add(code);
} }
lines.add(OutputLine<T>(code, line)); lines[key] = OutputLine<T>(key, line);
} }
String join() { String join() {
return lines.map((OutputLine<T> line) => line.value).join('\n'); return lines.values.map((OutputLine<T> line) => line.values.join('\n')).join('\n');
} }
String sortedJoin() { String sortedJoin() {
return (lines.sublist(0) return (lines.values.toList()
..sort((OutputLine<T> a, OutputLine<T> b) => a.key.compareTo(b.key))) ..sort((OutputLine<T> a, OutputLine<T> b) => a.key.compareTo(b.key)))
.map((OutputLine<T> line) => line.value) .map((OutputLine<T> line) => line.values.join('\n'))
.join('\n'); .join('\n');
} }
} }
......
...@@ -2211,6 +2211,7 @@ const Map<String, LogicalKeyboardKey> kWebToLogicalKey = <String, LogicalKeyboar ...@@ -2211,6 +2211,7 @@ const Map<String, LogicalKeyboardKey> kWebToLogicalKey = <String, LogicalKeyboar
'EndCall': LogicalKeyboardKey.endCall, 'EndCall': LogicalKeyboardKey.endCall,
'Enter': LogicalKeyboardKey.enter, 'Enter': LogicalKeyboardKey.enter,
'EraseEof': LogicalKeyboardKey.eraseEof, 'EraseEof': LogicalKeyboardKey.eraseEof,
'Esc': LogicalKeyboardKey.escape,
'Escape': LogicalKeyboardKey.escape, 'Escape': LogicalKeyboardKey.escape,
'ExSel': LogicalKeyboardKey.exSel, 'ExSel': LogicalKeyboardKey.exSel,
'Execute': LogicalKeyboardKey.execute, 'Execute': LogicalKeyboardKey.execute,
...@@ -2495,6 +2496,7 @@ const Map<String, PhysicalKeyboardKey> kWebToPhysicalKey = <String, PhysicalKeyb ...@@ -2495,6 +2496,7 @@ const Map<String, PhysicalKeyboardKey> kWebToPhysicalKey = <String, PhysicalKeyb
'Enter': PhysicalKeyboardKey.enter, 'Enter': PhysicalKeyboardKey.enter,
'Equal': PhysicalKeyboardKey.equal, 'Equal': PhysicalKeyboardKey.equal,
'Escape': PhysicalKeyboardKey.escape, 'Escape': PhysicalKeyboardKey.escape,
'Esc': PhysicalKeyboardKey.escape,
'F1': PhysicalKeyboardKey.f1, 'F1': PhysicalKeyboardKey.f1,
'F10': PhysicalKeyboardKey.f10, 'F10': PhysicalKeyboardKey.f10,
'F11': PhysicalKeyboardKey.f11, 'F11': PhysicalKeyboardKey.f11,
......
...@@ -2680,6 +2680,23 @@ void main() { ...@@ -2680,6 +2680,23 @@ void main() {
expect(data.keyCode, equals(0x10)); expect(data.keyCode, equals(0x10));
}); });
test('Esc keys generated by older browsers are correctly translated', () {
final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const <String, Object?>{
'type': 'keydown',
'keymap': 'web',
'code': 'Esc',
'key': 'Esc',
'location': 0,
'metaState': 0x0,
'keyCode': 0x1B,
});
final RawKeyEventDataWeb data = escapeKeyEvent.data as RawKeyEventDataWeb;
expect(data.physicalKey, equals(PhysicalKeyboardKey.escape));
expect(data.logicalKey, equals(LogicalKeyboardKey.escape));
expect(data.keyLabel, isEmpty);
expect(data.keyCode, equals(0x1B));
});
test('Arrow keys from a keyboard give correct physical key mappings', () { test('Arrow keys from a keyboard give correct physical key mappings', () {
final RawKeyEvent arrowKeyDown = RawKeyEvent.fromMessage(const <String, Object?>{ final RawKeyEvent arrowKeyDown = RawKeyEvent.fromMessage(const <String, Object?>{
'type': 'keydown', 'type': 'keydown',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment