diff --git a/HISTORY.md b/HISTORY.md
index 7bb236717b..1afecba649 100644
--- a/HISTORY.md
+++ b/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)
diff --git a/VERSION.md b/VERSION.md
index a41e5425c0..5e9ac7140c 100644
--- a/VERSION.md
+++ b/VERSION.md
@@ -1 +1 @@
-18.0.95
\ No newline at end of file
+18.0.101
\ No newline at end of file
diff --git a/android/KMAPro/kMAPro/src/main/res/drawable-ldrtl-hdpi/blank_osk.png b/android/KMAPro/kMAPro/src/main/res/drawable-ldrtl-hdpi/blank_osk.png
new file mode 100644
index 0000000000..c5d555caca
Binary files /dev/null and b/android/KMAPro/kMAPro/src/main/res/drawable-ldrtl-hdpi/blank_osk.png differ
diff --git a/android/KMAPro/kMAPro/src/main/res/drawable-ldrtl-land-hdpi/blank_osk.png b/android/KMAPro/kMAPro/src/main/res/drawable-ldrtl-land-hdpi/blank_osk.png
new file mode 100644
index 0000000000..3e41a359a0
Binary files /dev/null and b/android/KMAPro/kMAPro/src/main/res/drawable-ldrtl-land-hdpi/blank_osk.png differ
diff --git a/android/KMAPro/kMAPro/src/main/res/drawable-ldrtl-sw600dp-land/blank_osk.png b/android/KMAPro/kMAPro/src/main/res/drawable-ldrtl-sw600dp-land/blank_osk.png
new file mode 100644
index 0000000000..282606a9d5
Binary files /dev/null and b/android/KMAPro/kMAPro/src/main/res/drawable-ldrtl-sw600dp-land/blank_osk.png differ
diff --git a/android/KMAPro/kMAPro/src/main/res/drawable-ldrtl-sw600dp/blank_osk.png b/android/KMAPro/kMAPro/src/main/res/drawable-ldrtl-sw600dp/blank_osk.png
new file mode 100644
index 0000000000..8246a64168
Binary files /dev/null and b/android/KMAPro/kMAPro/src/main/res/drawable-ldrtl-sw600dp/blank_osk.png differ
diff --git a/android/KMAPro/kMAPro/src/main/res/drawable-ldrtl-sw720dp-land/blank_osk.png b/android/KMAPro/kMAPro/src/main/res/drawable-ldrtl-sw720dp-land/blank_osk.png
new file mode 100644
index 0000000000..740c8559c9
Binary files /dev/null and b/android/KMAPro/kMAPro/src/main/res/drawable-ldrtl-sw720dp-land/blank_osk.png differ
diff --git a/android/KMAPro/kMAPro/src/main/res/drawable-ldrtl-sw720dp/blank_osk.png b/android/KMAPro/kMAPro/src/main/res/drawable-ldrtl-sw720dp/blank_osk.png
new file mode 100644
index 0000000000..0e3343bbd1
Binary files /dev/null and b/android/KMAPro/kMAPro/src/main/res/drawable-ldrtl-sw720dp/blank_osk.png differ
diff --git a/android/KMAPro/kMAPro/src/main/res/layout/activity_adjust_longpress_delay.xml b/android/KMAPro/kMAPro/src/main/res/layout/activity_adjust_longpress_delay.xml
index ed0bed54a9..ef1ebd613b 100644
--- a/android/KMAPro/kMAPro/src/main/res/layout/activity_adjust_longpress_delay.xml
+++ b/android/KMAPro/kMAPro/src/main/res/layout/activity_adjust_longpress_delay.xml
@@ -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" />
+ android:src="@drawable/ic_action_increment" />
diff --git a/android/KMAPro/kMAPro/src/main/res/layout/activity_info.xml b/android/KMAPro/kMAPro/src/main/res/layout/activity_info.xml
index 3b71e87178..314a503412 100644
--- a/android/KMAPro/kMAPro/src/main/res/layout/activity_info.xml
+++ b/android/KMAPro/kMAPro/src/main/res/layout/activity_info.xml
@@ -1,12 +1,12 @@
+ 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" >
-
-
+ android:orientation="horizontal">
-
+
+
+
+
+
= startOfNextRange) {
- return searchForProperty(codePoint, midpoint + 1, right);
- }
-
- // We found it!
- return candidate[I.Value];
-}
+}
\ No newline at end of file
diff --git a/common/models/wordbreakers/src/main/default/searchForProperty.ts b/common/models/wordbreakers/src/main/default/searchForProperty.ts
new file mode 100644
index 0000000000..78f1b5f268
--- /dev/null
+++ b/common/models/wordbreakers/src/main/default/searchForProperty.ts
@@ -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;
+}
\ No newline at end of file
diff --git a/common/models/wordbreakers/src/index.ts b/common/models/wordbreakers/src/main/index.ts
similarity index 100%
rename from common/models/wordbreakers/src/index.ts
rename to common/models/wordbreakers/src/main/index.ts
diff --git a/common/models/wordbreakers/src/placeholder.ts b/common/models/wordbreakers/src/main/placeholder.ts
similarity index 100%
rename from common/models/wordbreakers/src/placeholder.ts
rename to common/models/wordbreakers/src/main/placeholder.ts
diff --git a/common/models/wordbreakers/src/main/test-index.ts b/common/models/wordbreakers/src/main/test-index.ts
new file mode 100644
index 0000000000..6ea7b04532
--- /dev/null
+++ b/common/models/wordbreakers/src/main/test-index.ts
@@ -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';
diff --git a/common/models/wordbreakers/test/test-search-property.js b/common/models/wordbreakers/test/test-search-property.js
new file mode 100644
index 0000000000..9f33e4cc0c
--- /dev/null
+++ b/common/models/wordbreakers/test/test-search-property.js
@@ -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'));
+ });
+});
\ No newline at end of file
diff --git a/common/models/wordbreakers/tools/data-compiler/LICENSE b/common/models/wordbreakers/tools/data-compiler/LICENSE
new file mode 100644
index 0000000000..14c39a294a
--- /dev/null
+++ b/common/models/wordbreakers/tools/data-compiler/LICENSE
@@ -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.
\ No newline at end of file
diff --git a/common/models/wordbreakers/tools/data-compiler/index.ts b/common/models/wordbreakers/tools/data-compiler/index.ts
new file mode 100644
index 0000000000..8f3c41bad3
--- /dev/null
+++ b/common/models/wordbreakers/tools/data-compiler/index.ts
@@ -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();
+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();
+
+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;
+}
\ No newline at end of file
diff --git a/common/models/wordbreakers/tools/data-compiler/tsconfig.json b/common/models/wordbreakers/tools/data-compiler/tsconfig.json
new file mode 100644
index 0000000000..577d1174df
--- /dev/null
+++ b/common/models/wordbreakers/tools/data-compiler/tsconfig.json
@@ -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"
+ ]
+}
diff --git a/common/models/wordbreakers/tsconfig.json b/common/models/wordbreakers/tsconfig.json
index 54d12d5d8c..46095418b2 100644
--- a/common/models/wordbreakers/tsconfig.json
+++ b/common/models/wordbreakers/tsconfig.json
@@ -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"
]
-}
+}
\ No newline at end of file
diff --git a/common/web/es-bundling/src/common-bundle.mts b/common/web/es-bundling/src/common-bundle.mts
index fb3dfb95a4..856d08ec05 100644
--- a/common/web/es-bundling/src/common-bundle.mts
+++ b/common/web/es-bundling/src/common-bundle.mts
@@ -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= Sets the charset type for esbuild to emit. Defaults to 'ascii'
+ but may also be 'utf8'.
--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,
diff --git a/common/web/gesture-recognizer/build.sh b/common/web/gesture-recognizer/build.sh
deleted file mode 100755
index a27cd3f8d1..0000000000
--- a/common/web/gesture-recognizer/build.sh
+++ /dev/null
@@ -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
\ No newline at end of file
diff --git a/common/web/gesture-recognizer/src/test/auto/browser/web-test-runner.CI.config.mjs b/common/web/gesture-recognizer/src/test/auto/browser/web-test-runner.CI.config.mjs
deleted file mode 100644
index d18a8a9cb0..0000000000
--- a/common/web/gesture-recognizer/src/test/auto/browser/web-test-runner.CI.config.mjs
+++ /dev/null
@@ -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})
- ]
-}
\ No newline at end of file
diff --git a/common/web/gesture-recognizer/src/test/auto/browser/web-test-runner.config.mjs b/common/web/gesture-recognizer/src/test/auto/browser/web-test-runner.config.mjs
deleted file mode 100644
index 0d5bac8508..0000000000
--- a/common/web/gesture-recognizer/src/test/auto/browser/web-test-runner.config.mjs
+++ /dev/null
@@ -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
-}
\ No newline at end of file
diff --git a/common/web/gesture-recognizer/src/test/tsconfig.json b/common/web/gesture-recognizer/src/test/tsconfig.json
deleted file mode 100644
index 4eea3ef803..0000000000
--- a/common/web/gesture-recognizer/src/test/tsconfig.json
+++ /dev/null
@@ -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": "../../"}
- ]
-}
diff --git a/common/web/gesture-recognizer/test.sh b/common/web/gesture-recognizer/test.sh
deleted file mode 100755
index 03d0e32fa1..0000000000
--- a/common/web/gesture-recognizer/test.sh
+++ /dev/null
@@ -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
\ No newline at end of file
diff --git a/common/windows/.gitignore b/common/windows/.gitignore
index 7af23e7e1a..a6cb808a34 100644
--- a/common/windows/.gitignore
+++ b/common/windows/.gitignore
@@ -7,3 +7,4 @@ delphi/**/*.~*
delphi/**/__recovery/
delphi/**/__history/
delphi/general/keymanversion_build.inc
+delphi/ext/cef4delphi/packages/CEF4Delphi.res
diff --git a/common/windows/delphi/Defines.mak b/common/windows/delphi/Defines.mak
deleted file mode 100644
index 50210e5fea..0000000000
--- a/common/windows/delphi/Defines.mak
+++ /dev/null
@@ -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
diff --git a/common/windows/delphi/Header.mak b/common/windows/delphi/Header.mak
deleted file mode 100644
index 6c78b3724e..0000000000
--- a/common/windows/delphi/Header.mak
+++ /dev/null
@@ -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
\ No newline at end of file
diff --git a/common/windows/delphi/Target.mak b/common/windows/delphi/Target.mak
deleted file mode 100644
index 777bd84beb..0000000000
--- a/common/windows/delphi/Target.mak
+++ /dev/null
@@ -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
diff --git a/common/windows/delphi/components/common_components.dproj b/common/windows/delphi/components/common_components.dproj
index 2bd91473ab..4ecda90464 100644
--- a/common/windows/delphi/components/common_components.dproj
+++ b/common/windows/delphi/components/common_components.dproj
@@ -13,31 +13,6 @@
true
-
- true
- Base
- true
-
-
- true
- Base
- true
-
-
- true
- Base
- true
-
-
- true
- Base
- true
-
-
- true
- Base
- true
-
true
Base
@@ -59,6 +34,12 @@
Base
true
+
+ true
+ Cfg_2
+ true
+ true
+
.\obj\$(Platform)\$(Config)
.\$(Platform)\$(Config)
@@ -77,23 +58,6 @@
3081
CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
-
- None
- 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
-
-
- None
- 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
-
-
- None
-
-
- None
-
-
- None
-
Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
Debug
@@ -113,6 +77,7 @@
false
true
1033
+ ..\..\lib
false
@@ -120,6 +85,11 @@
0
0
+
+ ..\..\lib
+ true
+ 1033
+
MainSource
@@ -164,8 +134,6 @@
common_components.dpk
- File c:\projects\keyman\app\windows\lib\DCPdelphi2009.bpl not found
- File c:\projects\keyman\app\windows\lib\delphiprojectmanager.bpl not found
Microsoft Office 2000 Sample Automation Server Wrapper Components
Microsoft Office XP Sample Automation Server Wrapper Components
@@ -944,13 +912,6 @@
- False
- False
- False
- False
- False
- False
- False
True
False
diff --git a/common/windows/delphi/ext/cef4delphi/packages/CEF4Delphi.res b/common/windows/delphi/ext/cef4delphi/packages/CEF4Delphi.res
deleted file mode 100644
index b9b013c212..0000000000
Binary files a/common/windows/delphi/ext/cef4delphi/packages/CEF4Delphi.res and /dev/null differ
diff --git a/common/windows/delphi/tools/certificates/build.sh b/common/windows/delphi/tools/certificates/build.sh
index 378723a125..10ab4c75ce 100755
--- a/common/windows/delphi/tools/certificates/build.sh
+++ b/common/windows/delphi/tools/certificates/build.sh
@@ -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
diff --git a/core/src/ldml/ldml_processor.cpp b/core/src/ldml/ldml_processor.cpp
index f90fcfaa94..fcadda629c 100644
--- a/core/src/ldml/ldml_processor.cpp
+++ b/core/src/ldml/ldml_processor.cpp
@@ -85,7 +85,7 @@ ldml_processor::ldml_processor(path const & kb_path, const std::vector
} 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.
diff --git a/core/src/ldml/ldml_vkeys.cpp b/core/src/ldml/ldml_vkeys.cpp
index 07a2ff08ad..f79f82141f 100644
--- a/core/src/ldml/ldml_vkeys.cpp
+++ b/core/src/ldml/ldml_vkeys.cpp
@@ -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
diff --git a/core/src/ldml/ldml_vkeys.hpp b/core/src/ldml/ldml_vkeys.hpp
index ed3368dc7e..6a54d77065 100644
--- a/core/src/ldml/ldml_vkeys.hpp
+++ b/core/src/ldml/ldml_vkeys.hpp
@@ -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 vkey_id;
+typedef std::pair 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
diff --git a/developer/src/README.md b/developer/src/README.md
index 7e7ea9d336..d789b63f08 100644
--- a/developer/src/README.md
+++ b/developer/src/README.md
@@ -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.
\ No newline at end of file
+Various build-time tools for Keyman Developer.
+
+
diff --git a/developer/src/common/web/utils/build.sh b/developer/src/common/web/utils/build.sh
index 8829765237..2209463e18 100755
--- a/developer/src/common/web/utils/build.sh
+++ b/developer/src/common/web/utils/build.sh
@@ -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
}
diff --git a/developer/src/common/web/utils/src/types/ldml-keyboard/ldml-keyboard-xml-reader.ts b/developer/src/common/web/utils/src/types/ldml-keyboard/ldml-keyboard-xml-reader.ts
index 162cac4aac..ddeaf719ab 100644
--- a/developer/src/common/web/utils/src/types/ldml-keyboard/ldml-keyboard-xml-reader.ts
+++ b/developer/src/common/web/utils/src/types/ldml-keyboard/ldml-keyboard-xml-reader.ts
@@ -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 {
diff --git a/developer/src/kmc-ldml/src/compiler/visual-keyboard-compiler.ts b/developer/src/kmc-ldml/src/compiler/visual-keyboard-compiler.ts
index 6182e6e2c8..6d76bc403e 100644
--- a/developer/src/kmc-ldml/src/compiler/visual-keyboard-compiler.ts
+++ b/developer/src/kmc-ldml/src/compiler/visual-keyboard-compiler.ts
@@ -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(
diff --git a/developer/src/kmc-model/test/test-compile-model.ts b/developer/src/kmc-model/test/test-compile-model.ts
index e3074d697a..7de9d6d5da 100644
--- a/developer/src/kmc-model/test/test-compile-model.ts
+++ b/developer/src/kmc-model/test/test-compile-model.ts
@@ -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',
diff --git a/developer/src/kmcmplib/src/Compiler.cpp b/developer/src/kmcmplib/src/Compiler.cpp
index 3893a72855..313cc859e5 100644
--- a/developer/src/kmcmplib/src/Compiler.cpp
+++ b/developer/src/kmcmplib/src/Compiler.cpp
@@ -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;
diff --git a/developer/src/kmcmplib/tests/gtest-compiler-test.cpp b/developer/src/kmcmplib/tests/gtest-compiler-test.cpp
index 1c20597645..aab01f8131 100644
--- a/developer/src/kmcmplib/tests/gtest-compiler-test.cpp
+++ b/developer/src/kmcmplib/tests/gtest-compiler-test.cpp
@@ -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)
diff --git a/developer/src/tike/build.sh b/developer/src/tike/build.sh
index 1ab9dbe320..fd81ca692d 100755
--- a/developer/src/tike/build.sh
+++ b/developer/src/tike/build.sh
@@ -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
diff --git a/docs/build/linux-ubuntu.md b/docs/build/linux-ubuntu.md
index 0107491dda..a45d9390ba 100644
--- a/docs/build/linux-ubuntu.md
+++ b/docs/build/linux-ubuntu.md
@@ -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
diff --git a/docs/build/macos.md b/docs/build/macos.md
index 81b1bcd0e7..25b0c1f82a 100644
--- a/docs/build/macos.md
+++ b/docs/build/macos.md
@@ -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
diff --git a/docs/build/windows.md b/docs/build/windows.md
index dcb55ce4a4..3168bcd0ae 100644
--- a/docs/build/windows.md
+++ b/docs/build/windows.md
@@ -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 ` 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 ` 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`: `\upstream\emscripten`
-After installing emscripten, you'll need to install node.js and openjdk.
+```bat
+SETX EMSCRIPTEN_BASE "\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)
diff --git a/docs/file-formats/kmx-plus-file-format.md b/docs/file-formats/kmx-plus-file-format.md
index 75e1df4295..3b7003f09a 100644
--- a/docs/file-formats/kmx-plus-file-format.md
+++ b/docs/file-formats/kmx-plus-file-format.md
@@ -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
diff --git a/docs/minimum-versions.md b/docs/minimum-versions.md
index a9a2ead26b..f582632007 100644
--- a/docs/minimum-versions.md
+++ b/docs/minimum-versions.md
@@ -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 |
diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift
index 5b77f79307..d1d134b249 100644
--- a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift
+++ b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift
@@ -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()
+ }
}
}
diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Resource Data/FontManager.swift b/ios/engine/KMEI/KeymanEngine/Classes/Resource Data/FontManager.swift
index d64019cc27..6070de2c96 100644
--- a/ios/engine/KMEI/KeymanEngine/Classes/Resource Data/FontManager.swift
+++ b/ios/engine/KMEI/KeymanEngine/Classes/Resource Data/FontManager.swift
@@ -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 = []
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) {
+ // 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?
+ 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?
- 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) -> Set {
+ 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
}
}
diff --git a/linux/keyman-config/keyman_config/kvk2ldml.py b/linux/keyman-config/keyman_config/kvk2ldml.py
index 5b3ab85ae8..3b3aee281b 100755
--- a/linux/keyman-config/keyman_config/kvk2ldml.py
+++ b/linux/keyman-config/keyman_config/kvk2ldml.py
@@ -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(" 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("CFBundlePackageType
APPL
CFBundleShortVersionString
- Keyman $(PRODUCT_VERSION) for macOS
+ $(PRODUCT_VERSION)
CFBundleSignature
????
CFBundleURLTypes
diff --git a/mac/Keyman4MacIM/Keyman4MacIM/TextApiCompliance.h b/mac/Keyman4MacIM/Keyman4MacIM/TextApiCompliance.h
index 6c80417faf..81cc4c3b34 100644
--- a/mac/Keyman4MacIM/Keyman4MacIM/TextApiCompliance.h
+++ b/mac/Keyman4MacIM/Keyman4MacIM/TextApiCompliance.h
@@ -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;
diff --git a/mac/Keyman4MacIM/Keyman4MacIM/TextApiCompliance.m b/mac/Keyman4MacIM/Keyman4MacIM/TextApiCompliance.m
index 0f62fa61a8..e83439794b 100644
--- a/mac/Keyman4MacIM/Keyman4MacIM/TextApiCompliance.m
+++ b/mac/Keyman4MacIM/Keyman4MacIM/TextApiCompliance.m
@@ -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 */
diff --git a/mac/Keyman4MacIM/KeymanTests/InputMethodTests.m b/mac/Keyman4MacIM/KeymanTests/InputMethodTests.m
index 8eb9d974ce..7372a2a548 100644
--- a/mac/Keyman4MacIM/KeymanTests/InputMethodTests.m
+++ b/mac/Keyman4MacIM/KeymanTests/InputMethodTests.m
@@ -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
diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/Info.plist b/mac/KeymanEngine4Mac/KeymanEngine4Mac/Info.plist
index 970606a26a..3f42d3e63f 100644
--- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/Info.plist
+++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/Info.plist
@@ -17,7 +17,7 @@
CFBundlePackageType
FMWK
CFBundleShortVersionString
- Keyman Engine $(PRODUCT_VERSION) for macOS
+ $(PRODUCT_VERSION)
CFBundleSignature
????
CFBundleVersion
diff --git a/oem/firstvoices/keyboards.csv b/oem/firstvoices/keyboards.csv
index cbede23edc..22812ec14d 100644
--- a/oem/firstvoices/keyboards.csv
+++ b/oem/firstvoices/keyboards.csv
@@ -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)
diff --git a/package-lock.json b/package-lock.json
index 548b4b5c54..03eb87447a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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",
diff --git a/package.json b/package.json
index 3f0012db10..72508afc03 100644
--- a/package.json
+++ b/package.json
@@ -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": {
diff --git a/resources/build/win/environment.inc.sh b/resources/build/win/environment.inc.sh
index d2b351fcbc..71c18f305b 100644
--- a/resources/build/win/environment.inc.sh
+++ b/resources/build/win/environment.inc.sh
@@ -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"
}
\ No newline at end of file
diff --git a/resources/locate_emscripten.inc.sh b/resources/locate_emscripten.inc.sh
index f678e8449e..3d470f7577 100644
--- a/resources/locate_emscripten.inc.sh
+++ b/resources/locate_emscripten.inc.sh
@@ -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
}
diff --git a/resources/standards-data/unicode-character-database/WordBreakProperty.txt b/resources/standards-data/unicode-character-database/WordBreakProperty.txt
new file mode 100644
index 0000000000..302a2769b3
--- /dev/null
+++ b/resources/standards-data/unicode-character-database/WordBreakProperty.txt
@@ -0,0 +1,1468 @@
+# WordBreakProperty-15.1.0.txt
+# Date: 2023-03-31, 03:19:05 GMT
+# © 2023 Unicode®, Inc.
+# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
+# For terms of use, see https://www.unicode.org/terms_of_use.html
+#
+# Unicode Character Database
+# For documentation, see https://www.unicode.org/reports/tr44/
+
+# ================================================
+
+# Property: Word_Break
+
+# All code points not explicitly listed for Word_Break
+# have the value Other (XX).
+
+# @missing: 0000..10FFFF; Other
+
+# ================================================
+
+0022 ; Double_Quote # Po QUOTATION MARK
+
+# Total code points: 1
+
+# ================================================
+
+0027 ; Single_Quote # Po APOSTROPHE
+
+# Total code points: 1
+
+# ================================================
+
+05D0..05EA ; Hebrew_Letter # Lo [27] HEBREW LETTER ALEF..HEBREW LETTER TAV
+05EF..05F2 ; Hebrew_Letter # Lo [4] HEBREW YOD TRIANGLE..HEBREW LIGATURE YIDDISH DOUBLE YOD
+FB1D ; Hebrew_Letter # Lo HEBREW LETTER YOD WITH HIRIQ
+FB1F..FB28 ; Hebrew_Letter # Lo [10] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER WIDE TAV
+FB2A..FB36 ; Hebrew_Letter # Lo [13] HEBREW LETTER SHIN WITH SHIN DOT..HEBREW LETTER ZAYIN WITH DAGESH
+FB38..FB3C ; Hebrew_Letter # Lo [5] HEBREW LETTER TET WITH DAGESH..HEBREW LETTER LAMED WITH DAGESH
+FB3E ; Hebrew_Letter # Lo HEBREW LETTER MEM WITH DAGESH
+FB40..FB41 ; Hebrew_Letter # Lo [2] HEBREW LETTER NUN WITH DAGESH..HEBREW LETTER SAMEKH WITH DAGESH
+FB43..FB44 ; Hebrew_Letter # Lo [2] HEBREW LETTER FINAL PE WITH DAGESH..HEBREW LETTER PE WITH DAGESH
+FB46..FB4F ; Hebrew_Letter # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW LIGATURE ALEF LAMED
+
+# Total code points: 75
+
+# ================================================
+
+000D ; CR # Cc
+
+# Total code points: 1
+
+# ================================================
+
+000A ; LF # Cc
+
+# Total code points: 1
+
+# ================================================
+
+000B..000C ; Newline # Cc [2] ..
+0085 ; Newline # Cc
+2028 ; Newline # Zl LINE SEPARATOR
+2029 ; Newline # Zp PARAGRAPH SEPARATOR
+
+# Total code points: 5
+
+# ================================================
+
+0300..036F ; Extend # Mn [112] COMBINING GRAVE ACCENT..COMBINING LATIN SMALL LETTER X
+0483..0487 ; Extend # Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE
+0488..0489 ; Extend # Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN
+0591..05BD ; Extend # Mn [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG
+05BF ; Extend # Mn HEBREW POINT RAFE
+05C1..05C2 ; Extend # Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT
+05C4..05C5 ; Extend # Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT
+05C7 ; Extend # Mn HEBREW POINT QAMATS QATAN
+0610..061A ; Extend # Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA
+064B..065F ; Extend # Mn [21] ARABIC FATHATAN..ARABIC WAVY HAMZA BELOW
+0670 ; Extend # Mn ARABIC LETTER SUPERSCRIPT ALEF
+06D6..06DC ; Extend # Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN
+06DF..06E4 ; Extend # Mn [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA
+06E7..06E8 ; Extend # Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON
+06EA..06ED ; Extend # Mn [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM
+0711 ; Extend # Mn SYRIAC LETTER SUPERSCRIPT ALAPH
+0730..074A ; Extend # Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH
+07A6..07B0 ; Extend # Mn [11] THAANA ABAFILI..THAANA SUKUN
+07EB..07F3 ; Extend # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE
+07FD ; Extend # Mn NKO DANTAYALAN
+0816..0819 ; Extend # Mn [4] SAMARITAN MARK IN..SAMARITAN MARK DAGESH
+081B..0823 ; Extend # Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A
+0825..0827 ; Extend # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U
+0829..082D ; Extend # Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA
+0859..085B ; Extend # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK
+0898..089F ; Extend # Mn [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA
+08CA..08E1 ; Extend # Mn [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA
+08E3..0902 ; Extend # Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA
+0903 ; Extend # Mc DEVANAGARI SIGN VISARGA
+093A ; Extend # Mn DEVANAGARI VOWEL SIGN OE
+093B ; Extend # Mc DEVANAGARI VOWEL SIGN OOE
+093C ; Extend # Mn DEVANAGARI SIGN NUKTA
+093E..0940 ; Extend # Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II
+0941..0948 ; Extend # Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI
+0949..094C ; Extend # Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU
+094D ; Extend # Mn DEVANAGARI SIGN VIRAMA
+094E..094F ; Extend # Mc [2] DEVANAGARI VOWEL SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW
+0951..0957 ; Extend # Mn [7] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI VOWEL SIGN UUE
+0962..0963 ; Extend # Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL
+0981 ; Extend # Mn BENGALI SIGN CANDRABINDU
+0982..0983 ; Extend # Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA
+09BC ; Extend # Mn BENGALI SIGN NUKTA
+09BE..09C0 ; Extend # Mc [3] BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN II
+09C1..09C4 ; Extend # Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR
+09C7..09C8 ; Extend # Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI
+09CB..09CC ; Extend # Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU
+09CD ; Extend # Mn BENGALI SIGN VIRAMA
+09D7 ; Extend # Mc BENGALI AU LENGTH MARK
+09E2..09E3 ; Extend # Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL
+09FE ; Extend # Mn BENGALI SANDHI MARK
+0A01..0A02 ; Extend # Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI
+0A03 ; Extend # Mc GURMUKHI SIGN VISARGA
+0A3C ; Extend # Mn GURMUKHI SIGN NUKTA
+0A3E..0A40 ; Extend # Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II
+0A41..0A42 ; Extend # Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU
+0A47..0A48 ; Extend # Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI
+0A4B..0A4D ; Extend # Mn [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA
+0A51 ; Extend # Mn GURMUKHI SIGN UDAAT
+0A70..0A71 ; Extend # Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK
+0A75 ; Extend # Mn GURMUKHI SIGN YAKASH
+0A81..0A82 ; Extend # Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA
+0A83 ; Extend # Mc GUJARATI SIGN VISARGA
+0ABC ; Extend # Mn GUJARATI SIGN NUKTA
+0ABE..0AC0 ; Extend # Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II
+0AC1..0AC5 ; Extend # Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E
+0AC7..0AC8 ; Extend # Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI
+0AC9 ; Extend # Mc GUJARATI VOWEL SIGN CANDRA O
+0ACB..0ACC ; Extend # Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU
+0ACD ; Extend # Mn GUJARATI SIGN VIRAMA
+0AE2..0AE3 ; Extend # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL
+0AFA..0AFF ; Extend # Mn [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE
+0B01 ; Extend # Mn ORIYA SIGN CANDRABINDU
+0B02..0B03 ; Extend # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA
+0B3C ; Extend # Mn ORIYA SIGN NUKTA
+0B3E ; Extend # Mc ORIYA VOWEL SIGN AA
+0B3F ; Extend # Mn ORIYA VOWEL SIGN I
+0B40 ; Extend # Mc ORIYA VOWEL SIGN II
+0B41..0B44 ; Extend # Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR
+0B47..0B48 ; Extend # Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI
+0B4B..0B4C ; Extend # Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU
+0B4D ; Extend # Mn ORIYA SIGN VIRAMA
+0B55..0B56 ; Extend # Mn [2] ORIYA SIGN OVERLINE..ORIYA AI LENGTH MARK
+0B57 ; Extend # Mc ORIYA AU LENGTH MARK
+0B62..0B63 ; Extend # Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL
+0B82 ; Extend # Mn TAMIL SIGN ANUSVARA
+0BBE..0BBF ; Extend # Mc [2] TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN I
+0BC0 ; Extend # Mn TAMIL VOWEL SIGN II
+0BC1..0BC2 ; Extend # Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU
+0BC6..0BC8 ; Extend # Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI
+0BCA..0BCC ; Extend # Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU
+0BCD ; Extend # Mn TAMIL SIGN VIRAMA
+0BD7 ; Extend # Mc TAMIL AU LENGTH MARK
+0C00 ; Extend # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE
+0C01..0C03 ; Extend # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA
+0C04 ; Extend # Mn TELUGU SIGN COMBINING ANUSVARA ABOVE
+0C3C ; Extend # Mn TELUGU SIGN NUKTA
+0C3E..0C40 ; Extend # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II
+0C41..0C44 ; Extend # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR
+0C46..0C48 ; Extend # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI
+0C4A..0C4D ; Extend # Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA
+0C55..0C56 ; Extend # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK
+0C62..0C63 ; Extend # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL
+0C81 ; Extend # Mn KANNADA SIGN CANDRABINDU
+0C82..0C83 ; Extend # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA
+0CBC ; Extend # Mn KANNADA SIGN NUKTA
+0CBE ; Extend # Mc KANNADA VOWEL SIGN AA
+0CBF ; Extend # Mn KANNADA VOWEL SIGN I
+0CC0..0CC4 ; Extend # Mc [5] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN VOCALIC RR
+0CC6 ; Extend # Mn KANNADA VOWEL SIGN E
+0CC7..0CC8 ; Extend # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI
+0CCA..0CCB ; Extend # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO
+0CCC..0CCD ; Extend # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA
+0CD5..0CD6 ; Extend # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK
+0CE2..0CE3 ; Extend # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL
+0CF3 ; Extend # Mc KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT
+0D00..0D01 ; Extend # Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU
+0D02..0D03 ; Extend # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA
+0D3B..0D3C ; Extend # Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA
+0D3E..0D40 ; Extend # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II
+0D41..0D44 ; Extend # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR
+0D46..0D48 ; Extend # Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI
+0D4A..0D4C ; Extend # Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU
+0D4D ; Extend # Mn MALAYALAM SIGN VIRAMA
+0D57 ; Extend # Mc MALAYALAM AU LENGTH MARK
+0D62..0D63 ; Extend # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL
+0D81 ; Extend # Mn SINHALA SIGN CANDRABINDU
+0D82..0D83 ; Extend # Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA
+0DCA ; Extend # Mn SINHALA SIGN AL-LAKUNA
+0DCF..0DD1 ; Extend # Mc [3] SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA
+0DD2..0DD4 ; Extend # Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA
+0DD6 ; Extend # Mn SINHALA VOWEL SIGN DIGA PAA-PILLA
+0DD8..0DDF ; Extend # Mc [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA
+0DF2..0DF3 ; Extend # Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA
+0E31 ; Extend # Mn THAI CHARACTER MAI HAN-AKAT
+0E34..0E3A ; Extend # Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU
+0E47..0E4E ; Extend # Mn [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN
+0EB1 ; Extend # Mn LAO VOWEL SIGN MAI KAN
+0EB4..0EBC ; Extend # Mn [9] LAO VOWEL SIGN I..LAO SEMIVOWEL SIGN LO
+0EC8..0ECE ; Extend # Mn [7] LAO TONE MAI EK..LAO YAMAKKAN
+0F18..0F19 ; Extend # Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS
+0F35 ; Extend # Mn TIBETAN MARK NGAS BZUNG NYI ZLA
+0F37 ; Extend # Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS
+0F39 ; Extend # Mn TIBETAN MARK TSA -PHRU
+0F3E..0F3F ; Extend # Mc [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES
+0F71..0F7E ; Extend # Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO
+0F7F ; Extend # Mc TIBETAN SIGN RNAM BCAD
+0F80..0F84 ; Extend # Mn [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA
+0F86..0F87 ; Extend # Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS
+0F8D..0F97 ; Extend # Mn [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA
+0F99..0FBC ; Extend # Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA
+0FC6 ; Extend # Mn TIBETAN SYMBOL PADMA GDAN
+102B..102C ; Extend # Mc [2] MYANMAR VOWEL SIGN TALL AA..MYANMAR VOWEL SIGN AA
+102D..1030 ; Extend # Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU
+1031 ; Extend # Mc MYANMAR VOWEL SIGN E
+1032..1037 ; Extend # Mn [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW
+1038 ; Extend # Mc MYANMAR SIGN VISARGA
+1039..103A ; Extend # Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT
+103B..103C ; Extend # Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA
+103D..103E ; Extend # Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA
+1056..1057 ; Extend # Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR
+1058..1059 ; Extend # Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL
+105E..1060 ; Extend # Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA
+1062..1064 ; Extend # Mc [3] MYANMAR VOWEL SIGN SGAW KAREN EU..MYANMAR TONE MARK SGAW KAREN KE PHO
+1067..106D ; Extend # Mc [7] MYANMAR VOWEL SIGN WESTERN PWO KAREN EU..MYANMAR SIGN WESTERN PWO KAREN TONE-5
+1071..1074 ; Extend # Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE
+1082 ; Extend # Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA
+1083..1084 ; Extend # Mc [2] MYANMAR VOWEL SIGN SHAN AA..MYANMAR VOWEL SIGN SHAN E
+1085..1086 ; Extend # Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y
+1087..108C ; Extend # Mc [6] MYANMAR SIGN SHAN TONE-2..MYANMAR SIGN SHAN COUNCIL TONE-3
+108D ; Extend # Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE
+108F ; Extend # Mc MYANMAR SIGN RUMAI PALAUNG TONE-5
+109A..109C ; Extend # Mc [3] MYANMAR SIGN KHAMTI TONE-1..MYANMAR VOWEL SIGN AITON A
+109D ; Extend # Mn MYANMAR VOWEL SIGN AITON AI
+135D..135F ; Extend # Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK
+1712..1714 ; Extend # Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA
+1715 ; Extend # Mc TAGALOG SIGN PAMUDPOD
+1732..1733 ; Extend # Mn [2] HANUNOO VOWEL SIGN I..HANUNOO VOWEL SIGN U
+1734 ; Extend # Mc HANUNOO SIGN PAMUDPOD
+1752..1753 ; Extend # Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U
+1772..1773 ; Extend # Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U
+17B4..17B5 ; Extend # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
+17B6 ; Extend # Mc KHMER VOWEL SIGN AA
+17B7..17BD ; Extend # Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA
+17BE..17C5 ; Extend # Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU
+17C6 ; Extend # Mn KHMER SIGN NIKAHIT
+17C7..17C8 ; Extend # Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU
+17C9..17D3 ; Extend # Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT
+17DD ; Extend # Mn KHMER SIGN ATTHACAN
+180B..180D ; Extend # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
+180F ; Extend # Mn MONGOLIAN FREE VARIATION SELECTOR FOUR
+1885..1886 ; Extend # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
+18A9 ; Extend # Mn MONGOLIAN LETTER ALI GALI DAGALGA
+1920..1922 ; Extend # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U
+1923..1926 ; Extend # Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU
+1927..1928 ; Extend # Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O
+1929..192B ; Extend # Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA
+1930..1931 ; Extend # Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA
+1932 ; Extend # Mn LIMBU SMALL LETTER ANUSVARA
+1933..1938 ; Extend # Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA
+1939..193B ; Extend # Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I
+1A17..1A18 ; Extend # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U
+1A19..1A1A ; Extend # Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O
+1A1B ; Extend # Mn BUGINESE VOWEL SIGN AE
+1A55 ; Extend # Mc TAI THAM CONSONANT SIGN MEDIAL RA
+1A56 ; Extend # Mn TAI THAM CONSONANT SIGN MEDIAL LA
+1A57 ; Extend # Mc TAI THAM CONSONANT SIGN LA TANG LAI
+1A58..1A5E ; Extend # Mn [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA
+1A60 ; Extend # Mn TAI THAM SIGN SAKOT
+1A61 ; Extend # Mc TAI THAM VOWEL SIGN A
+1A62 ; Extend # Mn TAI THAM VOWEL SIGN MAI SAT
+1A63..1A64 ; Extend # Mc [2] TAI THAM VOWEL SIGN AA..TAI THAM VOWEL SIGN TALL AA
+1A65..1A6C ; Extend # Mn [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW
+1A6D..1A72 ; Extend # Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI
+1A73..1A7C ; Extend # Mn [10] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN KHUEN-LUE KARAN
+1A7F ; Extend # Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT
+1AB0..1ABD ; Extend # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW
+1ABE ; Extend # Me COMBINING PARENTHESES OVERLAY
+1ABF..1ACE ; Extend # Mn [16] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER INSULAR T
+1B00..1B03 ; Extend # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG
+1B04 ; Extend # Mc BALINESE SIGN BISAH
+1B34 ; Extend # Mn BALINESE SIGN REREKAN
+1B35 ; Extend # Mc BALINESE VOWEL SIGN TEDUNG
+1B36..1B3A ; Extend # Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA
+1B3B ; Extend # Mc BALINESE VOWEL SIGN RA REPA TEDUNG
+1B3C ; Extend # Mn BALINESE VOWEL SIGN LA LENGA
+1B3D..1B41 ; Extend # Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG
+1B42 ; Extend # Mn BALINESE VOWEL SIGN PEPET
+1B43..1B44 ; Extend # Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG
+1B6B..1B73 ; Extend # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG
+1B80..1B81 ; Extend # Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR
+1B82 ; Extend # Mc SUNDANESE SIGN PANGWISAD
+1BA1 ; Extend # Mc SUNDANESE CONSONANT SIGN PAMINGKAL
+1BA2..1BA5 ; Extend # Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU
+1BA6..1BA7 ; Extend # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG
+1BA8..1BA9 ; Extend # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG
+1BAA ; Extend # Mc SUNDANESE SIGN PAMAAEH
+1BAB..1BAD ; Extend # Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA
+1BE6 ; Extend # Mn BATAK SIGN TOMPI
+1BE7 ; Extend # Mc BATAK VOWEL SIGN E
+1BE8..1BE9 ; Extend # Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE
+1BEA..1BEC ; Extend # Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O
+1BED ; Extend # Mn BATAK VOWEL SIGN KARO O
+1BEE ; Extend # Mc BATAK VOWEL SIGN U
+1BEF..1BF1 ; Extend # Mn [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H
+1BF2..1BF3 ; Extend # Mc [2] BATAK PANGOLAT..BATAK PANONGONAN
+1C24..1C2B ; Extend # Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU
+1C2C..1C33 ; Extend # Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T
+1C34..1C35 ; Extend # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG
+1C36..1C37 ; Extend # Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA
+1CD0..1CD2 ; Extend # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA
+1CD4..1CE0 ; Extend # Mn [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA
+1CE1 ; Extend # Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA
+1CE2..1CE8 ; Extend # Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL
+1CED ; Extend # Mn VEDIC SIGN TIRYAK
+1CF4 ; Extend # Mn VEDIC TONE CANDRA ABOVE
+1CF7 ; Extend # Mc VEDIC SIGN ATIKRAMA
+1CF8..1CF9 ; Extend # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE
+1DC0..1DFF ; Extend # Mn [64] COMBINING DOTTED GRAVE ACCENT..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW
+200C ; Extend # Cf ZERO WIDTH NON-JOINER
+20D0..20DC ; Extend # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE
+20DD..20E0 ; Extend # Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH
+20E1 ; Extend # Mn COMBINING LEFT RIGHT ARROW ABOVE
+20E2..20E4 ; Extend # Me [3] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE
+20E5..20F0 ; Extend # Mn [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE
+2CEF..2CF1 ; Extend # Mn [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS
+2D7F ; Extend # Mn TIFINAGH CONSONANT JOINER
+2DE0..2DFF ; Extend # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS
+302A..302D ; Extend # Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK
+302E..302F ; Extend # Mc [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK
+3099..309A ; Extend # Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+A66F ; Extend # Mn COMBINING CYRILLIC VZMET
+A670..A672 ; Extend # Me [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN
+A674..A67D ; Extend # Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK
+A69E..A69F ; Extend # Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E
+A6F0..A6F1 ; Extend # Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS
+A802 ; Extend # Mn SYLOTI NAGRI SIGN DVISVARA
+A806 ; Extend # Mn SYLOTI NAGRI SIGN HASANTA
+A80B ; Extend # Mn SYLOTI NAGRI SIGN ANUSVARA
+A823..A824 ; Extend # Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I
+A825..A826 ; Extend # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E
+A827 ; Extend # Mc SYLOTI NAGRI VOWEL SIGN OO
+A82C ; Extend # Mn SYLOTI NAGRI SIGN ALTERNATE HASANTA
+A880..A881 ; Extend # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA
+A8B4..A8C3 ; Extend # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU
+A8C4..A8C5 ; Extend # Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU
+A8E0..A8F1 ; Extend # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA
+A8FF ; Extend # Mn DEVANAGARI VOWEL SIGN AY
+A926..A92D ; Extend # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU
+A947..A951 ; Extend # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R
+A952..A953 ; Extend # Mc [2] REJANG CONSONANT SIGN H..REJANG VIRAMA
+A980..A982 ; Extend # Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR
+A983 ; Extend # Mc JAVANESE SIGN WIGNYAN
+A9B3 ; Extend # Mn JAVANESE SIGN CECAK TELU
+A9B4..A9B5 ; Extend # Mc [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG
+A9B6..A9B9 ; Extend # Mn [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT
+A9BA..A9BB ; Extend # Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE
+A9BC..A9BD ; Extend # Mn [2] JAVANESE VOWEL SIGN PEPET..JAVANESE CONSONANT SIGN KERET
+A9BE..A9C0 ; Extend # Mc [3] JAVANESE CONSONANT SIGN PENGKAL..JAVANESE PANGKON
+A9E5 ; Extend # Mn MYANMAR SIGN SHAN SAW
+AA29..AA2E ; Extend # Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE
+AA2F..AA30 ; Extend # Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI
+AA31..AA32 ; Extend # Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE
+AA33..AA34 ; Extend # Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA
+AA35..AA36 ; Extend # Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA
+AA43 ; Extend # Mn CHAM CONSONANT SIGN FINAL NG
+AA4C ; Extend # Mn CHAM CONSONANT SIGN FINAL M
+AA4D ; Extend # Mc CHAM CONSONANT SIGN FINAL H
+AA7B ; Extend # Mc MYANMAR SIGN PAO KAREN TONE
+AA7C ; Extend # Mn MYANMAR SIGN TAI LAING TONE-2
+AA7D ; Extend # Mc MYANMAR SIGN TAI LAING TONE-5
+AAB0 ; Extend # Mn TAI VIET MAI KANG
+AAB2..AAB4 ; Extend # Mn [3] TAI VIET VOWEL I..TAI VIET VOWEL U
+AAB7..AAB8 ; Extend # Mn [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA
+AABE..AABF ; Extend # Mn [2] TAI VIET VOWEL AM..TAI VIET TONE MAI EK
+AAC1 ; Extend # Mn TAI VIET TONE MAI THO
+AAEB ; Extend # Mc MEETEI MAYEK VOWEL SIGN II
+AAEC..AAED ; Extend # Mn [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI
+AAEE..AAEF ; Extend # Mc [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN AAU
+AAF5 ; Extend # Mc MEETEI MAYEK VOWEL SIGN VISARGA
+AAF6 ; Extend # Mn MEETEI MAYEK VIRAMA
+ABE3..ABE4 ; Extend # Mc [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP
+ABE5 ; Extend # Mn MEETEI MAYEK VOWEL SIGN ANAP
+ABE6..ABE7 ; Extend # Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL SIGN SOUNAP
+ABE8 ; Extend # Mn MEETEI MAYEK VOWEL SIGN UNAP
+ABE9..ABEA ; Extend # Mc [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG
+ABEC ; Extend # Mc MEETEI MAYEK LUM IYEK
+ABED ; Extend # Mn MEETEI MAYEK APUN IYEK
+FB1E ; Extend # Mn HEBREW POINT JUDEO-SPANISH VARIKA
+FE00..FE0F ; Extend # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
+FE20..FE2F ; Extend # Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF
+FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
+101FD ; Extend # Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE
+102E0 ; Extend # Mn COPTIC EPACT THOUSANDS MARK
+10376..1037A ; Extend # Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII
+10A01..10A03 ; Extend # Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R
+10A05..10A06 ; Extend # Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O
+10A0C..10A0F ; Extend # Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA
+10A38..10A3A ; Extend # Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW
+10A3F ; Extend # Mn KHAROSHTHI VIRAMA
+10AE5..10AE6 ; Extend # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW
+10D24..10D27 ; Extend # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI
+10EAB..10EAC ; Extend # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK
+10EFD..10EFF ; Extend # Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA
+10F46..10F50 ; Extend # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW
+10F82..10F85 ; Extend # Mn [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW
+11000 ; Extend # Mc BRAHMI SIGN CANDRABINDU
+11001 ; Extend # Mn BRAHMI SIGN ANUSVARA
+11002 ; Extend # Mc BRAHMI SIGN VISARGA
+11038..11046 ; Extend # Mn [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA
+11070 ; Extend # Mn BRAHMI SIGN OLD TAMIL VIRAMA
+11073..11074 ; Extend # Mn [2] BRAHMI VOWEL SIGN OLD TAMIL SHORT E..BRAHMI VOWEL SIGN OLD TAMIL SHORT O
+1107F..11081 ; Extend # Mn [3] BRAHMI NUMBER JOINER..KAITHI SIGN ANUSVARA
+11082 ; Extend # Mc KAITHI SIGN VISARGA
+110B0..110B2 ; Extend # Mc [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II
+110B3..110B6 ; Extend # Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI
+110B7..110B8 ; Extend # Mc [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU
+110B9..110BA ; Extend # Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA
+110C2 ; Extend # Mn KAITHI VOWEL SIGN VOCALIC R
+11100..11102 ; Extend # Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA
+11127..1112B ; Extend # Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU
+1112C ; Extend # Mc CHAKMA VOWEL SIGN E
+1112D..11134 ; Extend # Mn [8] CHAKMA VOWEL SIGN AI..CHAKMA MAAYYAA
+11145..11146 ; Extend # Mc [2] CHAKMA VOWEL SIGN AA..CHAKMA VOWEL SIGN EI
+11173 ; Extend # Mn MAHAJANI SIGN NUKTA
+11180..11181 ; Extend # Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA
+11182 ; Extend # Mc SHARADA SIGN VISARGA
+111B3..111B5 ; Extend # Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II
+111B6..111BE ; Extend # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O
+111BF..111C0 ; Extend # Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA
+111C9..111CC ; Extend # Mn [4] SHARADA SANDHI MARK..SHARADA EXTRA SHORT VOWEL MARK
+111CE ; Extend # Mc SHARADA VOWEL SIGN PRISHTHAMATRA E
+111CF ; Extend # Mn SHARADA SIGN INVERTED CANDRABINDU
+1122C..1122E ; Extend # Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II
+1122F..11231 ; Extend # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI
+11232..11233 ; Extend # Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU
+11234 ; Extend # Mn KHOJKI SIGN ANUSVARA
+11235 ; Extend # Mc KHOJKI SIGN VIRAMA
+11236..11237 ; Extend # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA
+1123E ; Extend # Mn KHOJKI SIGN SUKUN
+11241 ; Extend # Mn KHOJKI VOWEL SIGN VOCALIC R
+112DF ; Extend # Mn KHUDAWADI SIGN ANUSVARA
+112E0..112E2 ; Extend # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II
+112E3..112EA ; Extend # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA
+11300..11301 ; Extend # Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU
+11302..11303 ; Extend # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA
+1133B..1133C ; Extend # Mn [2] COMBINING BINDU BELOW..GRANTHA SIGN NUKTA
+1133E..1133F ; Extend # Mc [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I
+11340 ; Extend # Mn GRANTHA VOWEL SIGN II
+11341..11344 ; Extend # Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR
+11347..11348 ; Extend # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI
+1134B..1134D ; Extend # Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA
+11357 ; Extend # Mc GRANTHA AU LENGTH MARK
+11362..11363 ; Extend # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL
+11366..1136C ; Extend # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX
+11370..11374 ; Extend # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA
+11435..11437 ; Extend # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II
+11438..1143F ; Extend # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI
+11440..11441 ; Extend # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU
+11442..11444 ; Extend # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA
+11445 ; Extend # Mc NEWA SIGN VISARGA
+11446 ; Extend # Mn NEWA SIGN NUKTA
+1145E ; Extend # Mn NEWA SANDHI MARK
+114B0..114B2 ; Extend # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II
+114B3..114B8 ; Extend # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL
+114B9 ; Extend # Mc TIRHUTA VOWEL SIGN E
+114BA ; Extend # Mn TIRHUTA VOWEL SIGN SHORT E
+114BB..114BE ; Extend # Mc [4] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN AU
+114BF..114C0 ; Extend # Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA
+114C1 ; Extend # Mc TIRHUTA SIGN VISARGA
+114C2..114C3 ; Extend # Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA
+115AF..115B1 ; Extend # Mc [3] SIDDHAM VOWEL SIGN AA..SIDDHAM VOWEL SIGN II
+115B2..115B5 ; Extend # Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR
+115B8..115BB ; Extend # Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU
+115BC..115BD ; Extend # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA
+115BE ; Extend # Mc SIDDHAM SIGN VISARGA
+115BF..115C0 ; Extend # Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA
+115DC..115DD ; Extend # Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU
+11630..11632 ; Extend # Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II
+11633..1163A ; Extend # Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI
+1163B..1163C ; Extend # Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU
+1163D ; Extend # Mn MODI SIGN ANUSVARA
+1163E ; Extend # Mc MODI SIGN VISARGA
+1163F..11640 ; Extend # Mn [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA
+116AB ; Extend # Mn TAKRI SIGN ANUSVARA
+116AC ; Extend # Mc TAKRI SIGN VISARGA
+116AD ; Extend # Mn TAKRI VOWEL SIGN AA
+116AE..116AF ; Extend # Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II
+116B0..116B5 ; Extend # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU
+116B6 ; Extend # Mc TAKRI SIGN VIRAMA
+116B7 ; Extend # Mn TAKRI SIGN NUKTA
+1171D..1171F ; Extend # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA
+11720..11721 ; Extend # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA
+11722..11725 ; Extend # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU
+11726 ; Extend # Mc AHOM VOWEL SIGN E
+11727..1172B ; Extend # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER
+1182C..1182E ; Extend # Mc [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II
+1182F..11837 ; Extend # Mn [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA
+11838 ; Extend # Mc DOGRA SIGN VISARGA
+11839..1183A ; Extend # Mn [2] DOGRA SIGN VIRAMA..DOGRA SIGN NUKTA
+11930..11935 ; Extend # Mc [6] DIVES AKURU VOWEL SIGN AA..DIVES AKURU VOWEL SIGN E
+11937..11938 ; Extend # Mc [2] DIVES AKURU VOWEL SIGN AI..DIVES AKURU VOWEL SIGN O
+1193B..1193C ; Extend # Mn [2] DIVES AKURU SIGN ANUSVARA..DIVES AKURU SIGN CANDRABINDU
+1193D ; Extend # Mc DIVES AKURU SIGN HALANTA
+1193E ; Extend # Mn DIVES AKURU VIRAMA
+11940 ; Extend # Mc DIVES AKURU MEDIAL YA
+11942 ; Extend # Mc DIVES AKURU MEDIAL RA
+11943 ; Extend # Mn DIVES AKURU SIGN NUKTA
+119D1..119D3 ; Extend # Mc [3] NANDINAGARI VOWEL SIGN AA..NANDINAGARI VOWEL SIGN II
+119D4..119D7 ; Extend # Mn [4] NANDINAGARI VOWEL SIGN U..NANDINAGARI VOWEL SIGN VOCALIC RR
+119DA..119DB ; Extend # Mn [2] NANDINAGARI VOWEL SIGN E..NANDINAGARI VOWEL SIGN AI
+119DC..119DF ; Extend # Mc [4] NANDINAGARI VOWEL SIGN O..NANDINAGARI SIGN VISARGA
+119E0 ; Extend # Mn NANDINAGARI SIGN VIRAMA
+119E4 ; Extend # Mc NANDINAGARI VOWEL SIGN PRISHTHAMATRA E
+11A01..11A0A ; Extend # Mn [10] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL LENGTH MARK
+11A33..11A38 ; Extend # Mn [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA
+11A39 ; Extend # Mc ZANABAZAR SQUARE SIGN VISARGA
+11A3B..11A3E ; Extend # Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA
+11A47 ; Extend # Mn ZANABAZAR SQUARE SUBJOINER
+11A51..11A56 ; Extend # Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE
+11A57..11A58 ; Extend # Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU
+11A59..11A5B ; Extend # Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK
+11A8A..11A96 ; Extend # Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA
+11A97 ; Extend # Mc SOYOMBO SIGN VISARGA
+11A98..11A99 ; Extend # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER
+11C2F ; Extend # Mc BHAIKSUKI VOWEL SIGN AA
+11C30..11C36 ; Extend # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L
+11C38..11C3D ; Extend # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA
+11C3E ; Extend # Mc BHAIKSUKI SIGN VISARGA
+11C3F ; Extend # Mn BHAIKSUKI SIGN VIRAMA
+11C92..11CA7 ; Extend # Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA
+11CA9 ; Extend # Mc MARCHEN SUBJOINED LETTER YA
+11CAA..11CB0 ; Extend # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA
+11CB1 ; Extend # Mc MARCHEN VOWEL SIGN I
+11CB2..11CB3 ; Extend # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E
+11CB4 ; Extend # Mc MARCHEN VOWEL SIGN O
+11CB5..11CB6 ; Extend # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU
+11D31..11D36 ; Extend # Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R
+11D3A ; Extend # Mn MASARAM GONDI VOWEL SIGN E
+11D3C..11D3D ; Extend # Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O
+11D3F..11D45 ; Extend # Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA
+11D47 ; Extend # Mn MASARAM GONDI RA-KARA
+11D8A..11D8E ; Extend # Mc [5] GUNJALA GONDI VOWEL SIGN AA..GUNJALA GONDI VOWEL SIGN UU
+11D90..11D91 ; Extend # Mn [2] GUNJALA GONDI VOWEL SIGN EE..GUNJALA GONDI VOWEL SIGN AI
+11D93..11D94 ; Extend # Mc [2] GUNJALA GONDI VOWEL SIGN OO..GUNJALA GONDI VOWEL SIGN AU
+11D95 ; Extend # Mn GUNJALA GONDI SIGN ANUSVARA
+11D96 ; Extend # Mc GUNJALA GONDI SIGN VISARGA
+11D97 ; Extend # Mn GUNJALA GONDI VIRAMA
+11EF3..11EF4 ; Extend # Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U
+11EF5..11EF6 ; Extend # Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O
+11F00..11F01 ; Extend # Mn [2] KAWI SIGN CANDRABINDU..KAWI SIGN ANUSVARA
+11F03 ; Extend # Mc KAWI SIGN VISARGA
+11F34..11F35 ; Extend # Mc [2] KAWI VOWEL SIGN AA..KAWI VOWEL SIGN ALTERNATE AA
+11F36..11F3A ; Extend # Mn [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R
+11F3E..11F3F ; Extend # Mc [2] KAWI VOWEL SIGN E..KAWI VOWEL SIGN AI
+11F40 ; Extend # Mn KAWI VOWEL SIGN EU
+11F41 ; Extend # Mc KAWI SIGN KILLER
+11F42 ; Extend # Mn KAWI CONJOINER
+13440 ; Extend # Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY
+13447..13455 ; Extend # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED
+16AF0..16AF4 ; Extend # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE
+16B30..16B36 ; Extend # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
+16F4F ; Extend # Mn MIAO SIGN CONSONANT MODIFIER BAR
+16F51..16F87 ; Extend # Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI
+16F8F..16F92 ; Extend # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW
+16FE4 ; Extend # Mn KHITAN SMALL SCRIPT FILLER
+16FF0..16FF1 ; Extend # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY
+1BC9D..1BC9E ; Extend # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK
+1CF00..1CF2D ; Extend # Mn [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT
+1CF30..1CF46 ; Extend # Mn [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG
+1D165..1D166 ; Extend # Mc [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM
+1D167..1D169 ; Extend # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3
+1D16D..1D172 ; Extend # Mc [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5
+1D17B..1D182 ; Extend # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE
+1D185..1D18B ; Extend # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE
+1D1AA..1D1AD ; Extend # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO
+1D242..1D244 ; Extend # Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME
+1DA00..1DA36 ; Extend # Mn [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN
+1DA3B..1DA6C ; Extend # Mn [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT
+1DA75 ; Extend # Mn SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS
+1DA84 ; Extend # Mn SIGNWRITING LOCATION HEAD NECK
+1DA9B..1DA9F ; Extend # Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6
+1DAA1..1DAAF ; Extend # Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16
+1E000..1E006 ; Extend # Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE
+1E008..1E018 ; Extend # Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU
+1E01B..1E021 ; Extend # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI
+1E023..1E024 ; Extend # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS
+1E026..1E02A ; Extend # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA
+1E08F ; Extend # Mn COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+1E130..1E136 ; Extend # Mn [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D
+1E2AE ; Extend # Mn TOTO SIGN RISING TONE
+1E2EC..1E2EF ; Extend # Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI
+1E4EC..1E4EF ; Extend # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH
+1E8D0..1E8D6 ; Extend # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS
+1E944..1E94A ; Extend # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA
+1F3FB..1F3FF ; Extend # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6
+E0020..E007F ; Extend # Cf [96] TAG SPACE..CANCEL TAG
+E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
+
+# Total code points: 2554
+
+# ================================================
+
+1F1E6..1F1FF ; Regional_Indicator # So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z
+
+# Total code points: 26
+
+# ================================================
+
+00AD ; Format # Cf SOFT HYPHEN
+061C ; Format # Cf ARABIC LETTER MARK
+180E ; Format # Cf MONGOLIAN VOWEL SEPARATOR
+200E..200F ; Format # Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK
+202A..202E ; Format # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
+2060..2064 ; Format # Cf [5] WORD JOINER..INVISIBLE PLUS
+2066..206F ; Format # Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES
+FEFF ; Format # Cf ZERO WIDTH NO-BREAK SPACE
+FFF9..FFFB ; Format # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR
+13430..1343F ; Format # Cf [16] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE
+1BCA0..1BCA3 ; Format # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP
+1D173..1D17A ; Format # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE
+E0001 ; Format # Cf LANGUAGE TAG
+
+# Total code points: 58
+
+# ================================================
+
+3031..3035 ; Katakana # Lm [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF
+309B..309C ; Katakana # Sk [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+30A0 ; Katakana # Pd KATAKANA-HIRAGANA DOUBLE HYPHEN
+30A1..30FA ; Katakana # Lo [90] KATAKANA LETTER SMALL A..KATAKANA LETTER VO
+30FC..30FE ; Katakana # Lm [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK
+30FF ; Katakana # Lo KATAKANA DIGRAPH KOTO
+31F0..31FF ; Katakana # Lo [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO
+32D0..32FE ; Katakana # So [47] CIRCLED KATAKANA A..CIRCLED KATAKANA WO
+3300..3357 ; Katakana # So [88] SQUARE APAATO..SQUARE WATTO
+FF66..FF6F ; Katakana # Lo [10] HALFWIDTH KATAKANA LETTER WO..HALFWIDTH KATAKANA LETTER SMALL TU
+FF70 ; Katakana # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
+FF71..FF9D ; Katakana # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N
+1AFF0..1AFF3 ; Katakana # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5
+1AFF5..1AFFB ; Katakana # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5
+1AFFD..1AFFE ; Katakana # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8
+1B000 ; Katakana # Lo KATAKANA LETTER ARCHAIC E
+1B120..1B122 ; Katakana # Lo [3] KATAKANA LETTER ARCHAIC YI..KATAKANA LETTER ARCHAIC WU
+1B155 ; Katakana # Lo KATAKANA LETTER SMALL KO
+1B164..1B167 ; Katakana # Lo [4] KATAKANA LETTER SMALL WI..KATAKANA LETTER SMALL N
+
+# Total code points: 331
+
+# ================================================
+
+0041..005A ; ALetter # L& [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z
+0061..007A ; ALetter # L& [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z
+00AA ; ALetter # Lo FEMININE ORDINAL INDICATOR
+00B5 ; ALetter # L& MICRO SIGN
+00BA ; ALetter # Lo MASCULINE ORDINAL INDICATOR
+00C0..00D6 ; ALetter # L& [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS
+00D8..00F6 ; ALetter # L& [31] LATIN CAPITAL LETTER O WITH STROKE..LATIN SMALL LETTER O WITH DIAERESIS
+00F8..01BA ; ALetter # L& [195] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER EZH WITH TAIL
+01BB ; ALetter # Lo LATIN LETTER TWO WITH STROKE
+01BC..01BF ; ALetter # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN
+01C0..01C3 ; ALetter # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK
+01C4..0293 ; ALetter # L& [208] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER EZH WITH CURL
+0294 ; ALetter # Lo LATIN LETTER GLOTTAL STOP
+0295..02AF ; ALetter # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL
+02B0..02C1 ; ALetter # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP
+02C2..02C5 ; ALetter # Sk [4] MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER DOWN ARROWHEAD
+02C6..02D1 ; ALetter # Lm [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON
+02D2..02D7 ; ALetter # Sk [6] MODIFIER LETTER CENTRED RIGHT HALF RING..MODIFIER LETTER MINUS SIGN
+02DE..02DF ; ALetter # Sk [2] MODIFIER LETTER RHOTIC HOOK..MODIFIER LETTER CROSS ACCENT
+02E0..02E4 ; ALetter # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP
+02E5..02EB ; ALetter # Sk [7] MODIFIER LETTER EXTRA-HIGH TONE BAR..MODIFIER LETTER YANG DEPARTING TONE MARK
+02EC ; ALetter # Lm MODIFIER LETTER VOICING
+02ED ; ALetter # Sk MODIFIER LETTER UNASPIRATED
+02EE ; ALetter # Lm MODIFIER LETTER DOUBLE APOSTROPHE
+02EF..02FF ; ALetter # Sk [17] MODIFIER LETTER LOW DOWN ARROWHEAD..MODIFIER LETTER LOW LEFT ARROW
+0370..0373 ; ALetter # L& [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI
+0374 ; ALetter # Lm GREEK NUMERAL SIGN
+0376..0377 ; ALetter # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA
+037A ; ALetter # Lm GREEK YPOGEGRAMMENI
+037B..037D ; ALetter # L& [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
+037F ; ALetter # L& GREEK CAPITAL LETTER YOT
+0386 ; ALetter # L& GREEK CAPITAL LETTER ALPHA WITH TONOS
+0388..038A ; ALetter # L& [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS
+038C ; ALetter # L& GREEK CAPITAL LETTER OMICRON WITH TONOS
+038E..03A1 ; ALetter # L& [20] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK CAPITAL LETTER RHO
+03A3..03F5 ; ALetter # L& [83] GREEK CAPITAL LETTER SIGMA..GREEK LUNATE EPSILON SYMBOL
+03F7..0481 ; ALetter # L& [139] GREEK CAPITAL LETTER SHO..CYRILLIC SMALL LETTER KOPPA
+048A..052F ; ALetter # L& [166] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER EL WITH DESCENDER
+0531..0556 ; ALetter # L& [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH
+0559 ; ALetter # Lm ARMENIAN MODIFIER LETTER LEFT HALF RING
+055A..055C ; ALetter # Po [3] ARMENIAN APOSTROPHE..ARMENIAN EXCLAMATION MARK
+055E ; ALetter # Po ARMENIAN QUESTION MARK
+0560..0588 ; ALetter # L& [41] ARMENIAN SMALL LETTER TURNED AYB..ARMENIAN SMALL LETTER YI WITH STROKE
+058A ; ALetter # Pd ARMENIAN HYPHEN
+05F3 ; ALetter # Po HEBREW PUNCTUATION GERESH
+0620..063F ; ALetter # Lo [32] ARABIC LETTER KASHMIRI YEH..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE
+0640 ; ALetter # Lm ARABIC TATWEEL
+0641..064A ; ALetter # Lo [10] ARABIC LETTER FEH..ARABIC LETTER YEH
+066E..066F ; ALetter # Lo [2] ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF
+0671..06D3 ; ALetter # Lo [99] ARABIC LETTER ALEF WASLA..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE
+06D5 ; ALetter # Lo ARABIC LETTER AE
+06E5..06E6 ; ALetter # Lm [2] ARABIC SMALL WAW..ARABIC SMALL YEH
+06EE..06EF ; ALetter # Lo [2] ARABIC LETTER DAL WITH INVERTED V..ARABIC LETTER REH WITH INVERTED V
+06FA..06FC ; ALetter # Lo [3] ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC LETTER GHAIN WITH DOT BELOW
+06FF ; ALetter # Lo ARABIC LETTER HEH WITH INVERTED V
+070F ; ALetter # Cf SYRIAC ABBREVIATION MARK
+0710 ; ALetter # Lo SYRIAC LETTER ALAPH
+0712..072F ; ALetter # Lo [30] SYRIAC LETTER BETH..SYRIAC LETTER PERSIAN DHALATH
+074D..07A5 ; ALetter # Lo [89] SYRIAC LETTER SOGDIAN ZHAIN..THAANA LETTER WAAVU
+07B1 ; ALetter # Lo THAANA LETTER NAA
+07CA..07EA ; ALetter # Lo [33] NKO LETTER A..NKO LETTER JONA RA
+07F4..07F5 ; ALetter # Lm [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE
+07FA ; ALetter # Lm NKO LAJANYALAN
+0800..0815 ; ALetter # Lo [22] SAMARITAN LETTER ALAF..SAMARITAN LETTER TAAF
+081A ; ALetter # Lm SAMARITAN MODIFIER LETTER EPENTHETIC YUT
+0824 ; ALetter # Lm SAMARITAN MODIFIER LETTER SHORT A
+0828 ; ALetter # Lm SAMARITAN MODIFIER LETTER I
+0840..0858 ; ALetter # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN
+0860..086A ; ALetter # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA
+0870..0887 ; ALetter # Lo [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT
+0889..088E ; ALetter # Lo [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL
+08A0..08C8 ; ALetter # Lo [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF
+08C9 ; ALetter # Lm ARABIC SMALL FARSI YEH
+0904..0939 ; ALetter # Lo [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA
+093D ; ALetter # Lo DEVANAGARI SIGN AVAGRAHA
+0950 ; ALetter # Lo DEVANAGARI OM
+0958..0961 ; ALetter # Lo [10] DEVANAGARI LETTER QA..DEVANAGARI LETTER VOCALIC LL
+0971 ; ALetter # Lm DEVANAGARI SIGN HIGH SPACING DOT
+0972..0980 ; ALetter # Lo [15] DEVANAGARI LETTER CANDRA A..BENGALI ANJI
+0985..098C ; ALetter # Lo [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L
+098F..0990 ; ALetter # Lo [2] BENGALI LETTER E..BENGALI LETTER AI
+0993..09A8 ; ALetter # Lo [22] BENGALI LETTER O..BENGALI LETTER NA
+09AA..09B0 ; ALetter # Lo [7] BENGALI LETTER PA..BENGALI LETTER RA
+09B2 ; ALetter # Lo BENGALI LETTER LA
+09B6..09B9 ; ALetter # Lo [4] BENGALI LETTER SHA..BENGALI LETTER HA
+09BD ; ALetter # Lo BENGALI SIGN AVAGRAHA
+09CE ; ALetter # Lo BENGALI LETTER KHANDA TA
+09DC..09DD ; ALetter # Lo [2] BENGALI LETTER RRA..BENGALI LETTER RHA
+09DF..09E1 ; ALetter # Lo [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL
+09F0..09F1 ; ALetter # Lo [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL
+09FC ; ALetter # Lo BENGALI LETTER VEDIC ANUSVARA
+0A05..0A0A ; ALetter # Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU
+0A0F..0A10 ; ALetter # Lo [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI
+0A13..0A28 ; ALetter # Lo [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA
+0A2A..0A30 ; ALetter # Lo [7] GURMUKHI LETTER PA..GURMUKHI LETTER RA
+0A32..0A33 ; ALetter # Lo [2] GURMUKHI LETTER LA..GURMUKHI LETTER LLA
+0A35..0A36 ; ALetter # Lo [2] GURMUKHI LETTER VA..GURMUKHI LETTER SHA
+0A38..0A39 ; ALetter # Lo [2] GURMUKHI LETTER SA..GURMUKHI LETTER HA
+0A59..0A5C ; ALetter # Lo [4] GURMUKHI LETTER KHHA..GURMUKHI LETTER RRA
+0A5E ; ALetter # Lo GURMUKHI LETTER FA
+0A72..0A74 ; ALetter # Lo [3] GURMUKHI IRI..GURMUKHI EK ONKAR
+0A85..0A8D ; ALetter # Lo [9] GUJARATI LETTER A..GUJARATI VOWEL CANDRA E
+0A8F..0A91 ; ALetter # Lo [3] GUJARATI LETTER E..GUJARATI VOWEL CANDRA O
+0A93..0AA8 ; ALetter # Lo [22] GUJARATI LETTER O..GUJARATI LETTER NA
+0AAA..0AB0 ; ALetter # Lo [7] GUJARATI LETTER PA..GUJARATI LETTER RA
+0AB2..0AB3 ; ALetter # Lo [2] GUJARATI LETTER LA..GUJARATI LETTER LLA
+0AB5..0AB9 ; ALetter # Lo [5] GUJARATI LETTER VA..GUJARATI LETTER HA
+0ABD ; ALetter # Lo GUJARATI SIGN AVAGRAHA
+0AD0 ; ALetter # Lo GUJARATI OM
+0AE0..0AE1 ; ALetter # Lo [2] GUJARATI LETTER VOCALIC RR..GUJARATI LETTER VOCALIC LL
+0AF9 ; ALetter # Lo GUJARATI LETTER ZHA
+0B05..0B0C ; ALetter # Lo [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L
+0B0F..0B10 ; ALetter # Lo [2] ORIYA LETTER E..ORIYA LETTER AI
+0B13..0B28 ; ALetter # Lo [22] ORIYA LETTER O..ORIYA LETTER NA
+0B2A..0B30 ; ALetter # Lo [7] ORIYA LETTER PA..ORIYA LETTER RA
+0B32..0B33 ; ALetter # Lo [2] ORIYA LETTER LA..ORIYA LETTER LLA
+0B35..0B39 ; ALetter # Lo [5] ORIYA LETTER VA..ORIYA LETTER HA
+0B3D ; ALetter # Lo ORIYA SIGN AVAGRAHA
+0B5C..0B5D ; ALetter # Lo [2] ORIYA LETTER RRA..ORIYA LETTER RHA
+0B5F..0B61 ; ALetter # Lo [3] ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL
+0B71 ; ALetter # Lo ORIYA LETTER WA
+0B83 ; ALetter # Lo TAMIL SIGN VISARGA
+0B85..0B8A ; ALetter # Lo [6] TAMIL LETTER A..TAMIL LETTER UU
+0B8E..0B90 ; ALetter # Lo [3] TAMIL LETTER E..TAMIL LETTER AI
+0B92..0B95 ; ALetter # Lo [4] TAMIL LETTER O..TAMIL LETTER KA
+0B99..0B9A ; ALetter # Lo [2] TAMIL LETTER NGA..TAMIL LETTER CA
+0B9C ; ALetter # Lo TAMIL LETTER JA
+0B9E..0B9F ; ALetter # Lo [2] TAMIL LETTER NYA..TAMIL LETTER TTA
+0BA3..0BA4 ; ALetter # Lo [2] TAMIL LETTER NNA..TAMIL LETTER TA
+0BA8..0BAA ; ALetter # Lo [3] TAMIL LETTER NA..TAMIL LETTER PA
+0BAE..0BB9 ; ALetter # Lo [12] TAMIL LETTER MA..TAMIL LETTER HA
+0BD0 ; ALetter # Lo TAMIL OM
+0C05..0C0C ; ALetter # Lo [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L
+0C0E..0C10 ; ALetter # Lo [3] TELUGU LETTER E..TELUGU LETTER AI
+0C12..0C28 ; ALetter # Lo [23] TELUGU LETTER O..TELUGU LETTER NA
+0C2A..0C39 ; ALetter # Lo [16] TELUGU LETTER PA..TELUGU LETTER HA
+0C3D ; ALetter # Lo TELUGU SIGN AVAGRAHA
+0C58..0C5A ; ALetter # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA
+0C5D ; ALetter # Lo TELUGU LETTER NAKAARA POLLU
+0C60..0C61 ; ALetter # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL
+0C80 ; ALetter # Lo KANNADA SIGN SPACING CANDRABINDU
+0C85..0C8C ; ALetter # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L
+0C8E..0C90 ; ALetter # Lo [3] KANNADA LETTER E..KANNADA LETTER AI
+0C92..0CA8 ; ALetter # Lo [23] KANNADA LETTER O..KANNADA LETTER NA
+0CAA..0CB3 ; ALetter # Lo [10] KANNADA LETTER PA..KANNADA LETTER LLA
+0CB5..0CB9 ; ALetter # Lo [5] KANNADA LETTER VA..KANNADA LETTER HA
+0CBD ; ALetter # Lo KANNADA SIGN AVAGRAHA
+0CDD..0CDE ; ALetter # Lo [2] KANNADA LETTER NAKAARA POLLU..KANNADA LETTER FA
+0CE0..0CE1 ; ALetter # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL
+0CF1..0CF2 ; ALetter # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA
+0D04..0D0C ; ALetter # Lo [9] MALAYALAM LETTER VEDIC ANUSVARA..MALAYALAM LETTER VOCALIC L
+0D0E..0D10 ; ALetter # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI
+0D12..0D3A ; ALetter # Lo [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA
+0D3D ; ALetter # Lo MALAYALAM SIGN AVAGRAHA
+0D4E ; ALetter # Lo MALAYALAM LETTER DOT REPH
+0D54..0D56 ; ALetter # Lo [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL
+0D5F..0D61 ; ALetter # Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL
+0D7A..0D7F ; ALetter # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K
+0D85..0D96 ; ALetter # Lo [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA
+0D9A..0DB1 ; ALetter # Lo [24] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA
+0DB3..0DBB ; ALetter # Lo [9] SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA
+0DBD ; ALetter # Lo SINHALA LETTER DANTAJA LAYANNA
+0DC0..0DC6 ; ALetter # Lo [7] SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA
+0F00 ; ALetter # Lo TIBETAN SYLLABLE OM
+0F40..0F47 ; ALetter # Lo [8] TIBETAN LETTER KA..TIBETAN LETTER JA
+0F49..0F6C ; ALetter # Lo [36] TIBETAN LETTER NYA..TIBETAN LETTER RRA
+0F88..0F8C ; ALetter # Lo [5] TIBETAN SIGN LCE TSA CAN..TIBETAN SIGN INVERTED MCHU CAN
+10A0..10C5 ; ALetter # L& [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE
+10C7 ; ALetter # L& GEORGIAN CAPITAL LETTER YN
+10CD ; ALetter # L& GEORGIAN CAPITAL LETTER AEN
+10D0..10FA ; ALetter # L& [43] GEORGIAN LETTER AN..GEORGIAN LETTER AIN
+10FC ; ALetter # Lm MODIFIER LETTER GEORGIAN NAR
+10FD..10FF ; ALetter # L& [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN
+1100..1248 ; ALetter # Lo [329] HANGUL CHOSEONG KIYEOK..ETHIOPIC SYLLABLE QWA
+124A..124D ; ALetter # Lo [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE
+1250..1256 ; ALetter # Lo [7] ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO
+1258 ; ALetter # Lo ETHIOPIC SYLLABLE QHWA
+125A..125D ; ALetter # Lo [4] ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE
+1260..1288 ; ALetter # Lo [41] ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XWA
+128A..128D ; ALetter # Lo [4] ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE
+1290..12B0 ; ALetter # Lo [33] ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KWA
+12B2..12B5 ; ALetter # Lo [4] ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE
+12B8..12BE ; ALetter # Lo [7] ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO
+12C0 ; ALetter # Lo ETHIOPIC SYLLABLE KXWA
+12C2..12C5 ; ALetter # Lo [4] ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE
+12C8..12D6 ; ALetter # Lo [15] ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE PHARYNGEAL O
+12D8..1310 ; ALetter # Lo [57] ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE GWA
+1312..1315 ; ALetter # Lo [4] ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE
+1318..135A ; ALetter # Lo [67] ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE FYA
+1380..138F ; ALetter # Lo [16] ETHIOPIC SYLLABLE SEBATBEIT MWA..ETHIOPIC SYLLABLE PWE
+13A0..13F5 ; ALetter # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV
+13F8..13FD ; ALetter # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV
+1401..166C ; ALetter # Lo [620] CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA
+166F..167F ; ALetter # Lo [17] CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS BLACKFOOT W
+1681..169A ; ALetter # Lo [26] OGHAM LETTER BEITH..OGHAM LETTER PEITH
+16A0..16EA ; ALetter # Lo [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X
+16EE..16F0 ; ALetter # Nl [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL
+16F1..16F8 ; ALetter # Lo [8] RUNIC LETTER K..RUNIC LETTER FRANKS CASKET AESC
+1700..1711 ; ALetter # Lo [18] TAGALOG LETTER A..TAGALOG LETTER HA
+171F..1731 ; ALetter # Lo [19] TAGALOG LETTER ARCHAIC RA..HANUNOO LETTER HA
+1740..1751 ; ALetter # Lo [18] BUHID LETTER A..BUHID LETTER HA
+1760..176C ; ALetter # Lo [13] TAGBANWA LETTER A..TAGBANWA LETTER YA
+176E..1770 ; ALetter # Lo [3] TAGBANWA LETTER LA..TAGBANWA LETTER SA
+1820..1842 ; ALetter # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI
+1843 ; ALetter # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN
+1844..1878 ; ALetter # Lo [53] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER CHA WITH TWO DOTS
+1880..1884 ; ALetter # Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA
+1887..18A8 ; ALetter # Lo [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA
+18AA ; ALetter # Lo MONGOLIAN LETTER MANCHU ALI GALI LHA
+18B0..18F5 ; ALetter # Lo [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S
+1900..191E ; ALetter # Lo [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA
+1A00..1A16 ; ALetter # Lo [23] BUGINESE LETTER KA..BUGINESE LETTER HA
+1B05..1B33 ; ALetter # Lo [47] BALINESE LETTER AKARA..BALINESE LETTER HA
+1B45..1B4C ; ALetter # Lo [8] BALINESE LETTER KAF SASAK..BALINESE LETTER ARCHAIC JNYA
+1B83..1BA0 ; ALetter # Lo [30] SUNDANESE LETTER A..SUNDANESE LETTER HA
+1BAE..1BAF ; ALetter # Lo [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA
+1BBA..1BE5 ; ALetter # Lo [44] SUNDANESE AVAGRAHA..BATAK LETTER U
+1C00..1C23 ; ALetter # Lo [36] LEPCHA LETTER KA..LEPCHA LETTER A
+1C4D..1C4F ; ALetter # Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA
+1C5A..1C77 ; ALetter # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH
+1C78..1C7D ; ALetter # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD
+1C80..1C88 ; ALetter # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK
+1C90..1CBA ; ALetter # L& [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN
+1CBD..1CBF ; ALetter # L& [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN
+1CE9..1CEC ; ALetter # Lo [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL
+1CEE..1CF3 ; ALetter # Lo [6] VEDIC SIGN HEXIFORM LONG ANUSVARA..VEDIC SIGN ROTATED ARDHAVISARGA
+1CF5..1CF6 ; ALetter # Lo [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA
+1CFA ; ALetter # Lo VEDIC SIGN DOUBLE ANUSVARA ANTARGOMUKHA
+1D00..1D2B ; ALetter # L& [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL
+1D2C..1D6A ; ALetter # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI
+1D6B..1D77 ; ALetter # L& [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G
+1D78 ; ALetter # Lm MODIFIER LETTER CYRILLIC EN
+1D79..1D9A ; ALetter # L& [34] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK
+1D9B..1DBF ; ALetter # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA
+1E00..1F15 ; ALetter # L& [278] LATIN CAPITAL LETTER A WITH RING BELOW..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA
+1F18..1F1D ; ALetter # L& [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+1F20..1F45 ; ALetter # L& [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA
+1F48..1F4D ; ALetter # L& [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+1F50..1F57 ; ALetter # L& [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F59 ; ALetter # L& GREEK CAPITAL LETTER UPSILON WITH DASIA
+1F5B ; ALetter # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+1F5D ; ALetter # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+1F5F..1F7D ; ALetter # L& [31] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER OMEGA WITH OXIA
+1F80..1FB4 ; ALetter # L& [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+1FB6..1FBC ; ALetter # L& [7] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FBE ; ALetter # L& GREEK PROSGEGRAMMENI
+1FC2..1FC4 ; ALetter # L& [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+1FC6..1FCC ; ALetter # L& [7] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FD0..1FD3 ; ALetter # L& [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+1FD6..1FDB ; ALetter # L& [6] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH OXIA
+1FE0..1FEC ; ALetter # L& [13] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA
+1FF2..1FF4 ; ALetter # L& [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+1FF6..1FFC ; ALetter # L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+2071 ; ALetter # Lm SUPERSCRIPT LATIN SMALL LETTER I
+207F ; ALetter # Lm SUPERSCRIPT LATIN SMALL LETTER N
+2090..209C ; ALetter # Lm [13] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER T
+2102 ; ALetter # L& DOUBLE-STRUCK CAPITAL C
+2107 ; ALetter # L& EULER CONSTANT
+210A..2113 ; ALetter # L& [10] SCRIPT SMALL G..SCRIPT SMALL L
+2115 ; ALetter # L& DOUBLE-STRUCK CAPITAL N
+2119..211D ; ALetter # L& [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R
+2124 ; ALetter # L& DOUBLE-STRUCK CAPITAL Z
+2126 ; ALetter # L& OHM SIGN
+2128 ; ALetter # L& BLACK-LETTER CAPITAL Z
+212A..212D ; ALetter # L& [4] KELVIN SIGN..BLACK-LETTER CAPITAL C
+212F..2134 ; ALetter # L& [6] SCRIPT SMALL E..SCRIPT SMALL O
+2135..2138 ; ALetter # Lo [4] ALEF SYMBOL..DALET SYMBOL
+2139 ; ALetter # L& INFORMATION SOURCE
+213C..213F ; ALetter # L& [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI
+2145..2149 ; ALetter # L& [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J
+214E ; ALetter # L& TURNED SMALL F
+2160..2182 ; ALetter # Nl [35] ROMAN NUMERAL ONE..ROMAN NUMERAL TEN THOUSAND
+2183..2184 ; ALetter # L& [2] ROMAN NUMERAL REVERSED ONE HUNDRED..LATIN SMALL LETTER REVERSED C
+2185..2188 ; ALetter # Nl [4] ROMAN NUMERAL SIX LATE FORM..ROMAN NUMERAL ONE HUNDRED THOUSAND
+24B6..24E9 ; ALetter # So [52] CIRCLED LATIN CAPITAL LETTER A..CIRCLED LATIN SMALL LETTER Z
+2C00..2C7B ; ALetter # L& [124] GLAGOLITIC CAPITAL LETTER AZU..LATIN LETTER SMALL CAPITAL TURNED E
+2C7C..2C7D ; ALetter # Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V
+2C7E..2CE4 ; ALetter # L& [103] LATIN CAPITAL LETTER S WITH SWASH TAIL..COPTIC SYMBOL KAI
+2CEB..2CEE ; ALetter # L& [4] COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI..COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA
+2CF2..2CF3 ; ALetter # L& [2] COPTIC CAPITAL LETTER BOHAIRIC KHEI..COPTIC SMALL LETTER BOHAIRIC KHEI
+2D00..2D25 ; ALetter # L& [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE
+2D27 ; ALetter # L& GEORGIAN SMALL LETTER YN
+2D2D ; ALetter # L& GEORGIAN SMALL LETTER AEN
+2D30..2D67 ; ALetter # Lo [56] TIFINAGH LETTER YA..TIFINAGH LETTER YO
+2D6F ; ALetter # Lm TIFINAGH MODIFIER LETTER LABIALIZATION MARK
+2D80..2D96 ; ALetter # Lo [23] ETHIOPIC SYLLABLE LOA..ETHIOPIC SYLLABLE GGWE
+2DA0..2DA6 ; ALetter # Lo [7] ETHIOPIC SYLLABLE SSA..ETHIOPIC SYLLABLE SSO
+2DA8..2DAE ; ALetter # Lo [7] ETHIOPIC SYLLABLE CCA..ETHIOPIC SYLLABLE CCO
+2DB0..2DB6 ; ALetter # Lo [7] ETHIOPIC SYLLABLE ZZA..ETHIOPIC SYLLABLE ZZO
+2DB8..2DBE ; ALetter # Lo [7] ETHIOPIC SYLLABLE CCHA..ETHIOPIC SYLLABLE CCHO
+2DC0..2DC6 ; ALetter # Lo [7] ETHIOPIC SYLLABLE QYA..ETHIOPIC SYLLABLE QYO
+2DC8..2DCE ; ALetter # Lo [7] ETHIOPIC SYLLABLE KYA..ETHIOPIC SYLLABLE KYO
+2DD0..2DD6 ; ALetter # Lo [7] ETHIOPIC SYLLABLE XYA..ETHIOPIC SYLLABLE XYO
+2DD8..2DDE ; ALetter # Lo [7] ETHIOPIC SYLLABLE GYA..ETHIOPIC SYLLABLE GYO
+2E2F ; ALetter # Lm VERTICAL TILDE
+3005 ; ALetter # Lm IDEOGRAPHIC ITERATION MARK
+303B ; ALetter # Lm VERTICAL IDEOGRAPHIC ITERATION MARK
+303C ; ALetter # Lo MASU MARK
+3105..312F ; ALetter # Lo [43] BOPOMOFO LETTER B..BOPOMOFO LETTER NN
+3131..318E ; ALetter # Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE
+31A0..31BF ; ALetter # Lo [32] BOPOMOFO LETTER BU..BOPOMOFO LETTER AH
+A000..A014 ; ALetter # Lo [21] YI SYLLABLE IT..YI SYLLABLE E
+A015 ; ALetter # Lm YI SYLLABLE WU
+A016..A48C ; ALetter # Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR
+A4D0..A4F7 ; ALetter # Lo [40] LISU LETTER BA..LISU LETTER OE
+A4F8..A4FD ; ALetter # Lm [6] LISU LETTER TONE MYA TI..LISU LETTER TONE MYA JEU
+A500..A60B ; ALetter # Lo [268] VAI SYLLABLE EE..VAI SYLLABLE NG
+A60C ; ALetter # Lm VAI SYLLABLE LENGTHENER
+A610..A61F ; ALetter # Lo [16] VAI SYLLABLE NDOLE FA..VAI SYMBOL JONG
+A62A..A62B ; ALetter # Lo [2] VAI SYLLABLE NDOLE MA..VAI SYLLABLE NDOLE DO
+A640..A66D ; ALetter # L& [46] CYRILLIC CAPITAL LETTER ZEMLYA..CYRILLIC SMALL LETTER DOUBLE MONOCULAR O
+A66E ; ALetter # Lo CYRILLIC LETTER MULTIOCULAR O
+A67F ; ALetter # Lm CYRILLIC PAYEROK
+A680..A69B ; ALetter # L& [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O
+A69C..A69D ; ALetter # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN
+A6A0..A6E5 ; ALetter # Lo [70] BAMUM LETTER A..BAMUM LETTER KI
+A6E6..A6EF ; ALetter # Nl [10] BAMUM LETTER MO..BAMUM LETTER KOGHOM
+A708..A716 ; ALetter # Sk [15] MODIFIER LETTER EXTRA-HIGH DOTTED TONE BAR..MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR
+A717..A71F ; ALetter # Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK
+A720..A721 ; ALetter # Sk [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE
+A722..A76F ; ALetter # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CON
+A770 ; ALetter # Lm MODIFIER LETTER US
+A771..A787 ; ALetter # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T
+A788 ; ALetter # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT
+A789..A78A ; ALetter # Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN
+A78B..A78E ; ALetter # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT
+A78F ; ALetter # Lo LATIN LETTER SINOLOGICAL DOT
+A790..A7CA ; ALetter # L& [59] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY
+A7D0..A7D1 ; ALetter # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G
+A7D3 ; ALetter # L& LATIN SMALL LETTER DOUBLE THORN
+A7D5..A7D9 ; ALetter # L& [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S
+A7F2..A7F4 ; ALetter # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q
+A7F5..A7F6 ; ALetter # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H
+A7F7 ; ALetter # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I
+A7F8..A7F9 ; ALetter # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE
+A7FA ; ALetter # L& LATIN LETTER SMALL CAPITAL TURNED M
+A7FB..A801 ; ALetter # Lo [7] LATIN EPIGRAPHIC LETTER REVERSED F..SYLOTI NAGRI LETTER I
+A803..A805 ; ALetter # Lo [3] SYLOTI NAGRI LETTER U..SYLOTI NAGRI LETTER O
+A807..A80A ; ALetter # Lo [4] SYLOTI NAGRI LETTER KO..SYLOTI NAGRI LETTER GHO
+A80C..A822 ; ALetter # Lo [23] SYLOTI NAGRI LETTER CO..SYLOTI NAGRI LETTER HO
+A840..A873 ; ALetter # Lo [52] PHAGS-PA LETTER KA..PHAGS-PA LETTER CANDRABINDU
+A882..A8B3 ; ALetter # Lo [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA
+A8F2..A8F7 ; ALetter # Lo [6] DEVANAGARI SIGN SPACING CANDRABINDU..DEVANAGARI SIGN CANDRABINDU AVAGRAHA
+A8FB ; ALetter # Lo DEVANAGARI HEADSTROKE
+A8FD..A8FE ; ALetter # Lo [2] DEVANAGARI JAIN OM..DEVANAGARI LETTER AY
+A90A..A925 ; ALetter # Lo [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO
+A930..A946 ; ALetter # Lo [23] REJANG LETTER KA..REJANG LETTER A
+A960..A97C ; ALetter # Lo [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH
+A984..A9B2 ; ALetter # Lo [47] JAVANESE LETTER A..JAVANESE LETTER HA
+A9CF ; ALetter # Lm JAVANESE PANGRANGKEP
+AA00..AA28 ; ALetter # Lo [41] CHAM LETTER A..CHAM LETTER HA
+AA40..AA42 ; ALetter # Lo [3] CHAM LETTER FINAL K..CHAM LETTER FINAL NG
+AA44..AA4B ; ALetter # Lo [8] CHAM LETTER FINAL CH..CHAM LETTER FINAL SS
+AAE0..AAEA ; ALetter # Lo [11] MEETEI MAYEK LETTER E..MEETEI MAYEK LETTER SSA
+AAF2 ; ALetter # Lo MEETEI MAYEK ANJI
+AAF3..AAF4 ; ALetter # Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK
+AB01..AB06 ; ALetter # Lo [6] ETHIOPIC SYLLABLE TTHU..ETHIOPIC SYLLABLE TTHO
+AB09..AB0E ; ALetter # Lo [6] ETHIOPIC SYLLABLE DDHU..ETHIOPIC SYLLABLE DDHO
+AB11..AB16 ; ALetter # Lo [6] ETHIOPIC SYLLABLE DZU..ETHIOPIC SYLLABLE DZO
+AB20..AB26 ; ALetter # Lo [7] ETHIOPIC SYLLABLE CCHHA..ETHIOPIC SYLLABLE CCHHO
+AB28..AB2E ; ALetter # Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO
+AB30..AB5A ; ALetter # L& [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG
+AB5B ; ALetter # Sk MODIFIER BREVE WITH INVERTED BREVE
+AB5C..AB5F ; ALetter # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK
+AB60..AB68 ; ALetter # L& [9] LATIN SMALL LETTER SAKHA YAT..LATIN SMALL LETTER TURNED R WITH MIDDLE TILDE
+AB69 ; ALetter # Lm MODIFIER LETTER SMALL TURNED W
+AB70..ABBF ; ALetter # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA
+ABC0..ABE2 ; ALetter # Lo [35] MEETEI MAYEK LETTER KOK..MEETEI MAYEK LETTER I LONSUM
+AC00..D7A3 ; ALetter # Lo [11172] HANGUL SYLLABLE GA..HANGUL SYLLABLE HIH
+D7B0..D7C6 ; ALetter # Lo [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E
+D7CB..D7FB ; ALetter # Lo [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH
+FB00..FB06 ; ALetter # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST
+FB13..FB17 ; ALetter # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH
+FB50..FBB1 ; ALetter # Lo [98] ARABIC LETTER ALEF WASLA ISOLATED FORM..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM
+FBD3..FD3D ; ALetter # Lo [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM
+FD50..FD8F ; ALetter # Lo [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM
+FD92..FDC7 ; ALetter # Lo [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM
+FDF0..FDFB ; ALetter # Lo [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU
+FE70..FE74 ; ALetter # Lo [5] ARABIC FATHATAN ISOLATED FORM..ARABIC KASRATAN ISOLATED FORM
+FE76..FEFC ; ALetter # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM
+FF21..FF3A ; ALetter # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z
+FF41..FF5A ; ALetter # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z
+FFA0..FFBE ; ALetter # Lo [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH
+FFC2..FFC7 ; ALetter # Lo [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E
+FFCA..FFCF ; ALetter # Lo [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE
+FFD2..FFD7 ; ALetter # Lo [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU
+FFDA..FFDC ; ALetter # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I
+10000..1000B ; ALetter # Lo [12] LINEAR B SYLLABLE B008 A..LINEAR B SYLLABLE B046 JE
+1000D..10026 ; ALetter # Lo [26] LINEAR B SYLLABLE B036 JO..LINEAR B SYLLABLE B032 QO
+10028..1003A ; ALetter # Lo [19] LINEAR B SYLLABLE B060 RA..LINEAR B SYLLABLE B042 WO
+1003C..1003D ; ALetter # Lo [2] LINEAR B SYLLABLE B017 ZA..LINEAR B SYLLABLE B074 ZE
+1003F..1004D ; ALetter # Lo [15] LINEAR B SYLLABLE B020 ZO..LINEAR B SYLLABLE B091 TWO
+10050..1005D ; ALetter # Lo [14] LINEAR B SYMBOL B018..LINEAR B SYMBOL B089
+10080..100FA ; ALetter # Lo [123] LINEAR B IDEOGRAM B100 MAN..LINEAR B IDEOGRAM VESSEL B305
+10140..10174 ; ALetter # Nl [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS
+10280..1029C ; ALetter # Lo [29] LYCIAN LETTER A..LYCIAN LETTER X
+102A0..102D0 ; ALetter # Lo [49] CARIAN LETTER A..CARIAN LETTER UUU3
+10300..1031F ; ALetter # Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS
+1032D..10340 ; ALetter # Lo [20] OLD ITALIC LETTER YE..GOTHIC LETTER PAIRTHRA
+10341 ; ALetter # Nl GOTHIC LETTER NINETY
+10342..10349 ; ALetter # Lo [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL
+1034A ; ALetter # Nl GOTHIC LETTER NINE HUNDRED
+10350..10375 ; ALetter # Lo [38] OLD PERMIC LETTER AN..OLD PERMIC LETTER IA
+10380..1039D ; ALetter # Lo [30] UGARITIC LETTER ALPA..UGARITIC LETTER SSU
+103A0..103C3 ; ALetter # Lo [36] OLD PERSIAN SIGN A..OLD PERSIAN SIGN HA
+103C8..103CF ; ALetter # Lo [8] OLD PERSIAN SIGN AURAMAZDAA..OLD PERSIAN SIGN BUUMISH
+103D1..103D5 ; ALetter # Nl [5] OLD PERSIAN NUMBER ONE..OLD PERSIAN NUMBER HUNDRED
+10400..1044F ; ALetter # L& [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW
+10450..1049D ; ALetter # Lo [78] SHAVIAN LETTER PEEP..OSMANYA LETTER OO
+104B0..104D3 ; ALetter # L& [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA
+104D8..104FB ; ALetter # L& [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA
+10500..10527 ; ALetter # Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE
+10530..10563 ; ALetter # Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW
+10570..1057A ; ALetter # L& [11] VITHKUQI CAPITAL LETTER A..VITHKUQI CAPITAL LETTER GA
+1057C..1058A ; ALetter # L& [15] VITHKUQI CAPITAL LETTER HA..VITHKUQI CAPITAL LETTER RE
+1058C..10592 ; ALetter # L& [7] VITHKUQI CAPITAL LETTER SE..VITHKUQI CAPITAL LETTER XE
+10594..10595 ; ALetter # L& [2] VITHKUQI CAPITAL LETTER Y..VITHKUQI CAPITAL LETTER ZE
+10597..105A1 ; ALetter # L& [11] VITHKUQI SMALL LETTER A..VITHKUQI SMALL LETTER GA
+105A3..105B1 ; ALetter # L& [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE
+105B3..105B9 ; ALetter # L& [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE
+105BB..105BC ; ALetter # L& [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE
+10600..10736 ; ALetter # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664
+10740..10755 ; ALetter # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE
+10760..10767 ; ALetter # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807
+10780..10785 ; ALetter # Lm [6] MODIFIER LETTER SMALL CAPITAL AA..MODIFIER LETTER SMALL B WITH HOOK
+10787..107B0 ; ALetter # Lm [42] MODIFIER LETTER SMALL DZ DIGRAPH..MODIFIER LETTER SMALL V WITH RIGHT HOOK
+107B2..107BA ; ALetter # Lm [9] MODIFIER LETTER SMALL CAPITAL Y..MODIFIER LETTER SMALL S WITH CURL
+10800..10805 ; ALetter # Lo [6] CYPRIOT SYLLABLE A..CYPRIOT SYLLABLE JA
+10808 ; ALetter # Lo CYPRIOT SYLLABLE JO
+1080A..10835 ; ALetter # Lo [44] CYPRIOT SYLLABLE KA..CYPRIOT SYLLABLE WO
+10837..10838 ; ALetter # Lo [2] CYPRIOT SYLLABLE XA..CYPRIOT SYLLABLE XE
+1083C ; ALetter # Lo CYPRIOT SYLLABLE ZA
+1083F..10855 ; ALetter # Lo [23] CYPRIOT SYLLABLE ZO..IMPERIAL ARAMAIC LETTER TAW
+10860..10876 ; ALetter # Lo [23] PALMYRENE LETTER ALEPH..PALMYRENE LETTER TAW
+10880..1089E ; ALetter # Lo [31] NABATAEAN LETTER FINAL ALEPH..NABATAEAN LETTER TAW
+108E0..108F2 ; ALetter # Lo [19] HATRAN LETTER ALEPH..HATRAN LETTER QOPH
+108F4..108F5 ; ALetter # Lo [2] HATRAN LETTER SHIN..HATRAN LETTER TAW
+10900..10915 ; ALetter # Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU
+10920..10939 ; ALetter # Lo [26] LYDIAN LETTER A..LYDIAN LETTER C
+10980..109B7 ; ALetter # Lo [56] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC CURSIVE LETTER DA
+109BE..109BF ; ALetter # Lo [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN
+10A00 ; ALetter # Lo KHAROSHTHI LETTER A
+10A10..10A13 ; ALetter # Lo [4] KHAROSHTHI LETTER KA..KHAROSHTHI LETTER GHA
+10A15..10A17 ; ALetter # Lo [3] KHAROSHTHI LETTER CA..KHAROSHTHI LETTER JA
+10A19..10A35 ; ALetter # Lo [29] KHAROSHTHI LETTER NYA..KHAROSHTHI LETTER VHA
+10A60..10A7C ; ALetter # Lo [29] OLD SOUTH ARABIAN LETTER HE..OLD SOUTH ARABIAN LETTER THETH
+10A80..10A9C ; ALetter # Lo [29] OLD NORTH ARABIAN LETTER HEH..OLD NORTH ARABIAN LETTER ZAH
+10AC0..10AC7 ; ALetter # Lo [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW
+10AC9..10AE4 ; ALetter # Lo [28] MANICHAEAN LETTER ZAYIN..MANICHAEAN LETTER TAW
+10B00..10B35 ; ALetter # Lo [54] AVESTAN LETTER A..AVESTAN LETTER HE
+10B40..10B55 ; ALetter # Lo [22] INSCRIPTIONAL PARTHIAN LETTER ALEPH..INSCRIPTIONAL PARTHIAN LETTER TAW
+10B60..10B72 ; ALetter # Lo [19] INSCRIPTIONAL PAHLAVI LETTER ALEPH..INSCRIPTIONAL PAHLAVI LETTER TAW
+10B80..10B91 ; ALetter # Lo [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW
+10C00..10C48 ; ALetter # Lo [73] OLD TURKIC LETTER ORKHON A..OLD TURKIC LETTER ORKHON BASH
+10C80..10CB2 ; ALetter # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US
+10CC0..10CF2 ; ALetter # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US
+10D00..10D23 ; ALetter # Lo [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA
+10E80..10EA9 ; ALetter # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET
+10EB0..10EB1 ; ALetter # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE
+10F00..10F1C ; ALetter # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL
+10F27 ; ALetter # Lo OLD SOGDIAN LIGATURE AYIN-DALETH
+10F30..10F45 ; ALetter # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN
+10F70..10F81 ; ALetter # Lo [18] OLD UYGHUR LETTER ALEPH..OLD UYGHUR LETTER LESH
+10FB0..10FC4 ; ALetter # Lo [21] CHORASMIAN LETTER ALEPH..CHORASMIAN LETTER TAW
+10FE0..10FF6 ; ALetter # Lo [23] ELYMAIC LETTER ALEPH..ELYMAIC LIGATURE ZAYIN-YODH
+11003..11037 ; ALetter # Lo [53] BRAHMI SIGN JIHVAMULIYA..BRAHMI LETTER OLD TAMIL NNNA
+11071..11072 ; ALetter # Lo [2] BRAHMI LETTER OLD TAMIL SHORT E..BRAHMI LETTER OLD TAMIL SHORT O
+11075 ; ALetter # Lo BRAHMI LETTER OLD TAMIL LLA
+11083..110AF ; ALetter # Lo [45] KAITHI LETTER A..KAITHI LETTER HA
+110D0..110E8 ; ALetter # Lo [25] SORA SOMPENG LETTER SAH..SORA SOMPENG LETTER MAE
+11103..11126 ; ALetter # Lo [36] CHAKMA LETTER AA..CHAKMA LETTER HAA
+11144 ; ALetter # Lo CHAKMA LETTER LHAA
+11147 ; ALetter # Lo CHAKMA LETTER VAA
+11150..11172 ; ALetter # Lo [35] MAHAJANI LETTER A..MAHAJANI LETTER RRA
+11176 ; ALetter # Lo MAHAJANI LIGATURE SHRI
+11183..111B2 ; ALetter # Lo [48] SHARADA LETTER A..SHARADA LETTER HA
+111C1..111C4 ; ALetter # Lo [4] SHARADA SIGN AVAGRAHA..SHARADA OM
+111DA ; ALetter # Lo SHARADA EKAM
+111DC ; ALetter # Lo SHARADA HEADSTROKE
+11200..11211 ; ALetter # Lo [18] KHOJKI LETTER A..KHOJKI LETTER JJA
+11213..1122B ; ALetter # Lo [25] KHOJKI LETTER NYA..KHOJKI LETTER LLA
+1123F..11240 ; ALetter # Lo [2] KHOJKI LETTER QA..KHOJKI LETTER SHORT I
+11280..11286 ; ALetter # Lo [7] MULTANI LETTER A..MULTANI LETTER GA
+11288 ; ALetter # Lo MULTANI LETTER GHA
+1128A..1128D ; ALetter # Lo [4] MULTANI LETTER CA..MULTANI LETTER JJA
+1128F..1129D ; ALetter # Lo [15] MULTANI LETTER NYA..MULTANI LETTER BA
+1129F..112A8 ; ALetter # Lo [10] MULTANI LETTER BHA..MULTANI LETTER RHA
+112B0..112DE ; ALetter # Lo [47] KHUDAWADI LETTER A..KHUDAWADI LETTER HA
+11305..1130C ; ALetter # Lo [8] GRANTHA LETTER A..GRANTHA LETTER VOCALIC L
+1130F..11310 ; ALetter # Lo [2] GRANTHA LETTER EE..GRANTHA LETTER AI
+11313..11328 ; ALetter # Lo [22] GRANTHA LETTER OO..GRANTHA LETTER NA
+1132A..11330 ; ALetter # Lo [7] GRANTHA LETTER PA..GRANTHA LETTER RA
+11332..11333 ; ALetter # Lo [2] GRANTHA LETTER LA..GRANTHA LETTER LLA
+11335..11339 ; ALetter # Lo [5] GRANTHA LETTER VA..GRANTHA LETTER HA
+1133D ; ALetter # Lo GRANTHA SIGN AVAGRAHA
+11350 ; ALetter # Lo GRANTHA OM
+1135D..11361 ; ALetter # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL
+11400..11434 ; ALetter # Lo [53] NEWA LETTER A..NEWA LETTER HA
+11447..1144A ; ALetter # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI
+1145F..11461 ; ALetter # Lo [3] NEWA LETTER VEDIC ANUSVARA..NEWA SIGN UPADHMANIYA
+11480..114AF ; ALetter # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA
+114C4..114C5 ; ALetter # Lo [2] TIRHUTA SIGN AVAGRAHA..TIRHUTA GVANG
+114C7 ; ALetter # Lo TIRHUTA OM
+11580..115AE ; ALetter # Lo [47] SIDDHAM LETTER A..SIDDHAM LETTER HA
+115D8..115DB ; ALetter # Lo [4] SIDDHAM LETTER THREE-CIRCLE ALTERNATE I..SIDDHAM LETTER ALTERNATE U
+11600..1162F ; ALetter # Lo [48] MODI LETTER A..MODI LETTER LLA
+11644 ; ALetter # Lo MODI SIGN HUVA
+11680..116AA ; ALetter # Lo [43] TAKRI LETTER A..TAKRI LETTER RRA
+116B8 ; ALetter # Lo TAKRI LETTER ARCHAIC KHA
+11800..1182B ; ALetter # Lo [44] DOGRA LETTER A..DOGRA LETTER RRA
+118A0..118DF ; ALetter # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO
+118FF..11906 ; ALetter # Lo [8] WARANG CITI OM..DIVES AKURU LETTER E
+11909 ; ALetter # Lo DIVES AKURU LETTER O
+1190C..11913 ; ALetter # Lo [8] DIVES AKURU LETTER KA..DIVES AKURU LETTER JA
+11915..11916 ; ALetter # Lo [2] DIVES AKURU LETTER NYA..DIVES AKURU LETTER TTA
+11918..1192F ; ALetter # Lo [24] DIVES AKURU LETTER DDA..DIVES AKURU LETTER ZA
+1193F ; ALetter # Lo DIVES AKURU PREFIXED NASAL SIGN
+11941 ; ALetter # Lo DIVES AKURU INITIAL RA
+119A0..119A7 ; ALetter # Lo [8] NANDINAGARI LETTER A..NANDINAGARI LETTER VOCALIC RR
+119AA..119D0 ; ALetter # Lo [39] NANDINAGARI LETTER E..NANDINAGARI LETTER RRA
+119E1 ; ALetter # Lo NANDINAGARI SIGN AVAGRAHA
+119E3 ; ALetter # Lo NANDINAGARI HEADSTROKE
+11A00 ; ALetter # Lo ZANABAZAR SQUARE LETTER A
+11A0B..11A32 ; ALetter # Lo [40] ZANABAZAR SQUARE LETTER KA..ZANABAZAR SQUARE LETTER KSSA
+11A3A ; ALetter # Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA
+11A50 ; ALetter # Lo SOYOMBO LETTER A
+11A5C..11A89 ; ALetter # Lo [46] SOYOMBO LETTER KA..SOYOMBO CLUSTER-INITIAL LETTER SA
+11A9D ; ALetter # Lo SOYOMBO MARK PLUTA
+11AB0..11AF8 ; ALetter # Lo [73] CANADIAN SYLLABICS NATTILIK HI..PAU CIN HAU GLOTTAL STOP FINAL
+11C00..11C08 ; ALetter # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L
+11C0A..11C2E ; ALetter # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA
+11C40 ; ALetter # Lo BHAIKSUKI SIGN AVAGRAHA
+11C72..11C8F ; ALetter # Lo [30] MARCHEN LETTER KA..MARCHEN LETTER A
+11D00..11D06 ; ALetter # Lo [7] MASARAM GONDI LETTER A..MASARAM GONDI LETTER E
+11D08..11D09 ; ALetter # Lo [2] MASARAM GONDI LETTER AI..MASARAM GONDI LETTER O
+11D0B..11D30 ; ALetter # Lo [38] MASARAM GONDI LETTER AU..MASARAM GONDI LETTER TRA
+11D46 ; ALetter # Lo MASARAM GONDI REPHA
+11D60..11D65 ; ALetter # Lo [6] GUNJALA GONDI LETTER A..GUNJALA GONDI LETTER UU
+11D67..11D68 ; ALetter # Lo [2] GUNJALA GONDI LETTER EE..GUNJALA GONDI LETTER AI
+11D6A..11D89 ; ALetter # Lo [32] GUNJALA GONDI LETTER OO..GUNJALA GONDI LETTER SA
+11D98 ; ALetter # Lo GUNJALA GONDI OM
+11EE0..11EF2 ; ALetter # Lo [19] MAKASAR LETTER KA..MAKASAR ANGKA
+11F02 ; ALetter # Lo KAWI SIGN REPHA
+11F04..11F10 ; ALetter # Lo [13] KAWI LETTER A..KAWI LETTER O
+11F12..11F33 ; ALetter # Lo [34] KAWI LETTER KA..KAWI LETTER JNYA
+11FB0 ; ALetter # Lo LISU LETTER YHA
+12000..12399 ; ALetter # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U
+12400..1246E ; ALetter # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM
+12480..12543 ; ALetter # Lo [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU
+12F90..12FF0 ; ALetter # Lo [97] CYPRO-MINOAN SIGN CM001..CYPRO-MINOAN SIGN CM114
+13000..1342F ; ALetter # Lo [1072] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH V011D
+13441..13446 ; ALetter # Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN
+14400..14646 ; ALetter # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530
+16800..16A38 ; ALetter # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ
+16A40..16A5E ; ALetter # Lo [31] MRO LETTER TA..MRO LETTER TEK
+16A70..16ABE ; ALetter # Lo [79] TANGSA LETTER OZ..TANGSA LETTER ZA
+16AD0..16AED ; ALetter # Lo [30] BASSA VAH LETTER ENNI..BASSA VAH LETTER I
+16B00..16B2F ; ALetter # Lo [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU
+16B40..16B43 ; ALetter # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM
+16B63..16B77 ; ALetter # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS
+16B7D..16B8F ; ALetter # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ
+16E40..16E7F ; ALetter # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y
+16F00..16F4A ; ALetter # Lo [75] MIAO LETTER PA..MIAO LETTER RTE
+16F50 ; ALetter # Lo MIAO LETTER NASALIZATION
+16F93..16F9F ; ALetter # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8
+16FE0..16FE1 ; ALetter # Lm [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK
+16FE3 ; ALetter # Lm OLD CHINESE ITERATION MARK
+1BC00..1BC6A ; ALetter # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M
+1BC70..1BC7C ; ALetter # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK
+1BC80..1BC88 ; ALetter # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL
+1BC90..1BC99 ; ALetter # Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW
+1D400..1D454 ; ALetter # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G
+1D456..1D49C ; ALetter # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A
+1D49E..1D49F ; ALetter # L& [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D
+1D4A2 ; ALetter # L& MATHEMATICAL SCRIPT CAPITAL G
+1D4A5..1D4A6 ; ALetter # L& [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K
+1D4A9..1D4AC ; ALetter # L& [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q
+1D4AE..1D4B9 ; ALetter # L& [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D
+1D4BB ; ALetter # L& MATHEMATICAL SCRIPT SMALL F
+1D4BD..1D4C3 ; ALetter # L& [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N
+1D4C5..1D505 ; ALetter # L& [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B
+1D507..1D50A ; ALetter # L& [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G
+1D50D..1D514 ; ALetter # L& [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q
+1D516..1D51C ; ALetter # L& [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y
+1D51E..1D539 ; ALetter # L& [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B
+1D53B..1D53E ; ALetter # L& [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G
+1D540..1D544 ; ALetter # L& [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M
+1D546 ; ALetter # L& MATHEMATICAL DOUBLE-STRUCK CAPITAL O
+1D54A..1D550 ; ALetter # L& [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y
+1D552..1D6A5 ; ALetter # L& [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J
+1D6A8..1D6C0 ; ALetter # L& [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA
+1D6C2..1D6DA ; ALetter # L& [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA
+1D6DC..1D6FA ; ALetter # L& [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA
+1D6FC..1D714 ; ALetter # L& [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA
+1D716..1D734 ; ALetter # L& [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA
+1D736..1D74E ; ALetter # L& [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA
+1D750..1D76E ; ALetter # L& [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA
+1D770..1D788 ; ALetter # L& [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA
+1D78A..1D7A8 ; ALetter # L& [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA
+1D7AA..1D7C2 ; ALetter # L& [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA
+1D7C4..1D7CB ; ALetter # L& [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA
+1DF00..1DF09 ; ALetter # L& [10] LATIN SMALL LETTER FENG DIGRAPH WITH TRILL..LATIN SMALL LETTER T WITH HOOK AND RETROFLEX HOOK
+1DF0A ; ALetter # Lo LATIN LETTER RETROFLEX CLICK WITH RETROFLEX HOOK
+1DF0B..1DF1E ; ALetter # L& [20] LATIN SMALL LETTER ESH WITH DOUBLE BAR..LATIN SMALL LETTER S WITH CURL
+1DF25..1DF2A ; ALetter # L& [6] LATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOK..LATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOK
+1E030..1E06D ; ALetter # Lm [62] MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE
+1E100..1E12C ; ALetter # Lo [45] NYIAKENG PUACHUE HMONG LETTER MA..NYIAKENG PUACHUE HMONG LETTER W
+1E137..1E13D ; ALetter # Lm [7] NYIAKENG PUACHUE HMONG SIGN FOR PERSON..NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER
+1E14E ; ALetter # Lo NYIAKENG PUACHUE HMONG LOGOGRAM NYAJ
+1E290..1E2AD ; ALetter # Lo [30] TOTO LETTER PA..TOTO LETTER A
+1E2C0..1E2EB ; ALetter # Lo [44] WANCHO LETTER AA..WANCHO LETTER YIH
+1E4D0..1E4EA ; ALetter # Lo [27] NAG MUNDARI LETTER O..NAG MUNDARI LETTER ELL
+1E4EB ; ALetter # Lm NAG MUNDARI SIGN OJOD
+1E7E0..1E7E6 ; ALetter # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO
+1E7E8..1E7EB ; ALetter # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE
+1E7ED..1E7EE ; ALetter # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE
+1E7F0..1E7FE ; ALetter # Lo [15] ETHIOPIC SYLLABLE GURAGE QWI..ETHIOPIC SYLLABLE GURAGE PWEE
+1E800..1E8C4 ; ALetter # Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON
+1E900..1E943 ; ALetter # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA
+1E94B ; ALetter # Lm ADLAM NASALIZATION MARK
+1EE00..1EE03 ; ALetter # Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL
+1EE05..1EE1F ; ALetter # Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF
+1EE21..1EE22 ; ALetter # Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM
+1EE24 ; ALetter # Lo ARABIC MATHEMATICAL INITIAL HEH
+1EE27 ; ALetter # Lo ARABIC MATHEMATICAL INITIAL HAH
+1EE29..1EE32 ; ALetter # Lo [10] ARABIC MATHEMATICAL INITIAL YEH..ARABIC MATHEMATICAL INITIAL QAF
+1EE34..1EE37 ; ALetter # Lo [4] ARABIC MATHEMATICAL INITIAL SHEEN..ARABIC MATHEMATICAL INITIAL KHAH
+1EE39 ; ALetter # Lo ARABIC MATHEMATICAL INITIAL DAD
+1EE3B ; ALetter # Lo ARABIC MATHEMATICAL INITIAL GHAIN
+1EE42 ; ALetter # Lo ARABIC MATHEMATICAL TAILED JEEM
+1EE47 ; ALetter # Lo ARABIC MATHEMATICAL TAILED HAH
+1EE49 ; ALetter # Lo ARABIC MATHEMATICAL TAILED YEH
+1EE4B ; ALetter # Lo ARABIC MATHEMATICAL TAILED LAM
+1EE4D..1EE4F ; ALetter # Lo [3] ARABIC MATHEMATICAL TAILED NOON..ARABIC MATHEMATICAL TAILED AIN
+1EE51..1EE52 ; ALetter # Lo [2] ARABIC MATHEMATICAL TAILED SAD..ARABIC MATHEMATICAL TAILED QAF
+1EE54 ; ALetter # Lo ARABIC MATHEMATICAL TAILED SHEEN
+1EE57 ; ALetter # Lo ARABIC MATHEMATICAL TAILED KHAH
+1EE59 ; ALetter # Lo ARABIC MATHEMATICAL TAILED DAD
+1EE5B ; ALetter # Lo ARABIC MATHEMATICAL TAILED GHAIN
+1EE5D ; ALetter # Lo ARABIC MATHEMATICAL TAILED DOTLESS NOON
+1EE5F ; ALetter # Lo ARABIC MATHEMATICAL TAILED DOTLESS QAF
+1EE61..1EE62 ; ALetter # Lo [2] ARABIC MATHEMATICAL STRETCHED BEH..ARABIC MATHEMATICAL STRETCHED JEEM
+1EE64 ; ALetter # Lo ARABIC MATHEMATICAL STRETCHED HEH
+1EE67..1EE6A ; ALetter # Lo [4] ARABIC MATHEMATICAL STRETCHED HAH..ARABIC MATHEMATICAL STRETCHED KAF
+1EE6C..1EE72 ; ALetter # Lo [7] ARABIC MATHEMATICAL STRETCHED MEEM..ARABIC MATHEMATICAL STRETCHED QAF
+1EE74..1EE77 ; ALetter # Lo [4] ARABIC MATHEMATICAL STRETCHED SHEEN..ARABIC MATHEMATICAL STRETCHED KHAH
+1EE79..1EE7C ; ALetter # Lo [4] ARABIC MATHEMATICAL STRETCHED DAD..ARABIC MATHEMATICAL STRETCHED DOTLESS BEH
+1EE7E ; ALetter # Lo ARABIC MATHEMATICAL STRETCHED DOTLESS FEH
+1EE80..1EE89 ; ALetter # Lo [10] ARABIC MATHEMATICAL LOOPED ALEF..ARABIC MATHEMATICAL LOOPED YEH
+1EE8B..1EE9B ; ALetter # Lo [17] ARABIC MATHEMATICAL LOOPED LAM..ARABIC MATHEMATICAL LOOPED GHAIN
+1EEA1..1EEA3 ; ALetter # Lo [3] ARABIC MATHEMATICAL DOUBLE-STRUCK BEH..ARABIC MATHEMATICAL DOUBLE-STRUCK DAL
+1EEA5..1EEA9 ; ALetter # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH
+1EEAB..1EEBB ; ALetter # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN
+1F130..1F149 ; ALetter # So [26] SQUARED LATIN CAPITAL LETTER A..SQUARED LATIN CAPITAL LETTER Z
+1F150..1F169 ; ALetter # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z
+1F170..1F189 ; ALetter # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z
+
+# Total code points: 29490
+
+# ================================================
+
+003A ; MidLetter # Po COLON
+00B7 ; MidLetter # Po MIDDLE DOT
+0387 ; MidLetter # Po GREEK ANO TELEIA
+055F ; MidLetter # Po ARMENIAN ABBREVIATION MARK
+05F4 ; MidLetter # Po HEBREW PUNCTUATION GERSHAYIM
+2027 ; MidLetter # Po HYPHENATION POINT
+FE13 ; MidLetter # Po PRESENTATION FORM FOR VERTICAL COLON
+FE55 ; MidLetter # Po SMALL COLON
+FF1A ; MidLetter # Po FULLWIDTH COLON
+
+# Total code points: 9
+
+# ================================================
+
+002C ; MidNum # Po COMMA
+003B ; MidNum # Po SEMICOLON
+037E ; MidNum # Po GREEK QUESTION MARK
+0589 ; MidNum # Po ARMENIAN FULL STOP
+060C..060D ; MidNum # Po [2] ARABIC COMMA..ARABIC DATE SEPARATOR
+066C ; MidNum # Po ARABIC THOUSANDS SEPARATOR
+07F8 ; MidNum # Po NKO COMMA
+2044 ; MidNum # Sm FRACTION SLASH
+FE10 ; MidNum # Po PRESENTATION FORM FOR VERTICAL COMMA
+FE14 ; MidNum # Po PRESENTATION FORM FOR VERTICAL SEMICOLON
+FE50 ; MidNum # Po SMALL COMMA
+FE54 ; MidNum # Po SMALL SEMICOLON
+FF0C ; MidNum # Po FULLWIDTH COMMA
+FF1B ; MidNum # Po FULLWIDTH SEMICOLON
+
+# Total code points: 15
+
+# ================================================
+
+002E ; MidNumLet # Po FULL STOP
+2018 ; MidNumLet # Pi LEFT SINGLE QUOTATION MARK
+2019 ; MidNumLet # Pf RIGHT SINGLE QUOTATION MARK
+2024 ; MidNumLet # Po ONE DOT LEADER
+FE52 ; MidNumLet # Po SMALL FULL STOP
+FF07 ; MidNumLet # Po FULLWIDTH APOSTROPHE
+FF0E ; MidNumLet # Po FULLWIDTH FULL STOP
+
+# Total code points: 7
+
+# ================================================
+
+0030..0039 ; Numeric # Nd [10] DIGIT ZERO..DIGIT NINE
+0600..0605 ; Numeric # Cf [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE
+0660..0669 ; Numeric # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
+066B ; Numeric # Po ARABIC DECIMAL SEPARATOR
+06DD ; Numeric # Cf ARABIC END OF AYAH
+06F0..06F9 ; Numeric # Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE
+07C0..07C9 ; Numeric # Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE
+0890..0891 ; Numeric # Cf [2] ARABIC POUND MARK ABOVE..ARABIC PIASTRE MARK ABOVE
+08E2 ; Numeric # Cf ARABIC DISPUTED END OF AYAH
+0966..096F ; Numeric # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
+09E6..09EF ; Numeric # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE
+0A66..0A6F ; Numeric # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE
+0AE6..0AEF ; Numeric # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE
+0B66..0B6F ; Numeric # Nd [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE
+0BE6..0BEF ; Numeric # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE
+0C66..0C6F ; Numeric # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE
+0CE6..0CEF ; Numeric # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
+0D66..0D6F ; Numeric # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE
+0DE6..0DEF ; Numeric # Nd [10] SINHALA LITH DIGIT ZERO..SINHALA LITH DIGIT NINE
+0E50..0E59 ; Numeric # Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE
+0ED0..0ED9 ; Numeric # Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE
+0F20..0F29 ; Numeric # Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE
+1040..1049 ; Numeric # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE
+1090..1099 ; Numeric # Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE
+17E0..17E9 ; Numeric # Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE
+1810..1819 ; Numeric # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE
+1946..194F ; Numeric # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE
+19D0..19D9 ; Numeric # Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE
+1A80..1A89 ; Numeric # Nd [10] TAI THAM HORA DIGIT ZERO..TAI THAM HORA DIGIT NINE
+1A90..1A99 ; Numeric # Nd [10] TAI THAM THAM DIGIT ZERO..TAI THAM THAM DIGIT NINE
+1B50..1B59 ; Numeric # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE
+1BB0..1BB9 ; Numeric # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE
+1C40..1C49 ; Numeric # Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE
+1C50..1C59 ; Numeric # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE
+A620..A629 ; Numeric # Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE
+A8D0..A8D9 ; Numeric # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE
+A900..A909 ; Numeric # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE
+A9D0..A9D9 ; Numeric # Nd [10] JAVANESE DIGIT ZERO..JAVANESE DIGIT NINE
+A9F0..A9F9 ; Numeric # Nd [10] MYANMAR TAI LAING DIGIT ZERO..MYANMAR TAI LAING DIGIT NINE
+AA50..AA59 ; Numeric # Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE
+ABF0..ABF9 ; Numeric # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DIGIT NINE
+FF10..FF19 ; Numeric # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
+104A0..104A9 ; Numeric # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE
+10D30..10D39 ; Numeric # Nd [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE
+11066..1106F ; Numeric # Nd [10] BRAHMI DIGIT ZERO..BRAHMI DIGIT NINE
+110BD ; Numeric # Cf KAITHI NUMBER SIGN
+110CD ; Numeric # Cf KAITHI NUMBER SIGN ABOVE
+110F0..110F9 ; Numeric # Nd [10] SORA SOMPENG DIGIT ZERO..SORA SOMPENG DIGIT NINE
+11136..1113F ; Numeric # Nd [10] CHAKMA DIGIT ZERO..CHAKMA DIGIT NINE
+111D0..111D9 ; Numeric # Nd [10] SHARADA DIGIT ZERO..SHARADA DIGIT NINE
+112F0..112F9 ; Numeric # Nd [10] KHUDAWADI DIGIT ZERO..KHUDAWADI DIGIT NINE
+11450..11459 ; Numeric # Nd [10] NEWA DIGIT ZERO..NEWA DIGIT NINE
+114D0..114D9 ; Numeric # Nd [10] TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE
+11650..11659 ; Numeric # Nd [10] MODI DIGIT ZERO..MODI DIGIT NINE
+116C0..116C9 ; Numeric # Nd [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE
+11730..11739 ; Numeric # Nd [10] AHOM DIGIT ZERO..AHOM DIGIT NINE
+118E0..118E9 ; Numeric # Nd [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE
+11950..11959 ; Numeric # Nd [10] DIVES AKURU DIGIT ZERO..DIVES AKURU DIGIT NINE
+11C50..11C59 ; Numeric # Nd [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE
+11D50..11D59 ; Numeric # Nd [10] MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE
+11DA0..11DA9 ; Numeric # Nd [10] GUNJALA GONDI DIGIT ZERO..GUNJALA GONDI DIGIT NINE
+11F50..11F59 ; Numeric # Nd [10] KAWI DIGIT ZERO..KAWI DIGIT NINE
+16A60..16A69 ; Numeric # Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE
+16AC0..16AC9 ; Numeric # Nd [10] TANGSA DIGIT ZERO..TANGSA DIGIT NINE
+16B50..16B59 ; Numeric # Nd [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE
+1D7CE..1D7FF ; Numeric # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE
+1E140..1E149 ; Numeric # Nd [10] NYIAKENG PUACHUE HMONG DIGIT ZERO..NYIAKENG PUACHUE HMONG DIGIT NINE
+1E2F0..1E2F9 ; Numeric # Nd [10] WANCHO DIGIT ZERO..WANCHO DIGIT NINE
+1E4F0..1E4F9 ; Numeric # Nd [10] NAG MUNDARI DIGIT ZERO..NAG MUNDARI DIGIT NINE
+1E950..1E959 ; Numeric # Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE
+1FBF0..1FBF9 ; Numeric # Nd [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE
+
+# Total code points: 693
+
+# ================================================
+
+005F ; ExtendNumLet # Pc LOW LINE
+202F ; ExtendNumLet # Zs NARROW NO-BREAK SPACE
+203F..2040 ; ExtendNumLet # Pc [2] UNDERTIE..CHARACTER TIE
+2054 ; ExtendNumLet # Pc INVERTED UNDERTIE
+FE33..FE34 ; ExtendNumLet # Pc [2] PRESENTATION FORM FOR VERTICAL LOW LINE..PRESENTATION FORM FOR VERTICAL WAVY LOW LINE
+FE4D..FE4F ; ExtendNumLet # Pc [3] DASHED LOW LINE..WAVY LOW LINE
+FF3F ; ExtendNumLet # Pc FULLWIDTH LOW LINE
+
+# Total code points: 11
+
+# ================================================
+
+200D ; ZWJ # Cf ZERO WIDTH JOINER
+
+# Total code points: 1
+
+# ================================================
+
+0020 ; WSegSpace # Zs SPACE
+1680 ; WSegSpace # Zs OGHAM SPACE MARK
+2000..2006 ; WSegSpace # Zs [7] EN QUAD..SIX-PER-EM SPACE
+2008..200A ; WSegSpace # Zs [3] PUNCTUATION SPACE..HAIR SPACE
+205F ; WSegSpace # Zs MEDIUM MATHEMATICAL SPACE
+3000 ; WSegSpace # Zs IDEOGRAPHIC SPACE
+
+# Total code points: 14
+
+# EOF
diff --git a/resources/standards-data/unicode-character-database/download.sh b/resources/standards-data/unicode-character-database/download.sh
new file mode 100755
index 0000000000..4b972e7afa
--- /dev/null
+++ b/resources/standards-data/unicode-character-database/download.sh
@@ -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
\ No newline at end of file
diff --git a/resources/standards-data/unicode-character-database/emoji-data.txt b/resources/standards-data/unicode-character-database/emoji-data.txt
new file mode 100644
index 0000000000..0ba10e9ce4
--- /dev/null
+++ b/resources/standards-data/unicode-character-database/emoji-data.txt
@@ -0,0 +1,1320 @@
+# emoji-data.txt
+# Date: 2023-02-01, 02:22:54 GMT
+# © 2023 Unicode®, Inc.
+# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
+# For terms of use, see https://www.unicode.org/terms_of_use.html
+#
+# Emoji Data for UTS #51
+# Used with Emoji Version 15.1 and subsequent minor revisions (if any)
+#
+# For documentation and usage, see https://www.unicode.org/reports/tr51
+#
+# Format:
+# ; #
+# Note: there is no guarantee as to the structure of whitespace or comments
+#
+# Characters and sequences are listed in code point order. Users should be shown a more natural order.
+# See the CLDR collation order for Emoji.
+
+
+# ================================================
+
+# All omitted code points have Emoji=No
+
+0023 ; Emoji # E0.0 [1] (#️) hash sign
+002A ; Emoji # E0.0 [1] (*️) asterisk
+0030..0039 ; Emoji # E0.0 [10] (0️..9️) digit zero..digit nine
+00A9 ; Emoji # E0.6 [1] (©️) copyright
+00AE ; Emoji # E0.6 [1] (®️) registered
+203C ; Emoji # E0.6 [1] (‼️) double exclamation mark
+2049 ; Emoji # E0.6 [1] (⁉️) exclamation question mark
+2122 ; Emoji # E0.6 [1] (™️) trade mark
+2139 ; Emoji # E0.6 [1] (ℹ️) information
+2194..2199 ; Emoji # E0.6 [6] (↔️..↙️) left-right arrow..down-left arrow
+21A9..21AA ; Emoji # E0.6 [2] (↩️..↪️) right arrow curving left..left arrow curving right
+231A..231B ; Emoji # E0.6 [2] (⌚..⌛) watch..hourglass done
+2328 ; Emoji # E1.0 [1] (⌨️) keyboard
+23CF ; Emoji # E1.0 [1] (⏏️) eject button
+23E9..23EC ; Emoji # E0.6 [4] (⏩..⏬) fast-forward button..fast down button
+23ED..23EE ; Emoji # E0.7 [2] (⏭️..⏮️) next track button..last track button
+23EF ; Emoji # E1.0 [1] (⏯️) play or pause button
+23F0 ; Emoji # E0.6 [1] (⏰) alarm clock
+23F1..23F2 ; Emoji # E1.0 [2] (⏱️..⏲️) stopwatch..timer clock
+23F3 ; Emoji # E0.6 [1] (⏳) hourglass not done
+23F8..23FA ; Emoji # E0.7 [3] (⏸️..⏺️) pause button..record button
+24C2 ; Emoji # E0.6 [1] (Ⓜ️) circled M
+25AA..25AB ; Emoji # E0.6 [2] (▪️..▫️) black small square..white small square
+25B6 ; Emoji # E0.6 [1] (▶️) play button
+25C0 ; Emoji # E0.6 [1] (◀️) reverse button
+25FB..25FE ; Emoji # E0.6 [4] (◻️..◾) white medium square..black medium-small square
+2600..2601 ; Emoji # E0.6 [2] (☀️..☁️) sun..cloud
+2602..2603 ; Emoji # E0.7 [2] (☂️..☃️) umbrella..snowman
+2604 ; Emoji # E1.0 [1] (☄️) comet
+260E ; Emoji # E0.6 [1] (☎️) telephone
+2611 ; Emoji # E0.6 [1] (☑️) check box with check
+2614..2615 ; Emoji # E0.6 [2] (☔..☕) umbrella with rain drops..hot beverage
+2618 ; Emoji # E1.0 [1] (☘️) shamrock
+261D ; Emoji # E0.6 [1] (☝️) index pointing up
+2620 ; Emoji # E1.0 [1] (☠️) skull and crossbones
+2622..2623 ; Emoji # E1.0 [2] (☢️..☣️) radioactive..biohazard
+2626 ; Emoji # E1.0 [1] (☦️) orthodox cross
+262A ; Emoji # E0.7 [1] (☪️) star and crescent
+262E ; Emoji # E1.0 [1] (☮️) peace symbol
+262F ; Emoji # E0.7 [1] (☯️) yin yang
+2638..2639 ; Emoji # E0.7 [2] (☸️..☹️) wheel of dharma..frowning face
+263A ; Emoji # E0.6 [1] (☺️) smiling face
+2640 ; Emoji # E4.0 [1] (♀️) female sign
+2642 ; Emoji # E4.0 [1] (♂️) male sign
+2648..2653 ; Emoji # E0.6 [12] (♈..♓) Aries..Pisces
+265F ; Emoji # E11.0 [1] (♟️) chess pawn
+2660 ; Emoji # E0.6 [1] (♠️) spade suit
+2663 ; Emoji # E0.6 [1] (♣️) club suit
+2665..2666 ; Emoji # E0.6 [2] (♥️..♦️) heart suit..diamond suit
+2668 ; Emoji # E0.6 [1] (♨️) hot springs
+267B ; Emoji # E0.6 [1] (♻️) recycling symbol
+267E ; Emoji # E11.0 [1] (♾️) infinity
+267F ; Emoji # E0.6 [1] (♿) wheelchair symbol
+2692 ; Emoji # E1.0 [1] (⚒️) hammer and pick
+2693 ; Emoji # E0.6 [1] (⚓) anchor
+2694 ; Emoji # E1.0 [1] (⚔️) crossed swords
+2695 ; Emoji # E4.0 [1] (⚕️) medical symbol
+2696..2697 ; Emoji # E1.0 [2] (⚖️..⚗️) balance scale..alembic
+2699 ; Emoji # E1.0 [1] (⚙️) gear
+269B..269C ; Emoji # E1.0 [2] (⚛️..⚜️) atom symbol..fleur-de-lis
+26A0..26A1 ; Emoji # E0.6 [2] (⚠️..⚡) warning..high voltage
+26A7 ; Emoji # E13.0 [1] (⚧️) transgender symbol
+26AA..26AB ; Emoji # E0.6 [2] (⚪..⚫) white circle..black circle
+26B0..26B1 ; Emoji # E1.0 [2] (⚰️..⚱️) coffin..funeral urn
+26BD..26BE ; Emoji # E0.6 [2] (⚽..⚾) soccer ball..baseball
+26C4..26C5 ; Emoji # E0.6 [2] (⛄..⛅) snowman without snow..sun behind cloud
+26C8 ; Emoji # E0.7 [1] (⛈️) cloud with lightning and rain
+26CE ; Emoji # E0.6 [1] (⛎) Ophiuchus
+26CF ; Emoji # E0.7 [1] (⛏️) pick
+26D1 ; Emoji # E0.7 [1] (⛑️) rescue worker’s helmet
+26D3 ; Emoji # E0.7 [1] (⛓️) chains
+26D4 ; Emoji # E0.6 [1] (⛔) no entry
+26E9 ; Emoji # E0.7 [1] (⛩️) shinto shrine
+26EA ; Emoji # E0.6 [1] (⛪) church
+26F0..26F1 ; Emoji # E0.7 [2] (⛰️..⛱️) mountain..umbrella on ground
+26F2..26F3 ; Emoji # E0.6 [2] (⛲..⛳) fountain..flag in hole
+26F4 ; Emoji # E0.7 [1] (⛴️) ferry
+26F5 ; Emoji # E0.6 [1] (⛵) sailboat
+26F7..26F9 ; Emoji # E0.7 [3] (⛷️..⛹️) skier..person bouncing ball
+26FA ; Emoji # E0.6 [1] (⛺) tent
+26FD ; Emoji # E0.6 [1] (⛽) fuel pump
+2702 ; Emoji # E0.6 [1] (✂️) scissors
+2705 ; Emoji # E0.6 [1] (✅) check mark button
+2708..270C ; Emoji # E0.6 [5] (✈️..✌️) airplane..victory hand
+270D ; Emoji # E0.7 [1] (✍️) writing hand
+270F ; Emoji # E0.6 [1] (✏️) pencil
+2712 ; Emoji # E0.6 [1] (✒️) black nib
+2714 ; Emoji # E0.6 [1] (✔️) check mark
+2716 ; Emoji # E0.6 [1] (✖️) multiply
+271D ; Emoji # E0.7 [1] (✝️) latin cross
+2721 ; Emoji # E0.7 [1] (✡️) star of David
+2728 ; Emoji # E0.6 [1] (✨) sparkles
+2733..2734 ; Emoji # E0.6 [2] (✳️..✴️) eight-spoked asterisk..eight-pointed star
+2744 ; Emoji # E0.6 [1] (❄️) snowflake
+2747 ; Emoji # E0.6 [1] (❇️) sparkle
+274C ; Emoji # E0.6 [1] (❌) cross mark
+274E ; Emoji # E0.6 [1] (❎) cross mark button
+2753..2755 ; Emoji # E0.6 [3] (❓..❕) red question mark..white exclamation mark
+2757 ; Emoji # E0.6 [1] (❗) red exclamation mark
+2763 ; Emoji # E1.0 [1] (❣️) heart exclamation
+2764 ; Emoji # E0.6 [1] (❤️) red heart
+2795..2797 ; Emoji # E0.6 [3] (➕..➗) plus..divide
+27A1 ; Emoji # E0.6 [1] (➡️) right arrow
+27B0 ; Emoji # E0.6 [1] (➰) curly loop
+27BF ; Emoji # E1.0 [1] (➿) double curly loop
+2934..2935 ; Emoji # E0.6 [2] (⤴️..⤵️) right arrow curving up..right arrow curving down
+2B05..2B07 ; Emoji # E0.6 [3] (⬅️..⬇️) left arrow..down arrow
+2B1B..2B1C ; Emoji # E0.6 [2] (⬛..⬜) black large square..white large square
+2B50 ; Emoji # E0.6 [1] (⭐) star
+2B55 ; Emoji # E0.6 [1] (⭕) hollow red circle
+3030 ; Emoji # E0.6 [1] (〰️) wavy dash
+303D ; Emoji # E0.6 [1] (〽️) part alternation mark
+3297 ; Emoji # E0.6 [1] (㊗️) Japanese “congratulations” button
+3299 ; Emoji # E0.6 [1] (㊙️) Japanese “secret” button
+1F004 ; Emoji # E0.6 [1] (🀄) mahjong red dragon
+1F0CF ; Emoji # E0.6 [1] (🃏) joker
+1F170..1F171 ; Emoji # E0.6 [2] (🅰️..🅱️) A button (blood type)..B button (blood type)
+1F17E..1F17F ; Emoji # E0.6 [2] (🅾️..🅿️) O button (blood type)..P button
+1F18E ; Emoji # E0.6 [1] (🆎) AB button (blood type)
+1F191..1F19A ; Emoji # E0.6 [10] (🆑..🆚) CL button..VS button
+1F1E6..1F1FF ; Emoji # E0.0 [26] (🇦..🇿) regional indicator symbol letter a..regional indicator symbol letter z
+1F201..1F202 ; Emoji # E0.6 [2] (🈁..🈂️) Japanese “here” button..Japanese “service charge” button
+1F21A ; Emoji # E0.6 [1] (🈚) Japanese “free of charge” button
+1F22F ; Emoji # E0.6 [1] (🈯) Japanese “reserved” button
+1F232..1F23A ; Emoji # E0.6 [9] (🈲..🈺) Japanese “prohibited” button..Japanese “open for business” button
+1F250..1F251 ; Emoji # E0.6 [2] (🉐..🉑) Japanese “bargain” button..Japanese “acceptable” button
+1F300..1F30C ; Emoji # E0.6 [13] (🌀..🌌) cyclone..milky way
+1F30D..1F30E ; Emoji # E0.7 [2] (🌍..🌎) globe showing Europe-Africa..globe showing Americas
+1F30F ; Emoji # E0.6 [1] (🌏) globe showing Asia-Australia
+1F310 ; Emoji # E1.0 [1] (🌐) globe with meridians
+1F311 ; Emoji # E0.6 [1] (🌑) new moon
+1F312 ; Emoji # E1.0 [1] (🌒) waxing crescent moon
+1F313..1F315 ; Emoji # E0.6 [3] (🌓..🌕) first quarter moon..full moon
+1F316..1F318 ; Emoji # E1.0 [3] (🌖..🌘) waning gibbous moon..waning crescent moon
+1F319 ; Emoji # E0.6 [1] (🌙) crescent moon
+1F31A ; Emoji # E1.0 [1] (🌚) new moon face
+1F31B ; Emoji # E0.6 [1] (🌛) first quarter moon face
+1F31C ; Emoji # E0.7 [1] (🌜) last quarter moon face
+1F31D..1F31E ; Emoji # E1.0 [2] (🌝..🌞) full moon face..sun with face
+1F31F..1F320 ; Emoji # E0.6 [2] (🌟..🌠) glowing star..shooting star
+1F321 ; Emoji # E0.7 [1] (🌡️) thermometer
+1F324..1F32C ; Emoji # E0.7 [9] (🌤️..🌬️) sun behind small cloud..wind face
+1F32D..1F32F ; Emoji # E1.0 [3] (🌭..🌯) hot dog..burrito
+1F330..1F331 ; Emoji # E0.6 [2] (🌰..🌱) chestnut..seedling
+1F332..1F333 ; Emoji # E1.0 [2] (🌲..🌳) evergreen tree..deciduous tree
+1F334..1F335 ; Emoji # E0.6 [2] (🌴..🌵) palm tree..cactus
+1F336 ; Emoji # E0.7 [1] (🌶️) hot pepper
+1F337..1F34A ; Emoji # E0.6 [20] (🌷..🍊) tulip..tangerine
+1F34B ; Emoji # E1.0 [1] (🍋) lemon
+1F34C..1F34F ; Emoji # E0.6 [4] (🍌..🍏) banana..green apple
+1F350 ; Emoji # E1.0 [1] (🍐) pear
+1F351..1F37B ; Emoji # E0.6 [43] (🍑..🍻) peach..clinking beer mugs
+1F37C ; Emoji # E1.0 [1] (🍼) baby bottle
+1F37D ; Emoji # E0.7 [1] (🍽️) fork and knife with plate
+1F37E..1F37F ; Emoji # E1.0 [2] (🍾..🍿) bottle with popping cork..popcorn
+1F380..1F393 ; Emoji # E0.6 [20] (🎀..🎓) ribbon..graduation cap
+1F396..1F397 ; Emoji # E0.7 [2] (🎖️..🎗️) military medal..reminder ribbon
+1F399..1F39B ; Emoji # E0.7 [3] (🎙️..🎛️) studio microphone..control knobs
+1F39E..1F39F ; Emoji # E0.7 [2] (🎞️..🎟️) film frames..admission tickets
+1F3A0..1F3C4 ; Emoji # E0.6 [37] (🎠..🏄) carousel horse..person surfing
+1F3C5 ; Emoji # E1.0 [1] (🏅) sports medal
+1F3C6 ; Emoji # E0.6 [1] (🏆) trophy
+1F3C7 ; Emoji # E1.0 [1] (🏇) horse racing
+1F3C8 ; Emoji # E0.6 [1] (🏈) american football
+1F3C9 ; Emoji # E1.0 [1] (🏉) rugby football
+1F3CA ; Emoji # E0.6 [1] (🏊) person swimming
+1F3CB..1F3CE ; Emoji # E0.7 [4] (🏋️..🏎️) person lifting weights..racing car
+1F3CF..1F3D3 ; Emoji # E1.0 [5] (🏏..🏓) cricket game..ping pong
+1F3D4..1F3DF ; Emoji # E0.7 [12] (🏔️..🏟️) snow-capped mountain..stadium
+1F3E0..1F3E3 ; Emoji # E0.6 [4] (🏠..🏣) house..Japanese post office
+1F3E4 ; Emoji # E1.0 [1] (🏤) post office
+1F3E5..1F3F0 ; Emoji # E0.6 [12] (🏥..🏰) hospital..castle
+1F3F3 ; Emoji # E0.7 [1] (🏳️) white flag
+1F3F4 ; Emoji # E1.0 [1] (🏴) black flag
+1F3F5 ; Emoji # E0.7 [1] (🏵️) rosette
+1F3F7 ; Emoji # E0.7 [1] (🏷️) label
+1F3F8..1F407 ; Emoji # E1.0 [16] (🏸..🐇) badminton..rabbit
+1F408 ; Emoji # E0.7 [1] (🐈) cat
+1F409..1F40B ; Emoji # E1.0 [3] (🐉..🐋) dragon..whale
+1F40C..1F40E ; Emoji # E0.6 [3] (🐌..🐎) snail..horse
+1F40F..1F410 ; Emoji # E1.0 [2] (🐏..🐐) ram..goat
+1F411..1F412 ; Emoji # E0.6 [2] (🐑..🐒) ewe..monkey
+1F413 ; Emoji # E1.0 [1] (🐓) rooster
+1F414 ; Emoji # E0.6 [1] (🐔) chicken
+1F415 ; Emoji # E0.7 [1] (🐕) dog
+1F416 ; Emoji # E1.0 [1] (🐖) pig
+1F417..1F429 ; Emoji # E0.6 [19] (🐗..🐩) boar..poodle
+1F42A ; Emoji # E1.0 [1] (🐪) camel
+1F42B..1F43E ; Emoji # E0.6 [20] (🐫..🐾) two-hump camel..paw prints
+1F43F ; Emoji # E0.7 [1] (🐿️) chipmunk
+1F440 ; Emoji # E0.6 [1] (👀) eyes
+1F441 ; Emoji # E0.7 [1] (👁️) eye
+1F442..1F464 ; Emoji # E0.6 [35] (👂..👤) ear..bust in silhouette
+1F465 ; Emoji # E1.0 [1] (👥) busts in silhouette
+1F466..1F46B ; Emoji # E0.6 [6] (👦..👫) boy..woman and man holding hands
+1F46C..1F46D ; Emoji # E1.0 [2] (👬..👭) men holding hands..women holding hands
+1F46E..1F4AC ; Emoji # E0.6 [63] (👮..💬) police officer..speech balloon
+1F4AD ; Emoji # E1.0 [1] (💭) thought balloon
+1F4AE..1F4B5 ; Emoji # E0.6 [8] (💮..💵) white flower..dollar banknote
+1F4B6..1F4B7 ; Emoji # E1.0 [2] (💶..💷) euro banknote..pound banknote
+1F4B8..1F4EB ; Emoji # E0.6 [52] (💸..📫) money with wings..closed mailbox with raised flag
+1F4EC..1F4ED ; Emoji # E0.7 [2] (📬..📭) open mailbox with raised flag..open mailbox with lowered flag
+1F4EE ; Emoji # E0.6 [1] (📮) postbox
+1F4EF ; Emoji # E1.0 [1] (📯) postal horn
+1F4F0..1F4F4 ; Emoji # E0.6 [5] (📰..📴) newspaper..mobile phone off
+1F4F5 ; Emoji # E1.0 [1] (📵) no mobile phones
+1F4F6..1F4F7 ; Emoji # E0.6 [2] (📶..📷) antenna bars..camera
+1F4F8 ; Emoji # E1.0 [1] (📸) camera with flash
+1F4F9..1F4FC ; Emoji # E0.6 [4] (📹..📼) video camera..videocassette
+1F4FD ; Emoji # E0.7 [1] (📽️) film projector
+1F4FF..1F502 ; Emoji # E1.0 [4] (📿..🔂) prayer beads..repeat single button
+1F503 ; Emoji # E0.6 [1] (🔃) clockwise vertical arrows
+1F504..1F507 ; Emoji # E1.0 [4] (🔄..🔇) counterclockwise arrows button..muted speaker
+1F508 ; Emoji # E0.7 [1] (🔈) speaker low volume
+1F509 ; Emoji # E1.0 [1] (🔉) speaker medium volume
+1F50A..1F514 ; Emoji # E0.6 [11] (🔊..🔔) speaker high volume..bell
+1F515 ; Emoji # E1.0 [1] (🔕) bell with slash
+1F516..1F52B ; Emoji # E0.6 [22] (🔖..🔫) bookmark..water pistol
+1F52C..1F52D ; Emoji # E1.0 [2] (🔬..🔭) microscope..telescope
+1F52E..1F53D ; Emoji # E0.6 [16] (🔮..🔽) crystal ball..downwards button
+1F549..1F54A ; Emoji # E0.7 [2] (🕉️..🕊️) om..dove
+1F54B..1F54E ; Emoji # E1.0 [4] (🕋..🕎) kaaba..menorah
+1F550..1F55B ; Emoji # E0.6 [12] (🕐..🕛) one o’clock..twelve o’clock
+1F55C..1F567 ; Emoji # E0.7 [12] (🕜..🕧) one-thirty..twelve-thirty
+1F56F..1F570 ; Emoji # E0.7 [2] (🕯️..🕰️) candle..mantelpiece clock
+1F573..1F579 ; Emoji # E0.7 [7] (🕳️..🕹️) hole..joystick
+1F57A ; Emoji # E3.0 [1] (🕺) man dancing
+1F587 ; Emoji # E0.7 [1] (🖇️) linked paperclips
+1F58A..1F58D ; Emoji # E0.7 [4] (🖊️..🖍️) pen..crayon
+1F590 ; Emoji # E0.7 [1] (🖐️) hand with fingers splayed
+1F595..1F596 ; Emoji # E1.0 [2] (🖕..🖖) middle finger..vulcan salute
+1F5A4 ; Emoji # E3.0 [1] (🖤) black heart
+1F5A5 ; Emoji # E0.7 [1] (🖥️) desktop computer
+1F5A8 ; Emoji # E0.7 [1] (🖨️) printer
+1F5B1..1F5B2 ; Emoji # E0.7 [2] (🖱️..🖲️) computer mouse..trackball
+1F5BC ; Emoji # E0.7 [1] (🖼️) framed picture
+1F5C2..1F5C4 ; Emoji # E0.7 [3] (🗂️..🗄️) card index dividers..file cabinet
+1F5D1..1F5D3 ; Emoji # E0.7 [3] (🗑️..🗓️) wastebasket..spiral calendar
+1F5DC..1F5DE ; Emoji # E0.7 [3] (🗜️..🗞️) clamp..rolled-up newspaper
+1F5E1 ; Emoji # E0.7 [1] (🗡️) dagger
+1F5E3 ; Emoji # E0.7 [1] (🗣️) speaking head
+1F5E8 ; Emoji # E2.0 [1] (🗨️) left speech bubble
+1F5EF ; Emoji # E0.7 [1] (🗯️) right anger bubble
+1F5F3 ; Emoji # E0.7 [1] (🗳️) ballot box with ballot
+1F5FA ; Emoji # E0.7 [1] (🗺️) world map
+1F5FB..1F5FF ; Emoji # E0.6 [5] (🗻..🗿) mount fuji..moai
+1F600 ; Emoji # E1.0 [1] (😀) grinning face
+1F601..1F606 ; Emoji # E0.6 [6] (😁..😆) beaming face with smiling eyes..grinning squinting face
+1F607..1F608 ; Emoji # E1.0 [2] (😇..😈) smiling face with halo..smiling face with horns
+1F609..1F60D ; Emoji # E0.6 [5] (😉..😍) winking face..smiling face with heart-eyes
+1F60E ; Emoji # E1.0 [1] (😎) smiling face with sunglasses
+1F60F ; Emoji # E0.6 [1] (😏) smirking face
+1F610 ; Emoji # E0.7 [1] (😐) neutral face
+1F611 ; Emoji # E1.0 [1] (😑) expressionless face
+1F612..1F614 ; Emoji # E0.6 [3] (😒..😔) unamused face..pensive face
+1F615 ; Emoji # E1.0 [1] (😕) confused face
+1F616 ; Emoji # E0.6 [1] (😖) confounded face
+1F617 ; Emoji # E1.0 [1] (😗) kissing face
+1F618 ; Emoji # E0.6 [1] (😘) face blowing a kiss
+1F619 ; Emoji # E1.0 [1] (😙) kissing face with smiling eyes
+1F61A ; Emoji # E0.6 [1] (😚) kissing face with closed eyes
+1F61B ; Emoji # E1.0 [1] (😛) face with tongue
+1F61C..1F61E ; Emoji # E0.6 [3] (😜..😞) winking face with tongue..disappointed face
+1F61F ; Emoji # E1.0 [1] (😟) worried face
+1F620..1F625 ; Emoji # E0.6 [6] (😠..😥) angry face..sad but relieved face
+1F626..1F627 ; Emoji # E1.0 [2] (😦..😧) frowning face with open mouth..anguished face
+1F628..1F62B ; Emoji # E0.6 [4] (😨..😫) fearful face..tired face
+1F62C ; Emoji # E1.0 [1] (😬) grimacing face
+1F62D ; Emoji # E0.6 [1] (😭) loudly crying face
+1F62E..1F62F ; Emoji # E1.0 [2] (😮..😯) face with open mouth..hushed face
+1F630..1F633 ; Emoji # E0.6 [4] (😰..😳) anxious face with sweat..flushed face
+1F634 ; Emoji # E1.0 [1] (😴) sleeping face
+1F635 ; Emoji # E0.6 [1] (😵) face with crossed-out eyes
+1F636 ; Emoji # E1.0 [1] (😶) face without mouth
+1F637..1F640 ; Emoji # E0.6 [10] (😷..🙀) face with medical mask..weary cat
+1F641..1F644 ; Emoji # E1.0 [4] (🙁..🙄) slightly frowning face..face with rolling eyes
+1F645..1F64F ; Emoji # E0.6 [11] (🙅..🙏) person gesturing NO..folded hands
+1F680 ; Emoji # E0.6 [1] (🚀) rocket
+1F681..1F682 ; Emoji # E1.0 [2] (🚁..🚂) helicopter..locomotive
+1F683..1F685 ; Emoji # E0.6 [3] (🚃..🚅) railway car..bullet train
+1F686 ; Emoji # E1.0 [1] (🚆) train
+1F687 ; Emoji # E0.6 [1] (🚇) metro
+1F688 ; Emoji # E1.0 [1] (🚈) light rail
+1F689 ; Emoji # E0.6 [1] (🚉) station
+1F68A..1F68B ; Emoji # E1.0 [2] (🚊..🚋) tram..tram car
+1F68C ; Emoji # E0.6 [1] (🚌) bus
+1F68D ; Emoji # E0.7 [1] (🚍) oncoming bus
+1F68E ; Emoji # E1.0 [1] (🚎) trolleybus
+1F68F ; Emoji # E0.6 [1] (🚏) bus stop
+1F690 ; Emoji # E1.0 [1] (🚐) minibus
+1F691..1F693 ; Emoji # E0.6 [3] (🚑..🚓) ambulance..police car
+1F694 ; Emoji # E0.7 [1] (🚔) oncoming police car
+1F695 ; Emoji # E0.6 [1] (🚕) taxi
+1F696 ; Emoji # E1.0 [1] (🚖) oncoming taxi
+1F697 ; Emoji # E0.6 [1] (🚗) automobile
+1F698 ; Emoji # E0.7 [1] (🚘) oncoming automobile
+1F699..1F69A ; Emoji # E0.6 [2] (🚙..🚚) sport utility vehicle..delivery truck
+1F69B..1F6A1 ; Emoji # E1.0 [7] (🚛..🚡) articulated lorry..aerial tramway
+1F6A2 ; Emoji # E0.6 [1] (🚢) ship
+1F6A3 ; Emoji # E1.0 [1] (🚣) person rowing boat
+1F6A4..1F6A5 ; Emoji # E0.6 [2] (🚤..🚥) speedboat..horizontal traffic light
+1F6A6 ; Emoji # E1.0 [1] (🚦) vertical traffic light
+1F6A7..1F6AD ; Emoji # E0.6 [7] (🚧..🚭) construction..no smoking
+1F6AE..1F6B1 ; Emoji # E1.0 [4] (🚮..🚱) litter in bin sign..non-potable water
+1F6B2 ; Emoji # E0.6 [1] (🚲) bicycle
+1F6B3..1F6B5 ; Emoji # E1.0 [3] (🚳..🚵) no bicycles..person mountain biking
+1F6B6 ; Emoji # E0.6 [1] (🚶) person walking
+1F6B7..1F6B8 ; Emoji # E1.0 [2] (🚷..🚸) no pedestrians..children crossing
+1F6B9..1F6BE ; Emoji # E0.6 [6] (🚹..🚾) men’s room..water closet
+1F6BF ; Emoji # E1.0 [1] (🚿) shower
+1F6C0 ; Emoji # E0.6 [1] (🛀) person taking bath
+1F6C1..1F6C5 ; Emoji # E1.0 [5] (🛁..🛅) bathtub..left luggage
+1F6CB ; Emoji # E0.7 [1] (🛋️) couch and lamp
+1F6CC ; Emoji # E1.0 [1] (🛌) person in bed
+1F6CD..1F6CF ; Emoji # E0.7 [3] (🛍️..🛏️) shopping bags..bed
+1F6D0 ; Emoji # E1.0 [1] (🛐) place of worship
+1F6D1..1F6D2 ; Emoji # E3.0 [2] (🛑..🛒) stop sign..shopping cart
+1F6D5 ; Emoji # E12.0 [1] (🛕) hindu temple
+1F6D6..1F6D7 ; Emoji # E13.0 [2] (🛖..🛗) hut..elevator
+1F6DC ; Emoji # E15.0 [1] (🛜) wireless
+1F6DD..1F6DF ; Emoji # E14.0 [3] (🛝..🛟) playground slide..ring buoy
+1F6E0..1F6E5 ; Emoji # E0.7 [6] (🛠️..🛥️) hammer and wrench..motor boat
+1F6E9 ; Emoji # E0.7 [1] (🛩️) small airplane
+1F6EB..1F6EC ; Emoji # E1.0 [2] (🛫..🛬) airplane departure..airplane arrival
+1F6F0 ; Emoji # E0.7 [1] (🛰️) satellite
+1F6F3 ; Emoji # E0.7 [1] (🛳️) passenger ship
+1F6F4..1F6F6 ; Emoji # E3.0 [3] (🛴..🛶) kick scooter..canoe
+1F6F7..1F6F8 ; Emoji # E5.0 [2] (🛷..🛸) sled..flying saucer
+1F6F9 ; Emoji # E11.0 [1] (🛹) skateboard
+1F6FA ; Emoji # E12.0 [1] (🛺) auto rickshaw
+1F6FB..1F6FC ; Emoji # E13.0 [2] (🛻..🛼) pickup truck..roller skate
+1F7E0..1F7EB ; Emoji # E12.0 [12] (🟠..🟫) orange circle..brown square
+1F7F0 ; Emoji # E14.0 [1] (🟰) heavy equals sign
+1F90C ; Emoji # E13.0 [1] (🤌) pinched fingers
+1F90D..1F90F ; Emoji # E12.0 [3] (🤍..🤏) white heart..pinching hand
+1F910..1F918 ; Emoji # E1.0 [9] (🤐..🤘) zipper-mouth face..sign of the horns
+1F919..1F91E ; Emoji # E3.0 [6] (🤙..🤞) call me hand..crossed fingers
+1F91F ; Emoji # E5.0 [1] (🤟) love-you gesture
+1F920..1F927 ; Emoji # E3.0 [8] (🤠..🤧) cowboy hat face..sneezing face
+1F928..1F92F ; Emoji # E5.0 [8] (🤨..🤯) face with raised eyebrow..exploding head
+1F930 ; Emoji # E3.0 [1] (🤰) pregnant woman
+1F931..1F932 ; Emoji # E5.0 [2] (🤱..🤲) breast-feeding..palms up together
+1F933..1F93A ; Emoji # E3.0 [8] (🤳..🤺) selfie..person fencing
+1F93C..1F93E ; Emoji # E3.0 [3] (🤼..🤾) people wrestling..person playing handball
+1F93F ; Emoji # E12.0 [1] (🤿) diving mask
+1F940..1F945 ; Emoji # E3.0 [6] (🥀..🥅) wilted flower..goal net
+1F947..1F94B ; Emoji # E3.0 [5] (🥇..🥋) 1st place medal..martial arts uniform
+1F94C ; Emoji # E5.0 [1] (🥌) curling stone
+1F94D..1F94F ; Emoji # E11.0 [3] (🥍..🥏) lacrosse..flying disc
+1F950..1F95E ; Emoji # E3.0 [15] (🥐..🥞) croissant..pancakes
+1F95F..1F96B ; Emoji # E5.0 [13] (🥟..🥫) dumpling..canned food
+1F96C..1F970 ; Emoji # E11.0 [5] (🥬..🥰) leafy green..smiling face with hearts
+1F971 ; Emoji # E12.0 [1] (🥱) yawning face
+1F972 ; Emoji # E13.0 [1] (🥲) smiling face with tear
+1F973..1F976 ; Emoji # E11.0 [4] (🥳..🥶) partying face..cold face
+1F977..1F978 ; Emoji # E13.0 [2] (🥷..🥸) ninja..disguised face
+1F979 ; Emoji # E14.0 [1] (🥹) face holding back tears
+1F97A ; Emoji # E11.0 [1] (🥺) pleading face
+1F97B ; Emoji # E12.0 [1] (🥻) sari
+1F97C..1F97F ; Emoji # E11.0 [4] (🥼..🥿) lab coat..flat shoe
+1F980..1F984 ; Emoji # E1.0 [5] (🦀..🦄) crab..unicorn
+1F985..1F991 ; Emoji # E3.0 [13] (🦅..🦑) eagle..squid
+1F992..1F997 ; Emoji # E5.0 [6] (🦒..🦗) giraffe..cricket
+1F998..1F9A2 ; Emoji # E11.0 [11] (🦘..🦢) kangaroo..swan
+1F9A3..1F9A4 ; Emoji # E13.0 [2] (🦣..🦤) mammoth..dodo
+1F9A5..1F9AA ; Emoji # E12.0 [6] (🦥..🦪) sloth..oyster
+1F9AB..1F9AD ; Emoji # E13.0 [3] (🦫..🦭) beaver..seal
+1F9AE..1F9AF ; Emoji # E12.0 [2] (🦮..🦯) guide dog..white cane
+1F9B0..1F9B9 ; Emoji # E11.0 [10] (🦰..🦹) red hair..supervillain
+1F9BA..1F9BF ; Emoji # E12.0 [6] (🦺..🦿) safety vest..mechanical leg
+1F9C0 ; Emoji # E1.0 [1] (🧀) cheese wedge
+1F9C1..1F9C2 ; Emoji # E11.0 [2] (🧁..🧂) cupcake..salt
+1F9C3..1F9CA ; Emoji # E12.0 [8] (🧃..🧊) beverage box..ice
+1F9CB ; Emoji # E13.0 [1] (🧋) bubble tea
+1F9CC ; Emoji # E14.0 [1] (🧌) troll
+1F9CD..1F9CF ; Emoji # E12.0 [3] (🧍..🧏) person standing..deaf person
+1F9D0..1F9E6 ; Emoji # E5.0 [23] (🧐..🧦) face with monocle..socks
+1F9E7..1F9FF ; Emoji # E11.0 [25] (🧧..🧿) red envelope..nazar amulet
+1FA70..1FA73 ; Emoji # E12.0 [4] (🩰..🩳) ballet shoes..shorts
+1FA74 ; Emoji # E13.0 [1] (🩴) thong sandal
+1FA75..1FA77 ; Emoji # E15.0 [3] (🩵..🩷) light blue heart..pink heart
+1FA78..1FA7A ; Emoji # E12.0 [3] (🩸..🩺) drop of blood..stethoscope
+1FA7B..1FA7C ; Emoji # E14.0 [2] (🩻..🩼) x-ray..crutch
+1FA80..1FA82 ; Emoji # E12.0 [3] (🪀..🪂) yo-yo..parachute
+1FA83..1FA86 ; Emoji # E13.0 [4] (🪃..🪆) boomerang..nesting dolls
+1FA87..1FA88 ; Emoji # E15.0 [2] (🪇..🪈) maracas..flute
+1FA90..1FA95 ; Emoji # E12.0 [6] (🪐..🪕) ringed planet..banjo
+1FA96..1FAA8 ; Emoji # E13.0 [19] (🪖..🪨) military helmet..rock
+1FAA9..1FAAC ; Emoji # E14.0 [4] (🪩..🪬) mirror ball..hamsa
+1FAAD..1FAAF ; Emoji # E15.0 [3] (🪭..🪯) folding hand fan..khanda
+1FAB0..1FAB6 ; Emoji # E13.0 [7] (🪰..🪶) fly..feather
+1FAB7..1FABA ; Emoji # E14.0 [4] (🪷..🪺) lotus..nest with eggs
+1FABB..1FABD ; Emoji # E15.0 [3] (🪻..🪽) hyacinth..wing
+1FABF ; Emoji # E15.0 [1] (🪿) goose
+1FAC0..1FAC2 ; Emoji # E13.0 [3] (🫀..🫂) anatomical heart..people hugging
+1FAC3..1FAC5 ; Emoji # E14.0 [3] (🫃..🫅) pregnant man..person with crown
+1FACE..1FACF ; Emoji # E15.0 [2] (🫎..🫏) moose..donkey
+1FAD0..1FAD6 ; Emoji # E13.0 [7] (🫐..🫖) blueberries..teapot
+1FAD7..1FAD9 ; Emoji # E14.0 [3] (🫗..🫙) pouring liquid..jar
+1FADA..1FADB ; Emoji # E15.0 [2] (🫚..🫛) ginger root..pea pod
+1FAE0..1FAE7 ; Emoji # E14.0 [8] (🫠..🫧) melting face..bubbles
+1FAE8 ; Emoji # E15.0 [1] (🫨) shaking face
+1FAF0..1FAF6 ; Emoji # E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands
+1FAF7..1FAF8 ; Emoji # E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand
+
+# Total elements: 1424
+
+# ================================================
+
+# All omitted code points have Emoji_Presentation=No
+
+231A..231B ; Emoji_Presentation # E0.6 [2] (⌚..⌛) watch..hourglass done
+23E9..23EC ; Emoji_Presentation # E0.6 [4] (⏩..⏬) fast-forward button..fast down button
+23F0 ; Emoji_Presentation # E0.6 [1] (⏰) alarm clock
+23F3 ; Emoji_Presentation # E0.6 [1] (⏳) hourglass not done
+25FD..25FE ; Emoji_Presentation # E0.6 [2] (◽..◾) white medium-small square..black medium-small square
+2614..2615 ; Emoji_Presentation # E0.6 [2] (☔..☕) umbrella with rain drops..hot beverage
+2648..2653 ; Emoji_Presentation # E0.6 [12] (♈..♓) Aries..Pisces
+267F ; Emoji_Presentation # E0.6 [1] (♿) wheelchair symbol
+2693 ; Emoji_Presentation # E0.6 [1] (⚓) anchor
+26A1 ; Emoji_Presentation # E0.6 [1] (⚡) high voltage
+26AA..26AB ; Emoji_Presentation # E0.6 [2] (⚪..⚫) white circle..black circle
+26BD..26BE ; Emoji_Presentation # E0.6 [2] (⚽..⚾) soccer ball..baseball
+26C4..26C5 ; Emoji_Presentation # E0.6 [2] (⛄..⛅) snowman without snow..sun behind cloud
+26CE ; Emoji_Presentation # E0.6 [1] (⛎) Ophiuchus
+26D4 ; Emoji_Presentation # E0.6 [1] (⛔) no entry
+26EA ; Emoji_Presentation # E0.6 [1] (⛪) church
+26F2..26F3 ; Emoji_Presentation # E0.6 [2] (⛲..⛳) fountain..flag in hole
+26F5 ; Emoji_Presentation # E0.6 [1] (⛵) sailboat
+26FA ; Emoji_Presentation # E0.6 [1] (⛺) tent
+26FD ; Emoji_Presentation # E0.6 [1] (⛽) fuel pump
+2705 ; Emoji_Presentation # E0.6 [1] (✅) check mark button
+270A..270B ; Emoji_Presentation # E0.6 [2] (✊..✋) raised fist..raised hand
+2728 ; Emoji_Presentation # E0.6 [1] (✨) sparkles
+274C ; Emoji_Presentation # E0.6 [1] (❌) cross mark
+274E ; Emoji_Presentation # E0.6 [1] (❎) cross mark button
+2753..2755 ; Emoji_Presentation # E0.6 [3] (❓..❕) red question mark..white exclamation mark
+2757 ; Emoji_Presentation # E0.6 [1] (❗) red exclamation mark
+2795..2797 ; Emoji_Presentation # E0.6 [3] (➕..➗) plus..divide
+27B0 ; Emoji_Presentation # E0.6 [1] (➰) curly loop
+27BF ; Emoji_Presentation # E1.0 [1] (➿) double curly loop
+2B1B..2B1C ; Emoji_Presentation # E0.6 [2] (⬛..⬜) black large square..white large square
+2B50 ; Emoji_Presentation # E0.6 [1] (⭐) star
+2B55 ; Emoji_Presentation # E0.6 [1] (⭕) hollow red circle
+1F004 ; Emoji_Presentation # E0.6 [1] (🀄) mahjong red dragon
+1F0CF ; Emoji_Presentation # E0.6 [1] (🃏) joker
+1F18E ; Emoji_Presentation # E0.6 [1] (🆎) AB button (blood type)
+1F191..1F19A ; Emoji_Presentation # E0.6 [10] (🆑..🆚) CL button..VS button
+1F1E6..1F1FF ; Emoji_Presentation # E0.0 [26] (🇦..🇿) regional indicator symbol letter a..regional indicator symbol letter z
+1F201 ; Emoji_Presentation # E0.6 [1] (🈁) Japanese “here” button
+1F21A ; Emoji_Presentation # E0.6 [1] (🈚) Japanese “free of charge” button
+1F22F ; Emoji_Presentation # E0.6 [1] (🈯) Japanese “reserved” button
+1F232..1F236 ; Emoji_Presentation # E0.6 [5] (🈲..🈶) Japanese “prohibited” button..Japanese “not free of charge” button
+1F238..1F23A ; Emoji_Presentation # E0.6 [3] (🈸..🈺) Japanese “application” button..Japanese “open for business” button
+1F250..1F251 ; Emoji_Presentation # E0.6 [2] (🉐..🉑) Japanese “bargain” button..Japanese “acceptable” button
+1F300..1F30C ; Emoji_Presentation # E0.6 [13] (🌀..🌌) cyclone..milky way
+1F30D..1F30E ; Emoji_Presentation # E0.7 [2] (🌍..🌎) globe showing Europe-Africa..globe showing Americas
+1F30F ; Emoji_Presentation # E0.6 [1] (🌏) globe showing Asia-Australia
+1F310 ; Emoji_Presentation # E1.0 [1] (🌐) globe with meridians
+1F311 ; Emoji_Presentation # E0.6 [1] (🌑) new moon
+1F312 ; Emoji_Presentation # E1.0 [1] (🌒) waxing crescent moon
+1F313..1F315 ; Emoji_Presentation # E0.6 [3] (🌓..🌕) first quarter moon..full moon
+1F316..1F318 ; Emoji_Presentation # E1.0 [3] (🌖..🌘) waning gibbous moon..waning crescent moon
+1F319 ; Emoji_Presentation # E0.6 [1] (🌙) crescent moon
+1F31A ; Emoji_Presentation # E1.0 [1] (🌚) new moon face
+1F31B ; Emoji_Presentation # E0.6 [1] (🌛) first quarter moon face
+1F31C ; Emoji_Presentation # E0.7 [1] (🌜) last quarter moon face
+1F31D..1F31E ; Emoji_Presentation # E1.0 [2] (🌝..🌞) full moon face..sun with face
+1F31F..1F320 ; Emoji_Presentation # E0.6 [2] (🌟..🌠) glowing star..shooting star
+1F32D..1F32F ; Emoji_Presentation # E1.0 [3] (🌭..🌯) hot dog..burrito
+1F330..1F331 ; Emoji_Presentation # E0.6 [2] (🌰..🌱) chestnut..seedling
+1F332..1F333 ; Emoji_Presentation # E1.0 [2] (🌲..🌳) evergreen tree..deciduous tree
+1F334..1F335 ; Emoji_Presentation # E0.6 [2] (🌴..🌵) palm tree..cactus
+1F337..1F34A ; Emoji_Presentation # E0.6 [20] (🌷..🍊) tulip..tangerine
+1F34B ; Emoji_Presentation # E1.0 [1] (🍋) lemon
+1F34C..1F34F ; Emoji_Presentation # E0.6 [4] (🍌..🍏) banana..green apple
+1F350 ; Emoji_Presentation # E1.0 [1] (🍐) pear
+1F351..1F37B ; Emoji_Presentation # E0.6 [43] (🍑..🍻) peach..clinking beer mugs
+1F37C ; Emoji_Presentation # E1.0 [1] (🍼) baby bottle
+1F37E..1F37F ; Emoji_Presentation # E1.0 [2] (🍾..🍿) bottle with popping cork..popcorn
+1F380..1F393 ; Emoji_Presentation # E0.6 [20] (🎀..🎓) ribbon..graduation cap
+1F3A0..1F3C4 ; Emoji_Presentation # E0.6 [37] (🎠..🏄) carousel horse..person surfing
+1F3C5 ; Emoji_Presentation # E1.0 [1] (🏅) sports medal
+1F3C6 ; Emoji_Presentation # E0.6 [1] (🏆) trophy
+1F3C7 ; Emoji_Presentation # E1.0 [1] (🏇) horse racing
+1F3C8 ; Emoji_Presentation # E0.6 [1] (🏈) american football
+1F3C9 ; Emoji_Presentation # E1.0 [1] (🏉) rugby football
+1F3CA ; Emoji_Presentation # E0.6 [1] (🏊) person swimming
+1F3CF..1F3D3 ; Emoji_Presentation # E1.0 [5] (🏏..🏓) cricket game..ping pong
+1F3E0..1F3E3 ; Emoji_Presentation # E0.6 [4] (🏠..🏣) house..Japanese post office
+1F3E4 ; Emoji_Presentation # E1.0 [1] (🏤) post office
+1F3E5..1F3F0 ; Emoji_Presentation # E0.6 [12] (🏥..🏰) hospital..castle
+1F3F4 ; Emoji_Presentation # E1.0 [1] (🏴) black flag
+1F3F8..1F407 ; Emoji_Presentation # E1.0 [16] (🏸..🐇) badminton..rabbit
+1F408 ; Emoji_Presentation # E0.7 [1] (🐈) cat
+1F409..1F40B ; Emoji_Presentation # E1.0 [3] (🐉..🐋) dragon..whale
+1F40C..1F40E ; Emoji_Presentation # E0.6 [3] (🐌..🐎) snail..horse
+1F40F..1F410 ; Emoji_Presentation # E1.0 [2] (🐏..🐐) ram..goat
+1F411..1F412 ; Emoji_Presentation # E0.6 [2] (🐑..🐒) ewe..monkey
+1F413 ; Emoji_Presentation # E1.0 [1] (🐓) rooster
+1F414 ; Emoji_Presentation # E0.6 [1] (🐔) chicken
+1F415 ; Emoji_Presentation # E0.7 [1] (🐕) dog
+1F416 ; Emoji_Presentation # E1.0 [1] (🐖) pig
+1F417..1F429 ; Emoji_Presentation # E0.6 [19] (🐗..🐩) boar..poodle
+1F42A ; Emoji_Presentation # E1.0 [1] (🐪) camel
+1F42B..1F43E ; Emoji_Presentation # E0.6 [20] (🐫..🐾) two-hump camel..paw prints
+1F440 ; Emoji_Presentation # E0.6 [1] (👀) eyes
+1F442..1F464 ; Emoji_Presentation # E0.6 [35] (👂..👤) ear..bust in silhouette
+1F465 ; Emoji_Presentation # E1.0 [1] (👥) busts in silhouette
+1F466..1F46B ; Emoji_Presentation # E0.6 [6] (👦..👫) boy..woman and man holding hands
+1F46C..1F46D ; Emoji_Presentation # E1.0 [2] (👬..👭) men holding hands..women holding hands
+1F46E..1F4AC ; Emoji_Presentation # E0.6 [63] (👮..💬) police officer..speech balloon
+1F4AD ; Emoji_Presentation # E1.0 [1] (💭) thought balloon
+1F4AE..1F4B5 ; Emoji_Presentation # E0.6 [8] (💮..💵) white flower..dollar banknote
+1F4B6..1F4B7 ; Emoji_Presentation # E1.0 [2] (💶..💷) euro banknote..pound banknote
+1F4B8..1F4EB ; Emoji_Presentation # E0.6 [52] (💸..📫) money with wings..closed mailbox with raised flag
+1F4EC..1F4ED ; Emoji_Presentation # E0.7 [2] (📬..📭) open mailbox with raised flag..open mailbox with lowered flag
+1F4EE ; Emoji_Presentation # E0.6 [1] (📮) postbox
+1F4EF ; Emoji_Presentation # E1.0 [1] (📯) postal horn
+1F4F0..1F4F4 ; Emoji_Presentation # E0.6 [5] (📰..📴) newspaper..mobile phone off
+1F4F5 ; Emoji_Presentation # E1.0 [1] (📵) no mobile phones
+1F4F6..1F4F7 ; Emoji_Presentation # E0.6 [2] (📶..📷) antenna bars..camera
+1F4F8 ; Emoji_Presentation # E1.0 [1] (📸) camera with flash
+1F4F9..1F4FC ; Emoji_Presentation # E0.6 [4] (📹..📼) video camera..videocassette
+1F4FF..1F502 ; Emoji_Presentation # E1.0 [4] (📿..🔂) prayer beads..repeat single button
+1F503 ; Emoji_Presentation # E0.6 [1] (🔃) clockwise vertical arrows
+1F504..1F507 ; Emoji_Presentation # E1.0 [4] (🔄..🔇) counterclockwise arrows button..muted speaker
+1F508 ; Emoji_Presentation # E0.7 [1] (🔈) speaker low volume
+1F509 ; Emoji_Presentation # E1.0 [1] (🔉) speaker medium volume
+1F50A..1F514 ; Emoji_Presentation # E0.6 [11] (🔊..🔔) speaker high volume..bell
+1F515 ; Emoji_Presentation # E1.0 [1] (🔕) bell with slash
+1F516..1F52B ; Emoji_Presentation # E0.6 [22] (🔖..🔫) bookmark..water pistol
+1F52C..1F52D ; Emoji_Presentation # E1.0 [2] (🔬..🔭) microscope..telescope
+1F52E..1F53D ; Emoji_Presentation # E0.6 [16] (🔮..🔽) crystal ball..downwards button
+1F54B..1F54E ; Emoji_Presentation # E1.0 [4] (🕋..🕎) kaaba..menorah
+1F550..1F55B ; Emoji_Presentation # E0.6 [12] (🕐..🕛) one o’clock..twelve o’clock
+1F55C..1F567 ; Emoji_Presentation # E0.7 [12] (🕜..🕧) one-thirty..twelve-thirty
+1F57A ; Emoji_Presentation # E3.0 [1] (🕺) man dancing
+1F595..1F596 ; Emoji_Presentation # E1.0 [2] (🖕..🖖) middle finger..vulcan salute
+1F5A4 ; Emoji_Presentation # E3.0 [1] (🖤) black heart
+1F5FB..1F5FF ; Emoji_Presentation # E0.6 [5] (🗻..🗿) mount fuji..moai
+1F600 ; Emoji_Presentation # E1.0 [1] (😀) grinning face
+1F601..1F606 ; Emoji_Presentation # E0.6 [6] (😁..😆) beaming face with smiling eyes..grinning squinting face
+1F607..1F608 ; Emoji_Presentation # E1.0 [2] (😇..😈) smiling face with halo..smiling face with horns
+1F609..1F60D ; Emoji_Presentation # E0.6 [5] (😉..😍) winking face..smiling face with heart-eyes
+1F60E ; Emoji_Presentation # E1.0 [1] (😎) smiling face with sunglasses
+1F60F ; Emoji_Presentation # E0.6 [1] (😏) smirking face
+1F610 ; Emoji_Presentation # E0.7 [1] (😐) neutral face
+1F611 ; Emoji_Presentation # E1.0 [1] (😑) expressionless face
+1F612..1F614 ; Emoji_Presentation # E0.6 [3] (😒..😔) unamused face..pensive face
+1F615 ; Emoji_Presentation # E1.0 [1] (😕) confused face
+1F616 ; Emoji_Presentation # E0.6 [1] (😖) confounded face
+1F617 ; Emoji_Presentation # E1.0 [1] (😗) kissing face
+1F618 ; Emoji_Presentation # E0.6 [1] (😘) face blowing a kiss
+1F619 ; Emoji_Presentation # E1.0 [1] (😙) kissing face with smiling eyes
+1F61A ; Emoji_Presentation # E0.6 [1] (😚) kissing face with closed eyes
+1F61B ; Emoji_Presentation # E1.0 [1] (😛) face with tongue
+1F61C..1F61E ; Emoji_Presentation # E0.6 [3] (😜..😞) winking face with tongue..disappointed face
+1F61F ; Emoji_Presentation # E1.0 [1] (😟) worried face
+1F620..1F625 ; Emoji_Presentation # E0.6 [6] (😠..😥) angry face..sad but relieved face
+1F626..1F627 ; Emoji_Presentation # E1.0 [2] (😦..😧) frowning face with open mouth..anguished face
+1F628..1F62B ; Emoji_Presentation # E0.6 [4] (😨..😫) fearful face..tired face
+1F62C ; Emoji_Presentation # E1.0 [1] (😬) grimacing face
+1F62D ; Emoji_Presentation # E0.6 [1] (😭) loudly crying face
+1F62E..1F62F ; Emoji_Presentation # E1.0 [2] (😮..😯) face with open mouth..hushed face
+1F630..1F633 ; Emoji_Presentation # E0.6 [4] (😰..😳) anxious face with sweat..flushed face
+1F634 ; Emoji_Presentation # E1.0 [1] (😴) sleeping face
+1F635 ; Emoji_Presentation # E0.6 [1] (😵) face with crossed-out eyes
+1F636 ; Emoji_Presentation # E1.0 [1] (😶) face without mouth
+1F637..1F640 ; Emoji_Presentation # E0.6 [10] (😷..🙀) face with medical mask..weary cat
+1F641..1F644 ; Emoji_Presentation # E1.0 [4] (🙁..🙄) slightly frowning face..face with rolling eyes
+1F645..1F64F ; Emoji_Presentation # E0.6 [11] (🙅..🙏) person gesturing NO..folded hands
+1F680 ; Emoji_Presentation # E0.6 [1] (🚀) rocket
+1F681..1F682 ; Emoji_Presentation # E1.0 [2] (🚁..🚂) helicopter..locomotive
+1F683..1F685 ; Emoji_Presentation # E0.6 [3] (🚃..🚅) railway car..bullet train
+1F686 ; Emoji_Presentation # E1.0 [1] (🚆) train
+1F687 ; Emoji_Presentation # E0.6 [1] (🚇) metro
+1F688 ; Emoji_Presentation # E1.0 [1] (🚈) light rail
+1F689 ; Emoji_Presentation # E0.6 [1] (🚉) station
+1F68A..1F68B ; Emoji_Presentation # E1.0 [2] (🚊..🚋) tram..tram car
+1F68C ; Emoji_Presentation # E0.6 [1] (🚌) bus
+1F68D ; Emoji_Presentation # E0.7 [1] (🚍) oncoming bus
+1F68E ; Emoji_Presentation # E1.0 [1] (🚎) trolleybus
+1F68F ; Emoji_Presentation # E0.6 [1] (🚏) bus stop
+1F690 ; Emoji_Presentation # E1.0 [1] (🚐) minibus
+1F691..1F693 ; Emoji_Presentation # E0.6 [3] (🚑..🚓) ambulance..police car
+1F694 ; Emoji_Presentation # E0.7 [1] (🚔) oncoming police car
+1F695 ; Emoji_Presentation # E0.6 [1] (🚕) taxi
+1F696 ; Emoji_Presentation # E1.0 [1] (🚖) oncoming taxi
+1F697 ; Emoji_Presentation # E0.6 [1] (🚗) automobile
+1F698 ; Emoji_Presentation # E0.7 [1] (🚘) oncoming automobile
+1F699..1F69A ; Emoji_Presentation # E0.6 [2] (🚙..🚚) sport utility vehicle..delivery truck
+1F69B..1F6A1 ; Emoji_Presentation # E1.0 [7] (🚛..🚡) articulated lorry..aerial tramway
+1F6A2 ; Emoji_Presentation # E0.6 [1] (🚢) ship
+1F6A3 ; Emoji_Presentation # E1.0 [1] (🚣) person rowing boat
+1F6A4..1F6A5 ; Emoji_Presentation # E0.6 [2] (🚤..🚥) speedboat..horizontal traffic light
+1F6A6 ; Emoji_Presentation # E1.0 [1] (🚦) vertical traffic light
+1F6A7..1F6AD ; Emoji_Presentation # E0.6 [7] (🚧..🚭) construction..no smoking
+1F6AE..1F6B1 ; Emoji_Presentation # E1.0 [4] (🚮..🚱) litter in bin sign..non-potable water
+1F6B2 ; Emoji_Presentation # E0.6 [1] (🚲) bicycle
+1F6B3..1F6B5 ; Emoji_Presentation # E1.0 [3] (🚳..🚵) no bicycles..person mountain biking
+1F6B6 ; Emoji_Presentation # E0.6 [1] (🚶) person walking
+1F6B7..1F6B8 ; Emoji_Presentation # E1.0 [2] (🚷..🚸) no pedestrians..children crossing
+1F6B9..1F6BE ; Emoji_Presentation # E0.6 [6] (🚹..🚾) men’s room..water closet
+1F6BF ; Emoji_Presentation # E1.0 [1] (🚿) shower
+1F6C0 ; Emoji_Presentation # E0.6 [1] (🛀) person taking bath
+1F6C1..1F6C5 ; Emoji_Presentation # E1.0 [5] (🛁..🛅) bathtub..left luggage
+1F6CC ; Emoji_Presentation # E1.0 [1] (🛌) person in bed
+1F6D0 ; Emoji_Presentation # E1.0 [1] (🛐) place of worship
+1F6D1..1F6D2 ; Emoji_Presentation # E3.0 [2] (🛑..🛒) stop sign..shopping cart
+1F6D5 ; Emoji_Presentation # E12.0 [1] (🛕) hindu temple
+1F6D6..1F6D7 ; Emoji_Presentation # E13.0 [2] (🛖..🛗) hut..elevator
+1F6DC ; Emoji_Presentation # E15.0 [1] (🛜) wireless
+1F6DD..1F6DF ; Emoji_Presentation # E14.0 [3] (🛝..🛟) playground slide..ring buoy
+1F6EB..1F6EC ; Emoji_Presentation # E1.0 [2] (🛫..🛬) airplane departure..airplane arrival
+1F6F4..1F6F6 ; Emoji_Presentation # E3.0 [3] (🛴..🛶) kick scooter..canoe
+1F6F7..1F6F8 ; Emoji_Presentation # E5.0 [2] (🛷..🛸) sled..flying saucer
+1F6F9 ; Emoji_Presentation # E11.0 [1] (🛹) skateboard
+1F6FA ; Emoji_Presentation # E12.0 [1] (🛺) auto rickshaw
+1F6FB..1F6FC ; Emoji_Presentation # E13.0 [2] (🛻..🛼) pickup truck..roller skate
+1F7E0..1F7EB ; Emoji_Presentation # E12.0 [12] (🟠..🟫) orange circle..brown square
+1F7F0 ; Emoji_Presentation # E14.0 [1] (🟰) heavy equals sign
+1F90C ; Emoji_Presentation # E13.0 [1] (🤌) pinched fingers
+1F90D..1F90F ; Emoji_Presentation # E12.0 [3] (🤍..🤏) white heart..pinching hand
+1F910..1F918 ; Emoji_Presentation # E1.0 [9] (🤐..🤘) zipper-mouth face..sign of the horns
+1F919..1F91E ; Emoji_Presentation # E3.0 [6] (🤙..🤞) call me hand..crossed fingers
+1F91F ; Emoji_Presentation # E5.0 [1] (🤟) love-you gesture
+1F920..1F927 ; Emoji_Presentation # E3.0 [8] (🤠..🤧) cowboy hat face..sneezing face
+1F928..1F92F ; Emoji_Presentation # E5.0 [8] (🤨..🤯) face with raised eyebrow..exploding head
+1F930 ; Emoji_Presentation # E3.0 [1] (🤰) pregnant woman
+1F931..1F932 ; Emoji_Presentation # E5.0 [2] (🤱..🤲) breast-feeding..palms up together
+1F933..1F93A ; Emoji_Presentation # E3.0 [8] (🤳..🤺) selfie..person fencing
+1F93C..1F93E ; Emoji_Presentation # E3.0 [3] (🤼..🤾) people wrestling..person playing handball
+1F93F ; Emoji_Presentation # E12.0 [1] (🤿) diving mask
+1F940..1F945 ; Emoji_Presentation # E3.0 [6] (🥀..🥅) wilted flower..goal net
+1F947..1F94B ; Emoji_Presentation # E3.0 [5] (🥇..🥋) 1st place medal..martial arts uniform
+1F94C ; Emoji_Presentation # E5.0 [1] (🥌) curling stone
+1F94D..1F94F ; Emoji_Presentation # E11.0 [3] (🥍..🥏) lacrosse..flying disc
+1F950..1F95E ; Emoji_Presentation # E3.0 [15] (🥐..🥞) croissant..pancakes
+1F95F..1F96B ; Emoji_Presentation # E5.0 [13] (🥟..🥫) dumpling..canned food
+1F96C..1F970 ; Emoji_Presentation # E11.0 [5] (🥬..🥰) leafy green..smiling face with hearts
+1F971 ; Emoji_Presentation # E12.0 [1] (🥱) yawning face
+1F972 ; Emoji_Presentation # E13.0 [1] (🥲) smiling face with tear
+1F973..1F976 ; Emoji_Presentation # E11.0 [4] (🥳..🥶) partying face..cold face
+1F977..1F978 ; Emoji_Presentation # E13.0 [2] (🥷..🥸) ninja..disguised face
+1F979 ; Emoji_Presentation # E14.0 [1] (🥹) face holding back tears
+1F97A ; Emoji_Presentation # E11.0 [1] (🥺) pleading face
+1F97B ; Emoji_Presentation # E12.0 [1] (🥻) sari
+1F97C..1F97F ; Emoji_Presentation # E11.0 [4] (🥼..🥿) lab coat..flat shoe
+1F980..1F984 ; Emoji_Presentation # E1.0 [5] (🦀..🦄) crab..unicorn
+1F985..1F991 ; Emoji_Presentation # E3.0 [13] (🦅..🦑) eagle..squid
+1F992..1F997 ; Emoji_Presentation # E5.0 [6] (🦒..🦗) giraffe..cricket
+1F998..1F9A2 ; Emoji_Presentation # E11.0 [11] (🦘..🦢) kangaroo..swan
+1F9A3..1F9A4 ; Emoji_Presentation # E13.0 [2] (🦣..🦤) mammoth..dodo
+1F9A5..1F9AA ; Emoji_Presentation # E12.0 [6] (🦥..🦪) sloth..oyster
+1F9AB..1F9AD ; Emoji_Presentation # E13.0 [3] (🦫..🦭) beaver..seal
+1F9AE..1F9AF ; Emoji_Presentation # E12.0 [2] (🦮..🦯) guide dog..white cane
+1F9B0..1F9B9 ; Emoji_Presentation # E11.0 [10] (🦰..🦹) red hair..supervillain
+1F9BA..1F9BF ; Emoji_Presentation # E12.0 [6] (🦺..🦿) safety vest..mechanical leg
+1F9C0 ; Emoji_Presentation # E1.0 [1] (🧀) cheese wedge
+1F9C1..1F9C2 ; Emoji_Presentation # E11.0 [2] (🧁..🧂) cupcake..salt
+1F9C3..1F9CA ; Emoji_Presentation # E12.0 [8] (🧃..🧊) beverage box..ice
+1F9CB ; Emoji_Presentation # E13.0 [1] (🧋) bubble tea
+1F9CC ; Emoji_Presentation # E14.0 [1] (🧌) troll
+1F9CD..1F9CF ; Emoji_Presentation # E12.0 [3] (🧍..🧏) person standing..deaf person
+1F9D0..1F9E6 ; Emoji_Presentation # E5.0 [23] (🧐..🧦) face with monocle..socks
+1F9E7..1F9FF ; Emoji_Presentation # E11.0 [25] (🧧..🧿) red envelope..nazar amulet
+1FA70..1FA73 ; Emoji_Presentation # E12.0 [4] (🩰..🩳) ballet shoes..shorts
+1FA74 ; Emoji_Presentation # E13.0 [1] (🩴) thong sandal
+1FA75..1FA77 ; Emoji_Presentation # E15.0 [3] (🩵..🩷) light blue heart..pink heart
+1FA78..1FA7A ; Emoji_Presentation # E12.0 [3] (🩸..🩺) drop of blood..stethoscope
+1FA7B..1FA7C ; Emoji_Presentation # E14.0 [2] (🩻..🩼) x-ray..crutch
+1FA80..1FA82 ; Emoji_Presentation # E12.0 [3] (🪀..🪂) yo-yo..parachute
+1FA83..1FA86 ; Emoji_Presentation # E13.0 [4] (🪃..🪆) boomerang..nesting dolls
+1FA87..1FA88 ; Emoji_Presentation # E15.0 [2] (🪇..🪈) maracas..flute
+1FA90..1FA95 ; Emoji_Presentation # E12.0 [6] (🪐..🪕) ringed planet..banjo
+1FA96..1FAA8 ; Emoji_Presentation # E13.0 [19] (🪖..🪨) military helmet..rock
+1FAA9..1FAAC ; Emoji_Presentation # E14.0 [4] (🪩..🪬) mirror ball..hamsa
+1FAAD..1FAAF ; Emoji_Presentation # E15.0 [3] (🪭..🪯) folding hand fan..khanda
+1FAB0..1FAB6 ; Emoji_Presentation # E13.0 [7] (🪰..🪶) fly..feather
+1FAB7..1FABA ; Emoji_Presentation # E14.0 [4] (🪷..🪺) lotus..nest with eggs
+1FABB..1FABD ; Emoji_Presentation # E15.0 [3] (🪻..🪽) hyacinth..wing
+1FABF ; Emoji_Presentation # E15.0 [1] (🪿) goose
+1FAC0..1FAC2 ; Emoji_Presentation # E13.0 [3] (🫀..🫂) anatomical heart..people hugging
+1FAC3..1FAC5 ; Emoji_Presentation # E14.0 [3] (🫃..🫅) pregnant man..person with crown
+1FACE..1FACF ; Emoji_Presentation # E15.0 [2] (🫎..🫏) moose..donkey
+1FAD0..1FAD6 ; Emoji_Presentation # E13.0 [7] (🫐..🫖) blueberries..teapot
+1FAD7..1FAD9 ; Emoji_Presentation # E14.0 [3] (🫗..🫙) pouring liquid..jar
+1FADA..1FADB ; Emoji_Presentation # E15.0 [2] (🫚..🫛) ginger root..pea pod
+1FAE0..1FAE7 ; Emoji_Presentation # E14.0 [8] (🫠..🫧) melting face..bubbles
+1FAE8 ; Emoji_Presentation # E15.0 [1] (🫨) shaking face
+1FAF0..1FAF6 ; Emoji_Presentation # E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands
+1FAF7..1FAF8 ; Emoji_Presentation # E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand
+
+# Total elements: 1205
+
+# ================================================
+
+# All omitted code points have Emoji_Modifier=No
+
+1F3FB..1F3FF ; Emoji_Modifier # E1.0 [5] (🏻..🏿) light skin tone..dark skin tone
+
+# Total elements: 5
+
+# ================================================
+
+# All omitted code points have Emoji_Modifier_Base=No
+
+261D ; Emoji_Modifier_Base # E0.6 [1] (☝️) index pointing up
+26F9 ; Emoji_Modifier_Base # E0.7 [1] (⛹️) person bouncing ball
+270A..270C ; Emoji_Modifier_Base # E0.6 [3] (✊..✌️) raised fist..victory hand
+270D ; Emoji_Modifier_Base # E0.7 [1] (✍️) writing hand
+1F385 ; Emoji_Modifier_Base # E0.6 [1] (🎅) Santa Claus
+1F3C2..1F3C4 ; Emoji_Modifier_Base # E0.6 [3] (🏂..🏄) snowboarder..person surfing
+1F3C7 ; Emoji_Modifier_Base # E1.0 [1] (🏇) horse racing
+1F3CA ; Emoji_Modifier_Base # E0.6 [1] (🏊) person swimming
+1F3CB..1F3CC ; Emoji_Modifier_Base # E0.7 [2] (🏋️..🏌️) person lifting weights..person golfing
+1F442..1F443 ; Emoji_Modifier_Base # E0.6 [2] (👂..👃) ear..nose
+1F446..1F450 ; Emoji_Modifier_Base # E0.6 [11] (👆..👐) backhand index pointing up..open hands
+1F466..1F46B ; Emoji_Modifier_Base # E0.6 [6] (👦..👫) boy..woman and man holding hands
+1F46C..1F46D ; Emoji_Modifier_Base # E1.0 [2] (👬..👭) men holding hands..women holding hands
+1F46E..1F478 ; Emoji_Modifier_Base # E0.6 [11] (👮..👸) police officer..princess
+1F47C ; Emoji_Modifier_Base # E0.6 [1] (👼) baby angel
+1F481..1F483 ; Emoji_Modifier_Base # E0.6 [3] (💁..💃) person tipping hand..woman dancing
+1F485..1F487 ; Emoji_Modifier_Base # E0.6 [3] (💅..💇) nail polish..person getting haircut
+1F48F ; Emoji_Modifier_Base # E0.6 [1] (💏) kiss
+1F491 ; Emoji_Modifier_Base # E0.6 [1] (💑) couple with heart
+1F4AA ; Emoji_Modifier_Base # E0.6 [1] (💪) flexed biceps
+1F574..1F575 ; Emoji_Modifier_Base # E0.7 [2] (🕴️..🕵️) person in suit levitating..detective
+1F57A ; Emoji_Modifier_Base # E3.0 [1] (🕺) man dancing
+1F590 ; Emoji_Modifier_Base # E0.7 [1] (🖐️) hand with fingers splayed
+1F595..1F596 ; Emoji_Modifier_Base # E1.0 [2] (🖕..🖖) middle finger..vulcan salute
+1F645..1F647 ; Emoji_Modifier_Base # E0.6 [3] (🙅..🙇) person gesturing NO..person bowing
+1F64B..1F64F ; Emoji_Modifier_Base # E0.6 [5] (🙋..🙏) person raising hand..folded hands
+1F6A3 ; Emoji_Modifier_Base # E1.0 [1] (🚣) person rowing boat
+1F6B4..1F6B5 ; Emoji_Modifier_Base # E1.0 [2] (🚴..🚵) person biking..person mountain biking
+1F6B6 ; Emoji_Modifier_Base # E0.6 [1] (🚶) person walking
+1F6C0 ; Emoji_Modifier_Base # E0.6 [1] (🛀) person taking bath
+1F6CC ; Emoji_Modifier_Base # E1.0 [1] (🛌) person in bed
+1F90C ; Emoji_Modifier_Base # E13.0 [1] (🤌) pinched fingers
+1F90F ; Emoji_Modifier_Base # E12.0 [1] (🤏) pinching hand
+1F918 ; Emoji_Modifier_Base # E1.0 [1] (🤘) sign of the horns
+1F919..1F91E ; Emoji_Modifier_Base # E3.0 [6] (🤙..🤞) call me hand..crossed fingers
+1F91F ; Emoji_Modifier_Base # E5.0 [1] (🤟) love-you gesture
+1F926 ; Emoji_Modifier_Base # E3.0 [1] (🤦) person facepalming
+1F930 ; Emoji_Modifier_Base # E3.0 [1] (🤰) pregnant woman
+1F931..1F932 ; Emoji_Modifier_Base # E5.0 [2] (🤱..🤲) breast-feeding..palms up together
+1F933..1F939 ; Emoji_Modifier_Base # E3.0 [7] (🤳..🤹) selfie..person juggling
+1F93C..1F93E ; Emoji_Modifier_Base # E3.0 [3] (🤼..🤾) people wrestling..person playing handball
+1F977 ; Emoji_Modifier_Base # E13.0 [1] (🥷) ninja
+1F9B5..1F9B6 ; Emoji_Modifier_Base # E11.0 [2] (🦵..🦶) leg..foot
+1F9B8..1F9B9 ; Emoji_Modifier_Base # E11.0 [2] (🦸..🦹) superhero..supervillain
+1F9BB ; Emoji_Modifier_Base # E12.0 [1] (🦻) ear with hearing aid
+1F9CD..1F9CF ; Emoji_Modifier_Base # E12.0 [3] (🧍..🧏) person standing..deaf person
+1F9D1..1F9DD ; Emoji_Modifier_Base # E5.0 [13] (🧑..🧝) person..elf
+1FAC3..1FAC5 ; Emoji_Modifier_Base # E14.0 [3] (🫃..🫅) pregnant man..person with crown
+1FAF0..1FAF6 ; Emoji_Modifier_Base # E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands
+1FAF7..1FAF8 ; Emoji_Modifier_Base # E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand
+
+# Total elements: 134
+
+# ================================================
+
+# All omitted code points have Emoji_Component=No
+
+0023 ; Emoji_Component # E0.0 [1] (#️) hash sign
+002A ; Emoji_Component # E0.0 [1] (*️) asterisk
+0030..0039 ; Emoji_Component # E0.0 [10] (0️..9️) digit zero..digit nine
+200D ; Emoji_Component # E0.0 [1] () zero width joiner
+20E3 ; Emoji_Component # E0.0 [1] (⃣) combining enclosing keycap
+FE0F ; Emoji_Component # E0.0 [1] () VARIATION SELECTOR-16
+1F1E6..1F1FF ; Emoji_Component # E0.0 [26] (🇦..🇿) regional indicator symbol letter a..regional indicator symbol letter z
+1F3FB..1F3FF ; Emoji_Component # E1.0 [5] (🏻..🏿) light skin tone..dark skin tone
+1F9B0..1F9B3 ; Emoji_Component # E11.0 [4] (🦰..🦳) red hair..white hair
+E0020..E007F ; Emoji_Component # E0.0 [96] (..) tag space..cancel tag
+
+# Total elements: 146
+
+# ================================================
+
+# All omitted code points have Extended_Pictographic=No
+
+00A9 ; Extended_Pictographic# E0.6 [1] (©️) copyright
+00AE ; Extended_Pictographic# E0.6 [1] (®️) registered
+203C ; Extended_Pictographic# E0.6 [1] (‼️) double exclamation mark
+2049 ; Extended_Pictographic# E0.6 [1] (⁉️) exclamation question mark
+2122 ; Extended_Pictographic# E0.6 [1] (™️) trade mark
+2139 ; Extended_Pictographic# E0.6 [1] (ℹ️) information
+2194..2199 ; Extended_Pictographic# E0.6 [6] (↔️..↙️) left-right arrow..down-left arrow
+21A9..21AA ; Extended_Pictographic# E0.6 [2] (↩️..↪️) right arrow curving left..left arrow curving right
+231A..231B ; Extended_Pictographic# E0.6 [2] (⌚..⌛) watch..hourglass done
+2328 ; Extended_Pictographic# E1.0 [1] (⌨️) keyboard
+2388 ; Extended_Pictographic# E0.0 [1] (⎈) HELM SYMBOL
+23CF ; Extended_Pictographic# E1.0 [1] (⏏️) eject button
+23E9..23EC ; Extended_Pictographic# E0.6 [4] (⏩..⏬) fast-forward button..fast down button
+23ED..23EE ; Extended_Pictographic# E0.7 [2] (⏭️..⏮️) next track button..last track button
+23EF ; Extended_Pictographic# E1.0 [1] (⏯️) play or pause button
+23F0 ; Extended_Pictographic# E0.6 [1] (⏰) alarm clock
+23F1..23F2 ; Extended_Pictographic# E1.0 [2] (⏱️..⏲️) stopwatch..timer clock
+23F3 ; Extended_Pictographic# E0.6 [1] (⏳) hourglass not done
+23F8..23FA ; Extended_Pictographic# E0.7 [3] (⏸️..⏺️) pause button..record button
+24C2 ; Extended_Pictographic# E0.6 [1] (Ⓜ️) circled M
+25AA..25AB ; Extended_Pictographic# E0.6 [2] (▪️..▫️) black small square..white small square
+25B6 ; Extended_Pictographic# E0.6 [1] (▶️) play button
+25C0 ; Extended_Pictographic# E0.6 [1] (◀️) reverse button
+25FB..25FE ; Extended_Pictographic# E0.6 [4] (◻️..◾) white medium square..black medium-small square
+2600..2601 ; Extended_Pictographic# E0.6 [2] (☀️..☁️) sun..cloud
+2602..2603 ; Extended_Pictographic# E0.7 [2] (☂️..☃️) umbrella..snowman
+2604 ; Extended_Pictographic# E1.0 [1] (☄️) comet
+2605 ; Extended_Pictographic# E0.0 [1] (★) BLACK STAR
+2607..260D ; Extended_Pictographic# E0.0 [7] (☇..☍) LIGHTNING..OPPOSITION
+260E ; Extended_Pictographic# E0.6 [1] (☎️) telephone
+260F..2610 ; Extended_Pictographic# E0.0 [2] (☏..☐) WHITE TELEPHONE..BALLOT BOX
+2611 ; Extended_Pictographic# E0.6 [1] (☑️) check box with check
+2612 ; Extended_Pictographic# E0.0 [1] (☒) BALLOT BOX WITH X
+2614..2615 ; Extended_Pictographic# E0.6 [2] (☔..☕) umbrella with rain drops..hot beverage
+2616..2617 ; Extended_Pictographic# E0.0 [2] (☖..☗) WHITE SHOGI PIECE..BLACK SHOGI PIECE
+2618 ; Extended_Pictographic# E1.0 [1] (☘️) shamrock
+2619..261C ; Extended_Pictographic# E0.0 [4] (☙..☜) REVERSED ROTATED FLORAL HEART BULLET..WHITE LEFT POINTING INDEX
+261D ; Extended_Pictographic# E0.6 [1] (☝️) index pointing up
+261E..261F ; Extended_Pictographic# E0.0 [2] (☞..☟) WHITE RIGHT POINTING INDEX..WHITE DOWN POINTING INDEX
+2620 ; Extended_Pictographic# E1.0 [1] (☠️) skull and crossbones
+2621 ; Extended_Pictographic# E0.0 [1] (☡) CAUTION SIGN
+2622..2623 ; Extended_Pictographic# E1.0 [2] (☢️..☣️) radioactive..biohazard
+2624..2625 ; Extended_Pictographic# E0.0 [2] (☤..☥) CADUCEUS..ANKH
+2626 ; Extended_Pictographic# E1.0 [1] (☦️) orthodox cross
+2627..2629 ; Extended_Pictographic# E0.0 [3] (☧..☩) CHI RHO..CROSS OF JERUSALEM
+262A ; Extended_Pictographic# E0.7 [1] (☪️) star and crescent
+262B..262D ; Extended_Pictographic# E0.0 [3] (☫..☭) FARSI SYMBOL..HAMMER AND SICKLE
+262E ; Extended_Pictographic# E1.0 [1] (☮️) peace symbol
+262F ; Extended_Pictographic# E0.7 [1] (☯️) yin yang
+2630..2637 ; Extended_Pictographic# E0.0 [8] (☰..☷) TRIGRAM FOR HEAVEN..TRIGRAM FOR EARTH
+2638..2639 ; Extended_Pictographic# E0.7 [2] (☸️..☹️) wheel of dharma..frowning face
+263A ; Extended_Pictographic# E0.6 [1] (☺️) smiling face
+263B..263F ; Extended_Pictographic# E0.0 [5] (☻..☿) BLACK SMILING FACE..MERCURY
+2640 ; Extended_Pictographic# E4.0 [1] (♀️) female sign
+2641 ; Extended_Pictographic# E0.0 [1] (♁) EARTH
+2642 ; Extended_Pictographic# E4.0 [1] (♂️) male sign
+2643..2647 ; Extended_Pictographic# E0.0 [5] (♃..♇) JUPITER..PLUTO
+2648..2653 ; Extended_Pictographic# E0.6 [12] (♈..♓) Aries..Pisces
+2654..265E ; Extended_Pictographic# E0.0 [11] (♔..♞) WHITE CHESS KING..BLACK CHESS KNIGHT
+265F ; Extended_Pictographic# E11.0 [1] (♟️) chess pawn
+2660 ; Extended_Pictographic# E0.6 [1] (♠️) spade suit
+2661..2662 ; Extended_Pictographic# E0.0 [2] (♡..♢) WHITE HEART SUIT..WHITE DIAMOND SUIT
+2663 ; Extended_Pictographic# E0.6 [1] (♣️) club suit
+2664 ; Extended_Pictographic# E0.0 [1] (♤) WHITE SPADE SUIT
+2665..2666 ; Extended_Pictographic# E0.6 [2] (♥️..♦️) heart suit..diamond suit
+2667 ; Extended_Pictographic# E0.0 [1] (♧) WHITE CLUB SUIT
+2668 ; Extended_Pictographic# E0.6 [1] (♨️) hot springs
+2669..267A ; Extended_Pictographic# E0.0 [18] (♩..♺) QUARTER NOTE..RECYCLING SYMBOL FOR GENERIC MATERIALS
+267B ; Extended_Pictographic# E0.6 [1] (♻️) recycling symbol
+267C..267D ; Extended_Pictographic# E0.0 [2] (♼..♽) RECYCLED PAPER SYMBOL..PARTIALLY-RECYCLED PAPER SYMBOL
+267E ; Extended_Pictographic# E11.0 [1] (♾️) infinity
+267F ; Extended_Pictographic# E0.6 [1] (♿) wheelchair symbol
+2680..2685 ; Extended_Pictographic# E0.0 [6] (⚀..⚅) DIE FACE-1..DIE FACE-6
+2690..2691 ; Extended_Pictographic# E0.0 [2] (⚐..⚑) WHITE FLAG..BLACK FLAG
+2692 ; Extended_Pictographic# E1.0 [1] (⚒️) hammer and pick
+2693 ; Extended_Pictographic# E0.6 [1] (⚓) anchor
+2694 ; Extended_Pictographic# E1.0 [1] (⚔️) crossed swords
+2695 ; Extended_Pictographic# E4.0 [1] (⚕️) medical symbol
+2696..2697 ; Extended_Pictographic# E1.0 [2] (⚖️..⚗️) balance scale..alembic
+2698 ; Extended_Pictographic# E0.0 [1] (⚘) FLOWER
+2699 ; Extended_Pictographic# E1.0 [1] (⚙️) gear
+269A ; Extended_Pictographic# E0.0 [1] (⚚) STAFF OF HERMES
+269B..269C ; Extended_Pictographic# E1.0 [2] (⚛️..⚜️) atom symbol..fleur-de-lis
+269D..269F ; Extended_Pictographic# E0.0 [3] (⚝..⚟) OUTLINED WHITE STAR..THREE LINES CONVERGING LEFT
+26A0..26A1 ; Extended_Pictographic# E0.6 [2] (⚠️..⚡) warning..high voltage
+26A2..26A6 ; Extended_Pictographic# E0.0 [5] (⚢..⚦) DOUBLED FEMALE SIGN..MALE WITH STROKE SIGN
+26A7 ; Extended_Pictographic# E13.0 [1] (⚧️) transgender symbol
+26A8..26A9 ; Extended_Pictographic# E0.0 [2] (⚨..⚩) VERTICAL MALE WITH STROKE SIGN..HORIZONTAL MALE WITH STROKE SIGN
+26AA..26AB ; Extended_Pictographic# E0.6 [2] (⚪..⚫) white circle..black circle
+26AC..26AF ; Extended_Pictographic# E0.0 [4] (⚬..⚯) MEDIUM SMALL WHITE CIRCLE..UNMARRIED PARTNERSHIP SYMBOL
+26B0..26B1 ; Extended_Pictographic# E1.0 [2] (⚰️..⚱️) coffin..funeral urn
+26B2..26BC ; Extended_Pictographic# E0.0 [11] (⚲..⚼) NEUTER..SESQUIQUADRATE
+26BD..26BE ; Extended_Pictographic# E0.6 [2] (⚽..⚾) soccer ball..baseball
+26BF..26C3 ; Extended_Pictographic# E0.0 [5] (⚿..⛃) SQUARED KEY..BLACK DRAUGHTS KING
+26C4..26C5 ; Extended_Pictographic# E0.6 [2] (⛄..⛅) snowman without snow..sun behind cloud
+26C6..26C7 ; Extended_Pictographic# E0.0 [2] (⛆..⛇) RAIN..BLACK SNOWMAN
+26C8 ; Extended_Pictographic# E0.7 [1] (⛈️) cloud with lightning and rain
+26C9..26CD ; Extended_Pictographic# E0.0 [5] (⛉..⛍) TURNED WHITE SHOGI PIECE..DISABLED CAR
+26CE ; Extended_Pictographic# E0.6 [1] (⛎) Ophiuchus
+26CF ; Extended_Pictographic# E0.7 [1] (⛏️) pick
+26D0 ; Extended_Pictographic# E0.0 [1] (⛐) CAR SLIDING
+26D1 ; Extended_Pictographic# E0.7 [1] (⛑️) rescue worker’s helmet
+26D2 ; Extended_Pictographic# E0.0 [1] (⛒) CIRCLED CROSSING LANES
+26D3 ; Extended_Pictographic# E0.7 [1] (⛓️) chains
+26D4 ; Extended_Pictographic# E0.6 [1] (⛔) no entry
+26D5..26E8 ; Extended_Pictographic# E0.0 [20] (⛕..⛨) ALTERNATE ONE-WAY LEFT WAY TRAFFIC..BLACK CROSS ON SHIELD
+26E9 ; Extended_Pictographic# E0.7 [1] (⛩️) shinto shrine
+26EA ; Extended_Pictographic# E0.6 [1] (⛪) church
+26EB..26EF ; Extended_Pictographic# E0.0 [5] (⛫..⛯) CASTLE..MAP SYMBOL FOR LIGHTHOUSE
+26F0..26F1 ; Extended_Pictographic# E0.7 [2] (⛰️..⛱️) mountain..umbrella on ground
+26F2..26F3 ; Extended_Pictographic# E0.6 [2] (⛲..⛳) fountain..flag in hole
+26F4 ; Extended_Pictographic# E0.7 [1] (⛴️) ferry
+26F5 ; Extended_Pictographic# E0.6 [1] (⛵) sailboat
+26F6 ; Extended_Pictographic# E0.0 [1] (⛶) SQUARE FOUR CORNERS
+26F7..26F9 ; Extended_Pictographic# E0.7 [3] (⛷️..⛹️) skier..person bouncing ball
+26FA ; Extended_Pictographic# E0.6 [1] (⛺) tent
+26FB..26FC ; Extended_Pictographic# E0.0 [2] (⛻..⛼) JAPANESE BANK SYMBOL..HEADSTONE GRAVEYARD SYMBOL
+26FD ; Extended_Pictographic# E0.6 [1] (⛽) fuel pump
+26FE..2701 ; Extended_Pictographic# E0.0 [4] (⛾..✁) CUP ON BLACK SQUARE..UPPER BLADE SCISSORS
+2702 ; Extended_Pictographic# E0.6 [1] (✂️) scissors
+2703..2704 ; Extended_Pictographic# E0.0 [2] (✃..✄) LOWER BLADE SCISSORS..WHITE SCISSORS
+2705 ; Extended_Pictographic# E0.6 [1] (✅) check mark button
+2708..270C ; Extended_Pictographic# E0.6 [5] (✈️..✌️) airplane..victory hand
+270D ; Extended_Pictographic# E0.7 [1] (✍️) writing hand
+270E ; Extended_Pictographic# E0.0 [1] (✎) LOWER RIGHT PENCIL
+270F ; Extended_Pictographic# E0.6 [1] (✏️) pencil
+2710..2711 ; Extended_Pictographic# E0.0 [2] (✐..✑) UPPER RIGHT PENCIL..WHITE NIB
+2712 ; Extended_Pictographic# E0.6 [1] (✒️) black nib
+2714 ; Extended_Pictographic# E0.6 [1] (✔️) check mark
+2716 ; Extended_Pictographic# E0.6 [1] (✖️) multiply
+271D ; Extended_Pictographic# E0.7 [1] (✝️) latin cross
+2721 ; Extended_Pictographic# E0.7 [1] (✡️) star of David
+2728 ; Extended_Pictographic# E0.6 [1] (✨) sparkles
+2733..2734 ; Extended_Pictographic# E0.6 [2] (✳️..✴️) eight-spoked asterisk..eight-pointed star
+2744 ; Extended_Pictographic# E0.6 [1] (❄️) snowflake
+2747 ; Extended_Pictographic# E0.6 [1] (❇️) sparkle
+274C ; Extended_Pictographic# E0.6 [1] (❌) cross mark
+274E ; Extended_Pictographic# E0.6 [1] (❎) cross mark button
+2753..2755 ; Extended_Pictographic# E0.6 [3] (❓..❕) red question mark..white exclamation mark
+2757 ; Extended_Pictographic# E0.6 [1] (❗) red exclamation mark
+2763 ; Extended_Pictographic# E1.0 [1] (❣️) heart exclamation
+2764 ; Extended_Pictographic# E0.6 [1] (❤️) red heart
+2765..2767 ; Extended_Pictographic# E0.0 [3] (❥..❧) ROTATED HEAVY BLACK HEART BULLET..ROTATED FLORAL HEART BULLET
+2795..2797 ; Extended_Pictographic# E0.6 [3] (➕..➗) plus..divide
+27A1 ; Extended_Pictographic# E0.6 [1] (➡️) right arrow
+27B0 ; Extended_Pictographic# E0.6 [1] (➰) curly loop
+27BF ; Extended_Pictographic# E1.0 [1] (➿) double curly loop
+2934..2935 ; Extended_Pictographic# E0.6 [2] (⤴️..⤵️) right arrow curving up..right arrow curving down
+2B05..2B07 ; Extended_Pictographic# E0.6 [3] (⬅️..⬇️) left arrow..down arrow
+2B1B..2B1C ; Extended_Pictographic# E0.6 [2] (⬛..⬜) black large square..white large square
+2B50 ; Extended_Pictographic# E0.6 [1] (⭐) star
+2B55 ; Extended_Pictographic# E0.6 [1] (⭕) hollow red circle
+3030 ; Extended_Pictographic# E0.6 [1] (〰️) wavy dash
+303D ; Extended_Pictographic# E0.6 [1] (〽️) part alternation mark
+3297 ; Extended_Pictographic# E0.6 [1] (㊗️) Japanese “congratulations” button
+3299 ; Extended_Pictographic# E0.6 [1] (㊙️) Japanese “secret” button
+1F000..1F003 ; Extended_Pictographic# E0.0 [4] (🀀..🀃) MAHJONG TILE EAST WIND..MAHJONG TILE NORTH WIND
+1F004 ; Extended_Pictographic# E0.6 [1] (🀄) mahjong red dragon
+1F005..1F0CE ; Extended_Pictographic# E0.0 [202] (🀅..🃎) MAHJONG TILE GREEN DRAGON..PLAYING CARD KING OF DIAMONDS
+1F0CF ; Extended_Pictographic# E0.6 [1] (🃏) joker
+1F0D0..1F0FF ; Extended_Pictographic# E0.0 [48] (..) ..
+1F10D..1F10F ; Extended_Pictographic# E0.0 [3] (🄍..🄏) CIRCLED ZERO WITH SLASH..CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH
+1F12F ; Extended_Pictographic# E0.0 [1] (🄯) COPYLEFT SYMBOL
+1F16C..1F16F ; Extended_Pictographic# E0.0 [4] (🅬..🅯) RAISED MR SIGN..CIRCLED HUMAN FIGURE
+1F170..1F171 ; Extended_Pictographic# E0.6 [2] (🅰️..🅱️) A button (blood type)..B button (blood type)
+1F17E..1F17F ; Extended_Pictographic# E0.6 [2] (🅾️..🅿️) O button (blood type)..P button
+1F18E ; Extended_Pictographic# E0.6 [1] (🆎) AB button (blood type)
+1F191..1F19A ; Extended_Pictographic# E0.6 [10] (🆑..🆚) CL button..VS button
+1F1AD..1F1E5 ; Extended_Pictographic# E0.0 [57] (🆭..) MASK WORK SYMBOL..
+1F201..1F202 ; Extended_Pictographic# E0.6 [2] (🈁..🈂️) Japanese “here” button..Japanese “service charge” button
+1F203..1F20F ; Extended_Pictographic# E0.0 [13] (..) ..
+1F21A ; Extended_Pictographic# E0.6 [1] (🈚) Japanese “free of charge” button
+1F22F ; Extended_Pictographic# E0.6 [1] (🈯) Japanese “reserved” button
+1F232..1F23A ; Extended_Pictographic# E0.6 [9] (🈲..🈺) Japanese “prohibited” button..Japanese “open for business” button
+1F23C..1F23F ; Extended_Pictographic# E0.0 [4] (..) ..
+1F249..1F24F ; Extended_Pictographic# E0.0 [7] (..) ..
+1F250..1F251 ; Extended_Pictographic# E0.6 [2] (🉐..🉑) Japanese “bargain” button..Japanese “acceptable” button
+1F252..1F2FF ; Extended_Pictographic# E0.0 [174] (..) ..
+1F300..1F30C ; Extended_Pictographic# E0.6 [13] (🌀..🌌) cyclone..milky way
+1F30D..1F30E ; Extended_Pictographic# E0.7 [2] (🌍..🌎) globe showing Europe-Africa..globe showing Americas
+1F30F ; Extended_Pictographic# E0.6 [1] (🌏) globe showing Asia-Australia
+1F310 ; Extended_Pictographic# E1.0 [1] (🌐) globe with meridians
+1F311 ; Extended_Pictographic# E0.6 [1] (🌑) new moon
+1F312 ; Extended_Pictographic# E1.0 [1] (🌒) waxing crescent moon
+1F313..1F315 ; Extended_Pictographic# E0.6 [3] (🌓..🌕) first quarter moon..full moon
+1F316..1F318 ; Extended_Pictographic# E1.0 [3] (🌖..🌘) waning gibbous moon..waning crescent moon
+1F319 ; Extended_Pictographic# E0.6 [1] (🌙) crescent moon
+1F31A ; Extended_Pictographic# E1.0 [1] (🌚) new moon face
+1F31B ; Extended_Pictographic# E0.6 [1] (🌛) first quarter moon face
+1F31C ; Extended_Pictographic# E0.7 [1] (🌜) last quarter moon face
+1F31D..1F31E ; Extended_Pictographic# E1.0 [2] (🌝..🌞) full moon face..sun with face
+1F31F..1F320 ; Extended_Pictographic# E0.6 [2] (🌟..🌠) glowing star..shooting star
+1F321 ; Extended_Pictographic# E0.7 [1] (🌡️) thermometer
+1F322..1F323 ; Extended_Pictographic# E0.0 [2] (🌢..🌣) BLACK DROPLET..WHITE SUN
+1F324..1F32C ; Extended_Pictographic# E0.7 [9] (🌤️..🌬️) sun behind small cloud..wind face
+1F32D..1F32F ; Extended_Pictographic# E1.0 [3] (🌭..🌯) hot dog..burrito
+1F330..1F331 ; Extended_Pictographic# E0.6 [2] (🌰..🌱) chestnut..seedling
+1F332..1F333 ; Extended_Pictographic# E1.0 [2] (🌲..🌳) evergreen tree..deciduous tree
+1F334..1F335 ; Extended_Pictographic# E0.6 [2] (🌴..🌵) palm tree..cactus
+1F336 ; Extended_Pictographic# E0.7 [1] (🌶️) hot pepper
+1F337..1F34A ; Extended_Pictographic# E0.6 [20] (🌷..🍊) tulip..tangerine
+1F34B ; Extended_Pictographic# E1.0 [1] (🍋) lemon
+1F34C..1F34F ; Extended_Pictographic# E0.6 [4] (🍌..🍏) banana..green apple
+1F350 ; Extended_Pictographic# E1.0 [1] (🍐) pear
+1F351..1F37B ; Extended_Pictographic# E0.6 [43] (🍑..🍻) peach..clinking beer mugs
+1F37C ; Extended_Pictographic# E1.0 [1] (🍼) baby bottle
+1F37D ; Extended_Pictographic# E0.7 [1] (🍽️) fork and knife with plate
+1F37E..1F37F ; Extended_Pictographic# E1.0 [2] (🍾..🍿) bottle with popping cork..popcorn
+1F380..1F393 ; Extended_Pictographic# E0.6 [20] (🎀..🎓) ribbon..graduation cap
+1F394..1F395 ; Extended_Pictographic# E0.0 [2] (🎔..🎕) HEART WITH TIP ON THE LEFT..BOUQUET OF FLOWERS
+1F396..1F397 ; Extended_Pictographic# E0.7 [2] (🎖️..🎗️) military medal..reminder ribbon
+1F398 ; Extended_Pictographic# E0.0 [1] (🎘) MUSICAL KEYBOARD WITH JACKS
+1F399..1F39B ; Extended_Pictographic# E0.7 [3] (🎙️..🎛️) studio microphone..control knobs
+1F39C..1F39D ; Extended_Pictographic# E0.0 [2] (🎜..🎝) BEAMED ASCENDING MUSICAL NOTES..BEAMED DESCENDING MUSICAL NOTES
+1F39E..1F39F ; Extended_Pictographic# E0.7 [2] (🎞️..🎟️) film frames..admission tickets
+1F3A0..1F3C4 ; Extended_Pictographic# E0.6 [37] (🎠..🏄) carousel horse..person surfing
+1F3C5 ; Extended_Pictographic# E1.0 [1] (🏅) sports medal
+1F3C6 ; Extended_Pictographic# E0.6 [1] (🏆) trophy
+1F3C7 ; Extended_Pictographic# E1.0 [1] (🏇) horse racing
+1F3C8 ; Extended_Pictographic# E0.6 [1] (🏈) american football
+1F3C9 ; Extended_Pictographic# E1.0 [1] (🏉) rugby football
+1F3CA ; Extended_Pictographic# E0.6 [1] (🏊) person swimming
+1F3CB..1F3CE ; Extended_Pictographic# E0.7 [4] (🏋️..🏎️) person lifting weights..racing car
+1F3CF..1F3D3 ; Extended_Pictographic# E1.0 [5] (🏏..🏓) cricket game..ping pong
+1F3D4..1F3DF ; Extended_Pictographic# E0.7 [12] (🏔️..🏟️) snow-capped mountain..stadium
+1F3E0..1F3E3 ; Extended_Pictographic# E0.6 [4] (🏠..🏣) house..Japanese post office
+1F3E4 ; Extended_Pictographic# E1.0 [1] (🏤) post office
+1F3E5..1F3F0 ; Extended_Pictographic# E0.6 [12] (🏥..🏰) hospital..castle
+1F3F1..1F3F2 ; Extended_Pictographic# E0.0 [2] (🏱..🏲) WHITE PENNANT..BLACK PENNANT
+1F3F3 ; Extended_Pictographic# E0.7 [1] (🏳️) white flag
+1F3F4 ; Extended_Pictographic# E1.0 [1] (🏴) black flag
+1F3F5 ; Extended_Pictographic# E0.7 [1] (🏵️) rosette
+1F3F6 ; Extended_Pictographic# E0.0 [1] (🏶) BLACK ROSETTE
+1F3F7 ; Extended_Pictographic# E0.7 [1] (🏷️) label
+1F3F8..1F3FA ; Extended_Pictographic# E1.0 [3] (🏸..🏺) badminton..amphora
+1F400..1F407 ; Extended_Pictographic# E1.0 [8] (🐀..🐇) rat..rabbit
+1F408 ; Extended_Pictographic# E0.7 [1] (🐈) cat
+1F409..1F40B ; Extended_Pictographic# E1.0 [3] (🐉..🐋) dragon..whale
+1F40C..1F40E ; Extended_Pictographic# E0.6 [3] (🐌..🐎) snail..horse
+1F40F..1F410 ; Extended_Pictographic# E1.0 [2] (🐏..🐐) ram..goat
+1F411..1F412 ; Extended_Pictographic# E0.6 [2] (🐑..🐒) ewe..monkey
+1F413 ; Extended_Pictographic# E1.0 [1] (🐓) rooster
+1F414 ; Extended_Pictographic# E0.6 [1] (🐔) chicken
+1F415 ; Extended_Pictographic# E0.7 [1] (🐕) dog
+1F416 ; Extended_Pictographic# E1.0 [1] (🐖) pig
+1F417..1F429 ; Extended_Pictographic# E0.6 [19] (🐗..🐩) boar..poodle
+1F42A ; Extended_Pictographic# E1.0 [1] (🐪) camel
+1F42B..1F43E ; Extended_Pictographic# E0.6 [20] (🐫..🐾) two-hump camel..paw prints
+1F43F ; Extended_Pictographic# E0.7 [1] (🐿️) chipmunk
+1F440 ; Extended_Pictographic# E0.6 [1] (👀) eyes
+1F441 ; Extended_Pictographic# E0.7 [1] (👁️) eye
+1F442..1F464 ; Extended_Pictographic# E0.6 [35] (👂..👤) ear..bust in silhouette
+1F465 ; Extended_Pictographic# E1.0 [1] (👥) busts in silhouette
+1F466..1F46B ; Extended_Pictographic# E0.6 [6] (👦..👫) boy..woman and man holding hands
+1F46C..1F46D ; Extended_Pictographic# E1.0 [2] (👬..👭) men holding hands..women holding hands
+1F46E..1F4AC ; Extended_Pictographic# E0.6 [63] (👮..💬) police officer..speech balloon
+1F4AD ; Extended_Pictographic# E1.0 [1] (💭) thought balloon
+1F4AE..1F4B5 ; Extended_Pictographic# E0.6 [8] (💮..💵) white flower..dollar banknote
+1F4B6..1F4B7 ; Extended_Pictographic# E1.0 [2] (💶..💷) euro banknote..pound banknote
+1F4B8..1F4EB ; Extended_Pictographic# E0.6 [52] (💸..📫) money with wings..closed mailbox with raised flag
+1F4EC..1F4ED ; Extended_Pictographic# E0.7 [2] (📬..📭) open mailbox with raised flag..open mailbox with lowered flag
+1F4EE ; Extended_Pictographic# E0.6 [1] (📮) postbox
+1F4EF ; Extended_Pictographic# E1.0 [1] (📯) postal horn
+1F4F0..1F4F4 ; Extended_Pictographic# E0.6 [5] (📰..📴) newspaper..mobile phone off
+1F4F5 ; Extended_Pictographic# E1.0 [1] (📵) no mobile phones
+1F4F6..1F4F7 ; Extended_Pictographic# E0.6 [2] (📶..📷) antenna bars..camera
+1F4F8 ; Extended_Pictographic# E1.0 [1] (📸) camera with flash
+1F4F9..1F4FC ; Extended_Pictographic# E0.6 [4] (📹..📼) video camera..videocassette
+1F4FD ; Extended_Pictographic# E0.7 [1] (📽️) film projector
+1F4FE ; Extended_Pictographic# E0.0 [1] (📾) PORTABLE STEREO
+1F4FF..1F502 ; Extended_Pictographic# E1.0 [4] (📿..🔂) prayer beads..repeat single button
+1F503 ; Extended_Pictographic# E0.6 [1] (🔃) clockwise vertical arrows
+1F504..1F507 ; Extended_Pictographic# E1.0 [4] (🔄..🔇) counterclockwise arrows button..muted speaker
+1F508 ; Extended_Pictographic# E0.7 [1] (🔈) speaker low volume
+1F509 ; Extended_Pictographic# E1.0 [1] (🔉) speaker medium volume
+1F50A..1F514 ; Extended_Pictographic# E0.6 [11] (🔊..🔔) speaker high volume..bell
+1F515 ; Extended_Pictographic# E1.0 [1] (🔕) bell with slash
+1F516..1F52B ; Extended_Pictographic# E0.6 [22] (🔖..🔫) bookmark..water pistol
+1F52C..1F52D ; Extended_Pictographic# E1.0 [2] (🔬..🔭) microscope..telescope
+1F52E..1F53D ; Extended_Pictographic# E0.6 [16] (🔮..🔽) crystal ball..downwards button
+1F546..1F548 ; Extended_Pictographic# E0.0 [3] (🕆..🕈) WHITE LATIN CROSS..CELTIC CROSS
+1F549..1F54A ; Extended_Pictographic# E0.7 [2] (🕉️..🕊️) om..dove
+1F54B..1F54E ; Extended_Pictographic# E1.0 [4] (🕋..🕎) kaaba..menorah
+1F54F ; Extended_Pictographic# E0.0 [1] (🕏) BOWL OF HYGIEIA
+1F550..1F55B ; Extended_Pictographic# E0.6 [12] (🕐..🕛) one o’clock..twelve o’clock
+1F55C..1F567 ; Extended_Pictographic# E0.7 [12] (🕜..🕧) one-thirty..twelve-thirty
+1F568..1F56E ; Extended_Pictographic# E0.0 [7] (🕨..🕮) RIGHT SPEAKER..BOOK
+1F56F..1F570 ; Extended_Pictographic# E0.7 [2] (🕯️..🕰️) candle..mantelpiece clock
+1F571..1F572 ; Extended_Pictographic# E0.0 [2] (🕱..🕲) BLACK SKULL AND CROSSBONES..NO PIRACY
+1F573..1F579 ; Extended_Pictographic# E0.7 [7] (🕳️..🕹️) hole..joystick
+1F57A ; Extended_Pictographic# E3.0 [1] (🕺) man dancing
+1F57B..1F586 ; Extended_Pictographic# E0.0 [12] (🕻..🖆) LEFT HAND TELEPHONE RECEIVER..PEN OVER STAMPED ENVELOPE
+1F587 ; Extended_Pictographic# E0.7 [1] (🖇️) linked paperclips
+1F588..1F589 ; Extended_Pictographic# E0.0 [2] (🖈..🖉) BLACK PUSHPIN..LOWER LEFT PENCIL
+1F58A..1F58D ; Extended_Pictographic# E0.7 [4] (🖊️..🖍️) pen..crayon
+1F58E..1F58F ; Extended_Pictographic# E0.0 [2] (🖎..🖏) LEFT WRITING HAND..TURNED OK HAND SIGN
+1F590 ; Extended_Pictographic# E0.7 [1] (🖐️) hand with fingers splayed
+1F591..1F594 ; Extended_Pictographic# E0.0 [4] (🖑..🖔) REVERSED RAISED HAND WITH FINGERS SPLAYED..REVERSED VICTORY HAND
+1F595..1F596 ; Extended_Pictographic# E1.0 [2] (🖕..🖖) middle finger..vulcan salute
+1F597..1F5A3 ; Extended_Pictographic# E0.0 [13] (🖗..🖣) WHITE DOWN POINTING LEFT HAND INDEX..BLACK DOWN POINTING BACKHAND INDEX
+1F5A4 ; Extended_Pictographic# E3.0 [1] (🖤) black heart
+1F5A5 ; Extended_Pictographic# E0.7 [1] (🖥️) desktop computer
+1F5A6..1F5A7 ; Extended_Pictographic# E0.0 [2] (🖦..🖧) KEYBOARD AND MOUSE..THREE NETWORKED COMPUTERS
+1F5A8 ; Extended_Pictographic# E0.7 [1] (🖨️) printer
+1F5A9..1F5B0 ; Extended_Pictographic# E0.0 [8] (🖩..🖰) POCKET CALCULATOR..TWO BUTTON MOUSE
+1F5B1..1F5B2 ; Extended_Pictographic# E0.7 [2] (🖱️..🖲️) computer mouse..trackball
+1F5B3..1F5BB ; Extended_Pictographic# E0.0 [9] (🖳..🖻) OLD PERSONAL COMPUTER..DOCUMENT WITH PICTURE
+1F5BC ; Extended_Pictographic# E0.7 [1] (🖼️) framed picture
+1F5BD..1F5C1 ; Extended_Pictographic# E0.0 [5] (🖽..🗁) FRAME WITH TILES..OPEN FOLDER
+1F5C2..1F5C4 ; Extended_Pictographic# E0.7 [3] (🗂️..🗄️) card index dividers..file cabinet
+1F5C5..1F5D0 ; Extended_Pictographic# E0.0 [12] (🗅..🗐) EMPTY NOTE..PAGES
+1F5D1..1F5D3 ; Extended_Pictographic# E0.7 [3] (🗑️..🗓️) wastebasket..spiral calendar
+1F5D4..1F5DB ; Extended_Pictographic# E0.0 [8] (🗔..🗛) DESKTOP WINDOW..DECREASE FONT SIZE SYMBOL
+1F5DC..1F5DE ; Extended_Pictographic# E0.7 [3] (🗜️..🗞️) clamp..rolled-up newspaper
+1F5DF..1F5E0 ; Extended_Pictographic# E0.0 [2] (🗟..🗠) PAGE WITH CIRCLED TEXT..STOCK CHART
+1F5E1 ; Extended_Pictographic# E0.7 [1] (🗡️) dagger
+1F5E2 ; Extended_Pictographic# E0.0 [1] (🗢) LIPS
+1F5E3 ; Extended_Pictographic# E0.7 [1] (🗣️) speaking head
+1F5E4..1F5E7 ; Extended_Pictographic# E0.0 [4] (🗤..🗧) THREE RAYS ABOVE..THREE RAYS RIGHT
+1F5E8 ; Extended_Pictographic# E2.0 [1] (🗨️) left speech bubble
+1F5E9..1F5EE ; Extended_Pictographic# E0.0 [6] (🗩..🗮) RIGHT SPEECH BUBBLE..LEFT ANGER BUBBLE
+1F5EF ; Extended_Pictographic# E0.7 [1] (🗯️) right anger bubble
+1F5F0..1F5F2 ; Extended_Pictographic# E0.0 [3] (🗰..🗲) MOOD BUBBLE..LIGHTNING MOOD
+1F5F3 ; Extended_Pictographic# E0.7 [1] (🗳️) ballot box with ballot
+1F5F4..1F5F9 ; Extended_Pictographic# E0.0 [6] (🗴..🗹) BALLOT SCRIPT X..BALLOT BOX WITH BOLD CHECK
+1F5FA ; Extended_Pictographic# E0.7 [1] (🗺️) world map
+1F5FB..1F5FF ; Extended_Pictographic# E0.6 [5] (🗻..🗿) mount fuji..moai
+1F600 ; Extended_Pictographic# E1.0 [1] (😀) grinning face
+1F601..1F606 ; Extended_Pictographic# E0.6 [6] (😁..😆) beaming face with smiling eyes..grinning squinting face
+1F607..1F608 ; Extended_Pictographic# E1.0 [2] (😇..😈) smiling face with halo..smiling face with horns
+1F609..1F60D ; Extended_Pictographic# E0.6 [5] (😉..😍) winking face..smiling face with heart-eyes
+1F60E ; Extended_Pictographic# E1.0 [1] (😎) smiling face with sunglasses
+1F60F ; Extended_Pictographic# E0.6 [1] (😏) smirking face
+1F610 ; Extended_Pictographic# E0.7 [1] (😐) neutral face
+1F611 ; Extended_Pictographic# E1.0 [1] (😑) expressionless face
+1F612..1F614 ; Extended_Pictographic# E0.6 [3] (😒..😔) unamused face..pensive face
+1F615 ; Extended_Pictographic# E1.0 [1] (😕) confused face
+1F616 ; Extended_Pictographic# E0.6 [1] (😖) confounded face
+1F617 ; Extended_Pictographic# E1.0 [1] (😗) kissing face
+1F618 ; Extended_Pictographic# E0.6 [1] (😘) face blowing a kiss
+1F619 ; Extended_Pictographic# E1.0 [1] (😙) kissing face with smiling eyes
+1F61A ; Extended_Pictographic# E0.6 [1] (😚) kissing face with closed eyes
+1F61B ; Extended_Pictographic# E1.0 [1] (😛) face with tongue
+1F61C..1F61E ; Extended_Pictographic# E0.6 [3] (😜..😞) winking face with tongue..disappointed face
+1F61F ; Extended_Pictographic# E1.0 [1] (😟) worried face
+1F620..1F625 ; Extended_Pictographic# E0.6 [6] (😠..😥) angry face..sad but relieved face
+1F626..1F627 ; Extended_Pictographic# E1.0 [2] (😦..😧) frowning face with open mouth..anguished face
+1F628..1F62B ; Extended_Pictographic# E0.6 [4] (😨..😫) fearful face..tired face
+1F62C ; Extended_Pictographic# E1.0 [1] (😬) grimacing face
+1F62D ; Extended_Pictographic# E0.6 [1] (😭) loudly crying face
+1F62E..1F62F ; Extended_Pictographic# E1.0 [2] (😮..😯) face with open mouth..hushed face
+1F630..1F633 ; Extended_Pictographic# E0.6 [4] (😰..😳) anxious face with sweat..flushed face
+1F634 ; Extended_Pictographic# E1.0 [1] (😴) sleeping face
+1F635 ; Extended_Pictographic# E0.6 [1] (😵) face with crossed-out eyes
+1F636 ; Extended_Pictographic# E1.0 [1] (😶) face without mouth
+1F637..1F640 ; Extended_Pictographic# E0.6 [10] (😷..🙀) face with medical mask..weary cat
+1F641..1F644 ; Extended_Pictographic# E1.0 [4] (🙁..🙄) slightly frowning face..face with rolling eyes
+1F645..1F64F ; Extended_Pictographic# E0.6 [11] (🙅..🙏) person gesturing NO..folded hands
+1F680 ; Extended_Pictographic# E0.6 [1] (🚀) rocket
+1F681..1F682 ; Extended_Pictographic# E1.0 [2] (🚁..🚂) helicopter..locomotive
+1F683..1F685 ; Extended_Pictographic# E0.6 [3] (🚃..🚅) railway car..bullet train
+1F686 ; Extended_Pictographic# E1.0 [1] (🚆) train
+1F687 ; Extended_Pictographic# E0.6 [1] (🚇) metro
+1F688 ; Extended_Pictographic# E1.0 [1] (🚈) light rail
+1F689 ; Extended_Pictographic# E0.6 [1] (🚉) station
+1F68A..1F68B ; Extended_Pictographic# E1.0 [2] (🚊..🚋) tram..tram car
+1F68C ; Extended_Pictographic# E0.6 [1] (🚌) bus
+1F68D ; Extended_Pictographic# E0.7 [1] (🚍) oncoming bus
+1F68E ; Extended_Pictographic# E1.0 [1] (🚎) trolleybus
+1F68F ; Extended_Pictographic# E0.6 [1] (🚏) bus stop
+1F690 ; Extended_Pictographic# E1.0 [1] (🚐) minibus
+1F691..1F693 ; Extended_Pictographic# E0.6 [3] (🚑..🚓) ambulance..police car
+1F694 ; Extended_Pictographic# E0.7 [1] (🚔) oncoming police car
+1F695 ; Extended_Pictographic# E0.6 [1] (🚕) taxi
+1F696 ; Extended_Pictographic# E1.0 [1] (🚖) oncoming taxi
+1F697 ; Extended_Pictographic# E0.6 [1] (🚗) automobile
+1F698 ; Extended_Pictographic# E0.7 [1] (🚘) oncoming automobile
+1F699..1F69A ; Extended_Pictographic# E0.6 [2] (🚙..🚚) sport utility vehicle..delivery truck
+1F69B..1F6A1 ; Extended_Pictographic# E1.0 [7] (🚛..🚡) articulated lorry..aerial tramway
+1F6A2 ; Extended_Pictographic# E0.6 [1] (🚢) ship
+1F6A3 ; Extended_Pictographic# E1.0 [1] (🚣) person rowing boat
+1F6A4..1F6A5 ; Extended_Pictographic# E0.6 [2] (🚤..🚥) speedboat..horizontal traffic light
+1F6A6 ; Extended_Pictographic# E1.0 [1] (🚦) vertical traffic light
+1F6A7..1F6AD ; Extended_Pictographic# E0.6 [7] (🚧..🚭) construction..no smoking
+1F6AE..1F6B1 ; Extended_Pictographic# E1.0 [4] (🚮..🚱) litter in bin sign..non-potable water
+1F6B2 ; Extended_Pictographic# E0.6 [1] (🚲) bicycle
+1F6B3..1F6B5 ; Extended_Pictographic# E1.0 [3] (🚳..🚵) no bicycles..person mountain biking
+1F6B6 ; Extended_Pictographic# E0.6 [1] (🚶) person walking
+1F6B7..1F6B8 ; Extended_Pictographic# E1.0 [2] (🚷..🚸) no pedestrians..children crossing
+1F6B9..1F6BE ; Extended_Pictographic# E0.6 [6] (🚹..🚾) men’s room..water closet
+1F6BF ; Extended_Pictographic# E1.0 [1] (🚿) shower
+1F6C0 ; Extended_Pictographic# E0.6 [1] (🛀) person taking bath
+1F6C1..1F6C5 ; Extended_Pictographic# E1.0 [5] (🛁..🛅) bathtub..left luggage
+1F6C6..1F6CA ; Extended_Pictographic# E0.0 [5] (🛆..🛊) TRIANGLE WITH ROUNDED CORNERS..GIRLS SYMBOL
+1F6CB ; Extended_Pictographic# E0.7 [1] (🛋️) couch and lamp
+1F6CC ; Extended_Pictographic# E1.0 [1] (🛌) person in bed
+1F6CD..1F6CF ; Extended_Pictographic# E0.7 [3] (🛍️..🛏️) shopping bags..bed
+1F6D0 ; Extended_Pictographic# E1.0 [1] (🛐) place of worship
+1F6D1..1F6D2 ; Extended_Pictographic# E3.0 [2] (🛑..🛒) stop sign..shopping cart
+1F6D3..1F6D4 ; Extended_Pictographic# E0.0 [2] (🛓..🛔) STUPA..PAGODA
+1F6D5 ; Extended_Pictographic# E12.0 [1] (🛕) hindu temple
+1F6D6..1F6D7 ; Extended_Pictographic# E13.0 [2] (🛖..🛗) hut..elevator
+1F6D8..1F6DB ; Extended_Pictographic# E0.0 [4] (..) ..
+1F6DC ; Extended_Pictographic# E15.0 [1] (🛜) wireless
+1F6DD..1F6DF ; Extended_Pictographic# E14.0 [3] (🛝..🛟) playground slide..ring buoy
+1F6E0..1F6E5 ; Extended_Pictographic# E0.7 [6] (🛠️..🛥️) hammer and wrench..motor boat
+1F6E6..1F6E8 ; Extended_Pictographic# E0.0 [3] (🛦..🛨) UP-POINTING MILITARY AIRPLANE..UP-POINTING SMALL AIRPLANE
+1F6E9 ; Extended_Pictographic# E0.7 [1] (🛩️) small airplane
+1F6EA ; Extended_Pictographic# E0.0 [1] (🛪) NORTHEAST-POINTING AIRPLANE
+1F6EB..1F6EC ; Extended_Pictographic# E1.0 [2] (🛫..🛬) airplane departure..airplane arrival
+1F6ED..1F6EF ; Extended_Pictographic# E0.0 [3] (..) ..
+1F6F0 ; Extended_Pictographic# E0.7 [1] (🛰️) satellite
+1F6F1..1F6F2 ; Extended_Pictographic# E0.0 [2] (🛱..🛲) ONCOMING FIRE ENGINE..DIESEL LOCOMOTIVE
+1F6F3 ; Extended_Pictographic# E0.7 [1] (🛳️) passenger ship
+1F6F4..1F6F6 ; Extended_Pictographic# E3.0 [3] (🛴..🛶) kick scooter..canoe
+1F6F7..1F6F8 ; Extended_Pictographic# E5.0 [2] (🛷..🛸) sled..flying saucer
+1F6F9 ; Extended_Pictographic# E11.0 [1] (🛹) skateboard
+1F6FA ; Extended_Pictographic# E12.0 [1] (🛺) auto rickshaw
+1F6FB..1F6FC ; Extended_Pictographic# E13.0 [2] (🛻..🛼) pickup truck..roller skate
+1F6FD..1F6FF ; Extended_Pictographic# E0.0 [3] (..) ..
+1F774..1F77F ; Extended_Pictographic# E0.0 [12] (🝴..🝿) LOT OF FORTUNE..ORCUS
+1F7D5..1F7DF ; Extended_Pictographic# E0.0 [11] (🟕..) CIRCLED TRIANGLE..
+1F7E0..1F7EB ; Extended_Pictographic# E12.0 [12] (🟠..🟫) orange circle..brown square
+1F7EC..1F7EF ; Extended_Pictographic# E0.0 [4] (..) ..
+1F7F0 ; Extended_Pictographic# E14.0 [1] (🟰) heavy equals sign
+1F7F1..1F7FF ; Extended_Pictographic# E0.0 [15] (..) ..
+1F80C..1F80F ; Extended_Pictographic# E0.0 [4] (..) ..
+1F848..1F84F ; Extended_Pictographic# E0.0 [8] (..) ..
+1F85A..1F85F ; Extended_Pictographic# E0.0 [6] (..) ..
+1F888..1F88F ; Extended_Pictographic# E0.0 [8] (..) ..
+1F8AE..1F8FF ; Extended_Pictographic# E0.0 [82] (..) ..
+1F90C ; Extended_Pictographic# E13.0 [1] (🤌) pinched fingers
+1F90D..1F90F ; Extended_Pictographic# E12.0 [3] (🤍..🤏) white heart..pinching hand
+1F910..1F918 ; Extended_Pictographic# E1.0 [9] (🤐..🤘) zipper-mouth face..sign of the horns
+1F919..1F91E ; Extended_Pictographic# E3.0 [6] (🤙..🤞) call me hand..crossed fingers
+1F91F ; Extended_Pictographic# E5.0 [1] (🤟) love-you gesture
+1F920..1F927 ; Extended_Pictographic# E3.0 [8] (🤠..🤧) cowboy hat face..sneezing face
+1F928..1F92F ; Extended_Pictographic# E5.0 [8] (🤨..🤯) face with raised eyebrow..exploding head
+1F930 ; Extended_Pictographic# E3.0 [1] (🤰) pregnant woman
+1F931..1F932 ; Extended_Pictographic# E5.0 [2] (🤱..🤲) breast-feeding..palms up together
+1F933..1F93A ; Extended_Pictographic# E3.0 [8] (🤳..🤺) selfie..person fencing
+1F93C..1F93E ; Extended_Pictographic# E3.0 [3] (🤼..🤾) people wrestling..person playing handball
+1F93F ; Extended_Pictographic# E12.0 [1] (🤿) diving mask
+1F940..1F945 ; Extended_Pictographic# E3.0 [6] (🥀..🥅) wilted flower..goal net
+1F947..1F94B ; Extended_Pictographic# E3.0 [5] (🥇..🥋) 1st place medal..martial arts uniform
+1F94C ; Extended_Pictographic# E5.0 [1] (🥌) curling stone
+1F94D..1F94F ; Extended_Pictographic# E11.0 [3] (🥍..🥏) lacrosse..flying disc
+1F950..1F95E ; Extended_Pictographic# E3.0 [15] (🥐..🥞) croissant..pancakes
+1F95F..1F96B ; Extended_Pictographic# E5.0 [13] (🥟..🥫) dumpling..canned food
+1F96C..1F970 ; Extended_Pictographic# E11.0 [5] (🥬..🥰) leafy green..smiling face with hearts
+1F971 ; Extended_Pictographic# E12.0 [1] (🥱) yawning face
+1F972 ; Extended_Pictographic# E13.0 [1] (🥲) smiling face with tear
+1F973..1F976 ; Extended_Pictographic# E11.0 [4] (🥳..🥶) partying face..cold face
+1F977..1F978 ; Extended_Pictographic# E13.0 [2] (🥷..🥸) ninja..disguised face
+1F979 ; Extended_Pictographic# E14.0 [1] (🥹) face holding back tears
+1F97A ; Extended_Pictographic# E11.0 [1] (🥺) pleading face
+1F97B ; Extended_Pictographic# E12.0 [1] (🥻) sari
+1F97C..1F97F ; Extended_Pictographic# E11.0 [4] (🥼..🥿) lab coat..flat shoe
+1F980..1F984 ; Extended_Pictographic# E1.0 [5] (🦀..🦄) crab..unicorn
+1F985..1F991 ; Extended_Pictographic# E3.0 [13] (🦅..🦑) eagle..squid
+1F992..1F997 ; Extended_Pictographic# E5.0 [6] (🦒..🦗) giraffe..cricket
+1F998..1F9A2 ; Extended_Pictographic# E11.0 [11] (🦘..🦢) kangaroo..swan
+1F9A3..1F9A4 ; Extended_Pictographic# E13.0 [2] (🦣..🦤) mammoth..dodo
+1F9A5..1F9AA ; Extended_Pictographic# E12.0 [6] (🦥..🦪) sloth..oyster
+1F9AB..1F9AD ; Extended_Pictographic# E13.0 [3] (🦫..🦭) beaver..seal
+1F9AE..1F9AF ; Extended_Pictographic# E12.0 [2] (🦮..🦯) guide dog..white cane
+1F9B0..1F9B9 ; Extended_Pictographic# E11.0 [10] (🦰..🦹) red hair..supervillain
+1F9BA..1F9BF ; Extended_Pictographic# E12.0 [6] (🦺..🦿) safety vest..mechanical leg
+1F9C0 ; Extended_Pictographic# E1.0 [1] (🧀) cheese wedge
+1F9C1..1F9C2 ; Extended_Pictographic# E11.0 [2] (🧁..🧂) cupcake..salt
+1F9C3..1F9CA ; Extended_Pictographic# E12.0 [8] (🧃..🧊) beverage box..ice
+1F9CB ; Extended_Pictographic# E13.0 [1] (🧋) bubble tea
+1F9CC ; Extended_Pictographic# E14.0 [1] (🧌) troll
+1F9CD..1F9CF ; Extended_Pictographic# E12.0 [3] (🧍..🧏) person standing..deaf person
+1F9D0..1F9E6 ; Extended_Pictographic# E5.0 [23] (🧐..🧦) face with monocle..socks
+1F9E7..1F9FF ; Extended_Pictographic# E11.0 [25] (🧧..🧿) red envelope..nazar amulet
+1FA00..1FA6F ; Extended_Pictographic# E0.0 [112] (🨀..) NEUTRAL CHESS KING..
+1FA70..1FA73 ; Extended_Pictographic# E12.0 [4] (🩰..🩳) ballet shoes..shorts
+1FA74 ; Extended_Pictographic# E13.0 [1] (🩴) thong sandal
+1FA75..1FA77 ; Extended_Pictographic# E15.0 [3] (🩵..🩷) light blue heart..pink heart
+1FA78..1FA7A ; Extended_Pictographic# E12.0 [3] (🩸..🩺) drop of blood..stethoscope
+1FA7B..1FA7C ; Extended_Pictographic# E14.0 [2] (🩻..🩼) x-ray..crutch
+1FA7D..1FA7F ; Extended_Pictographic# E0.0 [3] (..) ..
+1FA80..1FA82 ; Extended_Pictographic# E12.0 [3] (🪀..🪂) yo-yo..parachute
+1FA83..1FA86 ; Extended_Pictographic# E13.0 [4] (🪃..🪆) boomerang..nesting dolls
+1FA87..1FA88 ; Extended_Pictographic# E15.0 [2] (🪇..🪈) maracas..flute
+1FA89..1FA8F ; Extended_Pictographic# E0.0 [7] (..) ..
+1FA90..1FA95 ; Extended_Pictographic# E12.0 [6] (🪐..🪕) ringed planet..banjo
+1FA96..1FAA8 ; Extended_Pictographic# E13.0 [19] (🪖..🪨) military helmet..rock
+1FAA9..1FAAC ; Extended_Pictographic# E14.0 [4] (🪩..🪬) mirror ball..hamsa
+1FAAD..1FAAF ; Extended_Pictographic# E15.0 [3] (🪭..🪯) folding hand fan..khanda
+1FAB0..1FAB6 ; Extended_Pictographic# E13.0 [7] (🪰..🪶) fly..feather
+1FAB7..1FABA ; Extended_Pictographic# E14.0 [4] (🪷..🪺) lotus..nest with eggs
+1FABB..1FABD ; Extended_Pictographic# E15.0 [3] (🪻..🪽) hyacinth..wing
+1FABE ; Extended_Pictographic# E0.0 [1] ()
+1FABF ; Extended_Pictographic# E15.0 [1] (🪿) goose
+1FAC0..1FAC2 ; Extended_Pictographic# E13.0 [3] (🫀..🫂) anatomical heart..people hugging
+1FAC3..1FAC5 ; Extended_Pictographic# E14.0 [3] (🫃..🫅) pregnant man..person with crown
+1FAC6..1FACD ; Extended_Pictographic# E0.0 [8] (..) ..
+1FACE..1FACF ; Extended_Pictographic# E15.0 [2] (🫎..🫏) moose..donkey
+1FAD0..1FAD6 ; Extended_Pictographic# E13.0 [7] (🫐..🫖) blueberries..teapot
+1FAD7..1FAD9 ; Extended_Pictographic# E14.0 [3] (🫗..🫙) pouring liquid..jar
+1FADA..1FADB ; Extended_Pictographic# E15.0 [2] (🫚..🫛) ginger root..pea pod
+1FADC..1FADF ; Extended_Pictographic# E0.0 [4] (..) ..
+1FAE0..1FAE7 ; Extended_Pictographic# E14.0 [8] (🫠..🫧) melting face..bubbles
+1FAE8 ; Extended_Pictographic# E15.0 [1] (🫨) shaking face
+1FAE9..1FAEF ; Extended_Pictographic# E0.0 [7] (..) ..
+1FAF0..1FAF6 ; Extended_Pictographic# E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands
+1FAF7..1FAF8 ; Extended_Pictographic# E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand
+1FAF9..1FAFF ; Extended_Pictographic# E0.0 [7] (..) ..
+1FC00..1FFFD ; Extended_Pictographic# E0.0[1022] (..) ..
+
+# Total elements: 3537
+
+#EOF
diff --git a/tsconfig.json b/tsconfig.json
index 1a02e20ff1..fc9c15a34f 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -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" },
]
diff --git a/web/README.md b/web/README.md
index f09fe519bb..9e7d896c7b 100644
--- a/web/README.md
+++ b/web/README.md
@@ -94,7 +94,7 @@ graph TD;
LMWorker-->Wordbreakers;
LMLayer["@keymanapp/lexical-model-layer
(/web/src/engine/predictive-text/worker-main)"];
LMLayer-->LMWorker;
- Gestures["@keymanapp/gesture-recognizer
(/common/web/gesture-recognizer)"];
+ Gestures["@keymanapp/gesture-recognizer
(/web/src/engine/osk/gesture-recognizer)"];
Gestures-->WebUtils;
subgraph PredText["PredText: WebWorker + its interface"]
diff --git a/web/build.sh b/web/build.sh
index 16d3d11235..445c4b2e63 100755
--- a/web/build.sh
+++ b/web/build.sh
@@ -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 \
diff --git a/web/ci.sh b/web/ci.sh
index 5e26a1e30e..0dd42fa61e 100755
--- a/web/ci.sh
+++ b/web/ci.sh
@@ -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
diff --git a/web/common.inc.sh b/web/common.inc.sh
index 9457fa5a41..8edfb9f4fa 100644
--- a/web/common.inc.sh
+++ b/web/common.inc.sh
@@ -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() {
diff --git a/web/package.json b/web/package.json
index 96a11c0cd3..5c6684afd3 100644
--- a/web/package.json
+++ b/web/package.json
@@ -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": {
diff --git a/web/src/app/browser/build.sh b/web/src/app/browser/build.sh
index 1d757e264a..d4c1023314 100755
--- a/web/src/app/browser/build.sh
+++ b/web/src/app/browser/build.sh
@@ -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
diff --git a/web/src/app/webview/build.sh b/web/src/app/webview/build.sh
index e22e1b470e..371c9325f2 100755
--- a/web/src/app/webview/build.sh
+++ b/web/src/app/webview/build.sh
@@ -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 \
diff --git a/web/src/engine/js-processor/src/mock.ts b/web/src/engine/js-processor/src/mock.ts
index 151d8313ca..e44b76e759 100644
--- a/web/src/engine/js-processor/src/mock.ts
+++ b/web/src/engine/js-processor/src/mock.ts
@@ -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;
diff --git a/web/src/engine/keyboard/build.sh b/web/src/engine/keyboard/build.sh
index 226a7d9d75..7b04e478a0 100755
--- a/web/src/engine/keyboard/build.sh
+++ b/web/src/engine/keyboard/build.sh
@@ -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"
diff --git a/web/src/engine/osk/build.sh b/web/src/engine/osk/build.sh
index 0d676a2d3e..e54a75bad1 100755
--- a/web/src/engine/osk/build.sh
+++ b/web/src/engine/osk/build.sh
@@ -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" \
diff --git a/common/web/gesture-recognizer/.c8rc.json b/web/src/engine/osk/gesture-processor/.c8rc.json
similarity index 100%
rename from common/web/gesture-recognizer/.c8rc.json
rename to web/src/engine/osk/gesture-processor/.c8rc.json
diff --git a/common/web/gesture-recognizer/.gitignore b/web/src/engine/osk/gesture-processor/.gitignore
similarity index 100%
rename from common/web/gesture-recognizer/.gitignore
rename to web/src/engine/osk/gesture-processor/.gitignore
diff --git a/common/web/gesture-recognizer/README.md b/web/src/engine/osk/gesture-processor/README.md
similarity index 78%
rename from common/web/gesture-recognizer/README.md
rename to web/src/engine/osk/gesture-processor/README.md
index cbb310092d..3b941963de 100644
--- a/common/web/gesture-recognizer/README.md
+++ b/web/src/engine/osk/gesture-processor/README.md
@@ -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.
\ No newline at end of file
diff --git a/web/src/engine/osk/gesture-processor/build.sh b/web/src/engine/osk/gesture-processor/build.sh
new file mode 100755
index 0000000000..b2ea635d8a
--- /dev/null
+++ b/web/src/engine/osk/gesture-processor/build.sh
@@ -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
diff --git a/common/web/gesture-recognizer/docs/host-page-viz.png b/web/src/engine/osk/gesture-processor/docs/host-page-viz.png
similarity index 100%
rename from common/web/gesture-recognizer/docs/host-page-viz.png
rename to web/src/engine/osk/gesture-processor/docs/host-page-viz.png
diff --git a/common/web/gesture-recognizer/docs/recognizer-configuration.md b/web/src/engine/osk/gesture-processor/docs/recognizer-configuration.md
similarity index 100%
rename from common/web/gesture-recognizer/docs/recognizer-configuration.md
rename to web/src/engine/osk/gesture-processor/docs/recognizer-configuration.md
diff --git a/common/web/gesture-recognizer/package.json b/web/src/engine/osk/gesture-processor/package.json
similarity index 88%
rename from common/web/gesture-recognizer/package.json
rename to web/src/engine/osk/gesture-processor/package.json
index 66cf248c0f..fd8e7fcddf 100644
--- a/common/web/gesture-recognizer/package.json
+++ b/web/src/engine/osk/gesture-processor/package.json
@@ -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",
diff --git a/common/web/gesture-recognizer/src/engine/configuration/gestureRecognizerConfiguration.ts b/web/src/engine/osk/gesture-processor/src/engine/configuration/gestureRecognizerConfiguration.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/configuration/gestureRecognizerConfiguration.ts
rename to web/src/engine/osk/gesture-processor/src/engine/configuration/gestureRecognizerConfiguration.ts
diff --git a/common/web/gesture-recognizer/src/engine/configuration/paddedZoneSource.ts b/web/src/engine/osk/gesture-processor/src/engine/configuration/paddedZoneSource.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/configuration/paddedZoneSource.ts
rename to web/src/engine/osk/gesture-processor/src/engine/configuration/paddedZoneSource.ts
diff --git a/common/web/gesture-recognizer/src/engine/configuration/recognitionZoneSource.ts b/web/src/engine/osk/gesture-processor/src/engine/configuration/recognitionZoneSource.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/configuration/recognitionZoneSource.ts
rename to web/src/engine/osk/gesture-processor/src/engine/configuration/recognitionZoneSource.ts
diff --git a/common/web/gesture-recognizer/src/engine/configuration/viewportZoneSource.ts b/web/src/engine/osk/gesture-processor/src/engine/configuration/viewportZoneSource.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/configuration/viewportZoneSource.ts
rename to web/src/engine/osk/gesture-processor/src/engine/configuration/viewportZoneSource.ts
diff --git a/common/web/gesture-recognizer/src/engine/configuration/zoneBoundaryChecker.ts b/web/src/engine/osk/gesture-processor/src/engine/configuration/zoneBoundaryChecker.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/configuration/zoneBoundaryChecker.ts
rename to web/src/engine/osk/gesture-processor/src/engine/configuration/zoneBoundaryChecker.ts
diff --git a/common/web/gesture-recognizer/src/engine/gestureRecognizer.ts b/web/src/engine/osk/gesture-processor/src/engine/gestureRecognizer.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/gestureRecognizer.ts
rename to web/src/engine/osk/gesture-processor/src/engine/gestureRecognizer.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/asyncClosureDispatchQueue.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/asyncClosureDispatchQueue.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/asyncClosureDispatchQueue.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/asyncClosureDispatchQueue.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/cumulativePathStats.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/cumulativePathStats.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/cumulativePathStats.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/cumulativePathStats.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/gestureDebugPath.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/gestureDebugPath.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/gestureDebugPath.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/gestureDebugPath.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/gestureDebugSource.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/gestureDebugSource.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/gestureDebugSource.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/gestureDebugSource.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/gesturePath.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/gesturePath.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/gesturePath.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/gesturePath.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/gestureSource.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/gestureSource.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/gestureSource.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/gestureSource.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/gestures/index.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/gestures/index.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/gestures/index.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/gestures/index.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/gestures/matchers/gestureMatcher.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/gestures/matchers/gestureMatcher.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/gestures/matchers/gestureMatcher.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/gestures/matchers/gestureMatcher.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/gestures/matchers/gestureSequence.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/gestures/matchers/gestureSequence.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/gestures/matchers/gestureSequence.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/gestures/matchers/gestureSequence.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/gestures/matchers/index.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/gestures/matchers/index.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/gestures/matchers/index.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/gestures/matchers/index.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/gestures/matchers/matcherSelector.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/gestures/matchers/matcherSelector.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/gestures/matchers/matcherSelector.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/gestures/matchers/matcherSelector.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/gestures/matchers/pathMatcher.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/gestures/matchers/pathMatcher.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/gestures/matchers/pathMatcher.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/gestures/matchers/pathMatcher.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/gestures/specs/contactModel.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/gestures/specs/contactModel.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/gestures/specs/contactModel.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/gestures/specs/contactModel.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/gestures/specs/gestureModel.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/gestures/specs/gestureModel.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/gestures/specs/gestureModel.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/gestures/specs/gestureModel.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/gestures/specs/gestureModelDefs.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/gestures/specs/gestureModelDefs.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/gestures/specs/gestureModelDefs.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/gestures/specs/gestureModelDefs.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/gestures/specs/index.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/gestures/specs/index.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/gestures/specs/index.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/gestures/specs/index.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/gestures/specs/modelDefValidator.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/gestures/specs/modelDefValidator.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/gestures/specs/modelDefValidator.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/gestures/specs/modelDefValidator.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/gestures/specs/pathModel.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/gestures/specs/pathModel.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/gestures/specs/pathModel.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/gestures/specs/pathModel.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/inputEngineBase.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/inputEngineBase.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/inputEngineBase.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/inputEngineBase.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/inputSample.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/inputSample.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/inputSample.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/inputSample.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/segmentClassifier.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/segmentClassifier.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/segmentClassifier.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/segmentClassifier.ts
diff --git a/common/web/gesture-recognizer/src/engine/headless/touchpointCoordinator.ts b/web/src/engine/osk/gesture-processor/src/engine/headless/touchpointCoordinator.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/headless/touchpointCoordinator.ts
rename to web/src/engine/osk/gesture-processor/src/engine/headless/touchpointCoordinator.ts
diff --git a/common/web/gesture-recognizer/src/engine/index.ts b/web/src/engine/osk/gesture-processor/src/engine/index.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/index.ts
rename to web/src/engine/osk/gesture-processor/src/engine/index.ts
diff --git a/common/web/gesture-recognizer/src/engine/inputEventEngine.ts b/web/src/engine/osk/gesture-processor/src/engine/inputEventEngine.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/inputEventEngine.ts
rename to web/src/engine/osk/gesture-processor/src/engine/inputEventEngine.ts
diff --git a/common/web/gesture-recognizer/src/engine/mouseEventEngine.ts b/web/src/engine/osk/gesture-processor/src/engine/mouseEventEngine.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/mouseEventEngine.ts
rename to web/src/engine/osk/gesture-processor/src/engine/mouseEventEngine.ts
diff --git a/common/web/gesture-recognizer/src/engine/mutable.ts b/web/src/engine/osk/gesture-processor/src/engine/mutable.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/mutable.ts
rename to web/src/engine/osk/gesture-processor/src/engine/mutable.ts
diff --git a/common/web/gesture-recognizer/src/engine/nonoptional.ts b/web/src/engine/osk/gesture-processor/src/engine/nonoptional.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/nonoptional.ts
rename to web/src/engine/osk/gesture-processor/src/engine/nonoptional.ts
diff --git a/common/web/gesture-recognizer/src/engine/reportError.ts b/web/src/engine/osk/gesture-processor/src/engine/reportError.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/reportError.ts
rename to web/src/engine/osk/gesture-processor/src/engine/reportError.ts
diff --git a/common/web/gesture-recognizer/src/engine/touchEventEngine.ts b/web/src/engine/osk/gesture-processor/src/engine/touchEventEngine.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/engine/touchEventEngine.ts
rename to web/src/engine/osk/gesture-processor/src/engine/touchEventEngine.ts
diff --git a/common/web/gesture-recognizer/src/tools/build.sh b/web/src/engine/osk/gesture-processor/src/tools/build.sh
similarity index 54%
rename from common/web/gesture-recognizer/src/tools/build.sh
rename to web/src/engine/osk/gesture-processor/src/tools/build.sh
index 657a8ab1bf..1813ab62a8 100755
--- a/common/web/gesture-recognizer/src/tools/build.sh
+++ b/web/src/engine/osk/gesture-processor/src/tools/build.sh
@@ -3,61 +3,49 @@
## 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"
+. "$(dirname "$THIS_SCRIPT")/../../../../../../../resources/build/builder.inc.sh"
## END STANDARD BUILD SCRIPT INCLUDE
+. "$KEYMAN_ROOT/web/common.inc.sh"
. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh"
BUNDLE_CMD="node $KEYMAN_ROOT/common/web/es-bundling/build/common-bundle.mjs"
+BASE_DIR="/web/src/engine/osk/gesture-processor"
+BUILD_DIR="${BASE_DIR}/build"
+
################################ Main script ################################
-builder_describe "Testing-oriented tools for the Gesture Recognizer module of web-based Keyman OSKs" \
+builder_describe "Testing-oriented tools for the Gesture Processor module of web-based Keyman OSKs" \
"clean" \
"build" \
":fixture The HTML-element fixture and CSS fixture used for both user-testing and unit-testing" \
":recorder The web page used for recording input sequences for use in unit-testing" \
- ":test-module The TS library used to interface with the main gesture-recognizer module for tests"
+ ":test-module The TS library used to interface with the main gesture-processor module for tests"
builder_parse "$@"
builder_describe_outputs \
configure /node_modules \
- build:fixture /common/web/gesture-recognizer/build/tools/host-fixture.html \
- build:recorder /common/web/gesture-recognizer/src/tools/recorder/build/recorder.mjs \
- build:test-module /common/web/gesture-recognizer/build/tools/lib/index.mjs
+ build:fixture "${BUILD_DIR}/tools/host-fixture.html" \
+ build:recorder "${BASE_DIR}/src/tools/recorder/build/recorder.mjs" \
+ build:test-module "${BUILD_DIR}/tools/lib/index.mjs"
# TODO: build if out-of-date if test is specified
# TODO: configure if npm has not been run, and build is specified
-if builder_start_action clean:recorder; then
- rm -rf ./recorder/build
- builder_finish_action success clean:recorder
-fi
-
-if builder_start_action clean:fixture; then
+function do_clean_fixture() {
rm -f ../../build/tools/host-fixture.html
rm -f ../../build/tools/gestureHost.css
- builder_finish_action success clean:fixture
-fi
+}
-if builder_start_action clean:test-module; then
+function do_clean_testmodule() {
rm -rf ../../build/tools/*.ts*
rm -rf ../../build/tools/*.js*
- builder_finish_action success clean:test-module
-fi
+}
-if builder_start_action build:fixture; then
- if [ ! -d ../../build/tools ]; then
- mkdir -p ../../build/tools
- fi
- ./host-fixture/extract-fixture.sh > ../../build/tools/host-fixture.html
- cp ./host-fixture/gestureHost.css ../../build/tools/gestureHost.css
- builder_finish_action success build:fixture
-fi
-
-if builder_start_action build:recorder; then
- if [ ! -d recorder/build ]; then
+function do_build_recorder() {
+ if [[ ! -d recorder/build ]]; then
mkdir -p recorder/build
fi
cp recorder/src/pageStyle.css recorder/build/pageStyle.css
@@ -70,15 +58,27 @@ if builder_start_action build:recorder; then
pushd recorder >/dev/null
node update-index.cjs build/index.html
popd >/dev/null
- builder_finish_action success build:recorder
-fi
+}
-if builder_start_action build:test-module; then
- tsc -b "$THIS_SCRIPT_PATH/unit-test-resources/tsconfig.json"
+function do_build_fixture() {
+ if [[ ! -d ../../build/tools ]]; then
+ mkdir -p ../../build/tools
+ fi
+ ./host-fixture/extract-fixture.sh > ../../build/tools/host-fixture.html
+ cp ./host-fixture/gestureHost.css ../../build/tools/gestureHost.css
+}
- $BUNDLE_CMD "${KEYMAN_ROOT}/common/web/gesture-recognizer/build/tools/obj/index.js" \
- --out "${KEYMAN_ROOT}/common/web/gesture-recognizer/build/tools/lib/index.mjs" \
+function do_build_testmodule() {
+ compile "" "${THIS_SCRIPT_PATH}/unit-test-resources" "${KEYMAN_ROOT}/${BUILD_DIR}/tools"
+
+ $BUNDLE_CMD "${KEYMAN_ROOT}/${BUILD_DIR}/tools/obj/index.js" \
+ --out "${KEYMAN_ROOT}/${BUILD_DIR}/tools/lib/index.mjs" \
--format "esm"
+}
- builder_finish_action success build:test-module
-fi
\ No newline at end of file
+builder_run_action clean:recorder rm -rf ./recorder/build
+builder_run_action clean:fixture do_clean_fixture
+builder_run_action clean:test-module do_clean_testmodule
+builder_run_action build:recorder do_build_recorder
+builder_run_action build:fixture do_build_fixture
+builder_run_action build:test-module do_build_testmodule
diff --git a/common/web/gesture-recognizer/src/tools/host-fixture/extract-fixture.sh b/web/src/engine/osk/gesture-processor/src/tools/host-fixture/extract-fixture.sh
similarity index 100%
rename from common/web/gesture-recognizer/src/tools/host-fixture/extract-fixture.sh
rename to web/src/engine/osk/gesture-processor/src/tools/host-fixture/extract-fixture.sh
diff --git a/common/web/gesture-recognizer/src/tools/host-fixture/extractor.cjs b/web/src/engine/osk/gesture-processor/src/tools/host-fixture/extractor.cjs
similarity index 100%
rename from common/web/gesture-recognizer/src/tools/host-fixture/extractor.cjs
rename to web/src/engine/osk/gesture-processor/src/tools/host-fixture/extractor.cjs
diff --git a/common/web/gesture-recognizer/src/test/auto/browser/cases/gestureHost.css b/web/src/engine/osk/gesture-processor/src/tools/host-fixture/gestureHost.css
similarity index 100%
rename from common/web/gesture-recognizer/src/test/auto/browser/cases/gestureHost.css
rename to web/src/engine/osk/gesture-processor/src/tools/host-fixture/gestureHost.css
diff --git a/common/web/gesture-recognizer/src/tools/host-fixture/host-fixture.html b/web/src/engine/osk/gesture-processor/src/tools/host-fixture/host-fixture.html
similarity index 100%
rename from common/web/gesture-recognizer/src/tools/host-fixture/host-fixture.html
rename to web/src/engine/osk/gesture-processor/src/tools/host-fixture/host-fixture.html
diff --git a/common/web/gesture-recognizer/src/tools/recorder/src/index.html b/web/src/engine/osk/gesture-processor/src/tools/recorder/src/index.html
similarity index 100%
rename from common/web/gesture-recognizer/src/tools/recorder/src/index.html
rename to web/src/engine/osk/gesture-processor/src/tools/recorder/src/index.html
diff --git a/common/web/gesture-recognizer/src/tools/recorder/src/pageStyle.css b/web/src/engine/osk/gesture-processor/src/tools/recorder/src/pageStyle.css
similarity index 100%
rename from common/web/gesture-recognizer/src/tools/recorder/src/pageStyle.css
rename to web/src/engine/osk/gesture-processor/src/tools/recorder/src/pageStyle.css
diff --git a/common/web/gesture-recognizer/src/tools/recorder/src/recorder.mjs b/web/src/engine/osk/gesture-processor/src/tools/recorder/src/recorder.mjs
similarity index 100%
rename from common/web/gesture-recognizer/src/tools/recorder/src/recorder.mjs
rename to web/src/engine/osk/gesture-processor/src/tools/recorder/src/recorder.mjs
diff --git a/common/web/gesture-recognizer/src/tools/recorder/update-index.cjs b/web/src/engine/osk/gesture-processor/src/tools/recorder/update-index.cjs
similarity index 100%
rename from common/web/gesture-recognizer/src/tools/recorder/update-index.cjs
rename to web/src/engine/osk/gesture-processor/src/tools/recorder/update-index.cjs
diff --git a/common/web/gesture-recognizer/src/tools/unit-test-resources/build-bundler.js b/web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/build-bundler.js
similarity index 100%
rename from common/web/gesture-recognizer/src/tools/unit-test-resources/build-bundler.js
rename to web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/build-bundler.js
diff --git a/common/web/gesture-recognizer/src/tools/unit-test-resources/src/fixtureLayoutConfiguration.ts b/web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/src/fixtureLayoutConfiguration.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/tools/unit-test-resources/src/fixtureLayoutConfiguration.ts
rename to web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/src/fixtureLayoutConfiguration.ts
diff --git a/common/web/gesture-recognizer/src/tools/unit-test-resources/src/headlessInputEngine.ts b/web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/src/headlessInputEngine.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/tools/unit-test-resources/src/headlessInputEngine.ts
rename to web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/src/headlessInputEngine.ts
diff --git a/common/web/gesture-recognizer/src/tools/unit-test-resources/src/hostFixtureLayoutController.ts b/web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/src/hostFixtureLayoutController.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/tools/unit-test-resources/src/hostFixtureLayoutController.ts
rename to web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/src/hostFixtureLayoutController.ts
diff --git a/common/web/gesture-recognizer/src/tools/unit-test-resources/src/index.ts b/web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/src/index.ts
similarity index 87%
rename from common/web/gesture-recognizer/src/tools/unit-test-resources/src/index.ts
rename to web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/src/index.ts
index e3bf02cc37..dfc9740330 100644
--- a/common/web/gesture-recognizer/src/tools/unit-test-resources/src/index.ts
+++ b/web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/src/index.ts
@@ -1,6 +1,7 @@
export * from './fixtureLayoutConfiguration.js';
export * from './headlessInputEngine.js';
export * from './hostFixtureLayoutController.js';
+export * from './inputRecording.js';
export * from './inputSequenceSimulator.js';
export * from './sequenceRecorder.js';
export * from './touchpathTurtle.js';
\ No newline at end of file
diff --git a/common/web/gesture-recognizer/src/tools/unit-test-resources/src/inputRecording.ts b/web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/src/inputRecording.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/tools/unit-test-resources/src/inputRecording.ts
rename to web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/src/inputRecording.ts
diff --git a/common/web/gesture-recognizer/src/tools/unit-test-resources/src/inputSequenceSimulator.ts b/web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/src/inputSequenceSimulator.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/tools/unit-test-resources/src/inputSequenceSimulator.ts
rename to web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/src/inputSequenceSimulator.ts
diff --git a/common/web/gesture-recognizer/src/tools/unit-test-resources/src/jsonObject.ts b/web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/src/jsonObject.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/tools/unit-test-resources/src/jsonObject.ts
rename to web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/src/jsonObject.ts
diff --git a/common/web/gesture-recognizer/src/tools/unit-test-resources/src/sequenceRecorder.ts b/web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/src/sequenceRecorder.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/tools/unit-test-resources/src/sequenceRecorder.ts
rename to web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/src/sequenceRecorder.ts
diff --git a/common/web/gesture-recognizer/src/tools/unit-test-resources/src/touchpathTurtle.ts b/web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/src/touchpathTurtle.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/tools/unit-test-resources/src/touchpathTurtle.ts
rename to web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/src/touchpathTurtle.ts
diff --git a/common/web/gesture-recognizer/src/tools/unit-test-resources/tsconfig.json b/web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/tsconfig.json
similarity index 84%
rename from common/web/gesture-recognizer/src/tools/unit-test-resources/tsconfig.json
rename to web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/tsconfig.json
index 7254159211..34d1929af1 100644
--- a/common/web/gesture-recognizer/src/tools/unit-test-resources/tsconfig.json
+++ b/web/src/engine/osk/gesture-processor/src/tools/unit-test-resources/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "../../../../tsconfig.kmw-main-base.json",
+ "extends": "../../../../../../../tsconfig.base.json",
"compilerOptions": {
"baseUrl": "./",
"lib": [ "dom", "es6" ],
diff --git a/common/web/gesture-recognizer/tsconfig.json b/web/src/engine/osk/gesture-processor/tsconfig.json
similarity index 61%
rename from common/web/gesture-recognizer/tsconfig.json
rename to web/src/engine/osk/gesture-processor/tsconfig.json
index c4ff34e963..0b2d3a87b9 100644
--- a/common/web/gesture-recognizer/tsconfig.json
+++ b/web/src/engine/osk/gesture-processor/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "../tsconfig.kmw-main-base.json",
+ "extends": "../../../../tsconfig.base.json",
"compilerOptions": {
"baseUrl": "./",
"lib": [ "dom", "es6" ],
@@ -8,8 +8,8 @@
"tsBuildInfoFile": "./build/obj/tsconfig.tsbuildinfo",
},
"include": ["./src/engine/**/*.ts"],
- "exclude": ["./src/test/**/*.ts", "./src/tools/**/*.ts"],
"references": [
- { "path": "../utils" }
- ]
+ { "path": "../../../../../common/web/utils" },
+ ],
+ "exclude": ["./src/test/**/*.ts", "./src/tools/**/*.ts"]
}
diff --git a/web/src/engine/osk/src/visualKeyboard.ts b/web/src/engine/osk/src/visualKeyboard.ts
index 013ad76241..570a82a209 100644
--- a/web/src/engine/osk/src/visualKeyboard.ts
+++ b/web/src/engine/osk/src/visualKeyboard.ts
@@ -1239,6 +1239,7 @@ export default class VisualKeyboard extends EventEmitter implements Ke
const groupStyle = getComputedStyle(this.layerGroup.element);
const isInDOM = computedStyle.height != '' && computedStyle.height != 'auto';
+ const isGroupInDOM = groupStyle.height != '' && groupStyle.height != 'auto';
if (computedStyle.border) {
this._borderWidth = new ParsedLengthStyle(computedStyle.borderWidth).val;
@@ -1251,10 +1252,11 @@ export default class VisualKeyboard extends EventEmitter implements Ke
this._computedHeight = this.height;
} else if (isInDOM) {
this._computedWidth = parseInt(computedStyle.width, 10);
- if (!this._computedWidth) {
- this._computedWidth = parseInt(groupStyle.width, 10);
- }
this._computedHeight = parseInt(computedStyle.height, 10);
+ } else if (isGroupInDOM) {
+ // May occur for documentation-keyboards, which are detached from their VisualKeyboard base.
+ this._computedWidth = parseInt(groupStyle.width, 10);
+ this._computedHeight = parseInt(groupStyle.height, 10);
} else {
// Cannot perform layout operations!
return;
@@ -1597,6 +1599,16 @@ export default class VisualKeyboard extends EventEmitter implements Ke
// the page.
kbdObj.appendStyleSheet();
+ // Unset the width + height we used thus far; this method's consumer may choose to rescale
+ // the returned element. If so, we don't want to use our outdated value by mistake.
+ //
+ // While `kbdObj.setSize()` could be used in theory, it _also_ unsets the element styling.
+ // We actually wish to _leave_ this styling in place - one of our parameters is `height`, and
+ // it should remain in place in the styling on the output element as the default in case
+ // the consumer _doesn't_ add styling afterward.
+ delete kbdObj._width;
+ delete kbdObj._height;
+
return classWrapper;
}
diff --git a/web/src/engine/osk/tsconfig.json b/web/src/engine/osk/tsconfig.json
index 0f24be8efa..629443ed50 100644
--- a/web/src/engine/osk/tsconfig.json
+++ b/web/src/engine/osk/tsconfig.json
@@ -12,7 +12,7 @@
"include": [ "src/**/*.ts" ],
"references": [
- { "path": "../../../../common/web/gesture-recognizer" },
+ { "path": "./gesture-processor" },
{ "path": "../interfaces" },
{ "path": "../dom-utils" },
{ "path": "../events" }
diff --git a/web/src/engine/predictive-text/worker-thread/build.sh b/web/src/engine/predictive-text/worker-thread/build.sh
index 8c6a4ca001..a77e863c73 100755
--- a/web/src/engine/predictive-text/worker-thread/build.sh
+++ b/web/src/engine/predictive-text/worker-thread/build.sh
@@ -64,6 +64,7 @@ function do_build() {
# The ES6 target needs no polyfills - we go straight to the wrapped version.
$bundle_cmd src/main/worker-main.ts \
--out $INTERMEDIATE/worker-main.js \
+ --charset "utf8" \
--target "es6" \
--sourceRoot '@keymanapp/keyman/web/src/engine/predictive-text/worker-thread/src/main'
@@ -75,6 +76,7 @@ function do_build() {
$bundle_cmd src/main/worker-main.ts \
--out $INTERMEDIATE/worker-main.min.js \
--minify \
+ --charset "utf8" \
--profile build/filesize-profile.log \
--target "es6" \
--sourceRoot '@keymanapp/keyman/web/src/engine/predictive-text/worker-thread/src/main'
diff --git a/common/web/gesture-recognizer/src/test/auto/browser/cases/canary.def.ts b/web/src/test/auto/dom/cases/gesture-processor/canary.spec.ts
similarity index 87%
rename from common/web/gesture-recognizer/src/test/auto/browser/cases/canary.def.ts
rename to web/src/test/auto/dom/cases/gesture-processor/canary.spec.ts
index 241977b322..78fbcf6f79 100644
--- a/common/web/gesture-recognizer/src/test/auto/browser/cases/canary.def.ts
+++ b/web/src/test/auto/dom/cases/gesture-processor/canary.spec.ts
@@ -2,10 +2,14 @@ import { assert } from 'chai';
import sinon from 'sinon';
import {
+ DeviceLayoutClass,
FixtureLayoutConfiguration,
HostFixtureLayoutController,
- InputSequenceSimulator
-} from '#tools';
+ InputSequenceSimulator,
+ ReceiverLayoutClass,
+ RoamingLayoutClass,
+ SafeLayoutClass
+} from '#gesture-tools';
import { DEFAULT_BROWSER_TIMEOUT } from '@keymanapp/common-test-resources/test-timeouts.mjs';
@@ -75,11 +79,11 @@ describe("'Canary' checks", function() {
it("InputSequenceSimulator.replayTouchSample", async function() {
let playbackEngine = new InputSequenceSimulator(this.controller);
- let layout = new FixtureLayoutConfiguration("screen2", "bounds1", "full", "safe-loose");
+ let layout = new FixtureLayoutConfiguration("screen2" as DeviceLayoutClass, "bounds1" as RoamingLayoutClass, "full" as ReceiverLayoutClass, "safe-loose" as SafeLayoutClass);
this.controller.layoutConfiguration = layout;
let fireEvent = () => {
- playbackEngine.replayTouchSamples(/*relative coord:*/ [ { sample: {targetX: 10, targetY: 10}, identifier: 1}],
+ playbackEngine.replayTouchSamples(/*relative coord:*/ [ { sample: {targetX: 10, targetY: 10, t: 0}, identifier: 1}],
/*state:*/ "start",
/*recentTouches:*/ [],
);
@@ -101,11 +105,11 @@ describe("'Canary' checks", function() {
it("InputSequenceSimulator.replayMouseSample", async function() {
let playbackEngine = new InputSequenceSimulator(this.controller);
- let layout = new FixtureLayoutConfiguration("screen2", "bounds1", "full", "safe-loose");
+ let layout = new FixtureLayoutConfiguration("screen2" as DeviceLayoutClass, "bounds1" as RoamingLayoutClass, "full" as ReceiverLayoutClass, "safe-loose" as SafeLayoutClass);
this.controller.layoutConfiguration = layout;
let fireEvent = () => {
- playbackEngine.replayMouseSample(/*relative coord:*/ {targetX: 15, targetY: 15},
+ playbackEngine.replayMouseSample(/*relative coord:*/ {targetX: 15, targetY: 15, t: 0},
/*state:*/ "start"
);
}
diff --git a/common/web/gesture-recognizer/src/tools/host-fixture/gestureHost.css b/web/src/test/auto/dom/cases/gesture-processor/gestureHost.css
similarity index 100%
rename from common/web/gesture-recognizer/src/tools/host-fixture/gestureHost.css
rename to web/src/test/auto/dom/cases/gesture-processor/gestureHost.css
diff --git a/common/web/gesture-recognizer/src/test/auto/browser/cases/host-page.spec.html b/web/src/test/auto/dom/cases/gesture-processor/host-page.spec.html
similarity index 90%
rename from common/web/gesture-recognizer/src/test/auto/browser/cases/host-page.spec.html
rename to web/src/test/auto/dom/cases/gesture-processor/host-page.spec.html
index c4a4d7a47e..ce3aae6c48 100644
--- a/common/web/gesture-recognizer/src/test/auto/browser/cases/host-page.spec.html
+++ b/web/src/test/auto/dom/cases/gesture-processor/host-page.spec.html
@@ -1,6 +1,6 @@
+ imports for the .spec.js test suites. -->
@@ -18,9 +18,9 @@
import { runTests } from '@web/test-runner-mocha';
runTests(async() => {
- await import('./canary.def.ts');
- await import('./ignoredInputs.def.ts');
- await import('./recordedCoordSequences.def.ts');
+ await import('./canary.spec.ts');
+ await import('./ignoredInputs.spec.ts');
+ await import('./recordedCoordSequences.spec.ts');
});
diff --git a/common/web/gesture-recognizer/src/test/auto/browser/cases/ignoredInputs.def.ts b/web/src/test/auto/dom/cases/gesture-processor/ignoredInputs.spec.ts
similarity index 82%
rename from common/web/gesture-recognizer/src/test/auto/browser/cases/ignoredInputs.def.ts
rename to web/src/test/auto/dom/cases/gesture-processor/ignoredInputs.spec.ts
index b107fdea5d..a288f925a3 100644
--- a/common/web/gesture-recognizer/src/test/auto/browser/cases/ignoredInputs.def.ts
+++ b/web/src/test/auto/dom/cases/gesture-processor/ignoredInputs.spec.ts
@@ -5,8 +5,12 @@ import {
FixtureLayoutConfiguration,
HostFixtureLayoutController,
InputSequenceSimulator,
- SequenceRecorder
-} from '#tools';
+ SequenceRecorder,
+ DeviceLayoutClass,
+ RoamingLayoutClass,
+ ReceiverLayoutClass,
+ SafeLayoutClass
+} from '#gesture-tools';
import { DEFAULT_BROWSER_TIMEOUT } from '@keymanapp/common-test-resources/test-timeouts.mjs';
@@ -28,19 +32,20 @@ describe("Layer one - DOM -> InputSequence", function() {
it("starts in roaming zone are ignored", function() {
let playbackEngine = new InputSequenceSimulator(controller);
let recorder = new SequenceRecorder(controller);
- let layout = new FixtureLayoutConfiguration("screen2", "bounds1", "full", "safe-loose");
+ let layout = new FixtureLayoutConfiguration("screen2" as DeviceLayoutClass, "bounds1" as RoamingLayoutClass, "full" as ReceiverLayoutClass, "safe-loose" as SafeLayoutClass);
controller.layoutConfiguration = layout;
let fireEvent = () => {
- playbackEngine.replayTouchSamples(/*relative coord:*/ [{sample: {targetX: 10, targetY: -5}, identifier: 1}],
+ playbackEngine.replayTouchSamples(/*relative coord:*/ [{sample: {targetX: 10, targetY: -5, t: 0}, identifier: 1}],
/*state:*/ "start",
/*recentTouches:*/ [],
- /*targetElement:*/ controller.recognizer.config.maxRoamingBounds
+ /*targetElement:*/ controller.recognizer.config.maxRoamingBounds as HTMLElement
);
}
// This test is invalidated if the handler itself isn't called. So... let's verify that!
// This requires white-box inspection of the actual handler control-flow, and we must do
+ // @ts-ignore // touchEngine is private
let touchEngine = controller.recognizer.touchEngine;
let trueHandler = touchEngine.onTouchStart;
let fakeHandler = touchEngine.onTouchStart = sinon.fake();
@@ -61,11 +66,11 @@ describe("Layer one - DOM -> InputSequence", function() {
it("ignores target-external events", function() {
let playbackEngine = new InputSequenceSimulator(controller);
let recorder = new SequenceRecorder(controller);
- let layout = new FixtureLayoutConfiguration("screen2", "bounds1", "full", "safe-loose");
+ let layout = new FixtureLayoutConfiguration("screen2" as DeviceLayoutClass, "bounds1" as RoamingLayoutClass, "full" as ReceiverLayoutClass, "safe-loose" as SafeLayoutClass);
controller.layoutConfiguration = layout;
let fireEvent = () => {
- playbackEngine.replayMouseSample(/*relative coord:*/ {targetX: -5, targetY: 15},
+ playbackEngine.replayMouseSample(/*relative coord:*/ {targetX: -5, targetY: 15, t: 0},
/*state:*/ "start",
/*targetElement:*/ document.body
);
@@ -73,6 +78,7 @@ describe("Layer one - DOM -> InputSequence", function() {
// This test is invalidated if the handler itself isn't called. So... let's verify that!
// Not quite covered by the canary cases b/c of the distinct targetElement.
+ // @ts-ignore // touchEngine is private
let mouseEngine = controller.recognizer.mouseEngine;
let trueHandler = mouseEngine.onMouseStart;
let fakeHandler = mouseEngine.onMouseStart = sinon.fake();
diff --git a/common/web/gesture-recognizer/src/test/auto/browser/cases/recordedCoordSequences.def.ts b/web/src/test/auto/dom/cases/gesture-processor/recordedCoordSequences.spec.ts
similarity index 88%
rename from common/web/gesture-recognizer/src/test/auto/browser/cases/recordedCoordSequences.def.ts
rename to web/src/test/auto/dom/cases/gesture-processor/recordedCoordSequences.spec.ts
index 95af23b61d..06136c66a7 100644
--- a/common/web/gesture-recognizer/src/test/auto/browser/cases/recordedCoordSequences.def.ts
+++ b/web/src/test/auto/dom/cases/gesture-processor/recordedCoordSequences.spec.ts
@@ -5,12 +5,13 @@ import type { GestureDebugSource, InputSample, SerializedGestureSource } from '@
import {
HostFixtureLayoutController,
- InputSequenceSimulator
-} from '#tools';
+ InputSequenceSimulator,
+ RecordedCoordSequenceSet
+} from '#gesture-tools';
function isOnAndroid() {
const agent=navigator.userAgent;
- return agent.indexOf('Android' >= 0);
+ return agent.indexOf('Android') >= 0;
}
const loc = document.location;
@@ -18,7 +19,7 @@ const loc = document.location;
// filesystem for the drive.
const domain = `${loc.protocol}/${loc.host}`
-async function fetchRecording(jsonFilename) {
+async function fetchRecording(jsonFilename: string): Promise {
const jsonResponse = await fetch(new URL(`${domain}/resources/json/${jsonFilename}.json`));
return await jsonResponse.json();
}
@@ -47,7 +48,7 @@ describe("Layer one - DOM -> InputSequence", function() {
});
// We rely on this function to have the same context as `it` - the test-definition function.
- let replayAndCompare = function(testObj) {
+ let replayAndCompare = function(testObj: RecordedCoordSequenceSet, mochaContext: Mocha.Context) {
let playbackEngine = new InputSequenceSimulator(controller);
// **********************************
@@ -68,18 +69,18 @@ describe("Layer one - DOM -> InputSequence", function() {
// replayAsync sets up timeouts against the `clock` object.
// This will run through the simulated timeout queue asynchronously.
- this.clock.runAllAsync();
+ mochaContext.clock.runAllAsync();
// resultPromise resolves on the final timeout in the queue.
- return resultPromise.then((result) => {
+ return resultPromise.then((result: RecordedCoordSequenceSet) => {
assert.equal(result.inputs.length, testObj.inputs.length);
// Removes the timestamp element; we know that this component may not match perfectly.
- let sampleCleaner = (sample) => { return {targetX: sample.targetX, targetY: sample.targetY} };
+ let sampleCleaner = (sample: InputSample) => { return {targetX: sample.targetX, targetY: sample.targetY} };
// Returns just the observed, cleaned samples for a sequence object. The recorded coordinates
// should match perfectly.
- let seqCleaner = (input) => {
+ let seqCleaner = (input: SerializedGestureSource) => {
return input.path.coords.map(sampleCleaner);
};
@@ -124,7 +125,7 @@ describe("Layer one - DOM -> InputSequence", function() {
// The 'terminationEvent' property should match. Any sequence that was "canceled" should still
// cancel; that's a pretty critical detail!
- let terminationEventMapper = (seq) => {
+ let terminationEventMapper = (seq: SerializedGestureSource) => {
return seq.path.wasCancelled;
}
@@ -151,7 +152,7 @@ describe("Layer one - DOM -> InputSequence", function() {
// 'describe' has a notably different `this` reference than `it`, `before`, etc,
// hence the `.call` construction.
- return replayAndCompare.call(this, testObj);
+ return replayAndCompare.call(this, testObj, this);
});
}
});
diff --git a/web/src/test/auto/dom/cases/keyboard/domKeyboardLoader.spec.ts b/web/src/test/auto/dom/cases/keyboard/domKeyboardLoader.spec.ts
index da610402eb..95db91b0f8 100644
--- a/web/src/test/auto/dom/cases/keyboard/domKeyboardLoader.spec.ts
+++ b/web/src/test/auto/dom/cases/keyboard/domKeyboardLoader.spec.ts
@@ -30,7 +30,7 @@ describe('Keyboard loading in DOM', function() {
it('`window`, disabled rule processing', async () => {
const harness = new KeyboardHarness(window, MinimalKeymanGlobal);
let keyboardLoader = new DOMKeyboardLoader(harness);
- let keyboard: Keyboard = await keyboardLoader.loadKeyboardFromPath('/resources/keyboards/khmer_angkor.js');
+ let keyboard: Keyboard = await keyboardLoader.loadKeyboardFromPath('/common/test/resources/keyboards/khmer_angkor.js');
assert.isOk(keyboard);
assert.equal(keyboard.id, 'Keyboard_khmer_angkor');
@@ -48,7 +48,7 @@ describe('Keyboard loading in DOM', function() {
it('`window`, enabled rule processing', async () => {
const harness = new KeyboardInterface(window, MinimalKeymanGlobal);
const keyboardLoader = new DOMKeyboardLoader(harness);
- const keyboard: Keyboard = await keyboardLoader.loadKeyboardFromPath('/resources/keyboards/khmer_angkor.js');
+ const keyboard: Keyboard = await keyboardLoader.loadKeyboardFromPath('/common/test/resources/keyboards/khmer_angkor.js');
harness.activeKeyboard = keyboard;
assert.isOk(keyboard);
@@ -80,14 +80,14 @@ describe('Keyboard loading in DOM', function() {
let keyboardLoader = new DOMKeyboardLoader(harness);
// Preload a keyboard and make it active.
- const test_kbd: Keyboard = await keyboardLoader.loadKeyboardFromPath('/resources/keyboards/test_917.js');
+ const test_kbd: Keyboard = await keyboardLoader.loadKeyboardFromPath('/common/test/resources/keyboards/test_917.js');
harness.activeKeyboard = test_kbd;
assert.isNotOk(harness.loadedKeyboard);
// With an active keyboard, load three keyboards but activate none of them.
- const lao_keyboard_promise = keyboardLoader.loadKeyboardFromPath('/resources/keyboards/lao_2008_basic.js');
- const khmer_keyboard_promise = keyboardLoader.loadKeyboardFromPath('/resources/keyboards/khmer_angkor.js');
- const chiral_keyboard_promise = keyboardLoader.loadKeyboardFromPath('/resources/keyboards/test_chirality.js');
+ const lao_keyboard_promise = keyboardLoader.loadKeyboardFromPath('/common/test/resources/keyboards/lao_2008_basic.js');
+ const khmer_keyboard_promise = keyboardLoader.loadKeyboardFromPath('/common/test/resources/keyboards/khmer_angkor.js');
+ const chiral_keyboard_promise = keyboardLoader.loadKeyboardFromPath('/common/test/resources/keyboards/test_chirality.js');
// Sure, why not `await` out of order?
const chiral_keyboard = await chiral_keyboard_promise;
diff --git a/web/src/test/auto/dom/web-test-runner.config.mjs b/web/src/test/auto/dom/web-test-runner.config.mjs
index 62edfc7dbf..3050837cd5 100644
--- a/web/src/test/auto/dom/web-test-runner.config.mjs
+++ b/web/src/test/auto/dom/web-test-runner.config.mjs
@@ -1,8 +1,8 @@
// @ts-check
import { devices, playwrightLauncher } from '@web/test-runner-playwright';
import { defaultReporter, summaryReporter } from '@web/test-runner';
-import teamcityReporter from '@keymanapp/common-test-resources/test-runner-TC-reporter.mjs';
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 { importMapsPlugin } from '@web/dev-server-import-maps';
import { dirname, resolve } from 'path';
import { fileURLToPath } from 'url';
@@ -17,7 +17,17 @@ export default {
browsers: [
new LauncherWrapper(playwrightLauncher({ product: 'chromium' })),
new LauncherWrapper(playwrightLauncher({ product: 'firefox' })),
- new LauncherWrapper(playwrightLauncher({ product: 'webkit', concurrency: 1 }))
+ new LauncherWrapper(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,
@@ -51,14 +61,25 @@ export default {
files: ['build/test/dom/cases/element-wrappers/**/*.spec.mjs']
},
{
- name: 'engine/osk',
+ name: 'engine/gesture-processor',
// Relative, from the containing package.json
- files: ['build/test/dom/cases/osk/**/*.spec.mjs']
+ // Note: here we use the .spec.html file in the src directory!
+ files: ['src/test/auto/dom/cases/gesture-processor/**/*.spec.html']
+ },
+ {
+ name: 'engine/keyboard',
+ // Relative, from the containing package.json
+ files: ['build/test/dom/cases/keyboard/**/*.spec.mjs']
},
{
name: 'engine/keyboard-storage',
// Relative, from the containing package.json
files: ['build/test/dom/cases/keyboard-storage/**/*.spec.mjs']
+ },
+ {
+ name: 'engine/osk',
+ // Relative, from the containing package.json
+ files: ['build/test/dom/cases/osk/**/*.spec.mjs']
}
],
middleware: [
@@ -72,7 +93,7 @@ export default {
}
],
plugins: [
- esbuildPlugin({ts: true}),
+ esbuildPlugin({ts: true, target: 'auto'}),
importMapsPlugin({
inject: {
importMap: {
@@ -88,8 +109,12 @@ export default {
reporters: [
summaryReporter({}), /* local-dev mocha-style */
sessionStabilityReporter({}),
- defaultReporter()
+ 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
diff --git a/common/web/gesture-recognizer/src/test/auto/headless/asyncClosureDispatchQueue.spec.ts b/web/src/test/auto/headless/engine/osk/gesture-processor/asyncClosureDispatchQueue.tests.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/test/auto/headless/asyncClosureDispatchQueue.spec.ts
rename to web/src/test/auto/headless/engine/osk/gesture-processor/asyncClosureDispatchQueue.tests.ts
diff --git a/common/web/gesture-recognizer/src/test/auto/headless/gesturePath.spec.ts b/web/src/test/auto/headless/engine/osk/gesture-processor/gesturePath.tests.ts
similarity index 97%
rename from common/web/gesture-recognizer/src/test/auto/headless/gesturePath.spec.ts
rename to web/src/test/auto/headless/engine/osk/gesture-processor/gesturePath.tests.ts
index 111e00ee93..0a90b0c628 100644
--- a/common/web/gesture-recognizer/src/test/auto/headless/gesturePath.spec.ts
+++ b/web/src/test/auto/headless/engine/osk/gesture-processor/gesturePath.tests.ts
@@ -6,14 +6,14 @@ import fs from 'fs';
import { GestureDebugPath } from '@keymanapp/gesture-recognizer';
import { timedPromise } from '@keymanapp/web-utils';
-import { TouchpathTurtle } from '#tools';
+import { TouchpathTurtle } from '#gesture-tools';
// Ensures that the resources are resolved relative to this script's source, not
// to the cwd when the test runner was launched or to its built version.
const scriptFolder = path.dirname(url.fileURLToPath(import.meta.url))
- .replace("build/test/auto", "src/test/auto") // Mac/Linux
- .replace("build\\test\\auto", "src\\test\\auto"); // Windows
-const SEGMENT_TEST_JSON_FOLDER = path.resolve(`${scriptFolder}/../../resources/json/segmentation`);
+ .replace("build/test", "src/test/auto") // Mac/Linux
+ .replace("build\\test", "src\\test\\auto"); // Windows
+const SEGMENT_TEST_JSON_FOLDER = path.resolve(`${scriptFolder}/../../../../resources/json/segmentation`);
describe("GesturePath", function() {
// Note: if part of the suite below fails, it'll probably cascade into failures for some of the
diff --git a/common/web/gesture-recognizer/src/test/auto/headless/gestureSource.spec.ts b/web/src/test/auto/headless/engine/osk/gesture-processor/gestureSource.tests.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/test/auto/headless/gestureSource.spec.ts
rename to web/src/test/auto/headless/engine/osk/gesture-processor/gestureSource.tests.ts
diff --git a/common/web/gesture-recognizer/src/test/auto/headless/gestures/gestureMatcher.spec.ts b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/gestureMatcher.tests.ts
similarity index 99%
rename from common/web/gesture-recognizer/src/test/auto/headless/gestures/gestureMatcher.spec.ts
rename to web/src/test/auto/headless/engine/osk/gesture-processor/gestures/gestureMatcher.tests.ts
index aea79a15a9..ede257ca75 100644
--- a/common/web/gesture-recognizer/src/test/auto/headless/gestures/gestureMatcher.spec.ts
+++ b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/gestureMatcher.tests.ts
@@ -3,13 +3,13 @@ import sinon from 'sinon';
import * as PromiseStatusModule from 'promise-status-async';
const PromiseStatuses = PromiseStatusModule.PromiseStatuses;
-import { assertingPromiseStatus as promiseStatus } from '../../../resources/assertingPromiseStatus.js';
+import { assertingPromiseStatus as promiseStatus } from '../../../../../resources/assertingPromiseStatus.js';
import { InputSample, gestures, GestureDebugPath } from '@keymanapp/gesture-recognizer';
-import { TouchpathTurtle } from '#tools';
+import { TouchpathTurtle } from '#gesture-tools';
-import { simulateMultiSourceMatcherInput } from "../../../resources/simulateMultiSourceInput.js";
+import { simulateMultiSourceMatcherInput } from "../../../../../resources/simulateMultiSourceInput.js";
import {
FlickEndModel,
diff --git a/common/web/gesture-recognizer/src/test/auto/headless/gestures/gestureModelDefs.spec.ts b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/gestureModelDefs.tests.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/test/auto/headless/gestures/gestureModelDefs.spec.ts
rename to web/src/test/auto/headless/engine/osk/gesture-processor/gestures/gestureModelDefs.tests.ts
diff --git a/common/web/gesture-recognizer/src/test/auto/headless/gestures/gestureSequence.spec.ts b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/gestureSequence.tests.ts
similarity index 99%
rename from common/web/gesture-recognizer/src/test/auto/headless/gestures/gestureSequence.spec.ts
rename to web/src/test/auto/headless/engine/osk/gesture-processor/gestures/gestureSequence.tests.ts
index 346e146809..fe3837e42f 100644
--- a/common/web/gesture-recognizer/src/test/auto/headless/gestures/gestureSequence.spec.ts
+++ b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/gestureSequence.tests.ts
@@ -2,7 +2,7 @@ import { assert } from 'chai'
import sinon from 'sinon';
import * as PromiseStatusModule from 'promise-status-async';
-import { assertingPromiseStatus as promiseStatus } from '../../../resources/assertingPromiseStatus.js';
+import { assertingPromiseStatus as promiseStatus } from '../../../../../resources/assertingPromiseStatus.js';
import { GestureModelDefs, buildGestureMatchInspector, gestures } from '@keymanapp/gesture-recognizer';
const { matchers } = gestures;
@@ -16,10 +16,10 @@ type MatcherSelection = gestures.matchers.MatcherSelection;
const getGestureModelSet = gestures.specs.getGestureModelSet;
const modelSetForAction = gestures.matchers.modelSetForAction;
-import { HeadlessInputEngine, TouchpathTurtle } from '#tools';
+import { HeadlessInputEngine, TouchpathTurtle } from '#gesture-tools';
import { ManagedPromise, timedPromise } from '@keymanapp/web-utils';
-import { assertGestureSequence, SequenceAssertion } from "../../../resources/sequenceAssertions.js";
+import { assertGestureSequence, SequenceAssertion } from "../../../../../resources/sequenceAssertions.js";
import {
LongpressModel,
diff --git a/common/web/gesture-recognizer/src/test/auto/headless/gestures/isolatedGestureSpecs.ts b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/isolatedGestureSpecs.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/test/auto/headless/gestures/isolatedGestureSpecs.ts
rename to web/src/test/auto/headless/engine/osk/gesture-processor/gestures/isolatedGestureSpecs.ts
diff --git a/common/web/gesture-recognizer/src/test/auto/headless/gestures/isolatedPathSpecs.ts b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/isolatedPathSpecs.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/test/auto/headless/gestures/isolatedPathSpecs.ts
rename to web/src/test/auto/headless/engine/osk/gesture-processor/gestures/isolatedPathSpecs.ts
diff --git a/common/web/gesture-recognizer/src/test/auto/headless/gestures/matcherSelector.spec.ts b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/matcherSelector.tests.ts
similarity index 99%
rename from common/web/gesture-recognizer/src/test/auto/headless/gestures/matcherSelector.spec.ts
rename to web/src/test/auto/headless/engine/osk/gesture-processor/gestures/matcherSelector.tests.ts
index 8fdfd936a6..583e0c6031 100644
--- a/common/web/gesture-recognizer/src/test/auto/headless/gestures/matcherSelector.spec.ts
+++ b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/matcherSelector.tests.ts
@@ -3,14 +3,14 @@ import sinon from 'sinon';
import * as PromiseStatusModule from 'promise-status-async';
const PromiseStatuses = PromiseStatusModule.PromiseStatuses;
-import { assertingPromiseStatus as promiseStatus } from '../../../resources/assertingPromiseStatus.js';
+import { assertingPromiseStatus as promiseStatus } from '../../../../../resources/assertingPromiseStatus.js';
-import { simulateMultiSourceMatcherInput, simulateSelectorInput } from "../../../resources/simulateMultiSourceInput.js";
+import { simulateMultiSourceMatcherInput, simulateSelectorInput } from "../../../../../resources/simulateMultiSourceInput.js";
import { timedPromise } from '@keymanapp/web-utils';
import { gestures } from '@keymanapp/gesture-recognizer';
-import { TouchpathTurtle } from '#tools';
+import { TouchpathTurtle } from '#gesture-tools';
type MatcherSelection = gestures.matchers.MatcherSelection;
type GestureModel = gestures.specs.GestureModel;
diff --git a/common/web/gesture-recognizer/src/test/auto/headless/gestures/pathMatcher.spec.ts b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/pathMatcher.tests.ts
similarity index 99%
rename from common/web/gesture-recognizer/src/test/auto/headless/gestures/pathMatcher.spec.ts
rename to web/src/test/auto/headless/engine/osk/gesture-processor/gestures/pathMatcher.tests.ts
index 4678efed71..ac2250f5f9 100644
--- a/common/web/gesture-recognizer/src/test/auto/headless/gestures/pathMatcher.spec.ts
+++ b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/pathMatcher.tests.ts
@@ -3,7 +3,7 @@ import sinon from 'sinon';
import * as PromiseStatusModule from 'promise-status-async';
const PromiseStatuses = PromiseStatusModule.PromiseStatuses;
-import { assertingPromiseStatus as promiseStatus } from '../../../resources/assertingPromiseStatus.js';
+import { assertingPromiseStatus as promiseStatus } from '../../../../../resources/assertingPromiseStatus.js';
import { InputSample, GestureSource, gestures, CumulativePathStats } from '@keymanapp/gesture-recognizer';
import { timedPromise } from '@keymanapp/web-utils';
diff --git a/common/web/gesture-recognizer/src/test/auto/headless/gestures/touchpointCoordinator.spec.ts b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/touchpointCoordinator.tests.ts
similarity index 99%
rename from common/web/gesture-recognizer/src/test/auto/headless/gestures/touchpointCoordinator.spec.ts
rename to web/src/test/auto/headless/engine/osk/gesture-processor/gestures/touchpointCoordinator.tests.ts
index 784d7e30b6..44f0bce4f7 100644
--- a/common/web/gesture-recognizer/src/test/auto/headless/gestures/touchpointCoordinator.spec.ts
+++ b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/touchpointCoordinator.tests.ts
@@ -2,7 +2,7 @@ import { assert } from 'chai'
import sinon from 'sinon';
import * as PromiseStatusModule from 'promise-status-async';
-import { assertingPromiseStatus as promiseStatus } from '../../../resources/assertingPromiseStatus.js';
+import { assertingPromiseStatus as promiseStatus } from '../../../../../resources/assertingPromiseStatus.js';
import { GestureModelDefs, GestureSource, gestures, TouchpointCoordinator } from '@keymanapp/gesture-recognizer';
const { matchers } = gestures;
@@ -11,10 +11,10 @@ const { matchers } = gestures;
const { GestureSequence } = matchers;
type GestureSequence = gestures.matchers.GestureSequence;
-import { HeadlessInputEngine, TouchpathTurtle } from '#tools';
+import { HeadlessInputEngine, TouchpathTurtle } from '#gesture-tools';
import { ManagedPromise, timedPromise } from '@keymanapp/web-utils';
-import { assertGestureSequence, SequenceAssertion } from "../../../resources/sequenceAssertions.js";
+import { assertGestureSequence, SequenceAssertion } from "../../../../../resources/sequenceAssertions.js";
import {
LongpressModel,
diff --git a/common/web/gesture-recognizer/src/test/auto/headless/pathStats.spec.ts b/web/src/test/auto/headless/engine/osk/gesture-processor/pathStats.tests.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/test/auto/headless/pathStats.spec.ts
rename to web/src/test/auto/headless/engine/osk/gesture-processor/pathStats.tests.ts
diff --git a/common/web/gesture-recognizer/src/test/resources/@types/promiseStatus.d.ts b/web/src/test/auto/resources/@types/promiseStatus.d.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/test/resources/@types/promiseStatus.d.ts
rename to web/src/test/auto/resources/@types/promiseStatus.d.ts
diff --git a/common/web/gesture-recognizer/src/test/resources/assertSegmentSimilarity.js b/web/src/test/auto/resources/assertSegmentSimilarity.js
similarity index 100%
rename from common/web/gesture-recognizer/src/test/resources/assertSegmentSimilarity.js
rename to web/src/test/auto/resources/assertSegmentSimilarity.js
diff --git a/common/web/gesture-recognizer/src/test/resources/assertingPromiseStatus.ts b/web/src/test/auto/resources/assertingPromiseStatus.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/test/resources/assertingPromiseStatus.ts
rename to web/src/test/auto/resources/assertingPromiseStatus.ts
diff --git a/common/web/gesture-recognizer/src/test/resources/json/canaryRecording.json b/web/src/test/auto/resources/json/canaryRecording.json
similarity index 100%
rename from common/web/gesture-recognizer/src/test/resources/json/canaryRecording.json
rename to web/src/test/auto/resources/json/canaryRecording.json
diff --git a/common/web/gesture-recognizer/src/test/resources/json/receiver/basicMultitouch.json b/web/src/test/auto/resources/json/receiver/basicMultitouch.json
similarity index 100%
rename from common/web/gesture-recognizer/src/test/resources/json/receiver/basicMultitouch.json
rename to web/src/test/auto/resources/json/receiver/basicMultitouch.json
diff --git a/common/web/gesture-recognizer/src/test/resources/json/receiver/desktopRoamAndReturn.json b/web/src/test/auto/resources/json/receiver/desktopRoamAndReturn.json
similarity index 100%
rename from common/web/gesture-recognizer/src/test/resources/json/receiver/desktopRoamAndReturn.json
rename to web/src/test/auto/resources/json/receiver/desktopRoamAndReturn.json
diff --git a/common/web/gesture-recognizer/src/test/resources/json/receiver/embeddedBorderCancel.json b/web/src/test/auto/resources/json/receiver/embeddedBorderCancel.json
similarity index 100%
rename from common/web/gesture-recognizer/src/test/resources/json/receiver/embeddedBorderCancel.json
rename to web/src/test/auto/resources/json/receiver/embeddedBorderCancel.json
diff --git a/common/web/gesture-recognizer/src/test/resources/json/receiver/hardBorderCancel.json b/web/src/test/auto/resources/json/receiver/hardBorderCancel.json
similarity index 100%
rename from common/web/gesture-recognizer/src/test/resources/json/receiver/hardBorderCancel.json
rename to web/src/test/auto/resources/json/receiver/hardBorderCancel.json
diff --git a/common/web/gesture-recognizer/src/test/resources/json/receiver/mobileProximityApproach.json b/web/src/test/auto/resources/json/receiver/mobileProximityApproach.json
similarity index 100%
rename from common/web/gesture-recognizer/src/test/resources/json/receiver/mobileProximityApproach.json
rename to web/src/test/auto/resources/json/receiver/mobileProximityApproach.json
diff --git a/common/web/gesture-recognizer/src/test/resources/json/receiver/mobileSafeZoneCancel.json b/web/src/test/auto/resources/json/receiver/mobileSafeZoneCancel.json
similarity index 100%
rename from common/web/gesture-recognizer/src/test/resources/json/receiver/mobileSafeZoneCancel.json
rename to web/src/test/auto/resources/json/receiver/mobileSafeZoneCancel.json
diff --git a/common/web/gesture-recognizer/src/test/resources/json/receiver/popupLongRoamingEnd.json b/web/src/test/auto/resources/json/receiver/popupLongRoamingEnd.json
similarity index 100%
rename from common/web/gesture-recognizer/src/test/resources/json/receiver/popupLongRoamingEnd.json
rename to web/src/test/auto/resources/json/receiver/popupLongRoamingEnd.json
diff --git a/common/web/gesture-recognizer/src/test/resources/json/receiver/popupSafePersistence.json b/web/src/test/auto/resources/json/receiver/popupSafePersistence.json
similarity index 100%
rename from common/web/gesture-recognizer/src/test/resources/json/receiver/popupSafePersistence.json
rename to web/src/test/auto/resources/json/receiver/popupSafePersistence.json
diff --git a/common/web/gesture-recognizer/src/test/resources/json/receiver/popupShimCancel.json b/web/src/test/auto/resources/json/receiver/popupShimCancel.json
similarity index 100%
rename from common/web/gesture-recognizer/src/test/resources/json/receiver/popupShimCancel.json
rename to web/src/test/auto/resources/json/receiver/popupShimCancel.json
diff --git a/common/web/gesture-recognizer/src/test/resources/json/segmentation/flick_ne_se.json b/web/src/test/auto/resources/json/segmentation/flick_ne_se.json
similarity index 100%
rename from common/web/gesture-recognizer/src/test/resources/json/segmentation/flick_ne_se.json
rename to web/src/test/auto/resources/json/segmentation/flick_ne_se.json
diff --git a/common/web/gesture-recognizer/src/test/resources/json/segmentation/longpress_to_ne.json b/web/src/test/auto/resources/json/segmentation/longpress_to_ne.json
similarity index 100%
rename from common/web/gesture-recognizer/src/test/resources/json/segmentation/longpress_to_ne.json
rename to web/src/test/auto/resources/json/segmentation/longpress_to_ne.json
diff --git a/common/web/gesture-recognizer/src/test/resources/json/segmentation/nonstationary_hold.json b/web/src/test/auto/resources/json/segmentation/nonstationary_hold.json
similarity index 100%
rename from common/web/gesture-recognizer/src/test/resources/json/segmentation/nonstationary_hold.json
rename to web/src/test/auto/resources/json/segmentation/nonstationary_hold.json
diff --git a/common/web/gesture-recognizer/src/test/resources/json/segmentation/quick_small_square.json b/web/src/test/auto/resources/json/segmentation/quick_small_square.json
similarity index 100%
rename from common/web/gesture-recognizer/src/test/resources/json/segmentation/quick_small_square.json
rename to web/src/test/auto/resources/json/segmentation/quick_small_square.json
diff --git a/common/web/gesture-recognizer/src/test/resources/json/segmentation/simple_ne_move.json b/web/src/test/auto/resources/json/segmentation/simple_ne_move.json
similarity index 100%
rename from common/web/gesture-recognizer/src/test/resources/json/segmentation/simple_ne_move.json
rename to web/src/test/auto/resources/json/segmentation/simple_ne_move.json
diff --git a/common/web/gesture-recognizer/src/test/resources/sequenceAssertions.ts b/web/src/test/auto/resources/sequenceAssertions.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/test/resources/sequenceAssertions.ts
rename to web/src/test/auto/resources/sequenceAssertions.ts
diff --git a/common/web/gesture-recognizer/src/test/resources/simulateMultiSourceInput.ts b/web/src/test/auto/resources/simulateMultiSourceInput.ts
similarity index 100%
rename from common/web/gesture-recognizer/src/test/resources/simulateMultiSourceInput.ts
rename to web/src/test/auto/resources/simulateMultiSourceInput.ts
diff --git a/web/src/test/auto/tsconfig.json b/web/src/test/auto/tsconfig.json
index f61a4f23a8..f88f147539 100644
--- a/web/src/test/auto/tsconfig.json
+++ b/web/src/test/auto/tsconfig.json
@@ -11,6 +11,7 @@
"include": [
"dom/**/*.ts",
"headless/**/*.ts",
- "integrated/**/*.ts"
+ "integrated/**/*.ts",
+ "resources/**/*.ts"
]
}
diff --git a/web/src/test/manual/build.sh b/web/src/test/manual/build.sh
index 046cefe152..905a799ab5 100755
--- a/web/src/test/manual/build.sh
+++ b/web/src/test/manual/build.sh
@@ -49,11 +49,11 @@ function do_copy() {
cp "$SENTRY_SRC" "$KEYMAN_ROOT/$DEST/sentry-bundle.min.js"
cp "$SENTRY_MAP" "$KEYMAN_ROOT/$DEST/sentry-bundle.min.js.map"
- GESTURE_RECOGNIZER_BUILD="$KEYMAN_ROOT/common/web/gesture-recognizer/build/lib/."
- GESTURE_RECOGNIZER_TARGET="$KEYMAN_ROOT/web/build/engine/gesture-recognizer/lib/"
+ GESTURE_PROCESSOR_BUILD="$KEYMAN_ROOT/web/src/engine/osk/gesture-processor/build/lib/."
+ GESTURE_PROCESSOR_TARGET="$KEYMAN_ROOT/web/build/engine/gesture-processor/lib/"
- mkdir -p "$GESTURE_RECOGNIZER_TARGET"
- cp -a "$GESTURE_RECOGNIZER_BUILD" "$GESTURE_RECOGNIZER_TARGET"
+ mkdir -p "$GESTURE_PROCESSOR_TARGET"
+ cp -a "$GESTURE_PROCESSOR_BUILD" "$GESTURE_PROCESSOR_TARGET"
}
builder_run_action clean rm -rf "$KEYMAN_ROOT/$DEST"
diff --git a/web/src/test/manual/web/gesture-recognizer/hostConfiguration.mjs b/web/src/test/manual/web/gesture-recognizer/hostConfiguration.mjs
index 7bd1426a58..2e40a29640 100644
--- a/web/src/test/manual/web/gesture-recognizer/hostConfiguration.mjs
+++ b/web/src/test/manual/web/gesture-recognizer/hostConfiguration.mjs
@@ -1,6 +1,6 @@
// -- BEGIN: Code for controlling the layout-simulation elements --
-import { GestureRecognizer } from '../../../../../build/engine/gesture-recognizer/lib/index.mjs';
+import { GestureRecognizer } from '../../../../../build/engine/gesture-processor/lib/index.mjs';
function updateConfig() {
let layout = document.config.screen;
diff --git a/windows/src/.gitignore b/windows/src/.gitignore
index 350b7e4bdb..065f4a07f3 100644
--- a/windows/src/.gitignore
+++ b/windows/src/.gitignore
@@ -34,3 +34,8 @@ keyman-windows-coverity.tgz
# This file is still generated by devtools. TODO: eliminate in future
PathDefines.mak
+
+# .res files, generated during build
+desktop/kmshell/kmshell.res
+engine/keyman/keyman.res
+engine/keyman32/version64.res
diff --git a/windows/src/README.md b/windows/src/README.md
index 1d057482bb..b18b626dc0 100644
--- a/windows/src/README.md
+++ b/windows/src/README.md
@@ -1,40 +1,39 @@
-# Keyman for Windows and Keyman Developer
+# Keyman for Windows
## Build Prerequisites
* See [Windows Build Environment Configuration](../../docs/build/windows.md).
-## Building Keyman for Windows and Keyman Developer
+## Building Keyman for Windows
-1. Start 'Developer Command Prompt for VS 2019'.
-2. Run `nmake build` from the **windows/src** folder.
+1. Start 'Git Bash' (part of Git for Windows).
+2. Run `windows/src/build.sh`.
3. Artifacts from a successful build will be placed in **windows/bin** folder.
-*Note*: running `nmake build` will currently reset the packages and path settings
+*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 `nmake` to see build targets. Common build targets are:
+Type `build.sh` to see build targets and actions. Common build actions are:
-* `nmake build`
-: builds Keyman for Windows and Keyman Developer
+* `build.sh build`
+: builds Keyman for Windows
-* `nmake clean`
+* `build.sh clean`
: remove temporary files and build artifacts
-* `nmake release`
+* `build.sh publish`
: makes a release of all Keyman Windows projects
-* `nmake install`
+* `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 by adding
-the environment variable `NODELPHI=1` before starting the build. 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 copying the relevant Delphi-built
+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, or
+Keyman Engine's C++ components, you may be able to get away without building
+them. In this situation, we recommend copying the relevant Delphi-built
components into windows/bin folders from a compatible installed version of
Keyman for testing and debugging purposes.
@@ -45,8 +44,8 @@ build, you will need to obtain valid code signing certificates. See
Certificates, below. Official release builds for Keyman are built in the Keyman
project's CI environment.
-1. Start 'Developer Command Prompt for VS 2019'.
-2. Run `nmake release` from the **windows/src** folder.
+1. Start 'Git Bash'.
+2. Run `windows/src/build.sh publish`.
3. Artifacts from a successful build will be placed in **windows/release**
folder.
4. **buildtools/help-keyman-com.sh** will push updated documentation to
@@ -65,7 +64,7 @@ globally trusted. The environment variables `SC_PFX_SHA1` and `SC_PFX_SHA256`
can be set to custom certificate paths.
The Keyman repo can build test certificates for you. To build your own, run
-`./build.sh certificates` from **common/windows/delphi/tools/certificates** to
+`./common/windows/delphi/tools/certificates/build.sh certificates` to
build and install your own local root CA "**KeymanTestCA**" certificates. If you
specify a password for the certificate, you'll need to set that in the
environment variable `SC_PWD`.
@@ -76,7 +75,7 @@ You do not need to install the **KeymanTest** certificates, only the
**KeymanTestCA** certificates.
If you have not already installed the **KeymanTestCA** certificates using the
-`nmake` command above, to manually install the Keyman **KeymanTestCA**
+`build.sh` command above, to manually install the Keyman **KeymanTestCA**
certificates, do the following in **common/windows/delphi/tools/certificates**:
1. Open the certificate and click 'Install certificate...' to open the
diff --git a/windows/src/build.sh b/windows/src/build.sh
index a1fc4d0e1a..4ef6da65b8 100755
--- a/windows/src/build.sh
+++ b/windows/src/build.sh
@@ -18,6 +18,7 @@ builder_describe \
":engine Keyman Engine for Windows" \
":desktop Keyman for Windows" \
":components=global/delphi Delphi components" \
+ ":support Support tools" \
":test=test/unit-tests Shared unit tests" \
":fv=../../oem/firstvoices/windows/src/inst OEM FirstVoices for Windows app"
diff --git a/windows/src/desktop/kmshell/kmshell.res b/windows/src/desktop/kmshell/kmshell.res
deleted file mode 100644
index cfcbd309f1..0000000000
Binary files a/windows/src/desktop/kmshell/kmshell.res and /dev/null differ
diff --git a/windows/src/engine/keyman/build.sh b/windows/src/engine/keyman/build.sh
index 50ef210ce2..ce34599410 100755
--- a/windows/src/engine/keyman/build.sh
+++ b/windows/src/engine/keyman/build.sh
@@ -8,6 +8,7 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
builder_describe "Keyman main host process (32-bit)" \
@/common/include \
@/common/windows/delphi \
+ @/windows/src/global/delphi \
clean configure build test publish install debug-manifest
builder_parse "$@"
diff --git a/windows/src/engine/keyman32/calldll.cpp b/windows/src/engine/keyman32/calldll.cpp
index bd917ae9c5..5b08f7b5e0 100644
--- a/windows/src/engine/keyman32/calldll.cpp
+++ b/windows/src/engine/keyman32/calldll.cpp
@@ -439,26 +439,69 @@ extern "C" BOOL _declspec(dllexport) WINAPI KMDisplayIM(HWND hwnd, BOOL FShowAlw
*Globals::hwndIM() = hwnd;
*Globals::hwndIMAlways() = FShowAlways;
- POINT pt;
- RECT r;
+ POINT IMTop, Caret;
+ RECT RectIM, RectApp;
+ HWND hFocus;
+ int n = 0;
- GetCaretPos(&pt);
+ HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
+ if (hMonitor == NULL) {
+ return FALSE;
+ }
- int n;
- //if(pt.x == 0 && pt.y == 0)
- n = SWP_NOMOVE;
- //else n = 0;
+ MONITORINFO monitor_info;
+ monitor_info.cbSize = sizeof(monitor_info);
+ if (!GetMonitorInfo(hMonitor, &monitor_info)) {
+ return FALSE;
+ }
- ClientToScreen(hwndFocus, &pt);
- GetWindowRect(hwnd, &r);
- if(pt.x + r.right - r.left >= GetSystemMetrics(SM_CXSCREEN))
- pt.x = GetSystemMetrics(SM_CXSCREEN) - (r.right - r.left);
+ if (!GetWindowRect(hwnd, &RectIM)) {
+ return FALSE;
+ }
- if(pt.y - (r.bottom-r.top) > 0) pt.y -= (r.bottom-r.top);
- else pt.y += 32; // guessing...
+ // Only adjust the IM window coordinates if it is not going to be visible on the
+ // monitor it is currently showing on. Otherwise leave it to the 3rd party app
+ // to control the location of the IM Window.
+ // If changing the coordinates to place the IM window use the caret postion of the
+ // application that has focus.
+ if ((RectIM.left < monitor_info.rcMonitor.left) || (RectIM.right > monitor_info.rcMonitor.right) ||
+ (RectIM.top < monitor_info.rcMonitor.top) || (RectIM.bottom > monitor_info.rcMonitor.bottom)) {
- SetWindowPos(hwnd, HWND_TOPMOST, pt.x,pt.y,0,0, n|SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOACTIVATE);
- //SendDebugMessageFormat("Exit");
+ if (!GetCaretPos(&Caret)) {
+ return FALSE;
+ }
+
+ hFocus = GetFocus();
+ if (!GetWindowRect(hFocus, &RectApp)) {
+ return FALSE;
+ }
+
+ IMTop.x = Caret.x + RectApp.left;
+ IMTop.y = Caret.y + RectApp.top + 24;
+ LONG IMWidth = RectIM.right - RectIM.left;
+
+ if (IMTop.x + IMWidth > RectApp.right) {
+ // align IM right edge with App right edge
+ if (IMWidth < (RectApp.right - RectApp.left)) {
+ IMTop.x = RectApp.right - IMWidth;
+ }
+ else { // align IM left edge with App left edge
+ IMTop.x = RectApp.left;
+ }
+ }
+
+ if (IMTop.y + RectIM.bottom - RectIM.top > RectApp.bottom) {
+ IMTop.y = RectApp.top + Caret.y - (RectIM.bottom - RectIM.top);
+ }
+ n = 0; // Move to tracked postion
+ } else {
+ IMTop.x = 0; // will be ignored by SWP_NOMOVE;
+ IMTop.y = 0;
+ n = SWP_NOMOVE;
+ }
+
+ SetWindowPos(hwnd, HWND_TOPMOST, IMTop.x, IMTop.y, 0, 0, n|SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOACTIVATE);
+ //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMDisplayIM: Exit");
return TRUE;
}
diff --git a/windows/src/support/Makefile b/windows/src/support/Makefile
deleted file mode 100644
index 56609e21e4..0000000000
--- a/windows/src/support/Makefile
+++ /dev/null
@@ -1,38 +0,0 @@
-#
-# Support Makefile
-#
-
-!ifdef NODELPHI
-TARGETS=etl2log texteditor
-!else
-TARGETS=oskbulkrenderer etl2log texteditor
-!endif
-CLEANS=clean-support
-
-!include ..\Header.mak
-
-# ----------------------------------------------------------------------
-
-oskbulkrenderer: .virtual
- cd $(ROOT)\src\support\oskbulkrenderer
- $(MAKE) $(TARGET)
-
-etl2log: .virtual
- cd $(ROOT)\src\support\etl2log
- $(MAKE) $(TARGET)
-
-texteditor: .virtual
- cd $(ROOT)\src\support\texteditor
- $(MAKE) $(TARGET)
-
-# ----------------------------------------------------------------------
-
-clean-support:
- cd $(ROOT)\src\support
- -del version.txt
-
-!include ..\Target.mak
-
-# ----------------------------------------------------------------------
-# EOF
-# ----------------------------------------------------------------------
diff --git a/windows/src/support/build.sh b/windows/src/support/build.sh
new file mode 100755
index 0000000000..f9f20f1716
--- /dev/null
+++ b/windows/src/support/build.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+## START STANDARD BUILD SCRIPT INCLUDE
+# adjust relative paths as necessary
+THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
+. "${THIS_SCRIPT%/*}/../../../resources/build/builder.inc.sh"
+## END STANDARD BUILD SCRIPT INCLUDE
+
+builder_describe \
+ "Keyman for Windows support tools" \
+ \
+ clean \
+ configure \
+ build \
+ test \
+ \
+ :oskbulkrenderer \
+ :etl2log \
+ :texteditor
+
+builder_parse "$@"
+
+builder_run_child_actions clean configure build test publish install
diff --git a/windows/src/support/charident/Makefile b/windows/src/support/charident/Makefile
deleted file mode 100644
index cff6741677..0000000000
--- a/windows/src/support/charident/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-#
-# charident Makefile
-#
-
-!include ..\..\Defines.mak
-
-build: version.res dirs
- $(DCC32) charident.dpr
- $(COPY) charident.exe $(PROGRAM)\support
-
-clean: def-clean
-
-signcode:
- $(SIGNCODE) /d "Character Identifier" $(PROGRAM)\support\charident.exe
-
-wrap-symbols:
- $(SYMSTORE) $(PROGRAM)\support\charident.exe /t keyman-windows
-#TODO: $(SYMSTORE) $(DEBUGPATH)\support\charident.dbg /t keyman-windows
-
-!include ..\..\Target.mak
diff --git a/windows/src/support/etl2log/Makefile b/windows/src/support/etl2log/Makefile
deleted file mode 100644
index 48bdb1a592..0000000000
--- a/windows/src/support/etl2log/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# etl2log Makefile
-#
-
-!include ..\..\Defines.mak
-
-build: version.res dirs
- $(MSBUILD) etl2log.vcxproj $(MSBUILD_BUILD)
- $(COPY) $(WIN32_TARGET_PATH)\etl2log.exe $(PROGRAM)\support
- $(COPY) $(WIN32_TARGET_PATH)\etl2log.pdb $(DEBUGPATH)\support
-
-clean: def-clean
- $(MSBUILD) etl2log.vcxproj $(MSBUILD_CLEAN)
-
-signcode:
- $(SIGNCODE) /d "Keyman Engine Tools" $(PROGRAM)\support\etl2log.exe
-
-wrap-symbols:
- $(SYMSTORE) $(PROGRAM)\support\etl2log.exe /t keyman-windows
- $(SYMSTORE) $(DEBUGPATH)\support\etl2log.pdb /t keyman-windows
-
-!include ..\..\Target.mak
diff --git a/windows/src/support/etl2log/build.sh b/windows/src/support/etl2log/build.sh
new file mode 100755
index 0000000000..e2fdee1acd
--- /dev/null
+++ b/windows/src/support/etl2log/build.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+## START STANDARD BUILD SCRIPT INCLUDE
+# adjust relative paths as necessary
+THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
+. "${THIS_SCRIPT%/*}/../../../../resources/build/builder.inc.sh"
+## END STANDARD BUILD SCRIPT INCLUDE
+
+builder_describe "etl2log" \
+ clean configure build test
+
+builder_parse "$@"
+
+#-------------------------------------------------------------------------------------------------------------------
+
+source "$KEYMAN_ROOT/resources/build/win/environment.inc.sh"
+WIN32_TARGET="$WIN32_TARGET_PATH/etl2log.exe"
+
+builder_describe_outputs \
+ configure:project /resources/build/win/delphi_environment_generated.inc.sh \
+ build:project /windows/src/support/etl2log/$WIN32_TARGET
+
+#-------------------------------------------------------------------------------------------------------------------
+
+function do_clean() {
+ vs_msbuild etl2log.vcxproj //t:Clean
+ clean_windows_project_files
+}
+
+function do_build() {
+ create-windows-output-folders
+ build_version.res
+ vs_msbuild etl2log.vcxproj //t:Build "//p:Platform=Win32"
+ cp "$WIN32_TARGET" "$WINDOWS_PROGRAM_SUPPORT"
+ cp "$WIN32_TARGET_PATH/etl2log.pdb" "$WINDOWS_DEBUGPATH_SUPPORT"
+}
+
+builder_run_action clean:project do_clean
+builder_run_action configure:project configure_windows_build_environment
+builder_run_action build:project do_build
+# builder_run_action test:project do_test
diff --git a/windows/src/support/kdebug/Makefile b/windows/src/support/kdebug/Makefile
deleted file mode 100644
index 1a13a18ebe..0000000000
--- a/windows/src/support/kdebug/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# KDebug Makefile
-#
-
-!include ..\..\Defines.mak
-
-!ifdef DEBUG
- NMCFG=kdebug - Win32 Debug
-!else
- NMCFG=kdebug - Win32 Release
-!endif
-
-install: dirs build
-
-build: version.res
- $(NMAKE) /f kdebug.mak "CFG=$(NMCFG)"
-
-clean: def-clean
- $(NMAKE) /f kdebug.mak "CFG=$(NMCFG)" CLEAN
-
-!include ..\..\Target.mak
diff --git a/windows/src/support/keycodetester/Makefile b/windows/src/support/keycodetester/Makefile
deleted file mode 100644
index 38687abaeb..0000000000
--- a/windows/src/support/keycodetester/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# Keycodetester Makefile
-#
-
-!include ..\..\Defines.mak
-
-install: dirs build
- $(COPY) keycodetester.exe $(PROGRAM)\bldutil
-
-build:
- $(DCC32) keycodetester.dpr
-
-clean: def-clean
-
-!include ..\..\Target.mak
diff --git a/windows/src/support/km_yim/Makefile b/windows/src/support/km_yim/Makefile
deleted file mode 100644
index 1aef5f80f0..0000000000
--- a/windows/src/support/km_yim/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# TODO: remove this project
-#
-
-!include ..\..\Defines.mak
-
-build:
-# version.res
- $(DCC32) km_yim.dpr
- rem $(TDSPACK) $(PROGRAM)\desktop\km_yim.exe km_yim.tds
- rem $(TDS2DBG) $(PROGRAM)\desktop\km_yim.exe
- $(WZZIP) inst_km_yim.zip km_yim.exe
-# $(WZSE) inst_km_yim -setup -t inst_km_yim.dialog.txt -st "Tavultesoft Keyman Desktop Yahoo Messenger Addin" -c km_yim.exe
-
-clean: def-clean
- if exist inst_km_yim.zip del inst_km_yim.zip
-
-signcode:
- $(SIGNCODE) /d "Tavultesoft Keyman Desktop Yahoo Messenger Addin" inst_km_yim.exe
-
-wrap-symbols:
- rem
-
-!include ..\..\Target.mak
diff --git a/windows/src/support/kmkb0045/Makefile b/windows/src/support/kmkb0045/Makefile
deleted file mode 100644
index 3e914c8acd..0000000000
--- a/windows/src/support/kmkb0045/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# TODO: remove this project
-#
-
-!include ..\..\Defines.mak
-
-build: version.res manifest.res
- $(DCC32) kmkb0045.dpr
- $(SENTRYTOOL_DELPHIPREP) kmkb0045.exe -dpr kmkb0045.dpr
- $(TDS2DBG) kmkb0045.exe
- $(COPY) kmkb0045.exe $(PROGRAM)\support
-
-clean: def-clean
-
-signcode:
- $(SIGNCODE) /d "Tavultesoft KMKB0045" $(PROGRAM)\support\kmkb0045.exe
-
-
-!include ..\..\Target.mak
diff --git a/windows/src/support/oskbulkrenderer/Makefile b/windows/src/support/oskbulkrenderer/Makefile
deleted file mode 100644
index 65b8e02ba6..0000000000
--- a/windows/src/support/oskbulkrenderer/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# oskbulkrenderer Makefile
-#
-
-!include ..\..\Defines.mak
-
-build: version.res dirs
- $(DELPHI_MSBUILD) oskbulkrenderer.dproj "/p:Platform=Win32"
-
- $(SENTRYTOOL_DELPHIPREP) $(WIN32_TARGET_PATH)\oskbulkrenderer.exe -dpr oskbulkrenderer.dpr
- $(TDS2DBG) $(WIN32_TARGET_PATH)\oskbulkrenderer.exe
- $(COPY) $(WIN32_TARGET_PATH)\oskbulkrenderer.exe $(PROGRAM)\support
- if exist $(WIN32_TARGET_PATH)\oskbulkrenderer.dbg $(COPY) $(WIN32_TARGET_PATH)\oskbulkrenderer.dbg $(DEBUGPATH)\support
-
-clean: def-clean
- -rd /s/q Win32
-
-signcode:
- rem Not signing this utility
-
-wrap-symbols:
- @rem
-
-!include ..\..\Target.mak
diff --git a/windows/src/support/oskbulkrenderer/build.sh b/windows/src/support/oskbulkrenderer/build.sh
new file mode 100755
index 0000000000..76fa8a4032
--- /dev/null
+++ b/windows/src/support/oskbulkrenderer/build.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+## START STANDARD BUILD SCRIPT INCLUDE
+# adjust relative paths as necessary
+THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
+. "${THIS_SCRIPT%/*}/../../../../resources/build/builder.inc.sh"
+## END STANDARD BUILD SCRIPT INCLUDE
+
+builder_describe "oskbuildrenderer" \
+ clean configure build test
+
+builder_parse "$@"
+
+#-------------------------------------------------------------------------------------------------------------------
+
+source "$KEYMAN_ROOT/resources/build/win/environment.inc.sh"
+WIN32_TARGET="$WIN32_TARGET_PATH/oskbulkrenderer.exe"
+
+builder_describe_outputs \
+ configure:project /resources/build/win/delphi_environment_generated.inc.sh \
+ build:project /windows/src/support/oskbulkrenderer/$WIN32_TARGET
+
+#-------------------------------------------------------------------------------------------------------------------
+
+function do_clean() {
+ clean_windows_project_files
+}
+
+function do_build() {
+ create-windows-output-folders
+ build_version.res
+ delphi_msbuild oskbulkrenderer.dproj "//p:Platform=Win32"
+
+ cp "$WIN32_TARGET" "$WINDOWS_PROGRAM_SUPPORT"
+}
+
+builder_run_action clean:project do_clean
+builder_run_action configure:project configure_windows_build_environment
+builder_run_action build:project do_build
+# builder_run_action test:project do_test
diff --git a/windows/src/support/richedit_examine/Makefile b/windows/src/support/richedit_examine/Makefile
deleted file mode 100644
index adacba5901..0000000000
--- a/windows/src/support/richedit_examine/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# richedit_examine Makefile
-#
-
-!include ..\..\Defines.mak
-
-install: dirs build
- $(COPY) richedit_examine.exe $(PROGRAM)\bldutil
-
-build: version.res
- $(DCC32) richedit_examine.dpr
-
-clean: def-clean
-
-!include ..\..\Target.mak
diff --git a/windows/src/support/texteditor/Makefile b/windows/src/support/texteditor/Makefile
deleted file mode 100644
index 473bf57598..0000000000
--- a/windows/src/support/texteditor/Makefile
+++ /dev/null
@@ -1,36 +0,0 @@
-#
-# Keyman Text Editor Makefile
-#
-
-!include ..\..\Defines.mak
-
-build:
- $(MSBUILD) editor.vcxproj $(MSBUILD_BUILD) /p:Platform=x86
- $(MSBUILD) editor.vcxproj $(MSBUILD_BUILD) /p:Platform=x64
- $(COPY) $(WIN32_TARGET_PATH)\editor32.exe $(PROGRAM)\support
- $(COPY) $(WIN32_TARGET_PATH)\editor32.pdb $(DEBUGPATH)\support
- $(COPY) $(X64_TARGET_PATH)\editor64.exe $(PROGRAM)\support
- $(COPY) $(X64_TARGET_PATH)\editor64.pdb $(DEBUGPATH)\support
-
-clean: def-clean
- $(MSBUILD) $(MSBUILD_CLEAN) editor.sln
-
-signcode:
- $(SIGNCODE) /d "Text Editor for testing Keyman" $(PROGRAM)\support\editor32.exe
- $(SIGNCODE) /d "Text Editor for testing Keyman" $(PROGRAM)\support\editor64.exe
-
-install:
- $(COPY) $(PROGRAM)\support\editor32.exe "$(INSTALLPATH_KEYMANENGINE)"
- $(COPY) $(PROGRAM)\support\editor64.exe "$(INSTALLPATH_KEYMANENGINE)"
-
-wrap-symbols:
- $(SYMSTORE) $(PROGRAM)\support\editor32.exe /t keyman-windows
- $(SYMSTORE) $(PROGRAM)\support\editor64.exe /t keyman-windows
- $(SYMSTORE) $(DEBUGPATH)\support\editor32.pdb /t keyman-windows
- $(SYMSTORE) $(DEBUGPATH)\support\editor64.pdb /t keyman-windows
-
-
-!include ..\..\Target.mak
-# ----------------------------------------------------------------------
-# EOF
-# ----------------------------------------------------------------------
diff --git a/windows/src/support/texteditor/build.sh b/windows/src/support/texteditor/build.sh
new file mode 100755
index 0000000000..312ee1d0f4
--- /dev/null
+++ b/windows/src/support/texteditor/build.sh
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+## START STANDARD BUILD SCRIPT INCLUDE
+# adjust relative paths as necessary
+THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
+. "${THIS_SCRIPT%/*}/../../../../resources/build/builder.inc.sh"
+## END STANDARD BUILD SCRIPT INCLUDE
+
+builder_describe "texteditor" \
+ clean configure build test
+
+builder_parse "$@"
+
+#-------------------------------------------------------------------------------------------------------------------
+
+source "$KEYMAN_ROOT/resources/build/win/environment.inc.sh"
+WIN32_TARGET="$WIN32_TARGET_PATH/editor32.exe"
+X64_TARGET="$X64_TARGET_PATH/editor64.exe"
+
+builder_describe_outputs \
+ configure:project /resources/build/win/delphi_environment_generated.inc.sh \
+ build:project /windows/src/support/texteditor/$WIN32_TARGET
+
+#-------------------------------------------------------------------------------------------------------------------
+
+function do_clean() {
+ vs_msbuild Editor.vcxproj //t:Clean
+ clean_windows_project_files
+}
+
+function do_build() {
+ create-windows-output-folders
+ # build_version.res
+ vs_msbuild Editor.vcxproj //t:Build "//p:Platform=Win32"
+ vs_msbuild Editor.vcxproj //t:Build "//p:Platform=x64"
+ cp "$WIN32_TARGET" "$WINDOWS_PROGRAM_SUPPORT"
+ cp "$X64_TARGET" "$WINDOWS_PROGRAM_SUPPORT"
+ cp "$WIN32_TARGET_PATH/editor32.pdb" "$WINDOWS_DEBUGPATH_SUPPORT"
+ cp "$X64_TARGET_PATH/editor64.pdb" "$WINDOWS_DEBUGPATH_SUPPORT"
+}
+
+builder_run_action clean:project do_clean
+builder_run_action configure:project configure_windows_build_environment
+builder_run_action build:project do_build
+# builder_run_action test:project do_test
diff --git a/windows/src/support/windowinfo/Makefile b/windows/src/support/windowinfo/Makefile
deleted file mode 100644
index ac7da2c182..0000000000
--- a/windows/src/support/windowinfo/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# windowinfo Makefile
-#
-
-!include ..\..\Defines.mak
-
-install: dirs build
- $(COPY) windowinfo.exe $(PROGRAM)\bldutil
-
-build: version.res
- $(DCC32) windowinfo.dpr
-
-clean: def-clean
-
-!include ..\..\Target.mak
diff --git a/windows/src/test/manual-tests/integration-tests/Makefile b/windows/src/test/manual-tests/integration-tests/Makefile
deleted file mode 100644
index 093dc44140..0000000000
--- a/windows/src/test/manual-tests/integration-tests/Makefile
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# Integration Tests Makefile.
-#
-
-# ----------------------------------------------------------------------
-
-TARGETS=keymanapi
-
-test:
- $(MAKE) "TARGET=test" $(TARGETS)
-
-!include ..\..\Header.mak
-
-# ----------------------------------------------------------------------
-
-keymanapi:
- cd $(ROOT)\src\test\integration-tests\keymanapi
- $(MAKE) $(TARGET)
-
-# ----------------------------------------------------------------------
-
-!include ..\..\Target.mak
-
-# ----------------------------------------------------------------------
-# EOF
-# ----------------------------------------------------------------------
diff --git a/windows/src/test/manual-tests/integration-tests/keymanapi/Makefile b/windows/src/test/manual-tests/integration-tests/keymanapi/Makefile
deleted file mode 100644
index 7becbb044d..0000000000
--- a/windows/src/test/manual-tests/integration-tests/keymanapi/Makefile
+++ /dev/null
@@ -1,23 +0,0 @@
-#
-# Integration tests for keymanapi
-#
-
-!include ..\..\..\Defines.mak
-
-!ifdef EXCLUDE_ELEVATED
-TEST_MODE=--exclude:Elevated
-!endif
-
-test: build
- $(WIN32_TARGET_PATH)\keymanapi_test.exe -b -exit:continue $(TEST_MODE)
- $(WIN64_TARGET_PATH)\keymanapi_test.exe -b -exit:continue $(TEST_MODE)
-
-build:
- $(DELPHI_MSBUILD) "/p:Platform=Win32" keymanapi_test.dproj
- $(DELPHI_MSBUILD) "/p:Platform=Win64" keymanapi_test.dproj
-
-clean: def-clean
- -rd /s/q Win32
- -rd /s/q Win64
-
-!include ..\..\..\Target.mak
diff --git a/windows/src/test/manual-tests/regressiontest/Makefile b/windows/src/test/manual-tests/regressiontest/Makefile
deleted file mode 100644
index dbfa70078c..0000000000
--- a/windows/src/test/manual-tests/regressiontest/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# REGRESSIONTEST Makefile
-#
-
-
-!include ..\..\Defines.mak
-
-build: dirs
- $(DCC32) regressiontest.dpr
- $(COPY) regressiontest.exe $(PROGRAM)\support
-
-clean: def-clean
- cd tests
- $(MAKE) clean
-
-!include ..\..\Target.mak
diff --git a/windows/src/test/manual-tests/regressiontest/tests/Makefile b/windows/src/test/manual-tests/regressiontest/tests/Makefile
deleted file mode 100644
index 01f8705399..0000000000
--- a/windows/src/test/manual-tests/regressiontest/tests/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-
-!include ..\..\..\Defines.mak
-
-all:
- for %d in (*.kmn) do $(PROGRAM)\bin\kmc.cmd build "%d"
-
-.kmn.kmx:
- &$(PROGRAM)\bin\kmc.cmd build $**
-
-clean:
- -del *.kmx
diff --git a/windows/src/test/manual-tests/test_httpuploader/Makefile b/windows/src/test/manual-tests/test_httpuploader/Makefile
deleted file mode 100644
index b6250f4bfd..0000000000
--- a/windows/src/test/manual-tests/test_httpuploader/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# test_httpuploader Makefile
-#
-
-!include ..\..\Defines.mak
-
-build: version.res manifest.res
- $(DCC32) test_httpuploader.dpr
-
-icons:
- rc icons.rc
-
-clean: def-clean
-
-signcode:
- rem no signcode
-
-!include ..\..\Target.mak