chore(web): Merge branch 'feature-esmodule-web-engine' into chore/web/hardware-event-keyboard

This commit is contained in:
Joshua A. Horton 2023-05-23 11:50:54 +07:00
commit 2fe0d3c33a
113 changed files with 1641 additions and 3312 deletions

View file

@ -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)

View file

@ -1 +1 @@
17.0.106
17.0.110

View file

@ -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")

View file

@ -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);

View file

@ -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';

View file

@ -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)}`;
}

View file

@ -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"

View file

@ -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;
}

View file

@ -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<string,any>) {
let keys = Object.keys(source);
const keys = Object.keys(source);
const m = source as Record<string,any>;
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<string,any>) {
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<string,any>) {
codes.push(code);
}
}
}
}

View file

@ -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<WasmWrapper> {
return new WasmWrapper(await loadWasmHost());
}
};
export class KmnCompiler {
callbackName: string;
callbacks: CompilerCallbacks;
wasm: WasmWrapper;
constructor() {
this.callbackName = 'kmnCompilerCallback' + callbackProcIdentifier;
callbackProcIdentifier++;
}
public async init(): Promise<boolean> {
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<boolean> {
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;
}
}
}
/**
*
* @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;
}
}

View file

@ -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 {

View file

@ -1,2 +1,2 @@
export { Compiler } from './compiler/compiler.js';
export { KmnCompiler } from './compiler/compiler.js';

View file

@ -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);
}
}
});
});
});

View file

@ -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}`);
}
});
});

View file

@ -1,6 +1,6 @@
export default interface CompilerOptions {
export interface CompilerOptions {
/**
* Add debug information to the .kmx file when compiling
*/

View file

@ -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

View file

@ -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 =

View file

@ -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

View file

@ -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();

View file

@ -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";

View file

@ -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;
}

View file

@ -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);

View file

@ -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 "$@"
#-------------------------------------------------------------------------------------------------------------------

View file

