From f21a7d3f1107cddd797ebfb9db618f15bc72d183 Mon Sep 17 00:00:00 2001 From: Sabine Date: Tue, 29 Oct 2024 10:44:37 +0100 Subject: [PATCH] feat(developer): kmc-convert-start to use deadkeys(read&map them from .ukelele file) --- .../keylayout-to-kmn-converter.ts | 176 +++++++++++++++--- .../test/test-keylayout-to-kmn-converter.ts | 4 +- 2 files changed, 152 insertions(+), 28 deletions(-) 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 37ff5422d6..0ee66a3d28 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 @@ -65,9 +65,9 @@ export class KeylayoutToKmnConverter { */ public read(filename: string):Uint8Array[] { /* - // _S2 TODO and what about deadkeys??? // _S2 TODO which format to use in output ? + [K_A] > 'a' (character code) or + [K_A] > U+0061 (virt Keycode) // _S2 which stores? + // _S2 use var a = document.getElementById("target"); */ const options = { @@ -75,42 +75,136 @@ export class KeylayoutToKmnConverter { attributeNamePrefix: '@_', // to access the attribute }; - const xmlFile = readFileSync(`${process.cwd()}/data/MySample.keylayout`, 'utf8'); + //const xmlFile = readFileSync(`${process.cwd()}/data/MySample.keylayout`, 'utf8'); + const xmlFile = readFileSync(`${process.cwd()}/data/My_dk_Keyboard.keylayout`, 'utf8'); const parser = new XMLParser(options); const jsonObj = parser.parse(xmlFile); // get plain Object const nrOfStates = jsonObj.keyboard.keyMapSet[0].keyMap.length - const nrOfKeys_inLayer = jsonObj.keyboard.keyMapSet[0].keyMap[0].key.length + const nrOfKeys_inLayer = jsonObj.keyboard.keyMapSet[0].keyMap[0].key.length // will all have the same length later - // create Object:any for storing Uint8tarray will be array[Uint8Array] Uint8Array might have several numbers (unicode) - // all keys for all layers - const keys_all_Layers :any[] = [] - const modifier_array: any[] = [] // why not put modifiers into Uint8Array along with values of keys of layer + const modifier_array: any[] = [] // array holding all MODIFIER strings e.g. "anyShift caps anyOption" -why not put modifiers into Uint8Array along with values of keys of layer + const keys_action_all_Layers :any[] = [] // array holding all values with ACTION attribute (needed for finding deadkeys) + const deadkeys_all_Layers :any[] = [] // array holding all DEADKEYS for each mod state â, ê, ,.... + const data_all_Layers :any[] = [] // array holds ALL DATA: keys, output, action, dedkeys,... + // loop through all ss-combin for (let j = 0; j < nrOfStates; j++) { - + // get modifier list e.g. "anyshift caps? anyOption" modifier_array[j] = jsonObj.keyboard.modifierMap.keyMapSelect[j].modifier['@_keys'] - // create a new keys_in_Layer (type Uint8tarray) - const keys_single_Layer :Uint8Array[] = [] + // create a new array of keys_in_Layer (type Uint8tarray) + const keys_output_One_Layer :Uint8Array[] = [] + const keys_action_One_Layer :Uint8Array[] = [] - for (let i = 0; i < nrOfKeys_inLayer; i++) { + // ......................................................... + // get all keys for attribute "output" ( y,c,b,...) + // ......................................................... + for (let i = 0; i < jsonObj.keyboard.keyMapSet[0].keyMap[j].key.length; i++) { if(jsonObj.keyboard.keyMapSet[0].keyMap[j].key[i]['@_output'] !== "\0" ) { // textencoder converts string -> bytes ( 'A' -> [ 65 ], '☺' -> [ 226, 152, 186 ]) // textencoder is of Uint8Array(1) for A and Uint8Array(3) for ☺ - keys_single_Layer[i] = new TextEncoder().encode(jsonObj.keyboard.keyMapSet[0].keyMap[j].key[i]['@_output' ]); + keys_output_One_Layer[i] = new TextEncoder().encode(jsonObj.keyboard.keyMapSet[0].keyMap[j].key[i]['@_output' ]); + } + + // ......................................................... + // get all keys for attribute "action" ( ^,a,e,i,...) + // ......................................................... + if(jsonObj.keyboard.keyMapSet[0].keyMap[j].key[i]['@_action'] !== "\0" ) { + keys_action_One_Layer[i] = new TextEncoder().encode(jsonObj.keyboard.keyMapSet[0].keyMap[j].key[i]['@_action' ]); } } - - keys_all_Layers[j] = keys_single_Layer + // ......................................................... + // create array of "action" and array of "output" + // ......................................................... + data_all_Layers[j] = keys_output_One_Layer // save all @output data ( will be used for conversion, write...) + keys_action_all_Layers[j] = keys_action_One_Layer // save all @action data ( will be used for deadkeys) } - // add the modifiers-> better idea? - keys_all_Layers[nrOfStates] = modifier_array - // Keys_all_Layers needs to have nrOfStates entries + 1 for modifiers - return((keys_all_Layers.length === nrOfStates + 1) && keys_all_Layers[0].length === nrOfKeys_inLayer) ? keys_all_Layers : null; + console.log('modifiers: ', modifier_array) + console.log('********************************************************') + // ......................................................... + // create array of "deadkey" / "deadkey names" + // ......................................................... + const dk_vec2d:string[][] = [] + for (let jj= 0; jj< jsonObj.keyboard.actions.action.length; jj++ ) { + // if there is a "next" attribute-> it is a dk + if(jsonObj.keyboard.actions.action[jj].when['@_next'] !== undefined ) { + const vec1d:string[] = [] + vec1d.push(jsonObj.keyboard.actions.action[jj].when['@_next']) + vec1d.push(jsonObj.keyboard.actions.action[jj]['@_id']) + dk_vec2d.push(vec1d) + } + } + console.log('dk_vec2d',dk_vec2d ) + console.log('********************************************************') + + // ......................................................... + // create array of deadkey base ^ ´ ` + // ......................................................... + const dk :string[] = []; + for ( let k=0; k < dk_vec2d.length; k++) { + dk.push(dk_vec2d[k][1] ) + } + console.log('dk: ', dk) + console.log('********************************************************') + + // ......................................................... + // create array of "deadkeyables" + // ......................................................... + const deadkeyables :string[][]=[] + for ( let j=0; j plain deadkeyables ( a,^, e,i,´,u => a,e,i,u) + deadkeyables[j] = deadkeyables[j].filter( function( el ) { + return dk.indexOf( el ) < 0; + }); + } + console.log('deadkeyables per modifier state: ', deadkeyables) + console.log('********************************************************') + + // ......................................................... + // create deadkeys-array + // ......................................................... + // for all 'dk' + for ( let k=0; k '^' ) + data_all_Layers.push(dk) // add plain dk ( '^', '´','`') + data_all_Layers.push(deadkeyables) // add char that can be modified with dk ( a,e,i,o,u) + data_all_Layers.push(deadkeys_all_Layers) // add modified keys ( â,ê,î,ô,û) + + return data_all_Layers + return((data_all_Layers.length === nrOfStates + 5) && data_all_Layers[0].length === nrOfKeys_inLayer) ? data_all_Layers : null; } +/*public fill_singleLayer_AllKeys(index_kmn:any):any { + + return kk.index_kmn +}*/ /** * @brief convert data of .keylayout-file to kmn-file This will convert/rename modifiers, position of Keys and deadkeys and save into an array * @param data_ukelele (Uint8Array) data of the ukelele .keylayout-file @@ -121,7 +215,7 @@ export class KeylayoutToKmnConverter { const data_kmn :any[] = []; - for (let j = 0; j < data_ukelele.length-1 ; j++) { + for (let j = 0; j < data_ukelele.length-5 ; j++) { const keys_singleLayer :Uint8Array[] = [] // now convert & sort @@ -139,14 +233,21 @@ export class KeylayoutToKmnConverter { // keyman VK-code == mac VK // later more here... + //console.log("data_ukelele[j][1]", data_ukelele[0][1] , '--> keys_singleLayer[24]',keys_singleLayer[24] ) data_kmn[j] = keys_singleLayer } - //copy the modifier states + //copy the modifier states __ better idea? + //data_kmn[data_ukelele.length - 1] = data_ukelele[data_ukelele.length - 1] + data_kmn[data_ukelele.length - 5] = data_ukelele[data_ukelele.length - 5] + data_kmn[data_ukelele.length - 4] = data_ukelele[data_ukelele.length - 4] + data_kmn[data_ukelele.length - 3] = data_ukelele[data_ukelele.length - 3] + data_kmn[data_ukelele.length - 2] = data_ukelele[data_ukelele.length - 2] data_kmn[data_ukelele.length - 1] = data_ukelele[data_ukelele.length - 1] //console.log(" _S2 convert finished\n", data_kmn) - return (data_kmn.length === data_ukelele.length ) ? data_kmn : null + return data_kmn + //return (data_kmn.length === data_ukelele.length ) ? data_kmn : null } /** @brief write data to file @@ -154,6 +255,7 @@ export class KeylayoutToKmnConverter { * @return true if data has been written; false if not */ public write(kmn_array: any[]):boolean { + const kmn_Key_Name = [ 'K_A','K_B','K_C','K_D','K_E','K_F','K_G','K_H','K_I','K_J','K_K','K_L','K_M','K_N','K_O','K_P','K_Q','K_R','K_S','K_T','K_U','K_V','K_W','K_X','K_Y','K_Z', 'K_0','K_1','K_2','K_3','K_4','K_5','K_6','K_7','K_8','K_9', @@ -165,6 +267,9 @@ export class KeylayoutToKmnConverter { 'K_xDF', 'K_OEM_102' ] + // ************************************************************* + // **** write stores ******************************************* + // ************************************************************* let data = "\n" data += "c\n" data += "c Keyman keyboard generated by kmn-convert\n" @@ -180,19 +285,25 @@ export class KeylayoutToKmnConverter { data += "group(main) using keys\n" data += "\n" + // ************************************************************* + // **** write rules ******************************************** + // ************************************************************* // if caps is used we need to add NCAPS in kmn-file + console.log("kmn_array",kmn_array) let isCAPSused = false for (let i= 0 ; i < kmn_array[kmn_array.length-1].length; i++) { - if( String((kmn_array[kmn_array.length-1][i]).indexOf("caps") !== -1 ) ) { + if ( String((kmn_array[kmn_array.length-1][i]).indexOf("caps") !== -1 ) ) { isCAPSused = true } } - for (let i = 0; i < kmn_array.length-1; i++) { + //for (let i = 0; i < kmn_array.length-1; i++) { + for (let i = 0; i < kmn_array.length-5; i++) { for (let j = 0; j < kmn_array[0].length; j++) { // get the modifier for the layer - const label_modifier = this.create_modifier(kmn_array[kmn_array.length-1][i], isCAPSused) + //const label_modifier = this.create_modifier(kmn_array[kmn_array.length-1][i], isCAPSused) + const label_modifier = this.create_modifier(kmn_array[kmn_array.length-5][i], isCAPSused) // get the character that will be written as result in kmn-file const resulting_character = new TextDecoder().decode(kmn_array[i][j]) @@ -201,10 +312,23 @@ export class KeylayoutToKmnConverter { if (resulting_character !== '') data += `+ [` + label_modifier + ' ' + kmn_Key_Name[j] + `] > \'` + resulting_character +'\'\n' } - data += '\n' } + // ************************************************************* + // **** write deadkeys ***************************************** + // ************************************************************* + // val vk dk + /*+ [K_BKQUOTE] > dk(005e) + + + [K_EQUAL] > dk(00b4) + + [SHIFT K_EQUAL] > dk(0060)*/ + + data += "match > use(deadkeys)\n\n" + data += "group(deadkeys)\n" + data += "store(" + ".....)\n" + data += '\n' + writeFileSync("data/MyResult.kmn", data, { flag: "w"}) console.log(" _S2 write finished\n") @@ -295,4 +419,4 @@ export class KeylayoutToKmnConverter { } return unique_Modifier.join(" ").replace(/\s+/g, " ").trim().toUpperCase() } -} +} \ No newline at end of file diff --git a/developer/src/kmc-convert/test/test-keylayout-to-kmn-converter.ts b/developer/src/kmc-convert/test/test-keylayout-to-kmn-converter.ts index bfacef2f97..dbe813f0dc 100644 --- a/developer/src/kmc-convert/test/test-keylayout-to-kmn-converter.ts +++ b/developer/src/kmc-convert/test/test-keylayout-to-kmn-converter.ts @@ -33,9 +33,9 @@ describe('KeylayoutToKmnConverter', function() { it('should throw on all elements loaded', async function () { // some keys, no deadkeys - const inputFilename = makePathToFixture('../data/Mysample.keylayout'); + //const inputFilename = makePathToFixture('../data/Mysample.keylayout'); // all keys, some deadkeys - //const inputFilename = makePathToFixture('../data/My_dk_Keyboard.keylayout'); + const inputFilename = makePathToFixture('../data/My_dk_Keyboard.keylayout'); const outputFilename = makePathToFixture('../data/MyResult.kmn');