@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
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { TouchLayoutFile, TouchLayoutPlatform, TouchLayoutKey, TouchLayoutSubKey } from "./keyman-touch-layout-file.js";
|
|
2
|
+
|
|
3
|
+
export interface TouchLayoutFileWriterOptions {
|
|
4
|
+
formatted?: boolean;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export class TouchLayoutFileWriter {
|
|
8
|
+
|
|
9
|
+
options: TouchLayoutFileWriterOptions;
|
|
10
|
+
|
|
11
|
+
constructor(options?: TouchLayoutFileWriterOptions) {
|
|
12
|
+
this.options = {...options};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Writes the touch layout to a .keyman-touch-layout JSON file
|
|
17
|
+
* @param source TouchLayoutFile
|
|
18
|
+
* @returns Uint8Array, the .keyman-touch-layout file
|
|
19
|
+
*/
|
|
20
|
+
write(source: TouchLayoutFile): Uint8Array {
|
|
21
|
+
const output = JSON.stringify(source, null, this.options?.formatted ? 2 : undefined);
|
|
22
|
+
const encoder = new TextEncoder();
|
|
23
|
+
return encoder.encode(output);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Compiles the touch layout file into a KeymanWeb-compatible JSON-style
|
|
28
|
+
* object string. In the future, this may be optimized to remove unnecessary
|
|
29
|
+
* quoting of property names, and remove unused properties, as this string
|
|
30
|
+
* is embedded into .js code.
|
|
31
|
+
* @param source
|
|
32
|
+
* @returns string
|
|
33
|
+
*/
|
|
34
|
+
compile(source: TouchLayoutFile): string {
|
|
35
|
+
// Deep copy the source
|
|
36
|
+
source = JSON.parse(JSON.stringify(source));
|
|
37
|
+
|
|
38
|
+
// Fixup pad, width and sp to string types, as that's what KeymanWeb
|
|
39
|
+
// currently expects
|
|
40
|
+
|
|
41
|
+
const fixupKey = (key: TouchLayoutKey | TouchLayoutSubKey) => {
|
|
42
|
+
if(Object.hasOwn(key, 'pad')) (key.pad as any) = key.pad.toString();
|
|
43
|
+
if(Object.hasOwn(key, 'sp')) (key.sp as any) = key.sp.toString();
|
|
44
|
+
if(Object.hasOwn(key, 'width')) (key.width as any) = key.width.toString();
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const fixupPlatform = (platform: TouchLayoutPlatform) => {
|
|
48
|
+
for(let layer of platform.layer) {
|
|
49
|
+
for(let row of layer.row) {
|
|
50
|
+
for(let key of row.key) {
|
|
51
|
+
fixupKey(key);
|
|
52
|
+
if(key.sk) {
|
|
53
|
+
for(let sk of key.sk) {
|
|
54
|
+
fixupKey(sk);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if(key.multitap) {
|
|
58
|
+
for(let sk of key.multitap) {
|
|
59
|
+
fixupKey(sk);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if(key.flick) {
|
|
63
|
+
for(let id of Object.keys(key.flick)) {
|
|
64
|
+
fixupKey((key.flick as any)[id] as TouchLayoutSubKey);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
if(source.desktop) {
|
|
73
|
+
fixupPlatform(source.desktop);
|
|
74
|
+
}
|
|
75
|
+
if(source.phone) {
|
|
76
|
+
fixupPlatform(source.phone);
|
|
77
|
+
}
|
|
78
|
+
if(source.tablet) {
|
|
79
|
+
fixupPlatform(source.tablet);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return JSON.stringify(source, null, this.options?.formatted ? 2 : undefined);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
//
|
|
2
|
+
// .keyman-touch-layout JSON format
|
|
3
|
+
//
|
|
4
|
+
// Follows /common/schemas/keyman-touch-layout/keyman-touch-layout.spec.json for
|
|
5
|
+
// reading and
|
|
6
|
+
// /common/schemas/keyman-touch-layout/keyman-touch-layout.clean.spec.json for
|
|
7
|
+
// writing
|
|
8
|
+
//
|
|
9
|
+
|
|
10
|
+
export interface TouchLayoutFile {
|
|
11
|
+
tablet?: TouchLayoutPlatform;
|
|
12
|
+
phone?: TouchLayoutPlatform;
|
|
13
|
+
desktop?: TouchLayoutPlatform;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type TouchLayoutFont = string;
|
|
17
|
+
export type TouchLayoutFontSize = string;
|
|
18
|
+
export type TouchLayoutDefaultHint = "none"|"dot"|"longpress"|"multitap"|"flick"|"flick-n"|"flick-ne"|"flick-e"|"flick-se"|"flick-s"|"flick-sw"|"flick-w"|"flick-nw";
|
|
19
|
+
|
|
20
|
+
export interface TouchLayoutPlatform {
|
|
21
|
+
font?: TouchLayoutFont;
|
|
22
|
+
fontsize?: TouchLayoutFontSize;
|
|
23
|
+
layer: TouchLayoutLayer[];
|
|
24
|
+
displayUnderlying?: boolean;
|
|
25
|
+
defaultHint: TouchLayoutDefaultHint;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export type TouchLayoutLayerId = string; // pattern = /^[a-zA-Z0-9_-]+$/
|
|
29
|
+
|
|
30
|
+
export interface TouchLayoutLayer {
|
|
31
|
+
id: TouchLayoutLayerId;
|
|
32
|
+
row: TouchLayoutRow[];
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type TouchLayoutRowId = number;
|
|
36
|
+
|
|
37
|
+
export interface TouchLayoutRow {
|
|
38
|
+
id: TouchLayoutRowId;
|
|
39
|
+
key: TouchLayoutKey[];
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
type Key_Type = 'T'|'K'|'U'|'t'|'k'|'u';
|
|
43
|
+
type Key_Id = string;
|
|
44
|
+
export type TouchLayoutKeyId = `${Key_Type}_${Key_Id}`; // pattern = /^[TKUtku]_[a-zA-Z0-9_]+$/
|
|
45
|
+
|
|
46
|
+
export interface TouchLayoutKey {
|
|
47
|
+
id?: TouchLayoutKeyId;
|
|
48
|
+
text?: string;
|
|
49
|
+
layer?: TouchLayoutLayerId;
|
|
50
|
+
nextlayer?: TouchLayoutLayerId;
|
|
51
|
+
font?: TouchLayoutFont;
|
|
52
|
+
fontsize?: TouchLayoutFontSize;
|
|
53
|
+
sp?: TouchLayoutKeySp;
|
|
54
|
+
pad?: TouchLayoutKeyPad;
|
|
55
|
+
width?: TouchLayoutKeyWidth;
|
|
56
|
+
sk?: TouchLayoutSubKey[];
|
|
57
|
+
flick?: TouchLayoutFlick;
|
|
58
|
+
multitap?: TouchLayoutSubKey[];
|
|
59
|
+
hint?: string;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export enum TouchLayoutKeySp { normal=0, special=1, specialActive=2, deadkey=8, blank=9, spacer=10 };
|
|
63
|
+
export type TouchLayoutKeyPad = number; // 0-100000
|
|
64
|
+
export type TouchLayoutKeyWidth = number; // 0-100000
|
|
65
|
+
|
|
66
|
+
export interface TouchLayoutSubKey {
|
|
67
|
+
id: TouchLayoutKeyId;
|
|
68
|
+
text?: string;
|
|
69
|
+
layer?: TouchLayoutLayerId;
|
|
70
|
+
nextlayer?: TouchLayoutLayerId;
|
|
71
|
+
font?: TouchLayoutFont;
|
|
72
|
+
fontsize?: TouchLayoutFontSize;
|
|
73
|
+
sp?: TouchLayoutKeySp;
|
|
74
|
+
pad?: TouchLayoutKeyPad;
|
|
75
|
+
width?: TouchLayoutKeyWidth;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export interface TouchLayoutFlick {
|
|
79
|
+
n?: TouchLayoutSubKey;
|
|
80
|
+
s?: TouchLayoutSubKey;
|
|
81
|
+
e?: TouchLayoutSubKey;
|
|
82
|
+
w?: TouchLayoutSubKey;
|
|
83
|
+
ne?: TouchLayoutSubKey;
|
|
84
|
+
nw?: TouchLayoutSubKey;
|
|
85
|
+
se?: TouchLayoutSubKey;
|
|
86
|
+
sw?: TouchLayoutSubKey;
|
|
87
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { constants } from '@keymanapp/ldml-keyboard-constants';
|
|
2
|
+
import { Strs, StrsItem } from './kmx-plus.js';
|
|
3
|
+
|
|
4
|
+
export enum ElemElementFlags {
|
|
5
|
+
none = 0,
|
|
6
|
+
unicode_set = constants.elem_flags_unicode_set,
|
|
7
|
+
tertiary_base = constants.elem_flags_tertiary_base,
|
|
8
|
+
prebase = constants.elem_flags_prebase
|
|
9
|
+
}
|
|
10
|
+
;
|
|
11
|
+
|
|
12
|
+
export class ElemElement {
|
|
13
|
+
value: StrsItem; // UnicodeSet or UCS32LE character
|
|
14
|
+
order: number; // -128 to +127; used only by reorder element values
|
|
15
|
+
tertiary: number; // -128 to +127; used only by reorder element values
|
|
16
|
+
flags: ElemElementFlags;
|
|
17
|
+
isEqual(a: ElemElement) {
|
|
18
|
+
return a.value === this.value &&
|
|
19
|
+
a.order === this.order &&
|
|
20
|
+
a.tertiary === this.tertiary &&
|
|
21
|
+
a.flags === this.flags;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
;
|
|
25
|
+
|
|
26
|
+
export class ElementString extends Array<ElemElement> {
|
|
27
|
+
constructor(strs: Strs, source: string, order?: string, tertiary?: string, tertiary_base?: string, prebase?: string) {
|
|
28
|
+
super();
|
|
29
|
+
//TODO-LDML: full UnicodeSet and parsing
|
|
30
|
+
if(!source) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let items = source.split("");
|
|
35
|
+
|
|
36
|
+
let orders: Array<string> = order ? order.split(" ") : [];
|
|
37
|
+
if(orders.length == 1) {
|
|
38
|
+
orders = Array<string>(items.length).fill(orders[0]);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let tertiaries: Array<string> = tertiary ? tertiary.split(" ") : [];
|
|
42
|
+
if(tertiaries.length == 1) {
|
|
43
|
+
tertiaries = Array<string>(items.length).fill(tertiaries[0]);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let tertiary_bases: Array<string> = tertiary_base ? tertiary_base.split(" ") : [];
|
|
47
|
+
if(tertiary_bases.length == 1) {
|
|
48
|
+
tertiary_bases = Array<string>(items.length).fill(tertiary_bases[0]);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let prebases: Array<string> = prebase ? prebase.split(" ") : [];
|
|
52
|
+
if(prebases.length == 1) {
|
|
53
|
+
prebases = Array<string>(items.length).fill(prebases[0]);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
for(let i = 0; i < items.length; i++) {
|
|
57
|
+
let elem = new ElemElement();
|
|
58
|
+
elem.value = strs.allocString(items[i]);
|
|
59
|
+
elem.order = orders.length ? parseInt(orders[i], 10) : 0;
|
|
60
|
+
elem.tertiary = tertiaries.length ? parseInt(tertiaries[i], 10) : 0;
|
|
61
|
+
elem.flags = ElemElementFlags.none |
|
|
62
|
+
(tertiary_bases?.[i] == '1' /* TODO-LDML: or 'true'? */ ? ElemElementFlags.tertiary_base : 0) |
|
|
63
|
+
(prebases?.[i] == '1' /* TODO-LDML: or 'true'? */ ? ElemElementFlags.prebase : 0);
|
|
64
|
+
this.push(elem);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
isEqual(a: ElementString): boolean {
|
|
68
|
+
if (a.length != this.length) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
for (let i = 0; i < a.length; i++) {
|
|
72
|
+
if (!this[i].isEqual(a[i])) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
;
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import * as r from 'restructure';
|
|
2
|
+
import { KMXFile, GROUP, KEY, STORE } from './kmx.js';
|
|
3
|
+
import { KMXPlusFile } from './kmx-plus.js';
|
|
4
|
+
import KMXPlusBuilder from './kmx-plus-builder/kmx-plus-builder.js';
|
|
5
|
+
|
|
6
|
+
// These type-checking structures are here to ensure that
|
|
7
|
+
// we match the structures from kmx.ts in the generator
|
|
8
|
+
//
|
|
9
|
+
// They are used internally when building a .kmx file
|
|
10
|
+
|
|
11
|
+
interface BUILDER_COMP_KEYBOARD {
|
|
12
|
+
dwIdentifier: number;
|
|
13
|
+
dwFileVersion: number;
|
|
14
|
+
dwCheckSum: number;
|
|
15
|
+
KeyboardID: number;
|
|
16
|
+
IsRegistered: number;
|
|
17
|
+
version: number;
|
|
18
|
+
|
|
19
|
+
cxStoreArray: number;
|
|
20
|
+
cxGroupArray: number;
|
|
21
|
+
|
|
22
|
+
dpStoreArray: number;
|
|
23
|
+
dpGroupArray: number;
|
|
24
|
+
|
|
25
|
+
StartGroup_ANSI: number;
|
|
26
|
+
StartGroup_Unicode: number;
|
|
27
|
+
|
|
28
|
+
dwFlags: number;
|
|
29
|
+
|
|
30
|
+
dwHotKey: number;
|
|
31
|
+
|
|
32
|
+
dpBitmapOffset: number;
|
|
33
|
+
dwBitmapSize: number;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
interface BUILDER_COMP_KEYBOARD_KMXPLUSINFO {
|
|
37
|
+
dpKMXPlus: number;
|
|
38
|
+
dwKMXPlusSize: number;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
interface BUILDER_COMP_STORE {
|
|
42
|
+
dwSystemID: number;
|
|
43
|
+
dpName: number;
|
|
44
|
+
dpString: number;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
interface BUILDER_COMP_KEY {
|
|
48
|
+
Key: number;
|
|
49
|
+
_padding: number;
|
|
50
|
+
Line: number;
|
|
51
|
+
ShiftFlags: number;
|
|
52
|
+
dpOutput: number;
|
|
53
|
+
dpContext: number;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
interface BUILDER_COMP_GROUP {
|
|
57
|
+
dpName: number;
|
|
58
|
+
dpKeyArray: number;
|
|
59
|
+
dpMatch: number;
|
|
60
|
+
dpNoMatch: number;
|
|
61
|
+
cxKeyArray: number;
|
|
62
|
+
fUsingKeys: number;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
export default class KMXBuilder {
|
|
67
|
+
file: KMXFile;
|
|
68
|
+
base_keyboard: number = 0;
|
|
69
|
+
base_kmxplus: number = 0;
|
|
70
|
+
comp_header: BUILDER_COMP_KEYBOARD;
|
|
71
|
+
comp_kmxplus: BUILDER_COMP_KEYBOARD_KMXPLUSINFO;
|
|
72
|
+
comp_stores: {base: number, store: STORE, obj: BUILDER_COMP_STORE}[] = [];
|
|
73
|
+
comp_groups: {base: number, group: GROUP, obj: BUILDER_COMP_GROUP, keys: {base: number, key: KEY, obj: BUILDER_COMP_KEY}[]}[] = [];
|
|
74
|
+
comp_kmxplus_data: Uint8Array;
|
|
75
|
+
writeDebug: boolean = false;
|
|
76
|
+
|
|
77
|
+
constructor(file: KMXFile, writeDebug: boolean) {
|
|
78
|
+
this.file = file;
|
|
79
|
+
this.writeDebug = writeDebug;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
calculateStringOffsetAndSize(string: string, base: number, requireString: boolean = false) {
|
|
83
|
+
if(string.length == 0 && !requireString) {
|
|
84
|
+
// Zero length strings take up no space in the file, and
|
|
85
|
+
// are treated as a 'null string'
|
|
86
|
+
return [0, base];
|
|
87
|
+
}
|
|
88
|
+
return [base, base + string.length * 2 + 2]; // include trailing zero
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private build() {
|
|
92
|
+
this.base_keyboard = 0;
|
|
93
|
+
this.base_kmxplus = 0;
|
|
94
|
+
|
|
95
|
+
// Header
|
|
96
|
+
|
|
97
|
+
this.comp_header = {
|
|
98
|
+
dwIdentifier: KMXFile.FILEID_COMPILED,
|
|
99
|
+
dwFileVersion: KMXFile.VERSION_160,
|
|
100
|
+
dwCheckSum: 0, // Deprecated in Keyman 16.0
|
|
101
|
+
KeyboardID: 0,
|
|
102
|
+
IsRegistered: 1,
|
|
103
|
+
version: 0,
|
|
104
|
+
cxStoreArray: 0,
|
|
105
|
+
cxGroupArray: 0,
|
|
106
|
+
dpStoreArray: 0,
|
|
107
|
+
dpGroupArray: 0,
|
|
108
|
+
StartGroup_ANSI: 0xFFFFFFFF,
|
|
109
|
+
StartGroup_Unicode: 0xFFFFFFFF,
|
|
110
|
+
dwFlags: 0,
|
|
111
|
+
dwHotKey: 0,
|
|
112
|
+
dpBitmapOffset: 0,
|
|
113
|
+
dwBitmapSize: 0
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
let size = KMXFile.COMP_KEYBOARD_SIZE;
|
|
117
|
+
|
|
118
|
+
if(this.file instanceof KMXPlusFile) {
|
|
119
|
+
// Reserve space for KMXPlus header; we'll come back and fill in details
|
|
120
|
+
// once we know base kmx file size.
|
|
121
|
+
this.comp_header.dwFlags |= KMXFile.KF_KMXPLUS;
|
|
122
|
+
this.base_kmxplus = size;
|
|
123
|
+
size += KMXFile.COMP_KEYBOARD_KMXPLUSINFO_SIZE;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Stores
|
|
127
|
+
|
|
128
|
+
this.comp_header.cxStoreArray = this.file.keyboard.stores.length;
|
|
129
|
+
this.comp_header.dpStoreArray = this.comp_header.cxStoreArray ? size : 0;
|
|
130
|
+
let storeBase = size;
|
|
131
|
+
size += this.file.keyboard.stores.length * KMXFile.COMP_STORE_SIZE;
|
|
132
|
+
for(let store of this.file.keyboard.stores) {
|
|
133
|
+
let comp_store: BUILDER_COMP_STORE = {
|
|
134
|
+
dwSystemID: store.dwSystemID,
|
|
135
|
+
dpName: 0,
|
|
136
|
+
dpString: 0
|
|
137
|
+
};
|
|
138
|
+
this.comp_stores.push({base: storeBase, store: store, obj: comp_store});
|
|
139
|
+
if(this.writeDebug /*TODO: || store.isOption*/) {
|
|
140
|
+
[comp_store.dpName, size] = this.calculateStringOffsetAndSize(store.dpName, size);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
[comp_store.dpString, size] = this.calculateStringOffsetAndSize(store.dpString, size);
|
|
144
|
+
storeBase += KMXFile.COMP_STORE_SIZE;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Groups
|
|
148
|
+
|
|
149
|
+
this.comp_header.cxGroupArray = this.file.keyboard.groups.length;
|
|
150
|
+
this.comp_header.dpGroupArray = this.comp_header.cxGroupArray ? size : 0;
|
|
151
|
+
let groupBase = size;
|
|
152
|
+
size += this.file.keyboard.groups.length * KMXFile.COMP_GROUP_SIZE;
|
|
153
|
+
for(let group of this.file.keyboard.groups) {
|
|
154
|
+
let comp_group: BUILDER_COMP_GROUP = {
|
|
155
|
+
dpName: 0,
|
|
156
|
+
dpKeyArray: 0,
|
|
157
|
+
dpMatch: 0,
|
|
158
|
+
dpNoMatch: 0,
|
|
159
|
+
cxKeyArray: group.keys.length,
|
|
160
|
+
fUsingKeys: group.fUsingKeys ? 1 : 0
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
let comp_keys: {base: number, key: KEY, obj: BUILDER_COMP_KEY}[] = [];
|
|
164
|
+
|
|
165
|
+
this.comp_groups.push({base: groupBase, group: group, obj: comp_group, keys: comp_keys});
|
|
166
|
+
|
|
167
|
+
if(this.writeDebug) {
|
|
168
|
+
[comp_group.dpName, size] = this.calculateStringOffsetAndSize(group.dpName, size);
|
|
169
|
+
}
|
|
170
|
+
[comp_group.dpMatch, size] = this.calculateStringOffsetAndSize(group.dpMatch, size);
|
|
171
|
+
[comp_group.dpNoMatch, size] = this.calculateStringOffsetAndSize(group.dpNoMatch, size);
|
|
172
|
+
|
|
173
|
+
// Keys within a group
|
|
174
|
+
|
|
175
|
+
comp_group.dpKeyArray = group.keys.length ? size : 0;
|
|
176
|
+
|
|
177
|
+
let keyBase = size;
|
|
178
|
+
size += group.keys.length * KMXFile.COMP_KEY_SIZE;
|
|
179
|
+
for(let key of group.keys) {
|
|
180
|
+
let comp_key: BUILDER_COMP_KEY = {
|
|
181
|
+
Key: key.Key,
|
|
182
|
+
_padding: 0,
|
|
183
|
+
Line: key.Line,
|
|
184
|
+
ShiftFlags: key.ShiftFlags,
|
|
185
|
+
dpOutput: 0,
|
|
186
|
+
dpContext: 0
|
|
187
|
+
};
|
|
188
|
+
comp_keys.push({base: keyBase, key: key, obj: comp_key});
|
|
189
|
+
[comp_key.dpOutput, size] = this.calculateStringOffsetAndSize(key.dpOutput, size, true);
|
|
190
|
+
[comp_key.dpContext, size] = this.calculateStringOffsetAndSize(key.dpContext, size, true);
|
|
191
|
+
keyBase += KMXFile.COMP_KEY_SIZE;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
groupBase += KMXFile.COMP_GROUP_SIZE;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
size += this.buildBitmap();
|
|
198
|
+
size += this.buildKMXPlus(size);
|
|
199
|
+
|
|
200
|
+
return size;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
buildBitmap() {
|
|
204
|
+
// TODO
|
|
205
|
+
return 0;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
buildKMXPlus(base: number) {
|
|
209
|
+
if(!(this.file instanceof KMXPlusFile)) {
|
|
210
|
+
return 0;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const plusbuilder: KMXPlusBuilder = new KMXPlusBuilder(this.file, this.writeDebug);
|
|
214
|
+
this.comp_kmxplus_data = plusbuilder.compile();
|
|
215
|
+
this.comp_kmxplus = {
|
|
216
|
+
dpKMXPlus: base,
|
|
217
|
+
dwKMXPlusSize: this.comp_kmxplus_data.length
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
return this.comp_kmxplus.dwKMXPlusSize;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
setString(file: Uint8Array, pos: number, str: string, requireString: boolean = false): void {
|
|
224
|
+
if(requireString && !str.length) {
|
|
225
|
+
// Just write zero terminator, as r.String for a zero-length string
|
|
226
|
+
// seems to fail.
|
|
227
|
+
let sbuf = r.uint16le;
|
|
228
|
+
file.set(sbuf.toBuffer(0), pos);
|
|
229
|
+
}
|
|
230
|
+
else if(pos && str.length) {
|
|
231
|
+
let sbuf = new r.String(null, 'utf16le'); // null-terminated string
|
|
232
|
+
file.set(sbuf.toBuffer(str), pos);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
compile(): Uint8Array {
|
|
237
|
+
const fileSize = this.build();
|
|
238
|
+
|
|
239
|
+
let file: Uint8Array = new Uint8Array(fileSize);
|
|
240
|
+
|
|
241
|
+
// Write headers
|
|
242
|
+
|
|
243
|
+
const header = this.file.COMP_KEYBOARD.toBuffer(this.comp_header);
|
|
244
|
+
file.set(header, this.base_keyboard);
|
|
245
|
+
|
|
246
|
+
if(this.file instanceof KMXPlusFile) {
|
|
247
|
+
const kmxplus: Uint8Array = this.file.COMP_KEYBOARD_KMXPLUSINFO.toBuffer(this.comp_kmxplus);
|
|
248
|
+
file.set(kmxplus, this.base_kmxplus);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Write store array and data
|
|
252
|
+
|
|
253
|
+
for(let store of this.comp_stores) {
|
|
254
|
+
file.set(this.file.COMP_STORE.toBuffer(store.obj), store.base);
|
|
255
|
+
if(this.writeDebug) {
|
|
256
|
+
this.setString(file, store.obj.dpName, store.store.dpName);
|
|
257
|
+
}
|
|
258
|
+
this.setString(file, store.obj.dpString, store.store.dpString);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Write group array and data
|
|
262
|
+
|
|
263
|
+
for(let group of this.comp_groups) {
|
|
264
|
+
file.set(this.file.COMP_GROUP.toBuffer(group.obj), group.base);
|
|
265
|
+
if(this.writeDebug) {
|
|
266
|
+
this.setString(file, group.obj.dpName, group.group.dpName);
|
|
267
|
+
}
|
|
268
|
+
this.setString(file, group.obj.dpMatch, group.group.dpMatch);
|
|
269
|
+
this.setString(file, group.obj.dpNoMatch, group.group.dpNoMatch);
|
|
270
|
+
|
|
271
|
+
for(let key of group.keys) {
|
|
272
|
+
file.set(this.file.COMP_KEY.toBuffer(key.obj), key.base);
|
|
273
|
+
// for back-compat reasons, these are never NULL strings
|
|
274
|
+
this.setString(file, key.obj.dpContext, key.key.dpContext, true);
|
|
275
|
+
this.setString(file, key.obj.dpOutput, key.key.dpOutput, true);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Write KMXPlus data stream
|
|
280
|
+
|
|
281
|
+
if(this.file instanceof KMXPlusFile) {
|
|
282
|
+
file.set(this.comp_kmxplus_data, this.comp_kmxplus.dpKMXPlus);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return file;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { constants } from '@keymanapp/ldml-keyboard-constants';
|
|
2
|
+
import { KMXPlusData } from "../kmx-plus.js";
|
|
3
|
+
import { build_strs_index, BUILDER_STRS } from "./build-strs.js";
|
|
4
|
+
import { BUILDER_SECTION } from './builder-section.js';
|
|
5
|
+
|
|
6
|
+
/* ------------------------------------------------------------------
|
|
7
|
+
* disp section
|
|
8
|
+
------------------------------------------------------------------ */
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Builder for the 'disp' section
|
|
12
|
+
*/
|
|
13
|
+
interface BUILDER_DISP_ITEM {
|
|
14
|
+
to: number;
|
|
15
|
+
display: number;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export interface BUILDER_DISP extends BUILDER_SECTION {
|
|
19
|
+
count: number;
|
|
20
|
+
baseCharacter: number;
|
|
21
|
+
items: BUILDER_DISP_ITEM[];
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export function build_disp(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS): BUILDER_DISP {
|
|
25
|
+
if(!kmxplus.disp.disps.length && !kmxplus.disp.baseCharacter.value) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let disp: BUILDER_DISP = {
|
|
30
|
+
ident: constants.hex_section_id(constants.section.disp),
|
|
31
|
+
size: constants.length_disp + constants.length_disp_item * kmxplus.disp.disps.length,
|
|
32
|
+
_offset: 0,
|
|
33
|
+
count: kmxplus.disp.disps.length,
|
|
34
|
+
baseCharacter: build_strs_index(sect_strs, kmxplus.disp.baseCharacter),
|
|
35
|
+
items: []
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
for(let item of kmxplus.disp.disps) {
|
|
39
|
+
disp.items.push({
|
|
40
|
+
to: build_strs_index(sect_strs, item.to),
|
|
41
|
+
display: build_strs_index(sect_strs, item.display),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return disp;
|
|
46
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { constants } from "@keymanapp/ldml-keyboard-constants";
|
|
2
|
+
import { ElementString } from "../element-string.js";
|
|
3
|
+
import { Elem } from "../kmx-plus.js";
|
|
4
|
+
import { build_strs_index, BUILDER_STRS } from "./build-strs.js";
|
|
5
|
+
import { BUILDER_SECTION } from "./builder-section.js";
|
|
6
|
+
|
|
7
|
+
/* ------------------------------------------------------------------
|
|
8
|
+
* elem section
|
|
9
|
+
------------------------------------------------------------------ */
|
|
10
|
+
|
|
11
|
+
interface BUILDER_ELEM_ELEMENT {
|
|
12
|
+
element: number; // str | UTF-32 char
|
|
13
|
+
flags: number;
|
|
14
|
+
_value: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
interface BUILDER_ELEM_STRING {
|
|
18
|
+
offset: number;
|
|
19
|
+
length: number;
|
|
20
|
+
items: BUILDER_ELEM_ELEMENT[];
|
|
21
|
+
_value: ElementString;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Builder for the 'elem' section
|
|
26
|
+
*/
|
|
27
|
+
export interface BUILDER_ELEM extends BUILDER_SECTION {
|
|
28
|
+
count: number;
|
|
29
|
+
strings: BUILDER_ELEM_STRING[];
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function binaryElemCompare(a: BUILDER_ELEM_STRING, b: BUILDER_ELEM_STRING): number {
|
|
33
|
+
for(let i = 0; i < a.items.length && i < b.items.length; i++) {
|
|
34
|
+
if(a.items[i]._value < b.items[i]._value) return -1;
|
|
35
|
+
if(a.items[i]._value > b.items[i]._value) return 1;
|
|
36
|
+
if(a.items[i].flags < b.items[i].flags) return -1;
|
|
37
|
+
if(a.items[i].flags > b.items[i].flags) return 1;
|
|
38
|
+
}
|
|
39
|
+
if(a.items.length < b.items.length) return -1;
|
|
40
|
+
if(a.items.length > b.items.length) return 1;
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function build_elem(source_elem: Elem, sect_strs: BUILDER_STRS): BUILDER_ELEM {
|
|
45
|
+
let result: BUILDER_ELEM = {
|
|
46
|
+
ident: constants.hex_section_id(constants.section.elem),
|
|
47
|
+
size: 0, // finalized below
|
|
48
|
+
_offset: 0,
|
|
49
|
+
count: source_elem.strings.length,
|
|
50
|
+
strings: [], // finalized below
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// TODO: consider padding
|
|
54
|
+
result.strings = source_elem.strings.map(item => {
|
|
55
|
+
let res: BUILDER_ELEM_STRING = {
|
|
56
|
+
offset: 0, // finalized below
|
|
57
|
+
length: item.length,
|
|
58
|
+
items: [],
|
|
59
|
+
_value: item
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
res.items = item.map(v => {
|
|
63
|
+
return {
|
|
64
|
+
element: build_strs_index(sect_strs, v.value),
|
|
65
|
+
flags: constants.elem_flags_unicode_set |
|
|
66
|
+
v.flags | //
|
|
67
|
+
((v.order ?? 0) << constants.elem_flags_order_bitshift) | // -128 to +127; used only by reorder element values
|
|
68
|
+
((v.tertiary ?? 0) << constants.elem_flags_tertiary_bitshift), // -128 to +127; used only by reorder element values
|
|
69
|
+
_value: v.value.value
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
return res;
|
|
73
|
+
});
|
|
74
|
+
result.strings.sort((a,b) => binaryElemCompare(a, b));
|
|
75
|
+
|
|
76
|
+
/* Calculate offsets and total size */
|
|
77
|
+
|
|
78
|
+
let offset = constants.length_elem + constants.length_elem_item * result.count;
|
|
79
|
+
for(let item of result.strings) {
|
|
80
|
+
if (item.length === 0) {
|
|
81
|
+
// no length gets a zero offset
|
|
82
|
+
item.offset = 0;
|
|
83
|
+
} else {
|
|
84
|
+
item.offset = offset;
|
|
85
|
+
offset += item.length * constants.length_elem_item_element;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
result.size = offset;
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function build_elem_index(sect_elem: BUILDER_ELEM, value: ElementString) {
|
|
94
|
+
if(!(value instanceof ElementString)) {
|
|
95
|
+
throw new Error('unexpected value '+value);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const result = sect_elem.strings.findIndex(v => value.isEqual(v._value));
|
|
99
|
+
if(result < 0) {
|
|
100
|
+
throw new Error('unexpectedly missing StrsItem '+value);
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
}
|