diff --git a/developer/src/kmc-kmn/src/kmw-compiler/constants.ts b/developer/src/kmc-kmn/src/kmw-compiler/constants.ts index 55bae9fdb90..1c41df145b8 100644 --- a/developer/src/kmc-kmn/src/kmw-compiler/constants.ts +++ b/developer/src/kmc-kmn/src/kmw-compiler/constants.ts @@ -1,3 +1,5 @@ +import { KMX } from "@keymanapp/common-types"; + export enum TRequiredKey { K_LOPT='K_LOPT', K_BKSP='K_BKSP', K_ENTER='K_ENTER' }; // I4447 @@ -8,9 +10,9 @@ export const // See also builder.js: specialCharacters; web/source/osk/oskKey.ts: specialCharacters export const CSpecialText10: string = '*Shift*\0*Enter*\0*Tab*\0*BkSp*\0*Menu*\0*Hide*\0*Alt*\0*Ctrl*\0*Caps*\0' + - '*ABC*\0*abc*\0*123*\0*Symbol*\0*Currency*\0*Shifted*\0*AltGr*\0*TabLeft*', + '*ABC*\0*abc*\0*123*\0*Symbol*\0*Currency*\0*Shifted*\0*AltGr*\0*TabLeft*\0', // these names were added in Keyman 14 - CSpecialText14: string = '*LTREnter*\0*LTRBkSp*\0*RTLEnter*\0*RTLBkSp*\0*ShiftLock*\0*ShiftedLock*\0*ZWNJ*\0*ZWNJiOS*\0*ZWNJAndroid*', + CSpecialText14: string = '*LTREnter*\0*LTRBkSp*\0*RTLEnter*\0*RTLBkSp*\0*ShiftLock*\0*ShiftedLock*\0*ZWNJ*\0*ZWNJiOS*\0*ZWNJAndroid*\0', CSpecialText14ZWNJ: string = '*ZWNJ*\0*ZWNJiOS*\0*ZWNJAndroid*', CSpecialText14Map: string[][] = [ ['*LTREnter*', '*Enter*'], @@ -21,9 +23,29 @@ export const ['*ShiftedLock*', '*Shifted*'], ['*ZWNJ*', '<|>'], ['*ZWNJiOS*', '<|>'], - ['*ZWNJAndroid*', '<|>'] + ['*ZWNJAndroid*', '<|>'], + ], + // these names were added in Keyman 17 + CSpecialText17: string = '*Sp*\0*NBSp*\0*NarNBSp*\0*EnQ*\0*EmQ*\0*EnSp*\0*EmSp*\0*PunctSp*\0' + + '*ThSp*\0*HSp*\0*ZWSp*\0*ZWJ*\0*WJ*\0*CGJ*\0*LTRM*\0*RTLM*\0*SH*\0*HTab*\0', + CSpecialText17ZWNJ: string = '*ZWNJGeneric*', + CSpecialText17Map: string[][] = [ + ['*ZWNJGeneric*', '<|>'] ]; + // Map for checking minimum versions and Special Text + export const CSpecialText = new Map([ + [KMX.KMXFile.VERSION_100, CSpecialText10], + // [KMX.KMXFile.VERSION_110, CSpecialText10], - this file version does not exist + // [KMX.KMXFile.VERSION_120, CSpecialText10], - this file version does not exist + // [KMX.KMXFile.VERSION_130, CSpecialText10], - this file version does not exist + [KMX.KMXFile.VERSION_140, CSpecialText14 + CSpecialText10], + [KMX.KMXFile.VERSION_150, CSpecialText14 + CSpecialText10], + [KMX.KMXFile.VERSION_160, CSpecialText14 + CSpecialText10], + [KMX.KMXFile.VERSION_170, CSpecialText17 + CSpecialText14 + CSpecialText10] + ]); + export const CSpecialTextMinVer = KMX.KMXFile.VERSION_100; + export const CSpecialTextMaxVer = KMX.KMXFile.VERSION_170; // These correspond to TSS_ values in kmx.ts export const diff --git a/developer/src/kmc-kmn/src/kmw-compiler/validate-layout-file.ts b/developer/src/kmc-kmn/src/kmw-compiler/validate-layout-file.ts index de335c088ba..dfde10772a8 100644 --- a/developer/src/kmc-kmn/src/kmw-compiler/validate-layout-file.ts +++ b/developer/src/kmc-kmn/src/kmw-compiler/validate-layout-file.ts @@ -1,7 +1,7 @@ import { KMX, Osk, TouchLayout, TouchLayoutFileReader, TouchLayoutFileWriter } from "@keymanapp/common-types"; -import { callbacks, IsKeyboardVersion14OrLater, IsKeyboardVersion15OrLater } from "./compiler-globals.js"; +import { callbacks, fk, IsKeyboardVersion14OrLater, IsKeyboardVersion15OrLater, IsKeyboardVersion17OrLater } from "./compiler-globals.js"; import { JavaScript_Key } from "./javascript-strings.js"; -import { TRequiredKey, CRequiredKeys, CSpecialText10, CSpecialText14, CSpecialText14ZWNJ, CSpecialText14Map } from "./constants.js"; +import { TRequiredKey, CRequiredKeys, CSpecialText, CSpecialText14Map, CSpecialText17Map, CSpecialTextMinVer, CSpecialTextMaxVer } from "./constants.js"; import { KeymanWebTouchStandardKeyNames, KMWAdditionalKeyNames, VKeyNames } from "./keymanweb-key-codes.js"; import { KmwCompilerMessages } from "./kmw-compiler-messages.js"; @@ -144,8 +144,9 @@ function CheckKey( // Keyman versions before 14 do not support '*special*' labels on non-special keys. // ZWNJ use, however, is safe because it will be transformed in function // TransformSpecialKeys14 to '<|>', which does not require the custom OSK font. - if((CSpecialText10.includes(FText) || CSpecialText14.includes(FText)) && - !CSpecialText14ZWNJ.includes(FText) && + const mapVersion = Math.max(Math.min(fk.fileVersion, CSpecialTextMaxVer), CSpecialTextMinVer); + const specialText = CSpecialText.get(mapVersion); + if(specialText.includes(FText) && !IsKeyboardVersion14OrLater() && !([TouchLayout.TouchLayoutKeySp.special, TouchLayout.TouchLayoutKeySp.specialActive].includes(FKeyType))) { callbacks.reportMessage(KmwCompilerMessages.Warn_TouchLayoutSpecialLabelOnNormalKey({ @@ -199,6 +200,22 @@ function TransformSpecialKeys14(FDebug: boolean, sLayoutFile: string): string { return sLayoutFile; } +function TransformSpecialKeys17(FDebug: boolean, sLayoutFile: string): string { + // Rewrite Special key labels that are only supported in Keyman 17+ + // This code is a little ugly but effective. + if(!IsKeyboardVersion17OrLater()) { + for(let i = 0; i < CSpecialText17Map.length; i++) { + // Assumes the JSON output format will not change + if(FDebug) { + sLayoutFile = sLayoutFile.replaceAll('"text": "'+CSpecialText17Map[i][0]+'"', '"text": this._v>16 ? "'+CSpecialText17Map[i][0]+'" : "'+CSpecialText17Map[i][1]+'"'); + } else { + sLayoutFile = sLayoutFile.replaceAll('"text":"'+CSpecialText17Map[i][0]+'"', '"text":this._v>16?"'+CSpecialText17Map[i][0]+'":"'+CSpecialText17Map[i][1]+'"'); + } + } + } + return sLayoutFile; +} + export function ValidateLayoutFile(fk: KMX.KEYBOARD, FDebug: boolean, sLayoutFile: string, sVKDictionary: string, displayMap: Osk.PuaMap): VLFOutput { // I4060 // I4139 let FDictionary: string[] = sVKDictionary.split(/\s+/); @@ -286,8 +303,10 @@ export function ValidateLayoutFile(fk: KMX.KEYBOARD, FDebug: boolean, sLayoutFil sLayoutFile = TransformSpecialKeys14(FDebug, sLayoutFile); + sLayoutFile = TransformSpecialKeys17(FDebug, sLayoutFile); + return { output: sLayoutFile, result } -} \ No newline at end of file +} diff --git a/developer/src/tike/xml/layoutbuilder/constants.js b/developer/src/tike/xml/layoutbuilder/constants.js index d79850bc23a..117020e5d51 100644 --- a/developer/src/tike/xml/layoutbuilder/constants.js +++ b/developer/src/tike/xml/layoutbuilder/constants.js @@ -551,8 +551,8 @@ $(function() { } this.lookupKeyNames.sort(); - // Defines the PUA code mapping for the various 'special' modifier/control keys on keyboards. - // This is lifted directly from visualKeyboard.ts and must be kept in sync. See also CompileKeymanWeb.pas: CSpecialText10 + // Defines the PUA code mapping for the various 'special' modifier/control/non-printing keys on keyboards. + // This is lifted directly from specialCharacters.ts and must be kept in sync. See also CompileKeymanWeb.pas: CSpecialText10 this.specialCharacters = { '*Shift*': 8, '*Enter*': 5, @@ -586,7 +586,9 @@ $(function() { '*RAltShift*': 0x68, '*LCtrlShift*': 0x69, '*RCtrlShift*': 0x70, - // Following codes introduced in Keyman 14.0 + // Added in Keyman 14.0 + '*LTREnter*': 0x05, // Default alias of '*Enter*'. + '*LTRBkSp*': 0x04, // Default alias of '*BkSp*'. '*RTLEnter*': 0x71, '*RTLBkSp*': 0x72, '*ShiftLock*': 0x73, @@ -594,8 +596,29 @@ $(function() { '*ZWNJ*': 0x75, // * If this one is specified, auto-detection will kick in. '*ZWNJiOS*': 0x75, // The iOS version will be used by default, but the '*ZWNJAndroid*': 0x76, // Android platform has its own default glyph. - '*LTREnter*': 5, // * Forces LTR shaping for the Enter/BkSp keys regardless - '*LTRBkSp*': 4, // of layout's directionality. + // Added in Keyman 17.0. + // Reference: https://github.com/silnrsi/font-symchar/blob/v4.000/documentation/encoding.md + '*ZWNJGeneric*': 0x79, // Generic version of ZWNJ (no override) + '*Sp*': 0x80, // Space + '*NBSp*': 0x82, // No-break Space + '*NarNBSp*': 0x83, // Narrow No-break Space + '*EnQ*': 0x84, // En Quad + '*EmQ*': 0x85, // Em Quad + '*EnSp*': 0x86, // En Space + '*EmSp*': 0x87, // Em Space + // TODO: Skipping #-per-em-space + '*PunctSp*': 0x8c, // Punctuation Space + '*ThSp*': 0x8d, // Thin Space + '*HSp*': 0x8e, // Hair Space + '*ZWSp*': 0x81, // Zero Width Space + '*ZWJ*': 0x77, // Zero Width Joiner + '*WJ*': 0x78, // Word Joiner + '*CGJ*': 0x7a, // Combining Grapheme Joiner + '*LTRM*': 0x90, // Left-to-right Mark + '*RTLM*': 0x91, // Right-to-left Mark + '*SH*': 0xa1, // Soft Hyphen + '*HTab*': 0xa2, // Horizontal Tabulation + // TODO: Skipping size references }; this.specialKeyNames = Object.entries(this.specialCharacters).map(ch => ch[0]); @@ -711,4 +734,4 @@ $(function() { return r; }; -}.bind(builder)); \ No newline at end of file +}.bind(builder)); diff --git a/developer/src/tike/xml/layoutbuilder/keymanweb-osk.ttf b/developer/src/tike/xml/layoutbuilder/keymanweb-osk.ttf index d33aedc35ef..e0651b14d4f 100644 Binary files a/developer/src/tike/xml/layoutbuilder/keymanweb-osk.ttf and b/developer/src/tike/xml/layoutbuilder/keymanweb-osk.ttf differ