[gen_keycodes] Remove nonexistent Web keys and improve their emulation (#87098)

diff --git a/dev/tools/gen_keycodes/data/logical_key_data.json b/dev/tools/gen_keycodes/data/logical_key_data.json
index fab6a3c..1143b52 100644
--- a/dev/tools/gen_keycodes/data/logical_key_data.json
+++ b/dev/tools/gen_keycodes/data/logical_key_data.json
@@ -4,9 +4,6 @@
     "value": 32,
     "keyLabel": " ",
     "names": {
-      "web": [
-        "Space"
-      ],
       "gtk": [
         "KP_Space"
       ],
@@ -41,21 +38,13 @@
   "Exclamation": {
     "name": "Exclamation",
     "value": 33,
-    "keyLabel": "!",
-    "names": {
-      "web": [
-        "Exclamation"
-      ]
-    }
+    "keyLabel": "!"
   },
   "Quote": {
     "name": "Quote",
     "value": 34,
     "keyLabel": "\"",
     "names": {
-      "web": [
-        "Quote"
-      ],
       "windows": [
         "OEM_7"
       ],
@@ -86,9 +75,6 @@
     "value": 35,
     "keyLabel": "#",
     "names": {
-      "web": [
-        "NumberSign"
-      ],
       "android": [
         "POUND"
       ]
@@ -102,71 +88,38 @@
   "Dollar": {
     "name": "Dollar",
     "value": 36,
-    "keyLabel": "$",
-    "names": {
-      "web": [
-        "Dollar"
-      ]
-    }
+    "keyLabel": "$"
   },
   "Percent": {
     "name": "Percent",
     "value": 37,
-    "keyLabel": "%",
-    "names": {
-      "web": [
-        "Percent"
-      ]
-    }
+    "keyLabel": "%"
   },
   "Ampersand": {
     "name": "Ampersand",
     "value": 38,
-    "keyLabel": "&",
-    "names": {
-      "web": [
-        "Ampersand"
-      ]
-    }
+    "keyLabel": "&"
   },
   "QuoteSingle": {
     "name": "QuoteSingle",
     "value": 39,
-    "keyLabel": "'",
-    "names": {
-      "web": [
-        "QuoteSingle"
-      ]
-    }
+    "keyLabel": "'"
   },
   "ParenthesisLeft": {
     "name": "ParenthesisLeft",
     "value": 40,
-    "keyLabel": "(",
-    "names": {
-      "web": [
-        "ParenthesisLeft"
-      ]
-    }
+    "keyLabel": "("
   },
   "ParenthesisRight": {
     "name": "ParenthesisRight",
     "value": 41,
-    "keyLabel": ")",
-    "names": {
-      "web": [
-        "ParenthesisRight"
-      ]
-    }
+    "keyLabel": ")"
   },
   "Asterisk": {
     "name": "Asterisk",
     "value": 42,
     "keyLabel": "*",
     "names": {
-      "web": [
-        "Asterisk"
-      ],
       "android": [
         "STAR"
       ]
@@ -182,9 +135,6 @@
     "value": 43,
     "keyLabel": "+",
     "names": {
-      "web": [
-        "Add"
-      ],
       "android": [
         "PLUS"
       ]
@@ -200,9 +150,6 @@
     "value": 44,
     "keyLabel": ",",
     "names": {
-      "web": [
-        "Comma"
-      ],
       "windows": [
         "OEM_COMMA"
       ],
@@ -233,9 +180,6 @@
     "value": 45,
     "keyLabel": "-",
     "names": {
-      "web": [
-        "Minus"
-      ],
       "windows": [
         "OEM_MINUS"
       ],
@@ -266,9 +210,6 @@
     "value": 46,
     "keyLabel": ".",
     "names": {
-      "web": [
-        "Period"
-      ],
       "gtk": [
         "KP_Decimal"
       ],
@@ -305,9 +246,6 @@
     "value": 47,
     "keyLabel": "/",
     "names": {
-      "web": [
-        "Slash"
-      ],
       "windows": [
         "OEM_2"
       ],
@@ -338,9 +276,6 @@
     "value": 48,
     "keyLabel": "0",
     "names": {
-      "web": [
-        "Digit0"
-      ],
       "android": [
         "0"
       ],
@@ -365,9 +300,6 @@
     "value": 49,
     "keyLabel": "1",
     "names": {
-      "web": [
-        "Digit1"
-      ],
       "android": [
         "1"
       ],
@@ -392,9 +324,6 @@
     "value": 50,
     "keyLabel": "2",
     "names": {
-      "web": [
-        "Digit2"
-      ],
       "android": [
         "2"
       ],
@@ -419,9 +348,6 @@
     "value": 51,
     "keyLabel": "3",
     "names": {
-      "web": [
-        "Digit3"
-      ],
       "android": [
         "3"
       ],
@@ -446,9 +372,6 @@
     "value": 52,
     "keyLabel": "4",
     "names": {
-      "web": [
-        "Digit4"
-      ],
       "android": [
         "4"
       ],
@@ -473,9 +396,6 @@
     "value": 53,
     "keyLabel": "5",
     "names": {
-      "web": [
-        "Digit5"
-      ],
       "android": [
         "5"
       ],
@@ -500,9 +420,6 @@
     "value": 54,
     "keyLabel": "6",
     "names": {
-      "web": [
-        "Digit6"
-      ],
       "android": [
         "6"
       ],
@@ -527,9 +444,6 @@
     "value": 55,
     "keyLabel": "7",
     "names": {
-      "web": [
-        "Digit7"
-      ],
       "android": [
         "7"
       ],
@@ -554,9 +468,6 @@
     "value": 56,
     "keyLabel": "8",
     "names": {
-      "web": [
-        "Digit8"
-      ],
       "android": [
         "8"
       ],
@@ -581,9 +492,6 @@
     "value": 57,
     "keyLabel": "9",
     "names": {
-      "web": [
-        "Digit9"
-      ],
       "android": [
         "9"
       ],
@@ -606,21 +514,13 @@
   "Colon": {
     "name": "Colon",
     "value": 58,
-    "keyLabel": ":",
-    "names": {
-      "web": [
-        "Colon"
-      ]
-    }
+    "keyLabel": ":"
   },
   "Semicolon": {
     "name": "Semicolon",
     "value": 59,
     "keyLabel": ";",
     "names": {
-      "web": [
-        "Semicolon"
-      ],
       "windows": [
         "OEM_1"
       ],
@@ -649,21 +549,13 @@
   "Less": {
     "name": "Less",
     "value": 60,
-    "keyLabel": "<",
-    "names": {
-      "web": [
-        "Less"
-      ]
-    }
+    "keyLabel": "<"
   },
   "Equal": {
     "name": "Equal",
     "value": 61,
     "keyLabel": "=",
     "names": {
-      "web": [
-        "Equal"
-      ],
       "windows": [
         "OEM_PLUS"
       ],
@@ -692,31 +584,18 @@
   "Greater": {
     "name": "Greater",
     "value": 62,
-    "keyLabel": ">",
-    "names": {
-      "web": [
-        "Greater"
-      ]
-    }
+    "keyLabel": ">"
   },
   "Question": {
     "name": "Question",
     "value": 63,
-    "keyLabel": "?",
-    "names": {
-      "web": [
-        "Question"
-      ]
-    }
+    "keyLabel": "?"
   },
   "At": {
     "name": "At",
     "value": 64,
     "keyLabel": "@",
     "names": {
-      "web": [
-        "At"
-      ],
       "android": [
         "AT"
       ]
@@ -732,9 +611,6 @@
     "value": 91,
     "keyLabel": "[",
     "names": {
-      "web": [
-        "BracketLeft"
-      ],
       "windows": [
         "OEM_4"
       ],
@@ -765,9 +641,6 @@
     "value": 92,
     "keyLabel": "\\",
     "names": {
-      "web": [
-        "Backslash"
-      ],
       "windows": [
         "OEM_5"
       ],
@@ -798,9 +671,6 @@
     "value": 93,
     "keyLabel": "]",
     "names": {
-      "web": [
-        "BracketRight"
-      ],
       "windows": [
         "OEM_6"
       ],
@@ -829,31 +699,18 @@
   "Caret": {
     "name": "Caret",
     "value": 94,
-    "keyLabel": "^",
-    "names": {
-      "web": [
-        "Caret"
-      ]
-    }
+    "keyLabel": "^"
   },
   "Underscore": {
     "name": "Underscore",
     "value": 95,
-    "keyLabel": "_",
-    "names": {
-      "web": [
-        "Underscore"
-      ]
-    }
+    "keyLabel": "_"
   },
   "Backquote": {
     "name": "Backquote",
     "value": 96,
     "keyLabel": "`",
     "names": {
-      "web": [
-        "Backquote"
-      ],
       "windows": [
         "OEM_3"
       ],
@@ -884,9 +741,6 @@
     "value": 97,
     "keyLabel": "a",
     "names": {
-      "web": [
-        "KeyA"
-      ],
       "android": [
         "A"
       ],
@@ -911,9 +765,6 @@
     "value": 98,
     "keyLabel": "b",
     "names": {
-      "web": [
-        "KeyB"
-      ],
       "android": [
         "B"
       ],
@@ -938,9 +789,6 @@
     "value": 99,
     "keyLabel": "c",
     "names": {
-      "web": [
-        "KeyC"
-      ],
       "android": [
         "C"
       ],
@@ -965,9 +813,6 @@
     "value": 100,
     "keyLabel": "d",
     "names": {
-      "web": [
-        "KeyD"
-      ],
       "android": [
         "D"
       ],
@@ -992,9 +837,6 @@
     "value": 101,
     "keyLabel": "e",
     "names": {
-      "web": [
-        "KeyE"
-      ],
       "android": [
         "E"
       ],
@@ -1019,9 +861,6 @@
     "value": 102,
     "keyLabel": "f",
     "names": {
-      "web": [
-        "KeyF"
-      ],
       "android": [
         "F"
       ],
@@ -1046,9 +885,6 @@
     "value": 103,
     "keyLabel": "g",
     "names": {
-      "web": [
-        "KeyG"
-      ],
       "android": [
         "G"
       ],
@@ -1073,9 +909,6 @@
     "value": 104,
     "keyLabel": "h",
     "names": {
-      "web": [
-        "KeyH"
-      ],
       "android": [
         "H"
       ],
@@ -1100,9 +933,6 @@
     "value": 105,
     "keyLabel": "i",
     "names": {
-      "web": [
-        "KeyI"
-      ],
       "android": [
         "I"
       ],
@@ -1127,9 +957,6 @@
     "value": 106,
     "keyLabel": "j",
     "names": {
-      "web": [
-        "KeyJ"
-      ],
       "android": [
         "J"
       ],
@@ -1154,9 +981,6 @@
     "value": 107,
     "keyLabel": "k",
     "names": {
-      "web": [
-        "KeyK"
-      ],
       "android": [
         "K"
       ],
@@ -1181,9 +1005,6 @@
     "value": 108,
     "keyLabel": "l",
     "names": {
-      "web": [
-        "KeyL"
-      ],
       "android": [
         "L"
       ],
@@ -1208,9 +1029,6 @@
     "value": 109,
     "keyLabel": "m",
     "names": {
-      "web": [
-        "KeyM"
-      ],
       "android": [
         "M"
       ],
@@ -1235,9 +1053,6 @@
     "value": 110,
     "keyLabel": "n",
     "names": {
-      "web": [
-        "KeyN"
-      ],
       "android": [
         "N"
       ],
@@ -1262,9 +1077,6 @@
     "value": 111,
     "keyLabel": "o",
     "names": {
-      "web": [
-        "KeyO"
-      ],
       "android": [
         "O"
       ],
@@ -1289,9 +1101,6 @@
     "value": 112,
     "keyLabel": "p",
     "names": {
-      "web": [
-        "KeyP"
-      ],
       "android": [
         "P"
       ],
@@ -1316,9 +1125,6 @@
     "value": 113,
     "keyLabel": "q",
     "names": {
-      "web": [
-        "KeyQ"
-      ],
       "android": [
         "Q"
       ],
@@ -1343,9 +1149,6 @@
     "value": 114,
     "keyLabel": "r",
     "names": {
-      "web": [
-        "KeyR"
-      ],
       "android": [
         "R"
       ],
@@ -1370,9 +1173,6 @@
     "value": 115,
     "keyLabel": "s",
     "names": {
-      "web": [
-        "KeyS"
-      ],
       "android": [
         "S"
       ],
@@ -1397,9 +1197,6 @@
     "value": 116,
     "keyLabel": "t",
     "names": {
-      "web": [
-        "KeyT"
-      ],
       "android": [
         "T"
       ],
@@ -1424,9 +1221,6 @@
     "value": 117,
     "keyLabel": "u",
     "names": {
-      "web": [
-        "KeyU"
-      ],
       "android": [
         "U"
       ],
@@ -1451,9 +1245,6 @@
     "value": 118,
     "keyLabel": "v",
     "names": {
-      "web": [
-        "KeyV"
-      ],
       "android": [
         "V"
       ],
@@ -1478,9 +1269,6 @@
     "value": 119,
     "keyLabel": "w",
     "names": {
-      "web": [
-        "KeyW"
-      ],
       "android": [
         "W"
       ],
@@ -1505,9 +1293,6 @@
     "value": 120,
     "keyLabel": "x",
     "names": {
-      "web": [
-        "KeyX"
-      ],
       "android": [
         "X"
       ],
@@ -1532,9 +1317,6 @@
     "value": 121,
     "keyLabel": "y",
     "names": {
-      "web": [
-        "KeyY"
-      ],
       "android": [
         "Y"
       ],
@@ -1559,9 +1341,6 @@
     "value": 122,
     "keyLabel": "z",
     "names": {
-      "web": [
-        "KeyZ"
-      ],
       "android": [
         "Z"
       ],
@@ -1584,42 +1363,22 @@
   "BraceLeft": {
     "name": "BraceLeft",
     "value": 123,
-    "keyLabel": "{",
-    "names": {
-      "web": [
-        "BraceLeft"
-      ]
-    }
+    "keyLabel": "{"
   },
   "Bar": {
     "name": "Bar",
     "value": 124,
-    "keyLabel": "|",
-    "names": {
-      "web": [
-        "Bar"
-      ]
-    }
+    "keyLabel": "|"
   },
   "BraceRight": {
     "name": "BraceRight",
     "value": 125,
-    "keyLabel": "}",
-    "names": {
-      "web": [
-        "BraceRight"
-      ]
-    }
+    "keyLabel": "}"
   },
   "Tilde": {
     "name": "Tilde",
     "value": 126,
-    "keyLabel": "~",
-    "names": {
-      "web": [
-        "Tilde"
-      ]
-    }
+    "keyLabel": "~"
   },
   "Unidentified": {
     "name": "Unidentified",
@@ -1633,7 +1392,6 @@
   "Backspace": {
     "name": "Backspace",
     "value": 4294967304,
-    "keyLabel": "\b",
     "names": {
       "web": [
         "Backspace"
@@ -1684,7 +1442,6 @@
   "Tab": {
     "name": "Tab",
     "value": 4294967305,
-    "keyLabel": "\t",
     "names": {
       "web": [
         "Tab"
@@ -1739,7 +1496,6 @@
   "Enter": {
     "name": "Enter",
     "value": 4294967309,
-    "keyLabel": "\r",
     "names": {
       "web": [
         "Enter"
@@ -1794,7 +1550,6 @@
   "Escape": {
     "name": "Escape",
     "value": 4294967323,
-    "keyLabel": "\u001b",
     "names": {
       "web": [
         "Escape"
@@ -1845,7 +1600,6 @@
   "Delete": {
     "name": "Delete",
     "value": 4294967423,
-    "keyLabel": "",
     "names": {
       "web": [
         "Delete"
@@ -7866,9 +7620,6 @@
     "name": "Suspend",
     "value": 8589934592,
     "names": {
-      "web": [
-        "Suspend"
-      ],
       "gtk": [
         "Suspend"
       ]
@@ -7885,11 +7636,6 @@
   "Resume": {
     "name": "Resume",
     "value": 8589934593,
-    "names": {
-      "web": [
-        "Resume"
-      ]
-    },
     "values": {
       "fuchsia": [
         77309411349
@@ -7900,9 +7646,6 @@
     "name": "Sleep",
     "value": 8589934594,
     "names": {
-      "web": [
-        "Sleep"
-      ],
       "gtk": [
         "Sleep"
       ],
@@ -7931,11 +7674,6 @@
   "Abort": {
     "name": "Abort",
     "value": 8589934595,
-    "names": {
-      "web": [
-        "Abort"
-      ]
-    },
     "values": {
       "fuchsia": [
         77309870235
@@ -7946,9 +7684,6 @@
     "name": "Lang1",
     "value": 8589934608,
     "names": {
-      "web": [
-        "Lang1"
-      ],
       "macos": [
         "Lang1"
       ],
@@ -7978,9 +7713,6 @@
     "name": "Lang2",
     "value": 8589934609,
     "names": {
-      "web": [
-        "Lang2"
-      ],
       "macos": [
         "Lang2"
       ],
@@ -8004,9 +7736,6 @@
     "name": "Lang3",
     "value": 8589934610,
     "names": {
-      "web": [
-        "Lang3"
-      ],
       "ios": [
         "Lang3"
       ]
@@ -8024,9 +7753,6 @@
     "name": "Lang4",
     "value": 8589934611,
     "names": {
-      "web": [
-        "Lang4"
-      ],
       "ios": [
         "Lang4"
       ]
@@ -8044,9 +7770,6 @@
     "name": "Lang5",
     "value": 8589934612,
     "names": {
-      "web": [
-        "Lang5"
-      ],
       "ios": [
         "Lang5"
       ]
@@ -8063,11 +7786,6 @@
   "IntlBackslash": {
     "name": "IntlBackslash",
     "value": 8589934624,
-    "names": {
-      "web": [
-        "IntlBackslash"
-      ]
-    },
     "values": {
       "fuchsia": [
         77309870180
@@ -8078,9 +7796,6 @@
     "name": "IntlRo",
     "value": 8589934625,
     "names": {
-      "web": [
-        "IntlRo"
-      ],
       "macos": [
         "IntlRo"
       ],
@@ -8110,9 +7825,6 @@
     "name": "IntlYen",
     "value": 8589934626,
     "names": {
-      "web": [
-        "IntlYen"
-      ],
       "macos": [
         "IntlYen"
       ],
@@ -8148,9 +7860,6 @@
     "name": "ControlLeft",
     "value": 8589934848,
     "names": {
-      "web": [
-        "ControlLeft"
-      ],
       "macos": [
         "ControlLeft"
       ],
@@ -8200,9 +7909,6 @@
     "name": "ControlRight",
     "value": 8589934849,
     "names": {
-      "web": [
-        "ControlRight"
-      ],
       "macos": [
         "ControlRight"
       ],
@@ -8250,9 +7956,6 @@
     "name": "ShiftLeft",
     "value": 8589934850,
     "names": {
-      "web": [
-        "ShiftLeft"
-      ],
       "macos": [
         "ShiftLeft"
       ],
@@ -8302,9 +8005,6 @@
     "name": "ShiftRight",
     "value": 8589934851,
     "names": {
-      "web": [
-        "ShiftRight"
-      ],
       "macos": [
         "ShiftRight"
       ],
@@ -8352,9 +8052,6 @@
     "name": "AltLeft",
     "value": 8589934852,
     "names": {
-      "web": [
-        "AltLeft"
-      ],
       "macos": [
         "AltLeft"
       ],
@@ -8402,9 +8099,6 @@
     "name": "AltRight",
     "value": 8589934853,
     "names": {
-      "web": [
-        "AltRight"
-      ],
       "macos": [
         "AltRight"
       ],
@@ -8454,9 +8148,6 @@
     "name": "MetaLeft",
     "value": 8589934854,
     "names": {
-      "web": [
-        "MetaLeft"
-      ],
       "macos": [
         "MetaLeft"
       ],
@@ -8504,9 +8195,6 @@
     "name": "MetaRight",
     "value": 8589934855,
     "names": {
-      "web": [
-        "MetaRight"
-      ],
       "macos": [
         "MetaRight"
       ],
@@ -8552,47 +8240,24 @@
   },
   "Control": {
     "name": "Control",
-    "value": 8589935088,
-    "names": {
-      "web": [
-        "Control"
-      ]
-    }
+    "value": 8589935088
   },
   "Shift": {
     "name": "Shift",
-    "value": 8589935090,
-    "names": {
-      "web": [
-        "Shift"
-      ]
-    }
+    "value": 8589935090
   },
   "Alt": {
     "name": "Alt",
-    "value": 8589935092,
-    "names": {
-      "web": [
-        "Alt"
-      ]
-    }
+    "value": 8589935092
   },
   "Meta": {
     "name": "Meta",
-    "value": 8589935094,
-    "names": {
-      "web": [
-        "Meta"
-      ]
-    }
+    "value": 8589935094
   },
   "NumpadEnter": {
     "name": "NumpadEnter",
     "value": 8589935117,
     "names": {
-      "web": [
-        "NumpadEnter"
-      ],
       "macos": [
         "NumpadEnter"
       ],
@@ -8634,9 +8299,6 @@
     "name": "NumpadParenLeft",
     "value": 8589935144,
     "names": {
-      "web": [
-        "NumpadParenLeft"
-      ],
       "android": [
         "NUMPAD_LEFT_PAREN"
       ]
@@ -8654,9 +8316,6 @@
     "name": "NumpadParenRight",
     "value": 8589935145,
     "names": {
-      "web": [
-        "NumpadParenRight"
-      ],
       "android": [
         "NUMPAD_RIGHT_PAREN"
       ]
@@ -8674,9 +8333,6 @@
     "name": "NumpadMultiply",
     "value": 8589935146,
     "names": {
-      "web": [
-        "NumpadMultiply"
-      ],
       "macos": [
         "NumpadMultiply"
       ],
@@ -8724,9 +8380,6 @@
     "name": "NumpadAdd",
     "value": 8589935147,
     "names": {
-      "web": [
-        "NumpadAdd"
-      ],
       "macos": [
         "NumpadAdd"
       ],
@@ -8774,9 +8427,6 @@
     "name": "NumpadComma",
     "value": 8589935148,
     "names": {
-      "web": [
-        "NumpadComma"
-      ],
       "macos": [
         "NumpadComma"
       ],
@@ -8812,9 +8462,6 @@
     "name": "NumpadSubtract",
     "value": 8589935149,
     "names": {
-      "web": [
-        "NumpadSubtract"
-      ],
       "macos": [
         "NumpadSubtract"
       ],
@@ -8856,9 +8503,6 @@
     "name": "NumpadDecimal",
     "value": 8589935150,
     "names": {
-      "web": [
-        "NumpadDecimal"
-      ],
       "macos": [
         "NumpadDecimal"
       ],
@@ -8906,9 +8550,6 @@
     "name": "NumpadDivide",
     "value": 8589935151,
     "names": {
-      "web": [
-        "NumpadDivide"
-      ],
       "macos": [
         "NumpadDivide"
       ],
@@ -8956,9 +8597,6 @@
     "name": "Numpad0",
     "value": 8589935152,
     "names": {
-      "web": [
-        "Numpad0"
-      ],
       "macos": [
         "Numpad0"
       ],
@@ -9008,9 +8646,6 @@
     "name": "Numpad1",
     "value": 8589935153,
     "names": {
-      "web": [
-        "Numpad1"
-      ],
       "macos": [
         "Numpad1"
       ],
@@ -9060,9 +8695,6 @@
     "name": "Numpad2",
     "value": 8589935154,
     "names": {
-      "web": [
-        "Numpad2"
-      ],
       "macos": [
         "Numpad2"
       ],
@@ -9112,9 +8744,6 @@
     "name": "Numpad3",
     "value": 8589935155,
     "names": {
-      "web": [
-        "Numpad3"
-      ],
       "macos": [
         "Numpad3"
       ],
@@ -9164,9 +8793,6 @@
     "name": "Numpad4",
     "value": 8589935156,
     "names": {
-      "web": [
-        "Numpad4"
-      ],
       "macos": [
         "Numpad4"
       ],
@@ -9216,9 +8842,6 @@
     "name": "Numpad5",
     "value": 8589935157,
     "names": {
-      "web": [
-        "Numpad5"
-      ],
       "macos": [
         "Numpad5"
       ],
@@ -9266,9 +8889,6 @@
     "name": "Numpad6",
     "value": 8589935158,
     "names": {
-      "web": [
-        "Numpad6"
-      ],
       "macos": [
         "Numpad6"
       ],
@@ -9318,9 +8938,6 @@
     "name": "Numpad7",
     "value": 8589935159,
     "names": {
-      "web": [
-        "Numpad7"
-      ],
       "macos": [
         "Numpad7"
       ],
@@ -9370,9 +8987,6 @@
     "name": "Numpad8",
     "value": 8589935160,
     "names": {
-      "web": [
-        "Numpad8"
-      ],
       "macos": [
         "Numpad8"
       ],
@@ -9422,9 +9036,6 @@
     "name": "Numpad9",
     "value": 8589935161,
     "names": {
-      "web": [
-        "Numpad9"
-      ],
       "macos": [
         "Numpad9"
       ],
@@ -9474,9 +9085,6 @@
     "name": "NumpadEqual",
     "value": 8589935165,
     "names": {
-      "web": [
-        "NumpadEqual"
-      ],
       "macos": [
         "NumpadEqual"
       ],
@@ -9524,9 +9132,6 @@
     "name": "GameButton1",
     "value": 8589935361,
     "names": {
-      "web": [
-        "GameButton1"
-      ],
       "android": [
         "BUTTON_1"
       ]
@@ -9544,9 +9149,6 @@
     "name": "GameButton2",
     "value": 8589935362,
     "names": {
-      "web": [
-        "GameButton2"
-      ],
       "android": [
         "BUTTON_2"
       ]
@@ -9564,9 +9166,6 @@
     "name": "GameButton3",
     "value": 8589935363,
     "names": {
-      "web": [
-        "GameButton3"
-      ],
       "android": [
         "BUTTON_3"
       ]
@@ -9584,9 +9183,6 @@
     "name": "GameButton4",
     "value": 8589935364,
     "names": {
-      "web": [
-        "GameButton4"
-      ],
       "android": [
         "BUTTON_4"
       ]
@@ -9604,9 +9200,6 @@
     "name": "GameButton5",
     "value": 8589935365,
     "names": {
-      "web": [
-        "GameButton5"
-      ],
       "android": [
         "BUTTON_5"
       ]
@@ -9624,9 +9217,6 @@
     "name": "GameButton6",
     "value": 8589935366,
     "names": {
-      "web": [
-        "GameButton6"
-      ],
       "android": [
         "BUTTON_6"
       ]
@@ -9644,9 +9234,6 @@
     "name": "GameButton7",
     "value": 8589935367,
     "names": {
-      "web": [
-        "GameButton7"
-      ],
       "android": [
         "BUTTON_7"
       ]
@@ -9664,9 +9251,6 @@
     "name": "GameButton8",
     "value": 8589935368,
     "names": {
-      "web": [
-        "GameButton8"
-      ],
       "windows": [
         "GAMEPAD_A"
       ],
@@ -9690,9 +9274,6 @@
     "name": "GameButton9",
     "value": 8589935369,
     "names": {
-      "web": [
-        "GameButton9"
-      ],
       "windows": [
         "GAMEPAD_B"
       ],
@@ -9716,9 +9297,6 @@
     "name": "GameButton10",
     "value": 8589935370,
     "names": {
-      "web": [
-        "GameButton10"
-      ],
       "windows": [
         "GAMEPAD_X"
       ],
@@ -9742,9 +9320,6 @@
     "name": "GameButton11",
     "value": 8589935371,
     "names": {
-      "web": [
-        "GameButton11"
-      ],
       "windows": [
         "GAMEPAD_Y"
       ],
@@ -9768,9 +9343,6 @@
     "name": "GameButton12",
     "value": 8589935372,
     "names": {
-      "web": [
-        "GameButton12"
-      ],
       "windows": [
         "GAMEPAD_RIGHT_SHOULDER"
       ],
@@ -9794,9 +9366,6 @@
     "name": "GameButton13",
     "value": 8589935373,
     "names": {
-      "web": [
-        "GameButton13"
-      ],
       "windows": [
         "GAMEPAD_LEFT_SHOULDER"
       ],
@@ -9820,9 +9389,6 @@
     "name": "GameButton14",
     "value": 8589935374,
     "names": {
-      "web": [
-        "GameButton14"
-      ],
       "windows": [
         "GAMEPAD_LEFT_TRIGGER"
       ],
@@ -9846,9 +9412,6 @@
     "name": "GameButton15",
     "value": 8589935375,
     "names": {
-      "web": [
-        "GameButton15"
-      ],
       "windows": [
         "GAMEPAD_RIGHT_TRIGGER"
       ],
@@ -9872,9 +9435,6 @@
     "name": "GameButton16",
     "value": 8589935376,
     "names": {
-      "web": [
-        "GameButton16"
-      ],
       "windows": [
         "GAMEPAD_DPAD_UP"
       ],
@@ -9898,9 +9458,6 @@
     "name": "GameButtonA",
     "value": 8589935377,
     "names": {
-      "web": [
-        "GameButtonA"
-      ],
       "android": [
         "BUTTON_A"
       ]
@@ -9918,9 +9475,6 @@
     "name": "GameButtonB",
     "value": 8589935378,
     "names": {
-      "web": [
-        "GameButtonB"
-      ],
       "android": [
         "BUTTON_B"
       ]
@@ -9938,9 +9492,6 @@
     "name": "GameButtonC",
     "value": 8589935379,
     "names": {
-      "web": [
-        "GameButtonC"
-      ],
       "android": [
         "BUTTON_C"
       ]
@@ -9958,9 +9509,6 @@
     "name": "GameButtonLeft1",
     "value": 8589935380,
     "names": {
-      "web": [
-        "GameButtonLeft1"
-      ],
       "android": [
         "BUTTON_L1"
       ]
@@ -9978,9 +9526,6 @@
     "name": "GameButtonLeft2",
     "value": 8589935381,
     "names": {
-      "web": [
-        "GameButtonLeft2"
-      ],
       "android": [
         "BUTTON_L2"
       ]
@@ -9998,9 +9543,6 @@
     "name": "GameButtonMode",
     "value": 8589935382,
     "names": {
-      "web": [
-        "GameButtonMode"
-      ],
       "android": [
         "BUTTON_MODE"
       ]
@@ -10018,9 +9560,6 @@
     "name": "GameButtonRight1",
     "value": 8589935383,
     "names": {
-      "web": [
-        "GameButtonRight1"
-      ],
       "android": [
         "BUTTON_R1"
       ]
@@ -10038,9 +9577,6 @@
     "name": "GameButtonRight2",
     "value": 8589935384,
     "names": {
-      "web": [
-        "GameButtonRight2"
-      ],
       "android": [
         "BUTTON_R2"
       ]
@@ -10058,9 +9594,6 @@
     "name": "GameButtonSelect",
     "value": 8589935385,
     "names": {
-      "web": [
-        "GameButtonSelect"
-      ],
       "android": [
         "BUTTON_SELECT"
       ]
@@ -10078,9 +9611,6 @@
     "name": "GameButtonStart",
     "value": 8589935386,
     "names": {
-      "web": [
-        "GameButtonStart"
-      ],
       "android": [
         "BUTTON_START"
       ]
@@ -10098,9 +9628,6 @@
     "name": "GameButtonThumbLeft",
     "value": 8589935387,
     "names": {
-      "web": [
-        "GameButtonThumbLeft"
-      ],
       "android": [
         "BUTTON_THUMBL"
       ]
@@ -10118,9 +9645,6 @@
     "name": "GameButtonThumbRight",
     "value": 8589935388,
     "names": {
-      "web": [
-        "GameButtonThumbRight"
-      ],
       "android": [
         "BUTTON_THUMBR"
       ]
@@ -10138,9 +9662,6 @@
     "name": "GameButtonX",
     "value": 8589935389,
     "names": {
-      "web": [
-        "GameButtonX"
-      ],
       "android": [
         "BUTTON_X"
       ]
@@ -10158,9 +9679,6 @@
     "name": "GameButtonY",
     "value": 8589935390,
     "names": {
-      "web": [
-        "GameButtonY"
-      ],
       "android": [
         "BUTTON_Y"
       ]
@@ -10178,9 +9696,6 @@
     "name": "GameButtonZ",
     "value": 8589935391,
     "names": {
-      "web": [
-        "GameButtonZ"
-      ],
       "android": [
         "BUTTON_Z"
       ]
diff --git a/dev/tools/gen_keycodes/lib/logical_key_data.dart b/dev/tools/gen_keycodes/lib/logical_key_data.dart
index a26d4b5..9941902 100644
--- a/dev/tools/gen_keycodes/lib/logical_key_data.dart
+++ b/dev/tools/gen_keycodes/lib/logical_key_data.dart
@@ -11,11 +11,7 @@
 import 'constants.dart';
 import 'physical_key_data.dart';
 
-bool _isControlCharacter(String label) {
-  if (label.length != 1) {
-    return false;
-  }
-  final int codeUnit = label.codeUnitAt(0);
+bool _isControlCharacter(int codeUnit) {
   return (codeUnit <= 0x1f && codeUnit >= 0x00) || (codeUnit >= 0x7f && codeUnit <= 0x9f);
 }
 
@@ -27,8 +23,11 @@
   final String right;
 }
 
-List<T> _toNonEmptyArray<T>(dynamic source) {
-  final List<dynamic>? dynamicNullableList = source as List<dynamic>?;
+// Return map[key1][key2] as a non-nullable List<T>, where both map[key1] or
+// map[key1][key2] might be null.
+List<T> _getGrandchildList<T>(Map<String, dynamic> map, String key1, String key2) {
+  final dynamic value = (map[key1] as Map<String, dynamic>?)?[key2];
+  final List<dynamic>? dynamicNullableList = value as List<dynamic>?;
   final List<dynamic> dynamicList = dynamicNullableList ?? <dynamic>[];
   return dynamicList.cast<T>();
 }
@@ -155,20 +154,23 @@
       final int value = match.namedGroup('unicode') != null ?
         getHex(match.namedGroup('unicode')!) :
         match.namedGroup('char')!.codeUnitAt(0);
-      final String? keyLabel = match.namedGroup('kind')! == 'UNI' ? String.fromCharCode(value) : null;
+      final String? keyLabel = (match.namedGroup('kind')! == 'UNI' && !_isControlCharacter(value)) ?
+        String.fromCharCode(value) : null;
       // Skip modifier keys from DOM. They will be added with supplemental data.
       if (_chromeModifiers.containsKey(name) && source == 'DOM') {
         continue;
       }
 
-      final bool isPrintable = (keyLabel != null && !_isControlCharacter(keyLabel))
-        || printable.containsKey(name);
+      final bool isPrintable = keyLabel != null;
       data.putIfAbsent(name, () {
-        return LogicalKeyEntry.fromName(
+        final LogicalKeyEntry entry = LogicalKeyEntry.fromName(
           value: toPlane(value, _sourceToPlane(source, isPrintable)),
           name: name,
           keyLabel: keyLabel,
-        )..webNames.add(webName);
+        );
+        if (source == 'DOM' && !isPrintable)
+          entry.webNames.add(webName);
+        return entry;
       });
     }
   }
@@ -418,9 +420,11 @@
   })();
 
   static int _sourceToPlane(String source, bool isPrintable) {
+    if (isPrintable)
+      return kUnicodePlane.value;
     switch (source) {
       case 'DOM':
-        return isPrintable ? kUnicodePlane.value : kUnprintablePlane.value;
+        return kUnprintablePlane.value;
       case 'FLUTTER':
         return kFlutterPlane.value;
       default:
@@ -470,20 +474,20 @@
   LogicalKeyEntry.fromJsonMapEntry(Map<String, dynamic> map)
     : value = map['value'] as int,
       name = map['name'] as String,
-      webNames = _toNonEmptyArray<String>((map['names'] as Map<String, dynamic>)['web']),
-      macOSKeyCodeNames = _toNonEmptyArray<String>((map['names'] as Map<String, dynamic>)['macos']),
-      macOSKeyCodeValues = _toNonEmptyArray<int>((map['values'] as Map<String, dynamic>?)?['macos']),
-      iOSKeyCodeNames = _toNonEmptyArray<String>((map['names'] as Map<String, dynamic>)['ios']),
-      iOSKeyCodeValues = _toNonEmptyArray<int>((map['values'] as Map<String, dynamic>?)?['ios']),
-      gtkNames = _toNonEmptyArray<String>((map['names'] as Map<String, dynamic>)['gtk']),
-      gtkValues = _toNonEmptyArray<int>((map['values'] as Map<String, dynamic>?)?['gtk']),
-      windowsNames = _toNonEmptyArray<String>((map['names'] as Map<String, dynamic>)['windows']),
-      windowsValues = _toNonEmptyArray<int>((map['values'] as Map<String, dynamic>?)?['windows']),
-      androidNames = _toNonEmptyArray<String>((map['names'] as Map<String, dynamic>)['android']),
-      androidValues = _toNonEmptyArray<int>((map['values'] as Map<String, dynamic>?)?['android']),
-      fuchsiaValues = _toNonEmptyArray<int>((map['values'] as Map<String, dynamic>?)?['fuchsia']),
-      glfwNames = _toNonEmptyArray<String>((map['names'] as Map<String, dynamic>)['glfw']),
-      glfwValues = _toNonEmptyArray<int>((map['values'] as Map<String, dynamic>?)?['glfw']),
+      webNames = _getGrandchildList<String>(map, 'names', 'web'),
+      macOSKeyCodeNames = _getGrandchildList<String>(map, 'names', 'macos'),
+      macOSKeyCodeValues = _getGrandchildList<int>(map, 'values', 'macos'),
+      iOSKeyCodeNames = _getGrandchildList<String>(map, 'names', 'ios'),
+      iOSKeyCodeValues = _getGrandchildList<int>(map, 'values', 'ios'),
+      gtkNames = _getGrandchildList<String>(map, 'names', 'gtk'),
+      gtkValues = _getGrandchildList<int>(map, 'values', 'gtk'),
+      windowsNames = _getGrandchildList<String>(map, 'names', 'windows'),
+      windowsValues = _getGrandchildList<int>(map, 'values', 'windows'),
+      androidNames = _getGrandchildList<String>(map, 'names', 'android'),
+      androidValues = _getGrandchildList<int>(map, 'values', 'android'),
+      fuchsiaValues = _getGrandchildList<int>(map, 'values', 'fuchsia'),
+      glfwNames = _getGrandchildList<String>(map, 'names', 'glfw'),
+      glfwValues = _getGrandchildList<int>(map, 'values', 'glfw'),
       keyLabel = map['keyLabel'] as String?;
 
   final int value;
diff --git a/dev/tools/gen_keycodes/test/gen_keycodes_test.dart b/dev/tools/gen_keycodes/test/gen_keycodes_test.dart
index 447ee4d..a963eb5 100644
--- a/dev/tools/gen_keycodes/test/gen_keycodes_test.dart
+++ b/dev/tools/gen_keycodes/test/gen_keycodes_test.dart
@@ -22,8 +22,10 @@
   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');
+final PhysicalKeyData physicalData = PhysicalKeyData.fromJson(
+    json.decode(readDataFile('physical_key_data.json')) as Map<String, dynamic>);
+final LogicalKeyData logicalData = LogicalKeyData.fromJson(
+    json.decode(readDataFile('logical_key_data.json')) as Map<String, dynamic>);
 
 void main() {
   setUp(() {
@@ -45,14 +47,6 @@
   }
 
   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,
@@ -67,14 +61,6 @@
     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,
@@ -93,14 +79,6 @@
     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,
@@ -120,14 +98,6 @@
     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,
@@ -143,14 +113,6 @@
     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,
@@ -166,14 +128,6 @@
     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,
@@ -188,4 +142,25 @@
     expect(output, contains('kWebLogicalLocationMap'));
     checkCommonOutput(output);
   });
+  test('LogicalKeyData', () async {
+    final List<LogicalKeyEntry> entries = logicalData.entries.toList();
+
+    // Regression tests for https://github.com/flutter/flutter/pull/87098
+
+    expect(
+      entries.indexWhere((LogicalKeyEntry entry) => entry.name == 'ShiftLeft'),
+      isNot(-1));
+    expect(
+      entries.indexWhere((LogicalKeyEntry entry) => entry.webNames.contains('ShiftLeft')),
+      -1);
+    // 'Shift' maps to both 'ShiftLeft' and 'ShiftRight', and should be resolved
+    // by other ways.
+    expect(
+      entries.indexWhere((LogicalKeyEntry entry) => entry.webNames.contains('Shift')),
+      -1);
+    // Printable keys must not be added with Web key of their names.
+    expect(
+      entries.indexWhere((LogicalKeyEntry entry) => entry.webNames.contains('Slash')),
+      -1);
+  });
 }
diff --git a/packages/flutter/lib/src/services/keyboard_maps.dart b/packages/flutter/lib/src/services/keyboard_maps.dart
index 74cea74..3827e9e 100644
--- a/packages/flutter/lib/src/services/keyboard_maps.dart
+++ b/packages/flutter/lib/src/services/keyboard_maps.dart
@@ -2141,25 +2141,17 @@
 const Map<String, LogicalKeyboardKey> kWebToLogicalKey = <String, LogicalKeyboardKey>{
   'AVRInput': LogicalKeyboardKey.avrInput,
   'AVRPower': LogicalKeyboardKey.avrPower,
-  'Abort': LogicalKeyboardKey.abort,
   'Accel': LogicalKeyboardKey.accel,
   'Accept': LogicalKeyboardKey.accept,
-  'Add': LogicalKeyboardKey.add,
   'Again': LogicalKeyboardKey.again,
   'AllCandidates': LogicalKeyboardKey.allCandidates,
   'Alphanumeric': LogicalKeyboardKey.alphanumeric,
-  'Alt': LogicalKeyboardKey.alt,
   'AltGraph': LogicalKeyboardKey.altGraph,
-  'AltLeft': LogicalKeyboardKey.altLeft,
-  'AltRight': LogicalKeyboardKey.altRight,
-  'Ampersand': LogicalKeyboardKey.ampersand,
   'AppSwitch': LogicalKeyboardKey.appSwitch,
   'ArrowDown': LogicalKeyboardKey.arrowDown,
   'ArrowLeft': LogicalKeyboardKey.arrowLeft,
   'ArrowRight': LogicalKeyboardKey.arrowRight,
   'ArrowUp': LogicalKeyboardKey.arrowUp,
-  'Asterisk': LogicalKeyboardKey.asterisk,
-  'At': LogicalKeyboardKey.at,
   'Attn': LogicalKeyboardKey.attn,
   'AudioBalanceLeft': LogicalKeyboardKey.audioBalanceLeft,
   'AudioBalanceRight': LogicalKeyboardKey.audioBalanceRight,
@@ -2174,14 +2166,7 @@
   'AudioVolumeDown': LogicalKeyboardKey.audioVolumeDown,
   'AudioVolumeMute': LogicalKeyboardKey.audioVolumeMute,
   'AudioVolumeUp': LogicalKeyboardKey.audioVolumeUp,
-  'Backquote': LogicalKeyboardKey.backquote,
-  'Backslash': LogicalKeyboardKey.backslash,
   'Backspace': LogicalKeyboardKey.backspace,
-  'Bar': LogicalKeyboardKey.bar,
-  'BraceLeft': LogicalKeyboardKey.braceLeft,
-  'BraceRight': LogicalKeyboardKey.braceRight,
-  'BracketLeft': LogicalKeyboardKey.bracketLeft,
-  'BracketRight': LogicalKeyboardKey.bracketRight,
   'BrightnessDown': LogicalKeyboardKey.brightnessDown,
   'BrightnessUp': LogicalKeyboardKey.brightnessUp,
   'BrowserBack': LogicalKeyboardKey.browserBack,
@@ -2196,55 +2181,36 @@
   'CameraFocus': LogicalKeyboardKey.cameraFocus,
   'Cancel': LogicalKeyboardKey.cancel,
   'CapsLock': LogicalKeyboardKey.capsLock,
-  'Caret': LogicalKeyboardKey.caret,
   'ChannelDown': LogicalKeyboardKey.channelDown,
   'ChannelUp': LogicalKeyboardKey.channelUp,
   'Clear': LogicalKeyboardKey.clear,
   'Close': LogicalKeyboardKey.close,
   'ClosedCaptionToggle': LogicalKeyboardKey.closedCaptionToggle,
   'CodeInput': LogicalKeyboardKey.codeInput,
-  'Colon': LogicalKeyboardKey.colon,
   'ColorF0Red': LogicalKeyboardKey.colorF0Red,
   'ColorF1Green': LogicalKeyboardKey.colorF1Green,
   'ColorF2Yellow': LogicalKeyboardKey.colorF2Yellow,
   'ColorF3Blue': LogicalKeyboardKey.colorF3Blue,
   'ColorF4Grey': LogicalKeyboardKey.colorF4Grey,
   'ColorF5Brown': LogicalKeyboardKey.colorF5Brown,
-  'Comma': LogicalKeyboardKey.comma,
   'Compose': LogicalKeyboardKey.compose,
   'ContextMenu': LogicalKeyboardKey.contextMenu,
-  'Control': LogicalKeyboardKey.control,
-  'ControlLeft': LogicalKeyboardKey.controlLeft,
-  'ControlRight': LogicalKeyboardKey.controlRight,
   'Convert': LogicalKeyboardKey.convert,
   'Copy': LogicalKeyboardKey.copy,
   'CrSel': LogicalKeyboardKey.crSel,
   'Cut': LogicalKeyboardKey.cut,
   'DVR': LogicalKeyboardKey.dvr,
   'Delete': LogicalKeyboardKey.delete,
-  'Digit0': LogicalKeyboardKey.digit0,
-  'Digit1': LogicalKeyboardKey.digit1,
-  'Digit2': LogicalKeyboardKey.digit2,
-  'Digit3': LogicalKeyboardKey.digit3,
-  'Digit4': LogicalKeyboardKey.digit4,
-  'Digit5': LogicalKeyboardKey.digit5,
-  'Digit6': LogicalKeyboardKey.digit6,
-  'Digit7': LogicalKeyboardKey.digit7,
-  'Digit8': LogicalKeyboardKey.digit8,
-  'Digit9': LogicalKeyboardKey.digit9,
   'Dimmer': LogicalKeyboardKey.dimmer,
   'DisplaySwap': LogicalKeyboardKey.displaySwap,
-  'Dollar': LogicalKeyboardKey.dollar,
   'Eisu': LogicalKeyboardKey.eisu,
   'Eject': LogicalKeyboardKey.eject,
   'End': LogicalKeyboardKey.end,
   'EndCall': LogicalKeyboardKey.endCall,
   'Enter': LogicalKeyboardKey.enter,
-  'Equal': LogicalKeyboardKey.equal,
   'EraseEof': LogicalKeyboardKey.eraseEof,
   'Escape': LogicalKeyboardKey.escape,
   'ExSel': LogicalKeyboardKey.exSel,
-  'Exclamation': LogicalKeyboardKey.exclamation,
   'Execute': LogicalKeyboardKey.execute,
   'Exit': LogicalKeyboardKey.exit,
   'F1': LogicalKeyboardKey.f1,
@@ -2287,40 +2253,8 @@
   'Find': LogicalKeyboardKey.find,
   'Fn': LogicalKeyboardKey.fn,
   'FnLock': LogicalKeyboardKey.fnLock,
-  'GameButton1': LogicalKeyboardKey.gameButton1,
-  'GameButton10': LogicalKeyboardKey.gameButton10,
-  'GameButton11': LogicalKeyboardKey.gameButton11,
-  'GameButton12': LogicalKeyboardKey.gameButton12,
-  'GameButton13': LogicalKeyboardKey.gameButton13,
-  'GameButton14': LogicalKeyboardKey.gameButton14,
-  'GameButton15': LogicalKeyboardKey.gameButton15,
-  'GameButton16': LogicalKeyboardKey.gameButton16,
-  'GameButton2': LogicalKeyboardKey.gameButton2,
-  'GameButton3': LogicalKeyboardKey.gameButton3,
-  'GameButton4': LogicalKeyboardKey.gameButton4,
-  'GameButton5': LogicalKeyboardKey.gameButton5,
-  'GameButton6': LogicalKeyboardKey.gameButton6,
-  'GameButton7': LogicalKeyboardKey.gameButton7,
-  'GameButton8': LogicalKeyboardKey.gameButton8,
-  'GameButton9': LogicalKeyboardKey.gameButton9,
-  'GameButtonA': LogicalKeyboardKey.gameButtonA,
-  'GameButtonB': LogicalKeyboardKey.gameButtonB,
-  'GameButtonC': LogicalKeyboardKey.gameButtonC,
-  'GameButtonLeft1': LogicalKeyboardKey.gameButtonLeft1,
-  'GameButtonLeft2': LogicalKeyboardKey.gameButtonLeft2,
-  'GameButtonMode': LogicalKeyboardKey.gameButtonMode,
-  'GameButtonRight1': LogicalKeyboardKey.gameButtonRight1,
-  'GameButtonRight2': LogicalKeyboardKey.gameButtonRight2,
-  'GameButtonSelect': LogicalKeyboardKey.gameButtonSelect,
-  'GameButtonStart': LogicalKeyboardKey.gameButtonStart,
-  'GameButtonThumbLeft': LogicalKeyboardKey.gameButtonThumbLeft,
-  'GameButtonThumbRight': LogicalKeyboardKey.gameButtonThumbRight,
-  'GameButtonX': LogicalKeyboardKey.gameButtonX,
-  'GameButtonY': LogicalKeyboardKey.gameButtonY,
-  'GameButtonZ': LogicalKeyboardKey.gameButtonZ,
   'GoBack': LogicalKeyboardKey.goBack,
   'GoHome': LogicalKeyboardKey.goHome,
-  'Greater': LogicalKeyboardKey.greater,
   'GroupFirst': LogicalKeyboardKey.groupFirst,
   'GroupLast': LogicalKeyboardKey.groupLast,
   'GroupNext': LogicalKeyboardKey.groupNext,
@@ -2341,46 +2275,12 @@
   'Info': LogicalKeyboardKey.info,
   'Insert': LogicalKeyboardKey.insert,
   'InstantReplay': LogicalKeyboardKey.instantReplay,
-  'IntlBackslash': LogicalKeyboardKey.intlBackslash,
-  'IntlRo': LogicalKeyboardKey.intlRo,
-  'IntlYen': LogicalKeyboardKey.intlYen,
   'JunjaMode': LogicalKeyboardKey.junjaMode,
   'KanaMode': LogicalKeyboardKey.kanaMode,
   'KanjiMode': LogicalKeyboardKey.kanjiMode,
   'Katakana': LogicalKeyboardKey.katakana,
   'Key11': LogicalKeyboardKey.key11,
   'Key12': LogicalKeyboardKey.key12,
-  'KeyA': LogicalKeyboardKey.keyA,
-  'KeyB': LogicalKeyboardKey.keyB,
-  'KeyC': LogicalKeyboardKey.keyC,
-  'KeyD': LogicalKeyboardKey.keyD,
-  'KeyE': LogicalKeyboardKey.keyE,
-  'KeyF': LogicalKeyboardKey.keyF,
-  'KeyG': LogicalKeyboardKey.keyG,
-  'KeyH': LogicalKeyboardKey.keyH,
-  'KeyI': LogicalKeyboardKey.keyI,
-  'KeyJ': LogicalKeyboardKey.keyJ,
-  'KeyK': LogicalKeyboardKey.keyK,
-  'KeyL': LogicalKeyboardKey.keyL,
-  'KeyM': LogicalKeyboardKey.keyM,
-  'KeyN': LogicalKeyboardKey.keyN,
-  'KeyO': LogicalKeyboardKey.keyO,
-  'KeyP': LogicalKeyboardKey.keyP,
-  'KeyQ': LogicalKeyboardKey.keyQ,
-  'KeyR': LogicalKeyboardKey.keyR,
-  'KeyS': LogicalKeyboardKey.keyS,
-  'KeyT': LogicalKeyboardKey.keyT,
-  'KeyU': LogicalKeyboardKey.keyU,
-  'KeyV': LogicalKeyboardKey.keyV,
-  'KeyW': LogicalKeyboardKey.keyW,
-  'KeyX': LogicalKeyboardKey.keyX,
-  'KeyY': LogicalKeyboardKey.keyY,
-  'KeyZ': LogicalKeyboardKey.keyZ,
-  'Lang1': LogicalKeyboardKey.lang1,
-  'Lang2': LogicalKeyboardKey.lang2,
-  'Lang3': LogicalKeyboardKey.lang3,
-  'Lang4': LogicalKeyboardKey.lang4,
-  'Lang5': LogicalKeyboardKey.lang5,
   'LastNumberRedial': LogicalKeyboardKey.lastNumberRedial,
   'LaunchApplication1': LogicalKeyboardKey.launchApplication1,
   'LaunchApplication2': LogicalKeyboardKey.launchApplication2,
@@ -2397,7 +2297,6 @@
   'LaunchWebBrowser': LogicalKeyboardKey.launchWebBrowser,
   'LaunchWebCam': LogicalKeyboardKey.launchWebCam,
   'LaunchWordProcessor': LogicalKeyboardKey.launchWordProcessor,
-  'Less': LogicalKeyboardKey.less,
   'Link': LogicalKeyboardKey.link,
   'ListProgram': LogicalKeyboardKey.listProgram,
   'LiveContent': LogicalKeyboardKey.liveContent,
@@ -2426,14 +2325,10 @@
   'MediaTopMenu': LogicalKeyboardKey.mediaTopMenu,
   'MediaTrackNext': LogicalKeyboardKey.mediaTrackNext,
   'MediaTrackPrevious': LogicalKeyboardKey.mediaTrackPrevious,
-  'Meta': LogicalKeyboardKey.meta,
-  'MetaLeft': LogicalKeyboardKey.metaLeft,
-  'MetaRight': LogicalKeyboardKey.metaRight,
   'MicrophoneToggle': LogicalKeyboardKey.microphoneToggle,
   'MicrophoneVolumeDown': LogicalKeyboardKey.microphoneVolumeDown,
   'MicrophoneVolumeMute': LogicalKeyboardKey.microphoneVolumeMute,
   'MicrophoneVolumeUp': LogicalKeyboardKey.microphoneVolumeUp,
-  'Minus': LogicalKeyboardKey.minus,
   'ModeChange': LogicalKeyboardKey.modeChange,
   'NavigateIn': LogicalKeyboardKey.navigateIn,
   'NavigateNext': LogicalKeyboardKey.navigateNext,
@@ -2446,38 +2341,13 @@
   'NonConvert': LogicalKeyboardKey.nonConvert,
   'Notification': LogicalKeyboardKey.notification,
   'NumLock': LogicalKeyboardKey.numLock,
-  'NumberSign': LogicalKeyboardKey.numberSign,
-  'Numpad0': LogicalKeyboardKey.numpad0,
-  'Numpad1': LogicalKeyboardKey.numpad1,
-  'Numpad2': LogicalKeyboardKey.numpad2,
-  'Numpad3': LogicalKeyboardKey.numpad3,
-  'Numpad4': LogicalKeyboardKey.numpad4,
-  'Numpad5': LogicalKeyboardKey.numpad5,
-  'Numpad6': LogicalKeyboardKey.numpad6,
-  'Numpad7': LogicalKeyboardKey.numpad7,
-  'Numpad8': LogicalKeyboardKey.numpad8,
-  'Numpad9': LogicalKeyboardKey.numpad9,
-  'NumpadAdd': LogicalKeyboardKey.numpadAdd,
-  'NumpadComma': LogicalKeyboardKey.numpadComma,
-  'NumpadDecimal': LogicalKeyboardKey.numpadDecimal,
-  'NumpadDivide': LogicalKeyboardKey.numpadDivide,
-  'NumpadEnter': LogicalKeyboardKey.numpadEnter,
-  'NumpadEqual': LogicalKeyboardKey.numpadEqual,
-  'NumpadMultiply': LogicalKeyboardKey.numpadMultiply,
-  'NumpadParenLeft': LogicalKeyboardKey.numpadParenLeft,
-  'NumpadParenRight': LogicalKeyboardKey.numpadParenRight,
-  'NumpadSubtract': LogicalKeyboardKey.numpadSubtract,
   'OnDemand': LogicalKeyboardKey.onDemand,
   'Open': LogicalKeyboardKey.open,
   'PageDown': LogicalKeyboardKey.pageDown,
   'PageUp': LogicalKeyboardKey.pageUp,
   'Pairing': LogicalKeyboardKey.pairing,
-  'ParenthesisLeft': LogicalKeyboardKey.parenthesisLeft,
-  'ParenthesisRight': LogicalKeyboardKey.parenthesisRight,
   'Paste': LogicalKeyboardKey.paste,
   'Pause': LogicalKeyboardKey.pause,
-  'Percent': LogicalKeyboardKey.percent,
-  'Period': LogicalKeyboardKey.period,
   'PinPDown': LogicalKeyboardKey.pInPDown,
   'PinPMove': LogicalKeyboardKey.pInPMove,
   'PinPToggle': LogicalKeyboardKey.pInPToggle,
@@ -2493,14 +2363,10 @@
   'PrintScreen': LogicalKeyboardKey.printScreen,
   'Process': LogicalKeyboardKey.process,
   'Props': LogicalKeyboardKey.props,
-  'Question': LogicalKeyboardKey.question,
-  'Quote': LogicalKeyboardKey.quote,
-  'QuoteSingle': LogicalKeyboardKey.quoteSingle,
   'RandomToggle': LogicalKeyboardKey.randomToggle,
   'RcLowBattery': LogicalKeyboardKey.rcLowBattery,
   'RecordSpeedNext': LogicalKeyboardKey.recordSpeedNext,
   'Redo': LogicalKeyboardKey.redo,
-  'Resume': LogicalKeyboardKey.resume,
   'RfBypass': LogicalKeyboardKey.rfBypass,
   'Romaji': LogicalKeyboardKey.romaji,
   'STBInput': LogicalKeyboardKey.stbInput,
@@ -2510,15 +2376,9 @@
   'ScreenModeNext': LogicalKeyboardKey.screenModeNext,
   'ScrollLock': LogicalKeyboardKey.scrollLock,
   'Select': LogicalKeyboardKey.select,
-  'Semicolon': LogicalKeyboardKey.semicolon,
   'Settings': LogicalKeyboardKey.settings,
-  'Shift': LogicalKeyboardKey.shift,
-  'ShiftLeft': LogicalKeyboardKey.shiftLeft,
   'ShiftLevel5': LogicalKeyboardKey.shiftLevel5,
-  'ShiftRight': LogicalKeyboardKey.shiftRight,
   'SingleCandidate': LogicalKeyboardKey.singleCandidate,
-  'Slash': LogicalKeyboardKey.slash,
-  'Sleep': LogicalKeyboardKey.sleep,
   'Soft1': LogicalKeyboardKey.soft1,
   'Soft2': LogicalKeyboardKey.soft2,
   'Soft3': LogicalKeyboardKey.soft3,
@@ -2527,7 +2387,6 @@
   'Soft6': LogicalKeyboardKey.soft6,
   'Soft7': LogicalKeyboardKey.soft7,
   'Soft8': LogicalKeyboardKey.soft8,
-  'Space': LogicalKeyboardKey.space,
   'SpeechCorrectionList': LogicalKeyboardKey.speechCorrectionList,
   'SpeechInputToggle': LogicalKeyboardKey.speechInputToggle,
   'SpellCheck': LogicalKeyboardKey.spellCheck,
@@ -2535,7 +2394,6 @@
   'Standby': LogicalKeyboardKey.standby,
   'Subtitle': LogicalKeyboardKey.subtitle,
   'Super': LogicalKeyboardKey.superKey,
-  'Suspend': LogicalKeyboardKey.suspend,
   'Symbol': LogicalKeyboardKey.symbol,
   'SymbolLock': LogicalKeyboardKey.symbolLock,
   'TV': LogicalKeyboardKey.tv,
@@ -2570,8 +2428,6 @@
   'TVTimer': LogicalKeyboardKey.tvTimer,
   'Tab': LogicalKeyboardKey.tab,
   'Teletext': LogicalKeyboardKey.teletext,
-  'Tilde': LogicalKeyboardKey.tilde,
-  'Underscore': LogicalKeyboardKey.underscore,
   'Undo': LogicalKeyboardKey.undo,
   'Unidentified': LogicalKeyboardKey.unidentified,
   'VideoModeNext': LogicalKeyboardKey.videoModeNext,
diff --git a/packages/flutter/lib/src/services/raw_keyboard.dart b/packages/flutter/lib/src/services/raw_keyboard.dart
index ba67416..e99f28b 100644
--- a/packages/flutter/lib/src/services/raw_keyboard.dart
+++ b/packages/flutter/lib/src/services/raw_keyboard.dart
@@ -285,12 +285,10 @@
   /// Creates a concrete [RawKeyEvent] class from a message in the form received
   /// on the [SystemChannels.keyEvent] channel.
   factory RawKeyEvent.fromMessage(Map<String, dynamic> message) {
-    final RawKeyEventData data;
     String? character;
-
     RawKeyEventData _dataFromWeb() {
       final String? key = message['key'] as String?;
-      if (key != null && key.isNotEmpty) {
+      if (key != null && key.isNotEmpty && key.length == 1) {
         character = key;
       }
       return RawKeyEventDataWeb(
@@ -300,6 +298,8 @@
         metaState: message['metaState'] as int? ?? 0,
       );
     }
+
+    final RawKeyEventData data;
     if (kIsWeb) {
       data = _dataFromWeb();
     } else {
diff --git a/packages/flutter/lib/src/services/raw_keyboard_web.dart b/packages/flutter/lib/src/services/raw_keyboard_web.dart
index 70e2b94..4ae924e 100644
--- a/packages/flutter/lib/src/services/raw_keyboard_web.dart
+++ b/packages/flutter/lib/src/services/raw_keyboard_web.dart
@@ -10,6 +10,13 @@
 import 'keyboard_maps.dart';
 import 'raw_keyboard.dart';
 
+String? _unicodeChar(String key) {
+  if (key.length == 1) {
+    return key.substring(0, 1);
+  }
+  return null;
+}
+
 /// Platform-specific key event data for Web.
 ///
 /// See also:
@@ -74,7 +81,7 @@
   final int metaState;
 
   @override
-  String get keyLabel => key == 'Unidentified' ? '' : key;
+  String get keyLabel => key == 'Unidentified' ? '' : _unicodeChar(key) ?? '';
 
   @override
   PhysicalKeyboardKey get physicalKey {
@@ -95,9 +102,14 @@
       return newKey;
     }
 
+    final bool isPrintable = key.length == 1;
+    if (isPrintable)
+      return LogicalKeyboardKey(key.codeUnitAt(0));
+
     // This is a non-printable key that we don't know about, so we mint a new
-    // code.
-    return LogicalKeyboardKey(code.hashCode | LogicalKeyboardKey.webPlane);
+    // key from `code`. Don't mint with `key`, because the `key` will always be
+    // "Unidentified" .
+    return LogicalKeyboardKey(code.hashCode + LogicalKeyboardKey.webPlane);
   }
 
   @override
diff --git a/packages/flutter/test/services/raw_keyboard_test.dart b/packages/flutter/test/services/raw_keyboard_test.dart
index f5c227c..30a3941 100644
--- a/packages/flutter/test/services/raw_keyboard_test.dart
+++ b/packages/flutter/test/services/raw_keyboard_test.dart
@@ -2400,6 +2400,7 @@
         'keymap': 'web',
         'code': 'KeyA',
         'key': 'a',
+        'location': 0,
         'metaState': 0x0,
       });
       final RawKeyEventDataWeb data = keyAEvent.data as RawKeyEventDataWeb;
@@ -2413,6 +2414,8 @@
         'type': 'keydown',
         'keymap': 'web',
         'code': 'Escape',
+        'key': 'Escape',
+        'location': 0,
         'metaState': 0x0,
       });
       final RawKeyEventDataWeb data = escapeKeyEvent.data as RawKeyEventDataWeb;
@@ -2426,6 +2429,8 @@
         'type': 'keydown',
         'keymap': 'web',
         'code': 'ShiftLeft',
+        'key': 'Shift',
+        'location': 1,
         'metaState': RawKeyEventDataWeb.modifierShift,
       });
       final RawKeyEventDataWeb data = shiftKeyEvent.data as RawKeyEventDataWeb;
@@ -2439,6 +2444,8 @@
         'type': 'keydown',
         'keymap': 'web',
         'code': 'ArrowDown',
+        'key': 'ArrowDown',
+        'location': 0,
         'metaState': 0x0,
       });
       final RawKeyEventDataWeb data = arrowKeyDown.data as RawKeyEventDataWeb;
@@ -2447,6 +2454,25 @@
       expect(data.keyLabel, isEmpty);
     });
 
+    test('Unrecognized keys are mapped to Web plane', () {
+      final RawKeyEvent arrowKeyDown = RawKeyEvent.fromMessage(const <String, dynamic>{
+        'type': 'keydown',
+        'keymap': 'web',
+        'code': 'Unrecog1',
+        'key': 'Unrecog2',
+        'location': 0,
+        'metaState': 0x0,
+      });
+      final RawKeyEventDataWeb data = arrowKeyDown.data as RawKeyEventDataWeb;
+      // This might be easily broken on Web if the code fails to acknowledge
+      // that JavaScript doesn't handle 64-bit bit-wise operation.
+      expect(data.physicalKey.usbHidUsage, greaterThan(0x01700000000));
+      expect(data.physicalKey.usbHidUsage, lessThan(0x01800000000));
+      expect(data.logicalKey.keyId, greaterThan(0x01700000000));
+      expect(data.logicalKey.keyId, lessThan(0x01800000000));
+      expect(data.keyLabel, isEmpty);
+    });
+
     test('data.toString', () {
       expect(RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
diff --git a/packages/flutter_test/lib/src/event_simulation.dart b/packages/flutter_test/lib/src/event_simulation.dart
index 32f81dc..c4e34e1 100644
--- a/packages/flutter_test/lib/src/event_simulation.dart
+++ b/packages/flutter_test/lib/src/event_simulation.dart
@@ -14,6 +14,16 @@
 import 'binding.dart';
 import 'test_async_utils.dart';
 
+// A tuple of `key` and `location` from Web's `KeyboardEvent` class.
+//
+// See [RawKeyEventDataWeb]'s `key` and `location` fields for details.
+@immutable
+class _WebKeyLocationPair {
+  const _WebKeyLocationPair(this.key, this.location);
+  final String key;
+  final int location;
+}
+
 // TODO(gspencergoog): Replace this with more robust key simulation code once
 // the new key event code is in.
 // https://github.com/flutter/flutter/issues/33521
@@ -145,8 +155,32 @@
     }
   }
 
-  static String _getWebKeyCode(LogicalKeyboardKey key) {
+  static PhysicalKeyboardKey _inferPhysicalKey(LogicalKeyboardKey key) {
+    PhysicalKeyboardKey? result;
+    for (final PhysicalKeyboardKey physicalKey in PhysicalKeyboardKey.knownPhysicalKeys) {
+      if (physicalKey.debugName == key.debugName) {
+        result = physicalKey;
+        break;
+      }
+    }
+    assert(result != null, 'Unable to infer physical key for $key');
+    return result!;
+  }
+
+  static _WebKeyLocationPair _getWebKeyLocation(LogicalKeyboardKey key, String keyLabel) {
     String? result;
+    for (final MapEntry<String, List<LogicalKeyboardKey?>> entry in kWebLocationMap.entries) {
+      final int foundIndex = entry.value.indexOf(key);
+      // If foundIndex is -1, then the key is not defined in kWebLocationMap.
+      // If foundIndex is 0, then the key is in the standard part of the keyboard,
+      // but we have to check `keyLabel` to see if it's remapped or modified.
+      if (foundIndex != -1 && foundIndex != 0) {
+        return _WebKeyLocationPair(entry.key, foundIndex);
+      }
+    }
+    if (keyLabel.isNotEmpty) {
+      return _WebKeyLocationPair(keyLabel, 0);
+    }
     for (final String code in kWebToLogicalKey.keys) {
       if (key.keyId == kWebToLogicalKey[code]!.keyId) {
         result = code;
@@ -154,6 +188,18 @@
       }
     }
     assert(result != null, 'Key $key not found in web keyCode map');
+    return _WebKeyLocationPair(result!, 0);
+  }
+
+  static String _getWebCode(PhysicalKeyboardKey key) {
+    String? result;
+    for (final MapEntry<String, PhysicalKeyboardKey> entry in kWebToPhysicalKey.entries) {
+      if (entry.value.usbHidUsage == key.usbHidUsage) {
+        result = entry.key;
+        break;
+      }
+    }
+    assert(result != null, 'Key $key not found in web code map');
     return result!;
   }
 
@@ -215,8 +261,6 @@
     physicalKey ??= _findPhysicalKeyByPlatform(key, platform);
 
     assert(key.debugName != null);
-    final int keyCode = _getKeyCode(key, platform);
-    final int scanCode = _getScanCode(physicalKey, platform);
 
     final Map<String, dynamic> result = <String, dynamic>{
       'type': isDown ? 'keydown' : 'keyup',
@@ -225,14 +269,19 @@
 
     final String resultCharacter = character ?? _keyLabel(key) ?? '';
     void assignWeb() {
-      result['code'] = _getWebKeyCode(key);
-      result['key'] = resultCharacter;
+      final _WebKeyLocationPair keyLocation = _getWebKeyLocation(key, resultCharacter);
+      final PhysicalKeyboardKey actualPhysicalKey = physicalKey ?? _inferPhysicalKey(key);
+      result['code'] = _getWebCode(actualPhysicalKey);
+      result['key'] = keyLocation.key;
+      result['location'] = keyLocation.location;
       result['metaState'] = _getWebModifierFlags(key, isDown);
     }
     if (kIsWeb) {
       assignWeb();
       return result;
     }
+    final int keyCode = _getKeyCode(key, platform);
+    final int scanCode = _getScanCode(physicalKey, platform);
 
     switch (platform) {
       case 'android':