From b5e2e99a36cd26f2705474aaa7643d68cc0790ef Mon Sep 17 00:00:00 2001 From: Sabine Date: Tue, 3 Mar 2026 22:50:57 +0100 Subject: [PATCH] feat(developer): functional changes to remove convertCharacterToUnicodeCodePoint() --- common/web/types/src/util/convert-utils.ts | 2 +- .../types/tests/util/convert-utils.tests.ts | 14 +- .../keylayout-to-kmn-converter.ts | 8 +- .../src/keylayout-to-kmn/kmn-file-writer.ts | 130 +++++++++++++++--- .../Test_Character_Codepoint_C0.keylayout | 88 ++++++++++++ .../Test_Character_Codepoint_C2.keylayout | 63 +++++++++ .../Test_Character_Codepoint_C3.keylayout | 59 ++++++++ .../test/data/Test_mixedEncodings.keylayout | 10 +- .../test/keylayout-to-kmn-converter.tests.ts | 42 +++++- 9 files changed, 384 insertions(+), 32 deletions(-) create mode 100644 developer/src/kmc-convert/test/data/Test_Character_Codepoint_C0.keylayout create mode 100644 developer/src/kmc-convert/test/data/Test_Character_Codepoint_C2.keylayout create mode 100644 developer/src/kmc-convert/test/data/Test_Character_Codepoint_C3.keylayout diff --git a/common/web/types/src/util/convert-utils.ts b/common/web/types/src/util/convert-utils.ts index b35650499e..4cecea4d58 100644 --- a/common/web/types/src/util/convert-utils.ts +++ b/common/web/types/src/util/convert-utils.ts @@ -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; } diff --git a/common/web/types/tests/util/convert-utils.tests.ts b/common/web/types/tests/util/convert-utils.tests.ts index c45a504a9f..a90fe8b08a 100644 --- a/common/web/types/tests/util/convert-utils.tests.ts +++ b/common/web/types/tests/util/convert-utils.tests.ts @@ -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], diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts index 1ce8aeea4b..282be6e53a 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts @@ -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); } diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts index a662a4f952..1e3feadaf0 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts @@ -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), diff --git a/developer/src/kmc-convert/test/data/Test_Character_Codepoint_C0.keylayout b/developer/src/kmc-convert/test/data/Test_Character_Codepoint_C0.keylayout new file mode 100644 index 0000000000..eefcb2588f --- /dev/null +++ b/developer/src/kmc-convert/test/data/Test_Character_Codepoint_C0.keylayout @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/developer/src/kmc-convert/test/data/Test_Character_Codepoint_C2.keylayout b/developer/src/kmc-convert/test/data/Test_Character_Codepoint_C2.keylayout new file mode 100644 index 0000000000..2c710068c6 --- /dev/null +++ b/developer/src/kmc-convert/test/data/Test_Character_Codepoint_C2.keylayout @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/developer/src/kmc-convert/test/data/Test_Character_Codepoint_C3.keylayout b/developer/src/kmc-convert/test/data/Test_Character_Codepoint_C3.keylayout new file mode 100644 index 0000000000..5618a605cf --- /dev/null +++ b/developer/src/kmc-convert/test/data/Test_Character_Codepoint_C3.keylayout @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/developer/src/kmc-convert/test/data/Test_mixedEncodings.keylayout b/developer/src/kmc-convert/test/data/Test_mixedEncodings.keylayout index a937765242..33566a0840 100644 --- a/developer/src/kmc-convert/test/data/Test_mixedEncodings.keylayout +++ b/developer/src/kmc-convert/test/data/Test_mixedEncodings.keylayout @@ -14,7 +14,7 @@ - + @@ -23,16 +23,16 @@ - + - - + + - + diff --git a/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts b/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts index 49496fcf79..98ec717147 100644 --- a/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts +++ b/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts @@ -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]);