mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-28 18:47:41 +00:00
Merge pull request #8711 from keymanapp/feat/typescript-keymanweb-compiler
feat(developer): Rewrite of KeymanWeb compiler in Typescript
This commit is contained in:
commit
169ba9a8ae
40 changed files with 12565 additions and 19 deletions
|
|
@ -78,7 +78,7 @@ fi
|
|||
|
||||
if builder_start_action test; then
|
||||
copy_schemas
|
||||
npm test
|
||||
npm test -- "${builder_extra_params[@]}"
|
||||
builder_finish_action success test
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -17,12 +17,19 @@ export class TouchLayoutFileWriter {
|
|||
* @param source TouchLayoutFile
|
||||
* @returns Uint8Array, the .keyman-touch-layout file
|
||||
*/
|
||||
write(source: TouchLayoutFile): Uint8Array {
|
||||
const output = JSON.stringify(source, null, this.options?.formatted ? 2 : undefined);
|
||||
public write(source: TouchLayoutFile): Uint8Array {
|
||||
const output = this.toJSONString(source);
|
||||
const encoder = new TextEncoder();
|
||||
return encoder.encode(output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the output as a JSON string
|
||||
*/
|
||||
public toJSONString(source: TouchLayoutFile): string {
|
||||
return JSON.stringify(source, null, this.options?.formatted ? 2 : undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the touch layout file into a KeymanWeb-compatible JSON-style
|
||||
* object string. In the future, this may be optimized to remove unnecessary
|
||||
|
|
@ -31,7 +38,11 @@ export class TouchLayoutFileWriter {
|
|||
* @param source
|
||||
* @returns string
|
||||
*/
|
||||
compile(source: TouchLayoutFile): string {
|
||||
public compile(source: TouchLayoutFile): string {
|
||||
return this.toJSONString(this.fixup(source));
|
||||
}
|
||||
|
||||
public fixup(source: TouchLayoutFile): TouchLayoutFile {
|
||||
// Deep copy the source
|
||||
source = JSON.parse(JSON.stringify(source));
|
||||
|
||||
|
|
@ -40,13 +51,23 @@ export class TouchLayoutFileWriter {
|
|||
|
||||
const fixupKey = (key: TouchLayoutKey | TouchLayoutSubKey) => {
|
||||
if(Object.hasOwn(key, 'pad')) (key.pad as any) = key.pad.toString();
|
||||
if(Object.hasOwn(key, 'sp')) (key.sp as any) = key.sp.toString();
|
||||
if(Object.hasOwn(key, 'sp')) {
|
||||
if(key.sp == 0) {
|
||||
delete key.sp;
|
||||
}
|
||||
else {
|
||||
(key.sp as any) = key.sp.toString();
|
||||
}
|
||||
}
|
||||
if(Object.hasOwn(key, 'width')) (key.width as any) = key.width.toString();
|
||||
if(Object.hasOwn(key, 'text') && key.text === '') delete key.text;
|
||||
};
|
||||
|
||||
const fixupPlatform = (platform: TouchLayoutPlatform) => {
|
||||
for(let layer of platform.layer) {
|
||||
for(let row of layer.row) {
|
||||
// this matches the old spec for touch layout files
|
||||
(row.id as any) = row.id.toString();
|
||||
for(let key of row.key) {
|
||||
fixupKey(key);
|
||||
if(key.sk) {
|
||||
|
|
@ -79,6 +100,6 @@ export class TouchLayoutFileWriter {
|
|||
fixupPlatform(source.tablet);
|
||||
}
|
||||
|
||||
return JSON.stringify(source, null, this.options?.formatted ? 2 : undefined);
|
||||
return source;
|
||||
}
|
||||
};
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { KMXFile, BUILDER_COMP_KEYBOARD, KEYBOARD, STORE } from "./kmx.js";
|
||||
import { KMXFile, BUILDER_COMP_KEYBOARD, KEYBOARD, STORE, GROUP, KEY } from "./kmx.js";
|
||||
import * as r from 'restructure';
|
||||
|
||||
export class KmxFileReader {
|
||||
|
|
@ -13,17 +13,60 @@ export class KmxFileReader {
|
|||
return this.rString.fromBuffer(source.slice(offset));
|
||||
}
|
||||
|
||||
private processSystemStore(store: STORE, result: KEYBOARD) {
|
||||
switch(store.dwSystemID) {
|
||||
case KMXFile.TSS_MNEMONIC:
|
||||
result.isMnemonic = store.dpString == '1';
|
||||
break;
|
||||
case KMXFile.TSS_KEYBOARDVERSION:
|
||||
result.keyboardVersion = store.dpString;
|
||||
break;
|
||||
case KMXFile.TSS_BEGIN_NEWCONTEXT:
|
||||
if(store.dpString.length == 3 && store.dpString.charCodeAt(0) == 0xFFFF && store.dpString.charCodeAt(1) == KMXFile.CODE_USE) {
|
||||
result.startGroup.newContext = store.dpString.charCodeAt(2) - 1;
|
||||
}
|
||||
else {
|
||||
// TODO: error
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case KMXFile.TSS_BEGIN_POSTKEYSTROKE:
|
||||
if(store.dpString.length == 3 && store.dpString.charCodeAt(0) == 0xFFFF && store.dpString.charCodeAt(1) == KMXFile.CODE_USE) {
|
||||
result.startGroup.postKeystroke = store.dpString.charCodeAt(2) - 1;
|
||||
}
|
||||
else {
|
||||
// TODO: error
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public read(source: Uint8Array): KEYBOARD {
|
||||
let binaryKeyboard: BUILDER_COMP_KEYBOARD;
|
||||
let kmx = new KMXFile();
|
||||
binaryKeyboard = kmx.COMP_KEYBOARD.fromBuffer(source);
|
||||
if(binaryKeyboard.dwIdentifier != KMXFile.FILEID_COMPILED) {
|
||||
// TODO: error
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: all header fields
|
||||
|
||||
let result = new KEYBOARD();
|
||||
result.fileVersion = binaryKeyboard.dwFileVersion;
|
||||
result.flags = binaryKeyboard.dwFlags;
|
||||
result.hotkey = binaryKeyboard.dwHotKey;
|
||||
result.startGroup = {
|
||||
ansi: binaryKeyboard.StartGroup_ANSI == 0xFFFFFFFF ? -1 : binaryKeyboard.StartGroup_ANSI,
|
||||
unicode: binaryKeyboard.StartGroup_Unicode == 0xFFFFFFFF ? -1 : binaryKeyboard.StartGroup_Unicode,
|
||||
newContext: -1, //TODO
|
||||
postKeystroke: -1 // TODO
|
||||
}
|
||||
|
||||
// Informative data
|
||||
result.keyboardVersion = '';
|
||||
result.isMnemonic = false;
|
||||
|
||||
let offset = binaryKeyboard.dpStoreArray;
|
||||
for(let i = 0; i < binaryKeyboard.cxStoreArray; i++) {
|
||||
let binaryStore = kmx.COMP_STORE.fromBuffer(source.slice(offset));
|
||||
|
|
@ -32,13 +75,52 @@ export class KmxFileReader {
|
|||
store.dpName = this.readString(source, binaryStore.dpName);
|
||||
store.dpString = this.readString(source, binaryStore.dpString);
|
||||
result.stores.push(store);
|
||||
|
||||
if(!this.processSystemStore(store, result)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
offset += KMXFile.COMP_STORE_SIZE;
|
||||
}
|
||||
|
||||
// TODO: groups
|
||||
offset = binaryKeyboard.dpGroupArray;
|
||||
for(let i = 0; i < binaryKeyboard.cxGroupArray; i++) {
|
||||
let binaryGroup = kmx.COMP_GROUP.fromBuffer(source.slice(offset));
|
||||
let group = new GROUP();
|
||||
group.dpMatch = this.readString(source, binaryGroup.dpMatch);
|
||||
group.dpName = this.readString(source, binaryGroup.dpName);
|
||||
group.dpNoMatch = this.readString(source, binaryGroup.dpNoMatch);
|
||||
group.fUsingKeys = binaryGroup.fUsingKeys;
|
||||
group.keys = [];
|
||||
|
||||
let keyOffset = binaryGroup.dpKeyArray;
|
||||
for(let j = 0; j < binaryGroup.cxKeyArray; j++) {
|
||||
let binaryKey = kmx.COMP_KEY.fromBuffer(source.slice(keyOffset));
|
||||
let key = new KEY();
|
||||
key.Key = binaryKey.Key;
|
||||
key.Line = binaryKey.Line;
|
||||
key.ShiftFlags = binaryKey.ShiftFlags;
|
||||
key.dpContext = this.readString(source, binaryKey.dpContext);
|
||||
key.dpOutput = this.readString(source, binaryKey.dpOutput);
|
||||
group.keys.push(key);
|
||||
keyOffset += KMXFile.COMP_KEY_SIZE;
|
||||
}
|
||||
|
||||
result.groups.push(group);
|
||||
offset += KMXFile.COMP_GROUP_SIZE;
|
||||
}
|
||||
|
||||
// TODO: KMXPlusFile
|
||||
|
||||
// Validate startGroup offsets
|
||||
let gp: keyof KEYBOARD['startGroup'];
|
||||
for(gp in result.startGroup) {
|
||||
if(result.startGroup[gp] < -1 || result.startGroup[gp] >= result.groups.length) {
|
||||
// TODO: error
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
|
@ -8,9 +8,28 @@ import * as r from 'restructure';
|
|||
// kmx-builder will transform these to the corresponding COMP_xxxx
|
||||
|
||||
export class KEYBOARD {
|
||||
//TODO: additional header fields
|
||||
fileVersion?: number; // dwFileVersion (TSS_FILEVERSION)
|
||||
|
||||
startGroup: {
|
||||
ansi: number; // from COMP_KEYBOARD
|
||||
unicode: number; // from COMP_KEYBOARD
|
||||
newContext: number; // from TSS_BEGIN_NEWCONTEXT store
|
||||
postKeystroke: number; // from TSS_BEGIN_POSTKEYSTROKE store
|
||||
} = {ansi:-1, unicode:-1, newContext:-1, postKeystroke:-1};
|
||||
|
||||
flags?: number;
|
||||
hotkey?: number;
|
||||
|
||||
//bitmap:
|
||||
groups: GROUP[] = [];
|
||||
stores: STORE[] = [];
|
||||
|
||||
// Following values are extracted from stores[] but are
|
||||
// informative only
|
||||
|
||||
keyboardVersion?: string; // version (TSS_KEYBOARDVERSION)
|
||||
isMnemonic: boolean; // TSS_MNEMONICLAYOUT store
|
||||
|
||||
};
|
||||
|
||||
export class STORE {
|
||||
|
|
@ -21,7 +40,7 @@ export class STORE {
|
|||
|
||||
export class GROUP {
|
||||
dpName: string;
|
||||
keys: KEY[];
|
||||
keys: KEY[] = [];
|
||||
dpMatch: string;
|
||||
dpNoMatch: string;
|
||||
fUsingKeys: boolean;
|
||||
|
|
@ -319,6 +338,21 @@ export class KMXFile {
|
|||
public static readonly ISVIRTUALKEY = 0x4000; // It is a Virtual Key Sequence
|
||||
public static readonly VIRTUALCHARKEY = 0x8000; // Keyman 6.0: Virtual Key Cap Sequence NOT YET
|
||||
|
||||
public static readonly MASK_MODIFIER_CHIRAL = KMXFile.LCTRLFLAG | KMXFile.RCTRLFLAG | KMXFile.LALTFLAG | KMXFile.RALTFLAG;
|
||||
public static readonly MASK_MODIFIER_SHIFT = KMXFile.K_SHIFTFLAG;
|
||||
public static readonly MASK_MODIFIER_NONCHIRAL = KMXFile.K_CTRLFLAG | KMXFile.K_ALTFLAG;
|
||||
|
||||
public static readonly MASK_STATEKEY = KMXFile.CAPITALFLAG | KMXFile.NOTCAPITALFLAG |
|
||||
KMXFile.NUMLOCKFLAG | KMXFile.NOTNUMLOCKFLAG |
|
||||
KMXFile.SCROLLFLAG | KMXFile.NOTSCROLLFLAG;
|
||||
public static readonly MASK_KEYTYPE = KMXFile.ISVIRTUALKEY | KMXFile.VIRTUALCHARKEY;
|
||||
|
||||
public static readonly MASK_MODIFIER = KMXFile.MASK_MODIFIER_CHIRAL | KMXFile.MASK_MODIFIER_SHIFT | KMXFile.MASK_MODIFIER_NONCHIRAL;
|
||||
|
||||
public static readonly MASK_KEYS = KMXFile.MASK_MODIFIER | KMXFile.MASK_STATEKEY;
|
||||
public static readonly KMX_MASK_VALID = KMXFile.MASK_KEYS | KMXFile.MASK_KEYTYPE;
|
||||
|
||||
|
||||
public static readonly K_MODIFIERFLAG = 0x007F;
|
||||
public static readonly K_NOTMODIFIERFLAG = 0xFF00; // I4548
|
||||
|
||||
|
|
@ -328,12 +362,13 @@ export class KMXFile {
|
|||
public static readonly COMP_GROUP_SIZE = 24;
|
||||
public static readonly COMP_KEY_SIZE = 20;
|
||||
|
||||
|
||||
public static readonly VERSION_MASK_MINOR = 0x00FF;
|
||||
public static readonly VERSION_MASK_MAJOR = 0xFF00;
|
||||
|
||||
/* In-memory representation of the keyboard */
|
||||
|
||||
public keyboard: KEYBOARD = {
|
||||
groups: [],
|
||||
stores: []
|
||||
};
|
||||
public keyboard: KEYBOARD = new KEYBOARD();
|
||||
|
||||
constructor() {
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ export class VisualKeyboardFont {
|
|||
name?: string;
|
||||
size?: number;
|
||||
color?: number; // unused
|
||||
style?: string; // TODO: figure out style vs color issues
|
||||
};
|
||||
|
||||
export { BUILDER_KVK_KEY_FLAGS as VisualKeyboardKeyFlags } from "./kvk-file.js";
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ builder_describe \
|
|||
test \
|
||||
":kmcmplib=src/kmcmplib Compiler - .kmn compiler" \
|
||||
":kmc-kmn=src/kmc-kmn Compiler - .kmn wrapper Keyboard Module" \
|
||||
":kmc-kmw=src/kmc-kmw Compiler - .kmn Javascript Keyboard Module" \
|
||||
":kmc-ldml=src/kmc-ldml Compiler - LDML Keyboard Module" \
|
||||
":kmc-model=src/kmc-model Compiler - Lexical Model Module" \
|
||||
":kmc-model-info=src/kmc-model-info Compiler - .model_info Module" \
|
||||
|
|
|
|||
|
|
@ -26,13 +26,15 @@ export interface CompilerOptions {
|
|||
saveDebug?: boolean;
|
||||
compilerWarningsAsErrors?: boolean;
|
||||
warnDeprecatedCode?: boolean;
|
||||
target?: 'kmx' | 'js';
|
||||
};
|
||||
|
||||
const baseOptions: CompilerOptions = {
|
||||
shouldAddCompilerVersion: true,
|
||||
saveDebug: true,
|
||||
compilerWarningsAsErrors: false,
|
||||
warnDeprecatedCode: true
|
||||
warnDeprecatedCode: true,
|
||||
target: 'kmx'
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -66,6 +68,7 @@ export class KmnCompiler {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return this.verifyInitialized();
|
||||
}
|
||||
|
||||
|
|
|
|||
39
developer/src/kmc-kmw/Makefile
Normal file
39
developer/src/kmc-kmw/Makefile
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#
|
||||
# Keyman Developer - kmc KMW Keyboard Compiler Makefile
|
||||
#
|
||||
|
||||
!include ..\Defines.mak
|
||||
|
||||
# We do configure here because parent Makefile calls this first; other
|
||||
# kmc and kmc-* makefiles don't do it
|
||||
build: configure .virtual
|
||||
$(GIT_BASH_FOR_KEYMAN) build.sh build
|
||||
|
||||
configure: .virtual
|
||||
$(GIT_BASH_FOR_KEYMAN) build.sh configure
|
||||
|
||||
clean: .virtual
|
||||
$(GIT_BASH_FOR_KEYMAN) build.sh clean
|
||||
|
||||
test: .virtual
|
||||
$(GIT_BASH_FOR_KEYMAN) build.sh test
|
||||
|
||||
# build.sh bundle must be run from shell as it requires a temp folder to be
|
||||
# passed in. See inst/download.in.mak for instantiation.
|
||||
|
||||
publish: .virtual
|
||||
$(GIT_BASH_FOR_KEYMAN) build.sh publish
|
||||
|
||||
signcode:
|
||||
@rem nothing to do
|
||||
|
||||
wrap-symbols:
|
||||
@rem nothing to do
|
||||
|
||||
test-manifest:
|
||||
@rem nothing to do
|
||||
|
||||
install:
|
||||
@rem nothing to do
|
||||
|
||||
!include ..\Target.mak
|
||||
68
developer/src/kmc-kmw/build.sh
Executable file
68
developer/src/kmc-kmw/build.sh
Executable file
|
|
@ -0,0 +1,68 @@
|
|||
#!/usr/bin/env bash
|
||||
## START STANDARD BUILD SCRIPT INCLUDE
|
||||
# adjust relative paths as necessary
|
||||
THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
|
||||
. "${THIS_SCRIPT%/*}/../../../resources/build/build-utils.sh"
|
||||
## END STANDARD BUILD SCRIPT INCLUDE
|
||||
|
||||
cd "$THIS_SCRIPT_PATH"
|
||||
|
||||
. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh"
|
||||
. "$KEYMAN_ROOT/resources/build/build-utils-ci.inc.sh"
|
||||
|
||||
builder_describe "Build Keyman kmc KMW Keyboard Compiler module" \
|
||||
"@/common/web/types" \
|
||||
"@/developer/src/kmc-kmn" \
|
||||
"configure" \
|
||||
"build" \
|
||||
"clean" \
|
||||
"test" \
|
||||
"pack build a local .tgz pack for testing" \
|
||||
"publish publish to npm" \
|
||||
"--dry-run,-n don't actually publish, just dry run"
|
||||
|
||||
builder_describe_outputs \
|
||||
configure /node_modules \
|
||||
build build/src/main.js
|
||||
|
||||
builder_parse "$@"
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
function copy_schema() {
|
||||
# We need the schema file at runtime and bundled, so always copy it for all
|
||||
# actions except `clean` and `configure`
|
||||
mkdir -p "$THIS_SCRIPT_PATH/build/src/"
|
||||
cp "$KEYMAN_ROOT/common/schemas/keyman-touch-layout/keyman-touch-layout.spec.json" "$THIS_SCRIPT_PATH/build/src/"
|
||||
cp "$KEYMAN_ROOT/common/schemas/kvks/kvks.schema.json" "$THIS_SCRIPT_PATH/build/src/"
|
||||
}
|
||||
|
||||
function do_build() {
|
||||
copy_schema
|
||||
npm run build
|
||||
}
|
||||
|
||||
function do_test() {
|
||||
# TODO: add c8 for coverage
|
||||
copy_schema
|
||||
npm test
|
||||
}
|
||||
|
||||
function do_publish() {
|
||||
copy_schema
|
||||
builder_publish_to_npm
|
||||
}
|
||||
|
||||
function do_pack() {
|
||||
copy_schema
|
||||
builder_publish_to_pack
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
builder_run_action clean rm -rf ./build/ ./tsconfig.tsbuildinfo
|
||||
builder_run_action configure verify_npm_setup
|
||||
builder_run_action build do_build
|
||||
builder_run_action test do_test
|
||||
builder_run_action pack do_pack
|
||||
builder_run_action publish do_publish
|
||||
56
developer/src/kmc-kmw/package.json
Normal file
56
developer/src/kmc-kmw/package.json
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"name": "@keymanapp/kmc-kmw",
|
||||
"description": "Keyman Developer KMW keyboard compiler",
|
||||
"keywords": [
|
||||
"keyboard",
|
||||
"keyman",
|
||||
"ldml",
|
||||
"unicode"
|
||||
],
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": "./build/src/main.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc -b",
|
||||
"tsc": "tsc",
|
||||
"test": "cd test && tsc -b && cd .. && mocha",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"author": "Marc Durdin <marc@keyman.com> (https://github.com/mcdurdin)",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/keymanapp/keyman/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@keymanapp/common-types": "*",
|
||||
"@keymanapp/kmc-kmn": "*",
|
||||
"ajv": "^8.11.0",
|
||||
"restructure": "git+https://github.com/keymanapp/dependency-restructure.git#49d129cf0916d082a7278bb09296fb89cecfcc50",
|
||||
"semver": "^7.3.7",
|
||||
"xml2js": "git+https://github.com/keymanapp/dependency-node-xml2js#535fe732dc408d697e0f847c944cc45f0baf0829"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.1.7",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "^10.14.6",
|
||||
"@types/semver": "^7.3.12",
|
||||
"@types/xml2js": "^0.4.5",
|
||||
"c8": "^7.12.0",
|
||||
"chai": "^4.3.4",
|
||||
"chalk": "^2.4.2",
|
||||
"mocha": "^8.4.0",
|
||||
"ts-node": "^9.1.1",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"mocha": {
|
||||
"spec": "build/test/**/test-*.js",
|
||||
"require": [
|
||||
"source-map-support/register"
|
||||
]
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/keymanapp/keyman.git"
|
||||
}
|
||||
}
|
||||
14
developer/src/kmc-kmw/src/compiler/callbacks.ts
Normal file
14
developer/src/kmc-kmw/src/compiler/callbacks.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
export interface CompilerEvent {
|
||||
line: number;
|
||||
code: number;
|
||||
message: string;
|
||||
};
|
||||
|
||||
export default interface CompilerCallbacks {
|
||||
loadFile(baseFilename: string, filename: string): Buffer;
|
||||
loadLdmlKeyboardSchema(): Buffer;
|
||||
loadKvksJsonSchema(): Buffer;
|
||||
reportMessage(event: CompilerEvent): void;
|
||||
};
|
||||
|
||||
// TODO: eliminate this
|
||||
30
developer/src/kmc-kmw/src/compiler/compiler-globals.ts
Normal file
30
developer/src/kmc-kmw/src/compiler/compiler-globals.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { KMX, CompilerCallbacks } from "@keymanapp/common-types";
|
||||
import CompilerOptions from "./compiler-options.js";
|
||||
|
||||
export let FTabStop: string;
|
||||
export let nl: string;
|
||||
export let FCompilerWarningsAsErrors = false;
|
||||
export let fk: KMX.KEYBOARD;
|
||||
export let FMnemonic: boolean;
|
||||
export let options: CompilerOptions;
|
||||
export let callbacks: CompilerCallbacks;
|
||||
|
||||
export function setupGlobals(_callbacks: CompilerCallbacks, _options: CompilerOptions, _tab: string, _nl: string, _keyboard: KMX.KEYBOARD) {
|
||||
callbacks = _callbacks;
|
||||
options = _options;
|
||||
FTabStop = _tab;
|
||||
nl = _nl;
|
||||
fk = _keyboard;
|
||||
}
|
||||
|
||||
export function IsKeyboardVersion10OrLater(): boolean {
|
||||
return fk.fileVersion >= KMX.KMXFile.VERSION_100;
|
||||
}
|
||||
|
||||
export function IsKeyboardVersion14OrLater(): boolean {
|
||||
return fk.fileVersion >= KMX.KMXFile.VERSION_140;
|
||||
}
|
||||
|
||||
export function IsKeyboardVersion15OrLater(): boolean {
|
||||
return fk.fileVersion >= KMX.KMXFile.VERSION_150;
|
||||
}
|
||||
15
developer/src/kmc-kmw/src/compiler/compiler-options.ts
Normal file
15
developer/src/kmc-kmw/src/compiler/compiler-options.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
|
||||
export default interface CompilerOptions {
|
||||
/**
|
||||
* Add debug information to the .kmx file when compiling
|
||||
*/
|
||||
debug: boolean;
|
||||
|
||||
/**
|
||||
* Add metadata about the compiler version to .kmx file when compiling
|
||||
*/
|
||||
addCompilerVersion: boolean;
|
||||
};
|
||||
|
||||
// TODO: we have a shared CompilerOptions intf, eliminate this
|
||||
1561
developer/src/kmc-kmw/src/compiler/javascript-strings.ts
Normal file
1561
developer/src/kmc-kmw/src/compiler/javascript-strings.ts
Normal file
File diff suppressed because it is too large
Load diff
271
developer/src/kmc-kmw/src/compiler/keymanweb-key-codes.ts
Normal file
271
developer/src/kmc-kmw/src/compiler/keymanweb-key-codes.ts
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
export const
|
||||
CKeymanWebKeyCodes: number[] = [
|
||||
0xFF, // L"K_?00", // &H0
|
||||
0xFF, // L"K_LBUTTON", // &H1
|
||||
0xFF, // L"K_RBUTTON", // &H2
|
||||
0xFF, // L"K_CANCEL", // &H3
|
||||
0xFF, // L"K_MBUTTON", // &H4
|
||||
0xFF, // L"K_?05", // &H5
|
||||
0xFF, // L"K_?06", // &H6
|
||||
0xFF, // L"K_?07", // &H7
|
||||
0xFF, // L"K_BKSP", // &H8
|
||||
0xFF, // L"K_TAB", // &H9
|
||||
0xFF, // L"K_?0A", // &HA
|
||||
0xFF, // L"K_?0B", // &HB
|
||||
0xFF, // L"K_KP5", // &HC
|
||||
0xFF, // L"K_ENTER", // &HD
|
||||
0xFF, // L"K_?0E", // &HE
|
||||
0xFF, // L"K_?0F", // &HF
|
||||
0xFF, // L"K_SHIFT", // &H10
|
||||
0xFF, // L"K_CONTROL", // &H11
|
||||
0xFF, // L"K_ALT", // &H12
|
||||
0xFF, // L"K_PAUSE", // &H13
|
||||
0xFF, // L"K_CAPS", // &H14
|
||||
0xFF, // L"K_KANJI?15", // &H15
|
||||
0xFF, // L"K_KANJI?16", // &H16
|
||||
0xFF, // L"K_KANJI?17", // &H17
|
||||
0xFF, // L"K_KANJI?18", // &H18
|
||||
0xFF, // L"K_KANJI?19", // &H19
|
||||
0xFF, // L"K_?1A", // &H1A
|
||||
0xFF, // L"K_ESC", // &H1B
|
||||
0xFF, // L"K_KANJI?1C", // &H1C
|
||||
0xFF, // L"K_KANJI?1D", // &H1D
|
||||
0xFF, // L"K_KANJI?1E", // &H1E
|
||||
0xFF, // L"K_KANJI?1F", // &H1F
|
||||
0x40, // L"K_SPACE", // &H20
|
||||
0xFF, // L"K_PGUP", // &H21
|
||||
0xFF, // L"K_PGDN", // &H22
|
||||
0xFF, // L"K_END", // &H23
|
||||
0xFF, // L"K_HOME", // &H24
|
||||
0xFF, // L"K_LEFT", // &H25
|
||||
0xFF, // L"K_UP", // &H26
|
||||
0xFF, // L"K_RIGHT", // &H27
|
||||
0xFF, // L"K_DOWN", // &H28
|
||||
0xFF, // L"K_SEL", // &H29
|
||||
0xFF, // L"K_PRINT", // &H2A
|
||||
0xFF, // L"K_EXEC", // &H2B
|
||||
0xFF, // L"K_PRTSCN", // &H2C
|
||||
0xFF, // L"K_INS", // &H2D
|
||||
0xFF, // L"K_DEL", // &H2E
|
||||
0xFF, // L"K_HELP", // &H2F
|
||||
0x0A, // L"K_0", // &H30
|
||||
0x01, // L"K_1", // &H31
|
||||
0x02, // L"K_2", // &H32
|
||||
0x03, // L"K_3", // &H33
|
||||
0x04, // L"K_4", // &H34
|
||||
0x05, // L"K_5", // &H35
|
||||
0x06, // L"K_6", // &H36
|
||||
0x07, // L"K_7", // &H37
|
||||
0x08, // L"K_8", // &H38
|
||||
0x09, // L"K_9", // &H39
|
||||
0xFF, // L"K_?3A", // &H3A
|
||||
0xFF, // L"K_?3B", // &H3B
|
||||
0xFF, // L"K_?3C", // &H3C
|
||||
0xFF, // L"K_?3D", // &H3D
|
||||
0xFF, // L"K_?3E", // &H3E
|
||||
0xFF, // L"K_?3F", // &H3F
|
||||
0xFF, // L"K_?40", // &H40
|
||||
|
||||
0x20, // L"K_A", // &H41
|
||||
0x35, // L"K_B", // &H42
|
||||
0x33, // L"K_C", // &H43
|
||||
0x22, // L"K_D", // &H44
|
||||
0x12, // L"K_E", // &H45
|
||||
0x23, // L"K_F", // &H46
|
||||
0x24, // L"K_G", // &H47
|
||||
0x25, // L"K_H", // &H48
|
||||
0x17, // L"K_I", // &H49
|
||||
0x26, // L"K_J", // &H4A
|
||||
0x27, // L"K_K", // &H4B
|
||||
0x28, // L"K_L", // &H4C
|
||||
0x37, // L"K_M", // &H4D
|
||||
0x36, // L"K_N", // &H4E
|
||||
0x18, // L"K_O", // &H4F
|
||||
0x19, // L"K_P", // &H50
|
||||
0x10, // L"K_Q", // &H51
|
||||
0x13, // L"K_R", // &H52
|
||||
0x21, // L"K_S", // &H53
|
||||
0x14, // L"K_T", // &H54
|
||||
0x16, // L"K_U", // &H55
|
||||
0x34, // L"K_V", // &H56
|
||||
0x11, // L"K_W", // &H57
|
||||
0x32, // L"K_X", // &H58
|
||||
0x15, // L"K_Y", // &H59
|
||||
0x31, // L"K_Z", // &H5A
|
||||
0xFF, // L"K_?5B", // &H5B
|
||||
0xFF, // L"K_?5C", // &H5C
|
||||
0xFF, // L"K_?5D", // &H5D
|
||||
0xFF, // L"K_?5E", // &H5E
|
||||
0xFF, // L"K_?5F", // &H5F
|
||||
0xFF, // L"K_NP0", // &H60
|
||||
0xFF, // L"K_NP1", // &H61
|
||||
0xFF, // L"K_NP2", // &H62
|
||||
0xFF, // L"K_NP3", // &H63
|
||||
0xFF, // L"K_NP4", // &H64
|
||||
0xFF, // L"K_NP5", // &H65
|
||||
0xFF, // L"K_NP6", // &H66
|
||||
0xFF, // L"K_NP7", // &H67
|
||||
0xFF, // L"K_NP8", // &H68
|
||||
0xFF, // L"K_NP9", // &H69
|
||||
0xFF, // L"K_NPSTAR", // &H6A
|
||||
0xFF, // L"K_NPPLUS", // &H6B
|
||||
0xFF, // L"K_SEPARATOR", // &H6C
|
||||
0xFF, // L"K_NPMINUS", // &H6D
|
||||
0xFF, // L"K_NPDOT", // &H6E
|
||||
0xFF, // L"K_NPSLASH", // &H6F
|
||||
0xFF, // L"K_F1", // &H70
|
||||
0xFF, // L"K_F2", // &H71
|
||||
0xFF, // L"K_F3", // &H72
|
||||
0xFF, // L"K_F4", // &H73
|
||||
0xFF, // L"K_F5", // &H74
|
||||
0xFF, // L"K_F6", // &H75
|
||||
0xFF, // L"K_F7", // &H76
|
||||
0xFF, // L"K_F8", // &H77
|
||||
0xFF, // L"K_F9", // &H78
|
||||
0xFF, // L"K_F10", // &H79
|
||||
0xFF, // L"K_F11", // &H7A
|
||||
0xFF, // L"K_F12", // &H7B
|
||||
0xFF, // L"K_F13", // &H7C
|
||||
0xFF, // L"K_F14", // &H7D
|
||||
0xFF, // L"K_F15", // &H7E
|
||||
0xFF, // L"K_F16", // &H7F
|
||||
0xFF, // L"K_F17", // &H80
|
||||
0xFF, // L"K_F18", // &H81
|
||||
0xFF, // L"K_F19", // &H82
|
||||
0xFF, // L"K_F20", // &H83
|
||||
0xFF, // L"K_F21", // &H84
|
||||
0xFF, // L"K_F22", // &H85
|
||||
0xFF, // L"K_F23", // &H86
|
||||
0xFF, // L"K_F24", // &H87
|
||||
|
||||
0xFF, // L"K_?88", // &H88
|
||||
0xFF, // L"K_?89", // &H89
|
||||
0xFF, // L"K_?8A", // &H8A
|
||||
0xFF, // L"K_?8B", // &H8B
|
||||
0xFF, // L"K_?8C", // &H8C
|
||||
0xFF, // L"K_?8D", // &H8D
|
||||
0xFF, // L"K_?8E", // &H8E
|
||||
0xFF, // L"K_?8F", // &H8F
|
||||
|
||||
0xFF, // L"K_NUMLOCK", // &H90
|
||||
0xFF, // L"K_SCROLL", // &H91
|
||||
|
||||
0xFF, // L"K_?92", // &H92
|
||||
0xFF, // L"K_?93", // &H93
|
||||
0xFF, // L"K_?94", // &H94
|
||||
0xFF, // L"K_?95", // &H95
|
||||
0xFF, // L"K_?96", // &H96
|
||||
0xFF, // L"K_?97", // &H97
|
||||
0xFF, // L"K_?98", // &H98
|
||||
0xFF, // L"K_?99", // &H99
|
||||
0xFF, // L"K_?9A", // &H9A
|
||||
0xFF, // L"K_?9B", // &H9B
|
||||
0xFF, // L"K_?9C", // &H9C
|
||||
0xFF, // L"K_?9D", // &H9D
|
||||
0xFF, // L"K_?9E", // &H9E
|
||||
0xFF, // L"K_?9F", // &H9F
|
||||
0xFF, // L"K_?A0", // &HA0
|
||||
0xFF, // L"K_?A1", // &HA1
|
||||
0xFF, // L"K_?A2", // &HA2
|
||||
0xFF, // L"K_?A3", // &HA3
|
||||
0xFF, // L"K_?A4", // &HA4
|
||||
0xFF, // L"K_?A5", // &HA5
|
||||
0xFF, // L"K_?A6", // &HA6
|
||||
0xFF, // L"K_?A7", // &HA7
|
||||
0xFF, // L"K_?A8", // &HA8
|
||||
0xFF, // L"K_?A9", // &HA9
|
||||
0xFF, // L"K_?AA", // &HAA
|
||||
0xFF, // L"K_?AB", // &HAB
|
||||
0xFF, // L"K_?AC", // &HAC
|
||||
0xFF, // L"K_?AD", // &HAD
|
||||
0xFF, // L"K_?AE", // &HAE
|
||||
0xFF, // L"K_?AF", // &HAF
|
||||
0xFF, // L"K_?B0", // &HB0
|
||||
0xFF, // L"K_?B1", // &HB1
|
||||
0xFF, // L"K_?B2", // &HB2
|
||||
0xFF, // L"K_?B3", // &HB3
|
||||
0xFF, // L"K_?B4", // &HB4
|
||||
0xFF, // L"K_?B5", // &HB5
|
||||
0xFF, // L"K_?B6", // &HB6
|
||||
0xFF, // L"K_?B7", // &HB7
|
||||
0xFF, // L"K_?B8", // &HB8
|
||||
0xFF, // L"K_?B9", // &HB9
|
||||
|
||||
0x29, // L"K_COLON", // &HBA
|
||||
0x0C, // L"K_EQUAL", // &HBB
|
||||
0x38, // L"K_COMMA", // &HBC
|
||||
0x0B, // L"K_HYPHEN", // &HBD
|
||||
0x39, // L"K_PERIOD", // &HBE
|
||||
0x3A, // L"K_SLASH", // &HBF
|
||||
0x00, // L"K_BKQUOTE", // &HC0
|
||||
|
||||
0x00, // L"K_?C1", // &HC1
|
||||
0x00, // L"K_?C2", // &HC2
|
||||
0x00, // L"K_?C3", // &HC3
|
||||
0x00, // L"K_?C4", // &HC4
|
||||
0x00, // L"K_?C5", // &HC5
|
||||
0x00, // L"K_?C6", // &HC6
|
||||
0x00, // L"K_?C7", // &HC7
|
||||
0x00, // L"K_?C8", // &HC8
|
||||
0x00, // L"K_?C9", // &HC9
|
||||
0x00, // L"K_?CA", // &HCA
|
||||
0x00, // L"K_?CB", // &HCB
|
||||
0x00, // L"K_?CC", // &HCC
|
||||
0x00, // L"K_?CD", // &HCD
|
||||
0x00, // L"K_?CE", // &HCE
|
||||
0x00, // L"K_?CF", // &HCF
|
||||
0x00, // L"K_?D0", // &HD0
|
||||
0x00, // L"K_?D1", // &HD1
|
||||
0x00, // L"K_?D2", // &HD2
|
||||
0x00, // L"K_?D3", // &HD3
|
||||
0x00, // L"K_?D4", // &HD4
|
||||
0x00, // L"K_?D5", // &HD5
|
||||
0x00, // L"K_?D6", // &HD6
|
||||
0x00, // L"K_?D7", // &HD7
|
||||
0x00, // L"K_?D8", // &HD8
|
||||
0x00, // L"K_?D9", // &HD9
|
||||
0x00, // L"K_?DA", // &HDA
|
||||
|
||||
0x1A, // L"K_LBRKT", // &HDB
|
||||
0x1C, // L"K_BKSLASH", // &HDC
|
||||
0x1B, // L"K_RBRKT", // &HDD
|
||||
0x2A, // L"K_QUOTE", // &HDE
|
||||
0x00, // L"K_oDF", // &HDF
|
||||
0x00, // L"K_oE0", // &HE0
|
||||
0x00, // L"K_oE1", // &HE1
|
||||
0x30, // L"K_oE2", // &HE2
|
||||
0x00, // L"K_oE3", // &HE3
|
||||
0x00, // L"K_oE4", // &HE4
|
||||
|
||||
0x00, // L"K_?E5", // &HE5
|
||||
|
||||
0x00, // L"K_oE6", // &HE6
|
||||
|
||||
0x00, // L"K_?E7", // &HE7
|
||||
0x00, // L"K_?E8", // &HE8
|
||||
|
||||
0x00, // L"K_oE9", // &HE9
|
||||
0x00, // L"K_oEA", // &HEA
|
||||
0x00, // L"K_oEB", // &HEB
|
||||
0x00, // L"K_oEC", // &HEC
|
||||
0x00, // L"K_oED", // &HED
|
||||
0x00, // L"K_oEE", // &HEE
|
||||
0x00, // L"K_oEF", // &HEF
|
||||
0x00, // L"K_oF0", // &HF0
|
||||
0x00, // L"K_oF1", // &HF1
|
||||
0x00, // L"K_oF2", // &HF2
|
||||
0x00, // L"K_oF3", // &HF3
|
||||
0x00, // L"K_oF4", // &HF4
|
||||
0x00, // L"K_oF5", // &HF5
|
||||
|
||||
0x00, // L"K_?F6", // &HF6
|
||||
0x00, // L"K_?F7", // &HF7
|
||||
0x00, // L"K_?F8", // &HF8
|
||||
0x00, // L"K_?F9", // &HF9
|
||||
0x00, // L"K_?FA", // &HFA
|
||||
0x00, // L"K_?FB", // &HFB
|
||||
0x00, // L"K_?FC", // &HFC
|
||||
0x00, // L"K_?FD", // &HFD
|
||||
0x00, // L"K_?FE", // &HFE
|
||||
0x00 // L"K_?FF" // &HFF
|
||||
];
|
||||
220
developer/src/kmc-kmw/src/compiler/messages.ts
Normal file
220
developer/src/kmc-kmw/src/compiler/messages.ts
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
import { callbacks, FCompilerWarningsAsErrors } from "./compiler-globals.js";
|
||||
|
||||
export let FError = false;
|
||||
|
||||
export function ReportError(line: number, msgcode: number, text: string) { // I1971
|
||||
let flag = CERR_FLAG | CFATAL_FLAG;
|
||||
if(FCompilerWarningsAsErrors) {
|
||||
flag |= CWARN_FLAG;
|
||||
}
|
||||
if (msgcode & flag) {
|
||||
FError = true;
|
||||
}
|
||||
// TODO: these Codes Are All Wrong But We'll Fix It Soon
|
||||
callbacks.reportMessage({code: msgcode, message: text, line}); // I3310
|
||||
}
|
||||
|
||||
export const
|
||||
CHINT_FLAG = 0x1000,
|
||||
CWARN_FLAG = 0x2000,
|
||||
CERR_FLAG = 0x4000,
|
||||
CFATAL_FLAG = 0x8000,
|
||||
|
||||
// Any messages from the lexical model compiler occupy this range:
|
||||
CERR_LEXICAL_MODEL_MIN = 0x0800,
|
||||
CERR_LEXICAL_MODEL_MAX = 0x08FF,
|
||||
|
||||
CERR_None = 0x0000,
|
||||
CERR_EndOfFile = 0x0001,
|
||||
|
||||
CERR_BadCallParams = 0x8002,
|
||||
CERR_CannotAllocateMemory = 0x9004,
|
||||
CERR_InfileNotExist = 0x8005,
|
||||
CERR_CannotCreateOutfile = 0x8006,
|
||||
CERR_UnableToWriteFully = 0x8007,
|
||||
CERR_CannotReadInfile = 0x8008,
|
||||
CERR_SomewhereIGotItWrong = 0x8009,
|
||||
|
||||
CERR_InvalidToken = 0x400A,
|
||||
CERR_InvalidBegin = 0x400B,
|
||||
CERR_InvalidName = 0x400C,
|
||||
CERR_InvalidVersion = 0x400D,
|
||||
CERR_InvalidLanguageLine = 0x400E,
|
||||
CERR_LayoutButNoLanguage = 0x400F,
|
||||
CERR_InvalidLayoutLine = 0x4010,
|
||||
CERR_NoVersionLine = 0x4011,
|
||||
CERR_InvalidGroupLine = 0x4012,
|
||||
CERR_InvalidStoreLine = 0x4013,
|
||||
CERR_InvalidCodeInKeyPartOfRule = 0x4014,
|
||||
CERR_InvalidDeadkey = 0x4015,
|
||||
CERR_InvalidValue = 0x4016,
|
||||
CERR_ZeroLengthString = 0x4017,
|
||||
CERR_TooManyIndexToKeyRefs = 0x4018,
|
||||
CERR_UnterminatedString = 0x4019,
|
||||
CERR_StringInVirtualKeySection = 0x401A,
|
||||
CERR_AnyInVirtualKeySection = 0x401B,
|
||||
CERR_InvalidAny = 0x401C,
|
||||
CERR_StoreDoesNotExist = 0x401D,
|
||||
CERR_BeepInVirtualKeySection = 0x401E,
|
||||
CERR_IndexInVirtualKeySection = 0x401F,
|
||||
CERR_InvalidIndex = 0x4020,
|
||||
CERR_OutsInVirtualKeySection = 0x4021,
|
||||
CERR_InvalidOuts = 0x4022,
|
||||
CERR_ContextInVirtualKeySection = 0x4024,
|
||||
CERR_InvalidUse = 0x4025,
|
||||
CERR_GroupDoesNotExist = 0x4026,
|
||||
CERR_VirtualKeyNotAllowedHere = 0x4027,
|
||||
CERR_InvalidSwitch = 0x4028,
|
||||
CERR_NoTokensFound = 0x4029,
|
||||
CERR_InvalidLineContinuation = 0x402A,
|
||||
CERR_LineTooLong = 0x402B,
|
||||
CERR_InvalidCopyright = 0x402C,
|
||||
CERR_CodeInvalidInThisSection = 0x402D,
|
||||
CERR_InvalidMessage = 0x402E,
|
||||
CERR_InvalidLanguageName = 0x402F,
|
||||
CERR_InvalidBitmapLine = 0x4030,
|
||||
CERR_CannotReadBitmapFile = 0x4031,
|
||||
CERR_IndexDoesNotPointToAny = 0x4032,
|
||||
CERR_ReservedCharacter = 0x4033,
|
||||
CERR_InvalidCharacter = 0x4034,
|
||||
CERR_InvalidCall = 0x4035,
|
||||
CERR_CallInVirtualKeySection = 0x4036,
|
||||
CERR_CodeInvalidInKeyStore = 0x4037,
|
||||
CERR_CannotLoadIncludeFile = 0x4038,
|
||||
|
||||
CERR_60FeatureOnly_EthnologueCode = 0x4039,
|
||||
CERR_60FeatureOnly_MnemonicLayout = 0x403A,
|
||||
CERR_60FeatureOnly_OldCharPosMatching = 0x403B,
|
||||
CERR_60FeatureOnly_NamedCodes = 0x403C,
|
||||
CERR_60FeatureOnly_Contextn = 0x403D,
|
||||
CERR_501FeatureOnly_Call = 0x403E,
|
||||
|
||||
CERR_InvalidNamedCode = 0x403F,
|
||||
CERR_InvalidSystemStore = 0x4040,
|
||||
|
||||
CERR_CallIsProfessionalFeature = 0x4041,
|
||||
CERR_IncludeCodesIsProfessionalFeature = 0x4042,
|
||||
CERR_MnemonicLayoutIsProfessionalFeature = 0x4043,
|
||||
CERR_60FeatureOnly_VirtualCharKey = 0x4044,
|
||||
|
||||
CERR_VersionAlreadyIncluded = 0x4045,
|
||||
|
||||
CERR_70FeatureOnly = 0x4046,
|
||||
|
||||
CERR_80FeatureOnly = 0x4047,
|
||||
CERR_InvalidInVirtualKeySection = 0x4048,
|
||||
CERR_InvalidIf = 0x4049,
|
||||
CERR_InvalidReset = 0x404A,
|
||||
CERR_InvalidSet = 0x404B,
|
||||
CERR_InvalidSave = 0x404C,
|
||||
|
||||
CERR_InvalidEthnologueCode = 0x404D,
|
||||
|
||||
CERR_CannotCreateTempfile = 0x804E,
|
||||
|
||||
CERR_90FeatureOnly_IfSystemStores = 0x404F,
|
||||
CERR_IfSystemStore_NotFound = 0x4050,
|
||||
CERR_90FeatureOnly_SetSystemStores = 0x4051,
|
||||
CERR_SetSystemStore_NotFound = 0x4052,
|
||||
CERR_90FeatureOnlyVirtualKeyDictionary = 0x4053,
|
||||
|
||||
CERR_NotSupportedInKeymanWebContext = 0x4054,
|
||||
CERR_NotSupportedInKeymanWebOutput = 0x4055,
|
||||
CERR_NotSupportedInKeymanWebStore = 0x4056,
|
||||
CERR_VirtualCharacterKeysNotSupportedInKeymanWeb = 0x4057,
|
||||
CERR_VirtualKeysNotValidForMnemonicLayouts = 0x4058,
|
||||
CERR_InvalidTouchLayoutFile = 0x4059,
|
||||
CERR_TouchLayoutInvalidIdentifier = 0x405A, // I4142
|
||||
CERR_InvalidKeyCode = 0x405B, // I4142
|
||||
|
||||
CERR_90FeatureOnlyLayoutFile = 0x405C,
|
||||
CERR_90FeatureOnlyKeyboardVersion = 0x405D,
|
||||
CERR_KeyboardVersionFormatInvalid = 0x405E,
|
||||
CERR_ContextExHasInvalidOffset = 0x405F,
|
||||
CERR_90FeatureOnlyEmbedCSS = 0x4060,
|
||||
CERR_90FeatureOnlyTargets = 0x4061,
|
||||
CERR_ContextAndIndexInvalidInMatchNomatch = 0x4062,
|
||||
CERR_140FeatureOnlyContextAndNotAnyWeb = 0x4063,
|
||||
|
||||
CERR_ExpansionMustFollowCharacterOrVKey = 0x4064,
|
||||
CERR_VKeyExpansionMustBeFollowedByVKey = 0x4065,
|
||||
CERR_CharacterExpansionMustBeFollowedByCharacter = 0x4066,
|
||||
CERR_VKeyExpansionMustUseConsistentShift = 0x4067,
|
||||
CERR_ExpansionMustBePositive = 0x4068,
|
||||
|
||||
CERR_CasedKeysMustContainOnlyVirtualKeys = 0x4069,
|
||||
CERR_CasedKeysMustNotIncludeShiftStates = 0x406A,
|
||||
CERR_CasedKeysNotSupportedWithMnemonicLayout = 0x406B,
|
||||
|
||||
CERR_CannotUseReadWriteGroupFromReadonlyGroup = 0x406C,
|
||||
CERR_StatementNotPermittedInReadonlyGroup = 0x406D,
|
||||
CERR_OutputInReadonlyGroup = 0x406E,
|
||||
CERR_NewContextGroupMustBeReadonly = 0x406F,
|
||||
CERR_PostKeystrokeGroupMustBeReadonly = 0x4070,
|
||||
|
||||
CERR_DuplicateGroup = 0x4071,
|
||||
CERR_DuplicateStore = 0x4072,
|
||||
|
||||
CWARN_TooManyWarnings = 0x2080,
|
||||
CWARN_OldVersion = 0x2081,
|
||||
CWARN_BitmapNotUsed = 0x2082,
|
||||
CWARN_CustomLanguagesNotSupported = 0x2083,
|
||||
CWARN_KeyBadLength = 0x2084,
|
||||
CWARN_IndexStoreShort = 0x2085,
|
||||
CWARN_UnicodeInANSIGroup = 0x2086,
|
||||
CWARN_ANSIInUnicodeGroup = 0x2087,
|
||||
CWARN_UnicodeSurrogateUsed = 0x2088,
|
||||
CWARN_ReservedCharacter = 0x2089,
|
||||
CWARN_Info = 0x208A,
|
||||
CWARN_VirtualKeyWithMnemonicLayout = 0x208B,
|
||||
CWARN_VirtualCharKeyWithPositionalLayout = 0x208C,
|
||||
CWARN_StoreAlreadyUsedAsOptionOrCall = 0x208D,
|
||||
CWARN_StoreAlreadyUsedAsStoreOrCall = 0x208E,
|
||||
CWARN_StoreAlreadyUsedAsStoreOrOption = 0x208F,
|
||||
|
||||
CWARN_PunctuationInEthnologueCode = 0x2090,
|
||||
|
||||
CWARN_TouchLayoutMissingLayer = 0x2091,
|
||||
CWARN_TouchLayoutCustomKeyNotDefined = 0x2092,
|
||||
CWARN_TouchLayoutMissingRequiredKeys = 0x2093,
|
||||
CWARN_HelpFileMissing = 0x2094,
|
||||
CWARN_EmbedJsFileMissing = 0x2095,
|
||||
CWARN_TouchLayoutFileMissing = 0x2096,
|
||||
CWARN_VisualKeyboardFileMissing = 0x2097,
|
||||
CWARN_ExtendedShiftFlagsNotSupportedInKeymanWeb = 0x2098, // I4118
|
||||
CWARN_TouchLayoutUnidentifiedKey = 0x2099, // I4142
|
||||
CHINT_UnreachableKeyCode = 0x109A, // I4141
|
||||
|
||||
CWARN_CouldNotCopyJsonFile = 0x209B, // I4688
|
||||
CWARN_PlatformNotInTargets = 0x209C,
|
||||
|
||||
CWARN_HeaderStatementIsDeprecated = 0x209D,
|
||||
CWARN_UseNotLastStatementInRule = 0x209E,
|
||||
|
||||
CWARN_TouchLayoutFontShouldBeSameForAllPlatforms = 0x209F, // I4872
|
||||
CWARN_InvalidJSONMetadataFile = 0x20A0, // I4872
|
||||
CWARN_JSONMetadataOSKFontShouldMatchTouchFont = 0x20A1, // I4872
|
||||
|
||||
CWARN_DontMixChiralAndNonChiralModifiers = 0x20A3,
|
||||
CWARN_MixingLeftAndRightModifiers = 0x20A4,
|
||||
|
||||
CWARN_LanguageHeadersDeprecatedInKeyman10 = 0x20A5,
|
||||
|
||||
CHINT_NonUnicodeFile = 0x10A6,
|
||||
|
||||
CWARN_TooManyErrorsOrWarnings = 0x20A7,
|
||||
|
||||
CWARN_HotkeyHasInvalidModifier = 0x20A8,
|
||||
|
||||
CWARN_TouchLayoutSpecialLabelOnNormalKey = 0x20A9,
|
||||
|
||||
CWARN_OptionStoreNameInvalid = 0x20AA,
|
||||
|
||||
CWARN_NulNotFirstStatementInContext = 0x20AB,
|
||||
CWARN_IfShouldBeAtStartOfContext = 0x20AC,
|
||||
|
||||
CWARN_KeyShouldIncludeNCaps = 0x20AD,
|
||||
|
||||
CHINT_UnreachableRule = 0x10AE,
|
||||
CHINT_FilenameHasDifferingCase = 0x10AF,
|
||||
CWARN_MissingFile = 0x20B0;
|
||||
280
developer/src/kmc-kmw/src/compiler/validate-layout-file.ts
Normal file
280
developer/src/kmc-kmw/src/compiler/validate-layout-file.ts
Normal file
|
|
@ -0,0 +1,280 @@
|
|||
import { KMX, TouchLayout, TouchLayoutFileReader, TouchLayoutFileWriter } from "@keymanapp/common-types";
|
||||
import { callbacks, IsKeyboardVersion14OrLater, IsKeyboardVersion15OrLater } from "./compiler-globals.js";
|
||||
import { JavaScript_Key, VKeyNames } from "./javascript-strings.js";
|
||||
|
||||
|
||||
interface VLFOutput {
|
||||
output: string;
|
||||
result: boolean;
|
||||
};
|
||||
|
||||
function IsValidUnicodeValue(ch: number): boolean { // I4198
|
||||
return ((ch >= 0x0020) && (ch <= 0x007F)) ||
|
||||
((ch >= 0x00A0) && (ch <= 0x10FFFF));
|
||||
}
|
||||
|
||||
enum TKeyIdType { Key_Invalid, Key_Constant, Key_Touch, Key_Unicode, Key_Unicode_Multi }; // I4142
|
||||
|
||||
function GetKeyIdUnicodeType(value: string): TKeyIdType {
|
||||
let values = value.split('_');
|
||||
for(let v of values) {
|
||||
if(!IsValidUnicodeValue(parseInt(v,16))) {
|
||||
return TKeyIdType.Key_Invalid;
|
||||
}
|
||||
}
|
||||
if(values.length > 1) {
|
||||
return TKeyIdType.Key_Unicode_Multi;
|
||||
}
|
||||
return TKeyIdType.Key_Unicode;
|
||||
}
|
||||
|
||||
function KeyIdType(FId: string): TKeyIdType { // I4142
|
||||
FId = FId.toUpperCase();
|
||||
switch(FId.charAt(0)) {
|
||||
case 'T':
|
||||
return TKeyIdType.Key_Touch;
|
||||
case 'U':
|
||||
if(FId.startsWith('U_')) {
|
||||
return GetKeyIdUnicodeType(FId.substring(2));
|
||||
}
|
||||
default:
|
||||
// Note: can't use indexOf because some VKeyNames are mixed case, e.g. K_oE2
|
||||
if(VKeyNames.find(key => key.toUpperCase() == FId)) {
|
||||
return TKeyIdType.Key_Constant;
|
||||
}
|
||||
}
|
||||
return TKeyIdType.Key_Invalid;
|
||||
}
|
||||
|
||||
enum TRequiredKey { K_LOPT, K_BKSP, K_ENTER }; // I4447
|
||||
|
||||
const
|
||||
CRequiredKeys: TRequiredKey[] = [TRequiredKey.K_LOPT, TRequiredKey.K_BKSP, TRequiredKey.K_ENTER]; // I4447
|
||||
|
||||
// See also builder.js: specialCharacters; web/source/osk/oskKey.ts: specialCharacters
|
||||
const
|
||||
CSpecialText10: string =
|
||||
'*Shift*\0*Enter*\0*Tab*\0*BkSp*\0*Menu*\0*Hide*\0*Alt*\0*Ctrl*\0*Caps*\0'+
|
||||
'*ABC*\0*abc*\0*123*\0*Symbol*\0*Currency*\0*Shifted*\0*AltGr*\0*TabLeft*',
|
||||
|
||||
// these names were added in Keyman 14
|
||||
CSpecialText14: string =
|
||||
'*LTREnter*\0*LTRBkSp*\0*RTLEnter*\0*RTLBkSp*\0*ShiftLock*\0*ShiftedLock*\0*ZWNJ*\0*ZWNJiOS*\0*ZWNJAndroid*',
|
||||
CSpecialText14ZWNJ: string =
|
||||
'*ZWNJ*\0*ZWNJiOS*\0*ZWNJAndroid*',
|
||||
|
||||
CSpecialText14Map: string[][] = [
|
||||
['*LTREnter*', '*Enter*'],
|
||||
['*LTRBkSp*', '*BkSp*'],
|
||||
['*RTLEnter*', '*Enter*'],
|
||||
['*RTLBkSp*', '*BkSp*'],
|
||||
['*ShiftLock*', '*Shift*'],
|
||||
['*ShiftedLock*', '*Shifted*'],
|
||||
['*ZWNJ*', '<|>'],
|
||||
['*ZWNJiOS*', '<|>'],
|
||||
['*ZWNJAndroid*', '<|>']
|
||||
];
|
||||
|
||||
// TODO lifecycle
|
||||
|
||||
function CheckKey(FPlatform: TouchLayout.TouchLayoutPlatform,
|
||||
FId: string, FText: string, FNextLayer: string, FKeyType: TouchLayout.TouchLayoutKeySp,
|
||||
FRequiredKeys: TRequiredKey[], FDictionary: string[]) { // I4119
|
||||
|
||||
//
|
||||
// Check that each touch layer has K_LOPT, [K_ROPT,] K_BKSP, K_ENTER
|
||||
//
|
||||
|
||||
for(let key of CRequiredKeys) {
|
||||
if(TRequiredKey[key].toLowerCase() == FId.toLowerCase()) {
|
||||
FRequiredKeys.push(key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Check that each layer referenced exists
|
||||
//
|
||||
|
||||
if(typeof FNextLayer == 'string' && FNextLayer.length > 0) {
|
||||
if(FPlatform.layer.find(l => l.id.toLowerCase() == FNextLayer.toLowerCase()) == undefined) {
|
||||
// TODO: callbacks.reportMessage() ReportError(0, CWARN_TouchLayoutMissingLayer, 'Key "'+FId+'" on platform "'+FPlatform.Name+'", layer "'+FLayer.Id+'", platform "'+FPlatform.Name+'", references a missing layer "'+FNextLayer+'".');
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Check that the key has a valid id // I4142
|
||||
//
|
||||
|
||||
if(FId.trim() == '') {
|
||||
if(!(FKeyType in [TouchLayout.TouchLayoutKeySp.blank, TouchLayout.TouchLayoutKeySp.spacer]) && FNextLayer == '') {
|
||||
// TODO: ReportError(0, CWARN_TouchLayoutUnidentifiedKey, 'A key on layer "'+FLayer.Id+'" has no identifier.');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let FValid = KeyIdType(FId);
|
||||
|
||||
if(FValid == TKeyIdType.Key_Invalid) {
|
||||
// TODO: ReportError(0, CERR_TouchLayoutInvalidIdentifier, 'Key "'+FId+'" on "'+FPlatform.Name+'", layer "'+FLayer.Id+'" has an invalid identifier.');
|
||||
}
|
||||
else if (FValid == TKeyIdType.Key_Unicode_Multi && !IsKeyboardVersion15OrLater()) {
|
||||
// TODO: ReportError(0, CERR_TouchLayoutInvalidIdentifier, 'Key "'+FId+'" on "'+FPlatform.Name+'", layer "'+FLayer.Id+'" has a multi-part identifier which requires version 15.0 or newer.');
|
||||
}
|
||||
|
||||
//
|
||||
// Check that each custom key code has at least *a* rule associated with it
|
||||
//
|
||||
|
||||
if (FValid == TKeyIdType.Key_Touch && FNextLayer == '' && FKeyType in [TouchLayout.TouchLayoutKeySp.normal, TouchLayout.TouchLayoutKeySp.deadkey]) {
|
||||
// Search for the key in the key dictionary - ignore K_LOPT, K_ROPT...
|
||||
if(FDictionary.indexOf(FId) < 0) {
|
||||
// TODO: ReportError(0, CWARN_TouchLayoutCustomKeyNotDefined, 'Key "'+FId+'" on layer "'+FLayer.Id+'", platform "'+FPlatform.Name+'", is a custom key but has no corresponding rule in the source.');
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Check that if the key has a *special* label, it is available in the target version
|
||||
//
|
||||
if(FText.startsWith('*') && FText.endsWith('*') && FText.length > 2) {
|
||||
// Keyman versions before 14 do not support '*special*' labels on non-special keys.
|
||||
// ZWNJ use, however, is safe because it will be transformed in function
|
||||
// TransformSpecialKeys14 to '<|>', which does not require the custom OSK font.
|
||||
if((CSpecialText10.includes(FText) || CSpecialText14.includes(FText)) &&
|
||||
!CSpecialText14ZWNJ.includes(FText) &&
|
||||
!IsKeyboardVersion14OrLater() &&
|
||||
!(FKeyType in [TouchLayout.TouchLayoutKeySp.special, TouchLayout.TouchLayoutKeySp.specialActive])) {
|
||||
// TODO: ReportError(0, CWARN_TouchLayoutSpecialLabelOnNormalKey,
|
||||
// Format('Key "%s" on layout "%s", platform "%s" does not have the key type "Special" or "Special (active)" but has the label "%s". This feature is only supported in Keyman 14 or later', [
|
||||
// FId, FLayer.Id, FPlatform.Name, FText
|
||||
// ]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function CheckDictionaryKeyValidity(fk: KMX.KEYBOARD, FDictionary: string[]) { // I4142
|
||||
|
||||
// TODO: O(eeek) performance here
|
||||
|
||||
for(let i = 0; i < FDictionary.length; i++) {
|
||||
if(FDictionary[i] == '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(KeyIdType(FDictionary[i]) in [TKeyIdType.Key_Invalid, TKeyIdType.Key_Constant]) {
|
||||
for(let fgp of fk.groups) {
|
||||
if(fgp.fUsingKeys) {
|
||||
for(let fkp of fgp.keys) {
|
||||
if(JavaScript_Key(fkp, fk.isMnemonic) == i+256) {
|
||||
// TODO: ReportError(fkp.Line, CERR_InvalidKeyCode, 'Invalid key identifier "'+FDictionary[i]+'"');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function TransformSpecialKeys14(FDebug: boolean, sLayoutFile: string): string {
|
||||
// Rewrite Special key labels that are only supported in Keyman 14+
|
||||
// This code is a little ugly but effective.
|
||||
if(!IsKeyboardVersion14OrLater()) {
|
||||
for(let i = 0; i < CSpecialText14Map.length; i++) {
|
||||
// Assumes the JSON output format will not change
|
||||
if(FDebug) {
|
||||
sLayoutFile = sLayoutFile.replace('"text": "'+CSpecialText14Map[i][0]+'"', '"text": this._v>13 ? "'+CSpecialText14Map[i][0]+'" : "'+CSpecialText14Map[i][1]+'"');
|
||||
} else {
|
||||
sLayoutFile = sLayoutFile.replace('"text":"'+CSpecialText14Map[i][0]+'"', '"text":this._v>13?"'+CSpecialText14Map[i][0]+'":"'+CSpecialText14Map[i][1]+'"');
|
||||
}
|
||||
}
|
||||
}
|
||||
return sLayoutFile;
|
||||
}
|
||||
|
||||
export function ValidateLayoutFile(fk: KMX.KEYBOARD, FDebug: boolean, sLayoutFile: string, sVKDictionary: string): VLFOutput { // I4060 // I4139
|
||||
|
||||
/*
|
||||
var
|
||||
FPlatform: TTouchLayoutPlatform;
|
||||
FLayer: TTouchLayoutLayer;
|
||||
FRow: TTouchLayoutRow;
|
||||
FKey: TTouchLayoutKey;
|
||||
FSubKey: TTouchLayoutSubKey;
|
||||
FRequiredKeys: set of TRequiredKey;
|
||||
FDictionary: TStringList;
|
||||
FDirection: TTouchLayoutFlickDirection;
|
||||
|
||||
*/
|
||||
|
||||
let FDictionary: string[] = sVKDictionary.split(/\s+/);
|
||||
|
||||
CheckDictionaryKeyValidity(fk, FDictionary); // I4142
|
||||
|
||||
let reader = new TouchLayoutFileReader();
|
||||
let data = reader.read(callbacks.loadFile(sLayoutFile));
|
||||
if(!data) {
|
||||
// TODO: ReportError(0, CERR_InvalidTouchLayoutFile, sMsg);
|
||||
return {output:null, result: false};
|
||||
}
|
||||
|
||||
let FTouchLayoutFont = ''; // I4872
|
||||
let pid: keyof TouchLayout.TouchLayoutFile;
|
||||
for(pid in data) {
|
||||
let platform = data[pid];
|
||||
|
||||
// Test that the font matches on all platforms // I4872
|
||||
|
||||
if(FTouchLayoutFont == '') {
|
||||
FTouchLayoutFont = platform.font;
|
||||
}
|
||||
else if(platform.font.toLowerCase() != FTouchLayoutFont) {
|
||||
// TODO: ReportError(0, CWARN_TouchLayoutFontShouldBeSameForAllPlatforms, 'The touch layout font should be the same for all platforms.');
|
||||
// TODO: why support multiple font values if it has to be the same across all platforms?!
|
||||
}
|
||||
|
||||
// Test that all required keys are present
|
||||
for(let layer of platform.layer) {
|
||||
let FRequiredKeys: TRequiredKey[] = [];
|
||||
for(let row of layer.row) {
|
||||
for(let key of row.key) {
|
||||
CheckKey(platform, key.id, key.text, key.nextlayer, key.sp, FRequiredKeys, FDictionary); // I4119
|
||||
if(key.sk) {
|
||||
for(let subkey of key.sk) {
|
||||
CheckKey(platform, subkey.id, subkey.text, subkey.nextlayer, subkey.sp, FRequiredKeys, FDictionary);
|
||||
}
|
||||
}
|
||||
let direction: keyof TouchLayout.TouchLayoutFlick;
|
||||
if(key.flick) {
|
||||
for(direction in key.flick) {
|
||||
CheckKey(platform, key.flick[direction].id, key.flick[direction].text,
|
||||
key.flick[direction].nextlayer, key.flick[direction].sp, FRequiredKeys, FDictionary);
|
||||
}
|
||||
}
|
||||
|
||||
if(key.multitap) {
|
||||
for(let subkey of key.multitap) {
|
||||
CheckKey(platform, subkey.id, subkey.text, subkey.nextlayer, subkey.sp, FRequiredKeys, FDictionary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(FRequiredKeys.length != CRequiredKeys.length) {
|
||||
// TODO: ReportError(0, CWARN_TouchLayoutMissingRequiredKeys, 'Layer "'+FLayer.Id+'" on platform "'+FPlatform.Name+'" is missing the required key(s) '+RequiredKeysToString(CRequiredKeys-FRequiredKeys)+'.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If not debugging, then this strips out formatting for a big saving in file size
|
||||
// This also normalises any values such as Pad or Width which should be strings
|
||||
let writer = new TouchLayoutFileWriter({formatted: FDebug});
|
||||
|
||||
sLayoutFile = writer.compile(data);
|
||||
|
||||
sLayoutFile = TransformSpecialKeys14(FDebug, sLayoutFile);
|
||||
|
||||
return {
|
||||
output: sLayoutFile,
|
||||
result: true
|
||||
}
|
||||
}
|
||||
163
developer/src/kmc-kmw/src/compiler/visual-keyboard-compiler.ts
Normal file
163
developer/src/kmc-kmw/src/compiler/visual-keyboard-compiler.ts
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
import { KMX, KvkFile, VisualKeyboard } from "@keymanapp/common-types";
|
||||
import { FTabStop, nl } from "./compiler-globals.js";
|
||||
import { CKeymanWebKeyCodes } from "./keymanweb-key-codes.js";
|
||||
import { RequotedString } from "./write-compiled-keyboard.js";
|
||||
|
||||
interface VKFFResult {
|
||||
result: string;
|
||||
displayUnderling: boolean;
|
||||
}
|
||||
|
||||
export function VisualKeyboardFromFile(visualKeyboard: VisualKeyboard.VisualKeyboard, debug: boolean): VKFFResult {
|
||||
let fbold = ''; // TODO 'bold ' if visualKeyboard.header.unicodeFont.style
|
||||
let fitalic = ''; // TODO 'italic ' if visualKeyboard.header.unicodeFont.style
|
||||
let f102 = visualKeyboard.header.flags & KvkFile.BUILDER_KVK_HEADER_FLAGS.kvkh102 ? '1' : '0';
|
||||
|
||||
let result = `{F:'${fbold}${fitalic} 1em "${RequotedString(visualKeyboard.header.unicodeFont.name)}"',K102:${f102}}` +
|
||||
`;` + VisualKeyboardToKLS(visualKeyboard) +
|
||||
';' + BuildBKFromKLS(debug);
|
||||
|
||||
return {
|
||||
result: result,
|
||||
// TODO: this can go in caller, later
|
||||
displayUnderling: !!(visualKeyboard.header.flags & KvkFile.BUILDER_KVK_HEADER_FLAGS.kvkhDisplayUnderlying)
|
||||
}
|
||||
}
|
||||
|
||||
function WideQuote(s: string): string {
|
||||
let result = '';
|
||||
for(let i = 0; i < s.length; i++) {
|
||||
if(s[i] == '"' || s[i] == '\\') {
|
||||
result += '\\' + s[i];
|
||||
} else {
|
||||
result += s[i];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function VkShiftStateToKmxShiftState(ShiftState: number): number {
|
||||
|
||||
interface TVKToKMX {
|
||||
VK: number; KMX: number;
|
||||
}
|
||||
|
||||
const Map: TVKToKMX[] = [
|
||||
{VK: KvkFile.BUILDER_KVK_SHIFT_STATE.KVKS_SHIFT, KMX: KMX.KMXFile.K_SHIFTFLAG},
|
||||
{VK: KvkFile.BUILDER_KVK_SHIFT_STATE.KVKS_CTRL, KMX: KMX.KMXFile.K_CTRLFLAG},
|
||||
{VK: KvkFile.BUILDER_KVK_SHIFT_STATE.KVKS_ALT, KMX: KMX.KMXFile.K_ALTFLAG},
|
||||
{VK: KvkFile.BUILDER_KVK_SHIFT_STATE.KVKS_LCTRL, KMX: KMX.KMXFile.LCTRLFLAG},
|
||||
{VK: KvkFile.BUILDER_KVK_SHIFT_STATE.KVKS_RCTRL, KMX: KMX.KMXFile.RCTRLFLAG},
|
||||
{VK: KvkFile.BUILDER_KVK_SHIFT_STATE.KVKS_LALT, KMX: KMX.KMXFile.LALTFLAG},
|
||||
{VK: KvkFile.BUILDER_KVK_SHIFT_STATE.KVKS_RALT, KMX: KMX.KMXFile.RALTFLAG}
|
||||
];
|
||||
|
||||
let result = 0;
|
||||
for(let i = 0; i < Map.length; i++) {
|
||||
if (ShiftState & Map[i].VK) {
|
||||
result |= Map[i].KMX;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
function VKShiftToLayerName(shift: number): string {
|
||||
|
||||
const masks: string[] = [
|
||||
'leftctrl',
|
||||
'rightctrl',
|
||||
'leftalt',
|
||||
'rightalt',
|
||||
'shift',
|
||||
'ctrl',
|
||||
'alt'
|
||||
];
|
||||
|
||||
shift = VkShiftStateToKmxShiftState(shift);
|
||||
if(shift == 0) {
|
||||
return 'default';
|
||||
}
|
||||
|
||||
let result = '';
|
||||
for(let i = 0; i < masks.length; i++) {
|
||||
if(shift & (1 << i)) {
|
||||
result += masks[i] + '-';
|
||||
}
|
||||
}
|
||||
return result.substring(0, result.length - 1);
|
||||
}
|
||||
|
||||
|
||||
function VisualKeyboardToKLS(FVK: VisualKeyboard.VisualKeyboard): string {
|
||||
|
||||
interface TLayer {
|
||||
shift: number;
|
||||
name: string;
|
||||
keys: string[];
|
||||
};
|
||||
|
||||
let layers: TLayer[] = [];
|
||||
|
||||
// Discover the layers used in the visual keyboard
|
||||
for(let key of FVK.keys) {
|
||||
if(key.flags & KvkFile.BUILDER_KVK_KEY_FLAGS.kvkkUnicode) {
|
||||
// Find the index of the key in KMW VK arrays
|
||||
let n = CKeymanWebKeyCodes[key.vkey];
|
||||
if(n == 0xFF) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let layer = layers.find(layer => layer.shift == key.shift);
|
||||
if(!layer) {
|
||||
// 0-64 covers all possible VirtualKeyCodes in CKemyanWebKeyCodes
|
||||
layer = { shift: key.shift, name: '', keys: new Array(65)};
|
||||
layers.push(layer);
|
||||
}
|
||||
layer.keys[n] = key.text;
|
||||
}
|
||||
}
|
||||
|
||||
// Build the layer array
|
||||
|
||||
let result = nl+FTabStop+'this.KV.KLS={'+nl;
|
||||
|
||||
for(let i = 0; i < layers.length; i++) {
|
||||
let layer = layers[i];
|
||||
result += `${FTabStop}${FTabStop}"${VKShiftToLayerName(layer.shift)}": [`;
|
||||
for(let j = 0; j < layer.keys.length - 1; j++) {
|
||||
result += '"'+WideQuote(layer.keys[j] ?? '')+'",';
|
||||
}
|
||||
result += '"'+WideQuote(layer.keys[layer.keys.length-1] ?? '')+'"]';
|
||||
if(i < layers.length - 1) {
|
||||
result += ',' + nl;
|
||||
}
|
||||
}
|
||||
result += nl+FTabStop+'}';
|
||||
return result;
|
||||
}
|
||||
|
||||
function BuildBKFromKLS(debug: boolean): string {
|
||||
const func =
|
||||
'function(x){var e=Array.apply(null,Array(65)).map(String.prototype.valueOf,"")'+
|
||||
',r=[],v,i,m=[\'default\',\'shift\',\'ctrl\',\'shift-ctrl\',\'alt\',\'shift-alt\','+
|
||||
'\'ctrl-alt\',\'shift-ctrl-alt\'];for(i=m.length-1;i>=0;i--)if((v=x[m[i]])||r.length)'+
|
||||
'r=(v?v:e).slice().concat(r);return r}';
|
||||
const func_debug =
|
||||
'function(x){'+nl+
|
||||
' var'+nl+
|
||||
' empty=Array.apply(null, Array(65)).map(String.prototype.valueOf,""),'+nl+
|
||||
' result=[], v, i,'+nl+
|
||||
' modifiers=[\'default\',\'shift\',\'ctrl\',\'shift-ctrl\',\'alt\',\'shift-alt\',\'ctrl-alt\',\'shift-ctrl-alt\'];'+nl+
|
||||
' for(i=modifiers.length-1;i>=0;i--) {'+nl+
|
||||
' v = x[modifiers[i]];'+nl+
|
||||
' if(v || result.length > 0) {'+nl+
|
||||
' result=(v ? v : empty).slice().concat(result);'+nl+
|
||||
' }'+nl+
|
||||
' }'+nl+
|
||||
' return result;'+nl+
|
||||
' }';
|
||||
|
||||
return nl+FTabStop+'this.KV.BK=('+(debug ? func_debug : func)+')(this.KV.KLS)';
|
||||
}
|
||||
665
developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts
Normal file
665
developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts
Normal file
|
|
@ -0,0 +1,665 @@
|
|||
import { VisualKeyboard } from "@keymanapp/common-types";
|
||||
import { KMX, CompilerCallbacks, KvkFileReader, KvksFileReader } from "@keymanapp/common-types";
|
||||
import { ExpandSentinel, incxstr, xstrlen } from "../util/util.js";
|
||||
// import { KEY, KEYBOARD, KMX.KMXFile, STORE } from "../../../../../common/web/types/src/kmx/kmx.js";
|
||||
import { options, nl, FTabStop, setupGlobals, IsKeyboardVersion10OrLater } from "./compiler-globals.js";
|
||||
import CompilerOptions from "./compiler-options.js";
|
||||
import { JavaScript_ContextMatch, JavaScript_KeyAsString, JavaScript_Name, JavaScript_OutputString, JavaScript_Rules, JavaScript_Shift, JavaScript_ShiftAsString, JavaScript_Store, zeroPadHex } from './javascript-strings.js';
|
||||
import { CERR_InvalidBegin, CWARN_DontMixChiralAndNonChiralModifiers, ReportError } from "./messages.js";
|
||||
import { ValidateLayoutFile } from "./validate-layout-file.js";
|
||||
import { VisualKeyboardFromFile } from "./visual-keyboard-compiler.js";
|
||||
|
||||
export let FFix183_LadderLength: number = 100; // TODO: option
|
||||
|
||||
function requote(s: string): string {
|
||||
return "'" + s.replaceAll(/(['\\])/, "\\$1") + "'";
|
||||
}
|
||||
|
||||
export function RequotedString(s: string, RequoteSingleQuotes: boolean = false): string {
|
||||
// TODO: use a JSON encode
|
||||
let i: number = 0;
|
||||
while(i < s.length) {
|
||||
if (s.charAt(i) == '"' || s.charAt(i) == '\\') {
|
||||
s = s.substring(0, i) + '\\' + s.substring(i);
|
||||
i++;
|
||||
}
|
||||
else if (s.charAt(i) == '\'' && RequoteSingleQuotes) {
|
||||
s = s.substring(0, i) + '\\' + s.substring(i);
|
||||
i++;
|
||||
}
|
||||
else if(s.charAt(i) == '\n') {
|
||||
s = s.substring(0, i) + '\\n' + s.substring(i + 1);
|
||||
}
|
||||
else if(s.charAt(i) == '\r') {
|
||||
s = s.substring(0, i) + ' ' + s.substring(i + 1);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
export function WriteCompiledKeyboard(callbacks: CompilerCallbacks, kmnfile: string, kmxfile: string, name: string, keyboard: KMX.KEYBOARD, FDebug: boolean = false): string {
|
||||
let opts: CompilerOptions = {
|
||||
addCompilerVersion: false,
|
||||
debug: FDebug
|
||||
};
|
||||
setupGlobals(callbacks, opts, FDebug?' ':'', FDebug?'\r\n':'', keyboard);
|
||||
|
||||
// let fgp: GROUP;
|
||||
|
||||
// let fsp: STORE;
|
||||
// let fkp: KEY;
|
||||
|
||||
// let j: number;
|
||||
// let n: number;
|
||||
|
||||
let vMnemonic: number = 0;
|
||||
let /*s: string,*/ sRTL: string = "", sHelp: string = "''", sHelpFile: string = "",
|
||||
sEmbedJS: string = "", sEmbedCSS: string = "";
|
||||
let sVisualKeyboard: string = "", sFullName: string = "";
|
||||
let sBegin_NewContext: string = "", sBegin_PostKeystroke: string = "";
|
||||
let sLayoutFile: string = "", sVKDictionary: string;
|
||||
let linecomment: string; // I3438
|
||||
// let HasRules: boolean;
|
||||
let sModifierBitmask: string;
|
||||
let FOptionStores: string;
|
||||
let FKeyboardVersion = "1.0";
|
||||
// let rec: TSentinelRecord;
|
||||
|
||||
let result = "";
|
||||
// Locate the name of the keyboard
|
||||
for(let i = 0; i < keyboard.stores.length; i++) {
|
||||
const fsp = keyboard.stores[i];
|
||||
if(fsp.dwSystemID == KMX.KMXFile.TSS_NAME) {
|
||||
sFullName = fsp.dpString;
|
||||
}
|
||||
else if(fsp.dwSystemID == KMX.KMXFile.TSS_KEYBOARDVERSION) { // I4155
|
||||
FKeyboardVersion = fsp.dpString;
|
||||
}
|
||||
else if (fsp.dpName == 'HelpFile' || fsp.dwSystemID == KMX.KMXFile.TSS_KMW_HELPFILE) {
|
||||
sHelpFile = fsp.dpString;
|
||||
}
|
||||
else if (fsp.dpName == 'Help' || fsp.dwSystemID == KMX.KMXFile.TSS_KMW_HELPTEXT) {
|
||||
sHelp = '"'+RequotedString(fsp.dpString)+'"';
|
||||
}
|
||||
else if (fsp.dpName == 'VisualKeyboard' || fsp.dwSystemID == KMX.KMXFile.TSS_VISUALKEYBOARD) {
|
||||
sVisualKeyboard = fsp.dpString;
|
||||
}
|
||||
else if (fsp.dpName == 'EmbedJS' || fsp.dwSystemID == KMX.KMXFile.TSS_KMW_EMBEDJS) {
|
||||
sEmbedJS = fsp.dpString;
|
||||
}
|
||||
else if (fsp.dpName == 'EmbedCSS' || fsp.dwSystemID == KMX.KMXFile.TSS_KMW_EMBEDCSS) { // I4368
|
||||
sEmbedCSS = fsp.dpString;
|
||||
}
|
||||
else if (fsp.dpName == 'RTL' || fsp.dwSystemID == KMX.KMXFile.TSS_KMW_RTL) {
|
||||
sRTL = fsp.dpString == '1' ? FTabStop+'this.KRTL=1;'+nl : ''; // I3681
|
||||
}
|
||||
else if (fsp.dwSystemID == KMX.KMXFile.TSS_MNEMONIC) {
|
||||
vMnemonic = fsp.dpString == '1' ? 1 : 0;
|
||||
}
|
||||
else if (fsp.dwSystemID == KMX.KMXFile.TSS_VKDICTIONARY) { // I3438
|
||||
sVKDictionary = fsp.dpString;
|
||||
}
|
||||
else if (fsp.dwSystemID == KMX.KMXFile.TSS_LAYOUTFILE) { // I3483
|
||||
sLayoutFile = fsp.dpString;
|
||||
}
|
||||
else if (fsp.dwSystemID == KMX.KMXFile.TSS_BEGIN_NEWCONTEXT) {
|
||||
sBegin_NewContext = fsp.dpString;
|
||||
}
|
||||
else if (fsp.dwSystemID == KMX.KMXFile.TSS_BEGIN_POSTKEYSTROKE) {
|
||||
sBegin_PostKeystroke = fsp.dpString;
|
||||
}
|
||||
}
|
||||
|
||||
const sName = 'Keyboard_'+name; //TODO: verify --> GetKeymanWebCompiledNameFromFileName(FInFile);
|
||||
|
||||
if (sHelpFile != '') {
|
||||
sHelp = '';
|
||||
//TODO: load sHelpFile from file
|
||||
/*with TStringList.Create do
|
||||
try
|
||||
try
|
||||
LoadFromFile(ExtractFilePath(FInFile) + sHelpFile, TEncoding.UTF8); // I3337
|
||||
for n := 0 to Count - 1 do
|
||||
sHelp := sHelp + Strings[n] + ' ';
|
||||
except
|
||||
on E:EFOpenError do
|
||||
begin
|
||||
ReportError(0, CWARN_HelpFileMissing, E.Message); // I1971 // I4061
|
||||
sHelp := '';
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
Free;
|
||||
end;*/
|
||||
|
||||
sHelp = requote(sHelp);
|
||||
}
|
||||
|
||||
if (sEmbedJS != '') {
|
||||
//TODO: load sEmbedJS from file
|
||||
/*try
|
||||
with TStringList.Create do
|
||||
try
|
||||
LoadFromFile(ExtractFilePath(FInFile) + sEmbedJS, TEncoding.UTF8); // I3337
|
||||
sEmbedJS := Text;
|
||||
finally
|
||||
Free;
|
||||
end;
|
||||
except
|
||||
on E:EFOpenError do // I3683
|
||||
begin
|
||||
ReportError(0, CWARN_EmbedJsFileMissing, E.Message); // I4061
|
||||
sEmbedJS := '';
|
||||
end;
|
||||
end;*/
|
||||
}
|
||||
|
||||
if (sEmbedCSS != '') { // I4368
|
||||
//TODO: load sEmbedCSS from file
|
||||
/*try
|
||||
with TStringList.Create do
|
||||
try
|
||||
LoadFromFile(ExtractFilePath(FInFile) + sEmbedCSS, TEncoding.UTF8); // I3337
|
||||
sEmbedCSS := Text;
|
||||
finally
|
||||
Free;
|
||||
end;
|
||||
except
|
||||
on E:EFOpenError do // I3683
|
||||
begin
|
||||
ReportError(0, CWARN_EmbedJsFileMissing, E.Message); // I4061
|
||||
sEmbedCSS := '';
|
||||
end;
|
||||
end;*/
|
||||
}
|
||||
|
||||
if (sLayoutFile != '') { // I3483
|
||||
let path = callbacks.resolveFilename(kmnfile, sLayoutFile);
|
||||
|
||||
let result = ValidateLayoutFile(keyboard, options.debug, path, sVKDictionary);
|
||||
if(!result.result) {
|
||||
sLayoutFile = '';
|
||||
// TODO: error
|
||||
// ReportError(0, CWARN_TouchLayoutFileInvalid, 'Touch layout file is not valid');
|
||||
} else {
|
||||
// TODO: reusing the same variable here is ugly
|
||||
sLayoutFile = result.output;
|
||||
}
|
||||
}
|
||||
|
||||
// Default to hide underlying layout characters. This is overridden by touch
|
||||
// layout platform.displayUnderlying property or, if that is not present for
|
||||
// the given platform, by the OSK property.
|
||||
let fDisplayUnderlying = false;
|
||||
|
||||
if (sVisualKeyboard != '') {
|
||||
// TODO: stop reusing sVisualKeyboard for both filename and content
|
||||
let path = callbacks.resolveFilename(kmnfile, sVisualKeyboard);
|
||||
|
||||
let kvk: VisualKeyboard.VisualKeyboard;
|
||||
if(path.match(/\.kvks$/i)) {
|
||||
let reader = new KvksFileReader();
|
||||
let source = reader.read(callbacks.loadFile(path));
|
||||
reader.validate(source, callbacks.loadSchema("kvks")); // TODO: handle exceptions
|
||||
kvk = reader.transform(source);
|
||||
// TODO: log errors
|
||||
}
|
||||
else {
|
||||
// Note: very old keyboard sources may still have .kvk as an xml
|
||||
// file, but we'll treat that as an error rather than silently
|
||||
// falling back to KvksFileReader
|
||||
let reader = new KvkFileReader();
|
||||
kvk = reader.read(callbacks.loadFile(path));
|
||||
}
|
||||
|
||||
let result = VisualKeyboardFromFile(kvk, options.debug);
|
||||
if(!result.result) {
|
||||
// TODO: error
|
||||
sVisualKeyboard = 'null';
|
||||
}
|
||||
else {
|
||||
sVisualKeyboard = result.result;
|
||||
}
|
||||
}
|
||||
else {
|
||||
sVisualKeyboard = 'null';
|
||||
}
|
||||
|
||||
|
||||
const fMnemonic = vMnemonic == 1;
|
||||
|
||||
sModifierBitmask = GetKeyboardModifierBitmask(keyboard, fMnemonic);
|
||||
|
||||
result +=
|
||||
`${JavaScript_SetupProlog()}${nl}` +
|
||||
`KeymanWeb.KR(new ${sName}());${nl}` +
|
||||
`${JavaScript_SetupEpilog()}${nl}` +
|
||||
`function ${sName}()${nl}` +
|
||||
`{${nl}` +
|
||||
`${FTabStop}${JavaScript_SetupDebug()}${nl}` +
|
||||
// Following line caches the Keyman major version
|
||||
`${FTabStop}this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9;${nl}` +
|
||||
`${FTabStop}this.KI="${sName}";${nl}` +
|
||||
`${FTabStop}this.KN="${RequotedString(sFullName)}";${nl}` +
|
||||
`${FTabStop}this.KMINVER="${(keyboard.fileVersion & KMX.KMXFile.VERSION_MASK_MAJOR) >> 8}.${keyboard.fileVersion & KMX.KMXFile.VERSION_MASK_MINOR}";${nl}` +
|
||||
`${FTabStop}this.KV=${sVisualKeyboard};${nl}` +
|
||||
`${FTabStop}this.KDU=${fDisplayUnderlying?'1':'0'};${nl}` +
|
||||
`${FTabStop}this.KH=${sHelp};${nl}` +
|
||||
`${FTabStop}this.KM=${vMnemonic};${nl}` +
|
||||
`${FTabStop}this.KBVER="${FKeyboardVersion}";${nl}` + // I4155
|
||||
`${FTabStop}this.KMBM=${sModifierBitmask};${nl}` +
|
||||
`${sRTL}`; // I3681
|
||||
|
||||
if (HasSupplementaryPlaneChars()) {
|
||||
result += `${FTabStop}this.KS=1;${nl}`;
|
||||
}
|
||||
|
||||
if (sVKDictionary != '') { // I3438
|
||||
result += `${FTabStop}this.KVKD="${RequotedString(sVKDictionary)}";${nl}`; // I3681
|
||||
}
|
||||
|
||||
if (sLayoutFile != '') { // I3483
|
||||
result += `${FTabStop}this.KVKL=${sLayoutFile};${nl}`; // I3681
|
||||
}
|
||||
|
||||
if (sEmbedCSS != '') { // I4368
|
||||
result += `${FTabStop}this.KCSS="${RequotedString(sEmbedCSS)}";${nl}`;
|
||||
}
|
||||
|
||||
function isDebugStore(fsp: KMX.STORE) {
|
||||
return fsp.dwSystemID == KMX.KMXFile.TSS_DEBUG_LINE;
|
||||
}
|
||||
|
||||
function isReservedStore(fsp: KMX.STORE) {
|
||||
return fsp.dwSystemID != KMX.KMXFile.TSS_NONE;
|
||||
}
|
||||
|
||||
function isOptionStore(fsp: KMX.STORE) {
|
||||
// TODO: how do we determine this, see CheckStoreUsage()
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write the stores out
|
||||
FOptionStores = '';
|
||||
for(let i = 0; i < keyboard.stores.length; i++) {
|
||||
let fsp = keyboard.stores[i];
|
||||
// I3438 - Save all system stores to the keyboard, for now // I3684
|
||||
|
||||
if (!isDebugStore(fsp)) { // and not (fsp.dwSystemID in [TSS_BITMAP, TSS_NAME, TSS_VERSION, TSS_CUSTOMKEYMANEDITION, TSS_CUSTOMKEYMANEDITIONNAME, TSS_KEYMANCOPYRIGHT]) then
|
||||
if (fsp.dwSystemID == KMX.KMXFile.TSS_COMPARISON) {
|
||||
result += `${FTabStop}this.s${JavaScript_Name(i, fsp.dpName)}=${JavaScript_Store(keyboard, 0/*fsp.line*/, fsp.dpString)};${nl}`;
|
||||
}
|
||||
else if (fsp.dwSystemID == KMX.KMXFile.TSS_COMPILEDVERSION) {
|
||||
result += `${FTabStop}this.KVER=${JavaScript_Store(keyboard, 0/*fsp.line*/, fsp.dpString)};${nl}`;
|
||||
}
|
||||
//else if fsp.dwSystemID = TSS_VKDICTIONARY then // I3438, required for vkdictionary
|
||||
// Result := Result + Format('%sthis.s%s=%s;%s', [FTabStop, JavaScript_Name(i, fsp.szName), JavaScript_Store(fsp.line, fsp.dpString), nl])
|
||||
else if (isOptionStore(fsp) && !isReservedStore(fsp)) {
|
||||
result += `${FTabStop}this.s${JavaScript_Name(i,fsp.dpName)}=KeymanWeb.KLOAD(this.KI,"${JavaScript_Name(i,fsp.dpName,true)}",`+
|
||||
`${JavaScript_Store(keyboard, 0/*fsp.line*/, fsp.dpString)});${nl}`;
|
||||
|
||||
if (FOptionStores != '') {
|
||||
FOptionStores += ',';
|
||||
}
|
||||
FOptionStores += `'s${JavaScript_Name(i, fsp.dpName)}`;
|
||||
}
|
||||
else if (fsp.dwSystemID == KMX.KMXFile.TSS_NONE /* aka not fsp.fIsReserved */) {
|
||||
result += `${FTabStop}this.s${JavaScript_Name(i, fsp.dpName)}=${JavaScript_Store(keyboard, 0/*fsp.line*/, fsp.dpString)};${nl}`; // I3681
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result += `${FTabStop}this.KVS=[${FOptionStores}];${nl}`;
|
||||
|
||||
// Write the groups out
|
||||
|
||||
// I853 - begin unicode missing causes crash
|
||||
if (keyboard.startGroup.unicode == 0xFFFFFFFF) {
|
||||
ReportError(0, CERR_InvalidBegin, 'A "begin unicode" statement is required to compile a KeymanWeb keyboard');
|
||||
return null;
|
||||
}
|
||||
|
||||
result += WriteBeginStatement(keyboard, 'gs', keyboard.startGroup.unicode);
|
||||
|
||||
let rec = ExpandSentinel(keyboard, sBegin_NewContext, 0);
|
||||
if(rec.Code == KMX.KMXFile.CODE_USE) {
|
||||
result += WriteBeginStatement(keyboard, 'gn', rec.Use.GroupIndex);
|
||||
}
|
||||
rec = ExpandSentinel(keyboard, sBegin_PostKeystroke, 0);
|
||||
if(rec.Code == KMX.KMXFile.CODE_USE) {
|
||||
result += WriteBeginStatement(keyboard, 'gpk', rec.Use.GroupIndex);
|
||||
}
|
||||
|
||||
let fgp = keyboard.groups[keyboard.startGroup.unicode];
|
||||
result +=
|
||||
`${FTabStop}this.gs=function(t,e) {${nl}` +
|
||||
`${FTabStop+FTabStop}return this.g${JavaScript_Name(keyboard.startGroup.unicode, fgp.dpName)}(t,e);${nl}` +
|
||||
`${FTabStop}};${nl}`; // I3681
|
||||
|
||||
for(let i = 0; i < keyboard.groups.length; i++) { // I1964
|
||||
let fgp = keyboard.groups[i];
|
||||
/*
|
||||
Note on `r` and `m` variables in a group function:
|
||||
|
||||
`m` can have one of three values:
|
||||
0: no rule from this group was matched
|
||||
1: a rule from this group was matched and did not include a `use`
|
||||
statement
|
||||
2: a rule from this group matched and did include a `use` statement
|
||||
(#5440)
|
||||
|
||||
`m` is only used within a rule group to control the firing of the
|
||||
`match` and `nomatch` rules.
|
||||
|
||||
`r` can have one of two values:
|
||||
0: no rule from the final group matched (even if a rule from an
|
||||
higher-level group did)
|
||||
1: a rule from the final group did match;
|
||||
|
||||
`r` serves as the rule group's return value and is forwarded
|
||||
recursively, best serving as a flag for whether or not default
|
||||
output for a key should be emitted (0 means yes, emit the
|
||||
default character output for that key).
|
||||
*/
|
||||
|
||||
result +=
|
||||
`${FTabStop}this.g${JavaScript_Name(i, fgp.dpName)}=function(t,e) {${nl}` +
|
||||
`${FTabStop+FTabStop}var k=KeymanWeb,r=${fgp.fUsingKeys?0:1},m=0;${nl}`; //I1959
|
||||
|
||||
// fkp := fgp.dpKeyArray;
|
||||
let HasRules = false;
|
||||
|
||||
if (FFix183_LadderLength != 0) {
|
||||
result += JavaScript_Rules(keyboard, fMnemonic, fgp);
|
||||
}
|
||||
else {
|
||||
for (let j = 0; j < fgp.keys.length; j++) { // I1964
|
||||
let fkp = fgp.keys[j];
|
||||
if (!RuleIsExcludedByPlatform(keyboard, fkp)) {
|
||||
result += FTabStop+FTabStop; // I3681
|
||||
if (HasRules) {
|
||||
result += 'else ';
|
||||
}
|
||||
HasRules = true;
|
||||
|
||||
if (fgp.fUsingKeys) {
|
||||
result += `if(k.KKM(e,${JavaScript_ShiftAsString(fkp, fMnemonic)},${JavaScript_KeyAsString(fkp, fMnemonic)})`;
|
||||
}
|
||||
|
||||
if (xstrlen(fkp.dpContext) > 0) {
|
||||
result += fgp.fUsingKeys ? '&&' : 'if(';
|
||||
result += JavaScript_ContextMatch(keyboard, fkp, fkp.dpContext);
|
||||
}
|
||||
else if (!fgp.fUsingKeys) {
|
||||
result += 'if(1';
|
||||
}
|
||||
|
||||
linecomment = (fkp.Line > 0 && FDebug) ? ` // Line ${fkp.Line}` : '';
|
||||
|
||||
result +=
|
||||
`) {${linecomment}${nl}` +
|
||||
FTabStop+FTabStop+FTabStop;
|
||||
if (fgp.fUsingKeys) { // I1959
|
||||
result += 'r=m=1;' + JavaScript_OutputString(keyboard, FTabStop + FTabStop + FTabStop, fkp, fkp.dpOutput, fgp); // I1959 // I3681
|
||||
}
|
||||
else {
|
||||
result += 'm=1;' + JavaScript_OutputString(keyboard, FTabStop + FTabStop + FTabStop, fkp, fkp.dpOutput, fgp); // I1959 // I3681
|
||||
}
|
||||
result += `${nl}${FTabStop}${FTabStop}}${nl}`; // I3681
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(fgp.dpMatch) {
|
||||
result +=
|
||||
`${FTabStop+FTabStop}if(m==1) {${nl}`+
|
||||
`${FTabStop+FTabStop}${JavaScript_OutputString(keyboard, FTabStop + FTabStop + FTabStop, null, fgp.dpMatch, fgp)}${nl}`+
|
||||
`${FTabStop+FTabStop}}${nl}`;
|
||||
}
|
||||
if(fgp.dpNoMatch) {
|
||||
if(fgp.fUsingKeys) { // I1382 - fixup m=1 to m=g()
|
||||
result +=
|
||||
`${FTabStop+FTabStop}if(!m&&k.KIK(e)) {${nl}`+
|
||||
`${FTabStop+FTabStop+FTabStop}r=1;${JavaScript_OutputString(keyboard, FTabStop + FTabStop + FTabStop, null, fgp.dpNoMatch, fgp)}${nl}`+
|
||||
`${FTabStop+FTabStop}}${nl}`; // I1959. part 2, I2224 // I3681
|
||||
}
|
||||
else {
|
||||
result +=
|
||||
`${FTabStop+FTabStop}if(!m) {${nl}`+
|
||||
`${FTabStop+FTabStop+FTabStop}${JavaScript_OutputString(keyboard, FTabStop + FTabStop + FTabStop, null, fgp.dpNoMatch, fgp)}${nl}`+
|
||||
`${FTabStop+FTabStop}}${nl}`;
|
||||
}
|
||||
}
|
||||
result +=
|
||||
`${FTabStop+FTabStop}return r;${nl}`+
|
||||
`${FTabStop}};${nl}`;
|
||||
}
|
||||
|
||||
/* TODO
|
||||
for(let n = 0 to FCallFunctions.Count - 1 do
|
||||
begin
|
||||
s := ExtractFilePath(FInFile) + FCallFunctions[n] + '.call_js';
|
||||
if FileExists(s) then
|
||||
with TStringList.Create do
|
||||
try
|
||||
LoadFromFile(s, TEncoding.UTF8); // I3337
|
||||
Result := Result + Format('%sthis.c%d=function(t,e){%s};%s', [FTabstop, n, Trim(Text), nl]); // I3681
|
||||
finally
|
||||
Free;
|
||||
end
|
||||
else
|
||||
Result := Result + Format('%sthis.c%d=function(t,e){alert("call(%s) not defined");};%s', [FTabstop, n, FCallFunctions[n], nl]); // I3681
|
||||
end;
|
||||
*/
|
||||
result += sEmbedJS + '}' + nl; // I3681
|
||||
return result;
|
||||
}
|
||||
|
||||
///
|
||||
/// Determine the modifiers used in the target keyboard and return a bitmask
|
||||
/// representing them, or an number value when not in debug mode
|
||||
///
|
||||
/// @return string of JavaScript code, e.g. 'modCodes.SHIFT | modCodes.CTRL /* 0x0030 */'
|
||||
///
|
||||
function GetKeyboardModifierBitmask(keyboard: KMX.KEYBOARD, fMnemonic: boolean): string {
|
||||
let bitMask = 0;
|
||||
for(let gp of keyboard.groups) {
|
||||
if(gp.fUsingKeys) {
|
||||
for(let kp of gp.keys) {
|
||||
if(!RuleIsExcludedByPlatform(keyboard, kp)) {
|
||||
bitMask |= JavaScript_Shift(kp, fMnemonic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((bitMask & KMX.KMXFile.MASK_MODIFIER_CHIRAL) && (bitMask & KMX.KMXFile.MASK_MODIFIER_NONCHIRAL)) {
|
||||
ReportError(0, CWARN_DontMixChiralAndNonChiralModifiers, 'This keyboard contains Ctrl,Alt and LCtrl,LAlt,RCtrl,RAlt sets of modifiers. Use only one or the other set for web target.');
|
||||
}
|
||||
|
||||
if(options.debug) {
|
||||
return FormatModifierAsBitflags(bitMask & KMX.KMXFile.MASK_KEYS); // Exclude KMX_ISVIRTUALKEY, KMX_VIRTUALCHARKEY
|
||||
}
|
||||
|
||||
return '0x'+(bitMask & KMX.KMXFile.MASK_KEYS).toString(16).toUpperCase();
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// If debug mode, then returns Javascript code necessary for
|
||||
/// accessing constants in the compiled keyboard
|
||||
///
|
||||
/// @return string of JavaScript code
|
||||
///
|
||||
function JavaScript_SetupDebug() {
|
||||
if(IsKeyboardVersion10OrLater()) {
|
||||
if(options.debug) {
|
||||
return 'var modCodes = keyman.osk.modifierCodes;'+nl+
|
||||
FTabStop+'var keyCodes = keyman.osk.keyCodes;'+nl;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function JavaScript_SetupProlog() {
|
||||
if(IsKeyboardVersion10OrLater()) {
|
||||
return 'if(typeof keyman === \'undefined\') {'+nl+
|
||||
FTabStop+'console.log(\'Keyboard requires KeymanWeb 10.0 or later\');'+nl+
|
||||
FTabStop+'if(typeof tavultesoft !== \'undefined\') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later");'+nl+
|
||||
'} else {';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function JavaScript_SetupEpilog() {
|
||||
if(IsKeyboardVersion10OrLater()) {
|
||||
return '}';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function HasSupplementaryPlaneChars() {
|
||||
return false; // TODO
|
||||
/* function StringHasSuppChars(p: PWideChar): Boolean;
|
||||
begin
|
||||
if not Assigned(p) then
|
||||
Exit(False);
|
||||
|
||||
while p^ <> #0 do
|
||||
begin
|
||||
if Char.IsSurrogate(p, 0) then
|
||||
Exit(True);
|
||||
p := incxstr(p);
|
||||
end;
|
||||
|
||||
Result := False;
|
||||
end;
|
||||
|
||||
var
|
||||
I: number;
|
||||
fsp: PFILE_STORE;
|
||||
fgp: PFILE_GROUP;
|
||||
j: number;
|
||||
fkp: PFILE_KEY;
|
||||
begin
|
||||
fsp := fk.dpStoreArray;
|
||||
for i := 0 to number(fk.cxStoreArray) - 1 do
|
||||
begin
|
||||
if StringHasSuppChars(fsp.dpString) then
|
||||
Exit(True);
|
||||
Inc(fsp);
|
||||
end;
|
||||
|
||||
fgp := fk.dpGroupArray;
|
||||
for i := 0 to number(fk.cxGroupArray) - 1 do
|
||||
begin
|
||||
fkp := fgp.dpKeyArray;
|
||||
for j := 0 to number(fgp.cxKeyArray) - 1 do
|
||||
begin
|
||||
if StringHasSuppChars(fkp.dpContext) or
|
||||
StringHasSuppChars(fkp.dpOutput) then
|
||||
Exit(True);
|
||||
Inc(fkp);
|
||||
end;
|
||||
|
||||
if StringHasSuppChars(fgp.dpMatch) or
|
||||
StringHasSuppChars(fgp.dpNoMatch) then
|
||||
Exit(True);
|
||||
|
||||
Inc(fgp);
|
||||
end;
|
||||
|
||||
Result := False;
|
||||
end;*/
|
||||
}
|
||||
|
||||
export function RuleIsExcludedByPlatform(keyboard: KMX.KEYBOARD, fkp: KMX.KEY): boolean {
|
||||
if(fkp.dpContext == null || fkp.dpContext == '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
let x = 0;
|
||||
while(x < fkp.dpContext.length) {
|
||||
let rec = ExpandSentinel(keyboard, fkp.dpContext, x);
|
||||
if(rec.IsSentinel &&
|
||||
(rec.Code == KMX.KMXFile.CODE_IFSYSTEMSTORE) &&
|
||||
(rec.IfSystemStore.dwSystemID == KMX.KMXFile.TSS_PLATFORM) &&
|
||||
rec.IfSystemStore.Store.dpString.includes('native')) {
|
||||
if(rec.IfSystemStore.Store.dpString.match(/windows|desktop|macosx|linux/)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
x = incxstr(fkp.dpContext, x);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function WriteBeginStatement(keyboard: KMX.KEYBOARD, name: string, groupIndex: number): string {
|
||||
const fgp = keyboard.groups[groupIndex];
|
||||
return `${FTabStop}this.${name}=function(t,e) {${nl}`+
|
||||
`${FTabStop+FTabStop}return this.g${JavaScript_Name(groupIndex, fgp.dpName)}(t,e);${nl}`+
|
||||
`${FTabStop}};${nl}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a modifier bit mask integer into its component bit flags
|
||||
*
|
||||
* @param FBitMask A KMX modifier bitmask value
|
||||
*
|
||||
* @return string of JavaScript code, e.g. 'modCodes.SHIFT | modCodes.CTRL /* 0x0030 ./'
|
||||
**/
|
||||
export function FormatModifierAsBitflags(FBitMask: number): string {
|
||||
const mask: string[] = [
|
||||
'LCTRL', // 0X0001
|
||||
'RCTRL', // 0X0002
|
||||
'LALT', // 0X0004
|
||||
'RALT', // 0X0008
|
||||
|
||||
'SHIFT', // 0X0010
|
||||
'CTRL', // 0X0020
|
||||
'ALT', // 0X0040
|
||||
|
||||
'???', // Reserved
|
||||
|
||||
'CAPS', // 0X0100
|
||||
'NO_CAPS', // 0X0200
|
||||
|
||||
'NUM_LOCK', // 0X0400
|
||||
'NO_NUM_LOCK', // 0X0800
|
||||
|
||||
'SCROLL_LOCK', // 0X1000
|
||||
'NO_SCROLL_LOCK', // 0X2000
|
||||
|
||||
'VIRTUAL_KEY' // 0X4000
|
||||
];
|
||||
|
||||
let i: number;
|
||||
let result = '';
|
||||
|
||||
//TODO: We need to think about mnemonic layouts which are incompletely supported at present
|
||||
//tavultesoft.keymanweb.osk.
|
||||
|
||||
if(IsKeyboardVersion10OrLater()) {
|
||||
// This depends on flags defined in KeymanWeb 10.0
|
||||
result = '';
|
||||
|
||||
for(i = 0; i < mask.length; i++) {
|
||||
if(FBitMask & (1 << i)) {
|
||||
if(result != '') result += ' | ';
|
||||
result += 'modCodes.'+mask[i];
|
||||
}
|
||||
}
|
||||
|
||||
if(result == '') {
|
||||
result = '0';
|
||||
}
|
||||
|
||||
result += ' /* 0x' + zeroPadHex(FBitMask, 4) + ' */';
|
||||
}
|
||||
else {
|
||||
result = '0x'+zeroPadHex(FBitMask, 4);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
2
developer/src/kmc-kmw/src/main.ts
Normal file
2
developer/src/kmc-kmw/src/main.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
export { WriteCompiledKeyboard } from './compiler/write-compiled-keyboard.js';
|
||||
293
developer/src/kmc-kmw/src/util/util.ts
Normal file
293
developer/src/kmc-kmw/src/util/util.ts
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
import { KMX } from "@keymanapp/common-types";
|
||||
|
||||
/**
|
||||
* Verifies that value is an item in the enumeration.
|
||||
*/
|
||||
export function isValidEnumValue<T extends {[key: number]: string | number}>(enu: T, value: string) {
|
||||
return (Object.values(enu) as string[]).includes(value);
|
||||
}
|
||||
|
||||
export interface TSentinelRecord {
|
||||
IsSentinel: boolean;
|
||||
Code?: number;
|
||||
|
||||
Any?: {
|
||||
StoreIndex: number;
|
||||
Store: KMX.STORE;
|
||||
};
|
||||
Index?: {
|
||||
StoreIndex: number;
|
||||
Store: KMX.STORE;
|
||||
Index: number;
|
||||
};
|
||||
DeadKey?: {
|
||||
DeadKey: number;
|
||||
};
|
||||
Use?: {
|
||||
GroupIndex: number;
|
||||
Group: KMX.GROUP;
|
||||
};
|
||||
Call?: {
|
||||
StoreIndex: number;
|
||||
Store: KMX.STORE;
|
||||
};
|
||||
ContextEx?: {
|
||||
Index: number;
|
||||
};
|
||||
IfOpt?: {
|
||||
StoreIndex1: number;
|
||||
Store1: KMX.STORE;
|
||||
StoreIndex2: number;
|
||||
Store2: KMX.STORE;
|
||||
IsNot: number;
|
||||
};
|
||||
IfSystemStore?: {
|
||||
dwSystemID: number;
|
||||
SystemStore: KMX.STORE;
|
||||
StoreIndex: number;
|
||||
Store: KMX.STORE;
|
||||
IsNot: number;
|
||||
};
|
||||
SetOpt?: {
|
||||
StoreIndex1: number;
|
||||
Store1: KMX.STORE;
|
||||
StoreIndex2: number;
|
||||
Store2: KMX.STORE;
|
||||
};
|
||||
SetSystemStore?: {
|
||||
dwSystemID: number;
|
||||
SystemStore: KMX.STORE;
|
||||
StoreIndex: number;
|
||||
Store: KMX.STORE;
|
||||
};
|
||||
ResetOpt?: {
|
||||
StoreIndex: number;
|
||||
Store: KMX.STORE;
|
||||
};
|
||||
SaveOpt?: {
|
||||
StoreIndex: number;
|
||||
Store: KMX.STORE;
|
||||
};
|
||||
ChrVal?: number;
|
||||
};
|
||||
|
||||
|
||||
export function ExpandSentinel(fk: KMX.KEYBOARD, pwsz: string, x: number): TSentinelRecord {
|
||||
let result: TSentinelRecord = {
|
||||
IsSentinel: false
|
||||
};
|
||||
if(pwsz.charCodeAt(x) == KMX.KMXFile.UC_SENTINEL) {
|
||||
result.IsSentinel = true;
|
||||
x++;
|
||||
result.Code = pwsz.charCodeAt(x);
|
||||
x++;
|
||||
switch(result.Code) {
|
||||
case KMX.KMXFile.CODE_ANY:
|
||||
case KMX.KMXFile.CODE_NOTANY: // I3981
|
||||
let anyIdx = pwsz.charCodeAt(x) - 1;
|
||||
result.Any = {
|
||||
StoreIndex: anyIdx,
|
||||
Store: fk.stores[anyIdx]
|
||||
}
|
||||
break;
|
||||
case KMX.KMXFile.CODE_INDEX:
|
||||
let indexIdx = pwsz.charCodeAt(x) - 1;
|
||||
x++;
|
||||
result.Index = {
|
||||
StoreIndex: indexIdx,
|
||||
Store: fk.stores[indexIdx],
|
||||
Index: pwsz.charCodeAt(x) - 1
|
||||
}
|
||||
break;
|
||||
case KMX.KMXFile.CODE_DEADKEY:
|
||||
result.DeadKey = { DeadKey: pwsz.charCodeAt(x) - 1 };
|
||||
break;
|
||||
case KMX.KMXFile.CODE_USE:
|
||||
let useIdx = pwsz.charCodeAt(x) - 1;
|
||||
result.Use = {
|
||||
GroupIndex: useIdx,
|
||||
Group: fk.groups[useIdx]
|
||||
};
|
||||
break;
|
||||
case KMX.KMXFile.CODE_CALL:
|
||||
let callIdx = pwsz.charCodeAt(x) - 1;
|
||||
result.Call = {
|
||||
StoreIndex: callIdx,
|
||||
Store: fk.stores[callIdx]
|
||||
}
|
||||
break;
|
||||
case KMX.KMXFile.CODE_CONTEXTEX:
|
||||
result.ContextEx = { Index: pwsz.charCodeAt(x) - 1 };
|
||||
break;
|
||||
case KMX.KMXFile.CODE_SETOPT: // I3429
|
||||
let setIdx1 = pwsz.charCodeAt(x) - 1;
|
||||
x++;
|
||||
let setIdx2 = pwsz.charCodeAt(x) - 1;
|
||||
result.SetOpt = {
|
||||
StoreIndex1: setIdx1,
|
||||
Store1: fk.stores[setIdx1],
|
||||
StoreIndex2: setIdx2,
|
||||
Store2: fk.stores[setIdx2]
|
||||
};
|
||||
break;
|
||||
case KMX.KMXFile.CODE_SETSYSTEMSTORE: // I3437
|
||||
let setsIdx1 = pwsz.charCodeAt(x) - 1;
|
||||
x++;
|
||||
let setsIdx2 = pwsz.charCodeAt(x) - 1;
|
||||
result.SetSystemStore = {
|
||||
dwSystemID: setsIdx1,
|
||||
SystemStore: fk.stores.find(s => s.dwSystemID == setsIdx1) || null,
|
||||
StoreIndex: setsIdx2,
|
||||
Store: fk.stores[setsIdx2]
|
||||
};
|
||||
break;
|
||||
case KMX.KMXFile.CODE_RESETOPT: // I3429
|
||||
result.ResetOpt = {
|
||||
StoreIndex: pwsz.charCodeAt(x) - 1,
|
||||
Store: fk.stores[result.ResetOpt.StoreIndex]
|
||||
};
|
||||
break;
|
||||
case KMX.KMXFile.CODE_SAVEOPT: // I3429
|
||||
result.SaveOpt = {
|
||||
StoreIndex: pwsz.charCodeAt(x) - 1,
|
||||
Store: fk.stores[result.SaveOpt.StoreIndex]
|
||||
};
|
||||
break;
|
||||
case KMX.KMXFile.CODE_IFOPT: // I3429
|
||||
let ifIdx1 = pwsz.charCodeAt(x) - 1;
|
||||
x++;
|
||||
let ifNot = pwsz.charCodeAt(x) - 1;
|
||||
x++;
|
||||
let ifIdx2 = pwsz.charCodeAt(x) - 1;
|
||||
result.IfOpt = {
|
||||
StoreIndex1: ifIdx1,
|
||||
Store1: fk.stores[ifIdx1],
|
||||
IsNot: ifNot, // I3429
|
||||
StoreIndex2: ifIdx2,
|
||||
Store2: fk.stores[ifIdx2]
|
||||
};
|
||||
break;
|
||||
case KMX.KMXFile.CODE_IFSYSTEMSTORE: // I3430
|
||||
let ifsSystemID = pwsz.charCodeAt(x) - 1;
|
||||
x++;
|
||||
let ifsNot = pwsz.charCodeAt(x) - 1;
|
||||
x++;
|
||||
let ifsIdx2 = pwsz.charCodeAt(x) - 1;
|
||||
result.IfSystemStore = {
|
||||
dwSystemID: ifsSystemID,
|
||||
SystemStore: fk.stores.find(s => s.dwSystemID == ifsSystemID) || null,
|
||||
IsNot: ifsNot,
|
||||
StoreIndex: ifsIdx2,
|
||||
Store: fk.stores[ifsIdx2]
|
||||
};
|
||||
break;
|
||||
case KMX.KMXFile.CODE_NUL:
|
||||
case KMX.KMXFile.CODE_CONTEXT:
|
||||
case KMX.KMXFile.CODE_RETURN:
|
||||
case KMX.KMXFile.CODE_BEEP:
|
||||
case KMX.KMXFile.CODE_EXTENDED:
|
||||
// No additional detail needed, or outside scope
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unrecognized system store value ${result.Code}`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
result.ChrVal = GetSuppChar(pwsz, x);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function GetSuppChar(p: string, x: number): number {
|
||||
return p.codePointAt(x);
|
||||
}
|
||||
|
||||
export function incxstr(p: string, x: number): number {
|
||||
if(x >= p.length) {
|
||||
return p.length;
|
||||
}
|
||||
|
||||
let ch = p.charCodeAt(x);
|
||||
if(ch != KMX.KMXFile.UC_SENTINEL) {
|
||||
if(ch >= 0xD800 && ch <= 0xDBFF) {
|
||||
x++;
|
||||
if(x == p.length) {
|
||||
return x;
|
||||
}
|
||||
ch = p.charCodeAt(x);
|
||||
if (ch >= 0xDC00 && ch <= 0xDFFF) {
|
||||
x++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
x++;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
x++;
|
||||
if(x == p.length) {
|
||||
return x;
|
||||
}
|
||||
|
||||
switch(p.charCodeAt(x)) {
|
||||
case KMX.KMXFile.CODE_ANY: x += 2; break;
|
||||
case KMX.KMXFile.CODE_INDEX: x += 3; break;
|
||||
case KMX.KMXFile.CODE_USE: x += 2; break;
|
||||
case KMX.KMXFile.CODE_DEADKEY: x += 2; break;
|
||||
case KMX.KMXFile.CODE_EXTENDED:
|
||||
x += 3;
|
||||
while(x <= p.length && p.charCodeAt(x) != KMX.KMXFile.UC_SENTINEL_EXTENDEDEND) {
|
||||
x++;
|
||||
}
|
||||
x++;
|
||||
break;
|
||||
case KMX.KMXFile.CODE_CALL: x += 2; break;
|
||||
case KMX.KMXFile.CODE_CONTEXTEX: x += 2; break;
|
||||
case KMX.KMXFile.CODE_NOTANY: x += 2; break;
|
||||
|
||||
case KMX.KMXFile.CODE_CLEARCONTEXT: x += 2; break;
|
||||
case KMX.KMXFile.CODE_IFOPT: x += 4; break;
|
||||
case KMX.KMXFile.CODE_IFSYSTEMSTORE: x += 4; break;
|
||||
case KMX.KMXFile.CODE_SETOPT: x += 3; break;
|
||||
case KMX.KMXFile.CODE_SETSYSTEMSTORE: x += 3; break;
|
||||
case KMX.KMXFile.CODE_RESETOPT: x += 2; break;
|
||||
case KMX.KMXFile.CODE_SAVEOPT: x += 2; break;
|
||||
|
||||
default: x++;
|
||||
}
|
||||
|
||||
if(x >= p.length) {
|
||||
return p.length;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
export function xstrlen(p: string): number {
|
||||
let result = 0, x = 0;
|
||||
while(x < p.length) {
|
||||
x = incxstr(p, x);
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function xstrlen_printing(p: string): number {
|
||||
let result = 0, x = 0;
|
||||
while(x < p.length) {
|
||||
if(x + 1 < p.length && p.charCodeAt(x) == KMX.KMXFile.UC_SENTINEL) {
|
||||
switch(p.charCodeAt(x+1)) {
|
||||
case KMX.KMXFile.CODE_DEADKEY:
|
||||
case KMX.KMXFile.CODE_NUL:
|
||||
case KMX.KMXFile.CODE_IFOPT:
|
||||
case KMX.KMXFile.CODE_IFSYSTEMSTORE:
|
||||
result--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
x = incxstr(p, x);
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
7
developer/src/kmc-kmw/test/README.md
Normal file
7
developer/src/kmc-kmw/test/README.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Keyman kmn kmw Keyboard Compiler Tests
|
||||
======================================
|
||||
|
||||
Test
|
||||
----
|
||||
|
||||
../build.sh test
|
||||
BIN
developer/src/kmc-kmw/test/fixtures/khmer_angkor.ico
vendored
Normal file
BIN
developer/src/kmc-kmw/test/fixtures/khmer_angkor.ico
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
5463
developer/src/kmc-kmw/test/fixtures/khmer_angkor.js
vendored
Normal file
5463
developer/src/kmc-kmw/test/fixtures/khmer_angkor.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
1950
developer/src/kmc-kmw/test/fixtures/khmer_angkor.keyman-touch-layout
vendored
Normal file
1950
developer/src/kmc-kmw/test/fixtures/khmer_angkor.keyman-touch-layout
vendored
Normal file
File diff suppressed because it is too large
Load diff
642
developer/src/kmc-kmw/test/fixtures/khmer_angkor.kmn
vendored
Normal file
642
developer/src/kmc-kmw/test/fixtures/khmer_angkor.kmn
vendored
Normal file
|
|
@ -0,0 +1,642 @@
|
|||
store(&VERSION) '10.0'
|
||||
store(&NAME) "Khmer Angkor"
|
||||
store(©RIGHT) '© 2015-2022 SIL International'
|
||||
store(&MESSAGE) "More than just a Khmer Unicode keyboard."
|
||||
store(&TARGETS) 'any'
|
||||
store(&LAYOUTFILE) 'khmer_angkor.keyman-touch-layout'
|
||||
store(&KEYBOARDVERSION) '1.3'
|
||||
store(&BITMAP) 'khmer_angkor.ico'
|
||||
store(&VISUALKEYBOARD) 'khmer_angkor.kvks'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
|
||||
|
||||
c ==============================================STORES==============================================
|
||||
|
||||
|
||||
|
||||
c 33 consonants and two deprecated consonants
|
||||
|
||||
store(c_key) [K_K] [K_X] [SHIFT K_K] [SHIFT K_X] [K_G] \
|
||||
[K_C] [K_Q] [SHIFT K_C] [SHIFT K_Q] [SHIFT K_J] \
|
||||
[K_D] [K_Z] [SHIFT K_D] [SHIFT K_Z] [SHIFT K_N] \
|
||||
[K_T] [K_F] [SHIFT K_T] [SHIFT K_F] [K_N] \
|
||||
[K_B] [K_P] [SHIFT K_B] [SHIFT K_P] [K_M] \
|
||||
[K_Y] [K_R] [K_L] [K_V] [K_S] [K_H] [SHIFT K_L] [SHIFT K_G] \
|
||||
[RALT K_K] [RALT K_B]
|
||||
store(c_out) U+1780 U+1781 U+1782 U+1783 U+1784 \
|
||||
U+1785 U+1786 U+1787 U+1788 U+1789 \
|
||||
U+178A U+178B U+178C U+178D U+178E \
|
||||
U+178F U+1790 U+1791 U+1792 U+1793 \
|
||||
U+1794 U+1795 U+1796 U+1797 U+1798 \
|
||||
U+1799 U+179A U+179B U+179C U+179F U+17A0 U+17A1 U+17A2 \
|
||||
U+179D U+179E c deprecated, but they are used in minority languages
|
||||
|
||||
c All genuine dependent vowels
|
||||
|
||||
store(v_gen_key) [K_A] [K_I] [SHIFT K_I] [K_W] [SHIFT K_W] [K_U] [SHIFT K_U] [SHIFT K_Y] \
|
||||
[K_COLON] [SHIFT K_LBRKT] [K_LBRKT] [K_E] [SHIFT K_E] [SHIFT K_S] [K_O] [SHIFT K_O]
|
||||
store(v_gen) U+17B6 U+17B7 U+17B8 U+17B9 U+17BA U+17BB U+17BC U+17BD \
|
||||
U+17BE U+17BF U+17C0 U+17C1 U+17C2 U+17C3 U+17C4 U+17C5
|
||||
|
||||
c All pseudo dependent vowels
|
||||
|
||||
store(v_pseudo_key) [SHIFT K_M] [SHIFT K_H] [RALT K_QUOTE]
|
||||
store(v_pseudo) U+17C6 U+17C7 U+17C8
|
||||
|
||||
c Both genuine and pseudo vowels
|
||||
|
||||
store(v_key) outs(v_gen_key) outs(v_pseudo_key)
|
||||
store(v_out) outs(v_gen) outs(v_pseudo)
|
||||
store(v_any) outs(v_out)
|
||||
|
||||
c These seven vowels can be concatenated with Reahmuk (U+17C7) to make េះ ោះ ុះ ិះ ីះ ឹះ and ែះ.
|
||||
|
||||
store(v_combo_R) U+17C1 U+17C4 U+17BB U+17B7 U+17B8 U+17B9 U+17C2
|
||||
|
||||
c these two vowels can be concatenated with Nikahit (U+17C6) to make ាំ and ុំ.
|
||||
|
||||
store(v_combo_N) U+17B6 U+17BB
|
||||
store(v_combo) outs(v_combo_R) outs(v_combo_N)
|
||||
|
||||
c Independent vowels
|
||||
|
||||
store(ind_v_key) [K_HYPHEN] [RALT K_I] [SHIFT K_RBRKT] [RALT K_T] [RALT K_LBRKT] [K_RBRKT] [RALT K_R] [SHIFT K_R] \
|
||||
[SHIFT K_BKSLASH] [K_BKSLASH] [RALT K_E] [RALT K_P] [RALT K_O] [K_EQUAL] [RALT K_RBRKT]
|
||||
store(ind_v_out) U+17A5 U+17A6 U+17A7 U+17A8 U+17A9 U+17AA U+17AB U+17AC \
|
||||
U+17AD U+17AE U+17AF U+17B0 U+17B1 U+17B2 U+17B3
|
||||
|
||||
c Diacritics
|
||||
|
||||
store(diacritic_key) [K_QUOTE] [SHIFT K_7] [SHIFT K_HYPHEN] [SHIFT K_8] [SHIFT K_6] [RALT K_QUOTE] \
|
||||
[RALT K_EQUAL] [RALT K_3] [RALT K_W] [RALT K_Q] [K_J]
|
||||
store(diacritic_out) U+17CB U+17D0 U+17CC U+17CF U+17CD U+17C8 \
|
||||
U+17CE U+17D1 U+17DD U+17DC U+17D2
|
||||
|
||||
c Consonant shifter--Muusikatoan(U+17C9) and Triisap(U+17CA)
|
||||
|
||||
store(c_shifter_key) [SHIFT K_QUOTE] [K_SLASH]
|
||||
store(c_shifter) U+17C9 U+17CA
|
||||
|
||||
c punctuations
|
||||
|
||||
store(punct_key) [K_PERIOD] [SHIFT K_PERIOD] [RALT K_COLON] [SHIFT K_2] [RALT K_L] [RALT K_6] [RALT K_7] [RALT K_M]
|
||||
store(punct_out) U+17D4 U+17D5 U+17D6 U+17D7 U+17D8 U+17D9 U+17DA U+17D3
|
||||
|
||||
store(latin_punct_key) [K_BKQUOTE] [SHIFT K_BKQUOTE] [SHIFT K_9] [SHIFT K_0] [SHIFT K_1] [SHIFT K_3] \
|
||||
[SHIFT K_5] [SHIFT K_EQUAL] [SHIFT K_SLASH] [RALT K_9] [RALT K_0] [RALT K_BKSLASH] \
|
||||
[RALT K_2] [RALT K_8] [RALT K_COMMA] [RALT K_D] [RALT K_PERIOD] [RALT K_SLASH] \
|
||||
[RALT K_Y] [RALT K_U] [RALT K_BKQUOTE] [RALT K_1] [RALT K_A] [RALT K_S] \
|
||||
[RALT K_F] [RALT K_G] [RALT K_HYPHEN] [RALT K_H] [RALT K_J] [RALT K_N] \
|
||||
[RALT K_Z] [RALT K_X] [RALT K_C] [RALT K_V]
|
||||
store(latin_punct_out) U+00AB U+00BB U+0028 U+0029 U+0021 U+0022 \
|
||||
U+0025 U+003D U+003F U+007B U+007D U+005C \
|
||||
U+0040 U+002A U+002C U+00D7 U+002E U+002F \
|
||||
U+005B U+005D U+200D U+200C U+002B U+002D \
|
||||
U+00F7 U+003A U+2248 U+2018 U+2019 U+003B \
|
||||
U+003C U+003E U+0023 U+0026
|
||||
c white space, ZWSP, ZWJ
|
||||
store(spaces_key) [K_SPACE] [SHIFT K_SPACE] [RALT K_SPACE]
|
||||
store(spaces_out) U+200B U+0020 U+00A0
|
||||
|
||||
c Currency: Riel, Dollar and Euro
|
||||
|
||||
store(currency_key) [SHIFT K_4] [RALT K_4] [RALT K_5]
|
||||
store(currency_out) U+17DB U+0024 U+20AC
|
||||
|
||||
c Khmer digits 0 through 9
|
||||
|
||||
store(digit_key) [K_0] [K_1] [K_2] [K_3] [K_4] [K_5] [K_6] [K_7] [K_8] [K_9]
|
||||
store(digit_out) U+17E0 U+17E1 U+17E2 U+17E3 U+17E4 U+17E5 U+17E6 U+17E7 U+17E8 U+17E9
|
||||
|
||||
c Khmer Lek Attak (a.k.a. divination lore)
|
||||
store(lek_attak_key) [SHIFT RALT K_0] [SHIFT RALT K_1] [SHIFT RALT K_2] [SHIFT RALT K_3] [SHIFT RALT K_4] \
|
||||
[SHIFT RALT K_5] [SHIFT RALT K_6] [SHIFT RALT K_7] [SHIFT RALT K_8] [SHIFT RALT K_9]
|
||||
store(lek_attak_out) U+17F0 U+17F1 U+17F2 U+17F3 U+17F4 \
|
||||
U+17F5 U+17F6 U+17F7 U+17F8 U+17F9
|
||||
|
||||
c Lunar date format (Khmer style)
|
||||
|
||||
store(lunar_date_key) [SHIFT RALT K_A] [SHIFT RALT K_B] [SHIFT RALT K_C] [SHIFT RALT K_D] [SHIFT RALT K_E] \
|
||||
[SHIFT RALT K_F] [SHIFT RALT K_G] [SHIFT RALT K_H] [SHIFT RALT K_I] [SHIFT RALT K_J] \
|
||||
[SHIFT RALT K_K] [SHIFT RALT K_L] [SHIFT RALT K_M] [SHIFT RALT K_N] [SHIFT RALT K_O] \
|
||||
[SHIFT RALT K_P] [SHIFT RALT K_Q] [SHIFT RALT K_R] [SHIFT RALT K_S] [SHIFT RALT K_T] \
|
||||
[SHIFT RALT K_U] [SHIFT RALT K_V] [SHIFT RALT K_W] [SHIFT RALT K_X] [SHIFT RALT K_Y] \
|
||||
[SHIFT RALT K_Z] [SHIFT RALT K_COLON] [SHIFT RALT K_COMMA] [SHIFT RALT K_PERIOD] [SHIFT RALT K_LBRKT] \
|
||||
[SHIFT RALT K_RBRKT] [SHIFT RALT K_QUOTE]
|
||||
store(lunar_date_out) U+19EC U+19FB U+19F9 U+19EE U+19E2 \
|
||||
U+19EF U+19F0 U+19F1 U+19E7 U+19F2 \
|
||||
U+19F3 U+19F4 U+19FD U+19FC U+19E8 \
|
||||
U+19E9 U+19E0 U+19E3 U+19ED U+19E4 \
|
||||
U+19E6 U+19FA U+19E1 U+19F8 U+19E5 \
|
||||
U+19F7 U+19F5 U+19FE U+19FF U+19EA \
|
||||
U+19EB U+19F6
|
||||
|
||||
c Subscripts for mobile/table layouts
|
||||
|
||||
store(input_subcons) \
|
||||
[T_17D2_1780] [T_17D2_1781] [T_17D2_1782] [T_17D2_1783] [T_17D2_1784] [T_17D2_1785] [T_17D2_1786] [T_17D2_1787] \
|
||||
[T_17D2_1788] [T_17D2_1789] [T_17D2_178A] [T_17D2_178B] [T_17D2_178C] [T_17D2_178D] [T_17D2_178E] [T_17D2_178F] \
|
||||
[T_17D2_1790] [T_17D2_1791] [T_17D2_1792] [T_17D2_1793] [T_17D2_1794] [T_17D2_1795] [T_17D2_1796] [T_17D2_1797] \
|
||||
[T_17D2_1798] [T_17D2_1799] [T_17D2_179A] [T_17D2_179B] [T_17D2_179C] [T_17D2_179D] [T_17D2_179E] [T_17D2_179F] \
|
||||
[T_17D2_17A0] [T_17D2_17A1] [T_17D2_17A2]
|
||||
|
||||
store(subcons) \
|
||||
U+1780 U+1781 U+1782 U+1783 U+1784 U+1785 U+1786 U+1787 \
|
||||
U+1788 U+1789 U+178A U+178B U+178C U+178D U+178E U+178F \
|
||||
U+1790 U+1791 U+1792 U+1793 U+1794 U+1795 U+1796 U+1797 \
|
||||
U+1798 U+1799 U+179A U+179B U+179C U+179D U+179E U+179F \
|
||||
U+17A0 U+17A1 U+17A2
|
||||
|
||||
c Arabic digits 0 through 9
|
||||
|
||||
store(arabic_digit_key) [U_0030] [U_0031] [U_0032] [U_0033] [U_0034] [U_0035] [U_0036] [U_0037] [U_0038] [U_0039]
|
||||
store(arabic_digit_out) U+0030 U+0031 U+0032 U+0033 U+0034 U+0035 U+0036 U+0037 U+0038 U+0039
|
||||
|
||||
c These stores are for consonant (cluster) and consonant shifter configuration
|
||||
|
||||
store(v_above) U+17B7 U+17B8 U+17B9 U+17BA \
|
||||
U+17BE U+17D0 c These vowels are rendered above the base consonant.
|
||||
store(shiftable_c_1st) U+179F U+17A0 U+17A2 c These consonants shift to the 2nd series when adding U+17CA to them.
|
||||
store(shiftable_BA) U+1794 c BA is unique because it can be used with both U+17CA (shift to 2nd) and and U+179C (shift to PA, still in 1st series).
|
||||
store(shiftable_c_2nd) U+1784 U+1789 U+1798 U+1799 \
|
||||
U+179A U+179C U+1793 U+179B c These consonants shift to the 1st series when adding U+17C9 to them.
|
||||
store(shiftable_c_2nd_with_BA) outs(shiftable_c_2nd) outs(shiftable_BA)
|
||||
store(c_2nd_combo_LO) U+1799 U+1798 U+1784 U+1794 \
|
||||
U+179C c These can be combined with U+179B to make a 2nd series consonant cluster.
|
||||
store(c_2nd_combo_MO) U+1799 U+179B U+1784 U+179A c These can be combined with U+1798 to make a 2nd series consonant cluster.
|
||||
store(c_1st_combo_LO) U+1794 U+17A0 U+17A2 c they can be combined with U+179B to make a 1st series consonant cluster.
|
||||
store(c_1st_combo_MO) U+17A0 U+179F U+17A2 c they can be combined with U+1798 to make a 1st series consonant cluster.
|
||||
store(c_combo_SA) U+1794 U+1799 U+179B U+1798 \
|
||||
U+1793 U+1789 U+1784 U+179A \
|
||||
U+179C U+17A2 c they can be combined with U+179F to make a 1st series consonant cluster.
|
||||
store(c_combo_QA) U+1786 U+1788 U+1794 U+1795 \
|
||||
U+178F U+1791 c they can be combined with U+17A2 to make a 1st series consonant cluster.
|
||||
store(c_combo_HA) U+179C U+17A3 c they can be combined with U+17A0 to make a 1st series consonant cluster.
|
||||
|
||||
|
||||
|
||||
c ==============================================BASIC RULES & CONSTRAINTS/ROTATIONS==============================================
|
||||
|
||||
|
||||
|
||||
group(main) using keys
|
||||
|
||||
c Basic rules with RALT key
|
||||
|
||||
+ any(c_key) > index(c_out,1)
|
||||
+ any(v_key) > index(v_out,1)
|
||||
+ any(ind_v_key) > index(ind_v_out,1)
|
||||
+ any(diacritic_key) > index(diacritic_out,1)
|
||||
+ any(c_shifter_key) > index(c_shifter,1)
|
||||
+ any(punct_key) > index(punct_out,1)
|
||||
+ any(latin_punct_key) > index(latin_punct_out,1)
|
||||
+ any(currency_key) > index(currency_out,1)
|
||||
+ any(digit_key) > index(digit_out,1)
|
||||
+ any(lek_attak_key) > index(lek_attak_out,1)
|
||||
+ any(lunar_date_key) > index(lunar_date_out,1)
|
||||
+ any(spaces_key) > index(spaces_out,1)
|
||||
|
||||
c two-unicode-code-point vowels
|
||||
|
||||
+ [SHIFT K_A] > U+17B6 U+17C6
|
||||
+ [SHIFT K_V] > U+17C1 U+17C7
|
||||
+ [SHIFT K_COLON] > U+17C4 U+17C7
|
||||
+ [K_COMMA] > U+17BB U+17C6
|
||||
+ [SHIFT K_COMMA] > U+17BB U+17C7
|
||||
|
||||
c Constraints
|
||||
|
||||
any(v_gen) + [K_QUOTE] > context beep c no Bantoc after any genuine vowel
|
||||
any(v_pseudo) + [K_QUOTE] > context beep c no Bantoc after any pseudo vowel
|
||||
any(c_shifter) + [K_QUOTE] > context beep c no Bantoc after Triisap/Muusikatoan
|
||||
U+17D2 any(c_out) + [K_QUOTE] > context beep c no Bantoc on a subscript
|
||||
any(c_shifter) + any(c_shifter_key) > context beep c no two Triisap/Muusikatoan
|
||||
|
||||
c Rotation
|
||||
|
||||
U+17C7 + [SHIFT K_H] > U+17C8 c U+17C7 is changed to U+17C8 when pressing [SHIFT K_H].
|
||||
U+17C8 + [SHIFT K_H] > U+17C7 c U+17C8 is changed to U+17C7 when K_H is pressed.
|
||||
c any(v_gen) U+17C7 + [SHIFT K_H] > context beep c Don't rotate between U+17C7 and U+17C8.
|
||||
|
||||
c Press Space twice to get a White Space
|
||||
|
||||
U+200B + [K_SPACE] > U+0020
|
||||
|
||||
c One backspace deletes a two-part vowels (i.e. psuedoVowel + U+17C7)
|
||||
|
||||
any(v_combo_N) U+17C6 + [K_BKSP] > nul
|
||||
any(v_combo_R) U+17C7 + [K_BKSP] > nul
|
||||
|
||||
c When pressing [K_U] after ាំ and ុំ, the U+17BB is converted to a respective consonant shifter placing before them (ាំ and ុំ).
|
||||
|
||||
any(shiftable_c_1st) U+17B6 U+17C6 + [K_U] > context(1) U+17CA context(2) context(3) c fix ស ាំ ុ > ស៊ាំ
|
||||
any(shiftable_c_2nd_with_BA) U+17B6 U+17C6 + [K_U] > context(1) U+17C9 context(2) context(3) c fix ម ាំ ុ > ម៉ាំ
|
||||
|
||||
c Consonant shifter constraints (beep when the consonant shifter is used in inappropriate environment)
|
||||
|
||||
any(shiftable_c_1st) + [SHIFT K_QUOTE] > context U+17C9 beep
|
||||
any(shiftable_c_2nd_with_BA) + [K_SLASH] > context U+17CA beep
|
||||
|
||||
c 1st series consonant clusters
|
||||
|
||||
any(c_combo_QA) U+17D2 U+17A2 + [SHIFT K_QUOTE] > context U+17C9 beep
|
||||
U+179B U+17D2 any(c_1st_combo_LO) + [SHIFT K_QUOTE] > context U+17C9 beep
|
||||
U+1798 U+17D2 any(c_1st_combo_MO) + [SHIFT K_QUOTE] > context U+17C9 beep
|
||||
U+179F U+17D2 any(c_combo_SA) + [SHIFT K_QUOTE] > context U+17C9 beep
|
||||
any(c_combo_HA) U+17D2 U+17A0 + [SHIFT K_QUOTE] > context U+17C9 beep
|
||||
U+17A2 U+17D2 U+1784 + [SHIFT K_QUOTE] > context U+17C9 beep
|
||||
U+17A2 U+17D2 U+179C + [SHIFT K_QUOTE] > context U+17C9 beep
|
||||
|
||||
c 2nd series consonant clusters
|
||||
|
||||
U+179B U+17D2 any(c_2nd_combo_LO) + [K_SLASH] > context U+17CA beep
|
||||
U+1798 U+17D2 any(c_2nd_combo_MO) + [K_SLASH] > context U+17CA beep
|
||||
|
||||
|
||||
c ==============================================MOBILE/TABLET TOUCH LAYOUT==============================================
|
||||
|
||||
|
||||
|
||||
+ any(input_subcons) > U+17D2 index(subcons, 1)
|
||||
|
||||
c delete a subscript (a subscript sign + a consonant) upon a backspace
|
||||
|
||||
platform('touch') U+17D2 any(c_out) + [K_BKSP] > nul c working OK
|
||||
|
||||
+ [K_NPSTAR] > U+002A
|
||||
+ [SHIFT K_NPSTAR] > U+002A
|
||||
+ [K_NPPLUS] > U+002B
|
||||
+ [SHIFT K_NPPLUS] > U+002B
|
||||
+ [K_NPMINUS] > U+002D
|
||||
+ [SHIFT K_NPMINUS] > U+002D
|
||||
+ [K_NPDOT] > U+002E
|
||||
+ [SHIFT K_NPDOT] > U+002E
|
||||
+ [K_NPSLASH] > U+002F
|
||||
+ [SHIFT K_NPSLASH] > U+002F
|
||||
|
||||
|
||||
|
||||
c ==============================================NORMALIZATION==============================================
|
||||
|
||||
|
||||
|
||||
match > use(normalise)
|
||||
|
||||
group(normalise)
|
||||
|
||||
c Illegitimate vowel combinations should be transformed to the legitimate ones (Case #6 and #7).
|
||||
|
||||
U+17C1 U+17B6 > U+17C4 c when type េ and ា, tranform them to ោ
|
||||
U+17B6 U+17C1 > U+17C4 c when type ា and េ, tranform them to ោ
|
||||
U+17C1 U+17B8 > U+17BE c when type េ and ី , tranform them to ើ
|
||||
U+17B8 U+17C1 > U+17BE c when type ី and េ, tranform them to ើ
|
||||
|
||||
c Illegitimate vowel combinations should be transformed to the legitimate ones (Case #5).
|
||||
|
||||
U+17C6 U+17BB > U+17BB U+17C6 c when type ំ and ុ , tranform them to ុំ
|
||||
U+17C6 U+17B6 > U+17B6 U+17C6 c when type ំ and ា, tranform them to ាំ
|
||||
|
||||
|
||||
c Rotate vowels
|
||||
|
||||
any(v_gen) any(v_gen) > context(2) c the last vowel stroke replaces the previous one.
|
||||
|
||||
c Rotation of two-part vowels
|
||||
|
||||
any(v_gen) any(v_pseudo) any(v_gen) > context(3) c a two-part vowel rotates to a genuine vowel.
|
||||
any(v_gen) any(v_pseudo) any(v_pseudo) > context(3) c a two-part vowel rotates to a pseudo vowel.
|
||||
any(v_gen) any(v_gen) any(v_pseudo) > context(2) context(3) c a genuine vowel rotates to a two-part vowel.
|
||||
any(v_pseudo) any(v_gen) any(v_pseudo) > context(2) context(3) c a pseudo vowel roates to a two-part vowel.
|
||||
any(v_gen) any(v_pseudo) any(v_gen) any(v_pseudo) > context(3) context(4) c a two-part vowel rotates to another two-part vowel.
|
||||
any(v_pseudo) any(v_pseudo) > context(2) c a pseudo vowel rotates to another pseudo vowel.
|
||||
c any(v_pseudo) any(v_gen) > context(2) c a pseudo vowel roates to a genuine vowel.
|
||||
|
||||
c Delete extraneous coeng markers
|
||||
|
||||
U+17D2 U+17D2 > context(1) c no two coengs are allowed.
|
||||
U+17D2 any(v_any) > context(2) c The coeng is deleted when a vowel is put after it.
|
||||
U+17D2 any(v_gen) any(v_pseudo) > context(2) context(3) c The coeng is deleted when a pseudo vowel is put after it.
|
||||
|
||||
c Case #1: when a subscript is typed after a vowel, the subscript should be automatically moved to before the vowel.
|
||||
|
||||
any(v_any) U+17D2 any(subcons) > context(2) context(3) context(1) c a vowel has to come after a subscript.
|
||||
any(v_combo_N) U+17C6 U+17D2 any(subcons) > context(3) context(4) context(1) context(2) c these two-part vowels have to come after a subscript.
|
||||
any(v_combo_R) U+17C7 U+17D2 any(subcons) > context(3) context(4) context(1) context(2) c these two-part vowels have to come after a subscript.
|
||||
|
||||
c a subscript placed after a shifter and a vowel (a genuine/pseudo vowel or a two-part vowel) has to move to before them.
|
||||
|
||||
any(c_shifter) any(v_any) U+17D2 any(subcons) > context(3) context(4) context(1) context(2) c after a genuine/pseudo vowel
|
||||
any(c_shifter) any(v_combo_N) U+17C6 U+17D2 any(subcons) > context(4) context(5) context(1) context(2) context(3) c after a two-part vowel
|
||||
any(c_shifter) any(v_combo_R) U+17C7 U+17D2 any(subcons) > context(4) context(5) context(1) context(2) context(3) c after a two-part vowel
|
||||
|
||||
c Case #2: when [D2+9A] is typed before a subscript, it should be moved to after it.
|
||||
|
||||
U+17D2 U+178A U+17D2 U+179A > context(1) U+178F context(3) context(4) c change subscript ្ដ to ្ត after ្រ
|
||||
U+17D2 U+179A U+17D2 U+178A > context(3) U+178F context(1) context(2) c ្ដ placed after ្រ has to be changed to ្ត and placed before ្រ
|
||||
|
||||
U+17D2 U+178A any(v_any) U+17D2 U+179A > context(1) U+178F context(4) context(5) context(3) c fixed 6e
|
||||
U+17D2 U+178A any(v_combo_N) U+17C6 U+17D2 U+179A > context(1) U+178F context(5) context(6) context(3) context(4)
|
||||
U+17D2 U+178A any(v_combo_R) U+17C7 U+17D2 U+179A > context(1) U+178F context(5) context(6) context(3) context(4)
|
||||
|
||||
U+17D2 U+179A any(v_any) U+17D2 U+178A > context(1) U+178F context(4) context(2) context(3) c fixed 6g
|
||||
U+17D2 U+179A any(v_combo_N) U+17C6 U+17D2 U+178A > context(1) U+178F context(5) context(2) context(3) context(4)
|
||||
U+17D2 U+179A any(v_combo_R) U+17C7 U+17D2 U+178A > context(1) U+178F context(5) context(2) context(3) context(4)
|
||||
|
||||
U+17D2 U+179A any(c_shifter) U+17D2 any(subcons) > context(4) context(5) context(1) context(2) context(3) c when a shifter intervenes, move it to the end.
|
||||
U+17D2 U+179A U+17D2 any(subcons) > context(3) context(4) context(1) context(2) c move any subscript placed after [D2+DA] to before them
|
||||
U+17D2 U+179A any(v_any) U+17D2 any(subcons) > context(4) context(5) context(1) context(2) context(3) c when a vowel intervenes, move it to the end
|
||||
U+17D2 U+179A any(v_combo_N) U+17C6 U+17D2 any(subcons) > context(5) context(6) context(1) context(2) context(3) context(4) c when a two-part vowel intervenes, move it to the end too.
|
||||
U+17D2 U+179A any(v_combo_R) U+17C7 U+17D2 any(subcons) > context(5) context(6) context(1) context(2) context(3) context(4) c (same as stated right above)
|
||||
|
||||
c when a subscript is placed after a consonant shifter, they should be reversed. (Case #3)
|
||||
|
||||
any(c_shifter) U+17D2 any(subcons) > context(2) context(3) context(1)
|
||||
|
||||
c Reordering - Triisap and Muusikatoan store before a vowel and a vowelcomboR and pseudo vowel.
|
||||
|
||||
any(v_any) any(c_shifter) > context(2) context(1) c place either a enguine or pseudo vowel after a consonant shifter
|
||||
any(v_gen) any(v_pseudo) any(c_shifter) > context(3) context(1) context(2) c place a two-part vowel after a consonant shifter(i.e. មោះ៉ )
|
||||
any(c_shifter) any(v_any) any(c_shifter) > context(3) context(2) c when either a genuine or pseudo vowel is in between two consonant shifters, replace the one on the left with the one on the right.
|
||||
any(c_shifter) any(v_gen) any(v_pseudo) any(c_shifter) > context(2) context(3) context(4) c when a two-part vowel is in between two consonants shifter, replace the one on the left with the one the right.
|
||||
|
||||
c +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
c + when [BB] is place either before or after an above vowel (ិ ី ឹ ឺ ើ and ាំ) and a Samyok Sannya (Case #4) +
|
||||
c + the [BB] should transform to a respective consonant shifter placed before the vowel. +
|
||||
c + the consonant shifter is a Trisap if the base consonant is ស ហ អ +
|
||||
c + the consonant shifter is a Muusikatoan if the base consonant is ង ញ ម យ រ វ ប and ន ល +
|
||||
c +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
c consonant clusters --1st > 2nd series (with U+17BB)
|
||||
|
||||
any(c_combo_QA) U+17D2 U+17A2 U+17BB any(v_above) > context(1) context(2) context(3) U+17CA context(5)
|
||||
any(c_combo_QA) U+17D2 U+17A2 U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6)
|
||||
any(c_combo_QA) U+17D2 U+17A2 any(v_above) U+17BB > context(1) context(2) context(3) U+17CA context(4)
|
||||
any(c_combo_QA) U+17D2 U+17A2 U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(6) context(7)
|
||||
|
||||
U+179B U+17D2 any(c_1st_combo_LO) U+17BB any(v_above) > context(1) context(2) context(3) U+17CA context(5)
|
||||
U+179B U+17D2 any(c_1st_combo_LO) U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6)
|
||||
U+179B U+17D2 any(c_1st_combo_LO) any(v_above) U+17BB > context(1) context(2) context(3) U+17CA context(4)
|
||||
U+179B U+17D2 any(c_1st_combo_LO) U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(6) context(7)
|
||||
|
||||
U+1798 U+17D2 any(c_1st_combo_MO) U+17BB any(v_above) > context(1) context(2) context(3) U+17CA context(5)
|
||||
U+1798 U+17D2 any(c_1st_combo_MO) U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6)
|
||||
U+1798 U+17D2 any(c_1st_combo_MO) any(v_above) U+17BB > context(1) context(2) context(3) U+17CA context(4)
|
||||
U+1798 U+17D2 any(c_1st_combo_MO) U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(6) context(7)
|
||||
|
||||
U+179F U+17D2 U+1794 U+17BB any(v_above) > context(1) context(2) context(3) U+17C9 context(5) c prevent ស្បុិ from transforming to ស្ប៊ិ, but produce ស្ប៉ិ instead because ប never have Triisap shifted down.
|
||||
U+179F U+17D2 U+1794 U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17C9 context(5) context(6)
|
||||
U+179F U+17D2 U+1794 any(v_above) U+17BB > context(1) context(2) context(3) U+17C9 context(4)
|
||||
U+179F U+17D2 U+1794 U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17C9 context(6) context(7)
|
||||
|
||||
U+179F U+17D2 any(c_combo_SA) U+17BB any(v_above) > context(1) context(2) context(3) U+17CA context(5)
|
||||
U+179F U+17D2 any(c_combo_SA) U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6)
|
||||
U+179F U+17D2 any(c_combo_SA) any(v_above) U+17BB > context(1) context(2) context(3) U+17CA context(4)
|
||||
U+179F U+17D2 any(c_combo_SA) U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(6) context(7)
|
||||
|
||||
any(c_combo_HA) U+17D2 U+17A0 U+17BB any(v_above) > context(1) context(2) context(3) U+17CA context(5)
|
||||
any(c_combo_HA) U+17D2 U+17A0 U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6)
|
||||
any(c_combo_HA) U+17D2 U+17A0 any(v_above) U+17BB > context(1) context(2) context(3) U+17CA context(4)
|
||||
any(c_combo_HA) U+17D2 U+17A0 U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(6) context(7)
|
||||
|
||||
U+17A2 U+17D2 U+1784 U+17BB any(v_above) > context(1) context(2) context(3) U+17CA context(5)
|
||||
U+17A2 U+17D2 U+1784 U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6)
|
||||
U+17A2 U+17D2 U+1784 any(v_above) U+17BB > context(1) context(2) context(3) U+17CA context(4)
|
||||
U+17A2 U+17D2 U+1784 U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(6) context(7)
|
||||
|
||||
U+17A2 U+17D2 U+179C U+17BB any(v_above) > context(1) context(2) context(3) U+17CA context(5)
|
||||
U+17A2 U+17D2 U+179C U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6)
|
||||
U+17A2 U+17D2 U+179C any(v_above) U+17BB > context(1) context(2) context(3) U+17CA context(4)
|
||||
U+17A2 U+17D2 U+179C U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(6) context(7)
|
||||
|
||||
U+17A0 U+17D2 U+1794 U+17BB any(v_above) > context(1) context(2) context(3) U+17C9 context(5) c change U+17BB preceded by HA and coeng BA to U+17C9 before the above vowel
|
||||
U+17A0 U+17D2 U+1794 U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17C9 context(3) context(6) c change U+17BB preceded by HA and coeng BA to U+17C9 before ាំ
|
||||
U+17A0 U+17D2 U+1794 any(v_above) U+17BB > context(1) context(2) context(3) U+17C9 context(4) c change U+17BB preceded by HA and coeng BA to U+17C9 before the above vowel
|
||||
U+17A0 U+17D2 U+1794 U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17C9 context(6) context(7) c change U+17BB preceded by HA and coeng BA to U+17C9 before U+17B6 U+17C6
|
||||
|
||||
|
||||
U+17A0 U+17D2 any(shiftable_c_2nd_with_BA) U+17BB any(v_above) > context(1) context(2) context(3) U+17CA context(5) c change U+17BB preceded by HA and coeng shiftable_c_2nd to U+17CA before the above vowel
|
||||
U+17A0 U+17D2 any(shiftable_c_2nd_with_BA) U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(3) context(6) c change U+17BB preceded by HA and coeng shiftable_c_2nd to U+17CA before ាំ
|
||||
U+17A0 U+17D2 any(shiftable_c_2nd_with_BA) any(v_above) U+17BB > context(1) context(2) context(3) U+17CA context(4) c change U+17BB preceded by HA and coeng shiftable_c_2nd to U+17CA before the above vowel
|
||||
U+17A0 U+17D2 any(shiftable_c_2nd_with_BA) U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(6) context(7) c change U+17BB preceded by HA and coeng shiftable_c_2nd to U+17CA before U+17B6 U+17C6
|
||||
|
||||
c consonant clusters --2nd > 1st series (with U+17BB)
|
||||
|
||||
U+179B U+17D2 any(c_2nd_combo_LO) U+17BB any(v_above) > context(1) context(2) context(3) U+17C9 context(5)
|
||||
U+179B U+17D2 any(c_2nd_combo_LO) U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17C9 context(5) context(6)
|
||||
U+179B U+17D2 any(c_2nd_combo_LO) any(v_above) U+17BB > context(1) context(2) context(3) U+17C9 context(4)
|
||||
U+179B U+17D2 any(c_2nd_combo_LO) U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17C9 context(6) context(7)
|
||||
|
||||
U+1798 U+17D2 any(c_2nd_combo_MO) U+17BB any(v_above) > context(1) context(2) context(3) U+17C9 context(5)
|
||||
U+1798 U+17D2 any(c_2nd_combo_MO) U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17C9 context(5) context(6)
|
||||
U+1798 U+17D2 any(c_2nd_combo_MO) any(v_above) U+17BB > context(1) context(2) context(3) U+17C9 context(4)
|
||||
U+1798 U+17D2 any(c_2nd_combo_MO) U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17C9 context(6) context(7)
|
||||
|
||||
c single consonants --1st > 2nd series (with U+17BB)
|
||||
|
||||
any(shiftable_c_1st) U+17BB any(v_above) > context(1) U+17CA context(3) c change U+17BB to U+17CA before the above vowel
|
||||
any(shiftable_c_1st) U+17BB U+17B6 U+17C6 > context(1) U+17CA context(3) context(4) c change U+17BB to U+17CA before ាំ
|
||||
any(shiftable_c_1st) any(v_above) U+17BB > context(1) U+17CA context(2) c change U+17BB to U+17CA and place it before the above vowel
|
||||
any(shiftable_c_1st) U+17BB U+17C6 U+17B6 U+17C6 > context(1) U+17CA context(4) context(5) c change U+17BB U+17C6 to U+17CA
|
||||
|
||||
c single consonants --2nd > 1st series (with U+17BB)
|
||||
|
||||
any(shiftable_c_2nd_with_BA) U+17BB any(v_above) > context(1) U+17C9 context(3) c change U+17BB to U+17C9 before the above vowel
|
||||
any(shiftable_c_2nd_with_BA) U+17BB U+17B6 U+17C6 > context(1) U+17C9 context(3) context(4) c change U+17BB to U+17C9 before ាំ
|
||||
any(shiftable_c_2nd_with_BA) any(v_above) U+17BB > context(1) U+17C9 context(2) c change U+17BB to U+17C9 before the above vowel
|
||||
any(shiftable_c_2nd_with_BA) U+17BB U+17C6 U+17B6 U+17C6 > context(1) U+17C9 context(4) context(5) c change U+17BB U+17C6 to U+17C9
|
||||
|
||||
c prevent incorrect use of consonant shifter with 2nd series consonant clusters (without U+17BB)
|
||||
|
||||
U+179B U+17D2 any(c_2nd_combo_LO) U+17CA any(v_above) > context(1) context(2) context(3) U+17C9 context(5)
|
||||
U+1798 U+17D2 any(c_2nd_combo_MO) U+17CA any(v_above) > context(1) context(2) context(3) U+17C9 context(5)
|
||||
U+179B U+17D2 any(c_2nd_combo_LO) U+17CA any(v_gen) any(v_pseudo) > context(1) context(2) context(3) U+17C9 context(5) context(6)
|
||||
U+1798 U+17D2 any(c_2nd_combo_MO) U+17CA any(v_gen) any(v_pseudo) > context(1) context(2) context(3) U+17C9 context(5) context(6)
|
||||
|
||||
c single consonants --2nd > 1st series (without U+17BB)
|
||||
|
||||
any(shiftable_c_2nd) U+17CA any(v_above) > context(1) U+17C9 context(3) c change U+17CA to U+17C9 before the above vowel
|
||||
any(shiftable_c_2nd) U+17CA any(v_gen) any(v_pseudo) > context(1) U+17C9 context(3) context(4) c change U+17CA to U+17C9 before ាំ
|
||||
|
||||
U+17D2 any(shiftable_c_2nd) U+17CA any(v_above) > context c stop ស្រ៊ី from becoming ស្រ៉ី
|
||||
U+17D2 any(shiftable_c_2nd) U+17CA any(v_gen) any(v_pseudo) > context
|
||||
|
||||
c SPECIAL CASE -- the following clusters may accept either of the two consonant shifters.
|
||||
|
||||
U+1794 U+17D2 U+1799 any(c_shifter) > context
|
||||
U+179F U+17D2 U+1794 any(c_shifter) > context
|
||||
U+1786 U+17D2 U+1794 any(c_shifter) > context
|
||||
U+1794 U+17D2 U+1799 any(c_shifter) > context
|
||||
U+179F U+17D2 U+1794 any(c_shifter) > context
|
||||
U+1786 U+17D2 U+1794 any(c_shifter) > context
|
||||
|
||||
c single --1st > 2nd series (without U+17BB)
|
||||
|
||||
any(shiftable_c_1st) U+17C9 any(v_above) > context(1) U+17CA context(3) c change U+17C9 to U+17CA before the above vowel
|
||||
any(shiftable_c_1st) U+17C9 any(v_gen) any(v_pseudo) > context(1) U+17CA context(3) context(4) c change U+17C9 to U+17CA before ាំ
|
||||
|
||||
c consonant clusters --1st > 2nd series (without U+17BB)
|
||||
|
||||
any(c_combo_QA) U+17D2 U+17A2 U+17C9 any(v_above) > context(1) context(2) context(3) U+17CA context(5)
|
||||
U+179B U+17D2 any(c_1st_combo_LO) U+17C9 any(v_above) > context(1) context(2) context(3) U+17CA context(5)
|
||||
U+1798 U+17D2 any(c_1st_combo_MO) U+17C9 any(v_above) > context(1) context(2) context(3) U+17CA context(5)
|
||||
U+179F U+17D2 U+1794 U+17C9 any(v_above) > context(1) context(2) context(3) U+17C9 context(5) c prevent ស្ប៉ី from transforming to ស្ប៊ី
|
||||
U+179F U+17D2 any(c_combo_SA) U+17C9 any(v_above) > context(1) context(2) context(3) U+17CA context(5)
|
||||
any(c_combo_HA) U+17D2 U+17A0 U+17C9 any(v_above) > context(1) context(2) context(3) U+17CA context(5)
|
||||
U+17A2 U+17D2 U+1784 U+17C9 any(v_above) > context(1) context(2) context(3) U+17CA context(5)
|
||||
U+17A2 U+17D2 U+179C U+17C9 any(v_above) > context(1) context(2) context(3) U+17CA context(5)
|
||||
any(c_combo_QA) U+17D2 U+17A2 U+17C9 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6)
|
||||
U+179B U+17D2 any(c_1st_combo_LO) U+17C9 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6)
|
||||
U+1798 U+17D2 any(c_1st_combo_MO) U+17C9 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6)
|
||||
U+179F U+17D2 U+1794 U+17C9 U+17B6 U+17C6 > context(1) context(2) context(3) U+17C9 context(5) context(6) c prevent ស្ប៉ាំ from transforming to ស្ប៊ាំ
|
||||
U+179F U+17D2 any(c_combo_SA) U+17C9 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6)
|
||||
any(c_combo_HA) U+17D2 U+17A0 U+17C9 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6)
|
||||
U+17A2 U+17D2 U+1784 U+17C9 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6)
|
||||
U+17A2 U+17D2 U+179C U+17C9 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6)
|
||||
|
||||
c U+17B6 U+17BB and U+17C6 in that order preceeded by any first series consonant (cluster) are transformed to U+17CA U+17B6 and U+17C6
|
||||
|
||||
any(shiftable_c_1st) U+17B6 U+17BB U+17C6 > context(1) U+17CA context(2) context(4)
|
||||
any(shiftable_c_1st) U+17BB U+17C6 U+17B6 > context(1) U+17CA context(4) context(3)
|
||||
|
||||
any(c_combo_QA) U+17D2 U+17A2 U+17B6 U+17BB U+17C6 > context(1) context(2) context(3) U+17CA context(4) context(6)
|
||||
any(c_combo_QA) U+17D2 U+17A2 U+17BB U+17C6 U+17B6 > context(1) context(2) context(3) U+17CA context(6) context(5)
|
||||
|
||||
U+179B U+17D2 any(c_1st_combo_LO) U+17B6 U+17BB U+17C6 > context(1) context(2) context(3) U+17CA context(4) context(6)
|
||||
U+179B U+17D2 any(c_1st_combo_LO) U+17BB U+17C6 U+17B6 > context(1) context(2) context(3) U+17CA context(6) context(5)
|
||||
|
||||
U+1798 U+17D2 any(c_1st_combo_MO) U+17B6 U+17BB U+17C6 > context(1) context(2) context(3) U+17CA context(4) context(6)
|
||||
U+1798 U+17D2 any(c_1st_combo_MO) U+17BB U+17C6 U+17B6 > context(1) context(2) context(3) U+17CA context(6) context(5)
|
||||
|
||||
U+179F U+17D2 any(c_combo_SA) U+17B6 U+17BB U+17C6 > context(1) context(2) context(3) U+17CA context(4) context(6)
|
||||
U+179F U+17D2 any(c_combo_SA) U+17BB U+17C6 U+17B6 > context(1) context(2) context(3) U+17CA context(6) context(5)
|
||||
|
||||
any(c_combo_HA) U+17D2 U+17A0 U+17B6 U+17BB U+17C6 > context(1) context(2) context(3) U+17CA context(4) context(6)
|
||||
any(c_combo_HA) U+17D2 U+17A0 U+17BB U+17C6 U+17B6 > context(1) context(2) context(3) U+17CA context(6) context(5)
|
||||
|
||||
U+17A2 U+17D2 U+1784 U+17B6 U+17BB U+17C6 > context(1) context(2) context(3) U+17CA context(4) context(6)
|
||||
U+17A2 U+17D2 U+1784 U+17BB U+17C6 U+17B6 > context(1) context(2) context(3) U+17CA context(6) context(5)
|
||||
|
||||
U+17A2 U+17D2 U+179C U+17B6 U+17BB U+17C6 > context(1) context(2) context(3) U+17CA context(4) context(6)
|
||||
U+17A2 U+17D2 U+179C U+17BB U+17C6 U+17B6 > context(1) context(2) context(3) U+17CA context(4) context(6)
|
||||
|
||||
c U+17B6 U+17BB and U+17C6 in that order preceeded by any second series consonant (cluster) are transformed to U+17C9 U+17B6 and U+17C6
|
||||
|
||||
any(shiftable_c_2nd_with_BA) U+17B6 U+17BB U+17C6 > context(1) U+17C9 context(2) context(4)
|
||||
any(shiftable_c_2nd_with_BA) U+17BB U+17C6 U+17B6 > context(1) U+17C9 context(4) context(3)
|
||||
|
||||
U+179B U+17D2 any(c_2nd_combo_LO) U+17B6 U+17BB U+17C6 > context(1) context(2) context(3) U+17C9 context(4) context(6)
|
||||
U+179B U+17D2 any(c_2nd_combo_LO) U+17BB U+17C6 U+17B6 > context(1) context(2) context(3) U+17C9 context(6) context(5)
|
||||
|
||||
U+1798 U+17D2 any(c_2nd_combo_MO) U+17B6 U+17BB U+17C6 > context(1) context(2) context(3) U+17C9 context(4) context(6)
|
||||
U+1798 U+17D2 any(c_2nd_combo_MO) U+17BB U+17C6 U+17B6 > context(1) context(2) context(3) U+17C9 context(6) context(5)
|
||||
|
||||
c េុី/ុេី/៉េី > ៊ើ
|
||||
|
||||
any(shiftable_c_1st) U+17C1 U+17BB U+17B8 > context(1) U+17CA U+17BE c cancel out by vowel rotation
|
||||
any(shiftable_c_1st) U+17BB U+17C1 U+17B8 > context(1) U+17CA U+17BE c cancel out by vowel rotation
|
||||
any(shiftable_c_1st) U+17C9 U+17C1 U+17B8 > context(1) U+17CA U+17BE
|
||||
|
||||
any(c_combo_QA) U+17D2 U+17A2 U+17C1 U+17BB U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation
|
||||
any(c_combo_QA) U+17D2 U+17A2 U+17BB U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation
|
||||
any(c_combo_QA) U+17D2 U+17A2 U+17C9 U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE
|
||||
|
||||
U+179B U+17D2 any(c_1st_combo_LO) U+17C1 U+17BB U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation
|
||||
U+179B U+17D2 any(c_1st_combo_LO) U+17BB U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation
|
||||
U+179B U+17D2 any(c_1st_combo_LO) U+17C9 U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE
|
||||
|
||||
U+1798 U+17D2 any(c_1st_combo_MO) U+17C1 U+17BB U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation
|
||||
U+1798 U+17D2 any(c_1st_combo_MO) U+17BB U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation
|
||||
U+1798 U+17D2 any(c_1st_combo_MO) U+17C9 U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE
|
||||
|
||||
U+179F U+17D2 any(c_combo_SA) U+17C1 U+17BB U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation
|
||||
U+179F U+17D2 any(c_combo_SA) U+17BB U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation
|
||||
U+179F U+17D2 any(c_combo_SA) U+17C9 U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE
|
||||
|
||||
any(c_combo_HA) U+17D2 U+17A0 U+17C1 U+17BB U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation
|
||||
any(c_combo_HA) U+17D2 U+17A0 U+17BB U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation
|
||||
any(c_combo_HA) U+17D2 U+17A0 U+17C9 U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE
|
||||
|
||||
U+17A2 U+17D2 U+1784 U+17C1 U+17BB U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation
|
||||
U+17A2 U+17D2 U+1784 U+17BB U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation
|
||||
U+17A2 U+17D2 U+1784 U+17C9 U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE
|
||||
|
||||
U+17A2 U+17D2 U+179C U+17C1 U+17BB U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation
|
||||
U+17A2 U+17D2 U+179C U+17BB U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation
|
||||
U+17A2 U+17D2 U+179C U+17C9 U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE
|
||||
|
||||
c េុី/ុេី/៊េី > ៉ើ
|
||||
|
||||
any(shiftable_c_2nd) U+17C1 U+17BB U+17B8 > context(1) U+17C9 U+17BE c cancel out by vowel rotation
|
||||
any(shiftable_c_2nd) U+17BB U+17C1 U+17B8 > context(1) U+17C9 U+17BE c cancel out by vowel rotation
|
||||
any(shiftable_c_2nd) U+17CA U+17C1 U+17B8 > context(1) U+17C9 U+17BE
|
||||
|
||||
U+179B U+17D2 any(c_2nd_combo_LO) U+17C1 U+17BB U+17B8 > context(1) context(2) context(3) U+17C9 U+17BE c cancel out by vowel rotation
|
||||
U+179B U+17D2 any(c_2nd_combo_LO) U+17BB U+17C1 U+17B8 > context(1) context(2) context(3) U+17C9 U+17BE c cancel out by vowel rotation
|
||||
U+179B U+17D2 any(c_2nd_combo_LO) U+17CA U+17C1 U+17B8 > context(1) context(2) context(3) U+17C9 U+17BE
|
||||
|
||||
U+1798 U+17D2 any(c_2nd_combo_MO) U+17C1 U+17BB U+17B8 > context(1) context(2) context(3) U+17C9 U+17BE c cancel out by vowel rotation
|
||||
U+1798 U+17D2 any(c_2nd_combo_MO) U+17BB U+17C1 U+17B8 > context(1) context(2) context(3) U+17C9 U+17BE c cancel out by vowel rotation
|
||||
U+1798 U+17D2 any(c_2nd_combo_MO) U+17CA U+17C1 U+17B8 > context(1) context(2) context(3) U+17C9 U+17BE
|
||||
|
||||
c place Robat after a base before any vowel
|
||||
|
||||
any(c_out) any(v_gen) U+17CC > context(1) context(3) context(2)
|
||||
|
||||
c Use appropriate identical subscript in two separate contexts. (Case #8)
|
||||
|
||||
U+178E U+17D2 U+178F > context(1) context(2) U+178A
|
||||
U+1793 U+17D2 U+178A > context(1) context(2) U+178F
|
||||
|
||||
c BONUSES(note that these combinations are invalid and they can't be found in the CN dictionary 1967 nor RH 1997, but users think they are)
|
||||
|
||||
U+1791 U+17D2 U+1794 > U+17A1 c ទ្ប transforms to ឡ
|
||||
|
||||
U+1794 U+17D2 U+1789 > U+17AB c ប្ញ transforms to ឫ
|
||||
U+17AB U+17BB > U+17AC c ឫុ transforms to ឬ
|
||||
|
||||
U+17AD U+17B6 > U+1789 c ឭា transforms to ញ
|
||||
U+17AE U+17B6 > U+1789 c ឮា transforms to ញ
|
||||
|
||||
U+1796 U+17D2 U+1789 > U+17AD c ព្ញ transforms to ឭ
|
||||
U+17AD U+17BB > U+17AE c ឭុ transforms to ឮ
|
||||
|
||||
U+1796 U+17D2 U+178B > U+17B0 c ព្ឋ transforms to ឰ
|
||||
|
||||
U+17A7 U+17B7 > U+17B1 c ឧិ transforms to ឱ
|
||||
U+17A7 U+17CC > U+17B1 c ឧ៌ transforms to ឱ
|
||||
U+17A7 U+17CD > U+17B1 c ឧ៍ transforms to ឱ
|
||||
|
||||
c U+17D4 U+179B U+17D4 > U+17D8 c ។ល។ transforms to U+17D8
|
||||
|
||||
U+178A U+17D2 U+1792 > U+178A U+17D2 U+178B c ដ្ធ > ដ្ឋ
|
||||
U+1791 U+17D2 U+178B > U+1791 U+17D2 U+1792 c ទ្ឋ > ទ្ធ
|
||||
|
||||
c additional rules
|
||||
|
||||
U+1796 U+1793 U+17D2 U+178B > context(1) context(2) context(3) U+1792 c ពន្ឋ > ពន្ធ
|
||||
U+1796 U+17D0 U+1793 U+17D2 U+178B > context(1) context(2) context(3) context(4) U+1792 c ព័ន្ឋ > ព័ន្ធ
|
||||
|
||||
|
||||
U+17AA U+17D2 U+1799 > U+17B1 context(2) context(3) c ឪ្យ > ឱ្យ
|
||||
U+17B3 U+17D2 U+1799 > U+17B1 context(2) context(3) c ឳ្យ > ឱ្យ
|
||||
|
||||
U+1789 U+17D2 U+179C > U+1796 context(2) context(3) U+17B6 c ញ្វ (as in សញ្វវុធ) > ព្វា as in សញ្វវុធ
|
||||
|
||||
U+17D2 U+1799 U+17C1 U+17BA > U+17BF c េ្យឺ > ឿ
|
||||
U+17D2 U+1799 U+17C1 U+17B9 > U+17BF c េ្យឹ > ឿ
|
||||
U+17D2 U+1799 U+17C1 U+17B8 > U+17BF c េ្យី > ឿ
|
||||
|
||||
U+17D2 U+1799 U+17D2 any(c_out) U+17C1 U+17BA > context(3) context(4) U+17BF c គ្រេ្យឺង > គ្រឿង
|
||||
U+17D2 U+1799 U+17D2 any(c_out) U+17C1 U+17B9 > context(3) context(4) U+17BF c គ្រេ្យឹង > គ្រឿង
|
||||
U+17D2 U+1799 U+17D2 any(c_out) U+17C1 U+17B8 > context(3) context(4) U+17BF c គ្រេ្យីង > គ្រឿង
|
||||
|
||||
c In everyday practice, both 'regular space' and 'no-break space' are not used before punctuation, i.e. ។ ! etc.
|
||||
c An annoying issue of having line broken up at the end of the line dropping the punctuation (។, ! and also ៗ) to the next line.
|
||||
c It may be helpful to include a rule where a 'Zero Width No-Break Space' should be output together with those punct.
|
||||
c ref: https://www.unicode.org/L2/L2020/20008-core-text.pdf
|
||||
c ref: https://www.unicode.org/versions/Unicode12.0.0/ch23.pdf#G12985
|
||||
c ref: https://www.compart.com/en/unicode/U+FEFF
|
||||
|
||||
c EOF
|
||||
206
developer/src/kmc-kmw/test/fixtures/khmer_angkor.kvks
vendored
Normal file
206
developer/src/kmc-kmw/test/fixtures/khmer_angkor.kvks
vendored
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<visualkeyboard>
|
||||
<header>
|
||||
<version>10.0</version>
|
||||
<kbdname>khmer_angkor</kbdname>
|
||||
<flags>
|
||||
<usealtgr/>
|
||||
</flags>
|
||||
</header>
|
||||
<encoding name="unicode" fontname="Khmer Busra Kbd" fontsize="16">
|
||||
<layer shift="RA">
|
||||
<key vkey="K_B">ឞ</key>
|
||||
<key vkey="K_K">ឝ</key>
|
||||
<key vkey="K_QUOTE">ៈ</key>
|
||||
<key vkey="K_RBRKT">ឳ</key>
|
||||
<key vkey="K_T">ឨ</key>
|
||||
<key vkey="K_LBRKT">ឩ</key>
|
||||
<key vkey="K_P">ឰ</key>
|
||||
<key vkey="K_R">ឫ</key>
|
||||
<key vkey="K_I">ឦ</key>
|
||||
<key vkey="K_O">ឱ</key>
|
||||
<key vkey="K_E">ឯ</key>
|
||||
<key vkey="K_3"></key>
|
||||
<key vkey="K_W"></key>
|
||||
<key vkey="K_Q">ៜ</key>
|
||||
<key vkey="K_EQUAL"></key>
|
||||
<key vkey="K_COLON">៖</key>
|
||||
<key vkey="K_6">៙</key>
|
||||
<key vkey="K_7">៚</key>
|
||||
<key vkey="K_M"></key>
|
||||
<key vkey="K_L">៘</key>
|
||||
<key vkey="K_1"></key>
|
||||
<key vkey="K_BKQUOTE"></key>
|
||||
<key vkey="K_U">]</key>
|
||||
<key vkey="K_Y">[</key>
|
||||
<key vkey="K_SLASH">/</key>
|
||||
<key vkey="K_PERIOD">.</key>
|
||||
<key vkey="K_H">‘</key>
|
||||
<key vkey="K_A">+</key>
|
||||
<key vkey="K_V">&</key>
|
||||
<key vkey="K_J">’</key>
|
||||
<key vkey="K_8">*</key>
|
||||
<key vkey="K_2">@</key>
|
||||
<key vkey="K_BKSLASH">\</key>
|
||||
<key vkey="K_0">}</key>
|
||||
<key vkey="K_9">{</key>
|
||||
<key vkey="K_S">-</key>
|
||||
<key vkey="K_F">÷</key>
|
||||
<key vkey="K_G">:</key>
|
||||
<key vkey="K_COMMA">,</key>
|
||||
<key vkey="K_HYPHEN">≈</key>
|
||||
<key vkey="K_N">;</key>
|
||||
<key vkey="K_Z"><</key>
|
||||
<key vkey="K_C">#</key>
|
||||
<key vkey="K_X">></key>
|
||||
<key vkey="K_D">×</key>
|
||||
<key vkey="K_4">$</key>
|
||||
<key vkey="K_5">€</key>
|
||||
<key vkey="K_SPACE"> </key>
|
||||
</layer>
|
||||
<layer shift="SRA">
|
||||
<key vkey="K_8">៸</key>
|
||||
<key vkey="K_0">៰</key>
|
||||
<key vkey="K_1">៱</key>
|
||||
<key vkey="K_2">៲</key>
|
||||
<key vkey="K_3">៳</key>
|
||||
<key vkey="K_4">៴</key>
|
||||
<key vkey="K_5">៵</key>
|
||||
<key vkey="K_6">៶</key>
|
||||
<key vkey="K_7">៷</key>
|
||||
<key vkey="K_9">៹</key>
|
||||
<key vkey="K_PERIOD">᧿</key>
|
||||
<key vkey="K_COMMA">᧾</key>
|
||||
<key vkey="K_LBRKT">᧪</key>
|
||||
<key vkey="K_RBRKT">᧫</key>
|
||||
<key vkey="K_QUOTE">᧶</key>
|
||||
<key vkey="K_COLON">᧵</key>
|
||||
<key vkey="K_A">᧬</key>
|
||||
<key vkey="K_Z">᧷</key>
|
||||
<key vkey="K_Y">᧥</key>
|
||||
<key vkey="K_X">᧸</key>
|
||||
<key vkey="K_W">᧡</key>
|
||||
<key vkey="K_B">᧻</key>
|
||||
<key vkey="K_C">᧹</key>
|
||||
<key vkey="K_D">᧮</key>
|
||||
<key vkey="K_E">᧢</key>
|
||||
<key vkey="K_F">᧯</key>
|
||||
<key vkey="K_G">᧰</key>
|
||||
<key vkey="K_U">᧦</key>
|
||||
<key vkey="K_H">᧱</key>
|
||||
<key vkey="K_T">᧤</key>
|
||||
<key vkey="K_S">᧭</key>
|
||||
<key vkey="K_R">᧣</key>
|
||||
<key vkey="K_I">᧧</key>
|
||||
<key vkey="K_Q">᧠</key>
|
||||
<key vkey="K_V">᧺</key>
|
||||
<key vkey="K_J">᧲</key>
|
||||
<key vkey="K_K">᧳</key>
|
||||
<key vkey="K_L">᧴</key>
|
||||
<key vkey="K_P">᧩</key>
|
||||
<key vkey="K_O">᧨</key>
|
||||
<key vkey="K_N">᧼</key>
|
||||
<key vkey="K_M">᧽</key>
|
||||
</layer>
|
||||
<layer shift="">
|
||||
<key vkey="K_SPACE"></key>
|
||||
<key vkey="K_QUOTE"></key>
|
||||
<key vkey="K_COMMA"></key>
|
||||
<key vkey="K_HYPHEN">ឥ</key>
|
||||
<key vkey="K_PERIOD">។</key>
|
||||
<key vkey="K_SLASH"></key>
|
||||
<key vkey="K_0">០</key>
|
||||
<key vkey="K_1">១</key>
|
||||
<key vkey="K_2">២</key>
|
||||
<key vkey="K_3">៣</key>
|
||||
<key vkey="K_4">៤</key>
|
||||
<key vkey="K_5">៥</key>
|
||||
<key vkey="K_6">៦</key>
|
||||
<key vkey="K_7">៧</key>
|
||||
<key vkey="K_8">៨</key>
|
||||
<key vkey="K_9">៩</key>
|
||||
<key vkey="K_COLON"></key>
|
||||
<key vkey="K_EQUAL">ឲ</key>
|
||||
<key vkey="K_LBRKT"></key>
|
||||
<key vkey="K_BKSLASH">ឮ</key>
|
||||
<key vkey="K_RBRKT">ឪ</key>
|
||||
<key vkey="K_BKQUOTE">«</key>
|
||||
<key vkey="K_A"></key>
|
||||
<key vkey="K_B">ប</key>
|
||||
<key vkey="K_C">ច</key>
|
||||
<key vkey="K_D">ដ</key>
|
||||
<key vkey="K_E"></key>
|
||||
<key vkey="K_F">ថ</key>
|
||||
<key vkey="K_G">ង</key>
|
||||
<key vkey="K_H">ហ</key>
|
||||
<key vkey="K_I"></key>
|
||||
<key vkey="K_J"></key>
|
||||
<key vkey="K_K">ក</key>
|
||||
<key vkey="K_L">ល</key>
|
||||
<key vkey="K_M">ម</key>
|
||||
<key vkey="K_N">ន</key>
|
||||
<key vkey="K_O"></key>
|
||||
<key vkey="K_P">ផ</key>
|
||||
<key vkey="K_Q">ឆ</key>
|
||||
<key vkey="K_R">រ</key>
|
||||
<key vkey="K_S">ស</key>
|
||||
<key vkey="K_T">ត</key>
|
||||
<key vkey="K_U"></key>
|
||||
<key vkey="K_V">វ</key>
|
||||
<key vkey="K_W"></key>
|
||||
<key vkey="K_X">ខ</key>
|
||||
<key vkey="K_Y">យ</key>
|
||||
<key vkey="K_Z">ឋ</key>
|
||||
</layer>
|
||||
<layer shift="S">
|
||||
<key vkey="K_SPACE"></key>
|
||||
<key vkey="K_1">!</key>
|
||||
<key vkey="K_QUOTE"></key>
|
||||
<key vkey="K_3">"</key>
|
||||
<key vkey="K_4">៛</key>
|
||||
<key vkey="K_5">%</key>
|
||||
<key vkey="K_7"></key>
|
||||
<key vkey="K_9">(</key>
|
||||
<key vkey="K_0">)</key>
|
||||
<key vkey="K_8"></key>
|
||||
<key vkey="K_EQUAL">=</key>
|
||||
<key vkey="K_COLON"></key>
|
||||
<key vkey="K_PERIOD">៕</key>
|
||||
<key vkey="K_SLASH">?</key>
|
||||
<key vkey="K_2">ៗ</key>
|
||||
<key vkey="K_A"></key>
|
||||
<key vkey="K_B">ព</key>
|
||||
<key vkey="K_C">ជ</key>
|
||||
<key vkey="K_D">ឌ</key>
|
||||
<key vkey="K_E"></key>
|
||||
<key vkey="K_F">ធ</key>
|
||||
<key vkey="K_G">អ</key>
|
||||
<key vkey="K_H">ះ</key>
|
||||
<key vkey="K_I"></key>
|
||||
<key vkey="K_J">ញ</key>
|
||||
<key vkey="K_K">គ</key>
|
||||
<key vkey="K_L">ឡ</key>
|
||||
<key vkey="K_M"></key>
|
||||
<key vkey="K_N">ណ</key>
|
||||
<key vkey="K_O"></key>
|
||||
<key vkey="K_P">ភ</key>
|
||||
<key vkey="K_Q">ឈ</key>
|
||||
<key vkey="K_R">ឬ</key>
|
||||
<key vkey="K_S"></key>
|
||||
<key vkey="K_T">ទ</key>
|
||||
<key vkey="K_U"></key>
|
||||
<key vkey="K_V"></key>
|
||||
<key vkey="K_W"></key>
|
||||
<key vkey="K_X">ឃ</key>
|
||||
<key vkey="K_Y"></key>
|
||||
<key vkey="K_Z">ឍ</key>
|
||||
<key vkey="K_6"></key>
|
||||
<key vkey="K_HYPHEN"></key>
|
||||
<key vkey="K_LBRKT"></key>
|
||||
<key vkey="K_BKSLASH">ឭ</key>
|
||||
<key vkey="K_RBRKT">ឧ</key>
|
||||
<key vkey="K_BKQUOTE">»</key>
|
||||
<key vkey="K_COMMA"></key>
|
||||
</layer>
|
||||
</encoding>
|
||||
</visualkeyboard>
|
||||
55
developer/src/kmc-kmw/test/test-compiler-manual.ts
Normal file
55
developer/src/kmc-kmw/test/test-compiler-manual.ts
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import { dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import fs from 'fs';
|
||||
import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers';
|
||||
import { KmnCompiler } from '@keymanapp/kmc-kmn';
|
||||
import { KMX, KmxFileReader } from '@keymanapp/common-types';
|
||||
import { WriteCompiledKeyboard } from '../src/compiler/write-compiled-keyboard.js';
|
||||
import { extractTouchLayout } from './util.js';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url)).replace(/\\/g, '/');
|
||||
const fixturesDir = __dirname + '/../../test/fixtures/';
|
||||
const fixtureName = fixturesDir + 'khmer_angkor.js';
|
||||
const infile = fixturesDir + 'khmer_angkor.kmn';
|
||||
const outfile = fixturesDir + 'khmer_angkor.kmx'; // intermediate outfile
|
||||
const testOutfile = fixturesDir + 'khmer_angkor.test.js';
|
||||
|
||||
if(fs.existsSync(testOutfile)) {
|
||||
fs.unlinkSync(testOutfile);
|
||||
}
|
||||
|
||||
const callbacks = new TestCompilerCallbacks();
|
||||
|
||||
const kmnCompiler = new KmnCompiler();
|
||||
if(!await kmnCompiler.init(callbacks)) {
|
||||
console.error('kmx compiler failed to init');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// TODO: runToMemory, add option to kmxCompiler to store debug-data for conversion to .js (e.g. store metadata, group readonly metadata, etc)
|
||||
if(!kmnCompiler.run(infile, outfile, {
|
||||
shouldAddCompilerVersion: false,
|
||||
saveDebug: true,
|
||||
target: 'js'
|
||||
})) {
|
||||
callbacks.printMessages();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const reader = new KmxFileReader();
|
||||
const keyboard: KMX.KEYBOARD = reader.read(callbacks.loadFile(outfile));
|
||||
|
||||
const js = WriteCompiledKeyboard(callbacks, infile, outfile, 'khmer_angkor', keyboard, true);
|
||||
|
||||
callbacks.printMessages();
|
||||
|
||||
const fjs = fs.readFileSync(fixtureName, 'utf8');
|
||||
|
||||
const expected = extractTouchLayout(fjs);
|
||||
const actual = extractTouchLayout(js);
|
||||
|
||||
if(expected.js !== actual.js) {
|
||||
fs.writeFileSync(testOutfile, js);
|
||||
console.error('JS not equal');
|
||||
process.exit(1);
|
||||
}
|
||||
65
developer/src/kmc-kmw/test/test-compiler.ts
Normal file
65
developer/src/kmc-kmw/test/test-compiler.ts
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import 'mocha';
|
||||
import { assert } from 'chai';
|
||||
// import sinonChai from 'sinon-chai';
|
||||
import { WriteCompiledKeyboard } from '../src/compiler/write-compiled-keyboard.js';
|
||||
import { dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import fs from 'fs';
|
||||
import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers';
|
||||
import { KmnCompiler } from '@keymanapp/kmc-kmn';
|
||||
import { KMX, KmxFileReader } from '@keymanapp/common-types';
|
||||
import { extractTouchLayout } from './util.js';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url)).replace(/\\/g, '/');
|
||||
const fixturesDir = __dirname + '/../../test/fixtures/';
|
||||
//const baselineDir = __dirname + '/../../../../../common/test/keyboards/baseline/';
|
||||
// chai.use(sinonChai);
|
||||
|
||||
describe('Compiler class', function() {
|
||||
const callbacks = new TestCompilerCallbacks();
|
||||
|
||||
this.afterEach(function() {
|
||||
callbacks.printMessages();
|
||||
callbacks.clear();
|
||||
});
|
||||
|
||||
it('should compile a basic keyboard', async function() {
|
||||
// const compiler = new KeymanWebCompiler(callbacks, {addCompilerVersion: false, debug: true});
|
||||
|
||||
const fixtureName = fixturesDir + 'khmer_angkor.js';
|
||||
const infile = fixturesDir + 'khmer_angkor.kmn';
|
||||
const outfile = fixturesDir + 'khmer_angkor.kmx'; // intermediate outfile
|
||||
const testOutfile = fixturesDir + 'khmer_angkor.test.js';
|
||||
|
||||
if(fs.existsSync(testOutfile)) {
|
||||
fs.unlinkSync(testOutfile);
|
||||
}
|
||||
|
||||
const kmnCompiler = new KmnCompiler();
|
||||
assert.isTrue(await kmnCompiler.init(callbacks));
|
||||
|
||||
// TODO: runToMemory, add option to kmxCompiler to store debug-data for conversion to .js (e.g. store metadata, group readonly metadata, visual keyboard source filename, etc)
|
||||
assert.isTrue(kmnCompiler.run(infile, outfile, {
|
||||
shouldAddCompilerVersion: false,
|
||||
saveDebug: true,
|
||||
target: 'js'
|
||||
}));
|
||||
|
||||
const reader = new KmxFileReader();
|
||||
const keyboard: KMX.KEYBOARD = reader.read(callbacks.loadFile(outfile));
|
||||
|
||||
const js = WriteCompiledKeyboard(callbacks, infile, outfile, 'khmer_angkor', keyboard, true);
|
||||
|
||||
const fjs = fs.readFileSync(fixtureName, 'utf8');
|
||||
|
||||
const expected = extractTouchLayout(fjs);
|
||||
const actual = extractTouchLayout(js);
|
||||
|
||||
fs.writeFileSync(testOutfile + '.strip.js', actual.js);
|
||||
fs.writeFileSync(fixtureName + '.strip.js', expected.js);
|
||||
fs.writeFileSync(testOutfile, js);
|
||||
|
||||
assert.deepEqual(actual.js, expected.js);
|
||||
assert.deepEqual(JSON.parse(actual.touchLayout), JSON.parse(expected.touchLayout));
|
||||
});
|
||||
});
|
||||
26
developer/src/kmc-kmw/test/tsconfig.json
Normal file
26
developer/src/kmc-kmw/test/tsconfig.json
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"extends": "../../kmc/tsconfig.kmc-base.json",
|
||||
|
||||
"compilerOptions": {
|
||||
"rootDir": ".",
|
||||
"rootDirs": ["./", "../src/"],
|
||||
"outDir": "../build/test",
|
||||
"baseUrl": ".",
|
||||
"allowSyntheticDefaultImports": true, // for chai
|
||||
"paths": {
|
||||
"@keymanapp/common-types": ["../../../../common/web/types/src/main"],
|
||||
"@keymanapp/developer-test-helpers": ["../../common/web/test-helpers/index"],
|
||||
"@keymanapp/kmc-kmn": ["../../kmc-kmn/src/main"],
|
||||
},
|
||||
},
|
||||
"include": [
|
||||
"**/test-*.ts",
|
||||
"util.ts"
|
||||
],
|
||||
"references": [
|
||||
{ "path": "../../../../common/web/types/" },
|
||||
{ "path": "../../kmc-kmn/" },
|
||||
{ "path": "../../common/web/test-helpers/" },
|
||||
{ "path": "../" }
|
||||
]
|
||||
}
|
||||
19
developer/src/kmc-kmw/test/util.ts
Normal file
19
developer/src/kmc-kmw/test/util.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
interface ETLResult {
|
||||
js: string;
|
||||
touchLayout: string;
|
||||
}
|
||||
|
||||
export function extractTouchLayout(js: string): ETLResult|null {
|
||||
let m = /KVKL=(?<kvkl>.+?);[\r\n]/ds.exec(js);
|
||||
if(!m) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let kvkl = (<any>m).indices.groups.kvkl;
|
||||
|
||||
return {
|
||||
js: js.substring(0, kvkl[0]) + 'null' + js.substring(kvkl[1]),
|
||||
touchLayout: m.groups?.['kvkl'] ?? ''
|
||||
};
|
||||
}
|
||||
22
developer/src/kmc-kmw/tsconfig.json
Normal file
22
developer/src/kmc-kmw/tsconfig.json
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.esm-base.json",
|
||||
|
||||
"compilerOptions": {
|
||||
"outDir": "build/src/",
|
||||
"rootDir": "src/",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@keymanapp/common-types": ["../../../common/web/types/src/main"],
|
||||
"@keymanapp/kmc-kmn": ["../kmc-kmn/src/main"],
|
||||
},
|
||||
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
],
|
||||
"references": [
|
||||
{ "path": "../../../common/web/types/" },
|
||||
{ "path": "../kmc-kmn/" },
|
||||
{ "path": "../../../core/include/ldml/"},
|
||||
]
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
if(typeof keyman === 'undefined') {console.error('Keyboard requires KeymanWeb 16.0 or later');} else {KeymanWeb.KR(new Keyboard_basic());}function Keyboard_basic() {this.KI="Keyboard_basic";this.KN={"value":"TestKbd"};this.KMINVER="16.0";this.KV={F: '10pt "Arial"', K102: 0};this.KV.KLS={TODO_LDML: 2};this.KDU=1;this.KH="";this.KM=0;this.KBVER="1.0.0";this.KMBM=0;this.KVKL={"desktop":{"defaultHint":"none","layer":[{"id":"base","row":[{"id":0,"key":[{"id":"T_hmaqtugha","text":"ħ"},{"id":"T_that","text":"ថា"}]}]}]}};this.gs=function(t,e){return 0;};}
|
||||
if(typeof keyman === 'undefined') {console.error('Keyboard requires KeymanWeb 16.0 or later');} else {KeymanWeb.KR(new Keyboard_basic());}function Keyboard_basic() {this.KI="Keyboard_basic";this.KN={"value":"TestKbd"};this.KMINVER="16.0";this.KV={F: '10pt "Arial"', K102: 0};this.KV.KLS={TODO_LDML: 2};this.KDU=1;this.KH="";this.KM=0;this.KBVER="1.0.0";this.KMBM=0;this.KVKL={"desktop":{"defaultHint":"none","layer":[{"id":"base","row":[{"id":"0","key":[{"id":"T_hmaqtugha","text":"ħ"},{"id":"T_that","text":"ថា"}]}]}]}};this.gs=function(t,e){return 0;};}
|
||||
|
|
@ -24,7 +24,7 @@ function Keyboard_basic() {
|
|||
"id": "base",
|
||||
"row": [
|
||||
{
|
||||
"id": 0,
|
||||
"id": "0",
|
||||
"key": [
|
||||
{
|
||||
"id": "T_hmaqtugha",
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ builder_describe "Build Keyman Keyboard Compiler kmc" \
|
|||
"@/common/web/keyman-version" \
|
||||
"@/common/web/types" \
|
||||
"@/developer/src/kmc-kmn" \
|
||||
"@/developer/src/kmc-kmw" \
|
||||
"@/developer/src/kmc-ldml" \
|
||||
"@/developer/src/kmc-model" \
|
||||
"@/developer/src/kmc-model-info" \
|
||||
|
|
@ -113,6 +114,7 @@ readonly PACKAGES=(
|
|||
common/models/types
|
||||
core/include/ldml
|
||||
developer/src/kmc-kmn
|
||||
developer/src/kmc-kmw
|
||||
developer/src/kmc-ldml
|
||||
developer/src/kmc-model
|
||||
developer/src/kmc-model-info
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
"@keymanapp/keyman-version": "*",
|
||||
"@keymanapp/common-types": "*",
|
||||
"@keymanapp/kmc-kmn": "*",
|
||||
"@keymanapp/kmc-kmw": "*",
|
||||
"@keymanapp/kmc-ldml": "*",
|
||||
"@keymanapp/kmc-model": "*",
|
||||
"@keymanapp/kmc-model-info": "*",
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
"paths": {
|
||||
"@keymanapp/common-types": [ "../../../common/web/types/src/main" ],
|
||||
"@keymanapp/kmc-kmn": [ "../kmc-kmn/src/main" ],
|
||||
"@keymanapp/kmc-kmw": [ "../kmc-kmw/src/main" ],
|
||||
"@keymanapp/kmc-ldml": [ "../kmc-ldml/src/main" ],
|
||||
"@keymanapp/kmc-model": [ "../kmc-model/src/main" ],
|
||||
"@keymanapp/kmc-model-info": [ "../kmc-model-info/src/model-info-compiler" ],
|
||||
|
|
@ -21,6 +22,7 @@
|
|||
{ "path": "../../../common/web/keyman-version/tsconfig.esm.json" },
|
||||
{ "path": "../../../common/web/types" },
|
||||
{ "path": "../kmc-kmn" },
|
||||
{ "path": "../kmc-kmw" },
|
||||
{ "path": "../kmc-ldml" },
|
||||
{ "path": "../kmc-model" },
|
||||
{ "path": "../kmc-model-info" },
|
||||
|
|
|
|||
261
package-lock.json
generated
261
package-lock.json
generated
|
|
@ -11,6 +11,7 @@
|
|||
"core/include/ldml",
|
||||
"developer/src/common/web/test-helpers",
|
||||
"developer/src/kmc-kmn",
|
||||
"developer/src/kmc-kmw",
|
||||
"developer/src/kmc-ldml",
|
||||
"developer/src/kmc-model",
|
||||
"developer/src/kmc-model-info",
|
||||
|
|
@ -635,6 +636,7 @@
|
|||
"@keymanapp/common-types": "*",
|
||||
"@keymanapp/keyman-version": "*",
|
||||
"@keymanapp/kmc-kmn": "*",
|
||||
"@keymanapp/kmc-kmw": "*",
|
||||
"@keymanapp/kmc-ldml": "*",
|
||||
"@keymanapp/kmc-model": "*",
|
||||
"@keymanapp/kmc-model-info": "*",
|
||||
|
|
@ -1029,6 +1031,261 @@
|
|||
"node": ">=0.3.1"
|
||||
}
|
||||
},
|
||||
"developer/src/kmc-kmw": {
|
||||
"name": "@keymanapp/kmc-kmw",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@keymanapp/common-types": "*",
|
||||
"@keymanapp/kmc-kmn": "*",
|
||||
"ajv": "^8.11.0",
|
||||
"restructure": "git+https://github.com/keymanapp/dependency-restructure.git#49d129cf0916d082a7278bb09296fb89cecfcc50",
|
||||
"semver": "^7.3.7",
|
||||
"xml2js": "git+https://github.com/keymanapp/dependency-node-xml2js#535fe732dc408d697e0f847c944cc45f0baf0829"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.1.7",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "^10.14.6",
|
||||
"@types/semver": "^7.3.12",
|
||||
"@types/xml2js": "^0.4.5",
|
||||
"c8": "^7.12.0",
|
||||
"chai": "^4.3.4",
|
||||
"chalk": "^2.4.2",
|
||||
"mocha": "^8.4.0",
|
||||
"ts-node": "^9.1.1",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
},
|
||||
"developer/src/kmc-kmw/node_modules/@types/mocha": {
|
||||
"version": "5.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz",
|
||||
"integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==",
|
||||
"dev": true
|
||||
},
|
||||
"developer/src/kmc-kmw/node_modules/@types/node": {
|
||||
"version": "10.17.60",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz",
|
||||
"integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==",
|
||||
"dev": true
|
||||
},
|
||||
"developer/src/kmc-kmw/node_modules/ajv": {
|
||||
"version": "8.12.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
||||
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"developer/src/kmc-kmw/node_modules/ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-convert": "^1.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"developer/src/kmc-kmw/node_modules/chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"developer/src/kmc-kmw/node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"developer/src/kmc-kmw/node_modules/color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
||||
"dev": true
|
||||
},
|
||||
"developer/src/kmc-kmw/node_modules/js-yaml": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz",
|
||||
"integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"js-yaml": "bin/js-yaml.js"
|
||||
}
|
||||
},
|
||||
"developer/src/kmc-kmw/node_modules/json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
|
||||
},
|
||||
"developer/src/kmc-kmw/node_modules/minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"developer/src/kmc-kmw/node_modules/mocha": {
|
||||
"version": "8.4.0",
|
||||
"resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz",
|
||||
"integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@ungap/promise-all-settled": "1.1.2",
|
||||
"ansi-colors": "4.1.1",
|
||||
"browser-stdout": "1.3.1",
|
||||
"chokidar": "3.5.1",
|
||||
"debug": "4.3.1",
|
||||
"diff": "5.0.0",
|
||||
"escape-string-regexp": "4.0.0",
|
||||
"find-up": "5.0.0",
|
||||
"glob": "7.1.6",
|
||||
"growl": "1.10.5",
|
||||
"he": "1.2.0",
|
||||
"js-yaml": "4.0.0",
|
||||
"log-symbols": "4.0.0",
|
||||
"minimatch": "3.0.4",
|
||||
"ms": "2.1.3",
|
||||
"nanoid": "3.1.20",
|
||||
"serialize-javascript": "5.0.1",
|
||||
"strip-json-comments": "3.1.1",
|
||||
"supports-color": "8.1.1",
|
||||
"which": "2.0.2",
|
||||
"wide-align": "1.1.3",
|
||||
"workerpool": "6.1.0",
|
||||
"yargs": "16.2.0",
|
||||
"yargs-parser": "20.2.4",
|
||||
"yargs-unparser": "2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"_mocha": "bin/_mocha",
|
||||
"mocha": "bin/mocha"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.12.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mochajs"
|
||||
}
|
||||
},
|
||||
"developer/src/kmc-kmw/node_modules/mocha/node_modules/escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"developer/src/kmc-kmw/node_modules/mocha/node_modules/supports-color": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
||||
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
||||
}
|
||||
},
|
||||
"developer/src/kmc-kmw/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true
|
||||
},
|
||||
"developer/src/kmc-kmw/node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"developer/src/kmc-kmw/node_modules/supports-color/node_modules/has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"developer/src/kmc-kmw/node_modules/ts-node": {
|
||||
"version": "9.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz",
|
||||
"integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"arg": "^4.1.0",
|
||||
"create-require": "^1.1.0",
|
||||
"diff": "^4.0.1",
|
||||
"make-error": "^1.1.1",
|
||||
"source-map-support": "^0.5.17",
|
||||
"yn": "3.1.1"
|
||||
},
|
||||
"bin": {
|
||||
"ts-node": "dist/bin.js",
|
||||
"ts-node-script": "dist/bin-script.js",
|
||||
"ts-node-transpile-only": "dist/bin-transpile.js",
|
||||
"ts-script": "dist/bin-script-deprecated.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=2.7"
|
||||
}
|
||||
},
|
||||
"developer/src/kmc-kmw/node_modules/ts-node/node_modules/diff": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
|
||||
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.3.1"
|
||||
}
|
||||
},
|
||||
"developer/src/kmc-ldml": {
|
||||
"name": "@keymanapp/kmc-ldml",
|
||||
"license": "MIT",
|
||||
|
|
@ -2322,6 +2579,10 @@
|
|||
"resolved": "developer/src/kmc-kmn",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@keymanapp/kmc-kmw": {
|
||||
"resolved": "developer/src/kmc-kmw",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@keymanapp/kmc-ldml": {
|
||||
"resolved": "developer/src/kmc-ldml",
|
||||
"link": true
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
"core/include/ldml",
|
||||
"developer/src/common/web/test-helpers",
|
||||
"developer/src/kmc-kmn",
|
||||
"developer/src/kmc-kmw",
|
||||
"developer/src/kmc-ldml",
|
||||
"developer/src/kmc-model",
|
||||
"developer/src/kmc-model-info",
|
||||
|
|
|
|||
|
|
@ -8,10 +8,14 @@
|
|||
{ "path": "./core/include/ldml/tsconfig.json" },
|
||||
|
||||
//{ "path": "./developer/src/kmc/test/tsconfig.json" },
|
||||
{ "path": "./developer/src/common/web/test-helpers/tsconfig.json" },
|
||||
|
||||
{ "path": "./developer/src/kmc/tsconfig.json" },
|
||||
|
||||
{ "path": "./developer/src/kmc-kmn/test/tsconfig.json" },
|
||||
{ "path": "./developer/src/kmc-kmn/tsconfig.json" },
|
||||
{ "path": "./developer/src/kmc-kmw/test/tsconfig.json" },
|
||||
{ "path": "./developer/src/kmc-kmw/tsconfig.json" },
|
||||
{ "path": "./developer/src/kmc-ldml/test/tsconfig.json" },
|
||||
{ "path": "./developer/src/kmc-ldml/tsconfig.json" },
|
||||
{ "path": "./developer/src/kmc-model/test/tsconfig.json" },
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue