Merge pull request #12321 from keymanapp/chore/merge-master-into-user-dict
chore: merge master into user-dict
42
HISTORY.md
|
|
@ -1,5 +1,47 @@
|
|||
# Keyman Version History
|
||||
|
||||
## 18.0.100 alpha 2024-08-28
|
||||
|
||||
* fix(windows): check IM window will be in a visible location (#11967)
|
||||
|
||||
## 18.0.99 alpha 2024-08-27
|
||||
|
||||
* feat(web): import the generator for the pred-text wordbreaker's Unicode-property data-table (#10690)
|
||||
* feat(web): optimize the wordbreaker data table for filesize and ease of first-load parsing (#10692)
|
||||
* (#12297)
|
||||
* (#12115)
|
||||
|
||||
## 18.0.98 alpha 2024-08-26
|
||||
|
||||
* change(ios): defer registration of fonts past initialization (#12190)
|
||||
* refactor(ios): optimize font registration (#12210)
|
||||
* test(mac): add unit tests to validate first calls to compliance check (#11724)
|
||||
* fix(mac): limit short bundle version string to x.y.z format in info.plist (#12233)
|
||||
* chore(developer): extend timeouts for lm compiler tests to 5 secs (#12273)
|
||||
* fix(developer): find last matching key in LDML key bag when building KVK (#12278)
|
||||
* chore(android): Cleanup stray debug statements in console (#12287)
|
||||
* fix(developer): ensure call() detects invalid store in kmcmplib compiler (#12263)
|
||||
|
||||
## 18.0.97 alpha 2024-08-24
|
||||
|
||||
* refactor(linux): cleanup API of kvk2ldml.py (#12276)
|
||||
* chore(common): adjust build settings for windows clean builds (#12264)
|
||||
* chore(windows): remove remaining unused Makefiles (#12274)
|
||||
* docs(developer): update build documentation to refer to build.sh (#12272)
|
||||
|
||||
## 18.0.96 alpha 2024-08-23
|
||||
|
||||
* fix(android): Fix navigation arrows in Info Activity for RTL (#12244)
|
||||
* fix(web): fix documentation-keyboard spacebar-text scaling (#12232)
|
||||
* fix(android): Use increment and decrement arrows on longpress delay menu (#12242)
|
||||
* fix(android): Add RTL assets for adjusting keyboard height menu (#12261)
|
||||
* chore(common): use `npm install` in emsdk update (#12269)
|
||||
* docs: refresh windows.md (#12248)
|
||||
|
||||
## 18.0.95 alpha 2024-08-22
|
||||
|
||||
* chore(common): allow build agents to automatically select emsdk version, and enable support for 3.1.60+ (#12243)
|
||||
|
||||
## 18.0.94 alpha 2024-08-21
|
||||
|
||||
* fix(core): look for `emcc` instead of `emcc.py` (#12235)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
18.0.95
|
||||
18.0.101
|
||||
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
|
@ -23,7 +23,7 @@
|
|||
android:layout_marginStart="5dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:contentDescription="@string/ic_delay_time_down"
|
||||
android:src="@drawable/ic_light_dialog_textsize_down" />
|
||||
android:src="@drawable/ic_action_decrement" />
|
||||
|
||||
<!-- Seekbar range 0 to 6 corresponds to longpress duration 300 ms to 1500 ms -->
|
||||
<SeekBar
|
||||
|
|
@ -43,7 +43,7 @@
|
|||
android:layout_marginStart="5dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:contentDescription="@string/ic_delay_time_up"
|
||||
android:src="@drawable/ic_light_dialog_textsize_up" />
|
||||
android:src="@drawable/ic_action_increment" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@color/ms_white"
|
||||
tools:context=".InfoActivity" >
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@color/ms_white"
|
||||
tools:context=".InfoActivity" >
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/titlebar"
|
||||
|
|
@ -15,25 +15,31 @@
|
|||
android:layout_alignParentTop="true"
|
||||
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
|
||||
|
||||
<!-- Navigation buttons -->
|
||||
<ImageButton
|
||||
android:id="@+id/back_button"
|
||||
style="?android:attr/actionButtonStyle"
|
||||
app:tint="@color/image_button_color"
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:contentDescription="@string/label_back"
|
||||
android:src="@drawable/ic_action_back" />
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/forward_button"
|
||||
style="?android:attr/actionButtonStyle"
|
||||
app:tint="@color/image_button_color"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/label_forward"
|
||||
android:src="@drawable/ic_action_forward" />
|
||||
<!-- Navigation buttons in a LinearLayout to mirror on RTL -->
|
||||
<ImageButton
|
||||
android:id="@+id/back_button"
|
||||
style="?android:attr/actionButtonStyle"
|
||||
app:tint="@color/image_button_color"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:contentDescription="@string/label_back"
|
||||
android:src="@drawable/ic_action_back" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/forward_button"
|
||||
style="?android:attr/actionButtonStyle"
|
||||
app:tint="@color/image_button_color"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/label_forward"
|
||||
android:src="@drawable/ic_action_forward" />
|
||||
</LinearLayout>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/close_button"
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ function notifyHost(event, params) {
|
|||
function setLongpressDelay(delay) {
|
||||
if (keyman.osk) {
|
||||
keyman.osk.gestureParams.longpress.waitLength = delay;
|
||||
console.debug('setLongpressDelay('+delay+')');
|
||||
console_debug('setLongpressDelay('+delay+')');
|
||||
} else {
|
||||
window.console.log('setLongpressDelay error: keyman.osk undefined');
|
||||
}
|
||||
|
|
@ -304,7 +304,7 @@ function updateKMSelectionRange(start, end) {
|
|||
|
||||
console_debug('result:\n' + build_context_string(context));
|
||||
} else {
|
||||
console.debug('range unchanged');
|
||||
console_debug('range unchanged');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
3
common/models/wordbreakers/.gitignore
vendored
|
|
@ -1 +1,2 @@
|
|||
build/
|
||||
build/
|
||||
src/main/default/data.inc.ts
|
||||
|
|
@ -12,6 +12,8 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
|
|||
|
||||
################################ Main script ################################
|
||||
|
||||
# Note: the raw text files used for data.inc.ts are found within
|
||||
# /resources/standards-data/unicode-character-database.
|
||||
builder_describe "Builds the predictive-text wordbreaker implementation module" \
|
||||
"clean" \
|
||||
"configure" \
|
||||
|
|
@ -20,16 +22,26 @@ builder_describe "Builds the predictive-text wordbreaker implementation module"
|
|||
"--ci"
|
||||
|
||||
builder_describe_outputs \
|
||||
configure /node_modules \
|
||||
build build/obj/index.js
|
||||
configure src/main/default/data.inc.ts \
|
||||
build build/main/obj/index.js
|
||||
|
||||
builder_parse "$@"
|
||||
|
||||
function do_configure() {
|
||||
verify_npm_setup
|
||||
|
||||
# This is a script used to build the data.inc.ts file needed by the
|
||||
# default wordbreaker. We rarely update the backing data, but it
|
||||
# is needed _before_ the `build` action's compilation step.
|
||||
tsc -b tools/data-compiler/tsconfig.json
|
||||
node ./build/tools/data-compiler/obj/index.js
|
||||
}
|
||||
|
||||
function do_build() {
|
||||
tsc -b
|
||||
tsc -b ./tsconfig.json
|
||||
|
||||
# Declaration bundling.
|
||||
tsc --emitDeclarationOnly --outFile ./build/lib/index.d.ts
|
||||
tsc -p ./tsconfig.json --emitDeclarationOnly --outFile ./build/main/lib/index.d.ts
|
||||
}
|
||||
|
||||
function do_test() {
|
||||
|
|
@ -40,7 +52,7 @@ function do_test() {
|
|||
fi
|
||||
}
|
||||
|
||||
builder_run_action configure verify_npm_setup
|
||||
builder_run_action configure do_configure
|
||||
builder_run_action clean rm -rf build/
|
||||
builder_run_action build do_build
|
||||
builder_run_action test do_test
|
||||
|
|
@ -14,17 +14,23 @@
|
|||
],
|
||||
"homepage": "https://github.com/keymanapp/keyman",
|
||||
"license": "MIT",
|
||||
"main": "build/obj/index.js",
|
||||
"types": "build/obj/index.d.ts",
|
||||
"main": "build/main/obj/index.js",
|
||||
"types": "build/main/obj/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"es6-bundling": "./src/index.ts",
|
||||
"default": "./build/obj/index.js"
|
||||
"es6-bundling": "./src/main/index.ts",
|
||||
"default": "./build/main/obj/index.js"
|
||||
},
|
||||
"./lib": {
|
||||
"types": "./build/lib/index.d.ts"
|
||||
"types": "./build/main/lib/index.d.ts"
|
||||
},
|
||||
"./obj/*.js": "./build/obj/*.js"
|
||||
"./obj/*.js": "./build/main/obj/*.js",
|
||||
"./test-index": {
|
||||
"default": "./build/main/obj/test-index.js"
|
||||
},
|
||||
"./README.md": {
|
||||
"default": "./README.md"
|
||||
}
|
||||
},
|
||||
"directories": {
|
||||
"lib": "lib",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import { WordBreakProperty, WORD_BREAK_PROPERTY, I, propertyMap } from "./data.js";
|
||||
import { WordBreakProperty, propertyMap } from "./data.inc.js";
|
||||
|
||||
import { searchForProperty } from "./searchForProperty.js";
|
||||
|
||||
/**
|
||||
* A set of options used to customize and extend the behavior of the default
|
||||
|
|
@ -566,7 +568,7 @@ function property(character: string, options?: DefaultWordBreakerOptions): WordB
|
|||
// TODO: remove dependence on character.codepointAt()?
|
||||
let codepoint = character.codePointAt(0) as number;
|
||||
|
||||
return searchForProperty(codepoint, 0, WORD_BREAK_PROPERTY.length - 1);
|
||||
return searchForProperty(codepoint);
|
||||
}
|
||||
|
||||
function propertyVal(propName: string, options?: DefaultWordBreakerOptions) {
|
||||
|
|
@ -574,35 +576,4 @@ function propertyVal(propName: string, options?: DefaultWordBreakerOptions) {
|
|||
|
||||
const customIndex = options?.customProperties?.findIndex(matcher) ?? -1;
|
||||
return customIndex != -1 ? -customIndex - 1 : propertyMap.findIndex(matcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binary search for the word break property of a given CODE POINT.
|
||||
*
|
||||
* The auto-generated data.ts master array defines a **character range**
|
||||
* lookup table. If a character's codepoint is equal to or greater than
|
||||
* the I.Start value for an entry and exclusively less than the next entry,
|
||||
* it falls in the first entry's range bucket and is classified accordingly
|
||||
* by this method.
|
||||
*/
|
||||
function searchForProperty(codePoint: number, left: number, right: number): WordBreakProperty {
|
||||
// All items that are not found in the array are assigned the 'Other' property.
|
||||
if (right < left) {
|
||||
return WordBreakProperty.Other;
|
||||
}
|
||||
|
||||
let midpoint = left + ~~((right - left) / 2);
|
||||
let candidate = WORD_BREAK_PROPERTY[midpoint];
|
||||
|
||||
let nextRange = WORD_BREAK_PROPERTY[midpoint + 1];
|
||||
let startOfNextRange = nextRange ? nextRange[I.Start] : Infinity;
|
||||
|
||||
if (codePoint < candidate[I.Start]) {
|
||||
return searchForProperty(codePoint, left, midpoint - 1);
|
||||
} else if (codePoint >= startOfNextRange) {
|
||||
return searchForProperty(codePoint, midpoint + 1, right);
|
||||
}
|
||||
|
||||
// We found it!
|
||||
return candidate[I.Value];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
import { WordBreakProperty, WORD_BREAK_PROPERTY_BMP, WORD_BREAK_PROPERTY_NON_BMP } from "./data.inc.js";
|
||||
|
||||
export function searchForProperty(codePoint: number): WordBreakProperty {
|
||||
const bucketSize = codePoint <= 0xFFFF ? 2 : 3;
|
||||
|
||||
// SMP chars take a bit more space to encode.
|
||||
const encodedArray = bucketSize == 2 ? WORD_BREAK_PROPERTY_BMP : WORD_BREAK_PROPERTY_NON_BMP;
|
||||
|
||||
return _searchForProperty(encodedArray, codePoint, bucketSize, 0, encodedArray.length / bucketSize - 1) - 0x20;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binary search for the word break property of a given CODE POINT.
|
||||
*
|
||||
* The auto-generated data.ts master strings encode **character range**
|
||||
* lookup tables. If a character's codepoint is equal to or greater than
|
||||
* the start-of-range value for an entry and exclusively less than the next
|
||||
* entry's start-of-range, it falls within the first entry's range bucket
|
||||
* and is classified accordingly by this method.
|
||||
*/
|
||||
function _searchForProperty(encodedArray: string, codePoint: number, bucketSize: number, left: number, right: number): WordBreakProperty {
|
||||
// All items that are not found in the array are assigned the 'Other' property.
|
||||
if (right < left) { // May need special handling at end of BMP / start of non-BMP.
|
||||
return WordBreakProperty.Other;
|
||||
}
|
||||
|
||||
let midpoint = left + ~~((right - left) / 2);
|
||||
let candidate = encodedArray.codePointAt(bucketSize * midpoint);
|
||||
|
||||
// If out-of-bounds, gives NaN.
|
||||
let nextRange = encodedArray.codePointAt(bucketSize * (midpoint + 1));
|
||||
let startOfNextRange = isNaN(nextRange) ? Infinity : nextRange;
|
||||
|
||||
if (codePoint < candidate) {
|
||||
return _searchForProperty(encodedArray, codePoint, bucketSize, left, midpoint - 1);
|
||||
} else if (codePoint >= startOfNextRange) {
|
||||
return _searchForProperty(encodedArray, codePoint, bucketSize, midpoint + 1, right);
|
||||
}
|
||||
|
||||
// We found it!
|
||||
const propertyCode = encodedArray.charCodeAt(bucketSize * (midpoint + 1) - 1);
|
||||
return propertyCode as WordBreakProperty;
|
||||
}
|
||||
5
common/models/wordbreakers/src/main/test-index.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// Include all standard exports.
|
||||
export * from './index.js';
|
||||
|
||||
// Exposes some internal properties for unit-test accessibility
|
||||
export { WordBreakProperty } from './default/data.inc.js';
|
||||
33
common/models/wordbreakers/test/test-search-property.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* Smoke-test the default
|
||||
*/
|
||||
|
||||
import { assert } from 'chai';
|
||||
import { searchForProperty } from '../build/main/obj/default/searchForProperty.js';
|
||||
import { propertyMap } from '../build/main/obj/default/data.inc.js';
|
||||
|
||||
describe('searchForProperty', () => {
|
||||
it('correctly finds character classes for standard ASCII characters', () => {
|
||||
assert.equal(searchForProperty('a'.codePointAt(0)), propertyMap.indexOf('ALetter'));
|
||||
assert.equal(searchForProperty('Z'.codePointAt(0)), propertyMap.indexOf('ALetter'));
|
||||
|
||||
assert.equal(searchForProperty("'".codePointAt(0)), propertyMap.indexOf('Single_Quote'));
|
||||
assert.equal(searchForProperty('"'.codePointAt(0)), propertyMap.indexOf('Double_Quote'));
|
||||
assert.equal(searchForProperty(','.codePointAt(0)), propertyMap.indexOf('MidNum'));
|
||||
assert.equal(searchForProperty('.'.codePointAt(0)), propertyMap.indexOf('MidNumLet'));
|
||||
assert.equal(searchForProperty('-'.codePointAt(0)), propertyMap.indexOf('Other'));
|
||||
});
|
||||
|
||||
it('correctly finds character classes for specialized BMP characters', () => {
|
||||
assert.equal(searchForProperty(0x05D0), propertyMap.indexOf('Hebrew_Letter'));
|
||||
assert.equal(searchForProperty(0x3031), propertyMap.indexOf('Katakana'));
|
||||
assert.equal(searchForProperty(0xFFFE), propertyMap.indexOf('Other'));
|
||||
assert.equal(searchForProperty(0xFFFF), propertyMap.indexOf('Other'));
|
||||
});
|
||||
|
||||
it('correctly finds character classes for non-BMP characters', () => {
|
||||
assert.equal(searchForProperty(0x0001F1E6), propertyMap.indexOf('Regional_Indicator'));
|
||||
assert.equal(searchForProperty(0x00013430), propertyMap.indexOf('Format'));
|
||||
assert.equal(searchForProperty(0x00010000), propertyMap.indexOf('ALetter'));
|
||||
});
|
||||
});
|
||||
22
common/models/wordbreakers/tools/data-compiler/LICENSE
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 National Research Council Canada
|
||||
Copyright (c) 2024 Eddie Antonio Santos
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
388
common/models/wordbreakers/tools/data-compiler/index.ts
Normal file
|
|
@ -0,0 +1,388 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
// Original version found at: https://github.com/eddieantonio/unicode-default-word-boundary/blob/master/libexec/compile-word-break.js
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import { createRequire } from 'module';
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
/*
|
||||
* Generates the TypeScript file for data required for the word boundary
|
||||
* function:
|
||||
*
|
||||
* - a sorted array to facilitate binary search of the Word_Break property.
|
||||
* - a regular expression that matches characters that have Extended_Pictographic=Yes.
|
||||
*
|
||||
* For internal use only. Please keep away from children.
|
||||
*
|
||||
* The generated file is saved to ../../src/main/default/data.inc.ts
|
||||
*/
|
||||
|
||||
const MAX_CODE_POINT = 0x10FFFF;
|
||||
|
||||
// Where to get the data:
|
||||
// - https://www.unicode.org/reports/tr51/#emoji_data
|
||||
// - https://www.unicode.org/reports/tr41/#Props0
|
||||
|
||||
//////////////////////////////////// Main ////////////////////////////////////
|
||||
|
||||
const projectDir = path.dirname(require.resolve("@keymanapp/models-wordbreakers/README.md"));
|
||||
const generatedFilename = path.join(projectDir, 'src', 'main', 'default', 'data.inc.ts');
|
||||
|
||||
// The data files should be in this repository, with names matching the
|
||||
// Unicode version.
|
||||
const wordBoundaryFilename = path.join(projectDir, `../../../resources/standards-data/unicode-character-database/WordBreakProperty.txt`);
|
||||
const emojiDataFilename = path.join(projectDir, `../../../resources/standards-data/unicode-character-database/emoji-data.txt`);
|
||||
|
||||
///////////////////////////// Word_Boundary file /////////////////////////////
|
||||
|
||||
interface DataRange {
|
||||
start: number;
|
||||
end: number;
|
||||
property: string;
|
||||
}
|
||||
|
||||
// Extract the ranges IN ASCENDING ORDER from the file.
|
||||
// This will be the big binary search table.
|
||||
let ranges = readCharacterPropertyFile(wordBoundaryFilename)
|
||||
.sort((a, b) => {
|
||||
return a.start - b.start;
|
||||
});
|
||||
|
||||
// The list of ranges are initially sparse — having gaps between assigned
|
||||
// ranges. Fill in those gaps:
|
||||
ranges = makeDense(ranges);
|
||||
ensureDense(ranges);
|
||||
|
||||
// The possible Word_Break property assignments.
|
||||
let categories = new Set<string>();
|
||||
for (let {property} of ranges) {
|
||||
categories.add(property);
|
||||
}
|
||||
// Also add pseudo-categories of start-of-text and end-of-text:
|
||||
categories.add('sot');
|
||||
categories.add('eot');
|
||||
|
||||
///////////////////////// Extended_Pictographic=Yes //////////////////////////
|
||||
|
||||
let extendedPictographicCodePoints = readCharacterPropertyFile(emojiDataFilename)
|
||||
.filter(({property}) => property === 'Extended_Pictographic');
|
||||
|
||||
// Try generating the regular expression both in a way that is
|
||||
// backwards-compatbile and one that only works in ES6+.
|
||||
// let extendedPictographicRegExp;
|
||||
let compatibleRegexp = utf16AlternativesStrategy();
|
||||
let es6Regexp = unicodeRangeStrategy();
|
||||
|
||||
// Choose the shortest regular expression.
|
||||
// In my experience, the ES6 regexp is an order of magnitude smaller!
|
||||
if (es6Regexp.length < compatibleRegexp.length) {
|
||||
// extendedPictographicRegExp = es6Regexp;
|
||||
console.warn(`Using ES6 regexp [${es6Regexp.length} chars]`);
|
||||
} else {
|
||||
// extendedPictographicRegExp = compatibleRegexp;
|
||||
console.warn(`Using compatibility regexp [${compatibleRegexp.length} chars]`);
|
||||
}
|
||||
|
||||
let catIndexSeed = 0;
|
||||
const categoryMap = new Map<string, number>();
|
||||
|
||||
for(let cat of categories) {
|
||||
categoryMap.set(cat, catIndexSeed++);
|
||||
if(catIndexSeed == '`'.charCodeAt(0)) {
|
||||
catIndexSeed++; // Skip the back-tick as an encoding symbol.
|
||||
// Reduces complications, as it's the encoding string start/end char.
|
||||
}
|
||||
}
|
||||
|
||||
const bmpRanges: typeof ranges = [];
|
||||
const nonBmpRanges: typeof ranges = [];
|
||||
|
||||
// { start: number, property: number}[]
|
||||
for(let range of ranges) { // already sorted
|
||||
if(range.start <= 0xFFFF) {
|
||||
bmpRanges.push(range);
|
||||
} else {
|
||||
if(nonBmpRanges.length == 0) {
|
||||
const finalBmpRange = bmpRanges[bmpRanges.length - 1];
|
||||
bmpRanges.push({
|
||||
start: 0xFFFF,
|
||||
property: finalBmpRange.property,
|
||||
end: undefined
|
||||
});
|
||||
|
||||
if(range.start != 0x10000) {
|
||||
nonBmpRanges.push({
|
||||
start: 0x10000,
|
||||
property: finalBmpRange.property,
|
||||
end: undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
nonBmpRanges.push(range);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////// Creating the generated file /////////////////////////
|
||||
|
||||
// Save the output in the gen/ directory.
|
||||
let stream = fs.createWriteStream(generatedFilename);
|
||||
|
||||
function escape(codedChar: string) {
|
||||
if(codedChar == '`' || codedChar == '\\') {
|
||||
return '\\' + codedChar;
|
||||
} else {
|
||||
return codedChar;
|
||||
}
|
||||
}
|
||||
|
||||
// // Former entry in the original version by Eddie that was never included in our repo:
|
||||
// export const extendedPictographic = ${extendedPictographicRegExp};
|
||||
|
||||
// Generate the file!
|
||||
stream.write(`// Automatically generated file. DO NOT MODIFY.
|
||||
// The generator script is defined at /common/models/wordbreakers/src/data-compiler/index.ts.
|
||||
|
||||
/**
|
||||
* Valid values for a word break property.
|
||||
*
|
||||
* Is optimized away at compile-time; use \`propertyMap\` to find the mapped
|
||||
* value at runtime for a property name if needed.
|
||||
*/
|
||||
export const enum WordBreakProperty {
|
||||
${ /* Create enum values for each word break property */
|
||||
Array.from(categories)
|
||||
.map(x => ` ${x} = ${categoryMap.get(x)}`)
|
||||
.join(',\n')
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Contains property names per associated index, as this is compiled away
|
||||
* by TypeScript for \`const enum\` cases like \`WordBreakProperty\`.
|
||||
*/
|
||||
export const propertyMap = [
|
||||
${ /* Enumerate the plain-text names for ease of lookup at runtime */
|
||||
Array.from(categories)
|
||||
.map(x => ` "${x}"`)
|
||||
.join(',\n')
|
||||
}
|
||||
];
|
||||
|
||||
export const WORD_BREAK_PROPERTY_BMP: string = \`${
|
||||
// To consider: emit `\uxxxx` codes instead of the raw char?
|
||||
bmpRanges.map(({start, property}) => {
|
||||
let codedStart = escape(String.fromCodePoint(start));
|
||||
|
||||
// Offset the encoded property value to lie within a friendlier range,
|
||||
// with characters that render naturally within code editors.
|
||||
const codedProp = escape(String.fromCharCode(categoryMap.get(property) + 0x20));
|
||||
return `${codedStart}${codedProp}`;
|
||||
}).join('')
|
||||
}\`;
|
||||
|
||||
export const WORD_BREAK_PROPERTY_NON_BMP: string = \`${
|
||||
// To consider: emit `\uxxxx` codes instead of the raw char?
|
||||
nonBmpRanges.map(({start, property}) => {
|
||||
const codedStart = escape(String.fromCodePoint(start));
|
||||
|
||||
// Offset the encoded property value to lie within a friendlier range,
|
||||
// with characters that render naturally within code editors.
|
||||
const codedProp = escape(String.fromCharCode(categoryMap.get(property) + 0x20));
|
||||
return `${codedStart}${codedProp}`;
|
||||
}).join('')
|
||||
}\`;
|
||||
`);
|
||||
|
||||
/**
|
||||
* Reads a Unicode character property file.
|
||||
*
|
||||
* Character property files are composed of comment lines, empty lines, and
|
||||
* property lines. Comments lines begin with '#' and should be ignored, as
|
||||
* well as empty lines.
|
||||
*
|
||||
* Property lines have a code point or a code point range, followed by a
|
||||
* semi-colon, followed by the property text. e.g.,
|
||||
*
|
||||
* 1F600 ; Emoji # 6.1 [1] (😀) grinning face
|
||||
* 26C4..26C5 ; Emoji_Presentation # 5.2 [2] (⛄..⛅) snowman without snow..sun behind butt
|
||||
*
|
||||
* This will read the file at the given filename, and return an ordered array
|
||||
* or property lines, with attributes:
|
||||
*
|
||||
* {start: number, end: number, property: string}
|
||||
*
|
||||
* If the property specifies a single code point (i.e., not a range of code
|
||||
* points), then end === start.
|
||||
*/
|
||||
function readCharacterPropertyFile(filename: string) {
|
||||
let textContents = fs.readFileSync(filename, { encoding: 'utf8'});
|
||||
|
||||
return textContents.split('\n')
|
||||
.filter(line => !line.startsWith('#') && line.trim())
|
||||
.map(line => {
|
||||
let [_, startText, endText, property] = line.match(
|
||||
// Parse lines that look like this:
|
||||
// 0000 .. 0000 ; CategoryName
|
||||
/^([0-9A-F]{4,6})(?:..([0-9A-F]{4,6}))?\s+;\s+([A-Za-z_]+)/
|
||||
);
|
||||
|
||||
let start = parseCodepoint(startText);
|
||||
let end = endText !== undefined ? parseCodepoint(endText) : start;
|
||||
|
||||
return { start, end, property };
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a code point, expressed as a 4 or 6 digit hexadecimal string.
|
||||
* Does some bounds checking in order to determine if the string is in fact a
|
||||
* valid code point.
|
||||
*/
|
||||
function parseCodepoint(hexString: string) {
|
||||
let number = parseInt(hexString, 16);
|
||||
if (Number.isNaN(number)) {
|
||||
throw new SyntaxError(`Cannot parse codepoint: ${hexString}`);
|
||||
}
|
||||
|
||||
if (number < 0 || number > MAX_CODE_POINT) {
|
||||
throw new RangeError(`Codepoint out of range: ${number}`);
|
||||
}
|
||||
|
||||
return number;
|
||||
}
|
||||
|
||||
function toUnicodeEscape(codePoint: number) {
|
||||
let isBMP = codePoint <= 0xFFFF;
|
||||
let simpleConversion = codePoint.toString(16).toUpperCase();
|
||||
|
||||
let padding = (isBMP ? 4 : 6) - simpleConversion.length;
|
||||
let digits = '0'.repeat(padding) + simpleConversion;
|
||||
|
||||
if (isBMP) {
|
||||
return '\\u' + digits;
|
||||
} else {
|
||||
return `\\u{${digits}}`;
|
||||
}
|
||||
}
|
||||
|
||||
function utf16AlternativesStrategy() {
|
||||
let codePoints = [];
|
||||
for (let {start, end} of extendedPictographicCodePoints) {
|
||||
for (let current = start; current <= end; current ++) {
|
||||
codePoints.push(current);
|
||||
}
|
||||
}
|
||||
|
||||
let alternatives = codePoints.map(codePointToUTF16Escape);
|
||||
return `/^(?:${alternatives.join('|')})/`;
|
||||
}
|
||||
|
||||
function codePointToUTF16Escape(codePoint: number): string {
|
||||
// Scalar values remain the same
|
||||
if (codePoint <= 0xFFFF) {
|
||||
return toUnicodeEscape(codePoint);
|
||||
}
|
||||
|
||||
const LOWEST_TEN_BITS_MASK = 0x03FF;
|
||||
let astralBits = codePoint - 0x10000;
|
||||
|
||||
let highSurrogate = 0xD800 + (astralBits >>> 10);
|
||||
let lowSurrogate = 0xDC00 + (astralBits & LOWEST_TEN_BITS_MASK);
|
||||
|
||||
console.assert(highSurrogate <= 0xDBFF);
|
||||
console.assert(lowSurrogate <= 0xDFFF);
|
||||
console.assert(String.fromCharCode(highSurrogate) + String.fromCharCode(lowSurrogate) ===
|
||||
String.fromCodePoint(codePoint));
|
||||
return codePointToUTF16Escape(highSurrogate) + codePointToUTF16Escape(lowSurrogate);
|
||||
}
|
||||
|
||||
function unicodeRangeStrategy() {
|
||||
let regexp = '';
|
||||
for (let {start, end} of extendedPictographicCodePoints) {
|
||||
if (start === end) {
|
||||
regexp += toUnicodeEscape(start);
|
||||
} else {
|
||||
regexp += toUnicodeEscape(start) + '-' + toUnicodeEscape(end);
|
||||
}
|
||||
}
|
||||
return `/^[${regexp}]/u`;
|
||||
}
|
||||
|
||||
function makeDense(ranges: DataRange[]) {
|
||||
return joinSameAdjacentProperties(fillInGaps(ranges));
|
||||
}
|
||||
|
||||
function ensureDense(ranges: DataRange[]) {
|
||||
let lastEnd = -1;
|
||||
let lastProperty = 'sot';
|
||||
for (let range of ranges) {
|
||||
let {start, end, property} = range
|
||||
|
||||
if (lastEnd + 1 !== start) {
|
||||
throw new Error(`Non-adjacent range: ${JSON.stringify(range)}`);
|
||||
}
|
||||
|
||||
if (lastProperty === property) {
|
||||
throw new Error(`adjacent ranges have same property: ${JSON.stringify(range)}`);
|
||||
}
|
||||
|
||||
lastEnd = end;
|
||||
lastProperty = property;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function joinSameAdjacentProperties(ranges: DataRange[]) {
|
||||
console.assert(ranges.length > 1);
|
||||
|
||||
let conjoinedRanges = [];
|
||||
conjoinedRanges.push(ranges.shift());
|
||||
|
||||
for (let range of ranges) {
|
||||
let lastRange = conjoinedRanges[conjoinedRanges.length - 1];
|
||||
if (range.property === lastRange.property) {
|
||||
lastRange.end = range.end;
|
||||
} else {
|
||||
conjoinedRanges.push(range);
|
||||
}
|
||||
}
|
||||
|
||||
return conjoinedRanges;
|
||||
}
|
||||
|
||||
function fillInGaps(ranges: DataRange[]) {
|
||||
console.assert(ranges.length > 1);
|
||||
|
||||
let denseRanges = [];
|
||||
let nextUnaccountedCodepoint = 0x0000;
|
||||
|
||||
for (let range of ranges) {
|
||||
if (range.start > nextUnaccountedCodepoint) {
|
||||
// Need to create a range BEFORE the next start of ranges
|
||||
denseRanges.push({
|
||||
start: nextUnaccountedCodepoint,
|
||||
end: range.start - 1,
|
||||
// If it's unassigned in the file, it should be 'Other'.
|
||||
property: 'Other',
|
||||
});
|
||||
}
|
||||
|
||||
denseRanges.push(range);
|
||||
nextUnaccountedCodepoint = range.end + 1;
|
||||
}
|
||||
|
||||
// Create the last range (till the end)
|
||||
if (nextUnaccountedCodepoint < MAX_CODE_POINT) {
|
||||
denseRanges.push({
|
||||
start: nextUnaccountedCodepoint,
|
||||
end: MAX_CODE_POINT,
|
||||
property: 'Other',
|
||||
})
|
||||
}
|
||||
|
||||
return denseRanges;
|
||||
}
|
||||
21
common/models/wordbreakers/tools/data-compiler/tsconfig.json
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.kmw-worker-base.json",
|
||||
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"outDir": "../../build/tools/data-compiler/obj",
|
||||
"tsBuildInfoFile": "../../build/tools/data-compiler/obj/tsconfig.tsbuildinfo",
|
||||
"rootDir": "./",
|
||||
"module": "node16",
|
||||
"moduleResolution": "node16"
|
||||
},
|
||||
"references": [
|
||||
{ "path": "../../../types" }
|
||||
],
|
||||
"include": [
|
||||
"./**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
|
|
@ -3,18 +3,17 @@
|
|||
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"outDir": "build/obj",
|
||||
"tsBuildInfoFile": "build/obj/tsconfig.tsbuildinfo",
|
||||
"rootDir": "./src"
|
||||
"outDir": "./build/main/obj",
|
||||
"tsBuildInfoFile": "./build/main/obj/tsconfig.tsbuildinfo",
|
||||
"rootDir": "./src/main"
|
||||
},
|
||||
"references": [
|
||||
{ "path": "../types" }
|
||||
],
|
||||
"include": [
|
||||
"src/**/*"
|
||||
"./src/main/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"test/**/*.ts"
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ import esbuild from 'esbuild';
|
|||
import { esmConfiguration, forES6, iifeConfiguration } from './configuration.mjs';
|
||||
import { prepareTslibTreeshaking } from './tslibTreeshaking.mjs';
|
||||
|
||||
let CHARSET = 'ascii';
|
||||
let FORMAT = 'iife';
|
||||
let MINIFY = false;
|
||||
|
||||
|
|
@ -28,6 +29,8 @@ Parameters:
|
|||
|
||||
Options:
|
||||
--help Shows this script's documentation
|
||||
--charset=<charset> Sets the charset type for esbuild to emit. Defaults to 'ascii'
|
||||
but may also be 'utf8'.
|
||||
--format=<format> Sets the format type to use for the generated bundle. Should be
|
||||
'iife' or 'esm'.
|
||||
|
||||
|
|
@ -49,15 +52,28 @@ if(process.argv.length > 2) {
|
|||
case '--help':
|
||||
doHelp();
|
||||
break;
|
||||
case '--format': // bc TS uses this exact flag. esbuild... uses sourcemap (in the JS config)
|
||||
let input = process.argv[++i];
|
||||
switch(input) {
|
||||
case 'iife':
|
||||
case 'esm':
|
||||
FORMAT = input;
|
||||
case '--charset':
|
||||
let charsetOption = process.argv[++i];
|
||||
switch(charsetOption) {
|
||||
case 'ascii':
|
||||
case 'utf8':
|
||||
CHARSET = charsetOption;
|
||||
break;
|
||||
default:
|
||||
console.error(`Invalid bundling format specified: ${input}. Must be 'iife' or 'esm'.`);
|
||||
console.error(`Invalid bundling format specified: ${charsetOption}. Must be 'ascii' or 'utf8'.`);
|
||||
doHelp(1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '--format': // bc TS uses this exact flag. esbuild... uses sourcemap (in the JS config)
|
||||
let formatOption = process.argv[++i];
|
||||
switch(formatOption) {
|
||||
case 'iife':
|
||||
case 'esm':
|
||||
FORMAT = formatOption;
|
||||
break;
|
||||
default:
|
||||
console.error(`Invalid bundling format specified: ${formatOption}. Must be 'iife' or 'esm'.`);
|
||||
doHelp(1);
|
||||
break;
|
||||
}
|
||||
|
|
@ -128,6 +144,7 @@ const baseConfig = FORMAT == 'iife' ? iifeConfiguration : esmConfiguration;
|
|||
const config: esbuild.BuildOptions = {
|
||||
...jsVersionTarget == 'es6' ? forES6(baseConfig) : baseConfig,
|
||||
entryPoints: [sourceFile],
|
||||
charset: CHARSET as 'ascii' | 'utf8',
|
||||
outfile: destFile,
|
||||
minify: MINIFY,
|
||||
metafile: !!profilePath,
|
||||
|
|
|
|||
|
|
@ -1,78 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
## START STANDARD BUILD SCRIPT INCLUDE
|
||||
# adjust relative paths as necessary
|
||||
THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
|
||||
. "$(dirname "$THIS_SCRIPT")/../../../resources/build/builder.inc.sh"
|
||||
## END STANDARD BUILD SCRIPT INCLUDE
|
||||
|
||||
. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh"
|
||||
|
||||
BUNDLE_CMD="node $KEYMAN_ROOT/common/web/es-bundling/build/common-bundle.mjs"
|
||||
|
||||
################################ Main script ################################
|
||||
|
||||
builder_describe "Builds the gesture-recognition model for Web-based on-screen keyboards" \
|
||||
"@/common/web/es-bundling build" \
|
||||
"@/common/web/utils build" \
|
||||
"clean" \
|
||||
"configure" \
|
||||
"build" \
|
||||
"test" \
|
||||
":module" \
|
||||
":tools tools for testing & developing test resources for this module" \
|
||||
"--ci sets the --ci option for child scripts (i.e, the $(builder_term test) action)"
|
||||
|
||||
builder_describe_outputs \
|
||||
configure /node_modules \
|
||||
build:module /common/web/gesture-recognizer/build/lib/index.mjs \
|
||||
build:tools /common/web/gesture-recognizer/build/tools/lib/index.mjs
|
||||
|
||||
builder_parse "$@"
|
||||
|
||||
# TODO: build if out-of-date if test is specified
|
||||
# TODO: configure if npm has not been run, and build is specified
|
||||
|
||||
function do_configure() {
|
||||
verify_npm_setup
|
||||
|
||||
# Configure Web browser-engine testing environments. As is, this should only
|
||||
# make changes when we update the dependency, even on our CI build agents.
|
||||
playwright install
|
||||
}
|
||||
|
||||
builder_run_action configure do_configure
|
||||
|
||||
if builder_start_action clean; then
|
||||
rm -rf build/
|
||||
builder_finish_action success clean
|
||||
fi
|
||||
|
||||
if builder_start_action build:module; then
|
||||
# Build
|
||||
tsc --build $builder_verbose
|
||||
|
||||
$BUNDLE_CMD "${KEYMAN_ROOT}/common/web/gesture-recognizer/build/obj/index.js" \
|
||||
--out "${KEYMAN_ROOT}/common/web/gesture-recognizer/build/lib/index.mjs" \
|
||||
--format esm
|
||||
|
||||
builder_finish_action success build:module
|
||||
fi
|
||||
|
||||
if builder_start_action build:tools; then
|
||||
src/tools/build.sh build
|
||||
builder_finish_action success build:tools
|
||||
fi
|
||||
|
||||
if builder_start_action test:module; then
|
||||
if builder_has_option --ci; then
|
||||
./test.sh --ci
|
||||
else
|
||||
./test.sh
|
||||
fi
|
||||
builder_finish_action success test:module
|
||||
fi
|
||||
|
||||
if builder_has_action test:tools && ! builder_has_action test:module; then
|
||||
echo "The $(builder_term test:tools) action is currently a no-op."
|
||||
fi
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
// @ts-check
|
||||
import BASE_CONFIG from './web-test-runner.config.mjs';
|
||||
import teamcityReporter from '@keymanapp/common-test-resources/test-runner-TC-reporter.mjs';
|
||||
import { sessionStabilityReporter } from '@keymanapp/common-test-resources/test-runner-stability-reporter.mjs';
|
||||
|
||||
/** @type {import('@web/test-runner').TestRunnerConfig} */
|
||||
export default {
|
||||
...BASE_CONFIG,
|
||||
reporters: [
|
||||
teamcityReporter(), /* custom-written, for CI-friendly reports */
|
||||
sessionStabilityReporter({ciMode: true})
|
||||
]
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
// @ts-check
|
||||
import { devices, playwrightLauncher } from '@web/test-runner-playwright';
|
||||
import { defaultReporter, summaryReporter } from '@web/test-runner';
|
||||
import { LauncherWrapper, sessionStabilityReporter } from '@keymanapp/common-test-resources/test-runner-stability-reporter.mjs';
|
||||
import named from '@keymanapp/common-test-resources/test-runner-rename-browser.mjs'
|
||||
import { esbuildPlugin } from '@web/dev-server-esbuild';
|
||||
import { importMapsPlugin } from '@web/dev-server-import-maps';
|
||||
import { dirname, resolve } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const dir = dirname(fileURLToPath(import.meta.url));
|
||||
const KEYMAN_ROOT = resolve(dir, '../../../../../../../');
|
||||
|
||||
/** @type {import('@web/test-runner').TestRunnerConfig} */
|
||||
export default {
|
||||
// debug: true,
|
||||
browsers: [
|
||||
new LauncherWrapper(playwrightLauncher({ product: 'chromium' })),
|
||||
new LauncherWrapper(playwrightLauncher({ product: 'firefox' })),
|
||||
playwrightLauncher({ product: 'webkit', concurrency: 1}),
|
||||
named(new LauncherWrapper(playwrightLauncher({ product: 'webkit', concurrency: 1, createBrowserContext({browser}) {
|
||||
return browser.newContext({...devices['iPhone X'] });
|
||||
}})), 'iOS Phone (emulated)'),
|
||||
named(new LauncherWrapper(playwrightLauncher({ product: 'chromium' , createBrowserContext({browser}) {
|
||||
return browser.newContext({...devices['Pixel 4'] })
|
||||
}})), 'Android Phone (emulated)'),
|
||||
],
|
||||
concurrency: 10,
|
||||
nodeResolve: true,
|
||||
files: [
|
||||
'**/*.spec.html'
|
||||
],
|
||||
middleware: [
|
||||
// Rewrites short-hand paths for test resources, making them fully relative to the repo root.
|
||||
function rewriteResourcePath(context, next) {
|
||||
if(context.url.startsWith('/resources/')) {
|
||||
context.url = '/common/web/gesture-recognizer/src/test' + context.url;
|
||||
}
|
||||
|
||||
return next();
|
||||
}
|
||||
],
|
||||
plugins: [
|
||||
esbuildPlugin({ ts: true, target: 'auto'}),
|
||||
importMapsPlugin({
|
||||
inject: {
|
||||
importMap: {
|
||||
// Redirects `eventemitter3` imports to the bundled ESM library. The standard import is an
|
||||
// ESM wrapper around the CommonJS implementation, and WTR fails when it hits the CommonJS.
|
||||
imports: {
|
||||
'eventemitter3': '/node_modules/eventemitter3/dist/eventemitter3.esm.js'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
],
|
||||
reporters: [
|
||||
summaryReporter({}), /* local-dev mocha-style */
|
||||
sessionStabilityReporter({}),
|
||||
defaultReporter({})
|
||||
],
|
||||
/*
|
||||
Un-comment the next two lines for easy interactive debugging; it'll launch the
|
||||
test page in your preferred browser.
|
||||
*/
|
||||
// open: true,
|
||||
// manual: true,
|
||||
rootDir: KEYMAN_ROOT
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* VS Code Intellisense needs this helper in order to properly use subpath imports in the
|
||||
* test specs found under the `headless` subfolder. Otherwise, it'll report errors while
|
||||
* editing - even if the tests themselves actually work.
|
||||
*/
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../build/test/",
|
||||
// Not needed when testing via Node, and when `true` it seems to desync preset breakpoints
|
||||
// worse than when `false`.
|
||||
"importHelpers": false,
|
||||
|
||||
"allowJs": true,
|
||||
|
||||
"baseUrl": "../../",
|
||||
"tsBuildInfoFile": "../../build/test/tsconfig.tsbuildinfo",
|
||||
"rootDir": "./",
|
||||
"typeRoots": ["./resources/@types", "../../../../../node_modules/@types"]
|
||||
},
|
||||
"include": [
|
||||
"./auto/headless/**/*.ts",
|
||||
"./resources/**/*.ts"
|
||||
],
|
||||
// Undo the base config's exclude.
|
||||
"exclude": ["../../../../../node_modules/promise-status-async/lib/index.d.ts"],
|
||||
"references": [
|
||||
{"path": "../../"}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
## START STANDARD BUILD SCRIPT INCLUDE
|
||||
# adjust relative paths as necessary
|
||||
THIS_SCRIPT="$(greadlink -f "${BASH_SOURCE[0]}" 2>/dev/null || readlink -f "${BASH_SOURCE[0]}")"
|
||||
. "$(dirname "$THIS_SCRIPT")/../../../resources/build/build-utils.sh"
|
||||
## END STANDARD BUILD SCRIPT INCLUDE
|
||||
|
||||
. $KEYMAN_ROOT/resources/shellHelperFunctions.sh
|
||||
|
||||
# This script runs from its own folder
|
||||
cd "$(dirname $THIS_SCRIPT)"
|
||||
|
||||
################################ Main script ################################
|
||||
|
||||
builder_describe "Runs all tests for the gesture-recognizer module" \
|
||||
"@/common/web/gesture-recognizer" \
|
||||
"test+" \
|
||||
":headless Runs headless user tests" \
|
||||
":browser Runs browser-based user tests" \
|
||||
"--ci Uses CI-based test configurations & emits CI-friendly test reports"
|
||||
|
||||
builder_parse "$@"
|
||||
|
||||
# TODO: build if out-of-date if test is specified
|
||||
# TODO: configure if npm has not been run, and build is specified
|
||||
|
||||
# START - Script parameter configuration
|
||||
REPORT_STYLE="local" # Default setting.
|
||||
|
||||
if builder_has_option --ci; then
|
||||
REPORT_STYLE="ci"
|
||||
|
||||
echo "Replacing user-friendly test reports & configurations with CI-friendly versions."
|
||||
fi
|
||||
|
||||
# END - Script parameter configuration
|
||||
|
||||
test-headless ( ) {
|
||||
# During debugging, "--slow 0" allows reporting the duration of ALL tests, not just the ones that run long.
|
||||
# Can be useful... but probably shouldn't be the default.
|
||||
MOCHA_FLAGS=
|
||||
|
||||
if [ $REPORT_STYLE == "ci" ]; then
|
||||
MOCHA_FLAGS="$MOCHA_FLAGS --reporter mocha-teamcity-reporter"
|
||||
fi
|
||||
|
||||
# The currently-bundled declaration file for this package generates errors when compiling against it
|
||||
# with current tsc versions.
|
||||
rm -f "${KEYMAN_ROOT}/node_modules/promise-status-async/lib/index.d.ts"
|
||||
|
||||
tsc -b ./src/test/tsconfig.json
|
||||
c8 mocha --recursive $MOCHA_FLAGS ./build/test/auto/headless/
|
||||
}
|
||||
|
||||
test-browser ( ) {
|
||||
local WTR_DEBUG=
|
||||
local WTR_CONFIG=
|
||||
if [[ $# -eq 1 && $1 == "debug" ]]; then
|
||||
WTR_DEBUG=" --manual"
|
||||
elif [ $REPORT_STYLE != "local" ]; then
|
||||
WTR_CONFIG=.CI
|
||||
fi
|
||||
|
||||
web-test-runner --config src/test/auto/browser/web-test-runner${WTR_CONFIG}.config.mjs ${WTR_DEBUG}
|
||||
}
|
||||
|
||||
if builder_start_action test:headless; then
|
||||
test-headless
|
||||
builder_finish_action success test:headless
|
||||
fi
|
||||
|
||||
if builder_start_action test:browser; then
|
||||
if builder_has_option --debug; then
|
||||
echo "Running browser-based unit tests in debug-mode configuration..."
|
||||
echo
|
||||
echo "${COLOR_YELLOW}You must manually terminate this mode (CTRL-C) for the script to exit.${COLOR_RESET}"
|
||||
sleep 2
|
||||
test-browser debug
|
||||
else
|
||||
test-browser
|
||||
fi
|
||||
builder_finish_action success test:browser
|
||||
fi
|
||||
1
common/windows/.gitignore
vendored
|
|
@ -7,3 +7,4 @@ delphi/**/*.~*
|
|||
delphi/**/__recovery/
|
||||
delphi/**/__history/
|
||||
delphi/general/keymanversion_build.inc
|
||||
delphi/ext/cef4delphi/packages/CEF4Delphi.res
|
||||
|
|
|
|||
|
|
@ -1,299 +0,0 @@
|
|||
# DEBUG=1
|
||||
|
||||
# TODO: this should be a shared Defines.mak for common,developer,windows. So we
|
||||
# need to move any project-specific stuff into a defines-windows.mak,
|
||||
# defines-etc.mak
|
||||
|
||||
#
|
||||
# Paths
|
||||
#
|
||||
|
||||
!IFNDEF KEYMAN_ROOT
|
||||
!ERROR KEYMAN_ROOT must be defined!
|
||||
!ENDIF
|
||||
|
||||
# TODO: COMMON_ROOT should be common\windows
|
||||
COMMON_ROOT=$(KEYMAN_ROOT)\common\windows\delphi
|
||||
WINDOWS_ROOT=$(KEYMAN_ROOT)\windows
|
||||
OUTLIB=$(WINDOWS_ROOT)\lib
|
||||
COMMON_OUTLIB=$(KEYMAN_ROOT)\windows\lib
|
||||
COMMON_BIN=$(KEYMAN_ROOT)\windows\bin
|
||||
|
||||
# INCLUDE=$(ROOT)\src\global\inc;$(INCLUDE)
|
||||
|
||||
!IFDEF DEBUG
|
||||
GO_FAST=1
|
||||
MAKEFLAG_DEBUG="DEBUG=$(DEBUG)"
|
||||
DELPHI_MSBUILD_FLAG_DEBUG="/p:Config=Debug"
|
||||
!ELSE
|
||||
!IFDEF TEAMCITY_PR_NUMBER
|
||||
GO_FAST=1
|
||||
!ENDIF
|
||||
DELPHI_MSBUILD_FLAG_DEBUG="/p:Config=Release"
|
||||
!ENDIF
|
||||
|
||||
!IFDEF USERDEFINES
|
||||
MAKEFLAG_USERDEFINES="USERDEFINES=$(USERDEFINES)"
|
||||
!ENDIF
|
||||
|
||||
!IFDEF SC_TIMESTAMP
|
||||
MAKEFLAG_SC_TIMESTAMP="SC_TIMESTAMP=$(SC_TIMESTAMP)"
|
||||
!ENDIF
|
||||
|
||||
!IFDEF BUILDHELP
|
||||
MAKEFLAG_BUILDHELP="BUILDHELP=$(BUILDHELP)"
|
||||
!ENDIF
|
||||
|
||||
!IFDEF LINT
|
||||
MAKEFLAG_LINT="LINT=$(LINT)"
|
||||
!ENDIF
|
||||
|
||||
!IFDEF NOUI
|
||||
MAKEFLAG_QUIET="NOUI=$(NOUI)"
|
||||
!ELSE
|
||||
!IFDEF QUIET
|
||||
MAKEFLAG_QUIET="QUIET=$(QUIET)"
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
!IFDEF RELEASE_OEM
|
||||
MAKEFLAG_RELEASE_OEM="RELEASE_OEM=$(RELEASE_OEM)"
|
||||
!ENDIF
|
||||
|
||||
#
|
||||
# USERDEFINES allows the developer to specify overrides for various settings. We need a variable
|
||||
# because Makefiles cannot test for file existence
|
||||
#
|
||||
|
||||
# TODO: can we eliminate this?
|
||||
|
||||
!ifdef USERDEFINES
|
||||
!include $(WINDOWS_ROOT)\src\UserDefines.mak
|
||||
!endif
|
||||
|
||||
#
|
||||
# Delphi Compiler Configuration - Delphi 10.3.2
|
||||
#
|
||||
|
||||
!IFNDEF DELPHI_VERSION
|
||||
DELPHI_VERSION=20.0
|
||||
!ENDIF
|
||||
|
||||
DCC32PATH=C:\Program Files (x86)\Embarcadero\Studio\$(DELPHI_VERSION)\bin
|
||||
|
||||
#
|
||||
# Pass local configuration through to sub-instances of MAKE
|
||||
#
|
||||
|
||||
MAKE="nmake" /C $(MAKEFLAG_QUICK_BUILD_KEYMAN) $(MAKEFLAG_USERDEFINES) $(MAKEFLAG_DEBUG) $(MAKEFLAG_BUILDHELP) $(MAKEFLAG_BUILDRTF) $(MAKEFLAG_SC_TIMESTAMP) $(MAKEFLAG_LINT) $(MAKEFLAG_QUIET) $(MAKEFLAG_RELEASE_OEM)
|
||||
|
||||
#
|
||||
# Delphi build commands
|
||||
#
|
||||
|
||||
!IFDEF DEBUG
|
||||
TARGET_PATH=Debug
|
||||
!ELSE
|
||||
TARGET_PATH=Release
|
||||
!ENDIF
|
||||
|
||||
!IFDEF LINT
|
||||
DELPHIWARNINGS=-W+MESSAGE_DIRECTIVE -W+IMPLICIT_STRING_CAST -W+IMPLICIT_STRING_CAST_LOSS -W+EXPLICIT_STRING_CAST -W+EXPLICIT_STRING_CAST_LOSS -W+CVT_WCHAR_TO_ACHAR -W+CVT_NARROWING_STRING_LOST -W+CVT_ACHAR_TO_WCHAR -W+CVT_WIDENING_STRING_LOST -W+UNICODE_TO_LOCALE -W+LOCALE_TO_UNICODE -W+IMPLICIT_VARIANTS
|
||||
!ELSE
|
||||
DELPHIWARNINGS=-W-MESSAGE_DIRECTIVE -W-IMPLICIT_STRING_CAST -W-IMPLICIT_STRING_CAST_LOSS -W-EXPLICIT_STRING_CAST -W-EXPLICIT_STRING_CAST_LOSS -W-CVT_WCHAR_TO_ACHAR -W-CVT_NARROWING_STRING_LOST -W-CVT_ACHAR_TO_WCHAR -W-CVT_WIDENING_STRING_LOST -W-UNICODE_TO_LOCALE -W-LOCALE_TO_UNICODE -W-IMPLICIT_VARIANTS -W-IMPLICIT_INTEGER_CAST_LOSS -W-IMPLICIT_CONVERSION_LOSS -W-COMBINING_SIGNED_UNSIGNED64 -W-COMBINING_SIGNED_UNSIGNED64
|
||||
!ENDIF
|
||||
|
||||
DELPHIDPRPARAMS=-Q -B -GD -H -VT -^$C+ -^$D+ -^$J+ -^$L+ -^$O+ -^$Q- -^$R- -^$W+ -^$Y+ -E. $(DELPHIWARNINGS) -I$(DELPHIINCLUDES) -U$(DELPHIINCLUDES) -R$(DELPHIINCLUDES) -NSVcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Web;Soap;Winapi;System.Win -NU.\obj\Win32\$(TARGET_PATH) -E.\bin\Win32\$(TARGET_PATH)
|
||||
DELPHIDPRPARAMS64=-Q -B -GD -H -VT -^$C+ -^$D+ -^$J+ -^$L+ -^$O+ -^$Q- -^$R- -^$W+ -^$Y+ -E. $(DELPHIWARNINGS) -I$(DELPHIINCLUDES) -U$(DELPHIINCLUDES) -R$(DELPHIINCLUDES) -NSVcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Web;Soap;Winapi;System.Win -NU.\obj\Win64\$(TARGET_PATH) -E.\bin\Win64\$(TARGET_PATH)
|
||||
DELPHIDPKPARAMS=-Q -B -GD -VT -^$C+ -^$D+ -^$J+ -^$L+ -^$O+ -^$Q- -^$R- -^$W+ -^$Y+ -E. $(DELPHIWARNINGS) -I$(DELPHIINCLUDES) -U$(DELPHIINCLUDES) -R$(DELPHIINCLUDES) -NSVcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Web;Soap;Winapi;System.Win -LE$(OUTLIB) -LN$(OUTLIB) -NSData -NUobj\Win32\$(TARGET_PATH)
|
||||
|
||||
COMMON_DELPHIDPKPARAMS=-Q -B -GD -VT -^$C+ -^$D+ -^$J+ -^$L+ -^$O+ -^$Q- -^$R- -^$W+ -^$Y+ -E. $(DELPHIWARNINGS) -I$(DELPHIINCLUDES) -U$(DELPHIINCLUDES) -R$(DELPHIINCLUDES) -NSVcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Web;Soap;Winapi;System.Win -LE$(COMMON_OUTLIB) -LN$(COMMON_OUTLIB) -NSData -NUobj\Win32\$(TARGET_PATH)
|
||||
|
||||
# we are using cmd /c because dcc32/dcc64 are failing on direct execution
|
||||
# from nmake
|
||||
DCC32=cmd /c "$(DCC32PATH)\dcc32.exe" $(DELPHIDPRPARAMS)
|
||||
DCC32DPK=cmd /c "$(DCC32PATH)\dcc32.exe" $(DELPHIDPKPARAMS)
|
||||
COMMON_DCC32DPK=cmd /c "$(DCC32PATH)\dcc32.exe" $(COMMON_DELPHIDPKPARAMS)
|
||||
DCC64=cmd /c "$(DCC32PATH)\dcc64.exe" $(DELPHIDPRPARAMS64) -N0x64\ -Ex64\
|
||||
|
||||
#
|
||||
# Delphi MSBuild related commands and macros
|
||||
#
|
||||
|
||||
DELPHI_MSBUILD="$(COMMON_ROOT)\tools\msbuild-wrapper.bat" "$(DCC32PATH)" $(DELPHI_MSBUILD_FLAG_DEBUG)
|
||||
|
||||
!IFDEF NODELPHI
|
||||
DCC32=echo skipping
|
||||
DCC32DPK=echo skipping
|
||||
DCC64=echo skipping
|
||||
DELPHI_MSBUILD=echo skipping
|
||||
!ENDIF
|
||||
|
||||
# Visual C++ x86, x64
|
||||
WIN32_TARGET_PATH=bin\Win32\$(TARGET_PATH)
|
||||
X64_TARGET_PATH=bin\x64\$(TARGET_PATH)
|
||||
|
||||
# Delphi x86, x64
|
||||
# WIN32_TARGET_PATH=...
|
||||
WIN64_TARGET_PATH=bin\Win64\$(TARGET_PATH)
|
||||
|
||||
#
|
||||
# Shared devtools app for common Delphi source manipulation
|
||||
#
|
||||
|
||||
DEVTOOLS=$(COMMON_ROOT)\tools\devtools\$(WIN32_TARGET_PATH)\devtools.exe
|
||||
|
||||
#
|
||||
# Other program build commands
|
||||
#
|
||||
|
||||
BRCC32=rc.exe
|
||||
|
||||
HHC="C:\Program Files (x86)\HTML Help Workshop\hhc.exe"
|
||||
NMAKE=nmake.exe
|
||||
CL=cl.exe
|
||||
MSBUILD=msbuild.exe
|
||||
# /maxcpucount see https://devblogs.microsoft.com/cppblog/precompiled-header-pch-issues-and-recommendations/
|
||||
MT=mt.exe
|
||||
VCBUILD=error
|
||||
|
||||
!IFDEF DEBUG
|
||||
MSBUILD_BUILD=/t:Build /p:Configuration=Debug
|
||||
MSBUILD_CLEAN=/t:Clean /p:Configuration=Debug
|
||||
!ELSE
|
||||
MSBUILD_BUILD=/t:Rebuild /p:Configuration=Release
|
||||
MSBUILD_CLEAN=/t:Clean /p:Configuration=Release
|
||||
!ENDIF
|
||||
|
||||
COPY=copy
|
||||
ISXBUILD=C:\PROGRA~1\INSTALLSHIELD\Express\System\IsExpCmdBld
|
||||
WZZIPPATH="C:\program files\7-zip\7z.exe"
|
||||
!IFDEF GO_FAST
|
||||
WZZIP=$(WZZIPPATH) a -mx1
|
||||
!ELSE
|
||||
WZZIP=$(WZZIPPATH) a -mx9
|
||||
!ENDIF
|
||||
WZUNZIP=$(WZZIPPATH) e
|
||||
|
||||
# we are using cmd /c because tds2dbg is failing on direct execution
|
||||
# from nmake
|
||||
TDS2DBG=cmd /c $(KEYMAN_ROOT)\common\windows\bin\tools\tds2dbg
|
||||
SENTRYTOOL=$(COMMON_ROOT)\tools\sentrytool\$(WIN32_TARGET_PATH)\sentrytool.exe
|
||||
SENTRYTOOL_DELPHIPREP=$(SENTRYTOOL) delphiprep -r $(KEYMAN_ROOT) -i $(DELPHIINCLUDES)
|
||||
|
||||
WIXPATH="c:\program files (x86)\WiX Toolset v3.11\bin"
|
||||
WIXCANDLE=$(WIXPATH)\candle.exe -wx -nologo
|
||||
|
||||
!IFDEF LINT
|
||||
WIXLIGHTLINT=
|
||||
!ELSE
|
||||
# we suppress ICE82 because it reports spurious errors with merge module keymanengine to do with duplicate sequence numbers. Safely ignored.
|
||||
WIXLIGHTLINT= -sice:ICE82 -sice:ICE80
|
||||
!ENDIF
|
||||
|
||||
!IFDEF GO_FAST
|
||||
# for debug builds, we turn off compression because it is so hideously slow
|
||||
# for test builds, we also turn off compression
|
||||
WIXLIGHTCOMPRESSION=-dcl:none
|
||||
!ELSE
|
||||
WIXLIGHTCOMPRESSION=-dcl:high
|
||||
!ENDIF
|
||||
|
||||
WIXLIGHT=$(WIXPATH)\light.exe -wx -nologo $(WIXLIGHTLINT) $(WIXLIGHTCOMPRESSION)
|
||||
|
||||
WIXLIT=$(WIXPATH)\lit.exe -wx -nologo
|
||||
WIXHEAT=$(WIXPATH)\heat.exe
|
||||
|
||||
LINKPATH=link.exe
|
||||
|
||||
#
|
||||
# Certificates and code signing
|
||||
#
|
||||
|
||||
!ifdef SIGNCODE_BUILD
|
||||
MAKE=$(MAKE) "SIGNCODE_BUILD=$(SIGNCODE_BUILD)"
|
||||
!else
|
||||
MAKE=$(MAKE)
|
||||
!endif
|
||||
|
||||
#
|
||||
# To get a .pfx from a .spc and .pvk, run pvk2pfx.exe
|
||||
#
|
||||
|
||||
!IFNDEF SC_PFX_SHA1
|
||||
SC_PFX_SHA1="$(COMMON_ROOT)\tools\certificates\keymantest-sha1.pfx"
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF SC_PFX_SHA256
|
||||
SC_PFX_SHA256="$(COMMON_ROOT)\tools\certificates\keymantest-sha256.pfx"
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF SC_URL
|
||||
SC_URL="https://keyman.com/"
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF SC_PWD
|
||||
SC_PWD=""
|
||||
!ENDIF
|
||||
|
||||
SIGNCODE=@"$(KEYMAN_ROOT)\common\windows\signtime.bat" signtool.exe $(SC_PFX_SHA1) $(SC_PFX_SHA256) $(SC_URL) $(SC_PWD)
|
||||
|
||||
#
|
||||
# On some computers, the PLATFORM environment variable is set to x86. This can break msbuild
|
||||
# with our projects. This may be resolvable in the future, but for now the easy fix is ...
|
||||
#
|
||||
|
||||
PLATFORM=Win32
|
||||
|
||||
#
|
||||
# mkver commands. mkver determines tag from the local build environment variables
|
||||
# in the same way as /resources/build/build-utils.sh.
|
||||
#
|
||||
|
||||
!ifdef GIT_BASH_FOR_KEYMAN
|
||||
MKVER_SH=$(GIT_BASH_FOR_KEYMAN) $(KEYMAN_ROOT)\common\windows\mkver.sh
|
||||
!else
|
||||
MKVER_SH=start /wait $(KEYMAN_ROOT)\common\windows\mkver.sh
|
||||
!endif
|
||||
|
||||
MKVER_M=$(MKVER_SH) manifest.in manifest.xml
|
||||
MKVER_U=$(MKVER_SH)
|
||||
|
||||
#
|
||||
# Symstore
|
||||
#
|
||||
|
||||
# KEYMAN_SYMSTOREPATH defaults to sibling folder "symbols". If it is not present,
|
||||
# then we won't attempt to write symbols to the store.
|
||||
!IFNDEF KEYMAN_SYMSTOREPATH
|
||||
KEYMAN_SYMSTOREPATH=$(KEYMAN_ROOT)\..\symbols
|
||||
!ENDIF
|
||||
|
||||
# Nearly matches algorithm from resources/build/build-utils.sh
|
||||
# For now, we'll use it only for SYMSTORE, where it is for reference
|
||||
# only. Thus using the variable name __VERSION_WITH_TAG. Issues:
|
||||
# 1. always appends tier, even for stable
|
||||
# 2. test builds will append a branch name for master/beta/stable-x.y
|
||||
# 3. this is only available for `make symbols` (VERSION_WIN, VERSION_TIER
|
||||
# are defined in Targets.mak only here)
|
||||
# Fixing this properly would be possible but take a fair bit more
|
||||
# work than I want to do just now. The intent is to make it possible to find
|
||||
# symbols in the symstore index which we can purge later on.
|
||||
__VERSION_WITH_TAG=$(VERSION_WIN)-$(VERSION_TIER)
|
||||
!IFNDEF TEAMCITY_VERSION
|
||||
__VERSION_WITH_TAG=$(__VERSION_WITH_TAG)-local
|
||||
!ELSE
|
||||
!IFDEF TEAMCITY_PR_NUMBER
|
||||
__VERSION_WITH_TAG=$(__VERSION_WITH_TAG)-test-$(TEAMCITY_PR_NUMBER)
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
# This command depends on VERSION_WIN and VERSION_TIER being defined, through
|
||||
# `make symbols` (i.e. don't call `make wrap-symbols`)
|
||||
SYMSTORE="C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\symstore.exe" add \
|
||||
/s "$(KEYMAN_SYMSTOREPATH)" \
|
||||
/v "$(VERSION_WIN)" \
|
||||
/c "Version: $(__VERSION_WITH_TAG)" \
|
||||
/compress /f
|
||||
|
||||
CLEAN=-del /S /Q
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
#
|
||||
# Header.mak - used for makefiles which are in parent folders
|
||||
#
|
||||
|
||||
HEADER_MAK=1
|
||||
|
||||
!IFNDEF TARGETS
|
||||
!ERROR You must define the targets before including the Header.mak file!
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF KEYMAN_ROOT
|
||||
!ERROR KEYMAN_ROOT must be defined!
|
||||
!ENDIF
|
||||
|
||||
# This path will need to be updated if the root path changes
|
||||
|
||||
!include $(KEYMAN_ROOT)\common\windows\delphi\Defines.mak
|
||||
|
||||
#
|
||||
# The targets build, signcode, symbols are standard
|
||||
# targets for all projects
|
||||
#
|
||||
|
||||
build: $(BUILDPREREQ)
|
||||
$(MAKE) "TARGET=build" $(TARGETS)
|
||||
|
||||
!IFNDEF NOTARGET_SIGNCODE
|
||||
signcode:
|
||||
$(MAKE) "TARGET=signcode" $(TARGETS)
|
||||
|
||||
symbols:
|
||||
$(MAKE) "TARGET=symbols" $(TARGETS)
|
||||
!ELSE
|
||||
signcode:
|
||||
rem no signcode required
|
||||
|
||||
symbols:
|
||||
rem no symbols required
|
||||
!ENDIF
|
||||
|
||||
build-release:
|
||||
!IFDEF RELEASE_TARGETS
|
||||
$(MAKE) "TARGET=build-release" $(RELEASE_TARGETS)
|
||||
!ELSE
|
||||
@rem
|
||||
!ENDIF
|
||||
|
||||
clean:
|
||||
$(MAKE) "TARGET=clean" $(TARGETS) $(CLEANS)
|
||||
|
||||
install:
|
||||
$(MAKE) "TARGET=install" $(TARGETS)
|
||||
|
||||
test-manifest:
|
||||
!IFDEF MANIFESTS
|
||||
$(MAKE) "TARGET=test-manifest" $(MANIFESTS)
|
||||
!ELSE
|
||||
$(MAKE) "TARGET=test-manifest" $(TARGETS)
|
||||
!ENDIF
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
!CMDSWITCHES +S
|
||||
|
||||
def-clean:
|
||||
$(CLEAN) *.err *.stat *.dproj.local *.Build.CppClean.Log *.suo *.jdbg *.dbg *.dcu *.~* *.dsk *.exe *.rsm *.ncb *.opt *.pch *.plg *.aps *.001 *.sbr *.dep *.drc *.bak *.pdb *.lib *.cod *.ilk *.tds vc80.idb *.map *.bsc version.res manifest.xml manifest.res >nul 2>nul
|
||||
$(CLEAN) ExcMagic.Debug *.wixpdb *.identcache *.embed.manifest *.embed.manifest.res *.intermediate.manifest error.log >nul 2>nul
|
||||
if exist bin rd /s/q bin
|
||||
if exist obj rd /s/q obj
|
||||
|
||||
!CMDSWITCHES -S
|
||||
|
||||
# This virtual rule forces targets which are folders, e.g. `kmshell` to
|
||||
# always execute
|
||||
.virtual:
|
||||
rem always execute
|
||||
|
|
@ -13,31 +13,6 @@
|
|||
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Android' and '$(Base)'=='true') or '$(Base_Android)'!=''">
|
||||
<Base_Android>true</Base_Android>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Android64' and '$(Base)'=='true') or '$(Base_Android64)'!=''">
|
||||
<Base_Android64>true</Base_Android64>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='iOSDevice32' and '$(Base)'=='true') or '$(Base_iOSDevice32)'!=''">
|
||||
<Base_iOSDevice32>true</Base_iOSDevice32>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='iOSDevice64' and '$(Base)'=='true') or '$(Base_iOSDevice64)'!=''">
|
||||
<Base_iOSDevice64>true</Base_iOSDevice64>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='iOSSimulator' and '$(Base)'=='true') or '$(Base_iOSSimulator)'!=''">
|
||||
<Base_iOSSimulator>true</Base_iOSSimulator>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
|
||||
<Base_Win32>true</Base_Win32>
|
||||
<CfgParent>Base</CfgParent>
|
||||
|
|
@ -59,6 +34,12 @@
|
|||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
|
||||
<Cfg_2_Win32>true</Cfg_2_Win32>
|
||||
<CfgParent>Cfg_2</CfgParent>
|
||||
<Cfg_2>true</Cfg_2>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base)'!=''">
|
||||
<DCC_DcuOutput>.\obj\$(Platform)\$(Config)</DCC_DcuOutput>
|
||||
<DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
|
||||
|
|
@ -77,23 +58,6 @@
|
|||
<VerInfo_Locale>3081</VerInfo_Locale>
|
||||
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_Android)'!=''">
|
||||
<DCC_CBuilderOutput>None</DCC_CBuilderOutput>
|
||||
<EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_Android64)'!=''">
|
||||
<DCC_CBuilderOutput>None</DCC_CBuilderOutput>
|
||||
<EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_iOSDevice32)'!=''">
|
||||
<DCC_CBuilderOutput>None</DCC_CBuilderOutput>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_iOSDevice64)'!=''">
|
||||
<DCC_CBuilderOutput>None</DCC_CBuilderOutput>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_iOSSimulator)'!=''">
|
||||
<DCC_CBuilderOutput>None</DCC_CBuilderOutput>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_Win32)'!=''">
|
||||
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
|
||||
<BT_BuildType>Debug</BT_BuildType>
|
||||
|
|
@ -113,6 +77,7 @@
|
|||
<DCC_RemoteDebug>false</DCC_RemoteDebug>
|
||||
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
|
||||
<VerInfo_Locale>1033</VerInfo_Locale>
|
||||
<DCC_HppOutput>..\..\lib</DCC_HppOutput>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_2)'!=''">
|
||||
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
|
||||
|
|
@ -120,6 +85,11 @@
|
|||
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
|
||||
<DCC_DebugInformation>0</DCC_DebugInformation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
|
||||
<DCC_HppOutput>..\..\lib</DCC_HppOutput>
|
||||
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
|
||||
<VerInfo_Locale>1033</VerInfo_Locale>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<DelphiCompile Include="$(MainSource)">
|
||||
<MainSource>MainSource</MainSource>
|
||||
|
|
@ -164,8 +134,6 @@
|
|||
<Source Name="MainSource">common_components.dpk</Source>
|
||||
</Source>
|
||||
<Excluded_Packages>
|
||||
<Excluded_Packages Name="c:\projects\keyman\app\windows\lib\DCPdelphi2009.bpl">File c:\projects\keyman\app\windows\lib\DCPdelphi2009.bpl not found</Excluded_Packages>
|
||||
<Excluded_Packages Name="c:\projects\keyman\app\windows\lib\delphiprojectmanager.bpl">File c:\projects\keyman\app\windows\lib\delphiprojectmanager.bpl not found</Excluded_Packages>
|
||||
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k260.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
|
||||
<Excluded_Packages Name="$(BDSBIN)\dclofficexp260.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
|
||||
</Excluded_Packages>
|
||||
|
|
@ -944,13 +912,6 @@
|
|||
<ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
|
||||
</Deployment>
|
||||
<Platforms>
|
||||
<Platform value="Android">False</Platform>
|
||||
<Platform value="Android64">False</Platform>
|
||||
<Platform value="iOSDevice32">False</Platform>
|
||||
<Platform value="iOSDevice64">False</Platform>
|
||||
<Platform value="iOSSimulator">False</Platform>
|
||||
<Platform value="OSX32">False</Platform>
|
||||
<Platform value="OSX64">False</Platform>
|
||||
<Platform value="Win32">True</Platform>
|
||||
<Platform value="Win64">False</Platform>
|
||||
</Platforms>
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ builder_describe_outputs \
|
|||
function do_certificates() {
|
||||
rm -f KeymanTestCA-sha1.* KeymanTest-sha1.* KeymanTest-sha256.* KeymanTestCA-sha256.*
|
||||
|
||||
source "$KEYMAN_ROOT/resources/build/win/visualstudio_environment.inc.sh"
|
||||
|
||||
makecert -r -pe -n "CN=Keyman Test CA SHA1" -ss CA -sr CurrentUser -a sha1 -cy authority -sky signature -sv KeymanTestCA-sha1.pvk KeymanTestCA-sha1.cer
|
||||
certutil -user -addstore Root KeymanTestCA-sha1.cer
|
||||
makecert -pe -n "CN=Keyman Test Certificate SHA1" -a sha1 -cy end -sky signature -ic KeymanTestCA-sha1.cer -iv KeymanTestCA-sha1.pvk -sv KeymanTest-sha1.pvk KeymanTest-sha1.cer
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ ldml_processor::ldml_processor(path const & kb_path, const std::vector<uint8_t>
|
|||
} else {
|
||||
str = keyEntry->get_to_string();
|
||||
}
|
||||
keys.add((km_core_virtual_key)kmapEntry->vkey, (uint16_t)kmapEntry->mod, str);
|
||||
keys.add((km_core_virtual_key)kmapEntry->vkey, kmapEntry->mod, str);
|
||||
}
|
||||
} // else: no keys! but still valid. Just, no keys.
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ vkeys::vkeys() : vkey_to_string() {
|
|||
}
|
||||
|
||||
void
|
||||
vkeys::add(km_core_virtual_key vk, uint16_t modifier_state, std::u16string output) {
|
||||
vkeys::add(km_core_virtual_key vk, km_core_ldml_modifier_state modifier_state, std::u16string output) {
|
||||
// construct key
|
||||
const vkey_id id(vk, modifier_state);
|
||||
// assign the string
|
||||
|
|
|
|||
|
|
@ -19,10 +19,17 @@ namespace km {
|
|||
namespace core {
|
||||
namespace ldml {
|
||||
|
||||
/**
|
||||
* LDML keyboards have 32-bit modifier flags in order to support
|
||||
* LDML_KEYS_MOD_OTHER (0x10000), unlike the Core APIs which have only 16 bit
|
||||
* modifier flags.
|
||||
*/
|
||||
typedef uint32_t km_core_ldml_modifier_state;
|
||||
|
||||
/**
|
||||
* identifier for keybag lookup
|
||||
*/
|
||||
typedef std::pair<km_core_virtual_key, uint16_t> vkey_id;
|
||||
typedef std::pair<km_core_virtual_key, km_core_ldml_modifier_state> vkey_id;
|
||||
|
||||
/**
|
||||
* LDML Class to manage all things key related: vkey remapping and vkey to string
|
||||
|
|
@ -35,9 +42,9 @@ public:
|
|||
vkeys();
|
||||
|
||||
/**
|
||||
* add a vkey to the bag
|
||||
* add a vkey to the bag.
|
||||
*/
|
||||
void add(km_core_virtual_key vk, uint16_t modifier_state, std::u16string output);
|
||||
void add(km_core_virtual_key vk, km_core_ldml_modifier_state ldml_modifier_state, std::u16string output);
|
||||
|
||||
/**
|
||||
* Lookup a vkey, returns an empty string if not found
|
||||
|
|
|
|||
|
|
@ -2,6 +2,42 @@
|
|||
|
||||
This is the current home for Keyman Developer.
|
||||
|
||||
## Build Prerequisites
|
||||
|
||||
* See [Windows Build Environment Configuration](../../docs/build/windows.md).
|
||||
|
||||
## Building Keyman Developer
|
||||
|
||||
1. Start 'Git Bash' (part of Git for Windows).
|
||||
2. Run `developer/src/build.sh`.
|
||||
3. Artifacts from a successful build will be placed in **developer/bin** folder.
|
||||
|
||||
*Note*: running `build.sh` will currently reset the packages and path settings
|
||||
in your Delphi environment. If you use Delphi for other projects, you should
|
||||
consider building Keyman under a login user dedicated to it, or in a VM.
|
||||
|
||||
Type `build.sh` to see build targets and actions. Common build actions are:
|
||||
|
||||
* `build.sh build`
|
||||
: builds Keyman Developer
|
||||
|
||||
* `build.sh clean`
|
||||
: remove temporary files and build artifacts
|
||||
|
||||
* `build.sh publish`
|
||||
: makes a release of all Keyman Developer projects
|
||||
|
||||
* `build.sh install`
|
||||
: install some or all components to Program Files (requires elevated command prompt).
|
||||
|
||||
### Building without Delphi
|
||||
|
||||
It is possible to build all components that do _not_ require Delphi. Currently a
|
||||
few components are Delphi-based (TIKE, setup, a few others), but you may be able
|
||||
to get away without building them. In this situation, we recommend copying the
|
||||
relevant Delphi-built components into developer/bin folders from a compatible
|
||||
installed version of Keyman Developer for testing and debugging purposes.
|
||||
|
||||
# Folders
|
||||
|
||||
## common
|
||||
|
|
@ -106,4 +142,6 @@ testing and packing keyboards for distribution.
|
|||
|
||||
## tools
|
||||
|
||||
Various build-time tools for Keyman Developer.
|
||||
Various build-time tools for Keyman Developer.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -35,9 +35,9 @@ function copy_cldr_imports() {
|
|||
# TODO-LDML: developer/src/inst/download.in.mak needs these also...
|
||||
CLDR_PATH=$(dirname "$CLDR_INFO_PATH")
|
||||
CLDR_VER=$(basename "$CLDR_PATH")
|
||||
mkdir -p "$THIS_SCRIPT_PATH/build/src/import/$CLDR_VER"
|
||||
mkdir -p "$THIS_SCRIPT_PATH/build/src/types/import/$CLDR_VER"
|
||||
# TODO-LDML: When these are copied, the DOCTYPE will break due to the wrong path. We don't use the DTD so it should be OK.
|
||||
cp "$CLDR_INFO_PATH" "$CLDR_PATH/import/"*.xml "$THIS_SCRIPT_PATH/build/src/import/$CLDR_VER/"
|
||||
cp "$CLDR_INFO_PATH" "$CLDR_PATH/import/"*.xml "$THIS_SCRIPT_PATH/build/src/types/import/$CLDR_VER/"
|
||||
done
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export class LDMLKeyboardXMLSourceFileReader {
|
|||
}
|
||||
|
||||
static get defaultImportsURL(): [string,string] {
|
||||
return ['../../import/', import.meta.url];
|
||||
return ['../import/', import.meta.url];
|
||||
}
|
||||
|
||||
readImportFile(version: string, subpath: string): Uint8Array {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,23 @@ import { LDMLKeyboard, CompilerCallbacks } from "@keymanapp/developer-utils";
|
|||
import { KeysCompiler } from "./keys.js";
|
||||
import { LdmlCompilerMessages } from "./ldml-compiler-messages.js";
|
||||
|
||||
// This is a partial polyfill for findLast, so not polluting Array.prototype
|
||||
// https://medium.com/@stheodorejohn/findlast-method-polyfill-in-javascript-bridging-browser-gaps-c3baf6aabae1
|
||||
// TODO: remove and replace with Array.prototype.findLast when it is
|
||||
// well-supported
|
||||
function findLast(arr: any, callback: any) {
|
||||
if (!arr) {
|
||||
return undefined;
|
||||
}
|
||||
const len = arr.length >>> 0;
|
||||
for (let i = len - 1; i >= 0; i--) {
|
||||
if (callback(arr[i], i, arr)) {
|
||||
return arr[i];
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export class LdmlKeyboardVisualKeyboardCompiler {
|
||||
public constructor(private callbacks: CompilerCallbacks) {
|
||||
}
|
||||
|
|
@ -57,7 +74,8 @@ export class LdmlKeyboardVisualKeyboardCompiler {
|
|||
const keyId = key;
|
||||
x++;
|
||||
|
||||
let keydef = source.keyboard3.keys?.key?.find(x => x.id == key);
|
||||
//@ts-ignore
|
||||
let keydef = findLast(source.keyboard3.keys?.key, x => x.id == key);
|
||||
|
||||
if (!keydef) {
|
||||
this.callbacks.reportMessage(
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import { KeymanFileTypes } from '@keymanapp/common-types';
|
|||
describe('LexicalModelCompiler', function () {
|
||||
let callbacks = new TestCompilerCallbacks();
|
||||
|
||||
this.timeout(5000);
|
||||
|
||||
// Try to compile ALL of the correct models.
|
||||
const MODELS = [
|
||||
'example.qaa.sencoten',
|
||||
|
|
|
|||
|
|
@ -2310,11 +2310,11 @@ KMX_DWORD GetXStringImpl(PKMX_WCHAR tstr, PFILE_KEYBOARD fk, PKMX_WCHAR str, KMX
|
|||
{
|
||||
if (u16icmp(q, fk->dpStoreArray[i].szName) == 0) break;
|
||||
}
|
||||
if (i == fk->cxStoreArray) return KmnCompilerMessages::ERROR_StoreDoesNotExist;
|
||||
|
||||
if (!kmcmp::IsValidCallStore(&fk->dpStoreArray[i])) return KmnCompilerMessages::ERROR_InvalidCall;
|
||||
kmcmp::CheckStoreUsage(fk, i, FALSE, FALSE, TRUE);
|
||||
|
||||
if (i == fk->cxStoreArray) return KmnCompilerMessages::ERROR_StoreDoesNotExist;
|
||||
tstr[mx++] = UC_SENTINEL;
|
||||
tstr[mx++] = CODE_CALL;
|
||||
tstr[mx++] = (KMX_WCHAR)i + 1;
|
||||
|
|
|
|||
|
|
@ -1225,6 +1225,94 @@ TEST_F(CompilerTest, GetXStringImpl_type_o_test) {
|
|||
EXPECT_EQ(0, u16cmp(tstr_outs_space_after_valid, tstr));
|
||||
}
|
||||
|
||||
// tests strings starting with 'c'
|
||||
TEST_F(CompilerTest, GetXStringImpl_type_c_test) {
|
||||
KMX_WCHAR tstr[128];
|
||||
fileKeyboard.version = VERSION_60;
|
||||
KMX_WCHAR str[LINESIZE];
|
||||
KMX_WCHAR output[GLOBAL_BUFSIZE];
|
||||
PKMX_WCHAR newp = nullptr;
|
||||
PFILE_STORE file_store = new FILE_STORE[100];
|
||||
fileKeyboard.cxStoreArray = 3u;
|
||||
fileKeyboard.dpStoreArray = file_store;
|
||||
file_store[1].fIsCall = TRUE;
|
||||
file_store[1].dwSystemID = TSS_NONE;
|
||||
u16cpy(file_store[0].szName, u"a");
|
||||
u16cpy(file_store[1].szName, u"b");
|
||||
u16cpy(file_store[2].szName, u"c");
|
||||
|
||||
// call, KmnCompilerMessages::ERROR_501FeatureOnly_Call
|
||||
fileKeyboard.version = VERSION_50;
|
||||
u16cpy(str, u"call");
|
||||
EXPECT_EQ(KmnCompilerMessages::ERROR_501FeatureOnly_Call, GetXStringImpl(tstr, &fileKeyboard, str, u"", output, 80, 0, &newp, FALSE));
|
||||
|
||||
// call, KmnCompilerMessages::ERROR_CallInVirtualKeySection *** TODO ***
|
||||
|
||||
// call, no close delimiter => NULL
|
||||
fileKeyboard.version = VERSION_501;
|
||||
u16cpy(str, u"call(");
|
||||
EXPECT_EQ(KmnCompilerMessages::ERROR_InvalidCall, GetXStringImpl(tstr, &fileKeyboard, str, u"", output, 80, 0, &newp, FALSE));
|
||||
|
||||
// call, empty delimiters => empty string
|
||||
fileKeyboard.version = VERSION_501;
|
||||
u16cpy(str, u"call()");
|
||||
EXPECT_EQ(KmnCompilerMessages::ERROR_InvalidCall, GetXStringImpl(tstr, &fileKeyboard, str, u"", output, 80, 0, &newp, FALSE));
|
||||
|
||||
// call, space in delimiters (see I11814, I11937, #11910, #11894, #11938)
|
||||
fileKeyboard.version = VERSION_501;
|
||||
u16cpy(str, u"call( )");
|
||||
EXPECT_EQ(KmnCompilerMessages::ERROR_InvalidCall, GetXStringImpl(tstr, &fileKeyboard, str, u"", output, 80, 0, &newp, FALSE));
|
||||
|
||||
// call, KmnCompilerMessages::ERROR_StoreDoesNotExist
|
||||
fileKeyboard.version = VERSION_501;
|
||||
u16cpy(str, u"call(d)");
|
||||
EXPECT_EQ(KmnCompilerMessages::ERROR_StoreDoesNotExist, GetXStringImpl(tstr, &fileKeyboard, str, u"", output, 80, 0, &newp, FALSE));
|
||||
|
||||
// call, KmnCompilerMessages::ERROR_StoreDoesNotExist, space before store
|
||||
fileKeyboard.version = VERSION_501;
|
||||
u16cpy(str, u"call( d)");
|
||||
EXPECT_EQ(KmnCompilerMessages::ERROR_StoreDoesNotExist, GetXStringImpl(tstr, &fileKeyboard, str, u"", output, 80, 0, &newp, FALSE));
|
||||
|
||||
// call, KmnCompilerMessages::ERROR_StoreDoesNotExist, space after store
|
||||
fileKeyboard.version = VERSION_501;
|
||||
u16cpy(str, u"call(d )");
|
||||
EXPECT_EQ(KmnCompilerMessages::ERROR_StoreDoesNotExist, GetXStringImpl(tstr, &fileKeyboard, str, u"", output, 80, 0, &newp, FALSE));
|
||||
|
||||
// call, KmnCompilerMessages::ERROR_InvalidCall
|
||||
fileKeyboard.version = VERSION_501;
|
||||
file_store[1].dpString = (PKMX_WCHAR)u"*"; // cause IsValidCallStore() to fail
|
||||
u16cpy(str, u"call(b)");
|
||||
EXPECT_EQ(KmnCompilerMessages::ERROR_InvalidCall, GetXStringImpl(tstr, &fileKeyboard, str, u"", output, 80, 0, &newp, FALSE));
|
||||
|
||||
// call, valid
|
||||
fileKeyboard.version = VERSION_501;
|
||||
file_store[1].dpString = (PKMX_WCHAR)u"a.dll:A";
|
||||
file_store[1].dwSystemID = TSS_NONE;
|
||||
u16cpy(str, u"call(b)");
|
||||
EXPECT_EQ(STATUS_Success, GetXStringImpl(tstr, &fileKeyboard, str, u"", output, 80, 0, &newp, FALSE));
|
||||
const KMX_WCHAR tstr_call_valid[] = { UC_SENTINEL, CODE_CALL, 2, 0 };
|
||||
EXPECT_EQ(0, u16cmp(tstr_call_valid, tstr));
|
||||
EXPECT_EQ(TSS_CALLDEFINITION, file_store[1].dwSystemID);
|
||||
|
||||
// call, space before store, valid
|
||||
fileKeyboard.version = VERSION_501;
|
||||
file_store[1].dpString = (PKMX_WCHAR)u"a.dll:A";
|
||||
file_store[1].dwSystemID = TSS_NONE;
|
||||
u16cpy(str, u"call( b)");
|
||||
EXPECT_EQ(STATUS_Success, GetXStringImpl(tstr, &fileKeyboard, str, u"", output, 80, 0, &newp, FALSE));
|
||||
EXPECT_EQ(0, u16cmp(tstr_call_valid, tstr));
|
||||
EXPECT_EQ(TSS_CALLDEFINITION, file_store[1].dwSystemID);
|
||||
|
||||
// call, space after store, valid (see I11937, #11938)
|
||||
fileKeyboard.version = VERSION_501;
|
||||
file_store[1].dpString = (PKMX_WCHAR)u"a.dll:A";
|
||||
file_store[1].dwSystemID = TSS_NONE;
|
||||
u16cpy(str, u"call(b )");
|
||||
EXPECT_EQ(STATUS_Success, GetXStringImpl(tstr, &fileKeyboard, str, u"", output, 80, 0, &newp, FALSE));
|
||||
EXPECT_EQ(0, u16cmp(tstr_call_valid, tstr));
|
||||
EXPECT_EQ(TSS_CALLDEFINITION, file_store[1].dwSystemID);
|
||||
}
|
||||
|
||||
// KMX_DWORD process_baselayout(PFILE_KEYBOARD fk, PKMX_WCHAR q, PKMX_WCHAR tstr, int *mx)
|
||||
// KMX_DWORD process_platform(PFILE_KEYBOARD fk, PKMX_WCHAR q, PKMX_WCHAR tstr, int *mx)
|
||||
// KMX_DWORD process_if_synonym(KMX_DWORD dwSystemID, PFILE_KEYBOARD fk, PKMX_WCHAR q, PKMX_WCHAR tstr, int *mx)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ source "$KEYMAN_ROOT/resources/build/win/environment.inc.sh"
|
|||
WIN32_TARGET="$WIN32_TARGET_PATH/tike.exe"
|
||||
|
||||
builder_describe_outputs \
|
||||
configure:project /resources/build/win/delphi_environment_generated.inc.sh \
|
||||
configure:project /developer/src/tike/xml/layoutbuilder/keymanweb-osk.ttf \
|
||||
build:project /developer/src/tike/$WIN32_TARGET
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------------------
|
||||
|
|
@ -31,6 +31,7 @@ function do_configure() {
|
|||
mkdir -p "$DEVELOPER_PROGRAM"
|
||||
cp "$KEYMAN_ROOT/common/schemas/kps/kps.xsd" "$DEVELOPER_PROGRAM"
|
||||
cp "$KEYMAN_ROOT/common/resources/fonts/keymanweb-osk.ttf" "$DEVELOPER_ROOT/src/tike/xml/layoutbuilder/keymanweb-osk.ttf"
|
||||
run_in_vs_env rc icons.rc
|
||||
}
|
||||
|
||||
function do_monaco_copy() {
|
||||
|
|
@ -52,8 +53,6 @@ function do_monaco_copy() {
|
|||
pushd "$DEVELOPER_ROOT/src/tike/xml/app/lib/sentry"
|
||||
replaceVersionStrings_Mkver init.js.in init.js
|
||||
popd
|
||||
|
||||
run_in_vs_env rc icons.rc
|
||||
}
|
||||
|
||||
KEYMANCORE_DLL=keymancore-2.dll
|
||||
|
|
|
|||
26
docs/build/linux-ubuntu.md
vendored
|
|
@ -63,17 +63,33 @@ See [node.md](node.md) for more information.
|
|||
|
||||
#### Emscripten
|
||||
|
||||
You'll also have to install `emscripten` (version 3.1.44 is known to work):
|
||||
You'll also have to install `emscripten`:
|
||||
|
||||
```shell
|
||||
git clone https://github.com/emscripten-core/emsdk.git
|
||||
cd emsdk
|
||||
./emsdk install 3.1.44
|
||||
./emsdk activate 3.1.44
|
||||
export EMSCRIPTEN_BASE=$(pwd)/upstream/emscripten
|
||||
./emsdk install 3.1.58
|
||||
./emsdk activate 3.1.58
|
||||
export EMSCRIPTEN_BASE="$(pwd)/upstream/emscripten"
|
||||
echo "export EMSCRIPTEN_BASE=\"$EMSCRIPTEN_BASE\"" >> .bashrc
|
||||
```
|
||||
|
||||
**NOTE:** Don't put EMSDK on the path, i.e. don't source `emsdk_env.sh`.
|
||||
> ![WARNING]
|
||||
> Don't put EMSDK on the path, i.e. don't source `emsdk_env.sh`.
|
||||
>
|
||||
> Emscripten very unhelpfully overwrites `JAVA_HOME`, and adds its own
|
||||
> versions of Python, Node and Java to the `PATH`. For best results, restart
|
||||
> your shell after installing Emscripten so that you don't end up with the
|
||||
> wrong versions.
|
||||
|
||||
**Optional environment variables**:
|
||||
|
||||
To let the Keyman build scripts control the version of Emscripten installed on
|
||||
your computer:
|
||||
|
||||
```shell
|
||||
export KEYMAN_USE_EMSDK=1
|
||||
```
|
||||
|
||||
## Keyman Core
|
||||
|
||||
|
|
|
|||
36
docs/build/macos.md
vendored
|
|
@ -91,16 +91,38 @@ See [node.md](node.md) for more information.
|
|||
|
||||
### emscripten
|
||||
|
||||
To install emscripten:
|
||||
The recommended way to install emscripten is with the official method, as that
|
||||
then allows the build scripts to select the appropriate version automatically.
|
||||
|
||||
```shell
|
||||
brew install emscripten
|
||||
To install emscripten, `cd` to an appropriate path, and then:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/emscripten-core/emsdk
|
||||
cd emsdk
|
||||
emsdk install 3.1.58
|
||||
emsdk activate 3.1.58
|
||||
export EMSCRIPTEN_BASE="$(pwd)/upstream/emscripten"
|
||||
echo "export EMSCRIPTEN_BASE=\"$EMSCRIPTEN_BASE\"" >> .bashrc
|
||||
```
|
||||
|
||||
Note: if you install emscripten with brew on macOS, only emscripten binaries are
|
||||
added to the path via symlinks. This makes it reasonably safe to have emscripten
|
||||
on the path, unlike on other platforms where emscripten also ends up adding its
|
||||
versions of node, python, and other binaries to the path.
|
||||
You will want to add `EMSCRIPTEN_BASE` to your .bashrc.
|
||||
|
||||
> ![WARNING]
|
||||
> Don't put EMSDK on the path, i.e. don't source `emsdk_env.sh`.
|
||||
>
|
||||
> Emscripten very unhelpfully overwrites `JAVA_HOME`, and adds its own
|
||||
> versions of Python, Node and Java to the `PATH`. For best results, restart
|
||||
> your shell after installing Emscripten so that you don't end up with the
|
||||
> wrong versions.
|
||||
|
||||
**Optional environment variables**:
|
||||
|
||||
To let the Keyman build scripts control the version of Emscripten installed on
|
||||
your computer:
|
||||
|
||||
```shell
|
||||
export KEYMAN_USE_EMSDK=1
|
||||
```
|
||||
|
||||
## Keyman for iOS Dependencies
|
||||
|
||||
|
|
|
|||
314
docs/build/windows.md
vendored
|
|
@ -6,13 +6,13 @@ On Windows, you can build the following projects:
|
|||
|
||||
* [Keyman for Android](#keyman-for-android)
|
||||
* [Keyman for Windows](#keyman-for-windows)
|
||||
* [Keyman Developer](#keyman-developer) (together with Keyman for Windows)
|
||||
* [Keyman Developer](#keyman-developer)
|
||||
* [KeymanWeb](#keymanweb)
|
||||
|
||||
The following libraries can also be built:
|
||||
|
||||
* Keyman Core (Windows, wasm targets) (aka core)
|
||||
* Common/Web
|
||||
* Keyman Core (Windows, wasm targets)
|
||||
* Common libraries
|
||||
|
||||
The following projects **cannot** be built on Windows:
|
||||
|
||||
|
|
@ -63,10 +63,6 @@ Dependencies:
|
|||
* [Base](#base-dependencies)
|
||||
* [Windows Platform](#windows-platform-dependencies)
|
||||
|
||||
**Note**: Keyman for Windows is currently built together with Keyman Developer.
|
||||
We are working on splitting these projects. For now, you will need the Keyman
|
||||
Developer dependencies as well.
|
||||
|
||||
Building:
|
||||
* [Building Keyman for Windows](../../windows/src/README.md)
|
||||
|
||||
|
|
@ -75,7 +71,7 @@ Building:
|
|||
Dependencies:
|
||||
* [Base](#base-dependencies)
|
||||
* [Web](#web-dependencies)
|
||||
* [Windows Platform](#windows-platform-dependencies)
|
||||
* [Windows Platform](#windows-platform-dependencies) (optional, for Windows-only components)
|
||||
|
||||
Building:
|
||||
* [Building Keyman Developer](../../windows/src/README.md)
|
||||
|
|
@ -94,42 +90,19 @@ Building:
|
|||
**Dependencies**:
|
||||
* [Base](#base-dependencies)
|
||||
* [Web](#web-dependencies)
|
||||
|
||||
**Additional requirements**:
|
||||
* Android SDK
|
||||
* Android Studio
|
||||
* Ant
|
||||
* Gradle
|
||||
* Maven
|
||||
* Optional: OpenJDK 11 (https://learn.microsoft.com/en-us/java/openjdk/download)
|
||||
|
||||
```ps1
|
||||
# Elevated PowerShell
|
||||
choco install android-sdk android-studio ant gradle maven
|
||||
# optionally install sdk images
|
||||
sdkmanager "system-images;android-33;google_apis;armeabi-v7a"
|
||||
sdkmanager --update
|
||||
sdkmanager --licenses
|
||||
```
|
||||
|
||||
* Run Android Studio once after installation to install additional components
|
||||
such as emulator images and SDK updates.
|
||||
|
||||
**Required environment variables**:
|
||||
* [`JAVA_HOME`](#java_home)
|
||||
|
||||
**Optional environment variables**:
|
||||
* [`JAVA_HOME_11`](#java_home)
|
||||
* [Android](#android-dependencies)
|
||||
|
||||
Building:
|
||||
* [Building Keyman for Android](../../android/README.md)
|
||||
|
||||
## Prerequisites
|
||||
---
|
||||
|
||||
## Dependencies and Prerequisites
|
||||
|
||||
Many dependencies are only required for specific projects.
|
||||
|
||||
We prefer [Chocolatey](https://chocolatey.org/install) at present for
|
||||
installation of dependencies. Chocolatey should be run in an elevated
|
||||
installation of most dependencies. Chocolatey should be run in an elevated
|
||||
PowerShell.
|
||||
|
||||
### Base Dependencies
|
||||
|
|
@ -150,28 +123,36 @@ PowerShell.
|
|||
# for *much* faster download, hide progress bar (PowerShell/PowerShell#2138)
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
choco install git jq python ninja pandoc meson
|
||||
refreshenv
|
||||
```
|
||||
|
||||
**Environment variables**:
|
||||
* [`KEYMAN_ROOT`](#keyman_root)
|
||||
* `PATH`: add your Python scripts folder to your path: it will normally be `%appdata%\Python\Python310\Scripts`.
|
||||
|
||||
If you pull the entire `keyman.git` repo to `c:\keyman`, then the paths by
|
||||
default will work without changes. Otherwise, you will need to set an
|
||||
environment variable `KEYMAN_ROOT` to the root path of the Keyman repo. For
|
||||
example:
|
||||
|
||||
```bat
|
||||
SET KEYMAN_ROOT=c:\Projects\keyman\keyman
|
||||
SET PATH=%path%;%appdata%\Python\Python310\Scripts
|
||||
SETX KEYMAN_ROOT "c:\Projects\keyman\keyman"
|
||||
```
|
||||
|
||||
To check whether environment variables are set, run `SET <variable>` in command
|
||||
prompt.
|
||||
> [!NOTE]
|
||||
> The `SETX` command will set persistent environment variables but they do not
|
||||
> impact the current shell environment. Start a new shell to see the variables.
|
||||
|
||||
You can use Windows Settings to add these environment variables permanently:
|
||||
|
||||
1. In Windows Search, type "environment" and select "Edit System Environment
|
||||
Variables"
|
||||
2. Click `Environment Variables...`
|
||||
3. You can add or edit variables in either User or System settings, as you
|
||||
prefer.
|
||||
> [!TIP]
|
||||
>
|
||||
> To check whether environment variables are set, run `SET <variable>` in command
|
||||
> prompt.
|
||||
>
|
||||
> You can alternatively use Windows Settings to add these environment variables
|
||||
> permanently:
|
||||
>
|
||||
> 1. In Windows Search, type "environment" and select "Edit System Environment
|
||||
> Variables"
|
||||
> 2. Click `Environment Variables...`
|
||||
> 3. You can add or edit variables in either User or System settings, as you
|
||||
> prefer.
|
||||
|
||||
### Web Dependencies
|
||||
|
||||
|
|
@ -181,32 +162,46 @@ You can use Windows Settings to add these environment variables permanently:
|
|||
* KeymanWeb
|
||||
|
||||
**Requirements**:
|
||||
* emscripten 3.1.46 or later
|
||||
* node.js 18+
|
||||
* [openjdk 11](https://learn.microsoft.com/en-us/java/openjdk/download#openjdk-11)+
|
||||
* Emscripten
|
||||
* node.js
|
||||
|
||||
```ps1
|
||||
# Elevated PowerShell
|
||||
#### Emscripten
|
||||
|
||||
# for *much* faster download, hide progress bar (PowerShell/PowerShell#2138)
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
In bash, run the following commands:
|
||||
|
||||
choco install emscripten --version 3.1.46
|
||||
```bash
|
||||
cd /c/Projects/keyman
|
||||
git clone https://github.com/emscripten-core/emsdk
|
||||
cd emsdk
|
||||
emsdk install 3.1.58
|
||||
emsdk activate 3.1.58
|
||||
```
|
||||
|
||||
Note: emscripten very unhelpfully overwrites JAVA_HOME, and adds its own
|
||||
versions of Python, Node and Java to the PATH. For best results, go ahead
|
||||
and remove those paths from your PATH variable before continuing.
|
||||
> ![WARNING]
|
||||
> Emscripten very unhelpfully overwrites `JAVA_HOME`, and adds its own
|
||||
> versions of Python, Node and Java to the `PATH`. For best results, restart
|
||||
> your shell after installing Emscripten so that you don't end up with the
|
||||
> wrong versions.
|
||||
|
||||
There is no need to add emscripten to the path in order to build Keyman.
|
||||
However, you should set the EMSCRIPTEN_BASE variable to the path where `emcc`
|
||||
can be found, but always in the upstream\emscripten subdirectory where you
|
||||
installed emsdk (most likely %LocalAppData%\emsdk\upstream\emscripten)
|
||||
However, you should set the `EMSCRIPTEN_BASE` variable to the path where `emcc`
|
||||
can be found, in the `upstream\emscripten` subdirectory of where you installed
|
||||
emsdk.
|
||||
|
||||
**Environment variables**:
|
||||
* `EMSCRIPTEN_BASE`: `<your-emsdk-path>\upstream\emscripten`
|
||||
|
||||
After installing emscripten, you'll need to install node.js and openjdk.
|
||||
```bat
|
||||
SETX EMSCRIPTEN_BASE "<your-emsdk-path>\upstream\emscripten"
|
||||
```
|
||||
|
||||
**Optional environment variables**:
|
||||
|
||||
To let the Keyman build scripts control the version of Emscripten
|
||||
installed on your computer:
|
||||
|
||||
```bat
|
||||
SETX KEYMAN_USE_EMSDK 1
|
||||
```
|
||||
|
||||
#### node.js
|
||||
|
||||
|
|
@ -214,30 +209,22 @@ Our recommended way to install node.js is to use
|
|||
[nvm-windows](https://github.com/coreybutler/nvm-windows). This makes it
|
||||
easy to switch between versions of node.js.
|
||||
|
||||
Alternatively, use Powershell + Chocolatey to install node.js:
|
||||
|
||||
```ps1
|
||||
# Elevated PowerShell
|
||||
|
||||
# for *much* faster download, hide progress bar (PowerShell/PowerShell#2138)
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
choco install nodejs
|
||||
```bat
|
||||
nvm install 20.16.0
|
||||
nvm use 20.16.0
|
||||
```
|
||||
|
||||
See [node.md](node.md) for more information.
|
||||
**Optional environment variables**:
|
||||
|
||||
#### openjdk
|
||||
To let the Keyman build scripts control the version of node.js installed
|
||||
and active on your computer:
|
||||
|
||||
Use Powershell + Chocolatey to install OpenJDK:
|
||||
|
||||
```ps1
|
||||
# Elevated PowerShell
|
||||
|
||||
# for *much* faster download, hide progress bar (PowerShell/PowerShell#2138)
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
choco install openjdk
|
||||
```
|
||||
```bat
|
||||
SETX KEYMAN_USE_NVM 1
|
||||
````
|
||||
|
||||
See [node.md](node.md) for more information, including automatic selection
|
||||
of appropriate node versions during builds.
|
||||
|
||||
### Windows Platform Dependencies
|
||||
|
||||
|
|
@ -260,8 +247,7 @@ choco install openjdk
|
|||
Start Delphi IDE once after installation as it will create various environment
|
||||
files and take you through required registration.
|
||||
|
||||
* Note: It is possible to build all components that do _not_ require Delphi by
|
||||
adding the environment variable `NODELPHI=1` before starting the build.
|
||||
* Note: It is possible to build all components that do _not_ require Delphi.
|
||||
Currently many components are Delphi-based, but if you are working just in
|
||||
Keyman Core, the compiler, or Keyman Engine's C++ components, you may be
|
||||
able to get away without building them. In this situation, we recommend
|
||||
|
|
@ -273,10 +259,12 @@ choco install openjdk
|
|||
```ps1
|
||||
choco install visualstudio2019community visualstudio2019-workload-nativedesktop visualstudio2019buildtools
|
||||
```
|
||||
|
||||
* Verify required build tools are installed
|
||||
* Run `Visual Studio Installer`
|
||||
* Check the `Individual components` tab
|
||||
* Verify `MSVC v142 - VS 2019 c++ x64/x86 build tools (Latest)` is installed. If not, install it.
|
||||
* Verify `MSVC v142 - VS 2019 c++ x64/x86 build tools (Latest)` is installed.
|
||||
If not, install it.
|
||||
|
||||
Recommended: configure Visual Studio to use two-space tab stops:
|
||||
1. Open the options dialog: Tools > Options.
|
||||
|
|
@ -284,55 +272,15 @@ choco install openjdk
|
|||
3. Change 'Tab size' to 2 and 'Indent size' to 2.
|
||||
4. Select 'Insert spaces'.
|
||||
|
||||
* Windows SDK (C++ Desktop Development)
|
||||
|
||||
https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/
|
||||
|
||||
**Required environment variables**:
|
||||
* `PATH`
|
||||
* Add the C:\Projects\keyman\keyman\windows\lib folder in the Keyman
|
||||
* Add the `C:\Projects\keyman\keyman\windows\lib` folder in the Keyman
|
||||
repository to your `PATH` environment variable. This is required for
|
||||
Keyman's design-time packages to load in Delphi.
|
||||
* [`KEYMAN_CEF4DELPHI_ROOT`](#keyman_cef4delphi_root)
|
||||
|
||||
**Optional environment variables**:
|
||||
* [`GIT_BASH_FOR_KEYMAN`](#git_bash_for_keyman)
|
||||
* [`USERDEFINES`](#userdefines)
|
||||
|
||||
```bat
|
||||
SET KEYMAN_CEF4DELPHI_ROOT=c:\Projects\keyman\CEF4Delphi_Binary
|
||||
SET GIT_BASH_FOR_KEYMAN="C:\Program Files\Git\bin\bash.exe" --init-file "c:\Program Files\Git\etc\profile" -l
|
||||
```
|
||||
|
||||
**Additional requirements for release builds**:
|
||||
* [Certificates](#certificates)
|
||||
* [7-Zip](http://www.7-zip.org/), used for archiving build files
|
||||
* [HTML Help Workshop](http://web.archive.org/web/20160201063255/http://download.microsoft.com/download/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe) note: Microsoft no longer offer this download...
|
||||
* [WiX 3.11.1](https://github.com/wixtoolset/wix3/releases/tag/wix3111rtm)
|
||||
* [CEF4Delphi_Binary](https://github.com/keymanapp/CEF4Delphi_Binary) repository
|
||||
|
||||
```ps1
|
||||
# Elevated PowerShell
|
||||
choco install 7zip html-help-workshop
|
||||
choco install wixtoolset --version=3.11.1
|
||||
git clone https://github.com/keymanapp/CEF4Delphi_Binary C:\Projects\keyman\CEF4Delphi_Binary
|
||||
```
|
||||
|
||||
## Certificates
|
||||
|
||||
In order to make a release build, you need to sign all the executables. See
|
||||
[windows/src/README.md#Certificates](../../windows/src/README.md#Certificates)
|
||||
for details on how to create test code signing certificates or specify your own
|
||||
certificates for the build.
|
||||
|
||||
## Notes on Environment Variables
|
||||
|
||||
### KEYMAN_ROOT
|
||||
|
||||
If you pull the entire `keyman.git` repo to `c:\keyman`, then the paths by
|
||||
default will work without changes. Otherwise, you will need to set an
|
||||
environment variable `KEYMAN_ROOT` to the root path of the Keyman repo. For
|
||||
example:
|
||||
|
||||
```bat
|
||||
SET KEYMAN_ROOT=c:\projects\keyman\keyman
|
||||
```
|
||||
|
||||
### KEYMAN_CEF4DELPHI_ROOT
|
||||
|
||||
|
|
@ -349,41 +297,85 @@ release build, the common/windows/cef-checkout.sh script will checkout the corre
|
|||
branch of the repository automatically and extract any compressed files found in
|
||||
it.
|
||||
|
||||
### GIT_BASH_FOR_KEYMAN
|
||||
|
||||
This environment variable is optional: the build will run bash in a separate
|
||||
window in order to build KeymanWeb if it isn't present, but you'll lose logging
|
||||
and have the annoyance of a window popping up halfway through the build. To
|
||||
resolve both of those issues, set the environment variable to:
|
||||
The [`KEYMAN_CEF4DELPHI_ROOT`](#keyman_cef4delphi_root) variable is
|
||||
used to specify the path to the CEF4Delphi binaries.
|
||||
|
||||
```bat
|
||||
SET GIT_BASH_FOR_KEYMAN="C:\Program Files\Git\bin\bash.exe" --init-file "c:\Program Files\Git\etc\profile" -l
|
||||
SETX KEYMAN_CEF4DELPHI_ROOT "c:\Projects\keyman\CEF4Delphi_Binary"
|
||||
```
|
||||
|
||||
You should verify the install location of Git on your computer as it may vary.
|
||||
**Additional requirements for release builds**:
|
||||
* [Certificates](#certificates)
|
||||
* [7-Zip](http://www.7-zip.org/), used for archiving build files
|
||||
* [HTML Help Workshop](http://web.archive.org/web/20160201063255/http://download.microsoft.com/download/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe) note: Microsoft no longer offer this download...
|
||||
* [WiX 3.11.1](https://github.com/wixtoolset/wix3/releases/tag/wix3111rtm)
|
||||
* [CEF4Delphi_Binary](https://github.com/keymanapp/CEF4Delphi_Binary) repository
|
||||
|
||||
### USERDEFINES
|
||||
|
||||
You can specify defines that will not be added to the git repository and will be
|
||||
used in the build in the UserDefines.mak file in the root folder. This is used
|
||||
mostly for code signing certificates. If not specified, a test certificate will
|
||||
be used to sign executables when you build a release.
|
||||
|
||||
To include UserDefines.mak in the build, use the command line parameter
|
||||
`-DUSERDEFINES`. You can also set an environment variable `USERDEFINES=1` to get
|
||||
the same result.
|
||||
|
||||
### JAVA_HOME
|
||||
|
||||
This environment variable tells Gradle what version of Java to use for building Keyman for Android.
|
||||
|
||||
**Multiple versions of Java:** If you need to build Keyman for Android 16.0 or older versions, you can set `JAVA_HOME_11` to the OpenJDK 11 path and `JAVA_HOME` to the OpenJDK 8 path. This will build both versions correctly from command line. But note that you do need to update your `JAVA_HOME` env var to the associated version before opening Android Studio and loading any Android projects. `JAVA_HOME_11` is mostly used by CI.
|
||||
|
||||
```bat
|
||||
SET JAVA_HOME="path to OpenJDK 8"
|
||||
SET JAVA_HOME_11="path to OpenJDK 11"
|
||||
```ps1
|
||||
# Elevated PowerShell
|
||||
choco install 7zip html-help-workshop
|
||||
choco install wixtoolset --version=3.11.1
|
||||
git clone https://github.com/keymanapp/CEF4Delphi_Binary C:\Projects\keyman\CEF4Delphi_Binary
|
||||
```
|
||||
|
||||
### Android dependencies
|
||||
|
||||
**Projects**:
|
||||
* Keyman for Android
|
||||
|
||||
**Requirements**:
|
||||
* Android SDK
|
||||
* Android Studio
|
||||
* Ant
|
||||
* Gradle
|
||||
* Maven
|
||||
* JDK 11 (Temurin11)
|
||||
|
||||
#### JDK 11
|
||||
|
||||
Use Powershell + Chocolatey to install JDK 11:
|
||||
|
||||
```ps1
|
||||
# Elevated PowerShell
|
||||
|
||||
# for *much* faster download, hide progress bar (PowerShell/PowerShell#2138)
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
choco install temurin11
|
||||
```
|
||||
|
||||
**Multiple versions of Java:** If you need to build Keyman for Android 16.0 or
|
||||
older versions, you can set `JAVA_HOME_11` to the JDK 11 path and
|
||||
`JAVA_HOME` to the JDK 8 path. This will build both versions correctly
|
||||
from command line. But note that you do need to update your `JAVA_HOME` env
|
||||
var to the associated version before opening Android Studio and loading any
|
||||
Android projects. `JAVA_HOME_11` is mostly used by CI.
|
||||
|
||||
#### Android Studio and friends
|
||||
|
||||
```ps1
|
||||
# Elevated PowerShell
|
||||
choco install androidstudio ant gradle maven android-sdk
|
||||
```
|
||||
|
||||
Start a new shell to get the new paths and then update Android SDKs:
|
||||
|
||||
```ps1
|
||||
# optionally install sdk images
|
||||
sdkmanager --update
|
||||
# sdkmanager "system-images;android-33;google_apis;armeabi-v7a"
|
||||
sdkmanager --licenses
|
||||
```
|
||||
|
||||
* Run Android Studio once after installation to install additional components
|
||||
such as emulator images and SDK updates.
|
||||
|
||||
## Certificates
|
||||
|
||||
In order to make a release build, you need to sign all the executables. See
|
||||
[windows/src/README.md#Certificates](../../windows/src/README.md#Certificates)
|
||||
for details on how to create test code signing certificates or specify your own
|
||||
certificates for the build.
|
||||
|
||||
## Optional Tools
|
||||
|
||||
* sentry-cli (optional)
|
||||
|
|
|
|||
|
|
@ -456,7 +456,7 @@ For each key:
|
|||
|---|------|---------|------------------------------------------|
|
||||
|16+| 32 | vkey | int: vkey ID |
|
||||
|20+| 32 | mod | int: modifier key flags |
|
||||
|24+| 32 | key | int: index into `key` sibling subtable |
|
||||
|24+| 32 | key | int: index into `keys` sibling subtable |
|
||||
|
||||
- `vkey`: If this is 0-255, it is the resolved standard/predefined vkey (K_A,
|
||||
etc.). It is resolved because the `vkeyMap` from LDML has already been
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ https://help.keyman.com/developer/engine/android/latest-version/
|
|||
| KEYMAN Variable | Value |
|
||||
|-----------------------------------|--------------|
|
||||
| KEYMAN_DEFAULT_VERSION_UBUNTU_CONTAINER | noble |
|
||||
| KEYMAN_MAX_VERSION_EMSCRIPTEN | 3.1.58 |
|
||||
| KEYMAN_MIN_TARGET_VERSION_ANDROID | 5 |
|
||||
| KEYMAN_MIN_TARGET_VERSION_CHROME | 95.0 |
|
||||
| KEYMAN_MIN_TARGET_VERSION_IOS | 12.2 |
|
||||
|
|
@ -58,7 +57,7 @@ https://help.keyman.com/developer/engine/android/latest-version/
|
|||
| KEYMAN_MIN_TARGET_VERSION_WINDOWS | 10 |
|
||||
| KEYMAN_MIN_VERSION_ANDROID_SDK | 21 |
|
||||
| KEYMAN_MIN_VERSION_CPP | 17 |
|
||||
| KEYMAN_MIN_VERSION_EMSCRIPTEN | 3.1.44 |
|
||||
| KEYMAN_MIN_VERSION_EMSCRIPTEN | 3.1.58 |
|
||||
| KEYMAN_MIN_VERSION_MESON | 1.0.0 |
|
||||
| KEYMAN_MIN_VERSION_NODE_MAJOR | 20 |
|
||||
| KEYMAN_MIN_VERSION_NPM | 10.5.1 |
|
||||
|
|
|
|||
|
|
@ -831,12 +831,22 @@ public class Manager: NSObject, UIGestureRecognizerDelegate {
|
|||
shared.copyUserDefaults(to: nonShared, withKeys: keysToCopy, shouldOverwrite: true)
|
||||
do {
|
||||
try shared.copyFiles(to: nonShared)
|
||||
FontManager.shared.registerCustomFonts()
|
||||
} catch {
|
||||
let message = ("Failed to copy from shared container: \(error)")
|
||||
os_log("%{public}s", log:KeymanEngineLogger.settings, type: .error, message)
|
||||
SentryManager.capture(error, message:message)
|
||||
}
|
||||
|
||||
// This operation has a surprisingly high cost and isn't critical
|
||||
// for getting the keyboard loaded and available to the OS.
|
||||
//
|
||||
// We certainly want it done _soon_... but we don't want it to cause
|
||||
// the primary, synchronous initialization call from the OS to run so
|
||||
// long that the keyboard fails to start due to its enforced time
|
||||
// constraints.
|
||||
DispatchQueue.main.async {
|
||||
FontManager.shared.registerCustomFonts()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,17 @@ public class FontManager {
|
|||
fonts[url] = RegisteredFont(name: name, isRegistered: false)
|
||||
return name
|
||||
}
|
||||
|
||||
private func cachedFont(at url: URL) -> RegisteredFont? {
|
||||
if let font = fonts[url] {
|
||||
return font
|
||||
}
|
||||
guard let name = readFontName(at: url) else {
|
||||
return nil
|
||||
}
|
||||
fonts[url] = RegisteredFont(name: name, isRegistered: false)
|
||||
return fonts[url]
|
||||
}
|
||||
|
||||
/// Registers all new fonts found in the font path. Call this after you have preloaded all your font files
|
||||
/// with `preloadFontFile(atPath:shouldOverwrite:)`
|
||||
|
|
@ -33,8 +44,50 @@ public class FontManager {
|
|||
guard let keyboardDirs = Storage.active.keyboardDirs else {
|
||||
return
|
||||
}
|
||||
|
||||
var fontSet: Set<URL> = []
|
||||
for dir in keyboardDirs {
|
||||
registerFonts(in: dir)
|
||||
fontSet = fontSet.union(listFonts(in: dir))
|
||||
}
|
||||
|
||||
registerListedFonts(fontSet)
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates across all listed fonts, registering those not yet registered.
|
||||
* Checks for, and filters out, any fonts already registered on the system.
|
||||
* Also initializes the registration cache per URL if needed.
|
||||
*/
|
||||
private func registerListedFonts(_ initialFontSet: Set<URL>) {
|
||||
// If we are unable to read the font file's properties sufficiently,
|
||||
// skip it. We also don't need to register anything already registered or
|
||||
// that cannot be registered due to loading/parsing errors.
|
||||
//
|
||||
// Calls to `cachedFont` after the `.filter` below may be assumed to have
|
||||
// non-nil return values.
|
||||
var fontSet = initialFontSet.filter { !(cachedFont(at: $0)?.isRegistered ?? true) }
|
||||
|
||||
// The prior line filters out any entries where cachedFont(at: $0) would be nil.
|
||||
// Batch-lookups all fonts lacking cache-confirmation of prior registration.
|
||||
var fontNamesToRegister = missingFonts(from: Set(fontSet.map { cachedFont(at: $0)!.name }))
|
||||
|
||||
for fontUrl in fontSet {
|
||||
let fontName = cachedFont(at: fontUrl)!.name
|
||||
|
||||
guard fontNamesToRegister.contains(fontName) else {
|
||||
let message = "Did not register font at \(fontUrl) because font name \(fontName) is already registered"
|
||||
os_log("%{public}s", log:KeymanEngineLogger.resources, type: .info, message)
|
||||
continue
|
||||
}
|
||||
|
||||
let didRegister = _registerFont(at: fontUrl)
|
||||
fonts[fontUrl] = RegisteredFont(name: fontName, isRegistered: didRegister)
|
||||
|
||||
// We no longer need to register a font with this name, so drop it from
|
||||
// the set to register.
|
||||
if didRegister {
|
||||
fontNamesToRegister.remove(fontName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -43,6 +96,8 @@ public class FontManager {
|
|||
guard let keyboardDirs = Storage.active.keyboardDirs else {
|
||||
return
|
||||
}
|
||||
// This doesn't use the expensive looped lookup operation seen in missingFonts,
|
||||
// so there's no need to batch similar operations here.
|
||||
for dir in keyboardDirs {
|
||||
unregisterFonts(in: dir)
|
||||
}
|
||||
|
|
@ -63,44 +118,29 @@ public class FontManager {
|
|||
}
|
||||
return name as String
|
||||
}
|
||||
|
||||
private func _registerFont(at url: URL) -> Bool {
|
||||
var errorRef: Unmanaged<CFError>?
|
||||
let fontName = fontName(at: url)!
|
||||
let didRegister = CTFontManagerRegisterFontsForURL(url as CFURL, .none, &errorRef)
|
||||
let error = errorRef?.takeRetainedValue() // Releases errorRef
|
||||
if !didRegister {
|
||||
let message = "Failed to register font \(fontName) at \(url) reason: \(String(describing: error))"
|
||||
os_log("%{public}s", log:KeymanEngineLogger.resources, type: .error, message)
|
||||
} else {
|
||||
let message = "Registered font \(fontName) at \(url)"
|
||||
os_log("%{public}s", log:KeymanEngineLogger.resources, type: .info, message)
|
||||
}
|
||||
|
||||
return didRegister
|
||||
}
|
||||
|
||||
/// - Parameters:
|
||||
/// - url: URL of the font to register
|
||||
/// - Returns: Font is registered.
|
||||
public func registerFont(at url: URL) -> Bool {
|
||||
let fontName: String
|
||||
if let font = fonts[url] {
|
||||
if font.isRegistered {
|
||||
return true
|
||||
}
|
||||
fontName = font.name
|
||||
} else {
|
||||
guard let name = readFontName(at: url) else {
|
||||
return false
|
||||
}
|
||||
fontName = name
|
||||
}
|
||||
|
||||
let didRegister: Bool
|
||||
if !fontExists(fontName) {
|
||||
var errorRef: Unmanaged<CFError>?
|
||||
didRegister = CTFontManagerRegisterFontsForURL(url as CFURL, .none, &errorRef)
|
||||
let error = errorRef?.takeRetainedValue() // Releases errorRef
|
||||
if !didRegister {
|
||||
let message = "Failed to register font \(fontName) at \(url) reason: \(String(describing: error))"
|
||||
os_log("%{public}s", log:KeymanEngineLogger.resources, type: .error, message)
|
||||
} else {
|
||||
let message = "Registered font \(fontName) at \(url)"
|
||||
os_log("%{public}s", log:KeymanEngineLogger.resources, type: .info, message)
|
||||
}
|
||||
} else {
|
||||
didRegister = false
|
||||
let message = "Did not register font at \(url) because font name \(fontName) is already registered"
|
||||
os_log("%{public}s", log:KeymanEngineLogger.resources, type: .info, message)
|
||||
}
|
||||
let font = RegisteredFont(name: fontName, isRegistered: didRegister)
|
||||
fonts[url] = font
|
||||
return didRegister
|
||||
registerListedFonts([url])
|
||||
return fonts[url]?.isRegistered ?? false
|
||||
}
|
||||
|
||||
/// - Parameters:
|
||||
|
|
@ -133,32 +173,53 @@ public class FontManager {
|
|||
|
||||
return font.isRegistered
|
||||
}
|
||||
|
||||
public func registerFonts(in directory: URL) {
|
||||
|
||||
private func listFonts(in directory: URL) -> [URL] {
|
||||
guard let urls = try? FileManager.default.contentsOfDirectory(at: directory, includingPropertiesForKeys: nil) else {
|
||||
let message = "Could not list contents of directory \(directory)"
|
||||
os_log("%{public}s", log:KeymanEngineLogger.resources, type: .error, message)
|
||||
return
|
||||
}
|
||||
for url in urls where url.lastPathComponent.hasFontExtension {
|
||||
_ = registerFont(at: url)
|
||||
return []
|
||||
}
|
||||
return urls.filter { $0.lastPathComponent.hasFontExtension }
|
||||
}
|
||||
|
||||
public func registerFonts(in directory: URL) {
|
||||
let fontsToRegister = listFonts(in: directory)
|
||||
registerListedFonts(Set(fontsToRegister))
|
||||
}
|
||||
|
||||
public func unregisterFonts(in directory: URL, fromSystemOnly: Bool = true) {
|
||||
guard let urls = try? FileManager.default.contentsOfDirectory(at: directory, includingPropertiesForKeys: nil) else {
|
||||
let message = "Could not list contents of directory \(directory)"
|
||||
os_log("%{public}s", log:KeymanEngineLogger.resources, type: .error, message)
|
||||
return
|
||||
}
|
||||
for url in urls where url.lastPathComponent.hasFontExtension {
|
||||
let fontsToUnregister = listFonts(in: directory)
|
||||
for url in fontsToUnregister {
|
||||
_ = unregisterFont(at: url, fromSystemOnly: fromSystemOnly)
|
||||
}
|
||||
}
|
||||
|
||||
private func fontExists(_ fontName: String) -> Bool {
|
||||
return UIFont.familyNames.contains { familyName in
|
||||
UIFont.fontNames(forFamilyName: familyName).contains(fontName)
|
||||
/**
|
||||
* Queries the system for existing registrations for the specified fonts with a single batch run.
|
||||
* Only fonts that could not be found will be returned within the result set.
|
||||
*/
|
||||
private func missingFonts(from fontNames: Set<String>) -> Set<String> {
|
||||
var fontsToFind = fontNames
|
||||
|
||||
UIFont.familyNames.forEach { familyName in
|
||||
if fontsToFind.count == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
let familyFonts = UIFont.fontNames(forFamilyName: familyName)
|
||||
|
||||
for font in familyFonts {
|
||||
if fontsToFind.contains(font) {
|
||||
fontsToFind.remove(font)
|
||||
}
|
||||
|
||||
if fontsToFind.count == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fontsToFind
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -164,43 +164,43 @@ VKey_to_Iso = {
|
|||
}
|
||||
|
||||
|
||||
def bytecheck(value, check):
|
||||
def _bytecheck(value, check):
|
||||
if bytes([value & check[0]]) == check:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def get_nkey(file, fileContent, offset):
|
||||
def _get_nkey(file, fileContent, offset):
|
||||
nkey = NKey()
|
||||
data = struct.unpack_from("<B2H", fileContent, offset)
|
||||
|
||||
nkey.flags = data[0]
|
||||
nkey.hasBitmap = bytecheck(data[0], kvkkBitmap)
|
||||
nkey.hasUnicode = bytecheck(data[0], kvkkUnicode)
|
||||
nkey.hasBitmap = _bytecheck(data[0], kvkkBitmap)
|
||||
nkey.hasUnicode = _bytecheck(data[0], kvkkUnicode)
|
||||
|
||||
nkey.shiftflags = data[1]
|
||||
if data[1] == 0:
|
||||
nkey.Normal = True
|
||||
nkey.Shift = bytecheck(data[1], KVKS_SHIFT)
|
||||
nkey.Ctrl = bytecheck(data[1], KVKS_CTRL)
|
||||
nkey.Alt = bytecheck(data[1], KVKS_ALT)
|
||||
nkey.LCtrl = bytecheck(data[1], KVKS_LCTRL)
|
||||
nkey.RCtrl = bytecheck(data[1], KVKS_RCTRL)
|
||||
nkey.LAlt = bytecheck(data[1], KVKS_LALT)
|
||||
nkey.RAlt = bytecheck(data[1], KVKS_RALT)
|
||||
nkey.Shift = _bytecheck(data[1], KVKS_SHIFT)
|
||||
nkey.Ctrl = _bytecheck(data[1], KVKS_CTRL)
|
||||
nkey.Alt = _bytecheck(data[1], KVKS_ALT)
|
||||
nkey.LCtrl = _bytecheck(data[1], KVKS_LCTRL)
|
||||
nkey.RCtrl = _bytecheck(data[1], KVKS_RCTRL)
|
||||
nkey.LAlt = _bytecheck(data[1], KVKS_LALT)
|
||||
nkey.RAlt = _bytecheck(data[1], KVKS_RALT)
|
||||
|
||||
nkey.VKey = data[2]
|
||||
|
||||
nkey.text, newoffset = get_nstring(file, fileContent, offset + struct.calcsize("<B2H"))
|
||||
nkey.bitmap, newoffset = get_nbitmap(file, fileContent, newoffset)
|
||||
nkey.text, newoffset = _get_nstring(file, fileContent, offset + struct.calcsize("<B2H"))
|
||||
nkey.bitmap, newoffset = _get_nbitmap(file, fileContent, newoffset)
|
||||
|
||||
return nkey, newoffset
|
||||
|
||||
|
||||
def get_nfont(file, fileContent, offset):
|
||||
def _get_nfont(file, fileContent, offset):
|
||||
nfont = NFont()
|
||||
nfont.name, curoffset = get_nstring(file, fileContent, offset)
|
||||
nfont.name, curoffset = _get_nstring(file, fileContent, offset)
|
||||
data = struct.unpack_from("<L4B", fileContent, curoffset)
|
||||
nfont.resv = data[4]
|
||||
nfont.blue = data[1]
|
||||
|
|
@ -210,7 +210,7 @@ def get_nfont(file, fileContent, offset):
|
|||
return nfont, curoffset + struct.calcsize("<L4B")
|
||||
|
||||
|
||||
def get_nstring(file, fileContent, offset):
|
||||
def _get_nstring(file, fileContent, offset):
|
||||
stringlength = struct.unpack_from("<H", fileContent, offset)
|
||||
file.seek(offset + 2)
|
||||
if stringlength[0] > 256:
|
||||
|
|
@ -224,7 +224,7 @@ def get_nstring(file, fileContent, offset):
|
|||
return stringdata.decode('utf-16'), offset + 2 + (2 * stringlength[0])
|
||||
|
||||
|
||||
def get_nbitmap(file, fileContent, offset):
|
||||
def _get_nbitmap(file, fileContent, offset):
|
||||
bitmap = None
|
||||
bitmaplength = struct.unpack_from("<I", fileContent, offset)
|
||||
file.seek(offset + struct.calcsize("<I"))
|
||||
|
|
@ -283,31 +283,31 @@ def print_kvk(kvkData, allkeys=False):
|
|||
print(" text:", key.text)
|
||||
|
||||
|
||||
def plus_join(modifier, name):
|
||||
def _plus_join(modifier, name):
|
||||
if modifier:
|
||||
modifier = modifier + "+"
|
||||
modifier = modifier + name
|
||||
return modifier
|
||||
|
||||
|
||||
def get_modifer(key):
|
||||
def _get_modifer(key):
|
||||
modifier = ""
|
||||
if key.Normal:
|
||||
return "None"
|
||||
if key.Shift:
|
||||
modifier = plus_join(modifier, "shift")
|
||||
modifier = _plus_join(modifier, "shift")
|
||||
if key.Ctrl:
|
||||
modifier = plus_join(modifier, "ctrl")
|
||||
modifier = _plus_join(modifier, "ctrl")
|
||||
if key.Alt:
|
||||
modifier = plus_join(modifier, "alt")
|
||||
modifier = _plus_join(modifier, "alt")
|
||||
if key.LCtrl:
|
||||
modifier = plus_join(modifier, "ctrlL")
|
||||
modifier = _plus_join(modifier, "ctrlL")
|
||||
if key.RCtrl:
|
||||
modifier = plus_join(modifier, "ctrlR")
|
||||
modifier = _plus_join(modifier, "ctrlR")
|
||||
if key.LAlt:
|
||||
modifier = plus_join(modifier, "altL")
|
||||
modifier = _plus_join(modifier, "altL")
|
||||
if key.RAlt:
|
||||
modifier = plus_join(modifier, "altR")
|
||||
modifier = _plus_join(modifier, "altR")
|
||||
return modifier
|
||||
|
||||
|
||||
|
|
@ -315,7 +315,7 @@ def convert_ldml(kvkData):
|
|||
keymaps = {}
|
||||
|
||||
for key in kvkData.Keys:
|
||||
modifier = get_modifer(key)
|
||||
modifier = _get_modifer(key)
|
||||
if modifier in keymaps:
|
||||
keymaps[modifier] = keymaps[modifier] + (key,)
|
||||
else:
|
||||
|
|
@ -381,20 +381,20 @@ def parse_kvk_file(kvkfile):
|
|||
kvkstart = struct.unpack_from("<4s4cc", fileContent, 0)
|
||||
kvkData.version = (kvkstart[1], kvkstart[2], kvkstart[3], kvkstart[4])
|
||||
kvkData.flags = kvkstart[5]
|
||||
kvkData.key102 = bytecheck(kvkData.flags[0], kvkk102key)
|
||||
kvkData.DisplayUnderlying = bytecheck(kvkData.flags[0], kvkkDisplayUnderlying)
|
||||
kvkData.UseUnderlying = bytecheck(kvkData.flags[0], kvkkUseUnderlying)
|
||||
kvkData.AltGr = bytecheck(kvkData.flags[0], kvkkAltGr)
|
||||
kvkData.key102 = _bytecheck(kvkData.flags[0], kvkk102key)
|
||||
kvkData.DisplayUnderlying = _bytecheck(kvkData.flags[0], kvkkDisplayUnderlying)
|
||||
kvkData.UseUnderlying = _bytecheck(kvkData.flags[0], kvkkUseUnderlying)
|
||||
kvkData.AltGr = _bytecheck(kvkData.flags[0], kvkkAltGr)
|
||||
|
||||
kvkData.AssociatedKeyboard, newoffset = get_nstring(file, fileContent, struct.calcsize("<4s4cc"))
|
||||
kvkData.AnsiFont, newoffset = get_nfont(file, fileContent, newoffset)
|
||||
kvkData.UnicodeFont, newoffset = get_nfont(file, fileContent, newoffset)
|
||||
kvkData.AssociatedKeyboard, newoffset = _get_nstring(file, fileContent, struct.calcsize("<4s4cc"))
|
||||
kvkData.AnsiFont, newoffset = _get_nfont(file, fileContent, newoffset)
|
||||
kvkData.UnicodeFont, newoffset = _get_nfont(file, fileContent, newoffset)
|
||||
numkeys = struct.unpack_from("I", fileContent, newoffset)
|
||||
kvkData.KeyCount = numkeys[0]
|
||||
newoffset = newoffset + struct.calcsize("I")
|
||||
|
||||
for num in range(numkeys[0]):
|
||||
nkey, newoffset = get_nkey(file, fileContent, newoffset)
|
||||
nkey, newoffset = _get_nkey(file, fileContent, newoffset)
|
||||
nkey.number = num
|
||||
kvkData.Keys.append(nkey)
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>Keyman $(PRODUCT_VERSION) for macOS</string>
|
||||
<string>$(PRODUCT_VERSION)</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@property (readonly) NSString *clientApplicationId;
|
||||
|
||||
-(instancetype)initWithClient:(id) client applicationId:(NSString *)appId;
|
||||
-(NSString *)description;
|
||||
-(void)checkCompliance:(id) client;
|
||||
-(void) checkComplianceAfterInsert:(id) client delete:(NSString *)textToDelete insert:(NSString *)textToInsert;
|
||||
-(BOOL)isComplianceUncertain;
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ NSString *const kKMLegacyApps = @"KMLegacyApps";
|
|||
|
||||
-(NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"complianceUncertain: %d, hasCompliantSelectionApi: %d, canReadText: %d, canReplaceText: %d, mustBackspaceUsingEvents: %d, clientAppId: %@, client: %@", self.complianceUncertain, self.hasCompliantSelectionApi, [self canReadText], [self canReplaceText], [self mustBackspaceUsingEvents], _clientApplicationId, _client];
|
||||
return [NSString stringWithFormat:@"complianceUncertain: %d, hasCompliantSelectionApi: %d, canReadText: %d, canReplaceText: %d, mustBackspaceUsingEvents: %d, clientApplicationId: %@, client: %@", self.complianceUncertain, self.hasCompliantSelectionApi, [self canReadText], [self canReplaceText], [self mustBackspaceUsingEvents], _clientApplicationId, _client];
|
||||
}
|
||||
|
||||
/** test to see if the API selectedRange functions properly for the text input client */
|
||||
|
|
|
|||
|
|
@ -15,23 +15,27 @@
|
|||
#import "TextApiCompliance.h"
|
||||
|
||||
KMInputMethodEventHandler *testEventHandler = nil;
|
||||
id testClient = nil;
|
||||
|
||||
@interface InputMethodTests : XCTestCase
|
||||
@end
|
||||
|
||||
@interface KMInputMethodEventHandler (Testing)
|
||||
|
||||
@property (nonatomic, retain) TextApiCompliance* apiCompliance;
|
||||
@property (nonatomic, retain) NSString* clientApplicationId;
|
||||
@property BOOL contextChanged;
|
||||
- (instancetype)initWithClient:(NSString *)clientAppId client:(id) sender;
|
||||
- (NSRange) calculateInsertRangeForDeletedText:(NSString*)textToDelete selectionRange:(NSRange) selection;
|
||||
- (void)checkTextApiCompliance:(id)client;
|
||||
|
||||
@end
|
||||
|
||||
@implementation InputMethodTests
|
||||
|
||||
- (void)setUp {
|
||||
id client = [[AppleCompliantTestClient alloc] init];
|
||||
testClient = [[AppleCompliantTestClient alloc] init];
|
||||
NSString *clientAppId = @"com.compliant.app";
|
||||
testEventHandler = [[KMInputMethodEventHandler alloc]initWithClient:clientAppId client:client];
|
||||
testEventHandler = [[KMInputMethodEventHandler alloc]initWithClient:clientAppId client:testClient];
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
|
|
@ -85,4 +89,43 @@ KMInputMethodEventHandler *testEventHandler = nil;
|
|||
XCTAssertTrue(correctResult, @"insert or replacement range expected to be {1,2}");
|
||||
}
|
||||
|
||||
/**
|
||||
* test compliance check of a KMInputMethodEventHandler with a nil client application ID
|
||||
* not sure if this can ever happen, but the lifecycle of the input method is not 100% clear,
|
||||
* and we would like this scenario, if it can occur, to not result in a crash
|
||||
*/
|
||||
- (void)testCheckCompliance_withUnknownApplicationId_createsComplianceObject {
|
||||
id client = [[AppleCompliantTestClient alloc] init];
|
||||
KMInputMethodEventHandler *eventHandler = [[KMInputMethodEventHandler alloc]initWithClient:nil client:client];
|
||||
[eventHandler checkTextApiCompliance:client];
|
||||
XCTAssertNotNil(eventHandler.apiCompliance, @"apiCompliance object was not created");
|
||||
}
|
||||
|
||||
- (void)testCheckCompliance_withNilComplianceObject_createsComplianceObject {
|
||||
[testEventHandler checkTextApiCompliance:testClient];
|
||||
XCTAssertNotNil(testEventHandler.apiCompliance, @"apiCompliance object was not created");
|
||||
}
|
||||
|
||||
- (void)testCheckCompliance_withChangedClientApplicationId_createsNewComplianceObject {
|
||||
// first call causes textApiCompliance object to be created
|
||||
[testEventHandler checkTextApiCompliance:testClient];
|
||||
TextApiCompliance *originalComplianceObject = testEventHandler.apiCompliance;
|
||||
|
||||
testEventHandler.clientApplicationId = @"com.different.app";
|
||||
// second call causes new textApiCompliance object to be created due to stale application ID
|
||||
[testEventHandler checkTextApiCompliance:testClient];
|
||||
XCTAssertNotEqualObjects(originalComplianceObject, testEventHandler.apiCompliance, @"New TextApiCompliance object not created for new client application ID");
|
||||
}
|
||||
|
||||
- (void)testCheckCompliance_withContextChanged_createsNewComplianceObject {
|
||||
// first call causes textApiCompliance object to be created
|
||||
[testEventHandler checkTextApiCompliance:testClient];
|
||||
TextApiCompliance *originalComplianceObject = testEventHandler.apiCompliance;
|
||||
|
||||
testEventHandler.contextChanged = YES;
|
||||
// second call causes new textApiCompliance object to be created due to setting contextChanged flag
|
||||
[testEventHandler checkTextApiCompliance:testClient];
|
||||
XCTAssertNotEqualObjects(originalComplianceObject, testEventHandler.apiCompliance, @"New TextApiCompliance object not created after contextChanged flag set");
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>Keyman Engine $(PRODUCT_VERSION) for macOS</string>
|
||||
<string>$(PRODUCT_VERSION)</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
|
|
|||
|
|
@ -7,57 +7,58 @@ fv,fv_uummarmiutun,Uummarmiutun,Arctic,fv_uummarmiutun_kmw-9.0.js,9.1.1,ikt-Latn
|
|||
fv,fv_eastern_canadian_inuktitut,ᐃᓄᒃᑎᑐᑦ (Eastern Canadian Inuktitut),Arctic,fv_eastern_canadian_inuktitut_kmw-9.0.js,9.2.1,ike-Cans,Eastern Canadian Inuktitut (Unified Canadian Aboriginal Syllabics)
|
||||
fv,fv_migmaq,Mi'gmawi'simg / Mi'kmawi'simk,Atlantic,fv_migmaq_kmw-9.0.js,9.1.2,mic-Latn,Mi'kmaq (Latin)
|
||||
fv,fv_skicinuwatuwewakon,Skicinuwatuwewakon,Atlantic,fv_skicinuwatuwewakon_kmw-9.0.js,9.1.1,pqm-Latn,Malecite-Passamaquoddy (Latin)
|
||||
fv,fv_uwikala,'Uwik̓ala,BC Coast,fv_uwikala_kmw-9.0.js,9.3,hei,Heiltsuk
|
||||
fv,fv_uwikala,'Uwik̓ala,BC Coast,fv_uwikala_kmw-9.0.js,9.4,hei,Heiltsuk
|
||||
fv,fv_dexwlesucid,Dəxʷləšucid,BC Coast,fv_dexwlesucid_kmw-9.0.js,9.2.1,lut-Latn,Lushootseed (Latin)
|
||||
fv,fv_diitiidatx,Diidiitidq,BC Coast,fv_diitiidatx_kmw-9.0.js,9.2.1,nuk-Latn,Nuu-chah-nulth (Latin)
|
||||
fv,fv_gitsenimx,Gitsenimx̱,BC Coast,fv_gitsenimx_kmw-9.0.js,10.1.1,git,Gitxsan (Latin)
|
||||
fv,fv_gitsenimx,Gitsenimx̱,BC Coast,fv_gitsenimx_kmw-9.0.js,10.1.2,git,Gitxsan (Latin)
|
||||
fv,fv_hailzaqvla,Haiɫzaqvla,BC Coast,fv_hailzaqvla_kmw-9.0.js,9.5.2,hei,Heiltsuk (Latin)
|
||||
fv,fv_haisla,Haisla,BC Coast,fv_haisla.js,2.1,has-Latn,Haisla (Latin)
|
||||
fv,fv_haisla,Haisla,BC Coast,fv_haisla.js,2.1.2,has-Latn,Haisla (Latin)
|
||||
fv,fv_halqemeylem,Halq'eméylem,BC Coast,fv_halqemeylem_kmw-9.0.js,9.2,hur-Latn,Halkomelem (Latin)
|
||||
fv,fv_henqeminem,Hǝn̓q̓ǝmin̓ǝm,BC Coast,fv_henqeminem_kmw-9.0.js,10.1,hur-Latn,Halkomelem (Latin)
|
||||
fv,fv_klahoose,Homalco-Klahoose-Sliammon,BC Coast,fv_klahoose_kmw-9.0.js,10.1,coo,Comox
|
||||
fv,fv_hulquminum,Hul’q’umi’num’,BC Coast,fv_hulquminum_kmw-9.0.js,9.1,hur-Latn,Halkomelem (Latin)
|
||||
fv,fv_hulquminum_combine,Hul̓q̓umin̓um̓,BC Coast,fv_hulquminum_combine_kmw-9.0.js,2.0.1,hur-Latn,Halkomelem (Latin)
|
||||
fv,fv_kwakwala_liqwala,Kʷak̓ʷala,BC Coast,fv_kwakwala_liqwala_kmw-9.0.js,9.2.5,kwk-Latn,Kwakiutl (Latin)
|
||||
fv,fv_kwakwala,Kwak̕wala,BC Coast,fv_kwakwala_kmw-9.0.js,9.1.2,kwk-Latn,Kwakiutl (Latin)
|
||||
fv,fv_nexwslayemucen,Nəxʷsƛ̓ay̓əmúcən,BC Coast,fv_nexwslayemucen_kmw-9.0.js,9.2.1,clm-Latn,Clallam (Latin)
|
||||
fv,fv_nisgaa,Nisg̱a'a,BC Coast,fv_nisgaa_kmw-9.0.js,9.1.2,ncg-Latn,Nisga'a (Latin)
|
||||
fv,fv_nuucaanul,Nuučaan̓uł,BC Coast,fv_nuucaanul_kmw-9.0.js,9.1.4,nuk-Latn,Nuu-chah-nulth (Latin)
|
||||
fv,fv_nuxalk,Nuxalk,BC Coast,fv_nuxalk_kmw-9.0.js,10.0,blc-Latn,Bella Coola (Latin)
|
||||
fv,fv_kwakwala_liqwala,Kʷak̓ʷala,BC Coast,fv_kwakwala_liqwala_kmw-9.0.js,9.3,kwk-Latn,Kwakiutl (Latin)
|
||||
fv,fv_kwakwala,Kwak̕wala,BC Coast,fv_kwakwala_kmw-9.0.js,9.2,kwk-Latn,Kwakiutl (Latin)
|
||||
fv,fv_lekwungen,Lək̓ʷəŋən,BC Coast,fv_lekwungen-9.0.js,1.0,str,Lekwungen
|
||||
fv,fv_nexwslayemucen,Nəxʷsƛ̓ay̓əmúcən,BC Coast,fv_nexwslayemucen_kmw-9.0.js,10.0,clm-Latn,Clallam (Latin)
|
||||
fv,fv_nisgaa,Nisg̱a'a,BC Coast,fv_nisgaa_kmw-9.0.js,9.2,ncg-Latn,Nisga'a (Latin)
|
||||
fv,fv_nuucaanul,Nuučaan̓uł,BC Coast,fv_nuucaanul_kmw-9.0.js,9.2,nuk-Latn,Nuu-chah-nulth (Latin)
|
||||
fv,fv_nuxalk,Nuxalk,BC Coast,fv_nuxalk_kmw-9.0.js,10.0.1,blc-Latn,Bella Coola (Latin)
|
||||
fv,fv_sencoten,SENĆOŦEN,BC Coast,fv_sencoten_kmw-9.0.js,9.2.2,str,Straits Salish
|
||||
fv,fv_sguuxs,Sgüüx̱s,BC Coast,fv_sguuxs.js,1.0.1,tsi,Tsimshian
|
||||
fv,fv_sguuxs,Sgüüx̱s,BC Coast,fv_sguuxs.js,1.1,tsi,Tsimshian
|
||||
fv,fv_shashishalhem,Shashishalhem,BC Coast,fv_shashishalhem_kmw-9.0.js,9.2,sec-Latn,Sechelt (Latin)
|
||||
fv,fv_skwxwumesh_snichim,Sḵwx̱wúmesh sníchim,BC Coast,fv_skwxwumesh_snichim_kmw-9.0.js,9.3,squ-Latn,Squamish (Latin)
|
||||
fv,fv_skwxwumesh_snichim,Sḵwx̱wúmesh sníchim,BC Coast,fv_skwxwumesh_snichim_kmw-9.0.js,10.0,squ-Latn,Squamish (Latin)
|
||||
fv,fv_smalgyax,Sm'algya̱x,BC Coast,fv_smalgyax_kmw-9.0.js,9.2,tsi-Latn,Tsimshian (Latin)
|
||||
fv,fv_xaislakala,X̄a'ʼislak̓ala,BC Coast,fv_xaislakala_kmw-9.0.js,9.1.1,has-Latn,Haisla (Latin)
|
||||
fv,fv_hlgaagilda_xaayda_kil,X̱aayda-X̱aad Kil,BC Coast,fv_hlgaagilda_xaayda_kil_kmw-9.0.js,9.3,hax,Southern Haida
|
||||
fv,fv_dakelh,Dakelh,BC Interior,fv_dakelh_kmw-9.0.js,9.2,caf-Latn,Southern Carrier (Latin)
|
||||
fv,fv_xaislakala,X̄a'ʼislak̓ala,BC Coast,fv_xaislakala_kmw-9.0.js,10.0,has-Latn,Haisla (Latin)
|
||||
fv,fv_hlgaagilda_xaayda_kil,X̱aayda-X̱aad Kil,BC Coast,fv_hlgaagilda_xaayda_kil_kmw-9.0.js,9.4,hax,Southern Haida
|
||||
fv,fv_dakelh,Dakelh,BC Interior,fv_dakelh_kmw-9.0.js,9.2.1,caf-Latn,Southern Carrier (Latin)
|
||||
fv,fv_ktunaxa,Ktunaxa,BC Interior,fv_ktunaxa_kmw-9.0.js,10.0,kut-Latn,Kutenai (Latin)
|
||||
fv,fv_kwadacha_tsekene,Kwadacha Tsek’ene,BC Interior,fv_kwadacha_tsekene_kmw-9.0.js,1.0,sek-Latn,Sekani
|
||||
fv,fv_kwadacha_tsekene,Kwadacha Tsek’ene,BC Interior,fv_kwadacha_tsekene_kmw-9.0.js,1.1,sek-Latn,Sekani
|
||||
fv,fv_natwits,Nedut’en-Witsuwit'en,BC Interior,fv_natwits_kmw-9.0.js,9.1.3,caf-Latn,Southern Carrier (Latin)
|
||||
fv,fv_nlekepmxcin,Nłeʔkepmxcin,BC Interior,fv_nlekepmxcin_kmw-9.0.js,9.4,thp-Latn,Thompson (Latin)
|
||||
fv,fv_nlha7kapmxtsin,Nlha7kapmxtsin,BC Interior,fv_nlha7kapmxtsin_kmw-9.0.js,10.0,thp-Latn,Thompson (Latin)
|
||||
fv,fv_nlakapamuxcheen,Nlakapamuxcheen,BC Interior,fv_nlakapamuxcheen_kmw-9.0.js,1.0.2,thp,Thompson
|
||||
fv,fv_nsilxcen,Nsilxcən,BC Interior,fv_nsilxcen_kmw-9.0.js,9.3,oka,Okanagan
|
||||
fv,fv_nlekepmxcin,Nłeʔkepmxcin,BC Interior,fv_nlekepmxcin_kmw-9.0.js,9.5.1,thp-Latn,Thompson (Latin)
|
||||
fv,fv_nlha7kapmxtsin,Nlha7kapmxtsin,BC Interior,fv_nlha7kapmxtsin_kmw-9.0.js,10.1.1,thp-Latn,Thompson (Latin)
|
||||
fv,fv_nlakapamuxcheen,Nlakapamuxcheen,BC Interior,fv_nlakapamuxcheen_kmw-9.0.js,1.1,thp,Thompson
|
||||
fv,fv_nsilxcen,Nsilxcən,BC Interior,fv_nsilxcen_kmw-9.0.js,10.0,oka,Okanagan
|
||||
fv,fv_secwepemctsin,Secwepemctsín,BC Interior,fv_secwepemctsin_kmw-9.0.js,9.2,shs-Latn,Shuswap (Latin)
|
||||
fv,fv_stlatlimxec,Sƛ̓aƛ̓imxəc,BC Interior,fv_stlatlimxec_kmw-9.0.js,9.3,lil-Latn,Lillooet (Latin)
|
||||
fv,fv_statimcets,St̓át̓imcets,BC Interior,fv_statimcets_kmw-9.0.js,9.1.4,lil-Latn,Lillooet (Latin)
|
||||
fv,fv_taltan,Tāłtān,BC Interior,fv_taltan_kmw-9.0.js,9.1.5,tht-Latn,Tahltan (Latin)
|
||||
fv,fv_tsekehne,Tsek'ehne,BC Interior,fv_tsekehne_kmw-9.0.js,9.1.2,sek-Latn,Sekani (Latin)
|
||||
fv,fv_tsilhqotin,Tŝilhqot'in,BC Interior,fv_tsilhqotin_kmw-9.0.js,9.1.3,clc-Latn,Chilcotin (Latin)
|
||||
fv,fv_southern_carrier,ᑐᑊᘁᗕᑋᗸ (Southern Carrier),BC Interior,fv_southern_carrier_kmw-9.0.js,10.0.1,caf-Cans,Southern Carrier (Unified Canadian Aboriginal Syllabics)
|
||||
fv,fv_statimcets,St̓át̓imcets,BC Interior,fv_statimcets_kmw-9.0.js,9.2,lil-Latn,Lillooet (Latin)
|
||||
fv,fv_taltan,Tāłtān,BC Interior,fv_taltan_kmw-9.0.js,9.2,tht-Latn,Tahltan (Latin)
|
||||
fv,fv_tsekehne,Tsek'ehne,BC Interior,fv_tsekehne_kmw-9.0.js,9.2,sek-Latn,Sekani (Latin)
|
||||
fv,fv_tsilhqotin,Tŝilhqot'in,BC Interior,fv_tsilhqotin_kmw-9.0.js,9.2,clc-Latn,Chilcotin (Latin)
|
||||
fv,fv_southern_carrier,ᑐᑊᘁᗕᑋᗸ (Southern Carrier),BC Interior,fv_southern_carrier_kmw-9.0.js,10.1,caf-Cans,Southern Carrier (Unified Canadian Aboriginal Syllabics)
|
||||
fv,fv_anicinapemi8in,Anicinapemi8in/Anishinàbemiwin,Eastern Subarctic,fv_anicinapemi8in_kmw-9.0.js,9.1.1,alq-Latn,Algonquin (Latin)
|
||||
fv,fv_atikamekw,Atikamekw,Eastern Subarctic,fv_atikamekw_kmw-9.0.js,9.1.1,atj-Latn,Atikamekw (Latin)
|
||||
fv,fv_ilnu_innu_aimun,Ilnu-Innu Aimun,Eastern Subarctic,fv_ilnu_innu_aimun_kmw-9.0.js,9.1.1,moe-Latn,Montagnais (Latin)
|
||||
fv,fv_swampy_cree,ᐃᓂᓂᒧᐎᐣ (Swampy Cree),Eastern Subarctic,fv_swampy_cree_kmw-9.0.js,9.2.1,csw-Cans,Swampy Cree (Unified Canadian Aboriginal Syllabics)
|
||||
fv,fv_moose_cree,ᐃᓕᓖᒧᐎᓐ (Moose Cree),Eastern Subarctic,fv_moose_cree_kmw-9.0.js,9.2.1,crm-Cans,Moose Cree (Unified Canadian Aboriginal Syllabics)
|
||||
fv,fv_northern_east_cree,ᐄᔨᔫ-ᐄᓅ ᐊᔨᒨᓐ (Northern East Cree),Eastern Subarctic,fv_northern_east_cree_kmw-9.0.js,9.2.1,crl-Cans,Northern East Cree (Unified Canadian Aboriginal Syllabics)
|
||||
fv,fv_severn_ojibwa,ᐊᓂᔑᓂᓂᒧᐎᐣ (Severn Ojibwa),Eastern Subarctic,fv_severn_ojibwa_kmw-9.0.js,10.0.1,ojs-Cans,Severn Ojibwa (Unified Canadian Aboriginal Syllabics)
|
||||
fv,fv_severn_ojibwa_rdot,ᐊᓂᔑᓂᓂᒧᐏᐣ (Severn Ojibwa right w-dot),Eastern Subarctic,fv_severn_ojibwa_kmw-9.0.js,1.0.1,ojs,Oji-Cree
|
||||
fv,fv_ojibwa,ᐊᓂᔑᓇᐯᒧᐎᓐ (a-finals),Eastern Subarctic,fv_ojibwa_kmw-9.0.js,10.0.1,ojb-Cans,Northwestern Ojibwa (Unified Canadian Aboriginal Syllabics)
|
||||
fv,fv_ojibwa_rdot,ᐁᓂᔑᓇᐯᒧᐏᓐ (a-finals right w-dot),Eastern Subarctic,fv_ojibwa_rdot_kmw-9.0.js,1.0.1,oj,Ojibwa
|
||||
fv,fv_ojibwa_ifinal,ᐊᓂᔑᓇᐯᒧᐎᣙ (i-finals),Eastern Subarctic,fv_ojibwa_ifinal_kmw-9.0.js,1.0,oj,Ojibwa
|
||||
fv,fv_ojibwa_ifinal_rdot,ᐊᓂᔑᓇᐯᒧᐏᣙ (i-finals right w-dot),Eastern Subarctic,fv_ojibwa_ifinal_rdot_kmw-9.0.js,1.0,oj,Ojibwa
|
||||
fv,fv_severn_ojibwa,ᐊᓂᔑᓂᓂᒧᐎᐣ (Severn Ojibwa),Eastern Subarctic,fv_severn_ojibwa_kmw-9.0.js,10.1,ojs-Cans,Severn Ojibwa (Unified Canadian Aboriginal Syllabics)
|
||||
fv,fv_severn_ojibwa_rdot,ᐊᓂᔑᓂᓂᒧᐏᐣ (Severn Ojibwa right w-dot),Eastern Subarctic,fv_severn_ojibwa_kmw-9.0.js,1.1,ojs,Oji-Cree
|
||||
fv,fv_ojibwa,ᐊᓂᔑᓇᐯᒧᐎᓐ (a-finals),Eastern Subarctic,fv_ojibwa_kmw-9.0.js,10.1,ojb-Cans,Northwestern Ojibwa (Unified Canadian Aboriginal Syllabics)
|
||||
fv,fv_ojibwa_rdot,ᐁᓂᔑᓇᐯᒧᐏᓐ (a-finals right w-dot),Eastern Subarctic,fv_ojibwa_rdot_kmw-9.0.js,1.0.2,oj,Ojibwa
|
||||
fv,fv_ojibwa_ifinal,ᐊᓂᔑᓇᐯᒧᐎᣙ (i-finals),Eastern Subarctic,fv_ojibwa_ifinal_kmw-9.0.js,1.0.1,oj,Ojibwa
|
||||
fv,fv_ojibwa_ifinal_rdot,ᐊᓂᔑᓇᐯᒧᐏᣙ (i-finals right w-dot),Eastern Subarctic,fv_ojibwa_ifinal_rdot_kmw-9.0.js,1.0.1,oj,Ojibwa
|
||||
fv,fv_naskapi,ᓇᔅᑲᐱ (Naskapi),Eastern Subarctic,fv_naskapi_kmw-9.0.js,9.3.1,nsk-Cans,Naskapi (Unified Canadian Aboriginal Syllabics)
|
||||
sil,sil_euro_latin,English,European,european2-1.6.js,3.0.2,en,English
|
||||
basic,basic_kbdcan,Français,European,canadian_french-1.0.js,1.1.1,fr-CA,French (Canada)
|
||||
|
|
@ -82,23 +83,23 @@ fv,fv_isga_iabi,Isga Iʔabi,Prairies,fv_isga_iabi_kmw-9.0.js,9.1.1,sto-Latn,Ston
|
|||
fv,fv_lakota,Lak̇ot̄a,Prairies,fv_lakota-9.0.js,9.1.1,lkt-Latn,Lakota (Latin)
|
||||
fv,fv_nakoda,Nakoda,Prairies,fv_nakoda_kmw-9.0.js,9.1.1,asb-Latn,Assiniboine (Latin)
|
||||
fv,fv_tsuutina,Tsúùt'ínà,Prairies,fv_tsuutina_kmw-9.0.js,9.1.1,srs-Latn,Sarsi (Latin)
|
||||
fv,fv_plains_cree,ᓀᐦᐃᔭᐍᐏᐣ (Plains Cree),Prairies,fv_plains_cree_kmw-9.0.js,11.0.2,crk-Cans,ᓀᐦᐃᔭᐍᐏᐣ (Cree syllabics)
|
||||
fv,fv_plains_cree,ᓀᐦᐃᔭᐍᐏᐣ (Plains Cree),Prairies,fv_plains_cree_kmw-9.0.js,11.1,crk-Cans,ᓀᐦᐃᔭᐍᐏᐣ (Cree syllabics)
|
||||
fv,fv_dine_bizaad,Diné Bizaad,South West,fv_dine_bizaad_kmw-9.0.js,9.1.1,nv-Latn,Navajo (Latin)
|
||||
fv,fv_dane_zaa_zaage,Dane-Z̲aa Z̲áágéʔ,Western Subarctic,fv_dane_zaa_zaage_kmw-9.0.js,9.4,bea,Beaver
|
||||
fv,fv_dene_dzage,Dene Dzage,Western Subarctic,fv_dene_dzage_kmw-9.0.js,11.0.1,kkz-Latn,Kaska (Latin)
|
||||
fv,fv_dene_zhatie,Dene Zhatié,Western Subarctic,fv_dene_zhatie_kmw-9.0.js,10.2,den,Dene Zhatıé
|
||||
fv,fv_dene_zhatie,Dene Zhatié,Western Subarctic,fv_dene_zhatie_kmw-9.0.js,10.2.1,den,Dene Zhatıé
|
||||
fv,fv_denesuline_epsilon,Dënesųłıné,Western Subarctic,fv_denesuline_epsilon_kmw-9.0.js,10.0.1,chp,Chipewyan
|
||||
fv,fv_denesuline,Dɛnɛsųłiné,Western Subarctic,fv_denesuline_kmw-9.0.js,10.0.1,chp,Chipewyan (Latin)
|
||||
fv,fv_gwichin,Gwich'in,Western Subarctic,fv_gwichin_kmw-9.0.js,9.2.1,gwi-Latn,Gwichʼin (Latin)
|
||||
fv,fv_han,Hän,Western Subarctic,fv_han_kmw-9.0.js,9.2,haa-Latn,Han (Latin)
|
||||
fv,fv_kashogotine_yati,K'áshogot'ı̨nę́ Yatı̨́,Western Subarctic,fv_kashogotine_yati_kmw-9.0.js,10.0,scs,North Slavey
|
||||
fv,fv_tlingit,Łingít,Western Subarctic,fv_tlingit_kmw-9.0.js,10.0.1,tli,Tlingit (Latin)
|
||||
fv,fv_kashogotine_yati,K'áshogot'ı̨nę́ Yatı̨́,Western Subarctic,fv_kashogotine_yati_kmw-9.0.js,10.1,scs,North Slavey
|
||||
fv,fv_tlingit,Łingít,Western Subarctic,fv_tlingit_kmw-9.0.js,10.1,tli,Tlingit (Latin)
|
||||
fv,fv_neeaandeg,Nee'aanděg',Western Subarctic,fv_neeaandeg_kmw-9.0.js,9.1.1,tcb-Latn,Tanacross (Latin)
|
||||
fv,fv_neeaaneegn,Nee'aaneegn',Western Subarctic,fv_neeaaneegn_kmw-9.0.js,9.1,tau-Latn,Upper Tanana (Latin)
|
||||
fv,fv_northern_tutchone,Northern Tutchone,Western Subarctic,fv_northern_tutchone_kmw-9.0.js,9.2,ttm-Latn,Northern Tutchone (Latin)
|
||||
fv,fv_sahugotine_yati,Sahtúgot'ı̨nę́ Yatı̨́,Western Subarctic,fv_sahugotine_yati_kmw-9.0.js,9.1.1,scs-Latn,North Slavey (Latin)
|
||||
fv,fv_shihgotine_yati,Shıhgot'ı̨nę́ Yatı̨́,Western Subarctic,fv_shihgotine_yati_kmw-9.0.js,9.1.1,scs-Latn,North Slavey (Latin)
|
||||
fv,fv_southern_tutchone,Southern Tutchone,Western Subarctic,fv_southern_tutchone_kmw-9.0.js,9.2.2,tce-Latn,Southern Tutchone (Latin)
|
||||
fv,fv_southern_tutchone,Southern Tutchone,Western Subarctic,fv_southern_tutchone_kmw-9.0.js,9.3,tce-Latn,Southern Tutchone (Latin)
|
||||
fv,fv_tagizi_dene,Tāgizi Dene,Western Subarctic,fv_tagizi_dene_kmw-9.0.js,9.3,tgx-Latn,Tagish (Latin)
|
||||
fv,fv_tlicho_yatii,Tłı̨chǫ Yatıı̀,Western Subarctic,fv_tlicho_yatii_kmw-9.0.js,9.1.1,dgr-Latn,Dogrib (Latin)
|
||||
fv,fv_dene_mb,ᑌᓀ ᔭᕠᐁ (Dene MB),Western Subarctic,fv_dene_mb_kmw-9.0.js,9.2.1,chp-Cans,Chipewyan (Unified Canadian Aboriginal Syllabics)
|
||||
|
|
|
|||
|
60
package-lock.json
generated
|
|
@ -27,6 +27,7 @@
|
|||
"common/web/*",
|
||||
"common/tools/hextobin",
|
||||
"web",
|
||||
"web/src/engine/osk/gesture-processor",
|
||||
"web/src/engine/predictive-text/*"
|
||||
],
|
||||
"dependencies": {
|
||||
|
|
@ -59,7 +60,7 @@
|
|||
"eslint-plugin-promise": "^6.1.1",
|
||||
"mocha": "^10.0.0",
|
||||
"mocha-teamcity-reporter": "^4.0.0",
|
||||
"playwright": "^1.43.1",
|
||||
"playwright": "^1.46.1",
|
||||
"sinon": "^17.0.1",
|
||||
"source-map-support": "^0.5.21",
|
||||
"tslib": "^2.5.2",
|
||||
|
|
@ -159,19 +160,6 @@
|
|||
},
|
||||
"devDependencies": {}
|
||||
},
|
||||
"common/web/gesture-recognizer": {
|
||||
"name": "@keymanapp/gesture-recognizer",
|
||||
"dependencies": {
|
||||
"eventemitter3": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@keymanapp/resources-gosh": "*",
|
||||
"mocha": "^10.0.0",
|
||||
"mocha-teamcity-reporter": "^4.0.0",
|
||||
"promise-status-async": "^1.2.10",
|
||||
"typescript": "^5.4.5"
|
||||
}
|
||||
},
|
||||
"common/web/keyman-version": {
|
||||
"name": "@keymanapp/keyman-version",
|
||||
"license": "MIT",
|
||||
|
|
@ -404,7 +392,7 @@
|
|||
"eventemitter3": "^5.0.0",
|
||||
"restructure": "^3.0.1",
|
||||
"sax": ">=0.6.0",
|
||||
"semver": "^7.5.2",
|
||||
"semver": "^7.5.4",
|
||||
"xmlbuilder": "~11.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
@ -1153,7 +1141,7 @@
|
|||
"@keymanapp/keyman-version": "*",
|
||||
"@keymanapp/kmc-kmn": "*",
|
||||
"@keymanapp/ldml-keyboard-constants": "*",
|
||||
"semver": "^7.5.2"
|
||||
"semver": "^7.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@keymanapp/developer-test-helpers": "*",
|
||||
|
|
@ -1942,7 +1930,7 @@
|
|||
"open": "^8.4.0",
|
||||
"restructure": "^3.0.1",
|
||||
"sax": ">=0.6.0",
|
||||
"semver": "^7.5.2",
|
||||
"semver": "^7.5.4",
|
||||
"ws": "^8.17.1",
|
||||
"xmlbuilder": "~11.0.0"
|
||||
},
|
||||
|
|
@ -2795,7 +2783,7 @@
|
|||
"link": true
|
||||
},
|
||||
"node_modules/@keymanapp/gesture-recognizer": {
|
||||
"resolved": "common/web/gesture-recognizer",
|
||||
"resolved": "web/src/engine/osk/gesture-processor",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@keymanapp/hextobin": {
|
||||
|
|
@ -12077,33 +12065,35 @@
|
|||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.43.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.1.tgz",
|
||||
"integrity": "sha512-V7SoH0ai2kNt1Md9E3Gwas5B9m8KR2GVvwZnAI6Pg0m3sh7UvgiYhRrhsziCmqMJNouPckiOhk8T+9bSAK0VIA==",
|
||||
"version": "1.46.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.46.1.tgz",
|
||||
"integrity": "sha512-oPcr1yqoXLCkgKtD5eNUPLiN40rYEM39odNpIb6VE6S7/15gJmA1NzVv6zJYusV0e7tzvkU/utBFNa/Kpxmwng==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.43.1"
|
||||
"playwright-core": "1.46.1"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.43.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.1.tgz",
|
||||
"integrity": "sha512-EI36Mto2Vrx6VF7rm708qSnesVQKbxEWvPrfA1IPY6HgczBplDx7ENtx+K2n4kJ41sLLkuGfmb0ZLSSXlDhqPg==",
|
||||
"version": "1.46.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.46.1.tgz",
|
||||
"integrity": "sha512-h9LqIQaAv+CYvWzsZ+h3RsrqCStkBHlgo6/TJlFst3cOTlLghBQlJwPOZKQJTKNaD3QIB7aAVQ+gfWbN3NXB7A==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/portfinder": {
|
||||
|
|
@ -14630,7 +14620,7 @@
|
|||
"devDependencies": {
|
||||
"@types/semver": "^7.1.0",
|
||||
"@types/yargs": "^17.0.26",
|
||||
"semver": "^7.5.2"
|
||||
"semver": "^7.5.4"
|
||||
}
|
||||
},
|
||||
"resources/build/version/node_modules/ansi-regex": {
|
||||
|
|
@ -14764,6 +14754,20 @@
|
|||
"mocha": "^10.0.0"
|
||||
}
|
||||
},
|
||||
"web/src/engine/osk/gesture-processor": {
|
||||
"name": "@keymanapp/gesture-recognizer",
|
||||
"dependencies": {
|
||||
"@keymanapp/web-utils": "*",
|
||||
"eventemitter3": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@keymanapp/resources-gosh": "*",
|
||||
"mocha": "^10.0.0",
|
||||
"mocha-teamcity-reporter": "^4.0.0",
|
||||
"promise-status-async": "^1.2.10",
|
||||
"typescript": "^5.4.5"
|
||||
}
|
||||
},
|
||||
"web/src/engine/predictive-text/types": {
|
||||
"name": "@keymanapp/lm-message-types",
|
||||
"license": "MIT",
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
"eslint-plugin-promise": "^6.1.1",
|
||||
"mocha": "^10.0.0",
|
||||
"mocha-teamcity-reporter": "^4.0.0",
|
||||
"playwright": "^1.43.1",
|
||||
"playwright": "^1.46.1",
|
||||
"sinon": "^17.0.1",
|
||||
"source-map-support": "^0.5.21",
|
||||
"tslib": "^2.5.2",
|
||||
|
|
@ -52,6 +52,7 @@
|
|||
"common/web/*",
|
||||
"common/tools/hextobin",
|
||||
"web",
|
||||
"web/src/engine/osk/gesture-processor",
|
||||
"web/src/engine/predictive-text/*"
|
||||
],
|
||||
"dependencies": {
|
||||
|
|
|
|||
|
|
@ -23,8 +23,10 @@ source "$KEYMAN_ROOT/resources/build/win/environment_generated.inc.sh"
|
|||
WINDOWS_ROOT="$KEYMAN_ROOT/windows"
|
||||
WINDOWS_PROGRAM_APP="$WINDOWS_ROOT/bin/desktop"
|
||||
WINDOWS_PROGRAM_ENGINE="$WINDOWS_ROOT/bin/engine"
|
||||
WINDOWS_PROGRAM_SUPPORT="$WINDOWS_ROOT/bin/support"
|
||||
WINDOWS_DEBUGPATH_APP="$WINDOWS_ROOT/debug/desktop"
|
||||
WINDOWS_DEBUGPATH_ENGINE="$WINDOWS_ROOT/debug/engine"
|
||||
WINDOWS_DEBUGPATH_SUPPORT="$WINDOWS_ROOT/debug/support"
|
||||
|
||||
COMMON_ROOT="$KEYMAN_ROOT/common/windows/delphi"
|
||||
OUTLIB="$WINDOWS_ROOT/lib"
|
||||
|
|
@ -141,6 +143,8 @@ create-windows-output-folders() {
|
|||
mkdir -p "$OUTLIB"
|
||||
mkdir -p "$WINDOWS_PROGRAM_APP"
|
||||
mkdir -p "$WINDOWS_PROGRAM_ENGINE"
|
||||
mkdir -p "$WINDOWS_PROGRAM_SUPPORT"
|
||||
mkdir -p "$WINDOWS_DEBUGPATH_APP"
|
||||
mkdir -p "$WINDOWS_DEBUGPATH_ENGINE"
|
||||
mkdir -p "$WINDOWS_DEBUGPATH_SUPPORT"
|
||||
}
|
||||
|
|
@ -69,5 +69,7 @@ _select_emscripten_version_with_emsdk() {
|
|||
git pull
|
||||
./emsdk install "$KEYMAN_MIN_VERSION_EMSCRIPTEN"
|
||||
./emsdk activate "$KEYMAN_MIN_VERSION_EMSCRIPTEN"
|
||||
cd upstream/emscripten
|
||||
npm install
|
||||
popd > /dev/null
|
||||
}
|
||||
|
|
|
|||
58
resources/standards-data/unicode-character-database/download.sh
Executable file
|
|
@ -0,0 +1,58 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
## START STANDARD BUILD SCRIPT INCLUDE
|
||||
# adjust relative paths as necessary
|
||||
THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
|
||||
. "$(dirname "$THIS_SCRIPT")/../../../resources/build/builder.inc.sh"
|
||||
## END STANDARD BUILD SCRIPT INCLUDE
|
||||
|
||||
. "$KEYMAN_ROOT/resources/build/minimum-versions.inc.sh"
|
||||
|
||||
################################ Main script ################################
|
||||
|
||||
builder_describe \
|
||||
"Downloads Unicode data files, version $KEYMAN_VERSION_UNICODE (see minimum-versions.inc.sh), to be committed to repo." \
|
||||
download+
|
||||
|
||||
builder_describe_outputs \
|
||||
download /resources/standards-data/unicode-character-database/UnicodeData.txt
|
||||
|
||||
builder_parse "$@"
|
||||
|
||||
# Used by Developer
|
||||
BLOCKS_SRC_HREF="https://www.unicode.org/Public/$KEYMAN_VERSION_UNICODE/ucd/Blocks.txt"
|
||||
BLOCKS_SRC_LOCAL="./Blocks.txt"
|
||||
|
||||
UNICODE_DATA_SRC_HREF="https://www.unicode.org/Public/$KEYMAN_VERSION_UNICODE/ucd/UnicodeData.txt"
|
||||
UNICODE_DATA_SRC_LOCAL="./UnicodeData.txt"
|
||||
|
||||
# Used by common/models/wordbreakers for the default Unicode wordbreaker.
|
||||
WORDBREAK_PROP_SRC_HREF="https://www.unicode.org/Public/$KEYMAN_VERSION_UNICODE/ucd/auxiliary/WordBreakProperty.txt"
|
||||
WORDBREAK_PROP_SRC_LOCAL="./WordBreakProperty.txt"
|
||||
|
||||
EMOJI_DATA_SRC_HREF="https://www.unicode.org/Public/$KEYMAN_VERSION_UNICODE/ucd/emoji/emoji-data.txt"
|
||||
EMOJI_DATA_SRC_LOCAL="./emoji-data.txt"
|
||||
|
||||
function downloadPropertyFile() {
|
||||
local SRC="$1"
|
||||
local DEST="$2"
|
||||
|
||||
local RETRY=5 # Curl retries this number of times before giving up
|
||||
local RETRY_DELAY=5 # Make curl sleep this amount of time before each retry when a transfer has failed
|
||||
|
||||
echo "Downloading ${SRC} - ${RETRY} attempts"
|
||||
# local URL_DOWNLOAD_FILE=`curl --retry "$RETRY" --retry-delay "$RETRY_DELAY" --silent "${SRC}" | "$JQ" -r .txt`
|
||||
curl --fail --retry "$RETRY" --retry-delay "$RETRY_DELAY" --silent "$SRC" --output "$DEST" || {
|
||||
builder_die "Downloading $SRC failed with error $?"
|
||||
}
|
||||
}
|
||||
|
||||
do_download() {
|
||||
downloadPropertyFile "${BLOCKS_SRC_HREF}" "${BLOCKS_SRC_LOCAL}"
|
||||
downloadPropertyFile "${UNICODE_DATA_SRC_HREF}" "${UNICODE_DATA_SRC_LOCAL}"
|
||||
|
||||
downloadPropertyFile "${WORDBREAK_PROP_SRC_HREF}" "${WORDBREAK_PROP_SRC_LOCAL}"
|
||||
downloadPropertyFile "${EMOJI_DATA_SRC_HREF}" "${EMOJI_DATA_SRC_LOCAL}"
|
||||
}
|
||||
|
||||
builder_run_action download do_download
|
||||
1320
resources/standards-data/unicode-character-database/emoji-data.txt
Normal file
|
|
@ -7,8 +7,6 @@
|
|||
{ "path": "./common/models/wordbreakers/tsconfig.json" },
|
||||
{ "path": "./common/tools/hextobin/" },
|
||||
|
||||
{ "path": "./common/web/gesture-recognizer/tsconfig.json" },
|
||||
{ "path": "./common/web/gesture-recognizer/src/tools/unit-test-resources/tsconfig.json" },
|
||||
{ "path": "./common/web/keyman-version" },
|
||||
{ "path": "./common/web/recorder/tsconfig.json" },
|
||||
{ "path": "./common/web/sentry-manager/src/tsconfig.json" },
|
||||
|
|
@ -43,6 +41,8 @@
|
|||
{ "path": "./web/src/engine/predictive-text/types/" },
|
||||
{ "path": "./web/src/engine/predictive-text/worker-main/tsconfig.all.json" },
|
||||
{ "path": "./web/src/engine/predictive-text/worker-thread" },
|
||||
{ "path": "./web/src/engine/osk/gesture-processor/tsconfig.json" },
|
||||
{ "path": "./web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/tsconfig.json" },
|
||||
// { "path": "./web/tools/recorder/tsconfig.json" },
|
||||
// { "path": "./web/tools/sourcemap-root/tsconfig.json" },
|
||||
]
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ graph TD;
|
|||
LMWorker-->Wordbreakers;
|
||||
LMLayer["@keymanapp/lexical-model-layer<br>(/web/src/engine/predictive-text/worker-main)"];
|
||||
LMLayer-->LMWorker;
|
||||
Gestures["@keymanapp/gesture-recognizer<br>(/common/web/gesture-recognizer)"];
|
||||
Gestures["@keymanapp/gesture-recognizer<br>(/web/src/engine/osk/gesture-recognizer)"];
|
||||
Gestures-->WebUtils;
|
||||
|
||||
subgraph PredText["PredText: WebWorker + its interface"]
|
||||
|
|
|
|||
|
|
@ -109,6 +109,11 @@ precompile() {
|
|||
|
||||
build_action() {
|
||||
builder_echo "Building auto tests..."
|
||||
|
||||
# The currently-bundled declaration file for gesture-processor generates
|
||||
# errors when compiling against it with current tsc versions.
|
||||
rm -f "${KEYMAN_ROOT}/node_modules/promise-status-async/lib/index.d.ts"
|
||||
|
||||
tsc --project "${KEYMAN_ROOT}/web/src/test/auto/tsconfig.json"
|
||||
|
||||
for dir in \
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ if builder_start_action test; then
|
|||
# No --reporter option exists yet for the headless modules.
|
||||
|
||||
"$KEYMAN_ROOT/web/src/engine/keyboard/build.sh" test $OPTIONS
|
||||
"$KEYMAN_ROOT/common/web/gesture-recognizer/test.sh" $OPTIONS
|
||||
"$KEYMAN_ROOT/web/src/engine/osk/gesture-processor/build.sh" test $OPTIONS
|
||||
|
||||
./build.sh test $OPTIONS
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ BUNDLE_CMD="node $KEYMAN_ROOT/common/web/es-bundling/build/common-bundle.mjs"
|
|||
# ### Parameters
|
||||
#
|
||||
# * 1: `product` the product's source path under src/
|
||||
# * 2: `src_dir` the source directory. Optional. Default: ${KEYMAN_ROOT}/web/src
|
||||
# * 3: `build_dir` the build directory. Optional. Default: ${KEYMAN_ROOT}/web/build
|
||||
#
|
||||
# ### Example
|
||||
#
|
||||
|
|
@ -22,11 +24,13 @@ function compile() {
|
|||
fi
|
||||
|
||||
local COMPILE_TARGET="$1"
|
||||
local SRC_DIR=${2:-"${KEYMAN_ROOT}/web/src"}
|
||||
local BUILD_DIR=${3:-"${KEYMAN_ROOT}/web/build"}
|
||||
|
||||
tsc -b "${KEYMAN_ROOT}/web/src/$COMPILE_TARGET"
|
||||
tsc -b "${SRC_DIR}/$COMPILE_TARGET"
|
||||
|
||||
# So... tsc does declaration-bundling on its own pretty well, at least for local development.
|
||||
tsc --emitDeclarationOnly --outFile "${KEYMAN_ROOT}/web/build/$COMPILE_TARGET/lib/index.d.ts" -p "${KEYMAN_ROOT}/web/src/$COMPILE_TARGET"
|
||||
tsc --emitDeclarationOnly --outFile "${BUILD_DIR}/$COMPILE_TARGET/lib/index.d.ts" -p "${SRC_DIR}/$COMPILE_TARGET"
|
||||
}
|
||||
|
||||
function _copy_dir_if_exists() {
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@
|
|||
}
|
||||
},
|
||||
"imports": {
|
||||
"#gesture-tools": "./src/engine/osk/gesture-processor/build/tools/obj/index.js",
|
||||
"#recorder": "./build/tools/testing/recorder/obj/index.js"
|
||||
},
|
||||
"repository": {
|
||||
|
|
|
|||
|
|
@ -44,22 +44,20 @@ do_clean() {
|
|||
}
|
||||
|
||||
compile_and_copy() {
|
||||
local COMPILE_FLAGS=
|
||||
if builder_has_option --ci; then
|
||||
COMPILE_FLAGS=--ci
|
||||
fi
|
||||
compile $SUBPROJECT_NAME $COMPILE_FLAGS
|
||||
compile $SUBPROJECT_NAME
|
||||
|
||||
BUILD_ROOT="${KEYMAN_ROOT}/web/build/app/browser"
|
||||
SRC_ROOT="${KEYMAN_ROOT}/web/src/app/browser/src"
|
||||
|
||||
$BUNDLE_CMD "${SRC_ROOT}/debug-main.js" \
|
||||
--out "${BUILD_ROOT}/debug/keymanweb.js" \
|
||||
--charset "utf8" \
|
||||
--sourceRoot "@keymanapp/keyman/web/build/app/browser/debug" \
|
||||
--target "es6"
|
||||
|
||||
$BUNDLE_CMD "${SRC_ROOT}/release-main.js" \
|
||||
--out "${BUILD_ROOT}/release/keymanweb.js" \
|
||||
--charset "utf8" \
|
||||
--profile "${BUILD_ROOT}/filesize-profile.log" \
|
||||
--sourceRoot "@keymanapp/keyman/web/build/app/browser/release" \
|
||||
--minify \
|
||||
|
|
@ -67,6 +65,7 @@ compile_and_copy() {
|
|||
|
||||
$BUNDLE_CMD "${BUILD_ROOT}/obj/test-index.js" \
|
||||
--out "${BUILD_ROOT}/lib/index.mjs" \
|
||||
--charset "utf8" \
|
||||
--sourceRoot "@keymanapp/keyman/web/build/app/browser/lib" \
|
||||
--format esm
|
||||
|
||||
|
|
|
|||
|
|
@ -45,11 +45,13 @@ compile_and_copy() {
|
|||
|
||||
$BUNDLE_CMD "${SRC_ROOT}/debug-main.js" \
|
||||
--out "${BUILD_ROOT}/debug/keymanweb-webview.js" \
|
||||
--charset "utf8" \
|
||||
--sourceRoot "@keymanapp/keyman/web/build/app/webview/debug" \
|
||||
--target "es6"
|
||||
|
||||
$BUNDLE_CMD "${SRC_ROOT}/release-main.js" \
|
||||
--out "${BUILD_ROOT}/release/keymanweb-webview.js" \
|
||||
--charset "utf8" \
|
||||
--profile "${BUILD_ROOT}/filesize-profile.log" \
|
||||
--sourceRoot "@keymanapp/keyman/web/build/app/webview/release" \
|
||||
--minify \
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import OutputTarget from './outputTarget.js';
|
||||
|
||||
// Due to some interesting requirements on compile ordering in TS,
|
||||
// this needs to be in the same file as OutputTarget now.
|
||||
export class Mock extends OutputTarget {
|
||||
text: string;
|
||||
|
||||
|
|
|
|||
|
|
@ -66,12 +66,6 @@ function do_build() {
|
|||
--format esm \
|
||||
--platform node
|
||||
|
||||
# # Tests
|
||||
# builder_echo "Bundle tests"
|
||||
# ${BUNDLE_CMD} "${BUILD_DIR}/tests/dom/cases/domKeyboardLoader.spec.js" \
|
||||
# --out "${BUILD_DIR}/tests/dom/domKeyboardLoader.spec.mjs" \
|
||||
# --format esm
|
||||
|
||||
# Declaration bundling.
|
||||
builder_echo "Declaration bundling"
|
||||
tsc --emitDeclarationOnly --outFile "${BUILD_DIR}/lib/index.d.ts"
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@ SUBPROJECT_NAME=engine/osk
|
|||
|
||||
builder_describe "Builds the Keyman Engine for Web's On-Screen Keyboard package (OSK)." \
|
||||
"@/web/src/engine/keyboard build" \
|
||||
"@/common/web/gesture-recognizer build" \
|
||||
"@/web/src/engine/interfaces build" \
|
||||
"@/web/src/engine/dom-utils build" \
|
||||
"@/web/src/engine/events build" \
|
||||
"@/web/src/engine/osk/gesture-processor" \
|
||||
"clean" \
|
||||
"configure" \
|
||||
"build" \
|
||||
|
|
|
|||
|
|
@ -6,6 +6,6 @@ KeymanWeb, seen within this repo at /web/.
|
|||
|
||||
## Minimum Compilation Requirements
|
||||
|
||||
See the repo-level [document for build configuration](../../../docs/build/index.md) for details on how to
|
||||
See the repo-level [document for build configuration](../../../../../docs/build/index.md) for details on how to
|
||||
configure your build environment.
|
||||
- Follow the Keyman Engine for Web (KeymanWeb) requirements where appropriate.
|
||||
65
web/src/engine/osk/gesture-processor/build.sh
Executable file
|
|
@ -0,0 +1,65 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
## START STANDARD BUILD SCRIPT INCLUDE
|
||||
# adjust relative paths as necessary
|
||||
THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
|
||||
. "$(dirname "$THIS_SCRIPT")/../../../../../resources/build/builder.inc.sh"
|
||||
## END STANDARD BUILD SCRIPT INCLUDE
|
||||
|
||||
SUBPROJECT_NAME=engine/osk/gesture-processor
|
||||
|
||||
. "${KEYMAN_ROOT}/web/common.inc.sh"
|
||||
. "${KEYMAN_ROOT}/resources/shellHelperFunctions.sh"
|
||||
|
||||
BUNDLE_CMD="node $KEYMAN_ROOT/common/web/es-bundling/build/common-bundle.mjs"
|
||||
|
||||
BUILD_DIR="/web/src/engine/osk/gesture-processor/build"
|
||||
|
||||
################################ Main script ################################
|
||||
|
||||
builder_describe "Builds the gesture-recognition model for Web-based on-screen keyboards" \
|
||||
"@/common/web/es-bundling build" \
|
||||
"@/common/web/utils build" \
|
||||
"clean" \
|
||||
"configure" \
|
||||
"build" \
|
||||
"test" \
|
||||
":module" \
|
||||
":tools tools for testing & developing test resources for this module" \
|
||||
"--ci sets the --ci option for child scripts (i.e, the $(builder_term test) action)"
|
||||
|
||||
builder_describe_outputs \
|
||||
configure /node_modules \
|
||||
build:module "${BUILD_DIR}/lib/index.mjs" \
|
||||
build:tools "${BUILD_DIR}/tools/lib/index.mjs"
|
||||
|
||||
builder_parse "$@"
|
||||
|
||||
# TODO: build if out-of-date if test is specified
|
||||
# TODO: configure if npm has not been run, and build is specified
|
||||
|
||||
function do_configure() {
|
||||
verify_npm_setup
|
||||
}
|
||||
|
||||
function do_build_module() {
|
||||
# Build
|
||||
tsc --build $builder_verbose
|
||||
|
||||
$BUNDLE_CMD "${KEYMAN_ROOT}/${BUILD_DIR}/obj/index.js" \
|
||||
--out "${KEYMAN_ROOT}/${BUILD_DIR}/lib/index.mjs" \
|
||||
--format esm
|
||||
}
|
||||
|
||||
function do_test_tools() {
|
||||
if ! builder_has_action test:module; then
|
||||
echo "The $(builder_term test:tools) action is currently a no-op."
|
||||
fi
|
||||
}
|
||||
|
||||
builder_run_action configure do_configure
|
||||
builder_run_action clean rm -rf build/ intermediate/
|
||||
builder_run_action build:module do_build_module
|
||||
builder_run_action build:tools src/tools/build.sh build
|
||||
builder_run_action test:module test-headless-typescript "${SUBPROJECT_NAME}"
|
||||
builder_run_action test:tools do_test_tools
|
||||
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 92 KiB |
|
|
@ -8,14 +8,12 @@
|
|||
"promise-status-async": "^1.2.10",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"imports": {
|
||||
"#tools": "./build/tools/obj/index.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gosh ./build.sh",
|
||||
"test": "gosh ./test.sh"
|
||||
"test": "gosh ./build.sh test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@keymanapp/web-utils": "*",
|
||||
"eventemitter3": "^5.0.0"
|
||||
},
|
||||
"main": "./build/obj/index.js",
|
||||