@keymanapp/kmc-kmn 18.0.41-alpha → 18.0.46-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 (45) hide show
  1. package/build/src/compiler/compiler.d.ts +181 -181
  2. package/build/src/compiler/compiler.js +493 -496
  3. package/build/src/compiler/compiler.js.map +1 -1
  4. package/build/src/compiler/kmn-compiler-messages.d.ts +458 -458
  5. package/build/src/compiler/kmn-compiler-messages.d.ts.map +1 -1
  6. package/build/src/compiler/kmn-compiler-messages.js +459 -462
  7. package/build/src/compiler/kmn-compiler-messages.js.map +1 -1
  8. package/build/src/compiler/osk.d.ts +31 -31
  9. package/build/src/compiler/osk.js +84 -87
  10. package/build/src/compiler/osk.js.map +1 -1
  11. package/build/src/import/kmcmplib/wasm-host.d.ts +2 -2
  12. package/build/src/import/kmcmplib/wasm-host.js +3262 -3265
  13. package/build/src/import/kmcmplib/wasm-host.js.map +1 -1
  14. package/build/src/import/kmcmplib/wasm-host.wasm +0 -0
  15. package/build/src/kmw-compiler/compiler-globals.d.ts +19 -19
  16. package/build/src/kmw-compiler/compiler-globals.js +38 -41
  17. package/build/src/kmw-compiler/compiler-globals.js.map +1 -1
  18. package/build/src/kmw-compiler/constants.d.ts +16 -16
  19. package/build/src/kmw-compiler/constants.js +79 -82
  20. package/build/src/kmw-compiler/constants.js.map +1 -1
  21. package/build/src/kmw-compiler/javascript-strings.d.ts +32 -32
  22. package/build/src/kmw-compiler/javascript-strings.js +852 -855
  23. package/build/src/kmw-compiler/javascript-strings.js.map +1 -1
  24. package/build/src/kmw-compiler/keymanweb-key-codes.d.ts +22 -22
  25. package/build/src/kmw-compiler/keymanweb-key-codes.js +819 -822
  26. package/build/src/kmw-compiler/keymanweb-key-codes.js.map +1 -1
  27. package/build/src/kmw-compiler/kmw-compiler-messages.d.ts +30 -30
  28. package/build/src/kmw-compiler/kmw-compiler-messages.js +40 -43
  29. package/build/src/kmw-compiler/kmw-compiler-messages.js.map +1 -1
  30. package/build/src/kmw-compiler/kmw-compiler.d.ts +13 -13
  31. package/build/src/kmw-compiler/kmw-compiler.js +547 -550
  32. package/build/src/kmw-compiler/kmw-compiler.js.map +1 -1
  33. package/build/src/kmw-compiler/util.d.ts +74 -74
  34. package/build/src/kmw-compiler/util.js +247 -250
  35. package/build/src/kmw-compiler/util.js.map +1 -1
  36. package/build/src/kmw-compiler/validate-layout-file.d.ts +8 -8
  37. package/build/src/kmw-compiler/validate-layout-file.js +276 -279
  38. package/build/src/kmw-compiler/validate-layout-file.js.map +1 -1
  39. package/build/src/kmw-compiler/visual-keyboard-compiler.d.ts +2 -2
  40. package/build/src/kmw-compiler/visual-keyboard-compiler.js +119 -122
  41. package/build/src/kmw-compiler/visual-keyboard-compiler.js.map +1 -1
  42. package/build/src/main.d.ts +9 -9
  43. package/build/src/main.js +10 -13
  44. package/build/src/main.js.map +1 -1
  45. package/package.json +5 -5
