@keymanapp/kmc-kmn 18.0.40-alpha → 18.0.45-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,855 +1,852 @@
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]="b36da389-b79e-5e9b-92b2-425c80ccf066")}catch(e){}}();
3
- import { GetSuppChar, ExpandSentinel, incxstr, xstrlen, xstrlen_printing } from "./util.js";
4
- import { KMX } from "@keymanapp/common-types";
5
- import { callbacks, FCallFunctions, FFix183_LadderLength, FMnemonic, FTabStop, FUnreachableKeys, IsKeyboardVersion10OrLater, IsKeyboardVersion14OrLater, kmxResult, nl, options } from "./compiler-globals.js";
6
- import { KmwCompilerMessages } from "./kmw-compiler-messages.js";
7
- import { FormatModifierAsBitflags, RuleIsExcludedByPlatform } from "./kmw-compiler.js";
8
- import { KMXCodeNames, SValidIdentifierCharSet, UnreachableKeyCodes, USEnglishShift, USEnglishUnshift, USEnglishValues } from "./constants.js";
9
- import { KMWVKeyNames, VKeyNames } from "./keymanweb-key-codes.js";
10
- export function JavaScript_Name(i, pwszName, KeepNameForPersistentStorage = false) {
11
- let FChanged = false;
12
- let p = pwszName;
13
- if ((pwszName == null || pwszName == undefined || pwszName == '') || (!options.saveDebug && !KeepNameForPersistentStorage)) { // I3659 // I3681
14
- return i.toString(10); // for uniqueness
15
- }
16
- else {
17
- let result = KeepNameForPersistentStorage // I3659
18
- ? '' // Potential for overlap in theory but in practice we only use this for named option stores so can never overlap
19
- : '_'; // Ensures we cannot overlap numbered instances
20
- while (p.length) {
21
- let ch = p.charAt(0);
22
- if (SValidIdentifierCharSet.test(ch)) { // I3681
23
- result += ch;
24
- }
25
- else {
26
- result += '_';
27
- FChanged = true;
28
- }
29
- p = p.substring(1);
30
- }
31
- if (!KeepNameForPersistentStorage) {
32
- // Ensure each transformed name is still unique
33
- result += '_' + i.toString(10);
34
- if (FChanged) {
35
- result += '/*' + pwszName.replace(/\*\//g, '*-/') + '*/';
36
- }
37
- }
38
- else if (FChanged) {
39
- // For named option stores, we are only supporting the valid identifier
40
- // character set, which is a breaking change in 14.0.
41
- callbacks.reportMessage(KmwCompilerMessages.Warn_OptionStoreNameInvalid({ name: pwszName }));
42
- }
43
- return result;
44
- }
45
- }
46
- export function JavaScript_Store(fk, line, pwsz) {
47
- let ch, rec, result;
48
- const wcsentinel = String.fromCharCode(KMX.KMXFile.UC_SENTINEL);
49
- let n = pwsz.indexOf(wcsentinel);
50
- // Start: plain text store. Always use for < 10.0, conditionally for >= 10.0.
51
- if (n < 0 || !IsKeyboardVersion10OrLater()) {
52
- result = '"';
53
- while (pwsz.length) {
54
- if (pwsz.charCodeAt(0) == KMX.KMXFile.UC_SENTINEL) {
55
- result += '.'; // UC_SENTINEL values are not supported in stores for KMW < 10.0.
56
- }
57
- else {
58
- ch = GetSuppChar(pwsz, 0);
59
- if (ch == '"'.charCodeAt(0) || ch == '\\'.charCodeAt(0)) {
60
- result += '\\';
61
- }
62
- result += JavaScript_String(ch); // I2242
63
- }
64
- const x = incxstr(pwsz, 0);
65
- pwsz = pwsz.substring(x);
66
- }
67
- result += '"';
68
- }
69
- else {
70
- result = '[';
71
- let x = 0;
72
- while (x < pwsz.length) {
73
- if (result != '[') {
74
- result += ',';
75
- }
76
- rec = ExpandSentinel(fk, pwsz, x);
77
- if (rec.IsSentinel) {
78
- if (rec.Code == KMX.KMXFile.CODE_DEADKEY) {
79
- result += `{t:'d',d:${rec.DeadKey.DeadKey}}`;
80
- }
81
- else if (rec.Code == KMX.KMXFile.CODE_BEEP) {
82
- result += `{t:'b'}`;
83
- }
84
- else { //if rec.Code = CODE_EXTENDED then
85
- // At some point, we may wish to filter which codes are safe to stub out like this
86
- // versus which ones should be an error. The commented-out-code shows the way to
87
- // handle such cases.
88
- result += `''`;
89
- }
90
- // else
91
- // begin
92
- // //ReportError(line, CERR_SomewhereIGotItWrong, 'Internal Error: unexpected sentinel character in store definition');
93
- // end;
94
- }
95
- else {
96
- ch = GetSuppChar(pwsz, x);
97
- result += '"';
98
- // TODO: Refactor the section below into JavaScript_String, as it's
99
- // quite common in our code base.
100
- if (ch == '"'.charCodeAt(0) || ch == '\\'.charCodeAt(0)) {
101
- result += '\\';
102
- }
103
- result += JavaScript_String(ch) + '"'; // I2242
104
- }
105
- x = incxstr(pwsz, x);
106
- }
107
- result += ']';
108
- }
109
- return result;
110
- }
111
- export function JavaScript_String(ch) {
112
- if (ch < 32) {
113
- switch (ch) {
114
- case 9: return '\\t';
115
- case 10: return '\\n';
116
- case 13: return '\\r';
117
- }
118
- return '\\x' + zeroPadHex(ch, 2);
119
- }
120
- else {
121
- // Note: unpaired surrogates will be maintained
122
- return String.fromCodePoint(ch);
123
- }
124
- }
125
- function JavaScript_Rule(FTabStops, FElse, fk, fgp, fkp) {
126
- let predicate = '1', linecomment = '', FIndent;
127
- let result = '';
128
- if (fkp.Line > 0 && options.saveDebug) { // I4384
129
- linecomment = ' // Line ' + fkp.Line.toString(); // I4373
130
- }
131
- if (xstrlen(fkp.dpContext) > 0) {
132
- predicate = JavaScript_ContextMatch(fk, fkp, fkp.dpContext);
133
- }
134
- FIndent = FTabStops + FTabStop;
135
- result = `${FTabStops}${FElse}if(${predicate}){${nl}`;
136
- if (fgp.fUsingKeys) {
137
- result += `${FIndent}r=m=1;${linecomment}${JavaScript_OutputString(fk, FIndent, fkp, fkp.dpOutput, fgp)}`; // I1959 // I3681
138
- }
139
- else {
140
- result += `${FIndent}m=1;${linecomment}${JavaScript_OutputString(fk, FIndent, fkp, fkp.dpOutput, fgp)}`; // I1959 // I3681
141
- }
142
- result += `${nl}${FTabStops}}${nl}`;
143
- return result;
144
- }
145
- export function JavaScript_Rules(keyboard, fMnemonic, fgp) {
146
- let IsEqualKey = function (k1, k2) {
147
- return ((JavaScript_Key(k1, FMnemonic) == JavaScript_Key(k2, FMnemonic)) &&
148
- (JavaScript_Shift(k1, FMnemonic) == JavaScript_Shift(k2, FMnemonic)));
149
- };
150
- let result = '';
151
- let HasRules = false;
152
- let processed_rule = Array(fgp.keys.length);
153
- for (let j = 0; j < fgp.keys.length; j++) {
154
- processed_rule[j] = false;
155
- }
156
- let j = 0;
157
- let Counter = 0;
158
- while (j < fgp.keys.length) { // I1964
159
- let fkp = fgp.keys[j];
160
- if (!processed_rule[j] && !RuleIsExcludedByPlatform(keyboard, fkp)) {
161
- // Break down by key code
162
- // We know the rules are sorted by context length and then key code.
163
- // First pass, break the grouping down by key code.
164
- if (fgp.fUsingKeys) {
165
- result +=
166
- `${FTabStop + FTabStop}${HasRules ? 'else ' : ''}` +
167
- `if(k.KKM(e,${JavaScript_ShiftAsString(fkp, fMnemonic)},${JavaScript_KeyAsString(fkp, fMnemonic)})) {${nl}`;
168
- HasRules = true;
169
- Counter++;
170
- let LocalHasRules = false;
171
- let fkp2 = fgp.keys[j];
172
- let j2 = j;
173
- let LocalCounter = 0;
174
- while (j < fgp.keys.length) {
175
- fkp = fgp.keys[j];
176
- if (!processed_rule[j] && !RuleIsExcludedByPlatform(keyboard, fkp) && IsEqualKey(fkp, fkp2)) {
177
- processed_rule[j] = true;
178
- result += JavaScript_Rule(FTabStop + FTabStop + FTabStop, LocalHasRules ? 'else ' : '', keyboard, fgp, fkp);
179
- LocalCounter++;
180
- if (FFix183_LadderLength != 0 && (LocalCounter % FFix183_LadderLength) == 0) {
181
- // Break if/else ladders
182
- result += `${FTabStop + FTabStop + FTabStop}if(m) {}${nl}`;
183
- }
184
- LocalHasRules = true;
185
- }
186
- j++;
187
- }
188
- result += FTabStop + FTabStop + '}' + nl;
189
- j = j2 + 1;
190
- }
191
- else {
192
- // TODO: context character level switches instead of full context comparisons
193
- result += JavaScript_Rule(FTabStop + FTabStop + FTabStop, HasRules ? 'else ' : '', keyboard, fgp, fkp);
194
- HasRules = true;
195
- Counter++;
196
- j++;
197
- }
198
- if (FFix183_LadderLength != 0 && (Counter % FFix183_LadderLength) == 0) {
199
- // Break if/else ladders
200
- // We need to only match if no previous line is matched (i.e. m is false)
201
- result += `${FTabStop + FTabStop + FTabStop}if(m) {}${nl}`;
202
- }
203
- }
204
- else {
205
- j++;
206
- }
207
- }
208
- return result;
209
- }
210
- export function JavaScript_Shift(fkp, FMnemonic) {
211
- if (FMnemonic) {
212
- if (fkp.ShiftFlags & KMX.KMXFile.VIRTUALCHARKEY) {
213
- callbacks.reportMessage(KmwCompilerMessages.Error_VirtualCharacterKeysNotSupportedInKeymanWeb({ line: fkp.Line }));
214
- return 0;
215
- }
216
- if (fkp.ShiftFlags & KMX.KMXFile.ISVIRTUALKEY && fkp.Key <= 255) {
217
- // We prohibit K_ keys for mnemonic layouts. We don't block T_ and U_ keys.
218
- // TODO: this doesn't resolve the issue of, e.g. SHIFT+K_SPACE
219
- // https://github.com/keymanapp/keyman/issues/265
220
- callbacks.reportMessage(KmwCompilerMessages.Error_VirtualKeysNotValidForMnemonicLayouts({ line: fkp.Line }));
221
- return 0;
222
- }
223
- }
224
- if (fkp.ShiftFlags & KMX.KMXFile.ISVIRTUALKEY) {
225
- if (IsKeyboardVersion10OrLater()) {
226
- // Full chiral modifier and state key support starts with KeymanWeb 10.0
227
- return fkp.ShiftFlags;
228
- }
229
- // Non-chiral support only and no support for state keys
230
- if (fkp.ShiftFlags & (KMX.KMXFile.LCTRLFLAG | KMX.KMXFile.RCTRLFLAG | KMX.KMXFile.LALTFLAG | KMX.KMXFile.RALTFLAG)) { // I4118
231
- callbacks.reportMessage(KmwCompilerMessages.Warn_ExtendedShiftFlagsNotSupportedInKeymanWeb({ line: fkp.Line, flags: 'LALT, RALT, LCTRL, RCTRL' }));
232
- }
233
- if (fkp.ShiftFlags & (KMX.KMXFile.CAPITALFLAG | KMX.KMXFile.NOTCAPITALFLAG | KMX.KMXFile.NUMLOCKFLAG | KMX.KMXFile.NOTNUMLOCKFLAG |
234
- KMX.KMXFile.SCROLLFLAG | KMX.KMXFile.NOTSCROLLFLAG)) { // I4118
235
- callbacks.reportMessage(KmwCompilerMessages.Warn_ExtendedShiftFlagsNotSupportedInKeymanWeb({ line: fkp.Line, flags: 'CAPS and NCAPS' }));
236
- }
237
- return KMX.KMXFile.ISVIRTUALKEY | (fkp.ShiftFlags & (KMX.KMXFile.K_SHIFTFLAG | KMX.KMXFile.K_CTRLFLAG | KMX.KMXFile.K_ALTFLAG));
238
- }
239
- return USEnglishShift.includes(String.fromCharCode(fkp.Key)) ? KMX.KMXFile.ISVIRTUALKEY | KMX.KMXFile.K_SHIFTFLAG : KMX.KMXFile.ISVIRTUALKEY;
240
- }
241
- /**
242
- * Returns a Javascript representation of a key modifier state, either as a constant (debug mode)
243
- * or as an integer.
244
- *
245
- * @param fkp Pointer to key record
246
- * @param FMnemonic True if the keyboard is a mnemonic layout
247
- *
248
- * @return string representation of the key modifier state, e.g.
249
- * 'modCodes.SHIFT | modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4110 * /' or
250
- * '16656'
251
- */
252
- export function JavaScript_ShiftAsString(fkp, FMnemonic) {
253
- if (!options.saveDebug) {
254
- return JavaScript_Shift(fkp, FMnemonic).toString();
255
- }
256
- return ' ' + FormatModifierAsBitflags(JavaScript_Shift(fkp, FMnemonic));
257
- }
258
- function FormatKeyForErrorMessage(fkp, FMnemonic) {
259
- function FormatShift(ShiftFlags) {
260
- const mask = [
261
- 'LCTRL',
262
- 'RCTRL',
263
- 'LALT',
264
- 'RALT',
265
- 'SHIFT',
266
- 'CTRL',
267
- 'ALT',
268
- '???',
269
- 'CAPS',
270
- 'NCAPS',
271
- 'NUMLOCK',
272
- 'NNUMLOCK',
273
- 'SCROLLLOCK',
274
- 'NSCROLLLOCK' // 0X2000
275
- ];
276
- let result = '';
277
- for (let i = 0; i < mask.length; i++) {
278
- if (ShiftFlags & (1 << i)) {
279
- result += mask[i] + ' ';
280
- }
281
- }
282
- return result;
283
- }
284
- let result;
285
- if (!FMnemonic) {
286
- if (fkp.ShiftFlags & KMX.KMXFile.ISVIRTUALKEY) {
287
- if (fkp.Key < 256) {
288
- result = `[${FormatShift(fkp.ShiftFlags)}${VKeyNames[fkp.Key]}]`;
289
- }
290
- else {
291
- result = `[${FormatShift(fkp.ShiftFlags)}K_${fkp.Key.toString(16).toUpperCase()}]`;
292
- }
293
- }
294
- else {
295
- result = `'${String.fromCharCode(fkp.Key)}'`;
296
- }
297
- }
298
- else {
299
- if (fkp.ShiftFlags & KMX.KMXFile.VIRTUALCHARKEY) {
300
- result = `[${FormatShift(fkp.ShiftFlags)}'${String.fromCharCode(fkp.Key)}']`;
301
- }
302
- else {
303
- result = `'${String.fromCharCode(fkp.Key)}'`;
304
- }
305
- }
306
- return result;
307
- }
308
- export function JavaScript_Key(fkp, FMnemonic) {
309
- let Result;
310
- if (!FMnemonic) {
311
- if (fkp.ShiftFlags & KMX.KMXFile.ISVIRTUALKEY) {
312
- Result = fkp.Key;
313
- }
314
- else {
315
- // Convert the character to a virtual key
316
- let n = USEnglishShift.indexOf(String.fromCharCode(fkp.Key));
317
- if (n < 0) {
318
- n = USEnglishUnshift.indexOf(String.fromCharCode(fkp.Key));
319
- }
320
- if (n < 0) {
321
- Result = 0;
322
- }
323
- else {
324
- Result = USEnglishValues.charCodeAt(n);
325
- }
326
- }
327
- }
328
- else {
329
- Result = fkp.Key;
330
- }
331
- // Check that key is not unreachable (e.g. K_SHIFT, touch-specific special keys 50,000+)
332
- if (UnreachableKeyCodes.indexOf(Result) >= 0) {
333
- Result = 0;
334
- }
335
- if (Result == 0 || Result >= 50001 /* TKeymanWebTouchStandardKey.K_LOPT */) { // I4141
336
- if (!FUnreachableKeys.includes(fkp)) {
337
- callbacks.reportMessage(KmwCompilerMessages.Hint_UnreachableKeyCode({ line: fkp.Line, key: FormatKeyForErrorMessage(fkp, FMnemonic) }));
338
- FUnreachableKeys.push(fkp);
339
- }
340
- }
341
- return Result;
342
- }
343
- /**
344
- * Returns a Javascript representation of a key value, either as a constant (debug mode)
345
- * or as an integer.
346
- *
347
- * @param fkp Pointer to key record
348
- * @param FMnemonic True if the keyboard is a mnemonic layout
349
- *
350
- * @return string representation of the key value, e.g. 'keyCodes.K_A /* 0x41 * /' or '65'
351
- */
352
- export function JavaScript_KeyAsString(fkp, FMnemonic) {
353
- if (options.saveDebug) {
354
- return ' ' + FormatKeyAsString(JavaScript_Key(fkp, FMnemonic));
355
- }
356
- else {
357
- return JavaScript_Key(fkp, FMnemonic).toString();
358
- }
359
- }
360
- export function JavaScript_ContextMatch(fk, fkp, context) {
361
- if (IsKeyboardVersion10OrLater()) {
362
- return JavaScript_FullContextValue(fk, fkp, context);
363
- }
364
- else {
365
- return JavaScript_CompositeContextValue(fk, fkp, context);
366
- }
367
- }
368
- function JavaScript_ContextLength(Context) {
369
- return xstrlen_printing(Context);
370
- }
371
- function GetCodeName(code) {
372
- if (code >= 0 && code < KMXCodeNames.length && KMXCodeNames[code] != '') {
373
- return KMXCodeNames[code];
374
- }
375
- return code.toString();
376
- }
377
- function CheckStoreForInvalidFunctions(fk, key, store) {
378
- let n, rec;
379
- const wcsentinel = String.fromCharCode(0xFFFF);
380
- n = store.dpString.indexOf(wcsentinel);
381
- // Disable the check with versions >= 10.0, since we now support deadkeys in stores.
382
- if (n >= 0 && !IsKeyboardVersion10OrLater) {
383
- rec = ExpandSentinel(fk, store.dpString, n);
384
- callbacks.reportMessage(KmwCompilerMessages.Error_NotSupportedInKeymanWebStore({ code: GetCodeName(rec.Code), store: store.dpName }));
385
- }
386
- }
387
- // Used when targeting versions prior to 10.0, before the introduction of FullContextMatch/KFCM.
388
- function JavaScript_CompositeContextValue(fk, fkp, pwsz) {
389
- let Result = '';
390
- let InQuotes = false;
391
- let Len = JavaScript_ContextLength(pwsz);
392
- let StartQuotes = -1;
393
- let x = 0, Cur = 0;
394
- while (x < pwsz.length) {
395
- let rec = ExpandSentinel(fk, pwsz, x);
396
- if (rec.IsSentinel) {
397
- if (InQuotes) {
398
- Result += `",${Cur - StartQuotes})`;
399
- InQuotes = false;
400
- }
401
- if (Result != '') {
402
- Result += '&&';
403
- }
404
- switch (rec.Code) {
405
- case KMX.KMXFile.CODE_ANY:
406
- CheckStoreForInvalidFunctions(fk, fkp, rec.Any.Store); // I1520
407
- Result += `k.KA(${Cur},k.KC(${Len - Cur},1,t),this.s${JavaScript_Name(rec.Any.StoreIndex, rec.Any.Store.dpName)})`;
408
- break;
409
- case KMX.KMXFile.CODE_DEADKEY:
410
- Result += `k.KDM(${Len - Cur},t,${rec.DeadKey.DeadKey})`;
411
- Cur--; // don't increment on deadkeys -- correlates with AdjustIndex function // I3910
412
- break;
413
- case KMX.KMXFile.CODE_NUL: // I2243
414
- Result += `k.KN(${Len - Cur},t)`;
415
- Cur--; // don't increment on nul -- correlates with AdjustIndex function // I3910
416
- break;
417
- case KMX.KMXFile.CODE_IFOPT: // I3429
418
- Result += `this.s${JavaScript_Name(rec.IfOpt.StoreIndex1, rec.IfOpt.Store1.dpName)}` +
419
- `${rec.IfOpt.IsNot == 0 ? '!==' : '==='}` +
420
- `this.s${JavaScript_Name(rec.IfOpt.StoreIndex2, rec.IfOpt.Store2.dpName)}`; // I3429 // I3659 // I3681
421
- Cur--; // don't increment on ifopt -- correlates with AdjustIndex function // I3910
422
- break;
423
- case KMX.KMXFile.CODE_IFSYSTEMSTORE: // I3430
424
- Result += `${rec.IfSystemStore.IsNot == 0 ? '!' : ''}` +
425
- `k.KIFS(${rec.IfSystemStore.dwSystemID},` +
426
- `this.s${JavaScript_Name(rec.IfSystemStore.StoreIndex, rec.IfSystemStore.Store.dpName)},t)`;
427
- Cur--; // don't increment on ifsystemstore -- correlates with AdjustIndex function // I3910
428
- break;
429
- case KMX.KMXFile.CODE_CONTEXTEX: // I3980
430
- Result += `k.KCCM(${Len - Cur},${Len - rec.ContextEx.Index},t)`;
431
- break;
432
- case KMX.KMXFile.CODE_NOTANY: // I3981
433
- CheckStoreForInvalidFunctions(fk, fkp, rec.Any.Store); // I1520
434
- Result += `k.KC(${Len - Cur},1,t)!=""&&!k.KA(${Cur},k.KC(${Len - Cur},1,t),` +
435
- `this.s${JavaScript_Name(rec.Any.StoreIndex, rec.Any.Store.dpName)})`;
436
- break;
437
- default:
438
- callbacks.reportMessage(KmwCompilerMessages.Error_NotSupportedInKeymanWebContext({ line: fkp.Line, code: GetCodeName(rec.Code) }));
439
- Result += '/*.*/ 0 ';
440
- }
441
- }
442
- else {
443
- if (!InQuotes) {
444
- if (Result != '') {
445
- Result += '&&';
446
- }
447
- Result += `k.KCM(${Len - Cur},t,"`;
448
- StartQuotes = Cur;
449
- InQuotes = true;
450
- }
451
- if (rec.ChrVal == '"'.charCodeAt(0) || rec.ChrVal == '\\'.charCodeAt(0)) {
452
- Result += '\\';
453
- }
454
- Result += JavaScript_String(rec.ChrVal); // I2242
455
- }
456
- Cur++;
457
- x = incxstr(pwsz, x);
458
- }
459
- if (InQuotes) {
460
- Result += `",${Cur - StartQuotes})`;
461
- }
462
- return Result;
463
- }
464
- // Used when targeting versions >= 10.0, after the introduction of FullContextMatch/KFCM.
465
- function JavaScript_FullContextValue(fk, fkp, pwsz) {
466
- let Result = '';
467
- let FullContext = '';
468
- let Suffix = '';
469
- let Len = xstrlen(pwsz);
470
- let x = 0;
471
- while (x < pwsz.length) {
472
- if (FullContext != '') {
473
- FullContext += ',';
474
- }
475
- let rec = ExpandSentinel(fk, pwsz, x);
476
- if (rec.IsSentinel) {
477
- switch (rec.Code) {
478
- case KMX.KMXFile.CODE_ANY:
479
- CheckStoreForInvalidFunctions(fk, fkp, rec.Any.Store); // I1520
480
- FullContext += `{t:'a',a:this.s${JavaScript_Name(rec.Any.StoreIndex, rec.Any.Store.dpName)}}`;
481
- break;
482
- case KMX.KMXFile.CODE_DEADKEY:
483
- FullContext += `{t:'d',d:${rec.DeadKey.DeadKey}}`;
484
- break;
485
- case KMX.KMXFile.CODE_NUL: // I2243
486
- FullContext += `{t:'n'}`;
487
- break;
488
- case KMX.KMXFile.CODE_IFOPT: // I3429
489
- Len--;
490
- if (Suffix != '') {
491
- Suffix += '&&';
492
- }
493
- if (FullContext == ',') {
494
- FullContext = '';
495
- }
496
- Suffix += `this.s${JavaScript_Name(rec.IfOpt.StoreIndex1, rec.IfOpt.Store1.dpName)}` +
497
- `${rec.IfOpt.IsNot == 0 ? '!==' : '==='}this.s${JavaScript_Name(rec.IfOpt.StoreIndex2, rec.IfOpt.Store2.dpName)}`; // I3429 // I3659 // I3681
498
- break;
499
- case KMX.KMXFile.CODE_IFSYSTEMSTORE: // I3430
500
- Len--;
501
- if (Suffix != '') {
502
- Suffix += '&&';
503
- }
504
- if (FullContext == ',') {
505
- FullContext = '';
506
- }
507
- Suffix += `${rec.IfSystemStore.IsNot == 0 ? '!' : ''}k.KIFS(${rec.IfSystemStore.dwSystemID},` +
508
- `this.s${JavaScript_Name(rec.IfSystemStore.StoreIndex, rec.IfSystemStore.Store.dpName)},t)`; // I3430 // I3659 // I3681
509
- break;
510
- case KMX.KMXFile.CODE_NOTANY: // I3981
511
- CheckStoreForInvalidFunctions(fk, fkp, rec.Any.Store); // I1520
512
- FullContext += `{t:'a',a:this.s${JavaScript_Name(rec.Any.StoreIndex, rec.Any.Store.dpName)},n:1}`;
513
- break;
514
- case KMX.KMXFile.CODE_CONTEXTEX:
515
- FullContext += `{t:'c',c:${rec.ContextEx.Index + 1}}`; // I4611
516
- break;
517
- case KMX.KMXFile.CODE_INDEX:
518
- FullContext += `{t:'i',i:this.s${JavaScript_Name(rec.Index.StoreIndex, rec.Index.Store.dpName)},` +
519
- `o:${rec.Index.Index}}`; // I4611
520
- break;
521
- default:
522
- callbacks.reportMessage(KmwCompilerMessages.Error_NotSupportedInKeymanWebContext({ line: fkp.Line, code: GetCodeName(rec.Code) }));
523
- Result += '/*.*/ 0 ';
524
- }
525
- }
526
- else { // Simple context character.
527
- FullContext += `'`;
528
- if (rec.ChrVal == '"'.charCodeAt(0) || rec.ChrVal == '\\'.charCodeAt(0) || rec.ChrVal == '\''.charCodeAt(0)) {
529
- FullContext += '\\';
530
- }
531
- FullContext += JavaScript_String(rec.ChrVal) + `'`; // I2242
532
- }
533
- x = incxstr(pwsz, x);
534
- }
535
- if (FullContext != '') {
536
- Result = `k.KFCM(${Len},t,[${FullContext}])`;
537
- }
538
- if (Result != '' && Suffix != '') {
539
- Result += '&&' + Suffix;
540
- }
541
- else if (Suffix != '') {
542
- Result = Suffix;
543
- }
544
- return Result;
545
- }
546
- function isGroupReadOnly(fk, fgp) {
547
- const index = fk.groups.indexOf(fgp);
548
- return kmxResult.extra.groups[index].isReadOnly;
549
- }
550
- function CallFunctionName(s) {
551
- let n;
552
- n = s.indexOf(':');
553
- return s.substring(n + 1); // not found gives -1, substring(0) is ok :grin:
554
- }
555
- export function JavaScript_OutputString(fk, FTabStops, fkp, pwszOutput, fgp) {
556
- let InQuotes = false;
557
- let len = 0;
558
- const nlt = nl + FTabStops; // I3681
559
- const AdjustIndex = function (pwszContext, Index) {
560
- let Result = Index;
561
- let x = 0;
562
- for (let I = 1; I < Index; I++) {
563
- let recContext = ExpandSentinel(fk, pwszContext, x);
564
- if (IsKeyboardVersion10OrLater()) {
565
- if (recContext.IsSentinel && [KMX.KMXFile.CODE_NUL, KMX.KMXFile.CODE_IFOPT, KMX.KMXFile.CODE_IFSYSTEMSTORE].includes(recContext.Code)) {
566
- Result--;
567
- }
568
- }
569
- else {
570
- if (recContext.IsSentinel && [KMX.KMXFile.CODE_DEADKEY, KMX.KMXFile.CODE_NUL, KMX.KMXFile.CODE_IFOPT, KMX.KMXFile.CODE_IFSYSTEMSTORE].includes(recContext.Code)) {
571
- Result--;
572
- }
573
- }
574
- x = incxstr(pwszContext, x);
575
- }
576
- return Result;
577
- };
578
- const ContextChar = function (ContextIndex, pwszContext, xContext) {
579
- let Index;
580
- let Result = '';
581
- let recContext = ExpandSentinel(fk, pwszContext, xContext);
582
- if (recContext.IsSentinel) {
583
- if (InQuotes) { // I4611
584
- Result += '");';
585
- InQuotes = false;
586
- }
587
- switch (recContext.Code) {
588
- case KMX.KMXFile.CODE_ANY:
589
- Index = AdjustIndex(fkp.dpContext, ContextIndex) + 1; // I3910 // I4611
590
- Result += nlt + `k.KIO(${len},this.s${JavaScript_Name(recContext.Any.StoreIndex, recContext.Any.Store.dpName)},${Index},t);`; // I4611
591
- break;
592
- case KMX.KMXFile.CODE_DEADKEY:
593
- Result += nlt + `k.KDO(${len},t,${recContext.DeadKey.DeadKey});`; // I4611
594
- break;
595
- case KMX.KMXFile.CODE_NOTANY:
596
- // #917: Minimum version required is 14.0: the KCXO function was only added for 14.0
597
- // Note that this is checked in compiler.cpp as well, so this error can probably never occur
598
- if (!IsKeyboardVersion14OrLater()) {
599
- callbacks.reportMessage(KmwCompilerMessages.Error_NotAnyRequiresVersion14({ line: fkp.Line }));
600
- }
601
- Result += nlt + `k.KCXO(${len},t,${AdjustIndex(fkp.dpContext, xstrlen(fkp.dpContext))},${AdjustIndex(fkp.dpContext, ContextIndex) + 1});`;
602
- break;
603
- case KMX.KMXFile.CODE_IFOPT:
604
- case KMX.KMXFile.CODE_IFSYSTEMSTORE:
605
- case KMX.KMXFile.CODE_NUL:
606
- // These have no output for a context emit
607
- break;
608
- default:
609
- callbacks.reportMessage(KmwCompilerMessages.Error_NotSupportedInKeymanWebContext({ line: fkp.Line, code: GetCodeName(recContext.Code) }));
610
- Result += nlt + '/*.*/ '; // I4611
611
- }
612
- }
613
- else {
614
- if (!InQuotes) {
615
- Result += nlt + `k.KO(${len},t,"`; // I4611
616
- InQuotes = true;
617
- }
618
- if (recContext.ChrVal == '"'.charCodeAt(0) || recContext.ChrVal == '\\'.charCodeAt(0)) {
619
- Result += '\\';
620
- }
621
- Result += JavaScript_String(recContext.ChrVal); // I2242
622
- }
623
- return Result;
624
- };
625
- let Result = '';
626
- InQuotes = false;
627
- let pwsz = pwszOutput;
628
- if (fkp != null) {
629
- if (IsKeyboardVersion10OrLater()) {
630
- // KMW >= 10.0 use the full, sentinel-based length for context deletions.
631
- len = xstrlen(fkp.dpContext);
632
- let n = len;
633
- let x = 0;
634
- for (let i = 0; i < n; i++) {
635
- let rec = ExpandSentinel(fk, fkp.dpContext, x);
636
- if (rec.IsSentinel && [KMX.KMXFile.CODE_NUL, KMX.KMXFile.CODE_IFOPT, KMX.KMXFile.CODE_IFSYSTEMSTORE].includes(rec.Code)) {
637
- len--;
638
- }
639
- x = incxstr(fkp.dpContext, x);
640
- }
641
- }
642
- else {
643
- // KMW < 10.0 exclude all sentinel-based characters, including deadkeys, from direct context deletion.
644
- // Deadkeys have alternative special handling.
645
- len = xstrlen_printing(fkp.dpContext);
646
- }
647
- }
648
- else {
649
- len = -1;
650
- }
651
- let x = 0;
652
- if (IsKeyboardVersion10OrLater() && pwsz.length > 0) {
653
- if (!isGroupReadOnly(fk, fgp)) {
654
- Result += nlt + `k.KDC(${len},t);`; // I3681
655
- }
656
- len = -1;
657
- }
658
- while (x < pwsz.length) {
659
- let rec = ExpandSentinel(fk, pwsz, x);
660
- if (rec.IsSentinel) {
661
- if (InQuotes) {
662
- if (!isGroupReadOnly(fk, fgp)) {
663
- Result += '");';
664
- }
665
- InQuotes = false;
666
- }
667
- switch (rec.Code) {
668
- case KMX.KMXFile.CODE_CONTEXT:
669
- if (x > 0 || len == -1) {
670
- let xContext = 0;
671
- let n = 0;
672
- while (xContext < fkp.dpContext.length) { // I4611
673
- if (!isGroupReadOnly(fk, fgp)) {
674
- Result += ContextChar(n, fkp.dpContext, xContext);
675
- }
676
- n++;
677
- xContext = incxstr(fkp.dpContext, xContext);
678
- }
679
- //Result := Result + Format('k.KO(%d,t,k.KC(%d,%d,t));', [len, xstrlen_printing(fkp.dpContext), xstrlen_printing(fkp.dpContext)]);
680
- }
681
- // else, we don't need to output anything - just don't delete the context
682
- len = -1;
683
- break;
684
- case KMX.KMXFile.CODE_CONTEXTEX:
685
- let xContext = 0;
686
- for (let i = 0; i < rec.ContextEx.Index; i++) {
687
- xContext = incxstr(fkp.dpContext, xContext);
688
- }
689
- if (!isGroupReadOnly(fk, fgp)) {
690
- Result += ContextChar(rec.ContextEx.Index, fkp.dpContext, xContext); // I4611
691
- }
692
- len = -1;
693
- break;
694
- case KMX.KMXFile.CODE_BEEP:
695
- if (!isGroupReadOnly(fk, fgp)) {
696
- if (len > 0) {
697
- Result += nlt + `k.KO(${len},t,"");`; // I3681
698
- }
699
- Result += nlt + 'k.KB(t);'; // I3681
700
- }
701
- len = -1;
702
- break;
703
- case KMX.KMXFile.CODE_NUL:
704
- if (!isGroupReadOnly(fk, fgp)) {
705
- if (len > 0) {
706
- Result += nlt + `k.KO(${len},t,"");`; // I3681
707
- }
708
- }
709
- len = -1;
710
- break;
711
- case KMX.KMXFile.CODE_INDEX:
712
- CheckStoreForInvalidFunctions(fk, fkp, rec.Index.Store); // I1520
713
- // This code was wrong. We need to ignore CODE_NUL, CODE_DEADKEY in LHS context index counter.
714
- // This is why the compiler goes wrong -- and why the previous fix was inconsistent.
715
- // The I783 test did not test either of these cases. It seems some of the keyboards were
716
- // compiled in-between the original fix and I783 re-fix, and then happened to work due to
717
- // their simplicity.
718
- let Index = AdjustIndex(fkp.dpContext, rec.Index.Index); // I3910
719
- if (!isGroupReadOnly(fk, fgp)) {
720
- Result += nlt + `k.KIO(${len},this.s${JavaScript_Name(rec.Index.StoreIndex, rec.Index.Store.dpName)},${Index},t);`;
721
- // I783 - was: rec.Index.Index [2007-06-04]
722
- // I783 again. Returned to rec.Index.Index. Was previously: [2008-08-15]
723
- // xstrlen(fkp.dpContext) + 1 - rec.Index.Index]);
724
- // this was wrong. Can't find any reason why this change was made
725
- // which suggests it was in response to another bug and poorly traced (bad Marc)
726
- // and not properly tested (bad, bad Marc). Anyway, now tested with test_i783
727
- }
728
- len = -1;
729
- break;
730
- case KMX.KMXFile.CODE_DEADKEY:
731
- if (!isGroupReadOnly(fk, fgp)) {
732
- Result += nlt + `k.KDO(${len},t,${rec.DeadKey.DeadKey});`; // I3681
733
- }
734
- len = -1;
735
- break;
736
- case KMX.KMXFile.CODE_USE:
737
- if (!isGroupReadOnly(fk, fgp)) {
738
- if (len > 0) {
739
- Result += nlt + `k.KO(${len},t,"");`; // I3681
740
- }
741
- }
742
- Result += nlt + `r=this.g${JavaScript_Name(rec.Use.GroupIndex, rec.Use.Group.dpName)}(t,e);`; // I1959 // I3681
743
- Result += nlt + 'm=2;'; // #5440 - match desktop behavior
744
- len = -1;
745
- break;
746
- case KMX.KMXFile.CODE_CALL:
747
- if (!isGroupReadOnly(fk, fgp)) {
748
- if (len > 0) {
749
- Result += nlt + `k.KO(${len},t,"");`; // I3681
750
- }
751
- }
752
- let n = FCallFunctions.indexOf(CallFunctionName(rec.Call.Store.dpString));
753
- if (n == -1) {
754
- n = FCallFunctions.push(CallFunctionName(rec.Call.Store.dpString)) - 1;
755
- }
756
- Result += nlt + `r=this.c${n}(t,e);`; // I1959 // I3681
757
- Result += nlt + 'm=2;'; // #5440 - match desktop behavior
758
- len = -1;
759
- break;
760
- case KMX.KMXFile.CODE_SETOPT: // I3429
761
- if (!isGroupReadOnly(fk, fgp)) {
762
- if (len > 0) {
763
- Result += nlt + `k.KO(${len},t,"");`; // I3681
764
- }
765
- }
766
- Result += nlt + `this.s${JavaScript_Name(rec.SetOpt.StoreIndex1, rec.SetOpt.Store1.dpName)}=` +
767
- `this.s${JavaScript_Name(rec.SetOpt.StoreIndex2, rec.SetOpt.Store2.dpName)};`;
768
- len = -1;
769
- break;
770
- case KMX.KMXFile.CODE_RESETOPT: // I3429
771
- if (!isGroupReadOnly(fk, fgp)) {
772
- if (len > 0) {
773
- Result += nlt + `k.KO(${len},t,"");`; // I3681
774
- }
775
- }
776
- Result += nlt + `this.s${JavaScript_Name(rec.ResetOpt.StoreIndex, rec.ResetOpt.Store.dpName)}=` +
777
- `k.KLOAD(this.KI,"${JavaScript_Name(rec.ResetOpt.StoreIndex, rec.ResetOpt.Store.dpName, true)}",` +
778
- `${JavaScript_Store(fk, fkp.Line, rec.ResetOpt.Store.dpString)});`; // I3429 // I3681 // I3659
779
- len = -1;
780
- break;
781
- case KMX.KMXFile.CODE_SAVEOPT: // I3429
782
- if (!isGroupReadOnly(fk, fgp)) {
783
- if (len > 0) {
784
- Result += nlt + `k.KO(${len},t,"");`; // I3681
785
- }
786
- }
787
- Result += nlt + `k.KSAVE("${JavaScript_Name(rec.SaveOpt.StoreIndex, rec.SaveOpt.Store.dpName, true)}",` +
788
- `this.s${JavaScript_Name(rec.SaveOpt.StoreIndex, rec.SaveOpt.Store.dpName)});`; // I3690 // I3429 // I3659 // I3681
789
- len = -1;
790
- break;
791
- case KMX.KMXFile.CODE_SETSYSTEMSTORE: // I3437
792
- if (!isGroupReadOnly(fk, fgp)) {
793
- if (len > 0) {
794
- Result += nlt + `k.KO(${len},t,"");`; // I3681
795
- }
796
- }
797
- Result += nlt + `k.KSETS(${rec.SetSystemStore.dwSystemID},` +
798
- `this.s${JavaScript_Name(rec.SetSystemStore.StoreIndex, rec.SetSystemStore.Store.dpName)},t);`; // I3681
799
- len = -1;
800
- break;
801
- default:
802
- callbacks.reportMessage(KmwCompilerMessages.Error_NotSupportedInKeymanWebOutput({ line: fkp.Line, code: GetCodeName(rec.Code) }));
803
- Result += '';
804
- }
805
- }
806
- else {
807
- if (!InQuotes) {
808
- if (!isGroupReadOnly(fk, fgp)) {
809
- Result += nlt + `k.KO(${len},t,"`; // I3681
810
- }
811
- InQuotes = true;
812
- len = -1;
813
- }
814
- if (!isGroupReadOnly(fk, fgp)) {
815
- if (rec.ChrVal == '"'.charCodeAt(0) || rec.ChrVal == '\\'.charCodeAt(0)) {
816
- Result += '\\';
817
- }
818
- Result += JavaScript_String(rec.ChrVal); // I2242
819
- }
820
- }
821
- x = incxstr(pwsz, x);
822
- }
823
- if (InQuotes) {
824
- if (!isGroupReadOnly(fk, fgp)) {
825
- Result += '");';
826
- }
827
- }
828
- return Result;
829
- }
830
- export function zeroPadHex(n, len) {
831
- let result = n.toString(16).toUpperCase();
832
- if (result.length < len) {
833
- return '0'.repeat(len - result.length) + result;
834
- }
835
- return result;
836
- }
837
- /**
838
- * Converts a key value into a constant
839
- *
840
- * @param key A virtual key code
841
- *
842
- * @return string of JavaScript code, e.g. 'keyCodes.K_A /* 0x41 * /'
843
- */
844
- function FormatKeyAsString(key) {
845
- if (IsKeyboardVersion10OrLater()) {
846
- // Depends on flags defined in KeymanWeb 10.0
847
- if (key <= 255 && KMWVKeyNames[key] != '') {
848
- return 'keyCodes.' + KMWVKeyNames[key] + ' /* 0x' + zeroPadHex(key, 2) + ' */';
849
- }
850
- return '0x' + zeroPadHex(key, 2);
851
- }
852
- return '0x' + zeroPadHex(key, 2);
853
- }
854
- //# sourceMappingURL=javascript-strings.js.map
855
- //# debugId=b36da389-b79e-5e9b-92b2-425c80ccf066
1
+ import { GetSuppChar, ExpandSentinel, incxstr, xstrlen, xstrlen_printing } from "./util.js";
2
+ import { KMX } from "@keymanapp/common-types";
3
+ import { callbacks, FCallFunctions, FFix183_LadderLength, FMnemonic, FTabStop, FUnreachableKeys, IsKeyboardVersion10OrLater, IsKeyboardVersion14OrLater, kmxResult, nl, options } from "./compiler-globals.js";
4
+ import { KmwCompilerMessages } from "./kmw-compiler-messages.js";
5
+ import { FormatModifierAsBitflags, RuleIsExcludedByPlatform } from "./kmw-compiler.js";
6
+ import { KMXCodeNames, SValidIdentifierCharSet, UnreachableKeyCodes, USEnglishShift, USEnglishUnshift, USEnglishValues } from "./constants.js";
7
+ import { KMWVKeyNames, VKeyNames } from "./keymanweb-key-codes.js";
8
+ export function JavaScript_Name(i, pwszName, KeepNameForPersistentStorage = false) {
9
+ let FChanged = false;
10
+ let p = pwszName;
11
+ if ((pwszName == null || pwszName == undefined || pwszName == '') || (!options.saveDebug && !KeepNameForPersistentStorage)) { // I3659 // I3681
12
+ return i.toString(10); // for uniqueness
13
+ }
14
+ else {
15
+ let result = KeepNameForPersistentStorage // I3659
16
+ ? '' // Potential for overlap in theory but in practice we only use this for named option stores so can never overlap
17
+ : '_'; // Ensures we cannot overlap numbered instances
18
+ while (p.length) {
19
+ let ch = p.charAt(0);
20
+ if (SValidIdentifierCharSet.test(ch)) { // I3681
21
+ result += ch;
22
+ }
23
+ else {
24
+ result += '_';
25
+ FChanged = true;
26
+ }
27
+ p = p.substring(1);
28
+ }
29
+ if (!KeepNameForPersistentStorage) {
30
+ // Ensure each transformed name is still unique
31
+ result += '_' + i.toString(10);
32
+ if (FChanged) {
33
+ result += '/*' + pwszName.replace(/\*\//g, '*-/') + '*/';
34
+ }
35
+ }
36
+ else if (FChanged) {
37
+ // For named option stores, we are only supporting the valid identifier
38
+ // character set, which is a breaking change in 14.0.
39
+ callbacks.reportMessage(KmwCompilerMessages.Warn_OptionStoreNameInvalid({ name: pwszName }));
40
+ }
41
+ return result;
42
+ }
43
+ }
44
+ export function JavaScript_Store(fk, line, pwsz) {
45
+ let ch, rec, result;
46
+ const wcsentinel = String.fromCharCode(KMX.KMXFile.UC_SENTINEL);
47
+ let n = pwsz.indexOf(wcsentinel);
48
+ // Start: plain text store. Always use for < 10.0, conditionally for >= 10.0.
49
+ if (n < 0 || !IsKeyboardVersion10OrLater()) {
50
+ result = '"';
51
+ while (pwsz.length) {
52
+ if (pwsz.charCodeAt(0) == KMX.KMXFile.UC_SENTINEL) {
53
+ result += '.'; // UC_SENTINEL values are not supported in stores for KMW < 10.0.
54
+ }
55
+ else {
56
+ ch = GetSuppChar(pwsz, 0);
57
+ if (ch == '"'.charCodeAt(0) || ch == '\\'.charCodeAt(0)) {
58
+ result += '\\';
59
+ }
60
+ result += JavaScript_String(ch); // I2242
61
+ }
62
+ const x = incxstr(pwsz, 0);
63
+ pwsz = pwsz.substring(x);
64
+ }
65
+ result += '"';
66
+ }
67
+ else {
68
+ result = '[';
69
+ let x = 0;
70
+ while (x < pwsz.length) {
71
+ if (result != '[') {
72
+ result += ',';
73
+ }
74
+ rec = ExpandSentinel(fk, pwsz, x);
75
+ if (rec.IsSentinel) {
76
+ if (rec.Code == KMX.KMXFile.CODE_DEADKEY) {
77
+ result += `{t:'d',d:${rec.DeadKey.DeadKey}}`;
78
+ }
79
+ else if (rec.Code == KMX.KMXFile.CODE_BEEP) {
80
+ result += `{t:'b'}`;
81
+ }
82
+ else { //if rec.Code = CODE_EXTENDED then
83
+ // At some point, we may wish to filter which codes are safe to stub out like this
84
+ // versus which ones should be an error. The commented-out-code shows the way to
85
+ // handle such cases.
86
+ result += `''`;
87
+ }
88
+ // else
89
+ // begin
90
+ // //ReportError(line, CERR_SomewhereIGotItWrong, 'Internal Error: unexpected sentinel character in store definition');
91
+ // end;
92
+ }
93
+ else {
94
+ ch = GetSuppChar(pwsz, x);
95
+ result += '"';
96
+ // TODO: Refactor the section below into JavaScript_String, as it's
97
+ // quite common in our code base.
98
+ if (ch == '"'.charCodeAt(0) || ch == '\\'.charCodeAt(0)) {
99
+ result += '\\';
100
+ }
101
+ result += JavaScript_String(ch) + '"'; // I2242
102
+ }
103
+ x = incxstr(pwsz, x);
104
+ }
105
+ result += ']';
106
+ }
107
+ return result;
108
+ }
109
+ export function JavaScript_String(ch) {
110
+ if (ch < 32) {
111
+ switch (ch) {
112
+ case 9: return '\\t';
113
+ case 10: return '\\n';
114
+ case 13: return '\\r';
115
+ }
116
+ return '\\x' + zeroPadHex(ch, 2);
117
+ }
118
+ else {
119
+ // Note: unpaired surrogates will be maintained
120
+ return String.fromCodePoint(ch);
121
+ }
122
+ }
123
+ function JavaScript_Rule(FTabStops, FElse, fk, fgp, fkp) {
124
+ let predicate = '1', linecomment = '', FIndent;
125
+ let result = '';
126
+ if (fkp.Line > 0 && options.saveDebug) { // I4384
127
+ linecomment = ' // Line ' + fkp.Line.toString(); // I4373
128
+ }
129
+ if (xstrlen(fkp.dpContext) > 0) {
130
+ predicate = JavaScript_ContextMatch(fk, fkp, fkp.dpContext);
131
+ }
132
+ FIndent = FTabStops + FTabStop;
133
+ result = `${FTabStops}${FElse}if(${predicate}){${nl}`;
134
+ if (fgp.fUsingKeys) {
135
+ result += `${FIndent}r=m=1;${linecomment}${JavaScript_OutputString(fk, FIndent, fkp, fkp.dpOutput, fgp)}`; // I1959 // I3681
136
+ }
137
+ else {
138
+ result += `${FIndent}m=1;${linecomment}${JavaScript_OutputString(fk, FIndent, fkp, fkp.dpOutput, fgp)}`; // I1959 // I3681
139
+ }
140
+ result += `${nl}${FTabStops}}${nl}`;
141
+ return result;
142
+ }
143
+ export function JavaScript_Rules(keyboard, fMnemonic, fgp) {
144
+ let IsEqualKey = function (k1, k2) {
145
+ return ((JavaScript_Key(k1, FMnemonic) == JavaScript_Key(k2, FMnemonic)) &&
146
+ (JavaScript_Shift(k1, FMnemonic) == JavaScript_Shift(k2, FMnemonic)));
147
+ };
148
+ let result = '';
149
+ let HasRules = false;
150
+ let processed_rule = Array(fgp.keys.length);
151
+ for (let j = 0; j < fgp.keys.length; j++) {
152
+ processed_rule[j] = false;
153
+ }
154
+ let j = 0;
155
+ let Counter = 0;
156
+ while (j < fgp.keys.length) { // I1964
157
+ let fkp = fgp.keys[j];
158
+ if (!processed_rule[j] && !RuleIsExcludedByPlatform(keyboard, fkp)) {
159
+ // Break down by key code
160
+ // We know the rules are sorted by context length and then key code.
161
+ // First pass, break the grouping down by key code.
162
+ if (fgp.fUsingKeys) {
163
+ result +=
164
+ `${FTabStop + FTabStop}${HasRules ? 'else ' : ''}` +
165
+ `if(k.KKM(e,${JavaScript_ShiftAsString(fkp, fMnemonic)},${JavaScript_KeyAsString(fkp, fMnemonic)})) {${nl}`;
166
+ HasRules = true;
167
+ Counter++;
168
+ let LocalHasRules = false;
169
+ let fkp2 = fgp.keys[j];
170
+ let j2 = j;
171
+ let LocalCounter = 0;
172
+ while (j < fgp.keys.length) {
173
+ fkp = fgp.keys[j];
174
+ if (!processed_rule[j] && !RuleIsExcludedByPlatform(keyboard, fkp) && IsEqualKey(fkp, fkp2)) {
175
+ processed_rule[j] = true;
176
+ result += JavaScript_Rule(FTabStop + FTabStop + FTabStop, LocalHasRules ? 'else ' : '', keyboard, fgp, fkp);
177
+ LocalCounter++;
178
+ if (FFix183_LadderLength != 0 && (LocalCounter % FFix183_LadderLength) == 0) {
179
+ // Break if/else ladders
180
+ result += `${FTabStop + FTabStop + FTabStop}if(m) {}${nl}`;
181
+ }
182
+ LocalHasRules = true;
183
+ }
184
+ j++;
185
+ }
186
+ result += FTabStop + FTabStop + '}' + nl;
187
+ j = j2 + 1;
188
+ }
189
+ else {
190
+ // TODO: context character level switches instead of full context comparisons
191
+ result += JavaScript_Rule(FTabStop + FTabStop + FTabStop, HasRules ? 'else ' : '', keyboard, fgp, fkp);
192
+ HasRules = true;
193
+ Counter++;
194
+ j++;
195
+ }
196
+ if (FFix183_LadderLength != 0 && (Counter % FFix183_LadderLength) == 0) {
197
+ // Break if/else ladders
198
+ // We need to only match if no previous line is matched (i.e. m is false)
199
+ result += `${FTabStop + FTabStop + FTabStop}if(m) {}${nl}`;
200
+ }
201
+ }
202
+ else {
203
+ j++;
204
+ }
205
+ }
206
+ return result;
207
+ }
208
+ export function JavaScript_Shift(fkp, FMnemonic) {
209
+ if (FMnemonic) {
210
+ if (fkp.ShiftFlags & KMX.KMXFile.VIRTUALCHARKEY) {
211
+ callbacks.reportMessage(KmwCompilerMessages.Error_VirtualCharacterKeysNotSupportedInKeymanWeb({ line: fkp.Line }));
212
+ return 0;
213
+ }
214
+ if (fkp.ShiftFlags & KMX.KMXFile.ISVIRTUALKEY && fkp.Key <= 255) {
215
+ // We prohibit K_ keys for mnemonic layouts. We don't block T_ and U_ keys.
216
+ // TODO: this doesn't resolve the issue of, e.g. SHIFT+K_SPACE
217
+ // https://github.com/keymanapp/keyman/issues/265
218
+ callbacks.reportMessage(KmwCompilerMessages.Error_VirtualKeysNotValidForMnemonicLayouts({ line: fkp.Line }));
219
+ return 0;
220
+ }
221
+ }
222
+ if (fkp.ShiftFlags & KMX.KMXFile.ISVIRTUALKEY) {
223
+ if (IsKeyboardVersion10OrLater()) {
224
+ // Full chiral modifier and state key support starts with KeymanWeb 10.0
225
+ return fkp.ShiftFlags;
226
+ }
227
+ // Non-chiral support only and no support for state keys
228
+ if (fkp.ShiftFlags & (KMX.KMXFile.LCTRLFLAG | KMX.KMXFile.RCTRLFLAG | KMX.KMXFile.LALTFLAG | KMX.KMXFile.RALTFLAG)) { // I4118
229
+ callbacks.reportMessage(KmwCompilerMessages.Warn_ExtendedShiftFlagsNotSupportedInKeymanWeb({ line: fkp.Line, flags: 'LALT, RALT, LCTRL, RCTRL' }));
230
+ }
231
+ if (fkp.ShiftFlags & (KMX.KMXFile.CAPITALFLAG | KMX.KMXFile.NOTCAPITALFLAG | KMX.KMXFile.NUMLOCKFLAG | KMX.KMXFile.NOTNUMLOCKFLAG |
232
+ KMX.KMXFile.SCROLLFLAG | KMX.KMXFile.NOTSCROLLFLAG)) { // I4118
233
+ callbacks.reportMessage(KmwCompilerMessages.Warn_ExtendedShiftFlagsNotSupportedInKeymanWeb({ line: fkp.Line, flags: 'CAPS and NCAPS' }));
234
+ }
235
+ return KMX.KMXFile.ISVIRTUALKEY | (fkp.ShiftFlags & (KMX.KMXFile.K_SHIFTFLAG | KMX.KMXFile.K_CTRLFLAG | KMX.KMXFile.K_ALTFLAG));
236
+ }
237
+ return USEnglishShift.includes(String.fromCharCode(fkp.Key)) ? KMX.KMXFile.ISVIRTUALKEY | KMX.KMXFile.K_SHIFTFLAG : KMX.KMXFile.ISVIRTUALKEY;
238
+ }
239
+ /**
240
+ * Returns a Javascript representation of a key modifier state, either as a constant (debug mode)
241
+ * or as an integer.
242
+ *
243
+ * @param fkp Pointer to key record
244
+ * @param FMnemonic True if the keyboard is a mnemonic layout
245
+ *
246
+ * @return string representation of the key modifier state, e.g.
247
+ * 'modCodes.SHIFT | modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4110 * /' or
248
+ * '16656'
249
+ */
250
+ export function JavaScript_ShiftAsString(fkp, FMnemonic) {
251
+ if (!options.saveDebug) {
252
+ return JavaScript_Shift(fkp, FMnemonic).toString();
253
+ }
254
+ return ' ' + FormatModifierAsBitflags(JavaScript_Shift(fkp, FMnemonic));
255
+ }
256
+ function FormatKeyForErrorMessage(fkp, FMnemonic) {
257
+ function FormatShift(ShiftFlags) {
258
+ const mask = [
259
+ 'LCTRL', // 0X0001
260
+ 'RCTRL', // 0X0002
261
+ 'LALT', // 0X0004
262
+ 'RALT', // 0X0008
263
+ 'SHIFT', // 0X0010
264
+ 'CTRL', // 0X0020
265
+ 'ALT', // 0X0040
266
+ '???', // Reserved
267
+ 'CAPS', // 0X0100
268
+ 'NCAPS', // 0X0200
269
+ 'NUMLOCK', // 0X0400
270
+ 'NNUMLOCK', // 0X0800
271
+ 'SCROLLLOCK', // 0X1000
272
+ 'NSCROLLLOCK' // 0X2000
273
+ ];
274
+ let result = '';
275
+ for (let i = 0; i < mask.length; i++) {
276
+ if (ShiftFlags & (1 << i)) {
277
+ result += mask[i] + ' ';
278
+ }
279
+ }
280
+ return result;
281
+ }
282
+ let result;
283
+ if (!FMnemonic) {
284
+ if (fkp.ShiftFlags & KMX.KMXFile.ISVIRTUALKEY) {
285
+ if (fkp.Key < 256) {
286
+ result = `[${FormatShift(fkp.ShiftFlags)}${VKeyNames[fkp.Key]}]`;
287
+ }
288
+ else {
289
+ result = `[${FormatShift(fkp.ShiftFlags)}K_${fkp.Key.toString(16).toUpperCase()}]`;
290
+ }
291
+ }
292
+ else {
293
+ result = `'${String.fromCharCode(fkp.Key)}'`;
294
+ }
295
+ }
296
+ else {
297
+ if (fkp.ShiftFlags & KMX.KMXFile.VIRTUALCHARKEY) {
298
+ result = `[${FormatShift(fkp.ShiftFlags)}'${String.fromCharCode(fkp.Key)}']`;
299
+ }
300
+ else {
301
+ result = `'${String.fromCharCode(fkp.Key)}'`;
302
+ }
303
+ }
304
+ return result;
305
+ }
306
+ export function JavaScript_Key(fkp, FMnemonic) {
307
+ let Result;
308
+ if (!FMnemonic) {
309
+ if (fkp.ShiftFlags & KMX.KMXFile.ISVIRTUALKEY) {
310
+ Result = fkp.Key;
311
+ }
312
+ else {
313
+ // Convert the character to a virtual key
314
+ let n = USEnglishShift.indexOf(String.fromCharCode(fkp.Key));
315
+ if (n < 0) {
316
+ n = USEnglishUnshift.indexOf(String.fromCharCode(fkp.Key));
317
+ }
318
+ if (n < 0) {
319
+ Result = 0;
320
+ }
321
+ else {
322
+ Result = USEnglishValues.charCodeAt(n);
323
+ }
324
+ }
325
+ }
326
+ else {
327
+ Result = fkp.Key;
328
+ }
329
+ // Check that key is not unreachable (e.g. K_SHIFT, touch-specific special keys 50,000+)
330
+ if (UnreachableKeyCodes.indexOf(Result) >= 0) {
331
+ Result = 0;
332
+ }
333
+ if (Result == 0 || Result >= 50001 /* TKeymanWebTouchStandardKey.K_LOPT */) { // I4141
334
+ if (!FUnreachableKeys.includes(fkp)) {
335
+ callbacks.reportMessage(KmwCompilerMessages.Hint_UnreachableKeyCode({ line: fkp.Line, key: FormatKeyForErrorMessage(fkp, FMnemonic) }));
336
+ FUnreachableKeys.push(fkp);
337
+ }
338
+ }
339
+ return Result;
340
+ }
341
+ /**
342
+ * Returns a Javascript representation of a key value, either as a constant (debug mode)
343
+ * or as an integer.
344
+ *
345
+ * @param fkp Pointer to key record
346
+ * @param FMnemonic True if the keyboard is a mnemonic layout
347
+ *
348
+ * @return string representation of the key value, e.g. 'keyCodes.K_A /* 0x41 * /' or '65'
349
+ */
350
+ export function JavaScript_KeyAsString(fkp, FMnemonic) {
351
+ if (options.saveDebug) {
352
+ return ' ' + FormatKeyAsString(JavaScript_Key(fkp, FMnemonic));
353
+ }
354
+ else {
355
+ return JavaScript_Key(fkp, FMnemonic).toString();
356
+ }
357
+ }
358
+ export function JavaScript_ContextMatch(fk, fkp, context) {
359
+ if (IsKeyboardVersion10OrLater()) {
360
+ return JavaScript_FullContextValue(fk, fkp, context);
361
+ }
362
+ else {
363
+ return JavaScript_CompositeContextValue(fk, fkp, context);
364
+ }
365
+ }
366
+ function JavaScript_ContextLength(Context) {
367
+ return xstrlen_printing(Context);
368
+ }
369
+ function GetCodeName(code) {
370
+ if (code >= 0 && code < KMXCodeNames.length && KMXCodeNames[code] != '') {
371
+ return KMXCodeNames[code];
372
+ }
373
+ return code.toString();
374
+ }
375
+ function CheckStoreForInvalidFunctions(fk, key, store) {
376
+ let n, rec;
377
+ const wcsentinel = String.fromCharCode(0xFFFF);
378
+ n = store.dpString.indexOf(wcsentinel);
379
+ // Disable the check with versions >= 10.0, since we now support deadkeys in stores.
380
+ if (n >= 0 && !IsKeyboardVersion10OrLater) {
381
+ rec = ExpandSentinel(fk, store.dpString, n);
382
+ callbacks.reportMessage(KmwCompilerMessages.Error_NotSupportedInKeymanWebStore({ code: GetCodeName(rec.Code), store: store.dpName }));
383
+ }
384
+ }
385
+ // Used when targeting versions prior to 10.0, before the introduction of FullContextMatch/KFCM.
386
+ function JavaScript_CompositeContextValue(fk, fkp, pwsz) {
387
+ let Result = '';
388
+ let InQuotes = false;
389
+ let Len = JavaScript_ContextLength(pwsz);
390
+ let StartQuotes = -1;
391
+ let x = 0, Cur = 0;
392
+ while (x < pwsz.length) {
393
+ let rec = ExpandSentinel(fk, pwsz, x);
394
+ if (rec.IsSentinel) {
395
+ if (InQuotes) {
396
+ Result += `",${Cur - StartQuotes})`;
397
+ InQuotes = false;
398
+ }
399
+ if (Result != '') {
400
+ Result += '&&';
401
+ }
402
+ switch (rec.Code) {
403
+ case KMX.KMXFile.CODE_ANY:
404
+ CheckStoreForInvalidFunctions(fk, fkp, rec.Any.Store); // I1520
405
+ Result += `k.KA(${Cur},k.KC(${Len - Cur},1,t),this.s${JavaScript_Name(rec.Any.StoreIndex, rec.Any.Store.dpName)})`;
406
+ break;
407
+ case KMX.KMXFile.CODE_DEADKEY:
408
+ Result += `k.KDM(${Len - Cur},t,${rec.DeadKey.DeadKey})`;
409
+ Cur--; // don't increment on deadkeys -- correlates with AdjustIndex function // I3910
410
+ break;
411
+ case KMX.KMXFile.CODE_NUL: // I2243
412
+ Result += `k.KN(${Len - Cur},t)`;
413
+ Cur--; // don't increment on nul -- correlates with AdjustIndex function // I3910
414
+ break;
415
+ case KMX.KMXFile.CODE_IFOPT: // I3429
416
+ Result += `this.s${JavaScript_Name(rec.IfOpt.StoreIndex1, rec.IfOpt.Store1.dpName)}` +
417
+ `${rec.IfOpt.IsNot == 0 ? '!==' : '==='}` +
418
+ `this.s${JavaScript_Name(rec.IfOpt.StoreIndex2, rec.IfOpt.Store2.dpName)}`; // I3429 // I3659 // I3681
419
+ Cur--; // don't increment on ifopt -- correlates with AdjustIndex function // I3910
420
+ break;
421
+ case KMX.KMXFile.CODE_IFSYSTEMSTORE: // I3430
422
+ Result += `${rec.IfSystemStore.IsNot == 0 ? '!' : ''}` +
423
+ `k.KIFS(${rec.IfSystemStore.dwSystemID},` +
424
+ `this.s${JavaScript_Name(rec.IfSystemStore.StoreIndex, rec.IfSystemStore.Store.dpName)},t)`;
425
+ Cur--; // don't increment on ifsystemstore -- correlates with AdjustIndex function // I3910
426
+ break;
427
+ case KMX.KMXFile.CODE_CONTEXTEX: // I3980
428
+ Result += `k.KCCM(${Len - Cur},${Len - rec.ContextEx.Index},t)`;
429
+ break;
430
+ case KMX.KMXFile.CODE_NOTANY: // I3981
431
+ CheckStoreForInvalidFunctions(fk, fkp, rec.Any.Store); // I1520
432
+ Result += `k.KC(${Len - Cur},1,t)!=""&&!k.KA(${Cur},k.KC(${Len - Cur},1,t),` +
433
+ `this.s${JavaScript_Name(rec.Any.StoreIndex, rec.Any.Store.dpName)})`;
434
+ break;
435
+ default:
436
+ callbacks.reportMessage(KmwCompilerMessages.Error_NotSupportedInKeymanWebContext({ line: fkp.Line, code: GetCodeName(rec.Code) }));
437
+ Result += '/*.*/ 0 ';
438
+ }
439
+ }
440
+ else {
441
+ if (!InQuotes) {
442
+ if (Result != '') {
443
+ Result += '&&';
444
+ }
445
+ Result += `k.KCM(${Len - Cur},t,"`;
446
+ StartQuotes = Cur;
447
+ InQuotes = true;
448
+ }
449
+ if (rec.ChrVal == '"'.charCodeAt(0) || rec.ChrVal == '\\'.charCodeAt(0)) {
450
+ Result += '\\';
451
+ }
452
+ Result += JavaScript_String(rec.ChrVal); // I2242
453
+ }
454
+ Cur++;
455
+ x = incxstr(pwsz, x);
456
+ }
457
+ if (InQuotes) {
458
+ Result += `",${Cur - StartQuotes})`;
459
+ }
460
+ return Result;
461
+ }
462
+ // Used when targeting versions >= 10.0, after the introduction of FullContextMatch/KFCM.
463
+ function JavaScript_FullContextValue(fk, fkp, pwsz) {
464
+ let Result = '';
465
+ let FullContext = '';
466
+ let Suffix = '';
467
+ let Len = xstrlen(pwsz);
468
+ let x = 0;
469
+ while (x < pwsz.length) {
470
+ if (FullContext != '') {
471
+ FullContext += ',';
472
+ }
473
+ let rec = ExpandSentinel(fk, pwsz, x);
474
+ if (rec.IsSentinel) {
475
+ switch (rec.Code) {
476
+ case KMX.KMXFile.CODE_ANY:
477
+ CheckStoreForInvalidFunctions(fk, fkp, rec.Any.Store); // I1520
478
+ FullContext += `{t:'a',a:this.s${JavaScript_Name(rec.Any.StoreIndex, rec.Any.Store.dpName)}}`;
479
+ break;
480
+ case KMX.KMXFile.CODE_DEADKEY:
481
+ FullContext += `{t:'d',d:${rec.DeadKey.DeadKey}}`;
482
+ break;
483
+ case KMX.KMXFile.CODE_NUL: // I2243
484
+ FullContext += `{t:'n'}`;
485
+ break;
486
+ case KMX.KMXFile.CODE_IFOPT: // I3429
487
+ Len--;
488
+ if (Suffix != '') {
489
+ Suffix += '&&';
490
+ }
491
+ if (FullContext == ',') {
492
+ FullContext = '';
493
+ }
494
+ Suffix += `this.s${JavaScript_Name(rec.IfOpt.StoreIndex1, rec.IfOpt.Store1.dpName)}` +
495
+ `${rec.IfOpt.IsNot == 0 ? '!==' : '==='}this.s${JavaScript_Name(rec.IfOpt.StoreIndex2, rec.IfOpt.Store2.dpName)}`; // I3429 // I3659 // I3681
496
+ break;
497
+ case KMX.KMXFile.CODE_IFSYSTEMSTORE: // I3430
498
+ Len--;
499
+ if (Suffix != '') {
500
+ Suffix += '&&';
501
+ }
502
+ if (FullContext == ',') {
503
+ FullContext = '';
504
+ }
505
+ Suffix += `${rec.IfSystemStore.IsNot == 0 ? '!' : ''}k.KIFS(${rec.IfSystemStore.dwSystemID},` +
506
+ `this.s${JavaScript_Name(rec.IfSystemStore.StoreIndex, rec.IfSystemStore.Store.dpName)},t)`; // I3430 // I3659 // I3681
507
+ break;
508
+ case KMX.KMXFile.CODE_NOTANY: // I3981
509
+ CheckStoreForInvalidFunctions(fk, fkp, rec.Any.Store); // I1520
510
+ FullContext += `{t:'a',a:this.s${JavaScript_Name(rec.Any.StoreIndex, rec.Any.Store.dpName)},n:1}`;
511
+ break;
512
+ case KMX.KMXFile.CODE_CONTEXTEX:
513
+ FullContext += `{t:'c',c:${rec.ContextEx.Index + 1}}`; // I4611
514
+ break;
515
+ case KMX.KMXFile.CODE_INDEX:
516
+ FullContext += `{t:'i',i:this.s${JavaScript_Name(rec.Index.StoreIndex, rec.Index.Store.dpName)},` +
517
+ `o:${rec.Index.Index}}`; // I4611
518
+ break;
519
+ default:
520
+ callbacks.reportMessage(KmwCompilerMessages.Error_NotSupportedInKeymanWebContext({ line: fkp.Line, code: GetCodeName(rec.Code) }));
521
+ Result += '/*.*/ 0 ';
522
+ }
523
+ }
524
+ else { // Simple context character.
525
+ FullContext += `'`;
526
+ if (rec.ChrVal == '"'.charCodeAt(0) || rec.ChrVal == '\\'.charCodeAt(0) || rec.ChrVal == '\''.charCodeAt(0)) {
527
+ FullContext += '\\';
528
+ }
529
+ FullContext += JavaScript_String(rec.ChrVal) + `'`; // I2242
530
+ }
531
+ x = incxstr(pwsz, x);
532
+ }
533
+ if (FullContext != '') {
534
+ Result = `k.KFCM(${Len},t,[${FullContext}])`;
535
+ }
536
+ if (Result != '' && Suffix != '') {
537
+ Result += '&&' + Suffix;
538
+ }
539
+ else if (Suffix != '') {
540
+ Result = Suffix;
541
+ }
542
+ return Result;
543
+ }
544
+ function isGroupReadOnly(fk, fgp) {
545
+ const index = fk.groups.indexOf(fgp);
546
+ return kmxResult.extra.groups[index].isReadOnly;
547
+ }
548
+ function CallFunctionName(s) {
549
+ let n;
550
+ n = s.indexOf(':');
551
+ return s.substring(n + 1); // not found gives -1, substring(0) is ok :grin:
552
+ }
553
+ export function JavaScript_OutputString(fk, FTabStops, fkp, pwszOutput, fgp) {
554
+ let InQuotes = false;
555
+ let len = 0;
556
+ const nlt = nl + FTabStops; // I3681
557
+ const AdjustIndex = function (pwszContext, Index) {
558
+ let Result = Index;
559
+ let x = 0;
560
+ for (let I = 1; I < Index; I++) {
561
+ let recContext = ExpandSentinel(fk, pwszContext, x);
562
+ if (IsKeyboardVersion10OrLater()) {
563
+ if (recContext.IsSentinel && [KMX.KMXFile.CODE_NUL, KMX.KMXFile.CODE_IFOPT, KMX.KMXFile.CODE_IFSYSTEMSTORE].includes(recContext.Code)) {
564
+ Result--;
565
+ }
566
+ }
567
+ else {
568
+ if (recContext.IsSentinel && [KMX.KMXFile.CODE_DEADKEY, KMX.KMXFile.CODE_NUL, KMX.KMXFile.CODE_IFOPT, KMX.KMXFile.CODE_IFSYSTEMSTORE].includes(recContext.Code)) {
569
+ Result--;
570
+ }
571
+ }
572
+ x = incxstr(pwszContext, x);
573
+ }
574
+ return Result;
575
+ };
576
+ const ContextChar = function (ContextIndex, pwszContext, xContext) {
577
+ let Index;
578
+ let Result = '';
579
+ let recContext = ExpandSentinel(fk, pwszContext, xContext);
580
+ if (recContext.IsSentinel) {
581
+ if (InQuotes) { // I4611
582
+ Result += '");';
583
+ InQuotes = false;
584
+ }
585
+ switch (recContext.Code) {
586
+ case KMX.KMXFile.CODE_ANY:
587
+ Index = AdjustIndex(fkp.dpContext, ContextIndex) + 1; // I3910 // I4611
588
+ Result += nlt + `k.KIO(${len},this.s${JavaScript_Name(recContext.Any.StoreIndex, recContext.Any.Store.dpName)},${Index},t);`; // I4611
589
+ break;
590
+ case KMX.KMXFile.CODE_DEADKEY:
591
+ Result += nlt + `k.KDO(${len},t,${recContext.DeadKey.DeadKey});`; // I4611
592
+ break;
593
+ case KMX.KMXFile.CODE_NOTANY:
594
+ // #917: Minimum version required is 14.0: the KCXO function was only added for 14.0
595
+ // Note that this is checked in compiler.cpp as well, so this error can probably never occur
596
+ if (!IsKeyboardVersion14OrLater()) {
597
+ callbacks.reportMessage(KmwCompilerMessages.Error_NotAnyRequiresVersion14({ line: fkp.Line }));
598
+ }
599
+ Result += nlt + `k.KCXO(${len},t,${AdjustIndex(fkp.dpContext, xstrlen(fkp.dpContext))},${AdjustIndex(fkp.dpContext, ContextIndex) + 1});`;
600
+ break;
601
+ case KMX.KMXFile.CODE_IFOPT:
602
+ case KMX.KMXFile.CODE_IFSYSTEMSTORE:
603
+ case KMX.KMXFile.CODE_NUL:
604
+ // These have no output for a context emit
605
+ break;
606
+ default:
607
+ callbacks.reportMessage(KmwCompilerMessages.Error_NotSupportedInKeymanWebContext({ line: fkp.Line, code: GetCodeName(recContext.Code) }));
608
+ Result += nlt + '/*.*/ '; // I4611
609
+ }
610
+ }
611
+ else {
612
+ if (!InQuotes) {
613
+ Result += nlt + `k.KO(${len},t,"`; // I4611
614
+ InQuotes = true;
615
+ }
616
+ if (recContext.ChrVal == '"'.charCodeAt(0) || recContext.ChrVal == '\\'.charCodeAt(0)) {
617
+ Result += '\\';
618
+ }
619
+ Result += JavaScript_String(recContext.ChrVal); // I2242
620
+ }
621
+ return Result;
622
+ };
623
+ let Result = '';
624
+ InQuotes = false;
625
+ let pwsz = pwszOutput;
626
+ if (fkp != null) {
627
+ if (IsKeyboardVersion10OrLater()) {
628
+ // KMW >= 10.0 use the full, sentinel-based length for context deletions.
629
+ len = xstrlen(fkp.dpContext);
630
+ let n = len;
631
+ let x = 0;
632
+ for (let i = 0; i < n; i++) {
633
+ let rec = ExpandSentinel(fk, fkp.dpContext, x);
634
+ if (rec.IsSentinel && [KMX.KMXFile.CODE_NUL, KMX.KMXFile.CODE_IFOPT, KMX.KMXFile.CODE_IFSYSTEMSTORE].includes(rec.Code)) {
635
+ len--;
636
+ }
637
+ x = incxstr(fkp.dpContext, x);
638
+ }
639
+ }
640
+ else {
641
+ // KMW < 10.0 exclude all sentinel-based characters, including deadkeys, from direct context deletion.
642
+ // Deadkeys have alternative special handling.
643
+ len = xstrlen_printing(fkp.dpContext);
644
+ }
645
+ }
646
+ else {
647
+ len = -1;
648
+ }
649
+ let x = 0;
650
+ if (IsKeyboardVersion10OrLater() && pwsz.length > 0) {
651
+ if (!isGroupReadOnly(fk, fgp)) {
652
+ Result += nlt + `k.KDC(${len},t);`; // I3681
653
+ }
654
+ len = -1;
655
+ }
656
+ while (x < pwsz.length) {
657
+ let rec = ExpandSentinel(fk, pwsz, x);
658
+ if (rec.IsSentinel) {
659
+ if (InQuotes) {
660
+ if (!isGroupReadOnly(fk, fgp)) {
661
+ Result += '");';
662
+ }
663
+ InQuotes = false;
664
+ }
665
+ switch (rec.Code) {
666
+ case KMX.KMXFile.CODE_CONTEXT:
667
+ if (x > 0 || len == -1) {
668
+ let xContext = 0;
669
+ let n = 0;
670
+ while (xContext < fkp.dpContext.length) { // I4611
671
+ if (!isGroupReadOnly(fk, fgp)) {
672
+ Result += ContextChar(n, fkp.dpContext, xContext);
673
+ }
674
+ n++;
675
+ xContext = incxstr(fkp.dpContext, xContext);
676
+ }
677
+ //Result := Result + Format('k.KO(%d,t,k.KC(%d,%d,t));', [len, xstrlen_printing(fkp.dpContext), xstrlen_printing(fkp.dpContext)]);
678
+ }
679
+ // else, we don't need to output anything - just don't delete the context
680
+ len = -1;
681
+ break;
682
+ case KMX.KMXFile.CODE_CONTEXTEX:
683
+ let xContext = 0;
684
+ for (let i = 0; i < rec.ContextEx.Index; i++) {
685
+ xContext = incxstr(fkp.dpContext, xContext);
686
+ }
687
+ if (!isGroupReadOnly(fk, fgp)) {
688
+ Result += ContextChar(rec.ContextEx.Index, fkp.dpContext, xContext); // I4611
689
+ }
690
+ len = -1;
691
+ break;
692
+ case KMX.KMXFile.CODE_BEEP:
693
+ if (!isGroupReadOnly(fk, fgp)) {
694
+ if (len > 0) {
695
+ Result += nlt + `k.KO(${len},t,"");`; // I3681
696
+ }
697
+ Result += nlt + 'k.KB(t);'; // I3681
698
+ }
699
+ len = -1;
700
+ break;
701
+ case KMX.KMXFile.CODE_NUL:
702
+ if (!isGroupReadOnly(fk, fgp)) {
703
+ if (len > 0) {
704
+ Result += nlt + `k.KO(${len},t,"");`; // I3681
705
+ }
706
+ }
707
+ len = -1;
708
+ break;
709
+ case KMX.KMXFile.CODE_INDEX:
710
+ CheckStoreForInvalidFunctions(fk, fkp, rec.Index.Store); // I1520
711
+ // This code was wrong. We need to ignore CODE_NUL, CODE_DEADKEY in LHS context index counter.
712
+ // This is why the compiler goes wrong -- and why the previous fix was inconsistent.
713
+ // The I783 test did not test either of these cases. It seems some of the keyboards were
714
+ // compiled in-between the original fix and I783 re-fix, and then happened to work due to
715
+ // their simplicity.
716
+ let Index = AdjustIndex(fkp.dpContext, rec.Index.Index); // I3910
717
+ if (!isGroupReadOnly(fk, fgp)) {
718
+ Result += nlt + `k.KIO(${len},this.s${JavaScript_Name(rec.Index.StoreIndex, rec.Index.Store.dpName)},${Index},t);`;
719
+ // I783 - was: rec.Index.Index [2007-06-04]
720
+ // I783 again. Returned to rec.Index.Index. Was previously: [2008-08-15]
721
+ // xstrlen(fkp.dpContext) + 1 - rec.Index.Index]);
722
+ // this was wrong. Can't find any reason why this change was made
723
+ // which suggests it was in response to another bug and poorly traced (bad Marc)
724
+ // and not properly tested (bad, bad Marc). Anyway, now tested with test_i783
725
+ }
726
+ len = -1;
727
+ break;
728
+ case KMX.KMXFile.CODE_DEADKEY:
729
+ if (!isGroupReadOnly(fk, fgp)) {
730
+ Result += nlt + `k.KDO(${len},t,${rec.DeadKey.DeadKey});`; // I3681
731
+ }
732
+ len = -1;
733
+ break;
734
+ case KMX.KMXFile.CODE_USE:
735
+ if (!isGroupReadOnly(fk, fgp)) {
736
+ if (len > 0) {
737
+ Result += nlt + `k.KO(${len},t,"");`; // I3681
738
+ }
739
+ }
740
+ Result += nlt + `r=this.g${JavaScript_Name(rec.Use.GroupIndex, rec.Use.Group.dpName)}(t,e);`; // I1959 // I3681
741
+ Result += nlt + 'm=2;'; // #5440 - match desktop behavior
742
+ len = -1;
743
+ break;
744
+ case KMX.KMXFile.CODE_CALL:
745
+ if (!isGroupReadOnly(fk, fgp)) {
746
+ if (len > 0) {
747
+ Result += nlt + `k.KO(${len},t,"");`; // I3681
748
+ }
749
+ }
750
+ let n = FCallFunctions.indexOf(CallFunctionName(rec.Call.Store.dpString));
751
+ if (n == -1) {
752
+ n = FCallFunctions.push(CallFunctionName(rec.Call.Store.dpString)) - 1;
753
+ }
754
+ Result += nlt + `r=this.c${n}(t,e);`; // I1959 // I3681
755
+ Result += nlt + 'm=2;'; // #5440 - match desktop behavior
756
+ len = -1;
757
+ break;
758
+ case KMX.KMXFile.CODE_SETOPT: // I3429
759
+ if (!isGroupReadOnly(fk, fgp)) {
760
+ if (len > 0) {
761
+ Result += nlt + `k.KO(${len},t,"");`; // I3681
762
+ }
763
+ }
764
+ Result += nlt + `this.s${JavaScript_Name(rec.SetOpt.StoreIndex1, rec.SetOpt.Store1.dpName)}=` +
765
+ `this.s${JavaScript_Name(rec.SetOpt.StoreIndex2, rec.SetOpt.Store2.dpName)};`;
766
+ len = -1;
767
+ break;
768
+ case KMX.KMXFile.CODE_RESETOPT: // I3429
769
+ if (!isGroupReadOnly(fk, fgp)) {
770
+ if (len > 0) {
771
+ Result += nlt + `k.KO(${len},t,"");`; // I3681
772
+ }
773
+ }
774
+ Result += nlt + `this.s${JavaScript_Name(rec.ResetOpt.StoreIndex, rec.ResetOpt.Store.dpName)}=` +
775
+ `k.KLOAD(this.KI,"${JavaScript_Name(rec.ResetOpt.StoreIndex, rec.ResetOpt.Store.dpName, true)}",` +
776
+ `${JavaScript_Store(fk, fkp.Line, rec.ResetOpt.Store.dpString)});`; // I3429 // I3681 // I3659
777
+ len = -1;
778
+ break;
779
+ case KMX.KMXFile.CODE_SAVEOPT: // I3429
780
+ if (!isGroupReadOnly(fk, fgp)) {
781
+ if (len > 0) {
782
+ Result += nlt + `k.KO(${len},t,"");`; // I3681
783
+ }
784
+ }
785
+ Result += nlt + `k.KSAVE("${JavaScript_Name(rec.SaveOpt.StoreIndex, rec.SaveOpt.Store.dpName, true)}",` +
786
+ `this.s${JavaScript_Name(rec.SaveOpt.StoreIndex, rec.SaveOpt.Store.dpName)});`; // I3690 // I3429 // I3659 // I3681
787
+ len = -1;
788
+ break;
789
+ case KMX.KMXFile.CODE_SETSYSTEMSTORE: // I3437
790
+ if (!isGroupReadOnly(fk, fgp)) {
791
+ if (len > 0) {
792
+ Result += nlt + `k.KO(${len},t,"");`; // I3681
793
+ }
794
+ }
795
+ Result += nlt + `k.KSETS(${rec.SetSystemStore.dwSystemID},` +
796
+ `this.s${JavaScript_Name(rec.SetSystemStore.StoreIndex, rec.SetSystemStore.Store.dpName)},t);`; // I3681
797
+ len = -1;
798
+ break;
799
+ default:
800
+ callbacks.reportMessage(KmwCompilerMessages.Error_NotSupportedInKeymanWebOutput({ line: fkp?.Line ?? 0, code: GetCodeName(rec.Code) }));
801
+ Result += '';
802
+ }
803
+ }
804
+ else {
805
+ if (!InQuotes) {
806
+ if (!isGroupReadOnly(fk, fgp)) {
807
+ Result += nlt + `k.KO(${len},t,"`; // I3681
808
+ }
809
+ InQuotes = true;
810
+ len = -1;
811
+ }
812
+ if (!isGroupReadOnly(fk, fgp)) {
813
+ if (rec.ChrVal == '"'.charCodeAt(0) || rec.ChrVal == '\\'.charCodeAt(0)) {
814
+ Result += '\\';
815
+ }
816
+ Result += JavaScript_String(rec.ChrVal); // I2242
817
+ }
818
+ }
819
+ x = incxstr(pwsz, x);
820
+ }
821
+ if (InQuotes) {
822
+ if (!isGroupReadOnly(fk, fgp)) {
823
+ Result += '");';
824
+ }
825
+ }
826
+ return Result;
827
+ }
828
+ export function zeroPadHex(n, len) {
829
+ let result = n.toString(16).toUpperCase();
830
+ if (result.length < len) {
831
+ return '0'.repeat(len - result.length) + result;
832
+ }
833
+ return result;
834
+ }
835
+ /**
836
+ * Converts a key value into a constant
837
+ *
838
+ * @param key A virtual key code
839
+ *
840
+ * @return string of JavaScript code, e.g. 'keyCodes.K_A /* 0x41 * /'
841
+ */
842
+ function FormatKeyAsString(key) {
843
+ if (IsKeyboardVersion10OrLater()) {
844
+ // Depends on flags defined in KeymanWeb 10.0
845
+ if (key <= 255 && KMWVKeyNames[key] != '') {
846
+ return 'keyCodes.' + KMWVKeyNames[key] + ' /* 0x' + zeroPadHex(key, 2) + ' */';
847
+ }
848
+ return '0x' + zeroPadHex(key, 2);
849
+ }
850
+ return '0x' + zeroPadHex(key, 2);
851
+ }
852
+ //# sourceMappingURL=javascript-strings.js.map