Modify key info generation for new iOS key code. (#83439)

The (new, not yet used) code gen for iOS was setting up a std::map from key codes to logical and physical key codes, but it was using uint32_t, which isn't big enough to hold the Flutter key codes.

Also, iOS needs to be able to filter out function keys, so I added a function key set.
diff --git a/dev/bots/test.dart b/dev/bots/test.dart
index 8d6213f..04a6afa 100644
--- a/dev/bots/test.dart
+++ b/dev/bots/test.dart
@@ -728,6 +728,7 @@
     await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'android_semantics_testing'));
     await _runFlutterTest(path.join(flutterRoot, 'dev', 'manual_tests'));
     await _runFlutterTest(path.join(flutterRoot, 'dev', 'tools', 'vitool'));
+    await _runFlutterTest(path.join(flutterRoot, 'dev', 'tools', 'gen_keycodes'));
     await _runFlutterTest(path.join(flutterRoot, 'examples', 'hello_world'), options: soundNullSafetyOptions);
     await _runFlutterTest(path.join(flutterRoot, 'examples', 'layers'), options: soundNullSafetyOptions);
     await _runFlutterTest(path.join(flutterRoot, 'dev', 'benchmarks', 'test_apps', 'stocks'));
diff --git a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml
index 8418f9c..967b4d9 100644
--- a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml
+++ b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml
@@ -7,7 +7,7 @@
 dependencies:
   flutter:
     sdk: flutter
-  camera: 0.8.1+4
+  camera: 0.8.1+5
 
   camera_platform_interface: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
   characters: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -27,4 +27,4 @@
 flutter:
   uses-material-design: true
 
-# PUBSPEC CHECKSUM: 0d05
+# PUBSPEC CHECKSUM: 1c06
diff --git a/dev/tools/gen_keycodes/data/README.md b/dev/tools/gen_keycodes/data/README.md
index 33cd43d..2fca083 100644
--- a/dev/tools/gen_keycodes/data/README.md
+++ b/dev/tools/gen_keycodes/data/README.md
@@ -33,7 +33,7 @@
 | File name | Explanation |
 | ---- | ---- |
 | [`ios_logical_to_physical.json`](ios_logical_to_physical.json) | Maps a logical key name to the names of its corresponding physical keys. This is used to derive logical keys (from `keyCode`) that can't or shouldn't be derived from `characterIgnoringModifiers`. |
-| [`ios_keyboard_map_cc.tmpl`](ios_keyboard_map_cc.tmpl) | The template for `keyboard_map.cc`. (Unused for now.) |
+| [`ios_key_code_map_mm.tmpl`](ios_key_code_map_mm.tmpl) | The template for `KeyCodeMap.mm`.|
 
 ### Web
 
@@ -71,7 +71,7 @@
 
 | File name | Explanation |
 | ---- | ---- |
-| [`macos_key_code_map_cc.tmpl`](macos_key_code_map_cc.tmpl) | The template for `KeyCodeMap.cc`. |
+| [`macos_key_code_map_cc.tmpl`](macos_key_code_map_cc.tmpl) | The template for `KeyCodeMap.mm`. |
 | [`macos_logical_to_physical.json`](macos_logical_to_physical.json) | Maps a logical key name to the names of its corresponding physical keys. This is used to derive logical keys (from `keyCode`) that can't or shouldn't be derived from `characterIgnoringModifiers`. |
 
 ### Fuchsia
