[Keyboard, iOS] Generate iOS's special key mapping (#106909)

diff --git a/dev/tools/gen_keycodes/data/ios_key_code_map_mm.tmpl b/dev/tools/gen_keycodes/data/ios_key_code_map_mm.tmpl
index 9cecd01..da621f4 100644
--- a/dev/tools/gen_keycodes/data/ios_key_code_map_mm.tmpl
+++ b/dev/tools/gen_keycodes/data/ios_key_code_map_mm.tmpl
@@ -48,4 +48,9 @@
 @@@IOS_FUNCTION_KEY_SET@@@
 };
 
+API_AVAILABLE(ios(13.4))
+NSDictionary<NSString*, NSNumber*>* specialKeyMapping = [[NSDictionary alloc] initWithDictionary:@{
+@@@SPECIAL_KEY_MAPPING@@@
+}];
+
 @@@SPECIAL_KEY_CONSTANTS@@@
diff --git a/dev/tools/gen_keycodes/data/keyboard_maps.tmpl b/dev/tools/gen_keycodes/data/keyboard_maps.tmpl
index 36e4c02..7129959 100644
--- a/dev/tools/gen_keycodes/data/keyboard_maps.tmpl
+++ b/dev/tools/gen_keycodes/data/keyboard_maps.tmpl
@@ -78,6 +78,15 @@
 @@@IOS_SCAN_CODE_MAP@@@
 };
 
+/// Maps iOS specific string values of nonvisible keys to logical keys
+///
+/// Some unprintable keys on iOS has literal names on their key label, such as
+/// "UIKeyInputEscape". See:
+/// https://developer.apple.com/documentation/uikit/uikeycommand/input_strings_for_special_keys?language=objc
+const Map<String, LogicalKeyboardKey> kIosSpecialLogicalMap = <String, LogicalKeyboardKey>{
+@@@IOS_SPECIAL_MAP@@@
+};
+
 /// A map of iOS key codes which have printable representations, but appear
 /// on the number pad. Used to provide different key objects for keys like
 /// KEY_EQUALS and NUMPAD_EQUALS.
diff --git a/dev/tools/gen_keycodes/lib/data.dart b/dev/tools/gen_keycodes/lib/data.dart
new file mode 100644
index 0000000..faaf12b
--- /dev/null
+++ b/dev/tools/gen_keycodes/lib/data.dart
@@ -0,0 +1,30 @@
+// 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.
+
+/// Maps iOS's special key labels to logical key names.
+///
+/// See https://developer.apple.com/documentation/uikit/uikeycommand/input_strings_for_special_keys?language=objc
+const Map<String, String> kIosSpecialKeyMapping = <String, String>{
+  'UIKeyInputEscape': 'Escape',
+  'UIKeyInputF1': 'F1',
+  'UIKeyInputF2': 'F2',
+  'UIKeyInputF3': 'F3',
+  'UIKeyInputF4': 'F4',
+  'UIKeyInputF5': 'F5',
+  'UIKeyInputF6': 'F6',
+  'UIKeyInputF7': 'F7',
+  'UIKeyInputF8': 'F8',
+  'UIKeyInputF9': 'F9',
+  'UIKeyInputF10': 'F10',
+  'UIKeyInputF11': 'F11',
+  'UIKeyInputF12': 'F12',
+  'UIKeyInputUpArrow': 'ArrowUp',
+  'UIKeyInputDownArrow': 'ArrowDown',
+  'UIKeyInputLeftArrow': 'ArrowLeft',
+  'UIKeyInputRightArrow': 'ArrowRight',
+  'UIKeyInputHome': 'Home',
+  'UIKeyInputEnd': 'Enter',
+  'UIKeyInputPageUp': 'PageUp',
+  'UIKeyInputPageDown': 'PageDown',
+};
diff --git a/dev/tools/gen_keycodes/lib/ios_code_gen.dart b/dev/tools/gen_keycodes/lib/ios_code_gen.dart
index 0d9e800..58e53c9 100644
--- a/dev/tools/gen_keycodes/lib/ios_code_gen.dart
+++ b/dev/tools/gen_keycodes/lib/ios_code_gen.dart
@@ -6,6 +6,7 @@
 
 import 'base_code_gen.dart';
 import 'constants.dart';
+import 'data.dart';
 import 'logical_key_data.dart';
 import 'physical_key_data.dart';
 import 'utils.dart';
@@ -105,6 +106,15 @@
     return modifierKeyMap.toString().trimRight();
   }
 