@@ -1,550 +1,547 @@
1
-
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="bb0f70f6-191e-5f90-80c7-09d068e49b8a")}catch(e){}}();
3
- import { KMX, KvkFileReader, KmxFileReader } from "@keymanapp/common-types";
4
- import { ExpandSentinel, incxstr, xstrlen } from "./util.js";
5
- import { options, nl, FTabStop, setupGlobals, IsKeyboardVersion10OrLater, callbacks, FFix183_LadderLength, FCallFunctions, fk, IsKeyboardVersion17OrLater } from "./compiler-globals.js";
6
- import { JavaScript_ContextMatch, JavaScript_KeyAsString, JavaScript_Name, JavaScript_OutputString, JavaScript_Rules, JavaScript_Shift, JavaScript_ShiftAsString, JavaScript_Store, zeroPadHex } from './javascript-strings.js';
7
- import { KmwCompilerMessages } from "./kmw-compiler-messages.js";
8
- import { ValidateLayoutFile } from "./validate-layout-file.js";
9
- import { VisualKeyboardFromFile } from "./visual-keyboard-compiler.js";
10
- import { STORETYPE_DEBUG, STORETYPE_OPTION, STORETYPE_RESERVED } from "../compiler/compiler.js";
11
- function requote(s) {
12
- return "'" + s.replaceAll(/(['\\])/g, "\\$1") + "'";
13
- }
14
- export function RequotedString(s, RequoteSingleQuotes = false) {
15
- // TODO: use a JSON encode
16
- let i = 0;
17
- while (i < s.length) {
18
- if (s.charAt(i) == '"' || s.charAt(i) == '\\') {
19
- s = s.substring(0, i) + '\\' + s.substring(i);
20
- i++;
21
- }
22
- else if (s.charAt(i) == '\'' && RequoteSingleQuotes) {
23
- s = s.substring(0, i) + '\\' + s.substring(i);
24
- i++;
25
- }
26
- else if (s.charAt(i) == '\n') {
27
- s = s.substring(0, i) + ' ' + s.substring(i + 1);
28
- }
29
- else if (s.charAt(i) == '\r') {
30
- // Yes, `\r` gets converted to `\n`, per kmcomp pattern
31
- // in the future we may change this
32
- s = s.substring(0, i) + '\\n' + s.substring(i + 1);
33
- }
34
- i++;
35
- }
36
- return s;
37
- }
38
- export function WriteCompiledKeyboard(callbacks, kmnfile, keyboardData, kvkData, kmxResult, FDebug = false) {
39
- let opts = {
40
- shouldAddCompilerVersion: false,
41
- saveDebug: FDebug
42
- };
43
- const reader = new KmxFileReader();
44
- const keyboard = reader.read(keyboardData);
45
- setupGlobals(callbacks, opts, FDebug ? ' ' : '', FDebug ? '\r\n' : '', kmxResult, keyboard, kmnfile);
46
- const isStoreType = (index, type) => !!(kmxResult.extra.stores[index].storeType & type);
47
- const isDebugStore = (index) => isStoreType(index, STORETYPE_DEBUG);
48
- const isReservedStore = (index) => isStoreType(index, STORETYPE_RESERVED);
49
- const isOptionStore = (index) => isStoreType(index, STORETYPE_OPTION);
50
- const getStoreLine = (index) => kmxResult.extra.stores[index].line;
51
- let vMnemonic = 0;
52
- let sRTL = "", sHelp = "''", sHelpFile = "", sEmbedJSFilename = "", sEmbedCSSFilename = "";
53
- let sVisualKeyboardFilename = "", sFullName = "";
54
- let sBegin_NewContext = "", sBegin_PostKeystroke = "";
55
- let sLayoutFilename = "", sVKDictionary = "";
56
- let linecomment; // I3438
57
- let sModifierBitmask;
58
- let FOptionStores;
59
- let FKeyboardVersion = "1.0";
60
- let sHelpFileStoreIndex, sEmbedJSStoreIndex, sEmbedCSSStoreIndex;
61
- let result = "";
62
- // Locate the name of the keyboard
63
- for (let i = 0; i < keyboard.stores.length; i++) {
64
- const fsp = keyboard.stores[i];
65
- if (fsp.dwSystemID == KMX.KMXFile.TSS_NAME) {
66
- sFullName = fsp.dpString;
67
- }
68
- else if (fsp.dwSystemID == KMX.KMXFile.TSS_KEYBOARDVERSION) { // I4155
69
- FKeyboardVersion = fsp.dpString;
70
- }
71
- else if (fsp.dpName == 'HelpFile' || fsp.dwSystemID == KMX.KMXFile.TSS_KMW_HELPFILE) {
72
- sHelpFile = fsp.dpString;
73
- sHelpFileStoreIndex = i;
74
- }
75
- else if (fsp.dpName == 'Help' || fsp.dwSystemID == KMX.KMXFile.TSS_KMW_HELPTEXT) {
76
- sHelp = '"' + RequotedString(fsp.dpString) + '"';
77
- }
78
- else if (fsp.dpName == 'VisualKeyboard' || fsp.dwSystemID == KMX.KMXFile.TSS_VISUALKEYBOARD) {
79
- sVisualKeyboardFilename = fsp.dpString;
80
- }
81
- else if (fsp.dpName == 'EmbedJS' || fsp.dwSystemID == KMX.KMXFile.TSS_KMW_EMBEDJS) {
82
- sEmbedJSFilename = fsp.dpString;
83
- sEmbedJSStoreIndex = i;
84
- }
85
- else if (fsp.dpName == 'EmbedCSS' || fsp.dwSystemID == KMX.KMXFile.TSS_KMW_EMBEDCSS) { // I4368
86
- sEmbedCSSFilename = fsp.dpString;
87
- sEmbedCSSStoreIndex = i;
88
- }
89
- else if (fsp.dpName == 'RTL' || fsp.dwSystemID == KMX.KMXFile.TSS_KMW_RTL) {
90
- sRTL = fsp.dpString == '1' ? FTabStop + 'this.KRTL=1;' + nl : ''; // I3681
91
- }
92
- else if (fsp.dwSystemID == KMX.KMXFile.TSS_MNEMONIC) {
93
- vMnemonic = fsp.dpString == '1' ? 1 : 0;
94
- }
95
- else if (fsp.dwSystemID == KMX.KMXFile.TSS_VKDICTIONARY) { // I3438
96
- sVKDictionary = fsp.dpString;
97
- }
98
- else if (fsp.dwSystemID == KMX.KMXFile.TSS_LAYOUTFILE) { // I3483
99
- sLayoutFilename = fsp.dpString;
100
- }
101
- else if (fsp.dwSystemID == KMX.KMXFile.TSS_BEGIN_NEWCONTEXT) {
102
- sBegin_NewContext = fsp.dpString;
103
- }
104
- else if (fsp.dwSystemID == KMX.KMXFile.TSS_BEGIN_POSTKEYSTROKE) {
105
- sBegin_PostKeystroke = fsp.dpString;
106
- }
107
- }
108
- const sName = 'Keyboard_' + getKeymanWebCompiledNameFromFileName(kmnfile);
109
- if (sHelpFile != '') {
110
- sHelp = '';
111
- sHelpFile = callbacks.resolveFilename(kmnfile, sHelpFile);
112
- try {
113
- const data = callbacks.loadFile(sHelpFile);
114
- let html = new TextDecoder().decode(data);
115
- if (!html.endsWith('\n'))
116
- html += '\n'; // CompileKeymanWeb.pas adds a new line at EOF
117
- sHelp = html.replace(/\r/g, '').replace(/\n/g, ' ');
118
- sHelp = requote(sHelp);
119
- }
120
- catch (e) {
121
- callbacks.reportMessage(KmwCompilerMessages.Warn_HelpFileMissing({ line: getStoreLine(sHelpFileStoreIndex), helpFilename: sHelpFile, e }));
122
- sHelp = '';
123
- }
124
- }
125
- let sEmbedJS = '';
126
- if (sEmbedJSFilename != '') {
127
- sEmbedJSFilename = callbacks.resolveFilename(kmnfile, sEmbedJSFilename);
128
- try {
129
- const data = callbacks.loadFile(sEmbedJSFilename);
130
- sEmbedJS = new TextDecoder().decode(data);
131
- }
132
- catch (e) {
133
- callbacks.reportMessage(KmwCompilerMessages.Warn_EmbedJsFileMissing({ line: getStoreLine(sEmbedJSStoreIndex), jsFilename: sEmbedJSFilename, e }));
134
- sEmbedJS = '';
135
- }
136
- }
137
- let sEmbedCSS = '';
138
- if (sEmbedCSSFilename != '') { // I4368
139
- sEmbedCSSFilename = callbacks.resolveFilename(kmnfile, sEmbedCSSFilename);
140
- try {
141
- const data = callbacks.loadFile(sEmbedCSSFilename);
142
- sEmbedCSS = new TextDecoder().decode(data);
143
- if (sEmbedCSS != '' && !sEmbedCSS.endsWith('\r\n'))
144
- sEmbedCSS += '\r\n'; // match CompileKeymanWeb.pas
145
- }
146
- catch (e) {
147
- // TODO(lowpri): rename error constant to Warn_EmbedFileMissing
148
- callbacks.reportMessage(KmwCompilerMessages.Warn_EmbedJsFileMissing({ line: getStoreLine(sEmbedCSSStoreIndex), jsFilename: sEmbedCSSFilename, e }));
149
- sEmbedCSS = '';
150
- }
151
- }
152
- let sLayoutFile = '';
153
- if (sLayoutFilename != '') { // I3483
154
- sLayoutFilename = callbacks.resolveFilename(kmnfile, sLayoutFilename);
155
- let result = ValidateLayoutFile(keyboard, options.saveDebug, sLayoutFilename, sVKDictionary, kmxResult.displayMap);
156
- if (!result) {
157
- sLayoutFile = '';
158
- return null;
159
- }
160
- else if (!result.result) {
161
- sLayoutFile = '';
162
- callbacks.reportMessage(KmwCompilerMessages.Error_InvalidTouchLayoutFile({ filename: sLayoutFilename }));
163
- return null;
164
- }
165
- else {
166
- sLayoutFile = result.output;
167
- }
168
- }
169
- // Default to hide underlying layout characters. This is overridden by touch
170
- // layout platform.displayUnderlying property or, if that is not present for
171
- // the given platform, by the OSK property.
172
- let fDisplayUnderlying = false;
173
- let sVisualKeyboard = 'null'; // 'null' as a string is correct
174
- if (sVisualKeyboardFilename != '') {
175
- const reader = new KvkFileReader();
176
- const kvk = reader.read(kvkData);
177
- fDisplayUnderlying = !!(kvk.header.flags & 2 /* KvkFile.BUILDER_KVK_HEADER_FLAGS.kvkhDisplayUnderlying */);
178
- sVisualKeyboard = VisualKeyboardFromFile(kvk, options.saveDebug);
179
- }
180
- const fMnemonic = vMnemonic == 1;
181
- sModifierBitmask = GetKeyboardModifierBitmask(keyboard, fMnemonic);
182
- result +=
183
- `${JavaScript_SetupProlog()}${nl}` +
184
- `KeymanWeb.KR(new ${sName}());${nl}` +
185
- `${JavaScript_SetupEpilog()}${nl}` +
186
- `function ${sName}()${nl}` +
187
- `{${nl}` +
188
- `${FTabStop}${JavaScript_SetupDebug()}${nl}` +
189
- // Following line caches the Keyman major version
190
- `${FTabStop}this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9;${nl}` +
191
- `${FTabStop}this.KI="${sName}";${nl}` +
192
- `${FTabStop}this.KN="${RequotedString(sFullName)}";${nl}` +
193
- `${FTabStop}this.KMINVER="${(keyboard.fileVersion & KMX.KMXFile.VERSION_MASK_MAJOR) >> 8}.${keyboard.fileVersion & KMX.KMXFile.VERSION_MASK_MINOR}";${nl}` +
194
- `${FTabStop}this.KV=${sVisualKeyboard};${nl}` +
195
- `${FTabStop}this.KDU=${fDisplayUnderlying ? '1' : '0'};${nl}` +
196
- `${FTabStop}this.KH=${sHelp};${nl}` +
197
- `${FTabStop}this.KM=${vMnemonic};${nl}` +
198
- `${FTabStop}this.KBVER="${FKeyboardVersion}";${nl}` + // I4155
199
- `${FTabStop}this.KMBM=${sModifierBitmask};${nl}` +
200
- `${sRTL}`; // I3681
201
- if (HasSupplementaryPlaneChars()) {
202
- result += `${FTabStop}this.KS=1;${nl}`;
203
- }
204
- if (sVKDictionary != '') { // I3438
205
- result += `${FTabStop}this.KVKD="${RequotedString(sVKDictionary)}";${nl}`; // I3681
206
- }
207
- if (sLayoutFile != '') { // I3483
208
- result += `${FTabStop}this.KVKL=${sLayoutFile};${nl}`; // I3681
209
- }
210
- if (sEmbedCSS != '') { // I4368
211
- result += `${FTabStop}this.KCSS="${RequotedString(sEmbedCSS)}";${nl}`;
212
- }
213
- // Write the stores out
214
- FOptionStores = '';
215
- for (let i = 0; i < keyboard.stores.length; i++) {
216
- let fsp = keyboard.stores[i];
217
- // I3438 - Save all system stores to the keyboard, for now // I3684
218
- if (!isDebugStore(i)) {
219
- if (fsp.dwSystemID == KMX.KMXFile.TSS_COMPARISON) {
220
- result += `${FTabStop}this.s${JavaScript_Name(i, fsp.dpName)}=${JavaScript_Store(keyboard, getStoreLine(i), fsp.dpString)};${nl}`;
221
- }
222
- else if (fsp.dwSystemID == KMX.KMXFile.TSS_COMPILEDVERSION) {
223
- result += `${FTabStop}this.KVER=${JavaScript_Store(keyboard, getStoreLine(i), fsp.dpString)};${nl}`;
224
- }
225
- else if (isOptionStore(i) && !isReservedStore(i)) {
226
- result += `${FTabStop}this.s${JavaScript_Name(i, fsp.dpName)}=KeymanWeb.KLOAD(this.KI,"${JavaScript_Name(i, fsp.dpName, true)}",` +
227
- `${JavaScript_Store(keyboard, getStoreLine(i), fsp.dpString)});${nl}`;
228
- if (FOptionStores != '') {
229
- FOptionStores += ',';
230
- }
231
- FOptionStores += `'s${JavaScript_Name(i, fsp.dpName)}'`;
232
- }
233
- else if (fsp.dwSystemID == KMX.KMXFile.TSS_NONE /* aka !isReservedStore(i) */) {
234
- result += `${FTabStop}this.s${JavaScript_Name(i, fsp.dpName)}=${JavaScript_Store(keyboard, getStoreLine(i), fsp.dpString)};${nl}`; // I3681
235
- }
236
- }
237
- }
238
- result += `${FTabStop}this.KVS=[${FOptionStores}];${nl}`;
239
- // Write the groups out
240
- // I853 - begin unicode missing causes crash
241
- if (keyboard.startGroup.unicode == 0xFFFFFFFF) {
242
- callbacks.reportMessage(KmwCompilerMessages.Error_InvalidBegin());
243
- return null;
244
- }
245
- result += WriteBeginStatement(keyboard, 'gs', keyboard.startGroup.unicode);
246
- let rec = ExpandSentinel(keyboard, sBegin_NewContext, 0);
247
- if (rec.Code == KMX.KMXFile.CODE_USE) {
248
- result += WriteBeginStatement(keyboard, 'gn', rec.Use.GroupIndex);
249
- }
250
- rec = ExpandSentinel(keyboard, sBegin_PostKeystroke, 0);
251
- if (rec.Code == KMX.KMXFile.CODE_USE) {
252
- result += WriteBeginStatement(keyboard, 'gpk', rec.Use.GroupIndex);
253
- }
254
- let fgp = keyboard.groups[keyboard.startGroup.unicode];
255
- result +=
256
- `${FTabStop}this.gs=function(t,e) {${nl}` +
257
- `${FTabStop + FTabStop}return this.g${JavaScript_Name(keyboard.startGroup.unicode, fgp.dpName)}(t,e);${nl}` +
258
- `${FTabStop}};${nl}`; // I3681
259
- for (let i = 0; i < keyboard.groups.length; i++) { // I1964
260
- let fgp = keyboard.groups[i];
261
- /*
262
- Note on `r` and `m` variables in a group function:
263
-
264
- `m` can have one of three values:
265
- 0: no rule from this group was matched
266
- 1: a rule from this group was matched and did not include a `use`
267
- statement
268
- 2: a rule from this group matched and did include a `use` statement
269
- (#5440)
270
-
271
- `m` is only used within a rule group to control the firing of the
272
- `match` and `nomatch` rules.
273
-
274
- `r` can have one of two values:
275
- 0: no rule from the final group matched (even if a rule from an
276
- higher-level group did)
277
- 1: a rule from the final group did match;
278
-
279
- `r` serves as the rule group's return value and is forwarded
280
- recursively, best serving as a flag for whether or not default
281
- output for a key should be emitted (0 means yes, emit the
282
- default character output for that key).
283
- */
284
- result +=
285
- `${FTabStop}this.g${JavaScript_Name(i, fgp.dpName)}=function(t,e) {${nl}` +
286
- `${FTabStop + FTabStop}var k=KeymanWeb,r=${fgp.fUsingKeys ? 0 : 1},m=0;${nl}`; //I1959
287
- // fkp := fgp.dpKeyArray;
288
- let HasRules = false;
289
- if (FFix183_LadderLength != 0) {
290
- result += JavaScript_Rules(keyboard, fMnemonic, fgp);
291
- }
292
- else {
293
- for (let j = 0; j < fgp.keys.length; j++) { // I1964
294
- let fkp = fgp.keys[j];
295
- if (!RuleIsExcludedByPlatform(keyboard, fkp)) {
296
- result += FTabStop + FTabStop; // I3681
297
- if (HasRules) {
298
- result += 'else ';
299
- }
300
- HasRules = true;
301
- if (fgp.fUsingKeys) {
302
- result += `if(k.KKM(e,${JavaScript_ShiftAsString(fkp, fMnemonic)},${JavaScript_KeyAsString(fkp, fMnemonic)})`;
303
- }
304
- if (xstrlen(fkp.dpContext) > 0) {
305
- result += fgp.fUsingKeys ? '&&' : 'if(';
306
- result += JavaScript_ContextMatch(keyboard, fkp, fkp.dpContext);
307
- }
308
- else if (!fgp.fUsingKeys) {
309
- result += 'if(1';
310
- }
311
- linecomment = (fkp.Line > 0 && FDebug) ? ` // Line ${fkp.Line}` : '';
312
- result +=
313
- `) {${linecomment}${nl}` +
314
- FTabStop + FTabStop + FTabStop;
315
- if (fgp.fUsingKeys) { // I1959
316
- result += 'r=m=1;' + JavaScript_OutputString(keyboard, FTabStop + FTabStop + FTabStop, fkp, fkp.dpOutput, fgp); // I1959 // I3681
317
- }
318
- else {
319
- result += 'm=1;' + JavaScript_OutputString(keyboard, FTabStop + FTabStop + FTabStop, fkp, fkp.dpOutput, fgp); // I1959 // I3681
320
- }
321
- result += `${nl}${FTabStop}${FTabStop}}${nl}`; // I3681
322
- }
323
- }
324
- }
325
- if (fgp.dpMatch) {
326
- result +=
327
- `${FTabStop + FTabStop}if(m==1) {${nl}` +
328
- `${FTabStop + FTabStop}${JavaScript_OutputString(keyboard, FTabStop + FTabStop + FTabStop, null, fgp.dpMatch, fgp)}${nl}` +
329
- `${FTabStop + FTabStop}}${nl}`;
330
- }
331
- if (fgp.dpNoMatch) {
332
- if (fgp.fUsingKeys) { // I1382 - fixup m=1 to m=g()
333
- result +=
334
- `${FTabStop + FTabStop}if(!m&&k.KIK(e)) {${nl}` +
335
- `${FTabStop + FTabStop + FTabStop}r=1;${JavaScript_OutputString(keyboard, FTabStop + FTabStop + FTabStop, null, fgp.dpNoMatch, fgp)}${nl}` +
336
- `${FTabStop + FTabStop}}${nl}`; // I1959. part 2, I2224 // I3681
337
- }
338
- else {
339
- result +=
340
- `${FTabStop + FTabStop}if(!m) {${nl}` +
341
- `${FTabStop + FTabStop}${JavaScript_OutputString(keyboard, FTabStop + FTabStop + FTabStop, null, fgp.dpNoMatch, fgp)}${nl}` +
342
- // TODO: add FTabStop to line above, once we have 100% identical match
343
- // to legacy compiler, but because legacy compiler missed this
344
- // tabstop we'll leave it out here for now
345
- `${FTabStop + FTabStop}}${nl}`;
346
- }
347
- }
348
- result +=
349
- `${FTabStop + FTabStop}return r;${nl}` +
350
- `${FTabStop}};${nl}`;
351
- }
352
- for (let n = 0; n < FCallFunctions.length; n++) {
353
- const s = callbacks.resolveFilename(kmnfile, FCallFunctions[n] + '.call_js');
354
- if (callbacks.fs.existsSync(s)) {
355
- const data = new TextDecoder().decode(callbacks.loadFile(s));
356
- result += `${FTabStop}this.c${n}=function(t,e){${data.trim()}};${nl}`;
357
- }
358
- else {
359
- result += `${FTabStop}this.c${n}=function(t,e){alert("call(${FCallFunctions[n]}) not defined");};${nl}`;
360
- }
361
- }
362
- result += sEmbedJS + '}' + nl; // I3681
363
- return result;
364
- }
365
- ///
366
- /// Determine the modifiers used in the target keyboard and return a bitmask
367
- /// representing them, or an number value when not in debug mode
368
- ///
369
- /// @return string of JavaScript code, e.g. 'modCodes.SHIFT | modCodes.CTRL /* 0x0030 */'
370
- ///
371
- function GetKeyboardModifierBitmask(keyboard, fMnemonic) {
372
- let bitMask = 0;
373
- for (let gp of keyboard.groups) {
374
- if (gp.fUsingKeys) {
375
- for (let kp of gp.keys) {
376
- if (!RuleIsExcludedByPlatform(keyboard, kp)) {
377
- bitMask |= JavaScript_Shift(kp, fMnemonic);
378
- }
379
- }
380
- }
381
- }
382
- if ((bitMask & KMX.KMXFile.MASK_MODIFIER_CHIRAL) && (bitMask & KMX.KMXFile.MASK_MODIFIER_NONCHIRAL)) {
383
- callbacks.reportMessage(KmwCompilerMessages.Warn_DontMixChiralAndNonChiralModifiers());
384
- }
385
- if (options.saveDebug) {
386
- return FormatModifierAsBitflags(bitMask & KMX.KMXFile.MASK_KEYS); // Exclude KMX_ISVIRTUALKEY, KMX_VIRTUALCHARKEY
387
- }
388
- return '0x' + (bitMask & KMX.KMXFile.MASK_KEYS).toString(16).toUpperCase();
389
- }
390
- ///
391
- /// If debug mode, then returns Javascript code necessary for
392
- /// accessing constants in the compiled keyboard
393
- ///
394
- /// @return string of JavaScript code
395
- ///
396
- function JavaScript_SetupDebug() {
397
- if (IsKeyboardVersion10OrLater()) {
398
- if (options.saveDebug) {
399
- if (IsKeyboardVersion17OrLater()) {
400
- return 'var modCodes = KeymanWeb.Codes.modifierCodes;' + nl +
401
- FTabStop + 'var keyCodes = KeymanWeb.Codes.keyCodes;' + nl;
402
- }
403
- else {
404
- return 'var modCodes = keyman.osk.modifierCodes;' + nl +
405
- FTabStop + 'var keyCodes = keyman.osk.keyCodes;' + nl;
406
- }
407
- }
408
- }
409
- return '';
410
- }
411
- function JavaScript_SetupProlog() {
412
- if (IsKeyboardVersion10OrLater()) {
413
- return 'if(typeof keyman === \'undefined\') {' + nl +
414
- FTabStop + 'console.log(\'Keyboard requires KeymanWeb 10.0 or later\');' + nl +
415
- FTabStop + 'if(typeof tavultesoft !== \'undefined\') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later");' + nl +
416
- '} else {';
417
- }
418
- return '';
419
- }
420
- function JavaScript_SetupEpilog() {
421
- if (IsKeyboardVersion10OrLater()) {
422
- return '}';
423
- }
424
- return '';
425
- }
426
- function HasSupplementaryPlaneChars() {
427
- const suppChar = /[\uD800-\uDBFF][\uDC00-\uDFFF]/;
428
- for (let sp of fk.stores) {
429
- if (suppChar.test(sp.dpString)) {
430
- return true;
431
- }
432
- }
433
- for (let gp of fk.groups) {
434
- for (let kp of gp.keys) {
435
- if (suppChar.test(kp.dpContext) || suppChar.test(kp.dpOutput)) {
436
- return true;
437
- }
438
- }
439
- if (suppChar.test(gp.dpMatch) || suppChar.test(gp.dpNoMatch)) {
440
- return true;
441
- }
442
- }
443
- return false;
444
- }
445
- export function RuleIsExcludedByPlatform(keyboard, fkp) {
446
- if (fkp.dpContext == null || fkp.dpContext == '') {
447
- return false;
448
- }
449
- let x = 0;
450
- while (x < fkp.dpContext.length) {
451
- let rec = ExpandSentinel(keyboard, fkp.dpContext, x);
452
- if (rec.IsSentinel &&
453
- (rec.Code == KMX.KMXFile.CODE_IFSYSTEMSTORE) &&
454
- (rec.IfSystemStore.dwSystemID == KMX.KMXFile.TSS_PLATFORM) &&
455
- rec.IfSystemStore.Store.dpString.includes('native')) {
456
- if (rec.IfSystemStore.Store.dpString.match(/windows|desktop|macosx|linux/)) {
457
- return true;
458
- }
459
- }
460
- x = incxstr(fkp.dpContext, x);
461
- }
462
- return false;
463
- }
464
- function WriteBeginStatement(keyboard, name, groupIndex) {
465
- const fgp = keyboard.groups[groupIndex];
466
- return `${FTabStop}this.${name}=function(t,e) {${nl}` +
467
- `${FTabStop + FTabStop}return this.g${JavaScript_Name(groupIndex, fgp.dpName)}(t,e);${nl}` +
468
- `${FTabStop}};${nl}`;
469
- }
470
- /**
471
- * Converts a modifier bit mask integer into its component bit flags
472
- *
473
- * @param FBitMask A KMX modifier bitmask value
474
- *
475
- * @return string of JavaScript code, e.g. 'modCodes.SHIFT | modCodes.CTRL /* 0x0030 ./'
476
- **/
477
- export function FormatModifierAsBitflags(FBitMask) {
478
- const mask = [
479
- 'LCTRL',
480
- 'RCTRL',
481
- 'LALT',
482
- 'RALT',
483
- 'SHIFT',
484
- 'CTRL',
485
- 'ALT',
486
- '???',
487
- 'CAPS',
488
- 'NO_CAPS',
489
- 'NUM_LOCK',
490
- 'NO_NUM_LOCK',
491
- 'SCROLL_LOCK',
492
- 'NO_SCROLL_LOCK',
493
- 'VIRTUAL_KEY' // 0X4000
494
- ];
495
- let i;
496
- let result = '';
497
- //TODO: We need to think about mnemonic layouts which are incompletely supported at present
498
- //tavultesoft.keymanweb.osk.
499
- if (IsKeyboardVersion10OrLater()) {
500
- // This depends on flags defined in KeymanWeb 10.0
501
- result = '';
502
- for (i = 0; i < mask.length; i++) {
503
- if (FBitMask & (1 << i)) {
504
- if (result != '')
505
- result += ' | ';
506
- result += 'modCodes.' + mask[i];
507
- }
508
- }
509
- if (result == '') {
510
- result = '0';
511
- }
512
- result += ' /* 0x' + zeroPadHex(FBitMask, 4) + ' */';
513
- }
514
- else {
515
- result = '0x' + zeroPadHex(FBitMask, 4);
516
- }
517
- return result;
518
- }
519
- function cleanKeyboardID(name) {
520
- name = name.toLowerCase();
521
- if (name.length == 0) {
522
- return name;
523
- }
524
- if (name[0].match(/\d/)) {
525
- name = '_' + name;
526
- }
527
- let result = '';
528
- for (let i = 0; i < name.length; i++) {
529
- if (!name[i].match(/[a-z0-9_]/)) {
530
- result += '_';
531
- }
532
- else {
533
- result += name[i];
534
- }
535
- }
536
- return result;
537
- }
538
- function getKeymanWebCompiledNameFromFileName(filename) {
539
- let m = /([^/\\]+)$/.exec(filename);
540
- if (!m) {
541
- return null;
542
- }
543
- m = /^(.+?)(\.[^.]+)?$/.exec(m[1]);
544
- if (!m) {
545
- return null;
546
- }
547
- return cleanKeyboardID(m[1]);
548
- }
549
- //# sourceMappingURL=kmw-compiler.js.map
550
- //# debugId=bb0f70f6-191e-5f90-80c7-09d068e49b8a
1
+ import { KMX, KvkFileReader, KmxFileReader } from "@keymanapp/common-types";
2
+ import { ExpandSentinel, incxstr, xstrlen } from "./util.js";
3
+ import { options, nl, FTabStop, setupGlobals, IsKeyboardVersion10OrLater, callbacks, FFix183_LadderLength, FCallFunctions, fk, IsKeyboardVersion17OrLater } from "./compiler-globals.js";
4
+ import { JavaScript_ContextMatch, JavaScript_KeyAsString, JavaScript_Name, JavaScript_OutputString, JavaScript_Rules, JavaScript_Shift, JavaScript_ShiftAsString, JavaScript_Store, zeroPadHex } from './javascript-strings.js';
5
+ import { KmwCompilerMessages } from "./kmw-compiler-messages.js";
6
+ import { ValidateLayoutFile } from "./validate-layout-file.js";
7
+ import { VisualKeyboardFromFile } from "./visual-keyboard-compiler.js";
8
+ import { STORETYPE_DEBUG, STORETYPE_OPTION, STORETYPE_RESERVED } from "../compiler/compiler.js";
9
+ function requote(s) {
10
+ return "'" + s.replaceAll(/(['\\])/g, "\\$1") + "'";
11
+ }
12
+ export function RequotedString(s, RequoteSingleQuotes = false) {
13
+ // TODO: use a JSON encode
14
+ let i = 0;
15
+ while (i < s.length) {
16
+ if (s.charAt(i) == '"' || s.charAt(i) == '\\') {
17
+ s = s.substring(0, i) + '\\' + s.substring(i);
18
+ i++;
19
+ }
20
+ else if (s.charAt(i) == '\'' && RequoteSingleQuotes) {
21
+ s = s.substring(0, i) + '\\' + s.substring(i);
22
+ i++;
23
+ }
24
+ else if (s.charAt(i) == '\n') {
25
+ s = s.substring(0, i) + ' ' + s.substring(i + 1);
26
+ }
27
+ else if (s.charAt(i) == '\r') {
28
+ // Yes, `\r` gets converted to `\n`, per kmcomp pattern
29
+ // in the future we may change this
30
+ s = s.substring(0, i) + '\\n' + s.substring(i + 1);
31
+ }
32
+ i++;
33
+ }
34
+ return s;
35
+ }
36
+ export function WriteCompiledKeyboard(callbacks, kmnfile, keyboardData, kvkData, kmxResult, FDebug = false) {
37
+ let opts = {
38
+ shouldAddCompilerVersion: false,
39
+ saveDebug: FDebug
40
+ };
41
+ const reader = new KmxFileReader();
42
+ const keyboard = reader.read(keyboardData);
43
+ setupGlobals(callbacks, opts, FDebug ? ' ' : '', FDebug ? '\r\n' : '', kmxResult, keyboard, kmnfile);
44
+ const isStoreType = (index, type) => !!(kmxResult.extra.stores[index].storeType & type);
45
+ const isDebugStore = (index) => isStoreType(index, STORETYPE_DEBUG);
46
+ const isReservedStore = (index) => isStoreType(index, STORETYPE_RESERVED);
47
+ const isOptionStore = (index) => isStoreType(index, STORETYPE_OPTION);
48
+ const getStoreLine = (index) => kmxResult.extra.stores[index].line;
49
+ let vMnemonic = 0;
50
+ let sRTL = "", sHelp = "''", sHelpFile = "", sEmbedJSFilename = "", sEmbedCSSFilename = "";
51
+ let sVisualKeyboardFilename = "", sFullName = "";
52
+ let sBegin_NewContext = "", sBegin_PostKeystroke = "";
53
+ let sLayoutFilename = "", sVKDictionary = "";
54
+ let linecomment; // I3438
55
+ let sModifierBitmask;
56
+ let FOptionStores;
57
+ let FKeyboardVersion = "1.0";
58
+ let sHelpFileStoreIndex, sEmbedJSStoreIndex, sEmbedCSSStoreIndex;
59
+ let result = "";
60
+ // Locate the name of the keyboard
61
+ for (let i = 0; i < keyboard.stores.length; i++) {
62
+ const fsp = keyboard.stores[i];
63
+ if (fsp.dwSystemID == KMX.KMXFile.TSS_NAME) {
64
+ sFullName = fsp.dpString;
65
+ }
66
+ else if (fsp.dwSystemID == KMX.KMXFile.TSS_KEYBOARDVERSION) { // I4155
67
+ FKeyboardVersion = fsp.dpString;
68
+ }
69
+ else if (fsp.dpName == 'HelpFile' || fsp.dwSystemID == KMX.KMXFile.TSS_KMW_HELPFILE) {
70
+ sHelpFile = fsp.dpString;
71
+ sHelpFileStoreIndex = i;
72
+ }
73
+ else if (fsp.dpName == 'Help' || fsp.dwSystemID == KMX.KMXFile.TSS_KMW_HELPTEXT) {
74
+ sHelp = '"' + RequotedString(fsp.dpString) + '"';
75
+ }
76
+ else if (fsp.dpName == 'VisualKeyboard' || fsp.dwSystemID == KMX.KMXFile.TSS_VISUALKEYBOARD) {
77
+ sVisualKeyboardFilename = fsp.dpString;
78
+ }
79
+ else if (fsp.dpName == 'EmbedJS' || fsp.dwSystemID == KMX.KMXFile.TSS_KMW_EMBEDJS) {
80
+ sEmbedJSFilename = fsp.dpString;
81
+ sEmbedJSStoreIndex = i;
82
+ }
83
+ else if (fsp.dpName == 'EmbedCSS' || fsp.dwSystemID == KMX.KMXFile.TSS_KMW_EMBEDCSS) { // I4368
84
+ sEmbedCSSFilename = fsp.dpString;
85
+ sEmbedCSSStoreIndex = i;
86
+ }
87
+ else if (fsp.dpName == 'RTL' || fsp.dwSystemID == KMX.KMXFile.TSS_KMW_RTL) {
88
+ sRTL = fsp.dpString == '1' ? FTabStop + 'this.KRTL=1;' + nl : ''; // I3681
89
+ }
90
+ else if (fsp.dwSystemID == KMX.KMXFile.TSS_MNEMONIC) {
91
+ vMnemonic = fsp.dpString == '1' ? 1 : 0;
92
+ }
93
+ else if (fsp.dwSystemID == KMX.KMXFile.TSS_VKDICTIONARY) { // I3438
94
+ sVKDictionary = fsp.dpString;
95
+ }
96
+ else if (fsp.dwSystemID == KMX.KMXFile.TSS_LAYOUTFILE) { // I3483
97
+ sLayoutFilename = fsp.dpString;
98
+ }
99
+ else if (fsp.dwSystemID == KMX.KMXFile.TSS_BEGIN_NEWCONTEXT) {
100
+ sBegin_NewContext = fsp.dpString;
101
+ }
102
+ else if (fsp.dwSystemID == KMX.KMXFile.TSS_BEGIN_POSTKEYSTROKE) {
103
+ sBegin_PostKeystroke = fsp.dpString;
104
+ }
105
+ }
106
+ const sName = 'Keyboard_' + getKeymanWebCompiledNameFromFileName(kmnfile);
107
+ if (sHelpFile != '') {
108
+ sHelp = '';
109
+ sHelpFile = callbacks.resolveFilename(kmnfile, sHelpFile);
110
+ try {
111
+ const data = callbacks.loadFile(sHelpFile);
112
+ let html = new TextDecoder().decode(data);
113
+ if (!html.endsWith('\n'))
114
+ html += '\n'; // CompileKeymanWeb.pas adds a new line at EOF
115
+ sHelp = html.replace(/\r/g, '').replace(/\n/g, ' ');
116
+ sHelp = requote(sHelp);
117
+ }
118
+ catch (e) {
119
+ callbacks.reportMessage(KmwCompilerMessages.Warn_HelpFileMissing({ line: getStoreLine(sHelpFileStoreIndex), helpFilename: sHelpFile, e }));
120
+ sHelp = '';
121
+ }
122
+ }
123
+ let sEmbedJS = '';
124
+ if (sEmbedJSFilename != '') {
125
+ sEmbedJSFilename = callbacks.resolveFilename(kmnfile, sEmbedJSFilename);
126
+ try {
127
+ const data = callbacks.loadFile(sEmbedJSFilename);
128
+ sEmbedJS = new TextDecoder().decode(data);
129
+ }
130
+ catch (e) {
131
+ callbacks.reportMessage(KmwCompilerMessages.Warn_EmbedJsFileMissing({ line: getStoreLine(sEmbedJSStoreIndex), jsFilename: sEmbedJSFilename, e }));
132
+ sEmbedJS = '';
133
+ }
134
+ }
135
+ let sEmbedCSS = '';
136
+ if (sEmbedCSSFilename != '') { // I4368
137
+ sEmbedCSSFilename = callbacks.resolveFilename(kmnfile, sEmbedCSSFilename);
138
+ try {
139
+ const data = callbacks.loadFile(sEmbedCSSFilename);
140
+ sEmbedCSS = new TextDecoder().decode(data);
141
+ if (sEmbedCSS != '' && !sEmbedCSS.endsWith('\r\n'))
142
+ sEmbedCSS += '\r\n'; // match CompileKeymanWeb.pas
143
+ }
144
+ catch (e) {
145
+ // TODO(lowpri): rename error constant to Warn_EmbedFileMissing
146
+ callbacks.reportMessage(KmwCompilerMessages.Warn_EmbedJsFileMissing({ line: getStoreLine(sEmbedCSSStoreIndex), jsFilename: sEmbedCSSFilename, e }));
147
+ sEmbedCSS = '';
148
+ }
149
+ }
150
+ let sLayoutFile = '';
151
+ if (sLayoutFilename != '') { // I3483
152
+ sLayoutFilename = callbacks.resolveFilename(kmnfile, sLayoutFilename);
153
+ let result = ValidateLayoutFile(keyboard, options.saveDebug, sLayoutFilename, sVKDictionary, kmxResult.displayMap);
154
+ if (!result) {
155
+ sLayoutFile = '';
156
+ return null;
157
+ }
158
+ else if (!result.result) {
159
+ sLayoutFile = '';
160
+ callbacks.reportMessage(KmwCompilerMessages.Error_InvalidTouchLayoutFile({ filename: sLayoutFilename }));
161
+ return null;
162
+ }
163
+ else {
164
+ sLayoutFile = result.output;
165
+ }
166
+ }
167
+ // Default to hide underlying layout characters. This is overridden by touch
168
+ // layout platform.displayUnderlying property or, if that is not present for
169
+ // the given platform, by the OSK property.
170
+ let fDisplayUnderlying = false;
171
+ let sVisualKeyboard = 'null'; // 'null' as a string is correct
172
+ if (sVisualKeyboardFilename != '') {
173
+ const reader = new KvkFileReader();
174
+ const kvk = reader.read(kvkData);
175
+ fDisplayUnderlying = !!(kvk.header.flags & 2 /* KvkFile.BUILDER_KVK_HEADER_FLAGS.kvkhDisplayUnderlying */);
176
+ sVisualKeyboard = VisualKeyboardFromFile(kvk, options.saveDebug);
177
+ }
178
+ const fMnemonic = vMnemonic == 1;
179
+ sModifierBitmask = GetKeyboardModifierBitmask(keyboard, fMnemonic);
180
+ result +=
181
+ `${JavaScript_SetupProlog()}${nl}` +
182
+ `KeymanWeb.KR(new ${sName}());${nl}` +
183
+ `${JavaScript_SetupEpilog()}${nl}` +
184
+ `function ${sName}()${nl}` +
185
+ `{${nl}` +
186
+ `${FTabStop}${JavaScript_SetupDebug()}${nl}` +
187
+ // Following line caches the Keyman major version
188
+ `${FTabStop}this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9;${nl}` +
189
+ `${FTabStop}this.KI="${sName}";${nl}` +
190
+ `${FTabStop}this.KN="${RequotedString(sFullName)}";${nl}` +
191
+ `${FTabStop}this.KMINVER="${(keyboard.fileVersion & KMX.KMXFile.VERSION_MASK_MAJOR) >> 8}.${keyboard.fileVersion & KMX.KMXFile.VERSION_MASK_MINOR}";${nl}` +
192
+ `${FTabStop}this.KV=${sVisualKeyboard};${nl}` +
193
+ `${FTabStop}this.KDU=${fDisplayUnderlying ? '1' : '0'};${nl}` +
194
+ `${FTabStop}this.KH=${sHelp};${nl}` +
195
+ `${FTabStop}this.KM=${vMnemonic};${nl}` +
196
+ `${FTabStop}this.KBVER="${FKeyboardVersion}";${nl}` + // I4155
197
+ `${FTabStop}this.KMBM=${sModifierBitmask};${nl}` +
198
+ `${sRTL}`; // I3681
199
+ if (HasSupplementaryPlaneChars()) {
200
+ result += `${FTabStop}this.KS=1;${nl}`;
201
+ }
202
+ if (sVKDictionary != '') { // I3438
203
+ result += `${FTabStop}this.KVKD="${RequotedString(sVKDictionary)}";${nl}`; // I3681
204
+ }
205
+ if (sLayoutFile != '') { // I3483
206
+ result += `${FTabStop}this.KVKL=${sLayoutFile};${nl}`; // I3681
207
+ }
208
+ if (sEmbedCSS != '') { // I4368
209
+ result += `${FTabStop}this.KCSS="${RequotedString(sEmbedCSS)}";${nl}`;
210
+ }
211
+ // Write the stores out
212
+ FOptionStores = '';
213
+ for (let i = 0; i < keyboard.stores.length; i++) {
214
+ let fsp = keyboard.stores[i];
215
+ // I3438 - Save all system stores to the keyboard, for now // I3684
216
+ if (!isDebugStore(i)) {
217
+ if (fsp.dwSystemID == KMX.KMXFile.TSS_COMPARISON) {
218
+ result += `${FTabStop}this.s${JavaScript_Name(i, fsp.dpName)}=${JavaScript_Store(keyboard, getStoreLine(i), fsp.dpString)};${nl}`;
219
+ }
220
+ else if (fsp.dwSystemID == KMX.KMXFile.TSS_COMPILEDVERSION) {
221
+ result += `${FTabStop}this.KVER=${JavaScript_Store(keyboard, getStoreLine(i), fsp.dpString)};${nl}`;
222
+ }
223
+ else if (isOptionStore(i) && !isReservedStore(i)) {
224
+ result += `${FTabStop}this.s${JavaScript_Name(i, fsp.dpName)}=KeymanWeb.KLOAD(this.KI,"${JavaScript_Name(i, fsp.dpName, true)}",` +
225
+ `${JavaScript_Store(keyboard, getStoreLine(i), fsp.dpString)});${nl}`;
226
+ if (FOptionStores != '') {
227
+ FOptionStores += ',';
228
+ }
229
+ FOptionStores += `'s${JavaScript_Name(i, fsp.dpName)}'`;
230
+ }
231
+ else if (fsp.dwSystemID == KMX.KMXFile.TSS_NONE /* aka !isReservedStore(i) */) {
232
+ result += `${FTabStop}this.s${JavaScript_Name(i, fsp.dpName)}=${JavaScript_Store(keyboard, getStoreLine(i), fsp.dpString)};${nl}`; // I3681
233
+ }
234
+ }
235
+ }
236
+ result += `${FTabStop}this.KVS=[${FOptionStores}];${nl}`;
237
+ // Write the groups out
238
+ // I853 - begin unicode missing causes crash
239
+ if (keyboard.startGroup.unicode == 0xFFFFFFFF) {
240
+ callbacks.reportMessage(KmwCompilerMessages.Error_InvalidBegin());
241
+ return null;
242
+ }
243
+ result += WriteBeginStatement(keyboard, 'gs', keyboard.startGroup.unicode);
244
+ let rec = ExpandSentinel(keyboard, sBegin_NewContext, 0);
245
+ if (rec.Code == KMX.KMXFile.CODE_USE) {
246
+ result += WriteBeginStatement(keyboard, 'gn', rec.Use.GroupIndex);
247
+ }
248
+ rec = ExpandSentinel(keyboard, sBegin_PostKeystroke, 0);
249
+ if (rec.Code == KMX.KMXFile.CODE_USE) {
250
+ result += WriteBeginStatement(keyboard, 'gpk', rec.Use.GroupIndex);
251
+ }
252
+ let fgp = keyboard.groups[keyboard.startGroup.unicode];
253
+ result +=
254
+ `${FTabStop}this.gs=function(t,e) {${nl}` +
255
+ `${FTabStop + FTabStop}return this.g${JavaScript_Name(keyboard.startGroup.unicode, fgp.dpName)}(t,e);${nl}` +
256
+ `${FTabStop}};${nl}`; // I3681
257
+ for (let i = 0; i < keyboard.groups.length; i++) { // I1964
258
+ let fgp = keyboard.groups[i];
259
+ /*
260
+ Note on `r` and `m` variables in a group function:
261
+
262
+ `m` can have one of three values:
263
+ 0: no rule from this group was matched
264
+ 1: a rule from this group was matched and did not include a `use`
265
+ statement
266
+ 2: a rule from this group matched and did include a `use` statement
267
+ (#5440)
268
+
269
+ `m` is only used within a rule group to control the firing of the
270
+ `match` and `nomatch` rules.
271
+
272
+ `r` can have one of two values:
273
+ 0: no rule from the final group matched (even if a rule from an
274
+ higher-level group did)
275
+ 1: a rule from the final group did match;
276
+
277
+ `r` serves as the rule group's return value and is forwarded
278
+ recursively, best serving as a flag for whether or not default
279
+ output for a key should be emitted (0 means yes, emit the
280
+ default character output for that key).
281
+ */
282
+ result +=
283
+ `${FTabStop}this.g${JavaScript_Name(i, fgp.dpName)}=function(t,e) {${nl}` +
284
+ `${FTabStop + FTabStop}var k=KeymanWeb,r=${fgp.fUsingKeys ? 0 : 1},m=0;${nl}`; //I1959
285
+ // fkp := fgp.dpKeyArray;
286
+ let HasRules = false;
287
+ if (FFix183_LadderLength != 0) {
288
+ result += JavaScript_Rules(keyboard, fMnemonic, fgp);
289
+ }
290
+ else {
291
+ for (let j = 0; j < fgp.keys.length; j++) { // I1964
292
+ let fkp = fgp.keys[j];
293
+ if (!RuleIsExcludedByPlatform(keyboard, fkp)) {
294
+ result += FTabStop + FTabStop; // I3681
295
+ if (HasRules) {
296
+ result += 'else ';
297
+ }
298
+ HasRules = true;
299
+ if (fgp.fUsingKeys) {
300
+ result += `if(k.KKM(e,${JavaScript_ShiftAsString(fkp, fMnemonic)},${JavaScript_KeyAsString(fkp, fMnemonic)})`;
301
+ }
302
+ if (xstrlen(fkp.dpContext) > 0) {
303
+ result += fgp.fUsingKeys ? '&&' : 'if(';
304
+ result += JavaScript_ContextMatch(keyboard, fkp, fkp.dpContext);
305
+ }
306
+ else if (!fgp.fUsingKeys) {
307
+ result += 'if(1';
308
+ }
309
+ linecomment = (fkp.Line > 0 && FDebug) ? ` // Line ${fkp.Line}` : '';
310
+ result +=
311
+ `) {${linecomment}${nl}` +
312
+ FTabStop + FTabStop + FTabStop;
313
+ if (fgp.fUsingKeys) { // I1959
314
+ result += 'r=m=1;' + JavaScript_OutputString(keyboard, FTabStop + FTabStop + FTabStop, fkp, fkp.dpOutput, fgp); // I1959 // I3681
315
+ }
316
+ else {
317
+ result += 'm=1;' + JavaScript_OutputString(keyboard, FTabStop + FTabStop + FTabStop, fkp, fkp.dpOutput, fgp); // I1959 // I3681
318
+ }
319
+ result += `${nl}${FTabStop}${FTabStop}}${nl}`; // I3681
320
+ }
321
+ }
322
+ }
323
+ if (fgp.dpMatch) {
324
+ result +=
325
+ `${FTabStop + FTabStop}if(m==1) {${nl}` +
326
+ `${FTabStop + FTabStop}${JavaScript_OutputString(keyboard, FTabStop + FTabStop + FTabStop, null, fgp.dpMatch, fgp)}${nl}` +
327
+ `${FTabStop + FTabStop}}${nl}`;
328
+ }
329
+ if (fgp.dpNoMatch) {
330
+ if (fgp.fUsingKeys) { // I1382 - fixup m=1 to m=g()
331
+ result +=
332
+ `${FTabStop + FTabStop}if(!m&&k.KIK(e)) {${nl}` +
333
+ `${FTabStop + FTabStop + FTabStop}r=1;${JavaScript_OutputString(keyboard, FTabStop + FTabStop + FTabStop, null, fgp.dpNoMatch, fgp)}${nl}` +
334
+ `${FTabStop + FTabStop}}${nl}`; // I1959. part 2, I2224 // I3681
335
+ }
336
+ else {
337
+ result +=
338
+ `${FTabStop + FTabStop}if(!m) {${nl}` +
339
+ `${FTabStop + FTabStop}${JavaScript_OutputString(keyboard, FTabStop + FTabStop + FTabStop, null, fgp.dpNoMatch, fgp)}${nl}` +
340
+ // TODO: add FTabStop to line above, once we have 100% identical match
341
+ // to legacy compiler, but because legacy compiler missed this
342
+ // tabstop we'll leave it out here for now
343
+ `${FTabStop + FTabStop}}${nl}`;
344
+ }
345
+ }
346
+ result +=
347
+ `${FTabStop + FTabStop}return r;${nl}` +
348
+ `${FTabStop}};${nl}`;
349
+ }
350
+ for (let n = 0; n < FCallFunctions.length; n++) {
351
+ const s = callbacks.resolveFilename(kmnfile, FCallFunctions[n] + '.call_js');
352
+ if (callbacks.fs.existsSync(s)) {
353
+ const data = new TextDecoder().decode(callbacks.loadFile(s));
354
+ result += `${FTabStop}this.c${n}=function(t,e){${data.trim()}};${nl}`;
355
+ }
356
+ else {
357
+ result += `${FTabStop}this.c${n}=function(t,e){alert("call(${FCallFunctions[n]}) not defined");};${nl}`;
358
+ }
359
+ }
360
+ result += sEmbedJS + '}' + nl; // I3681
361
+ return result;
362
+ }
363
+ ///
364
+ /// Determine the modifiers used in the target keyboard and return a bitmask
365
+ /// representing them, or an number value when not in debug mode
366
+ ///
367
+ /// @return string of JavaScript code, e.g. 'modCodes.SHIFT | modCodes.CTRL /* 0x0030 */'
368
+ ///
369
+ function GetKeyboardModifierBitmask(keyboard, fMnemonic) {
370
+ let bitMask = 0;
371
+ for (let gp of keyboard.groups) {
372
+ if (gp.fUsingKeys) {
373
+ for (let kp of gp.keys) {
374
+ if (!RuleIsExcludedByPlatform(keyboard, kp)) {
375
+ bitMask |= JavaScript_Shift(kp, fMnemonic);
376
+ }
377
+ }
378
+ }
379
+ }
380
+ if ((bitMask & KMX.KMXFile.MASK_MODIFIER_CHIRAL) && (bitMask & KMX.KMXFile.MASK_MODIFIER_NONCHIRAL)) {
381
+ callbacks.reportMessage(KmwCompilerMessages.Warn_DontMixChiralAndNonChiralModifiers());
382
+ }
383
+ if (options.saveDebug) {
384
+ return FormatModifierAsBitflags(bitMask & KMX.KMXFile.MASK_KEYS); // Exclude KMX_ISVIRTUALKEY, KMX_VIRTUALCHARKEY
385
+ }
386
+ return '0x' + (bitMask & KMX.KMXFile.MASK_KEYS).toString(16).toUpperCase();
387
+ }
388
+ ///
389
+ /// If debug mode, then returns Javascript code necessary for
390
+ /// accessing constants in the compiled keyboard
391
+ ///
392
+ /// @return string of JavaScript code
393
+ ///
394
+ function JavaScript_SetupDebug() {
395
+ if (IsKeyboardVersion10OrLater()) {
396
+ if (options.saveDebug) {
397
+ if (IsKeyboardVersion17OrLater()) {
398
+ return 'var modCodes = KeymanWeb.Codes.modifierCodes;' + nl +
399
+ FTabStop + 'var keyCodes = KeymanWeb.Codes.keyCodes;' + nl;
400
+ }
401
+ else {
402
+ return 'var modCodes = keyman.osk.modifierCodes;' + nl +
403
+ FTabStop + 'var keyCodes = keyman.osk.keyCodes;' + nl;
404
+ }
405
+ }
406
+ }
407
+ return '';
408
+ }
409
+ function JavaScript_SetupProlog() {
410
+ if (IsKeyboardVersion10OrLater()) {
411
+ return 'if(typeof keyman === \'undefined\') {' + nl +
412
+ FTabStop + 'console.log(\'Keyboard requires KeymanWeb 10.0 or later\');' + nl +
413
+ FTabStop + 'if(typeof tavultesoft !== \'undefined\') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later");' + nl +
414
+ '} else {';
415
+ }
416
+ return '';
417
+ }
418
+ function JavaScript_SetupEpilog() {
419
+ if (IsKeyboardVersion10OrLater()) {
420
+ return '}';
421
+ }
422
+ return '';
423
+ }
424
+ function HasSupplementaryPlaneChars() {
425
+ const suppChar = /[\uD800-\uDBFF][\uDC00-\uDFFF]/;
426
+ for (let sp of fk.stores) {
427
+ if (suppChar.test(sp.dpString)) {
428
+ return true;
429
+ }
430
+ }
431
+ for (let gp of fk.groups) {
432
+ for (let kp of gp.keys) {
433
+ if (suppChar.test(kp.dpContext) || suppChar.test(kp.dpOutput)) {
434
+ return true;
435
+ }
436
+ }
437
+ if (suppChar.test(gp.dpMatch) || suppChar.test(gp.dpNoMatch)) {
438
+ return true;
439
+ }
440
+ }
441
+ return false;
442
+ }
443
+ export function RuleIsExcludedByPlatform(keyboard, fkp) {
444
+ if (fkp.dpContext == null || fkp.dpContext == '') {
445
+ return false;
446
+ }
447
+ let x = 0;
448
+ while (x < fkp.dpContext.length) {
449
+ let rec = ExpandSentinel(keyboard, fkp.dpContext, x);
450
+ if (rec.IsSentinel &&
451
+ (rec.Code == KMX.KMXFile.CODE_IFSYSTEMSTORE) &&
452
+ (rec.IfSystemStore.dwSystemID == KMX.KMXFile.TSS_PLATFORM) &&
453
+ rec.IfSystemStore.Store.dpString.includes('native')) {
454
+ if (rec.IfSystemStore.Store.dpString.match(/windows|desktop|macosx|linux/)) {
455
+ return true;
456
+ }
457
+ }
458
+ x = incxstr(fkp.dpContext, x);
459
+ }
460
+ return false;
461
+ }
462
+ function WriteBeginStatement(keyboard, name, groupIndex) {
463
+ const fgp = keyboard.groups[groupIndex];
464
+ return `${FTabStop}this.${name}=function(t,e) {${nl}` +
465
+ `${FTabStop + FTabStop}return this.g${JavaScript_Name(groupIndex, fgp.dpName)}(t,e);${nl}` +
466
+ `${FTabStop}};${nl}`;
467
+ }
468
+ /**
469
+ * Converts a modifier bit mask integer into its component bit flags
470
+ *
471
+ * @param FBitMask A KMX modifier bitmask value
472
+ *
473
+ * @return string of JavaScript code, e.g. 'modCodes.SHIFT | modCodes.CTRL /* 0x0030 ./'
474
+ **/
475
+ export function FormatModifierAsBitflags(FBitMask) {
476
+ const mask = [
477
+ 'LCTRL', // 0X0001
478
+ 'RCTRL', // 0X0002
479
+ 'LALT', // 0X0004
480
+ 'RALT', // 0X0008
481
+ 'SHIFT', // 0X0010
482
+ 'CTRL', // 0X0020
483
+ 'ALT', // 0X0040
484
+ '???', // Reserved
485
+ 'CAPS', // 0X0100
486
+ 'NO_CAPS', // 0X0200
487
+ 'NUM_LOCK', // 0X0400
488
+ 'NO_NUM_LOCK', // 0X0800
489
+ 'SCROLL_LOCK', // 0X1000
490
+ 'NO_SCROLL_LOCK', // 0X2000
491
+ 'VIRTUAL_KEY' // 0X4000
492
+ ];
493
+ let i;
494
+ let result = '';
495
+ //TODO: We need to think about mnemonic layouts which are incompletely supported at present
496
+ //tavultesoft.keymanweb.osk.
497
+ if (IsKeyboardVersion10OrLater()) {
498
+ // This depends on flags defined in KeymanWeb 10.0
499
+ result = '';
500
+ for (i = 0; i < mask.length; i++) {
501
+ if (FBitMask & (1 << i)) {
502
+ if (result != '')
503
+ result += ' | ';
504
+ result += 'modCodes.' + mask[i];
505
+ }
506
+ }
507
+ if (result == '') {
508
+ result = '0';
509
+ }
510
+ result += ' /* 0x' + zeroPadHex(FBitMask, 4) + ' */';
511
+ }
512
+ else {
513
+ result = '0x' + zeroPadHex(FBitMask, 4);
514
+ }
515
+ return result;
516
+ }
517
+ function cleanKeyboardID(name) {
518
+ name = name.toLowerCase();
519
+ if (name.length == 0) {
520
+ return name;
521
+ }
522
+ if (name[0].match(/\d/)) {
523
+ name = '_' + name;
524
+ }
525
+ let result = '';
526
+ for (let i = 0; i < name.length; i++) {
527
+ if (!name[i].match(/[a-z0-9_]/)) {
528
+ result += '_';
529
+ }
530
+ else {
531
+ result += name[i];
532
+ }
533
+ }
534
+ return result;
535
+ }
536
+ function getKeymanWebCompiledNameFromFileName(filename) {
537
+ let m = /([^/\\]+)$/.exec(filename);
538
+ if (!m) {
539
+ return null;
540
+ }
541
+ m = /^(.+?)(\.[^.]+)?$/.exec(m[1]);
542
+ if (!m) {
543
+ return null;
544
+ }
545
+ return cleanKeyboardID(m[1]);
546
+ }
547
+ //# sourceMappingURL=kmw-compiler.js.map