@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.
- package/build/src/consts/virtual-key-constants.d.ts +131 -0
- package/build/src/consts/virtual-key-constants.d.ts.map +1 -0
- package/build/src/consts/virtual-key-constants.js +245 -0
- package/build/src/consts/virtual-key-constants.js.map +1 -0
- package/build/src/import/techpreview/cldr_info.json +5 -0
- package/build/src/import/techpreview/keys-Latn-implied.xml +80 -0
- package/build/src/import/techpreview/keys-Zyyy-currency.xml +22 -0
- package/build/src/import/techpreview/keys-Zyyy-punctuation.xml +46 -0
- package/build/src/keyman-touch-layout/keyman-touch-layout-file-reader.d.ts +7 -0
- package/build/src/keyman-touch-layout/keyman-touch-layout-file-reader.d.ts.map +1 -0
- package/build/src/keyman-touch-layout/keyman-touch-layout-file-reader.js +74 -0
- package/build/src/keyman-touch-layout/keyman-touch-layout-file-reader.js.map +1 -0
- package/build/src/keyman-touch-layout/keyman-touch-layout-file-writer.d.ts +24 -0
- package/build/src/keyman-touch-layout/keyman-touch-layout-file-writer.d.ts.map +1 -0
- package/build/src/keyman-touch-layout/keyman-touch-layout-file-writer.js +75 -0
- package/build/src/keyman-touch-layout/keyman-touch-layout-file-writer.js.map +1 -0
- package/build/src/keyman-touch-layout/keyman-touch-layout-file.d.ts +76 -0
- package/build/src/keyman-touch-layout/keyman-touch-layout-file.d.ts.map +1 -0
- package/build/src/keyman-touch-layout/keyman-touch-layout-file.js +26 -0
- package/build/src/keyman-touch-layout/keyman-touch-layout-file.js.map +1 -0
- package/build/src/keyman-touch-layout.clean.spec.json +170 -0
- package/build/src/kmx/element-string.d.ts +19 -0
- package/build/src/kmx/element-string.d.ts.map +1 -0
- package/build/src/kmx/element-string.js +72 -0
- package/build/src/kmx/element-string.js.map +1 -0
- package/build/src/kmx/kmx-builder.d.ts +77 -0
- package/build/src/kmx/kmx-builder.d.ts.map +1 -0
- package/build/src/kmx/kmx-builder.js +193 -0
- package/build/src/kmx/kmx-builder.js.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-disp.d.ts +18 -0
- package/build/src/kmx/kmx-plus-builder/build-disp.d.ts.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-disp.js +25 -0
- package/build/src/kmx/kmx-plus-builder/build-disp.js.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-elem.d.ts +26 -0
- package/build/src/kmx/kmx-plus-builder/build-elem.d.ts.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-elem.js +78 -0
- package/build/src/kmx/kmx-plus-builder/build-elem.js.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-keys.d.ts +60 -0
- package/build/src/kmx/kmx-plus-builder/build-keys.d.ts.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-keys.js +107 -0
- package/build/src/kmx/kmx-plus-builder/build-keys.js.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-layr.d.ts +54 -0
- package/build/src/kmx/kmx-plus-builder/build-layr.d.ts.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-layr.js +99 -0
- package/build/src/kmx/kmx-plus-builder/build-layr.js.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-list.d.ts +34 -0
- package/build/src/kmx/kmx-plus-builder/build-list.d.ts.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-list.js +62 -0
- package/build/src/kmx/kmx-plus-builder/build-list.js.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-loca.d.ts +12 -0
- package/build/src/kmx/kmx-plus-builder/build-loca.d.ts.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-loca.js +20 -0
- package/build/src/kmx/kmx-plus-builder/build-loca.js.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-meta.d.ts +17 -0
- package/build/src/kmx/kmx-plus-builder/build-meta.d.ts.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-meta.js +21 -0
- package/build/src/kmx/kmx-plus-builder/build-meta.js.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-name.d.ts +12 -0
- package/build/src/kmx/kmx-plus-builder/build-name.d.ts.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-name.js +23 -0
- package/build/src/kmx/kmx-plus-builder/build-name.js.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-ordr.d.ts +18 -0
- package/build/src/kmx/kmx-plus-builder/build-ordr.d.ts.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-ordr.js +27 -0
- package/build/src/kmx/kmx-plus-builder/build-ordr.js.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-sect.d.ts +16 -0
- package/build/src/kmx/kmx-plus-builder/build-sect.d.ts.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-sect.js +14 -0
- package/build/src/kmx/kmx-plus-builder/build-sect.js.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-strs.d.ts +18 -0
- package/build/src/kmx/kmx-plus-builder/build-strs.d.ts.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-strs.js +34 -0
- package/build/src/kmx/kmx-plus-builder/build-strs.js.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-tran.d.ts +20 -0
- package/build/src/kmx/kmx-plus-builder/build-tran.d.ts.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-tran.js +30 -0
- package/build/src/kmx/kmx-plus-builder/build-tran.js.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-vkey.d.ts +16 -0
- package/build/src/kmx/kmx-plus-builder/build-vkey.d.ts.map +1 -0
- package/build/src/kmx/kmx-plus-builder/build-vkey.js +23 -0
- package/build/src/kmx/kmx-plus-builder/build-vkey.js.map +1 -0
- package/build/src/kmx/kmx-plus-builder/builder-section.d.ts +6 -0
- package/build/src/kmx/kmx-plus-builder/builder-section.d.ts.map +1 -0
- package/build/src/kmx/kmx-plus-builder/builder-section.js +3 -0
- package/build/src/kmx/kmx-plus-builder/builder-section.js.map +1 -0
- package/build/src/kmx/kmx-plus-builder/kmx-plus-builder.d.ts +47 -0
- package/build/src/kmx/kmx-plus-builder/kmx-plus-builder.d.ts.map +1 -0
- package/build/src/kmx/kmx-plus-builder/kmx-plus-builder.js +143 -0
- package/build/src/kmx/kmx-plus-builder/kmx-plus-builder.js.map +1 -0
- package/build/src/kmx/kmx-plus.d.ts +259 -0
- package/build/src/kmx/kmx-plus.d.ts.map +1 -0
- package/build/src/kmx/kmx-plus.js +594 -0
- package/build/src/kmx/kmx-plus.js.map +1 -0
- package/build/src/kmx/kmx.d.ts +166 -0
- package/build/src/kmx/kmx.d.ts.map +1 -0
- package/build/src/kmx/kmx.js +271 -0
- package/build/src/kmx/kmx.js.map +1 -0
- package/build/src/kmx/string-list.d.ts +29 -0
- package/build/src/kmx/string-list.d.ts.map +1 -0
- package/build/src/kmx/string-list.js +75 -0
- package/build/src/kmx/string-list.js.map +1 -0
- package/build/src/kpj/keyman-developer-project.d.ts +58 -0
- package/build/src/kpj/keyman-developer-project.d.ts.map +1 -0
- package/build/src/kpj/keyman-developer-project.js +141 -0
- package/build/src/kpj/keyman-developer-project.js.map +1 -0
- package/build/src/kpj/kpj-file-reader.d.ts +17 -0
- package/build/src/kpj/kpj-file-reader.d.ts.map +1 -0
- package/build/src/kpj/kpj-file-reader.js +92 -0
- package/build/src/kpj/kpj-file-reader.js.map +1 -0
- package/build/src/kpj/kpj-file.d.ts +39 -0
- package/build/src/kpj/kpj-file.d.ts.map +1 -0
- package/build/src/kpj/kpj-file.js +11 -0
- package/build/src/kpj/kpj-file.js.map +1 -0
- package/build/src/kpj.schema.json +127 -0
- package/build/src/kvk/kvk-file-reader.d.ts +5 -0
- package/build/src/kvk/kvk-file-reader.d.ts.map +1 -0
- package/build/src/kvk/kvk-file-reader.js +35 -0
- package/build/src/kvk/kvk-file-reader.js.map +1 -0
- package/build/src/kvk/kvk-file-writer.d.ts +20 -0
- package/build/src/kvk/kvk-file-writer.d.ts.map +1 -0
- package/build/src/kvk/kvk-file-writer.js +67 -0
- package/build/src/kvk/kvk-file-writer.js.map +1 -0
- package/build/src/kvk/kvk-file.d.ts +64 -0
- package/build/src/kvk/kvk-file.d.ts.map +1 -0
- package/build/src/kvk/kvk-file.js +63 -0
- package/build/src/kvk/kvk-file.js.map +1 -0
- package/build/src/kvk/kvks-file-reader.d.ts +30 -0
- package/build/src/kvk/kvks-file-reader.d.ts.map +1 -0
- package/build/src/kvk/kvks-file-reader.js +154 -0
- package/build/src/kvk/kvks-file-reader.js.map +1 -0
- package/build/src/kvk/kvks-file-writer.d.ts +6 -0
- package/build/src/kvk/kvks-file-writer.d.ts.map +1 -0
- package/build/src/kvk/kvks-file-writer.js +99 -0
- package/build/src/kvk/kvks-file-writer.js.map +1 -0
- package/build/src/kvk/kvks-file.d.ts +44 -0
- package/build/src/kvk/kvks-file.d.ts.map +1 -0
- package/build/src/kvk/kvks-file.js +10 -0
- package/build/src/kvk/kvks-file.js.map +1 -0
- package/build/src/kvk/visual-keyboard.d.ts +35 -0
- package/build/src/kvk/visual-keyboard.d.ts.map +1 -0
- package/build/src/kvk/visual-keyboard.js +61 -0
- package/build/src/kvk/visual-keyboard.js.map +1 -0
- package/build/src/kvks.schema.json +182 -0
- package/build/src/ldml-keyboard/ldml-keyboard-testdata-xml.d.ts +56 -0
- package/build/src/ldml-keyboard/ldml-keyboard-testdata-xml.d.ts.map +1 -0
- package/build/src/ldml-keyboard/ldml-keyboard-testdata-xml.js +20 -0
- package/build/src/ldml-keyboard/ldml-keyboard-testdata-xml.js.map +1 -0
- package/build/src/ldml-keyboard/ldml-keyboard-xml-reader.d.ts +91 -0
- package/build/src/ldml-keyboard/ldml-keyboard-xml-reader.d.ts.map +1 -0
- package/build/src/ldml-keyboard/ldml-keyboard-xml-reader.js +370 -0
- package/build/src/ldml-keyboard/ldml-keyboard-xml-reader.js.map +1 -0
- package/build/src/ldml-keyboard/ldml-keyboard-xml.d.ts +143 -0
- package/build/src/ldml-keyboard/ldml-keyboard-xml.d.ts.map +1 -0
- package/build/src/ldml-keyboard/ldml-keyboard-xml.js +34 -0
- package/build/src/ldml-keyboard/ldml-keyboard-xml.js.map +1 -0
- package/build/src/ldml-keyboard.schema.json +634 -0
- package/build/src/ldml-keyboardtest.schema.json +221 -0
- package/build/src/main.d.ts +21 -0
- package/build/src/main.d.ts.map +1 -0
- package/build/src/main.js +20 -0
- package/build/src/main.js.map +1 -0
- package/build/src/util/common-events.d.ts +49 -0
- package/build/src/util/common-events.d.ts.map +1 -0
- package/build/src/util/common-events.js +29 -0
- package/build/src/util/common-events.js.map +1 -0
- package/build/src/util/compiler-interfaces.d.ts +51 -0
- package/build/src/util/compiler-interfaces.d.ts.map +1 -0
- package/build/src/util/compiler-interfaces.js +33 -0
- package/build/src/util/compiler-interfaces.js.map +1 -0
- package/build/src/util/util.d.ts +17 -0
- package/build/src/util/util.d.ts.map +1 -0
- package/build/src/util/util.js +67 -0
- package/build/src/util/util.js.map +1 -0
- package/build/tsconfig.tsbuildinfo +1 -0
- package/build.sh +86 -0
- package/package.json +58 -0
- package/src/consts/virtual-key-constants.ts +257 -0
- package/src/keyman-touch-layout/keyman-touch-layout-file-reader.ts +81 -0
- package/src/keyman-touch-layout/keyman-touch-layout-file-writer.ts +84 -0
- package/src/keyman-touch-layout/keyman-touch-layout-file.ts +87 -0
- package/src/kmx/element-string.ts +79 -0
- package/src/kmx/kmx-builder.ts +287 -0
- package/src/kmx/kmx-plus-builder/build-disp.ts +46 -0
- package/src/kmx/kmx-plus-builder/build-elem.ts +103 -0
- package/src/kmx/kmx-plus-builder/build-keys.ts +175 -0
- package/src/kmx/kmx-plus-builder/build-layr.ts +154 -0
- package/src/kmx/kmx-plus-builder/build-list.ts +95 -0
- package/src/kmx/kmx-plus-builder/build-loca.ts +34 -0
- package/src/kmx/kmx-plus-builder/build-meta.ts +37 -0
- package/src/kmx/kmx-plus-builder/build-name.ts +37 -0
- package/src/kmx/kmx-plus-builder/build-ordr.ts +45 -0
- package/src/kmx/kmx-plus-builder/build-sect.ts +31 -0
- package/src/kmx/kmx-plus-builder/build-strs.ts +58 -0
- package/src/kmx/kmx-plus-builder/build-tran.ts +50 -0
- package/src/kmx/kmx-plus-builder/build-vkey.ts +43 -0
- package/src/kmx/kmx-plus-builder/builder-section.ts +6 -0
- package/src/kmx/kmx-plus-builder/kmx-plus-builder.ts +190 -0
- package/src/kmx/kmx-plus.ts +692 -0
- package/src/kmx/kmx.ts +360 -0
- package/src/kmx/string-list.ts +74 -0
- package/src/kpj/keyman-developer-project.ts +155 -0
- package/src/kpj/kpj-file-reader.ts +103 -0
- package/src/kpj/kpj-file.ts +52 -0
- package/src/kvk/kvk-file-reader.ts +34 -0
- package/src/kvk/kvk-file-writer.ts +72 -0
- package/src/kvk/kvk-file.ts +122 -0
- package/src/kvk/kvks-file-reader.ts +164 -0
- package/src/kvk/kvks-file-writer.ts +113 -0
- package/src/kvk/kvks-file.ts +53 -0
- package/src/kvk/visual-keyboard.ts +80 -0
- package/src/ldml-keyboard/ldml-keyboard-testdata-xml.ts +74 -0
- package/src/ldml-keyboard/ldml-keyboard-xml-reader.ts +387 -0
- package/src/ldml-keyboard/ldml-keyboard-xml.ts +177 -0
- package/src/main.ts +27 -0
- package/src/restructure.d.ts +2 -0
- package/src/util/common-events.ts +50 -0
- package/src/util/compiler-interfaces.ts +54 -0
- package/src/util/util.ts +68 -0
- package/test/fixtures/import-minimal.xml +8 -0
- package/test/fixtures/import-minimal1.xml +11 -0
- package/test/fixtures/import-minimal2.xml +11 -0
- package/test/fixtures/import-symbols.xml +13 -0
- package/test/fixtures/invalid-conforms-to.xml +19 -0
- package/test/fixtures/invalid-import-base.xml +16 -0
- package/test/fixtures/invalid-import-path.xml +16 -0
- package/test/fixtures/invalid-import-readfail.xml +16 -0
- package/test/fixtures/invalid-import-wrongroot.xml +16 -0
- package/test/fixtures/invalid-structure-per-dtd.xml +8 -0
- package/test/fixtures/keyman-touch-layout/khmer_angkor.keyman-touch-layout +1950 -0
- package/test/fixtures/keyman-touch-layout/legacy.keyman-touch-layout +36 -0
- package/test/fixtures/kpj/khmer_angkor.kpj +187 -0
- package/test/fixtures/kvk/khmer_angkor.kvk +0 -0
- package/test/fixtures/kvk/khmer_angkor.kvks +206 -0
- package/test/fixtures/test-fr.xml +22 -0
- package/test/helpers/index.ts +39 -0
- package/test/helpers/reader-callback-test.ts +199 -0
- package/test/keyman-touch-layout/test-keyman-touch-layout-file-reader.ts +71 -0
- package/test/keyman-touch-layout/test-keyman-touch-layout-round-trip.ts +35 -0
- package/test/kpj/test-kpj-file-reader.ts +123 -0
- package/test/kvk/test-kvk-file.ts +15 -0
- package/test/kvk/test-kvk-round-trip.ts +87 -0
- package/test/kvk/test-kvk-utils.ts +24 -0
- package/test/kvk/test-kvks-file.ts +45 -0
- package/test/ldml-keyboard/test-ldml-keyboard-testdata-reader.ts +51 -0
- package/test/ldml-keyboard/test-ldml-keyboard-xml-reader.ts +131 -0
- package/test/tsconfig.json +21 -0
- package/test/util/test-unescape.ts +38 -0
- package/tsconfig.json +17 -0
package/src/kmx/kmx.ts
ADDED
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
import * as r from 'restructure';
|
|
2
|
+
|
|
3
|
+
/* Definitions from kmx_file.h. Must be kept in sync */
|
|
4
|
+
|
|
5
|
+
// TODO: split kmx-file from kmx in-memory, similar to what I've done for kvk (keep restructure decl + BUILDER_ interfaces together)
|
|
6
|
+
|
|
7
|
+
// In memory representations of KMX structures
|
|
8
|
+
// kmx-builder will transform these to the corresponding COMP_xxxx
|
|
9
|
+
|
|
10
|
+
export class KEYBOARD {
|
|
11
|
+
//TODO: additional header fields
|
|
12
|
+
groups: GROUP[];
|
|
13
|
+
stores: STORE[];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export class STORE {
|
|
17
|
+
dwSystemID: number;
|
|
18
|
+
dpName: string;
|
|
19
|
+
dpString: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export class GROUP {
|
|
23
|
+
dpName: string;
|
|
24
|
+
keys: KEY[];
|
|
25
|
+
dpMatch: string;
|
|
26
|
+
dpNoMatch: string;
|
|
27
|
+
fUsingKeys: boolean;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export class KEY {
|
|
31
|
+
Key: number;
|
|
32
|
+
Line: number;
|
|
33
|
+
ShiftFlags: number;
|
|
34
|
+
dpOutput: string;
|
|
35
|
+
dpContext: string;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
export class KMXFile {
|
|
40
|
+
|
|
41
|
+
/* KMX file structures */
|
|
42
|
+
|
|
43
|
+
public readonly COMP_STORE: any;
|
|
44
|
+
public readonly COMP_KEY: any;
|
|
45
|
+
public readonly COMP_GROUP: any;
|
|
46
|
+
public readonly COMP_KEYBOARD_KMXPLUSINFO: any;
|
|
47
|
+
public readonly COMP_KEYBOARD: any;
|
|
48
|
+
|
|
49
|
+
public static readonly FILEID_COMPILED = 0x5354584B; // 'KXTS'
|
|
50
|
+
|
|
51
|
+
//
|
|
52
|
+
// File version identifiers (COMP_KEYBOARD.dwFileVersion)
|
|
53
|
+
//
|
|
54
|
+
|
|
55
|
+
public static readonly VERSION_30 = 0x00000300;
|
|
56
|
+
public static readonly VERSION_31 = 0x00000301;
|
|
57
|
+
public static readonly VERSION_32 = 0x00000302;
|
|
58
|
+
public static readonly VERSION_40 = 0x00000400;
|
|
59
|
+
public static readonly VERSION_50 = 0x00000500;
|
|
60
|
+
public static readonly VERSION_501 = 0x00000501;
|
|
61
|
+
public static readonly VERSION_60 = 0x00000600;
|
|
62
|
+
public static readonly VERSION_70 = 0x00000700;
|
|
63
|
+
public static readonly VERSION_80 = 0x00000800;
|
|
64
|
+
public static readonly VERSION_90 = 0x00000900;
|
|
65
|
+
public static readonly VERSION_100 = 0x00000A00;
|
|
66
|
+
public static readonly VERSION_140 = 0x00000E00;
|
|
67
|
+
public static readonly VERSION_150 = 0x00000F00;
|
|
68
|
+
|
|
69
|
+
public static readonly VERSION_160 = 0x00001000;
|
|
70
|
+
|
|
71
|
+
public static readonly VERSION_MIN = this.VERSION_50;
|
|
72
|
+
public static readonly VERSION_MAX = this.VERSION_160;
|
|
73
|
+
|
|
74
|
+
//
|
|
75
|
+
// Backspace types
|
|
76
|
+
//
|
|
77
|
+
|
|
78
|
+
public static readonly BK_DEFAULT = 0;
|
|
79
|
+
public static readonly BK_DEADKEY = 1;
|
|
80
|
+
|
|
81
|
+
// Different begin types (COMP_STORE.StartGroup_*)
|
|
82
|
+
|
|
83
|
+
public static readonly BEGIN_ANSI = 0;
|
|
84
|
+
public static readonly BEGIN_UNICODE = 1;
|
|
85
|
+
|
|
86
|
+
//
|
|
87
|
+
// System Store values (COMP_STORE.dwSystemID)
|
|
88
|
+
//
|
|
89
|
+
|
|
90
|
+
public static readonly TSS_NONE = 0;
|
|
91
|
+
public static readonly TSS_BITMAP = 1;
|
|
92
|
+
public static readonly TSS_COPYRIGHT = 2;
|
|
93
|
+
public static readonly TSS_HOTKEY = 3;
|
|
94
|
+
public static readonly TSS_LANGUAGE = 4;
|
|
95
|
+
public static readonly TSS_LAYOUT = 5;
|
|
96
|
+
public static readonly TSS_MESSAGE = 6;
|
|
97
|
+
public static readonly TSS_NAME = 7;
|
|
98
|
+
public static readonly TSS_VERSION = 8;
|
|
99
|
+
public static readonly TSS_CAPSONONLY = 9;
|
|
100
|
+
public static readonly TSS_CAPSALWAYSOFF = 10;
|
|
101
|
+
public static readonly TSS_SHIFTFREESCAPS = 11;
|
|
102
|
+
public static readonly TSS_LANGUAGENAME = 12;
|
|
103
|
+
|
|
104
|
+
public static readonly TSS_CALLDEFINITION = 13;
|
|
105
|
+
public static readonly TSS_CALLDEFINITION_LOADFAILED = 14;
|
|
106
|
+
|
|
107
|
+
public static readonly TSS_ETHNOLOGUECODE = 15;
|
|
108
|
+
|
|
109
|
+
public static readonly TSS_DEBUG_LINE = 16;
|
|
110
|
+
|
|
111
|
+
public static readonly TSS_MNEMONIC = 17;
|
|
112
|
+
|
|
113
|
+
public static readonly TSS_INCLUDECODES = 18;
|
|
114
|
+
|
|
115
|
+
public static readonly TSS_OLDCHARPOSMATCHING = 19;
|
|
116
|
+
|
|
117
|
+
public static readonly TSS_COMPILEDVERSION = 20;
|
|
118
|
+
public static readonly TSS_KEYMANCOPYRIGHT = 21;
|
|
119
|
+
|
|
120
|
+
public static readonly TSS_CUSTOMKEYMANEDITION = 22;
|
|
121
|
+
public static readonly TSS_CUSTOMKEYMANEDITIONNAME = 23;
|
|
122
|
+
|
|
123
|
+
/* Keyman 7.0 system stores */
|
|
124
|
+
|
|
125
|
+
public static readonly TSS__KEYMAN_60_MAX = 23;
|
|
126
|
+
|
|
127
|
+
public static readonly TSS_VISUALKEYBOARD = 24;
|
|
128
|
+
public static readonly TSS_KMW_RTL = 25;
|
|
129
|
+
public static readonly TSS_KMW_HELPFILE = 26;
|
|
130
|
+
public static readonly TSS_KMW_HELPTEXT = 27;
|
|
131
|
+
public static readonly TSS_KMW_EMBEDJS = 28;
|
|
132
|
+
|
|
133
|
+
public static readonly TSS_WINDOWSLANGUAGES = 29;
|
|
134
|
+
|
|
135
|
+
public static readonly TSS__KEYMAN_70_MAX = 29;
|
|
136
|
+
|
|
137
|
+
/* Keyman 8.0 system stores */
|
|
138
|
+
|
|
139
|
+
public static readonly TSS_COMPARISON = 30;
|
|
140
|
+
|
|
141
|
+
public static readonly TSS__KEYMAN_80_MAX = 30;
|
|
142
|
+
|
|
143
|
+
/* Keyman 9.0 system stores */
|
|
144
|
+
|
|
145
|
+
public static readonly TSS_PLATFORM = 31;
|
|
146
|
+
public static readonly TSS_BASELAYOUT = 32;
|
|
147
|
+
public static readonly TSS_LAYER = 33;
|
|
148
|
+
|
|
149
|
+
public static readonly TSS_PLATFORM_NOMATCH = 0x8001; // Reserved for internal use - after platform statement is run, set to either TSS_PLATFORM_NOMATCH or TSS_PLATFORM_MATCH
|
|
150
|
+
public static readonly TSS_PLATFORM_MATCH = 0x8002; // Reserved for internal use - as the result will never change for the lifetime of the process.
|
|
151
|
+
|
|
152
|
+
public static readonly TSS_VKDICTIONARY = 34; // Dictionary of virtual key names for v9 dynamic layouts
|
|
153
|
+
public static readonly TSS_LAYOUTFILE = 35; // Keyman 9 layer-based JSON OSK
|
|
154
|
+
public static readonly TSS_KEYBOARDVERSION = 36; // &keyboardversion system store // I4140
|
|
155
|
+
public static readonly TSS_KMW_EMBEDCSS = 37;
|
|
156
|
+
|
|
157
|
+
public static readonly TSS_TARGETS = 38;
|
|
158
|
+
|
|
159
|
+
public static readonly TSS__KEYMAN_90_MAX = 38;
|
|
160
|
+
|
|
161
|
+
/* Keyman 14.0 system stores */
|
|
162
|
+
|
|
163
|
+
public static readonly TSS_CASEDKEYS = 39;
|
|
164
|
+
|
|
165
|
+
public static readonly TSS__KEYMAN_140_MAX = 39;
|
|
166
|
+
|
|
167
|
+
/* Keyman 15.0 system stores */
|
|
168
|
+
|
|
169
|
+
public static readonly TSS_BEGIN_NEWCONTEXT = 40;
|
|
170
|
+
public static readonly TSS_BEGIN_POSTKEYSTROKE = 41;
|
|
171
|
+
public static readonly TSS_NEWLAYER = 42;
|
|
172
|
+
public static readonly TSS_OLDLAYER = 43;
|
|
173
|
+
|
|
174
|
+
public static readonly TSS__KEYMAN_150_MAX = 43;
|
|
175
|
+
|
|
176
|
+
public static readonly TSS__MAX = 43;
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
public static readonly UC_SENTINEL = 0xFFFF;
|
|
180
|
+
public static readonly UC_SENTINEL_EXTENDEDEND = 0x10;
|
|
181
|
+
|
|
182
|
+
public static readonly U_UC_SENTINEL = "\uFFFF";
|
|
183
|
+
|
|
184
|
+
//
|
|
185
|
+
// VK__MAX defines the highest virtual key code defined in the system = 0xFF. Custom VK codes start at 256
|
|
186
|
+
//
|
|
187
|
+
|
|
188
|
+
public static readonly VK__MAX = 255;
|
|
189
|
+
|
|
190
|
+
//
|
|
191
|
+
// Extended String CODE_ values
|
|
192
|
+
//
|
|
193
|
+
|
|
194
|
+
public static readonly CODE_ANY = 0x01;
|
|
195
|
+
public static readonly CODE_INDEX = 0x02;
|
|
196
|
+
public static readonly CODE_CONTEXT = 0x03;
|
|
197
|
+
public static readonly CODE_NUL = 0x04;
|
|
198
|
+
public static readonly CODE_USE = 0x05;
|
|
199
|
+
public static readonly CODE_RETURN = 0x06;
|
|
200
|
+
public static readonly CODE_BEEP = 0x07;
|
|
201
|
+
public static readonly CODE_DEADKEY = 0x08;
|
|
202
|
+
// 0x09 = bkspace.-- we don't need to keep this separate though with UC_SENTINEL
|
|
203
|
+
public static readonly CODE_EXTENDED = 0x0A;
|
|
204
|
+
//public static readonly CODE_EXTENDEDEND = 0x0B; deprecated
|
|
205
|
+
public static readonly CODE_SWITCH = 0x0C;
|
|
206
|
+
public static readonly CODE_KEY = 0x0D;
|
|
207
|
+
public static readonly CODE_CLEARCONTEXT = 0x0E;
|
|
208
|
+
public static readonly CODE_CALL = 0x0F;
|
|
209
|
+
// UC_SENTINEL_EXTENDEDEND 0x10
|
|
210
|
+
public static readonly CODE_CONTEXTEX = 0x11;
|
|
211
|
+
|
|
212
|
+
public static readonly CODE_NOTANY = 0x12;
|
|
213
|
+
|
|
214
|
+
public static readonly CODE_KEYMAN70_LASTCODE = 0x12;
|
|
215
|
+
|
|
216
|
+
public static readonly CODE_SETOPT = 0x13;
|
|
217
|
+
public static readonly CODE_IFOPT = 0x14;
|
|
218
|
+
public static readonly CODE_SAVEOPT = 0x15;
|
|
219
|
+
public static readonly CODE_RESETOPT = 0x16;
|
|
220
|
+
|
|
221
|
+
public static readonly CODE_KEYMAN80_LASTCODE = 0x16;
|
|
222
|
+
|
|
223
|
+
/* Keyman 9.0 codes */
|
|
224
|
+
|
|
225
|
+
public static readonly CODE_IFSYSTEMSTORE = 0x17;
|
|
226
|
+
public static readonly CODE_SETSYSTEMSTORE = 0x18;
|
|
227
|
+
|
|
228
|
+
public static readonly CODE_LASTCODE = 0x18;
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
public static readonly KF_SHIFTFREESCAPS = 0x0001;
|
|
232
|
+
public static readonly KF_CAPSONONLY = 0x0002;
|
|
233
|
+
public static readonly KF_CAPSALWAYSOFF = 0x0004;
|
|
234
|
+
public static readonly KF_LOGICALLAYOUT = 0x0008;
|
|
235
|
+
public static readonly KF_AUTOMATICVERSION = 0x0010;
|
|
236
|
+
|
|
237
|
+
// 16.0: Support for LDML Keyboards in KMXPlus file format
|
|
238
|
+
public static readonly KF_KMXPLUS = 0x0020;
|
|
239
|
+
|
|
240
|
+
public static readonly HK_ALT = 0x00010000;
|
|
241
|
+
public static readonly HK_CTRL = 0x00020000;
|
|
242
|
+
public static readonly HK_SHIFT = 0x00040000;
|
|
243
|
+
|
|
244
|
+
public static readonly LCTRLFLAG = 0x0001; // Left Control flag
|
|
245
|
+
public static readonly RCTRLFLAG = 0x0002; // Right Control flag
|
|
246
|
+
public static readonly LALTFLAG = 0x0004; // Left Alt flag
|
|
247
|
+
public static readonly RALTFLAG = 0x0008; // Right Alt flag
|
|
248
|
+
public static readonly K_SHIFTFLAG = 0x0010; // Either shift flag
|
|
249
|
+
public static readonly K_CTRLFLAG = 0x0020; // Either ctrl flag
|
|
250
|
+
public static readonly K_ALTFLAG = 0x0040; // Either alt flag
|
|
251
|
+
//public static readonly K_METAFLAG = 0x0080; // Either Meta-key flag (tentative). Not usable in keyboard rules;
|
|
252
|
+
// Used internally (currently, only by KMW) to ensure Meta-key
|
|
253
|
+
// shortcuts safely bypass rules
|
|
254
|
+
// Meta key = Command key on macOS, Windows key on Windows
|
|
255
|
+
public static readonly CAPITALFLAG = 0x0100; // Caps lock on
|
|
256
|
+
public static readonly NOTCAPITALFLAG = 0x0200; // Caps lock NOT on
|
|
257
|
+
public static readonly NUMLOCKFLAG = 0x0400; // Num lock on
|
|
258
|
+
public static readonly NOTNUMLOCKFLAG = 0x0800; // Num lock NOT on
|
|
259
|
+
public static readonly SCROLLFLAG = 0x1000; // Scroll lock on
|
|
260
|
+
public static readonly NOTSCROLLFLAG = 0x2000; // Scroll lock NOT on
|
|
261
|
+
public static readonly ISVIRTUALKEY = 0x4000; // It is a Virtual Key Sequence
|
|
262
|
+
public static readonly VIRTUALCHARKEY = 0x8000; // Keyman 6.0: Virtual Key Cap Sequence NOT YET
|
|
263
|
+
|
|
264
|
+
public static readonly K_MODIFIERFLAG = 0x007F;
|
|
265
|
+
public static readonly K_NOTMODIFIERFLAG = 0xFF00; // I4548
|
|
266
|
+
|
|
267
|
+
public static readonly COMP_KEYBOARD_SIZE = 64;
|
|
268
|
+
public static readonly COMP_KEYBOARD_KMXPLUSINFO_SIZE = 8;
|
|
269
|
+
public static readonly COMP_STORE_SIZE = 12;
|
|
270
|
+
public static readonly COMP_GROUP_SIZE = 24;
|
|
271
|
+
public static readonly COMP_KEY_SIZE = 20;
|
|
272
|
+
|
|
273
|
+
/* In-memory representation of the keyboard */
|
|
274
|
+
|
|
275
|
+
public keyboard: KEYBOARD = {
|
|
276
|
+
groups: [],
|
|
277
|
+
stores: []
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
constructor() {
|
|
281
|
+
|
|
282
|
+
// Binary-correct structures matching kmx_file.h
|
|
283
|
+
|
|
284
|
+
this.COMP_STORE = new r.Struct({
|
|
285
|
+
dwSystemID: r.uint32le,
|
|
286
|
+
dpName: r.uint32le,
|
|
287
|
+
dpString: r.uint32le
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
if(this.COMP_STORE.size() != KMXFile.COMP_STORE_SIZE) {
|
|
291
|
+
throw "COMP_STORE size is "+this.COMP_STORE.size()+" but should be "+KMXFile.COMP_STORE_SIZE+" bytes";
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
this.COMP_KEY = new r.Struct({
|
|
295
|
+
Key: r.uint16le,
|
|
296
|
+
_padding: new r.Reserved(r.uint16le), // padding
|
|
297
|
+
Line: r.uint32le,
|
|
298
|
+
ShiftFlags: r.uint32le,
|
|
299
|
+
dpOutput: r.uint32le,
|
|
300
|
+
dpContext: r.uint32le
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
if(this.COMP_KEY.size() != KMXFile.COMP_KEY_SIZE) {
|
|
304
|
+
throw "COMP_KEY size is "+this.COMP_KEY.size()+" but should be "+KMXFile.COMP_KEY_SIZE+" bytes";
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
this.COMP_GROUP = new r.Struct({
|
|
308
|
+
dpName: r.uint32le,
|
|
309
|
+
dpKeyArray: r.uint32le, // [LPKEY] address of first item in key array
|
|
310
|
+
dpMatch: r.uint32le,
|
|
311
|
+
dpNoMatch: r.uint32le,
|
|
312
|
+
cxKeyArray: r.uint32le, // in array entries
|
|
313
|
+
fUsingKeys: r.uint32le // group(xx) [using keys] <-- specified or not
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
if(this.COMP_GROUP.size() != KMXFile.COMP_GROUP_SIZE) {
|
|
317
|
+
throw "COMP_GROUP size is "+this.COMP_GROUP.size()+" but should be "+KMXFile.COMP_GROUP_SIZE+" bytes";
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
this.COMP_KEYBOARD_KMXPLUSINFO = new r.Struct({
|
|
321
|
+
dpKMXPlus: r.uint32le, // 0040 offset of KMXPlus data, <sect> header is first
|
|
322
|
+
dwKMXPlusSize: r.uint32le // 0044 size in bytes of entire KMXPlus data
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
if(this.COMP_KEYBOARD_KMXPLUSINFO.size() != KMXFile.COMP_KEYBOARD_KMXPLUSINFO_SIZE) {
|
|
326
|
+
throw "COMP_KEYBOARD_KMXPLUSINFO size is "+this.COMP_KEYBOARD_KMXPLUSINFO.size()+" but should be "+KMXFile.COMP_KEYBOARD_KMXPLUSINFO_SIZE+" bytes";
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
this.COMP_KEYBOARD = new r.Struct({
|
|
330
|
+
dwIdentifier: r.uint32le, // 0000 Keyman compiled keyboard id
|
|
331
|
+
|
|
332
|
+
dwFileVersion: r.uint32le, // 0004 Version of the file - Keyman 4.0 is 0x0400
|
|
333
|
+
|
|
334
|
+
dwCheckSum: r.uint32le, // 0008 As stored in keyboard
|
|
335
|
+
KeyboardID: r.uint32le, // 000C as stored in HKEY_LOCAL_MACHINE//system//currentcontrolset//control//keyboard layouts
|
|
336
|
+
IsRegistered: r.uint32le, // 0010
|
|
337
|
+
version: r.uint32le, // 0014 keyboard version
|
|
338
|
+
|
|
339
|
+
cxStoreArray: r.uint32le, // 0018 in array entries
|
|
340
|
+
cxGroupArray: r.uint32le, // 001C in array entries
|
|
341
|
+
|
|
342
|
+
dpStoreArray: r.uint32le, // 0020 [LPSTORE] address of first item in store array
|
|
343
|
+
dpGroupArray: r.uint32le, // 0024 [LPGROUP] address of first item in group array
|
|
344
|
+
|
|
345
|
+
StartGroup_ANSI: r.uint32le, // 0028 index of starting ANSI group
|
|
346
|
+
StartGroup_Unicode: r.uint32le, // 0028 index of starting Unicode groups
|
|
347
|
+
|
|
348
|
+
dwFlags: r.uint32le, // 0030 Flags for the keyboard file
|
|
349
|
+
|
|
350
|
+
dwHotKey: r.uint32le, // 0034 standard windows hotkey (hiword=shift/ctrl/alt stuff, loword=vkey)
|
|
351
|
+
|
|
352
|
+
dpBitmapOffset: r.uint32le, // 0038 offset of the bitmaps in the file
|
|
353
|
+
dwBitmapSize: r.uint32le // 003C size in bytes of the bitmaps
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
if(this.COMP_KEYBOARD.size() != KMXFile.COMP_KEYBOARD_SIZE) {
|
|
357
|
+
throw "COMP_KEYBOARD size is "+this.COMP_KEYBOARD.size()+" but should be "+KMXFile.COMP_KEYBOARD_SIZE+" bytes";
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Strs, StrsItem } from './kmx-plus.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A single entry in a ListItem.
|
|
5
|
+
* Contains a StrsItem as its value.
|
|
6
|
+
*/
|
|
7
|
+
export class ListIndex {
|
|
8
|
+
readonly value: StrsItem; // will become index into Strs table
|
|
9
|
+
constructor(value: StrsItem) {
|
|
10
|
+
this.value = value;
|
|
11
|
+
}
|
|
12
|
+
isEqual(a: ListIndex | string) {
|
|
13
|
+
// so we can compare this to a string
|
|
14
|
+
return a.toString() === this.toString();
|
|
15
|
+
}
|
|
16
|
+
toString(): string {
|
|
17
|
+
return this.value.value;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A string list in memory. This will be replaced with an index
|
|
23
|
+
* into the string table at finalization.
|
|
24
|
+
*/
|
|
25
|
+
export class ListItem extends Array<ListIndex> {
|
|
26
|
+
/**
|
|
27
|
+
* Construct a new list from an array of strings.
|
|
28
|
+
* Use List. This is meant to be called by the List.allocString*() functions.
|
|
29
|
+
* @param strs the Strs section is needed to construct this object.
|
|
30
|
+
* @param source array of strings
|
|
31
|
+
* @returns
|
|
32
|
+
*/
|
|
33
|
+
constructor(strs: Strs, source: Array<string>) {
|
|
34
|
+
super();
|
|
35
|
+
if(!source) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
for (const str of source) {
|
|
40
|
+
let index = new ListIndex(strs.allocString(str));
|
|
41
|
+
this.push(index);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
isEqual(a: ListItem | string[]): boolean {
|
|
45
|
+
if (a.length != this.length) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
for (let i = 0; i < a.length; i++) {
|
|
49
|
+
if (!this[i].isEqual(a[i])) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
compareTo(o: ListItem): number {
|
|
56
|
+
for (let i = 0; i < Math.min(this.length, o.length); i++) {
|
|
57
|
+
const r = this[i].value.compareTo(o[i].value);
|
|
58
|
+
if (r !== 0) {
|
|
59
|
+
return r;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// prefix is the same, so go by length: shortest is first.
|
|
63
|
+
if (this.length < o.length) {
|
|
64
|
+
return -1;
|
|
65
|
+
} else if (this.length > o.length) {
|
|
66
|
+
return 1;
|
|
67
|
+
} else {
|
|
68
|
+
return 0;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
toString(): string {
|
|
72
|
+
return this.map(v => v.value.value).join(' ');
|
|
73
|
+
}
|
|
74
|
+
};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Version 1.0 of Keyman Developer Project .kpj file
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
|
|
8
|
+
export class KeymanDeveloperProject {
|
|
9
|
+
options: KeymanDeveloperProjectOptions;
|
|
10
|
+
files: KeymanDeveloperProjectFile[];
|
|
11
|
+
constructor(version: KeymanDeveloperProjectVersion) {
|
|
12
|
+
this.options = new KeymanDeveloperProjectOptions(version);
|
|
13
|
+
this.files = [];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Adds .kmn, .xml, .kps to project based on options.sourcePath
|
|
17
|
+
* @param projectPath Full path to project.kpj (even if the file doesn't exist)
|
|
18
|
+
*/
|
|
19
|
+
populateFiles(projectPath: string) {
|
|
20
|
+
if(this.options.version != '2.0') {
|
|
21
|
+
throw new Error('populateFiles can only be called on a v2.0 project');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let sourcePath = this.resolveProjectPath(projectPath, this.options.sourcePath);
|
|
25
|
+
let files = fs.readdirSync(sourcePath);
|
|
26
|
+
for(let filename of files) {
|
|
27
|
+
let fullPath = path.join(sourcePath, filename);
|
|
28
|
+
if(filename.match(/\.xml$/i)) {
|
|
29
|
+
if(!fs.readFileSync(fullPath, 'utf-8').match(/ldmlKeyboard\.dtd/)) {
|
|
30
|
+
// Skip this .xml because we assume it isn't really a keyboard .xml
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if(filename.match(/\.(kmn|kps|xml|model\.ts)$/i)) {
|
|
35
|
+
let file = new KeymanDeveloperProjectFile20(fullPath);
|
|
36
|
+
this.files.push(file);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
resolveProjectPath(projectPath: string, p: string): string {
|
|
42
|
+
// Replace placeholders in the target path
|
|
43
|
+
return p.replace('$PROJECTPATH', path.dirname(projectPath));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
resolveInputFilePath(projectPath: string, file: KeymanDeveloperProjectFile): string {
|
|
47
|
+
let p = path.dirname(projectPath);
|
|
48
|
+
return path.normalize(path.resolve(p, file.filePath));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
resolveOutputFilePath(projectPath: string, file: KeymanDeveloperProjectFile, sourceExt: string, targetExt: string): string {
|
|
52
|
+
// Roughly corresponds to Delphi TProject.GetTargetFileName
|
|
53
|
+
let p = this.options.version == '1.0' ?
|
|
54
|
+
this.options.buildPath || '$SOURCEPATH' :
|
|
55
|
+
this.options.buildPath;
|
|
56
|
+
|
|
57
|
+
// Replace placeholders in the target path
|
|
58
|
+
if(this.options.version == '1.0') {
|
|
59
|
+
// TODO: do we need to support $VERSION?
|
|
60
|
+
// $SOURCEPATH only supported in 1.0 projects
|
|
61
|
+
p = p.replace('$SOURCEPATH', path.dirname(this.resolveInputFilePath(projectPath, file)));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
p = this.resolveProjectPath(projectPath, p);
|
|
65
|
+
|
|
66
|
+
let f = file.filename.replace(new RegExp(`\\${sourceExt}$`, 'i'), targetExt);
|
|
67
|
+
return path.normalize(path.join(p, f));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export enum KeymanDeveloperProjectType {
|
|
73
|
+
Keyboard,
|
|
74
|
+
LexicalModel
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export type KeymanDeveloperProjectVersion =
|
|
78
|
+
"1.0" | // Keyman Developer <17.0: All files referenced in .kpj
|
|
79
|
+
"2.0"; // Keyman Developer 17.0+: Files in sub-folders implicitly included
|
|
80
|
+
|
|
81
|
+
export class KeymanDeveloperProjectOptions {
|
|
82
|
+
buildPath: string;
|
|
83
|
+
sourcePath: string;
|
|
84
|
+
compilerWarningsAsErrors: boolean = false;
|
|
85
|
+
warnDeprecatedCode: boolean = true;
|
|
86
|
+
checkFilenameConventions: boolean = true;
|
|
87
|
+
projectType: KeymanDeveloperProjectType = KeymanDeveloperProjectType.Keyboard;
|
|
88
|
+
readonly version: KeymanDeveloperProjectVersion;
|
|
89
|
+
constructor(version: KeymanDeveloperProjectVersion) {
|
|
90
|
+
this.version = version;
|
|
91
|
+
switch(version) {
|
|
92
|
+
case "1.0":
|
|
93
|
+
this.buildPath = '';
|
|
94
|
+
this.sourcePath = '';
|
|
95
|
+
break;
|
|
96
|
+
case "2.0":
|
|
97
|
+
this.buildPath = '$PROJECTPATH/build';
|
|
98
|
+
this.sourcePath = '$PROJECTPATH/source';
|
|
99
|
+
break;
|
|
100
|
+
default:
|
|
101
|
+
throw new Error('Invalid version');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export type KeymanDeveloperProjectFile = KeymanDeveloperProjectFile10 | KeymanDeveloperProjectFile20;
|
|
107
|
+
|
|
108
|
+
export class KeymanDeveloperProjectFile10 {
|
|
109
|
+
readonly id: string; // 1.0 only
|
|
110
|
+
readonly filename: string;
|
|
111
|
+
readonly filePath: string;
|
|
112
|
+
readonly fileVersion: string; // 1.0 only
|
|
113
|
+
readonly fileType: string; // file extension of filename, but .model.ts is technically not the ext because of 2 periods
|
|
114
|
+
details: KeymanDeveloperProjectFileDetail_Kmn & KeymanDeveloperProjectFileDetail_Kps; // 1.0 only
|
|
115
|
+
childFiles: KeymanDeveloperProjectFile[]; // 1.0 only
|
|
116
|
+
constructor(id: string, filename: string, filePath: string, fileVersion:string, fileType: string) {
|
|
117
|
+
this.details = {};
|
|
118
|
+
this.childFiles = [];
|
|
119
|
+
this.id = id;
|
|
120
|
+
this.filename = filename;
|
|
121
|
+
this.filePath = filePath;
|
|
122
|
+
this.fileVersion = fileVersion;
|
|
123
|
+
this.fileType = fileType;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export type KeymanDeveloperProjectFileType20 = '.model.ts' | '.kmn' | '.xml' | '.kps';
|
|
128
|
+
|
|
129
|
+
export class KeymanDeveloperProjectFile20 {
|
|
130
|
+
readonly filename: string;
|
|
131
|
+
readonly filePath: string;
|
|
132
|
+
readonly fileType: string; // file extension of filename, but .model.ts is technically not the ext because of 2 periods
|
|
133
|
+
constructor(filePath: string) {
|
|
134
|
+
this.filename = path.basename(filePath);
|
|
135
|
+
this.filePath = filePath;
|
|
136
|
+
if(this.filename.match(/\.model\.ts$/)) {
|
|
137
|
+
// .model.ts is a bit of a hassle...
|
|
138
|
+
this.fileType = '.model.ts';
|
|
139
|
+
} else {
|
|
140
|
+
this.fileType = path.extname(this.filename);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export class KeymanDeveloperProjectFileDetail_Kps {
|
|
146
|
+
name?: string;
|
|
147
|
+
copyright?: string;
|
|
148
|
+
version?: string;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
export class KeymanDeveloperProjectFileDetail_Kmn {
|
|
152
|
+
name?: string;
|
|
153
|
+
copyright?: string;
|
|
154
|
+
message?: string;
|
|
155
|
+
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import * as xml2js from 'xml2js';
|
|
2
|
+
import { KPJFile, KPJFileProject } from './kpj-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 { KeymanDeveloperProject, KeymanDeveloperProjectFile10, KeymanDeveloperProjectType } from './keyman-developer-project.js';
|
|
7
|
+
|
|
8
|
+
export class KPJFileReader {
|
|
9
|
+
public read(file: Uint8Array): KPJFile {
|
|
10
|
+
let data: KPJFile;
|
|
11
|
+
|
|
12
|
+
const parser = new xml2js.Parser({
|
|
13
|
+
explicitArray: false,
|
|
14
|
+
mergeAttrs: false,
|
|
15
|
+
includeWhiteChars: false,
|
|
16
|
+
normalize: false,
|
|
17
|
+
emptyTag: ''
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
parser.parseString(file, (e: unknown, r: unknown) => { data = r as KPJFile });
|
|
21
|
+
data = this.boxArrays(data);
|
|
22
|
+
return data as KPJFile;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public validate(source: KPJFile, schemaBuffer: Buffer): void {
|
|
26
|
+
const schema = JSON.parse(schemaBuffer.toString('utf8'));
|
|
27
|
+
const ajv = new Ajv();
|
|
28
|
+
if(!ajv.validate(schema, source)) {
|
|
29
|
+
throw new Error(ajv.errorsText());
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private boolFromString(value: string, def: boolean) {
|
|
34
|
+
value = (value || '').toLowerCase();
|
|
35
|
+
if(value === 'true') return true;
|
|
36
|
+
if(value === 'false') return false;
|
|
37
|
+
return def;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public transform(projectPath: string, source: KPJFile): KeymanDeveloperProject {
|
|
41
|
+
// NOTE: at this point, the xml should have been validated
|
|
42
|
+
// and matched the schema result so we can assume the source
|
|
43
|
+
// is a valid shape
|
|
44
|
+
let project = source.KeymanDeveloperProject;
|
|
45
|
+
let result: KeymanDeveloperProject = new KeymanDeveloperProject(project.Options?.Version || "1.0");
|
|
46
|
+
if(result.options.version == '2.0') {
|
|
47
|
+
result.options.buildPath = (project.Options?.BuildPath || result.options.buildPath).replace(/\\/g, '/');
|
|
48
|
+
result.options.sourcePath = (project.Options?.SourcePath || result.options.sourcePath).replace(/\\/g, '/');
|
|
49
|
+
} else {
|
|
50
|
+
result.options.buildPath = (project.Options?.BuildPath || '').replace(/\\/g, '/');
|
|
51
|
+
}
|
|
52
|
+
result.options.checkFilenameConventions = this.boolFromString(project.Options?.CheckFilenameConventions, true);
|
|
53
|
+
result.options.compilerWarningsAsErrors = this.boolFromString(project.Options?.CompilerWarningsAsErrors, false);
|
|
54
|
+
result.options.warnDeprecatedCode = this.boolFromString(project.Options?.WarnDeprecatedCode, true);
|
|
55
|
+
result.options.projectType =
|
|
56
|
+
project.Options?.ProjectType == 'keyboard' ? KeymanDeveloperProjectType.Keyboard :
|
|
57
|
+
project.Options?.ProjectType == 'lexicalmodel' ? KeymanDeveloperProjectType.LexicalModel :
|
|
58
|
+
KeymanDeveloperProjectType.Keyboard; // Default is keyboard if missing
|
|
59
|
+
|
|
60
|
+
if(result.options.version == '1.0') {
|
|
61
|
+
this.transformFilesVersion10(project, result);
|
|
62
|
+
} else {
|
|
63
|
+
result.populateFiles(projectPath);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private transformFilesVersion10(project: KPJFileProject, result: KeymanDeveloperProject) {
|
|
70
|
+
let ids: { [id: string]: KeymanDeveloperProjectFile10; } = {};
|
|
71
|
+
for (let sourceFile of project.Files?.File) {
|
|
72
|
+
let file: KeymanDeveloperProjectFile10 = new KeymanDeveloperProjectFile10(
|
|
73
|
+
sourceFile.ID || '',
|
|
74
|
+
sourceFile.Filename || '',
|
|
75
|
+
(sourceFile.Filepath || '').replace(/\\/g, '/'),
|
|
76
|
+
sourceFile.FileVersion || '',
|
|
77
|
+
sourceFile.FileType || ''
|
|
78
|
+
);
|
|
79
|
+
if (sourceFile.Details) {
|
|
80
|
+
file.details.copyright = sourceFile.Details.Copyright;
|
|
81
|
+
file.details.name = sourceFile.Details.Name;
|
|
82
|
+
file.details.message = sourceFile.Details.Message;
|
|
83
|
+
file.details.version = sourceFile.Details.Version;
|
|
84
|
+
}
|
|
85
|
+
if (sourceFile.ParentFileID && ids[sourceFile.ParentFileID]) {
|
|
86
|
+
ids[sourceFile.ParentFileID].childFiles.push(file);
|
|
87
|
+
} else {
|
|
88
|
+
result.files.push(file);
|
|
89
|
+
ids[file.id] = file;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* xml2js will not place single-entry objects into arrays.
|
|
96
|
+
* Easiest way to fix this is to box them ourselves as needed
|
|
97
|
+
* @param source KVKSourceFile
|
|
98
|
+
*/
|
|
99
|
+
private boxArrays(source: KPJFile) {
|
|
100
|
+
boxXmlArray(source.KeymanDeveloperProject?.Files, 'File');
|
|
101
|
+
return source;
|
|
102
|
+
}
|
|
103
|
+
}
|