Merge pull request #8276 from keymanapp/feat/core/8069-key2-keys-epic-ldml

feat(core): ldml rename key2 to keys 🙀
This commit is contained in:
Steven R. Loomis 2023-02-22 14:49:00 -06:00 • committed by GitHub
commit bc68033183
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 335 additions and 353 deletions

View file

@ -1,18 +1,18 @@
import { constants } from "@keymanapp/ldml-keyboard-constants";
import { Key2Flick, KMXPlusData, StrsItem } from "../kmx-plus.js";
import { KeysFlick, KMXPlusData, StrsItem } from "../kmx-plus.js";
import { build_strs_index, BUILDER_STRS } from "./build-strs.js";
import { build_list_index, BUILDER_LIST } from "./build-list.js";
import { BUILDER_SECTION } from "./builder-section.js";
/* ------------------------------------------------------------------
* key2 section
* keys section
------------------------------------------------------------------ */
/**
* This struct is a single <key> in the key2 keybag
* This struct is a single <key> in the keys keybag
*/
interface BUILDER_KEY2_KEY {
interface BUILDER_KEYS_KEY {
to: number; // str or single codepoint
flags: number;
id: number; // str with original key id
@ -28,59 +28,59 @@ interface BUILDER_KEY2_KEY {
/**
* This is a <flicks>, a list of <flick> elements.
*/
interface BUILDER_KEY2_FLICKS {
count: number; // number of BUILDER_KEY2_FLICK entries in this flick list
interface BUILDER_KEYS_FLICKS {
count: number; // number of BUILDER_KEYS_FLICK entries in this flick list
flick: number; // index into the flick[] subtable of the first flick in the list
id: number; // str with the original id of this flicks
_id: string; // copy of the flicks id, used for sorting during build
_flicks: Key2Flick[]; // temporary copy of Key2Flick object
_flicks: KeysFlick[]; // temporary copy of KeysFlick object
};
/**
* This is a single <flick> element.
*/
interface BUILDER_KEY2_FLICK {
interface BUILDER_KEYS_FLICK {
directions: number; // list of cardinal/intercardinal directions
flags: number; //
to: number; // str or single codepoint
};
interface BUILDER_KEY2_KMAP {
interface BUILDER_KEYS_KMAP {
vkey: number;
mod: number;
key: number; //index to key2.key
key: number; //index to keys.key
};
/**
* Builder for the 'keys' section
*/
export interface BUILDER_KEY2 extends BUILDER_SECTION {
export interface BUILDER_KEYS extends BUILDER_SECTION {
ident: number;
size: number;
keyCount: number;
flicksCount: number;
flickCount: number;
kmapCount: number;
keys: BUILDER_KEY2_KEY[];
flicks: BUILDER_KEY2_FLICKS[];
flick: BUILDER_KEY2_FLICK[];
kmap: BUILDER_KEY2_KMAP[];
keys: BUILDER_KEYS_KEY[];
flicks: BUILDER_KEYS_FLICKS[];
flick: BUILDER_KEYS_FLICK[];
kmap: BUILDER_KEYS_KMAP[];
};
export function build_key2(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS, sect_list: BUILDER_LIST): BUILDER_KEY2 {
if(kmxplus.key2.keys.length == 0 &&
(kmxplus.key2.flicks.length <= 1)) { // if no keys and only the 'null' flick.
export function build_keys(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS, sect_list: BUILDER_LIST): BUILDER_KEYS {
if(kmxplus.keys.keys.length == 0 &&
(kmxplus.keys.flicks.length <= 1)) { // if no keys and only the 'null' flick.
return null;
}
let key2: BUILDER_KEY2 = {
ident: constants.hex_section_id(constants.section.key2),
let keys: BUILDER_KEYS = {
ident: constants.hex_section_id(constants.section.keys),
size: 0,
keyCount: kmxplus.key2.keys.length,
flicksCount: kmxplus.key2.flicks.length,
keyCount: kmxplus.keys.keys.length,
flicksCount: kmxplus.keys.flicks.length,
flickCount: 0,
kmapCount: kmxplus.key2.kmap.length,
kmapCount: kmxplus.keys.kmap.length,
keys: [],
flicks: [],
flick: [],
@ -90,11 +90,11 @@ export function build_key2(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS, sect_l
// flicks first: the keys will need to index into the flicks table.
// Note that per the Key2 class and spec, there is always a flicks=0 meaning 'no flicks'
key2.flicks = kmxplus.key2.flicks.map((flicks) => {
let result : BUILDER_KEY2_FLICKS = {
// Note that per the Keys class and spec, there is always a flicks=0 meaning 'no flicks'
keys.flicks = kmxplus.keys.flicks.map((flicks) => {
let result : BUILDER_KEYS_FLICKS = {
count: flicks.flicks.length,
flick: key2.flick.length, // index of first flick
flick: keys.flick.length, // index of first flick
id: build_strs_index(sect_strs, flicks.id),
_id: flicks.id.value,
_flicks: flicks.flicks,
@ -102,22 +102,22 @@ export function build_key2(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS, sect_l
return result;
});
// Sort the flicks array by id
key2.flicks.sort((a, b) => StrsItem.binaryStringCompare(a._id, b._id));
keys.flicks.sort((a, b) => StrsItem.binaryStringCompare(a._id, b._id));
// now, allocate 'flick' entries for each 'flicks'
key2.flicks.forEach((flicks) => {
keys.flicks.forEach((flicks) => {
flicks._flicks.forEach((flick) => {
key2.flick.push({
keys.flick.push({
directions: build_list_index(sect_list, flick.directions),
flags: flick.flags,
to: build_strs_index(sect_strs, flick.to),
});
key2.flickCount++;
keys.flickCount++;
});
});
// now, keys
key2.keys = kmxplus.key2.keys.map((key) => {
let result : BUILDER_KEY2_KEY = {
keys.keys = kmxplus.keys.keys.map((key) => {
let result : BUILDER_KEYS_KEY = {
to: build_strs_index(sect_strs, key.to),
flags: key.flags,
id: build_strs_index(sect_strs, key.id),
@ -127,33 +127,33 @@ export function build_key2(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS, sect_l
longPress: build_list_index(sect_list, key.longPress),
longPressDefault: build_strs_index(sect_strs, key.longPressDefault),
multiTap: build_list_index(sect_list, key.multiTap),
flicks: key2.flicks.findIndex(v => v._id === (key.flicks || '')), // flicks id='' is the 'null' flicks
flicks: keys.flicks.findIndex(v => v._id === (key.flicks || '')), // flicks id='' is the 'null' flicks
};
// Make sure the flicks were found
if (result.flicks === -1) {
throw new Error(`Key2: Could not find flicks id=${key.flicks} for key=${key.id.value}`);
throw new Error(`Keys: Could not find flicks id=${key.flicks} for key=${key.id.value}`);
}
return result;
});
// sort the keys by id
key2.keys.sort((a, b) => StrsItem.binaryStringCompare(a._id, b._id));
keys.keys.sort((a, b) => StrsItem.binaryStringCompare(a._id, b._id));
// finally, kmap
key2.kmap = kmxplus.key2.kmap.map(({vkey, mod, key}) => {
let result : BUILDER_KEY2_KMAP = {
keys.kmap = kmxplus.keys.kmap.map(({vkey, mod, key}) => {
let result : BUILDER_KEYS_KMAP = {
vkey,
mod,
key: key2.keys.findIndex(k => k._id === key),
key: keys.keys.findIndex(k => k._id === key),
};
// Make sure the key was found
if (result.key === -1) {
throw new Error(`Key2: Could not find key2.key id=${result.key} for key2.kmap.key=${key}`);
throw new Error(`Keys: Could not find keys.key id=${result.key} for keys.kmap.key=${key}`);
}
return result;
});
// Sort kmap by vkey, mod order, per C7043
key2.kmap.sort((a,b) => {
keys.kmap.sort((a,b) => {
let rc = 0;
if (rc === 0) {
rc = (a.vkey - b.vkey);
@ -164,12 +164,12 @@ export function build_key2(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS, sect_l
return rc;
});
let offset = constants.length_key2 +
(constants.length_key2_key * key2.keyCount) +
(constants.length_key2_flick_element * key2.flickCount) +
(constants.length_key2_flick_list * key2.flicksCount) +
(constants.length_key2_kmap * key2.kmapCount);
key2.size = offset;
let offset = constants.length_keys +
(constants.length_keys_key * keys.keyCount) +
(constants.length_keys_flick_element * keys.flickCount) +
(constants.length_keys_flick_list * keys.flicksCount) +
(constants.length_keys_kmap * keys.kmapCount);
keys.size = offset;
return key2;
return keys;
}

View file

@ -5,7 +5,7 @@ import { BUILDER_SECTION } from './builder-section.js';
import { BUILDER_SECT, build_sect } from './build-sect.js';
import { BUILDER_DISP, build_disp } from './build-disp.js';
import { BUILDER_ELEM, build_elem } from './build-elem.js';
import { BUILDER_KEY2, build_key2 } from './build-key2.js';
import { BUILDER_KEYS, build_keys } from './build-keys.js';
import { BUILDER_LAYR, build_layr } from './build-layr.js';
import { BUILDER_LIST, build_list } from './build-list.js';
import { BUILDER_LOCA, build_loca } from './build-loca.js';
@ -26,7 +26,7 @@ type SectionBuilders = {
disp?: BUILDER_DISP;
elem?: BUILDER_ELEM;
finl?: BUILDER_FINL;
key2?: BUILDER_KEY2;
keys?: BUILDER_KEYS;
layr?: BUILDER_LAYR;
list?: BUILDER_LIST;
loca?: BUILDER_LOCA;
@ -62,7 +62,7 @@ export default class KMXPlusBuilder {
this.emitSection(file, this.file.COMP_PLUS_ELEM, this.sect.elem);
this.emitElements(file);
this.emitSection(file, this.file.COMP_PLUS_FINL, this.sect.finl);
this.emitSection(file, this.file.COMP_PLUS_KEY2, this.sect.key2);
this.emitSection(file, this.file.COMP_PLUS_KEYS, this.sect.keys);
this.emitSection(file, this.file.COMP_PLUS_LAYR, this.sect.layr);
this.emitSection(file, this.file.COMP_PLUS_LIST, this.sect.list);
this.emitSection(file, this.file.COMP_PLUS_LOCA, this.sect.loca);
@ -92,7 +92,7 @@ export default class KMXPlusBuilder {
this.sect.bksp = build_bksp(this.file.kmxplus.bksp, this.sect.strs, this.sect.elem);
this.sect.disp = build_disp(this.file.kmxplus, this.sect.strs);
this.sect.finl = build_finl(this.file.kmxplus.finl, this.sect.strs, this.sect.elem);
this.sect.key2 = build_key2(this.file.kmxplus, this.sect.strs, this.sect.list);
this.sect.keys = build_keys(this.file.kmxplus, this.sect.strs, this.sect.list);
this.sect.layr = build_layr(this.file.kmxplus, this.sect.strs, this.sect.list);
this.sect.loca = build_loca(this.file.kmxplus, this.sect.strs);
this.sect.meta = build_meta(this.file.kmxplus, this.sect.strs);
@ -128,7 +128,7 @@ export default class KMXPlusBuilder {
offset = this.finalize_sect_item(this.sect.disp, offset);
offset = this.finalize_sect_item(this.sect.elem, offset);
offset = this.finalize_sect_item(this.sect.finl, offset);
offset = this.finalize_sect_item(this.sect.key2, offset);
offset = this.finalize_sect_item(this.sect.keys, offset);
offset = this.finalize_sect_item(this.sect.layr, offset);
offset = this.finalize_sect_item(this.sect.list, offset);
offset = this.finalize_sect_item(this.sect.loca, offset);

View file

@ -245,7 +245,7 @@ export class Layr extends Section {
lists: LayrList[] = [];
};
export class Key2Keys {
export class KeysKeys {
flags: number;
flicks: string; // for in-memory only
id: StrsItem;
@ -258,16 +258,16 @@ export class Key2Keys {
};
export class Key2Kmap {
export class KeysKmap {
vkey: number;
mod: number;
key: string; // for in-memory only
};
export class Key2Flicks {
flicks: Key2Flick[] = [];
export class KeysFlicks {
flicks: KeysFlick[] = [];
id: StrsItem;
compareTo(b: Key2Flicks): number {
compareTo(b: KeysFlicks): number {
return this.id.compareTo(b.id);
}
constructor(id: StrsItem) {
@ -275,19 +275,19 @@ export class Key2Flicks {
}
};
export class Key2Flick {
export class KeysFlick {
directions: ListItem;
flags: number;
to: StrsItem;
};
export class Key2 extends Section {
keys: Key2Keys[] = [];
flicks: Key2Flicks[] = [];
kmap: Key2Kmap[] = [];
export class Keys extends Section {
keys: KeysKeys[] = [];
flicks: KeysFlicks[] = [];
kmap: KeysKmap[] = [];
constructor(strs: Strs) {
super();
let nullFlicks = new Key2Flicks(strs.allocString(''));
let nullFlicks = new KeysFlicks(strs.allocString(''));
this.flicks.push(nullFlicks); // C7043: null element string
}
};
@ -347,7 +347,7 @@ export interface KMXPlusData {
disp?: Disp;
elem?: Elem; // elem is ignored in-memory
finl?: Finl;
key2?: Key2;
keys?: Keys;
layr?: Layr;
list?: List; // list is ignored in-memory
loca?: Loca;
@ -381,7 +381,7 @@ export class KMXPlusFile extends KMXFile {
public readonly COMP_PLUS_FINL_ITEM: any;
public readonly COMP_PLUS_FINL: any;
// COMP_PLUS_KEYS is now COMP_PLUS_KEY2_KMAP
// COMP_PLUS_KEYS is now COMP_PLUS_KEYS_KMAP
public readonly COMP_PLUS_LAYR_ENTRY: any;
public readonly COMP_PLUS_LAYR_KEY: any;
@ -389,11 +389,11 @@ export class KMXPlusFile extends KMXFile {
public readonly COMP_PLUS_LAYR_ROW: any;
public readonly COMP_PLUS_LAYR: any;
public readonly COMP_PLUS_KEY2_FLICK: any;
public readonly COMP_PLUS_KEY2_FLICKS: any;
public readonly COMP_PLUS_KEY2_KEY: any;
public readonly COMP_PLUS_KEY2_KMAP: any;
public readonly COMP_PLUS_KEY2: any;
public readonly COMP_PLUS_KEYS_FLICK: any;
public readonly COMP_PLUS_KEYS_FLICKS: any;
public readonly COMP_PLUS_KEYS_KEY: any;
public readonly COMP_PLUS_KEYS_KMAP: any;
public readonly COMP_PLUS_KEYS: any;
public readonly COMP_PLUS_LIST_LIST: any;
public readonly COMP_PLUS_LIST_INDEX: any;
@ -482,7 +482,7 @@ export class KMXPlusFile extends KMXFile {
// 'finl' - see 'tran'
// 'keys' - see 'key2.kmap'
// 'keys' - see 'keys.kmap'
// 'layr'
@ -522,19 +522,19 @@ export class KMXPlusFile extends KMXFile {
keys: new r.Array(this.COMP_PLUS_LAYR_KEY, 'keyCount'),
});
this.COMP_PLUS_KEY2_FLICK = new r.Struct({
this.COMP_PLUS_KEYS_FLICK = new r.Struct({
directions: r.uint32le, // list
flags: r.uint32le,
to: r.uint32le, // str | codepoint
});
this.COMP_PLUS_KEY2_FLICKS = new r.Struct({
this.COMP_PLUS_KEYS_FLICKS = new r.Struct({
count: r.uint32le,
flick: r.uint32le,
id: r.uint32le, // str
});
this.COMP_PLUS_KEY2_KEY = new r.Struct({
this.COMP_PLUS_KEYS_KEY = new r.Struct({
to: r.uint32le, // str | codepoint
flags: r.uint32le,
id: r.uint32le, // str
@ -546,23 +546,23 @@ export class KMXPlusFile extends KMXFile {
flicks: r.uint32le, // index into flicks table
});
this.COMP_PLUS_KEY2_KMAP = new r.Struct({
this.COMP_PLUS_KEYS_KMAP = new r.Struct({
vkey: r.uint32le,
mod: r.uint32le,
key: r.uint32le, // index into 'keys' subtable
});
this.COMP_PLUS_KEY2 = new r.Struct({
this.COMP_PLUS_KEYS = new r.Struct({
ident: r.uint32le,
size: r.uint32le,
keyCount: r.uint32le,
flicksCount: r.uint32le,
flickCount: r.uint32le,
kmapCount: r.uint32le,
keys: new r.Array(this.COMP_PLUS_KEY2_KEY, 'keyCount'),
flicks: new r.Array(this.COMP_PLUS_KEY2_FLICKS, 'flicksCount'),
flick: new r.Array(this.COMP_PLUS_KEY2_FLICK, 'flickCount'),
kmap: new r.Array(this.COMP_PLUS_KEY2_KMAP, 'kmapCount'),
keys: new r.Array(this.COMP_PLUS_KEYS_KEY, 'keyCount'),
flicks: new r.Array(this.COMP_PLUS_KEYS_FLICKS, 'flicksCount'),
flick: new r.Array(this.COMP_PLUS_KEYS_FLICK, 'flickCount'),
kmap: new r.Array(this.COMP_PLUS_KEYS_KMAP, 'kmapCount'),
});
// 'list'

View file

@ -174,25 +174,21 @@ export function testTestdataReaderCases(cases : TestDataCase[]) {
assert.notOk(source, `loading ${testcase.subpath} (expected failure)`);
}
// special case for an expected exception
if (testcase.throws) {
assert.throws(() => reader.validate(source, loadLdmlKeyboardTestDataSchema()), testcase.throws);
} else {
assert.doesNotThrow(() => reader.validate(source, loadLdmlKeyboardTestDataSchema()), `validating ${testcase.subpath}`);
// if we expected errors or warnings, show them
if (testcase.errors) {
assert.includeDeepMembers(callbacks.messages, testcase.errors, 'expected errors to be included');
}
if (testcase.warnings) {
assert.includeDeepMembers(callbacks.messages, testcase.warnings, 'expected warnings to be included');
} else if (!expectFailure) {
// no warnings, so expect zero messages
assert.strictEqual(callbacks.messages.length, 0, 'expected zero messages but got ' +callbacks.messages.map(e => e.message).join(' ') );
}
// TODO-LDML: no validation for now.
// if we expected errors or warnings, show them
if (testcase.errors) {
assert.includeDeepMembers(callbacks.messages, testcase.errors, 'expected errors to be included');
}
if (testcase.warnings) {
assert.includeDeepMembers(callbacks.messages, testcase.warnings, 'expected warnings to be included');
} else if (!expectFailure) {
// no warnings, so expect zero messages
assert.strictEqual(callbacks.messages.length, 0, 'expected zero messages but got ' +callbacks.messages.map(e => e.message).join(' ') );
}
// run the user-supplied callback if any
if (testcase.callback) {
testcase.callback(data, source, testcase.subpath, callbacks);
}
// run the user-supplied callback if any
if (testcase.callback) {
testcase.callback(data, source, testcase.subpath, callbacks);
}
});
}

View file

@ -28,10 +28,10 @@
#define LDML_ELEM_FLAGS_TERTIARY_MASK 0xFF000000
#define LDML_ELEM_FLAGS_UNICODE_SET 0x1
#define LDML_FINL_FLAGS_ERROR 0x1
#define LDML_KEY2_FLICK_FLAGS_EXTEND 0x1
#define LDML_KEY2_KEY_FLAGS_EXTEND 0x1
#define LDML_KEY2_KEY_FLAGS_GAP 0x2
#define LDML_KEY2_KEY_FLAGS_NOTRANSFORM 0x4
#define LDML_KEYS_FLICK_FLAGS_EXTEND 0x1
#define LDML_KEYS_KEY_FLAGS_EXTEND 0x1
#define LDML_KEYS_KEY_FLAGS_GAP 0x2
#define LDML_KEYS_KEY_FLAGS_NOTRANSFORM 0x4
#define LDML_KEYS_MOD_ALL 0x11F
#define LDML_KEYS_MOD_ALT 0xC
#define LDML_KEYS_MOD_ALTL 0x4
@ -57,11 +57,11 @@
#define LDML_LENGTH_FINL 0x8
#define LDML_LENGTH_FINL_ITEM 0x10
#define LDML_LENGTH_HEADER 0x8
#define LDML_LENGTH_KEY2 0x18
#define LDML_LENGTH_KEY2_FLICK_ELEMENT 0xC
#define LDML_LENGTH_KEY2_FLICK_LIST 0xC
#define LDML_LENGTH_KEY2_KEY 0x24
#define LDML_LENGTH_KEY2_KMAP 0xC
#define LDML_LENGTH_KEYS 0x18
#define LDML_LENGTH_KEYS_FLICK_ELEMENT 0xC
#define LDML_LENGTH_KEYS_FLICK_LIST 0xC
#define LDML_LENGTH_KEYS_KEY 0x24
#define LDML_LENGTH_KEYS_KMAP 0xC
#define LDML_LENGTH_LAYR 0x18
#define LDML_LENGTH_LAYR_ENTRY 0x10
#define LDML_LENGTH_LAYR_KEY 0x4
@ -96,8 +96,8 @@
#define LDML_SECTIONNAME_ELEM "elem"
#define LDML_SECTIONID_FINL 0x6C6E6966 /* "finl" */
#define LDML_SECTIONNAME_FINL "finl"
#define LDML_SECTIONID_KEY2 0x3279656B /* "key2" */
#define LDML_SECTIONNAME_KEY2 "key2"
#define LDML_SECTIONID_KEYS 0x7379656B /* "keys" */
#define LDML_SECTIONNAME_KEYS "keys"
#define LDML_SECTIONID_LAYR 0x7279616C /* "layr" */
#define LDML_SECTIONNAME_LAYR "layr"
#define LDML_SECTIONID_LIST 0x7473696C /* "list" */

View file

@ -29,7 +29,7 @@ export type SectionIdent =
'disp' |
'elem' |
'finl' |
'key2' |
'keys' |
'layr' |
'list' |
'loca' |
@ -224,7 +224,7 @@ class Constants {
readonly finl_flags_error = 0x0001;
/* ------------------------------------------------------------------
* keys section is now key2.kmap
* keys section is now keys.kmap
------------------------------------------------------------------ */
/**
@ -287,49 +287,49 @@ class Constants {
readonly keys_mod_all: number = Array.from(this.keys_mod_map.values()).reduce((p, v) => (p | v), this.keys_mod_none);
/* ------------------------------------------------------------------
* key2 section
* keys section
------------------------------------------------------------------ */
/**
* Minimum length of the 'key2' section not including variable parts
* Minimum length of the 'keys' section not including variable parts
*/
readonly length_key2 = 24;
readonly length_keys = 24;
/**
* Length of each item in the 'key2' keys sub-table
* Length of each item in the 'keys' keys sub-table
*/
readonly length_key2_key = 36;
readonly length_keys_key = 36;
/**
* Length of each item in the 'key2' flick lists sub-table
* Length of each item in the 'keys' flick lists sub-table
*/
readonly length_key2_flick_list = 12;
readonly length_keys_flick_list = 12;
/**
* Length of each item in the 'key2' flick elements sub-table
* Length of each item in the 'keys' flick elements sub-table
*/
readonly length_key2_flick_element = 12;
readonly length_keys_flick_element = 12;
/**
* Length of each item in the 'key2.kmap' key map subtable
* Length of each item in the 'keys.kmap' key map subtable
*/
readonly length_key2_kmap = 12;
readonly length_keys_kmap = 12;
/**
* 0 if to is a char, 1 if it is a string
*/
readonly key2_key_flags_extend = 0x00000001;
readonly keys_key_flags_extend = 0x00000001;
/**
* 1 if the key is a gap
*/
readonly key2_key_flags_gap = 0x00000002;
readonly keys_key_flags_gap = 0x00000002;
/**
* 1 if the key is transform=no
*/
readonly key2_key_flags_notransform = 0x00000004;
readonly keys_key_flags_notransform = 0x00000004;
/**
* 0 if to is a char, 1 if it is a string
*/
readonly key2_flick_flags_extend = 0x00000001;
readonly keys_flick_flags_extend = 0x00000001;
/* ------------------------------------------------------------------
* layr section
@ -517,7 +517,7 @@ class Constants {
disp: 'disp',
elem: 'elem',
finl: 'finl',
key2: 'key2',
keys: 'keys',
layr: 'layr',
list: 'list',
loca: 'loca',

View file

@ -538,63 +538,63 @@ COMP_KMXPLUS_LAYR_Helper::getKey(KMX_DWORD key) const {
}
bool
COMP_KMXPLUS_KEY2::valid(KMX_DWORD _kmn_unused(length)) const {
COMP_KMXPLUS_KEYS::valid(KMX_DWORD _kmn_unused(length)) const {
if (header.size < sizeof(*this)
+ (keyCount * sizeof(COMP_KMXPLUS_KEY2_KEY))
+ (flicksCount * sizeof(COMP_KMXPLUS_KEY2_FLICK_LIST))
+ (flickCount * sizeof(COMP_KMXPLUS_KEY2_FLICK_ELEMENT))
+ (kmapCount * sizeof(COMP_KMXPLUS_KEY2_KMAP))) {
+ (keyCount * sizeof(COMP_KMXPLUS_KEYS_KEY))
+ (flicksCount * sizeof(COMP_KMXPLUS_KEYS_FLICK_LIST))
+ (flickCount * sizeof(COMP_KMXPLUS_KEYS_FLICK_ELEMENT))
+ (kmapCount * sizeof(COMP_KMXPLUS_KEYS_KMAP))) {
DebugLog("header.size < expected size");
assert(false);
return false;
}
// further validation in the COMP_KMXPLUS_KEY2_Helper helper obj
// further validation in the COMP_KMXPLUS_KEYS_Helper helper obj
return true;
}
COMP_KMXPLUS_KEY2_Helper::COMP_KMXPLUS_KEY2_Helper() : key2(nullptr), is_valid(false) {
COMP_KMXPLUS_KEYS_Helper::COMP_KMXPLUS_KEYS_Helper() : key2(nullptr), is_valid(false) {
}
bool
COMP_KMXPLUS_KEY2_Helper::setKey2(const COMP_KMXPLUS_KEY2 *newKey2) {
DebugLog("validating newKey2=%p", newKey2);
COMP_KMXPLUS_KEYS_Helper::setKeys(const COMP_KMXPLUS_KEYS *newKeys) {
DebugLog("validating newKeys=%p", newKeys);
is_valid = true;
if (newKey2 == nullptr) {
if (newKeys == nullptr) {
// null = invalid
is_valid = false;
// No assert here: just a missing layer
return false;
}
key2 = newKey2;
const uint8_t *rawdata = reinterpret_cast<const uint8_t *>(newKey2);
rawdata += LDML_LENGTH_KEY2; // skip past non-dynamic portion
key2 = newKeys;
const uint8_t *rawdata = reinterpret_cast<const uint8_t *>(newKeys);
rawdata += LDML_LENGTH_KEYS; // skip past non-dynamic portion
// keys
if (key2->keyCount > 0) {
keys = reinterpret_cast<const COMP_KMXPLUS_KEY2_KEY *>(rawdata);
keys = reinterpret_cast<const COMP_KMXPLUS_KEYS_KEY *>(rawdata);
} else {
keys = nullptr;
is_valid = false;
assert(is_valid);
}
rawdata += sizeof(COMP_KMXPLUS_KEY2_KEY) * key2->keyCount;
rawdata += sizeof(COMP_KMXPLUS_KEYS_KEY) * key2->keyCount;
// flicks
if (key2->flicksCount > 0) {
flickLists = reinterpret_cast<const COMP_KMXPLUS_KEY2_FLICK_LIST *>(rawdata);
flickLists = reinterpret_cast<const COMP_KMXPLUS_KEYS_FLICK_LIST *>(rawdata);
} else {
flickLists = nullptr; // not an error
}
rawdata += sizeof(COMP_KMXPLUS_KEY2_FLICK_LIST) * key2->flicksCount;
rawdata += sizeof(COMP_KMXPLUS_KEYS_FLICK_LIST) * key2->flicksCount;
// flick
if (key2->flickCount > 0) {
flickElements = reinterpret_cast<const COMP_KMXPLUS_KEY2_FLICK_ELEMENT *>(rawdata);
flickElements = reinterpret_cast<const COMP_KMXPLUS_KEYS_FLICK_ELEMENT *>(rawdata);
} else {
flickElements = nullptr; // not an error
}
rawdata += sizeof(COMP_KMXPLUS_KEY2_FLICK_ELEMENT) * key2->flickCount;
rawdata += sizeof(COMP_KMXPLUS_KEYS_FLICK_ELEMENT) * key2->flickCount;
// kmap
if (key2->kmapCount > 0) {
kmap = reinterpret_cast<const COMP_KMXPLUS_KEY2_KMAP *>(rawdata);
kmap = reinterpret_cast<const COMP_KMXPLUS_KEYS_KMAP *>(rawdata);
} else {
kmap = nullptr; // not an error
}
@ -654,13 +654,13 @@ COMP_KMXPLUS_KEY2_Helper::setKey2(const COMP_KMXPLUS_KEY2 *newKey2) {
}
}
// Return results
DebugLog("COMP_KMXPLUS_KEY2_Helper.setKey2(): %s", is_valid ? "valid" : "invalid");
DebugLog("COMP_KMXPLUS_KEYS_Helper.setKeys(): %s", is_valid ? "valid" : "invalid");
assert(is_valid);
return is_valid;
}
const COMP_KMXPLUS_KEY2_KEY *
COMP_KMXPLUS_KEY2_Helper::getKeys(KMX_DWORD i) const {
const COMP_KMXPLUS_KEYS_KEY *
COMP_KMXPLUS_KEYS_Helper::getKeys(KMX_DWORD i) const {
if (!valid() || i >= key2->keyCount) {
assert(false);
return nullptr;
@ -668,8 +668,8 @@ COMP_KMXPLUS_KEY2_Helper::getKeys(KMX_DWORD i) const {
return keys + i;
}
const COMP_KMXPLUS_KEY2_KEY*
COMP_KMXPLUS_KEY2_Helper::findKeyByStringId(KMX_DWORD strId, KMX_DWORD &i) const {
const COMP_KMXPLUS_KEYS_KEY*
COMP_KMXPLUS_KEYS_Helper::findKeyByStringId(KMX_DWORD strId, KMX_DWORD &i) const {
for (i = 0; i < key2->keyCount; i++) {
if (keys[i].id == strId) {
return &keys[i];
@ -678,8 +678,8 @@ COMP_KMXPLUS_KEY2_Helper::findKeyByStringId(KMX_DWORD strId, KMX_DWORD &i) const
return nullptr;
}
const COMP_KMXPLUS_KEY2_FLICK_LIST *
COMP_KMXPLUS_KEY2_Helper::getFlickLists(KMX_DWORD i) const {
const COMP_KMXPLUS_KEYS_FLICK_LIST *
COMP_KMXPLUS_KEYS_Helper::getFlickLists(KMX_DWORD i) const {
if (!valid() || i >= key2->flicksCount) {
assert(false);
return nullptr;
@ -687,8 +687,8 @@ COMP_KMXPLUS_KEY2_Helper::getFlickLists(KMX_DWORD i) const {
return flickLists + i;
}
const COMP_KMXPLUS_KEY2_FLICK_ELEMENT *
COMP_KMXPLUS_KEY2_Helper::getFlickElements(KMX_DWORD i) const {
const COMP_KMXPLUS_KEYS_FLICK_ELEMENT *
COMP_KMXPLUS_KEYS_Helper::getFlickElements(KMX_DWORD i) const {
if (!valid() || i >= key2->flickCount) {
assert(false);
return nullptr;
@ -696,8 +696,8 @@ COMP_KMXPLUS_KEY2_Helper::getFlickElements(KMX_DWORD i) const {
return flickElements + i;
}
const COMP_KMXPLUS_KEY2_KMAP *
COMP_KMXPLUS_KEY2_Helper::getKmap(KMX_DWORD i) const {
const COMP_KMXPLUS_KEYS_KMAP *
COMP_KMXPLUS_KEYS_Helper::getKmap(KMX_DWORD i) const {
if (!valid() || i >= key2->kmapCount) {
assert(false);
return nullptr;
@ -706,8 +706,8 @@ COMP_KMXPLUS_KEY2_Helper::getKmap(KMX_DWORD i) const {
}
std::u16string
COMP_KMXPLUS_KEY2_KEY::get_string() const {
assert(!(flags & LDML_KEY2_KEY_FLAGS_EXTEND)); // should not be called.
COMP_KMXPLUS_KEYS_KEY::get_string() const {
assert(!(flags & LDML_KEYS_KEY_FLAGS_EXTEND)); // should not be called.
char16_single buf;
const int len = Utf32CharToUtf16(to, buf);
return std::u16string(buf.ch, len);
@ -849,7 +849,7 @@ kmx_plus::kmx_plus(const COMP_KEYBOARD *keyboard, size_t length)
// these will be nullptr if they don't validate
disp = section_from_sect<COMP_KMXPLUS_DISP>(sect);
elem = section_from_sect<COMP_KMXPLUS_ELEM>(sect);
key2 = section_from_sect<COMP_KMXPLUS_KEY2>(sect);
key2 = section_from_sect<COMP_KMXPLUS_KEYS>(sect);
layr = section_from_sect<COMP_KMXPLUS_LAYR>(sect);
list = section_from_sect<COMP_KMXPLUS_LIST>(sect);
loca = section_from_sect<COMP_KMXPLUS_LOCA>(sect);
@ -859,7 +859,7 @@ kmx_plus::kmx_plus(const COMP_KEYBOARD *keyboard, size_t length)
vkey = section_from_sect<COMP_KMXPLUS_VKEY>(sect);
// calculate and validate the dynamic parts
(void)key2Helper.setKey2(key2);
(void)key2Helper.setKeys(key2);
(void)layrHelper.setLayr(layr);
(void)listHelper.setList(list);
}

View file

@ -438,8 +438,8 @@ static_assert(sizeof(struct COMP_KMXPLUS_LAYR) == LDML_LENGTH_LAYR, "mismatched
/* ------------------------------------------------------------------
* key2 section
------------------------------------------------------------------ */
struct COMP_KMXPLUS_KEY2 {
static const KMX_DWORD IDENT = LDML_SECTIONID_KEY2;
struct COMP_KMXPLUS_KEYS {
static const KMX_DWORD IDENT = LDML_SECTIONID_KEYS;
COMP_KMXPLUS_HEADER header;
KMX_DWORD keyCount;
KMX_DWORD flicksCount;
@ -456,19 +456,19 @@ struct COMP_KMXPLUS_KEY2 {
bool valid(KMX_DWORD length) const;
};
struct COMP_KMXPLUS_KEY2_FLICK_ELEMENT {
struct COMP_KMXPLUS_KEYS_FLICK_ELEMENT {
KMXPLUS_LIST directions;
KMX_DWORD flags;
KMXPLUS_STR to; // string or codepoint
};
struct COMP_KMXPLUS_KEY2_FLICK_LIST {
struct COMP_KMXPLUS_KEYS_FLICK_LIST {
KMX_DWORD count;
KMX_DWORD flick; // flick index
KMXPLUS_STR id;
};
struct COMP_KMXPLUS_KEY2_KEY {
struct COMP_KMXPLUS_KEYS_KEY {
KMXPLUS_STR to;
KMX_DWORD flags;
KMXPLUS_STR id;
@ -482,26 +482,26 @@ struct COMP_KMXPLUS_KEY2_KEY {
std::u16string get_string() const;
};
struct COMP_KMXPLUS_KEY2_KMAP {
struct COMP_KMXPLUS_KEYS_KMAP {
KMX_DWORD vkey;
KMX_DWORD mod;
KMX_DWORD key; // index into key subtable
};
class COMP_KMXPLUS_KEY2_Helper {
class COMP_KMXPLUS_KEYS_Helper {
public:
COMP_KMXPLUS_KEY2_Helper();
COMP_KMXPLUS_KEYS_Helper();
/**
* Initialize the helper to point at a layr section.
* @return true if valid
*/
bool setKey2(const COMP_KMXPLUS_KEY2 *newKey2);
bool setKeys(const COMP_KMXPLUS_KEYS *newKeys);
inline bool valid() const { return is_valid; }
const COMP_KMXPLUS_KEY2_KEY *getKeys(KMX_DWORD key) const;
const COMP_KMXPLUS_KEY2_FLICK_LIST *getFlickLists(KMX_DWORD list) const;
const COMP_KMXPLUS_KEY2_FLICK_ELEMENT *getFlickElements(KMX_DWORD element) const;
const COMP_KMXPLUS_KEY2_KMAP *getKmap(KMX_DWORD element) const;
const COMP_KMXPLUS_KEYS_KEY *getKeys(KMX_DWORD key) const;
const COMP_KMXPLUS_KEYS_FLICK_LIST *getFlickLists(KMX_DWORD list) const;
const COMP_KMXPLUS_KEYS_FLICK_ELEMENT *getFlickElements(KMX_DWORD element) const;
const COMP_KMXPLUS_KEYS_KMAP *getKmap(KMX_DWORD element) const;
/**
* Search for a key by string id.
@ -509,23 +509,23 @@ public:
* @param index on exit, index of item if found. Undefined otherwise.
* @return pointer to key or nullptr
*/
const COMP_KMXPLUS_KEY2_KEY *findKeyByStringId(KMX_DWORD strId, KMX_DWORD &index) const;
const COMP_KMXPLUS_KEYS_KEY *findKeyByStringId(KMX_DWORD strId, KMX_DWORD &index) const;
private:
const COMP_KMXPLUS_KEY2 *key2;
const COMP_KMXPLUS_KEYS *key2;
bool is_valid;
const COMP_KMXPLUS_KEY2_KEY *keys;
const COMP_KMXPLUS_KEY2_FLICK_LIST *flickLists;
const COMP_KMXPLUS_KEY2_FLICK_ELEMENT *flickElements;
const COMP_KMXPLUS_KEY2_KMAP *kmap;
const COMP_KMXPLUS_KEYS_KEY *keys;
const COMP_KMXPLUS_KEYS_FLICK_LIST *flickLists;
const COMP_KMXPLUS_KEYS_FLICK_ELEMENT *flickElements;
const COMP_KMXPLUS_KEYS_KMAP *kmap;
};
static_assert(sizeof(struct COMP_KMXPLUS_KEY2_KEY) == LDML_LENGTH_KEY2_KEY, "mismatched size of key2.key");
static_assert(sizeof(struct COMP_KMXPLUS_KEY2_FLICK_ELEMENT) == LDML_LENGTH_KEY2_FLICK_ELEMENT, "mismatched size of key2.flick");
static_assert(sizeof(struct COMP_KMXPLUS_KEY2_FLICK_LIST) == LDML_LENGTH_KEY2_FLICK_LIST, "mismatched size of key2.flicks");
static_assert(sizeof(struct COMP_KMXPLUS_KEY2_KMAP) == LDML_LENGTH_KEY2_KMAP, "mismatched size of key2.kmap");
static_assert(sizeof(struct COMP_KMXPLUS_KEY2) % 0x4 == 0, "Structs prior to variable part should align to 32-bit boundary");
static_assert(sizeof(struct COMP_KMXPLUS_KEY2) == LDML_LENGTH_KEY2, "mismatched size of section key2");
static_assert(sizeof(struct COMP_KMXPLUS_KEYS_KEY) == LDML_LENGTH_KEYS_KEY, "mismatched size of key2.key");
static_assert(sizeof(struct COMP_KMXPLUS_KEYS_FLICK_ELEMENT) == LDML_LENGTH_KEYS_FLICK_ELEMENT, "mismatched size of key2.flick");
static_assert(sizeof(struct COMP_KMXPLUS_KEYS_FLICK_LIST) == LDML_LENGTH_KEYS_FLICK_LIST, "mismatched size of key2.flicks");
static_assert(sizeof(struct COMP_KMXPLUS_KEYS_KMAP) == LDML_LENGTH_KEYS_KMAP, "mismatched size of key2.kmap");
static_assert(sizeof(struct COMP_KMXPLUS_KEYS) % 0x4 == 0, "Structs prior to variable part should align to 32-bit boundary");
static_assert(sizeof(struct COMP_KMXPLUS_KEYS) == LDML_LENGTH_KEYS, "mismatched size of section key2");
/* ------------------------------------------------------------------
* list section
@ -602,7 +602,7 @@ class kmx_plus {
// keep the next elements sorted
const COMP_KMXPLUS_DISP *disp;
const COMP_KMXPLUS_ELEM *elem;
const COMP_KMXPLUS_KEY2 *key2;
const COMP_KMXPLUS_KEYS *key2;
const COMP_KMXPLUS_LAYR *layr;
const COMP_KMXPLUS_LIST *list;
const COMP_KMXPLUS_LOCA *loca;
@ -614,7 +614,7 @@ class kmx_plus {
inline bool is_valid() { return valid; }
COMP_KMXPLUS_LAYR_Helper layrHelper;
COMP_KMXPLUS_LIST_Helper listHelper;
COMP_KMXPLUS_KEY2_Helper key2Helper;
COMP_KMXPLUS_KEYS_Helper key2Helper;
private:
bool valid; // true if valid
};

View file

@ -109,7 +109,7 @@ See [C7043.2.11](#c7043211-tran-finl-and-bksptransforms).
### C7043.2.5 Removed: `keys`
_this section has been merged into `key2.kmap`_
_this section has been merged into the new `keys.kmap`_
### C7043.2.6 `loca`—Locales

View file

@ -71,7 +71,7 @@ ldml_processor::ldml_processor(path const & kb_path, const std::vector<uint8_t>
auto keyEntry = kplus.key2Helper.getKeys(kmapEntry->key);
assert(keyEntry != nullptr);
if (keyEntry->flags && LDML_KEY2_KEY_FLAGS_EXTEND) {
if (keyEntry->flags && LDML_KEYS_KEY_FLAGS_EXTEND) {
if (nullptr == kplus.strs) {
DebugLog("for keys: kplus.strs == nullptr"); // need a string table to get strings
assert(false);

View file

@ -5,7 +5,7 @@
using namespace km::kbp::kmx;
int main(int argc, const char *argv[]) {
COMP_KMXPLUS_KEY2_KEY e[2] = {
COMP_KMXPLUS_KEYS_KEY e[2] = {
{
0x00000127, // to = U+0127 = 295
0x00000000 // flags: !EXTEND

View file

@ -3,7 +3,7 @@ import CompilerOptions from './compiler-options.js';
import { CompilerMessages } from './messages.js';
import { BkspCompiler, FinlCompiler, TranCompiler } from './tran.js';
import { DispCompiler } from './disp.js';
import { Key2Compiler } from './key2.js';
import { KeysCompiler } from './keys.js';
import { LayrCompiler } from './layr.js';
import { LocaCompiler } from './loca.js';
import { MetaCompiler } from './meta.js';
@ -18,7 +18,7 @@ const SECTION_COMPILERS = [
BkspCompiler,
DispCompiler,
FinlCompiler,
Key2Compiler,
KeysCompiler,
LayrCompiler,
LocaCompiler,
MetaCompiler,

View file

@ -4,15 +4,15 @@ import { CompilerMessages } from './messages.js';
import { SectionCompiler } from "./section-compiler.js";
import GlobalSections = KMXPlus.GlobalSections;
import Key2 = KMXPlus.Key2;
import Keys = KMXPlus.Keys;
import ListItem = KMXPlus.ListItem;
import Key2Flicks = KMXPlus.Key2Flicks;
import KeysFlicks = KMXPlus.KeysFlicks;
import { allUsedKeyIdsInLayers, calculateUniqueKeys, translateLayerAttrToModifier, validModifier } from '../util/util.js';
export class Key2Compiler extends SectionCompiler {
export class KeysCompiler extends SectionCompiler {
public get id() {
return constants.section.key2;
return constants.section.keys;
}
public validate() {
@ -36,13 +36,13 @@ export class Key2Compiler extends SectionCompiler {
return valid;
}
public compile(sections: GlobalSections): Key2 {
public compile(sections: GlobalSections): Keys {
if (!this.keyboard?.keys?.key && !this.keyboard?.keys?.flicks) {
// short-circuit if no keys or flicks
return null;
}
let sect = new Key2(sections.strs);
let sect = new Keys(sections.strs);
// Load the flicks first
this.loadFlicks(sections, sect);
@ -65,15 +65,15 @@ export class Key2Compiler extends SectionCompiler {
return sect;
}
public loadFlicks(sections: GlobalSections, sect: Key2) {
public loadFlicks(sections: GlobalSections, sect: Keys) {
for (let lkflicks of this.keyboard.keys.flicks) {
let flicks: Key2Flicks = new Key2Flicks(sections.strs.allocString(lkflicks.id));
let flicks: KeysFlicks = new KeysFlicks(sections.strs.allocString(lkflicks.id));
for (let lkflick of lkflicks.flick) {
let flags = 0;
// TODO-LDML: single char
const to = sections.strs.allocAndUnescapeString(lkflick.to);
flags |= constants.key2_flick_flags_extend;
flags |= constants.keys_flick_flags_extend;
let directions : ListItem = sections.list.allocListFromSpaces(sections.strs, lkflick.directions);
flicks.flicks.push({
directions,
@ -86,7 +86,7 @@ export class Key2Compiler extends SectionCompiler {
}
}
public loadKeys(sections: GlobalSections, sect: Key2) {
public loadKeys(sections: GlobalSections, sect: Keys) {
const usedKeys = allUsedKeyIdsInLayers(this.keyboard?.layers);
const uniqueKeys = calculateUniqueKeys([...this.keyboard.keys?.key]);
@ -99,17 +99,17 @@ export class Key2Compiler extends SectionCompiler {
const flicks = key.flicks;
// TODO-LDML: verify that this flick id exists
if (!!key.gap) {
flags |= constants.key2_key_flags_gap;
flags |= constants.keys_key_flags_gap;
}
if (key.transform === 'no') {
flags |= constants.key2_key_flags_notransform;
flags |= constants.keys_key_flags_notransform;
}
const id = sections.strs.allocString(key.id);
const longPress: ListItem = sections.list.allocListFromEscapedSpaces(sections.strs, key.longPress);
const longPressDefault = sections.strs.allocAndUnescapeString(key.longPressDefault);
const multiTap: ListItem = sections.list.allocListFromEscapedSpaces(sections.strs, key.multiTap);
const keySwitch = sections.strs.allocString(key.switch); // 'switch' is a reserved word
flags |= constants.key2_key_flags_extend;
flags |= constants.keys_key_flags_extend;
const to = sections.strs.allocAndUnescapeString(key.to); // TODO-LDML: single char
const width = Math.ceil((key.width || 1) * 10.0); // default, width=1
sect.keys.push({
@ -188,9 +188,9 @@ export class Key2Compiler extends SectionCompiler {
private compileHardwareLayerToKmap(
sections: GlobalSections,
layer: LDMLKeyboard.LKLayer,
sect: Key2,
sect: Keys,
hardware: string,
): Key2 {
): Keys {
const mod = translateLayerAttrToModifier(layer);
const keymap = Constants.HardwareToKeymap.get(hardware);

View file

@ -107,8 +107,8 @@ block(sectitems)
66 69 6e 6c
diff(sect,finl)
6b 65 79 32
diff(sect,key2)
6b 65 79 73
diff(sect,keys)
6c 61 79 72
diff(sect,layr)
@ -255,12 +255,12 @@ block(finl)
01 00 00 00 # KMX_DWORD flags;
# };
# ----------------------------------------------------------------------------------------------------
# key2
# keys
# ----------------------------------------------------------------------------------------------------
block(key2) # struct COMP_KMXPLUS_KEY2 {
6b 65 79 32 # KMX_DWORD header.ident; // 0000 Section name - key2
sizeof(key2) # KMX_DWORD header.size; // 0004 Section length
block(keys) # struct COMP_KMXPLUS_KEYS {
6b 65 79 73 # KMX_DWORD header.ident; // 0000 Section name - keys
sizeof(keys) # KMX_DWORD header.size; // 0004 Section length
02 00 00 00 # KMX_DWORD keyCount
01 00 00 00 # KMX_DWORD flicksCount
00 00 00 00 # KMX_DWORD flickCount
@ -277,7 +277,7 @@ block(key2) # struct COMP_KMXPLUS_KEY2 {
00 00 00 00 # TODO: index(listNull,listNull,4) # LIST multiTap
00 00 00 00 # flicks 0
# (#0001) that
index(strNull,strKey2,2) # KMXPLUS_STR 'U+0127'
index(strNull,strKeys,2) # KMXPLUS_STR 'U+0127'
01 00 00 00 # KMX_DWORD flags = extend
index(strNull,strThat,2) # KMXPLUS_STR 'hmaqtugha'
00 00 00 00 # KMXPLUS_STR switch
@ -301,9 +301,6 @@ block(key2) # struct COMP_KMXPLUS_KEY2 {
31 00 00 00 00 00 00 00 01 00 00 00 # KMX_DWORD vkey, mod, key;
c0 00 00 00 00 00 00 00 00 00 00 00 # KMX_DWORD vkey, mod, key;
# ----------------------------------------------------------------------------------------------------
# keys is now under key2.kmap
# ----------------------------------------------------------------------------------------------------
# ----------------------------------------------------------------------------------------------------
# layr
@ -442,7 +439,7 @@ block(strs) # struct COMP_KMXPLUS_STRS {
diff(strs,strThat) sizeof(strThat,2)
diff(strs,strTranTo) sizeof(strTranTo,2)
diff(strs,strKey1) sizeof(strKey1,2)
diff(strs,strKey2) sizeof(strKey2,2)
diff(strs,strKeys) sizeof(strKeys,2)
diff(strs,strElemOrdrFrom3) sizeof(strElemOrdrFrom3,2)
diff(strs,strElemOrdrFrom1) sizeof(strElemOrdrFrom1,2)
diff(strs,strElemOrdrBefore) sizeof(strElemOrdrBefore,2)
@ -470,7 +467,7 @@ block(strs) # struct COMP_KMXPLUS_STRS {
block(strThat) 74 00 68 00 61 00 74 00 block(x) 00 00 # 'that'
block(strTranTo) E2 00 block(x) 00 00 # 'â'
block(strKey1) 27 01 block(x) 00 00 # 'ħ'
block(strKey2) 90 17 b6 17 block(x) 00 00 # 'ថា'
block(strKeys) 90 17 b6 17 block(x) 00 00 # 'ថា'
# <reorder before="ᩫ" from="᩠᩵ᩅ" order="10 55 10" />
block(strElemOrdrFrom3) 45 1a block(x) 00 00 # 'ᩅ'
block(strElemOrdrFrom1) 60 1a block(x) 00 00 # '᩠'

View file

@ -3,7 +3,7 @@
<!DOCTYPE keyboard SYSTEM "../../../../../../../resources/standards-data/ldml-keyboards/techpreview/dtd/ldmlKeyboard.dtd">
<keyboard locale="mt" conformsTo="techpreview">
<names>
<name value="key2-escaped2" />
<name value="keys-escaped2" />
</names>
<keys>

View file

@ -1,108 +0,0 @@
import 'mocha';
import { assert } from 'chai';
import { Key2Compiler } from '../src/compiler/key2.js';
import { compilerTestCallbacks, loadSectionFixture, testCompilationCases } from './helpers/index.js';
import { KMXPlus } from '@keymanapp/common-types';
import { constants } from '@keymanapp/ldml-keyboard-constants';
import Key2 = KMXPlus.Key2;
describe('key2', function () {
this.slow(500); // 0.5 sec -- json schema validation takes a while
it('should compile minimal keys data', function () {
let key2 = loadSectionFixture(Key2Compiler, 'sections/keys/minimal.xml', compilerTestCallbacks) as Key2;
assert.ok(key2);
assert.equal(compilerTestCallbacks.messages.length, 0);
assert.equal(key2.keys.length, 1);
assert.equal(key2.flicks.length, 1); // there's always a 'null' flick
assert.equal(key2.keys[0].to.value, '🪦');
assert.equal(key2.keys[0].id.value, 'grave');
});
it('should compile maximal key2 data', function () {
let key2 = loadSectionFixture(Key2Compiler, 'sections/key2/maximal.xml', compilerTestCallbacks) as Key2;
assert.ok(key2);
assert.equal(compilerTestCallbacks.messages.length, 0);
assert.equal(key2.keys.length, 4);
const [q] = key2.keys.filter(({ id }) => id.value === 'q');
assert.ok(q);
assert.isFalse(!!(q.flags & constants.key2_key_flags_gap));
assert.equal(q.width, 32, 'q\'s width'); // ceil(3.14159 * 10.0)
assert.equal(q.flicks, 'flick0'); // note this is a string, not a StrsItem
assert.equal(q.longPress.toString(), 'á é í');
assert.equal(q.longPressDefault.value, 'é');
assert.equal(q.multiTap.toString(), 'ä ë ï');
const [flick0] = key2.flicks.filter(({ id }) => id.value === 'flick0');
assert.ok(flick0);
assert.equal(flick0.flicks.length, 2);
const [flick0_nw_se] = flick0.flicks.filter(({ directions }) => directions && directions.isEqual('nw se'.split(' ')));
assert.ok(flick0_nw_se);
assert.equal(flick0_nw_se.to?.value, 'ç');
const [flick0_ne_sw] = flick0.flicks.filter(({ directions }) => directions && directions.isEqual('ne sw'.split(' ')));
assert.ok(flick0_ne_sw);
assert.equal(flick0_ne_sw.to?.value, 'ê');
});
it('should compile escaped key2 data', function () {
let key2 = loadSectionFixture(Key2Compiler, 'sections/key2/escaped.xml', compilerTestCallbacks) as Key2;
assert.ok(key2);
assert.equal(compilerTestCallbacks.messages.length, 0);
assert.equal(key2.keys.length, 4);
const [q] = key2.keys.filter(({ id }) => id.value === 'q');
assert.ok(q);
assert.isFalse(!!(q.flags & constants.key2_key_flags_gap));
assert.equal(q.width, 32); // ceil(3.1 * 10)
assert.equal(q.flicks, 'flick0'); // note this is a string, not a StrsItem
assert.equal(q.longPress.toString(), 'á é í');
assert.equal(q.longPressDefault.value, 'é');
assert.equal(q.multiTap.toString(), 'ä ë ï');
const [flick0] = key2.flicks.filter(({ id }) => id.value === 'flick0');
assert.ok(flick0);
assert.equal(flick0.flicks.length, 2);
const [flick0_nw_se] = flick0.flicks.filter(({ directions }) => directions && directions.isEqual('nw se'.split(' ')));
assert.ok(flick0_nw_se);
assert.equal(flick0_nw_se.to?.value, 'ç');
const [flick0_ne_sw] = flick0.flicks.filter(({ directions }) => directions && directions.isEqual('ne sw'.split(' ')));
assert.ok(flick0_ne_sw);
assert.equal(flick0_ne_sw.to?.value, 'ế');
});
it('should accept layouts with gap/switch keys', function () {
let key2 = loadSectionFixture(Key2Compiler, 'sections/keys/gap-switch.xml', compilerTestCallbacks) as Key2;
assert.ok(key2);
assert.equal(compilerTestCallbacks.messages.length, 0);
assert.equal(key2.keys.length, 4);
const [Qgap] = key2.keys.filter(({ id }) => id.value === 'Q');
assert.ok(Qgap);
assert.isTrue(!!(Qgap.flags & constants.key2_key_flags_gap), 'Q’s gap=');
const [Wshift] = key2.keys.filter(({ id }) => id.value === 'W');
assert.isNotNull(Wshift);
assert.isFalse(!!(Wshift.flags & constants.key2_key_flags_gap));
assert.equal(Wshift.switch.value, 'shift');
});
testCompilationCases(Key2Compiler, [
{
subpath: 'sections/key2/escaped2.xml',
callback: (key2, subpath, callbacks) => {
assert.isNotNull(key2);
assert.equal((<Key2>key2).keys.length, 1);
const [q] = (<Key2>key2).keys.filter(({ id }) => id.value === 'grave');
assert.equal(q.to.value, String.fromCodePoint(0x1faa6));
},
},
]);
});

View file

@ -1,31 +1,128 @@
import 'mocha';
import { assert } from 'chai';
import { Key2Compiler } from '../src/compiler/key2.js';
import { KeysCompiler } from '../src/compiler/keys.js';
import { compilerTestCallbacks, loadSectionFixture, testCompilationCases } from './helpers/index.js';
import { KMXPlus, Constants } from '@keymanapp/common-types';
import { CompilerMessages } from '../src/compiler/messages.js';
import { constants } from '@keymanapp/ldml-keyboard-constants';
import Keys = KMXPlus.Keys;
const K = Constants.USVirtualKeyCodes;
import Key2 = KMXPlus.Key2;
import { constants } from '@keymanapp/ldml-keyboard-constants';
describe('keys', function () {
this.slow(500); // 0.5 sec -- json schema validation takes a while
// Note: keeping the test cases, but they now apply to the subtable
describe('key2.kmap', function () {
it('should compile minimal keys data', function () {
let keys = loadSectionFixture(KeysCompiler, 'sections/keys/minimal.xml', compilerTestCallbacks) as Keys;
assert.ok(keys);
assert.equal(compilerTestCallbacks.messages.length, 0);
assert.equal(keys.keys.length, 1);
assert.equal(keys.flicks.length, 1); // there's always a 'null' flick
assert.equal(keys.keys[0].to.value, '🪦');
assert.equal(keys.keys[0].id.value, 'grave');
});
it('should compile maximal keys data', function () {
let keys = loadSectionFixture(KeysCompiler, 'sections/keys/maximal.xml', compilerTestCallbacks) as Keys;
assert.ok(keys);
assert.equal(compilerTestCallbacks.messages.length, 0);
assert.equal(keys.keys.length, 4);
const [q] = keys.keys.filter(({ id }) => id.value === 'q');
assert.ok(q);
assert.isFalse(!!(q.flags & constants.keys_key_flags_gap));
assert.equal(q.width, 32, 'q\'s width'); // ceil(3.14159 * 10.0)
assert.equal(q.flicks, 'flick0'); // note this is a string, not a StrsItem
assert.equal(q.longPress.toString(), 'á é í');
assert.equal(q.longPressDefault.value, 'é');
assert.equal(q.multiTap.toString(), 'ä ë ï');
const [flick0] = keys.flicks.filter(({ id }) => id.value === 'flick0');
assert.ok(flick0);
assert.equal(flick0.flicks.length, 2);
const [flick0_nw_se] = flick0.flicks.filter(({ directions }) => directions && directions.isEqual('nw se'.split(' ')));
assert.ok(flick0_nw_se);
assert.equal(flick0_nw_se.to?.value, 'ç');
const [flick0_ne_sw] = flick0.flicks.filter(({ directions }) => directions && directions.isEqual('ne sw'.split(' ')));
assert.ok(flick0_ne_sw);
assert.equal(flick0_ne_sw.to?.value, 'ê');
});
it('should compile escaped keys data', function () {
let keys = loadSectionFixture(KeysCompiler, 'sections/keys/escaped.xml', compilerTestCallbacks) as Keys;
assert.ok(keys);
assert.equal(compilerTestCallbacks.messages.length, 0);
assert.equal(keys.keys.length, 4);
const [q] = keys.keys.filter(({ id }) => id.value === 'q');
assert.ok(q);
assert.isFalse(!!(q.flags & constants.keys_key_flags_gap));
assert.equal(q.width, 32); // ceil(3.1 * 10)
assert.equal(q.flicks, 'flick0'); // note this is a string, not a StrsItem
assert.equal(q.longPress.toString(), 'á é í');
assert.equal(q.longPressDefault.value, 'é');
assert.equal(q.multiTap.toString(), 'ä ë ï');
const [flick0] = keys.flicks.filter(({ id }) => id.value === 'flick0');
assert.ok(flick0);
assert.equal(flick0.flicks.length, 2);
const [flick0_nw_se] = flick0.flicks.filter(({ directions }) => directions && directions.isEqual('nw se'.split(' ')));
assert.ok(flick0_nw_se);
assert.equal(flick0_nw_se.to?.value, 'ç');
const [flick0_ne_sw] = flick0.flicks.filter(({ directions }) => directions && directions.isEqual('ne sw'.split(' ')));
assert.ok(flick0_ne_sw);
assert.equal(flick0_ne_sw.to?.value, 'ế');
});
it('should accept layouts with gap/switch keys', function () {
let keys = loadSectionFixture(KeysCompiler, 'sections/keys/gap-switch.xml', compilerTestCallbacks) as Keys;
assert.ok(keys);
assert.equal(compilerTestCallbacks.messages.length, 0);
assert.equal(keys.keys.length, 4);
const [Qgap] = keys.keys.filter(({ id }) => id.value === 'Q');
assert.ok(Qgap);
assert.isTrue(!!(Qgap.flags & constants.keys_key_flags_gap), 'Q’s gap=');
const [Wshift] = keys.keys.filter(({ id }) => id.value === 'W');
assert.isNotNull(Wshift);
assert.isFalse(!!(Wshift.flags & constants.keys_key_flags_gap));
assert.equal(Wshift.switch.value, 'shift');
});
testCompilationCases(KeysCompiler, [
{
subpath: 'sections/keys/escaped2.xml',
callback: (keys, subpath, callbacks) => {
assert.isNotNull(keys);
assert.equal((<Keys>keys).keys.length, 1);
const [q] = (<Keys>keys).keys.filter(({ id }) => id.value === 'grave');
assert.equal(q.to.value, String.fromCodePoint(0x1faa6));
},
},
]);
});
describe('keys.kmap', function () {
this.slow(500); // 0.5 sec -- json schema validation takes a while
it('should compile minimal kmap data', function() {
let key2 = loadSectionFixture(Key2Compiler, 'sections/keys/minimal.xml', compilerTestCallbacks) as Key2;
assert.isNotNull(key2);
let keys = loadSectionFixture(KeysCompiler, 'sections/keys/minimal.xml', compilerTestCallbacks) as Keys;
assert.isNotNull(keys);
assert.equal(compilerTestCallbacks.messages.length, 0);
assert.equal(key2.kmap.length, 1);
assert.equal(keys.kmap.length, 1);
});
testCompilationCases(Key2Compiler, [
testCompilationCases(KeysCompiler, [
{
subpath: 'sections/keys/hardware.xml',
callback: (sect, subpath, callbacks) => {
const keys = sect as Key2;
const keys = sect as Keys;
assert.isNotNull(keys);
assert.equal(compilerTestCallbacks.messages.length, 0);
assert.equal(keys.keys.length, 4);
@ -56,7 +153,7 @@ describe('key2.kmap', function () {
{
subpath: 'sections/keys/hardware_us.xml',
callback: (sect, subpath, callbacks) => {
const keys = sect as Key2;
const keys = sect as Keys;
assert.isNotNull(keys);
assert.includeDeepMembers(keys.kmap, [
{
@ -80,7 +177,7 @@ describe('key2.kmap', function () {
{
subpath: 'sections/keys/hardware_iso.xml',
callback: (sect, subpath, callbacks) => {
const keys = sect as Key2;
const keys = sect as Keys;
assert.isNotNull(keys);
assert.includeDeepMembers(keys.kmap, [
{
@ -110,7 +207,7 @@ describe('key2.kmap', function () {
]);
it('should reject structurally invalid layers', function() {
let keys = loadSectionFixture(Key2Compiler, 'sections/keys/invalid-missing-layer.xml', compilerTestCallbacks) as Key2;
let keys = loadSectionFixture(KeysCompiler, 'sections/keys/invalid-missing-layer.xml', compilerTestCallbacks) as Keys;
assert.isNull(keys);
assert.equal(compilerTestCallbacks.messages.length, 1);
@ -118,7 +215,7 @@ describe('key2.kmap', function () {
});
it('should reject layouts with too many hardware rows', function() {
let keys = loadSectionFixture(Key2Compiler, 'sections/keys/invalid-hardware-too-many-rows.xml', compilerTestCallbacks) as Key2;
let keys = loadSectionFixture(KeysCompiler, 'sections/keys/invalid-hardware-too-many-rows.xml', compilerTestCallbacks) as Keys;
assert.isNull(keys);
assert.equal(compilerTestCallbacks.messages.length, 1);
@ -126,7 +223,7 @@ describe('key2.kmap', function () {
});
it('should reject layouts with too many hardware keys', function() {
let keys = loadSectionFixture(Key2Compiler, 'sections/keys/invalid-hardware-too-many-keys.xml', compilerTestCallbacks) as Key2;
let keys = loadSectionFixture(KeysCompiler, 'sections/keys/invalid-hardware-too-many-keys.xml', compilerTestCallbacks) as Keys;
assert.isNull(keys);
assert.equal(compilerTestCallbacks.messages.length, 1);
@ -134,20 +231,20 @@ describe('key2.kmap', function () {
});
it('should reject layouts with undefined keys', function() {
let keys = loadSectionFixture(Key2Compiler, 'sections/keys/invalid-undefined-key.xml', compilerTestCallbacks) as Key2;
let keys = loadSectionFixture(KeysCompiler, 'sections/keys/invalid-undefined-key.xml', compilerTestCallbacks) as Keys;
assert.isNull(keys);
assert.equal(compilerTestCallbacks.messages.length, 1);
assert.deepEqual(compilerTestCallbacks.messages[0], CompilerMessages.Error_KeyNotFoundInKeyBag({col: 1, form: 'hardware', keyId: 'foo', layer: 'base', row: 1}));
});
it('should reject layouts with invalid keys', function() {
let keys = loadSectionFixture(Key2Compiler, 'sections/keys/invalid-key-missing-attrs.xml', compilerTestCallbacks) as Key2;
let keys = loadSectionFixture(KeysCompiler, 'sections/keys/invalid-key-missing-attrs.xml', compilerTestCallbacks) as Keys;
assert.isNull(keys);
assert.equal(compilerTestCallbacks.messages.length, 1);
assert.deepEqual(compilerTestCallbacks.messages[0], CompilerMessages.Error_KeyMissingToGapOrSwitch({keyId: 'Q'}));
});
it('should accept layouts with gap/switch keys', function() {
let keys = loadSectionFixture(Key2Compiler, 'sections/keys/gap-switch.xml', compilerTestCallbacks) as Key2;
let keys = loadSectionFixture(KeysCompiler, 'sections/keys/gap-switch.xml', compilerTestCallbacks) as Keys;
assert.isNotNull(keys);
assert.equal(compilerTestCallbacks.messages.length, 0);
assert.equal(keys.keys.length, 4);

View file

@ -43,9 +43,9 @@ describe('layr', function () {
assert.equal(row0.keys[0]?.value, 'grave');
});
// reuse key2 maximal
it('should compile maximal key2 data', function () {
let layr = loadSectionFixture(LayrCompiler, 'sections/key2/maximal.xml', compilerTestCallbacks) as Layr;
// reuse keys maximal
it('should compile maximal keys data', function () {
let layr = loadSectionFixture(LayrCompiler, 'sections/keys/maximal.xml', compilerTestCallbacks) as Layr;
assert.ok(layr);
assert.equal(compilerTestCallbacks.messages.length, 0);