mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-15 12:07:42 +00:00
Merge pull request #7380 from keymanapp/feat/common/epic-ldml/7379-kvks-writer-for-ts
feat(common): kvks writer for TypeScript 🙀
This commit is contained in:
commit
7baa9f01cd
6 changed files with 199 additions and 30 deletions
|
|
@ -75,18 +75,27 @@
|
|||
"$ref": "#/definitions/kvk-layer"
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"$ref": "#/definitions/kvk-encoding-name"
|
||||
},
|
||||
"fontname": {
|
||||
"type": "string"
|
||||
},
|
||||
"fontsize": {
|
||||
"type": "string"
|
||||
"$": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"$ref": "#/definitions/kvk-encoding-name"
|
||||
},
|
||||
"fontname": {
|
||||
"type": "string"
|
||||
},
|
||||
"fontsize": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
"$"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
|
@ -99,12 +108,21 @@
|
|||
"$ref": "#/definitions/kvk-key"
|
||||
}
|
||||
},
|
||||
"shift": {
|
||||
"$ref": "#/definitions/kvk-layer-shift"
|
||||
"$": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"shift": {
|
||||
"$ref": "#/definitions/kvk-layer-shift"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"shift"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"shift"
|
||||
"$"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
|
@ -114,15 +132,24 @@
|
|||
"bitmap": {
|
||||
"type": "string"
|
||||
},
|
||||
"vkey": {
|
||||
"type": "string"
|
||||
"$": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"vkey": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"vkey"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"_": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"vkey"
|
||||
"$"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export default class KVKSFileReader {
|
|||
|
||||
const parser = new xml2js.Parser({
|
||||
explicitArray: false,
|
||||
mergeAttrs: true,
|
||||
mergeAttrs: false,
|
||||
includeWhiteChars: true,
|
||||
normalize: false,
|
||||
emptyTag: {} as any
|
||||
|
|
@ -81,7 +81,8 @@ export default class KVKSFileReader {
|
|||
flags: 0,
|
||||
ansiFont: { name: "Arial", size: -12, color: 0xFF000008 }, // TODO-LDML: consider defaults
|
||||
unicodeFont: { name: "Arial", size: -12, color: 0xFF000008 }, // TODO-LDML: consider defaults
|
||||
associatedKeyboard: source.visualkeyboard?.header?.kbdname
|
||||
associatedKeyboard: source.visualkeyboard?.header?.kbdname,
|
||||
underlyingLayout: source.visualkeyboard?.header?.layout,
|
||||
},
|
||||
keys: []
|
||||
};
|
||||
|
|
@ -100,19 +101,19 @@ export default class KVKSFileReader {
|
|||
}
|
||||
|
||||
for(let encoding of source.visualkeyboard.encoding) {
|
||||
let isUnicode = (encoding.name == 'unicode'),
|
||||
let isUnicode = (encoding.$?.name == 'unicode'),
|
||||
font = isUnicode ? result.header.unicodeFont : result.header.ansiFont;
|
||||
font.name = encoding.fontname;
|
||||
font.size = parseInt(encoding.fontsize,10);
|
||||
font.name = encoding.$?.fontname;
|
||||
font.size = parseInt(encoding.$?.fontsize,10);
|
||||
for(let layer of encoding.layer) {
|
||||
let shift = this.kvksShiftToKvkShift(layer.shift);
|
||||
let shift = this.kvksShiftToKvkShift(layer.$?.shift);
|
||||
for(let sourceKey of layer.key) {
|
||||
let vkey = (USVirtualKeyCodes as any)[sourceKey.vkey];
|
||||
let vkey = (USVirtualKeyCodes as any)[sourceKey.$?.vkey];
|
||||
if(!vkey) {
|
||||
if(errors) {
|
||||
let e = new KVKSParseError();
|
||||
e.type = KVKSParseErrorType.invalidVkey;
|
||||
e.vkey = sourceKey.vkey;
|
||||
e.vkey = sourceKey.$?.vkey;
|
||||
errors.push(e);
|
||||
}
|
||||
continue;
|
||||
|
|
|
|||
113
common/web/types/src/kvk/kvks-file-writer.ts
Normal file
113
common/web/types/src/kvk/kvks-file-writer.ts
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
import * as xml2js from 'xml2js';
|
||||
import KVKSourceFile, { KVKSEncoding, KVKSFlags, KVKSKey, KVKSLayer } from './kvks-file.js';
|
||||
import { VisualKeyboard, VisualKeyboardHeaderFlags, VisualKeyboardKeyFlags, VisualKeyboardLegalShiftStates, VisualKeyboardShiftState } from './visual-keyboard.js';
|
||||
import { USVirtualKeyCodes } from '../consts/virtual-key-constants.js';
|
||||
|
||||
export default class KVKSFileWriter {
|
||||
public write(vk: VisualKeyboard): string {
|
||||
|
||||
const builder = new xml2js.Builder({
|
||||
allowSurrogateChars: true,
|
||||
attrkey: '$',
|
||||
charkey: '_',
|
||||
xmldec: {
|
||||
version: '1.0',
|
||||
encoding: 'UTF-8',
|
||||
standalone: true
|
||||
}
|
||||
})
|
||||
|
||||
let flags: KVKSFlags = {};
|
||||
if(vk.header.flags & VisualKeyboardHeaderFlags.kvkhDisplayUnderlying) {
|
||||
flags.displayunderlying = '';
|
||||
}
|
||||
if(vk.header.flags & VisualKeyboardHeaderFlags.kvkh102) {
|
||||
flags.key102 = '';
|
||||
}
|
||||
if(vk.header.flags & VisualKeyboardHeaderFlags.kvkhAltGr) {
|
||||
flags.usealtgr = '';
|
||||
}
|
||||
if(vk.header.flags & VisualKeyboardHeaderFlags.kvkhUseUnderlying) {
|
||||
flags.useunderlying = '';
|
||||
}
|
||||
|
||||
|
||||
|
||||
let kvks: KVKSourceFile = {
|
||||
visualkeyboard: {
|
||||
header: {
|
||||
version: '10.0',
|
||||
kbdname: vk.header.associatedKeyboard,
|
||||
flags: flags,
|
||||
},
|
||||
encoding: []
|
||||
}
|
||||
};
|
||||
|
||||
if(vk.header.underlyingLayout) kvks.visualkeyboard.header.layout = vk.header.underlyingLayout;
|
||||
|
||||
let encodings: {ansi: {o: KVKSEncoding, l: {[name:string]:KVKSLayer}}, unicode: {o: KVKSEncoding, l: {[name:string]:KVKSLayer}}} = {ansi:null,unicode:null};
|
||||
|
||||
for(let key of vk.keys) {
|
||||
const encoding = key.flags & VisualKeyboardKeyFlags.kvkkUnicode ? 'unicode' : 'ansi';
|
||||
const shift = this.kvkShiftToKvksShift(key.shift);
|
||||
|
||||
if(!encodings[encoding]) {
|
||||
encodings[encoding] = {
|
||||
o: {
|
||||
layer: [],
|
||||
$: {name: encoding,
|
||||
fontname: encoding == 'ansi' ? vk.header.ansiFont.name : vk.header.unicodeFont.name,
|
||||
fontsize: (encoding == 'ansi' ? vk.header.ansiFont.size : vk.header.unicodeFont.size).toString(),
|
||||
},
|
||||
},
|
||||
l: {}
|
||||
};
|
||||
kvks.visualkeyboard.encoding.push(encodings[encoding].o);
|
||||
}
|
||||
let e = encodings[encoding];
|
||||
if(!e.l[shift]) {
|
||||
e.l[shift] = {
|
||||
key: [],
|
||||
$: {shift: shift},
|
||||
};
|
||||
e.o.layer.push(e.l[shift]);
|
||||
}
|
||||
let l = e.l[shift];
|
||||
|
||||
// TODO-LDML: map
|
||||
let vkeyName = '';
|
||||
for(let vkey of Object.keys(USVirtualKeyCodes)) {
|
||||
if((USVirtualKeyCodes as any)[vkey] == key.vkey) {
|
||||
vkeyName = vkey;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(vkeyName == '') {
|
||||
//TODO-LDML: warn
|
||||
continue;
|
||||
}
|
||||
let k: KVKSKey = {
|
||||
$: {vkey: vkeyName},
|
||||
_: key.text,
|
||||
}
|
||||
|
||||
l.key.push(k);
|
||||
}
|
||||
|
||||
// console.dir(kvks, {depth:8});
|
||||
let result = builder.buildObject(kvks);
|
||||
return result; //Uint8Array.from(result);
|
||||
}
|
||||
|
||||
public kvkShiftToKvksShift(shift: VisualKeyboardShiftState): string {
|
||||
// TODO-LDML(lowpri): make a map of this?
|
||||
for(let state of VisualKeyboardLegalShiftStates) {
|
||||
if(state.shift == shift) {
|
||||
return state.name;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,6 @@ export interface KVKSHeader {
|
|||
version?: string;
|
||||
kbdname?: string;
|
||||
flags?: KVKSFlags;
|
||||
keybitmap?: string;
|
||||
layout?: string;
|
||||
};
|
||||
|
||||
|
|
@ -29,19 +28,25 @@ export interface KVKSFlags {
|
|||
};
|
||||
|
||||
export interface KVKSEncoding {
|
||||
name?: string;
|
||||
fontname?: string;
|
||||
fontsize?: string;
|
||||
$?: {
|
||||
name?: string;
|
||||
fontname?: string;
|
||||
fontsize?: string;
|
||||
};
|
||||
layer?: KVKSLayer[];
|
||||
};
|
||||
|
||||
export interface KVKSLayer {
|
||||
shift?: string;
|
||||
$?: {
|
||||
shift?: string;
|
||||
};
|
||||
key?: KVKSKey[];
|
||||
};
|
||||
|
||||
export interface KVKSKey {
|
||||
vkey?: string;
|
||||
$?: {
|
||||
vkey?: string;
|
||||
}
|
||||
bitmap?: string;
|
||||
_?: string;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ export class VisualKeyboardHeader {
|
|||
associatedKeyboard?: string;
|
||||
ansiFont: VisualKeyboardFont; // generally unused
|
||||
unicodeFont: VisualKeyboardFont;
|
||||
underlyingLayout?: string;
|
||||
};
|
||||
|
||||
export class VisualKeyboardFont {
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@ import * as fs from 'fs';
|
|||
import 'mocha';
|
||||
import { loadKvksJsonSchema, makePathToFixture } from '../helpers/index.js';
|
||||
import KvksFileReader, { KVKSParseError } from "../../src/kvk/kvks-file-reader.js";
|
||||
import KvksFileWriter from "../../src/kvk/kvks-file-writer.js";
|
||||
import { verify_khmer_angkor } from './test-kvk-utils.js';
|
||||
import { assert } from 'chai';
|
||||
|
||||
describe('kvks-file-reader', function() {
|
||||
it('kvks-file-reader should read a valid file', function() {
|
||||
it('should read a valid file', function() {
|
||||
const path = makePathToFixture('kvk', 'khmer_angkor.kvks');
|
||||
const input = fs.readFileSync(path);
|
||||
|
||||
|
|
@ -21,3 +22,24 @@ describe('kvks-file-reader', function() {
|
|||
verify_khmer_angkor(vk);
|
||||
});
|
||||
});
|
||||
|
||||
describe('kvks-file-writer', function() {
|
||||
it('should write a valid file', function() {
|
||||
const path = makePathToFixture('kvk', 'khmer_angkor.kvks');
|
||||
const input = fs.readFileSync(path);
|
||||
|
||||
const reader = new KvksFileReader();
|
||||
const kvksExpected = reader.read(input);
|
||||
const errors: KVKSParseError[] = [];
|
||||
const vk = reader.transform(kvksExpected, errors);
|
||||
assert.isEmpty(errors);
|
||||
|
||||
const writer = new KvksFileWriter();
|
||||
const output = writer.write(vk);
|
||||
|
||||
// We compare the (re)loaded data, because there may be
|
||||
// minor, irrelevant formatting differences in the emitted xml
|
||||
const kvks = reader.read(Buffer.from(output, 'utf8'));
|
||||
assert.deepEqual(kvks, kvksExpected);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue