Skip to content

Commit

Permalink
feat(common): scancode - move vkey map generation into KeysCompiler 🙀
Browse files Browse the repository at this point in the history
- also fix visual keyboard compiler to use same code

For: #9403
  • Loading branch information
srl295 committed Sep 30, 2023
1 parent 64eaf39 commit ffe00c0
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 178 deletions.
3 changes: 2 additions & 1 deletion common/web/types/src/kvk/kvk-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export interface BUILDER_KVK_KEY {
export const BUILDER_KVK_KEY_Size = 9; // size of fixed elements of BUILDER_KVK_KEY

export const enum BUILDER_KVK_HEADER_FLAGS {
kvkhNone = 0x00, // no flags
kvkh102 = 0x01,
kvkhDisplayUnderlying = 0x02,
kvkhUseUnderlying = 0x04,
Expand Down Expand Up @@ -122,4 +123,4 @@ export default class KVKFile {
});

}
};
};
168 changes: 0 additions & 168 deletions common/web/types/test/ldml-keyboard/test-ldml-keyboard-xml-reader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import 'mocha';
import {assert} from 'chai';
import { CommonTypesMessages } from '../../src/util/common-events.js';
import { testReaderCases } from '../helpers/reader-callback-test.js';
import { KeyMap, USVirtualKeyCodes } from '../../src/consts/virtual-key-constants.js';
import fs from 'node:fs';

function pluckKeysFromKeybag(keys: LKKey[], ids: string[]) {
return keys.filter(({id}) => ids.indexOf(id) !== -1);
Expand Down Expand Up @@ -143,169 +141,3 @@ describe('ldml keyboard xml reader tests', function () {
},
]);
});

