@keymanapp/common-types 17.0.85-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) hide show
  1. package/build/src/consts/virtual-key-constants.d.ts +131 -0
  2. package/build/src/consts/virtual-key-constants.d.ts.map +1 -0
  3. package/build/src/consts/virtual-key-constants.js +245 -0
  4. package/build/src/consts/virtual-key-constants.js.map +1 -0
  5. package/build/src/import/techpreview/cldr_info.json +5 -0
  6. package/build/src/import/techpreview/keys-Latn-implied.xml +80 -0
  7. package/build/src/import/techpreview/keys-Zyyy-currency.xml +22 -0
  8. package/build/src/import/techpreview/keys-Zyyy-punctuation.xml +46 -0
  9. package/build/src/keyman-touch-layout/keyman-touch-layout-file-reader.d.ts +7 -0
  10. package/build/src/keyman-touch-layout/keyman-touch-layout-file-reader.d.ts.map +1 -0
  11. package/build/src/keyman-touch-layout/keyman-touch-layout-file-reader.js +74 -0
  12. package/build/src/keyman-touch-layout/keyman-touch-layout-file-reader.js.map +1 -0
  13. package/build/src/keyman-touch-layout/keyman-touch-layout-file-writer.d.ts +24 -0
  14. package/build/src/keyman-touch-layout/keyman-touch-layout-file-writer.d.ts.map +1 -0
  15. package/build/src/keyman-touch-layout/keyman-touch-layout-file-writer.js +75 -0
  16. package/build/src/keyman-touch-layout/keyman-touch-layout-file-writer.js.map +1 -0
  17. package/build/src/keyman-touch-layout/keyman-touch-layout-file.d.ts +76 -0
  18. package/build/src/keyman-touch-layout/keyman-touch-layout-file.d.ts.map +1 -0
  19. package/build/src/keyman-touch-layout/keyman-touch-layout-file.js +26 -0
  20. package/build/src/keyman-touch-layout/keyman-touch-layout-file.js.map +1 -0
  21. package/build/src/keyman-touch-layout.clean.spec.json +170 -0
  22. package/build/src/kmx/element-string.d.ts +19 -0
  23. package/build/src/kmx/element-string.d.ts.map +1 -0
  24. package/build/src/kmx/element-string.js +72 -0
  25. package/build/src/kmx/element-string.js.map +1 -0
  26. package/build/src/kmx/kmx-builder.d.ts +77 -0
  27. package/build/src/kmx/kmx-builder.d.ts.map +1 -0
  28. package/build/src/kmx/kmx-builder.js +193 -0
  29. package/build/src/kmx/kmx-builder.js.map +1 -0
  30. package/build/src/kmx/kmx-plus-builder/build-disp.d.ts +18 -0
  31. package/build/src/kmx/kmx-plus-builder/build-disp.d.ts.map +1 -0
  32. package/build/src/kmx/kmx-plus-builder/build-disp.js +25 -0
  33. package/build/src/kmx/kmx-plus-builder/build-disp.js.map +1 -0
  34. package/build/src/kmx/kmx-plus-builder/build-elem.d.ts +26 -0
  35. package/build/src/kmx/kmx-plus-builder/build-elem.d.ts.map +1 -0
  36. package/build/src/kmx/kmx-plus-builder/build-elem.js +78 -0
  37. package/build/src/kmx/kmx-plus-builder/build-elem.js.map +1 -0
  38. package/build/src/kmx/kmx-plus-builder/build-keys.d.ts +60 -0
  39. package/build/src/kmx/kmx-plus-builder/build-keys.d.ts.map +1 -0
  40. package/build/src/kmx/kmx-plus-builder/build-keys.js +107 -0
  41. package/build/src/kmx/kmx-plus-builder/build-keys.js.map +1 -0
  42. package/build/src/kmx/kmx-plus-builder/build-layr.d.ts +54 -0
  43. package/build/src/kmx/kmx-plus-builder/build-layr.d.ts.map +1 -0
  44. package/build/src/kmx/kmx-plus-builder/build-layr.js +99 -0
  45. package/build/src/kmx/kmx-plus-builder/build-layr.js.map +1 -0
  46. package/build/src/kmx/kmx-plus-builder/build-list.d.ts +34 -0
  47. package/build/src/kmx/kmx-plus-builder/build-list.d.ts.map +1 -0
  48. package/build/src/kmx/kmx-plus-builder/build-list.js +62 -0
  49. package/build/src/kmx/kmx-plus-builder/build-list.js.map +1 -0
  50. package/build/src/kmx/kmx-plus-builder/build-loca.d.ts +12 -0
  51. package/build/src/kmx/kmx-plus-builder/build-loca.d.ts.map +1 -0
  52. package/build/src/kmx/kmx-plus-builder/build-loca.js +20 -0
  53. package/build/src/kmx/kmx-plus-builder/build-loca.js.map +1 -0
  54. package/build/src/kmx/kmx-plus-builder/build-meta.d.ts +17 -0
  55. package/build/src/kmx/kmx-plus-builder/build-meta.d.ts.map +1 -0
  56. package/build/src/kmx/kmx-plus-builder/build-meta.js +21 -0
  57. package/build/src/kmx/kmx-plus-builder/build-meta.js.map +1 -0
  58. package/build/src/kmx/kmx-plus-builder/build-name.d.ts +12 -0
  59. package/build/src/kmx/kmx-plus-builder/build-name.d.ts.map +1 -0
  60. package/build/src/kmx/kmx-plus-builder/build-name.js +23 -0
  61. package/build/src/kmx/kmx-plus-builder/build-name.js.map +1 -0
  62. package/build/src/kmx/kmx-plus-builder/build-ordr.d.ts +18 -0
  63. package/build/src/kmx/kmx-plus-builder/build-ordr.d.ts.map +1 -0
  64. package/build/src/kmx/kmx-plus-builder/build-ordr.js +27 -0
  65. package/build/src/kmx/kmx-plus-builder/build-ordr.js.map +1 -0
  66. package/build/src/kmx/kmx-plus-builder/build-sect.d.ts +16 -0
  67. package/build/src/kmx/kmx-plus-builder/build-sect.d.ts.map +1 -0
  68. package/build/src/kmx/kmx-plus-builder/build-sect.js +14 -0
  69. package/build/src/kmx/kmx-plus-builder/build-sect.js.map +1 -0
  70. package/build/src/kmx/kmx-plus-builder/build-strs.d.ts +18 -0
  71. package/build/src/kmx/kmx-plus-builder/build-strs.d.ts.map +1 -0
  72. package/build/src/kmx/kmx-plus-builder/build-strs.js +34 -0
  73. package/build/src/kmx/kmx-plus-builder/build-strs.js.map +1 -0
  74. package/build/src/kmx/kmx-plus-builder/build-tran.d.ts +20 -0
  75. package/build/src/kmx/kmx-plus-builder/build-tran.d.ts.map +1 -0
  76. package/build/src/kmx/kmx-plus-builder/build-tran.js +30 -0
  77. package/build/src/kmx/kmx-plus-builder/build-tran.js.map +1 -0
  78. package/build/src/kmx/kmx-plus-builder/build-vkey.d.ts +16 -0
  79. package/build/src/kmx/kmx-plus-builder/build-vkey.d.ts.map +1 -0
  80. package/build/src/kmx/kmx-plus-builder/build-vkey.js +23 -0
  81. package/build/src/kmx/kmx-plus-builder/build-vkey.js.map +1 -0
  82. package/build/src/kmx/kmx-plus-builder/builder-section.d.ts +6 -0
  83. package/build/src/kmx/kmx-plus-builder/builder-section.d.ts.map +1 -0
  84. package/build/src/kmx/kmx-plus-builder/builder-section.js +3 -0
  85. package/build/src/kmx/kmx-plus-builder/builder-section.js.map +1 -0
  86. package/build/src/kmx/kmx-plus-builder/kmx-plus-builder.d.ts +47 -0
  87. package/build/src/kmx/kmx-plus-builder/kmx-plus-builder.d.ts.map +1 -0
  88. package/build/src/kmx/kmx-plus-builder/kmx-plus-builder.js +143 -0
  89. package/build/src/kmx/kmx-plus-builder/kmx-plus-builder.js.map +1 -0
  90. package/build/src/kmx/kmx-plus.d.ts +259 -0
  91. package/build/src/kmx/kmx-plus.d.ts.map +1 -0
  92. package/build/src/kmx/kmx-plus.js +594 -0
  93. package/build/src/kmx/kmx-plus.js.map +1 -0
  94. package/build/src/kmx/kmx.d.ts +166 -0
  95. package/build/src/kmx/kmx.d.ts.map +1 -0
  96. package/build/src/kmx/kmx.js +271 -0
  97. package/build/src/kmx/kmx.js.map +1 -0
  98. package/build/src/kmx/string-list.d.ts +29 -0
  99. package/build/src/kmx/string-list.d.ts.map +1 -0
  100. package/build/src/kmx/string-list.js +75 -0
  101. package/build/src/kmx/string-list.js.map +1 -0
  102. package/build/src/kpj/keyman-developer-project.d.ts +58 -0
  103. package/build/src/kpj/keyman-developer-project.d.ts.map +1 -0
  104. package/build/src/kpj/keyman-developer-project.js +141 -0
  105. package/build/src/kpj/keyman-developer-project.js.map +1 -0
  106. package/build/src/kpj/kpj-file-reader.d.ts +17 -0
  107. package/build/src/kpj/kpj-file-reader.d.ts.map +1 -0
  108. package/build/src/kpj/kpj-file-reader.js +92 -0
  109. package/build/src/kpj/kpj-file-reader.js.map +1 -0
  110. package/build/src/kpj/kpj-file.d.ts +39 -0
  111. package/build/src/kpj/kpj-file.d.ts.map +1 -0
  112. package/build/src/kpj/kpj-file.js +11 -0
  113. package/build/src/kpj/kpj-file.js.map +1 -0
  114. package/build/src/kpj.schema.json +127 -0
  115. package/build/src/kvk/kvk-file-reader.d.ts +5 -0
  116. package/build/src/kvk/kvk-file-reader.d.ts.map +1 -0
  117. package/build/src/kvk/kvk-file-reader.js +35 -0
  118. package/build/src/kvk/kvk-file-reader.js.map +1 -0
  119. package/build/src/kvk/kvk-file-writer.d.ts +20 -0
  120. package/build/src/kvk/kvk-file-writer.d.ts.map +1 -0
  121. package/build/src/kvk/kvk-file-writer.js +67 -0
  122. package/build/src/kvk/kvk-file-writer.js.map +1 -0
  123. package/build/src/kvk/kvk-file.d.ts +64 -0
  124. package/build/src/kvk/kvk-file.d.ts.map +1 -0
  125. package/build/src/kvk/kvk-file.js +63 -0
  126. package/build/src/kvk/kvk-file.js.map +1 -0
  127. package/build/src/kvk/kvks-file-reader.d.ts +30 -0
  128. package/build/src/kvk/kvks-file-reader.d.ts.map +1 -0
  129. package/build/src/kvk/kvks-file-reader.js +154 -0
  130. package/build/src/kvk/kvks-file-reader.js.map +1 -0
  131. package/build/src/kvk/kvks-file-writer.d.ts +6 -0
  132. package/build/src/kvk/kvks-file-writer.d.ts.map +1 -0
  133. package/build/src/kvk/kvks-file-writer.js +99 -0
  134. package/build/src/kvk/kvks-file-writer.js.map +1 -0
  135. package/build/src/kvk/kvks-file.d.ts +44 -0
  136. package/build/src/kvk/kvks-file.d.ts.map +1 -0
  137. package/build/src/kvk/kvks-file.js +10 -0
  138. package/build/src/kvk/kvks-file.js.map +1 -0
  139. package/build/src/kvk/visual-keyboard.d.ts +35 -0
  140. package/build/src/kvk/visual-keyboard.d.ts.map +1 -0
  141. package/build/src/kvk/visual-keyboard.js +61 -0
  142. package/build/src/kvk/visual-keyboard.js.map +1 -0
  143. package/build/src/kvks.schema.json +182 -0
  144. package/build/src/ldml-keyboard/ldml-keyboard-testdata-xml.d.ts +56 -0
  145. package/build/src/ldml-keyboard/ldml-keyboard-testdata-xml.d.ts.map +1 -0
  146. package/build/src/ldml-keyboard/ldml-keyboard-testdata-xml.js +20 -0
  147. package/build/src/ldml-keyboard/ldml-keyboard-testdata-xml.js.map +1 -0
  148. package/build/src/ldml-keyboard/ldml-keyboard-xml-reader.d.ts +91 -0
  149. package/build/src/ldml-keyboard/ldml-keyboard-xml-reader.d.ts.map +1 -0
  150. package/build/src/ldml-keyboard/ldml-keyboard-xml-reader.js +370 -0
  151. package/build/src/ldml-keyboard/ldml-keyboard-xml-reader.js.map +1 -0
  152. package/build/src/ldml-keyboard/ldml-keyboard-xml.d.ts +143 -0
  153. package/build/src/ldml-keyboard/ldml-keyboard-xml.d.ts.map +1 -0
  154. package/build/src/ldml-keyboard/ldml-keyboard-xml.js +34 -0
  155. package/build/src/ldml-keyboard/ldml-keyboard-xml.js.map +1 -0
  156. package/build/src/ldml-keyboard.schema.json +634 -0
  157. package/build/src/ldml-keyboardtest.schema.json +221 -0
  158. package/build/src/main.d.ts +21 -0
  159. package/build/src/main.d.ts.map +1 -0
  160. package/build/src/main.js +20 -0
  161. package/build/src/main.js.map +1 -0
  162. package/build/src/util/common-events.d.ts +49 -0
  163. package/build/src/util/common-events.d.ts.map +1 -0
  164. package/build/src/util/common-events.js +29 -0
  165. package/build/src/util/common-events.js.map +1 -0
  166. package/build/src/util/compiler-interfaces.d.ts +51 -0
  167. package/build/src/util/compiler-interfaces.d.ts.map +1 -0
  168. package/build/src/util/compiler-interfaces.js +33 -0
  169. package/build/src/util/compiler-interfaces.js.map +1 -0
  170. package/build/src/util/util.d.ts +17 -0
  171. package/build/src/util/util.d.ts.map +1 -0
  172. package/build/src/util/util.js +67 -0
  173. package/build/src/util/util.js.map +1 -0
  174. package/build/tsconfig.tsbuildinfo +1 -0
  175. package/build.sh +86 -0
  176. package/package.json +58 -0
  177. package/src/consts/virtual-key-constants.ts +257 -0
  178. package/src/keyman-touch-layout/keyman-touch-layout-file-reader.ts +81 -0
  179. package/src/keyman-touch-layout/keyman-touch-layout-file-writer.ts +84 -0
  180. package/src/keyman-touch-layout/keyman-touch-layout-file.ts +87 -0
  181. package/src/kmx/element-string.ts +79 -0
  182. package/src/kmx/kmx-builder.ts +287 -0
  183. package/src/kmx/kmx-plus-builder/build-disp.ts +46 -0
  184. package/src/kmx/kmx-plus-builder/build-elem.ts +103 -0
  185. package/src/kmx/kmx-plus-builder/build-keys.ts +175 -0
  186. package/src/kmx/kmx-plus-builder/build-layr.ts +154 -0
  187. package/src/kmx/kmx-plus-builder/build-list.ts +95 -0
  188. package/src/kmx/kmx-plus-builder/build-loca.ts +34 -0
  189. package/src/kmx/kmx-plus-builder/build-meta.ts +37 -0
  190. package/src/kmx/kmx-plus-builder/build-name.ts +37 -0
  191. package/src/kmx/kmx-plus-builder/build-ordr.ts +45 -0
  192. package/src/kmx/kmx-plus-builder/build-sect.ts +31 -0
  193. package/src/kmx/kmx-plus-builder/build-strs.ts +58 -0
  194. package/src/kmx/kmx-plus-builder/build-tran.ts +50 -0
  195. package/src/kmx/kmx-plus-builder/build-vkey.ts +43 -0
  196. package/src/kmx/kmx-plus-builder/builder-section.ts +6 -0
  197. package/src/kmx/kmx-plus-builder/kmx-plus-builder.ts +190 -0
  198. package/src/kmx/kmx-plus.ts +692 -0
  199. package/src/kmx/kmx.ts +360 -0
  200. package/src/kmx/string-list.ts +74 -0
  201. package/src/kpj/keyman-developer-project.ts +155 -0
  202. package/src/kpj/kpj-file-reader.ts +103 -0
  203. package/src/kpj/kpj-file.ts +52 -0
  204. package/src/kvk/kvk-file-reader.ts +34 -0
  205. package/src/kvk/kvk-file-writer.ts +72 -0
  206. package/src/kvk/kvk-file.ts +122 -0
  207. package/src/kvk/kvks-file-reader.ts +164 -0
  208. package/src/kvk/kvks-file-writer.ts +113 -0
  209. package/src/kvk/kvks-file.ts +53 -0
  210. package/src/kvk/visual-keyboard.ts +80 -0
  211. package/src/ldml-keyboard/ldml-keyboard-testdata-xml.ts +74 -0
  212. package/src/ldml-keyboard/ldml-keyboard-xml-reader.ts +387 -0
  213. package/src/ldml-keyboard/ldml-keyboard-xml.ts +177 -0
  214. package/src/main.ts +27 -0
  215. package/src/restructure.d.ts +2 -0
  216. package/src/util/common-events.ts +50 -0
  217. package/src/util/compiler-interfaces.ts +54 -0
  218. package/src/util/util.ts +68 -0
  219. package/test/fixtures/import-minimal.xml +8 -0
  220. package/test/fixtures/import-minimal1.xml +11 -0
  221. package/test/fixtures/import-minimal2.xml +11 -0
  222. package/test/fixtures/import-symbols.xml +13 -0
  223. package/test/fixtures/invalid-conforms-to.xml +19 -0
  224. package/test/fixtures/invalid-import-base.xml +16 -0
  225. package/test/fixtures/invalid-import-path.xml +16 -0
  226. package/test/fixtures/invalid-import-readfail.xml +16 -0
  227. package/test/fixtures/invalid-import-wrongroot.xml +16 -0
  228. package/test/fixtures/invalid-structure-per-dtd.xml +8 -0
  229. package/test/fixtures/keyman-touch-layout/khmer_angkor.keyman-touch-layout +1950 -0
  230. package/test/fixtures/keyman-touch-layout/legacy.keyman-touch-layout +36 -0
  231. package/test/fixtures/kpj/khmer_angkor.kpj +187 -0
  232. package/test/fixtures/kvk/khmer_angkor.kvk +0 -0
  233. package/test/fixtures/kvk/khmer_angkor.kvks +206 -0
  234. package/test/fixtures/test-fr.xml +22 -0
  235. package/test/helpers/index.ts +39 -0
  236. package/test/helpers/reader-callback-test.ts +199 -0
  237. package/test/keyman-touch-layout/test-keyman-touch-layout-file-reader.ts +71 -0
  238. package/test/keyman-touch-layout/test-keyman-touch-layout-round-trip.ts +35 -0
  239. package/test/kpj/test-kpj-file-reader.ts +123 -0
  240. package/test/kvk/test-kvk-file.ts +15 -0
  241. package/test/kvk/test-kvk-round-trip.ts +87 -0
  242. package/test/kvk/test-kvk-utils.ts +24 -0
  243. package/test/kvk/test-kvks-file.ts +45 -0
  244. package/test/ldml-keyboard/test-ldml-keyboard-testdata-reader.ts +51 -0
  245. package/test/ldml-keyboard/test-ldml-keyboard-xml-reader.ts +131 -0
  246. package/test/tsconfig.json +21 -0
  247. package/test/util/test-unescape.ts +38 -0
  248. package/tsconfig.json +17 -0
