feat(developer): add tests

This commit is contained in:
Sabine 2025-08-01 18:54:24 +02:00
parent 9cc6ecccee
commit f3d5cc4bd8
14 changed files with 923 additions and 778 deletions

View file

@ -13,7 +13,7 @@ import { util } from '@keymanapp/common-types';
import { ConverterMessages } from '../converter-messages.js';
import { SchemaValidators } from '@keymanapp/common-types';
import { DeveloperUtilsMessages } from '@keymanapp/developer-utils';
import { KeylayoutXMLSourceFile } from "@keymanapp/developer-utils"
import { KeylayoutXMLSourceFile } from "@keymanapp/developer-utils";
import boxXmlArray = util.boxXmlArray;
@ -73,27 +73,22 @@ export class KeylayoutFileReader {
this.remove_whitespace(source);
this.removeWhitespace_boxArray(source.layouts, 'layout');
this.removeWhitespace_boxArray(source, 'keyMapSet');
this.removeWhitespace_boxArray(source.layouts, 'layout');
this.removeWhitespace_boxArray(source?.modifierMap, 'keyMapSelect');
for (const keyMapSelect of source?.modifierMap?.keyMapSelect) {
this.removeWhitespace_boxArray(keyMapSelect, 'modifier');
}
// keyMapSet is the only top level tag that might occur several times => we need to consider 2 cases
if (!Array.isArray(source?.keyMapSet) === false) {
for (let i = 0; i < source?.keyMapSet.length; i++) {
for (const keyMap of source?.keyMapSet[i]?.keyMap) {
this.removeWhitespace_boxArray(keyMap, 'key');
}
this.removeWhitespace_boxArray(source.keyMapSet[i], 'keyMap');
}
} else {
for (const keyMap of source?.keyMapSet?.keyMap) {
this.removeWhitespace_boxArray(source.keyMapSet[0], 'keyMap');
for (const keyMapSet of source?.keyMapSet) {
for (const keyMap of keyMapSet.keyMap) {
this.removeWhitespace_boxArray(keyMap, 'key');
}
this.removeWhitespace_boxArray(source.keyMapSet, 'keyMap');
this.removeWhitespace_boxArray(source, 'keyMapSet');
this.removeWhitespace_boxArray(keyMapSet, 'keyMap');
}
this.removeWhitespace_boxArray(source?.actions, 'action');
@ -133,7 +128,7 @@ export class KeylayoutFileReader {
return jsonObj;
}
catch (err) {
this.callbacks.reportMessage(ConverterMessages.Error_FileNotFound({ inputFilename }));
this.callbacks.reportMessage(ConverterMessages.Error_UnableToRead({ inputFilename }));
return null;
}
}

View file

@ -48,10 +48,11 @@ export interface idStateOutput_object {
* @param data data read from keylayout file
* @return static variable USE_KEY_COUNT holding the number of keys used in a .keykayout file.
*/
export function find_usedKeysCount(data: any): number {
export function find_usedKeysCount(data: any, pos: number): number {
let USE_KEY_COUNT = KeylayoutToKmnConverter.MAX_KEY_COUNT;
for (let i = 0; i < data.keyboard.keyMapSet[0].keyMap.length; i++) {
if (data.keyboard.keyMapSet[0].keyMap[i].key.length < USE_KEY_COUNT) {
//if (data.keyboard.keyMapSet[0].keyMap[i].key.length < USE_KEY_COUNT) {
if ((i === pos) && (data.keyboard.keyMapSet[0].keyMap[i].key.length < USE_KEY_COUNT)) {
// set the max to n-1 (use key 0 -> nth-1)
USE_KEY_COUNT = data.keyboard.keyMapSet[0].keyMap[i].key.length - 1;
}
@ -164,9 +165,9 @@ export class KeylayoutToKmnConverter {
}
modifierBehavior.push(singleModifierSet);
}
const behav = 0;
// fix the amount of processable keys to the maximun nr of keys of a keyMap to avoid processing more keys than defined
KeylayoutToKmnConverter.USE_KEY_COUNT = find_usedKeysCount(jsonObj);
KeylayoutToKmnConverter.USE_KEY_COUNT = find_usedKeysCount(jsonObj, behav);
// fill rules into arrayOf_Rules of data_object
return this.createRuleData(data_object, jsonObj);
@ -191,30 +192,53 @@ export class KeylayoutToKmnConverter {
// check if we use CAPS in a modifier throughout the .keylayout file. In this case we need to add NCAPS
const isCapsused: boolean = this.checkIfCapsIsUsed(data_ukelele.arrayOf_Modifiers);
// if there are different amounts of keyMapSelect vs keyMap
if (jsonObj.keyboard.modifierMap?.keyMapSelect.length !== jsonObj.keyboard.keyMapSet[0].keyMap.length) {
const errorText = data_ukelele.keylayout_filename;
this.callbacks.reportMessage(ConverterMessages.Error_InvalidFile({ errorText }));
}
// loop keys 0-49 (= all keys we use)
for (let j = 0; j <= KeylayoutToKmnConverter.USE_KEY_COUNT; j++) {
//for (let j = 0; j <= KeylayoutToKmnConverter.MAX_KEY_COUNT; j++) {
for (let j = 0; j <= KeylayoutToKmnConverter.MAX_KEY_COUNT; j++) {
// loop behaviors (in ukelele it is possible to define multiple modifier combinations that behave in the same way)
for (let i = 0; i < jsonObj.keyboard.keyMapSet[0].keyMap.length; i++) {
const KeyIndex_j = j;
const BehavIndex_i = i;
const maxKey = jsonObj.keyboard.keyMapSet[0].keyMap[i].key.length;
const maxBeh = jsonObj.keyboard.keyMapSet[0].keyMap.length;
const isItAvailable = (((KeyIndex_j < maxKey) && (BehavIndex_i < maxBeh)));
if (!isItAvailable) {
continue;
}
let rule_obj: Rule;
//if (i < maxkey) {
if ((j < jsonObj.keyboard.keyMapSet[0].keyMap[i].key.length)) {
// ...............................................................................................................................
// case C0: output ...............................................................................................................
// C0 see: https://docs.google.com/document/d/12J3NGO6RxIthCpZDTR8FYSRjiMgXJDLwPY2z9xqKzJ0/edit?tab=t.0#heading=h.g7jwx3lx0ydd ...
// a key is mapped to a character directly ( code -> output) .....................................................................
// ...............e. g. <key code="1" output="s"/> ...............................................................................
// ...............................................................................................................................
//if (i < maxBeh) {
// if (i < jsonObj.keyboard.keyMapSet[0].keyMap.length) {
// ...............................................................................................................................
// case C0: output ...............................................................................................................
// C0 see: https://docs.google.com/document/d/12J3NGO6RxIthCpZDTR8FYSRjiMgXJDLwPY2z9xqKzJ0/edit?tab=t.0#heading=h.g7jwx3lx0ydd ...
// a key is mapped to a character directly ( code -> output) .....................................................................
// ...............e. g. <key code="1" output="s"/> ...............................................................................
// ...............................................................................................................................
if ((jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['@_output'] !== undefined)
&& (jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['@_output'] !== "")) {
if ((jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['@_output'] !== undefined)
&& (jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['@_output'] !== "")) {
// loop behaviours
for (let l = 0; l < data_ukelele.arrayOf_Modifiers[i].length; l++) {
if (this.map_UkeleleKC_To_VK(Number(jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['@_code']))) {
// loop modifiers
for (let l = 0; l < data_ukelele.arrayOf_Modifiers[i].length; l++) {
rule_obj = new Rule(
if (this.map_UkeleleKC_To_VK(Number(jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['@_code']))) {
rule_obj = new Rule(
/* rule_type */ "C0",
/* modifier_prev_deadkey*/ "",
@ -230,35 +254,36 @@ export class KeylayoutToKmnConverter {
/* modifier_key*/ this.create_kmn_modifier(data_ukelele.arrayOf_Modifiers[i][l], isCapsused),
/* key */ this.map_UkeleleKC_To_VK(Number(jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['@_code'])),
/* output */ new TextEncoder().encode(jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['@_output']),
);
object_array.push(rule_obj);
);
object_array.push(rule_obj);
}
}
// }
}
else if (jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['@_action'] !== undefined) {
}
else if (jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['@_action'] !== undefined) {
action_id = jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['@_action'];
// ...............................................................................................................................
// case C1: action + state none + output .........................................................................................
// C1 see: https://docs.google.com/document/d/12J3NGO6RxIthCpZDTR8FYSRjiMgXJDLwPY2z9xqKzJ0/edit?tab=t.0#heading=h.g7jwx3lx0ydd ...
// a key is mapped to an action and then to an output ............................................................................
// KeyMap:code -> KeyMap:action->action:action_state(none) -> action_output ......................................................
// ...............e. g. <when state="none" output="a" ............................................................................
// ...............................................................................................................................
action_id = jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['@_action'];
// ...............................................................................................................................
// case C1: action + state none + output .........................................................................................
// C1 see: https://docs.google.com/document/d/12J3NGO6RxIthCpZDTR8FYSRjiMgXJDLwPY2z9xqKzJ0/edit?tab=t.0#heading=h.g7jwx3lx0ydd ...
// a key is mapped to an action and then to an output ............................................................................
// KeyMap:code -> KeyMap:action->action:action_state(none) -> action_output ......................................................
// ...............e. g. <when state="none" output="a" ............................................................................
// ...............................................................................................................................
for (let l = 0; l < data_ukelele.arrayOf_Modifiers[i].length; l++) {
for (let l = 0; l < data_ukelele.arrayOf_Modifiers[i].length; l++) {
if ((this.get_Output__From__ActionId_None(jsonObj, action_id) !== undefined)
&& (this.get_Output__From__ActionId_None(jsonObj, action_id) !== "")) {
if ((this.get_Output__From__ActionId_None(jsonObj, action_id) !== undefined)
&& (this.get_Output__From__ActionId_None(jsonObj, action_id) !== "")) {
const outputchar: string = this.get_Output__From__ActionId_None(jsonObj, action_id);
const outputchar: string = this.get_Output__From__ActionId_None(jsonObj, action_id);
const b1_modifierKey_obj: allArrayContents_object[] =
this.get_ActionOutputBehaviourKeyModi_From__ActionIDStateOutput(jsonObj, data_ukelele.arrayOf_Modifiers, action_id, outputchar, isCapsused);
const b1_modifierKey_obj: allArrayContents_object[] =
this.get_ActionOutputBehaviourKeyModi_From__ActionIDStateOutput(jsonObj, data_ukelele.arrayOf_Modifiers, action_id, outputchar, isCapsused);
for (let m = 0; m < b1_modifierKey_obj.length; m++) {
rule_obj = new Rule(
for (let m = 0; m < b1_modifierKey_obj.length; m++) {
rule_obj = new Rule(
/* rule_type */ "C1",
/* modifier_prev_deadkey*/ "",
@ -274,29 +299,29 @@ export class KeylayoutToKmnConverter {
/* modifier_key*/ b1_modifierKey_obj[m].modifier,
/* key */ b1_modifierKey_obj[m].key,
/* output */ new TextEncoder().encode(outputchar)
);
if ((outputchar !== undefined) && (outputchar !== "undefined") && (outputchar !== "")) {
object_array.push(rule_obj);
);
if ((outputchar !== undefined) && (outputchar !== "undefined") && (outputchar !== "")) {
object_array.push(rule_obj);
}
}
}
}
// ...............................................................................................................................
// case C2: action + none + next .................................................................................................
// ...............e. g.<when state="none" next="20"/> ............................................................................
// replace state x with all rules that result in 14 (<when state="x" next="14") ..................................................
// ...............................................................................................................................
// Definition of C2 and Blocks 1-6 see ...........................................................................................
// https://docs.google.com/document/d/12J3NGO6RxIthCpZDTR8FYSRjiMgXJDLwPY2z9xqKzJ0/edit?tab=t.0#heading=h.g7jwx3lx0ydd .........
// ...............................................................................................................................
// ...............................................................................................................................
// case C2: action + none + next .................................................................................................
// ...............e. g.<when state="none" next="20"/> ............................................................................
// replace state x with all rules that result in 14 (<when state="x" next="14") ..................................................
// ...............................................................................................................................
// Definition of C2 and Blocks 1-6 see ...........................................................................................
// https://docs.google.com/document/d/12J3NGO6RxIthCpZDTR8FYSRjiMgXJDLwPY2z9xqKzJ0/edit?tab=t.0#heading=h.g7jwx3lx0ydd .........
// ...............................................................................................................................
const b1_actionIndex: number = this.get_ActionIndex__From__ActionId(jsonObj, action_id);
const b1_actionIndex: number = this.get_ActionIndex__From__ActionId(jsonObj, action_id);
// with action_id from above loop all 'action' and search for a state(none)-next-pair ............................................................................................................
// e.g. in Block 5: find <when state="none" next="1"/> for action id a18 ......................................................................................................................
for (let l = 0; l < jsonObj.keyboard.actions.action[b1_actionIndex].when.length; l++) {
if ((jsonObj.keyboard.actions.action[b1_actionIndex].when[l]['@_state'] === "none") // find "none"
&& (jsonObj.keyboard.actions.action[b1_actionIndex].when[l]['@_next'] !== undefined)) { // find "next"
// with action_id from above loop all 'action' and search for a state(none)-next-pair ............................................................................................................
// e.g. in Block 5: find <when state="none" next="1"/> for action id a18 ......................................................................................................................
for (let l = 0; l < jsonObj.keyboard.actions.action[b1_actionIndex].when.length; l++) {
if ((jsonObj.keyboard.actions.action[b1_actionIndex].when[l]['@_state'] === "none") // find "none"
&& (jsonObj.keyboard.actions.action[b1_actionIndex].when[l]['@_next'] !== undefined)) { // find "next"
// Data of Block Nr 5 .....................................................................................................................................................................
// of this state(none)-next-pair get value of next (next="1") .............................................................................................................................
@ -322,14 +347,14 @@ export class KeylayoutToKmnConverter {
// create array[Keycode,Keyname,action id,actionIndex,output] and array[Keyname,action id,behaviour,modifier,output] ......................................................................
/* eg: ['0','K_A','a9','0','â'] */ const b1_keycode_obj: allArrayContents_object[] = this.get_KeyActionOutput_array__From__ActionStateOutput_array(jsonObj, b6_actionId_obj);
/* eg: ['K_A','a9','0','NCAPS','â']*/ const b1_modifierKey_obj: allArrayContents_object[] = this.get_KeyMBehaviourModOutputArray__from__KeyActionBehaviourOutput_array(jsonObj, b1_keycode_obj, isCapsused);
// .......................................................................................................................................................................................
// .......................................................................................................................................................................................
for (let n1 = 0; n1 < b4_deadkeyModifier_obj.length; n1++) {
for (let n2 = 0; n2 < b4_deadkeyModifier_obj[n1].length; n2++) {
for (let n3 = 0; n3 < b4_deadkey_obj.length; n3++) {
for (let n4 = 0; n4 < b1_modifierKey_obj.length; n4++) {
for (let n1 = 0; n1 < b4_deadkeyModifier_obj.length; n1++) {
for (let n2 = 0; n2 < b4_deadkeyModifier_obj[n1].length; n2++) {
for (let n3 = 0; n3 < b4_deadkey_obj.length; n3++) {
for (let n4 = 0; n4 < b1_modifierKey_obj.length; n4++) {
rule_obj = new Rule(
rule_obj = new Rule(
/* rule_type */ "C2",
/* modifier_prev_deadkey*/ "",
@ -345,35 +370,35 @@ export class KeylayoutToKmnConverter {
/* modifier_key*/ b1_modifierKey_obj[n4].modifier,
/* key */ b1_modifierKey_obj[n4].key,
/* output */ new TextEncoder().encode(b1_modifierKey_obj[n4].outchar),
);
if ((b1_modifierKey_obj[n4].outchar !== undefined)
&& (b1_modifierKey_obj[n4].outchar !== "undefined")
&& (b1_modifierKey_obj[n4].outchar !== "")) {
object_array.push(rule_obj);
);
if ((b1_modifierKey_obj[n4].outchar !== undefined)
&& (b1_modifierKey_obj[n4].outchar !== "undefined")
&& (b1_modifierKey_obj[n4].outchar !== "")) {
object_array.push(rule_obj);
}
}
}
}
}
}
}
}
// ...............................................................................................................................
// case C3: action + state Nr + Next .............................................................................................
// ...............e. g.<when state="3" next="1"/> ................................................................................
// replace state x with all rules that result in 1 (<when state="x" next="1") ....................................................
// ...............................................................................................................................
// Definition of C3 and Blocks 1-6 see ...........................................................................................
// https://docs.google.com/document/d/12J3NGO6RxIthCpZDTR8FYSRjiMgXJDLwPY2z9xqKzJ0/edit?tab=t.0#heading=h.g7jwx3lx0ydd ..........
// ...............................................................................................................................
// ...............................................................................................................................
// case C3: action + state Nr + Next .............................................................................................
// ...............e. g.<when state="3" next="1"/> ................................................................................
// replace state x with all rules that result in 1 (<when state="x" next="1") ....................................................
// ...............................................................................................................................
// Definition of C3 and Blocks 1-6 see ...........................................................................................
// https://docs.google.com/document/d/12J3NGO6RxIthCpZDTR8FYSRjiMgXJDLwPY2z9xqKzJ0/edit?tab=t.0#heading=h.g7jwx3lx0ydd ..........
// ...............................................................................................................................
// loop all action-when and find state-next-pair
// loop all action-when and find state-next-pair
// with action_id from above loop all 'action' and search for a state-next-pair ...................................................................................................................
// e.g. in Block 5: find <when state="3" next="1"/> for action id a16 .............................................................................................................................
for (let l = 0; l < jsonObj.keyboard.actions.action[b1_actionIndex].when.length; l++) {
if ((jsonObj.keyboard.actions.action[b1_actionIndex].when[l]['@_state'] !== "none")
&& (jsonObj.keyboard.actions.action[b1_actionIndex].when[l]['@_next'] !== undefined)) {
// with action_id from above loop all 'action' and search for a state-next-pair ...................................................................................................................
// e.g. in Block 5: find <when state="3" next="1"/> for action id a16 .............................................................................................................................
for (let l = 0; l < jsonObj.keyboard.actions.action[b1_actionIndex].when.length; l++) {
if ((jsonObj.keyboard.actions.action[b1_actionIndex].when[l]['@_state'] !== "none")
&& (jsonObj.keyboard.actions.action[b1_actionIndex].when[l]['@_next'] !== undefined)) {
// Data of Block Nr 5 ........................................................................................................................................................................
// of this state-next-pair get value of next (next="1") and state="3" ........................................................................................................................
@ -408,17 +433,17 @@ export class KeylayoutToKmnConverter {
// create array[Keycode,Keyname,action id,actionIndex,output] and array[Keyname,action id,behaviour,modifier,output] .........................................................................
/* eg: ['49','K_SPACE','a0','0','Â'] */ const b1_keycode_obj: allArrayContents_object[] = this.get_KeyActionOutput_array__From__ActionStateOutput_array(jsonObj, b6_actionId_obj);
/* eg: ['K_SPACE','a0','0','NCAPS','Â'] */ const b1_modifierKey_obj: allArrayContents_object[] = this.get_KeyMBehaviourModOutputArray__from__KeyActionBehaviourOutput_array(jsonObj, b1_keycode_obj, isCapsused);
// ...........................................................................................................................................................................................
// ...........................................................................................................................................................................................
for (let n1 = 0; n1 < b2_prev_deadkeyModifier_obj.length; n1++) {
for (let n2 = 0; n2 < b2_prev_deadkeyModifier_obj[n1].length; n2++) {
for (let n3 = 0; n3 < b2_prev_deadkey_obj.length; n3++) {
for (let n4 = 0; n4 < b4_deadkeyModifier_obj.length; n4++) {
for (let n5 = 0; n5 < b4_deadkeyModifier_obj[n4].length; n5++) {
for (let n6 = 0; n6 < b4_deadkey_obj.length; n6++) {
for (let n7 = 0; n7 < b1_modifierKey_obj.length; n7++) {
for (let n1 = 0; n1 < b2_prev_deadkeyModifier_obj.length; n1++) {
for (let n2 = 0; n2 < b2_prev_deadkeyModifier_obj[n1].length; n2++) {
for (let n3 = 0; n3 < b2_prev_deadkey_obj.length; n3++) {
for (let n4 = 0; n4 < b4_deadkeyModifier_obj.length; n4++) {
for (let n5 = 0; n5 < b4_deadkeyModifier_obj[n4].length; n5++) {
for (let n6 = 0; n6 < b4_deadkey_obj.length; n6++) {
for (let n7 = 0; n7 < b1_modifierKey_obj.length; n7++) {
rule_obj = new Rule(
rule_obj = new Rule(
/* rule_type */ "C3",
/* modifier_prev_deadkey*/ this.create_kmn_modifier(b2_prev_deadkeyModifier_obj[n1][n2], isCapsused),
/* prev_deadkey */ this.map_UkeleleKC_To_VK(Number(b2_prev_deadkey_obj[n3].key)),
@ -433,11 +458,12 @@ export class KeylayoutToKmnConverter {
/* modifier_key*/ b1_modifierKey_obj[n7].modifier,
/* key */ b1_modifierKey_obj[n7].key,
/* output */ new TextEncoder().encode(b1_modifierKey_obj[n7].outchar),
);
if ((b1_modifierKey_obj[n7].outchar !== undefined)
&& (b1_modifierKey_obj[n7].outchar !== "undefined")
&& (b1_modifierKey_obj[n7].outchar !== "")) {
object_array.push(rule_obj);
);
if ((b1_modifierKey_obj[n7].outchar !== undefined)
&& (b1_modifierKey_obj[n7].outchar !== "undefined")
&& (b1_modifierKey_obj[n7].outchar !== "")) {
object_array.push(rule_obj);
}
}
}
}
@ -448,24 +474,24 @@ export class KeylayoutToKmnConverter {
}
}
}
} else {
/* QUESTION
// _S2 why does this not work here? Correct data in this.callback.messages is available !?!?!
this.callbacks.reportMessage(ConverterMessages.Error_UnsupportedCharactersDetected({
inputFilename: jsonObj.keyboard['@_name'] + ".keylayout",
keymap_index: jsonObj.keyboard.keyMapSet[0].keyMap[i]['@_index'],
output: jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['@_output'],
key: jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['@_code']
}));
return null;*/
console.log(" ERROR : some output characters can not be used in Keyman \"",
(jsonObj.keyboard['@_name'] + ".keylayout\""),
"\"<keyMap index=\"", jsonObj.keyboard.keyMapSet[0].keyMap[i]['@_index'], "\">\" :",
jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]);
continue;
}
} else {
/* QUESTION
// _S2 why does this not work here? Correct data in this.callback.messages is available !?!?!
this.callbacks.reportMessage(ConverterMessages.Error_UnsupportedCharactersDetected({
inputFilename: jsonObj.keyboard['@_name'] + ".keylayout",
keymap_index: jsonObj.keyboard.keyMapSet[0].keyMap[i]['@_index'],
output: jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['@_output'],
key: jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['@_code']
}));
return null;*/
console.log("ERROR : some output characters can not be used in Keyman \"",
(jsonObj.keyboard['@_name'] + ".keylayout\""),
"\"<keyMap index=\"", jsonObj.keyboard.keyMapSet[0].keyMap[i]['@_index'], "\">\" :",
jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]);
continue;
}
}
}
@ -495,7 +521,12 @@ export class KeylayoutToKmnConverter {
unique_dkB_count++;
for (let i = 0; i < object_array.length; i++) {
if ((object_array[i].modifier_deadkey !== "") && (object_array[i].deadkey !== "")) {
if (
((object_array[i].modifier_deadkey !== undefined) && (object_array[i].modifier_deadkey !== "")) &&
((object_array[i].deadkey !== undefined) && (object_array[i].deadkey !== ""))
) {
let isFirstUsedHere_dk: boolean = true;
// check if not used before
@ -1006,16 +1037,15 @@ export class KeylayoutToKmnConverter {
* @param search : string - an actionId to be found
* @return an array: allArrayContents_object[] containing [{keycode,behaviour}]
*/
// _S2 check if all array2d types ate deleted
// _S2 check if action/search is available in all get_ func
public get_KeyModifier_array__From__ActionID(data: any, search: string): allArrayContents_object[] {
const mapIndexArray_2D: number[][] = [];
let returnObject: allArrayContents_object;
const mapIndexObject1D: allArrayContents_object[] = [];
for (let i = 0; i < data.keyboard.keyMapSet[0].keyMap.length; i++) {
for (let j = 0; j <= KeylayoutToKmnConverter.USE_KEY_COUNT; j++) {
if (data.keyboard.keyMapSet[0].keyMap[i].key[j]['@_action'] === search) {
mapIndexArray_2D.push([data.keyboard.keyMapSet[0].keyMap[i].key[j]['@_code'], i]);
returnObject = {
key: data.keyboard.keyMapSet[0].keyMap[i].key[j]['@_code'],
behaviour: String(i),

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE keyboard SYSTEM "../../../../../resources/standards-data/Keylayout/Keylayout.dtd">
<!--
Data generated August 1st 2025
Generated by S. Schmitt
-->
<keyboard group="126" id="-1272" name="Test_C0" maxout="1">
<layouts>
<layout first="0" last="0" mapSet="138" modifiers="30"/>
</layouts>
<modifierMap id="30" defaultIndex="0">
<keyMapSelect mapIndex="0">
<modifier keys=""/>
</keyMapSelect>
<keyMapSelect mapIndex="1">
<modifier keys="caps"/>
</keyMapSelect>
</modifierMap>
<keyMapSet id="ANSI">
<keyMap index="0">
<key code="0" output="a"/>
</keyMap>
<keyMap index="1">
<key code="0" output="A"/>
</keyMap>
</keyMapSet>
<actions>
<action id="a0">
<when state="none" output="S"/>
</action>
<action id="a1">
<when state="none" output="s"/>
</action>
</actions>
<terminators>
<when state="1" output="ˆ"/>
</terminators>
</keyboard>

View file

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE keyboard SYSTEM "../../../../../resources/standards-data/Keylayout/Keylayout.dtd">
<!--
Data generated August 1st 2025
Generated by S. Schmitt
-->
<keyboard group="126" id="-1272" name="Test" maxout="1">
<layouts>
<layout first="0" last="0" mapSet="138" modifiers="30"/>
</layouts>
<modifierMap id="30" defaultIndex="0">
<keyMapSelect mapIndex="1">
<modifier keys="caps"/>
</keyMapSelect>
<keyMapSelect mapIndex="2">
<modifier keys="shift? leftShift caps? "/>
<modifier keys="anyShift caps?"/>
<modifier keys="shift leftShift caps "/>
<modifier keys="shift? rightShift caps? "/>
</keyMapSelect>
<keyMapSelect mapIndex="3">
<modifier keys="anyShift? anyOption caps? anyControl"/>
</keyMapSelect>
<keyMapSelect mapIndex="4">
<modifier keys="anyShift caps? anyOption ?"/>
</keyMapSelect>
<keyMapSelect mapIndex="5">
<modifier keys="anyOption"/>
</keyMapSelect>
<keyMapSelect mapIndex="6">
<modifier keys="caps anyOption ?"/>
</keyMapSelect>
</modifierMap>
<keyMapSet id="ANSI">
<keyMap index="1">
<key code="0" action="a0"/>
<key code="1" output="S"/>
<key code="24" output="ì"/>
<key code="28" output="8"/>
<key code="32" action="a4"/>
</keyMap>
<keyMap index="2">
<key code="0" action="a0"/>
<key code="1" output="ẞ"/>
<key code="24" output="^"/>
<key code="28" output="("/>
<key code="32" action="a4"/>
</keyMap>
<keyMap index="3">
<key code="0" output="U+1F600"/>
<key code="1" output="U+1F389"/>
<key code="24" output="="/>
<key code="27" output="&#x001F;"/>
<key code="32" output="&#x0015;"/>
</keyMap>
<keyMap index="4">
<key code="0" output="Å"/>
<key code="1" output="ሴ"/>
<key code="24" output="😎"/>
<key code="28" output="&#x1F601;"/>
<key code="32" output="&#4567;"/>
</keyMap>
<keyMap index="5">
<key code="0" output="å"/>
<key code="1" output="ß"/>
<key code="24" action="a3"/>
<key code="28" action="A_17"/>
<key code="32" action="A_16"/>
</keyMap>
<keyMap index="6">
<key code="0" output="Å"/>
<key code="1" output="ß"/>
<key code="24" output="ˆ"/>
<key code="28" output="´"/>
<key code="32" output="¨"/>
</keyMap>
</keyMapSet>
<actions>
<action id="a0">
<when state="none" output="A"/>
<when state="1" output="Â"/>
</action>
<action id="a1">
<when state="none" next="4"/>
<when state="3" next="1"/>
</action>
<action id="a2">
<when state="none" next="3"/>
</action>
<action id="a3">
<when state="none" next="1"/>
</action>
<action id="a4">
<when state="none" output="U"/>
<when state="1" output="Û"/>
</action>
</actions>
<terminators>
<when state="1" output="ˆ"/>
</terminators>
</keyboard>

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE keyboard SYSTEM "../../../../../resources/standards-data/Keylayout/Keylayout.dtd">
<!--
Data generated August 1st 2025
Generated by S. Schmitt
-->
<keyboard group="126" id="-1272" name="Test_C1" maxout="1">
<layouts>
<layout first="0" last="0" mapSet="138" modifiers="30"/>
</layouts>
<modifierMap id="30" defaultIndex="0">
<keyMapSelect mapIndex="0">
<modifier keys=""/>
</keyMapSelect>
<keyMapSelect mapIndex="1">
<modifier keys="caps"/>
</keyMapSelect>
</modifierMap>
<keyMapSet id="ANSI">
<keyMap index="0">
<key code="1" action="a1"/>
</keyMap>
<keyMap index="1">
<key code="1" action="a0"/>
</keyMap>
</keyMapSet>
<actions>
<action id="a0">
<when state="none" output="S"/>
</action>
<action id="a1">
<when state="none" output="s"/>
</action>
</actions>
<terminators>
<when state="1" output="ˆ"/>
</terminators>
</keyboard>

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE keyboard SYSTEM "../../../../../resources/standards-data/Keylayout/Keylayout.dtd">
<!--
Data generated August 1st 2025
Generated by S. Schmitt
-->
<keyboard group="126" id="-1272" name="Test" maxout="1">
<layouts>
<layout first="0" last="0" mapSet="138" modifiers="30"/>
</layouts>
<modifierMap id="30" defaultIndex="0">
<keyMapSelect mapIndex="0">
<modifier keys=""/>
</keyMapSelect>
<keyMapSelect mapIndex="1">
<modifier keys="shift"/>
</keyMapSelect>
</modifierMap>
<keyMapSet id="ANSI">
<keyMap index="0">
<key code="24" action="a1"/>
</keyMap>
<keyMap index="1">
<key code="0" action="a2"/>
</keyMap>
</keyMapSet>
<actions>
<action id="a1">
<when state="none" next="1"/>
</action>
<action id="a2">
<when state="1" output="Â"/>
</action>
</actions>
<terminators>
<when state="1" output="ˆ"/>
</terminators>
</keyboard>

View file

@ -0,0 +1,61 @@
<?xml version="1.1" encoding="UTF-8"?>
<!DOCTYPE keyboard SYSTEM "file://localhost/System/Library/DTDs/KeyboardLayout.dtd">
<!--
Data generated Fri Nov 1 02:29:44 2024
Generated by kluchrtoxml_64 build 203
-->
<!--Last edited by Ukelele version 396 on 2024-11-01 at 02:29 (CET)-->
<keyboard group="126" id="-1272" name="Test_C3" maxout="1">
<layouts>
<layout first="0" last="0" mapSet="138" modifiers="30"/>
</layouts>
<modifierMap id="30" defaultIndex="0">
<keyMapSelect mapIndex="0">
<modifier keys=""/>
</keyMapSelect>
<keyMapSelect mapIndex="2">
<modifier keys="caps"/>
</keyMapSelect>
<keyMapSelect mapIndex="3">
<modifier keys="anyOption"/>
</keyMapSelect>
</modifierMap>
<keyMapSet id="ANSI">
<keyMap index="0">
<key code="0" action="A6"/>
<key code="32" output="u"/>
</keyMap>
<keyMap index="2">
<key code="0" output="A"/>
<key code="32" action="A5"/>
</keyMap>
<keyMap index="3">
<key code="28" action="A4"/>
<key code="32" action="A3"/>
</keyMap>
</keyMapSet>
<actions>
<action id="A3">
<when state="3" next="1"/>
</action>
<action id="A4">
<when state="none" next="3"/>
</action>
<action id="A5">
<when state="none" next="3"/>
</action>
<action id="A6">
<when state="1" output="â"/>
</action>
</actions>
<terminators>
<when state="1" output="ˆ"/>
<when state="2" output="`"/>
<when state="3" output="´"/>
<when state="4" output="¨"/>
<when state="5" output="˜"/>
</terminators>
</keyboard>

View file

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE keyboard SYSTEM "../../../../../resources/standards-data/Keylayout/Keylayout.dtd">
<!--
Data generated August 1st 2025
Generated by S. Schmitt
Test_DifferentAmountMapSelect_KeyMapERROR
-->
<keyboard group="126" id="-1272" name="Test_DifferentAmountMapSelect_KeyMapERROR" maxout="1">
<layouts>
<layout first="0" last="0" mapSet="138" modifiers="30"/>
</layouts>
<!-- different amount of tags MapSelect(2) vs. KeyMap(3) -->
<modifierMap id="30" defaultIndex="0">
<keyMapSelect mapIndex="0">
<modifier keys=""/>
<modifier keys="shift? caps? "/>
</keyMapSelect>
<keyMapSelect mapIndex="1">
<modifier keys="caps"/>
</keyMapSelect>
<keyMapSelect mapIndex="2">
<modifier keys="shift"/>
</keyMapSelect>
</modifierMap>
<!-- different amount of tags MapSelect(2) vs. KeyMap(3) -->
<keyMapSet id="ANSI">
<keyMap index="0">
<key code="0" action="A_9"/>
<key code="1" output="s"/>
<key code="2" output="d"/>
<key code="3" output="f"/>
<key code="4" output="h"/>
<key code="9" output="v"/>
<key code="10" output="\"/>
</keyMap>
<keyMap index="1">
<key code="0" action="A_1"/>
<key code="1" output="S"/>
<key code="2" output="D"/>
<key code="3" output="F"/>
<key code="4" output="@"/>
<key code="5" output="G"/>
<key code="6" output="Z"/>
<key code="7" output="X"/>
<key code="8" output="C"/>
<key code="9" output="V"/>
<key code="10" output="\"/>
</keyMap>
</keyMapSet>
<actions>
<action id="A_1">
<when state="none" output="A"/>
<when state="1" output="Â"/>
<when state="2" output="À"/>
<when state="3" output="Á"/>
<when state="4" output="Ä"/>
<when state="5" output="Ã"/>
</action>
<action id="A_9">
<when state="none" output="A"/>
<when state="1" output="â"/>
<when state="2" output="à"/>
<when state="3" output="á"/>
<when state="4" output="ä"/>
<when state="5" output="ã"/>
</action>
</actions>
<terminators>
<when state="1" output="ˆ"/>
<when state="2" output="`"/>
<when state="3" output="´"/>
<when state="4" output="¨"/>
<when state="5" output="˜"/>
</terminators>
</keyboard>

View file

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE keyboard SYSTEM "../../../../../resources/standards-data/Keylayout/Keylayout.dtd">
<!--
Data generated August 1st 2025
Generated by S. Schmitt
tests different order of keys in keymap
tests missing keys in keymap
tests duplicate keys in keymap
-->
<keyboard group="126" id="-1272" name="Test" maxout="1">
<layouts>
<layout first="0" last="0" mapSet="138" modifiers="30"/>
</layouts>
<modifierMap id="30" defaultIndex="0">
<keyMapSelect mapIndex="0">
<modifier keys=""/>
</keyMapSelect>
<keyMapSelect mapIndex="1">
<modifier keys="caps"/>
</keyMapSelect>
</modifierMap>
<keyMapSet id="ANSI">
<keyMap index="0">
<key code="4" output="ሴ"/>
<key code="0" output="a"/>
<key code="3" output="@"/>
<key code="6" output="😎"/>
</keyMap>
<keyMap index="1">
<key code="2" output="&#2345;"/>
<key code="0" output=" "/>
<key code="2" output="&#2345;"/>
<key code="1" output="&#x1244;"/>
</keyMap>
</keyMapSet>
<actions>
<action id="A_0">
<when state="none" output=" "/>
</action>
</actions>
<terminators>
<when state="1" output="ˆ"/>
</terminators>
</keyboard>

View file

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE keyboard SYSTEM "../../../../../resources/standards-data/Keylayout/Keylayout.dtd">
<!--
Data generated August 1st 2025
Generated by S. Schmitt
-->
<keyboard group="126" id="-1272" name="Test" maxout="1">
<layouts>
<layout first="0" last="0" mapSet="138" modifiers="30"/>
</layouts>
<modifierMap id="30" defaultIndex="0">
<keyMapSelect mapIndex="0">
<modifier keys="shift"/>
</keyMapSelect>
<keyMapSelect mapIndex="1">
<modifier keys="caps"/>
</keyMapSelect>
<keyMapSelect mapIndex="2">
<modifier keys="control"/>
</keyMapSelect>
<keyMapSelect mapIndex="3">
<modifier keys="option"/>
</keyMapSelect>
<keyMapSelect mapIndex="4">
<modifier keys="caps control"/>
</keyMapSelect>
<keyMapSelect mapIndex="5">
<modifier keys="shift leftShift caps "/>
<modifier keys="shift leftShift caps option"/>
<modifier keys="shift option"/>
<modifier keys="caps option"/>
<modifier keys="shift option control"/>
</keyMapSelect>
<keyMapSelect mapIndex="6">
<modifier keys="WrongModifierName"/>
</keyMapSelect>
<keyMapSelect mapIndex="7">
<modifier keys="Ano therWr ongModi fierName"/>
</keyMapSelect>
</modifierMap>
<keyMapSet id="ANSI">
<keyMap index="0">
<key code="0" output="a"/>
<key code="1" output="s"/>
<key code="2" output="d"/>
<key code="3" output="f"/>
</keyMap>
<keyMap index="1">
<key code="0" output="A"/>
<key code="1" output="S"/>
<key code="2" output="D"/>
<key code="3" output="F"/>
</keyMap>
<keyMap index="2">
<key code="0" output="â"/>
<key code="1" output="ŝ"/>
<key code="2" output="ḏ"/>
<key code="3" output="ḟ"/>
</keyMap>
<keyMap index="3">
<key code="0" output="á"/>
<key code="1" output="ş"/>
<key code="2" output="ḍ"/>
<key code="3" output="ff"/>
</keyMap>
<keyMap index="4">
<key code="0" output="å"/>
<key code="1" output="š"/>
<key code="2" output="ḓ"/>
<key code="3" output="ⓕ"/>
</keyMap>
<keyMap index="5">
<key code="0" output="Å"/>
<key code="1" output="ṡ"/>
<key code="2" output="ḓ"/>
<key code="3" output="fl"/>
</keyMap>
<keyMap index="6">
<key code="0" output="Â"/>
<key code="1" output="ś"/>
<key code="2" output="ḓ"/>
<key code="3" output="ᶠ"/>
</keyMap>
<keyMap index="7">
<key code="0" output="Â"/>
<key code="1" output="ś"/>
<key code="2" output="ḓ"/>
<key code="3" output="🐟"/>
</keyMap>
</keyMapSet>
<actions>
<action id="a0">
<when state="none" output="D"/>
</action>
</actions>
<terminators>
<when state="1" output="ˆ"/>
</terminators>
</keyboard>

View file

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE keyboard SYSTEM "../../../../../resources/standards-data/Keylayout/Keylayout.dtd">
<!--
Data generated August 1st 2025
Generated by S. Schmitt
this is esentoiially the same as Test_modifier.keylayout with every CAPS removed which results in
skipping NCAPS in this case
creating ambiguous rules in some cases since removing caps creates a new shiftstate: shift + caps => shift
-->
<keyboard group="126" id="-1272" name="Test" maxout="1">
<layouts>
<layout first="0" last="0" mapSet="138" modifiers="30"/>
</layouts>
<modifierMap id="30" defaultIndex="0">
<keyMapSelect mapIndex="0">
<modifier keys="shift"/>
</keyMapSelect>
<keyMapSelect mapIndex="1">
<modifier keys=""/>
</keyMapSelect>
<keyMapSelect mapIndex="2">
<modifier keys="control"/>
</keyMapSelect>
<keyMapSelect mapIndex="3">
<modifier keys="option"/>
</keyMapSelect>
<keyMapSelect mapIndex="4">
<modifier keys=" control"/>
</keyMapSelect>
<keyMapSelect mapIndex="5">
<modifier keys="shift leftShift "/>
<modifier keys="shift leftShift option"/>
<modifier keys="shift option"/>
<modifier keys=" option"/>
<modifier keys="shift option control"/>
</keyMapSelect>
<keyMapSelect mapIndex="6">
<modifier keys="WrongModifierName"/>
</keyMapSelect>
<keyMapSelect mapIndex="7">
<modifier keys="Ano therWr ongModi fierName"/>
</keyMapSelect>
</modifierMap>
<keyMapSet id="ANSI">
<keyMap index="0">
<key code="0" output="a"/>
<key code="1" output="s"/>
<key code="2" output="d"/>
<key code="3" output="f"/>
</keyMap>
<keyMap index="1">
<key code="0" output="A"/>
<key code="1" output="S"/>
<key code="2" output="D"/>
<key code="3" output="F"/>
</keyMap>
<keyMap index="2">
<key code="0" output="â"/>
<key code="1" output="ŝ"/>
<key code="2" output="ḏ"/>
<key code="3" output="ḟ"/>
</keyMap>
<keyMap index="3">
<key code="0" output="á"/>
<key code="1" output="ş"/>
<key code="2" output="ḍ"/>
<key code="3" output="ff"/>
</keyMap>
<keyMap index="4">
<key code="0" output="å"/>
<key code="1" output="š"/>
<key code="2" output="ḓ"/>
<key code="3" output="ⓕ"/>
</keyMap>
<keyMap index="5">
<key code="0" output="Å"/>
<key code="1" output="ṡ"/>
<key code="2" output="ḓ"/>
<key code="3" output="fl"/>
</keyMap>
<keyMap index="6">
<key code="0" output="Â"/>
<key code="1" output="ś"/>
<key code="2" output="ḓ"/>
<key code="3" output="ᶠ"/>
</keyMap>
<keyMap index="7">
<key code="0" output="Â"/>
<key code="1" output="ś"/>
<key code="2" output="ḓ"/>
<key code="3" output="🐟"/>
</keyMap>
</keyMapSet>
<actions>
<action id="a0">
<when state="none" output="D"/>
</action>
</actions>
<terminators>
<when state="1" output="ˆ"/>
</terminators>
</keyboard>

View file

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE keyboard SYSTEM "../../../../../resources/standards-data/Keylayout/Keylayout.dtd">
<!--
Data generated August 1st 2025
Generated by S. Schmitt
if keymaps have different amount of keys derfined -> should print all ( here 2+4 rules)
-->
<keyboard group="126" id="-1272" name="Test_nr_elements" maxout="1">
<layouts>
<layout first="0" last="0" mapSet="138" modifiers="30"/>
</layouts>
<modifierMap id="30" defaultIndex="0">
<keyMapSelect mapIndex="0">
<modifier keys=""/>
</keyMapSelect>
<keyMapSelect mapIndex="1">
<modifier keys="caps"/>
</keyMapSelect>
</modifierMap>
<keyMapSet id="ANSI">
<keyMap index="0">
<key code="0" output="a"/>
<key code="1" output="s"/>
</keyMap>
<keyMap index="1">
<key code="0" output="A"/>
<key code="1" output="S"/>
<key code="2" output="D"/>
<key code="3" output="F"/>
</keyMap>
</keyMapSet>
<actions>
<action id="A_0">
<when state="none" output=" "/>
</action>
</actions>
<terminators>
<when state="1" output="ˆ"/>
</terminators>
</keyboard>

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE keyboard SYSTEM "../../../../../resources/standards-data/Keylayout/Keylayout.dtd">
<!--
Data generated August 1st 2025
Generated by S. Schmitt
-->
<keyboard group="126" id="-1272" name="Test" maxout="1">
<layouts>
<layout first="0" last="0" mapSet="138" modifiers="30"/>
</layouts>
<modifierMap id="30" defaultIndex="0">
<keyMapSelect mapIndex="0">
<modifier keys=""/>
</keyMapSelect>
</modifierMap>
<keyMapSet id="ANSI">
<keyMap index="0">
<key code="0" output="a"/>
<key code="1" output=""/>
<key code="2" output="ä"/>
<key code="3" output="@"/>
<key code="4" output="ሴ"/>
<key code="5" output="😎"/>
</keyMap>
</keyMapSet>
<actions>
<action id="A_0">
<when state="none" output=" "/>
<when state="1" output="ˆ"/>
<when state="2" output="`"/>
<when state="3" output="´"/>
<when state="4" output="¨"/>
<when state="5" output="˜"/>
</action>
</actions>
<terminators>
<when state="1" output="ˆ"/>
</terminators>
</keyboard>

View file

@ -10,10 +10,8 @@
import 'mocha';
import { assert } from 'chai';
import { compilerTestCallbacks, compilerTestOptions, makePathToFixture } from './helpers/index.js';
import { idStateOutput_object, allArrayContents_object, KeylayoutToKmnConverter } from '../src/keylayout-to-kmn/keylayout-to-kmn-converter.js';
import { KeylayoutFileReader } from '../src/keylayout-to-kmn/keylayout-file-reader.js';
import { ConverterMessages } from '../src/converter-messages.js';
import * as NodeAssert from 'node:assert';
import { KeylayoutToKmnConverter } from '../src/keylayout-to-kmn/keylayout-to-kmn-converter.js';
describe('KeylayoutToKmnConverter', function () {
@ -21,665 +19,75 @@ describe('KeylayoutToKmnConverter', function () {
compilerTestCallbacks.clear();
});
describe('run() ', function () {
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
it('run() should throw on null input file name and null output file name', async function () {
// note, could use 'chai as promised' library to make this more fluent:
const result = sut.run(null, null);
assert.isNotNull(result);
assert.equal(compilerTestCallbacks.messages.length, 1);
assert.deepEqual(compilerTestCallbacks.messages[0], ConverterMessages.Error_FileNotFound({ inputFilename: null }));
});
it('run() should throw on null input file name and empty output file name', async function () {
const result = sut.run(null, '');
assert.isNotNull(result);
assert.equal(compilerTestCallbacks.messages.length, 1);
assert.deepEqual(compilerTestCallbacks.messages[0], ConverterMessages.Error_FileNotFound({ inputFilename: null }));
});
it('run() should throw on null input file name and unknown output file name', async function () {
const result = sut.run(null, 'X');
assert.isNotNull(result);
assert.equal(compilerTestCallbacks.messages.length, 1);
assert.deepEqual(compilerTestCallbacks.messages[0], ConverterMessages.Error_FileNotFound({ inputFilename: null }));
});
it('run() should throw on unavailable input file name and null output file name', async function () {
const inputFilename = makePathToFixture('../data/Unavailable.keylayout');
const result = sut.run(inputFilename, null);
assert.isNotNull(result);
assert.equal(compilerTestCallbacks.messages.length, 1);
assert.deepEqual(compilerTestCallbacks.messages[0], ConverterMessages.Error_OutputFilenameIsRequired());
});
it('run() should throw on and null output file name', async function () {
const inputFilename = makePathToFixture('../data/Test.keylayout');
const result = sut.run(inputFilename, null);
assert.isNotNull(result);
assert.equal(compilerTestCallbacks.messages.length, 1);
assert.deepEqual(compilerTestCallbacks.messages[0], ConverterMessages.Error_OutputFilenameIsRequired());
});
it('run() should return on correct input file name and empty output file name ', async function () {
const inputFilename = makePathToFixture('../data/Test.keylayout');
await NodeAssert.doesNotReject(async () => sut.run(inputFilename, ''));
});
it('run() should return on correct input file name and null output file name', async function () {
const inputFilename = makePathToFixture('../data/Test.keylayout');
await NodeAssert.doesNotReject(async () => sut.run(inputFilename, null));
});
it('run() should return on correct input file name and given output file name ', async function () {
const inputFilename = makePathToFixture('../data/Test.keylayout');
const outputFilename = makePathToFixture('../data/OutputName.kmn');
await NodeAssert.doesNotReject(async () => sut.run(inputFilename, outputFilename));
});
it('run() should throw on incorrect input file extention and output file extention', async function () {
const inputFilename = makePathToFixture('../data/Test_command.A');
const outputFilename = makePathToFixture('../data/data/OutputXName.B');
const result = sut.run(inputFilename, outputFilename);
assert.isNotNull(result);
assert.equal(compilerTestCallbacks.messages.length, 2);
assert.deepEqual(compilerTestCallbacks.messages[0], ConverterMessages.Error_FileNotFound({ inputFilename: inputFilename }));
});
it('run() return on correct input file extention and unsupperted output file extention', async function () {
const inputFilename = makePathToFixture('../data/Test.keylayout');
const outputFilename = makePathToFixture('../data/OutputXName.B');
await NodeAssert.doesNotReject(async () => sut.run(inputFilename, outputFilename));
});
});
describe('convert() ', function () {
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
const inputFilename = makePathToFixture('../data/Test.keylayout');
const read = sut_r.read(inputFilename);
const converted = sut.convert_bound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn'));
// convert_object from unavailable file name
const inputFilename_unavailable = makePathToFixture('../data/X.keylayout');
const read_unavailable = sut_r.read(inputFilename_unavailable);
const converted_unavailable = sut.convert_bound.convert(read_unavailable, inputFilename_unavailable.replace(/\.keylayout$/, '.kmn'));
// convert_object from empty filename
const inputFilename_empty = makePathToFixture('');
const read_empty = sut_r.read(inputFilename_empty);
const converted_empty = sut.convert_bound.convert(read_empty, inputFilename_empty);
it('should return converted array on correct input', async function () {
assert.isTrue(converted.arrayOf_Rules.length !== 0);
});
it('should return empty on empty input', async function () {
assert.isTrue((converted_empty.keylayout_filename === ''
&& converted_empty.arrayOf_Modifiers.length === 0
&& converted_empty.arrayOf_Rules.length === 0));
});
it('should return empty on only name as input', async function () {
assert.isTrue((converted_unavailable.keylayout_filename === ''
&& converted_unavailable.arrayOf_Modifiers.length === 0
&& converted_unavailable.arrayOf_Rules.length === 0));
});
it('should return empty on only modifiers as input', async function () {
const converted_mod = sut.convert_bound.convert({
keylayout_filename: '',
arrayOf_Modifiers: [['caps'], ['Shift'], ['command']],
arrayOf_Rules: []
}, '');
assert.isTrue((converted_mod.keylayout_filename === ''
&& converted_mod.arrayOf_Modifiers.length === 0
&& converted_mod.arrayOf_Rules.length === 0));
});
it('should return empty on only rules as input', async function () {
const converted_rule = sut.convert_bound.convert({
keylayout_filename: '',
arrayOf_Modifiers: [],
arrayOf_Rules: [['C0', '', '', 0, 0, '', '', 0, 0, 'CAPS', 'K_A', 'A']]
}, '');
assert.isTrue((converted_rule.keylayout_filename === ''
&& converted_rule.arrayOf_Modifiers.length === 0
&& converted_rule.arrayOf_Rules.length === 0));
});
});
describe('create_kmn_modifier ', function () {
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
[
['shift', true, 'NCAPS SHIFT'],
['leftshift', true, 'NCAPS SHIFT'],
['rightShift', true, 'NCAPS SHIFT'],
['shift rightShift?', true, 'NCAPS SHIFT'],
['rightShift?', true, 'NCAPS'],
['shift Shift?', true, 'NCAPS SHIFT'],
['shift rightShift? caps? rightOption? rightControl', true, 'NCAPS SHIFT RCTRL'],
['leftshift rightShift? caps? rightOption? rightControl', true, 'NCAPS SHIFT RCTRL'],
['anycontrol', true, 'NCAPS CTRL'],
['shift?', true, 'NCAPS'],
['?', true, 'NCAPS'],
['?', false, ''],
['caps', true, 'CAPS'],
['', true, 'NCAPS'],
[' ', false, ''],
['wrongModifierName', false, 'wrongModifierName'],
['shift', false, 'SHIFT'],
['shift command', true, 'NCAPS SHIFT command'],
['rshift', true, 'NCAPS SHIFT'],
['rshift', false, 'SHIFT'],
['rightshift', true, 'NCAPS SHIFT'],
['riGhtsHift', true, 'NCAPS SHIFT'],
['LEFTCONTROL', true, 'NCAPS LCTRL'],
['RCONTROL', true, 'NCAPS RCTRL'],
['leftoption', true, 'NCAPS LALT'],
['loption', true, 'NCAPS LALT'],
].forEach(function (values) {
it(('should convert "' + values[0] + '"').padEnd(36, " ") + 'to "' + values[2] + '"', async function () {
const result = sut.create_kmn_modifier(values[0] as string, values[1] as boolean);
assert.equal(result, values[2]);
});
});
});
describe('isAcceptableKeymanModifier ', function () {
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
[
['NCAPS', true],
['NxCAPS', false],
['SHIFT', true],
['ALT', true],
['RALT', true],
['LALT', true],
['CTRL', true],
['LCTRL', true],
['RCTRL', true],
['LCTRL CAPS', true],
['LCTRL X', false],
['', true],
[null, false],
].forEach(function (values) {
it(("isAcceptableKeymanModifier(" + values[0] + ")").padEnd(38, " ") + ' should return ' + values[1], async function () {
const result = sut.isAcceptableKeymanModifier(values[0] as string);
assert.equal(result, values[1]);
});
});
});
describe('map_UkeleleKC_To_VK ', function () {
// todo remove
describe('RunAllFiles', function () {
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
[
[0x00, 'K_A'],
[0x31, 'K_SPACE'],
[0x18, 'K_EQUAL'],
[0x10, 'K_Y'],
[0x18, 'K_EQUAL'],
[0x21, 'K_LBRKT'],
[0x999, ''],
[-1, ''],
[null, ''],
[undefined, ''],
[, ''],
].forEach(function (values) {
it(("map_UkeleleKC_To_VK(" + values[0] + ")").padEnd(26, " ") + "should return " + "'" + values[1] + "'", async function () {
const result = sut.map_UkeleleKC_To_VK(values[0] as number);
assert.equal(result, values[1]);
});
[makePathToFixture('../data/Italian.keylayout')],
[makePathToFixture('../data/Italian_command.keylayout')],
[makePathToFixture('../data/Swiss_French.keylayout')],
[makePathToFixture('../data/Spanish.keylayout')],
[makePathToFixture('../data/Swiss_German.keylayout')],
[makePathToFixture('../data/US.keylayout')],
[makePathToFixture('../data/Polish.keylayout')],
[makePathToFixture('../data/French.keylayout')],
[makePathToFixture('../data/Latin_American.keylayout')],
// [makePathToFixture('../data/German_complete.keylayout')],
[makePathToFixture('../data/German_complete_reduced.keylayout')],
//[makePathToFixture('../data/German_Standard.keylayout')],
].forEach(function (files_) {
sut.run(files_[0]);
assert.isTrue(true);
});
});
describe('checkIfCapsIsUsed ', function () {
describe('RunTestFiles resulting in errors ', function () {
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
[
[[['caps', 'xxx'], ['yyy']], true],
[[['Caps', 'xxx'], ['yyy']], true],
[[['Caps?', 'xxx'], ['yyy']], true],
[[['caps?', 'xxx'], ['yyy']], true],
[[['CaPs', 'xxx'], ['yyy']], true],
[[['zzz', 'xxx'], ['yyy']], false],
[[['', ''], ['']], false],
[[null], false],
].forEach(function (values) {
it(("checkIfCapsIsUsed([['caps', 'xxx'], ['yyy']])").padEnd(45, " ") + "should return " + "'" + values[1] + "'", async function () {
const result = sut.checkIfCapsIsUsed(values[0] as string[][]) === values[1];
assert.isTrue(result);
['../data/Test_DifferentAmountMapSelect_KeyMapERROR.keylayout', 5292040],
['../data/Test_DifferentAmountMapSelect_KeyMapERROR_1.keylayout', 5292040],
['../data/Test_MissingkeyMapERROR.keylayout', 5246977],
['../data/Test_MissingkeyERROR.keylayout', 5246977],
['../data/Test_MissingLayoutsERROR.keylayout', 5292036],
['../data/Test_MissingmodifierMapERROR.keylayout', 5292036],
['../data/Test_MissingkeyMapSetERROR.keylayout', 5292036],
['../data/Test_MissingActionsERROR.keylayout', 5292036],
['../data/Test_MissingTerminatorsERROR.keylayout', 5292036],
['../data/Test_MissingAllERROR.keylayout', 5292036],
].forEach(function (files_) {
it(files_ + " should give error ", async function () {
sut.run(makePathToFixture(files_[0] as string));
assert.isTrue(compilerTestCallbacks.messages.length > 0);
assert.isTrue(String(compilerTestCallbacks.messages[0].code) === String(files_[1]));
});
});
});
describe('get_Modifier_array__From__KeyModifier_array ', function () {
describe('RunSpecialTestFiles', function () {
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
const inputFilename = makePathToFixture('../data/Test.keylayout');
const read = sut_r.read(inputFilename);
const converted = sut.convert_bound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn'));
[
[[{ key: '0', behaviour: 0 }], [['', 'shift? caps? ']]],
[[{ key: '0', behaviour: 2 }], [['shift? leftShift caps? ', 'anyShift caps?', 'shift leftShift caps ', 'shift? rightShift caps? ']]],
[[{ key: '0', behaviour: 999 }], [null]],
[[{ key: '999', behaviour: null }], [null]],
[[{ key: '0', behaviour: -999 }], [null]],
[[{ key: '0', behaviour: null }], [null]],
[[], []],
[makePathToFixture('../data/Test_C0.keylayout')],
[makePathToFixture('../data/Test_C1.keylayout')],
[makePathToFixture('../data/Test_C2.keylayout')],
[makePathToFixture('../data/Test_C2_several.keylayout')],
[makePathToFixture('../data/Test_C3.keylayout')],
[makePathToFixture('../data/Test_C3_several.keylayout')],
[makePathToFixture('../data/Test_C0_C1_C2_C3.keylayout')],
].forEach(function (values) {
it((values[1] !== null) ?
("get_Modifier_array__From__KeyModifier_array('" + JSON.stringify(values[0]) + "')").padEnd(68, " ") + " should return '" + /*values[1] +*/ JSON.stringify(values[1]) + "'" :
("get_Modifier_array__From__KeyModifier_array('" + JSON.stringify(values[0]) + "')").padEnd(68, " ") + " should return '" + "null" + "'", async function () {
const result = sut.get_Modifier_array__From__KeyModifier_array(converted.arrayOf_Modifiers, values[0] as allArrayContents_object[]);
assert.deepStrictEqual(JSON.stringify(result), JSON.stringify(values[1]));
});
});
});
describe('get_KeyModifier_array__From__ActionID ', function () {
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
const inputFilename = makePathToFixture('../data/Test.keylayout');
const read = sut_r.read(inputFilename);
[
['A_16', [{ "key": "32", "behaviour": "5" }]],
['A_19', [{ "key": "45", "behaviour": "5" }]],
['A_18', [{ "key": "24", "behaviour": "0" }, { "key": "24", "behaviour": "5" }]],
['unknown', []],
[undefined, []],
[null, []],
[' ', []],
['', []],
].forEach(function (values) {
let outstring = '[ ';
for (let i = 0; i < values[1].length; i++) {
outstring = outstring + "[ " + JSON.stringify(values[1][i]) + "], ";
}
it(("get_KeyModifier_array__From__ActionID('" + values[0] + "')").padEnd(57, " ") + ' should return ' + outstring.substring(0, outstring.lastIndexOf(']') + 2) + " ]", async function () {
const result = sut.get_KeyModifier_array__From__ActionID(read, String(values[0]));
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
[makePathToFixture('../data/Test_duplicate_missing_keycode.keylayout')],
[makePathToFixture('../data/Test_characters.keylayout')],
[makePathToFixture('../data/Test_modifier.keylayout')],
[makePathToFixture('../data/Test_modifierNoCaps.keylayout')],
[makePathToFixture('../data/Test_onlyOneKeymap.keylayout')],
[makePathToFixture('../data/Test_nr_elements.keylayout')],
[makePathToFixture('../data/Test.keylayout')],
].forEach(function (files_) {
it(files_ + " should give no errors ", async function () {
sut.run(files_[0]);
assert.isTrue(compilerTestCallbacks.messages.length === 0);
});
});
});
describe('get_ActionID__From__ActionNext ', function () {
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
const inputFilename = makePathToFixture('../data/Test.keylayout');
const read = sut_r.read(inputFilename);
[
['none', ''],
['0', ''],
['A_18', ''],
['1', 'A_16'],
['2', 'A_8'],
['3', 'A_17'],
['', ''],
[' ', ''],
['99', ''],
[null, ''],
[undefined, ''],
['unknown', ''],
].forEach(function (values) {
it(("get_ActionID__From__ActionNext('" + values[0] + "')").padEnd(49, " ") + ' should return ' + "'" + values[1] + "'", async function () {
const result = sut.get_ActionID__From__ActionNext(read, String(values[0]));
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
});
});
});
describe('get_ActionIndex__From__ActionId ', function () {
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
const inputFilename = makePathToFixture('../data/Test.keylayout');
const read = sut_r.read(inputFilename);
[
['none', 0],
['A_16', 8],
['A_18', 10],
['A_19', 11],
['0', 0],
['', 0],
[' ', 0],
[null, 0],
[undefined, 0],
['unknown', 0],
].forEach(function (values) {
it(("get_ActionIndex__From__ActionId('" + values[0] + "')").padEnd(50, " ") + ' should return ' + values[1], async function () {
const result = sut.get_ActionIndex__From__ActionId(read, String(values[0]));
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
});
});
});
describe('get_Output__From__ActionId_None ', function () {
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
const inputFilename = makePathToFixture('../data/Test.keylayout');
const read = sut_r.read(inputFilename);
[
['A_14', 'u'],
['', ''],
[' ', ''],
['A_18', undefined],
['unknown', ''],
].forEach(function (values) {
it(
("get_Output__From__ActionId_None('" + values[0] + "')").padEnd(56, " ") + ' should return ' + "'" + values[1] + "'", async function () {
const result = sut.get_Output__From__ActionId_None(read, String(values[0]));
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
});
});
[[null, ''],
[undefined, ''],
[99, ''],
].forEach(function (values) {
it(("get_Output__From__ActionId_None('" + values[0] + "')").padEnd(56, " ") + ' should return ' + values[1], async function () {
const result = sut.get_Output__From__ActionId_None(read, String(values[0]));
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
});
});
});
describe('get_KeyMBehaviourModOutputArray__from__KeyActionBehaviourOutput_array ', function () {
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
const inputFilename = makePathToFixture('../data/Test.keylayout');
const read = sut_r.read(inputFilename);
const b1_keycode_arr: allArrayContents_object[] = [
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '0', outchar: 'ˆ' },
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '1', outchar: 'ˆ' },
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '2', outchar: 'ˆ' },
{ keyCode: '6', key: 'K_Z', actionId: 'A_0', behaviour: '4', outchar: 'ˆ' },
{ keyCode: '25', key: 'K_9', actionId: 'A_0', behaviour: '4', outchar: 'ˆ' },
{ keyCode: '43', key: 'K_COMMA', actionId: 'A_0', behaviour: '4', outchar: 'ˆ' },
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '3', outchar: 'ˆ' },
{ keyCode: '0', key: 'K_A', actionId: 'A_1', behaviour: '2', outchar: 'Â' },
{ keyCode: '0', key: 'K_A', actionId: 'A_1', behaviour: '1', outchar: 'Â' },
{ keyCode: '14', key: 'K_E', actionId: 'A_10', behaviour: '0', outchar: 'ê' },
{ keyCode: '34', key: 'K_I', actionId: 'A_11', behaviour: '0', outchar: 'î' },
{ keyCode: '31', key: 'K_O', actionId: 'A_13', behaviour: '0', outchar: 'ô' },
{ keyCode: '32', key: 'K_U', actionId: 'A_14', behaviour: '0', outchar: 'û' },
{ keyCode: '14', key: 'K_E', actionId: 'A_2', behaviour: '2', outchar: 'Ê' },
{ keyCode: '14', key: 'K_E', actionId: 'A_2', behaviour: '1', outchar: 'Ê' },
{ keyCode: '34', key: 'K_I', actionId: 'A_3', behaviour: '2', outchar: 'Î' },
{ keyCode: '34', key: 'K_I', actionId: 'A_3', behaviour: '1', outchar: 'Î' },
{ keyCode: '31', key: 'K_O', actionId: 'A_5', behaviour: '2', outchar: 'Ô' },
{ keyCode: '31', key: 'K_O', actionId: 'A_5', behaviour: '1', outchar: 'Ô' },
{ keyCode: '32', key: 'K_U', actionId: 'A_6', behaviour: '2', outchar: 'Û' },
{ keyCode: '32', key: 'K_U', actionId: 'A_6', behaviour: '1', outchar: 'Û' },
{ keyCode: '0', key: 'K_A', actionId: 'A_9', behaviour: '0', outchar: 'â' }
];
const b1_modifierKey_arr: allArrayContents_object[] = [
{ actionId: 'A_0', key: 'K_SPACE', behaviour: '0', modifier: 'NCAPS', outchar: 'ˆ' },
{ actionId: 'A_0', key: 'K_SPACE', behaviour: '1', modifier: 'CAPS', outchar: 'ˆ' },
{ actionId: 'A_0', key: 'K_SPACE', behaviour: '2', modifier: 'NCAPS SHIFT', outchar: 'ˆ' },
{ actionId: 'A_0', key: 'K_SPACE', behaviour: '2', modifier: 'SHIFT CAPS', outchar: 'ˆ' },
{ actionId: 'A_0', key: 'K_Z', behaviour: '4', modifier: 'NCAPS SHIFT RALT', outchar: 'ˆ' },
{ actionId: 'A_0', key: 'K_9', behaviour: '4', modifier: 'NCAPS SHIFT RALT', outchar: 'ˆ' },
{ actionId: 'A_0', key: 'K_COMMA', behaviour: '4', modifier: 'NCAPS SHIFT RALT', outchar: 'ˆ' },
{ actionId: 'A_0', key: 'K_SPACE', behaviour: '3', modifier: 'NCAPS RALT CTRL', outchar: 'ˆ' },
{ actionId: 'A_0', key: 'K_SPACE', behaviour: '3', modifier: 'NCAPS CTRL', outchar: 'ˆ' },
{ actionId: 'A_1', key: 'K_A', behaviour: '2', modifier: 'NCAPS SHIFT', outchar: 'Â' },
{ actionId: 'A_1', key: 'K_A', behaviour: '2', modifier: 'SHIFT CAPS', outchar: 'Â' },
{ actionId: 'A_1', key: 'K_A', behaviour: '1', modifier: 'CAPS', outchar: 'Â' },
{ actionId: 'A_10', key: 'K_E', behaviour: '0', modifier: 'NCAPS', outchar: 'ê' },
{ actionId: 'A_11', key: 'K_I', behaviour: '0', modifier: 'NCAPS', outchar: 'î' },
{ actionId: 'A_13', key: 'K_O', behaviour: '0', modifier: 'NCAPS', outchar: 'ô' },
{ actionId: 'A_14', key: 'K_U', behaviour: '0', modifier: 'NCAPS', outchar: 'û' },
{ actionId: 'A_2', key: 'K_E', behaviour: '2', modifier: 'NCAPS SHIFT', outchar: 'Ê' },
{ actionId: 'A_2', key: 'K_E', behaviour: '2', modifier: 'SHIFT CAPS', outchar: 'Ê' },
{ actionId: 'A_2', key: 'K_E', behaviour: '1', modifier: 'CAPS', outchar: 'Ê' },
{ actionId: 'A_3', key: 'K_I', behaviour: '2', modifier: 'NCAPS SHIFT', outchar: 'Î' },
{ actionId: 'A_3', key: 'K_I', behaviour: '2', modifier: 'SHIFT CAPS', outchar: 'Î' },
{ actionId: 'A_3', key: 'K_I', behaviour: '1', modifier: 'CAPS', outchar: 'Î' },
{ actionId: 'A_5', key: 'K_O', behaviour: '2', modifier: 'NCAPS SHIFT', outchar: 'Ô' },
{ actionId: 'A_5', key: 'K_O', behaviour: '2', modifier: 'SHIFT CAPS', outchar: 'Ô' },
{ actionId: 'A_5', key: 'K_O', behaviour: '1', modifier: 'CAPS', outchar: 'Ô' },
{ actionId: 'A_6', key: 'K_U', behaviour: '2', modifier: 'NCAPS SHIFT', outchar: 'Û' },
{ actionId: 'A_6', key: 'K_U', behaviour: '2', modifier: 'SHIFT CAPS', outchar: 'Û' },
{ actionId: 'A_6', key: 'K_U', behaviour: '1', modifier: 'CAPS', outchar: 'Û' },
{ actionId: 'A_9', key: 'K_A', behaviour: '0', modifier: 'NCAPS', outchar: 'â' }
];
[[b1_keycode_arr, b1_modifierKey_arr],
[[{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '0', modifier: '0', outchar: 'ˆ' }], [{ actionId: 'A_0', key: 'K_SPACE', behaviour: '0', modifier: 'NCAPS', outchar: 'ˆ' }]],
[[{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '0', modifier: '', outchar: 'ˆ' }], [{ actionId: 'A_0', key: 'K_SPACE', behaviour: '0', modifier: 'NCAPS', outchar: 'ˆ' }]],
[[{ keyCode: '49', key: 'K_SPACE', actionId: '', behaviour: '0', modifier: '0', outchar: 'ˆ' }], [{ actionId: '', key: 'K_SPACE', behaviour: '0', modifier: 'NCAPS', outchar: 'ˆ' }]],
[[{ keyCode: '49', key: '', actionId: 'A_0', behaviour: '0', modifier: '0', outchar: 'ˆ' }], [{ actionId: 'A_0', key: '', behaviour: '0', modifier: 'NCAPS', outchar: 'ˆ' }]],
[[{ keyCode: '', key: 'K_SPACE', actionId: 'A_0', behaviour: '0', modifier: '0', outchar: 'ˆ' }], [{ actionId: 'A_0', key: 'K_SPACE', behaviour: '0', modifier: 'NCAPS', outchar: 'ˆ' }]],
[[{ keyCode: '', key: '', actionId: '', behaviour: '0', modifier: '', outchar: '' }], [{ actionId: '', key: '', behaviour: '0', modifier: 'NCAPS', outchar: '' }]],
].forEach(function (values) {
const isCaps_used = true;
const string_in = "get_KeyMBehaviourModOutputArray__from__KeyActionBehaviourOutput_array(['" + "', '" + "', '" + values[0][0].keyCode + "', '" + values[0][0].key + "', '" + values[0][0].actionId + "', '" + values[0][0].modifier + "', '" + values[0][0].outchar + "'])";
const string_out = "['" + "', '" + "', '" + values[1][0].key + "', '" + values[1][0].actionId + "', '" + "', '" + values[1][0].modifier + "', '" + values[1][0].outchar + "']";
it((JSON.stringify(values[1]).length > 60) ? 'an array of objects should return an array of objects' :
string_in.padEnd(74, " ") + ' should return ' + string_out, async function () {
const result = sut.get_KeyMBehaviourModOutputArray__from__KeyActionBehaviourOutput_array(read, values[0], isCaps_used);
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
});
});
[[{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '0', modifier: '0', outchar: 'ˆ' }, { actionId: 'A_0', key: 'K_SPACE', behaviour: '0', modifier: '', outchar: 'ˆ' }],
[{ keyCode: '', key: 'K_SPACE', actionId: 'A_0', behaviour: '0', modifier: '0', outchar: 'ˆ' }, { actionId: 'A_0', key: 'K_SPACE', behaviour: '0', modifier: '', outchar: 'ˆ' }],
[{ keyCode: '', key: '', actionId: '', behaviour: '0', modifier: '', outchar: '' }, { actionId: '', key: '', behaviour: '0', modifier: '', outchar: '' }],
].forEach(function (values) {
const isCaps_used = false;
const string_in = "get_KeyMBehaviourModOutputArray__from__KeyActionBehaviourOutput_array([ '" + values[0].keyCode + "', '" + values[0].key + "', '" + values[0].actionId + "', '" + values[0].modifier + "', '" + values[0].outchar + "'])";
const string_out = "['" + values[1].actionId + "', '" + "', '" + values[1].modifier + "', '" + values[1].key + "', '" + values[1].outchar + "']";
it(string_in.padEnd(74, " ") + ' should return ' + string_out, async function () {
const result = sut.get_KeyMBehaviourModOutputArray__from__KeyActionBehaviourOutput_array(read, [values[0]], isCaps_used);
assert.equal(JSON.stringify(result), JSON.stringify([values[1]]));
});
});
[[[], []],
[undefined, []],
[null, []],
].forEach(function (values) {
const isCaps = true;
it(("get_KeyMBehaviourModOutputArray__from__KeyActionBehaviourOutput_array([" + values[0] + "])").padEnd(74, " ") + ' should return ' + "[" + values[1] + "]", async function () {
const result = sut.get_KeyMBehaviourModOutputArray__from__KeyActionBehaviourOutput_array(read, values[0], isCaps);
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
});
});
});
describe('get_ActionStateOutput_array__From__ActionState ', function () {
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
const inputFilename = makePathToFixture('../data/Test.keylayout');
const read = sut_r.read(inputFilename);
[['1', [
{ "id": "A_0", "state": "1", "output": "ˆ" },
{ "id": "A_1", "state": "1", "output": "Â" },
{ "id": "A_10", "state": "1", "output": "ê" },
{ "id": "A_11", "state": "1", "output": "î" },
{ "id": "A_13", "state": "1", "output": "ô" },
{ "id": "A_14", "state": "1", "output": "û" },
{ "id": "A_2", "state": "1", "output": "Ê" },
{ "id": "A_3", "state": "1", "output": "Î" },
{ "id": "A_5", "state": "1", "output": "Ô" },
{ "id": "A_6", "state": "1", "output": "Û" },
{ "id": "A_9", "state": "1", "output": "â" }
],],
['2', [
{ "id": "A_0", "state": "2", "output": "`" },
{ "id": "A_1", "state": "2", "output": "À" },
{ "id": "A_10", "state": "2", "output": "è" },
{ "id": "A_11", "state": "2", "output": "ì" },
{ "id": "A_13", "state": "2", "output": "ò" },
{ "id": "A_14", "state": "2", "output": "ù" },
{ "id": "A_2", "state": "2", "output": "È" },
{ "id": "A_3", "state": "2", "output": "Ì" },
{ "id": "A_5", "state": "2", "output": "Ò" },
{ "id": "A_6", "state": "2", "output": "Ù" },
{ "id": "A_9", "state": "2", "output": "à" }
],],
['789', [],],
['', [],],
[' ', [],],
[123, [],],
[null, [],],
[undefined, [],],
].forEach(function (values) {
it((JSON.stringify(values[1]).length > 30) ?
("get_ActionStateOutput_array__From__ActionState('" + values[0] + "')").padEnd(60, " ") + ' should return an array of objects' :
("get_ActionStateOutput_array__From__ActionState('" + values[0] + "')").padEnd(60, " ") + ' should return ' + "'" + JSON.stringify(values[1]) + "'", async function () {
const result = sut.get_ActionStateOutput_array__From__ActionState(read, String(values[0]));
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
});
});
});
describe('get_ActionOutputBehaviourKeyModi_From__ActionIDStateOutput ', function () {
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
const inputFilename = makePathToFixture('../data/Test.keylayout');
const read = sut_r.read(inputFilename);
const converted = sut.convert_bound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn'));
[
['A_1', 'A', true,
[{ "outchar": "A", "actionId": "A_1", "behaviour": "1", "key": "K_A", "modifier": "CAPS" },
{ "outchar": "A", "actionId": "A_1", "behaviour": "2", "key": "K_A", "modifier": "NCAPS SHIFT" },
{ "outchar": "A", "actionId": "A_1", "behaviour": "2", "key": "K_A", "modifier": "SHIFT CAPS" }]
],
['A_1', 'A', false,
[{ "outchar": "A", "actionId": "A_1", "behaviour": "1", "key": "K_A", "modifier": "CAPS" },
{ "outchar": "A", "actionId": "A_1", "behaviour": "2", "key": "K_A", "modifier": "SHIFT" },
{ "outchar": "A", "actionId": "A_1", "behaviour": "2", "key": "K_A", "modifier": "SHIFT CAPS" }]
],
['A_9', 'a', true, [{ "outchar": "a", "actionId": "A_9", "behaviour": "0", "key": "K_A", "modifier": "NCAPS" }]],
['A_9', 'a', false, [{ "outchar": "a", "actionId": "A_9", "behaviour": "0", "key": "K_A", "modifier": "" }]],
['A_9', 'a', , [{ "outchar": "a", "actionId": "A_9", "behaviour": "0", "key": "K_A", "modifier": "" }]],
['A_9', '', true, [{ "outchar": "", "actionId": "A_9", "behaviour": "0", "key": "K_A", "modifier": "NCAPS" }]],
['A_9', '', false, [{ "outchar": "", "actionId": "A_9", "behaviour": "0", "key": "K_A", "modifier": "" }]],
['', 'a', true, []],
['', 'a', false, []],
['', '', , []],
].forEach(function (values) {
it((JSON.stringify(values[3]).length > 35) ?
("get_ActionOutputBehaviourKeyModi_From__ActionIDStateOutput('" + values[0] + "', '" + values[1] + "', " + values[2] + ")").padEnd(67, " ") + ' should return an array of objects' :
("get_ActionOutputBehaviourKeyModi_From__ActionIDStateOutput('" + values[0] + "', '" + values[1] + "', " + values[2] + ")").padEnd(67, " ") + ' should return ' + "'" + JSON.stringify(values[3]) + "'", async function () {
const result = sut.get_ActionOutputBehaviourKeyModi_From__ActionIDStateOutput(read, converted.arrayOf_Modifiers, String(values[0]), String(values[1]), Boolean(values[2]));
assert.equal(JSON.stringify(result), JSON.stringify(values[3]));
});
});
});
describe('get_KeyActionOutput_array__From__ActionStateOutput_array ', function () {
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
const sut_r = new KeylayoutFileReader(compilerTestCallbacks);
const inputFilename = makePathToFixture('../data/Test.keylayout');
const read = sut_r.read(inputFilename);
const b6_actionId_arr: idStateOutput_object[] = [
{ "id": "A_0", "state": "1", "output": "ˆ" },
{ "id": "A_1", "state": "1", "output": "Â" },
{ "id": "A_10", "state": "1", "output": "ê" },
{ "id": "A_11", "state": "1", "output": "î" },
{ "id": "A_13", "state": "1", "output": "ô" },
{ "id": "A_14", "state": "1", "output": "û" },
{ "id": "A_2", "state": "1", "output": "Ê" },
{ "id": "A_3", "state": "1", "output": "Î" },
{ "id": "A_5", "state": "1", "output": "Ô" },
{ "id": "A_6", "state": "1", "output": "Û" },
{ "id": "A_9", "state": "1", "output": "â" }
];
const b1_keycode_arr: allArrayContents_object[] = [
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '0', outchar: 'ˆ' },
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '1', outchar: 'ˆ' },
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '2', outchar: 'ˆ' },
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '3', outchar: 'ˆ' },
{ keyCode: '6', key: 'K_Z', actionId: 'A_0', behaviour: '4', outchar: 'ˆ' },
{ keyCode: '25', key: 'K_9', actionId: 'A_0', behaviour: '4', outchar: 'ˆ' },
{ keyCode: '43', key: 'K_COMMA', actionId: 'A_0', behaviour: '4', outchar: 'ˆ' },
{ keyCode: '0', key: 'K_A', actionId: 'A_1', behaviour: '1', outchar: 'Â' },
{ keyCode: '0', key: 'K_A', actionId: 'A_1', behaviour: '2', outchar: 'Â' },
{ keyCode: '14', key: 'K_E', actionId: 'A_10', behaviour: '0', outchar: 'ê' },
{ keyCode: '34', key: 'K_I', actionId: 'A_11', behaviour: '0', outchar: 'î' },
{ keyCode: '31', key: 'K_O', actionId: 'A_13', behaviour: '0', outchar: 'ô' },
{ keyCode: '32', key: 'K_U', actionId: 'A_14', behaviour: '0', outchar: 'û' },
{ keyCode: '14', key: 'K_E', actionId: 'A_2', behaviour: '1', outchar: 'Ê' },
{ keyCode: '14', key: 'K_E', actionId: 'A_2', behaviour: '2', outchar: 'Ê' },
{ keyCode: '34', key: 'K_I', actionId: 'A_3', behaviour: '1', outchar: 'Î' },
{ keyCode: '34', key: 'K_I', actionId: 'A_3', behaviour: '2', outchar: 'Î' },
{ keyCode: '31', key: 'K_O', actionId: 'A_5', behaviour: '1', outchar: 'Ô' },
{ keyCode: '31', key: 'K_O', actionId: 'A_5', behaviour: '2', outchar: 'Ô' },
{ keyCode: '32', key: 'K_U', actionId: 'A_6', behaviour: '1', outchar: 'Û' },
{ keyCode: '32', key: 'K_U', actionId: 'A_6', behaviour: '2', outchar: 'Û' },
{ keyCode: '0', key: 'K_A', actionId: 'A_9', behaviour: '0', outchar: 'â' }
];
[[b6_actionId_arr, b1_keycode_arr],
].forEach(function (values) {
it(("get_KeyActionOutput_array__From__ActionStateOutput_array([['" + JSON.stringify(values[0]) + "'],..])").padEnd(73, " ") + '1 should return an array of objects', async function () {
const result = sut.get_KeyActionOutput_array__From__ActionStateOutput_array(read, values[0] as idStateOutput_object[]);
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
});
});
const oneEntryResult = [
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '0', outchar: 'ˆ' },
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '1', outchar: 'ˆ' },
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '2', outchar: 'ˆ' },
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '3', outchar: 'ˆ' },
{ keyCode: '6', key: 'K_Z', actionId: 'A_0', behaviour: '4', outchar: 'ˆ' },
{ keyCode: '25', key: 'K_9', actionId: 'A_0', behaviour: '4', outchar: 'ˆ' },
{ keyCode: '43', key: 'K_COMMA', actionId: 'A_0', behaviour: '4', outchar: 'ˆ' }
];
const oneEntryResultNoOutput = [
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '0', outchar: '' },
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '1', outchar: '' },
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '2', outchar: '' },
{ keyCode: '49', key: 'K_SPACE', actionId: 'A_0', behaviour: '3', outchar: '' },
{ keyCode: '6', key: 'K_Z', actionId: 'A_0', behaviour: '4', outchar: '' },
{ keyCode: '25', key: 'K_9', actionId: 'A_0', behaviour: '4', outchar: '' },
{ keyCode: '43', key: 'K_COMMA', actionId: 'A_0', behaviour: '4', outchar: '' },
];
[[[{ "id": "A_0", "state": "1", "output": "ˆ" }], oneEntryResult],
[[{ "id": "A_0", "state": "1", "output": "" }], oneEntryResultNoOutput],
[[{ "id": "A_0", "state": "", "output": "ˆ" }], oneEntryResult],
].forEach(function (values) {
it(("get_KeyActionOutput_array__From__ActionStateOutput_array(['" + JSON.stringify(values[0]) + "'])").padEnd(73, " ") + '2 should return an array of objects', async function () {
const result = sut.get_KeyActionOutput_array__From__ActionStateOutput_array(read, values[0] as idStateOutput_object[]);
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
});
});
[[[{ "id": "", "state": "1", "output": "ˆ" }], []],
[[{ "id": "", "state": "", "output": "" }], []],
[[{ "id": " ", "state": " ", "output": "" }], []],
].forEach(function (values) {
it(("get_KeyActionOutput_array__From__ActionStateOutput_array(" + JSON.stringify(values[0]) + ")").padEnd(73, " ") + ' should return ' + "'[" + JSON.stringify(values[1]) + "]'", async function () {
const result = sut.get_KeyActionOutput_array__From__ActionStateOutput_array(read, values[0] as idStateOutput_object[]);
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
});
});
[[, []],
[undefined, []],
[null, []],
].forEach(function (values) {
it(("get_KeyActionOutput_array__From__ActionStateOutput_array(" + JSON.stringify(values[0]) + ")").padEnd(73, " ") + ' should return ' + "'[" + JSON.stringify(values[1]) + "]'", async function () {
const result = sut.get_KeyActionOutput_array__From__ActionStateOutput_array(read, values[0] as idStateOutput_object[]);
assert.equal(JSON.stringify(result), JSON.stringify(values[1]));
});
});
});
});