diff --git a/dev/tools/gen_keycodes/data/ios_key_code_map_cc.tmpl b/dev/tools/gen_keycodes/data/ios_key_code_map_cc.tmpl
deleted file mode 100644
index 3848592..0000000
--- a/dev/tools/gen_keycodes/data/ios_key_code_map_cc.tmpl
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2013 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.
-
-#include <map>
-#include "./KeyCodeMap_internal.h"
-
-// DO NOT EDIT -- DO NOT EDIT -- DO NOT EDIT
-// This file is generated by
-// flutter/flutter:dev/tools/gen_keycodes/bin/gen_keycodes.dart and should not
-// be edited directly.
-//
-// Edit the template
-// flutter/flutter:dev/tools/gen_keycodes/data/ios_key_code_map_cc.tmpl instead.
-//
-// See flutter/flutter:dev/tools/gen_keycodes/README.md for more information.
-
-@@@MASK_CONSTANTS@@@
-
-// Maps iOS-specific key code values representing [PhysicalKeyboardKey].
-//
-// iOS doesn't provide a scan code, but a virtual keycode to represent a physical key.
-const std::map<uint32_t, uint32_t> keyCodeToPhysicalKey = {
-@@@IOS_SCAN_CODE_MAP@@@
-};
-
-const std::map<uint32_t, uint32_t> keyCodeToLogicalKey = {
-@@@IOS_KEYCODE_LOGICAL_MAP@@@
-};
-
-const std::map<uint32_t, uint32_t> keyCodeToModifierFlag = {
-@@@KEYCODE_TO_MODIFIER_FLAG_MAP@@@
-};
-
-const std::map<uint32_t, uint32_t> modifierFlagToKeyCode = {
-@@@MODIFIER_FLAG_TO_KEYCODE_MAP@@@
-};
-
-@@@SPECIAL_KEY_CONSTANTS@@@
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
new file mode 100644
index 0000000..9cecd01
--- /dev/null
+++ b/dev/tools/gen_keycodes/data/ios_key_code_map_mm.tmpl
@@ -0,0 +1,51 @@
+// Copyright 2013 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.
+
+#include <map>
+#include <set>
+#include "flutter/shell/platform/darwin/ios/framework/Source/KeyCodeMap_Internal.h"
+
+// DO NOT EDIT -- DO NOT EDIT -- DO NOT EDIT
+// This file is generated by
+// flutter/flutter:dev/tools/gen_keycodes/bin/gen_keycodes.dart and should not
+// be edited directly.
+//
+// Edit the template
+// flutter/flutter:dev/tools/gen_keycodes/data/ios_key_code_map_mm.tmpl instead.
+//
+// See flutter/flutter:dev/tools/gen_keycodes/README.md for more information.
+
+@@@MASK_CONSTANTS@@@
+
+// Maps iOS-specific key code values representing PhysicalKeyboardKey.
+//
+// iOS doesn't provide a scan code, but a virtual keycode to represent a physical key.
+const std::map<uint32_t, uint64_t> keyCodeToPhysicalKey = {
+@@@IOS_SCAN_CODE_MAP@@@
+};
+
+// Maps iOS-specific virtual key code values to logical keys representing
+// LogicalKeyboardKey
+const std::map<uint32_t, uint64_t> keyCodeToLogicalKey = {
+@@@IOS_KEYCODE_LOGICAL_MAP@@@
+};
+
+// Maps iOS-specific virtual key codes to an equivalent modifier flag enum
+// value.
+const std::map<uint32_t, ModifierFlag> keyCodeToModifierFlag = {
+@@@KEYCODE_TO_MODIFIER_FLAG_MAP@@@
+};
+
+// Maps modifier flag enum values to an iOS-specific virtual key code.
+const std::map<ModifierFlag, uint32_t> modifierFlagToKeyCode = {
+@@@MODIFIER_FLAG_TO_KEYCODE_MAP@@@
+};
+
+// A set of virtual key codes mapping to function keys, so that may be
+// identified as such.
+const std::set<uint32_t> functionKeyCodes = {
+@@@IOS_FUNCTION_KEY_SET@@@
+};
+
+@@@SPECIAL_KEY_CONSTANTS@@@
diff --git a/dev/tools/gen_keycodes/data/ios_keyboard_map_cc.tmpl b/dev/tools/gen_keycodes/data/ios_keyboard_map_cc.tmpl
deleted file mode 100644
index 439d90a..0000000
--- a/dev/tools/gen_keycodes/data/ios_keyboard_map_cc.tmpl
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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.
-
-#include <map>
-
-// DO NOT EDIT -- DO NOT EDIT -- DO NOT EDIT
-// This file is generated by
-// flutter/flutter:dev/tools/gen_keycodes/bin/gen_keycodes.dart and should not
-// be edited directly.
-//
-// Edit the template
-// flutter/flutter:dev/tools/gen_keycodes/data/ios_keyboard_map_cc.tmpl instead.
-//
-// See flutter/flutter:dev/tools/gen_keycodes/README.md for more information.
-
-// Maps iOS-specific key code values representing [PhysicalKeyboardKey].
-//
-// iOS doesn't provide a scan code, but a virtual keycode to represent a physical key.
-const std::map<int, int> g_ios_to_physical_key = {
-@@@IOS_SCAN_CODE_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.
-const std::map<int, int> g_ios_numpad_map = {
-@@@IOS_NUMPAD_MAP@@@
-};
diff --git a/dev/tools/gen_keycodes/lib/ios_code_gen.dart b/dev/tools/gen_keycodes/lib/ios_code_gen.dart
index 40cade2..1cf3d82 100644
--- a/dev/tools/gen_keycodes/lib/ios_code_gen.dart
+++ b/dev/tools/gen_keycodes/lib/ios_code_gen.dart
@@ -43,6 +43,21 @@
     return lines.sortedJoin().trimRight();
   }
 
