@@ -171,6 +171,22 @@ class PhysicalKeyData {
171171 // Skip key that is not actually generated by any keyboard.
172172 continue ;
173173 }
174+ final PhysicalKeyEntry ? existing = entries[usbHidCode];
175+ // Allow duplicate entries for Fn, which overwrites.
176+ if (existing != null && existing.name != 'Fn' ) {
177+ // If it's an existing entry, the only thing we currently support is
178+ // to insert an extra DOMKey. The other entries must be empty.
179+ assert (evdevCode == 0
180+ && xKbScanCode == 0
181+ && windowsScanCode == 0
182+ && macScanCode == 0xffff
183+ && chromiumCode != null
184+ && chromiumCode.isNotEmpty,
185+ 'Duplicate usbHidCode ${existing .usbHidCode } of key ${existing .name } '
186+ 'conflicts with existing ${entries [existing .usbHidCode ]!.name }.' );
187+ existing.otherWebCodes.add (chromiumCode! );
188+ continue ;
189+ }
174190 final PhysicalKeyEntry newEntry = PhysicalKeyEntry (
175191 usbHidCode: usbHidCode,
176192 androidScanCodes: nameToAndroidScanCodes[name] ?? < int > [],
@@ -182,15 +198,6 @@ class PhysicalKeyData {
182198 name: name,
183199 chromiumCode: chromiumCode,
184200 );
185- // Remove duplicates: last one wins, so that supplemental codes
186- // override.
187- if (entries.containsKey (newEntry.usbHidCode)) {
188- // This is expected for Fn. Warn for other keys.
189- if (newEntry.name != 'Fn' ) {
190- print ('Duplicate usbHidCode ${newEntry .usbHidCode } of key ${newEntry .name } '
191- 'conflicts with existing ${entries [newEntry .usbHidCode ]!.name }. Keeping the new one.' );
192- }
193- }
194201 entries[newEntry.usbHidCode] = newEntry;
195202 }
196203 return entries.map ((int code, PhysicalKeyEntry entry) =>
@@ -216,7 +223,8 @@ class PhysicalKeyEntry {
216223 required this .macOSScanCode,
217224 required this .iOSScanCode,
218225 required this .chromiumCode,
219- });
226+ List <String >? otherWebCodes,
227+ }) : otherWebCodes = otherWebCodes ?? < String > [];
220228
221229 /// Populates the key from a JSON map.
222230 factory PhysicalKeyEntry .fromJsonMapEntry (Map <String , dynamic > map) {
@@ -232,6 +240,7 @@ class PhysicalKeyEntry {
232240 windowsScanCode: scanCodes['windows' ] as int ? ,
233241 macOSScanCode: scanCodes['macos' ] as int ? ,
234242 iOSScanCode: scanCodes['ios' ] as int ? ,
243+ otherWebCodes: (map['otherWebCodes' ] as List <dynamic >? )? .cast <String >(),
235244 );
236245 }
237246
@@ -258,11 +267,14 @@ class PhysicalKeyEntry {
258267 final String name;
259268 /// The Chromium event code for the key.
260269 final String ? chromiumCode;
270+ /// Other codes used by Web besides chromiumCode.
271+ final List <String > otherWebCodes;
261272
262273 Iterable <String > webCodes () sync * {
263274 if (chromiumCode != null ) {
264275 yield chromiumCode! ;
265276 }
277+ yield * otherWebCodes;
266278 }
267279
268280 /// Creates a JSON map from the key data.
@@ -272,6 +284,7 @@ class PhysicalKeyEntry {
272284 'name' : name,
273285 'chromium' : chromiumCode,
274286 },
287+ 'otherWebCodes' : otherWebCodes,
275288 'scanCodes' : < String , dynamic > {
276289 'android' : androidScanCodes,
277290 'usb' : usbHidCode,
@@ -323,11 +336,14 @@ class PhysicalKeyEntry {
323336
324337 @override
325338 String toString () {
339+ final String otherWebStr = otherWebCodes.isEmpty
340+ ? ''
341+ : ', otherWebCodes: [${otherWebCodes .join (', ' )}]' ;
326342 return """'$constantName ': (name: "$name ", usbHidCode: ${toHex (usbHidCode )}, """
327343 'linuxScanCode: ${toHex (evdevCode )}, xKbScanCode: ${toHex (xKbScanCode )}, '
328344 'windowsKeyCode: ${toHex (windowsScanCode )}, macOSScanCode: ${toHex (macOSScanCode )}, '
329345 'windowsScanCode: ${toHex (windowsScanCode )}, chromiumSymbolName: $chromiumCode '
330- 'iOSScanCode: ${toHex (iOSScanCode )})' ;
346+ 'iOSScanCode: ${toHex (iOSScanCode )})$ otherWebStr ' ;
331347 }
332348
333349 static int compareByUsbHidCode (PhysicalKeyEntry a, PhysicalKeyEntry b) =>
0 commit comments