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 fff0a3da05..44d3552b88 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 @@ -46,7 +46,7 @@ import boxXmlArray = util.boxXmlArray;*/ // OK no added NCAPS when first modifier in modifierMap does not contain "caps" or"caps?" // use length to clear array instead of defining evetry time new (modifierMap_ONE_InKeymapSelect.length=0 // naming of for-loop var i,j,k?... - // warning if contrADICTING RULES E:G: [ 'modifier_C0', 'SHIFT NCAPS', 'K_C', 'c', '0', '1' ], vs [ 'modifier_C0', 'SHIFT NCAPS', 'K_C', 'C', '1', '0' ], + // warning if contrADICTING RULES E:G: [ 'modifier_C0', 'SHIFT NCAPS', 'K_C', 'c'], vs [ 'modifier_C0', 'SHIFT NCAPS', 'K_C', 'C' ], // print NCAPS as the first of the modifiers in create_kmn_modifier // use boxXmlArray from codebase instead of my own // where are rules for action+none ( a, e, u, etc) @@ -185,13 +185,12 @@ export class KeylayoutToKmnConverter { */ public read(filename: string): convert_object { - const modifierMap_ALL_KeyMapSelects: string[][] = [] // modifier for each keymapselect + const modifierBehaviors: string[][] = [] // modifier for each keymapselect const kmn_Rules_AllLayers: Uint8Array[][] = [] - // TODO remove unneccassary elements const DataObject: convert_object = { name: "Ukelele-kmn", // needed?? remove - ArrayOf_Element_ModifierMaps_ALLKeyMapSelect: modifierMap_ALL_KeyMapSelects, // 18 modifiers in 8 KeyMapSelect(behaviors) + ArrayOf_Element_ModifierMaps_ALLKeyMapSelect: modifierBehaviors, // 18 modifiers in 8 KeyMapSelect(behaviors) ArrayOf_processed_RuleData: kmn_Rules_AllLayers, }; @@ -214,29 +213,23 @@ export class KeylayoutToKmnConverter { const parser = new XMLParser(options); const jsonObj = parser.parse(xmlFile); // get plain Object - // const duplicate_layouts_array: string[] = [] // array holding the layouts e.g. ANSI or JIS // needed?? I think no - // jsonObj now contains only arrays; no single fields boxArrays_S(jsonObj.keyboard); - // in case there always ANSI which is always keyMapSet[0] - // const keyMapSet_ANSI_count = 0 - // ......................................................... // MODIFIER MAP: get behaviours(=MapIndex) and modifiers (shift? leftShift caps? ) // ......................................................... for (let j = 0; j < jsonObj.keyboard.modifierMap.keyMapSelect.length; j++) { - const modifierMap_ONE_InKeymapSelect: string[] = [] + const singleModifierSet: string[] = [] for (let k = 0; k < jsonObj.keyboard.modifierMap.keyMapSelect[j].modifier.length; k++) { - modifierMap_ONE_InKeymapSelect.push(jsonObj.keyboard.modifierMap.keyMapSelect[j].modifier[k]['@_keys']) + singleModifierSet.push(jsonObj.keyboard.modifierMap.keyMapSelect[j].modifier[k]['@_keys']) } - modifierMap_ALL_KeyMapSelects.push(modifierMap_ONE_InKeymapSelect) + modifierBehaviors.push(singleModifierSet) } // Todo ? move to convert? // TODO review condition - // start to read other data return this.createRuleData(DataObject, jsonObj) } @@ -260,41 +253,10 @@ export class KeylayoutToKmnConverter { //TODO need to use export const USVirtualKeyCodes here public write(data_ukelele: convert_object): boolean { - // ************************************************************* - // **** write stores ******************************************* - // ************************************************************* let data = "\n" - data += "c\n" - data += "c Keyman keyboard generated by kmn-convert\n" - data += "c\n" + data += this.createDataToWrite(data_ukelele) data += "\n" - data += '\########## OK #################################################################\n' - data += "store(&VERSION) \'...\'\n" - data += "store(&TARGETS) \'any\'\n" - data += "store(&KEYBOARDVERSION) \'...\'\n" - data += "store(©RIGHT) '© 2024 SIL International\n" - // TODO what else ?? - - data += '\########## OK #################################################################\n' - data += "\n" - data += "begin Unicode > use(main)\n\n" - data += "group(main) using keys\n\n" - - data += '\########## OK #################################################################\n' - data += "Tipp: if K_? is replaced by undefined-> no enry in kmn_Key_Name=> add K_? there and it will be shown here\n" - data += "Tipp: keys that are marked with sction do not aoear in ukelele_Array_output->do not appear in kmn\n" - data += "\n" - - // ************************************************************* - // **** write rules ******************************************** - // ************************************************************* - - // if caps is used in .keylayout-file we need to add NCAPS in the kmn-file - - - data += this.writeLastPart(data_ukelele) + '\n' - /*writeFileSync("data/MyResult.kmn", data, { flag: "w" })*/ this.callbacks.fs.writeFileSync("data/MyResult.kmn", new TextEncoder().encode(data)) // not usable here since it takes UInt8array data @@ -307,13 +269,9 @@ export class KeylayoutToKmnConverter { data += '\n' } - - //... helpers ............................................................................................. - // TODO move outside of class? // ToDo keep only uint8array-version - // for more info about mapping and cases C0-C4 - // see https://docs.google.com/document/d/1ISjACTA9aUBueTo1AoKnOsI6QR5kXeeD_maI0XUyXqg/edit?tab=t.0 + // for more info about mapping and cases C0-C4 see https://docs.google.com/document/d/1ISjACTA9aUBueTo1AoKnOsI6QR5kXeeD_maI0XUyXqg/edit?tab=t.0 public createRuleData(data_ukelele: convert_object, jsonObj: any): convert_object { const DataArray_U8: Uint8Array[][] = [] @@ -323,16 +281,15 @@ export class KeylayoutToKmnConverter { const used_Keys_count = 51 const isCapsused = this.checkIfCapsUsed(data_ukelele.ArrayOf_Element_ModifierMaps_ALLKeyMapSelect) - // loop keys 0-50 (= all that we use) - //for (let j = 0; j < jsonObj.keyboard.keyMapSet[0].keyMap[i].key.length; j++) { + // loop keys 0-50 (= all keys we use) for (let j = 0; j < used_Keys_count; j++) { - // loop behaviors + // loop behaviors ( in ukelele it is possible to define multiple modifier combinations that behave the same) for (let i = 0; i < jsonObj.keyboard.keyMapSet[0].keyMap.length; i++) { // ...................................................................................................... // case C0: output ...................................................................................... - // a key is mapped to a character ( code-> output) ...................................................... + // a key is mapped to a character directly ( code-> output) ............................................. // ...............e. g. ...................................................... // ...................................................................................................... // in keys at top for code 1 (K_S) take output ("s") [italian copy] @@ -343,7 +300,7 @@ export class KeylayoutToKmnConverter { if (jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['@_output'] !== undefined) { output_id = jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['@_output'] - // loop modifiers + // loop modifier combinations for (let l = 0; l < data_ukelele.ArrayOf_Element_ModifierMaps_ALLKeyMapSelect[i].length; l++) { const DataArraySingleStateC0_U8: Uint8Array[] = [] @@ -363,29 +320,26 @@ export class KeylayoutToKmnConverter { } // ...................................................................................................... - // actions ............................................................................... + // case C1: action + state none + output ................................................................ + // a key is mapped to an action and then to an output ................................................... + // code->action->action(none)->action(output) ........................................................... + // ...............e. g. a // ...................................................................................................... - else if (jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['@_action'] !== undefined) { - // ...................................................................................................... - // case C1: action + state none + output .............................................................. - // a key is mapped to an action and then to an output ................................................... - // code->action->action(none)->action(output) ........................................................... - // ...............e. g. a - // ...................................................................................................... + action_id = jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['@_action'] const result_C1 = this.lookup_6_ActionNone__To__ActionOutput(jsonObj, action_id) const result_C1_U8 = new TextEncoder().encode(this.lookup_6_ActionNone__To__ActionOutput(jsonObj, action_id)) - // modifiers + // loop modifiers for (let l = 0; l < data_ukelele.ArrayOf_Element_ModifierMaps_ALLKeyMapSelect[i].length; l++) { const DataArraySingleStateC1_U8: Uint8Array[] = [] @@ -547,7 +501,7 @@ export class KeylayoutToKmnConverter { } } // ...................................................................................................... - // case C4: action + state none + Next ............................................................DONE . + // case C4: action + state none + Next .................................................................. // ...............e. g. ................................................... // a key is mapped to an action and then to a terminator ................................................ // code->action->action(none)->action(next)->terminator(output) ......................................... @@ -596,8 +550,6 @@ export class KeylayoutToKmnConverter { return data_ukelele } - - // public lookup_2_KeyMapAction__To__ActionAction() { } public lookup_3_ActionNone__To__ActionNext(data: any, search: string): string { for (let jj = 0; jj < data.keyboard.actions.action.length; jj++) { if (data.keyboard.actions.action[jj]['@_id'] === search) { @@ -609,7 +561,6 @@ export class KeylayoutToKmnConverter { } return "" } - //public lookup_4_ActionNext__To__ActionState() { } public lookup_5_ActionState__To__ActionNext(data: any, action_idName: string): string[] { const returnarray: string[] = [] // e.g. action_idName = 3 @@ -658,17 +609,6 @@ export class KeylayoutToKmnConverter { } return OutputValue } - //public lookup_7_ActionState__To__ActionOutput() { } - //public lookup_8_ActionNext__To__TerminatorState() { } - - public lookup_9_TerminatorState__To__TerminatorOutput_ui8(data: any, search: string): Uint8Array { - for (let jj = 0; jj < data.keyboard.terminators.when.length; jj++) { - if (data.keyboard.terminators.when[jj]['@_state'] === search) { - return new TextEncoder().encode(data.keyboard.terminators.when[jj]['@_output']); - } - } - return new TextEncoder().encode("") - } public lookup_9_TerminatorState__To__TerminatorOutput_str(data: any, search: string): string { let OutputValue = "" for (let jj = 0; jj < data.keyboard.terminators.when.length; jj++) { @@ -695,31 +635,6 @@ export class KeylayoutToKmnConverter { } return 999 } - public lookup_11_KeyMapAction__To__KeyIndex(data: any, search: string): number { - for (let kk = 0; kk < data.keyboard.keyMapSet[0].keyMap.length; kk++) { - for (let jj = 0; jj < data.keyboard.keyMapSet[0].keyMap[kk].key.length; jj++) { - if (data.keyboard.keyMapSet[0].keyMap[kk].key[jj]['@_action'] === search) { - return data.keyboard.keyMapSet[0].keyMap[kk]['@_index'] - } - } - } - return 999 - } - // get all entries that result in state 3 - public lookup_12_ActionNext__from__ActionState(data: any, search: string): string { - // loop all action - for (let jj = 0; jj < data.keyboard.actions.action.length; jj++) { - // loop all when - for (let kk = 0; kk < data.keyboard.actions.action[jj].when.length; kk++) { - // if next === a´search - if (data.keyboard.actions.action[jj].when[kk]['@_next'] === search) { - // return actionIDName - return data.keyboard.actions.action[jj]['@_id'] - } - } - } - return "" - } public lookup_13_ActionNext__To__ActionID(data: any, search: string) { for (let ll = 0; ll < data.keyboard.actions.action.length; ll++) { for (let mm = 0; mm < data.keyboard.actions.action[ll].when.length; mm++) { @@ -747,7 +662,6 @@ export class KeylayoutToKmnConverter { return mapIndexArray_max } - /** * @brief member function to return the unicode value of a character * @param character the value that will converted @@ -905,85 +819,19 @@ export class KeylayoutToKmnConverter { else return "" } - public useElementAsString(u18ArrayElemnent: Uint8Array): string { - return new TextDecoder().decode(u18ArrayElemnent) - } - public useAsString(u18ArrayElemnent: Uint8Array[]): string { - let str = "" - for (let i = 0; i < u18ArrayElemnent.length; i++) { - str = str + " " + new TextDecoder().decode(u18ArrayElemnent[i]) - } - return str - } //---------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------- - public writeLastPart(data_ukelele: convert_object): string { - // create a string array ....................................................... - const workArray2D: string[][] = [] - for (let k = 0; k < data_ukelele.ArrayOf_processed_RuleData.length; k++) { - const array1D: string[] = [] - for (let l = 0; l < data_ukelele.ArrayOf_processed_RuleData[k].length; l++) { - const u8data = data_ukelele.ArrayOf_processed_RuleData[k][l] - array1D.push(this.useElementAsString(u8data)) - } - workArray2D.push(array1D) - } - console.log("workArray2D ", workArray2D) + public createData_Deadkeys(data_ukelele: convert_object, workArray2D: string[][]): string { - //°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° - // FIRST PART RULES °° ( + [NCAPS K_S] > 's') °°°°°°°°°°°°°°°°°°°°° - //°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° let data: string = "" - - // select only lines that contain C0 or C1 and no empty fields. Also remove duplicates - const [uniqueDeadkeys_first] = workArray2D.reduce((acc, curr) => { - if ((curr[3] !== "") && ((curr[0] === "first_modifier_C0") || (curr[0] === "first_modifier_C1"))) { - const [uniq, set] = acc; - if (!set.has(curr.join(','))) { - set.add(curr.join(',')); - uniq.push(curr); - } - } - return acc; - }, [[], new Set()], - ); - - - let keymarker = "" - for (let kkk = 0; kkk < uniqueDeadkeys_first.length; kkk++) { - - // find key nr - let keyNr = 0; - for (let pp = 0; pp < 50; pp++) { - if (this.map_UkeleleKC_To_VK(pp) === uniqueDeadkeys_first[kkk][2]) - keyNr = pp - } - - // skip keyNr 48 ( TAB ) - if (keyNr === 48) - continue - - if (keymarker !== uniqueDeadkeys_first[kkk][2]) - data += '\n' - - data += keyNr + "-(modif:" + "ii" + "-" + "i" + `) + [` + (uniqueDeadkeys_first[kkk][1] + ' ' + uniqueDeadkeys_first[kkk][2]).trim() + `] > \'` + uniqueDeadkeys_first[kkk][3] + '\'\n' - keymarker = uniqueDeadkeys_first[kkk][2] - } - data += '\n' - console.log("data ", data) - - //°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° - // DEADKEY RULES °° ([RALT K_8] > dk(00B4) °°°°°°°°°°°°°°°°°°°°°°°° - //°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° - // filter for dk values data += '\########## OK #################################################################\n' data += '\nNOW MY C4 RULES **ccc ********* (only to get 02C6 ect) *********************\n\n' - // select only lines that contain isTerminator and remove duplicates + // select only lines that contain "isTerminator" and remove duplicates const [uniqueDeadkeys] = workArray2D.reduce((acc, curr) => { if (curr[4] === "isTerminator") { const [uniq, set] = acc; @@ -1002,43 +850,42 @@ export class KeylayoutToKmnConverter { data += line + '\n' } - //°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° - // DEADKEYABLE/DEADKEYED LIST (a,A,e,E) - (â,Â,ê,ê) °°°°°°°°°°°°°°° - //°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° - // we have 5 different types: - /* - C0: size: 4 ['first_modifier_C0', 'RIGHTSHIFT ', 'K_S', 'S' ] - C1: size: 4 ['first_modifier_C1', 'CAPS', 'K_N', 'N' ], - C2: size: 5 ['first_modifier_C2', 'CAPS', 'K_E', 'K_9', 'È' ], use 2.(K_E) and 4.('È') to get Name and DEADKEYED - C3: size: 6 ['first_modifier_C3', 'NCAPS RALT', 'K_8', 'NCAPS RALT', 'K_U', 'ˆ' ], - C4: size: 4 ['first_modifier_C4', 'NCAPS 0', 'K_SPACE', '' ], - C4: size: 7 ['first_modifier_C4', 'NCAPS RALT', 'K_N', '˜', 'isTerminator', '˜', '02DC '], use 2.(K_N) , 5. (isTerminator) and 6.('02DC') to get Name and DEADKEY in hex + + /* + How to create rules from keylayout data ffrom data_ukelele.ArrayOf_processed_RuleData: + + There are 6 different types of data entries (C0-C4) in data_ukelele.ArrayOf_processed_RuleData e.g. that contain all data to retrieve deadkeys, deadkeyables and deadkeyed characters: + + C0: (size: 4) ['first_modifier_C0', 'RIGHTSHIFT ', 'K_S', 'S' ] + C1: (size: 4) ['first_modifier_C1', 'CAPS', 'K_A', 'A' ], + C2: (size: 5) ['first_modifier_C2', 'CAPS', 'K_A', 'K_N', 'Ã' ], use 2.(K_A) and 4.('Ã') to get name and DEADKEYED + C3: (size: 6) ['first_modifier_C3', 'NCAPS RALT', 'K_8', 'NCAPS RALT', 'K_U', 'ˆ' ], + C4: (size: 4) ['first_modifier_C4', 'NCAPS 0', 'K_SPACE', '' ], + C4: (size: 7) ['first_modifier_C4', 'NCAPS RALT', 'K_N', '˜', 'isTerminator', '˜', '02DC '], use 2.(K_N) , 5. (isTerminator) and 6.('02DC') to get key name and DEADKEY in hex - Find DEADKEYABLE - 1) first_modifier_C1 CAPS K_A A - 2) first_modifier_C2 CAPS K_A K_EQUAL Â - 3) first_modifier_C2 CAPS K_A K_9 À - - Find C2 rule with Deadkeyed ( n = 5) - - get C1 rule with same second and third entries -> (first_modifier_C1 CAPS K_A) - - get 4th entry ===> DEADKEYABLE (e.g. A) + To Find a DEADKEY e.g. ^ + 1) look in modifier_C4 with 'isTerminator' included (n = 7) + 2) get 7th entry ===> DEADKEY (e.g. 02DC) + + To Find a DEADKEYABLE ( a character that can be converted to a deadkey e.g. A (-> Ã) ): + 1) first_modifier_C1 CAPS K_A A + 2) first_modifier_C2 CAPS K_A K_N Ã + - Find C2 rule with 5 entries (Deadkeyed) (e.g. first_modifier_C2 CAPS K_A K_N Ã) + - get C1 rule with same second and third entries -> (e.g. first_modifier_C1 CAPS K_A) + - get 2nd entry of C1 rule ===> DEADKEYABLE (e.g. A) - Find DEADKEY - 1) look in modifier_C4 (n = 7) - 2) get 7th entry ===> DEADKEY (e.g. 02DC) - - Find DEADKEYED - 1) look in modifier_C2 - 2) get 3rd entry (='K_A') - 3) get 5th entry ===> DEADKEYED (='Â') + To Find a DEADKEYED ( a character that has been converted from another character e.g. Ã ): + 1) look in modifier_C2 CAPS K_A K_N Ã + 2) get 3rd entry (='K_A') + 3) get 5th entry ===> DEADKEYED (='Ã') */ - // create deadkeyables_raw, deadkeyed_raw array let deadkeyables_raw: string[][] = [] let deadkeyed_raw: string[][] = [] - // find deadkeyable [ 'first_modifier_C1', 'CAPS', 'K_A', 'A', '', '', '' ] - deadkeyables_raw = workArray2D.filter(function ([A, B, C, D, E, F, G]) { + // find C1 line for deadkeyable [ 'first_modifier_C1', 'CAPS', 'K_A', 'A' ] + deadkeyables_raw = workArray2D.filter(function ([A, B, C, D]) { return ((A === "first_modifier_C1") /*&& (B === shiftstate) && (C === key_name)*/ && ((C !== "K_SPACE") && (D !== "")) ) @@ -1046,8 +893,8 @@ export class KeylayoutToKmnConverter { console.log("deadkeyables_raw", deadkeyables_raw.length, deadkeyables_raw) - // find deadkeyed [ 'first_modifier_C2', 'CAPS', 'K_A', 'K_N', 'Ã' ] - deadkeyed_raw = workArray2D.filter(function ([A, B, C, D, E, F, G]) { + // find C2 line for deadkeyed [ 'first_modifier_C2', 'CAPS', 'K_A', 'K_N', 'Ã' ] + deadkeyed_raw = workArray2D.filter(function ([A, B, C]) { return ((A === "first_modifier_C2")/* && (B === shiftstate) && (C === key_name)*/ && ((C !== "K_SPACE")) ) @@ -1055,27 +902,29 @@ export class KeylayoutToKmnConverter { console.log("deadkeyed_raw", deadkeyed_raw.length, deadkeyed_raw) - const join_dkable_dked: any[][] = [] - // loop dedkeyables, take Keyname + const dk_array_comlpete: any[][] = [] + + // create 2D array with data of both deadkeyables_raw, deadkeyed_raw and remove possible duplicates + + for (let rr = 0; rr < deadkeyables_raw.length; rr++) { - // loop dedkeyed, take Keyname + // loop deadkeyed_raw, take Keyname for (let ss = 0; ss < deadkeyed_raw.length; ss++) { - const dkable_dked_array: any[] = [] - //if available ( shiftstate the same, keyname the same) - if ((deadkeyables_raw[rr][1] === deadkeyed_raw[ss][1]) - && ((deadkeyables_raw[rr][2] === deadkeyed_raw[ss][2]))) { - dkable_dked_array.push(deadkeyables_raw[rr][3]) // deadkeyable e.g. a - dkable_dked_array.push(deadkeyed_raw[ss][3]) // Keyname dk e.g. K_EQUAL - dkable_dked_array.push(deadkeyed_raw[ss][4]) // deadkeyed e.g. â + const dk_array: any[] = [] + //if available ( if both have the same shiftstate and keyname) + if ((deadkeyables_raw[rr][1] === deadkeyed_raw[ss][1]) && ((deadkeyables_raw[rr][2] === deadkeyed_raw[ss][2]))) { + dk_array.push(deadkeyables_raw[rr][3]) // deadkeyable e.g. A + dk_array.push(deadkeyed_raw[ss][3]) // Keyname dk e.g. K_N + dk_array.push(deadkeyed_raw[ss][4]) // deadkeyed e.g. Ã } - if (dkable_dked_array.length > 0) - join_dkable_dked.push(dkable_dked_array) + if (dk_array.length > 0) + dk_array_comlpete.push(dk_array) } } - console.log("join_dkable_dked", join_dkable_dked.length, join_dkable_dked) + console.log("dk_array_comlpete", dk_array_comlpete.length, dk_array_comlpete) // remove duplicates - const [unique_join_dkable_dked] = join_dkable_dked.reduce((acc, curr) => { + const [unique_dk_array_comlpete] = dk_array_comlpete.reduce((acc, curr) => { const [uniq, set] = acc; if (!set.has(curr.join(','))) { set.add(curr.join(',')); @@ -1084,21 +933,22 @@ export class KeylayoutToKmnConverter { return acc; }, [[], new Set()], ); - console.log("unique_join_dkable_dked", unique_join_dkable_dked.length, unique_join_dkable_dked); + console.log("unique_join_dkable_dked", unique_dk_array_comlpete.length, unique_dk_array_comlpete); - // create 2dArray uniqueDeadkeys.length*unique_join_dkable_dked - const deadkeyedArray: string[][] = Array.from({ length: uniqueDeadkeys.length }, () => new Array(2).fill('')); - const deadkeyablesArray: string[][] = Array.from({ length: uniqueDeadkeys.length }, () => new Array(1).fill('')); + // deadkeyablesArray'a' 'A' 'e' 'E' 'y' 'Y' 'o' 'O' 'u' 'U' 'i' 'I' + // deadkeyedArray 'ä' 'Ä' 'ë' 'Ë' 'ÿ' 'Ÿ' 'ö' 'Ö' 'ü' 'Ü' 'ï' 'Ï' + const deadkeyedElement: string[][] = Array.from({ length: uniqueDeadkeys.length }, () => new Array(2).fill('')); + const deadkeyablesElement: string[][] = Array.from({ length: uniqueDeadkeys.length }, () => new Array(1).fill('')); for (let i = 0; i < uniqueDeadkeys.length; i++) { - for (let j = 0; j < unique_join_dkable_dked.length; j++) { + for (let j = 0; j < unique_dk_array_comlpete.length; j++) { - if (uniqueDeadkeys[i][2] === unique_join_dkable_dked[j][1]) { - deadkeyablesArray[i][0] = deadkeyablesArray[i][0] + "\'" + unique_join_dkable_dked[j][0] + "\' " - deadkeyedArray[i][0] = deadkeyedArray[i][0] + "\'" + unique_join_dkable_dked[j][2] + "\' " + if (uniqueDeadkeys[i][2] === unique_dk_array_comlpete[j][1]) { + deadkeyablesElement[i][0] = deadkeyablesElement[i][0] + "\'" + unique_dk_array_comlpete[j][0] + "\' " + deadkeyedElement[i][0] = deadkeyedElement[i][0] + "\'" + unique_dk_array_comlpete[j][2] + "\' " } } - deadkeyedArray[i][1] = (uniqueDeadkeys[i][6]) + deadkeyedElement[i][1] = (uniqueDeadkeys[i][6]) } data += "\n" @@ -1106,15 +956,153 @@ export class KeylayoutToKmnConverter { data += '\nmatch > use(deadkeys)\n\n' data += '\ngroup(deadkeys)\n\n' - // finally write out - for (let i = 0; i < deadkeyablesArray.length; i++) { - data += "\n\ndk: " + deadkeyedArray[i][1] - data += "\ndeadkeyablesArray" + deadkeyablesArray[i][0] - data += "\ndeadkeyedArray " + deadkeyedArray[i][0] + for (let i = 0; i < deadkeyablesElement.length; i++) { + data += "\n\ndk: " + deadkeyedElement[i][1] + data += "\ndeadkeyablesArray" + deadkeyablesElement[i][0] + data += "\ndeadkeyedArray " + deadkeyedElement[i][0] } return data } + public createData_Rules(data_ukelele: convert_object, workArray2D: string[][]): string { + const maxkey = 50 + let data: string = "" + let keymarker = "" + + // select only lines that contain C0 or C1 and create an output. Also remove duplicates + const [uniqueDeadkeys] = workArray2D.reduce((acc, curr) => { + if ((curr[3] !== "") && ((curr[0] === "first_modifier_C0") || (curr[0] === "first_modifier_C1"))) { + const [uniq, set] = acc; + if (!set.has(curr.join(','))) { + set.add(curr.join(',')); + uniq.push(curr); + } + } + return acc; + }, [[], new Set()], + ); + + for (let kkk = 0; kkk < uniqueDeadkeys.length; kkk++) { + // lookup key nr of the key that is being processed + let keyNr = 0; + for (let pp = 0; pp < maxkey; pp++) { + if (this.map_UkeleleKC_To_VK(pp) === uniqueDeadkeys[kkk][2]) + keyNr = pp + } + + // skip keyNr 48 ( TAB ) + if (keyNr === 48) + continue + + // add a line after rules of each key + if (uniqueDeadkeys[kkk][2] !== keymarker) + data += '\n' + + data += keyNr + "-(modif:" + "ii" + "-" + "i" + `) + [` + (uniqueDeadkeys[kkk][1] + ' ' + uniqueDeadkeys[kkk][2]).trim() + `] > \'` + uniqueDeadkeys[kkk][3] + '\'\n' + keymarker = uniqueDeadkeys[kkk][2] + } + + data += '\n' + console.log("data ", data) + + return data + } + + public createData_Stores(data_ukelele: convert_object): string { + let data: string = "" + + data += "c\n" + data += "c Keyman keyboard generated by kmn-convert\n" + data += "c\n" + data += "\n" + + data += '\########## OK #################################################################\n' + data += "store(&VERSION) \'...\'\n" + data += "store(&TARGETS) \'any\'\n" + data += "store(&KEYBOARDVERSION) \'...\'\n" + data += "store(©RIGHT) '© 2024 SIL International\n" + // TODO what else ?? + + data += '\########## OK #################################################################\n' + data += "\n" + data += "begin Unicode > use(main)\n\n" + data += "group(main) using keys\n\n" + + data += '\########## OK #################################################################\n' + data += "Tipp: if K_? is replaced by undefined-> no enry in kmn_Key_Name=> add K_? there and it will be shown here\n" + data += "Tipp: keys that are marked with sction do not aoear in ukelele_Array_output->do not appear in kmn\n" + data += "\n" + + return data + } + + public createDataToWrite(data_ukelele: convert_object): string { + + // create a string array to work with ................................................ + const workArray2D: string[][] = [] + for (let k = 0; k < data_ukelele.ArrayOf_processed_RuleData.length; k++) { + const array1D: string[] = [] + for (let l = 0; l < data_ukelele.ArrayOf_processed_RuleData[k].length; l++) { + const u8data = data_ukelele.ArrayOf_processed_RuleData[k][l] + array1D.push(new TextDecoder().decode(u8data)) + } + workArray2D.push(array1D) + } + console.log("workArray2D ", workArray2D) + + + let data: string = "" + data += this.createData_Stores(data_ukelele) + data += this.createData_Rules(data_ukelele, workArray2D) + data += this.createData_Deadkeys(data_ukelele, workArray2D) + return data + } + + // public lookup_2_KeyMapAction__To__ActionAction() { } + //public lookup_4_ActionNext__To__ActionState() { } + //public lookup_7_ActionState__To__ActionOutput() { } + //public lookup_8_ActionNext__To__TerminatorState() { } + /* public lookup_9_TerminatorState__To__TerminatorOutput_ui8(data: any, search: string): Uint8Array { + for (let jj = 0; jj < data.keyboard.terminators.when.length; jj++) { + if (data.keyboard.terminators.when[jj]['@_state'] === search) { + return new TextEncoder().encode(data.keyboard.terminators.when[jj]['@_output']); + } + } + return new TextEncoder().encode("") + }*/ + /*public lookup_11_KeyMapAction__To__KeyIndex(data: any, search: string): number { + for (let kk = 0; kk < data.keyboard.keyMapSet[0].keyMap.length; kk++) { + for (let jj = 0; jj < data.keyboard.keyMapSet[0].keyMap[kk].key.length; jj++) { + if (data.keyboard.keyMapSet[0].keyMap[kk].key[jj]['@_action'] === search) { + return data.keyboard.keyMapSet[0].keyMap[kk]['@_index'] + } + } + } + return 999 + }*/ + // get all entries that result in state 3 + /*public lookup_12_ActionNext__from__ActionState(data: any, search: string): string { + // loop all action + for (let jj = 0; jj < data.keyboard.actions.action.length; jj++) { + // loop all when + for (let kk = 0; kk < data.keyboard.actions.action[jj].when.length; kk++) { + // if next === a´search + if (data.keyboard.actions.action[jj].when[kk]['@_next'] === search) { + // return actionIDName + return data.keyboard.actions.action[jj]['@_id'] + } + } + } + return "" + }*/ + /* + public useAsString(u18ArrayElemnent: Uint8Array[]): string { + let str = "" + for (let i = 0; i < u18ArrayElemnent.length; i++) { + str = str + " " + new TextDecoder().decode(u18ArrayElemnent[i]) + } + return str + }*/ }