@@ -0,0 +1,52 @@
1
+ /*
2
+ * Keyman Developer Project File
3
+ */
4
+
5
+
6
+ // These interfaces match XML read by xml2js. Use `KeymanDeveloperProject`
7
+ // returned by `KPJFileReader.transform()` for all processing.
8
+
9
+ export interface KPJFile {
10
+ KeymanDeveloperProject: KPJFileProject;
11
+ }
12
+
13
+ export interface KPJFileProject {
14
+ Options?: KPJFileOptions; // Required
15
+ Files?: KPJFileFiles; // Required in 1.0, optional and always ignored in 2.0
16
+ };
17
+
18
+ export interface KPJFileOptions {
19
+ BuildPath?: string; // default '' in 1.0, '$PROJECTPATH/build' in 2.0
20
+ SourcePath?: string; // default '' in 1.0, '$PROJECTPATH/source' in 2.0
21
+ CompilerWarningsAsErrors?: string; // default False
22
+ WarnDeprecatedCode?: string; // default True
23
+ CheckFilenameConventions?: string; // default True
24
+ ProjectType?: 'keyboard' | 'lexicalmodel'; // default 'keyboard'
25
+ Version?: '1.0' | '2.0'; // default 1.0
26
+ };
27
+
28
+ export interface KPJFileFiles {
29
+ File?: KPJFileFile[];
30
+ };
31
+
32
+ export interface KPJFileFile {
33
+ ID?: string;
34
+ Filename?: string;
35
+ Filepath?: string;
36
+ FileVersion?: string;
37
+ FileType?: string;
38
+ Details?: KPJFileFileDetail_Kmn & KPJFileFileDetail_Kps;
39
+ ParentFileID?: string;
40
+ };
41
+
42
+ export interface KPJFileFileDetail_Kmn {
43
+ Name?: string;
44
+ Copyright?: string;
45
+ Message?: string;
46
+ };
47
+
48
+ export interface KPJFileFileDetail_Kps {
49
+ Name?: string;
50
+ Copyright?: string;
51
+ Version?: string;
52
+ };
@@ -0,0 +1,34 @@
1
+ import KVKFile, { BUILDER_KVK_FILE, BUILDER_KVK_HEADER_IDENTIFIER, BUILDER_KVK_HEADER_VERSION } from "./kvk-file.js";
2
+ import { VisualKeyboard, VisualKeyboardKey } from "./visual-keyboard.js";
3
+
4
+ export default class KvkFileReader {
5
+ public read(source: Uint8Array): VisualKeyboard {
6
+ let binary: BUILDER_KVK_FILE;
7
+ let kvk = new KVKFile();
8
+ binary = kvk.KVK_FILE.fromBuffer(source);
9
+ if(binary.header.identifier != BUILDER_KVK_HEADER_IDENTIFIER ||
10
+ binary.header.version != BUILDER_KVK_HEADER_VERSION) {
11
+ return null;
12
+ }
13
+ let result = new VisualKeyboard();
14
+ result.header.version = binary.header.version;
15
+ result.header.flags = binary.header.flags;
16
+ result.header.associatedKeyboard = binary.header.associatedKeyboard.str;
17
+ result.header.ansiFont.color = binary.header.ansiFont.color;
18
+ result.header.ansiFont.name = binary.header.ansiFont.name.str;
19
+ result.header.ansiFont.size = binary.header.ansiFont.size;
20
+ result.header.unicodeFont.color = binary.header.unicodeFont.color;
21
+ result.header.unicodeFont.name = binary.header.unicodeFont.name.str;
22
+ result.header.unicodeFont.size = binary.header.unicodeFont.size;
23
+ for(let binaryKey of binary.keys) {
24
+ let key: VisualKeyboardKey = {
25
+ flags: binaryKey.flags,
26
+ vkey: binaryKey.vkey,
27
+ shift: binaryKey.shift,
28
+ text: binaryKey.text.str
29
+ };
30
+ result.keys.push(key);
31
+ }
32
+ return result;
33
+ }
34
+ };
@@ -0,0 +1,72 @@
1
+ import KVKFile, { BUILDER_KVK_FILE, BUILDER_KVK_HEADER_IDENTIFIER, BUILDER_KVK_HEADER_VERSION, BUILDER_KVK_KEY, BUILDER_KVK_STRING } from "./kvk-file.js";
2
+ import { VisualKeyboard } from "./visual-keyboard.js";
3
+
4
+ export default class KvkFileWriter {
5
+ /**
6
+ * Writes the visual keyboard to a binary .kvk format byte array.
7
+ * @param source VisualKeyboard
8
+ * @returns Uint8Array, the .kvk file
9
+ */
10
+ write(source: VisualKeyboard): Uint8Array {
11
+ const binary = this.build(source);
12
+ const kvk = new KVKFile();
13
+ const file: Uint8Array = new Uint8Array(kvk.KVK_FILE.size(binary));
14
+ const data = kvk.KVK_FILE.toBuffer(binary);
15
+ file.set(data, 0);
16
+ return file;
17
+ }
18
+
19
+ private build(source: VisualKeyboard) {
20
+ const binary: BUILDER_KVK_FILE = {
21
+ header: {
22
+ identifier: BUILDER_KVK_HEADER_IDENTIFIER,
23
+ version: BUILDER_KVK_HEADER_VERSION,
24
+ associatedKeyboard: {len:0,str:''},
25
+ flags: source.header.flags,
26
+ ansiFont:{
27
+ color: source.header.ansiFont.color,
28
+ size: source.header.ansiFont.size,
29
+ name: {len:0,str:''}
30
+ },
31
+ unicodeFont:{
32
+ color: source.header.unicodeFont.color,
33
+ size: source.header.unicodeFont.size,
34
+ name: {len:0,str:''}
35
+ },
36
+ },
37
+ keyCount: source.keys.length,
38
+ keys:[]
39
+ };
40
+
41
+ this.setString(binary.header.associatedKeyboard, source.header.associatedKeyboard);
42
+ this.setString(binary.header.ansiFont.name, source.header.ansiFont.name);
43
+ this.setString(binary.header.unicodeFont.name, source.header.unicodeFont.name);
44
+
45
+ for(let sourceKey of source.keys) {
46
+ const binaryKey: BUILDER_KVK_KEY = {
47
+ flags: sourceKey.flags,
48
+ vkey: sourceKey.vkey,
49
+ shift: sourceKey.shift,
50
+ text: { len: 0, str: '' },
51
+ bitmap: 0
52
+ };
53
+ this.setString(binaryKey.text, sourceKey.text || '');
54
+ binary.keys.push(binaryKey);
55
+ }
56
+
57
+ return binary;
58
+ }
59
+
60
+ /**
61
+ * Fills a kvk string from a source string. Note that the format includes both
62
+ * a length word and zero termination.
63
+ *
64
+ * @param str
65
+ * @param value
66
+ * @returns number
67
+ */
68
+ private setString(str: BUILDER_KVK_STRING, value: string): void {
69
+ str.len = value.length + 1;
70
+ str.str = value;
71
+ }
72
+ };
@@ -0,0 +1,122 @@
1
+ import * as r from 'restructure';
2
+ //
3
+ // Binary backing structures for .kvk format
4
+ // matching VisualKeyboardSaverBinary.pas
5
+ //
6
+
7
+ export const BUILDER_KVK_HEADER_IDENTIFIER = 0x464B564B; // 'KVKF', little-endian
8
+ export const BUILDER_KVK_HEADER_VERSION = 0x0600; // Keyman 6.0
9
+
10
+ export interface BUILDER_KVK_STRING {
11
+ len: number;
12
+ str: string;
13
+ };
14
+
15
+ export interface BUILDER_KVK_FONT {
16
+ name: BUILDER_KVK_STRING; // 0000, variable length
17
+ size: number; // 4 bytes
18
+ color: number; // 4 bytes
19
+ };
20
+
21
+ export const BUILDER_KVK_FONT_Size = 8; // size of fixed elements of BUILDER_KVK_FONT
22
+
23
+ export const enum BUILDER_KVK_KEY_FLAGS {
24
+ kvkkBitmap = 0x01,
25
+ kvkkUnicode = 0x02
26
+ };
27
+
28
+ export const enum BUILDER_KVK_SHIFT_STATE {
29
+ KVKS_NORMAL = 0,
30
+ KVKS_SHIFT = 1,
31
+ KVKS_CTRL = 2,
32
+ KVKS_ALT = 4,
33
+ KVKS_LCTRL = 8,
34
+ KVKS_RCTRL = 16,
35
+ KVKS_LALT = 32,
36
+ KVKS_RALT = 64
37
+ };
38
+
39
+ export interface BUILDER_KVK_KEY {
40
+ flags: BUILDER_KVK_KEY_FLAGS; // 0000, 1 byte
41
+ shift: number; // 0001, 2 bytes
42
+ vkey: number; // 0003, 2 bytes
43
+ text: BUILDER_KVK_STRING; // 0005, variable length
44
+ bitmap: number; // always 0 // 4 bytes
45
+ };
46
+
47
+ export const BUILDER_KVK_KEY_Size = 9; // size of fixed elements of BUILDER_KVK_KEY
48
+
49
+ export const enum BUILDER_KVK_HEADER_FLAGS {
50
+ kvkh102 = 0x01,
51
+ kvkhDisplayUnderlying = 0x02,
52
+ kvkhUseUnderlying = 0x04,
53
+ kvkhAltGr = 0x08
54
+ };
55
+
56
+ export interface BUILDER_KVK_HEADER {
57
+ identifier: number; // 0000, 4 bytes
58
+ version: number; // 0004, 4 bytes
59
+ flags: BUILDER_KVK_HEADER_FLAGS; // 0008, 1 byte
60
+ associatedKeyboard: BUILDER_KVK_STRING; // 0009, variable length
61
+ ansiFont: BUILDER_KVK_FONT; // variable length
62
+ unicodeFont: BUILDER_KVK_FONT; // variable length
63
+ };
64
+
65
+ export const BUILDER_KVK_HEADER_Size = 9 + BUILDER_KVK_FONT_Size + BUILDER_KVK_FONT_Size; // size of fixed elements of BUILDER_KVK_HEADER
66
+
67
+ export interface BUILDER_KVK_FILE {
68
+ header: BUILDER_KVK_HEADER; // variable length
69
+ keyCount: number; // 4 bytes
70
+ keys: BUILDER_KVK_KEY[]; // variable length
71
+ };
72
+
73
+ export default class KVKFile {
74
+ public KVK_HEADER: any;
75
+ public KVK_KEY: any;
76
+ public KVK_KEYS: any;
77
+ public KVK_FONT: any;
78
+ public KVK_FILE: any;
79
+ public KVK_STRING: any;
80
+
81
+ constructor() {
82
+ //
83
+ // Binary restructure definitions matching VisualKeyboardSaverBinary.pas
84
+ // TODO: move binaries to separate kvk-file.ts
85
+ //
86
+
87
+ this.KVK_STRING = new r.Struct({
88
+ len: r.int16le,
89
+ str: new r.String(null, 'utf16le')
90
+ });
91
+
92
+ this.KVK_FONT = new r.Struct({
93
+ name: this.KVK_STRING,
94
+ size: r.int32le,
95
+ color: r.uint32le
96
+ });
97
+
98
+ this.KVK_KEY = new r.Struct({
99
+ flags: r.uint8,
100
+ shift: r.uint16le,
101
+ vkey: r.uint16le,
102
+ text: this.KVK_STRING,
103
+ bitmap: r.uint32le // always 00 00 00 00 for now
104
+ });
105
+
106
+ this.KVK_HEADER = new r.Struct({
107
+ identifier: r.uint32le, // KVKF
108
+ version: r.uint32le, // 0x0600
109
+ flags: r.uint8,
110
+ associatedKeyboard: this.KVK_STRING,
111
+ ansiFont: this.KVK_FONT,
112
+ unicodeFont: this.KVK_FONT
113
+ });
114
+
115
+ this.KVK_FILE = new r.Struct({
116
+ header: this.KVK_HEADER,
117
+ keyCount: r.uint32le,
118
+ keys: new r.Array(this.KVK_KEY, 'keyCount')
119
+ });
120
+
121
+ }
122
+ };
@@ -0,0 +1,164 @@
1
+ import * as xml2js from 'xml2js';
2
+ import KVKSourceFile from './kvks-file.js';
3
+ import { default as AjvModule } from 'ajv';
4
+ const Ajv = AjvModule.default; // The actual expected Ajv type.
5
+ import { boxXmlArray } from '../util/util.js';
6
+ import { VisualKeyboard, VisualKeyboardHeaderFlags, VisualKeyboardKey, VisualKeyboardKeyFlags, VisualKeyboardLegalShiftStates, VisualKeyboardShiftState } from './visual-keyboard.js';
7
+ import { USVirtualKeyCodes } from '../consts/virtual-key-constants.js';
8
+ import { BUILDER_KVK_HEADER_VERSION } from './kvk-file.js';
9
+
10
+ export enum KVKSParseErrorType { invalidVkey };
11
+ export class KVKSParseError extends Error {
12
+ public type: KVKSParseErrorType;
13
+ public vkey: string;
14
+ };
15
+
16
+ export default class KVKSFileReader {
17
+ public read(file: Uint8Array): KVKSourceFile {
18
+ let source: KVKSourceFile;
19
+
20
+ const parser = new xml2js.Parser({
21
+ explicitArray: false,
22
+ mergeAttrs: false,
23
+ includeWhiteChars: true,
24
+ normalize: false,
25
+ emptyTag: {} as any
26
+ // Why "as any"? xml2js is broken:
27
+ // https://github.com/Leonidas-from-XIV/node-xml2js/issues/648 means
28
+ // that an old version of `emptyTag` is used which doesn't support
29
+ // functions, but DefinitelyTyped is requiring use of function or a
30
+ // string. See also notes at
31
+ // https://github.com/DefinitelyTyped/DefinitelyTyped/pull/59259#issuecomment-1254405470
32
+ // An alternative fix would be to pull xml2js directly from github
33
+ // rather than using the version tagged on npmjs.com.
34
+ });
35
+
36
+ parser.parseString(file, (e: unknown, r: unknown) => { source = r as KVKSourceFile });
37
+ source = this.boxArrays(source);
38
+ this.cleanupUnderscore('visualkeyboard', source.visualkeyboard);
39
+ return source;
40
+ }
41
+
42
+ /**
43
+ * The only element that allows spaces is <key>. Remove
44
+ * all other empty whitespace-only values.
45
+ * @param root
46
+ * @param source
47
+ */
48
+ private cleanupUnderscore(root: string, source: any) {
49
+ if(root != 'key') {
50
+ if(source?.['_']?.trim() === '') {
51
+ delete source['_'];
52
+ }
53
+ }
54
+
55
+ for(let key of Object.keys(source)) {
56
+ if(Array.isArray(source[key])) {
57
+ for(let item of source[key]) {
58
+ if(typeof(item) === 'object') {
59
+ this.cleanupUnderscore(key, item);
60
+ }
61
+ }
62
+ } else if(typeof source[key] === 'object') {
63
+ this.cleanupUnderscore(key, source[key]);
64
+ }
65
+ }
66
+ }
67
+
68
+ public validate(source: KVKSourceFile, schemaBuffer: Buffer): void {
69
+ const schema = JSON.parse(schemaBuffer.toString('utf8'));
70
+ const ajv = new Ajv();
71
+ if(!ajv.validate(schema, source)) {
72
+ throw new Error(ajv.errorsText());
73
+ }
74
+ }
75
+
76
+ public transform(source: KVKSourceFile, errors?: KVKSParseError[]): VisualKeyboard {
77
+ // NOTE: at this point, the xml should have been validated
78
+ // and matched the schema result so we can assume properties exist
79
+ let result: VisualKeyboard = {
80
+ header: {
81
+ version: BUILDER_KVK_HEADER_VERSION,
82
+ flags: 0,
83
+ ansiFont: { name: "Arial", size: -12, color: 0xFF000008 }, // TODO-LDML: consider defaults
84
+ unicodeFont: { name: "Arial", size: -12, color: 0xFF000008 }, // TODO-LDML: consider defaults
85
+ associatedKeyboard: source.visualkeyboard?.header?.kbdname,
86
+ underlyingLayout: source.visualkeyboard?.header?.layout,
87
+ },
88
+ keys: []
89
+ };
90
+
91
+ if(source.visualkeyboard?.header?.flags?.displayunderlying !== undefined) {
92
+ result.header.flags |= VisualKeyboardHeaderFlags.kvkhDisplayUnderlying;
93
+ }
94
+ if(source.visualkeyboard?.header?.flags?.key102 !== undefined) {
95
+ result.header.flags |= VisualKeyboardHeaderFlags.kvkh102;
96
+ }
97
+ if(source.visualkeyboard?.header?.flags?.usealtgr !== undefined) {
98
+ result.header.flags |= VisualKeyboardHeaderFlags.kvkhAltGr;
99
+ }
100
+ if(source.visualkeyboard?.header?.flags?.useunderlying !== undefined) {
101
+ result.header.flags |= VisualKeyboardHeaderFlags.kvkhUseUnderlying;
102
+ }
103
+
104
+ for(let encoding of source.visualkeyboard.encoding) {
105
+ let isUnicode = (encoding.$?.name == 'unicode'),
106
+ font = isUnicode ? result.header.unicodeFont : result.header.ansiFont;
107
+ font.name = encoding.$?.fontname;
108
+ font.size = parseInt(encoding.$?.fontsize,10);
109
+ for(let layer of encoding.layer) {
110
+ let shift = this.kvksShiftToKvkShift(layer.$?.shift);
111
+ for(let sourceKey of layer.key) {
112
+ let vkey = (USVirtualKeyCodes as any)[sourceKey.$?.vkey];
113
+ if(!vkey) {
114
+ if(errors) {
115
+ let e = new KVKSParseError();
116
+ e.type = KVKSParseErrorType.invalidVkey;
117
+ e.vkey = sourceKey.$?.vkey;
118
+ errors.push(e);
119
+ }
120
+ continue;
121
+ }
122
+ let key: VisualKeyboardKey = {
123
+ flags: isUnicode ? VisualKeyboardKeyFlags.kvkkUnicode : 0, // TODO-LDML: bitmap support
124
+ shift: shift,
125
+ text: sourceKey._ ?? '',
126
+ vkey: vkey
127
+ }
128
+ result.keys.push(key);
129
+ }
130
+ }
131
+ }
132
+
133
+ return result;
134
+ }
135
+
136
+ /**
137
+ * xml2js will not place single-entry objects into arrays.
138
+ * Easiest way to fix this is to box them ourselves as needed
139
+ * @param source KVKSourceFile
140
+ */
141
+ private boxArrays(source: KVKSourceFile) {
142
+ boxXmlArray(source.visualkeyboard, 'encoding');
143
+ for(let encoding of source.visualkeyboard.encoding) {
144
+ boxXmlArray(encoding, 'layer');
145
+ for(let layer of encoding.layer) {
146
+ boxXmlArray(layer, 'key');
147
+ }
148
+ }
149
+ return source;
150
+ }
151
+
152
+
153
+ public kvksShiftToKvkShift(shift: string): VisualKeyboardShiftState {
154
+ shift = shift.toUpperCase();
155
+
156
+ // TODO-LDML(lowpri): make a map of this?
157
+ for(let state of VisualKeyboardLegalShiftStates) {
158
+ if(state.name == shift) {
159
+ return state.shift;
160
+ }
161
+ }
162
+ return 0;
163
+ }
164
+ }
@@ -0,0 +1,113 @@
1
+ import * as xml2js from 'xml2js';
2
+ import KVKSourceFile, { KVKSEncoding, KVKSFlags, KVKSKey, KVKSLayer } from './kvks-file.js';
3
+ import { VisualKeyboard, VisualKeyboardHeaderFlags, VisualKeyboardKeyFlags, VisualKeyboardLegalShiftStates, VisualKeyboardShiftState } from './visual-keyboard.js';
4
+ import { USVirtualKeyCodes } from '../consts/virtual-key-constants.js';
5
+
6
+ export default class KVKSFileWriter {
7
+ public write(vk: VisualKeyboard): string {
8
+
9
+ const builder = new xml2js.Builder({
10
+ allowSurrogateChars: true,
11
+ attrkey: '$',
12
+ charkey: '_',
13
+ xmldec: {
14
+ version: '1.0',
15
+ encoding: 'UTF-8',
16
+ standalone: true
17
+ }
18
+ })
19
+
20
+ let flags: KVKSFlags = {};
21
+ if(vk.header.flags & VisualKeyboardHeaderFlags.kvkhDisplayUnderlying) {
22
+ flags.displayunderlying = '';
23
+ }
24
+ if(vk.header.flags & VisualKeyboardHeaderFlags.kvkh102) {
25
+ flags.key102 = '';
26
+ }
27
+ if(vk.header.flags & VisualKeyboardHeaderFlags.kvkhAltGr) {
28
+ flags.usealtgr = '';
29
+ }
30
+ if(vk.header.flags & VisualKeyboardHeaderFlags.kvkhUseUnderlying) {
31
+ flags.useunderlying = '';
32
+ }
33
+
34
+
35
+
36
+ let kvks: KVKSourceFile = {
37
+ visualkeyboard: {
38
+ header: {
39
+ version: '10.0',
40
+ kbdname: vk.header.associatedKeyboard,
41
+ flags: flags,
42
+ },
43
+ encoding: []
44
+ }
45
+ };
46
+
47
+ if(vk.header.underlyingLayout) kvks.visualkeyboard.header.layout = vk.header.underlyingLayout;
48
+
49
+ let encodings: {ansi: {o: KVKSEncoding, l: {[name:string]:KVKSLayer}}, unicode: {o: KVKSEncoding, l: {[name:string]:KVKSLayer}}} = {ansi:null,unicode:null};
50
+
51
+ for(let key of vk.keys) {
52
+ const encoding = key.flags & VisualKeyboardKeyFlags.kvkkUnicode ? 'unicode' : 'ansi';
53
+ const shift = this.kvkShiftToKvksShift(key.shift);
54
+
55
+ if(!encodings[encoding]) {
56
+ encodings[encoding] = {
57
+ o: {
58
+ layer: [],
59
+ $: {name: encoding,
60
+ fontname: encoding == 'ansi' ? vk.header.ansiFont.name : vk.header.unicodeFont.name,
61
+ fontsize: (encoding == 'ansi' ? vk.header.ansiFont.size : vk.header.unicodeFont.size).toString(),
62
+ },
63
+ },
64
+ l: {}
65
+ };
66
+ kvks.visualkeyboard.encoding.push(encodings[encoding].o);
67
+ }
68
+ let e = encodings[encoding];
69
+ if(!e.l[shift]) {
70
+ e.l[shift] = {
71
+ key: [],
72
+ $: {shift: shift},
73
+ };
74
+ e.o.layer.push(e.l[shift]);
75
+ }
76
+ let l = e.l[shift];
77
+
78
+ // TODO-LDML: map
79
+ let vkeyName = '';
80
+ for(let vkey of Object.keys(USVirtualKeyCodes)) {
81
+ if((USVirtualKeyCodes as any)[vkey] == key.vkey) {
82
+ vkeyName = vkey;
83
+ break;
84
+ }
85
+ }
86
+
87
+ if(vkeyName == '') {
88
+ //TODO-LDML: warn
89
+ continue;
90
+ }
91
+ let k: KVKSKey = {
92
+ $: {vkey: vkeyName},
93
+ _: key.text,
94
+ }
95
+
96
+ l.key.push(k);
97
+ }
98
+
99
+ // console.dir(kvks, {depth:8});
100
+ let result = builder.buildObject(kvks);
101
+ return result; //Uint8Array.from(result);
102
+ }
103
+
104
+ public kvkShiftToKvksShift(shift: VisualKeyboardShiftState): string {
105
+ // TODO-LDML(lowpri): make a map of this?
106
+ for(let state of VisualKeyboardLegalShiftStates) {
107
+ if(state.shift == shift) {
108
+ return state.name;
109
+ }
110
+ }
111
+ return '';
112
+ }
113
+ }
@@ -0,0 +1,53 @@
1
+ // .kvks xml format
2
+ // See VisualKeyboardLoaderXML.pas, not the same as VisualKeyboardImportXML.pas!
3
+
4
+ export default interface KVKSourceFile {
5
+ /**
6
+ * <visualkeyboard> -- the root element.
7
+ */
8
+ visualkeyboard: KVKSVisualKeyboard;
9
+ }
10
+
11
+ export interface KVKSVisualKeyboard {
12
+ header?: KVKSHeader;
13
+ encoding?: KVKSEncoding[];
14
+ };
15
+
16
+ export interface KVKSHeader {
17
+ version?: string;
18
+ kbdname?: string;
19
+ flags?: KVKSFlags;
20
+ layout?: string;
21
+ };
22
+
23
+ export interface KVKSFlags {
24
+ key102?: string;
25
+ displayunderlying?: string;
26
+ useunderlying?: string;
27
+ usealtgr?: string;
28
+ };
29
+
30
+ export interface KVKSEncoding {
31
+ $?: {
32
+ name?: string;
33
+ fontname?: string;
34
+ fontsize?: string;
35
+ };
36
+ layer?: KVKSLayer[];
37
+ };
38
+
39
+ export interface KVKSLayer {
40
+ $?: {
41
+ shift?: string;
42
+ };
43
+ key?: KVKSKey[];
44
+ };
45
+
46
+ export interface KVKSKey {
47
+ $?: {
48
+ vkey?: string;
49
+ }
50
+ bitmap?: string;
51
+ _?: string;
52
+ };
53
+
@@ -0,0 +1,80 @@
1
+ //
2
+ // Visual Keyboard in-memory data
3
+ //
4
+ // Corresponds to .kvk / .kvks file data
5
+ //
6
+
7
+ import { BUILDER_KVK_SHIFT_STATE, BUILDER_KVK_HEADER_FLAGS, BUILDER_KVK_KEY_FLAGS } from "./kvk-file.js";
8
+
9
+ export class VisualKeyboard {
10
+ header: VisualKeyboardHeader = {flags: 0, ansiFont:{}, unicodeFont:{}, underlyingLayout: undefined};
11
+ keys: VisualKeyboardKey[] = [];
12
+ };
13
+
14
+ export { BUILDER_KVK_HEADER_FLAGS as VisualKeyboardHeaderFlags } from "./kvk-file.js";
15
+
16
+ export class VisualKeyboardHeader {
17
+ version?: number; // 0x0600
18
+ flags: BUILDER_KVK_HEADER_FLAGS;
19
+ associatedKeyboard?: string;
20
+ ansiFont: VisualKeyboardFont; // generally unused
21
+ unicodeFont: VisualKeyboardFont;
22
+ underlyingLayout?: string;
23
+ };
24
+
25
+ export class VisualKeyboardFont {
26
+ name?: string;
27
+ size?: number;
28
+ color?: number; // unused
29
+ };
30
+
31
+ export { BUILDER_KVK_KEY_FLAGS as VisualKeyboardKeyFlags } from "./kvk-file.js";
32
+
33
+ export { BUILDER_KVK_SHIFT_STATE as VisualKeyboardShiftState } from "./kvk-file.js";
34
+
35
+ export class VisualKeyboardKey {
36
+ flags?: BUILDER_KVK_KEY_FLAGS;
37
+ shift?: BUILDER_KVK_SHIFT_STATE;
38
+ vkey?: number;
39
+ text?: string;
40
+ //bitmap: bitmap-image, unsupported in ldml keyboards; may include for round-tripabilty?
41
+ };
42
+
43
+ interface VisualKeyboardLegalShiftState {
44
+ desc: string;
45
+ name: string;
46
+ shift: number;
47
+ vkeys: number[];
48
+ };
49
+
50
+ import { BUILDER_KVK_SHIFT_STATE as ss } from "./kvk-file.js";
51
+ import { USVirtualKeyCodes as vk } from "../consts/virtual-key-constants.js";
52
+
53
+ export const VisualKeyboardLegalShiftStates: VisualKeyboardLegalShiftState[] = [
54
+ {desc: 'Unshifted', name: '', shift: ss.KVKS_NORMAL, vkeys: []}, //1
55
+
56
+ {desc: 'Shift', name: 'S', shift: ss.KVKS_SHIFT, vkeys: [vk.K_SHIFT]},
57
+ {desc: 'Ctrl', name: 'C', shift: ss.KVKS_CTRL, vkeys: [vk.K_CONTROL]},
58
+ {desc: 'Alt', name: 'A', shift: ss.KVKS_ALT, vkeys: [vk.K_ALT]},
59
+ {desc: 'Shift+Ctrl', name: 'SC', shift: ss.KVKS_SHIFT | ss.KVKS_CTRL, vkeys: [vk.K_SHIFT,vk.K_CONTROL]},
60
+ {desc: 'Shift+Alt', name: 'SA', shift: ss.KVKS_SHIFT | ss.KVKS_ALT, vkeys: [vk.K_SHIFT,vk.K_ALT]},
61
+ {desc: 'Ctrl+Alt', name: 'CA', shift: ss.KVKS_CTRL | ss.KVKS_ALT, vkeys: [vk.K_CONTROL,vk.K_ALT]},
62
+ {desc: 'Shift+Ctrl+Alt', name: 'SCA', shift: ss.KVKS_SHIFT | ss.KVKS_CTRL | ss.KVKS_ALT, vkeys: [vk.K_SHIFT,vk.K_CONTROL,vk.K_ALT]}, //7
63
+
64
+ {desc: 'Left Ctrl', name: 'LC', shift: ss.KVKS_LCTRL, vkeys: [vk.K_LCONTROL]},
65
+ {desc: 'Right Ctrl', name: 'RC', shift: ss.KVKS_RCTRL, vkeys: [vk.K_RCONTROL]},
66
+ {desc: 'Left Alt', name: 'LA', shift: ss.KVKS_LALT, vkeys: [vk.K_LALT]},
67
+ {desc: 'Right Alt', name: 'RA', shift: ss.KVKS_RALT, vkeys: [vk.K_RALT]},
68
+ {desc: 'Shift+Left Ctrl', name: 'SLC', shift: ss.KVKS_SHIFT | ss.KVKS_LCTRL, vkeys: [vk.K_SHIFT,vk.K_LCONTROL]},
69
+ {desc: 'Shift+Right Ctrl', name: 'SRC', shift: ss.KVKS_SHIFT | ss.KVKS_RCTRL, vkeys: [vk.K_SHIFT,vk.K_RCONTROL]},
70
+ {desc: 'Shift+Left Alt', name: 'SLA', shift: ss.KVKS_SHIFT | ss.KVKS_LALT, vkeys: [vk.K_SHIFT,vk.K_LALT]},
71
+ {desc: 'Shift+Right Alt', name: 'SRA', shift: ss.KVKS_SHIFT | ss.KVKS_RALT, vkeys: [vk.K_SHIFT,vk.K_RALT]},
72
+ {desc: 'Left Ctrl+Left Alt', name: 'LCLA', shift: ss.KVKS_LCTRL | ss.KVKS_LALT, vkeys: [vk.K_LCONTROL,vk.K_LALT]},
73
+ {desc: 'Left Ctrl+Right Alt', name: 'LCRA', shift: ss.KVKS_LCTRL | ss.KVKS_RALT, vkeys: [vk.K_LCONTROL,vk.K_RALT]},
74
+ {desc: 'Right Ctrl+Left Alt', name: 'RCLA', shift: ss.KVKS_RCTRL | ss.KVKS_LALT, vkeys: [vk.K_RCONTROL,vk.K_LALT]},
75
+ {desc: 'Right Ctrl+Right Alt', name: 'RCRA', shift: ss.KVKS_RCTRL | ss.KVKS_RALT, vkeys: [vk.K_RCONTROL,vk.K_RALT]},
76
+ {desc: 'Shift+Left Ctrl+Left Alt', name: 'SLCLA', shift: ss.KVKS_SHIFT | ss.KVKS_LCTRL | ss.KVKS_LALT, vkeys: [vk.K_SHIFT, vk.K_LCONTROL,vk.K_LALT]},
77
+ {desc: 'Shift+Left Ctrl+Right Alt', name: 'SLCRA', shift: ss.KVKS_SHIFT | ss.KVKS_LCTRL | ss.KVKS_RALT, vkeys: [vk.K_SHIFT, vk.K_LCONTROL,vk.K_RALT]},
78
+ {desc: 'Shift+Right Ctrl+Left Alt', name: 'SRCLA', shift: ss.KVKS_SHIFT | ss.KVKS_RCTRL | ss.KVKS_LALT, vkeys: [vk.K_SHIFT, vk.K_RCONTROL,vk.K_LALT]},
79
+ {desc: 'Shift+Right Ctrl+Right Alt', name: 'SRCRA', shift: ss.KVKS_SHIFT | ss.KVKS_RCTRL | ss.KVKS_RALT, vkeys: [vk.K_SHIFT, vk.K_RCONTROL,vk.K_RALT]}, //16
80
+ ];