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