Ignore key events on edit control on web platform (#52656) (#52661)

diff --git a/packages/flutter/lib/src/rendering/editable.dart b/packages/flutter/lib/src/rendering/editable.dart
index fa62b49..11e0f98 100644
--- a/packages/flutter/lib/src/rendering/editable.dart
+++ b/packages/flutter/lib/src/rendering/editable.dart
@@ -473,6 +473,11 @@
   // string using Unicode scalar values, rather than using the number of
   // extended grapheme clusters (a.k.a. "characters" in the end user's mind).
   void _handleKeyEvent(RawKeyEvent keyEvent) {
+    if(kIsWeb) {
+      // On web platform, we should ignore the key because it's processed already.
+      return;
+    }
+
     if (keyEvent is! RawKeyDownEvent || onSelectionChanged == null)
       return;
     final Set<LogicalKeyboardKey> keysPressed = LogicalKeyboardKey.collapseSynonyms(RawKeyboard.instance.keysPressed);
@@ -492,7 +497,7 @@
     final bool isLineModifierPressed = isMacOS ? keyEvent.isMetaPressed : keyEvent.isAltPressed;
     final bool isShortcutModifierPressed = isMacOS ? keyEvent.isMetaPressed : keyEvent.isControlPressed;
     if (_movementKeys.contains(key)) {
-        _handleMovement(key, wordModifier: isWordModifierPressed, lineModifier: isLineModifierPressed, shift: keyEvent.isShiftPressed);
+      _handleMovement(key, wordModifier: isWordModifierPressed, lineModifier: isLineModifierPressed, shift: keyEvent.isShiftPressed);
     } else if (isShortcutModifierPressed && _shortcutKeys.contains(key)) {
       // _handleShortcuts depends on being started in the same stack invocation
       // as the _handleKeyEvent method
diff --git a/packages/flutter/test/rendering/editable_test.dart b/packages/flutter/test/rendering/editable_test.dart
index c25d402..525083f 100644
--- a/packages/flutter/test/rendering/editable_test.dart
+++ b/packages/flutter/test/rendering/editable_test.dart
@@ -368,6 +368,58 @@
     expect(editable, paintsExactlyCountTimes(#drawRect, 1));
   }, skip: isBrowser);
 
+  test('ignore key event from web platform', () async {
+    final TextSelectionDelegate delegate = FakeEditableTextState();
+    final ViewportOffset viewportOffset = ViewportOffset.zero();
+    TextSelection currentSelection;
+    final RenderEditable editable = RenderEditable(
+      backgroundCursorColor: Colors.grey,
+      selectionColor: Colors.black,
+      textDirection: TextDirection.ltr,
+      cursorColor: Colors.red,
+      offset: viewportOffset,
+      // This makes the scroll axis vertical.
+      maxLines: 2,
+      textSelectionDelegate: delegate,
+      onSelectionChanged: (TextSelection selection, RenderEditable renderObject, SelectionChangedCause cause) {
+        currentSelection = selection;
+      },
+      startHandleLayerLink: LayerLink(),
+      endHandleLayerLink: LayerLink(),
+      text: const TextSpan(
+        text: 'test\ntest',
+        style: TextStyle(
+          height: 1.0, fontSize: 10.0, fontFamily: 'Ahem',
+        ),
+      ),
+      selection: const TextSelection.collapsed(
+        offset: 4,
+      ),
+    );
+
+    layout(editable);
+    editable.hasFocus = true;
+
+    expect(
+      editable,
+      paints..paragraph(offset: Offset.zero),
+    );
+
+    editable.selectPositionAt(from: const Offset(0, 0), cause: SelectionChangedCause.tap);
+    editable.selection = const TextSelection.collapsed(offset: 0);
+    pumpFrame();
+
+    if(kIsWeb) {
+      await simulateKeyDownEvent(LogicalKeyboardKey.arrowRight, platform: 'web');
+      expect(currentSelection.isCollapsed, true);
+      expect(currentSelection.baseOffset, 0);
+    } else {
+      await simulateKeyDownEvent(LogicalKeyboardKey.arrowRight, platform: 'android');
+      expect(currentSelection.isCollapsed, true);
+      expect(currentSelection.baseOffset, 1);
+    }
+  });
+
   test('selects correct place with offsets', () {
     final TextSelectionDelegate delegate = FakeEditableTextState();
     final ViewportOffset viewportOffset = ViewportOffset.zero();
diff --git a/packages/flutter_test/lib/src/event_simulation.dart b/packages/flutter_test/lib/src/event_simulation.dart
index 388d722..2a96d31 100644
--- a/packages/flutter_test/lib/src/event_simulation.dart
+++ b/packages/flutter_test/lib/src/event_simulation.dart
@@ -39,6 +39,7 @@
       case 'fuchsia':
       case 'macos':
       case 'linux':
+      case 'web':
         return true;
     }
     return false;
@@ -61,6 +62,9 @@
       case 'linux':
         map = kLinuxToPhysicalKey;
         break;
+      case 'web':
+      // web doesn't have int type code
+        return null;
     }
     for (final int code in map.keys) {
       if (key.usbHidUsage == map[code].usbHidUsage) {
@@ -85,6 +89,9 @@
       case 'macos':
       // macOS doesn't do key codes, just scan codes.
         return null;
+      case 'web':
+      // web doesn't have int type code
+        return null;
       case 'linux':
         map = kGlfwToLogicalKey;
         break;
@@ -97,10 +104,18 @@
     }
     return keyCode;
   }
+  static String _getWebKeyCode(LogicalKeyboardKey key) {
+    for (final String code in kWebToLogicalKey.keys) {
+      if (key.keyId == kWebToLogicalKey[code].keyId) {
+        return code;
+      }
+    }
+    return null;
+  }
 
   static PhysicalKeyboardKey _findPhysicalKey(LogicalKeyboardKey key, String platform) {
     assert(_osIsSupported(platform), 'Platform $platform not supported for key simulation');
-    Map<int, PhysicalKeyboardKey> map;
+    Map<dynamic, PhysicalKeyboardKey> map;
     switch (platform) {
       case 'android':
         map = kAndroidToPhysicalKey;
@@ -114,6 +129,9 @@
       case 'linux':
         map = kLinuxToPhysicalKey;
         break;
+      case 'web':
+        map = kWebToPhysicalKey;
+        break;
     }
     for (final PhysicalKeyboardKey physicalKey in map.values) {
       if (key.debugName == physicalKey.debugName) {
@@ -138,10 +156,10 @@
     physicalKey ??= _findPhysicalKey(key, platform);
 
     assert(key.debugName != null);
-    final int keyCode = platform == 'macos' ? -1 : _getKeyCode(key, platform);
-    assert(platform == 'macos' || keyCode != null, 'Key $key not found in $platform keyCode map');
-    final int scanCode = _getScanCode(physicalKey, platform);
-    assert(scanCode != null, 'Physical key for $key not found in $platform scanCode map');
+    final int keyCode = platform == 'macos' || platform == 'web' ? -1 : _getKeyCode(key, platform);
+    assert(platform == 'macos' || platform == 'web' || keyCode != null, 'Key $key not found in $platform keyCode map');
+    final int scanCode = platform == 'web' ? -1 : _getScanCode(physicalKey, platform);
+    assert(platform == 'web' || scanCode != null, 'Physical key for $key not found in $platform scanCode map');
 
     final Map<String, dynamic> result = <String, dynamic>{
       'type': isDown ? 'keydown' : 'keyup',
@@ -173,6 +191,10 @@
         result['charactersIgnoringModifiers'] = key.keyLabel;
         result['modifiers'] = _getMacOsModifierFlags(key, isDown);
         break;
+      case 'web':
+        result['code'] = _getWebKeyCode(key);
+        result['key'] = '';
+        result['metaState'] = _getWebModifierFlags(key, isDown);
     }
     return result;
   }
@@ -288,6 +310,50 @@
     return result;
   }
 
+  static int _getWebModifierFlags(LogicalKeyboardKey newKey, bool isDown) {
+    int result = 0;
+    final Set<LogicalKeyboardKey> pressed = RawKeyboard.instance.keysPressed;
+    if (isDown) {
+      pressed.add(newKey);
+    } else {
+      pressed.remove(newKey);
+    }
+    if (pressed.contains(LogicalKeyboardKey.shiftLeft)) {
+      result |= RawKeyEventDataWeb.modifierShift;
+    }
+    if (pressed.contains(LogicalKeyboardKey.shiftRight)) {
+      result |= RawKeyEventDataWeb.modifierShift;
+    }
+    if (pressed.contains(LogicalKeyboardKey.metaLeft)) {
+      result |= RawKeyEventDataWeb.modifierMeta;
+    }
+    if (pressed.contains(LogicalKeyboardKey.metaRight)) {
+      result |= RawKeyEventDataWeb.modifierMeta;
+    }
+    if (pressed.contains(LogicalKeyboardKey.controlLeft)) {
+      result |= RawKeyEventDataWeb.modifierControl;
+    }
+    if (pressed.contains(LogicalKeyboardKey.controlRight)) {
+      result |= RawKeyEventDataWeb.modifierControl;
+    }
+    if (pressed.contains(LogicalKeyboardKey.altLeft)) {
+      result |= RawKeyEventDataWeb.modifierAlt;
+    }
+    if (pressed.contains(LogicalKeyboardKey.altRight)) {
+      result |= RawKeyEventDataWeb.modifierAlt;
+    }
+    if (pressed.contains(LogicalKeyboardKey.capsLock)) {
+      result |= RawKeyEventDataWeb.modifierCapsLock;
+    }
+    if (pressed.contains(LogicalKeyboardKey.numLock)) {
+      result |= RawKeyEventDataWeb.modifierNumLock;
+    }
+    if (pressed.contains(LogicalKeyboardKey.scrollLock)) {
+      result |= RawKeyEventDataWeb.modifierScrollLock;
+    }
+    return result;
+  }
+
   static int _getMacOsModifierFlags(LogicalKeyboardKey newKey, bool isDown) {
     int result = 0;
     final Set<LogicalKeyboardKey> pressed = RawKeyboard.instance.keysPressed;