chore(web): Merge branch 'refactor/web/common-layout-typing' into feat/web/base-recognizer-integration

This commit is contained in:
Joshua A. Horton 2023-10-11 15:18:48 +07:00
commit 00f119e566
365 changed files with 7668 additions and 8255 deletions

View file

@ -1,5 +1,30 @@
# Keyman Version History
## 17.0.186 alpha 2023-10-04
* feat(developer): show an INFO message when warnings have failed a build (#9652)
* chore(developer): reduce duplicate words warning to hint (#9653)
* feat(developer): issue hint if package includes keyboard source files (#9658)
* chore(developer): switch on code coverage reporting for kmc (#9662)
* fix(core): clean cached ICU in core (#9668)
* feat(developer): warn if .kps includes a .js which is not touch-capable (#9667)
## 17.0.185 alpha 2023-10-03
* chore(web): Add non-printing characters to the OSK (#9547)
* feat(developer): support `store(&version) '17.0'` (#9656)
* chore(developer): add test for `checkFilenameConventions == false` or unset (#9661)
* feat(developer): ldml scan codes support (#9615)
## 17.0.184 alpha 2023-10-02
* fix(web): fixes toolbar refocus timing after a keyboard change (#9618)
## 17.0.183 alpha 2023-09-29
* feat(web): browser-KMW support for default subkeys (#9496)
* refactor(linux): Add more tests for `keymanutil.c` ️ (#9595)
## 17.0.182 alpha 2023-09-28
* chore(web): builds that output to web/build/publish should also clean it (#9613)

View file

@ -1 +1 @@
17.0.183
17.0.187

View file

@ -10,6 +10,8 @@ and consists of these engineering keyboards:
* web/testing/chirality/chirality.js
* web/testing/platform/platformtest.js
test9469.kmp is another engineering keyboard to show non-printing characters on the OSK.
### Compiling From Command Line
1. Launch a command prompt to the `android/` folder
2. Compile KMEA. This will build and copy `keyman-engine.aar` to the Samples and Test projects

View file

@ -28,14 +28,14 @@ typedef uint8_t KMX_BYTE;
typedef uint16_t KMX_WORD;
#if defined(__cplusplus)
typedef char16_t km_kbp_cp;
typedef char32_t km_kbp_usv;
typedef char16_t km_core_cp;
typedef char32_t km_core_usv;
#else
typedef uint16_t km_kbp_cp; // code point
typedef uint32_t km_kbp_usv; // Unicode Scalar Value
typedef uint16_t km_core_cp; // code point
typedef uint32_t km_core_usv; // Unicode Scalar Value
#endif
typedef km_kbp_cp KMX_WCHAR; // wc, 16-bit UNICODE character
typedef km_core_cp KMX_WCHAR; // wc, 16-bit UNICODE character
typedef KMX_WCHAR* PKMX_WCHAR;
typedef char KMX_CHAR;
@ -60,7 +60,7 @@ typedef KMX_DWORD* PKMX_DWORD;
#ifdef USE_CHAR16_T
#define lpuch(x) u ## x
typedef km_kbp_cp KMX_UCHAR;
typedef km_core_cp KMX_UCHAR;
#else
#define lpuch(x) L ## x
typedef wchar_t KMX_UCHAR;

View file

@ -68,9 +68,10 @@ namespace kmx {
#define VERSION_150 0x00000F00
#define VERSION_160 0x00001000
#define VERSION_170 0x00001100
#define VERSION_MIN VERSION_50
#define VERSION_MAX VERSION_160
#define VERSION_MAX VERSION_170
//
// Backspace types

View file

@ -30,7 +30,7 @@
#endif
#define try_status(expr) { \
auto __s = (expr); \
if (__s != KM_KBP_STATUS_OK) { \
if (__s != KM_CORE_STATUS_OK) { \
_assert_failed(__s, u ## #expr); \
} \
}

View file

@ -21,9 +21,7 @@
"exports": {
".": "./build/obj/index.js",
"./lib": {
"types": "./build/lib/index.d.ts",
"import": "./build/lib/index.mjs",
"require": "./build/lib/index.cjs"
"types": "./build/lib/index.d.ts"
},
"./obj/*.js": "./build/obj/*.js"
},

View file

@ -19,8 +19,7 @@
"exports": {
".": "./build/obj/index.js",
"./lib": {
"import": "./build/lib/index.mjs",
"require": "./build/lib/index.cjs"
"types": "./build/lib/index.d.ts"
},
"./obj/*.js": "./build/obj/*.js"
},

View file

@ -1,28 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<!-- Set the viewport width to match iOS device widths -->
<!-- <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no" /> -->
<meta name="viewport" content="width=device-width,user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<!-- Enable IE9 Standards mode -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>LMLayer Testing</title>
<style type='text/css'>
body {padding-left:20px;margin-left:12px; font-family:Tahoma,Helvetica}
h1 {color: #800;margin-left:10px;}
h2 {color: #008;margin-left:20px;}
</style>
</head>
<body>
<h1>Language-Modeling Layer module testing</h1>
<h2><a href="./simple-webworker">A simple basic WebWorker.</a></h2> Designed as a baseline functionality test we can run against various platforms as a first-stage canary of sorts.
<h2><a href="./one-stage-embedded-webworker">An embedded WebWorker prototype.</a></h2> A prototype for directly embedding a WebWorker's code within a "master" script.
<h2><a href="./two-stage-embedded-webworker">A better embedded WebWorker prototype.</a></h2> A prototype for two-stage compilation of a master/slave main-script/WebWorker pair.
<h2><a href="./post-blob-webworker/">Sending code via a Blob URI</a></h2> A prototype for sending code over to a WebWorker via a Blob URI reference.
</body>
</html>

View file

@ -1,2 +0,0 @@
main.js
main.js.map

View file

@ -1,54 +0,0 @@
#!/usr/bin/env bash
#
# Compiles the Language Modeling Layer for common use in predictive text and autocorrective applications.
# Designed for optimal compatibility with the Keyman Suite.
#
## START STANDARD BUILD SCRIPT INCLUDE
# adjust relative paths as necessary
THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
. "${THIS_SCRIPT%/*}/../../../../resources/build/build-utils.sh"
. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh"
## END STANDARD BUILD SCRIPT INCLUDE
display_usage ( ) {
echo "build.sh [-clean]"
echo
echo " -clean to erase pre-existing build products before a re-build"
}
SOURCE="testing/one-stage-embedded-webworker"
echo "Node.js + dependencies check"
npm install --no-optional
if [ $? -ne 0 ]; then
builder_die "Build environment setup error detected! Please ensure Node.js is installed!"
fi
# A nice, extensible method for -clean operations. Add to this as necessary.
clean ( ) {
rm -rf "./*.js"
if [ $? -ne 0 ]; then
builder_die "Failed to erase the prior build."
fi
}
# Process command-line arguments
while [[ $# -gt 0 ]] ; do
key="$1"
case $key in
-clean)
clean
;;
esac
shift # past the processed argument
done
npm run tsc -- -p $SOURCE/tsconfig.json
if [ $? -ne 0 ]; then
builder_die "Compilation failed."
fi
echo "Typescript compilation successful."

View file

@ -1,42 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<!-- Set the viewport width to match phone and tablet device widths -->
<meta name="viewport" content="width=device-width,user-scalable=no" />
<!-- Allow KeymanWeb to be saved to the iPhone home screen -->
<meta name="apple-mobile-web-app-capable" content="yes" />
<!-- Enable IE9 Standards mode -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Embedded WebWorker test</title>
<!-- Your page CSS -->
<style type='text/css'>
body {font-family: Tahoma,helvetica;}
h3 {font-size: 1em;font-weight:normal;color: darkred; margin-bottom: 4px}
.test {font-size: 1.5em; width:80%; min-height:30px; border: 1px solid gray;}
#KeymanWebControl {width:50%;min-width:600px;}
</style>
<script src="main.js"></script>
</head>
<!-- Sample page HTML -->
<body>
<h2>LM Layer Testing - One-Stage Embedded WebWorkers</h2>
<p>This page serves as a prototype for embedding a WebWorker's code within its "master" script
across the TypeScript transpilation boundary.</p>
<input type='text' id='txtFeedback' value="No clicks yet." readonly></input> <br>
<script>
var txtFeedback = document.getElementById("txtFeedback");
txtFeedback.value = "No clicks yet.";
</script>
<input type='button' id='btnInput' onclick='canaryWorker.postMessage("Hello.");' value='Message the WebWorker.' />
<h3><a href="../index.html">Return to testing home page</a></h3>
</body>
</html>

View file

@ -1,52 +0,0 @@
// Useful for passing class constructors
type Workable<T> = {
new (...args: any[]): T;
// Requires a static implementation.
onmessage(e: any): void;
};
class A {
a(x: number, y: number):number {
return x + y;
}
}
var WorkerGlobals = {
counter: 0,
a: A
}
class WorkerCore {
static WorkerGlobals = WorkerGlobals;
//static counter: number;
static onmessage(e: any) {
WorkerGlobals.counter++;
console.log("Message received from main page: ", e.data);
// Forces TypeScript to interpret this line as plain JavaScript, as it uses a non-Worker definition.
// @ts-ignore
postMessage(WorkerGlobals.counter);
}
}
function createWorkerFromClasses(globals: object, fn: Workable<object>): Worker {
var sep = ";\n";
let glb = "var WorkerGlobals = " + JSON.stringify(globals);
let wc = "var onmessage = " + fn.onmessage.toString();
var blob = new Blob([glb, sep, wc], { type: 'text/javascript' });
let url = URL.createObjectURL(blob);
return new Worker(url);
}
var canaryWorker = createWorkerFromClasses(WorkerGlobals, WorkerCore);
canaryWorker.onmessage = function(e) {
var counter = e.data; // Number of times the WebWorker has been messaged.
console.log("Received message from the WebWorker: " + e.data);
var txtFeedback = <HTMLInputElement>document.getElementById("txtFeedback");
txtFeedback.value = counter + " click(s)";
}

View file

@ -1,13 +0,0 @@
{
"compilerOptions": {
"allowJs": false,
"module": "none",
"outDir": "./",
"inlineSources": true,
"sourceMap": true,
"target": "es5"
},
"files" : [
"main.ts"
]
}

View file

@ -1,5 +0,0 @@
// receive a message and execute its uri
onmessage = function (e) {
let uri = e.data.uri;
importScripts(uri);
};

View file

@ -1,72 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<!-- Set the viewport width to match phone and tablet device widths -->
<meta name="viewport" content="width=device-width,user-scalable=no" />
<!-- Allow KeymanWeb to be saved to the iPhone home screen -->
<meta name="apple-mobile-web-app-capable" content="yes" />
<!-- Enable IE9 Standards mode -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Blob URI test</title>
<!-- Your page CSS -->
<style type='text/css'>
body {font-family: Tahoma,helvetica;}
h3 {font-size: 1em;font-weight:normal;color: darkred; margin-bottom: 4px}
.test {font-size: 1.5em; width:80%; min-height:30px; border: 1px solid gray;}
#KeymanWebControl {width:50%;min-width:600px;}
</style>
<script>
if (window.Worker) {
var canaryWorker = new Worker('canaryWorker.js');
canaryWorker.onmessage = function(e) {
var message = e.data; // Number of times the WebWorker has been messaged.
console.log("Received message from the WebWorker: " + e.data);
var txtFeedback = document.getElementById("txtFeedback");
txtFeedback.value = message;
}
} else {
console.error("WebWorkers are not supported in this browser!");
}
</script>
</head>
<!-- Sample page HTML -->
<body>
<h2>LM Layer Testing - Sending a function to a WebWorker via a Blob URI test</h2>
<p>This page sends a function over to the Worker via a Blob URI, and
expects the function to reply back.
</p>
<input type='text' id='txtFeedback' value="Haven't heard back yet" readonly> <br>
<script>
var txtFeedback = document.getElementById("txtFeedback");
txtFeedback.value = "Have not heard back from worker";
function sendCode () {
function payload () {
postMessage('Hello, from the blobified code!');
}
// Create an immediately-invoked function expression... to immediately
// invoke the code!
let iife = ['(', payload.toString(), '())'];
let blob = new Blob(iife, { type: 'text/javascript' });
let uri = URL.createObjectURL(blob);
// Go!
canaryWorker.postMessage({ uri: uri });
}
</script>
<input type='button' id='btnInput' onclick='sendCode()' value='Send the source code!' />
<h3><a href="../index.html">Return to testing home page</a></h3>
</body>
</html>

View file

@ -1,9 +0,0 @@
var counter = 0;
onmessage = function(e) {
counter++;
console.log("Message received from main page: ", e.data);
postMessage(counter);
}

View file

@ -1,55 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<!-- Set the viewport width to match phone and tablet device widths -->
<meta name="viewport" content="width=device-width,user-scalable=no" />
<!-- Allow KeymanWeb to be saved to the iPhone home screen -->
<meta name="apple-mobile-web-app-capable" content="yes" />
<!-- Enable IE9 Standards mode -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Basic WebWorker test</title>
<!-- Your page CSS -->
<style type='text/css'>
body {font-family: Tahoma,helvetica;}
h3 {font-size: 1em;font-weight:normal;color: darkred; margin-bottom: 4px}
.test {font-size: 1.5em; width:80%; min-height:30px; border: 1px solid gray;}
#KeymanWebControl {width:50%;min-width:600px;}
</style>
<script>
if(window.Worker) {
var canaryWorker = new Worker('canaryWorker.js');
canaryWorker.onmessage = function(e) {
var counter = e.data; // Number of times the WebWorker has been messaged.
console.log("Received message from the WebWorker: " + e.data);
var txtFeedback = document.getElementById("txtFeedback");
txtFeedback.value = counter + " click(s)";
}
} else {
console.error("WebWorkers are not supported in this browser!");
}
</script>
</head>
<!-- Sample page HTML -->
<body>
<h2>LM Layer Testing - basic WebWorker canary</h2>
<p>This page uses a simple WebWorker useful for ensuring functionality on various platforms.</p>
<input type='text' id='txtFeedback' value="No clicks yet." readonly></input> <br>
<script>
var txtFeedback = document.getElementById("txtFeedback");
txtFeedback.value = "No clicks yet.";
</script>
<input type='button' id='btnInput' onclick='canaryWorker.postMessage("Hello.");' value='Message the WebWorker.' />
<h3><a href="../index.html">Return to testing home page</a></h3>
</body>
</html>

View file

@ -1,2 +0,0 @@
**/*.js
**/*.js.map

View file

@ -1,68 +0,0 @@
#!/usr/bin/env bash
#
# Compiles the Language Modeling Layer for common use in predictive text and autocorrective applications.
# Designed for optimal compatibility with the Keyman Suite.
#
## START STANDARD BUILD SCRIPT INCLUDE
# adjust relative paths as necessary
THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
. "${THIS_SCRIPT%/*}/../../../../resources/build/build-utils.sh"
. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh"
## END STANDARD BUILD SCRIPT INCLUDE
display_usage ( ) {
echo "build.sh [-clean]"
echo
echo " -clean to erase pre-existing build products before a re-build"
}
SOURCE="testing/two-stage-embedded-webworker"
COMPILED_WORKER="worker.js"
EMBEDDED_WORKER="embedded_worker.js"
echo "Node.js + dependencies check"
npm install --no-optional
if [ $? -ne 0 ]; then
builder_die "Build environment setup error detected! Please ensure Node.js is installed!"
fi
# A nice, extensible method for -clean operations. Add to this as necessary.
clean ( ) {
rm -rf "./*.js"
if [ $? -ne 0 ]; then
builder_die "Failed to erase the prior build."
fi
}
# Process command-line arguments
while [[ $# -gt 0 ]] ; do
key="$1"
case $key in
-clean)
clean
;;
esac
shift # past the processed argument
done
npm run tsc -- -p $SOURCE/worker/tsconfig.json
if [ $? -ne 0 ]; then
builder_die "Worker compilation failed."
fi
rm $EMBEDDED_WORKER &> /dev/null
echo "var LMLayerWorker = function() {" >> $EMBEDDED_WORKER
cat $COMPILED_WORKER >> $EMBEDDED_WORKER
echo "" >> $EMBEDDED_WORKER
echo "}" >> $EMBEDDED_WORKER
npm run tsc -- -p $SOURCE/tsconfig.json
if [ $? -ne 0 ]; then
builder_die "Final compilation failed."
fi
echo "Typescript compilation successful."

View file

@ -1,42 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<!-- Set the viewport width to match phone and tablet device widths -->
<meta name="viewport" content="width=device-width,user-scalable=no" />
<!-- Allow KeymanWeb to be saved to the iPhone home screen -->
<meta name="apple-mobile-web-app-capable" content="yes" />
<!-- Enable IE9 Standards mode -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Embedded WebWorker test</title>
<!-- Your page CSS -->
<style type='text/css'>
body {font-family: Tahoma,helvetica;}
h3 {font-size: 1em;font-weight:normal;color: darkred; margin-bottom: 4px}
.test {font-size: 1.5em; width:80%; min-height:30px; border: 1px solid gray;}
#KeymanWebControl {width:50%;min-width:600px;}
</style>
<script src="main.js"></script>
</head>
<!-- Sample page HTML -->
<body>
<h2>LM Layer Testing - One-Stage Embedded WebWorkers</h2>
<p>This page serves as a prototype for embedding a WebWorker's code within its "master" script
across the TypeScript transpilation boundary.</p>
<input type='text' id='txtFeedback' value="No clicks yet." readonly></input> <br>
<script>
var txtFeedback = document.getElementById("txtFeedback");
txtFeedback.value = "No clicks yet.";
</script>
<input type='button' id='btnInput' onclick='canaryWorker.postMessage("Hello.");' value='Message the WebWorker.' />
<h3><a href="../index.html">Return to testing home page</a></h3>
</body>
</html>

View file

@ -1,30 +0,0 @@
// Provides the final source for our compiled WebWorker within a wrapping function.
/// <reference path="embedded_worker.js" />
function createWorker(fn: Function): Worker {
var str_fn = fn.toString();
// We now unwrap our WebWorker from its function.
var str_lines = str_fn.split("\n");
var blob_lines = []
for(var i=1; i < str_lines.length -1; i++) {
blob_lines.push(str_lines[i] + "\n");
}
// Unwrapping complete.
var blob = new Blob(blob_lines, { type: 'text/javascript' });
let url = URL.createObjectURL(blob);
return new Worker(url);
}
var canaryWorker = createWorker(LMLayerWorker);
canaryWorker.onmessage = function(e) {
var counter = e.data; // Number of times the WebWorker has been messaged.
console.log("Received message from the WebWorker: " + e.data);
var txtFeedback = <HTMLInputElement>document.getElementById("txtFeedback");
txtFeedback.value = counter + " click(s)";
}

View file

@ -1,13 +0,0 @@
{
"compilerOptions": {
"allowJs": true,
"module": "none",
"outFile": "./main.js",
"inlineSources": true,
"inlineSourceMap": true,
"target": "es5"
},
"files" : [
"main.ts"
]
}

View file

@ -1,9 +0,0 @@
var counter = 0;
onmessage = function(e) {
counter++;
console.log("Message received from main page: ", e.data);
postMessage(counter);
}

View file

@ -1,11 +0,0 @@
{
"compilerOptions": {
"allowJs": false,
"module": "none",
"outFile": "../worker.js",
"inlineSources": true,
"sourceMap": true,
"lib": ["webworker", "es6"],
"target": "es5"
}
}

View file

@ -1,11 +1,4 @@
#!/usr/bin/env bash
#
# Builds hextobin.js
#
# Exit on command failure and when using unset variables:
set -eu
## START STANDARD BUILD SCRIPT INCLUDE
# adjust relative paths as necessary
THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
@ -22,21 +15,10 @@ cd "$THIS_SCRIPT_PATH"
builder_describe "Build hextobin" clean configure build
builder_describe_outputs \
configure /node_modules \
build build/index.js
build /common/tools/hextobin/build/index.js
builder_parse "$@"
if builder_start_action clean; then
npm run clean
builder_finish_action success clean
fi
if builder_start_action configure; then
verify_npm_setup
builder_finish_action success configure
fi
if builder_start_action build; then
npm run build
builder_finish_action success build
fi
builder_run_action clean rm -rf build/ node_modules/
builder_run_action configure verify_npm_setup
builder_run_action build tsc --build

View file

@ -1,11 +1,11 @@
#!/usr/bin/env node
import * as fs from 'fs';
import * as rd from 'readline';
import * as program from 'commander';
import { Command } from 'commander';
import hextobin from './index.js';
let inputFilename: string = "";
let outputFilename: string = "";
const program = new Command();
program
.description(
`Will convert the input file which is a hex dump to the output file. Hex dump can contain
@ -43,6 +43,4 @@ function exitDueToUsageError(message: string): never {
return process.exit(64); // SysExits.EX_USAGE
}
import hextobin from './index';
hextobin(inputFilename, outputFilename, {silent: false});

View file

@ -1,6 +1,8 @@
{
"name": "@keymanapp/hextobin",
"description": "hextobin conversion tool",
"type": "module",
"private": true,
"keywords": [
"keyman",
"hex",
@ -14,14 +16,6 @@
"bin": {
"hextobin": "build/hextobin.js"
},
"scripts": {
"clean": "tsc -b --clean",
"build": "tsc -b"
},
"repository": {
"type": "git",
"url": "git+https://github.com/keymanapp/keyman.git"
},
"devDependencies": {
"@types/node": "^18.7.18"
}

View file

@ -1,19 +1,9 @@
{
"extends": "../../../tsconfig-base.json",
"compilerOptions": {
"composite": true,
"declaration": true,
"target": "ES2020",
"module": "CommonJS",
"moduleResolution": "node",
"rootDir": ".",
"outDir": "build/",
},
"exclude": [
"node_modules"
],
"files": [
"index.ts",
"hextobin.ts"
]
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"rootDir": ".",
"outDir": "build/"
},
"exclude": ["node_modules"],
"files": ["index.ts", "hextobin.ts"]
}

View file

@ -0,0 +1 @@
declare module 'convert-source-map';

View file

@ -1,12 +1,11 @@
{
"extends": "../../../tsconfig-base.json",
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"allowJs": false,
"allowSyntheticDefaultImports": true,
"declaration": true,
"module": "es6",
"moduleResolution": "node",
"sourceMap": false,
"inlineSourceMap": true,
"inlineSources": true,
"sourceRoot": "/common/tools/sourcemap-path-remapper/src",

View file

@ -1,5 +1,5 @@
{
"extends": "../../../tsconfig.esm-base.json",
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"baseUrl": "./",
"outDir": "build/",

View file

@ -51,7 +51,7 @@ export class HostFixtureLayoutController extends EventEmitter {
};
};
private _setup: () => boolean = function(this: HostFixtureLayoutController) {
private _setup: () => void = function(this: HostFixtureLayoutController) {
let config = this.buildBaseFixtureConfig();
this._recognizer = new GestureRecognizer<any>(null /* TODO */, config);
this._hostFixture = document.getElementById('host-fixture');

View file

@ -51,6 +51,12 @@ class ActiveKeyBase {
_baseKeyEvent: KeyEvent;
isMnemonic: boolean = false;
/**
* Only available on subkeys, but we don't distinguish between base keys and subkeys
* at this level yet in KMW.
*/
default?: boolean;
proportionalPad: number;
proportionalX: number;
proportionalWidth: number;
@ -207,7 +213,7 @@ class ActiveKeyBase {
rawKey.sp ||= 0; // The default button class.
}
static polyfill(key: LayoutKey, keyboard: Keyboard, layout: ActiveLayout, displayLayer: string) {
static polyfill(key: LayoutKey | LayoutSubKey, keyboard: Keyboard, layout: ActiveLayout, displayLayer: string) {
// Add class functions to the existing layout object, allowing it to act as an ActiveLayout.
let dummy = new ActiveKeyBase();
let proto = Object.getPrototypeOf(dummy);
@ -225,8 +231,8 @@ class ActiveKeyBase {
}
// Ensure subkeys are also properly extended.
if(key.sk) {
for(let subkey of key.sk) {
if((key as LayoutKey).sk) {
for(let subkey of (key as LayoutKey).sk) {
ActiveSubkey.polyfill(subkey, keyboard, layout, displayLayer);
}
}
@ -235,6 +241,8 @@ class ActiveKeyBase {
aKey.displayLayer = displayLayer;
aKey.layer = aKey.layer || displayLayer;
aKey.default = (key as LayoutSubKey).default;
// Compute the key's base KeyEvent properties for use in future event generation
aKey.constructBaseKeyEvent(keyboard, layout, displayLayer);
}
@ -299,10 +307,6 @@ class ActiveKeyBase {
export class ActiveKey extends ActiveKeyBase implements LayoutKey {
public polyfill() {
}
public getSubkey(coreID: string): ActiveKey {
if(this.sk) {
for(let key of this.sk) {

View file

@ -22,8 +22,11 @@ export type KLS = {[layerName: string]: string[]};
export type ButtonClass = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
export type ButtonClassString = "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"|"10";
export interface LayoutLayer extends LayoutLayerBase {
// Post-processing elements tracked by Web.
export type LayoutLayer = {
"id": string,
"row": LayoutRow[],
// Post-processing elements.
shiftKey?: LayoutKey,
capsKey?: LayoutKey,
numKey?: LayoutKey,

View file

@ -1,22 +0,0 @@
/*
* Bundles @keymanapp/keyman-version as a single-file CommonJS module for components
* still in need of it.
*/
import esbuild from 'esbuild';
// Bundles to a compact ESModule
esbuild.buildSync({
entryPoints: ['build/version.inc.js'],
bundle: true,
sourcemap: true,
//minify: true, // No need to minify a module.
//keepNames: true,
format: "cjs",
// Sets 'common/web' as a root folder for module resolution;
// this allows the keyman-version import to resolve.
nodePaths: ['..'],
outfile: "build/version.inc.cjs",
tsconfig: 'tsconfig.json',
target: "es5"
});

View file

@ -1,11 +1,4 @@
#!/usr/bin/env bash
#
# Builds the include script for the current Keyman version.
#
# Exit on command failure and when using unset variables:
set -eu
## START STANDARD BUILD SCRIPT INCLUDE
# adjust relative paths as necessary
THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
@ -13,6 +6,7 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
## END STANDARD BUILD SCRIPT INCLUDE
. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh"
. "$KEYMAN_ROOT/resources/build/build-utils-ci.inc.sh"
# This script runs from its own folder
cd "$THIS_SCRIPT_PATH"
@ -25,8 +19,7 @@ builder_describe "Build the include script for current Keyman version" \
build \
"pack build a local .tgz pack for testing" \
"publish publish to npm" \
test \
--dry-run
test
builder_describe_outputs \
configure "/node_modules" \
@ -34,21 +27,7 @@ builder_describe_outputs \
builder_parse "$@"
if builder_start_action configure; then
verify_npm_setup
builder_finish_action success configure
fi
if builder_start_action clean; then
npm run clean
rm -f ./version.inc.ts
rm -f ./keyman-version.mts
rm -rf build
builder_finish_action success clean
fi
if builder_start_action build; then
function do_build() {
# Generate version.inc.ts
echo "
// Generated by common/web/keyman-version/build.sh
@ -72,22 +51,11 @@ export class KEYMAN_VERSION {
export default KEYMAN_VERSION;
" > ./version.inc.ts
tsc -b $builder_verbose
# kmlmc (the lexical model compiler) relies on a Node-based import, but after some of the earlier
# ES-modularization work, our main output's an ES module. Fortunately, esbuild can provide an easy stopgap.
tsc --build $builder_verbose
}
# Generates a CommonJS variant (in case other modules still need it).
node ./build-bundler.js
builder_finish_action success build
fi
if builder_start_action publish; then
. "$KEYMAN_ROOT/resources/build/build-utils-ci.inc.sh"
builder_publish_to_npm
builder_finish_action success publish
elif builder_start_action pack; then
. "$KEYMAN_ROOT/resources/build/build-utils-ci.inc.sh"
builder_publish_to_pack
builder_finish_action success pack
fi
builder_run_action clean rm -rf version.inc.ts keyman-version.mts build/
builder_run_action configure verify_npm_setup
builder_run_action build do_build
builder_run_action publish builder_publish_to_npm
builder_run_action pack builder_publish_to_pack

View file

@ -1,26 +1,15 @@
{
"name": "@keymanapp/keyman-version",
"description": "Keyman global version data",
"main": "./build/version.inc.cjs",
"exports": {
".": {
"import": "./build/version.inc.js",
"require": "./build/version.inc.cjs"
},
"./build/version.inc.cjs": "./build/version.inc.cjs"
".": "./build/version.inc.js"
},
"files": [
"/build/"
],
"scripts": {
"build": "echo 'Building @keymanapp/keyman-version' && tsc -b",
"clean": "tsc -b --clean",
"tsc": "tsc"
},
"license": "MIT",
"type": "module",
"devDependencies": {
"@types/node": "^20.4.1",
"typescript": "^4.9.5"
}
}

View file

@ -1,17 +1,12 @@
{
"extends": "../../../tsconfig-base.json",
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"allowJs": false,
"declaration": true,
"module": "es6",
"sourceMap": true,
"outDir": "./build",
"lib": ["es6"],
"target": "es5",
"downlevelIteration": true,
"rootDir": "."
},
"include": [
"version.inc.ts"
]

View file

@ -1,5 +1,5 @@
{
"extends": "../../../tsconfig-base.json",
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"declaration": true,
"module": "none",

View file

@ -1,13 +1,22 @@
{
"extends": "../../../../tsconfig-base.json",
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
// TODO: These override /tsconfig.base.json settings, and so should be removed if possible,
// but existing code in web/ breaks some of these settinsg
"noImplicitThis": false,
"noImplicitReturns": false,
"noImplicitAny": false,
"strictFunctionTypes": false,
"noUnusedLocals": false,
"allowJs": true,
"allowSyntheticDefaultImports": true,
"baseUrl": "./",
"inlineSources": true,
"lib": ["es6", "dom"],
"module": "es6",
"moduleResolution": "Node16",
"outDir": "../build/obj",
"rootDir": "./",
"sourceMap": true,

View file

@ -122,8 +122,8 @@ export const USVirtualKeyCodes = {
*/
K_oE2:226,
K_OE2:226,
k_oC1:193, // ISO B11, ABNT-2 key to left of right shift, not on US keyboard
k_OC1:193,
K_oC1:193, // ISO B11, ABNT-2 key to left of right shift, not on US keyboard
K_OC1:193,
'K_?C1':193,
'k_?C1':193,
K_oDF:0xDF,
@ -144,125 +144,90 @@ export const USVirtualKeyCodes = {
const k = USVirtualKeyCodes;
/** Map a CLDR scancode to a US VKey ala USVirtualKeyCodes */
export const CLDRScanToUSVirtualKeyCodes = {
0x02: k.K_1,
0x03: k.K_2,
0x04: k.K_3,
0x05: k.K_4,
0x06: k.K_5,
0x07: k.K_6,
0x08: k.K_7,
0x09: k.K_8,
0x0A: k.K_9,
0x0B: k.K_0,
0x0C: k.K_HYPHEN,
0x0D: k.K_EQUAL,
0x10: k.K_Q,
0x11: k.K_W,
0x12: k.K_E,
0x13: k.K_R,
0x14: k.K_T,
0x15: k.K_Y,
0x16: k.K_U,
0x17: k.K_I,
0x18: k.K_O,
0x19: k.K_P,
0x1A: k.K_LBRKT,
0x1B: k.K_RBRKT,
0x1E: k.K_A,
0x1F: k.K_S,
0x20: k.K_D,
0x21: k.K_F,
0x22: k.K_G,
0x23: k.K_H,
0x24: k.K_J,
0x25: k.K_K,
0x26: k.K_L,
0x27: k.K_COLON,
0x28: k.K_QUOTE,
0x29: k.K_BKQUOTE,
0x2B: k.K_BKSLASH,
0x2C: k.K_Z,
0x2D: k.K_X,
0x2E: k.K_C,
0x2F: k.K_V,
0x30: k.K_B,
0x31: k.K_N,
0x32: k.K_M,
0x33: k.K_COMMA,
0x34: k.K_PERIOD,
0x35: k.K_SLASH,
0x39: k.K_SPACE,
0x56: k.K_oE2, // << Same as 0x7D; found on iso, abnt2
0x73: k.K_oC1,
0x7D: k.K_oE2, // << Same as 0x56; found on jis
};
export type KeyMap = number[][];
export const USVirtualKeyMap: KeyMap = [
// ` 1 2 3 4 5 6 7 8 9 0 - = [bksp]
[ k.K_BKQUOTE, k.K_1, k.K_2, k.K_3, k.K_4, k.K_5, k.K_6, k.K_7, k.K_8, k.K_9, k.K_0, k.K_HYPHEN, k.K_EQUAL ],
// [tab] Q W E R T Y U I O P [ ] \
[ k.K_Q, k.K_W, k.K_E, k.K_R, k.K_T, k.K_Y, k.K_U, k.K_I, k.K_O, k.K_P, k.K_LBRKT, k.K_RBRKT, k.K_BKSLASH ],
// [caps] A S D F G H J K L ; ' [enter]
[ k.K_A, k.K_S, k.K_D, k.K_F, k.K_G, k.K_H, k.K_J, k.K_K, k.K_L, k.K_COLON, k.K_QUOTE ],
// [shift] Z X C V B N M , . / [shift] *=oE2
[ k.K_Z, k.K_X, k.K_C, k.K_V, k.K_B, k.K_N, k.K_M, k.K_COMMA, k.K_PERIOD, k.K_SLASH ],
// space
[ k.K_SPACE ],
];
export const ISOVirtualKeyMap: KeyMap = [
// ` 1 2 3 4 5 6 7 8 9 0 - = [bksp]
[ k.K_BKQUOTE, k.K_1, k.K_2, k.K_3, k.K_4, k.K_5, k.K_6, k.K_7, k.K_8, k.K_9, k.K_0, k.K_HYPHEN, k.K_EQUAL ],
// [tab] Q W E R T Y U I O P [ ]
[ k.K_Q, k.K_W, k.K_E, k.K_R, k.K_T, k.K_Y, k.K_U, k.K_I, k.K_O, k.K_P, k.K_LBRKT, k.K_RBRKT ],
// [caps] A S D F G H J K L ; ' \ [enter]
[ k.K_A, k.K_S, k.K_D, k.K_F, k.K_G, k.K_H, k.K_J, k.K_K, k.K_L, k.K_COLON, k.K_QUOTE, k.K_BKSLASH ],
// [shift] * Z X C V B N M , . / [shift] *=oE2
[ k.K_oE2, k.K_Z, k.K_X, k.K_C, k.K_V, k.K_B, k.K_N, k.K_M, k.K_COMMA, k.K_PERIOD, k.K_SLASH ],
// space
[ k.K_SPACE ],
];
export const JISVirtualKeyMap: KeyMap = [
// [Hankaku/Zenkaku] 1 2 3 4 5 6 7 8 9 0 - ^ ¥ [bksp]
[ k.K_1, k.K_2, k.K_3, k.K_4, k.K_5, k.K_6, k.K_7, k.K_8, k.K_9, k.K_0, k.K_HYPHEN, k.K_EQUAL, k.K_BKSLASH /* YEN */ ],
// [tab] Q W E R T Y U I O P @«`» [ [enter]
[ k.K_Q, k.K_W, k.K_E, k.K_R, k.K_T, k.K_Y, k.K_U, k.K_I, k.K_O, k.K_P, k.K_BKQUOTE, k.K_LBRKT ],
// [caps] A S D F G H J K L ; : ] [enter]
[ k.K_A, k.K_S, k.K_D, k.K_F, k.K_G, k.K_H, k.K_J, k.K_K, k.K_L, k.K_COLON, k.K_QUOTE, k.K_RBRKT ],
// [shift] Z X C V B N M , . / _ [shift]
[ k.K_Z, k.K_X, k.K_C, k.K_V, k.K_B, k.K_N, k.K_M, k.K_COMMA, k.K_PERIOD, k.K_SLASH, k.K_oE2 /* ろ */ ],
// space
[ k.K_SPACE ],
];
export const ABNT2VirtualKeyMap: KeyMap = [
// ' 1 2 3 4 5 6 7 8 9 0 - = [bksp]
[ k.K_BKQUOTE, k.K_1, k.K_2, k.K_3, k.K_4, k.K_5, k.K_6, k.K_7, k.K_8, k.K_9, k.K_0, k.K_HYPHEN, k.K_EQUAL ],
// [tab] Q W E R T Y U I O P ´ [
[ k.K_Q, k.K_W, k.K_E, k.K_R, k.K_T, k.K_Y, k.K_U, k.K_I, k.K_O, k.K_P, k.K_LBRKT, k.K_RBRKT ],
// [caps] A S D F G H J K L ç ~ ] [enter]
[ k.K_A, k.K_S, k.K_D, k.K_F, k.K_G, k.K_H, k.K_J, k.K_K, k.K_L, k.K_COLON, k.K_QUOTE, k.K_BKSLASH ],
// [shift] \ Z X C V B N M , . ; / [shift]
[ k.K_oE2, k.K_Z, k.K_X, k.K_C, k.K_V, k.K_B, k.K_N, k.K_M, k.K_COMMA, k.K_PERIOD, k.K_SLASH, k.k_oC1 /* ABNT2 */ ],
// space
[ k.K_SPACE ],
];
/**
* Map from a hardware constant to a keymap
* For the 'key' see constants.layr_list_hardware_map
* Convert a scan code numerical KeyMap to VKeys
* @param scans keymap to convert
* @param badScans output: set of not-found scancodes
* @returns
*/
export const HardwareToKeymap: Map<string, KeyMap> = new Map(
[
["us", USVirtualKeyMap],
["iso", ISOVirtualKeyMap],
["jis", JISVirtualKeyMap],
["abnt2", ABNT2VirtualKeyMap],
]
);
export function CLDRScanToKeyMap(scans: KeyMap, badScans?: Set<number>): KeyMap {
return scans.map((row) => row.map((scan) => CLDRScanToVkey(scan, badScans)));
}
/** Convert one scan code to vkey, or undefined */
export function CLDRScanToVkey(scan: number, badScans?: Set<number>): number {
/** typescript fun to index the scan table */
function hasScanCode(key: PropertyKey): key is keyof typeof CLDRScanToUSVirtualKeyCodes {
return key in CLDRScanToUSVirtualKeyCodes;
}
if (hasScanCode(scan)) {
return CLDRScanToUSVirtualKeyCodes[scan];
} else {
badScans?.add(scan);
return undefined;
}
}
/**
* Maps LDML VKey Names from CLDR VKey Enum in TR35 to Keyman virtual key codes
*/
export const LdmlVkeyNames: Record<string, number> = {
'SPACE': k.K_SPACE, // 0x20, // A03
'0': k.K_0, // 0x30, // E10
'1': k.K_1, // 0x31, // E01
'2': k.K_2, // 0x32, // E02
'3': k.K_3, // 0x33, // E03
'4': k.K_4, // 0x34, // E04
'5': k.K_5, // 0x35, // E05
'6': k.K_6, // 0x36, // E06
'7': k.K_7, // 0x37, // E07
'8': k.K_8, // 0x38, // E08
'9': k.K_9, // 0x39, // E09
'A': k.K_A, // 0x41, // C01
'B': k.K_B, // 0x42, // B05
'C': k.K_C, // 0x43, // B03
'D': k.K_D, // 0x44, // C03
'E': k.K_E, // 0x45, // D03
'F': k.K_F, // 0x46, // C04
'G': k.K_G, // 0x47, // C05
'H': k.K_H, // 0x48, // C06
'I': k.K_I, // 0x49, // D08
'J': k.K_J, // 0x4A, // C07
'K': k.K_K, // 0x4B, // C08
'L': k.K_L, // 0x4C, // C09
'M': k.K_M, // 0x4D, // B07
'N': k.K_N, // 0x4E, // B06
'O': k.K_O, // 0x4F, // D09
'P': k.K_P, // 0x50, // D10
'Q': k.K_Q, // 0x51, // D01
'R': k.K_R, // 0x52, // D04
'S': k.K_S, // 0x53, // C02
'T': k.K_T, // 0x54, // D05
'U': k.K_U, // 0x55, // D07
'V': k.K_V, // 0x56, // B05
'W': k.K_W, // 0x57, // D02
'X': k.K_X, // 0x58, // B02
'Y': k.K_Y, // 0x59, // D06
'Z': k.K_Z, // 0x5A, // B01
'SEMICOLON': k.K_COLON, // 0xBA, // C10
'EQUAL': k.K_EQUAL, // 0xBB, // E12
'COMMA': k.K_COMMA, // 0xBC, // B08
'HYPHEN': k.K_HYPHEN, // 0xBD, // E11
'PERIOD': k.K_PERIOD, // 0xBE, // B09
'SLASH': k.K_SLASH, // 0xBF, // B10
'GRAVE': k.K_BKQUOTE, // 0xC0, // E00
'LBRACKET': k.K_LBRKT, // 0xDB, // D11
'BACKSLASH': k.K_BKSLASH, // 0xDC, // D13
'RBRACKET': k.K_RBRKT, // 0xDD, // D12
'QUOTE': k.K_QUOTE, // 0xDE, // C11
'LESS-THAN': k.K_oE2, // 0xE2, // B00 102nd key on European layouts, right of left shift.
'ABNT2': k.k_oC1, // 0xC1, // B11 Extra key, left of right-shift, ABNT2
};

View file

@ -31,11 +31,11 @@ export class ElementString extends Array<ElemElement> {
* @param source if a string array, does not get reinterpreted as UnicodeSet. This is used with vars, etc. Or pass `["str"]` for an explicit 1-element elem.
* If it is a string, will be interpreted per reorder element rules.
*/
constructor(sections: DependencySections, source: string | string[], order?: string, tertiary?: string, tertiary_base?: string, prebase?: string) {
super();
//TODO-LDML: full UnicodeSet and parsing
static fromStrings(sections: DependencySections, source: string | string[], order?: string, tertiary?: string, tertiary_base?: string, prebase?: string) : ElementString {
// the returned array
const array = new ElementString();
if(!source) {
return;
return array;
}
let items : ElementSegment[];
@ -80,16 +80,16 @@ export class ElementString extends Array<ElemElement> {
throw Error(`Could not parse uset ${item.segment}`);
}
elem.uset = sections.uset.allocUset(uset, sections);
elem.value = sections.strs.allocString('', true); // no string
elem.value = sections.strs.allocString('', {singleOk: true}); // no string
} else if (item.type === ElementType.codepoint || item.type === ElementType.escaped || item.type === ElementType.string) {
// some kind of a string
let str = item.segment;
if (item.type === ElementType.escaped && !MATCH_HEX_ESCAPE.test(str)) {
str = unescapeOneQuadString(str);
// TODO-LDML: any other escape forms here?
elem.value = sections.strs.allocString(str, true);
elem.value = sections.strs.allocString(str, { singleOk: true });
} else {
elem.value = sections.strs.allocAndUnescapeString(str, true);
elem.value = sections.strs.allocString(str, { unescape: true, singleOk: true });
}
// Now did we end up with one char or no?
if (elem.value.isOneChar) {
@ -104,8 +104,9 @@ export class ElementString extends Array<ElemElement> {
(ElemElementFlags.type & typeFlag) |
(tertiary_bases?.[i] == '1' /* TODO-LDML: or 'true'? */ ? ElemElementFlags.tertiary_base : 0) |
(prebases?.[i] == '1' /* TODO-LDML: or 'true'? */ ? ElemElementFlags.prebase : 0);
this.push(elem);
array.push(elem);
};
return array;
}
isEqual(a: ElementString): boolean {
if (a.length != this.length) {

View file

@ -13,7 +13,7 @@ import { BUILDER_SECTION } from "./builder-section.js";
* List of layers, the <layers> element
*/
interface BUILDER_LAYR_LIST {
hardware: number; // hardware indicator
hardware: BUILDER_STR_REF; // hardware or 'touch'
layer: number; // index of first layer in the list, in the
count: number; // number of layer entries in the list
minDeviceWidth: number; // width in millimeters
@ -82,7 +82,7 @@ export function build_layr(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS, sect_l
layr.lists = kmxplus.layr.lists.map((list) => {
const blist: BUILDER_LAYR_LIST = {
hardware: list.hardware,
hardware: build_strs_index(sect_strs, list.hardware),
layer: null, // to be set below
_layers: list.layers,
count: list.layers.length,
@ -92,6 +92,7 @@ export function build_layr(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS, sect_l
});
// now sort the lists
layr.lists.sort((a, b) => {
// sort by string #
if (a.hardware < b.hardware) {
return -1;
} else if (a.hardware > b.hardware) {

View file

@ -1,43 +0,0 @@
import { constants } from '@keymanapp/ldml-keyboard-constants';
import { KMXPlusData } from "../kmx-plus.js";
import { BUILDER_SECTION } from './builder-section.js';
/* ------------------------------------------------------------------
* vkey section
------------------------------------------------------------------ */
/**
* Builder for the 'vkey' section
*/
interface BUILDER_VKEY_ITEM {
vkey: number;
target: number;
};
export interface BUILDER_VKEY extends BUILDER_SECTION {
count: number;
items: BUILDER_VKEY_ITEM[];
};
export function build_vkey(kmxplus: KMXPlusData): BUILDER_VKEY {
if(!kmxplus.vkey.vkeys.length) {
return null;
}
let vkey: BUILDER_VKEY = {
ident: constants.hex_section_id(constants.section.vkey),
size: constants.length_vkey + constants.length_vkey_item * kmxplus.vkey.vkeys.length,
_offset: 0,
count: kmxplus.vkey.vkeys.length,
items: []
};
for(let item of kmxplus.vkey.vkeys) {
vkey.items.push({
vkey: item.vkey,
target: item.target
});
}
return vkey;
}

View file

@ -15,7 +15,6 @@ import { BUILDER_STRS, build_strs } from './build-strs.js';
import { BUILDER_TRAN, build_tran } from './build-tran.js';
import { BUILDER_USET, build_uset } from './build-uset.js';
import { BUILDER_VARS, build_vars } from './build-vars.js';
import { BUILDER_VKEY, build_vkey } from './build-vkey.js';
type BUILDER_BKSP = BUILDER_TRAN;
// type BUILDER_FINL = BUILDER_TRAN;
@ -36,7 +35,6 @@ type SectionBuilders = {
tran?: BUILDER_TRAN;
uset?: BUILDER_USET;
vars?: BUILDER_VARS;
vkey?: BUILDER_VKEY;
};
export default class KMXPlusBuilder {
@ -73,7 +71,6 @@ export default class KMXPlusBuilder {
this.emitSection(file, this.file.COMP_PLUS_TRAN, this.sect.tran);
this.emitSection(file, this.file.COMP_PLUS_USET, this.sect.uset);
this.emitSection(file, this.file.COMP_PLUS_VARS, this.sect.vars);
this.emitSection(file, this.file.COMP_PLUS_VKEY, this.sect.vkey);
return file;
}
@ -100,7 +97,6 @@ export default class KMXPlusBuilder {
this.sect.tran = build_tran(this.file.kmxplus.tran, this.sect.strs, this.sect.elem);
this.sect.uset = build_uset(this.file.kmxplus, this.sect.strs);
this.sect.vars = build_vars(this.file.kmxplus, this.sect.strs, this.sect.elem, this.sect.list);
this.sect.vkey = build_vkey(this.file.kmxplus);
// Finalize the sect (index) section
@ -138,7 +134,6 @@ export default class KMXPlusBuilder {
offset = this.finalize_sect_item(this.sect.tran, offset);
offset = this.finalize_sect_item(this.sect.uset, offset);
offset = this.finalize_sect_item(this.sect.vars, offset);
offset = this.finalize_sect_item(this.sect.vkey, offset);
this.sect.sect.total = offset;
}

View file

@ -35,14 +35,14 @@ export class Elem extends Section {
strings: ElementString[] = [];
constructor(sections: DependencySections) {
super();
this.strings.push(new ElementString(sections, '')); // C7043: null element string
this.strings.push(ElementString.fromStrings(sections, '')); // C7043: null element string
}
/**
* @param source if a string array, does not get reinterpreted as UnicodeSet. This is used with vars, etc. Or pass `["str"]` for an explicit 1-element elem.
* If it is a string, will be interpreted per reorder element ruls.
*/
allocElementString(sections: DependencySections, source: string | string[], order?: string, tertiary?: string, tertiary_base?: string, prebase?: string): ElementString {
let s = new ElementString(sections, source, order, tertiary, tertiary_base, prebase);
let s = ElementString.fromStrings(sections, source, order, tertiary, tertiary_base, prebase);
let result = this.strings.find(item => item.isEqual(s));
if(result === undefined) {
result = s;
@ -143,45 +143,67 @@ export class CharStrsItem extends StrsItem {
}
};
/** class for string manipulation options. These are in order of the pipeline. */
export interface StrsOptions {
/** apply string variables (requires sections) */
stringVariables?: boolean;
/** apply markers (requires sections) */
markers?: boolean;
/** unescape with unescapeString */
unescape?: boolean;
/** string can be stored as a single CharStrsItem, not in strs table. */
singleOk?: boolean;
};
export class Strs extends Section {
strings: StrsItem[] = [ new StrsItem('') ]; // C7043: The null string is always requierd
/**
* Allocate a StrsItem given the string, unescaping if necessary.
* @param s escaped string
* @param singleOk if true, allocate a CharStrsItem (not in strs table) if single-char capable.
* @returns
* @param opts options for allocation
* @param sections other sections, if needed
* @returns StrsItem
*/
allocAndUnescapeString(s?: string, singleOk?: boolean): StrsItem {
return this.allocString(unescapeString(s), singleOk);
}
/**
* Allocate a StrsItem given the string.
* @param s string
* @param singleOk if true, allocate a CharStrsItem (not in strs table) if single-char capable.
* @returns
*/
allocString(s?: string, singleOk?: boolean): StrsItem {
if(s === undefined || s === null) {
// undefined or null are always equivalent to empty string, see C7043
s = '';
}
allocString(s?: string, opts?: StrsOptions, sections?: DependencySections): StrsItem {
// Run the string processing pipeline
s = Strs.processString(s, opts, sections);
if(typeof s !== 'string') {
throw new Error('alloc_string: s must be a string, undefined, or null.');
}
// if it's a single char, don't push it into the list
if (singleOk && isOneChar(s)) {
// if it's a single char, don't push it into the strs table
if (opts?.singleOk && isOneChar(s)) {
return new CharStrsItem(s);
}
// default: look to see if the string is already present
let result = this.strings.find(item => item.value === s);
if(result === undefined) {
// only add if not already present
result = new StrsItem(s);
this.strings.push(result);
}
return result;
}
/** process everything according to opts */
static processString(s: string, opts: StrsOptions, sections: DependencySections) {
s = s ?? '';
// type check everything else
if (typeof s !== 'string') {
throw new Error('alloc_string: s must be a string, undefined, or null.');
}
// substitute variables
if (opts?.stringVariables) {
s = sections.vars.substituteStrings(s, sections);
}
// substitute markers
if (opts?.markers) {
s = sections.vars.substituteMarkerString(s);
}
// unescape \u{…}
if (opts?.unescape) {
s = unescapeString(s);
}
return s;
}
};
/**
@ -234,6 +256,7 @@ export class Vars extends Section {
});
}
substituteStrings(str: string, sections: DependencySections): string {
if (!str) return str;
return str.replaceAll(VariableParser.STRING_REFERENCE, (_entire, id) => {
const val = this.findStringVariableValue(id);
if (val === null) {
@ -293,8 +316,8 @@ export class Vars extends Section {
return v[0];
}
}
substituteMarkerString(s : string) : string {
return MarkerParser.toSentinelString(s, this.markers);
substituteMarkerString(s : string, forMatch? : boolean) : string {
return MarkerParser.toSentinelString(s, this.markers, forMatch);
}
};
@ -309,7 +332,7 @@ export class VarsItem extends Section {
constructor(id: string, value: string, sections: DependencySections) {
super();
this.id = sections.strs.allocString(id);
this.value = sections.strs.allocAndUnescapeString(value);
this.value = sections.strs.allocString(value, {unescape: true});
}
valid() : boolean {
@ -404,17 +427,6 @@ export class Bksp extends Tran {
}
};
// 'vkey'
export class VkeyItem {
vkey: number;
target: number;
}
export class Vkey extends Section {
vkeys: VkeyItem[] = [];
};
// 'disp'
export class DispItem {
to: StrsItem;
@ -433,7 +445,7 @@ export class Disp extends Section {
* In-memory `<layers>`
*/
export class LayrList {
hardware: number;
hardware: StrsItem;
layers: LayrEntry[] = [];
minDeviceWidth: number; // millimeters
};
@ -510,19 +522,14 @@ export class List extends Section {
* Allocate a list from a space-separated list of items.
* Note that passing undefined or null or `''` will
* end up being the same as the empty list `[]`
* @param strs Strs section for allocation
* @param s space-separated list of items
* @param opts string options
* @param sections sections
* @returns a List object
*/
allocListFromSpaces(strs: Strs, s?: string): ListItem {
allocListFromSpaces(s: string, opts: StrsOptions, sections: DependencySections): ListItem {
s = s ?? '';
return this.allocList(strs, s.split(' '));
}
allocListFromEscapedSpaces(strs: Strs, s?: string): ListItem {
if(s === undefined || s === null) {
s = '';
}
return this.allocList(strs, s.split(' ').map(unescapeString));
return this.allocList(s.split(' '), opts, sections);
}
/**
* Return a List object referring to the string list.
@ -532,7 +539,7 @@ export class List extends Section {
* @param s string list to allocate
* @returns
*/
allocList(strs: Strs, s?: string[]): ListItem {
allocList(s: string[], opts: StrsOptions, sections: DependencySections): ListItem {
// Special case the 'null' list for [] or ['']
if (!s || (s.length === 1 && s[0] === '')) {
return this.lists[0];
@ -540,14 +547,14 @@ export class List extends Section {
let result = this.lists.find(item => item.isEqual(s));
if(result === undefined) {
// allocate a new ListItem
result = new ListItem(strs, s);
result = ListItem.fromStrings(s, opts, sections);
this.lists.push(result);
}
return result;
}
constructor(strs: Strs) {
super();
this.lists.push(new ListItem(strs, [])); // C7043: null element string
this.lists.push(ListItem.fromStrings([], {}, { strs })); // C7043: null element string
}
lists: ListItem[] = [];
};
@ -569,7 +576,6 @@ export interface KMXPlusData {
tran?: Tran;
uset?: Uset; // uset is ignored in-memory
vars?: Vars;
vkey?: Vkey;
};
export class KMXPlusFile extends KMXFile {
@ -720,7 +726,7 @@ export class KMXPlusFile extends KMXFile {
});
this.COMP_PLUS_LAYR_LIST = new r.Struct({
hardware: r.uint32le, //enum
hardware: STR_REF, // str: hardware name
layer: r.uint32le, // index into layers
count: r.uint32le,
minDeviceWidth: r.uint32le, // integer: millimeters

View file

@ -144,9 +144,10 @@ export class KMXFile {
public static readonly VERSION_150 = 0x00000F00;
public static readonly VERSION_160 = 0x00001000;
public static readonly VERSION_170 = 0x00001100;
public static readonly VERSION_MIN = this.VERSION_50;
public static readonly VERSION_MAX = this.VERSION_160;
public static readonly VERSION_MAX = this.VERSION_170;
//
// Backspace types

View file

@ -1,5 +1,5 @@
import { OrderedStringList } from 'src/ldml-keyboard/pattern-parser.js';
import { Strs, StrsItem } from './kmx-plus.js';
import { DependencySections, StrsItem, StrsOptions } from './kmx-plus.js';
/**
* A single entry in a ListItem.
@ -27,20 +27,22 @@ export class ListItem extends Array<ListIndex> implements OrderedStringList {
/**
* Construct a new list from an array of strings.
* Use List. This is meant to be called by the List.allocString*() functions.
* @param strs the Strs section is needed to construct this object.
* @param source array of strings
* @param opts string handling options
* @param sections the Strs section is needed to construct this object, and other sections may
* be needed depending on the options
* @returns
*/
constructor(strs: Strs, source: Array<string>) {
super();
if(!source) {
return;
static fromStrings(source: Array<string>, opts: StrsOptions, sections: DependencySections) : ListItem {
const a = new ListItem();
if (!source) {
return a;
}
for (const str of source) {
let index = new ListIndex(strs.allocString(str));
this.push(index);
let index = new ListIndex(sections.strs.allocString(str, opts, sections));
a.push(index);
}
return a;
}
getItemOrder(item: string): number {
return this.findIndex(({value}) => value.value === item);
@ -72,12 +74,13 @@ export class ListItem extends Array<ListIndex> implements OrderedStringList {
return 0;
}
}
/** for debugging, print as single string */
/** for debugging and tests, print as single string */
toString(): string {
return this.toStringArray().join(' ');
}
/** for debugging, map to string array */
/** for debugging and tests, map to string array */
toStringArray(): string[] {
return this.map(v => v.value.value);
// TODO-LDML: this crashes: return this.map(v => v.toString());
return Array.from(this.values()).map(v => v.toString());
}
};

View file

@ -49,6 +49,7 @@ export interface BUILDER_KVK_KEY {
export const BUILDER_KVK_KEY_Size = 9; // size of fixed elements of BUILDER_KVK_KEY
export const enum BUILDER_KVK_HEADER_FLAGS {
kvkhNone = 0x00, // no flags
kvkh102 = 0x01,
kvkhDisplayUnderlying = 0x02,
kvkhUseUnderlying = 0x04,
@ -122,4 +123,4 @@ export default class KVKFile {
});
}
};
};

View file

@ -2,7 +2,7 @@
///<reference lib="dom" />
import * as xml2js from 'xml2js';
import { LDMLKeyboardXMLSourceFile, LKImport } from './ldml-keyboard-xml.js';
import { LDMLKeyboardXMLSourceFile, LKImport, ImportStatus } from './ldml-keyboard-xml.js';
import { default as AjvModule } from 'ajv';
const Ajv = AjvModule.default; // The actual expected Ajv type.
import { boxXmlArray } from '../util/util.js';
@ -52,11 +52,18 @@ export class LDMLKeyboardXMLSourceFileReader {
if (!source.keyboard3.keys.import) {
source.keyboard3.keys.import = [];
}
if (!source.keyboard3.forms) {
source.keyboard3.forms = {
form: [],
};
}
if (!source.keyboard3.forms.import) {
source.keyboard3.forms.import = [];
}
}
boxXmlArray(source?.keyboard3, 'layers');
boxXmlArray(source?.keyboard3?.displays, 'display');
boxXmlArray(source?.keyboard3?.names, 'name');
boxXmlArray(source?.keyboard3?.vkeys, 'vkey');
boxXmlArray(source?.keyboard3?.keys, 'key');
boxXmlArray(source?.keyboard3?.keys, 'flicks');
boxXmlArray(source?.keyboard3?.locales, 'locale');
@ -71,6 +78,12 @@ export class LDMLKeyboardXMLSourceFileReader {
}
}
}
if(source?.keyboard3?.forms?.form) {
boxXmlArray(source?.keyboard3?.forms, 'form');
for(let form of source?.keyboard3?.forms?.form) {
boxXmlArray(form, 'scanCodes');
}
}
if(source?.keyboard3?.keys?.flicks) {
for(let flicks of source?.keyboard3?.keys?.flicks) {
boxXmlArray(flicks, 'flick');
@ -152,7 +165,15 @@ export class LDMLKeyboardXMLSourceFileReader {
if (!this.resolveOneImport(obj, subtag, {
base: constants.cldr_import_base,
path: constants.cldr_implied_keys_import
})) {
}, true)) {
return false;
}
} else if (subtag === 'forms') {
// <import base="cldr" path="techpreview/scanCodes-implied.xml"/>
if (!this.resolveOneImport(obj, subtag, {
base: constants.cldr_import_base,
path: constants.cldr_implied_forms_import
}, true)) {
return false;
}
}
@ -163,9 +184,10 @@ export class LDMLKeyboardXMLSourceFileReader {
* @param obj the object being imported into
* @param subtag obj's element tag, e.g. `keys`
* @param asImport the import structure
* @param implied true if it is an implied import
* @returns true on success, false on failure
*/
private resolveOneImport(obj: any, subtag: string, asImport: LKImport) : boolean {
private resolveOneImport(obj: any, subtag: string, asImport: LKImport, implied? : boolean) : boolean {
const { base, path } = asImport;
if (base !== constants.cldr_import_base) {
this.callbacks.reportMessage(CommonTypesMessages.Error_ImportInvalidBase({base, path, subtag}));
@ -192,12 +214,20 @@ export class LDMLKeyboardXMLSourceFileReader {
// pull all children of importXml[subtag] into obj
for (const subsubtag of Object.keys(importRootNode).reverse()) { // e.g. <key/>
const subsubval = importRootNode[subsubtag];
const basePath = `${base}/${path}`;
if (!Array.isArray(subsubval)) {
// This is somewhat of an internal error, indicating that a non-mergeable XML file was imported
// Not exercisable with the standard LDML imports.
this.callbacks.reportMessage(CommonTypesMessages.Error_ImportMergeFail({base, path, subtag, subsubtag}));
return false;
}
// Mark all children as an import
subsubval.forEach(o => o[ImportStatus.import] = basePath);
if (implied) {
// mark all children as an implied import
subsubval.forEach(o => o[ImportStatus.impliedImport] = basePath);
}
if (!obj[subsubtag]) {
obj[subsubtag] = []; // start with empty array
}

View file

@ -12,7 +12,7 @@ export interface LDMLKeyboardXMLSourceFile {
* <keyboard> -- the root element.
*/
keyboard3: LKKeyboard;
}
};
export interface LKKeyboard {
locale?: string;
@ -24,9 +24,9 @@ export interface LKKeyboard {
names?: LKNames;
settings?: LKSettings;
keys?: LKKeys;
forms?: LKForms;
displays?: LKDisplays;
layers?: LKLayers[];
vkeys?: LKVkeys;
variables?: LKVariables;
transforms?: LKTransforms[];
};
@ -128,15 +128,6 @@ export interface LKRow {
keys?: string;
};
export interface LKVkeys {
vkey?: LKVkey[];
};
export interface LKVkey {
from?: string;
to?: string;
};
export interface LKVariables {
string?: LKString[];
set?: LKSet[];
@ -193,3 +184,36 @@ export interface LKDisplays {
display?: LKDisplay[];
displayOptions?: LKDisplayOptions;
};
export interface LKForms {
form?: LKForm[];
};
export interface LKForm {
id?: string;
scanCodes?: LKScanCodes[];
};
export interface LKScanCodes {
codes?: string;
};
/**
* Utilities for determining the import status of items
*/
export class ImportStatus {
/** item came in via implied (spec based) import, such as keys-Latn-implied.xml */
static impliedImport = Symbol('LDML implied import');
/** item came in via import */
static import = Symbol('LDML import');
/** @returns true if the object was loaded through an implied import */
static isImpliedImport(o : any) : boolean {
return o && !!o[ImportStatus.impliedImport];
}
/** @returns true if the object was loaded through an explicit import */
static isImport(o : any) : boolean {
return o && !!o[ImportStatus.import];
}
};

View file

@ -65,6 +65,15 @@ export class MarkerParser {
/** Max count of markers */
public static readonly MAX_MARKER_COUNT = constants.marker_max_count;
private static anyMarkerMatch() : string {
const start = (`0000` + (this.MIN_MARKER_INDEX).toString(16)).slice(-4);
const end = (`0000` + (this.MAX_MARKER_INDEX).toString(16)).slice(-4);
return `${this.SENTINEL}${this.MARKER_CODE}[\\u${start}-\\u${end}]`;
}
/** Expression that matches any marker */
public static readonly ANY_MARKER_MATCH = MarkerParser.anyMarkerMatch();
/**
* Pattern for matching a marker reference, OR the special marker \m{.}
*/
@ -91,10 +100,13 @@ export class MarkerParser {
}
/** @returns all marker strings as sentinel values */
public static toSentinelString(s: string, markers?: OrderedStringList) : string {
public static toSentinelString(s: string, markers?: OrderedStringList, forMatch?: boolean) : string {
if (!s) return s;
return s.replaceAll(this.REFERENCE, (sub, arg) => {
if (arg === MarkerParser.ANY_MARKER_ID) {
if (forMatch) {
return this.ANY_MARKER_MATCH;
}
return MarkerParser.markerOutput(MarkerParser.ANY_MARKER_INDEX);
}
if (!markers) {
@ -103,10 +115,10 @@ export class MarkerParser {
const order = markers.getItemOrder(arg);
if (order === -1) {
throw RangeError(`Internal Error: Could not find marker \\m{${arg}}`);
} else if(order >= MarkerParser.MAX_MARKER_INDEX) {
} else if(order > MarkerParser.MAX_MARKER_INDEX) {
throw RangeError(`Internal Error: marker \\m{${arg}} has out of range index ${order}`);
} else {
return MarkerParser.markerOutput(order+1);
return MarkerParser.markerOutput(order + 1);
}
});
}

View file

@ -1,8 +1,9 @@
import { LKKey } from './../../src/ldml-keyboard/ldml-keyboard-xml.js';
import { LKKey, ImportStatus } from './../../src/ldml-keyboard/ldml-keyboard-xml.js';
import 'mocha';
import {assert} from 'chai';
import { CommonTypesMessages } from '../../src/util/common-events.js';
import { testReaderCases } from '../helpers/reader-callback-test.js';
import { CLDRScanToVkey, CLDRScanToKeyMap, USVirtualKeyCodes } from '../../src/consts/virtual-key-constants.js';
function pluckKeysFromKeybag(keys: LKKey[], ids: string[]) {
return keys.filter(({id}) => ids.indexOf(id) !== -1);
@ -40,6 +41,9 @@ describe('ldml keyboard xml reader tests', function () {
{id: 'b', to: 'b'},
{id: 'c', to: 'c'},
]);
// all of the keys are implied imports here
assert.isTrue(ImportStatus.isImpliedImport(source?.keyboard3?.keys.key.find(({id}) => id === 'a')));
assert.isTrue(ImportStatus.isImport(source?.keyboard3?.keys.key.find(({id}) => id === 'a')));
},
},
{
@ -81,6 +85,15 @@ describe('ldml keyboard xml reader tests', function () {
{id: 'zz', to: 'zz'}, // new key
{id: 'hash', to: '##'}, // override
]);
// 'a' is an implied import
assert.isTrue(ImportStatus.isImpliedImport(k.find(({id}) => id === 'a')));
assert.isTrue(ImportStatus.isImport(k.find(({id}) => id === 'a')));
// 'hash' is an import but not implied
assert.isFalse(ImportStatus.isImpliedImport(k.find(({id}) => id === 'hash')));
assert.isTrue(ImportStatus.isImport(k.find(({id}) => id === 'hash')));
// 'zz' is not imported
assert.isFalse(ImportStatus.isImpliedImport(k.find(({id}) => id === 'zz')));
assert.isFalse(ImportStatus.isImport(k.find(({id}) => id === 'zz')));
},
},
{
@ -129,3 +142,41 @@ describe('ldml keyboard xml reader tests', function () {
},
]);
});
describe('check scan code routines', () => {
it('should be able to detect bad single scancodes', () => {
const badScans = new Set<number>();
const ckey = CLDRScanToVkey(0xFF, badScans);
assert.isUndefined(ckey, `expected undefined 0xFF`);
assert.equal(badScans.size, 1);
assert.sameDeepMembers(Array.from(badScans.values()), [0xFF]);
});
it('should be able to detect bad list scancodes', () => {
const badScans = new Set<number>();
const ckeys = CLDRScanToKeyMap([[0x02, 0xFF]], badScans);
assert.sameDeepMembers(ckeys, [[49, undefined]]);
assert.equal(badScans.size, 1);
assert.sameDeepMembers(Array.from(badScans.values()), [0xFF]);
});
it('CLDRScanToUSVirtualKeyCodes should be 1:1', () => {
const vkeyToScan = new Map<number, number>();
// check all scancodes
for (let scan = 0; scan <= 0xFF; scan++) {
const vkey = CLDRScanToVkey(scan);
if (vkey === undefined) {
// not mapped, which is OK
continue;
}
if (scan === 0x56 || scan === 0x7D) {
// These both can map to this scancode
assert.equal(vkey, USVirtualKeyCodes.K_oE2);
} else {
// don't check those exceptions
assert.isFalse(vkeyToScan.has(vkey),
`vkey ${vkey} mapped from more than one scancode: ${Number(vkeyToScan.get(vkey)).toString(16)} and ${Number(scan).toString(16)}`);
}
// do make sure nothing else maps to that vkey
vkeyToScan.set(vkey, scan);
}
});
});

View file

@ -75,6 +75,7 @@ describe('Test of Pattern Parsers', () => {
'a': 0,
'b': 1,
'c': 2,
'zz': MarkerParser.MAX_MARKER_INDEX - 1, // this is an ordering, so needs to be -1
'zzz': 0x2FFFFF,
};
const o = m[item];
@ -103,6 +104,21 @@ describe('Test of Pattern Parsers', () => {
markers
)
);
// verify the matching behavior of these
assert.isTrue(new RegExp(MarkerParser.toSentinelString(`^Q\\m{a}$`, markers, true), 'u')
.test(MarkerParser.toSentinelString(`Q\\m{a}`, markers, false)), `Q\\m{a} did not match`);
assert.isFalse(new RegExp(MarkerParser.toSentinelString(`^Q\\m{a}$`, markers, true), 'u')
.test(MarkerParser.toSentinelString(`Q\\m{b}`, markers, false)), `Q\\m{a} should not match Q\\m{b}`);
assert.isTrue(new RegExp(MarkerParser.toSentinelString(`^Q\\m{.}$`, markers, true), 'u')
.test(MarkerParser.toSentinelString(`Q\\m{a}`, markers, false)), `Q\\m{.} did not match Q\\m{a}`);
assert.isTrue(new RegExp(MarkerParser.toSentinelString(`^Q\\m{.}$`, markers, true), 'u')
.test(MarkerParser.toSentinelString(`Q\\m{zz}`, markers, false)), `Q\\m{.} did not match Q\\m{zz} (max marker)`);
assert.isFalse(new RegExp(MarkerParser.toSentinelString(`^Q\\m{.}$`, markers, true), 'u')
.test(MarkerParser.toSentinelString(`\\m{a}`, markers, false)), `Q\\m{.} did not match \\m{a}`);
assert.isTrue(new RegExp(MarkerParser.toSentinelString(`^\\m{.}$`, markers, true), 'u')
.test(MarkerParser.toSentinelString(`\\m{a}`, markers, false)), `\\m{.} did not match \\m{a}`);
assert.isFalse(new RegExp(MarkerParser.toSentinelString(`^\\m{.}$`, markers, true), 'u')
.test(MarkerParser.toSentinelString(`\\m{a}\\m{b}`, markers, false)), `\\m{.} did not match \\m{a}\\m{b}`);
});
it('should match some marker constants', () => {
assert.equal(constants.uc_sentinel, KMXFile.UC_SENTINEL);

View file

@ -1,5 +1,5 @@
{
"extends": "../../../../tsconfig.esm-base.json",
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
"rootDir": ".",

View file

@ -1,5 +1,5 @@
{
"extends": "../../../tsconfig.esm-base.json",
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "build/src/",

View file

@ -74,8 +74,9 @@
#define VERSION_140 0x00000E00
#define VERSION_150 0x00000F00
#define VERSION_160 0x00001000
#define VERSION_170 0x00001100
#define VERSION_MIN VERSION_50
#define VERSION_MAX VERSION_160
#define VERSION_MAX VERSION_170
/*
Special flag for WM_CHAR/WM_KEY???/WM_SYSKEY???: says that key has been

View file

@ -4,7 +4,8 @@
!include ..\..\..\Defines.mak
build: dirs # version.res manifest.res
build: dirs
# version.res manifest.res
$(DELPHI_MSBUILD) SentryClientTest.dproj "/p:Platform=Win32"
$(DELPHI_MSBUILD) SentryClientVclTest.dproj "/p:Platform=Win32"

View file

@ -99,9 +99,10 @@ const
VERSION_140 = $00000E00;
VERSION_150 = $00000F00;
VERSION_160 = $00001000;
VERSION_170 = $00001100;
VERSION_MIN = VERSION_50;
VERSION_MAX = VERSION_160;
VERSION_MAX = VERSION_170;
VERSION_MASK_MINOR = $00FF;
VERSION_MASK_MAJOR = $FF00;

View file

@ -7,7 +7,7 @@ NOTARGET_SIGNCODE=yes
!ifdef NODELPHI
TARGETS=.virtual
!else
TARGETS=build_standards_data buildunidata devtools sentrytool test-klog
TARGETS=build_standards_data buildunidata devtools sentrytool test-klog verify_signatures
!endif
CLEANS=clean-tools
@ -28,6 +28,10 @@ buildunidata: .virtual
cd $(COMMON_ROOT)\tools\buildunidata
$(MAKE) $(TARGET)
verify_signatures: .virtual
cd $(COMMON_ROOT)\tools\verify_signatures
$(MAKE) $(TARGET)
devtools: .virtual
!ifdef NODELPHI
echo Skipping devtools

View file

@ -0,0 +1,13 @@
#
# test for signatures and version information being correct in ?install directory or ?bin directory
#
!include ..\..\Defines.mak
build:
$(DELPHI_MSBUILD) verify_signatures.dproj
copy sigcheck.bin $(WIN32_TARGET_PATH)\sigcheck.exe
clean: def-clean
!include ..\..\Target.mak

View file

@ -1,4 +1,4 @@
program verify;
program verify_signatures;
{$APPTYPE CONSOLE}
@ -36,6 +36,7 @@ begin
Delete(s,1,1);
end;
// TODO: sign these files and move the check down to the EndsWith node test
if str[0].ToLower.Contains('sentry.') or str[0].ToLower.Contains('crashpad_handler') or str[0].ToLower.Contains('keymanmc') then
// We don't verify sentry.dll or sentry.x64.dll or crashpad_handler.exe because they're not our files
// We don't verify keymanmc.dll because it has no version resources, as it is mc-generated
@ -62,6 +63,14 @@ begin
end;
end;
if str[0].ToLower.EndsWith('node') then
begin
// It's one of the node addons -- in developer server at time of writing
// we don't have a version resource but we have signed it, so treat it
// as valid
Exit('');
end;
if str[3] <> 'SIL International' then
begin
Exit('File has wrong company name');
@ -90,7 +99,7 @@ begin
if (ParamStr(1) = '-?') or (ParamCount < 1) then
begin
writeln('verify [-d] VERSION.md: Verify the output of sigcheck to ensure all executables are signed and have proper version.');
writeln('verify_signatures [-d] VERSION.md: Verify the output of sigcheck to ensure all executables are signed and have proper version.');
writeln(' -d: Check the timestamp on the signature is less than 2 days old.');
writeln(' VERSION.md: path to the version to verify against');
Halt(2);

View file

@ -3,7 +3,7 @@
<ProjectGuid>{A6DCA558-8DD0-4FFF-8DAE-F305AB8D2AF4}</ProjectGuid>
<ProjectVersion>18.8</ProjectVersion>
<FrameworkType>None</FrameworkType>
<MainSource>verify.dpr</MainSource>
<MainSource>verify_signatures.dpr</MainSource>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
@ -45,7 +45,7 @@
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<SanitizedProjectName>verify</SanitizedProjectName>
<SanitizedProjectName>verify_signatures</SanitizedProjectName>
<Icns_MainIcns>$(BDS)\bin\delphi_PROJECTICNS.icns</Icns_MainIcns>
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
<DCC_UsePackage>bindcompfmx;fmx;rtl;dbrtl;DbxClientDriver;bindcomp;inetdb;DBXInterBaseDriver;xmlrtl;DbxCommonDriver;DBXMySQLDriver;dbxcds;soaprtl;bindengine;CustomIPTransport;dsnap;fmxase;inet;fmxobj;inetdbxpress;fmxdae;dbexpress;$(DCC_UsePackage)</DCC_UsePackage>
@ -161,7 +161,7 @@
<VersionInfoKeys Name="Comments"/>
</VersionInfoKeys>
<Source>
<Source Name="MainSource">verify.dpr</Source>
<Source Name="MainSource">verify_signatures.dpr</Source>
</Source>
<Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k260.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>

View file

@ -11,7 +11,18 @@ do_clean() {
# clean: note build/<target> will be left, but build/<target>/<configuration> should be gone
local target=$1
builder_start_action clean:$target || return 0
rm -rf "$MESON_PATH"
# Removes ICU cached components so it will be re-downloaded and built. Note:
# we could use `git clean`, but this clarifies exactly what is deleted, and
# but we try not to use git commands in build scripts, to maintain clear
# responsibility
rm -rf \
"$THIS_SCRIPT_PATH/subprojects/icu" \
"$THIS_SCRIPT_PATH/subprojects/*.tgz" \
"$THIS_SCRIPT_PATH/subprojects/*.zip"
builder_finish_action success clean:$target
}

View file

@ -4,7 +4,7 @@
"sitemap": "@doc_dir@/sitemap.txt",
"index": "@doc_dir@/markdown_files/index.md",
"c_sources": [
"@include_dir@/keyman/keyboardprocessor.h"
"@include_dir@/keyman/keyman_core_api.h"
],
"c_include_directories": [
"@include_dir@",

View file

@ -47,7 +47,7 @@
}
},
"properties": {
"$schema": { "const": "keyman/keyboardprocessor/doc/introspection.schema" },
"$schema": { "const": "keyman/core/doc/introspection.schema" },
"keyboard": { "$ref": "#/definitions/keyboard" },
"options": {
"type": "object",

View file

@ -46,7 +46,7 @@ A virtual key board event and modifier map recevied from the Platform layer to b
processed with the state object for this Client application.
- __Virtual Key:__
A code based on the US English layout, with values matching the Windows
virtual key codes. See `keyboardprocessor_vkeys.h` for definitions.
virtual key codes. See `keyman_core_api_vkeys.h` for definitions.
- __Modifier Key:__
The set of Control, Shift, Alt, Caps Lock keys. On some platforms these may
have other names (e.g. Alt is called Option on macOS); other platform-specific
@ -58,4 +58,4 @@ Caps Lock.
### Namespace
All calls, types and enums are prefixed with the namespace identifier `km_kbp_`
All calls, types and enums are prefixed with the namespace identifier `km_core_`

View file

@ -18,7 +18,7 @@ if hotdoc.found()
output: 'hotdoc.json',
configuration: cfg)
deps = files(
'../include/keyman/keyboardprocessor.h',
'../include/keyman/keyman_core_api.h',
'../src/jsonpp.hpp',
'../src/utfcodec.hpp'
)

View file

@ -1,9 +0,0 @@
#pragma once
// Defined environment options for KMX processor
#define KM_KBP_KMX_ENV_PLATFORM u"platform"
#define KM_KBP_KMX_ENV_BASELAYOUT u"baseLayout"
#define KM_KBP_KMX_ENV_BASELAYOUTALT u"baseLayoutAlt"
#define KM_KBP_KMX_ENV_SIMULATEALTGR u"simulateAltgr"
#define KM_KBP_KMX_ENV_CAPSLOCK u"capsLock"
#define KM_KBP_KMX_ENV_BASELAYOUTGIVESCTRLRALTFORRALT u"baseLayoutGivesCtrlRAltForRAlt"

View file

@ -1,15 +0,0 @@
#define km_kbp_version_stringify(x) km_kbp_version_to_string(x)
#define km_kbp_version_to_string(x) #x
// Product versioning
#define KM_KBP_VERSION_MAJOR @majorver@
#define KM_KBP_VERSION_MINOR @minorver@
#define KM_KBP_VERSION_PATCH @patchver@
#define KM_KBP_VERSION_STRING km_kbp_version_stringify(@majorver@ ## . ## @minorver@ ## . ## @patchver@ ## .0)
// API versioning
#define KM_KBP_LIB_CURRENT @lib_curr@
#define KM_KBP_LIB_AGE @lib_age@
#define KM_KBP_LIB_REVISION @lib_rev@

View file

@ -1,312 +0,0 @@
/*
Copyright: © 2018 SIL International.
Description: API declarations for modifier keys, handy access masks and
Keyman VKEY names. These follow the same keytop->code
associations as the Windows API. This is a separate header to
maintain readability of the primary API header.
Create Date: 17 Oct 2018
Authors: Tim Eves (TSE)
History: 17 Oct 2018 - TSE - Moved & refactored km_kbp_modifier_state
from keyboardprocessor.h.
- Added VKey and mask definitions.
6 Oct 2018 - TSE - Move into keyman folder.
*/
#pragma once
enum km_kbp_modifier_state {
KM_KBP_MODIFIER_LCTRL = 1 << 0,
KM_KBP_MODIFIER_RCTRL = 1 << 1,
KM_KBP_MODIFIER_LALT = 1 << 2,
KM_KBP_MODIFIER_RALT = 1 << 3,
KM_KBP_MODIFIER_SHIFT = 1 << 4,
KM_KBP_MODIFIER_CTRL = 1 << 5,
KM_KBP_MODIFIER_ALT = 1 << 6,
/*
KM_KBP_MODIFIER_META = 1 << 7, // Either Meta-key flag (tentative). Not usable by keyboards currently
// Used internally (currently, only by KMW) to ensure Meta-key
// shortcuts safely bypass rules
// Meta key = Command key on macOS, Windows key on Windows
*/
KM_KBP_MODIFIER_CAPS = 1 << 8,
KM_KBP_MODIFIER_NOCAPS = 1 << 9,
/*
KM_KBP_MODIFIER_NUMLOCK = 1 << 10,
KM_KBP_MODIFIER_NONUMLOCK = 1 << 11,
KM_KBP_MODIFIER_SCROLLOCK = 1 << 12,
KM_KBP_MODIFIER_NOSCROLLOCK = 1 << 13,
KM_KBP_MODIFIER_VIRTUALKEY = 1 << 14,
*/
};
enum km_kbp_modifier_mask {
KM_KBP_MODIFIER_MASK_ALL = 0x7f,
KM_KBP_MODIFIER_MASK_ALT_GR_SIM = KM_KBP_MODIFIER_LCTRL|KM_KBP_MODIFIER_LALT,
KM_KBP_MODIFIER_MASK_CHIRAL = 0x1f,
KM_KBP_MODIFIER_MASK_IS_CHIRAL = 0x0f,
KM_KBP_MODIFIER_MASK_NON_CHIRAL = 0x7f,
KM_KBP_MODIFIER_MASK_CAPS = 0x0300,
/*KM_KBP_MODIFIER_MASK_NUMLOCK = 0x0C00,
KM_KBP_MODIFIER_MASK_SCROLLLOCK = 0x3000,*/
};
// These are Windows API VKEYs, using Keyman VKEY names.
enum km_kpb_virtual_key {
KM_KBP_VKEY__00,
KM_KBP_VKEY_LBUTTON,
KM_KBP_VKEY_RBUTTON,
KM_KBP_VKEY_CANCEL,
KM_KBP_VKEY_MBUTTON,
KM_KBP_VKEY__05,
KM_KBP_VKEY__06,
KM_KBP_VKEY__07,
KM_KBP_VKEY_BKSP,
KM_KBP_VKEY_TAB,
KM_KBP_VKEY__0A,
KM_KBP_VKEY__0B,
KM_KBP_VKEY_KP5,
KM_KBP_VKEY_ENTER,
KM_KBP_VKEY__0E,
KM_KBP_VKEY__0F,
KM_KBP_VKEY_SHIFT,
KM_KBP_VKEY_CONTROL,
KM_KBP_VKEY_ALT,
KM_KBP_VKEY_PAUSE,
KM_KBP_VKEY_CAPS,
KM_KBP_VKEY__15,
KM_KBP_VKEY__16,
KM_KBP_VKEY__17,
KM_KBP_VKEY__18,
KM_KBP_VKEY__19,
KM_KBP_VKEY__1A,
KM_KBP_VKEY_ESC,
KM_KBP_VKEY__1C,
KM_KBP_VKEY__1D,
KM_KBP_VKEY__1E,
KM_KBP_VKEY__1F,
KM_KBP_VKEY_SPACE,
KM_KBP_VKEY_PGUP,
KM_KBP_VKEY_PGDN,
KM_KBP_VKEY_END,
KM_KBP_VKEY_HOME,
KM_KBP_VKEY_LEFT,
KM_KBP_VKEY_UP,
KM_KBP_VKEY_RIGHT,
KM_KBP_VKEY_DOWN,
KM_KBP_VKEY_SEL,
KM_KBP_VKEY_PRINT,
KM_KBP_VKEY_EXEC,
KM_KBP_VKEY_PRTSCN,
KM_KBP_VKEY_INS,
KM_KBP_VKEY_DEL,
KM_KBP_VKEY_HELP,
KM_KBP_VKEY_0,
KM_KBP_VKEY_1,
KM_KBP_VKEY_2,
KM_KBP_VKEY_3,
KM_KBP_VKEY_4,
KM_KBP_VKEY_5,
KM_KBP_VKEY_6,
KM_KBP_VKEY_7,
KM_KBP_VKEY_8,
KM_KBP_VKEY_9,
KM_KBP_VKEY__3A,
KM_KBP_VKEY__3B,
KM_KBP_VKEY__3C,
KM_KBP_VKEY__3D,
KM_KBP_VKEY__3E,
KM_KBP_VKEY__3F,
KM_KBP_VKEY__40,
KM_KBP_VKEY_A,
KM_KBP_VKEY_B,
KM_KBP_VKEY_C,
KM_KBP_VKEY_D,
KM_KBP_VKEY_E,
KM_KBP_VKEY_F,
KM_KBP_VKEY_G,
KM_KBP_VKEY_H,
KM_KBP_VKEY_I,
KM_KBP_VKEY_J,
KM_KBP_VKEY_K,
KM_KBP_VKEY_L,
KM_KBP_VKEY_M,
KM_KBP_VKEY_N,
KM_KBP_VKEY_O,
KM_KBP_VKEY_P,
KM_KBP_VKEY_Q,
KM_KBP_VKEY_R,
KM_KBP_VKEY_S,
KM_KBP_VKEY_T,
KM_KBP_VKEY_U,
KM_KBP_VKEY_V,
KM_KBP_VKEY_W,
KM_KBP_VKEY_X,
KM_KBP_VKEY_Y,
KM_KBP_VKEY_Z,
KM_KBP_VKEY__5B,
KM_KBP_VKEY__5C,
KM_KBP_VKEY__5D,
KM_KBP_VKEY__5E,
KM_KBP_VKEY__5F,
KM_KBP_VKEY_NP0,
KM_KBP_VKEY_NP1,
KM_KBP_VKEY_NP2,
KM_KBP_VKEY_NP3,
KM_KBP_VKEY_NP4,
KM_KBP_VKEY_NP5,
KM_KBP_VKEY_NP6,
KM_KBP_VKEY_NP7,
KM_KBP_VKEY_NP8,
KM_KBP_VKEY_NP9,
KM_KBP_VKEY_NPSTAR,
KM_KBP_VKEY_NPPLUS,
KM_KBP_VKEY_SEPARATOR,
KM_KBP_VKEY_NPMINUS,
KM_KBP_VKEY_NPDOT,
KM_KBP_VKEY_NPSLASH,
KM_KBP_VKEY_F1,
KM_KBP_VKEY_F2,
KM_KBP_VKEY_F3,
KM_KBP_VKEY_F4,
KM_KBP_VKEY_F5,
KM_KBP_VKEY_F6,
KM_KBP_VKEY_F7,
KM_KBP_VKEY_F8,
KM_KBP_VKEY_F9,
KM_KBP_VKEY_F10,
KM_KBP_VKEY_F11,
KM_KBP_VKEY_F12,
KM_KBP_VKEY_F13,
KM_KBP_VKEY_F14,
KM_KBP_VKEY_F15,
KM_KBP_VKEY_F16,
KM_KBP_VKEY_F17,
KM_KBP_VKEY_F18,
KM_KBP_VKEY_F19,
KM_KBP_VKEY_F20,
KM_KBP_VKEY_F21,
KM_KBP_VKEY_F22,
KM_KBP_VKEY_F23,
KM_KBP_VKEY_F24,
KM_KBP_VKEY__88,
KM_KBP_VKEY__89,
KM_KBP_VKEY__8A,
KM_KBP_VKEY__8B,
KM_KBP_VKEY__8C,
KM_KBP_VKEY__8D,
KM_KBP_VKEY__8E,
KM_KBP_VKEY__8F,
KM_KBP_VKEY_NUMLOCK,
KM_KBP_VKEY_SCROLL,
KM_KBP_VKEY__92,
KM_KBP_VKEY__93,
KM_KBP_VKEY__94,
KM_KBP_VKEY__95,
KM_KBP_VKEY__96,
KM_KBP_VKEY__97,
KM_KBP_VKEY__98,
KM_KBP_VKEY__99,
KM_KBP_VKEY__9A,
KM_KBP_VKEY__9B,
KM_KBP_VKEY__9C,
KM_KBP_VKEY__9D,
KM_KBP_VKEY__9E,
KM_KBP_VKEY__9F,
KM_KBP_VKEY__A0,
KM_KBP_VKEY__A1,
KM_KBP_VKEY__A2,
KM_KBP_VKEY__A3,
KM_KBP_VKEY__A4,
KM_KBP_VKEY__A5,
KM_KBP_VKEY__A6,
KM_KBP_VKEY__A7,
KM_KBP_VKEY__A8,
KM_KBP_VKEY__A9,
KM_KBP_VKEY__AA,
KM_KBP_VKEY__AB,
KM_KBP_VKEY__AC,
KM_KBP_VKEY__AD,
KM_KBP_VKEY__AE,
KM_KBP_VKEY__AF,
KM_KBP_VKEY__B0,
KM_KBP_VKEY__B1,
KM_KBP_VKEY__B2,
KM_KBP_VKEY__B3,
KM_KBP_VKEY__B4,
KM_KBP_VKEY__B5,
KM_KBP_VKEY__B6,
KM_KBP_VKEY__B7,
KM_KBP_VKEY__B8,
KM_KBP_VKEY__B9,
KM_KBP_VKEY_COLON,
KM_KBP_VKEY_EQUAL,
KM_KBP_VKEY_COMMA,
KM_KBP_VKEY_HYPHEN,
KM_KBP_VKEY_PERIOD,
KM_KBP_VKEY_SLASH,
KM_KBP_VKEY_BKQUOTE,
KM_KBP_VKEY__C1,
KM_KBP_VKEY__C2,
KM_KBP_VKEY__C3,
KM_KBP_VKEY__C4,
KM_KBP_VKEY__C5,
KM_KBP_VKEY__C6,
KM_KBP_VKEY__C7,
KM_KBP_VKEY__C8,
KM_KBP_VKEY__C9,
KM_KBP_VKEY__CA,
KM_KBP_VKEY__CB,
KM_KBP_VKEY__CC,
KM_KBP_VKEY__CD,
KM_KBP_VKEY__CE,
KM_KBP_VKEY__CF,
KM_KBP_VKEY__D0,
KM_KBP_VKEY__D1,
KM_KBP_VKEY__D2,
KM_KBP_VKEY__D3,
KM_KBP_VKEY__D4,
KM_KBP_VKEY__D5,
KM_KBP_VKEY__D6,
KM_KBP_VKEY__D7,
KM_KBP_VKEY__D8,
KM_KBP_VKEY__D9,
KM_KBP_VKEY__DA,
KM_KBP_VKEY_LBRKT,
KM_KBP_VKEY_BKSLASH,
KM_KBP_VKEY_RBRKT,
KM_KBP_VKEY_QUOTE,
KM_KBP_VKEY_oDF,
KM_KBP_VKEY_oE0,
KM_KBP_VKEY_oE1,
KM_KBP_VKEY_oE2, // 102nd key on European layouts
KM_KBP_VKEY_oE3,
KM_KBP_VKEY_oE4,
KM_KBP_VKEY__E5,
KM_KBP_VKEY_oE6,
KM_KBP_VKEY__E7,
KM_KBP_VKEY__E8,
KM_KBP_VKEY_oE9,
KM_KBP_VKEY_oEA,
KM_KBP_VKEY_oEB,
KM_KBP_VKEY_oEC,
KM_KBP_VKEY_oED,
KM_KBP_VKEY_oEE,
KM_KBP_VKEY_oEF,
KM_KBP_VKEY_oF0,
KM_KBP_VKEY_oF1,
KM_KBP_VKEY_oF2,
KM_KBP_VKEY_oF3,
KM_KBP_VKEY_oF4,
KM_KBP_VKEY_oF5,
KM_KBP_VKEY__F6,
KM_KBP_VKEY__F7,
KM_KBP_VKEY__F8,
KM_KBP_VKEY__F9,
KM_KBP_VKEY__FA,
KM_KBP_VKEY__FB,
KM_KBP_VKEY__FC,
KM_KBP_VKEY__FD,
KM_KBP_VKEY__FE,
KM_KBP_VKEY__FF,
};

View file

@ -27,7 +27,7 @@
#endif
#if defined _WIN32 || defined __CYGWIN__
typedef wchar_t const * km_kbp_path_name;
typedef wchar_t const * km_core_path_name;
#define _KM_KBP_PATH_SEPARATOR (L'\\')
#define _KM_KBP_EXT_SEPARATOR (L'.')
#if defined __GNUC__ // These three will be redefined for Windows
@ -43,7 +43,7 @@
#define _kmn_import_flag dllimport
#define _kmn_static_flag
#else
typedef char const * km_kbp_path_name;
typedef char const * km_core_path_name;
#define _KM_KBP_PATH_SEPARATOR ('/')
#define _KM_KBP_EXT_SEPARATOR ('.')
#endif

View file

@ -0,0 +1,9 @@
#pragma once
// Defined environment options for KMX processor
#define KM_CORE_KMX_ENV_PLATFORM u"platform"
#define KM_CORE_KMX_ENV_BASELAYOUT u"baseLayout"
#define KM_CORE_KMX_ENV_BASELAYOUTALT u"baseLayoutAlt"
#define KM_CORE_KMX_ENV_SIMULATEALTGR u"simulateAltgr"
#define KM_CORE_KMX_ENV_CAPSLOCK u"capsLock"
#define KM_CORE_KMX_ENV_BASELAYOUTGIVESCTRLRALTFORRALT u"baseLayoutGivesCtrlRAltForRAlt"

View file

@ -15,8 +15,8 @@
#include <stdint.h>
#include <stdlib.h>
#include <keyman/keyboardprocessor_bits.h>
#include <keyman/keyboardprocessor_vkeys.h>
#include <keyman/keyman_core_api_bits.h>
#include <keyman/keyman_core_api_vkeys.h>
#if defined(__cplusplus)
extern "C"
@ -24,7 +24,7 @@ extern "C"
#endif
/**
* The maximum size of context in km_kbp_cp units for a single debug
* The maximum size of context in km_core_cp units for a single debug
* event. This is taken from MAXCONTEXT in keyman32 (Windows) and is purely
* a convenience value. We can increase it if there is a demonstrated need.
*/
@ -42,31 +42,31 @@ extern "C"
* These modifier flags are used internally in the kmx engine, so will be
* exposed only in debugging modifier states.
*/
#define KM_KBP_MODIFIER_VIRTUALKEY 0x4000
#define KM_KBP_MODIFIER_VIRTUALCHARKEY 0x8000
#define KM_CORE_MODIFIER_VIRTUALKEY 0x4000
#define KM_CORE_MODIFIER_VIRTUALCHARKEY 0x8000
/**
* Input key event data. The `character` member is derived from
* a US English key event for vk + modifier_state, and is 0 if
* the vk + modifier_state do not generate a character.
*
* Used only in event type KM_KBP_DEBUG_BEGIN.
* Used only in event type KM_CORE_DEBUG_BEGIN.
*/
typedef struct {
uint16_t vk;
uint16_t modifier_state;
char16_t character;
} km_kbp_state_debug_key_info;
} km_core_state_debug_key_info;
/**
* Option event data.
*
* Used only in event type KM_KBP_DEBUG_SET_OPTION.
* Used only in event type KM_CORE_DEBUG_SET_OPTION.
*/
typedef struct {
void *store; // LPSTORE
km_kbp_cp value[DEBUG_MAX_CONTEXT]; // value to be saved into the store
} km_kbp_state_debug_kmx_option_info;
km_core_cp value[DEBUG_MAX_CONTEXT]; // value to be saved into the store
} km_core_state_debug_kmx_option_info;
/**
* KMX processor data for each event. kmx_base.h defines the types that are
@ -76,11 +76,11 @@ typedef struct {
* The context value here will be an intermediate value, and may differ
* from event to event as the context can be rewritten for each rule match.
*
* Used in all event types except KM_KBP_DEBUG_BEGIN, KM_KBP_DEBUG_END.
* Used in all event types except KM_CORE_DEBUG_BEGIN, KM_CORE_DEBUG_END.
*/
typedef struct {
km_kbp_cp context[DEBUG_MAX_CONTEXT]; // The context matched by the rule (? may not need this?) // TODO: rename to context_matched
km_core_cp context[DEBUG_MAX_CONTEXT]; // The context matched by the rule (? may not need this?) // TODO: rename to context_matched
void *group; // LPGROUP
void *rule; // LPKEY
uint16_t store_offsets[DEBUG_STORE_OFFSETS_SIZE]; // pairs--store, char position, terminated by 0xFFFF // TODO use a better structure here
@ -89,8 +89,8 @@ typedef struct {
/// the debugger; the debugger uses this to determine when to
/// execute the actions when single-stepping.
uint16_t first_action;
km_kbp_state_debug_kmx_option_info option;
} km_kbp_state_debug_kmx_info;
km_core_state_debug_kmx_option_info option;
} km_core_state_debug_kmx_info;
/**
* A single debug event.
@ -98,38 +98,38 @@ typedef struct {
typedef struct {
uint32_t type; // 32 bits is better optimized than 8 bits
uint32_t flags;
km_kbp_state_debug_key_info key_info;
km_kbp_state_debug_kmx_info kmx_info;
} km_kbp_state_debug_item;
km_core_state_debug_key_info key_info;
km_core_state_debug_kmx_info kmx_info;
} km_core_state_debug_item;
/**
* A single debug event.
*/
enum km_kbp_debug_type {
KM_KBP_DEBUG_BEGIN = 0,
//KM_KBP_DEBUG_BEGIN_ANSI = 1, // not supported; instead rewrite ansi keyboards to Unicode with mcompile
KM_KBP_DEBUG_GROUP_ENTER = 2,
KM_KBP_DEBUG_GROUP_EXIT = 3,
KM_KBP_DEBUG_RULE_ENTER = 4,
KM_KBP_DEBUG_RULE_EXIT = 5,
KM_KBP_DEBUG_MATCH_ENTER = 6,
KM_KBP_DEBUG_MATCH_EXIT = 7,
KM_KBP_DEBUG_NOMATCH_ENTER = 8,
KM_KBP_DEBUG_NOMATCH_EXIT = 9,
KM_KBP_DEBUG_END = 10,
KM_KBP_DEBUG_SET_OPTION = 11,
enum km_core_debug_type {
KM_CORE_DEBUG_BEGIN = 0,
//KM_CORE_DEBUG_BEGIN_ANSI = 1, // not supported; instead rewrite ansi keyboards to Unicode with mcompile
KM_CORE_DEBUG_GROUP_ENTER = 2,
KM_CORE_DEBUG_GROUP_EXIT = 3,
KM_CORE_DEBUG_RULE_ENTER = 4,
KM_CORE_DEBUG_RULE_EXIT = 5,
KM_CORE_DEBUG_MATCH_ENTER = 6,
KM_CORE_DEBUG_MATCH_EXIT = 7,
KM_CORE_DEBUG_NOMATCH_ENTER = 8,
KM_CORE_DEBUG_NOMATCH_EXIT = 9,
KM_CORE_DEBUG_END = 10,
KM_CORE_DEBUG_SET_OPTION = 11,
};
// Flags for KM_KBP_DEBUG_GROUP_EXIT
#define KM_KBP_DEBUG_FLAG_RECURSIVE_OVERFLOW 0x0001
#define KM_KBP_DEBUG_FLAG_NOMATCH 0x0002
// Flags for KM_CORE_DEBUG_GROUP_EXIT
#define KM_CORE_DEBUG_FLAG_RECURSIVE_OVERFLOW 0x0001
#define KM_CORE_DEBUG_FLAG_NOMATCH 0x0002
// Flags for KM_KBP_DEBUG_BEGIN
// Flags for KM_CORE_DEBUG_BEGIN
// TODO: do we need this at all?
#define KM_KBP_DEBUG_FLAG_UNICODE 0x0001 // Always set
#define KM_CORE_DEBUG_FLAG_UNICODE 0x0001 // Always set
// Flags for KM_KBP_DEBUG_END
#define KM_KBP_DEBUG_FLAG_OUTPUTKEYSTROKE 0x0001
// Flags for KM_CORE_DEBUG_END
#define KM_CORE_DEBUG_FLAG_OUTPUTKEYSTROKE 0x0001
/**
* Enable or disable debug tracing
@ -137,11 +137,11 @@ enum km_kbp_debug_type {
* @param state Pointer to initialized state
* @param value Set to 1 to enable debugging, 0 to disable
*
* @returns KM_KBP_STATUS_OK on success
* @returns KM_CORE_STATUS_OK on success
*/
KMN_API
km_kbp_status
km_kbp_state_debug_set(km_kbp_state *state, int value);
km_core_status
km_core_state_debug_set(km_core_state *state, int value);
/**
* Get current debug tracing status
@ -152,7 +152,7 @@ km_kbp_state_debug_set(km_kbp_state *state, int value);
*/
KMN_API
uint8_t
km_kbp_state_debug_get(km_kbp_state const *state);
km_core_state_debug_get(km_core_state const *state);
/**
* Read current debug trace log
@ -162,11 +162,11 @@ km_kbp_state_debug_get(km_kbp_state const *state);
* nullptr if not required.
*
* @returns pointer to read only array of debug item events,
* with last entry guaranteed to be KM_KBP_DEBUG_END.
* with last entry guaranteed to be KM_CORE_DEBUG_END.
*/
KMN_API
km_kbp_state_debug_item const *
km_kbp_state_debug_items(km_kbp_state const *state, size_t *num_items);
km_core_state_debug_item const *
km_core_state_debug_items(km_core_state const *state, size_t *num_items);
#if defined(__cplusplus)
} // extern "C"

View file

@ -0,0 +1,15 @@
#define km_core_version_stringify(x) km_core_version_to_string(x)
#define km_core_version_to_string(x) #x
// Product versioning
#define KM_CORE_VERSION_MAJOR @majorver@
#define KM_CORE_VERSION_MINOR @minorver@
#define KM_CORE_VERSION_PATCH @patchver@
#define KM_CORE_VERSION_STRING km_core_version_stringify(@majorver@ ## . ## @minorver@ ## . ## @patchver@ ## .0)
// API versioning
#define KM_CORE_LIB_CURRENT @lib_curr@
#define KM_CORE_LIB_AGE @lib_age@
#define KM_CORE_LIB_REVISION @lib_rev@

View file

@ -0,0 +1,312 @@
/*
Copyright: © 2018 SIL International.
Description: API declarations for modifier keys, handy access masks and
Keyman VKEY names. These follow the same keytop->code
associations as the Windows API. This is a separate header to
maintain readability of the primary API header.
Create Date: 17 Oct 2018
Authors: Tim Eves (TSE)
History: 17 Oct 2018 - TSE - Moved & refactored km_core_modifier_state
from keyman_core_api.h.
- Added VKey and mask definitions.
6 Oct 2018 - TSE - Move into keyman folder.
*/
#pragma once
enum km_core_modifier_state {
KM_CORE_MODIFIER_LCTRL = 1 << 0,
KM_CORE_MODIFIER_RCTRL = 1 << 1,
KM_CORE_MODIFIER_LALT = 1 << 2,
KM_CORE_MODIFIER_RALT = 1 << 3,
KM_CORE_MODIFIER_SHIFT = 1 << 4,
KM_CORE_MODIFIER_CTRL = 1 << 5,
KM_CORE_MODIFIER_ALT = 1 << 6,
/*
KM_CORE_MODIFIER_META = 1 << 7, // Either Meta-key flag (tentative). Not usable by keyboards currently
// Used internally (currently, only by KMW) to ensure Meta-key
// shortcuts safely bypass rules
// Meta key = Command key on macOS, Windows key on Windows
*/
KM_CORE_MODIFIER_CAPS = 1 << 8,
KM_CORE_MODIFIER_NOCAPS = 1 << 9,
/*
KM_CORE_MODIFIER_NUMLOCK = 1 << 10,
KM_CORE_MODIFIER_NONUMLOCK = 1 << 11,
KM_CORE_MODIFIER_SCROLLOCK = 1 << 12,
KM_CORE_MODIFIER_NOSCROLLOCK = 1 << 13,
KM_CORE_MODIFIER_VIRTUALKEY = 1 << 14,
*/
};
enum km_core_modifier_mask {
KM_CORE_MODIFIER_MASK_ALL = 0x7f,
KM_CORE_MODIFIER_MASK_ALT_GR_SIM = KM_CORE_MODIFIER_LCTRL|KM_CORE_MODIFIER_LALT,
KM_CORE_MODIFIER_MASK_CHIRAL = 0x1f,
KM_CORE_MODIFIER_MASK_IS_CHIRAL = 0x0f,
KM_CORE_MODIFIER_MASK_NON_CHIRAL = 0x7f,
KM_CORE_MODIFIER_MASK_CAPS = 0x0300,
/*KM_CORE_MODIFIER_MASK_NUMLOCK = 0x0C00,
KM_CORE_MODIFIER_MASK_SCROLLLOCK = 0x3000,*/
};
// These are Windows API VKEYs, using Keyman VKEY names.
enum km_kpb_virtual_key {
KM_CORE_VKEY__00,
KM_CORE_VKEY_LBUTTON,
KM_CORE_VKEY_RBUTTON,
KM_CORE_VKEY_CANCEL,
KM_CORE_VKEY_MBUTTON,
KM_CORE_VKEY__05,
KM_CORE_VKEY__06,
KM_CORE_VKEY__07,
KM_CORE_VKEY_BKSP,
KM_CORE_VKEY_TAB,
KM_CORE_VKEY__0A,
KM_CORE_VKEY__0B,
KM_CORE_VKEY_KP5,
KM_CORE_VKEY_ENTER,
KM_CORE_VKEY__0E,
KM_CORE_VKEY__0F,
KM_CORE_VKEY_SHIFT,
KM_CORE_VKEY_CONTROL,
KM_CORE_VKEY_ALT,
KM_CORE_VKEY_PAUSE,
KM_CORE_VKEY_CAPS,
KM_CORE_VKEY__15,
KM_CORE_VKEY__16,
KM_CORE_VKEY__17,
KM_CORE_VKEY__18,
KM_CORE_VKEY__19,
KM_CORE_VKEY__1A,
KM_CORE_VKEY_ESC,
KM_CORE_VKEY__1C,
KM_CORE_VKEY__1D,
KM_CORE_VKEY__1E,
KM_CORE_VKEY__1F,
KM_CORE_VKEY_SPACE,
KM_CORE_VKEY_PGUP,
KM_CORE_VKEY_PGDN,
KM_CORE_VKEY_END,
KM_CORE_VKEY_HOME,
KM_CORE_VKEY_LEFT,
KM_CORE_VKEY_UP,
KM_CORE_VKEY_RIGHT,
KM_CORE_VKEY_DOWN,
KM_CORE_VKEY_SEL,
KM_CORE_VKEY_PRINT,
KM_CORE_VKEY_EXEC,
KM_CORE_VKEY_PRTSCN,
KM_CORE_VKEY_INS,
KM_CORE_VKEY_DEL,
KM_CORE_VKEY_HELP,
KM_CORE_VKEY_0,
KM_CORE_VKEY_1,
KM_CORE_VKEY_2,
KM_CORE_VKEY_3,
KM_CORE_VKEY_4,
KM_CORE_VKEY_5,
KM_CORE_VKEY_6,
KM_CORE_VKEY_7,
KM_CORE_VKEY_8,
KM_CORE_VKEY_9,
KM_CORE_VKEY__3A,
KM_CORE_VKEY__3B,
KM_CORE_VKEY__3C,
KM_CORE_VKEY__3D,
KM_CORE_VKEY__3E,
KM_CORE_VKEY__3F,
KM_CORE_VKEY__40,
KM_CORE_VKEY_A,
KM_CORE_VKEY_B,
KM_CORE_VKEY_C,
KM_CORE_VKEY_D,
KM_CORE_VKEY_E,
KM_CORE_VKEY_F,
KM_CORE_VKEY_G,
KM_CORE_VKEY_H,
KM_CORE_VKEY_I,
KM_CORE_VKEY_J,
KM_CORE_VKEY_K,
KM_CORE_VKEY_L,
KM_CORE_VKEY_M,
KM_CORE_VKEY_N,
KM_CORE_VKEY_O,
KM_CORE_VKEY_P,
KM_CORE_VKEY_Q,
KM_CORE_VKEY_R,
KM_CORE_VKEY_S,
KM_CORE_VKEY_T,
KM_CORE_VKEY_U,
KM_CORE_VKEY_V,
KM_CORE_VKEY_W,
KM_CORE_VKEY_X,
KM_CORE_VKEY_Y,
KM_CORE_VKEY_Z,
KM_CORE_VKEY__5B,
KM_CORE_VKEY__5C,
KM_CORE_VKEY__5D,
KM_CORE_VKEY__5E,
KM_CORE_VKEY__5F,
KM_CORE_VKEY_NP0,
KM_CORE_VKEY_NP1,
KM_CORE_VKEY_NP2,
KM_CORE_VKEY_NP3,
KM_CORE_VKEY_NP4,
KM_CORE_VKEY_NP5,
KM_CORE_VKEY_NP6,
KM_CORE_VKEY_NP7,
KM_CORE_VKEY_NP8,
KM_CORE_VKEY_NP9,
KM_CORE_VKEY_NPSTAR,
KM_CORE_VKEY_NPPLUS,
KM_CORE_VKEY_SEPARATOR,
KM_CORE_VKEY_NPMINUS,
KM_CORE_VKEY_NPDOT,
KM_CORE_VKEY_NPSLASH,
KM_CORE_VKEY_F1,
KM_CORE_VKEY_F2,
KM_CORE_VKEY_F3,
KM_CORE_VKEY_F4,
KM_CORE_VKEY_F5,
KM_CORE_VKEY_F6,
KM_CORE_VKEY_F7,
KM_CORE_VKEY_F8,
KM_CORE_VKEY_F9,
KM_CORE_VKEY_F10,
KM_CORE_VKEY_F11,
KM_CORE_VKEY_F12,
KM_CORE_VKEY_F13,
KM_CORE_VKEY_F14,
KM_CORE_VKEY_F15,
KM_CORE_VKEY_F16,
KM_CORE_VKEY_F17,
KM_CORE_VKEY_F18,
KM_CORE_VKEY_F19,
KM_CORE_VKEY_F20,
KM_CORE_VKEY_F21,
KM_CORE_VKEY_F22,
KM_CORE_VKEY_F23,
KM_CORE_VKEY_F24,
KM_CORE_VKEY__88,
KM_CORE_VKEY__89,
KM_CORE_VKEY__8A,
KM_CORE_VKEY__8B,
KM_CORE_VKEY__8C,
KM_CORE_VKEY__8D,
KM_CORE_VKEY__8E,
KM_CORE_VKEY__8F,
KM_CORE_VKEY_NUMLOCK,
KM_CORE_VKEY_SCROLL,
KM_CORE_VKEY__92,
KM_CORE_VKEY__93,
KM_CORE_VKEY__94,
KM_CORE_VKEY__95,
KM_CORE_VKEY__96,
KM_CORE_VKEY__97,
KM_CORE_VKEY__98,
KM_CORE_VKEY__99,
KM_CORE_VKEY__9A,
KM_CORE_VKEY__9B,
KM_CORE_VKEY__9C,
KM_CORE_VKEY__9D,
KM_CORE_VKEY__9E,
KM_CORE_VKEY__9F,
KM_CORE_VKEY__A0,
KM_CORE_VKEY__A1,
KM_CORE_VKEY__A2,
KM_CORE_VKEY__A3,
KM_CORE_VKEY__A4,
KM_CORE_VKEY__A5,
KM_CORE_VKEY__A6,
KM_CORE_VKEY__A7,
KM_CORE_VKEY__A8,
KM_CORE_VKEY__A9,
KM_CORE_VKEY__AA,
KM_CORE_VKEY__AB,
KM_CORE_VKEY__AC,
KM_CORE_VKEY__AD,
KM_CORE_VKEY__AE,
KM_CORE_VKEY__AF,
KM_CORE_VKEY__B0,
KM_CORE_VKEY__B1,
KM_CORE_VKEY__B2,
KM_CORE_VKEY__B3,
KM_CORE_VKEY__B4,
KM_CORE_VKEY__B5,
KM_CORE_VKEY__B6,
KM_CORE_VKEY__B7,
KM_CORE_VKEY__B8,
KM_CORE_VKEY__B9,
KM_CORE_VKEY_COLON,
KM_CORE_VKEY_EQUAL,
KM_CORE_VKEY_COMMA,
KM_CORE_VKEY_HYPHEN,
KM_CORE_VKEY_PERIOD,
KM_CORE_VKEY_SLASH,
KM_CORE_VKEY_BKQUOTE,
KM_CORE_VKEY__C1,
KM_CORE_VKEY__C2,
KM_CORE_VKEY__C3,
KM_CORE_VKEY__C4,
KM_CORE_VKEY__C5,
KM_CORE_VKEY__C6,
KM_CORE_VKEY__C7,
KM_CORE_VKEY__C8,
KM_CORE_VKEY__C9,
KM_CORE_VKEY__CA,
KM_CORE_VKEY__CB,
KM_CORE_VKEY__CC,
KM_CORE_VKEY__CD,
KM_CORE_VKEY__CE,
KM_CORE_VKEY__CF,
KM_CORE_VKEY__D0,
KM_CORE_VKEY__D1,
KM_CORE_VKEY__D2,
KM_CORE_VKEY__D3,
KM_CORE_VKEY__D4,
KM_CORE_VKEY__D5,
KM_CORE_VKEY__D6,
KM_CORE_VKEY__D7,
KM_CORE_VKEY__D8,
KM_CORE_VKEY__D9,
KM_CORE_VKEY__DA,
KM_CORE_VKEY_LBRKT,
KM_CORE_VKEY_BKSLASH,
KM_CORE_VKEY_RBRKT,
KM_CORE_VKEY_QUOTE,
KM_CORE_VKEY_oDF,
KM_CORE_VKEY_oE0,
KM_CORE_VKEY_oE1,
KM_CORE_VKEY_oE2, // 102nd key on European layouts
KM_CORE_VKEY_oE3,
KM_CORE_VKEY_oE4,
KM_CORE_VKEY__E5,
KM_CORE_VKEY_oE6,
KM_CORE_VKEY__E7,
KM_CORE_VKEY__E8,
KM_CORE_VKEY_oE9,
KM_CORE_VKEY_oEA,
KM_CORE_VKEY_oEB,
KM_CORE_VKEY_oEC,
KM_CORE_VKEY_oED,
KM_CORE_VKEY_oEE,
KM_CORE_VKEY_oEF,
KM_CORE_VKEY_oF0,
KM_CORE_VKEY_oF1,
KM_CORE_VKEY_oF2,
KM_CORE_VKEY_oF3,
KM_CORE_VKEY_oF4,
KM_CORE_VKEY_oF5,
KM_CORE_VKEY__F6,
KM_CORE_VKEY__F7,
KM_CORE_VKEY__F8,
KM_CORE_VKEY__F9,
KM_CORE_VKEY__FA,
KM_CORE_VKEY__FB,
KM_CORE_VKEY__FC,
KM_CORE_VKEY__FD,
KM_CORE_VKEY__FE,
KM_CORE_VKEY__FF,
};

View file

@ -19,16 +19,16 @@ cfg.set('patchver', project_ver[2])
configure_file(
configuration: cfg,
input: 'keyboardprocessor_version.h.in',
output: 'keyboardprocessor_version.h',
input: 'keyman_core_api_version.h.in',
output: 'keyman_core_api_version.h',
)
install_headers('keyboardprocessor.h',
'keyboardprocessor_bits.h',
'keyboardprocessor_consts.h',
'keyboardprocessor_debug.h',
'keyboardprocessor_vkeys.h',
join_paths(meson.current_build_dir(), 'keyboardprocessor_version.h'),
install_headers('keyman_core_api.h',
'keyman_core_api_bits.h',
'keyman_core_api_consts.h',
'keyman_core_api_debug.h',
'keyman_core_api_vkeys.h',
join_paths(meson.current_build_dir(), 'keyman_core_api_version.h'),
'../../../common/include/km_types.h',
'../../../common/include/kmx_file.h',
subdir: 'keyman')

View file

@ -16,6 +16,7 @@
#pragma once
#define LDML_BKSP_FLAGS_ERROR 0x1
#define LDML_CLDR_IMPLIED_FORMS_IMPORT "techpreview/scanCodes-implied.xml"
#define LDML_CLDR_IMPLIED_KEYS_IMPORT "techpreview/keys-Latn-implied.xml"
#define LDML_CLDR_IMPORT_BASE "cldr"
#define LDML_CLDR_VERSION_LATEST "techpreview"
@ -45,11 +46,7 @@
#define LDML_KEYS_MOD_CTRLR 0x2
#define LDML_KEYS_MOD_NONE 0x0
#define LDML_KEYS_MOD_SHIFT 0x10
#define LDML_LAYR_LIST_HARDWARE_ABNT2 0x1
#define LDML_LAYR_LIST_HARDWARE_ISO 0x2
#define LDML_LAYR_LIST_HARDWARE_JIS 0x3
#define LDML_LAYR_LIST_HARDWARE_TOUCH 0x0
#define LDML_LAYR_LIST_HARDWARE_US 0x4
#define LDML_LAYR_LIST_HARDWARE_TOUCH "touch"
#define LDML_LENGTH_BKSP 0xC
#define LDML_LENGTH_BKSP_ITEM 0x10
#define LDML_LENGTH_DISP 0x10
@ -91,8 +88,6 @@
#define LDML_LENGTH_USET_USET 0xC
#define LDML_LENGTH_VARS 0x10
#define LDML_LENGTH_VARS_ITEM 0x10
#define LDML_LENGTH_VKEY 0xC
#define LDML_LENGTH_VKEY_ITEM 0x8
#define LDML_MARKER_ANY_INDEX 0xD7FF
#define LDML_MARKER_CODE 0x8
#define LDML_MARKER_MAX_COUNT 0xD7FE
@ -129,8 +124,6 @@
#define LDML_SECTIONNAME_USET "uset"
#define LDML_SECTIONID_VARS 0x73726176 /* "vars" */
#define LDML_SECTIONNAME_VARS "vars"
#define LDML_SECTIONID_VKEY 0x79656B76 /* "vkey" */
#define LDML_SECTIONNAME_VKEY "vkey"
#define LDML_TRAN_FLAGS_ERROR 0x1
#define LDML_TRAN_GROUP_TYPE_REORDER 0x1
#define LDML_TRAN_GROUP_TYPE_TRANSFORM 0x0

View file

@ -37,8 +37,7 @@ export type SectionIdent =
'strs' |
'tran' |
'uset' |
'vars' |
'vkey';
'vars';
type SectionMap = {
@ -74,6 +73,10 @@ class Constants {
* implied keys file
*/
readonly cldr_implied_keys_import = `${this.cldr_version_techpreview}/keys-Latn-implied.xml`;
/**
* implied scancodes file
*/
readonly cldr_implied_forms_import = `${this.cldr_version_techpreview}/scanCodes-implied.xml`;
/**
* Length of a raw section header, in bytes
*/
@ -350,35 +353,7 @@ class Constants {
/**
* for the 'hardware' field indicating a touch keyboard, non-hardware
*/
readonly layr_list_hardware_touch = 0;
/**
* for the 'hardware' field indicating an abnt2 layout
*/
readonly layr_list_hardware_abnt2 = 1;
/**
* for the 'hardware' field indicating an iso layout
*/
readonly layr_list_hardware_iso = 2;
/**
* for the 'hardware' field indicating a jis layout
*/
readonly layr_list_hardware_jis = 3;
/**
* for the 'hardware' field indicating a us layout
*/
readonly layr_list_hardware_us = 4;
/**
* Convenience map of layr_list_hardware field values
*/
readonly layr_list_hardware_map: Map<String, number> = new Map(
[
["touch", this.layr_list_hardware_touch],
["abnt2", this.layr_list_hardware_abnt2],
["iso", this.layr_list_hardware_iso],
["jis", this.layr_list_hardware_jis],
["us", this.layr_list_hardware_us],
]
);
readonly layr_list_hardware_touch = 'touch';
/**
* Length of each layer entry in the 'layr' section variable part
*/
@ -504,19 +479,6 @@ class Constants {
*/
readonly tran_group_type_reorder = 1;
/* ------------------------------------------------------------------
* vkey section
------------------------------------------------------------------ */
/**
* Minimum length of the 'vkey' section not including variable parts
*/
readonly length_vkey = 12;
/**
* Length of each item in the 'vkey' section variable part
*/
readonly length_vkey_item = 8;
/* ------------------------------------------------------------------
* vars section
* ------------------------------------------------------------------ */
@ -581,7 +543,6 @@ class Constants {
tran: 'tran',
uset: 'uset',
vars: 'vars',
vkey: 'vkey',
};
/**

View file

@ -1,5 +1,5 @@
{
"extends": "../../../tsconfig.esm-base.json",
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"composite": true,
"declaration": true,

View file

@ -1,10 +1,8 @@
{
"extends": "../../../tsconfig-base.json",
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"composite": true,
"declaration": true,
"module": "es2020",
"moduleResolution": "node",
"rootDir": ".",
"outDir": "build/",
},

View file

@ -3,13 +3,13 @@
Description: Internal context class and adaptor class for the API.
Create Date: 2 Oct 2018
Authors: Tim Eves (TSE)
History: 2 Oct 2018 - TSE - Refactored out of km_kbp_context_api.cpp
History: 2 Oct 2018 - TSE - Refactored out of km_core_context_api.cpp
*/
#pragma once
#include <list>
#include <vector>
#include <keyman/keyboardprocessor.h>
#include <keyman/keyman_core_api.h>
// Forward declarations
class json;
@ -20,32 +20,32 @@ namespace kbp
// This will likely be replaced with a class implementing a more space
// efficient data structure such as a ring buffer or bounded queue.
class context: public std::list<km_kbp_context_item>
class context: public std::list<km_core_context_item>
{
public:
void push_character(km_kbp_usv);
void push_character(km_core_usv);
void push_marker(uint32_t);
};
inline
void context::push_character(km_kbp_usv usv) {
emplace_back(km_kbp_context_item { KM_KBP_CT_CHAR, {0,}, {usv} });
void context::push_character(km_core_usv usv) {
emplace_back(km_core_context_item { KM_CORE_CT_CHAR, {0,}, {usv} });
}
inline
void context::push_marker(uint32_t marker) {
emplace_back(km_kbp_context_item { KM_KBP_CT_MARKER, {0,}, {marker} });
emplace_back(km_core_context_item { KM_CORE_CT_MARKER, {0,}, {marker} });
}
} // namespace kbp
} // namespace km
json & operator << (json &, km::kbp::context const &);
json & operator << (json &, km_kbp_context_item const &);
json & operator << (json &, km_core_context_item const &);
struct km_kbp_context : public km::kbp::context
struct km_core_context : public km::kbp::context
{
};

View file

@ -9,20 +9,20 @@
#include <cassert>
#include <vector>
#include <keyman/keyboardprocessor.h>
#include <keyman/keyboardprocessor_debug.h>
#include <keyman/keyman_core_api.h>
#include <keyman/keyman_core_api_debug.h>
namespace km {
namespace kbp
{
class debug_items : public std::vector<km_kbp_state_debug_item>
class debug_items : public std::vector<km_core_state_debug_item>
{
private:
bool _is_enabled;
public:
template<typename... Args> debug_items(Args&&... args);
void push_begin(km_kbp_state_debug_key_info *key_info, uint32_t flags);
void push_begin(km_core_state_debug_key_info *key_info, uint32_t flags);
void push_end(uint16_t first_action, uint32_t flags);
void assert_push_entry();
bool is_enabled() const noexcept;
@ -31,29 +31,29 @@ public:
template<typename... Args>
debug_items::debug_items(Args&&... args)
: std::vector<km_kbp_state_debug_item>(std::forward<Args>(args)...)
: std::vector<km_core_state_debug_item>(std::forward<Args>(args)...)
{
// Ensure the debug_items list is terminated in case the client calls
// km_kbp_state_debug_items before they call process_event.
// km_core_state_debug_items before they call process_event.
_is_enabled = false;
push_end(0, 0);
}
inline
void debug_items::assert_push_entry() {
assert(empty() || (!empty() && back().type != KM_KBP_DEBUG_END));
assert(empty() || (!empty() && back().type != KM_CORE_DEBUG_END));
}
inline
void debug_items::push_begin(km_kbp_state_debug_key_info *key_info, uint32_t flags) {
void debug_items::push_begin(km_core_state_debug_key_info *key_info, uint32_t flags) {
assert_push_entry();
emplace_back(km_kbp_state_debug_item{ KM_KBP_DEBUG_BEGIN, flags, {*key_info, }, { }});
emplace_back(km_core_state_debug_item{ KM_CORE_DEBUG_BEGIN, flags, {*key_info, }, { }});
}
inline
void debug_items::push_end(uint16_t first_action, uint32_t flags) {
assert_push_entry();
emplace_back(km_kbp_state_debug_item{ KM_KBP_DEBUG_END, flags, { }, { u"", nullptr, nullptr, { }, first_action, {} } });
emplace_back(km_core_state_debug_item{ KM_CORE_DEBUG_END, flags, { }, { u"", nullptr, nullptr, { }, first_action, {} } });
}
inline

View file

@ -1,6 +1,6 @@
/* Debugging */
#include <keyman/keyboardprocessor_bits.h>
#include <keyman/keyman_core_api_bits.h>
namespace km {
namespace kbp {

View file

@ -3,7 +3,7 @@
Description: Internal keyboard class and adaptor class for the API.
Create Date: 2 Oct 2018
Authors: Tim Eves (TSE)
History: 7 Oct 2018 - TSE - Refactored out of km_kbp_keyboard_api.cpp
History: 7 Oct 2018 - TSE - Refactored out of km_core_keyboard_api.cpp
*/
#include "keyboard.hpp"
#include "jsonpp.hpp"

View file

@ -3,7 +3,7 @@
Description: Internal keyboard class and adaptor class for the API.
Create Date: 2 Oct 2018
Authors: Tim Eves (TSE)
History: 2 Oct 2018 - TSE - Refactored out of km_kbp_keyboard_api.cpp
History: 2 Oct 2018 - TSE - Refactored out of km_core_keyboard_api.cpp
*/
#pragma once
@ -11,7 +11,7 @@
#include <string>
#include <vector>
#include <keyman/keyboardprocessor.h>
#include <keyman/keyman_core_api.h>
#include "option.hpp"
#include "path.hpp"
@ -22,7 +22,7 @@ class json;
namespace km {
namespace kbp
{
class keyboard_attributes : public km_kbp_keyboard_attrs
class keyboard_attributes : public km_core_keyboard_attrs
{
std::u16string _keyboard_id;
std::u16string _version_string;
@ -36,7 +36,7 @@ namespace kbp
using path_type = decltype(_folder_path);
keyboard_attributes()
: km_kbp_keyboard_attrs {nullptr, nullptr, nullptr, nullptr} {}
: km_core_keyboard_attrs {nullptr, nullptr, nullptr, nullptr} {}
keyboard_attributes(keyboard_attributes const &) = delete;
keyboard_attributes(keyboard_attributes &&);

View file

@ -12,7 +12,7 @@
#include <algorithm>
#include <vector>
#include <keyman/keyboardprocessor.h>
#include <keyman/keyman_core_api.h>
#include "context.hpp"
#include "jsonpp.hpp"
@ -20,44 +20,44 @@
namespace {
template<class U>
km_kbp_status
km_core_status
_context_items_from(typename U::codeunit_t const *text,
km_kbp_context_item **out_ptr)
km_core_context_item **out_ptr)
{
assert(text); assert(out_ptr);
if (!text || !out_ptr) return KM_KBP_STATUS_INVALID_ARGUMENT;
if (!text || !out_ptr) return KM_CORE_STATUS_INVALID_ARGUMENT;
*out_ptr = nullptr;
try
{
std::vector<km_kbp_context_item> res;
std::vector<km_core_context_item> res;
for (auto i = typename U::const_iterator(text); *i; ++i)
{
if(i.error()) return KM_KBP_STATUS_INVALID_UTF;
res.emplace_back(km_kbp_context_item {KM_KBP_CT_CHAR, {0,}, {*i}});
if(i.error()) return KM_CORE_STATUS_INVALID_UTF;
res.emplace_back(km_core_context_item {KM_CORE_CT_CHAR, {0,}, {*i}});
}
// Terminate the context_items array.
res.emplace_back(km_kbp_context_item KM_KBP_CONTEXT_ITEM_END);
res.emplace_back(km_core_context_item KM_CORE_CONTEXT_ITEM_END);
*out_ptr = new km_kbp_context_item[res.size()];
*out_ptr = new km_core_context_item[res.size()];
std::move(res.begin(), res.end(), *out_ptr);
}
catch (std::bad_alloc &)
{
return KM_KBP_STATUS_NO_MEM;
return KM_CORE_STATUS_NO_MEM;
}
return KM_KBP_STATUS_OK;
return KM_CORE_STATUS_OK;
}
template<class U>
km_kbp_status _context_items_to(km_kbp_context_item const *ci,
km_core_status _context_items_to(km_core_context_item const *ci,
typename U::codeunit_t *buf,
size_t * sz_ptr)
{
assert(ci); assert(sz_ptr);
if (!ci || !sz_ptr) return KM_KBP_STATUS_INVALID_ARGUMENT;
if (!ci || !sz_ptr) return KM_CORE_STATUS_INVALID_ARGUMENT;
auto const buf_size = *sz_ptr;
if (buf && buf_size > 0)
@ -65,9 +65,9 @@ namespace {
auto i = typename U::iterator(buf);
auto const e = decltype(i)(buf + buf_size - 1);
for (;i != e && ci->type != KM_KBP_CT_END && !i.error(); ++ci)
for (;i != e && ci->type != KM_CORE_CT_END && !i.error(); ++ci)
{
if (ci->type == KM_KBP_CT_CHAR)
if (ci->type == KM_CORE_CT_CHAR)
{
*i = ci->character; ++i;
}
@ -77,13 +77,13 @@ namespace {
*sz_ptr = buf_size - (e - i);
// Skip over any final markers - they are execluded from context
while(ci->type == KM_KBP_CT_MARKER) {
while(ci->type == KM_CORE_CT_MARKER) {
ci++;
}
return ci->type == KM_KBP_CT_END
? KM_KBP_STATUS_OK
: KM_KBP_STATUS_INSUFFICENT_BUFFER;
return ci->type == KM_CORE_CT_END
? KM_CORE_STATUS_OK
: KM_CORE_STATUS_INSUFFICENT_BUFFER;
}
else
{
@ -92,38 +92,38 @@ namespace {
do
{
if (ci->type == KM_KBP_CT_CHAR)
if (ci->type == KM_CORE_CT_CHAR)
{
int8_t l = 4;
U::codec::put(cps, ci->character, l);
n += l;
}
}
while(ci++->type != KM_KBP_CT_END);
while(ci++->type != KM_CORE_CT_END);
*sz_ptr = n+1;
return KM_KBP_STATUS_OK;
return KM_CORE_STATUS_OK;
}
}
}
km_kbp_status
km_kbp_context_items_from_utf16(km_kbp_cp const *text,
km_kbp_context_item **out_ptr)
km_core_status
km_core_context_items_from_utf16(km_core_cp const *text,
km_core_context_item **out_ptr)
{
return _context_items_from<utf16>(reinterpret_cast<utf16::codeunit_t const *>(text), out_ptr);
}
km_kbp_status
km_kbp_context_items_from_utf8(char const *text,
km_kbp_context_item **out_ptr)
km_core_status
km_core_context_items_from_utf8(char const *text,
km_core_context_item **out_ptr)
{
return _context_items_from<utf8>(reinterpret_cast<utf8::codeunit_t const *>(text), out_ptr);
}
km_kbp_status km_kbp_context_items_to_utf8(km_kbp_context_item const *ci,
km_core_status km_core_context_items_to_utf8(km_core_context_item const *ci,
char *buf, size_t * sz_ptr)
{
return _context_items_to<utf8>(ci,
@ -132,8 +132,8 @@ km_kbp_status km_kbp_context_items_to_utf8(km_kbp_context_item const *ci,
}
km_kbp_status km_kbp_context_items_to_utf16(km_kbp_context_item const *ci,
km_kbp_cp *buf, size_t * sz_ptr)
km_core_status km_core_context_items_to_utf16(km_core_context_item const *ci,
km_core_cp *buf, size_t * sz_ptr)
{
return _context_items_to<utf16>(ci,
reinterpret_cast<utf16::codeunit_t *>(buf),
@ -141,41 +141,41 @@ km_kbp_status km_kbp_context_items_to_utf16(km_kbp_context_item const *ci,
}
void km_kbp_context_items_dispose(km_kbp_context_item *ci)
void km_core_context_items_dispose(km_core_context_item *ci)
{
delete [] ci;
}
km_kbp_status km_kbp_context_set(km_kbp_context *ctxt, km_kbp_context_item const *ci)
km_core_status km_core_context_set(km_core_context *ctxt, km_core_context_item const *ci)
{
km_kbp_context_clear(ctxt);
return km_kbp_context_append(ctxt, ci);
km_core_context_clear(ctxt);
return km_core_context_append(ctxt, ci);
}
km_kbp_status km_kbp_context_get(km_kbp_context const *ctxt,
km_kbp_context_item **out_ptr)
km_core_status km_core_context_get(km_core_context const *ctxt,
km_core_context_item **out_ptr)
{
assert(ctxt); assert(out_ptr);
if (!ctxt || !out_ptr) return KM_KBP_STATUS_INVALID_ARGUMENT;
if (!ctxt || !out_ptr) return KM_CORE_STATUS_INVALID_ARGUMENT;
try
{
*out_ptr = new km_kbp_context_item[ctxt->size() + 1];
*out_ptr = new km_core_context_item[ctxt->size() + 1];
}
catch (std::bad_alloc &)
{
return KM_KBP_STATUS_NO_MEM;
return KM_CORE_STATUS_NO_MEM;
}
std::copy(ctxt->begin(), ctxt->end(), *out_ptr);
(*out_ptr)[ctxt->size()].type = KM_KBP_CT_END;
(*out_ptr)[ctxt->size()].type = KM_CORE_CT_END;
return KM_KBP_STATUS_OK;
return KM_CORE_STATUS_OK;
}
void km_kbp_context_clear(km_kbp_context *ctxt)
void km_core_context_clear(km_core_context *ctxt)
{
assert(ctxt);
if (ctxt)
@ -185,38 +185,38 @@ void km_kbp_context_clear(km_kbp_context *ctxt)
}
size_t km_kbp_context_length(km_kbp_context *ctxt)
size_t km_core_context_length(km_core_context *ctxt)
{
assert(ctxt);
return ctxt ? ctxt->size() : 0;
}
km_kbp_status km_kbp_context_append(km_kbp_context *ctxt,
km_kbp_context_item const *ci)
km_core_status km_core_context_append(km_core_context *ctxt,
km_core_context_item const *ci)
{
assert(ctxt); assert(ci);
if (!ctxt || !ci) return KM_KBP_STATUS_INVALID_ARGUMENT;
if (!ctxt || !ci) return KM_CORE_STATUS_INVALID_ARGUMENT;
try
{
for (;ci->type != KM_KBP_CT_END; ++ci)
for (;ci->type != KM_CORE_CT_END; ++ci)
{
ctxt->emplace_back(*ci);
}
} catch (std::bad_alloc &) {
return KM_KBP_STATUS_NO_MEM;
return KM_CORE_STATUS_NO_MEM;
}
return KM_KBP_STATUS_OK;
return KM_CORE_STATUS_OK;
}
km_kbp_status km_kbp_context_shrink(km_kbp_context *ctxt, size_t num,
km_kbp_context_item const * ci)
km_core_status km_core_context_shrink(km_core_context *ctxt, size_t num,
km_core_context_item const * ci)
{
assert(ctxt);
if (!ctxt) return KM_KBP_STATUS_INVALID_ARGUMENT;
if (!ctxt) return KM_CORE_STATUS_INVALID_ARGUMENT;
try
{
@ -225,21 +225,21 @@ km_kbp_status km_kbp_context_shrink(km_kbp_context *ctxt, size_t num,
if (ci)
{
auto const ip = ctxt->begin();
while(num-- && ci->type != KM_KBP_CT_END)
while(num-- && ci->type != KM_CORE_CT_END)
{
ctxt->emplace(ip, *ci);
ci++;
}
}
} catch (std::bad_alloc &) {
return KM_KBP_STATUS_NO_MEM;
return KM_CORE_STATUS_NO_MEM;
}
return KM_KBP_STATUS_OK;
return KM_CORE_STATUS_OK;
}
size_t
km_kbp_context_item_list_size(km_kbp_context_item const *context_items)
km_core_context_item_list_size(km_core_context_item const *context_items)
{
assert(context_items);
if (!context_items) return 0;
@ -258,18 +258,18 @@ json & operator << (json & j, km::kbp::context const & ctxt) {
return j << json::close;
}
json & operator << (json & j, km_kbp_context_item const & i)
json & operator << (json & j, km_core_context_item const & i)
{
utf8::codeunit_t cps[7] = {0,}; // 6 bytes for maximal UTF-8 char (e.g. U+10FFFF) + nul terminator
int8_t l = 4;
switch (i.type)
{
case KM_KBP_CT_CHAR:
case KM_CORE_CT_CHAR:
utf8::codec::put(cps, i.character, l);
j << json::string(&cps[0]);
break;
case KM_KBP_CT_MARKER:
case KM_CORE_CT_MARKER:
j << json::integer_u(i.marker);
break;
default:

View file

@ -8,29 +8,29 @@
#include <algorithm>
#include <sstream>
#include <keyman/keyboardprocessor.h>
#include <keyman/keyman_core_api.h>
#include "processor.hpp"
#include "state.hpp"
using namespace km::kbp;
km_kbp_status
km_kbp_state_debug_set(
km_kbp_state *state,
km_core_status
km_core_state_debug_set(
km_core_state *state,
int value
) {
assert(state);
if(!state) {
return KM_KBP_STATUS_INVALID_ARGUMENT;
return KM_CORE_STATUS_INVALID_ARGUMENT;
}
state->debug_items().set_enabled(value ? true : false);
return KM_KBP_STATUS_OK;
return KM_CORE_STATUS_OK;
}
uint8_t
km_kbp_state_debug_get(
km_kbp_state const *state
km_core_state_debug_get(
km_core_state const *state
) {
assert(state);
if(!state) {
@ -39,9 +39,9 @@ km_kbp_state_debug_get(
return state->debug_items().is_enabled() ? 1 : 0;
}
km_kbp_state_debug_item const *
km_kbp_state_debug_items(
km_kbp_state const *state,
km_core_state_debug_item const *
km_core_state_debug_items(
km_core_state const *state,
size_t *num_items
) {
assert(state && state->debug_items().size() > 0);
@ -58,6 +58,6 @@ km_kbp_state_debug_items(
// Process events will ensure that the debug vector is always well
// terminated
assert(state->debug_items().back().type == KM_KBP_DEBUG_END);
assert(state->debug_items().back().type == KM_CORE_DEBUG_END);
return state->debug_items().data();
}

View file

@ -11,7 +11,7 @@
#include <cassert>
#include <vector>
#include <keyman/keyboardprocessor.h>
#include <keyman/keyman_core_api.h>
#include "keyboard.hpp"
#include "processor.hpp"
#include "kmx/kmx_processor.hpp"
@ -43,85 +43,85 @@ namespace
}
km_kbp_status
km_kbp_keyboard_load(km_kbp_path_name kb_path, km_kbp_keyboard **keyboard)
km_core_status
km_core_keyboard_load(km_core_path_name kb_path, km_core_keyboard **keyboard)
{
assert(keyboard);
if (!keyboard)
return KM_KBP_STATUS_INVALID_ARGUMENT;
return KM_CORE_STATUS_INVALID_ARGUMENT;
try
{
abstract_processor *kp = processor_factory(kb_path);
km_kbp_status status = kp->validate();
if (status != KM_KBP_STATUS_OK) {
km_core_status status = kp->validate();
if (status != KM_CORE_STATUS_OK) {
delete kp;
return status;
}
*keyboard = static_cast<km_kbp_keyboard *>(kp);
*keyboard = static_cast<km_core_keyboard *>(kp);
}
catch (std::bad_alloc &)
{
return KM_KBP_STATUS_NO_MEM;
return KM_CORE_STATUS_NO_MEM;
}
return KM_KBP_STATUS_OK;
return KM_CORE_STATUS_OK;
}
void
km_kbp_keyboard_dispose(km_kbp_keyboard *keyboard)
km_core_keyboard_dispose(km_core_keyboard *keyboard)
{
delete keyboard;
}
km_kbp_status
km_kbp_keyboard_get_attrs(km_kbp_keyboard const *keyboard,
km_kbp_keyboard_attrs const **out)
km_core_status
km_core_keyboard_get_attrs(km_core_keyboard const *keyboard,
km_core_keyboard_attrs const **out)
{
assert(keyboard); assert(out);
if (!keyboard || !out)
return KM_KBP_STATUS_INVALID_ARGUMENT;
return KM_CORE_STATUS_INVALID_ARGUMENT;
*out = &keyboard->keyboard();
return KM_KBP_STATUS_OK;
return KM_CORE_STATUS_OK;
}
km_kbp_status
km_kbp_keyboard_get_key_list(km_kbp_keyboard const *keyboard,
km_kbp_keyboard_key **out)
km_core_status
km_core_keyboard_get_key_list(km_core_keyboard const *keyboard,
km_core_keyboard_key **out)
{
assert(keyboard); assert(out);
if (!keyboard || !out)
return KM_KBP_STATUS_INVALID_ARGUMENT;
return KM_CORE_STATUS_INVALID_ARGUMENT;
*out = keyboard->get_key_list();
return KM_KBP_STATUS_OK;
return KM_CORE_STATUS_OK;
}
void km_kbp_keyboard_key_list_dispose(km_kbp_keyboard_key *key_list)
void km_core_keyboard_key_list_dispose(km_core_keyboard_key *key_list)
{
delete[] key_list;
}
km_kbp_status km_kbp_keyboard_get_imx_list(
km_kbp_keyboard const *keyboard,
km_kbp_keyboard_imx** imx_list
km_core_status km_core_keyboard_get_imx_list(
km_core_keyboard const *keyboard,
km_core_keyboard_imx** imx_list
) {
assert(keyboard); assert(imx_list);
if (!keyboard || !imx_list) {
return KM_KBP_STATUS_INVALID_ARGUMENT;
return KM_CORE_STATUS_INVALID_ARGUMENT;
}
*imx_list = keyboard->get_imx_list();
return KM_KBP_STATUS_OK;
return KM_CORE_STATUS_OK;
}
void km_kbp_keyboard_imx_list_dispose(km_kbp_keyboard_imx *imx_list)
void km_core_keyboard_imx_list_dispose(km_core_keyboard_imx *imx_list)
{
if(!imx_list) {
return;
}
km_kbp_keyboard_imx *imx_rule_it = imx_list;
km_core_keyboard_imx *imx_rule_it = imx_list;
for (; imx_rule_it->library_name; ++imx_rule_it) {
delete [] imx_rule_it->library_name; // from u16dup
delete [] imx_rule_it->function_name; // from u16dup

View file

@ -11,7 +11,7 @@
#include <cassert>
#include <sstream>
#include <keyman/keyboardprocessor.h>
#include <keyman/keyman_core_api.h>
#include "processor.hpp"
#include "jsonpp.hpp"
@ -19,7 +19,7 @@
size_t
km_kbp_options_list_size(km_kbp_option_item const *opts)
km_core_options_list_size(km_core_option_item const *opts)
{
assert(opts);
if (!opts) return 0;
@ -33,31 +33,31 @@ km_kbp_options_list_size(km_kbp_option_item const *opts)
}
km_kbp_status
km_kbp_state_option_lookup(km_kbp_state const *state,
uint8_t scope, km_kbp_cp const *key,
km_kbp_cp const **value_out)
km_core_status
km_core_state_option_lookup(km_core_state const *state,
uint8_t scope, km_core_cp const *key,
km_core_cp const **value_out)
{
assert(state); assert(key); assert(value_out);
if (!state || !key || !value_out) return KM_KBP_STATUS_INVALID_ARGUMENT;
if (!state || !key || !value_out) return KM_CORE_STATUS_INVALID_ARGUMENT;
if (scope == KM_KBP_OPT_UNKNOWN || scope > KM_KBP_OPT_MAX_SCOPES)
return KM_KBP_STATUS_INVALID_ARGUMENT;
if (scope == KM_CORE_OPT_UNKNOWN || scope > KM_CORE_OPT_MAX_SCOPES)
return KM_CORE_STATUS_INVALID_ARGUMENT;
auto & processor = state->processor();
*value_out = processor.lookup_option(km_kbp_option_scope(scope), key);
if (!*value_out) return KM_KBP_STATUS_KEY_ERROR;
*value_out = processor.lookup_option(km_core_option_scope(scope), key);
if (!*value_out) return KM_CORE_STATUS_KEY_ERROR;
return KM_KBP_STATUS_OK;
return KM_CORE_STATUS_OK;
}
km_kbp_status
km_kbp_state_options_update(km_kbp_state *state, km_kbp_option_item const *opt)
km_core_status
km_core_state_options_update(km_core_state *state, km_core_option_item const *opt)
{
assert(state); assert(opt);
if (!state|| !opt) return KM_KBP_STATUS_INVALID_ARGUMENT;
if (!state|| !opt) return KM_CORE_STATUS_INVALID_ARGUMENT;
auto & processor = state->processor();
@ -65,32 +65,32 @@ km_kbp_state_options_update(km_kbp_state *state, km_kbp_option_item const *opt)
{
for (;opt->key; ++opt)
{
if (opt->scope == KM_KBP_OPT_UNKNOWN || opt->scope > KM_KBP_OPT_MAX_SCOPES)
return KM_KBP_STATUS_INVALID_ARGUMENT;
if (opt->scope == KM_CORE_OPT_UNKNOWN || opt->scope > KM_CORE_OPT_MAX_SCOPES)
return KM_CORE_STATUS_INVALID_ARGUMENT;
if (processor.update_option(
km_kbp_option_scope(opt->scope),
km_core_option_scope(opt->scope),
opt->key,
opt->value).empty())
return KM_KBP_STATUS_KEY_ERROR;
return KM_CORE_STATUS_KEY_ERROR;
}
}
catch (std::bad_alloc &)
{
return KM_KBP_STATUS_NO_MEM;
return KM_CORE_STATUS_NO_MEM;
}
return KM_KBP_STATUS_OK;
return KM_CORE_STATUS_OK;
}
// This function doesn't need to use the json pretty printer for such a simple
// list of key:value pairs but it's a good introduction to it.
km_kbp_status
km_kbp_state_options_to_json(km_kbp_state const *state, char *buf, size_t *space)
km_core_status
km_core_state_options_to_json(km_core_state const *state, char *buf, size_t *space)
{
assert(state); assert(space);
if (!state || !space)
return KM_KBP_STATUS_INVALID_ARGUMENT;
return KM_CORE_STATUS_INVALID_ARGUMENT;
std::stringstream _buf;
json jo(_buf);
@ -103,7 +103,7 @@ km_kbp_state_options_to_json(km_kbp_state const *state, char *buf, size_t *space
catch (std::bad_alloc &)
{
*space = 0;
return KM_KBP_STATUS_NO_MEM;
return KM_CORE_STATUS_NO_MEM;
}
// Fetch the finished doc and copy it to the buffer if there enough space.
@ -116,5 +116,5 @@ km_kbp_state_options_to_json(km_kbp_state const *state, char *buf, size_t *space
// Return space needed/used.
*space = doc.size()+1;
return KM_KBP_STATUS_OK;
return KM_CORE_STATUS_OK;
}

View file

@ -8,63 +8,63 @@
History: 17 Oct 2018 - TSE - Initial implementation.
*/
#include <keyman/keyboardprocessor.h>
#include <keyman/keyman_core_api.h>
#include "processor.hpp"
#include "state.hpp"
km_kbp_status
km_kbp_event(
km_kbp_state *state,
km_core_status
km_core_event(
km_core_state *state,
uint32_t event,
void* data
) {
assert(state != nullptr);
if(state == nullptr) {
return KM_KBP_STATUS_INVALID_ARGUMENT;
return KM_CORE_STATUS_INVALID_ARGUMENT;
}
// event: KM_KBP_EVENT_KEYBOARD_ACTIVATED; data should be nullptr
// future event: KM_KBP_EVENT_KEYBOARD_DEACTIVATED
// event: KM_CORE_EVENT_KEYBOARD_ACTIVATED; data should be nullptr
// future event: KM_CORE_EVENT_KEYBOARD_DEACTIVATED
switch(event) {
case KM_KBP_EVENT_KEYBOARD_ACTIVATED:
case KM_CORE_EVENT_KEYBOARD_ACTIVATED:
assert(data == nullptr);
if(data != nullptr) {
return KM_KBP_STATUS_INVALID_ARGUMENT;
return KM_CORE_STATUS_INVALID_ARGUMENT;
}
break;
default:
return KM_KBP_STATUS_INVALID_ARGUMENT;
return KM_CORE_STATUS_INVALID_ARGUMENT;
}
return state->processor().external_event(state, event, data);
}
km_kbp_status
km_kbp_process_event(km_kbp_state *state,
km_kbp_virtual_key vk,
km_core_status
km_core_process_event(km_core_state *state,
km_core_virtual_key vk,
uint16_t modifier_state,
uint8_t is_key_down,
uint16_t event_flags) {
assert(state != nullptr);
if(state == nullptr) {
return KM_KBP_STATUS_INVALID_ARGUMENT;
return KM_CORE_STATUS_INVALID_ARGUMENT;
}
return state->processor().process_event(state, vk, modifier_state, is_key_down, event_flags);
}
km_kbp_status
km_kbp_process_queued_actions(
km_kbp_state *state
km_core_status
km_core_process_queued_actions(
km_core_state *state
) {
assert(state != nullptr);
if(state == nullptr) {
return KM_KBP_STATUS_INVALID_ARGUMENT;
return KM_CORE_STATUS_INVALID_ARGUMENT;
}
return state->processor().process_queued_actions(state);
}
km_kbp_attr const *
km_kbp_get_engine_attrs(km_kbp_state const *state)
km_core_attr const *
km_core_get_engine_attrs(km_core_state const *state)
{
assert(state != nullptr);
if(state == nullptr) {

View file

@ -12,7 +12,7 @@
#include <algorithm>
#include <sstream>
#include <keyman/keyboardprocessor.h>
#include <keyman/keyman_core_api.h>
#include "jsonpp.hpp"
#include "processor.hpp"
@ -23,68 +23,68 @@ using namespace km::kbp;
// Forward declarations
class context;
km_kbp_status km_kbp_state_create(km_kbp_keyboard * keyboard,
km_kbp_option_item const *env,
km_kbp_state ** out)
km_core_status km_core_state_create(km_core_keyboard * keyboard,
km_core_option_item const *env,
km_core_state ** out)
{
assert(keyboard); assert(env); assert(out);
if (!keyboard || !env || !out)
return KM_KBP_STATUS_INVALID_ARGUMENT;
return KM_CORE_STATUS_INVALID_ARGUMENT;
try
{
*out = new km_kbp_state(static_cast<abstract_processor&>(*keyboard), env);
*out = new km_core_state(static_cast<abstract_processor&>(*keyboard), env);
}
catch (std::bad_alloc &)
{
return KM_KBP_STATUS_NO_MEM;
return KM_CORE_STATUS_NO_MEM;
}
return KM_KBP_STATUS_OK;
return KM_CORE_STATUS_OK;
}
km_kbp_status km_kbp_state_clone(km_kbp_state const *state,
km_kbp_state ** out)
km_core_status km_core_state_clone(km_core_state const *state,
km_core_state ** out)
{
assert(state); assert(out);
if (!state || !out)
return KM_KBP_STATUS_INVALID_ARGUMENT;
return KM_CORE_STATUS_INVALID_ARGUMENT;
*out = new km_kbp_state(*state);
return KM_KBP_STATUS_OK;
*out = new km_core_state(*state);
return KM_CORE_STATUS_OK;
}
void km_kbp_state_dispose(km_kbp_state *state)
void km_core_state_dispose(km_core_state *state)
{
delete state;
}
km_kbp_context *km_kbp_state_context(km_kbp_state *state)
km_core_context *km_core_state_context(km_core_state *state)
{
assert(state);
if (!state) return nullptr;
return static_cast<km_kbp_context *>(&state->context());
return static_cast<km_core_context *>(&state->context());
}
km_kbp_status kbp_state_get_intermediate_context(
km_kbp_state *state,
km_kbp_context_item ** context_items
km_core_status kbp_state_get_intermediate_context(
km_core_state *state,
km_core_context_item ** context_items
) {
assert(state);
assert(context_items);
if (!state || !context_items) {
return KM_KBP_STATUS_INVALID_ARGUMENT;
return KM_CORE_STATUS_INVALID_ARGUMENT;
}
auto & processor = state->processor();
*context_items = processor.get_intermediate_context();
return KM_KBP_STATUS_OK;
return KM_CORE_STATUS_OK;
}
km_kbp_action_item const * km_kbp_state_action_items(km_kbp_state const *state,
km_core_action_item const * km_core_state_action_items(km_core_state const *state,
size_t *num_items)
{
assert(state && state->actions().size() > 0);
@ -95,33 +95,33 @@ km_kbp_action_item const * km_kbp_state_action_items(km_kbp_state const *state,
// Process events will ensure that the actions vector is always well
// teminated
assert(state->actions().back().type == KM_KBP_IT_END);
assert(state->actions().back().type == KM_CORE_IT_END);
return state->actions().data();
}
km_kbp_status km_kbp_state_queue_action_items(
km_kbp_state *state,
km_kbp_action_item const *action_items
km_core_status km_core_state_queue_action_items(
km_core_state *state,
km_core_action_item const *action_items
) {
assert(state);
assert(action_items);
if (!state|| !action_items) {
return KM_KBP_STATUS_INVALID_ARGUMENT;
return KM_CORE_STATUS_INVALID_ARGUMENT;
}
auto & processor = state->processor();
for (; action_items->type != KM_KBP_IT_END; ++action_items) {
if (action_items->type >= KM_KBP_IT_MAX_TYPE_ID) {
return KM_KBP_STATUS_INVALID_ARGUMENT;
for (; action_items->type != KM_CORE_IT_END; ++action_items) {
if (action_items->type >= KM_CORE_IT_MAX_TYPE_ID) {
return KM_CORE_STATUS_INVALID_ARGUMENT;
}
if (!processor.queue_action(state, action_items)) {
return KM_KBP_STATUS_KEY_ERROR;
return KM_CORE_STATUS_KEY_ERROR;
}
}
return KM_KBP_STATUS_OK;
return KM_CORE_STATUS_OK;
}
namespace {
char const * action_item_name_lut[] = {
@ -146,10 +146,10 @@ namespace {
}
json & operator << (json & j, km_kbp_action_item const &act)
json & operator << (json & j, km_core_action_item const &act)
{
j << json::flat << json::object;
if (act.type >= KM_KBP_IT_MAX_TYPE_ID)
if (act.type >= KM_CORE_IT_MAX_TYPE_ID)
{
j << "invalid" << json::null << json::close;
return j;
@ -158,16 +158,16 @@ json & operator << (json & j, km_kbp_action_item const &act)
j << action_item_name_lut[act.type];
switch (act.type)
{
case KM_KBP_IT_END:
case KM_KBP_IT_ALERT:
case KM_KBP_IT_BACK:
case KM_CORE_IT_END:
case KM_CORE_IT_ALERT:
case KM_CORE_IT_BACK:
j << json::null;
break;
case KM_KBP_IT_CHAR:
case KM_KBP_IT_MARKER:
j << km_kbp_context_item {act.type, {0,}, {act.character}}; // TODO: is act.type correct here? it may map okay but this is bad practice to mix constants across types. Similarly using act.character instead of act.type
case KM_CORE_IT_CHAR:
case KM_CORE_IT_MARKER:
j << km_core_context_item {act.type, {0,}, {act.character}}; // TODO: is act.type correct here? it may map okay but this is bad practice to mix constants across types. Similarly using act.character instead of act.type
break;
case KM_KBP_IT_PERSIST_OPT:
case KM_CORE_IT_PERSIST_OPT:
j << json::object
<< scope_names_lut[act.option->scope]
<< json::flat << json::object
@ -187,7 +187,7 @@ json & operator << (json & j, actions const & acts)
j << json::array;
for (auto & act: acts)
{
if (act.type != KM_KBP_IT_END)
if (act.type != KM_CORE_IT_END)
{
j << act;
}
@ -197,13 +197,13 @@ json & operator << (json & j, actions const & acts)
}
km_kbp_status km_kbp_state_to_json(km_kbp_state const *state,
km_core_status km_core_state_to_json(km_core_state const *state,
char *buf,
size_t *space)
{
assert(state);
if (!state)
return KM_KBP_STATUS_INVALID_ARGUMENT;
return KM_CORE_STATUS_INVALID_ARGUMENT;
std::stringstream _buf;
json jo(_buf);
@ -212,7 +212,7 @@ km_kbp_status km_kbp_state_to_json(km_kbp_state const *state,
{
// Pretty print the document.
jo << json::object
<< "$schema" << "keyman/keyboardprocessor/doc/introspection.schema"
<< "$schema" << "keyman/core/doc/introspection.schema"
<< "keyboard" << state->processor().keyboard()
// << "options" << state->options() TODO: Fix
<< "context" << state->context()
@ -222,7 +222,7 @@ km_kbp_status km_kbp_state_to_json(km_kbp_state const *state,
catch (std::bad_alloc &)
{
*space = 0;
return KM_KBP_STATUS_NO_MEM;
return KM_CORE_STATUS_NO_MEM;
}
// Fetch the finished doc and copy it to the buffer if there enough space.
@ -235,13 +235,13 @@ km_kbp_status km_kbp_state_to_json(km_kbp_state const *state,
// Return space needed/used.
*space = doc.size()+1;
return KM_KBP_STATUS_OK;
return KM_CORE_STATUS_OK;
}
void km_kbp_state_imx_register_callback(
km_kbp_state *state,
km_kbp_keyboard_imx_platform imx_callback,
void km_core_state_imx_register_callback(
km_core_state *state,
km_core_keyboard_imx_platform imx_callback,
void *callback_object
) {
assert(state);
@ -251,7 +251,7 @@ void km_kbp_state_imx_register_callback(
state->imx_register_callback(imx_callback, callback_object);
}
void km_kbp_state_imx_deregister_callback(km_kbp_state *state)
void km_core_state_imx_deregister_callback(km_core_state *state)
{
assert(state);
if (!state) {

View file

@ -1,7 +1,7 @@
#pragma once
#include <keyman/keyboardprocessor_bits.h>
#include <keyman/keyboardprocessor.h>
#include <keyman/keyman_core_api_bits.h>
#include <keyman/keyman_core_api.h>
#if defined(_WIN32) || defined(_WIN64)
#define snprintf _snprintf

View file

@ -2,7 +2,7 @@
Copyright: Copyright (C) 2003-2018 SIL International.
Authors: mcdurdin
*/
#include <keyman/keyboardprocessor_consts.h>
#include <keyman/keyman_core_api_consts.h>
#include <kmx/kmx_processevent.h>
using namespace km::kbp;

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