describe('verify scancodes', function () {
// TODO-LDML: Temporarily, the old maps are here to double check round trips.
const k = USVirtualKeyCodes;

const USVirtualKeyMap: KeyMap = [
// ` 1 2 3 4 5 6 7 8 9 0 - = [bksp]
[ k.K_BKQUOTE, k.K_1, k.K_2, k.K_3, k.K_4, k.K_5, k.K_6, k.K_7, k.K_8, k.K_9, k.K_0, k.K_HYPHEN, k.K_EQUAL ],
// [tab] Q W E R T Y U I O P [ ] \
[ k.K_Q, k.K_W, k.K_E, k.K_R, k.K_T, k.K_Y, k.K_U, k.K_I, k.K_O, k.K_P, k.K_LBRKT, k.K_RBRKT, k.K_BKSLASH ],
// [caps] A S D F G H J K L ; ' [enter]
[ k.K_A, k.K_S, k.K_D, k.K_F, k.K_G, k.K_H, k.K_J, k.K_K, k.K_L, k.K_COLON, k.K_QUOTE ],
// [shift] Z X C V B N M , . / [shift] *=oE2
[ k.K_Z, k.K_X, k.K_C, k.K_V, k.K_B, k.K_N, k.K_M, k.K_COMMA, k.K_PERIOD, k.K_SLASH ],
// space
[ k.K_SPACE ],
];

const KSVirtualKeyMap: KeyMap = [
// ` 1 2 3 4 5 6 7 8 9 0 - = YEN [bksp]
[ k.K_BKQUOTE, k.K_1, k.K_2, k.K_3, k.K_4, k.K_5, k.K_6, k.K_7, k.K_8, k.K_9, k.K_0, k.K_HYPHEN, k.K_EQUAL, k.K_BKSLASH /* YEN */ ],
// [tab] Q W E R T Y U I O P [ ] \
[ k.K_Q, k.K_W, k.K_E, k.K_R, k.K_T, k.K_Y, k.K_U, k.K_I, k.K_O, k.K_P, k.K_LBRKT, k.K_RBRKT ],
// [caps] A S D F G H J K L ; ' [enter]
[ k.K_A, k.K_S, k.K_D, k.K_F, k.K_G, k.K_H, k.K_J, k.K_K, k.K_L, k.K_COLON, k.K_QUOTE ],
// [shift] Z X C V B N M , . / [shift]
[ k.K_Z, k.K_X, k.K_C, k.K_V, k.K_B, k.K_N, k.K_M, k.K_COMMA, k.K_PERIOD, k.K_SLASH ],
// space
[ k.K_SPACE ],
];

const ISOVirtualKeyMap: KeyMap = [
// ` 1 2 3 4 5 6 7 8 9 0 - = [bksp]
[ k.K_BKQUOTE, k.K_1, k.K_2, k.K_3, k.K_4, k.K_5, k.K_6, k.K_7, k.K_8, k.K_9, k.K_0, k.K_HYPHEN, k.K_EQUAL ],
// [tab] Q W E R T Y U I O P [ ]
[ k.K_Q, k.K_W, k.K_E, k.K_R, k.K_T, k.K_Y, k.K_U, k.K_I, k.K_O, k.K_P, k.K_LBRKT, k.K_RBRKT ],
// [caps] A S D F G H J K L ; ' \ [enter]
[ k.K_A, k.K_S, k.K_D, k.K_F, k.K_G, k.K_H, k.K_J, k.K_K, k.K_L, k.K_COLON, k.K_QUOTE, k.K_BKSLASH ],
// [shift] * Z X C V B N M , . / [shift] *=oE2
[ k.K_oE2, k.K_Z, k.K_X, k.K_C, k.K_V, k.K_B, k.K_N, k.K_M, k.K_COMMA, k.K_PERIOD, k.K_SLASH ],
// space
[ k.K_SPACE ],
];

const JISVirtualKeyMap: KeyMap = [
// [Hankaku/Zenkaku] 1 2 3 4 5 6 7 8 9 0 - ^ ¥ [bksp]
[ k.K_BKQUOTE, k.K_1, k.K_2, k.K_3, k.K_4, k.K_5, k.K_6, k.K_7, k.K_8, k.K_9, k.K_0, k.K_HYPHEN, k.K_EQUAL, k.K_oE2 /* YEN */ ],
// [tab] Q W E R T Y U I O P @ [ [enter]
[ k.K_Q, k.K_W, k.K_E, k.K_R, k.K_T, k.K_Y, k.K_U, k.K_I, k.K_O, k.K_P, k.K_LBRKT, k.K_RBRKT ],
// [caps] A S D F G H J K L ; : ] [enter]
[ k.K_A, k.K_S, k.K_D, k.K_F, k.K_G, k.K_H, k.K_J, k.K_K, k.K_L, k.K_COLON, k.K_QUOTE, k.K_BKSLASH ],
// [shift] Z X C V B N M , . / _ [shift]
[ k.K_Z, k.K_X, k.K_C, k.K_V, k.K_B, k.K_N, k.K_M, k.K_COMMA, k.K_PERIOD, k.K_SLASH, k.k_oC1 /* ろ */ ],
// space
[ k.K_SPACE ],
];

const ABNT2VirtualKeyMap: KeyMap = [
// ' 1 2 3 4 5 6 7 8 9 0 - = [bksp]
[ k.K_BKQUOTE, k.K_1, k.K_2, k.K_3, k.K_4, k.K_5, k.K_6, k.K_7, k.K_8, k.K_9, k.K_0, k.K_HYPHEN, k.K_EQUAL ],
// [tab] Q W E R T Y U I O P ´ [
[ k.K_Q, k.K_W, k.K_E, k.K_R, k.K_T, k.K_Y, k.K_U, k.K_I, k.K_O, k.K_P, k.K_LBRKT, k.K_RBRKT ],
// [caps] A S D F G H J K L ç ~ ] [enter]
[ k.K_A, k.K_S, k.K_D, k.K_F, k.K_G, k.K_H, k.K_J, k.K_K, k.K_L, k.K_COLON, k.K_QUOTE, k.K_BKSLASH ],
// [shift] \ Z X C V B N M , . ; / [shift]
[ k.K_oE2, k.K_Z, k.K_X, k.K_C, k.K_V, k.K_B, k.K_N, k.K_M, k.K_COMMA, k.K_PERIOD, k.K_SLASH, k.k_oC1 /* ABNT2 */ ],
// space
[ k.K_SPACE ],
];

/**
* Map from a hardware constant to a keymap
* For the 'key' see constants.layr_list_hardware_map
*/
const HardwareToKeymap: Map<string, KeyMap> = new Map(
[
["us", USVirtualKeyMap],
["iso", ISOVirtualKeyMap],
["jis", JISVirtualKeyMap],
["abnt2", ABNT2VirtualKeyMap],
["ks", KSVirtualKeyMap],
]
);

this.slow(500); // 0.5 sec -- json schema validation takes a while

// for err, convert a vkey name to a number
function findVkeyName(n : Number) : string {
for (const [k, v] of Object.entries(USVirtualKeyCodes)) {
if (v === n) {
return k;
}
}
return n.toString(); // punt
}

testReaderCases([
{
// We've read this above, but we're going to test for scancodes here
subpath: 'import-minimal.xml',
callback: (data, source, subpath, callbacks) => {
assert.ok(source?.keyboard3?.forms?.form);

const ldmlFormIds = source?.keyboard3?.forms?.form.map(f => f.id);
const kmcFormIds = Array.from(HardwareToKeymap.keys()); // comes from static data above.

assert.sameDeepMembers(ldmlFormIds, kmcFormIds, "LDML and kmc form ids");

const scanToVkey = new Map<string,number>();

source?.keyboard3?.forms?.form.forEach((form) => {
const {id, scanCodes} = form;
const km = HardwareToKeymap.get(id);
assert.ok(km, `kmc's ${id}`);
const ldmlRowCounts = scanCodes.map(o => o.codes.split(" ").length);
const kmcRowCounts = km.map(o => o.length);
assert.deepEqual(ldmlRowCounts, kmcRowCounts, `ldml/kmc counts for form ${id}`);

// Now, at least check to see if we're being consistent.
const ldmlRows = scanCodes.map(o => o.codes.split(" "));
for (let r=0;r<ldmlRows.length;r++) {
const ldmlRow = ldmlRows[r];
const kmcRow = km[r];
for (let c=0;c<ldmlRow.length;c++) {
const scan = ldmlRow[c];
const vkey = kmcRow[c];
if(!scanToVkey.has(scan)) {
scanToVkey.set(scan, vkey);
} else {
const have = findVkeyName(vkey);
const want = findVkeyName(scanToVkey.get(scan));
assert.equal(have, want, `while on ${id} ${r}:${c} - differing vkey for ${scan}`);
}
}
}
});

class ScanToVkey {
scan: string;
vname: string;
vcode: number;
};

const outMap: ScanToVkey[] = [];
for (const [k, v] of scanToVkey.entries()) {
outMap.push({
scan: k,
vname: findVkeyName(v),
vcode: v,
});
}

const comp = new Intl.Collator(['und'], { numeric: true });
outMap.sort((a, b) => comp.compare(a.scan, b.scan));
fs.writeFileSync('build/test/ldml-keyboard/scancodes.json', JSON.stringify(outMap, null, ' '), 'utf-8');
fs.writeFileSync('build/test/ldml-keyboard/scancodes.ts',
`export const scanToVkey = {\n` +
outMap.map(o => ` 0x${o.scan}: k.${o.vname},`).join('\n') +
`\n};\n`,
'utf-8');


},
},
]);
});
25 changes: 21 additions & 4 deletions developer/src/kmc-ldml/src/compiler/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,25 @@ export class KeysCompiler extends SectionCompiler {
}
}

