feat(developer): functional changes to remove convertCharacterToUnicodeCodePoint()

This commit is contained in:
Sabine 2026-03-03 22:50:57 +01:00
parent 28c6c78f97
commit b5e2e99a36
9 changed files with 384 additions and 32 deletions

View file

@ -121,7 +121,7 @@ export function convertToUnicodeCharacter(inputString: string): string | undefin
* the input character if a Unicode Codepoint or valid input character is provided (e.g. 'c' -> 'c', '😎' -> '😎')
* undefined if inputString is not valid, null or undefined, or a surrogate codepoint
*/
export function convertControlCharacterToUnicodeCodePoint(inputString: string): string | undefined {
export function convertCharacterToUnicodeCodePoint(inputString: string): string | undefined {
if ((inputString === null) || (inputString === undefined)) {
return undefined;
}

View file

@ -4,7 +4,7 @@ import { convertUtil } from '@keymanapp/common-types';
describe('convert-utils', function () {
describe('convertControlCharacterToUnicodeCodePoint from convert-utils', function () {
describe('convertCharacterToUnicodeCodePoint from convert-utils', function () {
[
["U+0061", 'U+0061'],
["U+1234", 'U+1234'],
@ -68,7 +68,7 @@ describe('convert-utils', function () {
["ẘ", "ẘ"],
].forEach(function (values) {
it(('should convert "' + values[0] + '"').padEnd(25, " ") + 'to "' + values[1] + '"', async function () {
const result = convertUtil.convertControlCharacterToUnicodeCodePoint(values[0] as string);
const result = convertUtil.convertCharacterToUnicodeCodePoint(values[0] as string);
assert.equal(result, values[1]);
});
});
@ -84,14 +84,17 @@ describe('convert-utils', function () {
["ሴ", 'ሴ'],
["😎", '😎'],
["ẘ", "ẘ"],
["a", 'a'],
["ሴ", 'ሴ'],
["😆", '😆'],
["ẘ", "ẘ"],
["U+0061", 'a'],
["U+1234", 'ሴ'],
["U+1F60E", '😎'],
["U+1E98", "ẘ"],
["U+", undefined],
['U+', undefined],
['U+U+', undefined],
@ -99,8 +102,8 @@ describe('convert-utils', function () {
['U+D800', undefined],
['U+D83D', undefined],
['U+DFFF', undefined],
['U+10FFFF', '􏿿'],
['U+E000', ''],
['U+10FFFF', '􏿿'],
['U+E000', ''],
['U+1000000', undefined],
[">", '>'],
["@", undefined],
@ -110,10 +113,11 @@ describe('convert-utils', function () {
["ሴሴ", 'ሴሴ'],
['😎😆', '😎😆'],
["ẘẘ", "ẘẘ"],
["", ''],
["", ''],
['&', '&'],
['&;', '&;'],
['&&', '&&'],
['&&;', '&&;'],
["&#&#", undefined],
["&#x&#x", undefined],

View file

@ -117,7 +117,11 @@ export class KeylayoutToKmnConverter {
const outArray: ProcessedData = await this.convert(jsonO, inputFilename);
const kmnFileWriter = new KmnFileWriter(this.callbacks, this.options);
// TODO remove
const out_text_ok: boolean = kmnFileWriter.writeToFile(outArray); if (!out_text_ok) {
this.callbacks.reportMessage(ConverterMessages.Error_UnableToWrite({ outputFilename }));
return null;
}
// write to object/ConverterToKmnResult
const outUint8: Uint8Array = kmnFileWriter.write(outArray);
const result: ConverterToKmnResult = {
@ -475,6 +479,8 @@ export class KeylayoutToKmnConverter {
}
}
dataUkelele.arrayOfRules = objectArray;
const xxx=this.reviewRuleInputData(dataUkelele);
if (xxx === null) { console.log("Error in reviewRuleInputData NULLLLLLL"); return null; }
return this.reviewRuleInputData(dataUkelele);
}

View file

@ -17,6 +17,28 @@ export class KmnFileWriter {
constructor(private callbacks: CompilerCallbacks, private options: CompilerOptions) { };
// TODO remove
public writeToFile(dataUkelele: ProcessedData): boolean {
let data: string = "\n";
// add top part of kmn file: STORES
data += this.writeKmnFileHeader(dataUkelele);
// add bottom part of kmn file: RULES
data += this.writeDataRules(dataUkelele);
try {
this.callbacks.fs.writeFileSync(dataUkelele.kmnFilename, new TextEncoder().encode(data));
return true;
} catch (err) {
this.callbacks.reportMessage(ConverterMessages.Error_UnableToWrite({ outputFilename: dataUkelele.kmnFilename }));
return false;
}
}
/**
* @brief member function to write data from object to a Uint8Array
* @param dataUkelele the array holding all keyboard data
@ -43,7 +65,7 @@ export class KmnFileWriter {
return null;
}
}
/**
* @brief member function to create data for the header (stores) that will be printed to the resulting kmn file
* @param dataUkelele an object containing all data read from a .keylayout file
@ -145,16 +167,33 @@ export class KmnFileWriter {
const warnText = this.reviewRules(uniqueDataRules, k);
const outputCharacter = new TextDecoder().decode(uniqueDataRules[k].output);
const outputUnicodeCharacter = convertUtil.convertToUnicodeCharacter(outputCharacter);
const outputUnicodeCodePoint = convertUtil.convertControlCharacterToUnicodeCodePoint(outputCharacter);
if ((outputUnicodeCharacter !== undefined) && (outputUnicodeCodePoint !== undefined)) {
// const outputUnicodeCodePoint = convertUtil.convertCharacterToUnicodeCodePoint(outputCharacter);
// here exchange const outputUnicodeCodePoint = hu()
let inpt;
// if starts with &#x
if (outputCharacter.startsWith("&#x")) {
inpt = parseInt(outputCharacter.slice(3, -1), 16);
}
else if (outputCharacter.startsWith("&#")) {
inpt = parseInt(outputCharacter.slice(2, -1), 10);
}
else if (outputCharacter.startsWith("U+")) {
inpt = parseInt(outputCharacter.slice(2), 16);
}
if ((outputUnicodeCharacter !== undefined)) {
// if we are about to print a unicode codepoint instead of a single character we need to check if it is a control character
if ((Number("0x" + outputUnicodeCodePoint.substring(2, outputUnicodeCodePoint.length)) < KeylayoutToKmnConverter.MAX_CTRL_CHARACTER)) {
// if ((Number("0x" + outputUnicodeCodePoint.substring(2, outputUnicodeCodePoint.length)) < KeylayoutToKmnConverter.MAX_CTRL_CHARACTER)) {
// try
if (inpt < KeylayoutToKmnConverter.MAX_CTRL_CHARACTER) {
versionOutputCharacter = outputUnicodeCodePoint;
versionOutputCharacter = "U+" + inpt.toString(16).toUpperCase().padStart(4, "0");
if (outputUnicodeCodePoint.length > 1) {
//if (outputUnicodeCodePoint.length > 1) {
if (2 > 1) {
if (warnText[2] == "") {
warnText[2] = warnText[2] + "c WARNING: use of a control character " /*+ outputUnicodeCodePoint*/;
}
@ -166,7 +205,15 @@ export class KmnFileWriter {
versionOutputCharacter = outputUnicodeCharacter;
}
}
if ((outputUnicodeCharacter === undefined) || (outputUnicodeCodePoint === undefined)) {
/* console.log("-------------------------------------------------- ",);
console.log(" outputCharacter ", outputCharacter);
console.log(" outputUnicodeCharacter ", outputUnicodeCharacter);*/
if ((outputUnicodeCharacter === undefined)) {
this.callbacks.reportMessage(ConverterMessages.Error_UnsupportedCharactersDetected({
inputFilename: dataUkelele.keylayoutFilename,
output: new TextDecoder().decode(uniqueDataRules[k].output),
@ -219,13 +266,32 @@ export class KmnFileWriter {
const outputCharacter = new TextDecoder().decode(uniqueDataRules[k].output);
const outputUnicodeCharacter = convertUtil.convertToUnicodeCharacter(outputCharacter);
const outputUnicodeCodePoint = convertUtil.convertControlCharacterToUnicodeCodePoint(outputCharacter);
if ((outputUnicodeCharacter !== undefined) && (outputUnicodeCodePoint !== undefined)) {
// const outputUnicodeCodePoint = convertUtil.convertCharacterToUnicodeCodePoint(outputCharacter);
// here exchange const outputUnicodeCodePoint = hu()
let inpt;
// if starts with &#x
if (outputCharacter.startsWith("&#x")) {
inpt = parseInt(outputCharacter.slice(3, -1), 16);
}
else if (outputCharacter.startsWith("&#")) {
inpt = parseInt(outputCharacter.slice(2, -1), 10);
}
else if (outputCharacter.startsWith("U+")) {
inpt = parseInt(outputCharacter.slice(2), 16);
}
//const outputUnicodeCodePoint = convertUtil.convertCharacterToUnicodeCodePoint(outputCharacter);
if (outputUnicodeCharacter !== undefined) {
// if we are about to print a unicode codepoint instead of a single character we need to check if it is a control character
if (Number("0x" + outputUnicodeCodePoint.substring(2, outputUnicodeCodePoint.length)) < KeylayoutToKmnConverter.MAX_CTRL_CHARACTER) {
versionOutputCharacter = outputUnicodeCodePoint;
if (outputUnicodeCodePoint.length > 1) {
if (inpt < KeylayoutToKmnConverter.MAX_CTRL_CHARACTER) {
versionOutputCharacter = "U+" + inpt.toString(16).toUpperCase().padStart(4, "0");
// if (outputUnicodeCodePoint.length > 1) {
if (2 > 1) {
if (warnText[2] == "") {
warnText[2] = warnText[2] + "c WARNING: use of a control character ";
}
@ -237,7 +303,7 @@ export class KmnFileWriter {
versionOutputCharacter = outputUnicodeCharacter;
}
}
if ((outputUnicodeCharacter === undefined) || (outputUnicodeCodePoint === undefined)) {
if (outputUnicodeCharacter === undefined) {
this.callbacks.reportMessage(ConverterMessages.Error_UnsupportedCharactersDetected({
inputFilename: dataUkelele.keylayoutFilename,
output: new TextDecoder().decode(uniqueDataRules[k].output),
@ -313,14 +379,40 @@ export class KmnFileWriter {
const warnText = this.reviewRules(uniqueDataRules, k);
const outputCharacter = new TextDecoder().decode(uniqueDataRules[k].output);
const outputUnicodeCharacter = convertUtil.convertToUnicodeCharacter(outputCharacter);
const outputUnicodeCodePoint = convertUtil.convertControlCharacterToUnicodeCodePoint(outputCharacter);
if ((outputUnicodeCharacter !== undefined) && (outputUnicodeCodePoint !== undefined)) {
let inpt;
// if starts with &#x
if (outputCharacter.startsWith("&#x")) {
inpt = parseInt(outputCharacter.slice(3, -1), 16);
}
else if (outputCharacter.startsWith("&#")) {
inpt = parseInt(outputCharacter.slice(2, -1), 10);
}
else if (outputCharacter.startsWith("U+")) {
inpt = parseInt(outputCharacter.slice(2), 16);
}
//const outputUnicodeCodePoint = convertUtil.convertCharacterToUnicodeCodePoint(outputCharacter);
if (outputUnicodeCharacter !== undefined) {
// if we are about to print a unicode codepoint instead of a single character we need to check if a control character is to be used
if (Number("0x" + outputUnicodeCodePoint.substring(2, outputUnicodeCodePoint.length)) < KeylayoutToKmnConverter.MAX_CTRL_CHARACTER) {
//if (Number("0x" + outputUnicodeCodePoint.substring(2, outputUnicodeCodePoint.length)) < KeylayoutToKmnConverter.MAX_CTRL_CHARACTER) {
if (inpt < KeylayoutToKmnConverter.MAX_CTRL_CHARACTER) {
versionOutputCharacter = outputUnicodeCodePoint;
versionOutputCharacter = "U+" + inpt.toString(16).toUpperCase().padStart(4, "0");
if (outputUnicodeCodePoint.length > 1) {
//versionOutputCharacter = outputUnicodeCodePoint;
//if (outputUnicodeCodePoint.length > 1) {
if (2 > 1) {
if (warnText[2] == "") {
warnText[2] = warnText[2] + "c WARNING: use of a control character ";
}
@ -332,7 +424,7 @@ export class KmnFileWriter {
versionOutputCharacter = outputUnicodeCharacter;
}
}
if ((outputUnicodeCharacter === undefined) || (outputUnicodeCodePoint === undefined)) {
if (outputUnicodeCharacter === undefined) {
this.callbacks.reportMessage(ConverterMessages.Error_UnsupportedCharactersDetected({
inputFilename: dataUkelele.keylayoutFilename,
output: new TextDecoder().decode(uniqueDataRules[k].output),

View file

@ -0,0 +1,88 @@
<?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 several C0 rules
-->
<keyboard group="126" id="-1272" name="Test_Character_Codepoint_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>
<keyMapSelect mapIndex="2">
<modifier keys="shift"/>
</keyMapSelect>
<keyMapSelect mapIndex="3">
<modifier keys="shift caps"/>
</keyMapSelect>
</modifierMap>
<keyMapSet id="ANSI">
<keyMap index="0">
<key code="0" output="A"/> <!-- C0-> single character -->
<key code="1" output="AB"/> <!-- C0-> multiple character -->
<key code="2" output="&#x42;"/> <!-- C0-> html hex -->
<key code="3" output="&#67;"/> <!-- C0-> html dec -->
<key code="4" output="U+0044"/> <!-- C0-> unicode -->
<key code="5" output="&"/> <!-- C0-> special: ampersand -->
<key code="6" output="U+10FFFF"/> <!-- C0-> special: last unicode -->
<key code="7" output="&#x19;"/> <!-- C0-> special: codepoint + warning -->
</keyMap>
<keyMap index="1">
<key code="0" output="ሴ"/>
<key code="1" output="ሴቄ"/>
<key code="2" output="&#x1250;"/>
<key code="3" output="&#4680;"/>
<key code="4" output="U+1244"/>
<key code="5" output="&&"/> <!-- C0-> special: double ampersand -->
<key code="6" output="U+E000"/>
<key code="7" output="&#x20;"/>
</keyMap>
<keyMap index="2">
<key code="0" output="😎"/>
<key code="1" output="😎😆"/>
<key code="2" output="&#x1F60E;"/>
<key code="3" output="&#128508;"/>
<key code="4" output="U+1F61E"/>
<key code="5" output="&;"/> <!-- C0-> special: ampersand ; -->
<key code="6" output="U+D799"/>
<key code="7" output="&#x21;"/>
</keyMap>
<keyMap index="3">
<key code="0" output="ẘ"/> <!-- C0-> single diacritic -->
<key code="1" output="ቄṸ"/> <!-- C0-> multiple diacritic -->
<key code="2" output="&#x1E99;"/>
<key code="3" output="&#7844;"/>
<key code="4" output="U+1E99"/>
<key code="5" output="&&;"/> <!-- C0-> special: double ampersand ; -->
<key code="6" output="&gt;"/> <!-- C0-> special: named html entity -->
</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,63 @@
<?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 C2 rule
-->
<keyboard group="126" id="-1272" name="Test_C2" 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" action="a1"/>
<key code="1" action="a2"/>
<key code="2" action="a5"/>
<key code="3" action="a6"/>
</keyMap>
<keyMap index="1">
<key code="11" action="a3"/>
<key code="12" action="a4"/>
</keyMap>
</keyMapSet>
<actions>
<action id="a1">
<when state="none" next="1"/>
</action>
<action id="a3">
<when state="1" output="Â"/>
</action>
<action id="a4">
<when state="1" output="😎😆"/>
<when state="2" output="&#x1234;"/>
<when state="3" output="&#007;"/>
<when state="4" output="ẘ"/>
</action>
<action id="a2">
<when state="none" next="2"/>
</action>
<action id="a5">
<when state="none" next="3"/>
</action>
<action id="a6">
<when state="none" next="4"/>
</action>
</actions>
<terminators>
<when state="1" output="ˆ"/>
</terminators>
</keyboard>

View file

@ -0,0 +1,59 @@
<?xml version="1.1" encoding="UTF-8"?>
<!DOCTYPE keyboard SYSTEM "file://localhost/System/Library/DTDs/KeyboardLayout.dtd">
<!--
Data generated August 1st 2025
Generated by S. Schmitt
tests C3 rules
-->
<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"/>
</keyMap>
<keyMap index="2">
<key code="0" action="A7"/>
<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="3" next="1"/>
</action>
<action id="A6">
<when state="1" output="â"/>
</action>
<action id="A7">
<when state="1" output="&#0007;"/>
</action>
</actions>
<terminators>
<when state="1" output="ˆ"/>
</terminators>
</keyboard>

View file

@ -14,7 +14,7 @@
</layouts>
<modifierMap id="30" defaultIndex="0">
<keyMapSelect mapIndex="0">
<modifier keys="shift"/>
<modifier keys=""/>
</keyMapSelect>
<keyMapSelect mapIndex="1">
<modifier keys="caps"/>
@ -23,16 +23,16 @@
<keyMapSet id="ANSI">
<keyMap index="0">
<key code="0" output="A"/>
<key code="1" output="&#x41;"/>
<key code="1" output="&#x42;"/>
<key code="2" output="&#67;"/>
<key code="3" output="U+0044"/>
</keyMap>
<keyMap index="1">
<key code="0" output="😎"/>
<key code="1" output="&#x1F600;"/>
<key code="0" output="&#x1F600;"/>
<key code="1" output="😎"/>
<key code="2" output="&#128514;"/>
<key code="3" output="&gt;"/>
<key code="4" output=">"/>
<key code="4" output="<"/>
</keyMap>
</keyMapSet>
<actions>

View file

@ -21,11 +21,46 @@ describe('KeylayoutToKmnConverter', function () {
compilerTestCallbacks.clear();
});
describe('RunONE', function () {
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
[
[makePathToFixture('../data/Test_mixedEncodings.keylayout')],
].forEach(function (files) {
it(files + " should give no errors ", async function () {
sut.run(files[0]);
assert.isTrue(compilerTestCallbacks.messages.length === 0);
});
});
});
/*describe('RunFILES', function () {
this.timeout(10000); // allow longer time for these tests
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
[
[makePathToFixture('../data/Polish.keylayout')],
[makePathToFixture('../data/Spanish.keylayout')],
[makePathToFixture('../data/French.keylayout')],
[makePathToFixture('../data/German_complete_reduced.keylayout')],
// [makePathToFixture('../data/German_complete.keylayout')],
// [makePathToFixture('../data/German_standard.keylayout')],
[makePathToFixture('../data/Italian_command.keylayout')],
[makePathToFixture('../data/Italian.keylayout')],
[makePathToFixture('../data/Latin_American.keylayout')],
[makePathToFixture('../data/Swiss_French.keylayout')],
[makePathToFixture('../data/Swiss_German.keylayout')],
].forEach(function (files) {
it(files + " should give no errors ", async function () {
sut.run(files[0]);
assert.isTrue(compilerTestCallbacks.messages.length === 0);
});
});
});*/
describe('RunTestFiles resulting in errors ', function () {
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
[
[makePathToFixture('../data/Test_DifferentAmountOfMapSelectInKeyMapERROR.keylayout')],
[makePathToFixture('../data/Test_DifferentAmountOfMapSelectInKeyMapERROR_1.keylayout')],
[makePathToFixture('../data/Test_MissingkeyERROR.keylayout')],
[makePathToFixture('../data/Test_MissingkeyMapERROR.keylayout')],
[makePathToFixture('../data/Test_MissingLayoutsERROR.keylayout')],
@ -34,6 +69,7 @@ describe('KeylayoutToKmnConverter', function () {
[makePathToFixture('../data/Test_MissingActionsERROR.keylayout')],
[makePathToFixture('../data/Test_MissingTerminatorsERROR.keylayout')],
[makePathToFixture('../data/Test_MissingAllERROR.keylayout')],
[makePathToFixture('../data/Test_characters.keylayout')],
].forEach(function (files) {
it(files + " should give an error ", async function () {
sut.run(files[0]);
@ -43,6 +79,7 @@ describe('KeylayoutToKmnConverter', function () {
});
describe('RunSpecialTestFiles', function () {
this.timeout(10000); // allow longer time for these tests
const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions);
[
[makePathToFixture('../data/Test_C0.keylayout')],
@ -66,6 +103,9 @@ describe('KeylayoutToKmnConverter', function () {
[makePathToFixture('../data/Test_ambiguous_keys.keylayout')],
[makePathToFixture('../data/Test_nr_elements.keylayout')],
[makePathToFixture('../data/Test.keylayout')],
[makePathToFixture('../data/Test_Character_Codepoint_C0.keylayout')],
[makePathToFixture('../data/Test_Character_Codepoint_C2.keylayout')],
[makePathToFixture('../data/Test_Character_Codepoint_C3.keylayout')],
].forEach(function (files) {
it(files + " should give no errors ", async function () {
sut.run(files[0]);