+  String get _specialKeyMapping {
+    final OutputLines<int> lines = OutputLines<int>('iOS special key mapping');
+    kIosSpecialKeyMapping.forEach((String key, String logicalName) {
+      final int value = logicalData.entryByName(logicalName).value;
+      lines.add(value, '  @"$key" : @(${toHex(value)}),');
+    });
+    return lines.join().trimRight();
+  }
+
   /// This generates some keys that needs special attention.
   String get _specialKeyConstants {
     final StringBuffer specialKeyConstants = StringBuffer();
@@ -137,6 +147,7 @@
       'KEYCODE_TO_MODIFIER_FLAG_MAP': _keyToModifierFlagMap,
       'MODIFIER_FLAG_TO_KEYCODE_MAP': _modifierFlagToKeyMap,
       'SPECIAL_KEY_CONSTANTS': _specialKeyConstants,
+      'SPECIAL_KEY_MAPPING': _specialKeyMapping,
     };
   }
 }
diff --git a/dev/tools/gen_keycodes/lib/keyboard_maps_code_gen.dart b/dev/tools/gen_keycodes/lib/keyboard_maps_code_gen.dart
index cf4e65c..c0c793e 100644
--- a/dev/tools/gen_keycodes/lib/keyboard_maps_code_gen.dart
+++ b/dev/tools/gen_keycodes/lib/keyboard_maps_code_gen.dart
@@ -7,6 +7,7 @@
 import 'package:path/path.dart' as path;
 
 import 'base_code_gen.dart';
+import 'data.dart';
 import 'logical_key_data.dart';
 import 'physical_key_data.dart';
 import 'utils.dart';
@@ -246,6 +247,16 @@
     return lines.sortedJoin().trimRight();
   }
 
+  /// This generates the map of iOS key label to logical keys for special keys.
+  String get _iOSSpecialMap {
+    final OutputLines<int> lines = OutputLines<int>('iOS special key mapping');
+    kIosSpecialKeyMapping.forEach((String key, String logicalName) {
+      final LogicalKeyEntry entry = logicalData.entryByName(logicalName);
+      lines.add(entry.value, "  '$key': LogicalKeyboardKey.${entry.constantName},");
+    });
+    return lines.join().trimRight();
+  }
+
   /// This generates the map of iOS number pad key codes to logical keys.
   String get _iOSNumpadMap {
     final OutputLines<int> lines = OutputLines<int>('iOS numpad map');
@@ -353,6 +364,7 @@
       'MACOS_FUNCTION_KEY_MAP': _macOSFunctionKeyMap,
       'MACOS_KEY_CODE_MAP': _macOSKeyCodeMap,
       'IOS_SCAN_CODE_MAP': _iOSScanCodeMap,
+      'IOS_SPECIAL_MAP': _iOSSpecialMap,
       'IOS_NUMPAD_MAP': _iOSNumpadMap,
       'IOS_KEY_CODE_MAP': _iOSKeyCodeMap,
       'GLFW_KEY_CODE_MAP': _glfwKeyCodeMap,
diff --git a/packages/flutter/lib/src/services/keyboard_maps.g.dart b/packages/flutter/lib/src/services/keyboard_maps.g.dart
index 66abf82..079230c 100644
--- a/packages/flutter/lib/src/services/keyboard_maps.g.dart
+++ b/packages/flutter/lib/src/services/keyboard_maps.g.dart
@@ -1468,6 +1468,35 @@
   0x000000e7: PhysicalKeyboardKey.metaRight,
 };
 
