Expose keyCode field in RawKeyEventDataWeb. (#96483)

diff --git a/packages/flutter/lib/src/services/raw_keyboard.dart b/packages/flutter/lib/src/services/raw_keyboard.dart
index 188b1e8..490d970 100644
--- a/packages/flutter/lib/src/services/raw_keyboard.dart
+++ b/packages/flutter/lib/src/services/raw_keyboard.dart
@@ -300,6 +300,7 @@
         key: key ?? '',
         location: message['location'] as int? ?? 0,
         metaState: message['metaState'] as int? ?? 0,
+        keyCode: message['keyCode'] as int? ?? 0,
       );
     }
 
diff --git a/packages/flutter/lib/src/services/raw_keyboard_web.dart b/packages/flutter/lib/src/services/raw_keyboard_web.dart
index 2939313..3d10739 100644
--- a/packages/flutter/lib/src/services/raw_keyboard_web.dart
+++ b/packages/flutter/lib/src/services/raw_keyboard_web.dart
@@ -32,6 +32,7 @@
     required this.key,
     this.location = 0,
     this.metaState = modifierNone,
+    this.keyCode = 0,
   })  : assert(code != null),
         assert(metaState != null);
 
@@ -80,6 +81,12 @@
   ///  * [isMetaPressed], to see if a META key is pressed.
   final int metaState;
 
+  /// The `KeyboardEvent.keyCode` corresponding to this event.
+  ///
+  /// See <https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode>
+  /// for more information.
+  final int keyCode;
+
   @override
   String get keyLabel => key == 'Unidentified' ? '' : _unicodeChar(key) ?? '';
 
@@ -156,6 +163,7 @@
         properties.add(DiagnosticsProperty<String>('key', key));
         properties.add(DiagnosticsProperty<int>('location', location));
         properties.add(DiagnosticsProperty<int>('metaState', metaState));
+        properties.add(DiagnosticsProperty<int>('keyCode', keyCode));
   }
 
   @override
@@ -168,7 +176,8 @@
         && other.code == code
         && other.key == key
         && other.location == location
-        && other.metaState == metaState;
+        && other.metaState == metaState
+        && other.keyCode == keyCode;
   }
 
   @override
@@ -177,6 +186,7 @@
     key,
     location,
     metaState,
+    keyCode,
   );
 
   // Modifier key masks.
diff --git a/packages/flutter/test/services/raw_keyboard_test.dart b/packages/flutter/test/services/raw_keyboard_test.dart
index c55d616..03a00f0 100644
--- a/packages/flutter/test/services/raw_keyboard_test.dart
+++ b/packages/flutter/test/services/raw_keyboard_test.dart
@@ -2547,11 +2547,13 @@
         'key': 'a',
         'location': 0,
         'metaState': 0x0,
+        'keyCode': 0x41,
       });
       final RawKeyEventDataWeb data = keyAEvent.data as RawKeyEventDataWeb;
       expect(data.physicalKey, equals(PhysicalKeyboardKey.keyA));
       expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
       expect(data.keyLabel, equals('a'));
+      expect(data.keyCode, equals(0x41));
     });
 
     test('Upper letter keys are correctly translated', () {
@@ -2562,11 +2564,13 @@
         'key': 'A',
         'location': 0,
         'metaState': 0x1, // Shift
+        'keyCode': 0x41,
       });
       final RawKeyEventDataWeb data = keyAEvent.data as RawKeyEventDataWeb;
       expect(data.physicalKey, equals(PhysicalKeyboardKey.keyA));
       expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
       expect(data.keyLabel, equals('A'));
+      expect(data.keyCode, equals(0x41));
     });
 
     test('Control keyboard keys are correctly translated', () {
@@ -2577,11 +2581,13 @@
         'key': 'Escape',
         '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('Modifier keyboard keys are correctly translated', () {
@@ -2592,11 +2598,13 @@
         'key': 'Shift',
         'location': 1,
         'metaState': RawKeyEventDataWeb.modifierShift,
+        'keyCode': 0x10,
       });
       final RawKeyEventDataWeb data = shiftKeyEvent.data as RawKeyEventDataWeb;
       expect(data.physicalKey, equals(PhysicalKeyboardKey.shiftLeft));
       expect(data.logicalKey, equals(LogicalKeyboardKey.shiftLeft));
       expect(data.keyLabel, isEmpty);
+      expect(data.keyCode, equals(0x10));
     });
 
     test('Arrow keys from a keyboard give correct physical key mappings', () {
@@ -2607,11 +2615,13 @@
         'key': 'ArrowDown',
         'location': 0,
         'metaState': 0x0,
+        'keyCode': 0x28,
       });
       final RawKeyEventDataWeb data = arrowKeyDown.data as RawKeyEventDataWeb;
       expect(data.physicalKey, equals(PhysicalKeyboardKey.arrowDown));
       expect(data.logicalKey, equals(LogicalKeyboardKey.arrowDown));
       expect(data.keyLabel, isEmpty);
+      expect(data.keyCode, equals(0x28));
     });
 
     test('Unrecognized keys are mapped to Web plane', () {
@@ -2631,6 +2641,7 @@
       expect(data.logicalKey.keyId, greaterThan(0x01700000000));
       expect(data.logicalKey.keyId, lessThan(0x01800000000));
       expect(data.keyLabel, isEmpty);
+      expect(data.keyCode, equals(0));
     });
 
     test('data.toString', () {
@@ -2641,8 +2652,9 @@
         'key': 'a',
         'location': 2,
         'metaState': 0x10,
+        'keyCode': 0x41,
       }).data.toString(), equalsIgnoringHashCodes(
-        'RawKeyEventDataWeb#00000(code: KeyA, key: a, location: 2, metaState: 16)'));
+        'RawKeyEventDataWeb#00000(code: KeyA, key: a, location: 2, metaState: 16, keyCode: 65)'));
 
       // Without location
       expect(RawKeyEvent.fromMessage(const <String, Object?>{
@@ -2651,8 +2663,9 @@
         'code': 'KeyA',
         'key': 'a',
         'metaState': 0x10,
+        'keyCode': 0x41,
       }).data.toString(), equalsIgnoringHashCodes(
-        'RawKeyEventDataWeb#00000(code: KeyA, key: a, location: 0, metaState: 16)'));
+        'RawKeyEventDataWeb#00000(code: KeyA, key: a, location: 0, metaState: 16, keyCode: 65)'));
     });
 
     test('data.equality', () {
@@ -2663,11 +2676,13 @@
         'key': 'a',
         'location': 2,
         'metaState': 0x10,
+        'keyCode': 0x41,
       }).data, const RawKeyEventDataWeb(
         key: 'a',
         code: 'KeyA',
         location: 2,
         metaState: 0x10,
+        keyCode: 0x41
       ));
 
       expect(RawKeyEvent.fromMessage(const <String, Object?>{
@@ -2677,6 +2692,7 @@
         'key': 'a',
         'location': 2,
         'metaState': 0x10,
+        'keyCode': 0x41,
       }).data, isNot(equals(const RawKeyEventDataWeb(code: 'KeyA', key: 'a'))));
     });
   });