private getKeymapFromForm(hardware : string) : Constants.KeyMap {
return KeysCompiler.getKeymapFromForms(this.keyboard3?.forms.form, hardware);
}

public static getKeymapFromForms(forms: LDMLKeyboard.LKForm[], hardware: string): Constants.KeyMap {
const ldmlForm = forms.find((f) => f.id === hardware);
if (!ldmlForm) {
return undefined;
}
return KeysCompiler.getKeymapFromScancodes(ldmlForm);
}

public static getKeymapFromScancodes(ldmlForm: LDMLKeyboard.LKForm) {
const { scanCodes } = ldmlForm;
const ldmlScan = scanCodes.map(o => o.codes.split(" ").map(n => Number.parseInt(n, 16)));
const ldmlVkey = Constants.CLDRScanToKeyMap(ldmlScan);
return ldmlVkey;
}

/**
* TODO-LDML: from old 'keys'
* Validate for purpose of kmap
Expand All @@ -217,10 +236,8 @@ export class KeysCompiler extends SectionCompiler {
valid = false;
}

const keymap = Constants.HardwareToKeymap.get(hardware);
/* c8 ignore next 5 */
const keymap = this.getKeymapFromForm(hardware);
if (!keymap) {
// not reached due to XML validation
this.callbacks.reportMessage(
CompilerMessages.Error_InvalidHardware({ form: hardware })
);
Expand Down Expand Up @@ -287,7 +304,7 @@ export class KeysCompiler extends SectionCompiler {
hardware: string
): Keys {
const mod = translateLayerAttrToModifier(layer);
const keymap = Constants.HardwareToKeymap.get(hardware);
const keymap = this.getKeymapFromForm(hardware);

let y = -1;
for (let row of layer.row) {
Expand Down
19 changes: 14 additions & 5 deletions developer/src/kmc-ldml/src/compiler/visual-keyboard-compiler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Constants, VisualKeyboard, LDMLKeyboard } from "@keymanapp/common-types";
import { VisualKeyboard, LDMLKeyboard } from "@keymanapp/common-types";
import { KeysCompiler } from "./keys.js";

export class LdmlKeyboardVisualKeyboardCompiler {
public compile(source: LDMLKeyboard.LDMLKeyboardXMLSourceFile): VisualKeyboard.VisualKeyboard {
Expand All @@ -14,8 +15,9 @@ export class LdmlKeyboardVisualKeyboardCompiler {
result.header.unicodeFont = {...VisualKeyboard.DEFAULT_KVK_FONT};

for(let layers of source.keyboard3.layers) {
const hardware = layers.form;
for(let layer of layers.layer) {
this.compileHardwareLayer(source, result, layer);
this.compileHardwareLayer(source, result, layer, hardware);
}
}
return result;
Expand All @@ -24,9 +26,16 @@ export class LdmlKeyboardVisualKeyboardCompiler {
private compileHardwareLayer(
source: LDMLKeyboard.LDMLKeyboardXMLSourceFile,
vk: VisualKeyboard.VisualKeyboard,
layer: LDMLKeyboard.LKLayer
layer: LDMLKeyboard.LKLayer,
hardware: string,
) {
// TODO-LDML: consider consolidation with keys.ts?
if (hardware === 'touch') {
hardware = 'us'; // TODO-LDML: US Only. Do something different here?
}
const keymap = KeysCompiler.getKeymapFromForms(source.keyboard3?.forms?.form, hardware);
if (!keymap) {
throw Error(`Internal error: could not find keymap for form ${hardware}`);
}
const shift = this.translateLayerIdToVisualKeyboardShift(layer.id);

let y = -1;
Expand All @@ -48,7 +57,7 @@ export class LdmlKeyboardVisualKeyboardCompiler {
flags: VisualKeyboard.VisualKeyboardKeyFlags.kvkkUnicode,
shift: shift,
text: keydef.to, // TODO-LDML: displays
vkey: Constants.USVirtualKeyMap[y][x] // TODO-LDML: #7965 US-only
vkey: keymap[y][x],
});
}
}
Expand Down

0 comments on commit ffe00c0

Please sign in to comment.