@ -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 <Keyboard> 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) {

View file

@ -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 <Keyboards> but a corresponding .kmx file was not found in <Files>`);
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;
}

View file

@ -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;
}

View file

@ -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 <Keyboard> 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;
}
}

View file

@ -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',
];

View file

@ -17,6 +17,7 @@
</StartMenu>
<Info>
<Name URL="">Binary KVK File</Name>
<Version>1.3</Version>
</Info>
<Files>
<File>
@ -25,5 +26,21 @@
<CopyLocation>0</CopyLocation>
<FileType>.kvk</FileType>
</File>
<File>
<Name>../../invalid/khmer_angkor.kmx</Name>
<Description>Keyboard Khmer Angkor</Description>
<CopyLocation>0</CopyLocation>
<FileType>.kmx</FileType>
</File>
</Files>
<Keyboards>
<Keyboard>
<Name>Khmer Angkor</Name>
<ID>khmer_angkor</ID>
<Version>1.3</Version>
<Languages>
<Language ID="KM">Khmer</Language>
</Languages>
</Keyboard>
</Keyboards>
</Package>

View file

@ -9,11 +9,11 @@
<Name URL="">SENĆOŦEN (Saanich Dialect) Lexical Model</Name>
<Copyright URL="">© 2019 National Research Council Canada</Copyright>
<Author URL="mailto:Eddie.Santos@nrc-cnrc.gc.ca">Eddie Antonio Santos</Author>
<Version>1.0.3</Version>
<Version>1.3</Version>
</Info>
<Files>
<File>
<Name>nokeyboardversion.kmx</Name>
<Name>khmer_angkor.kmx</Name>
<Description>Keyboard Khmer Angkor</Description>
<CopyLocation>0</CopyLocation>
<FileType>.kmx</FileType>
@ -22,7 +22,7 @@
<Keyboards>
<Keyboard>
<Name>Khmer Angkor</Name>
<ID>nokeyboardversion</ID>
<ID>khmer_angkor</ID>
<Version>1.3</Version>
<Languages>
<Language ID="km">Central Khmer (Khmer, Cambodia)</Language>

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<Package>
<System>
<KeymanDeveloperVersion>15.0.266.0</KeymanDeveloperVersion>
<FileVersion>7.0</FileVersion>
</System>
<Info>
<Name URL="">SENĆOŦEN (Saanich Dialect) Lexical Model</Name>
<Copyright URL="">© 2019 National Research Council Canada</Copyright>
<Author URL="mailto:Eddie.Santos@nrc-cnrc.gc.ca">Eddie Antonio Santos</Author>
<Version>1.3</Version>
</Info>
<Files>
<File>
<Name>khmer_angkor.kmx</Name>
<Description>Keyboard Khmer Angkor</Description>
<CopyLocation>0</CopyLocation>
<FileType>.kmx</FileType>
</File>
</Files>
<Keyboards>
<Keyboard>
<Name>Khmer Angkor</Name>
<ID>khmer_angkor</ID>
<Version>1.3</Version>
<Languages>
<!-- ERROR_LanguageTagIsNotValid -->
<Language ID="en-au-latn">English (Australian script) as spoken in Latin</Language>
</Languages>
</Keyboard>
</Keyboards>
</Package>

View file

@ -8,12 +8,12 @@
<Name URL="">Khmer Angkor</Name>
<Copyright URL="">© 2015-2022 SIL International</Copyright>
<Author URL="mailto:makara_sok@sil.org">Makara Sok</Author>
<Version URL=""></Version>
<Version URL="">1.3</Version>
<WebSite URL="https://keyman.com/keyboards/khmer_angkor">https://keyman.com/keyboards/khmer_angkor</WebSite>
</Info>
<Files>
<File>
<Name>nokeyboardversion.kmx</Name>
<Name>khmer_angkor.kmx</Name>
<Description>Keyboard Khmer Angkor</Description>
<CopyLocation>0</CopyLocation>
<FileType>.kmx</FileType>
@ -39,7 +39,7 @@
<Keyboards>
<Keyboard>
<Name>Khmer Angkor</Name>
<ID>nokeyboardversion</ID>
<ID>khmer_angkor</ID>
<Version>1.3</Version>
<Languages>
<Language ID="km">Central Khmer (Khmer, Cambodia)</Language>

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<Package>
<System>
<KeymanDeveloperVersion>15.0.266.0</KeymanDeveloperVersion>
<FileVersion>7.0</FileVersion>
</System>
<Info>
<Name URL="">error_package_must_contain_a_model_or_a_keyboard</Name>
<Version>1.3</Version>
</Info>
<Files>
<File>
<!-- error_package_must_contain_a_model_or_a_keyboard. This is a common error:
to include a .kmn instead of a .kmx -->
<Name>khmer_angkor.kmn</Name>
<Description>Keyboard Khmer Angkor</Description>
<CopyLocation>0</CopyLocation>
<FileType>.kmn</FileType>
</File>
</Files>
</Package>

View file

@ -9,11 +9,11 @@
<Name URL=""> </Name>
<Copyright URL="">© 2019 National Research Council Canada</Copyright>
<Author URL="mailto:Eddie.Santos@nrc-cnrc.gc.ca">Eddie Antonio Santos</Author>
<Version>1.0.3</Version>
<Version>1.3</Version>
</Info>
<Files>
<File>
<Name>nokeyboardversion.kmx</Name>
<Name>khmer_angkor.kmx</Name>
<Description>Keyboard Khmer Angkor</Description>
<CopyLocation>0</CopyLocation>
<FileType>.kmx</FileType>
@ -22,7 +22,7 @@
<Keyboards>
<Keyboard>
<Name>Khmer Angkor</Name>
<ID>nokeyboardversion</ID>
<ID>khmer_angkor</ID>
<Version>1.3</Version>
<Languages>
<Language ID="km">Central Khmer (Khmer, Cambodia)</Language>

View file

@ -8,11 +8,11 @@
<!-- missing <Name/> -->
<Copyright URL="">© 2019 National Research Council Canada</Copyright>
<Author URL="mailto:Eddie.Santos@nrc-cnrc.gc.ca">Eddie Antonio Santos</Author>
<Version>1.0.3</Version>
<Version>1.3</Version>
</Info>
<Files>
<File>
<Name>nokeyboardversion.kmx</Name>
<Name>khmer_angkor.kmx</Name>
<Description>Keyboard Khmer Angkor</Description>
<CopyLocation>0</CopyLocation>
<FileType>.kmx</FileType>
@ -21,7 +21,7 @@
<Keyboards>
<Keyboard>
<Name>Khmer Angkor</Name>
<ID>nokeyboardversion</ID>
<ID>khmer_angkor</ID>
<Version>1.3</Version>
<Languages>
<Language ID="km">Central Khmer (Khmer, Cambodia)</Language>

View file

@ -0,0 +1,128 @@
<?xml version="1.0" encoding="utf-8"?>
<Package>
<System>
<KeymanDeveloperVersion>15.0.266.0</KeymanDeveloperVersion>
<FileVersion>7.0</FileVersion>
</System>
<Options>
<ExecuteProgram></ExecuteProgram>
<ReadMeFile>readme.htm</ReadMeFile>
<GraphicFile>splash.gif</GraphicFile>
<MSIFileName></MSIFileName>
<MSIOptions></MSIOptions>
<FollowKeyboardVersion/>
</Options>
<StartMenu>
<Folder></Folder>
<Items/>
</StartMenu>
<Info>
<Name URL="">Khmer Angkor</Name>
<Copyright URL="">© 2015-2022 SIL International</Copyright>
<Author URL="mailto:makara_sok@sil.org">Makara Sok</Author>
<Version URL=""></Version>
<WebSite URL="https://keyman.com/keyboards/khmer_angkor">https://keyman.com/keyboards/khmer_angkor</WebSite>
</Info>
<Files>
<!-- missing .kmx triggers this warning: We're moving towards requiring .kmx
even for mobile-only keyboards, and have made the decision not to attempt
to parse .js for the kmp compiler, because it is too fragile. -->
<File>
<Name>..\build\khmer_angkor.js</Name>
<Description>File khmer_angkor.js</Description>
<CopyLocation>0</CopyLocation>
<FileType>.js</FileType>
</File>
<File>
<Name>..\build\khmer_angkor.kvk</Name>
<Description>File khmer_angkor.kvk</Description>
<CopyLocation>0</CopyLocation>
<FileType>.kvk</FileType>
</File>
<File>
<Name>welcome\keyboard_layout.png</Name>
<Description>File keyboard_layout.png</Description>
<CopyLocation>0</CopyLocation>
<FileType>.png</FileType>
</File>
<File>
<Name>welcome\welcome.htm</Name>
<Description>File welcome.htm</Description>
<CopyLocation>0</CopyLocation>
<FileType>.htm</FileType>
</File>
<File>
<Name>..\shared\fonts\khmer\mondulkiri\FONTLOG.txt</Name>
<Description>File FONTLOG.txt</Description>
<CopyLocation>0</CopyLocation>
<FileType>.txt</FileType>
</File>
<File>
<Name>..\shared\fonts\khmer\mondulkiri\Mondulkiri-R.ttf</Name>
<Description>Font Khmer Mondulkiri</Description>
<CopyLocation>0</CopyLocation>
<FileType>.ttf</FileType>
</File>
<File>
<Name>..\shared\fonts\khmer\mondulkiri\OFL.txt</Name>
<Description>File OFL.txt</Description>
<CopyLocation>0</CopyLocation>
<FileType>.txt</FileType>
</File>
<File>
<Name>..\shared\fonts\khmer\mondulkiri\OFL-FAQ.txt</Name>
<Description>File OFL-FAQ.txt</Description>
<CopyLocation>0</CopyLocation>
<FileType>.txt</FileType>
</File>
<File>
<Name>welcome\KAK_Documentation_EN.pdf</Name>
<Description>File KAK_Documentation_EN.pdf</Description>
<CopyLocation>0</CopyLocation>
<FileType>.pdf</FileType>
</File>
<File>
<Name>welcome\KAK_Documentation_KH.pdf</Name>
<Description>File KAK_Documentation_KH.pdf</Description>
<CopyLocation>0</CopyLocation>
<FileType>.pdf</FileType>
</File>
<File>
<Name>readme.htm</Name>
<Description>File readme.htm</Description>
<CopyLocation>0</CopyLocation>
<FileType>.htm</FileType>
</File>
<File>
<Name>welcome\image002.png</Name>
<Description>File image002.png</Description>
<CopyLocation>0</CopyLocation>
<FileType>.png</FileType>
</File>
<File>
<Name>..\shared\fonts\khmer\busrakbd\khmer_busra_kbd.ttf</Name>
<Description>Font KhmerBusraKbd</Description>
<CopyLocation>0</CopyLocation>
<FileType>.ttf</FileType>
</File>
<File>
<Name>splash.gif</Name>
<Description>File splash.gif</Description>
<CopyLocation>0</CopyLocation>
<FileType>.gif</FileType>
</File>
</Files>
<Keyboards>
<Keyboard>
<Name>Khmer Angkor</Name>
<ID>khmer_angkor</ID>
<Version>1.3</Version>
<OSKFont>..\shared\fonts\khmer\busrakbd\khmer_busra_kbd.ttf</OSKFont>
<DisplayFont>..\shared\fonts\khmer\mondulkiri\Mondulkiri-R.ttf</DisplayFont>
<Languages>
<Language ID="km">Central Khmer (Khmer, Cambodia)</Language>
</Languages>
</Keyboard>
</Keyboards>
<Strings/>
</Package>

View file

@ -5,11 +5,6 @@
<FileVersion>7.0</FileVersion>
</System>
<Options>
<ExecuteProgram></ExecuteProgram>
<ReadMeFile>readme.htm</ReadMeFile>
<GraphicFile>splash.gif</GraphicFile>
<MSIFileName></MSIFileName>
<MSIOptions></MSIOptions>
<FollowKeyboardVersion/>
</Options>
<StartMenu>
@ -25,97 +20,18 @@
</Info>
<Files>
<File>
<Name>..\build\khmer_angkor.js</Name>
<Description>File khmer_angkor.js</Description>
<!-- File is missing -->
<Name>keyboardfilenotfound.kmx</Name>
<Description>Keyboard Khmer Angkor</Description>
<CopyLocation>0</CopyLocation>
<FileType>.js</FileType>
</File>
<File>
<Name>..\build\khmer_angkor.kvk</Name>
<Description>File khmer_angkor.kvk</Description>
<CopyLocation>0</CopyLocation>
<FileType>.kvk</FileType>
</File>
<File>
<Name>welcome\keyboard_layout.png</Name>
<Description>File keyboard_layout.png</Description>
<CopyLocation>0</CopyLocation>
<FileType>.png</FileType>
</File>
<File>
<Name>welcome\welcome.htm</Name>
<Description>File welcome.htm</Description>
<CopyLocation>0</CopyLocation>
<FileType>.htm</FileType>
</File>
<File>
<Name>..\shared\fonts\khmer\mondulkiri\FONTLOG.txt</Name>
<Description>File FONTLOG.txt</Description>
<CopyLocation>0</CopyLocation>
<FileType>.txt</FileType>
</File>
<File>
<Name>..\shared\fonts\khmer\mondulkiri\Mondulkiri-R.ttf</Name>
<Description>Font Khmer Mondulkiri</Description>
<CopyLocation>0</CopyLocation>
<FileType>.ttf</FileType>
</File>
<File>
<Name>..\shared\fonts\khmer\mondulkiri\OFL.txt</Name>
<Description>File OFL.txt</Description>
<CopyLocation>0</CopyLocation>
<FileType>.txt</FileType>
</File>
<File>
<Name>..\shared\fonts\khmer\mondulkiri\OFL-FAQ.txt</Name>
<Description>File OFL-FAQ.txt</Description>
<CopyLocation>0</CopyLocation>
<FileType>.txt</FileType>
</File>
<File>
<Name>welcome\KAK_Documentation_EN.pdf</Name>
<Description>File KAK_Documentation_EN.pdf</Description>
<CopyLocation>0</CopyLocation>
<FileType>.pdf</FileType>
</File>
<File>
<Name>welcome\KAK_Documentation_KH.pdf</Name>
<Description>File KAK_Documentation_KH.pdf</Description>
<CopyLocation>0</CopyLocation>
<FileType>.pdf</FileType>
</File>
<File>
<Name>readme.htm</Name>
<Description>File readme.htm</Description>
<CopyLocation>0</CopyLocation>
<FileType>.htm</FileType>
</File>
<File>
<Name>welcome\image002.png</Name>
<Description>File image002.png</Description>
<CopyLocation>0</CopyLocation>
<FileType>.png</FileType>
</File>
<File>
<Name>..\shared\fonts\khmer\busrakbd\khmer_busra_kbd.ttf</Name>
<Description>Font KhmerBusraKbd</Description>
<CopyLocation>0</CopyLocation>
<FileType>.ttf</FileType>
</File>
<File>
<Name>splash.gif</Name>
<Description>File splash.gif</Description>
<CopyLocation>0</CopyLocation>
<FileType>.gif</FileType>
<FileType>.kmx</FileType>
</File>
</Files>
<Keyboards>
<Keyboard>
<Name>Khmer Angkor</Name>
<ID>khmer_angkor</ID>
<ID>keyboardfilenotfound</ID>
<Version>1.3</Version>
<OSKFont>..\shared\fonts\khmer\busrakbd\khmer_busra_kbd.ttf</OSKFont>
<DisplayFont>..\shared\fonts\khmer\mondulkiri\Mondulkiri-R.ttf</DisplayFont>
<Languages>
<Language ID="km">Central Khmer (Khmer, Cambodia)</Language>
</Languages>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<Package>
<System>
<KeymanDeveloperVersion>15.0.266.0</KeymanDeveloperVersion>
<FileVersion>7.0</FileVersion>
</System>
<Info>
<Name URL="">SENĆOŦEN (Saanich Dialect) Lexical Model</Name>
<Copyright URL="">© 2019 National Research Council Canada</Copyright>
<Author URL="mailto:Eddie.Santos@nrc-cnrc.gc.ca">Eddie Antonio Santos</Author>
<Version>1.0.3</Version>
</Info>
<Files>
<File>
<Name>example.qaa.sencoten.model.js</Name>
<Description>Lexical model example.qaa.sencoten.model.js</Description>
<CopyLocation>0</CopyLocation>
<FileType>.model.js</FileType>
</File>
</Files>
<LexicalModels>
<LexicalModel>
<Name>SENĆOŦEN dictionary</Name>
<ID>example.qaa.sencoten</ID>
<!-- ERROR_LexicalModelMustHaveAtLeastOneLanguage -->
</LexicalModel>
</LexicalModels>
</Package>

Binary file not shown.

View file

@ -0,0 +1,6 @@
store(&name) 'version 4'
store(&keyboardversion) '4.0'
begin unicode > use(main)
group(main) using keys

Binary file not shown.

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<Package>
<System>
<KeymanDeveloperVersion>15.0.266.0</KeymanDeveloperVersion>
<FileVersion>7.0</FileVersion>
</System>
<Info>
<Name URL="">SENĆOŦEN (Saanich Dialect) Lexical Model</Name>
<Copyright URL="">© 2019 National Research Council Canada</Copyright>
<Author URL="mailto:Eddie.Santos@nrc-cnrc.gc.ca">Eddie Antonio Santos</Author>
<Version>1.3</Version>
</Info>
<Files>
<File>
<Name>khmer_angkor.kmx</Name>
<Description>Keyboard Khmer Angkor</Description>
<CopyLocation>0</CopyLocation>
<FileType>.kmx</FileType>
</File>
<!-- warn_doc_file_dangerous -->
<File>
<Name>khmer_angkor.docx</Name>
<Description>Documentation</Description>
<CopyLocation>0</CopyLocation>
<FileType>.docx</FileType>
</File>
</Files>
<Keyboards>
<Keyboard>
<Name>Khmer Angkor</Name>
<ID>khmer_angkor</ID>
<Version>1.3</Version>
<Languages>
<Language ID="KM">Khmer</Language>
</Languages>
</Keyboard>
</Keyboards>
</Package>

View file

@ -8,7 +8,7 @@
<Name URL="">SENĆOŦEN (Saanich Dialect) Lexical Model</Name>
<Copyright URL="">© 2019 National Research Council Canada</Copyright>
<Author URL="mailto:Eddie.Santos@nrc-cnrc.gc.ca">Eddie Antonio Santos</Author>
<Version>1.0.3</Version>
<Version>1.3</Version>
</Info>
<Files>
<File>
@ -22,7 +22,7 @@
<Keyboards>
<Keyboard>
<Name>Khmer Angkor</Name>
<ID>nokeyboardversion</ID>
<ID>my special keyboard</ID>
<Version>1.3</Version>
<Languages>
<Language ID="km">Central Khmer (Khmer, Cambodia)</Language>

View file

@ -8,12 +8,19 @@
<Name URL="">SENĆOŦEN (Saanich Dialect) Lexical Model</Name>
<Copyright URL="">© 2019 National Research Council Canada</Copyright>
<Author URL="mailto:Eddie.Santos@nrc-cnrc.gc.ca">Eddie Antonio Santos</Author>
<Version>1.0.3</Version>
<Version>1.3</Version>
</Info>
<Files>
<File>
<!-- extension should not have capitals -->
<Name>my_special-keyboard.KMX</Name>
<Name>my_file.PDF</Name>
<Description>My Documentation</Description>
<CopyLocation>0</CopyLocation>
<FileType>.PDF</FileType>
</File>
<File>
<!-- extension should not have capitals -->
<Name>khmer_angkor.kmx</Name>
<Description>Keyboard my special keyboard</Description>
<CopyLocation>0</CopyLocation>
<FileType>.kmx</FileType>
@ -22,7 +29,7 @@
<Keyboards>
<Keyboard>
<Name>Khmer Angkor</Name>
<ID>nokeyboardversion</ID>
<ID>khmer_angkor</ID>
<Version>1.3</Version>
<Languages>
<Language ID="km">Central Khmer (Khmer, Cambodia)</Language>

View file

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<Package>
<System>
<KeymanDeveloperVersion>15.0.266.0</KeymanDeveloperVersion>
<FileVersion>7.0</FileVersion>
</System>
<Info>
<Name URL="">SENĆOŦEN (Saanich Dialect) Lexical Model</Name>
<Copyright URL="">© 2019 National Research Council Canada</Copyright>
<Author URL="mailto:Eddie.Santos@nrc-cnrc.gc.ca">Eddie Antonio Santos</Author>
<Version>1.3</Version>
</Info>
<Files>
<File>
<Name>khmer_angkor.kmx</Name>
<Description>Keyboard Khmer Angkor</Description>
<CopyLocation>0</CopyLocation>
<FileType>.kmx</FileType>
</File>
<File>
<Name>version_four.kmx</Name>
<Description>Keyboard Version Four</Description>
<CopyLocation>0</CopyLocation>
<FileType>.kmx</FileType>
</File>
</Files>
<Keyboards>
<Keyboard>
<Name>Khmer Angkor</Name>
<ID>khmer_angkor</ID>
<Version>1.3</Version>
<Languages>
<Language ID="km">Khmer</Language>
</Languages>
</Keyboard>
<Keyboard>
<Name>Version 4</Name>
<ID>version_four</ID>
<Version>4.0</Version>
<Languages>
<Language ID="km">Khmer</Language>
</Languages>
</Keyboard>
</Keyboards>
</Package>

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<Package>
<System>
<KeymanDeveloperVersion>15.0.266.0</KeymanDeveloperVersion>
<FileVersion>7.0</FileVersion>
</System>
<Info>
<Name URL="">SENĆOŦEN (Saanich Dialect) Lexical Model</Name>
<Copyright URL="">© 2019 National Research Council Canada</Copyright>
<Author URL="mailto:Eddie.Santos@nrc-cnrc.gc.ca">Eddie Antonio Santos</Author>
<Version>1.3</Version>
</Info>
<Files>
<File>
<Name>version_four.kmx</Name>
<Description>Keyboard Version Four</Description>
<CopyLocation>0</CopyLocation>
<FileType>.kmx</FileType>
</File>
</Files>
<Keyboards>
<Keyboard>
<Name>Version 4</Name>
<ID>version_four</ID>
<Version>4.0</Version>
<Languages>
<Language ID="km">Khmer</Language>
</Languages>
</Keyboard>
</Keyboards>
</Package>

View file

@ -4,10 +4,15 @@
<KeymanDeveloperVersion>15.0.266.0</KeymanDeveloperVersion>
<FileVersion>7.0</FileVersion>
</System>
<!-- Missing <Info>/<Name/> -->
<Info>
<Name URL="">SENĆOŦEN (Saanich Dialect) Lexical Model</Name>
<Copyright URL="">© 2019 National Research Council Canada</Copyright>
<Author URL="mailto:Eddie.Santos@nrc-cnrc.gc.ca">Eddie Antonio Santos</Author>
<Version>1.3</Version>
</Info>
<Files>
<File>
<Name>nokeyboardversion.kmx</Name>
<Name>khmer_angkor.kmx</Name>
<Description>Keyboard Khmer Angkor</Description>
<CopyLocation>0</CopyLocation>
<FileType>.kmx</FileType>
@ -16,10 +21,11 @@
<Keyboards>
<Keyboard>
<Name>Khmer Angkor</Name>
<ID>nokeyboardversion</ID>
<ID>khmer_angkor</ID>
<Version>1.3</Version>
<Languages>
<Language ID="km">Central Khmer (Khmer, Cambodia)</Language>
<!-- WARN_LanguageTagIsNotMinimal -->
<Language ID="km-Khmr-KH">Central Khmer (Khmer, Cambodia)</Language>
</Languages>
</Keyboard>
</Keyboards>

View file

@ -8,11 +8,11 @@
<Name URL="">SENĆOŦEN (Saanich Dialect) Lexical Model</Name>
<Copyright URL="">© 2019 National Research Council Canada</Copyright>
<Author URL="mailto:Eddie.Santos@nrc-cnrc.gc.ca">Eddie Antonio Santos</Author>
<Version>1.0.3</Version>
<Version>1.3</Version>
</Info>
<Files>
<File>
<Name>nokeyboardversion.kmx</Name>
<Name>khmer_angkor.kmx</Name>
<Description>Keyboard Khmer Angkor</Description>
<CopyLocation>0</CopyLocation>
<FileType>.kmx</FileType>
@ -21,7 +21,7 @@
<Keyboards>
<Keyboard>
<Name>Khmer Angkor</Name>
<ID>nokeyboardversion</ID>
<ID>khmer_angkor</ID>
<Version>1.3</Version>
<Languages>
<!-- WARN_PackageShouldNotRepeatLanguages -->

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<Package>
<System>
<KeymanDeveloperVersion>15.0.266.0</KeymanDeveloperVersion>
<FileVersion>7.0</FileVersion>
</System>
<Info>
<Name URL="">SENĆOŦEN (Saanich Dialect) Lexical Model</Name>
<Copyright URL="">© 2019 National Research Council Canada</Copyright>
<Author URL="mailto:Eddie.Santos@nrc-cnrc.gc.ca">Eddie Antonio Santos</Author>
<Version>1.3</Version>
</Info>
<Files>
<File>
<Name>khmer_angkor.kmx</Name>
<Description>Keyboard Khmer Angkor</Description>
<CopyLocation>0</CopyLocation>
<FileType>.kmx</FileType>
</File>
<!-- warn_redist_file_should_not_be_in_package -->
<File>
<Name>keyman.exe</Name>
<Description>Keyman Program</Description>
<CopyLocation>0</CopyLocation>
<FileType>.exe</FileType>
</File>
</Files>
<Keyboards>
<Keyboard>
<Name>Khmer Angkor</Name>
<ID>khmer_angkor</ID>
<Version>1.3</Version>
<Languages>
<Language ID="KM">Khmer</Language>
</Languages>
</Keyboard>
</Keyboards>
</Package>

View file

@ -17,6 +17,7 @@
</StartMenu>
<Info>
<Name URL="">XML KVK File</Name>
<Version>1.3</Version>
</Info>
<Files>
<File>
@ -25,5 +26,21 @@
<CopyLocation>0</CopyLocation>
<FileType>.kvk</FileType>
</File>
<File>
<Name>../../invalid/khmer_angkor.kmx</Name>
<Description>Keyboard Khmer Angkor</Description>
<CopyLocation>0</CopyLocation>
<FileType>.kmx</FileType>
</File>
</Files>
<Keyboards>
<Keyboard>
<Name>Khmer Angkor</Name>
<ID>khmer_angkor</ID>
<Version>1.3</Version>
<Languages>
<Language ID="KM">Khmer</Language>
</Languages>
</Keyboard>
</Keyboards>
</Package>

View file

@ -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 <FollowKeyboardVersion> 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 <FollowKeyboardVersion> 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 <Keyboard> is listed in a package but not found in <Files>', async function() {
testForMessage(this, ['invalid', 'keyboardfilenotfound.kps'], CompilerMessages.ERROR_KeyboardFileNotFound);
it('should generate ERROR_KeyboardContentFileNotFound if a <Keyboard> is listed in a package but not found in <Files>', 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 <FollowKeyboardVersion> is set but keyboard has no version', async function() {
testForMessage(this, ['invalid', 'nokeyboardversion.kps'], CompilerMessages.WARN_KeyboardFileHasNoKeyboardVersion);
it('should generate INFO_KeyboardFileHasNoKeyboardVersion if <FollowKeyboardVersion> 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 <Keyboard> is listed in a package but not found in <Files>', async function() {
testForMessage(this, ['invalid', 'keyboardfilenotfound.kps'], CompilerMessages.ERROR_KeyboardFileNotFound);
});
// WARN_KeyboardVersionsDoNotMatch
it('should generate WARN_KeyboardVersionsDoNotMatch if two <Keyboards> 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 <Keyboard> 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);
});
});

View file

@ -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<boolean> {
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;
}
}

View file

@ -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);

View file

@ -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;

View file

@ -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

View file

@ -18,7 +18,7 @@
<Name URL="">k_000___null_keyboard</Name>
<Copyright URL="">Copyright (C) Keyman Team</Copyright>
<Author URL="">Keyman Team</Author>
<Version URL=""></Version>
<Version URL="">0.0</Version>
</Info>
<Files>
<File>

View file

@ -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);
});
});

View file

@ -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

View file

@ -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;
}
}

View file

@ -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.

View file

@ -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

View file

@ -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"

View file

@ -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()
}
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -6,10 +6,6 @@
"types": "./build/engine/attachment/obj/index.d.ts",
"import": "./build/engine/attachment/obj/index.js"
},
"./engine/attachment/lib": {
"types": "./build/engine/attachment/obj/index.d.ts",
"import": "./build/engine/attachment/lib/index.mjs"
},
"./engine/paths": {
"types": "./build/engine/paths/obj/index.d.ts",
"import": "./build/engine/paths/obj/index.js"
@ -18,10 +14,6 @@
"types": "./build/engine/device-detect/obj/index.d.ts",
"import": "./build/engine/device-detect/obj/index.js"
},
"./engine/device-detect/lib": {
"types": "./build/engine/device-detect/lib/index.d.ts",
"import": "./build/engine/device-detect/lib/index.mjs"
},
"./engine/dom-utils": {
"types": "./build/engine/dom-utils/obj/index.d.ts",
"import": "./build/engine/dom-utils/obj/index.js"
@ -30,10 +22,6 @@
"types": "./build/engine/element-wrappers/obj/index.d.ts",
"import": "./build/engine/element-wrappers/obj/index.js"
},
"./engine/element-wrappers/lib": {
"types": "./build/engine/element-wrappers/lib/index.d.ts",
"import": "./build/engine/element-wrappers/lib/index.mjs"
},
"./engine/events": {
"types": "./build/engine/events/obj/index.d.ts",
"import": "./build/engine/events/obj/index.js"
@ -43,41 +31,21 @@
"import": "./build/engine/package-cache/obj/index.js",
"require": "./build/engine/package-cache/obj/index.js"
},
"./engine/package-cache/lib": {
"types": "./build/engine/package-cache/lib/index.d.ts",
"import": "./build/engine/package-cache/lib/index.mjs"
},
"./engine/package-cache/dom-requester": {
"types": "./build/engine/package-cache/obj/domCloudRequester.d.ts",
"import": "./build/engine/package-cache/obj/domCloudRequester.js"
},
"./engine/package-cache/dom-requester/lib": {
"types": "./build/engine/package-cache/lib/index.d.ts",
"import": "./build/engine/package-cache/lib/dom-cloud-requester.mjs"
},
"./engine/package-cache/node-requester": {
"types": "./build/engine/package-cache/obj/nodeCloudRequester.d.ts",
"import": "./build/engine/package-cache/obj/nodeCloudRequester.js"
},
"./engine/package-cache/node-requester/lib": {
"types": "./build/engine/package-cache/lib/index.d.ts",
"import": "./build/engine/package-cache/lib/node-cloud-requester.mjs"
},
"./engine/main": {
"types": "./build/engine/main/obj/index.d.ts",
"import": "./build/engine/main/obj/index.js"
},
"./engine/main/lib": {
"types": "./build/engine/main/lib/index.d.ts",
"import": "./build/engine/main/lib/index.mjs"
},
"./engine/osk": {
"types": "./build/engine/osk/obj/index.d.ts",
"import": "./build/engine/osk/obj/index.js"
},
"./engine/osk/lib": {
"types": "./build/engine/osk/lib/index.d.ts",
"import": "./build/engine/osk/lib/index.mjs"
}
},
"repository": {

View file

@ -34,24 +34,24 @@ export default class DefaultBrowserRules extends DefaultRules {
applyCommand(Lkc: KeyEvent, outputTarget: OutputTarget): void {
let code = this.codeForEvent(Lkc);
const contextManager = this.contextManager;
const moveToNext = (back: boolean) => {
const contextManager = this.contextManager;
const activeElement = contextManager.activeTarget?.getElement();
const nextElement = contextManager.page.findNeighboringInput(activeElement, back);
nextElement.focus();
}
let elem: HTMLElement;
switch(code) {
// This method will be handled between `ContextManager` and PageContextAttachment:
// pageContextAttachment.findNeighboringInput(contextManager.activeTarget.getElement(), <same flag>)
case Codes.keyCodes['K_TAB']:
const bBack = (Lkc.Lmodifiers & Codes.modifierCodes['SHIFT']) != 0;
elem = contextManager.page.findNeighboringInput(contextManager.activeTarget.getElement(), bBack);
elem.focus();
moveToNext((Lkc.Lmodifiers & Codes.modifierCodes['SHIFT']) != 0);
break;
case Codes.keyCodes['K_TABBACK']:
elem = contextManager.page.findNeighboringInput(contextManager.activeTarget.getElement(), true);
elem.focus();
moveToNext(true);
break;
case Codes.keyCodes['K_TABFWD']:
elem = contextManager.page.findNeighboringInput(contextManager.activeTarget.getElement(), false);
elem.focus();
moveToNext(false);
break;
}

View file

@ -37,11 +37,9 @@ export class KeymanEngine extends KeymanEngineBase<ContextManager, HardwareEvent
// Get the absolute position of the caret
const y = getAbsoluteY(e);
const t = window.pageYOffset;
let dy = 0;
if(y < t) {
dy=y-t;
} else {
dy=y-t-(window.innerHeight - this.osk._Box.offsetHeight-e.offsetHeight-2);
let dy = y-t;
if(y >= t) {
dy -= (window.innerHeight - this.osk._Box.offsetHeight - e.offsetHeight - 2);
if(dy < 0) {
dy=0;
}

View file

@ -35,7 +35,7 @@ export function setupOskListeners(engine: KeymanEngine, osk: OSKView, contextMan
osk.on('showBuild', () => {
internalAlert('KeymanWeb Version ' + KEYMAN_VERSION.VERSION + '<br /><br />'
+'<span style="font-size:0.8em">Copyright &copy; 2021 SIL International</span>');
+'<span style="font-size:0.8em">Copyright &copy; 2007-2023 SIL International</span>');
});
osk.on('dragMove', async (promise) => {

View file

@ -1,8 +1,4 @@
#!/usr/bin/env bash
#
# set -x
set -eu
## START STANDARD BUILD SCRIPT INCLUDE
# adjust relative paths as necessary
@ -10,15 +6,14 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
. "${THIS_SCRIPT%/*}/../../../../resources/build/build-utils.sh"
## END STANDARD BUILD SCRIPT INCLUDE
# Imports common Web build-script definitions & functions
SUBPROJECT_NAME=engine/attachment
. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh"
. "$KEYMAN_ROOT/web/common.inc.sh"
# This script runs from its own folder
cd "$THIS_SCRIPT_PATH"
# Imports common Web build-script definitions & functions
SUBPROJECT_NAME=engine/attachment
. "$KEYMAN_ROOT/web/common.inc.sh"
# ################################ Main script ################################
builder_describe "Builds the Keyman Engine for Web (KMW) attachment engine." \
@ -40,26 +35,7 @@ builder_parse "$@"
#### Build action definitions ####
if builder_start_action configure; then
verify_npm_setup
builder_finish_action success configure
fi
if builder_start_action clean; then
rm -rf "$KEYMAN_ROOT/web/build/$SUBPROJECT_NAME"
builder_finish_action success clean
fi
if builder_start_action build; then
compile $SUBPROJECT_NAME
builder_finish_action success build
fi
if builder_start_action test; then
# No HEADLESS tests yet.
# TODO: DOM tests
builder_finish_action success test
fi
builder_run_action configure verify_npm_setup
builder_run_action clean rm -rf "$KEYMAN_ROOT/web/build/$SUBPROJECT_NAME"
builder_run_action build compile $SUBPROJECT_NAME
builder_run_action test # No headless tests; TODO (next PR): DOM tests

View file

@ -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;
}

View file

@ -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");
}

View file

@ -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);

View file

@ -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);
}
}
}

View file

@ -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 */

View file

@ -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;

View file

@ -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

View file

@ -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
};

View file

@ -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<LPCWSTR>(imx_list->library_name)));
if (imd && AddIMDLLHookCore(imd, wstrtostr(reinterpret_cast<LPCWSTR>(imx_list->function_name)), imx_list->imx_id)) {
if (imd && AddIMDLLHook(imd, wstrtostr(reinterpret_cast<LPCWSTR>(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<PCWSTR>(imx_list->library_name)),
wstrtostr(reinterpret_cast<PCWSTR>(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;
}

View file

@ -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);

View file

@ -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);
}
}
}

View file

@ -20,8 +20,5 @@
#define __CAPSSTATE_H
BOOL IsCapsLockOn(void);
void ResetCapsLock(void);
void KeyCapsLockPress(BOOL FIsUp);
void KeyShiftPress(BOOL FIsUp);
#endif

View file

@ -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 */

View file

@ -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);
}

View file

@ -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) &&

View file

@ -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<LPCWSTR>(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<LPCWSTR>(retValue), reinterpret_cast<LPCWSTR>(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;
}

View file

@ -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);

View file

@ -59,7 +59,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LibraryPath>$(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\src;$(ProjectDir)..\..\..\..\core\build\rust\x86\$(Configuration);$(LibraryPath)</LibraryPath>
<IncludePath>$(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\include;$(IncludePath)</IncludePath>
<IncludePath>$(ProjectDir)..\..\..\..\common\include;$(ProjectDir)..\..\..\..\core\include;$(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\include;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Midl>
@ -186,12 +186,6 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="$(KEYMAN_ROOT)\common\windows\cpp\src\xstring.cpp" />
<ClCompile Include="addins.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="appint\aiTIP.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -403,4 +397,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View file

@ -15,9 +15,6 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="addins.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="appint\aiTIP.cpp">
<Filter>Source Files</Filter>
</ClCompile>

View file

@ -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;
}
/**

View file

@ -4,8 +4,6 @@ EXPORTS
Keyman_GetInitialised
Keyman_Initialise
Keyman_Exit
Keyman_ForceKeyboard
Keyman_StopForcingKeyboard
Keyman_GetLastActiveWindow
Keyman_GetLastFocusWindow
KMSetOutput

View file

@ -176,12 +176,6 @@
<ItemGroup>
<ClCompile Include="..\..\global\cpp\kmtip_guids.cpp" />
<ClCompile Include="$(KEYMAN_ROOT)\common\windows\cpp\src\xstring.cpp" />
<ClCompile Include="addins.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="appint\aiTIP.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -362,7 +356,6 @@
<ItemGroup>
<ClInclude Include="keymanengine.h" />
<ClInclude Include="..\..\..\include\kmtip_guids.h" />
<ClInclude Include="addins.h" />
<ClInclude Include="appint\aiTIP.h" />
<ClInclude Include="appint\aiWin2000Unicode.h" />
<ClInclude Include="appint\appint.h" />

View file

@ -15,9 +15,6 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="addins.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="appint\aiTIP.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@ -162,9 +159,6 @@
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="addins.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="appint\aiTIP.h">
<Filter>Header Files</Filter>
</ClInclude>

View file

@ -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"

View file

@ -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();
}
}

Some files were not shown because too many files have changed in this diff Show more