diff --git a/HISTORY.md b/HISTORY.md index b8e4bba32c..213b87a6f8 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,36 @@ # Keyman Version History +## 17.0.109 alpha 2023-05-17 + +* fix(windows): add wrap-symbols to Text Editor Makefile (#8819) +* chore(linux): Make postinst script comply with Debian policy (#8810) +* chore(windows): remove legacy core and flag ️ (#8593) + +## 17.0.108 alpha 2023-05-16 + +* feat(windows): add text editor to the support makefile (#8750) +* feat(developer): verify keyboard versions in kmc-package (#8769) +* feat(developer): verify bcp47 tags are valid and minimal in kmc-package (#8778) +* feat(developer): verify at least one language in package (#8783) +* chore(developer): verify file types of content files in package (#8792) +* chore(developer): verify that package has at least a model or keyboard (#8793) +* chore(ios): Changes required for XCode 14.3 (#8746) + +## 17.0.107 alpha 2023-05-15 + +* chore(linux): Fix installation build step on TC (#8784) +* refactor(android/engine): Consolidate updateSelection (#8739) + +## 17.0.106 alpha 2023-05-12 + +* chore(developer): move package formats to common/web/types (#8729) +* feat(developer): add package validation (#8740) +* feat(developer): add validation of package filenames (#8751) +* feat(developer): validate content file names in packages (#8755) +* feat(developer): validate package name in compiler (#8757) +* chore(developer): rename Compiler and related classes (#8726) +* feat(developer): uset api from wasm! (#8716) + ## 17.0.105 alpha 2023-05-11 * chore(common): Update crowdin strings for Amharic (#8748) diff --git a/VERSION.md b/VERSION.md index 6c7991375d..18bc0b4cd1 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.106 \ No newline at end of file +17.0.110 \ No newline at end of file diff --git a/android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboard.java b/android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboard.java index 08717b9f21..88dc290322 100644 --- a/android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboard.java +++ b/android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboard.java @@ -47,6 +47,9 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; +import android.view.inputmethod.ExtractedText; +import android.view.inputmethod.ExtractedTextRequest; +import android.view.inputmethod.InputConnection; import android.webkit.ConsoleMessage; import android.webkit.WebChromeClient; import android.webkit.WebSettings; @@ -139,7 +142,7 @@ final class KMKeyboard extends WebView { } public boolean getShouldShowHelpBubble() { - if(this._shouldShowHelpBubble == null) { + if (this._shouldShowHelpBubble == null) { SharedPreferences prefs = context.getSharedPreferences(context.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE); this._shouldShowHelpBubble = prefs.getBoolean(KMManager.KMKey_ShouldShowHelpBubble, true); } @@ -151,10 +154,54 @@ final class KMKeyboard extends WebView { this._shouldShowHelpBubble = flag; } - protected boolean shouldIgnoreTextChange() { return shouldIgnoreTextChange; } - protected void setShouldIgnoreTextChange(boolean ignore) { this.shouldIgnoreTextChange = ignore; } - protected boolean shouldIgnoreSelectionChange() { return shouldIgnoreSelectionChange; } - protected void setShouldIgnoreSelectionChange(boolean ignore) { this.shouldIgnoreSelectionChange = ignore; } + protected boolean shouldIgnoreTextChange() { + return shouldIgnoreTextChange; + } + + protected void setShouldIgnoreTextChange(boolean ignore) { + this.shouldIgnoreTextChange = ignore; + } + + protected boolean shouldIgnoreSelectionChange() { + return shouldIgnoreSelectionChange; + } + + protected void setShouldIgnoreSelectionChange(boolean ignore) { + this.shouldIgnoreSelectionChange = ignore; + } + + protected boolean updateText(String text) { + boolean result = false; + String kmText = ""; + if (text != null) { + kmText = text.toString().replace("\\", "\\u005C").replace("'", "\\u0027").replace("\n", "\\n"); + } + + if (KMManager.isKeyboardLoaded(this.keyboardType) && !shouldIgnoreTextChange) { + this.loadJavascript(KMString.format("updateKMText('%s')", kmText)); + result = true; + } + + shouldIgnoreTextChange = false; + return result; + } + + protected boolean updateSelectionRange(int selStart, int selEnd) { + boolean result = false; + InputConnection ic = KMManager.getInputConnection(this.keyboardType); + if (ic != null) { + ExtractedText icText = ic.getExtractedText(new ExtractedTextRequest(), 0); + if (icText != null) { + updateText(icText.text.toString()); + } + } + this.loadJavascript(KMString.format("updateKMSelectionRange(%d,%d)", selStart, selEnd)); + result = true; + + return result; + } + + @SuppressWarnings("deprecation") @SuppressLint("SetJavaScriptEnabled") diff --git a/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java b/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java index 03ad41135d..7af3c2cf96 100644 --- a/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java +++ b/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java @@ -1952,25 +1952,11 @@ public final class KMManager { public static boolean updateText(KeyboardType kbType, String text) { boolean result = false; - String kmText = ""; - if (text != null) { - kmText = text.toString().replace("\\", "\\u005C").replace("'", "\\u0027").replace("\n", "\\n"); - } if (kbType == KeyboardType.KEYBOARD_TYPE_INAPP) { - if (isKeyboardLoaded(KeyboardType.KEYBOARD_TYPE_INAPP) && !InAppKeyboard.shouldIgnoreTextChange()) { - InAppKeyboard.loadJavascript(KMString.format("updateKMText('%s')", kmText)); - result = true; - } - - InAppKeyboard.setShouldIgnoreTextChange(false); + return InAppKeyboard.updateText(text); } else if (kbType == KeyboardType.KEYBOARD_TYPE_SYSTEM) { - if (isKeyboardLoaded(KeyboardType.KEYBOARD_TYPE_SYSTEM) && !SystemKeyboard.shouldIgnoreTextChange()) { - SystemKeyboard.loadJavascript(KMString.format("updateKMText('%s')", kmText)); - result = true; - } - - SystemKeyboard.setShouldIgnoreTextChange(false); + return SystemKeyboard.updateText(text); } return result; @@ -1980,23 +1966,13 @@ public final class KMManager { boolean result = false; if (kbType == KeyboardType.KEYBOARD_TYPE_INAPP) { if (isKeyboardLoaded(KeyboardType.KEYBOARD_TYPE_INAPP) && !InAppKeyboard.shouldIgnoreSelectionChange()) { - InAppKeyboard.loadJavascript(KMString.format("updateKMSelectionRange(%d,%d)", selStart, selEnd)); - result = true; + result = InAppKeyboard.updateSelectionRange(selStart, selEnd); } InAppKeyboard.setShouldIgnoreSelectionChange(false); } else if (kbType == KeyboardType.KEYBOARD_TYPE_SYSTEM) { if (isKeyboardLoaded(KeyboardType.KEYBOARD_TYPE_SYSTEM) && !SystemKeyboard.shouldIgnoreSelectionChange()) { - InputConnection ic = getInputConnection(KeyboardType.KEYBOARD_TYPE_SYSTEM); - if (ic != null) { - ExtractedText icText = ic.getExtractedText(new ExtractedTextRequest(), 0); - if (icText != null) { - updateText(kbType, icText.text.toString()); - } - } - - SystemKeyboard.loadJavascript(KMString.format("updateKMSelectionRange(%d,%d)", selStart, selEnd)); - result = true; + result = SystemKeyboard.updateSelectionRange(selStart, selEnd); } SystemKeyboard.setShouldIgnoreSelectionChange(false); diff --git a/common/web/types/src/main.ts b/common/web/types/src/main.ts index 19ca707b6d..4e77550384 100644 --- a/common/web/types/src/main.ts +++ b/common/web/types/src/main.ts @@ -18,7 +18,7 @@ export { default as LDMLKeyboardXMLSourceFileReader } from './ldml-keyboard/ldml export * as Constants from './consts/virtual-key-constants.js'; -export { CompilerCallbacks, CompilerSchema, CompilerEvent, CompilerErrorNamespace, CompilerErrorSeverity, CompilerPathCallbacks, CompilerFileSystemCallbacks, CompilerMessageSpec, compilerErrorSeverityName } from './util/compiler-interfaces.js'; +export { CompilerCallbacks, CompilerSchema, CompilerEvent, CompilerErrorNamespace, CompilerErrorSeverity, CompilerPathCallbacks, CompilerFileSystemCallbacks, CompilerMessageSpec, compilerErrorSeverityName, compilerExceptionToString, compilerErrorFormatCode } from './util/compiler-interfaces.js'; export { CommonTypesMessages } from './util/common-events.js'; export * as TouchLayout from './keyman-touch-layout/keyman-touch-layout-file.js'; diff --git a/common/web/types/src/util/compiler-interfaces.ts b/common/web/types/src/util/compiler-interfaces.ts index a58484298a..c7058b1578 100644 --- a/common/web/types/src/util/compiler-interfaces.ts +++ b/common/web/types/src/util/compiler-interfaces.ts @@ -32,6 +32,18 @@ export function compilerErrorSeverityName(code: number): string { } } +/** + * Format the error code number + * example: "FATAL:0x03004" + */ +export function compilerErrorFormatCode(code: number): string { + const severity = code & CompilerErrorSeverity.Severity_Mask; + const severityName = compilerErrorSeverityName(severity); + const errorCode = code & CompilerErrorSeverity.Error_Mask; + const errorCodeString = Number(errorCode).toString(16).padStart(5,'0'); + return `${severityName}:0x${errorCodeString}`; +} + /** * Defines the error code ranges for various compilers. Once defined, these * ranges must not be changed as external modules may depend on specific error @@ -137,3 +149,10 @@ export interface CompilerCallbacks { * @returns */ export const CompilerMessageSpec = (code: number, message: string) : CompilerEvent => { return { code, message } }; + +/** + * @param e Error-like + */ +export function compilerExceptionToString(e?: any) : string { + return `${(e ?? 'unknown error').toString()}\n\nCall stack:\n${(e instanceof Error ? e.stack : (new Error()).stack)}`; +} diff --git a/common/windows/cpp/include/registry.h b/common/windows/cpp/include/registry.h index 4e2fe9ae35..895f9e83be 100644 --- a/common/windows/cpp/include/registry.h +++ b/common/windows/cpp/include/registry.h @@ -129,9 +129,6 @@ #define REGSZ_Flag_UseCachedHotkeyModifierState "Flag_UseCachedHotkeyModifierState" -/* REGSZ_Flag_UseKeymanCore DWORD: Turns on the common core - instead of windows core */ -#define REGSZ_Flag_UseKeymanCore "Flag_UseKeymanCore" - /* DWORD: Enable/disable deep TSF integration, default enabled; 0 = disabled, 1 = enabled, 2 = default */ #define REGSZ_DeepTSFIntegration "deep tsf integration" diff --git a/developer/src/common/web/test-helpers/index.ts b/developer/src/common/web/test-helpers/index.ts index e79271227e..7f34107dc9 100644 --- a/developer/src/common/web/test-helpers/index.ts +++ b/developer/src/common/web/test-helpers/index.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import { CompilerEvent, CompilerCallbacks, CompilerSchema, CompilerPathCallbacks, CompilerFileSystemCallbacks } from '@keymanapp/common-types'; +import { CompilerEvent, CompilerCallbacks, CompilerSchema, CompilerPathCallbacks, CompilerFileSystemCallbacks, compilerErrorSeverityName } from '@keymanapp/common-types'; export { verifyCompilerMessagesObject } from './verifyCompilerMessagesObject.js'; // TODO: schemas are only used by kmc-ldml for now, so this works at this @@ -19,6 +19,17 @@ export class TestCompilerCallbacks implements CompilerCallbacks { this.messages = []; } + printMessages() { + this.messages.forEach(event => { + const code = event.code.toString(16); + if(event.line) { + console.log(`${compilerErrorSeverityName(event.code)} ${code} [${event.line}]: ${event.message}`); + } else { + console.log(`${compilerErrorSeverityName(event.code)} ${code}: ${event.message}`); + } + }); + } + hasMessage(code: number): boolean { return this.messages.find((item) => item.code == code) === undefined ? false : true; } diff --git a/developer/src/common/web/test-helpers/verifyCompilerMessagesObject.ts b/developer/src/common/web/test-helpers/verifyCompilerMessagesObject.ts index 7c52f403a2..223ab430f3 100644 --- a/developer/src/common/web/test-helpers/verifyCompilerMessagesObject.ts +++ b/developer/src/common/web/test-helpers/verifyCompilerMessagesObject.ts @@ -19,13 +19,13 @@ import {assert, expect} from 'chai'; const toTitleCase = (s: string) => s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase(); export function verifyCompilerMessagesObject(source: Record) { - let keys = Object.keys(source); + const keys = Object.keys(source); const m = source as Record; - let codes: number[] = []; + const codes: number[] = []; - for(let key of keys) { + for(const key of keys) { // Verify each object member matches the pattern we expect @@ -36,7 +36,7 @@ export function verifyCompilerMessagesObject(source: Record) { const c = o[1].toUpperCase() + '_' + o[2]; expect(m[c]).to.be.a('number', `Expected constant name ${c} to exist`); - let v = m[key]('','','','','','','','','','','','' /* ignore arguments*/); + const v = m[key]('','','','','','','','','','','','' /* ignore arguments*/); expect(v.code).to.equal(m[c], `Function ${key} returns the wrong code`); } else if(typeof m[key] == 'number') { @@ -63,4 +63,4 @@ export function verifyCompilerMessagesObject(source: Record) { codes.push(code); } } -} \ No newline at end of file +} diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index c112b4caf7..2f83e83aee 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -22,7 +22,7 @@ TODO: implement additional interfaces: */ // TODO: rename wasm-host? -import { CompilerCallbacks } from '@keymanapp/common-types'; +import { CompilerCallbacks, CompilerEvent } from '@keymanapp/common-types'; import loadWasmHost from '../import/kmcmplib/wasm-host.js'; import { CompilerMessages, mapErrorFromKmcmplib } from './messages.js'; @@ -47,33 +47,87 @@ const baseOptions: CompilerOptions = { */ let callbackProcIdentifier = 0; -export class Compiler { - wasmModule: any; - compileKeyboardFile: any; - setCompilerOptions: any; +/** + * Pointer in wasm-space + */ +type WasmPtr = number; + +/** + * The wrapped functions + */ +class WasmWrapper { + Module: any; + + compileKeyboardFile?: (pszInfile: string, pszOutfile: string, aSaveDebug: number, aCompilerWarningsAsErrors: number, aWarnDeprecatedCode: number, msgProc: string) => boolean; + parseUnicodeSet?: (pat: string, buf: WasmPtr, length: number) => number; + setCompilerOptions?: (shouldAddCompilerVersion: number) => boolean; + + constructor(wasmModule: any) { + this.Module = wasmModule; + if (!wasmModule) { + throw Error(`wasm host did not load`); + } + this.compileKeyboardFile = this.Module.cwrap('kmcmp_Wasm_CompileKeyboardFile', 'boolean', ['string', 'string', 'number', 'number', 'number', 'string']); + this.parseUnicodeSet = this.Module.cwrap('kmcmp_Wasm_ParseUnicodeSet', 'number', ['string', 'number', 'number']); + this.setCompilerOptions = this.Module.cwrap('kmcmp_Wasm_SetCompilerOptions', 'boolean', ['number']); + + if (this.parseUnicodeSet === undefined + || this.setCompilerOptions === undefined + || this.compileKeyboardFile === undefined) { + throw Error(`some wasm functions did not load properly.`); + } + } + + /** + * Entry point into Wasm functions + * @returns WasmWrapper + */ + public static async load() : Promise { + return new WasmWrapper(await loadWasmHost()); + } +}; + +export class KmnCompiler { callbackName: string; callbacks: CompilerCallbacks; + wasm: WasmWrapper; constructor() { this.callbackName = 'kmnCompilerCallback' + callbackProcIdentifier; callbackProcIdentifier++; } - public async init(): Promise { - if(!this.wasmModule) { - this.wasmModule = await loadWasmHost(); - this.compileKeyboardFile = this.wasmModule.cwrap('kmcmp_Wasm_CompileKeyboardFile', 'boolean', ['string', 'string', - 'number', 'number', 'number', 'string']); - this.setCompilerOptions = this.wasmModule.cwrap('kmcmp_Wasm_SetCompilerOptions', 'boolean', ['number']); + public async init(callbacks: CompilerCallbacks): Promise { + this.callbacks = callbacks; + if(!this.wasm) { + try { + this.wasm = await WasmWrapper.load(); + } catch(e: any) { + this.callbacks.reportMessage(CompilerMessages.Fatal_MissingWasmModule({e})); + return false; + } } - return this.compileKeyboardFile !== undefined && this.setCompilerOptions !== undefined; + return this.verifyInitialized(); } - public run(infile: string, outfile: string, callbacks: CompilerCallbacks, options?: CompilerOptions): boolean { - this.callbacks = callbacks; + /** + * Verify that wasm is spun up OK. + * @returns true if OK + */ + public verifyInitialized() : boolean { + if(!this.callbacks) { + // Can't report a message here. + throw Error('Must call Compiler.init(callbacks) before proceeding'); + } + if(!this.wasm) { // fail if wasm not loaded or function not found + this.callbacks.reportMessage(CompilerMessages.Fatal_MissingWasmModule({})); + return false; + } + return true; + } - if(!this.wasmModule) { - this.callbacks.reportMessage(CompilerMessages.Fatal_MissingWasmModule()); + public run(infile: string, outfile: string, options?: CompilerOptions): boolean { + if(!this.verifyInitialized()) { return false; } @@ -92,10 +146,10 @@ export class Compiler { private runCompiler(infile: string, outfile: string, options: CompilerOptions): boolean { try { - if(!this.setCompilerOptions(options.shouldAddCompilerVersion)) { + if (!this.wasm.setCompilerOptions(options.shouldAddCompilerVersion ? 1 : 0)) { this.callbacks.reportMessage(CompilerMessages.Fatal_UnableToSetCompilerOptions()); } - return this.compileKeyboardFile( + return this.wasm.compileKeyboardFile( infile, outfile, options.saveDebug ? 1 : 0, @@ -107,4 +161,85 @@ export class Compiler { return false; } } -} \ No newline at end of file + + /** + * + * @param pattern UnicodeSet pattern such as `[a-z]` + * @param bufferSize guess as to the buffer size + * @returns UnicodeSet accessor object, or null on failure + */ + public parseUnicodeSet(pattern: string, bufferSize: number) : UnicodeSet | null { + if(!this.verifyInitialized()) { + return null; + } + + if (!bufferSize) { + bufferSize = 100; // TODO-LDML: Preflight mode? Reuse buffer? + } + const { Module } = this.wasm; + const buf = Module.asm.malloc(bufferSize * 2 * Module.HEAPU32.BYTES_PER_ELEMENT); + // TODO-LDML: Catch OOM + const rc = this.wasm.parseUnicodeSet(pattern, buf, bufferSize); + if (rc >= 0) { + const ranges = []; + const startu = (buf / Module.HEAPU32.BYTES_PER_ELEMENT); + for (let i = 0; i < rc; i++) { + const low = Module.HEAPU32[startu + (i * 2) + 0]; + const high = Module.HEAPU32[startu + (i * 2) + 1]; + ranges.push([low, high]); + } + // TODO-LDML: no free?? + // Module.asm.free(buf); + return new UnicodeSet(pattern, ranges); + } else { + // translate error + // TODO-LDML: no free?? + // Module.asm.free(buf); + this.callbacks.reportMessage(getUnicodeSetError(rc)); + return null; + } + } +} + +/** + * translate UnicodeSet return code into a compiler event + * @param rc parseUnicodeSet error code + * @returns the compiler event + */ +function getUnicodeSetError(rc: number) : CompilerEvent { + // from kmcmplib.h + const KMCMP_ERROR_SYNTAX_ERR = -1; + const KMCMP_ERROR_HAS_STRINGS = -2; + const KMCMP_ERROR_UNSUPPORTED_PROPERTY = -3; + const KMCMP_FATAL_OUT_OF_RANGE = -4; + switch(rc) { + case KMCMP_ERROR_SYNTAX_ERR: + return CompilerMessages.Error_UnicodeSetSyntaxError(); + case KMCMP_ERROR_HAS_STRINGS: + return CompilerMessages.Error_UnicodeSetHasStrings(); + case KMCMP_ERROR_UNSUPPORTED_PROPERTY: + return CompilerMessages.Error_UnicodeSetHasProperties(); + case KMCMP_FATAL_OUT_OF_RANGE: + return CompilerMessages.Fatal_UnicodeSetOutOfRange(); + default: + return CompilerMessages.Fatal_UnexpectedException({e: `Unexpected UnicodeSet error code ${rc}`}); + } +} + +/** + * Represents a parsed UnicodeSet + */ +export class UnicodeSet { + constructor(public pattern: string, public ranges: number[][]) { + } + /** + * Number of ranges + */ + get length() : number { + return this.ranges.length; + } + + toString() : string { + return this.pattern; + } +} diff --git a/developer/src/kmc-kmn/src/compiler/messages.ts b/developer/src/kmc-kmn/src/compiler/messages.ts index 866a19d9be..10578870d7 100644 --- a/developer/src/kmc-kmn/src/compiler/messages.ts +++ b/developer/src/kmc-kmn/src/compiler/messages.ts @@ -1,4 +1,4 @@ -import { CompilerErrorNamespace, CompilerErrorSeverity, CompilerEvent, CompilerMessageSpec as m } from "@keymanapp/common-types"; +import { CompilerErrorNamespace, CompilerErrorSeverity, CompilerEvent, CompilerMessageSpec as m, compilerExceptionToString as exc } from "@keymanapp/common-types"; const Namespace = CompilerErrorNamespace.KmnCompiler; const SevInfo = CompilerErrorSeverity.Info | Namespace; @@ -44,14 +44,29 @@ export const enum KmnCompilerMessageRanges { and the below ranges are reserved. */ export class CompilerMessages { - static Fatal_UnexpectedException = (o:{e: any}) => m(this.FATAL_UnexpectedException, `Unexpected exception: ${(o.e ?? 'unknown error').toString()}\n\nCall stack:\n${(o.e instanceof Error ? o.e.stack : (new Error()).stack)}`); + static Fatal_UnexpectedException = (o:{e: any}) => m(this.FATAL_UnexpectedException, `Unexpected exception: ${exc(o.e)}`); static FATAL_UnexpectedException = SevFatal | 0x1000; - static Fatal_MissingWasmModule = () => m(this.FATAL_MissingWasmModule, `Could not instanatiate WASM compiler module`); + static Fatal_MissingWasmModule = (o:{e?: any}) => m(this.FATAL_MissingWasmModule, `Could not instantiate WASM compiler module or initialization failed: ${exc(o.e)}`); static FATAL_MissingWasmModule = SevFatal | 0x1001; static Fatal_UnableToSetCompilerOptions = () => m(this.FATAL_UnableToSetCompilerOptions, `Unable to set compiler options`); static FATAL_UnableToSetCompilerOptions = SevFatal | 0x1002; + + static Fatal_CallbacksNotSet = () => m(this.FATAL_CallbacksNotSet, `Callbacks were not set with init`); + static FATAL_CallbacksNotSet = SevFatal | 0x1003; + + static Fatal_UnicodeSetOutOfRange = () => m(this.FATAL_UnicodeSetOutOfRange, `UnicodeSet buffer was too small`); + static FATAL_UnicodeSetOutOfRange = SevFatal | 0x1004; + + static Error_UnicodeSetHasStrings = () => m(this.ERROR_UnicodeSetHasStrings, `UnicodeSet contains strings, not allowed`); + static ERROR_UnicodeSetHasStrings = SevError | 0x1005; + + static Error_UnicodeSetHasProperties = () => m(this.ERROR_UnicodeSetHasProperties, `UnicodeSet contains properties, not allowed`); + static ERROR_UnicodeSetHasProperties = SevError | 0x1006; + + static Error_UnicodeSetSyntaxError = () => m(this.ERROR_UnicodeSetSyntaxError, `UnicodeSet had a Syntax Error while parsing`); + static ERROR_UnicodeSetSyntaxError = SevError | 0x1007; } export function mapErrorFromKmcmplib(line: number, code: number, msg: string): CompilerEvent { diff --git a/developer/src/kmc-kmn/src/main.ts b/developer/src/kmc-kmn/src/main.ts index c3c3d6f173..70d11989c6 100644 --- a/developer/src/kmc-kmn/src/main.ts +++ b/developer/src/kmc-kmn/src/main.ts @@ -1,2 +1,2 @@ -export { Compiler } from './compiler/compiler.js'; +export { KmnCompiler } from './compiler/compiler.js'; diff --git a/developer/src/kmc-kmn/test/test-compiler.ts b/developer/src/kmc-kmn/test/test-compiler.ts index 081ed7762b..2eacd219e6 100644 --- a/developer/src/kmc-kmn/test/test-compiler.ts +++ b/developer/src/kmc-kmn/test/test-compiler.ts @@ -2,7 +2,7 @@ import 'mocha'; import sinon from 'sinon'; import chai, { assert } from 'chai'; import sinonChai from 'sinon-chai'; -import { Compiler } from '../src/main.js'; +import { KmnCompiler } from '../src/main.js'; import { dirname } from 'path'; import { fileURLToPath } from 'url'; import fs from 'fs'; @@ -15,6 +15,7 @@ chai.use(sinonChai); describe('Compiler class', function() { let consoleLog: any; + // TODO: do we need this? beforeEach(function() { consoleLog = sinon.spy(console, 'log'); }); @@ -23,21 +24,36 @@ describe('Compiler class', function() { consoleLog.restore(); }); + it('should throw on failure', async function() { + const compiler = new KmnCompiler(); + const callbacks : any = null; // ERROR + try { + await compiler.init(callbacks) + assert.fail('Expected exception'); + } catch(e) { + assert.ok(e); + } + assert.throws(() => compiler.verifyInitialized()); + }); + it('should start', async function() { - const compiler = new Compiler(); - assert(await compiler.init()); + const compiler = new KmnCompiler(); + const callbacks = new TestCompilerCallbacks(); + assert(await compiler.init(callbacks)); + assert(compiler.verifyInitialized()); }); it('should compile a basic keyboard', async function() { - const compiler = new Compiler(); + const compiler = new KmnCompiler(); const callbacks = new TestCompilerCallbacks(); - assert(await compiler.init()); + assert(await compiler.init(callbacks)); + assert(compiler.verifyInitialized()); const fixtureName = baselineDir + 'k_000___null_keyboard.kmx'; const infile = baselineDir + 'k_000___null_keyboard.kmn'; const outfile = __dirname + '/k_000___null_keyboard.kmx'; - assert(compiler.run(infile, outfile, callbacks, {saveDebug: true, shouldAddCompilerVersion: false})); + assert(compiler.run(infile, outfile, {saveDebug: true, shouldAddCompilerVersion: false})); assert(fs.existsSync(outfile)); const outfileData = fs.readFileSync(outfile); @@ -49,9 +65,10 @@ describe('Compiler class', function() { // Note, above test case is essentially a subset of this one, but will leave both because // the basic keyboard test is slightly simpler to read it('should build all baseline fixtures', async function() { - const compiler = new Compiler(); + const compiler = new KmnCompiler(); const callbacks = new TestCompilerCallbacks(); - assert(await compiler.init()); + assert(await compiler.init(callbacks)); + assert(compiler.verifyInitialized()); const files = fs.readdirSync(baselineDir); for(let file of files) { @@ -60,7 +77,7 @@ describe('Compiler class', function() { const infile = baselineDir + file.replace(/x$/, 'n'); const outfile = __dirname + '/' + file; - assert(compiler.run(infile, outfile, callbacks, {saveDebug: true, shouldAddCompilerVersion: false})); + assert(compiler.run(infile, outfile, {saveDebug: true, shouldAddCompilerVersion: false})); assert(fs.existsSync(outfile)); const outfileData = fs.readFileSync(outfile); @@ -69,6 +86,5 @@ describe('Compiler class', function() { assert.deepEqual(outfileData, fixtureData); } } - }); -}); \ No newline at end of file +}); diff --git a/developer/src/kmc-kmn/test/test-wasm-uset.ts b/developer/src/kmc-kmn/test/test-wasm-uset.ts new file mode 100644 index 0000000000..a63b408a95 --- /dev/null +++ b/developer/src/kmc-kmn/test/test-wasm-uset.ts @@ -0,0 +1,66 @@ +import 'mocha'; +import { assert } from 'chai'; +import { KmnCompiler } from '../src/main.js'; +import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; +import { CompilerMessages } from '../src/compiler/messages.js'; +import { compilerErrorFormatCode } from '@keymanapp/common-types'; + +describe('Compiler UnicodeSet function', function() { + it('should start', async function() { + const compiler = new KmnCompiler(); + const callbacks = new TestCompilerCallbacks(); + assert(await compiler.init(callbacks)); + assert(compiler.verifyInitialized()); + }); + + it('should compile a basic uset', async function() { + const compiler = new KmnCompiler(); + const callbacks = new TestCompilerCallbacks(); + assert(await compiler.init(callbacks)); + assert(compiler.verifyInitialized()); + + const pat = "[abc]"; + const set = compiler.parseUnicodeSet(pat, 23); + + assert(set.length === 1); + assert(set.ranges[0][0] === 'a'.charCodeAt(0)); + assert(set.ranges[0][1] === 'c'.charCodeAt(0)); + }); + it('should compile a more complex uset', async function() { + const compiler = new KmnCompiler(); + const callbacks = new TestCompilerCallbacks(); + assert(await compiler.init(callbacks)); + assert(compiler.verifyInitialized()); + + const pat = "[[🙀A-C]-[CB]]"; + const set = compiler.parseUnicodeSet(pat, 23); + + assert.equal(set.length, 2); + assert.equal(set.ranges[0][0], 'A'.charCodeAt(0)); + assert.equal(set.ranges[0][1], 'A'.charCodeAt(0)); + assert.equal(set.ranges[1][0], 0x1F640); + assert.equal(set.ranges[1][1], 0x1F640); + }); + it('should fail in various ways', async function() { + const compiler = new KmnCompiler(); + const callbacks = new TestCompilerCallbacks(); + assert(await compiler.init(callbacks)); + assert(compiler.verifyInitialized()); + // map from string to failing error + const failures = { + '[:Adlm:]': CompilerMessages.ERROR_UnicodeSetHasProperties, // what it saye + '[acegik]': CompilerMessages.FATAL_UnicodeSetOutOfRange, // 6 ranges, allocated 1 + '[[\\p{Mn}]&[A-Z]]': CompilerMessages.ERROR_UnicodeSetHasProperties, + '[abc{def}]': CompilerMessages.ERROR_UnicodeSetHasStrings, + '[[]': CompilerMessages.ERROR_UnicodeSetSyntaxError, + }; + for(const [pat, expected] of Object.entries(failures)) { + callbacks.clear(); + assert.notOk(compiler.parseUnicodeSet(pat, 1)); + assert.equal(callbacks.messages.length, 1); + const firstMessage = callbacks.messages[0]; + const code = firstMessage.code; + assert.equal(code, expected, `${compilerErrorFormatCode(code)}≠${compilerErrorFormatCode(expected)} got ${firstMessage.message} for ${pat}`); + } + }); +}); diff --git a/developer/src/kmc-ldml/src/compiler/compiler-options.ts b/developer/src/kmc-ldml/src/compiler/compiler-options.ts index d36322513b..3d29e6393a 100644 --- a/developer/src/kmc-ldml/src/compiler/compiler-options.ts +++ b/developer/src/kmc-ldml/src/compiler/compiler-options.ts @@ -1,6 +1,6 @@ -export default interface CompilerOptions { +export interface CompilerOptions { /** * Add debug information to the .kmx file when compiling */ diff --git a/developer/src/kmc-ldml/src/compiler/compiler.ts b/developer/src/kmc-ldml/src/compiler/compiler.ts index 29e0d61a53..b7b46e49b2 100644 --- a/developer/src/kmc-ldml/src/compiler/compiler.ts +++ b/developer/src/kmc-ldml/src/compiler/compiler.ts @@ -1,5 +1,5 @@ import { LDMLKeyboardXMLSourceFileReader, LDMLKeyboard, KMXPlus, CompilerCallbacks, LDMLKeyboardTestDataXMLSourceFile } from '@keymanapp/common-types'; -import CompilerOptions from './compiler-options.js'; +import { CompilerOptions } from './compiler-options.js'; import { CompilerMessages } from './messages.js'; import { BkspCompiler, FinlCompiler, TranCompiler } from './tran.js'; import { DispCompiler } from './disp.js'; @@ -28,7 +28,7 @@ const SECTION_COMPILERS = [ VkeyCompiler, ]; -export default class Compiler { +export class LdmlKeyboardCompiler { private readonly callbacks: CompilerCallbacks; // private readonly options: CompilerOptions; // not currently used diff --git a/developer/src/kmc-ldml/src/compiler/keymanweb-compiler.ts b/developer/src/kmc-ldml/src/compiler/keymanweb-compiler.ts index 3117134c2c..7ecdbe5937 100644 --- a/developer/src/kmc-ldml/src/compiler/keymanweb-compiler.ts +++ b/developer/src/kmc-ldml/src/compiler/keymanweb-compiler.ts @@ -1,19 +1,19 @@ import { CompilerCallbacks, VisualKeyboard, LDMLKeyboard, TouchLayoutFileWriter } from "@keymanapp/common-types"; -import CompilerOptions from "./compiler-options.js"; +import { CompilerOptions } from "./compiler-options.js"; import { TouchLayoutCompiler } from "./touch-layout-compiler.js"; -import VisualKeyboardCompiler from "./visual-keyboard-compiler.js"; +import { LdmlKeyboardVisualKeyboardCompiler } from "./visual-keyboard-compiler.js"; const MINIMUM_KMW_VERSION = '16.0'; -export interface KeymanWebCompilerOptions extends CompilerOptions { +export interface LdmlKeyboardKeymanWebCompilerOptions extends CompilerOptions { }; -export class KeymanWebCompiler { - private readonly options: KeymanWebCompilerOptions; +export class LdmlKeyboardKeymanWebCompiler { + private readonly options: LdmlKeyboardKeymanWebCompilerOptions; private readonly nl: string; private readonly tab: string; - constructor(private callbacks: CompilerCallbacks, options?: KeymanWebCompilerOptions) { + constructor(private callbacks: CompilerCallbacks, options?: LdmlKeyboardKeymanWebCompilerOptions) { this.options = { ...options }; this.nl = this.options.debug ? "\n" : ''; this.tab = this.options.debug ? " " : ''; @@ -21,7 +21,7 @@ export class KeymanWebCompiler { public compileVisualKeyboard(source: LDMLKeyboard.LDMLKeyboardXMLSourceFile) { const nl = this.nl, tab = this.tab; - const vkc = new VisualKeyboardCompiler(); + const vkc = new LdmlKeyboardVisualKeyboardCompiler(); const vk: VisualKeyboard.VisualKeyboard = vkc.compile(source); let result = diff --git a/developer/src/kmc-ldml/src/compiler/metadata-compiler.ts b/developer/src/kmc-ldml/src/compiler/metadata-compiler.ts index f459d5fab9..262b86c801 100644 --- a/developer/src/kmc-ldml/src/compiler/metadata-compiler.ts +++ b/developer/src/kmc-ldml/src/compiler/metadata-compiler.ts @@ -1,12 +1,12 @@ import { KMX, KMXPlus } from '@keymanapp/common-types'; -import CompilerOptions from "./compiler-options.js"; +import { CompilerOptions } from "./compiler-options.js"; import KEYMAN_VERSION from "@keymanapp/keyman-version"; import KMXPlusData = KMXPlus.KMXPlusData; import KMXFile = KMX.KMXFile; import KEYBOARD = KMX.KEYBOARD; -export default class KMXPlusMetadataCompiler { +export class KMXPlusMetadataCompiler { /** * Look for metadata fields in the KMXPlus data and copy them * through to the relevant KMX stores diff --git a/developer/src/kmc-ldml/src/compiler/visual-keyboard-compiler.ts b/developer/src/kmc-ldml/src/compiler/visual-keyboard-compiler.ts index b80b590b9c..d951080b9b 100644 --- a/developer/src/kmc-ldml/src/compiler/visual-keyboard-compiler.ts +++ b/developer/src/kmc-ldml/src/compiler/visual-keyboard-compiler.ts @@ -1,6 +1,6 @@ import { Constants, VisualKeyboard, LDMLKeyboard } from "@keymanapp/common-types"; -export default class VisualKeyboardCompiler { +export class LdmlKeyboardVisualKeyboardCompiler { public compile(source: LDMLKeyboard.LDMLKeyboardXMLSourceFile): VisualKeyboard.VisualKeyboard { let result = new VisualKeyboard.VisualKeyboard(); diff --git a/developer/src/kmc-ldml/src/main.ts b/developer/src/kmc-ldml/src/main.ts index 3bf1c37f1c..5d5d2f09e6 100644 --- a/developer/src/kmc-ldml/src/main.ts +++ b/developer/src/kmc-ldml/src/main.ts @@ -1,10 +1,10 @@ -export { default as Compiler } from './compiler/compiler.js'; -export { KeymanWebCompiler } from './compiler/keymanweb-compiler.js'; -export { default as VisualKeyboardCompiler } from './compiler/visual-keyboard-compiler.js'; +export { LdmlKeyboardCompiler } from './compiler/compiler.js'; +export { LdmlKeyboardKeymanWebCompiler } from './compiler/keymanweb-compiler.js'; +export { LdmlKeyboardVisualKeyboardCompiler } from './compiler/visual-keyboard-compiler.js'; export { TouchLayoutCompiler } from './compiler/touch-layout-compiler.js'; -export { default as CompilerOptions } from './compiler/compiler-options.js'; +export { CompilerOptions } from './compiler/compiler-options.js'; export { CompilerMessages } from './compiler/messages.js'; -export { default as KMXPlusMetadataCompiler } from './compiler/metadata-compiler.js'; +export { KMXPlusMetadataCompiler } from './compiler/metadata-compiler.js'; export { KMXBuilder } from "@keymanapp/common-types"; diff --git a/developer/src/kmc-ldml/test/helpers/index.ts b/developer/src/kmc-ldml/test/helpers/index.ts index 498975f71e..8ba8a28aa8 100644 --- a/developer/src/kmc-ldml/test/helpers/index.ts +++ b/developer/src/kmc-ldml/test/helpers/index.ts @@ -6,11 +6,11 @@ import * as path from 'path'; import { fileURLToPath } from 'url'; import { SectionCompiler } from '../../src/compiler/section-compiler.js'; import { KMXPlus, LDMLKeyboardXMLSourceFileReader, VisualKeyboard, CompilerEvent, LDMLKeyboardTestDataXMLSourceFile } from '@keymanapp/common-types'; -import Compiler from '../../src/compiler/compiler.js'; +import { LdmlKeyboardCompiler } from '../../src/compiler/compiler.js'; import { assert } from 'chai'; -import KMXPlusMetadataCompiler from '../../src/compiler/metadata-compiler.js'; -import CompilerOptions from '../../src/compiler/compiler-options.js'; -import VisualKeyboardCompiler from '../../src/compiler/visual-keyboard-compiler.js'; +import { KMXPlusMetadataCompiler } from '../../src/compiler/metadata-compiler.js'; +import { CompilerOptions } from '../../src/compiler/compiler-options.js'; +import { LdmlKeyboardVisualKeyboardCompiler } from '../../src/compiler/visual-keyboard-compiler.js'; import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; import KMXPlusFile = KMXPlus.KMXPlusFile; @@ -76,13 +76,13 @@ export function loadSectionFixture(compilerClass: typeof SectionCompiler, filena } export function loadTestdata(inputFilename: string, options: CompilerOptions) : LDMLKeyboardTestDataXMLSourceFile { - const k = new Compiler(compilerTestCallbacks, options); + const k = new LdmlKeyboardCompiler(compilerTestCallbacks, options); const source = k.loadTestData(inputFilename); return source; } export function compileKeyboard(inputFilename: string, options: CompilerOptions): KMXPlusFile { - const k = new Compiler(compilerTestCallbacks, options); + const k = new LdmlKeyboardCompiler(compilerTestCallbacks, options); const source = k.load(inputFilename); checkMessages(); assert.isNotNull(source, 'k.load should not have returned null'); @@ -103,7 +103,7 @@ export function compileKeyboard(inputFilename: string, options: CompilerOptions) } export function compileVisualKeyboard(inputFilename: string, options: CompilerOptions): VisualKeyboard.VisualKeyboard { - const k = new Compiler(compilerTestCallbacks, options); + const k = new LdmlKeyboardCompiler(compilerTestCallbacks, options); const source = k.load(inputFilename); checkMessages(); assert.isNotNull(source, 'k.load should not have returned null'); @@ -112,9 +112,9 @@ export function compileVisualKeyboard(inputFilename: string, options: CompilerOp checkMessages(); assert.isTrue(valid, 'k.validate should not have failed'); - const vk = (new VisualKeyboardCompiler()).compile(source); + const vk = (new LdmlKeyboardVisualKeyboardCompiler()).compile(source); checkMessages(); - assert.isNotNull(vk, 'VisualKeyboardCompiler.compile should not have returned null'); + assert.isNotNull(vk, 'LdmlKeyboardVisualKeyboardCompiler.compile should not have returned null'); return vk; } diff --git a/developer/src/kmc-ldml/test/test-keymanweb-compiler.ts b/developer/src/kmc-ldml/test/test-keymanweb-compiler.ts index 43f3721de6..fb4f28daee 100644 --- a/developer/src/kmc-ldml/test/test-keymanweb-compiler.ts +++ b/developer/src/kmc-ldml/test/test-keymanweb-compiler.ts @@ -1,11 +1,11 @@ import 'mocha'; import { assert } from 'chai'; import { checkMessages, compilerTestCallbacks, makePathToFixture } from './helpers/index.js'; -import { KeymanWebCompiler } from '../src/compiler/keymanweb-compiler.js'; -import Compiler from '../src/compiler/compiler.js'; +import { LdmlKeyboardKeymanWebCompiler } from '../src/compiler/keymanweb-compiler.js'; +import { LdmlKeyboardCompiler } from '../src/compiler/compiler.js'; import * as fs from 'fs'; -describe('KeymanWebCompiler', function() { +describe('LdmlKeyboardKeymanWebCompiler', function() { it('should build a .js file', async function() { // Let's build basic.xml @@ -16,7 +16,7 @@ describe('KeymanWebCompiler', function() { // Load input data; we'll use the LDML keyboard compiler loader to save us // effort here - const k = new Compiler(compilerTestCallbacks, {debug: true, addCompilerVersion: false}); + const k = new LdmlKeyboardCompiler(compilerTestCallbacks, {debug: true, addCompilerVersion: false}); const source = k.load(inputFilename); checkMessages(); assert.isNotNull(source, 'k.load should not have returned null'); @@ -27,7 +27,7 @@ describe('KeymanWebCompiler', function() { assert.isTrue(valid, 'k.validate should not have failed'); // Actual test: compile to javascript - const jsCompiler = new KeymanWebCompiler(compilerTestCallbacks, {debug: true}); + const jsCompiler = new LdmlKeyboardKeymanWebCompiler(compilerTestCallbacks, {debug: true}); const output = jsCompiler.compile('basic.xml', source); assert.isNotNull(output); @@ -36,7 +36,7 @@ describe('KeymanWebCompiler', function() { assert.strictEqual(output, outputFixture); // Second test: compile to javascript without debug formatting - const jsCompilerNoDebug = new KeymanWebCompiler(compilerTestCallbacks, {debug: false}); + const jsCompilerNoDebug = new LdmlKeyboardKeymanWebCompiler(compilerTestCallbacks, {debug: false}); const outputNoDebug = jsCompilerNoDebug.compile('basic.xml', source); assert.isNotNull(outputNoDebug); diff --git a/developer/src/kmc-package/build.sh b/developer/src/kmc-package/build.sh index 968b5fd241..3206f60fda 100755 --- a/developer/src/kmc-package/build.sh +++ b/developer/src/kmc-package/build.sh @@ -28,7 +28,7 @@ builder_describe "Build Keyman kmc Package Compiler module" \ "--dry-run,-n don't actually publish, just dry run" builder_describe_outputs \ configure /node_modules \ - build /developer/src/kmc-package/build/src/kmp-compiler.js + build /developer/src/kmc-package/build/src/main.js builder_parse "$@" #------------------------------------------------------------------------------------------------------------------- diff --git a/developer/src/kmc-package/src/compiler/kmp-compiler.ts b/developer/src/kmc-package/src/compiler/kmp-compiler.ts index 160182edb1..b660641df9 100644 --- a/developer/src/kmc-package/src/compiler/kmp-compiler.ts +++ b/developer/src/kmc-package/src/compiler/kmp-compiler.ts @@ -4,7 +4,8 @@ import KEYMAN_VERSION from "@keymanapp/keyman-version"; import { CompilerCallbacks, KvkFile } from '@keymanapp/common-types'; import { CompilerMessages } from './messages.js'; -import { KmpJsonFile, KpsFile, KMX, KmxFileReader } from '@keymanapp/common-types'; +import { KmpJsonFile, KpsFile } from '@keymanapp/common-types'; +import { PackageVersionValidation } from './package-version-validation.js'; const FILEVERSION_KMP_JSON = '12.0'; @@ -104,16 +105,16 @@ export class KmpCompiler { // if(kps.keyboards && kps.keyboards.keyboard) { - kmp.keyboards = this.arrayWrap(kps.keyboards.keyboard).map((keyboard: KpsFile.KpsFileKeyboard) => { - return { - displayFont: keyboard.displayFont ? this.callbacks.path.basename(keyboard.displayFont) : undefined, - oskFont: keyboard.oSKFont ? this.callbacks.path.basename(keyboard.oSKFont) : undefined, - name:keyboard.name, - id:keyboard.iD, - version:keyboard.version, - languages: this.kpsLanguagesToKmpLanguages(this.arrayWrap(keyboard.languages.language) as KpsFile.KpsFileLanguage[]) - }; - }); + kmp.keyboards = this.arrayWrap(kps.keyboards.keyboard).map((keyboard: KpsFile.KpsFileKeyboard) => ({ + displayFont: keyboard.displayFont ? this.callbacks.path.basename(keyboard.displayFont) : undefined, + oskFont: keyboard.oSKFont ? this.callbacks.path.basename(keyboard.oSKFont) : undefined, + name:keyboard.name, + id:keyboard.iD, + version:keyboard.version, + languages: keyboard.languages ? + this.kpsLanguagesToKmpLanguages(this.arrayWrap(keyboard.languages.language) as KpsFile.KpsFileLanguage[]) : + [] + })); } // @@ -121,20 +122,22 @@ export class KmpCompiler { // if(kps.lexicalModels && kps.lexicalModels.lexicalModel) { - kmp.lexicalModels = this.arrayWrap(kps.lexicalModels.lexicalModel).map((model: KpsFile.KpsFileLexicalModel) => { - return { name:model.name, id:model.iD, languages: this.kpsLanguagesToKmpLanguages(this.arrayWrap(model.languages.language) as KpsFile.KpsFileLanguage[]) } - }); + kmp.lexicalModels = this.arrayWrap(kps.lexicalModels.lexicalModel).map((model: KpsFile.KpsFileLexicalModel) => ({ + name:model.name, + id:model.iD, + languages: model.languages ? + this.kpsLanguagesToKmpLanguages(this.arrayWrap(model.languages.language) as KpsFile.KpsFileLanguage[]) : [] + })); } // - // FollowKeyboardVersion support + // Verify version metadata; doing this in the transform + // while we have access to the .kps metadata, and keeping the // - if(kps.options?.followKeyboardVersion !== undefined) { - kmp.info.version = { - description: this.extractKeyboardVersionFromKmx(kpsFilename, kmp) - }; - // TODO: compare the extracted version with other keyboards in the package + const versionValidator = new PackageVersionValidation(this.callbacks); + if(!versionValidator.validateAndUpdateVersions(kpsFilename, kps, kmp)) { + return null; } // @@ -195,67 +198,7 @@ export class KmpCompiler { return language.map((element) => { return { name: element._, id: element.$.ID } }); }; - private extractKeyboardVersionFromKmx(kpsFilename: string, kmp: KmpJsonFile.KmpJsonFile) { - // The DEFAULT_VERSION used to be '1.0', but we now use '0.0' to allow - // pre-release 0.x keyboards to be considered later than a keyboard without - // any version metadata at all. - const DEFAULT_VERSION = '0.0'; - // Note: there is often version metadata in the .kps element, but - // we don't read from the metadata because we want to ensure we have the - // most up-to-date keyboard version data here, from the compiled keyboard. - - // Lexical model packages do not allow FollowKeyboardVersion - if(kmp.lexicalModels && kmp.lexicalModels.length) { - this.callbacks.reportMessage(CompilerMessages.Error_FollowKeyboardVersionNotAllowedForModelPackages()); - return DEFAULT_VERSION; - } - - if(!kmp.keyboards || !kmp.keyboards.length) { - this.callbacks.reportMessage(CompilerMessages.Warn_FollowKeyboardVersionButNoKeyboards()); - return DEFAULT_VERSION; - } - - // Reset the keyboard version to the default in the kmp.json metadata, for - // warning/failure code paths in this file - kmp.keyboards[0].version = DEFAULT_VERSION; - - const file = kmp.files.find(file => this.callbacks.path.basename(file.name, '.kmx') == kmp.keyboards[0].id); - if(!file) { - this.callbacks.reportMessage(CompilerMessages.Error_KeyboardFileNotFound({id:kmp.keyboards[0].id})); - return DEFAULT_VERSION; - } - - const filename = this.callbacks.resolveFilename(kpsFilename, file.name); - if(!this.callbacks.fs.existsSync(filename)) { - // The zip phase will emit an error later if the file is missing, so - // we can just bail cleanly here - // console.debug(`The file ${filename} was not found`); - return DEFAULT_VERSION; - } - - // - // load the .kmx and extract the version number - // - const kmxFileData = this.callbacks.loadFile(filename); - const kmxReader: KmxFileReader = new KmxFileReader(); - const kmx: KMX.KEYBOARD = kmxReader.read(kmxFileData); - if(!kmx) { - // The file couldn't be read, it might be invalid or locked - this.callbacks.reportMessage(CompilerMessages.Error_KeyboardFileNotValid({filename})); - return DEFAULT_VERSION; - } - - const store = kmx.stores.find(store => store.dwSystemID == KMX.KMXFile.TSS_KEYBOARDVERSION); - if(!store) { - // We have no version number store, so use default version - this.callbacks.reportMessage(CompilerMessages.Warn_KeyboardFileHasNoKeyboardVersion({filename})); - return DEFAULT_VERSION; - } - - kmp.keyboards[0].version = store.dpString; - return store.dpString; - } private stripUndefined(o: any) { for(const key in o) { diff --git a/developer/src/kmc-package/src/compiler/messages.ts b/developer/src/kmc-package/src/compiler/messages.ts index 8c47e9e0db..35eb5a8512 100644 --- a/developer/src/kmc-package/src/compiler/messages.ts +++ b/developer/src/kmc-package/src/compiler/messages.ts @@ -1,7 +1,7 @@ import { CompilerErrorNamespace, CompilerErrorSeverity, CompilerMessageSpec as m } from "@keymanapp/common-types"; const Namespace = CompilerErrorNamespace.PackageCompiler; -// const SevInfo = CompilerErrorSeverity.Info | Namespace; +const SevInfo = CompilerErrorSeverity.Info | Namespace; // const SevHint = CompilerErrorSeverity.Hint | Namespace; const SevWarn = CompilerErrorSeverity.Warn | Namespace; const SevError = CompilerErrorSeverity.Error | Namespace; @@ -31,28 +31,28 @@ export class CompilerMessages { `FollowKeyboardVersion is not allowed in model packages`); static ERROR_FollowKeyboardVersionNotAllowedForModelPackages = SevError | 0x0006; - static Warn_FollowKeyboardVersionButNoKeyboards = () => m(this.WARN_FollowKeyboardVersionButNoKeyboards, + static Error_FollowKeyboardVersionButNoKeyboards = () => m(this.ERROR_FollowKeyboardVersionButNoKeyboards, `FollowKeyboardVersion is set, but the package contains no keyboards`); - static WARN_FollowKeyboardVersionButNoKeyboards = SevWarn | 0x0007; + static ERROR_FollowKeyboardVersionButNoKeyboards = SevError | 0x0007; - static Error_KeyboardFileNotFound = (o:{id:string}) => m(this.ERROR_KeyboardFileNotFound, + static Error_KeyboardContentFileNotFound = (o:{id:string}) => m(this.ERROR_KeyboardContentFileNotFound, `Keyboard ${o.id} was listed in but a corresponding .kmx file was not found in `); - static ERROR_KeyboardFileNotFound = SevError | 0x0008; + static ERROR_KeyboardContentFileNotFound = SevError | 0x0008; static Error_KeyboardFileNotValid = (o:{filename:string}) => m(this.ERROR_KeyboardFileNotValid, `Keyboard file ${o.filename} is not a valid .kmx file`); static ERROR_KeyboardFileNotValid = SevError | 0x0009; - static Warn_KeyboardFileHasNoKeyboardVersion = (o:{filename:string}) => m(this.WARN_KeyboardFileHasNoKeyboardVersion, - `Keyboard file ${o.filename} has no &KeyboardVersion store`); - static WARN_KeyboardFileHasNoKeyboardVersion = SevWarn | 0x000A; + static Info_KeyboardFileHasNoKeyboardVersion = (o:{filename:string}) => m(this.INFO_KeyboardFileHasNoKeyboardVersion, + `Keyboard file ${o.filename} has no &KeyboardVersion store, using default '0.0'`); + static INFO_KeyboardFileHasNoKeyboardVersion = SevInfo | 0x000A; static Error_PackageCannotContainBothModelsAndKeyboards = () => m(this.ERROR_PackageCannotContainBothModelsAndKeyboards, `The package contains both lexical models and keyboards, which is not permitted.`); static ERROR_PackageCannotContainBothModelsAndKeyboards = SevError | 0x000B; - static Warn_PackageShouldNotRepeatLanguages = (o:{resourceType: string, id: string, tag: string}) => m(this.WARN_PackageShouldNotRepeatLanguages, - `The ${o.resourceType} ${o.id} has a repeated language "${o.tag}".`); + static Warn_PackageShouldNotRepeatLanguages = (o:{resourceType: string, id: string, minimalTag: string, firstTag: string, secondTag: string}) => m(this.WARN_PackageShouldNotRepeatLanguages, + `Two language tags in ${o.resourceType} ${o.id}, '${o.firstTag}' and '${o.secondTag}', reduce to the same minimal tag '${o.minimalTag}'.`); static WARN_PackageShouldNotRepeatLanguages = SevWarn | 0x000C; static Warn_PackageNameDoesNotFollowLexicalModelConventions = (o:{filename: string}) => m(this.WARN_PackageNameDoesNotFollowLexicalModelConventions, @@ -74,5 +74,41 @@ export class CompilerMessages { static Error_PackageNameCannotBeBlank = () => m(this.ERROR_PackageNameCannotBeBlank, `Package name cannot be an empty string.`); static ERROR_PackageNameCannotBeBlank = SevError | 0x0010; + + static Error_KeyboardFileNotFound = (o:{filename:string}) => m(this.ERROR_KeyboardFileNotFound, + `Keyboard file ${o.filename} was not found. Has it been compiled?`); + static ERROR_KeyboardFileNotFound = SevError | 0x0011; + + static Warn_KeyboardVersionsDoNotMatch = (o: {keyboard:string, version:string, firstKeyboard:string, firstVersion:string}) => m(this.WARN_KeyboardVersionsDoNotMatch, + `Keyboard ${o.keyboard} version ${o.version} does not match keyboard ${o.firstKeyboard} version ${o.firstVersion}.`); + static WARN_KeyboardVersionsDoNotMatch = SevWarn | 0x0012; + + static Warn_KeyboardVersionsDoNotMatchPackageVersion = (o: {keyboard:string, keyboardVersion: string, packageVersion: string}) => m(this.WARN_KeyboardVersionsDoNotMatchPackageVersion, + `Keyboard ${o.keyboard} version ${o.keyboardVersion} does not match package version ${o.packageVersion}.`); + static WARN_KeyboardVersionsDoNotMatchPackageVersion = SevWarn | 0x0013; + + static Error_LanguageTagIsNotValid = (o: {resourceType: string, id:string, lang:string, e:any}) => m(this.ERROR_LanguageTagIsNotValid, + `Language tag '${o.lang}' in ${o.resourceType} ${o.id} is invalid.`); + static ERROR_LanguageTagIsNotValid = SevError | 0x0014; + + static Warn_LanguageTagIsNotMinimal = (o: {resourceType: string, id:string, actual:string, expected:string}) => m(this.WARN_LanguageTagIsNotMinimal, + `Language tag '${o.actual}' in ${o.resourceType} ${o.id} is not minimal, and should be '${o.expected}'.`); + static WARN_LanguageTagIsNotMinimal = SevWarn | 0x0015; + + static Error_MustHaveAtLeastOneLanguage = (o:{resourceType:string, id:string}) => m(this.ERROR_MustHaveAtLeastOneLanguage, + `The ${o.resourceType} ${o.id} must have at least one language specified.`); + static ERROR_MustHaveAtLeastOneLanguage = SevError | 0x0016; + + static Warn_RedistFileShouldNotBeInPackage = (o:{filename:string}) => m(this.WARN_RedistFileShouldNotBeInPackage, + `The Keyman system file '${o.filename}' should not be compiled into the package.`); + static WARN_RedistFileShouldNotBeInPackage = SevWarn | 0x0017; + + static Warn_DocFileDangerous = (o:{filename:string}) => m(this.WARN_DocFileDangerous, + `Microsoft Word .doc or .docx files ('${o.filename}') are not portable. You should instead use HTML or PDF format.`); + static WARN_DocFileDangerous = SevWarn | 0x0018; + + static Error_PackageMustContainAModelOrAKeyboard = () => m(this.ERROR_PackageMustContainAModelOrAKeyboard, + `Package must contain a lexical model or a keyboard.`); + static ERROR_PackageMustContainAModelOrAKeyboard = SevError | 0x0019; } diff --git a/developer/src/kmc-package/src/compiler/package-validation.ts b/developer/src/kmc-package/src/compiler/package-validation.ts index 5ef32c43da..0fd139bb47 100644 --- a/developer/src/kmc-package/src/compiler/package-validation.ts +++ b/developer/src/kmc-package/src/compiler/package-validation.ts @@ -1,5 +1,6 @@ import { KmpJsonFile, CompilerCallbacks } from '@keymanapp/common-types'; import { CompilerMessages } from './messages.js'; +import { keymanEngineForWindowsFiles, keymanForWindowsInstallerFiles, keymanForWindowsRedistFiles } from './redist-files.js'; // const SLexicalModelExtension = '.model.js'; @@ -41,16 +42,38 @@ export class PackageValidation { return true; } - private checkForDuplicatedLanguages(resourceType: 'keyboard'|'model', id: string, languages: KmpJsonFile.KmpJsonFileLanguage[]) { - let tags: {[index:string]: boolean} = {}; + private checkForDuplicatedOrNonMinimalLanguages(resourceType: 'keyboard'|'model', id: string, languages: KmpJsonFile.KmpJsonFileLanguage[]): boolean { + let minimalTags: {[tag: string]: string} = {}; + + if(languages.length == 0) { + this.callbacks.reportMessage(CompilerMessages.Error_MustHaveAtLeastOneLanguage({resourceType, id})); + return false; + } + for(let lang of languages) { - const langTag = lang.id.toLowerCase(); - if(tags[langTag]) { - this.callbacks.reportMessage(CompilerMessages.Warn_PackageShouldNotRepeatLanguages({resourceType:resourceType, id:id, tag:lang.id})); - } else { - tags[langTag] = true; + let locale; + try { + locale = new Intl.Locale(lang.id); + } catch(e: any) { + this.callbacks.reportMessage(CompilerMessages.Error_LanguageTagIsNotValid({resourceType, id, lang: lang.id, e})); + return false; + } + + const minimalTag = locale.minimize().toString(); + + if(minimalTag.toLowerCase() !== lang.id.toLowerCase()) { + this.callbacks.reportMessage(CompilerMessages.Warn_LanguageTagIsNotMinimal({resourceType, id, actual: lang.id, expected: minimalTag})); + } + + if(minimalTags[minimalTag]) { + this.callbacks.reportMessage(CompilerMessages.Warn_PackageShouldNotRepeatLanguages({resourceType, id, minimalTag, firstTag: lang.id, secondTag: minimalTags[minimalTag]})); + } + else { + minimalTags[minimalTag] = lang.id; } } + + return true; } private checkForModelsAndKeyboardsInSamePackage(kmpJson: KmpJsonFile.KmpJsonFile): boolean { @@ -59,6 +82,16 @@ export class PackageValidation { return false; } + if(!kmpJson.lexicalModels?.length && !kmpJson.keyboards?.length) { + // Note: we require at least 1 keyboard or model in the package. This may + // change in the future if we start to use packages to distribute, e.g. + // localizations or themes. + this.callbacks.reportMessage(CompilerMessages.Error_PackageMustContainAModelOrAKeyboard()); + return false; + } + + + return true; } @@ -74,7 +107,9 @@ export class PackageValidation { } for(let model of kmpJson.lexicalModels) { - this.checkForDuplicatedLanguages('model', model.id, model.languages); + if(!this.checkForDuplicatedOrNonMinimalLanguages('model', model.id, model.languages)) { + return false; + } } return true; @@ -92,7 +127,9 @@ export class PackageValidation { } for(let keyboard of kmpJson.keyboards) { - this.checkForDuplicatedLanguages('keyboard', keyboard.id, keyboard.languages); + if(!this.checkForDuplicatedOrNonMinimalLanguages('keyboard', keyboard.id, keyboard.languages)) { + return false; + } } return true; @@ -116,6 +153,23 @@ export class PackageValidation { this.callbacks.reportMessage(CompilerMessages.Warn_FileInPackageDoesNotFollowFilenameConventions({filename})); } + if(!this.checkIfContentFileIsDangerous(file)) { + return false; + } + + return true; + } + + private checkIfContentFileIsDangerous(file: KmpJsonFile.KmpJsonFileContentFile): boolean { + let filename = this.callbacks.path.basename(file.name).toLowerCase(); + if(keymanForWindowsInstallerFiles.includes(filename) || + keymanForWindowsRedistFiles.includes(filename) || + keymanEngineForWindowsFiles.includes(filename)) { + this.callbacks.reportMessage(CompilerMessages.Warn_RedistFileShouldNotBeInPackage({filename})); + } + if(filename.match(/\.doc(x?)$/)) { + this.callbacks.reportMessage(CompilerMessages.Warn_DocFileDangerous({filename})); + } return true; } diff --git a/developer/src/kmc-package/src/compiler/package-version-validation.ts b/developer/src/kmc-package/src/compiler/package-version-validation.ts new file mode 100644 index 0000000000..ffd7565912 --- /dev/null +++ b/developer/src/kmc-package/src/compiler/package-version-validation.ts @@ -0,0 +1,139 @@ +import { KmpJsonFile, CompilerCallbacks, KpsFile, KmxFileReader, KMX } from '@keymanapp/common-types'; +import { CompilerMessages } from './messages.js'; + +export class PackageVersionValidation { + + constructor(private callbacks: CompilerCallbacks) {} + + /** + * Verifies version information in corresponding keyboards and updates kmpJson + * metadata as the version information can be out of sync in the .kps file + * after updating a contained keyboard. + * @param kpsFilename + * @param kps + * @param kmp + * @returns + */ + public validateAndUpdateVersions(kpsFilename: string, kps: KpsFile.KpsFile, kmp: KmpJsonFile.KmpJsonFile) { + const followKeyboardVersion = kps.options?.followKeyboardVersion !== undefined; + + if(followKeyboardVersion) { + if(!this.checkFollowKeyboardVersion(kps, kmp)) { + return false; + } + } + + if(!kmp.keyboards) { + // Lexical models don't have version metadata; only their packages. + return true; + } + + let result = true; + + // We now know we have at least one keyboard in the package + + for(let keyboard of kmp.keyboards) { + result = this.updateKeyboardVersionFromKmx(kpsFilename, kmp, keyboard) && result; + if(result) { + if(kmp.keyboards[0].version !== keyboard.version) { + this.callbacks.reportMessage(CompilerMessages.Warn_KeyboardVersionsDoNotMatch({ + keyboard:keyboard.id, + version:keyboard.version, + firstKeyboard:kmp.keyboards[0].id, + firstVersion:kmp.keyboards[0].version + })); + } + } + } + + if(result) { + if(followKeyboardVersion) { + kmp.info.version.description = kmp.keyboards[0].version; + } + else if(kmp.info.version?.description != kmp.keyboards[0].version) { + // Only need to compare against first keyboard as we compare keyboards above + this.callbacks.reportMessage(CompilerMessages.Warn_KeyboardVersionsDoNotMatchPackageVersion({ + keyboard: kmp.keyboards[0].id, + keyboardVersion: kmp.keyboards[0].version, + packageVersion: kmp.info.version?.description + })); + } + } + + return result; + } + + private checkFollowKeyboardVersion(kps: KpsFile.KpsFile, kmp: KmpJsonFile.KmpJsonFile) { + // Lexical model packages do not allow FollowKeyboardVersion + if(kmp.lexicalModels && kmp.lexicalModels.length) { + this.callbacks.reportMessage(CompilerMessages.Error_FollowKeyboardVersionNotAllowedForModelPackages()); + return false; + } + + if(!kmp.keyboards || !kmp.keyboards.length) { + this.callbacks.reportMessage(CompilerMessages.Error_FollowKeyboardVersionButNoKeyboards()); + return false; + } + + return true; + } + + private updateKeyboardVersionFromKmx( + kpsFilename: string, + kmp: KmpJsonFile.KmpJsonFile, + keyboard: KmpJsonFile.KmpJsonFileKeyboard + ): boolean { + // The DEFAULT_VERSION used to be '1.0', but we now use '0.0' to allow + // pre-release 0.x keyboards to be considered later than a keyboard without + // any version metadata at all. + const DEFAULT_VERSION = '0.0'; + + // Note: there is often version metadata in the .kps element, but + // we don't read from the metadata because we want to ensure we have the + // most up-to-date keyboard version data here, from the compiled keyboard. + + // Reset the keyboard version to the default in the kmp.json metadata, for + // warning/failure code paths in this file + keyboard.version = DEFAULT_VERSION; + + const file = kmp.files.find(file => this.callbacks.path.basename(file.name, '.kmx') == keyboard.id); + if(!file) { + this.callbacks.reportMessage(CompilerMessages.Error_KeyboardContentFileNotFound({id:keyboard.id})); + return false; + } + + const filename = this.callbacks.resolveFilename(kpsFilename, file.name); + if(!this.callbacks.fs.existsSync(filename)) { + this.callbacks.reportMessage(CompilerMessages.Error_KeyboardFileNotFound({filename})); + return false; + } + + // + // load the .kmx and extract the version number + // + let kmxFileData; + try { + kmxFileData = this.callbacks.loadFile(filename); + } catch(e) { + this.callbacks.reportMessage(CompilerMessages.Error_FileCouldNotBeRead({filename, e})); + return false; + } + const kmxReader: KmxFileReader = new KmxFileReader(); + const kmx: KMX.KEYBOARD = kmxReader.read(kmxFileData); + if(!kmx) { + // The file couldn't be read, it might not be a .kmx file + this.callbacks.reportMessage(CompilerMessages.Error_KeyboardFileNotValid({filename})); + return false; + } + + const store = kmx.stores.find(store => store.dwSystemID == KMX.KMXFile.TSS_KEYBOARDVERSION); + if(!store) { + // We have no version number store, so use default version + this.callbacks.reportMessage(CompilerMessages.Info_KeyboardFileHasNoKeyboardVersion({filename})); + return true; + } + + keyboard.version = store.dpString; + return true; + } +} diff --git a/developer/src/kmc-package/src/compiler/redist-files.ts b/developer/src/kmc-package/src/compiler/redist-files.ts new file mode 100644 index 0000000000..9fccb32944 --- /dev/null +++ b/developer/src/kmc-package/src/compiler/redist-files.ts @@ -0,0 +1,64 @@ + +/** + * This is a set of known redistributable files for Keyman for Windows that + * should not be included in packages. It is not critical that this list matches + * the current deployment; it is just for warning against accidental inclusion + * of these files by package authors. Some redistributable files have been + * intentionally excluded because they could legitimately be a different file + * with the same name. + * + * This matches behaviour from the legacy package compiler; we may want to + * reconsider how this is done in the future. + * + * These lists have been constructed from 17.0.109 alpha build. Filenames + * intentionally in lower case. + */ + +export const + keymanForWindowsInstallerFiles: string[] = [ + 'keymandesktop.msi', + 'keymanengine.msm' + ]; + + +export const + keymanEngineForWindowsFiles: string[] = [ + 'base.xslt', + 'crashpad_handler.exe', + 'keyman-debug-etw.man', + 'keyman.exe', + 'keyman32.dll', + 'keyman64.dll', + 'keymanmc.dll', + 'keymanx64.exe', + 'kmcomapi.dll', + 'kmcomapi.x64.dll', + 'kmrefresh.x64.exe', + 'kmrefresh.x86.exe', + 'kmtip.dll', + 'kmtip64.dll', + 'mcompile.exe', + 'sentry.dll', + 'sentry.x64.dll', + 'si_browsers.xslt', + 'si_fonts.xslt', + 'si_hookdlls.xslt', + 'si_keyman.xslt', + 'si_language.xslt', + 'si_office.xslt', + 'si_overview.xslt', + 'si_processes.xslt', + 'si_processes_x64.xslt', + 'si_startup.xslt', + 'tsysinfo.exe', + ]; + +export const + keymanForWindowsRedistFiles: string[] = [ + 'desktop_resources.dll', + 'keymandesktop.chm', + 'kmbrowserhost.exe', + 'kmconfig.exe', + 'kmshell.exe', + 'unicodedata.mdb', + ]; diff --git a/developer/src/kmc-package/test/fixtures/binary_kvk_file/source/binary_kvk_file.kps b/developer/src/kmc-package/test/fixtures/binary_kvk_file/source/binary_kvk_file.kps index d98764ea86..a95f5c6fe1 100644 --- a/developer/src/kmc-package/test/fixtures/binary_kvk_file/source/binary_kvk_file.kps +++ b/developer/src/kmc-package/test/fixtures/binary_kvk_file/source/binary_kvk_file.kps @@ -17,6 +17,7 @@ Binary KVK File + 1.3 @@ -25,5 +26,21 @@ 0 .kvk + + ../../invalid/khmer_angkor.kmx + Keyboard Khmer Angkor + 0 + .kmx + + + + Khmer Angkor + khmer_angkor + 1.3 + + Khmer + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowKeyboardConventions.kps b/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowKeyboardConventions.kps index 5ff6eca048..867129bac3 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowKeyboardConventions.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowKeyboardConventions.kps @@ -9,11 +9,11 @@ SENĆOŦEN (Saanich Dialect) Lexical Model © 2019 National Research Council Canada Eddie Antonio Santos - 1.0.3 + 1.3 - nokeyboardversion.kmx + khmer_angkor.kmx Keyboard Khmer Angkor 0 .kmx @@ -22,7 +22,7 @@ Khmer Angkor - nokeyboardversion + khmer_angkor 1.3 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_language_tag_is_not_valid.kps b/developer/src/kmc-package/test/fixtures/invalid/error_language_tag_is_not_valid.kps new file mode 100644 index 0000000000..3c47540d2b --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/error_language_tag_is_not_valid.kps @@ -0,0 +1,32 @@ + + + + 15.0.266.0 + 7.0 + + + SENĆOŦEN (Saanich Dialect) Lexical Model + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.3 + + + + khmer_angkor.kmx + Keyboard Khmer Angkor + 0 + .kmx + + + + + Khmer Angkor + khmer_angkor + 1.3 + + + English (Australian script) as spoken in Latin + + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/ERROR_PackageCannotContainBothModelsAndKeyboards.kps b/developer/src/kmc-package/test/fixtures/invalid/error_package_cannot_contain_both_models_and_keyboards.kps similarity index 93% rename from developer/src/kmc-package/test/fixtures/invalid/ERROR_PackageCannotContainBothModelsAndKeyboards.kps rename to developer/src/kmc-package/test/fixtures/invalid/error_package_cannot_contain_both_models_and_keyboards.kps index c87b6808c7..5ee547dcf1 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/ERROR_PackageCannotContainBothModelsAndKeyboards.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/error_package_cannot_contain_both_models_and_keyboards.kps @@ -8,12 +8,12 @@ Khmer Angkor © 2015-2022 SIL International Makara Sok - + 1.3 https://keyman.com/keyboards/khmer_angkor - nokeyboardversion.kmx + khmer_angkor.kmx Keyboard Khmer Angkor 0 .kmx @@ -39,7 +39,7 @@ Khmer Angkor - nokeyboardversion + khmer_angkor 1.3 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_package_must_contain_a_model_or_a_keyboard.kps b/developer/src/kmc-package/test/fixtures/invalid/error_package_must_contain_a_model_or_a_keyboard.kps new file mode 100644 index 0000000000..335201a6e5 --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/error_package_must_contain_a_model_or_a_keyboard.kps @@ -0,0 +1,21 @@ + + + + 15.0.266.0 + 7.0 + + + error_package_must_contain_a_model_or_a_keyboard + 1.3 + + + + + khmer_angkor.kmn + Keyboard Khmer Angkor + 0 + .kmn + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank.kps b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank.kps index 6fb56f3827..870d8ae55b 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank.kps @@ -9,11 +9,11 @@ © 2019 National Research Council Canada Eddie Antonio Santos - 1.0.3 + 1.3 - nokeyboardversion.kmx + khmer_angkor.kmx Keyboard Khmer Angkor 0 .kmx @@ -22,7 +22,7 @@ Khmer Angkor - nokeyboardversion + khmer_angkor 1.3 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_2.kps b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_2.kps index 46b182ffc6..01eba9981d 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_2.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_2.kps @@ -8,11 +8,11 @@ © 2019 National Research Council Canada Eddie Antonio Santos - 1.0.3 + 1.3 - nokeyboardversion.kmx + khmer_angkor.kmx Keyboard Khmer Angkor 0 .kmx @@ -21,7 +21,7 @@ Khmer Angkor - nokeyboardversion + khmer_angkor 1.3 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/keyboardcontentfilenotfound.kps b/developer/src/kmc-package/test/fixtures/invalid/keyboardcontentfilenotfound.kps new file mode 100644 index 0000000000..cfcd527894 --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/keyboardcontentfilenotfound.kps @@ -0,0 +1,128 @@ + + + + 15.0.266.0 + 7.0 + + + + readme.htm + splash.gif + + + + + + + + + + Khmer Angkor + © 2015-2022 SIL International + Makara Sok + + https://keyman.com/keyboards/khmer_angkor + + + + + ..\build\khmer_angkor.js + File khmer_angkor.js + 0 + .js + + + ..\build\khmer_angkor.kvk + File khmer_angkor.kvk + 0 + .kvk + + + welcome\keyboard_layout.png + File keyboard_layout.png + 0 + .png + + + welcome\welcome.htm + File welcome.htm + 0 + .htm + + + ..\shared\fonts\khmer\mondulkiri\FONTLOG.txt + File FONTLOG.txt + 0 + .txt + + + ..\shared\fonts\khmer\mondulkiri\Mondulkiri-R.ttf + Font Khmer Mondulkiri + 0 + .ttf + + + ..\shared\fonts\khmer\mondulkiri\OFL.txt + File OFL.txt + 0 + .txt + + + ..\shared\fonts\khmer\mondulkiri\OFL-FAQ.txt + File OFL-FAQ.txt + 0 + .txt + + + welcome\KAK_Documentation_EN.pdf + File KAK_Documentation_EN.pdf + 0 + .pdf + + + welcome\KAK_Documentation_KH.pdf + File KAK_Documentation_KH.pdf + 0 + .pdf + + + readme.htm + File readme.htm + 0 + .htm + + + welcome\image002.png + File image002.png + 0 + .png + + + ..\shared\fonts\khmer\busrakbd\khmer_busra_kbd.ttf + Font KhmerBusraKbd + 0 + .ttf + + + splash.gif + File splash.gif + 0 + .gif + + + + + Khmer Angkor + khmer_angkor + 1.3 + ..\shared\fonts\khmer\busrakbd\khmer_busra_kbd.ttf + ..\shared\fonts\khmer\mondulkiri\Mondulkiri-R.ttf + + Central Khmer (Khmer, Cambodia) + + + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/keyboardfilenotfound.kps b/developer/src/kmc-package/test/fixtures/invalid/keyboardfilenotfound.kps index 224dd52042..cf6e49053a 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/keyboardfilenotfound.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/keyboardfilenotfound.kps @@ -5,11 +5,6 @@ 7.0 - - readme.htm - splash.gif - - @@ -25,97 +20,18 @@ - ..\build\khmer_angkor.js - File khmer_angkor.js + + keyboardfilenotfound.kmx + Keyboard Khmer Angkor 0 - .js - - - ..\build\khmer_angkor.kvk - File khmer_angkor.kvk - 0 - .kvk - - - welcome\keyboard_layout.png - File keyboard_layout.png - 0 - .png - - - welcome\welcome.htm - File welcome.htm - 0 - .htm - - - ..\shared\fonts\khmer\mondulkiri\FONTLOG.txt - File FONTLOG.txt - 0 - .txt - - - ..\shared\fonts\khmer\mondulkiri\Mondulkiri-R.ttf - Font Khmer Mondulkiri - 0 - .ttf - - - ..\shared\fonts\khmer\mondulkiri\OFL.txt - File OFL.txt - 0 - .txt - - - ..\shared\fonts\khmer\mondulkiri\OFL-FAQ.txt - File OFL-FAQ.txt - 0 - .txt - - - welcome\KAK_Documentation_EN.pdf - File KAK_Documentation_EN.pdf - 0 - .pdf - - - welcome\KAK_Documentation_KH.pdf - File KAK_Documentation_KH.pdf - 0 - .pdf - - - readme.htm - File readme.htm - 0 - .htm - - - welcome\image002.png - File image002.png - 0 - .png - - - ..\shared\fonts\khmer\busrakbd\khmer_busra_kbd.ttf - Font KhmerBusraKbd - 0 - .ttf - - - splash.gif - File splash.gif - 0 - .gif + .kmx Khmer Angkor - khmer_angkor + keyboardfilenotfound 1.3 - ..\shared\fonts\khmer\busrakbd\khmer_busra_kbd.ttf - ..\shared\fonts\khmer\mondulkiri\Mondulkiri-R.ttf Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/keyman.en.error_must_have_at_least_one_language.model.kps b/developer/src/kmc-package/test/fixtures/invalid/keyman.en.error_must_have_at_least_one_language.model.kps new file mode 100644 index 0000000000..b79330f06f --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/keyman.en.error_must_have_at_least_one_language.model.kps @@ -0,0 +1,28 @@ + + + + 15.0.266.0 + 7.0 + + + SENĆOŦEN (Saanich Dialect) Lexical Model + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.0.3 + + + + example.qaa.sencoten.model.js + Lexical model example.qaa.sencoten.model.js + 0 + .model.js + + + + + SENĆOŦEN dictionary + example.qaa.sencoten + + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/khmer_angkor.kmx b/developer/src/kmc-package/test/fixtures/invalid/khmer_angkor.kmx new file mode 100644 index 0000000000..c3d0289f48 Binary files /dev/null and b/developer/src/kmc-package/test/fixtures/invalid/khmer_angkor.kmx differ diff --git a/developer/src/kmc-package/test/fixtures/invalid/my special keyboard.kmx b/developer/src/kmc-package/test/fixtures/invalid/my special keyboard.kmx new file mode 100644 index 0000000000..c3d0289f48 Binary files /dev/null and b/developer/src/kmc-package/test/fixtures/invalid/my special keyboard.kmx differ diff --git a/developer/src/kmc-package/test/fixtures/invalid/my_special-keyboard.kmx b/developer/src/kmc-package/test/fixtures/invalid/my_special-keyboard.kmx new file mode 100644 index 0000000000..c3d0289f48 Binary files /dev/null and b/developer/src/kmc-package/test/fixtures/invalid/my_special-keyboard.kmx differ diff --git a/developer/src/kmc-package/test/fixtures/invalid/version_four.kmn b/developer/src/kmc-package/test/fixtures/invalid/version_four.kmn new file mode 100644 index 0000000000..cb2cce5816 --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/version_four.kmn @@ -0,0 +1,6 @@ +store(&name) 'version 4' +store(&keyboardversion) '4.0' + +begin unicode > use(main) + +group(main) using keys \ No newline at end of file diff --git a/developer/src/kmc-package/test/fixtures/invalid/version_four.kmx b/developer/src/kmc-package/test/fixtures/invalid/version_four.kmx new file mode 100644 index 0000000000..7180460e96 Binary files /dev/null and b/developer/src/kmc-package/test/fixtures/invalid/version_four.kmx differ diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_doc_file_dangerous.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_doc_file_dangerous.kps new file mode 100644 index 0000000000..045e14b740 --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_doc_file_dangerous.kps @@ -0,0 +1,38 @@ + + + + 15.0.266.0 + 7.0 + + + SENĆOŦEN (Saanich Dialect) Lexical Model + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.3 + + + + khmer_angkor.kmx + Keyboard Khmer Angkor + 0 + .kmx + + + + khmer_angkor.docx + Documentation + 0 + .docx + + + + + Khmer Angkor + khmer_angkor + 1.3 + + Khmer + + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions.kps index 25c100256b..6523df4813 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions.kps @@ -8,7 +8,7 @@ SENĆOŦEN (Saanich Dialect) Lexical Model © 2019 National Research Council Canada Eddie Antonio Santos - 1.0.3 + 1.3 @@ -22,7 +22,7 @@ Khmer Angkor - nokeyboardversion + my special keyboard 1.3 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions_2.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions_2.kps index 0d6e81165e..d29a01c580 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions_2.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions_2.kps @@ -8,12 +8,19 @@ SENĆOŦEN (Saanich Dialect) Lexical Model © 2019 National Research Council Canada Eddie Antonio Santos - 1.0.3 + 1.3 - my_special-keyboard.KMX + my_file.PDF + My Documentation + 0 + .PDF + + + + khmer_angkor.kmx Keyboard my special keyboard 0 .kmx @@ -22,7 +29,7 @@ Khmer Angkor - nokeyboardversion + khmer_angkor 1.3 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_keyboard_versions_do_not_match.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_keyboard_versions_do_not_match.kps new file mode 100644 index 0000000000..2eb09374c6 --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_keyboard_versions_do_not_match.kps @@ -0,0 +1,45 @@ + + + + 15.0.266.0 + 7.0 + + + SENĆOŦEN (Saanich Dialect) Lexical Model + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.3 + + + + khmer_angkor.kmx + Keyboard Khmer Angkor + 0 + .kmx + + + version_four.kmx + Keyboard Version Four + 0 + .kmx + + + + + Khmer Angkor + khmer_angkor + 1.3 + + Khmer + + + + Version 4 + version_four + 4.0 + + Khmer + + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_keyboard_versions_do_not_match_package_version.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_keyboard_versions_do_not_match_package_version.kps new file mode 100644 index 0000000000..fe0276104b --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_keyboard_versions_do_not_match_package_version.kps @@ -0,0 +1,31 @@ + + + + 15.0.266.0 + 7.0 + + + SENĆOŦEN (Saanich Dialect) Lexical Model + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.3 + + + + version_four.kmx + Keyboard Version Four + 0 + .kmx + + + + + Version 4 + version_four + 4.0 + + Khmer + + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_3.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_language_tag_is_not_minimal.kps similarity index 52% rename from developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_3.kps rename to developer/src/kmc-package/test/fixtures/invalid/warn_language_tag_is_not_minimal.kps index 5b29699f4c..8e4440e3da 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_3.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_language_tag_is_not_minimal.kps @@ -4,10 +4,15 @@ 15.0.266.0 7.0 - + + SENĆOŦEN (Saanich Dialect) Lexical Model + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.3 + - nokeyboardversion.kmx + khmer_angkor.kmx Keyboard Khmer Angkor 0 .kmx @@ -16,10 +21,11 @@ Khmer Angkor - nokeyboardversion + khmer_angkor 1.3 - Central Khmer (Khmer, Cambodia) + + Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_package_should_not_repeat_languages.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_package_should_not_repeat_languages.kps index c24f3897f6..a1c6cffe9f 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/warn_package_should_not_repeat_languages.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_package_should_not_repeat_languages.kps @@ -8,11 +8,11 @@ SENĆOŦEN (Saanich Dialect) Lexical Model © 2019 National Research Council Canada Eddie Antonio Santos - 1.0.3 + 1.3 - nokeyboardversion.kmx + khmer_angkor.kmx Keyboard Khmer Angkor 0 .kmx @@ -21,7 +21,7 @@ Khmer Angkor - nokeyboardversion + khmer_angkor 1.3 diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_redist_file_should_not_be_in_package.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_redist_file_should_not_be_in_package.kps new file mode 100644 index 0000000000..1b5d1e246d --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_redist_file_should_not_be_in_package.kps @@ -0,0 +1,38 @@ + + + + 15.0.266.0 + 7.0 + + + SENĆOŦEN (Saanich Dialect) Lexical Model + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.3 + + + + khmer_angkor.kmx + Keyboard Khmer Angkor + 0 + .kmx + + + + keyman.exe + Keyman Program + 0 + .exe + + + + + Khmer Angkor + khmer_angkor + 1.3 + + Khmer + + + + diff --git a/developer/src/kmc-package/test/fixtures/xml_kvk_file/source/xml_kvk_file.kps b/developer/src/kmc-package/test/fixtures/xml_kvk_file/source/xml_kvk_file.kps index f89e1dfd7a..9378181ad1 100644 --- a/developer/src/kmc-package/test/fixtures/xml_kvk_file/source/xml_kvk_file.kps +++ b/developer/src/kmc-package/test/fixtures/xml_kvk_file/source/xml_kvk_file.kps @@ -17,6 +17,7 @@ XML KVK File + 1.3 @@ -25,5 +26,21 @@ 0 .kvk + + ../../invalid/khmer_angkor.kmx + Keyboard Khmer Angkor + 0 + .kmx + + + + Khmer Angkor + khmer_angkor + 1.3 + + Khmer + + + diff --git a/developer/src/kmc-package/test/test-package-compiler.ts b/developer/src/kmc-package/test/test-package-compiler.ts index 86675597b1..731925a25e 100644 --- a/developer/src/kmc-package/test/test-package-compiler.ts +++ b/developer/src/kmc-package/test/test-package-compiler.ts @@ -13,6 +13,8 @@ import { KmpCompiler } from '../src/compiler/kmp-compiler.js'; import { PackageValidation } from '../src/compiler/package-validation.js'; import { CompilerMessages } from '../src/compiler/messages.js'; +const debug = true; + describe('KmpCompiler', function () { const MODELS : string[] = [ 'example.qaa.sencoten', @@ -141,6 +143,8 @@ describe('KmpCompiler', function () { await assert.isNull(kmpCompiler.buildKmpFile(kpsPath, kmpJson)); + if(debug) callbacks.printMessages(); + assert.lengthOf(callbacks.messages, 2); assert.deepEqual(callbacks.messages[0].code, CompilerMessages.WARN_AbsolutePath); assert.deepEqual(callbacks.messages[1].code, CompilerMessages.ERROR_FileDoesNotExist); @@ -169,7 +173,7 @@ describe('KmpCompiler', function () { kmpCompiler.buildKmpFile(kpsPath, kmpJson) } - //TODO: callbacks.printMessages(); after #8711 is merged + if(debug) callbacks.printMessages(); if(messageId) { assert.lengthOf(callbacks.messages, 1); @@ -195,16 +199,16 @@ describe('KmpCompiler', function () { testForMessage(this, ['invalid', 'followkeyboardversion.qaa.sencoten.model.kps'], CompilerMessages.ERROR_FollowKeyboardVersionNotAllowedForModelPackages); }); - // WARN_FollowKeyboardVersionButNoKeyboards + // ERROR_FollowKeyboardVersionButNoKeyboards - it('should generate WARN_FollowKeyboardVersionButNoKeyboards if is set for a package with no keyboards or models', async function() { - testForMessage(this, ['invalid', 'followkeyboardversion.empty.kps'], CompilerMessages.WARN_FollowKeyboardVersionButNoKeyboards); + it('should generate ERROR_FollowKeyboardVersionButNoKeyboards if is set for a package with no keyboards', async function() { + testForMessage(this, ['invalid', 'followkeyboardversion.empty.kps'], CompilerMessages.ERROR_FollowKeyboardVersionButNoKeyboards); }); - // ERROR_KeyboardFileNotFound + // ERROR_KeyboardContentFileNotFound - it('should generate ERROR_KeyboardFileNotFound if a is listed in a package but not found in ', async function() { - testForMessage(this, ['invalid', 'keyboardfilenotfound.kps'], CompilerMessages.ERROR_KeyboardFileNotFound); + it('should generate ERROR_KeyboardContentFileNotFound if a is listed in a package but not found in ', async function() { + testForMessage(this, ['invalid', 'keyboardcontentfilenotfound.kps'], CompilerMessages.ERROR_KeyboardContentFileNotFound); }); // ERROR_KeyboardFileNotValid @@ -213,16 +217,16 @@ describe('KmpCompiler', function () { testForMessage(this, ['invalid', 'keyboardfilenotvalid.kps'], CompilerMessages.ERROR_KeyboardFileNotValid); }); - // WARN_KeyboardFileHasNoKeyboardVersion + // INFO_KeyboardFileHasNoKeyboardVersion - it('should generate WARN_KeyboardFileHasNoKeyboardVersion if is set but keyboard has no version', async function() { - testForMessage(this, ['invalid', 'nokeyboardversion.kps'], CompilerMessages.WARN_KeyboardFileHasNoKeyboardVersion); + it('should generate INFO_KeyboardFileHasNoKeyboardVersion if is set but keyboard has no version', async function() { + testForMessage(this, ['invalid', 'nokeyboardversion.kps'], CompilerMessages.INFO_KeyboardFileHasNoKeyboardVersion); }); // ERROR_PackageCannotContainBothModelsAndKeyboards it('should generate ERROR_PackageCannotContainBothModelsAndKeyboards if package has both keyboards and models', async function() { - testForMessage(this, ['invalid', 'ERROR_PackageCannotContainBothModelsAndKeyboards.kps'], CompilerMessages.ERROR_PackageCannotContainBothModelsAndKeyboards); + testForMessage(this, ['invalid', 'error_package_cannot_contain_both_models_and_keyboards.kps'], CompilerMessages.ERROR_PackageCannotContainBothModelsAndKeyboards); }); // WARN_PackageShouldNotRepeatLanguages (models) @@ -261,7 +265,63 @@ describe('KmpCompiler', function () { it('should generate ERROR_PackageNameCannotBeBlank if package info has empty name', async function() { testForMessage(this, ['invalid', 'error_package_name_cannot_be_blank.kps'], CompilerMessages.ERROR_PackageNameCannotBeBlank); // blank field testForMessage(this, ['invalid', 'error_package_name_cannot_be_blank_2.kps'], CompilerMessages.ERROR_PackageNameCannotBeBlank); // missing field - testForMessage(this, ['invalid', 'error_package_name_cannot_be_blank_3.kps'], CompilerMessages.ERROR_PackageNameCannotBeBlank); // missing info section }); + // ERROR_KeyboardFileNotFound + + it('should generate ERROR_KeyboardFileNotFound if a is listed in a package but not found in ', async function() { + testForMessage(this, ['invalid', 'keyboardfilenotfound.kps'], CompilerMessages.ERROR_KeyboardFileNotFound); + }); + + // WARN_KeyboardVersionsDoNotMatch + + it('should generate WARN_KeyboardVersionsDoNotMatch if two have different versions', async function() { + testForMessage(this, ['invalid', 'warn_keyboard_versions_do_not_match.kps'], CompilerMessages.WARN_KeyboardVersionsDoNotMatch); + }); + + // WARN_KeyboardVersionsDoNotMatchPackageVersion + + it('should generate WARN_KeyboardVersionsDoNotMatchPackageVersion if version does not match package version', async function() { + testForMessage(this, ['invalid', 'warn_keyboard_versions_do_not_match_package_version.kps'], CompilerMessages.WARN_KeyboardVersionsDoNotMatchPackageVersion); + }); + + // ERROR_LanguageTagIsNotValid + + it('should generate ERROR_LanguageTagIsNotValid if keyboard has an invalid language tag', async function() { + testForMessage(this, ['invalid', 'error_language_tag_is_not_valid.kps'], CompilerMessages.ERROR_LanguageTagIsNotValid); + }); + + // WARN_LanguageTagIsNotMinimal + + it('should generate WARN_LanguageTagIsNotMinimal if keyboard has a non-minimal language tag', async function() { + testForMessage(this, ['invalid', 'warn_language_tag_is_not_minimal.kps'], CompilerMessages.WARN_LanguageTagIsNotMinimal); + }); + + // ERROR_MustHaveAtLeastOneLanguage + + it('should generate ERROR_MustHaveAtLeastOneLanguage if model or keyboard has zero language tags', async function() { + testForMessage(this, ['invalid', 'keyman.en.error_must_have_at_least_one_language.model.kps'], + CompilerMessages.ERROR_MustHaveAtLeastOneLanguage); + }); + + // WARN_RedistFileShouldNotBeInPackage + + it('should generate WARN_RedistFileShouldNotBeInPackage if package contains a redist file', async function() { + testForMessage(this, ['invalid', 'warn_redist_file_should_not_be_in_package.kps'], + CompilerMessages.WARN_RedistFileShouldNotBeInPackage); + }); + + // WARN_DocFileDangerous + + it('should generate WARN_DocFileDangerous if package contains a .doc file', async function() { + testForMessage(this, ['invalid', 'warn_doc_file_dangerous.kps'], + CompilerMessages.WARN_DocFileDangerous); + }); + + // ERROR_PackageMustContainAPackageOrAKeyboard + + it('should generate ERROR_PackageMustContainAModelOrAKeyboard if package contains a .doc file', async function() { + testForMessage(this, ['invalid', 'error_package_must_contain_a_model_or_a_keyboard.kps'], + CompilerMessages.ERROR_PackageMustContainAModelOrAKeyboard); + }); }); diff --git a/developer/src/kmc/src/commands/build/BuildKmnKeyboard.ts b/developer/src/kmc/src/commands/build/BuildKmnKeyboard.ts index cd5b7c7ac3..9055e2862b 100644 --- a/developer/src/kmc/src/commands/build/BuildKmnKeyboard.ts +++ b/developer/src/kmc/src/commands/build/BuildKmnKeyboard.ts @@ -1,6 +1,6 @@ import * as path from 'path'; import { BuildActivity, BuildActivityOptions } from './BuildActivity.js'; -import { Compiler } from '@keymanapp/kmc-kmn'; +import { KmnCompiler } from '@keymanapp/kmc-kmn'; import { platform } from 'os'; import { CompilerCallbacks } from '@keymanapp/common-types'; @@ -10,8 +10,8 @@ export class BuildKmnKeyboard extends BuildActivity { public get compiledExtension(): string { return '.kmx'; } public get description(): string { return 'Build a Keyman keyboard'; } public async build(infile: string, callbacks: CompilerCallbacks, options: BuildActivityOptions): Promise { - let compiler = new Compiler(); - if(!await compiler.init()) { + let compiler = new KmnCompiler(); + if(!await compiler.init(callbacks)) { return false; } @@ -23,7 +23,7 @@ export class BuildKmnKeyboard extends BuildActivity { // TODO: Currently this only builds .kmn->.kmx, and targeting .js is as-yet unsupported // TODO: Support additional options compilerWarningsAsErrors, warnDeprecatedCode - return compiler.run(infile, outfile, callbacks, + return compiler.run(infile, outfile, { saveDebug: options.debug, shouldAddCompilerVersion: options.compilerVersion, @@ -49,4 +49,4 @@ function getPosixAbsolutePath(filename: string): string { filename = filename.replace(/\\/g, '/'); } return filename; -} \ No newline at end of file +} diff --git a/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts b/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts index 4ccb55c122..024f7f5340 100644 --- a/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts +++ b/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts @@ -1,6 +1,6 @@ import * as path from 'path'; import * as fs from 'fs'; -import * as kmc from '@keymanapp/kmc-ldml'; +import * as kmcLdml from '@keymanapp/kmc-ldml'; import { KvkFileWriter, CompilerCallbacks } from '@keymanapp/common-types'; import { BuildActivity, BuildActivityOptions } from './BuildActivity.js'; @@ -43,14 +43,14 @@ export class BuildLdmlKeyboard extends BuildActivity { } function buildLdmlKeyboardToMemory(inputFilename: string, callbacks: CompilerCallbacks, options: BuildActivityOptions): [Uint8Array, Uint8Array, Uint8Array] { - let compilerOptions: kmc.CompilerOptions = { + let compilerOptions: kmcLdml.CompilerOptions = { debug: options.debug ?? false, addCompilerVersion: options.compilerVersion ?? true, // TODO: warnDeprecatedCode: options.warnDeprecatedCode, // TODO: treatWarningsAsErrors: options.treatWarningsAsErrors, } - const k = new kmc.Compiler(callbacks, options); + const k = new kmcLdml.LdmlKeyboardCompiler(callbacks, options); let source = k.load(inputFilename); if (!source) { return [null, null, null]; @@ -62,13 +62,13 @@ function buildLdmlKeyboardToMemory(inputFilename: string, callbacks: CompilerCal // In order for the KMX file to be loaded by non-KMXPlus components, it is helpful // to duplicate some of the metadata - kmc.KMXPlusMetadataCompiler.addKmxMetadata(kmx.kmxplus, kmx.keyboard, compilerOptions); + kmcLdml.KMXPlusMetadataCompiler.addKmxMetadata(kmx.kmxplus, kmx.keyboard, compilerOptions); // Use the builder to generate the binary output file - const builder = new kmc.KMXBuilder(kmx, options.debug); + const builder = new kmcLdml.KMXBuilder(kmx, options.debug); const kmx_binary = builder.compile(); - const vkcompiler = new kmc.VisualKeyboardCompiler(); + const vkcompiler = new kmcLdml.LdmlKeyboardVisualKeyboardCompiler(); const vk = vkcompiler.compile(source); const writer = new KvkFileWriter(); const kvk_binary = writer.write(vk); @@ -78,7 +78,7 @@ function buildLdmlKeyboardToMemory(inputFilename: string, callbacks: CompilerCal // const tlcompiler = new kmc.TouchLayoutCompiler(); // const tl = tlcompiler.compile(source); // const tlwriter = new TouchLayoutFileWriter(); - const kmwcompiler = new kmc.KeymanWebCompiler(callbacks, compilerOptions); + const kmwcompiler = new kmcLdml.LdmlKeyboardKeymanWebCompiler(callbacks, compilerOptions); const kmw_string = kmwcompiler.compile(inputFilename, source); const encoder = new TextEncoder(); const kmw_binary = encoder.encode(kmw_string); diff --git a/developer/src/kmc/src/commands/buildTestData/index.ts b/developer/src/kmc/src/commands/buildTestData/index.ts index 89674efbef..0990b91edb 100644 --- a/developer/src/kmc/src/commands/buildTestData/index.ts +++ b/developer/src/kmc/src/commands/buildTestData/index.ts @@ -29,7 +29,7 @@ export function buildTestData(infile: string, options: BuildTestDataOptions) { function loadTestData(inputFilename: string, options: kmc.CompilerOptions): LDMLKeyboardTestDataXMLSourceFile { const c: CompilerCallbacks = new NodeCompilerCallbacks(); - const k = new kmc.Compiler(c, options); + const k = new kmc.LdmlKeyboardCompiler(c, options); let source = k.loadTestData(inputFilename); if (!source) { return null; diff --git a/developer/src/kmc/src/kmlmi.ts b/developer/src/kmc/src/kmlmi.ts index 508c43ad0e..0868e0ccfe 100644 --- a/developer/src/kmc/src/kmlmi.ts +++ b/developer/src/kmc/src/kmlmi.ts @@ -48,6 +48,9 @@ let jsFilename = program.opts().jsFilename ? program.opts().jsFilename : path.jo const callbacks = new NodeCompilerCallbacks(); let kmpCompiler = new KmpCompiler(callbacks); let kmpJsonData = kmpCompiler.transformKpsToKmpObject(kpsFilename); +if(!kmpJsonData) { + process.exit(1); +} // // Validate the package file diff --git a/developer/src/kmc/test/fixtures/relative_paths/k_000___null_keyboard.kps b/developer/src/kmc/test/fixtures/relative_paths/k_000___null_keyboard.kps index 2839137769..af65dd9269 100644 --- a/developer/src/kmc/test/fixtures/relative_paths/k_000___null_keyboard.kps +++ b/developer/src/kmc/test/fixtures/relative_paths/k_000___null_keyboard.kps @@ -18,7 +18,7 @@ k_000___null_keyboard Copyright (C) Keyman Team Keyman Team - + 0.0 diff --git a/developer/src/kmc/test/test-project-build.ts b/developer/src/kmc/test/test-project-build.ts index a57f77d317..68b5926933 100644 --- a/developer/src/kmc/test/test-project-build.ts +++ b/developer/src/kmc/test/test-project-build.ts @@ -16,8 +16,9 @@ describe('BuildProject', function () { debug: false, warnDeprecatedCode: true, }); - // 4 messages == starting build, build successful x 2 - assert.equal(callbacks.messages.length, 4); + // 5 messages == starting build, info: no keyboard version, build successful x 2 + // callbacks.printMessages(); + assert.equal(callbacks.messages.length, 5); assert.isTrue(result); }); }); diff --git a/developer/src/kmcmplib/include/kmcmplibapi.h b/developer/src/kmcmplib/include/kmcmplibapi.h index be0f477ab9..97d46c3c36 100644 --- a/developer/src/kmcmplib/include/kmcmplibapi.h +++ b/developer/src/kmcmplib/include/kmcmplibapi.h @@ -76,14 +76,10 @@ static const int KMCMP_ERROR_HAS_STRINGS = -2; * Error: Invalid, uses properties \p{Mn} or [:Mn:] */ static const int KMCMP_ERROR_UNSUPPORTED_PROPERTY = -3; -/** - * Error: Invalid, other unsupported feature - */ -static const int KMCMP_ERROR_UNSUPPORTED = -4; /** * Fatal: output buffer too small */ -static const int KMCMP_FATAL_OUT_OF_RANGE = -5; +static const int KMCMP_FATAL_OUT_OF_RANGE = -4; /** * Function pointer to kmcmp_ParseUnicodeSet diff --git a/developer/src/kmcmplib/src/CompilerInterfaces.cpp b/developer/src/kmcmplib/src/CompilerInterfaces.cpp index 1eb9b6eaab..89c4655d16 100644 --- a/developer/src/kmcmplib/src/CompilerInterfaces.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfaces.cpp @@ -65,6 +65,15 @@ EXTERN bool kmcmp_Wasm_CompileKeyboardFile(char* pszInfile, msgProc ); } + +EXTERN int kmcmp_Wasm_ParseUnicodeSet(char* pat, + uint32_t* buf, int length +) { + return kmcmp_ParseUnicodeSet( + pat, buf, length + ); +} + #endif EXTERN bool kmcmp_CompileKeyboardFile(char* pszInfile, @@ -365,4 +374,4 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) kmcmp::CheckForDeprecatedFeatures(fk); return TRUE; -} \ No newline at end of file +} diff --git a/developer/src/tike/compile/keyman32_int.pas b/developer/src/tike/compile/keyman32_int.pas deleted file mode 100644 index 37ddbe9347..0000000000 --- a/developer/src/tike/compile/keyman32_int.pas +++ /dev/null @@ -1,108 +0,0 @@ -unit keyman32_int; - -interface - -uses Windows, SysUtils, Forms; - -function Keyman_Initialise(Handle: HWND; FSingleApp: Boolean): Boolean; -function Keyman_Exit: Boolean; -function Keyman_ForceKeyboard(const s: string): Boolean; -function Keyman_StopForcingKeyboard: Boolean; - -implementation - -uses TikeUtils; - -type TKeyman_ForceKeyboard = function (s: PChar): Boolean; stdcall; -type TKeyman_StopForcingKeyboard = function: Boolean; stdcall; -type TKeyman_Initialise = function(h: THandle; FSingleApp: LongBool): Boolean; stdcall; -type TKeyman_Exit = function: Boolean; stdcall; - -var - FInitKeyman: Boolean = False; - FKeyman32Path: string = ''; - -function Keyman_Initialise(Handle: HWND; FSingleApp: Boolean): Boolean; -var - hkeyman: THandle; - FLoad: Boolean; - ki: TKeyman_Initialise; -begin - Result := False; - FLoad := False; - hkeyman := GetModuleHandle('keyman32.dll'); - if hkeyman = 0 then - begin - hkeyman := LoadLibrary(PChar(GetKeymanInstallPath+'keyman32.dll')); - if hkeyman = 0 then Exit; - FLoad := True; - end; - ki := TKeyman_Initialise(GetProcAddress(hkeyman, 'Keyman_Initialise')); - if not Assigned(@ki) then Exit; - if not ki(Handle, FSingleApp) then - begin - if FLoad then FreeLibrary(hkeyman); - Exit; - end; - - FInitKeyman := True; - Result := True; -end; - -function Keyman_Exit: Boolean; -var - hkeyman: THandle; - ke: TKeyman_Exit; -begin - if not FInitKeyman then - begin - Result := True; - Exit; - end; - Result := False; - hkeyman := GetModuleHandle('keyman32.dll'); - if hkeyman = 0 then Exit; - ke := TKeyman_Exit(GetProcAddress(hkeyman, 'Keyman_Exit')); - if not Assigned(@ke) then Exit; - if not ke then Exit; - if FInitKeyman then FreeLibrary(hkeyman); - FInitKeyman := False; - Result := True; -end; - -function Keyman_ForceKeyboard(const s: string): Boolean; -var - hkeyman: THandle; - fk: TKeyman_ForceKeyboard; -begin - Result := False; - hkeyman := GetModuleHandle('keyman32.dll'); - if hkeyman = 0 then - begin - if not Keyman_Initialise(Application.MainForm.Handle, True) then Exit; - hkeyman := GetModuleHandle('keyman32.dll'); - if hkeyman = 0 then Exit; - end; - fk := TKeyman_ForceKeyboard(GetProcAddress(hkeyman, 'Keyman_ForceKeyboard')); - if(Assigned(@fk)) then - Result := fk(PChar(s)); -end; - -function Keyman_StopForcingKeyboard: Boolean; -var - hkeyman: THandle; - sfk: TKeyman_StopForcingKeyboard; -begin - Result := False; - hkeyman := GetModuleHandle('keyman32.dll'); - if hkeyman = 0 then Exit; - sfk := TKeyman_StopForcingKeyboard(GetProcAddress(hkeyman, 'Keyman_StopForcingKeyboard')); - if(Assigned(@sfk)) then - Result := sfk; - Keyman_Exit; -end; - -initialization -finalization - Keyman_Exit; -end. diff --git a/ios/Cartfile b/ios/Cartfile index 5ad8178ed4..b265ef77af 100644 --- a/ios/Cartfile +++ b/ios/Cartfile @@ -1,5 +1,5 @@ github "marmelroy/Zip" -github "DaveWoodCom/XCGLogger" ~> 6.1.0 +github "keymanapp/dependency-XCGLogger" "master" github "devicekit/DeviceKit" ~> 5.0 github "ashleymills/Reachability.swift" -github "getsentry/sentry-cocoa" ~> 6.2.1 +github "getsentry/sentry-cocoa" ~> 8.7.0 diff --git a/ios/Cartfile.resolved b/ios/Cartfile.resolved index fe74a57322..ff30a8871d 100644 --- a/ios/Cartfile.resolved +++ b/ios/Cartfile.resolved @@ -1,5 +1,5 @@ -github "DaveWoodCom/XCGLogger" "6.1.0" github "ashleymills/Reachability.swift" "v5.1.0" github "devicekit/DeviceKit" "5.0.0" -github "getsentry/sentry-cocoa" "6.2.1" +github "getsentry/sentry-cocoa" "8.7.0" +github "keymanapp/dependency-XCGLogger" "57a7b975dbb6fe4fe90cef3d1bc52b8adbd89113" github "marmelroy/Zip" "2.1.2" diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Errors/SentryManager.swift b/ios/engine/KMEI/KeymanEngine/Classes/Errors/SentryManager.swift index 127fcd12b5..94f9885076 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Errors/SentryManager.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Errors/SentryManager.swift @@ -167,7 +167,7 @@ public class SentryManager { public static func breadcrumbAndLog(crumb: Sentry.Breadcrumb, logLevel: XCGLogger.Level? = nil) { // Guarded in case a library consumer decides against initializing Sentry. if _started { - SentrySDK.addBreadcrumb(crumb: crumb) + SentrySDK.addBreadcrumb(crumb) } let level = logLevel ?? mapLoggingLevel(crumb.level) @@ -193,7 +193,7 @@ public class SentryManager { } public static func forceError() { - SentrySDK.addBreadcrumb(crumb: Sentry.Breadcrumb(level: .info, category: "Deliberate testing error")) + SentrySDK.addBreadcrumb(Sentry.Breadcrumb(level: .info, category: "Deliberate testing error")) SentrySDK.crash() } } diff --git a/linux/debian/ibus-keyman.postinst b/linux/debian/ibus-keyman.postinst index 4143effb61..6cff5c525c 100644 --- a/linux/debian/ibus-keyman.postinst +++ b/linux/debian/ibus-keyman.postinst @@ -1,7 +1,7 @@ -#!/bin/sh +#!/bin/bash -# Don't call `set -e`. Even if some commands should fail, it's still -# worth running the rest of the commands. +# Exit on errors - Debian policy 10.4 +set -e case "$1" in @@ -12,7 +12,7 @@ case "$1" in if which sudo > /dev/null && which ps > /dev/null; then # check for gnome-shell as it works differently - gspid=$(ps -C gnome-shell -o pid=|head -n 1) + ! gspid=$(ps -C gnome-shell -o pid=|head -n 1) if [ "$gspid" != "" ]; then # gnome-shell has multiple ibus-daemon processes and needs exit instead of restart is_gnome_shell=1 @@ -21,7 +21,7 @@ case "$1" in fi # Restart IBus if it is running - ibuspid=$(ps -C ibus-daemon -o pid=|head -n 1) + ! ibuspid=$(ps -C ibus-daemon -o pid=|head -n 1) if [ "$ibuspid" != "" ]; then if [ "$is_gnome_shell" = "1" ]; then @@ -41,7 +41,7 @@ case "$1" in # Verify that it's running now if [ -n "$SUDO_USER" ] && id "$SUDO_USER" > /dev/null 2>/dev/null; then - ibusdaemon=$(ps --user "$SUDO_USER" -o s= -o cmd | grep --regexp="^[^ZT] \(/usr/bin/\)\?ibus-daemon .*--xim.*") + ! ibusdaemon=$(ps --user "$SUDO_USER" -o s= -o cmd | grep --regexp="^[^ZT] \(/usr/bin/\)\?ibus-daemon .*--xim.*") if [ "$ibusdaemon" = "" ]; then # otherwise try to start it for the user installing the package if [ "$is_gnome_shell" = "1" ]; then diff --git a/linux/keyman-config/Makefile b/linux/keyman-config/Makefile index b18b1f133d..41eaab30ef 100644 --- a/linux/keyman-config/Makefile +++ b/linux/keyman-config/Makefile @@ -6,7 +6,14 @@ default: clean version man langtags langtags: cd buildtools && python3 ./build-langtags.py -install: # run as sudo +install: + if [ -n "${SUDO_USER}" ]; then \ + make install-sudo; \ + else \ + make install-temp; \ + fi + +install-sudo: # run as sudo pip3 install qrcode sentry-sdk # eventually change this to: pip3 install . python3 setup.py install diff --git a/oem/firstvoices/ios/Cartfile b/oem/firstvoices/ios/Cartfile index ec3127efc7..10efbc3d5a 100644 --- a/oem/firstvoices/ios/Cartfile +++ b/oem/firstvoices/ios/Cartfile @@ -1,4 +1,4 @@ -github "DaveWoodCom/XCGLogger" ~> 6.1.0 +github "keymanapp/dependency-XCGLogger" "master" github "devicekit/DeviceKit" ~> 5.0 github "ashleymills/Reachability.swift" -github "getsentry/sentry-cocoa" ~> 6.2.1 +github "getsentry/sentry-cocoa" ~> 8.7.0 diff --git a/oem/firstvoices/ios/Cartfile.resolved b/oem/firstvoices/ios/Cartfile.resolved index 16cb6213b6..5ac3a55318 100644 --- a/oem/firstvoices/ios/Cartfile.resolved +++ b/oem/firstvoices/ios/Cartfile.resolved @@ -1,4 +1,4 @@ -github "DaveWoodCom/XCGLogger" "6.1.0" github "ashleymills/Reachability.swift" "v5.1.0" github "devicekit/DeviceKit" "5.0.0" -github "getsentry/sentry-cocoa" "6.2.1" +github "getsentry/sentry-cocoa" "8.7.0" +github "keymanapp/dependency-XCGLogger" "57a7b975dbb6fe4fe90cef3d1bc52b8adbd89113" diff --git a/resources/builder.inc.sh b/resources/builder.inc.sh index cc3de2d2eb..6a47cbd529 100755 --- a/resources/builder.inc.sh +++ b/resources/builder.inc.sh @@ -359,7 +359,7 @@ _builder_failure_trap() { # finishes. # _builder_cleanup_deps() { - if ! builder_is_dep_build && [[ ! -z ${_builder_deps_built+x} ]]; then + if ! builder_is_dep_build && ! builder_is_child_build && [[ ! -z ${_builder_deps_built+x} ]]; then if $_builder_debug_internal; then builder_echo_debug "Dependencies that were built:" cat "$_builder_deps_built" @@ -558,7 +558,6 @@ builder_has_action() { function builder_run_action() { local action=$1 shift - echo "builder_run_action $action $@" if builder_start_action $action; then ($@) builder_finish_action success $action @@ -1758,6 +1757,7 @@ builder_has_dependencies() { builder_has_module_been_built() { local module="$1" + if [[ -z ${_builder_deps_built+x} ]]; then # not in a builder context, so we assume a build is needed return 1 diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index 190cf53e79..e29e504b2a 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -45,12 +45,6 @@ BOOL GetKeyboardFileName(LPSTR kbname, LPSTR buf, int nbuf) { PKEYMAN64THREADDATA _td = ThreadGlobals(); if(!_td) return FALSE; - if(_td->ForceFileName[0]) - { - strncpy_s(buf, nbuf, _td->ForceFileName, nbuf - 1); - buf[nbuf-1] = 0; - return TRUE; - } int n = 0; RegistryReadOnly *reg = Reg_GetKeymanInstalledKeyboard(kbname); @@ -75,9 +69,9 @@ BOOL GetKeyboardFileName(LPSTR kbname, LPSTR buf, int nbuf) return n; } -BOOL LoadlpKeyboardCore(int i) +BOOL LoadlpKeyboard(int i) { - SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboardCore: Enter ---"); + SendDebugMessageFormat(0, sdmLoad, 0, "%s: Enter ---", __FUNCTION__); PKEYMAN64THREADDATA _td = ThreadGlobals(); if (!_td) return FALSE; @@ -85,7 +79,7 @@ BOOL LoadlpKeyboardCore(int i) if (_td->lpActiveKeyboard == &_td->lpKeyboards[i]) _td->lpActiveKeyboard = NULL; // I822 TSF not working if (_td->lpKeyboards[i].lpCoreKeyboardState) { - SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboardCore: a keyboard km_kbp_state exits without matching keyboard - disposing of state"); + SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboard: a keyboard km_kbp_state exits without matching keyboard - disposing of state"); km_kbp_state_dispose(_td->lpKeyboards[i].lpCoreKeyboardState); _td->lpKeyboards[i].lpCoreKeyboardState = NULL; } @@ -95,7 +89,7 @@ BOOL LoadlpKeyboardCore(int i) PWCHAR keyboardPath = strtowstr(buf); km_kbp_status err_status = km_kbp_keyboard_load(keyboardPath, &_td->lpKeyboards[i].lpCoreKeyboard); if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboardCore: km_kbp_keyboard_load failed for %ls with error status [%d]", keyboardPath, err_status); + SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboard: km_kbp_keyboard_load failed for %ls with error status [%d]", keyboardPath, err_status); delete keyboardPath; return FALSE; } @@ -104,7 +98,7 @@ BOOL LoadlpKeyboardCore(int i) km_kbp_option_item *core_environment = nullptr; if(!SetupCoreEnvironment(&core_environment)) { - SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboardCore: Unable to set environment options for keyboard %ls", keyboardPath); + SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboard: Unable to set environment options for keyboard %ls", keyboardPath); return FALSE; } @@ -114,7 +108,7 @@ BOOL LoadlpKeyboardCore(int i) if (err_status != KM_KBP_STATUS_OK) { SendDebugMessageFormat( - 0, sdmLoad, 0, "LoadlpKeyboardCore: km_kbp_state_create failed with error status [%d]", err_status); + 0, sdmLoad, 0, "LoadlpKeyboard: km_kbp_state_create failed with error status [%d]", err_status); // Dispose of the keyboard to leave us in a consistent state ReleaseKeyboardMemoryCore(&_td->lpKeyboards[i].lpCoreKeyboard); return FALSE; @@ -122,38 +116,15 @@ BOOL LoadlpKeyboardCore(int i) // Register callback? err_status = km_kbp_keyboard_get_imx_list(_td->lpKeyboards[i].lpCoreKeyboard, &_td->lpKeyboards[i].lpIMXList); if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboardCore: km_kbp_keyboard_get_imx_list failed with error status [%d]", err_status); + SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboard: km_kbp_keyboard_get_imx_list failed with error status [%d]", err_status); // Dispose of the keyboard to leave us in a consistent state ReleaseKeyboardMemoryCore(&_td->lpKeyboards[i].lpCoreKeyboard); return FALSE; } - LoadDLLsCore(&_td->lpKeyboards[i]); - - LoadKeyboardOptionsREGCore(&_td->lpKeyboards[i], _td->lpKeyboards[i].lpCoreKeyboardState); - - return TRUE; -} - -BOOL LoadlpKeyboard(int i) -{ - if (Globals::get_CoreIntegration()) - { - return LoadlpKeyboardCore(i); - } - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - if(_td->lpKeyboards[i].Keyboard) return TRUE; - if(_td->lpActiveKeyboard == &_td->lpKeyboards[i]) _td->lpActiveKeyboard = NULL; // I822 TSF not working - - char buf[256]; - if(!GetKeyboardFileName(_td->lpKeyboards[i].Name, buf, 255)) return FALSE; - - if(!LoadKeyboard(buf, &_td->lpKeyboards[i].Keyboard)) return FALSE; // I5136 - LoadDLLs(&_td->lpKeyboards[i]); - LoadKeyboardOptions(&_td->lpKeyboards[i]); + LoadKeyboardOptionsRegistrytoCore(&_td->lpKeyboards[i], _td->lpKeyboards[i].lpCoreKeyboardState); return TRUE; } diff --git a/windows/src/engine/keyman32/addins.cpp b/windows/src/engine/keyman32/addins.cpp deleted file mode 100644 index 6c7f5d0f28..0000000000 --- a/windows/src/engine/keyman32/addins.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* - Name: addins - Copyright: Copyright (C) SIL International. - Documentation: - Description: - Create Date: 14 Jun 2008 - - Modified Date: 14 May 2010 - Authors: mcdurdin - Related Files: - Dependencies: - - Bugs: - Todo: - Notes: - History: 14 Jun 2008 - mcdurdin - I1488 - Fix registry handle leak - 11 Mar 2009 - mcdurdin - I1894 - Fix threading bugs introduced in I1888 - 11 Dec 2009 - mcdurdin - I934 - x64 - Initial version - 12 Mar 2010 - mcdurdin - I934 - x64 - Complete - 12 Mar 2010 - mcdurdin - I2229 - Remove hints and warnings - 04 May 2010 - mcdurdin - I2351 - Robustness - verify _td return value - 14 May 2010 - mcdurdin - I2374 - Fix crash in some situations -*/ - -#include "pch.h" - -void Addin_Release() -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return; - - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addin_Release: ENTER [%d]", nAddins); - if(_td->Addins) - { - for(int i = 0; i < _td->nAddins; i++) - if(_td->Addins[i].hAddin) - { - if(_td->Addins[i].Uninitialise) (*_td->Addins[i].Uninitialise)(); - FreeLibrary(_td->Addins[i].hAddin); - } - delete[] _td->Addins; - } - _td->Addins = NULL; - _td->nAddins = 0; - _td->CurrentAddin = -1; - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addin_Release: EXIT"); -} - -void ReadAddins(HKEY hkey) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return; - - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: ReadAddins: ENTER"); - RegistryReadOnly *reg = new RegistryReadOnly(hkey); - if(reg->OpenKeyReadOnly(hkey == HKEY_CURRENT_USER ? REGSZ_KeymanAddinsCU : REGSZ_KeymanAddinsLM)) - { - int n = _td->nAddins; - char buf[128]; - while(reg->GetValueNames(buf, 128, n)) - { - Addin *a = new Addin[n+1]; - if(_td->Addins) - { - memcpy(a, _td->Addins, n * sizeof(Addin)); - delete[] _td->Addins; - } - _td->Addins = a; - _td->Addins[n].hAddin = 0; - _td->Addins[n].FocusChanged = NULL; - _td->Addins[n].Initialise = NULL; - _td->Addins[n].OutputBackspace = NULL; - _td->Addins[n].OutputChar = NULL; - _td->Addins[n].Uninitialise = NULL; - _td->Addins[n].ShouldProcess = NULL; - strcpy(_td->Addins[n].ClassName, buf); - reg->ReadString(buf, _td->Addins[n].AddinName, 260); - _td->Addins[n].Application[0] = 0; - n++; - } - _td->nAddins = n; - } - delete reg; - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: ReadAddins: EXIT"); -} - -void Addin_Refresh() -{ - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addin_Refresh: ENTER"); - Addin_Release(); - ReadAddins(HKEY_CURRENT_USER); - ReadAddins(HKEY_LOCAL_MACHINE); - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addin_Refresh: EXIT"); -} - -BOOL LoadAddin() -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - if(_td->CurrentAddin == -1) return FALSE; - - Addin *a = &_td->Addins[_td->CurrentAddin]; - if(!a->hAddin) - { - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: LoadAddin: ENTER"); - a->hAddin = LoadLibrary(a->AddinName); - if(!a->hAddin) - { - a->hAddin = 0; - a->ClassName[0] = 0; // prevent add-in attempting to load again - _td->CurrenthWnd = 0; - _td->CurrentAddin = -1; - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: LoadAddin: EXIT - FALSE - LoadLibrary"); - return FALSE; - } - a->OutputBackspace = (PKeymanOutputBackspace) GetProcAddress(a->hAddin, "KeymanOutputBackspace"); - a->OutputChar = (PKeymanOutputChar) GetProcAddress(a->hAddin, "KeymanOutputChar"); - a->FocusChanged = (PKeymanFocusChanged) GetProcAddress(a->hAddin, "KeymanFocusChanged"); - a->ShouldProcess = (PKeymanShouldProcess) GetProcAddress(a->hAddin, "KeymanShouldProcess"); - a->Initialise = (PKeymanInit) GetProcAddress(a->hAddin, "KeymanInitialise"); - a->Uninitialise = (PKeymanInit) GetProcAddress(a->hAddin, "KeymanUninitialise"); - - if(a->Initialise && !(*a->Initialise)()) - { - FreeLibrary(a->hAddin); - a->hAddin = 0; - a->ClassName[0] = 0; - _td->CurrenthWnd = 0; - _td->CurrentAddin = -1; - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: LoadAddin: EXIT - FALSE - Initialise"); - return FALSE; - } - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: LoadAddin: EXIT - TRUE - Loaded"); - } - return TRUE; -} - -BOOL Addin_ShouldProcessUnichar(HWND hwnd) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ShouldProcessUnichar: ENTER"); - _td->CurrenthWnd = hwnd; - GetClassName(hwnd, _td->CurrentClassName, 128); - if(_td->CurrentAddin >= 0 && !_strcmpi(_td->CurrentClassName, _td->Addins[_td->CurrentAddin].ClassName)) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ShouldProcessUnichar: EXIT - TRUE - CurrentAddin okay"); - return TRUE; - } - - for(int i = 0; i < _td->nAddins; i++) - if(!_strcmpi(_td->CurrentClassName, _td->Addins[i].ClassName)) - { - _td->CurrentAddin = i; - if(!LoadAddin()) - { - _td->CurrentAddin = -1; - _td->Addins[i].ClassName[0] = 0; // prevent add-in attempting to load again - } - else if(_td->Addins[i].ShouldProcess && !(*_td->Addins[i].ShouldProcess)(hwnd)) - _td->CurrentAddin = -1; - else - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ShouldProcessUnichar: EXIT - TRUE - FoundAddin"); - return TRUE; - } - } - _td->CurrentAddin = -1; - _td->CurrenthWnd = 0; - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ShouldProcessUnichar: EXIT - FALSE"); - return FALSE; -} - -BOOL Addin_ProcessUnichar(HWND hwnd, DWORD chr) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: ENTER"); - if(_td->CurrenthWnd != hwnd) - if(!Addin_ShouldProcessUnichar(hwnd)) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: EXIT - FALSE - Addin_ShouldProcessUnichar"); - return FALSE; - } - - if(!LoadAddin()) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: EXIT - FALSE - !LoadAddin)"); - return FALSE; - } - if(!_td->Addins[_td->CurrentAddin].OutputChar) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: EXIT - FALSE !OutputChar"); - return FALSE; - } - - BOOL b = (*_td->Addins[_td->CurrentAddin].OutputChar)(hwnd, chr); - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: EXIT (b) == %d", b); - return b; -} - -BOOL Addin_ProcessBackspace(HWND hwnd) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: ENTER"); - if(_td->CurrenthWnd != hwnd) - if(!Addin_ShouldProcessUnichar(hwnd)) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: EXIT - !ShouldProcess"); - return FALSE; - } - - if(!LoadAddin()) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: EXIT - !LoadAddin"); - return FALSE; - } - if(!_td->Addins[_td->CurrentAddin].OutputBackspace) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: EXIT - !OutputBackspace"); - return FALSE; - } - - BOOL b = (*_td->Addins[_td->CurrentAddin].OutputBackspace)(hwnd); - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: EXIT - (b) = %d", b); - return b; -} - -void Addin_FocusChanged(HWND hwnd) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return; - - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: ENTER"); - - if(_td->CurrenthWnd != hwnd) - if(!Addin_ShouldProcessUnichar(hwnd)) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: EXIT - !ShouldProcess"); - return; - } - - if(!LoadAddin()) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: EXIT - !LoadAddin"); - return; - } - - // Addin variables must be valid now - - if(!_td->Addins[_td->CurrentAddin].FocusChanged) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: EXIT - !FocusChanged"); - return; - } - - (*_td->Addins[_td->CurrentAddin].FocusChanged)(); - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: EXIT"); -} diff --git a/windows/src/engine/keyman32/addins.h b/windows/src/engine/keyman32/addins.h deleted file mode 100644 index 71aa006e59..0000000000 --- a/windows/src/engine/keyman32/addins.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - Name: addins - Copyright: Copyright (C) SIL International. - Documentation: - Description: - Create Date: 11 Dec 2009 - - Modified Date: 11 Dec 2009 - Authors: mcdurdin - Related Files: - Dependencies: - - Bugs: - Todo: - Notes: - History: 11 Dec 2009 - mcdurdin - I934 - x64 - Initial version -*/ -void Addin_Release(); -void Addin_Refresh(); -BOOL Addin_ShouldProcessUnichar(HWND hwnd); -BOOL Addin_ProcessUnichar(HWND hwnd, DWORD chr); -BOOL Addin_ProcessBackspace(HWND hwnd); -void Addin_FocusChanged(HWND hwnd); diff --git a/windows/src/engine/keyman32/appint/aiTIP.cpp b/windows/src/engine/keyman32/appint/aiTIP.cpp index 23240b2a06..34f3afc867 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.cpp +++ b/windows/src/engine/keyman32/appint/aiTIP.cpp @@ -126,7 +126,6 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM BOOL isUp = keyFlags & KF_UP ? TRUE : FALSE; BOOL extended = keyFlags & KF_EXTENDED ? TRUE : FALSE; BYTE scan = keyFlags & 0xFF; - BOOL isUsingCoreProcessor = Globals::get_CoreIntegration(); SendDebugMessageFormat(0, sdmAIDefault, 0, "TIPProcessKey: Enter VirtualKey=%s lParam=%x IsUp=%d Extended=%d Updateable=%d Preserved=%d", Debug_VirtualKey((WORD) wParam), lParam, isUp, extended, Updateable, Preserved); @@ -163,72 +162,31 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM // core processor. The core processor has the keyboard Caps Lock stores and will // queue an action 'KM_KBP_IT_CAPSLOCK'. In processing the action the Windows engine will synthesise keystrokes // to ensure caps lock is in the correct state. - if (isUsingCoreProcessor) { - if (!Preserved) { - switch (wParam) { - case VK_MENU: - case VK_CONTROL: - ProcessModifierChange((UINT)wParam, isUp, extended); - return FALSE; - case VK_NUMLOCK: + if (!Preserved) { + switch (wParam) { + case VK_MENU: + case VK_CONTROL: + ProcessModifierChange((UINT)wParam, isUp, extended); + return FALSE; + case VK_NUMLOCK: + if (!isUp) + ProcessToggleChange((UINT)wParam); // I4793 + return FALSE; + case VK_CAPITAL: if (!isUp) - ProcessToggleChange((UINT)wParam); // I4793 - return FALSE; - case VK_CAPITAL: - if (!isUp) - ProcessToggleChange((UINT)wParam); // I4793 - break; - case VK_SHIFT: - ProcessModifierChange((UINT)wParam, isUp, extended); + ProcessToggleChange((UINT)wParam); // I4793 break; - } - } else { - // Mask out Ctrl, Shift and Alt and include new modifiers // I4548 - DWORD NewShiftState = TSFShiftToShift(lParam); // I3588 - SendDebugMessageFormat( - 0, sdmGlobal, 0, "TIPProcessKey: TSFShiftToShift start with %x, include %x", LocalShiftState, NewShiftState); - *Globals::ShiftState() = (LocalShiftState & K_NOTMODIFIERFLAG) | NewShiftState; // I3588 + case VK_SHIFT: + ProcessModifierChange((UINT)wParam, isUp, extended); + break; } - } else { // using windows processor TODO: #5442 Remove this else block - if (!Preserved) { - switch (wParam) { - case VK_CAPITAL: - if (!isUp) - ProcessToggleChange((UINT)wParam); // I4793 - if (!Updateable) { - // We only want to process the Caps Lock key event once -- - // in the first pass (!Updateable). - KeyCapsLockPress(isUp); // I4548 - } - return FALSE; - case VK_SHIFT: - if (!Updateable) { - // We only want to process the Shift key event once -- - // in the first pass (!Updateable). - KeyShiftPress(isUp); // I4548 - } - // Fall through - case VK_MENU: - case VK_CONTROL: - ProcessModifierChange((UINT)wParam, isUp, extended); - return FALSE; - case VK_NUMLOCK: - if (!isUp) - ProcessToggleChange((UINT)wParam); // I4793 - return FALSE; - } - // This would only get here if none of the above cases matched why not use default in the switch? - if (isUp) { - return FALSE; // return value ignored in this case; we only needed it for testing anyway - } - } else { - // Mask out Ctrl, Shift and Alt and include new modifiers // I4548 - DWORD NewShiftState = TSFShiftToShift(lParam); // I3588 - SendDebugMessageFormat( - 0, sdmGlobal, 0, "TIPProcessKey: TSFShiftToShift start with %x, include %x", LocalShiftState, NewShiftState); - *Globals::ShiftState() = (LocalShiftState & K_NOTMODIFIERFLAG) | NewShiftState; // I3588 - } - } // TODO: #5442 Remove this else block ^^ + } else { + // Mask out Ctrl, Shift and Alt and include new modifiers // I4548 + DWORD NewShiftState = TSFShiftToShift(lParam); // I3588 + SendDebugMessageFormat( + 0, sdmGlobal, 0, "TIPProcessKey: TSFShiftToShift start with %x, include %x", LocalShiftState, NewShiftState); + *Globals::ShiftState() = (LocalShiftState & K_NOTMODIFIERFLAG) | NewShiftState; // I3588 + } _td->TIPFUpdateable = Updateable; _td->TIPFPreserved = Preserved; // I4290 @@ -239,16 +197,7 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM _td->state.vkey = (WORD) wParam; _td->state.isDown = !isUp; - if (isUsingCoreProcessor) { - _td->state.lpCoreKb = _td->lpActiveKeyboard->lpCoreKeyboard; - - } else { - _td->state.lpkb = _td->lpActiveKeyboard->Keyboard; - _td->state.startgroup = &_td->state.lpkb->dpGroupArray[_td->state.lpkb->StartGroup[BEGIN_UNICODE]]; - _td->state.NoMatches = TRUE; - _td->state.LoopTimes = 0; - _td->state.StopOutput = FALSE; - } + _td->state.lpCoreKb = _td->lpActiveKeyboard->lpCoreKeyboard; _td->state.windowunicode = TRUE; @@ -257,30 +206,8 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM _td->TIPProcessOutput = outfunc; _td->TIPGetContext = ctfunc; - AppContextWithStores *savedContext = NULL; // I4370 // I4978 - - if (!Updateable) { - // The core processor km_kbp_process_event is only called once per key stroke - // therefore there is no need to preserve context and keyboard actions - if (!isUsingCoreProcessor) { - savedContext = new AppContextWithStores(_td->lpActiveKeyboard->Keyboard->cxStoreArray); // I4370 // I4978 - _td->app->SaveContext(savedContext); - } - } - BOOL res = ProcessHook(); - if (!Updateable) { - if (!isUsingCoreProcessor) { - if (res) { // I4585 // I4370 - // Reset the context if match found - _td->app->RestoreContext(savedContext); - delete savedContext; - savedContext = NULL; - } - } - } - _td->TIPProcessOutput = NULL; _td->TIPGetContext = NULL; @@ -439,65 +366,6 @@ void AITIP::ReadContext() { } } -AppContextWithStores::AppContextWithStores(int nKeyboardOptions) : AppContext() { // I4978 - this->nKeyboardOptions = nKeyboardOptions; - KeyboardOptions = new INTKEYBOARDOPTIONS[nKeyboardOptions]; - memset(KeyboardOptions, 0, sizeof(INTKEYBOARDOPTIONS) * nKeyboardOptions); -} - -AppContextWithStores::~AppContextWithStores() { // I4978 - for(DWORD i = 0; i < nKeyboardOptions; i++) { - if(KeyboardOptions[i].Value) delete KeyboardOptions[i].Value; - } - delete KeyboardOptions; -} - -void AITIP::SaveContext(AppContextWithStores *savedContext) { // I4370 // I4978 - savedContext->CopyFrom(context); - - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td || !_td->lpActiveKeyboard || !_td->lpActiveKeyboard->Keyboard) return; - - assert(savedContext->nKeyboardOptions == _td->lpActiveKeyboard->Keyboard->cxStoreArray); - - for(DWORD i = 0; i < savedContext->nKeyboardOptions; i++) { // I4978 - if(_td->lpActiveKeyboard->KeyboardOptions[i].Value != NULL) { - savedContext->KeyboardOptions[i].Value = new WCHAR[wcslen(_td->lpActiveKeyboard->KeyboardOptions[i].Value)+1]; - wcscpy_s(savedContext->KeyboardOptions[i].Value, wcslen(_td->lpActiveKeyboard->KeyboardOptions[i].Value)+1, _td->lpActiveKeyboard->KeyboardOptions[i].Value); - } - } -} - -void AITIP::RestoreContext(AppContextWithStores *savedContext) { // I4370 // I4978 - context->CopyFrom(savedContext); - - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td || !_td->lpActiveKeyboard || !_td->lpActiveKeyboard->Keyboard) return; - LPINTKEYBOARDINFO kp = _td->lpActiveKeyboard; - - assert(savedContext->nKeyboardOptions == kp->Keyboard->cxStoreArray); - - for(DWORD i = 0; i < savedContext->nKeyboardOptions; i++) { // I4978 - if(kp->KeyboardOptions[i].Value == NULL && savedContext->KeyboardOptions[i].Value != NULL) { - // Restore the previously saved value as it was reset - kp->KeyboardOptions[i].OriginalStore = kp->Keyboard->dpStoreArray[i].dpString; - kp->Keyboard->dpStoreArray[i].dpString = kp->KeyboardOptions[i].Value = savedContext->KeyboardOptions[i].Value; - savedContext->KeyboardOptions[i].Value = NULL; - } else if(kp->KeyboardOptions[i].Value != NULL && savedContext->KeyboardOptions[i].Value == NULL) { - // Clear the newly saved value back to the default - delete kp->KeyboardOptions[i].Value; - kp->KeyboardOptions[i].Value = NULL; - kp->Keyboard->dpStoreArray[i].dpString = kp->KeyboardOptions[i].OriginalStore; - } else if(kp->KeyboardOptions[i].Value != NULL && savedContext->KeyboardOptions[i].Value != NULL && - wcscmp(kp->KeyboardOptions[i].Value, savedContext->KeyboardOptions[i].Value) != 0) { - // Restore the previously saved value as it was changed - delete kp->KeyboardOptions[i].Value; - kp->Keyboard->dpStoreArray[i].dpString = kp->KeyboardOptions[i].Value = savedContext->KeyboardOptions[i].Value; - savedContext->KeyboardOptions[i].Value = NULL; - } - } -} - void AITIP::CopyContext(AppContext *savedContext) { savedContext->CopyFrom(context); } @@ -722,49 +590,3 @@ void FillStoreOffsets(AIDEBUGINFO *di) } di->StoreOffsets[n] = 0xFFFF; } - -BOOL AITIP::QueueDebugInformation(int ItemType, LPGROUP Group, LPKEY Rule, PWSTR fcontext, PWSTR foutput, DWORD_PTR dwExtraFlags) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return TRUE; - if(!_td->ForceFileName[0]) return TRUE; - - SendDebugMessageFormat(0, sdmAIDefault, 0, "AIDebugger::QueueDebugInformation ItemType=%d", ItemType); - AIDEBUGINFO di; - di.cbSize = sizeof(AIDEBUGINFO); - di.ItemType = ItemType; // int - di.Context = fcontext; // PWSTR - di.Rule = Rule; // LPKEY - di.Group = Group; // LPGROUP - di.Output = foutput; // PWSTR - di.Flags = dwExtraFlags; // DWORD - - if(di.Rule) FillStoreOffsets(&di); - - // data required - // keystroke - // context for rule - // if rule, then output of rule - // match positions for all stores in rule - - if(DebugControlled()) - SendMessage(GetDebugControlWindow(), WM_KEYMANDEBUG_RULEMATCH, ItemType, (LPARAM) &di); - - return TRUE; -} - -typedef BOOL(WINAPI *PREFRESHPRESERVEDKEYSFUNC)(BOOL Activating); - -void RefreshPreservedKeys(BOOL Activating) { -#ifdef _WIN64 - HMODULE hModule = GetModuleHandle("kmtip64"); -#else - HMODULE hModule = GetModuleHandle("kmtip"); -#endif - if (hModule != NULL) { - PREFRESHPRESERVEDKEYSFUNC pRefreshPreservedKeys = (PREFRESHPRESERVEDKEYSFUNC)GetProcAddress(hModule, "RefreshPreservedKeys"); - if (pRefreshPreservedKeys) { - pRefreshPreservedKeys(Activating); - } - } -} diff --git a/windows/src/engine/keyman32/appint/aiTIP.h b/windows/src/engine/keyman32/appint/aiTIP.h index 7ff5aff4ef..3c6fd9b698 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.h +++ b/windows/src/engine/keyman32/appint/aiTIP.h @@ -71,11 +71,6 @@ public: BOOL DebugControlled(); - // TODO: 5442 This would be better to called SaveContextWithStores or SaveContextWithKbdOptions - // Will be removed with 5442 when removing window core - void SaveContext(AppContextWithStores *savedContext); // I4370 // I4978 - void RestoreContext(AppContextWithStores *savedContext); // I4370 // I4978 - /** * Copy the member context * @@ -106,7 +101,6 @@ public: /* Queue and sending functions */ virtual BOOL SendActions(); // I4196 - virtual BOOL QueueDebugInformation(int ItemType, LPGROUP Group, LPKEY Rule, PWSTR fcontext, PWSTR foutput, DWORD_PTR dwExtraFlags); /* TIP interactions */ diff --git a/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp b/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp index 19da87a543..a6b540fd47 100644 --- a/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp +++ b/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp @@ -1,18 +1,18 @@ /* Name: AIWin2000Unicode Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 22 Jan 2007 Modified Date: 9 Aug 2015 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 22 Jan 2007 - mcdurdin - Fix for K_NPENTER 13 Jul 2007 - mcdurdin - I934 - Prep fox x64 23 Aug 2007 - mcdurdin - I719 - Fix Alt+LeftShift and Word interactions @@ -43,12 +43,6 @@ #include "pch.h" // I4128 // I4287 #include "serialkeyeventclient.h" -#define KEYMAN_MOREPOST "WM_KMMOREPOST" - -#ifndef WM_UNICHAR -#define WM_UNICHAR 0x0109 -#define UNICODE_NOCHAR 0xFFFF -#endif AIWin2000Unicode::AIWin2000Unicode() { @@ -70,13 +64,13 @@ BOOL AIWin2000Unicode::CanHandleWindow(HWND ahwnd) } BOOL AIWin2000Unicode::HandleWindow(HWND ahwnd) -{ +{ if(hwnd != ahwnd) { - hwnd = ahwnd; + hwnd = ahwnd; context->Reset(); } - return TRUE; + return TRUE; } BOOL AIWin2000Unicode::IsWindowHandled(HWND ahwnd) @@ -84,11 +78,11 @@ BOOL AIWin2000Unicode::IsWindowHandled(HWND ahwnd) return (hwnd == ahwnd); } -BOOL AIWin2000Unicode::IsUnicode() -{ +BOOL AIWin2000Unicode::IsUnicode() +{ BOOL Result = IsWindowUnicode(hwnd); SendDebugMessageFormat(0, sdmAIDefault, 0, "IsWindowUnicode=%s", Result ? "Yes" : "No"); - return Result; + return Result; } /* Context functions */ @@ -96,7 +90,7 @@ BOOL AIWin2000Unicode::IsUnicode() void AIWin2000Unicode::ReadContext() { } - + void AIWin2000Unicode::AddContext(WCHAR ch) //I2436 { context->Add(ch); @@ -121,7 +115,7 @@ void AIWin2000Unicode::SetContext(const WCHAR* buf) { return context->Set(buf); } - + BYTE SavedKbdState[256]; BOOL AIWin2000Unicode::SendActions() // I4196 @@ -137,7 +131,7 @@ BOOL AIWin2000Unicode::QueueAction(int ItemType, DWORD dwData) int result = AppIntegration::QueueAction(ItemType, dwData); //SendDebugMessageFormat(hwnd, sdmAIDefault, 0, "App::QueueAction ItemType=%d dwData=%x", ItemType, dwData); - + switch(ItemType) { case QIT_VKEYDOWN: @@ -166,27 +160,16 @@ BOOL AIWin2000Unicode::QueueAction(int ItemType, DWORD dwData) return result; } -BOOL AIWin2000Unicode::QueueDebugInformation(int ItemType, LPGROUP Group, LPKEY Rule, PWSTR fcontext, PWSTR foutput, DWORD_PTR dwExtraFlags) -{ - UNREFERENCED_PARAMETER(ItemType); - UNREFERENCED_PARAMETER(Group); - UNREFERENCED_PARAMETER(Rule); - UNREFERENCED_PARAMETER(fcontext); - UNREFERENCED_PARAMETER(foutput); - UNREFERENCED_PARAMETER(dwExtraFlags); - return TRUE; -} - // I1512 - SendInput with VK_PACKET for greater robustness BOOL AIWin2000Unicode::PostKeys() -{ +{ PKEYMAN64THREADDATA _td = ThreadGlobals(); if(!_td) { return FALSE; } - if(QueueSize == 0) + if(QueueSize == 0) { return TRUE; } @@ -208,7 +191,7 @@ BOOL AIWin2000Unicode::PostKeys() switch(Queue[n].ItemType) { case QIT_VKEYDOWN: if((Queue[n].dwData & QVK_KEYMASK) == 0x05) Queue[n].dwData = (Queue[n].dwData & QVK_FLAGMASK) | VK_RETURN; // I649 // I3438 - + /* 6.0.153.0: Fix repeat state for virtual keys */ if((Queue[n].dwData & QVK_KEYMASK) <= VK__MAX) // I3438 @@ -277,7 +260,6 @@ BOOL AIWin2000Unicode::PostKeys() break; case QIT_BACK: if(Queue[n].dwData & BK_DEADKEY) break; - if(Addin_ProcessBackspace(hwnd)) break; pInputs[i].type = INPUT_KEYBOARD; pInputs[i].ki.wVk = VK_BACK; diff --git a/windows/src/engine/keyman32/appint/aiWin2000Unicode.h b/windows/src/engine/keyman32/appint/aiWin2000Unicode.h index 73db7ac907..1ee49ed001 100644 --- a/windows/src/engine/keyman32/appint/aiWin2000Unicode.h +++ b/windows/src/engine/keyman32/appint/aiWin2000Unicode.h @@ -1,18 +1,18 @@ /* Name: aiWin2000Unicode Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 27 Jan 2009 Modified Date: 23 Jun 2014 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 27 Jan 2009 - mcdurdin - I1797 - Add fallback for AIWin2000 app integration 11 Dec 2009 - mcdurdin - I934 - x64 - Initial version 24 Jun 2010 - mcdurdin - I2436 - Add space to context for AIWin2000Unicode when not matched @@ -43,7 +43,7 @@ public: virtual BOOL QueueAction(int ItemType, DWORD dwData); /* Information functions */ - + virtual BOOL CanHandleWindow(HWND ahwnd); virtual BOOL IsWindowHandled(HWND ahwnd); virtual BOOL HandleWindow(HWND ahwnd); @@ -59,9 +59,8 @@ public: virtual void SetContext(const WCHAR* buf); /* Queue and sending functions */ - + virtual BOOL SendActions(); // I4196 - virtual BOOL QueueDebugInformation(int ItemType, LPGROUP Group, LPKEY Rule, PWSTR fcontext, PWSTR foutput, DWORD_PTR dwExtraFlags); }; #endif diff --git a/windows/src/engine/keyman32/appint/appint.h b/windows/src/engine/keyman32/appint/appint.h index 3e9a4dfb4d..6fe7ca7e20 100644 --- a/windows/src/engine/keyman32/appint/appint.h +++ b/windows/src/engine/keyman32/appint/appint.h @@ -43,22 +43,6 @@ typedef struct #define QIT_CAPSLOCK 8 #define QIT_INVALIDATECONTEXT 9 -// QueueDebugInformation ItemTypes -#define QID_BEGIN_UNICODE 0 -#define QID_BEGIN_ANSI 1 -#define QID_GROUP_ENTER 2 -#define QID_GROUP_EXIT 3 -#define QID_RULE_ENTER 4 -#define QID_RULE_EXIT 5 -#define QID_MATCH_ENTER 6 -#define QID_MATCH_EXIT 7 -#define QID_NOMATCH_ENTER 8 -#define QID_NOMATCH_EXIT 9 -#define QID_END 10 - -#define QID_FLAG_RECURSIVE_OVERFLOW 0x0001 -#define QID_FLAG_NOMATCH 0x0002 - #define QVK_EXTENDED 0x00010000 // Flag for QIT_VKEYDOWN to indicate an extended key #define QVK_KEYMASK 0x0000FFFF #define QVK_FLAGMASK 0xFFFF0000 @@ -178,15 +162,6 @@ public: }; -class AppContextWithStores : public AppContext // I4978 -{ -public: - AppContextWithStores(int nKeyboardOptions); - ~AppContextWithStores(); - DWORD nKeyboardOptions; - LPINTKEYBOARDOPTIONS KeyboardOptions; -}; - class AppIntegration:public AppActionQueue { protected: @@ -214,7 +189,6 @@ public: /* Queue and sending functions */ - virtual BOOL QueueDebugInformation(int ItemType, LPGROUP Group, LPKEY Rule, PWSTR fcontext, PWSTR foutput, DWORD_PTR dwExtraFlags) = 0; void SetCurrentShiftState(int ShiftFlags) { FShiftFlags = ShiftFlags; } virtual BOOL SendActions() = 0; // I4196 }; diff --git a/windows/src/engine/keyman32/calldll.cpp b/windows/src/engine/keyman32/calldll.cpp index 142db01747..f0c623373c 100644 --- a/windows/src/engine/keyman32/calldll.cpp +++ b/windows/src/engine/keyman32/calldll.cpp @@ -93,34 +93,6 @@ static LPIMDLL AddIMDLL(LPINTKEYBOARDINFO lpkbi, LPSTR kbdpath, LPSTR dllfilenam return imd; } -/* Add a dll hook function to the list of hook functions associated with a single dll */ - -static BOOL AddIMDLLHook(LPIMDLL imd, LPSTR funcname, DWORD storeno, PWCHAR *dpString) -{ - //SendDebugMessageFormat(0, sdmKeyboard, 0, "AddIMDLLHook: Enter"); - /* Get the procedure address for the function */ - - IMDLLHOOKProc dhp = (IMDLLHOOKProc) GetProcAddress(imd->hModule, funcname); - if(!dhp) return FALSE; - - /* Add the function to the list of functions in the DLL */ - - LPIMDLLHOOK hooks = new IMDLLHOOK[imd->nHooks+1]; - if(imd->nHooks > 0) - { - memcpy(hooks, imd->Hooks, sizeof(IMDLLHOOK) * imd->nHooks); - delete imd->Hooks; - } - imd->Hooks = hooks; - strncpy(imd->Hooks[imd->nHooks].name, funcname, 31); - imd->Hooks[imd->nHooks].name[31] = 0; - imd->Hooks[imd->nHooks].storeno = storeno; - imd->Hooks[imd->nHooks].function = dhp; - *dpString = (PWCHAR) &imd->Hooks[imd->nHooks++]; - //SendDebugMessageFormat(0, sdmKeyboard, 0, "AddIMDLLHook: Exit"); - return TRUE; -} - static km_kbp_action_item* kmnToCoreActionItem(int ItemType, DWORD dwData, WORD wVkey) { @@ -232,55 +204,6 @@ BOOL CallbackDLLs(LPINTKEYBOARDINFO lpkbi, PSTR cmd) return TRUE; } -/* Load the dlls associated with a keyboard */ - -BOOL LoadDLLs(LPINTKEYBOARDINFO lpkbi) -{ - char fullname[_MAX_PATH]; - //SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Enter"); - - if(lpkbi->nIMDLLs > 0) if(!UnloadDLLs(lpkbi)) return FALSE; - - if (!GetKeyboardFileName(lpkbi->Name, fullname, _MAX_PATH)) { - SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Filename not found[%s]", lpkbi->Name); - return FALSE; - } - - if (!lpkbi->Keyboard) { - SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Keyboard is null"); - return FALSE; - } - for(DWORD i = 0; i < lpkbi->Keyboard->cxStoreArray; i++) - { - LPSTORE s = &lpkbi->Keyboard->dpStoreArray[i]; - if(s->dwSystemID == TSS_CALLDEFINITION) - { - /* Break the store string into components */ - - PCHAR p = wstrtostr(s->dpString), q, r, context; - - q = strtok_s(p, ":", &context); - r = strtok_s(NULL, ":", &context); - - if(!q || !r) - { - s->dwSystemID = TSS_CALLDEFINITION_LOADFAILED; - delete[] p; - continue; - } - - LPIMDLL imd = AddIMDLL(lpkbi, fullname, q); - if(imd && AddIMDLLHook(imd, r, i, &s->dpString)) s->dwSystemID = TSS_CALLDEFINITION; - else s->dwSystemID = TSS_CALLDEFINITION_LOADFAILED; - - delete[] p; - } - } - - //SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Exit"); - return TRUE; -} - // Both Core and Window keyboard processor can use this function BOOL UnloadDLLs(LPINTKEYBOARDINFO lpkbi) { @@ -302,7 +225,7 @@ BOOL UnloadDLLs(LPINTKEYBOARDINFO lpkbi) lpkbi->IMDLLs = NULL; lpkbi->nIMDLLs = 0; - if (Globals::get_CoreIntegration() && lpkbi->lpCoreKeyboardState) { + if (lpkbi->lpCoreKeyboardState) { km_kbp_state_imx_deregister_callback(lpkbi->lpCoreKeyboardState); } return TRUE; @@ -330,26 +253,6 @@ BOOL DeactivateDLLs(LPINTKEYBOARDINFO lpkbi) return TRUE; } -void CallDLL(LPINTKEYBOARDINFO lpkbi, DWORD storenum) -{ - //SendDebugMessageFormat(0, sdmKeyboard, 0, "CallDll: Enter"); - if (!lpkbi->Keyboard) return; - if(storenum >= lpkbi->Keyboard->cxStoreArray) return; - - LPSTORE s = &lpkbi->Keyboard->dpStoreArray[storenum]; - if(s->dwSystemID != TSS_CALLDEFINITION) return; - if(s->dpString == NULL) return; - LPIMDLLHOOK imdh = (LPIMDLLHOOK) s->dpString; - - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return; - - if(_td->TIPFUpdateable) { // I4452 - (*imdh->function)(_td->state.msg.hwnd, _td->state.vkey, _td->state.charCode, Globals::get_ShiftState()); - } - //SendDebugMessageFormat(0, sdmKeyboard, 0, "CallDll: Exit"); -} - // The callback function called by the Core Keyboardprocessor extern "C" uint8_t IM_CallBackCore(km_kbp_state *km_state, uint32_t UniqueStoreNo, void *callbackObject) { //SendDebugMessageFormat(0, sdmKeyboard, 0, "IM_CallBackCore: Enter"); @@ -402,90 +305,84 @@ extern "C" BOOL _declspec(dllexport) WINAPI KMSetOutput(PWSTR buf, DWORD backlen if (!_td->app) return FALSE; - if (!Globals::get_CoreIntegration()) { // TODO: 5442 Remove If and fix indent - while (backlen-- > 0) - _td->app->QueueAction(QIT_BACK, BK_DEFAULT); - while (*buf) - _td->app->QueueAction(QIT_CHAR, *buf++); - return TRUE; - } else { - if (!_td->lpActiveKeyboard || !_td->lpActiveKeyboard->lpCoreKeyboardState) { - SendDebugMessageFormat(0, sdmKeyboard, 0, "KMSetOutputCore: no active state"); - return FALSE; - } - DWORD numActions = backlen + (DWORD)wcslen(buf); - DWORD idx = 0; - km_kbp_action_item *actionItems = new km_kbp_action_item[numActions + 1]; - // The actions sent to the core processor need to set the expected_type - // correctly. To do this need to check the context as we process the - // backspaces. - km_kbp_context_item *citems = nullptr; - if (KM_KBP_STATUS_OK != kbp_state_get_intermediate_context(_td->lpActiveKeyboard->lpCoreKeyboardState, &citems)) { - delete[] actionItems; - return FALSE; - } - - DWORD context_length = (DWORD)km_kbp_context_item_list_size(citems); - WCHAR *contextString = new WCHAR[(context_length * 3) + 1]; // *3 if every context item was a deadkey - if (!ContextItemToAppContext(citems, contextString, context_length)) { - km_kbp_context_items_dispose(citems); - delete[] contextString; - delete[] actionItems; - return FALSE; - } - km_kbp_context_items_dispose(citems); - AppContext context; - context.Set(contextString); - delete[] contextString; - - while (backlen-- > 0) { - actionItems[idx].type = KM_KBP_IT_BACK; - WCHAR *CodeUnitPtr; - const int DeadKeyLength = 3; - const int SurrogateLength = 2; - const int SingleCharLength = 1; - if (context.CharIsDeadkey()) { - CodeUnitPtr = context.BufMax(DeadKeyLength); - CodeUnitPtr += 2; - actionItems[idx].backspace.expected_type = KM_KBP_BT_MARKER; - actionItems[idx].backspace.expected_value = (uintptr_t)*CodeUnitPtr; - } else if (context.CharIsSurrogatePair()) { - CodeUnitPtr = context.BufMax(SurrogateLength); - actionItems[idx].backspace.expected_type = KM_KBP_BT_CHAR; - actionItems[idx].backspace.expected_value = (DWORD)Uni_SurrogateToUTF32(*CodeUnitPtr, *(CodeUnitPtr + 1)); - } else if (!context.IsEmpty()) { - CodeUnitPtr = context.BufMax(SingleCharLength); - actionItems[idx].backspace.expected_type = KM_KBP_BT_CHAR; - actionItems[idx].backspace.expected_value = (DWORD)*CodeUnitPtr; - } else { - actionItems[idx].backspace.expected_type = KM_KBP_BT_UNKNOWN; - actionItems[idx].backspace.expected_value = 0; - } - context.Delete(); - idx++; - } - - while (*buf) { - actionItems[idx].type = KM_KBP_IT_CHAR; - if (Uni_IsSurrogate1(*buf) && Uni_IsSurrogate2(*(buf + 1))) { - actionItems[idx].character = Uni_SurrogateToUTF32(*buf, *(buf + 1)); - buf++; - } else { - actionItems[idx].character = (DWORD)(*buf); - } - buf++; - idx++; - } - actionItems[idx].type = KM_KBP_IT_END; - if (KM_KBP_STATUS_OK != km_kbp_state_queue_action_items(_td->lpActiveKeyboard->lpCoreKeyboardState, actionItems)) { - delete[] actionItems; - return FALSE; - } - delete[] actionItems; - //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMSetOutputCore: Exit"); - return TRUE; + if (!_td->lpActiveKeyboard || !_td->lpActiveKeyboard->lpCoreKeyboardState) { + SendDebugMessageFormat(0, sdmKeyboard, 0, "KMSetOutputCore: no active state"); + return FALSE; } + DWORD numActions = backlen + (DWORD)wcslen(buf); + DWORD idx = 0; + km_kbp_action_item *actionItems = new km_kbp_action_item[numActions + 1]; + + // The actions sent to the core processor need to set the expected_type + // correctly. To do this need to check the context as we process the + // backspaces. + km_kbp_context_item *citems = nullptr; + if (KM_KBP_STATUS_OK != kbp_state_get_intermediate_context(_td->lpActiveKeyboard->lpCoreKeyboardState, &citems)) { + delete[] actionItems; + return FALSE; + } + + DWORD context_length = (DWORD)km_kbp_context_item_list_size(citems); + WCHAR *contextString = new WCHAR[(context_length * 3) + 1]; // *3 if every context item was a deadkey + if (!ContextItemToAppContext(citems, contextString, context_length)) { + km_kbp_context_items_dispose(citems); + delete[] contextString; + delete[] actionItems; + return FALSE; + } + km_kbp_context_items_dispose(citems); + AppContext context; + context.Set(contextString); + delete[] contextString; + + while (backlen-- > 0) { + actionItems[idx].type = KM_KBP_IT_BACK; + WCHAR *CodeUnitPtr; + const int DeadKeyLength = 3; + const int SurrogateLength = 2; + const int SingleCharLength = 1; + if (context.CharIsDeadkey()) { + CodeUnitPtr = context.BufMax(DeadKeyLength); + CodeUnitPtr += 2; + actionItems[idx].backspace.expected_type = KM_KBP_BT_MARKER; + actionItems[idx].backspace.expected_value = (uintptr_t)*CodeUnitPtr; + } else if (context.CharIsSurrogatePair()) { + CodeUnitPtr = context.BufMax(SurrogateLength); + actionItems[idx].backspace.expected_type = KM_KBP_BT_CHAR; + actionItems[idx].backspace.expected_value = (DWORD)Uni_SurrogateToUTF32(*CodeUnitPtr, *(CodeUnitPtr + 1)); + } else if (!context.IsEmpty()) { + CodeUnitPtr = context.BufMax(SingleCharLength); + actionItems[idx].backspace.expected_type = KM_KBP_BT_CHAR; + actionItems[idx].backspace.expected_value = (DWORD)*CodeUnitPtr; + } else { + actionItems[idx].backspace.expected_type = KM_KBP_BT_UNKNOWN; + actionItems[idx].backspace.expected_value = 0; + } + context.Delete(); + idx++; + } + + while (*buf) { + actionItems[idx].type = KM_KBP_IT_CHAR; + if (Uni_IsSurrogate1(*buf) && Uni_IsSurrogate2(*(buf + 1))) { + actionItems[idx].character = Uni_SurrogateToUTF32(*buf, *(buf + 1)); + buf++; + } else { + actionItems[idx].character = (DWORD)(*buf); + } + buf++; + idx++; + } + actionItems[idx].type = KM_KBP_IT_END; + if (KM_KBP_STATUS_OK != km_kbp_state_queue_action_items(_td->lpActiveKeyboard->lpCoreKeyboardState, actionItems)) { + delete[] actionItems; + return FALSE; + } + delete[] actionItems; + //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMSetOutputCore: Exit"); + return TRUE; + } extern "C" BOOL _declspec(dllexport) WINAPI KMQueueAction(int ItemType, DWORD dwData) { @@ -496,61 +393,53 @@ extern "C" BOOL _declspec(dllexport) WINAPI KMQueueAction(int ItemType, DWORD dw if (!_td->app) return FALSE; - if (!Globals::get_CoreIntegration()) { - return _td->app->QueueAction(ItemType, dwData); // TODO: 5442 Remove - } else { - if (!_td->lpActiveKeyboard || !_td->lpActiveKeyboard->lpCoreKeyboardState) { - return FALSE; - } - - km_kbp_action_item *actionItem = kmnToCoreActionItem(ItemType, dwData, _td->state.vkey); - km_kbp_status_codes error_status = - (km_kbp_status_codes)km_kbp_state_queue_action_items(_td->lpActiveKeyboard->lpCoreKeyboardState, actionItem); - if (error_status != KM_KBP_STATUS_OK) { - delete[] actionItem; - SendDebugMessageFormat(0, sdmKeyboard, 0, "KMQueueAction: Error core queue_action_items error status:[%lu]",error_status); - return FALSE; - } - delete[] actionItem; - //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMQueueActionCore: Exit"); - return TRUE; + if (!_td->lpActiveKeyboard || !_td->lpActiveKeyboard->lpCoreKeyboardState) { + return FALSE; } + + km_kbp_action_item *actionItem = kmnToCoreActionItem(ItemType, dwData, _td->state.vkey); + km_kbp_status_codes error_status = + (km_kbp_status_codes)km_kbp_state_queue_action_items(_td->lpActiveKeyboard->lpCoreKeyboardState, actionItem); + if (error_status != KM_KBP_STATUS_OK) { + delete[] actionItem; + SendDebugMessageFormat(0, sdmKeyboard, 0, "KMQueueAction: Error core queue_action_items error status:[%lu]",error_status); + return FALSE; + } + delete[] actionItem; + //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMQueueActionCore: Exit"); + return TRUE; + } extern "C" BOOL _declspec(dllexport) WINAPI KMGetContext(PWSTR buf, DWORD len) { //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMGetContext: Enter"); PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - if(!_td->app) return FALSE; - // TODO: 5442 KMGetContext is already public call (even though it is pointer) Rather then making a new KMGetContextCore - // This has been modified to check for core processor once we move to core processor the old Windows Platmform calling of - // ContextBuff can be removed - // - if(!Globals::get_CoreIntegration()){ - PWSTR q = _td->app->ContextBufMax(len); - if (!q) - return FALSE; // context buf does not exist - - wcscpy_s(buf, len + 1, q); // I3091 - return TRUE; - } else { - if (!_td->lpActiveKeyboard || !_td->lpActiveKeyboard->lpCoreKeyboardState) { - return FALSE; - } - km_kbp_context_item *citems = nullptr; - if (KM_KBP_STATUS_OK != kbp_state_get_intermediate_context(_td->lpActiveKeyboard->lpCoreKeyboardState, &citems)) { - return FALSE; - } - - if (!ContextItemToAppContext(citems, buf, len)) { - km_kbp_context_items_dispose(citems); - return FALSE; - } - km_kbp_context_items_dispose(citems); - //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMGetContext: Exit"); - return TRUE; + if(!_td) { + return FALSE; } + + if(!_td->app) { + return FALSE; + } + + if (!_td->lpActiveKeyboard || !_td->lpActiveKeyboard->lpCoreKeyboardState) { + return FALSE; + } + + km_kbp_context_item *citems = nullptr; + if (KM_KBP_STATUS_OK != kbp_state_get_intermediate_context(_td->lpActiveKeyboard->lpCoreKeyboardState, &citems)) { + return FALSE; + } + + if (!ContextItemToAppContext(citems, buf, len)) { + km_kbp_context_items_dispose(citems); + return FALSE; + } + km_kbp_context_items_dispose(citems); + //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMGetContext: Exit"); + return TRUE; + } extern "C" BOOL _declspec(dllexport) WINAPI KMDisplayIM(HWND hwnd, BOOL FShowAlways) @@ -650,8 +539,8 @@ BOOL IsIMWindow(HWND hwnd) /* Add a dll hook function to the list of hook functions associated with a single dll */ static BOOL -AddIMDLLHookCore(LPIMDLL imd, LPSTR funcname, DWORD storeno) { - //SendDebugMessageFormat(0, sdmKeyboard, 0, "AddIMDLLHookCore: Enter"); +AddIMDLLHook(LPIMDLL imd, LPSTR funcname, DWORD storeno) { + //SendDebugMessageFormat(0, sdmKeyboard, 0, "AddIMDLLHook: Enter"); /* Get the procedure address for the function */ IMDLLHOOKProc dhp = (IMDLLHOOKProc)GetProcAddress(imd->hModule, funcname); if (!dhp) @@ -670,15 +559,15 @@ AddIMDLLHookCore(LPIMDLL imd, LPSTR funcname, DWORD storeno) { imd->Hooks[imd->nHooks].storeno = storeno; imd->Hooks[imd->nHooks].function = dhp; imd->nHooks++; - //SendDebugMessageFormat(0, sdmKeyboard, 0, "AddIMDLLHookCore: Exit"); + //SendDebugMessageFormat(0, sdmKeyboard, 0, "AddIMDLLHook: Exit"); return TRUE; } /* Load the dlls associated with a keyboard */ BOOL -LoadDLLsCore(LPINTKEYBOARDINFO lpkbi) { +LoadDLLs(LPINTKEYBOARDINFO lpkbi) { char fullname[_MAX_PATH]; - //SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLsCore: Enter"); + //SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Enter"); if (lpkbi->nIMDLLs > 0) if (!UnloadDLLs(lpkbi)) @@ -694,11 +583,11 @@ LoadDLLsCore(LPINTKEYBOARDINFO lpkbi) { BOOL result = false; for (; imx_list->library_name; ++imx_list) { LPIMDLL imd = AddIMDLL(lpkbi, fullname, wstrtostr(reinterpret_cast(imx_list->library_name))); - if (imd && AddIMDLLHookCore(imd, wstrtostr(reinterpret_cast(imx_list->function_name)), imx_list->imx_id)) { + if (imd && AddIMDLLHook(imd, wstrtostr(reinterpret_cast(imx_list->function_name)), imx_list->imx_id)) { result = TRUE; } else { - SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLsCore: Error Loading Library name [%s], Function name [%s]", + SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Error Loading Library name [%s], Function name [%s]", wstrtostr(reinterpret_cast(imx_list->library_name)), wstrtostr(reinterpret_cast(imx_list->function_name))); } @@ -707,7 +596,7 @@ LoadDLLsCore(LPINTKEYBOARDINFO lpkbi) { if (result) { km_kbp_state_imx_register_callback(lpkbi->lpCoreKeyboardState, IM_CallBackCore, (void *)lpkbi); } - //SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLsCore: Exit"); + //SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Exit"); return TRUE; } diff --git a/windows/src/engine/keyman32/calldll.h b/windows/src/engine/keyman32/calldll.h index 9eb1a7ade4..6e719bde9a 100644 --- a/windows/src/engine/keyman32/calldll.h +++ b/windows/src/engine/keyman32/calldll.h @@ -19,24 +19,19 @@ #ifndef __CALLDLL_H #define __CALLDLL_H -BOOL LoadDLLs(LPINTKEYBOARDINFO lpkbi); -BOOL UnloadDLLs(LPINTKEYBOARDINFO lpkbi); -BOOL DeactivateDLLs(LPINTKEYBOARDINFO lpkbi); -BOOL ActivateDLLs(LPINTKEYBOARDINFO lpkbi); - -// TODO: 5444 This will become the only LoadDLLs function /** * Load the all the dlls used by the current keyboard * @param lpkbi The keyboard for which to load the dlls * @return BOOL True on success */ -BOOL LoadDLLsCore(LPINTKEYBOARDINFO lpkbi); +BOOL LoadDLLs(LPINTKEYBOARDINFO lpkbi); +BOOL UnloadDLLs(LPINTKEYBOARDINFO lpkbi); +BOOL DeactivateDLLs(LPINTKEYBOARDINFO lpkbi); +BOOL ActivateDLLs(LPINTKEYBOARDINFO lpkbi); BOOL IsIMWindow(HWND hwnd); -void CallDLL(LPINTKEYBOARDINFO lpkbi, DWORD storenum); - // Callback function used by the core processor to call out to 3rd Party Library functions extern "C" uint8_t IM_CallBackCore(km_kbp_state *km_state, uint32_t UniqueStoreNo, void *callbackObject); diff --git a/windows/src/engine/keyman32/capsstate.cpp b/windows/src/engine/keyman32/capsstate.cpp index c9d283cde4..4f9b466e9e 100644 --- a/windows/src/engine/keyman32/capsstate.cpp +++ b/windows/src/engine/keyman32/capsstate.cpp @@ -29,73 +29,3 @@ BOOL IsCapsLockOn(void) { return GetKeyState(VK_CAPITAL) & 1; } - -void ResetCapsLock(void) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if (!_td) return; - if (!_td->lpActiveKeyboard) return; - if (!_td->lpActiveKeyboard->Keyboard) return; - - SendDebugMessageFormat(0, sdmGlobal, 0, "ResetCapsLock: enter"); - - if (_td->lpActiveKeyboard->Keyboard->dwFlags & KF_CAPSALWAYSOFF) - { - SendDebugMessageFormat(0, sdmGlobal, 0, "ResetCapsLock: caps lock should be always off"); - if (IsCapsLockOn()) - { - SendDebugMessageFormat(0, sdmGlobal, 0, "ResetCapsLock: caps lock is on, switching off caps lock"); - keybd_event(VK_CAPITAL, 0x3A, 0, 0); - keybd_event(VK_CAPITAL, 0x3A, 0 | KEYEVENTF_KEYUP, 0); - } - } - SendDebugMessageFormat(0, sdmGlobal, 0, "ResetCapsLock: exit"); -} - - -void KeyCapsLockPress(BOOL FIsUp) // I3284 - void // I3529 -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if (!_td) return; - if (!_td->lpActiveKeyboard) return; // pass through to window - if (!_td->lpActiveKeyboard->Keyboard) return; - - if (_td->lpActiveKeyboard->Keyboard->dwFlags & KF_CAPSONONLY) - { - SendDebugMessageFormat(0, sdmAIDefault, 0, "KeyCapsLockPress: KF_CAPSONONLY: FIsUp=%d CapsState=%d", FIsUp, IsCapsLockOn()); - if (FIsUp && !IsCapsLockOn()) // I267 - 24/11/2006 invert GetKeyState test - { - keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, 0, 0); - keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, KEYEVENTF_KEYUP, 0); - } - } - else if (_td->lpActiveKeyboard->Keyboard->dwFlags & KF_CAPSALWAYSOFF) - { - SendDebugMessageFormat(0, sdmAIDefault, 0, "KeyCapsLockPress: KF_CAPSALWAYSOFF: FIsUp=%d CapsState=%d", FIsUp, IsCapsLockOn()); - if (!FIsUp && IsCapsLockOn()) - { // I267 - 24/11/2006 invert GetKeyState test - keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, KEYEVENTF_KEYUP, 0); - keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, 0, 0); - } - } -} - - -void KeyShiftPress(BOOL FIsUp) // I3284 - void // I3529 -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if (!_td) return; - if (!_td->lpActiveKeyboard) return; // pass through to window - if (!_td->lpActiveKeyboard->Keyboard) return; - - if (_td->lpActiveKeyboard->Keyboard->dwFlags & KF_SHIFTFREESCAPS) - { - SendDebugMessageFormat(0, sdmAIDefault, 0, "KeyShiftPress: KF_SHIFTFREESCAPS: FIsUp=%d CapsState=%d", FIsUp, IsCapsLockOn()); - if (!FIsUp && IsCapsLockOn()) - { - keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, 0, 0); - keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, KEYEVENTF_KEYUP, 0); - } - } -} - diff --git a/windows/src/engine/keyman32/capsstate.h b/windows/src/engine/keyman32/capsstate.h index aeb3e29000..d28ba9c0db 100644 --- a/windows/src/engine/keyman32/capsstate.h +++ b/windows/src/engine/keyman32/capsstate.h @@ -20,8 +20,5 @@ #define __CAPSSTATE_H BOOL IsCapsLockOn(void); -void ResetCapsLock(void); -void KeyCapsLockPress(BOOL FIsUp); -void KeyShiftPress(BOOL FIsUp); #endif diff --git a/windows/src/engine/keyman32/globals.h b/windows/src/engine/keyman32/globals.h index 6e840fce99..320ef811de 100644 --- a/windows/src/engine/keyman32/globals.h +++ b/windows/src/engine/keyman32/globals.h @@ -151,7 +151,6 @@ public: static BOOL get_debug_KeymanLog(); static BOOL get_debug_ToConsole(); - static BOOL get_CoreIntegration(); static void LoadDebugSettings(); }; @@ -216,8 +215,6 @@ typedef struct tagKEYMAN64THREADDATA FInitialised, FInitialising; - char ForceFileName[MAX_PATH]; - DWORD ActiveKeymanID; /* TIP Globals */ diff --git a/windows/src/engine/keyman32/glossary.cpp b/windows/src/engine/keyman32/glossary.cpp index 2954638c19..7a6aecddc0 100644 --- a/windows/src/engine/keyman32/glossary.cpp +++ b/windows/src/engine/keyman32/glossary.cpp @@ -1,18 +1,18 @@ /* Name: glossary Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 20 Jul 2008 Modified Date: 28 May 2014 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 20 Jul 2008 - mcdurdin - I1498 - Fix keyboard switching for Shadow keyboards on Vista+ 20 Jul 2008 - mcdurdin - I1546 - Fix language switch with ids >= x80000000 20 Jul 2008 - mcdurdin - I1545 - Fix registry leak @@ -38,9 +38,9 @@ BOOL HKLIsIME(HKL hkl) // I1498 - fix keyboard switching for shadow keyboards o if( (GetVersion() & 0xFF) >= 6 ) return FALSE; if( (GetVersion() & 0x8000000) == 0x8000000 || (GetVersion() & 0xFF) == 4 ) r = GetSystemMetrics(SM_DBCSENABLED); - else + else r = GetSystemMetrics(SM_IMMENABLED); - + return r && ImmIsIME(hkl); } #pragma warning(default: 4996) @@ -99,12 +99,12 @@ DWORD HKLToKeyboardID(HKL hkl) return (DWORD) LOWORD(hkl); } - for(len=16, n = i = 0; RegEnumKeyEx(hkey, i, str, &len, 0, NULL, NULL, &ft) == ERROR_SUCCESS; - len = 16, i++, n=0) + for(len=16, n = i = 0; RegEnumKeyEx(hkey, i, str, &len, 0, NULL, NULL, &ft) == ERROR_SUCCESS; + len = 16, i++, n=0) { RegOpenKeyEx(hkey, str, NULL, KEY_READ, &hsubkey); len = 16; - if(RegQueryValueEx(hsubkey, REGSZ_LayoutID, NULL, NULL, (LPBYTE) str2, &len) == ERROR_SUCCESS) + if(RegQueryValueEx(hsubkey, REGSZ_LayoutID, NULL, NULL, (LPBYTE) str2, &len) == ERROR_SUCCESS) { n = strtoul(str2, NULL, 16); // I1546 if(n == LayoutID) @@ -120,7 +120,7 @@ DWORD HKLToKeyboardID(HKL hkl) } RegCloseKey(hkey); - + //SendDebugMessageFormat(0, sdmGlobal, 0, "HKLToKeyboardID: fails[2], return LOWORD(hkl)=%x", LOWORD(hkl)); return (DWORD) LOWORD(hkl); // should never happen } @@ -143,11 +143,11 @@ WORD HKLToLayoutNumber(HKL hkl) if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSZ_SystemKeyboardLayouts, NULL, KEY_READ, &hkey) != ERROR_SUCCESS) return 0; - for(len=16, n = i = 0; RegEnumKeyEx(hkey, i, str, &len, 0, NULL, NULL, &ft) == ERROR_SUCCESS; len = 16, i++, n=0) + for(len=16, n = i = 0; RegEnumKeyEx(hkey, i, str, &len, 0, NULL, NULL, &ft) == ERROR_SUCCESS; len = 16, i++, n=0) { RegOpenKeyEx(hkey, str, NULL, KEY_READ, &hsubkey); len = 16; - if(RegQueryValueEx(hsubkey, REGSZ_LayoutID, NULL, NULL, (LPBYTE) str2, &len) == ERROR_SUCCESS) + if(RegQueryValueEx(hsubkey, REGSZ_LayoutID, NULL, NULL, (LPBYTE) str2, &len) == ERROR_SUCCESS) { if(strtoul(str2, NULL, 16) == LayoutID) break; // strtoul - I1546 } @@ -166,37 +166,3 @@ WORD HKLToLayoutID(HKL hkl) return HIWORD(hkl) & 0x0FFF; } - -DWORD EthnologueCodeToKeymanID(DWORD EthCode) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return KEYMANID_NONKEYMAN; - - for(int i = 0; i < _td->nKeyboards; i++) - { - if(!_td->lpKeyboards[i].Keyboard && !LoadlpKeyboard(i)) - { - SendDebugMessageFormat(0,sdmGlobal,0, - "EthnologueCodeToKeymanID: Unable to load keyboard %s", _td->lpKeyboards[i].Name); - return KEYMANID_NONKEYMAN; - } - - PWSTR ps = GetSystemStore(_td->lpKeyboards[i].Keyboard, TSS_ETHNOLOGUECODE); - if(ps) - { - SendDebugMessageFormat(0,sdmGlobal,0,"EthnologueCodeToKeymanID: %s %ws %x", _td->lpKeyboards[i].Name, ps, EthnologueStringCodeToDWord(ps)); - if(EthnologueStringCodeToDWord(ps) == EthCode) return _td->lpKeyboards[i].KeymanID; - } - } - - return KEYMANID_NONKEYMAN; -} - -DWORD EthnologueStringCodeToDWord(PWSTR EthCode) -{ - if(wcslen(EthCode) < 3 || wcslen(EthCode) > 4) return (DWORD)-1; - return (LOBYTE(EthCode[0])) | - (LOBYTE(EthCode[1]) << 8) | - (LOBYTE(EthCode[2]) << 16) | - (LOBYTE(EthCode[3]) << 24); -} diff --git a/windows/src/engine/keyman32/k32_globals.cpp b/windows/src/engine/keyman32/k32_globals.cpp index 054945b812..989a787f95 100644 --- a/windows/src/engine/keyman32/k32_globals.cpp +++ b/windows/src/engine/keyman32/k32_globals.cpp @@ -288,9 +288,6 @@ static BOOL f_debug_KeymanLog = FALSE, f_debug_ToConsole = FALSE; -static BOOL - f_CoreIntegration = TRUE; - #pragma data_seg() /***************************************************************************/ @@ -365,8 +362,6 @@ BOOL Globals::get_MnemonicDeadkeyConversionMode() { return f_MnemonicDeadkeyConv BOOL Globals::get_debug_KeymanLog() { return f_debug_KeymanLog; } BOOL Globals::get_debug_ToConsole() { return f_debug_ToConsole; } -BOOL Globals::get_CoreIntegration() { return f_CoreIntegration; } - void Globals::SetBaseKeyboardName(wchar_t *baseKeyboardName, wchar_t *baseKeyboardNameAlt) { // I4583 wcscpy_s(f_BaseKeyboardName, baseKeyboardName); wcscpy_s(f_BaseKeyboardNameAlt, baseKeyboardNameAlt); @@ -385,9 +380,6 @@ void Globals::SetBaseKeyboardFlags(char *baseKeyboard, BOOL simulateAltGr, BOOL be changed until Keyman is restarted. */ BOOL Globals::InitSettings() { - /* Check for common core vs windows core */ - f_CoreIntegration = Reg_GetDebugFlag(REGSZ_Flag_UseKeymanCore, TRUE); - SendDebugMessageFormat(0, sdmAIDefault, 0, "Globals::InitSettings - Coreintegration set in '" REGSZ_Flag_UseKeymanCore "' to %x", f_CoreIntegration); f_vk_prefix = _VK_PREFIX_DEFAULT; RegistryReadOnly reg(HKEY_LOCAL_MACHINE); if (reg.OpenKeyReadOnly(REGSZ_KeymanLM) && diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index 3e5edcff5b..96deb57590 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -19,10 +19,8 @@ */ #include "pch.h" -void IntSaveKeyboardOption(LPCSTR key, LPINTKEYBOARDINFO kp, int nStoreToSave); -BOOL IntLoadKeyboardOptions(LPCSTR key, LPINTKEYBOARDINFO kp); -BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* const state); -void IntSaveKeyboardOptionREGCore(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value); +BOOL IntLoadKeyboardOptionsRegistrytoCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* const state); +void IntSaveKeyboardOptionCoretoRegistry(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value); static km_kbp_cp* CloneKMKBPCP(const km_kbp_cp* cp) { LPCWSTR buf = reinterpret_cast(cp); @@ -37,123 +35,12 @@ static km_kbp_cp* CloneKMKBPCPFromWSTR(LPWSTR buf) { return clone; } -void LoadKeyboardOptions(LPINTKEYBOARDINFO kp) -{ // I3594 - IntLoadKeyboardOptions(REGSZ_KeyboardOptions, kp); -} - -void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp) +void SaveKeyboardOptionCoretoRegistry(LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value) { - if(!DebugAssert(!Globals::get_CoreIntegration(), "LoadSharedKeyboardOptions: Error called in core integration mode")) { - return; - } - // Called when another thread changes keyboard options and we are sharing keyboard settings - assert(kp != NULL); - assert(kp->Keyboard != NULL); - - if(kp->KeyboardOptions != NULL) FreeKeyboardOptions(kp); - - IntLoadKeyboardOptions(REGSZ_SharedKeyboardOptions, kp); + IntSaveKeyboardOptionCoretoRegistry(REGSZ_KeyboardOptions, kp, key, value); } -void FreeKeyboardOptions(LPINTKEYBOARDINFO kp) -{ - // This is a cleanup routine; we don't want to precondition all calls to it - // so we do not assert - if (kp == NULL || kp->Keyboard == NULL || kp->KeyboardOptions == NULL) - return; - - for(DWORD i = 0; i < kp->Keyboard->cxStoreArray; i++) - if(kp->KeyboardOptions[i].Value) - { - kp->Keyboard->dpStoreArray[i].dpString = kp->KeyboardOptions[i].OriginalStore; - delete kp->KeyboardOptions[i].Value; - } - delete kp->KeyboardOptions; - kp->KeyboardOptions = NULL; -} - -void SetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSet, int nStoreToRead) -{ - if (!DebugAssert(!Globals::get_CoreIntegration(), "SetKeyboardOption: Error called in core integration mode")) { - return; - } - assert(kp != NULL); - assert(kp->Keyboard != NULL); - assert(kp->KeyboardOptions != NULL); - assert(nStoreToSet >= 0); - assert(nStoreToSet < (int) kp->Keyboard->cxStoreArray); - assert(nStoreToRead >= 0); - assert(nStoreToRead < (int) kp->Keyboard->cxStoreArray); - - LPSTORE sp = &kp->Keyboard->dpStoreArray[nStoreToRead]; - if(kp->KeyboardOptions[nStoreToSet].Value) - { - delete kp->KeyboardOptions[nStoreToSet].Value; - } - else - { - kp->KeyboardOptions[nStoreToSet].OriginalStore = kp->Keyboard->dpStoreArray[nStoreToSet].dpString; - } - - kp->KeyboardOptions[nStoreToSet].Value = new WCHAR[wcslen(sp->dpString)+1]; - wcscpy_s(kp->KeyboardOptions[nStoreToSet].Value, wcslen(sp->dpString)+1, sp->dpString); - kp->Keyboard->dpStoreArray[nStoreToSet].dpString = kp->KeyboardOptions[nStoreToSet].Value; -} - -void ResetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToReset) -{ - if (!DebugAssert(!Globals::get_CoreIntegration(), "ResetKeyboardOption: Error called in core integration mode")) { - return; - } - assert(kp != NULL); - assert(kp->Keyboard != NULL); - assert(kp->KeyboardOptions != NULL); - assert(nStoreToReset >= 0); - assert(nStoreToReset < (int) kp->Keyboard->cxStoreArray); - - if(kp->KeyboardOptions[nStoreToReset].Value) - { - kp->Keyboard->dpStoreArray[nStoreToReset].dpString = kp->KeyboardOptions[nStoreToReset].OriginalStore; - delete kp->KeyboardOptions[nStoreToReset].Value; - kp->KeyboardOptions[nStoreToReset].Value = NULL; - - if(kp->Keyboard->dpStoreArray[nStoreToReset].dpName == NULL) return; - - RegistryReadOnly r(HKEY_CURRENT_USER); - if(r.OpenKeyReadOnly(REGSZ_KeymanActiveKeyboards) && r.OpenKeyReadOnly(kp->Name) && r.OpenKeyReadOnly(REGSZ_KeyboardOptions)) - { - if(r.ValueExists(kp->Keyboard->dpStoreArray[nStoreToReset].dpName)) - { - WCHAR val[256]; - if(!r.ReadString(kp->Keyboard->dpStoreArray[nStoreToReset].dpName, val, sizeof(val) / sizeof(val[0]))) return; - if(!val[0]) return; - val[255] = 0; - kp->KeyboardOptions[nStoreToReset].Value = new WCHAR[wcslen(val)+1]; - wcscpy_s(kp->KeyboardOptions[nStoreToReset].Value, wcslen(val)+1, val); - - kp->KeyboardOptions[nStoreToReset].OriginalStore = kp->Keyboard->dpStoreArray[nStoreToReset].dpString; - kp->Keyboard->dpStoreArray[nStoreToReset].dpString = kp->KeyboardOptions[nStoreToReset].Value; - } - } - } -} - - -void SaveKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSave) -{ - if (!DebugAssert(!Globals::get_CoreIntegration(), "SaveKeyboardOption: Error called in core integration mode")) { - return; - } - IntSaveKeyboardOption(REGSZ_KeyboardOptions, kp, nStoreToSave); -} - -void SaveKeyboardOptionREGCore(LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value) -{ - IntSaveKeyboardOptionREGCore(REGSZ_KeyboardOptions, kp, key, value); -} - -void IntSaveKeyboardOptionREGCore(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value) +void IntSaveKeyboardOptionCoretoRegistry(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value) { assert(REGKey != NULL); assert(kp != NULL); @@ -167,73 +54,13 @@ void IntSaveKeyboardOptionREGCore(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR k } } -BOOL IntLoadKeyboardOptions(LPCSTR key, LPINTKEYBOARDINFO kp) +void LoadKeyboardOptionsRegistrytoCore(LPINTKEYBOARDINFO kp, km_kbp_state* const state) { - assert(key != NULL); - assert(kp != NULL); - assert(kp->Keyboard != NULL); - assert(kp->KeyboardOptions == NULL); - - kp->KeyboardOptions = new INTKEYBOARDOPTIONS[kp->Keyboard->cxStoreArray]; - memset(kp->KeyboardOptions, 0, sizeof(INTKEYBOARDOPTIONS) * kp->Keyboard->cxStoreArray); - RegistryReadOnly r(HKEY_CURRENT_USER); - if(r.OpenKeyReadOnly(REGSZ_KeymanActiveKeyboards) && r.OpenKeyReadOnly(kp->Name) && r.OpenKeyReadOnly(key)) - { - WCHAR buf[256]; - int n = 0; - while(r.GetValueNames(buf, sizeof(buf) / sizeof(buf[0]), n)) - { - buf[255] = 0; - WCHAR val[256]; - if(r.ReadString(buf, val, sizeof(val) / sizeof(val[0])) && val[0]) - { - val[255] = 0; - for(DWORD i = 0; i < kp->Keyboard->cxStoreArray; i++) - { - if(kp->Keyboard->dpStoreArray[i].dpName != NULL && _wcsicmp(kp->Keyboard->dpStoreArray[i].dpName, buf) == 0) - { - kp->KeyboardOptions[i].Value = new WCHAR[wcslen(val)+1]; - wcscpy_s(kp->KeyboardOptions[i].Value, wcslen(val)+1, val); - - kp->KeyboardOptions[i].OriginalStore = kp->Keyboard->dpStoreArray[i].dpString; - kp->Keyboard->dpStoreArray[i].dpString = kp->KeyboardOptions[i].Value; - - break; - } - } - } - n++; - } - return TRUE; - } - return FALSE; + SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadKeyboardOptionsRegistrytoCore: Enter"); + IntLoadKeyboardOptionsRegistrytoCore(REGSZ_KeyboardOptions, kp, state); } -void IntSaveKeyboardOption(LPCSTR key, LPINTKEYBOARDINFO kp, int nStoreToSave) -{ - assert(key != NULL); - assert(kp != NULL); - assert(kp->Keyboard != NULL); - assert(kp->KeyboardOptions != NULL); - assert(nStoreToSave >= 0); - assert(nStoreToSave < (int) kp->Keyboard->cxStoreArray); - - if(kp->Keyboard->dpStoreArray[nStoreToSave].dpName == NULL) return; - - RegistryFullAccess r(HKEY_CURRENT_USER); - if(r.OpenKey(REGSZ_KeymanActiveKeyboards, TRUE) && r.OpenKey(kp->Name, TRUE) && r.OpenKey(key, TRUE)) - { - r.WriteString(kp->Keyboard->dpStoreArray[nStoreToSave].dpName, kp->Keyboard->dpStoreArray[nStoreToSave].dpString); - } -} - -void LoadKeyboardOptionsREGCore(LPINTKEYBOARDINFO kp, km_kbp_state* const state) -{ - SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadKeyboardOptionsREGCore: Enter"); - IntLoadKeyboardOptionsCore(REGSZ_KeyboardOptions, kp, state); -} - -BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* const state) +BOOL IntLoadKeyboardOptionsRegistrytoCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* const state) { assert(key != NULL); assert(kp != NULL); @@ -243,7 +70,7 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* km_kbp_status err_status = km_kbp_keyboard_get_attrs(kp->lpCoreKeyboard, &keyboardAttrs); if (err_status != KM_KBP_STATUS_OK) { SendDebugMessageFormat( - 0, sdmKeyboard, 0, "LoadKeyboardOptionsREGCore: km_kbp_keyboard_get_attrs failed with error status [%d]", err_status); + 0, sdmKeyboard, 0, "LoadKeyboardOptionsRegistrytoCore: km_kbp_keyboard_get_attrs failed with error status [%d]", err_status); return FALSE; } @@ -275,7 +102,7 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* err_status = km_kbp_state_options_update(state, keyboardOpts); if (err_status != KM_KBP_STATUS_OK) { SendDebugMessageFormat( - 0, sdmKeyboard, 0, "LoadKeyboardOptionsREGCore: km_kbp_state_options_update failed with error status [%d]", err_status); + 0, sdmKeyboard, 0, "LoadKeyboardOptionsRegistrytoCore: km_kbp_state_options_update failed with error status [%d]", err_status); } for (int i = 0; i < n; i++) { delete[] keyboardOpts[i].value; @@ -283,89 +110,3 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* delete[] keyboardOpts; return TRUE; } - -BOOL -UpdateKeyboardOptionsCore( - km_kbp_state* const lpCoreKeyboardState, - km_kbp_option_item *lpCoreKeyboardOptions) { - - int listSize = (int)km_kbp_options_list_size(lpCoreKeyboardOptions); - // Create a option list based on this size look up each key and store the return value in it. - // then at the end return this options list. - BOOL changed = FALSE; - km_kbp_cp const* retValue = nullptr; - for (int i = 0; i < listSize; i++) { - km_kbp_status err_status = km_kbp_state_option_lookup(lpCoreKeyboardState, lpCoreKeyboardOptions[i].scope, lpCoreKeyboardOptions[i].key, - &retValue); - if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat( - 0, sdmKeyboard, 0, "UpdateKeyboardOptionsCore: km_kbp_state_option_lookup failed with error status [%d]", err_status); - continue; - } - // compare to see if changed - if (wcscmp(reinterpret_cast(retValue), reinterpret_cast(lpCoreKeyboardOptions[i].value)) != 0) { - delete lpCoreKeyboardOptions[i].value; - lpCoreKeyboardOptions[i].value = CloneKMKBPCP(retValue); - changed = TRUE; - } - } - return changed; -} - -km_kbp_option_item* -SaveKeyboardOptionsCore(LPINTKEYBOARDINFO kp) { - - // Get the list of default options to determine size of list - const km_kbp_keyboard_attrs* keyboardAttrs; - km_kbp_status err_status = km_kbp_keyboard_get_attrs(kp->lpCoreKeyboard, &keyboardAttrs); - if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat( - 0, sdmKeyboard, 0, "SaveKeyboardOptionsCore: km_kbp_keyboard_get_attrs failed with error status [%d]", err_status); - return nullptr; - } - int listSize = (int)km_kbp_options_list_size(keyboardAttrs->default_options); - km_kbp_option_item* savedKeyboardOpts = new km_kbp_option_item[listSize + 1]; - km_kbp_cp const* retValue = nullptr; - - km_kbp_option_item const* kbDefaultOpts = keyboardAttrs->default_options; - for (int i = 0; i < listSize; i++, ++kbDefaultOpts) { - if (kbDefaultOpts->scope != KM_KBP_OPT_KEYBOARD) - continue; - err_status = - km_kbp_state_option_lookup(kp->lpCoreKeyboardState, KM_KBP_OPT_KEYBOARD, kbDefaultOpts->key, &retValue); - if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat( - 0, sdmKeyboard, 0, "SaveKeyboardOptionsCore: km_kbp_state_option_lookup failed with error status [%d]", err_status); - continue; - } - savedKeyboardOpts[i].key = CloneKMKBPCP(kbDefaultOpts->key); - savedKeyboardOpts[i].value = CloneKMKBPCP(retValue); - savedKeyboardOpts[i].scope = KM_KBP_OPT_KEYBOARD; - } - savedKeyboardOpts[listSize] = KM_KBP_OPTIONS_END; - return savedKeyboardOpts; -} - -BOOL -RestoreKeyboardOptionsCore( - km_kbp_state* const lpCoreKeyboardState, - km_kbp_option_item* lpCoreKeyboardOptions) { - km_kbp_status err_status = km_kbp_state_options_update(lpCoreKeyboardState, lpCoreKeyboardOptions); - if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat( - 0, sdmKeyboard, 0, "RestoreKeyboardOptionsCore: km_kbp_state_options_update failed with error status [%d]", err_status); - return FALSE; - } - return TRUE; -} - -void -DisposeKeyboardOptionsCore(km_kbp_option_item** lpCoreKeyboardOptions) { - size_t listSize = km_kbp_options_list_size(*lpCoreKeyboardOptions); - for (int i = 0; i < (int)listSize; i++) { - delete[] (*lpCoreKeyboardOptions)[i].key; - delete[] (*lpCoreKeyboardOptions)[i].value; - } - delete[] *lpCoreKeyboardOptions; - *lpCoreKeyboardOptions = NULL; -} diff --git a/windows/src/engine/keyman32/keyboardoptions.h b/windows/src/engine/keyman32/keyboardoptions.h index cef9ae6df1..f55b0bcc77 100644 --- a/windows/src/engine/keyman32/keyboardoptions.h +++ b/windows/src/engine/keyman32/keyboardoptions.h @@ -16,44 +16,6 @@ History: 25 May 2010 - mcdurdin - I1632 - Keyboard Options */ -void LoadKeyboardOptions(LPINTKEYBOARDINFO kp); -void FreeKeyboardOptions(LPINTKEYBOARDINFO kp); -void SetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSet, int nStoreToRead); -void ResetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToReset); -void SaveKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSave); -void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp); -/** - * Updates the supplied Keyboard processor options list from the keyboard processor pointed - * to by the state pointer. - * - * @param lpCoreKeyboardState The core keyboardprocessor state which has the source options - * @param[in,out] lpCoreKeyboardOptions The core keyboard options to be updated - * @return BOOL True if one or more options were updated - */ -BOOL UpdateKeyboardOptionsCore(km_kbp_state* const lpCoreKeyboardState, km_kbp_option_item *lpCoreKeyboardOptions); - -/** - * Returns a copy of the core keyboard processors current keyboard options - * The caller is responsible for freeing the returned km_kbp_option_item's list. - * - * @param kp A pointer to the keyboard info object that contains the - * keyboardprocessor state and keyboard for the source options list. - * - * @return km_kbp_option_item* The copy of the options list or NULL if copy failed - */ -km_kbp_option_item* SaveKeyboardOptionsCore(LPINTKEYBOARDINFO kp); - -/** - * Restore the core keyboard processor options to the supplied keyboard - * list of `km_kbp_option_item`s - * - * @param lpCoreKeyboardState The state pointer for the keyboard processor - * @param lpCoreKeyboardOptions The list of `km_kbp_option_item`s to restore - * - * return BOOL TRUE when the call to update keyboard processor was successful - */ -BOOL RestoreKeyboardOptionsCore(km_kbp_state* const lpCoreKeyboardState, km_kbp_option_item* lpCoreKeyboardOptions); - /* Common core integration functions */ /** @@ -62,7 +24,7 @@ BOOL RestoreKeyboardOptionsCore(km_kbp_state* const lpCoreKeyboardState, km_kbp_ * @param kp keyboard info object with options to be updated * @param state core keyboard state used to update keyboard options */ -void LoadKeyboardOptionsREGCore(LPINTKEYBOARDINFO kp, km_kbp_state* state); +void LoadKeyboardOptionsRegistrytoCore(LPINTKEYBOARDINFO kp, km_kbp_state* state); /** * Saves the keyboard option to the windows registry @@ -71,12 +33,6 @@ void LoadKeyboardOptionsREGCore(LPINTKEYBOARDINFO kp, km_kbp_state* state); * @param key keyboard key to save * @param value keyboard option value to save */ -void SaveKeyboardOptionREGCore(LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value); +void SaveKeyboardOptionCoretoRegistry(LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value); + -/** - * Free the allocated resources belonging to a key_kbp_option_items object - * that was created on the heap most likely using SaveKeyboardOptionREGCore - * - * @param lpCoreKeyboardOptions keyboard options items to be freed - */ -void DisposeKeyboardOptionsCore(km_kbp_option_item** lpCoreKeyboardOptions); diff --git a/windows/src/engine/keyman32/keyman-engine.vcxproj b/windows/src/engine/keyman32/keyman-engine.vcxproj index 6869117fd9..d2e78ef7e4 100644 --- a/windows/src/engine/keyman32/keyman-engine.vcxproj +++ b/windows/src/engine/keyman32/keyman-engine.vcxproj @@ -59,7 +59,7 @@ $(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\src;$(ProjectDir)..\..\..\..\core\build\rust\x86\$(Configuration);$(LibraryPath) - $(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\include;$(IncludePath) + $(ProjectDir)..\..\..\..\common\include;$(ProjectDir)..\..\..\..\core\include;$(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\include;$(IncludePath) @@ -186,12 +186,6 @@ - - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) @@ -403,4 +397,4 @@ - \ No newline at end of file + diff --git a/windows/src/engine/keyman32/keyman-engine.vcxproj.filters b/windows/src/engine/keyman32/keyman-engine.vcxproj.filters index 7cd4d906d1..c0eab08097 100644 --- a/windows/src/engine/keyman32/keyman-engine.vcxproj.filters +++ b/windows/src/engine/keyman32/keyman-engine.vcxproj.filters @@ -15,9 +15,6 @@ - - Source Files - Source Files diff --git a/windows/src/engine/keyman32/keyman32.cpp b/windows/src/engine/keyman32/keyman32.cpp index ee6cd754b8..86eda219a2 100644 --- a/windows/src/engine/keyman32/keyman32.cpp +++ b/windows/src/engine/keyman32/keyman32.cpp @@ -492,7 +492,6 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_Exit(void) *Globals::Keyman_Shutdown() = TRUE; ReleaseKeyboards(TRUE); - Addin_Release(); if(!Globals::get_Keyman_Initialised()) { @@ -529,138 +528,6 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_RestartEngine() return TRUE; } -/*******************************************************************************************/ -/* */ -/* Keyman Keyboard Override Functions */ -/* */ -/*******************************************************************************************/ - -extern "C" BOOL _declspec(dllexport) WINAPI Keyman_StopForcingKeyboard(); - -void RefreshPreservedKeys(BOOL Activating); - -extern "C" BOOL _declspec(dllexport) WINAPI Keyman_ForceKeyboard(PCSTR FileName) -{ - SendDebugMessageFormat(0,sdmGlobal,0,"Keyman_ForceKeyboard: ENTER %s", FileName); - - Keyman_StopForcingKeyboard(); // 7.0.219.0 - - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - - strncpy(_td->ForceFileName, FileName, MAX_PATH - 1); - _td->ForceFileName[MAX_PATH-1] = 0; - - if(_td->lpActiveKeyboard) - { - DeactivateDLLs(_td->lpActiveKeyboard); - } - - _td->lpActiveKeyboard = new INTKEYBOARDINFO; - memset(_td->lpActiveKeyboard, 0, sizeof(INTKEYBOARDINFO)); // I2437 - Crash unloading keyboard due to keyboard options not init - /*_td->lpActiveKeyboard->KeymanID = 0; - _td->lpActiveKeyboard->nIMDLLs = 0; - _td->lpActiveKeyboard->IMDLLs = NULL; - _td->lpActiveKeyboard->KeyboardOptions = NULL;*/ - _splitpath_s(FileName, NULL, 0, NULL, 0, _td->lpActiveKeyboard->Name, sizeof(_td->lpActiveKeyboard->Name), NULL, 0); - // TODO: 5442 - remove if/ else as there will no longer be the old LoadKeyboard option - if (Globals::get_CoreIntegration()) { - PWCHAR keyboardPath = strtowstr(_td->ForceFileName); - km_kbp_status err_status = km_kbp_keyboard_load(keyboardPath, &_td->lpActiveKeyboard->lpCoreKeyboard); - if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard Core: km_kbp_keyboard_load failed for %ls with error status [%d]", keyboardPath, err_status); // TODO: 5442 - remove word Core - delete keyboardPath; - return FALSE; - } - delete keyboardPath; - SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard Core: %s OK", FileName); // TODO: 5442 - remove word Core - - km_kbp_option_item *core_environment = nullptr; - - if(!SetupCoreEnvironment(&core_environment)) { - SendDebugMessageFormat(0, sdmLoad, 0, "Keyman_ForceKeyboard Core: Unable to set environment options for keyboard %s", FileName); // TODO: 5442 - remove word Core - return FALSE; - } - - err_status = - km_kbp_state_create(_td->lpActiveKeyboard->lpCoreKeyboard, core_environment, &_td->lpActiveKeyboard->lpCoreKeyboardState); - - DeleteCoreEnvironment(core_environment); - - if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat( - 0, sdmGlobal, 0, "Keyman_ForceKeyboard Core: km_kbp_state_create failed with error status [%d]", err_status); - // Dispose of the keyboard to leave us in a consitent state - ReleaseKeyboardMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboard); - return FALSE; - } - - ResetCapsLock(); - err_status = km_kbp_keyboard_get_imx_list(_td->lpActiveKeyboard->lpCoreKeyboard, &_td->lpActiveKeyboard->lpIMXList); - if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat(0, sdmLoad, 0, "Keyman_ForceKeyboard Core: km_kbp_keyboard_get_imx_list failed with error status [%d]", err_status); - // Dispose of the keyboard to leave us in a consistent state - ReleaseKeyboardMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboard); - return FALSE; - } - - LoadDLLsCore(_td->lpActiveKeyboard); - ActivateDLLs(_td->lpActiveKeyboard); - LoadKeyboardOptionsREGCore(_td->lpActiveKeyboard, _td->lpActiveKeyboard->lpCoreKeyboardState); - RefreshPreservedKeys(TRUE); - return TRUE; - } else { - if (LoadKeyboard(_td->ForceFileName, &_td->lpActiveKeyboard->Keyboard)) { - SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard: %s OK", FileName); - ResetCapsLock(); - LoadDLLs(_td->lpActiveKeyboard); - ActivateDLLs(_td->lpActiveKeyboard); - LoadKeyboardOptions(_td->lpActiveKeyboard); // I2437 - Crash unloading keyboard due to keyboard options not set - RefreshPreservedKeys(TRUE); - return TRUE; - } - } - SendDebugMessageFormat(0,sdmGlobal,0,"Keyman_ForceKeyboard: %s FAIL", FileName); - - delete _td->lpActiveKeyboard; - _td->lpActiveKeyboard = NULL; - - _td->ForceFileName[0] = 0; - return FALSE; -} - -extern "C" BOOL _declspec(dllexport) WINAPI Keyman_StopForcingKeyboard() -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) - { - SetLastError(ERROR_KEYMAN_THREAD_DATA_NOT_READY); // I3173 // I3525 - return FALSE; - } - - if(!_td->lpActiveKeyboard) - { - SetLastError(ERROR_KEYMAN_KEYBOARD_NOT_ACTIVE); // I3173 // I3525 - return FALSE; - } - SendDebugMessageFormat(0,sdmGlobal,0,"Keyman_StopForcingKeyboard"); - if(_td->ForceFileName[0]) - { - SendDebugMessageFormat(0,sdmGlobal,0,"Keyman_StopForcingKeyboard: Stopping forcing"); - if(!DeactivateDLLs(_td->lpActiveKeyboard)) return FALSE; // I3173 // I3525 - if(!UnloadDLLs(_td->lpActiveKeyboard)) return FALSE; // I3173 // I3525 - _td->ForceFileName[0] = 0; - FreeKeyboardOptions(_td->lpActiveKeyboard); - ReleaseKeyboardMemory(_td->lpActiveKeyboard->Keyboard); - ReleaseStateMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboardState); - ReleaseKeyboardMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboard); - RefreshPreservedKeys(FALSE); - delete _td->lpActiveKeyboard; - _td->lpActiveKeyboard = NULL; - } - return TRUE; -} - //--------------------------------------------------------------------------------------------------------- // // Utility guff functions @@ -936,8 +803,6 @@ void RefreshKeyboards(BOOL Initialising) // Can happen when multiple top-level windows for one process - Addin_Refresh(); - SendDebugMessageFormat(0,sdmGlobal,0,"---ENTER RefreshKeyboards---"); //FInRefreshKeyboards = TRUE; @@ -1006,8 +871,6 @@ void RefreshKeyboards(BOOL Initialising) RefreshKeyboardProfiles(kp, FALSE); // Read standard profiles RefreshKeyboardProfiles(kp, TRUE); // Read transient profiles - kp->Keyboard = NULL; - SendDebugMessageFormat(0,sdmGlobal,0,"RefreshKeyboards: Added keyboard %s, %d", kp->Name, kp->KeymanID); i++; @@ -1035,13 +898,15 @@ void ReleaseKeyboards(BOOL Lock) if(!_td || !_td->lpKeyboards) return; - if(Lock) if(_td->lpActiveKeyboard && !_td->ForceFileName[0]) DeactivateDLLs(_td->lpActiveKeyboard); + if(Lock) { + if(_td->lpActiveKeyboard) { + DeactivateDLLs(_td->lpActiveKeyboard); + } + } for(int i = 0; i < _td->nKeyboards; i++) { if(Lock) UnloadDLLs(&_td->lpKeyboards[i]); - FreeKeyboardOptions(&_td->lpKeyboards[i]); - ReleaseKeyboardMemory(_td->lpKeyboards[i].Keyboard); ReleaseStateMemoryCore(&_td->lpKeyboards[i].lpCoreKeyboardState); ReleaseKeyboardMemoryCore(&_td->lpKeyboards[i].lpCoreKeyboard); if(_td->lpKeyboards[i].Profiles) delete _td->lpKeyboards[i].Profiles; // I3581 @@ -1051,7 +916,6 @@ void ReleaseKeyboards(BOOL Lock) delete _td->lpKeyboards; _td->lpKeyboards = NULL; - if(!_td->ForceFileName[0]) _td->lpActiveKeyboard = NULL; } /** diff --git a/windows/src/engine/keyman32/keyman32.def b/windows/src/engine/keyman32/keyman32.def index 84f0f24a91..2fa0e767c5 100644 --- a/windows/src/engine/keyman32/keyman32.def +++ b/windows/src/engine/keyman32/keyman32.def @@ -4,8 +4,6 @@ EXPORTS Keyman_GetInitialised Keyman_Initialise Keyman_Exit - Keyman_ForceKeyboard - Keyman_StopForcingKeyboard Keyman_GetLastActiveWindow Keyman_GetLastFocusWindow KMSetOutput diff --git a/windows/src/engine/keyman32/keyman32.vcxproj b/windows/src/engine/keyman32/keyman32.vcxproj index 0d78d2c292..670df3c1d4 100644 --- a/windows/src/engine/keyman32/keyman32.vcxproj +++ b/windows/src/engine/keyman32/keyman32.vcxproj @@ -176,12 +176,6 @@ - - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) @@ -362,7 +356,6 @@ - diff --git a/windows/src/engine/keyman32/keyman32.vcxproj.filters b/windows/src/engine/keyman32/keyman32.vcxproj.filters index 8995c39a93..dcf5f5d4c5 100644 --- a/windows/src/engine/keyman32/keyman32.vcxproj.filters +++ b/windows/src/engine/keyman32/keyman32.vcxproj.filters @@ -15,9 +15,6 @@ - - Source Files - Source Files @@ -162,9 +159,6 @@ - - Header Files - Header Files diff --git a/windows/src/engine/keyman32/keymanengine.h b/windows/src/engine/keyman32/keymanengine.h index d56bcc1e3e..f40aeaf372 100644 --- a/windows/src/engine/keyman32/keymanengine.h +++ b/windows/src/engine/keyman32/keymanengine.h @@ -81,11 +81,9 @@ typedef struct tagINTKEYBOARDINFO DWORD __filler_Hotkey; DWORD __filler; // makes same as KEYBOARDINFO // I4462 char Name[256]; - LPKEYBOARD Keyboard; DWORD nIMDLLs; LPIMDLL IMDLLs; int __filler2; // makes same as KEYBOARDINFO - LPINTKEYBOARDOPTIONS KeyboardOptions; int nProfiles; LPINTKEYBOARDPROFILE Profiles; km_kbp_keyboard* lpCoreKeyboard; @@ -105,17 +103,11 @@ typedef struct tagKMSTATE { BOOL NoMatches; MSG msg; - // TODO: 5442 will remove these once windows core is deprecated - BOOL StopOutput; - int LoopTimes; - // TODO: 5442 WORD vkey; // I934 WCHAR charCode; // I4582 BOOL windowunicode; // I4287 BOOL isDown; - LPKEYBOARD lpkb; km_kbp_keyboard* lpCoreKb; // future use with IMDLL - LPGROUP startgroup; // TODO: 5442 will remove this once windows core is deprecated } KMSTATE; // I3616 @@ -129,7 +121,6 @@ LRESULT CALLBACK kmnLowLevelKeyboardProc( // I4124 _In_ LPARAM lParam ); -BOOL ReleaseKeyboardMemory(LPKEYBOARD kbd); BOOL ReleaseStateMemoryCore(km_kbp_state** state); BOOL ReleaseKeyboardMemoryCore(km_kbp_keyboard** kbd); @@ -230,8 +221,6 @@ DWORD HKLToKeyboardID(HKL hkl); WORD HKLToLanguageID(HKL hkl); WORD HKLToLayoutNumber(HKL hkl); WORD HKLToLayoutID(HKL hkl); -DWORD EthnologueCodeToKeymanID(DWORD EthCode); -DWORD EthnologueStringCodeToDWord(PWSTR EthCode); PWSTR GetSystemStore(LPKEYBOARD kb, DWORD SystemID); @@ -254,7 +243,6 @@ void keybd_shift(LPINPUT pInputs, int* n, BOOL isReset, LPBYTE const kbd); #include "keystate.h" #include "calldll.h" -#include "addins.h" #include "keymancontrol.h" #include "keyboardoptions.h" #include "kmprocessactions.h" diff --git a/windows/src/engine/keyman32/kmhook_getmessage.cpp b/windows/src/engine/keyman32/kmhook_getmessage.cpp index f6a56340f9..562c455abb 100644 --- a/windows/src/engine/keyman32/kmhook_getmessage.cpp +++ b/windows/src/engine/keyman32/kmhook_getmessage.cpp @@ -248,19 +248,6 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam) return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); } - /* - Handle WM_UNICHAR messages for RichEdit control -- should we test RichEdit version? - */ - - if(mp->message == WM_UNICHAR && Addin_ShouldProcessUnichar(mp->hwnd)) - { - if(Addin_ProcessUnichar(mp->hwnd, (DWORD) mp->wParam)) - { - mp->message = 0; - return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); - } - } - /* Handle wm_keyman_control_internal messages */ @@ -271,7 +258,6 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam) if(_td->lpActiveKeyboard) { - _td->state.lpkb = _td->lpActiveKeyboard->Keyboard; _td->state.lpCoreKb = _td->lpActiveKeyboard->lpCoreKeyboard; } // I4412 @@ -297,20 +283,17 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam) { if(_td->app) { - BOOL isUsingCoreProcessor = Globals::get_CoreIntegration(); - - if (isUsingCoreProcessor) { - // Call the core keyboard processor to process the queued actions - if (!_td->lpActiveKeyboard) { - return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); - } - if (KM_KBP_STATUS_OK != km_kbp_process_queued_actions(_td->lpActiveKeyboard->lpCoreKeyboardState)) { - SendDebugMessageFormat(0, sdmGlobal, 0, "_kmnGetMessageProc wm_keymanim_close process event fail"); - return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); - } - BOOL emitKeyStroke; - ProcessActions(&emitKeyStroke); + // Call the core keyboard processor to process the queued actions + if (!_td->lpActiveKeyboard) { + return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); } + if (KM_KBP_STATUS_OK != km_kbp_process_queued_actions(_td->lpActiveKeyboard->lpCoreKeyboardState)) { + SendDebugMessageFormat(0, sdmGlobal, 0, "_kmnGetMessageProc wm_keymanim_close process event fail"); + return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); + } + BOOL emitKeyStroke; + ProcessActions(&emitKeyStroke); + _td->app->SetCurrentShiftState(Globals::get_ShiftState()); _td->app->SendActions(); } @@ -372,7 +355,6 @@ void ProcessWMKeyman(HWND hwnd, WPARAM wParam, LPARAM lParam) hwnd = GetFocus(); if(_td->lpActiveKeyboard) { - _td->state.lpkb = _td->lpActiveKeyboard->Keyboard; _td->state.lpCoreKb = _td->lpActiveKeyboard->lpCoreKeyboard; } @@ -384,7 +366,6 @@ void ProcessWMKeyman(HWND hwnd, WPARAM wParam, LPARAM lParam) { if(_td->app) _td->app->ResetQueue(); GetCapsAndNumlockState(); - Addin_FocusChanged(hwnd); UpdateActiveWindows(); } } diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index 7faac081c2..64a6a48e98 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -119,7 +119,6 @@ Process_Event_Core(PKEYMAN64THREADDATA _td) { return TRUE; } - /* * BOOL ProcessHook(); * @@ -138,10 +137,7 @@ BOOL ProcessHook() PKEYMAN64THREADDATA _td = ThreadGlobals(); if(!_td) return FALSE; - LPGROUP gp = _td->state.startgroup; - fOutputKeystroke = FALSE; // TODO: 5442 no longer needs to be global once we use core processor - BOOL isUsingCoreProcessor = Globals::get_CoreIntegration(); // // If we are running in the debugger, don't do a second run through // @@ -160,44 +156,28 @@ BOOL ProcessHook() Debug_VirtualKey(_td->state.vkey), getcontext_debug()); } - AIDEBUGKEYINFO keyinfo; - keyinfo.shiftFlags = Globals::get_ShiftState(); - keyinfo.VirtualKey = _td->state.vkey; - keyinfo.Character = _td->state.charCode; - keyinfo.DeadKeyCharacter = 0; // I4582 - keyinfo.IsUp = !_td->state.isDown; - if(_td->app->IsUnicode()) - _td->app->QueueDebugInformation(QID_BEGIN_UNICODE, NULL, NULL, NULL, NULL, (DWORD_PTR) &keyinfo); - else - _td->app->QueueDebugInformation(QID_BEGIN_ANSI, NULL, NULL, NULL, NULL, (DWORD_PTR) &keyinfo); } - if (isUsingCoreProcessor) { // TODO: 5442 Note: Nested if will be reduced once using core only - // For applications not using the TSF kmtip calls this function twice for each keystroke, - // first to determine if we are doing processing work (TIPFUpdateable == FALSE), - // if we say yes it will call a second time to actually do the work. - // We call the core process event only once and use the core's queued actions - // on the second pass. - // For the TSF in most cases kmtip (except OnPreservedKey) will not call the non-updateable test parse. - // Therfore the core process event will need to be called before processing the actions. + // For applications not using the TSF kmtip calls this function twice for each keystroke, + // first to determine if we are doing processing work (TIPFUpdateable == FALSE), + // if we say yes it will call a second time to actually do the work. + // We call the core process event only once and use the core's queued actions + // on the second pass. + // For the TSF in most cases kmtip (except OnPreservedKey) will not call the non-updateable test parse. + // Therfore the core process event will need to be called before processing the actions. - // CoreProcessEventRun would be a sufficient test however testing TIPFUpdateable defines - // the status of the keystroke processing more precisely. - if (!_td->TIPFUpdateable || !_td->CoreProcessEventRun) { - if (!Process_Event_Core(_td)) { - return FALSE; - } + // CoreProcessEventRun would be a sufficient test however testing TIPFUpdateable defines + // the status of the keystroke processing more precisely. + if (!_td->TIPFUpdateable || !_td->CoreProcessEventRun) { + if (!Process_Event_Core(_td)) { + return FALSE; } - - if (!_td->TIPFUpdateable) { - ProcessActionsNonUpdatableParse(&fOutputKeystroke); - } else { - ProcessActions(&fOutputKeystroke); - } - } - else { - ProcessGroup(gp); // TODO: 5442 remove + + if (!_td->TIPFUpdateable) { + ProcessActionsNonUpdatableParse(&fOutputKeystroke); + } else { + ProcessActions(&fOutputKeystroke); } if (fOutputKeystroke && !_td->app->IsQueueEmpty()) { @@ -256,671 +236,9 @@ BOOL ProcessHook() // PWSTR contextBuf = _td->app->ContextBufMax(MAXCONTEXT); // SendDebugMessageFormat(0, sdmAIDefault, 0, "Kmprocess::ProcessHook After cxt=%s", Debug_UnicodeString(contextBuf, 1)); - _td->app->QueueDebugInformation(QID_END, NULL, NULL, NULL, NULL, 0); return !fOutputKeystroke; } -/* -* PRIVATE BOOL ProcessGroup(LPGROUP gp); -* -* Parameters: gp Pointer to group to process inside -* -* Returns: TRUE if messages are to be sent, -* and FALSE if no messages are to be sent. -* -* Called by: ProcessHook, recursive inside groups -* -* ProcessKey is where the keystroke conversion and output takes place. This routine -* has a lot of crucial code in it! -*/ - -BOOL ProcessGroup(LPGROUP gp) -{ - if (!DebugAssert(!Globals::get_CoreIntegration(), "KMPROCESS:ProcessGroup: Error called in core integration mode")) { - return FALSE; - } - DWORD i; - LPKEY kkp = NULL; - PWSTR p; - int sdmfI; - - /* - If the number of nested groups goes higher than 50, then break out - this is - a limitation of stack size. This is basically a catch-all for freaky apps that - cause message loopbacks and nasty things like that. Okay, it's really a catch all - for bugs! This means the user's system shouldn't hang. - */ - - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - - _td->app->QueueDebugInformation(QID_GROUP_ENTER, gp, NULL, NULL, NULL, 0); - - sdmfI = -1; - - for(i = 0; i < _td->state.lpkb->cxGroupArray; i++) - if(gp == &_td->state.lpkb->dpGroupArray[i]) - { - if(_td->state.msg.message == wm_keymankeydown && ShouldDebug(sdmKeyboard)) - SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, "Entering group %d of %d, context '%s'", i+1, _td->state.lpkb->cxGroupArray, getcontext_debug()); - sdmfI = i; - break; - } - - if(++_td->state.LoopTimes > 50) - { - if(_td->state.msg.message == wm_keymankeydown) SendDebugMessage(_td->state.msg.hwnd, sdmKeyboard, 0, "Aborting output: state.LoopTimes exceeded."); - _td->state.StopOutput = TRUE; - _td->app->QueueDebugInformation(QID_GROUP_EXIT, gp, NULL, NULL, NULL, QID_FLAG_RECURSIVE_OVERFLOW); - return FALSE; - } - - _td->state.NoMatches = TRUE; - - /* - The rule matching loop. - - This loop iterates through all the rules in the group that is currently being - processed. Each rule in a group can be of three different types: - 1. A virtual key rule, where the key to be matched is a virtual key - 2. A normal key rule (WM_CHAR), where the key to be matched is an Ascii char. - 3. A rule in a keyless group, where only the context is matched. - - The loop goes through and checks the rules like that. This loop could be optimized - with standard searching techniques - the ContextMatch may be difficult. - */ - - if(ShouldDebug(sdmKeyboard)) - SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, "state.vkey: %s shiftFlags: %x; charCode: %X", - Debug_VirtualKey(_td->state.vkey), Globals::get_ShiftState(), _td->state.charCode); // I4582 - - if(gp) - { - for(kkp = gp->dpKeyArray, i=0; i < gp->cxKeyArray; i++, kkp++) - { - if(!ContextMatch(kkp)) continue; - if(!gp->fUsingKeys) - { - if(kkp->dpContext[0] != 0) break; else continue; - } - - //if(kkp->Key == state.vkey) - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, 0, "kkp->Key: %d kkp->ShiftFlags: %x", - // kkp->Key, kkp->ShiftFlags); - - /* Keyman 6.0: support Virtual Characters */ - if(IsEquivalentShift(kkp->ShiftFlags, Globals::get_ShiftState())) - { - if(kkp->Key > VK__MAX && kkp->Key == _td->state.vkey) break; // I3438 // I4582 - else if(kkp->Key == _td->state.vkey) break; // I4169 - } - else if(kkp->ShiftFlags == 0 && kkp->Key == _td->state.charCode && _td->state.charCode != 0) break; - } - } - - if(!gp || i == gp->cxKeyArray) - { - /* - No rule was found that corresponded to the current state of the context and - keyboard. NoMatch should be checked for everything except virtual keys; and - context should also be kept. - - If the message was a virtual key, then just return without checking NoMatch. - NoMatch shouldn't be used for virtual keys because it will mean that no key - can ever get through that isn't matched - including arrows, func. keys, etc !! - Context is not kept for virtual keys being output. - */ - - if(_td->state.msg.message == wm_keymankeydown && ShouldDebug(sdmKeyboard)) SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, - "No match was found in group %d of %d", sdmfI, _td->state.lpkb->cxGroupArray); - - if(!gp || (_td->state.charCode == 0 && gp->fUsingKeys)) // I4585 - // 7.0.241.0: I1133 - Fix mismatched parentheses on state.charCode - ie. we don't want to output this letter if !gp->fUsingKeys - { - BOOL fIsBackspace = _td->state.vkey == VK_BACK && (Globals::get_ShiftState() & (LCTRLFLAG|RCTRLFLAG|LALTFLAG|RALTFLAG)) == 0; // I4128 - - if(/*_td->app->DebugControlled() &&*/ fIsBackspace) { // I4838 // I4933 - if(_td->state.msg.message == wm_keymankeydown) { // I4933 - if(!_td->app->IsLegacy()) { // I4933 - PWCHAR pdeletecontext = _td->app->ContextBuf(1); // I4933 - if(!pdeletecontext || *pdeletecontext == 0) { // I4933 - _td->app->ResetContext(); // I4933 - fOutputKeystroke = TRUE; // I4933 - return FALSE; // I4933 - } - if (Uni_IsSurrogate1(*pdeletecontext) && Uni_IsSurrogate2(*(pdeletecontext+1))) { - // 2 backspaces to delete both parts of surrogate pair - // This only needs to be done for TSF-aware apps as legacy apps - // will receive a BKSP WM_KEYDOWN event which results in deleting - // both parts in one action - _td->app->QueueAction(QIT_BACK, BK_BACKSPACE | BK_SURROGATE); - } - else { - _td->app->QueueAction(QIT_BACK, BK_BACKSPACE); - } - } - else { - _td->app->QueueAction(QIT_BACK, BK_BACKSPACE); // I4933 - } - } - } else if( (!_td->app->IsLegacy() || !fIsBackspace) && !_td->TIPFPreserved) { // I4024 // I4128 // I4287 // I4290 - SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, " ... IsLegacy = FALSE; IsTIP = TRUE"); // I4128 - if(_td->state.charCode == 0) _td->app->ResetContext(); // I3573 // I3577 // I4585 - fOutputKeystroke = TRUE; - return FALSE; - } - //fOutputKeystroke = TRUE; return FALSE; // Don't swallow keystroke // I3577 - ///SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, " ... IsLegacy = TRUE; IsTIP = TRUE"); - - /* - If the key is not a character key (white keys), or not processing, then we must init the stack - - unknown keys do things like moving position in the context, so must clear. - */ - if(fIsBackspace) // I4128 - { - /* - Must have special handling for VK_BACK: delete a character from the context stack - This only fires if the keyboard has no rule for backspace. - */ - } - else - { - //app->NoSetShift = FALSE; - - DWORD dw = _td->state.vkey; - if(dw == 0x05) dw = VK_RETURN; // I649 - VK_ENTER and K_NPENTER - - if(_td->state.msg.lParam & (1<<24)) dw |= QVK_EXTENDED; // Extended key flag // I3438 - - if(_td->state.charCode == 0) { - _td->app->ResetContext(); - } - - if(_td->TIPFPreserved) { // I4290 - if(_td->state.charCode != 0) { - _td->app->QueueAction(QIT_CHAR, _td->state.charCode); - } - } else { - if(_td->state.msg.message == wm_keymankeydown) - { - _td->app->QueueAction(QIT_VSHIFTDOWN, Globals::get_ShiftState()); // 15/05/2001 - fixing I201 -- enabled line - _td->app->QueueAction(QIT_VKEYDOWN, dw); - } - - if(_td->state.msg.message == wm_keymankeyup) { - _td->app->QueueAction(QIT_VKEYUP, dw); - _td->app->QueueAction(QIT_VSHIFTUP, Globals::get_ShiftState()); - } - } - } - } - else if (gp->dpNoMatch != NULL && *gp->dpNoMatch != 0 && _td->state.msg.message != wm_keymankeyup) - { - /* NoMatch rule found, and is a character key */ - _td->app->QueueDebugInformation(QID_NOMATCH_ENTER, gp, NULL, NULL, gp->dpNoMatch, 0); - PostString(gp->dpNoMatch, &_td->state.msg, _td->state.lpkb, NULL); - _td->app->QueueDebugInformation(QID_NOMATCH_EXIT, gp, NULL, NULL, gp->dpNoMatch, 0); - } - else if (_td->state.charCode != 0 && _td->state.charCode != 0xFFFF && _td->state.msg.message != wm_keymankeyup && gp->fUsingKeys) - { - /* No rule found, is a character key */ - // 7.0.239.0: I994 - Workaround output order issues - we will use the TSF to output all characters... - // if(app->Type1() == AIType_TIP) { fOutputKeystroke = TRUE; return FALSE; } // Don't swallow keystroke - - _td->app->QueueAction(QIT_CHAR, _td->state.charCode); - } - - _td->app->QueueDebugInformation(QID_GROUP_EXIT, gp, NULL, NULL, NULL, QID_FLAG_NOMATCH); - return TRUE; - } - - if(_td->state.msg.message == wm_keymankeyup) - return TRUE; - - SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, "match found in rule %d", i); - - _td->state.NoMatches = FALSE; - - /* - Save the context that will be used for output when the 'context' keyword is used. - For each deadkey, we need to add 2 characters; look in related stores as well... - */ - - assert(kkp != NULL); - - _td->miniContextIfLen = xstrlen(kkp->dpContext) - xstrlen_ignoreifopt(kkp->dpContext); - - // 11 Aug 2003 - I25(v6) - mcdurdin - CODE_NUL context support - if(*kkp->dpContext == UC_SENTINEL && *(kkp->dpContext+1) == CODE_NUL) - wcsncpy_s(_td->miniContext, GLOBAL_ContextStackSize, _td->app->ContextBuf(xstrlen_ignoreifopt(kkp->dpContext)-1), GLOBAL_ContextStackSize); // I3162 // I3536 - else - wcsncpy_s(_td->miniContext, GLOBAL_ContextStackSize, _td->app->ContextBuf(xstrlen_ignoreifopt(kkp->dpContext)), GLOBAL_ContextStackSize); // I3162 // I3536 - - _td->miniContext[GLOBAL_ContextStackSize-1] = 0; - - _td->app->QueueDebugInformation(QID_RULE_ENTER, gp, kkp, _td->miniContext, NULL, 0); - - /* - The next section includes several optimizations that make the code a little harder - to read, but are probably worth it in the time that they save. - - If the output string doesn't have a "context" byte at the start, post backspaces - to erase the appropriate number of characters in the application. If it does have - a "context" byte at the start, then the string won't change, and no backspaces are - necessary. You could go one step further with this optimization, in PostAllKeys, - by comparing the starts of the strings to see what is same, and not backspacing - that, but it is probably not necessary. - */ - - p = kkp->dpOutput; - if(*p != UC_SENTINEL || *(p+1) != CODE_CONTEXT) { - for(PWSTR mcp = decxstr(wcschr(_td->miniContext, 0), _td->miniContext); mcp != NULL; mcp = decxstr(mcp, _td->miniContext)) { - if (*mcp == UC_SENTINEL) { - switch (*(mcp + 1)) { - case CODE_DEADKEY: _td->app->QueueAction(QIT_BACK, BK_DEADKEY); break; - case CODE_NUL: break; // 11 Aug 2003 - I25(v6) - mcdurdin - CODE_NUL context support - } - } - else if (Uni_IsSurrogate1(*mcp) && Uni_IsSurrogate2(*(mcp + 1))) { - // 2 backspaces to delete both parts of surrogate pair - // This only needs to be done for TSF-aware apps as legacy apps - // will receive a BKSP WM_KEYDOWN event which results in deleting - // both parts in one action - _td->app->QueueAction(QIT_BACK, BK_SURROGATE); - } - else { - _td->app->QueueAction(QIT_BACK, 0); - } - } - } - else { - // otherwise, the "context" entry has to be jumped over - p += 2; - } - - /* Use PostString to post the rest of the output string. */ - - if(PostString(p, &_td->state.msg, _td->state.lpkb, NULL) == psrCheckMatches) - { - _td->app->QueueDebugInformation(QID_RULE_EXIT, gp, kkp, _td->miniContext, NULL, 0); - - if(gp->dpMatch && *gp->dpMatch) - { - _td->app->QueueDebugInformation(QID_MATCH_ENTER, gp, NULL, NULL, gp->dpMatch, 0); - PostString(gp->dpMatch, &_td->state.msg, _td->state.lpkb, NULL); - _td->app->QueueDebugInformation(QID_MATCH_EXIT, gp, NULL, NULL, gp->dpMatch, 0); - } - } - else - _td->app->QueueDebugInformation(QID_RULE_EXIT, gp, kkp, _td->miniContext, NULL, 0); - _td->app->QueueDebugInformation(QID_GROUP_EXIT, gp, NULL, NULL, NULL, 0); - - return TRUE; -} - -/* -* int PostString( LPSTR str, BOOL *useMode, LPMSG mp, -* LPKEYBOARD lpkb ); -* -* Parameters: str Pointer to string to send -* useMode Pointer to BOOL about whether a "use" command was found -* mp Pointer to MSG structure to copy in outputting messages -* lpkb Pointer to global keyboard structure -* -* Returns: 0 to continue, 1 and 2 to return. -* -* Called by: ProcessKey -* -* PostString posts a string of "context", "index", "beep", characters and virtual keys -* to the active application, via the Keyman PostKey buffer. -*/ - -int PostString(PWSTR str, LPMSG mp, LPKEYBOARD lpkb, PWSTR endstr) -{ - if (!DebugAssert(!Globals::get_CoreIntegration(), "KKMPROCESS:PostString: Error called in core integration mode")) { - return FALSE; - } - PWSTR p, q, temp; - LPSTORE s; - int n1, n2; - int i, n, shift; - BOOL FoundUse = FALSE; - - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - - // TODO: Refactor to use incxstr - for(p = str; *p && (p < endstr || !endstr); p++) - { - if(*p == UC_SENTINEL) - switch(*(++p)) - { - case CODE_EXTENDED: // Start of a virtual key section w/shift codes - p++; - - shift = *p; //(*p<<8) | *(p+1); - _td->app->QueueAction(QIT_VSHIFTDOWN, shift); - - p++; - - _td->app->QueueAction(QIT_VKEYDOWN, *p); - _td->app->QueueAction(QIT_VKEYUP, *p); - - _td->app->QueueAction(QIT_VSHIFTUP, shift); - - p++; // CODE_EXTENDEDEND - ////// CODE_EXTENDEDEND will be incremented by loop - - //app->QueueAction(QIT_VSHIFTUP, shift); - break; - - case CODE_DEADKEY: // A deadkey to be output - p++; - _td->app->QueueAction(QIT_DEADKEY, *p); - break; - case CODE_BEEP: // Sound an 'iconasterisk' beep - _td->app->QueueAction(QIT_BELL, 0); - break; - case CODE_CONTEXT: // copy the context to the output - PostString(_td->miniContext, mp, lpkb, wcschr(_td->miniContext, 0)); - break; - case CODE_CONTEXTEX: - p++; - for(q = _td->miniContext, i = _td->miniContextIfLen; *q && i < *p-1; i++, q=incxstr(q)); - if(*q) { - temp = incxstr(q); - PostString(q, mp, lpkb, temp); - } - break; - case CODE_RETURN: // stop processing and start PostAllKeys - _td->state.StopOutput = TRUE; - return psrPostMessages; - - case CODE_CALL: - p++; - CallDLL(_td->lpActiveKeyboard, *p-1); - if(_td->state.StopOutput) return psrPostMessages; - FoundUse = TRUE; - break; - case CODE_USE: // use another group - p++; - ProcessGroup(&lpkb->dpGroupArray[*p-1]); - if(_td->state.StopOutput) return psrPostMessages; - FoundUse = TRUE; - break; - case CODE_CLEARCONTEXT: - _td->app->ResetContext(); - _td->app->ReadContext(); - break; - case CODE_INDEX: - p++; - s = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[*p - 1]; - p++; - - n = _td->IndexStack[*p - 1]; - for(temp = s->dpString; *temp && n > 0; temp = incxstr(temp), n--); - PostString(temp, mp, lpkb, incxstr(temp)); - break; - case CODE_SETOPT: - p++; - n1 = *p - 1; - p++; - n2 = *p - 1; - SetKeyboardOption(_td->lpActiveKeyboard, n1, n2); - break; - case CODE_RESETOPT: - p++; - n1 = *p - 1; - ResetKeyboardOption(_td->lpActiveKeyboard, n1); - break; - case CODE_SAVEOPT: - p++; - n1 = *p - 1; - SaveKeyboardOption(_td->lpActiveKeyboard, n1); - break; - case CODE_IFSYSTEMSTORE: - p+=3; - break; - case CODE_SETSYSTEMSTORE: - p+=2; - break; - } - else - _td->app->QueueAction(QIT_CHAR, *p); - } - return FoundUse ? psrPostMessages : psrCheckMatches; -} - - -BOOL IsMatchingBaseLayout(PWCHAR layoutName) // I3432 -{ - BOOL bEqual = _wcsicmp(layoutName, Globals::get_BaseKeyboardName()) == 0 || // I4583 - _wcsicmp(layoutName, Globals::get_BaseKeyboardNameAlt()) == 0; // I4583 - - return bEqual; -} - -BOOL IsMatchingPlatformString(PWCHAR platform) // I3432 -{ - return - _wcsicmp(platform, L"windows") == 0 || - _wcsicmp(platform, L"desktop") == 0 || - _wcsicmp(platform, L"hardware") == 0 || - _wcsicmp(platform, L"native") == 0; -} - -BOOL IsMatchingPlatform(LPSTORE s) // I3432 -{ - PWCHAR t = new WCHAR[wcslen(s->dpString)+1]; - wcscpy_s(t, wcslen(s->dpString)+1, s->dpString); - PWCHAR context = NULL; - PWCHAR platform = wcstok_s(t, L" ", &context); - while(platform != NULL) - { - if(!IsMatchingPlatformString(platform)) - { - s->dwSystemID = TSS_PLATFORM_NOMATCH; - delete[] t; - return FALSE; - } - platform = wcstok_s(NULL, L" ", &context); - } - - s->dwSystemID = TSS_PLATFORM_MATCH; - delete[] t; - return TRUE; -} - -/* -* BOOL ContextMatch( LPKEY kkp ); -* -* Parameters: kkp Rule to compare -* -* Returns: 0 on OK, 1 on not equal -* -* Called by: ProcessKey -* -* ContextMatch compares the context of a rule with the current context. -*/ - -BOOL ContextMatch(LPKEY kkp) -{ - if (!DebugAssert(!Globals::get_CoreIntegration(), "KMPROCESS:ContextMatch: Error called in core integration mode")) { - return FALSE; - } - WORD /*i,*/ n; - PWSTR p, q, qbuf, temp; - LPWORD indexp; - LPSTORE s, t; - BOOL bEqual; - - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: ENTER [%d]", kkp->Line); - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - - memset(_td->IndexStack, 0, GLOBAL_ContextStackSize*sizeof(WORD)); // I3158 // I3524 - - p = kkp->dpContext; - - if(*p == 0) - { - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: EXIT TRUE -> no rule context"); - return TRUE; - } - - /* 11 Aug 2003 - I25(v6) - mcdurdin - test for CODE_NUL */ - - if(*p == UC_SENTINEL && *(p+1) == CODE_NUL) - { - // If context buf is longer than the context, then obviously not start of doc. - if(_td->app->ContextBuf(xstrlen_ignoreifopt(p))) return FALSE; // I2484 - Fix bug with if() following nul in same statement - p = incxstr(p); - if(*p == 0) return TRUE; - } - - for(PWCHAR pp = p; pp && *pp; pp = incxstr(pp)) - { - if(*pp == UC_SENTINEL && *(pp+1) == CODE_IFOPT) - { - s = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(pp+2))-1]; // I2590 - t = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(pp+4))-1]; // I2590 - - bEqual = wcscmp(s->dpString, t->dpString) == 0; - if(*(pp+3) == 1 && bEqual) return FALSE; // I2590 - if(*(pp+3) == 2 && !bEqual) return FALSE; // I2590 - } - else if(*pp == UC_SENTINEL && *(pp+1) == CODE_IFSYSTEMSTORE) // I3432 - { - DWORD dwSystemID = *(pp+2)-1; - t = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(pp+4))-1]; // I2590 - switch(dwSystemID) - { - case TSS_PLATFORM_MATCH: // Cached platform result - a matching platform - bEqual = TRUE; - break; - case TSS_PLATFORM_NOMATCH: // Cached platform result - not a matching platform - bEqual = FALSE; - break; - case TSS_PLATFORM: - bEqual = IsMatchingPlatform(t); - break; - case TSS_BASELAYOUT: - bEqual = IsMatchingBaseLayout(t->dpString); - break; - default: - { - PWCHAR ss = GetSystemStore(_td->lpActiveKeyboard->Keyboard, dwSystemID); - if(ss == NULL) return FALSE; - bEqual = wcscmp(ss, t->dpString) == 0; - } - } - - if(*(pp+3) == 1 && bEqual) return FALSE; // I2590 - if(*(pp+3) == 2 && !bEqual) return FALSE; // I2590 - } - } - - q = qbuf = _td->app->ContextBuf(xstrlen_ignoreifopt(p)); - if(!q) - { - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: EXIT FALSE -> context too short"); - return FALSE; // context buf is too short! - } - indexp = _td->IndexStack; - - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: [%d] Rule: %s", kkp->Line, format_unicode_debug(kkp->dpContext)); - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: [%d] Test: %s", kkp->Line, format_unicode_debug(q)); - - for(; *p && *q; p = incxstr(p)) - { - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: p:%x q:%x", *p, *q); - *indexp = 0; - - if(*p == UC_SENTINEL) - { - switch(*(p+1)) - { - case CODE_DEADKEY: - if(*q != UC_SENTINEL || *(q+1) != CODE_DEADKEY || *(q+2) != *(p+2)) - { - // SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: EXIT FALSE -> deadkeys don't match %x %x %x != %x %x %x", - // *p, *(p+1), *(p+2), *q, *(q+1), *(q+2)); - return FALSE; - } - break; - case CODE_ANY: - s = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(p+2))-1]; - - temp = xstrchr(s->dpString, q); - - /*SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard ,kkp->Line, "ContextMatch: CODE_ANY [%x %x %x %x %x %x %x %x %x %x] [%x %x %x] %d", - s->dpString[0], s->dpString[1], s->dpString[2], - s->dpString[3], s->dpString[4], s->dpString[5], - s->dpString[6], s->dpString[7], s->dpString[8], - s->dpString[9], - q[0], q[1], q[2], - (temp ? (INT_PTR)(temp-s->dpString) : 0));*/ - - if(temp != NULL) // I1622 - *indexp = (WORD) xstrpos(temp, s->dpString); - - //if((temp = xstrchr(s->dpString, GetSuppChar(q))) != NULL) - // *indexp = xstrpos(temp, s->dpString); - else - return FALSE; - break; - case CODE_NOTANY: - s = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(p+2))-1]; - - if((temp = xstrchr(s->dpString, q)) != NULL) // I1622 - return FALSE; - - //if((temp = xstrchr(s->dpString, GetSuppChar(q))) != NULL) - // return FALSE; - break; - case CODE_INDEX: - s = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(p+2))-1]; - *indexp = n = _td->IndexStack[(*(p+3))-1]; - - for(temp = s->dpString; *temp && n > 0; temp = incxstr(temp), n--); - if(n != 0) return FALSE; - if(xchrcmp(temp, q) != 0) return FALSE; - ////if(GetSuppChar(temp) != GetSuppChar(q)) return FALSE; // I1622 - break; - case CODE_CONTEXTEX: - // only the nth character - for(n = *(p+2) - 1, temp = qbuf; temp < q && n > 0; n--, temp = incxstr(temp)); - if(n == 0) - if(xchrcmp(temp, q) != 0) return FALSE; - //if(GetSuppChar(temp) != GetSuppChar(q)) return FALSE; - break; - case CODE_IFOPT: - case CODE_IFSYSTEMSTORE: // I3432 - indexp++; - continue; // don't increment q - default: - return FALSE; - } - } - else if(xchrcmp(p, q) != 0) //GetSuppChar(p) != GetSuppChar(q)) - { - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: [%d] FAIL: %s", kkp->Line, format_unicode_debug(p)); - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: [%d] FAIL: %s", kkp->Line, format_unicode_debug(q)); - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: EXIT FALSE -> chrs don't match"); - return FALSE; - } - indexp++; - q = incxstr(q); - } - - while(*p == UC_SENTINEL && (*(p+1) == CODE_IFOPT || *(p+1) == CODE_IFSYSTEMSTORE)) p = incxstr(p); // already tested // I3432 - - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: EXIT %s -> END OF FUNCTION", - // *p == *q ? "TRUE" : "FALSE"); - return *p == *q; /*at least one must ==0 at this point*/ -} - - PWSTR strtowstr(PSTR in) { PWSTR result; @@ -933,7 +251,6 @@ PWSTR strtowstr(PSTR in) return result; } - PSTR wstrtostr(PCWSTR in) { PSTR result; diff --git a/windows/src/engine/keyman32/kmprocessactions.cpp b/windows/src/engine/keyman32/kmprocessactions.cpp index 1e07523925..8855ad7e15 100644 --- a/windows/src/engine/keyman32/kmprocessactions.cpp +++ b/windows/src/engine/keyman32/kmprocessactions.cpp @@ -71,7 +71,7 @@ static BOOL processPersistOpt( SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessHook: Saving option to registry for keyboard [%s].", activeKeyboard->Name); LPWSTR value = new WCHAR[sizeof(actionItem->option->value) + 1]; wcscpy_s(value, sizeof(actionItem->option->value) + 1, reinterpret_cast(actionItem->option->value)); - SaveKeyboardOptionREGCore(activeKeyboard, reinterpret_cast(actionItem->option->key), value); + SaveKeyboardOptionCoretoRegistry(activeKeyboard, reinterpret_cast(actionItem->option->key), value); } } return TRUE; diff --git a/windows/src/engine/keyman32/preservedkeymap.cpp b/windows/src/engine/keyman32/preservedkeymap.cpp index cd13a82f8c..1fd803838d 100644 --- a/windows/src/engine/keyman32/preservedkeymap.cpp +++ b/windows/src/engine/keyman32/preservedkeymap.cpp @@ -37,12 +37,11 @@ struct PreservedKey class PreservedKeyMap { public: - BOOL MapKeyboard(KEYBOARD *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys); /** * Updates a map of preserved keys (with GUID) that are used in keyboard rules. * Passing in NULL for pPreservedKeys will cause cPreservedKeys to be set to the number - * of preserved keys needed for the supplied pKeyboard; this should be used in creating - * pPreservedKeys list to sufficient size. When pPreservedKeys list is passed the + * of preserved keys needed for the supplied pKeyboard; this should be used in creating + * pPreservedKeys list to sufficient size. When pPreservedKeys list is passed the * cPreservedKeys will be the actual count of the number of unique pPreservedKeys * * @param pKeyboard the keyboard for which the rules will be extracted from @@ -50,14 +49,13 @@ public: * @param cPreservedKeys number of preserved keys in pPreservedKeys - or the size pPreservedKeys needs to be * @return BOOL return TRUE on success */ - BOOL MapKeyboardCore(km_kbp_keyboard *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys); + BOOL MapKeyboard(km_kbp_keyboard *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys); private: BOOL m_BaseKeyboardUsesAltGr; // I4592 UINT ShiftToTSFShift(UINT ShiftFlags); BOOL MapUSCharToVK(UINT *puKey, UINT *puShiftFlags); - BOOL MapKeyRule(KEY *pKey, TF_PRESERVEDKEY *pPreservedKey); - BOOL MapKeyRuleCore(km_kbp_keyboard_key *pKeyRule, TF_PRESERVEDKEY *pPreservedKey); + BOOL MapKeyRule(km_kbp_keyboard_key *pKeyRule, TF_PRESERVEDKEY *pPreservedKey); BOOL IsMatchingKey(PreservedKey *pKey, PreservedKey *pKeys, size_t cKeys); }; @@ -199,45 +197,8 @@ UINT PreservedKeyMap::ShiftToTSFShift(UINT ShiftFlags) return res; } -BOOL PreservedKeyMap::MapKeyRule(KEY *pKey, TF_PRESERVEDKEY *pPreservedKey) -{ - UINT ShiftFlags; - UINT Key; - - Key = pKey->Key; - ShiftFlags = pKey->ShiftFlags; - - if(Key == VK_BACK || Key == VK_RETURN || Key == VK_TAB) // I4575 - { - // - // We never map backspace, return or tab because these are the only supported virtual key outputs, - // and result in recursion. Sadly, this is an imperfect solution forced upon us by preserved key - // limitations. - // - // Other virtual key output will be blocked with this version. - return FALSE; - } - - if (Key > 255) { - // - // Touch-defined keys have a value > 255, but these should never be preserved - // - return FALSE; - } - - if(ShiftFlags == 0) - { - if(!MapUSCharToVK(&Key, &ShiftFlags)) return FALSE; - } - - pPreservedKey->uVKey = (UINT) USVKToScanCodeToLayoutVK( (WORD) Key); // I3762 - pPreservedKey->uModifiers = ShiftToTSFShift(ShiftFlags); - - return TRUE; -} - BOOL -PreservedKeyMap::MapKeyRuleCore(km_kbp_keyboard_key *pKeyRule, TF_PRESERVEDKEY *pPreservedKey) { +PreservedKeyMap::MapKeyRule(km_kbp_keyboard_key *pKeyRule, TF_PRESERVEDKEY *pPreservedKey) { UINT ShiftFlags; UINT Key; @@ -280,94 +241,8 @@ BOOL PreservedKeyMap::IsMatchingKey(PreservedKey *pKey, PreservedKey *pKeys, siz return FALSE; } -// TODO: 5442 - Remove once core processor verfied -BOOL PreservedKeyMap::MapKeyboard(KEYBOARD *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys) -{ - size_t cKeys = 0, n; - DWORD i, j; - GROUP *pGroup; - - m_BaseKeyboardUsesAltGr = KeyboardGivesCtrlRAltForRAlt(); // I4592 - - // This is not the same as m_BaseKeyboardUsesAltGr -- we are turning - // the simulation back on after (possibly) turning it off, for a - // consistent experience. TODO: determine if m_BaseKeyboardUseAltGr - // is still needed given we always use kbdus as base for Keyman 10+ - BOOL bSimulateAltGr = Globals::get_SimulateAltGr(); - - // We only want to translate RALT and RALT+SHIFT for Ctrl+Alt rules. - // So we exclude all our other favourite modifier keys. - const UINT RALT_MATCHING_MASK = TF_MOD_CONTROL | TF_MOD_ALT | TF_MOD_LCONTROL | TF_MOD_RCONTROL | TF_MOD_LALT | TF_MOD_RALT; - - for(i = 0; i < pKeyboard->cxGroupArray; i++) - { - if(pKeyboard->dpGroupArray[i].fUsingKeys) - { - cKeys += pKeyboard->dpGroupArray[i].cxKeyArray; - } - } - - if(cKeys == 0) - { - return FALSE; - } - - if (bSimulateAltGr) - { - // We might need twice as many preserved keys to map both LCtrl+LAlt+x and RAlt+x - cKeys *= 2; - } - - if(pPreservedKeys == NULL) - { - *cPreservedKeys = cKeys; - return TRUE; - } - - if(*cPreservedKeys < cKeys) - { - return FALSE; - } - - PreservedKey *pKeys = *pPreservedKeys; - - for(n = i = 0; i < pKeyboard->cxGroupArray; i++) - { - pGroup = &pKeyboard->dpGroupArray[i]; - if(pGroup->fUsingKeys) - { - for(j = 0; j < pGroup->cxKeyArray; j++) - { - // If we have a key rule for the key, we should preserve it - if(MapKeyRule(&pGroup->dpKeyArray[j], &pKeys[n].key)) - { - // Don't attempt to add the same preserved key twice. Bad things happen - if(!IsMatchingKey(&pKeys[n], pKeys, n)) - { - CoCreateGuid(&pKeys[n].guid); - n++; - - if (bSimulateAltGr && (pKeys[n-1].key.uModifiers & RALT_MATCHING_MASK) == TF_MOD_RALT) - { - // Do this for RALT and RALT+SHIFT only, so we've tested against that mask - // Copy the key and fix modifiers - pKeys[n].key = pKeys[n - 1].key; - pKeys[n].key.uModifiers = (pKeys[n].key.uModifiers & ~TF_MOD_RALT) | TF_MOD_LCONTROL | TF_MOD_LALT; - CoCreateGuid(&pKeys[n].guid); - n++; - } - } - } - } - } - } - - *cPreservedKeys = n; // return actual count of allocated keys, usually smaller than allocated count - return TRUE; -} - BOOL -PreservedKeyMap::MapKeyboardCore(km_kbp_keyboard *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys) { +PreservedKeyMap::MapKeyboard(km_kbp_keyboard *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys) { size_t cKeys = 0, cRules = 0, n = 0; DWORD i; @@ -422,7 +297,7 @@ PreservedKeyMap::MapKeyboardCore(km_kbp_keyboard *pKeyboard, PreservedKey **pPre for (i = 0; i < cRules; i++) { // If we have a key rule for the key, we should preserve it - if (MapKeyRuleCore(&kb_key_list[i], &pKeys[n].key)) { + if (MapKeyRule(&kb_key_list[i], &pKeys[n].key)) { // Don't attempt to add the same preserved key twice. Bad things happen if (!IsMatchingKey(&pKeys[n], pKeys, n)) { CoCreateGuid(&pKeys[n].guid); @@ -457,23 +332,14 @@ extern "C" __declspec(dllexport) BOOL WINAPI GetKeyboardPreservedKeys(PreservedK if (!_td) { return FALSE; } + if (!_td->lpActiveKeyboard) { return FALSE; } - // It could be an active core keyboard - if (Globals::get_CoreIntegration()) { - if (!_td->lpActiveKeyboard->lpCoreKeyboard) { - return FALSE; - } - // use api to get key rules - return pkm.MapKeyboardCore(_td->lpActiveKeyboard->lpCoreKeyboard, pPreservedKeys, cPreservedKeys); - - } else { // TODO: 5442 Remove else - if (!_td->lpActiveKeyboard->Keyboard) { - return FALSE; - } - return pkm.MapKeyboard(_td->lpActiveKeyboard->Keyboard, pPreservedKeys, cPreservedKeys); + if (!_td->lpActiveKeyboard->lpCoreKeyboard) { + return FALSE; } - + // use api to get key rules + return pkm.MapKeyboard(_td->lpActiveKeyboard->lpCoreKeyboard, pPreservedKeys, cPreservedKeys); } diff --git a/windows/src/engine/keyman32/selectkeyboard.cpp b/windows/src/engine/keyman32/selectkeyboard.cpp index ae6f366f3f..0ca9e2e65f 100644 --- a/windows/src/engine/keyman32/selectkeyboard.cpp +++ b/windows/src/engine/keyman32/selectkeyboard.cpp @@ -53,7 +53,7 @@ // I3594 // I4220 -BOOL SelectKeyboardCore(DWORD KeymanID) +BOOL SelectKeyboard(DWORD KeymanID) { int i; HWND hwnd = GetFocus(); @@ -71,14 +71,9 @@ BOOL SelectKeyboardCore(DWORD KeymanID) __try { - if (_td->ForceFileName[0]) - { - SendDebugMessageFormat(hwnd, sdmGlobal, 0, "SelectKeyboard: Ignored due to ForceFile"); - return FALSE; // Keyboard file is force-loaded - } KMHideIM(); - + if (_td->lpActiveKeyboard) DeactivateDLLs(_td->lpActiveKeyboard); _td->lpActiveKeyboard = NULL; _td->ActiveKeymanID = KEYMANID_NONKEYMAN; @@ -101,12 +96,13 @@ BOOL SelectKeyboardCore(DWORD KeymanID) SendDebugMessageFormat(hwnd, sdmGlobal, 0, "SelectKeyboardCore: NewKeymanID: %x", _td->ActiveKeymanID); if (_td->app) _td->app->ResetContext(); - ResetCapsLock(); + + // TODO: #5822 tell the core with km_kbp_event so it can reset the capslock state SelectApplicationIntegration(); // I4287 if (_td->app && !_td->app->IsWindowHandled(hwnd)) _td->app->HandleWindow(hwnd); _td->state.windowunicode = !_td->app || _td->app->IsUnicode(); - + ActivateDLLs(_td->lpActiveKeyboard); return TRUE; @@ -130,88 +126,6 @@ BOOL SelectKeyboardCore(DWORD KeymanID) return TRUE; } -BOOL SelectKeyboard(DWORD KeymanID) -{ - if (Globals::get_CoreIntegration()) - { - return SelectKeyboardCore(KeymanID); - } - int i; - HWND hwnd = GetFocus(); - - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - - SendDebugMessageFormat(hwnd,sdmGlobal,0,"ENTER SelectKeyboard-------------------------------------------"); - SendDebugMessageFormat(hwnd,sdmGlobal,0,"ENTER SelectKeyboard: Current:(HKL=%x KeymanID=%x %s) New:(ID=%x)", //lpActiveKeyboard=%s ActiveKeymanID: %x sk: %x KeymanID: %d", - GetKeyboardLayout(0), - _td->ActiveKeymanID, - _td->lpActiveKeyboard == NULL ? "NULL" : _td->lpActiveKeyboard->Name, - //_td->NextKeyboardLayout, - KeymanID); - - __try - { - if(_td->ForceFileName[0]) - { - SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: Ignored due to ForceFile"); - return FALSE; // Keyboard file is force-loaded - } - - KMHideIM(); - - if(_td->lpActiveKeyboard) DeactivateDLLs(_td->lpActiveKeyboard); - _td->lpActiveKeyboard = NULL; - _td->ActiveKeymanID = KEYMANID_NONKEYMAN; - - //SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: nKeyboards=%d", nKeyboards); - - for(i = 0; i < _td->nKeyboards; i++) - { - if(_td->lpKeyboards[i].KeymanID == KeymanID) - { - if(!_td->lpKeyboards[i].Keyboard && !LoadlpKeyboard(i)) - { - SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: Unable to load"); - return TRUE; - } - - _td->lpActiveKeyboard = &_td->lpKeyboards[i]; - _td->ActiveKeymanID = _td->lpActiveKeyboard->KeymanID; - - SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: NewKeymanID: %x", _td->ActiveKeymanID); - - if(_td->app) _td->app->ResetContext(); - ResetCapsLock(); - - SelectApplicationIntegration(); // I4287 - if(_td->app && !_td->app->IsWindowHandled(hwnd)) _td->app->HandleWindow(hwnd); - _td->state.windowunicode = !_td->app || _td->app->IsUnicode(); - - ActivateDLLs(_td->lpActiveKeyboard); - - return TRUE; - } - } - - if(IsFocusedThread()) - { - SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: Keyboard Not Found"); - } - } - __finally - { - SendDebugMessageFormat(hwnd,sdmGlobal,0,"EXIT SelectKeyboard: Current:(HKL=%x KeymanID=%x %s) New:(ID=%x)", //lpActiveKeyboard=%s ActiveKeymanID: %x sk: %x KeymanID: %d", - GetKeyboardLayout(0), - _td->ActiveKeymanID, - _td->lpActiveKeyboard == NULL ? "NULL" : _td->lpActiveKeyboard->Name, - KeymanID); - SendDebugMessageFormat(hwnd,sdmGlobal,0,"EXIT SelectKeyboard-------------------------------------------"); - } - return TRUE; -} - - BOOL SelectKeyboardTSF(DWORD dwIdentity, BOOL foreground) // I3933 // I3949 // I4271 { if (!foreground && IsFocusedThread()) { diff --git a/windows/src/engine/keyman32/tests/keyman-engine-tests/keyboardoptionstests.cpp b/windows/src/engine/keyman32/tests/keyman-engine-tests/keyboardoptionstests.cpp index 4a16621ee8..795f89fe44 100644 --- a/windows/src/engine/keyman32/tests/keyman-engine-tests/keyboardoptionstests.cpp +++ b/windows/src/engine/keyman32/tests/keyman-engine-tests/keyboardoptionstests.cpp @@ -5,77 +5,6 @@ #include #include -// Test UpdateKeyboardOptionsCore, also uses SaveKeyboardOptionsCore -TEST(KEYBOARDOPTIONS, UpdateKeyboardOptionsCore) { - LPINTKEYBOARDINFO kp = new INTKEYBOARDINFO; - memset(kp, 0, sizeof(INTKEYBOARDINFO)); - - km_kbp_option_item test_env_opts[] = { - {u"__test_point", u"not tiggered", KM_KBP_OPT_KEYBOARD}, {u"hello", u"-", KM_KBP_OPT_ENVIRONMENT}, KM_KBP_OPTIONS_END}; - - km_kbp_path_name dummyPath = L"dummyActions.mock"; - EXPECT_EQ(km_kbp_keyboard_load(dummyPath, &kp->lpCoreKeyboard), KM_KBP_STATUS_OK); - EXPECT_EQ(km_kbp_state_create(kp->lpCoreKeyboard, test_env_opts, &kp->lpCoreKeyboardState), KM_KBP_STATUS_OK); - - kp->lpCoreKeyboardOptions = SaveKeyboardOptionsCore(kp); - // No Change - EXPECT_FALSE(UpdateKeyboardOptionsCore(kp->lpCoreKeyboardState, kp->lpCoreKeyboardOptions)); - std::u16string value = kp->lpCoreKeyboardOptions[0].value; - std::u16string expectedValue = u"not tiggered"; - EXPECT_TRUE(value == expectedValue); - - km_kbp_option_item update_key_opts[] = {{u"__test_point", u"triggered", KM_KBP_OPT_KEYBOARD}, KM_KBP_OPTIONS_END}; - EXPECT_EQ(km_kbp_state_options_update(kp->lpCoreKeyboardState, update_key_opts), KM_KBP_STATUS_OK); - // Change value to triggered - EXPECT_TRUE(UpdateKeyboardOptionsCore(kp->lpCoreKeyboardState, kp->lpCoreKeyboardOptions)); - value = kp->lpCoreKeyboardOptions[0].value; - expectedValue = u"triggered"; - EXPECT_TRUE(value == expectedValue); - DisposeKeyboardOptionsCore(&kp->lpCoreKeyboardOptions); - ReleaseStateMemoryCore(&kp->lpCoreKeyboardState); - ReleaseKeyboardMemoryCore(&kp->lpCoreKeyboard); - delete kp; - -} - -// Test SaveKeyboardOptionsCore and RestoreKeyboardOptionsCORE -TEST(KEYBOARDOPTIONS, SaveRestoreKeyboardOptionsCore) { - - LPINTKEYBOARDINFO kp = new INTKEYBOARDINFO; - memset(kp, 0, sizeof(INTKEYBOARDINFO)); - - km_kbp_option_item test_env_opts[] = { - {u"__test_point", u"not tiggered", KM_KBP_OPT_KEYBOARD}, {u"hello", u"-", KM_KBP_OPT_ENVIRONMENT}, KM_KBP_OPTIONS_END}; - km_kbp_path_name dummyPath = L"dummyActions.mock"; - EXPECT_EQ(km_kbp_keyboard_load(dummyPath, &kp->lpCoreKeyboard), KM_KBP_STATUS_OK); - EXPECT_EQ(km_kbp_state_create(kp->lpCoreKeyboard, test_env_opts, &kp->lpCoreKeyboardState), KM_KBP_STATUS_OK); - - km_kbp_option_item *SavedKBDOptions = SaveKeyboardOptionsCore(kp); - - std::u16string value = SavedKBDOptions[0].value; - std::u16string expectedValue = u"not tiggered"; - km_kbp_option_item update_key_opts[] = {{u"__test_point", u"triggered", KM_KBP_OPT_KEYBOARD}, KM_KBP_OPTIONS_END}; - EXPECT_EQ(km_kbp_state_options_update(kp->lpCoreKeyboardState, update_key_opts), KM_KBP_STATUS_OK); - - km_kbp_option_item *NewKBDOptions = SaveKeyboardOptionsCore(kp); - value = NewKBDOptions[0].value; - expectedValue = u"triggered"; - EXPECT_TRUE(value == expectedValue); - km_kbp_cp const *retValue = nullptr; - EXPECT_TRUE(RestoreKeyboardOptionsCore(kp->lpCoreKeyboardState, SavedKBDOptions)); - EXPECT_EQ(km_kbp_state_option_lookup(kp->lpCoreKeyboardState, KM_KBP_OPT_KEYBOARD, test_env_opts[0].key, &retValue), KM_KBP_STATUS_OK); - - value = retValue; - expectedValue = u"not tiggered"; - EXPECT_TRUE(value == expectedValue); - - DisposeKeyboardOptionsCore(&NewKBDOptions); - DisposeKeyboardOptionsCore(&SavedKBDOptions); - - ReleaseStateMemoryCore(&kp->lpCoreKeyboardState); - ReleaseKeyboardMemoryCore(&kp->lpCoreKeyboard); - delete kp; -} // Test SetupCoreEnvironment and also test km_kbp_state_options_update TEST(KEYBOARDOPTIONS, SetupCoreEnvironment) { diff --git a/windows/src/engine/keyman64/keyman64.vcxproj b/windows/src/engine/keyman64/keyman64.vcxproj index d70c0872ed..15546caef5 100644 --- a/windows/src/engine/keyman64/keyman64.vcxproj +++ b/windows/src/engine/keyman64/keyman64.vcxproj @@ -177,7 +177,6 @@ - @@ -279,7 +278,6 @@ - diff --git a/windows/src/engine/keyman64/keyman64.vcxproj.filters b/windows/src/engine/keyman64/keyman64.vcxproj.filters index 0b53bd96cb..cd8aeefb32 100644 --- a/windows/src/engine/keyman64/keyman64.vcxproj.filters +++ b/windows/src/engine/keyman64/keyman64.vcxproj.filters @@ -2,7 +2,6 @@ - @@ -41,7 +40,6 @@ - diff --git a/windows/src/engine/kmtip/keys.cpp b/windows/src/engine/kmtip/keys.cpp index d5d4882ca5..9f1552f4e3 100644 --- a/windows/src/engine/kmtip/keys.cpp +++ b/windows/src/engine/kmtip/keys.cpp @@ -362,36 +362,3 @@ STDMETHODIMP CKMTipTextService::OnPreservedKey(ITfContext *pContext, REFGUID rgu *pfEaten = FALSE; return S_OK; } - -BOOL CKMTipTextService::DoRefreshPreservedKeys(BOOL Activating) { - LogEnter(); - ITfKeystrokeMgr *pKeystrokeMgr; - HRESULT hr = S_OK; - - Log(L"CKMTipTextService::DoRefreshPreservedKeys"); - - if (!_pThreadMgr) { - return FALSE; - } - - if (_pThreadMgr->QueryInterface(IID_ITfKeystrokeMgr, (void **)&pKeystrokeMgr) != S_OK) { - return FALSE; - } - - _UnpreserveAltKeys(pKeystrokeMgr); - if (Activating) { - hr = _PreserveAltKeys(pKeystrokeMgr); // I3588 - } - - pKeystrokeMgr->Release(); - - return (hr == S_OK); -} - -__declspec(dllexport) BOOL WINAPI RefreshPreservedKeys(BOOL Activating) { - LogEnter(); - if (CKMTipTextService::ThreadThis) { - return CKMTipTextService::ThreadThis->DoRefreshPreservedKeys(Activating); - } - return FALSE; -} diff --git a/windows/src/engine/kmtip/kmtip.def b/windows/src/engine/kmtip/kmtip.def index 64c10743c2..854f6b6ca5 100644 --- a/windows/src/engine/kmtip/kmtip.def +++ b/windows/src/engine/kmtip/kmtip.def @@ -5,5 +5,4 @@ EXPORTS DllCanUnloadNow PRIVATE DllRegisterServer PRIVATE DllUnregisterServer PRIVATE - RefreshPreservedKeys Keyman_Diagnostic diff --git a/windows/src/engine/kmtip/kmtip.h b/windows/src/engine/kmtip/kmtip.h index aabe098b8b..3ab425891d 100644 --- a/windows/src/engine/kmtip/kmtip.h +++ b/windows/src/engine/kmtip/kmtip.h @@ -1,18 +1,18 @@ /* Name: kmtip Copyright: Copyright (C) SIL International. - Documentation: + Documentation: Description: CKMTipTextService declaration. Create Date: 7 Sep 2009 Modified Date: 27 Jan 2015 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 07 Sep 2009 - mcdurdin - I2095 - TSF addin is not threadsafe 01 May 2014 - mcdurdin - I4216 - V9.0 - Keyman TIP should use ITfTextInputProcessorEx 16 Jun 2014 - mcdurdin - I4274 - V9.0 - kmtip does not work if already active before KM starts @@ -88,8 +88,6 @@ public: BOOL TIPNotifyActivate(GUID *guidProfile); - BOOL DoRefreshPreservedKeys(BOOL Activating); - static __declspec(thread) CKMTipTextService *ThreadThis; private: @@ -107,7 +105,7 @@ private: void _UninitKeyman(); void _TryAndStartKeyman(); - + HRESULT _UnpreserveAltKeys(ITfKeystrokeMgr *pKeystrokeMgr); // Keyman interfaces diff --git a/windows/src/global/delphi/general/keyman32_int.pas b/windows/src/global/delphi/general/keyman32_int.pas deleted file mode 100644 index decebd7bdb..0000000000 --- a/windows/src/global/delphi/general/keyman32_int.pas +++ /dev/null @@ -1,184 +0,0 @@ -(* - Name: keyman32_int - Copyright: Copyright (C) SIL International. - Documentation: - Description: - Create Date: 1 Aug 2006 - - Modified Date: 17 Aug 2012 - Authors: mcdurdin - Related Files: - Dependencies: - - Bugs: - Todo: - Notes: - History: 01 Aug 2006 - mcdurdin - Add GetKeymanInstallPath function - 14 Sep 2006 - mcdurdin - Retrieve Debug_Keyman32 path if assigned - 18 Mar 2011 - mcdurdin - I2825 - Debug_Keyman32 override not working correctly - 03 May 2011 - mcdurdin - I2890 - Record diagnostic data when encountering registry errors - 17 Aug 2012 - mcdurdin - I3310 - V9.0 - Unicode in Delphi fixes -*) -unit keyman32_int; - -interface - -uses Windows, SysUtils, Forms, ErrorControlledRegistry, RegistryKeys; //, util; - -function Keyman_Initialise(Handle: HWND; FSingleApp: Boolean): Boolean; -function Keyman_Exit: Boolean; -function Keyman_ForceKeyboard(const s: string): Boolean; -function Keyman_StopForcingKeyboard: Boolean; - -implementation - -uses DebugPaths, Dialogs, KLog; - -type TKeyman_ForceKeyboard = function (s: PAnsiChar): Boolean; stdcall; // I3310 -type TKeyman_StopForcingKeyboard = function: Boolean; stdcall; -type TKeyman_Initialise = function(h: THandle; FSingleApp: LongBool): Boolean; stdcall; -type TKeyman_Exit = function: Boolean; stdcall; - -var - FInitKeyman: Boolean = False; - FKeyman32Path: string = ''; - -function GetKeymanInstallPath: string; -var - RootPath: string; -begin - RootPath := ''; - with TRegistryErrorControlled.Create do // I2890 - try - RootKey := HKEY_LOCAL_MACHINE; - if OpenKeyReadOnly(SRegKey_KeymanEngine_LM) and ValueExists(SRegValue_RootPath) then - RootPath := ReadString(SRegValue_RootPath); - finally - Free; - end; - - RootPath := GetDebugPath('Debug_Keyman32Path', RootPath); // I2825 - - if RootPath = '' then - begin - RootPath := ExtractFilePath(ParamStr(0)); - end; - - Result := IncludeTrailingPathDelimiter(RootPath); - - if not FileExists(Result + 'keyman32.dll') then - raise Exception.Create( 'The executable keyman32.dll could not '+ - 'be found. You should reinstall.'); -end; - -function Keyman_Initialise(Handle: HWND; FSingleApp: Boolean): Boolean; -var - hkeyman: THandle; - FLoad: Boolean; - ki: TKeyman_Initialise; - s: string; -begin - Result := False; - FLoad := False; - hkeyman := GetModuleHandle('keyman32.dll'); - if hkeyman = 0 then - begin - s := GetKeymanInstallPath; - hkeyman := LoadLibrary(PChar(s+'keyman32.dll')); - if hkeyman = 0 then - begin - KL.LogError('Keyman_Initialise: Unable to load '+s+'keyman32.dll: '+SysErrorMessage(GetLastError)); - Exit; - end; - KL.Log('Keyman_Initialise: Loaded keyman32.dll'); - FLoad := True; - end - else - KL.Log('Keyman_Initialise: Found keyman32.dll already loaded'); - ki := TKeyman_Initialise(GetProcAddress(hkeyman, 'Keyman_Initialise')); - if not Assigned(@ki) then - begin - KL.LogError('Keyman_Initialise: Unable to find Keyman_Initialise in '+s+'keyman32.dll: '+SysErrorMessage(GetLastError)); - if FLoad then FreeLibrary(hkeyman); - Exit; - end; - if not ki(Handle, FSingleApp) then - begin - KL.LogError('Keyman_Initialise: Call to Keyman_Initialise in '+s+'keyman32.dll failed: '+SysErrorMessage(GetLastError)); - if FLoad then FreeLibrary(hkeyman); - Exit; - end; - - KL.Log('Keyman_Initialise: Loaded successfully'); - FInitKeyman := True; - Result := True; -end; - -function Keyman_Exit: Boolean; -var - hkeyman: THandle; - ke: TKeyman_Exit; -begin - if not FInitKeyman then - begin - Result := True; - Exit; - end; - Result := False; - hkeyman := GetModuleHandle('keyman32.dll'); - if hkeyman = 0 then Exit; - ke := TKeyman_Exit(GetProcAddress(hkeyman, 'Keyman_Exit')); - if not Assigned(@ke) then Exit; - if not ke then Exit; - if FInitKeyman then FreeLibrary(hkeyman); - FInitKeyman := False; - Result := True; -end; - -function Keyman_ForceKeyboard(const s: string): Boolean; -var - hkeyman: THandle; - fk: TKeyman_ForceKeyboard; -begin - Result := False; - hkeyman := GetModuleHandle('keyman32.dll'); - if hkeyman = 0 then - begin - KL.Log('Keyman_ForceKeyboard: Attempting to load keyman32.dll'); - if not Keyman_Initialise(Application.MainForm.Handle, True) then - begin - KL.LogError('Keyman_ForceKeyboard: Unable to load keyman32.dll'); - Exit; - end; - hkeyman := GetModuleHandle('keyman32.dll'); - if hkeyman = 0 then Exit; - end; - fk := TKeyman_ForceKeyboard(GetProcAddress(hkeyman, 'Keyman_ForceKeyboard')); - if(Assigned(@fk)) then - begin - Result := fk(PAnsiChar(AnsiString(s))); // todo: k9: unicode // I3310 - if not Result then KL.LogError('Keyman_ForceKeyboard in keyman32.dll failed: '+s) - else KL.Log('Keyman_ForceKeyboard: success'); - end - else - KL.LogError('Keyman_ForceKeyboard: failed to find Keyman_ForceKeyboard in keyman32.dll'); -end; - -function Keyman_StopForcingKeyboard: Boolean; -var - hkeyman: THandle; - sfk: TKeyman_StopForcingKeyboard; -begin - Result := False; - hkeyman := GetModuleHandle('keyman32.dll'); - if hkeyman = 0 then Exit; - sfk := TKeyman_StopForcingKeyboard(GetProcAddress(hkeyman, 'Keyman_StopForcingKeyboard')); - if(Assigned(@sfk)) then - Result := sfk; -end; - -initialization -finalization - Keyman_Exit; -end. - diff --git a/windows/src/support/Makefile b/windows/src/support/Makefile index 7f624d29f4..56609e21e4 100644 --- a/windows/src/support/Makefile +++ b/windows/src/support/Makefile @@ -3,9 +3,9 @@ # !ifdef NODELPHI -TARGETS=etl2log +TARGETS=etl2log texteditor !else -TARGETS=oskbulkrenderer etl2log +TARGETS=oskbulkrenderer etl2log texteditor !endif CLEANS=clean-support @@ -21,6 +21,10 @@ etl2log: .virtual cd $(ROOT)\src\support\etl2log $(MAKE) $(TARGET) +texteditor: .virtual + cd $(ROOT)\src\support\texteditor + $(MAKE) $(TARGET) + # ---------------------------------------------------------------------- clean-support: diff --git a/windows/src/support/texteditor/Makefile b/windows/src/support/texteditor/Makefile index a9fa1b1cd2..473bf57598 100644 --- a/windows/src/support/texteditor/Makefile +++ b/windows/src/support/texteditor/Makefile @@ -8,9 +8,9 @@ build: $(MSBUILD) editor.vcxproj $(MSBUILD_BUILD) /p:Platform=x86 $(MSBUILD) editor.vcxproj $(MSBUILD_BUILD) /p:Platform=x64 $(COPY) $(WIN32_TARGET_PATH)\editor32.exe $(PROGRAM)\support - $(COPY) $(WIN32_TARGET_PATH)\editor32.pdb $(PROGRAM)\support + $(COPY) $(WIN32_TARGET_PATH)\editor32.pdb $(DEBUGPATH)\support $(COPY) $(X64_TARGET_PATH)\editor64.exe $(PROGRAM)\support - $(COPY) $(X64_TARGET_PATH)\editor64.pdb $(PROGRAM)\support + $(COPY) $(X64_TARGET_PATH)\editor64.pdb $(DEBUGPATH)\support clean: def-clean $(MSBUILD) $(MSBUILD_CLEAN) editor.sln @@ -23,6 +23,12 @@ install: $(COPY) $(PROGRAM)\support\editor32.exe "$(INSTALLPATH_KEYMANENGINE)" $(COPY) $(PROGRAM)\support\editor64.exe "$(INSTALLPATH_KEYMANENGINE)" +wrap-symbols: + $(SYMSTORE) $(PROGRAM)\support\editor32.exe /t keyman-windows + $(SYMSTORE) $(PROGRAM)\support\editor64.exe /t keyman-windows + $(SYMSTORE) $(DEBUGPATH)\support\editor32.pdb /t keyman-windows + $(SYMSTORE) $(DEBUGPATH)\support\editor64.pdb /t keyman-windows + !include ..\..\Target.mak # ----------------------------------------------------------------------