Unverified Commit 24d39997 authored by puelo's avatar puelo Committed by GitHub

Generate RawKeyEvents for iOS 13.4+ (#65193)

* Added RawKeyEvent support for iOS

* Removed unused remnant

* added some missing keys

* Removed trailing whitespaces

* commit for build

* Added mapping names

* Made iOS keycodes generatable and collectable

* Fixed naming and formatting issues

* fixed raw_keyboard_test
parent f8772661
...@@ -11,6 +11,7 @@ import 'package:path/path.dart' as path; ...@@ -11,6 +11,7 @@ import 'package:path/path.dart' as path;
import 'package:gen_keycodes/android_code_gen.dart'; import 'package:gen_keycodes/android_code_gen.dart';
import 'package:gen_keycodes/base_code_gen.dart'; import 'package:gen_keycodes/base_code_gen.dart';
import 'package:gen_keycodes/ios_code_gen.dart';
import 'package:gen_keycodes/macos_code_gen.dart'; import 'package:gen_keycodes/macos_code_gen.dart';
import 'package:gen_keycodes/fuchsia_code_gen.dart'; import 'package:gen_keycodes/fuchsia_code_gen.dart';
import 'package:gen_keycodes/glfw_code_gen.dart'; import 'package:gen_keycodes/glfw_code_gen.dart';
...@@ -252,7 +253,7 @@ Future<void> main(List<String> rawArguments) async { ...@@ -252,7 +253,7 @@ Future<void> main(List<String> rawArguments) async {
print('Writing ${'key maps'.padRight(15)}${mapsFile.absolute}'); print('Writing ${'key maps'.padRight(15)}${mapsFile.absolute}');
await mapsFile.writeAsString(KeyboardMapsCodeGenerator(data).generate()); await mapsFile.writeAsString(KeyboardMapsCodeGenerator(data).generate());
for (final String platform in <String>['android', 'darwin', 'glfw', 'fuchsia', 'linux', 'windows', 'web']) { for (final String platform in <String>['android', 'macos', 'ios', 'glfw', 'fuchsia', 'linux', 'windows', 'web']) {
PlatformCodeGenerator codeGenerator; PlatformCodeGenerator codeGenerator;
switch (platform) { switch (platform) {
case 'glfw': case 'glfw':
...@@ -264,9 +265,12 @@ Future<void> main(List<String> rawArguments) async { ...@@ -264,9 +265,12 @@ Future<void> main(List<String> rawArguments) async {
case 'android': case 'android':
codeGenerator = AndroidCodeGenerator(data); codeGenerator = AndroidCodeGenerator(data);
break; break;
case 'darwin': case 'macos':
codeGenerator = MacOsCodeGenerator(data); codeGenerator = MacOsCodeGenerator(data);
break; break;
case 'ios':
codeGenerator = IosCodeGenerator(data);
break;
case 'windows': case 'windows':
codeGenerator = WindowsCodeGenerator(data); codeGenerator = WindowsCodeGenerator(data);
break; break;
......
...@@ -17,7 +17,8 @@ ...@@ -17,7 +17,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -47,7 +48,8 @@ ...@@ -47,7 +48,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -78,7 +80,8 @@ ...@@ -78,7 +80,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -106,7 +109,8 @@ ...@@ -106,7 +109,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -137,7 +141,8 @@ ...@@ -137,7 +141,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -166,7 +171,8 @@ ...@@ -166,7 +171,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -191,7 +197,8 @@ ...@@ -191,7 +197,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -216,7 +223,8 @@ ...@@ -216,7 +223,8 @@
"linux": 633, "linux": 633,
"xkb": 641, "xkb": 641,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -249,7 +257,8 @@ ...@@ -249,7 +257,8 @@
"linux": 142, "linux": 142,
"xkb": 150, "xkb": 150,
"windows": 57439, "windows": 57439,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -286,7 +295,8 @@ ...@@ -286,7 +295,8 @@
"linux": 143, "linux": 143,
"xkb": 151, "xkb": 151,
"windows": 57443, "windows": 57443,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -315,7 +325,8 @@ ...@@ -315,7 +325,8 @@
"linux": 227, "linux": 227,
"xkb": 235, "xkb": 235,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -340,7 +351,8 @@ ...@@ -340,7 +351,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": 0
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -365,7 +377,8 @@ ...@@ -365,7 +377,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": 255, "windows": 255,
"macos": null "macos": null,
"ios": 1
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -390,7 +403,8 @@ ...@@ -390,7 +403,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": 252, "windows": 252,
"macos": null "macos": null,
"ios": 2
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -415,7 +429,8 @@ ...@@ -415,7 +429,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": 3
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -450,7 +465,8 @@ ...@@ -450,7 +465,8 @@
"linux": 30, "linux": 30,
"xkb": 38, "xkb": 38,
"windows": 30, "windows": 30,
"macos": 0 "macos": 0,
"ios": 4
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -493,7 +509,8 @@ ...@@ -493,7 +509,8 @@
"linux": 48, "linux": 48,
"xkb": 56, "xkb": 56,
"windows": 48, "windows": 48,
"macos": 11 "macos": 11,
"ios": 5
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -536,7 +553,8 @@ ...@@ -536,7 +553,8 @@
"linux": 46, "linux": 46,
"xkb": 54, "xkb": 54,
"windows": 46, "windows": 46,
"macos": 8 "macos": 8,
"ios": 6
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -579,7 +597,8 @@ ...@@ -579,7 +597,8 @@
"linux": 32, "linux": 32,
"xkb": 40, "xkb": 40,
"windows": 32, "windows": 32,
"macos": 2 "macos": 2,
"ios": 7
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -622,7 +641,8 @@ ...@@ -622,7 +641,8 @@
"linux": 18, "linux": 18,
"xkb": 26, "xkb": 26,
"windows": 18, "windows": 18,
"macos": 14 "macos": 14,
"ios": 8
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -665,7 +685,8 @@ ...@@ -665,7 +685,8 @@
"linux": 33, "linux": 33,
"xkb": 41, "xkb": 41,
"windows": 33, "windows": 33,
"macos": 3 "macos": 3,
"ios": 9
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -708,7 +729,8 @@ ...@@ -708,7 +729,8 @@
"linux": 34, "linux": 34,
"xkb": 42, "xkb": 42,
"windows": 34, "windows": 34,
"macos": 5 "macos": 5,
"ios": 10
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -751,7 +773,8 @@ ...@@ -751,7 +773,8 @@
"linux": 35, "linux": 35,
"xkb": 43, "xkb": 43,
"windows": 35, "windows": 35,
"macos": 4 "macos": 4,
"ios": 11
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -794,7 +817,8 @@ ...@@ -794,7 +817,8 @@
"linux": 23, "linux": 23,
"xkb": 31, "xkb": 31,
"windows": 23, "windows": 23,
"macos": 34 "macos": 34,
"ios": 12
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -837,7 +861,8 @@ ...@@ -837,7 +861,8 @@
"linux": 36, "linux": 36,
"xkb": 44, "xkb": 44,
"windows": 36, "windows": 36,
"macos": 38 "macos": 38,
"ios": 13
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -880,7 +905,8 @@ ...@@ -880,7 +905,8 @@
"linux": 37, "linux": 37,
"xkb": 45, "xkb": 45,
"windows": 37, "windows": 37,
"macos": 40 "macos": 40,
"ios": 14
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -923,7 +949,8 @@ ...@@ -923,7 +949,8 @@
"linux": 38, "linux": 38,
"xkb": 46, "xkb": 46,
"windows": 38, "windows": 38,
"macos": 37 "macos": 37,
"ios": 15
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -966,7 +993,8 @@ ...@@ -966,7 +993,8 @@
"linux": 50, "linux": 50,
"xkb": 58, "xkb": 58,
"windows": 50, "windows": 50,
"macos": 46 "macos": 46,
"ios": 16
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1009,7 +1037,8 @@ ...@@ -1009,7 +1037,8 @@
"linux": 49, "linux": 49,
"xkb": 57, "xkb": 57,
"windows": 49, "windows": 49,
"macos": 45 "macos": 45,
"ios": 17
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1052,7 +1081,8 @@ ...@@ -1052,7 +1081,8 @@
"linux": 24, "linux": 24,
"xkb": 32, "xkb": 32,
"windows": 24, "windows": 24,
"macos": 31 "macos": 31,
"ios": 18
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1095,7 +1125,8 @@ ...@@ -1095,7 +1125,8 @@
"linux": 25, "linux": 25,
"xkb": 33, "xkb": 33,
"windows": 25, "windows": 25,
"macos": 35 "macos": 35,
"ios": 19
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1138,7 +1169,8 @@ ...@@ -1138,7 +1169,8 @@
"linux": 16, "linux": 16,
"xkb": 24, "xkb": 24,
"windows": 16, "windows": 16,
"macos": 12 "macos": 12,
"ios": 20
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1181,7 +1213,8 @@ ...@@ -1181,7 +1213,8 @@
"linux": 19, "linux": 19,
"xkb": 27, "xkb": 27,
"windows": 19, "windows": 19,
"macos": 15 "macos": 15,
"ios": 21
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1224,7 +1257,8 @@ ...@@ -1224,7 +1257,8 @@
"linux": 31, "linux": 31,
"xkb": 39, "xkb": 39,
"windows": 31, "windows": 31,
"macos": 1 "macos": 1,
"ios": 22
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1267,7 +1301,8 @@ ...@@ -1267,7 +1301,8 @@
"linux": 20, "linux": 20,
"xkb": 28, "xkb": 28,
"windows": 20, "windows": 20,
"macos": 17 "macos": 17,
"ios": 23
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1310,7 +1345,8 @@ ...@@ -1310,7 +1345,8 @@
"linux": 22, "linux": 22,
"xkb": 30, "xkb": 30,
"windows": 22, "windows": 22,
"macos": 32 "macos": 32,
"ios": 24
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1353,7 +1389,8 @@ ...@@ -1353,7 +1389,8 @@
"linux": 47, "linux": 47,
"xkb": 55, "xkb": 55,
"windows": 47, "windows": 47,
"macos": 9 "macos": 9,
"ios": 25
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1396,7 +1433,8 @@ ...@@ -1396,7 +1433,8 @@
"linux": 17, "linux": 17,
"xkb": 25, "xkb": 25,
"windows": 17, "windows": 17,
"macos": 13 "macos": 13,
"ios": 26
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1439,7 +1477,8 @@ ...@@ -1439,7 +1477,8 @@
"linux": 45, "linux": 45,
"xkb": 53, "xkb": 53,
"windows": 45, "windows": 45,
"macos": 7 "macos": 7,
"ios": 27
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1482,7 +1521,8 @@ ...@@ -1482,7 +1521,8 @@
"linux": 21, "linux": 21,
"xkb": 29, "xkb": 29,
"windows": 21, "windows": 21,
"macos": 16 "macos": 16,
"ios": 28
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1525,7 +1565,8 @@ ...@@ -1525,7 +1565,8 @@
"linux": 44, "linux": 44,
"xkb": 52, "xkb": 52,
"windows": 44, "windows": 44,
"macos": 6 "macos": 6,
"ios": 29
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1566,7 +1607,8 @@ ...@@ -1566,7 +1607,8 @@
"linux": 2, "linux": 2,
"xkb": 10, "xkb": 10,
"windows": 2, "windows": 2,
"macos": 18 "macos": 18,
"ios": 30
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1605,7 +1647,8 @@ ...@@ -1605,7 +1647,8 @@
"linux": 3, "linux": 3,
"xkb": 11, "xkb": 11,
"windows": 3, "windows": 3,
"macos": 19 "macos": 19,
"ios": 31
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1644,7 +1687,8 @@ ...@@ -1644,7 +1687,8 @@
"linux": 4, "linux": 4,
"xkb": 12, "xkb": 12,
"windows": 4, "windows": 4,
"macos": 20 "macos": 20,
"ios": 32
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1683,7 +1727,8 @@ ...@@ -1683,7 +1727,8 @@
"linux": 5, "linux": 5,
"xkb": 13, "xkb": 13,
"windows": 5, "windows": 5,
"macos": 21 "macos": 21,
"ios": 33
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1722,7 +1767,8 @@ ...@@ -1722,7 +1767,8 @@
"linux": 6, "linux": 6,
"xkb": 14, "xkb": 14,
"windows": 6, "windows": 6,
"macos": 23 "macos": 23,
"ios": 34
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1761,7 +1807,8 @@ ...@@ -1761,7 +1807,8 @@
"linux": 7, "linux": 7,
"xkb": 15, "xkb": 15,
"windows": 7, "windows": 7,
"macos": 22 "macos": 22,
"ios": 35
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1800,7 +1847,8 @@ ...@@ -1800,7 +1847,8 @@
"linux": 8, "linux": 8,
"xkb": 16, "xkb": 16,
"windows": 8, "windows": 8,
"macos": 26 "macos": 26,
"ios": 36
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1839,7 +1887,8 @@ ...@@ -1839,7 +1887,8 @@
"linux": 9, "linux": 9,
"xkb": 17, "xkb": 17,
"windows": 9, "windows": 9,
"macos": 28 "macos": 28,
"ios": 37
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1878,7 +1927,8 @@ ...@@ -1878,7 +1927,8 @@
"linux": 10, "linux": 10,
"xkb": 18, "xkb": 18,
"windows": 10, "windows": 10,
"macos": 25 "macos": 25,
"ios": 38
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1917,7 +1967,8 @@ ...@@ -1917,7 +1967,8 @@
"linux": 11, "linux": 11,
"xkb": 19, "xkb": 19,
"windows": 11, "windows": 11,
"macos": 29 "macos": 29,
"ios": 39
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -1960,7 +2011,8 @@ ...@@ -1960,7 +2011,8 @@
"linux": 28, "linux": 28,
"xkb": 36, "xkb": 36,
"windows": 28, "windows": 28,
"macos": 36 "macos": 36,
"ios": 40
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2004,7 +2056,8 @@ ...@@ -2004,7 +2056,8 @@
"linux": 1, "linux": 1,
"xkb": 9, "xkb": 9,
"windows": 1, "windows": 1,
"macos": 53 "macos": 53,
"ios": 41
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2047,7 +2100,8 @@ ...@@ -2047,7 +2100,8 @@
"linux": 14, "linux": 14,
"xkb": 22, "xkb": 22,
"windows": 14, "windows": 14,
"macos": 51 "macos": 51,
"ios": 42
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2092,7 +2146,8 @@ ...@@ -2092,7 +2146,8 @@
"linux": 15, "linux": 15,
"xkb": 23, "xkb": 23,
"windows": 15, "windows": 15,
"macos": 48 "macos": 48,
"ios": 43
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2138,7 +2193,8 @@ ...@@ -2138,7 +2193,8 @@
"linux": 57, "linux": 57,
"xkb": 65, "xkb": 65,
"windows": 57, "windows": 57,
"macos": 49 "macos": 49,
"ios": 44
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2182,7 +2238,8 @@ ...@@ -2182,7 +2238,8 @@
"linux": 12, "linux": 12,
"xkb": 20, "xkb": 20,
"windows": 12, "windows": 12,
"macos": 27 "macos": 27,
"ios": 45
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2225,7 +2282,8 @@ ...@@ -2225,7 +2282,8 @@
"linux": 13, "linux": 13,
"xkb": 21, "xkb": 21,
"windows": 13, "windows": 13,
"macos": 24 "macos": 24,
"ios": 46
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2268,7 +2326,8 @@ ...@@ -2268,7 +2326,8 @@
"linux": 26, "linux": 26,
"xkb": 34, "xkb": 34,
"windows": 26, "windows": 26,
"macos": 33 "macos": 33,
"ios": 47
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2311,7 +2370,8 @@ ...@@ -2311,7 +2370,8 @@
"linux": 27, "linux": 27,
"xkb": 35, "xkb": 35,
"windows": 27, "windows": 27,
"macos": 30 "macos": 30,
"ios": 48
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2355,7 +2415,8 @@ ...@@ -2355,7 +2415,8 @@
"linux": 43, "linux": 43,
"xkb": 51, "xkb": 51,
"windows": 43, "windows": 43,
"macos": 42 "macos": 42,
"ios": 49
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2398,7 +2459,8 @@ ...@@ -2398,7 +2459,8 @@
"linux": 39, "linux": 39,
"xkb": 47, "xkb": 47,
"windows": 39, "windows": 39,
"macos": 41 "macos": 41,
"ios": 51
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2441,7 +2503,8 @@ ...@@ -2441,7 +2503,8 @@
"linux": 40, "linux": 40,
"xkb": 48, "xkb": 48,
"windows": 40, "windows": 40,
"macos": 39 "macos": 39,
"ios": 52
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2484,7 +2547,8 @@ ...@@ -2484,7 +2547,8 @@
"linux": 41, "linux": 41,
"xkb": 49, "xkb": 49,
"windows": 41, "windows": 41,
"macos": 50 "macos": 50,
"ios": 53
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2527,7 +2591,8 @@ ...@@ -2527,7 +2591,8 @@
"linux": 51, "linux": 51,
"xkb": 59, "xkb": 59,
"windows": 51, "windows": 51,
"macos": 43 "macos": 43,
"ios": 54
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2570,7 +2635,8 @@ ...@@ -2570,7 +2635,8 @@
"linux": 52, "linux": 52,
"xkb": 60, "xkb": 60,
"windows": 52, "windows": 52,
"macos": 47 "macos": 47,
"ios": 55
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2613,7 +2679,8 @@ ...@@ -2613,7 +2679,8 @@
"linux": 53, "linux": 53,
"xkb": 61, "xkb": 61,
"windows": 53, "windows": 53,
"macos": 44 "macos": 44,
"ios": 56
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2656,7 +2723,8 @@ ...@@ -2656,7 +2723,8 @@
"linux": 58, "linux": 58,
"xkb": 66, "xkb": 66,
"windows": 58, "windows": 58,
"macos": 57 "macos": 57,
"ios": 57
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2700,7 +2768,8 @@ ...@@ -2700,7 +2768,8 @@
"linux": 59, "linux": 59,
"xkb": 67, "xkb": 67,
"windows": 59, "windows": 59,
"macos": 122 "macos": 122,
"ios": 58
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2745,7 +2814,8 @@ ...@@ -2745,7 +2814,8 @@
"linux": 60, "linux": 60,
"xkb": 68, "xkb": 68,
"windows": 60, "windows": 60,
"macos": 120 "macos": 120,
"ios": 59
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2790,7 +2860,8 @@ ...@@ -2790,7 +2860,8 @@
"linux": 61, "linux": 61,
"xkb": 69, "xkb": 69,
"windows": 61, "windows": 61,
"macos": 99 "macos": 99,
"ios": 60
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2835,7 +2906,8 @@ ...@@ -2835,7 +2906,8 @@
"linux": 62, "linux": 62,
"xkb": 70, "xkb": 70,
"windows": 62, "windows": 62,
"macos": 118 "macos": 118,
"ios": 61
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2879,7 +2951,8 @@ ...@@ -2879,7 +2951,8 @@
"linux": 63, "linux": 63,
"xkb": 71, "xkb": 71,
"windows": 63, "windows": 63,
"macos": 96 "macos": 96,
"ios": 62
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2922,7 +2995,8 @@ ...@@ -2922,7 +2995,8 @@
"linux": 64, "linux": 64,
"xkb": 72, "xkb": 72,
"windows": 64, "windows": 64,
"macos": 97 "macos": 97,
"ios": 63
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -2965,7 +3039,8 @@ ...@@ -2965,7 +3039,8 @@
"linux": 65, "linux": 65,
"xkb": 73, "xkb": 73,
"windows": 65, "windows": 65,
"macos": 98 "macos": 98,
"ios": 64
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3008,7 +3083,8 @@ ...@@ -3008,7 +3083,8 @@
"linux": 66, "linux": 66,
"xkb": 74, "xkb": 74,
"windows": 66, "windows": 66,
"macos": 100 "macos": 100,
"ios": 65
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3051,7 +3127,8 @@ ...@@ -3051,7 +3127,8 @@
"linux": 67, "linux": 67,
"xkb": 75, "xkb": 75,
"windows": 67, "windows": 67,
"macos": 101 "macos": 101,
"ios": 66
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3094,7 +3171,8 @@ ...@@ -3094,7 +3171,8 @@
"linux": 68, "linux": 68,
"xkb": 76, "xkb": 76,
"windows": 68, "windows": 68,
"macos": 109 "macos": 109,
"ios": 67
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3137,7 +3215,8 @@ ...@@ -3137,7 +3215,8 @@
"linux": 87, "linux": 87,
"xkb": 95, "xkb": 95,
"windows": 87, "windows": 87,
"macos": 103 "macos": 103,
"ios": 68
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3180,7 +3259,8 @@ ...@@ -3180,7 +3259,8 @@
"linux": 88, "linux": 88,
"xkb": 96, "xkb": 96,
"windows": 88, "windows": 88,
"macos": 111 "macos": 111,
"ios": 69
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3221,7 +3301,8 @@ ...@@ -3221,7 +3301,8 @@
"linux": 99, "linux": 99,
"xkb": 107, "xkb": 107,
"windows": 57399, "windows": 57399,
"macos": null "macos": null,
"ios": 70
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3258,7 +3339,8 @@ ...@@ -3258,7 +3339,8 @@
"linux": 70, "linux": 70,
"xkb": 78, "xkb": 78,
"windows": 70, "windows": 70,
"macos": null "macos": null,
"ios": 71
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3298,7 +3380,8 @@ ...@@ -3298,7 +3380,8 @@
"linux": 119, "linux": 119,
"xkb": 127, "xkb": 127,
"windows": 69, "windows": 69,
"macos": null "macos": null,
"ios": 72
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3342,7 +3425,8 @@ ...@@ -3342,7 +3425,8 @@
"linux": 110, "linux": 110,
"xkb": 118, "xkb": 118,
"windows": 57426, "windows": 57426,
"macos": 114 "macos": 114,
"ios": 73
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3387,7 +3471,8 @@ ...@@ -3387,7 +3471,8 @@
"linux": 102, "linux": 102,
"xkb": 110, "xkb": 110,
"windows": 57415, "windows": 57415,
"macos": 115 "macos": 115,
"ios": 74
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3431,7 +3516,8 @@ ...@@ -3431,7 +3516,8 @@
"linux": 104, "linux": 104,
"xkb": 112, "xkb": 112,
"windows": 57417, "windows": 57417,
"macos": 116 "macos": 116,
"ios": 75
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3474,7 +3560,8 @@ ...@@ -3474,7 +3560,8 @@
"linux": 111, "linux": 111,
"xkb": 119, "xkb": 119,
"windows": 57427, "windows": 57427,
"macos": 117 "macos": 117,
"ios": 76
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3519,7 +3606,8 @@ ...@@ -3519,7 +3606,8 @@
"linux": 107, "linux": 107,
"xkb": 115, "xkb": 115,
"windows": 57423, "windows": 57423,
"macos": 119 "macos": 119,
"ios": 77
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3563,7 +3651,8 @@ ...@@ -3563,7 +3651,8 @@
"linux": 109, "linux": 109,
"xkb": 117, "xkb": 117,
"windows": 57425, "windows": 57425,
"macos": 121 "macos": 121,
"ios": 78
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3606,7 +3695,8 @@ ...@@ -3606,7 +3695,8 @@
"linux": 106, "linux": 106,
"xkb": 114, "xkb": 114,
"windows": 57421, "windows": 57421,
"macos": 124 "macos": 124,
"ios": 79
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3651,7 +3741,8 @@ ...@@ -3651,7 +3741,8 @@
"linux": 105, "linux": 105,
"xkb": 113, "xkb": 113,
"windows": 57419, "windows": 57419,
"macos": 123 "macos": 123,
"ios": 80
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3696,7 +3787,8 @@ ...@@ -3696,7 +3787,8 @@
"linux": 108, "linux": 108,
"xkb": 116, "xkb": 116,
"windows": 57424, "windows": 57424,
"macos": 125 "macos": 125,
"ios": 81
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3741,7 +3833,8 @@ ...@@ -3741,7 +3833,8 @@
"linux": 103, "linux": 103,
"xkb": 111, "xkb": 111,
"windows": 57416, "windows": 57416,
"macos": 126 "macos": 126,
"ios": 82
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3783,7 +3876,8 @@ ...@@ -3783,7 +3876,8 @@
"linux": 69, "linux": 69,
"xkb": 77, "xkb": 77,
"windows": 57413, "windows": 57413,
"macos": 71 "macos": 71,
"ios": 83
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3824,7 +3918,8 @@ ...@@ -3824,7 +3918,8 @@
"linux": 98, "linux": 98,
"xkb": 106, "xkb": 106,
"windows": 57397, "windows": 57397,
"macos": 75 "macos": 75,
"ios": 84
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3867,7 +3962,8 @@ ...@@ -3867,7 +3962,8 @@
"linux": 55, "linux": 55,
"xkb": 63, "xkb": 63,
"windows": 55, "windows": 55,
"macos": 67 "macos": 67,
"ios": 85
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3910,7 +4006,8 @@ ...@@ -3910,7 +4006,8 @@
"linux": 74, "linux": 74,
"xkb": 82, "xkb": 82,
"windows": 74, "windows": 74,
"macos": 78 "macos": 78,
"ios": 86
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3951,7 +4048,8 @@ ...@@ -3951,7 +4048,8 @@
"linux": 78, "linux": 78,
"xkb": 86, "xkb": 86,
"windows": 78, "windows": 78,
"macos": 69 "macos": 69,
"ios": 87
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -3992,7 +4090,8 @@ ...@@ -3992,7 +4090,8 @@
"linux": 96, "linux": 96,
"xkb": 104, "xkb": 104,
"windows": 57372, "windows": 57372,
"macos": 76 "macos": 76,
"ios": 88
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -4033,7 +4132,8 @@ ...@@ -4033,7 +4132,8 @@
"linux": 79, "linux": 79,
"xkb": 87, "xkb": 87,
"windows": 79, "windows": 79,
"macos": 83 "macos": 83,
"ios": 89
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -4076,7 +4176,8 @@ ...@@ -4076,7 +4176,8 @@
"linux": 80, "linux": 80,
"xkb": 88, "xkb": 88,
"windows": 80, "windows": 80,
"macos": 84 "macos": 84,
"ios": 90
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -4119,7 +4220,8 @@ ...@@ -4119,7 +4220,8 @@
"linux": 81, "linux": 81,
"xkb": 89, "xkb": 89,
"windows": 81, "windows": 81,
"macos": 85 "macos": 85,
"ios": 91
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -4162,7 +4264,8 @@ ...@@ -4162,7 +4264,8 @@
"linux": 75, "linux": 75,
"xkb": 83, "xkb": 83,
"windows": 75, "windows": 75,
"macos": 86 "macos": 86,
"ios": 92
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -4205,7 +4308,8 @@ ...@@ -4205,7 +4308,8 @@
"linux": 76, "linux": 76,
"xkb": 84, "xkb": 84,
"windows": 76, "windows": 76,
"macos": 87 "macos": 87,
"ios": 93
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -4248,7 +4352,8 @@ ...@@ -4248,7 +4352,8 @@
"linux": 77, "linux": 77,
"xkb": 85, "xkb": 85,
"windows": 77, "windows": 77,
"macos": 88 "macos": 88,
"ios": 94
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -4291,7 +4396,8 @@ ...@@ -4291,7 +4396,8 @@
"linux": 71, "linux": 71,
"xkb": 79, "xkb": 79,
"windows": 71, "windows": 71,
"macos": 89 "macos": 89,
"ios": 95
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -4334,7 +4440,8 @@ ...@@ -4334,7 +4440,8 @@
"linux": 72, "linux": 72,
"xkb": 80, "xkb": 80,
"windows": 72, "windows": 72,
"macos": 91 "macos": 91,
"ios": 96
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -4377,7 +4484,8 @@ ...@@ -4377,7 +4484,8 @@
"linux": 73, "linux": 73,
"xkb": 81, "xkb": 81,
"windows": 73, "windows": 73,
"macos": 92 "macos": 92,
"ios": 97
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -4420,7 +4528,8 @@ ...@@ -4420,7 +4528,8 @@
"linux": 82, "linux": 82,
"xkb": 90, "xkb": 90,
"windows": 82, "windows": 82,
"macos": 82 "macos": 82,
"ios": 98
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -4463,7 +4572,8 @@ ...@@ -4463,7 +4572,8 @@
"linux": 83, "linux": 83,
"xkb": 91, "xkb": 91,
"windows": 83, "windows": 83,
"macos": 65 "macos": 65,
"ios": 99
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -4496,7 +4606,8 @@ ...@@ -4496,7 +4606,8 @@
"linux": 86, "linux": 86,
"xkb": 94, "xkb": 94,
"windows": 86, "windows": 86,
"macos": 10 "macos": 10,
"ios": 100
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -4530,7 +4641,8 @@ ...@@ -4530,7 +4641,8 @@
"linux": 127, "linux": 127,
"xkb": 135, "xkb": 135,
"windows": 57437, "windows": 57437,
"macos": 110 "macos": 110,
"ios": 101
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -4568,7 +4680,8 @@ ...@@ -4568,7 +4680,8 @@
"linux": 116, "linux": 116,
"xkb": 124, "xkb": 124,
"windows": 57438, "windows": 57438,
"macos": null "macos": null,
"ios": 102
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -4607,7 +4720,8 @@ ...@@ -4607,7 +4720,8 @@
"linux": 117, "linux": 117,
"xkb": 125, "xkb": 125,
"windows": 89, "windows": 89,
"macos": 81 "macos": 81,
"ios": 103
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -4650,7 +4764,8 @@ ...@@ -4650,7 +4764,8 @@
"linux": 183, "linux": 183,
"xkb": 191, "xkb": 191,
"windows": 100, "windows": 100,
"macos": 105 "macos": 105,
"ios": 104
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -4691,7 +4806,8 @@ ...@@ -4691,7 +4806,8 @@
"linux": 184, "linux": 184,
"xkb": 192, "xkb": 192,
"windows": 101, "windows": 101,
"macos": 107 "macos": 107,
"ios": 105
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -4732,7 +4848,8 @@ ...@@ -4732,7 +4848,8 @@
"linux": 185, "linux": 185,
"xkb": 193, "xkb": 193,
"windows": 102, "windows": 102,
"macos": 113 "macos": 113,
"ios": 106
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -4773,7 +4890,8 @@ ...@@ -4773,7 +4890,8 @@
"linux": 186, "linux": 186,
"xkb": 194, "xkb": 194,
"windows": 103, "windows": 103,
"macos": 106 "macos": 106,
"ios": 107
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -4814,7 +4932,8 @@ ...@@ -4814,7 +4932,8 @@
"linux": 187, "linux": 187,
"xkb": 195, "xkb": 195,
"windows": 104, "windows": 104,
"macos": 64 "macos": 64,
"ios": 108
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -4855,7 +4974,8 @@ ...@@ -4855,7 +4974,8 @@
"linux": 188, "linux": 188,
"xkb": 196, "xkb": 196,
"windows": 105, "windows": 105,
"macos": 79 "macos": 79,
"ios": 109
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -4896,7 +5016,8 @@ ...@@ -4896,7 +5016,8 @@
"linux": 189, "linux": 189,
"xkb": 197, "xkb": 197,
"windows": 106, "windows": 106,
"macos": 80 "macos": 80,
"ios": 110
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -4937,7 +5058,8 @@ ...@@ -4937,7 +5058,8 @@
"linux": 190, "linux": 190,
"xkb": 198, "xkb": 198,
"windows": 107, "windows": 107,
"macos": 90 "macos": 90,
"ios": 111
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -4978,7 +5100,8 @@ ...@@ -4978,7 +5100,8 @@
"linux": 191, "linux": 191,
"xkb": 199, "xkb": 199,
"windows": 108, "windows": 108,
"macos": null "macos": null,
"ios": 112
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -5019,7 +5142,8 @@ ...@@ -5019,7 +5142,8 @@
"linux": 192, "linux": 192,
"xkb": 200, "xkb": 200,
"windows": 109, "windows": 109,
"macos": null "macos": null,
"ios": 113
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -5060,7 +5184,8 @@ ...@@ -5060,7 +5184,8 @@
"linux": 193, "linux": 193,
"xkb": 201, "xkb": 201,
"windows": 110, "windows": 110,
"macos": null "macos": null,
"ios": 114
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -5099,7 +5224,8 @@ ...@@ -5099,7 +5224,8 @@
"linux": 194, "linux": 194,
"xkb": 202, "xkb": 202,
"windows": 118, "windows": 118,
"macos": null "macos": null,
"ios": 115
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -5134,7 +5260,8 @@ ...@@ -5134,7 +5260,8 @@
"linux": 134, "linux": 134,
"xkb": 142, "xkb": 142,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": 116
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -5169,7 +5296,8 @@ ...@@ -5169,7 +5296,8 @@
"linux": 138, "linux": 138,
"xkb": 146, "xkb": 146,
"windows": 57403, "windows": 57403,
"macos": null "macos": null,
"ios": 117
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -5208,7 +5336,8 @@ ...@@ -5208,7 +5336,8 @@
"linux": 132, "linux": 132,
"xkb": 140, "xkb": 140,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": 119
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -5243,7 +5372,8 @@ ...@@ -5243,7 +5372,8 @@
"linux": 129, "linux": 129,
"xkb": 137, "xkb": 137,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": 121
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -5274,7 +5404,8 @@ ...@@ -5274,7 +5404,8 @@
"linux": 131, "linux": 131,
"xkb": 139, "xkb": 139,
"windows": 57352, "windows": 57352,
"macos": null "macos": null,
"ios": 122
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -5305,7 +5436,8 @@ ...@@ -5305,7 +5436,8 @@
"linux": 137, "linux": 137,
"xkb": 145, "xkb": 145,
"windows": 57367, "windows": 57367,
"macos": null "macos": null,
"ios": 123
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -5339,7 +5471,8 @@ ...@@ -5339,7 +5471,8 @@
"linux": 133, "linux": 133,
"xkb": 141, "xkb": 141,
"windows": 57368, "windows": 57368,
"macos": null "macos": null,
"ios": 124
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -5375,7 +5508,8 @@ ...@@ -5375,7 +5508,8 @@
"linux": 135, "linux": 135,
"xkb": 143, "xkb": 143,
"windows": 57354, "windows": 57354,
"macos": null "macos": null,
"ios": 125
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -5410,7 +5544,8 @@ ...@@ -5410,7 +5544,8 @@
"linux": 136, "linux": 136,
"xkb": 144, "xkb": 144,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": 126
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -5443,7 +5578,8 @@ ...@@ -5443,7 +5578,8 @@
"linux": 113, "linux": 113,
"xkb": 121, "xkb": 121,
"windows": 57376, "windows": 57376,
"macos": 74 "macos": 74,
"ios": 127
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -5478,7 +5614,8 @@ ...@@ -5478,7 +5614,8 @@
"linux": 115, "linux": 115,
"xkb": 123, "xkb": 123,
"windows": 57392, "windows": 57392,
"macos": 72 "macos": 72,
"ios": 128
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -5513,7 +5650,8 @@ ...@@ -5513,7 +5650,8 @@
"linux": 114, "linux": 114,
"xkb": 122, "xkb": 122,
"windows": 57390, "windows": 57390,
"macos": 73 "macos": 73,
"ios": 129
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -5547,7 +5685,8 @@ ...@@ -5547,7 +5685,8 @@
"linux": 121, "linux": 121,
"xkb": 129, "xkb": 129,
"windows": 126, "windows": 126,
"macos": 95 "macos": 95,
"ios": 133
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -5574,7 +5713,8 @@ ...@@ -5574,7 +5713,8 @@
"linux": 89, "linux": 89,
"xkb": 97, "xkb": 97,
"windows": 115, "windows": 115,
"macos": 94 "macos": 94,
"ios": 135
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -5601,7 +5741,8 @@ ...@@ -5601,7 +5741,8 @@
"linux": 93, "linux": 93,
"xkb": 101, "xkb": 101,
"windows": 112, "windows": 112,
"macos": null "macos": null,
"ios": 136
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -5630,7 +5771,8 @@ ...@@ -5630,7 +5771,8 @@
"linux": 124, "linux": 124,
"xkb": 132, "xkb": 132,
"windows": 125, "windows": 125,
"macos": 93 "macos": 93,
"ios": 137
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -5663,7 +5805,8 @@ ...@@ -5663,7 +5805,8 @@
"linux": 92, "linux": 92,
"xkb": 100, "xkb": 100,
"windows": 121, "windows": 121,
"macos": null "macos": null,
"ios": 138
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -5696,7 +5839,8 @@ ...@@ -5696,7 +5839,8 @@
"linux": 94, "linux": 94,
"xkb": 102, "xkb": 102,
"windows": 123, "windows": 123,
"macos": null "macos": null,
"ios": 139
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -5723,7 +5867,8 @@ ...@@ -5723,7 +5867,8 @@
"linux": 122, "linux": 122,
"xkb": 130, "xkb": 130,
"windows": 114, "windows": 114,
"macos": 104 "macos": 104,
"ios": 144
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -5748,7 +5893,8 @@ ...@@ -5748,7 +5893,8 @@
"linux": 123, "linux": 123,
"xkb": 131, "xkb": 131,
"windows": 113, "windows": 113,
"macos": 102 "macos": 102,
"ios": 145
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -5777,7 +5923,8 @@ ...@@ -5777,7 +5923,8 @@
"linux": 90, "linux": 90,
"xkb": 98, "xkb": 98,
"windows": 120, "windows": 120,
"macos": null "macos": null,
"ios": 146
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -5806,7 +5953,8 @@ ...@@ -5806,7 +5953,8 @@
"linux": 91, "linux": 91,
"xkb": 99, "xkb": 99,
"windows": 119, "windows": 119,
"macos": null "macos": null,
"ios": 147
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -5831,7 +5979,8 @@ ...@@ -5831,7 +5979,8 @@
"linux": 85, "linux": 85,
"xkb": 93, "xkb": 93,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": 148
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -5856,7 +6005,8 @@ ...@@ -5856,7 +6005,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": 155
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -5885,7 +6035,8 @@ ...@@ -5885,7 +6035,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": 163
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -5914,7 +6065,8 @@ ...@@ -5914,7 +6065,8 @@
"linux": 179, "linux": 179,
"xkb": 187, "xkb": 187,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": 182
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -5945,7 +6097,8 @@ ...@@ -5945,7 +6097,8 @@
"linux": 180, "linux": 180,
"xkb": 188, "xkb": 188,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": 183
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -5972,7 +6125,8 @@ ...@@ -5972,7 +6125,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": 187
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -5997,7 +6151,8 @@ ...@@ -5997,7 +6151,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": 208
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -6022,7 +6177,8 @@ ...@@ -6022,7 +6177,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": 209
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -6047,7 +6203,8 @@ ...@@ -6047,7 +6203,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": 210
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -6072,7 +6229,8 @@ ...@@ -6072,7 +6229,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": 211
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -6097,7 +6255,8 @@ ...@@ -6097,7 +6255,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": 212
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -6122,7 +6281,8 @@ ...@@ -6122,7 +6281,8 @@
"linux": 118, "linux": 118,
"xkb": 126, "xkb": 126,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": 215
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -6147,7 +6307,8 @@ ...@@ -6147,7 +6307,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": 216
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -6172,7 +6333,8 @@ ...@@ -6172,7 +6333,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": 217
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -6207,7 +6369,8 @@ ...@@ -6207,7 +6369,8 @@
"linux": 29, "linux": 29,
"xkb": 37, "xkb": 37,
"windows": 29, "windows": 29,
"macos": 59 "macos": 59,
"ios": 224
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -6250,7 +6413,8 @@ ...@@ -6250,7 +6413,8 @@
"linux": 42, "linux": 42,
"xkb": 50, "xkb": 50,
"windows": 42, "windows": 42,
"macos": 56 "macos": 56,
"ios": 225
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -6293,7 +6457,8 @@ ...@@ -6293,7 +6457,8 @@
"linux": 56, "linux": 56,
"xkb": 64, "xkb": 64,
"windows": 56, "windows": 56,
"macos": 58 "macos": 58,
"ios": 226
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -6336,7 +6501,8 @@ ...@@ -6336,7 +6501,8 @@
"linux": 125, "linux": 125,
"xkb": 133, "xkb": 133,
"windows": 57435, "windows": 57435,
"macos": 55 "macos": 55,
"ios": 227
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -6379,7 +6545,8 @@ ...@@ -6379,7 +6545,8 @@
"linux": 97, "linux": 97,
"xkb": 105, "xkb": 105,
"windows": 57373, "windows": 57373,
"macos": 62 "macos": 62,
"ios": 228
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -6422,7 +6589,8 @@ ...@@ -6422,7 +6589,8 @@
"linux": 54, "linux": 54,
"xkb": 62, "xkb": 62,
"windows": 54, "windows": 54,
"macos": 60 "macos": 60,
"ios": 229
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -6465,7 +6633,8 @@ ...@@ -6465,7 +6633,8 @@
"linux": 100, "linux": 100,
"xkb": 108, "xkb": 108,
"windows": 57400, "windows": 57400,
"macos": 61 "macos": 61,
"ios": 230
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -6508,7 +6677,8 @@ ...@@ -6508,7 +6677,8 @@
"linux": 126, "linux": 126,
"xkb": 134, "xkb": 134,
"windows": 57436, "windows": 57436,
"macos": 54 "macos": 54,
"ios": 231
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -6545,7 +6715,8 @@ ...@@ -6545,7 +6715,8 @@
"linux": 358, "linux": 358,
"xkb": 366, "xkb": 366,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -6576,7 +6747,8 @@ ...@@ -6576,7 +6747,8 @@
"linux": 370, "linux": 370,
"xkb": 378, "xkb": 378,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -6609,7 +6781,8 @@ ...@@ -6609,7 +6781,8 @@
"linux": 225, "linux": 225,
"xkb": 233, "xkb": 233,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -6644,7 +6817,8 @@ ...@@ -6644,7 +6817,8 @@
"linux": 224, "linux": 224,
"xkb": 232, "xkb": 232,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -6673,7 +6847,8 @@ ...@@ -6673,7 +6847,8 @@
"linux": 431, "linux": 431,
"xkb": 439, "xkb": 439,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -6698,7 +6873,8 @@ ...@@ -6698,7 +6873,8 @@
"linux": 592, "linux": 592,
"xkb": 600, "xkb": 600,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -6723,7 +6899,8 @@ ...@@ -6723,7 +6899,8 @@
"linux": 593, "linux": 593,
"xkb": 601, "xkb": 601,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -6748,7 +6925,8 @@ ...@@ -6748,7 +6925,8 @@
"linux": 244, "linux": 244,
"xkb": 252, "xkb": 252,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -6775,7 +6953,8 @@ ...@@ -6775,7 +6953,8 @@
"linux": 230, "linux": 230,
"xkb": 238, "xkb": 238,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -6804,7 +6983,8 @@ ...@@ -6804,7 +6983,8 @@
"linux": 229, "linux": 229,
"xkb": 237, "xkb": 237,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -6835,7 +7015,8 @@ ...@@ -6835,7 +7015,8 @@
"linux": 405, "linux": 405,
"xkb": 413, "xkb": 413,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -6864,7 +7045,8 @@ ...@@ -6864,7 +7045,8 @@
"linux": 169, "linux": 169,
"xkb": 177, "xkb": 177,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -6891,7 +7073,8 @@ ...@@ -6891,7 +7073,8 @@
"linux": 362, "linux": 362,
"xkb": 370, "xkb": 370,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -6920,7 +7103,8 @@ ...@@ -6920,7 +7103,8 @@
"linux": 174, "linux": 174,
"xkb": 182, "xkb": 182,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -6949,7 +7133,8 @@ ...@@ -6949,7 +7133,8 @@
"linux": 410, "linux": 410,
"xkb": 418, "xkb": 418,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -6980,7 +7165,8 @@ ...@@ -6980,7 +7165,8 @@
"linux": 411, "linux": 411,
"xkb": 419, "xkb": 419,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -7015,7 +7201,8 @@ ...@@ -7015,7 +7201,8 @@
"linux": 207, "linux": 207,
"xkb": 215, "xkb": 215,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -7051,7 +7238,8 @@ ...@@ -7051,7 +7238,8 @@
"linux": 201, "linux": 201,
"xkb": 209, "xkb": 209,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -7086,7 +7274,8 @@ ...@@ -7086,7 +7274,8 @@
"linux": 167, "linux": 167,
"xkb": 175, "xkb": 175,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -7121,7 +7310,8 @@ ...@@ -7121,7 +7310,8 @@
"linux": 208, "linux": 208,
"xkb": 216, "xkb": 216,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -7156,7 +7346,8 @@ ...@@ -7156,7 +7346,8 @@
"linux": 168, "linux": 168,
"xkb": 176, "xkb": 176,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -7191,7 +7382,8 @@ ...@@ -7191,7 +7382,8 @@
"linux": 163, "linux": 163,
"xkb": 171, "xkb": 171,
"windows": 57369, "windows": 57369,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -7226,7 +7418,8 @@ ...@@ -7226,7 +7418,8 @@
"linux": 165, "linux": 165,
"xkb": 173, "xkb": 173,
"windows": 57360, "windows": 57360,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -7264,7 +7457,8 @@ ...@@ -7264,7 +7457,8 @@
"linux": 166, "linux": 166,
"xkb": 174, "xkb": 174,
"windows": 57380, "windows": 57380,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -7302,7 +7496,8 @@ ...@@ -7302,7 +7496,8 @@
"linux": 161, "linux": 161,
"xkb": 169, "xkb": 169,
"windows": 57388, "windows": 57388,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -7337,7 +7532,8 @@ ...@@ -7337,7 +7532,8 @@
"linux": 164, "linux": 164,
"xkb": 172, "xkb": 172,
"windows": 57378, "windows": 57378,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -7366,7 +7562,8 @@ ...@@ -7366,7 +7562,8 @@
"linux": 582, "linux": 582,
"xkb": 590, "xkb": 590,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -7395,7 +7592,8 @@ ...@@ -7395,7 +7592,8 @@
"linux": 209, "linux": 209,
"xkb": 217, "xkb": 217,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -7420,7 +7618,8 @@ ...@@ -7420,7 +7618,8 @@
"linux": 171, "linux": 171,
"xkb": 179, "xkb": 179,
"windows": 57453, "windows": 57453,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -7445,7 +7644,8 @@ ...@@ -7445,7 +7644,8 @@
"linux": 421, "linux": 421,
"xkb": 429, "xkb": 429,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -7470,7 +7670,8 @@ ...@@ -7470,7 +7670,8 @@
"linux": 423, "linux": 423,
"xkb": 431, "xkb": 431,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -7504,7 +7705,8 @@ ...@@ -7504,7 +7705,8 @@
"linux": 155, "linux": 155,
"xkb": 163, "xkb": 163,
"windows": 57452, "windows": 57452,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -7539,7 +7741,8 @@ ...@@ -7539,7 +7741,8 @@
"linux": 429, "linux": 429,
"xkb": 437, "xkb": 437,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -7572,7 +7775,8 @@ ...@@ -7572,7 +7775,8 @@
"linux": 397, "linux": 397,
"xkb": 405, "xkb": 405,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -7603,7 +7807,8 @@ ...@@ -7603,7 +7807,8 @@
"linux": 140, "linux": 140,
"xkb": 148, "xkb": 148,
"windows": 57377, "windows": 57377,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -7632,7 +7837,8 @@ ...@@ -7632,7 +7837,8 @@
"linux": 144, "linux": 144,
"xkb": 152, "xkb": 152,
"windows": 57451, "windows": 57451,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -7661,7 +7867,8 @@ ...@@ -7661,7 +7867,8 @@
"linux": 150, "linux": 150,
"xkb": 158, "xkb": 158,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -7690,7 +7897,8 @@ ...@@ -7690,7 +7897,8 @@
"linux": 433, "linux": 433,
"xkb": 441, "xkb": 441,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -7717,7 +7925,8 @@ ...@@ -7717,7 +7925,8 @@
"linux": 152, "linux": 152,
"xkb": 160, "xkb": 160,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -7742,7 +7951,8 @@ ...@@ -7742,7 +7951,8 @@
"linux": 579, "linux": 579,
"xkb": 587, "xkb": 587,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -7767,7 +7977,8 @@ ...@@ -7767,7 +7977,8 @@
"linux": 580, "linux": 580,
"xkb": 588, "xkb": 588,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -7794,7 +8005,8 @@ ...@@ -7794,7 +8005,8 @@
"linux": 235, "linux": 235,
"xkb": 243, "xkb": 243,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -7821,7 +8033,8 @@ ...@@ -7821,7 +8033,8 @@
"linux": 432, "linux": 432,
"xkb": 440, "xkb": 440,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -7848,7 +8061,8 @@ ...@@ -7848,7 +8061,8 @@
"linux": 374, "linux": 374,
"xkb": 382, "xkb": 382,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -7875,7 +8089,8 @@ ...@@ -7875,7 +8089,8 @@
"linux": 581, "linux": 581,
"xkb": 589, "xkb": 589,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -7906,7 +8121,8 @@ ...@@ -7906,7 +8121,8 @@
"linux": 583, "linux": 583,
"xkb": 591, "xkb": 591,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -7935,7 +8151,8 @@ ...@@ -7935,7 +8151,8 @@
"linux": 392, "linux": 392,
"xkb": 400, "xkb": 400,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -7968,7 +8185,8 @@ ...@@ -7968,7 +8185,8 @@
"linux": 181, "linux": 181,
"xkb": 189, "xkb": 189,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -8003,7 +8221,8 @@ ...@@ -8003,7 +8221,8 @@
"linux": 206, "linux": 206,
"xkb": 214, "xkb": 214,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -8034,7 +8253,8 @@ ...@@ -8034,7 +8253,8 @@
"linux": 234, "linux": 234,
"xkb": 242, "xkb": 242,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -8069,7 +8289,8 @@ ...@@ -8069,7 +8289,8 @@
"linux": 210, "linux": 210,
"xkb": 218, "xkb": 218,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -8106,7 +8327,8 @@ ...@@ -8106,7 +8327,8 @@
"linux": 217, "linux": 217,
"xkb": 225, "xkb": 225,
"windows": 57445, "windows": 57445,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -8141,7 +8363,8 @@ ...@@ -8141,7 +8363,8 @@
"linux": 172, "linux": 172,
"xkb": 180, "xkb": 180,
"windows": 57394, "windows": 57394,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -8174,7 +8397,8 @@ ...@@ -8174,7 +8397,8 @@
"linux": 158, "linux": 158,
"xkb": 166, "xkb": 166,
"windows": 57450, "windows": 57450,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -8211,7 +8435,8 @@ ...@@ -8211,7 +8435,8 @@
"linux": 159, "linux": 159,
"xkb": 167, "xkb": 167,
"windows": 57449, "windows": 57449,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -8246,7 +8471,8 @@ ...@@ -8246,7 +8471,8 @@
"linux": 128, "linux": 128,
"xkb": 136, "xkb": 136,
"windows": 57448, "windows": 57448,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -8279,7 +8505,8 @@ ...@@ -8279,7 +8505,8 @@
"linux": 173, "linux": 173,
"xkb": 181, "xkb": 181,
"windows": 57447, "windows": 57447,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -8316,7 +8543,8 @@ ...@@ -8316,7 +8543,8 @@
"linux": 156, "linux": 156,
"xkb": 164, "xkb": 164,
"windows": 57446, "windows": 57446,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -8351,7 +8579,8 @@ ...@@ -8351,7 +8579,8 @@
"linux": 418, "linux": 418,
"xkb": 426, "xkb": 426,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -8384,7 +8613,8 @@ ...@@ -8384,7 +8613,8 @@
"linux": 419, "linux": 419,
"xkb": 427, "xkb": 427,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -8415,7 +8645,8 @@ ...@@ -8415,7 +8645,8 @@
"linux": 372, "linux": 372,
"xkb": 380, "xkb": 380,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -8448,7 +8679,8 @@ ...@@ -8448,7 +8679,8 @@
"linux": 182, "linux": 182,
"xkb": 190, "xkb": 190,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -8477,7 +8709,8 @@ ...@@ -8477,7 +8709,8 @@
"linux": 232, "linux": 232,
"xkb": 240, "xkb": 240,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -8506,7 +8739,8 @@ ...@@ -8506,7 +8739,8 @@
"linux": 233, "linux": 233,
"xkb": 241, "xkb": 241,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -8535,7 +8769,8 @@ ...@@ -8535,7 +8769,8 @@
"linux": 231, "linux": 231,
"xkb": 239, "xkb": 239,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -8562,7 +8797,8 @@ ...@@ -8562,7 +8797,8 @@
"linux": 584, "linux": 584,
"xkb": 592, "xkb": 592,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -8587,7 +8823,8 @@ ...@@ -8587,7 +8823,8 @@
"linux": 120, "linux": 120,
"xkb": 128, "xkb": 128,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": null, "android": null,
...@@ -8617,7 +8854,8 @@ ...@@ -8617,7 +8854,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -8649,7 +8887,8 @@ ...@@ -8649,7 +8887,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -8681,7 +8920,8 @@ ...@@ -8681,7 +8920,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -8713,7 +8953,8 @@ ...@@ -8713,7 +8953,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -8745,7 +8986,8 @@ ...@@ -8745,7 +8986,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -8777,7 +9019,8 @@ ...@@ -8777,7 +9019,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -8809,7 +9052,8 @@ ...@@ -8809,7 +9052,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -8841,7 +9085,8 @@ ...@@ -8841,7 +9085,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -8873,7 +9118,8 @@ ...@@ -8873,7 +9118,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -8905,7 +9151,8 @@ ...@@ -8905,7 +9151,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -8937,7 +9184,8 @@ ...@@ -8937,7 +9184,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -8969,7 +9217,8 @@ ...@@ -8969,7 +9217,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -9001,7 +9250,8 @@ ...@@ -9001,7 +9250,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -9033,7 +9283,8 @@ ...@@ -9033,7 +9283,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -9065,7 +9316,8 @@ ...@@ -9065,7 +9316,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -9097,7 +9349,8 @@ ...@@ -9097,7 +9349,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -9128,7 +9381,8 @@ ...@@ -9128,7 +9381,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -9159,7 +9413,8 @@ ...@@ -9159,7 +9413,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -9190,7 +9445,8 @@ ...@@ -9190,7 +9445,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -9221,7 +9477,8 @@ ...@@ -9221,7 +9477,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -9252,7 +9509,8 @@ ...@@ -9252,7 +9509,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -9283,7 +9541,8 @@ ...@@ -9283,7 +9541,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -9314,7 +9573,8 @@ ...@@ -9314,7 +9573,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -9345,7 +9605,8 @@ ...@@ -9345,7 +9605,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -9376,7 +9637,8 @@ ...@@ -9376,7 +9637,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -9407,7 +9669,8 @@ ...@@ -9407,7 +9669,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -9438,7 +9701,8 @@ ...@@ -9438,7 +9701,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -9469,7 +9733,8 @@ ...@@ -9469,7 +9733,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -9500,7 +9765,8 @@ ...@@ -9500,7 +9765,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -9531,7 +9797,8 @@ ...@@ -9531,7 +9797,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -9562,7 +9829,8 @@ ...@@ -9562,7 +9829,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": null "macos": null,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
...@@ -9593,7 +9861,8 @@ ...@@ -9593,7 +9861,8 @@
"linux": null, "linux": null,
"xkb": null, "xkb": null,
"windows": null, "windows": null,
"macos": 63 "macos": 63,
"ios": null
}, },
"keyCodes": { "keyCodes": {
"android": [ "android": [
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <map>
// DO NOT EDIT -- DO NOT EDIT -- DO NOT EDIT
// This file is generated by flutter/flutter@dev/tools/gen_keycodes/bin/gen_keycodes.dart and
// should not be edited directly.
//
// Edit the template dev/tools/gen_keycodes/data/keyboard_map_ios_cc.tmpl instead.
// See dev/tools/gen_keycodes/README.md for more information.
// Maps macOS-specific key code values representing [PhysicalKeyboardKey].
//
// iOS doesn't provide a scan code, but a virtual keycode to represent a physical key.
const std::map<int, int> g_ios_to_physical_key = {
@@@IOS_SCAN_CODE_MAP@@@
};
// A map of iOS key codes which have printable representations, but appear
// on the number pad. Used to provide different key objects for keys like
// KEY_EQUALS and NUMPAD_EQUALS.
const std::map<int, int> g_ios_numpad_map = {
@@@IOS_NUMPAD_MAP@@@
};
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
// This file is generated by flutter/flutter@dev/tools/gen_keycodes/bin/gen_keycodes.dart and // This file is generated by flutter/flutter@dev/tools/gen_keycodes/bin/gen_keycodes.dart and
// should not be edited directly. // should not be edited directly.
// //
// Edit the template dev/tools/gen_keycodes/data/keyboard_map_darwin_cc.tmpl instead. // Edit the template dev/tools/gen_keycodes/data/keyboard_map_macos_cc.tmpl instead.
// See dev/tools/gen_keycodes/README.md for more information. // See dev/tools/gen_keycodes/README.md for more information.
// Maps macOS-specific key code values representing [PhysicalKeyboardKey]. // Maps macOS-specific key code values representing [PhysicalKeyboardKey].
......
...@@ -59,6 +59,20 @@ const Map<int, LogicalKeyboardKey> kMacOsFunctionKeyMap = <int, LogicalKeyboardK ...@@ -59,6 +59,20 @@ const Map<int, LogicalKeyboardKey> kMacOsFunctionKeyMap = <int, LogicalKeyboardK
@@@MACOS_FUNCTION_KEY_MAP@@@ @@@MACOS_FUNCTION_KEY_MAP@@@
}; };
/// Maps iOS-specific key code values representing [PhysicalKeyboardKey].
///
/// iOS doesn't provide a scan code, but a virtual keycode to represent a physical key.
const Map<int, PhysicalKeyboardKey> kIosToPhysicalKey = <int, PhysicalKeyboardKey>{
@@@IOS_SCAN_CODE_MAP@@@
};
/// A map of iOS key codes which have printable representations, but appear
/// on the number pad. Used to provide different key objects for keys like
/// KEY_EQUALS and NUMPAD_EQUALS.
const Map<int, LogicalKeyboardKey> kIosNumPadMap = <int, LogicalKeyboardKey>{
@@@IOS_NUMPAD_MAP@@@
};
/// Maps GLFW-specific key codes to the matching [LogicalKeyboardKey]. /// Maps GLFW-specific key codes to the matching [LogicalKeyboardKey].
const Map<int, LogicalKeyboardKey> kGlfwToLogicalKey = <int, LogicalKeyboardKey>{ const Map<int, LogicalKeyboardKey> kGlfwToLogicalKey = <int, LogicalKeyboardKey>{
@@@GLFW_KEY_CODE_MAP@@@ @@@GLFW_KEY_CODE_MAP@@@
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:path/path.dart' as path;
import 'base_code_gen.dart';
import 'key_data.dart';
import 'utils.dart';
/// Generates the key mapping of iOS, based on the information in the key
/// data structure given to it.
class IosCodeGenerator extends PlatformCodeGenerator {
IosCodeGenerator(KeyData keyData) : super(keyData);
/// This generates the map of iOS key codes to physical keys.
String get _iosScanCodeMap {
final StringBuffer iosScanCodeMap = StringBuffer();
for (final Key entry in keyData.data) {
if (entry.iosScanCode != null) {
iosScanCodeMap.writeln(' { ${toHex(entry.iosScanCode)}, ${toHex(entry.usbHidCode)} }, // ${entry.constantName}');
}
}
return iosScanCodeMap.toString().trimRight();
}
/// This generates the map of iOS number pad key codes to logical keys.
String get _iosNumpadMap {
final StringBuffer iosNumPadMap = StringBuffer();
for (final Key entry in numpadKeyData) {
if (entry.iosScanCode != null) {
iosNumPadMap.writeln(' { ${toHex(entry.iosScanCode)}, ${toHex(entry.flutterId, digits: 10)} }, // ${entry.constantName}');
}
}
return iosNumPadMap.toString().trimRight();
}
@override
String get templatePath => path.join(flutterRoot.path, 'dev', 'tools', 'gen_keycodes', 'data', 'keyboard_map_ios_cc.tmpl');
@override
String outputPath(String platform) => path.joinAll(<String>[flutterRoot.path, '..', 'engine', 'src', 'flutter', 'shell', 'platform', 'darwin', platform, 'keycodes', 'keyboard_map_$platform.h']);
@override
Map<String, String> mappings() {
// There is no iOS keycode map since iOS uses keycode to represent a physical key.
// The LogicalKeyboardKey is generated by raw_keyboard_macos.dart from the unmodified characters
// from NSEvent.
return <String, String>{
'IOS_SCAN_CODE_MAP': _iosScanCodeMap,
'IOS_NUMPAD_MAP': _iosNumpadMap
};
}
}
...@@ -325,16 +325,18 @@ class KeyData { ...@@ -325,16 +325,18 @@ class KeyData {
input = input.replaceAll(commentRegExp, ''); input = input.replaceAll(commentRegExp, '');
input.replaceAllMapped(usbMapRegExp, (Match match) { input.replaceAllMapped(usbMapRegExp, (Match match) {
if (match != null) { if (match != null) {
final int usbHidCode = getHex(match.group(1));
final int macScanCode = getHex(match.group(5)); final int macScanCode = getHex(match.group(5));
final int linuxScanCode = getHex(match.group(2)); final int linuxScanCode = getHex(match.group(2));
final int xKbScanCode = getHex(match.group(3)); final int xKbScanCode = getHex(match.group(3));
final int windowsScanCode = getHex(match.group(4)); final int windowsScanCode = getHex(match.group(4));
final Key newEntry = Key( final Key newEntry = Key(
usbHidCode: getHex(match.group(1)), usbHidCode: usbHidCode,
linuxScanCode: linuxScanCode == 0 ? null : linuxScanCode, linuxScanCode: linuxScanCode == 0 ? null : linuxScanCode,
xKbScanCode: xKbScanCode == 0 ? null : xKbScanCode, xKbScanCode: xKbScanCode == 0 ? null : xKbScanCode,
windowsScanCode: windowsScanCode == 0 ? null : windowsScanCode, windowsScanCode: windowsScanCode == 0 ? null : windowsScanCode,
macOsScanCode: macScanCode == 0xffff ? null : macScanCode, macOsScanCode: macScanCode == 0xffff ? null : macScanCode,
iosScanCode: (usbHidCode & 0x070000) == 0x070000 ? (usbHidCode ^ 0x070000) : null,
name: match.group(6) == 'NULL' ? null : match.group(6), name: match.group(6) == 'NULL' ? null : match.group(6),
// The input data has a typo... // The input data has a typo...
chromiumName: shoutingToLowerCamel(match.group(7)).replaceAll('Minimium', 'Minimum'), chromiumName: shoutingToLowerCamel(match.group(7)).replaceAll('Minimium', 'Minimum'),
...@@ -375,6 +377,7 @@ class Key { ...@@ -375,6 +377,7 @@ class Key {
this.windowsKeyNames, this.windowsKeyNames,
this.windowsKeyCodes, this.windowsKeyCodes,
this.macOsScanCode, this.macOsScanCode,
this.iosScanCode,
@required this.chromiumName, @required this.chromiumName,
this.androidKeyNames, this.androidKeyNames,
this.androidScanCodes, this.androidScanCodes,
...@@ -403,6 +406,7 @@ class Key { ...@@ -403,6 +406,7 @@ class Key {
windowsKeyCodes: (map['keyCodes']['windows'] as List<dynamic>)?.cast<int>(), windowsKeyCodes: (map['keyCodes']['windows'] as List<dynamic>)?.cast<int>(),
windowsKeyNames: (map['names']['windows'] as List<dynamic>)?.cast<String>(), windowsKeyNames: (map['names']['windows'] as List<dynamic>)?.cast<String>(),
macOsScanCode: map['scanCodes']['macos'] as int, macOsScanCode: map['scanCodes']['macos'] as int,
iosScanCode: map['scanCodes']['ios'] as int,
glfwKeyNames: (map['names']['glfw'] as List<dynamic>)?.cast<String>(), glfwKeyNames: (map['names']['glfw'] as List<dynamic>)?.cast<String>(),
glfwKeyCodes: (map['keyCodes']['glfw'] as List<dynamic>)?.cast<int>(), glfwKeyCodes: (map['keyCodes']['glfw'] as List<dynamic>)?.cast<int>(),
gtkKeyNames: (map['names']['gtk'] as List<dynamic>)?.cast<String>(), gtkKeyNames: (map['names']['gtk'] as List<dynamic>)?.cast<String>(),
...@@ -428,6 +432,8 @@ class Key { ...@@ -428,6 +432,8 @@ class Key {
List<String> windowsKeyNames; List<String> windowsKeyNames;
/// The macOS scan code of the key from Chromium's header file. /// The macOS scan code of the key from Chromium's header file.
int macOsScanCode; int macOsScanCode;
/// The iOS scan code of the key from UIKey's documentation (USB Hid table)
int iosScanCode;
/// The name of the key, mostly derived from the DomKey name in Chromium, /// The name of the key, mostly derived from the DomKey name in Chromium,
/// but where there was no DomKey representation, derived from the Chromium /// but where there was no DomKey representation, derived from the Chromium
/// symbol name. /// symbol name.
...@@ -483,6 +489,7 @@ class Key { ...@@ -483,6 +489,7 @@ class Key {
'xkb': xKbScanCode, 'xkb': xKbScanCode,
'windows': windowsScanCode, 'windows': windowsScanCode,
'macos': macOsScanCode, 'macos': macOsScanCode,
'ios': iosScanCode,
}, },
'keyCodes': <String, List<int>>{ 'keyCodes': <String, List<int>>{
'android': androidKeyCodes, 'android': androidKeyCodes,
...@@ -550,7 +557,8 @@ class Key { ...@@ -550,7 +557,8 @@ class Key {
return """'$constantName': (name: "$name", usbHidCode: ${toHex(usbHidCode)}, """ return """'$constantName': (name: "$name", usbHidCode: ${toHex(usbHidCode)}, """
'linuxScanCode: ${toHex(linuxScanCode)}, xKbScanCode: ${toHex(xKbScanCode)}, ' 'linuxScanCode: ${toHex(linuxScanCode)}, xKbScanCode: ${toHex(xKbScanCode)}, '
'windowsKeyCode: ${toHex(windowsScanCode)}, macOsScanCode: ${toHex(macOsScanCode)}, ' 'windowsKeyCode: ${toHex(windowsScanCode)}, macOsScanCode: ${toHex(macOsScanCode)}, '
'windowsScanCode: ${toHex(windowsScanCode)}, chromiumSymbolName: $chromiumName'; 'windowsScanCode: ${toHex(windowsScanCode)}, chromiumSymbolName: $chromiumName '
'iOSScanCode: ${toHex(iosScanCode)})';
} }
/// Returns the static map of printable representations. /// Returns the static map of printable representations.
......
...@@ -198,6 +198,28 @@ class KeyboardMapsCodeGenerator extends BaseCodeGenerator { ...@@ -198,6 +198,28 @@ class KeyboardMapsCodeGenerator extends BaseCodeGenerator {
return macOsFunctionKeyMap.toString().trimRight(); return macOsFunctionKeyMap.toString().trimRight();
} }
/// This generates the map of iOS key codes to physical keys.
String get iosScanCodeMap {
final StringBuffer iosScanCodeMap = StringBuffer();
for (final Key entry in keyData.data) {
if (entry.iosScanCode != null) {
iosScanCodeMap.writeln(' ${toHex(entry.iosScanCode)}: PhysicalKeyboardKey.${entry.constantName},');
}
}
return iosScanCodeMap.toString().trimRight();
}
/// This generates the map of iOS number pad key codes to logical keys.
String get iosNumpadMap {
final StringBuffer iosNumPadMap = StringBuffer();
for (final Key entry in numpadKeyData) {
if (entry.iosScanCode != null) {
iosNumPadMap.writeln(' ${toHex(entry.iosScanCode)}: LogicalKeyboardKey.${entry.constantName},');
}
}
return iosNumPadMap.toString().trimRight();
}
/// This generates the map of Fuchsia key codes to logical keys. /// This generates the map of Fuchsia key codes to logical keys.
String get fuchsiaKeyCodeMap { String get fuchsiaKeyCodeMap {
final StringBuffer fuchsiaKeyCodeMap = StringBuffer(); final StringBuffer fuchsiaKeyCodeMap = StringBuffer();
...@@ -267,6 +289,8 @@ class KeyboardMapsCodeGenerator extends BaseCodeGenerator { ...@@ -267,6 +289,8 @@ class KeyboardMapsCodeGenerator extends BaseCodeGenerator {
'MACOS_SCAN_CODE_MAP': macOsScanCodeMap, 'MACOS_SCAN_CODE_MAP': macOsScanCodeMap,
'MACOS_NUMPAD_MAP': macOsNumpadMap, 'MACOS_NUMPAD_MAP': macOsNumpadMap,
'MACOS_FUNCTION_KEY_MAP': macOsFunctionKeyMap, 'MACOS_FUNCTION_KEY_MAP': macOsFunctionKeyMap,
'IOS_SCAN_CODE_MAP': iosScanCodeMap,
'IOS_NUMPAD_MAP': iosNumpadMap,
'GLFW_KEY_CODE_MAP': glfwKeyCodeMap, 'GLFW_KEY_CODE_MAP': glfwKeyCodeMap,
'GLFW_NUMPAD_MAP': glfwNumpadMap, 'GLFW_NUMPAD_MAP': glfwNumpadMap,
'GTK_KEY_CODE_MAP': gtkKeyCodeMap, 'GTK_KEY_CODE_MAP': gtkKeyCodeMap,
......
...@@ -47,7 +47,10 @@ class MacOsCodeGenerator extends PlatformCodeGenerator { ...@@ -47,7 +47,10 @@ class MacOsCodeGenerator extends PlatformCodeGenerator {
} }
@override @override
String get templatePath => path.join(flutterRoot.path, 'dev', 'tools', 'gen_keycodes', 'data', 'keyboard_map_darwin_cc.tmpl'); String get templatePath => path.join(flutterRoot.path, 'dev', 'tools', 'gen_keycodes', 'data', 'keyboard_map_macos_cc.tmpl');
@override
String outputPath(String platform) => path.joinAll(<String>[flutterRoot.path, '..', 'engine', 'src', 'flutter', 'shell', 'platform', 'darwin', platform, 'keycodes', 'keyboard_map_$platform.h']);
@override @override
Map<String, String> mappings() { Map<String, String> mappings() {
......
...@@ -27,6 +27,7 @@ export 'src/services/platform_views.dart'; ...@@ -27,6 +27,7 @@ export 'src/services/platform_views.dart';
export 'src/services/raw_keyboard.dart'; export 'src/services/raw_keyboard.dart';
export 'src/services/raw_keyboard_android.dart'; export 'src/services/raw_keyboard_android.dart';
export 'src/services/raw_keyboard_fuchsia.dart'; export 'src/services/raw_keyboard_fuchsia.dart';
export 'src/services/raw_keyboard_ios.dart';
export 'src/services/raw_keyboard_linux.dart'; export 'src/services/raw_keyboard_linux.dart';
export 'src/services/raw_keyboard_macos.dart'; export 'src/services/raw_keyboard_macos.dart';
export 'src/services/raw_keyboard_web.dart'; export 'src/services/raw_keyboard_web.dart';
......
...@@ -1178,6 +1178,196 @@ const Map<int, LogicalKeyboardKey> kMacOsFunctionKeyMap = <int, LogicalKeyboardK ...@@ -1178,6 +1178,196 @@ const Map<int, LogicalKeyboardKey> kMacOsFunctionKeyMap = <int, LogicalKeyboardK
0x0000005a: LogicalKeyboardKey.f20, 0x0000005a: LogicalKeyboardKey.f20,
}; };
/// Maps iOS-specific key code values representing [PhysicalKeyboardKey].
///
/// iOS doesn't provide a scan code, but a virtual keycode to represent a physical key.
const Map<int, PhysicalKeyboardKey> kIosToPhysicalKey = <int, PhysicalKeyboardKey>{
0x00000000: PhysicalKeyboardKey.usbReserved,
0x00000001: PhysicalKeyboardKey.usbErrorRollOver,
0x00000002: PhysicalKeyboardKey.usbPostFail,
0x00000003: PhysicalKeyboardKey.usbErrorUndefined,
0x00000004: PhysicalKeyboardKey.keyA,
0x00000005: PhysicalKeyboardKey.keyB,
0x00000006: PhysicalKeyboardKey.keyC,
0x00000007: PhysicalKeyboardKey.keyD,
0x00000008: PhysicalKeyboardKey.keyE,
0x00000009: PhysicalKeyboardKey.keyF,
0x0000000a: PhysicalKeyboardKey.keyG,
0x0000000b: PhysicalKeyboardKey.keyH,
0x0000000c: PhysicalKeyboardKey.keyI,
0x0000000d: PhysicalKeyboardKey.keyJ,
0x0000000e: PhysicalKeyboardKey.keyK,
0x0000000f: PhysicalKeyboardKey.keyL,
0x00000010: PhysicalKeyboardKey.keyM,
0x00000011: PhysicalKeyboardKey.keyN,
0x00000012: PhysicalKeyboardKey.keyO,
0x00000013: PhysicalKeyboardKey.keyP,
0x00000014: PhysicalKeyboardKey.keyQ,
0x00000015: PhysicalKeyboardKey.keyR,
0x00000016: PhysicalKeyboardKey.keyS,
0x00000017: PhysicalKeyboardKey.keyT,
0x00000018: PhysicalKeyboardKey.keyU,
0x00000019: PhysicalKeyboardKey.keyV,
0x0000001a: PhysicalKeyboardKey.keyW,
0x0000001b: PhysicalKeyboardKey.keyX,
0x0000001c: PhysicalKeyboardKey.keyY,
0x0000001d: PhysicalKeyboardKey.keyZ,
0x0000001e: PhysicalKeyboardKey.digit1,
0x0000001f: PhysicalKeyboardKey.digit2,
0x00000020: PhysicalKeyboardKey.digit3,
0x00000021: PhysicalKeyboardKey.digit4,
0x00000022: PhysicalKeyboardKey.digit5,
0x00000023: PhysicalKeyboardKey.digit6,
0x00000024: PhysicalKeyboardKey.digit7,
0x00000025: PhysicalKeyboardKey.digit8,
0x00000026: PhysicalKeyboardKey.digit9,
0x00000027: PhysicalKeyboardKey.digit0,
0x00000028: PhysicalKeyboardKey.enter,
0x00000029: PhysicalKeyboardKey.escape,
0x0000002a: PhysicalKeyboardKey.backspace,
0x0000002b: PhysicalKeyboardKey.tab,
0x0000002c: PhysicalKeyboardKey.space,
0x0000002d: PhysicalKeyboardKey.minus,
0x0000002e: PhysicalKeyboardKey.equal,
0x0000002f: PhysicalKeyboardKey.bracketLeft,
0x00000030: PhysicalKeyboardKey.bracketRight,
0x00000031: PhysicalKeyboardKey.backslash,
0x00000033: PhysicalKeyboardKey.semicolon,
0x00000034: PhysicalKeyboardKey.quote,
0x00000035: PhysicalKeyboardKey.backquote,
0x00000036: PhysicalKeyboardKey.comma,
0x00000037: PhysicalKeyboardKey.period,
0x00000038: PhysicalKeyboardKey.slash,
0x00000039: PhysicalKeyboardKey.capsLock,
0x0000003a: PhysicalKeyboardKey.f1,
0x0000003b: PhysicalKeyboardKey.f2,
0x0000003c: PhysicalKeyboardKey.f3,
0x0000003d: PhysicalKeyboardKey.f4,
0x0000003e: PhysicalKeyboardKey.f5,
0x0000003f: PhysicalKeyboardKey.f6,
0x00000040: PhysicalKeyboardKey.f7,
0x00000041: PhysicalKeyboardKey.f8,
0x00000042: PhysicalKeyboardKey.f9,
0x00000043: PhysicalKeyboardKey.f10,
0x00000044: PhysicalKeyboardKey.f11,
0x00000045: PhysicalKeyboardKey.f12,
0x00000046: PhysicalKeyboardKey.printScreen,
0x00000047: PhysicalKeyboardKey.scrollLock,
0x00000048: PhysicalKeyboardKey.pause,
0x00000049: PhysicalKeyboardKey.insert,
0x0000004a: PhysicalKeyboardKey.home,
0x0000004b: PhysicalKeyboardKey.pageUp,
0x0000004c: PhysicalKeyboardKey.delete,
0x0000004d: PhysicalKeyboardKey.end,
0x0000004e: PhysicalKeyboardKey.pageDown,
0x0000004f: PhysicalKeyboardKey.arrowRight,
0x00000050: PhysicalKeyboardKey.arrowLeft,
0x00000051: PhysicalKeyboardKey.arrowDown,
0x00000052: PhysicalKeyboardKey.arrowUp,
0x00000053: PhysicalKeyboardKey.numLock,
0x00000054: PhysicalKeyboardKey.numpadDivide,
0x00000055: PhysicalKeyboardKey.numpadMultiply,
0x00000056: PhysicalKeyboardKey.numpadSubtract,
0x00000057: PhysicalKeyboardKey.numpadAdd,
0x00000058: PhysicalKeyboardKey.numpadEnter,
0x00000059: PhysicalKeyboardKey.numpad1,
0x0000005a: PhysicalKeyboardKey.numpad2,
0x0000005b: PhysicalKeyboardKey.numpad3,
0x0000005c: PhysicalKeyboardKey.numpad4,
0x0000005d: PhysicalKeyboardKey.numpad5,
0x0000005e: PhysicalKeyboardKey.numpad6,
0x0000005f: PhysicalKeyboardKey.numpad7,
0x00000060: PhysicalKeyboardKey.numpad8,
0x00000061: PhysicalKeyboardKey.numpad9,
0x00000062: PhysicalKeyboardKey.numpad0,
0x00000063: PhysicalKeyboardKey.numpadDecimal,
0x00000064: PhysicalKeyboardKey.intlBackslash,
0x00000065: PhysicalKeyboardKey.contextMenu,
0x00000066: PhysicalKeyboardKey.power,
0x00000067: PhysicalKeyboardKey.numpadEqual,
0x00000068: PhysicalKeyboardKey.f13,
0x00000069: PhysicalKeyboardKey.f14,
0x0000006a: PhysicalKeyboardKey.f15,
0x0000006b: PhysicalKeyboardKey.f16,
0x0000006c: PhysicalKeyboardKey.f17,
0x0000006d: PhysicalKeyboardKey.f18,
0x0000006e: PhysicalKeyboardKey.f19,
0x0000006f: PhysicalKeyboardKey.f20,
0x00000070: PhysicalKeyboardKey.f21,
0x00000071: PhysicalKeyboardKey.f22,
0x00000072: PhysicalKeyboardKey.f23,
0x00000073: PhysicalKeyboardKey.f24,
0x00000074: PhysicalKeyboardKey.open,
0x00000075: PhysicalKeyboardKey.help,
0x00000077: PhysicalKeyboardKey.select,
0x00000079: PhysicalKeyboardKey.again,
0x0000007a: PhysicalKeyboardKey.undo,
0x0000007b: PhysicalKeyboardKey.cut,
0x0000007c: PhysicalKeyboardKey.copy,
0x0000007d: PhysicalKeyboardKey.paste,
0x0000007e: PhysicalKeyboardKey.find,
0x0000007f: PhysicalKeyboardKey.audioVolumeMute,
0x00000080: PhysicalKeyboardKey.audioVolumeUp,
0x00000081: PhysicalKeyboardKey.audioVolumeDown,
0x00000085: PhysicalKeyboardKey.numpadComma,
0x00000087: PhysicalKeyboardKey.intlRo,
0x00000088: PhysicalKeyboardKey.kanaMode,
0x00000089: PhysicalKeyboardKey.intlYen,
0x0000008a: PhysicalKeyboardKey.convert,
0x0000008b: PhysicalKeyboardKey.nonConvert,
0x00000090: PhysicalKeyboardKey.lang1,
0x00000091: PhysicalKeyboardKey.lang2,
0x00000092: PhysicalKeyboardKey.lang3,
0x00000093: PhysicalKeyboardKey.lang4,
0x00000094: PhysicalKeyboardKey.lang5,
0x0000009b: PhysicalKeyboardKey.abort,
0x000000a3: PhysicalKeyboardKey.props,
0x000000b6: PhysicalKeyboardKey.numpadParenLeft,
0x000000b7: PhysicalKeyboardKey.numpadParenRight,
0x000000bb: PhysicalKeyboardKey.numpadBackspace,
0x000000d0: PhysicalKeyboardKey.numpadMemoryStore,
0x000000d1: PhysicalKeyboardKey.numpadMemoryRecall,
0x000000d2: PhysicalKeyboardKey.numpadMemoryClear,
0x000000d3: PhysicalKeyboardKey.numpadMemoryAdd,
0x000000d4: PhysicalKeyboardKey.numpadMemorySubtract,
0x000000d7: PhysicalKeyboardKey.numpadSignChange,
0x000000d8: PhysicalKeyboardKey.numpadClear,
0x000000d9: PhysicalKeyboardKey.numpadClearEntry,
0x000000e0: PhysicalKeyboardKey.controlLeft,
0x000000e1: PhysicalKeyboardKey.shiftLeft,
0x000000e2: PhysicalKeyboardKey.altLeft,
0x000000e3: PhysicalKeyboardKey.metaLeft,
0x000000e4: PhysicalKeyboardKey.controlRight,
0x000000e5: PhysicalKeyboardKey.shiftRight,
0x000000e6: PhysicalKeyboardKey.altRight,
0x000000e7: PhysicalKeyboardKey.metaRight,
};
/// A map of iOS key codes which have printable representations, but appear
/// on the number pad. Used to provide different key objects for keys like
/// KEY_EQUALS and NUMPAD_EQUALS.
const Map<int, LogicalKeyboardKey> kIosNumPadMap = <int, LogicalKeyboardKey>{
0x00000054: LogicalKeyboardKey.numpadDivide,
0x00000055: LogicalKeyboardKey.numpadMultiply,
0x00000056: LogicalKeyboardKey.numpadSubtract,
0x00000057: LogicalKeyboardKey.numpadAdd,
0x00000059: LogicalKeyboardKey.numpad1,
0x0000005a: LogicalKeyboardKey.numpad2,
0x0000005b: LogicalKeyboardKey.numpad3,
0x0000005c: LogicalKeyboardKey.numpad4,
0x0000005d: LogicalKeyboardKey.numpad5,
0x0000005e: LogicalKeyboardKey.numpad6,
0x0000005f: LogicalKeyboardKey.numpad7,
0x00000060: LogicalKeyboardKey.numpad8,
0x00000061: LogicalKeyboardKey.numpad9,
0x00000062: LogicalKeyboardKey.numpad0,
0x00000063: LogicalKeyboardKey.numpadDecimal,
0x00000067: LogicalKeyboardKey.numpadEqual,
0x00000085: LogicalKeyboardKey.numpadComma,
0x000000b6: LogicalKeyboardKey.numpadParenLeft,
0x000000b7: LogicalKeyboardKey.numpadParenRight,
};
/// Maps GLFW-specific key codes to the matching [LogicalKeyboardKey]. /// Maps GLFW-specific key codes to the matching [LogicalKeyboardKey].
const Map<int, LogicalKeyboardKey> kGlfwToLogicalKey = <int, LogicalKeyboardKey>{ const Map<int, LogicalKeyboardKey> kGlfwToLogicalKey = <int, LogicalKeyboardKey>{
65: LogicalKeyboardKey.keyA, 65: LogicalKeyboardKey.keyA,
......
...@@ -10,6 +10,7 @@ import 'package:flutter/foundation.dart'; ...@@ -10,6 +10,7 @@ import 'package:flutter/foundation.dart';
import 'keyboard_key.dart'; import 'keyboard_key.dart';
import 'raw_keyboard_android.dart'; import 'raw_keyboard_android.dart';
import 'raw_keyboard_fuchsia.dart'; import 'raw_keyboard_fuchsia.dart';
import 'raw_keyboard_ios.dart';
import 'raw_keyboard_linux.dart'; import 'raw_keyboard_linux.dart';
import 'raw_keyboard_macos.dart'; import 'raw_keyboard_macos.dart';
import 'raw_keyboard_web.dart'; import 'raw_keyboard_web.dart';
...@@ -306,6 +307,13 @@ abstract class RawKeyEvent with Diagnosticable { ...@@ -306,6 +307,13 @@ abstract class RawKeyEvent with Diagnosticable {
modifiers: message['modifiers'] as int? ?? 0); modifiers: message['modifiers'] as int? ?? 0);
character = message['characters'] as String?; character = message['characters'] as String?;
break; break;
case 'ios':
data = RawKeyEventDataIos(
characters: message['characters'] as String? ?? '',
charactersIgnoringModifiers: message['charactersIgnoringModifiers'] as String? ?? '',
keyCode: message['keyCode'] as int? ?? 0,
modifiers: message['modifiers'] as int? ?? 0);
break;
case 'linux': case 'linux':
final int unicodeScalarValues = message['unicodeScalarValues'] as int? ?? 0; final int unicodeScalarValues = message['unicodeScalarValues'] as int? ?? 0;
data = RawKeyEventDataLinux( data = RawKeyEventDataLinux(
...@@ -340,9 +348,10 @@ abstract class RawKeyEvent with Diagnosticable { ...@@ -340,9 +348,10 @@ abstract class RawKeyEvent with Diagnosticable {
} }
break; break;
default: default:
// Raw key events are not yet implemented on iOS or other platforms, /// This exception would only be hit on platforms that haven't yet
// but this exception isn't hit, because the engine never sends these /// implemented raw key events, but will only be triggered if the
// messages. /// engine for those platforms sends raw key event messages in the
/// first place.
throw FlutterError('Unknown keymap for key events: $keymap'); throw FlutterError('Unknown keymap for key events: $keymap');
} }
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'keyboard_key.dart';
import 'keyboard_maps.dart';
import 'raw_keyboard.dart';
/// Maps iOS specific string values of nonvisible keys to logical keys
///
/// See: https://developer.apple.com/documentation/uikit/uikeycommand/input_strings_for_special_keys?language=objc
const Map<String, LogicalKeyboardKey> _kIosToLogicalMap = <String, LogicalKeyboardKey>{
'UIKeyInputEscape': LogicalKeyboardKey.escape,
'UIKeyInputF1': LogicalKeyboardKey.f1,
'UIKeyInputF2': LogicalKeyboardKey.f2,
'UIKeyInputF3': LogicalKeyboardKey.f3,
'UIKeyInputF4': LogicalKeyboardKey.f4,
'UIKeyInputF5': LogicalKeyboardKey.f5,
'UIKeyInputF6': LogicalKeyboardKey.f6,
'UIKeyInputF7': LogicalKeyboardKey.f7,
'UIKeyInputF8': LogicalKeyboardKey.f8,
'UIKeyInputF9': LogicalKeyboardKey.f9,
'UIKeyInputF10': LogicalKeyboardKey.f10,
'UIKeyInputF11': LogicalKeyboardKey.f11,
'UIKeyInputF12': LogicalKeyboardKey.f12,
'UIKeyInputUpArrow': LogicalKeyboardKey.arrowUp,
'UIKeyInputDownArrow': LogicalKeyboardKey.arrowDown,
'UIKeyInputLeftArrow': LogicalKeyboardKey.arrowLeft,
'UIKeyInputRightArrow': LogicalKeyboardKey.arrowRight,
'UIKeyInputHome': LogicalKeyboardKey.home,
'UIKeyInputEnd': LogicalKeyboardKey.enter,
'UIKeyInputPageUp': LogicalKeyboardKey.pageUp,
'UIKeyInputPageDown': LogicalKeyboardKey.pageDown
};
/// Platform-specific key event data for iOS.
///
/// This object contains information about key events obtained from iOS'
/// `UIKey` interface.
///
/// See also:
///
/// * [RawKeyboard], which uses this interface to expose key data.
class RawKeyEventDataIos extends RawKeyEventData {
/// Creates a key event data structure specific for iOS.
///
/// The [characters], [charactersIgnoringModifiers], and [modifiers], arguments
/// must not be null.
const RawKeyEventDataIos({
this.characters = '',
this.charactersIgnoringModifiers = '',
this.keyCode = 0,
this.modifiers = 0,
}) : assert(characters != null),
assert(charactersIgnoringModifiers != null),
assert(keyCode != null),
assert(modifiers != null);
/// The Unicode characters associated with a key-up or key-down event.
///
/// See also:
///
/// * [Apple's UIKey documentation](https://developer.apple.com/documentation/uikit/uikey/3526130-characters?language=objc)
final String characters;
/// The characters generated by a key event as if no modifier key (except for
/// Shift) applies.
///
/// See also:
///
/// * [Apple's UIKey documentation](https://developer.apple.com/documentation/uikit/uikey/3526131-charactersignoringmodifiers?language=objc)
final String charactersIgnoringModifiers;
/// The virtual key code for the keyboard key associated with a key event.
///
/// See also:
///
/// * [Apple's UIKey documentation](https://developer.apple.com/documentation/uikit/uikey/3526132-keycode?language=objc)
final int keyCode;
/// A mask of the current modifiers using the values in Modifier Flags.
///
/// See also:
///
/// * [Apple's UIKey documentation](https://developer.apple.com/documentation/uikit/uikey/3526133-modifierflags?language=objc)
final int modifiers;
@override
String get keyLabel => charactersIgnoringModifiers;
@override
PhysicalKeyboardKey get physicalKey => kIosToPhysicalKey[keyCode] ?? PhysicalKeyboardKey.none;
@override
LogicalKeyboardKey get logicalKey {
// Look to see if the keyCode is a printable number pad key, so that a
// difference between regular keys (e.g. "=") and the number pad version
// (e.g. the "=" on the number pad) can be determined.
final LogicalKeyboardKey? numPadKey = kIosNumPadMap[keyCode];
if (numPadKey != null) {
return numPadKey;
}
// Look to see if the [keyLabel] is one we know about and have a mapping for.
final LogicalKeyboardKey? newKey = _kIosToLogicalMap[keyLabel];
if (newKey != null) {
return newKey;
}
// If this key is printable, generate the LogicalKeyboardKey from its
// Unicode value. Control keys such as ESC, CRTL, and SHIFT are not
// printable. HOME, DEL, arrow keys, and function keys are considered
// modifier function keys, which generate invalid Unicode scalar values.
if (keyLabel.isNotEmpty &&
!LogicalKeyboardKey.isControlCharacter(keyLabel)) {
// Given that charactersIgnoringModifiers can contain a String of
// arbitrary length, limit to a maximum of two Unicode scalar values. It
// is unlikely that a keyboard would produce a code point bigger than 32
// bits, but it is still worth defending against this case.
assert(charactersIgnoringModifiers.length <= 2);
int codeUnit = charactersIgnoringModifiers.codeUnitAt(0);
if (charactersIgnoringModifiers.length == 2) {
final int secondCode = charactersIgnoringModifiers.codeUnitAt(1);
codeUnit = (codeUnit << 16) | secondCode;
}
final int keyId = LogicalKeyboardKey.unicodePlane | (codeUnit & LogicalKeyboardKey.valueMask);
return LogicalKeyboardKey.findKeyByKeyId(keyId) ?? LogicalKeyboardKey(
keyId,
keyLabel: keyLabel,
debugName: kReleaseMode ? null : 'Key ${keyLabel.toUpperCase()}',
);
}
// Control keys like "backspace" and movement keys like arrow keys don't
// have a printable representation, but are present on the physical
// keyboard. Since there is no logical keycode map for iOS (iOS uses the
// keycode to reference physical keys), a LogicalKeyboardKey is created with
// the physical key's HID usage and debugName. This avoids duplicating the
// physical key map.
if (physicalKey != PhysicalKeyboardKey.none) {
final int keyId = physicalKey.usbHidUsage | LogicalKeyboardKey.hidPlane;
return LogicalKeyboardKey.findKeyByKeyId(keyId) ?? LogicalKeyboardKey(
keyId,
keyLabel: physicalKey.debugName ?? '',
debugName: physicalKey.debugName,
);
}
// This is a non-printable key that is unrecognized, so a new code is minted
// with the autogenerated bit set.
const int iosKeyIdPlane = 0x00400000000;
return LogicalKeyboardKey(
iosKeyIdPlane | keyCode | LogicalKeyboardKey.autogeneratedMask,
debugName: kReleaseMode ? null : 'Unknown iOS key code $keyCode',
);
}
bool _isLeftRightModifierPressed(KeyboardSide side, int anyMask, int leftMask, int rightMask) {
if (modifiers & anyMask == 0) {
return false;
}
// If only the "anyMask" bit is set, then we respond true for requests of
// whether either left or right is pressed. Handles the case where iOS
// supplies just the "either" modifier flag, but not the left/right flag.
// (e.g. modifierShift but not modifierLeftShift).
final bool anyOnly = modifiers & (leftMask | rightMask | anyMask) == anyMask;
switch (side) {
case KeyboardSide.any:
return true;
case KeyboardSide.all:
return modifiers & leftMask != 0 && modifiers & rightMask != 0 || anyOnly;
case KeyboardSide.left:
return modifiers & leftMask != 0 || anyOnly;
case KeyboardSide.right:
return modifiers & rightMask != 0 || anyOnly;
}
}
@override
bool isModifierPressed(ModifierKey key, {KeyboardSide side = KeyboardSide.any}) {
final int independentModifier = modifiers & deviceIndependentMask;
bool result;
switch (key) {
case ModifierKey.controlModifier:
result = _isLeftRightModifierPressed(side, independentModifier & modifierControl, modifierLeftControl, modifierRightControl);
break;
case ModifierKey.shiftModifier:
result = _isLeftRightModifierPressed(side, independentModifier & modifierShift, modifierLeftShift, modifierRightShift);
break;
case ModifierKey.altModifier:
result = _isLeftRightModifierPressed(side, independentModifier & modifierOption, modifierLeftOption, modifierRightOption);
break;
case ModifierKey.metaModifier:
result = _isLeftRightModifierPressed(side, independentModifier & modifierCommand, modifierLeftCommand, modifierRightCommand);
break;
case ModifierKey.capsLockModifier:
result = independentModifier & modifierCapsLock != 0;
break;
// On iOS, the function modifier bit is set for any function key, like F1,
// F2, etc., but the meaning of ModifierKey.modifierFunction in Flutter is
// that of the Fn modifier key, so there's no good way to emulate that on
// iOS.
case ModifierKey.functionModifier:
case ModifierKey.numLockModifier:
case ModifierKey.symbolModifier:
case ModifierKey.scrollLockModifier:
// These modifier masks are not used in iOS keyboards.
result = false;
break;
}
assert(!result || getModifierSide(key) != null, "$runtimeType thinks that a modifier is pressed, but can't figure out what side it's on.");
return result;
}
@override
KeyboardSide? getModifierSide(ModifierKey key) {
KeyboardSide? findSide(int anyMask, int leftMask, int rightMask) {
final int combinedMask = leftMask | rightMask;
final int combined = modifiers & combinedMask;
if (combined == leftMask) {
return KeyboardSide.left;
} else if (combined == rightMask) {
return KeyboardSide.right;
} else if (combined == combinedMask || modifiers & (combinedMask | anyMask) == anyMask) {
// Handles the case where iOS supplies just the "either" modifier
// flag, but not the left/right flag. (e.g. modifierShift but not
// modifierLeftShift), or if left and right flags are provided, but not
// the "either" modifier flag.
return KeyboardSide.all;
}
return null;
}
switch (key) {
case ModifierKey.controlModifier:
return findSide(modifierControl, modifierLeftControl, modifierRightControl);
case ModifierKey.shiftModifier:
return findSide(modifierShift, modifierLeftShift, modifierRightShift);
case ModifierKey.altModifier:
return findSide(modifierOption, modifierLeftOption, modifierRightOption);
case ModifierKey.metaModifier:
return findSide(modifierCommand, modifierLeftCommand, modifierRightCommand);
case ModifierKey.capsLockModifier:
case ModifierKey.numLockModifier:
case ModifierKey.scrollLockModifier:
case ModifierKey.functionModifier:
case ModifierKey.symbolModifier:
return KeyboardSide.all;
}
}
// Modifier key masks. See Apple's UIKey documentation
// https://developer.apple.com/documentation/uikit/uikeymodifierflags?language=objc
// https://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-86/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h.auto.html
/// This mask is used to check the [modifiers] field to test whether the CAPS
/// LOCK modifier key is on.
///
/// {@template flutter.services.rawKeyEventDataIOS.modifiers}
/// Use this value if you need to decode the [modifiers] field yourself, but
/// it's much easier to use [isModifierPressed] if you just want to know if
/// a modifier is pressed.
/// {@endtemplate}
static const int modifierCapsLock = 0x10000;
/// This mask is used to check the [modifiers] field to test whether one of the
/// SHIFT modifier keys is pressed.
///
/// {@macro flutter.services.rawKeyEventDataIOS.modifiers}
static const int modifierShift = 0x20000;
/// This mask is used to check the [modifiers] field to test whether the left
/// SHIFT modifier key is pressed.
///
/// {@macro flutter.services.rawKeyEventDataIOS.modifiers}
static const int modifierLeftShift = 0x02;
/// This mask is used to check the [modifiers] field to test whether the right
/// SHIFT modifier key is pressed.
///
/// {@macro flutter.services.rawKeyEventDataIOS.modifiers}
static const int modifierRightShift = 0x04;
/// This mask is used to check the [modifiers] field to test whether one of the
/// CTRL modifier keys is pressed.
///
/// {@macro flutter.services.rawKeyEventDataIOS.modifiers}
static const int modifierControl = 0x40000;
/// This mask is used to check the [modifiers] field to test whether the left
/// CTRL modifier key is pressed.
///
/// {@macro flutter.services.rawKeyEventDataIOS.modifiers}
static const int modifierLeftControl = 0x01;
/// This mask is used to check the [modifiers] field to test whether the right
/// CTRL modifier key is pressed.
///
/// {@macro flutter.services.rawKeyEventDataIOS.modifiers}
static const int modifierRightControl = 0x2000;
/// This mask is used to check the [modifiers] field to test whether one of the
/// ALT modifier keys is pressed.
///
/// {@macro flutter.services.rawKeyEventDataIOS.modifiers}
static const int modifierOption = 0x80000;
/// This mask is used to check the [modifiers] field to test whether the left
/// ALT modifier key is pressed.
///
/// {@macro flutter.services.rawKeyEventDataIOS.modifiers}
static const int modifierLeftOption = 0x20;
/// This mask is used to check the [modifiers] field to test whether the right
/// ALT modifier key is pressed.
///
/// {@macro flutter.services.rawKeyEventDataIOS.modifiers}
static const int modifierRightOption = 0x40;
/// This mask is used to check the [modifiers] field to test whether one of the
/// CMD modifier keys is pressed.
///
/// {@macro flutter.services.rawKeyEventDataIOS.modifiers}
static const int modifierCommand = 0x100000;
/// This mask is used to check the [modifiers] field to test whether the left
/// CMD modifier keys is pressed.
///
/// {@macro flutter.services.rawKeyEventDataIOS.modifiers}
static const int modifierLeftCommand = 0x08;
/// This mask is used to check the [modifiers] field to test whether the right
/// CMD modifier keys is pressed.
///
/// {@macro flutter.services.rawKeyEventDataIOS.modifiers}
static const int modifierRightCommand = 0x10;
/// This mask is used to check the [modifiers] field to test whether any key in
/// the numeric keypad is pressed.
///
/// {@macro flutter.services.rawKeyEventDataIOS.modifiers}
static const int modifierNumericPad = 0x200000;
/// This mask is used to check the [modifiers] field to test whether the
/// HELP modifier key is pressed.
///
/// {@macro flutter.services.rawKeyEventDataIOS.modifiers}
static const int modifierHelp = 0x400000;
/// This mask is used to check the [modifiers] field to test whether one of the
/// FUNCTION modifier keys is pressed.
///
/// {@macro flutter.services.rawKeyEventDataIOS.modifiers}
static const int modifierFunction = 0x800000;
/// Used to retrieve only the device-independent modifier flags, allowing
/// applications to mask off the device-dependent modifier flags, including
/// event coalescing information.
static const int deviceIndependentMask = 0xffff0000;
@override
String toString() {
return '${objectRuntimeType(this, 'RawKeyEventDataIos')}(keyLabel: $keyLabel, keyCode: $keyCode, characters: $characters,'
' unmodifiedCharacters: $charactersIgnoringModifiers, modifiers: $modifiers, '
'modifiers down: $modifiersPressed)';
}
}
...@@ -41,7 +41,7 @@ void main() { ...@@ -41,7 +41,7 @@ void main() {
} }
}); });
testWidgets('keysPressed is maintained', (WidgetTester tester) async { testWidgets('keysPressed is maintained', (WidgetTester tester) async {
for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows']) { for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows', 'ios']) {
RawKeyboard.instance.clearKeysPressed(); RawKeyboard.instance.clearKeysPressed();
expect(RawKeyboard.instance.keysPressed, isEmpty, reason: 'on $platform'); expect(RawKeyboard.instance.keysPressed, isEmpty, reason: 'on $platform');
await simulateKeyDownEvent(LogicalKeyboardKey.shiftLeft, platform: platform); await simulateKeyDownEvent(LogicalKeyboardKey.shiftLeft, platform: platform);
...@@ -110,7 +110,7 @@ void main() { ...@@ -110,7 +110,7 @@ void main() {
await simulateKeyUpEvent(LogicalKeyboardKey.shiftLeft, platform: platform); await simulateKeyUpEvent(LogicalKeyboardKey.shiftLeft, platform: platform);
expect(RawKeyboard.instance.keysPressed, isEmpty, reason: 'on $platform'); expect(RawKeyboard.instance.keysPressed, isEmpty, reason: 'on $platform');
// The Fn key isn't mapped on linux or Windows. // The Fn key isn't mapped on linux or Windows.
if (platform != 'linux' && platform != 'windows') { if (platform != 'linux' && platform != 'windows' && platform != 'ios') {
await simulateKeyDownEvent(LogicalKeyboardKey.fn, platform: platform); await simulateKeyDownEvent(LogicalKeyboardKey.fn, platform: platform);
expect( expect(
RawKeyboard.instance.keysPressed, RawKeyboard.instance.keysPressed,
...@@ -146,7 +146,7 @@ void main() { ...@@ -146,7 +146,7 @@ void main() {
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/61021 }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61021
testWidgets('keysPressed is correct when modifier is released before key', (WidgetTester tester) async { testWidgets('keysPressed is correct when modifier is released before key', (WidgetTester tester) async {
for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows']) { for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows', 'ios']) {
RawKeyboard.instance.clearKeysPressed(); RawKeyboard.instance.clearKeysPressed();
expect(RawKeyboard.instance.keysPressed, isEmpty, reason: 'on $platform'); expect(RawKeyboard.instance.keysPressed, isEmpty, reason: 'on $platform');
await simulateKeyDownEvent(LogicalKeyboardKey.shiftLeft, platform: platform, physicalKey: PhysicalKeyboardKey.shiftLeft); await simulateKeyDownEvent(LogicalKeyboardKey.shiftLeft, platform: platform, physicalKey: PhysicalKeyboardKey.shiftLeft);
...@@ -221,6 +221,31 @@ void main() { ...@@ -221,6 +221,31 @@ void main() {
); );
}); });
testWidgets('keysPressed modifiers are synchronized with key events on iOS', (WidgetTester tester) async {
expect(RawKeyboard.instance.keysPressed, isEmpty);
// Generate the data for a regular key down event.
final Map<String, dynamic> data = KeyEventSimulator.getKeyData(
LogicalKeyboardKey.keyA,
platform: 'ios',
isDown: true,
);
// Change the modifiers so that they show the shift key as already down
// when this event is received, but it's not in keysPressed yet.
data['modifiers'] |= RawKeyEventDataMacOs.modifierLeftShift | RawKeyEventDataMacOs.modifierShift;
// dispatch the modified data.
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(data),
(ByteData? data) {},
);
expect(
RawKeyboard.instance.keysPressed,
equals(
<LogicalKeyboardKey>{LogicalKeyboardKey.shiftLeft, LogicalKeyboardKey.keyA},
),
);
});
testWidgets('keysPressed modifiers are synchronized with key events on Windows', (WidgetTester tester) async { testWidgets('keysPressed modifiers are synchronized with key events on Windows', (WidgetTester tester) async {
expect(RawKeyboard.instance.keysPressed, isEmpty); expect(RawKeyboard.instance.keysPressed, isEmpty);
// Generate the data for a regular key down event. // Generate the data for a regular key down event.
...@@ -403,6 +428,44 @@ void main() { ...@@ -403,6 +428,44 @@ void main() {
); );
}); });
testWidgets('sided modifiers without a side set return all sides on iOS', (WidgetTester tester) async {
expect(RawKeyboard.instance.keysPressed, isEmpty);
// Generate the data for a regular key down event.
final Map<String, dynamic> data = KeyEventSimulator.getKeyData(
LogicalKeyboardKey.keyA,
platform: 'ios',
isDown: true,
);
// Set only the generic "shift down" modifier, without setting a side.
data['modifiers'] |=
RawKeyEventDataIos.modifierShift |
RawKeyEventDataIos.modifierOption |
RawKeyEventDataIos.modifierCommand |
RawKeyEventDataIos.modifierControl;
// dispatch the modified data.
await ServicesBinding.instance?.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(data),
(ByteData? data) {},
);
expect(
RawKeyboard.instance.keysPressed,
equals(
<LogicalKeyboardKey>{
LogicalKeyboardKey.shiftLeft,
LogicalKeyboardKey.shiftRight,
LogicalKeyboardKey.altLeft,
LogicalKeyboardKey.altRight,
LogicalKeyboardKey.controlLeft,
LogicalKeyboardKey.controlRight,
LogicalKeyboardKey.metaLeft,
LogicalKeyboardKey.metaRight,
LogicalKeyboardKey.keyA,
},
),
);
});
testWidgets('sided modifiers without a side set return all sides on Windows', (WidgetTester tester) async { testWidgets('sided modifiers without a side set return all sides on Windows', (WidgetTester tester) async {
expect(RawKeyboard.instance.keysPressed, isEmpty); expect(RawKeyboard.instance.keysPressed, isEmpty);
// Generate the data for a regular key down event. // Generate the data for a regular key down event.
...@@ -946,7 +1009,6 @@ void main() { ...@@ -946,7 +1009,6 @@ void main() {
'type': 'keydown', 'type': 'keydown',
'keymap': 'macos', 'keymap': 'macos',
'keyCode': 0x04, 'keyCode': 0x04,
'plainCodePoint': 0x64,
'characters': 'a', 'characters': 'a',
'charactersIgnoringModifiers': 'a', 'charactersIgnoringModifiers': 'a',
'modifiers': modifier | RawKeyEventDataMacOs.modifierCapsLock, 'modifiers': modifier | RawKeyEventDataMacOs.modifierCapsLock,
...@@ -1037,6 +1099,152 @@ void main() { ...@@ -1037,6 +1099,152 @@ void main() {
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/35347 }, skip: isBrowser); // https://github.com/flutter/flutter/issues/35347
}); });
group('RawKeyEventDataIos', () {
const Map<int, _ModifierCheck> modifierTests = <int, _ModifierCheck>{
RawKeyEventDataIos.modifierOption | RawKeyEventDataIos.modifierLeftOption: _ModifierCheck(ModifierKey.altModifier, KeyboardSide.left),
RawKeyEventDataIos.modifierOption | RawKeyEventDataIos.modifierRightOption: _ModifierCheck(ModifierKey.altModifier, KeyboardSide.right),
RawKeyEventDataIos.modifierShift | RawKeyEventDataIos.modifierLeftShift: _ModifierCheck(ModifierKey.shiftModifier, KeyboardSide.left),
RawKeyEventDataIos.modifierShift | RawKeyEventDataIos.modifierRightShift: _ModifierCheck(ModifierKey.shiftModifier, KeyboardSide.right),
RawKeyEventDataIos.modifierControl | RawKeyEventDataIos.modifierLeftControl: _ModifierCheck(ModifierKey.controlModifier, KeyboardSide.left),
RawKeyEventDataIos.modifierControl | RawKeyEventDataIos.modifierRightControl: _ModifierCheck(ModifierKey.controlModifier, KeyboardSide.right),
RawKeyEventDataIos.modifierCommand | RawKeyEventDataIos.modifierLeftCommand: _ModifierCheck(ModifierKey.metaModifier, KeyboardSide.left),
RawKeyEventDataIos.modifierCommand | RawKeyEventDataIos.modifierRightCommand: _ModifierCheck(ModifierKey.metaModifier, KeyboardSide.right),
RawKeyEventDataIos.modifierOption: _ModifierCheck(ModifierKey.altModifier, KeyboardSide.all),
RawKeyEventDataIos.modifierShift: _ModifierCheck(ModifierKey.shiftModifier, KeyboardSide.all),
RawKeyEventDataIos.modifierControl: _ModifierCheck(ModifierKey.controlModifier, KeyboardSide.all),
RawKeyEventDataIos.modifierCommand: _ModifierCheck(ModifierKey.metaModifier, KeyboardSide.all),
RawKeyEventDataIos.modifierCapsLock: _ModifierCheck(ModifierKey.capsLockModifier, KeyboardSide.all),
};
test('modifier keys are recognized individually', () {
for (final int modifier in modifierTests.keys) {
final RawKeyEvent event = RawKeyEvent.fromMessage(<String, dynamic>{
'type': 'keydown',
'keymap': 'ios',
'keyCode': 0x04,
'characters': 'a',
'charactersIgnoringModifiers': 'a',
'modifiers': modifier,
});
final RawKeyEventDataIos data = event.data as RawKeyEventDataIos;
for (final ModifierKey key in ModifierKey.values) {
if (modifierTests[modifier]!.key == key) {
expect(
data.isModifierPressed(key, side: modifierTests[modifier]!.side),
isTrue,
reason: "$key should be pressed with metaState $modifier, but isn't.",
);
expect(data.getModifierSide(key), equals(modifierTests[modifier]!.side));
} else {
expect(
data.isModifierPressed(key, side: modifierTests[modifier]!.side),
isFalse,
reason: '$key should not be pressed with metaState $modifier.',
);
}
}
}
});
test('modifier keys are recognized when combined', () {
for (final int modifier in modifierTests.keys) {
if (modifier == RawKeyEventDataIos.modifierCapsLock) {
// No need to combine caps lock key with itself.
continue;
}
final RawKeyEvent event = RawKeyEvent.fromMessage(<String, dynamic>{
'type': 'keydown',
'keymap': 'ios',
'keyCode': 0x04,
'characters': 'a',
'charactersIgnoringModifiers': 'a',
'modifiers': modifier | RawKeyEventDataIos.modifierCapsLock,
});
final RawKeyEventDataIos data = event.data as RawKeyEventDataIos;
for (final ModifierKey key in ModifierKey.values) {
if (modifierTests[modifier]!.key == key || key == ModifierKey.capsLockModifier) {
expect(
data.isModifierPressed(key, side: modifierTests[modifier]!.side),
isTrue,
reason: '$key should be pressed with metaState $modifier '
"and additional key ${RawKeyEventDataIos.modifierCapsLock}, but isn't.",
);
if (key != ModifierKey.capsLockModifier) {
expect(data.getModifierSide(key), equals(modifierTests[modifier]!.side));
} else {
expect(data.getModifierSide(key), equals(KeyboardSide.all));
}
} else {
expect(
data.isModifierPressed(key, side: modifierTests[modifier]!.side),
isFalse,
reason: '$key should not be pressed with metaState $modifier '
'and additional key ${RawKeyEventDataIos.modifierCapsLock}.',
);
}
}
}
});
test('Printable keyboard keys are correctly translated', () {
const String unmodifiedCharacter = 'a';
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
'keymap': 'ios',
'keyCode': 0x00000004,
'characters': 'a',
'charactersIgnoringModifiers': unmodifiedCharacter,
'modifiers': 0x0,
});
final RawKeyEventDataIos data = keyAEvent.data as RawKeyEventDataIos;
expect(data.physicalKey, equals(PhysicalKeyboardKey.keyA));
expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
expect(data.keyLabel, equals('a'));
});
test('Control keyboard keys are correctly translated', () {
final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
'keymap': 'ios',
'keyCode': 0x00000029,
'characters': '',
'charactersIgnoringModifiers': '',
'modifiers': 0x0,
});
final RawKeyEventDataIos data = escapeKeyEvent.data as RawKeyEventDataIos;
expect(data.physicalKey, equals(PhysicalKeyboardKey.escape));
expect(data.logicalKey, equals(LogicalKeyboardKey.escape));
expect(data.keyLabel, isEmpty);
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/35347
test('Modifier keyboard keys are correctly translated', () {
final RawKeyEvent shiftLeftKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
'keymap': 'ios',
'keyCode': 0x000000e1,
'characters': '',
'charactersIgnoringModifiers': '',
'modifiers': RawKeyEventDataIos.modifierLeftShift,
});
final RawKeyEventDataIos data = shiftLeftKeyEvent.data as RawKeyEventDataIos;
expect(data.physicalKey, equals(PhysicalKeyboardKey.shiftLeft));
expect(data.logicalKey, equals(LogicalKeyboardKey.shiftLeft));
expect(data.keyLabel, isEmpty);
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/35347
test('Unprintable keyboard keys are correctly translated', () {
final RawKeyEvent leftArrowKey = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
'keymap': 'ios',
'keyCode': 0x00000050,
'characters': '',
'charactersIgnoringModifiers': 'UIKeyInputLeftArrow',
'modifiers': RawKeyEventDataIos.modifierFunction,
});
final RawKeyEventDataIos data = leftArrowKey.data as RawKeyEventDataIos;
expect(data.physicalKey, equals(PhysicalKeyboardKey.arrowLeft));
expect(data.logicalKey, equals(LogicalKeyboardKey.arrowLeft));
expect(data.logicalKey.keyLabel, isEmpty);
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/35347
});
group('RawKeyEventDataWindows', () { group('RawKeyEventDataWindows', () {
const Map<int, _ModifierCheck> modifierTests = <int, _ModifierCheck>{ const Map<int, _ModifierCheck> modifierTests = <int, _ModifierCheck>{
RawKeyEventDataWindows.modifierLeftAlt: _ModifierCheck(ModifierKey.altModifier, KeyboardSide.left), RawKeyEventDataWindows.modifierLeftAlt: _ModifierCheck(ModifierKey.altModifier, KeyboardSide.left),
......
...@@ -39,6 +39,7 @@ class KeyEventSimulator { ...@@ -39,6 +39,7 @@ class KeyEventSimulator {
case 'macos': case 'macos':
case 'linux': case 'linux':
case 'web': case 'web':
case 'ios':
case 'windows': case 'windows':
return true; return true;
} }
...@@ -58,6 +59,9 @@ class KeyEventSimulator { ...@@ -58,6 +59,9 @@ class KeyEventSimulator {
case 'macos': case 'macos':
map = kMacOsToPhysicalKey; map = kMacOsToPhysicalKey;
break; break;
case 'ios':
map = kIosToPhysicalKey;
break;
case 'linux': case 'linux':
map = kLinuxToPhysicalKey; map = kLinuxToPhysicalKey;
break; break;
...@@ -90,7 +94,10 @@ class KeyEventSimulator { ...@@ -90,7 +94,10 @@ class KeyEventSimulator {
map = kFuchsiaToLogicalKey; map = kFuchsiaToLogicalKey;
break; break;
case 'macos': case 'macos':
// macOS doesn't do key codes, just scan codes. // macOS doesn't do key codes, just scan codes.
return -1;
case 'ios':
// iOS doesn't do key codes, just scan codes.
return -1; return -1;
case 'web': case 'web':
// web doesn't have int type code // web doesn't have int type code
...@@ -137,6 +144,9 @@ class KeyEventSimulator { ...@@ -137,6 +144,9 @@ class KeyEventSimulator {
case 'macos': case 'macos':
map = kMacOsToPhysicalKey; map = kMacOsToPhysicalKey;
break; break;
case 'ios':
map = kIosToPhysicalKey;
break;
case 'linux': case 'linux':
map = kLinuxToPhysicalKey; map = kLinuxToPhysicalKey;
break; break;
...@@ -213,6 +223,12 @@ class KeyEventSimulator { ...@@ -213,6 +223,12 @@ class KeyEventSimulator {
} }
result['modifiers'] = _getMacOsModifierFlags(key, isDown); result['modifiers'] = _getMacOsModifierFlags(key, isDown);
break; break;
case 'ios':
result['keyCode'] = scanCode;
result['characters'] = key.keyLabel;
result['charactersIgnoringModifiers'] = key.keyLabel;
result['modifiers'] = _getIOSModifierFlags(key, isDown);
break;
case 'web': case 'web':
result['code'] = _getWebKeyCode(key); result['code'] = _getWebKeyCode(key);
result['key'] = key.keyLabel; result['key'] = key.keyLabel;
...@@ -504,6 +520,73 @@ class KeyEventSimulator { ...@@ -504,6 +520,73 @@ class KeyEventSimulator {
return result; return result;
} }
static int _getIOSModifierFlags(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 |= RawKeyEventDataIos.modifierLeftShift | RawKeyEventDataIos.modifierShift;
}
if (pressed.contains(LogicalKeyboardKey.shiftRight)) {
result |= RawKeyEventDataIos.modifierRightShift | RawKeyEventDataIos.modifierShift;
}
if (pressed.contains(LogicalKeyboardKey.metaLeft)) {
result |= RawKeyEventDataIos.modifierLeftCommand | RawKeyEventDataIos.modifierCommand;
}
if (pressed.contains(LogicalKeyboardKey.metaRight)) {
result |= RawKeyEventDataIos.modifierRightCommand | RawKeyEventDataIos.modifierCommand;
}
if (pressed.contains(LogicalKeyboardKey.controlLeft)) {
result |= RawKeyEventDataIos.modifierLeftControl | RawKeyEventDataIos.modifierControl;
}
if (pressed.contains(LogicalKeyboardKey.controlRight)) {
result |= RawKeyEventDataIos.modifierRightControl | RawKeyEventDataIos.modifierControl;
}
if (pressed.contains(LogicalKeyboardKey.altLeft)) {
result |= RawKeyEventDataIos.modifierLeftOption | RawKeyEventDataIos.modifierOption;
}
if (pressed.contains(LogicalKeyboardKey.altRight)) {
result |= RawKeyEventDataIos.modifierRightOption | RawKeyEventDataIos.modifierOption;
}
final Set<LogicalKeyboardKey> functionKeys = <LogicalKeyboardKey>{
LogicalKeyboardKey.f1,
LogicalKeyboardKey.f2,
LogicalKeyboardKey.f3,
LogicalKeyboardKey.f4,
LogicalKeyboardKey.f5,
LogicalKeyboardKey.f6,
LogicalKeyboardKey.f7,
LogicalKeyboardKey.f8,
LogicalKeyboardKey.f9,
LogicalKeyboardKey.f10,
LogicalKeyboardKey.f11,
LogicalKeyboardKey.f12,
LogicalKeyboardKey.f13,
LogicalKeyboardKey.f14,
LogicalKeyboardKey.f15,
LogicalKeyboardKey.f16,
LogicalKeyboardKey.f17,
LogicalKeyboardKey.f18,
LogicalKeyboardKey.f19,
LogicalKeyboardKey.f20,
LogicalKeyboardKey.f21,
};
if (pressed.intersection(functionKeys).isNotEmpty) {
result |= RawKeyEventDataIos.modifierFunction;
}
if (pressed.intersection(kMacOsNumPadMap.values.toSet()).isNotEmpty) {
result |= RawKeyEventDataIos.modifierNumericPad;
}
if (pressed.contains(LogicalKeyboardKey.capsLock)) {
result |= RawKeyEventDataIos.modifierCapsLock;
}
return result;
}
/// Simulates sending a hardware key down event through the system channel. /// Simulates sending a hardware key down event through the system channel.
/// ///
/// This only simulates key presses coming from a physical keyboard, not from a /// This only simulates key presses coming from a physical keyboard, not from a
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment