|
8 | 8 | using Unity.Collections.LowLevel.Unsafe; |
9 | 9 | using UnityEngine.InputSystem.Layouts; |
10 | 10 | using UnityEngine.Scripting; |
| 11 | +#if UNITY_2021_2_OR_NEWER |
| 12 | +using UnityEngine.Pool; |
| 13 | +#endif |
11 | 14 |
|
12 | 15 | // HID support is currently broken in 32-bit Windows standalone players. Consider 32bit Windows players unsupported for now. |
13 | 16 | #if UNITY_STANDALONE_WIN && !UNITY_64 |
@@ -974,7 +977,165 @@ public string ToJson() |
974 | 977 |
|
975 | 978 | public static HIDDeviceDescriptor FromJson(string json) |
976 | 979 | { |
| 980 | +#if UNITY_2021_2_OR_NEWER |
| 981 | + try |
| 982 | + { |
| 983 | + // HID descriptors, when formatted correctly, are always json strings with no whitespace and a |
| 984 | + // predictable order of elements, so we can try and use this simple predictive parser to extract |
| 985 | + // the data. If for any reason the data is not formatted correctly, we'll automatically fall back |
| 986 | + // to Unity's default json parser. |
| 987 | + var descriptor = new HIDDeviceDescriptor(); |
| 988 | + |
| 989 | + var jsonSpan = json.AsSpan(); |
| 990 | + var parser = new PredictiveParser(); |
| 991 | + parser.ExpectSingleChar(jsonSpan, '{'); |
| 992 | + |
| 993 | + parser.AcceptString(jsonSpan, out _); |
| 994 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 995 | + descriptor.vendorId = parser.ExpectInt(jsonSpan); |
| 996 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 997 | + |
| 998 | + parser.AcceptString(jsonSpan, out _); |
| 999 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1000 | + descriptor.productId = parser.ExpectInt(jsonSpan); |
| 1001 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1002 | + |
| 1003 | + parser.AcceptString(jsonSpan, out _); |
| 1004 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1005 | + descriptor.usage = parser.ExpectInt(jsonSpan); |
| 1006 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1007 | + |
| 1008 | + parser.AcceptString(jsonSpan, out _); |
| 1009 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1010 | + descriptor.usagePage = (UsagePage)parser.ExpectInt(jsonSpan); |
| 1011 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1012 | + |
| 1013 | + parser.AcceptString(jsonSpan, out _); |
| 1014 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1015 | + descriptor.inputReportSize = parser.ExpectInt(jsonSpan); |
| 1016 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1017 | + |
| 1018 | + parser.AcceptString(jsonSpan, out _); |
| 1019 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1020 | + descriptor.outputReportSize = parser.ExpectInt(jsonSpan); |
| 1021 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1022 | + |
| 1023 | + parser.AcceptString(jsonSpan, out _); |
| 1024 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1025 | + descriptor.featureReportSize = parser.ExpectInt(jsonSpan); |
| 1026 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1027 | + |
| 1028 | + // elements |
| 1029 | + parser.AcceptString(jsonSpan, out var key); |
| 1030 | + if (key.ToString() != "elements") return descriptor; |
| 1031 | + |
| 1032 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1033 | + parser.ExpectSingleChar(jsonSpan, '['); |
| 1034 | + |
| 1035 | + using var pool = ListPool<HIDElementDescriptor>.Get(out var elements); |
| 1036 | + while (!parser.AcceptSingleChar(jsonSpan, ']')) |
| 1037 | + { |
| 1038 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1039 | + parser.ExpectSingleChar(jsonSpan, '{'); |
| 1040 | + |
| 1041 | + HIDElementDescriptor elementDesc = default; |
| 1042 | + |
| 1043 | + |
| 1044 | + parser.AcceptSingleChar(jsonSpan, '}'); |
| 1045 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1046 | + |
| 1047 | + // usage |
| 1048 | + parser.ExpectString(jsonSpan); |
| 1049 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1050 | + elementDesc.usage = parser.ExpectInt(jsonSpan); |
| 1051 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1052 | + |
| 1053 | + parser.ExpectString(jsonSpan); |
| 1054 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1055 | + elementDesc.usagePage = (UsagePage)parser.ExpectInt(jsonSpan); |
| 1056 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1057 | + |
| 1058 | + parser.ExpectString(jsonSpan); |
| 1059 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1060 | + elementDesc.unit = parser.ExpectInt(jsonSpan); |
| 1061 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1062 | + |
| 1063 | + parser.ExpectString(jsonSpan); |
| 1064 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1065 | + elementDesc.unitExponent = parser.ExpectInt(jsonSpan); |
| 1066 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1067 | + |
| 1068 | + parser.ExpectString(jsonSpan); |
| 1069 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1070 | + elementDesc.logicalMin = parser.ExpectInt(jsonSpan); |
| 1071 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1072 | + |
| 1073 | + parser.ExpectString(jsonSpan); |
| 1074 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1075 | + elementDesc.logicalMax = parser.ExpectInt(jsonSpan); |
| 1076 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1077 | + |
| 1078 | + parser.ExpectString(jsonSpan); |
| 1079 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1080 | + elementDesc.physicalMin = parser.ExpectInt(jsonSpan); |
| 1081 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1082 | + |
| 1083 | + parser.ExpectString(jsonSpan); |
| 1084 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1085 | + elementDesc.physicalMax = parser.ExpectInt(jsonSpan); |
| 1086 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1087 | + |
| 1088 | + parser.ExpectString(jsonSpan); |
| 1089 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1090 | + elementDesc.collectionIndex = parser.ExpectInt(jsonSpan); |
| 1091 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1092 | + |
| 1093 | + parser.ExpectString(jsonSpan); |
| 1094 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1095 | + elementDesc.reportType = (HIDReportType)parser.ExpectInt(jsonSpan); |
| 1096 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1097 | + |
| 1098 | + parser.ExpectString(jsonSpan); |
| 1099 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1100 | + elementDesc.reportId = parser.ExpectInt(jsonSpan); |
| 1101 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1102 | + |
| 1103 | + // reportCount. We don't store this one |
| 1104 | + parser.ExpectString(jsonSpan); |
| 1105 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1106 | + parser.AcceptInt(jsonSpan); |
| 1107 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1108 | + |
| 1109 | + parser.ExpectString(jsonSpan); |
| 1110 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1111 | + elementDesc.reportSizeInBits = parser.ExpectInt(jsonSpan); |
| 1112 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1113 | + |
| 1114 | + parser.ExpectString(jsonSpan); |
| 1115 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1116 | + elementDesc.reportOffsetInBits = parser.ExpectInt(jsonSpan); |
| 1117 | + parser.AcceptSingleChar(jsonSpan, ','); |
| 1118 | + |
| 1119 | + parser.ExpectString(jsonSpan); |
| 1120 | + parser.ExpectSingleChar(jsonSpan, ':'); |
| 1121 | + elementDesc.flags = (HIDElementFlags)parser.ExpectInt(jsonSpan); |
| 1122 | + |
| 1123 | + parser.ExpectSingleChar(jsonSpan, '}'); |
| 1124 | + |
| 1125 | + elements.Add(elementDesc); |
| 1126 | + } |
| 1127 | + descriptor.elements = elements.ToArray(); |
| 1128 | + |
| 1129 | + return descriptor; |
| 1130 | + } |
| 1131 | + catch (Exception) |
| 1132 | + { |
| 1133 | + Debug.LogWarning($"Couldn't parse HID descriptor with fast parser. Using fallback"); |
| 1134 | + return JsonUtility.FromJson<HIDDeviceDescriptor>(json); |
| 1135 | + } |
| 1136 | +#else |
977 | 1137 | return JsonUtility.FromJson<HIDDeviceDescriptor>(json); |
| 1138 | +#endif |
978 | 1139 | } |
979 | 1140 | } |
980 | 1141 |
|
|
0 commit comments