+  Iterable<PhysicalKeyEntry> get _functionKeyData {
+    final RegExp functionKeyRe = RegExp(r'^f[0-9]+$');
+    return keyData.entries.where((PhysicalKeyEntry entry) {
+      return functionKeyRe.hasMatch(entry.constantName);
+    });
+  }
+
+  String get _functionKeys {
+    final StringBuffer result = StringBuffer();
+    for (final PhysicalKeyEntry entry in _functionKeyData) {
+      result.writeln('    ${toHex(entry.iOSScanCode)},  // ${entry.constantName}');
+    }
+    return result.toString().trimRight();
+  }
+
   String get _keyCodeToLogicalMap {
     final OutputLines<int> lines = OutputLines<int>('iOS keycode map');
     for (final LogicalKeyEntry entry in logicalData.entries) {
@@ -75,7 +90,7 @@
   String get _keyToModifierFlagMap {
     final StringBuffer modifierKeyMap = StringBuffer();
     for (final String name in kModifiersOfInterest) {
-      final String line = '{${toHex(logicalData.entryByName(name).iOSKeyCodeValues[0])}, kModifierFlag${lowerCamelToUpperCamel(name)}},';
+      final String line ='    {${toHex(logicalData.entryByName(name).iOSKeyCodeValues[0])}, kModifierFlag${lowerCamelToUpperCamel(name)}},';
       modifierKeyMap.writeln('    ${line.padRight(42)}// $name');
     }
     return modifierKeyMap.toString().trimRight();
@@ -85,7 +100,7 @@
   String get _modifierFlagToKeyMap {
     final StringBuffer modifierKeyMap = StringBuffer();
     for (final String name in kModifiersOfInterest) {
-      final String line = '{kModifierFlag${lowerCamelToUpperCamel(name)}, ${toHex(logicalData.entryByName(name).iOSKeyCodeValues[0])}},';
+      final String line ='    {kModifierFlag${lowerCamelToUpperCamel(name)}, ${toHex(logicalData.entryByName(name).iOSKeyCodeValues[0])}},';
       modifierKeyMap.writeln('    ${line.padRight(42)}// $name');
     }
     return modifierKeyMap.toString().trimRight();
@@ -104,7 +119,7 @@
   }
 
   @override
-  String get templatePath => path.join(dataRoot, 'ios_key_code_map_cc.tmpl');
+  String get templatePath => path.join(dataRoot, 'ios_key_code_map_mm.tmpl');
 
   @override
   String outputPath(String platform) => path.join(PlatformCodeGenerator.engineRoot,
@@ -119,6 +134,7 @@
       'MASK_CONSTANTS': _maskConstants,
       'IOS_SCAN_CODE_MAP': _scanCodeMap,
       'IOS_KEYCODE_LOGICAL_MAP': _keyCodeToLogicalMap,
+      'IOS_FUNCTION_KEY_SET': _functionKeys,
       'KEYCODE_TO_MODIFIER_FLAG_MAP': _keyToModifierFlagMap,
       'MODIFIER_FLAG_TO_KEYCODE_MAP': _modifierFlagToKeyMap,
       'SPECIAL_KEY_CONSTANTS': _specialKeyConstants,
diff --git a/dev/tools/gen_keycodes/lib/utils.dart b/dev/tools/gen_keycodes/lib/utils.dart
index cf8808e..840684b 100644
--- a/dev/tools/gen_keycodes/lib/utils.dart
+++ b/dev/tools/gen_keycodes/lib/utils.dart
@@ -5,6 +5,7 @@
 import 'dart:convert';
 import 'dart:io';
 
+import 'package:meta/meta.dart';
 import 'package:path/path.dart' as path;
 
 import 'constants.dart';
@@ -12,7 +13,12 @@
 /// The location of the Flutter root directory, based on the known location of
 /// this script.
 final Directory flutterRoot = Directory(path.dirname(Platform.script.toFilePath())).parent.parent.parent.parent;
-final String dataRoot = path.join(flutterRoot.path, 'dev', 'tools', 'gen_keycodes', 'data');
+String get dataRoot => testDataRoot ?? _dataRoot;
+String _dataRoot = path.join(flutterRoot.path, 'dev', 'tools', 'gen_keycodes', 'data');
+
+/// Allows overriding of the [dataRoot] for testing purposes.
+@visibleForTesting
+String? testDataRoot;
 
 /// Converts `FOO_BAR` to `FooBar`.
 String shoutingToUpperCamel(String shouting) {
diff --git a/dev/tools/gen_keycodes/pubspec.yaml b/dev/tools/gen_keycodes/pubspec.yaml
index b1ced7a..cc38b4f 100644
--- a/dev/tools/gen_keycodes/pubspec.yaml
+++ b/dev/tools/gen_keycodes/pubspec.yaml
@@ -21,4 +21,43 @@
   term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
   typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
 
-# PUBSPEC CHECKSUM: e46d
+dev_dependencies:
+  test: 1.17.10
+  test_api: 0.4.2
+
+  _fe_analyzer_shared: 23.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  analyzer: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  cli_util: 0.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  convert: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  coverage: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  crypto: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  file: 6.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  frontend_server_client: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  glob: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  logging: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  matcher: 0.12.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  mime: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  package_config: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  pub_semver: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  shelf_packages_handler: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  shelf_static: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  shelf_web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  source_map_stack_trace: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  test_core: 0.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  vm_service: 7.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  watcher: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  webkit_inspection_protocol: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  yaml: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+
+# PUBSPEC CHECKSUM: a37c
diff --git a/dev/tools/gen_keycodes/test/gen_keycodes_test.dart b/dev/tools/gen_keycodes/test/gen_keycodes_test.dart
new file mode 100644
index 0000000..447ee4d
--- /dev/null
+++ b/dev/tools/gen_keycodes/test/gen_keycodes_test.dart
@@ -0,0 +1,191 @@
+// 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.
+
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:gen_keycodes/android_code_gen.dart';
+import 'package:gen_keycodes/base_code_gen.dart';
+import 'package:gen_keycodes/gtk_code_gen.dart';
+import 'package:gen_keycodes/ios_code_gen.dart';
+import 'package:gen_keycodes/logical_key_data.dart';
+import 'package:gen_keycodes/macos_code_gen.dart';
+import 'package:gen_keycodes/physical_key_data.dart';
+import 'package:gen_keycodes/utils.dart';
+import 'package:gen_keycodes/web_code_gen.dart';
+import 'package:gen_keycodes/windows_code_gen.dart';
+import 'package:path/path.dart' as path;
+import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
+
+String readDataFile(String fileName) {
+  return File(path.join(dataRoot, fileName)).readAsStringSync();
+}
+
+final String testPhysicalData = path.join(dataRoot, 'physical_key_data.json');
+final String testLogicalData = path.join(dataRoot,'logical_key_data.json');
+
+void main() {
+  setUp(() {
+    testDataRoot = path.canonicalize(path.join(Directory.current.absolute.path, 'data'));
+  });
+
+  tearDown((){
+    testDataRoot = null;
+  });
+
+  void checkCommonOutput(String output) {
+    expect(output, contains(RegExp('Copyright 201[34]')));
+    expect(output, contains('DO NOT EDIT'));
+    expect(output, contains(RegExp(r'\b[kK]eyA\b')));
+    expect(output, contains(RegExp(r'\b[Dd]igit1\b')));
+    expect(output, contains(RegExp(r'\b[Ff]1\b')));
+    expect(output, contains(RegExp(r'\b[Nn]umpad1\b')));
+    expect(output, contains(RegExp(r'\b[Ss]hiftLeft\b')));
+  }
+
+  test('Generate Keycodes for Android', () {
+    PhysicalKeyData physicalData;
+    LogicalKeyData logicalData;
+
+    physicalData = PhysicalKeyData.fromJson(
+        json.decode(File(testPhysicalData).readAsStringSync()) as Map<String, dynamic>);
+    logicalData = LogicalKeyData.fromJson(
+        json.decode(File(testLogicalData).readAsStringSync()) as Map<String, dynamic>);
+
+    const String platform = 'android';
+    final PlatformCodeGenerator codeGenerator = AndroidCodeGenerator(
+      physicalData,
+      logicalData,
+    );
+    final String output = codeGenerator.generate();
+
+    expect(codeGenerator.outputPath(platform), endsWith('KeyboardMap.java'));
+    expect(output, contains('class KeyboardMap'));
+    expect(output, contains('scanCodeToPhysical'));
+    expect(output, contains('keyCodeToLogical'));
+    checkCommonOutput(output);
+  });
+  test('Generate Keycodes for macOS', () {
+    PhysicalKeyData physicalData;
+    LogicalKeyData logicalData;
+
+    physicalData = PhysicalKeyData.fromJson(
+        json.decode(File(testPhysicalData).readAsStringSync()) as Map<String, dynamic>);
+    logicalData = LogicalKeyData.fromJson(
+        json.decode(File(testLogicalData).readAsStringSync()) as Map<String, dynamic>);
+
+    const String platform = 'macos';
+    final PlatformCodeGenerator codeGenerator = MacOSCodeGenerator(
+      physicalData,
+      logicalData,
+    );
+    final String output = codeGenerator.generate();
+
+    expect(codeGenerator.outputPath(platform), endsWith('KeyCodeMap.mm'));
+    expect(output, contains('kValueMask'));
+    expect(output, contains('keyCodeToPhysicalKey'));
+    expect(output, contains('keyCodeToLogicalKey'));
+    expect(output, contains('keyCodeToModifierFlag'));
+    expect(output, contains('modifierFlagToKeyCode'));
+    expect(output, contains('kCapsLockPhysicalKey'));
+    expect(output, contains('kCapsLockLogicalKey'));
+    checkCommonOutput(output);
+  });
+  test('Generate Keycodes for iOS', () {
+    PhysicalKeyData physicalData;
+    LogicalKeyData logicalData;
+
+    physicalData = PhysicalKeyData.fromJson(
+        json.decode(File(testPhysicalData).readAsStringSync()) as Map<String, dynamic>);
+    logicalData = LogicalKeyData.fromJson(
+        json.decode(File(testLogicalData).readAsStringSync()) as Map<String, dynamic>);
+
+    const String platform = 'ios';
+    final PlatformCodeGenerator codeGenerator = IOSCodeGenerator(
+      physicalData,
+      logicalData,
+    );
+    final String output = codeGenerator.generate();
+
+    expect(codeGenerator.outputPath(platform), endsWith('KeyCodeMap.mm'));
+    expect(output, contains('kValueMask'));
+    expect(output, contains('keyCodeToPhysicalKey'));
+    expect(output, contains('keyCodeToLogicalKey'));
+    expect(output, contains('keyCodeToModifierFlag'));
+    expect(output, contains('modifierFlagToKeyCode'));
+    expect(output, contains('functionKeyCodes'));
+    expect(output, contains('kCapsLockPhysicalKey'));
+    expect(output, contains('kCapsLockLogicalKey'));
+    checkCommonOutput(output);
+  });
+  test('Generate Keycodes for Windows', () {
+    PhysicalKeyData physicalData;
+    LogicalKeyData logicalData;
+
+    physicalData = PhysicalKeyData.fromJson(
+        json.decode(File(testPhysicalData).readAsStringSync()) as Map<String, dynamic>);
+    logicalData = LogicalKeyData.fromJson(
+        json.decode(File(testLogicalData).readAsStringSync()) as Map<String, dynamic>);
+
+    const String platform = 'windows';
+    final PlatformCodeGenerator codeGenerator = WindowsCodeGenerator(
+      physicalData,
+      logicalData,
+      readDataFile(path.join(dataRoot, 'windows_scancode_logical_map.json')),
+    );
+    final String output = codeGenerator.generate();
+
+    expect(codeGenerator.outputPath(platform), endsWith('flutter_key_map.cc'));
+    expect(output, contains('KeyboardKeyEmbedderHandler::windowsToPhysicalMap_'));
+    expect(output, contains('KeyboardKeyEmbedderHandler::windowsToLogicalMap_'));
+    expect(output, contains('KeyboardKeyEmbedderHandler::scanCodeToLogicalMap_'));
+    checkCommonOutput(output);
+  });
+  test('Generate Keycodes for Linux', () {
+    PhysicalKeyData physicalData;
+    LogicalKeyData logicalData;
+
+    physicalData = PhysicalKeyData.fromJson(
+        json.decode(File(testPhysicalData).readAsStringSync()) as Map<String, dynamic>);
+    logicalData = LogicalKeyData.fromJson(
+        json.decode(File(testLogicalData).readAsStringSync()) as Map<String, dynamic>);
+
+    const String platform = 'gtk';
+    final PlatformCodeGenerator codeGenerator = GtkCodeGenerator(
+      physicalData,
+      logicalData,
+      readDataFile(path.join(dataRoot, 'gtk_modifier_bit_mapping.json')),
+      readDataFile(path.join(dataRoot, 'gtk_lock_bit_mapping.json')),
+    );
+    final String output = codeGenerator.generate();
+
+    expect(codeGenerator.outputPath(platform), endsWith('key_mapping.cc'));
+    expect(output, contains('initialize_modifier_bit_to_checked_keys'));
+    expect(output, contains('initialize_lock_bit_to_checked_keys'));
+    checkCommonOutput(output);
+  });
+  test('Generate Keycodes for Web', () {
+    PhysicalKeyData physicalData;
+    LogicalKeyData logicalData;
+
+    physicalData = PhysicalKeyData.fromJson(
+        json.decode(File(testPhysicalData).readAsStringSync()) as Map<String, dynamic>);
+    logicalData = LogicalKeyData.fromJson(
+        json.decode(File(testLogicalData).readAsStringSync()) as Map<String, dynamic>);
+
+    const String platform = 'web';
+    final PlatformCodeGenerator codeGenerator = WebCodeGenerator(
+      physicalData,
+      logicalData,
+      readDataFile(path.join(dataRoot, 'web_logical_location_mapping.json')),
+    );
+    final String output = codeGenerator.generate();
+
+    expect(codeGenerator.outputPath(platform), endsWith('key_map.dart'));
+    expect(output, contains('kWebToLogicalKey'));
+    expect(output, contains('kWebToPhysicalKey'));
+    expect(output, contains('kWebLogicalLocationMap'));
+    checkCommonOutput(output);
+  });
+}