+/// Maps iOS specific string values of nonvisible keys to logical keys
+///
+/// Some unprintable keys on iOS has literal names on their key label, such as
+/// "UIKeyInputEscape". See:
+/// https://developer.apple.com/documentation/uikit/uikeycommand/input_strings_for_special_keys?language=objc
+const Map<String, LogicalKeyboardKey> kIosSpecialLogicalMap = <String, LogicalKeyboardKey>{
+  'UIKeyInputEscape': LogicalKeyboardKey.escape,
+  'UIKeyInputF1': LogicalKeyboardKey.f1,
+  'UIKeyInputF2': LogicalKeyboardKey.f2,
+  'UIKeyInputF3': LogicalKeyboardKey.f3,
+  'UIKeyInputF4': LogicalKeyboardKey.f4,
+  'UIKeyInputF5': LogicalKeyboardKey.f5,
+  'UIKeyInputF6': LogicalKeyboardKey.f6,
+  'UIKeyInputF7': LogicalKeyboardKey.f7,
+  'UIKeyInputF8': LogicalKeyboardKey.f8,
+  'UIKeyInputF9': LogicalKeyboardKey.f9,
+  'UIKeyInputF10': LogicalKeyboardKey.f10,
+  'UIKeyInputF11': LogicalKeyboardKey.f11,
+  'UIKeyInputF12': LogicalKeyboardKey.f12,
+  'UIKeyInputUpArrow': LogicalKeyboardKey.arrowUp,
+  'UIKeyInputDownArrow': LogicalKeyboardKey.arrowDown,
+  'UIKeyInputLeftArrow': LogicalKeyboardKey.arrowLeft,
+  'UIKeyInputRightArrow': LogicalKeyboardKey.arrowRight,
+  'UIKeyInputHome': LogicalKeyboardKey.home,
+  'UIKeyInputEnd': LogicalKeyboardKey.enter,
+  'UIKeyInputPageUp': LogicalKeyboardKey.pageUp,
+  'UIKeyInputPageDown': LogicalKeyboardKey.pageDown,
+};
+
 /// A map of iOS key codes which have printable representations, but appear
 /// on the number pad. Used to provide different key objects for keys like
 /// KEY_EQUALS and NUMPAD_EQUALS.
diff --git a/packages/flutter/lib/src/services/raw_keyboard_ios.dart b/packages/flutter/lib/src/services/raw_keyboard_ios.dart
index f5f952c..4ee5f5d 100644
--- a/packages/flutter/lib/src/services/raw_keyboard_ios.dart
+++ b/packages/flutter/lib/src/services/raw_keyboard_ios.dart
@@ -12,32 +12,6 @@
 export 'keyboard_key.g.dart' show LogicalKeyboardKey, PhysicalKeyboardKey;
 export 'raw_keyboard.dart' show KeyboardSide, ModifierKey;
 
-/// Maps iOS specific string values of nonvisible keys to logical keys
-///
-/// See: https://developer.apple.com/documentation/uikit/uikeycommand/input_strings_for_special_keys?language=objc
-const Map<String, LogicalKeyboardKey> _kIosToLogicalMap = <String, LogicalKeyboardKey>{
-  'UIKeyInputEscape': LogicalKeyboardKey.escape,
-  'UIKeyInputF1': LogicalKeyboardKey.f1,
-  'UIKeyInputF2': LogicalKeyboardKey.f2,
-  'UIKeyInputF3': LogicalKeyboardKey.f3,
-  'UIKeyInputF4': LogicalKeyboardKey.f4,
-  'UIKeyInputF5': LogicalKeyboardKey.f5,
-  'UIKeyInputF6': LogicalKeyboardKey.f6,
-  'UIKeyInputF7': LogicalKeyboardKey.f7,
-  'UIKeyInputF8': LogicalKeyboardKey.f8,
-  'UIKeyInputF9': LogicalKeyboardKey.f9,
-  'UIKeyInputF10': LogicalKeyboardKey.f10,
-  'UIKeyInputF11': LogicalKeyboardKey.f11,
-  'UIKeyInputF12': LogicalKeyboardKey.f12,
-  'UIKeyInputUpArrow': LogicalKeyboardKey.arrowUp,
-  'UIKeyInputDownArrow': LogicalKeyboardKey.arrowDown,
-  'UIKeyInputLeftArrow': LogicalKeyboardKey.arrowLeft,
-  'UIKeyInputRightArrow': LogicalKeyboardKey.arrowRight,
-  'UIKeyInputHome': LogicalKeyboardKey.home,
-  'UIKeyInputEnd': LogicalKeyboardKey.enter,
-  'UIKeyInputPageUp': LogicalKeyboardKey.pageUp,
-  'UIKeyInputPageDown': LogicalKeyboardKey.pageDown,
-};
 /// Platform-specific key event data for iOS.
 ///
 /// This object contains information about key events obtained from iOS'
@@ -107,9 +81,9 @@
     }
 
     // Look to see if the [keyLabel] is one we know about and have a mapping for.
-    final LogicalKeyboardKey? newKey = _kIosToLogicalMap[keyLabel];
-    if (newKey != null) {
-      return newKey;
+    final LogicalKeyboardKey? specialKey = kIosSpecialLogicalMap[keyLabel];
+    if (specialKey != null) {
+      return specialKey;
     }
 
     // Keys that can't be derived with characterIgnoringModifiers will be