feat(developer): kmc-convert-first draft of read/convert/write using Uint8Array

This commit is contained in:
Sabine 2024-10-22 10:34:35 +02:00
parent cf29264e60
commit 632f2fc5ce
2 changed files with 173 additions and 64 deletions

View file

@ -77,6 +77,17 @@
<key code="27" output="ß"/>
<key code="47" output=""/>
</keyMap>
<!--anyShift caps? anyOption-->
<keyMap index="3">
<key code="0" output="A"/>
<key code="6" output="Y"/>
<key code="8" output="C"/>
<key code="11" output="B"/>
<key code="12" output="Q"/>
<key code="20" output="3"/>
<key code="27" output="ß"/>
<key code="47" output=""/>
</keyMap>
</keyMapSet>
<keyMapSet id="JIS">
<keyMap index="0" baseMapSet="ANSI" baseIndex="0">

View file

@ -21,6 +21,13 @@ export class KeylayoutToKmnConverter {
// be available as class properties
}
/**
* @brief run read/convert/write
* @param inputFilename the ukelele .keylayout-file to be converted
* @param outputFilename the resulting keyman .kmn-file
* @param binaryData ... _S2
* @return
*/
async run(inputFilename: string, outputFilename: string, binaryData: Uint8Array): Promise<ConverterToKmnArtifacts> {
if(!inputFilename || !outputFilename || !binaryData) {
@ -51,86 +58,101 @@ export class KeylayoutToKmnConverter {
throw new Error('Not finished yet');
}
// ............................................................................................................
// ............................................................................................................
// ............................................................................................................
/**
* @brief read filename ( a .keylayout-file) and write contents into Uint8Array keys_all_Layers
* @param filename the ukelele .keylayout-file to be converted
* @return in case of success Uint8Array keys_all_Layers; else null
*/
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 how to use names of shiftstates*/
/*
// _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?
*/
const options = {
ignoreAttributes: false,
attributeNamePrefix: '@_', // you have to assign this to use this to access the attribute
attributeNamePrefix: '@_', // to access the attribute
};
//xml file from https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ms762271(v=vs.85)
const xmlFile = readFileSync(`${process.cwd()}/data/MySample.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 = jsonObj.keyboard.keyMapSet[0].keyMap[0].key.length
const nrOfKeys_inLayer = jsonObj.keyboard.keyMapSet[0].keyMap[0].key.length
// create Object:any for storing Uint8tarray will be array[Uint8Array] Uint8Array might have several numbers (unicode)
const Keys_all_Layers :any[] = []
// 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
for (let j = 0; j < nrOfStates; j++) {
modifier_array[j] = jsonObj.keyboard.modifierMap.keyMapSelect[j].modifier['@_keys']
// create a new keys_in_Layer (type Uint8tarray)
const keys_in_Layer :Uint8Array[] = []
for (let i = 0; i < nrOfKeys; 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 ☺
const textencoder = new TextEncoder().encode(jsonObj.keyboard.keyMapSet[0].keyMap[j].key[i]['@_output' ]);
keys_in_Layer[i] = textencoder
}
const keys_single_Layer :Uint8Array[] = []
for (let i = 0; i < nrOfKeys_inLayer; 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' ]);
}
// add [nrOfStates] Objects:Uint8tarray to Keys_all_Layers
Keys_all_Layers[j] = keys_in_Layer
}
console.log(" _S2 read finished\n")
return(Keys_all_Layers.length === nrOfStates && Keys_all_Layers[0].length === nrOfKeys) ? Keys_all_Layers : null;
}
// ............................................................................................................
public convert(inArray: any[]):any[] {
const outArray :any[] = [];
const nrOfMaxKeys = 50
for (let j = 0; j < inArray.length ; j++) {
const outkeys_in_Layer :Uint8Array[] = []
// initialize keys
for (let i = 0; i < nrOfMaxKeys; i++) {
outkeys_in_Layer[i] = new TextEncoder().encode("\0");
}
// now convert
outkeys_in_Layer[0] = inArray[j][0];
outkeys_in_Layer[24] = inArray[j][1];
outkeys_in_Layer[2] = inArray[j][2];
outkeys_in_Layer[1] = inArray[j][3];
outkeys_in_Layer[16] = inArray[j][4];
outkeys_in_Layer[29] = inArray[j][5];
outkeys_in_Layer[38] = inArray[j][6];
outkeys_in_Layer[46] = inArray[j][7];
outArray[j] = outkeys_in_Layer
keys_all_Layers[j] = keys_single_Layer
}
console.log(" _S2 convert finished\n")
return (outArray.length === inArray.length ) ? outArray : null
// 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;
}
public write(writeArray: any[]):boolean {
/**
* @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
* @return outArray Uint8Array keys_all_Layers, the converted data for kmn-files if all layers have been converted; else null
*/
public convert(data_ukelele: any[]):any[] {
// sorting order: alphabetically OK?
const KeyArray = [
const data_kmn :any[] = [];
for (let j = 0; j < data_ukelele.length-1 ; j++) {
const keys_singleLayer :Uint8Array[] = []
// now convert & sort
keys_singleLayer[0] = data_ukelele[j][0];
keys_singleLayer[24] = data_ukelele[j][1];
keys_singleLayer[2] = data_ukelele[j][2];
keys_singleLayer[1] = data_ukelele[j][3];
keys_singleLayer[16] = data_ukelele[j][4];
keys_singleLayer[29] = data_ukelele[j][5];
keys_singleLayer[38] = data_ukelele[j][6];
keys_singleLayer[46] = data_ukelele[j][7];
// later more here...
data_kmn[j] = keys_singleLayer
}
//copy the modifier states
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
}
/** @brief write data to file
* @param kmn_array the array holding keyboard data
* @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',
'K_SPACE',
@ -156,16 +178,92 @@ public write(writeArray: any[]):boolean {
data += "group(main) using keys\n"
data += "\n"
for (let i = 0; i < writeArray.length; i++) {
for (let j = 0; j < writeArray[0].length; j++) {
const textdecoder = new TextDecoder().decode(writeArray[i][j])
if (textdecoder !== '\0' )
data += `+ [` + KeyArray[j] + `] > \'` + textdecoder +'\'\n'
for (let i = 0; i < kmn_array.length-1; 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])
// get the character that will be written as result in kmn-file
const resulting_character = new TextDecoder().decode(kmn_array[i][j])
// remove if-stmt later, only here for better visability
if (resulting_character !== '')
data += `+ [` + label_modifier + ' ' + kmn_Key_Name[j] + `] > \'` + resulting_character +'\'\n'
}
data += '\n'
}
writeFileSync("data/MyResult.kmn", data, { flag: "w"})
console.log(" _S2 write finished\n")
return true;
if( data.length > 0)
return true;
else
return false
}
}
/**
* @brief check if search_modifier is available in modifier_array
* @param search_modifier the value that will be searched for in modifier_array
* @param modifier_array the array holding all modifiers used
* @return true if search_modifier is found; false if not
*/
public isInArray(search_modifier:string, modifier_array: string[]):boolean {
for (let i =0; i < modifier_array.length; i++) {
if (search_modifier === String(modifier_array[i]))
return true
}
return false
}
/**
* @brief create modifier in kmn-style from modifier of .keylayout-file
* @param keylayout_modifier the modifier value used in the .keylayout-file
* @return kmn_modifier the modifier value used in the .kmn-file
*/
public create_modifier(keylayout_modifier:any):string {
let add_modifier = ""
let kmn_modifier = ""
// copy each modifier into element of array modifier_state
const modifier_state: string[] = keylayout_modifier.split(" ");
// TODO review these conditions-> what else do I need?
// TODO spelling entries of .keylayout( uppercase/lowercase, control<->ctrl,...)
// TODO anyOption?
// opt?+ LOPT?+ ROPT? -> what will be result??
for (let i = 0; i < modifier_state.length; i++) {
if ( String(modifier_state[i]) === "anyOption") add_modifier = "OPT "
else if ( String(modifier_state[i]) === "anyShift") add_modifier = "SHIFT "
else if ( String(modifier_state[i]) === "anyControl") add_modifier = "CTRL "
else if ( String(modifier_state[i]) === "anyOption?") add_modifier = "" // does anyOption?... happen?
else if ( String(modifier_state[i]) === "anyShift?") add_modifier = ""
else if ( String(modifier_state[i]) === "anyControl?") add_modifier = ""
else if( (String(modifier_state[i]) === "shift?" ) && this.isInArray('rshift',modifier_state)) add_modifier = "RSHIFT "
else if( (String(modifier_state[i]) === "shift?" ) && this.isInArray('lshift',modifier_state)) add_modifier = "LSHIFT "
else if( (String(modifier_state[i]) === "shift?" ) && this.isInArray('rshift',modifier_state) && this.isInArray('lshift',modifier_state)) add_modifier = "SHIFT "
else if( (String(modifier_state[i]) === "option?" ) && this.isInArray('rOption',modifier_state)) add_modifier = "ROPT "
else if( (String(modifier_state[i]) === "option?" ) && this.isInArray('lOption',modifier_state)) add_modifier = "LOPT "
else if( (String(modifier_state[i]) === "option?" ) && this.isInArray('rOption',modifier_state) && this.isInArray('lOption',modifier_state)) add_modifier = "OPT "
else if( (String(modifier_state[i]) === "ctrl?" ) && this.isInArray('rControl',modifier_state)) add_modifier = "RCTRL "
else if( (String(modifier_state[i]) === "ctrl?" ) && this.isInArray('lControl',modifier_state)) add_modifier = "LCTRL "
else if( (String(modifier_state[i]) === "ctrl?" ) && this.isInArray('rControl',modifier_state) && this.isInArray('lControl',modifier_state)) add_modifier = "CTRL "
else if( String(modifier_state[i]) === "caps?") add_modifier = "" // capital letters or not?
else if( String(modifier_state[i]) === "shift?") add_modifier = ""
else if( String(modifier_state[i]) === "ctrl?") add_modifier = ""
else add_modifier = String(modifier_state[i])
kmn_modifier += add_modifier
}
return kmn_modifier.trim().toUpperCase()
}
}