diff --git a/developer/src/common/include/kmn_compiler_errors.h b/developer/src/common/include/kmn_compiler_errors.h index fe7ba11a150..e0bea39549c 100644 --- a/developer/src/common/include/kmn_compiler_errors.h +++ b/developer/src/common/include/kmn_compiler_errors.h @@ -240,6 +240,8 @@ #define CHINT_UnreachableRule 0x000010AE +#define CWARN_VirtualKeyInOutput 0x000020AF + #define CERR_BufferOverflow 0x000080C0 #define CERR_Break 0x000080C1 diff --git a/developer/src/kmc-kmn/src/compiler/kmn-compiler-messages.ts b/developer/src/kmc-kmn/src/compiler/kmn-compiler-messages.ts index 2995c8f0165..4ad9d025982 100644 --- a/developer/src/kmc-kmn/src/compiler/kmn-compiler-messages.ts +++ b/developer/src/kmc-kmn/src/compiler/kmn-compiler-messages.ts @@ -302,6 +302,8 @@ export class KmnCompilerMessages { static HINT_UnreachableRule = SevHint | 0x0AE; + static WARN_VirtualKeyInOutput = SevWarn | 0x0AF; + static FATAL_BufferOverflow = SevFatal | 0x0C0; static FATAL_Break = SevFatal | 0x0C1; }; diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_virtual_key_in_output.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_virtual_key_in_output.kmn new file mode 100644 index 00000000000..e4919689b10 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_virtual_key_in_output.kmn @@ -0,0 +1,9 @@ +store(&NAME) 'WARN_VirtualKeyInOutput' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +c WARN_VirtualKeyInOutput ++ 'a' > [K_BKQUOTE] diff --git a/developer/src/kmc-kmn/test/test-messages.ts b/developer/src/kmc-kmn/test/test-messages.ts index 6970b997417..51e6894daa7 100644 --- a/developer/src/kmc-kmn/test/test-messages.ts +++ b/developer/src/kmc-kmn/test/test-messages.ts @@ -87,4 +87,11 @@ describe('CompilerMessages', function () { assert.equal(callbacks.messages[0].message, "Statement 'return' is not currently supported in output for web and touch targets"); }); + // WARN_VirtualKeyInOutput + + it('should generate WARN_VirtualKeyInOutput if a virtual key is found in the output part of a rule', async function() { + await testForMessage(this, ['invalid-keyboards', 'warn_virtual_key_in_output.kmn'], KmnCompilerMessages.WARN_VirtualKeyInOutput); + assert.equal(callbacks.messages[0].message, "Virtual keys are not supported in output"); + }); + }); diff --git a/developer/src/kmcmplib/src/CompMsg.cpp b/developer/src/kmcmplib/src/CompMsg.cpp index 8ab5db81f6b..715750d4f2f 100644 --- a/developer/src/kmcmplib/src/CompMsg.cpp +++ b/developer/src/kmcmplib/src/CompMsg.cpp @@ -143,6 +143,7 @@ const struct CompilerError CompilerErrors[] = { { CWARN_NulNotFirstStatementInContext , "nul must be the first statement in the context"}, { CWARN_IfShouldBeAtStartOfContext , "if, platform and baselayout should be at start of context (after nul, if present)"}, { CWARN_KeyShouldIncludeNCaps , "Other rules which reference this key include CAPS or NCAPS modifiers, so this rule must include NCAPS modifier to avoid inconsistent matches"}, + { CWARN_VirtualKeyInOutput , "Virtual keys are not supported in output"}, { 0, nullptr } }; diff --git a/developer/src/kmcmplib/src/Compiler.cpp b/developer/src/kmcmplib/src/Compiler.cpp index e2720f8608e..045b1c39ad1 100644 --- a/developer/src/kmcmplib/src/Compiler.cpp +++ b/developer/src/kmcmplib/src/Compiler.cpp @@ -1331,6 +1331,7 @@ KMX_BOOL CheckContextStatementPositions(PKMX_WCHAR context) { return TRUE; } + /** * Checks if a use() statement is followed by other content in the output of a rule */ @@ -1348,6 +1349,22 @@ KMX_DWORD CheckUseStatementsInOutput(PKMX_WCHAR output) { return CERR_None; } +/** + * Warn if output has virtual keys in it, which is not supported by Core at all, + * but was unofficially supported, but never worked properly, in Keyman for + * Windows for many years + */ +KMX_DWORD CheckVirtualKeysInOutput(PKMX_WCHAR output) { + PKMX_WCHAR p; + for (p = output; *p; p = incxstr(p)) { + if (*p == UC_SENTINEL && *(p + 1) == CODE_EXTENDED) { + AddWarning(CWARN_VirtualKeyInOutput); + break; + } + } + return CERR_None; +} + /** * Adds implicit `context` to start of output of rules for readonly groups */ @@ -1472,6 +1489,11 @@ KMX_DWORD ProcessKeyLineImpl(PFILE_KEYBOARD fk, PKMX_WCHAR str, KMX_BOOL IsUnico return msg; // I4867 } + // Warn if virtual keys are used in the output, as they are unsupported by Core + if ((msg = CheckVirtualKeysInOutput(pklOut)) != CERR_None) { + return msg; + } + if (gp->fReadOnly) { // Ensure no output is made from the rule, and that // use() statements meet required readonly semantics