mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-13 12:19:25 +00:00
chore(web): Merge branch 'master' into chore/web/merge-master-esmodule-a17s13-mid
This commit is contained in:
commit
ca894d0991
108 changed files with 1621 additions and 3234 deletions
31
HISTORY.md
31
HISTORY.md
|
|
@ -1,5 +1,36 @@
|
|||
# Keyman Version History
|
||||
|
||||
## 17.0.109 alpha 2023-05-17
|
||||
|
||||
* fix(windows): add wrap-symbols to Text Editor Makefile (#8819)
|
||||
* chore(linux): Make postinst script comply with Debian policy (#8810)
|
||||
* chore(windows): remove legacy core and flag ️ (#8593)
|
||||
|
||||
## 17.0.108 alpha 2023-05-16
|
||||
|
||||
* feat(windows): add text editor to the support makefile (#8750)
|
||||
* feat(developer): verify keyboard versions in kmc-package (#8769)
|
||||
* feat(developer): verify bcp47 tags are valid and minimal in kmc-package (#8778)
|
||||
* feat(developer): verify at least one language in package (#8783)
|
||||
* chore(developer): verify file types of content files in package (#8792)
|
||||
* chore(developer): verify that package has at least a model or keyboard (#8793)
|
||||
* chore(ios): Changes required for XCode 14.3 (#8746)
|
||||
|
||||
## 17.0.107 alpha 2023-05-15
|
||||
|
||||
* chore(linux): Fix installation build step on TC (#8784)
|
||||
* refactor(android/engine): Consolidate updateSelection (#8739)
|
||||
|
||||
## 17.0.106 alpha 2023-05-12
|
||||
|
||||
* chore(developer): move package formats to common/web/types (#8729)
|
||||
* feat(developer): add package validation (#8740)
|
||||
* feat(developer): add validation of package filenames (#8751)
|
||||
* feat(developer): validate content file names in packages (#8755)
|
||||
* feat(developer): validate package name in compiler (#8757)
|
||||
* chore(developer): rename Compiler and related classes (#8726)
|
||||
* feat(developer): uset api from wasm! (#8716)
|
||||
|
||||
## 17.0.105 alpha 2023-05-11
|
||||
|
||||
* chore(common): Update crowdin strings for Amharic (#8748)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
17.0.106
|
||||
17.0.110
|
||||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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)}`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
|
||||
export { Compiler } from './compiler/compiler.js';
|
||||
export { KmnCompiler } from './compiler/compiler.js';
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
66
developer/src/kmc-kmn/test/test-wasm-uset.ts
Normal file
66
developer/src/kmc-kmn/test/test-wasm-uset.ts
Normal 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}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
|
||||
export default interface CompilerOptions {
|
||||
export interface CompilerOptions {
|
||||
/**
|
||||
* Add debug information to the .kmx file when compiling
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 "$@"
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
64
developer/src/kmc-package/src/compiler/redist-files.ts
Normal file
64
developer/src/kmc-package/src/compiler/redist-files.ts
Normal 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',
|
||||
];
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
32
developer/src/kmc-package/test/fixtures/invalid/error_language_tag_is_not_valid.kps
vendored
Normal file
32
developer/src/kmc-package/test/fixtures/invalid/error_language_tag_is_not_valid.kps
vendored
Normal 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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
128
developer/src/kmc-package/test/fixtures/invalid/keyboardcontentfilenotfound.kps
vendored
Normal file
128
developer/src/kmc-package/test/fixtures/invalid/keyboardcontentfilenotfound.kps
vendored
Normal 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>
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
BIN
developer/src/kmc-package/test/fixtures/invalid/khmer_angkor.kmx
vendored
Normal file
BIN
developer/src/kmc-package/test/fixtures/invalid/khmer_angkor.kmx
vendored
Normal file
Binary file not shown.
BIN
developer/src/kmc-package/test/fixtures/invalid/my special keyboard.kmx
vendored
Normal file
BIN
developer/src/kmc-package/test/fixtures/invalid/my special keyboard.kmx
vendored
Normal file
Binary file not shown.
BIN
developer/src/kmc-package/test/fixtures/invalid/my_special-keyboard.kmx
vendored
Normal file
BIN
developer/src/kmc-package/test/fixtures/invalid/my_special-keyboard.kmx
vendored
Normal file
Binary file not shown.
6
developer/src/kmc-package/test/fixtures/invalid/version_four.kmn
vendored
Normal file
6
developer/src/kmc-package/test/fixtures/invalid/version_four.kmn
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
store(&name) 'version 4'
|
||||
store(&keyboardversion) '4.0'
|
||||
|
||||
begin unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
BIN
developer/src/kmc-package/test/fixtures/invalid/version_four.kmx
vendored
Normal file
BIN
developer/src/kmc-package/test/fixtures/invalid/version_four.kmx
vendored
Normal file
Binary file not shown.
38
developer/src/kmc-package/test/fixtures/invalid/warn_doc_file_dangerous.kps
vendored
Normal file
38
developer/src/kmc-package/test/fixtures/invalid/warn_doc_file_dangerous.kps
vendored
Normal 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>
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
45
developer/src/kmc-package/test/fixtures/invalid/warn_keyboard_versions_do_not_match.kps
vendored
Normal file
45
developer/src/kmc-package/test/fixtures/invalid/warn_keyboard_versions_do_not_match.kps
vendored
Normal 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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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 -->
|
||||
|
|
|
|||
38
developer/src/kmc-package/test/fixtures/invalid/warn_redist_file_should_not_be_in_package.kps
vendored
Normal file
38
developer/src/kmc-package/test/fixtures/invalid/warn_redist_file_should_not_be_in_package.kps
vendored
Normal 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>
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,8 +20,5 @@
|
|||
#define __CAPSSTATE_H
|
||||
|
||||
BOOL IsCapsLockOn(void);
|
||||
void ResetCapsLock(void);
|
||||
void KeyCapsLockPress(BOOL FIsUp);
|
||||
void KeyShiftPress(BOOL FIsUp);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) &&
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ EXPORTS
|
|||
Keyman_GetInitialised
|
||||
Keyman_Initialise
|
||||
Keyman_Exit
|
||||
Keyman_ForceKeyboard
|
||||
Keyman_StopForcingKeyboard
|
||||
Keyman_GetLastActiveWindow
|
||||
Keyman_GetLastFocusWindow
|
||||
KMSetOutput
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,7 +119,6 @@ Process_Event_Core(PKEYMAN64THREADDATA _td) {
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* BOOL ProcessHook();
|
||||
*
|
||||
|
|
@ -138,10 +137,7 @@ BOOL ProcessHook()
|
|||
PKEYMAN64THREADDATA _td = ThreadGlobals();
|
||||
if(!_td) return FALSE;
|
||||
|
||||
LPGROUP gp = _td->state.startgroup;
|
||||
|
||||
fOutputKeystroke = FALSE; // TODO: 5442 no longer needs to be global once we use core processor
|
||||
BOOL isUsingCoreProcessor = Globals::get_CoreIntegration();
|
||||
//
|
||||
// If we are running in the debugger, don't do a second run through
|
||||
//
|
||||
|
|
@ -160,44 +156,28 @@ BOOL ProcessHook()
|
|||
Debug_VirtualKey(_td->state.vkey), getcontext_debug());
|
||||
}
|
||||
|
||||
AIDEBUGKEYINFO keyinfo;
|
||||
keyinfo.shiftFlags = Globals::get_ShiftState();
|
||||
keyinfo.VirtualKey = _td->state.vkey;
|
||||
keyinfo.Character = _td->state.charCode;
|
||||
keyinfo.DeadKeyCharacter = 0; // I4582
|
||||
keyinfo.IsUp = !_td->state.isDown;
|
||||
if(_td->app->IsUnicode())
|
||||
_td->app->QueueDebugInformation(QID_BEGIN_UNICODE, NULL, NULL, NULL, NULL, (DWORD_PTR) &keyinfo);
|
||||
else
|
||||
_td->app->QueueDebugInformation(QID_BEGIN_ANSI, NULL, NULL, NULL, NULL, (DWORD_PTR) &keyinfo);
|
||||
}
|
||||
|
||||
if (isUsingCoreProcessor) { // TODO: 5442 Note: Nested if will be reduced once using core only
|
||||
// For applications not using the TSF kmtip calls this function twice for each keystroke,
|
||||
// first to determine if we are doing processing work (TIPFUpdateable == FALSE),
|
||||
// if we say yes it will call a second time to actually do the work.
|
||||
// We call the core process event only once and use the core's queued actions
|
||||
// on the second pass.
|
||||
// For the TSF in most cases kmtip (except OnPreservedKey) will not call the non-updateable test parse.
|
||||
// Therfore the core process event will need to be called before processing the actions.
|
||||
// For applications not using the TSF kmtip calls this function twice for each keystroke,
|
||||
// first to determine if we are doing processing work (TIPFUpdateable == FALSE),
|
||||
// if we say yes it will call a second time to actually do the work.
|
||||
// We call the core process event only once and use the core's queued actions
|
||||
// on the second pass.
|
||||
// For the TSF in most cases kmtip (except OnPreservedKey) will not call the non-updateable test parse.
|
||||
// Therfore the core process event will need to be called before processing the actions.
|
||||
|
||||
// CoreProcessEventRun would be a sufficient test however testing TIPFUpdateable defines
|
||||
// the status of the keystroke processing more precisely.
|
||||
if (!_td->TIPFUpdateable || !_td->CoreProcessEventRun) {
|
||||
if (!Process_Event_Core(_td)) {
|
||||
return FALSE;
|
||||
}
|
||||
// CoreProcessEventRun would be a sufficient test however testing TIPFUpdateable defines
|
||||
// the status of the keystroke processing more precisely.
|
||||
if (!_td->TIPFUpdateable || !_td->CoreProcessEventRun) {
|
||||
if (!Process_Event_Core(_td)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!_td->TIPFUpdateable) {
|
||||
ProcessActionsNonUpdatableParse(&fOutputKeystroke);
|
||||
} else {
|
||||
ProcessActions(&fOutputKeystroke);
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
ProcessGroup(gp); // TODO: 5442 remove
|
||||
|
||||
if (!_td->TIPFUpdateable) {
|
||||
ProcessActionsNonUpdatableParse(&fOutputKeystroke);
|
||||
} else {
|
||||
ProcessActions(&fOutputKeystroke);
|
||||
}
|
||||
|
||||
if (fOutputKeystroke && !_td->app->IsQueueEmpty()) {
|
||||
|
|
@ -256,671 +236,9 @@ BOOL ProcessHook()
|
|||
// PWSTR contextBuf = _td->app->ContextBufMax(MAXCONTEXT);
|
||||
// SendDebugMessageFormat(0, sdmAIDefault, 0, "Kmprocess::ProcessHook After cxt=%s", Debug_UnicodeString(contextBuf, 1));
|
||||
|
||||
_td->app->QueueDebugInformation(QID_END, NULL, NULL, NULL, NULL, 0);
|
||||
return !fOutputKeystroke;
|
||||
}
|
||||
|
||||
/*
|
||||
* PRIVATE BOOL ProcessGroup(LPGROUP gp);
|
||||
*
|
||||
* Parameters: gp Pointer to group to process inside
|
||||
*
|
||||
* Returns: TRUE if messages are to be sent,
|
||||
* and FALSE if no messages are to be sent.
|
||||
*
|
||||
* Called by: ProcessHook, recursive inside groups
|
||||
*
|
||||
* ProcessKey is where the keystroke conversion and output takes place. This routine
|
||||
* has a lot of crucial code in it!
|
||||
*/
|
||||
|
||||
BOOL ProcessGroup(LPGROUP gp)
|
||||
{
|
||||
if (!DebugAssert(!Globals::get_CoreIntegration(), "KMPROCESS:ProcessGroup: Error called in core integration mode")) {
|
||||
return FALSE;
|
||||
}
|
||||
DWORD i;
|
||||
LPKEY kkp = NULL;
|
||||
PWSTR p;
|
||||
int sdmfI;
|
||||
|
||||
/*
|
||||
If the number of nested groups goes higher than 50, then break out - this is
|
||||
a limitation of stack size. This is basically a catch-all for freaky apps that
|
||||
cause message loopbacks and nasty things like that. Okay, it's really a catch all
|
||||
for bugs! This means the user's system shouldn't hang.
|
||||
*/
|
||||
|
||||
PKEYMAN64THREADDATA _td = ThreadGlobals();
|
||||
if(!_td) return FALSE;
|
||||
|
||||
_td->app->QueueDebugInformation(QID_GROUP_ENTER, gp, NULL, NULL, NULL, 0);
|
||||
|
||||
sdmfI = -1;
|
||||
|
||||
for(i = 0; i < _td->state.lpkb->cxGroupArray; i++)
|
||||
if(gp == &_td->state.lpkb->dpGroupArray[i])
|
||||
{
|
||||
if(_td->state.msg.message == wm_keymankeydown && ShouldDebug(sdmKeyboard))
|
||||
SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, "Entering group %d of %d, context '%s'", i+1, _td->state.lpkb->cxGroupArray, getcontext_debug());
|
||||
sdmfI = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if(++_td->state.LoopTimes > 50)
|
||||
{
|
||||
if(_td->state.msg.message == wm_keymankeydown) SendDebugMessage(_td->state.msg.hwnd, sdmKeyboard, 0, "Aborting output: state.LoopTimes exceeded.");
|
||||
_td->state.StopOutput = TRUE;
|
||||
_td->app->QueueDebugInformation(QID_GROUP_EXIT, gp, NULL, NULL, NULL, QID_FLAG_RECURSIVE_OVERFLOW);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_td->state.NoMatches = TRUE;
|
||||
|
||||
/*
|
||||
The rule matching loop.
|
||||
|
||||
This loop iterates through all the rules in the group that is currently being
|
||||
processed. Each rule in a group can be of three different types:
|
||||
1. A virtual key rule, where the key to be matched is a virtual key
|
||||
2. A normal key rule (WM_CHAR), where the key to be matched is an Ascii char.
|
||||
3. A rule in a keyless group, where only the context is matched.
|
||||
|
||||
The loop goes through and checks the rules like that. This loop could be optimized
|
||||
with standard searching techniques - the ContextMatch may be difficult.
|
||||
*/
|
||||
|
||||
if(ShouldDebug(sdmKeyboard))
|
||||
SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, "state.vkey: %s shiftFlags: %x; charCode: %X",
|
||||
Debug_VirtualKey(_td->state.vkey), Globals::get_ShiftState(), _td->state.charCode); // I4582
|
||||
|
||||
if(gp)
|
||||
{
|
||||
for(kkp = gp->dpKeyArray, i=0; i < gp->cxKeyArray; i++, kkp++)
|
||||
{
|
||||
if(!ContextMatch(kkp)) continue;
|
||||
if(!gp->fUsingKeys)
|
||||
{
|
||||
if(kkp->dpContext[0] != 0) break; else continue;
|
||||
}
|
||||
|
||||
//if(kkp->Key == state.vkey)
|
||||
//SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, 0, "kkp->Key: %d kkp->ShiftFlags: %x",
|
||||
// kkp->Key, kkp->ShiftFlags);
|
||||
|
||||
/* Keyman 6.0: support Virtual Characters */
|
||||
if(IsEquivalentShift(kkp->ShiftFlags, Globals::get_ShiftState()))
|
||||
{
|
||||
if(kkp->Key > VK__MAX && kkp->Key == _td->state.vkey) break; // I3438 // I4582
|
||||
else if(kkp->Key == _td->state.vkey) break; // I4169
|
||||
}
|
||||
else if(kkp->ShiftFlags == 0 && kkp->Key == _td->state.charCode && _td->state.charCode != 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!gp || i == gp->cxKeyArray)
|
||||
{
|
||||
/*
|
||||
No rule was found that corresponded to the current state of the context and
|
||||
keyboard. NoMatch should be checked for everything except virtual keys; and
|
||||
context should also be kept.
|
||||
|
||||
If the message was a virtual key, then just return without checking NoMatch.
|
||||
NoMatch shouldn't be used for virtual keys because it will mean that no key
|
||||
can ever get through that isn't matched - including arrows, func. keys, etc !!
|
||||
Context is not kept for virtual keys being output.
|
||||
*/
|
||||
|
||||
if(_td->state.msg.message == wm_keymankeydown && ShouldDebug(sdmKeyboard)) SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0,
|
||||
"No match was found in group %d of %d", sdmfI, _td->state.lpkb->cxGroupArray);
|
||||
|
||||
if(!gp || (_td->state.charCode == 0 && gp->fUsingKeys)) // I4585
|
||||
// 7.0.241.0: I1133 - Fix mismatched parentheses on state.charCode - ie. we don't want to output this letter if !gp->fUsingKeys
|
||||
{
|
||||
BOOL fIsBackspace = _td->state.vkey == VK_BACK && (Globals::get_ShiftState() & (LCTRLFLAG|RCTRLFLAG|LALTFLAG|RALTFLAG)) == 0; // I4128
|
||||
|
||||
if(/*_td->app->DebugControlled() &&*/ fIsBackspace) { // I4838 // I4933
|
||||
if(_td->state.msg.message == wm_keymankeydown) { // I4933
|
||||
if(!_td->app->IsLegacy()) { // I4933
|
||||
PWCHAR pdeletecontext = _td->app->ContextBuf(1); // I4933
|
||||
if(!pdeletecontext || *pdeletecontext == 0) { // I4933
|
||||
_td->app->ResetContext(); // I4933
|
||||
fOutputKeystroke = TRUE; // I4933
|
||||
return FALSE; // I4933
|
||||
}
|
||||
if (Uni_IsSurrogate1(*pdeletecontext) && Uni_IsSurrogate2(*(pdeletecontext+1))) {
|
||||
// 2 backspaces to delete both parts of surrogate pair
|
||||
// This only needs to be done for TSF-aware apps as legacy apps
|
||||
// will receive a BKSP WM_KEYDOWN event which results in deleting
|
||||
// both parts in one action
|
||||
_td->app->QueueAction(QIT_BACK, BK_BACKSPACE | BK_SURROGATE);
|
||||
}
|
||||
else {
|
||||
_td->app->QueueAction(QIT_BACK, BK_BACKSPACE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
_td->app->QueueAction(QIT_BACK, BK_BACKSPACE); // I4933
|
||||
}
|
||||
}
|
||||
} else if( (!_td->app->IsLegacy() || !fIsBackspace) && !_td->TIPFPreserved) { // I4024 // I4128 // I4287 // I4290
|
||||
SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, " ... IsLegacy = FALSE; IsTIP = TRUE"); // I4128
|
||||
if(_td->state.charCode == 0) _td->app->ResetContext(); // I3573 // I3577 // I4585
|
||||
fOutputKeystroke = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
//fOutputKeystroke = TRUE; return FALSE; // Don't swallow keystroke // I3577
|
||||
///SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, " ... IsLegacy = TRUE; IsTIP = TRUE");
|
||||
|
||||
/*
|
||||
If the key is not a character key (white keys), or not processing, then we must init the stack -
|
||||
unknown keys do things like moving position in the context, so must clear.
|
||||
*/
|
||||
if(fIsBackspace) // I4128
|
||||
{
|
||||
/*
|
||||
Must have special handling for VK_BACK: delete a character from the context stack
|
||||
This only fires if the keyboard has no rule for backspace.
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
//app->NoSetShift = FALSE;
|
||||
|
||||
DWORD dw = _td->state.vkey;
|
||||
if(dw == 0x05) dw = VK_RETURN; // I649 - VK_ENTER and K_NPENTER
|
||||
|
||||
if(_td->state.msg.lParam & (1<<24)) dw |= QVK_EXTENDED; // Extended key flag // I3438
|
||||
|
||||
if(_td->state.charCode == 0) {
|
||||
_td->app->ResetContext();
|
||||
}
|
||||
|
||||
if(_td->TIPFPreserved) { // I4290
|
||||
if(_td->state.charCode != 0) {
|
||||
_td->app->QueueAction(QIT_CHAR, _td->state.charCode);
|
||||
}
|
||||
} else {
|
||||
if(_td->state.msg.message == wm_keymankeydown)
|
||||
{
|
||||
_td->app->QueueAction(QIT_VSHIFTDOWN, Globals::get_ShiftState()); // 15/05/2001 - fixing I201 -- enabled line
|
||||
_td->app->QueueAction(QIT_VKEYDOWN, dw);
|
||||
}
|
||||
|
||||
if(_td->state.msg.message == wm_keymankeyup) {
|
||||
_td->app->QueueAction(QIT_VKEYUP, dw);
|
||||
_td->app->QueueAction(QIT_VSHIFTUP, Globals::get_ShiftState());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (gp->dpNoMatch != NULL && *gp->dpNoMatch != 0 && _td->state.msg.message != wm_keymankeyup)
|
||||
{
|
||||
/* NoMatch rule found, and is a character key */
|
||||
_td->app->QueueDebugInformation(QID_NOMATCH_ENTER, gp, NULL, NULL, gp->dpNoMatch, 0);
|
||||
PostString(gp->dpNoMatch, &_td->state.msg, _td->state.lpkb, NULL);
|
||||
_td->app->QueueDebugInformation(QID_NOMATCH_EXIT, gp, NULL, NULL, gp->dpNoMatch, 0);
|
||||
}
|
||||
else if (_td->state.charCode != 0 && _td->state.charCode != 0xFFFF && _td->state.msg.message != wm_keymankeyup && gp->fUsingKeys)
|
||||
{
|
||||
/* No rule found, is a character key */
|
||||
// 7.0.239.0: I994 - Workaround output order issues - we will use the TSF to output all characters...
|
||||
// if(app->Type1() == AIType_TIP) { fOutputKeystroke = TRUE; return FALSE; } // Don't swallow keystroke
|
||||
|
||||
_td->app->QueueAction(QIT_CHAR, _td->state.charCode);
|
||||
}
|
||||
|
||||
_td->app->QueueDebugInformation(QID_GROUP_EXIT, gp, NULL, NULL, NULL, QID_FLAG_NOMATCH);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if(_td->state.msg.message == wm_keymankeyup)
|
||||
return TRUE;
|
||||
|
||||
SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, "match found in rule %d", i);
|
||||
|
||||
_td->state.NoMatches = FALSE;
|
||||
|
||||
/*
|
||||
Save the context that will be used for output when the 'context' keyword is used.
|
||||
For each deadkey, we need to add 2 characters; look in related stores as well...
|
||||
*/
|
||||
|
||||
assert(kkp != NULL);
|
||||
|
||||
_td->miniContextIfLen = xstrlen(kkp->dpContext) - xstrlen_ignoreifopt(kkp->dpContext);
|
||||
|
||||
// 11 Aug 2003 - I25(v6) - mcdurdin - CODE_NUL context support
|
||||
if(*kkp->dpContext == UC_SENTINEL && *(kkp->dpContext+1) == CODE_NUL)
|
||||
wcsncpy_s(_td->miniContext, GLOBAL_ContextStackSize, _td->app->ContextBuf(xstrlen_ignoreifopt(kkp->dpContext)-1), GLOBAL_ContextStackSize); // I3162 // I3536
|
||||
else
|
||||
wcsncpy_s(_td->miniContext, GLOBAL_ContextStackSize, _td->app->ContextBuf(xstrlen_ignoreifopt(kkp->dpContext)), GLOBAL_ContextStackSize); // I3162 // I3536
|
||||
|
||||
_td->miniContext[GLOBAL_ContextStackSize-1] = 0;
|
||||
|
||||
_td->app->QueueDebugInformation(QID_RULE_ENTER, gp, kkp, _td->miniContext, NULL, 0);
|
||||
|
||||
/*
|
||||
The next section includes several optimizations that make the code a little harder
|
||||
to read, but are probably worth it in the time that they save.
|
||||
|
||||
If the output string doesn't have a "context" byte at the start, post backspaces
|
||||
to erase the appropriate number of characters in the application. If it does have
|
||||
a "context" byte at the start, then the string won't change, and no backspaces are
|
||||
necessary. You could go one step further with this optimization, in PostAllKeys,
|
||||
by comparing the starts of the strings to see what is same, and not backspacing
|
||||
that, but it is probably not necessary.
|
||||
*/
|
||||
|
||||
p = kkp->dpOutput;
|
||||
if(*p != UC_SENTINEL || *(p+1) != CODE_CONTEXT) {
|
||||
for(PWSTR mcp = decxstr(wcschr(_td->miniContext, 0), _td->miniContext); mcp != NULL; mcp = decxstr(mcp, _td->miniContext)) {
|
||||
if (*mcp == UC_SENTINEL) {
|
||||
switch (*(mcp + 1)) {
|
||||
case CODE_DEADKEY: _td->app->QueueAction(QIT_BACK, BK_DEADKEY); break;
|
||||
case CODE_NUL: break; // 11 Aug 2003 - I25(v6) - mcdurdin - CODE_NUL context support
|
||||
}
|
||||
}
|
||||
else if (Uni_IsSurrogate1(*mcp) && Uni_IsSurrogate2(*(mcp + 1))) {
|
||||
// 2 backspaces to delete both parts of surrogate pair
|
||||
// This only needs to be done for TSF-aware apps as legacy apps
|
||||
// will receive a BKSP WM_KEYDOWN event which results in deleting
|
||||
// both parts in one action
|
||||
_td->app->QueueAction(QIT_BACK, BK_SURROGATE);
|
||||
}
|
||||
else {
|
||||
_td->app->QueueAction(QIT_BACK, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// otherwise, the "context" entry has to be jumped over
|
||||
p += 2;
|
||||
}
|
||||
|
||||
/* Use PostString to post the rest of the output string. */
|
||||
|
||||
if(PostString(p, &_td->state.msg, _td->state.lpkb, NULL) == psrCheckMatches)
|
||||
{
|
||||
_td->app->QueueDebugInformation(QID_RULE_EXIT, gp, kkp, _td->miniContext, NULL, 0);
|
||||
|
||||
if(gp->dpMatch && *gp->dpMatch)
|
||||
{
|
||||
_td->app->QueueDebugInformation(QID_MATCH_ENTER, gp, NULL, NULL, gp->dpMatch, 0);
|
||||
PostString(gp->dpMatch, &_td->state.msg, _td->state.lpkb, NULL);
|
||||
_td->app->QueueDebugInformation(QID_MATCH_EXIT, gp, NULL, NULL, gp->dpMatch, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
_td->app->QueueDebugInformation(QID_RULE_EXIT, gp, kkp, _td->miniContext, NULL, 0);
|
||||
_td->app->QueueDebugInformation(QID_GROUP_EXIT, gp, NULL, NULL, NULL, 0);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* int PostString( LPSTR str, BOOL *useMode, LPMSG mp,
|
||||
* LPKEYBOARD lpkb );
|
||||
*
|
||||
* Parameters: str Pointer to string to send
|
||||
* useMode Pointer to BOOL about whether a "use" command was found
|
||||
* mp Pointer to MSG structure to copy in outputting messages
|
||||
* lpkb Pointer to global keyboard structure
|
||||
*
|
||||
* Returns: 0 to continue, 1 and 2 to return.
|
||||
*
|
||||
* Called by: ProcessKey
|
||||
*
|
||||
* PostString posts a string of "context", "index", "beep", characters and virtual keys
|
||||
* to the active application, via the Keyman PostKey buffer.
|
||||
*/
|
||||
|
||||
int PostString(PWSTR str, LPMSG mp, LPKEYBOARD lpkb, PWSTR endstr)
|
||||
{
|
||||
if (!DebugAssert(!Globals::get_CoreIntegration(), "KKMPROCESS:PostString: Error called in core integration mode")) {
|
||||
return FALSE;
|
||||
}
|
||||
PWSTR p, q, temp;
|
||||
LPSTORE s;
|
||||
int n1, n2;
|
||||
int i, n, shift;
|
||||
BOOL FoundUse = FALSE;
|
||||
|
||||
PKEYMAN64THREADDATA _td = ThreadGlobals();
|
||||
if(!_td) return FALSE;
|
||||
|
||||
// TODO: Refactor to use incxstr
|
||||
for(p = str; *p && (p < endstr || !endstr); p++)
|
||||
{
|
||||
if(*p == UC_SENTINEL)
|
||||
switch(*(++p))
|
||||
{
|
||||
case CODE_EXTENDED: // Start of a virtual key section w/shift codes
|
||||
p++;
|
||||
|
||||
shift = *p; //(*p<<8) | *(p+1);
|
||||
_td->app->QueueAction(QIT_VSHIFTDOWN, shift);
|
||||
|
||||
p++;
|
||||
|
||||
_td->app->QueueAction(QIT_VKEYDOWN, *p);
|
||||
_td->app->QueueAction(QIT_VKEYUP, *p);
|
||||
|
||||
_td->app->QueueAction(QIT_VSHIFTUP, shift);
|
||||
|
||||
p++; // CODE_EXTENDEDEND
|
||||
////// CODE_EXTENDEDEND will be incremented by loop
|
||||
|
||||
//app->QueueAction(QIT_VSHIFTUP, shift);
|
||||
break;
|
||||
|
||||
case CODE_DEADKEY: // A deadkey to be output
|
||||
p++;
|
||||
_td->app->QueueAction(QIT_DEADKEY, *p);
|
||||
break;
|
||||
case CODE_BEEP: // Sound an 'iconasterisk' beep
|
||||
_td->app->QueueAction(QIT_BELL, 0);
|
||||
break;
|
||||
case CODE_CONTEXT: // copy the context to the output
|
||||
PostString(_td->miniContext, mp, lpkb, wcschr(_td->miniContext, 0));
|
||||
break;
|
||||
case CODE_CONTEXTEX:
|
||||
p++;
|
||||
for(q = _td->miniContext, i = _td->miniContextIfLen; *q && i < *p-1; i++, q=incxstr(q));
|
||||
if(*q) {
|
||||
temp = incxstr(q);
|
||||
PostString(q, mp, lpkb, temp);
|
||||
}
|
||||
break;
|
||||
case CODE_RETURN: // stop processing and start PostAllKeys
|
||||
_td->state.StopOutput = TRUE;
|
||||
return psrPostMessages;
|
||||
|
||||
case CODE_CALL:
|
||||
p++;
|
||||
CallDLL(_td->lpActiveKeyboard, *p-1);
|
||||
if(_td->state.StopOutput) return psrPostMessages;
|
||||
FoundUse = TRUE;
|
||||
break;
|
||||
case CODE_USE: // use another group
|
||||
p++;
|
||||
ProcessGroup(&lpkb->dpGroupArray[*p-1]);
|
||||
if(_td->state.StopOutput) return psrPostMessages;
|
||||
FoundUse = TRUE;
|
||||
break;
|
||||
case CODE_CLEARCONTEXT:
|
||||
_td->app->ResetContext();
|
||||
_td->app->ReadContext();
|
||||
break;
|
||||
case CODE_INDEX:
|
||||
p++;
|
||||
s = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[*p - 1];
|
||||
p++;
|
||||
|
||||
n = _td->IndexStack[*p - 1];
|
||||
for(temp = s->dpString; *temp && n > 0; temp = incxstr(temp), n--);
|
||||
PostString(temp, mp, lpkb, incxstr(temp));
|
||||
break;
|
||||
case CODE_SETOPT:
|
||||
p++;
|
||||
n1 = *p - 1;
|
||||
p++;
|
||||
n2 = *p - 1;
|
||||
SetKeyboardOption(_td->lpActiveKeyboard, n1, n2);
|
||||
break;
|
||||
case CODE_RESETOPT:
|
||||
p++;
|
||||
n1 = *p - 1;
|
||||
ResetKeyboardOption(_td->lpActiveKeyboard, n1);
|
||||
break;
|
||||
case CODE_SAVEOPT:
|
||||
p++;
|
||||
n1 = *p - 1;
|
||||
SaveKeyboardOption(_td->lpActiveKeyboard, n1);
|
||||
break;
|
||||
case CODE_IFSYSTEMSTORE:
|
||||
p+=3;
|
||||
break;
|
||||
case CODE_SETSYSTEMSTORE:
|
||||
p+=2;
|
||||
break;
|
||||
}
|
||||
else
|
||||
_td->app->QueueAction(QIT_CHAR, *p);
|
||||
}
|
||||
return FoundUse ? psrPostMessages : psrCheckMatches;
|
||||
}
|
||||
|
||||
|
||||
BOOL IsMatchingBaseLayout(PWCHAR layoutName) // I3432
|
||||
{
|
||||
BOOL bEqual = _wcsicmp(layoutName, Globals::get_BaseKeyboardName()) == 0 || // I4583
|
||||
_wcsicmp(layoutName, Globals::get_BaseKeyboardNameAlt()) == 0; // I4583
|
||||
|
||||
return bEqual;
|
||||
}
|
||||
|
||||
BOOL IsMatchingPlatformString(PWCHAR platform) // I3432
|
||||
{
|
||||
return
|
||||
_wcsicmp(platform, L"windows") == 0 ||
|
||||
_wcsicmp(platform, L"desktop") == 0 ||
|
||||
_wcsicmp(platform, L"hardware") == 0 ||
|
||||
_wcsicmp(platform, L"native") == 0;
|
||||
}
|
||||
|
||||
BOOL IsMatchingPlatform(LPSTORE s) // I3432
|
||||
{
|
||||
PWCHAR t = new WCHAR[wcslen(s->dpString)+1];
|
||||
wcscpy_s(t, wcslen(s->dpString)+1, s->dpString);
|
||||
PWCHAR context = NULL;
|
||||
PWCHAR platform = wcstok_s(t, L" ", &context);
|
||||
while(platform != NULL)
|
||||
{
|
||||
if(!IsMatchingPlatformString(platform))
|
||||
{
|
||||
s->dwSystemID = TSS_PLATFORM_NOMATCH;
|
||||
delete[] t;
|
||||
return FALSE;
|
||||
}
|
||||
platform = wcstok_s(NULL, L" ", &context);
|
||||
}
|
||||
|
||||
s->dwSystemID = TSS_PLATFORM_MATCH;
|
||||
delete[] t;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* BOOL ContextMatch( LPKEY kkp );
|
||||
*
|
||||
* Parameters: kkp Rule to compare
|
||||
*
|
||||
* Returns: 0 on OK, 1 on not equal
|
||||
*
|
||||
* Called by: ProcessKey
|
||||
*
|
||||
* ContextMatch compares the context of a rule with the current context.
|
||||
*/
|
||||
|
||||
BOOL ContextMatch(LPKEY kkp)
|
||||
{
|
||||
if (!DebugAssert(!Globals::get_CoreIntegration(), "KMPROCESS:ContextMatch: Error called in core integration mode")) {
|
||||
return FALSE;
|
||||
}
|
||||
WORD /*i,*/ n;
|
||||
PWSTR p, q, qbuf, temp;
|
||||
LPWORD indexp;
|
||||
LPSTORE s, t;
|
||||
BOOL bEqual;
|
||||
|
||||
//SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: ENTER [%d]", kkp->Line);
|
||||
PKEYMAN64THREADDATA _td = ThreadGlobals();
|
||||
if(!_td) return FALSE;
|
||||
|
||||
memset(_td->IndexStack, 0, GLOBAL_ContextStackSize*sizeof(WORD)); // I3158 // I3524
|
||||
|
||||
p = kkp->dpContext;
|
||||
|
||||
if(*p == 0)
|
||||
{
|
||||
//SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: EXIT TRUE -> no rule context");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* 11 Aug 2003 - I25(v6) - mcdurdin - test for CODE_NUL */
|
||||
|
||||
if(*p == UC_SENTINEL && *(p+1) == CODE_NUL)
|
||||
{
|
||||
// If context buf is longer than the context, then obviously not start of doc.
|
||||
if(_td->app->ContextBuf(xstrlen_ignoreifopt(p))) return FALSE; // I2484 - Fix bug with if() following nul in same statement
|
||||
p = incxstr(p);
|
||||
if(*p == 0) return TRUE;
|
||||
}
|
||||
|
||||
for(PWCHAR pp = p; pp && *pp; pp = incxstr(pp))
|
||||
{
|
||||
if(*pp == UC_SENTINEL && *(pp+1) == CODE_IFOPT)
|
||||
{
|
||||
s = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(pp+2))-1]; // I2590
|
||||
t = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(pp+4))-1]; // I2590
|
||||
|
||||
bEqual = wcscmp(s->dpString, t->dpString) == 0;
|
||||
if(*(pp+3) == 1 && bEqual) return FALSE; // I2590
|
||||
if(*(pp+3) == 2 && !bEqual) return FALSE; // I2590
|
||||
}
|
||||
else if(*pp == UC_SENTINEL && *(pp+1) == CODE_IFSYSTEMSTORE) // I3432
|
||||
{
|
||||
DWORD dwSystemID = *(pp+2)-1;
|
||||
t = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(pp+4))-1]; // I2590
|
||||
switch(dwSystemID)
|
||||
{
|
||||
case TSS_PLATFORM_MATCH: // Cached platform result - a matching platform
|
||||
bEqual = TRUE;
|
||||
break;
|
||||
case TSS_PLATFORM_NOMATCH: // Cached platform result - not a matching platform
|
||||
bEqual = FALSE;
|
||||
break;
|
||||
case TSS_PLATFORM:
|
||||
bEqual = IsMatchingPlatform(t);
|
||||
break;
|
||||
case TSS_BASELAYOUT:
|
||||
bEqual = IsMatchingBaseLayout(t->dpString);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
PWCHAR ss = GetSystemStore(_td->lpActiveKeyboard->Keyboard, dwSystemID);
|
||||
if(ss == NULL) return FALSE;
|
||||
bEqual = wcscmp(ss, t->dpString) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(*(pp+3) == 1 && bEqual) return FALSE; // I2590
|
||||
if(*(pp+3) == 2 && !bEqual) return FALSE; // I2590
|
||||
}
|
||||
}
|
||||
|
||||
q = qbuf = _td->app->ContextBuf(xstrlen_ignoreifopt(p));
|
||||
if(!q)
|
||||
{
|
||||
//SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: EXIT FALSE -> context too short");
|
||||
return FALSE; // context buf is too short!
|
||||
}
|
||||
indexp = _td->IndexStack;
|
||||
|
||||
//SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: [%d] Rule: %s", kkp->Line, format_unicode_debug(kkp->dpContext));
|
||||
//SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: [%d] Test: %s", kkp->Line, format_unicode_debug(q));
|
||||
|
||||
for(; *p && *q; p = incxstr(p))
|
||||
{
|
||||
//SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: p:%x q:%x", *p, *q);
|
||||
*indexp = 0;
|
||||
|
||||
if(*p == UC_SENTINEL)
|
||||
{
|
||||
switch(*(p+1))
|
||||
{
|
||||
case CODE_DEADKEY:
|
||||
if(*q != UC_SENTINEL || *(q+1) != CODE_DEADKEY || *(q+2) != *(p+2))
|
||||
{
|
||||
// SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: EXIT FALSE -> deadkeys don't match %x %x %x != %x %x %x",
|
||||
// *p, *(p+1), *(p+2), *q, *(q+1), *(q+2));
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case CODE_ANY:
|
||||
s = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(p+2))-1];
|
||||
|
||||
temp = xstrchr(s->dpString, q);
|
||||
|
||||
/*SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard ,kkp->Line, "ContextMatch: CODE_ANY [%x %x %x %x %x %x %x %x %x %x] [%x %x %x] %d",
|
||||
s->dpString[0], s->dpString[1], s->dpString[2],
|
||||
s->dpString[3], s->dpString[4], s->dpString[5],
|
||||
s->dpString[6], s->dpString[7], s->dpString[8],
|
||||
s->dpString[9],
|
||||
q[0], q[1], q[2],
|
||||
(temp ? (INT_PTR)(temp-s->dpString) : 0));*/
|
||||
|
||||
if(temp != NULL) // I1622
|
||||
*indexp = (WORD) xstrpos(temp, s->dpString);
|
||||
|
||||
//if((temp = xstrchr(s->dpString, GetSuppChar(q))) != NULL)
|
||||
// *indexp = xstrpos(temp, s->dpString);
|
||||
else
|
||||
return FALSE;
|
||||
break;
|
||||
case CODE_NOTANY:
|
||||
s = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(p+2))-1];
|
||||
|
||||
if((temp = xstrchr(s->dpString, q)) != NULL) // I1622
|
||||
return FALSE;
|
||||
|
||||
//if((temp = xstrchr(s->dpString, GetSuppChar(q))) != NULL)
|
||||
// return FALSE;
|
||||
break;
|
||||
case CODE_INDEX:
|
||||
s = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(p+2))-1];
|
||||
*indexp = n = _td->IndexStack[(*(p+3))-1];
|
||||
|
||||
for(temp = s->dpString; *temp && n > 0; temp = incxstr(temp), n--);
|
||||
if(n != 0) return FALSE;
|
||||
if(xchrcmp(temp, q) != 0) return FALSE;
|
||||
////if(GetSuppChar(temp) != GetSuppChar(q)) return FALSE; // I1622
|
||||
break;
|
||||
case CODE_CONTEXTEX:
|
||||
// only the nth character
|
||||
for(n = *(p+2) - 1, temp = qbuf; temp < q && n > 0; n--, temp = incxstr(temp));
|
||||
if(n == 0)
|
||||
if(xchrcmp(temp, q) != 0) return FALSE;
|
||||
//if(GetSuppChar(temp) != GetSuppChar(q)) return FALSE;
|
||||
break;
|
||||
case CODE_IFOPT:
|
||||
case CODE_IFSYSTEMSTORE: // I3432
|
||||
indexp++;
|
||||
continue; // don't increment q
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else if(xchrcmp(p, q) != 0) //GetSuppChar(p) != GetSuppChar(q))
|
||||
{
|
||||
//SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: [%d] FAIL: %s", kkp->Line, format_unicode_debug(p));
|
||||
//SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: [%d] FAIL: %s", kkp->Line, format_unicode_debug(q));
|
||||
//SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: EXIT FALSE -> chrs don't match");
|
||||
return FALSE;
|
||||
}
|
||||
indexp++;
|
||||
q = incxstr(q);
|
||||
}
|
||||
|
||||
while(*p == UC_SENTINEL && (*(p+1) == CODE_IFOPT || *(p+1) == CODE_IFSYSTEMSTORE)) p = incxstr(p); // already tested // I3432
|
||||
|
||||
//SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: EXIT %s -> END OF FUNCTION",
|
||||
// *p == *q ? "TRUE" : "FALSE");
|
||||
return *p == *q; /*at least one must ==0 at this point*/
|
||||
}
|
||||
|
||||
|
||||
PWSTR strtowstr(PSTR in)
|
||||
{
|
||||
PWSTR result;
|
||||
|
|
@ -933,7 +251,6 @@ PWSTR strtowstr(PSTR in)
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
PSTR wstrtostr(PCWSTR in)
|
||||
{
|
||||
PSTR result;
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ static BOOL processPersistOpt(
|
|||
SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessHook: Saving option to registry for keyboard [%s].", activeKeyboard->Name);
|
||||
LPWSTR value = new WCHAR[sizeof(actionItem->option->value) + 1];
|
||||
wcscpy_s(value, sizeof(actionItem->option->value) + 1, reinterpret_cast<LPCWSTR>(actionItem->option->value));
|
||||
SaveKeyboardOptionREGCore(activeKeyboard, reinterpret_cast<LPCWSTR>(actionItem->option->key), value);
|
||||
SaveKeyboardOptionCoretoRegistry(activeKeyboard, reinterpret_cast<LPCWSTR>(actionItem->option->key), value);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
|
|
|
|||
|
|
@ -37,12 +37,11 @@ struct PreservedKey
|
|||
class PreservedKeyMap
|
||||
{
|
||||
public:
|
||||
BOOL MapKeyboard(KEYBOARD *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys);
|
||||
/**
|
||||
* Updates a map of preserved keys (with GUID) that are used in keyboard rules.
|
||||
* Passing in NULL for pPreservedKeys will cause cPreservedKeys to be set to the number
|
||||
* of preserved keys needed for the supplied pKeyboard; this should be used in creating
|
||||
* pPreservedKeys list to sufficient size. When pPreservedKeys list is passed the
|
||||
* of preserved keys needed for the supplied pKeyboard; this should be used in creating
|
||||
* pPreservedKeys list to sufficient size. When pPreservedKeys list is passed the
|
||||
* cPreservedKeys will be the actual count of the number of unique pPreservedKeys
|
||||
*
|
||||
* @param pKeyboard the keyboard for which the rules will be extracted from
|
||||
|
|
@ -50,14 +49,13 @@ public:
|
|||
* @param cPreservedKeys number of preserved keys in pPreservedKeys - or the size pPreservedKeys needs to be
|
||||
* @return BOOL return TRUE on success
|
||||
*/
|
||||
BOOL MapKeyboardCore(km_kbp_keyboard *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys);
|
||||
BOOL MapKeyboard(km_kbp_keyboard *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys);
|
||||
|
||||
private:
|
||||
BOOL m_BaseKeyboardUsesAltGr; // I4592
|
||||
UINT ShiftToTSFShift(UINT ShiftFlags);
|
||||
BOOL MapUSCharToVK(UINT *puKey, UINT *puShiftFlags);
|
||||
BOOL MapKeyRule(KEY *pKey, TF_PRESERVEDKEY *pPreservedKey);
|
||||
BOOL MapKeyRuleCore(km_kbp_keyboard_key *pKeyRule, TF_PRESERVEDKEY *pPreservedKey);
|
||||
BOOL MapKeyRule(km_kbp_keyboard_key *pKeyRule, TF_PRESERVEDKEY *pPreservedKey);
|
||||
BOOL IsMatchingKey(PreservedKey *pKey, PreservedKey *pKeys, size_t cKeys);
|
||||
};
|
||||
|
||||
|
|
@ -199,45 +197,8 @@ UINT PreservedKeyMap::ShiftToTSFShift(UINT ShiftFlags)
|
|||
return res;
|
||||
}
|
||||
|
||||
BOOL PreservedKeyMap::MapKeyRule(KEY *pKey, TF_PRESERVEDKEY *pPreservedKey)
|
||||
{
|
||||
UINT ShiftFlags;
|
||||
UINT Key;
|
||||
|
||||
Key = pKey->Key;
|
||||
ShiftFlags = pKey->ShiftFlags;
|
||||
|
||||
if(Key == VK_BACK || Key == VK_RETURN || Key == VK_TAB) // I4575
|
||||
{
|
||||
//
|
||||
// We never map backspace, return or tab because these are the only supported virtual key outputs,
|
||||
// and result in recursion. Sadly, this is an imperfect solution forced upon us by preserved key
|
||||
// limitations.
|
||||
//
|
||||
// Other virtual key output will be blocked with this version.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Key > 255) {
|
||||
//
|
||||
// Touch-defined keys have a value > 255, but these should never be preserved
|
||||
//
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(ShiftFlags == 0)
|
||||
{
|
||||
if(!MapUSCharToVK(&Key, &ShiftFlags)) return FALSE;
|
||||
}
|
||||
|
||||
pPreservedKey->uVKey = (UINT) USVKToScanCodeToLayoutVK( (WORD) Key); // I3762
|
||||
pPreservedKey->uModifiers = ShiftToTSFShift(ShiftFlags);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
PreservedKeyMap::MapKeyRuleCore(km_kbp_keyboard_key *pKeyRule, TF_PRESERVEDKEY *pPreservedKey) {
|
||||
PreservedKeyMap::MapKeyRule(km_kbp_keyboard_key *pKeyRule, TF_PRESERVEDKEY *pPreservedKey) {
|
||||
UINT ShiftFlags;
|
||||
UINT Key;
|
||||
|
||||
|
|
@ -280,94 +241,8 @@ BOOL PreservedKeyMap::IsMatchingKey(PreservedKey *pKey, PreservedKey *pKeys, siz
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
// TODO: 5442 - Remove once core processor verfied
|
||||
BOOL PreservedKeyMap::MapKeyboard(KEYBOARD *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys)
|
||||
{
|
||||
size_t cKeys = 0, n;
|
||||
DWORD i, j;
|
||||
GROUP *pGroup;
|
||||
|
||||
m_BaseKeyboardUsesAltGr = KeyboardGivesCtrlRAltForRAlt(); // I4592
|
||||
|
||||
// This is not the same as m_BaseKeyboardUsesAltGr -- we are turning
|
||||
// the simulation back on after (possibly) turning it off, for a
|
||||
// consistent experience. TODO: determine if m_BaseKeyboardUseAltGr
|
||||
// is still needed given we always use kbdus as base for Keyman 10+
|
||||
BOOL bSimulateAltGr = Globals::get_SimulateAltGr();
|
||||
|
||||
// We only want to translate RALT and RALT+SHIFT for Ctrl+Alt rules.
|
||||
// So we exclude all our other favourite modifier keys.
|
||||
const UINT RALT_MATCHING_MASK = TF_MOD_CONTROL | TF_MOD_ALT | TF_MOD_LCONTROL | TF_MOD_RCONTROL | TF_MOD_LALT | TF_MOD_RALT;
|
||||
|
||||
for(i = 0; i < pKeyboard->cxGroupArray; i++)
|
||||
{
|
||||
if(pKeyboard->dpGroupArray[i].fUsingKeys)
|
||||
{
|
||||
cKeys += pKeyboard->dpGroupArray[i].cxKeyArray;
|
||||
}
|
||||
}
|
||||
|
||||
if(cKeys == 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (bSimulateAltGr)
|
||||
{
|
||||
// We might need twice as many preserved keys to map both LCtrl+LAlt+x and RAlt+x
|
||||
cKeys *= 2;
|
||||
}
|
||||
|
||||
if(pPreservedKeys == NULL)
|
||||
{
|
||||
*cPreservedKeys = cKeys;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if(*cPreservedKeys < cKeys)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PreservedKey *pKeys = *pPreservedKeys;
|
||||
|
||||
for(n = i = 0; i < pKeyboard->cxGroupArray; i++)
|
||||
{
|
||||
pGroup = &pKeyboard->dpGroupArray[i];
|
||||
if(pGroup->fUsingKeys)
|
||||
{
|
||||
for(j = 0; j < pGroup->cxKeyArray; j++)
|
||||
{
|
||||
// If we have a key rule for the key, we should preserve it
|
||||
if(MapKeyRule(&pGroup->dpKeyArray[j], &pKeys[n].key))
|
||||
{
|
||||
// Don't attempt to add the same preserved key twice. Bad things happen
|
||||
if(!IsMatchingKey(&pKeys[n], pKeys, n))
|
||||
{
|
||||
CoCreateGuid(&pKeys[n].guid);
|
||||
n++;
|
||||
|
||||
if (bSimulateAltGr && (pKeys[n-1].key.uModifiers & RALT_MATCHING_MASK) == TF_MOD_RALT)
|
||||
{
|
||||
// Do this for RALT and RALT+SHIFT only, so we've tested against that mask
|
||||
// Copy the key and fix modifiers
|
||||
pKeys[n].key = pKeys[n - 1].key;
|
||||
pKeys[n].key.uModifiers = (pKeys[n].key.uModifiers & ~TF_MOD_RALT) | TF_MOD_LCONTROL | TF_MOD_LALT;
|
||||
CoCreateGuid(&pKeys[n].guid);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*cPreservedKeys = n; // return actual count of allocated keys, usually smaller than allocated count
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
PreservedKeyMap::MapKeyboardCore(km_kbp_keyboard *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys) {
|
||||
PreservedKeyMap::MapKeyboard(km_kbp_keyboard *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys) {
|
||||
size_t cKeys = 0, cRules = 0, n = 0;
|
||||
DWORD i;
|
||||
|
||||
|
|
@ -422,7 +297,7 @@ PreservedKeyMap::MapKeyboardCore(km_kbp_keyboard *pKeyboard, PreservedKey **pPre
|
|||
|
||||
for (i = 0; i < cRules; i++) {
|
||||
// If we have a key rule for the key, we should preserve it
|
||||
if (MapKeyRuleCore(&kb_key_list[i], &pKeys[n].key)) {
|
||||
if (MapKeyRule(&kb_key_list[i], &pKeys[n].key)) {
|
||||
// Don't attempt to add the same preserved key twice. Bad things happen
|
||||
if (!IsMatchingKey(&pKeys[n], pKeys, n)) {
|
||||
CoCreateGuid(&pKeys[n].guid);
|
||||
|
|
@ -457,23 +332,14 @@ extern "C" __declspec(dllexport) BOOL WINAPI GetKeyboardPreservedKeys(PreservedK
|
|||
if (!_td) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!_td->lpActiveKeyboard) {
|
||||
return FALSE;
|
||||
}
|
||||
// It could be an active core keyboard
|
||||
if (Globals::get_CoreIntegration()) {
|
||||
|
||||
if (!_td->lpActiveKeyboard->lpCoreKeyboard) {
|
||||
return FALSE;
|
||||
}
|
||||
// use api to get key rules
|
||||
return pkm.MapKeyboardCore(_td->lpActiveKeyboard->lpCoreKeyboard, pPreservedKeys, cPreservedKeys);
|
||||
|
||||
} else { // TODO: 5442 Remove else
|
||||
if (!_td->lpActiveKeyboard->Keyboard) {
|
||||
return FALSE;
|
||||
}
|
||||
return pkm.MapKeyboard(_td->lpActiveKeyboard->Keyboard, pPreservedKeys, cPreservedKeys);
|
||||
if (!_td->lpActiveKeyboard->lpCoreKeyboard) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// use api to get key rules
|
||||
return pkm.MapKeyboard(_td->lpActiveKeyboard->lpCoreKeyboard, pPreservedKeys, cPreservedKeys);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@
|
|||
|
||||
// I3594 // I4220
|
||||
|
||||
BOOL SelectKeyboardCore(DWORD KeymanID)
|
||||
BOOL SelectKeyboard(DWORD KeymanID)
|
||||
{
|
||||
int i;
|
||||
HWND hwnd = GetFocus();
|
||||
|
|
@ -71,14 +71,9 @@ BOOL SelectKeyboardCore(DWORD KeymanID)
|
|||
|
||||
__try
|
||||
{
|
||||
if (_td->ForceFileName[0])
|
||||
{
|
||||
SendDebugMessageFormat(hwnd, sdmGlobal, 0, "SelectKeyboard: Ignored due to ForceFile");
|
||||
return FALSE; // Keyboard file is force-loaded
|
||||
}
|
||||
|
||||
KMHideIM();
|
||||
|
||||
|
||||
if (_td->lpActiveKeyboard) DeactivateDLLs(_td->lpActiveKeyboard);
|
||||
_td->lpActiveKeyboard = NULL;
|
||||
_td->ActiveKeymanID = KEYMANID_NONKEYMAN;
|
||||
|
|
@ -101,12 +96,13 @@ BOOL SelectKeyboardCore(DWORD KeymanID)
|
|||
SendDebugMessageFormat(hwnd, sdmGlobal, 0, "SelectKeyboardCore: NewKeymanID: %x", _td->ActiveKeymanID);
|
||||
|
||||
if (_td->app) _td->app->ResetContext();
|
||||
ResetCapsLock();
|
||||
|
||||
// TODO: #5822 tell the core with km_kbp_event so it can reset the capslock state
|
||||
|
||||
SelectApplicationIntegration(); // I4287
|
||||
if (_td->app && !_td->app->IsWindowHandled(hwnd)) _td->app->HandleWindow(hwnd);
|
||||
_td->state.windowunicode = !_td->app || _td->app->IsUnicode();
|
||||
|
||||
|
||||
ActivateDLLs(_td->lpActiveKeyboard);
|
||||
|
||||
return TRUE;
|
||||
|
|
@ -130,88 +126,6 @@ BOOL SelectKeyboardCore(DWORD KeymanID)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL SelectKeyboard(DWORD KeymanID)
|
||||
{
|
||||
if (Globals::get_CoreIntegration())
|
||||
{
|
||||
return SelectKeyboardCore(KeymanID);
|
||||
}
|
||||
int i;
|
||||
HWND hwnd = GetFocus();
|
||||
|
||||
PKEYMAN64THREADDATA _td = ThreadGlobals();
|
||||
if(!_td) return FALSE;
|
||||
|
||||
SendDebugMessageFormat(hwnd,sdmGlobal,0,"ENTER SelectKeyboard-------------------------------------------");
|
||||
SendDebugMessageFormat(hwnd,sdmGlobal,0,"ENTER SelectKeyboard: Current:(HKL=%x KeymanID=%x %s) New:(ID=%x)", //lpActiveKeyboard=%s ActiveKeymanID: %x sk: %x KeymanID: %d",
|
||||
GetKeyboardLayout(0),
|
||||
_td->ActiveKeymanID,
|
||||
_td->lpActiveKeyboard == NULL ? "NULL" : _td->lpActiveKeyboard->Name,
|
||||
//_td->NextKeyboardLayout,
|
||||
KeymanID);
|
||||
|
||||
__try
|
||||
{
|
||||
if(_td->ForceFileName[0])
|
||||
{
|
||||
SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: Ignored due to ForceFile");
|
||||
return FALSE; // Keyboard file is force-loaded
|
||||
}
|
||||
|
||||
KMHideIM();
|
||||
|
||||
if(_td->lpActiveKeyboard) DeactivateDLLs(_td->lpActiveKeyboard);
|
||||
_td->lpActiveKeyboard = NULL;
|
||||
_td->ActiveKeymanID = KEYMANID_NONKEYMAN;
|
||||
|
||||
//SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: nKeyboards=%d", nKeyboards);
|
||||
|
||||
for(i = 0; i < _td->nKeyboards; i++)
|
||||
{
|
||||
if(_td->lpKeyboards[i].KeymanID == KeymanID)
|
||||
{
|
||||
if(!_td->lpKeyboards[i].Keyboard && !LoadlpKeyboard(i))
|
||||
{
|
||||
SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: Unable to load");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
_td->lpActiveKeyboard = &_td->lpKeyboards[i];
|
||||
_td->ActiveKeymanID = _td->lpActiveKeyboard->KeymanID;
|
||||
|
||||
SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: NewKeymanID: %x", _td->ActiveKeymanID);
|
||||
|
||||
if(_td->app) _td->app->ResetContext();
|
||||
ResetCapsLock();
|
||||
|
||||
SelectApplicationIntegration(); // I4287
|
||||
if(_td->app && !_td->app->IsWindowHandled(hwnd)) _td->app->HandleWindow(hwnd);
|
||||
_td->state.windowunicode = !_td->app || _td->app->IsUnicode();
|
||||
|
||||
ActivateDLLs(_td->lpActiveKeyboard);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if(IsFocusedThread())
|
||||
{
|
||||
SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: Keyboard Not Found");
|
||||
}
|
||||
}
|
||||
__finally
|
||||
{
|
||||
SendDebugMessageFormat(hwnd,sdmGlobal,0,"EXIT SelectKeyboard: Current:(HKL=%x KeymanID=%x %s) New:(ID=%x)", //lpActiveKeyboard=%s ActiveKeymanID: %x sk: %x KeymanID: %d",
|
||||
GetKeyboardLayout(0),
|
||||
_td->ActiveKeymanID,
|
||||
_td->lpActiveKeyboard == NULL ? "NULL" : _td->lpActiveKeyboard->Name,
|
||||
KeymanID);
|
||||
SendDebugMessageFormat(hwnd,sdmGlobal,0,"EXIT SelectKeyboard-------------------------------------------");
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
BOOL SelectKeyboardTSF(DWORD dwIdentity, BOOL foreground) // I3933 // I3949 // I4271
|
||||
{
|
||||
if (!foreground && IsFocusedThread()) {
|
||||
|
|
|
|||
|
|
@ -5,77 +5,6 @@
|
|||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
// Test UpdateKeyboardOptionsCore, also uses SaveKeyboardOptionsCore
|
||||
TEST(KEYBOARDOPTIONS, UpdateKeyboardOptionsCore) {
|
||||
LPINTKEYBOARDINFO kp = new INTKEYBOARDINFO;
|
||||
memset(kp, 0, sizeof(INTKEYBOARDINFO));
|
||||
|
||||
km_kbp_option_item test_env_opts[] = {
|
||||
{u"__test_point", u"not tiggered", KM_KBP_OPT_KEYBOARD}, {u"hello", u"-", KM_KBP_OPT_ENVIRONMENT}, KM_KBP_OPTIONS_END};
|
||||
|
||||
km_kbp_path_name dummyPath = L"dummyActions.mock";
|
||||
EXPECT_EQ(km_kbp_keyboard_load(dummyPath, &kp->lpCoreKeyboard), KM_KBP_STATUS_OK);
|
||||
EXPECT_EQ(km_kbp_state_create(kp->lpCoreKeyboard, test_env_opts, &kp->lpCoreKeyboardState), KM_KBP_STATUS_OK);
|
||||
|
||||
kp->lpCoreKeyboardOptions = SaveKeyboardOptionsCore(kp);
|
||||
// No Change
|
||||
EXPECT_FALSE(UpdateKeyboardOptionsCore(kp->lpCoreKeyboardState, kp->lpCoreKeyboardOptions));
|
||||
std::u16string value = kp->lpCoreKeyboardOptions[0].value;
|
||||
std::u16string expectedValue = u"not tiggered";
|
||||
EXPECT_TRUE(value == expectedValue);
|
||||
|
||||
km_kbp_option_item update_key_opts[] = {{u"__test_point", u"triggered", KM_KBP_OPT_KEYBOARD}, KM_KBP_OPTIONS_END};
|
||||
EXPECT_EQ(km_kbp_state_options_update(kp->lpCoreKeyboardState, update_key_opts), KM_KBP_STATUS_OK);
|
||||
// Change value to triggered
|
||||
EXPECT_TRUE(UpdateKeyboardOptionsCore(kp->lpCoreKeyboardState, kp->lpCoreKeyboardOptions));
|
||||
value = kp->lpCoreKeyboardOptions[0].value;
|
||||
expectedValue = u"triggered";
|
||||
EXPECT_TRUE(value == expectedValue);
|
||||
DisposeKeyboardOptionsCore(&kp->lpCoreKeyboardOptions);
|
||||
ReleaseStateMemoryCore(&kp->lpCoreKeyboardState);
|
||||
ReleaseKeyboardMemoryCore(&kp->lpCoreKeyboard);
|
||||
delete kp;
|
||||
|
||||
}
|
||||
|
||||
// Test SaveKeyboardOptionsCore and RestoreKeyboardOptionsCORE
|
||||
TEST(KEYBOARDOPTIONS, SaveRestoreKeyboardOptionsCore) {
|
||||
|
||||
LPINTKEYBOARDINFO kp = new INTKEYBOARDINFO;
|
||||
memset(kp, 0, sizeof(INTKEYBOARDINFO));
|
||||
|
||||
km_kbp_option_item test_env_opts[] = {
|
||||
{u"__test_point", u"not tiggered", KM_KBP_OPT_KEYBOARD}, {u"hello", u"-", KM_KBP_OPT_ENVIRONMENT}, KM_KBP_OPTIONS_END};
|
||||
km_kbp_path_name dummyPath = L"dummyActions.mock";
|
||||
EXPECT_EQ(km_kbp_keyboard_load(dummyPath, &kp->lpCoreKeyboard), KM_KBP_STATUS_OK);
|
||||
EXPECT_EQ(km_kbp_state_create(kp->lpCoreKeyboard, test_env_opts, &kp->lpCoreKeyboardState), KM_KBP_STATUS_OK);
|
||||
|
||||
km_kbp_option_item *SavedKBDOptions = SaveKeyboardOptionsCore(kp);
|
||||
|
||||
std::u16string value = SavedKBDOptions[0].value;
|
||||
std::u16string expectedValue = u"not tiggered";
|
||||
km_kbp_option_item update_key_opts[] = {{u"__test_point", u"triggered", KM_KBP_OPT_KEYBOARD}, KM_KBP_OPTIONS_END};
|
||||
EXPECT_EQ(km_kbp_state_options_update(kp->lpCoreKeyboardState, update_key_opts), KM_KBP_STATUS_OK);
|
||||
|
||||
km_kbp_option_item *NewKBDOptions = SaveKeyboardOptionsCore(kp);
|
||||
value = NewKBDOptions[0].value;
|
||||
expectedValue = u"triggered";
|
||||
EXPECT_TRUE(value == expectedValue);
|
||||
km_kbp_cp const *retValue = nullptr;
|
||||
EXPECT_TRUE(RestoreKeyboardOptionsCore(kp->lpCoreKeyboardState, SavedKBDOptions));
|
||||
EXPECT_EQ(km_kbp_state_option_lookup(kp->lpCoreKeyboardState, KM_KBP_OPT_KEYBOARD, test_env_opts[0].key, &retValue), KM_KBP_STATUS_OK);
|
||||
|
||||
value = retValue;
|
||||
expectedValue = u"not tiggered";
|
||||
EXPECT_TRUE(value == expectedValue);
|
||||
|
||||
DisposeKeyboardOptionsCore(&NewKBDOptions);
|
||||
DisposeKeyboardOptionsCore(&SavedKBDOptions);
|
||||
|
||||
ReleaseStateMemoryCore(&kp->lpCoreKeyboardState);
|
||||
ReleaseKeyboardMemoryCore(&kp->lpCoreKeyboard);
|
||||
delete kp;
|
||||
}
|
||||
|
||||
// Test SetupCoreEnvironment and also test km_kbp_state_options_update
|
||||
TEST(KEYBOARDOPTIONS, SetupCoreEnvironment) {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue