Fix the `character` field of the `RawKeyEvent` to hold correct data on non-Android platforms. (#65667)

This fixes a problem where the character field of the RawKeyEvent was not being set at all for non-Android platforms.

I also updated the key maps, and corrected a problem with the Windows key map where the backquote character wasn't correctly mapped.
diff --git a/dev/manual_tests/lib/raw_keyboard.dart b/dev/manual_tests/lib/raw_keyboard.dart
index 5c50210..e08b260 100644
--- a/dev/manual_tests/lib/raw_keyboard.dart
+++ b/dev/manual_tests/lib/raw_keyboard.dart
@@ -79,6 +79,7 @@
           final String modifierList = data.modifiersPressed.keys.map<String>(_getEnumName).join(', ').replaceAll('Modifier', '');
           final List<Widget> dataText = <Widget>[
             Text('${_event.runtimeType}'),
+            if (_event.character?.isNotEmpty ?? false) Text('character produced: "${_event.character}"'),
             Text('modifiers set: $modifierList'),
           ];
           if (data is RawKeyEventDataAndroid) {
@@ -114,6 +115,10 @@
             dataText.add(Text('scanCode: ${data.scanCode}'));
             dataText.add(Text('characterCodePoint: ${data.characterCodePoint}'));
             dataText.add(Text('modifiers: ${data.modifiers} (${_asHex(data.modifiers)})'));
+          } else if (data is RawKeyEventDataWeb) {
+            dataText.add(Text('key: ${data.key}'));
+            dataText.add(Text('code: ${data.code}'));
+            dataText.add(Text('metaState: ${data.metaState} (${_asHex(data.metaState)})'));
           }
           dataText.add(Text('logical: ${_event.logicalKey}'));
           dataText.add(Text('physical: ${_event.physicalKey}'));
diff --git a/dev/tools/gen_keycodes/data/key_data.json b/dev/tools/gen_keycodes/data/key_data.json
index b68fc8a..6ee1488 100644
--- a/dev/tools/gen_keycodes/data/key_data.json
+++ b/dev/tools/gen_keycodes/data/key_data.json
@@ -2472,7 +2472,9 @@
       "gtk": [
         "quoteleft"
       ],
-      "windows": null
+      "windows": [
+        "OEM_3"
+      ]
     },
     "scanCodes": {
       "android": [
@@ -2494,7 +2496,9 @@
       "gtk": [
         96
       ],
-      "windows": null
+      "windows": [
+        192
+      ]
     }
   },
   "comma": {
@@ -6565,7 +6569,9 @@
       "windows": null
     },
     "scanCodes": {
-      "android": null,
+      "android": [
+        370
+      ],
       "usb": 786529,
       "linux": 370,
       "xkb": 378,
@@ -6822,7 +6828,9 @@
       "windows": null
     },
     "scanCodes": {
-      "android": null,
+      "android": [
+        405
+      ],
       "usb": 786563,
       "linux": 405,
       "xkb": 413,
@@ -7891,7 +7899,9 @@
       "windows": null
     },
     "scanCodes": {
-      "android": null,
+      "android": [
+        583
+      ],
       "usb": 786891,
       "linux": 583,
       "xkb": 591,
diff --git a/dev/tools/gen_keycodes/data/key_name_to_windows_name.json b/dev/tools/gen_keycodes/data/key_name_to_windows_name.json
index 2513e1d..921ca87 100644
--- a/dev/tools/gen_keycodes/data/key_name_to_windows_name.json
+++ b/dev/tools/gen_keycodes/data/key_name_to_windows_name.json
@@ -132,7 +132,7 @@
   "minus": ["OEM_MINUS"],
   "period": ["OEM_PERIOD"],
   "slash": ["OEM_2"],
-  "backQuote": ["OEM_3"],
+  "backquote": ["OEM_3"],
   "gamepadA": ["GAMEPAD_A"],
   "gamepadB": ["GAMEPAD_B"],
   "gamepadX": ["GAMEPAD_X"],
diff --git a/dev/tools/gen_keycodes/data/keyboard_maps.tmpl b/dev/tools/gen_keycodes/data/keyboard_maps.tmpl
index 182ebbf..498f636 100644
--- a/dev/tools/gen_keycodes/data/keyboard_maps.tmpl
+++ b/dev/tools/gen_keycodes/data/keyboard_maps.tmpl
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// @dart = 2.8
-
 // DO NOT EDIT -- DO NOT EDIT -- DO NOT EDIT
 // This file is generated by dev/tools/gen_keycodes/bin/gen_keycodes.dart and
 // should not be edited directly.
diff --git a/packages/flutter/lib/src/services/keyboard_maps.dart b/packages/flutter/lib/src/services/keyboard_maps.dart
index 0126631..c73c14d 100644
--- a/packages/flutter/lib/src/services/keyboard_maps.dart
+++ b/packages/flutter/lib/src/services/keyboard_maps.dart
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-
 // DO NOT EDIT -- DO NOT EDIT -- DO NOT EDIT
 // This file is generated by dev/tools/gen_keycodes/bin/gen_keycodes.dart and
 // should not be edited directly.
@@ -349,8 +348,10 @@
   100: PhysicalKeyboardKey.altRight,
   126: PhysicalKeyboardKey.metaRight,
   358: PhysicalKeyboardKey.info,
+  370: PhysicalKeyboardKey.closedCaptionToggle,
   225: PhysicalKeyboardKey.brightnessUp,
   224: PhysicalKeyboardKey.brightnessDown,
+  405: PhysicalKeyboardKey.mediaLast,
   174: PhysicalKeyboardKey.exit,
   402: PhysicalKeyboardKey.channelUp,
   403: PhysicalKeyboardKey.channelDown,
@@ -372,6 +373,7 @@
   215: PhysicalKeyboardKey.launchMail,
   429: PhysicalKeyboardKey.launchContacts,
   397: PhysicalKeyboardKey.launchCalendar,
+  583: PhysicalKeyboardKey.launchAssistant,
   181: PhysicalKeyboardKey.newKey,
   160: PhysicalKeyboardKey.close,
   206: PhysicalKeyboardKey.close,
@@ -2290,6 +2292,7 @@
   220: LogicalKeyboardKey.backslash,
   186: LogicalKeyboardKey.semicolon,
   222: LogicalKeyboardKey.quote,
+  192: LogicalKeyboardKey.backquote,
   188: LogicalKeyboardKey.comma,
   190: LogicalKeyboardKey.period,
   191: LogicalKeyboardKey.slash,
diff --git a/packages/flutter/lib/src/services/raw_keyboard.dart b/packages/flutter/lib/src/services/raw_keyboard.dart
index 46e49dd..a8a665e 100644
--- a/packages/flutter/lib/src/services/raw_keyboard.dart
+++ b/packages/flutter/lib/src/services/raw_keyboard.dart
@@ -267,6 +267,7 @@
   /// on the [SystemChannels.keyEvent] channel.
   factory RawKeyEvent.fromMessage(Map<String, dynamic> message) {
     RawKeyEventData data;
+    String? character;
 
     final String keymap = message['keymap'] as String;
     switch (keymap) {
@@ -284,13 +285,20 @@
           deviceId: message['deviceId'] as int? ?? 0,
           repeatCount: message['repeatCount'] as int? ?? 0,
         );
+        if (message.containsKey('character')) {
+          character = message['character'] as String?;
+        }
         break;
       case 'fuchsia':
+        final int codePoint = message['codePoint'] as int? ?? 0;
         data = RawKeyEventDataFuchsia(
           hidUsage: message['hidUsage'] as int? ?? 0,
-          codePoint: message['codePoint'] as int? ?? 0,
+          codePoint: codePoint,
           modifiers: message['modifiers'] as int? ?? 0,
         );
+        if (codePoint != 0) {
+          character = String.fromCharCode(codePoint);
+        }
         break;
       case 'macos':
         data = RawKeyEventDataMacOs(
@@ -298,15 +306,20 @@
             charactersIgnoringModifiers: message['charactersIgnoringModifiers'] as String? ?? '',
             keyCode: message['keyCode'] as int? ?? 0,
             modifiers: message['modifiers'] as int? ?? 0);
+        character = message['characters'] as String?;
         break;
       case 'linux':
+        final int unicodeScalarValues = message['unicodeScalarValues'] as int? ?? 0;
         data = RawKeyEventDataLinux(
             keyHelper: KeyHelper(message['toolkit'] as String? ?? ''),
-            unicodeScalarValues: message['unicodeScalarValues'] as int? ?? 0,
+            unicodeScalarValues: unicodeScalarValues,
             keyCode: message['keyCode'] as int? ?? 0,
             scanCode: message['scanCode'] as int? ?? 0,
             modifiers: message['modifiers'] as int? ?? 0,
             isDown: message['type'] == 'keydown');
+        if (unicodeScalarValues != 0) {
+          character = String.fromCharCode(unicodeScalarValues);
+        }
         break;
       case 'web':
         data = RawKeyEventDataWeb(
@@ -314,14 +327,19 @@
           key: message['key'] as String? ?? '',
           metaState: message['metaState'] as int? ?? 0,
         );
+        character = message['key'] as String?;
         break;
       case 'windows':
+        final int characterCodePoint = message['characterCodePoint'] as int? ?? 0;
         data = RawKeyEventDataWindows(
           keyCode: message['keyCode'] as int? ?? 0,
           scanCode: message['scanCode'] as int? ?? 0,
-          characterCodePoint: message['characterCodePoint'] as int? ?? 0,
+          characterCodePoint: characterCodePoint,
           modifiers: message['modifiers'] as int? ?? 0,
         );
+        if (characterCodePoint != 0) {
+          character = String.fromCharCode(characterCodePoint);
+        }
         break;
       default:
         // Raw key events are not yet implemented  on iOS or other platforms,
@@ -333,7 +351,7 @@
     final String type = message['type'] as String;
     switch (type) {
       case 'keydown':
-        return RawKeyDownEvent(data: data, character: message['character'] as String);
+        return RawKeyDownEvent(data: data, character: character);
       case 'keyup':
         return RawKeyUpEvent(data: data);
       default:
diff --git a/packages/flutter/test/services/raw_keyboard_test.dart b/packages/flutter/test/services/raw_keyboard_test.dart
index a19c5bb..b138267 100644
--- a/packages/flutter/test/services/raw_keyboard_test.dart
+++ b/packages/flutter/test/services/raw_keyboard_test.dart
@@ -17,6 +17,30 @@
 
 void main() {
   group('RawKeyboard', () {
+    testWidgets('The correct character is produced', (WidgetTester tester) async {
+      for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows']) {
+        String character = '';
+        void handleKey(RawKeyEvent event) {
+          expect(event.character, equals(character), reason: 'on $platform');
+        }
+        RawKeyboard.instance.addListener(handleKey);
+        character = 'a';
+        await simulateKeyDownEvent(LogicalKeyboardKey.keyA, platform: platform);
+        character = '`';
+        await simulateKeyDownEvent(LogicalKeyboardKey.backquote, platform: platform);
+        RawKeyboard.instance.removeListener(handleKey);
+      }
+    });
+    testWidgets('No character is produced for non-printables', (WidgetTester tester) async {
+      for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows']) {
+        void handleKey(RawKeyEvent event) {
+          expect(event.character, isNull, reason: 'on $platform');
+        }
+        RawKeyboard.instance.addListener(handleKey);
+        await simulateKeyDownEvent(LogicalKeyboardKey.shiftLeft, platform: platform);
+        RawKeyboard.instance.removeListener(handleKey);
+      }
+    });
     testWidgets('keysPressed is maintained', (WidgetTester tester) async {
       for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows']) {
         RawKeyboard.instance.clearKeysPressed();
diff --git a/packages/flutter_test/lib/src/event_simulation.dart b/packages/flutter_test/lib/src/event_simulation.dart
index f7a65f2..2a624b8 100644
--- a/packages/flutter_test/lib/src/event_simulation.dart
+++ b/packages/flutter_test/lib/src/event_simulation.dart
@@ -174,7 +174,6 @@
     final Map<String, dynamic> result = <String, dynamic>{
       'type': isDown ? 'keydown' : 'keyup',
       'keymap': platform,
-      'character': key.keyLabel,
     };
 
     switch (platform) {
@@ -182,6 +181,7 @@
         result['keyCode'] = keyCode;
         if (key.keyLabel.isNotEmpty) {
           result['codePoint'] = key.keyLabel.codeUnitAt(0);
+          result['character'] = key.keyLabel;
         }
         result['scanCode'] = scanCode;
         result['metaState'] = _getAndroidModifierFlags(key, isDown);
@@ -198,16 +198,19 @@
         result['keyCode'] = keyCode;
         result['scanCode'] = scanCode;
         result['modifiers'] = _getGlfwModifierFlags(key, isDown);
+        result['unicodeScalarValues'] = key.keyLabel.isNotEmpty ? key.keyLabel.codeUnitAt(0) : 0;
         break;
       case 'macos':
         result['keyCode'] = scanCode;
-        result['characters'] = key.keyLabel;
-        result['charactersIgnoringModifiers'] = key.keyLabel;
+        if (key.keyLabel.isNotEmpty) {
+          result['characters'] = key.keyLabel;
+          result['charactersIgnoringModifiers'] = key.keyLabel;
+        }
         result['modifiers'] = _getMacOsModifierFlags(key, isDown);
         break;
       case 'web':
         result['code'] = _getWebKeyCode(key);
-        result['key'] = '';
+        result['key'] = key.keyLabel;
         result['metaState'] = _getWebModifierFlags(key, isDown);
         break;
       case 'windows':