From 8f20507a8237c576ca745df2ec8e3c7ea4991c95 Mon Sep 17 00:00:00 2001 From: Ross Date: Fri, 14 Apr 2023 13:59:49 +1000 Subject: [PATCH 001/214] chore(windows): remove legacy core and flag Removing the legacy code that was replaced by the core. Also removing the feature flag for core integeration. --- windows/src/engine/keyman32/K32_load.cpp | 39 +- windows/src/engine/keyman32/appint/aiTIP.cpp | 165 +---- windows/src/engine/keyman32/appint/aiTIP.h | 5 - windows/src/engine/keyman32/calldll.cpp | 315 +++------ windows/src/engine/keyman32/calldll.h | 2 +- windows/src/engine/keyman32/globals.h | 1 - windows/src/engine/keyman32/glossary.cpp | 32 +- windows/src/engine/keyman32/k32_globals.cpp | 8 - .../src/engine/keyman32/keyboardoptions.cpp | 89 --- windows/src/engine/keyman32/keyman32.cpp | 89 ++- windows/src/engine/keyman32/keymanengine.h | 5 - .../src/engine/keyman32/kmhook_getmessage.cpp | 23 +- windows/src/engine/keyman32/kmprocess.cpp | 667 +----------------- .../src/engine/keyman32/preservedkeymap.cpp | 110 +-- .../src/engine/keyman32/selectkeyboard.cpp | 88 +-- 15 files changed, 238 insertions(+), 1400 deletions(-) diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index 190cf53e79..ed2889b375 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -75,9 +75,9 @@ BOOL GetKeyboardFileName(LPSTR kbname, LPSTR buf, int nbuf) return n; } -BOOL LoadlpKeyboardCore(int i) +BOOL LoadlpKeyboard(int i) { - SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboardCore: Enter ---"); + SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboard: Enter ---"); PKEYMAN64THREADDATA _td = ThreadGlobals(); if (!_td) return FALSE; @@ -85,7 +85,7 @@ BOOL LoadlpKeyboardCore(int i) if (_td->lpActiveKeyboard == &_td->lpKeyboards[i]) _td->lpActiveKeyboard = NULL; // I822 TSF not working if (_td->lpKeyboards[i].lpCoreKeyboardState) { - SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboardCore: a keyboard km_kbp_state exits without matching keyboard - disposing of state"); + SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboard: a keyboard km_kbp_state exits without matching keyboard - disposing of state"); km_kbp_state_dispose(_td->lpKeyboards[i].lpCoreKeyboardState); _td->lpKeyboards[i].lpCoreKeyboardState = NULL; } @@ -95,7 +95,7 @@ BOOL LoadlpKeyboardCore(int i) PWCHAR keyboardPath = strtowstr(buf); km_kbp_status err_status = km_kbp_keyboard_load(keyboardPath, &_td->lpKeyboards[i].lpCoreKeyboard); if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboardCore: km_kbp_keyboard_load failed for %ls with error status [%d]", keyboardPath, err_status); + SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboard: km_kbp_keyboard_load failed for %ls with error status [%d]", keyboardPath, err_status); delete keyboardPath; return FALSE; } @@ -104,7 +104,7 @@ BOOL LoadlpKeyboardCore(int i) km_kbp_option_item *core_environment = nullptr; if(!SetupCoreEnvironment(&core_environment)) { - SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboardCore: Unable to set environment options for keyboard %ls", keyboardPath); + SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboard: Unable to set environment options for keyboard %ls", keyboardPath); return FALSE; } @@ -114,7 +114,7 @@ BOOL LoadlpKeyboardCore(int i) if (err_status != KM_KBP_STATUS_OK) { SendDebugMessageFormat( - 0, sdmLoad, 0, "LoadlpKeyboardCore: km_kbp_state_create failed with error status [%d]", err_status); + 0, sdmLoad, 0, "LoadlpKeyboard: km_kbp_state_create failed with error status [%d]", err_status); // Dispose of the keyboard to leave us in a consistent state ReleaseKeyboardMemoryCore(&_td->lpKeyboards[i].lpCoreKeyboard); return FALSE; @@ -122,38 +122,15 @@ BOOL LoadlpKeyboardCore(int i) // Register callback? err_status = km_kbp_keyboard_get_imx_list(_td->lpKeyboards[i].lpCoreKeyboard, &_td->lpKeyboards[i].lpIMXList); if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboardCore: km_kbp_keyboard_get_imx_list failed with error status [%d]", err_status); + SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboard: km_kbp_keyboard_get_imx_list failed with error status [%d]", err_status); // Dispose of the keyboard to leave us in a consistent state ReleaseKeyboardMemoryCore(&_td->lpKeyboards[i].lpCoreKeyboard); return FALSE; } - LoadDLLsCore(&_td->lpKeyboards[i]); - - LoadKeyboardOptionsREGCore(&_td->lpKeyboards[i], _td->lpKeyboards[i].lpCoreKeyboardState); - - return TRUE; -} - -BOOL LoadlpKeyboard(int i) -{ - if (Globals::get_CoreIntegration()) - { - return LoadlpKeyboardCore(i); - } - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - if(_td->lpKeyboards[i].Keyboard) return TRUE; - if(_td->lpActiveKeyboard == &_td->lpKeyboards[i]) _td->lpActiveKeyboard = NULL; // I822 TSF not working - - char buf[256]; - if(!GetKeyboardFileName(_td->lpKeyboards[i].Name, buf, 255)) return FALSE; - - if(!LoadKeyboard(buf, &_td->lpKeyboards[i].Keyboard)) return FALSE; // I5136 - LoadDLLs(&_td->lpKeyboards[i]); - LoadKeyboardOptions(&_td->lpKeyboards[i]); + LoadKeyboardOptionsREGCore(&_td->lpKeyboards[i], _td->lpKeyboards[i].lpCoreKeyboardState); return TRUE; } diff --git a/windows/src/engine/keyman32/appint/aiTIP.cpp b/windows/src/engine/keyman32/appint/aiTIP.cpp index 23240b2a06..d90a85068d 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.cpp +++ b/windows/src/engine/keyman32/appint/aiTIP.cpp @@ -126,7 +126,6 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM BOOL isUp = keyFlags & KF_UP ? TRUE : FALSE; BOOL extended = keyFlags & KF_EXTENDED ? TRUE : FALSE; BYTE scan = keyFlags & 0xFF; - BOOL isUsingCoreProcessor = Globals::get_CoreIntegration(); SendDebugMessageFormat(0, sdmAIDefault, 0, "TIPProcessKey: Enter VirtualKey=%s lParam=%x IsUp=%d Extended=%d Updateable=%d Preserved=%d", Debug_VirtualKey((WORD) wParam), lParam, isUp, extended, Updateable, Preserved); @@ -163,72 +162,31 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM // core processor. The core processor has the keyboard Caps Lock stores and will // queue an action 'KM_KBP_IT_CAPSLOCK'. In processing the action the Windows engine will synthesise keystrokes // to ensure caps lock is in the correct state. - if (isUsingCoreProcessor) { - if (!Preserved) { - switch (wParam) { - case VK_MENU: - case VK_CONTROL: - ProcessModifierChange((UINT)wParam, isUp, extended); - return FALSE; - case VK_NUMLOCK: + if (!Preserved) { + switch (wParam) { + case VK_MENU: + case VK_CONTROL: + ProcessModifierChange((UINT)wParam, isUp, extended); + return FALSE; + case VK_NUMLOCK: + if (!isUp) + ProcessToggleChange((UINT)wParam); // I4793 + return FALSE; + case VK_CAPITAL: if (!isUp) - ProcessToggleChange((UINT)wParam); // I4793 - return FALSE; - case VK_CAPITAL: - if (!isUp) - ProcessToggleChange((UINT)wParam); // I4793 - break; - case VK_SHIFT: - ProcessModifierChange((UINT)wParam, isUp, extended); + ProcessToggleChange((UINT)wParam); // I4793 break; - } - } else { - // Mask out Ctrl, Shift and Alt and include new modifiers // I4548 - DWORD NewShiftState = TSFShiftToShift(lParam); // I3588 - SendDebugMessageFormat( - 0, sdmGlobal, 0, "TIPProcessKey: TSFShiftToShift start with %x, include %x", LocalShiftState, NewShiftState); - *Globals::ShiftState() = (LocalShiftState & K_NOTMODIFIERFLAG) | NewShiftState; // I3588 - } - } else { // using windows processor TODO: #5442 Remove this else block - if (!Preserved) { - switch (wParam) { - case VK_CAPITAL: - if (!isUp) - ProcessToggleChange((UINT)wParam); // I4793 - if (!Updateable) { - // We only want to process the Caps Lock key event once -- - // in the first pass (!Updateable). - KeyCapsLockPress(isUp); // I4548 - } - return FALSE; - case VK_SHIFT: - if (!Updateable) { - // We only want to process the Shift key event once -- - // in the first pass (!Updateable). - KeyShiftPress(isUp); // I4548 - } - // Fall through - case VK_MENU: - case VK_CONTROL: - ProcessModifierChange((UINT)wParam, isUp, extended); - return FALSE; - case VK_NUMLOCK: - if (!isUp) - ProcessToggleChange((UINT)wParam); // I4793 - return FALSE; - } - // This would only get here if none of the above cases matched why not use default in the switch? - if (isUp) { - return FALSE; // return value ignored in this case; we only needed it for testing anyway - } - } else { - // Mask out Ctrl, Shift and Alt and include new modifiers // I4548 - DWORD NewShiftState = TSFShiftToShift(lParam); // I3588 - SendDebugMessageFormat( - 0, sdmGlobal, 0, "TIPProcessKey: TSFShiftToShift start with %x, include %x", LocalShiftState, NewShiftState); - *Globals::ShiftState() = (LocalShiftState & K_NOTMODIFIERFLAG) | NewShiftState; // I3588 + case VK_SHIFT: + ProcessModifierChange((UINT)wParam, isUp, extended); + break; } - } // TODO: #5442 Remove this else block ^^ + } else { + // Mask out Ctrl, Shift and Alt and include new modifiers // I4548 + DWORD NewShiftState = TSFShiftToShift(lParam); // I3588 + SendDebugMessageFormat( + 0, sdmGlobal, 0, "TIPProcessKey: TSFShiftToShift start with %x, include %x", LocalShiftState, NewShiftState); + *Globals::ShiftState() = (LocalShiftState & K_NOTMODIFIERFLAG) | NewShiftState; // I3588 + } _td->TIPFUpdateable = Updateable; _td->TIPFPreserved = Preserved; // I4290 @@ -239,16 +197,7 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM _td->state.vkey = (WORD) wParam; _td->state.isDown = !isUp; - if (isUsingCoreProcessor) { - _td->state.lpCoreKb = _td->lpActiveKeyboard->lpCoreKeyboard; - - } else { - _td->state.lpkb = _td->lpActiveKeyboard->Keyboard; - _td->state.startgroup = &_td->state.lpkb->dpGroupArray[_td->state.lpkb->StartGroup[BEGIN_UNICODE]]; - _td->state.NoMatches = TRUE; - _td->state.LoopTimes = 0; - _td->state.StopOutput = FALSE; - } + _td->state.lpCoreKb = _td->lpActiveKeyboard->lpCoreKeyboard; _td->state.windowunicode = TRUE; @@ -257,30 +206,8 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM _td->TIPProcessOutput = outfunc; _td->TIPGetContext = ctfunc; - AppContextWithStores *savedContext = NULL; // I4370 // I4978 - - if (!Updateable) { - // The core processor km_kbp_process_event is only called once per key stroke - // therefore there is no need to preserve context and keyboard actions - if (!isUsingCoreProcessor) { - savedContext = new AppContextWithStores(_td->lpActiveKeyboard->Keyboard->cxStoreArray); // I4370 // I4978 - _td->app->SaveContext(savedContext); - } - } - BOOL res = ProcessHook(); - if (!Updateable) { - if (!isUsingCoreProcessor) { - if (res) { // I4585 // I4370 - // Reset the context if match found - _td->app->RestoreContext(savedContext); - delete savedContext; - savedContext = NULL; - } - } - } - _td->TIPProcessOutput = NULL; _td->TIPGetContext = NULL; @@ -452,52 +379,6 @@ AppContextWithStores::~AppContextWithStores() { // I4978 delete KeyboardOptions; } -void AITIP::SaveContext(AppContextWithStores *savedContext) { // I4370 // I4978 - savedContext->CopyFrom(context); - - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td || !_td->lpActiveKeyboard || !_td->lpActiveKeyboard->Keyboard) return; - - assert(savedContext->nKeyboardOptions == _td->lpActiveKeyboard->Keyboard->cxStoreArray); - - for(DWORD i = 0; i < savedContext->nKeyboardOptions; i++) { // I4978 - if(_td->lpActiveKeyboard->KeyboardOptions[i].Value != NULL) { - savedContext->KeyboardOptions[i].Value = new WCHAR[wcslen(_td->lpActiveKeyboard->KeyboardOptions[i].Value)+1]; - wcscpy_s(savedContext->KeyboardOptions[i].Value, wcslen(_td->lpActiveKeyboard->KeyboardOptions[i].Value)+1, _td->lpActiveKeyboard->KeyboardOptions[i].Value); - } - } -} - -void AITIP::RestoreContext(AppContextWithStores *savedContext) { // I4370 // I4978 - context->CopyFrom(savedContext); - - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td || !_td->lpActiveKeyboard || !_td->lpActiveKeyboard->Keyboard) return; - LPINTKEYBOARDINFO kp = _td->lpActiveKeyboard; - - assert(savedContext->nKeyboardOptions == kp->Keyboard->cxStoreArray); - - for(DWORD i = 0; i < savedContext->nKeyboardOptions; i++) { // I4978 - if(kp->KeyboardOptions[i].Value == NULL && savedContext->KeyboardOptions[i].Value != NULL) { - // Restore the previously saved value as it was reset - kp->KeyboardOptions[i].OriginalStore = kp->Keyboard->dpStoreArray[i].dpString; - kp->Keyboard->dpStoreArray[i].dpString = kp->KeyboardOptions[i].Value = savedContext->KeyboardOptions[i].Value; - savedContext->KeyboardOptions[i].Value = NULL; - } else if(kp->KeyboardOptions[i].Value != NULL && savedContext->KeyboardOptions[i].Value == NULL) { - // Clear the newly saved value back to the default - delete kp->KeyboardOptions[i].Value; - kp->KeyboardOptions[i].Value = NULL; - kp->Keyboard->dpStoreArray[i].dpString = kp->KeyboardOptions[i].OriginalStore; - } else if(kp->KeyboardOptions[i].Value != NULL && savedContext->KeyboardOptions[i].Value != NULL && - wcscmp(kp->KeyboardOptions[i].Value, savedContext->KeyboardOptions[i].Value) != 0) { - // Restore the previously saved value as it was changed - delete kp->KeyboardOptions[i].Value; - kp->Keyboard->dpStoreArray[i].dpString = kp->KeyboardOptions[i].Value = savedContext->KeyboardOptions[i].Value; - savedContext->KeyboardOptions[i].Value = NULL; - } - } -} - void AITIP::CopyContext(AppContext *savedContext) { savedContext->CopyFrom(context); } diff --git a/windows/src/engine/keyman32/appint/aiTIP.h b/windows/src/engine/keyman32/appint/aiTIP.h index 7ff5aff4ef..454943a0de 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.h +++ b/windows/src/engine/keyman32/appint/aiTIP.h @@ -71,11 +71,6 @@ public: BOOL DebugControlled(); - // TODO: 5442 This would be better to called SaveContextWithStores or SaveContextWithKbdOptions - // Will be removed with 5442 when removing window core - void SaveContext(AppContextWithStores *savedContext); // I4370 // I4978 - void RestoreContext(AppContextWithStores *savedContext); // I4370 // I4978 - /** * Copy the member context * diff --git a/windows/src/engine/keyman32/calldll.cpp b/windows/src/engine/keyman32/calldll.cpp index 142db01747..9b9a6ae428 100644 --- a/windows/src/engine/keyman32/calldll.cpp +++ b/windows/src/engine/keyman32/calldll.cpp @@ -93,34 +93,6 @@ static LPIMDLL AddIMDLL(LPINTKEYBOARDINFO lpkbi, LPSTR kbdpath, LPSTR dllfilenam return imd; } -/* Add a dll hook function to the list of hook functions associated with a single dll */ - -static BOOL AddIMDLLHook(LPIMDLL imd, LPSTR funcname, DWORD storeno, PWCHAR *dpString) -{ - //SendDebugMessageFormat(0, sdmKeyboard, 0, "AddIMDLLHook: Enter"); - /* Get the procedure address for the function */ - - IMDLLHOOKProc dhp = (IMDLLHOOKProc) GetProcAddress(imd->hModule, funcname); - if(!dhp) return FALSE; - - /* Add the function to the list of functions in the DLL */ - - LPIMDLLHOOK hooks = new IMDLLHOOK[imd->nHooks+1]; - if(imd->nHooks > 0) - { - memcpy(hooks, imd->Hooks, sizeof(IMDLLHOOK) * imd->nHooks); - delete imd->Hooks; - } - imd->Hooks = hooks; - strncpy(imd->Hooks[imd->nHooks].name, funcname, 31); - imd->Hooks[imd->nHooks].name[31] = 0; - imd->Hooks[imd->nHooks].storeno = storeno; - imd->Hooks[imd->nHooks].function = dhp; - *dpString = (PWCHAR) &imd->Hooks[imd->nHooks++]; - //SendDebugMessageFormat(0, sdmKeyboard, 0, "AddIMDLLHook: Exit"); - return TRUE; -} - static km_kbp_action_item* kmnToCoreActionItem(int ItemType, DWORD dwData, WORD wVkey) { @@ -232,55 +204,6 @@ BOOL CallbackDLLs(LPINTKEYBOARDINFO lpkbi, PSTR cmd) return TRUE; } -/* Load the dlls associated with a keyboard */ - -BOOL LoadDLLs(LPINTKEYBOARDINFO lpkbi) -{ - char fullname[_MAX_PATH]; - //SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Enter"); - - if(lpkbi->nIMDLLs > 0) if(!UnloadDLLs(lpkbi)) return FALSE; - - if (!GetKeyboardFileName(lpkbi->Name, fullname, _MAX_PATH)) { - SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Filename not found[%s]", lpkbi->Name); - return FALSE; - } - - if (!lpkbi->Keyboard) { - SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Keyboard is null"); - return FALSE; - } - for(DWORD i = 0; i < lpkbi->Keyboard->cxStoreArray; i++) - { - LPSTORE s = &lpkbi->Keyboard->dpStoreArray[i]; - if(s->dwSystemID == TSS_CALLDEFINITION) - { - /* Break the store string into components */ - - PCHAR p = wstrtostr(s->dpString), q, r, context; - - q = strtok_s(p, ":", &context); - r = strtok_s(NULL, ":", &context); - - if(!q || !r) - { - s->dwSystemID = TSS_CALLDEFINITION_LOADFAILED; - delete[] p; - continue; - } - - LPIMDLL imd = AddIMDLL(lpkbi, fullname, q); - if(imd && AddIMDLLHook(imd, r, i, &s->dpString)) s->dwSystemID = TSS_CALLDEFINITION; - else s->dwSystemID = TSS_CALLDEFINITION_LOADFAILED; - - delete[] p; - } - } - - //SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Exit"); - return TRUE; -} - // Both Core and Window keyboard processor can use this function BOOL UnloadDLLs(LPINTKEYBOARDINFO lpkbi) { @@ -302,7 +225,7 @@ BOOL UnloadDLLs(LPINTKEYBOARDINFO lpkbi) lpkbi->IMDLLs = NULL; lpkbi->nIMDLLs = 0; - if (Globals::get_CoreIntegration() && lpkbi->lpCoreKeyboardState) { + if (lpkbi->lpCoreKeyboardState) { km_kbp_state_imx_deregister_callback(lpkbi->lpCoreKeyboardState); } return TRUE; @@ -402,90 +325,84 @@ extern "C" BOOL _declspec(dllexport) WINAPI KMSetOutput(PWSTR buf, DWORD backlen if (!_td->app) return FALSE; - if (!Globals::get_CoreIntegration()) { // TODO: 5442 Remove If and fix indent - while (backlen-- > 0) - _td->app->QueueAction(QIT_BACK, BK_DEFAULT); - while (*buf) - _td->app->QueueAction(QIT_CHAR, *buf++); - return TRUE; - } else { - if (!_td->lpActiveKeyboard || !_td->lpActiveKeyboard->lpCoreKeyboardState) { - SendDebugMessageFormat(0, sdmKeyboard, 0, "KMSetOutputCore: no active state"); - return FALSE; - } - DWORD numActions = backlen + (DWORD)wcslen(buf); - DWORD idx = 0; - km_kbp_action_item *actionItems = new km_kbp_action_item[numActions + 1]; - - // The actions sent to the core processor need to set the expected_type - // correctly. To do this need to check the context as we process the - // backspaces. - km_kbp_context_item *citems = nullptr; - if (KM_KBP_STATUS_OK != kbp_state_get_intermediate_context(_td->lpActiveKeyboard->lpCoreKeyboardState, &citems)) { - delete[] actionItems; - return FALSE; - } - DWORD context_length = (DWORD)km_kbp_context_item_list_size(citems); - WCHAR *contextString = new WCHAR[(context_length * 3) + 1]; // *3 if every context item was a deadkey - if (!ContextItemToAppContext(citems, contextString, context_length)) { - km_kbp_context_items_dispose(citems); - delete[] contextString; - delete[] actionItems; - return FALSE; - } + if (!_td->lpActiveKeyboard || !_td->lpActiveKeyboard->lpCoreKeyboardState) { + SendDebugMessageFormat(0, sdmKeyboard, 0, "KMSetOutputCore: no active state"); + return FALSE; + } + DWORD numActions = backlen + (DWORD)wcslen(buf); + DWORD idx = 0; + km_kbp_action_item *actionItems = new km_kbp_action_item[numActions + 1]; + + // The actions sent to the core processor need to set the expected_type + // correctly. To do this need to check the context as we process the + // backspaces. + km_kbp_context_item *citems = nullptr; + if (KM_KBP_STATUS_OK != kbp_state_get_intermediate_context(_td->lpActiveKeyboard->lpCoreKeyboardState, &citems)) { + delete[] actionItems; + return FALSE; + } + + DWORD context_length = (DWORD)km_kbp_context_item_list_size(citems); + WCHAR *contextString = new WCHAR[(context_length * 3) + 1]; // *3 if every context item was a deadkey + if (!ContextItemToAppContext(citems, contextString, context_length)) { km_kbp_context_items_dispose(citems); - AppContext context; - context.Set(contextString); delete[] contextString; - - while (backlen-- > 0) { - actionItems[idx].type = KM_KBP_IT_BACK; - WCHAR *CodeUnitPtr; - const int DeadKeyLength = 3; - const int SurrogateLength = 2; - const int SingleCharLength = 1; - if (context.CharIsDeadkey()) { - CodeUnitPtr = context.BufMax(DeadKeyLength); - CodeUnitPtr += 2; - actionItems[idx].backspace.expected_type = KM_KBP_BT_MARKER; - actionItems[idx].backspace.expected_value = (uintptr_t)*CodeUnitPtr; - } else if (context.CharIsSurrogatePair()) { - CodeUnitPtr = context.BufMax(SurrogateLength); - actionItems[idx].backspace.expected_type = KM_KBP_BT_CHAR; - actionItems[idx].backspace.expected_value = (DWORD)Uni_SurrogateToUTF32(*CodeUnitPtr, *(CodeUnitPtr + 1)); - } else if (!context.IsEmpty()) { - CodeUnitPtr = context.BufMax(SingleCharLength); - actionItems[idx].backspace.expected_type = KM_KBP_BT_CHAR; - actionItems[idx].backspace.expected_value = (DWORD)*CodeUnitPtr; - } else { - actionItems[idx].backspace.expected_type = KM_KBP_BT_UNKNOWN; - actionItems[idx].backspace.expected_value = 0; - } - context.Delete(); - idx++; + delete[] actionItems; + return FALSE; + } + km_kbp_context_items_dispose(citems); + AppContext context; + context.Set(contextString); + delete[] contextString; + + while (backlen-- > 0) { + actionItems[idx].type = KM_KBP_IT_BACK; + WCHAR *CodeUnitPtr; + const int DeadKeyLength = 3; + const int SurrogateLength = 2; + const int SingleCharLength = 1; + if (context.CharIsDeadkey()) { + CodeUnitPtr = context.BufMax(DeadKeyLength); + CodeUnitPtr += 2; + actionItems[idx].backspace.expected_type = KM_KBP_BT_MARKER; + actionItems[idx].backspace.expected_value = (uintptr_t)*CodeUnitPtr; + } else if (context.CharIsSurrogatePair()) { + CodeUnitPtr = context.BufMax(SurrogateLength); + actionItems[idx].backspace.expected_type = KM_KBP_BT_CHAR; + actionItems[idx].backspace.expected_value = (DWORD)Uni_SurrogateToUTF32(*CodeUnitPtr, *(CodeUnitPtr + 1)); + } else if (!context.IsEmpty()) { + CodeUnitPtr = context.BufMax(SingleCharLength); + actionItems[idx].backspace.expected_type = KM_KBP_BT_CHAR; + actionItems[idx].backspace.expected_value = (DWORD)*CodeUnitPtr; + } else { + actionItems[idx].backspace.expected_type = KM_KBP_BT_UNKNOWN; + actionItems[idx].backspace.expected_value = 0; } + context.Delete(); + idx++; + } - while (*buf) { - actionItems[idx].type = KM_KBP_IT_CHAR; - if (Uni_IsSurrogate1(*buf) && Uni_IsSurrogate2(*(buf + 1))) { - actionItems[idx].character = Uni_SurrogateToUTF32(*buf, *(buf + 1)); - buf++; - } else { - actionItems[idx].character = (DWORD)(*buf); - } + while (*buf) { + actionItems[idx].type = KM_KBP_IT_CHAR; + if (Uni_IsSurrogate1(*buf) && Uni_IsSurrogate2(*(buf + 1))) { + actionItems[idx].character = Uni_SurrogateToUTF32(*buf, *(buf + 1)); buf++; - idx++; - } - actionItems[idx].type = KM_KBP_IT_END; - if (KM_KBP_STATUS_OK != km_kbp_state_queue_action_items(_td->lpActiveKeyboard->lpCoreKeyboardState, actionItems)) { - delete[] actionItems; - return FALSE; + } else { + actionItems[idx].character = (DWORD)(*buf); } + buf++; + idx++; + } + actionItems[idx].type = KM_KBP_IT_END; + if (KM_KBP_STATUS_OK != km_kbp_state_queue_action_items(_td->lpActiveKeyboard->lpCoreKeyboardState, actionItems)) { delete[] actionItems; - //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMSetOutputCore: Exit"); - return TRUE; + return FALSE; } + delete[] actionItems; + //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMSetOutputCore: Exit"); + return TRUE; + } extern "C" BOOL _declspec(dllexport) WINAPI KMQueueAction(int ItemType, DWORD dwData) { @@ -496,61 +413,53 @@ extern "C" BOOL _declspec(dllexport) WINAPI KMQueueAction(int ItemType, DWORD dw if (!_td->app) return FALSE; - if (!Globals::get_CoreIntegration()) { - return _td->app->QueueAction(ItemType, dwData); // TODO: 5442 Remove - } else { - if (!_td->lpActiveKeyboard || !_td->lpActiveKeyboard->lpCoreKeyboardState) { - return FALSE; - } + if (!_td->lpActiveKeyboard || !_td->lpActiveKeyboard->lpCoreKeyboardState) { + return FALSE; + } - km_kbp_action_item *actionItem = kmnToCoreActionItem(ItemType, dwData, _td->state.vkey); - km_kbp_status_codes error_status = - (km_kbp_status_codes)km_kbp_state_queue_action_items(_td->lpActiveKeyboard->lpCoreKeyboardState, actionItem); - if (error_status != KM_KBP_STATUS_OK) { - delete[] actionItem; - SendDebugMessageFormat(0, sdmKeyboard, 0, "KMQueueAction: Error core queue_action_items error status:[%lu]",error_status); - return FALSE; - } + km_kbp_action_item *actionItem = kmnToCoreActionItem(ItemType, dwData, _td->state.vkey); + km_kbp_status_codes error_status = + (km_kbp_status_codes)km_kbp_state_queue_action_items(_td->lpActiveKeyboard->lpCoreKeyboardState, actionItem); + if (error_status != KM_KBP_STATUS_OK) { delete[] actionItem; - //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMQueueActionCore: Exit"); - return TRUE; + SendDebugMessageFormat(0, sdmKeyboard, 0, "KMQueueAction: Error core queue_action_items error status:[%lu]",error_status); + return FALSE; } + delete[] actionItem; + //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMQueueActionCore: Exit"); + return TRUE; + } extern "C" BOOL _declspec(dllexport) WINAPI KMGetContext(PWSTR buf, DWORD len) { //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMGetContext: Enter"); PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - if(!_td->app) return FALSE; - // TODO: 5442 KMGetContext is already public call (even though it is pointer) Rather then making a new KMGetContextCore - // This has been modified to check for core processor once we move to core processor the old Windows Platmform calling of - // ContextBuff can be removed - // - if(!Globals::get_CoreIntegration()){ - PWSTR q = _td->app->ContextBufMax(len); - if (!q) - return FALSE; // context buf does not exist - - wcscpy_s(buf, len + 1, q); // I3091 - return TRUE; - } else { - if (!_td->lpActiveKeyboard || !_td->lpActiveKeyboard->lpCoreKeyboardState) { - return FALSE; - } - km_kbp_context_item *citems = nullptr; - if (KM_KBP_STATUS_OK != kbp_state_get_intermediate_context(_td->lpActiveKeyboard->lpCoreKeyboardState, &citems)) { - return FALSE; - } + if(!_td) { + return FALSE; + } + + if(!_td->app) { + return FALSE; + } - if (!ContextItemToAppContext(citems, buf, len)) { - km_kbp_context_items_dispose(citems); + if (!_td->lpActiveKeyboard || !_td->lpActiveKeyboard->lpCoreKeyboardState) { + return FALSE; + } + + km_kbp_context_item *citems = nullptr; + if (KM_KBP_STATUS_OK != kbp_state_get_intermediate_context(_td->lpActiveKeyboard->lpCoreKeyboardState, &citems)) { return FALSE; - } + } + + if (!ContextItemToAppContext(citems, buf, len)) { km_kbp_context_items_dispose(citems); - //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMGetContext: Exit"); - return TRUE; + return FALSE; } + km_kbp_context_items_dispose(citems); + //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMGetContext: Exit"); + return TRUE; + } extern "C" BOOL _declspec(dllexport) WINAPI KMDisplayIM(HWND hwnd, BOOL FShowAlways) @@ -650,8 +559,8 @@ BOOL IsIMWindow(HWND hwnd) /* Add a dll hook function to the list of hook functions associated with a single dll */ static BOOL -AddIMDLLHookCore(LPIMDLL imd, LPSTR funcname, DWORD storeno) { - //SendDebugMessageFormat(0, sdmKeyboard, 0, "AddIMDLLHookCore: Enter"); +AddIMDLLHook(LPIMDLL imd, LPSTR funcname, DWORD storeno) { + //SendDebugMessageFormat(0, sdmKeyboard, 0, "AddIMDLLHook: Enter"); /* Get the procedure address for the function */ IMDLLHOOKProc dhp = (IMDLLHOOKProc)GetProcAddress(imd->hModule, funcname); if (!dhp) @@ -670,15 +579,15 @@ AddIMDLLHookCore(LPIMDLL imd, LPSTR funcname, DWORD storeno) { imd->Hooks[imd->nHooks].storeno = storeno; imd->Hooks[imd->nHooks].function = dhp; imd->nHooks++; - //SendDebugMessageFormat(0, sdmKeyboard, 0, "AddIMDLLHookCore: Exit"); + //SendDebugMessageFormat(0, sdmKeyboard, 0, "AddIMDLLHook: Exit"); return TRUE; } /* Load the dlls associated with a keyboard */ BOOL -LoadDLLsCore(LPINTKEYBOARDINFO lpkbi) { +LoadDLLs(LPINTKEYBOARDINFO lpkbi) { char fullname[_MAX_PATH]; - //SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLsCore: Enter"); + //SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Enter"); if (lpkbi->nIMDLLs > 0) if (!UnloadDLLs(lpkbi)) @@ -694,11 +603,11 @@ LoadDLLsCore(LPINTKEYBOARDINFO lpkbi) { BOOL result = false; for (; imx_list->library_name; ++imx_list) { LPIMDLL imd = AddIMDLL(lpkbi, fullname, wstrtostr(reinterpret_cast(imx_list->library_name))); - if (imd && AddIMDLLHookCore(imd, wstrtostr(reinterpret_cast(imx_list->function_name)), imx_list->imx_id)) { + if (imd && AddIMDLLHook(imd, wstrtostr(reinterpret_cast(imx_list->function_name)), imx_list->imx_id)) { result = TRUE; } else { - SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLsCore: Error Loading Library name [%s], Function name [%s]", + SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Error Loading Library name [%s], Function name [%s]", wstrtostr(reinterpret_cast(imx_list->library_name)), wstrtostr(reinterpret_cast(imx_list->function_name))); } @@ -707,7 +616,7 @@ LoadDLLsCore(LPINTKEYBOARDINFO lpkbi) { if (result) { km_kbp_state_imx_register_callback(lpkbi->lpCoreKeyboardState, IM_CallBackCore, (void *)lpkbi); } - //SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLsCore: Exit"); + //SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadDLLs: Exit"); return TRUE; } diff --git a/windows/src/engine/keyman32/calldll.h b/windows/src/engine/keyman32/calldll.h index 9eb1a7ade4..6faebcb70a 100644 --- a/windows/src/engine/keyman32/calldll.h +++ b/windows/src/engine/keyman32/calldll.h @@ -30,7 +30,7 @@ BOOL ActivateDLLs(LPINTKEYBOARDINFO lpkbi); * @param lpkbi The keyboard for which to load the dlls * @return BOOL True on success */ -BOOL LoadDLLsCore(LPINTKEYBOARDINFO lpkbi); +BOOL LoadDLLs(LPINTKEYBOARDINFO lpkbi); BOOL IsIMWindow(HWND hwnd); diff --git a/windows/src/engine/keyman32/globals.h b/windows/src/engine/keyman32/globals.h index 6e840fce99..1465bab24d 100644 --- a/windows/src/engine/keyman32/globals.h +++ b/windows/src/engine/keyman32/globals.h @@ -151,7 +151,6 @@ public: static BOOL get_debug_KeymanLog(); static BOOL get_debug_ToConsole(); - static BOOL get_CoreIntegration(); static void LoadDebugSettings(); }; diff --git a/windows/src/engine/keyman32/glossary.cpp b/windows/src/engine/keyman32/glossary.cpp index 2954638c19..ba29ec3464 100644 --- a/windows/src/engine/keyman32/glossary.cpp +++ b/windows/src/engine/keyman32/glossary.cpp @@ -1,18 +1,18 @@ /* Name: glossary Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 20 Jul 2008 Modified Date: 28 May 2014 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 20 Jul 2008 - mcdurdin - I1498 - Fix keyboard switching for Shadow keyboards on Vista+ 20 Jul 2008 - mcdurdin - I1546 - Fix language switch with ids >= x80000000 20 Jul 2008 - mcdurdin - I1545 - Fix registry leak @@ -38,9 +38,9 @@ BOOL HKLIsIME(HKL hkl) // I1498 - fix keyboard switching for shadow keyboards o if( (GetVersion() & 0xFF) >= 6 ) return FALSE; if( (GetVersion() & 0x8000000) == 0x8000000 || (GetVersion() & 0xFF) == 4 ) r = GetSystemMetrics(SM_DBCSENABLED); - else + else r = GetSystemMetrics(SM_IMMENABLED); - + return r && ImmIsIME(hkl); } #pragma warning(default: 4996) @@ -99,12 +99,12 @@ DWORD HKLToKeyboardID(HKL hkl) return (DWORD) LOWORD(hkl); } - for(len=16, n = i = 0; RegEnumKeyEx(hkey, i, str, &len, 0, NULL, NULL, &ft) == ERROR_SUCCESS; - len = 16, i++, n=0) + for(len=16, n = i = 0; RegEnumKeyEx(hkey, i, str, &len, 0, NULL, NULL, &ft) == ERROR_SUCCESS; + len = 16, i++, n=0) { RegOpenKeyEx(hkey, str, NULL, KEY_READ, &hsubkey); len = 16; - if(RegQueryValueEx(hsubkey, REGSZ_LayoutID, NULL, NULL, (LPBYTE) str2, &len) == ERROR_SUCCESS) + if(RegQueryValueEx(hsubkey, REGSZ_LayoutID, NULL, NULL, (LPBYTE) str2, &len) == ERROR_SUCCESS) { n = strtoul(str2, NULL, 16); // I1546 if(n == LayoutID) @@ -120,7 +120,7 @@ DWORD HKLToKeyboardID(HKL hkl) } RegCloseKey(hkey); - + //SendDebugMessageFormat(0, sdmGlobal, 0, "HKLToKeyboardID: fails[2], return LOWORD(hkl)=%x", LOWORD(hkl)); return (DWORD) LOWORD(hkl); // should never happen } @@ -143,11 +143,11 @@ WORD HKLToLayoutNumber(HKL hkl) if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSZ_SystemKeyboardLayouts, NULL, KEY_READ, &hkey) != ERROR_SUCCESS) return 0; - for(len=16, n = i = 0; RegEnumKeyEx(hkey, i, str, &len, 0, NULL, NULL, &ft) == ERROR_SUCCESS; len = 16, i++, n=0) + for(len=16, n = i = 0; RegEnumKeyEx(hkey, i, str, &len, 0, NULL, NULL, &ft) == ERROR_SUCCESS; len = 16, i++, n=0) { RegOpenKeyEx(hkey, str, NULL, KEY_READ, &hsubkey); len = 16; - if(RegQueryValueEx(hsubkey, REGSZ_LayoutID, NULL, NULL, (LPBYTE) str2, &len) == ERROR_SUCCESS) + if(RegQueryValueEx(hsubkey, REGSZ_LayoutID, NULL, NULL, (LPBYTE) str2, &len) == ERROR_SUCCESS) { if(strtoul(str2, NULL, 16) == LayoutID) break; // strtoul - I1546 } @@ -195,7 +195,7 @@ DWORD EthnologueCodeToKeymanID(DWORD EthCode) DWORD EthnologueStringCodeToDWord(PWSTR EthCode) { if(wcslen(EthCode) < 3 || wcslen(EthCode) > 4) return (DWORD)-1; - return (LOBYTE(EthCode[0])) | + return (LOBYTE(EthCode[0])) | (LOBYTE(EthCode[1]) << 8) | (LOBYTE(EthCode[2]) << 16) | (LOBYTE(EthCode[3]) << 24); diff --git a/windows/src/engine/keyman32/k32_globals.cpp b/windows/src/engine/keyman32/k32_globals.cpp index 054945b812..989a787f95 100644 --- a/windows/src/engine/keyman32/k32_globals.cpp +++ b/windows/src/engine/keyman32/k32_globals.cpp @@ -288,9 +288,6 @@ static BOOL f_debug_KeymanLog = FALSE, f_debug_ToConsole = FALSE; -static BOOL - f_CoreIntegration = TRUE; - #pragma data_seg() /***************************************************************************/ @@ -365,8 +362,6 @@ BOOL Globals::get_MnemonicDeadkeyConversionMode() { return f_MnemonicDeadkeyConv BOOL Globals::get_debug_KeymanLog() { return f_debug_KeymanLog; } BOOL Globals::get_debug_ToConsole() { return f_debug_ToConsole; } -BOOL Globals::get_CoreIntegration() { return f_CoreIntegration; } - void Globals::SetBaseKeyboardName(wchar_t *baseKeyboardName, wchar_t *baseKeyboardNameAlt) { // I4583 wcscpy_s(f_BaseKeyboardName, baseKeyboardName); wcscpy_s(f_BaseKeyboardNameAlt, baseKeyboardNameAlt); @@ -385,9 +380,6 @@ void Globals::SetBaseKeyboardFlags(char *baseKeyboard, BOOL simulateAltGr, BOOL be changed until Keyman is restarted. */ BOOL Globals::InitSettings() { - /* Check for common core vs windows core */ - f_CoreIntegration = Reg_GetDebugFlag(REGSZ_Flag_UseKeymanCore, TRUE); - SendDebugMessageFormat(0, sdmAIDefault, 0, "Globals::InitSettings - Coreintegration set in '" REGSZ_Flag_UseKeymanCore "' to %x", f_CoreIntegration); f_vk_prefix = _VK_PREFIX_DEFAULT; RegistryReadOnly reg(HKEY_LOCAL_MACHINE); if (reg.OpenKeyReadOnly(REGSZ_KeymanLM) && diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index 3e5edcff5b..1b8efe22f8 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -42,20 +42,6 @@ void LoadKeyboardOptions(LPINTKEYBOARDINFO kp) IntLoadKeyboardOptions(REGSZ_KeyboardOptions, kp); } -void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp) -{ - if(!DebugAssert(!Globals::get_CoreIntegration(), "LoadSharedKeyboardOptions: Error called in core integration mode")) { - return; - } - // Called when another thread changes keyboard options and we are sharing keyboard settings - assert(kp != NULL); - assert(kp->Keyboard != NULL); - - if(kp->KeyboardOptions != NULL) FreeKeyboardOptions(kp); - - IntLoadKeyboardOptions(REGSZ_SharedKeyboardOptions, kp); -} - void FreeKeyboardOptions(LPINTKEYBOARDINFO kp) { // This is a cleanup routine; we don't want to precondition all calls to it @@ -73,81 +59,6 @@ void FreeKeyboardOptions(LPINTKEYBOARDINFO kp) kp->KeyboardOptions = NULL; } -void SetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSet, int nStoreToRead) -{ - if (!DebugAssert(!Globals::get_CoreIntegration(), "SetKeyboardOption: Error called in core integration mode")) { - return; - } - assert(kp != NULL); - assert(kp->Keyboard != NULL); - assert(kp->KeyboardOptions != NULL); - assert(nStoreToSet >= 0); - assert(nStoreToSet < (int) kp->Keyboard->cxStoreArray); - assert(nStoreToRead >= 0); - assert(nStoreToRead < (int) kp->Keyboard->cxStoreArray); - - LPSTORE sp = &kp->Keyboard->dpStoreArray[nStoreToRead]; - if(kp->KeyboardOptions[nStoreToSet].Value) - { - delete kp->KeyboardOptions[nStoreToSet].Value; - } - else - { - kp->KeyboardOptions[nStoreToSet].OriginalStore = kp->Keyboard->dpStoreArray[nStoreToSet].dpString; - } - - kp->KeyboardOptions[nStoreToSet].Value = new WCHAR[wcslen(sp->dpString)+1]; - wcscpy_s(kp->KeyboardOptions[nStoreToSet].Value, wcslen(sp->dpString)+1, sp->dpString); - kp->Keyboard->dpStoreArray[nStoreToSet].dpString = kp->KeyboardOptions[nStoreToSet].Value; -} - -void ResetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToReset) -{ - if (!DebugAssert(!Globals::get_CoreIntegration(), "ResetKeyboardOption: Error called in core integration mode")) { - return; - } - assert(kp != NULL); - assert(kp->Keyboard != NULL); - assert(kp->KeyboardOptions != NULL); - assert(nStoreToReset >= 0); - assert(nStoreToReset < (int) kp->Keyboard->cxStoreArray); - - if(kp->KeyboardOptions[nStoreToReset].Value) - { - kp->Keyboard->dpStoreArray[nStoreToReset].dpString = kp->KeyboardOptions[nStoreToReset].OriginalStore; - delete kp->KeyboardOptions[nStoreToReset].Value; - kp->KeyboardOptions[nStoreToReset].Value = NULL; - - if(kp->Keyboard->dpStoreArray[nStoreToReset].dpName == NULL) return; - - RegistryReadOnly r(HKEY_CURRENT_USER); - if(r.OpenKeyReadOnly(REGSZ_KeymanActiveKeyboards) && r.OpenKeyReadOnly(kp->Name) && r.OpenKeyReadOnly(REGSZ_KeyboardOptions)) - { - if(r.ValueExists(kp->Keyboard->dpStoreArray[nStoreToReset].dpName)) - { - WCHAR val[256]; - if(!r.ReadString(kp->Keyboard->dpStoreArray[nStoreToReset].dpName, val, sizeof(val) / sizeof(val[0]))) return; - if(!val[0]) return; - val[255] = 0; - kp->KeyboardOptions[nStoreToReset].Value = new WCHAR[wcslen(val)+1]; - wcscpy_s(kp->KeyboardOptions[nStoreToReset].Value, wcslen(val)+1, val); - - kp->KeyboardOptions[nStoreToReset].OriginalStore = kp->Keyboard->dpStoreArray[nStoreToReset].dpString; - kp->Keyboard->dpStoreArray[nStoreToReset].dpString = kp->KeyboardOptions[nStoreToReset].Value; - } - } - } -} - - -void SaveKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSave) -{ - if (!DebugAssert(!Globals::get_CoreIntegration(), "SaveKeyboardOption: Error called in core integration mode")) { - return; - } - IntSaveKeyboardOption(REGSZ_KeyboardOptions, kp, nStoreToSave); -} - void SaveKeyboardOptionREGCore(LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value) { IntSaveKeyboardOptionREGCore(REGSZ_KeyboardOptions, kp, key, value); diff --git a/windows/src/engine/keyman32/keyman32.cpp b/windows/src/engine/keyman32/keyman32.cpp index ee6cd754b8..cc857dfeb7 100644 --- a/windows/src/engine/keyman32/keyman32.cpp +++ b/windows/src/engine/keyman32/keyman32.cpp @@ -563,64 +563,55 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_ForceKeyboard(PCSTR FileName _td->lpActiveKeyboard->IMDLLs = NULL; _td->lpActiveKeyboard->KeyboardOptions = NULL;*/ _splitpath_s(FileName, NULL, 0, NULL, 0, _td->lpActiveKeyboard->Name, sizeof(_td->lpActiveKeyboard->Name), NULL, 0); - // TODO: 5442 - remove if/ else as there will no longer be the old LoadKeyboard option - if (Globals::get_CoreIntegration()) { - PWCHAR keyboardPath = strtowstr(_td->ForceFileName); - km_kbp_status err_status = km_kbp_keyboard_load(keyboardPath, &_td->lpActiveKeyboard->lpCoreKeyboard); - if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard Core: km_kbp_keyboard_load failed for %ls with error status [%d]", keyboardPath, err_status); // TODO: 5442 - remove word Core - delete keyboardPath; - return FALSE; - } + + PWCHAR keyboardPath = strtowstr(_td->ForceFileName); + km_kbp_status err_status = km_kbp_keyboard_load(keyboardPath, &_td->lpActiveKeyboard->lpCoreKeyboard); + if (err_status != KM_KBP_STATUS_OK) { + SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard: km_kbp_keyboard_load failed for %ls with error status [%d]", keyboardPath, err_status); delete keyboardPath; - SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard Core: %s OK", FileName); // TODO: 5442 - remove word Core - km_kbp_option_item *core_environment = nullptr; + goto fail; + } + delete keyboardPath; + SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard: %s OK", FileName); - if(!SetupCoreEnvironment(&core_environment)) { - SendDebugMessageFormat(0, sdmLoad, 0, "Keyman_ForceKeyboard Core: Unable to set environment options for keyboard %s", FileName); // TODO: 5442 - remove word Core - return FALSE; - } + km_kbp_option_item *core_environment = nullptr; - err_status = - km_kbp_state_create(_td->lpActiveKeyboard->lpCoreKeyboard, core_environment, &_td->lpActiveKeyboard->lpCoreKeyboardState); + if(!SetupCoreEnvironment(&core_environment)) { + SendDebugMessageFormat(0, sdmLoad, 0, "Keyman_ForceKeyboard: Unable to set environment options for keyboard %s", FileName); + goto fail; + } - DeleteCoreEnvironment(core_environment); + err_status = + km_kbp_state_create(_td->lpActiveKeyboard->lpCoreKeyboard, core_environment, &_td->lpActiveKeyboard->lpCoreKeyboardState); - if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat( - 0, sdmGlobal, 0, "Keyman_ForceKeyboard Core: km_kbp_state_create failed with error status [%d]", err_status); - // Dispose of the keyboard to leave us in a consitent state - ReleaseKeyboardMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboard); - return FALSE; - } + DeleteCoreEnvironment(core_environment); - ResetCapsLock(); - err_status = km_kbp_keyboard_get_imx_list(_td->lpActiveKeyboard->lpCoreKeyboard, &_td->lpActiveKeyboard->lpIMXList); - if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat(0, sdmLoad, 0, "Keyman_ForceKeyboard Core: km_kbp_keyboard_get_imx_list failed with error status [%d]", err_status); - // Dispose of the keyboard to leave us in a consistent state - ReleaseKeyboardMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboard); - return FALSE; - } + if (err_status != KM_KBP_STATUS_OK) { + SendDebugMessageFormat( + 0, sdmGlobal, 0, "Keyman_ForceKeyboard Core: km_kbp_state_create failed with error status [%d]", err_status); + // Dispose of the keyboard to leave us in a consitent state + ReleaseKeyboardMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboard); + goto fail; + } - LoadDLLsCore(_td->lpActiveKeyboard); - ActivateDLLs(_td->lpActiveKeyboard); - LoadKeyboardOptionsREGCore(_td->lpActiveKeyboard, _td->lpActiveKeyboard->lpCoreKeyboardState); - RefreshPreservedKeys(TRUE); - return TRUE; - } else { - if (LoadKeyboard(_td->ForceFileName, &_td->lpActiveKeyboard->Keyboard)) { - SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard: %s OK", FileName); - ResetCapsLock(); - LoadDLLs(_td->lpActiveKeyboard); - ActivateDLLs(_td->lpActiveKeyboard); - LoadKeyboardOptions(_td->lpActiveKeyboard); // I2437 - Crash unloading keyboard due to keyboard options not set - RefreshPreservedKeys(TRUE); - return TRUE; - } + ResetCapsLock(); + err_status = km_kbp_keyboard_get_imx_list(_td->lpActiveKeyboard->lpCoreKeyboard, &_td->lpActiveKeyboard->lpIMXList); + if (err_status != KM_KBP_STATUS_OK) { + SendDebugMessageFormat(0, sdmLoad, 0, "Keyman_ForceKeyboard Core: km_kbp_keyboard_get_imx_list failed with error status [%d]", err_status); + // Dispose of the keyboard to leave us in a consistent state + ReleaseStateMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboardState); + ReleaseKeyboardMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboard); + goto fail; } - SendDebugMessageFormat(0,sdmGlobal,0,"Keyman_ForceKeyboard: %s FAIL", FileName); + + LoadDLLs(_td->lpActiveKeyboard); + ActivateDLLs(_td->lpActiveKeyboard); + LoadKeyboardOptionsREGCore(_td->lpActiveKeyboard, _td->lpActiveKeyboard->lpCoreKeyboardState); + RefreshPreservedKeys(TRUE); + return TRUE; + // happy to use while(!done) pattern +fail: delete _td->lpActiveKeyboard; _td->lpActiveKeyboard = NULL; diff --git a/windows/src/engine/keyman32/keymanengine.h b/windows/src/engine/keyman32/keymanengine.h index d56bcc1e3e..96bf668c2f 100644 --- a/windows/src/engine/keyman32/keymanengine.h +++ b/windows/src/engine/keyman32/keymanengine.h @@ -105,17 +105,12 @@ typedef struct tagKMSTATE { BOOL NoMatches; MSG msg; - // TODO: 5442 will remove these once windows core is deprecated - BOOL StopOutput; - int LoopTimes; - // TODO: 5442 WORD vkey; // I934 WCHAR charCode; // I4582 BOOL windowunicode; // I4287 BOOL isDown; LPKEYBOARD lpkb; km_kbp_keyboard* lpCoreKb; // future use with IMDLL - LPGROUP startgroup; // TODO: 5442 will remove this once windows core is deprecated } KMSTATE; // I3616 diff --git a/windows/src/engine/keyman32/kmhook_getmessage.cpp b/windows/src/engine/keyman32/kmhook_getmessage.cpp index f6a56340f9..bc7200ef0d 100644 --- a/windows/src/engine/keyman32/kmhook_getmessage.cpp +++ b/windows/src/engine/keyman32/kmhook_getmessage.cpp @@ -297,20 +297,17 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam) { if(_td->app) { - BOOL isUsingCoreProcessor = Globals::get_CoreIntegration(); - - if (isUsingCoreProcessor) { - // Call the core keyboard processor to process the queued actions - if (!_td->lpActiveKeyboard) { - return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); - } - if (KM_KBP_STATUS_OK != km_kbp_process_queued_actions(_td->lpActiveKeyboard->lpCoreKeyboardState)) { - SendDebugMessageFormat(0, sdmGlobal, 0, "_kmnGetMessageProc wm_keymanim_close process event fail"); - return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); - } - BOOL emitKeyStroke; - ProcessActions(&emitKeyStroke); + // Call the core keyboard processor to process the queued actions + if (!_td->lpActiveKeyboard) { + return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); } + if (KM_KBP_STATUS_OK != km_kbp_process_queued_actions(_td->lpActiveKeyboard->lpCoreKeyboardState)) { + SendDebugMessageFormat(0, sdmGlobal, 0, "_kmnGetMessageProc wm_keymanim_close process event fail"); + return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); + } + BOOL emitKeyStroke; + ProcessActions(&emitKeyStroke); + _td->app->SetCurrentShiftState(Globals::get_ShiftState()); _td->app->SendActions(); } diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index 7faac081c2..ff0e234edc 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -138,10 +138,7 @@ BOOL ProcessHook() PKEYMAN64THREADDATA _td = ThreadGlobals(); if(!_td) return FALSE; - LPGROUP gp = _td->state.startgroup; - fOutputKeystroke = FALSE; // TODO: 5442 no longer needs to be global once we use core processor - BOOL isUsingCoreProcessor = Globals::get_CoreIntegration(); // // If we are running in the debugger, don't do a second run through // @@ -172,32 +169,26 @@ BOOL ProcessHook() _td->app->QueueDebugInformation(QID_BEGIN_ANSI, NULL, NULL, NULL, NULL, (DWORD_PTR) &keyinfo); } - if (isUsingCoreProcessor) { // TODO: 5442 Note: Nested if will be reduced once using core only - // For applications not using the TSF kmtip calls this function twice for each keystroke, - // first to determine if we are doing processing work (TIPFUpdateable == FALSE), - // if we say yes it will call a second time to actually do the work. - // We call the core process event only once and use the core's queued actions - // on the second pass. - // For the TSF in most cases kmtip (except OnPreservedKey) will not call the non-updateable test parse. - // Therfore the core process event will need to be called before processing the actions. - - // CoreProcessEventRun would be a sufficient test however testing TIPFUpdateable defines - // the status of the keystroke processing more precisely. - if (!_td->TIPFUpdateable || !_td->CoreProcessEventRun) { - if (!Process_Event_Core(_td)) { - return FALSE; - } - } - - if (!_td->TIPFUpdateable) { - ProcessActionsNonUpdatableParse(&fOutputKeystroke); - } else { - ProcessActions(&fOutputKeystroke); + // For applications not using the TSF kmtip calls this function twice for each keystroke, + // first to determine if we are doing processing work (TIPFUpdateable == FALSE), + // if we say yes it will call a second time to actually do the work. + // We call the core process event only once and use the core's queued actions + // on the second pass. + // For the TSF in most cases kmtip (except OnPreservedKey) will not call the non-updateable test parse. + // Therfore the core process event will need to be called before processing the actions. + + // CoreProcessEventRun would be a sufficient test however testing TIPFUpdateable defines + // the status of the keystroke processing more precisely. + if (!_td->TIPFUpdateable || !_td->CoreProcessEventRun) { + if (!Process_Event_Core(_td)) { + return FALSE; } - } - else { - ProcessGroup(gp); // TODO: 5442 remove + + if (!_td->TIPFUpdateable) { + ProcessActionsNonUpdatableParse(&fOutputKeystroke); + } else { + ProcessActions(&fOutputKeystroke); } if (fOutputKeystroke && !_td->app->IsQueueEmpty()) { @@ -260,438 +251,6 @@ BOOL ProcessHook() return !fOutputKeystroke; } -/* -* PRIVATE BOOL ProcessGroup(LPGROUP gp); -* -* Parameters: gp Pointer to group to process inside -* -* Returns: TRUE if messages are to be sent, -* and FALSE if no messages are to be sent. -* -* Called by: ProcessHook, recursive inside groups -* -* ProcessKey is where the keystroke conversion and output takes place. This routine -* has a lot of crucial code in it! -*/ - -BOOL ProcessGroup(LPGROUP gp) -{ - if (!DebugAssert(!Globals::get_CoreIntegration(), "KMPROCESS:ProcessGroup: Error called in core integration mode")) { - return FALSE; - } - DWORD i; - LPKEY kkp = NULL; - PWSTR p; - int sdmfI; - - /* - If the number of nested groups goes higher than 50, then break out - this is - a limitation of stack size. This is basically a catch-all for freaky apps that - cause message loopbacks and nasty things like that. Okay, it's really a catch all - for bugs! This means the user's system shouldn't hang. - */ - - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - - _td->app->QueueDebugInformation(QID_GROUP_ENTER, gp, NULL, NULL, NULL, 0); - - sdmfI = -1; - - for(i = 0; i < _td->state.lpkb->cxGroupArray; i++) - if(gp == &_td->state.lpkb->dpGroupArray[i]) - { - if(_td->state.msg.message == wm_keymankeydown && ShouldDebug(sdmKeyboard)) - SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, "Entering group %d of %d, context '%s'", i+1, _td->state.lpkb->cxGroupArray, getcontext_debug()); - sdmfI = i; - break; - } - - if(++_td->state.LoopTimes > 50) - { - if(_td->state.msg.message == wm_keymankeydown) SendDebugMessage(_td->state.msg.hwnd, sdmKeyboard, 0, "Aborting output: state.LoopTimes exceeded."); - _td->state.StopOutput = TRUE; - _td->app->QueueDebugInformation(QID_GROUP_EXIT, gp, NULL, NULL, NULL, QID_FLAG_RECURSIVE_OVERFLOW); - return FALSE; - } - - _td->state.NoMatches = TRUE; - - /* - The rule matching loop. - - This loop iterates through all the rules in the group that is currently being - processed. Each rule in a group can be of three different types: - 1. A virtual key rule, where the key to be matched is a virtual key - 2. A normal key rule (WM_CHAR), where the key to be matched is an Ascii char. - 3. A rule in a keyless group, where only the context is matched. - - The loop goes through and checks the rules like that. This loop could be optimized - with standard searching techniques - the ContextMatch may be difficult. - */ - - if(ShouldDebug(sdmKeyboard)) - SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, "state.vkey: %s shiftFlags: %x; charCode: %X", - Debug_VirtualKey(_td->state.vkey), Globals::get_ShiftState(), _td->state.charCode); // I4582 - - if(gp) - { - for(kkp = gp->dpKeyArray, i=0; i < gp->cxKeyArray; i++, kkp++) - { - if(!ContextMatch(kkp)) continue; - if(!gp->fUsingKeys) - { - if(kkp->dpContext[0] != 0) break; else continue; - } - - //if(kkp->Key == state.vkey) - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, 0, "kkp->Key: %d kkp->ShiftFlags: %x", - // kkp->Key, kkp->ShiftFlags); - - /* Keyman 6.0: support Virtual Characters */ - if(IsEquivalentShift(kkp->ShiftFlags, Globals::get_ShiftState())) - { - if(kkp->Key > VK__MAX && kkp->Key == _td->state.vkey) break; // I3438 // I4582 - else if(kkp->Key == _td->state.vkey) break; // I4169 - } - else if(kkp->ShiftFlags == 0 && kkp->Key == _td->state.charCode && _td->state.charCode != 0) break; - } - } - - if(!gp || i == gp->cxKeyArray) - { - /* - No rule was found that corresponded to the current state of the context and - keyboard. NoMatch should be checked for everything except virtual keys; and - context should also be kept. - - If the message was a virtual key, then just return without checking NoMatch. - NoMatch shouldn't be used for virtual keys because it will mean that no key - can ever get through that isn't matched - including arrows, func. keys, etc !! - Context is not kept for virtual keys being output. - */ - - if(_td->state.msg.message == wm_keymankeydown && ShouldDebug(sdmKeyboard)) SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, - "No match was found in group %d of %d", sdmfI, _td->state.lpkb->cxGroupArray); - - if(!gp || (_td->state.charCode == 0 && gp->fUsingKeys)) // I4585 - // 7.0.241.0: I1133 - Fix mismatched parentheses on state.charCode - ie. we don't want to output this letter if !gp->fUsingKeys - { - BOOL fIsBackspace = _td->state.vkey == VK_BACK && (Globals::get_ShiftState() & (LCTRLFLAG|RCTRLFLAG|LALTFLAG|RALTFLAG)) == 0; // I4128 - - if(/*_td->app->DebugControlled() &&*/ fIsBackspace) { // I4838 // I4933 - if(_td->state.msg.message == wm_keymankeydown) { // I4933 - if(!_td->app->IsLegacy()) { // I4933 - PWCHAR pdeletecontext = _td->app->ContextBuf(1); // I4933 - if(!pdeletecontext || *pdeletecontext == 0) { // I4933 - _td->app->ResetContext(); // I4933 - fOutputKeystroke = TRUE; // I4933 - return FALSE; // I4933 - } - if (Uni_IsSurrogate1(*pdeletecontext) && Uni_IsSurrogate2(*(pdeletecontext+1))) { - // 2 backspaces to delete both parts of surrogate pair - // This only needs to be done for TSF-aware apps as legacy apps - // will receive a BKSP WM_KEYDOWN event which results in deleting - // both parts in one action - _td->app->QueueAction(QIT_BACK, BK_BACKSPACE | BK_SURROGATE); - } - else { - _td->app->QueueAction(QIT_BACK, BK_BACKSPACE); - } - } - else { - _td->app->QueueAction(QIT_BACK, BK_BACKSPACE); // I4933 - } - } - } else if( (!_td->app->IsLegacy() || !fIsBackspace) && !_td->TIPFPreserved) { // I4024 // I4128 // I4287 // I4290 - SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, " ... IsLegacy = FALSE; IsTIP = TRUE"); // I4128 - if(_td->state.charCode == 0) _td->app->ResetContext(); // I3573 // I3577 // I4585 - fOutputKeystroke = TRUE; - return FALSE; - } - //fOutputKeystroke = TRUE; return FALSE; // Don't swallow keystroke // I3577 - ///SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, " ... IsLegacy = TRUE; IsTIP = TRUE"); - - /* - If the key is not a character key (white keys), or not processing, then we must init the stack - - unknown keys do things like moving position in the context, so must clear. - */ - if(fIsBackspace) // I4128 - { - /* - Must have special handling for VK_BACK: delete a character from the context stack - This only fires if the keyboard has no rule for backspace. - */ - } - else - { - //app->NoSetShift = FALSE; - - DWORD dw = _td->state.vkey; - if(dw == 0x05) dw = VK_RETURN; // I649 - VK_ENTER and K_NPENTER - - if(_td->state.msg.lParam & (1<<24)) dw |= QVK_EXTENDED; // Extended key flag // I3438 - - if(_td->state.charCode == 0) { - _td->app->ResetContext(); - } - - if(_td->TIPFPreserved) { // I4290 - if(_td->state.charCode != 0) { - _td->app->QueueAction(QIT_CHAR, _td->state.charCode); - } - } else { - if(_td->state.msg.message == wm_keymankeydown) - { - _td->app->QueueAction(QIT_VSHIFTDOWN, Globals::get_ShiftState()); // 15/05/2001 - fixing I201 -- enabled line - _td->app->QueueAction(QIT_VKEYDOWN, dw); - } - - if(_td->state.msg.message == wm_keymankeyup) { - _td->app->QueueAction(QIT_VKEYUP, dw); - _td->app->QueueAction(QIT_VSHIFTUP, Globals::get_ShiftState()); - } - } - } - } - else if (gp->dpNoMatch != NULL && *gp->dpNoMatch != 0 && _td->state.msg.message != wm_keymankeyup) - { - /* NoMatch rule found, and is a character key */ - _td->app->QueueDebugInformation(QID_NOMATCH_ENTER, gp, NULL, NULL, gp->dpNoMatch, 0); - PostString(gp->dpNoMatch, &_td->state.msg, _td->state.lpkb, NULL); - _td->app->QueueDebugInformation(QID_NOMATCH_EXIT, gp, NULL, NULL, gp->dpNoMatch, 0); - } - else if (_td->state.charCode != 0 && _td->state.charCode != 0xFFFF && _td->state.msg.message != wm_keymankeyup && gp->fUsingKeys) - { - /* No rule found, is a character key */ - // 7.0.239.0: I994 - Workaround output order issues - we will use the TSF to output all characters... - // if(app->Type1() == AIType_TIP) { fOutputKeystroke = TRUE; return FALSE; } // Don't swallow keystroke - - _td->app->QueueAction(QIT_CHAR, _td->state.charCode); - } - - _td->app->QueueDebugInformation(QID_GROUP_EXIT, gp, NULL, NULL, NULL, QID_FLAG_NOMATCH); - return TRUE; - } - - if(_td->state.msg.message == wm_keymankeyup) - return TRUE; - - SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, "match found in rule %d", i); - - _td->state.NoMatches = FALSE; - - /* - Save the context that will be used for output when the 'context' keyword is used. - For each deadkey, we need to add 2 characters; look in related stores as well... - */ - - assert(kkp != NULL); - - _td->miniContextIfLen = xstrlen(kkp->dpContext) - xstrlen_ignoreifopt(kkp->dpContext); - - // 11 Aug 2003 - I25(v6) - mcdurdin - CODE_NUL context support - if(*kkp->dpContext == UC_SENTINEL && *(kkp->dpContext+1) == CODE_NUL) - wcsncpy_s(_td->miniContext, GLOBAL_ContextStackSize, _td->app->ContextBuf(xstrlen_ignoreifopt(kkp->dpContext)-1), GLOBAL_ContextStackSize); // I3162 // I3536 - else - wcsncpy_s(_td->miniContext, GLOBAL_ContextStackSize, _td->app->ContextBuf(xstrlen_ignoreifopt(kkp->dpContext)), GLOBAL_ContextStackSize); // I3162 // I3536 - - _td->miniContext[GLOBAL_ContextStackSize-1] = 0; - - _td->app->QueueDebugInformation(QID_RULE_ENTER, gp, kkp, _td->miniContext, NULL, 0); - - /* - The next section includes several optimizations that make the code a little harder - to read, but are probably worth it in the time that they save. - - If the output string doesn't have a "context" byte at the start, post backspaces - to erase the appropriate number of characters in the application. If it does have - a "context" byte at the start, then the string won't change, and no backspaces are - necessary. You could go one step further with this optimization, in PostAllKeys, - by comparing the starts of the strings to see what is same, and not backspacing - that, but it is probably not necessary. - */ - - p = kkp->dpOutput; - if(*p != UC_SENTINEL || *(p+1) != CODE_CONTEXT) { - for(PWSTR mcp = decxstr(wcschr(_td->miniContext, 0), _td->miniContext); mcp != NULL; mcp = decxstr(mcp, _td->miniContext)) { - if (*mcp == UC_SENTINEL) { - switch (*(mcp + 1)) { - case CODE_DEADKEY: _td->app->QueueAction(QIT_BACK, BK_DEADKEY); break; - case CODE_NUL: break; // 11 Aug 2003 - I25(v6) - mcdurdin - CODE_NUL context support - } - } - else if (Uni_IsSurrogate1(*mcp) && Uni_IsSurrogate2(*(mcp + 1))) { - // 2 backspaces to delete both parts of surrogate pair - // This only needs to be done for TSF-aware apps as legacy apps - // will receive a BKSP WM_KEYDOWN event which results in deleting - // both parts in one action - _td->app->QueueAction(QIT_BACK, BK_SURROGATE); - } - else { - _td->app->QueueAction(QIT_BACK, 0); - } - } - } - else { - // otherwise, the "context" entry has to be jumped over - p += 2; - } - - /* Use PostString to post the rest of the output string. */ - - if(PostString(p, &_td->state.msg, _td->state.lpkb, NULL) == psrCheckMatches) - { - _td->app->QueueDebugInformation(QID_RULE_EXIT, gp, kkp, _td->miniContext, NULL, 0); - - if(gp->dpMatch && *gp->dpMatch) - { - _td->app->QueueDebugInformation(QID_MATCH_ENTER, gp, NULL, NULL, gp->dpMatch, 0); - PostString(gp->dpMatch, &_td->state.msg, _td->state.lpkb, NULL); - _td->app->QueueDebugInformation(QID_MATCH_EXIT, gp, NULL, NULL, gp->dpMatch, 0); - } - } - else - _td->app->QueueDebugInformation(QID_RULE_EXIT, gp, kkp, _td->miniContext, NULL, 0); - _td->app->QueueDebugInformation(QID_GROUP_EXIT, gp, NULL, NULL, NULL, 0); - - return TRUE; -} - -/* -* int PostString( LPSTR str, BOOL *useMode, LPMSG mp, -* LPKEYBOARD lpkb ); -* -* Parameters: str Pointer to string to send -* useMode Pointer to BOOL about whether a "use" command was found -* mp Pointer to MSG structure to copy in outputting messages -* lpkb Pointer to global keyboard structure -* -* Returns: 0 to continue, 1 and 2 to return. -* -* Called by: ProcessKey -* -* PostString posts a string of "context", "index", "beep", characters and virtual keys -* to the active application, via the Keyman PostKey buffer. -*/ - -int PostString(PWSTR str, LPMSG mp, LPKEYBOARD lpkb, PWSTR endstr) -{ - if (!DebugAssert(!Globals::get_CoreIntegration(), "KKMPROCESS:PostString: Error called in core integration mode")) { - return FALSE; - } - PWSTR p, q, temp; - LPSTORE s; - int n1, n2; - int i, n, shift; - BOOL FoundUse = FALSE; - - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - - // TODO: Refactor to use incxstr - for(p = str; *p && (p < endstr || !endstr); p++) - { - if(*p == UC_SENTINEL) - switch(*(++p)) - { - case CODE_EXTENDED: // Start of a virtual key section w/shift codes - p++; - - shift = *p; //(*p<<8) | *(p+1); - _td->app->QueueAction(QIT_VSHIFTDOWN, shift); - - p++; - - _td->app->QueueAction(QIT_VKEYDOWN, *p); - _td->app->QueueAction(QIT_VKEYUP, *p); - - _td->app->QueueAction(QIT_VSHIFTUP, shift); - - p++; // CODE_EXTENDEDEND - ////// CODE_EXTENDEDEND will be incremented by loop - - //app->QueueAction(QIT_VSHIFTUP, shift); - break; - - case CODE_DEADKEY: // A deadkey to be output - p++; - _td->app->QueueAction(QIT_DEADKEY, *p); - break; - case CODE_BEEP: // Sound an 'iconasterisk' beep - _td->app->QueueAction(QIT_BELL, 0); - break; - case CODE_CONTEXT: // copy the context to the output - PostString(_td->miniContext, mp, lpkb, wcschr(_td->miniContext, 0)); - break; - case CODE_CONTEXTEX: - p++; - for(q = _td->miniContext, i = _td->miniContextIfLen; *q && i < *p-1; i++, q=incxstr(q)); - if(*q) { - temp = incxstr(q); - PostString(q, mp, lpkb, temp); - } - break; - case CODE_RETURN: // stop processing and start PostAllKeys - _td->state.StopOutput = TRUE; - return psrPostMessages; - - case CODE_CALL: - p++; - CallDLL(_td->lpActiveKeyboard, *p-1); - if(_td->state.StopOutput) return psrPostMessages; - FoundUse = TRUE; - break; - case CODE_USE: // use another group - p++; - ProcessGroup(&lpkb->dpGroupArray[*p-1]); - if(_td->state.StopOutput) return psrPostMessages; - FoundUse = TRUE; - break; - case CODE_CLEARCONTEXT: - _td->app->ResetContext(); - _td->app->ReadContext(); - break; - case CODE_INDEX: - p++; - s = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[*p - 1]; - p++; - - n = _td->IndexStack[*p - 1]; - for(temp = s->dpString; *temp && n > 0; temp = incxstr(temp), n--); - PostString(temp, mp, lpkb, incxstr(temp)); - break; - case CODE_SETOPT: - p++; - n1 = *p - 1; - p++; - n2 = *p - 1; - SetKeyboardOption(_td->lpActiveKeyboard, n1, n2); - break; - case CODE_RESETOPT: - p++; - n1 = *p - 1; - ResetKeyboardOption(_td->lpActiveKeyboard, n1); - break; - case CODE_SAVEOPT: - p++; - n1 = *p - 1; - SaveKeyboardOption(_td->lpActiveKeyboard, n1); - break; - case CODE_IFSYSTEMSTORE: - p+=3; - break; - case CODE_SETSYSTEMSTORE: - p+=2; - break; - } - else - _td->app->QueueAction(QIT_CHAR, *p); - } - return FoundUse ? psrPostMessages : psrCheckMatches; -} - - BOOL IsMatchingBaseLayout(PWCHAR layoutName) // I3432 { BOOL bEqual = _wcsicmp(layoutName, Globals::get_BaseKeyboardName()) == 0 || // I4583 @@ -731,196 +290,6 @@ BOOL IsMatchingPlatform(LPSTORE s) // I3432 return TRUE; } -/* -* BOOL ContextMatch( LPKEY kkp ); -* -* Parameters: kkp Rule to compare -* -* Returns: 0 on OK, 1 on not equal -* -* Called by: ProcessKey -* -* ContextMatch compares the context of a rule with the current context. -*/ - -BOOL ContextMatch(LPKEY kkp) -{ - if (!DebugAssert(!Globals::get_CoreIntegration(), "KMPROCESS:ContextMatch: Error called in core integration mode")) { - return FALSE; - } - WORD /*i,*/ n; - PWSTR p, q, qbuf, temp; - LPWORD indexp; - LPSTORE s, t; - BOOL bEqual; - - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: ENTER [%d]", kkp->Line); - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - - memset(_td->IndexStack, 0, GLOBAL_ContextStackSize*sizeof(WORD)); // I3158 // I3524 - - p = kkp->dpContext; - - if(*p == 0) - { - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: EXIT TRUE -> no rule context"); - return TRUE; - } - - /* 11 Aug 2003 - I25(v6) - mcdurdin - test for CODE_NUL */ - - if(*p == UC_SENTINEL && *(p+1) == CODE_NUL) - { - // If context buf is longer than the context, then obviously not start of doc. - if(_td->app->ContextBuf(xstrlen_ignoreifopt(p))) return FALSE; // I2484 - Fix bug with if() following nul in same statement - p = incxstr(p); - if(*p == 0) return TRUE; - } - - for(PWCHAR pp = p; pp && *pp; pp = incxstr(pp)) - { - if(*pp == UC_SENTINEL && *(pp+1) == CODE_IFOPT) - { - s = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(pp+2))-1]; // I2590 - t = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(pp+4))-1]; // I2590 - - bEqual = wcscmp(s->dpString, t->dpString) == 0; - if(*(pp+3) == 1 && bEqual) return FALSE; // I2590 - if(*(pp+3) == 2 && !bEqual) return FALSE; // I2590 - } - else if(*pp == UC_SENTINEL && *(pp+1) == CODE_IFSYSTEMSTORE) // I3432 - { - DWORD dwSystemID = *(pp+2)-1; - t = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(pp+4))-1]; // I2590 - switch(dwSystemID) - { - case TSS_PLATFORM_MATCH: // Cached platform result - a matching platform - bEqual = TRUE; - break; - case TSS_PLATFORM_NOMATCH: // Cached platform result - not a matching platform - bEqual = FALSE; - break; - case TSS_PLATFORM: - bEqual = IsMatchingPlatform(t); - break; - case TSS_BASELAYOUT: - bEqual = IsMatchingBaseLayout(t->dpString); - break; - default: - { - PWCHAR ss = GetSystemStore(_td->lpActiveKeyboard->Keyboard, dwSystemID); - if(ss == NULL) return FALSE; - bEqual = wcscmp(ss, t->dpString) == 0; - } - } - - if(*(pp+3) == 1 && bEqual) return FALSE; // I2590 - if(*(pp+3) == 2 && !bEqual) return FALSE; // I2590 - } - } - - q = qbuf = _td->app->ContextBuf(xstrlen_ignoreifopt(p)); - if(!q) - { - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: EXIT FALSE -> context too short"); - return FALSE; // context buf is too short! - } - indexp = _td->IndexStack; - - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: [%d] Rule: %s", kkp->Line, format_unicode_debug(kkp->dpContext)); - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: [%d] Test: %s", kkp->Line, format_unicode_debug(q)); - - for(; *p && *q; p = incxstr(p)) - { - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: p:%x q:%x", *p, *q); - *indexp = 0; - - if(*p == UC_SENTINEL) - { - switch(*(p+1)) - { - case CODE_DEADKEY: - if(*q != UC_SENTINEL || *(q+1) != CODE_DEADKEY || *(q+2) != *(p+2)) - { - // SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: EXIT FALSE -> deadkeys don't match %x %x %x != %x %x %x", - // *p, *(p+1), *(p+2), *q, *(q+1), *(q+2)); - return FALSE; - } - break; - case CODE_ANY: - s = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(p+2))-1]; - - temp = xstrchr(s->dpString, q); - - /*SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard ,kkp->Line, "ContextMatch: CODE_ANY [%x %x %x %x %x %x %x %x %x %x] [%x %x %x] %d", - s->dpString[0], s->dpString[1], s->dpString[2], - s->dpString[3], s->dpString[4], s->dpString[5], - s->dpString[6], s->dpString[7], s->dpString[8], - s->dpString[9], - q[0], q[1], q[2], - (temp ? (INT_PTR)(temp-s->dpString) : 0));*/ - - if(temp != NULL) // I1622 - *indexp = (WORD) xstrpos(temp, s->dpString); - - //if((temp = xstrchr(s->dpString, GetSuppChar(q))) != NULL) - // *indexp = xstrpos(temp, s->dpString); - else - return FALSE; - break; - case CODE_NOTANY: - s = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(p+2))-1]; - - if((temp = xstrchr(s->dpString, q)) != NULL) // I1622 - return FALSE; - - //if((temp = xstrchr(s->dpString, GetSuppChar(q))) != NULL) - // return FALSE; - break; - case CODE_INDEX: - s = &_td->lpActiveKeyboard->Keyboard->dpStoreArray[(*(p+2))-1]; - *indexp = n = _td->IndexStack[(*(p+3))-1]; - - for(temp = s->dpString; *temp && n > 0; temp = incxstr(temp), n--); - if(n != 0) return FALSE; - if(xchrcmp(temp, q) != 0) return FALSE; - ////if(GetSuppChar(temp) != GetSuppChar(q)) return FALSE; // I1622 - break; - case CODE_CONTEXTEX: - // only the nth character - for(n = *(p+2) - 1, temp = qbuf; temp < q && n > 0; n--, temp = incxstr(temp)); - if(n == 0) - if(xchrcmp(temp, q) != 0) return FALSE; - //if(GetSuppChar(temp) != GetSuppChar(q)) return FALSE; - break; - case CODE_IFOPT: - case CODE_IFSYSTEMSTORE: // I3432 - indexp++; - continue; // don't increment q - default: - return FALSE; - } - } - else if(xchrcmp(p, q) != 0) //GetSuppChar(p) != GetSuppChar(q)) - { - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: [%d] FAIL: %s", kkp->Line, format_unicode_debug(p)); - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: [%d] FAIL: %s", kkp->Line, format_unicode_debug(q)); - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: EXIT FALSE -> chrs don't match"); - return FALSE; - } - indexp++; - q = incxstr(q); - } - - while(*p == UC_SENTINEL && (*(p+1) == CODE_IFOPT || *(p+1) == CODE_IFSYSTEMSTORE)) p = incxstr(p); // already tested // I3432 - - //SendDebugMessageFormat(state.msg.hwnd, sdmKeyboard, kkp->Line, "ContextMatch: EXIT %s -> END OF FUNCTION", - // *p == *q ? "TRUE" : "FALSE"); - return *p == *q; /*at least one must ==0 at this point*/ -} - - PWSTR strtowstr(PSTR in) { PWSTR result; diff --git a/windows/src/engine/keyman32/preservedkeymap.cpp b/windows/src/engine/keyman32/preservedkeymap.cpp index cd13a82f8c..638099da57 100644 --- a/windows/src/engine/keyman32/preservedkeymap.cpp +++ b/windows/src/engine/keyman32/preservedkeymap.cpp @@ -37,12 +37,11 @@ struct PreservedKey class PreservedKeyMap { public: - BOOL MapKeyboard(KEYBOARD *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys); /** * Updates a map of preserved keys (with GUID) that are used in keyboard rules. * Passing in NULL for pPreservedKeys will cause cPreservedKeys to be set to the number - * of preserved keys needed for the supplied pKeyboard; this should be used in creating - * pPreservedKeys list to sufficient size. When pPreservedKeys list is passed the + * of preserved keys needed for the supplied pKeyboard; this should be used in creating + * pPreservedKeys list to sufficient size. When pPreservedKeys list is passed the * cPreservedKeys will be the actual count of the number of unique pPreservedKeys * * @param pKeyboard the keyboard for which the rules will be extracted from @@ -280,92 +279,6 @@ BOOL PreservedKeyMap::IsMatchingKey(PreservedKey *pKey, PreservedKey *pKeys, siz return FALSE; } -// TODO: 5442 - Remove once core processor verfied -BOOL PreservedKeyMap::MapKeyboard(KEYBOARD *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys) -{ - size_t cKeys = 0, n; - DWORD i, j; - GROUP *pGroup; - - m_BaseKeyboardUsesAltGr = KeyboardGivesCtrlRAltForRAlt(); // I4592 - - // This is not the same as m_BaseKeyboardUsesAltGr -- we are turning - // the simulation back on after (possibly) turning it off, for a - // consistent experience. TODO: determine if m_BaseKeyboardUseAltGr - // is still needed given we always use kbdus as base for Keyman 10+ - BOOL bSimulateAltGr = Globals::get_SimulateAltGr(); - - // We only want to translate RALT and RALT+SHIFT for Ctrl+Alt rules. - // So we exclude all our other favourite modifier keys. - const UINT RALT_MATCHING_MASK = TF_MOD_CONTROL | TF_MOD_ALT | TF_MOD_LCONTROL | TF_MOD_RCONTROL | TF_MOD_LALT | TF_MOD_RALT; - - for(i = 0; i < pKeyboard->cxGroupArray; i++) - { - if(pKeyboard->dpGroupArray[i].fUsingKeys) - { - cKeys += pKeyboard->dpGroupArray[i].cxKeyArray; - } - } - - if(cKeys == 0) - { - return FALSE; - } - - if (bSimulateAltGr) - { - // We might need twice as many preserved keys to map both LCtrl+LAlt+x and RAlt+x - cKeys *= 2; - } - - if(pPreservedKeys == NULL) - { - *cPreservedKeys = cKeys; - return TRUE; - } - - if(*cPreservedKeys < cKeys) - { - return FALSE; - } - - PreservedKey *pKeys = *pPreservedKeys; - - for(n = i = 0; i < pKeyboard->cxGroupArray; i++) - { - pGroup = &pKeyboard->dpGroupArray[i]; - if(pGroup->fUsingKeys) - { - for(j = 0; j < pGroup->cxKeyArray; j++) - { - // If we have a key rule for the key, we should preserve it - if(MapKeyRule(&pGroup->dpKeyArray[j], &pKeys[n].key)) - { - // Don't attempt to add the same preserved key twice. Bad things happen - if(!IsMatchingKey(&pKeys[n], pKeys, n)) - { - CoCreateGuid(&pKeys[n].guid); - n++; - - if (bSimulateAltGr && (pKeys[n-1].key.uModifiers & RALT_MATCHING_MASK) == TF_MOD_RALT) - { - // Do this for RALT and RALT+SHIFT only, so we've tested against that mask - // Copy the key and fix modifiers - pKeys[n].key = pKeys[n - 1].key; - pKeys[n].key.uModifiers = (pKeys[n].key.uModifiers & ~TF_MOD_RALT) | TF_MOD_LCONTROL | TF_MOD_LALT; - CoCreateGuid(&pKeys[n].guid); - n++; - } - } - } - } - } - } - - *cPreservedKeys = n; // return actual count of allocated keys, usually smaller than allocated count - return TRUE; -} - BOOL PreservedKeyMap::MapKeyboardCore(km_kbp_keyboard *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys) { size_t cKeys = 0, cRules = 0, n = 0; @@ -457,23 +370,14 @@ extern "C" __declspec(dllexport) BOOL WINAPI GetKeyboardPreservedKeys(PreservedK if (!_td) { return FALSE; } + if (!_td->lpActiveKeyboard) { return FALSE; } - // It could be an active core keyboard - if (Globals::get_CoreIntegration()) { - - if (!_td->lpActiveKeyboard->lpCoreKeyboard) { - return FALSE; - } - // use api to get key rules - return pkm.MapKeyboardCore(_td->lpActiveKeyboard->lpCoreKeyboard, pPreservedKeys, cPreservedKeys); - } else { // TODO: 5442 Remove else - if (!_td->lpActiveKeyboard->Keyboard) { - return FALSE; - } - return pkm.MapKeyboard(_td->lpActiveKeyboard->Keyboard, pPreservedKeys, cPreservedKeys); + if (!_td->lpActiveKeyboard->lpCoreKeyboard) { + return FALSE; } - + // use api to get key rules + return pkm.MapKeyboardCore(_td->lpActiveKeyboard->lpCoreKeyboard, pPreservedKeys, cPreservedKeys); } diff --git a/windows/src/engine/keyman32/selectkeyboard.cpp b/windows/src/engine/keyman32/selectkeyboard.cpp index ae6f366f3f..0e35eca3ce 100644 --- a/windows/src/engine/keyman32/selectkeyboard.cpp +++ b/windows/src/engine/keyman32/selectkeyboard.cpp @@ -53,7 +53,7 @@ // I3594 // I4220 -BOOL SelectKeyboardCore(DWORD KeymanID) +BOOL SelectKeyboard(DWORD KeymanID) { int i; HWND hwnd = GetFocus(); @@ -78,7 +78,7 @@ BOOL SelectKeyboardCore(DWORD KeymanID) } KMHideIM(); - + if (_td->lpActiveKeyboard) DeactivateDLLs(_td->lpActiveKeyboard); _td->lpActiveKeyboard = NULL; _td->ActiveKeymanID = KEYMANID_NONKEYMAN; @@ -106,7 +106,7 @@ BOOL SelectKeyboardCore(DWORD KeymanID) SelectApplicationIntegration(); // I4287 if (_td->app && !_td->app->IsWindowHandled(hwnd)) _td->app->HandleWindow(hwnd); _td->state.windowunicode = !_td->app || _td->app->IsUnicode(); - + ActivateDLLs(_td->lpActiveKeyboard); return TRUE; @@ -130,88 +130,6 @@ BOOL SelectKeyboardCore(DWORD KeymanID) return TRUE; } -BOOL SelectKeyboard(DWORD KeymanID) -{ - if (Globals::get_CoreIntegration()) - { - return SelectKeyboardCore(KeymanID); - } - int i; - HWND hwnd = GetFocus(); - - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - - SendDebugMessageFormat(hwnd,sdmGlobal,0,"ENTER SelectKeyboard-------------------------------------------"); - SendDebugMessageFormat(hwnd,sdmGlobal,0,"ENTER SelectKeyboard: Current:(HKL=%x KeymanID=%x %s) New:(ID=%x)", //lpActiveKeyboard=%s ActiveKeymanID: %x sk: %x KeymanID: %d", - GetKeyboardLayout(0), - _td->ActiveKeymanID, - _td->lpActiveKeyboard == NULL ? "NULL" : _td->lpActiveKeyboard->Name, - //_td->NextKeyboardLayout, - KeymanID); - - __try - { - if(_td->ForceFileName[0]) - { - SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: Ignored due to ForceFile"); - return FALSE; // Keyboard file is force-loaded - } - - KMHideIM(); - - if(_td->lpActiveKeyboard) DeactivateDLLs(_td->lpActiveKeyboard); - _td->lpActiveKeyboard = NULL; - _td->ActiveKeymanID = KEYMANID_NONKEYMAN; - - //SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: nKeyboards=%d", nKeyboards); - - for(i = 0; i < _td->nKeyboards; i++) - { - if(_td->lpKeyboards[i].KeymanID == KeymanID) - { - if(!_td->lpKeyboards[i].Keyboard && !LoadlpKeyboard(i)) - { - SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: Unable to load"); - return TRUE; - } - - _td->lpActiveKeyboard = &_td->lpKeyboards[i]; - _td->ActiveKeymanID = _td->lpActiveKeyboard->KeymanID; - - SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: NewKeymanID: %x", _td->ActiveKeymanID); - - if(_td->app) _td->app->ResetContext(); - ResetCapsLock(); - - SelectApplicationIntegration(); // I4287 - if(_td->app && !_td->app->IsWindowHandled(hwnd)) _td->app->HandleWindow(hwnd); - _td->state.windowunicode = !_td->app || _td->app->IsUnicode(); - - ActivateDLLs(_td->lpActiveKeyboard); - - return TRUE; - } - } - - if(IsFocusedThread()) - { - SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: Keyboard Not Found"); - } - } - __finally - { - SendDebugMessageFormat(hwnd,sdmGlobal,0,"EXIT SelectKeyboard: Current:(HKL=%x KeymanID=%x %s) New:(ID=%x)", //lpActiveKeyboard=%s ActiveKeymanID: %x sk: %x KeymanID: %d", - GetKeyboardLayout(0), - _td->ActiveKeymanID, - _td->lpActiveKeyboard == NULL ? "NULL" : _td->lpActiveKeyboard->Name, - KeymanID); - SendDebugMessageFormat(hwnd,sdmGlobal,0,"EXIT SelectKeyboard-------------------------------------------"); - } - return TRUE; -} - - BOOL SelectKeyboardTSF(DWORD dwIdentity, BOOL foreground) // I3933 // I3949 // I4271 { if (!foreground && IsFocusedThread()) { -- GitLab From ec8539543bd01a1561dd6ed8514baa1879c3ed9b Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 19 Apr 2023 14:27:03 +1000 Subject: [PATCH 002/214] chore(windows): remove dead code --- windows/src/engine/keyman32/kmprocess.cpp | 41 ------------------- .../src/engine/keyman32/preservedkeymap.cpp | 38 ----------------- 2 files changed, 79 deletions(-) diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index ff0e234edc..142817bc6a 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -119,7 +119,6 @@ Process_Event_Core(PKEYMAN64THREADDATA _td) { return TRUE; } - /* * BOOL ProcessHook(); * @@ -251,45 +250,6 @@ BOOL ProcessHook() return !fOutputKeystroke; } -BOOL IsMatchingBaseLayout(PWCHAR layoutName) // I3432 -{ - BOOL bEqual = _wcsicmp(layoutName, Globals::get_BaseKeyboardName()) == 0 || // I4583 - _wcsicmp(layoutName, Globals::get_BaseKeyboardNameAlt()) == 0; // I4583 - - return bEqual; -} - -BOOL IsMatchingPlatformString(PWCHAR platform) // I3432 -{ - return - _wcsicmp(platform, L"windows") == 0 || - _wcsicmp(platform, L"desktop") == 0 || - _wcsicmp(platform, L"hardware") == 0 || - _wcsicmp(platform, L"native") == 0; -} - -BOOL IsMatchingPlatform(LPSTORE s) // I3432 -{ - PWCHAR t = new WCHAR[wcslen(s->dpString)+1]; - wcscpy_s(t, wcslen(s->dpString)+1, s->dpString); - PWCHAR context = NULL; - PWCHAR platform = wcstok_s(t, L" ", &context); - while(platform != NULL) - { - if(!IsMatchingPlatformString(platform)) - { - s->dwSystemID = TSS_PLATFORM_NOMATCH; - delete[] t; - return FALSE; - } - platform = wcstok_s(NULL, L" ", &context); - } - - s->dwSystemID = TSS_PLATFORM_MATCH; - delete[] t; - return TRUE; -} - PWSTR strtowstr(PSTR in) { PWSTR result; @@ -302,7 +262,6 @@ PWSTR strtowstr(PSTR in) return result; } - PSTR wstrtostr(PCWSTR in) { PSTR result; diff --git a/windows/src/engine/keyman32/preservedkeymap.cpp b/windows/src/engine/keyman32/preservedkeymap.cpp index 638099da57..be3cd54a53 100644 --- a/windows/src/engine/keyman32/preservedkeymap.cpp +++ b/windows/src/engine/keyman32/preservedkeymap.cpp @@ -55,7 +55,6 @@ private: BOOL m_BaseKeyboardUsesAltGr; // I4592 UINT ShiftToTSFShift(UINT ShiftFlags); BOOL MapUSCharToVK(UINT *puKey, UINT *puShiftFlags); - BOOL MapKeyRule(KEY *pKey, TF_PRESERVEDKEY *pPreservedKey); BOOL MapKeyRuleCore(km_kbp_keyboard_key *pKeyRule, TF_PRESERVEDKEY *pPreservedKey); BOOL IsMatchingKey(PreservedKey *pKey, PreservedKey *pKeys, size_t cKeys); }; @@ -198,43 +197,6 @@ UINT PreservedKeyMap::ShiftToTSFShift(UINT ShiftFlags) return res; } -BOOL PreservedKeyMap::MapKeyRule(KEY *pKey, TF_PRESERVEDKEY *pPreservedKey) -{ - UINT ShiftFlags; - UINT Key; - - Key = pKey->Key; - ShiftFlags = pKey->ShiftFlags; - - if(Key == VK_BACK || Key == VK_RETURN || Key == VK_TAB) // I4575 - { - // - // We never map backspace, return or tab because these are the only supported virtual key outputs, - // and result in recursion. Sadly, this is an imperfect solution forced upon us by preserved key - // limitations. - // - // Other virtual key output will be blocked with this version. - return FALSE; - } - - if (Key > 255) { - // - // Touch-defined keys have a value > 255, but these should never be preserved - // - return FALSE; - } - - if(ShiftFlags == 0) - { - if(!MapUSCharToVK(&Key, &ShiftFlags)) return FALSE; - } - - pPreservedKey->uVKey = (UINT) USVKToScanCodeToLayoutVK( (WORD) Key); // I3762 - pPreservedKey->uModifiers = ShiftToTSFShift(ShiftFlags); - - return TRUE; -} - BOOL PreservedKeyMap::MapKeyRuleCore(km_kbp_keyboard_key *pKeyRule, TF_PRESERVEDKEY *pPreservedKey) { UINT ShiftFlags; -- GitLab From 1b46bc1d010af451e372a2e566fbe7cd14ad1733 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 20 Apr 2023 16:55:54 +1000 Subject: [PATCH 003/214] chore(windows): remove keyboardoptions deadcode --- windows/src/engine/keyman32/appint/aiTIP.cpp | 13 --- windows/src/engine/keyman32/appint/appint.h | 9 -- .../src/engine/keyman32/keyboardoptions.cpp | 84 ------------------- windows/src/engine/keyman32/keyboardoptions.h | 6 -- windows/src/engine/keyman32/keyman32.cpp | 2 - windows/src/engine/keyman32/keymanengine.h | 1 - 6 files changed, 115 deletions(-) diff --git a/windows/src/engine/keyman32/appint/aiTIP.cpp b/windows/src/engine/keyman32/appint/aiTIP.cpp index d90a85068d..8b4fd9ed6b 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.cpp +++ b/windows/src/engine/keyman32/appint/aiTIP.cpp @@ -366,19 +366,6 @@ void AITIP::ReadContext() { } } -AppContextWithStores::AppContextWithStores(int nKeyboardOptions) : AppContext() { // I4978 - this->nKeyboardOptions = nKeyboardOptions; - KeyboardOptions = new INTKEYBOARDOPTIONS[nKeyboardOptions]; - memset(KeyboardOptions, 0, sizeof(INTKEYBOARDOPTIONS) * nKeyboardOptions); -} - -AppContextWithStores::~AppContextWithStores() { // I4978 - for(DWORD i = 0; i < nKeyboardOptions; i++) { - if(KeyboardOptions[i].Value) delete KeyboardOptions[i].Value; - } - delete KeyboardOptions; -} - void AITIP::CopyContext(AppContext *savedContext) { savedContext->CopyFrom(context); } diff --git a/windows/src/engine/keyman32/appint/appint.h b/windows/src/engine/keyman32/appint/appint.h index 3e9a4dfb4d..77b20c3b01 100644 --- a/windows/src/engine/keyman32/appint/appint.h +++ b/windows/src/engine/keyman32/appint/appint.h @@ -178,15 +178,6 @@ public: }; -class AppContextWithStores : public AppContext // I4978 -{ -public: - AppContextWithStores(int nKeyboardOptions); - ~AppContextWithStores(); - DWORD nKeyboardOptions; - LPINTKEYBOARDOPTIONS KeyboardOptions; -}; - class AppIntegration:public AppActionQueue { protected: diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index 1b8efe22f8..6ef1d660f9 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -19,8 +19,6 @@ */ #include "pch.h" -void IntSaveKeyboardOption(LPCSTR key, LPINTKEYBOARDINFO kp, int nStoreToSave); -BOOL IntLoadKeyboardOptions(LPCSTR key, LPINTKEYBOARDINFO kp); BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* const state); void IntSaveKeyboardOptionREGCore(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value); @@ -37,28 +35,6 @@ static km_kbp_cp* CloneKMKBPCPFromWSTR(LPWSTR buf) { return clone; } -void LoadKeyboardOptions(LPINTKEYBOARDINFO kp) -{ // I3594 - IntLoadKeyboardOptions(REGSZ_KeyboardOptions, kp); -} - -void FreeKeyboardOptions(LPINTKEYBOARDINFO kp) -{ - // This is a cleanup routine; we don't want to precondition all calls to it - // so we do not assert - if (kp == NULL || kp->Keyboard == NULL || kp->KeyboardOptions == NULL) - return; - - for(DWORD i = 0; i < kp->Keyboard->cxStoreArray; i++) - if(kp->KeyboardOptions[i].Value) - { - kp->Keyboard->dpStoreArray[i].dpString = kp->KeyboardOptions[i].OriginalStore; - delete kp->KeyboardOptions[i].Value; - } - delete kp->KeyboardOptions; - kp->KeyboardOptions = NULL; -} - void SaveKeyboardOptionREGCore(LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value) { IntSaveKeyboardOptionREGCore(REGSZ_KeyboardOptions, kp, key, value); @@ -78,66 +54,6 @@ void IntSaveKeyboardOptionREGCore(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR k } } -BOOL IntLoadKeyboardOptions(LPCSTR key, LPINTKEYBOARDINFO kp) -{ - assert(key != NULL); - assert(kp != NULL); - assert(kp->Keyboard != NULL); - assert(kp->KeyboardOptions == NULL); - - kp->KeyboardOptions = new INTKEYBOARDOPTIONS[kp->Keyboard->cxStoreArray]; - memset(kp->KeyboardOptions, 0, sizeof(INTKEYBOARDOPTIONS) * kp->Keyboard->cxStoreArray); - RegistryReadOnly r(HKEY_CURRENT_USER); - if(r.OpenKeyReadOnly(REGSZ_KeymanActiveKeyboards) && r.OpenKeyReadOnly(kp->Name) && r.OpenKeyReadOnly(key)) - { - WCHAR buf[256]; - int n = 0; - while(r.GetValueNames(buf, sizeof(buf) / sizeof(buf[0]), n)) - { - buf[255] = 0; - WCHAR val[256]; - if(r.ReadString(buf, val, sizeof(val) / sizeof(val[0])) && val[0]) - { - val[255] = 0; - for(DWORD i = 0; i < kp->Keyboard->cxStoreArray; i++) - { - if(kp->Keyboard->dpStoreArray[i].dpName != NULL && _wcsicmp(kp->Keyboard->dpStoreArray[i].dpName, buf) == 0) - { - kp->KeyboardOptions[i].Value = new WCHAR[wcslen(val)+1]; - wcscpy_s(kp->KeyboardOptions[i].Value, wcslen(val)+1, val); - - kp->KeyboardOptions[i].OriginalStore = kp->Keyboard->dpStoreArray[i].dpString; - kp->Keyboard->dpStoreArray[i].dpString = kp->KeyboardOptions[i].Value; - - break; - } - } - } - n++; - } - return TRUE; - } - return FALSE; -} - -void IntSaveKeyboardOption(LPCSTR key, LPINTKEYBOARDINFO kp, int nStoreToSave) -{ - assert(key != NULL); - assert(kp != NULL); - assert(kp->Keyboard != NULL); - assert(kp->KeyboardOptions != NULL); - assert(nStoreToSave >= 0); - assert(nStoreToSave < (int) kp->Keyboard->cxStoreArray); - - if(kp->Keyboard->dpStoreArray[nStoreToSave].dpName == NULL) return; - - RegistryFullAccess r(HKEY_CURRENT_USER); - if(r.OpenKey(REGSZ_KeymanActiveKeyboards, TRUE) && r.OpenKey(kp->Name, TRUE) && r.OpenKey(key, TRUE)) - { - r.WriteString(kp->Keyboard->dpStoreArray[nStoreToSave].dpName, kp->Keyboard->dpStoreArray[nStoreToSave].dpString); - } -} - void LoadKeyboardOptionsREGCore(LPINTKEYBOARDINFO kp, km_kbp_state* const state) { SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadKeyboardOptionsREGCore: Enter"); diff --git a/windows/src/engine/keyman32/keyboardoptions.h b/windows/src/engine/keyman32/keyboardoptions.h index cef9ae6df1..7694bab47d 100644 --- a/windows/src/engine/keyman32/keyboardoptions.h +++ b/windows/src/engine/keyman32/keyboardoptions.h @@ -16,12 +16,6 @@ History: 25 May 2010 - mcdurdin - I1632 - Keyboard Options */ -void LoadKeyboardOptions(LPINTKEYBOARDINFO kp); -void FreeKeyboardOptions(LPINTKEYBOARDINFO kp); -void SetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSet, int nStoreToRead); -void ResetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToReset); -void SaveKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSave); -void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp); /** * Updates the supplied Keyboard processor options list from the keyboard processor pointed * to by the state pointer. diff --git a/windows/src/engine/keyman32/keyman32.cpp b/windows/src/engine/keyman32/keyman32.cpp index cc857dfeb7..1d22fd3941 100644 --- a/windows/src/engine/keyman32/keyman32.cpp +++ b/windows/src/engine/keyman32/keyman32.cpp @@ -641,7 +641,6 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_StopForcingKeyboard() if(!DeactivateDLLs(_td->lpActiveKeyboard)) return FALSE; // I3173 // I3525 if(!UnloadDLLs(_td->lpActiveKeyboard)) return FALSE; // I3173 // I3525 _td->ForceFileName[0] = 0; - FreeKeyboardOptions(_td->lpActiveKeyboard); ReleaseKeyboardMemory(_td->lpActiveKeyboard->Keyboard); ReleaseStateMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboardState); ReleaseKeyboardMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboard); @@ -1031,7 +1030,6 @@ void ReleaseKeyboards(BOOL Lock) for(int i = 0; i < _td->nKeyboards; i++) { if(Lock) UnloadDLLs(&_td->lpKeyboards[i]); - FreeKeyboardOptions(&_td->lpKeyboards[i]); ReleaseKeyboardMemory(_td->lpKeyboards[i].Keyboard); ReleaseStateMemoryCore(&_td->lpKeyboards[i].lpCoreKeyboardState); ReleaseKeyboardMemoryCore(&_td->lpKeyboards[i].lpCoreKeyboard); diff --git a/windows/src/engine/keyman32/keymanengine.h b/windows/src/engine/keyman32/keymanengine.h index 96bf668c2f..267e2843cc 100644 --- a/windows/src/engine/keyman32/keymanengine.h +++ b/windows/src/engine/keyman32/keymanengine.h @@ -85,7 +85,6 @@ typedef struct tagINTKEYBOARDINFO DWORD nIMDLLs; LPIMDLL IMDLLs; int __filler2; // makes same as KEYBOARDINFO - LPINTKEYBOARDOPTIONS KeyboardOptions; int nProfiles; LPINTKEYBOARDPROFILE Profiles; km_kbp_keyboard* lpCoreKeyboard; -- GitLab From 616dcc8420a8aed70b6b64839a2d7048d1b2433f Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 20 Apr 2023 21:27:59 +1000 Subject: [PATCH 004/214] chore(windows): revert whitespace changes for review --- windows/src/engine/keyman32/glossary.cpp | 32 ++++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/windows/src/engine/keyman32/glossary.cpp b/windows/src/engine/keyman32/glossary.cpp index ba29ec3464..2954638c19 100644 --- a/windows/src/engine/keyman32/glossary.cpp +++ b/windows/src/engine/keyman32/glossary.cpp @@ -1,18 +1,18 @@ /* Name: glossary Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 20 Jul 2008 Modified Date: 28 May 2014 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 20 Jul 2008 - mcdurdin - I1498 - Fix keyboard switching for Shadow keyboards on Vista+ 20 Jul 2008 - mcdurdin - I1546 - Fix language switch with ids >= x80000000 20 Jul 2008 - mcdurdin - I1545 - Fix registry leak @@ -38,9 +38,9 @@ BOOL HKLIsIME(HKL hkl) // I1498 - fix keyboard switching for shadow keyboards o if( (GetVersion() & 0xFF) >= 6 ) return FALSE; if( (GetVersion() & 0x8000000) == 0x8000000 || (GetVersion() & 0xFF) == 4 ) r = GetSystemMetrics(SM_DBCSENABLED); - else + else r = GetSystemMetrics(SM_IMMENABLED); - + return r && ImmIsIME(hkl); } #pragma warning(default: 4996) @@ -99,12 +99,12 @@ DWORD HKLToKeyboardID(HKL hkl) return (DWORD) LOWORD(hkl); } - for(len=16, n = i = 0; RegEnumKeyEx(hkey, i, str, &len, 0, NULL, NULL, &ft) == ERROR_SUCCESS; - len = 16, i++, n=0) + for(len=16, n = i = 0; RegEnumKeyEx(hkey, i, str, &len, 0, NULL, NULL, &ft) == ERROR_SUCCESS; + len = 16, i++, n=0) { RegOpenKeyEx(hkey, str, NULL, KEY_READ, &hsubkey); len = 16; - if(RegQueryValueEx(hsubkey, REGSZ_LayoutID, NULL, NULL, (LPBYTE) str2, &len) == ERROR_SUCCESS) + if(RegQueryValueEx(hsubkey, REGSZ_LayoutID, NULL, NULL, (LPBYTE) str2, &len) == ERROR_SUCCESS) { n = strtoul(str2, NULL, 16); // I1546 if(n == LayoutID) @@ -120,7 +120,7 @@ DWORD HKLToKeyboardID(HKL hkl) } RegCloseKey(hkey); - + //SendDebugMessageFormat(0, sdmGlobal, 0, "HKLToKeyboardID: fails[2], return LOWORD(hkl)=%x", LOWORD(hkl)); return (DWORD) LOWORD(hkl); // should never happen } @@ -143,11 +143,11 @@ WORD HKLToLayoutNumber(HKL hkl) if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSZ_SystemKeyboardLayouts, NULL, KEY_READ, &hkey) != ERROR_SUCCESS) return 0; - for(len=16, n = i = 0; RegEnumKeyEx(hkey, i, str, &len, 0, NULL, NULL, &ft) == ERROR_SUCCESS; len = 16, i++, n=0) + for(len=16, n = i = 0; RegEnumKeyEx(hkey, i, str, &len, 0, NULL, NULL, &ft) == ERROR_SUCCESS; len = 16, i++, n=0) { RegOpenKeyEx(hkey, str, NULL, KEY_READ, &hsubkey); len = 16; - if(RegQueryValueEx(hsubkey, REGSZ_LayoutID, NULL, NULL, (LPBYTE) str2, &len) == ERROR_SUCCESS) + if(RegQueryValueEx(hsubkey, REGSZ_LayoutID, NULL, NULL, (LPBYTE) str2, &len) == ERROR_SUCCESS) { if(strtoul(str2, NULL, 16) == LayoutID) break; // strtoul - I1546 } @@ -195,7 +195,7 @@ DWORD EthnologueCodeToKeymanID(DWORD EthCode) DWORD EthnologueStringCodeToDWord(PWSTR EthCode) { if(wcslen(EthCode) < 3 || wcslen(EthCode) > 4) return (DWORD)-1; - return (LOBYTE(EthCode[0])) | + return (LOBYTE(EthCode[0])) | (LOBYTE(EthCode[1]) << 8) | (LOBYTE(EthCode[2]) << 16) | (LOBYTE(EthCode[3]) << 24); -- GitLab From 4019a79676310cd2b1ddc63bdf218c9b6fd2fa39 Mon Sep 17 00:00:00 2001 From: Ross Date: Fri, 21 Apr 2023 18:43:50 +1000 Subject: [PATCH 005/214] chore(windows): address review comments --- common/windows/cpp/include/registry.h | 3 - windows/src/engine/keyman32/calldll.cpp | 20 ------ windows/src/engine/keyman32/calldll.h | 2 - windows/src/engine/keyman32/capsstate.cpp | 70 ------------------- windows/src/engine/keyman32/capsstate.h | 3 - windows/src/engine/keyman32/glossary.cpp | 49 ++++++------- windows/src/engine/keyman32/keyman32.cpp | 14 ++-- windows/src/engine/keyman32/keymanengine.h | 2 - .../src/engine/keyman32/kmhook_getmessage.cpp | 2 - .../src/engine/keyman32/selectkeyboard.cpp | 3 +- 10 files changed, 32 insertions(+), 136 deletions(-) diff --git a/common/windows/cpp/include/registry.h b/common/windows/cpp/include/registry.h index 4e2fe9ae35..895f9e83be 100644 --- a/common/windows/cpp/include/registry.h +++ b/common/windows/cpp/include/registry.h @@ -129,9 +129,6 @@ #define REGSZ_Flag_UseCachedHotkeyModifierState "Flag_UseCachedHotkeyModifierState" -/* REGSZ_Flag_UseKeymanCore DWORD: Turns on the common core - instead of windows core */ -#define REGSZ_Flag_UseKeymanCore "Flag_UseKeymanCore" - /* DWORD: Enable/disable deep TSF integration, default enabled; 0 = disabled, 1 = enabled, 2 = default */ #define REGSZ_DeepTSFIntegration "deep tsf integration" diff --git a/windows/src/engine/keyman32/calldll.cpp b/windows/src/engine/keyman32/calldll.cpp index 9b9a6ae428..f0c623373c 100644 --- a/windows/src/engine/keyman32/calldll.cpp +++ b/windows/src/engine/keyman32/calldll.cpp @@ -253,26 +253,6 @@ BOOL DeactivateDLLs(LPINTKEYBOARDINFO lpkbi) return TRUE; } -void CallDLL(LPINTKEYBOARDINFO lpkbi, DWORD storenum) -{ - //SendDebugMessageFormat(0, sdmKeyboard, 0, "CallDll: Enter"); - if (!lpkbi->Keyboard) return; - if(storenum >= lpkbi->Keyboard->cxStoreArray) return; - - LPSTORE s = &lpkbi->Keyboard->dpStoreArray[storenum]; - if(s->dwSystemID != TSS_CALLDEFINITION) return; - if(s->dpString == NULL) return; - LPIMDLLHOOK imdh = (LPIMDLLHOOK) s->dpString; - - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return; - - if(_td->TIPFUpdateable) { // I4452 - (*imdh->function)(_td->state.msg.hwnd, _td->state.vkey, _td->state.charCode, Globals::get_ShiftState()); - } - //SendDebugMessageFormat(0, sdmKeyboard, 0, "CallDll: Exit"); -} - // The callback function called by the Core Keyboardprocessor extern "C" uint8_t IM_CallBackCore(km_kbp_state *km_state, uint32_t UniqueStoreNo, void *callbackObject) { //SendDebugMessageFormat(0, sdmKeyboard, 0, "IM_CallBackCore: Enter"); diff --git a/windows/src/engine/keyman32/calldll.h b/windows/src/engine/keyman32/calldll.h index 6faebcb70a..cf9d64e1a2 100644 --- a/windows/src/engine/keyman32/calldll.h +++ b/windows/src/engine/keyman32/calldll.h @@ -35,8 +35,6 @@ BOOL LoadDLLs(LPINTKEYBOARDINFO lpkbi); BOOL IsIMWindow(HWND hwnd); -void CallDLL(LPINTKEYBOARDINFO lpkbi, DWORD storenum); - // Callback function used by the core processor to call out to 3rd Party Library functions extern "C" uint8_t IM_CallBackCore(km_kbp_state *km_state, uint32_t UniqueStoreNo, void *callbackObject); diff --git a/windows/src/engine/keyman32/capsstate.cpp b/windows/src/engine/keyman32/capsstate.cpp index c9d283cde4..4f9b466e9e 100644 --- a/windows/src/engine/keyman32/capsstate.cpp +++ b/windows/src/engine/keyman32/capsstate.cpp @@ -29,73 +29,3 @@ BOOL IsCapsLockOn(void) { return GetKeyState(VK_CAPITAL) & 1; } - -void ResetCapsLock(void) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if (!_td) return; - if (!_td->lpActiveKeyboard) return; - if (!_td->lpActiveKeyboard->Keyboard) return; - - SendDebugMessageFormat(0, sdmGlobal, 0, "ResetCapsLock: enter"); - - if (_td->lpActiveKeyboard->Keyboard->dwFlags & KF_CAPSALWAYSOFF) - { - SendDebugMessageFormat(0, sdmGlobal, 0, "ResetCapsLock: caps lock should be always off"); - if (IsCapsLockOn()) - { - SendDebugMessageFormat(0, sdmGlobal, 0, "ResetCapsLock: caps lock is on, switching off caps lock"); - keybd_event(VK_CAPITAL, 0x3A, 0, 0); - keybd_event(VK_CAPITAL, 0x3A, 0 | KEYEVENTF_KEYUP, 0); - } - } - SendDebugMessageFormat(0, sdmGlobal, 0, "ResetCapsLock: exit"); -} - - -void KeyCapsLockPress(BOOL FIsUp) // I3284 - void // I3529 -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if (!_td) return; - if (!_td->lpActiveKeyboard) return; // pass through to window - if (!_td->lpActiveKeyboard->Keyboard) return; - - if (_td->lpActiveKeyboard->Keyboard->dwFlags & KF_CAPSONONLY) - { - SendDebugMessageFormat(0, sdmAIDefault, 0, "KeyCapsLockPress: KF_CAPSONONLY: FIsUp=%d CapsState=%d", FIsUp, IsCapsLockOn()); - if (FIsUp && !IsCapsLockOn()) // I267 - 24/11/2006 invert GetKeyState test - { - keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, 0, 0); - keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, KEYEVENTF_KEYUP, 0); - } - } - else if (_td->lpActiveKeyboard->Keyboard->dwFlags & KF_CAPSALWAYSOFF) - { - SendDebugMessageFormat(0, sdmAIDefault, 0, "KeyCapsLockPress: KF_CAPSALWAYSOFF: FIsUp=%d CapsState=%d", FIsUp, IsCapsLockOn()); - if (!FIsUp && IsCapsLockOn()) - { // I267 - 24/11/2006 invert GetKeyState test - keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, KEYEVENTF_KEYUP, 0); - keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, 0, 0); - } - } -} - - -void KeyShiftPress(BOOL FIsUp) // I3284 - void // I3529 -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if (!_td) return; - if (!_td->lpActiveKeyboard) return; // pass through to window - if (!_td->lpActiveKeyboard->Keyboard) return; - - if (_td->lpActiveKeyboard->Keyboard->dwFlags & KF_SHIFTFREESCAPS) - { - SendDebugMessageFormat(0, sdmAIDefault, 0, "KeyShiftPress: KF_SHIFTFREESCAPS: FIsUp=%d CapsState=%d", FIsUp, IsCapsLockOn()); - if (!FIsUp && IsCapsLockOn()) - { - keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, 0, 0); - keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, KEYEVENTF_KEYUP, 0); - } - } -} - diff --git a/windows/src/engine/keyman32/capsstate.h b/windows/src/engine/keyman32/capsstate.h index aeb3e29000..d28ba9c0db 100644 --- a/windows/src/engine/keyman32/capsstate.h +++ b/windows/src/engine/keyman32/capsstate.h @@ -20,8 +20,5 @@ #define __CAPSSTATE_H BOOL IsCapsLockOn(void); -void ResetCapsLock(void); -void KeyCapsLockPress(BOOL FIsUp); -void KeyShiftPress(BOOL FIsUp); #endif diff --git a/windows/src/engine/keyman32/glossary.cpp b/windows/src/engine/keyman32/glossary.cpp index 2954638c19..be1c498451 100644 --- a/windows/src/engine/keyman32/glossary.cpp +++ b/windows/src/engine/keyman32/glossary.cpp @@ -167,30 +167,31 @@ WORD HKLToLayoutID(HKL hkl) return HIWORD(hkl) & 0x0FFF; } -DWORD EthnologueCodeToKeymanID(DWORD EthCode) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return KEYMANID_NONKEYMAN; - - for(int i = 0; i < _td->nKeyboards; i++) - { - if(!_td->lpKeyboards[i].Keyboard && !LoadlpKeyboard(i)) - { - SendDebugMessageFormat(0,sdmGlobal,0, - "EthnologueCodeToKeymanID: Unable to load keyboard %s", _td->lpKeyboards[i].Name); - return KEYMANID_NONKEYMAN; - } - - PWSTR ps = GetSystemStore(_td->lpKeyboards[i].Keyboard, TSS_ETHNOLOGUECODE); - if(ps) - { - SendDebugMessageFormat(0,sdmGlobal,0,"EthnologueCodeToKeymanID: %s %ws %x", _td->lpKeyboards[i].Name, ps, EthnologueStringCodeToDWord(ps)); - if(EthnologueStringCodeToDWord(ps) == EthCode) return _td->lpKeyboards[i].KeymanID; - } - } - - return KEYMANID_NONKEYMAN; -} +// TODO: Make this use the core +//DWORD EthnologueCodeToKeymanID(DWORD EthCode) +//{ +// PKEYMAN64THREADDATA _td = ThreadGlobals(); +// if(!_td) return KEYMANID_NONKEYMAN; +// +// for(int i = 0; i < _td->nKeyboards; i++) +// { +// if(!_td->lpKeyboards[i].Keyboard && !LoadlpKeyboard(i)) +// { +// SendDebugMessageFormat(0,sdmGlobal,0, +// "EthnologueCodeToKeymanID: Unable to load keyboard %s", _td->lpKeyboards[i].Name); +// return KEYMANID_NONKEYMAN; +// } +// +// PWSTR ps = GetSystemStore(_td->lpKeyboards[i].Keyboard, TSS_ETHNOLOGUECODE); +// if(ps) +// { +// SendDebugMessageFormat(0,sdmGlobal,0,"EthnologueCodeToKeymanID: %s %ws %x", _td->lpKeyboards[i].Name, ps, EthnologueStringCodeToDWord(ps)); +// if(EthnologueStringCodeToDWord(ps) == EthCode) return _td->lpKeyboards[i].KeymanID; +// } +// } +// +// return KEYMANID_NONKEYMAN; +//} DWORD EthnologueStringCodeToDWord(PWSTR EthCode) { diff --git a/windows/src/engine/keyman32/keyman32.cpp b/windows/src/engine/keyman32/keyman32.cpp index 1d22fd3941..962697d78b 100644 --- a/windows/src/engine/keyman32/keyman32.cpp +++ b/windows/src/engine/keyman32/keyman32.cpp @@ -558,10 +558,7 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_ForceKeyboard(PCSTR FileName _td->lpActiveKeyboard = new INTKEYBOARDINFO; memset(_td->lpActiveKeyboard, 0, sizeof(INTKEYBOARDINFO)); // I2437 - Crash unloading keyboard due to keyboard options not init - /*_td->lpActiveKeyboard->KeymanID = 0; - _td->lpActiveKeyboard->nIMDLLs = 0; - _td->lpActiveKeyboard->IMDLLs = NULL; - _td->lpActiveKeyboard->KeyboardOptions = NULL;*/ + _splitpath_s(FileName, NULL, 0, NULL, 0, _td->lpActiveKeyboard->Name, sizeof(_td->lpActiveKeyboard->Name), NULL, 0); PWCHAR keyboardPath = strtowstr(_td->ForceFileName); @@ -595,7 +592,10 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_ForceKeyboard(PCSTR FileName goto fail; } - ResetCapsLock(); + // TODO: #5882 Add km_kbp_event to reset keyboard action sent to keyman core + // (only the core knows the caps rules such CAPS_ALWAYS_OFF) + // so it can then respond with a possible reset + err_status = km_kbp_keyboard_get_imx_list(_td->lpActiveKeyboard->lpCoreKeyboard, &_td->lpActiveKeyboard->lpIMXList); if (err_status != KM_KBP_STATUS_OK) { SendDebugMessageFormat(0, sdmLoad, 0, "Keyman_ForceKeyboard Core: km_kbp_keyboard_get_imx_list failed with error status [%d]", err_status); @@ -641,7 +641,6 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_StopForcingKeyboard() if(!DeactivateDLLs(_td->lpActiveKeyboard)) return FALSE; // I3173 // I3525 if(!UnloadDLLs(_td->lpActiveKeyboard)) return FALSE; // I3173 // I3525 _td->ForceFileName[0] = 0; - ReleaseKeyboardMemory(_td->lpActiveKeyboard->Keyboard); ReleaseStateMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboardState); ReleaseKeyboardMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboard); RefreshPreservedKeys(FALSE); @@ -996,8 +995,6 @@ void RefreshKeyboards(BOOL Initialising) RefreshKeyboardProfiles(kp, FALSE); // Read standard profiles RefreshKeyboardProfiles(kp, TRUE); // Read transient profiles - kp->Keyboard = NULL; - SendDebugMessageFormat(0,sdmGlobal,0,"RefreshKeyboards: Added keyboard %s, %d", kp->Name, kp->KeymanID); i++; @@ -1030,7 +1027,6 @@ void ReleaseKeyboards(BOOL Lock) for(int i = 0; i < _td->nKeyboards; i++) { if(Lock) UnloadDLLs(&_td->lpKeyboards[i]); - ReleaseKeyboardMemory(_td->lpKeyboards[i].Keyboard); ReleaseStateMemoryCore(&_td->lpKeyboards[i].lpCoreKeyboardState); ReleaseKeyboardMemoryCore(&_td->lpKeyboards[i].lpCoreKeyboard); if(_td->lpKeyboards[i].Profiles) delete _td->lpKeyboards[i].Profiles; // I3581 diff --git a/windows/src/engine/keyman32/keymanengine.h b/windows/src/engine/keyman32/keymanengine.h index 267e2843cc..c70d039ff7 100644 --- a/windows/src/engine/keyman32/keymanengine.h +++ b/windows/src/engine/keyman32/keymanengine.h @@ -81,7 +81,6 @@ typedef struct tagINTKEYBOARDINFO DWORD __filler_Hotkey; DWORD __filler; // makes same as KEYBOARDINFO // I4462 char Name[256]; - LPKEYBOARD Keyboard; DWORD nIMDLLs; LPIMDLL IMDLLs; int __filler2; // makes same as KEYBOARDINFO @@ -123,7 +122,6 @@ LRESULT CALLBACK kmnLowLevelKeyboardProc( // I4124 _In_ LPARAM lParam ); -BOOL ReleaseKeyboardMemory(LPKEYBOARD kbd); BOOL ReleaseStateMemoryCore(km_kbp_state** state); BOOL ReleaseKeyboardMemoryCore(km_kbp_keyboard** kbd); diff --git a/windows/src/engine/keyman32/kmhook_getmessage.cpp b/windows/src/engine/keyman32/kmhook_getmessage.cpp index bc7200ef0d..5aec91a958 100644 --- a/windows/src/engine/keyman32/kmhook_getmessage.cpp +++ b/windows/src/engine/keyman32/kmhook_getmessage.cpp @@ -271,7 +271,6 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam) if(_td->lpActiveKeyboard) { - _td->state.lpkb = _td->lpActiveKeyboard->Keyboard; _td->state.lpCoreKb = _td->lpActiveKeyboard->lpCoreKeyboard; } // I4412 @@ -369,7 +368,6 @@ void ProcessWMKeyman(HWND hwnd, WPARAM wParam, LPARAM lParam) hwnd = GetFocus(); if(_td->lpActiveKeyboard) { - _td->state.lpkb = _td->lpActiveKeyboard->Keyboard; _td->state.lpCoreKb = _td->lpActiveKeyboard->lpCoreKeyboard; } diff --git a/windows/src/engine/keyman32/selectkeyboard.cpp b/windows/src/engine/keyman32/selectkeyboard.cpp index 0e35eca3ce..5ee61592b7 100644 --- a/windows/src/engine/keyman32/selectkeyboard.cpp +++ b/windows/src/engine/keyman32/selectkeyboard.cpp @@ -101,7 +101,8 @@ BOOL SelectKeyboard(DWORD KeymanID) SendDebugMessageFormat(hwnd, sdmGlobal, 0, "SelectKeyboardCore: NewKeymanID: %x", _td->ActiveKeymanID); if (_td->app) _td->app->ResetContext(); - ResetCapsLock(); + + // TODO: #5882 tell the core with km_kbp_event so it can reset the capslock state SelectApplicationIntegration(); // I4287 if (_td->app && !_td->app->IsWindowHandled(hwnd)) _td->app->HandleWindow(hwnd); -- GitLab From 5f07f7ad080991bd9f2feebec0d9cc261be107c5 Mon Sep 17 00:00:00 2001 From: Ross Date: Fri, 21 Apr 2023 19:02:03 +1000 Subject: [PATCH 006/214] chore(windows): remove addins c-h files --- windows/src/engine/keyman32/addins.cpp | 263 ------------------ windows/src/engine/keyman32/addins.h | 23 -- .../keyman32/appint/aiWin2000Unicode.cpp | 1 - .../src/engine/keyman32/keyman-engine.vcxproj | 6 - .../keyman32/keyman-engine.vcxproj.filters | 3 - windows/src/engine/keyman32/keyman32.cpp | 3 - windows/src/engine/keyman32/keyman32.vcxproj | 7 - .../engine/keyman32/keyman32.vcxproj.filters | 6 - windows/src/engine/keyman32/keymanengine.h | 1 - .../src/engine/keyman32/kmhook_getmessage.cpp | 9 +- windows/src/engine/keyman64/keyman64.vcxproj | 2 - .../engine/keyman64/keyman64.vcxproj.filters | 2 - 12 files changed, 2 insertions(+), 324 deletions(-) delete mode 100644 windows/src/engine/keyman32/addins.cpp delete mode 100644 windows/src/engine/keyman32/addins.h diff --git a/windows/src/engine/keyman32/addins.cpp b/windows/src/engine/keyman32/addins.cpp deleted file mode 100644 index 6c7f5d0f28..0000000000 --- a/windows/src/engine/keyman32/addins.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* - Name: addins - Copyright: Copyright (C) SIL International. - Documentation: - Description: - Create Date: 14 Jun 2008 - - Modified Date: 14 May 2010 - Authors: mcdurdin - Related Files: - Dependencies: - - Bugs: - Todo: - Notes: - History: 14 Jun 2008 - mcdurdin - I1488 - Fix registry handle leak - 11 Mar 2009 - mcdurdin - I1894 - Fix threading bugs introduced in I1888 - 11 Dec 2009 - mcdurdin - I934 - x64 - Initial version - 12 Mar 2010 - mcdurdin - I934 - x64 - Complete - 12 Mar 2010 - mcdurdin - I2229 - Remove hints and warnings - 04 May 2010 - mcdurdin - I2351 - Robustness - verify _td return value - 14 May 2010 - mcdurdin - I2374 - Fix crash in some situations -*/ - -#include "pch.h" - -void Addin_Release() -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return; - - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addin_Release: ENTER [%d]", nAddins); - if(_td->Addins) - { - for(int i = 0; i < _td->nAddins; i++) - if(_td->Addins[i].hAddin) - { - if(_td->Addins[i].Uninitialise) (*_td->Addins[i].Uninitialise)(); - FreeLibrary(_td->Addins[i].hAddin); - } - delete[] _td->Addins; - } - _td->Addins = NULL; - _td->nAddins = 0; - _td->CurrentAddin = -1; - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addin_Release: EXIT"); -} - -void ReadAddins(HKEY hkey) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return; - - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: ReadAddins: ENTER"); - RegistryReadOnly *reg = new RegistryReadOnly(hkey); - if(reg->OpenKeyReadOnly(hkey == HKEY_CURRENT_USER ? REGSZ_KeymanAddinsCU : REGSZ_KeymanAddinsLM)) - { - int n = _td->nAddins; - char buf[128]; - while(reg->GetValueNames(buf, 128, n)) - { - Addin *a = new Addin[n+1]; - if(_td->Addins) - { - memcpy(a, _td->Addins, n * sizeof(Addin)); - delete[] _td->Addins; - } - _td->Addins = a; - _td->Addins[n].hAddin = 0; - _td->Addins[n].FocusChanged = NULL; - _td->Addins[n].Initialise = NULL; - _td->Addins[n].OutputBackspace = NULL; - _td->Addins[n].OutputChar = NULL; - _td->Addins[n].Uninitialise = NULL; - _td->Addins[n].ShouldProcess = NULL; - strcpy(_td->Addins[n].ClassName, buf); - reg->ReadString(buf, _td->Addins[n].AddinName, 260); - _td->Addins[n].Application[0] = 0; - n++; - } - _td->nAddins = n; - } - delete reg; - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: ReadAddins: EXIT"); -} - -void Addin_Refresh() -{ - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addin_Refresh: ENTER"); - Addin_Release(); - ReadAddins(HKEY_CURRENT_USER); - ReadAddins(HKEY_LOCAL_MACHINE); - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addin_Refresh: EXIT"); -} - -BOOL LoadAddin() -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - if(_td->CurrentAddin == -1) return FALSE; - - Addin *a = &_td->Addins[_td->CurrentAddin]; - if(!a->hAddin) - { - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: LoadAddin: ENTER"); - a->hAddin = LoadLibrary(a->AddinName); - if(!a->hAddin) - { - a->hAddin = 0; - a->ClassName[0] = 0; // prevent add-in attempting to load again - _td->CurrenthWnd = 0; - _td->CurrentAddin = -1; - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: LoadAddin: EXIT - FALSE - LoadLibrary"); - return FALSE; - } - a->OutputBackspace = (PKeymanOutputBackspace) GetProcAddress(a->hAddin, "KeymanOutputBackspace"); - a->OutputChar = (PKeymanOutputChar) GetProcAddress(a->hAddin, "KeymanOutputChar"); - a->FocusChanged = (PKeymanFocusChanged) GetProcAddress(a->hAddin, "KeymanFocusChanged"); - a->ShouldProcess = (PKeymanShouldProcess) GetProcAddress(a->hAddin, "KeymanShouldProcess"); - a->Initialise = (PKeymanInit) GetProcAddress(a->hAddin, "KeymanInitialise"); - a->Uninitialise = (PKeymanInit) GetProcAddress(a->hAddin, "KeymanUninitialise"); - - if(a->Initialise && !(*a->Initialise)()) - { - FreeLibrary(a->hAddin); - a->hAddin = 0; - a->ClassName[0] = 0; - _td->CurrenthWnd = 0; - _td->CurrentAddin = -1; - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: LoadAddin: EXIT - FALSE - Initialise"); - return FALSE; - } - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: LoadAddin: EXIT - TRUE - Loaded"); - } - return TRUE; -} - -BOOL Addin_ShouldProcessUnichar(HWND hwnd) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ShouldProcessUnichar: ENTER"); - _td->CurrenthWnd = hwnd; - GetClassName(hwnd, _td->CurrentClassName, 128); - if(_td->CurrentAddin >= 0 && !_strcmpi(_td->CurrentClassName, _td->Addins[_td->CurrentAddin].ClassName)) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ShouldProcessUnichar: EXIT - TRUE - CurrentAddin okay"); - return TRUE; - } - - for(int i = 0; i < _td->nAddins; i++) - if(!_strcmpi(_td->CurrentClassName, _td->Addins[i].ClassName)) - { - _td->CurrentAddin = i; - if(!LoadAddin()) - { - _td->CurrentAddin = -1; - _td->Addins[i].ClassName[0] = 0; // prevent add-in attempting to load again - } - else if(_td->Addins[i].ShouldProcess && !(*_td->Addins[i].ShouldProcess)(hwnd)) - _td->CurrentAddin = -1; - else - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ShouldProcessUnichar: EXIT - TRUE - FoundAddin"); - return TRUE; - } - } - _td->CurrentAddin = -1; - _td->CurrenthWnd = 0; - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ShouldProcessUnichar: EXIT - FALSE"); - return FALSE; -} - -BOOL Addin_ProcessUnichar(HWND hwnd, DWORD chr) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: ENTER"); - if(_td->CurrenthWnd != hwnd) - if(!Addin_ShouldProcessUnichar(hwnd)) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: EXIT - FALSE - Addin_ShouldProcessUnichar"); - return FALSE; - } - - if(!LoadAddin()) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: EXIT - FALSE - !LoadAddin)"); - return FALSE; - } - if(!_td->Addins[_td->CurrentAddin].OutputChar) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: EXIT - FALSE !OutputChar"); - return FALSE; - } - - BOOL b = (*_td->Addins[_td->CurrentAddin].OutputChar)(hwnd, chr); - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: EXIT (b) == %d", b); - return b; -} - -BOOL Addin_ProcessBackspace(HWND hwnd) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: ENTER"); - if(_td->CurrenthWnd != hwnd) - if(!Addin_ShouldProcessUnichar(hwnd)) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: EXIT - !ShouldProcess"); - return FALSE; - } - - if(!LoadAddin()) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: EXIT - !LoadAddin"); - return FALSE; - } - if(!_td->Addins[_td->CurrentAddin].OutputBackspace) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: EXIT - !OutputBackspace"); - return FALSE; - } - - BOOL b = (*_td->Addins[_td->CurrentAddin].OutputBackspace)(hwnd); - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: EXIT - (b) = %d", b); - return b; -} - -void Addin_FocusChanged(HWND hwnd) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return; - - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: ENTER"); - - if(_td->CurrenthWnd != hwnd) - if(!Addin_ShouldProcessUnichar(hwnd)) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: EXIT - !ShouldProcess"); - return; - } - - if(!LoadAddin()) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: EXIT - !LoadAddin"); - return; - } - - // Addin variables must be valid now - - if(!_td->Addins[_td->CurrentAddin].FocusChanged) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: EXIT - !FocusChanged"); - return; - } - - (*_td->Addins[_td->CurrentAddin].FocusChanged)(); - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: EXIT"); -} diff --git a/windows/src/engine/keyman32/addins.h b/windows/src/engine/keyman32/addins.h deleted file mode 100644 index 71aa006e59..0000000000 --- a/windows/src/engine/keyman32/addins.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - Name: addins - Copyright: Copyright (C) SIL International. - Documentation: - Description: - Create Date: 11 Dec 2009 - - Modified Date: 11 Dec 2009 - Authors: mcdurdin - Related Files: - Dependencies: - - Bugs: - Todo: - Notes: - History: 11 Dec 2009 - mcdurdin - I934 - x64 - Initial version -*/ -void Addin_Release(); -void Addin_Refresh(); -BOOL Addin_ShouldProcessUnichar(HWND hwnd); -BOOL Addin_ProcessUnichar(HWND hwnd, DWORD chr); -BOOL Addin_ProcessBackspace(HWND hwnd); -void Addin_FocusChanged(HWND hwnd); diff --git a/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp b/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp index 19da87a543..5fa67fc715 100644 --- a/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp +++ b/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp @@ -277,7 +277,6 @@ BOOL AIWin2000Unicode::PostKeys() break; case QIT_BACK: if(Queue[n].dwData & BK_DEADKEY) break; - if(Addin_ProcessBackspace(hwnd)) break; pInputs[i].type = INPUT_KEYBOARD; pInputs[i].ki.wVk = VK_BACK; diff --git a/windows/src/engine/keyman32/keyman-engine.vcxproj b/windows/src/engine/keyman32/keyman-engine.vcxproj index 6869117fd9..632b4e6a67 100644 --- a/windows/src/engine/keyman32/keyman-engine.vcxproj +++ b/windows/src/engine/keyman32/keyman-engine.vcxproj @@ -186,12 +186,6 @@ - - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) diff --git a/windows/src/engine/keyman32/keyman-engine.vcxproj.filters b/windows/src/engine/keyman32/keyman-engine.vcxproj.filters index 7cd4d906d1..c0eab08097 100644 --- a/windows/src/engine/keyman32/keyman-engine.vcxproj.filters +++ b/windows/src/engine/keyman32/keyman-engine.vcxproj.filters @@ -15,9 +15,6 @@ - - Source Files - Source Files diff --git a/windows/src/engine/keyman32/keyman32.cpp b/windows/src/engine/keyman32/keyman32.cpp index 962697d78b..0e238cb6ea 100644 --- a/windows/src/engine/keyman32/keyman32.cpp +++ b/windows/src/engine/keyman32/keyman32.cpp @@ -492,7 +492,6 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_Exit(void) *Globals::Keyman_Shutdown() = TRUE; ReleaseKeyboards(TRUE); - Addin_Release(); if(!Globals::get_Keyman_Initialised()) { @@ -925,8 +924,6 @@ void RefreshKeyboards(BOOL Initialising) // Can happen when multiple top-level windows for one process - Addin_Refresh(); - SendDebugMessageFormat(0,sdmGlobal,0,"---ENTER RefreshKeyboards---"); //FInRefreshKeyboards = TRUE; diff --git a/windows/src/engine/keyman32/keyman32.vcxproj b/windows/src/engine/keyman32/keyman32.vcxproj index 0d78d2c292..670df3c1d4 100644 --- a/windows/src/engine/keyman32/keyman32.vcxproj +++ b/windows/src/engine/keyman32/keyman32.vcxproj @@ -176,12 +176,6 @@ - - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) @@ -362,7 +356,6 @@ - diff --git a/windows/src/engine/keyman32/keyman32.vcxproj.filters b/windows/src/engine/keyman32/keyman32.vcxproj.filters index 8995c39a93..dcf5f5d4c5 100644 --- a/windows/src/engine/keyman32/keyman32.vcxproj.filters +++ b/windows/src/engine/keyman32/keyman32.vcxproj.filters @@ -15,9 +15,6 @@ - - Source Files - Source Files @@ -162,9 +159,6 @@ - - Header Files - Header Files diff --git a/windows/src/engine/keyman32/keymanengine.h b/windows/src/engine/keyman32/keymanengine.h index c70d039ff7..fe536cb399 100644 --- a/windows/src/engine/keyman32/keymanengine.h +++ b/windows/src/engine/keyman32/keymanengine.h @@ -246,7 +246,6 @@ void keybd_shift(LPINPUT pInputs, int* n, BOOL isReset, LPBYTE const kbd); #include "keystate.h" #include "calldll.h" -#include "addins.h" #include "keymancontrol.h" #include "keyboardoptions.h" #include "kmprocessactions.h" diff --git a/windows/src/engine/keyman32/kmhook_getmessage.cpp b/windows/src/engine/keyman32/kmhook_getmessage.cpp index 5aec91a958..9b128dccc6 100644 --- a/windows/src/engine/keyman32/kmhook_getmessage.cpp +++ b/windows/src/engine/keyman32/kmhook_getmessage.cpp @@ -252,13 +252,9 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam) Handle WM_UNICHAR messages for RichEdit control -- should we test RichEdit version? */ - if(mp->message == WM_UNICHAR && Addin_ShouldProcessUnichar(mp->hwnd)) + if(mp->message == WM_UNICHAR) { - if(Addin_ProcessUnichar(mp->hwnd, (DWORD) mp->wParam)) - { - mp->message = 0; - return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); - } + return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); } /* @@ -379,7 +375,6 @@ void ProcessWMKeyman(HWND hwnd, WPARAM wParam, LPARAM lParam) { if(_td->app) _td->app->ResetQueue(); GetCapsAndNumlockState(); - Addin_FocusChanged(hwnd); UpdateActiveWindows(); } } diff --git a/windows/src/engine/keyman64/keyman64.vcxproj b/windows/src/engine/keyman64/keyman64.vcxproj index d70c0872ed..15546caef5 100644 --- a/windows/src/engine/keyman64/keyman64.vcxproj +++ b/windows/src/engine/keyman64/keyman64.vcxproj @@ -177,7 +177,6 @@ - @@ -279,7 +278,6 @@ - diff --git a/windows/src/engine/keyman64/keyman64.vcxproj.filters b/windows/src/engine/keyman64/keyman64.vcxproj.filters index 0b53bd96cb..cd8aeefb32 100644 --- a/windows/src/engine/keyman64/keyman64.vcxproj.filters +++ b/windows/src/engine/keyman64/keyman64.vcxproj.filters @@ -2,7 +2,6 @@ - @@ -41,7 +40,6 @@ - -- GitLab From ec01969adc539200e84f994cd9d5974d5bf05bc3 Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 26 Apr 2023 23:00:21 +1000 Subject: [PATCH 007/214] chore(windows): fix issue number in comments --- windows/src/engine/keyman32/keyman32.cpp | 6 +++--- windows/src/engine/keyman32/selectkeyboard.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/windows/src/engine/keyman32/keyman32.cpp b/windows/src/engine/keyman32/keyman32.cpp index 0e238cb6ea..a1690409f9 100644 --- a/windows/src/engine/keyman32/keyman32.cpp +++ b/windows/src/engine/keyman32/keyman32.cpp @@ -591,9 +591,10 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_ForceKeyboard(PCSTR FileName goto fail; } - // TODO: #5882 Add km_kbp_event to reset keyboard action sent to keyman core + // TODO: #5822 Add km_kbp_event to reset keyboard action sent to keyman core // (only the core knows the caps rules such CAPS_ALWAYS_OFF) - // so it can then respond with a possible reset + // so it can then respond with a possible reset. Currently this sorts itself out + // the first keystroke pressed after switching to a new keyboard. err_status = km_kbp_keyboard_get_imx_list(_td->lpActiveKeyboard->lpCoreKeyboard, &_td->lpActiveKeyboard->lpIMXList); if (err_status != KM_KBP_STATUS_OK) { @@ -609,7 +610,6 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_ForceKeyboard(PCSTR FileName LoadKeyboardOptionsREGCore(_td->lpActiveKeyboard, _td->lpActiveKeyboard->lpCoreKeyboardState); RefreshPreservedKeys(TRUE); return TRUE; - // happy to use while(!done) pattern fail: delete _td->lpActiveKeyboard; diff --git a/windows/src/engine/keyman32/selectkeyboard.cpp b/windows/src/engine/keyman32/selectkeyboard.cpp index 5ee61592b7..d600262fd4 100644 --- a/windows/src/engine/keyman32/selectkeyboard.cpp +++ b/windows/src/engine/keyman32/selectkeyboard.cpp @@ -102,7 +102,7 @@ BOOL SelectKeyboard(DWORD KeymanID) if (_td->app) _td->app->ResetContext(); - // TODO: #5882 tell the core with km_kbp_event so it can reset the capslock state + // TODO: #5822 tell the core with km_kbp_event so it can reset the capslock state SelectApplicationIntegration(); // I4287 if (_td->app && !_td->app->IsWindowHandled(hwnd)) _td->app->HandleWindow(hwnd); -- GitLab From 0ee25dc59fe145b74a5fdc9291319c624e0e05b2 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 27 Apr 2023 14:15:06 +1000 Subject: [PATCH 008/214] chore(windows): Revert "chore(windows): remove addins c-h files" This reverts commit 5f07f7ad080991bd9f2feebec0d9cc261be107c5. --- windows/src/engine/keyman32/addins.cpp | 263 ++++++++++++++++++ windows/src/engine/keyman32/addins.h | 23 ++ .../keyman32/appint/aiWin2000Unicode.cpp | 1 + .../src/engine/keyman32/keyman-engine.vcxproj | 6 + .../keyman32/keyman-engine.vcxproj.filters | 3 + windows/src/engine/keyman32/keyman32.cpp | 3 + windows/src/engine/keyman32/keyman32.vcxproj | 7 + .../engine/keyman32/keyman32.vcxproj.filters | 6 + windows/src/engine/keyman32/keymanengine.h | 1 + .../src/engine/keyman32/kmhook_getmessage.cpp | 9 +- windows/src/engine/keyman64/keyman64.vcxproj | 2 + .../engine/keyman64/keyman64.vcxproj.filters | 2 + 12 files changed, 324 insertions(+), 2 deletions(-) create mode 100644 windows/src/engine/keyman32/addins.cpp create mode 100644 windows/src/engine/keyman32/addins.h diff --git a/windows/src/engine/keyman32/addins.cpp b/windows/src/engine/keyman32/addins.cpp new file mode 100644 index 0000000000..6c7f5d0f28 --- /dev/null +++ b/windows/src/engine/keyman32/addins.cpp @@ -0,0 +1,263 @@ +/* + Name: addins + Copyright: Copyright (C) SIL International. + Documentation: + Description: + Create Date: 14 Jun 2008 + + Modified Date: 14 May 2010 + Authors: mcdurdin + Related Files: + Dependencies: + + Bugs: + Todo: + Notes: + History: 14 Jun 2008 - mcdurdin - I1488 - Fix registry handle leak + 11 Mar 2009 - mcdurdin - I1894 - Fix threading bugs introduced in I1888 + 11 Dec 2009 - mcdurdin - I934 - x64 - Initial version + 12 Mar 2010 - mcdurdin - I934 - x64 - Complete + 12 Mar 2010 - mcdurdin - I2229 - Remove hints and warnings + 04 May 2010 - mcdurdin - I2351 - Robustness - verify _td return value + 14 May 2010 - mcdurdin - I2374 - Fix crash in some situations +*/ + +#include "pch.h" + +void Addin_Release() +{ + PKEYMAN64THREADDATA _td = ThreadGlobals(); + if(!_td) return; + + //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addin_Release: ENTER [%d]", nAddins); + if(_td->Addins) + { + for(int i = 0; i < _td->nAddins; i++) + if(_td->Addins[i].hAddin) + { + if(_td->Addins[i].Uninitialise) (*_td->Addins[i].Uninitialise)(); + FreeLibrary(_td->Addins[i].hAddin); + } + delete[] _td->Addins; + } + _td->Addins = NULL; + _td->nAddins = 0; + _td->CurrentAddin = -1; + //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addin_Release: EXIT"); +} + +void ReadAddins(HKEY hkey) +{ + PKEYMAN64THREADDATA _td = ThreadGlobals(); + if(!_td) return; + + //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: ReadAddins: ENTER"); + RegistryReadOnly *reg = new RegistryReadOnly(hkey); + if(reg->OpenKeyReadOnly(hkey == HKEY_CURRENT_USER ? REGSZ_KeymanAddinsCU : REGSZ_KeymanAddinsLM)) + { + int n = _td->nAddins; + char buf[128]; + while(reg->GetValueNames(buf, 128, n)) + { + Addin *a = new Addin[n+1]; + if(_td->Addins) + { + memcpy(a, _td->Addins, n * sizeof(Addin)); + delete[] _td->Addins; + } + _td->Addins = a; + _td->Addins[n].hAddin = 0; + _td->Addins[n].FocusChanged = NULL; + _td->Addins[n].Initialise = NULL; + _td->Addins[n].OutputBackspace = NULL; + _td->Addins[n].OutputChar = NULL; + _td->Addins[n].Uninitialise = NULL; + _td->Addins[n].ShouldProcess = NULL; + strcpy(_td->Addins[n].ClassName, buf); + reg->ReadString(buf, _td->Addins[n].AddinName, 260); + _td->Addins[n].Application[0] = 0; + n++; + } + _td->nAddins = n; + } + delete reg; + //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: ReadAddins: EXIT"); +} + +void Addin_Refresh() +{ + //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addin_Refresh: ENTER"); + Addin_Release(); + ReadAddins(HKEY_CURRENT_USER); + ReadAddins(HKEY_LOCAL_MACHINE); + //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addin_Refresh: EXIT"); +} + +BOOL LoadAddin() +{ + PKEYMAN64THREADDATA _td = ThreadGlobals(); + if(!_td) return FALSE; + if(_td->CurrentAddin == -1) return FALSE; + + Addin *a = &_td->Addins[_td->CurrentAddin]; + if(!a->hAddin) + { + //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: LoadAddin: ENTER"); + a->hAddin = LoadLibrary(a->AddinName); + if(!a->hAddin) + { + a->hAddin = 0; + a->ClassName[0] = 0; // prevent add-in attempting to load again + _td->CurrenthWnd = 0; + _td->CurrentAddin = -1; + //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: LoadAddin: EXIT - FALSE - LoadLibrary"); + return FALSE; + } + a->OutputBackspace = (PKeymanOutputBackspace) GetProcAddress(a->hAddin, "KeymanOutputBackspace"); + a->OutputChar = (PKeymanOutputChar) GetProcAddress(a->hAddin, "KeymanOutputChar"); + a->FocusChanged = (PKeymanFocusChanged) GetProcAddress(a->hAddin, "KeymanFocusChanged"); + a->ShouldProcess = (PKeymanShouldProcess) GetProcAddress(a->hAddin, "KeymanShouldProcess"); + a->Initialise = (PKeymanInit) GetProcAddress(a->hAddin, "KeymanInitialise"); + a->Uninitialise = (PKeymanInit) GetProcAddress(a->hAddin, "KeymanUninitialise"); + + if(a->Initialise && !(*a->Initialise)()) + { + FreeLibrary(a->hAddin); + a->hAddin = 0; + a->ClassName[0] = 0; + _td->CurrenthWnd = 0; + _td->CurrentAddin = -1; + //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: LoadAddin: EXIT - FALSE - Initialise"); + return FALSE; + } + //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: LoadAddin: EXIT - TRUE - Loaded"); + } + return TRUE; +} + +BOOL Addin_ShouldProcessUnichar(HWND hwnd) +{ + PKEYMAN64THREADDATA _td = ThreadGlobals(); + if(!_td) return FALSE; + + //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ShouldProcessUnichar: ENTER"); + _td->CurrenthWnd = hwnd; + GetClassName(hwnd, _td->CurrentClassName, 128); + if(_td->CurrentAddin >= 0 && !_strcmpi(_td->CurrentClassName, _td->Addins[_td->CurrentAddin].ClassName)) + { + //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ShouldProcessUnichar: EXIT - TRUE - CurrentAddin okay"); + return TRUE; + } + + for(int i = 0; i < _td->nAddins; i++) + if(!_strcmpi(_td->CurrentClassName, _td->Addins[i].ClassName)) + { + _td->CurrentAddin = i; + if(!LoadAddin()) + { + _td->CurrentAddin = -1; + _td->Addins[i].ClassName[0] = 0; // prevent add-in attempting to load again + } + else if(_td->Addins[i].ShouldProcess && !(*_td->Addins[i].ShouldProcess)(hwnd)) + _td->CurrentAddin = -1; + else + { + //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ShouldProcessUnichar: EXIT - TRUE - FoundAddin"); + return TRUE; + } + } + _td->CurrentAddin = -1; + _td->CurrenthWnd = 0; + //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ShouldProcessUnichar: EXIT - FALSE"); + return FALSE; +} + +BOOL Addin_ProcessUnichar(HWND hwnd, DWORD chr) +{ + PKEYMAN64THREADDATA _td = ThreadGlobals(); + if(!_td) return FALSE; + + //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: ENTER"); + if(_td->CurrenthWnd != hwnd) + if(!Addin_ShouldProcessUnichar(hwnd)) + { + //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: EXIT - FALSE - Addin_ShouldProcessUnichar"); + return FALSE; + } + + if(!LoadAddin()) + { + //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: EXIT - FALSE - !LoadAddin)"); + return FALSE; + } + if(!_td->Addins[_td->CurrentAddin].OutputChar) + { + //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: EXIT - FALSE !OutputChar"); + return FALSE; + } + + BOOL b = (*_td->Addins[_td->CurrentAddin].OutputChar)(hwnd, chr); + //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: EXIT (b) == %d", b); + return b; +} + +BOOL Addin_ProcessBackspace(HWND hwnd) +{ + PKEYMAN64THREADDATA _td = ThreadGlobals(); + if(!_td) return FALSE; + + //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: ENTER"); + if(_td->CurrenthWnd != hwnd) + if(!Addin_ShouldProcessUnichar(hwnd)) + { + //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: EXIT - !ShouldProcess"); + return FALSE; + } + + if(!LoadAddin()) + { + //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: EXIT - !LoadAddin"); + return FALSE; + } + if(!_td->Addins[_td->CurrentAddin].OutputBackspace) + { + //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: EXIT - !OutputBackspace"); + return FALSE; + } + + BOOL b = (*_td->Addins[_td->CurrentAddin].OutputBackspace)(hwnd); + //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: EXIT - (b) = %d", b); + return b; +} + +void Addin_FocusChanged(HWND hwnd) +{ + PKEYMAN64THREADDATA _td = ThreadGlobals(); + if(!_td) return; + + //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: ENTER"); + + if(_td->CurrenthWnd != hwnd) + if(!Addin_ShouldProcessUnichar(hwnd)) + { + //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: EXIT - !ShouldProcess"); + return; + } + + if(!LoadAddin()) + { + //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: EXIT - !LoadAddin"); + return; + } + + // Addin variables must be valid now + + if(!_td->Addins[_td->CurrentAddin].FocusChanged) + { + //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: EXIT - !FocusChanged"); + return; + } + + (*_td->Addins[_td->CurrentAddin].FocusChanged)(); + //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: EXIT"); +} diff --git a/windows/src/engine/keyman32/addins.h b/windows/src/engine/keyman32/addins.h new file mode 100644 index 0000000000..71aa006e59 --- /dev/null +++ b/windows/src/engine/keyman32/addins.h @@ -0,0 +1,23 @@ +/* + Name: addins + Copyright: Copyright (C) SIL International. + Documentation: + Description: + Create Date: 11 Dec 2009 + + Modified Date: 11 Dec 2009 + Authors: mcdurdin + Related Files: + Dependencies: + + Bugs: + Todo: + Notes: + History: 11 Dec 2009 - mcdurdin - I934 - x64 - Initial version +*/ +void Addin_Release(); +void Addin_Refresh(); +BOOL Addin_ShouldProcessUnichar(HWND hwnd); +BOOL Addin_ProcessUnichar(HWND hwnd, DWORD chr); +BOOL Addin_ProcessBackspace(HWND hwnd); +void Addin_FocusChanged(HWND hwnd); diff --git a/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp b/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp index 5fa67fc715..19da87a543 100644 --- a/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp +++ b/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp @@ -277,6 +277,7 @@ BOOL AIWin2000Unicode::PostKeys() break; case QIT_BACK: if(Queue[n].dwData & BK_DEADKEY) break; + if(Addin_ProcessBackspace(hwnd)) break; pInputs[i].type = INPUT_KEYBOARD; pInputs[i].ki.wVk = VK_BACK; diff --git a/windows/src/engine/keyman32/keyman-engine.vcxproj b/windows/src/engine/keyman32/keyman-engine.vcxproj index 632b4e6a67..6869117fd9 100644 --- a/windows/src/engine/keyman32/keyman-engine.vcxproj +++ b/windows/src/engine/keyman32/keyman-engine.vcxproj @@ -186,6 +186,12 @@ + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) diff --git a/windows/src/engine/keyman32/keyman-engine.vcxproj.filters b/windows/src/engine/keyman32/keyman-engine.vcxproj.filters index c0eab08097..7cd4d906d1 100644 --- a/windows/src/engine/keyman32/keyman-engine.vcxproj.filters +++ b/windows/src/engine/keyman32/keyman-engine.vcxproj.filters @@ -15,6 +15,9 @@ + + Source Files + Source Files diff --git a/windows/src/engine/keyman32/keyman32.cpp b/windows/src/engine/keyman32/keyman32.cpp index a1690409f9..3b0953afae 100644 --- a/windows/src/engine/keyman32/keyman32.cpp +++ b/windows/src/engine/keyman32/keyman32.cpp @@ -492,6 +492,7 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_Exit(void) *Globals::Keyman_Shutdown() = TRUE; ReleaseKeyboards(TRUE); + Addin_Release(); if(!Globals::get_Keyman_Initialised()) { @@ -924,6 +925,8 @@ void RefreshKeyboards(BOOL Initialising) // Can happen when multiple top-level windows for one process + Addin_Refresh(); + SendDebugMessageFormat(0,sdmGlobal,0,"---ENTER RefreshKeyboards---"); //FInRefreshKeyboards = TRUE; diff --git a/windows/src/engine/keyman32/keyman32.vcxproj b/windows/src/engine/keyman32/keyman32.vcxproj index 670df3c1d4..0d78d2c292 100644 --- a/windows/src/engine/keyman32/keyman32.vcxproj +++ b/windows/src/engine/keyman32/keyman32.vcxproj @@ -176,6 +176,12 @@ + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) @@ -356,6 +362,7 @@ + diff --git a/windows/src/engine/keyman32/keyman32.vcxproj.filters b/windows/src/engine/keyman32/keyman32.vcxproj.filters index dcf5f5d4c5..8995c39a93 100644 --- a/windows/src/engine/keyman32/keyman32.vcxproj.filters +++ b/windows/src/engine/keyman32/keyman32.vcxproj.filters @@ -15,6 +15,9 @@ + + Source Files + Source Files @@ -159,6 +162,9 @@ + + Header Files + Header Files diff --git a/windows/src/engine/keyman32/keymanengine.h b/windows/src/engine/keyman32/keymanengine.h index fe536cb399..c70d039ff7 100644 --- a/windows/src/engine/keyman32/keymanengine.h +++ b/windows/src/engine/keyman32/keymanengine.h @@ -246,6 +246,7 @@ void keybd_shift(LPINPUT pInputs, int* n, BOOL isReset, LPBYTE const kbd); #include "keystate.h" #include "calldll.h" +#include "addins.h" #include "keymancontrol.h" #include "keyboardoptions.h" #include "kmprocessactions.h" diff --git a/windows/src/engine/keyman32/kmhook_getmessage.cpp b/windows/src/engine/keyman32/kmhook_getmessage.cpp index 9b128dccc6..5aec91a958 100644 --- a/windows/src/engine/keyman32/kmhook_getmessage.cpp +++ b/windows/src/engine/keyman32/kmhook_getmessage.cpp @@ -252,9 +252,13 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam) Handle WM_UNICHAR messages for RichEdit control -- should we test RichEdit version? */ - if(mp->message == WM_UNICHAR) + if(mp->message == WM_UNICHAR && Addin_ShouldProcessUnichar(mp->hwnd)) { - return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); + if(Addin_ProcessUnichar(mp->hwnd, (DWORD) mp->wParam)) + { + mp->message = 0; + return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); + } } /* @@ -375,6 +379,7 @@ void ProcessWMKeyman(HWND hwnd, WPARAM wParam, LPARAM lParam) { if(_td->app) _td->app->ResetQueue(); GetCapsAndNumlockState(); + Addin_FocusChanged(hwnd); UpdateActiveWindows(); } } diff --git a/windows/src/engine/keyman64/keyman64.vcxproj b/windows/src/engine/keyman64/keyman64.vcxproj index 15546caef5..d70c0872ed 100644 --- a/windows/src/engine/keyman64/keyman64.vcxproj +++ b/windows/src/engine/keyman64/keyman64.vcxproj @@ -177,6 +177,7 @@ + @@ -278,6 +279,7 @@ + diff --git a/windows/src/engine/keyman64/keyman64.vcxproj.filters b/windows/src/engine/keyman64/keyman64.vcxproj.filters index cd8aeefb32..0b53bd96cb 100644 --- a/windows/src/engine/keyman64/keyman64.vcxproj.filters +++ b/windows/src/engine/keyman64/keyman64.vcxproj.filters @@ -2,6 +2,7 @@ + @@ -40,6 +41,7 @@ + -- GitLab From 3de6d819c08756c372c2e99a735ed137021b81a4 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 27 Apr 2023 16:15:09 +1000 Subject: [PATCH 009/214] chore(windows): remove dulicate function definition calldll --- windows/src/engine/keyman32/calldll.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/windows/src/engine/keyman32/calldll.h b/windows/src/engine/keyman32/calldll.h index cf9d64e1a2..6e719bde9a 100644 --- a/windows/src/engine/keyman32/calldll.h +++ b/windows/src/engine/keyman32/calldll.h @@ -19,18 +19,15 @@ #ifndef __CALLDLL_H #define __CALLDLL_H -BOOL LoadDLLs(LPINTKEYBOARDINFO lpkbi); -BOOL UnloadDLLs(LPINTKEYBOARDINFO lpkbi); -BOOL DeactivateDLLs(LPINTKEYBOARDINFO lpkbi); -BOOL ActivateDLLs(LPINTKEYBOARDINFO lpkbi); - -// TODO: 5444 This will become the only LoadDLLs function /** * Load the all the dlls used by the current keyboard * @param lpkbi The keyboard for which to load the dlls * @return BOOL True on success */ BOOL LoadDLLs(LPINTKEYBOARDINFO lpkbi); +BOOL UnloadDLLs(LPINTKEYBOARDINFO lpkbi); +BOOL DeactivateDLLs(LPINTKEYBOARDINFO lpkbi); +BOOL ActivateDLLs(LPINTKEYBOARDINFO lpkbi); BOOL IsIMWindow(HWND hwnd); -- GitLab From a1326ad47b65244628c895a69e1b6cd7a49df42f Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 2 May 2023 12:14:05 +0700 Subject: [PATCH 010/214] chore(common): `set -eu` in build-utils.sh Enforces -e (abort script on error) and -u (error on unset variable use) on all scripts that source build-utils.sh. This may result in some downstream build failures which we'll need to address before merge to master. --- linux/scripts/dist.sh | 2 +- resources/build/build-utils.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/linux/scripts/dist.sh b/linux/scripts/dist.sh index 7b1be441d9..38fb42932a 100755 --- a/linux/scripts/dist.sh +++ b/linux/scripts/dist.sh @@ -17,7 +17,7 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" BASEDIR=$(pwd) -if [ "$1" == "origdist" ]; then +if [[ ! -z ${1+x} ]] && [ "$1" == "origdist" ]; then create_origdist=1 shift fi diff --git a/resources/build/build-utils.sh b/resources/build/build-utils.sh index 3cff571b21..bba5589b19 100755 --- a/resources/build/build-utils.sh +++ b/resources/build/build-utils.sh @@ -30,7 +30,7 @@ # # Exit on command failure and when using unset variables: -# TODO #8693: set -eu +set -eu # # Prevents 'clear' on exit of mingw64 bash shell -- GitLab From 5634843bb28458bc07b83fc504782a45197edb4e Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 2 May 2023 12:28:25 +0700 Subject: [PATCH 011/214] chore(linux): fixup missing parameter test --- linux/scripts/dist.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux/scripts/dist.sh b/linux/scripts/dist.sh index 38fb42932a..f412531cd2 100755 --- a/linux/scripts/dist.sh +++ b/linux/scripts/dist.sh @@ -61,7 +61,7 @@ echo "3.0 (quilt)" > debian/source/format cd "$BASEDIR" # create orig.tar.gz -if [ -n "$create_origdist" ]; then +if [ ! -z "${create_origdist+x}" ]; then cd dist pkgvers="keyman-$VERSION" tar xfz keyman-"${VERSION}".tar.gz -- GitLab From 2934a15dd76007f026989da56d56194aefc48d9e Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 2 May 2023 12:30:29 +0700 Subject: [PATCH 012/214] chore(mac): fixup missing parameter test --- mac/build.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mac/build.sh b/mac/build.sh index 480cbd8587..e55fdedc72 100755 --- a/mac/build.sh +++ b/mac/build.sh @@ -273,11 +273,11 @@ if $LOCALDEPLOY && ! $NOTARIZE ; then fi if $PREPRELEASE || $NOTARIZE ; then - if [ ! $DO_CODESIGN ] || [ -z "${CERTIFICATE_ID}" ]; then + if [ ! $DO_CODESIGN ] || [ -z "${CERTIFICATE_ID+x}" ]; then builder_die "Code signing must be configured for deployment. See build.sh -help for details." fi - if [ -z "${APPSTORECONNECT_PROVIDER}" ] || [ -z "${APPSTORECONNECT_USERNAME}" ] || [ -z "${APPSTORECONNECT_PASSWORD}" ]; then + if [ -z "${APPSTORECONNECT_PROVIDER+x}" ] || [ -z "${APPSTORECONNECT_USERNAME+x}" ] || [ -z "${APPSTORECONNECT_PASSWORD+x}" ]; then builder_die "Appstoreconnect Apple ID credentials must be configured in environment. See build.sh -help for details." fi fi @@ -388,7 +388,7 @@ if $DO_KEYMANIM ; then ENTITLEMENTS_FILE=Keyman.entitlements fi - if [ -z "$DEVELOPMENT_TEAM" ]; then + if [ -z "${DEVELOPMENT_TEAM+x}" ]; then DEVELOPMENT_TEAM=3YE4W86L3G fi @@ -432,7 +432,7 @@ fi if $PREPRELEASE || $NOTARIZE; then builder_heading "Notarizing app" - if [ "${CODESIGNING_SUPPRESSION}" != "" ] && [ -z "${CERTIFICATE_ID}" ]; then + if [ "${CODESIGNING_SUPPRESSION}" != "" ] && [ -z "${CERTIFICATE_ID+x}" ]; then builder_die "Notarization and signed executable is required for deployment, even locally. Specify CERTIFICATE_ID environment variable for custom certificate." else TARGET_PATH="$KM4MIM_BASE_PATH/build/$CONFIG" @@ -443,7 +443,7 @@ if $PREPRELEASE || $NOTARIZE; then # Note: get-task-allow entitlement must be *off* in our release build (to do this, don't include base entitlements in project build settings) # We may need to re-run the code signing if a custom certificate has been passed in - if [ ! -z "${CERTIFICATE_ID}" ]; then + if [ ! -z "${CERTIFICATE_ID+x}" ]; then builder_heading "Signing with custom certificate (CERTIFICATE_ID environment variable)." codesign --force --options runtime --entitlements Keyman4MacIM/Keyman.entitlements --deep --sign "${CERTIFICATE_ID}" "$TARGET_APP_PATH" fi -- GitLab From 57cf6e07db3645e2232c7f07aa0048b53766ccfd Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 2 May 2023 12:41:38 +0700 Subject: [PATCH 013/214] chore(common): fix typo in build script --- common/predictive-text/unit_tests/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/predictive-text/unit_tests/test.sh b/common/predictive-text/unit_tests/test.sh index a0554b6325..7dabaa7905 100755 --- a/common/predictive-text/unit_tests/test.sh +++ b/common/predictive-text/unit_tests/test.sh @@ -58,7 +58,7 @@ if builder_start_action test:libraries; then pushd "$KEYMAN_ROOT/common/models/templates" echo - echo "### Running $builder_term common/models/templates) tests" + echo "### Running $(builder_term common/models/templates) tests" if builder_has_option --ci; then npm run test -- -reporter mocha-teamcity-reporter else -- GitLab From e007a8acb640cf1de07e5919b675def000cc8f1e Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 2 May 2023 12:41:50 +0700 Subject: [PATCH 014/214] chore(ios): fix typos and gaps in build script --- ios/tools/prepRelease.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ios/tools/prepRelease.sh b/ios/tools/prepRelease.sh index 1f22de45f0..39b46722f7 100755 --- a/ios/tools/prepRelease.sh +++ b/ios/tools/prepRelease.sh @@ -70,17 +70,17 @@ KEYMAN_SAMPLES="samples" echo "engine dest: $KMEI_DST" -echo "Zipping ${UNI_FRAMEWORK} => ${UPLOAD_DIR}/${KMEI_DST}..." +echo "Zipping ${FRAMEWORK} => ${UPLOAD_DIR}/${KMEI_DST}..." cd "${KMEI_FRAMEWORK_BASE}" -zip -qrX ${KMEI_DST} ${FRAMEWORK} -cd $WORK_DIR +zip -qrX "${KMEI_DST}" ${FRAMEWORK} +cd "$WORK_DIR" echo "Copying Keyman Engine samples into ${UPLOAD_DIR}/${KMEI_DST_NAME}..." cp -rf "${KEYMAN_SAMPLES}" "${UPLOAD_DIR}/samples" cd "${UPLOAD_DIR}" zip -qr "${KMEI_DST_NAME}" "samples" rm -rf "samples" -cd $WORK_DIR +cd "$WORK_DIR" # # Keyman app -- GitLab From 127b0e0c43a3e4b8618a75959c8307311ae98f60 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 2 May 2023 13:49:24 +0700 Subject: [PATCH 015/214] chore(mac): fix missing build vars --- mac/build.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mac/build.sh b/mac/build.sh index e55fdedc72..5a16f00f11 100755 --- a/mac/build.sh +++ b/mac/build.sh @@ -132,6 +132,7 @@ QUIET=false NOTARIZE=false SKIP_BUILD=false UPLOAD_SENTRY=false +QUIET_FLAG= # Import local environment variables for build if [[ -f $(dirname "$THIS_SCRIPT")/localenv.sh ]]; then @@ -259,6 +260,7 @@ displayInfo "" \ "BUILD_ACTIONS: $BUILD_ACTIONS" \ "TEST_ACTION: $TEST_ACTION" \ "UPLOAD_SENTRY: $UPLOAD_SENTRY" \ + "QUIET_FLAG: $QUIET_FLAG" \ "" ### Validate notarization environment variables ### -- GitLab From 4a2062ecfb9d31c6ad24d3ca5682c181ab704466 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 2 May 2023 21:35:42 +1000 Subject: [PATCH 016/214] fix(common): predictive-text unit_tests further builder_term fixes --- common/predictive-text/unit_tests/test.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/predictive-text/unit_tests/test.sh b/common/predictive-text/unit_tests/test.sh index 7dabaa7905..f1b49635f6 100755 --- a/common/predictive-text/unit_tests/test.sh +++ b/common/predictive-text/unit_tests/test.sh @@ -68,7 +68,7 @@ if builder_start_action test:libraries; then pushd "$KEYMAN_ROOT/common/models/types" echo - echo "### Running $builder_term common/models/types) tests" + echo "### Running $(builder_term common/models/types) tests" # Is not mocha-based; it's TSC-based instead, as we're just ensuring that the .d.ts # file is a proper TS declaration file. npm run test @@ -100,7 +100,7 @@ if [[ $VERSION_ENVIRONMENT == test ]] && builder_has_action test :browser; then if builder_pull_get_details; then if ! ([[ $builder_pull_title =~ \(web\) ]] || builder_pull_has_label test-browserstack); then - echo "Auto-skipping $builder_term test:browser) for unrelated CI test build" + echo "Auto-skipping $(builder_term test:browser) for unrelated CI test build" exit 0 fi fi @@ -145,4 +145,4 @@ if builder_start_action test:browser; then npm run karma -- start $KARMA_INFO_LEVEL $KARMA_FLAGS $BROWSERS unit_tests/in_browser/$KARMA_CONFIG builder_finish_action success test:browser -fi \ No newline at end of file +fi -- GitLab From 6442bdb1f1c7244b99ca95954ba5d39824af2c6a Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Wed, 3 May 2023 09:05:57 +0700 Subject: [PATCH 017/214] fix(android/app): Resize OSK when resuming app from background --- .../main/java/com/tavultesoft/kmapro/MainActivity.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java index e112a6360d..6b92d4c2eb 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java +++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java @@ -109,6 +109,7 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene private final int minTextSize = 16; private final int maxTextSize = 72; private int textSize = minTextSize; + private int lastOrientation = Configuration.ORIENTATION_UNDEFINED; private static final String defaultKeyboardInstalled = "DefaultKeyboardInstalled"; private static final String defaultDictionaryInstalled = "DefaultDictionaryInstalled"; private static final String userTextKey = "UserText"; @@ -262,6 +263,14 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene super.onResume(); KMManager.onResume(); KMManager.hideSystemKeyboard(); + + // onConfigurationChanged() only triggers when device is rotated while app is in foreground + // This handles when device is rotated while app is in background + Configuration newConfig = this.getResources().getConfiguration(); + if (newConfig != null && newConfig.orientation != lastOrientation) { + lastOrientation = newConfig.orientation; + KMManager.onConfigurationChanged(newConfig); + } resizeTextView(textView.isKeyboardVisible()); KMManager.addKeyboardEventListener(this); @@ -349,6 +358,7 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene getSupportActionBar().setBackgroundDrawable(getActionBarDrawable(this)); resizeTextView(textView.isKeyboardVisible()); invalidateOptionsMenu(); + lastOrientation = newConfig.orientation; } @SuppressLint("RestrictedApi") -- GitLab From bc40860b09e7dff050fbdd263663238075bd1d1d Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 3 May 2023 14:13:17 +1000 Subject: [PATCH 018/214] chore(windows): remove EthnologueCodeToKeymanID --- windows/src/engine/keyman32/glossary.cpp | 65 +++++----------------- windows/src/engine/keyman32/keymanengine.h | 2 - 2 files changed, 15 insertions(+), 52 deletions(-) diff --git a/windows/src/engine/keyman32/glossary.cpp b/windows/src/engine/keyman32/glossary.cpp index be1c498451..7a6aecddc0 100644 --- a/windows/src/engine/keyman32/glossary.cpp +++ b/windows/src/engine/keyman32/glossary.cpp @@ -1,18 +1,18 @@ /* Name: glossary Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 20 Jul 2008 Modified Date: 28 May 2014 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 20 Jul 2008 - mcdurdin - I1498 - Fix keyboard switching for Shadow keyboards on Vista+ 20 Jul 2008 - mcdurdin - I1546 - Fix language switch with ids >= x80000000 20 Jul 2008 - mcdurdin - I1545 - Fix registry leak @@ -38,9 +38,9 @@ BOOL HKLIsIME(HKL hkl) // I1498 - fix keyboard switching for shadow keyboards o if( (GetVersion() & 0xFF) >= 6 ) return FALSE; if( (GetVersion() & 0x8000000) == 0x8000000 || (GetVersion() & 0xFF) == 4 ) r = GetSystemMetrics(SM_DBCSENABLED); - else + else r = GetSystemMetrics(SM_IMMENABLED); - + return r && ImmIsIME(hkl); } #pragma warning(default: 4996) @@ -99,12 +99,12 @@ DWORD HKLToKeyboardID(HKL hkl) return (DWORD) LOWORD(hkl); } - for(len=16, n = i = 0; RegEnumKeyEx(hkey, i, str, &len, 0, NULL, NULL, &ft) == ERROR_SUCCESS; - len = 16, i++, n=0) + for(len=16, n = i = 0; RegEnumKeyEx(hkey, i, str, &len, 0, NULL, NULL, &ft) == ERROR_SUCCESS; + len = 16, i++, n=0) { RegOpenKeyEx(hkey, str, NULL, KEY_READ, &hsubkey); len = 16; - if(RegQueryValueEx(hsubkey, REGSZ_LayoutID, NULL, NULL, (LPBYTE) str2, &len) == ERROR_SUCCESS) + if(RegQueryValueEx(hsubkey, REGSZ_LayoutID, NULL, NULL, (LPBYTE) str2, &len) == ERROR_SUCCESS) { n = strtoul(str2, NULL, 16); // I1546 if(n == LayoutID) @@ -120,7 +120,7 @@ DWORD HKLToKeyboardID(HKL hkl) } RegCloseKey(hkey); - + //SendDebugMessageFormat(0, sdmGlobal, 0, "HKLToKeyboardID: fails[2], return LOWORD(hkl)=%x", LOWORD(hkl)); return (DWORD) LOWORD(hkl); // should never happen } @@ -143,11 +143,11 @@ WORD HKLToLayoutNumber(HKL hkl) if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSZ_SystemKeyboardLayouts, NULL, KEY_READ, &hkey) != ERROR_SUCCESS) return 0; - for(len=16, n = i = 0; RegEnumKeyEx(hkey, i, str, &len, 0, NULL, NULL, &ft) == ERROR_SUCCESS; len = 16, i++, n=0) + for(len=16, n = i = 0; RegEnumKeyEx(hkey, i, str, &len, 0, NULL, NULL, &ft) == ERROR_SUCCESS; len = 16, i++, n=0) { RegOpenKeyEx(hkey, str, NULL, KEY_READ, &hsubkey); len = 16; - if(RegQueryValueEx(hsubkey, REGSZ_LayoutID, NULL, NULL, (LPBYTE) str2, &len) == ERROR_SUCCESS) + if(RegQueryValueEx(hsubkey, REGSZ_LayoutID, NULL, NULL, (LPBYTE) str2, &len) == ERROR_SUCCESS) { if(strtoul(str2, NULL, 16) == LayoutID) break; // strtoul - I1546 } @@ -166,38 +166,3 @@ WORD HKLToLayoutID(HKL hkl) return HIWORD(hkl) & 0x0FFF; } - -// TODO: Make this use the core -//DWORD EthnologueCodeToKeymanID(DWORD EthCode) -//{ -// PKEYMAN64THREADDATA _td = ThreadGlobals(); -// if(!_td) return KEYMANID_NONKEYMAN; -// -// for(int i = 0; i < _td->nKeyboards; i++) -// { -// if(!_td->lpKeyboards[i].Keyboard && !LoadlpKeyboard(i)) -// { -// SendDebugMessageFormat(0,sdmGlobal,0, -// "EthnologueCodeToKeymanID: Unable to load keyboard %s", _td->lpKeyboards[i].Name); -// return KEYMANID_NONKEYMAN; -// } -// -// PWSTR ps = GetSystemStore(_td->lpKeyboards[i].Keyboard, TSS_ETHNOLOGUECODE); -// if(ps) -// { -// SendDebugMessageFormat(0,sdmGlobal,0,"EthnologueCodeToKeymanID: %s %ws %x", _td->lpKeyboards[i].Name, ps, EthnologueStringCodeToDWord(ps)); -// if(EthnologueStringCodeToDWord(ps) == EthCode) return _td->lpKeyboards[i].KeymanID; -// } -// } -// -// return KEYMANID_NONKEYMAN; -//} - -DWORD EthnologueStringCodeToDWord(PWSTR EthCode) -{ - if(wcslen(EthCode) < 3 || wcslen(EthCode) > 4) return (DWORD)-1; - return (LOBYTE(EthCode[0])) | - (LOBYTE(EthCode[1]) << 8) | - (LOBYTE(EthCode[2]) << 16) | - (LOBYTE(EthCode[3]) << 24); -} diff --git a/windows/src/engine/keyman32/keymanengine.h b/windows/src/engine/keyman32/keymanengine.h index c70d039ff7..3314056acf 100644 --- a/windows/src/engine/keyman32/keymanengine.h +++ b/windows/src/engine/keyman32/keymanengine.h @@ -222,8 +222,6 @@ DWORD HKLToKeyboardID(HKL hkl); WORD HKLToLanguageID(HKL hkl); WORD HKLToLayoutNumber(HKL hkl); WORD HKLToLayoutID(HKL hkl); -DWORD EthnologueCodeToKeymanID(DWORD EthCode); -DWORD EthnologueStringCodeToDWord(PWSTR EthCode); PWSTR GetSystemStore(LPKEYBOARD kb, DWORD SystemID); -- GitLab From 9aa6ab2ee0dd8b5126910cbf1a8093fa535102f5 Mon Sep 17 00:00:00 2001 From: Ross Date: Fri, 21 Apr 2023 19:02:03 +1000 Subject: [PATCH 019/214] chore(windows): remove addins c-h files --- windows/src/engine/keyman32/addins.cpp | 263 ------------------ windows/src/engine/keyman32/addins.h | 23 -- .../keyman32/appint/aiWin2000Unicode.cpp | 1 - .../src/engine/keyman32/keyman-engine.vcxproj | 6 - .../keyman32/keyman-engine.vcxproj.filters | 3 - windows/src/engine/keyman32/keyman32.cpp | 3 - windows/src/engine/keyman32/keyman32.vcxproj | 7 - .../engine/keyman32/keyman32.vcxproj.filters | 6 - windows/src/engine/keyman32/keymanengine.h | 1 - .../src/engine/keyman32/kmhook_getmessage.cpp | 9 +- windows/src/engine/keyman64/keyman64.vcxproj | 2 - .../engine/keyman64/keyman64.vcxproj.filters | 2 - 12 files changed, 2 insertions(+), 324 deletions(-) delete mode 100644 windows/src/engine/keyman32/addins.cpp delete mode 100644 windows/src/engine/keyman32/addins.h diff --git a/windows/src/engine/keyman32/addins.cpp b/windows/src/engine/keyman32/addins.cpp deleted file mode 100644 index 6c7f5d0f28..0000000000 --- a/windows/src/engine/keyman32/addins.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* - Name: addins - Copyright: Copyright (C) SIL International. - Documentation: - Description: - Create Date: 14 Jun 2008 - - Modified Date: 14 May 2010 - Authors: mcdurdin - Related Files: - Dependencies: - - Bugs: - Todo: - Notes: - History: 14 Jun 2008 - mcdurdin - I1488 - Fix registry handle leak - 11 Mar 2009 - mcdurdin - I1894 - Fix threading bugs introduced in I1888 - 11 Dec 2009 - mcdurdin - I934 - x64 - Initial version - 12 Mar 2010 - mcdurdin - I934 - x64 - Complete - 12 Mar 2010 - mcdurdin - I2229 - Remove hints and warnings - 04 May 2010 - mcdurdin - I2351 - Robustness - verify _td return value - 14 May 2010 - mcdurdin - I2374 - Fix crash in some situations -*/ - -#include "pch.h" - -void Addin_Release() -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return; - - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addin_Release: ENTER [%d]", nAddins); - if(_td->Addins) - { - for(int i = 0; i < _td->nAddins; i++) - if(_td->Addins[i].hAddin) - { - if(_td->Addins[i].Uninitialise) (*_td->Addins[i].Uninitialise)(); - FreeLibrary(_td->Addins[i].hAddin); - } - delete[] _td->Addins; - } - _td->Addins = NULL; - _td->nAddins = 0; - _td->CurrentAddin = -1; - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addin_Release: EXIT"); -} - -void ReadAddins(HKEY hkey) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return; - - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: ReadAddins: ENTER"); - RegistryReadOnly *reg = new RegistryReadOnly(hkey); - if(reg->OpenKeyReadOnly(hkey == HKEY_CURRENT_USER ? REGSZ_KeymanAddinsCU : REGSZ_KeymanAddinsLM)) - { - int n = _td->nAddins; - char buf[128]; - while(reg->GetValueNames(buf, 128, n)) - { - Addin *a = new Addin[n+1]; - if(_td->Addins) - { - memcpy(a, _td->Addins, n * sizeof(Addin)); - delete[] _td->Addins; - } - _td->Addins = a; - _td->Addins[n].hAddin = 0; - _td->Addins[n].FocusChanged = NULL; - _td->Addins[n].Initialise = NULL; - _td->Addins[n].OutputBackspace = NULL; - _td->Addins[n].OutputChar = NULL; - _td->Addins[n].Uninitialise = NULL; - _td->Addins[n].ShouldProcess = NULL; - strcpy(_td->Addins[n].ClassName, buf); - reg->ReadString(buf, _td->Addins[n].AddinName, 260); - _td->Addins[n].Application[0] = 0; - n++; - } - _td->nAddins = n; - } - delete reg; - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: ReadAddins: EXIT"); -} - -void Addin_Refresh() -{ - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addin_Refresh: ENTER"); - Addin_Release(); - ReadAddins(HKEY_CURRENT_USER); - ReadAddins(HKEY_LOCAL_MACHINE); - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addin_Refresh: EXIT"); -} - -BOOL LoadAddin() -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - if(_td->CurrentAddin == -1) return FALSE; - - Addin *a = &_td->Addins[_td->CurrentAddin]; - if(!a->hAddin) - { - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: LoadAddin: ENTER"); - a->hAddin = LoadLibrary(a->AddinName); - if(!a->hAddin) - { - a->hAddin = 0; - a->ClassName[0] = 0; // prevent add-in attempting to load again - _td->CurrenthWnd = 0; - _td->CurrentAddin = -1; - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: LoadAddin: EXIT - FALSE - LoadLibrary"); - return FALSE; - } - a->OutputBackspace = (PKeymanOutputBackspace) GetProcAddress(a->hAddin, "KeymanOutputBackspace"); - a->OutputChar = (PKeymanOutputChar) GetProcAddress(a->hAddin, "KeymanOutputChar"); - a->FocusChanged = (PKeymanFocusChanged) GetProcAddress(a->hAddin, "KeymanFocusChanged"); - a->ShouldProcess = (PKeymanShouldProcess) GetProcAddress(a->hAddin, "KeymanShouldProcess"); - a->Initialise = (PKeymanInit) GetProcAddress(a->hAddin, "KeymanInitialise"); - a->Uninitialise = (PKeymanInit) GetProcAddress(a->hAddin, "KeymanUninitialise"); - - if(a->Initialise && !(*a->Initialise)()) - { - FreeLibrary(a->hAddin); - a->hAddin = 0; - a->ClassName[0] = 0; - _td->CurrenthWnd = 0; - _td->CurrentAddin = -1; - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: LoadAddin: EXIT - FALSE - Initialise"); - return FALSE; - } - //SendDebugMessageFormat(GetFocus(), sdmGlobal, 0, "Addins: LoadAddin: EXIT - TRUE - Loaded"); - } - return TRUE; -} - -BOOL Addin_ShouldProcessUnichar(HWND hwnd) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ShouldProcessUnichar: ENTER"); - _td->CurrenthWnd = hwnd; - GetClassName(hwnd, _td->CurrentClassName, 128); - if(_td->CurrentAddin >= 0 && !_strcmpi(_td->CurrentClassName, _td->Addins[_td->CurrentAddin].ClassName)) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ShouldProcessUnichar: EXIT - TRUE - CurrentAddin okay"); - return TRUE; - } - - for(int i = 0; i < _td->nAddins; i++) - if(!_strcmpi(_td->CurrentClassName, _td->Addins[i].ClassName)) - { - _td->CurrentAddin = i; - if(!LoadAddin()) - { - _td->CurrentAddin = -1; - _td->Addins[i].ClassName[0] = 0; // prevent add-in attempting to load again - } - else if(_td->Addins[i].ShouldProcess && !(*_td->Addins[i].ShouldProcess)(hwnd)) - _td->CurrentAddin = -1; - else - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ShouldProcessUnichar: EXIT - TRUE - FoundAddin"); - return TRUE; - } - } - _td->CurrentAddin = -1; - _td->CurrenthWnd = 0; - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ShouldProcessUnichar: EXIT - FALSE"); - return FALSE; -} - -BOOL Addin_ProcessUnichar(HWND hwnd, DWORD chr) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: ENTER"); - if(_td->CurrenthWnd != hwnd) - if(!Addin_ShouldProcessUnichar(hwnd)) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: EXIT - FALSE - Addin_ShouldProcessUnichar"); - return FALSE; - } - - if(!LoadAddin()) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: EXIT - FALSE - !LoadAddin)"); - return FALSE; - } - if(!_td->Addins[_td->CurrentAddin].OutputChar) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: EXIT - FALSE !OutputChar"); - return FALSE; - } - - BOOL b = (*_td->Addins[_td->CurrentAddin].OutputChar)(hwnd, chr); - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessUnichar: EXIT (b) == %d", b); - return b; -} - -BOOL Addin_ProcessBackspace(HWND hwnd) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: ENTER"); - if(_td->CurrenthWnd != hwnd) - if(!Addin_ShouldProcessUnichar(hwnd)) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: EXIT - !ShouldProcess"); - return FALSE; - } - - if(!LoadAddin()) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: EXIT - !LoadAddin"); - return FALSE; - } - if(!_td->Addins[_td->CurrentAddin].OutputBackspace) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: EXIT - !OutputBackspace"); - return FALSE; - } - - BOOL b = (*_td->Addins[_td->CurrentAddin].OutputBackspace)(hwnd); - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_ProcessBackspace: EXIT - (b) = %d", b); - return b; -} - -void Addin_FocusChanged(HWND hwnd) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return; - - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: ENTER"); - - if(_td->CurrenthWnd != hwnd) - if(!Addin_ShouldProcessUnichar(hwnd)) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: EXIT - !ShouldProcess"); - return; - } - - if(!LoadAddin()) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: EXIT - !LoadAddin"); - return; - } - - // Addin variables must be valid now - - if(!_td->Addins[_td->CurrentAddin].FocusChanged) - { - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: EXIT - !FocusChanged"); - return; - } - - (*_td->Addins[_td->CurrentAddin].FocusChanged)(); - //SendDebugMessageFormat(hwnd, sdmGlobal, 0, "Addin_FocusChanged: EXIT"); -} diff --git a/windows/src/engine/keyman32/addins.h b/windows/src/engine/keyman32/addins.h deleted file mode 100644 index 71aa006e59..0000000000 --- a/windows/src/engine/keyman32/addins.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - Name: addins - Copyright: Copyright (C) SIL International. - Documentation: - Description: - Create Date: 11 Dec 2009 - - Modified Date: 11 Dec 2009 - Authors: mcdurdin - Related Files: - Dependencies: - - Bugs: - Todo: - Notes: - History: 11 Dec 2009 - mcdurdin - I934 - x64 - Initial version -*/ -void Addin_Release(); -void Addin_Refresh(); -BOOL Addin_ShouldProcessUnichar(HWND hwnd); -BOOL Addin_ProcessUnichar(HWND hwnd, DWORD chr); -BOOL Addin_ProcessBackspace(HWND hwnd); -void Addin_FocusChanged(HWND hwnd); diff --git a/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp b/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp index 19da87a543..5fa67fc715 100644 --- a/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp +++ b/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp @@ -277,7 +277,6 @@ BOOL AIWin2000Unicode::PostKeys() break; case QIT_BACK: if(Queue[n].dwData & BK_DEADKEY) break; - if(Addin_ProcessBackspace(hwnd)) break; pInputs[i].type = INPUT_KEYBOARD; pInputs[i].ki.wVk = VK_BACK; diff --git a/windows/src/engine/keyman32/keyman-engine.vcxproj b/windows/src/engine/keyman32/keyman-engine.vcxproj index 6869117fd9..632b4e6a67 100644 --- a/windows/src/engine/keyman32/keyman-engine.vcxproj +++ b/windows/src/engine/keyman32/keyman-engine.vcxproj @@ -186,12 +186,6 @@ - - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) diff --git a/windows/src/engine/keyman32/keyman-engine.vcxproj.filters b/windows/src/engine/keyman32/keyman-engine.vcxproj.filters index 7cd4d906d1..c0eab08097 100644 --- a/windows/src/engine/keyman32/keyman-engine.vcxproj.filters +++ b/windows/src/engine/keyman32/keyman-engine.vcxproj.filters @@ -15,9 +15,6 @@ - - Source Files - Source Files diff --git a/windows/src/engine/keyman32/keyman32.cpp b/windows/src/engine/keyman32/keyman32.cpp index 3b0953afae..a1690409f9 100644 --- a/windows/src/engine/keyman32/keyman32.cpp +++ b/windows/src/engine/keyman32/keyman32.cpp @@ -492,7 +492,6 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_Exit(void) *Globals::Keyman_Shutdown() = TRUE; ReleaseKeyboards(TRUE); - Addin_Release(); if(!Globals::get_Keyman_Initialised()) { @@ -925,8 +924,6 @@ void RefreshKeyboards(BOOL Initialising) // Can happen when multiple top-level windows for one process - Addin_Refresh(); - SendDebugMessageFormat(0,sdmGlobal,0,"---ENTER RefreshKeyboards---"); //FInRefreshKeyboards = TRUE; diff --git a/windows/src/engine/keyman32/keyman32.vcxproj b/windows/src/engine/keyman32/keyman32.vcxproj index 0d78d2c292..670df3c1d4 100644 --- a/windows/src/engine/keyman32/keyman32.vcxproj +++ b/windows/src/engine/keyman32/keyman32.vcxproj @@ -176,12 +176,6 @@ - - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - %(AdditionalIncludeDirectories) - %(PreprocessorDefinitions) - %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) @@ -362,7 +356,6 @@ - diff --git a/windows/src/engine/keyman32/keyman32.vcxproj.filters b/windows/src/engine/keyman32/keyman32.vcxproj.filters index 8995c39a93..dcf5f5d4c5 100644 --- a/windows/src/engine/keyman32/keyman32.vcxproj.filters +++ b/windows/src/engine/keyman32/keyman32.vcxproj.filters @@ -15,9 +15,6 @@ - - Source Files - Source Files @@ -162,9 +159,6 @@ - - Header Files - Header Files diff --git a/windows/src/engine/keyman32/keymanengine.h b/windows/src/engine/keyman32/keymanengine.h index 3314056acf..3cebd7296a 100644 --- a/windows/src/engine/keyman32/keymanengine.h +++ b/windows/src/engine/keyman32/keymanengine.h @@ -244,7 +244,6 @@ void keybd_shift(LPINPUT pInputs, int* n, BOOL isReset, LPBYTE const kbd); #include "keystate.h" #include "calldll.h" -#include "addins.h" #include "keymancontrol.h" #include "keyboardoptions.h" #include "kmprocessactions.h" diff --git a/windows/src/engine/keyman32/kmhook_getmessage.cpp b/windows/src/engine/keyman32/kmhook_getmessage.cpp index 5aec91a958..9b128dccc6 100644 --- a/windows/src/engine/keyman32/kmhook_getmessage.cpp +++ b/windows/src/engine/keyman32/kmhook_getmessage.cpp @@ -252,13 +252,9 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam) Handle WM_UNICHAR messages for RichEdit control -- should we test RichEdit version? */ - if(mp->message == WM_UNICHAR && Addin_ShouldProcessUnichar(mp->hwnd)) + if(mp->message == WM_UNICHAR) { - if(Addin_ProcessUnichar(mp->hwnd, (DWORD) mp->wParam)) - { - mp->message = 0; - return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); - } + return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); } /* @@ -379,7 +375,6 @@ void ProcessWMKeyman(HWND hwnd, WPARAM wParam, LPARAM lParam) { if(_td->app) _td->app->ResetQueue(); GetCapsAndNumlockState(); - Addin_FocusChanged(hwnd); UpdateActiveWindows(); } } diff --git a/windows/src/engine/keyman64/keyman64.vcxproj b/windows/src/engine/keyman64/keyman64.vcxproj index d70c0872ed..15546caef5 100644 --- a/windows/src/engine/keyman64/keyman64.vcxproj +++ b/windows/src/engine/keyman64/keyman64.vcxproj @@ -177,7 +177,6 @@ - @@ -279,7 +278,6 @@ - diff --git a/windows/src/engine/keyman64/keyman64.vcxproj.filters b/windows/src/engine/keyman64/keyman64.vcxproj.filters index 0b53bd96cb..cd8aeefb32 100644 --- a/windows/src/engine/keyman64/keyman64.vcxproj.filters +++ b/windows/src/engine/keyman64/keyman64.vcxproj.filters @@ -2,7 +2,6 @@ - @@ -41,7 +40,6 @@ - -- GitLab From 2935084b45fb7ebde0a721ff350d7ea1d6926042 Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 3 May 2023 15:09:45 +1000 Subject: [PATCH 020/214] chore(windows): do nothing on WM_UNICHAR --- windows/src/engine/keyman32/kmhook_getmessage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/src/engine/keyman32/kmhook_getmessage.cpp b/windows/src/engine/keyman32/kmhook_getmessage.cpp index 9b128dccc6..0b7e96c66c 100644 --- a/windows/src/engine/keyman32/kmhook_getmessage.cpp +++ b/windows/src/engine/keyman32/kmhook_getmessage.cpp @@ -254,7 +254,7 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam) if(mp->message == WM_UNICHAR) { - return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); + // Do Nothing TODO: Remove WM_UNICHAR } /* -- GitLab From ebac0bb54b1a2b257c3d49ae020769b53afad521 Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 3 May 2023 15:19:16 +1000 Subject: [PATCH 021/214] chore(windows): remove save/restore keyboard options --- .../src/engine/keyman32/keyboardoptions.cpp | 86 ------------------- windows/src/engine/keyman32/keyboardoptions.h | 40 +-------- .../keyboardoptionstests.cpp | 71 --------------- 3 files changed, 1 insertion(+), 196 deletions(-) diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index 6ef1d660f9..41eeddba42 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -110,89 +110,3 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* delete[] keyboardOpts; return TRUE; } - -BOOL -UpdateKeyboardOptionsCore( - km_kbp_state* const lpCoreKeyboardState, - km_kbp_option_item *lpCoreKeyboardOptions) { - - int listSize = (int)km_kbp_options_list_size(lpCoreKeyboardOptions); - // Create a option list based on this size look up each key and store the return value in it. - // then at the end return this options list. - BOOL changed = FALSE; - km_kbp_cp const* retValue = nullptr; - for (int i = 0; i < listSize; i++) { - km_kbp_status err_status = km_kbp_state_option_lookup(lpCoreKeyboardState, lpCoreKeyboardOptions[i].scope, lpCoreKeyboardOptions[i].key, - &retValue); - if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat( - 0, sdmKeyboard, 0, "UpdateKeyboardOptionsCore: km_kbp_state_option_lookup failed with error status [%d]", err_status); - continue; - } - // compare to see if changed - if (wcscmp(reinterpret_cast(retValue), reinterpret_cast(lpCoreKeyboardOptions[i].value)) != 0) { - delete lpCoreKeyboardOptions[i].value; - lpCoreKeyboardOptions[i].value = CloneKMKBPCP(retValue); - changed = TRUE; - } - } - return changed; -} - -km_kbp_option_item* -SaveKeyboardOptionsCore(LPINTKEYBOARDINFO kp) { - - // Get the list of default options to determine size of list - const km_kbp_keyboard_attrs* keyboardAttrs; - km_kbp_status err_status = km_kbp_keyboard_get_attrs(kp->lpCoreKeyboard, &keyboardAttrs); - if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat( - 0, sdmKeyboard, 0, "SaveKeyboardOptionsCore: km_kbp_keyboard_get_attrs failed with error status [%d]", err_status); - return nullptr; - } - int listSize = (int)km_kbp_options_list_size(keyboardAttrs->default_options); - km_kbp_option_item* savedKeyboardOpts = new km_kbp_option_item[listSize + 1]; - km_kbp_cp const* retValue = nullptr; - - km_kbp_option_item const* kbDefaultOpts = keyboardAttrs->default_options; - for (int i = 0; i < listSize; i++, ++kbDefaultOpts) { - if (kbDefaultOpts->scope != KM_KBP_OPT_KEYBOARD) - continue; - err_status = - km_kbp_state_option_lookup(kp->lpCoreKeyboardState, KM_KBP_OPT_KEYBOARD, kbDefaultOpts->key, &retValue); - if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat( - 0, sdmKeyboard, 0, "SaveKeyboardOptionsCore: km_kbp_state_option_lookup failed with error status [%d]", err_status); - continue; - } - savedKeyboardOpts[i].key = CloneKMKBPCP(kbDefaultOpts->key); - savedKeyboardOpts[i].value = CloneKMKBPCP(retValue); - savedKeyboardOpts[i].scope = KM_KBP_OPT_KEYBOARD; - } - savedKeyboardOpts[listSize] = KM_KBP_OPTIONS_END; - return savedKeyboardOpts; -} - -BOOL -RestoreKeyboardOptionsCore( - km_kbp_state* const lpCoreKeyboardState, - km_kbp_option_item* lpCoreKeyboardOptions) { - km_kbp_status err_status = km_kbp_state_options_update(lpCoreKeyboardState, lpCoreKeyboardOptions); - if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat( - 0, sdmKeyboard, 0, "RestoreKeyboardOptionsCore: km_kbp_state_options_update failed with error status [%d]", err_status); - return FALSE; - } - return TRUE; -} - -void -DisposeKeyboardOptionsCore(km_kbp_option_item** lpCoreKeyboardOptions) { - size_t listSize = km_kbp_options_list_size(*lpCoreKeyboardOptions); - for (int i = 0; i < (int)listSize; i++) { - delete[] (*lpCoreKeyboardOptions)[i].key; - delete[] (*lpCoreKeyboardOptions)[i].value; - } - delete[] *lpCoreKeyboardOptions; - *lpCoreKeyboardOptions = NULL; -} diff --git a/windows/src/engine/keyman32/keyboardoptions.h b/windows/src/engine/keyman32/keyboardoptions.h index 7694bab47d..0cedea3a80 100644 --- a/windows/src/engine/keyman32/keyboardoptions.h +++ b/windows/src/engine/keyman32/keyboardoptions.h @@ -16,38 +16,6 @@ History: 25 May 2010 - mcdurdin - I1632 - Keyboard Options */ -/** - * Updates the supplied Keyboard processor options list from the keyboard processor pointed - * to by the state pointer. - * - * @param lpCoreKeyboardState The core keyboardprocessor state which has the source options - * @param[in,out] lpCoreKeyboardOptions The core keyboard options to be updated - * @return BOOL True if one or more options were updated - */ -BOOL UpdateKeyboardOptionsCore(km_kbp_state* const lpCoreKeyboardState, km_kbp_option_item *lpCoreKeyboardOptions); - -/** - * Returns a copy of the core keyboard processors current keyboard options - * The caller is responsible for freeing the returned km_kbp_option_item's list. - * - * @param kp A pointer to the keyboard info object that contains the - * keyboardprocessor state and keyboard for the source options list. - * - * @return km_kbp_option_item* The copy of the options list or NULL if copy failed - */ -km_kbp_option_item* SaveKeyboardOptionsCore(LPINTKEYBOARDINFO kp); - -/** - * Restore the core keyboard processor options to the supplied keyboard - * list of `km_kbp_option_item`s - * - * @param lpCoreKeyboardState The state pointer for the keyboard processor - * @param lpCoreKeyboardOptions The list of `km_kbp_option_item`s to restore - * - * return BOOL TRUE when the call to update keyboard processor was successful - */ -BOOL RestoreKeyboardOptionsCore(km_kbp_state* const lpCoreKeyboardState, km_kbp_option_item* lpCoreKeyboardOptions); - /* Common core integration functions */ /** @@ -67,10 +35,4 @@ void LoadKeyboardOptionsREGCore(LPINTKEYBOARDINFO kp, km_kbp_state* state); */ void SaveKeyboardOptionREGCore(LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value); -/** - * Free the allocated resources belonging to a key_kbp_option_items object - * that was created on the heap most likely using SaveKeyboardOptionREGCore - * - * @param lpCoreKeyboardOptions keyboard options items to be freed - */ -void DisposeKeyboardOptionsCore(km_kbp_option_item** lpCoreKeyboardOptions); + diff --git a/windows/src/engine/keyman32/tests/keyman-engine-tests/keyboardoptionstests.cpp b/windows/src/engine/keyman32/tests/keyman-engine-tests/keyboardoptionstests.cpp index 4a16621ee8..795f89fe44 100644 --- a/windows/src/engine/keyman32/tests/keyman-engine-tests/keyboardoptionstests.cpp +++ b/windows/src/engine/keyman32/tests/keyman-engine-tests/keyboardoptionstests.cpp @@ -5,77 +5,6 @@ #include #include -// Test UpdateKeyboardOptionsCore, also uses SaveKeyboardOptionsCore -TEST(KEYBOARDOPTIONS, UpdateKeyboardOptionsCore) { - LPINTKEYBOARDINFO kp = new INTKEYBOARDINFO; - memset(kp, 0, sizeof(INTKEYBOARDINFO)); - - km_kbp_option_item test_env_opts[] = { - {u"__test_point", u"not tiggered", KM_KBP_OPT_KEYBOARD}, {u"hello", u"-", KM_KBP_OPT_ENVIRONMENT}, KM_KBP_OPTIONS_END}; - - km_kbp_path_name dummyPath = L"dummyActions.mock"; - EXPECT_EQ(km_kbp_keyboard_load(dummyPath, &kp->lpCoreKeyboard), KM_KBP_STATUS_OK); - EXPECT_EQ(km_kbp_state_create(kp->lpCoreKeyboard, test_env_opts, &kp->lpCoreKeyboardState), KM_KBP_STATUS_OK); - - kp->lpCoreKeyboardOptions = SaveKeyboardOptionsCore(kp); - // No Change - EXPECT_FALSE(UpdateKeyboardOptionsCore(kp->lpCoreKeyboardState, kp->lpCoreKeyboardOptions)); - std::u16string value = kp->lpCoreKeyboardOptions[0].value; - std::u16string expectedValue = u"not tiggered"; - EXPECT_TRUE(value == expectedValue); - - km_kbp_option_item update_key_opts[] = {{u"__test_point", u"triggered", KM_KBP_OPT_KEYBOARD}, KM_KBP_OPTIONS_END}; - EXPECT_EQ(km_kbp_state_options_update(kp->lpCoreKeyboardState, update_key_opts), KM_KBP_STATUS_OK); - // Change value to triggered - EXPECT_TRUE(UpdateKeyboardOptionsCore(kp->lpCoreKeyboardState, kp->lpCoreKeyboardOptions)); - value = kp->lpCoreKeyboardOptions[0].value; - expectedValue = u"triggered"; - EXPECT_TRUE(value == expectedValue); - DisposeKeyboardOptionsCore(&kp->lpCoreKeyboardOptions); - ReleaseStateMemoryCore(&kp->lpCoreKeyboardState); - ReleaseKeyboardMemoryCore(&kp->lpCoreKeyboard); - delete kp; - -} - -// Test SaveKeyboardOptionsCore and RestoreKeyboardOptionsCORE -TEST(KEYBOARDOPTIONS, SaveRestoreKeyboardOptionsCore) { - - LPINTKEYBOARDINFO kp = new INTKEYBOARDINFO; - memset(kp, 0, sizeof(INTKEYBOARDINFO)); - - km_kbp_option_item test_env_opts[] = { - {u"__test_point", u"not tiggered", KM_KBP_OPT_KEYBOARD}, {u"hello", u"-", KM_KBP_OPT_ENVIRONMENT}, KM_KBP_OPTIONS_END}; - km_kbp_path_name dummyPath = L"dummyActions.mock"; - EXPECT_EQ(km_kbp_keyboard_load(dummyPath, &kp->lpCoreKeyboard), KM_KBP_STATUS_OK); - EXPECT_EQ(km_kbp_state_create(kp->lpCoreKeyboard, test_env_opts, &kp->lpCoreKeyboardState), KM_KBP_STATUS_OK); - - km_kbp_option_item *SavedKBDOptions = SaveKeyboardOptionsCore(kp); - - std::u16string value = SavedKBDOptions[0].value; - std::u16string expectedValue = u"not tiggered"; - km_kbp_option_item update_key_opts[] = {{u"__test_point", u"triggered", KM_KBP_OPT_KEYBOARD}, KM_KBP_OPTIONS_END}; - EXPECT_EQ(km_kbp_state_options_update(kp->lpCoreKeyboardState, update_key_opts), KM_KBP_STATUS_OK); - - km_kbp_option_item *NewKBDOptions = SaveKeyboardOptionsCore(kp); - value = NewKBDOptions[0].value; - expectedValue = u"triggered"; - EXPECT_TRUE(value == expectedValue); - km_kbp_cp const *retValue = nullptr; - EXPECT_TRUE(RestoreKeyboardOptionsCore(kp->lpCoreKeyboardState, SavedKBDOptions)); - EXPECT_EQ(km_kbp_state_option_lookup(kp->lpCoreKeyboardState, KM_KBP_OPT_KEYBOARD, test_env_opts[0].key, &retValue), KM_KBP_STATUS_OK); - - value = retValue; - expectedValue = u"not tiggered"; - EXPECT_TRUE(value == expectedValue); - - DisposeKeyboardOptionsCore(&NewKBDOptions); - DisposeKeyboardOptionsCore(&SavedKBDOptions); - - ReleaseStateMemoryCore(&kp->lpCoreKeyboardState); - ReleaseKeyboardMemoryCore(&kp->lpCoreKeyboard); - delete kp; -} // Test SetupCoreEnvironment and also test km_kbp_state_options_update TEST(KEYBOARDOPTIONS, SetupCoreEnvironment) { -- GitLab From 504e4bd671f806da98591e5a69e00e28512c10e0 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 4 May 2023 13:08:31 +1000 Subject: [PATCH 022/214] chore(windows): rename MapKeyboardCore --- windows/src/engine/keyman32/keyman-engine.vcxproj | 4 ++-- windows/src/engine/keyman32/preservedkeymap.cpp | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/windows/src/engine/keyman32/keyman-engine.vcxproj b/windows/src/engine/keyman32/keyman-engine.vcxproj index 632b4e6a67..d2e78ef7e4 100644 --- a/windows/src/engine/keyman32/keyman-engine.vcxproj +++ b/windows/src/engine/keyman32/keyman-engine.vcxproj @@ -59,7 +59,7 @@ $(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\src;$(ProjectDir)..\..\..\..\core\build\rust\x86\$(Configuration);$(LibraryPath) - $(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\include;$(IncludePath) + $(ProjectDir)..\..\..\..\common\include;$(ProjectDir)..\..\..\..\core\include;$(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\include;$(IncludePath) @@ -397,4 +397,4 @@ - \ No newline at end of file + diff --git a/windows/src/engine/keyman32/preservedkeymap.cpp b/windows/src/engine/keyman32/preservedkeymap.cpp index be3cd54a53..1fd803838d 100644 --- a/windows/src/engine/keyman32/preservedkeymap.cpp +++ b/windows/src/engine/keyman32/preservedkeymap.cpp @@ -49,13 +49,13 @@ public: * @param cPreservedKeys number of preserved keys in pPreservedKeys - or the size pPreservedKeys needs to be * @return BOOL return TRUE on success */ - BOOL MapKeyboardCore(km_kbp_keyboard *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys); + BOOL MapKeyboard(km_kbp_keyboard *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys); private: BOOL m_BaseKeyboardUsesAltGr; // I4592 UINT ShiftToTSFShift(UINT ShiftFlags); BOOL MapUSCharToVK(UINT *puKey, UINT *puShiftFlags); - BOOL MapKeyRuleCore(km_kbp_keyboard_key *pKeyRule, TF_PRESERVEDKEY *pPreservedKey); + BOOL MapKeyRule(km_kbp_keyboard_key *pKeyRule, TF_PRESERVEDKEY *pPreservedKey); BOOL IsMatchingKey(PreservedKey *pKey, PreservedKey *pKeys, size_t cKeys); }; @@ -198,7 +198,7 @@ UINT PreservedKeyMap::ShiftToTSFShift(UINT ShiftFlags) } BOOL -PreservedKeyMap::MapKeyRuleCore(km_kbp_keyboard_key *pKeyRule, TF_PRESERVEDKEY *pPreservedKey) { +PreservedKeyMap::MapKeyRule(km_kbp_keyboard_key *pKeyRule, TF_PRESERVEDKEY *pPreservedKey) { UINT ShiftFlags; UINT Key; @@ -242,7 +242,7 @@ BOOL PreservedKeyMap::IsMatchingKey(PreservedKey *pKey, PreservedKey *pKeys, siz } BOOL -PreservedKeyMap::MapKeyboardCore(km_kbp_keyboard *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys) { +PreservedKeyMap::MapKeyboard(km_kbp_keyboard *pKeyboard, PreservedKey **pPreservedKeys, size_t *cPreservedKeys) { size_t cKeys = 0, cRules = 0, n = 0; DWORD i; @@ -297,7 +297,7 @@ PreservedKeyMap::MapKeyboardCore(km_kbp_keyboard *pKeyboard, PreservedKey **pPre for (i = 0; i < cRules; i++) { // If we have a key rule for the key, we should preserve it - if (MapKeyRuleCore(&kb_key_list[i], &pKeys[n].key)) { + if (MapKeyRule(&kb_key_list[i], &pKeys[n].key)) { // Don't attempt to add the same preserved key twice. Bad things happen if (!IsMatchingKey(&pKeys[n], pKeys, n)) { CoCreateGuid(&pKeys[n].guid); @@ -341,5 +341,5 @@ extern "C" __declspec(dllexport) BOOL WINAPI GetKeyboardPreservedKeys(PreservedK return FALSE; } // use api to get key rules - return pkm.MapKeyboardCore(_td->lpActiveKeyboard->lpCoreKeyboard, pPreservedKeys, cPreservedKeys); + return pkm.MapKeyboard(_td->lpActiveKeyboard->lpCoreKeyboard, pPreservedKeys, cPreservedKeys); } -- GitLab From 708b6bcf688779e5c34380f14a732bb3449c524e Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 4 May 2023 14:16:09 +1000 Subject: [PATCH 023/214] chore(windows): rename KeyboardOptionCoretoRegistry LoadKeyboardOptionsREGCore -> LoadKeyboardOptionsRegistrytoCore SaveKeyboardOptionREGCore -> SaveKeyboardOptionCoretoRegistry --- windows/src/engine/keyman32/K32_load.cpp | 2 +- windows/src/engine/keyman32/keyboardoptions.cpp | 16 ++++++++-------- windows/src/engine/keyman32/keyboardoptions.h | 4 ++-- windows/src/engine/keyman32/keyman32.cpp | 2 +- windows/src/engine/keyman32/kmprocessactions.cpp | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index ed2889b375..fb712f2f12 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -130,7 +130,7 @@ BOOL LoadlpKeyboard(int i) LoadDLLs(&_td->lpKeyboards[i]); - LoadKeyboardOptionsREGCore(&_td->lpKeyboards[i], _td->lpKeyboards[i].lpCoreKeyboardState); + LoadKeyboardOptionsRegistrytoCore(&_td->lpKeyboards[i], _td->lpKeyboards[i].lpCoreKeyboardState); return TRUE; } diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index 41eeddba42..251969d926 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -20,7 +20,7 @@ #include "pch.h" BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* const state); -void IntSaveKeyboardOptionREGCore(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value); +void IntSaveKeyboardOptionCoretoRegistry(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value); static km_kbp_cp* CloneKMKBPCP(const km_kbp_cp* cp) { LPCWSTR buf = reinterpret_cast(cp); @@ -35,12 +35,12 @@ static km_kbp_cp* CloneKMKBPCPFromWSTR(LPWSTR buf) { return clone; } -void SaveKeyboardOptionREGCore(LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value) +void SaveKeyboardOptionCoretoRegistry(LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value) { - IntSaveKeyboardOptionREGCore(REGSZ_KeyboardOptions, kp, key, value); + IntSaveKeyboardOptionCoretoRegistry(REGSZ_KeyboardOptions, kp, key, value); } -void IntSaveKeyboardOptionREGCore(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value) +void IntSaveKeyboardOptionCoretoRegistry(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value) { assert(REGKey != NULL); assert(kp != NULL); @@ -54,9 +54,9 @@ void IntSaveKeyboardOptionREGCore(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR k } } -void LoadKeyboardOptionsREGCore(LPINTKEYBOARDINFO kp, km_kbp_state* const state) +void LoadKeyboardOptionsRegistrytoCore(LPINTKEYBOARDINFO kp, km_kbp_state* const state) { - SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadKeyboardOptionsREGCore: Enter"); + SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadKeyboardOptionsRegistrytoCore: Enter"); IntLoadKeyboardOptionsCore(REGSZ_KeyboardOptions, kp, state); } @@ -70,7 +70,7 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* km_kbp_status err_status = km_kbp_keyboard_get_attrs(kp->lpCoreKeyboard, &keyboardAttrs); if (err_status != KM_KBP_STATUS_OK) { SendDebugMessageFormat( - 0, sdmKeyboard, 0, "LoadKeyboardOptionsREGCore: km_kbp_keyboard_get_attrs failed with error status [%d]", err_status); + 0, sdmKeyboard, 0, "LoadKeyboardOptionsRegistrytoCore: km_kbp_keyboard_get_attrs failed with error status [%d]", err_status); return FALSE; } @@ -102,7 +102,7 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* err_status = km_kbp_state_options_update(state, keyboardOpts); if (err_status != KM_KBP_STATUS_OK) { SendDebugMessageFormat( - 0, sdmKeyboard, 0, "LoadKeyboardOptionsREGCore: km_kbp_state_options_update failed with error status [%d]", err_status); + 0, sdmKeyboard, 0, "LoadKeyboardOptionsRegistrytoCore: km_kbp_state_options_update failed with error status [%d]", err_status); } for (int i = 0; i < n; i++) { delete[] keyboardOpts[i].value; diff --git a/windows/src/engine/keyman32/keyboardoptions.h b/windows/src/engine/keyman32/keyboardoptions.h index 0cedea3a80..f55b0bcc77 100644 --- a/windows/src/engine/keyman32/keyboardoptions.h +++ b/windows/src/engine/keyman32/keyboardoptions.h @@ -24,7 +24,7 @@ * @param kp keyboard info object with options to be updated * @param state core keyboard state used to update keyboard options */ -void LoadKeyboardOptionsREGCore(LPINTKEYBOARDINFO kp, km_kbp_state* state); +void LoadKeyboardOptionsRegistrytoCore(LPINTKEYBOARDINFO kp, km_kbp_state* state); /** * Saves the keyboard option to the windows registry @@ -33,6 +33,6 @@ void LoadKeyboardOptionsREGCore(LPINTKEYBOARDINFO kp, km_kbp_state* state); * @param key keyboard key to save * @param value keyboard option value to save */ -void SaveKeyboardOptionREGCore(LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value); +void SaveKeyboardOptionCoretoRegistry(LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value); diff --git a/windows/src/engine/keyman32/keyman32.cpp b/windows/src/engine/keyman32/keyman32.cpp index a1690409f9..f2d2afe5ed 100644 --- a/windows/src/engine/keyman32/keyman32.cpp +++ b/windows/src/engine/keyman32/keyman32.cpp @@ -607,7 +607,7 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_ForceKeyboard(PCSTR FileName LoadDLLs(_td->lpActiveKeyboard); ActivateDLLs(_td->lpActiveKeyboard); - LoadKeyboardOptionsREGCore(_td->lpActiveKeyboard, _td->lpActiveKeyboard->lpCoreKeyboardState); + LoadKeyboardOptionsRegistrytoCore(_td->lpActiveKeyboard, _td->lpActiveKeyboard->lpCoreKeyboardState); RefreshPreservedKeys(TRUE); return TRUE; fail: diff --git a/windows/src/engine/keyman32/kmprocessactions.cpp b/windows/src/engine/keyman32/kmprocessactions.cpp index 1e07523925..8855ad7e15 100644 --- a/windows/src/engine/keyman32/kmprocessactions.cpp +++ b/windows/src/engine/keyman32/kmprocessactions.cpp @@ -71,7 +71,7 @@ static BOOL processPersistOpt( SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessHook: Saving option to registry for keyboard [%s].", activeKeyboard->Name); LPWSTR value = new WCHAR[sizeof(actionItem->option->value) + 1]; wcscpy_s(value, sizeof(actionItem->option->value) + 1, reinterpret_cast(actionItem->option->value)); - SaveKeyboardOptionREGCore(activeKeyboard, reinterpret_cast(actionItem->option->key), value); + SaveKeyboardOptionCoretoRegistry(activeKeyboard, reinterpret_cast(actionItem->option->key), value); } } return TRUE; -- GitLab From ae80062815979ee4ec8800abc7974b874afaa3eb Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 4 May 2023 15:11:14 +1000 Subject: [PATCH 024/214] chore(windows): missed rename IntLoadKeyboardOptionsRegistrytoCore --- windows/src/engine/keyman32/keyboardoptions.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index 251969d926..96deb57590 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -19,7 +19,7 @@ */ #include "pch.h" -BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* const state); +BOOL IntLoadKeyboardOptionsRegistrytoCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* const state); void IntSaveKeyboardOptionCoretoRegistry(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value); static km_kbp_cp* CloneKMKBPCP(const km_kbp_cp* cp) { @@ -57,10 +57,10 @@ void IntSaveKeyboardOptionCoretoRegistry(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LP void LoadKeyboardOptionsRegistrytoCore(LPINTKEYBOARDINFO kp, km_kbp_state* const state) { SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadKeyboardOptionsRegistrytoCore: Enter"); - IntLoadKeyboardOptionsCore(REGSZ_KeyboardOptions, kp, state); + IntLoadKeyboardOptionsRegistrytoCore(REGSZ_KeyboardOptions, kp, state); } -BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* const state) +BOOL IntLoadKeyboardOptionsRegistrytoCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* const state) { assert(key != NULL); assert(kp != NULL); -- GitLab From a7630a02652286f96c486c9eada9b9b0687d0e59 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 24 Mar 2023 18:31:18 +0100 Subject: [PATCH 025/214] fix(linux): Fix linux tests --- common/test/keyboards/.gitignore | 1 + linux/debian/rules | 2 + linux/ibus-keyman/src/kmpdetails.c | 4 - linux/ibus-keyman/tests/meson.build | 8 +- .../tests/scripts/run-single-test.sh | 1 + linux/ibus-keyman/tests/scripts/run-tests.sh | 62 ++++++++------ .../ibus-keyman/tests/scripts/setup-tests.sh | 80 +++++++++---------- .../tests/scripts/teardown-tests.sh | 1 + .../ibus-keyman/tests/scripts/test-helper.sh | 79 ++++++++++++++++++ 9 files changed, 161 insertions(+), 77 deletions(-) diff --git a/common/test/keyboards/.gitignore b/common/test/keyboards/.gitignore index 577a20b276..5dda6d16d8 100644 --- a/common/test/keyboards/.gitignore +++ b/common/test/keyboards/.gitignore @@ -1,3 +1,4 @@ +baseline/kmp.json **/build/ */*_source.zip index.html diff --git a/linux/debian/rules b/linux/debian/rules index e67ea1b5af..774371d252 100755 --- a/linux/debian/rules +++ b/linux/debian/rules @@ -9,6 +9,8 @@ export PYBUILD_INSTALL_ARGS=--install-scripts=/usr/share/keyman-config/ export KEYMAN_PKG_BUILD=1 +export XDG_DATA_HOME=$(shell mktemp -d) + # xenial needs this to be explicit export LC_ALL=C.UTF-8 diff --git a/linux/ibus-keyman/src/kmpdetails.c b/linux/ibus-keyman/src/kmpdetails.c index a6b7fbb189..eba95f4ef9 100644 --- a/linux/ibus-keyman/src/kmpdetails.c +++ b/linux/ibus-keyman/src/kmpdetails.c @@ -272,9 +272,6 @@ kmp_json_status get_keyboard_details(const char *kmp_dir, const char *id, keyboa } g_object_unref(parser); return JSON_OK; - - - } kmp_json_status get_kmp_details(const char *kmp_dir, kmp_details *details) @@ -295,7 +292,6 @@ kmp_json_status get_kmp_details(const char *kmp_dir, kmp_details *details) return JSON_FILE_NOT_EXISTS; } - json_parser_load_from_file (parser, kmp_json, &error); diff --git a/linux/ibus-keyman/tests/meson.build b/linux/ibus-keyman/tests/meson.build index 8b2dea17a0..c67f9920a9 100644 --- a/linux/ibus-keyman/tests/meson.build +++ b/linux/ibus-keyman/tests/meson.build @@ -6,13 +6,9 @@ test_files = [ 'testmodule.h', ] -kmx_dir = [ - core_dir / 'build/arch' / get_option('buildtype') / 'tests/kmx_test_source' -] - kmnkbp_tests_lib = cc.find_library( 'libkmnkbp-tests', - dirs: kmx_dir + dirs: [ core_dir / 'build/arch' / get_option('buildtype') / 'tests/kmx_test_source' ] ) deps = [ibus, gtk, x11, json_glib, kmnkbp_lib, kmnkbp_tests_lib] @@ -84,7 +80,7 @@ test( kmxtest_files = run_command( find_tests, - kmx_dir, + [ common_dir / 'test/keyboards/baseline' ], check: true, ).stdout().split('\n') diff --git a/linux/ibus-keyman/tests/scripts/run-single-test.sh b/linux/ibus-keyman/tests/scripts/run-single-test.sh index c265c27ccd..8e4e84f2ca 100755 --- a/linux/ibus-keyman/tests/scripts/run-single-test.sh +++ b/linux/ibus-keyman/tests/scripts/run-single-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +set -eu TESTDIR=${XDG_DATA_HOME:-$HOME/.local/share}/keyman/test_kmx . "$(dirname "$0")"/test-helper.sh diff --git a/linux/ibus-keyman/tests/scripts/run-tests.sh b/linux/ibus-keyman/tests/scripts/run-tests.sh index 81f32bd4ef..4c0934511f 100755 --- a/linux/ibus-keyman/tests/scripts/run-tests.sh +++ b/linux/ibus-keyman/tests/scripts/run-tests.sh @@ -1,7 +1,10 @@ #!/usr/bin/env bash +set -eu -TOP_SRCDIR=${top_srcdir:-$(realpath "$(dirname "$0")/..")} -TESTDIR=${XDG_DATA_HOME:-$HOME/.local/share}/keyman/test_kmx +TOP_SRCDIR=${top_srcdir:-$(realpath "$(dirname "$0")/../..")} +TESTBASEDIR=${XDG_DATA_HOME:-$HOME/.local/share}/keyman +TESTDIR=${TESTBASEDIR}/test_kmx +PID_FILE=/tmp/ibus-keyman-test-pids . "$(dirname "$0")"/test-helper.sh @@ -70,19 +73,9 @@ function run_tests() { exit 2 fi - # TODO: we are borrowing the KMX tests out of core; these should be shared in common - # to avoid deep links like this in future - KMX_TEST_DIR="${TOP_SRCDIR}"/../../common/test/keyboards/baseline - - if [ ! -d "$TESTDIR" ] || ! [[ $(find "${TESTDIR}/" -name \*.kmx 2>/dev/null | wc -l) -gt 0 ]]; then - if [[ $(find "${KMX_TEST_DIR}/" -name \*.kmx 2>/dev/null | wc -l) -gt 0 ]]; then - mkdir -p "$(realpath --canonicalize-missing "$TESTDIR"/..)" - ln -sf "$(realpath "${KMX_TEST_DIR}")" "$TESTDIR" - else - echo "Can't find kmx files in ${KMX_TEST_DIR}" - exit 3 - fi - fi + link_test_keyboards "${TOP_SRCDIR}/../../common/test/keyboards/baseline" "$TESTDIR" "$TESTBASEDIR" + + generate_kmpjson "$TESTDIR" echo "# NOTE: When the tests fail check /tmp/ibus-engine-keyman.log and /tmp/ibus-daemon.log!" echo "" @@ -100,7 +93,7 @@ function run_tests() { echo "kill -9 $! || true" >> "$PID_FILE" sleep 1s export WAYLAND_DISPLAY - WAYLAND_DISPLAY=$(cat "$TMPFILE" | grep "Using Wayland display" | cut -d"'" -f2) + WAYLAND_DISPLAY=$(grep "Using Wayland display" "$TMPFILE" | cut -d"'" -f2) rm "$TMPFILE" else echo "# Starting Xvfb..." @@ -127,6 +120,7 @@ function run_tests() { glib-compile-schemas "$SCHEMA_DIR" if [ $# -gt 0 ]; then + #shellcheck disable=SC2206 TESTFILES=($@) else pushd "$TESTDIR" > /dev/null || exit @@ -134,7 +128,7 @@ function run_tests() { popd > /dev/null || exit fi - export LD_LIBRARY_PATH=${COMMON_ARCH_DIR}/src:$LD_LIBRARY_PATH + export LD_LIBRARY_PATH=${COMMON_ARCH_DIR}/src:${LD_LIBRARY_PATH-} # Ubuntu 18.04 Bionic doesn't have ibus-memconf, and glib is not compiled with the keyfile # backend enabled, so we just use the default backend. Otherwise we use the keyfile @@ -144,19 +138,34 @@ function run_tests() { IBUS_CONFIG=--config=/usr/libexec/ibus-memconf fi - ibus-daemon "${ARG_VERBOSE-}" --panel=disable ${IBUS_CONFIG-} &> /tmp/ibus-daemon.log & + #shellcheck disable=SC2086 + ibus-daemon "${ARG_VERBOSE-}" --panel=disable --address=unix:abstract="${TEMP_DATA_DIR}"/test-ibus ${IBUS_CONFIG-} &> /tmp/ibus-daemon.log & echo "kill -9 $! || true" >> "$PID_FILE" sleep 1s - ../src/ibus-engine-keyman "${ARG_VERBOSE-}" &> /tmp/ibus-engine-keyman.log & + IBUS_ADDRESS=$(ibus address) + export IBUS_ADDRESS + + if [ -d "../../build/$(arch)/debug" ]; then + CONFIG=debug + elif [ -d "../../build/$(arch)/release" ]; then + CONFIG=release + else + echo "Can't find neither ../../build/$(arch)/debug nor ../../build/$(arch)/release" + exit 9 + fi + + "../../build/$(arch)/${CONFIG}/src/ibus-engine-keyman" "${ARG_VERBOSE-}" &> /tmp/ibus-engine-keyman.log & echo "kill -9 $! || true" >> "$PID_FILE" sleep 1s echo "# Starting tests..." # Note: -k and --tap are consumed by the GLib testing framework - "${G_TEST_BUILDDIR:-.}"/ibus-keyman-tests "${ARG_K-}" "${ARG_TAP-}" \ - "${ARG_VERBOSE-}" "${ARG_DEBUG-}" "${ARG_SURROUNDING_TEXT-}" "${ARG_NO_SURROUNDING_TEXT-}" \ - --directory "$TESTDIR" --"${DISPLAY_SERVER}" "${TESTFILES[@]}" + #shellcheck disable=SC2068 # we want to split array elements! + #shellcheck disable=SC2086 + "${G_TEST_BUILDDIR:-../../build/$(arch)/${CONFIG}/tests}/ibus-keyman-tests" ${ARG_K-} ${ARG_TAP-} \ + ${ARG_VERBOSE-} ${ARG_DEBUG-} ${ARG_SURROUNDING_TEXT-} ${ARG_NO_SURROUNDING_TEXT-} \ + --directory "$TESTDIR" --"${DISPLAY_SERVER}" ${TESTFILES[@]} echo "# Finished tests." cleanup @@ -197,13 +206,18 @@ if [ "$USE_WAYLAND" == "0" ] && [ "$USE_X11" == "0" ]; then exit 6 fi +G_TEST_BUILDDIR="${G_TEST_BUILDDIR:-../../build/$(arch)/debug/tests}" +if [ ! -f "${G_TEST_BUILDDIR}/ibus-keyman-tests" ]; then + G_TEST_BUILDDIR="${G_TEST_BUILDDIR:-../../build/$(arch)/release/tests}" +fi + echo > "$PID_FILE" trap cleanup EXIT SIGINT if [ "$USE_WAYLAND" == "1" ]; then - run_tests wayland "$@" + ( run_tests wayland "$@" ) fi if [ "$USE_X11" == "1" ]; then - run_tests x11 "$@" + ( run_tests x11 "$@" ) fi diff --git a/linux/ibus-keyman/tests/scripts/setup-tests.sh b/linux/ibus-keyman/tests/scripts/setup-tests.sh index 94400d40f2..1e868f7430 100755 --- a/linux/ibus-keyman/tests/scripts/setup-tests.sh +++ b/linux/ibus-keyman/tests/scripts/setup-tests.sh @@ -1,11 +1,13 @@ #!/usr/bin/env bash +set -eu DISPLAY_SERVER=$1 ENV_FILE=$2 PID_FILE=$3 TOP_SRCDIR=${G_TEST_SRCDIR:-$(realpath "$(dirname "$0")/..")}/.. TOP_BINDIR=${G_TEST_BUILDDIR:-$(realpath "$(dirname "$0/..")")}/.. -TESTDIR=${XDG_DATA_HOME:-$HOME/.local/share}/keyman/test_kmx +TESTBASEDIR=${XDG_DATA_HOME:-$HOME/.local/share}/keyman +TESTDIR=${TESTBASEDIR}/test_kmx . "$(dirname "$0")"/test-helper.sh @@ -32,19 +34,9 @@ else exit 2 fi -# TODO: we are borrowing the KMX tests out of core; these should be shared in common -# to avoid deep links like this in future -KMX_TEST_DIR="${TOP_SRCDIR}"/../../common/test/keyboards/baseline - -if [ ! -d "$TESTDIR" ] || ! [[ $(find "${TESTDIR}/" -name \*.kmx 2>/dev/null | wc -l) -gt 0 ]]; then - if [[ $(find "${KMX_TEST_DIR}/" -name \*.kmx 2>/dev/null | wc -l) -gt 0 ]]; then - mkdir -p "$(realpath --canonicalize-missing "$TESTDIR"/..)" - ln -sf "$(realpath "${KMX_TEST_DIR}")" "$TESTDIR" - else - echo "Can't find kmx files in ${KMX_TEST_DIR}" - exit 3 - fi -fi +link_test_keyboards "${TOP_SRCDIR}/../../common/test/keyboards/baseline" "$TESTDIR" "$TESTBASEDIR" + +generate_kmpjson "$TESTDIR" if [ "$DISPLAY_SERVER" == "wayland" ]; then if ! can_run_wayland; then @@ -79,36 +71,38 @@ else echo "export DISPLAY=\"$DISPLAY\"" >> "$ENV_FILE" fi - # Install schema to temporary directory. This removes the build dependency on the keyman package. - SCHEMA_DIR=$TEMP_DATA_DIR/glib-2.0/schemas - export XDG_DATA_DIRS=$TEMP_DATA_DIR:$XDG_DATA_DIRS - echo "export XDG_DATA_DIRS=\"$XDG_DATA_DIRS\"" >> "$ENV_FILE" - - mkdir -p "$SCHEMA_DIR" - cp "${TOP_SRCDIR}"/../keyman-config/com.keyman.gschema.xml "$SCHEMA_DIR"/ - glib-compile-schemas "$SCHEMA_DIR" - - export LD_LIBRARY_PATH=${COMMON_ARCH_DIR}/src:$LD_LIBRARY_PATH - echo "export LD_LIBRARY_PATH=\"$LD_LIBRARY_PATH\"" >> "$ENV_FILE" - - # Ubuntu 18.04 Bionic doesn't have ibus-memconf, and glib is not compiled with the keyfile - # backend enabled, so we just use the default backend. Otherwise we use the keyfile - # store which interferes less when running on a dev machine. - if [ -f /usr/libexec/ibus-memconf ]; then - export GSETTINGS_BACKEND=keyfile - echo "export GSETTINGS_BACKEND=\"$GSETTINGS_BACKEND\"" >> "$ENV_FILE" - IBUS_CONFIG=--config=/usr/libexec/ibus-memconf - fi +# Install schema to temporary directory. This removes the build dependency on the keyman package. +SCHEMA_DIR=$TEMP_DATA_DIR/glib-2.0/schemas +export XDG_DATA_DIRS=$TEMP_DATA_DIR:${XDG_DATA_DIRS-} +echo "export XDG_DATA_DIRS=\"$XDG_DATA_DIRS\"" >> "$ENV_FILE" + +mkdir -p "$SCHEMA_DIR" +cp "${TOP_SRCDIR}"/../keyman-config/com.keyman.gschema.xml "$SCHEMA_DIR"/ +glib-compile-schemas "$SCHEMA_DIR" + +export LD_LIBRARY_PATH=${COMMON_ARCH_DIR}/src:${LD_LIBRARY_PATH-} +echo "export LD_LIBRARY_PATH=\"$LD_LIBRARY_PATH\"" >> "$ENV_FILE" + +# Ubuntu 18.04 Bionic doesn't have ibus-memconf, and glib is not compiled with the keyfile +# backend enabled, so we just use the default backend. Otherwise we use the keyfile +# store which interferes less when running on a dev machine. +if [ -f /usr/libexec/ibus-memconf ]; then + export GSETTINGS_BACKEND=keyfile + echo "export GSETTINGS_BACKEND=\"$GSETTINGS_BACKEND\"" >> "$ENV_FILE" + IBUS_CONFIG=--config=/usr/libexec/ibus-memconf +fi - ibus-daemon "${ARG_VERBOSE-}" --daemonize --panel=disable ${IBUS_CONFIG-} &> /tmp/ibus-daemon.log - echo "kill -9 $! || true" >> "$PID_FILE" - sleep 1s +#shellcheck disable=SC2086 +ibus-daemon ${ARG_VERBOSE-} --daemonize --panel=disable --address=unix:abstract="${TEMP_DATA_DIR}/test-ibus" ${IBUS_CONFIG-} &> /tmp/ibus-daemon.log +echo "kill -9 $! || true" >> "$PID_FILE" +sleep 1s - IBUS_ADDRESS=$(ibus address) - export IBUS_ADDRESS +IBUS_ADDRESS=$(ibus address) +export IBUS_ADDRESS - echo "export IBUS_ADDRESS=\"$IBUS_ADDRESS\"" >> "$ENV_FILE" +echo "export IBUS_ADDRESS=\"$IBUS_ADDRESS\"" >> "$ENV_FILE" - "${TOP_BINDIR}"/src/ibus-engine-keyman "${ARG_VERBOSE-}" &> /tmp/ibus-engine-keyman.log & - echo "kill -9 $! || true" >> "$PID_FILE" - sleep 1s +#shellcheck disable=SC2086 +"${TOP_BINDIR}/src/ibus-engine-keyman" ${ARG_VERBOSE-} &> /tmp/ibus-engine-keyman.log & +echo "kill -9 $! || true" >> "$PID_FILE" +sleep 1s diff --git a/linux/ibus-keyman/tests/scripts/teardown-tests.sh b/linux/ibus-keyman/tests/scripts/teardown-tests.sh index 489769d721..45cfce605d 100755 --- a/linux/ibus-keyman/tests/scripts/teardown-tests.sh +++ b/linux/ibus-keyman/tests/scripts/teardown-tests.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +set -eu PID_FILE=$1 echo "Shutting down processes..." diff --git a/linux/ibus-keyman/tests/scripts/test-helper.sh b/linux/ibus-keyman/tests/scripts/test-helper.sh index 92c8a7e528..0098a86176 100755 --- a/linux/ibus-keyman/tests/scripts/test-helper.sh +++ b/linux/ibus-keyman/tests/scripts/test-helper.sh @@ -9,3 +9,82 @@ function can_run_wayland() { return 0 fi } + +function generate_kmpjson() { + local TESTDIR + TESTDIR="$1" + pushd "$TESTDIR" > /dev/null || exit + KMPFILE="${TESTDIR}/kmp.json" + cat <<-EOF > "$KMPFILE" + { + "system": { + "keymanDeveloperVersion": "10.0.1099.0", + "fileVersion": "7.0" + }, + "options": { + "readmeFile": "kmx.cpp" + }, + "info": { + "name": { + "description": "Test Keyboards" + }, + "version": { + "description": "0.0" + }, + "copyright": { + "description": "\u00A9 2018-2023 SIL International" + }, + "author": { + "description": "" + } + }, + "files": [ + { + "name": "kmp.json", + "description": "Package information (JSON)" + } + ], + "keyboards": [ +EOF + FIRST=true + for f in k_*.kmx; do + keyboard=$(basename "$f") + keyboard="${keyboard%.*}" + if $FIRST; then + FIRST=false + else + echo "," >> "$KMPFILE" + fi + cat <<-EOF >> "$KMPFILE" + { + "name": "$keyboard", + "id": "$keyboard", + "version": "0.0", + "languages": [ + { + "name": "Undetermined", + "id": "und" + } + ] + } +EOF + done + echo "]" >> "$KMPFILE" + echo "}" >> "$KMPFILE" + popd > /dev/null || exit +} + +function link_test_keyboards() { + KMX_TEST_DIR=$1 + TESTDIR=$2 + TESTBASEDIR=$3 + + if [[ $(find "${KMX_TEST_DIR}/" -name k_\*.kmx 2>/dev/null | wc -l) -gt 0 ]]; then + mkdir -p "$(realpath --canonicalize-missing "$TESTBASEDIR")" + rm -f "$TESTDIR" + ln -sf "$(realpath "${KMX_TEST_DIR}")" "$TESTDIR" + else + echo "Can't find test kmx files in ${KMX_TEST_DIR}" + exit 3 + fi +} -- GitLab From cb0b7535b149dce9c4ccbfee3905117353249bfb Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Thu, 27 Apr 2023 17:24:21 +0200 Subject: [PATCH 026/214] chore(linux): Build for Lunar on all platforms Add building and upload to llso/pso now that this is possible. --- .github/workflows/deb-packaging.yml | 2 +- linux/Jenkinsfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deb-packaging.yml b/.github/workflows/deb-packaging.yml index 80161dfeda..7b12bf8880 100644 --- a/.github/workflows/deb-packaging.yml +++ b/.github/workflows/deb-packaging.yml @@ -102,7 +102,7 @@ jobs: strategy: fail-fast: true matrix: - dist: [focal, jammy, kinetic] + dist: [focal, jammy, kinetic, lunar] arch: [amd64] runs-on: ubuntu-latest diff --git a/linux/Jenkinsfile b/linux/Jenkinsfile index 15f5b27777..b70cb95d70 100644 --- a/linux/Jenkinsfile +++ b/linux/Jenkinsfile @@ -5,7 +5,7 @@ @Library('lsdev-pipeline-library') _ keymanPackaging { - distributionsToPackage = 'focal jammy kinetic' + distributionsToPackage = 'focal jammy kinetic lunar' arches = 'amd64 i386' packagesToBuild = ['keyman'] } -- GitLab From 2df48623a070b6552fe2073fc691bf0d995bda17 Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Fri, 5 May 2023 14:02:02 -0400 Subject: [PATCH 027/214] auto: increment master version to 17.0.102 --- HISTORY.md | 5 +++++ VERSION.md | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 277044675b..f5134cf0f6 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,10 @@ # Keyman Version History +## 17.0.101 alpha 2023-05-05 + +* chore(common): `set -eu` in build-utils.sh (#8698) +* fix(android/app): Resize OSK when resuming app from background (#8704) + ## 17.0.100 alpha 2023-05-04 * (#8690) diff --git a/VERSION.md b/VERSION.md index 14ccd0be84..2aea3204c5 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.101 \ No newline at end of file +17.0.102 \ No newline at end of file -- GitLab From c6380fbaf9eddf0569dfcf92189483cc28709051 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Fri, 5 May 2023 14:24:29 -0500 Subject: [PATCH 028/214] =?UTF-8?q?feat(developer):=20uset=20api=20from=20?= =?UTF-8?q?wasm!=20=F0=9F=99=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For: #7234 --- .../src/kmc-kmn/src/compiler/compiler.ts | 76 ++++++++++++++++++- developer/src/kmc-kmn/test/test-compiler.ts | 2 +- developer/src/kmc-kmn/test/test-wasm-uset.ts | 70 +++++++++++++++++ .../src/kmcmplib/src/CompilerInterfaces.cpp | 11 ++- 4 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 developer/src/kmc-kmn/test/test-wasm-uset.ts diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index c112b4caf7..dbdde636a9 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -53,6 +53,7 @@ export class Compiler { setCompilerOptions: any; callbackName: string; callbacks: CompilerCallbacks; + _parseUnicodeSet: any; constructor() { this.callbackName = 'kmnCompilerCallback' + callbackProcIdentifier; @@ -65,8 +66,11 @@ export class Compiler { this.compileKeyboardFile = this.wasmModule.cwrap('kmcmp_Wasm_CompileKeyboardFile', 'boolean', ['string', 'string', 'number', 'number', 'number', 'string']); this.setCompilerOptions = this.wasmModule.cwrap('kmcmp_Wasm_SetCompilerOptions', 'boolean', ['number']); + this._parseUnicodeSet = this.wasmModule.cwrap('kmcmp_Wasm_ParseUnicodeSet', 'number', [ 'string', 'number', 'number']); } - return this.compileKeyboardFile !== undefined && this.setCompilerOptions !== undefined; + return this.compileKeyboardFile !== undefined + && this.setCompilerOptions !== undefined + && this._parseUnicodeSet !== undefined; } public run(infile: string, outfile: string, callbacks: CompilerCallbacks, options?: CompilerOptions): boolean { @@ -107,4 +111,72 @@ export class Compiler { return false; } } -} \ No newline at end of file + + /** + * + * @param pattern UnicodeSet pattern such as `[a-z]` + * @param bufferSize guess as to the buffer size + * @returns UnicodeSet accessor object + */ + public async parseUnicodeSet(pattern: string, bufferSize: number) : Promise { + if (!bufferSize) { + bufferSize = 100; + } + + const initOk = await this.init(); + if (!initOk) { + throw Error(`WASM machinery didn't start up properly`); + } + // Module seems to be the usual name for it + const Module = this.wasmModule; + const buf = Module.asm.malloc(bufferSize * 2 * Module.HEAPU32.BYTES_PER_ELEMENT); + const rc = this._parseUnicodeSet(pattern, buf, bufferSize); + if (rc < 0) { + throw new UnicodeSetError(rc); + } else { // rc ≥0 + const ranges = []; + const startu = (buf / Module.HEAPU32.BYTES_PER_ELEMENT); + for (let i = 0; i < rc; i++) { + const low = Module.HEAPU32[startu + (i * 2) + 0]; + const high = Module.HEAPU32[startu + (i * 2) + 1]; + ranges.push([low, high]); + } + return new UnicodeSet(pattern, ranges); + } + } +} + +export class UnicodeSetError extends Error { + code: number; + constructor(code:number) { + super(); + this.code = code; + this.message = `UnicodeSet error: ${code}`; + } +} + +// from kmcmplib.h +export const KMCMP_USET_OK = 0; +export const KMCMP_ERROR_SYNTAX_ERR = -1; +export const KMCMP_ERROR_HAS_STRINGS = -2; +export const KMCMP_ERROR_UNSUPPORTED_PROPERTY = -3; +export const KMCMP_ERROR_UNSUPPORTED = -4; +export const KMCMP_FATAL_OUT_OF_RANGE = -5; + +/** + * Represents a parsed UnicodeSet + */ +export class UnicodeSet { + pattern: string; + ranges: number[][]; + constructor(pattern: string, ranges: number[][]) { + this.pattern = pattern; + this.ranges = ranges; + } + /** + * Number of ranges + */ + get length() : number { + return this.ranges.length; + } +} diff --git a/developer/src/kmc-kmn/test/test-compiler.ts b/developer/src/kmc-kmn/test/test-compiler.ts index 081ed7762b..98ce1bd4ed 100644 --- a/developer/src/kmc-kmn/test/test-compiler.ts +++ b/developer/src/kmc-kmn/test/test-compiler.ts @@ -71,4 +71,4 @@ describe('Compiler class', function() { } }); -}); \ No newline at end of file +}); diff --git a/developer/src/kmc-kmn/test/test-wasm-uset.ts b/developer/src/kmc-kmn/test/test-wasm-uset.ts new file mode 100644 index 0000000000..ff96493029 --- /dev/null +++ b/developer/src/kmc-kmn/test/test-wasm-uset.ts @@ -0,0 +1,70 @@ +import 'mocha'; +import sinon from 'sinon'; +import chai, { assert } from 'chai'; +import sinonChai from 'sinon-chai'; +import { Compiler } from '../src/main.js'; +import { KMCMP_ERROR_HAS_STRINGS, KMCMP_ERROR_SYNTAX_ERR, KMCMP_ERROR_UNSUPPORTED_PROPERTY, KMCMP_FATAL_OUT_OF_RANGE, UnicodeSetError } from '../src/compiler/compiler.js'; +chai.use(sinonChai); + +describe('Compiler class', function() { + let consoleLog: any; + + beforeEach(function() { + consoleLog = sinon.spy(console, 'log'); + }); + + afterEach(function() { + consoleLog.restore(); + }); + + it('should start', async function() { + const compiler = new Compiler(); + assert(await compiler.init()); + }); + + it('should compile a basic uset', async function() { + const compiler = new Compiler(); + // const callbacks = new TestCompilerCallbacks(); + assert(await compiler.init()); + + const pat = "[abc]"; + const set = await compiler.parseUnicodeSet(pat, 23); + + assert(set.length === 1); + assert(set.ranges[0][0] === 'a'.charCodeAt(0)); + assert(set.ranges[0][1] === 'c'.charCodeAt(0)); + }); + it('should compile a more complex uset', async function() { + const compiler = new Compiler(); + assert(await compiler.init()); + + const pat = "[[🙀A-C]-[CB]]"; + const set = await compiler.parseUnicodeSet(pat, 23); + + assert.equal(set.length, 2); + assert.equal(set.ranges[0][0], 'A'.charCodeAt(0)); + assert.equal(set.ranges[0][1], 'A'.charCodeAt(0)); + assert.equal(set.ranges[1][0], 0x1F640); + assert.equal(set.ranges[1][1], 0x1F640); + }); + it('should fail in various ways', async function() { + const compiler = new Compiler(); + assert(await compiler.init()); + // map from string to failing error + const failures = { + '[:Adlm:]': KMCMP_ERROR_UNSUPPORTED_PROPERTY, // what it saye + '[acegik]': KMCMP_FATAL_OUT_OF_RANGE, // 6 ranges, allocated 1 + '[[\\p{Mn}]&[A-Z]]': KMCMP_ERROR_UNSUPPORTED_PROPERTY, + '[abc{def}]': KMCMP_ERROR_HAS_STRINGS, + '[[]': KMCMP_ERROR_SYNTAX_ERR, + }; + for(const [pat, rc] of Object.entries(failures)) { + try { + await compiler.parseUnicodeSet(pat, 1); + } catch (e) { + assert(e instanceof UnicodeSetError); + assert.equal(e.code, rc); + } + } + }); +}); diff --git a/developer/src/kmcmplib/src/CompilerInterfaces.cpp b/developer/src/kmcmplib/src/CompilerInterfaces.cpp index 1eb9b6eaab..89c4655d16 100644 --- a/developer/src/kmcmplib/src/CompilerInterfaces.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfaces.cpp @@ -65,6 +65,15 @@ EXTERN bool kmcmp_Wasm_CompileKeyboardFile(char* pszInfile, msgProc ); } + +EXTERN int kmcmp_Wasm_ParseUnicodeSet(char* pat, + uint32_t* buf, int length +) { + return kmcmp_ParseUnicodeSet( + pat, buf, length + ); +} + #endif EXTERN bool kmcmp_CompileKeyboardFile(char* pszInfile, @@ -365,4 +374,4 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) kmcmp::CheckForDeprecatedFeatures(fk); return TRUE; -} \ No newline at end of file +} -- GitLab From 806a757da21a5922e74465e35e42b0aeae31adcf Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 8 May 2023 14:48:53 +1000 Subject: [PATCH 029/214] chore(windows): remove old ld keyboard info --- windows/src/engine/keyman32/keymanengine.h | 1 - 1 file changed, 1 deletion(-) diff --git a/windows/src/engine/keyman32/keymanengine.h b/windows/src/engine/keyman32/keymanengine.h index 3314056acf..775a64d106 100644 --- a/windows/src/engine/keyman32/keymanengine.h +++ b/windows/src/engine/keyman32/keymanengine.h @@ -107,7 +107,6 @@ typedef struct tagKMSTATE WCHAR charCode; // I4582 BOOL windowunicode; // I4287 BOOL isDown; - LPKEYBOARD lpkb; km_kbp_keyboard* lpCoreKb; // future use with IMDLL } KMSTATE; -- GitLab From f150f0cd686bf54555733ce19429cfdef82887d3 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Mon, 8 May 2023 09:53:36 +0200 Subject: [PATCH 030/214] Update linux/ibus-keyman/tests/scripts/test-helper.sh Co-authored-by: Steven R. Loomis --- linux/ibus-keyman/tests/scripts/test-helper.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/linux/ibus-keyman/tests/scripts/test-helper.sh b/linux/ibus-keyman/tests/scripts/test-helper.sh index 0098a86176..7b37faaf21 100755 --- a/linux/ibus-keyman/tests/scripts/test-helper.sh +++ b/linux/ibus-keyman/tests/scripts/test-helper.sh @@ -15,6 +15,7 @@ function generate_kmpjson() { TESTDIR="$1" pushd "$TESTDIR" > /dev/null || exit KMPFILE="${TESTDIR}/kmp.json" + THISYEAR=$(date "+%Y") cat <<-EOF > "$KMPFILE" { "system": { -- GitLab From 215e8d5eb81e4f6ff20efd51e0ad64cfd7ed4773 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Mon, 8 May 2023 09:53:45 +0200 Subject: [PATCH 031/214] Update linux/ibus-keyman/tests/scripts/test-helper.sh Co-authored-by: Steven R. Loomis --- linux/ibus-keyman/tests/scripts/test-helper.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux/ibus-keyman/tests/scripts/test-helper.sh b/linux/ibus-keyman/tests/scripts/test-helper.sh index 7b37faaf21..92e517009c 100755 --- a/linux/ibus-keyman/tests/scripts/test-helper.sh +++ b/linux/ibus-keyman/tests/scripts/test-helper.sh @@ -33,7 +33,7 @@ function generate_kmpjson() { "description": "0.0" }, "copyright": { - "description": "\u00A9 2018-2023 SIL International" + "description": "\u00A9 2018-${THISYEAR} SIL International" }, "author": { "description": "" -- GitLab From 8520b1aaa911de51a2ba4f08404a0027f87c2783 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Mon, 8 May 2023 10:20:21 +0200 Subject: [PATCH 032/214] chore(linux): Fix uploading to launchpad This fixes some uninitialized variables. --- linux/scripts/launchpad.sh | 34 ++++++++---------------------- linux/scripts/package-build.inc.sh | 15 ++++++------- 2 files changed, 15 insertions(+), 34 deletions(-) diff --git a/linux/scripts/launchpad.sh b/linux/scripts/launchpad.sh index c16d89f7d6..cdca3e3c0d 100755 --- a/linux/scripts/launchpad.sh +++ b/linux/scripts/launchpad.sh @@ -10,7 +10,7 @@ # DIST="" only upload for this distribution # PACKAGEVERSION="" string to append to the package version. Default to "1~sil1" -set -e +set -eu ## START STANDARD BUILD SCRIPT INCLUDE # adjust relative paths as necessary @@ -18,16 +18,10 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "${THIS_SCRIPT%/*}/../../resources/build/build-utils.sh" ## END STANDARD BUILD SCRIPT INCLUDE -. $(dirname "$THIS_SCRIPT")/package-build.inc.sh +. "$(dirname "$THIS_SCRIPT")/package-build.inc.sh" checkPrerequisites -if [ "${UPLOAD}" == "yes" ]; then - SIM="" -else - SIM="-s" -fi - if [ "${TIER}" == "stable" ]; then ppa="ppa:keymanapp/keyman" elif [ "${TIER}" == "beta" ]; then @@ -37,39 +31,29 @@ else fi echo "ppa: ${ppa}" -if [ "${DIST:-}" != "" ]; then - distributions="${DIST}" -else - distributions="focal jammy kinetic lunar" -fi - -if [ "${PACKAGEVERSION:-}" != "" ]; then - packageversion="${PACKAGEVERSION}" -else - packageversion="1~sil1" -fi - +distributions="${DIST:-focal jammy kinetic lunar}" +packageversion="${PACKAGEVERSION:-1~sil1}" BASEDIR=$(pwd) rm -rf launchpad mkdir -p launchpad -for proj in ${projects}; do +for proj in ${projects:-}; do downloadSource launchpad - cd "${proj}-${version}" + cd "${proj}-${version:-}" pwd - cp debian/changelog ../${proj}-changelog + cp debian/changelog "../${proj}-changelog" for dist in ${distributions}; do - cp ../${proj}-changelog debian/changelog + cp "../${proj}-changelog" debian/changelog dch -v "${version}-${packageversion}~${dist}" "source package for PPA" dch -D "${dist}" -r "" debuild -d -S -sa -Zxz done cd .. for dist in ${distributions}; do - dput ${SIM} ${ppa} "${proj}_${version}-${packageversion}~${dist}_source.changes" + dput "${SIM}" ${ppa} "${proj}_${version}-${packageversion}~${dist}_source.changes" done cd "${BASEDIR}" done diff --git a/linux/scripts/package-build.inc.sh b/linux/scripts/package-build.inc.sh index 7134f6719f..39ea70f7d1 100644 --- a/linux/scripts/package-build.inc.sh +++ b/linux/scripts/package-build.inc.sh @@ -1,14 +1,14 @@ #!/bin/bash function checkPrerequisites() { - if [ "${UPLOAD}" == "yes" ]; then + if [ "${UPLOAD:=}" == "yes" ]; then SIM="" else SIM="-s" fi # Check the tier - if [[ -z "${TIER}" ]]; then + if [[ -z "${TIER:=}" ]]; then echo "TIER.md or \${TIER} must be set to (alpha, beta, stable) to use this script" exit 1 fi @@ -18,18 +18,15 @@ function checkPrerequisites() { exit 1 fi - if [ "${PROJECT}" != "" ]; then - projects="${PROJECT}" - else - projects="keyman" - fi + # shellcheck disable=SC2034 + projects="${PROJECT:=keyman}" } function downloadSource() { local packageDir packageDir=$1 - if [ "${proj}" == "keyman" ]; then + if [ "${proj:=}" == "keyman" ]; then cd "${BASEDIR}" || exit fi @@ -51,7 +48,7 @@ function downloadSource() { mv "${proj}"*.asc "${BASEDIR}/${packageDir}" rm "${proj}"*.debian.tar.xz cd "${BASEDIR}/${packageDir}" || exit - wget -N https://downloads.keyman.com/linux/${TIER}/${dirversion}/SHA256SUMS + wget -N "https://downloads.keyman.com/linux/${TIER}/${dirversion}/SHA256SUMS" sha256sum -c --ignore-missing SHA256SUMS |grep "${proj}" } -- GitLab From 03299c377ab250a1605686a81fce1f1c4b05d37d Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Mon, 8 May 2023 14:02:11 -0400 Subject: [PATCH 033/214] auto: increment master version to 17.0.103 --- HISTORY.md | 6 ++++++ VERSION.md | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index f5134cf0f6..274358c6a5 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,11 @@ # Keyman Version History +## 17.0.102 alpha 2023-05-08 + +* chore(linux): Build for Lunar on all platforms (#8713) +* fix(linux): Fix linux tests (#8510) +* chore(linux): Fix uploading to launchpad (#8720) + ## 17.0.101 alpha 2023-05-05 * chore(common): `set -eu` in build-utils.sh (#8698) diff --git a/VERSION.md b/VERSION.md index 2aea3204c5..8885a3f7c8 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.102 \ No newline at end of file +17.0.103 \ No newline at end of file -- GitLab From d36854e0faee97817c38d16a98503e9e9af620d0 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 9 May 2023 10:39:31 +0700 Subject: [PATCH 034/214] fix(mac): CONFIG not CONFIGURATION in build path Fixes an error in mac/build.sh, arising from work in #8698. Kinda proves that the `-u` flag was worth setting globally! --- mac/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mac/build.sh b/mac/build.sh index 5a16f00f11..5b6a3f525b 100755 --- a/mac/build.sh +++ b/mac/build.sh @@ -413,7 +413,7 @@ if $DO_KEYMANIM ; then if which sentry-cli >/dev/null; then cd "$KM4MIM_BASE_PATH" - sentry-cli upload-dif "build/${CONFIGURATION}" + sentry-cli upload-dif "build/$CONFIG" else builder_die "Error: sentry-cli not installed, download from https://github.com/getsentry/sentry-cli/releases" fi -- GitLab From 4838ba1ffe1b00232c0d0b5419e5fb03840c0b2f Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 9 May 2023 14:03:16 +0700 Subject: [PATCH 035/214] chore: rename kmc-keyboard to kmc-ldml Part of #8719. --- .../web/types/src/util/compiler-interfaces.ts | 6 +++--- core/src/ldml/C7532_ldml_updating.md | 18 +++++++++--------- developer/build.sh | 2 +- developer/src/Makefile | 6 +++--- developer/src/README.md | 2 +- developer/src/common/web/test-helpers/index.ts | 4 ++-- .../{kmc-keyboard => kmc-ldml}/.eslintrc.cjs | 0 .../src/{kmc-keyboard => kmc-ldml}/Makefile | 0 .../src/{kmc-keyboard => kmc-ldml}/build.sh | 2 +- .../{kmc-keyboard => kmc-ldml}/package.json | 4 ++-- .../src/compiler/compiler-options.ts | 0 .../src/compiler/compiler.ts | 0 .../src/compiler/disp.ts | 0 .../src/compiler/keymanweb-compiler.ts | 0 .../src/compiler/keys.ts | 0 .../src/compiler/layr.ts | 0 .../src/compiler/loca.ts | 0 .../src/compiler/messages.ts | 8 ++++---- .../src/compiler/meta.ts | 0 .../src/compiler/metadata-compiler.ts | 0 .../src/compiler/name.ts | 0 .../src/compiler/ordr.ts | 0 .../src/compiler/section-compiler.ts | 0 .../src/compiler/touch-layout-compiler.ts | 0 .../src/compiler/tran.ts | 0 .../src/compiler/visual-keyboard-compiler.ts | 0 .../src/compiler/vkey.ts | 0 .../src/{kmc-keyboard => kmc-ldml}/src/main.ts | 0 .../src/util/util.ts | 0 .../{kmc-keyboard => kmc-ldml}/test/README.md | 0 .../test/fixtures/basic-kvk.txt | 0 .../test/fixtures/basic-no-debug.js | 0 .../test/fixtures/basic.js | 0 .../test/fixtures/basic.txt | 0 .../test/fixtures/basic.xml | 0 .../test/fixtures/sections/bksp/minimal.xml | 0 .../test/fixtures/sections/disp/escaped.xml | 0 .../fixtures/sections/disp/invalid-dupto.xml | 0 .../test/fixtures/sections/disp/maximal.xml | 0 .../test/fixtures/sections/disp/minimal.xml | 0 .../fixtures/sections/disp/options-only.xml | 0 .../test/fixtures/sections/disp/typical.xml | 0 .../test/fixtures/sections/finl/minimal.xml | 0 .../test/fixtures/sections/keys/escaped.xml | 0 .../test/fixtures/sections/keys/escaped2.xml | 0 .../test/fixtures/sections/keys/gap-switch.xml | 0 .../test/fixtures/sections/keys/hardware.xml | 0 .../fixtures/sections/keys/hardware_iso.xml | 0 .../fixtures/sections/keys/hardware_us.xml | 0 .../sections/keys/invalid-bad-modifier.xml | 0 .../keys/invalid-hardware-too-many-keys.xml | 0 .../keys/invalid-hardware-too-many-rows.xml | 0 .../keys/invalid-key-missing-attrs.xml | 0 .../sections/keys/invalid-missing-flick.xml | 0 .../sections/keys/invalid-undefined-key.xml | 0 .../test/fixtures/sections/keys/maximal.xml | 0 .../test/fixtures/sections/keys/minimal.xml | 0 .../sections/layr/invalid-invalid-form.xml | 0 .../sections/layr/invalid-missing-hardware.xml | 0 .../sections/layr/invalid-missing-layer.xml | 0 .../sections/layr/invalid-missing-layer2.xml | 0 .../sections/layr/invalid-multi-hardware.xml | 0 .../fixtures/sections/loca/invalid-locale.xml | 0 .../test/fixtures/sections/loca/minimal.xml | 0 .../test/fixtures/sections/loca/multiple.xml | 0 .../sections/meta/invalid-normalization.xml | 0 .../sections/meta/invalid-version-1.0.xml | 0 .../sections/meta/invalid-version-v1.0.3.xml | 0 .../test/fixtures/sections/meta/maximal.xml | 0 .../test/fixtures/sections/meta/minimal.xml | 0 .../test/fixtures/sections/name/minimal.xml | 0 .../test/fixtures/sections/name/multiple.xml | 0 .../test/fixtures/sections/ordr/minimal.xml | 0 .../test/fixtures/sections/tran/minimal.xml | 0 .../sections/vkey/invalid-from-vkey.xml | 0 .../sections/vkey/invalid-repeated-vkey.xml | 0 .../fixtures/sections/vkey/invalid-to-vkey.xml | 0 .../test/fixtures/sections/vkey/minimal.xml | 0 .../test/fixtures/sections/vkey/redundant.xml | 0 .../fixtures/sections/vkey/same-target.xml | 0 .../test/fixtures/test-fr.json | 0 .../test/fixtures/test-fr.xml | 0 .../test/helpers/index.ts | 0 .../test/test-bksp.ts | 0 .../test/test-compiler-e2e.ts | 0 .../test/test-disp.ts | 0 .../test/test-finl.ts | 0 .../test/test-keymanweb-compiler.ts | 0 .../test/test-keys.ts | 0 .../test/test-layr.ts | 0 .../test/test-loca.ts | 0 .../test/test-messages.ts | 0 .../test/test-meta.ts | 0 .../test/test-metadata-compiler.ts | 0 .../test/test-name.ts | 0 .../test/test-ordr.ts | 0 .../test/test-testdata-e2e.ts | 0 .../test/test-tran.ts | 0 .../test/test-utils.ts | 0 .../test/test-virtual-key-constants.ts | 0 .../test/test-visual-keyboard-compiler-e2e.ts | 0 .../test/test-vkey.ts | 0 .../test/tsconfig.json | 0 .../{kmc-keyboard => kmc-ldml}/tsconfig.json | 0 developer/src/kmc-model-info/Makefile | 2 +- developer/src/kmc-model/Makefile | 2 +- developer/src/kmc-package/Makefile | 2 +- developer/src/kmc/Makefile | 2 +- developer/src/kmc/build.sh | 4 ++-- developer/src/kmc/package.json | 2 +- .../kmc/src/commands/buildTestData/index.ts | 2 +- developer/src/kmc/tsconfig.json | 6 ++++-- developer/src/test/auto/Makefile | 6 +++--- docs/npm-packages.md | 2 +- package.json | 2 +- tsconfig.esm.json | 4 ++-- 116 files changed, 45 insertions(+), 43 deletions(-) rename developer/src/{kmc-keyboard => kmc-ldml}/.eslintrc.cjs (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/Makefile (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/build.sh (98%) rename developer/src/{kmc-keyboard => kmc-ldml}/package.json (94%) rename developer/src/{kmc-keyboard => kmc-ldml}/src/compiler/compiler-options.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/src/compiler/compiler.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/src/compiler/disp.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/src/compiler/keymanweb-compiler.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/src/compiler/keys.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/src/compiler/layr.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/src/compiler/loca.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/src/compiler/messages.ts (98%) rename developer/src/{kmc-keyboard => kmc-ldml}/src/compiler/meta.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/src/compiler/metadata-compiler.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/src/compiler/name.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/src/compiler/ordr.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/src/compiler/section-compiler.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/src/compiler/touch-layout-compiler.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/src/compiler/tran.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/src/compiler/visual-keyboard-compiler.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/src/compiler/vkey.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/src/main.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/src/util/util.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/README.md (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/basic-kvk.txt (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/basic-no-debug.js (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/basic.js (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/basic.txt (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/basic.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/bksp/minimal.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/disp/escaped.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/disp/invalid-dupto.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/disp/maximal.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/disp/minimal.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/disp/options-only.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/disp/typical.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/finl/minimal.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/keys/escaped.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/keys/escaped2.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/keys/gap-switch.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/keys/hardware.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/keys/hardware_iso.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/keys/hardware_us.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/keys/invalid-bad-modifier.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/keys/invalid-hardware-too-many-keys.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/keys/invalid-hardware-too-many-rows.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/keys/invalid-key-missing-attrs.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/keys/invalid-missing-flick.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/keys/invalid-undefined-key.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/keys/maximal.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/keys/minimal.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/layr/invalid-invalid-form.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/layr/invalid-missing-hardware.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/layr/invalid-missing-layer.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/layr/invalid-missing-layer2.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/layr/invalid-multi-hardware.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/loca/invalid-locale.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/loca/minimal.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/loca/multiple.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/meta/invalid-normalization.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/meta/invalid-version-1.0.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/meta/invalid-version-v1.0.3.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/meta/maximal.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/meta/minimal.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/name/minimal.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/name/multiple.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/ordr/minimal.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/tran/minimal.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/vkey/invalid-from-vkey.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/vkey/invalid-repeated-vkey.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/vkey/invalid-to-vkey.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/vkey/minimal.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/vkey/redundant.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/sections/vkey/same-target.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/test-fr.json (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/fixtures/test-fr.xml (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/helpers/index.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/test-bksp.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/test-compiler-e2e.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/test-disp.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/test-finl.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/test-keymanweb-compiler.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/test-keys.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/test-layr.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/test-loca.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/test-messages.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/test-meta.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/test-metadata-compiler.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/test-name.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/test-ordr.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/test-testdata-e2e.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/test-tran.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/test-utils.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/test-virtual-key-constants.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/test-visual-keyboard-compiler-e2e.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/test-vkey.ts (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/test/tsconfig.json (100%) rename developer/src/{kmc-keyboard => kmc-ldml}/tsconfig.json (100%) diff --git a/common/web/types/src/util/compiler-interfaces.ts b/common/web/types/src/util/compiler-interfaces.ts index 55a3f9a77a..a58484298a 100644 --- a/common/web/types/src/util/compiler-interfaces.ts +++ b/common/web/types/src/util/compiler-interfaces.ts @@ -36,13 +36,13 @@ export function compilerErrorSeverityName(code: number): string { * Defines the error code ranges for various compilers. Once defined, these * ranges must not be changed as external modules may depend on specific error * codes. Individual errors are defined at a compiler level, for example, - * kmn-keyboard/src/compiler/messages.ts. + * kmc-ldml/src/compiler/messages.ts. */ export enum CompilerErrorNamespace { /** - * kmc-keyboard errors between 0x0000…0x0FFF + * kmc-ldml errors between 0x0000…0x0FFF */ - KeyboardCompiler = 0x0000, + LdmlKeyboardCompiler = 0x0000, /** * common/web/types errors between 0x1000…0x1FFF */ diff --git a/core/src/ldml/C7532_ldml_updating.md b/core/src/ldml/C7532_ldml_updating.md index 62f30ad4df..168d205cea 100644 --- a/core/src/ldml/C7532_ldml_updating.md +++ b/core/src/ldml/C7532_ldml_updating.md @@ -46,11 +46,11 @@ working on ‘layr’, using ‘disp’ as a model from https://github.com/keyma ## In-memory data: Phase 2 - first the compiler tests - - add a section in `developer/src/kmc-keyboard/test/fixtures/sections` if needed - - add a test case such as `developer/src/kmc-keyboard/test/test-key2.ts` + - add a section in `developer/src/kmc-ldml/test/fixtures/sections` if needed + - add a test case such as `developer/src/kmc-ldml/test/test-key2.ts` - add a compiler - - `developer/src/kmc-keyboard/compiler/key2.ts` - - link it in to `developer/src/kmc-keyboard/src/compiler/compiler.ts` + - `developer/src/kmc-ldml/compiler/key2.ts` + - link it in to `developer/src/kmc-ldml/src/compiler/compiler.ts` - add the import - add to `SECTION_COMPILERS` @@ -68,10 +68,10 @@ working on ‘layr’, using ‘disp’ as a model from https://github.com/keyma - Also note that restructure will happily ignore (write zeros for) any fields where the BUILDER_* fields don't match the COMP_PLUS_* fields. - update basic.xml and basic.txt - - Tweak `eveloper/src/kmc-keyboard/test/fixtures/basic.xml` as needed - - You can use `developer/src/kmc-keyboard/build.sh build-fixtures` which will generate these. The two .kmx files are supposed to match: if not, fix `basic.txt` or fix other bugs. - - `developer/src/kmc-keyboard/build/test/fixtures/basic-txt.kmx` - KMX generated from basic.txt. - - `developer/src/kmc-keyboard/build/test/fixtures/basic-xml.kmx` - KMX generated from basic.xml. - - `developer/src/kmc-keyboard/build/test/fixtures/basic-xml.kvk` - KVK generated from basic.xml. + - Tweak `eveloper/src/kmc-ldml/test/fixtures/basic.xml` as needed + - You can use `developer/src/kmc-ldml/build.sh build-fixtures` which will generate these. The two .kmx files are supposed to match: if not, fix `basic.txt` or fix other bugs. + - `developer/src/kmc-ldml/build/test/fixtures/basic-txt.kmx` - KMX generated from basic.txt. + - `developer/src/kmc-ldml/build/test/fixtures/basic-xml.kmx` - KMX generated from basic.xml. + - `developer/src/kmc-ldml/build/test/fixtures/basic-xml.kvk` - KVK generated from basic.xml. ## more to come diff --git a/developer/build.sh b/developer/build.sh index 07442bab54..76fc3c94a7 100755 --- a/developer/build.sh +++ b/developer/build.sh @@ -28,8 +28,8 @@ builder_describe \ build \ test \ ":kmcmplib=src/kmcmplib Compiler - .kmn compiler" \ - ":kmc-keyboard=src/kmc-keyboard Compiler - LDML Keyboard Module" \ ":kmc-kmn=src/kmc-kmn Compiler - .kmn wrapper Keyboard Module" \ + ":kmc-ldml=src/kmc-ldml Compiler - LDML Keyboard Module" \ ":kmc-model=src/kmc-model Compiler - Lexical Model Module" \ ":kmc-model-info=src/kmc-model-info Compiler - .model_info Module" \ ":kmc-package=src/kmc-package Compiler - Package Module" \ diff --git a/developer/src/Makefile b/developer/src/Makefile index c1ab53cce0..d4c6bd9384 100644 --- a/developer/src/Makefile +++ b/developer/src/Makefile @@ -69,12 +69,12 @@ server: .virtual cd $(DEVELOPER_ROOT)\src\server $(MAKE) $(TARGET) -kmc: kmc-keyboard kmc-kmn kmc-model kmc-model-info kmc-package +kmc: kmc-ldml kmc-kmn kmc-model kmc-model-info kmc-package cd $(DEVELOPER_ROOT)\src\kmc $(MAKE) $(TARGET) -kmc-keyboard: .virtual - cd $(DEVELOPER_ROOT)\src\kmc-keyboard +kmc-ldml: .virtual + cd $(DEVELOPER_ROOT)\src\kmc-ldml $(MAKE) $(TARGET) kmc-kmn: .virtual diff --git a/developer/src/README.md b/developer/src/README.md index e4de6c1328..95b33c36f4 100644 --- a/developer/src/README.md +++ b/developer/src/README.md @@ -70,7 +70,7 @@ details. node-based next generation compiler, hosts kmc, kmlmi, kmlmc, kmlmp -### src/kmc-keyboard - LDML Keyboard Compiler +### src/kmc-ldml - LDML Keyboard Compiler Next Generation keyboard compiler package - LDML keyboards only at present. Command line access through kmc. diff --git a/developer/src/common/web/test-helpers/index.ts b/developer/src/common/web/test-helpers/index.ts index 53c21ec590..e79271227e 100644 --- a/developer/src/common/web/test-helpers/index.ts +++ b/developer/src/common/web/test-helpers/index.ts @@ -3,9 +3,9 @@ import * as path from 'path'; import { CompilerEvent, CompilerCallbacks, CompilerSchema, CompilerPathCallbacks, CompilerFileSystemCallbacks } from '@keymanapp/common-types'; export { verifyCompilerMessagesObject } from './verifyCompilerMessagesObject.js'; -// TODO: schemas are only used by kmc-keyboard for now, so this works at this +// TODO: schemas are only used by kmc-ldml for now, so this works at this // time, but it's a little fragile if we need them elsewhere in the future -const SCHEMA_BASE = '../../../../kmc-keyboard/build/src/'; +const SCHEMA_BASE = '../../../../kmc-ldml/build/src/'; /** * A CompilerCallbacks implementation for testing diff --git a/developer/src/kmc-keyboard/.eslintrc.cjs b/developer/src/kmc-ldml/.eslintrc.cjs similarity index 100% rename from developer/src/kmc-keyboard/.eslintrc.cjs rename to developer/src/kmc-ldml/.eslintrc.cjs diff --git a/developer/src/kmc-keyboard/Makefile b/developer/src/kmc-ldml/Makefile similarity index 100% rename from developer/src/kmc-keyboard/Makefile rename to developer/src/kmc-ldml/Makefile diff --git a/developer/src/kmc-keyboard/build.sh b/developer/src/kmc-ldml/build.sh similarity index 98% rename from developer/src/kmc-keyboard/build.sh rename to developer/src/kmc-ldml/build.sh index edcb229e2a..71f146e835 100755 --- a/developer/src/kmc-keyboard/build.sh +++ b/developer/src/kmc-ldml/build.sh @@ -30,7 +30,7 @@ builder_describe "Build Keyman kmc Keyboard Compiler module" \ "--dry-run,-n don't actually publish, just dry run" builder_describe_outputs \ configure /node_modules \ - build /developer/src/kmc-keyboard/build/src/main.js + build /developer/src/kmc-ldml/build/src/main.js builder_parse "$@" diff --git a/developer/src/kmc-keyboard/package.json b/developer/src/kmc-ldml/package.json similarity index 94% rename from developer/src/kmc-keyboard/package.json rename to developer/src/kmc-ldml/package.json index 829acf29f8..fda0b44272 100644 --- a/developer/src/kmc-keyboard/package.json +++ b/developer/src/kmc-ldml/package.json @@ -1,6 +1,6 @@ { - "name": "@keymanapp/kmc-keyboard", - "description": "Keyman Developer keyboard compiler", + "name": "@keymanapp/kmc-ldml", + "description": "Keyman Developer LDML keyboard compiler", "keywords": [ "keyboard", "keyman", diff --git a/developer/src/kmc-keyboard/src/compiler/compiler-options.ts b/developer/src/kmc-ldml/src/compiler/compiler-options.ts similarity index 100% rename from developer/src/kmc-keyboard/src/compiler/compiler-options.ts rename to developer/src/kmc-ldml/src/compiler/compiler-options.ts diff --git a/developer/src/kmc-keyboard/src/compiler/compiler.ts b/developer/src/kmc-ldml/src/compiler/compiler.ts similarity index 100% rename from developer/src/kmc-keyboard/src/compiler/compiler.ts rename to developer/src/kmc-ldml/src/compiler/compiler.ts diff --git a/developer/src/kmc-keyboard/src/compiler/disp.ts b/developer/src/kmc-ldml/src/compiler/disp.ts similarity index 100% rename from developer/src/kmc-keyboard/src/compiler/disp.ts rename to developer/src/kmc-ldml/src/compiler/disp.ts diff --git a/developer/src/kmc-keyboard/src/compiler/keymanweb-compiler.ts b/developer/src/kmc-ldml/src/compiler/keymanweb-compiler.ts similarity index 100% rename from developer/src/kmc-keyboard/src/compiler/keymanweb-compiler.ts rename to developer/src/kmc-ldml/src/compiler/keymanweb-compiler.ts diff --git a/developer/src/kmc-keyboard/src/compiler/keys.ts b/developer/src/kmc-ldml/src/compiler/keys.ts similarity index 100% rename from developer/src/kmc-keyboard/src/compiler/keys.ts rename to developer/src/kmc-ldml/src/compiler/keys.ts diff --git a/developer/src/kmc-keyboard/src/compiler/layr.ts b/developer/src/kmc-ldml/src/compiler/layr.ts similarity index 100% rename from developer/src/kmc-keyboard/src/compiler/layr.ts rename to developer/src/kmc-ldml/src/compiler/layr.ts diff --git a/developer/src/kmc-keyboard/src/compiler/loca.ts b/developer/src/kmc-ldml/src/compiler/loca.ts similarity index 100% rename from developer/src/kmc-keyboard/src/compiler/loca.ts rename to developer/src/kmc-ldml/src/compiler/loca.ts diff --git a/developer/src/kmc-keyboard/src/compiler/messages.ts b/developer/src/kmc-ldml/src/compiler/messages.ts similarity index 98% rename from developer/src/kmc-keyboard/src/compiler/messages.ts rename to developer/src/kmc-ldml/src/compiler/messages.ts index 610f7732e7..32eb943a68 100644 --- a/developer/src/kmc-keyboard/src/compiler/messages.ts +++ b/developer/src/kmc-ldml/src/compiler/messages.ts @@ -1,10 +1,10 @@ import { CompilerErrorNamespace, CompilerErrorSeverity, CompilerMessageSpec as m } from "@keymanapp/common-types"; -const SevInfo = CompilerErrorSeverity.Info | CompilerErrorNamespace.KeyboardCompiler; -const SevHint = CompilerErrorSeverity.Hint | CompilerErrorNamespace.KeyboardCompiler; +const SevInfo = CompilerErrorSeverity.Info | CompilerErrorNamespace.LdmlKeyboardCompiler; +const SevHint = CompilerErrorSeverity.Hint | CompilerErrorNamespace.LdmlKeyboardCompiler; // const SevWarn = CompilerErrorSeverity.Warn | CompilerErrorNamespace.KeyboardCompiler; -const SevError = CompilerErrorSeverity.Error | CompilerErrorNamespace.KeyboardCompiler; -const SevFatal = CompilerErrorSeverity.Fatal | CompilerErrorNamespace.KeyboardCompiler; +const SevError = CompilerErrorSeverity.Error | CompilerErrorNamespace.LdmlKeyboardCompiler; +const SevFatal = CompilerErrorSeverity.Fatal | CompilerErrorNamespace.LdmlKeyboardCompiler; export class CompilerMessages { static Error_InvalidNormalization = (o:{form: string}) => m(this.ERROR_InvalidNormalization, `Invalid normalization form '${o.form}`); diff --git a/developer/src/kmc-keyboard/src/compiler/meta.ts b/developer/src/kmc-ldml/src/compiler/meta.ts similarity index 100% rename from developer/src/kmc-keyboard/src/compiler/meta.ts rename to developer/src/kmc-ldml/src/compiler/meta.ts diff --git a/developer/src/kmc-keyboard/src/compiler/metadata-compiler.ts b/developer/src/kmc-ldml/src/compiler/metadata-compiler.ts similarity index 100% rename from developer/src/kmc-keyboard/src/compiler/metadata-compiler.ts rename to developer/src/kmc-ldml/src/compiler/metadata-compiler.ts diff --git a/developer/src/kmc-keyboard/src/compiler/name.ts b/developer/src/kmc-ldml/src/compiler/name.ts similarity index 100% rename from developer/src/kmc-keyboard/src/compiler/name.ts rename to developer/src/kmc-ldml/src/compiler/name.ts diff --git a/developer/src/kmc-keyboard/src/compiler/ordr.ts b/developer/src/kmc-ldml/src/compiler/ordr.ts similarity index 100% rename from developer/src/kmc-keyboard/src/compiler/ordr.ts rename to developer/src/kmc-ldml/src/compiler/ordr.ts diff --git a/developer/src/kmc-keyboard/src/compiler/section-compiler.ts b/developer/src/kmc-ldml/src/compiler/section-compiler.ts similarity index 100% rename from developer/src/kmc-keyboard/src/compiler/section-compiler.ts rename to developer/src/kmc-ldml/src/compiler/section-compiler.ts diff --git a/developer/src/kmc-keyboard/src/compiler/touch-layout-compiler.ts b/developer/src/kmc-ldml/src/compiler/touch-layout-compiler.ts similarity index 100% rename from developer/src/kmc-keyboard/src/compiler/touch-layout-compiler.ts rename to developer/src/kmc-ldml/src/compiler/touch-layout-compiler.ts diff --git a/developer/src/kmc-keyboard/src/compiler/tran.ts b/developer/src/kmc-ldml/src/compiler/tran.ts similarity index 100% rename from developer/src/kmc-keyboard/src/compiler/tran.ts rename to developer/src/kmc-ldml/src/compiler/tran.ts diff --git a/developer/src/kmc-keyboard/src/compiler/visual-keyboard-compiler.ts b/developer/src/kmc-ldml/src/compiler/visual-keyboard-compiler.ts similarity index 100% rename from developer/src/kmc-keyboard/src/compiler/visual-keyboard-compiler.ts rename to developer/src/kmc-ldml/src/compiler/visual-keyboard-compiler.ts diff --git a/developer/src/kmc-keyboard/src/compiler/vkey.ts b/developer/src/kmc-ldml/src/compiler/vkey.ts similarity index 100% rename from developer/src/kmc-keyboard/src/compiler/vkey.ts rename to developer/src/kmc-ldml/src/compiler/vkey.ts diff --git a/developer/src/kmc-keyboard/src/main.ts b/developer/src/kmc-ldml/src/main.ts similarity index 100% rename from developer/src/kmc-keyboard/src/main.ts rename to developer/src/kmc-ldml/src/main.ts diff --git a/developer/src/kmc-keyboard/src/util/util.ts b/developer/src/kmc-ldml/src/util/util.ts similarity index 100% rename from developer/src/kmc-keyboard/src/util/util.ts rename to developer/src/kmc-ldml/src/util/util.ts diff --git a/developer/src/kmc-keyboard/test/README.md b/developer/src/kmc-ldml/test/README.md similarity index 100% rename from developer/src/kmc-keyboard/test/README.md rename to developer/src/kmc-ldml/test/README.md diff --git a/developer/src/kmc-keyboard/test/fixtures/basic-kvk.txt b/developer/src/kmc-ldml/test/fixtures/basic-kvk.txt similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/basic-kvk.txt rename to developer/src/kmc-ldml/test/fixtures/basic-kvk.txt diff --git a/developer/src/kmc-keyboard/test/fixtures/basic-no-debug.js b/developer/src/kmc-ldml/test/fixtures/basic-no-debug.js similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/basic-no-debug.js rename to developer/src/kmc-ldml/test/fixtures/basic-no-debug.js diff --git a/developer/src/kmc-keyboard/test/fixtures/basic.js b/developer/src/kmc-ldml/test/fixtures/basic.js similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/basic.js rename to developer/src/kmc-ldml/test/fixtures/basic.js diff --git a/developer/src/kmc-keyboard/test/fixtures/basic.txt b/developer/src/kmc-ldml/test/fixtures/basic.txt similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/basic.txt rename to developer/src/kmc-ldml/test/fixtures/basic.txt diff --git a/developer/src/kmc-keyboard/test/fixtures/basic.xml b/developer/src/kmc-ldml/test/fixtures/basic.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/basic.xml rename to developer/src/kmc-ldml/test/fixtures/basic.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/bksp/minimal.xml b/developer/src/kmc-ldml/test/fixtures/sections/bksp/minimal.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/bksp/minimal.xml rename to developer/src/kmc-ldml/test/fixtures/sections/bksp/minimal.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/disp/escaped.xml b/developer/src/kmc-ldml/test/fixtures/sections/disp/escaped.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/disp/escaped.xml rename to developer/src/kmc-ldml/test/fixtures/sections/disp/escaped.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/disp/invalid-dupto.xml b/developer/src/kmc-ldml/test/fixtures/sections/disp/invalid-dupto.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/disp/invalid-dupto.xml rename to developer/src/kmc-ldml/test/fixtures/sections/disp/invalid-dupto.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/disp/maximal.xml b/developer/src/kmc-ldml/test/fixtures/sections/disp/maximal.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/disp/maximal.xml rename to developer/src/kmc-ldml/test/fixtures/sections/disp/maximal.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/disp/minimal.xml b/developer/src/kmc-ldml/test/fixtures/sections/disp/minimal.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/disp/minimal.xml rename to developer/src/kmc-ldml/test/fixtures/sections/disp/minimal.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/disp/options-only.xml b/developer/src/kmc-ldml/test/fixtures/sections/disp/options-only.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/disp/options-only.xml rename to developer/src/kmc-ldml/test/fixtures/sections/disp/options-only.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/disp/typical.xml b/developer/src/kmc-ldml/test/fixtures/sections/disp/typical.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/disp/typical.xml rename to developer/src/kmc-ldml/test/fixtures/sections/disp/typical.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/finl/minimal.xml b/developer/src/kmc-ldml/test/fixtures/sections/finl/minimal.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/finl/minimal.xml rename to developer/src/kmc-ldml/test/fixtures/sections/finl/minimal.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/keys/escaped.xml b/developer/src/kmc-ldml/test/fixtures/sections/keys/escaped.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/keys/escaped.xml rename to developer/src/kmc-ldml/test/fixtures/sections/keys/escaped.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/keys/escaped2.xml b/developer/src/kmc-ldml/test/fixtures/sections/keys/escaped2.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/keys/escaped2.xml rename to developer/src/kmc-ldml/test/fixtures/sections/keys/escaped2.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/keys/gap-switch.xml b/developer/src/kmc-ldml/test/fixtures/sections/keys/gap-switch.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/keys/gap-switch.xml rename to developer/src/kmc-ldml/test/fixtures/sections/keys/gap-switch.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/keys/hardware.xml b/developer/src/kmc-ldml/test/fixtures/sections/keys/hardware.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/keys/hardware.xml rename to developer/src/kmc-ldml/test/fixtures/sections/keys/hardware.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/keys/hardware_iso.xml b/developer/src/kmc-ldml/test/fixtures/sections/keys/hardware_iso.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/keys/hardware_iso.xml rename to developer/src/kmc-ldml/test/fixtures/sections/keys/hardware_iso.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/keys/hardware_us.xml b/developer/src/kmc-ldml/test/fixtures/sections/keys/hardware_us.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/keys/hardware_us.xml rename to developer/src/kmc-ldml/test/fixtures/sections/keys/hardware_us.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/keys/invalid-bad-modifier.xml b/developer/src/kmc-ldml/test/fixtures/sections/keys/invalid-bad-modifier.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/keys/invalid-bad-modifier.xml rename to developer/src/kmc-ldml/test/fixtures/sections/keys/invalid-bad-modifier.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/keys/invalid-hardware-too-many-keys.xml b/developer/src/kmc-ldml/test/fixtures/sections/keys/invalid-hardware-too-many-keys.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/keys/invalid-hardware-too-many-keys.xml rename to developer/src/kmc-ldml/test/fixtures/sections/keys/invalid-hardware-too-many-keys.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/keys/invalid-hardware-too-many-rows.xml b/developer/src/kmc-ldml/test/fixtures/sections/keys/invalid-hardware-too-many-rows.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/keys/invalid-hardware-too-many-rows.xml rename to developer/src/kmc-ldml/test/fixtures/sections/keys/invalid-hardware-too-many-rows.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/keys/invalid-key-missing-attrs.xml b/developer/src/kmc-ldml/test/fixtures/sections/keys/invalid-key-missing-attrs.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/keys/invalid-key-missing-attrs.xml rename to developer/src/kmc-ldml/test/fixtures/sections/keys/invalid-key-missing-attrs.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/keys/invalid-missing-flick.xml b/developer/src/kmc-ldml/test/fixtures/sections/keys/invalid-missing-flick.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/keys/invalid-missing-flick.xml rename to developer/src/kmc-ldml/test/fixtures/sections/keys/invalid-missing-flick.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/keys/invalid-undefined-key.xml b/developer/src/kmc-ldml/test/fixtures/sections/keys/invalid-undefined-key.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/keys/invalid-undefined-key.xml rename to developer/src/kmc-ldml/test/fixtures/sections/keys/invalid-undefined-key.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/keys/maximal.xml b/developer/src/kmc-ldml/test/fixtures/sections/keys/maximal.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/keys/maximal.xml rename to developer/src/kmc-ldml/test/fixtures/sections/keys/maximal.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/keys/minimal.xml b/developer/src/kmc-ldml/test/fixtures/sections/keys/minimal.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/keys/minimal.xml rename to developer/src/kmc-ldml/test/fixtures/sections/keys/minimal.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/layr/invalid-invalid-form.xml b/developer/src/kmc-ldml/test/fixtures/sections/layr/invalid-invalid-form.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/layr/invalid-invalid-form.xml rename to developer/src/kmc-ldml/test/fixtures/sections/layr/invalid-invalid-form.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/layr/invalid-missing-hardware.xml b/developer/src/kmc-ldml/test/fixtures/sections/layr/invalid-missing-hardware.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/layr/invalid-missing-hardware.xml rename to developer/src/kmc-ldml/test/fixtures/sections/layr/invalid-missing-hardware.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/layr/invalid-missing-layer.xml b/developer/src/kmc-ldml/test/fixtures/sections/layr/invalid-missing-layer.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/layr/invalid-missing-layer.xml rename to developer/src/kmc-ldml/test/fixtures/sections/layr/invalid-missing-layer.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/layr/invalid-missing-layer2.xml b/developer/src/kmc-ldml/test/fixtures/sections/layr/invalid-missing-layer2.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/layr/invalid-missing-layer2.xml rename to developer/src/kmc-ldml/test/fixtures/sections/layr/invalid-missing-layer2.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/layr/invalid-multi-hardware.xml b/developer/src/kmc-ldml/test/fixtures/sections/layr/invalid-multi-hardware.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/layr/invalid-multi-hardware.xml rename to developer/src/kmc-ldml/test/fixtures/sections/layr/invalid-multi-hardware.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/loca/invalid-locale.xml b/developer/src/kmc-ldml/test/fixtures/sections/loca/invalid-locale.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/loca/invalid-locale.xml rename to developer/src/kmc-ldml/test/fixtures/sections/loca/invalid-locale.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/loca/minimal.xml b/developer/src/kmc-ldml/test/fixtures/sections/loca/minimal.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/loca/minimal.xml rename to developer/src/kmc-ldml/test/fixtures/sections/loca/minimal.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/loca/multiple.xml b/developer/src/kmc-ldml/test/fixtures/sections/loca/multiple.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/loca/multiple.xml rename to developer/src/kmc-ldml/test/fixtures/sections/loca/multiple.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/meta/invalid-normalization.xml b/developer/src/kmc-ldml/test/fixtures/sections/meta/invalid-normalization.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/meta/invalid-normalization.xml rename to developer/src/kmc-ldml/test/fixtures/sections/meta/invalid-normalization.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/meta/invalid-version-1.0.xml b/developer/src/kmc-ldml/test/fixtures/sections/meta/invalid-version-1.0.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/meta/invalid-version-1.0.xml rename to developer/src/kmc-ldml/test/fixtures/sections/meta/invalid-version-1.0.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/meta/invalid-version-v1.0.3.xml b/developer/src/kmc-ldml/test/fixtures/sections/meta/invalid-version-v1.0.3.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/meta/invalid-version-v1.0.3.xml rename to developer/src/kmc-ldml/test/fixtures/sections/meta/invalid-version-v1.0.3.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/meta/maximal.xml b/developer/src/kmc-ldml/test/fixtures/sections/meta/maximal.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/meta/maximal.xml rename to developer/src/kmc-ldml/test/fixtures/sections/meta/maximal.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/meta/minimal.xml b/developer/src/kmc-ldml/test/fixtures/sections/meta/minimal.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/meta/minimal.xml rename to developer/src/kmc-ldml/test/fixtures/sections/meta/minimal.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/name/minimal.xml b/developer/src/kmc-ldml/test/fixtures/sections/name/minimal.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/name/minimal.xml rename to developer/src/kmc-ldml/test/fixtures/sections/name/minimal.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/name/multiple.xml b/developer/src/kmc-ldml/test/fixtures/sections/name/multiple.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/name/multiple.xml rename to developer/src/kmc-ldml/test/fixtures/sections/name/multiple.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/ordr/minimal.xml b/developer/src/kmc-ldml/test/fixtures/sections/ordr/minimal.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/ordr/minimal.xml rename to developer/src/kmc-ldml/test/fixtures/sections/ordr/minimal.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/tran/minimal.xml b/developer/src/kmc-ldml/test/fixtures/sections/tran/minimal.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/tran/minimal.xml rename to developer/src/kmc-ldml/test/fixtures/sections/tran/minimal.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/vkey/invalid-from-vkey.xml b/developer/src/kmc-ldml/test/fixtures/sections/vkey/invalid-from-vkey.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/vkey/invalid-from-vkey.xml rename to developer/src/kmc-ldml/test/fixtures/sections/vkey/invalid-from-vkey.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/vkey/invalid-repeated-vkey.xml b/developer/src/kmc-ldml/test/fixtures/sections/vkey/invalid-repeated-vkey.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/vkey/invalid-repeated-vkey.xml rename to developer/src/kmc-ldml/test/fixtures/sections/vkey/invalid-repeated-vkey.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/vkey/invalid-to-vkey.xml b/developer/src/kmc-ldml/test/fixtures/sections/vkey/invalid-to-vkey.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/vkey/invalid-to-vkey.xml rename to developer/src/kmc-ldml/test/fixtures/sections/vkey/invalid-to-vkey.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/vkey/minimal.xml b/developer/src/kmc-ldml/test/fixtures/sections/vkey/minimal.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/vkey/minimal.xml rename to developer/src/kmc-ldml/test/fixtures/sections/vkey/minimal.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/vkey/redundant.xml b/developer/src/kmc-ldml/test/fixtures/sections/vkey/redundant.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/vkey/redundant.xml rename to developer/src/kmc-ldml/test/fixtures/sections/vkey/redundant.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/sections/vkey/same-target.xml b/developer/src/kmc-ldml/test/fixtures/sections/vkey/same-target.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/sections/vkey/same-target.xml rename to developer/src/kmc-ldml/test/fixtures/sections/vkey/same-target.xml diff --git a/developer/src/kmc-keyboard/test/fixtures/test-fr.json b/developer/src/kmc-ldml/test/fixtures/test-fr.json similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/test-fr.json rename to developer/src/kmc-ldml/test/fixtures/test-fr.json diff --git a/developer/src/kmc-keyboard/test/fixtures/test-fr.xml b/developer/src/kmc-ldml/test/fixtures/test-fr.xml similarity index 100% rename from developer/src/kmc-keyboard/test/fixtures/test-fr.xml rename to developer/src/kmc-ldml/test/fixtures/test-fr.xml diff --git a/developer/src/kmc-keyboard/test/helpers/index.ts b/developer/src/kmc-ldml/test/helpers/index.ts similarity index 100% rename from developer/src/kmc-keyboard/test/helpers/index.ts rename to developer/src/kmc-ldml/test/helpers/index.ts diff --git a/developer/src/kmc-keyboard/test/test-bksp.ts b/developer/src/kmc-ldml/test/test-bksp.ts similarity index 100% rename from developer/src/kmc-keyboard/test/test-bksp.ts rename to developer/src/kmc-ldml/test/test-bksp.ts diff --git a/developer/src/kmc-keyboard/test/test-compiler-e2e.ts b/developer/src/kmc-ldml/test/test-compiler-e2e.ts similarity index 100% rename from developer/src/kmc-keyboard/test/test-compiler-e2e.ts rename to developer/src/kmc-ldml/test/test-compiler-e2e.ts diff --git a/developer/src/kmc-keyboard/test/test-disp.ts b/developer/src/kmc-ldml/test/test-disp.ts similarity index 100% rename from developer/src/kmc-keyboard/test/test-disp.ts rename to developer/src/kmc-ldml/test/test-disp.ts diff --git a/developer/src/kmc-keyboard/test/test-finl.ts b/developer/src/kmc-ldml/test/test-finl.ts similarity index 100% rename from developer/src/kmc-keyboard/test/test-finl.ts rename to developer/src/kmc-ldml/test/test-finl.ts diff --git a/developer/src/kmc-keyboard/test/test-keymanweb-compiler.ts b/developer/src/kmc-ldml/test/test-keymanweb-compiler.ts similarity index 100% rename from developer/src/kmc-keyboard/test/test-keymanweb-compiler.ts rename to developer/src/kmc-ldml/test/test-keymanweb-compiler.ts diff --git a/developer/src/kmc-keyboard/test/test-keys.ts b/developer/src/kmc-ldml/test/test-keys.ts similarity index 100% rename from developer/src/kmc-keyboard/test/test-keys.ts rename to developer/src/kmc-ldml/test/test-keys.ts diff --git a/developer/src/kmc-keyboard/test/test-layr.ts b/developer/src/kmc-ldml/test/test-layr.ts similarity index 100% rename from developer/src/kmc-keyboard/test/test-layr.ts rename to developer/src/kmc-ldml/test/test-layr.ts diff --git a/developer/src/kmc-keyboard/test/test-loca.ts b/developer/src/kmc-ldml/test/test-loca.ts similarity index 100% rename from developer/src/kmc-keyboard/test/test-loca.ts rename to developer/src/kmc-ldml/test/test-loca.ts diff --git a/developer/src/kmc-keyboard/test/test-messages.ts b/developer/src/kmc-ldml/test/test-messages.ts similarity index 100% rename from developer/src/kmc-keyboard/test/test-messages.ts rename to developer/src/kmc-ldml/test/test-messages.ts diff --git a/developer/src/kmc-keyboard/test/test-meta.ts b/developer/src/kmc-ldml/test/test-meta.ts similarity index 100% rename from developer/src/kmc-keyboard/test/test-meta.ts rename to developer/src/kmc-ldml/test/test-meta.ts diff --git a/developer/src/kmc-keyboard/test/test-metadata-compiler.ts b/developer/src/kmc-ldml/test/test-metadata-compiler.ts similarity index 100% rename from developer/src/kmc-keyboard/test/test-metadata-compiler.ts rename to developer/src/kmc-ldml/test/test-metadata-compiler.ts diff --git a/developer/src/kmc-keyboard/test/test-name.ts b/developer/src/kmc-ldml/test/test-name.ts similarity index 100% rename from developer/src/kmc-keyboard/test/test-name.ts rename to developer/src/kmc-ldml/test/test-name.ts diff --git a/developer/src/kmc-keyboard/test/test-ordr.ts b/developer/src/kmc-ldml/test/test-ordr.ts similarity index 100% rename from developer/src/kmc-keyboard/test/test-ordr.ts rename to developer/src/kmc-ldml/test/test-ordr.ts diff --git a/developer/src/kmc-keyboard/test/test-testdata-e2e.ts b/developer/src/kmc-ldml/test/test-testdata-e2e.ts similarity index 100% rename from developer/src/kmc-keyboard/test/test-testdata-e2e.ts rename to developer/src/kmc-ldml/test/test-testdata-e2e.ts diff --git a/developer/src/kmc-keyboard/test/test-tran.ts b/developer/src/kmc-ldml/test/test-tran.ts similarity index 100% rename from developer/src/kmc-keyboard/test/test-tran.ts rename to developer/src/kmc-ldml/test/test-tran.ts diff --git a/developer/src/kmc-keyboard/test/test-utils.ts b/developer/src/kmc-ldml/test/test-utils.ts similarity index 100% rename from developer/src/kmc-keyboard/test/test-utils.ts rename to developer/src/kmc-ldml/test/test-utils.ts diff --git a/developer/src/kmc-keyboard/test/test-virtual-key-constants.ts b/developer/src/kmc-ldml/test/test-virtual-key-constants.ts similarity index 100% rename from developer/src/kmc-keyboard/test/test-virtual-key-constants.ts rename to developer/src/kmc-ldml/test/test-virtual-key-constants.ts diff --git a/developer/src/kmc-keyboard/test/test-visual-keyboard-compiler-e2e.ts b/developer/src/kmc-ldml/test/test-visual-keyboard-compiler-e2e.ts similarity index 100% rename from developer/src/kmc-keyboard/test/test-visual-keyboard-compiler-e2e.ts rename to developer/src/kmc-ldml/test/test-visual-keyboard-compiler-e2e.ts diff --git a/developer/src/kmc-keyboard/test/test-vkey.ts b/developer/src/kmc-ldml/test/test-vkey.ts similarity index 100% rename from developer/src/kmc-keyboard/test/test-vkey.ts rename to developer/src/kmc-ldml/test/test-vkey.ts diff --git a/developer/src/kmc-keyboard/test/tsconfig.json b/developer/src/kmc-ldml/test/tsconfig.json similarity index 100% rename from developer/src/kmc-keyboard/test/tsconfig.json rename to developer/src/kmc-ldml/test/tsconfig.json diff --git a/developer/src/kmc-keyboard/tsconfig.json b/developer/src/kmc-ldml/tsconfig.json similarity index 100% rename from developer/src/kmc-keyboard/tsconfig.json rename to developer/src/kmc-ldml/tsconfig.json diff --git a/developer/src/kmc-model-info/Makefile b/developer/src/kmc-model-info/Makefile index f3e73efd12..878d77f184 100644 --- a/developer/src/kmc-model-info/Makefile +++ b/developer/src/kmc-model-info/Makefile @@ -4,7 +4,7 @@ !include ..\Defines.mak -# We don't depend on configure here because kmc-keyboard does that already +# We don't depend on configure here because kmc-ldml does that already build: .virtual $(GIT_BASH_FOR_KEYMAN) build.sh build diff --git a/developer/src/kmc-model/Makefile b/developer/src/kmc-model/Makefile index 353d923bd4..b41bbe8184 100644 --- a/developer/src/kmc-model/Makefile +++ b/developer/src/kmc-model/Makefile @@ -4,7 +4,7 @@ !include ..\Defines.mak -# We don't depend on configure here because kmc-keyboard does that already +# We don't depend on configure here because kmc-ldml does that already build: .virtual $(GIT_BASH_FOR_KEYMAN) build.sh build diff --git a/developer/src/kmc-package/Makefile b/developer/src/kmc-package/Makefile index 02bf07dc02..0a5ba6a1c1 100644 --- a/developer/src/kmc-package/Makefile +++ b/developer/src/kmc-package/Makefile @@ -4,7 +4,7 @@ !include ..\Defines.mak -# We don't depend on configure here because kmc-keyboard does that already +# We don't depend on configure here because kmc-ldml does that already build: .virtual $(GIT_BASH_FOR_KEYMAN) build.sh build diff --git a/developer/src/kmc/Makefile b/developer/src/kmc/Makefile index 8e8dc7d5f3..1078ab1a67 100644 --- a/developer/src/kmc/Makefile +++ b/developer/src/kmc/Makefile @@ -4,7 +4,7 @@ !include ..\Defines.mak -# We don't depend on configure here because kmc-keyboard does that already, +# We don't depend on configure here because kmc-ldml does that already, # called from parent folder Makefile build: .virtual $(GIT_BASH_FOR_KEYMAN) build.sh build diff --git a/developer/src/kmc/build.sh b/developer/src/kmc/build.sh index b6022ff6cf..61ccd3bdca 100755 --- a/developer/src/kmc/build.sh +++ b/developer/src/kmc/build.sh @@ -20,8 +20,8 @@ builder_describe "Build Keyman Keyboard Compiler kmc" \ "@/common/include" \ "@/common/web/keyman-version" \ "@/common/web/types" \ - "@/developer/src/kmc-keyboard" \ "@/developer/src/kmc-kmn" \ + "@/developer/src/kmc-ldml" \ "@/developer/src/kmc-model" \ "@/developer/src/kmc-model-info" \ "@/developer/src/kmc-package" \ @@ -112,8 +112,8 @@ readonly PACKAGES=( common/web/types common/models/types core/include/ldml - developer/src/kmc-keyboard developer/src/kmc-kmn + developer/src/kmc-ldml developer/src/kmc-model developer/src/kmc-model-info developer/src/kmc-package diff --git a/developer/src/kmc/package.json b/developer/src/kmc/package.json index 5adeb15691..695ebc96e3 100644 --- a/developer/src/kmc/package.json +++ b/developer/src/kmc/package.json @@ -39,8 +39,8 @@ "dependencies": { "@keymanapp/keyman-version": "*", "@keymanapp/common-types": "*", - "@keymanapp/kmc-keyboard": "*", "@keymanapp/kmc-kmn": "*", + "@keymanapp/kmc-ldml": "*", "@keymanapp/kmc-model": "*", "@keymanapp/kmc-model-info": "*", "@keymanapp/kmc-package": "*", diff --git a/developer/src/kmc/src/commands/buildTestData/index.ts b/developer/src/kmc/src/commands/buildTestData/index.ts index 2341b11082..89674efbef 100644 --- a/developer/src/kmc/src/commands/buildTestData/index.ts +++ b/developer/src/kmc/src/commands/buildTestData/index.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import * as kmc from '@keymanapp/kmc-keyboard'; +import * as kmc from '@keymanapp/kmc-ldml'; import { CompilerCallbacks, LDMLKeyboardTestDataXMLSourceFile } from '@keymanapp/common-types'; import { NodeCompilerCallbacks } from '../../messages/NodeCompilerCallbacks.js'; diff --git a/developer/src/kmc/tsconfig.json b/developer/src/kmc/tsconfig.json index 41d2ab3428..9b6eb601ac 100644 --- a/developer/src/kmc/tsconfig.json +++ b/developer/src/kmc/tsconfig.json @@ -7,7 +7,8 @@ "baseUrl": ".", "paths": { "@keymanapp/common-types": [ "../../../common/web/types/src/main" ], - "@keymanapp/kmc-keyboard": [ "../kmc-keyboard/src/main" ], + "@keymanapp/kmc-kmn": [ "../kmc-kmn/src/main" ], + "@keymanapp/kmc-ldml": [ "../kmc-ldml/src/main" ], "@keymanapp/kmc-model": [ "../kmc-model/src/main" ], "@keymanapp/kmc-model-info": [ "../kmc-model-info/src/model-info-compiler" ], "@keymanapp/kmc-package": [ "../kmc-package/src/kmp-compiler" ], @@ -19,7 +20,8 @@ "references": [ { "path": "../../../common/web/keyman-version/tsconfig.esm.json" }, { "path": "../../../common/web/types" }, - { "path": "../kmc-keyboard" }, + { "path": "../kmc-kmn" }, + { "path": "../kmc-ldml" }, { "path": "../kmc-model" }, { "path": "../kmc-model-info" }, { "path": "../kmc-package" }, diff --git a/developer/src/test/auto/Makefile b/developer/src/test/auto/Makefile index 635d933bd1..ebbdf29016 100644 --- a/developer/src/test/auto/Makefile +++ b/developer/src/test/auto/Makefile @@ -26,7 +26,7 @@ developer-tests: \ model-ts-parser \ package-info \ kmc \ - kmc-keyboard \ + kmc-ldml \ kmc-model \ kmc-model-info \ kmc-package @@ -87,8 +87,8 @@ kmc: .virtual cd $(DEVELOPER_ROOT)\src\kmc $(MAKE) $(TARGET) -kmc-keyboard: .virtual - cd $(DEVELOPER_ROOT)\src\kmc-keyboard +kmc-ldml: .virtual + cd $(DEVELOPER_ROOT)\src\kmc-ldml $(MAKE) $(TARGET) kmc-model: .virtual diff --git a/docs/npm-packages.md b/docs/npm-packages.md index 57fbfb839f..040a6e11cc 100644 --- a/docs/npm-packages.md +++ b/docs/npm-packages.md @@ -13,8 +13,8 @@ Packages are **never** published from a developer's machine. * `@keymanapp/common-types` -- located at `common/web/types` * `@keymanapp/keyman-version` -- located at `common/web/keyman-version` * `@keymanapp/kmc` -- located at `developer/src/kmc` -* `@keymanapp/kmc-keyboard` -- located at `developer/src/kmc-keyboard` * `@keymanapp/kmc-kmn` -- located at `developer/src/kmc-kmn` +* `@keymanapp/kmc-ldml` -- located at `developer/src/kmc-ldml` * `@keymanapp/kmc-model` -- located at `developer/src/kmc-model` * `@keymanapp/kmc-model-info` -- located at `developer/src/kmc-model-info` * `@keymanapp/kmc-package` -- located at `developer/src/kmc-package` diff --git a/package.json b/package.json index d2e87ab82c..7a2b53d50d 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,8 @@ "resources/build/version", "core/include/ldml", "developer/src/common/web/test-helpers", - "developer/src/kmc-keyboard", "developer/src/kmc-kmn", + "developer/src/kmc-ldml", "developer/src/kmc-model", "developer/src/kmc-model-info", "developer/src/kmc-package", diff --git a/tsconfig.esm.json b/tsconfig.esm.json index 6d286efd53..44bf4011df 100644 --- a/tsconfig.esm.json +++ b/tsconfig.esm.json @@ -10,10 +10,10 @@ //{ "path": "./developer/src/kmc/test/tsconfig.json" }, { "path": "./developer/src/kmc/tsconfig.json" }, - { "path": "./developer/src/kmc-keyboard/test/tsconfig.json" }, - { "path": "./developer/src/kmc-keyboard/tsconfig.json" }, { "path": "./developer/src/kmc-kmn/test/tsconfig.json" }, { "path": "./developer/src/kmc-kmn/tsconfig.json" }, + { "path": "./developer/src/kmc-ldml/test/tsconfig.json" }, + { "path": "./developer/src/kmc-ldml/tsconfig.json" }, { "path": "./developer/src/kmc-model/test/tsconfig.json" }, { "path": "./developer/src/kmc-model/tsconfig.json" }, //{ "path": "./developer/src/kmc-model-info/test/tsconfig.json" }, -- GitLab From 03a2b3a76c06f0cadc3c379da42f8b31c46fa30a Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 9 May 2023 14:09:18 +0700 Subject: [PATCH 036/214] chore: npm install --- package-lock.json | 407 +++++++++++++++++++++++++--------------------- 1 file changed, 225 insertions(+), 182 deletions(-) diff --git a/package-lock.json b/package-lock.json index 173ea2605f..b39f76b2ce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,8 +10,8 @@ "resources/build/version", "core/include/ldml", "developer/src/common/web/test-helpers", - "developer/src/kmc-keyboard", "developer/src/kmc-kmn", + "developer/src/kmc-ldml", "developer/src/kmc-model", "developer/src/kmc-model-info", "developer/src/kmc-package", @@ -634,8 +634,8 @@ "dependencies": { "@keymanapp/common-types": "*", "@keymanapp/keyman-version": "*", - "@keymanapp/kmc-keyboard": "*", "@keymanapp/kmc-kmn": "*", + "@keymanapp/kmc-ldml": "*", "@keymanapp/kmc-model": "*", "@keymanapp/kmc-model-info": "*", "@keymanapp/kmc-package": "*", @@ -664,6 +664,7 @@ }, "developer/src/kmc-keyboard": { "name": "@keymanapp/kmc-keyboard", + "extraneous": true, "license": "MIT", "dependencies": { "@keymanapp/keyman-version": "*", @@ -688,34 +689,77 @@ "typescript": "^4.9.5" } }, - "developer/src/kmc-keyboard/node_modules/@types/mocha": { - "version": "5.2.7", + "developer/src/kmc-kmn": { + "name": "@keymanapp/kmc-kmn", + "license": "MIT", + "dependencies": { + "@keymanapp/keyman-version": "*" + }, + "devDependencies": { + "@keymanapp/developer-test-helpers": "*", + "@types/chai": "^4.1.7", + "@types/mocha": "^5.2.7", + "@types/node": "^10.14.6", + "@types/semver": "^7.3.12", + "@types/sinon": "^10.0.13", + "@types/sinon-chai": "^3.2.9", + "@types/xml2js": "^0.4.5", + "c8": "^7.12.0", + "chai": "^4.3.4", + "chalk": "^2.4.2", + "mocha": "^8.4.0", + "sinon": "^15.0.2", + "sinon-chai": "^3.7.0", + "ts-node": "^9.1.1", + "typescript": "^4.9.5" + } + }, + "developer/src/kmc-kmn/node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", "dev": true, - "license": "MIT" + "dependencies": { + "type-detect": "4.0.8" + } }, - "developer/src/kmc-keyboard/node_modules/@types/node": { - "version": "10.17.60", + "developer/src/kmc-kmn/node_modules/@sinonjs/samsam": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-7.0.1.tgz", + "integrity": "sha512-zsAk2Jkiq89mhZovB2LLOdTCxJF4hqqTToGP0ASWlhp4I1hqOjcfmZGafXntCN7MDC6yySH0mFHrYtHceOeLmw==", "dev": true, - "license": "MIT" + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } }, - "developer/src/kmc-keyboard/node_modules/ajv": { - "version": "8.11.2", - "license": "MIT", + "developer/src/kmc-kmn/node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "type-detect": "4.0.8" } }, - "developer/src/kmc-keyboard/node_modules/ansi-styles": { + "developer/src/kmc-kmn/node_modules/@types/mocha": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", + "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", + "dev": true + }, + "developer/src/kmc-kmn/node_modules/@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "dev": true + }, + "developer/src/kmc-kmn/node_modules/ansi-styles": { "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, - "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -723,10 +767,11 @@ "node": ">=4" } }, - "developer/src/kmc-keyboard/node_modules/chalk": { + "developer/src/kmc-kmn/node_modules/chalk": { "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -736,23 +781,32 @@ "node": ">=4" } }, - "developer/src/kmc-keyboard/node_modules/color-convert": { + "developer/src/kmc-kmn/node_modules/color-convert": { "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, - "license": "MIT", "dependencies": { "color-name": "1.1.3" } }, - "developer/src/kmc-keyboard/node_modules/color-name": { + "developer/src/kmc-kmn/node_modules/color-name": { "version": "1.1.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "developer/src/kmc-kmn/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true }, - "developer/src/kmc-keyboard/node_modules/js-yaml": { + "developer/src/kmc-kmn/node_modules/js-yaml": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", "dev": true, - "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -760,14 +814,11 @@ "js-yaml": "bin/js-yaml.js" } }, - "developer/src/kmc-keyboard/node_modules/json-schema-traverse": { - "version": "1.0.0", - "license": "MIT" - }, - "developer/src/kmc-keyboard/node_modules/minimatch": { + "developer/src/kmc-kmn/node_modules/minimatch": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -775,10 +826,11 @@ "node": "*" } }, - "developer/src/kmc-keyboard/node_modules/mocha": { + "developer/src/kmc-kmn/node_modules/mocha": { "version": "8.4.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz", + "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==", "dev": true, - "license": "MIT", "dependencies": { "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", @@ -818,10 +870,11 @@ "url": "https://opencollective.com/mochajs" } }, - "developer/src/kmc-keyboard/node_modules/mocha/node_modules/escape-string-regexp": { + "developer/src/kmc-kmn/node_modules/mocha/node_modules/escape-string-regexp": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -829,10 +882,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "developer/src/kmc-keyboard/node_modules/mocha/node_modules/supports-color": { + "developer/src/kmc-kmn/node_modules/mocha/node_modules/supports-color": { "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -843,15 +897,87 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "developer/src/kmc-keyboard/node_modules/ms": { + "developer/src/kmc-kmn/node_modules/ms": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "developer/src/kmc-kmn/node_modules/nise": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.4.tgz", + "integrity": "sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==", "dev": true, - "license": "MIT" + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "^10.0.2", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, + "developer/src/kmc-kmn/node_modules/nise/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "developer/src/kmc-kmn/node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "dependencies": { + "isarray": "0.0.1" + } + }, + "developer/src/kmc-kmn/node_modules/sinon": { + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.0.2.tgz", + "integrity": "sha512-PCVP63XZkg0/LOqQH5rEU4LILuvTFMb5tNxTHfs6VUMNnZz2XrnGSTZbAGITjzwQWbl/Bl/8hi4G3zZWjyBwHg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^10.0.2", + "@sinonjs/samsam": "^7.0.1", + "diff": "^5.1.0", + "nise": "^5.1.4", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "developer/src/kmc-kmn/node_modules/sinon/node_modules/diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } }, - "developer/src/kmc-keyboard/node_modules/supports-color": { + "developer/src/kmc-kmn/node_modules/sinon/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "developer/src/kmc-kmn/node_modules/supports-color": { "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, - "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -859,15 +985,16 @@ "node": ">=4" } }, - "developer/src/kmc-keyboard/node_modules/supports-color/node_modules/has-flag": { + "developer/src/kmc-kmn/node_modules/supports-color/node_modules/has-flag": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } }, - "developer/src/kmc-keyboard/node_modules/ts-node": { + "developer/src/kmc-kmn/node_modules/ts-node": { "version": "9.1.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", @@ -893,7 +1020,7 @@ "typescript": ">=2.7" } }, - "developer/src/kmc-keyboard/node_modules/ts-node/node_modules/diff": { + "developer/src/kmc-kmn/node_modules/ts-node/node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", @@ -902,11 +1029,15 @@ "node": ">=0.3.1" } }, - "developer/src/kmc-kmn": { - "name": "@keymanapp/kmc-kmn", + "developer/src/kmc-ldml": { "license": "MIT", "dependencies": { - "@keymanapp/keyman-version": "*" + "@keymanapp/keyman-version": "*", + "@keymanapp/ldml-keyboard-constants": "*", + "ajv": "^8.11.0", + "restructure": "git+https://github.com/keymanapp/dependency-restructure.git#49d129cf0916d082a7278bb09296fb89cecfcc50", + "semver": "^7.3.7", + "xml2js": "git+https://github.com/keymanapp/dependency-node-xml2js#535fe732dc408d697e0f847c944cc45f0baf0829" }, "devDependencies": { "@keymanapp/developer-test-helpers": "*", @@ -914,61 +1045,43 @@ "@types/mocha": "^5.2.7", "@types/node": "^10.14.6", "@types/semver": "^7.3.12", - "@types/sinon": "^10.0.13", - "@types/sinon-chai": "^3.2.9", "@types/xml2js": "^0.4.5", "c8": "^7.12.0", "chai": "^4.3.4", "chalk": "^2.4.2", "mocha": "^8.4.0", - "sinon": "^15.0.2", - "sinon-chai": "^3.7.0", "ts-node": "^9.1.1", "typescript": "^4.9.5" } }, - "developer/src/kmc-kmn/node_modules/@sinonjs/commons": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", - "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "developer/src/kmc-kmn/node_modules/@sinonjs/samsam": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-7.0.1.tgz", - "integrity": "sha512-zsAk2Jkiq89mhZovB2LLOdTCxJF4hqqTToGP0ASWlhp4I1hqOjcfmZGafXntCN7MDC6yySH0mFHrYtHceOeLmw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^2.0.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" - } - }, - "developer/src/kmc-kmn/node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "developer/src/kmc-kmn/node_modules/@types/mocha": { + "developer/src/kmc-ldml/node_modules/@types/mocha": { "version": "5.2.7", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", "dev": true }, - "developer/src/kmc-kmn/node_modules/@types/node": { + "developer/src/kmc-ldml/node_modules/@types/node": { "version": "10.17.60", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", "dev": true }, - "developer/src/kmc-kmn/node_modules/ansi-styles": { + "developer/src/kmc-ldml/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "developer/src/kmc-ldml/node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", @@ -980,7 +1093,7 @@ "node": ">=4" } }, - "developer/src/kmc-kmn/node_modules/chalk": { + "developer/src/kmc-ldml/node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", @@ -994,7 +1107,7 @@ "node": ">=4" } }, - "developer/src/kmc-kmn/node_modules/color-convert": { + "developer/src/kmc-ldml/node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", @@ -1003,19 +1116,13 @@ "color-name": "1.1.3" } }, - "developer/src/kmc-kmn/node_modules/color-name": { + "developer/src/kmc-ldml/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, - "developer/src/kmc-kmn/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "developer/src/kmc-kmn/node_modules/js-yaml": { + "developer/src/kmc-ldml/node_modules/js-yaml": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", @@ -1027,7 +1134,12 @@ "js-yaml": "bin/js-yaml.js" } }, - "developer/src/kmc-kmn/node_modules/minimatch": { + "developer/src/kmc-ldml/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "developer/src/kmc-ldml/node_modules/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", @@ -1039,7 +1151,7 @@ "node": "*" } }, - "developer/src/kmc-kmn/node_modules/mocha": { + "developer/src/kmc-ldml/node_modules/mocha": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz", "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==", @@ -1083,7 +1195,7 @@ "url": "https://opencollective.com/mochajs" } }, - "developer/src/kmc-kmn/node_modules/mocha/node_modules/escape-string-regexp": { + "developer/src/kmc-ldml/node_modules/mocha/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", @@ -1095,7 +1207,7 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "developer/src/kmc-kmn/node_modules/mocha/node_modules/supports-color": { + "developer/src/kmc-ldml/node_modules/mocha/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", @@ -1110,83 +1222,13 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "developer/src/kmc-kmn/node_modules/ms": { + "developer/src/kmc-ldml/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "developer/src/kmc-kmn/node_modules/nise": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.4.tgz", - "integrity": "sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^2.0.0", - "@sinonjs/fake-timers": "^10.0.2", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "path-to-regexp": "^1.7.0" - } - }, - "developer/src/kmc-kmn/node_modules/nise/node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "developer/src/kmc-kmn/node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dev": true, - "dependencies": { - "isarray": "0.0.1" - } - }, - "developer/src/kmc-kmn/node_modules/sinon": { - "version": "15.0.2", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.0.2.tgz", - "integrity": "sha512-PCVP63XZkg0/LOqQH5rEU4LILuvTFMb5tNxTHfs6VUMNnZz2XrnGSTZbAGITjzwQWbl/Bl/8hi4G3zZWjyBwHg==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0", - "@sinonjs/fake-timers": "^10.0.2", - "@sinonjs/samsam": "^7.0.1", - "diff": "^5.1.0", - "nise": "^5.1.4", - "supports-color": "^7.2.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/sinon" - } - }, - "developer/src/kmc-kmn/node_modules/sinon/node_modules/diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "developer/src/kmc-kmn/node_modules/sinon/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "developer/src/kmc-kmn/node_modules/supports-color": { + "developer/src/kmc-ldml/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", @@ -1198,7 +1240,7 @@ "node": ">=4" } }, - "developer/src/kmc-kmn/node_modules/supports-color/node_modules/has-flag": { + "developer/src/kmc-ldml/node_modules/supports-color/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", @@ -1207,7 +1249,7 @@ "node": ">=4" } }, - "developer/src/kmc-kmn/node_modules/ts-node": { + "developer/src/kmc-ldml/node_modules/ts-node": { "version": "9.1.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", @@ -1233,7 +1275,7 @@ "typescript": ">=2.7" } }, - "developer/src/kmc-kmn/node_modules/ts-node/node_modules/diff": { + "developer/src/kmc-ldml/node_modules/ts-node/node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", @@ -1553,6 +1595,7 @@ "name": "@keymanapp/kmc-package", "license": "MIT", "dependencies": { + "@keymanapp/common-types": "*", "jszip": "^3.7.0" }, "devDependencies": { @@ -2275,14 +2318,14 @@ "resolved": "developer/src/kmc", "link": true }, - "node_modules/@keymanapp/kmc-keyboard": { - "resolved": "developer/src/kmc-keyboard", - "link": true - }, "node_modules/@keymanapp/kmc-kmn": { "resolved": "developer/src/kmc-kmn", "link": true }, + "node_modules/@keymanapp/kmc-ldml": { + "resolved": "developer/src/kmc-ldml", + "link": true + }, "node_modules/@keymanapp/kmc-model": { "resolved": "developer/src/kmc-model", "link": true -- GitLab From 2f65acf268900ce2a63c9e7386ea4ce038b009b1 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 9 May 2023 14:24:59 +0700 Subject: [PATCH 037/214] chore(developer): additional kmc-ldml ref --- developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts b/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts index 8f11465584..4ccb55c122 100644 --- a/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts +++ b/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts @@ -1,6 +1,6 @@ import * as path from 'path'; import * as fs from 'fs'; -import * as kmc from '@keymanapp/kmc-keyboard'; +import * as kmc from '@keymanapp/kmc-ldml'; import { KvkFileWriter, CompilerCallbacks } from '@keymanapp/common-types'; import { BuildActivity, BuildActivityOptions } from './BuildActivity.js'; -- GitLab From 46267e347fc11e393db64349070db727b284ee55 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 9 May 2023 14:28:21 +0700 Subject: [PATCH 038/214] chore(developer): rename Compiler and related classes --- developer/src/kmc-kmn/src/compiler/compiler.ts | 2 +- developer/src/kmc-kmn/src/main.ts | 2 +- developer/src/kmc-kmn/test/test-compiler.ts | 9 +++++---- .../src/kmc-ldml/src/compiler/compiler-options.ts | 2 +- developer/src/kmc-ldml/src/compiler/compiler.ts | 4 ++-- .../kmc-ldml/src/compiler/keymanweb-compiler.ts | 14 +++++++------- .../src/kmc-ldml/src/compiler/metadata-compiler.ts | 4 ++-- .../src/compiler/visual-keyboard-compiler.ts | 2 +- developer/src/kmc-ldml/src/main.ts | 10 +++++----- .../src/kmc/src/commands/build/BuildKmnKeyboard.ts | 4 ++-- .../kmc/src/commands/build/BuildLdmlKeyboard.ts | 4 ++-- .../src/kmc/src/commands/buildTestData/index.ts | 2 +- 12 files changed, 30 insertions(+), 29 deletions(-) diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index c112b4caf7..0f64fdbbbd 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -47,7 +47,7 @@ const baseOptions: CompilerOptions = { */ let callbackProcIdentifier = 0; -export class Compiler { +export class KmnCompiler { wasmModule: any; compileKeyboardFile: any; setCompilerOptions: any; diff --git a/developer/src/kmc-kmn/src/main.ts b/developer/src/kmc-kmn/src/main.ts index c3c3d6f173..70d11989c6 100644 --- a/developer/src/kmc-kmn/src/main.ts +++ b/developer/src/kmc-kmn/src/main.ts @@ -1,2 +1,2 @@ -export { Compiler } from './compiler/compiler.js'; +export { KmnCompiler } from './compiler/compiler.js'; diff --git a/developer/src/kmc-kmn/test/test-compiler.ts b/developer/src/kmc-kmn/test/test-compiler.ts index 081ed7762b..2a6acca73e 100644 --- a/developer/src/kmc-kmn/test/test-compiler.ts +++ b/developer/src/kmc-kmn/test/test-compiler.ts @@ -2,7 +2,7 @@ import 'mocha'; import sinon from 'sinon'; import chai, { assert } from 'chai'; import sinonChai from 'sinon-chai'; -import { Compiler } from '../src/main.js'; +import { KmnCompiler } from '../src/main.js'; import { dirname } from 'path'; import { fileURLToPath } from 'url'; import fs from 'fs'; @@ -15,6 +15,7 @@ chai.use(sinonChai); describe('Compiler class', function() { let consoleLog: any; + // TODO: do we need this? beforeEach(function() { consoleLog = sinon.spy(console, 'log'); }); @@ -24,12 +25,12 @@ describe('Compiler class', function() { }); it('should start', async function() { - const compiler = new Compiler(); + const compiler = new KmnCompiler(); assert(await compiler.init()); }); it('should compile a basic keyboard', async function() { - const compiler = new Compiler(); + const compiler = new KmnCompiler(); const callbacks = new TestCompilerCallbacks(); assert(await compiler.init()); @@ -49,7 +50,7 @@ describe('Compiler class', function() { // Note, above test case is essentially a subset of this one, but will leave both because // the basic keyboard test is slightly simpler to read it('should build all baseline fixtures', async function() { - const compiler = new Compiler(); + const compiler = new KmnCompiler(); const callbacks = new TestCompilerCallbacks(); assert(await compiler.init()); diff --git a/developer/src/kmc-ldml/src/compiler/compiler-options.ts b/developer/src/kmc-ldml/src/compiler/compiler-options.ts index d36322513b..3d29e6393a 100644 --- a/developer/src/kmc-ldml/src/compiler/compiler-options.ts +++ b/developer/src/kmc-ldml/src/compiler/compiler-options.ts @@ -1,6 +1,6 @@ -export default interface CompilerOptions { +export interface CompilerOptions { /** * Add debug information to the .kmx file when compiling */ diff --git a/developer/src/kmc-ldml/src/compiler/compiler.ts b/developer/src/kmc-ldml/src/compiler/compiler.ts index 29e0d61a53..b7b46e49b2 100644 --- a/developer/src/kmc-ldml/src/compiler/compiler.ts +++ b/developer/src/kmc-ldml/src/compiler/compiler.ts @@ -1,5 +1,5 @@ import { LDMLKeyboardXMLSourceFileReader, LDMLKeyboard, KMXPlus, CompilerCallbacks, LDMLKeyboardTestDataXMLSourceFile } from '@keymanapp/common-types'; -import CompilerOptions from './compiler-options.js'; +import { CompilerOptions } from './compiler-options.js'; import { CompilerMessages } from './messages.js'; import { BkspCompiler, FinlCompiler, TranCompiler } from './tran.js'; import { DispCompiler } from './disp.js'; @@ -28,7 +28,7 @@ const SECTION_COMPILERS = [ VkeyCompiler, ]; -export default class Compiler { +export class LdmlKeyboardCompiler { private readonly callbacks: CompilerCallbacks; // private readonly options: CompilerOptions; // not currently used diff --git a/developer/src/kmc-ldml/src/compiler/keymanweb-compiler.ts b/developer/src/kmc-ldml/src/compiler/keymanweb-compiler.ts index 3117134c2c..7ecdbe5937 100644 --- a/developer/src/kmc-ldml/src/compiler/keymanweb-compiler.ts +++ b/developer/src/kmc-ldml/src/compiler/keymanweb-compiler.ts @@ -1,19 +1,19 @@ import { CompilerCallbacks, VisualKeyboard, LDMLKeyboard, TouchLayoutFileWriter } from "@keymanapp/common-types"; -import CompilerOptions from "./compiler-options.js"; +import { CompilerOptions } from "./compiler-options.js"; import { TouchLayoutCompiler } from "./touch-layout-compiler.js"; -import VisualKeyboardCompiler from "./visual-keyboard-compiler.js"; +import { LdmlKeyboardVisualKeyboardCompiler } from "./visual-keyboard-compiler.js"; const MINIMUM_KMW_VERSION = '16.0'; -export interface KeymanWebCompilerOptions extends CompilerOptions { +export interface LdmlKeyboardKeymanWebCompilerOptions extends CompilerOptions { }; -export class KeymanWebCompiler { - private readonly options: KeymanWebCompilerOptions; +export class LdmlKeyboardKeymanWebCompiler { + private readonly options: LdmlKeyboardKeymanWebCompilerOptions; private readonly nl: string; private readonly tab: string; - constructor(private callbacks: CompilerCallbacks, options?: KeymanWebCompilerOptions) { + constructor(private callbacks: CompilerCallbacks, options?: LdmlKeyboardKeymanWebCompilerOptions) { this.options = { ...options }; this.nl = this.options.debug ? "\n" : ''; this.tab = this.options.debug ? " " : ''; @@ -21,7 +21,7 @@ export class KeymanWebCompiler { public compileVisualKeyboard(source: LDMLKeyboard.LDMLKeyboardXMLSourceFile) { const nl = this.nl, tab = this.tab; - const vkc = new VisualKeyboardCompiler(); + const vkc = new LdmlKeyboardVisualKeyboardCompiler(); const vk: VisualKeyboard.VisualKeyboard = vkc.compile(source); let result = diff --git a/developer/src/kmc-ldml/src/compiler/metadata-compiler.ts b/developer/src/kmc-ldml/src/compiler/metadata-compiler.ts index f459d5fab9..262b86c801 100644 --- a/developer/src/kmc-ldml/src/compiler/metadata-compiler.ts +++ b/developer/src/kmc-ldml/src/compiler/metadata-compiler.ts @@ -1,12 +1,12 @@ import { KMX, KMXPlus } from '@keymanapp/common-types'; -import CompilerOptions from "./compiler-options.js"; +import { CompilerOptions } from "./compiler-options.js"; import KEYMAN_VERSION from "@keymanapp/keyman-version"; import KMXPlusData = KMXPlus.KMXPlusData; import KMXFile = KMX.KMXFile; import KEYBOARD = KMX.KEYBOARD; -export default class KMXPlusMetadataCompiler { +export class KMXPlusMetadataCompiler { /** * Look for metadata fields in the KMXPlus data and copy them * through to the relevant KMX stores diff --git a/developer/src/kmc-ldml/src/compiler/visual-keyboard-compiler.ts b/developer/src/kmc-ldml/src/compiler/visual-keyboard-compiler.ts index b80b590b9c..d951080b9b 100644 --- a/developer/src/kmc-ldml/src/compiler/visual-keyboard-compiler.ts +++ b/developer/src/kmc-ldml/src/compiler/visual-keyboard-compiler.ts @@ -1,6 +1,6 @@ import { Constants, VisualKeyboard, LDMLKeyboard } from "@keymanapp/common-types"; -export default class VisualKeyboardCompiler { +export class LdmlKeyboardVisualKeyboardCompiler { public compile(source: LDMLKeyboard.LDMLKeyboardXMLSourceFile): VisualKeyboard.VisualKeyboard { let result = new VisualKeyboard.VisualKeyboard(); diff --git a/developer/src/kmc-ldml/src/main.ts b/developer/src/kmc-ldml/src/main.ts index 3bf1c37f1c..e8af2f7804 100644 --- a/developer/src/kmc-ldml/src/main.ts +++ b/developer/src/kmc-ldml/src/main.ts @@ -1,10 +1,10 @@ -export { default as Compiler } from './compiler/compiler.js'; -export { KeymanWebCompiler } from './compiler/keymanweb-compiler.js'; -export { default as VisualKeyboardCompiler } from './compiler/visual-keyboard-compiler.js'; +export { LdmlKeyboardCompiler } from './compiler/compiler.js'; +export { LdmlKeyboardKeymanWebCompiler as KeymanWebCompiler } from './compiler/keymanweb-compiler.js'; +export { LdmlKeyboardVisualKeyboardCompiler } from './compiler/visual-keyboard-compiler.js'; export { TouchLayoutCompiler } from './compiler/touch-layout-compiler.js'; -export { default as CompilerOptions } from './compiler/compiler-options.js'; +export { CompilerOptions } from './compiler/compiler-options.js'; export { CompilerMessages } from './compiler/messages.js'; -export { default as KMXPlusMetadataCompiler } from './compiler/metadata-compiler.js'; +export { KMXPlusMetadataCompiler } from './compiler/metadata-compiler.js'; export { KMXBuilder } from "@keymanapp/common-types"; diff --git a/developer/src/kmc/src/commands/build/BuildKmnKeyboard.ts b/developer/src/kmc/src/commands/build/BuildKmnKeyboard.ts index cd5b7c7ac3..50a6fbb6bf 100644 --- a/developer/src/kmc/src/commands/build/BuildKmnKeyboard.ts +++ b/developer/src/kmc/src/commands/build/BuildKmnKeyboard.ts @@ -1,6 +1,6 @@ import * as path from 'path'; import { BuildActivity, BuildActivityOptions } from './BuildActivity.js'; -import { Compiler } from '@keymanapp/kmc-kmn'; +import { KmnCompiler } from '@keymanapp/kmc-kmn'; import { platform } from 'os'; import { CompilerCallbacks } from '@keymanapp/common-types'; @@ -10,7 +10,7 @@ export class BuildKmnKeyboard extends BuildActivity { public get compiledExtension(): string { return '.kmx'; } public get description(): string { return 'Build a Keyman keyboard'; } public async build(infile: string, callbacks: CompilerCallbacks, options: BuildActivityOptions): Promise { - let compiler = new Compiler(); + let compiler = new KmnCompiler(); if(!await compiler.init()) { return false; } diff --git a/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts b/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts index 4ccb55c122..46c939b0e0 100644 --- a/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts +++ b/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts @@ -50,7 +50,7 @@ function buildLdmlKeyboardToMemory(inputFilename: string, callbacks: CompilerCal // TODO: treatWarningsAsErrors: options.treatWarningsAsErrors, } - const k = new kmc.Compiler(callbacks, options); + const k = new kmc.LdmlKeyboardCompiler(callbacks, options); let source = k.load(inputFilename); if (!source) { return [null, null, null]; @@ -68,7 +68,7 @@ function buildLdmlKeyboardToMemory(inputFilename: string, callbacks: CompilerCal const builder = new kmc.KMXBuilder(kmx, options.debug); const kmx_binary = builder.compile(); - const vkcompiler = new kmc.VisualKeyboardCompiler(); + const vkcompiler = new kmc.LdmlKeyboardVisualKeyboardCompiler(); const vk = vkcompiler.compile(source); const writer = new KvkFileWriter(); const kvk_binary = writer.write(vk); diff --git a/developer/src/kmc/src/commands/buildTestData/index.ts b/developer/src/kmc/src/commands/buildTestData/index.ts index 89674efbef..0990b91edb 100644 --- a/developer/src/kmc/src/commands/buildTestData/index.ts +++ b/developer/src/kmc/src/commands/buildTestData/index.ts @@ -29,7 +29,7 @@ export function buildTestData(infile: string, options: BuildTestDataOptions) { function loadTestData(inputFilename: string, options: kmc.CompilerOptions): LDMLKeyboardTestDataXMLSourceFile { const c: CompilerCallbacks = new NodeCompilerCallbacks(); - const k = new kmc.Compiler(c, options); + const k = new kmc.LdmlKeyboardCompiler(c, options); let source = k.loadTestData(inputFilename); if (!source) { return null; -- GitLab From bd4987335289990cff45086961bc6b76a15fd330 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 9 May 2023 09:53:52 +0200 Subject: [PATCH 039/214] chore(linux): Fix another problem uploading to launchpad --- linux/scripts/launchpad.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/linux/scripts/launchpad.sh b/linux/scripts/launchpad.sh index cdca3e3c0d..30495d2b0e 100755 --- a/linux/scripts/launchpad.sh +++ b/linux/scripts/launchpad.sh @@ -15,9 +15,11 @@ set -eu ## START STANDARD BUILD SCRIPT INCLUDE # adjust relative paths as necessary THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" +# shellcheck source=resources/build/build-utils.sh . "${THIS_SCRIPT%/*}/../../resources/build/build-utils.sh" ## END STANDARD BUILD SCRIPT INCLUDE +# shellcheck source=linux/scripts/package-build.inc.sh . "$(dirname "$THIS_SCRIPT")/package-build.inc.sh" checkPrerequisites @@ -53,7 +55,7 @@ for proj in ${projects:-}; do done cd .. for dist in ${distributions}; do - dput "${SIM}" ${ppa} "${proj}_${version}-${packageversion}~${dist}_source.changes" + dput ${SIM} ${ppa} "${proj}_${version}-${packageversion}~${dist}_source.changes" done cd "${BASEDIR}" done -- GitLab From 53ccdbe2412cf0d21e01bba0cfdab59cd8c31dd4 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 9 May 2023 15:48:50 +0700 Subject: [PATCH 040/214] chore(developer): move package formats to common/web/types Package file interfaces were stored in developer/kmc-package but belong better now in common/web/types. --- common/web/types/src/main.ts | 6 ++- .../web/types/src/package}/kmp-json-file.ts | 0 .../web/types/src/package}/kps-file.ts | 0 developer/src/kmc-package/src/kmp-compiler.ts | 44 +++++++++---------- .../kmc-package/test/test-package-compiler.ts | 10 ++--- developer/src/kmc-package/tsconfig.json | 2 +- 6 files changed, 31 insertions(+), 31 deletions(-) rename {developer/src/kmc-package/src => common/web/types/src/package}/kmp-json-file.ts (100%) rename {developer/src/kmc-package/src => common/web/types/src/package}/kps-file.ts (100%) diff --git a/common/web/types/src/main.ts b/common/web/types/src/main.ts index 4dad5f96ab..19ca707b6d 100644 --- a/common/web/types/src/main.ts +++ b/common/web/types/src/main.ts @@ -29,4 +29,8 @@ export * as KPJ from './kpj/kpj-file.js'; export { KPJFileReader } from './kpj/kpj-file-reader.js'; export { KeymanDeveloperProject } from './kpj/keyman-developer-project.js'; -export * as util from './util/util.js'; \ No newline at end of file +export * as KpsFile from './package/kps-file.js'; +export * as KmpJsonFile from './package/kmp-json-file.js'; + +export * as util from './util/util.js'; + diff --git a/developer/src/kmc-package/src/kmp-json-file.ts b/common/web/types/src/package/kmp-json-file.ts similarity index 100% rename from developer/src/kmc-package/src/kmp-json-file.ts rename to common/web/types/src/package/kmp-json-file.ts diff --git a/developer/src/kmc-package/src/kps-file.ts b/common/web/types/src/package/kps-file.ts similarity index 100% rename from developer/src/kmc-package/src/kps-file.ts rename to common/web/types/src/package/kps-file.ts diff --git a/developer/src/kmc-package/src/kmp-compiler.ts b/developer/src/kmc-package/src/kmp-compiler.ts index 4fd532b368..f52c356ab1 100644 --- a/developer/src/kmc-package/src/kmp-compiler.ts +++ b/developer/src/kmc-package/src/kmp-compiler.ts @@ -2,13 +2,9 @@ import * as xml2js from 'xml2js'; import JSZip from 'jszip'; import KEYMAN_VERSION from "@keymanapp/keyman-version"; -import type { KpsFile, KpsFileContentFile, KpsFileInfo, KpsFileKeyboard, KpsFileLanguage, KpsFileLexicalModel, KpsFileOptions, KpsPackage } from './kps-file.js'; -import type { KmpJsonFile, KmpJsonFileInfo, KmpJsonFileLanguage, KmpJsonFileOptions } from './kmp-json-file.js'; import { CompilerCallbacks, KvkFile } from '@keymanapp/common-types'; import { CompilerMessages } from './messages.js'; -import { KMX, KmxFileReader } from '@keymanapp/common-types'; - -export { type KmpJsonFile } from './kmp-json-file.js'; +import { KmpJsonFile, KpsFile, KMX, KmxFileReader } from '@keymanapp/common-types'; const FILEVERSION_KMP_JSON = '12.0'; @@ -17,21 +13,21 @@ export default class KmpCompiler { constructor(private callbacks: CompilerCallbacks) { } - public transformKpsToKmpObject(kpsFilename: string): KmpJsonFile { + public transformKpsToKmpObject(kpsFilename: string): KmpJsonFile.KmpJsonFile { // Load the KPS data from XML as JS structured data. const data = this.callbacks.fs.readFileSync(kpsFilename, 'utf-8'); const kpsPackage = (() => { - let a: KpsPackage; + let a: KpsFile.KpsPackage; let parser = new xml2js.Parser({ tagNameProcessors: [xml2js.processors.firstCharLowerCase], explicitArray: false }); - parser.parseString(data, (e: unknown, r: unknown) => { a = r as KpsPackage }); + parser.parseString(data, (e: unknown, r: unknown) => { a = r as KpsFile.KpsPackage }); return a; })(); - let kps: KpsFile = kpsPackage.package; + let kps: KpsFile.KpsFile = kpsPackage.package; // // To convert to kmp.json, we need to: @@ -46,7 +42,7 @@ export default class KmpCompiler { // Start to construct the kmp.json file from the .kps file - let kmp: KmpJsonFile = { + let kmp: KmpJsonFile.KmpJsonFile = { system: { fileVersion: FILEVERSION_KMP_JSON, keymanDeveloperVersion: KEYMAN_VERSION.VERSION @@ -58,7 +54,7 @@ export default class KmpCompiler { // Fill in additional fields // - let keys: [keyof KpsFileOptions, keyof KmpJsonFileOptions][] = [ + let keys: [keyof KpsFile.KpsFileOptions, keyof KmpJsonFile.KmpJsonFileOptions][] = [ ['executeProgram','executeProgram'], ['graphicFile', 'graphicFile'], ['msiFileName','msiFilename'], @@ -86,7 +82,7 @@ export default class KmpCompiler { // if(kps.files && kps.files.file) { - kmp.files = this.arrayWrap(kps.files.file).map((file: KpsFileContentFile) => { + kmp.files = this.arrayWrap(kps.files.file).map((file: KpsFile.KpsFileContentFile) => { return { name: file.name, description: file.description, @@ -108,14 +104,14 @@ export default class KmpCompiler { // if(kps.keyboards && kps.keyboards.keyboard) { - kmp.keyboards = this.arrayWrap(kps.keyboards.keyboard).map((keyboard: KpsFileKeyboard) => { + kmp.keyboards = this.arrayWrap(kps.keyboards.keyboard).map((keyboard: KpsFile.KpsFileKeyboard) => { return { displayFont: keyboard.displayFont ? this.callbacks.path.basename(keyboard.displayFont) : undefined, oskFont: keyboard.oSKFont ? this.callbacks.path.basename(keyboard.oSKFont) : undefined, name:keyboard.name, id:keyboard.iD, version:keyboard.version, - languages: this.kpsLanguagesToKmpLanguages(this.arrayWrap(keyboard.languages.language) as KpsFileLanguage[]) + languages: this.kpsLanguagesToKmpLanguages(this.arrayWrap(keyboard.languages.language) as KpsFile.KpsFileLanguage[]) }; }); } @@ -125,8 +121,8 @@ export default class KmpCompiler { // if(kps.lexicalModels && kps.lexicalModels.lexicalModel) { - kmp.lexicalModels = this.arrayWrap(kps.lexicalModels.lexicalModel).map((model: KpsFileLexicalModel) => { - return { name:model.name, id:model.iD, languages: this.kpsLanguagesToKmpLanguages(this.arrayWrap(model.languages.language) as KpsFileLanguage[]) } + kmp.lexicalModels = this.arrayWrap(kps.lexicalModels.lexicalModel).map((model: KpsFile.KpsFileLexicalModel) => { + return { name:model.name, id:model.iD, languages: this.kpsLanguagesToKmpLanguages(this.arrayWrap(model.languages.language) as KpsFile.KpsFileLanguage[]) } }); } @@ -160,17 +156,17 @@ export default class KmpCompiler { kmp.strings = this.arrayWrap(kps.strings.string); } - kmp = this.stripUndefined(kmp) as KmpJsonFile; + kmp = this.stripUndefined(kmp) as KmpJsonFile.KmpJsonFile; return kmp; } // Helper functions - private kpsInfoToKmpInfo(info: KpsFileInfo): KmpJsonFileInfo { - let ni: KmpJsonFileInfo = {}; + private kpsInfoToKmpInfo(info: KpsFile.KpsFileInfo): KmpJsonFile.KmpJsonFileInfo { + let ni: KmpJsonFile.KmpJsonFileInfo = {}; - const keys: [(keyof KpsFileInfo), (keyof KmpJsonFileInfo)][] = [ + const keys: [(keyof KpsFile.KpsFileInfo), (keyof KmpJsonFile.KmpJsonFileInfo)][] = [ ['author','author'], ['copyright','copyright'], ['name','name'], @@ -195,11 +191,11 @@ export default class KmpCompiler { return [a]; }; - private kpsLanguagesToKmpLanguages(language: KpsFileLanguage[]): KmpJsonFileLanguage[] { + private kpsLanguagesToKmpLanguages(language: KpsFile.KpsFileLanguage[]): KmpJsonFile.KmpJsonFileLanguage[] { return language.map((element) => { return { name: element._, id: element.$.ID } }); }; - private extractKeyboardVersionFromKmx(kpsFilename: string, kmp: KmpJsonFile) { + private extractKeyboardVersionFromKmx(kpsFilename: string, kmp: KmpJsonFile.KmpJsonFile) { // The DEFAULT_VERSION used to be '1.0', but we now use '0.0' to allow // pre-release 0.x keyboards to be considered later than a keyboard without // any version metadata at all. @@ -278,13 +274,13 @@ export default class KmpCompiler { * @param kpsFilename - Filename of the kps, not read, used only for calculating relative paths * @param kmpJsonData - The kmp.json Object */ - public buildKmpFile(kpsFilename: string, kmpJsonData: KmpJsonFile): Promise { + public buildKmpFile(kpsFilename: string, kmpJsonData: KmpJsonFile.KmpJsonFile): Promise { const zip = JSZip(); const kmpJsonFileName = 'kmp.json'; // Make a copy of kmpJsonData, as we mutate paths for writing - const data: KmpJsonFile = JSON.parse(JSON.stringify(kmpJsonData)); + const data: KmpJsonFile.KmpJsonFile = JSON.parse(JSON.stringify(kmpJsonData)); if(!data.files) { data.files = []; } diff --git a/developer/src/kmc-package/test/test-package-compiler.ts b/developer/src/kmc-package/test/test-package-compiler.ts index 7708047a21..1faf65d8cc 100644 --- a/developer/src/kmc-package/test/test-package-compiler.ts +++ b/developer/src/kmc-package/test/test-package-compiler.ts @@ -6,7 +6,7 @@ import KmpCompiler from '../src/kmp-compiler.js'; import {makePathToFixture} from './helpers/index.js'; import JSZip from 'jszip'; import KEYMAN_VERSION from "@keymanapp/keyman-version"; -import { type KmpJsonFile } from '../src/kmp-json-file.js'; +import { KmpJsonFile } from '@keymanapp/common-types'; import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; import { CompilerMessages } from '../src/messages.js'; @@ -37,7 +37,7 @@ describe('KmpCompiler', function () { // Test just the transform from kps to kmp.json // it(`should transform ${modelID}.model.kps to kmp.json`, function () { - let kmpJson: KmpJsonFile; + let kmpJson: KmpJsonFile.KmpJsonFile; assert.doesNotThrow(() => { kmpJson = kmpCompiler.transformKpsToKmpObject(kpsPath); @@ -56,7 +56,7 @@ describe('KmpCompiler', function () { it(`should build a full .kmp for ${modelID}`, async function() { const zip = JSZip(); // Build kmp.json in memory - const kmpJson: KmpJsonFile = kmpCompiler.transformKpsToKmpObject(kpsPath); + const kmpJson: KmpJsonFile.KmpJsonFile = kmpCompiler.transformKpsToKmpObject(kpsPath); // Build file.kmp in memory const promise = kmpCompiler.buildKmpFile(kpsPath, kmpJson); promise.then(data => { @@ -86,7 +86,7 @@ describe('KmpCompiler', function () { const kmpJsonRefPath = makePathToFixture('khmer_angkor', 'ref', 'kmp.json'); const kmpCompiler = new KmpCompiler(callbacks); - const kmpJsonFixture: KmpJsonFile = JSON.parse(fs.readFileSync(kmpJsonRefPath, 'utf-8')); + const kmpJsonFixture: KmpJsonFile.KmpJsonFile = JSON.parse(fs.readFileSync(kmpJsonRefPath, 'utf-8')); // We override the fixture version so that we can compare with the compiler output kmpJsonFixture.system.keymanDeveloperVersion = KEYMAN_VERSION.VERSION; @@ -131,7 +131,7 @@ describe('KmpCompiler', function () { const kpsPath = makePathToFixture('absolute_path', 'source', 'absolute_path.kps'); const kmpCompiler = new KmpCompiler(callbacks); - let kmpJson: KmpJsonFile = null; + let kmpJson: KmpJsonFile.KmpJsonFile = null; assert.doesNotThrow(() => { kmpJson = kmpCompiler.transformKpsToKmpObject(kpsPath); diff --git a/developer/src/kmc-package/tsconfig.json b/developer/src/kmc-package/tsconfig.json index e7e5b3a93b..8913057047 100644 --- a/developer/src/kmc-package/tsconfig.json +++ b/developer/src/kmc-package/tsconfig.json @@ -7,7 +7,7 @@ "allowSyntheticDefaultImports": true, // for jszip }, "include": [ - "src/**/*.ts" + "src/**/*.ts", ], "references": [ { "path": "../../../common/web/keyman-version/tsconfig.esm.json" }, -- GitLab From 24d808a2107ba1befc161a69abb81f4fbee0da41 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 9 May 2023 11:03:55 +0200 Subject: [PATCH 041/214] chore(linux): Address code review comments This is a follow-up of #8510. --- .../ibus-keyman/tests/scripts/setup-tests.sh | 1 + .../ibus-keyman/tests/scripts/test-helper.sh | 27 ++++++++++--------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/linux/ibus-keyman/tests/scripts/setup-tests.sh b/linux/ibus-keyman/tests/scripts/setup-tests.sh index 1e868f7430..62f6a97817 100755 --- a/linux/ibus-keyman/tests/scripts/setup-tests.sh +++ b/linux/ibus-keyman/tests/scripts/setup-tests.sh @@ -9,6 +9,7 @@ TOP_BINDIR=${G_TEST_BUILDDIR:-$(realpath "$(dirname "$0/..")")}/.. TESTBASEDIR=${XDG_DATA_HOME:-$HOME/.local/share}/keyman TESTDIR=${TESTBASEDIR}/test_kmx +# shellcheck source=linux/ibus-keyman/tests/scripts/test-helper.sh . "$(dirname "$0")"/test-helper.sh echo > "$ENV_FILE" diff --git a/linux/ibus-keyman/tests/scripts/test-helper.sh b/linux/ibus-keyman/tests/scripts/test-helper.sh index 92e517009c..efee4c26f1 100755 --- a/linux/ibus-keyman/tests/scripts/test-helper.sh +++ b/linux/ibus-keyman/tests/scripts/test-helper.sh @@ -15,28 +15,18 @@ function generate_kmpjson() { TESTDIR="$1" pushd "$TESTDIR" > /dev/null || exit KMPFILE="${TESTDIR}/kmp.json" - THISYEAR=$(date "+%Y") cat <<-EOF > "$KMPFILE" { "system": { "keymanDeveloperVersion": "10.0.1099.0", "fileVersion": "7.0" }, - "options": { - "readmeFile": "kmx.cpp" - }, "info": { "name": { "description": "Test Keyboards" }, "version": { "description": "0.0" - }, - "copyright": { - "description": "\u00A9 2018-${THISYEAR} SIL International" - }, - "author": { - "description": "" } }, "files": [ @@ -44,6 +34,19 @@ function generate_kmpjson() { "name": "kmp.json", "description": "Package information (JSON)" } +EOF + for f in k_*.kmx; do + keyboard=$(basename "$f") + keyboard="${keyboard%.*}" + echo " ," >> "$KMPFILE" + cat <<-EOF >> "$KMPFILE" + { + "name": "$keyboard", + "description": "$keyboard" + } +EOF + done + cat <<-EOF >> "$KMPFILE" ], "keyboards": [ EOF @@ -54,7 +57,7 @@ EOF if $FIRST; then FIRST=false else - echo "," >> "$KMPFILE" + echo " ," >> "$KMPFILE" fi cat <<-EOF >> "$KMPFILE" { @@ -70,7 +73,7 @@ EOF } EOF done - echo "]" >> "$KMPFILE" + echo " ]" >> "$KMPFILE" echo "}" >> "$KMPFILE" popd > /dev/null || exit } -- GitLab From efb48e55680de6d3f55785a12ae2c9cb1fffa4be Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 9 May 2023 11:56:43 +0200 Subject: [PATCH 042/214] chore(linux): Add build.sh for keyman-config Also remove second output from build.sh which isn't supported and doesn't work. `ibus-keyman-tests` will be built when running `build.sh test`. --- linux/build.sh | 2 ++ linux/ibus-keyman/build.sh | 3 +- linux/keyman-config/.editorconfig | 5 ++- linux/keyman-config/build.sh | 57 +++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 3 deletions(-) create mode 100755 linux/keyman-config/build.sh diff --git a/linux/build.sh b/linux/build.sh index f0aaff70d5..8e2b10f289 100755 --- a/linux/build.sh +++ b/linux/build.sh @@ -5,6 +5,7 @@ set -eu ## START STANDARD BUILD SCRIPT INCLUDE # adjust relative paths as necessary THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" +# shellcheck source=resources/build/build-utils.sh . "${THIS_SCRIPT%/*}/../resources/build/build-utils.sh" ## END STANDARD BUILD SCRIPT INCLUDE @@ -15,6 +16,7 @@ cd "$THIS_SCRIPT_PATH" builder_describe \ "Build Keyman for Linux." \ ":engine=ibus-keyman ibus-keyman" \ + ":config=keyman-config keyman-config" \ "clean" \ "configure" \ "build" \ diff --git a/linux/ibus-keyman/build.sh b/linux/ibus-keyman/build.sh index a73a720924..8a16bbb1de 100755 --- a/linux/ibus-keyman/build.sh +++ b/linux/ibus-keyman/build.sh @@ -37,8 +37,7 @@ cd "$THIS_SCRIPT_PATH" builder_describe_outputs \ configure "${MESON_PATH}/build.ninja" \ - build "${MESON_PATH}/src/ibus-engine-keyman" \ - build "${MESON_PATH}/tests/ibus-keyman-tests" + build "${MESON_PATH}/src/ibus-engine-keyman" if builder_start_action clean; then rm -rf "$THIS_SCRIPT_PATH/../build/" diff --git a/linux/keyman-config/.editorconfig b/linux/keyman-config/.editorconfig index 4b530139d7..f65775da76 100644 --- a/linux/keyman-config/.editorconfig +++ b/linux/keyman-config/.editorconfig @@ -7,4 +7,7 @@ indent_size = 4 indent_style = tab [Makefile] -indent_style = tab \ No newline at end of file +indent_style = tab + +[*.sh] +indent_size = 2 diff --git a/linux/keyman-config/build.sh b/linux/keyman-config/build.sh new file mode 100755 index 0000000000..8498f201bc --- /dev/null +++ b/linux/keyman-config/build.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +set -eu + +## START STANDARD BUILD SCRIPT INCLUDE +# adjust relative paths as necessary +THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" +# shellcheck source=resources/build/build-utils.sh +. "${THIS_SCRIPT%/*}/../../resources/build/build-utils.sh" +## END STANDARD BUILD SCRIPT INCLUDE + +################################ Main script ################################ + +builder_describe \ + "Build keyman-config." \ + "clean" \ + "configure" \ + "build" \ + "test" \ + "install install artifacts" \ + "uninstall uninstall artifacts" \ + +builder_parse "$@" + +cd "$THIS_SCRIPT_PATH" + +builder_describe_outputs \ + build "keyman_config/standards/lang_tags_map.py" + +if builder_start_action clean; then + make clean + builder_finish_action success clean +fi + +if builder_start_action configure; then + builder_finish_action success configure +fi + +if builder_start_action build; then + make + builder_finish_action success build +fi + +if builder_start_action test; then + ./run-tests.sh + builder_finish_action success test +fi + +if builder_start_action install; then + make install + builder_finish_action success install +fi + +if builder_start_action uninstall; then + make uninstall + builder_finish_action success uninstall +fi -- GitLab From 009e2a11aec1e945fb1f49a9a613338d76f9cb75 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Tue, 9 May 2023 12:19:31 -0500 Subject: [PATCH 043/214] =?UTF-8?q?feat(developer):=20kmc-kmn:=20updates?= =?UTF-8?q?=20to=20uset=20api=20and=20Compiler=20=F0=9F=99=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for: #7234 Co-authored-by: Marc Durdin --- .../src/kmc-kmn/src/compiler/compiler.ts | 87 ++++++++++++------- .../src/kmc-kmn/src/compiler/messages.ts | 5 +- developer/src/kmc-kmn/test/test-compiler.ts | 27 ++++-- developer/src/kmc-kmn/test/test-wasm-uset.ts | 38 ++++---- .../src/commands/build/BuildKmnKeyboard.ts | 6 +- package-lock.json | 1 + 6 files changed, 104 insertions(+), 60 deletions(-) diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index dbdde636a9..f83c77142a 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -47,39 +47,72 @@ const baseOptions: CompilerOptions = { */ let callbackProcIdentifier = 0; +/** + * The wrapped functions + */ +class WrappedWasmFuncs { + compileKeyboardFile?: (a0: string, a1: string, a2: number, a3: number, a4: number, a5: string) => boolean; + parseUnicodeSet?: (a0: string, a1: number, a2: number) => number; + setCompilerOptions?: (shouldAddCompilerVersion: number) => boolean; + + constructor(wasmModule: any) { + this.compileKeyboardFile = wasmModule.cwrap('kmcmp_Wasm_CompileKeyboardFile', 'boolean', ['string', 'string', 'number', 'number', 'number', 'string']); + this.parseUnicodeSet = wasmModule.cwrap('kmcmp_Wasm_ParseUnicodeSet', 'number', ['string', 'number', 'number']); + this.setCompilerOptions = wasmModule.cwrap('kmcmp_Wasm_SetCompilerOptions', 'boolean', ['number']); + } + + /** + * @returns true if the functions are setup ok + */ + get ok(): boolean { + return this.parseUnicodeSet !== undefined + && this.setCompilerOptions !== undefined + && this.compileKeyboardFile !== undefined; + } +}; + export class Compiler { wasmModule: any; - compileKeyboardFile: any; - setCompilerOptions: any; callbackName: string; callbacks: CompilerCallbacks; - _parseUnicodeSet: any; + wasm: WrappedWasmFuncs; constructor() { this.callbackName = 'kmnCompilerCallback' + callbackProcIdentifier; callbackProcIdentifier++; } - public async init(): Promise { + public async init(callbacks: CompilerCallbacks): Promise { + if(!this.callbacks) { + this.callbacks = callbacks; + } if(!this.wasmModule) { this.wasmModule = await loadWasmHost(); - this.compileKeyboardFile = this.wasmModule.cwrap('kmcmp_Wasm_CompileKeyboardFile', 'boolean', ['string', 'string', - 'number', 'number', 'number', 'string']); - this.setCompilerOptions = this.wasmModule.cwrap('kmcmp_Wasm_SetCompilerOptions', 'boolean', ['number']); - this._parseUnicodeSet = this.wasmModule.cwrap('kmcmp_Wasm_ParseUnicodeSet', 'number', [ 'string', 'number', 'number']); + this.wasm = new WrappedWasmFuncs(this.wasmModule); } - return this.compileKeyboardFile !== undefined - && this.setCompilerOptions !== undefined - && this._parseUnicodeSet !== undefined; + return this.verifyInitted(); } - public run(infile: string, outfile: string, callbacks: CompilerCallbacks, options?: CompilerOptions): boolean { - this.callbacks = callbacks; - - if(!this.wasmModule) { + /** + * Verify that wasm is spun up OK. + * @returns true if OK + */ + public verifyInitted() : boolean { + if(!this.callbacks) { + // Can't report a message here. + throw Error('Must call Compiler.init(callbacks) before proceeding'); + } + if(!this.wasmModule || !this.wasm.ok) { // fail if wasm not loaded or function not found this.callbacks.reportMessage(CompilerMessages.Fatal_MissingWasmModule()); return false; } + return true; + } + + public run(infile: string, outfile: string, options?: CompilerOptions): boolean { + if(!this.verifyInitted()) { + return false; + } options = {...baseOptions, ...options}; (globalThis as any)[this.callbackName] = this.compilerMessageCallback; @@ -96,10 +129,10 @@ export class Compiler { private runCompiler(infile: string, outfile: string, options: CompilerOptions): boolean { try { - if(!this.setCompilerOptions(options.shouldAddCompilerVersion)) { + if (!this.wasm.setCompilerOptions(options.shouldAddCompilerVersion ? 1 : 0)) { this.callbacks.reportMessage(CompilerMessages.Fatal_UnableToSetCompilerOptions()); } - return this.compileKeyboardFile( + return this.wasm.compileKeyboardFile( infile, outfile, options.saveDebug ? 1 : 0, @@ -116,21 +149,21 @@ export class Compiler { * * @param pattern UnicodeSet pattern such as `[a-z]` * @param bufferSize guess as to the buffer size - * @returns UnicodeSet accessor object + * @returns UnicodeSet accessor object, or null on failure */ - public async parseUnicodeSet(pattern: string, bufferSize: number) : Promise { + public parseUnicodeSet(pattern: string, bufferSize: number) : UnicodeSet | null { + if(!this.verifyInitted()) { + return null; + } + if (!bufferSize) { bufferSize = 100; } - const initOk = await this.init(); - if (!initOk) { - throw Error(`WASM machinery didn't start up properly`); - } // Module seems to be the usual name for it const Module = this.wasmModule; const buf = Module.asm.malloc(bufferSize * 2 * Module.HEAPU32.BYTES_PER_ELEMENT); - const rc = this._parseUnicodeSet(pattern, buf, bufferSize); + const rc = this.wasm.parseUnicodeSet(pattern, buf, bufferSize); if (rc < 0) { throw new UnicodeSetError(rc); } else { // rc ≥0 @@ -167,11 +200,7 @@ export const KMCMP_FATAL_OUT_OF_RANGE = -5; * Represents a parsed UnicodeSet */ export class UnicodeSet { - pattern: string; - ranges: number[][]; - constructor(pattern: string, ranges: number[][]) { - this.pattern = pattern; - this.ranges = ranges; + constructor(public pattern: string, public ranges: number[][]) { } /** * Number of ranges diff --git a/developer/src/kmc-kmn/src/compiler/messages.ts b/developer/src/kmc-kmn/src/compiler/messages.ts index 866a19d9be..4278b35f05 100644 --- a/developer/src/kmc-kmn/src/compiler/messages.ts +++ b/developer/src/kmc-kmn/src/compiler/messages.ts @@ -47,11 +47,14 @@ export class CompilerMessages { static Fatal_UnexpectedException = (o:{e: any}) => m(this.FATAL_UnexpectedException, `Unexpected exception: ${(o.e ?? 'unknown error').toString()}\n\nCall stack:\n${(o.e instanceof Error ? o.e.stack : (new Error()).stack)}`); static FATAL_UnexpectedException = SevFatal | 0x1000; - static Fatal_MissingWasmModule = () => m(this.FATAL_MissingWasmModule, `Could not instanatiate WASM compiler module`); + static Fatal_MissingWasmModule = () => m(this.FATAL_MissingWasmModule, `Could not instantiate WASM compiler module or not initted`); static FATAL_MissingWasmModule = SevFatal | 0x1001; static Fatal_UnableToSetCompilerOptions = () => m(this.FATAL_UnableToSetCompilerOptions, `Unable to set compiler options`); static FATAL_UnableToSetCompilerOptions = SevFatal | 0x1002; + + static Fatal_CallbacksNotSet = () => m(this.FATAL_CallbacksNotSet, `Callbacks were not set with init`); + static FATAL_CallbacksNotSet = SevFatal | 0x1003; } export function mapErrorFromKmcmplib(line: number, code: number, msg: string): CompilerEvent { diff --git a/developer/src/kmc-kmn/test/test-compiler.ts b/developer/src/kmc-kmn/test/test-compiler.ts index 98ce1bd4ed..0e366a7d39 100644 --- a/developer/src/kmc-kmn/test/test-compiler.ts +++ b/developer/src/kmc-kmn/test/test-compiler.ts @@ -23,21 +23,36 @@ describe('Compiler class', function() { consoleLog.restore(); }); + it('should throw on failure', async function() { + const compiler = new Compiler(); + const callbacks : any = null; // ERROR + try { + await compiler.init(callbacks) + assert.fail('Expected exception'); + } catch(e) { + assert.ok(e); + } + assert.throws(() => compiler.verifyInitted()); + }); + it('should start', async function() { const compiler = new Compiler(); - assert(await compiler.init()); + const callbacks = new TestCompilerCallbacks(); + assert(await compiler.init(callbacks)); + assert(compiler.verifyInitted()); }); it('should compile a basic keyboard', async function() { const compiler = new Compiler(); const callbacks = new TestCompilerCallbacks(); - assert(await compiler.init()); + assert(await compiler.init(callbacks)); + assert(compiler.verifyInitted()); const fixtureName = baselineDir + 'k_000___null_keyboard.kmx'; const infile = baselineDir + 'k_000___null_keyboard.kmn'; const outfile = __dirname + '/k_000___null_keyboard.kmx'; - assert(compiler.run(infile, outfile, callbacks, {saveDebug: true, shouldAddCompilerVersion: false})); + assert(compiler.run(infile, outfile, {saveDebug: true, shouldAddCompilerVersion: false})); assert(fs.existsSync(outfile)); const outfileData = fs.readFileSync(outfile); @@ -51,7 +66,8 @@ describe('Compiler class', function() { it('should build all baseline fixtures', async function() { const compiler = new Compiler(); const callbacks = new TestCompilerCallbacks(); - assert(await compiler.init()); + assert(await compiler.init(callbacks)); + assert(compiler.verifyInitted()); const files = fs.readdirSync(baselineDir); for(let file of files) { @@ -60,7 +76,7 @@ describe('Compiler class', function() { const infile = baselineDir + file.replace(/x$/, 'n'); const outfile = __dirname + '/' + file; - assert(compiler.run(infile, outfile, callbacks, {saveDebug: true, shouldAddCompilerVersion: false})); + assert(compiler.run(infile, outfile, {saveDebug: true, shouldAddCompilerVersion: false})); assert(fs.existsSync(outfile)); const outfileData = fs.readFileSync(outfile); @@ -69,6 +85,5 @@ describe('Compiler class', function() { assert.deepEqual(outfileData, fixtureData); } } - }); }); diff --git a/developer/src/kmc-kmn/test/test-wasm-uset.ts b/developer/src/kmc-kmn/test/test-wasm-uset.ts index ff96493029..4e1295b9cd 100644 --- a/developer/src/kmc-kmn/test/test-wasm-uset.ts +++ b/developer/src/kmc-kmn/test/test-wasm-uset.ts @@ -1,31 +1,23 @@ import 'mocha'; -import sinon from 'sinon'; -import chai, { assert } from 'chai'; -import sinonChai from 'sinon-chai'; +import { assert } from 'chai'; import { Compiler } from '../src/main.js'; +import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; import { KMCMP_ERROR_HAS_STRINGS, KMCMP_ERROR_SYNTAX_ERR, KMCMP_ERROR_UNSUPPORTED_PROPERTY, KMCMP_FATAL_OUT_OF_RANGE, UnicodeSetError } from '../src/compiler/compiler.js'; -chai.use(sinonChai); - -describe('Compiler class', function() { - let consoleLog: any; - - beforeEach(function() { - consoleLog = sinon.spy(console, 'log'); - }); - - afterEach(function() { - consoleLog.restore(); - }); +describe('Compiler UnicodeSet function', function() { it('should start', async function() { const compiler = new Compiler(); - assert(await compiler.init()); + const callbacks = new TestCompilerCallbacks(); + assert(await compiler.init(callbacks)); + assert(compiler.verifyInitted()); }); it('should compile a basic uset', async function() { const compiler = new Compiler(); // const callbacks = new TestCompilerCallbacks(); - assert(await compiler.init()); + const callbacks = new TestCompilerCallbacks(); + assert(await compiler.init(callbacks)); + assert(compiler.verifyInitted()); const pat = "[abc]"; const set = await compiler.parseUnicodeSet(pat, 23); @@ -36,10 +28,12 @@ describe('Compiler class', function() { }); it('should compile a more complex uset', async function() { const compiler = new Compiler(); - assert(await compiler.init()); + const callbacks = new TestCompilerCallbacks(); + assert(await compiler.init(callbacks)); + assert(compiler.verifyInitted()); const pat = "[[🙀A-C]-[CB]]"; - const set = await compiler.parseUnicodeSet(pat, 23); + const set = compiler.parseUnicodeSet(pat, 23); assert.equal(set.length, 2); assert.equal(set.ranges[0][0], 'A'.charCodeAt(0)); @@ -49,7 +43,9 @@ describe('Compiler class', function() { }); it('should fail in various ways', async function() { const compiler = new Compiler(); - assert(await compiler.init()); + const callbacks = new TestCompilerCallbacks(); + assert(await compiler.init(callbacks)); + assert(compiler.verifyInitted()); // map from string to failing error const failures = { '[:Adlm:]': KMCMP_ERROR_UNSUPPORTED_PROPERTY, // what it saye @@ -60,7 +56,7 @@ describe('Compiler class', function() { }; for(const [pat, rc] of Object.entries(failures)) { try { - await compiler.parseUnicodeSet(pat, 1); + compiler.parseUnicodeSet(pat, 1); } catch (e) { assert(e instanceof UnicodeSetError); assert.equal(e.code, rc); diff --git a/developer/src/kmc/src/commands/build/BuildKmnKeyboard.ts b/developer/src/kmc/src/commands/build/BuildKmnKeyboard.ts index cd5b7c7ac3..2927a91059 100644 --- a/developer/src/kmc/src/commands/build/BuildKmnKeyboard.ts +++ b/developer/src/kmc/src/commands/build/BuildKmnKeyboard.ts @@ -11,7 +11,7 @@ export class BuildKmnKeyboard extends BuildActivity { public get description(): string { return 'Build a Keyman keyboard'; } public async build(infile: string, callbacks: CompilerCallbacks, options: BuildActivityOptions): Promise { let compiler = new Compiler(); - if(!await compiler.init()) { + if(!await compiler.init(callbacks)) { return false; } @@ -23,7 +23,7 @@ export class BuildKmnKeyboard extends BuildActivity { // TODO: Currently this only builds .kmn->.kmx, and targeting .js is as-yet unsupported // TODO: Support additional options compilerWarningsAsErrors, warnDeprecatedCode - return compiler.run(infile, outfile, callbacks, + return compiler.run(infile, outfile, { saveDebug: options.debug, shouldAddCompilerVersion: options.compilerVersion, @@ -49,4 +49,4 @@ function getPosixAbsolutePath(filename: string): string { filename = filename.replace(/\\/g, '/'); } return filename; -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 173ea2605f..7a7f3149c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1553,6 +1553,7 @@ "name": "@keymanapp/kmc-package", "license": "MIT", "dependencies": { + "@keymanapp/common-types": "*", "jszip": "^3.7.0" }, "devDependencies": { -- GitLab From 00b7b48af5c3b9e9265d593d35642f5365079b4b Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Tue, 9 May 2023 14:01:51 -0400 Subject: [PATCH 044/214] auto: increment master version to 17.0.104 --- HISTORY.md | 5 +++++ VERSION.md | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 274358c6a5..42c070735a 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,10 @@ # Keyman Version History +## 17.0.103 alpha 2023-05-09 + +* fix(mac): `$CONFIG` not `$CONFIGURATION` in build path (#8724) +* chore(linux): Fix another problem uploading to launchpad (#8727) + ## 17.0.102 alpha 2023-05-08 * chore(linux): Build for Lunar on all platforms (#8713) diff --git a/VERSION.md b/VERSION.md index 8885a3f7c8..ab165ae874 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.103 \ No newline at end of file +17.0.104 \ No newline at end of file -- GitLab From 348e3281bd9c79b6c2fca2e14f84dbe6d3671397 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Tue, 9 May 2023 18:40:12 -0500 Subject: [PATCH 045/214] =?UTF-8?q?feat(developer):=20kmc-kmn:=20updates?= =?UTF-8?q?=20to=20uset=20api=20and=20Compiler=20=F0=9F=99=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - use compiler messages - add some TODOs around free for: #7234 --- .../src/kmc-kmn/src/compiler/compiler.ts | 59 ++++++++++++------- .../src/kmc-kmn/src/compiler/messages.ts | 12 ++++ developer/src/kmc-kmn/test/test-wasm-uset.ts | 24 ++++---- developer/src/kmcmplib/include/kmcmplibapi.h | 6 +- 4 files changed, 62 insertions(+), 39 deletions(-) diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index f83c77142a..8b1b04e267 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -22,7 +22,7 @@ TODO: implement additional interfaces: */ // TODO: rename wasm-host? -import { CompilerCallbacks } from '@keymanapp/common-types'; +import { CompilerCallbacks, CompilerEvent } from '@keymanapp/common-types'; import loadWasmHost from '../import/kmcmplib/wasm-host.js'; import { CompilerMessages, mapErrorFromKmcmplib } from './messages.js'; @@ -157,16 +157,13 @@ export class Compiler { } if (!bufferSize) { - bufferSize = 100; + bufferSize = 100; // TODO-LDML: Preflight mode? Reuse buffer? } - - // Module seems to be the usual name for it const Module = this.wasmModule; const buf = Module.asm.malloc(bufferSize * 2 * Module.HEAPU32.BYTES_PER_ELEMENT); + // TODO-LDML: Catch OOM const rc = this.wasm.parseUnicodeSet(pattern, buf, bufferSize); - if (rc < 0) { - throw new UnicodeSetError(rc); - } else { // rc ≥0 + if (rc >= 0) { const ranges = []; const startu = (buf / Module.HEAPU32.BYTES_PER_ELEMENT); for (let i = 0; i < rc; i++) { @@ -174,28 +171,44 @@ export class Compiler { const high = Module.HEAPU32[startu + (i * 2) + 1]; ranges.push([low, high]); } + // TODO-LDML: no free?? + // Module.asm.free(buf); return new UnicodeSet(pattern, ranges); + } else { + // translate error + // TODO-LDML: no free?? + // Module.asm.free(buf); + this.callbacks.reportMessage(getUnicodeSetError(rc)); + return null; } } } -export class UnicodeSetError extends Error { - code: number; - constructor(code:number) { - super(); - this.code = code; - this.message = `UnicodeSet error: ${code}`; +/** + * translate UnicodeSet return code into a compiler event + * @param rc parseUnicodeSet error code + * @returns the compiler event + */ +function getUnicodeSetError(rc: number) : CompilerEvent { + // from kmcmplib.h + const KMCMP_ERROR_SYNTAX_ERR = -1; + const KMCMP_ERROR_HAS_STRINGS = -2; + const KMCMP_ERROR_UNSUPPORTED_PROPERTY = -3; + const KMCMP_FATAL_OUT_OF_RANGE = -4; + switch(rc) { + case KMCMP_ERROR_SYNTAX_ERR: + return CompilerMessages.Error_UnicodeSetSyntaxError(); + case KMCMP_ERROR_HAS_STRINGS: + return CompilerMessages.Error_UnicodeSetHasStrings(); + case KMCMP_ERROR_UNSUPPORTED_PROPERTY: + return CompilerMessages.Error_UnicodeSetHasProperties(); + case KMCMP_FATAL_OUT_OF_RANGE: + return CompilerMessages.Fatal_UnicodeSetOutOfRange(); + default: + return CompilerMessages.Fatal_UnexpectedException({e: `Unexpected UnicodeSet error code ${rc}`}); } } -// from kmcmplib.h -export const KMCMP_USET_OK = 0; -export const KMCMP_ERROR_SYNTAX_ERR = -1; -export const KMCMP_ERROR_HAS_STRINGS = -2; -export const KMCMP_ERROR_UNSUPPORTED_PROPERTY = -3; -export const KMCMP_ERROR_UNSUPPORTED = -4; -export const KMCMP_FATAL_OUT_OF_RANGE = -5; - /** * Represents a parsed UnicodeSet */ @@ -208,4 +221,8 @@ export class UnicodeSet { get length() : number { return this.ranges.length; } + + toString() : string { + return this.pattern; + } } diff --git a/developer/src/kmc-kmn/src/compiler/messages.ts b/developer/src/kmc-kmn/src/compiler/messages.ts index 4278b35f05..ae854f7316 100644 --- a/developer/src/kmc-kmn/src/compiler/messages.ts +++ b/developer/src/kmc-kmn/src/compiler/messages.ts @@ -55,6 +55,18 @@ export class CompilerMessages { static Fatal_CallbacksNotSet = () => m(this.FATAL_CallbacksNotSet, `Callbacks were not set with init`); static FATAL_CallbacksNotSet = SevFatal | 0x1003; + + static Fatal_UnicodeSetOutOfRange = () => m(this.FATAL_UnicodeSetOutOfRange, `UnicodeSet buffer was too small`); + static FATAL_UnicodeSetOutOfRange = SevFatal | 0x1004; + + static Error_UnicodeSetHasStrings = () => m(this.ERROR_UnicodeSetHasStrings, `UnicodeSet contains strings, not allowed`); + static ERROR_UnicodeSetHasStrings = SevError | 0x1005; + + static Error_UnicodeSetHasProperties = () => m(this.ERROR_UnicodeSetHasProperties, `UnicodeSet contains properties, not allowed`); + static ERROR_UnicodeSetHasProperties = SevError | 0x1006; + + static Error_UnicodeSetSyntaxError = () => m(this.ERROR_UnicodeSetSyntaxError, `UnicodeSet had a Syntax Error while parsing`); + static ERROR_UnicodeSetSyntaxError = SevError | 0x1007; } export function mapErrorFromKmcmplib(line: number, code: number, msg: string): CompilerEvent { diff --git a/developer/src/kmc-kmn/test/test-wasm-uset.ts b/developer/src/kmc-kmn/test/test-wasm-uset.ts index 4e1295b9cd..2fc8693a31 100644 --- a/developer/src/kmc-kmn/test/test-wasm-uset.ts +++ b/developer/src/kmc-kmn/test/test-wasm-uset.ts @@ -2,7 +2,7 @@ import 'mocha'; import { assert } from 'chai'; import { Compiler } from '../src/main.js'; import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; -import { KMCMP_ERROR_HAS_STRINGS, KMCMP_ERROR_SYNTAX_ERR, KMCMP_ERROR_UNSUPPORTED_PROPERTY, KMCMP_FATAL_OUT_OF_RANGE, UnicodeSetError } from '../src/compiler/compiler.js'; +import { CompilerMessages } from '../src/compiler/messages.js'; describe('Compiler UnicodeSet function', function() { it('should start', async function() { @@ -20,7 +20,7 @@ describe('Compiler UnicodeSet function', function() { assert(compiler.verifyInitted()); const pat = "[abc]"; - const set = await compiler.parseUnicodeSet(pat, 23); + const set = compiler.parseUnicodeSet(pat, 23); assert(set.length === 1); assert(set.ranges[0][0] === 'a'.charCodeAt(0)); @@ -48,19 +48,17 @@ describe('Compiler UnicodeSet function', function() { assert(compiler.verifyInitted()); // map from string to failing error const failures = { - '[:Adlm:]': KMCMP_ERROR_UNSUPPORTED_PROPERTY, // what it saye - '[acegik]': KMCMP_FATAL_OUT_OF_RANGE, // 6 ranges, allocated 1 - '[[\\p{Mn}]&[A-Z]]': KMCMP_ERROR_UNSUPPORTED_PROPERTY, - '[abc{def}]': KMCMP_ERROR_HAS_STRINGS, - '[[]': KMCMP_ERROR_SYNTAX_ERR, + '[:Adlm:]': CompilerMessages.ERROR_UnicodeSetHasProperties, // what it saye + '[acegik]': CompilerMessages.FATAL_UnicodeSetOutOfRange, // 6 ranges, allocated 1 + '[[\\p{Mn}]&[A-Z]]': CompilerMessages.ERROR_UnicodeSetHasProperties, + '[abc{def}]': CompilerMessages.ERROR_UnicodeSetHasStrings, + '[[]': CompilerMessages.ERROR_UnicodeSetSyntaxError, }; for(const [pat, rc] of Object.entries(failures)) { - try { - compiler.parseUnicodeSet(pat, 1); - } catch (e) { - assert(e instanceof UnicodeSetError); - assert.equal(e.code, rc); - } + callbacks.clear(); + assert.notOk(compiler.parseUnicodeSet(pat, 1)); + assert.equal(callbacks.messages.length, 1); + assert.equal(callbacks.messages[0].code, rc); } }); }); diff --git a/developer/src/kmcmplib/include/kmcmplibapi.h b/developer/src/kmcmplib/include/kmcmplibapi.h index be0f477ab9..97d46c3c36 100644 --- a/developer/src/kmcmplib/include/kmcmplibapi.h +++ b/developer/src/kmcmplib/include/kmcmplibapi.h @@ -76,14 +76,10 @@ static const int KMCMP_ERROR_HAS_STRINGS = -2; * Error: Invalid, uses properties \p{Mn} or [:Mn:] */ static const int KMCMP_ERROR_UNSUPPORTED_PROPERTY = -3; -/** - * Error: Invalid, other unsupported feature - */ -static const int KMCMP_ERROR_UNSUPPORTED = -4; /** * Fatal: output buffer too small */ -static const int KMCMP_FATAL_OUT_OF_RANGE = -5; +static const int KMCMP_FATAL_OUT_OF_RANGE = -4; /** * Function pointer to kmcmp_ParseUnicodeSet -- GitLab From 52f1d87f02d4efe9071c83c3b44476fc6268f894 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Thu, 27 Apr 2023 14:31:49 +0700 Subject: [PATCH 046/214] refactor(android/engine): Make updateSelectionRange consistent --- .../app/src/main/java/com/keyman/engine/KMManager.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java b/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java index b819be2dad..32de7e8dfe 100644 --- a/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java +++ b/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java @@ -1978,6 +1978,13 @@ public final class KMManager { boolean result = false; if (kbType == KeyboardType.KEYBOARD_TYPE_INAPP) { if (isKeyboardLoaded(KeyboardType.KEYBOARD_TYPE_INAPP) && !InAppKeyboard.shouldIgnoreSelectionChange()) { + InputConnection ic = getInputConnection(KeyboardType.KEYBOARD_TYPE_INAPP); + if (ic != null) { + ExtractedText icText = ic.getExtractedText(new ExtractedTextRequest(), 0); + if (icText != null) { + updateText(kbType, icText.text.toString()); + } + } InAppKeyboard.loadJavascript(KMString.format("updateKMSelectionRange(%d,%d)", selStart, selEnd)); result = true; } @@ -1992,7 +1999,6 @@ public final class KMManager { updateText(kbType, icText.text.toString()); } } - SystemKeyboard.loadJavascript(KMString.format("updateKMSelectionRange(%d,%d)", selStart, selEnd)); result = true; } -- GitLab From 184182f83e05770134eadbcc404754417641a5f7 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Wed, 3 May 2023 12:57:21 +0700 Subject: [PATCH 047/214] refactor(android/engine): Start refactoring updateSelectionRange --- .../java/com/keyman/engine/KMKeyboard.java | 57 +++++++++++++++++-- .../java/com/keyman/engine/KMManager.java | 38 ++----------- 2 files changed, 56 insertions(+), 39 deletions(-) diff --git a/android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboard.java b/android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboard.java index 08717b9f21..88dc290322 100644 --- a/android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboard.java +++ b/android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboard.java @@ -47,6 +47,9 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; +import android.view.inputmethod.ExtractedText; +import android.view.inputmethod.ExtractedTextRequest; +import android.view.inputmethod.InputConnection; import android.webkit.ConsoleMessage; import android.webkit.WebChromeClient; import android.webkit.WebSettings; @@ -139,7 +142,7 @@ final class KMKeyboard extends WebView { } public boolean getShouldShowHelpBubble() { - if(this._shouldShowHelpBubble == null) { + if (this._shouldShowHelpBubble == null) { SharedPreferences prefs = context.getSharedPreferences(context.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE); this._shouldShowHelpBubble = prefs.getBoolean(KMManager.KMKey_ShouldShowHelpBubble, true); } @@ -151,10 +154,54 @@ final class KMKeyboard extends WebView { this._shouldShowHelpBubble = flag; } - protected boolean shouldIgnoreTextChange() { return shouldIgnoreTextChange; } - protected void setShouldIgnoreTextChange(boolean ignore) { this.shouldIgnoreTextChange = ignore; } - protected boolean shouldIgnoreSelectionChange() { return shouldIgnoreSelectionChange; } - protected void setShouldIgnoreSelectionChange(boolean ignore) { this.shouldIgnoreSelectionChange = ignore; } + protected boolean shouldIgnoreTextChange() { + return shouldIgnoreTextChange; + } + + protected void setShouldIgnoreTextChange(boolean ignore) { + this.shouldIgnoreTextChange = ignore; + } + + protected boolean shouldIgnoreSelectionChange() { + return shouldIgnoreSelectionChange; + } + + protected void setShouldIgnoreSelectionChange(boolean ignore) { + this.shouldIgnoreSelectionChange = ignore; + } + + protected boolean updateText(String text) { + boolean result = false; + String kmText = ""; + if (text != null) { + kmText = text.toString().replace("\\", "\\u005C").replace("'", "\\u0027").replace("\n", "\\n"); + } + + if (KMManager.isKeyboardLoaded(this.keyboardType) && !shouldIgnoreTextChange) { + this.loadJavascript(KMString.format("updateKMText('%s')", kmText)); + result = true; + } + + shouldIgnoreTextChange = false; + return result; + } + + protected boolean updateSelectionRange(int selStart, int selEnd) { + boolean result = false; + InputConnection ic = KMManager.getInputConnection(this.keyboardType); + if (ic != null) { + ExtractedText icText = ic.getExtractedText(new ExtractedTextRequest(), 0); + if (icText != null) { + updateText(icText.text.toString()); + } + } + this.loadJavascript(KMString.format("updateKMSelectionRange(%d,%d)", selStart, selEnd)); + result = true; + + return result; + } + + @SuppressWarnings("deprecation") @SuppressLint("SetJavaScriptEnabled") diff --git a/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java b/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java index 32de7e8dfe..ebb8727bef 100644 --- a/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java +++ b/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java @@ -1950,25 +1950,11 @@ public final class KMManager { public static boolean updateText(KeyboardType kbType, String text) { boolean result = false; - String kmText = ""; - if (text != null) { - kmText = text.toString().replace("\\", "\\u005C").replace("'", "\\u0027").replace("\n", "\\n"); - } if (kbType == KeyboardType.KEYBOARD_TYPE_INAPP) { - if (isKeyboardLoaded(KeyboardType.KEYBOARD_TYPE_INAPP) && !InAppKeyboard.shouldIgnoreTextChange()) { - InAppKeyboard.loadJavascript(KMString.format("updateKMText('%s')", kmText)); - result = true; - } - - InAppKeyboard.setShouldIgnoreTextChange(false); + return InAppKeyboard.updateText(text); } else if (kbType == KeyboardType.KEYBOARD_TYPE_SYSTEM) { - if (isKeyboardLoaded(KeyboardType.KEYBOARD_TYPE_SYSTEM) && !SystemKeyboard.shouldIgnoreTextChange()) { - SystemKeyboard.loadJavascript(KMString.format("updateKMText('%s')", kmText)); - result = true; - } - - SystemKeyboard.setShouldIgnoreTextChange(false); + return SystemKeyboard.updateText(text); } return result; @@ -1978,29 +1964,13 @@ public final class KMManager { boolean result = false; if (kbType == KeyboardType.KEYBOARD_TYPE_INAPP) { if (isKeyboardLoaded(KeyboardType.KEYBOARD_TYPE_INAPP) && !InAppKeyboard.shouldIgnoreSelectionChange()) { - InputConnection ic = getInputConnection(KeyboardType.KEYBOARD_TYPE_INAPP); - if (ic != null) { - ExtractedText icText = ic.getExtractedText(new ExtractedTextRequest(), 0); - if (icText != null) { - updateText(kbType, icText.text.toString()); - } - } - InAppKeyboard.loadJavascript(KMString.format("updateKMSelectionRange(%d,%d)", selStart, selEnd)); - result = true; + result = InAppKeyboard.updateSelectionRange(selStart, selEnd); } InAppKeyboard.setShouldIgnoreSelectionChange(false); } else if (kbType == KeyboardType.KEYBOARD_TYPE_SYSTEM) { if (isKeyboardLoaded(KeyboardType.KEYBOARD_TYPE_SYSTEM) && !SystemKeyboard.shouldIgnoreSelectionChange()) { - InputConnection ic = getInputConnection(KeyboardType.KEYBOARD_TYPE_SYSTEM); - if (ic != null) { - ExtractedText icText = ic.getExtractedText(new ExtractedTextRequest(), 0); - if (icText != null) { - updateText(kbType, icText.text.toString()); - } - } - SystemKeyboard.loadJavascript(KMString.format("updateKMSelectionRange(%d,%d)", selStart, selEnd)); - result = true; + result = SystemKeyboard.updateSelectionRange(selStart, selEnd); } SystemKeyboard.setShouldIgnoreSelectionChange(false); -- GitLab From 7d8416dc9e670305546ab6f1f78e7c581915bee8 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 10 May 2023 09:07:23 +0700 Subject: [PATCH 048/214] chore(developer): fixup dependencies for kmc-model-info Removes the ugly cross-dependency on kmc-package, as the metadata file is now in common-types. --- developer/src/kmc-model-info/build.sh | 13 ++++--------- developer/src/kmc-model-info/package.json | 3 +-- .../src/kmc-model-info/src/model-info-compiler.ts | 4 ++-- developer/src/kmc-model-info/tsconfig.json | 3 +-- package-lock.json | 4 ++-- 5 files changed, 10 insertions(+), 17 deletions(-) diff --git a/developer/src/kmc-model-info/build.sh b/developer/src/kmc-model-info/build.sh index 02001fbc2b..7c2119826f 100755 --- a/developer/src/kmc-model-info/build.sh +++ b/developer/src/kmc-model-info/build.sh @@ -1,11 +1,4 @@ #!/usr/bin/env bash -# -# Compiles the kmc lexical model model-info compiler. -# - -# Exit on command failure and when using unset variables: -set -eu - ## START STANDARD BUILD SCRIPT INCLUDE # adjust relative paths as necessary THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" @@ -17,14 +10,16 @@ cd "$THIS_SCRIPT_PATH" . "$KEYMAN_ROOT/resources/shellHelperFunctions.sh" builder_describe "Build Keyman kmc Lexical Model model-info Compiler module" \ - "@/developer/src/kmc-package" \ + "@/common/web/types" \ + "@/common/models/types" \ + "clean" \ "configure" \ "build" \ - "clean" \ "test" \ "pack build a local .tgz pack for testing" \ "publish publish to npm" \ "--dry-run,-n don't actually publish, just dry run" + builder_describe_outputs \ configure /node_modules \ build /developer/src/kmc-model-info/build/src/model-info-compiler.js diff --git a/developer/src/kmc-model-info/package.json b/developer/src/kmc-model-info/package.json index 957056e042..709f9d2d6f 100644 --- a/developer/src/kmc-model-info/package.json +++ b/developer/src/kmc-model-info/package.json @@ -31,8 +31,7 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "dependencies": { - "@keymanapp/keyman-version": "*", - "@keymanapp/kmc-package": "*", + "@keymanapp/common-types": "*", "@keymanapp/models-types": "*" }, "devDependencies": { diff --git a/developer/src/kmc-model-info/src/model-info-compiler.ts b/developer/src/kmc-model-info/src/model-info-compiler.ts index 0cfe663816..7fd22308d5 100644 --- a/developer/src/kmc-model-info/src/model-info-compiler.ts +++ b/developer/src/kmc-model-info/src/model-info-compiler.ts @@ -7,14 +7,14 @@ import * as fs from "fs"; import * as path from "path"; import { minKeymanVersion } from "./min-keyman-version.js"; import { ModelInfoFile } from "./model-info-file.js"; -import { type KmpJsonFile } from "@keymanapp/kmc-package"; +import { KmpJsonFile } from "@keymanapp/common-types"; export class ModelInfoOptions { /** The identifier for the model */ model_id: string; /** The data from the .kps file, transformed to kmp.json */ - kmpJsonData: KmpJsonFile; + kmpJsonData: KmpJsonFile.KmpJsonFile; /** The path in the keymanapp/lexical-models repo where this model may be found (optional) */ sourcePath?: string; diff --git a/developer/src/kmc-model-info/tsconfig.json b/developer/src/kmc-model-info/tsconfig.json index 83aa040f1a..1e6ba49b19 100644 --- a/developer/src/kmc-model-info/tsconfig.json +++ b/developer/src/kmc-model-info/tsconfig.json @@ -12,8 +12,7 @@ "src/**/*.ts" ], "references": [ - { "path": "../kmc-package" }, // can we eliminate this in future? - { "path": "../../../common/web/keyman-version/tsconfig.esm.json"}, + { "path": "../../../common/web/types" }, { "path": "../../../common/models/types" }, ] } diff --git a/package-lock.json b/package-lock.json index 173ea2605f..e10338c55d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1270,8 +1270,7 @@ "name": "@keymanapp/kmc-model-info", "license": "MIT", "dependencies": { - "@keymanapp/keyman-version": "*", - "@keymanapp/kmc-package": "*", + "@keymanapp/common-types": "*", "@keymanapp/models-types": "*" }, "devDependencies": { @@ -1553,6 +1552,7 @@ "name": "@keymanapp/kmc-package", "license": "MIT", "dependencies": { + "@keymanapp/common-types": "*", "jszip": "^3.7.0" }, "devDependencies": { -- GitLab From dbc64bcbb02c5306f30a9bce9d3975e54139ca42 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 10 May 2023 11:50:54 +0700 Subject: [PATCH 049/214] feat(developer): add package validation Adds a package-validation.ts module, plus adds a call to the validation step in the compilers. Rearranges the kmc-package files to match other compilers better. Removes `default` from exports. And finally, adds ERROR_PackageCannotContainBothModelsAndKeyboards and WARN_PackageShouldNotRepeatLanguages messages, plus tests. --- developer/src/kmc-package/package.json | 3 +- .../src/{ => compiler}/kmp-compiler.ts | 2 +- .../src/{ => compiler}/messages.ts | 6 +++ .../src/compiler/package-validation.ts | 42 ++++++++++++++++ developer/src/kmc-package/src/main.ts | 2 + ...ageCannotContainBothModelsAndKeyboards.kps | 49 +++++++++++++++++++ .../WARN_PackageShouldNotRepeatLanguages.kps | 33 +++++++++++++ .../src/kmc-package/test/test-messages.ts | 2 +- .../kmc-package/test/test-package-compiler.ts | 31 ++++++++++-- .../kmc/src/commands/build/BuildPackage.ts | 11 ++++- developer/src/kmc/src/kmlmp.ts | 18 ++++++- 11 files changed, 187 insertions(+), 12 deletions(-) rename developer/src/kmc-package/src/{ => compiler}/kmp-compiler.ts (99%) rename developer/src/kmc-package/src/{ => compiler}/messages.ts (84%) create mode 100644 developer/src/kmc-package/src/compiler/package-validation.ts create mode 100644 developer/src/kmc-package/src/main.ts create mode 100644 developer/src/kmc-package/test/fixtures/invalid/ERROR_PackageCannotContainBothModelsAndKeyboards.kps create mode 100644 developer/src/kmc-package/test/fixtures/invalid/WARN_PackageShouldNotRepeatLanguages.kps diff --git a/developer/src/kmc-package/package.json b/developer/src/kmc-package/package.json index 2183e3c202..1595dc21ec 100644 --- a/developer/src/kmc-package/package.json +++ b/developer/src/kmc-package/package.json @@ -8,8 +8,7 @@ ], "type": "module", "exports": { - ".": "./build/src/kmp-compiler.js", - "./kmp-json-file": "./build/src/kmp-json-file.js" + ".": "./build/src/main.js" }, "files": [ "/build/src/" diff --git a/developer/src/kmc-package/src/kmp-compiler.ts b/developer/src/kmc-package/src/compiler/kmp-compiler.ts similarity index 99% rename from developer/src/kmc-package/src/kmp-compiler.ts rename to developer/src/kmc-package/src/compiler/kmp-compiler.ts index f52c356ab1..160182edb1 100644 --- a/developer/src/kmc-package/src/kmp-compiler.ts +++ b/developer/src/kmc-package/src/compiler/kmp-compiler.ts @@ -8,7 +8,7 @@ import { KmpJsonFile, KpsFile, KMX, KmxFileReader } from '@keymanapp/common-type const FILEVERSION_KMP_JSON = '12.0'; -export default class KmpCompiler { +export class KmpCompiler { constructor(private callbacks: CompilerCallbacks) { } diff --git a/developer/src/kmc-package/src/messages.ts b/developer/src/kmc-package/src/compiler/messages.ts similarity index 84% rename from developer/src/kmc-package/src/messages.ts rename to developer/src/kmc-package/src/compiler/messages.ts index 3d2ba22434..3d252682e2 100644 --- a/developer/src/kmc-package/src/messages.ts +++ b/developer/src/kmc-package/src/compiler/messages.ts @@ -47,6 +47,12 @@ export class CompilerMessages { `Keyboard file ${o.filename} has no &KeyboardVersion store`); static WARN_KeyboardFileHasNoKeyboardVersion = SevWarn | 0x000A; + static Error_PackageCannotContainBothModelsAndKeyboards = () => m(this.ERROR_PackageCannotContainBothModelsAndKeyboards, + `The package contains both lexical models and keyboards, which is not permitted.`); + static ERROR_PackageCannotContainBothModelsAndKeyboards = SevError | 0x000B; + static Warn_PackageShouldNotRepeatLanguages = (o:{resourceType: string, id: string, tag: string}) => m(this.WARN_PackageShouldNotRepeatLanguages, + `The ${o.resourceType} ${o.id} has a repeated language "${o.tag}".`); + static WARN_PackageShouldNotRepeatLanguages = SevWarn | 0x000C; } diff --git a/developer/src/kmc-package/src/compiler/package-validation.ts b/developer/src/kmc-package/src/compiler/package-validation.ts new file mode 100644 index 0000000000..0a23897ae7 --- /dev/null +++ b/developer/src/kmc-package/src/compiler/package-validation.ts @@ -0,0 +1,42 @@ +import { KmpJsonFile, CompilerCallbacks } from '@keymanapp/common-types'; +import { CompilerMessages } from './messages.js'; + +export class PackageValidation { + + constructor(private callbacks: CompilerCallbacks) { + } + + public validate(kmpJson: KmpJsonFile.KmpJsonFile) { + if(!this.checkLexicalModels(kmpJson)) { + return false; + } + return true; + } + + private checkForDuplicatedLanguages(resourceType: 'keyboard'|'model', id: string, languages: KmpJsonFile.KmpJsonFileLanguage[]) { + let tags: {[index:string]: boolean} = {}; + for(let lang of languages) { + const langTag = lang.id.toLowerCase(); + if(tags[langTag]) { + this.callbacks.reportMessage(CompilerMessages.Warn_PackageShouldNotRepeatLanguages({resourceType:resourceType, id:id, tag:lang.id})); + } else { + tags[langTag] = true; + } + } + } + + private checkLexicalModels(kmpJson: KmpJsonFile.KmpJsonFile): boolean { + if(kmpJson.lexicalModels?.length > 0 && kmpJson.keyboards?.length > 0) { + this.callbacks.reportMessage(CompilerMessages.Error_PackageCannotContainBothModelsAndKeyboards()); + return false; + } + + if(kmpJson.lexicalModels) { + for(let model of kmpJson.lexicalModels) { + this.checkForDuplicatedLanguages('model', model.id, model.languages); + } + } + + return true; + } +} diff --git a/developer/src/kmc-package/src/main.ts b/developer/src/kmc-package/src/main.ts new file mode 100644 index 0000000000..5903a59de3 --- /dev/null +++ b/developer/src/kmc-package/src/main.ts @@ -0,0 +1,2 @@ +export { KmpCompiler } from "./compiler/kmp-compiler.js"; +export { PackageValidation } from "./compiler/package-validation.js"; \ No newline at end of file diff --git a/developer/src/kmc-package/test/fixtures/invalid/ERROR_PackageCannotContainBothModelsAndKeyboards.kps b/developer/src/kmc-package/test/fixtures/invalid/ERROR_PackageCannotContainBothModelsAndKeyboards.kps new file mode 100644 index 0000000000..c87b6808c7 --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/ERROR_PackageCannotContainBothModelsAndKeyboards.kps @@ -0,0 +1,49 @@ + + + + 15.0.266.0 + 7.0 + + + Khmer Angkor + © 2015-2022 SIL International + Makara Sok + + https://keyman.com/keyboards/khmer_angkor + + + + nokeyboardversion.kmx + Keyboard Khmer Angkor + 0 + .kmx + + + example.qaa.sencoten.model.js + Lexical model example.qaa.sencoten.model.js + 0 + .model.js + + + + + + SENĆOŦEN dictionary + example.qaa.sencoten + + North Straits Salish + SENĆOŦEN + + + + + + Khmer Angkor + nokeyboardversion + 1.3 + + Central Khmer (Khmer, Cambodia) + + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageShouldNotRepeatLanguages.kps b/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageShouldNotRepeatLanguages.kps new file mode 100644 index 0000000000..0fdb270321 --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageShouldNotRepeatLanguages.kps @@ -0,0 +1,33 @@ + + + + 15.0.266.0 + 7.0 + + + SENĆOŦEN (Saanich Dialect) Lexical Model + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.0.3 + + + + example.qaa.sencoten.model.js + Lexical model example.qaa.sencoten.model.js + 0 + .model.js + + + + + SENĆOŦEN dictionary + example.qaa.sencoten + + North Straits Salish + + Salish Again + SENĆOŦEN + + + + diff --git a/developer/src/kmc-package/test/test-messages.ts b/developer/src/kmc-package/test/test-messages.ts index d6040b28db..48976fc6ad 100644 --- a/developer/src/kmc-package/test/test-messages.ts +++ b/developer/src/kmc-package/test/test-messages.ts @@ -1,6 +1,6 @@ import 'mocha'; -import { CompilerMessages } from '../src/messages.js'; import { verifyCompilerMessagesObject } from '@keymanapp/developer-test-helpers'; +import { CompilerMessages } from '../src/compiler/messages.js'; describe('CompilerMessages', function () { it('should have a valid CompilerMessages object', function() { diff --git a/developer/src/kmc-package/test/test-package-compiler.ts b/developer/src/kmc-package/test/test-package-compiler.ts index 1faf65d8cc..0dc0ca6249 100644 --- a/developer/src/kmc-package/test/test-package-compiler.ts +++ b/developer/src/kmc-package/test/test-package-compiler.ts @@ -1,15 +1,17 @@ import 'mocha'; import * as fs from 'fs'; -import {assert} from 'chai'; - -import KmpCompiler from '../src/kmp-compiler.js'; -import {makePathToFixture} from './helpers/index.js'; +import { assert } from 'chai'; import JSZip from 'jszip'; + import KEYMAN_VERSION from "@keymanapp/keyman-version"; import { KmpJsonFile } from '@keymanapp/common-types'; import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; -import { CompilerMessages } from '../src/messages.js'; +import { makePathToFixture } from './helpers/index.js'; + +import { KmpCompiler } from '../src/compiler/kmp-compiler.js'; +import { PackageValidation } from '../src/compiler/package-validation.js'; +import { CompilerMessages } from '../src/compiler/messages.js'; describe('KmpCompiler', function () { const MODELS : string[] = [ @@ -157,11 +159,18 @@ describe('KmpCompiler', function () { const kmpCompiler = new KmpCompiler(callbacks); let kmpJson = kmpCompiler.transformKpsToKmpObject(kpsPath); + if(kmpJson && callbacks.messages.length == 0) { + const validator = new PackageValidation(callbacks); + validator.validate(kmpJson); // we'll ignore return value and rely on the messages + } + if(kmpJson && callbacks.messages.length == 0) { // We'll try building the package if we have not yet received any messages kmpCompiler.buildKmpFile(kpsPath, kmpJson) } + //TODO: callbacks.printMessages(); after #8711 is merged + if(messageId) { assert.lengthOf(callbacks.messages, 1); assert.isTrue(callbacks.hasMessage(messageId)); @@ -210,4 +219,16 @@ describe('KmpCompiler', function () { testForMessage(this, ['invalid', 'nokeyboardversion.kps'], CompilerMessages.WARN_KeyboardFileHasNoKeyboardVersion); }); + // ERROR_PackageCannotContainBothModelsAndKeyboards + + it('should generate ERROR_PackageCannotContainBothModelsAndKeyboards if package has both keyboards and models', async function() { + testForMessage(this, ['invalid', 'ERROR_PackageCannotContainBothModelsAndKeyboards.kps'], CompilerMessages.ERROR_PackageCannotContainBothModelsAndKeyboards); + }); + + // WARN_PackageShouldNotRepeatLanguages + + it('should generate WARN_PackageShouldNotRepeatLanguages if model has same language repeated', async function() { + testForMessage(this, ['invalid', 'WARN_PackageShouldNotRepeatLanguages.kps'], CompilerMessages.WARN_PackageShouldNotRepeatLanguages); + }); + }); diff --git a/developer/src/kmc/src/commands/build/BuildPackage.ts b/developer/src/kmc/src/commands/build/BuildPackage.ts index 29a2d3b068..4342a57094 100644 --- a/developer/src/kmc/src/commands/build/BuildPackage.ts +++ b/developer/src/kmc/src/commands/build/BuildPackage.ts @@ -1,7 +1,7 @@ import * as fs from 'fs'; import { BuildActivity, BuildActivityOptions } from './BuildActivity.js'; -import KmpCompiler from '@keymanapp/kmc-package'; import { CompilerCallbacks } from '@keymanapp/common-types'; +import { KmpCompiler, PackageValidation } from '@keymanapp/kmc-package'; export class BuildPackage extends BuildActivity { public get name(): string { return 'Package'; } @@ -22,6 +22,15 @@ export class BuildPackage extends BuildActivity { return false; } + // + // Validate the package file + // + + const validation = new PackageValidation(callbacks); + if(!validation.validate(kmpJsonData)) { + return false; + } + // // Build the .kmp package file // diff --git a/developer/src/kmc/src/kmlmp.ts b/developer/src/kmc/src/kmlmp.ts index 202bfce254..49d38846af 100644 --- a/developer/src/kmc/src/kmlmp.ts +++ b/developer/src/kmc/src/kmlmp.ts @@ -3,9 +3,11 @@ * kmlmp - Keyman Lexical Model Package Compiler */ +// Note: this is a deprecated package and will be removed in Keyman 18.0 + import * as fs from 'fs'; import { Command } from 'commander'; -import KmpCompiler from '@keymanapp/kmc-package'; +import { PackageValidation, KmpCompiler } from '@keymanapp/kmc-package'; import { SysExits } from './util/sysexits.js'; import KEYMAN_VERSION from "@keymanapp/keyman-version"; import { NodeCompilerCallbacks } from './messages/NodeCompilerCallbacks.js'; @@ -15,7 +17,7 @@ const program = new Command(); /* Arguments */ program - .description('Compiles Keyman lexical model packages') + .description('Compiles Keyman lexical model packages\nDeprecated: use instead; will be removed in v18') .version(KEYMAN_VERSION.VERSION_WITH_TAG) .arguments('') .action(infile => inputFilename = infile) @@ -38,6 +40,18 @@ let outputFilename: string = program.opts().outFile ? program.opts().outFile : i const callbacks = new NodeCompilerCallbacks(); let kmpCompiler = new KmpCompiler(callbacks); let kmpJsonData = kmpCompiler.transformKpsToKmpObject(inputFilename); +if(!kmpJsonData) { + process.exit(1); +} + +// +// Validate the package file +// + +const validation = new PackageValidation(callbacks); +if(!validation.validate(kmpJsonData)) { + process.exit(1); +} // // Build the .kmp package file -- GitLab From 6c17f4851a9e465f61d8b57c0ad1dd7ee7c62857 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 10 May 2023 11:57:40 +0700 Subject: [PATCH 050/214] feat(developer): add validation for keyboards in package Adds validation for WARN_PackageShouldNotRepeatLanguages for keyboards plus unit test. --- .../src/compiler/package-validation.ts | 13 ++++++++ .../WARN_PackageShouldNotRepeatLanguages.kps | 24 +++++++------- ..._PackageShouldNotRepeatLanguages.model.kps | 33 +++++++++++++++++++ .../kmc-package/test/test-package-compiler.ts | 8 ++++- 4 files changed, 65 insertions(+), 13 deletions(-) create mode 100644 developer/src/kmc-package/test/fixtures/invalid/WARN_PackageShouldNotRepeatLanguages.model.kps diff --git a/developer/src/kmc-package/src/compiler/package-validation.ts b/developer/src/kmc-package/src/compiler/package-validation.ts index 0a23897ae7..be98a4829a 100644 --- a/developer/src/kmc-package/src/compiler/package-validation.ts +++ b/developer/src/kmc-package/src/compiler/package-validation.ts @@ -7,6 +7,9 @@ export class PackageValidation { } public validate(kmpJson: KmpJsonFile.KmpJsonFile) { + if(!this.checkKeyboards(kmpJson)) { + return false; + } if(!this.checkLexicalModels(kmpJson)) { return false; } @@ -39,4 +42,14 @@ export class PackageValidation { return true; } + + private checkKeyboards(kmpJson: KmpJsonFile.KmpJsonFile): boolean { + if(kmpJson.keyboards) { + for(let keyboard of kmpJson.keyboards) { + this.checkForDuplicatedLanguages('keyboard', keyboard.id, keyboard.languages); + } + } + + return true; + } } diff --git a/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageShouldNotRepeatLanguages.kps b/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageShouldNotRepeatLanguages.kps index 0fdb270321..c24f3897f6 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageShouldNotRepeatLanguages.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageShouldNotRepeatLanguages.kps @@ -12,22 +12,22 @@ - example.qaa.sencoten.model.js - Lexical model example.qaa.sencoten.model.js + nokeyboardversion.kmx + Keyboard Khmer Angkor 0 - .model.js + .kmx - - - SENĆOŦEN dictionary - example.qaa.sencoten + + + Khmer Angkor + nokeyboardversion + 1.3 - North Straits Salish - Salish Again - SENĆOŦEN + Central Khmer (Khmer, Cambodia) + Khmer - - + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageShouldNotRepeatLanguages.model.kps b/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageShouldNotRepeatLanguages.model.kps new file mode 100644 index 0000000000..0fdb270321 --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageShouldNotRepeatLanguages.model.kps @@ -0,0 +1,33 @@ + + + + 15.0.266.0 + 7.0 + + + SENĆOŦEN (Saanich Dialect) Lexical Model + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.0.3 + + + + example.qaa.sencoten.model.js + Lexical model example.qaa.sencoten.model.js + 0 + .model.js + + + + + SENĆOŦEN dictionary + example.qaa.sencoten + + North Straits Salish + + Salish Again + SENĆOŦEN + + + + diff --git a/developer/src/kmc-package/test/test-package-compiler.ts b/developer/src/kmc-package/test/test-package-compiler.ts index 0dc0ca6249..100bc04d4b 100644 --- a/developer/src/kmc-package/test/test-package-compiler.ts +++ b/developer/src/kmc-package/test/test-package-compiler.ts @@ -225,9 +225,15 @@ describe('KmpCompiler', function () { testForMessage(this, ['invalid', 'ERROR_PackageCannotContainBothModelsAndKeyboards.kps'], CompilerMessages.ERROR_PackageCannotContainBothModelsAndKeyboards); }); - // WARN_PackageShouldNotRepeatLanguages + // WARN_PackageShouldNotRepeatLanguages (models) it('should generate WARN_PackageShouldNotRepeatLanguages if model has same language repeated', async function() { + testForMessage(this, ['invalid', 'WARN_PackageShouldNotRepeatLanguages.model.kps'], CompilerMessages.WARN_PackageShouldNotRepeatLanguages); + }); + + // WARN_PackageShouldNotRepeatLanguages (keyboards) + + it('should generate WARN_PackageShouldNotRepeatLanguages if keyboard has same language repeated', async function() { testForMessage(this, ['invalid', 'WARN_PackageShouldNotRepeatLanguages.kps'], CompilerMessages.WARN_PackageShouldNotRepeatLanguages); }); -- GitLab From 97837d2021dc2dd4120165f142ac9b20c2dee493 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 10 May 2023 12:50:39 +0700 Subject: [PATCH 051/214] feat(common): add `builder_run_action` shorthand function --- developer/src/kmc-model/build.sh | 60 +++++--------------- resources/build/build-utils.md | 95 ++++++++++++++++++++++++++++---- resources/builder.inc.sh | 43 +++++++++++++++ 3 files changed, 141 insertions(+), 57 deletions(-) diff --git a/developer/src/kmc-model/build.sh b/developer/src/kmc-model/build.sh index 8479610c0a..ecf58e20e4 100755 --- a/developer/src/kmc-model/build.sh +++ b/developer/src/kmc-model/build.sh @@ -1,33 +1,28 @@ #!/usr/bin/env bash -# -# Compiles the kmc lexical model compiler. -# - -# Exit on command failure and when using unset variables: -set -eu - ## START STANDARD BUILD SCRIPT INCLUDE # adjust relative paths as necessary THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "${THIS_SCRIPT%/*}/../../../resources/build/build-utils.sh" ## END STANDARD BUILD SCRIPT INCLUDE -cd "$THIS_SCRIPT_PATH" - . "$KEYMAN_ROOT/resources/shellHelperFunctions.sh" +. "$KEYMAN_ROOT/resources/build/build-utils-ci.inc.sh" + +cd "$THIS_SCRIPT_PATH" # TODO: "@/common/models/types" \ builder_describe "Build Keyman kmc Lexical Model Compiler module" \ "@/common/web/keyman-version" \ "@/developer/src/common/web/test-helpers" \ + "clean" \ "configure" \ "build" \ - "clean" \ "test" \ "pack build a local .tgz pack for testing" \ "publish publish to npm" \ "--dry-run,-n don't actually publish, just dry run" + builder_describe_outputs \ configure /node_modules \ build /developer/src/kmc-model/build/src/main.js @@ -36,44 +31,15 @@ builder_parse "$@" #------------------------------------------------------------------------------------------------------------------- -if builder_start_action clean; then - rm -rf ./build/ ./tsconfig.tsbuildinfo - builder_finish_action success clean -fi - -#------------------------------------------------------------------------------------------------------------------- - -if builder_start_action configure; then - verify_npm_setup - builder_finish_action success configure -fi - -#------------------------------------------------------------------------------------------------------------------- - -if builder_start_action build; then - # Note: build-cjs only emits lexical-model-compiler.cjs at this time, as that - # is the only file required by other non-ES modules - # (common/web/input-processor tests) +function do_build() { mkdir -p build/cjs-src npm run build - builder_finish_action success build -fi +} -#------------------------------------------------------------------------------------------------------------------- - -if builder_start_action test; then - npm test - builder_finish_action success test -fi - -#------------------------------------------------------------------------------------------------------------------- +builder_run_action clean rm -rf ./build/ ./tsconfig.tsbuildinfo +builder_run_action configure verify_npm_setup +builder_run_action build do_build +builder_run_action test npm test +builder_run_action publish builder_publish_to_npm +builder_run_action pack builder_publish_to_pack -if builder_start_action publish; then - . "$KEYMAN_ROOT/resources/build/build-utils-ci.inc.sh" - builder_publish_to_npm - builder_finish_action success publish -elif builder_start_action pack; then - . "$KEYMAN_ROOT/resources/build/build-utils-ci.inc.sh" - builder_publish_to_pack - builder_finish_action success pack -fi diff --git a/resources/build/build-utils.md b/resources/build/build-utils.md index f6be8b3fc7..6c27e5e8a4 100644 --- a/resources/build/build-utils.md +++ b/resources/build/build-utils.md @@ -267,7 +267,7 @@ fi Each step is run separately, is started with [`builder_start_action`], and finishes with [`builder_finish_action`]. If a build step is complex, it may be worthwhile splitting it into a separate function or even a separate script -include. +include. See also [`builder_run_action`]. Use the longer form of `if ...; then` rather than the shorter `[ ... ] && ` pattern, for consistency and readability. @@ -303,10 +303,10 @@ have described outputs for them, and the outputs do not exist, and the dependency is required for one of the targets specified on the command line. The build order of dependencies is determined by the order in which -`builder_start_action` is called in the script for each action. +[`builder_start_action`] is called in the script for each action. You can also define your own internal dependencies with -`builder_describe_internal_dependency`. This allows you to define dependencies +[`builder_describe_internal_dependency`]. This allows you to define dependencies across targets. Use this judiciously; for example, Keyman Core uses this to build both x86_64 and arm64 targets, and test only the appropriate architecture on macOS. @@ -343,7 +343,7 @@ npm test -- $builder_debug ## `builder_describe` function Describes a build script, defines available parameters and their meanings. Use -together with `builder_parse` to process input parameters. +together with [`builder_parse`] to process input parameters. ### Usage @@ -391,7 +391,7 @@ builder_describe "Sample script" :engine ":proxy the proxy module" ``` There are several predefined targets. These will not be available to users of -your script unless you include them in the `builder_describe` call, but when +your script unless you include them in the [`builder_describe`] call, but when used, they have default descriptions, which can be used instead of adding your own in the call: * `:project`: `"this project"` @@ -515,15 +515,46 @@ builder_describe_internal_dependency \ ``` **Note:** actions and targets must be fully specified, and this _must_ be called -before either builder_describe_outputs or builder_parse in order for +before either [`builder_describe_outputs`] or [`builder_parse`] in order for dependencies to be resolved. -------------------------------------------------------------------------------- +## `builder_describe_outputs` function + +Defines an output file or folder expected to be present after successful +completion of an action for a target. Used to skip actions for dependency +builds. If `:target` is not provided, assumes `:project`. + +Relative paths are relative to script folder; absolute paths are relative to +repository root, not filesystem root. + +### Usage + +```bash + builder_describe_outputs action:target filename [...] +``` + +### Parameters + +* 1: `action[:target]` action and/or target associated with file +* 2: `filename` name of file or folder to check +* 3+: ... repeat previous arguments for additional outputs + +### Example + +```bash + builder_describe_outputs \ + "configure" "/node_modules" \ + "build" "build/index.js" +``` + +-------------------------------------------------------------------------------- + ## `builder_display_usage` function Prints the help for the script, constructed from the [`builder_describe`] -parameters, so must be called after `builder_describe`. +parameters, so must be called after [`builder_describe`]. ### Usage @@ -600,7 +631,7 @@ white for top-level builds and child builds. ## `builder_echo_debug` function -Wraps the `builder_echo` command with debug mode and a `[DEBUG]` prefix. +Wraps the [`builder_echo`] command with debug mode and a `[DEBUG]` prefix. ### Usage @@ -666,6 +697,7 @@ fi These last two parameters can optionally be space separated. ### Description + In normal circumstances, `builder_finish_action` will then print a corresponding message: @@ -752,7 +784,7 @@ fi ### Description The `--debug` standard option is currently handled differently to other options. -It should never be declared in `builder_describe`, because it is always +It should never be declared in [`builder_describe`], because it is always available anyway. `--debug` is automatically passed to child scripts and dependency scripts. @@ -779,6 +811,46 @@ correct quoting and escaping. -------------------------------------------------------------------------------- +## `builder_run_action` function + +Wraps [`builder_start_action'] and [`builder_finish`] commands in a shorthand +style for single-command actions. Can be used together with a local function for +multi-command actions. Do be aware that this pseudo-closure style cannot be +mixed with operators such as `<`, `>`, `&&`, `;`, `()` and so on. + +### Usage + +```bash + builder_run_action action[:target] command [command-params...] +``` + +### Parameters + +* 1: `action[:target]` name of action, and optionally also target, if target + excluded starts for all defined targets +* 2: command command to run if action is started +* 3...: command-params parameters for command + +### Example + +The following example shows a sensible pattern to use when you have a single +multi-command action and other single-command actions. If most of your actions +are multi-command, you may choose to use this approach, or stick with the +longhand form. + +```bash + function do_build() { + mkdir -p build/cjs-src + npm run build + } + + builder_run_action clean rm -rf ./build/ ./tsconfig.tsbuildinfo + builder_run_action configure verify_npm_setup + builder_run_action build do_build +``` + +-------------------------------------------------------------------------------- + ## `builder_run_child_actions` function Executes the specified actions on or all child targets, or on the specified @@ -937,6 +1009,8 @@ Note: it is recommended that you use `$(builder_term text)` instead of [standard builder parameters]: #standard-builder-parameters [`builder_describe`]: #builderdescribe-function +[`builder_describe_outputs`]: #builderdescribeoutputs-function +[`builder_describe_internal_dependency`]: #builderdescribeinternaldependency-function [`builder_display_usage`]: #builderdisplayusage-function [`$builder_extra_params`]: #builderextraparams-variable [`builder_finish_action`]: #builderfinishaction-function @@ -947,8 +1021,9 @@ Note: it is recommended that you use `$(builder_term text)` instead of [`builder_use_color`]: #builderusecolor-function [`$builder_verbose`]: #builderverbose-variable [formatting variables]: #formatting-variables +[`builder_run_action`]: #builderrunaction-function [`builder_run_child_actions`]: #builderrunchildactions-function [`builder_echo`]: #builderecho-function [`builder_die`]: #builderdie-function [`builder_echo_debug`]: #builderechodebug-function -[`builder_is_debug_build`]: #builderisdebugbuild-function +[`builder_is_debug_build`]: #builderisdebugbuild-function \ No newline at end of file diff --git a/resources/builder.inc.sh b/resources/builder.inc.sh index 385d03816f..fb474fcfc0 100755 --- a/resources/builder.inc.sh +++ b/resources/builder.inc.sh @@ -523,6 +523,49 @@ builder_has_action() { fi } +# +# Wraps builder_start_action and builder_finish action for single-command +# actions. Can be used together with a local function for multi-command actions. +# Do be aware that this pseudo-closure style cannot be mixed with operators such +# as `<`, `>`, `&&`, `;`, `()` and so on. +# +# ### Usage +# +# ```bash +# builder_run_action action[:target] command [command-params...] +# ``` +# +# ### Parameters +# +# * 1: `action[:target]` name of action, and optionally also target, if target +# excluded starts for all defined targets +# * 2: command command to run if action is started +# * 3...: command-params parameters for command +# +# ### Example +# +# ```bash +# function do_build() { +# mkdir -p build/cjs-src +# npm run build +# } +# +# builder_run_action clean rm -rf ./build/ ./tsconfig.tsbuildinfo +# builder_run_action configure verify_npm_setup +# builder_run_action build do_build +# ``` +# +function builder_run_action() { + local action=$1 + shift + echo "builder_run_action $action $@" + if builder_start_action $action; then + ($@) + builder_finish_action success $action + fi + return 0 +} + # # Returns `0` if the user has asked to perform action on target on the command # line, and then starts the action. Should be paired with -- GitLab From 7cf891b7c0fd9de1314488d17e1b89588583d129 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 10 May 2023 12:56:26 +0700 Subject: [PATCH 052/214] chore(developer): add validation to kmlmi --- developer/src/kmc/src/kmlmi.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/developer/src/kmc/src/kmlmi.ts b/developer/src/kmc/src/kmlmi.ts index de379e6372..d0d1a01bd4 100644 --- a/developer/src/kmc/src/kmlmi.ts +++ b/developer/src/kmc/src/kmlmi.ts @@ -5,8 +5,8 @@ import * as path from 'path'; import { Command } from 'commander'; -import KmpCompiler from '@keymanapp/kmc-package'; -import { ModelInfoOptions as ModelInfoOptions, writeMergedModelMetadataFile } from '@keymanapp/kmc-model-info'; +import { KmpCompiler, PackageValidation } from '@keymanapp/kmc-package'; +import { ModelInfoOptions, writeMergedModelMetadataFile } from '@keymanapp/kmc-model-info'; import { SysExits } from './util/sysexits.js'; import KEYMAN_VERSION from "@keymanapp/keyman-version"; import { NodeCompilerCallbacks } from './messages/NodeCompilerCallbacks.js'; @@ -49,6 +49,15 @@ const callbacks = new NodeCompilerCallbacks(); let kmpCompiler = new KmpCompiler(callbacks); let kmpJsonData = kmpCompiler.transformKpsToKmpObject(kpsFilename); +// +// Validate the package file +// + +const validation = new PackageValidation(callbacks); +if(!validation.validate(kmpJsonData)) { + process.exit(1); +} + // // Write out the merged .model_info file // -- GitLab From c4abc4fadbc153f592de8e6105a096c5fb58768f Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 10 May 2023 22:20:57 +1000 Subject: [PATCH 053/214] chore(windows): remove keyman_forcekeyboard --- windows/src/engine/keyman32/keyman32.cpp | 110 +---------------------- windows/src/engine/keyman32/keyman32.def | 2 - 2 files changed, 1 insertion(+), 111 deletions(-) diff --git a/windows/src/engine/keyman32/keyman32.cpp b/windows/src/engine/keyman32/keyman32.cpp index 3b0953afae..7444a696d4 100644 --- a/windows/src/engine/keyman32/keyman32.cpp +++ b/windows/src/engine/keyman32/keyman32.cpp @@ -535,120 +535,12 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_RestartEngine() /* */ /*******************************************************************************************/ -extern "C" BOOL _declspec(dllexport) WINAPI Keyman_StopForcingKeyboard(); -void RefreshPreservedKeys(BOOL Activating); - -extern "C" BOOL _declspec(dllexport) WINAPI Keyman_ForceKeyboard(PCSTR FileName) -{ - SendDebugMessageFormat(0,sdmGlobal,0,"Keyman_ForceKeyboard: ENTER %s", FileName); - - Keyman_StopForcingKeyboard(); // 7.0.219.0 - - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return FALSE; - - strncpy(_td->ForceFileName, FileName, MAX_PATH - 1); - _td->ForceFileName[MAX_PATH-1] = 0; - - if(_td->lpActiveKeyboard) - { - DeactivateDLLs(_td->lpActiveKeyboard); - } - _td->lpActiveKeyboard = new INTKEYBOARDINFO; - memset(_td->lpActiveKeyboard, 0, sizeof(INTKEYBOARDINFO)); // I2437 - Crash unloading keyboard due to keyboard options not init - - _splitpath_s(FileName, NULL, 0, NULL, 0, _td->lpActiveKeyboard->Name, sizeof(_td->lpActiveKeyboard->Name), NULL, 0); - - PWCHAR keyboardPath = strtowstr(_td->ForceFileName); - km_kbp_status err_status = km_kbp_keyboard_load(keyboardPath, &_td->lpActiveKeyboard->lpCoreKeyboard); - if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard: km_kbp_keyboard_load failed for %ls with error status [%d]", keyboardPath, err_status); - delete keyboardPath; - - goto fail; - } - delete keyboardPath; - SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard: %s OK", FileName); - - km_kbp_option_item *core_environment = nullptr; - - if(!SetupCoreEnvironment(&core_environment)) { - SendDebugMessageFormat(0, sdmLoad, 0, "Keyman_ForceKeyboard: Unable to set environment options for keyboard %s", FileName); - goto fail; - } - - err_status = - km_kbp_state_create(_td->lpActiveKeyboard->lpCoreKeyboard, core_environment, &_td->lpActiveKeyboard->lpCoreKeyboardState); - - DeleteCoreEnvironment(core_environment); - - if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat( - 0, sdmGlobal, 0, "Keyman_ForceKeyboard Core: km_kbp_state_create failed with error status [%d]", err_status); - // Dispose of the keyboard to leave us in a consitent state - ReleaseKeyboardMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboard); - goto fail; - } - - // TODO: #5822 Add km_kbp_event to reset keyboard action sent to keyman core - // (only the core knows the caps rules such CAPS_ALWAYS_OFF) - // so it can then respond with a possible reset. Currently this sorts itself out - // the first keystroke pressed after switching to a new keyboard. - - err_status = km_kbp_keyboard_get_imx_list(_td->lpActiveKeyboard->lpCoreKeyboard, &_td->lpActiveKeyboard->lpIMXList); - if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat(0, sdmLoad, 0, "Keyman_ForceKeyboard Core: km_kbp_keyboard_get_imx_list failed with error status [%d]", err_status); - // Dispose of the keyboard to leave us in a consistent state - ReleaseStateMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboardState); - ReleaseKeyboardMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboard); - goto fail; - } - - LoadDLLs(_td->lpActiveKeyboard); - ActivateDLLs(_td->lpActiveKeyboard); - LoadKeyboardOptionsREGCore(_td->lpActiveKeyboard, _td->lpActiveKeyboard->lpCoreKeyboardState); - RefreshPreservedKeys(TRUE); - return TRUE; -fail: +void RefreshPreservedKeys(BOOL Activating); - delete _td->lpActiveKeyboard; - _td->lpActiveKeyboard = NULL; - _td->ForceFileName[0] = 0; - return FALSE; -} -extern "C" BOOL _declspec(dllexport) WINAPI Keyman_StopForcingKeyboard() -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) - { - SetLastError(ERROR_KEYMAN_THREAD_DATA_NOT_READY); // I3173 // I3525 - return FALSE; - } - - if(!_td->lpActiveKeyboard) - { - SetLastError(ERROR_KEYMAN_KEYBOARD_NOT_ACTIVE); // I3173 // I3525 - return FALSE; - } - SendDebugMessageFormat(0,sdmGlobal,0,"Keyman_StopForcingKeyboard"); - if(_td->ForceFileName[0]) - { - SendDebugMessageFormat(0,sdmGlobal,0,"Keyman_StopForcingKeyboard: Stopping forcing"); - if(!DeactivateDLLs(_td->lpActiveKeyboard)) return FALSE; // I3173 // I3525 - if(!UnloadDLLs(_td->lpActiveKeyboard)) return FALSE; // I3173 // I3525 - _td->ForceFileName[0] = 0; - ReleaseStateMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboardState); - ReleaseKeyboardMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboard); - RefreshPreservedKeys(FALSE); - delete _td->lpActiveKeyboard; - _td->lpActiveKeyboard = NULL; - } - return TRUE; -} //--------------------------------------------------------------------------------------------------------- // diff --git a/windows/src/engine/keyman32/keyman32.def b/windows/src/engine/keyman32/keyman32.def index 84f0f24a91..2fa0e767c5 100644 --- a/windows/src/engine/keyman32/keyman32.def +++ b/windows/src/engine/keyman32/keyman32.def @@ -4,8 +4,6 @@ EXPORTS Keyman_GetInitialised Keyman_Initialise Keyman_Exit - Keyman_ForceKeyboard - Keyman_StopForcingKeyboard Keyman_GetLastActiveWindow Keyman_GetLastFocusWindow KMSetOutput -- GitLab From 7e830794990d6ac4a1428bd0f2dc7922e5b68ddb Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 10 May 2023 22:48:03 +1000 Subject: [PATCH 054/214] chore(windows): remove WM_UNICHAR completley --- .../keyman32/appint/aiWin2000Unicode.cpp | 43 ++++++++----------- windows/src/engine/keyman32/k32_dbg.cpp | 11 ----- .../src/engine/keyman32/kmhook_getmessage.cpp | 9 ---- 3 files changed, 19 insertions(+), 44 deletions(-) diff --git a/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp b/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp index 5fa67fc715..1ace76da88 100644 --- a/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp +++ b/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp @@ -1,18 +1,18 @@ /* Name: AIWin2000Unicode Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 22 Jan 2007 Modified Date: 9 Aug 2015 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 22 Jan 2007 - mcdurdin - Fix for K_NPENTER 13 Jul 2007 - mcdurdin - I934 - Prep fox x64 23 Aug 2007 - mcdurdin - I719 - Fix Alt+LeftShift and Word interactions @@ -45,11 +45,6 @@ #define KEYMAN_MOREPOST "WM_KMMOREPOST" -#ifndef WM_UNICHAR -#define WM_UNICHAR 0x0109 -#define UNICODE_NOCHAR 0xFFFF -#endif - AIWin2000Unicode::AIWin2000Unicode() { context = new AppContext; @@ -70,13 +65,13 @@ BOOL AIWin2000Unicode::CanHandleWindow(HWND ahwnd) } BOOL AIWin2000Unicode::HandleWindow(HWND ahwnd) -{ +{ if(hwnd != ahwnd) { - hwnd = ahwnd; + hwnd = ahwnd; context->Reset(); } - return TRUE; + return TRUE; } BOOL AIWin2000Unicode::IsWindowHandled(HWND ahwnd) @@ -84,11 +79,11 @@ BOOL AIWin2000Unicode::IsWindowHandled(HWND ahwnd) return (hwnd == ahwnd); } -BOOL AIWin2000Unicode::IsUnicode() -{ +BOOL AIWin2000Unicode::IsUnicode() +{ BOOL Result = IsWindowUnicode(hwnd); SendDebugMessageFormat(0, sdmAIDefault, 0, "IsWindowUnicode=%s", Result ? "Yes" : "No"); - return Result; + return Result; } /* Context functions */ @@ -96,7 +91,7 @@ BOOL AIWin2000Unicode::IsUnicode() void AIWin2000Unicode::ReadContext() { } - + void AIWin2000Unicode::AddContext(WCHAR ch) //I2436 { context->Add(ch); @@ -121,7 +116,7 @@ void AIWin2000Unicode::SetContext(const WCHAR* buf) { return context->Set(buf); } - + BYTE SavedKbdState[256]; BOOL AIWin2000Unicode::SendActions() // I4196 @@ -137,7 +132,7 @@ BOOL AIWin2000Unicode::QueueAction(int ItemType, DWORD dwData) int result = AppIntegration::QueueAction(ItemType, dwData); //SendDebugMessageFormat(hwnd, sdmAIDefault, 0, "App::QueueAction ItemType=%d dwData=%x", ItemType, dwData); - + switch(ItemType) { case QIT_VKEYDOWN: @@ -180,13 +175,13 @@ BOOL AIWin2000Unicode::QueueDebugInformation(int ItemType, LPGROUP Group, LPKEY // I1512 - SendInput with VK_PACKET for greater robustness BOOL AIWin2000Unicode::PostKeys() -{ +{ PKEYMAN64THREADDATA _td = ThreadGlobals(); if(!_td) { return FALSE; } - if(QueueSize == 0) + if(QueueSize == 0) { return TRUE; } @@ -208,7 +203,7 @@ BOOL AIWin2000Unicode::PostKeys() switch(Queue[n].ItemType) { case QIT_VKEYDOWN: if((Queue[n].dwData & QVK_KEYMASK) == 0x05) Queue[n].dwData = (Queue[n].dwData & QVK_FLAGMASK) | VK_RETURN; // I649 // I3438 - + /* 6.0.153.0: Fix repeat state for virtual keys */ if((Queue[n].dwData & QVK_KEYMASK) <= VK__MAX) // I3438 diff --git a/windows/src/engine/keyman32/k32_dbg.cpp b/windows/src/engine/keyman32/k32_dbg.cpp index 9785bad5d7..a1f63cf09e 100644 --- a/windows/src/engine/keyman32/k32_dbg.cpp +++ b/windows/src/engine/keyman32/k32_dbg.cpp @@ -194,7 +194,6 @@ char *msgnames[] = { "WM_SYSCHAR", "WM_SYSDEADCHAR", "WM_x108", -"WM_UNICHAR" }; void DebugMessage(LPMSG msg, WPARAM wParam) // I2908 @@ -218,16 +217,6 @@ void DebugMessage(LPMSG msg, WPARAM wParam) // I2908 (unsigned int) msg->lParam, wParam, (int) msg->time, - (unsigned int) GetMessageExtraInfo()); - else if(msg->message >= WM_KEYDOWN && msg->message <= WM_UNICHAR) - wsprintf(ds, "DebugMessage(%x, %s, wParam: '%c' (U+%04X), lParam: %X) [message flags: %x time: %d extra: %x]", - PtrToInt(msg->hwnd), - msgnames[msg->message-WM_KEYDOWN], - msg->wParam, - msg->wParam, - (unsigned int) msg->lParam, - wParam, - (int) msg->time, (unsigned int) GetMessageExtraInfo()); else wsprintf(ds, "%x: %d: wParam: %d, lParam: %X [message flags: %x time: %d]", PtrToInt(msg->hwnd), msg->message, msg->wParam, (unsigned int) msg->lParam, wParam, (int) msg->time); diff --git a/windows/src/engine/keyman32/kmhook_getmessage.cpp b/windows/src/engine/keyman32/kmhook_getmessage.cpp index 0b7e96c66c..562c455abb 100644 --- a/windows/src/engine/keyman32/kmhook_getmessage.cpp +++ b/windows/src/engine/keyman32/kmhook_getmessage.cpp @@ -248,15 +248,6 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam) return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); } - /* - Handle WM_UNICHAR messages for RichEdit control -- should we test RichEdit version? - */ - - if(mp->message == WM_UNICHAR) - { - // Do Nothing TODO: Remove WM_UNICHAR - } - /* Handle wm_keyman_control_internal messages */ -- GitLab From 589e6b8faf6045a4b5121eade517ca5e69125f18 Mon Sep 17 00:00:00 2001 From: davidmoore1 Date: Wed, 10 May 2023 10:44:07 -0400 Subject: [PATCH 055/214] Changes required for XCode 14.3 --- ios/Cartfile | 4 ++-- ios/Cartfile.resolved | 4 ++-- .../KMEI/KeymanEngine/Classes/Errors/SentryManager.swift | 4 ++-- oem/firstvoices/ios/Cartfile | 4 ++-- oem/firstvoices/ios/Cartfile.resolved | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ios/Cartfile b/ios/Cartfile index 5ad8178ed4..b265ef77af 100644 --- a/ios/Cartfile +++ b/ios/Cartfile @@ -1,5 +1,5 @@ github "marmelroy/Zip" -github "DaveWoodCom/XCGLogger" ~> 6.1.0 +github "keymanapp/dependency-XCGLogger" "master" github "devicekit/DeviceKit" ~> 5.0 github "ashleymills/Reachability.swift" -github "getsentry/sentry-cocoa" ~> 6.2.1 +github "getsentry/sentry-cocoa" ~> 8.7.0 diff --git a/ios/Cartfile.resolved b/ios/Cartfile.resolved index fe74a57322..ff30a8871d 100644 --- a/ios/Cartfile.resolved +++ b/ios/Cartfile.resolved @@ -1,5 +1,5 @@ -github "DaveWoodCom/XCGLogger" "6.1.0" github "ashleymills/Reachability.swift" "v5.1.0" github "devicekit/DeviceKit" "5.0.0" -github "getsentry/sentry-cocoa" "6.2.1" +github "getsentry/sentry-cocoa" "8.7.0" +github "keymanapp/dependency-XCGLogger" "57a7b975dbb6fe4fe90cef3d1bc52b8adbd89113" github "marmelroy/Zip" "2.1.2" diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Errors/SentryManager.swift b/ios/engine/KMEI/KeymanEngine/Classes/Errors/SentryManager.swift index 127fcd12b5..94f9885076 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Errors/SentryManager.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Errors/SentryManager.swift @@ -167,7 +167,7 @@ public class SentryManager { public static func breadcrumbAndLog(crumb: Sentry.Breadcrumb, logLevel: XCGLogger.Level? = nil) { // Guarded in case a library consumer decides against initializing Sentry. if _started { - SentrySDK.addBreadcrumb(crumb: crumb) + SentrySDK.addBreadcrumb(crumb) } let level = logLevel ?? mapLoggingLevel(crumb.level) @@ -193,7 +193,7 @@ public class SentryManager { } public static func forceError() { - SentrySDK.addBreadcrumb(crumb: Sentry.Breadcrumb(level: .info, category: "Deliberate testing error")) + SentrySDK.addBreadcrumb(Sentry.Breadcrumb(level: .info, category: "Deliberate testing error")) SentrySDK.crash() } } diff --git a/oem/firstvoices/ios/Cartfile b/oem/firstvoices/ios/Cartfile index ec3127efc7..3b128ec5d9 100644 --- a/oem/firstvoices/ios/Cartfile +++ b/oem/firstvoices/ios/Cartfile @@ -1,4 +1,4 @@ -github "DaveWoodCom/XCGLogger" ~> 6.1.0 +github "keymanapp/dependency-XCGLogger" "head" github "devicekit/DeviceKit" ~> 5.0 github "ashleymills/Reachability.swift" -github "getsentry/sentry-cocoa" ~> 6.2.1 +github "getsentry/sentry-cocoa" ~> 8.7.0 diff --git a/oem/firstvoices/ios/Cartfile.resolved b/oem/firstvoices/ios/Cartfile.resolved index 16cb6213b6..5ac3a55318 100644 --- a/oem/firstvoices/ios/Cartfile.resolved +++ b/oem/firstvoices/ios/Cartfile.resolved @@ -1,4 +1,4 @@ -github "DaveWoodCom/XCGLogger" "6.1.0" github "ashleymills/Reachability.swift" "v5.1.0" github "devicekit/DeviceKit" "5.0.0" -github "getsentry/sentry-cocoa" "6.2.1" +github "getsentry/sentry-cocoa" "8.7.0" +github "keymanapp/dependency-XCGLogger" "57a7b975dbb6fe4fe90cef3d1bc52b8adbd89113" -- GitLab From ac8517ad3a16e550e2b2f601caae7044872bd2bc Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Wed, 10 May 2023 18:12:10 +0200 Subject: [PATCH 056/214] chore(linux): Make us of new builder_run_action --- linux/keyman-config/build.sh | 36 ++++++------------------------------ 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/linux/keyman-config/build.sh b/linux/keyman-config/build.sh index 8498f201bc..d3a25baf0d 100755 --- a/linux/keyman-config/build.sh +++ b/linux/keyman-config/build.sh @@ -1,7 +1,5 @@ #!/usr/bin/env bash -set -eu - ## START STANDARD BUILD SCRIPT INCLUDE # adjust relative paths as necessary THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" @@ -27,31 +25,9 @@ cd "$THIS_SCRIPT_PATH" builder_describe_outputs \ build "keyman_config/standards/lang_tags_map.py" -if builder_start_action clean; then - make clean - builder_finish_action success clean -fi - -if builder_start_action configure; then - builder_finish_action success configure -fi - -if builder_start_action build; then - make - builder_finish_action success build -fi - -if builder_start_action test; then - ./run-tests.sh - builder_finish_action success test -fi - -if builder_start_action install; then - make install - builder_finish_action success install -fi - -if builder_start_action uninstall; then - make uninstall - builder_finish_action success uninstall -fi +builder_run_action clean make clean +builder_run_action configure # nothing to do +builder_run_action build make +builder_run_action test ./run-tests.sh +builder_run_action install make install +builder_run_action uninstall make uninstall -- GitLab From 7b0b01b1a4475d3d3bada814618281dbe1d5a592 Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Wed, 10 May 2023 14:02:29 -0400 Subject: [PATCH 057/214] auto: increment master version to 17.0.105 --- HISTORY.md | 6 ++++++ VERSION.md | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 42c070735a..5d9d9b3e87 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,11 @@ # Keyman Version History +## 17.0.104 alpha 2023-05-10 + +* chore(developer): rename kmc-keyboard to kmc-ldml (#8725) +* chore(linux): bring kmp.json for unit test up to spec (#8732) +* feat(common): add `builder_run_action` shorthand function (#8742) + ## 17.0.103 alpha 2023-05-09 * fix(mac): `$CONFIG` not `$CONFIGURATION` in build path (#8724) diff --git a/VERSION.md b/VERSION.md index ab165ae874..06c4aa53a4 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.104 \ No newline at end of file +17.0.105 \ No newline at end of file -- GitLab From b6afda598b14976178dbd95e72c693b3631da175 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 11 May 2023 11:00:15 +1000 Subject: [PATCH 058/214] chore(windows): wm_messages_h remov WM_UNICHAR --- .../src/test/manual-tests/msghooklister/src/App/wm_messages.h | 1 - 1 file changed, 1 deletion(-) diff --git a/windows/src/test/manual-tests/msghooklister/src/App/wm_messages.h b/windows/src/test/manual-tests/msghooklister/src/App/wm_messages.h index 8e684a761e..28fa203515 100644 --- a/windows/src/test/manual-tests/msghooklister/src/App/wm_messages.h +++ b/windows/src/test/manual-tests/msghooklister/src/App/wm_messages.h @@ -266,7 +266,6 @@ static const LPCTSTR WM_MESSAGE_STRINGS[] = { TEXT("WM_SYSCHAR"), TEXT("WM_SYSDEADCHAR"), TEXT("WM_YOMICHAR"), - TEXT("WM_UNICHAR"), TEXT("WM_CONVERTREQUEST"), TEXT("WM_CONVERTRESULT"), TEXT("WM_IM_INFO"), -- GitLab From 3ea8cc26f6bc31fa831d7fada00f6bfd3565234f Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Thu, 11 May 2023 10:10:13 +0700 Subject: [PATCH 059/214] chore(common): Update crowdin strings for Amharic --- .../src/main/res/values-am-rET/strings.xml | 4 +++- .../src/main/res/values-am-rET/strings.xml | 2 +- .../Keyman4MacIM/am.lproj/Localizable.strings | 2 +- .../desktop/kmshell/locale/am-ET/strings.xml | 24 +++++++++++++++++-- .../desktop/setup/locale/am-ET/strings.xml | 8 +++---- 5 files changed, 30 insertions(+), 10 deletions(-) diff --git a/android/KMAPro/kMAPro/src/main/res/values-am-rET/strings.xml b/android/KMAPro/kMAPro/src/main/res/values-am-rET/strings.xml index 09b4d41340..5071cc4269 100644 --- a/android/KMAPro/kMAPro/src/main/res/values-am-rET/strings.xml +++ b/android/KMAPro/kMAPro/src/main/res/values-am-rET/strings.xml @@ -1,5 +1,6 @@ + አጋራ @@ -25,6 +26,7 @@ እዚህ ጋር መጻፍ ይጀምሩ … + የጽሑፍ መጠን፦ %1$d @@ -156,5 +158,5 @@ የፊደል ገበታው አዲሱን የኪይማን ስሪት ይፈልጋል - Unable to launch web browser + ብራውሰሩን ማስጀመር አልተቻለም diff --git a/android/KMEA/app/src/main/res/values-am-rET/strings.xml b/android/KMEA/app/src/main/res/values-am-rET/strings.xml index dc9e7711ad..1bb95d5157 100644 --- a/android/KMEA/app/src/main/res/values-am-rET/strings.xml +++ b/android/KMEA/app/src/main/res/values-am-rET/strings.xml @@ -168,5 +168,5 @@ የፊደል ገበታውን ለመቀየር እዚህ ጋር ንካ - Unable to launch web browser + ብራውሰሩን ማስጀመር አልተቻለም diff --git a/mac/Keyman4MacIM/Keyman4MacIM/am.lproj/Localizable.strings b/mac/Keyman4MacIM/Keyman4MacIM/am.lproj/Localizable.strings index 06182ea47c..35de92b8d8 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/am.lproj/Localizable.strings +++ b/mac/Keyman4MacIM/Keyman4MacIM/am.lproj/Localizable.strings @@ -68,4 +68,4 @@ "copyright-label" = "የባለቤትነት መብት፦"; /* message displayed to alert user to need grant accessibility permission */ -"privacy-alert-text" = "To function properly, Keyman requires accessibility features:\n\nGrant access in System Preferences, Security & Privacy.\nRestart your system."; +"privacy-alert-text" = "ኪይማን በአግባቡ ለመስራት የተደራሽነት ባህሪያትን ይፈልጋል፦ \n\nበስርዓት ምርጫዎች፣ ደህንነት እና ግላዊነት ውስጥ መዳረሻ ፍቀድ። \nስርዓት እንደገና አስጀምር።"; diff --git a/windows/src/desktop/kmshell/locale/am-ET/strings.xml b/windows/src/desktop/kmshell/locale/am-ET/strings.xml index 141ba5da55..20e21edee6 100644 --- a/windows/src/desktop/kmshell/locale/am-ET/strings.xml +++ b/windows/src/desktop/kmshell/locale/am-ET/strings.xml @@ -46,6 +46,10 @@ ይቅር + + ቋንቋ ይጨምሩ ወይም ያጥፉ... + + የፊደል ገበታ ሰሌዳውን ለመምረጥ ይህንን ምስል ይጫኑ @@ -64,6 +68,18 @@ እርዳታ + + + + ያጥፉ + + + + ያንቁ + + + + እንዳይሰራ ያድርጉ @@ -174,6 +190,10 @@ ቋንቋ ይጨምሩ + + ቋንቋ ይጨምሩ ወይም ያጥፉ + + የስክሪን ላይ የፊደል ገበታ፦ @@ -223,7 +243,7 @@ - የፊደል ገበታ ሰሌዳ አማራጮች + የፊደል ገበታ ሰሌዳ አማራጮች... @@ -341,7 +361,7 @@ - (ባዶ ነው) + (አማራጭ ሆትኪዪ የለም) diff --git a/windows/src/desktop/setup/locale/am-ET/strings.xml b/windows/src/desktop/setup/locale/am-ET/strings.xml index 1c4f4252d9..b67dc6851a 100644 --- a/windows/src/desktop/setup/locale/am-ET/strings.xml +++ b/windows/src/desktop/setup/locale/am-ET/strings.xml @@ -72,9 +72,7 @@ %0:s በማውረድ ላይ %0:s በማውረድ ላይ - $APPNAME ማዋቀር ተጨማሪ አጋዥ ሪሶርሶችን ለማውረድ ከkeyman.com ጋር መገናኘት አልቻለም። - -እባክዎን የኢንተርኔት ኮኔክሽን መኖሩን ያረጋግጡ እና በፋየርዎልዎ ቅንብሮች ውስጥ በይነመረብን ለመድረስ ለ $APPNAME ማዋቀር ፈቃድ ይስጡ። - -ከቅንብር ለመውጣት (Abort)ን ይምረጡ፣ እንደገና ሪሶርሶቹን ለማውረድ እንደገና ይሞክሩ፣ ወይም ከኢንተርኔት ውጭ ለመቀጠል ችላ ይበሉት። + $APPNAME ማቀነባበሪያው ተጨማሪ አጋዥ ሪሶርሶችን ለማውረድ ከkeyman.com ጋር መገናኘት አልቻለም። + እባክዎን የኢንተርኔት ኮኔክሽን መኖሩን ያረጋግጡ እና በፋየርዎልዎ ቅንብሮች ውስጥ በይነመረብን ለመድረስ ለ $APPNAME ማቀነባበሪያውን ፈቃድ ይስጡ። + ከማቀነባበሪያው ለመውጣት (Abort) ን ይምረጡ፣ እንደገና ሪሶርሶቹን ለማውረድ ይሞክሩ፣ ወይም ከኢንተርኔት ውጭ ለመቀጠል ይሞክሩ። -- GitLab From 9136e571575afbbd2c38d8a5044febe9aa667b90 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 11 May 2023 14:03:18 +1000 Subject: [PATCH 060/214] chore(windows): remove ForceFileName RefreshPreservedKeys --- windows/src/engine/keyman32/K32_load.cpp | 6 ------ windows/src/engine/keyman32/appint/aiTIP.cpp | 17 ---------------- windows/src/engine/keyman32/globals.h | 2 -- windows/src/engine/keyman32/keyman32.cpp | 20 +++++-------------- .../src/engine/keyman32/selectkeyboard.cpp | 5 ----- 5 files changed, 5 insertions(+), 45 deletions(-) diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index ed2889b375..ed07f26fe7 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -45,12 +45,6 @@ BOOL GetKeyboardFileName(LPSTR kbname, LPSTR buf, int nbuf) { PKEYMAN64THREADDATA _td = ThreadGlobals(); if(!_td) return FALSE; - if(_td->ForceFileName[0]) - { - strncpy_s(buf, nbuf, _td->ForceFileName, nbuf - 1); - buf[nbuf-1] = 0; - return TRUE; - } int n = 0; RegistryReadOnly *reg = Reg_GetKeymanInstalledKeyboard(kbname); diff --git a/windows/src/engine/keyman32/appint/aiTIP.cpp b/windows/src/engine/keyman32/appint/aiTIP.cpp index 8b4fd9ed6b..dba603d6b2 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.cpp +++ b/windows/src/engine/keyman32/appint/aiTIP.cpp @@ -595,7 +595,6 @@ BOOL AITIP::QueueDebugInformation(int ItemType, LPGROUP Group, LPKEY Rule, PWSTR { PKEYMAN64THREADDATA _td = ThreadGlobals(); if(!_td) return TRUE; - if(!_td->ForceFileName[0]) return TRUE; SendDebugMessageFormat(0, sdmAIDefault, 0, "AIDebugger::QueueDebugInformation ItemType=%d", ItemType); AIDEBUGINFO di; @@ -620,19 +619,3 @@ BOOL AITIP::QueueDebugInformation(int ItemType, LPGROUP Group, LPKEY Rule, PWSTR return TRUE; } - -typedef BOOL(WINAPI *PREFRESHPRESERVEDKEYSFUNC)(BOOL Activating); - -void RefreshPreservedKeys(BOOL Activating) { -#ifdef _WIN64 - HMODULE hModule = GetModuleHandle("kmtip64"); -#else - HMODULE hModule = GetModuleHandle("kmtip"); -#endif - if (hModule != NULL) { - PREFRESHPRESERVEDKEYSFUNC pRefreshPreservedKeys = (PREFRESHPRESERVEDKEYSFUNC)GetProcAddress(hModule, "RefreshPreservedKeys"); - if (pRefreshPreservedKeys) { - pRefreshPreservedKeys(Activating); - } - } -} diff --git a/windows/src/engine/keyman32/globals.h b/windows/src/engine/keyman32/globals.h index 1465bab24d..320ef811de 100644 --- a/windows/src/engine/keyman32/globals.h +++ b/windows/src/engine/keyman32/globals.h @@ -215,8 +215,6 @@ typedef struct tagKEYMAN64THREADDATA FInitialised, FInitialising; - char ForceFileName[MAX_PATH]; - DWORD ActiveKeymanID; /* TIP Globals */ diff --git a/windows/src/engine/keyman32/keyman32.cpp b/windows/src/engine/keyman32/keyman32.cpp index 7444a696d4..7a2490f925 100644 --- a/windows/src/engine/keyman32/keyman32.cpp +++ b/windows/src/engine/keyman32/keyman32.cpp @@ -529,19 +529,6 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_RestartEngine() return TRUE; } -/*******************************************************************************************/ -/* */ -/* Keyman Keyboard Override Functions */ -/* */ -/*******************************************************************************************/ - - - -void RefreshPreservedKeys(BOOL Activating); - - - - //--------------------------------------------------------------------------------------------------------- // // Utility guff functions @@ -914,7 +901,11 @@ void ReleaseKeyboards(BOOL Lock) if(!_td || !_td->lpKeyboards) return; - if(Lock) if(_td->lpActiveKeyboard && !_td->ForceFileName[0]) DeactivateDLLs(_td->lpActiveKeyboard); + if(Lock) { + if(_td->lpActiveKeyboard) { + DeactivateDLLs(_td->lpActiveKeyboard); + } + } for(int i = 0; i < _td->nKeyboards; i++) { @@ -928,7 +919,6 @@ void ReleaseKeyboards(BOOL Lock) delete _td->lpKeyboards; _td->lpKeyboards = NULL; - if(!_td->ForceFileName[0]) _td->lpActiveKeyboard = NULL; } /** diff --git a/windows/src/engine/keyman32/selectkeyboard.cpp b/windows/src/engine/keyman32/selectkeyboard.cpp index d600262fd4..0ca9e2e65f 100644 --- a/windows/src/engine/keyman32/selectkeyboard.cpp +++ b/windows/src/engine/keyman32/selectkeyboard.cpp @@ -71,11 +71,6 @@ BOOL SelectKeyboard(DWORD KeymanID) __try { - if (_td->ForceFileName[0]) - { - SendDebugMessageFormat(hwnd, sdmGlobal, 0, "SelectKeyboard: Ignored due to ForceFile"); - return FALSE; // Keyboard file is force-loaded - } KMHideIM(); -- GitLab From aac63118ace26f7bf5244b504eb6510b59f531df Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Thu, 11 May 2023 11:08:30 +0700 Subject: [PATCH 061/214] chore(android/app): Cleanup build-play-store-notes script --- android/KMAPro/build-play-store-notes.sh | 92 +++++++++++------------- android/build-publish.sh | 10 +-- 2 files changed, 46 insertions(+), 56 deletions(-) diff --git a/android/KMAPro/build-play-store-notes.sh b/android/KMAPro/build-play-store-notes.sh index 3846ce9c42..e93e94ff28 100755 --- a/android/KMAPro/build-play-store-notes.sh +++ b/android/KMAPro/build-play-store-notes.sh @@ -1,55 +1,49 @@ -# Set sensible script defaults: -# set -e: Terminate script if a command returns an error -set -e -# set -u: Terminate script if an unset variable is used -set -u +#!/usr/bin/env bash -## START STANDARD BUILD SCRIPT INCLUDE -# adjust relative paths as necessary -THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" -. "${THIS_SCRIPT%/*}/../../resources/build/build-utils.sh" -## END STANDARD BUILD SCRIPT INCLUDE +# Assumption: parent script that sources this already has START STANDARD BUILD SCRIPT INCLUDE -QUIET=0 +# This script runs from its own folder +cd "$THIS_SCRIPT_PATH" -. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh" +################################ Main script ################################ -THIS_DIR="$(dirname "$THIS_SCRIPT")" - -# -# Copy release notes for Gradle Play Publisher to upload -# Reference: https://github.com/Triple-T/gradle-play-publisher#uploading-release-notes -# -PLAY_RELEASE_NOTES="$KEYMAN_ROOT/android/KMAPro/kMAPro/src/main/play/release-notes/en-US/$TIER.txt" -if [ $TIER = "stable" ]; then - PLAY_RELEASE_NOTES="$KEYMAN_ROOT/android/KMAPro/kMAPro/src/main/play/release-notes/en-US/default.txt" -fi -echo "Generating Play Store release notes to $PLAY_RELEASE_NOTES" -echo "" > "$PLAY_RELEASE_NOTES" - -# Copy whatsnew.md to release notes 1 line at a time, -# filtering for lines that start with "*". -# Pad release notes if whatsnew.md doesn't have any line items -# Play Store release notes have a limit of 500 characters -DEFAULT_RELEASE_NOTE="* Additional bug fixes and improvements" -FILTERED_LINES=$( grep '^\s*\*.*$' "$KEYMAN_ROOT/android/help/about/whatsnew.md" || [[ $? == 1 ]] ) # Continue if grep has no matches -if [ -z "$FILTERED_LINES" ]; then - FILTERED_LINES="$DEFAULT_RELEASE_NOTE" - builder_warn "Warning: whatsnew.md empty so using default release note: '$FILTERED_LINES'" -fi +function generateReleaseNotes() { + # + # Copy release notes for Gradle Play Publisher to upload + # Reference: https://github.com/Triple-T/gradle-play-publisher#uploading-release-notes + # + local PLAY_RELEASE_NOTES="$KEYMAN_ROOT/android/KMAPro/kMAPro/src/main/play/release-notes/en-US/$TIER.txt" + if [ $TIER = "stable" ]; then + PLAY_RELEASE_NOTES="$KEYMAN_ROOT/android/KMAPro/kMAPro/src/main/play/release-notes/en-US/default.txt" + fi + builder_heading "Generating Play Store release notes to $PLAY_RELEASE_NOTES" + # write to file + echo "" > "$PLAY_RELEASE_NOTES" -IFS=$'\n' # Change IFS to new line -for line in $FILTERED_LINES -do - CHARS_IN_RELEASE_NOTES=$( wc -m < $PLAY_RELEASE_NOTES ) - CHARS_IN_CURRENT_LINE=$( wc -m <<< $line ) - if (( CHARS_IN_RELEASE_NOTES + CHARS_IN_CURRENT_LINE + 1 < 450 )); then - # Copy line to Play Store release notes - echo "$line" >> $PLAY_RELEASE_NOTES - else - # 450 chars reached - builder_warn "Warning: Play Store release notes approaching 500 character limit" - echo "$DEFAULT_RELEASE_NOTE" >> $PLAY_RELEASE_NOTES - break + # Copy whatsnew.md to release notes 1 line at a time, + # filtering for lines that start with "*". + # Pad release notes if whatsnew.md doesn't have any line items + # Play Store release notes have a limit of 500 characters + local DEFAULT_RELEASE_NOTE="* Additional bug fixes and improvements" + local FILTERED_LINES=$( grep '^\s*\*.*$' "$KEYMAN_ROOT/android/help/about/whatsnew.md" || [[ $? == 1 ]] ) # Continue if grep has no matches + if [ -z "$FILTERED_LINES" ]; then + FILTERED_LINES="$DEFAULT_RELEASE_NOTE" + builder_warn "Warning: whatsnew.md empty so using default release note: '$FILTERED_LINES'" fi -done + + IFS=$'\n' # Change IFS to new line + for line in $FILTERED_LINES + do + local CHARS_IN_RELEASE_NOTES=$( wc -m < $PLAY_RELEASE_NOTES ) + local CHARS_IN_CURRENT_LINE=$( wc -m <<< $line ) + if (( CHARS_IN_RELEASE_NOTES + CHARS_IN_CURRENT_LINE + 1 < 450 )); then + # Copy line to Play Store release notes + echo "$line" >> $PLAY_RELEASE_NOTES + else + # 450 chars reached + builder_warn "Warning: Play Store release notes approaching 500 character limit" + echo "$DEFAULT_RELEASE_NOTE" >> $PLAY_RELEASE_NOTES + break + fi + done +} diff --git a/android/build-publish.sh b/android/build-publish.sh index 7e52edad92..2e01890a57 100755 --- a/android/build-publish.sh +++ b/android/build-publish.sh @@ -2,11 +2,6 @@ # CI script to publish specified app APKs to the Play Store. # The APKs should already have been built from a separate script -# Set sensible script defaults: -# set -e: Terminate script if a command returns an error -set -e -# set -u: Terminate script if an unset variable is used -set -u # set -x: Debugging use, print each statement # set -x @@ -16,6 +11,8 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "${THIS_SCRIPT%/*}/../resources/build/build-utils.sh" ## END STANDARD BUILD SCRIPT INCLUDE +. "$KEYMAN_ROOT/android/KMAPro/build-play-store-notes.sh" + echo Publishing APKs to Play Store # @@ -79,8 +76,7 @@ echo "BUILD_FLAGS $BUILD_FLAGS" if [ "$DO_KMAPRO" = true ]; then cd "$KEYMAN_ROOT/android/KMAPro/" # Copy Release Notes - ./build-play-store-notes.sh - + generateReleaseNotes ./gradlew $DAEMON_FLAG $BUILD_FLAGS fi -- GitLab From 2462472b38385895e36e79a3593d6098d6003061 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 11 May 2023 14:48:38 +1000 Subject: [PATCH 062/214] chore(windows): address review comments --- windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp | 1 - windows/src/engine/keyman32/k32_dbg.cpp | 1 + .../src/test/manual-tests/msghooklister/src/App/wm_messages.h | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp b/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp index 1ace76da88..5e7fab9ed3 100644 --- a/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp +++ b/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp @@ -43,7 +43,6 @@ #include "pch.h" // I4128 // I4287 #include "serialkeyeventclient.h" -#define KEYMAN_MOREPOST "WM_KMMOREPOST" AIWin2000Unicode::AIWin2000Unicode() { diff --git a/windows/src/engine/keyman32/k32_dbg.cpp b/windows/src/engine/keyman32/k32_dbg.cpp index a1f63cf09e..897616a53e 100644 --- a/windows/src/engine/keyman32/k32_dbg.cpp +++ b/windows/src/engine/keyman32/k32_dbg.cpp @@ -194,6 +194,7 @@ char *msgnames[] = { "WM_SYSCHAR", "WM_SYSDEADCHAR", "WM_x108", +"WM_UNICHAR" }; void DebugMessage(LPMSG msg, WPARAM wParam) // I2908 diff --git a/windows/src/test/manual-tests/msghooklister/src/App/wm_messages.h b/windows/src/test/manual-tests/msghooklister/src/App/wm_messages.h index 28fa203515..8e684a761e 100644 --- a/windows/src/test/manual-tests/msghooklister/src/App/wm_messages.h +++ b/windows/src/test/manual-tests/msghooklister/src/App/wm_messages.h @@ -266,6 +266,7 @@ static const LPCTSTR WM_MESSAGE_STRINGS[] = { TEXT("WM_SYSCHAR"), TEXT("WM_SYSDEADCHAR"), TEXT("WM_YOMICHAR"), + TEXT("WM_UNICHAR"), TEXT("WM_CONVERTREQUEST"), TEXT("WM_CONVERTRESULT"), TEXT("WM_IM_INFO"), -- GitLab From 1f3e8f768d47fc7f82962473b98994f4f2de7c2a Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 11 May 2023 14:57:01 +1000 Subject: [PATCH 063/214] chore(windows): remove RefreshPreservedKeys pt2 --- developer/src/tike/compile/keyman32_int.pas | 108 ---------- windows/src/engine/kmtip/keys.cpp | 33 ---- windows/src/engine/kmtip/kmtip.def | 1 - windows/src/engine/kmtip/kmtip.h | 16 +- .../global/delphi/general/keyman32_int.pas | 184 ------------------ 5 files changed, 7 insertions(+), 335 deletions(-) delete mode 100644 developer/src/tike/compile/keyman32_int.pas delete mode 100644 windows/src/global/delphi/general/keyman32_int.pas diff --git a/developer/src/tike/compile/keyman32_int.pas b/developer/src/tike/compile/keyman32_int.pas deleted file mode 100644 index 37ddbe9347..0000000000 --- a/developer/src/tike/compile/keyman32_int.pas +++ /dev/null @@ -1,108 +0,0 @@ -unit keyman32_int; - -interface - -uses Windows, SysUtils, Forms; - -function Keyman_Initialise(Handle: HWND; FSingleApp: Boolean): Boolean; -function Keyman_Exit: Boolean; -function Keyman_ForceKeyboard(const s: string): Boolean; -function Keyman_StopForcingKeyboard: Boolean; - -implementation - -uses TikeUtils; - -type TKeyman_ForceKeyboard = function (s: PChar): Boolean; stdcall; -type TKeyman_StopForcingKeyboard = function: Boolean; stdcall; -type TKeyman_Initialise = function(h: THandle; FSingleApp: LongBool): Boolean; stdcall; -type TKeyman_Exit = function: Boolean; stdcall; - -var - FInitKeyman: Boolean = False; - FKeyman32Path: string = ''; - -function Keyman_Initialise(Handle: HWND; FSingleApp: Boolean): Boolean; -var - hkeyman: THandle; - FLoad: Boolean; - ki: TKeyman_Initialise; -begin - Result := False; - FLoad := False; - hkeyman := GetModuleHandle('keyman32.dll'); - if hkeyman = 0 then - begin - hkeyman := LoadLibrary(PChar(GetKeymanInstallPath+'keyman32.dll')); - if hkeyman = 0 then Exit; - FLoad := True; - end; - ki := TKeyman_Initialise(GetProcAddress(hkeyman, 'Keyman_Initialise')); - if not Assigned(@ki) then Exit; - if not ki(Handle, FSingleApp) then - begin - if FLoad then FreeLibrary(hkeyman); - Exit; - end; - - FInitKeyman := True; - Result := True; -end; - -function Keyman_Exit: Boolean; -var - hkeyman: THandle; - ke: TKeyman_Exit; -begin - if not FInitKeyman then - begin - Result := True; - Exit; - end; - Result := False; - hkeyman := GetModuleHandle('keyman32.dll'); - if hkeyman = 0 then Exit; - ke := TKeyman_Exit(GetProcAddress(hkeyman, 'Keyman_Exit')); - if not Assigned(@ke) then Exit; - if not ke then Exit; - if FInitKeyman then FreeLibrary(hkeyman); - FInitKeyman := False; - Result := True; -end; - -function Keyman_ForceKeyboard(const s: string): Boolean; -var - hkeyman: THandle; - fk: TKeyman_ForceKeyboard; -begin - Result := False; - hkeyman := GetModuleHandle('keyman32.dll'); - if hkeyman = 0 then - begin - if not Keyman_Initialise(Application.MainForm.Handle, True) then Exit; - hkeyman := GetModuleHandle('keyman32.dll'); - if hkeyman = 0 then Exit; - end; - fk := TKeyman_ForceKeyboard(GetProcAddress(hkeyman, 'Keyman_ForceKeyboard')); - if(Assigned(@fk)) then - Result := fk(PChar(s)); -end; - -function Keyman_StopForcingKeyboard: Boolean; -var - hkeyman: THandle; - sfk: TKeyman_StopForcingKeyboard; -begin - Result := False; - hkeyman := GetModuleHandle('keyman32.dll'); - if hkeyman = 0 then Exit; - sfk := TKeyman_StopForcingKeyboard(GetProcAddress(hkeyman, 'Keyman_StopForcingKeyboard')); - if(Assigned(@sfk)) then - Result := sfk; - Keyman_Exit; -end; - -initialization -finalization - Keyman_Exit; -end. diff --git a/windows/src/engine/kmtip/keys.cpp b/windows/src/engine/kmtip/keys.cpp index d5d4882ca5..9f1552f4e3 100644 --- a/windows/src/engine/kmtip/keys.cpp +++ b/windows/src/engine/kmtip/keys.cpp @@ -362,36 +362,3 @@ STDMETHODIMP CKMTipTextService::OnPreservedKey(ITfContext *pContext, REFGUID rgu *pfEaten = FALSE; return S_OK; } - -BOOL CKMTipTextService::DoRefreshPreservedKeys(BOOL Activating) { - LogEnter(); - ITfKeystrokeMgr *pKeystrokeMgr; - HRESULT hr = S_OK; - - Log(L"CKMTipTextService::DoRefreshPreservedKeys"); - - if (!_pThreadMgr) { - return FALSE; - } - - if (_pThreadMgr->QueryInterface(IID_ITfKeystrokeMgr, (void **)&pKeystrokeMgr) != S_OK) { - return FALSE; - } - - _UnpreserveAltKeys(pKeystrokeMgr); - if (Activating) { - hr = _PreserveAltKeys(pKeystrokeMgr); // I3588 - } - - pKeystrokeMgr->Release(); - - return (hr == S_OK); -} - -__declspec(dllexport) BOOL WINAPI RefreshPreservedKeys(BOOL Activating) { - LogEnter(); - if (CKMTipTextService::ThreadThis) { - return CKMTipTextService::ThreadThis->DoRefreshPreservedKeys(Activating); - } - return FALSE; -} diff --git a/windows/src/engine/kmtip/kmtip.def b/windows/src/engine/kmtip/kmtip.def index 64c10743c2..854f6b6ca5 100644 --- a/windows/src/engine/kmtip/kmtip.def +++ b/windows/src/engine/kmtip/kmtip.def @@ -5,5 +5,4 @@ EXPORTS DllCanUnloadNow PRIVATE DllRegisterServer PRIVATE DllUnregisterServer PRIVATE - RefreshPreservedKeys Keyman_Diagnostic diff --git a/windows/src/engine/kmtip/kmtip.h b/windows/src/engine/kmtip/kmtip.h index aabe098b8b..3ab425891d 100644 --- a/windows/src/engine/kmtip/kmtip.h +++ b/windows/src/engine/kmtip/kmtip.h @@ -1,18 +1,18 @@ /* Name: kmtip Copyright: Copyright (C) SIL International. - Documentation: + Documentation: Description: CKMTipTextService declaration. Create Date: 7 Sep 2009 Modified Date: 27 Jan 2015 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 07 Sep 2009 - mcdurdin - I2095 - TSF addin is not threadsafe 01 May 2014 - mcdurdin - I4216 - V9.0 - Keyman TIP should use ITfTextInputProcessorEx 16 Jun 2014 - mcdurdin - I4274 - V9.0 - kmtip does not work if already active before KM starts @@ -88,8 +88,6 @@ public: BOOL TIPNotifyActivate(GUID *guidProfile); - BOOL DoRefreshPreservedKeys(BOOL Activating); - static __declspec(thread) CKMTipTextService *ThreadThis; private: @@ -107,7 +105,7 @@ private: void _UninitKeyman(); void _TryAndStartKeyman(); - + HRESULT _UnpreserveAltKeys(ITfKeystrokeMgr *pKeystrokeMgr); // Keyman interfaces diff --git a/windows/src/global/delphi/general/keyman32_int.pas b/windows/src/global/delphi/general/keyman32_int.pas deleted file mode 100644 index decebd7bdb..0000000000 --- a/windows/src/global/delphi/general/keyman32_int.pas +++ /dev/null @@ -1,184 +0,0 @@ -(* - Name: keyman32_int - Copyright: Copyright (C) SIL International. - Documentation: - Description: - Create Date: 1 Aug 2006 - - Modified Date: 17 Aug 2012 - Authors: mcdurdin - Related Files: - Dependencies: - - Bugs: - Todo: - Notes: - History: 01 Aug 2006 - mcdurdin - Add GetKeymanInstallPath function - 14 Sep 2006 - mcdurdin - Retrieve Debug_Keyman32 path if assigned - 18 Mar 2011 - mcdurdin - I2825 - Debug_Keyman32 override not working correctly - 03 May 2011 - mcdurdin - I2890 - Record diagnostic data when encountering registry errors - 17 Aug 2012 - mcdurdin - I3310 - V9.0 - Unicode in Delphi fixes -*) -unit keyman32_int; - -interface - -uses Windows, SysUtils, Forms, ErrorControlledRegistry, RegistryKeys; //, util; - -function Keyman_Initialise(Handle: HWND; FSingleApp: Boolean): Boolean; -function Keyman_Exit: Boolean; -function Keyman_ForceKeyboard(const s: string): Boolean; -function Keyman_StopForcingKeyboard: Boolean; - -implementation - -uses DebugPaths, Dialogs, KLog; - -type TKeyman_ForceKeyboard = function (s: PAnsiChar): Boolean; stdcall; // I3310 -type TKeyman_StopForcingKeyboard = function: Boolean; stdcall; -type TKeyman_Initialise = function(h: THandle; FSingleApp: LongBool): Boolean; stdcall; -type TKeyman_Exit = function: Boolean; stdcall; - -var - FInitKeyman: Boolean = False; - FKeyman32Path: string = ''; - -function GetKeymanInstallPath: string; -var - RootPath: string; -begin - RootPath := ''; - with TRegistryErrorControlled.Create do // I2890 - try - RootKey := HKEY_LOCAL_MACHINE; - if OpenKeyReadOnly(SRegKey_KeymanEngine_LM) and ValueExists(SRegValue_RootPath) then - RootPath := ReadString(SRegValue_RootPath); - finally - Free; - end; - - RootPath := GetDebugPath('Debug_Keyman32Path', RootPath); // I2825 - - if RootPath = '' then - begin - RootPath := ExtractFilePath(ParamStr(0)); - end; - - Result := IncludeTrailingPathDelimiter(RootPath); - - if not FileExists(Result + 'keyman32.dll') then - raise Exception.Create( 'The executable keyman32.dll could not '+ - 'be found. You should reinstall.'); -end; - -function Keyman_Initialise(Handle: HWND; FSingleApp: Boolean): Boolean; -var - hkeyman: THandle; - FLoad: Boolean; - ki: TKeyman_Initialise; - s: string; -begin - Result := False; - FLoad := False; - hkeyman := GetModuleHandle('keyman32.dll'); - if hkeyman = 0 then - begin - s := GetKeymanInstallPath; - hkeyman := LoadLibrary(PChar(s+'keyman32.dll')); - if hkeyman = 0 then - begin - KL.LogError('Keyman_Initialise: Unable to load '+s+'keyman32.dll: '+SysErrorMessage(GetLastError)); - Exit; - end; - KL.Log('Keyman_Initialise: Loaded keyman32.dll'); - FLoad := True; - end - else - KL.Log('Keyman_Initialise: Found keyman32.dll already loaded'); - ki := TKeyman_Initialise(GetProcAddress(hkeyman, 'Keyman_Initialise')); - if not Assigned(@ki) then - begin - KL.LogError('Keyman_Initialise: Unable to find Keyman_Initialise in '+s+'keyman32.dll: '+SysErrorMessage(GetLastError)); - if FLoad then FreeLibrary(hkeyman); - Exit; - end; - if not ki(Handle, FSingleApp) then - begin - KL.LogError('Keyman_Initialise: Call to Keyman_Initialise in '+s+'keyman32.dll failed: '+SysErrorMessage(GetLastError)); - if FLoad then FreeLibrary(hkeyman); - Exit; - end; - - KL.Log('Keyman_Initialise: Loaded successfully'); - FInitKeyman := True; - Result := True; -end; - -function Keyman_Exit: Boolean; -var - hkeyman: THandle; - ke: TKeyman_Exit; -begin - if not FInitKeyman then - begin - Result := True; - Exit; - end; - Result := False; - hkeyman := GetModuleHandle('keyman32.dll'); - if hkeyman = 0 then Exit; - ke := TKeyman_Exit(GetProcAddress(hkeyman, 'Keyman_Exit')); - if not Assigned(@ke) then Exit; - if not ke then Exit; - if FInitKeyman then FreeLibrary(hkeyman); - FInitKeyman := False; - Result := True; -end; - -function Keyman_ForceKeyboard(const s: string): Boolean; -var - hkeyman: THandle; - fk: TKeyman_ForceKeyboard; -begin - Result := False; - hkeyman := GetModuleHandle('keyman32.dll'); - if hkeyman = 0 then - begin - KL.Log('Keyman_ForceKeyboard: Attempting to load keyman32.dll'); - if not Keyman_Initialise(Application.MainForm.Handle, True) then - begin - KL.LogError('Keyman_ForceKeyboard: Unable to load keyman32.dll'); - Exit; - end; - hkeyman := GetModuleHandle('keyman32.dll'); - if hkeyman = 0 then Exit; - end; - fk := TKeyman_ForceKeyboard(GetProcAddress(hkeyman, 'Keyman_ForceKeyboard')); - if(Assigned(@fk)) then - begin - Result := fk(PAnsiChar(AnsiString(s))); // todo: k9: unicode // I3310 - if not Result then KL.LogError('Keyman_ForceKeyboard in keyman32.dll failed: '+s) - else KL.Log('Keyman_ForceKeyboard: success'); - end - else - KL.LogError('Keyman_ForceKeyboard: failed to find Keyman_ForceKeyboard in keyman32.dll'); -end; - -function Keyman_StopForcingKeyboard: Boolean; -var - hkeyman: THandle; - sfk: TKeyman_StopForcingKeyboard; -begin - Result := False; - hkeyman := GetModuleHandle('keyman32.dll'); - if hkeyman = 0 then Exit; - sfk := TKeyman_StopForcingKeyboard(GetProcAddress(hkeyman, 'Keyman_StopForcingKeyboard')); - if(Assigned(@sfk)) then - Result := sfk; -end; - -initialization -finalization - Keyman_Exit; -end. - -- GitLab From be8d5b08c62237948bfc02c9a135de2c4f586745 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 11 May 2023 15:20:50 +1000 Subject: [PATCH 064/214] feat(windows): add text editor to the support makefile Add text editor to the windows/src/support/Makefile Fixed the TextEditor Makefile to copy the debug file to the debug folder. --- windows/src/support/Makefile | 8 ++++++-- windows/src/support/texteditor/Makefile | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/windows/src/support/Makefile b/windows/src/support/Makefile index 7f624d29f4..56609e21e4 100644 --- a/windows/src/support/Makefile +++ b/windows/src/support/Makefile @@ -3,9 +3,9 @@ # !ifdef NODELPHI -TARGETS=etl2log +TARGETS=etl2log texteditor !else -TARGETS=oskbulkrenderer etl2log +TARGETS=oskbulkrenderer etl2log texteditor !endif CLEANS=clean-support @@ -21,6 +21,10 @@ etl2log: .virtual cd $(ROOT)\src\support\etl2log $(MAKE) $(TARGET) +texteditor: .virtual + cd $(ROOT)\src\support\texteditor + $(MAKE) $(TARGET) + # ---------------------------------------------------------------------- clean-support: diff --git a/windows/src/support/texteditor/Makefile b/windows/src/support/texteditor/Makefile index a9fa1b1cd2..a01ac22203 100644 --- a/windows/src/support/texteditor/Makefile +++ b/windows/src/support/texteditor/Makefile @@ -8,9 +8,9 @@ build: $(MSBUILD) editor.vcxproj $(MSBUILD_BUILD) /p:Platform=x86 $(MSBUILD) editor.vcxproj $(MSBUILD_BUILD) /p:Platform=x64 $(COPY) $(WIN32_TARGET_PATH)\editor32.exe $(PROGRAM)\support - $(COPY) $(WIN32_TARGET_PATH)\editor32.pdb $(PROGRAM)\support + $(COPY) $(WIN32_TARGET_PATH)\editor32.pdb $(DEBUGPATH)\support $(COPY) $(X64_TARGET_PATH)\editor64.exe $(PROGRAM)\support - $(COPY) $(X64_TARGET_PATH)\editor64.pdb $(PROGRAM)\support + $(COPY) $(X64_TARGET_PATH)\editor64.pdb $(DEBUGPATH)\support clean: def-clean $(MSBUILD) $(MSBUILD_CLEAN) editor.sln -- GitLab From a77aa8b54c26cfa6b264f80fdd57e4912076f5ec Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 11 May 2023 12:44:45 +0700 Subject: [PATCH 065/214] chore(developer): refactor checkForModelsAndKeyboardsInSamePackage into separate func --- .../src/kmc-package/src/compiler/package-validation.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/developer/src/kmc-package/src/compiler/package-validation.ts b/developer/src/kmc-package/src/compiler/package-validation.ts index be98a4829a..322cd9b355 100644 --- a/developer/src/kmc-package/src/compiler/package-validation.ts +++ b/developer/src/kmc-package/src/compiler/package-validation.ts @@ -7,6 +7,9 @@ export class PackageValidation { } public validate(kmpJson: KmpJsonFile.KmpJsonFile) { + if(!this.checkForModelsAndKeyboardsInSamePackage(kmpJson)) { + return false; + } if(!this.checkKeyboards(kmpJson)) { return false; } @@ -28,12 +31,16 @@ export class PackageValidation { } } - private checkLexicalModels(kmpJson: KmpJsonFile.KmpJsonFile): boolean { + private checkForModelsAndKeyboardsInSamePackage(kmpJson: KmpJsonFile.KmpJsonFile): boolean { if(kmpJson.lexicalModels?.length > 0 && kmpJson.keyboards?.length > 0) { this.callbacks.reportMessage(CompilerMessages.Error_PackageCannotContainBothModelsAndKeyboards()); return false; } + return true; + } + + private checkLexicalModels(kmpJson: KmpJsonFile.KmpJsonFile): boolean { if(kmpJson.lexicalModels) { for(let model of kmpJson.lexicalModels) { this.checkForDuplicatedLanguages('model', model.id, model.languages); -- GitLab From f5d43482c1aae7158f9a0a3bb88059ff3f3fb05f Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Thu, 11 May 2023 13:08:34 +0700 Subject: [PATCH 066/214] fix(android/app): Address review comments --- ...store-notes.sh => build-play-store-notes.inc.sh} | 13 +++++++++---- android/build-publish.sh | 5 ++--- 2 files changed, 11 insertions(+), 7 deletions(-) rename android/KMAPro/{build-play-store-notes.sh => build-play-store-notes.inc.sh} (92%) diff --git a/android/KMAPro/build-play-store-notes.sh b/android/KMAPro/build-play-store-notes.inc.sh similarity index 92% rename from android/KMAPro/build-play-store-notes.sh rename to android/KMAPro/build-play-store-notes.inc.sh index e93e94ff28..6e92b12108 100755 --- a/android/KMAPro/build-play-store-notes.sh +++ b/android/KMAPro/build-play-store-notes.inc.sh @@ -2,12 +2,11 @@ # Assumption: parent script that sources this already has START STANDARD BUILD SCRIPT INCLUDE -# This script runs from its own folder -cd "$THIS_SCRIPT_PATH" - ################################ Main script ################################ function generateReleaseNotes() { + pushd "$KEYMAN_ROOT/android/KMAPro/" + # # Copy release notes for Gradle Play Publisher to upload # Reference: https://github.com/Triple-T/gradle-play-publisher#uploading-release-notes @@ -31,7 +30,9 @@ function generateReleaseNotes() { builder_warn "Warning: whatsnew.md empty so using default release note: '$FILTERED_LINES'" fi - IFS=$'\n' # Change IFS to new line + # Change IFS to new line + local old_IFS="${IFS}" + IFS=$'\n' for line in $FILTERED_LINES do local CHARS_IN_RELEASE_NOTES=$( wc -m < $PLAY_RELEASE_NOTES ) @@ -46,4 +47,8 @@ function generateReleaseNotes() { break fi done + + # Restore IFS + IFS=${old_IFS} + popd } diff --git a/android/build-publish.sh b/android/build-publish.sh index 2e01890a57..124e69b46d 100755 --- a/android/build-publish.sh +++ b/android/build-publish.sh @@ -1,4 +1,3 @@ -#!/usr/bin/env bash # CI script to publish specified app APKs to the Play Store. # The APKs should already have been built from a separate script @@ -11,7 +10,7 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "${THIS_SCRIPT%/*}/../resources/build/build-utils.sh" ## END STANDARD BUILD SCRIPT INCLUDE -. "$KEYMAN_ROOT/android/KMAPro/build-play-store-notes.sh" +. "$KEYMAN_ROOT/android/KMAPro/build-play-store-notes.inc.sh" echo Publishing APKs to Play Store @@ -74,9 +73,9 @@ echo "BUILD_FLAGS $BUILD_FLAGS" # Publish Keyman for Android if [ "$DO_KMAPRO" = true ]; then - cd "$KEYMAN_ROOT/android/KMAPro/" # Copy Release Notes generateReleaseNotes + exit ./gradlew $DAEMON_FLAG $BUILD_FLAGS fi -- GitLab From 88b31ba49e2d29fa36bd127f9c7b368017eede95 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 11 May 2023 13:23:33 +0700 Subject: [PATCH 067/214] feat(developer): add validation of package filenames Adds `WARN_PackageNameDoesNotFollowKeyboardConventions` and `WARN_PackageNameDoesNotFollowLexicalModelConventions`, refactoring as required to test filenames, and adds unit tests for same. --- .../src/kmc-package/src/compiler/messages.ts | 11 ++++ .../src/compiler/package-validation.ts | 54 ++++++++++++++----- ...geNameDoesNotFollowKeyboardConventions.kps | 32 +++++++++++ ...meDoesNotFollowLexicalModelConventions.kps | 32 +++++++++++ ...age_should_not_repeat_languages.model.kps} | 0 ...n_package_should_not_repeat_languages.kps} | 0 .../kmc-package/test/test-package-compiler.ts | 18 +++++-- .../kmc/src/commands/build/BuildPackage.ts | 2 +- developer/src/kmc/src/kmlmi.ts | 2 +- developer/src/kmc/src/kmlmp.ts | 2 +- 10 files changed, 134 insertions(+), 19 deletions(-) create mode 100644 developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowKeyboardConventions.kps create mode 100644 developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowLexicalModelConventions.kps rename developer/src/kmc-package/test/fixtures/invalid/{WARN_PackageShouldNotRepeatLanguages.model.kps => keyman.en.warn_package_should_not_repeat_languages.model.kps} (100%) rename developer/src/kmc-package/test/fixtures/invalid/{WARN_PackageShouldNotRepeatLanguages.kps => warn_package_should_not_repeat_languages.kps} (100%) diff --git a/developer/src/kmc-package/src/compiler/messages.ts b/developer/src/kmc-package/src/compiler/messages.ts index 3d252682e2..38447d58e6 100644 --- a/developer/src/kmc-package/src/compiler/messages.ts +++ b/developer/src/kmc-package/src/compiler/messages.ts @@ -54,5 +54,16 @@ export class CompilerMessages { static Warn_PackageShouldNotRepeatLanguages = (o:{resourceType: string, id: string, tag: string}) => m(this.WARN_PackageShouldNotRepeatLanguages, `The ${o.resourceType} ${o.id} has a repeated language "${o.tag}".`); static WARN_PackageShouldNotRepeatLanguages = SevWarn | 0x000C; + + static Warn_PackageNameDoesNotFollowLexicalModelConventions = (o:{filename: string}) => m(this.WARN_PackageNameDoesNotFollowLexicalModelConventions, + `The package file ${o.filename} does not follow the recommended model filename conventions. The name should be all lower case, `+ + `include only alphanumeric characters and underscore (_), not start with a digit, and should have the structure `+ + `...model.kps.`); + static WARN_PackageNameDoesNotFollowLexicalModelConventions = SevWarn | 0x000D; + + static Warn_PackageNameDoesNotFollowKeyboardConventions = (o:{filename: string}) => m(this.WARN_PackageNameDoesNotFollowKeyboardConventions, + `The package file ${o.filename} does not follow the recommended keyboard filename conventions. The name should be all lower case, `+ + `include only alphanumeric characters and underscore (_), and not start with a digit.`); + static WARN_PackageNameDoesNotFollowKeyboardConventions = SevWarn | 0x000E; } diff --git a/developer/src/kmc-package/src/compiler/package-validation.ts b/developer/src/kmc-package/src/compiler/package-validation.ts index 322cd9b355..60a1e653c1 100644 --- a/developer/src/kmc-package/src/compiler/package-validation.ts +++ b/developer/src/kmc-package/src/compiler/package-validation.ts @@ -1,19 +1,31 @@ import { KmpJsonFile, CompilerCallbacks } from '@keymanapp/common-types'; import { CompilerMessages } from './messages.js'; +// const SLexicalModelExtension = '.model.js'; + +// The keyboard ID SHOULD adhere to this pattern: +const KEYBOARD_ID_PATTERN_PACKAGE = /^[a-z_][a-z0-9_]*\.(kps|kmp)$/; + +// The model ID SHOULD adhere to this pattern: +// author .bcp47 .uniq +const MODEL_ID_PATTERN_PACKAGE = /^[a-z_][a-z0-9_]*\.[a-z_][a-z0-9_-]*\.[a-z_][a-z0-9_]*\.model\.(kps|kmp)$/; +// const MODEL_ID_PATTERN_JS = /^[a-z_][a-z0-9_]*\.[a-z_][a-z0-9_-]*\.[a-z_][a-z0-9_]*\.model\.js$/; +// const MODEL_ID_PATTERN_TS = /^[a-z_][a-z0-9_]*\.[a-z_][a-z0-9_-]*\.[a-z_][a-z0-9_]*\.model\.ts$/; +// const MODEL_ID_PATTERN_PROJECT = /^[a-z_][a-z0-9_]*\.[a-z_][a-z0-9_-]*\.[a-z_][a-z0-9_]*\.model\.kpj$/; + export class PackageValidation { constructor(private callbacks: CompilerCallbacks) { } - public validate(kmpJson: KmpJsonFile.KmpJsonFile) { + public validate(filename: string, kmpJson: KmpJsonFile.KmpJsonFile) { if(!this.checkForModelsAndKeyboardsInSamePackage(kmpJson)) { return false; } - if(!this.checkKeyboards(kmpJson)) { + if(!this.checkKeyboards(filename, kmpJson)) { return false; } - if(!this.checkLexicalModels(kmpJson)) { + if(!this.checkLexicalModels(filename, kmpJson)) { return false; } return true; @@ -40,21 +52,37 @@ export class PackageValidation { return true; } - private checkLexicalModels(kmpJson: KmpJsonFile.KmpJsonFile): boolean { - if(kmpJson.lexicalModels) { - for(let model of kmpJson.lexicalModels) { - this.checkForDuplicatedLanguages('model', model.id, model.languages); - } + private checkLexicalModels(filename: string, kmpJson: KmpJsonFile.KmpJsonFile): boolean { + if(!kmpJson.lexicalModels || kmpJson.lexicalModels.length == 0) { + return true; + } + + filename = this.callbacks.path.basename(filename); + + if(!MODEL_ID_PATTERN_PACKAGE.test(filename)) { + this.callbacks.reportMessage(CompilerMessages.Warn_PackageNameDoesNotFollowLexicalModelConventions({filename})); + } + + for(let model of kmpJson.lexicalModels) { + this.checkForDuplicatedLanguages('model', model.id, model.languages); } return true; } - private checkKeyboards(kmpJson: KmpJsonFile.KmpJsonFile): boolean { - if(kmpJson.keyboards) { - for(let keyboard of kmpJson.keyboards) { - this.checkForDuplicatedLanguages('keyboard', keyboard.id, keyboard.languages); - } + private checkKeyboards(filename: string, kmpJson: KmpJsonFile.KmpJsonFile): boolean { + if(!kmpJson.keyboards || kmpJson.keyboards.length == 0) { + return true; + } + + filename = this.callbacks.path.basename(filename); + + if(!KEYBOARD_ID_PATTERN_PACKAGE.test(filename)) { + this.callbacks.reportMessage(CompilerMessages.Warn_PackageNameDoesNotFollowKeyboardConventions({filename})); + } + + for(let keyboard of kmpJson.keyboards) { + this.checkForDuplicatedLanguages('keyboard', keyboard.id, keyboard.languages); } return true; diff --git a/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowKeyboardConventions.kps b/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowKeyboardConventions.kps new file mode 100644 index 0000000000..5ff6eca048 --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowKeyboardConventions.kps @@ -0,0 +1,32 @@ + + + + + 15.0.266.0 + 7.0 + + + SENĆOŦEN (Saanich Dialect) Lexical Model + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.0.3 + + + + nokeyboardversion.kmx + Keyboard Khmer Angkor + 0 + .kmx + + + + + Khmer Angkor + nokeyboardversion + 1.3 + + Central Khmer (Khmer, Cambodia) + + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowLexicalModelConventions.kps b/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowLexicalModelConventions.kps new file mode 100644 index 0000000000..674ad85a2f --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowLexicalModelConventions.kps @@ -0,0 +1,32 @@ + + + + + 15.0.266.0 + 7.0 + + + SENĆOŦEN (Saanich Dialect) Lexical Model + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.0.3 + + + + example.qaa.sencoten.model.js + Lexical model example.qaa.sencoten.model.js + 0 + .model.js + + + + + SENĆOŦEN dictionary + example.qaa.sencoten + + North Straits Salish + SENĆOŦEN + + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageShouldNotRepeatLanguages.model.kps b/developer/src/kmc-package/test/fixtures/invalid/keyman.en.warn_package_should_not_repeat_languages.model.kps similarity index 100% rename from developer/src/kmc-package/test/fixtures/invalid/WARN_PackageShouldNotRepeatLanguages.model.kps rename to developer/src/kmc-package/test/fixtures/invalid/keyman.en.warn_package_should_not_repeat_languages.model.kps diff --git a/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageShouldNotRepeatLanguages.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_package_should_not_repeat_languages.kps similarity index 100% rename from developer/src/kmc-package/test/fixtures/invalid/WARN_PackageShouldNotRepeatLanguages.kps rename to developer/src/kmc-package/test/fixtures/invalid/warn_package_should_not_repeat_languages.kps diff --git a/developer/src/kmc-package/test/test-package-compiler.ts b/developer/src/kmc-package/test/test-package-compiler.ts index 100bc04d4b..47eb1cb8ce 100644 --- a/developer/src/kmc-package/test/test-package-compiler.ts +++ b/developer/src/kmc-package/test/test-package-compiler.ts @@ -161,7 +161,7 @@ describe('KmpCompiler', function () { let kmpJson = kmpCompiler.transformKpsToKmpObject(kpsPath); if(kmpJson && callbacks.messages.length == 0) { const validator = new PackageValidation(callbacks); - validator.validate(kmpJson); // we'll ignore return value and rely on the messages + validator.validate(kpsPath, kmpJson); // we'll ignore return value and rely on the messages } if(kmpJson && callbacks.messages.length == 0) { @@ -228,13 +228,25 @@ describe('KmpCompiler', function () { // WARN_PackageShouldNotRepeatLanguages (models) it('should generate WARN_PackageShouldNotRepeatLanguages if model has same language repeated', async function() { - testForMessage(this, ['invalid', 'WARN_PackageShouldNotRepeatLanguages.model.kps'], CompilerMessages.WARN_PackageShouldNotRepeatLanguages); + testForMessage(this, ['invalid', 'keyman.en.warn_package_should_not_repeat_languages.model.kps'], CompilerMessages.WARN_PackageShouldNotRepeatLanguages); }); // WARN_PackageShouldNotRepeatLanguages (keyboards) it('should generate WARN_PackageShouldNotRepeatLanguages if keyboard has same language repeated', async function() { - testForMessage(this, ['invalid', 'WARN_PackageShouldNotRepeatLanguages.kps'], CompilerMessages.WARN_PackageShouldNotRepeatLanguages); + testForMessage(this, ['invalid', 'warn_package_should_not_repeat_languages.kps'], CompilerMessages.WARN_PackageShouldNotRepeatLanguages); + }); + + // WARN_PackageNameDoesNotFollowLexicalModelConventions + + it('should generate WARN_PackageNameDoesNotFollowLexicalModelConventions if filename has wrong conventions', async function() { + testForMessage(this, ['invalid', 'WARN_PackageNameDoesNotFollowLexicalModelConventions.kps'], CompilerMessages.WARN_PackageNameDoesNotFollowLexicalModelConventions); + }); + + // WARN_PackageNameDoesNotFollowKeyboardConventions + + it('should generate WARN_PackageNameDoesNotFollowKeyboardConventions if filename has wrong conventions', async function() { + testForMessage(this, ['invalid', 'WARN_PackageNameDoesNotFollowKeyboardConventions.kps'], CompilerMessages.WARN_PackageNameDoesNotFollowKeyboardConventions); }); }); diff --git a/developer/src/kmc/src/commands/build/BuildPackage.ts b/developer/src/kmc/src/commands/build/BuildPackage.ts index 4342a57094..3c7c81f6a8 100644 --- a/developer/src/kmc/src/commands/build/BuildPackage.ts +++ b/developer/src/kmc/src/commands/build/BuildPackage.ts @@ -27,7 +27,7 @@ export class BuildPackage extends BuildActivity { // const validation = new PackageValidation(callbacks); - if(!validation.validate(kmpJsonData)) { + if(!validation.validate(infile, kmpJsonData)) { return false; } diff --git a/developer/src/kmc/src/kmlmi.ts b/developer/src/kmc/src/kmlmi.ts index d0d1a01bd4..508c43ad0e 100644 --- a/developer/src/kmc/src/kmlmi.ts +++ b/developer/src/kmc/src/kmlmi.ts @@ -54,7 +54,7 @@ let kmpJsonData = kmpCompiler.transformKpsToKmpObject(kpsFilename); // const validation = new PackageValidation(callbacks); -if(!validation.validate(kmpJsonData)) { +if(!validation.validate(kpsFilename, kmpJsonData)) { process.exit(1); } diff --git a/developer/src/kmc/src/kmlmp.ts b/developer/src/kmc/src/kmlmp.ts index 49d38846af..5a54a57d71 100644 --- a/developer/src/kmc/src/kmlmp.ts +++ b/developer/src/kmc/src/kmlmp.ts @@ -49,7 +49,7 @@ if(!kmpJsonData) { // const validation = new PackageValidation(callbacks); -if(!validation.validate(kmpJsonData)) { +if(!validation.validate(inputFilename, kmpJsonData)) { process.exit(1); } -- GitLab From e19f6fbde46d0f0e10e9f25a7bafed7b50324bca Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Thu, 11 May 2023 13:28:34 +0700 Subject: [PATCH 068/214] Apply suggestions from code review Co-authored-by: Marc Durdin --- android/KMAPro/build-play-store-notes.inc.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/android/KMAPro/build-play-store-notes.inc.sh b/android/KMAPro/build-play-store-notes.inc.sh index 6e92b12108..04fa876417 100755 --- a/android/KMAPro/build-play-store-notes.inc.sh +++ b/android/KMAPro/build-play-store-notes.inc.sh @@ -35,20 +35,20 @@ function generateReleaseNotes() { IFS=$'\n' for line in $FILTERED_LINES do - local CHARS_IN_RELEASE_NOTES=$( wc -m < $PLAY_RELEASE_NOTES ) + local CHARS_IN_RELEASE_NOTES=$( wc -m < "$PLAY_RELEASE_NOTES" ) local CHARS_IN_CURRENT_LINE=$( wc -m <<< $line ) if (( CHARS_IN_RELEASE_NOTES + CHARS_IN_CURRENT_LINE + 1 < 450 )); then # Copy line to Play Store release notes - echo "$line" >> $PLAY_RELEASE_NOTES + echo "$line" >> "$PLAY_RELEASE_NOTES" else # 450 chars reached builder_warn "Warning: Play Store release notes approaching 500 character limit" - echo "$DEFAULT_RELEASE_NOTE" >> $PLAY_RELEASE_NOTES + echo "$DEFAULT_RELEASE_NOTE" >> "$PLAY_RELEASE_NOTES" break fi done # Restore IFS - IFS=${old_IFS} + IFS="${old_IFS}" popd } -- GitLab From c169b5ca100a512aebba39834c52188902a4ee74 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Thu, 11 May 2023 13:29:34 +0700 Subject: [PATCH 069/214] chore(android/app): Remove stray test code --- android/build-publish.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/android/build-publish.sh b/android/build-publish.sh index 124e69b46d..e7475cdeba 100755 --- a/android/build-publish.sh +++ b/android/build-publish.sh @@ -75,7 +75,6 @@ echo "BUILD_FLAGS $BUILD_FLAGS" if [ "$DO_KMAPRO" = true ]; then # Copy Release Notes generateReleaseNotes - exit ./gradlew $DAEMON_FLAG $BUILD_FLAGS fi -- GitLab From 840c82c209a2f1de9d87698027e56cebc0e7944c Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Thu, 11 May 2023 13:31:30 +0700 Subject: [PATCH 070/214] chore(android): Revert script header --- android/build-publish.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/android/build-publish.sh b/android/build-publish.sh index e7475cdeba..a77903c9fe 100755 --- a/android/build-publish.sh +++ b/android/build-publish.sh @@ -1,3 +1,4 @@ +#!/usr/bin/env bash # CI script to publish specified app APKs to the Play Store. # The APKs should already have been built from a separate script -- GitLab From b2be12c25857e9250eee168a947a3015b1b4b4bf Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 11 May 2023 14:42:26 +0700 Subject: [PATCH 071/214] feat(developer): validate content file names in packages --- .../src/kmc-package/src/compiler/messages.ts | 5 +++ .../src/compiler/package-validation.ts | 28 ++++++++++++++++ ...e_does_not_follow_filename_conventions.kps | 32 +++++++++++++++++++ ...does_not_follow_filename_conventions_2.kps | 32 +++++++++++++++++++ .../kmc-package/test/test-package-compiler.ts | 7 ++++ 5 files changed, 104 insertions(+) create mode 100644 developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions.kps create mode 100644 developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions_2.kps diff --git a/developer/src/kmc-package/src/compiler/messages.ts b/developer/src/kmc-package/src/compiler/messages.ts index 38447d58e6..73134fec96 100644 --- a/developer/src/kmc-package/src/compiler/messages.ts +++ b/developer/src/kmc-package/src/compiler/messages.ts @@ -65,5 +65,10 @@ export class CompilerMessages { `The package file ${o.filename} does not follow the recommended keyboard filename conventions. The name should be all lower case, `+ `include only alphanumeric characters and underscore (_), and not start with a digit.`); static WARN_PackageNameDoesNotFollowKeyboardConventions = SevWarn | 0x000E; + + static Warn_FileInPackageDoesNotFollowFilenameConventions = (o:{filename: string}) => m(this.WARN_FileInPackageDoesNotFollowFilenameConventions, + `The file ${o.filename} does not follow the recommended filename conventions. The extension should be all lower case, `+ + `and the filename should include only alphanumeric characters, -, _, + and .`); + static WARN_FileInPackageDoesNotFollowFilenameConventions = SevWarn | 0x000F; } diff --git a/developer/src/kmc-package/src/compiler/package-validation.ts b/developer/src/kmc-package/src/compiler/package-validation.ts index 60a1e653c1..206688854c 100644 --- a/developer/src/kmc-package/src/compiler/package-validation.ts +++ b/developer/src/kmc-package/src/compiler/package-validation.ts @@ -13,6 +13,10 @@ const MODEL_ID_PATTERN_PACKAGE = /^[a-z_][a-z0-9_]*\.[a-z_][a-z0-9_-]*\.[a-z_][a // const MODEL_ID_PATTERN_TS = /^[a-z_][a-z0-9_]*\.[a-z_][a-z0-9_-]*\.[a-z_][a-z0-9_]*\.model\.ts$/; // const MODEL_ID_PATTERN_PROJECT = /^[a-z_][a-z0-9_]*\.[a-z_][a-z0-9_-]*\.[a-z_][a-z0-9_]*\.model\.kpj$/; +// "Content files" within the package should adhere to these pattern: +const CONTENT_FILE_BASENAME_PATTERN = /^[a-z0-9_+.-]+$/; +const CONTENT_FILE_EXTENSION_PATTERN = /^\.[a-z0-9_]+$/; + export class PackageValidation { constructor(private callbacks: CompilerCallbacks) { @@ -28,6 +32,9 @@ export class PackageValidation { if(!this.checkLexicalModels(filename, kmpJson)) { return false; } + if(!this.checkContentFiles(kmpJson)) { + return false; + } return true; } @@ -87,4 +94,25 @@ export class PackageValidation { return true; } + + private checkContentFiles(kmpJson: KmpJsonFile.KmpJsonFile): boolean { + for(let file of kmpJson.files) { + if(!this.checkContentFile(file)) { + return false; + } + } + + return true; + } + + private checkContentFile(file: KmpJsonFile.KmpJsonFileContentFile): boolean { + const filename = this.callbacks.path.basename(file.name); + const ext = this.callbacks.path.extname(filename); + const base = filename.substring(0, filename.length-ext.length); + if(!CONTENT_FILE_BASENAME_PATTERN.test(base) || !CONTENT_FILE_EXTENSION_PATTERN.test(ext)) { + this.callbacks.reportMessage(CompilerMessages.Warn_FileInPackageDoesNotFollowFilenameConventions({filename})); + } + + return true; + } } diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions.kps new file mode 100644 index 0000000000..25c100256b --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions.kps @@ -0,0 +1,32 @@ + + + + 15.0.266.0 + 7.0 + + + SENĆOŦEN (Saanich Dialect) Lexical Model + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.0.3 + + + + + my special keyboard.kmx + Keyboard my special keyboard + 0 + .kmx + + + + + Khmer Angkor + nokeyboardversion + 1.3 + + Central Khmer (Khmer, Cambodia) + + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions_2.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions_2.kps new file mode 100644 index 0000000000..0d6e81165e --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions_2.kps @@ -0,0 +1,32 @@ + + + + 15.0.266.0 + 7.0 + + + SENĆOŦEN (Saanich Dialect) Lexical Model + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.0.3 + + + + + my_special-keyboard.KMX + Keyboard my special keyboard + 0 + .kmx + + + + + Khmer Angkor + nokeyboardversion + 1.3 + + Central Khmer (Khmer, Cambodia) + + + + diff --git a/developer/src/kmc-package/test/test-package-compiler.ts b/developer/src/kmc-package/test/test-package-compiler.ts index 47eb1cb8ce..ab410562f0 100644 --- a/developer/src/kmc-package/test/test-package-compiler.ts +++ b/developer/src/kmc-package/test/test-package-compiler.ts @@ -249,4 +249,11 @@ describe('KmpCompiler', function () { testForMessage(this, ['invalid', 'WARN_PackageNameDoesNotFollowKeyboardConventions.kps'], CompilerMessages.WARN_PackageNameDoesNotFollowKeyboardConventions); }); + // WARN_FileInPackageDoesNotFollowFilenameConventions + + it('should generate WARN_FileInPackageDoesNotFollowFilenameConventions if content filename has wrong conventions', async function() { + testForMessage(this, ['invalid', 'warn_file_in_package_does_not_follow_filename_conventions.kps'], CompilerMessages.WARN_FileInPackageDoesNotFollowFilenameConventions); + testForMessage(this, ['invalid', 'warn_file_in_package_does_not_follow_filename_conventions_2.kps'], CompilerMessages.WARN_FileInPackageDoesNotFollowFilenameConventions); + }); + }); -- GitLab From 70279914a8a40f5cb38d027ab8258e5781bd9d86 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 11 May 2023 15:03:53 +0700 Subject: [PATCH 072/214] feat(developer): validate package name in compiler --- .../src/kmc-package/src/compiler/messages.ts | 4 +++ .../src/compiler/package-validation.ts | 12 +++++++ .../error_package_name_cannot_be_blank.kps | 32 +++++++++++++++++++ .../error_package_name_cannot_be_blank_2.kps | 31 ++++++++++++++++++ .../error_package_name_cannot_be_blank_3.kps | 26 +++++++++++++++ .../kmc-package/test/test-package-compiler.ts | 8 +++++ 6 files changed, 113 insertions(+) create mode 100644 developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank.kps create mode 100644 developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_2.kps create mode 100644 developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_3.kps diff --git a/developer/src/kmc-package/src/compiler/messages.ts b/developer/src/kmc-package/src/compiler/messages.ts index 73134fec96..8c47e9e0db 100644 --- a/developer/src/kmc-package/src/compiler/messages.ts +++ b/developer/src/kmc-package/src/compiler/messages.ts @@ -70,5 +70,9 @@ export class CompilerMessages { `The file ${o.filename} does not follow the recommended filename conventions. The extension should be all lower case, `+ `and the filename should include only alphanumeric characters, -, _, + and .`); static WARN_FileInPackageDoesNotFollowFilenameConventions = SevWarn | 0x000F; + + static Error_PackageNameCannotBeBlank = () => m(this.ERROR_PackageNameCannotBeBlank, + `Package name cannot be an empty string.`); + static ERROR_PackageNameCannotBeBlank = SevError | 0x0010; } diff --git a/developer/src/kmc-package/src/compiler/package-validation.ts b/developer/src/kmc-package/src/compiler/package-validation.ts index 206688854c..5ef32c43da 100644 --- a/developer/src/kmc-package/src/compiler/package-validation.ts +++ b/developer/src/kmc-package/src/compiler/package-validation.ts @@ -35,6 +35,9 @@ export class PackageValidation { if(!this.checkContentFiles(kmpJson)) { return false; } + if(!this.checkPackageInfo(kmpJson)) { + return false; + } return true; } @@ -115,4 +118,13 @@ export class PackageValidation { return true; } + + private checkPackageInfo(file: KmpJsonFile.KmpJsonFile) { + if(!file.info || !file.info.name || !file.info.name.description.trim()) { + this.callbacks.reportMessage(CompilerMessages.Error_PackageNameCannotBeBlank()); + return false; + } + + return true; + } } diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank.kps b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank.kps new file mode 100644 index 0000000000..6fb56f3827 --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank.kps @@ -0,0 +1,32 @@ + + + + 15.0.266.0 + 7.0 + + + + + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.0.3 + + + + nokeyboardversion.kmx + Keyboard Khmer Angkor + 0 + .kmx + + + + + Khmer Angkor + nokeyboardversion + 1.3 + + Central Khmer (Khmer, Cambodia) + + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_2.kps b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_2.kps new file mode 100644 index 0000000000..46b182ffc6 --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_2.kps @@ -0,0 +1,31 @@ + + + + 15.0.266.0 + 7.0 + + + + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.0.3 + + + + nokeyboardversion.kmx + Keyboard Khmer Angkor + 0 + .kmx + + + + + Khmer Angkor + nokeyboardversion + 1.3 + + Central Khmer (Khmer, Cambodia) + + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_3.kps b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_3.kps new file mode 100644 index 0000000000..5b29699f4c --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_3.kps @@ -0,0 +1,26 @@ + + + + 15.0.266.0 + 7.0 + + + + + nokeyboardversion.kmx + Keyboard Khmer Angkor + 0 + .kmx + + + + + Khmer Angkor + nokeyboardversion + 1.3 + + Central Khmer (Khmer, Cambodia) + + + + diff --git a/developer/src/kmc-package/test/test-package-compiler.ts b/developer/src/kmc-package/test/test-package-compiler.ts index ab410562f0..86675597b1 100644 --- a/developer/src/kmc-package/test/test-package-compiler.ts +++ b/developer/src/kmc-package/test/test-package-compiler.ts @@ -256,4 +256,12 @@ describe('KmpCompiler', function () { testForMessage(this, ['invalid', 'warn_file_in_package_does_not_follow_filename_conventions_2.kps'], CompilerMessages.WARN_FileInPackageDoesNotFollowFilenameConventions); }); + // ERROR_PackageNameCannotBeBlank + + it('should generate ERROR_PackageNameCannotBeBlank if package info has empty name', async function() { + testForMessage(this, ['invalid', 'error_package_name_cannot_be_blank.kps'], CompilerMessages.ERROR_PackageNameCannotBeBlank); // blank field + testForMessage(this, ['invalid', 'error_package_name_cannot_be_blank_2.kps'], CompilerMessages.ERROR_PackageNameCannotBeBlank); // missing field + testForMessage(this, ['invalid', 'error_package_name_cannot_be_blank_3.kps'], CompilerMessages.ERROR_PackageNameCannotBeBlank); // missing info section + }); + }); -- GitLab From 1b76f98ec8691f56841145770c6fecdbfacf057d Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Thu, 11 May 2023 09:49:26 +0200 Subject: [PATCH 073/214] chore(linux): Add .shellcheckrc instead of inline directives Also improve output specification. Co-authored-by: Marc Durdin --- .shellcheckrc | 2 ++ linux/keyman-config/build.sh | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 .shellcheckrc diff --git a/.shellcheckrc b/.shellcheckrc new file mode 100644 index 0000000000..36f5b46689 --- /dev/null +++ b/.shellcheckrc @@ -0,0 +1,2 @@ +external-sources=true +source-path=resources/build/ diff --git a/linux/keyman-config/build.sh b/linux/keyman-config/build.sh index d3a25baf0d..38cf22e917 100755 --- a/linux/keyman-config/build.sh +++ b/linux/keyman-config/build.sh @@ -3,7 +3,6 @@ ## START STANDARD BUILD SCRIPT INCLUDE # adjust relative paths as necessary THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" -# shellcheck source=resources/build/build-utils.sh . "${THIS_SCRIPT%/*}/../../resources/build/build-utils.sh" ## END STANDARD BUILD SCRIPT INCLUDE @@ -23,7 +22,7 @@ builder_parse "$@" cd "$THIS_SCRIPT_PATH" builder_describe_outputs \ - build "keyman_config/standards/lang_tags_map.py" + build "/linux/keyman-config/keyman_config/standards/lang_tags_map.py" builder_run_action clean make clean builder_run_action configure # nothing to do -- GitLab From 032a1233471cf5e3233f7e1a0ec86489b1f87cf6 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Thu, 11 May 2023 11:59:15 +0200 Subject: [PATCH 074/214] chore(linux): Properly fix shellcheck SC1091 warnings The secret is to disable the "shellcheck.useWorkspaceRootAsCwd". --- .shellcheckrc | 5 ++++- docs/settings/linux/settings.json | 1 + linux/build.sh | 1 - 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.shellcheckrc b/.shellcheckrc index 36f5b46689..1c46a510eb 100644 --- a/.shellcheckrc +++ b/.shellcheckrc @@ -1,2 +1,5 @@ external-sources=true -source-path=resources/build/ + +# If you get SC1091 for sourced files, add the following setting to +# your .vscode/settings.json file: +# "shellcheck.useWorkspaceRootAsCwd": false diff --git a/docs/settings/linux/settings.json b/docs/settings/linux/settings.json index be15b13027..891507dd2e 100644 --- a/docs/settings/linux/settings.json +++ b/docs/settings/linux/settings.json @@ -107,4 +107,5 @@ "--external-sources --source-path=resources/build/" ], "C_Cpp.errorSquiggles": "EnabledIfIncludesResolve", + "shellcheck.useWorkspaceRootAsCwd": false } diff --git a/linux/build.sh b/linux/build.sh index 8e2b10f289..8bdbb368c7 100755 --- a/linux/build.sh +++ b/linux/build.sh @@ -5,7 +5,6 @@ set -eu ## START STANDARD BUILD SCRIPT INCLUDE # adjust relative paths as necessary THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" -# shellcheck source=resources/build/build-utils.sh . "${THIS_SCRIPT%/*}/../resources/build/build-utils.sh" ## END STANDARD BUILD SCRIPT INCLUDE -- GitLab From 631758352805324cb564de60e90389e3aca9a611 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Thu, 11 May 2023 10:37:46 -0500 Subject: [PATCH 075/214] =?UTF-8?q?feat(developer):=20kmc-kmn:=20wasm=20an?= =?UTF-8?q?d=20error=20message=20updates=20=F0=9F=99=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit developer: - update wasm machinery in kmc-kmn to be more self contained - improve exception situation in wasm functions common: - compilerErrorFormatCode() for formatting the raw code such as for tests - compilerExceptionToString() for formatting exceptions in messages for: #7234 --- common/web/types/src/main.ts | 4 +- .../web/types/src/util/compiler-interfaces.ts | 19 +++++++ .../verifyCompilerMessagesObject.ts | 10 ++-- .../src/kmc-kmn/src/compiler/compiler.ts | 57 ++++++++++++------- .../src/kmc-kmn/src/compiler/messages.ts | 6 +- developer/src/kmc-kmn/test/test-wasm-uset.ts | 7 ++- 6 files changed, 72 insertions(+), 31 deletions(-) diff --git a/common/web/types/src/main.ts b/common/web/types/src/main.ts index 4dad5f96ab..749c29906e 100644 --- a/common/web/types/src/main.ts +++ b/common/web/types/src/main.ts @@ -18,7 +18,7 @@ export { default as LDMLKeyboardXMLSourceFileReader } from './ldml-keyboard/ldml export * as Constants from './consts/virtual-key-constants.js'; -export { CompilerCallbacks, CompilerSchema, CompilerEvent, CompilerErrorNamespace, CompilerErrorSeverity, CompilerPathCallbacks, CompilerFileSystemCallbacks, CompilerMessageSpec, compilerErrorSeverityName } from './util/compiler-interfaces.js'; +export { CompilerCallbacks, CompilerSchema, CompilerEvent, CompilerErrorNamespace, CompilerErrorSeverity, CompilerPathCallbacks, CompilerFileSystemCallbacks, CompilerMessageSpec, compilerErrorSeverityName, compilerExceptionToString, compilerErrorFormatCode } from './util/compiler-interfaces.js'; export { CommonTypesMessages } from './util/common-events.js'; export * as TouchLayout from './keyman-touch-layout/keyman-touch-layout-file.js'; @@ -29,4 +29,4 @@ export * as KPJ from './kpj/kpj-file.js'; export { KPJFileReader } from './kpj/kpj-file-reader.js'; export { KeymanDeveloperProject } from './kpj/keyman-developer-project.js'; -export * as util from './util/util.js'; \ No newline at end of file +export * as util from './util/util.js'; diff --git a/common/web/types/src/util/compiler-interfaces.ts b/common/web/types/src/util/compiler-interfaces.ts index a58484298a..c7058b1578 100644 --- a/common/web/types/src/util/compiler-interfaces.ts +++ b/common/web/types/src/util/compiler-interfaces.ts @@ -32,6 +32,18 @@ export function compilerErrorSeverityName(code: number): string { } } +/** + * Format the error code number + * example: "FATAL:0x03004" + */ +export function compilerErrorFormatCode(code: number): string { + const severity = code & CompilerErrorSeverity.Severity_Mask; + const severityName = compilerErrorSeverityName(severity); + const errorCode = code & CompilerErrorSeverity.Error_Mask; + const errorCodeString = Number(errorCode).toString(16).padStart(5,'0'); + return `${severityName}:0x${errorCodeString}`; +} + /** * Defines the error code ranges for various compilers. Once defined, these * ranges must not be changed as external modules may depend on specific error @@ -137,3 +149,10 @@ export interface CompilerCallbacks { * @returns */ export const CompilerMessageSpec = (code: number, message: string) : CompilerEvent => { return { code, message } }; + +/** + * @param e Error-like + */ +export function compilerExceptionToString(e?: any) : string { + return `${(e ?? 'unknown error').toString()}\n\nCall stack:\n${(e instanceof Error ? e.stack : (new Error()).stack)}`; +} diff --git a/developer/src/common/web/test-helpers/verifyCompilerMessagesObject.ts b/developer/src/common/web/test-helpers/verifyCompilerMessagesObject.ts index 7c52f403a2..223ab430f3 100644 --- a/developer/src/common/web/test-helpers/verifyCompilerMessagesObject.ts +++ b/developer/src/common/web/test-helpers/verifyCompilerMessagesObject.ts @@ -19,13 +19,13 @@ import {assert, expect} from 'chai'; const toTitleCase = (s: string) => s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase(); export function verifyCompilerMessagesObject(source: Record) { - let keys = Object.keys(source); + const keys = Object.keys(source); const m = source as Record; - let codes: number[] = []; + const codes: number[] = []; - for(let key of keys) { + for(const key of keys) { // Verify each object member matches the pattern we expect @@ -36,7 +36,7 @@ export function verifyCompilerMessagesObject(source: Record) { const c = o[1].toUpperCase() + '_' + o[2]; expect(m[c]).to.be.a('number', `Expected constant name ${c} to exist`); - let v = m[key]('','','','','','','','','','','','' /* ignore arguments*/); + const v = m[key]('','','','','','','','','','','','' /* ignore arguments*/); expect(v.code).to.equal(m[c], `Function ${key} returns the wrong code`); } else if(typeof m[key] == 'number') { @@ -63,4 +63,4 @@ export function verifyCompilerMessagesObject(source: Record) { codes.push(code); } } -} \ No newline at end of file +} diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index 8b1b04e267..be06f742dd 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -47,35 +47,50 @@ const baseOptions: CompilerOptions = { */ let callbackProcIdentifier = 0; +/** + * Pointer in wasm-space + */ +type WasmPtr = number; + /** * The wrapped functions */ -class WrappedWasmFuncs { - compileKeyboardFile?: (a0: string, a1: string, a2: number, a3: number, a4: number, a5: string) => boolean; - parseUnicodeSet?: (a0: string, a1: number, a2: number) => number; +class WasmWrapper { + Module: any; + + compileKeyboardFile?: (pszInfile: string, pszOutfile: string, aSaveDebug: number, aCompilerWarningsAsErrors: number, aWarnDeprecatedCode: number, msgProc: string) => boolean; + parseUnicodeSet?: (pat: string, buf: WasmPtr, length: number) => number; setCompilerOptions?: (shouldAddCompilerVersion: number) => boolean; constructor(wasmModule: any) { - this.compileKeyboardFile = wasmModule.cwrap('kmcmp_Wasm_CompileKeyboardFile', 'boolean', ['string', 'string', 'number', 'number', 'number', 'string']); - this.parseUnicodeSet = wasmModule.cwrap('kmcmp_Wasm_ParseUnicodeSet', 'number', ['string', 'number', 'number']); - this.setCompilerOptions = wasmModule.cwrap('kmcmp_Wasm_SetCompilerOptions', 'boolean', ['number']); + this.Module = wasmModule; + if (!wasmModule) { + throw Error(`wasm host did not load`); + } + this.compileKeyboardFile = this.Module.cwrap('kmcmp_Wasm_CompileKeyboardFile', 'boolean', ['string', 'string', 'number', 'number', 'number', 'string']); + this.parseUnicodeSet = this.Module.cwrap('kmcmp_Wasm_ParseUnicodeSet', 'number', ['string', 'number', 'number']); + this.setCompilerOptions = this.Module.cwrap('kmcmp_Wasm_SetCompilerOptions', 'boolean', ['number']); + + if (this.parseUnicodeSet == undefined + || this.setCompilerOptions == undefined + || this.compileKeyboardFile == undefined) { + throw Error(`some wasm functions did not load properly.`); + } } /** - * @returns true if the functions are setup ok + * Entry point into Wasm functions + * @returns WasmWrapper */ - get ok(): boolean { - return this.parseUnicodeSet !== undefined - && this.setCompilerOptions !== undefined - && this.compileKeyboardFile !== undefined; + public static async load() : Promise { + return new WasmWrapper(await loadWasmHost()); } }; export class Compiler { - wasmModule: any; callbackName: string; callbacks: CompilerCallbacks; - wasm: WrappedWasmFuncs; + wasm: WasmWrapper; constructor() { this.callbackName = 'kmnCompilerCallback' + callbackProcIdentifier; @@ -86,9 +101,13 @@ export class Compiler { if(!this.callbacks) { this.callbacks = callbacks; } - if(!this.wasmModule) { - this.wasmModule = await loadWasmHost(); - this.wasm = new WrappedWasmFuncs(this.wasmModule); + if(!this.wasm) { + try { + this.wasm = await WasmWrapper.load(); + } catch(e: any) { + this.callbacks.reportMessage(CompilerMessages.Fatal_MissingWasmModule({e})); + return false; + } } return this.verifyInitted(); } @@ -102,8 +121,8 @@ export class Compiler { // Can't report a message here. throw Error('Must call Compiler.init(callbacks) before proceeding'); } - if(!this.wasmModule || !this.wasm.ok) { // fail if wasm not loaded or function not found - this.callbacks.reportMessage(CompilerMessages.Fatal_MissingWasmModule()); + if(!this.wasm) { // fail if wasm not loaded or function not found + this.callbacks.reportMessage(CompilerMessages.Fatal_MissingWasmModule({})); return false; } return true; @@ -159,7 +178,7 @@ export class Compiler { if (!bufferSize) { bufferSize = 100; // TODO-LDML: Preflight mode? Reuse buffer? } - const Module = this.wasmModule; + const { Module } = this.wasm; const buf = Module.asm.malloc(bufferSize * 2 * Module.HEAPU32.BYTES_PER_ELEMENT); // TODO-LDML: Catch OOM const rc = this.wasm.parseUnicodeSet(pattern, buf, bufferSize); diff --git a/developer/src/kmc-kmn/src/compiler/messages.ts b/developer/src/kmc-kmn/src/compiler/messages.ts index ae854f7316..10578870d7 100644 --- a/developer/src/kmc-kmn/src/compiler/messages.ts +++ b/developer/src/kmc-kmn/src/compiler/messages.ts @@ -1,4 +1,4 @@ -import { CompilerErrorNamespace, CompilerErrorSeverity, CompilerEvent, CompilerMessageSpec as m } from "@keymanapp/common-types"; +import { CompilerErrorNamespace, CompilerErrorSeverity, CompilerEvent, CompilerMessageSpec as m, compilerExceptionToString as exc } from "@keymanapp/common-types"; const Namespace = CompilerErrorNamespace.KmnCompiler; const SevInfo = CompilerErrorSeverity.Info | Namespace; @@ -44,10 +44,10 @@ export const enum KmnCompilerMessageRanges { and the below ranges are reserved. */ export class CompilerMessages { - static Fatal_UnexpectedException = (o:{e: any}) => m(this.FATAL_UnexpectedException, `Unexpected exception: ${(o.e ?? 'unknown error').toString()}\n\nCall stack:\n${(o.e instanceof Error ? o.e.stack : (new Error()).stack)}`); + static Fatal_UnexpectedException = (o:{e: any}) => m(this.FATAL_UnexpectedException, `Unexpected exception: ${exc(o.e)}`); static FATAL_UnexpectedException = SevFatal | 0x1000; - static Fatal_MissingWasmModule = () => m(this.FATAL_MissingWasmModule, `Could not instantiate WASM compiler module or not initted`); + static Fatal_MissingWasmModule = (o:{e?: any}) => m(this.FATAL_MissingWasmModule, `Could not instantiate WASM compiler module or initialization failed: ${exc(o.e)}`); static FATAL_MissingWasmModule = SevFatal | 0x1001; static Fatal_UnableToSetCompilerOptions = () => m(this.FATAL_UnableToSetCompilerOptions, `Unable to set compiler options`); diff --git a/developer/src/kmc-kmn/test/test-wasm-uset.ts b/developer/src/kmc-kmn/test/test-wasm-uset.ts index 2fc8693a31..bc4774f45b 100644 --- a/developer/src/kmc-kmn/test/test-wasm-uset.ts +++ b/developer/src/kmc-kmn/test/test-wasm-uset.ts @@ -3,6 +3,7 @@ import { assert } from 'chai'; import { Compiler } from '../src/main.js'; import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; import { CompilerMessages } from '../src/compiler/messages.js'; +import { compilerErrorFormatCode } from '@keymanapp/common-types'; describe('Compiler UnicodeSet function', function() { it('should start', async function() { @@ -54,11 +55,13 @@ describe('Compiler UnicodeSet function', function() { '[abc{def}]': CompilerMessages.ERROR_UnicodeSetHasStrings, '[[]': CompilerMessages.ERROR_UnicodeSetSyntaxError, }; - for(const [pat, rc] of Object.entries(failures)) { + for(const [pat, expected] of Object.entries(failures)) { callbacks.clear(); assert.notOk(compiler.parseUnicodeSet(pat, 1)); assert.equal(callbacks.messages.length, 1); - assert.equal(callbacks.messages[0].code, rc); + const firstMessage = callbacks.messages[0]; + const code = firstMessage.code; + assert.equal(code, expected, `${compilerErrorFormatCode(code)}≠${compilerErrorFormatCode(expected)} got ${firstMessage.message} for ${pat}`); } }); }); -- GitLab From 7a63284dd2a164dee7daec523c5a1ad259a6722e Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Thu, 11 May 2023 14:01:52 -0400 Subject: [PATCH 076/214] auto: increment master version to 17.0.106 --- HISTORY.md | 6 ++++++ VERSION.md | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 5d9d9b3e87..b8e4bba32c 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,11 @@ # Keyman Version History +## 17.0.105 alpha 2023-05-11 + +* chore(common): Update crowdin strings for Amharic (#8748) +* chore(android/app): Cleanup build-play-store-notes script (#8749) +* chore(linux): Add build.sh for keyman-config (#8733) + ## 17.0.104 alpha 2023-05-10 * chore(developer): rename kmc-keyboard to kmc-ldml (#8725) diff --git a/VERSION.md b/VERSION.md index 06c4aa53a4..6c7991375d 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.105 \ No newline at end of file +17.0.106 \ No newline at end of file -- GitLab From 3c3a363478082d26c666a79e7f17ca0fa96cdefe Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 12 May 2023 07:19:33 +0700 Subject: [PATCH 077/214] feat(developer): verify keyboard versions in kmc-package Refactor the `extractKeyboardVersionFromKmx` function into a new class and add extra version checking. This caused a bit of a cascade of test failures due to some of the 'invalid' fixtures actually being invalid in multiple ways, so the fixtures have been corrected to only be wrong in a single way -- the way they are supposed to be broken. This means additional fixture files in the 'invalid' folder. Now updates keyboard version metadata for all keyboards in the package. Upgrades `WARN_FollowKeyboardVersionButNoKeyboards` to `ERROR_FollowKeyboardVersionButNoKeyboards`, as this leads to invalid package metadata on build. Renames `ERROR_KeyboardFileNotFound` to `ERROR_KeyboardContentFileNotFound` to better reflect that no `` in the package is found to match a given `` entry. Adds `ERROR_KeyboardFileNotFound` when a referenced .kmx does not exist. Adds and updates corresponding unit tests. --- .../src/common/web/test-helpers/index.ts | 13 +- .../kmc-package/src/compiler/kmp-compiler.ts | 74 +---------- .../src/kmc-package/src/compiler/messages.ts | 12 +- .../src/compiler/package-validation.ts | 2 +- .../compiler/package-version-validation.ts | 118 +++++++++++++++++ ...ageCannotContainBothModelsAndKeyboards.kps | 4 +- ...geNameDoesNotFollowKeyboardConventions.kps | 4 +- .../error_package_name_cannot_be_blank.kps | 4 +- .../error_package_name_cannot_be_blank_2.kps | 4 +- .../error_package_name_cannot_be_blank_3.kps | 4 +- .../invalid/keyboardcontentfilenotfound.kps | 125 ++++++++++++++++++ .../fixtures/invalid/keyboardfilenotfound.kps | 94 +------------ .../test/fixtures/invalid/khmer_angkor.kmx | Bin 0 -> 26280 bytes .../fixtures/invalid/my special keyboard.kmx | Bin 0 -> 26280 bytes .../fixtures/invalid/my_special-keyboard.kmx | Bin 0 -> 26280 bytes ...e_does_not_follow_filename_conventions.kps | 2 +- ...does_not_follow_filename_conventions_2.kps | 11 +- ...rn_package_should_not_repeat_languages.kps | 4 +- .../kmc-package/test/test-package-compiler.ts | 24 +++- developer/src/kmc/src/kmlmi.ts | 3 + 20 files changed, 318 insertions(+), 184 deletions(-) create mode 100644 developer/src/kmc-package/src/compiler/package-version-validation.ts create mode 100644 developer/src/kmc-package/test/fixtures/invalid/keyboardcontentfilenotfound.kps create mode 100644 developer/src/kmc-package/test/fixtures/invalid/khmer_angkor.kmx create mode 100644 developer/src/kmc-package/test/fixtures/invalid/my special keyboard.kmx create mode 100644 developer/src/kmc-package/test/fixtures/invalid/my_special-keyboard.kmx diff --git a/developer/src/common/web/test-helpers/index.ts b/developer/src/common/web/test-helpers/index.ts index 53c21ec590..3416a16c87 100644 --- a/developer/src/common/web/test-helpers/index.ts +++ b/developer/src/common/web/test-helpers/index.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import { CompilerEvent, CompilerCallbacks, CompilerSchema, CompilerPathCallbacks, CompilerFileSystemCallbacks } from '@keymanapp/common-types'; +import { CompilerEvent, CompilerCallbacks, CompilerSchema, CompilerPathCallbacks, CompilerFileSystemCallbacks, compilerErrorSeverityName } from '@keymanapp/common-types'; export { verifyCompilerMessagesObject } from './verifyCompilerMessagesObject.js'; // TODO: schemas are only used by kmc-keyboard for now, so this works at this @@ -19,6 +19,17 @@ export class TestCompilerCallbacks implements CompilerCallbacks { this.messages = []; } + printMessages() { + this.messages.forEach(event => { + const code = event.code.toString(16); + if(event.line) { + console.log(`${compilerErrorSeverityName(event.code)} ${code} [${event.line}]: ${event.message}`); + } else { + console.log(`${compilerErrorSeverityName(event.code)} ${code}: ${event.message}`); + } + }); + } + hasMessage(code: number): boolean { return this.messages.find((item) => item.code == code) === undefined ? false : true; } diff --git a/developer/src/kmc-package/src/compiler/kmp-compiler.ts b/developer/src/kmc-package/src/compiler/kmp-compiler.ts index 160182edb1..305a1faaa1 100644 --- a/developer/src/kmc-package/src/compiler/kmp-compiler.ts +++ b/developer/src/kmc-package/src/compiler/kmp-compiler.ts @@ -4,7 +4,8 @@ import KEYMAN_VERSION from "@keymanapp/keyman-version"; import { CompilerCallbacks, KvkFile } from '@keymanapp/common-types'; import { CompilerMessages } from './messages.js'; -import { KmpJsonFile, KpsFile, KMX, KmxFileReader } from '@keymanapp/common-types'; +import { KmpJsonFile, KpsFile } from '@keymanapp/common-types'; +import { PackageVersionValidation } from './package-version-validation.js'; const FILEVERSION_KMP_JSON = '12.0'; @@ -127,14 +128,13 @@ export class KmpCompiler { } // - // FollowKeyboardVersion support + // Verify version metadata; doing this in the transform + // while we have access to the .kps metadata, and keeping the // - if(kps.options?.followKeyboardVersion !== undefined) { - kmp.info.version = { - description: this.extractKeyboardVersionFromKmx(kpsFilename, kmp) - }; - // TODO: compare the extracted version with other keyboards in the package + const versionValidator = new PackageVersionValidation(this.callbacks); + if(!versionValidator.validateAndUpdateVersions(kpsFilename, kps, kmp)) { + return null; } // @@ -195,67 +195,7 @@ export class KmpCompiler { return language.map((element) => { return { name: element._, id: element.$.ID } }); }; - private extractKeyboardVersionFromKmx(kpsFilename: string, kmp: KmpJsonFile.KmpJsonFile) { - // The DEFAULT_VERSION used to be '1.0', but we now use '0.0' to allow - // pre-release 0.x keyboards to be considered later than a keyboard without - // any version metadata at all. - const DEFAULT_VERSION = '0.0'; - - // Note: there is often version metadata in the .kps element, but - // we don't read from the metadata because we want to ensure we have the - // most up-to-date keyboard version data here, from the compiled keyboard. - - // Lexical model packages do not allow FollowKeyboardVersion - if(kmp.lexicalModels && kmp.lexicalModels.length) { - this.callbacks.reportMessage(CompilerMessages.Error_FollowKeyboardVersionNotAllowedForModelPackages()); - return DEFAULT_VERSION; - } - - if(!kmp.keyboards || !kmp.keyboards.length) { - this.callbacks.reportMessage(CompilerMessages.Warn_FollowKeyboardVersionButNoKeyboards()); - return DEFAULT_VERSION; - } - - // Reset the keyboard version to the default in the kmp.json metadata, for - // warning/failure code paths in this file - kmp.keyboards[0].version = DEFAULT_VERSION; - - const file = kmp.files.find(file => this.callbacks.path.basename(file.name, '.kmx') == kmp.keyboards[0].id); - if(!file) { - this.callbacks.reportMessage(CompilerMessages.Error_KeyboardFileNotFound({id:kmp.keyboards[0].id})); - return DEFAULT_VERSION; - } - - const filename = this.callbacks.resolveFilename(kpsFilename, file.name); - if(!this.callbacks.fs.existsSync(filename)) { - // The zip phase will emit an error later if the file is missing, so - // we can just bail cleanly here - // console.debug(`The file ${filename} was not found`); - return DEFAULT_VERSION; - } - // - // load the .kmx and extract the version number - // - const kmxFileData = this.callbacks.loadFile(filename); - const kmxReader: KmxFileReader = new KmxFileReader(); - const kmx: KMX.KEYBOARD = kmxReader.read(kmxFileData); - if(!kmx) { - // The file couldn't be read, it might be invalid or locked - this.callbacks.reportMessage(CompilerMessages.Error_KeyboardFileNotValid({filename})); - return DEFAULT_VERSION; - } - - const store = kmx.stores.find(store => store.dwSystemID == KMX.KMXFile.TSS_KEYBOARDVERSION); - if(!store) { - // We have no version number store, so use default version - this.callbacks.reportMessage(CompilerMessages.Warn_KeyboardFileHasNoKeyboardVersion({filename})); - return DEFAULT_VERSION; - } - - kmp.keyboards[0].version = store.dpString; - return store.dpString; - } private stripUndefined(o: any) { for(const key in o) { diff --git a/developer/src/kmc-package/src/compiler/messages.ts b/developer/src/kmc-package/src/compiler/messages.ts index 8c47e9e0db..e5e208a5b9 100644 --- a/developer/src/kmc-package/src/compiler/messages.ts +++ b/developer/src/kmc-package/src/compiler/messages.ts @@ -31,13 +31,13 @@ export class CompilerMessages { `FollowKeyboardVersion is not allowed in model packages`); static ERROR_FollowKeyboardVersionNotAllowedForModelPackages = SevError | 0x0006; - static Warn_FollowKeyboardVersionButNoKeyboards = () => m(this.WARN_FollowKeyboardVersionButNoKeyboards, + static Error_FollowKeyboardVersionButNoKeyboards = () => m(this.ERROR_FollowKeyboardVersionButNoKeyboards, `FollowKeyboardVersion is set, but the package contains no keyboards`); - static WARN_FollowKeyboardVersionButNoKeyboards = SevWarn | 0x0007; + static ERROR_FollowKeyboardVersionButNoKeyboards = SevError | 0x0007; - static Error_KeyboardFileNotFound = (o:{id:string}) => m(this.ERROR_KeyboardFileNotFound, + static Error_KeyboardContentFileNotFound = (o:{id:string}) => m(this.ERROR_KeyboardContentFileNotFound, `Keyboard ${o.id} was listed in but a corresponding .kmx file was not found in `); - static ERROR_KeyboardFileNotFound = SevError | 0x0008; + static ERROR_KeyboardContentFileNotFound = SevError | 0x0008; static Error_KeyboardFileNotValid = (o:{filename:string}) => m(this.ERROR_KeyboardFileNotValid, `Keyboard file ${o.filename} is not a valid .kmx file`); @@ -74,5 +74,9 @@ export class CompilerMessages { static Error_PackageNameCannotBeBlank = () => m(this.ERROR_PackageNameCannotBeBlank, `Package name cannot be an empty string.`); static ERROR_PackageNameCannotBeBlank = SevError | 0x0010; + + static Error_KeyboardFileNotFound = (o:{filename:string}) => m(this.ERROR_KeyboardFileNotFound, + `Keyboard file ${o.filename} was not found. Has it been compiled?`); + static ERROR_KeyboardFileNotFound = SevError | 0x0011; } diff --git a/developer/src/kmc-package/src/compiler/package-validation.ts b/developer/src/kmc-package/src/compiler/package-validation.ts index 5ef32c43da..7033b6c565 100644 --- a/developer/src/kmc-package/src/compiler/package-validation.ts +++ b/developer/src/kmc-package/src/compiler/package-validation.ts @@ -41,7 +41,7 @@ export class PackageValidation { return true; } - private checkForDuplicatedLanguages(resourceType: 'keyboard'|'model', id: string, languages: KmpJsonFile.KmpJsonFileLanguage[]) { + private checkForDuplicatedLanguages(resourceType: 'keyboard'|'model', id: string, languages: KmpJsonFile.KmpJsonFileLanguage[]): void { let tags: {[index:string]: boolean} = {}; for(let lang of languages) { const langTag = lang.id.toLowerCase(); diff --git a/developer/src/kmc-package/src/compiler/package-version-validation.ts b/developer/src/kmc-package/src/compiler/package-version-validation.ts new file mode 100644 index 0000000000..bbf1062620 --- /dev/null +++ b/developer/src/kmc-package/src/compiler/package-version-validation.ts @@ -0,0 +1,118 @@ +import { KmpJsonFile, CompilerCallbacks, KpsFile, KmxFileReader, KMX } from '@keymanapp/common-types'; +import { CompilerMessages } from './messages.js'; + +export class PackageVersionValidation { + + constructor(private callbacks: CompilerCallbacks) {} + + /** + * Verifies version information in corresponding keyboards and updates kmpJson + * metadata as the version information can be out of sync in the .kps file + * after update a contained keyboard. + * @param kpsFilename + * @param kps + * @param kmp + * @returns + */ + public validateAndUpdateVersions(kpsFilename: string, kps: KpsFile.KpsFile, kmp: KmpJsonFile.KmpJsonFile) { + if(!this.checkFollowKeyboardVersion(kps, kmp)) { + return false; + } + + let result = true; + + if(!kmp.keyboards) { + // Lexical model packages don't have version metadata + return true; + } + + for(let keyboard of kmp.keyboards) { + result = this.updateKeyboardVersionFromKmx(kpsFilename, kmp, keyboard) && result; + } + + if(result && kps.options?.followKeyboardVersion !== undefined) { + // We know we have at least one keyboard because of earlier checkFollowKyeboardVersion check + kmp.info.version.description = kmp.keyboards[0].version; + } + + return result; + } + + private checkFollowKeyboardVersion(kps: KpsFile.KpsFile, kmp: KmpJsonFile.KmpJsonFile) { + if(kps.options?.followKeyboardVersion === undefined) { + return true; + } + + // Lexical model packages do not allow FollowKeyboardVersion + if(kmp.lexicalModels && kmp.lexicalModels.length) { + this.callbacks.reportMessage(CompilerMessages.Error_FollowKeyboardVersionNotAllowedForModelPackages()); + return false; + } + + if(!kmp.keyboards || !kmp.keyboards.length) { + this.callbacks.reportMessage(CompilerMessages.Error_FollowKeyboardVersionButNoKeyboards()); + return false; + } + + return true; + } + + private updateKeyboardVersionFromKmx( + kpsFilename: string, + kmp: KmpJsonFile.KmpJsonFile, + keyboard: KmpJsonFile.KmpJsonFileKeyboard + ): boolean { + // The DEFAULT_VERSION used to be '1.0', but we now use '0.0' to allow + // pre-release 0.x keyboards to be considered later than a keyboard without + // any version metadata at all. + const DEFAULT_VERSION = '0.0'; + + // Note: there is often version metadata in the .kps element, but + // we don't read from the metadata because we want to ensure we have the + // most up-to-date keyboard version data here, from the compiled keyboard. + + // Reset the keyboard version to the default in the kmp.json metadata, for + // warning/failure code paths in this file + keyboard.version = DEFAULT_VERSION; + + const file = kmp.files.find(file => this.callbacks.path.basename(file.name, '.kmx') == keyboard.id); + if(!file) { + this.callbacks.reportMessage(CompilerMessages.Error_KeyboardContentFileNotFound({id:keyboard.id})); + return false; + } + + const filename = this.callbacks.resolveFilename(kpsFilename, file.name); + if(!this.callbacks.fs.existsSync(filename)) { + this.callbacks.reportMessage(CompilerMessages.Error_KeyboardFileNotFound({filename})); + return false; + } + + // + // load the .kmx and extract the version number + // + let kmxFileData; + try { + kmxFileData = this.callbacks.loadFile(filename); + } catch(e) { + this.callbacks.reportMessage(CompilerMessages.Error_FileCouldNotBeRead({filename, e})); + return false; + } + const kmxReader: KmxFileReader = new KmxFileReader(); + const kmx: KMX.KEYBOARD = kmxReader.read(kmxFileData); + if(!kmx) { + // The file couldn't be read, it might not be a .kmx file + this.callbacks.reportMessage(CompilerMessages.Error_KeyboardFileNotValid({filename})); + return false; + } + + const store = kmx.stores.find(store => store.dwSystemID == KMX.KMXFile.TSS_KEYBOARDVERSION); + if(!store) { + // We have no version number store, so use default version + this.callbacks.reportMessage(CompilerMessages.Warn_KeyboardFileHasNoKeyboardVersion({filename})); + return true; + } + + keyboard.version = store.dpString; + return true; + } +} diff --git a/developer/src/kmc-package/test/fixtures/invalid/ERROR_PackageCannotContainBothModelsAndKeyboards.kps b/developer/src/kmc-package/test/fixtures/invalid/ERROR_PackageCannotContainBothModelsAndKeyboards.kps index c87b6808c7..37bdc02551 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/ERROR_PackageCannotContainBothModelsAndKeyboards.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/ERROR_PackageCannotContainBothModelsAndKeyboards.kps @@ -13,7 +13,7 @@ - nokeyboardversion.kmx + khmer_angkor.kmx Keyboard Khmer Angkor 0 .kmx @@ -39,7 +39,7 @@ Khmer Angkor - nokeyboardversion + khmer_angkor 1.3 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowKeyboardConventions.kps b/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowKeyboardConventions.kps index 5ff6eca048..e6d3caecb5 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowKeyboardConventions.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowKeyboardConventions.kps @@ -13,7 +13,7 @@ - nokeyboardversion.kmx + khmer_angkor.kmx Keyboard Khmer Angkor 0 .kmx @@ -22,7 +22,7 @@ Khmer Angkor - nokeyboardversion + khmer_angkor 1.3 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank.kps b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank.kps index 6fb56f3827..ffc566f84b 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank.kps @@ -13,7 +13,7 @@ - nokeyboardversion.kmx + khmer_angkor.kmx Keyboard Khmer Angkor 0 .kmx @@ -22,7 +22,7 @@ Khmer Angkor - nokeyboardversion + khmer_angkor 1.3 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_2.kps b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_2.kps index 46b182ffc6..67d39da4c3 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_2.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_2.kps @@ -12,7 +12,7 @@ - nokeyboardversion.kmx + khmer_angkor.kmx Keyboard Khmer Angkor 0 .kmx @@ -21,7 +21,7 @@ Khmer Angkor - nokeyboardversion + khmer_angkor 1.3 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_3.kps b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_3.kps index 5b29699f4c..fbc8689f87 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_3.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_3.kps @@ -7,7 +7,7 @@ - nokeyboardversion.kmx + khmer_angkor.kmx Keyboard Khmer Angkor 0 .kmx @@ -16,7 +16,7 @@ Khmer Angkor - nokeyboardversion + khmer_angkor 1.3 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/keyboardcontentfilenotfound.kps b/developer/src/kmc-package/test/fixtures/invalid/keyboardcontentfilenotfound.kps new file mode 100644 index 0000000000..224dd52042 --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/keyboardcontentfilenotfound.kps @@ -0,0 +1,125 @@ + + + + 15.0.266.0 + 7.0 + + + + readme.htm + splash.gif + + + + + + + + + + Khmer Angkor + © 2015-2022 SIL International + Makara Sok + + https://keyman.com/keyboards/khmer_angkor + + + + ..\build\khmer_angkor.js + File khmer_angkor.js + 0 + .js + + + ..\build\khmer_angkor.kvk + File khmer_angkor.kvk + 0 + .kvk + + + welcome\keyboard_layout.png + File keyboard_layout.png + 0 + .png + + + welcome\welcome.htm + File welcome.htm + 0 + .htm + + + ..\shared\fonts\khmer\mondulkiri\FONTLOG.txt + File FONTLOG.txt + 0 + .txt + + + ..\shared\fonts\khmer\mondulkiri\Mondulkiri-R.ttf + Font Khmer Mondulkiri + 0 + .ttf + + + ..\shared\fonts\khmer\mondulkiri\OFL.txt + File OFL.txt + 0 + .txt + + + ..\shared\fonts\khmer\mondulkiri\OFL-FAQ.txt + File OFL-FAQ.txt + 0 + .txt + + + welcome\KAK_Documentation_EN.pdf + File KAK_Documentation_EN.pdf + 0 + .pdf + + + welcome\KAK_Documentation_KH.pdf + File KAK_Documentation_KH.pdf + 0 + .pdf + + + readme.htm + File readme.htm + 0 + .htm + + + welcome\image002.png + File image002.png + 0 + .png + + + ..\shared\fonts\khmer\busrakbd\khmer_busra_kbd.ttf + Font KhmerBusraKbd + 0 + .ttf + + + splash.gif + File splash.gif + 0 + .gif + + + + + Khmer Angkor + khmer_angkor + 1.3 + ..\shared\fonts\khmer\busrakbd\khmer_busra_kbd.ttf + ..\shared\fonts\khmer\mondulkiri\Mondulkiri-R.ttf + + Central Khmer (Khmer, Cambodia) + + + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/keyboardfilenotfound.kps b/developer/src/kmc-package/test/fixtures/invalid/keyboardfilenotfound.kps index 224dd52042..cf6e49053a 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/keyboardfilenotfound.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/keyboardfilenotfound.kps @@ -5,11 +5,6 @@ 7.0 - - readme.htm - splash.gif - - @@ -25,97 +20,18 @@ - ..\build\khmer_angkor.js - File khmer_angkor.js + + keyboardfilenotfound.kmx + Keyboard Khmer Angkor 0 - .js - - - ..\build\khmer_angkor.kvk - File khmer_angkor.kvk - 0 - .kvk - - - welcome\keyboard_layout.png - File keyboard_layout.png - 0 - .png - - - welcome\welcome.htm - File welcome.htm - 0 - .htm - - - ..\shared\fonts\khmer\mondulkiri\FONTLOG.txt - File FONTLOG.txt - 0 - .txt - - - ..\shared\fonts\khmer\mondulkiri\Mondulkiri-R.ttf - Font Khmer Mondulkiri - 0 - .ttf - - - ..\shared\fonts\khmer\mondulkiri\OFL.txt - File OFL.txt - 0 - .txt - - - ..\shared\fonts\khmer\mondulkiri\OFL-FAQ.txt - File OFL-FAQ.txt - 0 - .txt - - - welcome\KAK_Documentation_EN.pdf - File KAK_Documentation_EN.pdf - 0 - .pdf - - - welcome\KAK_Documentation_KH.pdf - File KAK_Documentation_KH.pdf - 0 - .pdf - - - readme.htm - File readme.htm - 0 - .htm - - - welcome\image002.png - File image002.png - 0 - .png - - - ..\shared\fonts\khmer\busrakbd\khmer_busra_kbd.ttf - Font KhmerBusraKbd - 0 - .ttf - - - splash.gif - File splash.gif - 0 - .gif + .kmx Khmer Angkor - khmer_angkor + keyboardfilenotfound 1.3 - ..\shared\fonts\khmer\busrakbd\khmer_busra_kbd.ttf - ..\shared\fonts\khmer\mondulkiri\Mondulkiri-R.ttf Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/khmer_angkor.kmx b/developer/src/kmc-package/test/fixtures/invalid/khmer_angkor.kmx new file mode 100644 index 0000000000000000000000000000000000000000..c3d0289f4863c7c4a998c348eb1d425caadca79d GIT binary patch literal 26280 zcmd^He|Qx~xt;)}N1EaRDYFM_JW|R{{4&iTUDd;z6+h=`0Z!{~^8(dp4|zP`)L;iDPrY#(^yaip9fX9`^I0 z5uY#q4LKfGK10QDF<1-%vc(9sAA*_)c3DCUHOD5Rrf&wNjX@dzD!zfT<|D^1P<}T2 zsLW3&D;sHC+$-)Dld!)V-qhy#*i-9u8y-aagt$kQ@ilnSndtV<5&w>sE`atRVAp#e zO8C0?D)P)id2zIW&btWwL6klVXCqV@-@^VIroCTL8n<_FkW2U0Cs5DBsPC)r{sda| zAj%`Y03{4Xd3Uy3l5R`;buC1FG>>7R_!C7mu%-uA)M!zkHQ|5G_}yi!FPI#xMg35l zVEo1zYlg|eTGS7<$;NN0vGPq0)}lUZ!VhzdH8~1Q4%VVRYr?Q;apqSksJk zud&7lR@7&|sOgu8>9vSY^$M|6J}Q^V@5&PSJy|NhFPF>5bM&>q5`JiX)*KD3upd5ej*=zBcKP3Ohy0D)DR;?Qxm(uB=VZOyBlpVR%6;;G zf^&$PzK{CclM(-fDq+8TULN>=aISPM+B=VqdV2NNPu)tZiy z-NBWK_#7Ki|8=AB2#Q!&Iy}mwAnJ$K@gT48*^2la5fL-0B0fii@OPQosAM7jOKy}u zmz(4-xkUY3qvZsajvLAmv1+{29OY3E zG4qk|X+9F-ck-}2C|{B!i1=Y^`K%&p3IkhoqYW|EP-F2qNB!YO<7*K0 z=`3_FaVZg>ONm(5G;BThb;PeVd3mmmSZ5xV%yUY_%s3IBTOaYcr4gTJu!zqyNyNmIRY3BH#^%#0r~_l=0TOGSLX4@G>MzlC^4>=FaS$Hm96YPnr}8f*D)i|>d+ ztmOxaLE=^1O+P8VB)%+ej%UX2z}@zJF;a~0>&0X7Pl-`tG}hd-0@o1{H~q_2#3xIL zo8ob?F7S)`!%V-07F`=5UX%Sqb)3uN>mW=Y37@Zn@cFt5Q=TwaSeVEXK1Y@?qeS?0 zt%YcoZ^#z;raUR%lCAP>c}o5vh%?W`fM@FVOx>QT+cR~0rf$#F?U}kgQ@0n?eNMh3 z&&zk^1^J%5DBqWtwPV(-M>j-8La8@mwuTkJ~gRO}D2=GdFD zKgCYQT4R@EZ^SOe-io~+doOl1))qS*`(x~4jAKt^@TxDvSe=a3*;rkSb%U|G8tX=5 zMU3?UV|6puO~%SJ*3HK1ZmbU)D{8DB#_DOT4;ibMv2HO|Z(~VgdB%zvtB(faT@_GtBC0N&1 zDf?;Im9WZ!a@OH2b$L&rgbI}NnDVGnYAM#qv?6{2t79Rmw%LeEK|k4T~CrqJ_J=wnjoV^ipNrO?Nv z&_A0(&rho7rRe`WT&HCHoQEryTul445AmJcKY9P>VJsx~Pu~A|B6OHD?z32;Z z{NqBj0Je4!{EDM>9VkR5Ffk}Ag1o)K`v7At?N;zOaKh61g7*hrx3mG^gMb1{8w{Qe z+-+&Yz;l7AmNpW6H1K&#^TEdfuUT3?_yk~zrA-1a06uGJQ^2PIcAKYz7XtTNeh+{b z0rY-}wumppEb!UDE~RK~4)|Q)3zjwyd;zf2(iVb00^DP1i@}!ylPql+cqx!$Y0JS^ z0wXMK75EyU-qOmzD*z6Mh%ZDX_*&pT%Woa{2H=a9wh??Y@SLSpgKq`KSXvGEcHmx1 z+W}q+KAw(BovZZwe?*`1Uv`p|QFx}F6g7*e^ zOhf43Rb-d=kL@LfT~TDFBZT(x!q>2l(7bn*sg+z-=aNCipCXW1O^yz~=xQ?KJpV zfah$|&VgS5c+Mg1BKT#1W1O@r;CS(1=3UY{fp-OX%#aoV&jfhBBCR`kPk`qa(t3e= zzzm@`()xgB0Xr=%4&D#od4v4=gAWAweni?J@F74v$V+228$1WN0ry|ELCXan4Ro!ejsLP2fz;jo~0cIZvv#H9R)uD^tQBS@K)d!OFIRA7U*SZ=fE!lAF{Md;8%g3 zmWJ13qASqD(jws9fvBZL!FvNAv@{Pq3lNqT2k#Gbx3mG^g8^FWsm(_`g69C8EG-v& zG;p(}`QZ7$jg~eZd@?X6C=M_FL;?6zON&CA20jD$hUHfXKGV|3uL%4h;G34;Z17@B zBfq)e^MSdR-vaPOmPUS$fG+_aw)~cYmslG4m4dGT;+Ee^@YR+^er4blmPY4W3BDHK z`y2VK1K$Af{7l+L@ES*}18;D&Ch!(VI}3i<(YoTN&z^u?M;7=%N6Q8u?P&Sn1&%fy ze3qjXgUjTmjfiDL5o=n;j@MQqse@QC=Uk-4assC1hmpR&6@J)`k z6?~_o?FB#RXh*=00=#CRdXJG0!0Qsyn!!&3ynZ3A75p^7>v7V~fS&_+Zl^Y%2fqaH znvk^1;8y{@e~^aP-=Yh^Yhcp4g7iowiLVs;58R%rQj<7zUHK@1YZqs zKa;iwyd2if0e8!V0dHiB;k_cIB`9H*r1 z13v(8{E^lGehA?BBkeHw5rE^5v?lOl0LLF`$HAKcjz7{`z*_;1KhjQtp8+`jNIMID z9^m*R?E?5Epg;s0w9DXE0ggZNqe-(1FePv!tt)spfa8y}Oz1bhj=aY}Ku z6uboBI3=wVd^B)j++_8)<96%YnAGE)d(=Bvw$J@H=p$Y-`I9-Ib<~WZ*l^ z{WA2-z&D)FgZ~6T46BsBP!WQ@T0mr~bfZc)sq|Tu{z9eCsPtDV)wy0*_RA_gq|)Om zZBi+H0f3oWrN39{F_qpNCp}Z8UnUd3R?~*56&pQF3V~%8w)a(v+dH;Gm3~L1BUSpU zO0l5FHoh;V11S++oKl|>5sOp$DN69$H*KR;`fZi=SLtmkt&Y>KpRzBgc3x8HIhDSn z((@{PSEcmZuMqF4^rA}NSLq*Pq@Pyl8I}H3rGHWBS(Ub^^v^0ir_y&+O21`d45{>8 zm0nQk-&A@jf#{+p1{UR!u>S9V)lXYm3??~PzIhChXN zQoq^y)A*u?j?s$F)++)%&(VJx=rmSre=1`X%BSmK>+9i9*V@(SdXN^jE-Oii+0b5q zCx1!%nzC;vLD285b{Y0OWtSUG@S=A1yhfqAf2YbD088L27}{P^%BPjROVW%--)K>K zM5WaJhM<4BAL-6->)ekc0{zSRNAW2w^e#d zrS#Pb?%w!9koI*d-4(DJ#a>bAXXvnaRoUBvGt&{T<57>Yz3RA*bc!3S36N6R1h%oN zP{;HLUZ!k4Ds_+P5kOxy3ZX}r9`n^o`K?OzD5_QVo}j%u71Q&;Ze{B+Q?KkTD&4Ho z7gc&trO!|``1X%dJ!bWcqvw%5O4nmm&p;Hf^eaB4jVfKLQaw-TSwWBaeM;B!fu5!G z9HM6&J?`7udf>GUUC|!6cT(CJ<U33D8+gOYmz}|Aer#o6P_$o(R55CXQj(}fuv~F004l)Z-U6T)99*FnOM{g2JCGt_$)_T1YYTA)!>I5tr@(NSrqG1dx7UT+IaA}j#dJ` z+0p93TO92IcyF`F)^!X3pWtYP;7c5BCHNLcs|Rm!v9mBw`ANb#h`I9{3PP8w)jE=@Dq-94m>g?vEDx5108J?_#{Vr0DP{a zEd^iaXgk1>%SE|*U`p<&vvxM;8l*c75t#1HG^Mqv?yLC3^FeibiF=! zp`*2er+JB_Yw8O=+R-M1&vCSc;3bZ>7JP@JHGrRVw2R7!r!n6?Z7&vCTz;FBG#5WL9I=7BGCv=Z=7akReR!yIiCxbJBB;1e9J0DP*W%>aME(Pn|qakP2h3mt7Sc!{H} z0k3qlP2gJ{Z990Kqa6TmaIc+}B)gZFW?ICwum zzs0cMVd!@rUDc5rQ8c~t(C-`R&6)k~qrF`G7A;p?PcDAPme+1B{mvz9A-%~g!~YRY zzjfie&+ExWJ)z%>UQaIl-t>BNRJD6PZV#-x?jE2V`aNZPEpzMPtD19N*N3m_h--2^ zq28X|pkhs5PkP_mLv%shHRAt`Qw!-AD*cvU$7(ux=vS;%dH8K!SWl%@54~Nyww_dZ zbUmEMK93AlN~(PNoapQZs}a^iq@P#UY3EI>OOIbJFLC^~KYGJFe4T0ZrkjVaGL79- zd2~F5_3+3| z^etaQ8mp=5ajyqoLmH{+<_YVeR%fXH2h6|B&^vS*O*{@#*Vl1gHx{TaeP4PZWn0}m z+}2$D7M1G!+&tVTdF|wJ&r8R3`gMeHoqnD$uG7z>+)efsr;dD5>Zy#DFe6Xr?3o-k(8 zuP4ltemy$Q(yxQ(TUx=TbN$J`3cl2$^!-z}Uyt8w<10t~?UCel=saN@bA0jIC|SGQ zdN@`_Tt_`&p48{lfWJmV_45q52R%ib$$+=ahjlb+`b9e8qo#^KX z%{=1Uk2dXY828hLj^qdvY9(=&<(C zv!mKWPrG)08l$fi=nE_UGG`C|>Xn{NQhU%B4>Z%H_TYI&&%64mAaT8@=ddg_lU@7F zlwQ7M&rA9l($3!*D-nL;yag705u#^H+n3j|`!oBtS8mwv;mn*~yF>r<$|o;=f=%7_#Otd4(<`6n z;&jT^zUh}sPsQn$TNQXFkHhdf^3!wba>MJWebZ~N{Z1@(*FRe8^yO(e{;tvwF$2?gkEHUtK;MVxFLTjbBTCs$^rJj{ z=hJzvT@i4Z*ZN+&3P|m%*BjT~b@fVs^Xc_MxKijW^zpEbbSzvQaK6O0X&*XkUJ>wE zAwRxL>lSgpkaw23x9iB@(sj?!She48(G_xg+OQR?l|U^Y)R%^}Br}@mWPbAy9jVIi=Z05=*m>*sFhzWF0$t z4D$%)Cj$K>5Heczhm2SF+=qNEsC`k@uicP%{<0}-nkVRgD9|_a<$=95u<72i0vhirW+^Z4Nq<(&g?vr% z)hCYA7x}LK>p(A0@Td2akKqV?)ldJAV2^rZN!E5ewd?<>q2FoHd$k=((=)<;%nam3 zvrPD&ldmGjw(bX3b?oqH$UxLIqVCW~NAxWTqlLWadf%c_iaYxM8PBNNb-(Fzz<0K) z?ezaIeyNT=3+w0jyUWxUWYN{qmi~Vk8MyyOqj8jo?<+Co^~QbxKqEO0WT+GdO^43* zv%#IkKQnF@&G=iqj5lDX1NKkcpFe+I5Sp8t)&9_-L*nq^!^%E!;)L4M@vy$c{I`kU ziD(W6Jjp+hf<<&Rd2#~*)OJo)64%5G?AP-S(L|8~(LJ{hZ4ZQQ-PR@Bzk oDtl0`t=LoFCZ2P9{7X|R#ncIv*OjNe@{%3{{4&iTUDd;z6+h=`0Z!{~^8(dp4|zP`)L;iDPrY#(^yaip9fX9`^I0 z5uY#q4LKfGK10QDF<1-%vc(9sAA*_)c3DCUHOD5Rrf&wNjX@dzD!zfT<|D^1P<}T2 zsLW3&D;sHC+$-)Dld!)V-qhy#*i-9u8y-aagt$kQ@ilnSndtV<5&w>sE`atRVAp#e zO8C0?D)P)id2zIW&btWwL6klVXCqV@-@^VIroCTL8n<_FkW2U0Cs5DBsPC)r{sda| zAj%`Y03{4Xd3Uy3l5R`;buC1FG>>7R_!C7mu%-uA)M!zkHQ|5G_}yi!FPI#xMg35l zVEo1zYlg|eTGS7<$;NN0vGPq0)}lUZ!VhzdH8~1Q4%VVRYr?Q;apqSksJk zud&7lR@7&|sOgu8>9vSY^$M|6J}Q^V@5&PSJy|NhFPF>5bM&>q5`JiX)*KD3upd5ej*=zBcKP3Ohy0D)DR;?Qxm(uB=VZOyBlpVR%6;;G zf^&$PzK{CclM(-fDq+8TULN>=aISPM+B=VqdV2NNPu)tZiy z-NBWK_#7Ki|8=AB2#Q!&Iy}mwAnJ$K@gT48*^2la5fL-0B0fii@OPQosAM7jOKy}u zmz(4-xkUY3qvZsajvLAmv1+{29OY3E zG4qk|X+9F-ck-}2C|{B!i1=Y^`K%&p3IkhoqYW|EP-F2qNB!YO<7*K0 z=`3_FaVZg>ONm(5G;BThb;PeVd3mmmSZ5xV%yUY_%s3IBTOaYcr4gTJu!zqyNyNmIRY3BH#^%#0r~_l=0TOGSLX4@G>MzlC^4>=FaS$Hm96YPnr}8f*D)i|>d+ ztmOxaLE=^1O+P8VB)%+ej%UX2z}@zJF;a~0>&0X7Pl-`tG}hd-0@o1{H~q_2#3xIL zo8ob?F7S)`!%V-07F`=5UX%Sqb)3uN>mW=Y37@Zn@cFt5Q=TwaSeVEXK1Y@?qeS?0 zt%YcoZ^#z;raUR%lCAP>c}o5vh%?W`fM@FVOx>QT+cR~0rf$#F?U}kgQ@0n?eNMh3 z&&zk^1^J%5DBqWtwPV(-M>j-8La8@mwuTkJ~gRO}D2=GdFD zKgCYQT4R@EZ^SOe-io~+doOl1))qS*`(x~4jAKt^@TxDvSe=a3*;rkSb%U|G8tX=5 zMU3?UV|6puO~%SJ*3HK1ZmbU)D{8DB#_DOT4;ibMv2HO|Z(~VgdB%zvtB(faT@_GtBC0N&1 zDf?;Im9WZ!a@OH2b$L&rgbI}NnDVGnYAM#qv?6{2t79Rmw%LeEK|k4T~CrqJ_J=wnjoV^ipNrO?Nv z&_A0(&rho7rRe`WT&HCHoQEryTul445AmJcKY9P>VJsx~Pu~A|B6OHD?z32;Z z{NqBj0Je4!{EDM>9VkR5Ffk}Ag1o)K`v7At?N;zOaKh61g7*hrx3mG^gMb1{8w{Qe z+-+&Yz;l7AmNpW6H1K&#^TEdfuUT3?_yk~zrA-1a06uGJQ^2PIcAKYz7XtTNeh+{b z0rY-}wumppEb!UDE~RK~4)|Q)3zjwyd;zf2(iVb00^DP1i@}!ylPql+cqx!$Y0JS^ z0wXMK75EyU-qOmzD*z6Mh%ZDX_*&pT%Woa{2H=a9wh??Y@SLSpgKq`KSXvGEcHmx1 z+W}q+KAw(BovZZwe?*`1Uv`p|QFx}F6g7*e^ zOhf43Rb-d=kL@LfT~TDFBZT(x!q>2l(7bn*sg+z-=aNCipCXW1O^yz~=xQ?KJpV zfah$|&VgS5c+Mg1BKT#1W1O@r;CS(1=3UY{fp-OX%#aoV&jfhBBCR`kPk`qa(t3e= zzzm@`()xgB0Xr=%4&D#od4v4=gAWAweni?J@F74v$V+228$1WN0ry|ELCXan4Ro!ejsLP2fz;jo~0cIZvv#H9R)uD^tQBS@K)d!OFIRA7U*SZ=fE!lAF{Md;8%g3 zmWJ13qASqD(jws9fvBZL!FvNAv@{Pq3lNqT2k#Gbx3mG^g8^FWsm(_`g69C8EG-v& zG;p(}`QZ7$jg~eZd@?X6C=M_FL;?6zON&CA20jD$hUHfXKGV|3uL%4h;G34;Z17@B zBfq)e^MSdR-vaPOmPUS$fG+_aw)~cYmslG4m4dGT;+Ee^@YR+^er4blmPY4W3BDHK z`y2VK1K$Af{7l+L@ES*}18;D&Ch!(VI}3i<(YoTN&z^u?M;7=%N6Q8u?P&Sn1&%fy ze3qjXgUjTmjfiDL5o=n;j@MQqse@QC=Uk-4assC1hmpR&6@J)`k z6?~_o?FB#RXh*=00=#CRdXJG0!0Qsyn!!&3ynZ3A75p^7>v7V~fS&_+Zl^Y%2fqaH znvk^1;8y{@e~^aP-=Yh^Yhcp4g7iowiLVs;58R%rQj<7zUHK@1YZqs zKa;iwyd2if0e8!V0dHiB;k_cIB`9H*r1 z13v(8{E^lGehA?BBkeHw5rE^5v?lOl0LLF`$HAKcjz7{`z*_;1KhjQtp8+`jNIMID z9^m*R?E?5Epg;s0w9DXE0ggZNqe-(1FePv!tt)spfa8y}Oz1bhj=aY}Ku z6uboBI3=wVd^B)j++_8)<96%YnAGE)d(=Bvw$J@H=p$Y-`I9-Ib<~WZ*l^ z{WA2-z&D)FgZ~6T46BsBP!WQ@T0mr~bfZc)sq|Tu{z9eCsPtDV)wy0*_RA_gq|)Om zZBi+H0f3oWrN39{F_qpNCp}Z8UnUd3R?~*56&pQF3V~%8w)a(v+dH;Gm3~L1BUSpU zO0l5FHoh;V11S++oKl|>5sOp$DN69$H*KR;`fZi=SLtmkt&Y>KpRzBgc3x8HIhDSn z((@{PSEcmZuMqF4^rA}NSLq*Pq@Pyl8I}H3rGHWBS(Ub^^v^0ir_y&+O21`d45{>8 zm0nQk-&A@jf#{+p1{UR!u>S9V)lXYm3??~PzIhChXN zQoq^y)A*u?j?s$F)++)%&(VJx=rmSre=1`X%BSmK>+9i9*V@(SdXN^jE-Oii+0b5q zCx1!%nzC;vLD285b{Y0OWtSUG@S=A1yhfqAf2YbD088L27}{P^%BPjROVW%--)K>K zM5WaJhM<4BAL-6->)ekc0{zSRNAW2w^e#d zrS#Pb?%w!9koI*d-4(DJ#a>bAXXvnaRoUBvGt&{T<57>Yz3RA*bc!3S36N6R1h%oN zP{;HLUZ!k4Ds_+P5kOxy3ZX}r9`n^o`K?OzD5_QVo}j%u71Q&;Ze{B+Q?KkTD&4Ho z7gc&trO!|``1X%dJ!bWcqvw%5O4nmm&p;Hf^eaB4jVfKLQaw-TSwWBaeM;B!fu5!G z9HM6&J?`7udf>GUUC|!6cT(CJ<U33D8+gOYmz}|Aer#o6P_$o(R55CXQj(}fuv~F004l)Z-U6T)99*FnOM{g2JCGt_$)_T1YYTA)!>I5tr@(NSrqG1dx7UT+IaA}j#dJ` z+0p93TO92IcyF`F)^!X3pWtYP;7c5BCHNLcs|Rm!v9mBw`ANb#h`I9{3PP8w)jE=@Dq-94m>g?vEDx5108J?_#{Vr0DP{a zEd^iaXgk1>%SE|*U`p<&vvxM;8l*c75t#1HG^Mqv?yLC3^FeibiF=! zp`*2er+JB_Yw8O=+R-M1&vCSc;3bZ>7JP@JHGrRVw2R7!r!n6?Z7&vCTz;FBG#5WL9I=7BGCv=Z=7akReR!yIiCxbJBB;1e9J0DP*W%>aME(Pn|qakP2h3mt7Sc!{H} z0k3qlP2gJ{Z990Kqa6TmaIc+}B)gZFW?ICwum zzs0cMVd!@rUDc5rQ8c~t(C-`R&6)k~qrF`G7A;p?PcDAPme+1B{mvz9A-%~g!~YRY zzjfie&+ExWJ)z%>UQaIl-t>BNRJD6PZV#-x?jE2V`aNZPEpzMPtD19N*N3m_h--2^ zq28X|pkhs5PkP_mLv%shHRAt`Qw!-AD*cvU$7(ux=vS;%dH8K!SWl%@54~Nyww_dZ zbUmEMK93AlN~(PNoapQZs}a^iq@P#UY3EI>OOIbJFLC^~KYGJFe4T0ZrkjVaGL79- zd2~F5_3+3| z^etaQ8mp=5ajyqoLmH{+<_YVeR%fXH2h6|B&^vS*O*{@#*Vl1gHx{TaeP4PZWn0}m z+}2$D7M1G!+&tVTdF|wJ&r8R3`gMeHoqnD$uG7z>+)efsr;dD5>Zy#DFe6Xr?3o-k(8 zuP4ltemy$Q(yxQ(TUx=TbN$J`3cl2$^!-z}Uyt8w<10t~?UCel=saN@bA0jIC|SGQ zdN@`_Tt_`&p48{lfWJmV_45q52R%ib$$+=ahjlb+`b9e8qo#^KX z%{=1Uk2dXY828hLj^qdvY9(=&<(C zv!mKWPrG)08l$fi=nE_UGG`C|>Xn{NQhU%B4>Z%H_TYI&&%64mAaT8@=ddg_lU@7F zlwQ7M&rA9l($3!*D-nL;yag705u#^H+n3j|`!oBtS8mwv;mn*~yF>r<$|o;=f=%7_#Otd4(<`6n z;&jT^zUh}sPsQn$TNQXFkHhdf^3!wba>MJWebZ~N{Z1@(*FRe8^yO(e{;tvwF$2?gkEHUtK;MVxFLTjbBTCs$^rJj{ z=hJzvT@i4Z*ZN+&3P|m%*BjT~b@fVs^Xc_MxKijW^zpEbbSzvQaK6O0X&*XkUJ>wE zAwRxL>lSgpkaw23x9iB@(sj?!She48(G_xg+OQR?l|U^Y)R%^}Br}@mWPbAy9jVIi=Z05=*m>*sFhzWF0$t z4D$%)Cj$K>5Heczhm2SF+=qNEsC`k@uicP%{<0}-nkVRgD9|_a<$=95u<72i0vhirW+^Z4Nq<(&g?vr% z)hCYA7x}LK>p(A0@Td2akKqV?)ldJAV2^rZN!E5ewd?<>q2FoHd$k=((=)<;%nam3 zvrPD&ldmGjw(bX3b?oqH$UxLIqVCW~NAxWTqlLWadf%c_iaYxM8PBNNb-(Fzz<0K) z?ezaIeyNT=3+w0jyUWxUWYN{qmi~Vk8MyyOqj8jo?<+Co^~QbxKqEO0WT+GdO^43* zv%#IkKQnF@&G=iqj5lDX1NKkcpFe+I5Sp8t)&9_-L*nq^!^%E!;)L4M@vy$c{I`kU ziD(W6Jjp+hf<<&Rd2#~*)OJo)64%5G?AP-S(L|8~(LJ{hZ4ZQQ-PR@Bzk oDtl0`t=LoFCZ2P9{7X|R#ncIv*OjNe@{%3{{4&iTUDd;z6+h=`0Z!{~^8(dp4|zP`)L;iDPrY#(^yaip9fX9`^I0 z5uY#q4LKfGK10QDF<1-%vc(9sAA*_)c3DCUHOD5Rrf&wNjX@dzD!zfT<|D^1P<}T2 zsLW3&D;sHC+$-)Dld!)V-qhy#*i-9u8y-aagt$kQ@ilnSndtV<5&w>sE`atRVAp#e zO8C0?D)P)id2zIW&btWwL6klVXCqV@-@^VIroCTL8n<_FkW2U0Cs5DBsPC)r{sda| zAj%`Y03{4Xd3Uy3l5R`;buC1FG>>7R_!C7mu%-uA)M!zkHQ|5G_}yi!FPI#xMg35l zVEo1zYlg|eTGS7<$;NN0vGPq0)}lUZ!VhzdH8~1Q4%VVRYr?Q;apqSksJk zud&7lR@7&|sOgu8>9vSY^$M|6J}Q^V@5&PSJy|NhFPF>5bM&>q5`JiX)*KD3upd5ej*=zBcKP3Ohy0D)DR;?Qxm(uB=VZOyBlpVR%6;;G zf^&$PzK{CclM(-fDq+8TULN>=aISPM+B=VqdV2NNPu)tZiy z-NBWK_#7Ki|8=AB2#Q!&Iy}mwAnJ$K@gT48*^2la5fL-0B0fii@OPQosAM7jOKy}u zmz(4-xkUY3qvZsajvLAmv1+{29OY3E zG4qk|X+9F-ck-}2C|{B!i1=Y^`K%&p3IkhoqYW|EP-F2qNB!YO<7*K0 z=`3_FaVZg>ONm(5G;BThb;PeVd3mmmSZ5xV%yUY_%s3IBTOaYcr4gTJu!zqyNyNmIRY3BH#^%#0r~_l=0TOGSLX4@G>MzlC^4>=FaS$Hm96YPnr}8f*D)i|>d+ ztmOxaLE=^1O+P8VB)%+ej%UX2z}@zJF;a~0>&0X7Pl-`tG}hd-0@o1{H~q_2#3xIL zo8ob?F7S)`!%V-07F`=5UX%Sqb)3uN>mW=Y37@Zn@cFt5Q=TwaSeVEXK1Y@?qeS?0 zt%YcoZ^#z;raUR%lCAP>c}o5vh%?W`fM@FVOx>QT+cR~0rf$#F?U}kgQ@0n?eNMh3 z&&zk^1^J%5DBqWtwPV(-M>j-8La8@mwuTkJ~gRO}D2=GdFD zKgCYQT4R@EZ^SOe-io~+doOl1))qS*`(x~4jAKt^@TxDvSe=a3*;rkSb%U|G8tX=5 zMU3?UV|6puO~%SJ*3HK1ZmbU)D{8DB#_DOT4;ibMv2HO|Z(~VgdB%zvtB(faT@_GtBC0N&1 zDf?;Im9WZ!a@OH2b$L&rgbI}NnDVGnYAM#qv?6{2t79Rmw%LeEK|k4T~CrqJ_J=wnjoV^ipNrO?Nv z&_A0(&rho7rRe`WT&HCHoQEryTul445AmJcKY9P>VJsx~Pu~A|B6OHD?z32;Z z{NqBj0Je4!{EDM>9VkR5Ffk}Ag1o)K`v7At?N;zOaKh61g7*hrx3mG^gMb1{8w{Qe z+-+&Yz;l7AmNpW6H1K&#^TEdfuUT3?_yk~zrA-1a06uGJQ^2PIcAKYz7XtTNeh+{b z0rY-}wumppEb!UDE~RK~4)|Q)3zjwyd;zf2(iVb00^DP1i@}!ylPql+cqx!$Y0JS^ z0wXMK75EyU-qOmzD*z6Mh%ZDX_*&pT%Woa{2H=a9wh??Y@SLSpgKq`KSXvGEcHmx1 z+W}q+KAw(BovZZwe?*`1Uv`p|QFx}F6g7*e^ zOhf43Rb-d=kL@LfT~TDFBZT(x!q>2l(7bn*sg+z-=aNCipCXW1O^yz~=xQ?KJpV zfah$|&VgS5c+Mg1BKT#1W1O@r;CS(1=3UY{fp-OX%#aoV&jfhBBCR`kPk`qa(t3e= zzzm@`()xgB0Xr=%4&D#od4v4=gAWAweni?J@F74v$V+228$1WN0ry|ELCXan4Ro!ejsLP2fz;jo~0cIZvv#H9R)uD^tQBS@K)d!OFIRA7U*SZ=fE!lAF{Md;8%g3 zmWJ13qASqD(jws9fvBZL!FvNAv@{Pq3lNqT2k#Gbx3mG^g8^FWsm(_`g69C8EG-v& zG;p(}`QZ7$jg~eZd@?X6C=M_FL;?6zON&CA20jD$hUHfXKGV|3uL%4h;G34;Z17@B zBfq)e^MSdR-vaPOmPUS$fG+_aw)~cYmslG4m4dGT;+Ee^@YR+^er4blmPY4W3BDHK z`y2VK1K$Af{7l+L@ES*}18;D&Ch!(VI}3i<(YoTN&z^u?M;7=%N6Q8u?P&Sn1&%fy ze3qjXgUjTmjfiDL5o=n;j@MQqse@QC=Uk-4assC1hmpR&6@J)`k z6?~_o?FB#RXh*=00=#CRdXJG0!0Qsyn!!&3ynZ3A75p^7>v7V~fS&_+Zl^Y%2fqaH znvk^1;8y{@e~^aP-=Yh^Yhcp4g7iowiLVs;58R%rQj<7zUHK@1YZqs zKa;iwyd2if0e8!V0dHiB;k_cIB`9H*r1 z13v(8{E^lGehA?BBkeHw5rE^5v?lOl0LLF`$HAKcjz7{`z*_;1KhjQtp8+`jNIMID z9^m*R?E?5Epg;s0w9DXE0ggZNqe-(1FePv!tt)spfa8y}Oz1bhj=aY}Ku z6uboBI3=wVd^B)j++_8)<96%YnAGE)d(=Bvw$J@H=p$Y-`I9-Ib<~WZ*l^ z{WA2-z&D)FgZ~6T46BsBP!WQ@T0mr~bfZc)sq|Tu{z9eCsPtDV)wy0*_RA_gq|)Om zZBi+H0f3oWrN39{F_qpNCp}Z8UnUd3R?~*56&pQF3V~%8w)a(v+dH;Gm3~L1BUSpU zO0l5FHoh;V11S++oKl|>5sOp$DN69$H*KR;`fZi=SLtmkt&Y>KpRzBgc3x8HIhDSn z((@{PSEcmZuMqF4^rA}NSLq*Pq@Pyl8I}H3rGHWBS(Ub^^v^0ir_y&+O21`d45{>8 zm0nQk-&A@jf#{+p1{UR!u>S9V)lXYm3??~PzIhChXN zQoq^y)A*u?j?s$F)++)%&(VJx=rmSre=1`X%BSmK>+9i9*V@(SdXN^jE-Oii+0b5q zCx1!%nzC;vLD285b{Y0OWtSUG@S=A1yhfqAf2YbD088L27}{P^%BPjROVW%--)K>K zM5WaJhM<4BAL-6->)ekc0{zSRNAW2w^e#d zrS#Pb?%w!9koI*d-4(DJ#a>bAXXvnaRoUBvGt&{T<57>Yz3RA*bc!3S36N6R1h%oN zP{;HLUZ!k4Ds_+P5kOxy3ZX}r9`n^o`K?OzD5_QVo}j%u71Q&;Ze{B+Q?KkTD&4Ho z7gc&trO!|``1X%dJ!bWcqvw%5O4nmm&p;Hf^eaB4jVfKLQaw-TSwWBaeM;B!fu5!G z9HM6&J?`7udf>GUUC|!6cT(CJ<U33D8+gOYmz}|Aer#o6P_$o(R55CXQj(}fuv~F004l)Z-U6T)99*FnOM{g2JCGt_$)_T1YYTA)!>I5tr@(NSrqG1dx7UT+IaA}j#dJ` z+0p93TO92IcyF`F)^!X3pWtYP;7c5BCHNLcs|Rm!v9mBw`ANb#h`I9{3PP8w)jE=@Dq-94m>g?vEDx5108J?_#{Vr0DP{a zEd^iaXgk1>%SE|*U`p<&vvxM;8l*c75t#1HG^Mqv?yLC3^FeibiF=! zp`*2er+JB_Yw8O=+R-M1&vCSc;3bZ>7JP@JHGrRVw2R7!r!n6?Z7&vCTz;FBG#5WL9I=7BGCv=Z=7akReR!yIiCxbJBB;1e9J0DP*W%>aME(Pn|qakP2h3mt7Sc!{H} z0k3qlP2gJ{Z990Kqa6TmaIc+}B)gZFW?ICwum zzs0cMVd!@rUDc5rQ8c~t(C-`R&6)k~qrF`G7A;p?PcDAPme+1B{mvz9A-%~g!~YRY zzjfie&+ExWJ)z%>UQaIl-t>BNRJD6PZV#-x?jE2V`aNZPEpzMPtD19N*N3m_h--2^ zq28X|pkhs5PkP_mLv%shHRAt`Qw!-AD*cvU$7(ux=vS;%dH8K!SWl%@54~Nyww_dZ zbUmEMK93AlN~(PNoapQZs}a^iq@P#UY3EI>OOIbJFLC^~KYGJFe4T0ZrkjVaGL79- zd2~F5_3+3| z^etaQ8mp=5ajyqoLmH{+<_YVeR%fXH2h6|B&^vS*O*{@#*Vl1gHx{TaeP4PZWn0}m z+}2$D7M1G!+&tVTdF|wJ&r8R3`gMeHoqnD$uG7z>+)efsr;dD5>Zy#DFe6Xr?3o-k(8 zuP4ltemy$Q(yxQ(TUx=TbN$J`3cl2$^!-z}Uyt8w<10t~?UCel=saN@bA0jIC|SGQ zdN@`_Tt_`&p48{lfWJmV_45q52R%ib$$+=ahjlb+`b9e8qo#^KX z%{=1Uk2dXY828hLj^qdvY9(=&<(C zv!mKWPrG)08l$fi=nE_UGG`C|>Xn{NQhU%B4>Z%H_TYI&&%64mAaT8@=ddg_lU@7F zlwQ7M&rA9l($3!*D-nL;yag705u#^H+n3j|`!oBtS8mwv;mn*~yF>r<$|o;=f=%7_#Otd4(<`6n z;&jT^zUh}sPsQn$TNQXFkHhdf^3!wba>MJWebZ~N{Z1@(*FRe8^yO(e{;tvwF$2?gkEHUtK;MVxFLTjbBTCs$^rJj{ z=hJzvT@i4Z*ZN+&3P|m%*BjT~b@fVs^Xc_MxKijW^zpEbbSzvQaK6O0X&*XkUJ>wE zAwRxL>lSgpkaw23x9iB@(sj?!She48(G_xg+OQR?l|U^Y)R%^}Br}@mWPbAy9jVIi=Z05=*m>*sFhzWF0$t z4D$%)Cj$K>5Heczhm2SF+=qNEsC`k@uicP%{<0}-nkVRgD9|_a<$=95u<72i0vhirW+^Z4Nq<(&g?vr% z)hCYA7x}LK>p(A0@Td2akKqV?)ldJAV2^rZN!E5ewd?<>q2FoHd$k=((=)<;%nam3 zvrPD&ldmGjw(bX3b?oqH$UxLIqVCW~NAxWTqlLWadf%c_iaYxM8PBNNb-(Fzz<0K) z?ezaIeyNT=3+w0jyUWxUWYN{qmi~Vk8MyyOqj8jo?<+Co^~QbxKqEO0WT+GdO^43* zv%#IkKQnF@&G=iqj5lDX1NKkcpFe+I5Sp8t)&9_-L*nq^!^%E!;)L4M@vy$c{I`kU ziD(W6Jjp+hf<<&Rd2#~*)OJo)64%5G?AP-S(L|8~(LJ{hZ4ZQQ-PR@Bzk oDtl0`t=LoFCZ2P9{7X|R#ncIv*OjNe@{%3 Khmer Angkor - nokeyboardversion + my special keyboard 1.3 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions_2.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions_2.kps index 0d6e81165e..c822e75dfa 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions_2.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions_2.kps @@ -13,7 +13,14 @@ - my_special-keyboard.KMX + my_file.PDF + My Documentation + 0 + .PDF + + + + khmer_angkor.kmx Keyboard my special keyboard 0 .kmx @@ -22,7 +29,7 @@ Khmer Angkor - nokeyboardversion + khmer_angkor 1.3 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_package_should_not_repeat_languages.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_package_should_not_repeat_languages.kps index c24f3897f6..b8456b6ddd 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/warn_package_should_not_repeat_languages.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_package_should_not_repeat_languages.kps @@ -12,7 +12,7 @@ - nokeyboardversion.kmx + khmer_angkor.kmx Keyboard Khmer Angkor 0 .kmx @@ -21,7 +21,7 @@ Khmer Angkor - nokeyboardversion + khmer_angkor 1.3 diff --git a/developer/src/kmc-package/test/test-package-compiler.ts b/developer/src/kmc-package/test/test-package-compiler.ts index 86675597b1..1243068bb4 100644 --- a/developer/src/kmc-package/test/test-package-compiler.ts +++ b/developer/src/kmc-package/test/test-package-compiler.ts @@ -13,6 +13,8 @@ import { KmpCompiler } from '../src/compiler/kmp-compiler.js'; import { PackageValidation } from '../src/compiler/package-validation.js'; import { CompilerMessages } from '../src/compiler/messages.js'; +const debug = false; + describe('KmpCompiler', function () { const MODELS : string[] = [ 'example.qaa.sencoten', @@ -141,6 +143,8 @@ describe('KmpCompiler', function () { await assert.isNull(kmpCompiler.buildKmpFile(kpsPath, kmpJson)); + if(debug) callbacks.printMessages(); + assert.lengthOf(callbacks.messages, 2); assert.deepEqual(callbacks.messages[0].code, CompilerMessages.WARN_AbsolutePath); assert.deepEqual(callbacks.messages[1].code, CompilerMessages.ERROR_FileDoesNotExist); @@ -169,7 +173,7 @@ describe('KmpCompiler', function () { kmpCompiler.buildKmpFile(kpsPath, kmpJson) } - //TODO: callbacks.printMessages(); after #8711 is merged + if(debug) callbacks.printMessages(); if(messageId) { assert.lengthOf(callbacks.messages, 1); @@ -195,16 +199,16 @@ describe('KmpCompiler', function () { testForMessage(this, ['invalid', 'followkeyboardversion.qaa.sencoten.model.kps'], CompilerMessages.ERROR_FollowKeyboardVersionNotAllowedForModelPackages); }); - // WARN_FollowKeyboardVersionButNoKeyboards + // ERROR_FollowKeyboardVersionButNoKeyboards - it('should generate WARN_FollowKeyboardVersionButNoKeyboards if is set for a package with no keyboards or models', async function() { - testForMessage(this, ['invalid', 'followkeyboardversion.empty.kps'], CompilerMessages.WARN_FollowKeyboardVersionButNoKeyboards); + it('should generate ERROR_FollowKeyboardVersionButNoKeyboards if is set for a package with no keyboards', async function() { + testForMessage(this, ['invalid', 'followkeyboardversion.empty.kps'], CompilerMessages.ERROR_FollowKeyboardVersionButNoKeyboards); }); - // ERROR_KeyboardFileNotFound + // ERROR_KeyboardContentFileNotFound - it('should generate ERROR_KeyboardFileNotFound if a is listed in a package but not found in ', async function() { - testForMessage(this, ['invalid', 'keyboardfilenotfound.kps'], CompilerMessages.ERROR_KeyboardFileNotFound); + it('should generate ERROR_KeyboardContentFileNotFound if a is listed in a package but not found in ', async function() { + testForMessage(this, ['invalid', 'keyboardcontentfilenotfound.kps'], CompilerMessages.ERROR_KeyboardContentFileNotFound); }); // ERROR_KeyboardFileNotValid @@ -264,4 +268,10 @@ describe('KmpCompiler', function () { testForMessage(this, ['invalid', 'error_package_name_cannot_be_blank_3.kps'], CompilerMessages.ERROR_PackageNameCannotBeBlank); // missing info section }); + // ERROR_KeyboardFileNotFound + + it('should generate ERROR_KeyboardFileNotFound if a is listed in a package but not found in ', async function() { + testForMessage(this, ['invalid', 'keyboardfilenotfound.kps'], CompilerMessages.ERROR_KeyboardFileNotFound); + }); + }); diff --git a/developer/src/kmc/src/kmlmi.ts b/developer/src/kmc/src/kmlmi.ts index 508c43ad0e..0868e0ccfe 100644 --- a/developer/src/kmc/src/kmlmi.ts +++ b/developer/src/kmc/src/kmlmi.ts @@ -48,6 +48,9 @@ let jsFilename = program.opts().jsFilename ? program.opts().jsFilename : path.jo const callbacks = new NodeCompilerCallbacks(); let kmpCompiler = new KmpCompiler(callbacks); let kmpJsonData = kmpCompiler.transformKpsToKmpObject(kpsFilename); +if(!kmpJsonData) { + process.exit(1); +} // // Validate the package file -- GitLab From 53c51b79e692336365dfcbec4f5f5dfc9b7d827e Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 12 May 2023 08:26:54 +0700 Subject: [PATCH 078/214] feat(developer): add tests for keyboard and package version matching Adds `WARN_KeyboardVersionsDoNotMatch` and `WARN_KeyboardVersionsDoNotMatchPackageVersion`. Adds unit tests. Several other 'invalid' packages needed corrections after adding this validation. Note that one unit test was deleted because it could never be satisfied after adding this validation step. --- developer/src/kmc-package/build.sh | 2 +- .../src/kmc-package/src/compiler/messages.ts | 10 +++- .../compiler/package-version-validation.ts | 39 +++++++++++---- ...ageCannotContainBothModelsAndKeyboards.kps | 2 +- ...geNameDoesNotFollowKeyboardConventions.kps | 2 +- .../error_package_name_cannot_be_blank.kps | 2 +- .../error_package_name_cannot_be_blank_2.kps | 2 +- .../error_package_name_cannot_be_blank_3.kps | 26 ---------- .../test/fixtures/invalid/version_four.kmn | 6 +++ .../test/fixtures/invalid/version_four.kmx | Bin 0 -> 326 bytes ...e_does_not_follow_filename_conventions.kps | 2 +- ...does_not_follow_filename_conventions_2.kps | 2 +- .../warn_keyboard_versions_do_not_match.kps | 45 ++++++++++++++++++ ..._versions_do_not_match_package_version.kps | 31 ++++++++++++ ...rn_package_should_not_repeat_languages.kps | 2 +- .../kmc-package/test/test-package-compiler.ts | 15 +++++- 16 files changed, 142 insertions(+), 46 deletions(-) delete mode 100644 developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_3.kps create mode 100644 developer/src/kmc-package/test/fixtures/invalid/version_four.kmn create mode 100644 developer/src/kmc-package/test/fixtures/invalid/version_four.kmx create mode 100644 developer/src/kmc-package/test/fixtures/invalid/warn_keyboard_versions_do_not_match.kps create mode 100644 developer/src/kmc-package/test/fixtures/invalid/warn_keyboard_versions_do_not_match_package_version.kps diff --git a/developer/src/kmc-package/build.sh b/developer/src/kmc-package/build.sh index 968b5fd241..3206f60fda 100755 --- a/developer/src/kmc-package/build.sh +++ b/developer/src/kmc-package/build.sh @@ -28,7 +28,7 @@ builder_describe "Build Keyman kmc Package Compiler module" \ "--dry-run,-n don't actually publish, just dry run" builder_describe_outputs \ configure /node_modules \ - build /developer/src/kmc-package/build/src/kmp-compiler.js + build /developer/src/kmc-package/build/src/main.js builder_parse "$@" #------------------------------------------------------------------------------------------------------------------- diff --git a/developer/src/kmc-package/src/compiler/messages.ts b/developer/src/kmc-package/src/compiler/messages.ts index e5e208a5b9..44ac03c48d 100644 --- a/developer/src/kmc-package/src/compiler/messages.ts +++ b/developer/src/kmc-package/src/compiler/messages.ts @@ -78,5 +78,13 @@ export class CompilerMessages { static Error_KeyboardFileNotFound = (o:{filename:string}) => m(this.ERROR_KeyboardFileNotFound, `Keyboard file ${o.filename} was not found. Has it been compiled?`); static ERROR_KeyboardFileNotFound = SevError | 0x0011; -} + + static Warn_KeyboardVersionsDoNotMatch = (o: {keyboard:string, version:string, firstKeyboard:string, firstVersion:string}) => m(this.WARN_KeyboardVersionsDoNotMatch, + `Keyboard ${o.keyboard} version ${o.version} does not match keyboard ${o.firstKeyboard} version ${o.firstVersion}.`); + static WARN_KeyboardVersionsDoNotMatch = SevWarn | 0x0012; + + static Warn_KeyboardVersionsDoNotMatchPackageVersion = (o: {keyboard:string, keyboardVersion: string, packageVersion: string}) => m(this.WARN_KeyboardVersionsDoNotMatchPackageVersion, + `Keyboard ${o.keyboard} version ${o.keyboardVersion} does not match package version ${o.packageVersion}.`); + static WARN_KeyboardVersionsDoNotMatchPackageVersion = SevWarn | 0x0013; + } diff --git a/developer/src/kmc-package/src/compiler/package-version-validation.ts b/developer/src/kmc-package/src/compiler/package-version-validation.ts index bbf1062620..648eb432bc 100644 --- a/developer/src/kmc-package/src/compiler/package-version-validation.ts +++ b/developer/src/kmc-package/src/compiler/package-version-validation.ts @@ -15,8 +15,12 @@ export class PackageVersionValidation { * @returns */ public validateAndUpdateVersions(kpsFilename: string, kps: KpsFile.KpsFile, kmp: KmpJsonFile.KmpJsonFile) { - if(!this.checkFollowKeyboardVersion(kps, kmp)) { - return false; + const followKeyboardVersion = kps.options?.followKeyboardVersion !== undefined; + + if(followKeyboardVersion) { + if(!this.checkFollowKeyboardVersion(kps, kmp)) { + return false; + } } let result = true; @@ -26,23 +30,40 @@ export class PackageVersionValidation { return true; } + // We now know we have at least one keyboard in the package + for(let keyboard of kmp.keyboards) { result = this.updateKeyboardVersionFromKmx(kpsFilename, kmp, keyboard) && result; + if(result) { + if(kmp.keyboards[0].version !== keyboard.version) { + this.callbacks.reportMessage(CompilerMessages.Warn_KeyboardVersionsDoNotMatch({ + keyboard:keyboard.id, + version:keyboard.version, + firstKeyboard:kmp.keyboards[0].id, + firstVersion:kmp.keyboards[0].version + })); + } + } } - if(result && kps.options?.followKeyboardVersion !== undefined) { - // We know we have at least one keyboard because of earlier checkFollowKyeboardVersion check - kmp.info.version.description = kmp.keyboards[0].version; + if(result) { + if(followKeyboardVersion) { + kmp.info.version.description = kmp.keyboards[0].version; + } + else if(kmp.info.version?.description != kmp.keyboards[0].version) { + // Only need to compare against first keyboard as we compare keyboards above + this.callbacks.reportMessage(CompilerMessages.Warn_KeyboardVersionsDoNotMatchPackageVersion({ + keyboard: kmp.keyboards[0].id, + keyboardVersion: kmp.keyboards[0].version, + packageVersion: kmp.info.version.description + })); + } } return result; } private checkFollowKeyboardVersion(kps: KpsFile.KpsFile, kmp: KmpJsonFile.KmpJsonFile) { - if(kps.options?.followKeyboardVersion === undefined) { - return true; - } - // Lexical model packages do not allow FollowKeyboardVersion if(kmp.lexicalModels && kmp.lexicalModels.length) { this.callbacks.reportMessage(CompilerMessages.Error_FollowKeyboardVersionNotAllowedForModelPackages()); diff --git a/developer/src/kmc-package/test/fixtures/invalid/ERROR_PackageCannotContainBothModelsAndKeyboards.kps b/developer/src/kmc-package/test/fixtures/invalid/ERROR_PackageCannotContainBothModelsAndKeyboards.kps index 37bdc02551..5ee547dcf1 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/ERROR_PackageCannotContainBothModelsAndKeyboards.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/ERROR_PackageCannotContainBothModelsAndKeyboards.kps @@ -8,7 +8,7 @@ Khmer Angkor © 2015-2022 SIL International Makara Sok - + 1.3 https://keyman.com/keyboards/khmer_angkor diff --git a/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowKeyboardConventions.kps b/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowKeyboardConventions.kps index e6d3caecb5..867129bac3 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowKeyboardConventions.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowKeyboardConventions.kps @@ -9,7 +9,7 @@ SENĆOŦEN (Saanich Dialect) Lexical Model © 2019 National Research Council Canada Eddie Antonio Santos - 1.0.3 + 1.3 diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank.kps b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank.kps index ffc566f84b..870d8ae55b 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank.kps @@ -9,7 +9,7 @@ © 2019 National Research Council Canada Eddie Antonio Santos - 1.0.3 + 1.3 diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_2.kps b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_2.kps index 67d39da4c3..01eba9981d 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_2.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_2.kps @@ -8,7 +8,7 @@ © 2019 National Research Council Canada Eddie Antonio Santos - 1.0.3 + 1.3 diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_3.kps b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_3.kps deleted file mode 100644 index fbc8689f87..0000000000 --- a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_3.kps +++ /dev/null @@ -1,26 +0,0 @@ - - - - 15.0.266.0 - 7.0 - - - - - khmer_angkor.kmx - Keyboard Khmer Angkor - 0 - .kmx - - - - - Khmer Angkor - khmer_angkor - 1.3 - - Central Khmer (Khmer, Cambodia) - - - - diff --git a/developer/src/kmc-package/test/fixtures/invalid/version_four.kmn b/developer/src/kmc-package/test/fixtures/invalid/version_four.kmn new file mode 100644 index 0000000000..cb2cce5816 --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/version_four.kmn @@ -0,0 +1,6 @@ +store(&name) 'version 4' +store(&keyboardversion) '4.0' + +begin unicode > use(main) + +group(main) using keys \ No newline at end of file diff --git a/developer/src/kmc-package/test/fixtures/invalid/version_four.kmx b/developer/src/kmc-package/test/fixtures/invalid/version_four.kmx new file mode 100644 index 0000000000000000000000000000000000000000..7180460e961b26b2bbb372c70302c0d8f77934f8 GIT binary patch literal 326 zcmZvXJqp4=5QSeF#YR&2S6WyHgF!3>#U`Z|wt|9!8i``?2HsEb5Eh<5&~M^eh(37p zzS*5wl6X29t0ZODOIgUXf(qEUj|1R|K>1eC$PHHCt|dL~i>38}`AUKQ}gc_yxE@B^v+$ literal 0 HcmV?d00001 diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions.kps index 7ef30cfab2..6523df4813 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions.kps @@ -8,7 +8,7 @@ SENĆOŦEN (Saanich Dialect) Lexical Model © 2019 National Research Council Canada Eddie Antonio Santos - 1.0.3 + 1.3 diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions_2.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions_2.kps index c822e75dfa..d29a01c580 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions_2.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions_2.kps @@ -8,7 +8,7 @@ SENĆOŦEN (Saanich Dialect) Lexical Model © 2019 National Research Council Canada Eddie Antonio Santos - 1.0.3 + 1.3 diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_keyboard_versions_do_not_match.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_keyboard_versions_do_not_match.kps new file mode 100644 index 0000000000..2eb09374c6 --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_keyboard_versions_do_not_match.kps @@ -0,0 +1,45 @@ + + + + 15.0.266.0 + 7.0 + + + SENĆOŦEN (Saanich Dialect) Lexical Model + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.3 + + + + khmer_angkor.kmx + Keyboard Khmer Angkor + 0 + .kmx + + + version_four.kmx + Keyboard Version Four + 0 + .kmx + + + + + Khmer Angkor + khmer_angkor + 1.3 + + Khmer + + + + Version 4 + version_four + 4.0 + + Khmer + + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_keyboard_versions_do_not_match_package_version.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_keyboard_versions_do_not_match_package_version.kps new file mode 100644 index 0000000000..fe0276104b --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_keyboard_versions_do_not_match_package_version.kps @@ -0,0 +1,31 @@ + + + + 15.0.266.0 + 7.0 + + + SENĆOŦEN (Saanich Dialect) Lexical Model + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.3 + + + + version_four.kmx + Keyboard Version Four + 0 + .kmx + + + + + Version 4 + version_four + 4.0 + + Khmer + + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_package_should_not_repeat_languages.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_package_should_not_repeat_languages.kps index b8456b6ddd..a1c6cffe9f 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/warn_package_should_not_repeat_languages.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_package_should_not_repeat_languages.kps @@ -8,7 +8,7 @@ SENĆOŦEN (Saanich Dialect) Lexical Model © 2019 National Research Council Canada Eddie Antonio Santos - 1.0.3 + 1.3 diff --git a/developer/src/kmc-package/test/test-package-compiler.ts b/developer/src/kmc-package/test/test-package-compiler.ts index 1243068bb4..a99645055e 100644 --- a/developer/src/kmc-package/test/test-package-compiler.ts +++ b/developer/src/kmc-package/test/test-package-compiler.ts @@ -13,7 +13,7 @@ import { KmpCompiler } from '../src/compiler/kmp-compiler.js'; import { PackageValidation } from '../src/compiler/package-validation.js'; import { CompilerMessages } from '../src/compiler/messages.js'; -const debug = false; +const debug = true; describe('KmpCompiler', function () { const MODELS : string[] = [ @@ -265,7 +265,6 @@ describe('KmpCompiler', function () { it('should generate ERROR_PackageNameCannotBeBlank if package info has empty name', async function() { testForMessage(this, ['invalid', 'error_package_name_cannot_be_blank.kps'], CompilerMessages.ERROR_PackageNameCannotBeBlank); // blank field testForMessage(this, ['invalid', 'error_package_name_cannot_be_blank_2.kps'], CompilerMessages.ERROR_PackageNameCannotBeBlank); // missing field - testForMessage(this, ['invalid', 'error_package_name_cannot_be_blank_3.kps'], CompilerMessages.ERROR_PackageNameCannotBeBlank); // missing info section }); // ERROR_KeyboardFileNotFound @@ -274,4 +273,16 @@ describe('KmpCompiler', function () { testForMessage(this, ['invalid', 'keyboardfilenotfound.kps'], CompilerMessages.ERROR_KeyboardFileNotFound); }); + // WARN_KeyboardVersionsDoNotMatch + + it('should generate WARN_KeyboardVersionsDoNotMatch if two have different versions', async function() { + testForMessage(this, ['invalid', 'warn_keyboard_versions_do_not_match.kps'], CompilerMessages.WARN_KeyboardVersionsDoNotMatch); + }); + + // WARN_KeyboardVersionsDoNotMatchPackageVersion + + it('should generate ERROR_KeyboardFileNotFound if version does not match package version', async function() { + testForMessage(this, ['invalid', 'warn_keyboard_versions_do_not_match_package_version.kps'], CompilerMessages.WARN_KeyboardVersionsDoNotMatchPackageVersion); + }); + }); -- GitLab From d3e4762b527c1b1ccf4ee8038fe4a83fe9529e39 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 12 May 2023 09:07:46 +0700 Subject: [PATCH 079/214] chore(developer): Info_KeyboardFileHasNoKeyboardVersion Downgrades `Warn_KeyboardFileHasNoKeyboardVersion` to `Info_KeyboardFileHasNoKeyboardVersion`, because this is not an error, or even something wrong necessarily; it's just something it's good to be aware of. Updates unit test for kmc to cater for the extra message. --- developer/src/kmc-package/src/compiler/messages.ts | 8 ++++---- .../src/compiler/package-version-validation.ts | 2 +- developer/src/kmc-package/test/test-package-compiler.ts | 6 +++--- .../fixtures/relative_paths/k_000___null_keyboard.kps | 2 +- developer/src/kmc/test/test-project-build.ts | 5 +++-- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/developer/src/kmc-package/src/compiler/messages.ts b/developer/src/kmc-package/src/compiler/messages.ts index 44ac03c48d..7ae06ec371 100644 --- a/developer/src/kmc-package/src/compiler/messages.ts +++ b/developer/src/kmc-package/src/compiler/messages.ts @@ -1,7 +1,7 @@ import { CompilerErrorNamespace, CompilerErrorSeverity, CompilerMessageSpec as m } from "@keymanapp/common-types"; const Namespace = CompilerErrorNamespace.PackageCompiler; -// const SevInfo = CompilerErrorSeverity.Info | Namespace; +const SevInfo = CompilerErrorSeverity.Info | Namespace; // const SevHint = CompilerErrorSeverity.Hint | Namespace; const SevWarn = CompilerErrorSeverity.Warn | Namespace; const SevError = CompilerErrorSeverity.Error | Namespace; @@ -43,9 +43,9 @@ export class CompilerMessages { `Keyboard file ${o.filename} is not a valid .kmx file`); static ERROR_KeyboardFileNotValid = SevError | 0x0009; - static Warn_KeyboardFileHasNoKeyboardVersion = (o:{filename:string}) => m(this.WARN_KeyboardFileHasNoKeyboardVersion, - `Keyboard file ${o.filename} has no &KeyboardVersion store`); - static WARN_KeyboardFileHasNoKeyboardVersion = SevWarn | 0x000A; + static Info_KeyboardFileHasNoKeyboardVersion = (o:{filename:string}) => m(this.INFO_KeyboardFileHasNoKeyboardVersion, + `Keyboard file ${o.filename} has no &KeyboardVersion store, using default '0.0'`); + static INFO_KeyboardFileHasNoKeyboardVersion = SevInfo | 0x000A; static Error_PackageCannotContainBothModelsAndKeyboards = () => m(this.ERROR_PackageCannotContainBothModelsAndKeyboards, `The package contains both lexical models and keyboards, which is not permitted.`); diff --git a/developer/src/kmc-package/src/compiler/package-version-validation.ts b/developer/src/kmc-package/src/compiler/package-version-validation.ts index 648eb432bc..c240c77328 100644 --- a/developer/src/kmc-package/src/compiler/package-version-validation.ts +++ b/developer/src/kmc-package/src/compiler/package-version-validation.ts @@ -129,7 +129,7 @@ export class PackageVersionValidation { const store = kmx.stores.find(store => store.dwSystemID == KMX.KMXFile.TSS_KEYBOARDVERSION); if(!store) { // We have no version number store, so use default version - this.callbacks.reportMessage(CompilerMessages.Warn_KeyboardFileHasNoKeyboardVersion({filename})); + this.callbacks.reportMessage(CompilerMessages.Info_KeyboardFileHasNoKeyboardVersion({filename})); return true; } diff --git a/developer/src/kmc-package/test/test-package-compiler.ts b/developer/src/kmc-package/test/test-package-compiler.ts index a99645055e..bf04fda493 100644 --- a/developer/src/kmc-package/test/test-package-compiler.ts +++ b/developer/src/kmc-package/test/test-package-compiler.ts @@ -217,10 +217,10 @@ describe('KmpCompiler', function () { testForMessage(this, ['invalid', 'keyboardfilenotvalid.kps'], CompilerMessages.ERROR_KeyboardFileNotValid); }); - // WARN_KeyboardFileHasNoKeyboardVersion + // INFO_KeyboardFileHasNoKeyboardVersion - it('should generate WARN_KeyboardFileHasNoKeyboardVersion if is set but keyboard has no version', async function() { - testForMessage(this, ['invalid', 'nokeyboardversion.kps'], CompilerMessages.WARN_KeyboardFileHasNoKeyboardVersion); + it('should generate INFO_KeyboardFileHasNoKeyboardVersion if is set but keyboard has no version', async function() { + testForMessage(this, ['invalid', 'nokeyboardversion.kps'], CompilerMessages.INFO_KeyboardFileHasNoKeyboardVersion); }); // ERROR_PackageCannotContainBothModelsAndKeyboards diff --git a/developer/src/kmc/test/fixtures/relative_paths/k_000___null_keyboard.kps b/developer/src/kmc/test/fixtures/relative_paths/k_000___null_keyboard.kps index 2839137769..af65dd9269 100644 --- a/developer/src/kmc/test/fixtures/relative_paths/k_000___null_keyboard.kps +++ b/developer/src/kmc/test/fixtures/relative_paths/k_000___null_keyboard.kps @@ -18,7 +18,7 @@ k_000___null_keyboard Copyright (C) Keyman Team Keyman Team - + 0.0 diff --git a/developer/src/kmc/test/test-project-build.ts b/developer/src/kmc/test/test-project-build.ts index a57f77d317..68b5926933 100644 --- a/developer/src/kmc/test/test-project-build.ts +++ b/developer/src/kmc/test/test-project-build.ts @@ -16,8 +16,9 @@ describe('BuildProject', function () { debug: false, warnDeprecatedCode: true, }); - // 4 messages == starting build, build successful x 2 - assert.equal(callbacks.messages.length, 4); + // 5 messages == starting build, info: no keyboard version, build successful x 2 + // callbacks.printMessages(); + assert.equal(callbacks.messages.length, 5); assert.isTrue(result); }); }); -- GitLab From e4ad95550eb3dbc545398f0fab38cc5d5e1866cb Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 12 May 2023 13:21:13 +0700 Subject: [PATCH 080/214] feat(developer): verify bcp47 tags are valid and minimal in kmc-package Adds checks for bcp47 tag metadata for keyboards and lexical models -- both validity and minimality. Adds `ERROR_LanguageTagIsNotValid` and `WARN_LanguageTagIsNotMinimal` messages and corresponding unit tests. This was implemented by extending the existing duplicate id check, so renamed that function accordingly. --- .../src/kmc-package/src/compiler/messages.ts | 14 +++++-- .../src/compiler/package-validation.ts | 39 ++++++++++++++----- .../error_language_tag_is_not_valid.kps | 32 +++++++++++++++ .../warn_language_tag_is_not_minimal.kps | 32 +++++++++++++++ .../kmc-package/test/test-package-compiler.ts | 13 ++++++- 5 files changed, 117 insertions(+), 13 deletions(-) create mode 100644 developer/src/kmc-package/test/fixtures/invalid/error_language_tag_is_not_valid.kps create mode 100644 developer/src/kmc-package/test/fixtures/invalid/warn_language_tag_is_not_minimal.kps diff --git a/developer/src/kmc-package/src/compiler/messages.ts b/developer/src/kmc-package/src/compiler/messages.ts index 7ae06ec371..ec8ce08af8 100644 --- a/developer/src/kmc-package/src/compiler/messages.ts +++ b/developer/src/kmc-package/src/compiler/messages.ts @@ -51,8 +51,8 @@ export class CompilerMessages { `The package contains both lexical models and keyboards, which is not permitted.`); static ERROR_PackageCannotContainBothModelsAndKeyboards = SevError | 0x000B; - static Warn_PackageShouldNotRepeatLanguages = (o:{resourceType: string, id: string, tag: string}) => m(this.WARN_PackageShouldNotRepeatLanguages, - `The ${o.resourceType} ${o.id} has a repeated language "${o.tag}".`); + static Warn_PackageShouldNotRepeatLanguages = (o:{resourceType: string, id: string, minimalTag: string, firstTag: string, secondTag: string}) => m(this.WARN_PackageShouldNotRepeatLanguages, + `Two language tags in ${o.resourceType} ${o.id}, '${o.firstTag}' and '${o.secondTag}', reduce to the same minimal tag '${o.minimalTag}'.`); static WARN_PackageShouldNotRepeatLanguages = SevWarn | 0x000C; static Warn_PackageNameDoesNotFollowLexicalModelConventions = (o:{filename: string}) => m(this.WARN_PackageNameDoesNotFollowLexicalModelConventions, @@ -86,5 +86,13 @@ export class CompilerMessages { static Warn_KeyboardVersionsDoNotMatchPackageVersion = (o: {keyboard:string, keyboardVersion: string, packageVersion: string}) => m(this.WARN_KeyboardVersionsDoNotMatchPackageVersion, `Keyboard ${o.keyboard} version ${o.keyboardVersion} does not match package version ${o.packageVersion}.`); static WARN_KeyboardVersionsDoNotMatchPackageVersion = SevWarn | 0x0013; - } + + static Error_LanguageTagIsNotValid = (o: {resourceType: string, id:string, lang:string, e:any}) => m(this.ERROR_LanguageTagIsNotValid, + `Language tag '${o.lang}' in ${o.resourceType} ${o.id} is invalid.`); + static ERROR_LanguageTagIsNotValid = SevError | 0x0014; + + static Warn_LanguageTagIsNotMinimal = (o: {resourceType: string, id:string, actual:string, expected:string}) => m(this.WARN_LanguageTagIsNotMinimal, + `Language tag '${o.actual}' in ${o.resourceType} ${o.id} is not minimal, and should be '${o.expected}'.`); + static WARN_LanguageTagIsNotMinimal = SevWarn | 0x0015; +} diff --git a/developer/src/kmc-package/src/compiler/package-validation.ts b/developer/src/kmc-package/src/compiler/package-validation.ts index 7033b6c565..cfacf95cd4 100644 --- a/developer/src/kmc-package/src/compiler/package-validation.ts +++ b/developer/src/kmc-package/src/compiler/package-validation.ts @@ -41,16 +41,33 @@ export class PackageValidation { return true; } - private checkForDuplicatedLanguages(resourceType: 'keyboard'|'model', id: string, languages: KmpJsonFile.KmpJsonFileLanguage[]): void { - let tags: {[index:string]: boolean} = {}; + private checkForDuplicatedOrNonMinimalLanguages(resourceType: 'keyboard'|'model', id: string, languages: KmpJsonFile.KmpJsonFileLanguage[]): boolean { + let minimalTags: {[tag: string]: string} = {}; + for(let lang of languages) { - const langTag = lang.id.toLowerCase(); - if(tags[langTag]) { - this.callbacks.reportMessage(CompilerMessages.Warn_PackageShouldNotRepeatLanguages({resourceType:resourceType, id:id, tag:lang.id})); - } else { - tags[langTag] = true; + let locale; + try { + locale = new Intl.Locale(lang.id); + } catch(e: any) { + this.callbacks.reportMessage(CompilerMessages.Error_LanguageTagIsNotValid({resourceType, id, lang: lang.id, e})); + return false; + } + + const minimalTag = locale.minimize().toString(); + + if(minimalTag.toLowerCase() !== lang.id.toLowerCase()) { + this.callbacks.reportMessage(CompilerMessages.Warn_LanguageTagIsNotMinimal({resourceType, id, actual: lang.id, expected: minimalTag})); + } + + if(minimalTags[minimalTag]) { + this.callbacks.reportMessage(CompilerMessages.Warn_PackageShouldNotRepeatLanguages({resourceType, id, minimalTag, firstTag: lang.id, secondTag: minimalTags[minimalTag]})); + } + else { + minimalTags[minimalTag] = lang.id; } } + + return true; } private checkForModelsAndKeyboardsInSamePackage(kmpJson: KmpJsonFile.KmpJsonFile): boolean { @@ -74,7 +91,9 @@ export class PackageValidation { } for(let model of kmpJson.lexicalModels) { - this.checkForDuplicatedLanguages('model', model.id, model.languages); + if(!this.checkForDuplicatedOrNonMinimalLanguages('model', model.id, model.languages)) { + return false; + } } return true; @@ -92,7 +111,9 @@ export class PackageValidation { } for(let keyboard of kmpJson.keyboards) { - this.checkForDuplicatedLanguages('keyboard', keyboard.id, keyboard.languages); + if(!this.checkForDuplicatedOrNonMinimalLanguages('keyboard', keyboard.id, keyboard.languages)) { + return false; + } } return true; diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_language_tag_is_not_valid.kps b/developer/src/kmc-package/test/fixtures/invalid/error_language_tag_is_not_valid.kps new file mode 100644 index 0000000000..3c47540d2b --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/error_language_tag_is_not_valid.kps @@ -0,0 +1,32 @@ + + + + 15.0.266.0 + 7.0 + + + SENĆOŦEN (Saanich Dialect) Lexical Model + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.3 + + + + khmer_angkor.kmx + Keyboard Khmer Angkor + 0 + .kmx + + + + + Khmer Angkor + khmer_angkor + 1.3 + + + English (Australian script) as spoken in Latin + + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_language_tag_is_not_minimal.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_language_tag_is_not_minimal.kps new file mode 100644 index 0000000000..8e4440e3da --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_language_tag_is_not_minimal.kps @@ -0,0 +1,32 @@ + + + + 15.0.266.0 + 7.0 + + + SENĆOŦEN (Saanich Dialect) Lexical Model + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.3 + + + + khmer_angkor.kmx + Keyboard Khmer Angkor + 0 + .kmx + + + + + Khmer Angkor + khmer_angkor + 1.3 + + + Central Khmer (Khmer, Cambodia) + + + + diff --git a/developer/src/kmc-package/test/test-package-compiler.ts b/developer/src/kmc-package/test/test-package-compiler.ts index bf04fda493..95e6e3f9f0 100644 --- a/developer/src/kmc-package/test/test-package-compiler.ts +++ b/developer/src/kmc-package/test/test-package-compiler.ts @@ -281,8 +281,19 @@ describe('KmpCompiler', function () { // WARN_KeyboardVersionsDoNotMatchPackageVersion - it('should generate ERROR_KeyboardFileNotFound if version does not match package version', async function() { + it('should generate WARN_KeyboardVersionsDoNotMatchPackageVersion if version does not match package version', async function() { testForMessage(this, ['invalid', 'warn_keyboard_versions_do_not_match_package_version.kps'], CompilerMessages.WARN_KeyboardVersionsDoNotMatchPackageVersion); }); + // ERROR_LanguageTagIsNotValid + + it('should generate ERROR_LanguageTagIsNotValid if keyboard has an invalid language tag', async function() { + testForMessage(this, ['invalid', 'error_language_tag_is_not_valid.kps'], CompilerMessages.ERROR_LanguageTagIsNotValid); + }); + + // WARN_LanguageTagIsNotMinimal + + it('should generate WARN_LanguageTagIsNotMinimal if keyboard has a non-minimal language tag', async function() { + testForMessage(this, ['invalid', 'warn_language_tag_is_not_minimal.kps'], CompilerMessages.WARN_LanguageTagIsNotMinimal); + }); }); -- GitLab From b3436b8aff3b021998c58a7d53e14a262473566b Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 12 May 2023 13:31:56 +0700 Subject: [PATCH 081/214] chore(developer): fix kmc-ldml unit tests --- developer/src/kmc-ldml/test/helpers/index.ts | 18 +++++++++--------- .../kmc-ldml/test/test-keymanweb-compiler.ts | 10 +++++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/developer/src/kmc-ldml/test/helpers/index.ts b/developer/src/kmc-ldml/test/helpers/index.ts index 498975f71e..8ba8a28aa8 100644 --- a/developer/src/kmc-ldml/test/helpers/index.ts +++ b/developer/src/kmc-ldml/test/helpers/index.ts @@ -6,11 +6,11 @@ import * as path from 'path'; import { fileURLToPath } from 'url'; import { SectionCompiler } from '../../src/compiler/section-compiler.js'; import { KMXPlus, LDMLKeyboardXMLSourceFileReader, VisualKeyboard, CompilerEvent, LDMLKeyboardTestDataXMLSourceFile } from '@keymanapp/common-types'; -import Compiler from '../../src/compiler/compiler.js'; +import { LdmlKeyboardCompiler } from '../../src/compiler/compiler.js'; import { assert } from 'chai'; -import KMXPlusMetadataCompiler from '../../src/compiler/metadata-compiler.js'; -import CompilerOptions from '../../src/compiler/compiler-options.js'; -import VisualKeyboardCompiler from '../../src/compiler/visual-keyboard-compiler.js'; +import { KMXPlusMetadataCompiler } from '../../src/compiler/metadata-compiler.js'; +import { CompilerOptions } from '../../src/compiler/compiler-options.js'; +import { LdmlKeyboardVisualKeyboardCompiler } from '../../src/compiler/visual-keyboard-compiler.js'; import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; import KMXPlusFile = KMXPlus.KMXPlusFile; @@ -76,13 +76,13 @@ export function loadSectionFixture(compilerClass: typeof SectionCompiler, filena } export function loadTestdata(inputFilename: string, options: CompilerOptions) : LDMLKeyboardTestDataXMLSourceFile { - const k = new Compiler(compilerTestCallbacks, options); + const k = new LdmlKeyboardCompiler(compilerTestCallbacks, options); const source = k.loadTestData(inputFilename); return source; } export function compileKeyboard(inputFilename: string, options: CompilerOptions): KMXPlusFile { - const k = new Compiler(compilerTestCallbacks, options); + const k = new LdmlKeyboardCompiler(compilerTestCallbacks, options); const source = k.load(inputFilename); checkMessages(); assert.isNotNull(source, 'k.load should not have returned null'); @@ -103,7 +103,7 @@ export function compileKeyboard(inputFilename: string, options: CompilerOptions) } export function compileVisualKeyboard(inputFilename: string, options: CompilerOptions): VisualKeyboard.VisualKeyboard { - const k = new Compiler(compilerTestCallbacks, options); + const k = new LdmlKeyboardCompiler(compilerTestCallbacks, options); const source = k.load(inputFilename); checkMessages(); assert.isNotNull(source, 'k.load should not have returned null'); @@ -112,9 +112,9 @@ export function compileVisualKeyboard(inputFilename: string, options: CompilerOp checkMessages(); assert.isTrue(valid, 'k.validate should not have failed'); - const vk = (new VisualKeyboardCompiler()).compile(source); + const vk = (new LdmlKeyboardVisualKeyboardCompiler()).compile(source); checkMessages(); - assert.isNotNull(vk, 'VisualKeyboardCompiler.compile should not have returned null'); + assert.isNotNull(vk, 'LdmlKeyboardVisualKeyboardCompiler.compile should not have returned null'); return vk; } diff --git a/developer/src/kmc-ldml/test/test-keymanweb-compiler.ts b/developer/src/kmc-ldml/test/test-keymanweb-compiler.ts index 43f3721de6..8d33208902 100644 --- a/developer/src/kmc-ldml/test/test-keymanweb-compiler.ts +++ b/developer/src/kmc-ldml/test/test-keymanweb-compiler.ts @@ -1,8 +1,8 @@ import 'mocha'; import { assert } from 'chai'; import { checkMessages, compilerTestCallbacks, makePathToFixture } from './helpers/index.js'; -import { KeymanWebCompiler } from '../src/compiler/keymanweb-compiler.js'; -import Compiler from '../src/compiler/compiler.js'; +import { LdmlKeyboardKeymanWebCompiler } from '../src/compiler/keymanweb-compiler.js'; +import { LdmlKeyboardCompiler } from '../src/compiler/compiler.js'; import * as fs from 'fs'; describe('KeymanWebCompiler', function() { @@ -16,7 +16,7 @@ describe('KeymanWebCompiler', function() { // Load input data; we'll use the LDML keyboard compiler loader to save us // effort here - const k = new Compiler(compilerTestCallbacks, {debug: true, addCompilerVersion: false}); + const k = new LdmlKeyboardCompiler(compilerTestCallbacks, {debug: true, addCompilerVersion: false}); const source = k.load(inputFilename); checkMessages(); assert.isNotNull(source, 'k.load should not have returned null'); @@ -27,7 +27,7 @@ describe('KeymanWebCompiler', function() { assert.isTrue(valid, 'k.validate should not have failed'); // Actual test: compile to javascript - const jsCompiler = new KeymanWebCompiler(compilerTestCallbacks, {debug: true}); + const jsCompiler = new LdmlKeyboardKeymanWebCompiler(compilerTestCallbacks, {debug: true}); const output = jsCompiler.compile('basic.xml', source); assert.isNotNull(output); @@ -36,7 +36,7 @@ describe('KeymanWebCompiler', function() { assert.strictEqual(output, outputFixture); // Second test: compile to javascript without debug formatting - const jsCompilerNoDebug = new KeymanWebCompiler(compilerTestCallbacks, {debug: false}); + const jsCompilerNoDebug = new LdmlKeyboardKeymanWebCompiler(compilerTestCallbacks, {debug: false}); const outputNoDebug = jsCompilerNoDebug.compile('basic.xml', source); assert.isNotNull(outputNoDebug); -- GitLab From 187a25240a3fef2d0410f3e36c5441ee551a2711 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 12 May 2023 14:14:32 +0700 Subject: [PATCH 082/214] chore(developer): fixup missing rename --- .../src/kmc-ldml/test/test-keymanweb-compiler.ts | 2 +- .../kmc/src/commands/build/BuildLdmlKeyboard.ts | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/developer/src/kmc-ldml/test/test-keymanweb-compiler.ts b/developer/src/kmc-ldml/test/test-keymanweb-compiler.ts index 8d33208902..fb4f28daee 100644 --- a/developer/src/kmc-ldml/test/test-keymanweb-compiler.ts +++ b/developer/src/kmc-ldml/test/test-keymanweb-compiler.ts @@ -5,7 +5,7 @@ import { LdmlKeyboardKeymanWebCompiler } from '../src/compiler/keymanweb-compile import { LdmlKeyboardCompiler } from '../src/compiler/compiler.js'; import * as fs from 'fs'; -describe('KeymanWebCompiler', function() { +describe('LdmlKeyboardKeymanWebCompiler', function() { it('should build a .js file', async function() { // Let's build basic.xml diff --git a/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts b/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts index 46c939b0e0..024f7f5340 100644 --- a/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts +++ b/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts @@ -1,6 +1,6 @@ import * as path from 'path'; import * as fs from 'fs'; -import * as kmc from '@keymanapp/kmc-ldml'; +import * as kmcLdml from '@keymanapp/kmc-ldml'; import { KvkFileWriter, CompilerCallbacks } from '@keymanapp/common-types'; import { BuildActivity, BuildActivityOptions } from './BuildActivity.js'; @@ -43,14 +43,14 @@ export class BuildLdmlKeyboard extends BuildActivity { } function buildLdmlKeyboardToMemory(inputFilename: string, callbacks: CompilerCallbacks, options: BuildActivityOptions): [Uint8Array, Uint8Array, Uint8Array] { - let compilerOptions: kmc.CompilerOptions = { + let compilerOptions: kmcLdml.CompilerOptions = { debug: options.debug ?? false, addCompilerVersion: options.compilerVersion ?? true, // TODO: warnDeprecatedCode: options.warnDeprecatedCode, // TODO: treatWarningsAsErrors: options.treatWarningsAsErrors, } - const k = new kmc.LdmlKeyboardCompiler(callbacks, options); + const k = new kmcLdml.LdmlKeyboardCompiler(callbacks, options); let source = k.load(inputFilename); if (!source) { return [null, null, null]; @@ -62,13 +62,13 @@ function buildLdmlKeyboardToMemory(inputFilename: string, callbacks: CompilerCal // In order for the KMX file to be loaded by non-KMXPlus components, it is helpful // to duplicate some of the metadata - kmc.KMXPlusMetadataCompiler.addKmxMetadata(kmx.kmxplus, kmx.keyboard, compilerOptions); + kmcLdml.KMXPlusMetadataCompiler.addKmxMetadata(kmx.kmxplus, kmx.keyboard, compilerOptions); // Use the builder to generate the binary output file - const builder = new kmc.KMXBuilder(kmx, options.debug); + const builder = new kmcLdml.KMXBuilder(kmx, options.debug); const kmx_binary = builder.compile(); - const vkcompiler = new kmc.LdmlKeyboardVisualKeyboardCompiler(); + const vkcompiler = new kmcLdml.LdmlKeyboardVisualKeyboardCompiler(); const vk = vkcompiler.compile(source); const writer = new KvkFileWriter(); const kvk_binary = writer.write(vk); @@ -78,7 +78,7 @@ function buildLdmlKeyboardToMemory(inputFilename: string, callbacks: CompilerCal // const tlcompiler = new kmc.TouchLayoutCompiler(); // const tl = tlcompiler.compile(source); // const tlwriter = new TouchLayoutFileWriter(); - const kmwcompiler = new kmc.KeymanWebCompiler(callbacks, compilerOptions); + const kmwcompiler = new kmcLdml.LdmlKeyboardKeymanWebCompiler(callbacks, compilerOptions); const kmw_string = kmwcompiler.compile(inputFilename, source); const encoder = new TextEncoder(); const kmw_binary = encoder.encode(kmw_string); -- GitLab From 2528731b583e041422da9415f104b33b482c143e Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 12 May 2023 14:15:24 +0700 Subject: [PATCH 083/214] chore(developer): fixup missing rename --- developer/src/kmc-ldml/src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/developer/src/kmc-ldml/src/main.ts b/developer/src/kmc-ldml/src/main.ts index e8af2f7804..5d5d2f09e6 100644 --- a/developer/src/kmc-ldml/src/main.ts +++ b/developer/src/kmc-ldml/src/main.ts @@ -1,6 +1,6 @@ export { LdmlKeyboardCompiler } from './compiler/compiler.js'; -export { LdmlKeyboardKeymanWebCompiler as KeymanWebCompiler } from './compiler/keymanweb-compiler.js'; +export { LdmlKeyboardKeymanWebCompiler } from './compiler/keymanweb-compiler.js'; export { LdmlKeyboardVisualKeyboardCompiler } from './compiler/visual-keyboard-compiler.js'; export { TouchLayoutCompiler } from './compiler/touch-layout-compiler.js'; export { CompilerOptions } from './compiler/compiler-options.js'; -- GitLab From 8446775dd5987f298cbafd7ae7dab5a5b52f617a Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 12 May 2023 14:42:07 +0700 Subject: [PATCH 084/214] feat(developer): verify at least one language in package Adds `ERROR_MustHaveAtLeastOneLanguage` and corresponding unit test. --- .../kmc-package/src/compiler/kmp-compiler.ts | 29 ++++++++++--------- .../src/kmc-package/src/compiler/messages.ts | 4 +++ .../src/compiler/package-validation.ts | 5 ++++ ..._must_have_at_least_one_language.model.kps | 28 ++++++++++++++++++ .../kmc-package/test/test-package-compiler.ts | 7 +++++ 5 files changed, 60 insertions(+), 13 deletions(-) create mode 100644 developer/src/kmc-package/test/fixtures/invalid/keyman.en.error_must_have_at_least_one_language.model.kps diff --git a/developer/src/kmc-package/src/compiler/kmp-compiler.ts b/developer/src/kmc-package/src/compiler/kmp-compiler.ts index 305a1faaa1..b660641df9 100644 --- a/developer/src/kmc-package/src/compiler/kmp-compiler.ts +++ b/developer/src/kmc-package/src/compiler/kmp-compiler.ts @@ -105,16 +105,16 @@ export class KmpCompiler { // if(kps.keyboards && kps.keyboards.keyboard) { - kmp.keyboards = this.arrayWrap(kps.keyboards.keyboard).map((keyboard: KpsFile.KpsFileKeyboard) => { - return { - displayFont: keyboard.displayFont ? this.callbacks.path.basename(keyboard.displayFont) : undefined, - oskFont: keyboard.oSKFont ? this.callbacks.path.basename(keyboard.oSKFont) : undefined, - name:keyboard.name, - id:keyboard.iD, - version:keyboard.version, - languages: this.kpsLanguagesToKmpLanguages(this.arrayWrap(keyboard.languages.language) as KpsFile.KpsFileLanguage[]) - }; - }); + kmp.keyboards = this.arrayWrap(kps.keyboards.keyboard).map((keyboard: KpsFile.KpsFileKeyboard) => ({ + displayFont: keyboard.displayFont ? this.callbacks.path.basename(keyboard.displayFont) : undefined, + oskFont: keyboard.oSKFont ? this.callbacks.path.basename(keyboard.oSKFont) : undefined, + name:keyboard.name, + id:keyboard.iD, + version:keyboard.version, + languages: keyboard.languages ? + this.kpsLanguagesToKmpLanguages(this.arrayWrap(keyboard.languages.language) as KpsFile.KpsFileLanguage[]) : + [] + })); } // @@ -122,9 +122,12 @@ export class KmpCompiler { // if(kps.lexicalModels && kps.lexicalModels.lexicalModel) { - kmp.lexicalModels = this.arrayWrap(kps.lexicalModels.lexicalModel).map((model: KpsFile.KpsFileLexicalModel) => { - return { name:model.name, id:model.iD, languages: this.kpsLanguagesToKmpLanguages(this.arrayWrap(model.languages.language) as KpsFile.KpsFileLanguage[]) } - }); + kmp.lexicalModels = this.arrayWrap(kps.lexicalModels.lexicalModel).map((model: KpsFile.KpsFileLexicalModel) => ({ + name:model.name, + id:model.iD, + languages: model.languages ? + this.kpsLanguagesToKmpLanguages(this.arrayWrap(model.languages.language) as KpsFile.KpsFileLanguage[]) : [] + })); } // diff --git a/developer/src/kmc-package/src/compiler/messages.ts b/developer/src/kmc-package/src/compiler/messages.ts index ec8ce08af8..607af21eb9 100644 --- a/developer/src/kmc-package/src/compiler/messages.ts +++ b/developer/src/kmc-package/src/compiler/messages.ts @@ -94,5 +94,9 @@ export class CompilerMessages { static Warn_LanguageTagIsNotMinimal = (o: {resourceType: string, id:string, actual:string, expected:string}) => m(this.WARN_LanguageTagIsNotMinimal, `Language tag '${o.actual}' in ${o.resourceType} ${o.id} is not minimal, and should be '${o.expected}'.`); static WARN_LanguageTagIsNotMinimal = SevWarn | 0x0015; + + static Error_MustHaveAtLeastOneLanguage = (o:{resourceType:string, id:string}) => m(this.ERROR_MustHaveAtLeastOneLanguage, + `The ${o.resourceType} ${o.id} must have at least one language specified.`); + static ERROR_MustHaveAtLeastOneLanguage = SevError | 0x0016; } diff --git a/developer/src/kmc-package/src/compiler/package-validation.ts b/developer/src/kmc-package/src/compiler/package-validation.ts index cfacf95cd4..96990f2097 100644 --- a/developer/src/kmc-package/src/compiler/package-validation.ts +++ b/developer/src/kmc-package/src/compiler/package-validation.ts @@ -44,6 +44,11 @@ export class PackageValidation { private checkForDuplicatedOrNonMinimalLanguages(resourceType: 'keyboard'|'model', id: string, languages: KmpJsonFile.KmpJsonFileLanguage[]): boolean { let minimalTags: {[tag: string]: string} = {}; + if(languages.length == 0) { + this.callbacks.reportMessage(CompilerMessages.Error_MustHaveAtLeastOneLanguage({resourceType, id})); + return false; + } + for(let lang of languages) { let locale; try { diff --git a/developer/src/kmc-package/test/fixtures/invalid/keyman.en.error_must_have_at_least_one_language.model.kps b/developer/src/kmc-package/test/fixtures/invalid/keyman.en.error_must_have_at_least_one_language.model.kps new file mode 100644 index 0000000000..b79330f06f --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/keyman.en.error_must_have_at_least_one_language.model.kps @@ -0,0 +1,28 @@ + + + + 15.0.266.0 + 7.0 + + + SENĆOŦEN (Saanich Dialect) Lexical Model + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.0.3 + + + + example.qaa.sencoten.model.js + Lexical model example.qaa.sencoten.model.js + 0 + .model.js + + + + + SENĆOŦEN dictionary + example.qaa.sencoten + + + + diff --git a/developer/src/kmc-package/test/test-package-compiler.ts b/developer/src/kmc-package/test/test-package-compiler.ts index 95e6e3f9f0..8a81d56b7c 100644 --- a/developer/src/kmc-package/test/test-package-compiler.ts +++ b/developer/src/kmc-package/test/test-package-compiler.ts @@ -296,4 +296,11 @@ describe('KmpCompiler', function () { it('should generate WARN_LanguageTagIsNotMinimal if keyboard has a non-minimal language tag', async function() { testForMessage(this, ['invalid', 'warn_language_tag_is_not_minimal.kps'], CompilerMessages.WARN_LanguageTagIsNotMinimal); }); + + // ERROR_MustHaveAtLeastOneLanguage + + it('should generate ERROR_MustHaveAtLeastOneLanguage if model or keyboard has zero language tags', async function() { + testForMessage(this, ['invalid', 'keyman.en.error_must_have_at_least_one_language.model.kps'], + CompilerMessages.ERROR_MustHaveAtLeastOneLanguage); + }); }); -- GitLab From 65ef3d0982162bf183c190ab5a6e711b5a8deb24 Mon Sep 17 00:00:00 2001 From: Ross Date: Fri, 12 May 2023 18:21:44 +1000 Subject: [PATCH 085/214] chore(windows): remove QueDebugInformation method --- windows/src/engine/keyman32/appint/aiTIP.cpp | 29 ------------------- windows/src/engine/keyman32/appint/aiTIP.h | 1 - .../keyman32/appint/aiWin2000Unicode.cpp | 11 ------- .../engine/keyman32/appint/aiWin2000Unicode.h | 19 ++++++------ windows/src/engine/keyman32/appint/appint.h | 17 ----------- windows/src/engine/keyman32/kmprocess.cpp | 11 ------- 6 files changed, 9 insertions(+), 79 deletions(-) diff --git a/windows/src/engine/keyman32/appint/aiTIP.cpp b/windows/src/engine/keyman32/appint/aiTIP.cpp index dba603d6b2..34f3afc867 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.cpp +++ b/windows/src/engine/keyman32/appint/aiTIP.cpp @@ -590,32 +590,3 @@ void FillStoreOffsets(AIDEBUGINFO *di) } di->StoreOffsets[n] = 0xFFFF; } - -BOOL AITIP::QueueDebugInformation(int ItemType, LPGROUP Group, LPKEY Rule, PWSTR fcontext, PWSTR foutput, DWORD_PTR dwExtraFlags) -{ - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return TRUE; - - SendDebugMessageFormat(0, sdmAIDefault, 0, "AIDebugger::QueueDebugInformation ItemType=%d", ItemType); - AIDEBUGINFO di; - di.cbSize = sizeof(AIDEBUGINFO); - di.ItemType = ItemType; // int - di.Context = fcontext; // PWSTR - di.Rule = Rule; // LPKEY - di.Group = Group; // LPGROUP - di.Output = foutput; // PWSTR - di.Flags = dwExtraFlags; // DWORD - - if(di.Rule) FillStoreOffsets(&di); - - // data required - // keystroke - // context for rule - // if rule, then output of rule - // match positions for all stores in rule - - if(DebugControlled()) - SendMessage(GetDebugControlWindow(), WM_KEYMANDEBUG_RULEMATCH, ItemType, (LPARAM) &di); - - return TRUE; -} diff --git a/windows/src/engine/keyman32/appint/aiTIP.h b/windows/src/engine/keyman32/appint/aiTIP.h index 454943a0de..3c6fd9b698 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.h +++ b/windows/src/engine/keyman32/appint/aiTIP.h @@ -101,7 +101,6 @@ public: /* Queue and sending functions */ virtual BOOL SendActions(); // I4196 - virtual BOOL QueueDebugInformation(int ItemType, LPGROUP Group, LPKEY Rule, PWSTR fcontext, PWSTR foutput, DWORD_PTR dwExtraFlags); /* TIP interactions */ diff --git a/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp b/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp index 19da87a543..018b5c9509 100644 --- a/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp +++ b/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp @@ -166,17 +166,6 @@ BOOL AIWin2000Unicode::QueueAction(int ItemType, DWORD dwData) return result; } -BOOL AIWin2000Unicode::QueueDebugInformation(int ItemType, LPGROUP Group, LPKEY Rule, PWSTR fcontext, PWSTR foutput, DWORD_PTR dwExtraFlags) -{ - UNREFERENCED_PARAMETER(ItemType); - UNREFERENCED_PARAMETER(Group); - UNREFERENCED_PARAMETER(Rule); - UNREFERENCED_PARAMETER(fcontext); - UNREFERENCED_PARAMETER(foutput); - UNREFERENCED_PARAMETER(dwExtraFlags); - return TRUE; -} - // I1512 - SendInput with VK_PACKET for greater robustness BOOL AIWin2000Unicode::PostKeys() diff --git a/windows/src/engine/keyman32/appint/aiWin2000Unicode.h b/windows/src/engine/keyman32/appint/aiWin2000Unicode.h index 73db7ac907..1ee49ed001 100644 --- a/windows/src/engine/keyman32/appint/aiWin2000Unicode.h +++ b/windows/src/engine/keyman32/appint/aiWin2000Unicode.h @@ -1,18 +1,18 @@ /* Name: aiWin2000Unicode Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 27 Jan 2009 Modified Date: 23 Jun 2014 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 27 Jan 2009 - mcdurdin - I1797 - Add fallback for AIWin2000 app integration 11 Dec 2009 - mcdurdin - I934 - x64 - Initial version 24 Jun 2010 - mcdurdin - I2436 - Add space to context for AIWin2000Unicode when not matched @@ -43,7 +43,7 @@ public: virtual BOOL QueueAction(int ItemType, DWORD dwData); /* Information functions */ - + virtual BOOL CanHandleWindow(HWND ahwnd); virtual BOOL IsWindowHandled(HWND ahwnd); virtual BOOL HandleWindow(HWND ahwnd); @@ -59,9 +59,8 @@ public: virtual void SetContext(const WCHAR* buf); /* Queue and sending functions */ - + virtual BOOL SendActions(); // I4196 - virtual BOOL QueueDebugInformation(int ItemType, LPGROUP Group, LPKEY Rule, PWSTR fcontext, PWSTR foutput, DWORD_PTR dwExtraFlags); }; #endif diff --git a/windows/src/engine/keyman32/appint/appint.h b/windows/src/engine/keyman32/appint/appint.h index 77b20c3b01..6fe7ca7e20 100644 --- a/windows/src/engine/keyman32/appint/appint.h +++ b/windows/src/engine/keyman32/appint/appint.h @@ -43,22 +43,6 @@ typedef struct #define QIT_CAPSLOCK 8 #define QIT_INVALIDATECONTEXT 9 -// QueueDebugInformation ItemTypes -#define QID_BEGIN_UNICODE 0 -#define QID_BEGIN_ANSI 1 -#define QID_GROUP_ENTER 2 -#define QID_GROUP_EXIT 3 -#define QID_RULE_ENTER 4 -#define QID_RULE_EXIT 5 -#define QID_MATCH_ENTER 6 -#define QID_MATCH_EXIT 7 -#define QID_NOMATCH_ENTER 8 -#define QID_NOMATCH_EXIT 9 -#define QID_END 10 - -#define QID_FLAG_RECURSIVE_OVERFLOW 0x0001 -#define QID_FLAG_NOMATCH 0x0002 - #define QVK_EXTENDED 0x00010000 // Flag for QIT_VKEYDOWN to indicate an extended key #define QVK_KEYMASK 0x0000FFFF #define QVK_FLAGMASK 0xFFFF0000 @@ -205,7 +189,6 @@ public: /* Queue and sending functions */ - virtual BOOL QueueDebugInformation(int ItemType, LPGROUP Group, LPKEY Rule, PWSTR fcontext, PWSTR foutput, DWORD_PTR dwExtraFlags) = 0; void SetCurrentShiftState(int ShiftFlags) { FShiftFlags = ShiftFlags; } virtual BOOL SendActions() = 0; // I4196 }; diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index 142817bc6a..64a6a48e98 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -156,16 +156,6 @@ BOOL ProcessHook() Debug_VirtualKey(_td->state.vkey), getcontext_debug()); } - AIDEBUGKEYINFO keyinfo; - keyinfo.shiftFlags = Globals::get_ShiftState(); - keyinfo.VirtualKey = _td->state.vkey; - keyinfo.Character = _td->state.charCode; - keyinfo.DeadKeyCharacter = 0; // I4582 - keyinfo.IsUp = !_td->state.isDown; - if(_td->app->IsUnicode()) - _td->app->QueueDebugInformation(QID_BEGIN_UNICODE, NULL, NULL, NULL, NULL, (DWORD_PTR) &keyinfo); - else - _td->app->QueueDebugInformation(QID_BEGIN_ANSI, NULL, NULL, NULL, NULL, (DWORD_PTR) &keyinfo); } // For applications not using the TSF kmtip calls this function twice for each keystroke, @@ -246,7 +236,6 @@ BOOL ProcessHook() // PWSTR contextBuf = _td->app->ContextBufMax(MAXCONTEXT); // SendDebugMessageFormat(0, sdmAIDefault, 0, "Kmprocess::ProcessHook After cxt=%s", Debug_UnicodeString(contextBuf, 1)); - _td->app->QueueDebugInformation(QID_END, NULL, NULL, NULL, NULL, 0); return !fOutputKeystroke; } -- GitLab From 02a3b412229325aeaaf8e258476da44962c1641d Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Fri, 12 May 2023 08:37:32 -0500 Subject: [PATCH 086/214] Apply suggestions from code review Co-authored-by: Marc Durdin --- developer/src/kmc-kmn/src/compiler/compiler.ts | 18 ++++++++---------- developer/src/kmc-kmn/test/test-wasm-uset.ts | 1 - 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index be06f742dd..3cf0188b27 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -71,11 +71,11 @@ class WasmWrapper { this.parseUnicodeSet = this.Module.cwrap('kmcmp_Wasm_ParseUnicodeSet', 'number', ['string', 'number', 'number']); this.setCompilerOptions = this.Module.cwrap('kmcmp_Wasm_SetCompilerOptions', 'boolean', ['number']); - if (this.parseUnicodeSet == undefined - || this.setCompilerOptions == undefined - || this.compileKeyboardFile == undefined) { + if (this.parseUnicodeSet === undefined + || this.setCompilerOptions === undefined + || this.compileKeyboardFile === undefined) { throw Error(`some wasm functions did not load properly.`); - } + } } /** @@ -98,9 +98,7 @@ export class Compiler { } public async init(callbacks: CompilerCallbacks): Promise { - if(!this.callbacks) { - this.callbacks = callbacks; - } + this.callbacks = callbacks; if(!this.wasm) { try { this.wasm = await WasmWrapper.load(); @@ -109,14 +107,14 @@ export class Compiler { return false; } } - return this.verifyInitted(); + return this.verifyInitialized(); } /** * Verify that wasm is spun up OK. * @returns true if OK */ - public verifyInitted() : boolean { + public verifyInitialized() : boolean { if(!this.callbacks) { // Can't report a message here. throw Error('Must call Compiler.init(callbacks) before proceeding'); @@ -129,7 +127,7 @@ export class Compiler { } public run(infile: string, outfile: string, options?: CompilerOptions): boolean { - if(!this.verifyInitted()) { + if(!this.verifyInitialized()) { return false; } diff --git a/developer/src/kmc-kmn/test/test-wasm-uset.ts b/developer/src/kmc-kmn/test/test-wasm-uset.ts index bc4774f45b..5cc714eb40 100644 --- a/developer/src/kmc-kmn/test/test-wasm-uset.ts +++ b/developer/src/kmc-kmn/test/test-wasm-uset.ts @@ -15,7 +15,6 @@ describe('Compiler UnicodeSet function', function() { it('should compile a basic uset', async function() { const compiler = new Compiler(); - // const callbacks = new TestCompilerCallbacks(); const callbacks = new TestCompilerCallbacks(); assert(await compiler.init(callbacks)); assert(compiler.verifyInitted()); -- GitLab From e795287b93bd4c6704ffb639458262088eff0fda Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Fri, 12 May 2023 08:44:50 -0500 Subject: [PATCH 087/214] =?UTF-8?q?feat(developer):=20kmc-kmn:=20merge=20c?= =?UTF-8?q?onflict=20updates=20=F0=9F=99=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for: #7234 --- developer/src/kmc-kmn/src/compiler/compiler.ts | 2 +- developer/src/kmc-kmn/test/test-compiler.ts | 4 ++-- developer/src/kmc-kmn/test/test-wasm-uset.ts | 18 +++++++++--------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index 35a18cbc62..2f83e83aee 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -169,7 +169,7 @@ export class KmnCompiler { * @returns UnicodeSet accessor object, or null on failure */ public parseUnicodeSet(pattern: string, bufferSize: number) : UnicodeSet | null { - if(!this.verifyInitted()) { + if(!this.verifyInitialized()) { return null; } diff --git a/developer/src/kmc-kmn/test/test-compiler.ts b/developer/src/kmc-kmn/test/test-compiler.ts index 25b1abb8cf..2eacd219e6 100644 --- a/developer/src/kmc-kmn/test/test-compiler.ts +++ b/developer/src/kmc-kmn/test/test-compiler.ts @@ -25,7 +25,7 @@ describe('Compiler class', function() { }); it('should throw on failure', async function() { - const compiler = new Compiler(); + const compiler = new KmnCompiler(); const callbacks : any = null; // ERROR try { await compiler.init(callbacks) @@ -33,7 +33,7 @@ describe('Compiler class', function() { } catch(e) { assert.ok(e); } - assert.throws(() => compiler.verifyInitted()); + assert.throws(() => compiler.verifyInitialized()); }); it('should start', async function() { diff --git a/developer/src/kmc-kmn/test/test-wasm-uset.ts b/developer/src/kmc-kmn/test/test-wasm-uset.ts index 5cc714eb40..a63b408a95 100644 --- a/developer/src/kmc-kmn/test/test-wasm-uset.ts +++ b/developer/src/kmc-kmn/test/test-wasm-uset.ts @@ -1,23 +1,23 @@ import 'mocha'; import { assert } from 'chai'; -import { Compiler } from '../src/main.js'; +import { KmnCompiler } from '../src/main.js'; import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; import { CompilerMessages } from '../src/compiler/messages.js'; import { compilerErrorFormatCode } from '@keymanapp/common-types'; describe('Compiler UnicodeSet function', function() { it('should start', async function() { - const compiler = new Compiler(); + const compiler = new KmnCompiler(); const callbacks = new TestCompilerCallbacks(); assert(await compiler.init(callbacks)); - assert(compiler.verifyInitted()); + assert(compiler.verifyInitialized()); }); it('should compile a basic uset', async function() { - const compiler = new Compiler(); + const compiler = new KmnCompiler(); const callbacks = new TestCompilerCallbacks(); assert(await compiler.init(callbacks)); - assert(compiler.verifyInitted()); + assert(compiler.verifyInitialized()); const pat = "[abc]"; const set = compiler.parseUnicodeSet(pat, 23); @@ -27,10 +27,10 @@ describe('Compiler UnicodeSet function', function() { assert(set.ranges[0][1] === 'c'.charCodeAt(0)); }); it('should compile a more complex uset', async function() { - const compiler = new Compiler(); + const compiler = new KmnCompiler(); const callbacks = new TestCompilerCallbacks(); assert(await compiler.init(callbacks)); - assert(compiler.verifyInitted()); + assert(compiler.verifyInitialized()); const pat = "[[🙀A-C]-[CB]]"; const set = compiler.parseUnicodeSet(pat, 23); @@ -42,10 +42,10 @@ describe('Compiler UnicodeSet function', function() { assert.equal(set.ranges[1][1], 0x1F640); }); it('should fail in various ways', async function() { - const compiler = new Compiler(); + const compiler = new KmnCompiler(); const callbacks = new TestCompilerCallbacks(); assert(await compiler.init(callbacks)); - assert(compiler.verifyInitted()); + assert(compiler.verifyInitialized()); // map from string to failing error const failures = { '[:Adlm:]': CompilerMessages.ERROR_UnicodeSetHasProperties, // what it saye -- GitLab From 83615b9d6c649a0efaf946dda1c1695575453a54 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 12 May 2023 17:57:19 +0200 Subject: [PATCH 088/214] chore(linux): Fix installation build step on TC When building on TC we install into a temporary directory. This broke with the recent introduction of build.sh because that now calls `make install` whereas previously we explicitly called `make install-temp` on TC. Instead of adding a `install-temp` action to `build.sh` we now check in the Makefile if sudo is set. --- linux/keyman-config/Makefile | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/linux/keyman-config/Makefile b/linux/keyman-config/Makefile index b18b1f133d..41eaab30ef 100644 --- a/linux/keyman-config/Makefile +++ b/linux/keyman-config/Makefile @@ -6,7 +6,14 @@ default: clean version man langtags langtags: cd buildtools && python3 ./build-langtags.py -install: # run as sudo +install: + if [ -n "${SUDO_USER}" ]; then \ + make install-sudo; \ + else \ + make install-temp; \ + fi + +install-sudo: # run as sudo pip3 install qrcode sentry-sdk # eventually change this to: pip3 install . python3 setup.py install -- GitLab From db619deb66d0a0edf23d93e14bd9ffc2ff813ec9 Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Fri, 12 May 2023 14:02:41 -0400 Subject: [PATCH 089/214] auto: increment master version to 17.0.107 --- HISTORY.md | 10 ++++++++++ VERSION.md | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index b8e4bba32c..a90cd198d3 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,15 @@ # Keyman Version History +## 17.0.106 alpha 2023-05-12 + +* chore(developer): move package formats to common/web/types (#8729) +* feat(developer): add package validation (#8740) +* feat(developer): add validation of package filenames (#8751) +* feat(developer): validate content file names in packages (#8755) +* feat(developer): validate package name in compiler (#8757) +* chore(developer): rename Compiler and related classes (#8726) +* feat(developer): uset api from wasm! (#8716) + ## 17.0.105 alpha 2023-05-11 * chore(common): Update crowdin strings for Amharic (#8748) diff --git a/VERSION.md b/VERSION.md index 6c7991375d..58ff762bc8 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.106 \ No newline at end of file +17.0.107 \ No newline at end of file -- GitLab From 3c9492dd563c65f0af7f4b13676d95ce048dec91 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Sun, 14 May 2023 09:31:32 +0700 Subject: [PATCH 090/214] chore(developer): verify file types of content files in package This is a transfer of the functionality in the legacy package compiler; we could go much further in verifying file types and excluding certain files, but that's a big design session. For now, just refreshed to include the set of Keyman for Windows and Keyman Engine for Windows files which are most likely to be accidentally included. Adds WARN_RedistFileShouldNotBeInPackage and WARN_DocFileDangerous and corresponding unit tests and constant declarations. --- .../src/kmc-package/src/compiler/messages.ts | 8 +++ .../src/compiler/package-validation.ts | 18 ++++++ .../kmc-package/src/compiler/redist-files.ts | 64 +++++++++++++++++++ .../invalid/warn_doc_file_dangerous.kps | 38 +++++++++++ ...n_redist_file_should_not_be_in_package.kps | 38 +++++++++++ .../kmc-package/test/test-package-compiler.ts | 14 ++++ 6 files changed, 180 insertions(+) create mode 100644 developer/src/kmc-package/src/compiler/redist-files.ts create mode 100644 developer/src/kmc-package/test/fixtures/invalid/warn_doc_file_dangerous.kps create mode 100644 developer/src/kmc-package/test/fixtures/invalid/warn_redist_file_should_not_be_in_package.kps diff --git a/developer/src/kmc-package/src/compiler/messages.ts b/developer/src/kmc-package/src/compiler/messages.ts index 607af21eb9..af96301aad 100644 --- a/developer/src/kmc-package/src/compiler/messages.ts +++ b/developer/src/kmc-package/src/compiler/messages.ts @@ -98,5 +98,13 @@ export class CompilerMessages { static Error_MustHaveAtLeastOneLanguage = (o:{resourceType:string, id:string}) => m(this.ERROR_MustHaveAtLeastOneLanguage, `The ${o.resourceType} ${o.id} must have at least one language specified.`); static ERROR_MustHaveAtLeastOneLanguage = SevError | 0x0016; + + static Warn_RedistFileShouldNotBeInPackage = (o:{filename:string}) => m(this.WARN_RedistFileShouldNotBeInPackage, + `The Keyman system file '${o.filename}' should not be compiled into the package.`); + static WARN_RedistFileShouldNotBeInPackage = SevWarn | 0x0017; + + static Warn_DocFileDangerous = (o:{filename:string}) => m(this.WARN_DocFileDangerous, + `Microsoft Word .doc or .docx files ('${o.filename}') are not portable. You should instead use HTML or PDF format.`); + static WARN_DocFileDangerous = SevWarn | 0x0018; } diff --git a/developer/src/kmc-package/src/compiler/package-validation.ts b/developer/src/kmc-package/src/compiler/package-validation.ts index 96990f2097..f5a9c99313 100644 --- a/developer/src/kmc-package/src/compiler/package-validation.ts +++ b/developer/src/kmc-package/src/compiler/package-validation.ts @@ -1,5 +1,6 @@ import { KmpJsonFile, CompilerCallbacks } from '@keymanapp/common-types'; import { CompilerMessages } from './messages.js'; +import { keymanEngineForWindowsFiles, keymanForWindowsInstallerFiles, keymanForWindowsRedistFiles } from './redist-files.js'; // const SLexicalModelExtension = '.model.js'; @@ -142,6 +143,23 @@ export class PackageValidation { this.callbacks.reportMessage(CompilerMessages.Warn_FileInPackageDoesNotFollowFilenameConventions({filename})); } + if(!this.checkIfContentFileIsDangerous(file)) { + return false; + } + + return true; + } + + private checkIfContentFileIsDangerous(file: KmpJsonFile.KmpJsonFileContentFile): boolean { + let filename = this.callbacks.path.basename(file.name).toLowerCase(); + if(keymanForWindowsInstallerFiles.includes(filename) || + keymanForWindowsRedistFiles.includes(filename) || + keymanEngineForWindowsFiles.includes(filename)) { + this.callbacks.reportMessage(CompilerMessages.Warn_RedistFileShouldNotBeInPackage({filename})); + } + if(filename.match(/\.doc(x?)$/)) { + this.callbacks.reportMessage(CompilerMessages.Warn_DocFileDangerous({filename})); + } return true; } diff --git a/developer/src/kmc-package/src/compiler/redist-files.ts b/developer/src/kmc-package/src/compiler/redist-files.ts new file mode 100644 index 0000000000..9fccb32944 --- /dev/null +++ b/developer/src/kmc-package/src/compiler/redist-files.ts @@ -0,0 +1,64 @@ + +/** + * This is a set of known redistributable files for Keyman for Windows that + * should not be included in packages. It is not critical that this list matches + * the current deployment; it is just for warning against accidental inclusion + * of these files by package authors. Some redistributable files have been + * intentionally excluded because they could legitimately be a different file + * with the same name. + * + * This matches behaviour from the legacy package compiler; we may want to + * reconsider how this is done in the future. + * + * These lists have been constructed from 17.0.109 alpha build. Filenames + * intentionally in lower case. + */ + +export const + keymanForWindowsInstallerFiles: string[] = [ + 'keymandesktop.msi', + 'keymanengine.msm' + ]; + + +export const + keymanEngineForWindowsFiles: string[] = [ + 'base.xslt', + 'crashpad_handler.exe', + 'keyman-debug-etw.man', + 'keyman.exe', + 'keyman32.dll', + 'keyman64.dll', + 'keymanmc.dll', + 'keymanx64.exe', + 'kmcomapi.dll', + 'kmcomapi.x64.dll', + 'kmrefresh.x64.exe', + 'kmrefresh.x86.exe', + 'kmtip.dll', + 'kmtip64.dll', + 'mcompile.exe', + 'sentry.dll', + 'sentry.x64.dll', + 'si_browsers.xslt', + 'si_fonts.xslt', + 'si_hookdlls.xslt', + 'si_keyman.xslt', + 'si_language.xslt', + 'si_office.xslt', + 'si_overview.xslt', + 'si_processes.xslt', + 'si_processes_x64.xslt', + 'si_startup.xslt', + 'tsysinfo.exe', + ]; + +export const + keymanForWindowsRedistFiles: string[] = [ + 'desktop_resources.dll', + 'keymandesktop.chm', + 'kmbrowserhost.exe', + 'kmconfig.exe', + 'kmshell.exe', + 'unicodedata.mdb', + ]; diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_doc_file_dangerous.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_doc_file_dangerous.kps new file mode 100644 index 0000000000..045e14b740 --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_doc_file_dangerous.kps @@ -0,0 +1,38 @@ + + + + 15.0.266.0 + 7.0 + + + SENĆOŦEN (Saanich Dialect) Lexical Model + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.3 + + + + khmer_angkor.kmx + Keyboard Khmer Angkor + 0 + .kmx + + + + khmer_angkor.docx + Documentation + 0 + .docx + + + + + Khmer Angkor + khmer_angkor + 1.3 + + Khmer + + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_redist_file_should_not_be_in_package.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_redist_file_should_not_be_in_package.kps new file mode 100644 index 0000000000..1b5d1e246d --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_redist_file_should_not_be_in_package.kps @@ -0,0 +1,38 @@ + + + + 15.0.266.0 + 7.0 + + + SENĆOŦEN (Saanich Dialect) Lexical Model + © 2019 National Research Council Canada + Eddie Antonio Santos + 1.3 + + + + khmer_angkor.kmx + Keyboard Khmer Angkor + 0 + .kmx + + + + keyman.exe + Keyman Program + 0 + .exe + + + + + Khmer Angkor + khmer_angkor + 1.3 + + Khmer + + + + diff --git a/developer/src/kmc-package/test/test-package-compiler.ts b/developer/src/kmc-package/test/test-package-compiler.ts index 8a81d56b7c..1ccc8249f9 100644 --- a/developer/src/kmc-package/test/test-package-compiler.ts +++ b/developer/src/kmc-package/test/test-package-compiler.ts @@ -303,4 +303,18 @@ describe('KmpCompiler', function () { testForMessage(this, ['invalid', 'keyman.en.error_must_have_at_least_one_language.model.kps'], CompilerMessages.ERROR_MustHaveAtLeastOneLanguage); }); + + // WARN_RedistFileShouldNotBeInPackage + + it('should generate WARN_RedistFileShouldNotBeInPackage if package contains a redist file', async function() { + testForMessage(this, ['invalid', 'warn_redist_file_should_not_be_in_package.kps'], + CompilerMessages.WARN_RedistFileShouldNotBeInPackage); + }); + + // WARN_DocFileDangerous + + it('should generate WARN_DocFileDangerous if package contains a .doc file', async function() { + testForMessage(this, ['invalid', 'warn_doc_file_dangerous.kps'], + CompilerMessages.WARN_DocFileDangerous); + }); }); -- GitLab From abd174557c9e26bbb843357b263141ebc340b38e Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Sun, 14 May 2023 09:53:36 +0700 Subject: [PATCH 091/214] chore(developer): verify that package has at least a model or keyboard Adds `ERROR_PackageMustContainAPackageOrAKeyboard` and corresponding unit tests. A couple of unit tests tweaked as their fixtures were no longer valid! --- .../src/kmc-package/src/compiler/messages.ts | 4 ++++ .../src/compiler/package-validation.ts | 10 +++++++++ .../compiler/package-version-validation.ts | 2 +- .../source/binary_kvk_file.kps | 17 +++++++++++++++ ...e_must_contain_a_package_or_a_keyboard.kps | 21 +++++++++++++++++++ .../xml_kvk_file/source/xml_kvk_file.kps | 17 +++++++++++++++ .../kmc-package/test/test-package-compiler.ts | 7 +++++++ 7 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 developer/src/kmc-package/test/fixtures/invalid/error_package_must_contain_a_package_or_a_keyboard.kps diff --git a/developer/src/kmc-package/src/compiler/messages.ts b/developer/src/kmc-package/src/compiler/messages.ts index af96301aad..b179aa0ed1 100644 --- a/developer/src/kmc-package/src/compiler/messages.ts +++ b/developer/src/kmc-package/src/compiler/messages.ts @@ -106,5 +106,9 @@ export class CompilerMessages { static Warn_DocFileDangerous = (o:{filename:string}) => m(this.WARN_DocFileDangerous, `Microsoft Word .doc or .docx files ('${o.filename}') are not portable. You should instead use HTML or PDF format.`); static WARN_DocFileDangerous = SevWarn | 0x0018; + + static Error_PackageMustContainAPackageOrAKeyboard = () => m(this.ERROR_PackageMustContainAPackageOrAKeyboard, + `Package must contain a lexical model or a keyboard.`); + static ERROR_PackageMustContainAPackageOrAKeyboard = SevError | 0x0019; } diff --git a/developer/src/kmc-package/src/compiler/package-validation.ts b/developer/src/kmc-package/src/compiler/package-validation.ts index f5a9c99313..34bcc184b4 100644 --- a/developer/src/kmc-package/src/compiler/package-validation.ts +++ b/developer/src/kmc-package/src/compiler/package-validation.ts @@ -82,6 +82,16 @@ export class PackageValidation { return false; } + if(!kmpJson.lexicalModels?.length && !kmpJson.keyboards?.length) { + // Note: we require at least 1 keyboard or model in the package. This may + // change in the future if we start to use packages to distribute, e.g. + // localizations or themes. + this.callbacks.reportMessage(CompilerMessages.Error_PackageMustContainAPackageOrAKeyboard()); + return false; + } + + + return true; } diff --git a/developer/src/kmc-package/src/compiler/package-version-validation.ts b/developer/src/kmc-package/src/compiler/package-version-validation.ts index c240c77328..3c15cc006b 100644 --- a/developer/src/kmc-package/src/compiler/package-version-validation.ts +++ b/developer/src/kmc-package/src/compiler/package-version-validation.ts @@ -55,7 +55,7 @@ export class PackageVersionValidation { this.callbacks.reportMessage(CompilerMessages.Warn_KeyboardVersionsDoNotMatchPackageVersion({ keyboard: kmp.keyboards[0].id, keyboardVersion: kmp.keyboards[0].version, - packageVersion: kmp.info.version.description + packageVersion: kmp.info.version?.description })); } } diff --git a/developer/src/kmc-package/test/fixtures/binary_kvk_file/source/binary_kvk_file.kps b/developer/src/kmc-package/test/fixtures/binary_kvk_file/source/binary_kvk_file.kps index d98764ea86..a95f5c6fe1 100644 --- a/developer/src/kmc-package/test/fixtures/binary_kvk_file/source/binary_kvk_file.kps +++ b/developer/src/kmc-package/test/fixtures/binary_kvk_file/source/binary_kvk_file.kps @@ -17,6 +17,7 @@ Binary KVK File + 1.3 @@ -25,5 +26,21 @@ 0 .kvk + + ../../invalid/khmer_angkor.kmx + Keyboard Khmer Angkor + 0 + .kmx + + + + Khmer Angkor + khmer_angkor + 1.3 + + Khmer + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_package_must_contain_a_package_or_a_keyboard.kps b/developer/src/kmc-package/test/fixtures/invalid/error_package_must_contain_a_package_or_a_keyboard.kps new file mode 100644 index 0000000000..cf225de26a --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/error_package_must_contain_a_package_or_a_keyboard.kps @@ -0,0 +1,21 @@ + + + + 15.0.266.0 + 7.0 + + + error_package_must_contain_a_package_or_a_keyboard + 1.3 + + + + + khmer_angkor.kmn + Keyboard Khmer Angkor + 0 + .kmn + + + diff --git a/developer/src/kmc-package/test/fixtures/xml_kvk_file/source/xml_kvk_file.kps b/developer/src/kmc-package/test/fixtures/xml_kvk_file/source/xml_kvk_file.kps index f89e1dfd7a..9378181ad1 100644 --- a/developer/src/kmc-package/test/fixtures/xml_kvk_file/source/xml_kvk_file.kps +++ b/developer/src/kmc-package/test/fixtures/xml_kvk_file/source/xml_kvk_file.kps @@ -17,6 +17,7 @@ XML KVK File + 1.3 @@ -25,5 +26,21 @@ 0 .kvk + + ../../invalid/khmer_angkor.kmx + Keyboard Khmer Angkor + 0 + .kmx + + + + Khmer Angkor + khmer_angkor + 1.3 + + Khmer + + + diff --git a/developer/src/kmc-package/test/test-package-compiler.ts b/developer/src/kmc-package/test/test-package-compiler.ts index 1ccc8249f9..57a97897ca 100644 --- a/developer/src/kmc-package/test/test-package-compiler.ts +++ b/developer/src/kmc-package/test/test-package-compiler.ts @@ -317,4 +317,11 @@ describe('KmpCompiler', function () { testForMessage(this, ['invalid', 'warn_doc_file_dangerous.kps'], CompilerMessages.WARN_DocFileDangerous); }); + + // ERROR_PackageMustContainAPackageOrAKeyboard + + it('should generate ERROR_PackageMustContainAPackageOrAKeyboard if package contains a .doc file', async function() { + testForMessage(this, ['invalid', 'error_package_must_contain_a_package_or_a_keyboard.kps'], + CompilerMessages.ERROR_PackageMustContainAPackageOrAKeyboard); + }); }); -- GitLab From c1439759ca34e69ec97236718ef5dbf7a75f494f Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 25 Nov 2022 19:31:55 +0700 Subject: [PATCH 092/214] chore: temp step 1 of ts kmw --- common/windows/cpp/include/legacy_kmx_file.h | 3 +- .../src/common/delphi/compiler/compile.pas | 28 +- developer/src/kmc-kmw/Makefile | 39 ++ developer/src/kmc-kmw/build.sh | 73 ++++ developer/src/kmc-kmw/package.json | 54 +++ .../src/kmc-kmw/src/compiler/callbacks.ts | 11 + .../kmc-kmw/src/compiler/compiler-options.ts | 13 + .../src/compiler/keymanweb-compiler.ts | 82 ++++ .../src/kmc-kmw/src/compiler/messages.ts | 97 +++++ .../src/compiler/write-compiled-keyboard.ts | 408 ++++++++++++++++++ developer/src/kmc-kmw/src/main.ts | 2 + developer/src/kmc-kmw/src/util/util.ts | 7 + developer/src/kmc-kmw/tsconfig.json | 25 ++ developer/src/kmcmpdll/Compiler.cpp | 7 +- developer/src/kmcomp/kmcomp.dproj | 2 +- .../src/tike/compile/CompileKeymanWeb.pas | 35 ++ 16 files changed, 882 insertions(+), 4 deletions(-) create mode 100644 developer/src/kmc-kmw/Makefile create mode 100755 developer/src/kmc-kmw/build.sh create mode 100644 developer/src/kmc-kmw/package.json create mode 100644 developer/src/kmc-kmw/src/compiler/callbacks.ts create mode 100644 developer/src/kmc-kmw/src/compiler/compiler-options.ts create mode 100644 developer/src/kmc-kmw/src/compiler/keymanweb-compiler.ts create mode 100644 developer/src/kmc-kmw/src/compiler/messages.ts create mode 100644 developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts create mode 100644 developer/src/kmc-kmw/src/main.ts create mode 100644 developer/src/kmc-kmw/src/util/util.ts create mode 100644 developer/src/kmc-kmw/tsconfig.json diff --git a/common/windows/cpp/include/legacy_kmx_file.h b/common/windows/cpp/include/legacy_kmx_file.h index ae18543312..4aca74ed3d 100644 --- a/common/windows/cpp/include/legacy_kmx_file.h +++ b/common/windows/cpp/include/legacy_kmx_file.h @@ -416,7 +416,8 @@ typedef COMPILER_OPTIONS *PCOMPILER_OPTIONS; typedef int (CALLBACK *CompilerMessageProc)(int line, DWORD dwMsgCode, LPSTR szText); -//extern "C" BOOL __declspec(dllexport) CompileKeyboardFile(PSTR pszInfile, PSTR pszOutfile, BOOL FSaveDebug, BOOL ACompilerWarningsAsErrors, BOOL AWarnDeprecatedCode, CompilerMessageProc pMsgProc); // I4865 // I4866 +extern "C" BOOL __declspec(dllexport) CompileKeyboardFile(PSTR pszInfile, PSTR pszOutfile, BOOL FSaveDebug, BOOL ACompilerWarningsAsErrors, BOOL AWarnDeprecatedCode, CompilerMessageProc pMsgProc); // I4865 // I4866 +extern "C" BOOL __declspec(dllexport) CompileKeyboardFileEx(PSTR pszInfile, PSTR pszOutfile, BOOL ASaveDebug, BOOL ACompilerWarningsAsErrors, BOOL AWarnDeprecatedCode, CompilerMessageProc pMsgProc, int Target); #endif // _COMPILER_H diff --git a/developer/src/common/delphi/compiler/compile.pas b/developer/src/common/delphi/compiler/compile.pas index 9b304b39d8..9ebea18ad2 100644 --- a/developer/src/common/delphi/compiler/compile.pas +++ b/developer/src/common/delphi/compiler/compile.pas @@ -167,6 +167,7 @@ const function CompileKeyboardFile(kmnFile, kmxFile: PChar; FSaveDebug, CompilerWarningsAsErrors, WarnDeprecatedCode: BOOL; CallBack: TCompilerCallback): Integer; cdecl; // I4865 // I4866 function CompileKeyboardFileToBuffer(kmnFile: PChar; buf: PFILE_KEYBOARD; CompilerWarningsAsErrors, WarnDeprecatedCode: BOOL; CallBack: TCompilerCallback; Target: Integer): Integer; cdecl; // I4865 // I4866 +function CompileKeyboardFileEx(kmnFile, kmxfile: PChar; FSaveDebug, CompilerWarningsAsErrors, WarnDeprecatedCode: BOOL; CallBack: TCompilerCallback; Target: Integer): Integer; // I4865 // I4866 function Compiler_Diagnostic(mode: Integer): Integer; procedure Compiler_Diagnostic_Console(mode: Integer); @@ -200,13 +201,18 @@ var HKMCmpDll: THandle = 0; type - TCompileKeyboardFile = function (kmnFile, kmxFile: PAnsiChar; FSaveDebug, CompilerWarningsAsErrors, WarnDeprecatedCode: BOOL; // I3310 // I4865 // I4866 + TCompileKeyboardFile = function (kmnFile, kmxFile: PAnsiChar; + FSaveDebug, CompilerWarningsAsErrors, WarnDeprecatedCode: BOOL; // I3310 // I4865 // I4866 CallBack: TCompilerCallback): Integer; cdecl; // TODO: K9: Convert to Unicode TCompileKeyboardFileToBuffer = function (kmnFile: PAnsiChar; buf: PFILE_KEYBOARD; // I3310 CompilerWarningsAsErrors, WarnDeprecatedCode: BOOL; // I4865 // I4866 CallBack: TCompilerCallback; Target: Integer): Integer; cdecl; // TODO: K9: Convert to Unicode + TCompileKeyboardFileEx = function (kmnFile, kmxFile: PAnsiChar; + FSaveDebug, CompilerWarningsAsErrors, WarnDeprecatedCode: BOOL; + CallBack: TCompilerCallback; Target: Integer): Integer; cdecl; // TODO: K9: Convert to Unicode + TSetCompilerOptions = function (options: PCOMPILER_OPTIONS): BOOL; cdecl; function LoadCompiler(CallBack: TCompilerCallback = nil): Boolean; @@ -303,6 +309,26 @@ begin Result := ckf(PAnsiChar(AnsiString(kmnFile)), buf, CompilerWarningsAsErrors, WarnDeprecatedCode, Callback, Target); // I3310 // I4865 // I4866 end; +function CompileKeyboardFileEx(kmnFile, kmxfile: PChar; FSaveDebug, CompilerWarningsAsErrors, WarnDeprecatedCode: BOOL; CallBack: TCompilerCallback; Target: Integer): Integer; // I4865 // I4866 +var + ckf: TCompileKeyboardFileEx; +begin + //Result := 0; + + if not LoadCompiler(Callback) then Exit(-1); + + @ckf := GetProcAddress(HKMCmpDll, 'CompileKeyboardFileEx'); + if not Assigned(@ckf) then + begin + Callback(0, $8000, PAnsiChar(AnsiString('Could not access the compiler. Check that '+kmcmpdll_lib+' is in the program directory '+ // I4706 + 'and that it is not corrupt.'#13#10+'Windows error message: '+SysErrorMessage(GetLastError)))); + Result := -1; + Exit; + end; + + Result := ckf(PAnsiChar(AnsiString(kmnFile)), PAnsiChar(AnsiString(kmxfile)), FSaveDebug, CompilerWarningsAsErrors, WarnDeprecatedCode, Callback, Target); // I3310 // I4865 // I4866 +end; + type TKeyman_Diagnostic = procedure(mode: Integer); cdecl; diff --git a/developer/src/kmc-kmw/Makefile b/developer/src/kmc-kmw/Makefile new file mode 100644 index 0000000000..c9ae1e81a6 --- /dev/null +++ b/developer/src/kmc-kmw/Makefile @@ -0,0 +1,39 @@ +# +# Keyman Developer - kmc KMW Keyboard Compiler Makefile +# + +!include ..\Defines.mak + +# We do configure here because parent Makefile calls this first; other +# kmc and kmc-* makefiles don't do it +build: configure .virtual + $(GIT_BASH_FOR_KEYMAN) build.sh build + +configure: .virtual + $(GIT_BASH_FOR_KEYMAN) build.sh configure + +clean: .virtual + $(GIT_BASH_FOR_KEYMAN) build.sh clean + +test: .virtual + $(GIT_BASH_FOR_KEYMAN) build.sh test + +# build.sh bundle must be run from shell as it requires a temp folder to be +# passed in. See inst/download.in.mak for instantiation. + +publish: .virtual + $(GIT_BASH_FOR_KEYMAN) build.sh publish + +signcode: + @rem nothing to do + +wrap-symbols: + @rem nothing to do + +test-manifest: + @rem nothing to do + +install: + @rem nothing to do + +!include ..\Target.mak diff --git a/developer/src/kmc-kmw/build.sh b/developer/src/kmc-kmw/build.sh new file mode 100755 index 0000000000..684f5f7911 --- /dev/null +++ b/developer/src/kmc-kmw/build.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +# +# Compiles the kmc KeymanWeb keyboard compiler. +# + +# Exit on command failure and when using unset variables: +set -eu + +## START STANDARD BUILD SCRIPT INCLUDE +# adjust relative paths as necessary +THIS_SCRIPT="$(greadlink -f "${BASH_SOURCE[0]}" 2>/dev/null || readlink -f "${BASH_SOURCE[0]}")" +. "$(dirname "$THIS_SCRIPT")/../../../resources/build/build-utils.sh" +## END STANDARD BUILD SCRIPT INCLUDE + +cd "$THIS_SCRIPT_PATH" + +. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh" + +builder_describe "Build Keyman kmc KMW Keyboard Compiler module" \ + "@/common/web/keyman-version" \ + "@/common/web/types" \ + "configure" \ + "build" \ + "clean" \ + "test" \ + "publish publish to npm" \ + "--dry-run,-n don't actually publish, just dry run" +builder_describe_outputs \ + configure /node_modules \ + build build/src/main.js + +builder_parse "$@" + +#------------------------------------------------------------------------------------------------------------------- + +if builder_start_action clean; then + rm -rf ./build/ ./tsconfig.tsbuildinfo + builder_finish_action success clean +else + # We need the schema file at runtime and bundled, so always copy it for all actions except `clean` + mkdir -p "$THIS_SCRIPT_PATH/build/src/" + cp "$KEYMAN_ROOT/common/schemas/keyman-touch-layout/keyman-touch-layout.spec.json" "$THIS_SCRIPT_PATH/build/src/" + cp "$KEYMAN_ROOT/common/schemas/kvks/kvks.schema.json" "$THIS_SCRIPT_PATH/build/src/" +fi + +#------------------------------------------------------------------------------------------------------------------- + +if builder_start_action configure; then + verify_npm_setup + builder_finish_action success configure +fi + +#------------------------------------------------------------------------------------------------------------------- + +if builder_start_action build; then + npm run build + builder_finish_action success build +fi + +#------------------------------------------------------------------------------------------------------------------- + +if builder_start_action test; then + npm test + builder_finish_action success test +fi + +#------------------------------------------------------------------------------------------------------------------- + +if builder_start_action publish; then + . "$KEYMAN_ROOT/resources/build/npm-publish.inc.sh" + npm_publish + builder_finish_action success publish +fi diff --git a/developer/src/kmc-kmw/package.json b/developer/src/kmc-kmw/package.json new file mode 100644 index 0000000000..e41821bf22 --- /dev/null +++ b/developer/src/kmc-kmw/package.json @@ -0,0 +1,54 @@ +{ + "name": "@keymanapp/kmc-kmw", + "description": "Keyman Developer KMW keyboard compiler", + "keywords": [ + "keyboard", + "keyman", + "ldml", + "unicode" + ], + "type": "module", + "exports": { + ".": "./build/src/main.js" + }, + "scripts": { + "build": "tsc -b", + "test": "cd test && tsc -b && cd .. && c8 mocha", + "prepublishOnly": "npm run build" + }, + "author": "Marc Durdin (https://github.com/mcdurdin)", + "license": "MIT", + "bugs": { + "url": "https://github.com/keymanapp/keyman/issues" + }, + "dependencies": { + "@keymanapp/keyman-version": "*", + "ajv": "^8.11.0", + "restructure": "git+https://github.com/keymanapp/dependency-restructure.git#49d129cf0916d082a7278bb09296fb89cecfcc50", + "semver": "^7.3.7", + "xml2js": "git+https://github.com/keymanapp/dependency-node-xml2js#535fe732dc408d697e0f847c944cc45f0baf0829" + }, + "devDependencies": { + "@types/chai": "^4.1.7", + "@types/mocha": "^5.2.7", + "@types/node": "^10.14.6", + "@types/semver": "^7.3.12", + "@types/xml2js": "^0.4.5", + "c8": "^7.12.0", + "chai": "^4.3.4", + "chalk": "^2.4.2", + "mocha": "^8.4.0", + "ts-node": "^9.1.1", + "typescript": "4.6.3" + }, + "mocha": { + "spec": "build/test/**/test-*.js", + "require": [ + "source-map-support/register" + ] + }, + "repository": { + "type": "git", + "url": "git+https://github.com/keymanapp/keyman.git" + } +} diff --git a/developer/src/kmc-kmw/src/compiler/callbacks.ts b/developer/src/kmc-kmw/src/compiler/callbacks.ts new file mode 100644 index 0000000000..f6cd673b56 --- /dev/null +++ b/developer/src/kmc-kmw/src/compiler/callbacks.ts @@ -0,0 +1,11 @@ +export interface CompilerEvent { + code: number; + message: string; +}; + +export default interface CompilerCallbacks { + loadFile(baseFilename: string, filename: string): Buffer; + loadLdmlKeyboardSchema(): Buffer; + loadKvksJsonSchema(): Buffer; + reportMessage(event: CompilerEvent): void; +}; diff --git a/developer/src/kmc-kmw/src/compiler/compiler-options.ts b/developer/src/kmc-kmw/src/compiler/compiler-options.ts new file mode 100644 index 0000000000..76dd4b5ba4 --- /dev/null +++ b/developer/src/kmc-kmw/src/compiler/compiler-options.ts @@ -0,0 +1,13 @@ + + +export default interface CompilerOptions { + /** + * Add debug information to the .kmx file when compiling + */ + debug: boolean; + + /** + * Add metadata about the compiler version to .kmx file when compiling + */ + addCompilerVersion: boolean; +}; diff --git a/developer/src/kmc-kmw/src/compiler/keymanweb-compiler.ts b/developer/src/kmc-kmw/src/compiler/keymanweb-compiler.ts new file mode 100644 index 0000000000..03fc953e3f --- /dev/null +++ b/developer/src/kmc-kmw/src/compiler/keymanweb-compiler.ts @@ -0,0 +1,82 @@ +import { VisualKeyboard } from "@keymanapp/common-types"; + +import * as path from 'path'; +import { KMXFile } from "../../../../../common/web/types/src/kmx/kmx"; +// import VisualKeyboardCompiler from "./visual-keyboard-compiler.js"; + +export interface KeymanWebCompilerOptions { + debug?: boolean; +}; + +export class KeymanWebCompiler { + private readonly options: KeymanWebCompilerOptions; + private readonly nl: string; + private readonly tab: string; + + constructor(options?: KeymanWebCompilerOptions) { + this.options = options; + this.nl = this.options.debug ? "\n" : ''; + this.tab = this.options.debug ? " " : ''; + } + + public compile(name: string, source: KMXFile): string { + const nl = this.nl, tab = this.tab; + + // TODO: fill in from CompileKeymanWeb.pas + + const sName = 'Keyboard_'+this.cleanName(name); + const displayUnderlying = true; // TODO-LDML + const modifierBitmask = 0; // TODO-LDML: define the modifiers used by this keyboard + const vkDictionary = ''; // TODO-LDML: vk dictionary for touch keys + const hasSupplementaryPlaneChars = false; // TODO-LDML + const isRTL = false; // TODO-LDML + + let result = + `if(typeof keyman === 'undefined') {${nl}` + + `${tab}console.error('Keyboard requires KeymanWeb ${MINIMUM_KMW_VERSION} or later');${nl}` + + `} else {${nl}` + + `${tab}KeymanWeb.KR(new ${sName}());${nl}` + + `}${nl}` + + `function ${sName}() {${nl}` + + // `${tab}${this.setupDebug()}${nl}` + ? we may use this for modifierBitmask in future + // `${tab}this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9;${nl}` + ? we probably don't need this, it's for back-compat + `${tab}this.KI="${sName}";${nl}` + + `${tab}this.KN=${JSON.stringify(source.keyboard.names.name[0])};${nl}` + + `${tab}this.KMINVER=${JSON.stringify(MINIMUM_KMW_VERSION)};${nl}` + + `${tab}this.KV=${this.compileVisualKeyboard(source)};${nl}` + + `${tab}this.KDU=${displayUnderlying ? '1' : '0'};${nl}` + + `${tab}this.KH="";${nl}` + // TODO-LDML: help text not supported + `${tab}this.KM=0;${nl}` + // TODO-LDML: mnemonic layout not supported for LDML keyboards + `${tab}this.KBVER=${JSON.stringify(source.keyboard.version.number)};${nl}` + + `${tab}this.KMBM=${modifierBitmask};${nl}`; + + if(isRTL) { + result += `${tab}this.KRTL=1;${nl}`; + } + + if(hasSupplementaryPlaneChars) { + result += `${tab}this.KS=1;${nl}`; + } + + if(vkDictionary != '') { + result += `${tab}this.KVKD=${JSON.stringify(vkDictionary)};${nl}`; + } + + let layoutFile = this.compileTouchLayout(source); + if(layoutFile != '') { + result += `${tab}this.KVKL=${layoutFile};${nl}`; + } + // TODO-LDML: KCSS not supported + + // TODO-LDML: embed binary keyboard for loading into Core + + // A LDML keyboard has a no-op for its gs() (begin Unicode) function, + // because the functionality is embedded in Keyman Core + result += `${tab}this.gs=function(t,e){${nl}`+ + `${tab}${tab}return 0;${nl}`+ // TODO-LDML: we will start by embedding call into Keyman Core here + `${tab}};${nl}`; + + result += `}${nl}`; + return result; + } +} \ No newline at end of file diff --git a/developer/src/kmc-kmw/src/compiler/messages.ts b/developer/src/kmc-kmw/src/compiler/messages.ts new file mode 100644 index 0000000000..0a6801f9d2 --- /dev/null +++ b/developer/src/kmc-kmw/src/compiler/messages.ts @@ -0,0 +1,97 @@ + +export enum CompilerErrorSeverity { + Info = 0x000000, + Hint = 0x100000, + Warn = 0x200000, + Error = 0x300000, + Fatal = 0x400000, + Severity_Mask = 0xF00000, // includes reserved bits + Error_Mask = 0x0FFFFF, +}; + +const m = (code: number, message: string) => { return { code, message } }; +const SevInfo = CompilerErrorSeverity.Info; +const SevHint = CompilerErrorSeverity.Hint; +// const SevWarn = CompilerErrorSeverity.Warn; +const SevError = CompilerErrorSeverity.Error; +const SevFatal = CompilerErrorSeverity.Fatal; + +export class CompilerMessages { + static Error_InvalidNormalization = (o:{form: string}) => m(this.ERROR_InvalidNormalization, `Invalid normalization form '${o.form}`); + static ERROR_InvalidNormalization = SevError | 0x0001; + + static Error_InvalidLocale = (o:{tag: string}) => m(this.ERROR_InvalidLocale, `Invalid BCP 47 locale form '${o.tag}'`); + static ERROR_InvalidLocale = SevError | 0x0002; + + static Error_HardwareLayerHasTooManyRows = () => m(this.ERROR_HardwareLayerHasTooManyRows, `'hardware' layer has too many rows`); + static ERROR_HardwareLayerHasTooManyRows = SevError | 0x0003; + + static Error_RowOnHardwareLayerHasTooManyKeys = (o:{row: number}) => m(this.ERROR_RowOnHardwareLayerHasTooManyKeys, `Row #${o.row} on 'hardware' layer has too many keys`); + static ERROR_RowOnHardwareLayerHasTooManyKeys = SevError | 0x0004; + + static Error_KeyNotFoundInKeyBag = (o:{keyId: string, col: number, row: number, layer: string, form: string}) => + m(this.ERROR_KeyNotFoundInKeyBag, `Key '${o.keyId}' in position #${o.col} on row #${o.row} of layer ${o.layer}, form '${o.form}' not found in key bag`); + static ERROR_KeyNotFoundInKeyBag = SevError | 0x0005; + + static Hint_OneOrMoreRepeatedLocales = () => + m(this.HINT_OneOrMoreRepeatedLocales, `After minimization, one or more locales is repeated and has been removed`); + static HINT_OneOrMoreRepeatedLocales = SevHint | 0x0006; + + static Error_InvalidFile = (o:{errorText: string}) => + m(this.ERROR_InvalidFile, `The source file has an invalid structure: ${o.errorText}`); + static ERROR_InvalidFile = SevError | 0x0007; + + static Hint_LocaleIsNotMinimalAndClean = (o:{sourceLocale: string, locale: string}) => + m(this.HINT_LocaleIsNotMinimalAndClean, `Locale '${o.sourceLocale}' is not minimal or correctly formatted and should be '${o.locale}'`); + static HINT_LocaleIsNotMinimalAndClean = SevHint | 0x0008; + + static Error_VkeyIsNotValid = (o:{vkey: string}) => + m(this.ERROR_VkeyIsNotValid, `Virtual key '${o.vkey}' is not found in the CLDR VKey Enum table.`); + static ERROR_VkeyIsNotValid = SevError | 0x0009; + + static Hint_VkeyIsRedundant = (o:{vkey: string}) => + m(this.HINT_VkeyIsRedundant, `Virtual key '${o.vkey}' is mapped to itself, which is redundant.`); + static HINT_VkeyIsRedundant = SevHint | 0x000A; + + static Error_VkeyIsRepeated = (o:{vkey: string}) => + m(this.ERROR_VkeyIsRepeated, `Virtual key '${o.vkey}' has more than one vkey entry.`); + static ERROR_VkeyIsRepeated = SevError | 0x000B; + + static Info_MultipleVkeysHaveSameTarget = (o:{vkey: string}) => + m(this.INFO_MultipleVkeysHaveSameTarget, `Target virtual key '${o.vkey}' has multiple source mappings, which may be an error.`); + static INFO_MultipleVkeysHaveSameTarget = SevInfo | 0x000C; + + static Error_InvalidVersion = (o:{version: string}) => + m(this.ERROR_InvalidVersion, `Version number '${o.version}' must be a semantic version format string.`); + static ERROR_InvalidVersion = SevError | 0x000D; + + static Error_MustBeAtLeastOneLayerElement = () => + m(this.ERROR_MustBeAtLeastOneLayerElement, `The source file must contain at least one layer element.`); + static ERROR_MustBeAtLeastOneLayerElement = SevError | 0x000E; + + static Fatal_SectionCompilerFailed = (o:{sect: string}) => + m(this.FATAL_SectionCompilerFailed, `The compiler for '${o.sect}' failed unexpectedly.`); + static FATAL_SectionCompilerFailed = SevFatal | 0x000F; + + static Error_DisplayIsRepeated = (o:{to: string}) => + m(this.ERROR_DisplayIsRepeated, `display to='${o.to}' has more than one display entry.`); + static ERROR_DisplayIsRepeated = SevError | 0x0010; + + static Error_KeyMissingToGapOrSwitch = (o:{keyId: string}) => + m(this.ERROR_KeyMissingToGapOrSwitch, `key id='${o.keyId}' must have either to=, gap=, or switch=.`); +static ERROR_KeyMissingToGapOrSwitch = SevError | 0x0011; + + static severityName(code: number): string { + let severity = code & CompilerErrorSeverity.Severity_Mask; + switch(severity) { + case CompilerErrorSeverity.Info: return 'INFO'; + case CompilerErrorSeverity.Hint: return 'HINT'; + case CompilerErrorSeverity.Warn: return 'WARN'; + case CompilerErrorSeverity.Error: return 'ERROR'; + case CompilerErrorSeverity.Fatal: return 'FATAL'; + /* istanbul ignore next */ + default: return 'UNKNOWN'; + } + } +} + diff --git a/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts b/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts new file mode 100644 index 0000000000..603b2be784 --- /dev/null +++ b/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts @@ -0,0 +1,408 @@ +import { GROUP, KEY, KMXFile, STORE } from "../../../../../common/web/types/src/kmx/kmx"; + +function requote(s: string): string { + return "'" + s.replaceAll(/(['\\])/, "\\$1") + "'"; +} + +export function WriteCompiledKeyboard(source: KMXFile): string { + // let fgp: GROUP; + let fsp: STORE; + let fkp: KEY; + + let j: number; + let n: number; + + let vMnemonic: number = 0; + let s: string, sRTL: string = "", sHelp: string = "''", sHelpFile: string = "", + sEmbedJS: string = "", sEmbedCSS: string = ""; + let sVisualKeyboard: string = "", sFullName: string = ""; + let sBegin_NewContext: string, sBegin_PostKeystroke: string; + let sLayoutFile: string = "", sVKDictionary: string; + let linecomment: string; // I3438 + let HasRules: boolean; + let sModifierBitmask: string; + let FOptionStores: string; + let FKeyboardVersion = "1.0"; + // let rec: TSentinelRecord; + + let result = ""; + // Locate the name of the keyboard + for(let i = 0; i < source.keyboard.stores.length; i++) { + const fsp = source.keyboard.stores[i]; + if(fsp.dwSystemID == KMXFile.TSS_NAME) { + sFullName = fsp.dpString; + } + else if(fsp.dwSystemID == KMXFile.TSS_KEYBOARDVERSION) { // I4155 + FKeyboardVersion = fsp.dpString; + } + else if (fsp.dpName == 'HelpFile' || fsp.dwSystemID == KMXFile.TSS_KMW_HELPFILE) { + sHelpFile = fsp.dpString; + } + else if (fsp.dpName == 'Help' || fsp.dwSystemID == KMXFile.TSS_KMW_HELPTEXT) { + sHelp = '"'+RequotedString(fsp.dpString)+'"'; + } + else if (fsp.dpName == 'VisualKeyboard' || fsp.dwSystemID == KMXFile.TSS_VISUALKEYBOARD) { + sVisualKeyboard = fsp.dpString; + } + else if (fsp.dpName == 'EmbedJS' || fsp.dwSystemID == KMXFile.TSS_KMW_EMBEDJS) { + sEmbedJS = fsp.dpString; + } + else if (fsp.dpName == 'EmbedCSS' || fsp.dwSystemID == KMXFile.TSS_KMW_EMBEDCSS) { // I4368 + sEmbedCSS = fsp.dpString; + } + else if (fsp.dpName == 'RTL' || fsp.dwSystemID == KMXFile.TSS_KMW_RTL) { + sRTL = fsp.dpString == '1' ? FTabStop+'this.KRTL=1;'+nl : ''; // I3681 + } + else if (fsp.dwSystemID == KMXFile.TSS_MNEMONIC) { + vMnemonic = fsp.dpString == '1' ? 1 : 0; + } + else if (fsp.dwSystemID == KMXFile.TSS_VKDICTIONARY) { // I3438 + sVKDictionary = fsp.dpString; + } + else if (fsp.dwSystemID == KMXFile.TSS_LAYOUTFILE) { // I3483 + sLayoutFile = fsp.dpString; + } + else if (fsp.dwSystemID == KMXFile.TSS_BEGIN_NEWCONTEXT) { + sBegin_NewContext = fsp.dpString; + } + else if (fsp.dwSystemID -= KMXFile.TSS_BEGIN_POSTKEYSTROKE) { + sBegin_PostKeystroke = fsp.dpString; + } + } + + const sName = 'Keyboard_'+TKeyboardUtils.GetKeymanWebCompiledNameFromFileName(FInFile); + + if (sHelpFile != '') { + sHelp = ''; + //TODO: load sHelpFile from file + /*with TStringList.Create do + try + try + LoadFromFile(ExtractFilePath(FInFile) + sHelpFile, TEncoding.UTF8); // I3337 + for n := 0 to Count - 1 do + sHelp := sHelp + Strings[n] + ' '; + except + on E:EFOpenError do + begin + ReportError(0, CWARN_HelpFileMissing, E.Message); // I1971 // I4061 + sHelp := ''; + end; + end; + finally + Free; + end;*/ + + sHelp = requote(sHelp); + } + + if (sEmbedJS != '') { + //TODO: load sEmbedJS from file + /*try + with TStringList.Create do + try + LoadFromFile(ExtractFilePath(FInFile) + sEmbedJS, TEncoding.UTF8); // I3337 + sEmbedJS := Text; + finally + Free; + end; + except + on E:EFOpenError do // I3683 + begin + ReportError(0, CWARN_EmbedJsFileMissing, E.Message); // I4061 + sEmbedJS := ''; + end; + end;*/ + } + + if (sEmbedCSS != '') { // I4368 + //TODO: load sEmbedCSS from file + /*try + with TStringList.Create do + try + LoadFromFile(ExtractFilePath(FInFile) + sEmbedCSS, TEncoding.UTF8); // I3337 + sEmbedCSS := Text; + finally + Free; + end; + except + on E:EFOpenError do // I3683 + begin + ReportError(0, CWARN_EmbedJsFileMissing, E.Message); // I4061 + sEmbedCSS := ''; + end; + end;*/ + } + + if (sLayoutFile != '') { // I3483 + // TODO: Load sLayoutFile from file + /*try + with TStringList.Create do + try + LoadFromFile(ExtractFilePath(FInFile) + sLayoutFile, TEncoding.UTF8); + sLayoutFile := Text; + if not ValidateLayoutFile(sLayoutFile, sVKDictionary) then // I4060 + begin + sLayoutFile := ''; + end; + finally + Free; + end; + except + on E:EFOpenError do // I3683 + begin + ReportError(0, CWARN_TouchLayoutFileMissing, E.Message); // I4061 + sLayoutFile := ''; + end; + end;*/ + } + + // Default to hide underlying layout characters. This is overridden by touch + // layout platform.displayUnderlying property or, if that is not present for + // the given platform, by the OSK property. + let fDisplayUnderlying = false; + + if (sVisualKeyboard != '') { + //TODO: Load sVisualKeyboard from file + /* + try + // The Keyman .kmx compiler will change the value of this store from a + // .kvks to a .kvk during the build. Earlier in the build, the visual keyboard + // would have been compiled, so we need to account for that and use that file. + + sVisualKeyboard := VisualKeyboardFromFile(ExtractFilePath(FOutFile) + sVisualKeyboard, fDisplayUnderlying); + except + on E:EFOpenError do // I3947 + begin + ReportError(0, CWARN_VisualKeyboardFileMissing, E.Message); // I4061 + sVisualKeyboard := 'null'; + end; + end; + */ + } + else { + sVisualKeyboard = 'null'; + } + + sModifierBitmask = GetKeyboardModifierBitmask; + + fMnemonic = vMnemonic == 1; + + let nl = '';//TODO + let FTabStop = '';//TODO + + + result += + `${JavaScript_SetupProlog}${nl}` + + `'KeymanWeb.KR(new ${sName}());${nl}` + + `${JavaScript_SetupEpilog}${nl}` + + `function ${sName}()${nl}` + + `{${nl}` + + `${FTabStop}${JavaScript_SetupDebug}${nl}` + + // Following line caches the Keyman major version + `${FTabStop}this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9;${nl}` + + `${FTabStop}this.KI="${sName}";${nl}` + + `${FTabStop}this.KN="%s";${nl}` + , RequotedString(sFullName), nl, + `${FTabStop}this.KMINVER="${(fk.version & VERSION_MASK_MAJOR) >> 8}.${fkp.version & VERSION_MASK_MINOR}";${nl}` + + `${FTabStop}this.KV=${sVisualKeyboard};${nl}` + + `${FTabStop}this.KDU=${fDisplayUnderlying?'1':'0'};${nl}` + + `${FTabStop}this.KH=${sHelp};${nl}` + + `${FTabStop}this.KM=${vMnemonic};${nl}` + + `${FTabStop}this.KBVER="${FKeyboardVersion}";${nl}` + // I4155 + `${FTabStop}this.KMBM=${sModifierBitmask};${nl}` + + `${sRTL}`; // I3681 + + if (HasSupplementaryPlaneChars) { + result += `${FTabStop}this.KS=1;${nl}`; + } + + if (sVKDictionary != '') { // I3438 + result += `${FTabStop}this.KVKD="${RequotedString(sVKDictionary)}";${nl}`; // I3681 + } + + if (sLayoutFile != '') { // I3483 + result += `${FTabStop}this.KVKL=${sLayoutFile};${nl}`; // I3681 + } + + if (sEmbedCSS != '') { // I4368 + result += `${FTabStop}this.KCSS="${RequotedString(sEmbedCSS)}";${nl}`; + } + + // Write the stores out + FOptionStores = ''; + for(let i = 0; i < source.keyboard.stores.length; i++) { + let fsp = source.keyboard.stores[i]; + // I3438 - Save all system stores to the keyboard, for now // I3684 + + if (!fsp.fIsDebug) { // and not (fsp.dwSystemID in [TSS_BITMAP, TSS_NAME, TSS_VERSION, TSS_CUSTOMKEYMANEDITION, TSS_CUSTOMKEYMANEDITIONNAME, TSS_KEYMANCOPYRIGHT]) then + if (fsp.dwSystemID == KMXFile.TSS_COMPARISON) { + result += `${FTabStop}this.s${JavaScript_Name(i, fsp.dpName)}=${JavaScript_Store(fsp.line, fsp.dpString)};${nl}`; + } + else if (fsp.dwSystemID == KMXFile.TSS_COMPILEDVERSION) { + result += `${FTabStop}this.KVER=${JavaScript_Store(fsp.line, fsp.dpString)};${nl}`; + } + //else if fsp.dwSystemID = TSS_VKDICTIONARY then // I3438, required for vkdictionary + // Result := Result + Format('%sthis.s%s=%s;%s', [FTabStop, JavaScript_Name(i, fsp.szName), JavaScript_Store(fsp.line, fsp.dpString), nl]) + else if (fsp.fIsOption && !fsp.fIsReserved) { + result += `${FTabStop}this.s${JavaScript_Name(i,fsp.szName)}=KeymanWeb.KLOAD(this.KI,"${JavaScript_Name(i,fsp.szName,true)}",`+ + `${JavaScript_Store(fsp.line, fsp.dpString)});${nl}`; + + if (FOptionStores != '') { + FOptionStores += ','; + } + FOptionStores += `'s${JavaScript_Name(i,fsp.szName)}`; + } + else if (fsp.dwSystemID == KMXFile.TSS_NONE /* aka not fsp.fIsReserved */) { + result += `${FTabStop}this.s${JavaScript_Name(i, fsp.szName)}=${JavaScript_Store(fsp.line, fsp.dpString)};${nl}`; // I3681 + } + } + } + + result += `${FTabStop}this.KVS=[${FOptionStores}];${nl}`; + + // Write the groups out + + // I853 - begin unicode missing causes crash + if (fk.StartGroup[KMXFile.BEGIN_UNICODE] == 0xFFFFFFFF) { + ReportError(0, CERR_InvalidBegin, 'A "begin unicode" statement is required to compile a KeymanWeb keyboard'); + return null; + } + + result += WriteBeginStatement('gs', fk.StartGroup[KMXFile.BEGIN_UNICODE]); + + rec := ExpandSentinel(PChar(sBegin_NewContext)); + if rec.Code = CODE_USE then + Result := Result + WriteBeginStatement('gn', rec.Use.GroupIndex); + rec := ExpandSentinel(PChar(sBegin_PostKeystroke)); + if rec.Code = CODE_USE then + Result := Result + WriteBeginStatement('gpk', rec.Use.GroupIndex); + + let fgp = source.keyboard.groups[fk.StartGroup[KMXFile.BEGIN_UNICODE]]; + result += + `${FTabStop}this.gs=function(t,e) {${nl}` + + `${FTabStop+FTabStop}return this.g${JavaScript_Name(fk.StartGroup[KMXFile.BEGIN_UNICODE], fgp.dpName)}(t,e);${nl}` + + `${FTabStop}}${nl}`; // I3681 + + for(let i = 0; i < source.keyboard.groups.length; i++) { // I1964 + let fgp = source.keyboard.groups[i]; + /* + Note on `r` and `m` variables in a group function: + + `m` can have one of three values: + 0: no rule from this group was matched + 1: a rule from this group was matched and did not include a `use` + statement + 2: a rule from this group matched and did include a `use` statement + (#5440) + + `m` is only used within a rule group to control the firing of the + `match` and `nomatch` rules. + + `r` can have one of two values: + 0: no rule from the final group matched (even if a rule from an + higher-level group did) + 1: a rule from the final group did match; + + `r` serves as the rule group's return value and is forwarded + recursively, best serving as a flag for whether or not default + output for a key should be emitted (0 means yes, emit the + default character output for that key). + */ + + result += + `${FTabStop}this.g${JavaScript_Name(i, fgp.dpName)}=function(t,e) {${nl}` + + `${FTabStop+FTabStop}var k=KeymanWeb,r=${fgp.fUsingKeys?0:1},m=0;${nl}`; //I1959 + + // fkp := fgp.dpKeyArray; + let HasRules = false; + + if (FFix183_LadderLength != 0) { + result += JavaScript_Rules(fgp); + } + else { + for (let j = 0; j < fgp.keys.length; j++) { // I1964 + let fkp = fgp.keys[j]; + if (!RuleIsExcludedByPlatform(fkp)) { + result += FTabstop+FTabstop; // I3681 + if (HasRules) { + result += 'else '; + } + HasRules = true; + + if (fgp.fUsingKeys) { + result += `if(k.KKM(e,${JavaScript_ShiftAsString(fkp, fMnemonic)},${JavaScript_KeyAsString(fkp, fMnemonic)})`; + } + + if (xstrlen(fkp.dpContext) > 0) { + result += fgp.fUsingKeys ? '&&' : 'if('; + result += JavaScript_ContextMatch(fkp, fkp.dpContext); + } + else if (!fgp.fUsingKeys) { + result += 'if(1'; + } + + linecomment = (fkp.Line > 0 && FDebug) ? ` // Line ${fkp.Line}` : ''; + + result += + `) {${linecomment}${nl}` + + FTabStop+FTabStop+FTabStop; + if (fgp.fUsingKeys) { // I1959 + result += 'r=m=1;' + JavaScript_OutputString(FTabStop + FTabStop + FTabStop, fkp, fkp.dpOutput, fgp); // I1959 // I3681 + } + else { + result += 'm=1;' + JavaScript_OutputString(FTabStop + FTabStop + FTabStop, fkp, fkp.dpOutput, fgp); // I1959 // I3681 + } + result += `${nl}${FTabStop}${FTabStop}}${nl}`; // I3681 + } + } + } + + if Assigned(fgp.dpMatch) then + Result := Result + Format( + '%sif(m==1) {%s'+ + '%s%s%s'+ + '%s}%s', + [FTabstop+FTabstop, nl, + FTabstop+Ftabstop, JavaScript_OutputString(FTabStop + FTabStop + FTabStop, nil, fgp.dpMatch, fgp), nl, + FTabstop+FTabstop, nl]); // I3681 + if Assigned(fgp.dpNoMatch) then + if fgp.fUsingKeys then // I1382 - fixup m=1 to m=g() + Result := Result + Format( + '%sif(!m&&k.KIK(e)) {%s'+ + '%sr=1;%s%s'+ + '%s}%s', + [FTabstop+FTabstop, nl, + FTabstop+FTabstop+FTabstop, JavaScript_OutputString(FTabStop + FTabStop + FTabStop, nil, fgp.dpNoMatch, fgp), nl, + FTabstop+FTabstop, nl]) // I1959. part 2, I2224 // I3681 + else + Result := Result + Format( + '%sif(!m) {%s'+ + '%s%s%s'+ + '%s}%s', + [FTabstop+FTabstop, nl, + FTabstop+FTabstop, JavaScript_OutputString(FTabStop + FTabStop + FTabStop, nil, fgp.dpNoMatch, fgp), nl, + FTabstop+FTabstop, nl]); // I1959 // I3681 + + Result := Result + Format('%sreturn r;%s'+ + '%s};%s', + [FTabstop+FTabstop, nl, + FTabstop, nl]); // I1959 // I3681 + Inc(fgp); + end; + + for n := 0 to FCallFunctions.Count - 1 do + begin + s := ExtractFilePath(FInFile) + FCallFunctions[n] + '.call_js'; + if FileExists(s) then + with TStringList.Create do + try + LoadFromFile(s, TEncoding.UTF8); // I3337 + Result := Result + Format('%sthis.c%d=function(t,e){%s};%s', [FTabstop, n, Trim(Text), nl]); // I3681 + finally + Free; + end + else + Result := Result + Format('%sthis.c%d=function(t,e){alert("call(%s) not defined");};%s', [FTabstop, n, FCallFunctions[n], nl]); // I3681 + end; + + Result := Result + sEmbedJS + '}' + nl; // I3681 +end; diff --git a/developer/src/kmc-kmw/src/main.ts b/developer/src/kmc-kmw/src/main.ts new file mode 100644 index 0000000000..742b9e4f47 --- /dev/null +++ b/developer/src/kmc-kmw/src/main.ts @@ -0,0 +1,2 @@ + +export { KeymanWebCompiler } from './compiler/keymanweb-compiler.js'; diff --git a/developer/src/kmc-kmw/src/util/util.ts b/developer/src/kmc-kmw/src/util/util.ts new file mode 100644 index 0000000000..d663fc490b --- /dev/null +++ b/developer/src/kmc-kmw/src/util/util.ts @@ -0,0 +1,7 @@ + +/** + * Verifies that value is an item in the enumeration. + */ +export function isValidEnumValue(enu: T, value: string) { + return (Object.values(enu) as string[]).includes(value); +} diff --git a/developer/src/kmc-kmw/tsconfig.json b/developer/src/kmc-kmw/tsconfig.json new file mode 100644 index 0000000000..a9dcdbbb2a --- /dev/null +++ b/developer/src/kmc-kmw/tsconfig.json @@ -0,0 +1,25 @@ +{ + "extends": "../../../tsconfig.esm-base.json", + + "compilerOptions": { + "outDir": "build/src/", + "rootDir": "src/", + "baseUrl": ".", + "allowSyntheticDefaultImports": true, // for ajv + + "paths": { + // "@keymanapp/keyman-version": ["../../../common/web/keyman-version/keyman-version.mts"], + "@keymanapp/common-types": ["../../../common/web/types/src/main"], + // "@keymanapp/": ["core/include/ldml/ldml-keyboard-constants"], + }, + + }, + "include": [ + "src/**/*.ts" + ], + "references": [ + { "path": "../../../common/web/keyman-version/tsconfig.esm.json" }, + { "path": "../../../common/web/types/" }, + { "path": "../../../core/include/ldml/"}, + ] +} diff --git a/developer/src/kmcmpdll/Compiler.cpp b/developer/src/kmcmpdll/Compiler.cpp index 8cc28d2ab7..89defad84d 100644 --- a/developer/src/kmcmpdll/Compiler.cpp +++ b/developer/src/kmcmpdll/Compiler.cpp @@ -319,6 +319,11 @@ int kmcmpMsgproc(int line, uint32_t dwMsgCode, char* szText, void* context) { } extern "C" BOOL __declspec(dllexport) CompileKeyboardFile(PSTR pszInfile, PSTR pszOutfile, BOOL ASaveDebug, BOOL ACompilerWarningsAsErrors, BOOL AWarnDeprecatedCode, CompilerMessageProc pMsgProc) // I4865 // I4866 +{ + return CompileKeyboardFileEx(pszInfile, pszOutfile, ASaveDebug, ACompilerWarningsAsErrors, AWarnDeprecatedCode, pMsgProc, CKF_KEYMAN); +} + +extern "C" BOOL __declspec(dllexport) CompileKeyboardFileEx(PSTR pszInfile, PSTR pszOutfile, BOOL ASaveDebug, BOOL ACompilerWarningsAsErrors, BOOL AWarnDeprecatedCode, CompilerMessageProc pMsgProc, int Target) // I4865 // I4866 { HANDLE hInfile = INVALID_HANDLE_VALUE, hOutfile = INVALID_HANDLE_VALUE; BOOL err; @@ -338,7 +343,7 @@ extern "C" BOOL __declspec(dllexport) CompileKeyboardFile(PSTR pszInfile, PSTR p FCompilerWarningsAsErrors = ACompilerWarningsAsErrors; // I4865 FWarnDeprecatedCode = AWarnDeprecatedCode; // I4866 - CompileTarget = CKF_KEYMAN; + CompileTarget = Target; if (!pMsgProc || !pszInfile || !pszOutfile) SetError(CERR_BadCallParams); diff --git a/developer/src/kmcomp/kmcomp.dproj b/developer/src/kmcomp/kmcomp.dproj index 36c16e3535..9bb6af3b5c 100644 --- a/developer/src/kmcomp/kmcomp.dproj +++ b/developer/src/kmcomp/kmcomp.dproj @@ -109,7 +109,7 @@ RELEASE;$(DCC_Define) - c:\temp\foo.kps -schema-path C:\Projects\keyman\app\common\schemas\kps\ + \Projects\keyman\keyboards\release\k\khmer_angkor\source\khmer_angkor.kmn c:\temp\ka.js true 2 1033 diff --git a/developer/src/tike/compile/CompileKeymanWeb.pas b/developer/src/tike/compile/CompileKeymanWeb.pas index 13d5219f70..e55966e5c3 100644 --- a/developer/src/tike/compile/CompileKeymanWeb.pas +++ b/developer/src/tike/compile/CompileKeymanWeb.pas @@ -275,6 +275,7 @@ uses System.TypInfo, CompileErrorCodes, + TempFileManager, JsonUtil, KeymanDeveloperOptions, Keyman.System.KeyboardUtils, @@ -282,6 +283,7 @@ uses kmxfileutils, TouchLayout, Unicode, + utilexecute, utilstr, VisualKeyboard, VKeys; @@ -303,6 +305,7 @@ function TCompileKeymanWeb.Compile(AOwnerProject: TProject; const InFile: string var WarnDeprecatedCode: Boolean; Data: string; + TempOutFile: TTempFile; begin FUnreachableKeys.Clear; @@ -337,9 +340,40 @@ begin WarnDeprecatedCode := True; end; + TempOutFile := TTempFileManager.Get('.kmx'); + GCallbackW := Callback; FCallFunctions := TStringList.Create; try + if CompileKeyboardFileEx(PChar(InFile), PChar(TempOutFile.Name), False, FCompilerWarningsAsErrors, + WarnDeprecatedCode, WebCompilerMessageA, CKF_KEYMANWEB) > 0 then + begin + if Assigned(AOwnerProject) and + Assigned(AOwnerProject.CompilerMessageFile) and + AOwnerProject.CompilerMessageFile.HasCompileWarning and + FCompilerWarningsAsErrors then + FError := True; + + if not FError then + begin + CopyFile(PChar(TempOutFile.Name), PChar(OutFile+'.kmx'), False); + // TODO: convert by calling node kmwc.js + // TODO: add +// TUtilExecute('node.exe kmwc.js "'+TempOutFile.Name+'" "'+OutFile+'"'); + {Data := WriteCompiledKeyboard; + + if not FError then + with TStringStream.Create(Data, TEncoding.UTF8) do + try + SaveToFile(OutFile); + finally + Free; + end;} + end; + + Result := not FError; // I1971 + +{ if CompileKeyboardFileToBuffer(PChar(InFile), @fk, FCompilerWarningsAsErrors, WarnDeprecatedCode, WebCompilerMessageA, CKF_KEYMANWEB) > 0 then // I3482 // I4866 // I4865 @@ -365,6 +399,7 @@ begin end; Result := not FError; // I1971 +} end else begin -- GitLab From dc05daefde7962b81fd78e374b979fe8d98b1c22 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 7 Dec 2022 19:56:30 +0700 Subject: [PATCH 093/214] feat: more work on compiler --- common/web/types/build.sh | 2 +- common/web/types/src/kmx/kmx.ts | 19 +- .../src/compiler/write-compiled-keyboard.ts | 185 ++++++++++++++++-- 3 files changed, 183 insertions(+), 23 deletions(-) diff --git a/common/web/types/build.sh b/common/web/types/build.sh index eb983acec8..0f2b408f1e 100755 --- a/common/web/types/build.sh +++ b/common/web/types/build.sh @@ -78,7 +78,7 @@ fi if builder_start_action test; then copy_schemas - npm test + npm test -- "${builder_extra_params[@]}" builder_finish_action success test fi diff --git a/common/web/types/src/kmx/kmx.ts b/common/web/types/src/kmx/kmx.ts index 2f47bddcdd..febda9b5e6 100644 --- a/common/web/types/src/kmx/kmx.ts +++ b/common/web/types/src/kmx/kmx.ts @@ -8,7 +8,20 @@ import * as r from 'restructure'; // kmx-builder will transform these to the corresponding COMP_xxxx export class KEYBOARD { - //TODO: additional header fields + fileVersion?: number; // dwFileVersion + keyboardVersion?: number; // version + + startGroup?: { + ansi: number; + unicode: number; + newContext: number; + postKeystroke: number; + }; + + flags?: number; + hotkey?: number; + + //bitmap: groups: GROUP[] = []; stores: STORE[] = []; }; @@ -328,6 +341,10 @@ export class KMXFile { public static readonly COMP_GROUP_SIZE = 24; public static readonly COMP_KEY_SIZE = 20; + + public static readonly VERSION_MASK_MINOR = 0x00FF; + public static readonly VERSION_MASK_MAJOR = 0xFF00; + /* In-memory representation of the keyboard */ public keyboard: KEYBOARD = { diff --git a/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts b/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts index 603b2be784..2d4b061d56 100644 --- a/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts +++ b/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts @@ -4,9 +4,35 @@ function requote(s: string): string { return "'" + s.replaceAll(/(['\\])/, "\\$1") + "'"; } -export function WriteCompiledKeyboard(source: KMXFile): string { +function RequotedString(s: string, RequoteSingleQuotes: boolean = false): string { + // TODO: use a JSON encode + let i: number = 0; + while(i < s.length) { + if (s.charAt(i) == '"' || s.charAt(i) == '\\') { + s = s.substring(0, i) + '\\' + s.substring(i); + i++; + } + else if (s.charAt(i) == '\'' && RequoteSingleQuotes) { + s = s.substring(0, i) + '\\' + s.substring(i); + i++; + } + else if(s.charAt(i) == '\n') { + s = s.substring(0, i) + '\\n' + s.substring(i + 1); + } + else if(s.charAt(i) == '\r') { + s = s.substring(0, i) + ' ' + s.substring(i + 1); + } + } + return s; +} + +export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boolean = false): string { + let nl = FDebug ? '\n' : ''; + let FTabStop = FDebug ? ' ' : ''; + // let fgp: GROUP; - let fsp: STORE; + + let fsp: STORE; let fkp: KEY; let j: number; @@ -70,7 +96,7 @@ export function WriteCompiledKeyboard(source: KMXFile): string { } } - const sName = 'Keyboard_'+TKeyboardUtils.GetKeymanWebCompiledNameFromFileName(FInFile); + const sName = 'Keyboard_'+name; //TODO: verify --> GetKeymanWebCompiledNameFromFileName(FInFile); if (sHelpFile != '') { sHelp = ''; @@ -183,13 +209,9 @@ export function WriteCompiledKeyboard(source: KMXFile): string { sVisualKeyboard = 'null'; } - sModifierBitmask = GetKeyboardModifierBitmask; - - fMnemonic = vMnemonic == 1; - - let nl = '';//TODO - let FTabStop = '';//TODO + sModifierBitmask = GetKeyboardModifierBitmask(source); + const fMnemonic = vMnemonic == 1; result += `${JavaScript_SetupProlog}${nl}` + @@ -201,8 +223,8 @@ export function WriteCompiledKeyboard(source: KMXFile): string { // Following line caches the Keyman major version `${FTabStop}this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9;${nl}` + `${FTabStop}this.KI="${sName}";${nl}` + - `${FTabStop}this.KN="%s";${nl}` + , RequotedString(sFullName), nl, - `${FTabStop}this.KMINVER="${(fk.version & VERSION_MASK_MAJOR) >> 8}.${fkp.version & VERSION_MASK_MINOR}";${nl}` + + `${FTabStop}this.KN="${RequotedString(sFullName)}";${nl}`, nl, + `${FTabStop}this.KMINVER="${(source.keyboard.fileVersion & KMXFile.VERSION_MASK_MAJOR) >> 8}.${source.keyboard.fileVersion & KMXFile.VERSION_MASK_MINOR}";${nl}` + `${FTabStop}this.KV=${sVisualKeyboard};${nl}` + `${FTabStop}this.KDU=${fDisplayUnderlying?'1':'0'};${nl}` + `${FTabStop}this.KH=${sHelp};${nl}` + @@ -211,7 +233,7 @@ export function WriteCompiledKeyboard(source: KMXFile): string { `${FTabStop}this.KMBM=${sModifierBitmask};${nl}` + `${sRTL}`; // I3681 - if (HasSupplementaryPlaneChars) { + if (HasSupplementaryPlaneChars()) { result += `${FTabStop}this.KS=1;${nl}`; } @@ -267,19 +289,21 @@ export function WriteCompiledKeyboard(source: KMXFile): string { return null; } - result += WriteBeginStatement('gs', fk.StartGroup[KMXFile.BEGIN_UNICODE]); + result += WriteBeginStatement('gs', source.keyboard.startGroup.unicode); - rec := ExpandSentinel(PChar(sBegin_NewContext)); - if rec.Code = CODE_USE then - Result := Result + WriteBeginStatement('gn', rec.Use.GroupIndex); - rec := ExpandSentinel(PChar(sBegin_PostKeystroke)); - if rec.Code = CODE_USE then - Result := Result + WriteBeginStatement('gpk', rec.Use.GroupIndex); + let rec = ExpandSentinel(sBegin_NewContext); + if(rec.Code == CODE_USE) { + result += WriteBeginStatement('gn', rec.Use.GroupIndex); + } + rec = ExpandSentinel(sBegin_PostKeystroke); + if(rec.Code == CODE_USE) { + result += WriteBeginStatement('gpk', rec.Use.GroupIndex); + } - let fgp = source.keyboard.groups[fk.StartGroup[KMXFile.BEGIN_UNICODE]]; + let fgp = source.keyboard.groups[source.keyboard.startGroup.unicode]; result += `${FTabStop}this.gs=function(t,e) {${nl}` + - `${FTabStop+FTabStop}return this.g${JavaScript_Name(fk.StartGroup[KMXFile.BEGIN_UNICODE], fgp.dpName)}(t,e);${nl}` + + `${FTabStop+FTabStop}return this.g${JavaScript_Name(source.keyboard.startGroup.unicode, fgp.dpName)}(t,e);${nl}` + `${FTabStop}}${nl}`; // I3681 for(let i = 0; i < source.keyboard.groups.length; i++) { // I1964 @@ -406,3 +430,122 @@ export function WriteCompiledKeyboard(source: KMXFile): string { Result := Result + sEmbedJS + '}' + nl; // I3681 end; +} + +/// +/// Determine the modifiers used in the target keyboard and return a bitmask +/// representing them, or an integer value when not in debug mode +/// +/// @return string of JavaScript code, e.g. 'modCodes.SHIFT | modCodes.CTRL /* 0x0030 */' +/// +function GetKeyboardModifierBitmask(source: KMXFile): string { + let bitMask = 0; + for(let gp of source.keyboard.groups) { + if(gp.fUsingKeys) { + for(let kp of gp.keys) { + if(!RuleIsExcludedByPlatform(kp)) { + bitMask |= JavaScript_Shift(kp, fMnemonic); + } + } + } + } + + if ((bitMask & KMXFile.KMX_MASK_MODIFIER_CHIRAL) && (bitMask & KMXFile.KMX_MASK_MODIFIER_NONCHIRAL)) { + ReportError(0, CWARN_DontMixChiralAndNonChiralModifiers, 'This keyboard contains Ctrl,Alt and LCtrl,LAlt,RCtrl,RAlt sets of modifiers. Use only one or the other set for web target.'); + } + + if(FDebug) { + return FormatModifierAsBitflags(bitMask & KMXFile.KMX_MASK_KEYS); // Exclude KMX_ISVIRTUALKEY, KMX_VIRTUALCHARKEY + } + + return '0x'+(bitMask & KMXFile.KMX_MASK_KEYS).toString(16); +} + + +/// +/// If debug mode, then returns Javascript code necessary for +/// accessing constants in the compiled keyboard +/// +/// @return string of JavaScript code +/// +function JavaScript_SetupDebug() { + if(IsKeyboardVersion10OrLater()) { + if(FDebug) { + return 'var modCodes = keyman.osk.modifierCodes;'+nl+ + FTabStop+'var keyCodes = keyman.osk.keyCodes;'+nl; + } + } + return ''; +} + +function JavaScript_SetupProlog() { + if(IsKeyboardVersion10OrLater()) { + return 'if(typeof keyman === \'undefined\') {'+nl+ + FTabStop+'console.log(\'Keyboard requires KeymanWeb 10.0 or later\');'+nl+ + FTabStop+'if(typeof tavultesoft !== \'undefined\') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later");'+nl+ + '} else {'; + } + return ''; +} + +function JavaScript_SetupEpilog() { + if(IsKeyboardVersion10OrLater()) { + return '}'; + } + return ''; +} + +function HasSupplementaryPlaneChars() { + return false; // TODO +/* function StringHasSuppChars(p: PWideChar): Boolean; + begin + if not Assigned(p) then + Exit(False); + + while p^ <> #0 do + begin + if Char.IsSurrogate(p, 0) then + Exit(True); + p := incxstr(p); + end; + + Result := False; + end; + +var + I: Integer; + fsp: PFILE_STORE; + fgp: PFILE_GROUP; + j: Integer; + fkp: PFILE_KEY; +begin + fsp := fk.dpStoreArray; + for i := 0 to Integer(fk.cxStoreArray) - 1 do + begin + if StringHasSuppChars(fsp.dpString) then + Exit(True); + Inc(fsp); + end; + + fgp := fk.dpGroupArray; + for i := 0 to Integer(fk.cxGroupArray) - 1 do + begin + fkp := fgp.dpKeyArray; + for j := 0 to Integer(fgp.cxKeyArray) - 1 do + begin + if StringHasSuppChars(fkp.dpContext) or + StringHasSuppChars(fkp.dpOutput) then + Exit(True); + Inc(fkp); + end; + + if StringHasSuppChars(fgp.dpMatch) or + StringHasSuppChars(fgp.dpNoMatch) then + Exit(True); + + Inc(fgp); + end; + + Result := False; +end;*/ +} \ No newline at end of file -- GitLab From f68a4c84fdb41d1a9e8d1beff2ef636b78b13f54 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 19 Dec 2022 14:35:24 +1100 Subject: [PATCH 094/214] chore: continue --- .../src/kmc-kmw/src/compiler/callbacks.ts | 1 + .../kmc-kmw/src/compiler/compiler-globals.ts | 28 ++ .../src/compiler/javascript-strings.ts | 327 ++++++++++++++++++ .../src/compiler/keymanweb-compiler.ts | 15 +- .../src/kmc-kmw/src/compiler/messages.ts | 308 ++++++++++++----- .../src/compiler/write-compiled-keyboard.ts | 95 +++-- 6 files changed, 625 insertions(+), 149 deletions(-) create mode 100644 developer/src/kmc-kmw/src/compiler/compiler-globals.ts create mode 100644 developer/src/kmc-kmw/src/compiler/javascript-strings.ts diff --git a/developer/src/kmc-kmw/src/compiler/callbacks.ts b/developer/src/kmc-kmw/src/compiler/callbacks.ts index f6cd673b56..c20a2b078c 100644 --- a/developer/src/kmc-kmw/src/compiler/callbacks.ts +++ b/developer/src/kmc-kmw/src/compiler/callbacks.ts @@ -1,4 +1,5 @@ export interface CompilerEvent { + line: number; code: number; message: string; }; diff --git a/developer/src/kmc-kmw/src/compiler/compiler-globals.ts b/developer/src/kmc-kmw/src/compiler/compiler-globals.ts new file mode 100644 index 0000000000..f769c768ba --- /dev/null +++ b/developer/src/kmc-kmw/src/compiler/compiler-globals.ts @@ -0,0 +1,28 @@ +import { KEYBOARD, KMXFile } from "@keymanapp/common-types/src/kmx/kmx"; +import CompilerOptions from "./compiler-options.js"; + +export let FTabStop: string; +export let nl: string; +export let FCompilerWarningsAsErrors = false; +export let fk: KEYBOARD; +export let FMnemonic: boolean; +export let options: CompilerOptions; + +export function setupGlobals(_options: CompilerOptions, _tab: string, _nl: string, _keyboard: KEYBOARD) { + options = _options; + FTabStop = _tab; + nl = _nl; + fk = _keyboard; +} + +export function IsKeyboardVersion10OrLater(): boolean { + return fk.fileVersion >= KMXFile.VERSION_100; +} + +export function IsKeyboardVersion14OrLater(): boolean { + return fk.fileVersion >= KMXFile.VERSION_140; +} + +export function IsKeyboardVersion15OrLater(): boolean { + return fk.fileVersion >= KMXFile.VERSION_150; +} diff --git a/developer/src/kmc-kmw/src/compiler/javascript-strings.ts b/developer/src/kmc-kmw/src/compiler/javascript-strings.ts new file mode 100644 index 0000000000..8b95d484f0 --- /dev/null +++ b/developer/src/kmc-kmw/src/compiler/javascript-strings.ts @@ -0,0 +1,327 @@ +import { GROUP, KEY, KMXFile } from "../../../../../common/web/types/src/kmx/kmx.js"; + +import { FMnemonic, FTabStop, IsKeyboardVersion10OrLater, nl, options } from "./compiler-globals.js"; +import { CERR_VirtualCharacterKeysNotSupportedInKeymanWeb, CERR_VirtualKeysNotValidForMnemonicLayouts, CWARN_ExtendedShiftFlagsNotSupportedInKeymanWeb, CWARN_OptionStoreNameInvalid, ReportError } from "./messages.js"; + +//const SValidIdentifierCharSet = '123'; + +export function JavaScript_Name(i: number, pwszName: string, KeepNameForPersistentStorage: boolean = false): string { // I3659 + let FChanged: boolean = false; + let p = pwszName; + + if((pwszName == null || pwszName == undefined || pwszName == '') || (!isFDebug && !KeepNameForPersistentStorage)) { // I3659 // I3681 + return i.toString(10); // for uniqueness + } + else { + let result = KeepNameForPersistentStorage // I3659 + ? '' // Potential for overlap in theory but in practice we only use this for named option stores so can never overlap + : '_'; // Ensures we cannot overlap numbered instances + while(p.length) { + let ch = p.charAt(0); + if(SValidIdentifierCharSet.includes(ch)) { // I3681 + result += ch; + } else { + result += '_'; + FChanged = true; + } + p = p.substring(1); + } + if(!KeepNameForPersistentStorage) { + // Ensure each transformed name is still unique + result += '_' + i.toString(10); + if(FChanged) { + result += '/*'+pwszName.replace(/\*\//g, '*-/')+'*/'; + } + } else if(FChanged) { + // For named option stores, we are only supporting the valid identifier + // character set, which is a breaking change in 14.0. + ReportError(0, CWARN_OptionStoreNameInvalid, + Format('The option store %s should be named with characters in the range A-Z, a-z, 0-9 and _ only.', + [pwszName])); + } + return result; + } +} + +export function JavaScript_Store(line: number, pwsz: string): string { + let ch: number, rec: TSentinelRecord, result: string; + const wcsentinel: string = '\uFFFF'; + let n = pwsz.indexOf(wcsentinel); + + // Start: plain text store. Always use for < 10.0, conditionally for >= 10.0. + if(n == 0 || !IsKeyboardVersion10OrLater) { + result = '"'; + while(pwsz.length) { + if(pwsz.charCodeAt(0) == KMXFile.UC_SENTINEL) { + result += '.'; // UC_SENTINEL values are not supported in stores for KMW < 10.0. + } else { + ch = GetSuppChar(pwsz); + if(ch == '"' || ch == '\\') { + result += '\\'; + } + result += JavaScript_String(ch); // I2242 + } + + pwsz = pwsz.substring(1); + } + result += '"'; + } + else { + result = '['; + while(pwsz.length) { + if(result != '[') { + result += ','; + } + rec = ExpandSentinel(pwsz); + if(rec.IsSentinel) { + if(rec.Code == KMXFile.CODE_DEADKEY) { + result += `{t:'d',d:${rec.Deadkey.DeadKey}}`; + } + else if(rec.Code == KMXFile.CODE_BEEP) { + result += `{t:'b'}`; + } + else { //if rec.Code = CODE_EXTENDED then + // At some point, we may wish to filter which codes are safe to stub out like this + // versus which ones should be an error. The commented-out-code shows the way to + // handle such cases. + result += `''`; + } +// else +// begin +// //ReportError(line, CERR_SomewhereIGotItWrong, 'Internal Error: unexpected sentinel character in store definition'); +// end; + } + else { + ch = GetSuppChar(pwsz); + result += '"'; + // TODO: Refactor the section below into JavaScript_String, as it's + // quite common in our code base. + if(ch == '"'.charCodeAt(0) || ch == '\\'.charCodeAt(0)) { + result += '\\'; + } + result += JavaScript_String(ch) + '"'; // I2242 + } + + pwsz = pwsz.substring(1); + } + result += ']'; + } + return result; +} + +export function JavaScript_String(ch: number): string { // I2242 + if(ch < 32) { + switch(ch) { + case 9: return '\\t'; + case 10: return '\\n'; + case 13: return '\\r'; + } + if(ch < 9) { + return '\\x0'+ch.toString(16); + } else { + return '\\x'+ch.toString(16); + } + } + else { + return String.fromCodePoint(ch); + } +} + +export function JavaScript_Rules(fgp: GROUP): string { + let IsEqualKey = function(k1: KEY, k2: KEY): boolean { + return ( + (JavaScript_Key(k1, FMnemonic) == JavaScript_Key(k2, FMnemonic)) && + (JavaScript_Shift(k1, FMnemonic) == JavaScript_Shift(k2, FMnemonic)) + ); + } + + let result = ''; + let HasRules = false; + + let processed_rule = Array(fgp.keys.length); + for(let j = 0; j < fgp.keys.length; j++) { + processed_rule[j] = false; + } + + let j = 0; + let Counter = 0; + while(j < fgp.keys.length) { // I1964 + if(!processed_rule[j] && !RuleIsExcludedByPlatform(fkp)) { + let fkp = fgp.keys[j]; + // Break down by key code + // We know the rules are sorted by context length and then key code. + // First pass, break the grouping down by key code. + + if(fgp.fUsingKeys) { + result += + `${FTabStop+FTabStop}${HasRules?'else ':''}`+ + `if(k.KKM(e,${JavaScript_ShiftAsString(fkp, fMnemonic)},${JavaScript_KeyAsString(fkp, fMnemonic)})) {${nl}`; + + HasRules = true; + Counter++; + + let LocalHasRules = false; + let fkp2 = fgp.keys[j]; + let j2 = j; + let LocalCounter = 0; + while (j < fgp.keys.length) { + fkp = fgp.keys[j]; + if (!processed_rule[j] && !RuleIsExcludedByPlatform(fkp) && IsEqualKey(fkp, fkp2)) { + processed_rule[j] = true; + result += JavaScript_Rule(FTabStop + FTabStop + FTabStop, LocalHasRules ? 'else ' : '', fgp, fkp); + LocalCounter++; + + if (FFix183_LadderLength != 0 && (LocalCounter % FFix183_LadderLength) == 0) { + // Break if/else ladders + result += `${FTabStop+FTabStop+FTabStop}if(m) {}${nl}`; + } + LocalHasRules = true; + } + + j++; + } + + result += FTabStop + FTabStop + '}' + nl; + j = j2 + 1; + } + else { + // TODO: context character level switches instead of full context comparisons + result += JavaScript_Rule(FTabStop + FTabStop + FTabStop, HasRules ? 'else ' : '', fgp, fkp); + HasRules = true; + Counter++; + j++; + } + + if (FFix183_LadderLength != 0 && (Counter % FFix183_LadderLength) == 0) { + // Break if/else ladders + // We need to only match if no previous line is matched (i.e. m is false) + result += `${FTabStop+FTabStop+FTabStop}if(m) {}${nl}`; + } + } + else { + j++; + } + } + return result; +} + +export function JavaScript_Shift(fkp: KEY, FMnemonic: boolean): number { + if (FMnemonic) { + if (fkp.ShiftFlags & KMXFile.VIRTUALCHARKEY) { + ReportError(fkp.Line, CERR_VirtualCharacterKeysNotSupportedInKeymanWeb, 'Virtual character keys not currently supported in KeymanWeb'); // I1971 // I4061 + return 0; + } + + if (fkp.ShiftFlags & KMXFile.ISVIRTUALKEY && fkp.Key <= 255) { + // We prohibit K_ keys for mnemonic layouts. We don't block T_ and U_ keys. + // TODO: this doesn't resolve the issue of, e.g. SHIFT+K_SPACE + // https://github.com/keymanapp/keyman/issues/265 + ReportError(fkp.Line, CERR_VirtualKeysNotValidForMnemonicLayouts, 'Virtual keys are not valid for mnemonic layouts'); // I1971 // I4061 + return 0; + } + } + + if (fkp.ShiftFlags & KMXFile.ISVIRTUALKEY) { + if(IsKeyboardVersion10OrLater()) { + // Full chiral modifier and state key support starts with KeymanWeb 10.0 + return fkp.ShiftFlags; + } + + // Non-chiral support only and no support for state keys + if (fkp.ShiftFlags & (KMXFile.LCTRLFLAG | KMXFile.RCTRLFLAG | KMXFile.LALTFLAG | KMXFile.RALTFLAG)) { // I4118 + ReportError(fkp.Line, CWARN_ExtendedShiftFlagsNotSupportedInKeymanWeb, 'Extended shift flags LALT, RALT, LCTRL, RCTRL are not supported in KeymanWeb'); + } + + if (fkp.ShiftFlags & ( + KMXFile.CAPITALFLAG | KMXFile.NOTCAPITALFLAG | KMXFile.NUMLOCKFLAG | KMXFile.NOTNUMLOCKFLAG | + KMXFile.SCROLLFLAG | KMXFile.NOTSCROLLFLAG)) { // I4118 + ReportError(fkp.Line, CWARN_ExtendedShiftFlagsNotSupportedInKeymanWeb, 'Extended shift flags CAPS and NCAPS are not supported in KeymanWeb'); + } + + return KMXFile.ISVIRTUALKEY | (fkp.ShiftFlags & (KMXFile.K_SHIFTFLAG | KMXFile.K_CTRLFLAG | KMXFile.K_ALTFLAG)); + } + + return USEnglishShift.includes(fkp.Key) ? KMXFile.ISVIRTUALKEY | KMXFile.K_SHIFTFLAG : KMXFile.ISVIRTUALKEY; +} + +/** + * Returns a Javascript representation of a key modifier state, either as a constant (debug mode) + * or as an integer. + * + * @param fkp Pointer to key record + * @param FMnemonic True if the keyboard is a mnemonic layout + * + * @return string representation of the key modifier state, e.g. + * 'modCodes.SHIFT | modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4110 * /' or + * '16656' + */ +export function JavaScript_ShiftAsString(fkp: KEY, FMnemonic: boolean): string { + if(!options.debug) { + return JavaScript_Shift(fkp, FMnemonic).toString(); + } + return ' '+FormatModifierAsBitflags(JavaScript_Shift(fkp, FMnemonic)); +} + + + +function TCompileKeymanWeb.JavaScript_Key(fkp: PFILE_KEY; FMnemonic: Boolean): Integer; +var + n: Integer; + i: Integer; +begin + if not FMnemonic then + begin + if (fkp.ShiftFlags and KMX_ISVIRTUALKEY) = KMX_ISVIRTUALKEY then + begin + Result := Ord(fkp.Key); + end + else + begin + // Convert the character to a virtual key + n := Pos(fkp.Key, USEnglishShift); + if n = 0 then n := Pos(fkp.Key, USEnglishUnshift); + if n = 0 + then Result := 0 + else Result := Ord(USEnglishValues[n]); + end; + end + else + begin + Result := Ord(fkp.Key); + end; + + // Check that key is not unreachable (e.g. K_SHIFT, touch-specific special keys 50,000+) + + for i := 0 to High(UnreachableKeyCodes) do // I4141 + if Result = UnreachableKeyCodes[i] then + Result := 0; + + if (Result = 0) or (Result >= Ord(Low(TKeymanWebTouchStandardKey))) then // I4141 + begin + if not FUnreachableKeys.Contains(fkp) then + begin + ReportError(fkp.Line, CHINT_UnreachableKeyCode, + 'The rule will never be matched for key '+ + FormatKeyForErrorMessage(fkp,FMnemonic)+' because its key code is never fired.'); + FUnreachableKeys.Add(fkp); + end; + end; +end; + +/// +/// Returns a Javascript representation of a key value, either as a constant (debug mode) +/// or as an integer. +/// +/// @param fkp Pointer to key record +/// @param FMnemonic True if the keyboard is a mnemonic layout +/// +/// @return string representation of the key value, e.g. 'keyCodes.K_A /* 0x41 */' or '65' +/// +function JavaScript_KeyAsString(fkp: KEY, FMnemonic: boolean): string { + if(options.debug) { + return ' '+FormatKeyAsString(JavaScript_Key(fkp, FMnemonic)); + } else { + return JavaScript_Key(fkp, FMnemonic).toString(); + } +} + diff --git a/developer/src/kmc-kmw/src/compiler/keymanweb-compiler.ts b/developer/src/kmc-kmw/src/compiler/keymanweb-compiler.ts index 03fc953e3f..1b162b738a 100644 --- a/developer/src/kmc-kmw/src/compiler/keymanweb-compiler.ts +++ b/developer/src/kmc-kmw/src/compiler/keymanweb-compiler.ts @@ -1,22 +1,21 @@ import { VisualKeyboard } from "@keymanapp/common-types"; - import * as path from 'path'; -import { KMXFile } from "../../../../../common/web/types/src/kmx/kmx"; -// import VisualKeyboardCompiler from "./visual-keyboard-compiler.js"; -export interface KeymanWebCompilerOptions { - debug?: boolean; -}; +import { KMXFile } from "../../../../../common/web/types/src/kmx/kmx.js"; +// import VisualKeyboardCompiler from "./visual-keyboard-compiler.js"; +import { nl, FTabStop, setupGlobals } from "./compiler-globals.js"; +import CompilerOptions from "./compiler-options.js"; export class KeymanWebCompiler { - private readonly options: KeymanWebCompilerOptions; + private readonly options: CompilerOptions; private readonly nl: string; private readonly tab: string; - constructor(options?: KeymanWebCompilerOptions) { + constructor(options?: CompilerOptions) { this.options = options; this.nl = this.options.debug ? "\n" : ''; this.tab = this.options.debug ? " " : ''; + setupGlobals(this.options, this.tab, this.nl); } public compile(name: string, source: KMXFile): string { diff --git a/developer/src/kmc-kmw/src/compiler/messages.ts b/developer/src/kmc-kmw/src/compiler/messages.ts index 0a6801f9d2..9f443cfc0d 100644 --- a/developer/src/kmc-kmw/src/compiler/messages.ts +++ b/developer/src/kmc-kmw/src/compiler/messages.ts @@ -1,97 +1,219 @@ +import { FCompilerWarningsAsErrors } from "./compiler-globals.js"; -export enum CompilerErrorSeverity { - Info = 0x000000, - Hint = 0x100000, - Warn = 0x200000, - Error = 0x300000, - Fatal = 0x400000, - Severity_Mask = 0xF00000, // includes reserved bits - Error_Mask = 0x0FFFFF, -}; - -const m = (code: number, message: string) => { return { code, message } }; -const SevInfo = CompilerErrorSeverity.Info; -const SevHint = CompilerErrorSeverity.Hint; -// const SevWarn = CompilerErrorSeverity.Warn; -const SevError = CompilerErrorSeverity.Error; -const SevFatal = CompilerErrorSeverity.Fatal; - -export class CompilerMessages { - static Error_InvalidNormalization = (o:{form: string}) => m(this.ERROR_InvalidNormalization, `Invalid normalization form '${o.form}`); - static ERROR_InvalidNormalization = SevError | 0x0001; - - static Error_InvalidLocale = (o:{tag: string}) => m(this.ERROR_InvalidLocale, `Invalid BCP 47 locale form '${o.tag}'`); - static ERROR_InvalidLocale = SevError | 0x0002; - - static Error_HardwareLayerHasTooManyRows = () => m(this.ERROR_HardwareLayerHasTooManyRows, `'hardware' layer has too many rows`); - static ERROR_HardwareLayerHasTooManyRows = SevError | 0x0003; - - static Error_RowOnHardwareLayerHasTooManyKeys = (o:{row: number}) => m(this.ERROR_RowOnHardwareLayerHasTooManyKeys, `Row #${o.row} on 'hardware' layer has too many keys`); - static ERROR_RowOnHardwareLayerHasTooManyKeys = SevError | 0x0004; - - static Error_KeyNotFoundInKeyBag = (o:{keyId: string, col: number, row: number, layer: string, form: string}) => - m(this.ERROR_KeyNotFoundInKeyBag, `Key '${o.keyId}' in position #${o.col} on row #${o.row} of layer ${o.layer}, form '${o.form}' not found in key bag`); - static ERROR_KeyNotFoundInKeyBag = SevError | 0x0005; - - static Hint_OneOrMoreRepeatedLocales = () => - m(this.HINT_OneOrMoreRepeatedLocales, `After minimization, one or more locales is repeated and has been removed`); - static HINT_OneOrMoreRepeatedLocales = SevHint | 0x0006; - - static Error_InvalidFile = (o:{errorText: string}) => - m(this.ERROR_InvalidFile, `The source file has an invalid structure: ${o.errorText}`); - static ERROR_InvalidFile = SevError | 0x0007; - - static Hint_LocaleIsNotMinimalAndClean = (o:{sourceLocale: string, locale: string}) => - m(this.HINT_LocaleIsNotMinimalAndClean, `Locale '${o.sourceLocale}' is not minimal or correctly formatted and should be '${o.locale}'`); - static HINT_LocaleIsNotMinimalAndClean = SevHint | 0x0008; - - static Error_VkeyIsNotValid = (o:{vkey: string}) => - m(this.ERROR_VkeyIsNotValid, `Virtual key '${o.vkey}' is not found in the CLDR VKey Enum table.`); - static ERROR_VkeyIsNotValid = SevError | 0x0009; - - static Hint_VkeyIsRedundant = (o:{vkey: string}) => - m(this.HINT_VkeyIsRedundant, `Virtual key '${o.vkey}' is mapped to itself, which is redundant.`); - static HINT_VkeyIsRedundant = SevHint | 0x000A; - - static Error_VkeyIsRepeated = (o:{vkey: string}) => - m(this.ERROR_VkeyIsRepeated, `Virtual key '${o.vkey}' has more than one vkey entry.`); - static ERROR_VkeyIsRepeated = SevError | 0x000B; - - static Info_MultipleVkeysHaveSameTarget = (o:{vkey: string}) => - m(this.INFO_MultipleVkeysHaveSameTarget, `Target virtual key '${o.vkey}' has multiple source mappings, which may be an error.`); - static INFO_MultipleVkeysHaveSameTarget = SevInfo | 0x000C; - - static Error_InvalidVersion = (o:{version: string}) => - m(this.ERROR_InvalidVersion, `Version number '${o.version}' must be a semantic version format string.`); - static ERROR_InvalidVersion = SevError | 0x000D; - - static Error_MustBeAtLeastOneLayerElement = () => - m(this.ERROR_MustBeAtLeastOneLayerElement, `The source file must contain at least one layer element.`); - static ERROR_MustBeAtLeastOneLayerElement = SevError | 0x000E; - - static Fatal_SectionCompilerFailed = (o:{sect: string}) => - m(this.FATAL_SectionCompilerFailed, `The compiler for '${o.sect}' failed unexpectedly.`); - static FATAL_SectionCompilerFailed = SevFatal | 0x000F; - - static Error_DisplayIsRepeated = (o:{to: string}) => - m(this.ERROR_DisplayIsRepeated, `display to='${o.to}' has more than one display entry.`); - static ERROR_DisplayIsRepeated = SevError | 0x0010; - - static Error_KeyMissingToGapOrSwitch = (o:{keyId: string}) => - m(this.ERROR_KeyMissingToGapOrSwitch, `key id='${o.keyId}' must have either to=, gap=, or switch=.`); -static ERROR_KeyMissingToGapOrSwitch = SevError | 0x0011; - - static severityName(code: number): string { - let severity = code & CompilerErrorSeverity.Severity_Mask; - switch(severity) { - case CompilerErrorSeverity.Info: return 'INFO'; - case CompilerErrorSeverity.Hint: return 'HINT'; - case CompilerErrorSeverity.Warn: return 'WARN'; - case CompilerErrorSeverity.Error: return 'ERROR'; - case CompilerErrorSeverity.Fatal: return 'FATAL'; - /* istanbul ignore next */ - default: return 'UNKNOWN'; - } +export let FError = false; + +export function ReportError(line: number, msgcode: number, text: string) { // I1971 + let flag = CERR_FLAG | CFATAL_FLAG; + if(FCompilerWarningsAsErrors) { + flag |= CWARN_FLAG; + } + if (msgcode & flag) { + FError = true; } + FCallback(line, msgcode, text); // I3310 } +export const + CHINT_FLAG = 0x1000, + CWARN_FLAG = 0x2000, + CERR_FLAG = 0x4000, + CFATAL_FLAG = 0x8000, + +// Any messages from the lexical model compiler occupy this range: + CERR_LEXICAL_MODEL_MIN = 0x0800, + CERR_LEXICAL_MODEL_MAX = 0x08FF, + + CERR_None = 0x0000, + CERR_EndOfFile = 0x0001, + + CERR_BadCallParams = 0x8002, + CERR_CannotAllocateMemory = 0x9004, + CERR_InfileNotExist = 0x8005, + CERR_CannotCreateOutfile = 0x8006, + CERR_UnableToWriteFully = 0x8007, + CERR_CannotReadInfile = 0x8008, + CERR_SomewhereIGotItWrong = 0x8009, + + CERR_InvalidToken = 0x400A, + CERR_InvalidBegin = 0x400B, + CERR_InvalidName = 0x400C, + CERR_InvalidVersion = 0x400D, + CERR_InvalidLanguageLine = 0x400E, + CERR_LayoutButNoLanguage = 0x400F, + CERR_InvalidLayoutLine = 0x4010, + CERR_NoVersionLine = 0x4011, + CERR_InvalidGroupLine = 0x4012, + CERR_InvalidStoreLine = 0x4013, + CERR_InvalidCodeInKeyPartOfRule = 0x4014, + CERR_InvalidDeadkey = 0x4015, + CERR_InvalidValue = 0x4016, + CERR_ZeroLengthString = 0x4017, + CERR_TooManyIndexToKeyRefs = 0x4018, + CERR_UnterminatedString = 0x4019, + CERR_StringInVirtualKeySection = 0x401A, + CERR_AnyInVirtualKeySection = 0x401B, + CERR_InvalidAny = 0x401C, + CERR_StoreDoesNotExist = 0x401D, + CERR_BeepInVirtualKeySection = 0x401E, + CERR_IndexInVirtualKeySection = 0x401F, + CERR_InvalidIndex = 0x4020, + CERR_OutsInVirtualKeySection = 0x4021, + CERR_InvalidOuts = 0x4022, + CERR_ContextInVirtualKeySection = 0x4024, + CERR_InvalidUse = 0x4025, + CERR_GroupDoesNotExist = 0x4026, + CERR_VirtualKeyNotAllowedHere = 0x4027, + CERR_InvalidSwitch = 0x4028, + CERR_NoTokensFound = 0x4029, + CERR_InvalidLineContinuation = 0x402A, + CERR_LineTooLong = 0x402B, + CERR_InvalidCopyright = 0x402C, + CERR_CodeInvalidInThisSection = 0x402D, + CERR_InvalidMessage = 0x402E, + CERR_InvalidLanguageName = 0x402F, + CERR_InvalidBitmapLine = 0x4030, + CERR_CannotReadBitmapFile = 0x4031, + CERR_IndexDoesNotPointToAny = 0x4032, + CERR_ReservedCharacter = 0x4033, + CERR_InvalidCharacter = 0x4034, + CERR_InvalidCall = 0x4035, + CERR_CallInVirtualKeySection = 0x4036, + CERR_CodeInvalidInKeyStore = 0x4037, + CERR_CannotLoadIncludeFile = 0x4038, + + CERR_60FeatureOnly_EthnologueCode = 0x4039, + CERR_60FeatureOnly_MnemonicLayout = 0x403A, + CERR_60FeatureOnly_OldCharPosMatching = 0x403B, + CERR_60FeatureOnly_NamedCodes = 0x403C, + CERR_60FeatureOnly_Contextn = 0x403D, + CERR_501FeatureOnly_Call = 0x403E, + + CERR_InvalidNamedCode = 0x403F, + CERR_InvalidSystemStore = 0x4040, + + CERR_CallIsProfessionalFeature = 0x4041, + CERR_IncludeCodesIsProfessionalFeature = 0x4042, + CERR_MnemonicLayoutIsProfessionalFeature = 0x4043, + CERR_60FeatureOnly_VirtualCharKey = 0x4044, + + CERR_VersionAlreadyIncluded = 0x4045, + + CERR_70FeatureOnly = 0x4046, + + CERR_80FeatureOnly = 0x4047, + CERR_InvalidInVirtualKeySection = 0x4048, + CERR_InvalidIf = 0x4049, + CERR_InvalidReset = 0x404A, + CERR_InvalidSet = 0x404B, + CERR_InvalidSave = 0x404C, + + CERR_InvalidEthnologueCode = 0x404D, + + CERR_CannotCreateTempfile = 0x804E, + + CERR_90FeatureOnly_IfSystemStores = 0x404F, + CERR_IfSystemStore_NotFound = 0x4050, + CERR_90FeatureOnly_SetSystemStores = 0x4051, + CERR_SetSystemStore_NotFound = 0x4052, + CERR_90FeatureOnlyVirtualKeyDictionary = 0x4053, + + CERR_NotSupportedInKeymanWebContext = 0x4054, + CERR_NotSupportedInKeymanWebOutput = 0x4055, + CERR_NotSupportedInKeymanWebStore = 0x4056, + CERR_VirtualCharacterKeysNotSupportedInKeymanWeb = 0x4057, + CERR_VirtualKeysNotValidForMnemonicLayouts = 0x4058, + CERR_InvalidTouchLayoutFile = 0x4059, + CERR_TouchLayoutInvalidIdentifier = 0x405A, // I4142 + CERR_InvalidKeyCode = 0x405B, // I4142 + + CERR_90FeatureOnlyLayoutFile = 0x405C, + CERR_90FeatureOnlyKeyboardVersion = 0x405D, + CERR_KeyboardVersionFormatInvalid = 0x405E, + CERR_ContextExHasInvalidOffset = 0x405F, + CERR_90FeatureOnlyEmbedCSS = 0x4060, + CERR_90FeatureOnlyTargets = 0x4061, + CERR_ContextAndIndexInvalidInMatchNomatch = 0x4062, + CERR_140FeatureOnlyContextAndNotAnyWeb = 0x4063, + + CERR_ExpansionMustFollowCharacterOrVKey = 0x4064, + CERR_VKeyExpansionMustBeFollowedByVKey = 0x4065, + CERR_CharacterExpansionMustBeFollowedByCharacter = 0x4066, + CERR_VKeyExpansionMustUseConsistentShift = 0x4067, + CERR_ExpansionMustBePositive = 0x4068, + + CERR_CasedKeysMustContainOnlyVirtualKeys = 0x4069, + CERR_CasedKeysMustNotIncludeShiftStates = 0x406A, + CERR_CasedKeysNotSupportedWithMnemonicLayout = 0x406B, + + CERR_CannotUseReadWriteGroupFromReadonlyGroup = 0x406C, + CERR_StatementNotPermittedInReadonlyGroup = 0x406D, + CERR_OutputInReadonlyGroup = 0x406E, + CERR_NewContextGroupMustBeReadonly = 0x406F, + CERR_PostKeystrokeGroupMustBeReadonly = 0x4070, + + CERR_DuplicateGroup = 0x4071, + CERR_DuplicateStore = 0x4072, + + CWARN_TooManyWarnings = 0x2080, + CWARN_OldVersion = 0x2081, + CWARN_BitmapNotUsed = 0x2082, + CWARN_CustomLanguagesNotSupported = 0x2083, + CWARN_KeyBadLength = 0x2084, + CWARN_IndexStoreShort = 0x2085, + CWARN_UnicodeInANSIGroup = 0x2086, + CWARN_ANSIInUnicodeGroup = 0x2087, + CWARN_UnicodeSurrogateUsed = 0x2088, + CWARN_ReservedCharacter = 0x2089, + CWARN_Info = 0x208A, + CWARN_VirtualKeyWithMnemonicLayout = 0x208B, + CWARN_VirtualCharKeyWithPositionalLayout = 0x208C, + CWARN_StoreAlreadyUsedAsOptionOrCall = 0x208D, + CWARN_StoreAlreadyUsedAsStoreOrCall = 0x208E, + CWARN_StoreAlreadyUsedAsStoreOrOption = 0x208F, + + CWARN_PunctuationInEthnologueCode = 0x2090, + + CWARN_TouchLayoutMissingLayer = 0x2091, + CWARN_TouchLayoutCustomKeyNotDefined = 0x2092, + CWARN_TouchLayoutMissingRequiredKeys = 0x2093, + CWARN_HelpFileMissing = 0x2094, + CWARN_EmbedJsFileMissing = 0x2095, + CWARN_TouchLayoutFileMissing = 0x2096, + CWARN_VisualKeyboardFileMissing = 0x2097, + CWARN_ExtendedShiftFlagsNotSupportedInKeymanWeb = 0x2098, // I4118 + CWARN_TouchLayoutUnidentifiedKey = 0x2099, // I4142 + CHINT_UnreachableKeyCode = 0x109A, // I4141 + + CWARN_CouldNotCopyJsonFile = 0x209B, // I4688 + CWARN_PlatformNotInTargets = 0x209C, + + CWARN_HeaderStatementIsDeprecated = 0x209D, + CWARN_UseNotLastStatementInRule = 0x209E, + + CWARN_TouchLayoutFontShouldBeSameForAllPlatforms = 0x209F, // I4872 + CWARN_InvalidJSONMetadataFile = 0x20A0, // I4872 + CWARN_JSONMetadataOSKFontShouldMatchTouchFont = 0x20A1, // I4872 + + CWARN_DontMixChiralAndNonChiralModifiers = 0x20A3, + CWARN_MixingLeftAndRightModifiers = 0x20A4, + + CWARN_LanguageHeadersDeprecatedInKeyman10 = 0x20A5, + + CHINT_NonUnicodeFile = 0x10A6, + + CWARN_TooManyErrorsOrWarnings = 0x20A7, + + CWARN_HotkeyHasInvalidModifier = 0x20A8, + + CWARN_TouchLayoutSpecialLabelOnNormalKey = 0x20A9, + + CWARN_OptionStoreNameInvalid = 0x20AA, + + CWARN_NulNotFirstStatementInContext = 0x20AB, + CWARN_IfShouldBeAtStartOfContext = 0x20AC, + + CWARN_KeyShouldIncludeNCaps = 0x20AD, + + CHINT_UnreachableRule = 0x10AE, + CHINT_FilenameHasDifferingCase = 0x10AF, + CWARN_MissingFile = 0x20B0; diff --git a/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts b/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts index 2d4b061d56..260a55d522 100644 --- a/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts +++ b/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts @@ -1,4 +1,8 @@ -import { GROUP, KEY, KMXFile, STORE } from "../../../../../common/web/types/src/kmx/kmx"; +import { GROUP, KEY, KMXFile, STORE } from "../../../../../common/web/types/src/kmx/kmx.js"; +import { nl, FTabStop, setupGlobals, IsKeyboardVersion10OrLater } from "./compiler-globals.js"; +import CompilerOptions from "./compiler-options.js"; +import { JavaScript_Name, JavaScript_Rules, JavaScript_Shift, JavaScript_Store } from './javascript-strings.js'; +import { CERR_InvalidBegin, CWARN_DontMixChiralAndNonChiralModifiers, ReportError } from "./messages.js"; function requote(s: string): string { return "'" + s.replaceAll(/(['\\])/, "\\$1") + "'"; @@ -27,8 +31,11 @@ function RequotedString(s: string, RequoteSingleQuotes: boolean = false): string } export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boolean = false): string { - let nl = FDebug ? '\n' : ''; - let FTabStop = FDebug ? ' ' : ''; + let opts: CompilerOptions = { + addCompilerVersion: false, + debug: FDebug + }; + setupGlobals(opts, FDebug?' ':'', FDebug?'\n':'', source.keyboard); // let fgp: GROUP; @@ -255,7 +262,7 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo let fsp = source.keyboard.stores[i]; // I3438 - Save all system stores to the keyboard, for now // I3684 - if (!fsp.fIsDebug) { // and not (fsp.dwSystemID in [TSS_BITMAP, TSS_NAME, TSS_VERSION, TSS_CUSTOMKEYMANEDITION, TSS_CUSTOMKEYMANEDITIONNAME, TSS_KEYMANCOPYRIGHT]) then + if (!isDebugStore(fsp)) { // and not (fsp.dwSystemID in [TSS_BITMAP, TSS_NAME, TSS_VERSION, TSS_CUSTOMKEYMANEDITION, TSS_CUSTOMKEYMANEDITIONNAME, TSS_KEYMANCOPYRIGHT]) then if (fsp.dwSystemID == KMXFile.TSS_COMPARISON) { result += `${FTabStop}this.s${JavaScript_Name(i, fsp.dpName)}=${JavaScript_Store(fsp.line, fsp.dpString)};${nl}`; } @@ -264,17 +271,17 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo } //else if fsp.dwSystemID = TSS_VKDICTIONARY then // I3438, required for vkdictionary // Result := Result + Format('%sthis.s%s=%s;%s', [FTabStop, JavaScript_Name(i, fsp.szName), JavaScript_Store(fsp.line, fsp.dpString), nl]) - else if (fsp.fIsOption && !fsp.fIsReserved) { - result += `${FTabStop}this.s${JavaScript_Name(i,fsp.szName)}=KeymanWeb.KLOAD(this.KI,"${JavaScript_Name(i,fsp.szName,true)}",`+ + else if (isOptionStore(fsp) && !isReservedStore(fsp)) { + result += `${FTabStop}this.s${JavaScript_Name(i,fsp.dpName)}=KeymanWeb.KLOAD(this.KI,"${JavaScript_Name(i,fsp.dpName,true)}",`+ `${JavaScript_Store(fsp.line, fsp.dpString)});${nl}`; if (FOptionStores != '') { FOptionStores += ','; } - FOptionStores += `'s${JavaScript_Name(i,fsp.szName)}`; + FOptionStores += `'s${JavaScript_Name(i, fsp.dpName)}`; } else if (fsp.dwSystemID == KMXFile.TSS_NONE /* aka not fsp.fIsReserved */) { - result += `${FTabStop}this.s${JavaScript_Name(i, fsp.szName)}=${JavaScript_Store(fsp.line, fsp.dpString)};${nl}`; // I3681 + result += `${FTabStop}this.s${JavaScript_Name(i, fsp.dpName)}=${JavaScript_Store(fsp.line, fsp.dpString)};${nl}`; // I3681 } } } @@ -284,7 +291,7 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo // Write the groups out // I853 - begin unicode missing causes crash - if (fk.StartGroup[KMXFile.BEGIN_UNICODE] == 0xFFFFFFFF) { + if (source.keyboard.startGroup.unicode == 0xFFFFFFFF) { ReportError(0, CERR_InvalidBegin, 'A "begin unicode" statement is required to compile a KeymanWeb keyboard'); return null; } @@ -292,11 +299,11 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo result += WriteBeginStatement('gs', source.keyboard.startGroup.unicode); let rec = ExpandSentinel(sBegin_NewContext); - if(rec.Code == CODE_USE) { + if(rec.Code == KMXFile.CODE_USE) { result += WriteBeginStatement('gn', rec.Use.GroupIndex); } rec = ExpandSentinel(sBegin_PostKeystroke); - if(rec.Code == CODE_USE) { + if(rec.Code == KMXFile.CODE_USE) { result += WriteBeginStatement('gpk', rec.Use.GroupIndex); } @@ -346,7 +353,7 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo for (let j = 0; j < fgp.keys.length; j++) { // I1964 let fkp = fgp.keys[j]; if (!RuleIsExcludedByPlatform(fkp)) { - result += FTabstop+FTabstop; // I3681 + result += FTabStop+FTabStop; // I3681 if (HasRules) { result += 'else '; } @@ -380,40 +387,32 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo } } - if Assigned(fgp.dpMatch) then - Result := Result + Format( - '%sif(m==1) {%s'+ - '%s%s%s'+ - '%s}%s', - [FTabstop+FTabstop, nl, - FTabstop+Ftabstop, JavaScript_OutputString(FTabStop + FTabStop + FTabStop, nil, fgp.dpMatch, fgp), nl, - FTabstop+FTabstop, nl]); // I3681 - if Assigned(fgp.dpNoMatch) then - if fgp.fUsingKeys then // I1382 - fixup m=1 to m=g() - Result := Result + Format( - '%sif(!m&&k.KIK(e)) {%s'+ - '%sr=1;%s%s'+ - '%s}%s', - [FTabstop+FTabstop, nl, - FTabstop+FTabstop+FTabstop, JavaScript_OutputString(FTabStop + FTabStop + FTabStop, nil, fgp.dpNoMatch, fgp), nl, - FTabstop+FTabstop, nl]) // I1959. part 2, I2224 // I3681 - else - Result := Result + Format( - '%sif(!m) {%s'+ - '%s%s%s'+ - '%s}%s', - [FTabstop+FTabstop, nl, - FTabstop+FTabstop, JavaScript_OutputString(FTabStop + FTabStop + FTabStop, nil, fgp.dpNoMatch, fgp), nl, - FTabstop+FTabstop, nl]); // I1959 // I3681 - - Result := Result + Format('%sreturn r;%s'+ - '%s};%s', - [FTabstop+FTabstop, nl, - FTabstop, nl]); // I1959 // I3681 - Inc(fgp); - end; + if(fgp.dpMatch) { + result += + `${FTabStop+FTabStop}if(m==1) {${nl}`+ + `${FTabStop+FTabStop+FTabStop}${JavaScript_OutputString(FTabStop + FTabStop + FTabStop, null, fgp.dpMatch, fgp)}${nl}`+ + `${FTabStop+FTabStop}}${nl}`; + } + if(fgp.dpNoMatch) { + if(fgp.fUsingKeys) { // I1382 - fixup m=1 to m=g() + result += + `${FTabStop+FTabStop}if(!m&&k.KIK(e)) {${nl}`+ + `${FTabStop+FTabStop+FTabStop}r=1;${JavaScript_OutputString(FTabStop + FTabStop + FTabStop, null, fgp.dpNoMatch, fgp)}${nl}`+ + `${FTabStop+FTabStop}}${nl}`; // I1959. part 2, I2224 // I3681 + } + else { + result += + `${FTabStop+FTabStop}if(!m) {${nl}`+ + `${FTabStop+FTabStop+FTabStop}${JavaScript_OutputString(FTabStop + FTabStop + FTabStop, null, fgp.dpNoMatch, fgp)}${nl}`+ + `${FTabStop+FTabStop}}${nl}`; + } - for n := 0 to FCallFunctions.Count - 1 do + result += + `${FTabStop+FTabStop}return r;${nl}`+ + `${FTabStop+FTabStop}};${nl}`; + } +/* TODO + for(let n = 0 to FCallFunctions.Count - 1 do begin s := ExtractFilePath(FInFile) + FCallFunctions[n] + '.call_js'; if FileExists(s) then @@ -427,9 +426,9 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo else Result := Result + Format('%sthis.c%d=function(t,e){alert("call(%s) not defined");};%s', [FTabstop, n, FCallFunctions[n], nl]); // I3681 end; - - Result := Result + sEmbedJS + '}' + nl; // I3681 -end; +*/ + result += sEmbedJS + '}' + nl; // I3681 + return result; } /// -- GitLab From 13e80676001583a80717d85f5b8a128ba8908534 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 6 Jan 2023 07:05:09 +0700 Subject: [PATCH 095/214] feat: kmc-kmw more conversions --- .../kmc-kmw/src/compiler/compiler-globals.ts | 2 +- .../src/compiler/javascript-strings.ts | 615 ++++++++++++++++-- .../src/compiler/write-compiled-keyboard.ts | 93 ++- developer/src/kmc-kmw/src/util/util.ts | 244 +++++++ 4 files changed, 884 insertions(+), 70 deletions(-) diff --git a/developer/src/kmc-kmw/src/compiler/compiler-globals.ts b/developer/src/kmc-kmw/src/compiler/compiler-globals.ts index f769c768ba..067fea1d51 100644 --- a/developer/src/kmc-kmw/src/compiler/compiler-globals.ts +++ b/developer/src/kmc-kmw/src/compiler/compiler-globals.ts @@ -1,4 +1,4 @@ -import { KEYBOARD, KMXFile } from "@keymanapp/common-types/src/kmx/kmx"; +import { KEYBOARD, KMXFile } from "../../../../../common/web/types/src/kmx/kmx.js"; import CompilerOptions from "./compiler-options.js"; export let FTabStop: string; diff --git a/developer/src/kmc-kmw/src/compiler/javascript-strings.ts b/developer/src/kmc-kmw/src/compiler/javascript-strings.ts index 8b95d484f0..eaf31a08a3 100644 --- a/developer/src/kmc-kmw/src/compiler/javascript-strings.ts +++ b/developer/src/kmc-kmw/src/compiler/javascript-strings.ts @@ -1,7 +1,9 @@ -import { GROUP, KEY, KMXFile } from "../../../../../common/web/types/src/kmx/kmx.js"; +import { TSentinelRecord, GetSuppChar, ExpandSentinel, incxstr, xstrlen, xstrlen_printing } from "src/util/util.js"; +import { GROUP, KEY, KEYBOARD, KMXFile } from "../../../../../common/web/types/src/kmx/kmx.js"; import { FMnemonic, FTabStop, IsKeyboardVersion10OrLater, nl, options } from "./compiler-globals.js"; -import { CERR_VirtualCharacterKeysNotSupportedInKeymanWeb, CERR_VirtualKeysNotValidForMnemonicLayouts, CWARN_ExtendedShiftFlagsNotSupportedInKeymanWeb, CWARN_OptionStoreNameInvalid, ReportError } from "./messages.js"; +import { CERR_InvalidBegin, CERR_NotSupportedInKeymanWebContext, CERR_VirtualCharacterKeysNotSupportedInKeymanWeb, CERR_VirtualKeysNotValidForMnemonicLayouts, CHINT_UnreachableKeyCode, CWARN_ExtendedShiftFlagsNotSupportedInKeymanWeb, CWARN_OptionStoreNameInvalid, ReportError } from "./messages.js"; +import { FFix183_LadderLength, RuleIsExcludedByPlatform } from "./write-compiled-keyboard.js"; //const SValidIdentifierCharSet = '123'; @@ -36,14 +38,13 @@ export function JavaScript_Name(i: number, pwszName: string, KeepNameForPersiste // For named option stores, we are only supporting the valid identifier // character set, which is a breaking change in 14.0. ReportError(0, CWARN_OptionStoreNameInvalid, - Format('The option store %s should be named with characters in the range A-Z, a-z, 0-9 and _ only.', - [pwszName])); + `The option store ${pwszName} should be named with characters in the range A-Z, a-z, 0-9 and _ only.`); } return result; } } -export function JavaScript_Store(line: number, pwsz: string): string { +export function JavaScript_Store(fk: KEYBOARD, line: number, pwsz: string): string { let ch: number, rec: TSentinelRecord, result: string; const wcsentinel: string = '\uFFFF'; let n = pwsz.indexOf(wcsentinel); @@ -55,13 +56,14 @@ export function JavaScript_Store(line: number, pwsz: string): string { if(pwsz.charCodeAt(0) == KMXFile.UC_SENTINEL) { result += '.'; // UC_SENTINEL values are not supported in stores for KMW < 10.0. } else { - ch = GetSuppChar(pwsz); - if(ch == '"' || ch == '\\') { + ch = GetSuppChar(pwsz, 0); + if(ch == '"'.charCodeAt(0) || ch == '\\'.charCodeAt(0)) { result += '\\'; } result += JavaScript_String(ch); // I2242 } + // TODO: problems with supp chars pwsz = pwsz.substring(1); } result += '"'; @@ -72,10 +74,10 @@ export function JavaScript_Store(line: number, pwsz: string): string { if(result != '[') { result += ','; } - rec = ExpandSentinel(pwsz); + rec = ExpandSentinel(fk, pwsz, 0); if(rec.IsSentinel) { if(rec.Code == KMXFile.CODE_DEADKEY) { - result += `{t:'d',d:${rec.Deadkey.DeadKey}}`; + result += `{t:'d',d:${rec.DeadKey.DeadKey}}`; } else if(rec.Code == KMXFile.CODE_BEEP) { result += `{t:'b'}`; @@ -92,7 +94,7 @@ export function JavaScript_Store(line: number, pwsz: string): string { // end; } else { - ch = GetSuppChar(pwsz); + ch = GetSuppChar(pwsz, 0); result += '"'; // TODO: Refactor the section below into JavaScript_String, as it's // quite common in our code base. @@ -264,49 +266,46 @@ export function JavaScript_ShiftAsString(fkp: KEY, FMnemonic: boolean): string { -function TCompileKeymanWeb.JavaScript_Key(fkp: PFILE_KEY; FMnemonic: Boolean): Integer; -var - n: Integer; - i: Integer; -begin - if not FMnemonic then - begin - if (fkp.ShiftFlags and KMX_ISVIRTUALKEY) = KMX_ISVIRTUALKEY then - begin - Result := Ord(fkp.Key); - end - else - begin +function JavaScript_Key(fkp: KEY, FMnemonic: boolean): number { + let Result: number; + if(!FMnemonic) { + if(fkp.ShiftFlags & KMXFile.ISVIRTUALKEY) { + Result = fkp.Key; + } + else { // Convert the character to a virtual key - n := Pos(fkp.Key, USEnglishShift); - if n = 0 then n := Pos(fkp.Key, USEnglishUnshift); - if n = 0 - then Result := 0 - else Result := Ord(USEnglishValues[n]); - end; - end - else - begin - Result := Ord(fkp.Key); - end; + let n = USEnglishShift.indexOf(String.fromCharCode(fkp.Key)); + if(n < 0) { + n = USEnglishUnshift.indexOf(String.fromCharCode(fkp.Key)); + } + if(n < 0) { + Result = 0; + } + else { + Result = USEnglishValues.charCodeAt(n); + } + } + } + else { + Result = fkp.Key; + } // Check that key is not unreachable (e.g. K_SHIFT, touch-specific special keys 50,000+) - for i := 0 to High(UnreachableKeyCodes) do // I4141 - if Result = UnreachableKeyCodes[i] then - Result := 0; + if(UnreachableKeyCodes.indexOf(Result) >= 0) { + Result = 0; + } - if (Result = 0) or (Result >= Ord(Low(TKeymanWebTouchStandardKey))) then // I4141 - begin - if not FUnreachableKeys.Contains(fkp) then - begin + if (Result == 0 || Result >= Ord(Low(TKeymanWebTouchStandardKey))) { // I4141 + if(!FUnreachableKeys.includes(fkp)) { ReportError(fkp.Line, CHINT_UnreachableKeyCode, 'The rule will never be matched for key '+ FormatKeyForErrorMessage(fkp,FMnemonic)+' because its key code is never fired.'); - FUnreachableKeys.Add(fkp); - end; - end; -end; + FUnreachableKeys.push(fkp); + } + } + return Result; +} /// /// Returns a Javascript representation of a key value, either as a constant (debug mode) @@ -317,7 +316,7 @@ end; /// /// @return string representation of the key value, e.g. 'keyCodes.K_A /* 0x41 */' or '65' /// -function JavaScript_KeyAsString(fkp: KEY, FMnemonic: boolean): string { +export function JavaScript_KeyAsString(fkp: KEY, FMnemonic: boolean): string { if(options.debug) { return ' '+FormatKeyAsString(JavaScript_Key(fkp, FMnemonic)); } else { @@ -325,3 +324,527 @@ function JavaScript_KeyAsString(fkp: KEY, FMnemonic: boolean): string { } } +export function JavaScript_ContextMatch(fk: KEYBOARD, fkp: KEY, context: string): string { + if(IsKeyboardVersion10OrLater()) { + return JavaScript_FullContextValue(fk, fkp, context); + } + else { + return JavaScript_CompositeContextValue(fk, fkp, context); + } +} + +// Used when targeting versions prior to 10.0, before the introduction of FullContextMatch/KFCM. +function JavaScript_CompositeContextValue(fk: KEYBOARD, fkp: KEY, pwsz: string): string { + // Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions +// var + // StartQuotes, Len, Cur: Integer; + // InQuotes: Boolean; + // rec: TSentinelRecord; + + let Result = ''; + + let InQuotes = false; + let Len = JavaScript_ContextLength(pwsz); + let StartQuotes = -1; + let x = 0, Cur = 0; + + while(x < pwsz.length) { + let rec = ExpandSentinel(fk, pwsz, x); + if(rec.IsSentinel) { + if(InQuotes) { + Result += `",${Cur-StartQuotes})`; + InQuotes = false; + } + if(Result != '') { + Result += '&&'; + } + + switch(rec.Code) { + case KMXFile.CODE_ANY: + CheckStoreForInvalidFunctions(fkp, rec.Any.Store); // I1520 + Result += `k.KA(${Cur},k.KC(${Len-Cur},1,t),this.s${JavaScript_Name(rec.Any.StoreIndex, rec.Any.Store.dpName)})`; + break; + case KMXFile.CODE_DEADKEY: + Result += `k.KDM(${Len-Cur},t,${rec.DeadKey.DeadKey})`; + Cur--; // don't increment on deadkeys -- correlates with AdjustIndex function // I3910 + break; + case KMXFile.CODE_NUL: // I2243 + Result += `k.KN(${Len-Cur},t)`; + Cur--; // don't increment on nul -- correlates with AdjustIndex function // I3910 + break; + case KMXFile.CODE_IFOPT: // I3429 + Result += `this.s${JavaScript_Name(rec.IfOpt.StoreIndex1, rec.IfOpt.Store1.dpName)}`+ + `${rec.IfOpt.IsNot == 0 ? '!==':'==='}`+ + `this.s${JavaScript_Name(rec.IfOpt.StoreIndex2,rec.IfOpt.Store2.dpName)}`; // I3429 // I3659 // I3681 + Cur--; // don't increment on ifopt -- correlates with AdjustIndex function // I3910 + break; + case KMXFile.CODE_IFSYSTEMSTORE: // I3430 + Result += `${rec.IfSystemStore.IsNot == 0 ? '!' : ''}`+ + `k.KIFS(${rec.IfSystemStore.dwSystemID},`+ + `this.s${JavaScript_Name(rec.IfSystemStore.StoreIndex,rec.IfSystemStore.Store.dpName)},t)`; + Cur--; // don't increment on ifsystemstore -- correlates with AdjustIndex function // I3910 + break; + case KMXFile.CODE_CONTEXTEX: // I3980 + Result += `k.KCCM(${Len-Cur},${Len-rec.ContextEx.Index+1},t)`; + break; + case KMXFile.CODE_NOTANY: // I3981 + CheckStoreForInvalidFunctions(fkp, rec.Any.Store); // I1520 + Result += `k.KC(${Len-Cur},1,t)!=""&&!k.KA(${Cur},k.KC(${Len-Cur},1,t),`+ + `this.s${JavaScript_Name(rec.Any.StoreIndex, rec.Any.Store.dpName)})`; + break; + default: + ReportError(fkp.Line, CERR_NotSupportedInKeymanWebContext, + `Statement ${GetCodeName(rec.Code)} is not currently supported in context`); // I1971 // I4061 + Result += '/*.*/ 0 '; + } + } + else { + if(!InQuotes) { + if(Result != '') { + Result += '&&'; + } + Result += `k.KCM(${Len-Cur},t,"`; + StartQuotes = Cur; + InQuotes = true; + } + if(rec.ChrVal == '"'.charCodeAt(0) || rec.ChrVal == '\\'.charCodeAt(0)) { + Result += '\\'; + } + Result += Javascript_String(rec.ChrVal); // I2242 + } + + Cur++; + x = incxstr(pwsz, x); + } + + if(InQuotes) { + Result += `",${Cur - StartQuotes})`; + } + return Result; +} + +// Used when targeting versions >= 10.0, after the introduction of FullContextMatch/KFCM. +function JavaScript_FullContextValue(fk: KEYBOARD, fkp: KEY, pwsz: string): string { +/*var + Len: Integer; + rec: TSentinelRecord; + FullContext, Suffix: string; +begin*/ + let Result = ''; + let FullContext = ''; + let Suffix = ''; + let Len = xstrlen(pwsz); + let x = 0; + + while(x < pwsz.length) { + if(FullContext != '') { + FullContext += ','; + } + + let rec = ExpandSentinel(fk, pwsz, x); + if(rec.IsSentinel) { + switch(rec.Code) { + case KMXFile.CODE_ANY: + CheckStoreForInvalidFunctions(fkp, rec.Any.Store); // I1520 + FullContext += `{t:'a',a:this.s${JavaScript_Name(rec.Any.StoreIndex, rec.Any.Store.dpName)}}`; + break; + case KMXFile.CODE_DEADKEY: + FullContext += `{t:'d',d:${rec.DeadKey.DeadKey}}`; + break; + case KMXFile.CODE_NUL: // I2243 + FullContext += `{t:'n'}`; + break; + case KMXFile.CODE_IFOPT: // I3429 + Len--; + if(Suffix != '') { + Suffix += '&&'; + } + if(FullContext == ',') { + FullContext = ''; + } + Suffix += `this.s${JavaScript_Name(rec.IfOpt.StoreIndex1, rec.IfOpt.Store1.dpName)}`+ + `${rec.IfOpt.IsNot == 0 ? '!==' : '==='}this.s${JavaScript_Name(rec.IfOpt.StoreIndex2,rec.IfOpt.Store2.dpName)}`; // I3429 // I3659 // I3681 + break; + case KMXFile.CODE_IFSYSTEMSTORE: // I3430 + Len--; + if(Suffix != '') { + Suffix += '&&'; + } + if(FullContext == ',') { + FullContext = ''; + } + Suffix += `${rec.IfSystemStore.IsNot == 0 ? '!' : ''}k.KIFS(${rec.IfSystemStore.dwSystemID},`+ + `this.s${JavaScript_Name(rec.IfSystemStore.StoreIndex,rec.IfSystemStore.Store.dpName)},t)`; // I3430 // I3659 // I3681 + break; + case KMXFile.CODE_NOTANY: // I3981 + CheckStoreForInvalidFunctions(fkp, rec.Any.Store); // I1520 + FullContext += `{t:'a',a:this.s${JavaScript_Name(rec.Any.StoreIndex, rec.Any.Store.dpName)},n:1}`; + break; + case KMXFile.CODE_CONTEXTEX: + FullContext += `{t:'c',c:${rec.ContextEx.Index}}`; // I4611 + break; + case KMXFile.CODE_INDEX: + FullContext += `{t:'i',i:this.s${JavaScript_Name(rec.Index.StoreIndex, rec.Index.Store.szName)},`+ + `o:${rec.Index.Index}}`; // I4611 + break; + default: + ReportError(fkp.Line, CERR_NotSupportedInKeymanWebContext, `Statement ${GetCodeName(rec.Code)} is not currently supported in context`; // I1971 // I4061 + Result += '/*.*/ 0 '; + } + } + else + { // Simple context character. + FullContext += `'`; + if(rec.ChrVal == '"'.charCodeAt(0) || rec.ChrVal == '\\'.charCodeAt(0) || rec.ChrVal == '\''.charCodeAt(0)) { + FullContext += '\\'; + } + FullContext += Javascript_String(rec.ChrVal) + `'`; // I2242 + } + + x = incxstr(pwsz, x); + } + + if(FullContext != '') { + Result = `k.KFCM(${Len},t,[${FullContext}])`; + } + + if (Result != '' && Suffix != '') { + Result += '&&' + Suffix; + } + else if(Suffix != '') { + Result = Suffix; + } + return Result; +} + +export function JavaScript_OutputString(fk: KEYBOARD, FTabStops: string, fkp: KEY, pwszOutput: string, fgp: GROUP): string { + let InQuotes = false; + let len = 0; + const nlt = nl + FTabStops; // I3681 + +/*var + i, n, len: Integer; + InQuotes: Boolean; + rec: TSentinelRecord; + pwszcontext,pwsz: PWideChar; + Index: Integer; // I3910 + nlt: string;*/ + + const AdjustIndex = function(pwszContext: string, Index: number): number { // I3910 + let Result = Index; + let x = 0; + for(let I = 1; I < Index; I++) { + let recContext = ExpandSentinel(fk, pwszContext, x); + + if(IsKeyboardVersion10OrLater()) { + if(recContext.IsSentinel && [KMXFile.CODE_NUL, KMXFile.CODE_IFOPT, KMXFile.CODE_IFSYSTEMSTORE].includes(recContext.Code)) { + Result--; + } + } + else { + if(recContext.IsSentinel && [KMXFile.CODE_DEADKEY, KMXFile.CODE_NUL,KMXFile. KMXFile.CODE_IFOPT, KMXFile.CODE_IFSYSTEMSTORE].includes(recContext.Code)) { + Result--; + } + } + x = incxstr(pwszContext, x); + } + return Result; + } + + const ContextChar = function(ContextIndex: number, pwszContext: string, xContext: number): string { // I4611 + let Index: number; + let Result = ''; + let recContext = ExpandSentinel(fk, pwszContext, xContext); + if(recContext.IsSentinel) { + if(InQuotes) { // I4611 + Result += '");'; + InQuotes =false; + } + + switch(recContext.Code) { + case KMXFile.CODE_ANY: + Index = AdjustIndex(fkp.dpContext, ContextIndex); // I3910 // I4611 + Result += nlt + `k.KIO(${len},this.s${JavaScript_Name(recContext.Any.StoreIndex, recContext.Any.Store.dpName)},${Index},t);`; // I4611 + break; + case KMXFile.CODE_DEADKEY: + Result += nlt + `k.KDO(${len},t,${recContext.DeadKey.DeadKey});`; // I4611 + break; + case KMXFile.CODE_NOTANY: + // #917: Minimum version required is 14.0: the KCXO function was only added for 14.0 + // Note that this is checked in compiler.cpp as well, so this error can probably never occur + if(!IsKeyboardVersion14OrLater()) { + ReportError(fkp.Line, CERR_NotSupportedInKeymanWebContext, `Statement notany in context() match requires version 14.0+ of KeymanWeb`); // I1971 // I4061 + } + Result += nlt + `k.KCXO(${len},t,${AdjustIndex(fkp.dpContext, xstrlen(fkp.dpContext))},${AdjustIndex(fkp.dpContext, ContextIndex)});`; + break; + case KMXFile.CODE_IFOPT: + case KMXFile.CODE_IFSYSTEMSTORE: + case KMXFile.CODE_NUL: + // These have no output for a context emit + break; + default: + ReportError(fkp.Line, CERR_NotSupportedInKeymanWebContext, `Statement ${GetCodeName(recContext.Code)} is not currently supported in context() match`); // I1971 // I4061 + Result += nlt + '/*.*/ '; // I4611 + } + } + else { + if(!InQuotes) { + Result += nlt + `k.KO(${len},t,"`; // I4611 + InQuotes = true; + } + + if(recContext.ChrVal == '"'.charCodeAt(0) || recContext.ChrVal == '\\'.charCodeAt(0)) { + Result += '\\'; + } + Result += JavaScript_String(recContext.ChrVal); // I2242 + } + return Result; + } + + let Result = ''; + InQuotes = false; + + let pwsz = pwszOutput; + + if(fkp != null) { + if(IsKeyboardVersion10OrLater()) { + // KMW >= 10.0 use the full, sentinel-based length for context deletions. + len = xstrlen(fkp.dpContext); + n = len; + + let x = 0; + for(let i = 0; i < n; i++) { + let rec = ExpandSentinel(fk, fkp.dpContext, x); + if(rec.IsSentinel && [KMXFile.CODE_NUL, KMXFile.CODE_IFOPT, KMXFile.CODE_IFSYSTEMSTORE].includes(rec.Code)) { + len--; + } + x = incxstr(fkp.dpContext, x); + } + } + else { + // KMW < 10.0 exclude all sentinel-based characters, including deadkeys, from direct context deletion. + // Deadkeys have alternative special handling. + len = xstrlen_printing(fkp.dpContext); + } + } + else { + len = -1; + } + + let x = 0; + if(IsKeyboardVersion10OrLater() && pwsz.length > 0) { + if(fgp.fReadOnly) { + Result += nlt+`k.KDC(${len},t);`; // I3681 + } + len = -1; + } + + while(x < pwsz.length) { + let rec = ExpandSentinel(fk, pwsz, x); + if(rec.IsSentinel) { + if(InQuotes) { + if(!fgp.fReadOnly) { + Result += '");'; + } + InQuotes = false; + } + + switch(rec.Code) { + case KMXFile.CODE_CONTEXT: + if (x > 0 || len == -1) { + let xContext = 0; + n = 1; + while(xContext < fkp.dpContext.length) { // I4611 + if(!fgp.fReadOnly) { + Result += ContextChar(n, fkp.dpContext, xContext); + } + n++; + xContext = incxstr(fkp.dpContext, xContext); + } + //Result := Result + Format('k.KO(%d,t,k.KC(%d,%d,t));', [len, xstrlen_printing(fkp.dpContext), xstrlen_printing(fkp.dpContext)]); + } + // else, we don't need to output anything - just don't delete the context + len = -1; + break; + case KMXFile.CODE_CONTEXTEX: + let xContext = 0; + for(let i = 0; i < rec.ContextEx.Index; i++) { + xContext = incxstr(fkp.dpContext, xContext); + } + + if(!fgp.fReadOnly) { + Result += ContextChar(rec.ContextEx.Index, fkp.dpContext, xContext); // I4611 + } + len = -1; + break; + case KMXFile.CODE_BEEP: + if(!fgp.fReadOnly) { + if(len > 0) { + Result += nlt+`k.KO(${len},t,"");`; // I3681 + } + Result += nlt+'k.KB(t);'; // I3681 + } + len = -1; + break; + case KMXFile.CODE_NUL: + if(!fgp.fReadOnly) { + if(len > 0) { + Result += nlt+`k.KO(${len},t,"");`; // I3681 + } + } + len = -1; + break; + case KMXFile.CODE_INDEX: + CheckStoreForInvalidFunctions(fkp, rec.Index.Store); // I1520 + + // This code was wrong. We need to ignore CODE_NUL, CODE_DEADKEY in LHS context index counter. + // This is why the compiler goes wrong -- and why the previous fix was inconsistent. + // The I783 test did not test either of these cases. It seems some of the keyboards were + // compiled in-between the original fix and I783 re-fix, and then happened to work due to + // their simplicity. + + let Index = AdjustIndex(fkp.dpContext, rec.Index.Index); // I3910 + + if(!fgp.fReadOnly) { + Result += nlt+`k.KIO(${len},this.s${JavaScript_Name(rec.Index.StoreIndex, rec.Index.Store.dpName)},${Index},t);`; + // I783 - was: rec.Index.Index [2007-06-04] + // I783 again. Returned to rec.Index.Index. Was previously: [2008-08-15] + // xstrlen(fkp.dpContext) + 1 - rec.Index.Index]); + // this was wrong. Can't find any reason why this change was made + // which suggests it was in response to another bug and poorly traced (bad Marc) + // and not properly tested (bad, bad Marc). Anyway, now tested with test_i783 + } + len = -1; + break; + case KMXFile.CODE_DEADKEY: + if(!fgp.fReadOnly) { + Result += nlt+`k.KDO(${len},t,${rec.DeadKey.DeadKey});`; // I3681 + } + len = -1; + break; + case KMXFile.CODE_USE: + if(!fgp.fReadOnly) { + if(len > 0) { + Result += nlt+`k.KO(${len},t,"");`; // I3681 + } + } + Result += nlt+`r=this.g${JavaScript_Name(rec.Use.GroupIndex, rec.Use.Group.dpName)}(t,e);`; // I1959 // I3681 + Result += nlt+'m=2;'; // #5440 - match desktop behavior + len = -1; + break; + case KMXFile.CODE_CALL: + if(!fgp.fReadOnly) { + if(len > 0) { + Result += nlt+`k.KO(${len},t,"");`; // I3681 + } + } + n = FCallFunctions.IndexOf(CallFunctionName(rec.Call.Store.dpString)); + if(n == -1) { + n = FCallFunctions.Add(CallFunctionName(rec.Call.Store.dpString)); + } + Result += nlt+`r=this.c${n}(t,e);`; // I1959 // I3681 + Result += nlt+'m=2;'; // #5440 - match desktop behavior + len = -1; + break; + case KMXFile.CODE_SETOPT: // I3429 + if(!fgp.fReadOnly) { + if(len > 0) { + Result += nlt+`k.KO(${len},t,"");`; // I3681 + } + } + Result += nlt+`this.s${JavaScript_Name(rec.SetOpt.StoreIndex1,rec.SetOpt.Store1.dpName)}=`+ + `this.s${JavaScript_Name(rec.SetOpt.StoreIndex2,rec.SetOpt.Store2.dpName)};`; + len = -1; + break; + case KMXFile.CODE_RESETOPT: // I3429 + if(!fgp.fReadOnly) { + if(len > 0) { + Result += nlt+`k.KO(${len},t,"");`; // I3681 + } + } + + Result += nlt+`this.s${JavaScript_Name(rec.ResetOpt.StoreIndex,rec.ResetOpt.Store.dpName)}=`+ + `k.KLOAD(this.KI,"${JavaScript_Name(rec.ResetOpt.StoreIndex,rec.ResetOpt.Store.dpName,true)}",`+ + `${JavaScript_Store(fkp.Line, rec.ResetOpt.Store.dpString)});`; // I3429 // I3681 // I3659 + len = -1; + break; + case KMXFile.CODE_SAVEOPT: // I3429 + if(!fgp.fReadOnly) { + if(len > 0) { + Result += nlt+`k.KO(${len},t,"");`; // I3681 + } + } + + Result += nlt+`k.KSAVE("${JavaScript_Name(rec.SaveOpt.StoreIndex,rec.SaveOpt.Store.dpName,true)}",`+ + `this.s${JavaScript_Name(rec.SaveOpt.StoreIndex,rec.SaveOpt.Store.dpName)});`; // I3690 // I3429 // I3659 // I3681 + len = -1; + break; + case KMXFile.CODE_SETSYSTEMSTORE: // I3437 + if(!fgp.fReadOnly) { + if(len > 0) { + Result += nlt+`k.KO(${len},t,"");`; // I3681 + } + } + + Result += nlt+`k.KSETS(${rec.SetSystemStore.dwSystemID},`+ + `this.s${JavaScript_Name(rec.SetSystemStore.StoreIndex, rec.SetSystemStore.Store.dpName)},t);`; // I3681 + len = -1; + break; + default: + ReportError(fkp ? fkp.Line : 0, CERR_NotSupportedInKeymanWebOutput, `Statement ${GetCodeName(rec.Code)} is not currently supported in output`); // I1971 // I4061 + Result += ''; + } + } + else { + if(!InQuotes) { + if(!fgp.fReadOnly) { + if(len > 0) { + Result += nlt+`k.KO(${len},t,"");`; // I3681 + } + } + InQuotes = true; len = -1; + } + + if(!fgp.fReadOnly) { + if(rec.ChrVal == '"'.charCodeAt(0) || rec.ChrVal == '\\'.charCodeAt(0)) { + Result += '\\'; + } + Result += JavaScript_String(rec.ChrVal); // I2242 + } + } + + x = incxstr(pwsz, x); + } + + if(InQuotes) { + if(!fgp.fReadOnly) { + Result += '");'; + } + } + return Result; +} + +function zeroPadHex(n: number, len: number): string { + let result = n.toString(16); + if(result.length < len) { + return + } +} + +/** + * Converts a key value into a constant + * + * @param key A virtual key code + * + * @return string of JavaScript code, e.g. 'keyCodes.K_A /* 0x41 * /' + */ +function FormatKeyAsString(key: number): string { + if(IsKeyboardVersion10OrLater()) { + // Depends on flags defined in KeymanWeb 10.0 + if (key <= 255 && KMWVKeyNames[key] != '') { + Result = 'keyCodes.'+KMWVKeyNames[key]+ ' /* 0x' + zeroPadHex(key, 2) + ' */' + else Result := '0x' + IntToHex(key, 2); + end + else + Result := '0x' + IntToHex(key, 2); +end; diff --git a/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts b/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts index 260a55d522..b065a1ea0f 100644 --- a/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts +++ b/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts @@ -1,9 +1,12 @@ +import { ExpandSentinel, incxstr, xstrlen } from "src/util/util.js"; import { GROUP, KEY, KMXFile, STORE } from "../../../../../common/web/types/src/kmx/kmx.js"; -import { nl, FTabStop, setupGlobals, IsKeyboardVersion10OrLater } from "./compiler-globals.js"; +import { options, nl, FTabStop, setupGlobals, IsKeyboardVersion10OrLater } from "./compiler-globals.js"; import CompilerOptions from "./compiler-options.js"; -import { JavaScript_Name, JavaScript_Rules, JavaScript_Shift, JavaScript_Store } from './javascript-strings.js'; +import { JavaScript_ContextMatch, JavaScript_KeyAsString, JavaScript_Name, JavaScript_OutputString, JavaScript_Rules, JavaScript_Shift, JavaScript_ShiftAsString, JavaScript_Store } from './javascript-strings.js'; import { CERR_InvalidBegin, CWARN_DontMixChiralAndNonChiralModifiers, ReportError } from "./messages.js"; +export let FFix183_LadderLength: number = 100; // TODO: option + function requote(s: string): string { return "'" + s.replaceAll(/(['\\])/, "\\$1") + "'"; } @@ -256,6 +259,19 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo result += `${FTabStop}this.KCSS="${RequotedString(sEmbedCSS)}";${nl}`; } + function isDebugStore(fsp: STORE) { + return fsp.dwSystemID == KMXFile.TSS_DEBUG_LINE; + } + + function isReservedStore(fsp: STORE) { + return fsp.dwSystemID != KMXFile.TSS_NONE; + } + + function isOptionStore(fsp: STORE) { + // TODO: how do we determine this, see CheckStoreUsage() + return false; + } + // Write the stores out FOptionStores = ''; for(let i = 0; i < source.keyboard.stores.length; i++) { @@ -296,15 +312,15 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo return null; } - result += WriteBeginStatement('gs', source.keyboard.startGroup.unicode); + result += WriteBeginStatement(source, 'gs', source.keyboard.startGroup.unicode); - let rec = ExpandSentinel(sBegin_NewContext); + let rec = ExpandSentinel(source.keyboard, sBegin_NewContext, 0); if(rec.Code == KMXFile.CODE_USE) { - result += WriteBeginStatement('gn', rec.Use.GroupIndex); + result += WriteBeginStatement(source, 'gn', rec.Use.GroupIndex); } - rec = ExpandSentinel(sBegin_PostKeystroke); + rec = ExpandSentinel(source.keyboard, sBegin_PostKeystroke, 0); if(rec.Code == KMXFile.CODE_USE) { - result += WriteBeginStatement('gpk', rec.Use.GroupIndex); + result += WriteBeginStatement(source, 'gpk', rec.Use.GroupIndex); } let fgp = source.keyboard.groups[source.keyboard.startGroup.unicode]; @@ -352,7 +368,7 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo else { for (let j = 0; j < fgp.keys.length; j++) { // I1964 let fkp = fgp.keys[j]; - if (!RuleIsExcludedByPlatform(fkp)) { + if (!RuleIsExcludedByPlatform(source, fkp)) { result += FTabStop+FTabStop; // I3681 if (HasRules) { result += 'else '; @@ -365,7 +381,7 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo if (xstrlen(fkp.dpContext) > 0) { result += fgp.fUsingKeys ? '&&' : 'if('; - result += JavaScript_ContextMatch(fkp, fkp.dpContext); + result += JavaScript_ContextMatch(source.keyboard, fkp, fkp.dpContext); } else if (!fgp.fUsingKeys) { result += 'if(1'; @@ -377,10 +393,10 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo `) {${linecomment}${nl}` + FTabStop+FTabStop+FTabStop; if (fgp.fUsingKeys) { // I1959 - result += 'r=m=1;' + JavaScript_OutputString(FTabStop + FTabStop + FTabStop, fkp, fkp.dpOutput, fgp); // I1959 // I3681 + result += 'r=m=1;' + JavaScript_OutputString(source.keyboard, FTabStop + FTabStop + FTabStop, fkp, fkp.dpOutput, fgp); // I1959 // I3681 } else { - result += 'm=1;' + JavaScript_OutputString(FTabStop + FTabStop + FTabStop, fkp, fkp.dpOutput, fgp); // I1959 // I3681 + result += 'm=1;' + JavaScript_OutputString(source.keyboard, FTabStop + FTabStop + FTabStop, fkp, fkp.dpOutput, fgp); // I1959 // I3681 } result += `${nl}${FTabStop}${FTabStop}}${nl}`; // I3681 } @@ -390,20 +406,20 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo if(fgp.dpMatch) { result += `${FTabStop+FTabStop}if(m==1) {${nl}`+ - `${FTabStop+FTabStop+FTabStop}${JavaScript_OutputString(FTabStop + FTabStop + FTabStop, null, fgp.dpMatch, fgp)}${nl}`+ + `${FTabStop+FTabStop+FTabStop}${JavaScript_OutputString(source.keyboard, FTabStop + FTabStop + FTabStop, null, fgp.dpMatch, fgp)}${nl}`+ `${FTabStop+FTabStop}}${nl}`; } if(fgp.dpNoMatch) { if(fgp.fUsingKeys) { // I1382 - fixup m=1 to m=g() result += `${FTabStop+FTabStop}if(!m&&k.KIK(e)) {${nl}`+ - `${FTabStop+FTabStop+FTabStop}r=1;${JavaScript_OutputString(FTabStop + FTabStop + FTabStop, null, fgp.dpNoMatch, fgp)}${nl}`+ + `${FTabStop+FTabStop+FTabStop}r=1;${JavaScript_OutputString(source.keyboard, FTabStop + FTabStop + FTabStop, null, fgp.dpNoMatch, fgp)}${nl}`+ `${FTabStop+FTabStop}}${nl}`; // I1959. part 2, I2224 // I3681 } else { result += `${FTabStop+FTabStop}if(!m) {${nl}`+ - `${FTabStop+FTabStop+FTabStop}${JavaScript_OutputString(FTabStop + FTabStop + FTabStop, null, fgp.dpNoMatch, fgp)}${nl}`+ + `${FTabStop+FTabStop+FTabStop}${JavaScript_OutputString(source.keyboard, FTabStop + FTabStop + FTabStop, null, fgp.dpNoMatch, fgp)}${nl}`+ `${FTabStop+FTabStop}}${nl}`; } @@ -411,6 +427,8 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo `${FTabStop+FTabStop}return r;${nl}`+ `${FTabStop+FTabStop}};${nl}`; } +} + /* TODO for(let n = 0 to FCallFunctions.Count - 1 do begin @@ -433,7 +451,7 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo /// /// Determine the modifiers used in the target keyboard and return a bitmask -/// representing them, or an integer value when not in debug mode +/// representing them, or an number value when not in debug mode /// /// @return string of JavaScript code, e.g. 'modCodes.SHIFT | modCodes.CTRL /* 0x0030 */' /// @@ -442,7 +460,7 @@ function GetKeyboardModifierBitmask(source: KMXFile): string { for(let gp of source.keyboard.groups) { if(gp.fUsingKeys) { for(let kp of gp.keys) { - if(!RuleIsExcludedByPlatform(kp)) { + if(!RuleIsExcludedByPlatform(source, kp)) { bitMask |= JavaScript_Shift(kp, fMnemonic); } } @@ -453,7 +471,7 @@ function GetKeyboardModifierBitmask(source: KMXFile): string { ReportError(0, CWARN_DontMixChiralAndNonChiralModifiers, 'This keyboard contains Ctrl,Alt and LCtrl,LAlt,RCtrl,RAlt sets of modifiers. Use only one or the other set for web target.'); } - if(FDebug) { + if(options.debug) { return FormatModifierAsBitflags(bitMask & KMXFile.KMX_MASK_KEYS); // Exclude KMX_ISVIRTUALKEY, KMX_VIRTUALCHARKEY } @@ -469,7 +487,7 @@ function GetKeyboardModifierBitmask(source: KMXFile): string { /// function JavaScript_SetupDebug() { if(IsKeyboardVersion10OrLater()) { - if(FDebug) { + if(options.debug) { return 'var modCodes = keyman.osk.modifierCodes;'+nl+ FTabStop+'var keyCodes = keyman.osk.keyCodes;'+nl; } @@ -512,14 +530,14 @@ function HasSupplementaryPlaneChars() { end; var - I: Integer; + I: number; fsp: PFILE_STORE; fgp: PFILE_GROUP; - j: Integer; + j: number; fkp: PFILE_KEY; begin fsp := fk.dpStoreArray; - for i := 0 to Integer(fk.cxStoreArray) - 1 do + for i := 0 to number(fk.cxStoreArray) - 1 do begin if StringHasSuppChars(fsp.dpString) then Exit(True); @@ -527,10 +545,10 @@ begin end; fgp := fk.dpGroupArray; - for i := 0 to Integer(fk.cxGroupArray) - 1 do + for i := 0 to number(fk.cxGroupArray) - 1 do begin fkp := fgp.dpKeyArray; - for j := 0 to Integer(fgp.cxKeyArray) - 1 do + for j := 0 to number(fgp.cxKeyArray) - 1 do begin if StringHasSuppChars(fkp.dpContext) or StringHasSuppChars(fkp.dpOutput) then @@ -547,4 +565,33 @@ begin Result := False; end;*/ +} + +export function RuleIsExcludedByPlatform(source: KMXFile, fkp: KEY): boolean { + if(fkp.dpContext == null || fkp.dpContext == '') { + return false; + } + + let x = 0; + while(x < fkp.dpContext.length) { + let rec = ExpandSentinel(source.keyboard, fkp.dpContext, x); + if(rec.IsSentinel && + (rec.Code == KMXFile.CODE_IFSYSTEMSTORE) && + (rec.IfSystemStore.dwSystemID == KMXFile.TSS_PLATFORM) && + rec.IfSystemStore.Store.dpString.includes('native')) { + if(rec.IfSystemStore.Store.dpString.match(/windows|desktop|macosx|linux/)) { + return true; + } + } + x = incxstr(fkp.dpContext, x); + } + + return false; +} + +function WriteBeginStatement(source: KMXFile, name: string, groupIndex: number): string { + const fgp = source.keyboard.groups[groupIndex]; + return `${FTabStop}this.${name}=function(t,e) {${nl}`+ + `${FTabStop+FTabStop}return this.g${JavaScript_Name(groupIndex, fgp.dpName)}(t,e);${nl}`+ + `${FTabStop}};${nl}`; } \ No newline at end of file diff --git a/developer/src/kmc-kmw/src/util/util.ts b/developer/src/kmc-kmw/src/util/util.ts index d663fc490b..1c01a22bf5 100644 --- a/developer/src/kmc-kmw/src/util/util.ts +++ b/developer/src/kmc-kmw/src/util/util.ts @@ -1,3 +1,4 @@ +import { STORE, GROUP, KEYBOARD, KMXFile } from "../../../../../common/web/types/src/kmx/kmx.js"; /** * Verifies that value is an item in the enumeration. @@ -5,3 +6,246 @@ export function isValidEnumValue(enu: T, value: string) { return (Object.values(enu) as string[]).includes(value); } + +export interface TSentinelRecord { + IsSentinel: boolean; + Code?: number; + + Any?: { + StoreIndex: number; + Store: STORE; + }; + Index?: { + StoreIndex: number; + Store: STORE; + Index: number; + }; + DeadKey?: { + DeadKey: number; + }; + Use?: { + GroupIndex: number; + Group: GROUP; + }; + Call?: { + StoreIndex: number; + Store: STORE; + }; + ContextEx?: { + Index: number; + }; + IfOpt?: { + StoreIndex1: number; + Store1: STORE; + StoreIndex2: number; + Store2: STORE; + IsNot: number; + }; + IfSystemStore?: { + dwSystemID: number; + SystemStore: STORE; + StoreIndex: number; + Store: STORE; + IsNot: number; + }; + SetOpt?: { + StoreIndex1: number; + Store1: STORE; + StoreIndex2: number; + Store2: STORE; + }; + SetSystemStore?: { + dwSystemID: number; + SystemStore: STORE; + StoreIndex: number; + Store: STORE; + }; + ResetOpt?: { + StoreIndex: number; + Store: STORE; + }; + SaveOpt?: { + StoreIndex: number; + Store: STORE; + }; + ChrVal?: number; +}; + + +export function ExpandSentinel(fk: KEYBOARD, pwsz: string, x: number): TSentinelRecord { + let result: TSentinelRecord = { + IsSentinel: false + }; + if(pwsz.charCodeAt(x) == KMXFile.UC_SENTINEL) { + result.IsSentinel = true; + x++; + result.Code = pwsz.charCodeAt(x); + x++; + switch(result.Code) { + case KMXFile.CODE_ANY: + case KMXFile.CODE_NOTANY: // I3981 + result.Any.StoreIndex = pwsz.charCodeAt(x) - 1; + result.Any.Store = fk.stores[result.Any.StoreIndex]; + break; + case KMXFile.CODE_INDEX: + result.Index.StoreIndex = pwsz.charCodeAt(x) - 1; + result.Index.Store = fk.stores[result.Index.StoreIndex]; + x++; + result.Index.Index = pwsz.charCodeAt(x); + break; + case KMXFile.CODE_DEADKEY: + result.DeadKey.DeadKey = pwsz.charCodeAt(x) - 1; + break; + case KMXFile.CODE_USE: + result.Use.GroupIndex = pwsz.charCodeAt(x) - 1; + result.Use.Group = fk.groups[result.Use.GroupIndex]; + break; + case KMXFile.CODE_CALL: + result.Call.StoreIndex = pwsz.charCodeAt(x) - 1; + result.Call.Store = fk.stores[result.Call.StoreIndex]; + break; + case KMXFile.CODE_CONTEXTEX: + result.ContextEx.Index = pwsz.charCodeAt(x); + break; + case KMXFile.CODE_SETOPT: // I3429 + result.SetOpt.StoreIndex1 = pwsz.charCodeAt(x) - 1; + result.SetOpt.Store1 = fk.stores[result.SetOpt.StoreIndex1]; + x++; + result.SetOpt.StoreIndex2 = pwsz.charCodeAt(x) - 1; + result.SetOpt.Store2 = fk.stores[result.SetOpt.StoreIndex2]; + break; + case KMXFile.CODE_SETSYSTEMSTORE: // I3437 + result.SetSystemStore.dwSystemID = pwsz.charCodeAt(x) - 1; + result.SetSystemStore.SystemStore = fk.stores.find(s => s.dwSystemID == result.SetSystemStore.dwSystemID) || null; + x++; + result.SetSystemStore.StoreIndex = pwsz.charCodeAt(x) - 1; + result.SetSystemStore.Store = fk.stores[result.SetSystemStore.StoreIndex]; + break; + case KMXFile.CODE_RESETOPT: // I3429 + result.ResetOpt.StoreIndex = pwsz.charCodeAt(x) - 1; + result.ResetOpt.Store = fk.stores[result.ResetOpt.StoreIndex]; + break; + case KMXFile.CODE_SAVEOPT: // I3429 + result.SaveOpt.StoreIndex = pwsz.charCodeAt(x) - 1; + result.SaveOpt.Store = fk.stores[result.SaveOpt.StoreIndex]; + break; + case KMXFile.CODE_IFOPT: // I3429 + result.IfOpt.StoreIndex1 = pwsz.charCodeAt(x) - 1; + result.IfOpt.Store1 = fk.stores[result.IfOpt.StoreIndex1]; + x++; + result.IfOpt.IsNot = pwsz.charCodeAt(x) - 1; // I3429 + x++; + result.IfOpt.StoreIndex2 = pwsz.charCodeAt(x) - 1; + result.IfOpt.Store2 = fk.stores[result.IfOpt.StoreIndex2]; + break; + case KMXFile.CODE_IFSYSTEMSTORE: // I3430 + result.IfSystemStore.dwSystemID = pwsz.charCodeAt(x) - 1; + result.IfSystemStore.SystemStore = fk.stores.find(s => s.dwSystemID == result.IfSystemStore.dwSystemID) || null; + x++; + result.IfSystemStore.IsNot = pwsz.charCodeAt(x) - 1; // I3430 + x++; + result.IfSystemStore.StoreIndex = pwsz.charCodeAt(x) - 1; + result.IfSystemStore.Store = fk.stores[result.IfSystemStore.StoreIndex]; + break; + default: + throw new Error(`Unrecognized system store value ${result.Code}`); + } + } + else { + result.ChrVal = GetSuppChar(pwsz, x); + } + return result; +} + +export function GetSuppChar(p: string, x: number): number { + return p.codePointAt(x); +} + +export function incxstr(p: string, x: number): number { + if(x >= p.length) { + return p.length; + } + + let ch = p.charCodeAt(x); + if(ch != KMXFile.UC_SENTINEL) { + if(ch >= 0xD800 && ch <= 0xDBFF) { + x++; + if(x == p.length) { + return x; + } + ch = p.charCodeAt(x); + if (ch >= 0xDC00 && ch <= 0xDFFF) { + x++; + } + } + else { + x++; + } + return x; + } + + x++; + if(x == p.length) { + return x; + } + + switch(p.charCodeAt(x)) { + case KMXFile.CODE_ANY: x += 2; break; + case KMXFile.CODE_INDEX: x += 3; break; + case KMXFile.CODE_USE: x += 2; break; + case KMXFile.CODE_DEADKEY: x += 2; break; + case KMXFile.CODE_EXTENDED: + x += 3; + while(x <= p.length && p.charCodeAt(x) != KMXFile.UC_SENTINEL_EXTENDEDEND) { + x++; + } + break; + case KMXFile.CODE_CALL: x += 2; break; + case KMXFile.CODE_CONTEXTEX: x += 2; break; + case KMXFile.CODE_NOTANY: x += 2; break; + + case KMXFile.CODE_CLEARCONTEXT: x += 2; break; + case KMXFile.CODE_IFOPT: x += 4; break; + case KMXFile.CODE_IFSYSTEMSTORE: x += 4; break; + case KMXFile.CODE_SETOPT: x += 3; break; + case KMXFile.CODE_SETSYSTEMSTORE: x += 3; break; + case KMXFile.CODE_RESETOPT: x += 2; break; + case KMXFile.CODE_SAVEOPT: x += 2; break; + + default: x++; + } + + if(x >= p.length) { + return p.length; + } + + return x; +} + +export function xstrlen(p: string): number { + let result = 0, x = 0; + while(x < p.length) { + x = incxstr(p, x); + result++; + } + return result; +} + +export function xstrlen_printing(p: string): number { + let result = 0, x = 0; + while(x < p.length) { + if(x + 1 < p.length && p.charCodeAt(x) == KMXFile.UC_SENTINEL) { + switch(p.charCodeAt(x+1)) { + case KMXFile.CODE_DEADKEY: + case KMXFile.CODE_NUL: + case KMXFile.CODE_IFOPT: + case KMXFile.CODE_IFSYSTEMSTORE: + result--; + break; + } + } + x = incxstr(p, x); + result++; + } + return result; +} -- GitLab From 68f97306df2b8275c38e48658777d16c0ff72f4a Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 3 May 2023 12:27:05 +0700 Subject: [PATCH 096/214] feat: temp commit -- kmw compiler --- common/web/types/src/kmx/kmx-file-reader.ts | 42 +- common/web/types/src/kmx/kmx.ts | 34 +- developer/build.sh | 1 + .../src/common/web/test-helpers/index.ts | 13 +- developer/src/kmc-kmw/package-lock.json | 1789 ++++++ developer/src/kmc-kmw/package.json | 6 +- .../src/kmc-kmw/src/compiler/callbacks.ts | 2 + .../kmc-kmw/src/compiler/compiler-globals.ts | 14 +- .../kmc-kmw/src/compiler/compiler-options.ts | 2 + .../src/compiler/javascript-strings.ts | 965 ++- .../src/compiler/keymanweb-compiler.ts | 81 - .../src/kmc-kmw/src/compiler/messages.ts | 5 +- .../src/compiler/write-compiled-keyboard.ts | 231 +- developer/src/kmc-kmw/src/main.ts | 2 +- developer/src/kmc-kmw/src/util/util.ts | 214 +- developer/src/kmc-kmw/test/README.md | 7 + .../kmc-kmw/test/fixtures/khmer_angkor.ico | Bin 0 -> 1150 bytes .../src/kmc-kmw/test/fixtures/khmer_angkor.js | 5463 +++++++++++++++++ .../fixtures/khmer_angkor.keyman-touch-layout | 1950 ++++++ .../kmc-kmw/test/fixtures/khmer_angkor.kmn | 642 ++ .../kmc-kmw/test/fixtures/khmer_angkor.kvks | 206 + .../src/kmc-kmw/test/test-compiler-manual.ts | 49 + developer/src/kmc-kmw/test/test-compiler.ts | 55 + developer/src/kmc-kmw/test/tsconfig.json | 25 + developer/src/kmc-kmw/tsconfig.json | 4 +- 25 files changed, 11397 insertions(+), 405 deletions(-) create mode 100644 developer/src/kmc-kmw/package-lock.json delete mode 100644 developer/src/kmc-kmw/src/compiler/keymanweb-compiler.ts create mode 100644 developer/src/kmc-kmw/test/README.md create mode 100644 developer/src/kmc-kmw/test/fixtures/khmer_angkor.ico create mode 100644 developer/src/kmc-kmw/test/fixtures/khmer_angkor.js create mode 100644 developer/src/kmc-kmw/test/fixtures/khmer_angkor.keyman-touch-layout create mode 100644 developer/src/kmc-kmw/test/fixtures/khmer_angkor.kmn create mode 100644 developer/src/kmc-kmw/test/fixtures/khmer_angkor.kvks create mode 100644 developer/src/kmc-kmw/test/test-compiler-manual.ts create mode 100644 developer/src/kmc-kmw/test/test-compiler.ts create mode 100644 developer/src/kmc-kmw/test/tsconfig.json diff --git a/common/web/types/src/kmx/kmx-file-reader.ts b/common/web/types/src/kmx/kmx-file-reader.ts index 46cfc8eb39..824e56c71d 100644 --- a/common/web/types/src/kmx/kmx-file-reader.ts +++ b/common/web/types/src/kmx/kmx-file-reader.ts @@ -1,4 +1,4 @@ -import { KMXFile, BUILDER_COMP_KEYBOARD, KEYBOARD, STORE } from "./kmx.js"; +import { KMXFile, BUILDER_COMP_KEYBOARD, KEYBOARD, STORE, GROUP, KEY } from "./kmx.js"; import * as r from 'restructure'; export class KmxFileReader { @@ -21,9 +21,18 @@ export class KmxFileReader { return null; } - // TODO: all header fields - let result = new KEYBOARD(); + result.fileVersion = binaryKeyboard.dwFileVersion; + result.flags = binaryKeyboard.dwFlags; + result.hotkey = binaryKeyboard.dwHotKey; + result.keyboardVersion = '0'; //TODO + result.startGroup = { + ansi: binaryKeyboard.StartGroup_ANSI, + unicode: binaryKeyboard.StartGroup_Unicode, + newContext: -1, //TODO + postKeystroke: -1 // TODO + } + let offset = binaryKeyboard.dpStoreArray; for(let i = 0; i < binaryKeyboard.cxStoreArray; i++) { let binaryStore = kmx.COMP_STORE.fromBuffer(source.slice(offset)); @@ -35,7 +44,32 @@ export class KmxFileReader { offset += KMXFile.COMP_STORE_SIZE; } - // TODO: groups + offset = binaryKeyboard.dpGroupArray; + for(let i = 0; i < binaryKeyboard.cxGroupArray; i++) { + let binaryGroup = kmx.COMP_GROUP.fromBuffer(source.slice(offset)); + let group = new GROUP(); + group.dpMatch = this.readString(source, binaryGroup.dpMatch); + group.dpName = this.readString(source, binaryGroup.dpName); + group.dpNoMatch = this.readString(source, binaryGroup.dpNoMatch); + group.fUsingKeys = binaryGroup.fUsingKeys; + group.keys = []; + + let keyOffset = binaryGroup.dpKeyArray; + for(let j = 0; j < binaryGroup.cxKeyArray; j++) { + let binaryKey = kmx.COMP_KEY.fromBuffer(source.slice(keyOffset)); + let key = new KEY(); + key.Key = binaryKey.Key; + key.Line = binaryKey.Line; + key.ShiftFlags = binaryKey.ShiftFlags; + key.dpContext = this.readString(source, binaryKey.dpContext); + key.dpOutput = this.readString(source, binaryKey.dpOutput); + group.keys.push(key); + keyOffset += KMXFile.COMP_KEY_SIZE; + } + + result.groups.push(group); + offset += KMXFile.COMP_GROUP_SIZE; + } // TODO: KMXPlusFile diff --git a/common/web/types/src/kmx/kmx.ts b/common/web/types/src/kmx/kmx.ts index febda9b5e6..cb7af49480 100644 --- a/common/web/types/src/kmx/kmx.ts +++ b/common/web/types/src/kmx/kmx.ts @@ -8,15 +8,15 @@ import * as r from 'restructure'; // kmx-builder will transform these to the corresponding COMP_xxxx export class KEYBOARD { - fileVersion?: number; // dwFileVersion - keyboardVersion?: number; // version + fileVersion?: number; // dwFileVersion (TSS_FILEVERSION) + keyboardVersion?: string; // version (TSS_KEYBOARDVERSION) - startGroup?: { + startGroup: { ansi: number; unicode: number; - newContext: number; - postKeystroke: number; - }; + newContext: number; // TSS_BEGIN_NEWCONTEXT + postKeystroke: number; // TSS_BEGIN_POSTKEYSTROKE + } = {ansi:0xFFFFFFFF, unicode:0xFFFFFFFF, newContext:0xFFFFFFFF, postKeystroke:0xFFFFFFFF}; flags?: number; hotkey?: number; @@ -34,7 +34,7 @@ export class STORE { export class GROUP { dpName: string; - keys: KEY[]; + keys: KEY[] = []; dpMatch: string; dpNoMatch: string; fUsingKeys: boolean; @@ -332,6 +332,21 @@ export class KMXFile { public static readonly ISVIRTUALKEY = 0x4000; // It is a Virtual Key Sequence public static readonly VIRTUALCHARKEY = 0x8000; // Keyman 6.0: Virtual Key Cap Sequence NOT YET + public static readonly MASK_MODIFIER_CHIRAL = KMXFile.LCTRLFLAG | KMXFile.RCTRLFLAG | KMXFile.LALTFLAG | KMXFile.RALTFLAG; + public static readonly MASK_MODIFIER_SHIFT = KMXFile.K_SHIFTFLAG; + public static readonly MASK_MODIFIER_NONCHIRAL = KMXFile.K_CTRLFLAG | KMXFile.K_ALTFLAG; + + public static readonly MASK_STATEKEY = KMXFile.CAPITALFLAG | KMXFile.NOTCAPITALFLAG | + KMXFile.NUMLOCKFLAG | KMXFile.NOTNUMLOCKFLAG | + KMXFile.SCROLLFLAG | KMXFile.NOTSCROLLFLAG; + public static readonly MASK_KEYTYPE = KMXFile.ISVIRTUALKEY | KMXFile.VIRTUALCHARKEY; + + public static readonly MASK_MODIFIER = KMXFile.MASK_MODIFIER_CHIRAL | KMXFile.MASK_MODIFIER_SHIFT | KMXFile.MASK_MODIFIER_NONCHIRAL; + + public static readonly MASK_KEYS = KMXFile.MASK_MODIFIER | KMXFile.MASK_STATEKEY; + public static readonly KMX_MASK_VALID = KMXFile.MASK_KEYS | KMXFile.MASK_KEYTYPE; + + public static readonly K_MODIFIERFLAG = 0x007F; public static readonly K_NOTMODIFIERFLAG = 0xFF00; // I4548 @@ -347,10 +362,7 @@ export class KMXFile { /* In-memory representation of the keyboard */ - public keyboard: KEYBOARD = { - groups: [], - stores: [] - }; + public keyboard: KEYBOARD = new KEYBOARD(); constructor() { diff --git a/developer/build.sh b/developer/build.sh index 76fc3c94a7..0ad6e84bd5 100755 --- a/developer/build.sh +++ b/developer/build.sh @@ -29,6 +29,7 @@ builder_describe \ test \ ":kmcmplib=src/kmcmplib Compiler - .kmn compiler" \ ":kmc-kmn=src/kmc-kmn Compiler - .kmn wrapper Keyboard Module" \ + ":kmc-kmw=src/kmc-kmw Compiler - .kmn Javascript Keyboard Module" \ ":kmc-ldml=src/kmc-ldml Compiler - LDML Keyboard Module" \ ":kmc-model=src/kmc-model Compiler - Lexical Model Module" \ ":kmc-model-info=src/kmc-model-info Compiler - .model_info Module" \ diff --git a/developer/src/common/web/test-helpers/index.ts b/developer/src/common/web/test-helpers/index.ts index e79271227e..7f34107dc9 100644 --- a/developer/src/common/web/test-helpers/index.ts +++ b/developer/src/common/web/test-helpers/index.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import { CompilerEvent, CompilerCallbacks, CompilerSchema, CompilerPathCallbacks, CompilerFileSystemCallbacks } from '@keymanapp/common-types'; +import { CompilerEvent, CompilerCallbacks, CompilerSchema, CompilerPathCallbacks, CompilerFileSystemCallbacks, compilerErrorSeverityName } from '@keymanapp/common-types'; export { verifyCompilerMessagesObject } from './verifyCompilerMessagesObject.js'; // TODO: schemas are only used by kmc-ldml for now, so this works at this @@ -19,6 +19,17 @@ export class TestCompilerCallbacks implements CompilerCallbacks { this.messages = []; } + printMessages() { + this.messages.forEach(event => { + const code = event.code.toString(16); + if(event.line) { + console.log(`${compilerErrorSeverityName(event.code)} ${code} [${event.line}]: ${event.message}`); + } else { + console.log(`${compilerErrorSeverityName(event.code)} ${code}: ${event.message}`); + } + }); + } + hasMessage(code: number): boolean { return this.messages.find((item) => item.code == code) === undefined ? false : true; } diff --git a/developer/src/kmc-kmw/package-lock.json b/developer/src/kmc-kmw/package-lock.json new file mode 100644 index 0000000000..1a8b017d98 --- /dev/null +++ b/developer/src/kmc-kmw/package-lock.json @@ -0,0 +1,1789 @@ +{ + "name": "@keymanapp/kmc-kmw", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@keymanapp/kmc-kmw", + "license": "MIT", + "dependencies": { + "@keymanapp/keyman-version": "*", + "ajv": "^8.11.0", + "restructure": "git+https://github.com/keymanapp/dependency-restructure.git#49d129cf0916d082a7278bb09296fb89cecfcc50", + "semver": "^7.3.7", + "xml2js": "git+https://github.com/keymanapp/dependency-node-xml2js#535fe732dc408d697e0f847c944cc45f0baf0829" + }, + "devDependencies": { + "@types/chai": "^4.1.7", + "@types/mocha": "^5.2.7", + "@types/node": "^10.14.6", + "@types/semver": "^7.3.12", + "@types/xml2js": "^0.4.5", + "c8": "^7.12.0", + "chai": "^4.3.4", + "chalk": "^2.4.2", + "mocha": "^8.4.0", + "ts-node": "^9.1.1", + "typescript": "^4.9.5" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@keymanapp/keyman-version": { + "version": "16.0.139", + "resolved": "https://registry.npmjs.org/@keymanapp/keyman-version/-/keyman-version-16.0.139.tgz", + "integrity": "sha512-hUCgWq+msSTSxra9xOhSxN/nCPxk/hLnPHHTUnFvIc39uxJ/DjNQGkxtsxTdxjCqWZr7frE/2kT7ob9h5Dh5eQ==" + }, + "node_modules/@types/chai": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", + "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", + "dev": true + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/mocha": { + "version": "5.2.7", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "10.17.60", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "node_modules/@types/xml2js": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.11.tgz", + "integrity": "sha512-JdigeAKmCyoJUiQljjr7tQG3if9NkqGUgwEUqBvV0N7LM4HyQk7UXCnusRa1lnvXAEYJ8mw8GtZWioagNztOwA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/c8": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-7.13.0.tgz", + "integrity": "sha512-/NL4hQTv1gBL6J6ei80zu3IiTrmePDKXKXOTLpHvcIWZTVYQlDhVWjjWvkhICylE8EwwnMVzDZugCvdx0/DIIA==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^2.0.0", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-reports": "^3.1.4", + "rimraf": "^3.0.2", + "test-exclude": "^6.0.0", + "v8-to-istanbul": "^9.0.0", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9" + }, + "bin": { + "c8": "bin/c8.js" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.1" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/js-yaml": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.0" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha": { + "version": "8.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.1", + "debug": "4.3.1", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.0.0", + "log-symbols": "4.0.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.20", + "serialize-javascript": "5.0.1", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.1.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 10.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/mocha/node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.1.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", + "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/restructure": { + "version": "3.0.0", + "resolved": "git+ssh://git@github.com/keymanapp/dependency-restructure.git#49d129cf0916d082a7278bb09296fb89cecfcc50", + "integrity": "sha512-2vBFOLc0+dkUb3Pnpl87o+B4SIc3MAm3P8PXT8YFkP51URFGsgTgm3gAnwTX2jXSEd/5eT9n7C733loG6OaVgw==", + "license": "MIT" + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "node_modules/semver": { + "version": "7.3.7", + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-node": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", + "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", + "dev": true, + "dependencies": { + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "typescript": ">=2.7" + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", + "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2" + } + }, + "node_modules/workerpool": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", + "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/xml2js": { + "version": "0.4.23", + "resolved": "git+ssh://git@github.com/keymanapp/dependency-node-xml2js.git#535fe732dc408d697e0f847c944cc45f0baf0829", + "integrity": "sha512-5CS+yWxp0qg8zO7ng/iXrBZm2FXgpiJ+RJ3E0LzRxDXChESqzazRwzl8sXYe8/7je/NfwG4EXcClaRKUkcIvtQ==", + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/developer/src/kmc-kmw/package.json b/developer/src/kmc-kmw/package.json index e41821bf22..e00a3c7e31 100644 --- a/developer/src/kmc-kmw/package.json +++ b/developer/src/kmc-kmw/package.json @@ -13,6 +13,7 @@ }, "scripts": { "build": "tsc -b", + "tsc": "tsc", "test": "cd test && tsc -b && cd .. && c8 mocha", "prepublishOnly": "npm run build" }, @@ -22,7 +23,7 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "dependencies": { - "@keymanapp/keyman-version": "*", + "@keymanapp/common-types": "*", "ajv": "^8.11.0", "restructure": "git+https://github.com/keymanapp/dependency-restructure.git#49d129cf0916d082a7278bb09296fb89cecfcc50", "semver": "^7.3.7", @@ -39,7 +40,8 @@ "chalk": "^2.4.2", "mocha": "^8.4.0", "ts-node": "^9.1.1", - "typescript": "4.6.3" + "typescript": "^4.9.5", + "@keymanapp/kmc-kmn": "*" }, "mocha": { "spec": "build/test/**/test-*.js", diff --git a/developer/src/kmc-kmw/src/compiler/callbacks.ts b/developer/src/kmc-kmw/src/compiler/callbacks.ts index c20a2b078c..bdc7a17464 100644 --- a/developer/src/kmc-kmw/src/compiler/callbacks.ts +++ b/developer/src/kmc-kmw/src/compiler/callbacks.ts @@ -10,3 +10,5 @@ export default interface CompilerCallbacks { loadKvksJsonSchema(): Buffer; reportMessage(event: CompilerEvent): void; }; + +// TODO: eliminate this \ No newline at end of file diff --git a/developer/src/kmc-kmw/src/compiler/compiler-globals.ts b/developer/src/kmc-kmw/src/compiler/compiler-globals.ts index 067fea1d51..bb4874a559 100644 --- a/developer/src/kmc-kmw/src/compiler/compiler-globals.ts +++ b/developer/src/kmc-kmw/src/compiler/compiler-globals.ts @@ -1,14 +1,16 @@ -import { KEYBOARD, KMXFile } from "../../../../../common/web/types/src/kmx/kmx.js"; +import { KMX, CompilerCallbacks } from "@keymanapp/common-types"; import CompilerOptions from "./compiler-options.js"; export let FTabStop: string; export let nl: string; export let FCompilerWarningsAsErrors = false; -export let fk: KEYBOARD; +export let fk: KMX.KEYBOARD; export let FMnemonic: boolean; export let options: CompilerOptions; +export let callbacks: CompilerCallbacks; -export function setupGlobals(_options: CompilerOptions, _tab: string, _nl: string, _keyboard: KEYBOARD) { +export function setupGlobals(_callbacks: CompilerCallbacks, _options: CompilerOptions, _tab: string, _nl: string, _keyboard: KMX.KEYBOARD) { + callbacks = _callbacks; options = _options; FTabStop = _tab; nl = _nl; @@ -16,13 +18,13 @@ export function setupGlobals(_options: CompilerOptions, _tab: string, _nl: strin } export function IsKeyboardVersion10OrLater(): boolean { - return fk.fileVersion >= KMXFile.VERSION_100; + return fk.fileVersion >= KMX.KMXFile.VERSION_100; } export function IsKeyboardVersion14OrLater(): boolean { - return fk.fileVersion >= KMXFile.VERSION_140; + return fk.fileVersion >= KMX.KMXFile.VERSION_140; } export function IsKeyboardVersion15OrLater(): boolean { - return fk.fileVersion >= KMXFile.VERSION_150; + return fk.fileVersion >= KMX.KMXFile.VERSION_150; } diff --git a/developer/src/kmc-kmw/src/compiler/compiler-options.ts b/developer/src/kmc-kmw/src/compiler/compiler-options.ts index 76dd4b5ba4..bcb99c5d43 100644 --- a/developer/src/kmc-kmw/src/compiler/compiler-options.ts +++ b/developer/src/kmc-kmw/src/compiler/compiler-options.ts @@ -11,3 +11,5 @@ export default interface CompilerOptions { */ addCompilerVersion: boolean; }; + +// TODO: we have a shared CompilerOptions intf, eliminate this \ No newline at end of file diff --git a/developer/src/kmc-kmw/src/compiler/javascript-strings.ts b/developer/src/kmc-kmw/src/compiler/javascript-strings.ts index eaf31a08a3..b4ae08829d 100644 --- a/developer/src/kmc-kmw/src/compiler/javascript-strings.ts +++ b/developer/src/kmc-kmw/src/compiler/javascript-strings.ts @@ -1,17 +1,21 @@ -import { TSentinelRecord, GetSuppChar, ExpandSentinel, incxstr, xstrlen, xstrlen_printing } from "src/util/util.js"; -import { GROUP, KEY, KEYBOARD, KMXFile } from "../../../../../common/web/types/src/kmx/kmx.js"; +import { TSentinelRecord, GetSuppChar, ExpandSentinel, incxstr, xstrlen, xstrlen_printing } from "../util/util.js"; +import { KMX } from "@keymanapp/common-types"; -import { FMnemonic, FTabStop, IsKeyboardVersion10OrLater, nl, options } from "./compiler-globals.js"; -import { CERR_InvalidBegin, CERR_NotSupportedInKeymanWebContext, CERR_VirtualCharacterKeysNotSupportedInKeymanWeb, CERR_VirtualKeysNotValidForMnemonicLayouts, CHINT_UnreachableKeyCode, CWARN_ExtendedShiftFlagsNotSupportedInKeymanWeb, CWARN_OptionStoreNameInvalid, ReportError } from "./messages.js"; -import { FFix183_LadderLength, RuleIsExcludedByPlatform } from "./write-compiled-keyboard.js"; +import { FMnemonic, FTabStop, IsKeyboardVersion10OrLater, IsKeyboardVersion14OrLater, nl, options } from "./compiler-globals.js"; +import { CERR_NotSupportedInKeymanWebContext, CERR_NotSupportedInKeymanWebOutput, CERR_NotSupportedInKeymanWebStore, CERR_VirtualCharacterKeysNotSupportedInKeymanWeb, CERR_VirtualKeysNotValidForMnemonicLayouts, CHINT_UnreachableKeyCode, CWARN_ExtendedShiftFlagsNotSupportedInKeymanWeb, CWARN_OptionStoreNameInvalid, ReportError } from "./messages.js"; +import { FFix183_LadderLength, FormatModifierAsBitflags, RuleIsExcludedByPlatform } from "./write-compiled-keyboard.js"; -//const SValidIdentifierCharSet = '123'; +const SValidIdentifierCharSet = /[A-Za-z0-9_]/; + +// TODO: lifecycle +let FUnreachableKeys: KMX.KEY[] = []; +let FCallFunctions: string[] = []; export function JavaScript_Name(i: number, pwszName: string, KeepNameForPersistentStorage: boolean = false): string { // I3659 let FChanged: boolean = false; let p = pwszName; - if((pwszName == null || pwszName == undefined || pwszName == '') || (!isFDebug && !KeepNameForPersistentStorage)) { // I3659 // I3681 + if((pwszName == null || pwszName == undefined || pwszName == '') || (!options.debug && !KeepNameForPersistentStorage)) { // I3659 // I3681 return i.toString(10); // for uniqueness } else { @@ -20,7 +24,7 @@ export function JavaScript_Name(i: number, pwszName: string, KeepNameForPersiste : '_'; // Ensures we cannot overlap numbered instances while(p.length) { let ch = p.charAt(0); - if(SValidIdentifierCharSet.includes(ch)) { // I3681 + if(SValidIdentifierCharSet.test(ch)) { // I3681 result += ch; } else { result += '_'; @@ -44,16 +48,16 @@ export function JavaScript_Name(i: number, pwszName: string, KeepNameForPersiste } } -export function JavaScript_Store(fk: KEYBOARD, line: number, pwsz: string): string { +export function JavaScript_Store(fk: KMX.KEYBOARD, line: number, pwsz: string): string { let ch: number, rec: TSentinelRecord, result: string; - const wcsentinel: string = '\uFFFF'; + const wcsentinel: string = String.fromCharCode(KMX.KMXFile.UC_SENTINEL); let n = pwsz.indexOf(wcsentinel); // Start: plain text store. Always use for < 10.0, conditionally for >= 10.0. - if(n == 0 || !IsKeyboardVersion10OrLater) { + if(n < 0 || !IsKeyboardVersion10OrLater()) { result = '"'; while(pwsz.length) { - if(pwsz.charCodeAt(0) == KMXFile.UC_SENTINEL) { + if(pwsz.charCodeAt(0) == KMX.KMXFile.UC_SENTINEL) { result += '.'; // UC_SENTINEL values are not supported in stores for KMW < 10.0. } else { ch = GetSuppChar(pwsz, 0); @@ -70,16 +74,17 @@ export function JavaScript_Store(fk: KEYBOARD, line: number, pwsz: string): stri } else { result = '['; - while(pwsz.length) { + let x = 0; + while(x < pwsz.length) { if(result != '[') { result += ','; } - rec = ExpandSentinel(fk, pwsz, 0); + rec = ExpandSentinel(fk, pwsz, x); if(rec.IsSentinel) { - if(rec.Code == KMXFile.CODE_DEADKEY) { + if(rec.Code == KMX.KMXFile.CODE_DEADKEY) { result += `{t:'d',d:${rec.DeadKey.DeadKey}}`; } - else if(rec.Code == KMXFile.CODE_BEEP) { + else if(rec.Code == KMX.KMXFile.CODE_BEEP) { result += `{t:'b'}`; } else { //if rec.Code = CODE_EXTENDED then @@ -94,7 +99,7 @@ export function JavaScript_Store(fk: KEYBOARD, line: number, pwsz: string): stri // end; } else { - ch = GetSuppChar(pwsz, 0); + ch = GetSuppChar(pwsz, x); result += '"'; // TODO: Refactor the section below into JavaScript_String, as it's // quite common in our code base. @@ -104,7 +109,7 @@ export function JavaScript_Store(fk: KEYBOARD, line: number, pwsz: string): stri result += JavaScript_String(ch) + '"'; // I2242 } - pwsz = pwsz.substring(1); + x = incxstr(pwsz, x); } result += ']'; } @@ -119,9 +124,9 @@ export function JavaScript_String(ch: number): string { // I2242 case 13: return '\\r'; } if(ch < 9) { - return '\\x0'+ch.toString(16); + return '\\x0'+ch.toString(16).toUpperCase(); } else { - return '\\x'+ch.toString(16); + return '\\x'+ch.toString(16).toUpperCase(); } } else { @@ -129,8 +134,35 @@ export function JavaScript_String(ch: number): string { // I2242 } } -export function JavaScript_Rules(fgp: GROUP): string { - let IsEqualKey = function(k1: KEY, k2: KEY): boolean { +function JavaScript_Rule(FTabStops: string, FElse: string, fk: KMX.KEYBOARD, fgp: KMX.GROUP, fkp: KMX.KEY): string { + let predicate: string = '1', linecomment: string = '', FIndent: string; + let result = ''; + + if(fkp.Line > 0 && options.debug) { // I4384 + linecomment = ' // Line '+fkp.Line.toString(); // I4373 + } + + if(xstrlen(fkp.dpContext) > 0) { + predicate = JavaScript_ContextMatch(fk, fkp, fkp.dpContext); + } + + FIndent = FTabStops+FTabStop; + result = `${FTabStops}${FElse}if(${predicate}){${nl}`; + + if(fgp.fUsingKeys) { + result += `${FIndent}r=m=1;${linecomment}${JavaScript_OutputString(fk, FIndent, fkp, fkp.dpOutput, fgp)}`; // I1959 // I3681 + } + else { + result += `${FIndent}m=1;${linecomment}${JavaScript_OutputString(fk, FIndent, fkp, fkp.dpOutput, fgp)}`; // I1959 // I3681 + } + + result += `${nl}${FTabStops}}${nl}`; + return result; +} + + +export function JavaScript_Rules(keyboard: KMX.KEYBOARD, fMnemonic: boolean, fgp: KMX.GROUP): string { + let IsEqualKey = function(k1: KMX.KEY, k2: KMX.KEY): boolean { return ( (JavaScript_Key(k1, FMnemonic) == JavaScript_Key(k2, FMnemonic)) && (JavaScript_Shift(k1, FMnemonic) == JavaScript_Shift(k2, FMnemonic)) @@ -148,8 +180,8 @@ export function JavaScript_Rules(fgp: GROUP): string { let j = 0; let Counter = 0; while(j < fgp.keys.length) { // I1964 - if(!processed_rule[j] && !RuleIsExcludedByPlatform(fkp)) { - let fkp = fgp.keys[j]; + let fkp = fgp.keys[j]; + if(!processed_rule[j] && !RuleIsExcludedByPlatform(keyboard, fkp)) { // Break down by key code // We know the rules are sorted by context length and then key code. // First pass, break the grouping down by key code. @@ -168,9 +200,9 @@ export function JavaScript_Rules(fgp: GROUP): string { let LocalCounter = 0; while (j < fgp.keys.length) { fkp = fgp.keys[j]; - if (!processed_rule[j] && !RuleIsExcludedByPlatform(fkp) && IsEqualKey(fkp, fkp2)) { + if (!processed_rule[j] && !RuleIsExcludedByPlatform(keyboard, fkp) && IsEqualKey(fkp, fkp2)) { processed_rule[j] = true; - result += JavaScript_Rule(FTabStop + FTabStop + FTabStop, LocalHasRules ? 'else ' : '', fgp, fkp); + result += JavaScript_Rule(FTabStop + FTabStop + FTabStop, LocalHasRules ? 'else ' : '', keyboard, fgp, fkp); LocalCounter++; if (FFix183_LadderLength != 0 && (LocalCounter % FFix183_LadderLength) == 0) { @@ -188,7 +220,7 @@ export function JavaScript_Rules(fgp: GROUP): string { } else { // TODO: context character level switches instead of full context comparisons - result += JavaScript_Rule(FTabStop + FTabStop + FTabStop, HasRules ? 'else ' : '', fgp, fkp); + result += JavaScript_Rule(FTabStop + FTabStop + FTabStop, HasRules ? 'else ' : '', keyboard, fgp, fkp); HasRules = true; Counter++; j++; @@ -207,14 +239,42 @@ export function JavaScript_Rules(fgp: GROUP): string { return result; } -export function JavaScript_Shift(fkp: KEY, FMnemonic: boolean): number { +const + USEnglishUnshift: string = ' `' + '1234567890' + '-' + '=' + 'qwertyuiop' + '[' + ']' + '\\' + 'asdfghjkl' + ';' + '\'' + 'zxcvbnm' + ',' + '.' + '/', + USEnglishShift: string = 0xFF + '~' + '!@#$%^&*()' + '_' + '+' + 'QWERTYUIOP' + '{' + '}' + '|' + 'ASDFGHJKL' + ':' + '"' + 'ZXCVBNM' + '<' + '>' + '?', + USEnglishValues: string = 0x20 + 0xc0 + '1234567890' + 0xbd + 0xbb + 'QWERTYUIOP' + 0xdb + 0xdd + 0xdc + 'ASDFGHJKL' + 0xba + 0xde + 'ZXCVBNM' + 0xbc + 0xbe + 0xbf, + UnreachableKeyCodes: number[] = [ // I4141 + 0x00, // &H0 + 0x01, //VK_LBUTTON, // &H1 + 0x02, //VK_RBUTTON, // &H2 + 0x03, //VK_CANCEL, // &H3 + 0x04, //VK_MBUTTON, // &H4 + 0x05, // &H5 + 0x06, // &H6 + 0x07, // &H7 + 0x0A, // &HA + 0x0B, // &HB + 0x0E, // &HE + 0x0F, // &HF + 0x10, //VK_SHIFT, // &H10 + 0x11, //VK_CONTROL, // &H11 + 0x12, //VK_MENU, // &H12 + 0x13, //VK_PAUSE, // &H13 + 0x14, //VK_CAPITAL, // &H14 + 0x1B, //VK_ESCAPE, // &H1B + + 0x90, //VK_NUMLOCK, // &H90 + 0x91 //VK_SCROLL // &H91 + ]; + +export function JavaScript_Shift(fkp: KMX.KEY, FMnemonic: boolean): number { if (FMnemonic) { - if (fkp.ShiftFlags & KMXFile.VIRTUALCHARKEY) { + if (fkp.ShiftFlags & KMX.KMXFile.VIRTUALCHARKEY) { ReportError(fkp.Line, CERR_VirtualCharacterKeysNotSupportedInKeymanWeb, 'Virtual character keys not currently supported in KeymanWeb'); // I1971 // I4061 return 0; } - if (fkp.ShiftFlags & KMXFile.ISVIRTUALKEY && fkp.Key <= 255) { + if (fkp.ShiftFlags & KMX.KMXFile.ISVIRTUALKEY && fkp.Key <= 255) { // We prohibit K_ keys for mnemonic layouts. We don't block T_ and U_ keys. // TODO: this doesn't resolve the issue of, e.g. SHIFT+K_SPACE // https://github.com/keymanapp/keyman/issues/265 @@ -223,27 +283,27 @@ export function JavaScript_Shift(fkp: KEY, FMnemonic: boolean): number { } } - if (fkp.ShiftFlags & KMXFile.ISVIRTUALKEY) { + if (fkp.ShiftFlags & KMX.KMXFile.ISVIRTUALKEY) { if(IsKeyboardVersion10OrLater()) { // Full chiral modifier and state key support starts with KeymanWeb 10.0 return fkp.ShiftFlags; } // Non-chiral support only and no support for state keys - if (fkp.ShiftFlags & (KMXFile.LCTRLFLAG | KMXFile.RCTRLFLAG | KMXFile.LALTFLAG | KMXFile.RALTFLAG)) { // I4118 + if (fkp.ShiftFlags & (KMX.KMXFile.LCTRLFLAG | KMX.KMXFile.RCTRLFLAG | KMX.KMXFile.LALTFLAG | KMX.KMXFile.RALTFLAG)) { // I4118 ReportError(fkp.Line, CWARN_ExtendedShiftFlagsNotSupportedInKeymanWeb, 'Extended shift flags LALT, RALT, LCTRL, RCTRL are not supported in KeymanWeb'); } if (fkp.ShiftFlags & ( - KMXFile.CAPITALFLAG | KMXFile.NOTCAPITALFLAG | KMXFile.NUMLOCKFLAG | KMXFile.NOTNUMLOCKFLAG | - KMXFile.SCROLLFLAG | KMXFile.NOTSCROLLFLAG)) { // I4118 + KMX.KMXFile.CAPITALFLAG | KMX.KMXFile.NOTCAPITALFLAG | KMX.KMXFile.NUMLOCKFLAG | KMX.KMXFile.NOTNUMLOCKFLAG | + KMX.KMXFile.SCROLLFLAG | KMX.KMXFile.NOTSCROLLFLAG)) { // I4118 ReportError(fkp.Line, CWARN_ExtendedShiftFlagsNotSupportedInKeymanWeb, 'Extended shift flags CAPS and NCAPS are not supported in KeymanWeb'); } - return KMXFile.ISVIRTUALKEY | (fkp.ShiftFlags & (KMXFile.K_SHIFTFLAG | KMXFile.K_CTRLFLAG | KMXFile.K_ALTFLAG)); + return KMX.KMXFile.ISVIRTUALKEY | (fkp.ShiftFlags & (KMX.KMXFile.K_SHIFTFLAG | KMX.KMXFile.K_CTRLFLAG | KMX.KMXFile.K_ALTFLAG)); } - return USEnglishShift.includes(fkp.Key) ? KMXFile.ISVIRTUALKEY | KMXFile.K_SHIFTFLAG : KMXFile.ISVIRTUALKEY; + return USEnglishShift.includes(String.fromCharCode(fkp.Key)) ? KMX.KMXFile.ISVIRTUALKEY | KMX.KMXFile.K_SHIFTFLAG : KMX.KMXFile.ISVIRTUALKEY; } /** @@ -257,19 +317,364 @@ export function JavaScript_Shift(fkp: KEY, FMnemonic: boolean): number { * 'modCodes.SHIFT | modCodes.CAPS | modCodes.VIRTUAL_KEY /* 0x4110 * /' or * '16656' */ -export function JavaScript_ShiftAsString(fkp: KEY, FMnemonic: boolean): string { +export function JavaScript_ShiftAsString(fkp: KMX.KEY, FMnemonic: boolean): string { if(!options.debug) { return JavaScript_Shift(fkp, FMnemonic).toString(); } return ' '+FormatModifierAsBitflags(JavaScript_Shift(fkp, FMnemonic)); } +const VKeyNames = [ // from vkeys.h +// Key Codes +"K_?00", // &H0 +"K_LBUTTON", // &H1 +"K_RBUTTON", // &H2 +"K_CANCEL", // &H3 +"K_MBUTTON", // &H4 +"K_?05", // &H5 +"K_?06", // &H6 +"K_?07", // &H7 +"K_BKSP", // &H8 +"K_TAB", // &H9 +"K_?0A", // &HA +"K_?0B", // &HB +"K_KP5", // &HC +"K_ENTER", // &HD +"K_?0E", // &HE +"K_?0F", // &HF +"K_SHIFT", // &H10 +"K_CONTROL", // &H11 +"K_ALT", // &H12 +"K_PAUSE", // &H13 +"K_CAPS", // &H14 +"K_KANJI?15", // &H15 +"K_KANJI?16", // &H16 +"K_KANJI?17", // &H17 +"K_KANJI?18", // &H18 +"K_KANJI?19", // &H19 +"K_?1A", // &H1A +"K_ESC", // &H1B +"K_KANJI?1C", // &H1C +"K_KANJI?1D", // &H1D +"K_KANJI?1E", // &H1E +"K_KANJI?1F", // &H1F +"K_SPACE", // &H20 +"K_PGUP", // &H21 +"K_PGDN", // &H22 +"K_END", // &H23 +"K_HOME", // &H24 +"K_LEFT", // &H25 +"K_UP", // &H26 +"K_RIGHT", // &H27 +"K_DOWN", // &H28 +"K_SEL", // &H29 +"K_PRINT", // &H2A +"K_EXEC", // &H2B +"K_PRTSCN", // &H2C +"K_INS", // &H2D +"K_DEL", // &H2E +"K_HELP", // &H2F +"K_0", // &H30 +"K_1", // &H31 +"K_2", // &H32 +"K_3", // &H33 +"K_4", // &H34 +"K_5", // &H35 +"K_6", // &H36 +"K_7", // &H37 +"K_8", // &H38 +"K_9", // &H39 +"K_?3A", // &H3A +"K_?3B", // &H3B +"K_?3C", // &H3C +"K_?3D", // &H3D +"K_?3E", // &H3E +"K_?3F", // &H3F +"K_?40", // &H40 + +"K_A", // &H41 +"K_B", // &H42 +"K_C", // &H43 +"K_D", // &H44 +"K_E", // &H45 +"K_F", // &H46 +"K_G", // &H47 +"K_H", // &H48 +"K_I", // &H49 +"K_J", // &H4A +"K_K", // &H4B +"K_L", // &H4C +"K_M", // &H4D +"K_N", // &H4E +"K_O", // &H4F +"K_P", // &H50 +"K_Q", // &H51 +"K_R", // &H52 +"K_S", // &H53 +"K_T", // &H54 +"K_U", // &H55 +"K_V", // &H56 +"K_W", // &H57 +"K_X", // &H58 +"K_Y", // &H59 +"K_Z", // &H5A +"K_?5B", // &H5B +"K_?5C", // &H5C +"K_?5D", // &H5D +"K_?5E", // &H5E +"K_?5F", // &H5F +"K_NP0", // &H60 +"K_NP1", // &H61 +"K_NP2", // &H62 +"K_NP3", // &H63 +"K_NP4", // &H64 +"K_NP5", // &H65 +"K_NP6", // &H66 +"K_NP7", // &H67 +"K_NP8", // &H68 +"K_NP9", // &H69 +"K_NPSTAR", // &H6A +"K_NPPLUS", // &H6B +"K_SEPARATOR", // &H6C +"K_NPMINUS", // &H6D +"K_NPDOT", // &H6E +"K_NPSLASH", // &H6F +"K_F1", // &H70 +"K_F2", // &H71 +"K_F3", // &H72 +"K_F4", // &H73 +"K_F5", // &H74 +"K_F6", // &H75 +"K_F7", // &H76 +"K_F8", // &H77 +"K_F9", // &H78 +"K_F10", // &H79 +"K_F11", // &H7A +"K_F12", // &H7B +"K_F13", // &H7C +"K_F14", // &H7D +"K_F15", // &H7E +"K_F16", // &H7F +"K_F17", // &H80 +"K_F18", // &H81 +"K_F19", // &H82 +"K_F20", // &H83 +"K_F21", // &H84 +"K_F22", // &H85 +"K_F23", // &H86 +"K_F24", // &H87 + +"K_?88", // &H88 +"K_?89", // &H89 +"K_?8A", // &H8A +"K_?8B", // &H8B +"K_?8C", // &H8C +"K_?8D", // &H8D +"K_?8E", // &H8E +"K_?8F", // &H8F + +"K_NUMLOCK", // &H90 +"K_SCROLL", // &H91 + +"K_?92", // &H92 +"K_?93", // &H93 +"K_?94", // &H94 +"K_?95", // &H95 +"K_?96", // &H96 +"K_?97", // &H97 +"K_?98", // &H98 +"K_?99", // &H99 +"K_?9A", // &H9A +"K_?9B", // &H9B +"K_?9C", // &H9C +"K_?9D", // &H9D +"K_?9E", // &H9E +"K_?9F", // &H9F +"K_?A0", // &HA0 +"K_?A1", // &HA1 +"K_?A2", // &HA2 +"K_?A3", // &HA3 +"K_?A4", // &HA4 +"K_?A5", // &HA5 +"K_?A6", // &HA6 +"K_?A7", // &HA7 +"K_?A8", // &HA8 +"K_?A9", // &HA9 +"K_?AA", // &HAA +"K_?AB", // &HAB +"K_?AC", // &HAC +"K_?AD", // &HAD +"K_?AE", // &HAE +"K_?AF", // &HAF +"K_?B0", // &HB0 +"K_?B1", // &HB1 +"K_?B2", // &HB2 +"K_?B3", // &HB3 +"K_?B4", // &HB4 +"K_?B5", // &HB5 +"K_?B6", // &HB6 +"K_?B7", // &HB7 +"K_?B8", // &HB8 +"K_?B9", // &HB9 + +"K_COLON", // &HBA +"K_EQUAL", // &HBB +"K_COMMA", // &HBC +"K_HYPHEN", // &HBD +"K_PERIOD", // &HBE +"K_SLASH", // &HBF +"K_BKQUOTE", // &HC0 + +"K_?C1", // &HC1 +"K_?C2", // &HC2 +"K_?C3", // &HC3 +"K_?C4", // &HC4 +"K_?C5", // &HC5 +"K_?C6", // &HC6 +"K_?C7", // &HC7 +"K_?C8", // &HC8 +"K_?C9", // &HC9 +"K_?CA", // &HCA +"K_?CB", // &HCB +"K_?CC", // &HCC +"K_?CD", // &HCD +"K_?CE", // &HCE +"K_?CF", // &HCF +"K_?D0", // &HD0 +"K_?D1", // &HD1 +"K_?D2", // &HD2 +"K_?D3", // &HD3 +"K_?D4", // &HD4 +"K_?D5", // &HD5 +"K_?D6", // &HD6 +"K_?D7", // &HD7 +"K_?D8", // &HD8 +"K_?D9", // &HD9 +"K_?DA", // &HDA + +"K_LBRKT", // &HDB +"K_BKSLASH", // &HDC +"K_RBRKT", // &HDD +"K_QUOTE", // &HDE +"K_oDF", // &HDF +"K_oE0", // &HE0 +"K_oE1", // &HE1 +"K_oE2", // &HE2 +"K_oE3", // &HE3 +"K_oE4", // &HE4 + +"K_?E5", // &HE5 + +"K_oE6", // &HE6 + +"K_?E7", // &HE7 +"K_?E8", // &HE8 + +"K_oE9", // &HE9 +"K_oEA", // &HEA +"K_oEB", // &HEB +"K_oEC", // &HEC +"K_oED", // &HED +"K_oEE", // &HEE +"K_oEF", // &HEF +"K_oF0", // &HF0 +"K_oF1", // &HF1 +"K_oF2", // &HF2 +"K_oF3", // &HF3 +"K_oF4", // &HF4 +"K_oF5", // &HF5 + +"K_?F6", // &HF6 +"K_?F7", // &HF7 +"K_?F8", // &HF8 +"K_?F9", // &HF9 +"K_?FA", // &HFA +"K_?FB", // &HFB +"K_?FC", // &HFC +"K_?FD", // &HFD +"K_?FE", // &HFE +"K_?FF" // &HFF +]; + +const enum + TKeymanWebTouchStandardKey { + K_LOPT = 50001, + K_ROPT = 50002, + K_NUMERALS = 50003, + K_SYMBOLS = 50004, + K_CURRENCIES = 50005, + K_UPPER = 50006, + K_LOWER = 50007, + K_ALPHA = 50008, + K_SHIFTED = 50009, + K_ALTGR = 50010, + K_TABBACK = 50011, + K_TABFWD = 50012 + }; + +function FormatKeyForErrorMessage(fkp: KMX.KEY, FMnemonic: boolean): string { + function FormatShift(ShiftFlags: number): string { + const + mask: string[] = [ + 'LCTRL', // 0X0001 + 'RCTRL', // 0X0002 + 'LALT', // 0X0004 + 'RALT', // 0X0008 + + 'SHIFT', // 0X0010 + 'CTRL', // 0X0020 + 'ALT', // 0X0040 + + '???', // Reserved + + 'CAPS', // 0X0100 + 'NCAPS', // 0X0200 + + 'NUMLOCK', // 0X0400 + 'NNUMLOCK', // 0X0800 + + 'SCROLLLOCK', // 0X1000 + 'NSCROLLLOCK' // 0X2000 + ]; + + let result = ''; + for(let i = 0; i < mask.length; i++) { + if(ShiftFlags & (1 << i)) { + result += mask[i] + ' '; + } + } + return result; + } + let result: string; + if(!FMnemonic) { + if (fkp.ShiftFlags & KMX.KMXFile.ISVIRTUALKEY) { + if(fkp.Key < 256) { + result = `[${FormatShift(fkp.ShiftFlags)}${VKeyNames[fkp.Key]}]`; + } + else { + result = `[${FormatShift(fkp.ShiftFlags)}K_${fkp.Key.toString(16).toUpperCase()}]`; + } + } + else { + result = `'${String.fromCharCode(fkp.Key)}'`; + } + } + else { + if (fkp.ShiftFlags & KMX.KMXFile.VIRTUALCHARKEY) { + result = `[${FormatShift(fkp.ShiftFlags)}'${String.fromCharCode(fkp.Key)}']`; + } + else { + result = `'${String.fromCharCode(fkp.Key)}'`; + } + } + return result; +} -function JavaScript_Key(fkp: KEY, FMnemonic: boolean): number { +function JavaScript_Key(fkp: KMX.KEY, FMnemonic: boolean): number { let Result: number; if(!FMnemonic) { - if(fkp.ShiftFlags & KMXFile.ISVIRTUALKEY) { + if(fkp.ShiftFlags & KMX.KMXFile.ISVIRTUALKEY) { Result = fkp.Key; } else { @@ -296,7 +701,7 @@ function JavaScript_Key(fkp: KEY, FMnemonic: boolean): number { Result = 0; } - if (Result == 0 || Result >= Ord(Low(TKeymanWebTouchStandardKey))) { // I4141 + if (Result == 0 || Result >= TKeymanWebTouchStandardKey.K_LOPT) { // I4141 if(!FUnreachableKeys.includes(fkp)) { ReportError(fkp.Line, CHINT_UnreachableKeyCode, 'The rule will never be matched for key '+ @@ -316,7 +721,7 @@ function JavaScript_Key(fkp: KEY, FMnemonic: boolean): number { /// /// @return string representation of the key value, e.g. 'keyCodes.K_A /* 0x41 */' or '65' /// -export function JavaScript_KeyAsString(fkp: KEY, FMnemonic: boolean): string { +export function JavaScript_KeyAsString(fkp: KMX.KEY, FMnemonic: boolean): string { if(options.debug) { return ' '+FormatKeyAsString(JavaScript_Key(fkp, FMnemonic)); } else { @@ -324,7 +729,7 @@ export function JavaScript_KeyAsString(fkp: KEY, FMnemonic: boolean): string { } } -export function JavaScript_ContextMatch(fk: KEYBOARD, fkp: KEY, context: string): string { +export function JavaScript_ContextMatch(fk: KMX.KEYBOARD, fkp: KMX.KEY, context: string): string { if(IsKeyboardVersion10OrLater()) { return JavaScript_FullContextValue(fk, fkp, context); } @@ -333,8 +738,44 @@ export function JavaScript_ContextMatch(fk: KEYBOARD, fkp: KEY, context: string) } } +function JavaScript_ContextLength(Context: string): number { + return xstrlen_printing(Context); +} + +const + KMXCodeNames: string[] = [ + '', + 'any', 'index', 'context', 'nul', 'use', 'return', 'beep', 'deadkey', + '', + 'extended', '', 'switch', 'key', 'clearcontext', 'call', + '', 'contextex', 'notany', + 'set', 'if', 'save', 'reset', // I3429 + 'if(&system)', 'set(&system)']; // I3430 // I3437 + +function GetCodeName(code: number): string { + if (code >= 0 && code < KMXCodeNames.length && KMXCodeNames[code] != '') { + return KMXCodeNames[code]; + } + return code.toString(); +} + +function CheckStoreForInvalidFunctions(fk: KMX.KEYBOARD, key: KMX.KEY, store: KMX.STORE) { // I1520 + let n: number, rec: TSentinelRecord; + const wcsentinel = String.fromCharCode(0xFFFF); + + n = store.dpString.indexOf(wcsentinel); + + // Disable the check with versions >= 10.0, since we now support deadkeys in stores. + if (n >= 0 && !IsKeyboardVersion10OrLater) { + rec = ExpandSentinel(fk, store.dpString, n); + ReportError(key.Line, CERR_NotSupportedInKeymanWebStore, + `${GetCodeName(rec.Code)} is not currently supported in store '${store.dpName}' when used by any or index`); + } +} + + // Used when targeting versions prior to 10.0, before the introduction of FullContextMatch/KFCM. -function JavaScript_CompositeContextValue(fk: KEYBOARD, fkp: KEY, pwsz: string): string { +function JavaScript_CompositeContextValue(fk: KMX.KEYBOARD, fkp: KMX.KEY, pwsz: string): string { // Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions // var // StartQuotes, Len, Cur: Integer; @@ -360,35 +801,35 @@ function JavaScript_CompositeContextValue(fk: KEYBOARD, fkp: KEY, pwsz: string): } switch(rec.Code) { - case KMXFile.CODE_ANY: - CheckStoreForInvalidFunctions(fkp, rec.Any.Store); // I1520 + case KMX.KMXFile.CODE_ANY: + CheckStoreForInvalidFunctions(fk, fkp, rec.Any.Store); // I1520 Result += `k.KA(${Cur},k.KC(${Len-Cur},1,t),this.s${JavaScript_Name(rec.Any.StoreIndex, rec.Any.Store.dpName)})`; break; - case KMXFile.CODE_DEADKEY: + case KMX.KMXFile.CODE_DEADKEY: Result += `k.KDM(${Len-Cur},t,${rec.DeadKey.DeadKey})`; Cur--; // don't increment on deadkeys -- correlates with AdjustIndex function // I3910 break; - case KMXFile.CODE_NUL: // I2243 + case KMX.KMXFile.CODE_NUL: // I2243 Result += `k.KN(${Len-Cur},t)`; Cur--; // don't increment on nul -- correlates with AdjustIndex function // I3910 break; - case KMXFile.CODE_IFOPT: // I3429 + case KMX.KMXFile.CODE_IFOPT: // I3429 Result += `this.s${JavaScript_Name(rec.IfOpt.StoreIndex1, rec.IfOpt.Store1.dpName)}`+ `${rec.IfOpt.IsNot == 0 ? '!==':'==='}`+ `this.s${JavaScript_Name(rec.IfOpt.StoreIndex2,rec.IfOpt.Store2.dpName)}`; // I3429 // I3659 // I3681 Cur--; // don't increment on ifopt -- correlates with AdjustIndex function // I3910 break; - case KMXFile.CODE_IFSYSTEMSTORE: // I3430 + case KMX.KMXFile.CODE_IFSYSTEMSTORE: // I3430 Result += `${rec.IfSystemStore.IsNot == 0 ? '!' : ''}`+ `k.KIFS(${rec.IfSystemStore.dwSystemID},`+ `this.s${JavaScript_Name(rec.IfSystemStore.StoreIndex,rec.IfSystemStore.Store.dpName)},t)`; Cur--; // don't increment on ifsystemstore -- correlates with AdjustIndex function // I3910 break; - case KMXFile.CODE_CONTEXTEX: // I3980 + case KMX.KMXFile.CODE_CONTEXTEX: // I3980 Result += `k.KCCM(${Len-Cur},${Len-rec.ContextEx.Index+1},t)`; break; - case KMXFile.CODE_NOTANY: // I3981 - CheckStoreForInvalidFunctions(fkp, rec.Any.Store); // I1520 + case KMX.KMXFile.CODE_NOTANY: // I3981 + CheckStoreForInvalidFunctions(fk, fkp, rec.Any.Store); // I1520 Result += `k.KC(${Len-Cur},1,t)!=""&&!k.KA(${Cur},k.KC(${Len-Cur},1,t),`+ `this.s${JavaScript_Name(rec.Any.StoreIndex, rec.Any.Store.dpName)})`; break; @@ -410,7 +851,7 @@ function JavaScript_CompositeContextValue(fk: KEYBOARD, fkp: KEY, pwsz: string): if(rec.ChrVal == '"'.charCodeAt(0) || rec.ChrVal == '\\'.charCodeAt(0)) { Result += '\\'; } - Result += Javascript_String(rec.ChrVal); // I2242 + Result += JavaScript_String(rec.ChrVal); // I2242 } Cur++; @@ -424,7 +865,7 @@ function JavaScript_CompositeContextValue(fk: KEYBOARD, fkp: KEY, pwsz: string): } // Used when targeting versions >= 10.0, after the introduction of FullContextMatch/KFCM. -function JavaScript_FullContextValue(fk: KEYBOARD, fkp: KEY, pwsz: string): string { +function JavaScript_FullContextValue(fk: KMX.KEYBOARD, fkp: KMX.KEY, pwsz: string): string { /*var Len: Integer; rec: TSentinelRecord; @@ -444,17 +885,17 @@ begin*/ let rec = ExpandSentinel(fk, pwsz, x); if(rec.IsSentinel) { switch(rec.Code) { - case KMXFile.CODE_ANY: - CheckStoreForInvalidFunctions(fkp, rec.Any.Store); // I1520 + case KMX.KMXFile.CODE_ANY: + CheckStoreForInvalidFunctions(fk, fkp, rec.Any.Store); // I1520 FullContext += `{t:'a',a:this.s${JavaScript_Name(rec.Any.StoreIndex, rec.Any.Store.dpName)}}`; break; - case KMXFile.CODE_DEADKEY: + case KMX.KMXFile.CODE_DEADKEY: FullContext += `{t:'d',d:${rec.DeadKey.DeadKey}}`; break; - case KMXFile.CODE_NUL: // I2243 + case KMX.KMXFile.CODE_NUL: // I2243 FullContext += `{t:'n'}`; break; - case KMXFile.CODE_IFOPT: // I3429 + case KMX.KMXFile.CODE_IFOPT: // I3429 Len--; if(Suffix != '') { Suffix += '&&'; @@ -465,7 +906,7 @@ begin*/ Suffix += `this.s${JavaScript_Name(rec.IfOpt.StoreIndex1, rec.IfOpt.Store1.dpName)}`+ `${rec.IfOpt.IsNot == 0 ? '!==' : '==='}this.s${JavaScript_Name(rec.IfOpt.StoreIndex2,rec.IfOpt.Store2.dpName)}`; // I3429 // I3659 // I3681 break; - case KMXFile.CODE_IFSYSTEMSTORE: // I3430 + case KMX.KMXFile.CODE_IFSYSTEMSTORE: // I3430 Len--; if(Suffix != '') { Suffix += '&&'; @@ -476,19 +917,19 @@ begin*/ Suffix += `${rec.IfSystemStore.IsNot == 0 ? '!' : ''}k.KIFS(${rec.IfSystemStore.dwSystemID},`+ `this.s${JavaScript_Name(rec.IfSystemStore.StoreIndex,rec.IfSystemStore.Store.dpName)},t)`; // I3430 // I3659 // I3681 break; - case KMXFile.CODE_NOTANY: // I3981 - CheckStoreForInvalidFunctions(fkp, rec.Any.Store); // I1520 + case KMX.KMXFile.CODE_NOTANY: // I3981 + CheckStoreForInvalidFunctions(fk, fkp, rec.Any.Store); // I1520 FullContext += `{t:'a',a:this.s${JavaScript_Name(rec.Any.StoreIndex, rec.Any.Store.dpName)},n:1}`; break; - case KMXFile.CODE_CONTEXTEX: + case KMX.KMXFile.CODE_CONTEXTEX: FullContext += `{t:'c',c:${rec.ContextEx.Index}}`; // I4611 break; - case KMXFile.CODE_INDEX: - FullContext += `{t:'i',i:this.s${JavaScript_Name(rec.Index.StoreIndex, rec.Index.Store.szName)},`+ + case KMX.KMXFile.CODE_INDEX: + FullContext += `{t:'i',i:this.s${JavaScript_Name(rec.Index.StoreIndex, rec.Index.Store.dpName)},`+ `o:${rec.Index.Index}}`; // I4611 break; default: - ReportError(fkp.Line, CERR_NotSupportedInKeymanWebContext, `Statement ${GetCodeName(rec.Code)} is not currently supported in context`; // I1971 // I4061 + ReportError(fkp.Line, CERR_NotSupportedInKeymanWebContext, `Statement ${GetCodeName(rec.Code)} is not currently supported in context`); // I1971 // I4061 Result += '/*.*/ 0 '; } } @@ -498,7 +939,7 @@ begin*/ if(rec.ChrVal == '"'.charCodeAt(0) || rec.ChrVal == '\\'.charCodeAt(0) || rec.ChrVal == '\''.charCodeAt(0)) { FullContext += '\\'; } - FullContext += Javascript_String(rec.ChrVal) + `'`; // I2242 + FullContext += JavaScript_String(rec.ChrVal) + `'`; // I2242 } x = incxstr(pwsz, x); @@ -517,7 +958,18 @@ begin*/ return Result; } -export function JavaScript_OutputString(fk: KEYBOARD, FTabStops: string, fkp: KEY, pwszOutput: string, fgp: GROUP): string { +function isGroupReadOnly(fk: KMX.KEYBOARD, fgp: KMX.GROUP) { + // TODO: export group + store metadata in debug store, use that + return false; +} + +function CallFunctionName(s: string): string { + let n: number; + n = s.indexOf(':'); + return s.substring(n+1); // not found gives -1, substring(0) is ok :grin: +} + +export function JavaScript_OutputString(fk: KMX.KEYBOARD, FTabStops: string, fkp: KMX.KEY, pwszOutput: string, fgp: KMX.GROUP): string { let InQuotes = false; let len = 0; const nlt = nl + FTabStops; // I3681 @@ -537,18 +989,18 @@ export function JavaScript_OutputString(fk: KEYBOARD, FTabStops: string, fkp: KE let recContext = ExpandSentinel(fk, pwszContext, x); if(IsKeyboardVersion10OrLater()) { - if(recContext.IsSentinel && [KMXFile.CODE_NUL, KMXFile.CODE_IFOPT, KMXFile.CODE_IFSYSTEMSTORE].includes(recContext.Code)) { + if(recContext.IsSentinel && [KMX.KMXFile.CODE_NUL, KMX.KMXFile.CODE_IFOPT, KMX.KMXFile.CODE_IFSYSTEMSTORE].includes(recContext.Code)) { Result--; } } else { - if(recContext.IsSentinel && [KMXFile.CODE_DEADKEY, KMXFile.CODE_NUL,KMXFile. KMXFile.CODE_IFOPT, KMXFile.CODE_IFSYSTEMSTORE].includes(recContext.Code)) { + if(recContext.IsSentinel && [KMX.KMXFile.CODE_DEADKEY, KMX.KMXFile.CODE_NUL, KMX.KMXFile.CODE_IFOPT, KMX.KMXFile.CODE_IFSYSTEMSTORE].includes(recContext.Code)) { Result--; } } x = incxstr(pwszContext, x); } - return Result; + return Result + 1; // 1-based } const ContextChar = function(ContextIndex: number, pwszContext: string, xContext: number): string { // I4611 @@ -562,14 +1014,14 @@ export function JavaScript_OutputString(fk: KEYBOARD, FTabStops: string, fkp: KE } switch(recContext.Code) { - case KMXFile.CODE_ANY: + case KMX.KMXFile.CODE_ANY: Index = AdjustIndex(fkp.dpContext, ContextIndex); // I3910 // I4611 Result += nlt + `k.KIO(${len},this.s${JavaScript_Name(recContext.Any.StoreIndex, recContext.Any.Store.dpName)},${Index},t);`; // I4611 break; - case KMXFile.CODE_DEADKEY: + case KMX.KMXFile.CODE_DEADKEY: Result += nlt + `k.KDO(${len},t,${recContext.DeadKey.DeadKey});`; // I4611 break; - case KMXFile.CODE_NOTANY: + case KMX.KMXFile.CODE_NOTANY: // #917: Minimum version required is 14.0: the KCXO function was only added for 14.0 // Note that this is checked in compiler.cpp as well, so this error can probably never occur if(!IsKeyboardVersion14OrLater()) { @@ -577,9 +1029,9 @@ export function JavaScript_OutputString(fk: KEYBOARD, FTabStops: string, fkp: KE } Result += nlt + `k.KCXO(${len},t,${AdjustIndex(fkp.dpContext, xstrlen(fkp.dpContext))},${AdjustIndex(fkp.dpContext, ContextIndex)});`; break; - case KMXFile.CODE_IFOPT: - case KMXFile.CODE_IFSYSTEMSTORE: - case KMXFile.CODE_NUL: + case KMX.KMXFile.CODE_IFOPT: + case KMX.KMXFile.CODE_IFSYSTEMSTORE: + case KMX.KMXFile.CODE_NUL: // These have no output for a context emit break; default: @@ -610,12 +1062,12 @@ export function JavaScript_OutputString(fk: KEYBOARD, FTabStops: string, fkp: KE if(IsKeyboardVersion10OrLater()) { // KMW >= 10.0 use the full, sentinel-based length for context deletions. len = xstrlen(fkp.dpContext); - n = len; + let n = len; let x = 0; for(let i = 0; i < n; i++) { let rec = ExpandSentinel(fk, fkp.dpContext, x); - if(rec.IsSentinel && [KMXFile.CODE_NUL, KMXFile.CODE_IFOPT, KMXFile.CODE_IFSYSTEMSTORE].includes(rec.Code)) { + if(rec.IsSentinel && [KMX.KMXFile.CODE_NUL, KMX.KMXFile.CODE_IFOPT, KMX.KMXFile.CODE_IFSYSTEMSTORE].includes(rec.Code)) { len--; } x = incxstr(fkp.dpContext, x); @@ -633,7 +1085,7 @@ export function JavaScript_OutputString(fk: KEYBOARD, FTabStops: string, fkp: KE let x = 0; if(IsKeyboardVersion10OrLater() && pwsz.length > 0) { - if(fgp.fReadOnly) { + if(!isGroupReadOnly(fk, fgp)) { Result += nlt+`k.KDC(${len},t);`; // I3681 } len = -1; @@ -643,19 +1095,19 @@ export function JavaScript_OutputString(fk: KEYBOARD, FTabStops: string, fkp: KE let rec = ExpandSentinel(fk, pwsz, x); if(rec.IsSentinel) { if(InQuotes) { - if(!fgp.fReadOnly) { + if(!isGroupReadOnly(fk, fgp)) { Result += '");'; } InQuotes = false; } switch(rec.Code) { - case KMXFile.CODE_CONTEXT: + case KMX.KMXFile.CODE_CONTEXT: if (x > 0 || len == -1) { let xContext = 0; - n = 1; + let n = 0; while(xContext < fkp.dpContext.length) { // I4611 - if(!fgp.fReadOnly) { + if(!isGroupReadOnly(fk, fgp)) { Result += ContextChar(n, fkp.dpContext, xContext); } n++; @@ -666,19 +1118,19 @@ export function JavaScript_OutputString(fk: KEYBOARD, FTabStops: string, fkp: KE // else, we don't need to output anything - just don't delete the context len = -1; break; - case KMXFile.CODE_CONTEXTEX: + case KMX.KMXFile.CODE_CONTEXTEX: let xContext = 0; for(let i = 0; i < rec.ContextEx.Index; i++) { xContext = incxstr(fkp.dpContext, xContext); } - if(!fgp.fReadOnly) { + if(!isGroupReadOnly(fk, fgp)) { Result += ContextChar(rec.ContextEx.Index, fkp.dpContext, xContext); // I4611 } len = -1; break; - case KMXFile.CODE_BEEP: - if(!fgp.fReadOnly) { + case KMX.KMXFile.CODE_BEEP: + if(!isGroupReadOnly(fk, fgp)) { if(len > 0) { Result += nlt+`k.KO(${len},t,"");`; // I3681 } @@ -686,16 +1138,16 @@ export function JavaScript_OutputString(fk: KEYBOARD, FTabStops: string, fkp: KE } len = -1; break; - case KMXFile.CODE_NUL: - if(!fgp.fReadOnly) { + case KMX.KMXFile.CODE_NUL: + if(!isGroupReadOnly(fk, fgp)) { if(len > 0) { Result += nlt+`k.KO(${len},t,"");`; // I3681 } } len = -1; break; - case KMXFile.CODE_INDEX: - CheckStoreForInvalidFunctions(fkp, rec.Index.Store); // I1520 + case KMX.KMXFile.CODE_INDEX: + CheckStoreForInvalidFunctions(fk, fkp, rec.Index.Store); // I1520 // This code was wrong. We need to ignore CODE_NUL, CODE_DEADKEY in LHS context index counter. // This is why the compiler goes wrong -- and why the previous fix was inconsistent. @@ -705,7 +1157,7 @@ export function JavaScript_OutputString(fk: KEYBOARD, FTabStops: string, fkp: KE let Index = AdjustIndex(fkp.dpContext, rec.Index.Index); // I3910 - if(!fgp.fReadOnly) { + if(!isGroupReadOnly(fk, fgp)) { Result += nlt+`k.KIO(${len},this.s${JavaScript_Name(rec.Index.StoreIndex, rec.Index.Store.dpName)},${Index},t);`; // I783 - was: rec.Index.Index [2007-06-04] // I783 again. Returned to rec.Index.Index. Was previously: [2008-08-15] @@ -716,14 +1168,14 @@ export function JavaScript_OutputString(fk: KEYBOARD, FTabStops: string, fkp: KE } len = -1; break; - case KMXFile.CODE_DEADKEY: - if(!fgp.fReadOnly) { + case KMX.KMXFile.CODE_DEADKEY: + if(!isGroupReadOnly(fk, fgp)) { Result += nlt+`k.KDO(${len},t,${rec.DeadKey.DeadKey});`; // I3681 } len = -1; break; - case KMXFile.CODE_USE: - if(!fgp.fReadOnly) { + case KMX.KMXFile.CODE_USE: + if(!isGroupReadOnly(fk, fgp)) { if(len > 0) { Result += nlt+`k.KO(${len},t,"");`; // I3681 } @@ -732,22 +1184,22 @@ export function JavaScript_OutputString(fk: KEYBOARD, FTabStops: string, fkp: KE Result += nlt+'m=2;'; // #5440 - match desktop behavior len = -1; break; - case KMXFile.CODE_CALL: - if(!fgp.fReadOnly) { + case KMX.KMXFile.CODE_CALL: + if(!isGroupReadOnly(fk, fgp)) { if(len > 0) { Result += nlt+`k.KO(${len},t,"");`; // I3681 } } - n = FCallFunctions.IndexOf(CallFunctionName(rec.Call.Store.dpString)); + let n = FCallFunctions.indexOf(CallFunctionName(rec.Call.Store.dpString)); if(n == -1) { - n = FCallFunctions.Add(CallFunctionName(rec.Call.Store.dpString)); + n = FCallFunctions.push(CallFunctionName(rec.Call.Store.dpString)); } Result += nlt+`r=this.c${n}(t,e);`; // I1959 // I3681 Result += nlt+'m=2;'; // #5440 - match desktop behavior len = -1; break; - case KMXFile.CODE_SETOPT: // I3429 - if(!fgp.fReadOnly) { + case KMX.KMXFile.CODE_SETOPT: // I3429 + if(!isGroupReadOnly(fk, fgp)) { if(len > 0) { Result += nlt+`k.KO(${len},t,"");`; // I3681 } @@ -756,8 +1208,8 @@ export function JavaScript_OutputString(fk: KEYBOARD, FTabStops: string, fkp: KE `this.s${JavaScript_Name(rec.SetOpt.StoreIndex2,rec.SetOpt.Store2.dpName)};`; len = -1; break; - case KMXFile.CODE_RESETOPT: // I3429 - if(!fgp.fReadOnly) { + case KMX.KMXFile.CODE_RESETOPT: // I3429 + if(!isGroupReadOnly(fk, fgp)) { if(len > 0) { Result += nlt+`k.KO(${len},t,"");`; // I3681 } @@ -765,11 +1217,11 @@ export function JavaScript_OutputString(fk: KEYBOARD, FTabStops: string, fkp: KE Result += nlt+`this.s${JavaScript_Name(rec.ResetOpt.StoreIndex,rec.ResetOpt.Store.dpName)}=`+ `k.KLOAD(this.KI,"${JavaScript_Name(rec.ResetOpt.StoreIndex,rec.ResetOpt.Store.dpName,true)}",`+ - `${JavaScript_Store(fkp.Line, rec.ResetOpt.Store.dpString)});`; // I3429 // I3681 // I3659 + `${JavaScript_Store(fk, fkp.Line, rec.ResetOpt.Store.dpString)});`; // I3429 // I3681 // I3659 len = -1; break; - case KMXFile.CODE_SAVEOPT: // I3429 - if(!fgp.fReadOnly) { + case KMX.KMXFile.CODE_SAVEOPT: // I3429 + if(!isGroupReadOnly(fk, fgp)) { if(len > 0) { Result += nlt+`k.KO(${len},t,"");`; // I3681 } @@ -779,8 +1231,8 @@ export function JavaScript_OutputString(fk: KEYBOARD, FTabStops: string, fkp: KE `this.s${JavaScript_Name(rec.SaveOpt.StoreIndex,rec.SaveOpt.Store.dpName)});`; // I3690 // I3429 // I3659 // I3681 len = -1; break; - case KMXFile.CODE_SETSYSTEMSTORE: // I3437 - if(!fgp.fReadOnly) { + case KMX.KMXFile.CODE_SETSYSTEMSTORE: // I3437 + if(!isGroupReadOnly(fk, fgp)) { if(len > 0) { Result += nlt+`k.KO(${len},t,"");`; // I3681 } @@ -797,15 +1249,13 @@ export function JavaScript_OutputString(fk: KEYBOARD, FTabStops: string, fkp: KE } else { if(!InQuotes) { - if(!fgp.fReadOnly) { - if(len > 0) { - Result += nlt+`k.KO(${len},t,"");`; // I3681 - } + if(!isGroupReadOnly(fk, fgp)) { + Result += nlt+`k.KO(${len},t,"`; // I3681 } InQuotes = true; len = -1; } - if(!fgp.fReadOnly) { + if(!isGroupReadOnly(fk, fgp)) { if(rec.ChrVal == '"'.charCodeAt(0) || rec.ChrVal == '\\'.charCodeAt(0)) { Result += '\\'; } @@ -817,20 +1267,285 @@ export function JavaScript_OutputString(fk: KEYBOARD, FTabStops: string, fkp: KE } if(InQuotes) { - if(!fgp.fReadOnly) { + if(!isGroupReadOnly(fk, fgp)) { Result += '");'; } } return Result; } -function zeroPadHex(n: number, len: number): string { - let result = n.toString(16); +export function zeroPadHex(n: number, len: number): string { + let result = n.toString(16).toUpperCase(); if(result.length < len) { - return + return '0'.repeat(len - result.length) + result; } + return result; } +// TODO: move elsewhere +/// +/// Virtual key names used in KeymanWeb. Blanks indicate a +/// virtual key that is not recognised by KeymanWeb. +/// +const KMWVKeyNames: string[] = [ + '', + '', + '', + '', + '', + '', + '', + '', + 'K_BKSP', + 'K_TAB', + '', + '', + '', + 'K_ENTER', + '', + '', + 'K_SHIFT', + 'K_CONTROL', + 'K_ALT', + 'K_PAUSE', + 'K_CAPS', + '', + '', + '', + '', + '', + '', + 'K_ESC', + '', + '', + '', + '', + 'K_SPACE', + 'K_PGUP', + 'K_PGDN', + 'K_END', + 'K_HOME', + 'K_LEFT', + 'K_UP', + 'K_RIGHT', + 'K_DOWN', + 'K_SEL', + 'K_PRINT', + 'K_EXEC', + '', + 'K_INS', + 'K_DEL', + 'K_HELP', + 'K_0', + 'K_1', + 'K_2', + 'K_3', + 'K_4', + 'K_5', + 'K_6', + 'K_7', + 'K_8', + 'K_9', + '', + '', + '', + '', + '', + '', + '', + '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_NP0', + 'K_NP1', + 'K_NP2', + 'K_NP3', + 'K_NP4', + 'K_NP5', + 'K_NP6', + 'K_NP7', + 'K_NP8', + 'K_NP9', + 'K_NPSTAR', + 'K_NPPLUS', + 'K_SEPARATOR', + 'K_NPMINUS', + 'K_NPDOT', + 'K_NPSLASH', + 'K_F1', + 'K_F2', + 'K_F3', + 'K_F4', + 'K_F5', + 'K_F6', + 'K_F7', + 'K_F8', + 'K_F9', + 'K_F10', + 'K_F11', + 'K_F12', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + 'K_NUMLOCK', + 'K_SCROLL', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + 'K_LSHIFT', + 'K_RSHIFT', + 'K_LCONTROL', + 'K_RCONTROL', + 'K_LALT', + 'K_RALT', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + 'K_COLON', + 'K_EQUAL', + 'K_COMMA', + 'K_HYPHEN', + 'K_PERIOD', + 'K_SLASH', + 'K_BKQUOTE', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + 'K_LBRKT', + 'K_BKSLASH', + 'K_RBRKT', + 'K_QUOTE', + '', + '', + '', + 'K_oE2', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '' +]; + /** * Converts a key value into a constant * @@ -842,9 +1557,9 @@ function FormatKeyAsString(key: number): string { if(IsKeyboardVersion10OrLater()) { // Depends on flags defined in KeymanWeb 10.0 if (key <= 255 && KMWVKeyNames[key] != '') { - Result = 'keyCodes.'+KMWVKeyNames[key]+ ' /* 0x' + zeroPadHex(key, 2) + ' */' - else Result := '0x' + IntToHex(key, 2); - end - else - Result := '0x' + IntToHex(key, 2); -end; + return 'keyCodes.'+KMWVKeyNames[key]+ ' /* 0x' + zeroPadHex(key, 2) + ' */'; + } + return '0x' + zeroPadHex(key, 2); + } + return '0x' + zeroPadHex(key, 2); +} diff --git a/developer/src/kmc-kmw/src/compiler/keymanweb-compiler.ts b/developer/src/kmc-kmw/src/compiler/keymanweb-compiler.ts deleted file mode 100644 index 1b162b738a..0000000000 --- a/developer/src/kmc-kmw/src/compiler/keymanweb-compiler.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { VisualKeyboard } from "@keymanapp/common-types"; -import * as path from 'path'; - -import { KMXFile } from "../../../../../common/web/types/src/kmx/kmx.js"; -// import VisualKeyboardCompiler from "./visual-keyboard-compiler.js"; -import { nl, FTabStop, setupGlobals } from "./compiler-globals.js"; -import CompilerOptions from "./compiler-options.js"; - -export class KeymanWebCompiler { - private readonly options: CompilerOptions; - private readonly nl: string; - private readonly tab: string; - - constructor(options?: CompilerOptions) { - this.options = options; - this.nl = this.options.debug ? "\n" : ''; - this.tab = this.options.debug ? " " : ''; - setupGlobals(this.options, this.tab, this.nl); - } - - public compile(name: string, source: KMXFile): string { - const nl = this.nl, tab = this.tab; - - // TODO: fill in from CompileKeymanWeb.pas - - const sName = 'Keyboard_'+this.cleanName(name); - const displayUnderlying = true; // TODO-LDML - const modifierBitmask = 0; // TODO-LDML: define the modifiers used by this keyboard - const vkDictionary = ''; // TODO-LDML: vk dictionary for touch keys - const hasSupplementaryPlaneChars = false; // TODO-LDML - const isRTL = false; // TODO-LDML - - let result = - `if(typeof keyman === 'undefined') {${nl}` + - `${tab}console.error('Keyboard requires KeymanWeb ${MINIMUM_KMW_VERSION} or later');${nl}` + - `} else {${nl}` + - `${tab}KeymanWeb.KR(new ${sName}());${nl}` + - `}${nl}` + - `function ${sName}() {${nl}` + - // `${tab}${this.setupDebug()}${nl}` + ? we may use this for modifierBitmask in future - // `${tab}this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9;${nl}` + ? we probably don't need this, it's for back-compat - `${tab}this.KI="${sName}";${nl}` + - `${tab}this.KN=${JSON.stringify(source.keyboard.names.name[0])};${nl}` + - `${tab}this.KMINVER=${JSON.stringify(MINIMUM_KMW_VERSION)};${nl}` + - `${tab}this.KV=${this.compileVisualKeyboard(source)};${nl}` + - `${tab}this.KDU=${displayUnderlying ? '1' : '0'};${nl}` + - `${tab}this.KH="";${nl}` + // TODO-LDML: help text not supported - `${tab}this.KM=0;${nl}` + // TODO-LDML: mnemonic layout not supported for LDML keyboards - `${tab}this.KBVER=${JSON.stringify(source.keyboard.version.number)};${nl}` + - `${tab}this.KMBM=${modifierBitmask};${nl}`; - - if(isRTL) { - result += `${tab}this.KRTL=1;${nl}`; - } - - if(hasSupplementaryPlaneChars) { - result += `${tab}this.KS=1;${nl}`; - } - - if(vkDictionary != '') { - result += `${tab}this.KVKD=${JSON.stringify(vkDictionary)};${nl}`; - } - - let layoutFile = this.compileTouchLayout(source); - if(layoutFile != '') { - result += `${tab}this.KVKL=${layoutFile};${nl}`; - } - // TODO-LDML: KCSS not supported - - // TODO-LDML: embed binary keyboard for loading into Core - - // A LDML keyboard has a no-op for its gs() (begin Unicode) function, - // because the functionality is embedded in Keyman Core - result += `${tab}this.gs=function(t,e){${nl}`+ - `${tab}${tab}return 0;${nl}`+ // TODO-LDML: we will start by embedding call into Keyman Core here - `${tab}};${nl}`; - - result += `}${nl}`; - return result; - } -} \ No newline at end of file diff --git a/developer/src/kmc-kmw/src/compiler/messages.ts b/developer/src/kmc-kmw/src/compiler/messages.ts index 9f443cfc0d..07bd2794ca 100644 --- a/developer/src/kmc-kmw/src/compiler/messages.ts +++ b/developer/src/kmc-kmw/src/compiler/messages.ts @@ -1,4 +1,4 @@ -import { FCompilerWarningsAsErrors } from "./compiler-globals.js"; +import { callbacks, FCompilerWarningsAsErrors } from "./compiler-globals.js"; export let FError = false; @@ -10,7 +10,8 @@ export function ReportError(line: number, msgcode: number, text: string) { // I if (msgcode & flag) { FError = true; } - FCallback(line, msgcode, text); // I3310 + // TODO: these Codes Are All Wrong But We'll Fix It Soon + callbacks.reportMessage({code: msgcode, message: text, line}); // I3310 } export const diff --git a/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts b/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts index b065a1ea0f..0175072aeb 100644 --- a/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts +++ b/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts @@ -1,8 +1,9 @@ -import { ExpandSentinel, incxstr, xstrlen } from "src/util/util.js"; -import { GROUP, KEY, KMXFile, STORE } from "../../../../../common/web/types/src/kmx/kmx.js"; +import { KMX, CompilerCallbacks } from "@keymanapp/common-types"; +import { ExpandSentinel, incxstr, xstrlen } from "../util/util.js"; +// import { KEY, KEYBOARD, KMX.KMXFile, STORE } from "../../../../../common/web/types/src/kmx/kmx.js"; import { options, nl, FTabStop, setupGlobals, IsKeyboardVersion10OrLater } from "./compiler-globals.js"; import CompilerOptions from "./compiler-options.js"; -import { JavaScript_ContextMatch, JavaScript_KeyAsString, JavaScript_Name, JavaScript_OutputString, JavaScript_Rules, JavaScript_Shift, JavaScript_ShiftAsString, JavaScript_Store } from './javascript-strings.js'; +import { JavaScript_ContextMatch, JavaScript_KeyAsString, JavaScript_Name, JavaScript_OutputString, JavaScript_Rules, JavaScript_Shift, JavaScript_ShiftAsString, JavaScript_Store, zeroPadHex } from './javascript-strings.js'; import { CERR_InvalidBegin, CWARN_DontMixChiralAndNonChiralModifiers, ReportError } from "./messages.js"; export let FFix183_LadderLength: number = 100; // TODO: option @@ -29,33 +30,34 @@ function RequotedString(s: string, RequoteSingleQuotes: boolean = false): string else if(s.charAt(i) == '\r') { s = s.substring(0, i) + ' ' + s.substring(i + 1); } + i++; } return s; } -export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boolean = false): string { +export function WriteCompiledKeyboard(callbacks: CompilerCallbacks, name: string, keyboard: KMX.KEYBOARD, FDebug: boolean = false): string { let opts: CompilerOptions = { addCompilerVersion: false, debug: FDebug }; - setupGlobals(opts, FDebug?' ':'', FDebug?'\n':'', source.keyboard); + setupGlobals(callbacks, opts, FDebug?' ':'', FDebug?'\n':'', keyboard); // let fgp: GROUP; - let fsp: STORE; - let fkp: KEY; + // let fsp: STORE; + // let fkp: KEY; - let j: number; - let n: number; + // let j: number; + // let n: number; let vMnemonic: number = 0; - let s: string, sRTL: string = "", sHelp: string = "''", sHelpFile: string = "", + let /*s: string,*/ sRTL: string = "", sHelp: string = "''", sHelpFile: string = "", sEmbedJS: string = "", sEmbedCSS: string = ""; let sVisualKeyboard: string = "", sFullName: string = ""; - let sBegin_NewContext: string, sBegin_PostKeystroke: string; + let sBegin_NewContext: string = "", sBegin_PostKeystroke: string = ""; let sLayoutFile: string = "", sVKDictionary: string; let linecomment: string; // I3438 - let HasRules: boolean; + // let HasRules: boolean; let sModifierBitmask: string; let FOptionStores: string; let FKeyboardVersion = "1.0"; @@ -63,45 +65,45 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo let result = ""; // Locate the name of the keyboard - for(let i = 0; i < source.keyboard.stores.length; i++) { - const fsp = source.keyboard.stores[i]; - if(fsp.dwSystemID == KMXFile.TSS_NAME) { + for(let i = 0; i < keyboard.stores.length; i++) { + const fsp = keyboard.stores[i]; + if(fsp.dwSystemID == KMX.KMXFile.TSS_NAME) { sFullName = fsp.dpString; } - else if(fsp.dwSystemID == KMXFile.TSS_KEYBOARDVERSION) { // I4155 + else if(fsp.dwSystemID == KMX.KMXFile.TSS_KEYBOARDVERSION) { // I4155 FKeyboardVersion = fsp.dpString; } - else if (fsp.dpName == 'HelpFile' || fsp.dwSystemID == KMXFile.TSS_KMW_HELPFILE) { + else if (fsp.dpName == 'HelpFile' || fsp.dwSystemID == KMX.KMXFile.TSS_KMW_HELPFILE) { sHelpFile = fsp.dpString; } - else if (fsp.dpName == 'Help' || fsp.dwSystemID == KMXFile.TSS_KMW_HELPTEXT) { + else if (fsp.dpName == 'Help' || fsp.dwSystemID == KMX.KMXFile.TSS_KMW_HELPTEXT) { sHelp = '"'+RequotedString(fsp.dpString)+'"'; } - else if (fsp.dpName == 'VisualKeyboard' || fsp.dwSystemID == KMXFile.TSS_VISUALKEYBOARD) { + else if (fsp.dpName == 'VisualKeyboard' || fsp.dwSystemID == KMX.KMXFile.TSS_VISUALKEYBOARD) { sVisualKeyboard = fsp.dpString; } - else if (fsp.dpName == 'EmbedJS' || fsp.dwSystemID == KMXFile.TSS_KMW_EMBEDJS) { + else if (fsp.dpName == 'EmbedJS' || fsp.dwSystemID == KMX.KMXFile.TSS_KMW_EMBEDJS) { sEmbedJS = fsp.dpString; } - else if (fsp.dpName == 'EmbedCSS' || fsp.dwSystemID == KMXFile.TSS_KMW_EMBEDCSS) { // I4368 + else if (fsp.dpName == 'EmbedCSS' || fsp.dwSystemID == KMX.KMXFile.TSS_KMW_EMBEDCSS) { // I4368 sEmbedCSS = fsp.dpString; } - else if (fsp.dpName == 'RTL' || fsp.dwSystemID == KMXFile.TSS_KMW_RTL) { + else if (fsp.dpName == 'RTL' || fsp.dwSystemID == KMX.KMXFile.TSS_KMW_RTL) { sRTL = fsp.dpString == '1' ? FTabStop+'this.KRTL=1;'+nl : ''; // I3681 } - else if (fsp.dwSystemID == KMXFile.TSS_MNEMONIC) { + else if (fsp.dwSystemID == KMX.KMXFile.TSS_MNEMONIC) { vMnemonic = fsp.dpString == '1' ? 1 : 0; } - else if (fsp.dwSystemID == KMXFile.TSS_VKDICTIONARY) { // I3438 + else if (fsp.dwSystemID == KMX.KMXFile.TSS_VKDICTIONARY) { // I3438 sVKDictionary = fsp.dpString; } - else if (fsp.dwSystemID == KMXFile.TSS_LAYOUTFILE) { // I3483 + else if (fsp.dwSystemID == KMX.KMXFile.TSS_LAYOUTFILE) { // I3483 sLayoutFile = fsp.dpString; } - else if (fsp.dwSystemID == KMXFile.TSS_BEGIN_NEWCONTEXT) { + else if (fsp.dwSystemID == KMX.KMXFile.TSS_BEGIN_NEWCONTEXT) { sBegin_NewContext = fsp.dpString; } - else if (fsp.dwSystemID -= KMXFile.TSS_BEGIN_POSTKEYSTROKE) { + else if (fsp.dwSystemID == KMX.KMXFile.TSS_BEGIN_POSTKEYSTROKE) { sBegin_PostKeystroke = fsp.dpString; } } @@ -219,22 +221,23 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo sVisualKeyboard = 'null'; } - sModifierBitmask = GetKeyboardModifierBitmask(source); const fMnemonic = vMnemonic == 1; + sModifierBitmask = GetKeyboardModifierBitmask(keyboard, fMnemonic); + result += - `${JavaScript_SetupProlog}${nl}` + - `'KeymanWeb.KR(new ${sName}());${nl}` + - `${JavaScript_SetupEpilog}${nl}` + + `${JavaScript_SetupProlog()}${nl}` + + `KeymanWeb.KR(new ${sName}());${nl}` + + `${JavaScript_SetupEpilog()}${nl}` + `function ${sName}()${nl}` + `{${nl}` + - `${FTabStop}${JavaScript_SetupDebug}${nl}` + + `${FTabStop}${JavaScript_SetupDebug()}${nl}` + // Following line caches the Keyman major version `${FTabStop}this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9;${nl}` + `${FTabStop}this.KI="${sName}";${nl}` + `${FTabStop}this.KN="${RequotedString(sFullName)}";${nl}`, nl, - `${FTabStop}this.KMINVER="${(source.keyboard.fileVersion & KMXFile.VERSION_MASK_MAJOR) >> 8}.${source.keyboard.fileVersion & KMXFile.VERSION_MASK_MINOR}";${nl}` + + `${FTabStop}this.KMINVER="${(keyboard.fileVersion & KMX.KMXFile.VERSION_MASK_MAJOR) >> 8}.${keyboard.fileVersion & KMX.KMXFile.VERSION_MASK_MINOR}";${nl}` + `${FTabStop}this.KV=${sVisualKeyboard};${nl}` + `${FTabStop}this.KDU=${fDisplayUnderlying?'1':'0'};${nl}` + `${FTabStop}this.KH=${sHelp};${nl}` + @@ -259,45 +262,45 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo result += `${FTabStop}this.KCSS="${RequotedString(sEmbedCSS)}";${nl}`; } - function isDebugStore(fsp: STORE) { - return fsp.dwSystemID == KMXFile.TSS_DEBUG_LINE; + function isDebugStore(fsp: KMX.STORE) { + return fsp.dwSystemID == KMX.KMXFile.TSS_DEBUG_LINE; } - function isReservedStore(fsp: STORE) { - return fsp.dwSystemID != KMXFile.TSS_NONE; + function isReservedStore(fsp: KMX.STORE) { + return fsp.dwSystemID != KMX.KMXFile.TSS_NONE; } - function isOptionStore(fsp: STORE) { + function isOptionStore(fsp: KMX.STORE) { // TODO: how do we determine this, see CheckStoreUsage() return false; } // Write the stores out FOptionStores = ''; - for(let i = 0; i < source.keyboard.stores.length; i++) { - let fsp = source.keyboard.stores[i]; + for(let i = 0; i < keyboard.stores.length; i++) { + let fsp = keyboard.stores[i]; // I3438 - Save all system stores to the keyboard, for now // I3684 if (!isDebugStore(fsp)) { // and not (fsp.dwSystemID in [TSS_BITMAP, TSS_NAME, TSS_VERSION, TSS_CUSTOMKEYMANEDITION, TSS_CUSTOMKEYMANEDITIONNAME, TSS_KEYMANCOPYRIGHT]) then - if (fsp.dwSystemID == KMXFile.TSS_COMPARISON) { - result += `${FTabStop}this.s${JavaScript_Name(i, fsp.dpName)}=${JavaScript_Store(fsp.line, fsp.dpString)};${nl}`; + if (fsp.dwSystemID == KMX.KMXFile.TSS_COMPARISON) { + result += `${FTabStop}this.s${JavaScript_Name(i, fsp.dpName)}=${JavaScript_Store(keyboard, 0/*fsp.line*/, fsp.dpString)};${nl}`; } - else if (fsp.dwSystemID == KMXFile.TSS_COMPILEDVERSION) { - result += `${FTabStop}this.KVER=${JavaScript_Store(fsp.line, fsp.dpString)};${nl}`; + else if (fsp.dwSystemID == KMX.KMXFile.TSS_COMPILEDVERSION) { + result += `${FTabStop}this.KVER=${JavaScript_Store(keyboard, 0/*fsp.line*/, fsp.dpString)};${nl}`; } //else if fsp.dwSystemID = TSS_VKDICTIONARY then // I3438, required for vkdictionary // Result := Result + Format('%sthis.s%s=%s;%s', [FTabStop, JavaScript_Name(i, fsp.szName), JavaScript_Store(fsp.line, fsp.dpString), nl]) else if (isOptionStore(fsp) && !isReservedStore(fsp)) { result += `${FTabStop}this.s${JavaScript_Name(i,fsp.dpName)}=KeymanWeb.KLOAD(this.KI,"${JavaScript_Name(i,fsp.dpName,true)}",`+ - `${JavaScript_Store(fsp.line, fsp.dpString)});${nl}`; + `${JavaScript_Store(keyboard, 0/*fsp.line*/, fsp.dpString)});${nl}`; if (FOptionStores != '') { FOptionStores += ','; } FOptionStores += `'s${JavaScript_Name(i, fsp.dpName)}`; } - else if (fsp.dwSystemID == KMXFile.TSS_NONE /* aka not fsp.fIsReserved */) { - result += `${FTabStop}this.s${JavaScript_Name(i, fsp.dpName)}=${JavaScript_Store(fsp.line, fsp.dpString)};${nl}`; // I3681 + else if (fsp.dwSystemID == KMX.KMXFile.TSS_NONE /* aka not fsp.fIsReserved */) { + result += `${FTabStop}this.s${JavaScript_Name(i, fsp.dpName)}=${JavaScript_Store(keyboard, 0/*fsp.line*/, fsp.dpString)};${nl}`; // I3681 } } } @@ -307,30 +310,30 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo // Write the groups out // I853 - begin unicode missing causes crash - if (source.keyboard.startGroup.unicode == 0xFFFFFFFF) { + if (keyboard.startGroup.unicode == 0xFFFFFFFF) { ReportError(0, CERR_InvalidBegin, 'A "begin unicode" statement is required to compile a KeymanWeb keyboard'); return null; } - result += WriteBeginStatement(source, 'gs', source.keyboard.startGroup.unicode); + result += WriteBeginStatement(keyboard, 'gs', keyboard.startGroup.unicode); - let rec = ExpandSentinel(source.keyboard, sBegin_NewContext, 0); - if(rec.Code == KMXFile.CODE_USE) { - result += WriteBeginStatement(source, 'gn', rec.Use.GroupIndex); + let rec = ExpandSentinel(keyboard, sBegin_NewContext, 0); + if(rec.Code == KMX.KMXFile.CODE_USE) { + result += WriteBeginStatement(keyboard, 'gn', rec.Use.GroupIndex); } - rec = ExpandSentinel(source.keyboard, sBegin_PostKeystroke, 0); - if(rec.Code == KMXFile.CODE_USE) { - result += WriteBeginStatement(source, 'gpk', rec.Use.GroupIndex); + rec = ExpandSentinel(keyboard, sBegin_PostKeystroke, 0); + if(rec.Code == KMX.KMXFile.CODE_USE) { + result += WriteBeginStatement(keyboard, 'gpk', rec.Use.GroupIndex); } - let fgp = source.keyboard.groups[source.keyboard.startGroup.unicode]; + let fgp = keyboard.groups[keyboard.startGroup.unicode]; result += `${FTabStop}this.gs=function(t,e) {${nl}` + - `${FTabStop+FTabStop}return this.g${JavaScript_Name(source.keyboard.startGroup.unicode, fgp.dpName)}(t,e);${nl}` + - `${FTabStop}}${nl}`; // I3681 + `${FTabStop+FTabStop}return this.g${JavaScript_Name(keyboard.startGroup.unicode, fgp.dpName)}(t,e);${nl}` + + `${FTabStop}};${nl}`; // I3681 - for(let i = 0; i < source.keyboard.groups.length; i++) { // I1964 - let fgp = source.keyboard.groups[i]; + for(let i = 0; i < keyboard.groups.length; i++) { // I1964 + let fgp = keyboard.groups[i]; /* Note on `r` and `m` variables in a group function: @@ -363,12 +366,12 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo let HasRules = false; if (FFix183_LadderLength != 0) { - result += JavaScript_Rules(fgp); + result += JavaScript_Rules(keyboard, fMnemonic, fgp); } else { for (let j = 0; j < fgp.keys.length; j++) { // I1964 let fkp = fgp.keys[j]; - if (!RuleIsExcludedByPlatform(source, fkp)) { + if (!RuleIsExcludedByPlatform(keyboard, fkp)) { result += FTabStop+FTabStop; // I3681 if (HasRules) { result += 'else '; @@ -381,7 +384,7 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo if (xstrlen(fkp.dpContext) > 0) { result += fgp.fUsingKeys ? '&&' : 'if('; - result += JavaScript_ContextMatch(source.keyboard, fkp, fkp.dpContext); + result += JavaScript_ContextMatch(keyboard, fkp, fkp.dpContext); } else if (!fgp.fUsingKeys) { result += 'if(1'; @@ -393,10 +396,10 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo `) {${linecomment}${nl}` + FTabStop+FTabStop+FTabStop; if (fgp.fUsingKeys) { // I1959 - result += 'r=m=1;' + JavaScript_OutputString(source.keyboard, FTabStop + FTabStop + FTabStop, fkp, fkp.dpOutput, fgp); // I1959 // I3681 + result += 'r=m=1;' + JavaScript_OutputString(keyboard, FTabStop + FTabStop + FTabStop, fkp, fkp.dpOutput, fgp); // I1959 // I3681 } else { - result += 'm=1;' + JavaScript_OutputString(source.keyboard, FTabStop + FTabStop + FTabStop, fkp, fkp.dpOutput, fgp); // I1959 // I3681 + result += 'm=1;' + JavaScript_OutputString(keyboard, FTabStop + FTabStop + FTabStop, fkp, fkp.dpOutput, fgp); // I1959 // I3681 } result += `${nl}${FTabStop}${FTabStop}}${nl}`; // I3681 } @@ -406,28 +409,27 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo if(fgp.dpMatch) { result += `${FTabStop+FTabStop}if(m==1) {${nl}`+ - `${FTabStop+FTabStop+FTabStop}${JavaScript_OutputString(source.keyboard, FTabStop + FTabStop + FTabStop, null, fgp.dpMatch, fgp)}${nl}`+ + `${FTabStop+FTabStop}${JavaScript_OutputString(keyboard, FTabStop + FTabStop + FTabStop, null, fgp.dpMatch, fgp)}${nl}`+ `${FTabStop+FTabStop}}${nl}`; } if(fgp.dpNoMatch) { if(fgp.fUsingKeys) { // I1382 - fixup m=1 to m=g() result += `${FTabStop+FTabStop}if(!m&&k.KIK(e)) {${nl}`+ - `${FTabStop+FTabStop+FTabStop}r=1;${JavaScript_OutputString(source.keyboard, FTabStop + FTabStop + FTabStop, null, fgp.dpNoMatch, fgp)}${nl}`+ + `${FTabStop+FTabStop+FTabStop}r=1;${JavaScript_OutputString(keyboard, FTabStop + FTabStop + FTabStop, null, fgp.dpNoMatch, fgp)}${nl}`+ `${FTabStop+FTabStop}}${nl}`; // I1959. part 2, I2224 // I3681 } else { result += `${FTabStop+FTabStop}if(!m) {${nl}`+ - `${FTabStop+FTabStop+FTabStop}${JavaScript_OutputString(source.keyboard, FTabStop + FTabStop + FTabStop, null, fgp.dpNoMatch, fgp)}${nl}`+ + `${FTabStop+FTabStop+FTabStop}${JavaScript_OutputString(keyboard, FTabStop + FTabStop + FTabStop, null, fgp.dpNoMatch, fgp)}${nl}`+ `${FTabStop+FTabStop}}${nl}`; } - + } result += `${FTabStop+FTabStop}return r;${nl}`+ - `${FTabStop+FTabStop}};${nl}`; + `${FTabStop}};${nl}`; } -} /* TODO for(let n = 0 to FCallFunctions.Count - 1 do @@ -455,27 +457,27 @@ export function WriteCompiledKeyboard(name: string, source: KMXFile, FDebug: boo /// /// @return string of JavaScript code, e.g. 'modCodes.SHIFT | modCodes.CTRL /* 0x0030 */' /// -function GetKeyboardModifierBitmask(source: KMXFile): string { +function GetKeyboardModifierBitmask(keyboard: KMX.KEYBOARD, fMnemonic: boolean): string { let bitMask = 0; - for(let gp of source.keyboard.groups) { + for(let gp of keyboard.groups) { if(gp.fUsingKeys) { for(let kp of gp.keys) { - if(!RuleIsExcludedByPlatform(source, kp)) { + if(!RuleIsExcludedByPlatform(keyboard, kp)) { bitMask |= JavaScript_Shift(kp, fMnemonic); } } } } - if ((bitMask & KMXFile.KMX_MASK_MODIFIER_CHIRAL) && (bitMask & KMXFile.KMX_MASK_MODIFIER_NONCHIRAL)) { + if ((bitMask & KMX.KMXFile.MASK_MODIFIER_CHIRAL) && (bitMask & KMX.KMXFile.MASK_MODIFIER_NONCHIRAL)) { ReportError(0, CWARN_DontMixChiralAndNonChiralModifiers, 'This keyboard contains Ctrl,Alt and LCtrl,LAlt,RCtrl,RAlt sets of modifiers. Use only one or the other set for web target.'); } if(options.debug) { - return FormatModifierAsBitflags(bitMask & KMXFile.KMX_MASK_KEYS); // Exclude KMX_ISVIRTUALKEY, KMX_VIRTUALCHARKEY + return FormatModifierAsBitflags(bitMask & KMX.KMXFile.MASK_KEYS); // Exclude KMX_ISVIRTUALKEY, KMX_VIRTUALCHARKEY } - return '0x'+(bitMask & KMXFile.KMX_MASK_KEYS).toString(16); + return '0x'+(bitMask & KMX.KMXFile.MASK_KEYS).toString(16).toUpperCase(); } @@ -567,17 +569,17 @@ begin end;*/ } -export function RuleIsExcludedByPlatform(source: KMXFile, fkp: KEY): boolean { +export function RuleIsExcludedByPlatform(keyboard: KMX.KEYBOARD, fkp: KMX.KEY): boolean { if(fkp.dpContext == null || fkp.dpContext == '') { return false; } let x = 0; while(x < fkp.dpContext.length) { - let rec = ExpandSentinel(source.keyboard, fkp.dpContext, x); + let rec = ExpandSentinel(keyboard, fkp.dpContext, x); if(rec.IsSentinel && - (rec.Code == KMXFile.CODE_IFSYSTEMSTORE) && - (rec.IfSystemStore.dwSystemID == KMXFile.TSS_PLATFORM) && + (rec.Code == KMX.KMXFile.CODE_IFSYSTEMSTORE) && + (rec.IfSystemStore.dwSystemID == KMX.KMXFile.TSS_PLATFORM) && rec.IfSystemStore.Store.dpString.includes('native')) { if(rec.IfSystemStore.Store.dpString.match(/windows|desktop|macosx|linux/)) { return true; @@ -589,9 +591,70 @@ export function RuleIsExcludedByPlatform(source: KMXFile, fkp: KEY): boolean { return false; } -function WriteBeginStatement(source: KMXFile, name: string, groupIndex: number): string { - const fgp = source.keyboard.groups[groupIndex]; +function WriteBeginStatement(keyboard: KMX.KEYBOARD, name: string, groupIndex: number): string { + const fgp = keyboard.groups[groupIndex]; return `${FTabStop}this.${name}=function(t,e) {${nl}`+ `${FTabStop+FTabStop}return this.g${JavaScript_Name(groupIndex, fgp.dpName)}(t,e);${nl}`+ `${FTabStop}};${nl}`; -} \ No newline at end of file +} + +/** + * Converts a modifier bit mask integer into its component bit flags + * + * @param FBitMask A KMX modifier bitmask value + * + * @return string of JavaScript code, e.g. 'modCodes.SHIFT | modCodes.CTRL /* 0x0030 ./' +**/ +export function FormatModifierAsBitflags(FBitMask: number): string { + const mask: string[] = [ + 'LCTRL', // 0X0001 + 'RCTRL', // 0X0002 + 'LALT', // 0X0004 + 'RALT', // 0X0008 + + 'SHIFT', // 0X0010 + 'CTRL', // 0X0020 + 'ALT', // 0X0040 + + '???', // Reserved + + 'CAPS', // 0X0100 + 'NO_CAPS', // 0X0200 + + 'NUM_LOCK', // 0X0400 + 'NO_NUM_LOCK', // 0X0800 + + 'SCROLL_LOCK', // 0X1000 + 'NO_SCROLL_LOCK', // 0X2000 + + 'VIRTUAL_KEY' // 0X4000 + ]; + + let i: number; + let result = ''; + + //TODO: We need to think about mnemonic layouts which are incompletely supported at present + //tavultesoft.keymanweb.osk. + + if(IsKeyboardVersion10OrLater()) { + // This depends on flags defined in KeymanWeb 10.0 + result = ''; + + for(i = 0; i < mask.length; i++) { + if(FBitMask & (1 << i)) { + if(result != '') result += ' | '; + result += 'modCodes.'+mask[i]; + } + } + + if(result == '') { + result = '0'; + } + + result += ' /* 0x' + zeroPadHex(FBitMask, 4) + ' */'; + } + else { + result = '0x'+zeroPadHex(FBitMask, 4); + } + return result; +} diff --git a/developer/src/kmc-kmw/src/main.ts b/developer/src/kmc-kmw/src/main.ts index 742b9e4f47..35d6846bce 100644 --- a/developer/src/kmc-kmw/src/main.ts +++ b/developer/src/kmc-kmw/src/main.ts @@ -1,2 +1,2 @@ -export { KeymanWebCompiler } from './compiler/keymanweb-compiler.js'; +export { WriteCompiledKeyboard } from './compiler/write-compiled-keyboard.js'; diff --git a/developer/src/kmc-kmw/src/util/util.ts b/developer/src/kmc-kmw/src/util/util.ts index 1c01a22bf5..21aa9d3c14 100644 --- a/developer/src/kmc-kmw/src/util/util.ts +++ b/developer/src/kmc-kmw/src/util/util.ts @@ -1,4 +1,4 @@ -import { STORE, GROUP, KEYBOARD, KMXFile } from "../../../../../common/web/types/src/kmx/kmx.js"; +import { KMX } from "@keymanapp/common-types"; /** * Verifies that value is an item in the enumeration. @@ -13,11 +13,11 @@ export interface TSentinelRecord { Any?: { StoreIndex: number; - Store: STORE; + Store: KMX.STORE; }; Index?: { StoreIndex: number; - Store: STORE; + Store: KMX.STORE; Index: number; }; DeadKey?: { @@ -25,127 +25,168 @@ export interface TSentinelRecord { }; Use?: { GroupIndex: number; - Group: GROUP; + Group: KMX.GROUP; }; Call?: { StoreIndex: number; - Store: STORE; + Store: KMX.STORE; }; ContextEx?: { Index: number; }; IfOpt?: { StoreIndex1: number; - Store1: STORE; + Store1: KMX.STORE; StoreIndex2: number; - Store2: STORE; + Store2: KMX.STORE; IsNot: number; }; IfSystemStore?: { dwSystemID: number; - SystemStore: STORE; + SystemStore: KMX.STORE; StoreIndex: number; - Store: STORE; + Store: KMX.STORE; IsNot: number; }; SetOpt?: { StoreIndex1: number; - Store1: STORE; + Store1: KMX.STORE; StoreIndex2: number; - Store2: STORE; + Store2: KMX.STORE; }; SetSystemStore?: { dwSystemID: number; - SystemStore: STORE; + SystemStore: KMX.STORE; StoreIndex: number; - Store: STORE; + Store: KMX.STORE; }; ResetOpt?: { StoreIndex: number; - Store: STORE; + Store: KMX.STORE; }; SaveOpt?: { StoreIndex: number; - Store: STORE; + Store: KMX.STORE; }; ChrVal?: number; }; -export function ExpandSentinel(fk: KEYBOARD, pwsz: string, x: number): TSentinelRecord { +export function ExpandSentinel(fk: KMX.KEYBOARD, pwsz: string, x: number): TSentinelRecord { let result: TSentinelRecord = { IsSentinel: false }; - if(pwsz.charCodeAt(x) == KMXFile.UC_SENTINEL) { + if(pwsz.charCodeAt(x) == KMX.KMXFile.UC_SENTINEL) { result.IsSentinel = true; x++; result.Code = pwsz.charCodeAt(x); x++; switch(result.Code) { - case KMXFile.CODE_ANY: - case KMXFile.CODE_NOTANY: // I3981 - result.Any.StoreIndex = pwsz.charCodeAt(x) - 1; - result.Any.Store = fk.stores[result.Any.StoreIndex]; + case KMX.KMXFile.CODE_ANY: + case KMX.KMXFile.CODE_NOTANY: // I3981 + let anyIdx = pwsz.charCodeAt(x) - 1; + result.Any = { + StoreIndex: anyIdx, + Store: fk.stores[anyIdx] + } break; - case KMXFile.CODE_INDEX: - result.Index.StoreIndex = pwsz.charCodeAt(x) - 1; - result.Index.Store = fk.stores[result.Index.StoreIndex]; + case KMX.KMXFile.CODE_INDEX: + let indexIdx = pwsz.charCodeAt(x) - 1; x++; - result.Index.Index = pwsz.charCodeAt(x); + result.Index = { + StoreIndex: indexIdx, + Store: fk.stores[indexIdx], + Index: pwsz.charCodeAt(x) - 1 + } break; - case KMXFile.CODE_DEADKEY: - result.DeadKey.DeadKey = pwsz.charCodeAt(x) - 1; + case KMX.KMXFile.CODE_DEADKEY: + result.DeadKey = { DeadKey: pwsz.charCodeAt(x) - 1 }; break; - case KMXFile.CODE_USE: - result.Use.GroupIndex = pwsz.charCodeAt(x) - 1; - result.Use.Group = fk.groups[result.Use.GroupIndex]; + case KMX.KMXFile.CODE_USE: + let useIdx = pwsz.charCodeAt(x) - 1; + result.Use = { + GroupIndex: useIdx, + Group: fk.groups[useIdx] + }; break; - case KMXFile.CODE_CALL: - result.Call.StoreIndex = pwsz.charCodeAt(x) - 1; - result.Call.Store = fk.stores[result.Call.StoreIndex]; + case KMX.KMXFile.CODE_CALL: + let callIdx = pwsz.charCodeAt(x) - 1; + result.Call = { + StoreIndex: callIdx, + Store: fk.stores[callIdx] + } break; - case KMXFile.CODE_CONTEXTEX: - result.ContextEx.Index = pwsz.charCodeAt(x); + case KMX.KMXFile.CODE_CONTEXTEX: + result.ContextEx = { Index: pwsz.charCodeAt(x) - 1 }; break; - case KMXFile.CODE_SETOPT: // I3429 - result.SetOpt.StoreIndex1 = pwsz.charCodeAt(x) - 1; - result.SetOpt.Store1 = fk.stores[result.SetOpt.StoreIndex1]; + case KMX.KMXFile.CODE_SETOPT: // I3429 + let setIdx1 = pwsz.charCodeAt(x) - 1; x++; - result.SetOpt.StoreIndex2 = pwsz.charCodeAt(x) - 1; - result.SetOpt.Store2 = fk.stores[result.SetOpt.StoreIndex2]; + let setIdx2 = pwsz.charCodeAt(x) - 1; + result.SetOpt = { + StoreIndex1: setIdx1, + Store1: fk.stores[setIdx1], + StoreIndex2: setIdx2, + Store2: fk.stores[setIdx2] + }; break; - case KMXFile.CODE_SETSYSTEMSTORE: // I3437 - result.SetSystemStore.dwSystemID = pwsz.charCodeAt(x) - 1; - result.SetSystemStore.SystemStore = fk.stores.find(s => s.dwSystemID == result.SetSystemStore.dwSystemID) || null; + case KMX.KMXFile.CODE_SETSYSTEMSTORE: // I3437 + let setsIdx1 = pwsz.charCodeAt(x) - 1; x++; - result.SetSystemStore.StoreIndex = pwsz.charCodeAt(x) - 1; - result.SetSystemStore.Store = fk.stores[result.SetSystemStore.StoreIndex]; + let setsIdx2 = pwsz.charCodeAt(x) - 1; + result.SetSystemStore = { + dwSystemID: setsIdx1, + SystemStore: fk.stores.find(s => s.dwSystemID == setsIdx1) || null, + StoreIndex: setsIdx2, + Store: fk.stores[setsIdx2] + }; break; - case KMXFile.CODE_RESETOPT: // I3429 - result.ResetOpt.StoreIndex = pwsz.charCodeAt(x) - 1; - result.ResetOpt.Store = fk.stores[result.ResetOpt.StoreIndex]; + case KMX.KMXFile.CODE_RESETOPT: // I3429 + result.ResetOpt = { + StoreIndex: pwsz.charCodeAt(x) - 1, + Store: fk.stores[result.ResetOpt.StoreIndex] + }; break; - case KMXFile.CODE_SAVEOPT: // I3429 - result.SaveOpt.StoreIndex = pwsz.charCodeAt(x) - 1; - result.SaveOpt.Store = fk.stores[result.SaveOpt.StoreIndex]; + case KMX.KMXFile.CODE_SAVEOPT: // I3429 + result.SaveOpt = { + StoreIndex: pwsz.charCodeAt(x) - 1, + Store: fk.stores[result.SaveOpt.StoreIndex] + }; break; - case KMXFile.CODE_IFOPT: // I3429 - result.IfOpt.StoreIndex1 = pwsz.charCodeAt(x) - 1; - result.IfOpt.Store1 = fk.stores[result.IfOpt.StoreIndex1]; + case KMX.KMXFile.CODE_IFOPT: // I3429 + let ifIdx1 = pwsz.charCodeAt(x) - 1; x++; - result.IfOpt.IsNot = pwsz.charCodeAt(x) - 1; // I3429 + let ifNot = pwsz.charCodeAt(x) - 1; x++; - result.IfOpt.StoreIndex2 = pwsz.charCodeAt(x) - 1; - result.IfOpt.Store2 = fk.stores[result.IfOpt.StoreIndex2]; + let ifIdx2 = pwsz.charCodeAt(x) - 1; + result.IfOpt = { + StoreIndex1: ifIdx1, + Store1: fk.stores[ifIdx1], + IsNot: ifNot, // I3429 + StoreIndex2: ifIdx2, + Store2: fk.stores[ifIdx2] + }; break; - case KMXFile.CODE_IFSYSTEMSTORE: // I3430 - result.IfSystemStore.dwSystemID = pwsz.charCodeAt(x) - 1; - result.IfSystemStore.SystemStore = fk.stores.find(s => s.dwSystemID == result.IfSystemStore.dwSystemID) || null; + case KMX.KMXFile.CODE_IFSYSTEMSTORE: // I3430 + let ifsSystemID = pwsz.charCodeAt(x) - 1; x++; - result.IfSystemStore.IsNot = pwsz.charCodeAt(x) - 1; // I3430 + let ifsNot = pwsz.charCodeAt(x) - 1; x++; - result.IfSystemStore.StoreIndex = pwsz.charCodeAt(x) - 1; - result.IfSystemStore.Store = fk.stores[result.IfSystemStore.StoreIndex]; + let ifsIdx2 = pwsz.charCodeAt(x) - 1; + result.IfSystemStore = { + dwSystemID: ifsSystemID, + SystemStore: fk.stores.find(s => s.dwSystemID == ifsSystemID) || null, + IsNot: ifsNot, + StoreIndex: ifsIdx2, + Store: fk.stores[ifsIdx2] + }; + break; + case KMX.KMXFile.CODE_NUL: + case KMX.KMXFile.CODE_CONTEXT: + case KMX.KMXFile.CODE_RETURN: + case KMX.KMXFile.CODE_BEEP: + case KMX.KMXFile.CODE_EXTENDED: + // No additional detail needed, or outside scope break; default: throw new Error(`Unrecognized system store value ${result.Code}`); @@ -167,7 +208,7 @@ export function incxstr(p: string, x: number): number { } let ch = p.charCodeAt(x); - if(ch != KMXFile.UC_SENTINEL) { + if(ch != KMX.KMXFile.UC_SENTINEL) { if(ch >= 0xD800 && ch <= 0xDBFF) { x++; if(x == p.length) { @@ -190,27 +231,28 @@ export function incxstr(p: string, x: number): number { } switch(p.charCodeAt(x)) { - case KMXFile.CODE_ANY: x += 2; break; - case KMXFile.CODE_INDEX: x += 3; break; - case KMXFile.CODE_USE: x += 2; break; - case KMXFile.CODE_DEADKEY: x += 2; break; - case KMXFile.CODE_EXTENDED: + case KMX.KMXFile.CODE_ANY: x += 2; break; + case KMX.KMXFile.CODE_INDEX: x += 3; break; + case KMX.KMXFile.CODE_USE: x += 2; break; + case KMX.KMXFile.CODE_DEADKEY: x += 2; break; + case KMX.KMXFile.CODE_EXTENDED: x += 3; - while(x <= p.length && p.charCodeAt(x) != KMXFile.UC_SENTINEL_EXTENDEDEND) { + while(x <= p.length && p.charCodeAt(x) != KMX.KMXFile.UC_SENTINEL_EXTENDEDEND) { x++; } + x++; break; - case KMXFile.CODE_CALL: x += 2; break; - case KMXFile.CODE_CONTEXTEX: x += 2; break; - case KMXFile.CODE_NOTANY: x += 2; break; - - case KMXFile.CODE_CLEARCONTEXT: x += 2; break; - case KMXFile.CODE_IFOPT: x += 4; break; - case KMXFile.CODE_IFSYSTEMSTORE: x += 4; break; - case KMXFile.CODE_SETOPT: x += 3; break; - case KMXFile.CODE_SETSYSTEMSTORE: x += 3; break; - case KMXFile.CODE_RESETOPT: x += 2; break; - case KMXFile.CODE_SAVEOPT: x += 2; break; + case KMX.KMXFile.CODE_CALL: x += 2; break; + case KMX.KMXFile.CODE_CONTEXTEX: x += 2; break; + case KMX.KMXFile.CODE_NOTANY: x += 2; break; + + case KMX.KMXFile.CODE_CLEARCONTEXT: x += 2; break; + case KMX.KMXFile.CODE_IFOPT: x += 4; break; + case KMX.KMXFile.CODE_IFSYSTEMSTORE: x += 4; break; + case KMX.KMXFile.CODE_SETOPT: x += 3; break; + case KMX.KMXFile.CODE_SETSYSTEMSTORE: x += 3; break; + case KMX.KMXFile.CODE_RESETOPT: x += 2; break; + case KMX.KMXFile.CODE_SAVEOPT: x += 2; break; default: x++; } @@ -234,12 +276,12 @@ export function xstrlen(p: string): number { export function xstrlen_printing(p: string): number { let result = 0, x = 0; while(x < p.length) { - if(x + 1 < p.length && p.charCodeAt(x) == KMXFile.UC_SENTINEL) { + if(x + 1 < p.length && p.charCodeAt(x) == KMX.KMXFile.UC_SENTINEL) { switch(p.charCodeAt(x+1)) { - case KMXFile.CODE_DEADKEY: - case KMXFile.CODE_NUL: - case KMXFile.CODE_IFOPT: - case KMXFile.CODE_IFSYSTEMSTORE: + case KMX.KMXFile.CODE_DEADKEY: + case KMX.KMXFile.CODE_NUL: + case KMX.KMXFile.CODE_IFOPT: + case KMX.KMXFile.CODE_IFSYSTEMSTORE: result--; break; } diff --git a/developer/src/kmc-kmw/test/README.md b/developer/src/kmc-kmw/test/README.md new file mode 100644 index 0000000000..e1ccf019ac --- /dev/null +++ b/developer/src/kmc-kmw/test/README.md @@ -0,0 +1,7 @@ +Keyman kmn kmw Keyboard Compiler Tests +====================================== + +Test +---- + + ../build.sh test diff --git a/developer/src/kmc-kmw/test/fixtures/khmer_angkor.ico b/developer/src/kmc-kmw/test/fixtures/khmer_angkor.ico new file mode 100644 index 0000000000000000000000000000000000000000..42c90c398daf08f560778dd383cc0f7dd5922ae1 GIT binary patch literal 1150 zcmd^7J<7sB5PkA_fE4n9ogjjR=shgO&I@=AJDU_~?d&Ziq|ByFAdpQ`B*Z2}kB}2M zGfnj4Gb)zO@^;?t+c*2e0v&3GF#yN93;a?Z6AZ$D(2<@9X@6rs{lPb5gbEGL#9zU! zr{Q&7gHctLWUV!lBoSVgrDWEd{TeUN4RJ!6rtmxud7i_zZ8(l2Tqz|QuX*I>dEO_E zV+28fEXxGG?<0yL(b~MM6-5E9BWyPZn5GHKvV@0WD7BvXN4Q|tKgb!Ca^bqJ@Ja7T encw#Q&TZq>Vu$5?_m-!v-hbLR|9!sur*Q?n;~upD literal 0 HcmV?d00001 diff --git a/developer/src/kmc-kmw/test/fixtures/khmer_angkor.js b/developer/src/kmc-kmw/test/fixtures/khmer_angkor.js new file mode 100644 index 0000000000..e2296a99e8 --- /dev/null +++ b/developer/src/kmc-kmw/test/fixtures/khmer_angkor.js @@ -0,0 +1,5463 @@ +if(typeof keyman === 'undefined') { + console.log('Keyboard requires KeymanWeb 10.0 or later'); + if(typeof tavultesoft !== 'undefined') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later"); +} else { +KeymanWeb.KR(new Keyboard_khmer_angkor()); +} +function Keyboard_khmer_angkor() +{ + var modCodes = keyman.osk.modifierCodes; + var keyCodes = keyman.osk.keyCodes; + + this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9; + this.KI="Keyboard_khmer_angkor"; + this.KN="Khmer Angkor"; + this.KMINVER="10.0"; + this.KV={F:' 1em "Khmer Busra Kbd"',K102:0}; + this.KV.KLS={ + "rightalt": ["‍","‌","@","","$","€","៙","៚","*","{","}","≈","","","","","ៜ","","ឯ","ឫ","ឨ","[","]","ឦ","ឱ","ឰ","ឩ","ឳ","\\","","","","+","-","×","÷",":","‘","’","ឝ","៘","៖","ៈ","","","","","","","<",">","#","&","ឞ",";","",",",".","/","","","","",""," "], + "rightalt-shift": ["","៱","៲","៳","៴","៵","៶","៷","៸","៹","៰","","","","","","᧠","᧡","᧢","᧣","᧤","᧥","᧦","᧧","᧨","᧩","᧪","᧫","","","","","᧬","᧭","᧮","᧯","᧰","᧱","᧲","᧳","᧴","᧵","᧶","","","","","","","᧷","᧸","᧹","᧺","᧻","᧼","᧽","᧾","᧿","","","","","","",""], + "default": ["«","១","២","៣","៤","៥","៦","៧","៨","៩","០","ឥ","ឲ","","","","ឆ","","","រ","ត","យ","","","","ផ","","ឪ","ឮ","","","","","ស","ដ","ថ","ង","ហ","","ក","ល","","","","","","","","","ឋ","ខ","ច","វ","ប","ន","ម","","។","","","","","","","​"], + "shift": ["»","!","ៗ","\"","៛","%","","","","(",")","","=","","","","ឈ","","","ឬ","ទ","","","","","ភ","","ឧ","ឭ","","","","","","ឌ","ធ","អ","ះ","ញ","គ","ឡ","","","","","","","","","ឍ","ឃ","ជ","","ព","ណ","","","៕","?","","","","","",""] + }; + this.KV.BK=(function(x){ + var + empty=Array.apply(null, Array(65)).map(String.prototype.valueOf,""), + result=[], v, i, + modifiers=['default','shift','ctrl','shift-ctrl','alt','shift-alt','ctrl-alt','shift-ctrl-alt']; + for(i=modifiers.length-1;i>=0;i--) { + v = x[modifiers[i]]; + if(v || result.length > 0) { + result=(v ? v : empty).slice().concat(result); + } + } + return result; + })(this.KV.KLS); + this.KDU=0; + this.KH=''; + this.KM=0; + this.KBVER="1.3"; + this.KMBM=modCodes.RALT | modCodes.SHIFT /* 0x0018 */; + this.KVKD="T_17D2_1780 T_17D2_1781 T_17D2_1782 T_17D2_1783 T_17D2_1784 T_17D2_1785 T_17D2_1786 T_17D2_1787 T_17D2_1788 T_17D2_1789 T_17D2_178A T_17D2_178B T_17D2_178C T_17D2_178D T_17D2_178E T_17D2_178F T_17D2_1790 T_17D2_1791 T_17D2_1792 T_17D2_1793 T_17D2_1794 T_17D2_1795 T_17D2_1796 T_17D2_1797 T_17D2_1798 T_17D2_1799 T_17D2_179A T_17D2_179B T_17D2_179C T_17D2_179D T_17D2_179E T_17D2_179F T_17D2_17A0 T_17D2_17A1 T_17D2_17A2 U_0030 U_0031 U_0032 U_0033 U_0034 U_0035 U_0036 U_0037 U_0038 U_0039"; + this.KVKL={ + "phone": { + "font": "Khmer Busra Kbd", + "fontsize": "0.8em", + "displayUnderlying": false, + "layer": [ + { + "id": "default", + "row": [ + { + "id": "1", + "key": [ + { + "id": "K_Q", + "text": "\u1786", + "sk": [ + { + "layer": "shift", + "id": "K_Q", + "text": "\u1788" + }, + { + "id": "T_17D2_1786", + "text": "\uEF86" + }, + { + "id": "T_17D2_1788", + "text": "\uEF88" + } + ] + }, + { + "id": "K_W", + "text": "\uEFB9", + "sk": [ + { + "layer": "shift", + "id": "K_W", + "text": "\uEFBA" + } + ] + }, + { + "id": "K_E", + "text": "\uEFC1", + "sk": [ + { + "layer": "shift", + "id": "K_E", + "text": "\uEFC2" + }, + { + "layer": "shift", + "id": "K_S", + "text": "\uEFC3" + }, + { + "layer": "shift", + "id": "K_V", + "text": "\uEF12" + }, + { + "id": "U_17AF", + "text": "\u17AF" + }, + { + "id": "U_17B0", + "text": "\u17B0" + } + ] + }, + { + "id": "K_R", + "text": "\u179A", + "sk": [ + { + "id": "T_17D2_179A", + "text": "\uEF9A" + }, + { + "id": "U_17AB", + "text": "\u17AB" + }, + { + "id": "U_17AC", + "text": "\u17AC" + } + ] + }, + { + "id": "K_T", + "text": "\u178F", + "sk": [ + { + "layer": "shift", + "id": "K_T", + "text": "\u1791" + }, + { + "id": "T_17D2_178F", + "text": "\uEF8F" + }, + { + "layer": "default", + "id": "T_17D2_1791", + "text": "\uEF91" + } + ] + }, + { + "id": "K_Y", + "text": "\u1799", + "sk": [ + { + "id": "T_17D2_1799", + "text": "\uEF99" + } + ] + }, + { + "id": "K_U", + "text": "\uEFBB", + "sk": [ + { + "layer": "shift", + "id": "K_U", + "text": "\uEFBC" + }, + { + "layer": "shift", + "id": "K_Y", + "text": "\uEFBD" + }, + { + "id": "U_17A7", + "text": "\u17A7" + }, + { + "layer": "shift", + "id": "U_17AA", + "text": "\u17AA" + }, + { + "layer": "shift", + "id": "U_17A9", + "text": "\u17A9" + }, + { + "id": "U_17A8", + "text": "\u17A8" + } + ] + }, + { + "id": "K_I", + "text": "\uEFB7", + "sk": [ + { + "layer": "shift", + "id": "K_I", + "text": "\uEFB8" + }, + { + "id": "U_17A5", + "text": "\u17A5" + }, + { + "layer": "shift", + "id": "U_17A6", + "text": "\u17A6" + } + ] + }, + { + "id": "K_O", + "text": "\uEFC4", + "sk": [ + { + "layer": "shift", + "id": "K_O", + "text": "\uEFC5" + }, + { + "id": "K_LBRKT", + "text": "\uEFC0" + }, + { + "layer": "shift", + "id": "K_LBRKT", + "text": "\uEFBF" + }, + { + "layer": "shift", + "id": "K_COLON", + "text": "\uEF14" + }, + { + "id": "U_17B1", + "text": "\u17B1" + }, + { + "id": "U_17B2", + "text": "\u17B2" + }, + { + "layer": "shift", + "id": "U_17B3", + "text": "\u17B3" + } + ] + }, + { + "id": "K_P", + "text": "\u1795", + "sk": [ + { + "layer": "shift", + "id": "K_P", + "text": "\u1797" + }, + { + "id": "T_17D2_1795", + "text": "\uEF95" + }, + { + "layer": "default", + "id": "T_17D2_1797", + "text": "\uEF97" + } + ] + } + ] + }, + { + "id": "2", + "key": [ + { + "width": "100", + "id": "K_A", + "text": "\uEFB6", + "sk": [ + { + "layer": "shift", + "id": "K_A", + "text": "\uEF11" + } + ] + }, + { + "id": "K_S", + "text": "\u179F", + "sk": [ + { + "id": "T_17D2_179F", + "text": "\uEF9F" + }, + { + "id": "U_179D", + "text": "\u179D" + }, + { + "id": "U_179E", + "text": "\u179E" + } + ] + }, + { + "id": "K_D", + "text": "\u178A", + "sk": [ + { + "layer": "shift", + "id": "K_D", + "text": "\u178C" + }, + { + "id": "T_17D2_178A", + "text": "\uEF8A" + }, + { + "layer": "default", + "id": "T_17D2_178C", + "text": "\uEF8C" + } + ] + }, + { + "id": "K_F", + "text": "\u1790", + "sk": [ + { + "layer": "shift", + "id": "K_F", + "text": "\u1792" + }, + { + "id": "T_17D2_1790", + "text": "\uEF90" + }, + { + "layer": "default", + "id": "T_17D2_1792", + "text": "\uEF92" + } + ] + }, + { + "id": "K_G", + "text": "\u1784", + "sk": [ + { + "layer": "shift", + "id": "K_G", + "text": "\u17A2" + }, + { + "id": "T_17D2_1784", + "text": "\uEF84" + }, + { + "layer": "default", + "id": "T_17D2_17A2", + "text": "\uEFA2" + } + ] + }, + { + "id": "K_H", + "text": "\u17A0", + "sk": [ + { + "id": "T_17D2_17A0", + "text": "\uEFA0" + }, + { + "layer": "shift", + "id": "K_H", + "text": "\u17C7" + }, + { + "id": "U_17C8", + "text": "\u17C8" + } + ] + }, + { + "layer": "shift", + "id": "K_J", + "text": "\u1789", + "sk": [ + { + "id": "T_17D2_1789", + "text": "\uEF89" + } + ] + }, + { + "id": "K_K", + "text": "\u1780", + "sk": [ + { + "layer": "shift", + "id": "K_K", + "text": "\u1782" + }, + { + "id": "T_17D2_1780", + "text": "\uEF80" + }, + { + "id": "T_17D2_1782", + "text": "\uEF82" + } + ] + }, + { + "id": "K_L", + "text": "\u179B", + "sk": [ + { + "layer": "shift", + "id": "K_L", + "text": "\u17A1" + }, + { + "id": "T_17D2_179B", + "text": "\uEF9B" + }, + { + "id": "U_17AD", + "text": "\u17AD" + }, + { + "id": "U_17AE", + "text": "\u17AE" + } + ] + }, + { + "id": "K_COLON", + "text": "\uEFBE" + } + ] + }, + { + "id": "3", + "key": [ + { + "id": "K_Z", + "text": "\u178B", + "sk": [ + { + "layer": "shift", + "id": "K_Z", + "text": "\u178D" + }, + { + "id": "T_17D2_178B", + "text": "\uEF8B" + }, + { + "layer": "default", + "id": "T_17D2_178D", + "text": "\uEF8D" + } + ] + }, + { + "id": "K_X", + "text": "\u1781", + "sk": [ + { + "layer": "shift", + "id": "K_X", + "text": "\u1783" + }, + { + "id": "T_17D2_1781", + "text": "\uEF81" + }, + { + "layer": "default", + "id": "T_17D2_1783", + "text": "\uEF83" + } + ] + }, + { + "id": "K_C", + "text": "\u1785", + "sk": [ + { + "layer": "shift", + "id": "K_C", + "text": "\u1787" + }, + { + "id": "T_17D2_1785", + "text": "\uEF85" + }, + { + "layer": "default", + "id": "T_17D2_1787", + "text": "\uEF87" + } + ] + }, + { + "id": "K_V", + "text": "\u179C", + "sk": [ + { + "id": "T_17D2_179C", + "text": "\uEF9C" + } + ] + }, + { + "id": "K_B", + "text": "\u1794", + "sk": [ + { + "layer": "shift", + "id": "K_B", + "text": "\u1796" + }, + { + "id": "T_17D2_1794", + "text": "\uEF94" + }, + { + "layer": "default", + "id": "T_17D2_1796", + "text": "\uEF96" + } + ] + }, + { + "id": "K_N", + "text": "\u1793", + "sk": [ + { + "layer": "shift", + "id": "K_N", + "text": "\u178E" + }, + { + "id": "T_17D2_1793", + "text": "\uEF93" + }, + { + "layer": "default", + "id": "T_17D2_178E", + "text": "\uEF8E" + } + ] + }, + { + "id": "K_M", + "text": "\u1798", + "sk": [ + { + "id": "T_17D2_1798", + "text": "\uEF98" + }, + { + "layer": "shift", + "id": "K_M", + "text": "\uEFC6" + } + ] + }, + { + "id": "K_COMMA", + "text": "\uEF10", + "sk": [ + { + "layer": "shift", + "id": "K_COMMA", + "text": "\uEF13" + }, + { + "layer": "shift", + "id": "K_6", + "text": "\uEFCD" + }, + { + "layer": "shift", + "id": "K_7", + "text": "\uEFD0" + }, + { + "layer": "shift", + "id": "K_8", + "text": "\uEFCF" + }, + { + "layer": "shift", + "id": "K_HYPHEN", + "text": "\uEFCC" + }, + { + "layer": "shift", + "id": "U_17D1", + "text": "\uEFD1" + }, + { + "layer": "shift", + "id": "U_17DD", + "text": "\uEFDD" + }, + { + "layer": "shift", + "id": "U_17CE", + "text": "\uEFCE" + } + ] + }, + { + "width": "100", + "id": "K_QUOTE", + "text": "\uEFCB", + "sk": [ + { + "layer": "shift", + "id": "K_QUOTE", + "text": "\uEFC9" + }, + { + "id": "K_SLASH", + "text": "\uEFCA" + } + ] + }, + { + "width": "100", + "id": "K_BKSP", + "sp": "1", + "text": "*BkSp*" + } + ] + }, + { + "id": "4", + "key": [ + { + "nextlayer": "numeric", + "width": "140", + "id": "K_NUMLOCK", + "sp": "1", + "text": "\u17E1\u17E2\u17E3" + }, + { + "width": "120", + "id": "K_LOPT", + "sp": "1", + "text": "*Menu*" + }, + { + "width": "555", + "id": "K_SPACE", + "text": "\u200B", + "sk": [ + { + "layer": "default", + "id": "U_0020", + "text": " " + } + ] + }, + { + "width": "120", + "id": "K_PERIOD", + "text": "\u17D4", + "sk": [ + { + "layer": "shift", + "id": "K_PERIOD", + "text": "\u17D5" + }, + { + "id": "U_0021", + "text": "!" + }, + { + "id": "U_003F", + "text": "?" + } + ] + }, + { + "width": "140", + "id": "K_ENTER", + "sp": "1", + "text": "*Enter*" + } + ] + } + ] + }, + { + "id": "numeric", + "row": [ + { + "id": "1", + "key": [ + { + "id": "K_1", + "text": "\u17E1", + "sk": [ + { + "id": "U_0031", + "text": "1" + } + ] + }, + { + "id": "K_2", + "text": "\u17E2", + "sk": [ + { + "id": "U_0032", + "text": "2" + } + ] + }, + { + "id": "K_3", + "text": "\u17E3", + "sk": [ + { + "id": "U_0033", + "text": "3" + } + ] + }, + { + "id": "K_4", + "text": "\u17E4", + "sk": [ + { + "id": "U_0034", + "text": "4" + } + ] + }, + { + "id": "K_5", + "text": "\u17E5", + "sk": [ + { + "id": "U_0035", + "text": "5" + } + ] + }, + { + "id": "K_6", + "text": "\u17E6", + "sk": [ + { + "id": "U_0036", + "text": "6" + } + ] + }, + { + "id": "K_7", + "text": "\u17E7", + "sk": [ + { + "id": "U_0037", + "text": "7" + } + ] + }, + { + "id": "K_8", + "text": "\u17E8", + "sk": [ + { + "id": "U_0038", + "text": "8" + } + ] + }, + { + "id": "K_9", + "text": "\u17E9", + "sk": [ + { + "id": "U_0039", + "text": "9" + } + ] + }, + { + "id": "K_0", + "text": "\u17E0", + "sk": [ + { + "id": "U_0030", + "text": "0" + }, + { + "id": "U_17D3", + "text": "\uEFD3" + } + ] + } + ] + }, + { + "id": "2", + "key": [ + { + "id": "U_0040", + "text": "@", + "sk": [ + { + "id": "U_00A9", + "text": "\u00A9" + }, + { + "id": "U_00AE", + "text": "\u00AE" + } + ] + }, + { + "id": "U_0023", + "text": "#", + "sk": [ + { + "id": "U_2116", + "text": "\u2116" + }, + { + "id": "U_007E", + "text": "~" + } + ] + }, + { + "id": "U_17DB", + "text": "\u17DB", + "sk": [ + { + "id": "U_0024", + "text": "$" + }, + { + "id": "U_0E3F", + "text": "\u0E3F" + }, + { + "id": "U_00A2", + "text": "\u00A2" + }, + { + "id": "U_00A3", + "text": "\u00A3" + }, + { + "id": "U_00A5", + "text": "\u00A5" + } + ] + }, + { + "id": "U_0026", + "text": "&" + }, + { + "id": "U_0025", + "text": "%", + "sk": [ + { + "id": "U_2030", + "text": "\u2030" + }, + { + "id": "U_2031", + "text": "\u2031" + } + ] + }, + { + "id": "U_002B", + "text": "+", + "sk": [ + { + "id": "U_002D", + "text": "-" + }, + { + "id": "U_00D7", + "text": "\u00D7" + }, + { + "id": "U_00F7", + "text": "\u00F7" + }, + { + "id": "U_00B1", + "text": "\u00B1" + } + ] + }, + { + "id": "U_003D", + "text": "=", + "sk": [ + { + "id": "U_005F", + "text": "_" + }, + { + "id": "U_2260", + "text": "\u2260" + } + ] + }, + { + "id": "U_002A", + "text": "*", + "sk": [ + { + "id": "U_005E", + "text": "^" + } + ] + }, + { + "id": "U_003F", + "text": "?", + "sk": [ + { + "id": "U_00BF", + "text": "\u00BF" + } + ] + }, + { + "id": "U_0021", + "text": "!", + "sk": [ + { + "id": "U_00A1", + "text": "\u00A1" + } + ] + } + ] + }, + { + "id": "3", + "key": [ + { + "id": "U_2018", + "text": "\u2018", + "sk": [ + { + "id": "U_2019", + "text": "\u2019" + } + ] + }, + { + "id": "U_201C", + "text": "\u201C", + "sk": [ + { + "id": "U_201D", + "text": "\u201D" + } + ] + }, + { + "id": "U_00AB", + "text": "\u00AB", + "sk": [ + { + "id": "U_00BB", + "text": "\u00BB" + } + ] + }, + { + "id": "U_002F", + "text": "/", + "sk": [ + { + "id": "U_005C", + "text": "\\" + }, + { + "id": "U_007C", + "text": "|" + }, + { + "id": "U_00A6", + "text": "\u00A6" + } + ] + }, + { + "id": "U_0028", + "text": "(", + "sk": [ + { + "id": "U_0029", + "text": ")" + }, + { + "id": "U_005B", + "text": "[" + }, + { + "id": "U_005D", + "text": "]" + }, + { + "id": "U_007B", + "text": "{" + }, + { + "id": "U_007D", + "text": "}" + } + ] + }, + { + "id": "U_17D9", + "text": "\u17D9", + "sk": [ + { + "id": "U_17DA", + "text": "\u17DA" + }, + { + "id": "U_17DC", + "text": "\u17DC" + }, + { + "id": "U_00A7", + "text": "\u00A7" + }, + { + "id": "U_00D8", + "text": "\u00D8" + } + ] + }, + { + "id": "U_17D7", + "text": "\u17D7" + }, + { + "id": "U_003C", + "text": "<", + "sk": [ + { + "id": "U_2264", + "text": "\u2264" + }, + { + "id": "U_003E", + "text": ">" + }, + { + "id": "U_2265", + "text": "\u2265" + } + ] + }, + { + "id": "U_17D6", + "text": "\u17D6", + "sk": [ + { + "id": "U_003A", + "text": ":" + }, + { + "id": "U_003B", + "text": ";" + }, + { + "id": "U_2026", + "text": "\u2026" + } + ] + }, + { + "id": "K_BKSP", + "sp": "1", + "text": "*BkSp*" + } + ] + }, + { + "id": "4", + "key": [ + { + "nextlayer": "default", + "width": "140", + "id": "K_LCONTROL", + "sp": "2", + "text": "\u17E1\u17E2\u17E3" + }, + { + "width": "120", + "id": "K_LOPT", + "sp": "1", + "text": "*Menu*" + }, + { + "layer": "shift", + "width": "555", + "id": "K_SPACE", + "text": "\u200B" + }, + { + "width": "120", + "id": "K_PERIOD", + "text": "\u17D4", + "sk": [ + { + "layer": "shift", + "id": "K_PERIOD", + "text": "\u17D5" + }, + { + "id": "U_0021", + "text": "!" + }, + { + "id": "U_003F", + "text": "?" + } + ] + }, + { + "width": "140", + "id": "K_ENTER", + "sp": "1", + "text": "*Enter*" + } + ] + } + ] + } + ] + }, + "tablet": { + "font": "Khmer Busra Kbd", + "fontsize": "0.8em", + "displayUnderlying": false, + "layer": [ + { + "id": "default", + "row": [ + { + "id": "1", + "key": [ + { + "id": "K_1", + "text": "\u17E1" + }, + { + "id": "K_2", + "text": "\u17E2" + }, + { + "id": "K_3", + "text": "\u17E3" + }, + { + "id": "K_4", + "text": "\u17E4" + }, + { + "id": "K_5", + "text": "\u17E5" + }, + { + "id": "K_6", + "text": "\u17E6" + }, + { + "id": "K_7", + "text": "\u17E7" + }, + { + "id": "K_8", + "text": "\u17E8" + }, + { + "id": "K_9", + "text": "\u17E9" + }, + { + "id": "K_0", + "text": "\u17E0" + }, + { + "id": "K_HYPHEN", + "text": "\u17A5" + }, + { + "id": "K_EQUAL", + "text": "\u17B2" + }, + { + "width": "100", + "id": "K_BKSP", + "sp": "1", + "text": "*BkSp*" + } + ] + }, + { + "id": "2", + "key": [ + { + "id": "K_Q", + "pad": "75", + "text": "\u1786" + }, + { + "id": "K_W", + "text": "\uEFB9" + }, + { + "id": "K_E", + "text": "\uEFC1" + }, + { + "id": "K_R", + "text": "\u179A" + }, + { + "id": "K_T", + "text": "\u178F" + }, + { + "id": "K_Y", + "text": "\u1799" + }, + { + "id": "K_U", + "text": "\uEFBB" + }, + { + "id": "K_I", + "text": "\uEFB7" + }, + { + "id": "K_O", + "text": "\uEFC4" + }, + { + "id": "K_P", + "text": "\u1795" + }, + { + "id": "K_LBRKT", + "text": "\uEFC0" + }, + { + "id": "K_RBRKT", + "text": "\u17AA" + }, + { + "width": "10", + "id": "T_new_138", + "sp": "10" + } + ] + }, + { + "id": "3", + "key": [ + { + "id": "K_BKQUOTE", + "text": "\u00AB" + }, + { + "id": "K_A", + "text": "\uEFB6" + }, + { + "id": "K_S", + "text": "\u179F" + }, + { + "id": "K_D", + "text": "\u178A" + }, + { + "id": "K_F", + "text": "\u1790" + }, + { + "id": "K_G", + "text": "\u1784" + }, + { + "id": "K_H", + "text": "\u17A0" + }, + { + "id": "K_J", + "text": "\uEFD2" + }, + { + "id": "K_K", + "text": "\u1780" + }, + { + "id": "K_L", + "text": "\u179B" + }, + { + "id": "K_COLON", + "text": "\uEFBE" + }, + { + "id": "K_QUOTE", + "text": "\uEFCB" + }, + { + "id": "K_BKSLASH", + "text": "\u17AE" + } + ] + }, + { + "id": "4", + "key": [ + { + "nextlayer": "shift", + "width": "160", + "id": "K_SHIFT", + "sp": "1", + "text": "*Shift*" + }, + { + "id": "K_oE2" + }, + { + "id": "K_Z", + "text": "\u178B" + }, + { + "id": "K_X", + "text": "\u1781" + }, + { + "id": "K_C", + "text": "\u1785" + }, + { + "id": "K_V", + "text": "\u179C" + }, + { + "id": "K_B", + "text": "\u1794" + }, + { + "id": "K_N", + "text": "\u1793" + }, + { + "id": "K_M", + "text": "\u1798" + }, + { + "id": "K_COMMA", + "text": "\uEF10" + }, + { + "id": "K_PERIOD", + "text": "\u17D4" + }, + { + "id": "K_SLASH", + "text": "\uEFCA" + }, + { + "width": "10", + "id": "T_new_164", + "sp": "10" + } + ] + }, + { + "id": "5", + "key": [ + { + "nextlayer": "rightalt", + "width": "160", + "id": "K_LCONTROL", + "sp": "1", + "text": "*AltGr*" + }, + { + "width": "160", + "id": "K_LOPT", + "sp": "1", + "text": "*Menu*" + }, + { + "width": "930", + "id": "K_SPACE", + "text": "\u200B" + }, + { + "width": "160", + "id": "K_ENTER", + "sp": "1", + "text": "*Enter*" + } + ] + } + ] + }, + { + "id": "rightalt", + "row": [ + { + "id": "1", + "key": [ + { + "id": "K_1", + "text": "\u200C" + }, + { + "id": "K_2", + "text": "@" + }, + { + "id": "K_3", + "text": "\uEFD1" + }, + { + "id": "K_4", + "text": "$" + }, + { + "id": "K_5", + "text": "\u20AC" + }, + { + "id": "K_6", + "text": "\u17D9" + }, + { + "id": "K_7", + "text": "\u17DA" + }, + { + "id": "K_8", + "text": "*" + }, + { + "id": "K_9", + "text": "{" + }, + { + "id": "K_0", + "text": "}" + }, + { + "id": "K_HYPHEN", + "text": "\u2248" + }, + { + "id": "K_EQUAL", + "text": "\uEFCE" + }, + { + "width": "100", + "id": "K_BKSP", + "sp": "1", + "text": "*BkSp*" + } + ] + }, + { + "id": "2", + "key": [ + { + "id": "K_Q", + "pad": "75", + "text": "\u17DC" + }, + { + "id": "K_W", + "text": "\uEFDD" + }, + { + "id": "K_E", + "text": "\u17AF" + }, + { + "id": "K_R", + "text": "\u17AB" + }, + { + "id": "K_T", + "text": "\u17A8" + }, + { + "id": "K_Y", + "text": "[" + }, + { + "id": "K_U", + "text": "]" + }, + { + "id": "K_I", + "text": "\u17A6" + }, + { + "id": "K_O", + "text": "\u17B1" + }, + { + "id": "K_P", + "text": "\u17B0" + }, + { + "id": "K_LBRKT", + "text": "\u17A9" + }, + { + "id": "K_RBRKT", + "text": "\u17B3" + }, + { + "width": "10", + "id": "T_new_307", + "sp": "10" + } + ] + }, + { + "id": "3", + "key": [ + { + "id": "K_BKQUOTE", + "text": "\u200D" + }, + { + "id": "K_A", + "text": "+" + }, + { + "id": "K_S", + "text": "-" + }, + { + "id": "K_D", + "text": "\u00D7" + }, + { + "id": "K_F", + "text": "\u00F7" + }, + { + "id": "K_G", + "text": ":" + }, + { + "id": "K_H", + "text": "\u2018" + }, + { + "id": "K_J", + "text": "\u2019" + }, + { + "id": "K_K", + "text": "\u179D" + }, + { + "id": "K_L", + "text": "\u17D8" + }, + { + "id": "K_COLON", + "text": "\u17D6" + }, + { + "id": "K_QUOTE", + "text": "\u17C8" + }, + { + "id": "K_BKSLASH", + "text": "\\" + } + ] + }, + { + "id": "4", + "key": [ + { + "nextlayer": "shift", + "width": "160", + "id": "K_SHIFT", + "sp": "1", + "text": "*Shift*" + }, + { + "id": "K_oE2" + }, + { + "id": "K_Z", + "text": "<" + }, + { + "id": "K_X", + "text": ">" + }, + { + "id": "K_C", + "text": "#" + }, + { + "id": "K_V", + "text": "&" + }, + { + "id": "K_B", + "text": "\u179E" + }, + { + "id": "K_N", + "text": ";" + }, + { + "id": "K_M", + "text": "\uEFD3" + }, + { + "id": "K_COMMA", + "text": "," + }, + { + "id": "K_PERIOD", + "text": "." + }, + { + "id": "K_SLASH", + "text": "/" + }, + { + "width": "10", + "id": "T_new_333", + "sp": "10" + } + ] + }, + { + "id": "5", + "key": [ + { + "nextlayer": "default", + "width": "160", + "id": "K_LCONTROL", + "sp": "2", + "text": "*AltGr*" + }, + { + "width": "160", + "id": "K_LOPT", + "sp": "1", + "text": "*Menu*" + }, + { + "width": "930", + "id": "K_SPACE", + "text": "\u00A0" + }, + { + "width": "160", + "id": "K_ENTER", + "sp": "1", + "text": "*Enter*" + } + ] + } + ] + }, + { + "id": "shift", + "row": [ + { + "id": "1", + "key": [ + { + "id": "K_1", + "text": "!" + }, + { + "id": "K_2", + "text": "\u17D7" + }, + { + "id": "K_3", + "text": "\"" + }, + { + "id": "K_4", + "text": "\u17DB" + }, + { + "id": "K_5", + "text": "%" + }, + { + "id": "K_6", + "text": "\uEFCD" + }, + { + "id": "K_7", + "text": "\uEFD0" + }, + { + "id": "K_8", + "text": "\uEFCF" + }, + { + "id": "K_9", + "text": "(" + }, + { + "id": "K_0", + "text": ")" + }, + { + "id": "K_HYPHEN", + "text": "\uEFCC" + }, + { + "id": "K_EQUAL", + "text": "=" + }, + { + "width": "100", + "id": "K_BKSP", + "sp": "1", + "text": "*BkSp*" + } + ] + }, + { + "id": "2", + "key": [ + { + "id": "K_Q", + "pad": "75", + "text": "\u1788" + }, + { + "id": "K_W", + "text": "\uEFBA" + }, + { + "id": "K_E", + "text": "\uEFC2" + }, + { + "id": "K_R", + "text": "\u17AC" + }, + { + "id": "K_T", + "text": "\u1791" + }, + { + "id": "K_Y", + "text": "\uEFBD" + }, + { + "id": "K_U", + "text": "\uEFBC" + }, + { + "id": "K_I", + "text": "\uEFB8" + }, + { + "id": "K_O", + "text": "\uEFC5" + }, + { + "id": "K_P", + "text": "\u1797" + }, + { + "id": "K_LBRKT", + "text": "\uEFBF" + }, + { + "id": "K_RBRKT", + "text": "\u17A7" + }, + { + "width": "10", + "id": "T_new_364", + "sp": "10" + } + ] + }, + { + "id": "3", + "key": [ + { + "id": "K_BKQUOTE", + "text": "\u00BB" + }, + { + "id": "K_A", + "text": "\uEF11" + }, + { + "id": "K_S", + "text": "\uEFC3" + }, + { + "id": "K_D", + "text": "\u178C" + }, + { + "id": "K_F", + "text": "\u1792" + }, + { + "id": "K_G", + "text": "\u17A2" + }, + { + "id": "K_H", + "text": "\u17C7" + }, + { + "id": "K_J", + "text": "\u1789" + }, + { + "id": "K_K", + "text": "\u1782" + }, + { + "id": "K_L", + "text": "\u17A1" + }, + { + "id": "K_COLON", + "text": "\uEF14" + }, + { + "id": "K_QUOTE", + "text": "\uEFC9" + }, + { + "id": "K_BKSLASH", + "text": "\u17AD" + } + ] + }, + { + "id": "4", + "key": [ + { + "nextlayer": "default", + "width": "160", + "id": "K_SHIFT", + "sp": "2", + "text": "*Shift*" + }, + { + "id": "K_oE2" + }, + { + "id": "K_Z", + "text": "\u178D" + }, + { + "id": "K_X", + "text": "\u1783" + }, + { + "id": "K_C", + "text": "\u1787" + }, + { + "id": "K_V", + "text": "\uEF12" + }, + { + "id": "K_B", + "text": "\u1796" + }, + { + "id": "K_N", + "text": "\u178E" + }, + { + "id": "K_M", + "text": "\uEFC6" + }, + { + "id": "K_COMMA", + "text": "\uEF13" + }, + { + "id": "K_PERIOD", + "text": "\u17D5" + }, + { + "id": "K_SLASH", + "text": "?" + }, + { + "width": "10", + "id": "T_new_390", + "sp": "10" + } + ] + }, + { + "id": "5", + "key": [ + { + "nextlayer": "rightalt", + "width": "160", + "id": "K_LCONTROL", + "sp": "1", + "text": "*AltGr*" + }, + { + "width": "160", + "id": "K_LOPT", + "sp": "1", + "text": "*Menu*" + }, + { + "width": "930", + "id": "K_SPACE" + }, + { + "width": "160", + "id": "K_ENTER", + "sp": "1", + "text": "*Enter*" + } + ] + } + ] + } + ] + } +} +; + this.s_c_key_11=['','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','']; + this.s_c_out_12="កខគឃងចឆជឈញដឋឌឍណតថទធនបផពភមយរលវសហឡអឝឞ"; + this.s_v_gen_key_13=['','','','','','','','','','','','','','','','']; + this.s_v_gen_14="ាិីឹឺុូួើឿៀេែៃោៅ"; + this.s_v_pseudo_key_15=['','','']; + this.s_v_pseudo_16="ំះៈ"; + this.s_v_key_17=['','','','','','','','','','','','','','','','','','','']; + this.s_v_out_18="ាិីឹឺុូួើឿៀេែៃោៅំះៈ"; + this.s_v_any_19="ាិីឹឺុូួើឿៀេែៃោៅំះៈ"; + this.s_v_combo_R_20="េោុិីឹែ"; + this.s_v_combo_N_21="ាុ"; + this.s_v_combo_22="េោុិីឹែាុ"; + this.s_ind_v_key_23=['','','','','','','','','','','','','','','']; + this.s_ind_v_out_24="ឥឦឧឨឩឪឫឬឭឮឯឰឱឲឳ"; + this.s_diacritic_key_25=['','','','','','','','','','','']; + this.s_diacritic_out_26="់័៌៏៍ៈ៎៑៝ៜ្"; + this.s_c_shifter_key_27=['','']; + this.s_c_shifter_28="៉៊"; + this.s_punct_key_29=['','','','','','','','']; + this.s_punct_out_30="។៕៖ៗ៘៙៚៓"; + this.s_latin_punct_key_31=['','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','']; + this.s_latin_punct_out_32="«»()!\"%=?{}\\@*,×./[]‍‌+-÷:≈‘’;<>#&"; + this.s_spaces_key_33=['','','']; + this.s_spaces_out_34="​  "; + this.s_currency_key_35=['','','']; + this.s_currency_out_36="៛$€"; + this.s_digit_key_37=['','','','','','','','','','']; + this.s_digit_out_38="០១២៣៤៥៦៧៨៩"; + this.s_lek_attak_key_39=['','','','','','','','','','']; + this.s_lek_attak_out_40="៰៱៲៳៴៵៶៷៸៹"; + this.s_lunar_date_key_41=['','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','']; + this.s_lunar_date_out_42="᧬᧻᧹᧮᧢᧯᧰᧱᧧᧲᧳᧴᧽᧼᧨᧩᧠᧣᧭᧤᧦᧺᧡᧸᧥᧷᧵᧾᧿᧪᧫᧶"; + this.s_input_subcons_43=['','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','']; + this.s_subcons_44="កខគឃងចឆជឈញដឋឌឍណតថទធនបផពភមយរលវឝឞសហឡអ"; + this.s_arabic_digit_key_45=['','','','','','','','','','']; + this.s_arabic_digit_out_46="0123456789"; + this.s_v_above_47="ិីឹឺើ័"; + this.s_shiftable_c_1st_48="សហអ"; + this.s_shiftable_BA_49="ប"; + this.s_shiftable_c_2nd_50="ងញមយរវនល"; + this.s_shiftable_c_2nd_with_BA_51="ងញមយរវនលប"; + this.s_c_2nd_combo_LO_52="យមងបវ"; + this.s_c_2nd_combo_MO_53="យលងរ"; + this.s_c_1st_combo_LO_54="បហអ"; + this.s_c_1st_combo_MO_55="ហសអ"; + this.s_c_combo_SA_56="បយលមនញងរវអ"; + this.s_c_combo_QA_57="ឆឈបផតទ"; + this.s_c_combo_HA_58="វឣ"; + this.s62="touch"; + this.KVS=[]; + this.gs=function(t,e) { + return this.g_main_0(t,e); + }; + this.gs=function(t,e) { + return this.g_main_0(t,e); + }; + this.g_main_0=function(t,e) { + var k=KeymanWeb,r=0,m=0; + if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_BKSP /* 0x08 */)) { + if(k.KFCM(2,t,['្',{t:'a',a:this.s_c_out_12}])&&k.KIFS(31,this.s62,t)){ + r=m=1; // Line 266 + k.KDC(2,t); + } + else if(k.KFCM(2,t,[{t:'a',a:this.s_v_combo_N_21},'ំ'])){ + r=m=1; // Line 229 + k.KDC(2,t); + } + else if(k.KFCM(2,t,[{t:'a',a:this.s_v_combo_R_20},'ះ'])){ + r=m=1; // Line 230 + k.KDC(2,t); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_B /* 0x42 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ឞ"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_K /* 0x4B */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ឝ"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_QUOTE /* 0xDE */)) { + if(1){ + r=m=1; // Line 189 + k.KDC(0,t); + k.KO(-1,t,"ៈ"); + } + else if(1){ + r=m=1; // Line 191 + k.KDC(0,t); + k.KO(-1,t,"ៈ"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_E /* 0x45 */)) { + if(1){ + r=m=1; // Line 190 + k.KDC(0,t); + k.KO(-1,t,"ឯ"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_I /* 0x49 */)) { + if(1){ + r=m=1; // Line 190 + k.KDC(0,t); + k.KO(-1,t,"ឦ"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_O /* 0x4F */)) { + if(1){ + r=m=1; // Line 190 + k.KDC(0,t); + k.KO(-1,t,"ឱ"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_P /* 0x50 */)) { + if(1){ + r=m=1; // Line 190 + k.KDC(0,t); + k.KO(-1,t,"ឰ"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_R /* 0x52 */)) { + if(1){ + r=m=1; // Line 190 + k.KDC(0,t); + k.KO(-1,t,"ឫ"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_T /* 0x54 */)) { + if(1){ + r=m=1; // Line 190 + k.KDC(0,t); + k.KO(-1,t,"ឨ"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_LBRKT /* 0xDB */)) { + if(1){ + r=m=1; // Line 190 + k.KDC(0,t); + k.KO(-1,t,"ឩ"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_RBRKT /* 0xDD */)) { + if(1){ + r=m=1; // Line 190 + k.KDC(0,t); + k.KO(-1,t,"ឳ"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_3 /* 0x33 */)) { + if(1){ + r=m=1; // Line 191 + k.KDC(0,t); + k.KO(-1,t,"៑"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_Q /* 0x51 */)) { + if(1){ + r=m=1; // Line 191 + k.KDC(0,t); + k.KO(-1,t,"ៜ"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_W /* 0x57 */)) { + if(1){ + r=m=1; // Line 191 + k.KDC(0,t); + k.KO(-1,t,"៝"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_EQUAL /* 0xBB */)) { + if(1){ + r=m=1; // Line 191 + k.KDC(0,t); + k.KO(-1,t,"៎"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_6 /* 0x36 */)) { + if(1){ + r=m=1; // Line 193 + k.KDC(0,t); + k.KO(-1,t,"៙"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_7 /* 0x37 */)) { + if(1){ + r=m=1; // Line 193 + k.KDC(0,t); + k.KO(-1,t,"៚"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_L /* 0x4C */)) { + if(1){ + r=m=1; // Line 193 + k.KDC(0,t); + k.KO(-1,t,"៘"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_M /* 0x4D */)) { + if(1){ + r=m=1; // Line 193 + k.KDC(0,t); + k.KO(-1,t,"៓"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_COLON /* 0xBA */)) { + if(1){ + r=m=1; // Line 193 + k.KDC(0,t); + k.KO(-1,t,"៖"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_0 /* 0x30 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"}"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_1 /* 0x31 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"‌"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_2 /* 0x32 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"@"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_8 /* 0x38 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"*"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_9 /* 0x39 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"{"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_A /* 0x41 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"+"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_C /* 0x43 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"#"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_D /* 0x44 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"×"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_F /* 0x46 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"÷"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_G /* 0x47 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,":"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_H /* 0x48 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"‘"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_J /* 0x4A */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"’"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_N /* 0x4E */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,";"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_S /* 0x53 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"-"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_U /* 0x55 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"]"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_V /* 0x56 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"&"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_X /* 0x58 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,">"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_Y /* 0x59 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"["); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_Z /* 0x5A */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"<"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_COMMA /* 0xBC */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,","); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_HYPHEN /* 0xBD */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"≈"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_PERIOD /* 0xBE */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"."); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_SLASH /* 0xBF */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"/"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_BKQUOTE /* 0xC0 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"‍"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_BKSLASH /* 0xDC */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"\\"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_4 /* 0x34 */)) { + if(1){ + r=m=1; // Line 195 + k.KDC(0,t); + k.KO(-1,t,"$"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_5 /* 0x35 */)) { + if(1){ + r=m=1; // Line 195 + k.KDC(0,t); + k.KO(-1,t,"€"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_0 /* 0x30 */)) { + if(1){ + r=m=1; // Line 197 + k.KDC(0,t); + k.KO(-1,t,"៰"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_1 /* 0x31 */)) { + if(1){ + r=m=1; // Line 197 + k.KDC(0,t); + k.KO(-1,t,"៱"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_2 /* 0x32 */)) { + if(1){ + r=m=1; // Line 197 + k.KDC(0,t); + k.KO(-1,t,"៲"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_3 /* 0x33 */)) { + if(1){ + r=m=1; // Line 197 + k.KDC(0,t); + k.KO(-1,t,"៳"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_4 /* 0x34 */)) { + if(1){ + r=m=1; // Line 197 + k.KDC(0,t); + k.KO(-1,t,"៴"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_5 /* 0x35 */)) { + if(1){ + r=m=1; // Line 197 + k.KDC(0,t); + k.KO(-1,t,"៵"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_6 /* 0x36 */)) { + if(1){ + r=m=1; // Line 197 + k.KDC(0,t); + k.KO(-1,t,"៶"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_7 /* 0x37 */)) { + if(1){ + r=m=1; // Line 197 + k.KDC(0,t); + k.KO(-1,t,"៷"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_8 /* 0x38 */)) { + if(1){ + r=m=1; // Line 197 + k.KDC(0,t); + k.KO(-1,t,"៸"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_9 /* 0x39 */)) { + if(1){ + r=m=1; // Line 197 + k.KDC(0,t); + k.KO(-1,t,"៹"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_A /* 0x41 */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧬"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_B /* 0x42 */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧻"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_C /* 0x43 */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧹"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_D /* 0x44 */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧮"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_E /* 0x45 */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧢"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_F /* 0x46 */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧯"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_G /* 0x47 */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧰"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_H /* 0x48 */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧱"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_I /* 0x49 */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧧"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_J /* 0x4A */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧲"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_K /* 0x4B */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧳"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_L /* 0x4C */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧴"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_M /* 0x4D */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧽"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_N /* 0x4E */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧼"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_O /* 0x4F */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧨"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_P /* 0x50 */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧩"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_Q /* 0x51 */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧠"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_R /* 0x52 */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧣"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_S /* 0x53 */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧭"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_T /* 0x54 */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧤"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_U /* 0x55 */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧦"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_V /* 0x56 */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧺"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_W /* 0x57 */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧡"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_X /* 0x58 */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧸"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_Y /* 0x59 */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧥"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_Z /* 0x5A */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧷"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_COLON /* 0xBA */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧵"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_COMMA /* 0xBC */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧾"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_PERIOD /* 0xBE */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧿"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_LBRKT /* 0xDB */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧪"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_RBRKT /* 0xDD */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧫"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4018 */, keyCodes.K_QUOTE /* 0xDE */)) { + if(1){ + r=m=1; // Line 198 + k.KDC(0,t); + k.KO(-1,t,"᧶"); + } + } + else if(k.KKM(e, modCodes.RALT | modCodes.VIRTUAL_KEY /* 0x4008 */, keyCodes.K_SPACE /* 0x20 */)) { + if(1){ + r=m=1; // Line 199 + k.KDC(0,t); + k.KO(-1,t," "); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x100)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ក"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x101)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ខ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x102)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្គ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x103)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ឃ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x104)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ង"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x105)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ច"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x106)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ឆ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x107)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ជ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x108)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ឈ"); + } + } + if(m) {} + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x109)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ញ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x10A)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ដ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x10B)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ឋ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x10C)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ឌ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x10D)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ឍ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x10E)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ណ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x10F)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ត"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x110)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ថ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x111)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ទ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x112)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ធ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x113)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ន"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x114)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ប"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x115)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ផ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x116)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ព"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x117)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ភ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x118)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ម"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x119)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្យ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x11A)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្រ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x11B)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ល"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x11C)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្វ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x11D)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ឝ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x11E)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ឞ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x11F)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ស"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x120)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ហ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x121)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្ឡ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, 0x122)) { + if(1){ + r=m=1; // Line 262 + k.KDC(0,t); + k.KO(-1,t,"្អ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_NPSTAR /* 0x6A */)) { + if(1){ + r=m=1; // Line 268 + k.KDC(0,t); + k.KO(-1,t,"*"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_NPSTAR /* 0x6A */)) { + if(1){ + r=m=1; // Line 269 + k.KDC(0,t); + k.KO(-1,t,"*"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_NPPLUS /* 0x6B */)) { + if(1){ + r=m=1; // Line 270 + k.KDC(0,t); + k.KO(-1,t,"+"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_NPPLUS /* 0x6B */)) { + if(1){ + r=m=1; // Line 271 + k.KDC(0,t); + k.KO(-1,t,"+"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_NPMINUS /* 0x6D */)) { + if(1){ + r=m=1; // Line 272 + k.KDC(0,t); + k.KO(-1,t,"-"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_NPMINUS /* 0x6D */)) { + if(1){ + r=m=1; // Line 273 + k.KDC(0,t); + k.KO(-1,t,"-"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_NPDOT /* 0x6E */)) { + if(1){ + r=m=1; // Line 274 + k.KDC(0,t); + k.KO(-1,t,"."); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_NPDOT /* 0x6E */)) { + if(1){ + r=m=1; // Line 275 + k.KDC(0,t); + k.KO(-1,t,"."); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_NPSLASH /* 0x6F */)) { + if(1){ + r=m=1; // Line 276 + k.KDC(0,t); + k.KO(-1,t,"/"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_NPSLASH /* 0x6F */)) { + if(1){ + r=m=1; // Line 277 + k.KDC(0,t); + k.KO(-1,t,"/"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_SPACE /* 0x20 */)) { + if(k.KFCM(1,t,['​'])){ + r=m=1; // Line 225 + k.KDC(1,t); + k.KO(-1,t," "); + } + else if(1){ + r=m=1; // Line 199 + k.KDC(0,t); + k.KO(-1,t,"​"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_SPACE /* 0x20 */)) { + if(1){ + r=m=1; // Line 199 + k.KDC(0,t); + k.KO(-1,t," "); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_1 /* 0x31 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"!"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_QUOTE /* 0xDE */)) { + if(k.KFCM(3,t,[{t:'a',a:this.s_c_combo_QA_57},'្','អ'])){ + r=m=1; // Line 244 + k.KDC(3,t); + k.KIO(-1,this.s_c_combo_QA_57,1,t); + k.KO(-1,t,"្អ៉"); + k.KB(t); + } + else if(k.KFCM(3,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO_54}])){ + r=m=1; // Line 245 + k.KDC(3,t); + k.KO(-1,t,"ល្"); + k.KIO(-1,this.s_c_1st_combo_LO_54,3,t); + k.KO(-1,t,"៉"); + k.KB(t); + } + else if(k.KFCM(3,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO_55}])){ + r=m=1; // Line 246 + k.KDC(3,t); + k.KO(-1,t,"ម្"); + k.KIO(-1,this.s_c_1st_combo_MO_55,3,t); + k.KO(-1,t,"៉"); + k.KB(t); + } + else if(k.KFCM(3,t,['ស','្',{t:'a',a:this.s_c_combo_SA_56}])){ + r=m=1; // Line 247 + k.KDC(3,t); + k.KO(-1,t,"ស្"); + k.KIO(-1,this.s_c_combo_SA_56,3,t); + k.KO(-1,t,"៉"); + k.KB(t); + } + else if(k.KFCM(3,t,[{t:'a',a:this.s_c_combo_HA_58},'្','ហ'])){ + r=m=1; // Line 248 + k.KDC(3,t); + k.KIO(-1,this.s_c_combo_HA_58,1,t); + k.KO(-1,t,"្ហ៉"); + k.KB(t); + } + else if(k.KFCM(3,t,['អ','្','ង'])){ + r=m=1; // Line 249 + k.KDC(3,t); + k.KO(-1,t,"អ្ង៉"); + k.KB(t); + } + else if(k.KFCM(3,t,['អ','្','វ'])){ + r=m=1; // Line 250 + k.KDC(3,t); + k.KO(-1,t,"អ្វ៉"); + k.KB(t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_c_shifter_28}])){ + r=m=1; // Line 215 + k.KDC(1,t); + k.KIO(-1,this.s_c_shifter_28,1,t); + k.KB(t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_shiftable_c_1st_48}])){ + r=m=1; // Line 239 + k.KDC(1,t); + k.KIO(-1,this.s_shiftable_c_1st_48,1,t); + k.KO(-1,t,"៉"); + k.KB(t); + } + else if(1){ + r=m=1; // Line 192 + k.KDC(0,t); + k.KO(-1,t,"៉"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_3 /* 0x33 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"\""); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_4 /* 0x34 */)) { + if(1){ + r=m=1; // Line 195 + k.KDC(0,t); + k.KO(-1,t,"៛"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_5 /* 0x35 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"%"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_7 /* 0x37 */)) { + if(1){ + r=m=1; // Line 191 + k.KDC(0,t); + k.KO(-1,t,"័"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_QUOTE /* 0xDE */)) { + if(k.KFCM(2,t,['្',{t:'a',a:this.s_c_out_12}])){ + r=m=1; // Line 214 + k.KDC(2,t); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_out_12,2,t); + k.KB(t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_v_gen_14}])){ + r=m=1; // Line 211 + k.KDC(1,t); + k.KIO(-1,this.s_v_gen_14,1,t); + k.KB(t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_v_pseudo_16}])){ + r=m=1; // Line 212 + k.KDC(1,t); + k.KIO(-1,this.s_v_pseudo_16,1,t); + k.KB(t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_c_shifter_28}])){ + r=m=1; // Line 213 + k.KDC(1,t); + k.KIO(-1,this.s_c_shifter_28,1,t); + k.KB(t); + } + else if(1){ + r=m=1; // Line 191 + k.KDC(0,t); + k.KO(-1,t,"់"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_9 /* 0x39 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"("); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_0 /* 0x30 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,")"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_8 /* 0x38 */)) { + if(1){ + r=m=1; // Line 191 + k.KDC(0,t); + k.KO(-1,t,"៏"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_EQUAL /* 0xBB */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"="); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_COMMA /* 0xBC */)) { + if(1){ + r=m=1; // Line 206 + k.KDC(0,t); + k.KO(-1,t,"ុំ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_HYPHEN /* 0xBD */)) { + if(1){ + r=m=1; // Line 190 + k.KDC(0,t); + k.KO(-1,t,"ឥ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_PERIOD /* 0xBE */)) { + if(1){ + r=m=1; // Line 193 + k.KDC(0,t); + k.KO(-1,t,"។"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_SLASH /* 0xBF */)) { + if(k.KFCM(3,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO_52}])){ + r=m=1; // Line 254 + k.KDC(3,t); + k.KO(-1,t,"ល្"); + k.KIO(-1,this.s_c_2nd_combo_LO_52,3,t); + k.KO(-1,t,"៊"); + k.KB(t); + } + else if(k.KFCM(3,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO_53}])){ + r=m=1; // Line 255 + k.KDC(3,t); + k.KO(-1,t,"ម្"); + k.KIO(-1,this.s_c_2nd_combo_MO_53,3,t); + k.KO(-1,t,"៊"); + k.KB(t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_c_shifter_28}])){ + r=m=1; // Line 215 + k.KDC(1,t); + k.KIO(-1,this.s_c_shifter_28,1,t); + k.KB(t); + } + else if(k.KFCM(1,t,[{t:'a',a:this.s_shiftable_c_2nd_with_BA_51}])){ + r=m=1; // Line 240 + k.KDC(1,t); + k.KIO(-1,this.s_shiftable_c_2nd_with_BA_51,1,t); + k.KO(-1,t,"៊"); + k.KB(t); + } + else if(1){ + r=m=1; // Line 192 + k.KDC(0,t); + k.KO(-1,t,"៊"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_0 /* 0x30 */)) { + if(1){ + r=m=1; // Line 196 + k.KDC(0,t); + k.KO(-1,t,"០"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_1 /* 0x31 */)) { + if(1){ + r=m=1; // Line 196 + k.KDC(0,t); + k.KO(-1,t,"១"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_2 /* 0x32 */)) { + if(1){ + r=m=1; // Line 196 + k.KDC(0,t); + k.KO(-1,t,"២"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_3 /* 0x33 */)) { + if(1){ + r=m=1; // Line 196 + k.KDC(0,t); + k.KO(-1,t,"៣"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_4 /* 0x34 */)) { + if(1){ + r=m=1; // Line 196 + k.KDC(0,t); + k.KO(-1,t,"៤"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_5 /* 0x35 */)) { + if(1){ + r=m=1; // Line 196 + k.KDC(0,t); + k.KO(-1,t,"៥"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_6 /* 0x36 */)) { + if(1){ + r=m=1; // Line 196 + k.KDC(0,t); + k.KO(-1,t,"៦"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_7 /* 0x37 */)) { + if(1){ + r=m=1; // Line 196 + k.KDC(0,t); + k.KO(-1,t,"៧"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_8 /* 0x38 */)) { + if(1){ + r=m=1; // Line 196 + k.KDC(0,t); + k.KO(-1,t,"៨"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_9 /* 0x39 */)) { + if(1){ + r=m=1; // Line 196 + k.KDC(0,t); + k.KO(-1,t,"៩"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_COLON /* 0xBA */)) { + if(1){ + r=m=1; // Line 205 + k.KDC(0,t); + k.KO(-1,t,"ោះ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_COLON /* 0xBA */)) { + if(1){ + r=m=1; // Line 189 + k.KDC(0,t); + k.KO(-1,t,"ើ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_COMMA /* 0xBC */)) { + if(1){ + r=m=1; // Line 207 + k.KDC(0,t); + k.KO(-1,t,"ុះ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_EQUAL /* 0xBB */)) { + if(1){ + r=m=1; // Line 190 + k.KDC(0,t); + k.KO(-1,t,"ឲ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_PERIOD /* 0xBE */)) { + if(1){ + r=m=1; // Line 193 + k.KDC(0,t); + k.KO(-1,t,"៕"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_SLASH /* 0xBF */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"?"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_2 /* 0x32 */)) { + if(1){ + r=m=1; // Line 193 + k.KDC(0,t); + k.KO(-1,t,"ៗ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_A /* 0x41 */)) { + if(1){ + r=m=1; // Line 203 + k.KDC(0,t); + k.KO(-1,t,"ាំ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_B /* 0x42 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ព"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_C /* 0x43 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ជ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_D /* 0x44 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ឌ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_E /* 0x45 */)) { + if(1){ + r=m=1; // Line 189 + k.KDC(0,t); + k.KO(-1,t,"ែ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_F /* 0x46 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ធ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_G /* 0x47 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"អ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_H /* 0x48 */)) { + if(k.KFCM(1,t,['ះ'])){ + r=m=1; // Line 219 + k.KDC(1,t); + k.KO(-1,t,"ៈ"); + } + else if(k.KFCM(1,t,['ៈ'])){ + r=m=1; // Line 220 + k.KDC(1,t); + k.KO(-1,t,"ះ"); + } + else if(1){ + r=m=1; // Line 189 + k.KDC(0,t); + k.KO(-1,t,"ះ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_I /* 0x49 */)) { + if(1){ + r=m=1; // Line 189 + k.KDC(0,t); + k.KO(-1,t,"ី"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_J /* 0x4A */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ញ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_K /* 0x4B */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"គ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_L /* 0x4C */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ឡ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_M /* 0x4D */)) { + if(1){ + r=m=1; // Line 189 + k.KDC(0,t); + k.KO(-1,t,"ំ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_N /* 0x4E */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ណ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_O /* 0x4F */)) { + if(1){ + r=m=1; // Line 189 + k.KDC(0,t); + k.KO(-1,t,"ៅ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_P /* 0x50 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ភ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_Q /* 0x51 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ឈ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_R /* 0x52 */)) { + if(1){ + r=m=1; // Line 190 + k.KDC(0,t); + k.KO(-1,t,"ឬ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_S /* 0x53 */)) { + if(1){ + r=m=1; // Line 189 + k.KDC(0,t); + k.KO(-1,t,"ៃ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_T /* 0x54 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ទ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_U /* 0x55 */)) { + if(1){ + r=m=1; // Line 189 + k.KDC(0,t); + k.KO(-1,t,"ូ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_V /* 0x56 */)) { + if(1){ + r=m=1; // Line 204 + k.KDC(0,t); + k.KO(-1,t,"េះ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_W /* 0x57 */)) { + if(1){ + r=m=1; // Line 189 + k.KDC(0,t); + k.KO(-1,t,"ឺ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_X /* 0x58 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ឃ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_Y /* 0x59 */)) { + if(1){ + r=m=1; // Line 189 + k.KDC(0,t); + k.KO(-1,t,"ួ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_Z /* 0x5A */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ឍ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_LBRKT /* 0xDB */)) { + if(1){ + r=m=1; // Line 189 + k.KDC(0,t); + k.KO(-1,t,"ៀ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_BKSLASH /* 0xDC */)) { + if(1){ + r=m=1; // Line 190 + k.KDC(0,t); + k.KO(-1,t,"ឮ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_RBRKT /* 0xDD */)) { + if(1){ + r=m=1; // Line 190 + k.KDC(0,t); + k.KO(-1,t,"ឪ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_6 /* 0x36 */)) { + if(1){ + r=m=1; // Line 191 + k.KDC(0,t); + k.KO(-1,t,"៍"); + } + } + if(m) {} + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_HYPHEN /* 0xBD */)) { + if(1){ + r=m=1; // Line 191 + k.KDC(0,t); + k.KO(-1,t,"៌"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_BKQUOTE /* 0xC0 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"«"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_A /* 0x41 */)) { + if(1){ + r=m=1; // Line 189 + k.KDC(0,t); + k.KO(-1,t,"ា"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_B /* 0x42 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ប"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_C /* 0x43 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ច"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_D /* 0x44 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ដ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_E /* 0x45 */)) { + if(1){ + r=m=1; // Line 189 + k.KDC(0,t); + k.KO(-1,t,"េ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_F /* 0x46 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ថ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_G /* 0x47 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ង"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_H /* 0x48 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ហ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_I /* 0x49 */)) { + if(1){ + r=m=1; // Line 189 + k.KDC(0,t); + k.KO(-1,t,"ិ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_J /* 0x4A */)) { + if(1){ + r=m=1; // Line 191 + k.KDC(0,t); + k.KO(-1,t,"្"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_K /* 0x4B */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ក"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_L /* 0x4C */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ល"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_M /* 0x4D */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ម"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_N /* 0x4E */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ន"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_O /* 0x4F */)) { + if(1){ + r=m=1; // Line 189 + k.KDC(0,t); + k.KO(-1,t,"ោ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_P /* 0x50 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ផ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_Q /* 0x51 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ឆ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_R /* 0x52 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"រ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_S /* 0x53 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ស"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_T /* 0x54 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ត"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_U /* 0x55 */)) { + if(k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_1st_48},'ា','ំ'])){ + r=m=1; // Line 234 + k.KDC(3,t); + k.KIO(-1,this.s_shiftable_c_1st_48,1,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_2nd_with_BA_51},'ា','ំ'])){ + r=m=1; // Line 235 + k.KDC(3,t); + k.KIO(-1,this.s_shiftable_c_2nd_with_BA_51,1,t); + k.KO(-1,t,"៉"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(1){ + r=m=1; // Line 189 + k.KDC(0,t); + k.KO(-1,t,"ុ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_V /* 0x56 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"វ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_W /* 0x57 */)) { + if(1){ + r=m=1; // Line 189 + k.KDC(0,t); + k.KO(-1,t,"ឹ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_X /* 0x58 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ខ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_Y /* 0x59 */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"យ"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_Z /* 0x5A */)) { + if(1){ + r=m=1; // Line 188 + k.KDC(0,t); + k.KO(-1,t,"ឋ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_LBRKT /* 0xDB */)) { + if(1){ + r=m=1; // Line 189 + k.KDC(0,t); + k.KO(-1,t,"ឿ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_BKSLASH /* 0xDC */)) { + if(1){ + r=m=1; // Line 190 + k.KDC(0,t); + k.KO(-1,t,"ឭ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_RBRKT /* 0xDD */)) { + if(1){ + r=m=1; // Line 190 + k.KDC(0,t); + k.KO(-1,t,"ឧ"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_BKQUOTE /* 0xC0 */)) { + if(1){ + r=m=1; // Line 194 + k.KDC(0,t); + k.KO(-1,t,"»"); + } + } + if(m==1) { + + k.KDC(-1,t); + r=this.g_normalise_1(t,e); + m=2; + } + return r; + }; + this.g_normalise_1=function(t,e) { + var k=KeymanWeb,r=1,m=0; + if(k.KFCM(7,t,[{t:'a',a:this.s_c_combo_QA_57},'្','អ','ុ','ំ','ា','ំ'])){ + m=1; // Line 376 + k.KDC(7,t); + k.KIO(-1,this.s_c_combo_QA_57,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"អ៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(7,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO_54},'ុ','ំ','ា','ំ'])){ + m=1; // Line 381 + k.KDC(7,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_LO_54,3,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(7,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO_55},'ុ','ំ','ា','ំ'])){ + m=1; // Line 386 + k.KDC(7,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_MO_55,3,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(7,t,['ស','្','ប','ុ','ំ','ា','ំ'])){ + m=1; // Line 391 + k.KDC(7,t); + k.KO(-1,t,"ស"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ប៉"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(7,t,['ស','្',{t:'a',a:this.s_c_combo_SA_56},'ុ','ំ','ា','ំ'])){ + m=1; // Line 396 + k.KDC(7,t); + k.KO(-1,t,"ស"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_combo_SA_56,3,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(7,t,[{t:'a',a:this.s_c_combo_HA_58},'្','ហ','ុ','ំ','ា','ំ'])){ + m=1; // Line 401 + k.KDC(7,t); + k.KIO(-1,this.s_c_combo_HA_58,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"ហ៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(7,t,['អ','្','ង','ុ','ំ','ា','ំ'])){ + m=1; // Line 406 + k.KDC(7,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ង៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(7,t,['អ','្','វ','ុ','ំ','ា','ំ'])){ + m=1; // Line 411 + k.KDC(7,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"វ៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(7,t,['ហ','្','ប','ុ','ំ','ា','ំ'])){ + m=1; // Line 416 + k.KDC(7,t); + k.KO(-1,t,"ហ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ប៉"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(7,t,['ហ','្',{t:'a',a:this.s_shiftable_c_2nd_with_BA_51},'ុ','ំ','ា','ំ'])){ + m=1; // Line 422 + k.KDC(7,t); + k.KO(-1,t,"ហ"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_shiftable_c_2nd_with_BA_51,3,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(7,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO_52},'ុ','ំ','ា','ំ'])){ + m=1; // Line 429 + k.KDC(7,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_LO_52,3,t); + k.KO(-1,t,"៉"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(7,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO_53},'ុ','ំ','ា','ំ'])){ + m=1; // Line 434 + k.KDC(7,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_MO_53,3,t); + k.KO(-1,t,"៉"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['្','ដ',{t:'a',a:this.s_v_combo_N_21},'ំ','្','រ'])){ + m=1; // Line 340 + k.KDC(6,t); + k.KO(-1,t,"្ត"); + k.KO(-1,t,"្"); + k.KO(-1,t,"រ"); + k.KIO(-1,this.s_v_combo_N_21,3,t); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['្','ដ',{t:'a',a:this.s_v_combo_R_20},'ះ','្','រ'])){ + m=1; // Line 341 + k.KDC(6,t); + k.KO(-1,t,"្ត"); + k.KO(-1,t,"្"); + k.KO(-1,t,"រ"); + k.KIO(-1,this.s_v_combo_R_20,3,t); + k.KO(-1,t,"ះ"); + } + else if(k.KFCM(6,t,['្','រ',{t:'a',a:this.s_v_combo_N_21},'ំ','្','ដ'])){ + m=1; // Line 344 + k.KDC(6,t); + k.KO(-1,t,"្ត"); + k.KO(-1,t,"្"); + k.KO(-1,t,"រ"); + k.KIO(-1,this.s_v_combo_N_21,3,t); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['្','រ',{t:'a',a:this.s_v_combo_R_20},'ះ','្','ដ'])){ + m=1; // Line 345 + k.KDC(6,t); + k.KO(-1,t,"្ត"); + k.KO(-1,t,"្"); + k.KO(-1,t,"រ"); + k.KIO(-1,this.s_v_combo_R_20,3,t); + k.KO(-1,t,"ះ"); + } + else if(k.KFCM(6,t,['្','រ',{t:'a',a:this.s_v_combo_N_21},'ំ','្',{t:'a',a:this.s_subcons_44}])){ + m=1; // Line 350 + k.KDC(6,t); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_subcons_44,6,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"រ"); + k.KIO(-1,this.s_v_combo_N_21,3,t); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['្','រ',{t:'a',a:this.s_v_combo_R_20},'ះ','្',{t:'a',a:this.s_subcons_44}])){ + m=1; // Line 351 + k.KDC(6,t); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_subcons_44,6,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"រ"); + k.KIO(-1,this.s_v_combo_R_20,3,t); + k.KO(-1,t,"ះ"); + } + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA_57},'្','អ','ុ','ា','ំ'])){ + m=1; // Line 374 + k.KDC(6,t); + k.KIO(-1,this.s_c_combo_QA_57,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"អ៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO_54},'ុ','ា','ំ'])){ + m=1; // Line 379 + k.KDC(6,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_LO_54,3,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO_55},'ុ','ា','ំ'])){ + m=1; // Line 384 + k.KDC(6,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_MO_55,3,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ស','្','ប','ុ','ា','ំ'])){ + m=1; // Line 389 + k.KDC(6,t); + k.KO(-1,t,"ស"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ប៉"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA_56},'ុ','ា','ំ'])){ + m=1; // Line 394 + k.KDC(6,t); + k.KO(-1,t,"ស"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_combo_SA_56,3,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA_58},'្','ហ','ុ','ា','ំ'])){ + m=1; // Line 399 + k.KDC(6,t); + k.KIO(-1,this.s_c_combo_HA_58,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"ហ៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['អ','្','ង','ុ','ា','ំ'])){ + m=1; // Line 404 + k.KDC(6,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ង៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['អ','្','វ','ុ','ា','ំ'])){ + m=1; // Line 409 + k.KDC(6,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"វ៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ហ','្','ប','ុ','ា','ំ'])){ + m=1; // Line 414 + k.KDC(6,t); + k.KO(-1,t,"ហ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ប៉"); + k.KO(-1,t,"ប"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ហ','្',{t:'a',a:this.s_shiftable_c_2nd_with_BA_51},'ុ','ា','ំ'])){ + m=1; // Line 420 + k.KDC(6,t); + k.KO(-1,t,"ហ"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_shiftable_c_2nd_with_BA_51,3,t); + k.KO(-1,t,"៊"); + k.KIO(-1,this.s_shiftable_c_2nd_with_BA_51,3,t); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO_52},'ុ','ា','ំ'])){ + m=1; // Line 427 + k.KDC(6,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_LO_52,3,t); + k.KO(-1,t,"៉"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO_53},'ុ','ា','ំ'])){ + m=1; // Line 432 + k.KDC(6,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_MO_53,3,t); + k.KO(-1,t,"៉"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO_52},'៊',{t:'a',a:this.s_v_gen_14},{t:'a',a:this.s_v_pseudo_16}])){ + m=1; // Line 454 + k.KDC(6,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_LO_52,3,t); + k.KO(-1,t,"៉"); + k.KIO(-1,this.s_v_gen_14,5,t); + k.KIO(-1,this.s_v_pseudo_16,6,t); + } + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO_53},'៊',{t:'a',a:this.s_v_gen_14},{t:'a',a:this.s_v_pseudo_16}])){ + m=1; // Line 455 + k.KDC(6,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_MO_53,3,t); + k.KO(-1,t,"៉"); + k.KIO(-1,this.s_v_gen_14,5,t); + k.KIO(-1,this.s_v_pseudo_16,6,t); + } + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA_57},'្','អ','៉','ា','ំ'])){ + m=1; // Line 489 + k.KDC(6,t); + k.KIO(-1,this.s_c_combo_QA_57,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"អ៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO_54},'៉','ា','ំ'])){ + m=1; // Line 490 + k.KDC(6,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_LO_54,3,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO_55},'៉','ា','ំ'])){ + m=1; // Line 491 + k.KDC(6,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_MO_55,3,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ស','្','ប','៉','ា','ំ'])){ + m=1; // Line 492 + k.KDC(6,t); + k.KO(-1,t,"ស"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ប៉"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA_56},'៉','ា','ំ'])){ + m=1; // Line 493 + k.KDC(6,t); + k.KO(-1,t,"ស"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_combo_SA_56,3,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA_58},'្','ហ','៉','ា','ំ'])){ + m=1; // Line 494 + k.KDC(6,t); + k.KIO(-1,this.s_c_combo_HA_58,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"ហ៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['អ','្','ង','៉','ា','ំ'])){ + m=1; // Line 495 + k.KDC(6,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ង៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['អ','្','វ','៉','ា','ំ'])){ + m=1; // Line 496 + k.KDC(6,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"វ៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA_57},'្','អ','ា','ុ','ំ'])){ + m=1; // Line 503 + k.KDC(6,t); + k.KIO(-1,this.s_c_combo_QA_57,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"អ៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA_57},'្','អ','ុ','ំ','ា'])){ + m=1; // Line 504 + k.KDC(6,t); + k.KIO(-1,this.s_c_combo_QA_57,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"អ៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO_54},'ា','ុ','ំ'])){ + m=1; // Line 506 + k.KDC(6,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_LO_54,3,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO_54},'ុ','ំ','ា'])){ + m=1; // Line 507 + k.KDC(6,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_LO_54,3,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO_55},'ា','ុ','ំ'])){ + m=1; // Line 509 + k.KDC(6,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_MO_55,3,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO_55},'ុ','ំ','ា'])){ + m=1; // Line 510 + k.KDC(6,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_MO_55,3,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA_56},'ា','ុ','ំ'])){ + m=1; // Line 512 + k.KDC(6,t); + k.KO(-1,t,"ស"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_combo_SA_56,3,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA_56},'ុ','ំ','ា'])){ + m=1; // Line 513 + k.KDC(6,t); + k.KO(-1,t,"ស"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_combo_SA_56,3,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA_58},'្','ហ','ា','ុ','ំ'])){ + m=1; // Line 515 + k.KDC(6,t); + k.KIO(-1,this.s_c_combo_HA_58,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"ហ៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA_58},'្','ហ','ុ','ំ','ា'])){ + m=1; // Line 516 + k.KDC(6,t); + k.KIO(-1,this.s_c_combo_HA_58,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"ហ៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['អ','្','ង','ា','ុ','ំ'])){ + m=1; // Line 518 + k.KDC(6,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ង៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['អ','្','ង','ុ','ំ','ា'])){ + m=1; // Line 519 + k.KDC(6,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ង៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['អ','្','វ','ា','ុ','ំ'])){ + m=1; // Line 521 + k.KDC(6,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"វ៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['អ','្','វ','ុ','ំ','ា'])){ + m=1; // Line 522 + k.KDC(6,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"វ៊"); + k.KO(-1,t,"ុ"); + k.KO(-1,t,"ា"); + } + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO_52},'ា','ុ','ំ'])){ + m=1; // Line 529 + k.KDC(6,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_LO_52,3,t); + k.KO(-1,t,"៉"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO_52},'ុ','ំ','ា'])){ + m=1; // Line 530 + k.KDC(6,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_LO_52,3,t); + k.KO(-1,t,"៉"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO_53},'ា','ុ','ំ'])){ + m=1; // Line 532 + k.KDC(6,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_MO_53,3,t); + k.KO(-1,t,"៉"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO_53},'ុ','ំ','ា'])){ + m=1; // Line 533 + k.KDC(6,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_MO_53,3,t); + k.KO(-1,t,"៉"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA_57},'្','អ','េ','ុ','ី'])){ + m=1; // Line 541 + k.KDC(6,t); + k.KIO(-1,this.s_c_combo_QA_57,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"អ៊ើ"); + } + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA_57},'្','អ','ុ','េ','ី'])){ + m=1; // Line 542 + k.KDC(6,t); + k.KIO(-1,this.s_c_combo_QA_57,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"អ៊ើ"); + } + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_QA_57},'្','អ','៉','េ','ី'])){ + m=1; // Line 543 + k.KDC(6,t); + k.KIO(-1,this.s_c_combo_QA_57,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"អ៊ើ"); + } + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO_54},'េ','ុ','ី'])){ + m=1; // Line 545 + k.KDC(6,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_LO_54,3,t); + k.KO(-1,t,"៊ើ"); + } + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO_54},'ុ','េ','ី'])){ + m=1; // Line 546 + k.KDC(6,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_LO_54,3,t); + k.KO(-1,t,"៊ើ"); + } + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO_54},'៉','េ','ី'])){ + m=1; // Line 547 + k.KDC(6,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_LO_54,3,t); + k.KO(-1,t,"៊ើ"); + } + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO_55},'េ','ុ','ី'])){ + m=1; // Line 549 + k.KDC(6,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_MO_55,3,t); + k.KO(-1,t,"៊ើ"); + } + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO_55},'ុ','េ','ី'])){ + m=1; // Line 550 + k.KDC(6,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_MO_55,3,t); + k.KO(-1,t,"៊ើ"); + } + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO_55},'៉','េ','ី'])){ + m=1; // Line 551 + k.KDC(6,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_MO_55,3,t); + k.KO(-1,t,"៊ើ"); + } + else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA_56},'េ','ុ','ី'])){ + m=1; // Line 553 + k.KDC(6,t); + k.KO(-1,t,"ស"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_combo_SA_56,3,t); + k.KO(-1,t,"៊ើ"); + } + else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA_56},'ុ','េ','ី'])){ + m=1; // Line 554 + k.KDC(6,t); + k.KO(-1,t,"ស"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_combo_SA_56,3,t); + k.KO(-1,t,"៊ើ"); + } + else if(k.KFCM(6,t,['ស','្',{t:'a',a:this.s_c_combo_SA_56},'៉','េ','ី'])){ + m=1; // Line 555 + k.KDC(6,t); + k.KO(-1,t,"ស"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_combo_SA_56,3,t); + k.KO(-1,t,"៊ើ"); + } + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA_58},'្','ហ','េ','ុ','ី'])){ + m=1; // Line 557 + k.KDC(6,t); + k.KIO(-1,this.s_c_combo_HA_58,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"ហ៊ើ"); + } + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA_58},'្','ហ','ុ','េ','ី'])){ + m=1; // Line 558 + k.KDC(6,t); + k.KIO(-1,this.s_c_combo_HA_58,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"ហ៊ើ"); + } + else if(k.KFCM(6,t,[{t:'a',a:this.s_c_combo_HA_58},'្','ហ','៉','េ','ី'])){ + m=1; // Line 559 + k.KDC(6,t); + k.KIO(-1,this.s_c_combo_HA_58,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"ហ៊ើ"); + } + else if(k.KFCM(6,t,['អ','្','ង','េ','ុ','ី'])){ + m=1; // Line 561 + k.KDC(6,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ង៊ើ"); + } + else if(k.KFCM(6,t,['អ','្','ង','ុ','េ','ី'])){ + m=1; // Line 562 + k.KDC(6,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ង៊ើ"); + } + else if(k.KFCM(6,t,['អ','្','ង','៉','េ','ី'])){ + m=1; // Line 563 + k.KDC(6,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ង៊ើ"); + } + else if(k.KFCM(6,t,['អ','្','វ','េ','ុ','ី'])){ + m=1; // Line 565 + k.KDC(6,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"វ៊ើ"); + } + else if(k.KFCM(6,t,['អ','្','វ','ុ','េ','ី'])){ + m=1; // Line 566 + k.KDC(6,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"វ៊ើ"); + } + else if(k.KFCM(6,t,['អ','្','វ','៉','េ','ី'])){ + m=1; // Line 567 + k.KDC(6,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"វ៊ើ"); + } + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO_52},'េ','ុ','ី'])){ + m=1; // Line 575 + k.KDC(6,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_LO_52,3,t); + k.KO(-1,t,"៉ើ"); + } + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO_52},'ុ','េ','ី'])){ + m=1; // Line 576 + k.KDC(6,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_LO_52,3,t); + k.KO(-1,t,"៉ើ"); + } + else if(k.KFCM(6,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO_52},'៊','េ','ី'])){ + m=1; // Line 577 + k.KDC(6,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_LO_52,3,t); + k.KO(-1,t,"៉ើ"); + } + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO_53},'េ','ុ','ី'])){ + m=1; // Line 579 + k.KDC(6,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_MO_53,3,t); + k.KO(-1,t,"៉ើ"); + } + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO_53},'ុ','េ','ី'])){ + m=1; // Line 580 + k.KDC(6,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_MO_53,3,t); + k.KO(-1,t,"៉ើ"); + } + else if(k.KFCM(6,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO_53},'៊','េ','ី'])){ + m=1; // Line 581 + k.KDC(6,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_MO_53,3,t); + k.KO(-1,t,"៉ើ"); + } + else if(k.KFCM(6,t,['្','យ','្',{t:'a',a:this.s_c_out_12},'េ','ឺ'])){ + m=1; // Line 631 + k.KDC(6,t); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_out_12,4,t); + k.KO(-1,t,"ឿ"); + } + else if(k.KFCM(6,t,['្','យ','្',{t:'a',a:this.s_c_out_12},'េ','ឹ'])){ + m=1; // Line 632 + k.KDC(6,t); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_out_12,4,t); + k.KO(-1,t,"ឿ"); + } + else if(k.KFCM(6,t,['្','យ','្',{t:'a',a:this.s_c_out_12},'េ','ី'])){ + m=1; // Line 633 + k.KDC(6,t); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_out_12,4,t); + k.KO(-1,t,"ឿ"); + } + else if(k.KFCM(5,t,[{t:'a',a:this.s_c_shifter_28},{t:'a',a:this.s_v_combo_N_21},'ំ','្',{t:'a',a:this.s_subcons_44}])){ + m=1; // Line 331 + k.KDC(5,t); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_subcons_44,5,t); + k.KIO(-1,this.s_c_shifter_28,1,t); + k.KIO(-1,this.s_v_combo_N_21,2,t); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(5,t,[{t:'a',a:this.s_c_shifter_28},{t:'a',a:this.s_v_combo_R_20},'ះ','្',{t:'a',a:this.s_subcons_44}])){ + m=1; // Line 332 + k.KDC(5,t); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_subcons_44,5,t); + k.KIO(-1,this.s_c_shifter_28,1,t); + k.KIO(-1,this.s_v_combo_R_20,2,t); + k.KO(-1,t,"ះ"); + } + else if(k.KFCM(5,t,['្','ដ',{t:'a',a:this.s_v_any_19},'្','រ'])){ + m=1; // Line 339 + k.KDC(5,t); + k.KO(-1,t,"្ត"); + k.KO(-1,t,"្"); + k.KO(-1,t,"រ"); + k.KIO(-1,this.s_v_any_19,3,t); + } + else if(k.KFCM(5,t,['្','រ',{t:'a',a:this.s_v_any_19},'្','ដ'])){ + m=1; // Line 343 + k.KDC(5,t); + k.KO(-1,t,"្ត"); + k.KO(-1,t,"្"); + k.KO(-1,t,"រ"); + k.KIO(-1,this.s_v_any_19,3,t); + } + else if(k.KFCM(5,t,['្','រ',{t:'a',a:this.s_c_shifter_28},'្',{t:'a',a:this.s_subcons_44}])){ + m=1; // Line 347 + k.KDC(5,t); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_subcons_44,5,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"រ"); + k.KIO(-1,this.s_c_shifter_28,3,t); + } + else if(k.KFCM(5,t,['្','រ',{t:'a',a:this.s_v_any_19},'្',{t:'a',a:this.s_subcons_44}])){ + m=1; // Line 349 + k.KDC(5,t); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_subcons_44,5,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"រ"); + k.KIO(-1,this.s_v_any_19,3,t); + } + else if(k.KFCM(5,t,[{t:'a',a:this.s_c_combo_QA_57},'្','អ','ុ',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 373 + k.KDC(5,t); + k.KIO(-1,this.s_c_combo_QA_57,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"អ៊"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,[{t:'a',a:this.s_c_combo_QA_57},'្','អ',{t:'a',a:this.s_v_above_47},'ុ'])){ + m=1; // Line 375 + k.KDC(5,t); + k.KIO(-1,this.s_c_combo_QA_57,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"អ៊"); + k.KIO(-1,this.s_v_above_47,4,t); + } + else if(k.KFCM(5,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO_54},'ុ',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 378 + k.KDC(5,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_LO_54,3,t); + k.KO(-1,t,"៊"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO_54},{t:'a',a:this.s_v_above_47},'ុ'])){ + m=1; // Line 380 + k.KDC(5,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_LO_54,3,t); + k.KO(-1,t,"៊"); + k.KIO(-1,this.s_v_above_47,4,t); + } + else if(k.KFCM(5,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO_55},'ុ',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 383 + k.KDC(5,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_MO_55,3,t); + k.KO(-1,t,"៊"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO_55},{t:'a',a:this.s_v_above_47},'ុ'])){ + m=1; // Line 385 + k.KDC(5,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_MO_55,3,t); + k.KO(-1,t,"៊"); + k.KIO(-1,this.s_v_above_47,4,t); + } + if(m) {} + else if(k.KFCM(5,t,['ស','្','ប','ុ',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 388 + k.KDC(5,t); + k.KO(-1,t,"ស"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ប៉"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,['ស','្','ប',{t:'a',a:this.s_v_above_47},'ុ'])){ + m=1; // Line 390 + k.KDC(5,t); + k.KO(-1,t,"ស"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ប៉"); + k.KIO(-1,this.s_v_above_47,4,t); + } + else if(k.KFCM(5,t,['ស','្',{t:'a',a:this.s_c_combo_SA_56},'ុ',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 393 + k.KDC(5,t); + k.KO(-1,t,"ស"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_combo_SA_56,3,t); + k.KO(-1,t,"៊"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,['ស','្',{t:'a',a:this.s_c_combo_SA_56},{t:'a',a:this.s_v_above_47},'ុ'])){ + m=1; // Line 395 + k.KDC(5,t); + k.KO(-1,t,"ស"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_combo_SA_56,3,t); + k.KO(-1,t,"៊"); + k.KIO(-1,this.s_v_above_47,4,t); + } + else if(k.KFCM(5,t,[{t:'a',a:this.s_c_combo_HA_58},'្','ហ','ុ',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 398 + k.KDC(5,t); + k.KIO(-1,this.s_c_combo_HA_58,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"ហ៊"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,[{t:'a',a:this.s_c_combo_HA_58},'្','ហ',{t:'a',a:this.s_v_above_47},'ុ'])){ + m=1; // Line 400 + k.KDC(5,t); + k.KIO(-1,this.s_c_combo_HA_58,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"ហ៊"); + k.KIO(-1,this.s_v_above_47,4,t); + } + else if(k.KFCM(5,t,['អ','្','ង','ុ',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 403 + k.KDC(5,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ង៊"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,['អ','្','ង',{t:'a',a:this.s_v_above_47},'ុ'])){ + m=1; // Line 405 + k.KDC(5,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ង៊"); + k.KIO(-1,this.s_v_above_47,4,t); + } + else if(k.KFCM(5,t,['អ','្','វ','ុ',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 408 + k.KDC(5,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"វ៊"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,['អ','្','វ',{t:'a',a:this.s_v_above_47},'ុ'])){ + m=1; // Line 410 + k.KDC(5,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"វ៊"); + k.KIO(-1,this.s_v_above_47,4,t); + } + else if(k.KFCM(5,t,['ហ','្','ប','ុ',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 413 + k.KDC(5,t); + k.KO(-1,t,"ហ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ប៉"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,['ហ','្','ប',{t:'a',a:this.s_v_above_47},'ុ'])){ + m=1; // Line 415 + k.KDC(5,t); + k.KO(-1,t,"ហ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ប៉"); + k.KIO(-1,this.s_v_above_47,4,t); + } + else if(k.KFCM(5,t,['ហ','្',{t:'a',a:this.s_shiftable_c_2nd_with_BA_51},'ុ',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 419 + k.KDC(5,t); + k.KO(-1,t,"ហ"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_shiftable_c_2nd_with_BA_51,3,t); + k.KO(-1,t,"៊"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,['ហ','្',{t:'a',a:this.s_shiftable_c_2nd_with_BA_51},{t:'a',a:this.s_v_above_47},'ុ'])){ + m=1; // Line 421 + k.KDC(5,t); + k.KO(-1,t,"ហ"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_shiftable_c_2nd_with_BA_51,3,t); + k.KO(-1,t,"៊"); + k.KIO(-1,this.s_v_above_47,4,t); + } + else if(k.KFCM(5,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO_52},'ុ',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 426 + k.KDC(5,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_LO_52,3,t); + k.KO(-1,t,"៉"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO_52},{t:'a',a:this.s_v_above_47},'ុ'])){ + m=1; // Line 428 + k.KDC(5,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_LO_52,3,t); + k.KO(-1,t,"៉"); + k.KIO(-1,this.s_v_above_47,4,t); + } + else if(k.KFCM(5,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO_53},'ុ',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 431 + k.KDC(5,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_MO_53,3,t); + k.KO(-1,t,"៉"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO_53},{t:'a',a:this.s_v_above_47},'ុ'])){ + m=1; // Line 433 + k.KDC(5,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_MO_53,3,t); + k.KO(-1,t,"៉"); + k.KIO(-1,this.s_v_above_47,4,t); + } + else if(k.KFCM(5,t,[{t:'a',a:this.s_shiftable_c_1st_48},'ុ','ំ','ា','ំ'])){ + m=1; // Line 441 + k.KDC(5,t); + k.KIO(-1,this.s_shiftable_c_1st_48,1,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(5,t,[{t:'a',a:this.s_shiftable_c_2nd_with_BA_51},'ុ','ំ','ា','ំ'])){ + m=1; // Line 448 + k.KDC(5,t); + k.KIO(-1,this.s_shiftable_c_2nd_with_BA_51,1,t); + k.KO(-1,t,"៉"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(5,t,['ល','្',{t:'a',a:this.s_c_2nd_combo_LO_52},'៊',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 452 + k.KDC(5,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_LO_52,3,t); + k.KO(-1,t,"៉"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,['ម','្',{t:'a',a:this.s_c_2nd_combo_MO_53},'៊',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 453 + k.KDC(5,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_2nd_combo_MO_53,3,t); + k.KO(-1,t,"៉"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,['្',{t:'a',a:this.s_shiftable_c_2nd_50},'៊',{t:'a',a:this.s_v_gen_14},{t:'a',a:this.s_v_pseudo_16}])){ + m=1; // Line 463 + k.KDC(5,t); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_shiftable_c_2nd_50,2,t); + k.KO(-1,t,"៊"); + k.KIO(-1,this.s_v_gen_14,4,t); + k.KIO(-1,this.s_v_pseudo_16,5,t); + } + else if(k.KFCM(5,t,[{t:'a',a:this.s_c_combo_QA_57},'្','អ','៉',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 481 + k.KDC(5,t); + k.KIO(-1,this.s_c_combo_QA_57,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"អ៊"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,['ល','្',{t:'a',a:this.s_c_1st_combo_LO_54},'៉',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 482 + k.KDC(5,t); + k.KO(-1,t,"ល"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_LO_54,3,t); + k.KO(-1,t,"៊"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,['ម','្',{t:'a',a:this.s_c_1st_combo_MO_55},'៉',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 483 + k.KDC(5,t); + k.KO(-1,t,"ម"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_1st_combo_MO_55,3,t); + k.KO(-1,t,"៊"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,['ស','្','ប','៉',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 484 + k.KDC(5,t); + k.KO(-1,t,"ស"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ប៉"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,['ស','្',{t:'a',a:this.s_c_combo_SA_56},'៉',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 485 + k.KDC(5,t); + k.KO(-1,t,"ស"); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_c_combo_SA_56,3,t); + k.KO(-1,t,"៊"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,[{t:'a',a:this.s_c_combo_HA_58},'្','ហ','៉',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 486 + k.KDC(5,t); + k.KIO(-1,this.s_c_combo_HA_58,1,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"ហ៊"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,['អ','្','ង','៉',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 487 + k.KDC(5,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"ង៊"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,['អ','្','វ','៉',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 488 + k.KDC(5,t); + k.KO(-1,t,"អ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"វ៊"); + k.KIO(-1,this.s_v_above_47,5,t); + } + else if(k.KFCM(5,t,['ព','័','ន','្','ឋ'])){ + m=1; // Line 619 + k.KDC(5,t); + k.KO(-1,t,"ព"); + k.KO(-1,t,"័"); + k.KO(-1,t,"ន"); + k.KO(-1,t,"្ធ"); + } + else if(k.KFCM(4,t,[{t:'a',a:this.s_v_gen_14},{t:'a',a:this.s_v_pseudo_16},{t:'a',a:this.s_v_gen_14},{t:'a',a:this.s_v_pseudo_16}])){ + m=1; // Line 312 + k.KDC(4,t); + k.KIO(-1,this.s_v_gen_14,3,t); + k.KIO(-1,this.s_v_pseudo_16,4,t); + } + else if(k.KFCM(4,t,[{t:'a',a:this.s_v_combo_N_21},'ំ','្',{t:'a',a:this.s_subcons_44}])){ + m=1; // Line 325 + k.KDC(4,t); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_subcons_44,4,t); + k.KIO(-1,this.s_v_combo_N_21,1,t); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(4,t,[{t:'a',a:this.s_v_combo_R_20},'ះ','្',{t:'a',a:this.s_subcons_44}])){ + m=1; // Line 326 + k.KDC(4,t); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_subcons_44,4,t); + k.KIO(-1,this.s_v_combo_R_20,1,t); + k.KO(-1,t,"ះ"); + } + else if(k.KFCM(4,t,[{t:'a',a:this.s_c_shifter_28},{t:'a',a:this.s_v_any_19},'្',{t:'a',a:this.s_subcons_44}])){ + m=1; // Line 330 + k.KDC(4,t); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_subcons_44,4,t); + k.KIO(-1,this.s_c_shifter_28,1,t); + k.KIO(-1,this.s_v_any_19,2,t); + } + else if(k.KFCM(4,t,['្','ដ','្','រ'])){ + m=1; // Line 336 + k.KDC(4,t); + k.KO(-1,t,"្ត"); + k.KO(-1,t,"្"); + k.KO(-1,t,"រ"); + } + else if(k.KFCM(4,t,['្','រ','្','ដ'])){ + m=1; // Line 337 + k.KDC(4,t); + k.KO(-1,t,"្ត"); + k.KO(-1,t,"្"); + k.KO(-1,t,"រ"); + } + else if(k.KFCM(4,t,['្','រ','្',{t:'a',a:this.s_subcons_44}])){ + m=1; // Line 348 + k.KDC(4,t); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_subcons_44,4,t); + k.KO(-1,t,"្"); + k.KO(-1,t,"រ"); + } + else if(k.KFCM(4,t,[{t:'a',a:this.s_c_shifter_28},{t:'a',a:this.s_v_gen_14},{t:'a',a:this.s_v_pseudo_16},{t:'a',a:this.s_c_shifter_28}])){ + m=1; // Line 362 + k.KDC(4,t); + k.KIO(-1,this.s_v_gen_14,2,t); + k.KIO(-1,this.s_v_pseudo_16,3,t); + k.KIO(-1,this.s_c_shifter_28,4,t); + } + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st_48},'ុ','ា','ំ'])){ + m=1; // Line 439 + k.KDC(4,t); + k.KIO(-1,this.s_shiftable_c_1st_48,1,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd_with_BA_51},'ុ','ា','ំ'])){ + m=1; // Line 446 + k.KDC(4,t); + k.KIO(-1,this.s_shiftable_c_2nd_with_BA_51,1,t); + k.KO(-1,t,"៉"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd_50},'៊',{t:'a',a:this.s_v_gen_14},{t:'a',a:this.s_v_pseudo_16}])){ + m=1; // Line 460 + k.KDC(4,t); + k.KIO(-1,this.s_shiftable_c_2nd_50,1,t); + k.KO(-1,t,"៉"); + k.KIO(-1,this.s_v_gen_14,3,t); + k.KIO(-1,this.s_v_pseudo_16,4,t); + } + else if(k.KFCM(4,t,['្',{t:'a',a:this.s_shiftable_c_2nd_50},'៊',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 462 + k.KDC(4,t); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_shiftable_c_2nd_50,2,t); + k.KO(-1,t,"៊"); + k.KIO(-1,this.s_v_above_47,4,t); + } + else if(k.KFCM(4,t,['ប','្','យ',{t:'a',a:this.s_c_shifter_28}])){ + m=1; // Line 467 + k.KDC(4,t); + k.KO(-1,t,"ប្យ"); + k.KIO(-1,this.s_c_shifter_28,4,t); + } + else if(k.KFCM(4,t,['ស','្','ប',{t:'a',a:this.s_c_shifter_28}])){ + m=1; // Line 468 + k.KDC(4,t); + k.KO(-1,t,"ស្ប"); + k.KIO(-1,this.s_c_shifter_28,4,t); + } + else if(k.KFCM(4,t,['ឆ','្','ប',{t:'a',a:this.s_c_shifter_28}])){ + m=1; // Line 469 + k.KDC(4,t); + k.KO(-1,t,"ឆ្ប"); + k.KIO(-1,this.s_c_shifter_28,4,t); + } + else if(k.KFCM(4,t,['ប','្','យ',{t:'a',a:this.s_c_shifter_28}])){ + m=1; // Line 470 + k.KDC(4,t); + k.KO(-1,t,"ប្យ"); + k.KIO(-1,this.s_c_shifter_28,4,t); + } + else if(k.KFCM(4,t,['ស','្','ប',{t:'a',a:this.s_c_shifter_28}])){ + m=1; // Line 471 + k.KDC(4,t); + k.KO(-1,t,"ស្ប"); + k.KIO(-1,this.s_c_shifter_28,4,t); + } + else if(k.KFCM(4,t,['ឆ','្','ប',{t:'a',a:this.s_c_shifter_28}])){ + m=1; // Line 472 + k.KDC(4,t); + k.KO(-1,t,"ឆ្ប"); + k.KIO(-1,this.s_c_shifter_28,4,t); + } + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st_48},'៉',{t:'a',a:this.s_v_gen_14},{t:'a',a:this.s_v_pseudo_16}])){ + m=1; // Line 477 + k.KDC(4,t); + k.KIO(-1,this.s_shiftable_c_1st_48,1,t); + k.KO(-1,t,"៊"); + k.KIO(-1,this.s_v_gen_14,3,t); + k.KIO(-1,this.s_v_pseudo_16,4,t); + } + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st_48},'ា','ុ','ំ'])){ + m=1; // Line 500 + k.KDC(4,t); + k.KIO(-1,this.s_shiftable_c_1st_48,1,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st_48},'ុ','ំ','ា'])){ + m=1; // Line 501 + k.KDC(4,t); + k.KIO(-1,this.s_shiftable_c_1st_48,1,t); + k.KO(-1,t,"៊"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd_with_BA_51},'ា','ុ','ំ'])){ + m=1; // Line 526 + k.KDC(4,t); + k.KIO(-1,this.s_shiftable_c_2nd_with_BA_51,1,t); + k.KO(-1,t,"៉"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd_with_BA_51},'ុ','ំ','ា'])){ + m=1; // Line 527 + k.KDC(4,t); + k.KIO(-1,this.s_shiftable_c_2nd_with_BA_51,1,t); + k.KO(-1,t,"៉"); + k.KO(-1,t,"ា"); + k.KO(-1,t,"ំ"); + } + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st_48},'េ','ុ','ី'])){ + m=1; // Line 537 + k.KDC(4,t); + k.KIO(-1,this.s_shiftable_c_1st_48,1,t); + k.KO(-1,t,"៊ើ"); + } + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st_48},'ុ','េ','ី'])){ + m=1; // Line 538 + k.KDC(4,t); + k.KIO(-1,this.s_shiftable_c_1st_48,1,t); + k.KO(-1,t,"៊ើ"); + } + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_1st_48},'៉','េ','ី'])){ + m=1; // Line 539 + k.KDC(4,t); + k.KIO(-1,this.s_shiftable_c_1st_48,1,t); + k.KO(-1,t,"៊ើ"); + } + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd_50},'េ','ុ','ី'])){ + m=1; // Line 571 + k.KDC(4,t); + k.KIO(-1,this.s_shiftable_c_2nd_50,1,t); + k.KO(-1,t,"៉ើ"); + } + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd_50},'ុ','េ','ី'])){ + m=1; // Line 572 + k.KDC(4,t); + k.KIO(-1,this.s_shiftable_c_2nd_50,1,t); + k.KO(-1,t,"៉ើ"); + } + else if(k.KFCM(4,t,[{t:'a',a:this.s_shiftable_c_2nd_50},'៊','េ','ី'])){ + m=1; // Line 573 + k.KDC(4,t); + k.KIO(-1,this.s_shiftable_c_2nd_50,1,t); + k.KO(-1,t,"៉ើ"); + } + else if(k.KFCM(4,t,['ព','ន','្','ឋ'])){ + m=1; // Line 618 + k.KDC(4,t); + k.KO(-1,t,"ព"); + k.KO(-1,t,"ន"); + k.KO(-1,t,"្ធ"); + } + else if(k.KFCM(4,t,['្','យ','េ','ឺ'])){ + m=1; // Line 627 + k.KDC(4,t); + k.KO(-1,t,"ឿ"); + } + else if(k.KFCM(4,t,['្','យ','េ','ឹ'])){ + m=1; // Line 628 + k.KDC(4,t); + k.KO(-1,t,"ឿ"); + } + else if(k.KFCM(4,t,['្','យ','េ','ី'])){ + m=1; // Line 629 + k.KDC(4,t); + k.KO(-1,t,"ឿ"); + } + else if(k.KFCM(3,t,[{t:'a',a:this.s_v_gen_14},{t:'a',a:this.s_v_pseudo_16},{t:'a',a:this.s_v_gen_14}])){ + m=1; // Line 308 + k.KDC(3,t); + k.KIO(-1,this.s_v_gen_14,3,t); + } + else if(k.KFCM(3,t,[{t:'a',a:this.s_v_gen_14},{t:'a',a:this.s_v_pseudo_16},{t:'a',a:this.s_v_pseudo_16}])){ + m=1; // Line 309 + k.KDC(3,t); + k.KIO(-1,this.s_v_pseudo_16,3,t); + } + else if(k.KFCM(3,t,[{t:'a',a:this.s_v_gen_14},{t:'a',a:this.s_v_gen_14},{t:'a',a:this.s_v_pseudo_16}])){ + m=1; // Line 310 + k.KDC(3,t); + k.KIO(-1,this.s_v_gen_14,2,t); + k.KIO(-1,this.s_v_pseudo_16,3,t); + } + else if(k.KFCM(3,t,[{t:'a',a:this.s_v_pseudo_16},{t:'a',a:this.s_v_gen_14},{t:'a',a:this.s_v_pseudo_16}])){ + m=1; // Line 311 + k.KDC(3,t); + k.KIO(-1,this.s_v_gen_14,2,t); + k.KIO(-1,this.s_v_pseudo_16,3,t); + } + else if(k.KFCM(3,t,['្',{t:'a',a:this.s_v_gen_14},{t:'a',a:this.s_v_pseudo_16}])){ + m=1; // Line 320 + k.KDC(3,t); + k.KIO(-1,this.s_v_gen_14,2,t); + k.KIO(-1,this.s_v_pseudo_16,3,t); + } + else if(k.KFCM(3,t,[{t:'a',a:this.s_v_any_19},'្',{t:'a',a:this.s_subcons_44}])){ + m=1; // Line 324 + k.KDC(3,t); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_subcons_44,3,t); + k.KIO(-1,this.s_v_any_19,1,t); + } + else if(k.KFCM(3,t,[{t:'a',a:this.s_c_shifter_28},'្',{t:'a',a:this.s_subcons_44}])){ + m=1; // Line 355 + k.KDC(3,t); + k.KO(-1,t,"្"); + k.KIO(-1,this.s_subcons_44,3,t); + k.KIO(-1,this.s_c_shifter_28,1,t); + } + else if(k.KFCM(3,t,[{t:'a',a:this.s_v_gen_14},{t:'a',a:this.s_v_pseudo_16},{t:'a',a:this.s_c_shifter_28}])){ + m=1; // Line 360 + k.KDC(3,t); + k.KIO(-1,this.s_c_shifter_28,3,t); + k.KIO(-1,this.s_v_gen_14,1,t); + k.KIO(-1,this.s_v_pseudo_16,2,t); + } + else if(k.KFCM(3,t,[{t:'a',a:this.s_c_shifter_28},{t:'a',a:this.s_v_any_19},{t:'a',a:this.s_c_shifter_28}])){ + m=1; // Line 361 + k.KDC(3,t); + k.KIO(-1,this.s_c_shifter_28,3,t); + k.KIO(-1,this.s_v_any_19,2,t); + } + else if(k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_1st_48},'ុ',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 438 + k.KDC(3,t); + k.KIO(-1,this.s_shiftable_c_1st_48,1,t); + k.KO(-1,t,"៊"); + k.KIO(-1,this.s_v_above_47,3,t); + } + else if(k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_1st_48},{t:'a',a:this.s_v_above_47},'ុ'])){ + m=1; // Line 440 + k.KDC(3,t); + k.KIO(-1,this.s_shiftable_c_1st_48,1,t); + k.KO(-1,t,"៊"); + k.KIO(-1,this.s_v_above_47,2,t); + } + else if(k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_2nd_with_BA_51},'ុ',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 445 + k.KDC(3,t); + k.KIO(-1,this.s_shiftable_c_2nd_with_BA_51,1,t); + k.KO(-1,t,"៉"); + k.KIO(-1,this.s_v_above_47,3,t); + } + else if(k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_2nd_with_BA_51},{t:'a',a:this.s_v_above_47},'ុ'])){ + m=1; // Line 447 + k.KDC(3,t); + k.KIO(-1,this.s_shiftable_c_2nd_with_BA_51,1,t); + k.KO(-1,t,"៉"); + k.KIO(-1,this.s_v_above_47,2,t); + } + else if(k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_2nd_50},'៊',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 459 + k.KDC(3,t); + k.KIO(-1,this.s_shiftable_c_2nd_50,1,t); + k.KO(-1,t,"៉"); + k.KIO(-1,this.s_v_above_47,3,t); + } + else if(k.KFCM(3,t,[{t:'a',a:this.s_shiftable_c_1st_48},'៉',{t:'a',a:this.s_v_above_47}])){ + m=1; // Line 476 + k.KDC(3,t); + k.KIO(-1,this.s_shiftable_c_1st_48,1,t); + k.KO(-1,t,"៊"); + k.KIO(-1,this.s_v_above_47,3,t); + } + else if(k.KFCM(3,t,[{t:'a',a:this.s_c_out_12},{t:'a',a:this.s_v_gen_14},'៌'])){ + m=1; // Line 585 + k.KDC(3,t); + k.KIO(-1,this.s_c_out_12,1,t); + k.KO(-1,t,"៌"); + k.KIO(-1,this.s_v_gen_14,2,t); + } + else if(k.KFCM(3,t,['ណ','្','ត'])){ + m=1; // Line 589 + k.KDC(3,t); + k.KO(-1,t,"ណ"); + k.KO(-1,t,"្ដ"); + } + else if(k.KFCM(3,t,['ន','្','ដ'])){ + m=1; // Line 590 + k.KDC(3,t); + k.KO(-1,t,"ន"); + k.KO(-1,t,"្ត"); + } + else if(k.KFCM(3,t,['ទ','្','ប'])){ + m=1; // Line 594 + k.KDC(3,t); + k.KO(-1,t,"ឡ"); + } + else if(k.KFCM(3,t,['ប','្','ញ'])){ + m=1; // Line 596 + k.KDC(3,t); + k.KO(-1,t,"ឫ"); + } + else if(k.KFCM(3,t,['ព','្','ញ'])){ + m=1; // Line 602 + k.KDC(3,t); + k.KO(-1,t,"ឭ"); + } + else if(k.KFCM(3,t,['ព','្','ឋ'])){ + m=1; // Line 605 + k.KDC(3,t); + k.KO(-1,t,"ឰ"); + } + else if(k.KFCM(3,t,['ដ','្','ធ'])){ + m=1; // Line 613 + k.KDC(3,t); + k.KO(-1,t,"ដ្ឋ"); + } + else if(k.KFCM(3,t,['ទ','្','ឋ'])){ + m=1; // Line 614 + k.KDC(3,t); + k.KO(-1,t,"ទ្ធ"); + } + else if(k.KFCM(3,t,['ឪ','្','យ'])){ + m=1; // Line 622 + k.KDC(3,t); + k.KO(-1,t,"ឱ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"យ"); + } + else if(k.KFCM(3,t,['ឳ','្','យ'])){ + m=1; // Line 623 + k.KDC(3,t); + k.KO(-1,t,"ឱ"); + k.KO(-1,t,"្"); + k.KO(-1,t,"យ"); + } + else if(k.KFCM(3,t,['ញ','្','វ'])){ + m=1; // Line 625 + k.KDC(3,t); + k.KO(-1,t,"ព"); + k.KO(-1,t,"្"); + k.KO(-1,t,"វា"); + } + else if(k.KFCM(2,t,['េ','ា'])){ + m=1; // Line 291 + k.KDC(2,t); + k.KO(-1,t,"ោ"); + } + else if(k.KFCM(2,t,['ា','េ'])){ + m=1; // Line 292 + k.KDC(2,t); + k.KO(-1,t,"ោ"); + } + else if(k.KFCM(2,t,['េ','ី'])){ + m=1; // Line 293 + k.KDC(2,t); + k.KO(-1,t,"ើ"); + } + else if(k.KFCM(2,t,['ី','េ'])){ + m=1; // Line 294 + k.KDC(2,t); + k.KO(-1,t,"ើ"); + } + else if(k.KFCM(2,t,['ំ','ុ'])){ + m=1; // Line 298 + k.KDC(2,t); + k.KO(-1,t,"ុំ"); + } + else if(k.KFCM(2,t,['ំ','ា'])){ + m=1; // Line 299 + k.KDC(2,t); + k.KO(-1,t,"ាំ"); + } + else if(k.KFCM(2,t,[{t:'a',a:this.s_v_gen_14},{t:'a',a:this.s_v_gen_14}])){ + m=1; // Line 304 + k.KDC(2,t); + k.KIO(-1,this.s_v_gen_14,2,t); + } + else if(k.KFCM(2,t,[{t:'a',a:this.s_v_pseudo_16},{t:'a',a:this.s_v_pseudo_16}])){ + m=1; // Line 313 + k.KDC(2,t); + k.KIO(-1,this.s_v_pseudo_16,2,t); + } + if(m) {} + else if(k.KFCM(2,t,['្','្'])){ + m=1; // Line 318 + k.KDC(2,t); + k.KO(-1,t,"្"); + } + else if(k.KFCM(2,t,['្',{t:'a',a:this.s_v_any_19}])){ + m=1; // Line 319 + k.KDC(2,t); + k.KIO(-1,this.s_v_any_19,2,t); + } + else if(k.KFCM(2,t,[{t:'a',a:this.s_v_any_19},{t:'a',a:this.s_c_shifter_28}])){ + m=1; // Line 359 + k.KDC(2,t); + k.KIO(-1,this.s_c_shifter_28,2,t); + k.KIO(-1,this.s_v_any_19,1,t); + } + else if(k.KFCM(2,t,['ឫ','ុ'])){ + m=1; // Line 597 + k.KDC(2,t); + k.KO(-1,t,"ឬ"); + } + else if(k.KFCM(2,t,['ឭ','ា'])){ + m=1; // Line 599 + k.KDC(2,t); + k.KO(-1,t,"ញ"); + } + else if(k.KFCM(2,t,['ឮ','ា'])){ + m=1; // Line 600 + k.KDC(2,t); + k.KO(-1,t,"ញ"); + } + else if(k.KFCM(2,t,['ឭ','ុ'])){ + m=1; // Line 603 + k.KDC(2,t); + k.KO(-1,t,"ឮ"); + } + else if(k.KFCM(2,t,['ឧ','ិ'])){ + m=1; // Line 607 + k.KDC(2,t); + k.KO(-1,t,"ឱ"); + } + else if(k.KFCM(2,t,['ឧ','៌'])){ + m=1; // Line 608 + k.KDC(2,t); + k.KO(-1,t,"ឱ"); + } + else if(k.KFCM(2,t,['ឧ','៍'])){ + m=1; // Line 609 + k.KDC(2,t); + k.KO(-1,t,"ឱ"); + } + return r; + }; +} diff --git a/developer/src/kmc-kmw/test/fixtures/khmer_angkor.keyman-touch-layout b/developer/src/kmc-kmw/test/fixtures/khmer_angkor.keyman-touch-layout new file mode 100644 index 0000000000..711f849008 --- /dev/null +++ b/developer/src/kmc-kmw/test/fixtures/khmer_angkor.keyman-touch-layout @@ -0,0 +1,1950 @@ +{ + "tablet": { + "displayUnderlying": false, + "layer": [ + { + "id": "default", + "row": [ + { + "id": 1, + "key": [ + { + "id": "K_1", + "text": "១" + }, + { + "id": "K_2", + "text": "២" + }, + { + "id": "K_3", + "text": "៣" + }, + { + "id": "K_4", + "text": "៤" + }, + { + "id": "K_5", + "text": "៥" + }, + { + "id": "K_6", + "text": "៦" + }, + { + "id": "K_7", + "text": "៧" + }, + { + "id": "K_8", + "text": "៨" + }, + { + "id": "K_9", + "text": "៩" + }, + { + "id": "K_0", + "text": "០" + }, + { + "id": "K_HYPHEN", + "text": "ឥ" + }, + { + "id": "K_EQUAL", + "text": "ឲ" + }, + { + "id": "K_BKSP", + "text": "*BkSp*", + "width": "100", + "sp": "1" + } + ] + }, + { + "id": 2, + "key": [ + { + "id": "K_Q", + "text": "ឆ", + "pad": "75" + }, + { + "id": "K_W", + "text": "" + }, + { + "id": "K_E", + "text": "" + }, + { + "id": "K_R", + "text": "រ" + }, + { + "id": "K_T", + "text": "ត" + }, + { + "id": "K_Y", + "text": "យ" + }, + { + "id": "K_U", + "text": "" + }, + { + "id": "K_I", + "text": "" + }, + { + "id": "K_O", + "text": "" + }, + { + "id": "K_P", + "text": "ផ" + }, + { + "id": "K_LBRKT", + "text": "" + }, + { + "id": "K_RBRKT", + "text": "ឪ" + }, + { + "id": "T_new_138", + "text": "", + "width": "10", + "sp": "10" + } + ] + }, + { + "id": 3, + "key": [ + { + "id": "K_BKQUOTE", + "text": "«" + }, + { + "id": "K_A", + "text": "" + }, + { + "id": "K_S", + "text": "ស" + }, + { + "id": "K_D", + "text": "ដ" + }, + { + "id": "K_F", + "text": "ថ" + }, + { + "id": "K_G", + "text": "ង" + }, + { + "id": "K_H", + "text": "ហ" + }, + { + "id": "K_J", + "text": "" + }, + { + "id": "K_K", + "text": "ក" + }, + { + "id": "K_L", + "text": "ល" + }, + { + "id": "K_COLON", + "text": "" + }, + { + "id": "K_QUOTE", + "text": "" + }, + { + "id": "K_BKSLASH", + "text": "ឮ" + } + ] + }, + { + "id": 4, + "key": [ + { + "id": "K_SHIFT", + "text": "*Shift*", + "width": "160", + "sp": "1", + "nextlayer": "shift" + }, + { + "id": "K_oE2", + "text": "" + }, + { + "id": "K_Z", + "text": "ឋ" + }, + { + "id": "K_X", + "text": "ខ" + }, + { + "id": "K_C", + "text": "ច" + }, + { + "id": "K_V", + "text": "វ" + }, + { + "id": "K_B", + "text": "ប" + }, + { + "id": "K_N", + "text": "ន" + }, + { + "id": "K_M", + "text": "ម" + }, + { + "id": "K_COMMA", + "text": "" + }, + { + "id": "K_PERIOD", + "text": "។" + }, + { + "id": "K_SLASH", + "text": "" + }, + { + "id": "T_new_164", + "text": "", + "width": "10", + "sp": "10" + } + ] + }, + { + "id": 5, + "key": [ + { + "id": "K_LCONTROL", + "text": "*AltGr*", + "width": "160", + "sp": "1", + "nextlayer": "rightalt" + }, + { + "id": "K_LOPT", + "text": "*Menu*", + "width": "160", + "sp": "1" + }, + { + "id": "K_SPACE", + "text": "​", + "width": "930" + }, + { + "id": "K_ENTER", + "text": "*Enter*", + "width": "160", + "sp": "1" + } + ] + } + ] + }, + { + "id": "rightalt", + "row": [ + { + "id": 1, + "key": [ + { + "id": "K_1", + "text": "‌" + }, + { + "id": "K_2", + "text": "@" + }, + { + "id": "K_3", + "text": "" + }, + { + "id": "K_4", + "text": "$" + }, + { + "id": "K_5", + "text": "€" + }, + { + "id": "K_6", + "text": "៙" + }, + { + "id": "K_7", + "text": "៚" + }, + { + "id": "K_8", + "text": "*" + }, + { + "id": "K_9", + "text": "{" + }, + { + "id": "K_0", + "text": "}" + }, + { + "id": "K_HYPHEN", + "text": "≈" + }, + { + "id": "K_EQUAL", + "text": "" + }, + { + "id": "K_BKSP", + "text": "*BkSp*", + "width": "100", + "sp": "1" + } + ] + }, + { + "id": 2, + "key": [ + { + "id": "K_Q", + "text": "ៜ", + "pad": "75" + }, + { + "id": "K_W", + "text": "" + }, + { + "id": "K_E", + "text": "ឯ" + }, + { + "id": "K_R", + "text": "ឫ" + }, + { + "id": "K_T", + "text": "ឨ" + }, + { + "id": "K_Y", + "text": "[" + }, + { + "id": "K_U", + "text": "]" + }, + { + "id": "K_I", + "text": "ឦ" + }, + { + "id": "K_O", + "text": "ឱ" + }, + { + "id": "K_P", + "text": "ឰ" + }, + { + "id": "K_LBRKT", + "text": "ឩ" + }, + { + "id": "K_RBRKT", + "text": "ឳ" + }, + { + "id": "T_new_307", + "text": "", + "width": "10", + "sp": "10" + } + ] + }, + { + "id": 3, + "key": [ + { + "id": "K_BKQUOTE", + "text": "‍" + }, + { + "id": "K_A", + "text": "+" + }, + { + "id": "K_S", + "text": "-" + }, + { + "id": "K_D", + "text": "×" + }, + { + "id": "K_F", + "text": "÷" + }, + { + "id": "K_G", + "text": ":" + }, + { + "id": "K_H", + "text": "‘" + }, + { + "id": "K_J", + "text": "’" + }, + { + "id": "K_K", + "text": "ឝ" + }, + { + "id": "K_L", + "text": "៘" + }, + { + "id": "K_COLON", + "text": "៖" + }, + { + "id": "K_QUOTE", + "text": "ៈ" + }, + { + "id": "K_BKSLASH", + "text": "\\" + } + ] + }, + { + "id": 4, + "key": [ + { + "id": "K_SHIFT", + "text": "*Shift*", + "width": "160", + "sp": "1", + "nextlayer": "shift" + }, + { + "id": "K_oE2", + "text": "" + }, + { + "id": "K_Z", + "text": "<" + }, + { + "id": "K_X", + "text": ">" + }, + { + "id": "K_C", + "text": "#" + }, + { + "id": "K_V", + "text": "&" + }, + { + "id": "K_B", + "text": "ឞ" + }, + { + "id": "K_N", + "text": ";" + }, + { + "id": "K_M", + "text": "" + }, + { + "id": "K_COMMA", + "text": "," + }, + { + "id": "K_PERIOD", + "text": "." + }, + { + "id": "K_SLASH", + "text": "/" + }, + { + "id": "T_new_333", + "text": "", + "width": "10", + "sp": "10" + } + ] + }, + { + "id": 5, + "key": [ + { + "id": "K_LCONTROL", + "text": "*AltGr*", + "width": "160", + "sp": "2", + "nextlayer": "default" + }, + { + "id": "K_LOPT", + "text": "*Menu*", + "width": "160", + "sp": "1" + }, + { + "id": "K_SPACE", + "text": " ", + "width": "930" + }, + { + "id": "K_ENTER", + "text": "*Enter*", + "width": "160", + "sp": "1" + } + ] + } + ] + }, + { + "id": "shift", + "row": [ + { + "id": 1, + "key": [ + { + "id": "K_1", + "text": "!" + }, + { + "id": "K_2", + "text": "ៗ" + }, + { + "id": "K_3", + "text": "\"" + }, + { + "id": "K_4", + "text": "៛" + }, + { + "id": "K_5", + "text": "%" + }, + { + "id": "K_6", + "text": "" + }, + { + "id": "K_7", + "text": "" + }, + { + "id": "K_8", + "text": "" + }, + { + "id": "K_9", + "text": "(" + }, + { + "id": "K_0", + "text": ")" + }, + { + "id": "K_HYPHEN", + "text": "" + }, + { + "id": "K_EQUAL", + "text": "=" + }, + { + "id": "K_BKSP", + "text": "*BkSp*", + "width": "100", + "sp": "1" + } + ] + }, + { + "id": 2, + "key": [ + { + "id": "K_Q", + "text": "ឈ", + "pad": "75" + }, + { + "id": "K_W", + "text": "" + }, + { + "id": "K_E", + "text": "" + }, + { + "id": "K_R", + "text": "ឬ" + }, + { + "id": "K_T", + "text": "ទ" + }, + { + "id": "K_Y", + "text": "" + }, + { + "id": "K_U", + "text": "" + }, + { + "id": "K_I", + "text": "" + }, + { + "id": "K_O", + "text": "" + }, + { + "id": "K_P", + "text": "ភ" + }, + { + "id": "K_LBRKT", + "text": "" + }, + { + "id": "K_RBRKT", + "text": "ឧ" + }, + { + "id": "T_new_364", + "text": "", + "width": "10", + "sp": "10" + } + ] + }, + { + "id": 3, + "key": [ + { + "id": "K_BKQUOTE", + "text": "»" + }, + { + "id": "K_A", + "text": "" + }, + { + "id": "K_S", + "text": "" + }, + { + "id": "K_D", + "text": "ឌ" + }, + { + "id": "K_F", + "text": "ធ" + }, + { + "id": "K_G", + "text": "អ" + }, + { + "id": "K_H", + "text": "ះ" + }, + { + "id": "K_J", + "text": "ញ" + }, + { + "id": "K_K", + "text": "គ" + }, + { + "id": "K_L", + "text": "ឡ" + }, + { + "id": "K_COLON", + "text": "" + }, + { + "id": "K_QUOTE", + "text": "" + }, + { + "id": "K_BKSLASH", + "text": "ឭ" + } + ] + }, + { + "id": 4, + "key": [ + { + "id": "K_SHIFT", + "text": "*Shift*", + "width": "160", + "sp": "2", + "nextlayer": "default" + }, + { + "id": "K_oE2", + "text": "" + }, + { + "id": "K_Z", + "text": "ឍ" + }, + { + "id": "K_X", + "text": "ឃ" + }, + { + "id": "K_C", + "text": "ជ" + }, + { + "id": "K_V", + "text": "" + }, + { + "id": "K_B", + "text": "ព" + }, + { + "id": "K_N", + "text": "ណ" + }, + { + "id": "K_M", + "text": "" + }, + { + "id": "K_COMMA", + "text": "" + }, + { + "id": "K_PERIOD", + "text": "៕" + }, + { + "id": "K_SLASH", + "text": "?" + }, + { + "id": "T_new_390", + "text": "", + "width": "10", + "sp": "10" + } + ] + }, + { + "id": 5, + "key": [ + { + "id": "K_LCONTROL", + "text": "*AltGr*", + "width": "160", + "sp": "1", + "nextlayer": "rightalt" + }, + { + "id": "K_LOPT", + "text": "*Menu*", + "width": "160", + "sp": "1" + }, + { + "id": "K_SPACE", + "text": "", + "width": "930" + }, + { + "id": "K_ENTER", + "text": "*Enter*", + "width": "160", + "sp": "1" + } + ] + } + ] + } + ], + "font": "Khmer Busra Kbd", + "fontsize": "0.8em" + }, + "phone": { + "layer": [ + { + "id": "default", + "row": [ + { + "id": 1, + "key": [ + { + "id": "K_Q", + "text": "ឆ", + "pad": "", + "sk": [ + { + "text": "ឈ", + "id": "K_Q", + "layer": "shift" + }, + { + "text": "", + "id": "T_17D2_1786" + }, + { + "text": "", + "id": "T_17D2_1788" + } + ] + }, + { + "id": "K_W", + "text": "", + "sk": [ + { + "text": "", + "id": "K_W", + "layer": "shift" + } + ] + }, + { + "id": "K_E", + "text": "", + "sk": [ + { + "text": "", + "id": "K_E", + "layer": "shift" + }, + { + "text": "", + "id": "K_S", + "layer": "shift" + }, + { + "text": "", + "id": "K_V", + "layer": "shift" + }, + { + "text": "ឯ", + "id": "U_17AF" + }, + { + "text": "ឰ", + "id": "U_17B0" + } + ] + }, + { + "id": "K_R", + "text": "រ", + "sk": [ + { + "text": "", + "id": "T_17D2_179A" + }, + { + "text": "ឫ", + "id": "U_17AB" + }, + { + "text": "ឬ", + "id": "U_17AC" + } + ] + }, + { + "id": "K_T", + "text": "ត", + "sk": [ + { + "text": "ទ", + "id": "K_T", + "layer": "shift" + }, + { + "text": "", + "id": "T_17D2_178F" + }, + { + "text": "", + "id": "T_17D2_1791", + "layer": "default" + } + ] + }, + { + "id": "K_Y", + "text": "យ", + "sk": [ + { + "text": "", + "id": "T_17D2_1799" + } + ] + }, + { + "id": "K_U", + "text": "", + "sk": [ + { + "text": "", + "id": "K_U", + "layer": "shift" + }, + { + "text": "", + "id": "K_Y", + "layer": "shift" + }, + { + "text": "ឧ", + "id": "U_17A7" + }, + { + "text": "ឪ", + "id": "U_17AA", + "layer": "shift" + }, + { + "text": "ឩ", + "id": "U_17A9", + "layer": "shift" + }, + { + "text": "ឨ", + "id": "U_17A8" + } + ] + }, + { + "id": "K_I", + "text": "", + "sk": [ + { + "text": "", + "id": "K_I", + "layer": "shift" + }, + { + "text": "ឥ", + "id": "U_17A5" + }, + { + "text": "ឦ", + "id": "U_17A6", + "layer": "shift" + } + ] + }, + { + "id": "K_O", + "text": "", + "sk": [ + { + "text": "", + "id": "K_O", + "layer": "shift" + }, + { + "text": "", + "id": "K_LBRKT" + }, + { + "text": "", + "id": "K_LBRKT", + "layer": "shift" + }, + { + "text": "", + "id": "K_COLON", + "layer": "shift" + }, + { + "text": "ឱ", + "id": "U_17B1" + }, + { + "text": "ឲ", + "id": "U_17B2" + }, + { + "text": "ឳ", + "id": "U_17B3", + "layer": "shift" + } + ] + }, + { + "id": "K_P", + "text": "ផ", + "sk": [ + { + "text": "ភ", + "id": "K_P", + "layer": "shift" + }, + { + "text": "", + "id": "T_17D2_1795" + }, + { + "text": "", + "id": "T_17D2_1797", + "layer": "default" + } + ] + } + ] + }, + { + "id": 2, + "key": [ + { + "id": "K_A", + "text": "", + "pad": "", + "width": "100", + "sk": [ + { + "text": "", + "id": "K_A", + "layer": "shift" + } + ] + }, + { + "id": "K_S", + "text": "ស", + "sk": [ + { + "text": "", + "id": "T_17D2_179F" + }, + { + "text": "ឝ", + "id": "U_179D" + }, + { + "text": "ឞ", + "id": "U_179E" + } + ] + }, + { + "id": "K_D", + "text": "ដ", + "sk": [ + { + "text": "ឌ", + "id": "K_D", + "layer": "shift" + }, + { + "text": "", + "id": "T_17D2_178A" + }, + { + "text": "", + "id": "T_17D2_178C", + "layer": "default" + } + ] + }, + { + "id": "K_F", + "text": "ថ", + "sk": [ + { + "text": "ធ", + "id": "K_F", + "layer": "shift" + }, + { + "text": "", + "id": "T_17D2_1790" + }, + { + "text": "", + "id": "T_17D2_1792", + "layer": "default" + } + ] + }, + { + "id": "K_G", + "text": "ង", + "sk": [ + { + "text": "អ", + "id": "K_G", + "layer": "shift" + }, + { + "text": "", + "id": "T_17D2_1784" + }, + { + "text": "", + "id": "T_17D2_17A2", + "layer": "default" + } + ] + }, + { + "id": "K_H", + "text": "ហ", + "sk": [ + { + "text": "", + "id": "T_17D2_17A0" + }, + { + "text": "ះ", + "id": "K_H", + "layer": "shift" + }, + { + "text": "ៈ", + "id": "U_17C8" + } + ] + }, + { + "id": "K_J", + "text": "ញ", + "layer": "shift", + "sk": [ + { + "text": "", + "id": "T_17D2_1789" + } + ] + }, + { + "id": "K_K", + "text": "ក", + "sk": [ + { + "text": "គ", + "id": "K_K", + "layer": "shift" + }, + { + "text": "", + "id": "T_17D2_1780" + }, + { + "text": "", + "id": "T_17D2_1782" + } + ] + }, + { + "id": "K_L", + "text": "ល", + "sk": [ + { + "text": "ឡ", + "id": "K_L", + "layer": "shift" + }, + { + "text": "", + "id": "T_17D2_179B" + }, + { + "text": "ឭ", + "id": "U_17AD" + }, + { + "text": "ឮ", + "id": "U_17AE" + } + ] + }, + { + "id": "K_COLON", + "text": "" + } + ] + }, + { + "id": 3, + "key": [ + { + "id": "K_Z", + "text": "ឋ", + "pad": "", + "width": "", + "sk": [ + { + "text": "ឍ", + "id": "K_Z", + "layer": "shift" + }, + { + "text": "", + "id": "T_17D2_178B" + }, + { + "text": "", + "id": "T_17D2_178D", + "layer": "default" + } + ] + }, + { + "id": "K_X", + "text": "ខ", + "sk": [ + { + "text": "ឃ", + "id": "K_X", + "layer": "shift" + }, + { + "text": "", + "id": "T_17D2_1781" + }, + { + "text": "", + "id": "T_17D2_1783", + "layer": "default" + } + ] + }, + { + "id": "K_C", + "text": "ច", + "sk": [ + { + "text": "ជ", + "id": "K_C", + "layer": "shift" + }, + { + "text": "", + "id": "T_17D2_1785" + }, + { + "text": "", + "id": "T_17D2_1787", + "layer": "default" + } + ] + }, + { + "id": "K_V", + "text": "វ", + "sk": [ + { + "text": "", + "id": "T_17D2_179C" + } + ] + }, + { + "id": "K_B", + "text": "ប", + "sk": [ + { + "text": "ព", + "id": "K_B", + "layer": "shift" + }, + { + "text": "", + "id": "T_17D2_1794" + }, + { + "text": "", + "id": "T_17D2_1796", + "layer": "default" + } + ] + }, + { + "id": "K_N", + "text": "ន", + "sk": [ + { + "text": "ណ", + "id": "K_N", + "layer": "shift" + }, + { + "text": "", + "id": "T_17D2_1793" + }, + { + "text": "", + "id": "T_17D2_178E", + "layer": "default" + } + ] + }, + { + "id": "K_M", + "text": "ម", + "sk": [ + { + "text": "", + "id": "T_17D2_1798" + }, + { + "text": "", + "id": "K_M", + "layer": "shift" + } + ] + }, + { + "id": "K_COMMA", + "text": "", + "sk": [ + { + "text": "", + "id": "K_COMMA", + "layer": "shift" + }, + { + "text": "", + "id": "K_6", + "layer": "shift" + }, + { + "text": "", + "id": "K_7", + "layer": "shift" + }, + { + "text": "", + "id": "K_8", + "layer": "shift" + }, + { + "text": "", + "id": "K_HYPHEN", + "layer": "shift" + }, + { + "text": "", + "id": "U_17D1", + "layer": "shift" + }, + { + "text": "", + "id": "U_17DD", + "layer": "shift" + }, + { + "text": "", + "id": "U_17CE", + "layer": "shift" + } + ] + }, + { + "id": "K_QUOTE", + "text": "", + "width": "100", + "sk": [ + { + "text": "", + "id": "K_QUOTE", + "layer": "shift" + }, + { + "text": "", + "id": "K_SLASH" + } + ] + }, + { + "id": "K_BKSP", + "text": "*BkSp*", + "width": "100", + "sp": "1" + } + ] + }, + { + "id": 4, + "key": [ + { + "id": "K_NUMLOCK", + "text": "១២៣", + "width": "140", + "sp": "1", + "nextlayer": "numeric" + }, + { + "id": "K_LOPT", + "text": "*Menu*", + "width": "120", + "sp": "1" + }, + { + "id": "K_SPACE", + "text": "​", + "width": "555", + "sp": "0", + "sk": [ + { + "text": " ", + "id": "U_0020", + "layer": "default" + } + ] + }, + { + "id": "K_PERIOD", + "text": "។", + "width": "120", + "sk": [ + { + "text": "៕", + "id": "K_PERIOD", + "layer": "shift" + }, + { + "text": "!", + "id": "U_0021" + }, + { + "text": "?", + "id": "U_003F" + } + ] + }, + { + "id": "K_ENTER", + "text": "*Enter*", + "width": "140", + "sp": "1" + } + ] + } + ] + }, + { + "id": "numeric", + "row": [ + { + "id": 1, + "key": [ + { + "id": "K_1", + "text": "១", + "pad": "", + "sk": [ + { + "text": "1", + "id": "U_0031" + } + ] + }, + { + "id": "K_2", + "text": "២", + "sk": [ + { + "text": "2", + "id": "U_0032" + } + ] + }, + { + "id": "K_3", + "text": "៣", + "sk": [ + { + "text": "3", + "id": "U_0033" + } + ] + }, + { + "id": "K_4", + "text": "៤", + "sk": [ + { + "text": "4", + "id": "U_0034" + } + ] + }, + { + "id": "K_5", + "text": "៥", + "sk": [ + { + "text": "5", + "id": "U_0035" + } + ] + }, + { + "id": "K_6", + "text": "៦", + "sk": [ + { + "text": "6", + "id": "U_0036" + } + ] + }, + { + "id": "K_7", + "text": "៧", + "sk": [ + { + "text": "7", + "id": "U_0037" + } + ] + }, + { + "id": "K_8", + "text": "៨", + "sk": [ + { + "text": "8", + "id": "U_0038" + } + ] + }, + { + "id": "K_9", + "text": "៩", + "sk": [ + { + "text": "9", + "id": "U_0039" + } + ] + }, + { + "id": "K_0", + "text": "០", + "sk": [ + { + "text": "0", + "id": "U_0030" + }, + { + "text": "", + "id": "U_17D3" + } + ] + } + ] + }, + { + "id": 2, + "key": [ + { + "id": "U_0040", + "text": "@", + "pad": "", + "sk": [ + { + "text": "©", + "id": "U_00A9" + }, + { + "text": "®", + "id": "U_00AE" + } + ] + }, + { + "id": "U_0023", + "text": "#", + "sk": [ + { + "text": "№", + "id": "U_2116" + }, + { + "text": "~", + "id": "U_007E" + } + ] + }, + { + "id": "U_17DB", + "text": "៛", + "sk": [ + { + "text": "$", + "id": "U_0024" + }, + { + "text": "฿", + "id": "U_0E3F" + }, + { + "text": "¢", + "id": "U_00A2" + }, + { + "text": "£", + "id": "U_00A3" + }, + { + "text": "¥", + "id": "U_00A5" + } + ] + }, + { + "id": "U_0026", + "text": "&" + }, + { + "id": "U_0025", + "text": "%", + "sk": [ + { + "text": "‰", + "id": "U_2030" + }, + { + "text": "‱", + "id": "U_2031" + } + ] + }, + { + "id": "U_002B", + "text": "+", + "sk": [ + { + "text": "-", + "id": "U_002D" + }, + { + "text": "×", + "id": "U_00D7" + }, + { + "text": "÷", + "id": "U_00F7" + }, + { + "text": "±", + "id": "U_00B1" + } + ] + }, + { + "id": "U_003D", + "text": "=", + "sk": [ + { + "text": "_", + "id": "U_005F" + }, + { + "text": "≠", + "id": "U_2260" + } + ] + }, + { + "id": "U_002A", + "text": "*", + "sk": [ + { + "text": "^", + "id": "U_005E" + } + ] + }, + { + "id": "U_003F", + "text": "?", + "sk": [ + { + "text": "¿", + "id": "U_00BF" + } + ] + }, + { + "id": "U_0021", + "text": "!", + "sk": [ + { + "text": "¡", + "id": "U_00A1" + } + ] + } + ] + }, + { + "id": 3, + "key": [ + { + "id": "U_2018", + "text": "‘", + "sk": [ + { + "text": "’", + "id": "U_2019" + } + ] + }, + { + "id": "U_201C", + "text": "“", + "sk": [ + { + "text": "”", + "id": "U_201D" + } + ] + }, + { + "id": "U_00AB", + "text": "«", + "pad": "", + "sk": [ + { + "text": "»", + "id": "U_00BB" + } + ] + }, + { + "id": "U_002F", + "text": "/", + "sk": [ + { + "text": "\\", + "id": "U_005C" + }, + { + "text": "|", + "id": "U_007C" + }, + { + "text": "¦", + "id": "U_00A6" + } + ] + }, + { + "id": "U_0028", + "text": "(", + "sk": [ + { + "text": ")", + "id": "U_0029" + }, + { + "text": "[", + "id": "U_005B" + }, + { + "text": "]", + "id": "U_005D" + }, + { + "text": "{", + "id": "U_007B" + }, + { + "text": "}", + "id": "U_007D" + } + ] + }, + { + "id": "U_17D9", + "text": "៙", + "sk": [ + { + "text": "៚", + "id": "U_17DA" + }, + { + "text": "ៜ", + "id": "U_17DC" + }, + { + "text": "§", + "id": "U_00A7" + }, + { + "text": "Ø", + "id": "U_00D8" + } + ] + }, + { + "id": "U_17D7", + "text": "ៗ" + }, + { + "id": "U_003C", + "text": "<", + "sk": [ + { + "text": "≤", + "id": "U_2264" + }, + { + "text": ">", + "id": "U_003E" + }, + { + "text": "≥", + "id": "U_2265" + } + ] + }, + { + "id": "U_17D6", + "text": "៖", + "sk": [ + { + "text": ":", + "id": "U_003A" + }, + { + "text": ";", + "id": "U_003B" + }, + { + "text": "…", + "id": "U_2026" + } + ] + }, + { + "id": "K_BKSP", + "text": "*BkSp*", + "width": "", + "sp": "1" + } + ] + }, + { + "id": 4, + "key": [ + { + "id": "K_LCONTROL", + "text": "១២៣", + "width": "140", + "sp": "2", + "nextlayer": "default" + }, + { + "id": "K_LOPT", + "text": "*Menu*", + "width": "120", + "sp": "1" + }, + { + "id": "K_SPACE", + "text": "​", + "width": "555", + "sp": "0", + "layer": "shift", + "sk": [] + }, + { + "id": "K_PERIOD", + "text": "។", + "width": "120", + "sk": [ + { + "text": "៕", + "id": "K_PERIOD", + "layer": "shift" + }, + { + "text": "!", + "id": "U_0021" + }, + { + "text": "?", + "id": "U_003F" + } + ] + }, + { + "id": "K_ENTER", + "text": "*Enter*", + "width": "140", + "sp": "1" + } + ] + } + ] + } + ], + "displayUnderlying": false, + "font": "Khmer Busra Kbd", + "fontsize": "0.8em" + } +} \ No newline at end of file diff --git a/developer/src/kmc-kmw/test/fixtures/khmer_angkor.kmn b/developer/src/kmc-kmw/test/fixtures/khmer_angkor.kmn new file mode 100644 index 0000000000..b7919afca3 --- /dev/null +++ b/developer/src/kmc-kmw/test/fixtures/khmer_angkor.kmn @@ -0,0 +1,642 @@ +store(&VERSION) '10.0' +store(&NAME) "Khmer Angkor" +store(©RIGHT) '© 2015-2022 SIL International' +store(&MESSAGE) "More than just a Khmer Unicode keyboard." +store(&TARGETS) 'any' +store(&LAYOUTFILE) 'khmer_angkor.keyman-touch-layout' +store(&KEYBOARDVERSION) '1.3' +store(&BITMAP) 'khmer_angkor.ico' +store(&VISUALKEYBOARD) 'khmer_angkor.kvks' + +begin Unicode > use(main) + + + +c ==============================================STORES============================================== + + + +c 33 consonants and two deprecated consonants + +store(c_key) [K_K] [K_X] [SHIFT K_K] [SHIFT K_X] [K_G] \ + [K_C] [K_Q] [SHIFT K_C] [SHIFT K_Q] [SHIFT K_J] \ + [K_D] [K_Z] [SHIFT K_D] [SHIFT K_Z] [SHIFT K_N] \ + [K_T] [K_F] [SHIFT K_T] [SHIFT K_F] [K_N] \ + [K_B] [K_P] [SHIFT K_B] [SHIFT K_P] [K_M] \ + [K_Y] [K_R] [K_L] [K_V] [K_S] [K_H] [SHIFT K_L] [SHIFT K_G] \ + [RALT K_K] [RALT K_B] +store(c_out) U+1780 U+1781 U+1782 U+1783 U+1784 \ + U+1785 U+1786 U+1787 U+1788 U+1789 \ + U+178A U+178B U+178C U+178D U+178E \ + U+178F U+1790 U+1791 U+1792 U+1793 \ + U+1794 U+1795 U+1796 U+1797 U+1798 \ + U+1799 U+179A U+179B U+179C U+179F U+17A0 U+17A1 U+17A2 \ + U+179D U+179E c deprecated, but they are used in minority languages + +c All genuine dependent vowels + +store(v_gen_key) [K_A] [K_I] [SHIFT K_I] [K_W] [SHIFT K_W] [K_U] [SHIFT K_U] [SHIFT K_Y] \ + [K_COLON] [SHIFT K_LBRKT] [K_LBRKT] [K_E] [SHIFT K_E] [SHIFT K_S] [K_O] [SHIFT K_O] +store(v_gen) U+17B6 U+17B7 U+17B8 U+17B9 U+17BA U+17BB U+17BC U+17BD \ + U+17BE U+17BF U+17C0 U+17C1 U+17C2 U+17C3 U+17C4 U+17C5 + +c All pseudo dependent vowels + +store(v_pseudo_key) [SHIFT K_M] [SHIFT K_H] [RALT K_QUOTE] +store(v_pseudo) U+17C6 U+17C7 U+17C8 + +c Both genuine and pseudo vowels + +store(v_key) outs(v_gen_key) outs(v_pseudo_key) +store(v_out) outs(v_gen) outs(v_pseudo) +store(v_any) outs(v_out) + +c These seven vowels can be concatenated with Reahmuk (U+17C7) to make េះ ោះ ុះ ិះ ីះ ឹះ and ែះ. + +store(v_combo_R) U+17C1 U+17C4 U+17BB U+17B7 U+17B8 U+17B9 U+17C2 + +c these two vowels can be concatenated with Nikahit (U+17C6) to make ាំ and ុំ. + +store(v_combo_N) U+17B6 U+17BB +store(v_combo) outs(v_combo_R) outs(v_combo_N) + +c Independent vowels + +store(ind_v_key) [K_HYPHEN] [RALT K_I] [SHIFT K_RBRKT] [RALT K_T] [RALT K_LBRKT] [K_RBRKT] [RALT K_R] [SHIFT K_R] \ + [SHIFT K_BKSLASH] [K_BKSLASH] [RALT K_E] [RALT K_P] [RALT K_O] [K_EQUAL] [RALT K_RBRKT] +store(ind_v_out) U+17A5 U+17A6 U+17A7 U+17A8 U+17A9 U+17AA U+17AB U+17AC \ + U+17AD U+17AE U+17AF U+17B0 U+17B1 U+17B2 U+17B3 + +c Diacritics + +store(diacritic_key) [K_QUOTE] [SHIFT K_7] [SHIFT K_HYPHEN] [SHIFT K_8] [SHIFT K_6] [RALT K_QUOTE] \ + [RALT K_EQUAL] [RALT K_3] [RALT K_W] [RALT K_Q] [K_J] +store(diacritic_out) U+17CB U+17D0 U+17CC U+17CF U+17CD U+17C8 \ + U+17CE U+17D1 U+17DD U+17DC U+17D2 + +c Consonant shifter--Muusikatoan(U+17C9) and Triisap(U+17CA) + +store(c_shifter_key) [SHIFT K_QUOTE] [K_SLASH] +store(c_shifter) U+17C9 U+17CA + +c punctuations + +store(punct_key) [K_PERIOD] [SHIFT K_PERIOD] [RALT K_COLON] [SHIFT K_2] [RALT K_L] [RALT K_6] [RALT K_7] [RALT K_M] +store(punct_out) U+17D4 U+17D5 U+17D6 U+17D7 U+17D8 U+17D9 U+17DA U+17D3 + +store(latin_punct_key) [K_BKQUOTE] [SHIFT K_BKQUOTE] [SHIFT K_9] [SHIFT K_0] [SHIFT K_1] [SHIFT K_3] \ + [SHIFT K_5] [SHIFT K_EQUAL] [SHIFT K_SLASH] [RALT K_9] [RALT K_0] [RALT K_BKSLASH] \ + [RALT K_2] [RALT K_8] [RALT K_COMMA] [RALT K_D] [RALT K_PERIOD] [RALT K_SLASH] \ + [RALT K_Y] [RALT K_U] [RALT K_BKQUOTE] [RALT K_1] [RALT K_A] [RALT K_S] \ + [RALT K_F] [RALT K_G] [RALT K_HYPHEN] [RALT K_H] [RALT K_J] [RALT K_N] \ + [RALT K_Z] [RALT K_X] [RALT K_C] [RALT K_V] +store(latin_punct_out) U+00AB U+00BB U+0028 U+0029 U+0021 U+0022 \ + U+0025 U+003D U+003F U+007B U+007D U+005C \ + U+0040 U+002A U+002C U+00D7 U+002E U+002F \ + U+005B U+005D U+200D U+200C U+002B U+002D \ + U+00F7 U+003A U+2248 U+2018 U+2019 U+003B \ + U+003C U+003E U+0023 U+0026 +c white space, ZWSP, ZWJ +store(spaces_key) [K_SPACE] [SHIFT K_SPACE] [RALT K_SPACE] +store(spaces_out) U+200B U+0020 U+00A0 + +c Currency: Riel, Dollar and Euro + +store(currency_key) [SHIFT K_4] [RALT K_4] [RALT K_5] +store(currency_out) U+17DB U+0024 U+20AC + +c Khmer digits 0 through 9 + +store(digit_key) [K_0] [K_1] [K_2] [K_3] [K_4] [K_5] [K_6] [K_7] [K_8] [K_9] +store(digit_out) U+17E0 U+17E1 U+17E2 U+17E3 U+17E4 U+17E5 U+17E6 U+17E7 U+17E8 U+17E9 + +c Khmer Lek Attak (a.k.a. divination lore) +store(lek_attak_key) [SHIFT RALT K_0] [SHIFT RALT K_1] [SHIFT RALT K_2] [SHIFT RALT K_3] [SHIFT RALT K_4] \ + [SHIFT RALT K_5] [SHIFT RALT K_6] [SHIFT RALT K_7] [SHIFT RALT K_8] [SHIFT RALT K_9] +store(lek_attak_out) U+17F0 U+17F1 U+17F2 U+17F3 U+17F4 \ + U+17F5 U+17F6 U+17F7 U+17F8 U+17F9 + +c Lunar date format (Khmer style) + +store(lunar_date_key) [SHIFT RALT K_A] [SHIFT RALT K_B] [SHIFT RALT K_C] [SHIFT RALT K_D] [SHIFT RALT K_E] \ + [SHIFT RALT K_F] [SHIFT RALT K_G] [SHIFT RALT K_H] [SHIFT RALT K_I] [SHIFT RALT K_J] \ + [SHIFT RALT K_K] [SHIFT RALT K_L] [SHIFT RALT K_M] [SHIFT RALT K_N] [SHIFT RALT K_O] \ + [SHIFT RALT K_P] [SHIFT RALT K_Q] [SHIFT RALT K_R] [SHIFT RALT K_S] [SHIFT RALT K_T] \ + [SHIFT RALT K_U] [SHIFT RALT K_V] [SHIFT RALT K_W] [SHIFT RALT K_X] [SHIFT RALT K_Y] \ + [SHIFT RALT K_Z] [SHIFT RALT K_COLON] [SHIFT RALT K_COMMA] [SHIFT RALT K_PERIOD] [SHIFT RALT K_LBRKT] \ + [SHIFT RALT K_RBRKT] [SHIFT RALT K_QUOTE] +store(lunar_date_out) U+19EC U+19FB U+19F9 U+19EE U+19E2 \ + U+19EF U+19F0 U+19F1 U+19E7 U+19F2 \ + U+19F3 U+19F4 U+19FD U+19FC U+19E8 \ + U+19E9 U+19E0 U+19E3 U+19ED U+19E4 \ + U+19E6 U+19FA U+19E1 U+19F8 U+19E5 \ + U+19F7 U+19F5 U+19FE U+19FF U+19EA \ + U+19EB U+19F6 + +c Subscripts​ for mobile/table layouts + +store(input_subcons) \ + [T_17D2_1780] [T_17D2_1781] [T_17D2_1782] [T_17D2_1783] [T_17D2_1784] [T_17D2_1785] [T_17D2_1786] [T_17D2_1787] \ + [T_17D2_1788] [T_17D2_1789] [T_17D2_178A] [T_17D2_178B] [T_17D2_178C] [T_17D2_178D] [T_17D2_178E] [T_17D2_178F] \ + [T_17D2_1790] [T_17D2_1791] [T_17D2_1792] [T_17D2_1793] [T_17D2_1794] [T_17D2_1795] [T_17D2_1796] [T_17D2_1797] \ + [T_17D2_1798] [T_17D2_1799] [T_17D2_179A] [T_17D2_179B] [T_17D2_179C] [T_17D2_179D] [T_17D2_179E] [T_17D2_179F] \ + [T_17D2_17A0] [T_17D2_17A1] [T_17D2_17A2] + +store(subcons) \ + U+1780 U+1781 U+1782 U+1783 U+1784 U+1785 U+1786 U+1787 \ + U+1788 U+1789 U+178A U+178B U+178C U+178D U+178E U+178F \ + U+1790 U+1791 U+1792 U+1793 U+1794 U+1795 U+1796 U+1797 \ + U+1798 U+1799 U+179A U+179B U+179C U+179D U+179E U+179F \ + U+17A0 U+17A1 U+17A2 + +c Arabic digits 0 through 9 + +store(arabic_digit_key) [U_0030] [U_0031] [U_0032] [U_0033] [U_0034] [U_0035] [U_0036] [U_0037] [U_0038] [U_0039] +store(arabic_digit_out) U+0030 U+0031 U+0032 U+0033 U+0034 U+0035 U+0036 U+0037 U+0038 U+0039 + +c These stores are for consonant (cluster) and consonant shifter configuration + +store(v_above) U+17B7 U+17B8 U+17B9 U+17BA \ + U+17BE U+17D0 c These vowels are rendered above the base consonant. +store(shiftable_c_1st) U+179F U+17A0 U+17A2 c These consonants shift to the 2nd series when adding U+17CA to them. +store(shiftable_BA) U+1794 c BA is unique because it can be used with both U+17CA (shift to 2nd) and and U+179C (shift to PA, still in 1st series). +store(shiftable_c_2nd) U+1784 U+1789 U+1798 U+1799 \ + U+179A U+179C U+1793 U+179B c These consonants shift to the 1st series when adding U+17C9 to them. +store(shiftable_c_2nd_with_BA) outs(shiftable_c_2nd) outs(shiftable_BA) +store(c_2nd_combo_LO) U+1799 U+1798 U+1784 U+1794 \ + U+179C c These can be combined with U+179B to make a 2nd series consonant cluster. +store(c_2nd_combo_MO) U+1799 U+179B U+1784 U+179A c These can be combined with U+1798 to make a 2nd series consonant cluster. +store(c_1st_combo_LO) U+1794 U+17A0 U+17A2 c they can be combined with U+179B to make a 1st series consonant cluster. +store(c_1st_combo_MO) U+17A0 U+179F U+17A2 c they can be combined with U+1798 to make a 1st series consonant cluster. +store(c_combo_SA) U+1794 U+1799 U+179B U+1798 \ + U+1793 U+1789 U+1784 U+179A \ + U+179C U+17A2 c they can be combined with U+179F to make a 1st series consonant cluster. +store(c_combo_QA) U+1786 U+1788 U+1794 U+1795 \ + U+178F U+1791 c they can be combined with U+17A2 to make a 1st series consonant cluster. +store(c_combo_HA) U+179C U+17A3 c they can be combined with U+17A0 to make a 1st series consonant cluster. + + + +c ==============================================BASIC RULES & CONSTRAINTS/ROTATIONS============================================== + + + +group(main) using keys + +c Basic rules with RALT key + + + any(c_key) > index(c_out,1) + + any(v_key) > index(v_out,1) + + any(ind_v_key) > index(ind_v_out,1) + + any(diacritic_key) > index(diacritic_out,1) + + any(c_shifter_key) > index(c_shifter,1) + + any(punct_key) > index(punct_out,1) + + any(latin_punct_key) > index(latin_punct_out,1) + + any(currency_key) > index(currency_out,1) + + any(digit_key) > index(digit_out,1) + + any(lek_attak_key) > index(lek_attak_out,1) + + any(lunar_date_key) > index(lunar_date_out,1) + + any(spaces_key) > index(spaces_out,1) + +c two-unicode-code-point vowels + ++ [SHIFT K_A] > U+17B6 U+17C6 ++ [SHIFT K_V] > U+17C1 U+17C7 ++ [SHIFT K_COLON] > U+17C4 U+17C7 ++ [K_COMMA] > U+17BB U+17C6 ++ [SHIFT K_COMMA] > U+17BB U+17C7 + +c Constraints + +any(v_gen) + [K_QUOTE] > context beep c no Bantoc after any genuine vowel +any(v_pseudo) + [K_QUOTE] > context beep c no Bantoc after any pseudo vowel +any(c_shifter) + [K_QUOTE] > context beep c no Bantoc after Triisap/Muusikatoan +U+17D2 any(c_out) + [K_QUOTE] > context beep c no Bantoc on a subscript +any(c_shifter) + any(c_shifter_key) > context beep c no two Triisap/Muusikatoan + +c Rotation + +U+17C7 + [SHIFT K_H] > U+17C8 c U+17C7 is changed to U+17C8 when pressing [SHIFT K_H]. +U+17C8 + [SHIFT K_H] > U+17C7 c U+17C8 is changed to U+17C7 when K_H is pressed. +c any(v_gen) U+17C7 + [SHIFT K_H] > context beep c Don't rotate between U+17C7 and U+17C8. + +c Press Space twice to get a White Space + +U+200B + [K_SPACE] > U+0020 + +c One backspace deletes a two-part vowels (i.e. psuedoVowel + U+17C7) + +any(v_combo_N) U+17C6 + [K_BKSP] > nul +any(v_combo_R) U+17C7 + [K_BKSP] > nul + +c When pressing [K_U] after ាំ and ុំ, the U+17BB is converted to a respective consonant shifter placing before them (ាំ and ុំ). + +any(shiftable_c_1st) U+17B6 U+17C6 + [K_U] > context(1) U+17CA context(2) context(3) c fix ស ាំ ុ > ស៊ាំ +any(shiftable_c_2nd_with_BA) U+17B6 U+17C6 + [K_U] > context(1) U+17C9 context(2) context(3) c fix ម ាំ ុ > ម៉ាំ + +c Consonant shifter constraints (beep when the consonant shifter is used in inappropriate environment) + +any(shiftable_c_1st) + [SHIFT K_QUOTE] > context U+17C9 beep +any(shiftable_c_2nd_with_BA) + [K_SLASH] > context U+17CA beep + +c 1st series consonant clusters + +any(c_combo_QA) U+17D2 U+17A2 + [SHIFT K_QUOTE] > context U+17C9 beep +U+179B U+17D2 any(c_1st_combo_LO) + [SHIFT K_QUOTE] > context U+17C9 beep +U+1798 U+17D2 any(c_1st_combo_MO) + [SHIFT K_QUOTE] > context U+17C9 beep +U+179F U+17D2 any(c_combo_SA) + [SHIFT K_QUOTE] > context U+17C9 beep +any(c_combo_HA) U+17D2 U+17A0 + [SHIFT K_QUOTE] > context U+17C9 beep +U+17A2 U+17D2 U+1784 + [SHIFT K_QUOTE] > context U+17C9 beep +U+17A2 U+17D2 U+179C + [SHIFT K_QUOTE] > context U+17C9 beep + +c 2nd series consonant clusters + +U+179B U+17D2 any(c_2nd_combo_LO) + [K_SLASH] > context U+17CA beep +U+1798 U+17D2 any(c_2nd_combo_MO) + [K_SLASH] > context U+17CA beep + + +c ==============================================MOBILE/TABLET TOUCH LAYOUT============================================== + + + ++ any(input_subcons) > U+17D2 index(subcons, 1) + +c delete a subscript (a subscript sign + a consonant) upon a backspace + +platform('touch') U+17D2 any(c_out) + [K_BKSP] > nul c working OK + + + [K_NPSTAR] > U+002A + + [SHIFT K_NPSTAR] > U+002A + + [K_NPPLUS] > U+002B + + [SHIFT K_NPPLUS] > U+002B + + [K_NPMINUS] > U+002D + + [SHIFT K_NPMINUS] > U+002D + + [K_NPDOT] > U+002E + + [SHIFT K_NPDOT] > U+002E + + [K_NPSLASH] > U+002F + + [SHIFT K_NPSLASH] > U+002F + + + +c ==============================================NORMALIZATION============================================== + + + +match > use(normalise) + +group(normalise) + +c Illegitimate vowel combinations should be transformed to the legitimate ones (Case #6 and #7). + +U+17C1 U+17B6 > U+17C4 c when type េ and ា, tranform them to ោ +U+17B6 U+17C1 > U+17C4 c when type ា and េ, tranform them to ោ +U+17C1 U+17B8 > U+17BE c when type េ and ី , tranform them to ើ +U+17B8 U+17C1 > U+17BE c when type ី and េ, tranform them to ើ + +c Illegitimate vowel combinations should be transformed to the legitimate ones (Case #5). + +U+17C6 U+17BB > U+17BB U+17C6 c when type ំ and ុ , tranform them to ុំ +U+17C6 U+17B6 > U+17B6 U+17C6 c when type ំ and ា, tranform them to ាំ + + +c Rotate vowels + +any(v_gen) any(v_gen) > context(2) c the last vowel stroke replaces the previous one. + +c Rotation of two-part vowels + +any(v_gen) any(v_pseudo) any(v_gen) > context(3) c a two-part vowel rotates to a genuine vowel. +any(v_gen) any(v_pseudo) any(v_pseudo) > context(3) c a two-part vowel rotates to a pseudo vowel. +any(v_gen) any(v_gen) any(v_pseudo) > context(2) context(3) c a genuine vowel rotates to a two-part vowel. +any(v_pseudo) any(v_gen) any(v_pseudo) > context(2) context(3) c a pseudo vowel roates to a two-part vowel. +any(v_gen) any(v_pseudo) any(v_gen) any(v_pseudo) > context(3) context(4) c a two-part vowel rotates to another two-part vowel. +any(v_pseudo) any(v_pseudo) > context(2) c a pseudo vowel rotates to another pseudo vowel. +c any(v_pseudo) any(v_gen) > context(2) c a pseudo vowel roates to a genuine vowel. + +c Delete extraneous coeng markers + +U+17D2 U+17D2 > context(1) c no two coengs are allowed. +U+17D2 any(v_any) > context(2) c The coeng is deleted when a vowel is put after it. +U+17D2 any(v_gen) any(v_pseudo) > context(2) context(3) c The coeng is deleted when a pseudo vowel is put after it. + +c Case #1: when a subscript is typed after a vowel, the subscript should be automatically moved to before the vowel. + +any(v_any) U+17D2 any(subcons) > context(2) context(3) context(1) c a vowel has to come after a subscript. +any(v_combo_N) U+17C6 U+17D2 any(subcons) > context(3) context(4) context(1) context(2) c these two-part vowels have to come after a subscript. +any(v_combo_R) U+17C7 U+17D2 any(subcons) > context(3) context(4) context(1) context(2) c these two-part vowels have to come after a subscript. + +c a subscript placed after a shifter and a vowel (a genuine/pseudo vowel or a two-part vowel) has to move to before them. + +any(c_shifter) any(v_any) U+17D2 any(subcons) > context(3) context(4) context(1) context(2) c after a genuine/pseudo vowel +any(c_shifter) any(v_combo_N) U+17C6 U+17D2 any(subcons) > context(4) context(5) context(1) context(2) context(3) c after a two-part vowel +any(c_shifter) any(v_combo_R) U+17C7 U+17D2 any(subcons) > context(4) context(5) context(1) context(2) context(3) c after a two-part vowel + +c Case #2: when [D2+9A] is typed before a subscript, it should be moved to after it. + +U+17D2 U+178A U+17D2 U+179A > context(1) U+178F context(3) context(4) c change subscript ្ដ to ្ត after ្រ +U+17D2 U+179A U+17D2 U+178A > context(3) U+178F context(1) context(2) c ្ដ placed after ្រ has to be changed to ្ត and placed before ្រ + +U+17D2 U+178A any(v_any) U+17D2 U+179A > context(1) U+178F context(4) context(5) context(3) c fixed 6e +U+17D2 U+178A any(v_combo_N) U+17C6 U+17D2 U+179A > context(1) U+178F context(5) context(6) context(3) context(4) +U+17D2 U+178A any(v_combo_R) U+17C7 U+17D2 U+179A > context(1) U+178F context(5) context(6) context(3) context(4) + +U+17D2 U+179A any(v_any) U+17D2 U+178A > context(1) U+178F context(4) context(2) context(3) c fixed 6g +U+17D2 U+179A any(v_combo_N) U+17C6 U+17D2 U+178A > context(1) U+178F context(5) context(2) context(3) context(4) +U+17D2 U+179A any(v_combo_R) U+17C7 U+17D2 U+178A > context(1) U+178F context(5) context(2) context(3) context(4) + +U+17D2 U+179A any(c_shifter) U+17D2 any(subcons) > context(4) context(5) context(1) context(2) context(3) c when a shifter intervenes, move it to the end. +U+17D2 U+179A U+17D2 any(subcons) > context(3) context(4) context(1) context(2) c move any subscript placed after [D2+DA] to before them +U+17D2 U+179A any(v_any) U+17D2 any(subcons) > context(4) context(5) context(1) context(2) context(3) c when a vowel intervenes, move it to the end +U+17D2 U+179A any(v_combo_N) U+17C6 U+17D2 any(subcons) > context(5) context(6) context(1) context(2) context(3) context(4) c when a two-part vowel intervenes, move it to the end too. +U+17D2 U+179A any(v_combo_R) U+17C7 U+17D2 any(subcons) > context(5) context(6) context(1) context(2) context(3) context(4) c (same as stated right above) + +c when a subscript is placed after a consonant shifter, they should be reversed. (Case #3) + +any(c_shifter) U+17D2 any(subcons) > context(2) context(3) context(1) + +c Reordering - Triisap and Muusikatoan store before a vowel and a vowelcomboR and pseudo vowel. + +any(v_any) any(c_shifter) > context(2) context(1) c place either a enguine or pseudo vowel after a consonant shifter +any(v_gen) any(v_pseudo) any(c_shifter) > context(3) context(1) context(2) c place a two-part vowel after a consonant shifter(i.e. មោះ៉ ) +any(c_shifter) any(v_any) any(c_shifter) > context(3) context(2) c when either a genuine or pseudo vowel is in between two consonant shifters, replace the one on the left with the one on the right. +any(c_shifter) any(v_gen) any(v_pseudo) any(c_shifter) > context(2) context(3) context(4) c when a two-part vowel is in between two consonants shifter, replace the one on the left with the one the right. + +c +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +c + when [BB] is place either before or after an above vowel (ិ ី ឹ ឺ ើ and ាំ) and a Samyok Sannya (Case #4) + +c + the [BB] should transform to a respective consonant shifter placed before the vowel. + +c + the consonant shifter is a Trisap if the base consonant is ស ហ អ + +c + the consonant shifter is a Muusikatoan if the base consonant is ង ញ ម យ រ វ ប and ន ល + +c +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +c consonant clusters --1st > 2nd series (with U+17BB) + +any(c_combo_QA) U+17D2 U+17A2 U+17BB any(v_above) > context(1) context(2) context(3) U+17CA context(5) +any(c_combo_QA) U+17D2 U+17A2 U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6) +any(c_combo_QA) U+17D2 U+17A2 any(v_above) U+17BB > context(1) context(2) context(3) U+17CA context(4) +any(c_combo_QA) U+17D2 U+17A2 U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(6) context(7) + +U+179B U+17D2 any(c_1st_combo_LO) U+17BB any(v_above) > context(1) context(2) context(3) U+17CA context(5) +U+179B U+17D2 any(c_1st_combo_LO) U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6) +U+179B U+17D2 any(c_1st_combo_LO) any(v_above) U+17BB > context(1) context(2) context(3) U+17CA context(4) +U+179B U+17D2 any(c_1st_combo_LO) U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(6) context(7) + +U+1798 U+17D2 any(c_1st_combo_MO) U+17BB any(v_above) > context(1) context(2) context(3) U+17CA context(5) +U+1798 U+17D2 any(c_1st_combo_MO) U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6) +U+1798 U+17D2 any(c_1st_combo_MO) any(v_above) U+17BB > context(1) context(2) context(3) U+17CA context(4) +U+1798 U+17D2 any(c_1st_combo_MO) U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(6) context(7) + +U+179F U+17D2 U+1794 U+17BB any(v_above) > context(1) context(2) context(3) U+17C9 context(5) c prevent ស្បុិ from transforming to ស្ប៊ិ​​​, but produce ស្ប៉ិ instead because ប never have Triisap shifted down. +U+179F U+17D2 U+1794 U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17C9 context(5) context(6) +U+179F U+17D2 U+1794 any(v_above) U+17BB > context(1) context(2) context(3) U+17C9 context(4) +U+179F U+17D2 U+1794 U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17C9 context(6) context(7) + +U+179F U+17D2 any(c_combo_SA) U+17BB any(v_above) > context(1) context(2) context(3) U+17CA context(5) +U+179F U+17D2 any(c_combo_SA) U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6) +U+179F U+17D2 any(c_combo_SA) any(v_above) U+17BB > context(1) context(2) context(3) U+17CA context(4) +U+179F U+17D2 any(c_combo_SA) U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(6) context(7) + +any(c_combo_HA) U+17D2 U+17A0 U+17BB any(v_above) > context(1) context(2) context(3) U+17CA context(5) +any(c_combo_HA) U+17D2 U+17A0 U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6) +any(c_combo_HA) U+17D2 U+17A0 any(v_above) U+17BB > context(1) context(2) context(3) U+17CA context(4) +any(c_combo_HA) U+17D2 U+17A0 U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(6) context(7) + +U+17A2 U+17D2 U+1784 U+17BB any(v_above) > context(1) context(2) context(3) U+17CA context(5) +U+17A2 U+17D2 U+1784 U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6) +U+17A2 U+17D2 U+1784 any(v_above) U+17BB > context(1) context(2) context(3) U+17CA context(4) +U+17A2 U+17D2 U+1784 U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(6) context(7) + +U+17A2 U+17D2 U+179C U+17BB any(v_above) > context(1) context(2) context(3) U+17CA context(5) +U+17A2 U+17D2 U+179C U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6) +U+17A2 U+17D2 U+179C any(v_above) U+17BB > context(1) context(2) context(3) U+17CA context(4) +U+17A2 U+17D2 U+179C U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(6) context(7) + +U+17A0 U+17D2 U+1794 U+17BB any(v_above) > context(1) context(2) context(3) U+17C9 context(5) c change U+17BB preceded by HA and coeng BA to U+17C9 before the above vowel +U+17A0 U+17D2 U+1794 U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17C9 context(3) context(6) c change U+17BB preceded by HA and coeng BA to U+17C9 before ាំ +U+17A0 U+17D2 U+1794 any(v_above) U+17BB > context(1) context(2) context(3) U+17C9 context(4) c change U+17BB preceded by HA and coeng BA to U+17C9 before the above vowel +U+17A0 U+17D2 U+1794 U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17C9 context(6) context(7) c change U+17BB preceded by HA and coeng BA to U+17C9 before U+17B6 U+17C6 + + +U+17A0 U+17D2 any(shiftable_c_2nd_with_BA) U+17BB any(v_above) > context(1) context(2) context(3) U+17CA context(5) c change U+17BB preceded by HA and coeng shiftable_c_2nd to U+17CA before the above vowel +U+17A0 U+17D2 any(shiftable_c_2nd_with_BA) U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(3) context(6) c change U+17BB preceded by HA and coeng shiftable_c_2nd to U+17CA before ាំ +U+17A0 U+17D2 any(shiftable_c_2nd_with_BA) any(v_above) U+17BB > context(1) context(2) context(3) U+17CA context(4) c change U+17BB preceded by HA and coeng shiftable_c_2nd to U+17CA before the above vowel +U+17A0 U+17D2 any(shiftable_c_2nd_with_BA) U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(6) context(7) c change U+17BB preceded by HA and coeng shiftable_c_2nd to U+17CA before U+17B6 U+17C6 + +c consonant clusters --2nd > 1st series (with U+17BB) + +U+179B U+17D2 any(c_2nd_combo_LO) U+17BB any(v_above) > context(1) context(2) context(3) U+17C9 context(5) +U+179B U+17D2 any(c_2nd_combo_LO) U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17C9 context(5) context(6) +U+179B U+17D2 any(c_2nd_combo_LO) any(v_above) U+17BB > context(1) context(2) context(3) U+17C9 context(4) +U+179B U+17D2 any(c_2nd_combo_LO) U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17C9 context(6) context(7) + +U+1798 U+17D2 any(c_2nd_combo_MO) U+17BB any(v_above) > context(1) context(2) context(3) U+17C9 context(5) +U+1798 U+17D2 any(c_2nd_combo_MO) U+17BB U+17B6 U+17C6 > context(1) context(2) context(3) U+17C9 context(5) context(6) +U+1798 U+17D2 any(c_2nd_combo_MO) any(v_above) U+17BB > context(1) context(2) context(3) U+17C9 context(4) +U+1798 U+17D2 any(c_2nd_combo_MO) U+17BB U+17C6 U+17B6 U+17C6 > context(1) context(2) context(3) U+17C9 context(6) context(7) + +c single consonants --1st > 2nd series (with U+17BB) + +any(shiftable_c_1st) U+17BB any(v_above) > context(1) U+17CA context(3) c change U+17BB to U+17CA before the above vowel +any(shiftable_c_1st) U+17BB U+17B6 U+17C6 > context(1) U+17CA context(3) context(4) c change U+17BB to U+17CA before ាំ +any(shiftable_c_1st) any(v_above) U+17BB > context(1) U+17CA context(2) c change U+17BB to U+17CA and place it before the above vowel +any(shiftable_c_1st) U+17BB U+17C6 U+17B6 U+17C6 > context(1) U+17CA context(4) context(5) c change U+17BB U+17C6 to U+17CA + +c single consonants --2nd > 1st series (with U+17BB) + +any(shiftable_c_2nd_with_BA) U+17BB any(v_above) > context(1) U+17C9 context(3) c change U+17BB to U+17C9 before the above vowel +any(shiftable_c_2nd_with_BA) U+17BB U+17B6 U+17C6 > context(1) U+17C9 context(3) context(4) c change U+17BB to U+17C9 before ាំ +any(shiftable_c_2nd_with_BA) any(v_above) U+17BB > context(1) U+17C9 context(2) c change U+17BB to U+17C9 before the above vowel +any(shiftable_c_2nd_with_BA) U+17BB U+17C6 U+17B6 U+17C6 > context(1) U+17C9 context(4) context(5) c change U+17BB U+17C6 to U+17C9 + +c prevent incorrect use of consonant shifter with 2nd series consonant clusters (without U+17BB) + +U+179B U+17D2 any(c_2nd_combo_LO) U+17CA any(v_above) > context(1) context(2) context(3) U+17C9 context(5) +U+1798 U+17D2 any(c_2nd_combo_MO) U+17CA any(v_above) > context(1) context(2) context(3) U+17C9 context(5) +U+179B U+17D2 any(c_2nd_combo_LO) U+17CA any(v_gen) any(v_pseudo) > context(1) context(2) context(3) U+17C9 context(5) context(6) +U+1798 U+17D2 any(c_2nd_combo_MO) U+17CA any(v_gen) any(v_pseudo) > context(1) context(2) context(3) U+17C9 context(5) context(6) + +c single consonants --2nd > 1st series (without U+17BB) + +any(shiftable_c_2nd) U+17CA any(v_above) > context(1) U+17C9 context(3) c change U+17CA to U+17C9 before the above vowel +any(shiftable_c_2nd) U+17CA any(v_gen) any(v_pseudo) > context(1) U+17C9 context(3) context(4) c change U+17CA to U+17C9 before ាំ + +U+17D2 any(shiftable_c_2nd) U+17CA any(v_above) > context c stop ស្រ៊ី from becoming ស្រ៉ី +U+17D2 any(shiftable_c_2nd) U+17CA any(v_gen) any(v_pseudo) > context + +c SPECIAL CASE -- the following clusters may accept either of the two consonant shifters. + +U+1794 U+17D2 U+1799 any(c_shifter) > context +U+179F U+17D2 U+1794 any(c_shifter) > context +U+1786 U+17D2 U+1794 any(c_shifter) > context +U+1794 U+17D2 U+1799 any(c_shifter) > context +U+179F U+17D2 U+1794 any(c_shifter) > context +U+1786 U+17D2 U+1794 any(c_shifter) > context + +c single --1st > 2nd series (without U+17BB) + +any(shiftable_c_1st) U+17C9 any(v_above) > context(1) U+17CA context(3) c change U+17C9 to U+17CA before the above vowel +any(shiftable_c_1st) U+17C9 any(v_gen) any(v_pseudo) > context(1) U+17CA context(3) context(4) c change U+17C9 to U+17CA before ាំ + +c consonant clusters --1st > 2nd series (without U+17BB) + +any(c_combo_QA) U+17D2 U+17A2 U+17C9 any(v_above) > context(1) context(2) context(3) U+17CA context(5) +U+179B U+17D2 any(c_1st_combo_LO) U+17C9 any(v_above) > context(1) context(2) context(3) U+17CA context(5) +U+1798 U+17D2 any(c_1st_combo_MO) U+17C9 any(v_above) > context(1) context(2) context(3) U+17CA context(5) +U+179F U+17D2 U+1794 U+17C9 any(v_above) > context(1) context(2) context(3) U+17C9 context(5) c prevent ស្ប៉ី from transforming to ស្ប៊ី +U+179F U+17D2 any(c_combo_SA) U+17C9 any(v_above) > context(1) context(2) context(3) U+17CA context(5) +any(c_combo_HA) U+17D2 U+17A0 U+17C9 any(v_above) > context(1) context(2) context(3) U+17CA context(5) +U+17A2 U+17D2 U+1784 U+17C9 any(v_above) > context(1) context(2) context(3) U+17CA context(5) +U+17A2 U+17D2 U+179C U+17C9 any(v_above) > context(1) context(2) context(3) U+17CA context(5) +any(c_combo_QA) U+17D2 U+17A2 U+17C9 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6) +U+179B U+17D2 any(c_1st_combo_LO) U+17C9 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6) +U+1798 U+17D2 any(c_1st_combo_MO) U+17C9 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6) +U+179F U+17D2 U+1794 U+17C9 U+17B6 U+17C6 > context(1) context(2) context(3) U+17C9 context(5) context(6) c prevent ស្ប៉ាំ from transforming to ស្ប៊ាំ +U+179F U+17D2 any(c_combo_SA) U+17C9 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6) +any(c_combo_HA) U+17D2 U+17A0 U+17C9 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6) +U+17A2 U+17D2 U+1784 U+17C9 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6) +U+17A2 U+17D2 U+179C U+17C9 U+17B6 U+17C6 > context(1) context(2) context(3) U+17CA context(5) context(6) + +c U+17B6 U+17BB and U+17C6 in that order preceeded by any first series consonant (cluster) are transformed to U+17CA U+17B6 and U+17C6 + +any(shiftable_c_1st) U+17B6 U+17BB U+17C6 > context(1) U+17CA context(2) context(4) +any(shiftable_c_1st) U+17BB U+17C6 U+17B6 > context(1) U+17CA context(4) context(3) + +any(c_combo_QA) U+17D2 U+17A2 U+17B6 U+17BB U+17C6 > context(1) context(2) context(3) U+17CA context(4) context(6) +any(c_combo_QA) U+17D2 U+17A2 U+17BB U+17C6 U+17B6 > context(1) context(2) context(3) U+17CA context(6) context(5) + +U+179B U+17D2 any(c_1st_combo_LO) U+17B6 U+17BB U+17C6 > context(1) context(2) context(3) U+17CA context(4) context(6) +U+179B U+17D2 any(c_1st_combo_LO) U+17BB U+17C6 U+17B6 > context(1) context(2) context(3) U+17CA context(6) context(5) + +U+1798 U+17D2 any(c_1st_combo_MO) U+17B6 U+17BB U+17C6 > context(1) context(2) context(3) U+17CA context(4) context(6) +U+1798 U+17D2 any(c_1st_combo_MO) U+17BB U+17C6 U+17B6 > context(1) context(2) context(3) U+17CA context(6) context(5) + +U+179F U+17D2 any(c_combo_SA) U+17B6 U+17BB U+17C6 > context(1) context(2) context(3) U+17CA context(4) context(6) +U+179F U+17D2 any(c_combo_SA) U+17BB U+17C6 U+17B6 > context(1) context(2) context(3) U+17CA context(6) context(5) + +any(c_combo_HA) U+17D2 U+17A0 U+17B6 U+17BB U+17C6 > context(1) context(2) context(3) U+17CA context(4) context(6) +any(c_combo_HA) U+17D2 U+17A0 U+17BB U+17C6 U+17B6 > context(1) context(2) context(3) U+17CA context(6) context(5) + +U+17A2 U+17D2 U+1784 U+17B6 U+17BB U+17C6 > context(1) context(2) context(3) U+17CA context(4) context(6) +U+17A2 U+17D2 U+1784 U+17BB U+17C6 U+17B6 > context(1) context(2) context(3) U+17CA context(6) context(5) + +U+17A2 U+17D2 U+179C U+17B6 U+17BB U+17C6 > context(1) context(2) context(3) U+17CA context(4) context(6) +U+17A2 U+17D2 U+179C U+17BB U+17C6 U+17B6 > context(1) context(2) context(3) U+17CA context(4) context(6) + +c U+17B6 U+17BB and U+17C6 in that order preceeded by any second series consonant (cluster) are transformed to U+17C9 U+17B6 and U+17C6 + +any(shiftable_c_2nd_with_BA) U+17B6 U+17BB U+17C6 > context(1) U+17C9 context(2) context(4) +any(shiftable_c_2nd_with_BA) U+17BB U+17C6 U+17B6 > context(1) U+17C9 context(4) context(3) + +U+179B U+17D2 any(c_2nd_combo_LO) U+17B6 U+17BB U+17C6 > context(1) context(2) context(3) U+17C9 context(4) context(6) +U+179B U+17D2 any(c_2nd_combo_LO) U+17BB U+17C6 U+17B6 > context(1) context(2) context(3) U+17C9 context(6) context(5) + +U+1798 U+17D2 any(c_2nd_combo_MO) U+17B6 U+17BB U+17C6 > context(1) context(2) context(3) U+17C9 context(4) context(6) +U+1798 U+17D2 any(c_2nd_combo_MO) U+17BB U+17C6 U+17B6 > context(1) context(2) context(3) U+17C9 context(6) context(5) + +c េុី/ុេី/៉េី > ៊ើ + +any(shiftable_c_1st) U+17C1 U+17BB U+17B8 > context(1) U+17CA U+17BE c cancel out by vowel rotation +any(shiftable_c_1st) U+17BB U+17C1 U+17B8 > context(1) U+17CA U+17BE c cancel out by vowel rotation +any(shiftable_c_1st) U+17C9 U+17C1 U+17B8 > context(1) U+17CA U+17BE + +any(c_combo_QA) U+17D2 U+17A2 U+17C1 U+17BB U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation +any(c_combo_QA) U+17D2 U+17A2 U+17BB U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation +any(c_combo_QA) U+17D2 U+17A2 U+17C9 U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE + +U+179B U+17D2 any(c_1st_combo_LO) U+17C1 U+17BB U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation +U+179B U+17D2 any(c_1st_combo_LO) U+17BB U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation +U+179B U+17D2 any(c_1st_combo_LO) U+17C9 U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE + +U+1798 U+17D2 any(c_1st_combo_MO) U+17C1 U+17BB U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation +U+1798 U+17D2 any(c_1st_combo_MO) U+17BB U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation +U+1798 U+17D2 any(c_1st_combo_MO) U+17C9 U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE + +U+179F U+17D2 any(c_combo_SA) U+17C1 U+17BB U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation +U+179F U+17D2 any(c_combo_SA) U+17BB U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation +U+179F U+17D2 any(c_combo_SA) U+17C9 U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE + +any(c_combo_HA) U+17D2 U+17A0 U+17C1 U+17BB U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation +any(c_combo_HA) U+17D2 U+17A0 U+17BB U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation +any(c_combo_HA) U+17D2 U+17A0 U+17C9 U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE + +U+17A2 U+17D2 U+1784 U+17C1 U+17BB U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation +U+17A2 U+17D2 U+1784 U+17BB U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation +U+17A2 U+17D2 U+1784 U+17C9 U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE + +U+17A2 U+17D2 U+179C U+17C1 U+17BB U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation +U+17A2 U+17D2 U+179C U+17BB U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE c cancel out by vowel rotation +U+17A2 U+17D2 U+179C U+17C9 U+17C1 U+17B8 > context(1) context(2) context(3) U+17CA U+17BE + +c េុី/ុេី/៊េី > ៉ើ + +any(shiftable_c_2nd) U+17C1 U+17BB U+17B8 > context(1) U+17C9 U+17BE c cancel out by vowel rotation +any(shiftable_c_2nd) U+17BB U+17C1 U+17B8 > context(1) U+17C9 U+17BE c cancel out by vowel rotation +any(shiftable_c_2nd) U+17CA U+17C1 U+17B8 > context(1) U+17C9 U+17BE + +U+179B U+17D2 any(c_2nd_combo_LO) U+17C1 U+17BB U+17B8 > context(1) context(2) context(3) U+17C9 U+17BE c cancel out by vowel rotation +U+179B U+17D2 any(c_2nd_combo_LO) U+17BB U+17C1 U+17B8 > context(1) context(2) context(3) U+17C9 U+17BE c cancel out by vowel rotation +U+179B U+17D2 any(c_2nd_combo_LO) U+17CA U+17C1 U+17B8 > context(1) context(2) context(3) U+17C9 U+17BE + +U+1798 U+17D2 any(c_2nd_combo_MO) U+17C1 U+17BB U+17B8 > context(1) context(2) context(3) U+17C9 U+17BE c cancel out by vowel rotation +U+1798 U+17D2 any(c_2nd_combo_MO) U+17BB U+17C1 U+17B8 > context(1) context(2) context(3) U+17C9 U+17BE c cancel out by vowel rotation +U+1798 U+17D2 any(c_2nd_combo_MO) U+17CA U+17C1 U+17B8 > context(1) context(2) context(3) U+17C9 U+17BE + +c place Robat after a base before any vowel + +any(c_out) any(v_gen) U+17CC > context(1) context(3) context(2) + +c Use appropriate identical subscript in two separate contexts. (Case #8) + +U+178E U+17D2 U+178F > context(1) context(2) U+178A +U+1793 U+17D2 U+178A > context(1) context(2) U+178F + +c BONUSES​(note that these combinations are invalid and they can't be found in the CN dictionary 1967 nor RH 1997, but users think they are) + +U+1791 U+17D2 U+1794 > U+17A1 c ទ្ប transforms to ឡ + +U+1794 U+17D2 U+1789 > U+17AB c ប្ញ transforms to ឫ +U+17AB U+17BB > U+17AC c ឫុ transforms to ឬ + +U+17AD U+17B6 > U+1789 c ឭា transforms to ញ +U+17AE U+17B6 > U+1789 c ឮា transforms to ញ + +U+1796 U+17D2 U+1789 > U+17AD c ព្ញ transforms to ឭ +U+17AD U+17BB > U+17AE c ឭុ transforms to ឮ + +U+1796 U+17D2 U+178B > U+17B0 c ព្ឋ transforms to ឰ + +U+17A7 U+17B7 > U+17B1 c ឧិ transforms to ឱ +U+17A7 U+17CC > U+17B1 c ឧ៌ transforms to ឱ +U+17A7 U+17CD > U+17B1 c ឧ៍ transforms to ឱ + +c U+17D4 U+179B U+17D4 > U+17D8 c ។ល។ transforms to U+17D8 + +U+178A U+17D2 U+1792 > U+178A U+17D2 U+178B c ដ្ធ > ដ្ឋ +U+1791 U+17D2 U+178B > U+1791 U+17D2 U+1792 c ទ្ឋ > ទ្ធ + +c additional rules + +U+1796 U+1793 U+17D2 U+178B > context(1) context(2) context(3) U+1792 c ពន្ឋ > ពន្ធ +U+1796 U+17D0 U+1793 U+17D2 U+178B > context(1) context(2) context(3) context(4) U+1792 c ព័ន្ឋ > ព័ន្ធ + + +U+17AA U+17D2 U+1799 > U+17B1 context(2) context(3) c ឪ្យ > ឱ្យ +U+17B3 U+17D2 U+1799 > U+17B1 context(2) context(3) c ឳ្យ > ឱ្យ + +U+1789 U+17D2 U+179C > U+1796 context(2) context(3) U+17B6 c ញ្វ (as in សញ្វវុធ) > ព្វា as in សញ្វវុធ + +U+17D2 U+1799 U+17C1 U+17BA > U+17BF c េ្យឺ > ឿ +U+17D2 U+1799 U+17C1 U+17B9 > U+17BF c េ្យឹ > ឿ +U+17D2 U+1799 U+17C1 U+17B8 > U+17BF c េ្យី > ឿ + +U+17D2 U+1799 U+17D2 any(c_out) U+17C1 U+17BA > context(3) context(4) U+17BF c គ្រេ្យឺង > គ្រឿង +U+17D2 U+1799 U+17D2 any(c_out) U+17C1 U+17B9 > context(3) context(4) U+17BF c គ្រេ្យឹង > គ្រឿង +U+17D2 U+1799 U+17D2 any(c_out) U+17C1 U+17B8 > context(3) context(4) U+17BF c គ្រេ្យីង > គ្រឿង + +c In everyday practice, both 'regular space' and 'no-break space' are not used before punctuation, i.e. ។ ! etc. +c An annoying issue of having line broken up at the end of the line dropping the punctuation (។, ! and also ៗ) to the next line. +c It may be helpful to include a rule where a 'Zero Width No-Break Space' should be output together with those punct. +c ref: https://www.unicode.org/L2/L2020/20008-core-text.pdf +c ref: https://www.unicode.org/versions/Unicode12.0.0/ch23.pdf#G12985 +c ref: https://www.compart.com/en/unicode/U+FEFF + +c EOF diff --git a/developer/src/kmc-kmw/test/fixtures/khmer_angkor.kvks b/developer/src/kmc-kmw/test/fixtures/khmer_angkor.kvks new file mode 100644 index 0000000000..e9c38a464d --- /dev/null +++ b/developer/src/kmc-kmw/test/fixtures/khmer_angkor.kvks @@ -0,0 +1,206 @@ + + +
+ 10.0 + khmer_angkor + + + +
+ + + ឞ + ឝ + ៈ + ឳ + ឨ + ឩ + ឰ + ឫ + ឦ + ឱ + ឯ + + + ៜ + + ៖ + ៙ + ៚ + + ៘ + ‌ + ‍ + ] + [ + / + . + ‘ + + + & + ’ + * + @ + \ + } + { + - + ÷ + : + , + ≈ + ; + < + # + > + × + $ + € +   + + + ៸ + ៰ + ៱ + ៲ + ៳ + ៴ + ៵ + ៶ + ៷ + ៹ + ᧿ + ᧾ + ᧪ + ᧫ + ᧶ + ᧵ + ᧬ + ᧷ + ᧥ + ᧸ + ᧡ + ᧻ + ᧹ + ᧮ + ᧢ + ᧯ + ᧰ + ᧦ + ᧱ + ᧤ + ᧭ + ᧣ + ᧧ + ᧠ + ᧺ + ᧲ + ᧳ + ᧴ + ᧩ + ᧨ + ᧼ + ᧽ + + + ​ + + + ឥ + ។ + + ០ + ១ + ២ + ៣ + ៤ + ៥ + ៦ + ៧ + ៨ + ៩ + + ឲ + + ឮ + ឪ + « + + ប + ច + ដ + + ថ + ង + ហ + + + ក + ល + ម + ន + + ផ + ឆ + រ + ស + ត + + វ + + ខ + យ + ឋ + + + + ! + + " + ៛ + % + + ( + ) + + = + + ៕ + ? + ៗ + + ព + ជ + ឌ + + ធ + អ + ះ + + ញ + គ + ឡ + + ណ + + ភ + ឈ + ឬ + + ទ + + + + ឃ + + ឍ + + + + ឭ + ឧ + » + + + +
diff --git a/developer/src/kmc-kmw/test/test-compiler-manual.ts b/developer/src/kmc-kmw/test/test-compiler-manual.ts new file mode 100644 index 0000000000..af2589b833 --- /dev/null +++ b/developer/src/kmc-kmw/test/test-compiler-manual.ts @@ -0,0 +1,49 @@ +import { dirname } from 'path'; +import { fileURLToPath } from 'url'; +import fs from 'fs'; +import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; +import { Compiler } from '@keymanapp/kmc-kmn'; +import { KMX, KmxFileReader } from '@keymanapp/common-types'; +import { WriteCompiledKeyboard } from '../src/compiler/write-compiled-keyboard.js'; + +const __dirname = dirname(fileURLToPath(import.meta.url)).replace(/\\/g, '/'); +const fixturesDir = __dirname + '/../../test/fixtures/'; +const fixtureName = fixturesDir + 'khmer_angkor.js'; +const infile = fixturesDir + 'khmer_angkor.kmn'; +const outfile = fixturesDir + 'khmer_angkor.kmx'; // intermediate outfile +const testOutfile = fixturesDir + 'khmer_angkor.test.js'; + +if(fs.existsSync(testOutfile)) { + fs.unlinkSync(testOutfile); +} + +const callbacks = new TestCompilerCallbacks(); + +const kmxCompiler = new Compiler(); +if(!await kmxCompiler.init()) { + console.error('kmx compiler failed to init'); + process.exit(1); +} + +// TODO: runToMemory, add option to kmxCompiler to store debug-data for conversion to .js (e.g. store metadata, group readonly metadata, etc) +if(!kmxCompiler.run(infile, outfile, callbacks, { + shouldAddCompilerVersion: false, + saveDebug: true +})) { + callbacks.printMessages(); + process.exit(1); +} + +const reader = new KmxFileReader(); +const keyboard: KMX.KEYBOARD = reader.read(callbacks.loadFile(outfile)); + +const js = WriteCompiledKeyboard(callbacks, 'khmer_angkor', keyboard, true); + +callbacks.printMessages(); + +const fjs = fs.readFileSync(fixtureName, 'utf8'); +if(fjs !== js) { + fs.writeFileSync(testOutfile, js); + console.error('JS not equal'); + process.exit(1); +} diff --git a/developer/src/kmc-kmw/test/test-compiler.ts b/developer/src/kmc-kmw/test/test-compiler.ts new file mode 100644 index 0000000000..7fb0efd9ce --- /dev/null +++ b/developer/src/kmc-kmw/test/test-compiler.ts @@ -0,0 +1,55 @@ +import 'mocha'; +import { assert } from 'chai'; +// import sinonChai from 'sinon-chai'; +import { WriteCompiledKeyboard } from '../src/compiler/write-compiled-keyboard.js'; +import { dirname } from 'path'; +import { fileURLToPath } from 'url'; +import fs from 'fs'; +import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; +import { Compiler } from '@keymanapp/kmc-kmn'; +import { KMX, KmxFileReader } from '@keymanapp/common-types'; + +const __dirname = dirname(fileURLToPath(import.meta.url)).replace(/\\/g, '/'); +const fixturesDir = __dirname + '/../../test/fixtures/'; +//const baselineDir = __dirname + '/../../../../../common/test/keyboards/baseline/'; +// chai.use(sinonChai); + +describe('Compiler class', function() { + const callbacks = new TestCompilerCallbacks(); + + this.afterEach(function() { + callbacks.printMessages(); + callbacks.clear(); + }); + + it('should compile a basic keyboard', async function() { + // const compiler = new KeymanWebCompiler(callbacks, {addCompilerVersion: false, debug: true}); + + const fixtureName = fixturesDir + 'khmer_angkor.js'; + const infile = fixturesDir + 'khmer_angkor.kmn'; + const outfile = fixturesDir + 'khmer_angkor.kmx'; // intermediate outfile + const testOutfile = fixturesDir + 'khmer_angkor.test.js'; + + if(fs.existsSync(testOutfile)) { + fs.unlinkSync(testOutfile); + } + + const kmxCompiler = new Compiler(); + assert.isTrue(await kmxCompiler.init()); + + // TODO: runToMemory, add option to kmxCompiler to store debug-data for conversion to .js (e.g. store metadata, group readonly metadata, etc) + assert.isTrue(kmxCompiler.run(infile, outfile, callbacks)); + + const reader = new KmxFileReader(); + const keyboard: KMX.KEYBOARD = reader.read(callbacks.loadFile(outfile)); + + const js = WriteCompiledKeyboard(callbacks, 'khmer_angkor', keyboard, true); + // const js = compiler.compile('khmer_angkor', keyboard); + + const fjs = fs.readFileSync(fixtureName, 'utf8'); + if(fjs !== js) { + fs.writeFileSync(testOutfile, js); + assert.fail('JS not equal'); + } + }); +}); \ No newline at end of file diff --git a/developer/src/kmc-kmw/test/tsconfig.json b/developer/src/kmc-kmw/test/tsconfig.json new file mode 100644 index 0000000000..abdb3a7cfe --- /dev/null +++ b/developer/src/kmc-kmw/test/tsconfig.json @@ -0,0 +1,25 @@ +{ + "extends": "../../kmc/tsconfig.kmc-base.json", + + "compilerOptions": { + "rootDir": ".", + "rootDirs": ["./", "../src/"], + "outDir": "../build/test", + "baseUrl": ".", + "allowSyntheticDefaultImports": true, // for chai + "paths": { + "@keymanapp/common-types": ["../../../../common/web/types/src/main"], + "@keymanapp/developer-test-helpers": ["../../common/web/test-helpers/index"], + "@keymanapp/kmc-kmn": ["../../kmc-kmn/src/main"], + }, + }, + "include": [ + "**/test-*.ts" + ], + "references": [ + { "path": "../../../../common/web/types/" }, + { "path": "../../kmc-kmn/" }, + { "path": "../../common/web/test-helpers/" }, + { "path": "../" } + ] +} \ No newline at end of file diff --git a/developer/src/kmc-kmw/tsconfig.json b/developer/src/kmc-kmw/tsconfig.json index a9dcdbbb2a..fb2abd93e3 100644 --- a/developer/src/kmc-kmw/tsconfig.json +++ b/developer/src/kmc-kmw/tsconfig.json @@ -16,9 +16,9 @@ }, "include": [ "src/**/*.ts" - ], +, "src/compiler/__keymanweb-compiler.ts.tmp" ], "references": [ - { "path": "../../../common/web/keyman-version/tsconfig.esm.json" }, + // { "path": "../../../common/web/keyman-version/tsconfig.esm.json" }, { "path": "../../../common/web/types/" }, { "path": "../../../core/include/ldml/"}, ] -- GitLab From d2581ae4a88e0f9a131650b17c85cc2839fb5034 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 5 May 2023 09:14:15 +0700 Subject: [PATCH 097/214] feat(developer): 'working' kmw compiler --- .../keyman-touch-layout-file-writer.ts | 31 +- common/web/types/src/kmx/kmx-file-reader.ts | 54 +++- common/web/types/src/kmx/kmx.ts | 18 +- common/web/types/src/kvk/visual-keyboard.ts | 1 + common/web/types/src/main.ts | 2 +- .../src/kmc-kmn/src/compiler/compiler.ts | 12 +- developer/src/kmc-kmw/build.sh | 1 + developer/src/kmc-kmw/package.json | 4 +- .../src/compiler/javascript-strings.ts | 4 +- .../src/compiler/keymanweb-key-codes.ts | 271 +++++++++++++++++ .../src/compiler/validate-layout-file.ts | 280 ++++++++++++++++++ .../src/compiler/visual-keyboard-compiler.ts | 163 ++++++++++ .../src/compiler/write-compiled-keyboard.ts | 86 +++--- .../src/kmc-kmw/test/test-compiler-manual.ts | 12 +- developer/src/kmc-kmw/test/test-compiler.ts | 26 +- developer/src/kmc-kmw/test/tsconfig.json | 3 +- developer/src/kmc-kmw/test/util.ts | 19 ++ developer/src/kmc-kmw/tsconfig.json | 9 +- developer/src/kmcmpdll/Compiler.cpp | 2 +- developer/src/kmcmplib/include/kmcmplibapi.h | 3 +- developer/src/kmcmplib/src/Compiler.cpp | 15 +- .../src/kmcmplib/src/CompilerInterfaces.cpp | 9 +- developer/src/kmcmplib/tests/api-test.cpp | 2 +- developer/src/kmcmplib/tests/kmcompxtest.cpp | 2 +- 24 files changed, 938 insertions(+), 91 deletions(-) create mode 100644 developer/src/kmc-kmw/src/compiler/keymanweb-key-codes.ts create mode 100644 developer/src/kmc-kmw/src/compiler/validate-layout-file.ts create mode 100644 developer/src/kmc-kmw/src/compiler/visual-keyboard-compiler.ts create mode 100644 developer/src/kmc-kmw/test/util.ts diff --git a/common/web/types/src/keyman-touch-layout/keyman-touch-layout-file-writer.ts b/common/web/types/src/keyman-touch-layout/keyman-touch-layout-file-writer.ts index a86ed0441f..6ee01b7f8e 100644 --- a/common/web/types/src/keyman-touch-layout/keyman-touch-layout-file-writer.ts +++ b/common/web/types/src/keyman-touch-layout/keyman-touch-layout-file-writer.ts @@ -17,12 +17,19 @@ export class TouchLayoutFileWriter { * @param source TouchLayoutFile * @returns Uint8Array, the .keyman-touch-layout file */ - write(source: TouchLayoutFile): Uint8Array { - const output = JSON.stringify(source, null, this.options?.formatted ? 2 : undefined); + public write(source: TouchLayoutFile): Uint8Array { + const output = this.toJSONString(source); const encoder = new TextEncoder(); return encoder.encode(output); } + /** + * Gets the output as a JSON string + */ + public toJSONString(source: TouchLayoutFile): string { + return JSON.stringify(source, null, this.options?.formatted ? 2 : undefined); + } + /** * Compiles the touch layout file into a KeymanWeb-compatible JSON-style * object string. In the future, this may be optimized to remove unnecessary @@ -31,7 +38,11 @@ export class TouchLayoutFileWriter { * @param source * @returns string */ - compile(source: TouchLayoutFile): string { + public compile(source: TouchLayoutFile): string { + return this.toJSONString(this.fixup(source)); + } + + public fixup(source: TouchLayoutFile): TouchLayoutFile { // Deep copy the source source = JSON.parse(JSON.stringify(source)); @@ -40,13 +51,23 @@ export class TouchLayoutFileWriter { const fixupKey = (key: TouchLayoutKey | TouchLayoutSubKey) => { if(Object.hasOwn(key, 'pad')) (key.pad as any) = key.pad.toString(); - if(Object.hasOwn(key, 'sp')) (key.sp as any) = key.sp.toString(); + if(Object.hasOwn(key, 'sp')) { + if(key.sp == 0) { + delete key.sp; + } + else { + (key.sp as any) = key.sp.toString(); + } + } if(Object.hasOwn(key, 'width')) (key.width as any) = key.width.toString(); + if(Object.hasOwn(key, 'text') && key.text === '') delete key.text; }; const fixupPlatform = (platform: TouchLayoutPlatform) => { for(let layer of platform.layer) { for(let row of layer.row) { + // this matches the old spec for touch layout files + (row.id as any) = row.id.toString(); for(let key of row.key) { fixupKey(key); if(key.sk) { @@ -79,6 +100,6 @@ export class TouchLayoutFileWriter { fixupPlatform(source.tablet); } - return JSON.stringify(source, null, this.options?.formatted ? 2 : undefined); + return source; } }; \ No newline at end of file diff --git a/common/web/types/src/kmx/kmx-file-reader.ts b/common/web/types/src/kmx/kmx-file-reader.ts index 824e56c71d..45131ade77 100644 --- a/common/web/types/src/kmx/kmx-file-reader.ts +++ b/common/web/types/src/kmx/kmx-file-reader.ts @@ -13,11 +13,42 @@ export class KmxFileReader { return this.rString.fromBuffer(source.slice(offset)); } + private processSystemStore(store: STORE, result: KEYBOARD) { + switch(store.dwSystemID) { + case KMXFile.TSS_MNEMONIC: + result.isMnemonic = store.dpString == '1'; + break; + case KMXFile.TSS_KEYBOARDVERSION: + result.keyboardVersion = store.dpString; + break; + case KMXFile.TSS_BEGIN_NEWCONTEXT: + if(store.dpString.length == 3 && store.dpString.charCodeAt(0) == 0xFFFF && store.dpString.charCodeAt(1) == KMXFile.CODE_USE) { + result.startGroup.newContext = store.dpString.charCodeAt(2) - 1; + } + else { + // TODO: error + return false; + } + break; + case KMXFile.TSS_BEGIN_POSTKEYSTROKE: + if(store.dpString.length == 3 && store.dpString.charCodeAt(0) == 0xFFFF && store.dpString.charCodeAt(1) == KMXFile.CODE_USE) { + result.startGroup.postKeystroke = store.dpString.charCodeAt(2) - 1; + } + else { + // TODO: error + return false; + } + break; + } + return true; + } + public read(source: Uint8Array): KEYBOARD { let binaryKeyboard: BUILDER_COMP_KEYBOARD; let kmx = new KMXFile(); binaryKeyboard = kmx.COMP_KEYBOARD.fromBuffer(source); if(binaryKeyboard.dwIdentifier != KMXFile.FILEID_COMPILED) { + // TODO: error return null; } @@ -25,14 +56,17 @@ export class KmxFileReader { result.fileVersion = binaryKeyboard.dwFileVersion; result.flags = binaryKeyboard.dwFlags; result.hotkey = binaryKeyboard.dwHotKey; - result.keyboardVersion = '0'; //TODO result.startGroup = { - ansi: binaryKeyboard.StartGroup_ANSI, - unicode: binaryKeyboard.StartGroup_Unicode, + ansi: binaryKeyboard.StartGroup_ANSI == 0xFFFFFFFF ? -1 : binaryKeyboard.StartGroup_ANSI, + unicode: binaryKeyboard.StartGroup_Unicode == 0xFFFFFFFF ? -1 : binaryKeyboard.StartGroup_Unicode, newContext: -1, //TODO postKeystroke: -1 // TODO } + // Informative data + result.keyboardVersion = ''; + result.isMnemonic = false; + let offset = binaryKeyboard.dpStoreArray; for(let i = 0; i < binaryKeyboard.cxStoreArray; i++) { let binaryStore = kmx.COMP_STORE.fromBuffer(source.slice(offset)); @@ -41,6 +75,11 @@ export class KmxFileReader { store.dpName = this.readString(source, binaryStore.dpName); store.dpString = this.readString(source, binaryStore.dpString); result.stores.push(store); + + if(!this.processSystemStore(store, result)) { + return null; + } + offset += KMXFile.COMP_STORE_SIZE; } @@ -73,6 +112,15 @@ export class KmxFileReader { // TODO: KMXPlusFile + // Validate startGroup offsets + let gp: keyof KEYBOARD['startGroup']; + for(gp in result.startGroup) { + if(result.startGroup[gp] < -1 || result.startGroup[gp] >= result.groups.length) { + // TODO: error + return null; + } + } + return result; } }; \ No newline at end of file diff --git a/common/web/types/src/kmx/kmx.ts b/common/web/types/src/kmx/kmx.ts index cb7af49480..17e8b3749f 100644 --- a/common/web/types/src/kmx/kmx.ts +++ b/common/web/types/src/kmx/kmx.ts @@ -9,14 +9,13 @@ import * as r from 'restructure'; export class KEYBOARD { fileVersion?: number; // dwFileVersion (TSS_FILEVERSION) - keyboardVersion?: string; // version (TSS_KEYBOARDVERSION) startGroup: { - ansi: number; - unicode: number; - newContext: number; // TSS_BEGIN_NEWCONTEXT - postKeystroke: number; // TSS_BEGIN_POSTKEYSTROKE - } = {ansi:0xFFFFFFFF, unicode:0xFFFFFFFF, newContext:0xFFFFFFFF, postKeystroke:0xFFFFFFFF}; + ansi: number; // from COMP_KEYBOARD + unicode: number; // from COMP_KEYBOARD + newContext: number; // from TSS_BEGIN_NEWCONTEXT store + postKeystroke: number; // from TSS_BEGIN_POSTKEYSTROKE store + } = {ansi:-1, unicode:-1, newContext:-1, postKeystroke:-1}; flags?: number; hotkey?: number; @@ -24,6 +23,13 @@ export class KEYBOARD { //bitmap: groups: GROUP[] = []; stores: STORE[] = []; + + // Following values are extracted from stores[] but are + // informative only + + keyboardVersion?: string; // version (TSS_KEYBOARDVERSION) + isMnemonic: boolean; // TSS_MNEMONICLAYOUT store + }; export class STORE { diff --git a/common/web/types/src/kvk/visual-keyboard.ts b/common/web/types/src/kvk/visual-keyboard.ts index c1f1d5d7e9..4965a39b52 100644 --- a/common/web/types/src/kvk/visual-keyboard.ts +++ b/common/web/types/src/kvk/visual-keyboard.ts @@ -26,6 +26,7 @@ export class VisualKeyboardFont { name?: string; size?: number; color?: number; // unused + style?: string; // TODO: figure out style vs color issues }; export { BUILDER_KVK_KEY_FLAGS as VisualKeyboardKeyFlags } from "./kvk-file.js"; diff --git a/common/web/types/src/main.ts b/common/web/types/src/main.ts index 4e77550384..03ea2e8cd6 100644 --- a/common/web/types/src/main.ts +++ b/common/web/types/src/main.ts @@ -7,7 +7,7 @@ export { KmxFileReader } from './kmx/kmx-file-reader.js'; export * as VisualKeyboard from './kvk/visual-keyboard.js'; export { default as KMXPlusBuilder} from './kmx/kmx-plus-builder/kmx-plus-builder.js'; export { default as KvkFileReader } from './kvk/kvk-file-reader.js'; -export { default as KvksFileReader } from './kvk/kvks-file-reader.js'; +export { default as KvksFileReader, KVKSParseError } from './kvk/kvks-file-reader.js'; export { default as KvkFileWriter } from './kvk/kvk-file-writer.js'; export * as KvkFile from './kvk/kvk-file.js'; export * as KvksFile from './kvk/kvk-file.js'; diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index 2f83e83aee..5ca3f9a942 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -31,13 +31,15 @@ export interface CompilerOptions { saveDebug?: boolean; compilerWarningsAsErrors?: boolean; warnDeprecatedCode?: boolean; + target?: 'kmx' | 'js'; }; const baseOptions: CompilerOptions = { shouldAddCompilerVersion: true, saveDebug: true, compilerWarningsAsErrors: false, - warnDeprecatedCode: true + warnDeprecatedCode: true, + target: 'kmx' }; /** @@ -106,7 +108,7 @@ export class KmnCompiler { this.callbacks.reportMessage(CompilerMessages.Fatal_MissingWasmModule({e})); return false; } - } + return this.verifyInitialized(); } @@ -145,6 +147,9 @@ export class KmnCompiler { } private runCompiler(infile: string, outfile: string, options: CompilerOptions): boolean { + const CKF_KEYMAN = 0; + const CKF_KEYMANWEB = 1; + try { if (!this.wasm.setCompilerOptions(options.shouldAddCompilerVersion ? 1 : 0)) { this.callbacks.reportMessage(CompilerMessages.Fatal_UnableToSetCompilerOptions()); @@ -155,7 +160,8 @@ export class KmnCompiler { options.saveDebug ? 1 : 0, options.compilerWarningsAsErrors ? 1 : 0, options.warnDeprecatedCode ? 1 : 0, - this.callbackName); + this.callbackName, + options.target == 'js' ? CKF_KEYMANWEB : CKF_KEYMAN); } catch(e) { this.callbacks.reportMessage(CompilerMessages.Fatal_UnexpectedException({e:e})); return false; diff --git a/developer/src/kmc-kmw/build.sh b/developer/src/kmc-kmw/build.sh index 684f5f7911..be180cc725 100755 --- a/developer/src/kmc-kmw/build.sh +++ b/developer/src/kmc-kmw/build.sh @@ -19,6 +19,7 @@ cd "$THIS_SCRIPT_PATH" builder_describe "Build Keyman kmc KMW Keyboard Compiler module" \ "@/common/web/keyman-version" \ "@/common/web/types" \ + "@/developer/src/kmc-kmn" \ "configure" \ "build" \ "clean" \ diff --git a/developer/src/kmc-kmw/package.json b/developer/src/kmc-kmw/package.json index e00a3c7e31..fc4448b87e 100644 --- a/developer/src/kmc-kmw/package.json +++ b/developer/src/kmc-kmw/package.json @@ -24,6 +24,7 @@ }, "dependencies": { "@keymanapp/common-types": "*", + "@keymanapp/kmc-kmn": "*", "ajv": "^8.11.0", "restructure": "git+https://github.com/keymanapp/dependency-restructure.git#49d129cf0916d082a7278bb09296fb89cecfcc50", "semver": "^7.3.7", @@ -40,8 +41,7 @@ "chalk": "^2.4.2", "mocha": "^8.4.0", "ts-node": "^9.1.1", - "typescript": "^4.9.5", - "@keymanapp/kmc-kmn": "*" + "typescript": "^4.9.5" }, "mocha": { "spec": "build/test/**/test-*.js", diff --git a/developer/src/kmc-kmw/src/compiler/javascript-strings.ts b/developer/src/kmc-kmw/src/compiler/javascript-strings.ts index b4ae08829d..2504781b9b 100644 --- a/developer/src/kmc-kmw/src/compiler/javascript-strings.ts +++ b/developer/src/kmc-kmw/src/compiler/javascript-strings.ts @@ -324,7 +324,7 @@ export function JavaScript_ShiftAsString(fkp: KMX.KEY, FMnemonic: boolean): stri return ' '+FormatModifierAsBitflags(JavaScript_Shift(fkp, FMnemonic)); } -const VKeyNames = [ // from vkeys.h +export const VKeyNames = [ // from vkeys.h // Key Codes "K_?00", // &H0 "K_LBUTTON", // &H1 @@ -671,7 +671,7 @@ function FormatKeyForErrorMessage(fkp: KMX.KEY, FMnemonic: boolean): string { return result; } -function JavaScript_Key(fkp: KMX.KEY, FMnemonic: boolean): number { +export function JavaScript_Key(fkp: KMX.KEY, FMnemonic: boolean): number { let Result: number; if(!FMnemonic) { if(fkp.ShiftFlags & KMX.KMXFile.ISVIRTUALKEY) { diff --git a/developer/src/kmc-kmw/src/compiler/keymanweb-key-codes.ts b/developer/src/kmc-kmw/src/compiler/keymanweb-key-codes.ts new file mode 100644 index 0000000000..98e609d747 --- /dev/null +++ b/developer/src/kmc-kmw/src/compiler/keymanweb-key-codes.ts @@ -0,0 +1,271 @@ +export const + CKeymanWebKeyCodes: number[] = [ + 0xFF, // L"K_?00", // &H0 + 0xFF, // L"K_LBUTTON", // &H1 + 0xFF, // L"K_RBUTTON", // &H2 + 0xFF, // L"K_CANCEL", // &H3 + 0xFF, // L"K_MBUTTON", // &H4 + 0xFF, // L"K_?05", // &H5 + 0xFF, // L"K_?06", // &H6 + 0xFF, // L"K_?07", // &H7 + 0xFF, // L"K_BKSP", // &H8 + 0xFF, // L"K_TAB", // &H9 + 0xFF, // L"K_?0A", // &HA + 0xFF, // L"K_?0B", // &HB + 0xFF, // L"K_KP5", // &HC + 0xFF, // L"K_ENTER", // &HD + 0xFF, // L"K_?0E", // &HE + 0xFF, // L"K_?0F", // &HF + 0xFF, // L"K_SHIFT", // &H10 + 0xFF, // L"K_CONTROL", // &H11 + 0xFF, // L"K_ALT", // &H12 + 0xFF, // L"K_PAUSE", // &H13 + 0xFF, // L"K_CAPS", // &H14 + 0xFF, // L"K_KANJI?15", // &H15 + 0xFF, // L"K_KANJI?16", // &H16 + 0xFF, // L"K_KANJI?17", // &H17 + 0xFF, // L"K_KANJI?18", // &H18 + 0xFF, // L"K_KANJI?19", // &H19 + 0xFF, // L"K_?1A", // &H1A + 0xFF, // L"K_ESC", // &H1B + 0xFF, // L"K_KANJI?1C", // &H1C + 0xFF, // L"K_KANJI?1D", // &H1D + 0xFF, // L"K_KANJI?1E", // &H1E + 0xFF, // L"K_KANJI?1F", // &H1F + 0x40, // L"K_SPACE", // &H20 + 0xFF, // L"K_PGUP", // &H21 + 0xFF, // L"K_PGDN", // &H22 + 0xFF, // L"K_END", // &H23 + 0xFF, // L"K_HOME", // &H24 + 0xFF, // L"K_LEFT", // &H25 + 0xFF, // L"K_UP", // &H26 + 0xFF, // L"K_RIGHT", // &H27 + 0xFF, // L"K_DOWN", // &H28 + 0xFF, // L"K_SEL", // &H29 + 0xFF, // L"K_PRINT", // &H2A + 0xFF, // L"K_EXEC", // &H2B + 0xFF, // L"K_PRTSCN", // &H2C + 0xFF, // L"K_INS", // &H2D + 0xFF, // L"K_DEL", // &H2E + 0xFF, // L"K_HELP", // &H2F + 0x0A, // L"K_0", // &H30 + 0x01, // L"K_1", // &H31 + 0x02, // L"K_2", // &H32 + 0x03, // L"K_3", // &H33 + 0x04, // L"K_4", // &H34 + 0x05, // L"K_5", // &H35 + 0x06, // L"K_6", // &H36 + 0x07, // L"K_7", // &H37 + 0x08, // L"K_8", // &H38 + 0x09, // L"K_9", // &H39 + 0xFF, // L"K_?3A", // &H3A + 0xFF, // L"K_?3B", // &H3B + 0xFF, // L"K_?3C", // &H3C + 0xFF, // L"K_?3D", // &H3D + 0xFF, // L"K_?3E", // &H3E + 0xFF, // L"K_?3F", // &H3F + 0xFF, // L"K_?40", // &H40 + + 0x20, // L"K_A", // &H41 + 0x35, // L"K_B", // &H42 + 0x33, // L"K_C", // &H43 + 0x22, // L"K_D", // &H44 + 0x12, // L"K_E", // &H45 + 0x23, // L"K_F", // &H46 + 0x24, // L"K_G", // &H47 + 0x25, // L"K_H", // &H48 + 0x17, // L"K_I", // &H49 + 0x26, // L"K_J", // &H4A + 0x27, // L"K_K", // &H4B + 0x28, // L"K_L", // &H4C + 0x37, // L"K_M", // &H4D + 0x36, // L"K_N", // &H4E + 0x18, // L"K_O", // &H4F + 0x19, // L"K_P", // &H50 + 0x10, // L"K_Q", // &H51 + 0x13, // L"K_R", // &H52 + 0x21, // L"K_S", // &H53 + 0x14, // L"K_T", // &H54 + 0x16, // L"K_U", // &H55 + 0x34, // L"K_V", // &H56 + 0x11, // L"K_W", // &H57 + 0x32, // L"K_X", // &H58 + 0x15, // L"K_Y", // &H59 + 0x31, // L"K_Z", // &H5A + 0xFF, // L"K_?5B", // &H5B + 0xFF, // L"K_?5C", // &H5C + 0xFF, // L"K_?5D", // &H5D + 0xFF, // L"K_?5E", // &H5E + 0xFF, // L"K_?5F", // &H5F + 0xFF, // L"K_NP0", // &H60 + 0xFF, // L"K_NP1", // &H61 + 0xFF, // L"K_NP2", // &H62 + 0xFF, // L"K_NP3", // &H63 + 0xFF, // L"K_NP4", // &H64 + 0xFF, // L"K_NP5", // &H65 + 0xFF, // L"K_NP6", // &H66 + 0xFF, // L"K_NP7", // &H67 + 0xFF, // L"K_NP8", // &H68 + 0xFF, // L"K_NP9", // &H69 + 0xFF, // L"K_NPSTAR", // &H6A + 0xFF, // L"K_NPPLUS", // &H6B + 0xFF, // L"K_SEPARATOR", // &H6C + 0xFF, // L"K_NPMINUS", // &H6D + 0xFF, // L"K_NPDOT", // &H6E + 0xFF, // L"K_NPSLASH", // &H6F + 0xFF, // L"K_F1", // &H70 + 0xFF, // L"K_F2", // &H71 + 0xFF, // L"K_F3", // &H72 + 0xFF, // L"K_F4", // &H73 + 0xFF, // L"K_F5", // &H74 + 0xFF, // L"K_F6", // &H75 + 0xFF, // L"K_F7", // &H76 + 0xFF, // L"K_F8", // &H77 + 0xFF, // L"K_F9", // &H78 + 0xFF, // L"K_F10", // &H79 + 0xFF, // L"K_F11", // &H7A + 0xFF, // L"K_F12", // &H7B + 0xFF, // L"K_F13", // &H7C + 0xFF, // L"K_F14", // &H7D + 0xFF, // L"K_F15", // &H7E + 0xFF, // L"K_F16", // &H7F + 0xFF, // L"K_F17", // &H80 + 0xFF, // L"K_F18", // &H81 + 0xFF, // L"K_F19", // &H82 + 0xFF, // L"K_F20", // &H83 + 0xFF, // L"K_F21", // &H84 + 0xFF, // L"K_F22", // &H85 + 0xFF, // L"K_F23", // &H86 + 0xFF, // L"K_F24", // &H87 + + 0xFF, // L"K_?88", // &H88 + 0xFF, // L"K_?89", // &H89 + 0xFF, // L"K_?8A", // &H8A + 0xFF, // L"K_?8B", // &H8B + 0xFF, // L"K_?8C", // &H8C + 0xFF, // L"K_?8D", // &H8D + 0xFF, // L"K_?8E", // &H8E + 0xFF, // L"K_?8F", // &H8F + + 0xFF, // L"K_NUMLOCK", // &H90 + 0xFF, // L"K_SCROLL", // &H91 + + 0xFF, // L"K_?92", // &H92 + 0xFF, // L"K_?93", // &H93 + 0xFF, // L"K_?94", // &H94 + 0xFF, // L"K_?95", // &H95 + 0xFF, // L"K_?96", // &H96 + 0xFF, // L"K_?97", // &H97 + 0xFF, // L"K_?98", // &H98 + 0xFF, // L"K_?99", // &H99 + 0xFF, // L"K_?9A", // &H9A + 0xFF, // L"K_?9B", // &H9B + 0xFF, // L"K_?9C", // &H9C + 0xFF, // L"K_?9D", // &H9D + 0xFF, // L"K_?9E", // &H9E + 0xFF, // L"K_?9F", // &H9F + 0xFF, // L"K_?A0", // &HA0 + 0xFF, // L"K_?A1", // &HA1 + 0xFF, // L"K_?A2", // &HA2 + 0xFF, // L"K_?A3", // &HA3 + 0xFF, // L"K_?A4", // &HA4 + 0xFF, // L"K_?A5", // &HA5 + 0xFF, // L"K_?A6", // &HA6 + 0xFF, // L"K_?A7", // &HA7 + 0xFF, // L"K_?A8", // &HA8 + 0xFF, // L"K_?A9", // &HA9 + 0xFF, // L"K_?AA", // &HAA + 0xFF, // L"K_?AB", // &HAB + 0xFF, // L"K_?AC", // &HAC + 0xFF, // L"K_?AD", // &HAD + 0xFF, // L"K_?AE", // &HAE + 0xFF, // L"K_?AF", // &HAF + 0xFF, // L"K_?B0", // &HB0 + 0xFF, // L"K_?B1", // &HB1 + 0xFF, // L"K_?B2", // &HB2 + 0xFF, // L"K_?B3", // &HB3 + 0xFF, // L"K_?B4", // &HB4 + 0xFF, // L"K_?B5", // &HB5 + 0xFF, // L"K_?B6", // &HB6 + 0xFF, // L"K_?B7", // &HB7 + 0xFF, // L"K_?B8", // &HB8 + 0xFF, // L"K_?B9", // &HB9 + + 0x29, // L"K_COLON", // &HBA + 0x0C, // L"K_EQUAL", // &HBB + 0x38, // L"K_COMMA", // &HBC + 0x0B, // L"K_HYPHEN", // &HBD + 0x39, // L"K_PERIOD", // &HBE + 0x3A, // L"K_SLASH", // &HBF + 0x00, // L"K_BKQUOTE", // &HC0 + + 0x00, // L"K_?C1", // &HC1 + 0x00, // L"K_?C2", // &HC2 + 0x00, // L"K_?C3", // &HC3 + 0x00, // L"K_?C4", // &HC4 + 0x00, // L"K_?C5", // &HC5 + 0x00, // L"K_?C6", // &HC6 + 0x00, // L"K_?C7", // &HC7 + 0x00, // L"K_?C8", // &HC8 + 0x00, // L"K_?C9", // &HC9 + 0x00, // L"K_?CA", // &HCA + 0x00, // L"K_?CB", // &HCB + 0x00, // L"K_?CC", // &HCC + 0x00, // L"K_?CD", // &HCD + 0x00, // L"K_?CE", // &HCE + 0x00, // L"K_?CF", // &HCF + 0x00, // L"K_?D0", // &HD0 + 0x00, // L"K_?D1", // &HD1 + 0x00, // L"K_?D2", // &HD2 + 0x00, // L"K_?D3", // &HD3 + 0x00, // L"K_?D4", // &HD4 + 0x00, // L"K_?D5", // &HD5 + 0x00, // L"K_?D6", // &HD6 + 0x00, // L"K_?D7", // &HD7 + 0x00, // L"K_?D8", // &HD8 + 0x00, // L"K_?D9", // &HD9 + 0x00, // L"K_?DA", // &HDA + + 0x1A, // L"K_LBRKT", // &HDB + 0x1C, // L"K_BKSLASH", // &HDC + 0x1B, // L"K_RBRKT", // &HDD + 0x2A, // L"K_QUOTE", // &HDE + 0x00, // L"K_oDF", // &HDF + 0x00, // L"K_oE0", // &HE0 + 0x00, // L"K_oE1", // &HE1 + 0x30, // L"K_oE2", // &HE2 + 0x00, // L"K_oE3", // &HE3 + 0x00, // L"K_oE4", // &HE4 + + 0x00, // L"K_?E5", // &HE5 + + 0x00, // L"K_oE6", // &HE6 + + 0x00, // L"K_?E7", // &HE7 + 0x00, // L"K_?E8", // &HE8 + + 0x00, // L"K_oE9", // &HE9 + 0x00, // L"K_oEA", // &HEA + 0x00, // L"K_oEB", // &HEB + 0x00, // L"K_oEC", // &HEC + 0x00, // L"K_oED", // &HED + 0x00, // L"K_oEE", // &HEE + 0x00, // L"K_oEF", // &HEF + 0x00, // L"K_oF0", // &HF0 + 0x00, // L"K_oF1", // &HF1 + 0x00, // L"K_oF2", // &HF2 + 0x00, // L"K_oF3", // &HF3 + 0x00, // L"K_oF4", // &HF4 + 0x00, // L"K_oF5", // &HF5 + + 0x00, // L"K_?F6", // &HF6 + 0x00, // L"K_?F7", // &HF7 + 0x00, // L"K_?F8", // &HF8 + 0x00, // L"K_?F9", // &HF9 + 0x00, // L"K_?FA", // &HFA + 0x00, // L"K_?FB", // &HFB + 0x00, // L"K_?FC", // &HFC + 0x00, // L"K_?FD", // &HFD + 0x00, // L"K_?FE", // &HFE + 0x00 // L"K_?FF" // &HFF + ]; \ No newline at end of file diff --git a/developer/src/kmc-kmw/src/compiler/validate-layout-file.ts b/developer/src/kmc-kmw/src/compiler/validate-layout-file.ts new file mode 100644 index 0000000000..30d6f660d9 --- /dev/null +++ b/developer/src/kmc-kmw/src/compiler/validate-layout-file.ts @@ -0,0 +1,280 @@ +import { KMX, TouchLayout, TouchLayoutFileReader, TouchLayoutFileWriter } from "@keymanapp/common-types"; +import { callbacks, IsKeyboardVersion14OrLater, IsKeyboardVersion15OrLater } from "./compiler-globals.js"; +import { JavaScript_Key, VKeyNames } from "./javascript-strings.js"; + + +interface VLFOutput { + output: string; + result: boolean; +}; + +function IsValidUnicodeValue(ch: number): boolean { // I4198 + return ((ch >= 0x0020) && (ch <= 0x007F)) || + ((ch >= 0x00A0) && (ch <= 0x10FFFF)); +} + +enum TKeyIdType { Key_Invalid, Key_Constant, Key_Touch, Key_Unicode, Key_Unicode_Multi }; // I4142 + +function GetKeyIdUnicodeType(value: string): TKeyIdType { + let values = value.split('_'); + for(let v of values) { + if(!IsValidUnicodeValue(parseInt(v,16))) { + return TKeyIdType.Key_Invalid; + } + } + if(values.length > 1) { + return TKeyIdType.Key_Unicode_Multi; + } + return TKeyIdType.Key_Unicode; +} + +function KeyIdType(FId: string): TKeyIdType { // I4142 + FId = FId.toUpperCase(); + switch(FId.charAt(0)) { + case 'T': + return TKeyIdType.Key_Touch; + case 'U': + if(FId.startsWith('U_')) { + return GetKeyIdUnicodeType(FId.substring(2)); + } + default: + // Note: can't use indexOf because some VKeyNames are mixed case, e.g. K_oE2 + if(VKeyNames.find(key => key.toUpperCase() == FId)) { + return TKeyIdType.Key_Constant; + } + } + return TKeyIdType.Key_Invalid; +} + +enum TRequiredKey { K_LOPT, K_BKSP, K_ENTER }; // I4447 + +const + CRequiredKeys: TRequiredKey[] = [TRequiredKey.K_LOPT, TRequiredKey.K_BKSP, TRequiredKey.K_ENTER]; // I4447 + + // See also builder.js: specialCharacters; web/source/osk/oskKey.ts: specialCharacters +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*', + + // 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*', + CSpecialText14ZWNJ: string = + '*ZWNJ*\0*ZWNJiOS*\0*ZWNJAndroid*', + + CSpecialText14Map: string[][] = [ + ['*LTREnter*', '*Enter*'], + ['*LTRBkSp*', '*BkSp*'], + ['*RTLEnter*', '*Enter*'], + ['*RTLBkSp*', '*BkSp*'], + ['*ShiftLock*', '*Shift*'], + ['*ShiftedLock*', '*Shifted*'], + ['*ZWNJ*', '<|>'], + ['*ZWNJiOS*', '<|>'], + ['*ZWNJAndroid*', '<|>'] + ]; + +// TODO lifecycle + +function CheckKey(FPlatform: TouchLayout.TouchLayoutPlatform, + FId: string, FText: string, FNextLayer: string, FKeyType: TouchLayout.TouchLayoutKeySp, + FRequiredKeys: TRequiredKey[], FDictionary: string[]) { // I4119 + + // + // Check that each touch layer has K_LOPT, [K_ROPT,] K_BKSP, K_ENTER + // + + for(let key of CRequiredKeys) { + if(TRequiredKey[key].toLowerCase() == FId.toLowerCase()) { + FRequiredKeys.push(key); + break; + } + } + + // + // Check that each layer referenced exists + // + + if(typeof FNextLayer == 'string' && FNextLayer.length > 0) { + if(FPlatform.layer.find(l => l.id.toLowerCase() == FNextLayer.toLowerCase()) == undefined) { + // TODO: callbacks.reportMessage() ReportError(0, CWARN_TouchLayoutMissingLayer, 'Key "'+FId+'" on platform "'+FPlatform.Name+'", layer "'+FLayer.Id+'", platform "'+FPlatform.Name+'", references a missing layer "'+FNextLayer+'".'); + } + } + + // + // Check that the key has a valid id // I4142 + // + + if(FId.trim() == '') { + if(!(FKeyType in [TouchLayout.TouchLayoutKeySp.blank, TouchLayout.TouchLayoutKeySp.spacer]) && FNextLayer == '') { + // TODO: ReportError(0, CWARN_TouchLayoutUnidentifiedKey, 'A key on layer "'+FLayer.Id+'" has no identifier.'); + } + return; + } + + let FValid = KeyIdType(FId); + + if(FValid == TKeyIdType.Key_Invalid) { + // TODO: ReportError(0, CERR_TouchLayoutInvalidIdentifier, 'Key "'+FId+'" on "'+FPlatform.Name+'", layer "'+FLayer.Id+'" has an invalid identifier.'); + } + else if (FValid == TKeyIdType.Key_Unicode_Multi && !IsKeyboardVersion15OrLater()) { + // TODO: ReportError(0, CERR_TouchLayoutInvalidIdentifier, 'Key "'+FId+'" on "'+FPlatform.Name+'", layer "'+FLayer.Id+'" has a multi-part identifier which requires version 15.0 or newer.'); + } + + // + // Check that each custom key code has at least *a* rule associated with it + // + + if (FValid == TKeyIdType.Key_Touch && FNextLayer == '' && FKeyType in [TouchLayout.TouchLayoutKeySp.normal, TouchLayout.TouchLayoutKeySp.deadkey]) { + // Search for the key in the key dictionary - ignore K_LOPT, K_ROPT... + if(FDictionary.indexOf(FId) < 0) { + // TODO: ReportError(0, CWARN_TouchLayoutCustomKeyNotDefined, 'Key "'+FId+'" on layer "'+FLayer.Id+'", platform "'+FPlatform.Name+'", is a custom key but has no corresponding rule in the source.'); + } + } + + // + // Check that if the key has a *special* label, it is available in the target version + // + if(FText.startsWith('*') && FText.endsWith('*') && FText.length > 2) { + // 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) && + !IsKeyboardVersion14OrLater() && + !(FKeyType in [TouchLayout.TouchLayoutKeySp.special, TouchLayout.TouchLayoutKeySp.specialActive])) { + // TODO: ReportError(0, CWARN_TouchLayoutSpecialLabelOnNormalKey, + // Format('Key "%s" on layout "%s", platform "%s" does not have the key type "Special" or "Special (active)" but has the label "%s". This feature is only supported in Keyman 14 or later', [ + // FId, FLayer.Id, FPlatform.Name, FText + // ])); + } + } +} + +function CheckDictionaryKeyValidity(fk: KMX.KEYBOARD, FDictionary: string[]) { // I4142 + + // TODO: O(eeek) performance here + + for(let i = 0; i < FDictionary.length; i++) { + if(FDictionary[i] == '') { + continue; + } + + if(KeyIdType(FDictionary[i]) in [TKeyIdType.Key_Invalid, TKeyIdType.Key_Constant]) { + for(let fgp of fk.groups) { + if(fgp.fUsingKeys) { + for(let fkp of fgp.keys) { + if(JavaScript_Key(fkp, fk.isMnemonic) == i+256) { + // TODO: ReportError(fkp.Line, CERR_InvalidKeyCode, 'Invalid key identifier "'+FDictionary[i]+'"'); + } + } + } + } + } + } +} + +function TransformSpecialKeys14(FDebug: boolean, sLayoutFile: string): string { + // Rewrite Special key labels that are only supported in Keyman 14+ + // This code is a little ugly but effective. + if(!IsKeyboardVersion14OrLater()) { + for(let i = 0; i < CSpecialText14Map.length; i++) { + // Assumes the JSON output format will not change + if(FDebug) { + sLayoutFile = sLayoutFile.replace('"text": "'+CSpecialText14Map[i][0]+'"', '"text": this._v>13 ? "'+CSpecialText14Map[i][0]+'" : "'+CSpecialText14Map[i][1]+'"'); + } else { + sLayoutFile = sLayoutFile.replace('"text":"'+CSpecialText14Map[i][0]+'"', '"text":this._v>13?"'+CSpecialText14Map[i][0]+'":"'+CSpecialText14Map[i][1]+'"'); + } + } + } + return sLayoutFile; +} + +export function ValidateLayoutFile(fk: KMX.KEYBOARD, FDebug: boolean, sLayoutFile: string, sVKDictionary: string): VLFOutput { // I4060 // I4139 + +/* +var + FPlatform: TTouchLayoutPlatform; + FLayer: TTouchLayoutLayer; + FRow: TTouchLayoutRow; + FKey: TTouchLayoutKey; + FSubKey: TTouchLayoutSubKey; + FRequiredKeys: set of TRequiredKey; + FDictionary: TStringList; + FDirection: TTouchLayoutFlickDirection; + +*/ + + let FDictionary: string[] = sVKDictionary.split(/\s+/); + + CheckDictionaryKeyValidity(fk, FDictionary); // I4142 + + let reader = new TouchLayoutFileReader(); + let data = reader.read(callbacks.loadFile(sLayoutFile)); + if(!data) { + // TODO: ReportError(0, CERR_InvalidTouchLayoutFile, sMsg); + return {output:null, result: false}; + } + + let FTouchLayoutFont = ''; // I4872 + let pid: keyof TouchLayout.TouchLayoutFile; + for(pid in data) { + let platform = data[pid]; + + // Test that the font matches on all platforms // I4872 + + if(FTouchLayoutFont == '') { + FTouchLayoutFont = platform.font; + } + else if(platform.font.toLowerCase() != FTouchLayoutFont) { + // TODO: ReportError(0, CWARN_TouchLayoutFontShouldBeSameForAllPlatforms, 'The touch layout font should be the same for all platforms.'); + // TODO: why support multiple font values if it has to be the same across all platforms?! + } + + // Test that all required keys are present + for(let layer of platform.layer) { + let FRequiredKeys: TRequiredKey[] = []; + for(let row of layer.row) { + for(let key of row.key) { + CheckKey(platform, key.id, key.text, key.nextlayer, key.sp, FRequiredKeys, FDictionary); // I4119 + if(key.sk) { + for(let subkey of key.sk) { + CheckKey(platform, subkey.id, subkey.text, subkey.nextlayer, subkey.sp, FRequiredKeys, FDictionary); + } + } + let direction: keyof TouchLayout.TouchLayoutFlick; + if(key.flick) { + for(direction in key.flick) { + CheckKey(platform, key.flick[direction].id, key.flick[direction].text, + key.flick[direction].nextlayer, key.flick[direction].sp, FRequiredKeys, FDictionary); + } + } + + if(key.multitap) { + for(let subkey of key.multitap) { + CheckKey(platform, subkey.id, subkey.text, subkey.nextlayer, subkey.sp, FRequiredKeys, FDictionary); + } + } + } + } + + if(FRequiredKeys.length != CRequiredKeys.length) { + // TODO: ReportError(0, CWARN_TouchLayoutMissingRequiredKeys, 'Layer "'+FLayer.Id+'" on platform "'+FPlatform.Name+'" is missing the required key(s) '+RequiredKeysToString(CRequiredKeys-FRequiredKeys)+'.'); + } + } + } + + // If not debugging, then this strips out formatting for a big saving in file size + // This also normalises any values such as Pad or Width which should be strings + let writer = new TouchLayoutFileWriter({formatted: FDebug}); + + sLayoutFile = writer.compile(data); + + sLayoutFile = TransformSpecialKeys14(FDebug, sLayoutFile); + + return { + output: sLayoutFile, + result: true + } +} \ No newline at end of file diff --git a/developer/src/kmc-kmw/src/compiler/visual-keyboard-compiler.ts b/developer/src/kmc-kmw/src/compiler/visual-keyboard-compiler.ts new file mode 100644 index 0000000000..6dc7cf3178 --- /dev/null +++ b/developer/src/kmc-kmw/src/compiler/visual-keyboard-compiler.ts @@ -0,0 +1,163 @@ +import { KMX, KvkFile, VisualKeyboard } from "@keymanapp/common-types"; +import { FTabStop, nl } from "./compiler-globals.js"; +import { CKeymanWebKeyCodes } from "./keymanweb-key-codes.js"; +import { RequotedString } from "./write-compiled-keyboard.js"; + +interface VKFFResult { + result: string; + displayUnderling: boolean; +} + +export function VisualKeyboardFromFile(visualKeyboard: VisualKeyboard.VisualKeyboard, debug: boolean): VKFFResult { + let fbold = ''; // TODO 'bold ' if visualKeyboard.header.unicodeFont.style + let fitalic = ''; // TODO 'italic ' if visualKeyboard.header.unicodeFont.style + let f102 = visualKeyboard.header.flags & KvkFile.BUILDER_KVK_HEADER_FLAGS.kvkh102 ? '1' : '0'; + + let result = `{F:'${fbold}${fitalic} 1em "${RequotedString(visualKeyboard.header.unicodeFont.name)}"',K102:${f102}}` + + `;` + VisualKeyboardToKLS(visualKeyboard) + + ';' + BuildBKFromKLS(debug); + + return { + result: result, + // TODO: this can go in caller, later + displayUnderling: !!(visualKeyboard.header.flags & KvkFile.BUILDER_KVK_HEADER_FLAGS.kvkhDisplayUnderlying) + } +} + +function WideQuote(s: string): string { + let result = ''; + for(let i = 0; i < s.length; i++) { + if(s[i] == '"' || s[i] == '\\') { + result += '\\' + s[i]; + } else { + result += s[i]; + } + } + return result; +} + +function VkShiftStateToKmxShiftState(ShiftState: number): number { + + interface TVKToKMX { + VK: number; KMX: number; + } + + const Map: TVKToKMX[] = [ + {VK: KvkFile.BUILDER_KVK_SHIFT_STATE.KVKS_SHIFT, KMX: KMX.KMXFile.K_SHIFTFLAG}, + {VK: KvkFile.BUILDER_KVK_SHIFT_STATE.KVKS_CTRL, KMX: KMX.KMXFile.K_CTRLFLAG}, + {VK: KvkFile.BUILDER_KVK_SHIFT_STATE.KVKS_ALT, KMX: KMX.KMXFile.K_ALTFLAG}, + {VK: KvkFile.BUILDER_KVK_SHIFT_STATE.KVKS_LCTRL, KMX: KMX.KMXFile.LCTRLFLAG}, + {VK: KvkFile.BUILDER_KVK_SHIFT_STATE.KVKS_RCTRL, KMX: KMX.KMXFile.RCTRLFLAG}, + {VK: KvkFile.BUILDER_KVK_SHIFT_STATE.KVKS_LALT, KMX: KMX.KMXFile.LALTFLAG}, + {VK: KvkFile.BUILDER_KVK_SHIFT_STATE.KVKS_RALT, KMX: KMX.KMXFile.RALTFLAG} + ]; + + let result = 0; + for(let i = 0; i < Map.length; i++) { + if (ShiftState & Map[i].VK) { + result |= Map[i].KMX; + } + } + + return result; +} + + +function VKShiftToLayerName(shift: number): string { + + const masks: string[] = [ + 'leftctrl', + 'rightctrl', + 'leftalt', + 'rightalt', + 'shift', + 'ctrl', + 'alt' + ]; + + shift = VkShiftStateToKmxShiftState(shift); + if(shift == 0) { + return 'default'; + } + + let result = ''; + for(let i = 0; i < masks.length; i++) { + if(shift & (1 << i)) { + result += masks[i] + '-'; + } + } + return result.substring(0, result.length - 1); +} + + +function VisualKeyboardToKLS(FVK: VisualKeyboard.VisualKeyboard): string { + + interface TLayer { + shift: number; + name: string; + keys: string[]; + }; + + let layers: TLayer[] = []; + + // Discover the layers used in the visual keyboard + for(let key of FVK.keys) { + if(key.flags & KvkFile.BUILDER_KVK_KEY_FLAGS.kvkkUnicode) { + // Find the index of the key in KMW VK arrays + let n = CKeymanWebKeyCodes[key.vkey]; + if(n == 0xFF) { + continue; + } + + let layer = layers.find(layer => layer.shift == key.shift); + if(!layer) { + // 0-64 covers all possible VirtualKeyCodes in CKemyanWebKeyCodes + layer = { shift: key.shift, name: '', keys: new Array(65)}; + layers.push(layer); + } + layer.keys[n] = key.text; + } + } + + // Build the layer array + + let result = nl+FTabStop+'this.KV.KLS={'+nl; + + for(let i = 0; i < layers.length; i++) { + let layer = layers[i]; + result += `${FTabStop}${FTabStop}"${VKShiftToLayerName(layer.shift)}": [`; + for(let j = 0; j < layer.keys.length - 1; j++) { + result += '"'+WideQuote(layer.keys[j] ?? '')+'",'; + } + result += '"'+WideQuote(layer.keys[layer.keys.length-1] ?? '')+'"]'; + if(i < layers.length - 1) { + result += ',' + nl; + } + } + result += nl+FTabStop+'}'; + return result; +} + +function BuildBKFromKLS(debug: boolean): string { + const func = + 'function(x){var e=Array.apply(null,Array(65)).map(String.prototype.valueOf,"")'+ + ',r=[],v,i,m=[\'default\',\'shift\',\'ctrl\',\'shift-ctrl\',\'alt\',\'shift-alt\','+ + '\'ctrl-alt\',\'shift-ctrl-alt\'];for(i=m.length-1;i>=0;i--)if((v=x[m[i]])||r.length)'+ + 'r=(v?v:e).slice().concat(r);return r}'; + const func_debug = + 'function(x){'+nl+ + ' var'+nl+ + ' empty=Array.apply(null, Array(65)).map(String.prototype.valueOf,""),'+nl+ + ' result=[], v, i,'+nl+ + ' modifiers=[\'default\',\'shift\',\'ctrl\',\'shift-ctrl\',\'alt\',\'shift-alt\',\'ctrl-alt\',\'shift-ctrl-alt\'];'+nl+ + ' for(i=modifiers.length-1;i>=0;i--) {'+nl+ + ' v = x[modifiers[i]];'+nl+ + ' if(v || result.length > 0) {'+nl+ + ' result=(v ? v : empty).slice().concat(result);'+nl+ + ' }'+nl+ + ' }'+nl+ + ' return result;'+nl+ + ' }'; + + return nl+FTabStop+'this.KV.BK=('+(debug ? func_debug : func)+')(this.KV.KLS)'; +} diff --git a/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts b/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts index 0175072aeb..7e89aa7cdd 100644 --- a/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts +++ b/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts @@ -1,10 +1,13 @@ -import { KMX, CompilerCallbacks } from "@keymanapp/common-types"; +import { KVKSParseError, VisualKeyboard } from "@keymanapp/common-types"; +import { KMX, CompilerCallbacks, KvkFileReader, KvksFileReader } from "@keymanapp/common-types"; import { ExpandSentinel, incxstr, xstrlen } from "../util/util.js"; // import { KEY, KEYBOARD, KMX.KMXFile, STORE } from "../../../../../common/web/types/src/kmx/kmx.js"; import { options, nl, FTabStop, setupGlobals, IsKeyboardVersion10OrLater } from "./compiler-globals.js"; import CompilerOptions from "./compiler-options.js"; import { JavaScript_ContextMatch, JavaScript_KeyAsString, JavaScript_Name, JavaScript_OutputString, JavaScript_Rules, JavaScript_Shift, JavaScript_ShiftAsString, JavaScript_Store, zeroPadHex } from './javascript-strings.js'; import { CERR_InvalidBegin, CWARN_DontMixChiralAndNonChiralModifiers, ReportError } from "./messages.js"; +import { ValidateLayoutFile } from "./validate-layout-file.js"; +import { VisualKeyboardFromFile } from "./visual-keyboard-compiler.js"; export let FFix183_LadderLength: number = 100; // TODO: option @@ -12,7 +15,7 @@ function requote(s: string): string { return "'" + s.replaceAll(/(['\\])/, "\\$1") + "'"; } -function RequotedString(s: string, RequoteSingleQuotes: boolean = false): string { +export function RequotedString(s: string, RequoteSingleQuotes: boolean = false): string { // TODO: use a JSON encode let i: number = 0; while(i < s.length) { @@ -35,12 +38,12 @@ function RequotedString(s: string, RequoteSingleQuotes: boolean = false): string return s; } -export function WriteCompiledKeyboard(callbacks: CompilerCallbacks, name: string, keyboard: KMX.KEYBOARD, FDebug: boolean = false): string { +export function WriteCompiledKeyboard(callbacks: CompilerCallbacks, kmnfile: string, kmxfile: string, name: string, keyboard: KMX.KEYBOARD, FDebug: boolean = false): string { let opts: CompilerOptions = { addCompilerVersion: false, debug: FDebug }; - setupGlobals(callbacks, opts, FDebug?' ':'', FDebug?'\n':'', keyboard); + setupGlobals(callbacks, opts, FDebug?' ':'', FDebug?'\r\n':'', keyboard); // let fgp: GROUP; @@ -172,26 +175,17 @@ export function WriteCompiledKeyboard(callbacks: CompilerCallbacks, name: string } if (sLayoutFile != '') { // I3483 - // TODO: Load sLayoutFile from file - /*try - with TStringList.Create do - try - LoadFromFile(ExtractFilePath(FInFile) + sLayoutFile, TEncoding.UTF8); - sLayoutFile := Text; - if not ValidateLayoutFile(sLayoutFile, sVKDictionary) then // I4060 - begin - sLayoutFile := ''; - end; - finally - Free; - end; - except - on E:EFOpenError do // I3683 - begin - ReportError(0, CWARN_TouchLayoutFileMissing, E.Message); // I4061 - sLayoutFile := ''; - end; - end;*/ + let path = callbacks.resolveFilename(kmnfile, sLayoutFile); + + let result = ValidateLayoutFile(keyboard, options.debug, path, sVKDictionary); + if(!result.result) { + sLayoutFile = ''; + // TODO: error + // ReportError(0, CWARN_TouchLayoutFileInvalid, 'Touch layout file is not valid'); + } else { + // TODO: reusing the same variable here is ugly + sLayoutFile = result.output; + } } // Default to hide underlying layout characters. This is overridden by touch @@ -200,22 +194,34 @@ export function WriteCompiledKeyboard(callbacks: CompilerCallbacks, name: string let fDisplayUnderlying = false; if (sVisualKeyboard != '') { - //TODO: Load sVisualKeyboard from file - /* - try - // The Keyman .kmx compiler will change the value of this store from a - // .kvks to a .kvk during the build. Earlier in the build, the visual keyboard - // would have been compiled, so we need to account for that and use that file. + // TODO: stop reusing sVisualKeyboard for both filename and content + let path = callbacks.resolveFilename(kmnfile, sVisualKeyboard); + + let kvk: VisualKeyboard.VisualKeyboard; + if(path.match(/\.kvks$/i)) { + let reader = new KvksFileReader(); + let source = reader.read(callbacks.loadFile(path)); + reader.validate(source, callbacks.loadSchema("kvks")); // TODO: handle exceptions + let errors: KVKSParseError[]; + kvk = reader.transform(source, errors); + // TODO: log errors + } + else { + // Note: very old keyboard sources may still have .kvk as an xml + // file, but we'll treat that as an error rather than silently + // falling back to KvksFileReader + let reader = new KvkFileReader(); + kvk = reader.read(callbacks.loadFile(path)); + } - sVisualKeyboard := VisualKeyboardFromFile(ExtractFilePath(FOutFile) + sVisualKeyboard, fDisplayUnderlying); - except - on E:EFOpenError do // I3947 - begin - ReportError(0, CWARN_VisualKeyboardFileMissing, E.Message); // I4061 - sVisualKeyboard := 'null'; - end; - end; - */ + let result = VisualKeyboardFromFile(kvk, options.debug); + if(!result.result) { + // TODO: error + sVisualKeyboard = 'null'; + } + else { + sVisualKeyboard = result.result; + } } else { sVisualKeyboard = 'null'; @@ -236,7 +242,7 @@ export function WriteCompiledKeyboard(callbacks: CompilerCallbacks, name: string // Following line caches the Keyman major version `${FTabStop}this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9;${nl}` + `${FTabStop}this.KI="${sName}";${nl}` + - `${FTabStop}this.KN="${RequotedString(sFullName)}";${nl}`, nl, + `${FTabStop}this.KN="${RequotedString(sFullName)}";${nl}` + `${FTabStop}this.KMINVER="${(keyboard.fileVersion & KMX.KMXFile.VERSION_MASK_MAJOR) >> 8}.${keyboard.fileVersion & KMX.KMXFile.VERSION_MASK_MINOR}";${nl}` + `${FTabStop}this.KV=${sVisualKeyboard};${nl}` + `${FTabStop}this.KDU=${fDisplayUnderlying?'1':'0'};${nl}` + diff --git a/developer/src/kmc-kmw/test/test-compiler-manual.ts b/developer/src/kmc-kmw/test/test-compiler-manual.ts index af2589b833..9f4f5ea4db 100644 --- a/developer/src/kmc-kmw/test/test-compiler-manual.ts +++ b/developer/src/kmc-kmw/test/test-compiler-manual.ts @@ -5,6 +5,7 @@ import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; import { Compiler } from '@keymanapp/kmc-kmn'; import { KMX, KmxFileReader } from '@keymanapp/common-types'; import { WriteCompiledKeyboard } from '../src/compiler/write-compiled-keyboard.js'; +import { extractTouchLayout } from './util.js'; const __dirname = dirname(fileURLToPath(import.meta.url)).replace(/\\/g, '/'); const fixturesDir = __dirname + '/../../test/fixtures/'; @@ -28,7 +29,8 @@ if(!await kmxCompiler.init()) { // TODO: runToMemory, add option to kmxCompiler to store debug-data for conversion to .js (e.g. store metadata, group readonly metadata, etc) if(!kmxCompiler.run(infile, outfile, callbacks, { shouldAddCompilerVersion: false, - saveDebug: true + saveDebug: true, + target: 'js' })) { callbacks.printMessages(); process.exit(1); @@ -37,12 +39,16 @@ if(!kmxCompiler.run(infile, outfile, callbacks, { const reader = new KmxFileReader(); const keyboard: KMX.KEYBOARD = reader.read(callbacks.loadFile(outfile)); -const js = WriteCompiledKeyboard(callbacks, 'khmer_angkor', keyboard, true); +const js = WriteCompiledKeyboard(callbacks, infile, outfile, 'khmer_angkor', keyboard, true); callbacks.printMessages(); const fjs = fs.readFileSync(fixtureName, 'utf8'); -if(fjs !== js) { + +const expected = extractTouchLayout(fjs); +const actual = extractTouchLayout(js); + +if(expected.js !== actual.js) { fs.writeFileSync(testOutfile, js); console.error('JS not equal'); process.exit(1); diff --git a/developer/src/kmc-kmw/test/test-compiler.ts b/developer/src/kmc-kmw/test/test-compiler.ts index 7fb0efd9ce..7332d71bda 100644 --- a/developer/src/kmc-kmw/test/test-compiler.ts +++ b/developer/src/kmc-kmw/test/test-compiler.ts @@ -8,6 +8,7 @@ import fs from 'fs'; import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; import { Compiler } from '@keymanapp/kmc-kmn'; import { KMX, KmxFileReader } from '@keymanapp/common-types'; +import { extractTouchLayout } from './util.js'; const __dirname = dirname(fileURLToPath(import.meta.url)).replace(/\\/g, '/'); const fixturesDir = __dirname + '/../../test/fixtures/'; @@ -37,19 +38,28 @@ describe('Compiler class', function() { const kmxCompiler = new Compiler(); assert.isTrue(await kmxCompiler.init()); - // TODO: runToMemory, add option to kmxCompiler to store debug-data for conversion to .js (e.g. store metadata, group readonly metadata, etc) - assert.isTrue(kmxCompiler.run(infile, outfile, callbacks)); + // TODO: runToMemory, add option to kmxCompiler to store debug-data for conversion to .js (e.g. store metadata, group readonly metadata, visual keyboard source filename, etc) + assert.isTrue(kmxCompiler.run(infile, outfile, callbacks, { + shouldAddCompilerVersion: false, + saveDebug: true, + target: 'js' + })); const reader = new KmxFileReader(); const keyboard: KMX.KEYBOARD = reader.read(callbacks.loadFile(outfile)); - const js = WriteCompiledKeyboard(callbacks, 'khmer_angkor', keyboard, true); - // const js = compiler.compile('khmer_angkor', keyboard); + const js = WriteCompiledKeyboard(callbacks, infile, outfile, 'khmer_angkor', keyboard, true); const fjs = fs.readFileSync(fixtureName, 'utf8'); - if(fjs !== js) { - fs.writeFileSync(testOutfile, js); - assert.fail('JS not equal'); - } + + const expected = extractTouchLayout(fjs); + const actual = extractTouchLayout(js); + + fs.writeFileSync(testOutfile + '.strip.js', actual.js); + fs.writeFileSync(fixtureName + '.strip.js', expected.js); + fs.writeFileSync(testOutfile, js); + + assert.deepEqual(actual.js, expected.js); + assert.deepEqual(JSON.parse(actual.touchLayout), JSON.parse(expected.touchLayout)); }); }); \ No newline at end of file diff --git a/developer/src/kmc-kmw/test/tsconfig.json b/developer/src/kmc-kmw/test/tsconfig.json index abdb3a7cfe..3159c14bfd 100644 --- a/developer/src/kmc-kmw/test/tsconfig.json +++ b/developer/src/kmc-kmw/test/tsconfig.json @@ -14,7 +14,8 @@ }, }, "include": [ - "**/test-*.ts" + "**/test-*.ts", + "util.ts" ], "references": [ { "path": "../../../../common/web/types/" }, diff --git a/developer/src/kmc-kmw/test/util.ts b/developer/src/kmc-kmw/test/util.ts new file mode 100644 index 0000000000..f63e8dd26e --- /dev/null +++ b/developer/src/kmc-kmw/test/util.ts @@ -0,0 +1,19 @@ + +interface ETLResult { + js: string; + touchLayout: string; +} + +export function extractTouchLayout(js: string): ETLResult|null { + let m = /KVKL=(?.+?);[\r\n]/ds.exec(js); + if(!m) { + return null; + } + + let kvkl = (m).indices.groups.kvkl; + + return { + js: js.substring(0, kvkl[0]) + 'null' + js.substring(kvkl[1]), + touchLayout: m.groups?.['kvkl'] ?? '' + }; +} diff --git a/developer/src/kmc-kmw/tsconfig.json b/developer/src/kmc-kmw/tsconfig.json index fb2abd93e3..4fabe4a39d 100644 --- a/developer/src/kmc-kmw/tsconfig.json +++ b/developer/src/kmc-kmw/tsconfig.json @@ -5,21 +5,18 @@ "outDir": "build/src/", "rootDir": "src/", "baseUrl": ".", - "allowSyntheticDefaultImports": true, // for ajv - "paths": { - // "@keymanapp/keyman-version": ["../../../common/web/keyman-version/keyman-version.mts"], "@keymanapp/common-types": ["../../../common/web/types/src/main"], - // "@keymanapp/": ["core/include/ldml/ldml-keyboard-constants"], + "@keymanapp/kmc-kmn": ["../kmc-kmn/src/main"], }, }, "include": [ "src/**/*.ts" -, "src/compiler/__keymanweb-compiler.ts.tmp" ], + ], "references": [ - // { "path": "../../../common/web/keyman-version/tsconfig.esm.json" }, { "path": "../../../common/web/types/" }, + { "path": "../kmc-kmn/" }, { "path": "../../../core/include/ldml/"}, ] } diff --git a/developer/src/kmcmpdll/Compiler.cpp b/developer/src/kmcmpdll/Compiler.cpp index 89defad84d..847a1ff78c 100644 --- a/developer/src/kmcmpdll/Compiler.cpp +++ b/developer/src/kmcmpdll/Compiler.cpp @@ -334,7 +334,7 @@ extern "C" BOOL __declspec(dllexport) CompileKeyboardFileEx(PSTR pszInfile, PSTR if ( flag_use_new_kmcomp ) { - return kmcmp_CompileKeyboardFile(pszInfile, pszOutfile, ASaveDebug, ACompilerWarningsAsErrors,AWarnDeprecatedCode, kmcmpMsgproc, (void*) pMsgProc); + return kmcmp_CompileKeyboardFile(pszInfile, pszOutfile, ASaveDebug, ACompilerWarningsAsErrors,AWarnDeprecatedCode, kmcmpMsgproc, (void*) pMsgProc, Target); } //printf("---> stayed in CompileKeyboardFile() of kmcmpdll\n"); diff --git a/developer/src/kmcmplib/include/kmcmplibapi.h b/developer/src/kmcmplib/include/kmcmplibapi.h index 97d46c3c36..8360dd8ea4 100644 --- a/developer/src/kmcmplib/include/kmcmplibapi.h +++ b/developer/src/kmcmplib/include/kmcmplibapi.h @@ -32,7 +32,8 @@ EXTERN bool kmcmp_CompileKeyboardFile( bool ACompilerWarningsAsErrors, bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, - void* AmsgprocContext + void* AmsgprocContext, + int target // CKF_KEYMAN || CKF_KEYMANWEB ); /* Compile target */ diff --git a/developer/src/kmcmplib/src/Compiler.cpp b/developer/src/kmcmplib/src/Compiler.cpp index 06e707e7ea..48d97120d5 100644 --- a/developer/src/kmcmplib/src/Compiler.cpp +++ b/developer/src/kmcmplib/src/Compiler.cpp @@ -1042,12 +1042,21 @@ KMX_DWORD ProcessSystemStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, PFILE_STORE pp2[4] = 0; } - delete[] sp->dpString; - sp->dpString = q; + if(CompileTarget == CKF_KEYMAN) { + // When we compile to kmx, we want to save this info into + // the .kmx, but for KMW, we need the original source file + // for the KMW compiler process + delete[] sp->dpString; + sp->dpString = q; + } - if ((msg = CheckFilenameConsistency( (sp->dpString), FALSE)) != CERR_None) { + if ((msg = CheckFilenameConsistency(q, FALSE)) != CERR_None) { return msg; } + + if(CompileTarget == CKF_KEYMANWEB) { + delete[] q; + } } break; case TSS_KMW_RTL: diff --git a/developer/src/kmcmplib/src/CompilerInterfaces.cpp b/developer/src/kmcmplib/src/CompilerInterfaces.cpp index 89c4655d16..f684da6e58 100644 --- a/developer/src/kmcmplib/src/CompilerInterfaces.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfaces.cpp @@ -53,7 +53,7 @@ EXTERN bool kmcmp_Wasm_SetCompilerOptions(int ShouldAddCompilerVersion) { EXTERN bool kmcmp_Wasm_CompileKeyboardFile(char* pszInfile, char* pszOutfile, int ASaveDebug, int ACompilerWarningsAsErrors, - int AWarnDeprecatedCode, char* msgProc + int AWarnDeprecatedCode, char* msgProc, int target ) { return kmcmp_CompileKeyboardFile( pszInfile, @@ -62,7 +62,8 @@ EXTERN bool kmcmp_Wasm_CompileKeyboardFile(char* pszInfile, ACompilerWarningsAsErrors, AWarnDeprecatedCode, wasm_CompilerMessageProc, - msgProc + msgProc, + target ); } @@ -78,7 +79,7 @@ EXTERN int kmcmp_Wasm_ParseUnicodeSet(char* pat, EXTERN bool kmcmp_CompileKeyboardFile(char* pszInfile, char* pszOutfile, bool ASaveDebug, bool ACompilerWarningsAsErrors, - bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, void* AmsgprocContext + bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, void* AmsgprocContext, int Target ) { FILE* fp_in = NULL; FILE* fp_out = NULL; @@ -90,7 +91,7 @@ EXTERN bool kmcmp_CompileKeyboardFile(char* pszInfile, kmcmp::FCompilerWarningsAsErrors = ACompilerWarningsAsErrors; // I4865 AWarnDeprecatedCode_GLOBAL_LIB = AWarnDeprecatedCode; - kmcmp::CompileTarget = CKF_KEYMAN; + kmcmp::CompileTarget = Target; if (!pMsgproc || !pszInfile || !pszOutfile) SetError(CERR_BadCallParams); diff --git a/developer/src/kmcmplib/tests/api-test.cpp b/developer/src/kmcmplib/tests/api-test.cpp index 4c46b1f1a4..4c08272d4b 100644 --- a/developer/src/kmcmplib/tests/api-test.cpp +++ b/developer/src/kmcmplib/tests/api-test.cpp @@ -62,7 +62,7 @@ void test_kmcmp_CompileKeyboardFile() { fclose(fp); // It should fail when a zero-byte file is passed in - assert(!kmcmp_CompileKeyboardFile(kmn_file, kmx_file, true, false, true, msgproc, nullptr)); + assert(!kmcmp_CompileKeyboardFile(kmn_file, kmx_file, true, false, true, msgproc, nullptr, CKF_KEYMAN)); assert(error_vec.size() == 1); assert(error_vec[0] == CERR_CannotReadInfile); diff --git a/developer/src/kmcmplib/tests/kmcompxtest.cpp b/developer/src/kmcmplib/tests/kmcompxtest.cpp index 1ce542917d..fc1e23a514 100644 --- a/developer/src/kmcmplib/tests/kmcompxtest.cpp +++ b/developer/src/kmcmplib/tests/kmcompxtest.cpp @@ -78,7 +78,7 @@ int main(int argc, char *argv[]) return __LINE__; } - if(kmcmp_CompileKeyboardFile(kmn_file, kmx_file, true, false, true, msgproc, nullptr)) { + if(kmcmp_CompileKeyboardFile(kmn_file, kmx_file, true, false, true, msgproc, nullptr, CKF_KEYMAN)) { char* testname = strrchr( (char*) kmn_file, '/') + 1; if(strncmp(testname, pfirst5, 5) == 0){ return __LINE__; // exit code: CERR_ in Name + no Error found -- GitLab From d00396467a6c12dde80bb3798d2eeb5555238fe6 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 5 May 2023 10:26:34 +0700 Subject: [PATCH 098/214] chore(developer): add kmc-kmw to npm workspace --- developer/src/kmc-kmw/package-lock.json | 1789 ----------------------- package.json | 1 + tsconfig.esm.json | 4 + 3 files changed, 5 insertions(+), 1789 deletions(-) delete mode 100644 developer/src/kmc-kmw/package-lock.json diff --git a/developer/src/kmc-kmw/package-lock.json b/developer/src/kmc-kmw/package-lock.json deleted file mode 100644 index 1a8b017d98..0000000000 --- a/developer/src/kmc-kmw/package-lock.json +++ /dev/null @@ -1,1789 +0,0 @@ -{ - "name": "@keymanapp/kmc-kmw", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@keymanapp/kmc-kmw", - "license": "MIT", - "dependencies": { - "@keymanapp/keyman-version": "*", - "ajv": "^8.11.0", - "restructure": "git+https://github.com/keymanapp/dependency-restructure.git#49d129cf0916d082a7278bb09296fb89cecfcc50", - "semver": "^7.3.7", - "xml2js": "git+https://github.com/keymanapp/dependency-node-xml2js#535fe732dc408d697e0f847c944cc45f0baf0829" - }, - "devDependencies": { - "@types/chai": "^4.1.7", - "@types/mocha": "^5.2.7", - "@types/node": "^10.14.6", - "@types/semver": "^7.3.12", - "@types/xml2js": "^0.4.5", - "c8": "^7.12.0", - "chai": "^4.3.4", - "chalk": "^2.4.2", - "mocha": "^8.4.0", - "ts-node": "^9.1.1", - "typescript": "^4.9.5" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "node_modules/@keymanapp/keyman-version": { - "version": "16.0.139", - "resolved": "https://registry.npmjs.org/@keymanapp/keyman-version/-/keyman-version-16.0.139.tgz", - "integrity": "sha512-hUCgWq+msSTSxra9xOhSxN/nCPxk/hLnPHHTUnFvIc39uxJ/DjNQGkxtsxTdxjCqWZr7frE/2kT7ob9h5Dh5eQ==" - }, - "node_modules/@types/chai": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", - "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", - "dev": true - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "node_modules/@types/mocha": { - "version": "5.2.7", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "10.17.60", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", - "dev": true - }, - "node_modules/@types/xml2js": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.11.tgz", - "integrity": "sha512-JdigeAKmCyoJUiQljjr7tQG3if9NkqGUgwEUqBvV0N7LM4HyQk7UXCnusRa1lnvXAEYJ8mw8GtZWioagNztOwA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, - "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/c8": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/c8/-/c8-7.13.0.tgz", - "integrity": "sha512-/NL4hQTv1gBL6J6ei80zu3IiTrmePDKXKXOTLpHvcIWZTVYQlDhVWjjWvkhICylE8EwwnMVzDZugCvdx0/DIIA==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@istanbuljs/schema": "^0.1.3", - "find-up": "^5.0.0", - "foreground-child": "^2.0.0", - "istanbul-lib-coverage": "^3.2.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-reports": "^3.1.4", - "rimraf": "^3.0.2", - "test-exclude": "^6.0.0", - "v8-to-istanbul": "^9.0.0", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9" - }, - "bin": { - "c8": "bin/c8.js" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chai": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", - "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", - "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^4.1.2", - "get-func-name": "^2.0.0", - "loupe": "^2.3.1", - "pathval": "^1.1.1", - "type-detect": "^4.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", - "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.1" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", - "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true, - "engines": { - "node": ">=4.x" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/js-yaml": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", - "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-symbols": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/log-symbols/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/log-symbols/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/loupe": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", - "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.0" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mocha": { - "version": "8.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.1", - "debug": "4.3.1", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.6", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.0.0", - "log-symbols": "4.0.0", - "minimatch": "3.0.4", - "ms": "2.1.3", - "nanoid": "3.1.20", - "serialize-javascript": "5.0.1", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.1.0", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" - }, - "engines": { - "node": ">= 10.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/mocha/node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.1.20", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", - "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/restructure": { - "version": "3.0.0", - "resolved": "git+ssh://git@github.com/keymanapp/dependency-restructure.git#49d129cf0916d082a7278bb09296fb89cecfcc50", - "integrity": "sha512-2vBFOLc0+dkUb3Pnpl87o+B4SIc3MAm3P8PXT8YFkP51URFGsgTgm3gAnwTX2jXSEd/5eT9n7C733loG6OaVgw==", - "license": "MIT" - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "node_modules/semver": { - "version": "7.3.7", - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/serialize-javascript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", - "dev": true, - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-node": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", - "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", - "dev": true, - "dependencies": { - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "source-map-support": "^0.5.17", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "typescript": ">=2.7" - } - }, - "node_modules/ts-node/node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/v8-to-istanbul": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", - "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2" - } - }, - "node_modules/workerpool": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", - "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "git+ssh://git@github.com/keymanapp/dependency-node-xml2js.git#535fe732dc408d697e0f847c944cc45f0baf0829", - "integrity": "sha512-5CS+yWxp0qg8zO7ng/iXrBZm2FXgpiJ+RJ3E0LzRxDXChESqzazRwzl8sXYe8/7je/NfwG4EXcClaRKUkcIvtQ==", - "license": "MIT", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/package.json b/package.json index 7a2b53d50d..9b62b5a341 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "core/include/ldml", "developer/src/common/web/test-helpers", "developer/src/kmc-kmn", + "developer/src/kmc-kmw", "developer/src/kmc-ldml", "developer/src/kmc-model", "developer/src/kmc-model-info", diff --git a/tsconfig.esm.json b/tsconfig.esm.json index 44bf4011df..63001931f1 100644 --- a/tsconfig.esm.json +++ b/tsconfig.esm.json @@ -8,10 +8,14 @@ { "path": "./core/include/ldml/tsconfig.json" }, //{ "path": "./developer/src/kmc/test/tsconfig.json" }, + { "path": "./developer/src/common/web/test-helpers/tsconfig.json" }, + { "path": "./developer/src/kmc/tsconfig.json" }, { "path": "./developer/src/kmc-kmn/test/tsconfig.json" }, { "path": "./developer/src/kmc-kmn/tsconfig.json" }, + { "path": "./developer/src/kmc-kmw/test/tsconfig.json" }, + { "path": "./developer/src/kmc-kmw/tsconfig.json" }, { "path": "./developer/src/kmc-ldml/test/tsconfig.json" }, { "path": "./developer/src/kmc-ldml/tsconfig.json" }, { "path": "./developer/src/kmc-model/test/tsconfig.json" }, -- GitLab From c4b8f574cfc16c83efb437fb8113686879922862 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 9 May 2023 10:00:51 +0700 Subject: [PATCH 099/214] chore(developer): add kmc-kmw to kmc deps --- developer/src/kmc/build.sh | 2 ++ developer/src/kmc/package.json | 1 + developer/src/kmc/tsconfig.json | 2 ++ 3 files changed, 5 insertions(+) diff --git a/developer/src/kmc/build.sh b/developer/src/kmc/build.sh index 61ccd3bdca..6b62da5ae9 100755 --- a/developer/src/kmc/build.sh +++ b/developer/src/kmc/build.sh @@ -21,6 +21,7 @@ builder_describe "Build Keyman Keyboard Compiler kmc" \ "@/common/web/keyman-version" \ "@/common/web/types" \ "@/developer/src/kmc-kmn" \ + "@/developer/src/kmc-kmw" \ "@/developer/src/kmc-ldml" \ "@/developer/src/kmc-model" \ "@/developer/src/kmc-model-info" \ @@ -113,6 +114,7 @@ readonly PACKAGES=( common/models/types core/include/ldml developer/src/kmc-kmn + developer/src/kmc-kmw developer/src/kmc-ldml developer/src/kmc-model developer/src/kmc-model-info diff --git a/developer/src/kmc/package.json b/developer/src/kmc/package.json index 695ebc96e3..0c9c2cece2 100644 --- a/developer/src/kmc/package.json +++ b/developer/src/kmc/package.json @@ -40,6 +40,7 @@ "@keymanapp/keyman-version": "*", "@keymanapp/common-types": "*", "@keymanapp/kmc-kmn": "*", + "@keymanapp/kmc-kmw": "*", "@keymanapp/kmc-ldml": "*", "@keymanapp/kmc-model": "*", "@keymanapp/kmc-model-info": "*", diff --git a/developer/src/kmc/tsconfig.json b/developer/src/kmc/tsconfig.json index 9b6eb601ac..777d73e648 100644 --- a/developer/src/kmc/tsconfig.json +++ b/developer/src/kmc/tsconfig.json @@ -8,6 +8,7 @@ "paths": { "@keymanapp/common-types": [ "../../../common/web/types/src/main" ], "@keymanapp/kmc-kmn": [ "../kmc-kmn/src/main" ], + "@keymanapp/kmc-kmw": [ "../kmc-kmw/src/main" ], "@keymanapp/kmc-ldml": [ "../kmc-ldml/src/main" ], "@keymanapp/kmc-model": [ "../kmc-model/src/main" ], "@keymanapp/kmc-model-info": [ "../kmc-model-info/src/model-info-compiler" ], @@ -21,6 +22,7 @@ { "path": "../../../common/web/keyman-version/tsconfig.esm.json" }, { "path": "../../../common/web/types" }, { "path": "../kmc-kmn" }, + { "path": "../kmc-kmw" }, { "path": "../kmc-ldml" }, { "path": "../kmc-model" }, { "path": "../kmc-model-info" }, -- GitLab From ea374aaffd2e6adcc57c7ba8cf47d854c31b3c58 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 9 May 2023 12:03:21 +0700 Subject: [PATCH 100/214] chore(developer): rollback temp kmcomp js build stub --- .../src/tike/compile/CompileKeymanWeb.pas | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/developer/src/tike/compile/CompileKeymanWeb.pas b/developer/src/tike/compile/CompileKeymanWeb.pas index e55966e5c3..13d5219f70 100644 --- a/developer/src/tike/compile/CompileKeymanWeb.pas +++ b/developer/src/tike/compile/CompileKeymanWeb.pas @@ -275,7 +275,6 @@ uses System.TypInfo, CompileErrorCodes, - TempFileManager, JsonUtil, KeymanDeveloperOptions, Keyman.System.KeyboardUtils, @@ -283,7 +282,6 @@ uses kmxfileutils, TouchLayout, Unicode, - utilexecute, utilstr, VisualKeyboard, VKeys; @@ -305,7 +303,6 @@ function TCompileKeymanWeb.Compile(AOwnerProject: TProject; const InFile: string var WarnDeprecatedCode: Boolean; Data: string; - TempOutFile: TTempFile; begin FUnreachableKeys.Clear; @@ -340,40 +337,9 @@ begin WarnDeprecatedCode := True; end; - TempOutFile := TTempFileManager.Get('.kmx'); - GCallbackW := Callback; FCallFunctions := TStringList.Create; try - if CompileKeyboardFileEx(PChar(InFile), PChar(TempOutFile.Name), False, FCompilerWarningsAsErrors, - WarnDeprecatedCode, WebCompilerMessageA, CKF_KEYMANWEB) > 0 then - begin - if Assigned(AOwnerProject) and - Assigned(AOwnerProject.CompilerMessageFile) and - AOwnerProject.CompilerMessageFile.HasCompileWarning and - FCompilerWarningsAsErrors then - FError := True; - - if not FError then - begin - CopyFile(PChar(TempOutFile.Name), PChar(OutFile+'.kmx'), False); - // TODO: convert by calling node kmwc.js - // TODO: add -// TUtilExecute('node.exe kmwc.js "'+TempOutFile.Name+'" "'+OutFile+'"'); - {Data := WriteCompiledKeyboard; - - if not FError then - with TStringStream.Create(Data, TEncoding.UTF8) do - try - SaveToFile(OutFile); - finally - Free; - end;} - end; - - Result := not FError; // I1971 - -{ if CompileKeyboardFileToBuffer(PChar(InFile), @fk, FCompilerWarningsAsErrors, WarnDeprecatedCode, WebCompilerMessageA, CKF_KEYMANWEB) > 0 then // I3482 // I4866 // I4865 @@ -399,7 +365,6 @@ begin end; Result := not FError; // I1971 -} end else begin -- GitLab From eac6651c03bbd0981f05ae5ae476df5ea57cbef0 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 9 May 2023 13:09:55 +0700 Subject: [PATCH 101/214] chore(developer): use older pattern for row id In order to match existing behaviour with the legacy KeymanWeb compiler, we should use quoted numbers for row ids. This behaviour can probably be changed over to the new model in the future, but for now this prevents unit tests from causing us grief. --- developer/src/kmc-ldml/test/fixtures/basic-no-debug.js | 2 +- developer/src/kmc-ldml/test/fixtures/basic.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/developer/src/kmc-ldml/test/fixtures/basic-no-debug.js b/developer/src/kmc-ldml/test/fixtures/basic-no-debug.js index 177d55963e..48317a457a 100644 --- a/developer/src/kmc-ldml/test/fixtures/basic-no-debug.js +++ b/developer/src/kmc-ldml/test/fixtures/basic-no-debug.js @@ -1 +1 @@ -if(typeof keyman === 'undefined') {console.error('Keyboard requires KeymanWeb 16.0 or later');} else {KeymanWeb.KR(new Keyboard_basic());}function Keyboard_basic() {this.KI="Keyboard_basic";this.KN={"value":"TestKbd"};this.KMINVER="16.0";this.KV={F: '10pt "Arial"', K102: 0};this.KV.KLS={TODO_LDML: 2};this.KDU=1;this.KH="";this.KM=0;this.KBVER="1.0.0";this.KMBM=0;this.KVKL={"desktop":{"defaultHint":"none","layer":[{"id":"base","row":[{"id":0,"key":[{"id":"T_hmaqtugha","text":"ħ"},{"id":"T_that","text":"ថា"}]}]}]}};this.gs=function(t,e){return 0;};} \ No newline at end of file +if(typeof keyman === 'undefined') {console.error('Keyboard requires KeymanWeb 16.0 or later');} else {KeymanWeb.KR(new Keyboard_basic());}function Keyboard_basic() {this.KI="Keyboard_basic";this.KN={"value":"TestKbd"};this.KMINVER="16.0";this.KV={F: '10pt "Arial"', K102: 0};this.KV.KLS={TODO_LDML: 2};this.KDU=1;this.KH="";this.KM=0;this.KBVER="1.0.0";this.KMBM=0;this.KVKL={"desktop":{"defaultHint":"none","layer":[{"id":"base","row":[{"id":"0","key":[{"id":"T_hmaqtugha","text":"ħ"},{"id":"T_that","text":"ថា"}]}]}]}};this.gs=function(t,e){return 0;};} \ No newline at end of file diff --git a/developer/src/kmc-ldml/test/fixtures/basic.js b/developer/src/kmc-ldml/test/fixtures/basic.js index 59a1902ee6..179fa0dc06 100644 --- a/developer/src/kmc-ldml/test/fixtures/basic.js +++ b/developer/src/kmc-ldml/test/fixtures/basic.js @@ -24,7 +24,7 @@ function Keyboard_basic() { "id": "base", "row": [ { - "id": 0, + "id": "0", "key": [ { "id": "T_hmaqtugha", -- GitLab From 80e5d650de7ed1cb3f17b9bb1bf8a07b83d1dabe Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 9 May 2023 15:24:35 +0700 Subject: [PATCH 102/214] chore(developer): split CKF_KEYMANWEB for typescript compiler --- developer/src/common/delphi/compiler/compile.pas | 1 + developer/src/kmc-kmn/src/compiler/compiler.ts | 5 +++-- developer/src/kmcmplib/include/kmcmplibapi.h | 5 +++-- developer/src/kmcmplib/src/Compiler.cpp | 16 ++++++++-------- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/developer/src/common/delphi/compiler/compile.pas b/developer/src/common/delphi/compiler/compile.pas index 9ebea18ad2..04470239c5 100644 --- a/developer/src/common/delphi/compiler/compile.pas +++ b/developer/src/common/delphi/compiler/compile.pas @@ -141,6 +141,7 @@ type const CKF_KEYMAN = 0; CKF_KEYMANWEB = 1; + // CKF_KEYMANWEB_MODERN = 2; // used only by Typescript-based compiler const CERR_FATAL = $00008000; diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index 5ca3f9a942..18995796e2 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -148,7 +148,8 @@ export class KmnCompiler { private runCompiler(infile: string, outfile: string, options: CompilerOptions): boolean { const CKF_KEYMAN = 0; - const CKF_KEYMANWEB = 1; + // const CKF_KEYMANWEB = 1; // not used -- legacy compiler only + const CKF_KEYMANWEB_MODERN = 2; try { if (!this.wasm.setCompilerOptions(options.shouldAddCompilerVersion ? 1 : 0)) { @@ -161,7 +162,7 @@ export class KmnCompiler { options.compilerWarningsAsErrors ? 1 : 0, options.warnDeprecatedCode ? 1 : 0, this.callbackName, - options.target == 'js' ? CKF_KEYMANWEB : CKF_KEYMAN); + options.target == 'js' ? CKF_KEYMANWEB_MODERN : CKF_KEYMAN); } catch(e) { this.callbacks.reportMessage(CompilerMessages.Fatal_UnexpectedException({e:e})); return false; diff --git a/developer/src/kmcmplib/include/kmcmplibapi.h b/developer/src/kmcmplib/include/kmcmplibapi.h index 8360dd8ea4..2df44d8b6d 100644 --- a/developer/src/kmcmplib/include/kmcmplibapi.h +++ b/developer/src/kmcmplib/include/kmcmplibapi.h @@ -33,13 +33,14 @@ EXTERN bool kmcmp_CompileKeyboardFile( bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, void* AmsgprocContext, - int target // CKF_KEYMAN || CKF_KEYMANWEB + int target // CKF_KEYMAN || CKF_KEYMANWEB || CKF_KEYMANWEB_MODERN ); /* Compile target */ #define CKF_KEYMAN 0 -#define CKF_KEYMANWEB 1 +#define CKF_KEYMANWEB 1 // For legacy kmcomp compiler, to be deprecated and removed +#define CKF_KEYMANWEB_MODERN 2 // For Typescript kmc-kmw compiler EXTERN bool kmcmp_CompileKeyboardFileToBuffer( char* pszInfile, diff --git a/developer/src/kmcmplib/src/Compiler.cpp b/developer/src/kmcmplib/src/Compiler.cpp index 48d97120d5..4292dd21d9 100644 --- a/developer/src/kmcmplib/src/Compiler.cpp +++ b/developer/src/kmcmplib/src/Compiler.cpp @@ -1042,10 +1042,10 @@ KMX_DWORD ProcessSystemStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, PFILE_STORE pp2[4] = 0; } - if(CompileTarget == CKF_KEYMAN) { - // When we compile to kmx, we want to save this info into - // the .kmx, but for KMW, we need the original source file - // for the KMW compiler process + if(CompileTarget != CKF_KEYMANWEB_MODERN) { + // When we compile to kmx, we want to save this info into the .kmx, and + // for the legacy kmw compiler, but for kmc-kmw, we need the original + // source file for the kmc-kmw compiler process delete[] sp->dpString; sp->dpString = q; } @@ -1054,7 +1054,7 @@ KMX_DWORD ProcessSystemStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, PFILE_STORE return msg; } - if(CompileTarget == CKF_KEYMANWEB) { + if(CompileTarget == CKF_KEYMANWEB_MODERN) { delete[] q; } } @@ -1234,7 +1234,7 @@ KMX_DWORD CheckStatementOffsets(PFILE_KEYBOARD fk, PFILE_GROUP gp, PKMX_WCHAR co // Due to a limitation in earlier versions of KeymanWeb, the minimum version // for context() referring to notany() is 14.0. See #917 for details. - if (kmcmp::CompileTarget == CKF_KEYMANWEB) { + if (kmcmp::CompileTarget != CKF_KEYMAN) { for (q = context, i = 1; *q && i < contextOffset; q = incxstr(q), i++); if (*q == UC_SENTINEL && *(q + 1) == CODE_NOTANY) { VERIFY_KEYBOARD_VERSION(fk, VERSION_140, CERR_140FeatureOnlyContextAndNotAnyWeb); @@ -1687,7 +1687,7 @@ int LineTokenType(PKMX_WCHAR *str) /* Test KeymanWeb, Keyman and KeymanOnly prefixes */ if (kmcmp::CompileTarget == CKF_KEYMAN && lpt == lptKeymanWebOnly) return T_BLANK; - if (kmcmp::CompileTarget == CKF_KEYMANWEB && lpt == lptKeymanOnly) return T_BLANK; + if (kmcmp::CompileTarget != CKF_KEYMAN && lpt == lptKeymanOnly) return T_BLANK; while (iswspace(*p)) p++; @@ -2168,7 +2168,7 @@ KMX_DWORD GetXStringImpl(PKMX_WCHAR tstr, PFILE_KEYBOARD fk, PKMX_WCHAR str, KMX // in the web target platform, even if there are platform() rules excluding this possibility. In that (rare) situation, the keyboard developer should simply specify // the &version to be 9.0 or whatever to avoid this behaviour. if (sFlag & (LCTRLFLAG | LALTFLAG | RCTRLFLAG | RALTFLAG | CAPITALFLAG | NOTCAPITALFLAG | NUMLOCKFLAG | NOTNUMLOCKFLAG | SCROLLFLAG | NOTSCROLLFLAG) && - kmcmp::CompileTarget == CKF_KEYMANWEB && + kmcmp::CompileTarget != CKF_KEYMAN && fk->dwFlags & KF_AUTOMATICVERSION) { VERIFY_KEYBOARD_VERSION(fk, VERSION_100, 0); } -- GitLab From 4416957d2ef8050e2c3fa360befaf8512f5f0283 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 9 May 2023 15:30:27 +0700 Subject: [PATCH 103/214] chore(developer): skip c8 test for kmc-kmw for now --- developer/src/kmc-kmw/build.sh | 1 + developer/src/kmc-kmw/package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/developer/src/kmc-kmw/build.sh b/developer/src/kmc-kmw/build.sh index be180cc725..aa712d10ce 100755 --- a/developer/src/kmc-kmw/build.sh +++ b/developer/src/kmc-kmw/build.sh @@ -61,6 +61,7 @@ fi #------------------------------------------------------------------------------------------------------------------- if builder_start_action test; then + # TODO: add c8 for coverage npm test builder_finish_action success test fi diff --git a/developer/src/kmc-kmw/package.json b/developer/src/kmc-kmw/package.json index fc4448b87e..c1494fb139 100644 --- a/developer/src/kmc-kmw/package.json +++ b/developer/src/kmc-kmw/package.json @@ -14,7 +14,7 @@ "scripts": { "build": "tsc -b", "tsc": "tsc", - "test": "cd test && tsc -b && cd .. && c8 mocha", + "test": "cd test && tsc -b && cd .. && mocha", "prepublishOnly": "npm run build" }, "author": "Marc Durdin (https://github.com/mcdurdin)", -- GitLab From 9a4f8de5e2f0cb645a75b4f47a9e02781009b723 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 11 May 2023 12:52:02 +0700 Subject: [PATCH 104/214] chore(common): npm install --- package-lock.json | 259 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 259 insertions(+) diff --git a/package-lock.json b/package-lock.json index 20d7ce98c4..5b63a9341f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1284,6 +1284,261 @@ "node": ">=0.3.1" } }, + "developer/src/kmc-ldml": { + "license": "MIT", + "dependencies": { + "@keymanapp/keyman-version": "*", + "@keymanapp/ldml-keyboard-constants": "*", + "ajv": "^8.11.0", + "restructure": "git+https://github.com/keymanapp/dependency-restructure.git#49d129cf0916d082a7278bb09296fb89cecfcc50", + "semver": "^7.3.7", + "xml2js": "git+https://github.com/keymanapp/dependency-node-xml2js#535fe732dc408d697e0f847c944cc45f0baf0829" + }, + "devDependencies": { + "@keymanapp/developer-test-helpers": "*", + "@types/chai": "^4.1.7", + "@types/mocha": "^5.2.7", + "@types/node": "^10.14.6", + "@types/semver": "^7.3.12", + "@types/xml2js": "^0.4.5", + "c8": "^7.12.0", + "chai": "^4.3.4", + "chalk": "^2.4.2", + "mocha": "^8.4.0", + "ts-node": "^9.1.1", + "typescript": "^4.9.5" + } + }, + "developer/src/kmc-ldml/node_modules/@types/mocha": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", + "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", + "dev": true + }, + "developer/src/kmc-ldml/node_modules/@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "dev": true + }, + "developer/src/kmc-ldml/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "developer/src/kmc-ldml/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "developer/src/kmc-ldml/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "developer/src/kmc-ldml/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "developer/src/kmc-ldml/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "developer/src/kmc-ldml/node_modules/js-yaml": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "developer/src/kmc-ldml/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "developer/src/kmc-ldml/node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "developer/src/kmc-ldml/node_modules/mocha": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz", + "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==", + "dev": true, + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.1", + "debug": "4.3.1", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.0.0", + "log-symbols": "4.0.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.20", + "serialize-javascript": "5.0.1", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.1.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 10.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "developer/src/kmc-ldml/node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "developer/src/kmc-ldml/node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "developer/src/kmc-ldml/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "developer/src/kmc-ldml/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "developer/src/kmc-ldml/node_modules/supports-color/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "developer/src/kmc-ldml/node_modules/ts-node": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", + "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", + "dev": true, + "dependencies": { + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "typescript": ">=2.7" + } + }, + "developer/src/kmc-ldml/node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "developer/src/kmc-model": { "name": "@keymanapp/kmc-model", "license": "MIT", @@ -2325,6 +2580,10 @@ "resolved": "developer/src/kmc-ldml", "link": true }, + "node_modules/@keymanapp/kmc-ldml": { + "resolved": "developer/src/kmc-ldml", + "link": true + }, "node_modules/@keymanapp/kmc-model": { "resolved": "developer/src/kmc-model", "link": true -- GitLab From 6094457f18dd27c424be8af3bab8f9e1a3a68cf6 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Sun, 14 May 2023 12:49:44 +0700 Subject: [PATCH 105/214] chore: package-lock.json again --- package-lock.json | 50 ++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5b63a9341f..568c70e2b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "core/include/ldml", "developer/src/common/web/test-helpers", "developer/src/kmc-kmn", + "developer/src/kmc-kmw", "developer/src/kmc-ldml", "developer/src/kmc-model", "developer/src/kmc-model-info", @@ -635,6 +636,7 @@ "@keymanapp/common-types": "*", "@keymanapp/keyman-version": "*", "@keymanapp/kmc-kmn": "*", + "@keymanapp/kmc-kmw": "*", "@keymanapp/kmc-ldml": "*", "@keymanapp/kmc-model": "*", "@keymanapp/kmc-model-info": "*", @@ -1029,18 +1031,17 @@ "node": ">=0.3.1" } }, - "developer/src/kmc-ldml": { + "developer/src/kmc-kmw": { "license": "MIT", "dependencies": { - "@keymanapp/keyman-version": "*", - "@keymanapp/ldml-keyboard-constants": "*", + "@keymanapp/common-types": "*", + "@keymanapp/kmc-kmn": "*", "ajv": "^8.11.0", "restructure": "git+https://github.com/keymanapp/dependency-restructure.git#49d129cf0916d082a7278bb09296fb89cecfcc50", "semver": "^7.3.7", "xml2js": "git+https://github.com/keymanapp/dependency-node-xml2js#535fe732dc408d697e0f847c944cc45f0baf0829" }, "devDependencies": { - "@keymanapp/developer-test-helpers": "*", "@types/chai": "^4.1.7", "@types/mocha": "^5.2.7", "@types/node": "^10.14.6", @@ -1054,19 +1055,19 @@ "typescript": "^4.9.5" } }, - "developer/src/kmc-ldml/node_modules/@types/mocha": { + "developer/src/kmc-kmw/node_modules/@types/mocha": { "version": "5.2.7", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", "dev": true }, - "developer/src/kmc-ldml/node_modules/@types/node": { + "developer/src/kmc-kmw/node_modules/@types/node": { "version": "10.17.60", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", "dev": true }, - "developer/src/kmc-ldml/node_modules/ajv": { + "developer/src/kmc-kmw/node_modules/ajv": { "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", @@ -1081,7 +1082,7 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "developer/src/kmc-ldml/node_modules/ansi-styles": { + "developer/src/kmc-kmw/node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", @@ -1093,7 +1094,7 @@ "node": ">=4" } }, - "developer/src/kmc-ldml/node_modules/chalk": { + "developer/src/kmc-kmw/node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", @@ -1107,7 +1108,7 @@ "node": ">=4" } }, - "developer/src/kmc-ldml/node_modules/color-convert": { + "developer/src/kmc-kmw/node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", @@ -1116,13 +1117,13 @@ "color-name": "1.1.3" } }, - "developer/src/kmc-ldml/node_modules/color-name": { + "developer/src/kmc-kmw/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, - "developer/src/kmc-ldml/node_modules/js-yaml": { + "developer/src/kmc-kmw/node_modules/js-yaml": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", @@ -1134,12 +1135,12 @@ "js-yaml": "bin/js-yaml.js" } }, - "developer/src/kmc-ldml/node_modules/json-schema-traverse": { + "developer/src/kmc-kmw/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, - "developer/src/kmc-ldml/node_modules/minimatch": { + "developer/src/kmc-kmw/node_modules/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", @@ -1151,7 +1152,7 @@ "node": "*" } }, - "developer/src/kmc-ldml/node_modules/mocha": { + "developer/src/kmc-kmw/node_modules/mocha": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz", "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==", @@ -1195,7 +1196,7 @@ "url": "https://opencollective.com/mochajs" } }, - "developer/src/kmc-ldml/node_modules/mocha/node_modules/escape-string-regexp": { + "developer/src/kmc-kmw/node_modules/mocha/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", @@ -1207,7 +1208,7 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "developer/src/kmc-ldml/node_modules/mocha/node_modules/supports-color": { + "developer/src/kmc-kmw/node_modules/mocha/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", @@ -1222,13 +1223,13 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "developer/src/kmc-ldml/node_modules/ms": { + "developer/src/kmc-kmw/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "developer/src/kmc-ldml/node_modules/supports-color": { + "developer/src/kmc-kmw/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", @@ -1240,7 +1241,7 @@ "node": ">=4" } }, - "developer/src/kmc-ldml/node_modules/supports-color/node_modules/has-flag": { + "developer/src/kmc-kmw/node_modules/supports-color/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", @@ -1249,7 +1250,7 @@ "node": ">=4" } }, - "developer/src/kmc-ldml/node_modules/ts-node": { + "developer/src/kmc-kmw/node_modules/ts-node": { "version": "9.1.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", @@ -1275,7 +1276,7 @@ "typescript": ">=2.7" } }, - "developer/src/kmc-ldml/node_modules/ts-node/node_modules/diff": { + "developer/src/kmc-kmw/node_modules/ts-node/node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", @@ -1285,6 +1286,7 @@ } }, "developer/src/kmc-ldml": { + "name": "@keymanapp/kmc-ldml", "license": "MIT", "dependencies": { "@keymanapp/keyman-version": "*", @@ -2576,8 +2578,8 @@ "resolved": "developer/src/kmc-kmn", "link": true }, - "node_modules/@keymanapp/kmc-ldml": { - "resolved": "developer/src/kmc-ldml", + "node_modules/@keymanapp/kmc-kmw": { + "resolved": "developer/src/kmc-kmw", "link": true }, "node_modules/@keymanapp/kmc-ldml": { -- GitLab From 9978cb2d502073dfa6b146f223588c7051e791ed Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Sun, 14 May 2023 13:40:11 +0700 Subject: [PATCH 106/214] chore(developer): fix typo --- developer/src/kmc-kmn/src/compiler/compiler.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index 18995796e2..73aad247d1 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -108,6 +108,7 @@ export class KmnCompiler { this.callbacks.reportMessage(CompilerMessages.Fatal_MissingWasmModule({e})); return false; } + } return this.verifyInitialized(); } -- GitLab From 7f1c05cba466e74b13444e045d0705974a0480a0 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Sun, 14 May 2023 17:18:59 +1000 Subject: [PATCH 107/214] chore: rename Error_PackageMustContainAModelOrAKeyboard Co-authored-by: Darcy Wong --- developer/src/kmc-package/src/compiler/messages.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/developer/src/kmc-package/src/compiler/messages.ts b/developer/src/kmc-package/src/compiler/messages.ts index b179aa0ed1..4c62fc1fa1 100644 --- a/developer/src/kmc-package/src/compiler/messages.ts +++ b/developer/src/kmc-package/src/compiler/messages.ts @@ -107,7 +107,7 @@ export class CompilerMessages { `Microsoft Word .doc or .docx files ('${o.filename}') are not portable. You should instead use HTML or PDF format.`); static WARN_DocFileDangerous = SevWarn | 0x0018; - static Error_PackageMustContainAPackageOrAKeyboard = () => m(this.ERROR_PackageMustContainAPackageOrAKeyboard, + static Error_PackageMustContainAModelOrAKeyboard = () => m(this.ERROR_PackageMustContainAModelOrAKeyboard, `Package must contain a lexical model or a keyboard.`); static ERROR_PackageMustContainAPackageOrAKeyboard = SevError | 0x0019; } -- GitLab From 135d6f9c0f94446d36b1f5856e30ba5d92ad371a Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Sun, 14 May 2023 17:23:21 +1000 Subject: [PATCH 108/214] chore(developer): rename misnamed error message --- developer/src/kmc-package/src/compiler/messages.ts | 2 +- .../src/kmc-package/src/compiler/package-validation.ts | 2 +- ...=> error_package_must_contain_a_model_or_a_keyboard.kps} | 4 ++-- developer/src/kmc-package/test/test-package-compiler.ts | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) rename developer/src/kmc-package/test/fixtures/invalid/{error_package_must_contain_a_package_or_a_keyboard.kps => error_package_must_contain_a_model_or_a_keyboard.kps} (74%) diff --git a/developer/src/kmc-package/src/compiler/messages.ts b/developer/src/kmc-package/src/compiler/messages.ts index 4c62fc1fa1..35eb5a8512 100644 --- a/developer/src/kmc-package/src/compiler/messages.ts +++ b/developer/src/kmc-package/src/compiler/messages.ts @@ -109,6 +109,6 @@ export class CompilerMessages { static Error_PackageMustContainAModelOrAKeyboard = () => m(this.ERROR_PackageMustContainAModelOrAKeyboard, `Package must contain a lexical model or a keyboard.`); - static ERROR_PackageMustContainAPackageOrAKeyboard = SevError | 0x0019; + static ERROR_PackageMustContainAModelOrAKeyboard = SevError | 0x0019; } diff --git a/developer/src/kmc-package/src/compiler/package-validation.ts b/developer/src/kmc-package/src/compiler/package-validation.ts index 34bcc184b4..0fd139bb47 100644 --- a/developer/src/kmc-package/src/compiler/package-validation.ts +++ b/developer/src/kmc-package/src/compiler/package-validation.ts @@ -86,7 +86,7 @@ export class PackageValidation { // Note: we require at least 1 keyboard or model in the package. This may // change in the future if we start to use packages to distribute, e.g. // localizations or themes. - this.callbacks.reportMessage(CompilerMessages.Error_PackageMustContainAPackageOrAKeyboard()); + this.callbacks.reportMessage(CompilerMessages.Error_PackageMustContainAModelOrAKeyboard()); return false; } diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_package_must_contain_a_package_or_a_keyboard.kps b/developer/src/kmc-package/test/fixtures/invalid/error_package_must_contain_a_model_or_a_keyboard.kps similarity index 74% rename from developer/src/kmc-package/test/fixtures/invalid/error_package_must_contain_a_package_or_a_keyboard.kps rename to developer/src/kmc-package/test/fixtures/invalid/error_package_must_contain_a_model_or_a_keyboard.kps index cf225de26a..335201a6e5 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/error_package_must_contain_a_package_or_a_keyboard.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/error_package_must_contain_a_model_or_a_keyboard.kps @@ -5,12 +5,12 @@ 7.0 - error_package_must_contain_a_package_or_a_keyboard + error_package_must_contain_a_model_or_a_keyboard 1.3 - khmer_angkor.kmn Keyboard Khmer Angkor diff --git a/developer/src/kmc-package/test/test-package-compiler.ts b/developer/src/kmc-package/test/test-package-compiler.ts index 57a97897ca..e38f78d280 100644 --- a/developer/src/kmc-package/test/test-package-compiler.ts +++ b/developer/src/kmc-package/test/test-package-compiler.ts @@ -320,8 +320,8 @@ describe('KmpCompiler', function () { // ERROR_PackageMustContainAPackageOrAKeyboard - it('should generate ERROR_PackageMustContainAPackageOrAKeyboard if package contains a .doc file', async function() { - testForMessage(this, ['invalid', 'error_package_must_contain_a_package_or_a_keyboard.kps'], - CompilerMessages.ERROR_PackageMustContainAPackageOrAKeyboard); + it('should generate ERROR_PackageMustContainAModelOrAKeyboard if package contains a .doc file', async function() { + testForMessage(this, ['invalid', 'error_package_must_contain_a_model_or_a_keyboard.kps'], + CompilerMessages.ERROR_PackageMustContainAModelOrAKeyboard); }); }); -- GitLab From e7a6d3293d4bb57a33556cae1e753c5bd47c7e03 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Sun, 14 May 2023 16:02:18 +0700 Subject: [PATCH 109/214] refactor(developer): move file write out of WriteCompiledKeyboard Stage one of the kmcmplib filesystem refactoring, as we move to writing to buffers and allowing caller to write to disk. Moves responsibility for writing data out of WriteCompiledKeyboard and into kmcmp_CompileKeyboardFile. This means that there are now no file writes in Compiler.cpp, except for the temp UTF16fromUTF8 (which I will also change to a in-memory buffer "real soon now"). Note that responsibility for writing in kmcmp_CompileKeyboardFile is very much temporary as we'll move it out of the library altogether in a subsequent commit. --- developer/src/kmc-kmn/build.sh | 7 ++++++- developer/src/kmcmplib/src/Compiler.cpp | 16 ++++++---------- .../src/kmcmplib/src/CompilerInterfaces.cpp | 9 ++++++++- developer/src/kmcmplib/src/kmcmplib.h | 2 +- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/developer/src/kmc-kmn/build.sh b/developer/src/kmc-kmn/build.sh index 8c57d71e98..a69dec7646 100755 --- a/developer/src/kmc-kmn/build.sh +++ b/developer/src/kmc-kmn/build.sh @@ -51,11 +51,15 @@ fi #------------------------------------------------------------------------------------------------------------------- -if builder_start_action build; then +function copy_deps() { mkdir -p build/src/import/kmcmplib mkdir -p src/import/kmcmplib cp ../kmcmplib/build/wasm/$BUILDER_CONFIGURATION/src/wasm-host.js ./src/import/kmcmplib/wasm-host.js cp ../kmcmplib/build/wasm/$BUILDER_CONFIGURATION/src/wasm-host.wasm ./build/src/import/kmcmplib/wasm-host.wasm +} + +if builder_start_action build; then + copy_deps tsc --build builder_finish_action success build fi @@ -63,6 +67,7 @@ fi #------------------------------------------------------------------------------------------------------------------- if builder_start_action test; then + copy_deps tsc --build test/ npm run lint c8 --reporter=lcov --reporter=text mocha "${builder_extra_params[@]}" diff --git a/developer/src/kmcmplib/src/Compiler.cpp b/developer/src/kmcmplib/src/Compiler.cpp index 06e707e7ea..7520bd0450 100644 --- a/developer/src/kmcmplib/src/Compiler.cpp +++ b/developer/src/kmcmplib/src/Compiler.cpp @@ -2888,7 +2888,7 @@ KMX_BOOL kmcmp::CheckStoreUsage(PFILE_KEYBOARD fk, int storeIndex, KMX_BOOL fIsS return TRUE; } -KMX_DWORD WriteCompiledKeyboard(PFILE_KEYBOARD fk, FILE* fp_out) +KMX_DWORD WriteCompiledKeyboard(PFILE_KEYBOARD fk, KMX_BYTE**data, size_t& dataSize) { PFILE_GROUP fgp; PFILE_STORE fsp; @@ -2903,6 +2903,9 @@ KMX_DWORD WriteCompiledKeyboard(PFILE_KEYBOARD fk, FILE* fp_out) size_t size; KMX_DWORD i, j; + *data = nullptr; + dataSize = 0; + // Calculate how much memory to allocate size = sizeof(COMP_KEYBOARD) + @@ -3056,15 +3059,8 @@ KMX_DWORD WriteCompiledKeyboard(PFILE_KEYBOARD fk, FILE* fp_out) SetChecksum(buf, &ck->dwCheckSum, (KMX_DWORD)size); - KMX_DWORD dwBytesWritten = 0; - dwBytesWritten = (KMX_DWORD)fwrite(buf,1, (KMX_DWORD)size , fp_out); - - if (dwBytesWritten != size) { - delete[] buf; - return CERR_UnableToWriteFully; - } - - delete[] buf; + *data = buf; + dataSize = size; return CERR_None; } diff --git a/developer/src/kmcmplib/src/CompilerInterfaces.cpp b/developer/src/kmcmplib/src/CompilerInterfaces.cpp index 89c4655d16..0b3d8067d3 100644 --- a/developer/src/kmcmplib/src/CompilerInterfaces.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfaces.cpp @@ -144,9 +144,16 @@ EXTERN bool kmcmp_CompileKeyboardFile(char* pszInfile, bool result = CompileKeyboardHandle(fp_in, &fk); if(result) { KMX_DWORD msg; - if ((msg = WriteCompiledKeyboard(&fk, fp_out)) != CERR_None) { + KMX_BYTE* data = nullptr; + size_t dataSize = 0; + if ((msg = WriteCompiledKeyboard(&fk, &data, dataSize)) != CERR_None) { result = FALSE; AddCompileError(msg); + } else { + if(fwrite(data, 1, dataSize, fp_out) != dataSize) { + AddCompileError(CERR_UnableToWriteFully); + } + delete[] data; } } else { AddCompileError(CERR_InvalidValue); diff --git a/developer/src/kmcmplib/src/kmcmplib.h b/developer/src/kmcmplib/src/kmcmplib.h index a851915de2..b547ecf844 100644 --- a/developer/src/kmcmplib/src/kmcmplib.h +++ b/developer/src/kmcmplib/src/kmcmplib.h @@ -41,7 +41,7 @@ KMX_BOOL AddCompileError(KMX_DWORD msg); PKMX_WCHAR strtowstr(PKMX_STR in); PFILE_STORE FindSystemStore(PFILE_KEYBOARD fk, KMX_DWORD dwSystemID); FILE* UTF16TempFromUTF8(FILE* fp_in , KMX_BOOL hasPreamble); -KMX_DWORD WriteCompiledKeyboard(PFILE_KEYBOARD fk, FILE* fp_out); +KMX_DWORD WriteCompiledKeyboard(PFILE_KEYBOARD fk, KMX_BYTE**data, size_t& dataSize); KMX_DWORD AddStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, KMX_WCHAR const * str, KMX_DWORD *dwStoreID= NULL); KMX_DWORD ReadLine(FILE* fp_in , PKMX_WCHAR wstr, KMX_BOOL PreProcess); KMX_DWORD ParseLine(PFILE_KEYBOARD fk, PKMX_WCHAR str); -- GitLab From ac0cd831f85f44bb324b6721f5cad90754cf4cca Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Sun, 14 May 2023 17:14:51 +0700 Subject: [PATCH 110/214] refactor(developer): CompileKeyboard merge --- .../src/kmcmplib/src/CompilerInterfaces.cpp | 133 +++++++----------- 1 file changed, 48 insertions(+), 85 deletions(-) diff --git a/developer/src/kmcmplib/src/CompilerInterfaces.cpp b/developer/src/kmcmplib/src/CompilerInterfaces.cpp index 0b3d8067d3..8e84e7ff7e 100644 --- a/developer/src/kmcmplib/src/CompilerInterfaces.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfaces.cpp @@ -76,23 +76,22 @@ EXTERN int kmcmp_Wasm_ParseUnicodeSet(char* pat, #endif -EXTERN bool kmcmp_CompileKeyboardFile(char* pszInfile, - char* pszOutfile, bool ASaveDebug, bool ACompilerWarningsAsErrors, - bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, void* AmsgprocContext -) { +bool CompileKeyboard(char* pszInfile, + void* pfkBuffer, bool ASaveDebug, bool ACompilerWarningsAsErrors, + bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, void* AmsgprocContext, + int Target) { + FILE* fp_in = NULL; - FILE* fp_out = NULL; KMX_CHAR str[260]; - //printf("°°-> changed to CompileKeyboardFile() of kmcmplib \n"); - - kmcmp::FSaveDebug = ASaveDebug; + kmcmp::FSaveDebug = ASaveDebug; // I3681 kmcmp::FCompilerWarningsAsErrors = ACompilerWarningsAsErrors; // I4865 AWarnDeprecatedCode_GLOBAL_LIB = AWarnDeprecatedCode; - kmcmp::CompileTarget = CKF_KEYMAN; + kmcmp::CompileTarget = Target; + + if (!pMsgproc || !pszInfile || !pfkBuffer) SetError(CERR_BadCallParams); - if (!pMsgproc || !pszInfile || !pszOutfile) SetError(CERR_BadCallParams); PKMX_STR p; @@ -133,111 +132,75 @@ EXTERN bool kmcmp_CompileKeyboardFile(char* pszInfile, SetError(CERR_CannotCreateTempfile); } - fp_out = Open_File(pszOutfile, "wb"); - - if (fp_out == NULL) { - SetError(CERR_CannotCreateOutfile); - } - - FILE_KEYBOARD fk; kmcmp::CodeConstants = new kmcmp::NamedCodeConstants; - bool result = CompileKeyboardHandle(fp_in, &fk); - if(result) { - KMX_DWORD msg; - KMX_BYTE* data = nullptr; - size_t dataSize = 0; - if ((msg = WriteCompiledKeyboard(&fk, &data, dataSize)) != CERR_None) { - result = FALSE; - AddCompileError(msg); - } else { - if(fwrite(data, 1, dataSize, fp_out) != dataSize) { - AddCompileError(CERR_UnableToWriteFully); - } - delete[] data; - } - } else { - AddCompileError(CERR_InvalidValue); - } + bool result = CompileKeyboardHandle(fp_in, static_cast(pfkBuffer)); + delete kmcmp::CodeConstants; fclose(fp_in); - fclose(fp_out); - delete kmcmp::CodeConstants; - - if (kmcmp::nErrors > 0) - { - remove(pszOutfile); + if (kmcmp::nErrors > 0) { return FALSE; } return result; } - - EXTERN bool kmcmp_CompileKeyboardFileToBuffer(char* pszInfile, void* pfkBuffer, bool ACompilerWarningsAsErrors, bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, void* AmsgprocContext, int Target) // I4865 // I4866 { - //printf("°°-> changed to CompileKeyboardFileToBuffer() of kmcmplib \n"); - FILE* fp_in = NULL; - KMX_CHAR str[260]; - - kmcmp::FSaveDebug = TRUE; // I3681 - kmcmp::FCompilerWarningsAsErrors = ACompilerWarningsAsErrors; // I4865 - AWarnDeprecatedCode_GLOBAL_LIB = AWarnDeprecatedCode; - kmcmp::CompileTarget = Target; - if (!pMsgproc || !pszInfile || !pfkBuffer) { SetError(CERR_BadCallParams); } - PKMX_STR p; + return CompileKeyboard(pszInfile, pfkBuffer, TRUE, ACompilerWarningsAsErrors, AWarnDeprecatedCode, + pMsgproc, AmsgprocContext, Target); +} - if ((p = strrchr_slash(pszInfile)) != nullptr) { - strncpy(kmcmp::CompileDir, pszInfile, (int)(p - pszInfile + 1)); // I3481 - kmcmp::CompileDir[(int)(p - pszInfile + 1)] = 0; - } - else { - kmcmp::CompileDir[0] = 0; +EXTERN bool kmcmp_CompileKeyboardFile(char* pszInfile, + char* pszOutfile, bool ASaveDebug, bool ACompilerWarningsAsErrors, + bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, void* AmsgprocContext) // I4865 // I4866 +{ + if (!pMsgproc || !pszInfile || !pszOutfile) { + SetError(CERR_BadCallParams); } - msgproc = pMsgproc; - msgprocContext = AmsgprocContext; - kmcmp::currentLine = 0; - kmcmp::nErrors = 0; - - fp_in = Open_File(pszInfile,"rb"); - - if (fp_in == NULL) { - SetError(CERR_InfileNotExist); + FILE_KEYBOARD fk; + bool result = CompileKeyboard(pszInfile, &fk, ASaveDebug, ACompilerWarningsAsErrors, AWarnDeprecatedCode, + pMsgproc, AmsgprocContext, CKF_KEYMAN); + if(!result) { + return false; } - // Transfer the file to a memory stream for processing UTF-8 or ANSI to UTF-16? - // What about really large files? Transfer to a temp file... + FILE* fp_out = Open_File(pszOutfile, "wb"); - if( !fread(str,1,3,fp_in)) - { - fclose(fp_in); - SetError(CERR_CannotReadInfile); + if (fp_out == NULL) { + SetError(CERR_CannotCreateOutfile); } - fseek( fp_in,0,SEEK_SET); - if (str[0] == UTF8Sig[0] && str[1] == UTF8Sig[1] && str[2] == UTF8Sig[2]) - fp_in = UTF16TempFromUTF8(fp_in, TRUE); - else if (str[0] == UTF16Sig[0] && str[1] == UTF16Sig[1]) - fseek( fp_in,2,SEEK_SET); - else - fp_in = UTF16TempFromUTF8(fp_in, FALSE); - - kmcmp::CodeConstants = new kmcmp::NamedCodeConstants; + if(result) { + KMX_DWORD msg; + KMX_BYTE* data = nullptr; + size_t dataSize = 0; + if ((msg = WriteCompiledKeyboard(&fk, &data, dataSize)) != CERR_None) { + result = FALSE; + AddCompileError(msg); + } else { + if(fwrite(data, 1, dataSize, fp_out) != dataSize) { + AddCompileError(CERR_UnableToWriteFully); + } + delete[] data; + } + } else { + AddCompileError(CERR_InvalidValue); + } - bool result = CompileKeyboardHandle(fp_in, static_cast(pfkBuffer)); - delete kmcmp::CodeConstants; - fclose(fp_in); + fclose(fp_out); if (kmcmp::nErrors > 0) { + remove(pszOutfile); return FALSE; } + return result; } -- GitLab From 0908f91719aaec2746fcd9b857c73f530ab563ce Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 15 May 2023 10:25:30 +1000 Subject: [PATCH 111/214] chore(windows): restore debug message --- windows/src/engine/keyman32/k32_dbg.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/windows/src/engine/keyman32/k32_dbg.cpp b/windows/src/engine/keyman32/k32_dbg.cpp index 897616a53e..9785bad5d7 100644 --- a/windows/src/engine/keyman32/k32_dbg.cpp +++ b/windows/src/engine/keyman32/k32_dbg.cpp @@ -218,6 +218,16 @@ void DebugMessage(LPMSG msg, WPARAM wParam) // I2908 (unsigned int) msg->lParam, wParam, (int) msg->time, + (unsigned int) GetMessageExtraInfo()); + else if(msg->message >= WM_KEYDOWN && msg->message <= WM_UNICHAR) + wsprintf(ds, "DebugMessage(%x, %s, wParam: '%c' (U+%04X), lParam: %X) [message flags: %x time: %d extra: %x]", + PtrToInt(msg->hwnd), + msgnames[msg->message-WM_KEYDOWN], + msg->wParam, + msg->wParam, + (unsigned int) msg->lParam, + wParam, + (int) msg->time, (unsigned int) GetMessageExtraInfo()); else wsprintf(ds, "%x: %d: wParam: %d, lParam: %X [message flags: %x time: %d]", PtrToInt(msg->hwnd), msg->message, msg->wParam, (unsigned int) msg->lParam, wParam, (int) msg->time); -- GitLab From 603c1d6ea0757d75c8314310768e117e9e003f2f Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 12 May 2023 11:42:57 +0200 Subject: [PATCH 112/214] feat(linux): Add system service to toggle capslock LED This implements the server side. --- docs/settings/linux/tasks.json | 95 ++++++++++++++ linux/.gitignore | 2 +- linux/build.sh | 5 +- linux/keyman-system-service/README.md | 28 ++++ linux/keyman-system-service/build.sh | 73 +++++++++++ linux/keyman-system-service/meson.build | 11 ++ .../resources/com.keyman.SystemService1.conf | 22 ++++ .../com.keyman.SystemService1.service | 7 + .../resources/meson.build | 3 + .../resources/systemd-keyman.service | 51 ++++++++ .../src/KeyboardDevice.cpp | 85 ++++++++++++ .../src/KeyboardDevice.h | 25 ++++ .../src/ServerMethods.cpp | 80 ++++++++++++ .../keyman-system-service/src/ServerMethods.h | 17 +++ .../src/com.keyman.SystemService1.System.xml | 29 +++++ .../keyman-system-service/src/dbus-service.c | 121 ++++++++++++++++++ linux/keyman-system-service/src/meson.build | 17 +++ .../tests/KeyboardDeviceMock.cpp | 45 +++++++ linux/keyman-system-service/tests/README.md | 11 ++ linux/keyman-system-service/tests/meson.build | 27 ++++ .../tests/services/README.md | 5 + .../tests/services/at-spi-dbus-bus.service.in | 3 + .../tests/services/gvfs-daemon.service.in | 3 + .../tests/services/keyman-test.service.in | 5 + .../tests/services/meson.build | 16 +++ 25 files changed, 783 insertions(+), 3 deletions(-) create mode 100644 linux/keyman-system-service/README.md create mode 100755 linux/keyman-system-service/build.sh create mode 100644 linux/keyman-system-service/meson.build create mode 100644 linux/keyman-system-service/resources/com.keyman.SystemService1.conf create mode 100644 linux/keyman-system-service/resources/com.keyman.SystemService1.service create mode 100644 linux/keyman-system-service/resources/meson.build create mode 100644 linux/keyman-system-service/resources/systemd-keyman.service create mode 100644 linux/keyman-system-service/src/KeyboardDevice.cpp create mode 100644 linux/keyman-system-service/src/KeyboardDevice.h create mode 100644 linux/keyman-system-service/src/ServerMethods.cpp create mode 100644 linux/keyman-system-service/src/ServerMethods.h create mode 100644 linux/keyman-system-service/src/com.keyman.SystemService1.System.xml create mode 100644 linux/keyman-system-service/src/dbus-service.c create mode 100644 linux/keyman-system-service/src/meson.build create mode 100644 linux/keyman-system-service/tests/KeyboardDeviceMock.cpp create mode 100644 linux/keyman-system-service/tests/README.md create mode 100644 linux/keyman-system-service/tests/meson.build create mode 100644 linux/keyman-system-service/tests/services/README.md create mode 100644 linux/keyman-system-service/tests/services/at-spi-dbus-bus.service.in create mode 100644 linux/keyman-system-service/tests/services/gvfs-daemon.service.in create mode 100644 linux/keyman-system-service/tests/services/keyman-test.service.in create mode 100644 linux/keyman-system-service/tests/services/meson.build diff --git a/docs/settings/linux/tasks.json b/docs/settings/linux/tasks.json index 77df789fe3..9728cd709e 100644 --- a/docs/settings/linux/tasks.json +++ b/docs/settings/linux/tasks.json @@ -158,5 +158,100 @@ "group": "test", "detail": "unit test keyman-config" }, + { + "type": "shell", + "label": "keyman-system-service: clean", + "command": "${workspaceFolder}/linux/keyman-system-service/build.sh", + "args": [ + "--debug", + "clean" + ], + "options": { + "cwd": "${workspaceFolder}/linux/keyman-system-service" + }, + "group": "build", + "detail": "clean keyman-system-service" + }, + { + "type": "shell", + "label": "keyman-system-service: build", + "command": "${workspaceFolder}/linux/keyman-system-service/build.sh", + "args": [ + "--debug", + "build" + ], + "options": { + "cwd": "${workspaceFolder}/linux/keyman-system-service" + }, + "problemMatcher": [ + { + "owner": "cpp", + "source": "compiler", + "fileLocation": [ + "relative", + "${workspaceFolder}/linux/keyman-system-service/" + ], + "pattern": [ + { + "regexp": "^../../../(.*):(\\d+):(\\d+):\\s+(warning|error|note):\\s+(.*)(\\s+\\[.*\\])?$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + ] + }, + { + "owner": "cpp", + "source": "linker", + "fileLocation": "absolute", + "pattern": [ + { + "regexp": "^(/usr/bin/ld:\\s+)?(.*):(\\d+):\\s+(.*)$", + "file": 2, + "location": 3, + "message": 4 + } + ] + } + ], + "presentation": { + "clear": true + }, + "group": "build", + "detail": "build keyman-system-service" + }, + { + "type": "shell", + "label": "keyman-system-service: configure", + "command": "${workspaceFolder}/linux/keyman-system-service/build.sh", + "args": [ + "--debug", + "configure" + ], + "options": { + "cwd": "${workspaceFolder}/linux/keyman-system-service", + }, + "presentation": { + "clear": true + }, + "group": "build", + "detail": "configure keyman-system-service" + }, + { + "type": "shell", + "label": "keyman-system-service: test", + "command": "${workspaceFolder}/linux/keyman-system-service/build.sh", + "args": [ + "--debug", + "test:arch" + ], + "problemMatcher": [ + "$gcc" + ], + "group": "test", + "detail": "run tests for keyman-system-service" + }, ] } diff --git a/linux/.gitignore b/linux/.gitignore index 478f418b60..0abbd99c58 100644 --- a/linux/.gitignore +++ b/linux/.gitignore @@ -17,7 +17,7 @@ dist/ upload/ launchpad launchpad-* -keyman-config/build +build/ keyman-config/debian/man keyman-config/experiments/*.txt keyman-config/keyman_config/version.py diff --git a/linux/build.sh b/linux/build.sh index 8bdbb368c7..6c7a92069b 100755 --- a/linux/build.sh +++ b/linux/build.sh @@ -14,8 +14,9 @@ cd "$THIS_SCRIPT_PATH" builder_describe \ "Build Keyman for Linux." \ - ":engine=ibus-keyman ibus-keyman" \ - ":config=keyman-config keyman-config" \ + ":config=keyman-config keyman-config" \ + ":engine=ibus-keyman ibus-keyman" \ + ":service=keyman-system-service keyman-system-service" \ "clean" \ "configure" \ "build" \ diff --git a/linux/keyman-system-service/README.md b/linux/keyman-system-service/README.md new file mode 100644 index 0000000000..358004af8f --- /dev/null +++ b/linux/keyman-system-service/README.md @@ -0,0 +1,28 @@ +# keyman-system-service + +A DBus system service that allows to access /dev/input/* devices +to toggle capslock and perform other keyboard related actions when +running under Wayland. + +See , +, +, +. + +## Notes + +- If we need to limit access to the interface to only Keyman, we can use + [polkit](https://www.freedesktop.org/software/polkit/docs/latest/polkit.8.html) + which allows to add a rule with an action that checks for the program. + +- to see the log file + + ```bash + journalctl -f -u systemd-keyman + ``` + +- to monitor method calls + + ```bash + sudo busctl monitor com.keyman.SystemService1 + ``` diff --git a/linux/keyman-system-service/build.sh b/linux/keyman-system-service/build.sh new file mode 100755 index 0000000000..ce62dbcec3 --- /dev/null +++ b/linux/keyman-system-service/build.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash + +## START STANDARD BUILD SCRIPT INCLUDE +# adjust relative paths as necessary +THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" +. "${THIS_SCRIPT%/*}/../../resources/build/build-utils.sh" +## END STANDARD BUILD SCRIPT INCLUDE + +################################ Main script ################################ + +builder_describe \ + "Build keyman-system-service." \ + ":service" \ + "clean" \ + "configure" \ + "build" \ + "test" \ + "install install artifacts" \ + "uninstall uninstall artifacts" + +builder_parse "$@" + +cd "$THIS_SCRIPT_PATH/" + +if builder_has_option --debug; then + MESON_TARGET=debug + export CPPFLAGS=-DG_MESSAGES_DEBUG + export CFLAGS="-O0" + export CXXFLAGS="-O0" +else + MESON_TARGET=release +fi +MESON_PATH="build/$(uname -m)/$MESON_TARGET" + +builder_describe_outputs \ + configure "${MESON_PATH}/build.ninja" \ + build "${MESON_PATH}/src/keyman-system-service" + +if builder_start_action clean; then + rm -rf "$THIS_SCRIPT_PATH/build/" + builder_finish_action success clean +fi + +if builder_start_action configure; then + cd "$THIS_SCRIPT_PATH" + # shellcheck disable=SC2086 + meson setup "$MESON_PATH" --werror --buildtype $MESON_TARGET "${builder_extra_params[@]}" + builder_finish_action success configure +fi + +if builder_start_action build; then + cd "$MESON_PATH" + ninja + builder_finish_action success build +fi + +if builder_start_action test; then + cd "$MESON_PATH" + meson test --print-errorlogs $builder_verbose + builder_finish_action success test +fi + +if builder_start_action install; then + cd "$MESON_PATH" + ninja install + builder_finish_action success install +fi + +if builder_start_action uninstall; then + cd "$MESON_PATH" + ninja uninstall + builder_finish_action success uninstall +fi diff --git a/linux/keyman-system-service/meson.build b/linux/keyman-system-service/meson.build new file mode 100644 index 0000000000..596ba48bcd --- /dev/null +++ b/linux/keyman-system-service/meson.build @@ -0,0 +1,11 @@ +project('keyman-system-service', 'c', 'cpp', + version: run_command('cat', '../../VERSION.md', check: true).stdout().strip(), + license: 'GPL-2+', + meson_version: '>=1.0') + +evdev = dependency('libevdev', version: '>= 1.9') +systemd = dependency('libsystemd') + +subdir('resources') +subdir('src') +subdir('tests') diff --git a/linux/keyman-system-service/resources/com.keyman.SystemService1.conf b/linux/keyman-system-service/resources/com.keyman.SystemService1.conf new file mode 100644 index 0000000000..e2c564a94b --- /dev/null +++ b/linux/keyman-system-service/resources/com.keyman.SystemService1.conf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + diff --git a/linux/keyman-system-service/resources/com.keyman.SystemService1.service b/linux/keyman-system-service/resources/com.keyman.SystemService1.service new file mode 100644 index 0000000000..3966fb1bbc --- /dev/null +++ b/linux/keyman-system-service/resources/com.keyman.SystemService1.service @@ -0,0 +1,7 @@ +# /usr/share/dbus-1/system-services/com.keyman.SystemService1.service + +[D-BUS Service] +Name=com.keyman.SystemService1 +Exec=/bin/false +User=root +SystemdService=systemd-keyman.service diff --git a/linux/keyman-system-service/resources/meson.build b/linux/keyman-system-service/resources/meson.build new file mode 100644 index 0000000000..c28cb81e58 --- /dev/null +++ b/linux/keyman-system-service/resources/meson.build @@ -0,0 +1,3 @@ +install_data('com.keyman.SystemService1.conf', install_dir: get_option('datadir') / 'dbus-1/system.d/') +install_data('com.keyman.SystemService1.service', install_dir: get_option('datadir') / 'dbus-1/system-services/') +install_data('systemd-keyman.service', install_dir: get_option('prefix') / 'lib/systemd/system/') diff --git a/linux/keyman-system-service/resources/systemd-keyman.service b/linux/keyman-system-service/resources/systemd-keyman.service new file mode 100644 index 0000000000..7cb67508a8 --- /dev/null +++ b/linux/keyman-system-service/resources/systemd-keyman.service @@ -0,0 +1,51 @@ +# systemd service file +# /usr/lib/systemd/system/systemd-keyman.service +# See https://stackoverflow.com/a/31725112 + +[Unit] +Description=Keyman System Service + +[Service] +Type=dbus +BusName=com.keyman.SystemService1 +ExecStart=/usr/libexec/keyman-system-service +Restart=on-failure + +# Filesystem lockdown +ProtectSystem=strict +ProtectKernelTunables=true +ProtectControlGroups=true +ReadWritePaths=/dev/input/ +PrivateTmp=true + +# Network +PrivateNetwork=true +IPAddressDeny=any +RestrictAddressFamilies=AF_UNIX + +# Execute Mappings +MemoryDenyWriteExecute=true + +# Modules +ProtectKernelModules=true + +# Real-time +RestrictRealtime=true + +# Privilege escalation +NoNewPrivileges=true + +# Capabilities +CapabilityBoundingSet= + +# System call interfaces +LockPersonality=yes +SystemCallArchitectures=native +SystemCallFilter=@system-service + +# Namespaces +PrivateUsers=yes +RestrictNamespaces=yes + +# Locked memory +LimitMEMLOCK=0 diff --git a/linux/keyman-system-service/src/KeyboardDevice.cpp b/linux/keyman-system-service/src/KeyboardDevice.cpp new file mode 100644 index 0000000000..c93b86f5d3 --- /dev/null +++ b/linux/keyman-system-service/src/KeyboardDevice.cpp @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include +#include +#include "KeyboardDevice.h" + +using namespace std; + +KeyboardDevice::KeyboardDevice() +{ + this->dev = nullptr; + this->fd = -1; + this->hasCapsLockLed = -1; + this->debug = false; +} + +KeyboardDevice::~KeyboardDevice() +{ + libevdev_free(this->dev); + if (this->fd != -1) + close(this->fd); +} + +bool KeyboardDevice::Initialize(const char* name) +{ + string path("/dev/input/"); + path.append(name); + + this->fd = open(path.c_str(), O_RDWR); + if (this->fd < 0) { + std::cerr << "Failed to open device " << path << ": " << strerror(errno) << std::endl; + return false; + } + + int rc = libevdev_new_from_fd(this->fd, &this->dev); + if (rc < 0) { + std::cerr << "Failed to init libevdev for " << path << ": " << strerror(-rc) << std::endl; + close(this->fd); + this->fd = -1; + return false; + } + + return true; +} + +bool KeyboardDevice::HasCapsLockLed() +{ + if (this->hasCapsLockLed < 0) { + if (!libevdev_has_event_code(this->dev, EV_LED, LED_CAPSL)) { + this->hasCapsLockLed = 0; + if (this->debug) { + std::cerr << "Device '" << libevdev_get_name(this->dev) << "' doesn't have " + << libevdev_event_code_get_name(EV_LED, LED_CAPSL) << "." << std::endl; + } + } else { + this->hasCapsLockLed = 1; + } + } + return this->hasCapsLockLed == 1; +} + +void KeyboardDevice::SetCapsLockLed(bool on) +{ + if (!this->HasCapsLockLed()) { + return; + } + + int rc = libevdev_kernel_set_led_value(this->dev, LED_CAPSL, on ? LIBEVDEV_LED_ON : LIBEVDEV_LED_OFF); + if (rc != 0) { + std::cerr << "Failed to set LED " << libevdev_event_code_get_name(EV_LED, LED_CAPSL) + << ": " << strerror(-rc) << std::endl; + } +} + +bool KeyboardDevice::GetCapsLockLed() +{ + if (!this->HasCapsLockLed()) { + return false; + } + + int val = libevdev_get_event_value(this->dev, EV_LED, LED_CAPSL); + return val; +} diff --git a/linux/keyman-system-service/src/KeyboardDevice.h b/linux/keyman-system-service/src/KeyboardDevice.h new file mode 100644 index 0000000000..af9ce119f3 --- /dev/null +++ b/linux/keyman-system-service/src/KeyboardDevice.h @@ -0,0 +1,25 @@ +#ifndef __KEYBOARDDEVICE_H__ +#define __KEYBOARDDEVICE_H__ + +#include + +class KeyboardDevice +{ + public: + KeyboardDevice(); + virtual ~KeyboardDevice(); + + bool Initialize(const char* name); + bool HasCapsLockLed(); + void SetCapsLockLed(bool on); + bool GetCapsLockLed(); + void SetDebug(bool on) { debug = on; } + + private: + struct libevdev *dev; + int fd; + int hasCapsLockLed; + bool debug; +}; + +#endif // __KEYBOARDDEVICE_H__ diff --git a/linux/keyman-system-service/src/ServerMethods.cpp b/linux/keyman-system-service/src/ServerMethods.cpp new file mode 100644 index 0000000000..41e81b0b40 --- /dev/null +++ b/linux/keyman-system-service/src/ServerMethods.cpp @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "KeyboardDevice.h" +#include "ServerMethods.h" + +void * +get_kbd_devices() +{ + std::list* kbd_devices = new std::list(); + + DIR *dirstream; + struct dirent *dir; + dirstream = opendir("/dev/input"); + if (dirstream) { + while ((dir = readdir(dirstream)) != NULL) { + // we're looking for a character device like `event1` + if (dir->d_type == DT_CHR && strncmp(dir->d_name, "event", 5) == 0) { + KeyboardDevice *kbdDevice = new KeyboardDevice(); + if (!kbdDevice->Initialize(dir->d_name) || !kbdDevice->HasCapsLockLed()) { + delete kbdDevice; + continue; + } + kbd_devices->push_back(kbdDevice); + } + } + closedir(dirstream); + } + + return kbd_devices; +} + +void +close_kbd_devices( + void * data +) { + std::list *kbd_devices = static_cast*>(data); + for (KeyboardDevice *device : *kbd_devices) { + delete device; + } + delete kbd_devices; +} + +void +set_caps_lock_indicator_on_devices( + void *data, + void *user_data +) { + std::list *kbd_devices = static_cast*>(data); + uint *state = static_cast(user_data); + for (KeyboardDevice *kbdDevice : *kbd_devices) { + if (!kbdDevice->HasCapsLockLed()) { + syslog(LOG_USER | LOG_NOTICE, "%s: No kbdDevice or no CapsLockLed", __FUNCTION__); + continue; + } + syslog(LOG_USER | LOG_NOTICE, "%s: Caps Lock indicator: %s", __FUNCTION__, (*state != 0 ? "ON" : "OFF")); + kbdDevice->SetCapsLockLed(*state != 0); + } +} + +uint32_t +get_caps_lock_indicator_on_devices( + void *data +) { + std::list *kbd_devices = static_cast*>(data); + bool state = false; + for (KeyboardDevice *kbdDevice : *kbd_devices) { + if (!kbdDevice->HasCapsLockLed()) { + syslog(LOG_USER | LOG_NOTICE, "%s: No kbdDevice or no CapsLockLed", __FUNCTION__); + continue; + } + state |= kbdDevice->GetCapsLockLed(); + } + return state; +} diff --git a/linux/keyman-system-service/src/ServerMethods.h b/linux/keyman-system-service/src/ServerMethods.h new file mode 100644 index 0000000000..e03ec33b0a --- /dev/null +++ b/linux/keyman-system-service/src/ServerMethods.h @@ -0,0 +1,17 @@ +#ifndef __SERVERMETHODS_H__ +#define __SERVERMETHODS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +void* get_kbd_devices(); +void close_kbd_devices(void *data); +void set_caps_lock_indicator_on_devices(void *data, void *user_data); +uint32_t get_caps_lock_indicator_on_devices(void *data); + +#ifdef __cplusplus +} +#endif + +#endif // __SERVERMETHODS_H__ diff --git a/linux/keyman-system-service/src/com.keyman.SystemService1.System.xml b/linux/keyman-system-service/src/com.keyman.SystemService1.System.xml new file mode 100644 index 0000000000..b75a1f2390 --- /dev/null +++ b/linux/keyman-system-service/src/com.keyman.SystemService1.System.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + diff --git a/linux/keyman-system-service/src/dbus-service.c b/linux/keyman-system-service/src/dbus-service.c new file mode 100644 index 0000000000..eafe4da857 --- /dev/null +++ b/linux/keyman-system-service/src/dbus-service.c @@ -0,0 +1,121 @@ +// This file implements a service which will run on the system dbus, +// based on the sd-bus library, see +// https://0pointer.net/blog/the-new-sd-bus-api-of-systemd.html + +#include +#include +#include +#include "ServerMethods.h" + +#define KEYMAN_BUS_NAME "com.keyman.SystemService1" +#define KEYMAN_INTERFACE_NAME "com.keyman.SystemService1.System" +#define KEYMAN_OBJECT_PATH "/com/keyman/SystemService1/System" + +static int32_t +on_set_caps_lock_indicator( + sd_bus_message *msg, + void *user_data, + sd_bus_error *ret_error +) { + int32_t ret; + uint32_t state; + + ret_error = NULL; + + ret = sd_bus_message_read_basic(msg, 'b', &state); + if (ret < 0) { + syslog(LOG_USER | LOG_NOTICE, "Failed to parse parameter: %s", strerror(-ret)); + return ret; + } + + set_caps_lock_indicator_on_devices(user_data, &state); + return sd_bus_reply_method_return(msg, ""); +} + +static int32_t +on_get_caps_lock_indicator( + sd_bus_message *msg, + void *user_data, + sd_bus_error *ret_error +) { + uint32_t state; + + ret_error = NULL; + + state = get_caps_lock_indicator_on_devices(user_data); + return sd_bus_reply_method_return(msg, "b", state); +} + +static const sd_bus_vtable system_service_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_METHOD("SetCapsLockIndicator", "b", "", on_set_caps_lock_indicator, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetCapsLockIndicator", "", "b", on_get_caps_lock_indicator, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_VTABLE_END +}; + +static int finish(int ret, void *kbd_devices, sd_bus_slot *slot, sd_bus *bus) { + close_kbd_devices(kbd_devices); + sd_bus_slot_unref(slot); + sd_bus_unref(bus); + + return ret < 0 ? 1 : 0; +} + +int main(int argc, char *argv[]) { + void *kbd_devices = NULL; + sd_bus_slot *slot = NULL; + sd_bus *bus = NULL; + int ret; + + kbd_devices = get_kbd_devices(); + +#ifdef KEYMAN_TESTING + ret = sd_bus_open_user(&bus); +#else + ret = sd_bus_open_system(&bus); +#endif + + if (ret < 0) { + syslog(LOG_USER | LOG_NOTICE, "Failed to connect to system bus: %s", strerror(-ret)); + return finish(ret, kbd_devices, slot, bus); + } + + // Install the object + ret = sd_bus_add_object_vtable(bus, + &slot, + KEYMAN_OBJECT_PATH, + KEYMAN_INTERFACE_NAME, + system_service_vtable, + kbd_devices); + if (ret < 0) { + syslog(LOG_USER | LOG_NOTICE, "Failed to issue method call: %s", strerror(-ret)); + return finish(ret, kbd_devices, slot, bus); + } + + // Take a well-known service name so that clients can find us + ret = sd_bus_request_name(bus, KEYMAN_BUS_NAME, 0); + if (ret < 0) { + syslog(LOG_USER | LOG_NOTICE, "Failed to acquire service name: %s", strerror(-ret)); + return finish(ret, kbd_devices, slot, bus); + } + + for (;;) { + // Process requests + ret = sd_bus_process(bus, NULL); + if (ret < 0) { + syslog(LOG_USER | LOG_NOTICE, "Failed to process bus: %s", strerror(-ret)); + return finish(ret, kbd_devices, slot, bus); + } + if (ret > 0) // we processed a request, try to process another one, right-away + continue; + + // Wait for the next request to process + ret = sd_bus_wait(bus, (uint64_t) -1); + if (ret < 0) { + syslog(LOG_USER | LOG_NOTICE, "Failed to wait on bus: %s", strerror(-ret)); + return finish(ret, kbd_devices, slot, bus); + } + } + + return finish(0, kbd_devices, slot, bus); +} diff --git a/linux/keyman-system-service/src/meson.build b/linux/keyman-system-service/src/meson.build new file mode 100644 index 0000000000..b5993d0319 --- /dev/null +++ b/linux/keyman-system-service/src/meson.build @@ -0,0 +1,17 @@ +service_files = files( + 'dbus-service.c', + 'KeyboardDevice.cpp', + 'ServerMethods.cpp', +) + +deps = [evdev, systemd] + +exe = executable( + 'keyman-system-service', + sources: [service_files], + dependencies: deps, + install: true, + install_dir: get_option('libexecdir'), +) + +install_data('com.keyman.SystemService1.System.xml', install_dir: get_option('datadir') / 'dbus-1/interfaces') diff --git a/linux/keyman-system-service/tests/KeyboardDeviceMock.cpp b/linux/keyman-system-service/tests/KeyboardDeviceMock.cpp new file mode 100644 index 0000000000..1baa20dcb8 --- /dev/null +++ b/linux/keyman-system-service/tests/KeyboardDeviceMock.cpp @@ -0,0 +1,45 @@ +// A KeyboardDevice mock. +#include +#include +#include +#include +#include +#include + +#ifndef KeyboardDevice +#define KeyboardDevice KeyboardDeviceMock +#endif + +#include "KeyboardDevice.h" + +using namespace std; + +KeyboardDeviceMock::KeyboardDeviceMock() { + this->dev = nullptr; + this->fd = -1; + this->hasCapsLockLed = 1; + this->debug = false; +} + +KeyboardDeviceMock::~KeyboardDeviceMock() { +} + +bool +KeyboardDeviceMock::Initialize(const char* name) { + return true; +} + +bool +KeyboardDeviceMock::HasCapsLockLed() { + return true; +} + +void +KeyboardDeviceMock::SetCapsLockLed(bool on) { + this->hasCapsLockLed = on ? 1 : 0; +} + +bool +KeyboardDeviceMock::GetCapsLockLed() { + return this->hasCapsLockLed == 1; +} diff --git a/linux/keyman-system-service/tests/README.md b/linux/keyman-system-service/tests/README.md new file mode 100644 index 0000000000..af77363b65 --- /dev/null +++ b/linux/keyman-system-service/tests/README.md @@ -0,0 +1,11 @@ +# keyman-system-service tests + +This directory defines a keyman-test-service. This is mostly identical to +keyman-system-service. The differences are: + +- it runs on the session bus instead of system bus +- KeyboardDevice (which in production interacts with evdev) is mocked + so that the tests don't require root permissions. + +The keyman-test-service gets called/used by the ibus-keyman integration +tests. diff --git a/linux/keyman-system-service/tests/meson.build b/linux/keyman-system-service/tests/meson.build new file mode 100644 index 0000000000..3ed97cde13 --- /dev/null +++ b/linux/keyman-system-service/tests/meson.build @@ -0,0 +1,27 @@ +test_service_files = files( + '../src/dbus-service.c', + '../src/ServerMethods.cpp', + 'KeyboardDeviceMock.cpp', +) + +deps = [evdev, systemd] + +test_c_args = [ + '-DKEYMAN_TESTING', + '-DKeyboardDevice=KeyboardDeviceMock' +] + +exe = executable( + 'keyman-test-service', + sources: [test_service_files], + c_args: test_c_args, + cpp_args: test_c_args, + dependencies: deps, + include_directories: [ '../src' ] +) + +# we currently don't have any unit tests for keyman-system-service. +# The keyman-test-service we build here gets used by the ibus-keyman +# integration tests. + +subdir('services') diff --git a/linux/keyman-system-service/tests/services/README.md b/linux/keyman-system-service/tests/services/README.md new file mode 100644 index 0000000000..17c6950c55 --- /dev/null +++ b/linux/keyman-system-service/tests/services/README.md @@ -0,0 +1,5 @@ +# tests/services + +This directory contains the service file for our keyman test service as +well as some additional files for services that are required for things +to properly work in our test environment. diff --git a/linux/keyman-system-service/tests/services/at-spi-dbus-bus.service.in b/linux/keyman-system-service/tests/services/at-spi-dbus-bus.service.in new file mode 100644 index 0000000000..8294093a7f --- /dev/null +++ b/linux/keyman-system-service/tests/services/at-spi-dbus-bus.service.in @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.a11y.Bus +Exec=/usr/libexec/at-spi-bus-launcher diff --git a/linux/keyman-system-service/tests/services/gvfs-daemon.service.in b/linux/keyman-system-service/tests/services/gvfs-daemon.service.in new file mode 100644 index 0000000000..b5357bdda3 --- /dev/null +++ b/linux/keyman-system-service/tests/services/gvfs-daemon.service.in @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.gtk.vfs.Daemon +Exec=/usr/libexec/gvfsd diff --git a/linux/keyman-system-service/tests/services/keyman-test.service.in b/linux/keyman-system-service/tests/services/keyman-test.service.in new file mode 100644 index 0000000000..8946119f23 --- /dev/null +++ b/linux/keyman-system-service/tests/services/keyman-test.service.in @@ -0,0 +1,5 @@ +# Service definition file for keyman-test-service + +[D-BUS Service] +Name=com.keyman.SystemService1 +Exec=@installed_tests_dir@/keyman-test-service diff --git a/linux/keyman-system-service/tests/services/meson.build b/linux/keyman-system-service/tests/services/meson.build new file mode 100644 index 0000000000..e741aa5fbf --- /dev/null +++ b/linux/keyman-system-service/tests/services/meson.build @@ -0,0 +1,16 @@ +dbus_service_files = [ + 'at-spi-dbus-bus.service', + 'gvfs-daemon.service', + 'keyman-test.service', +] + +config_data = configuration_data() +config_data.set('installed_tests_dir', meson.current_build_dir() / '..') + +foreach service_file : dbus_service_files + configure_file( + input: service_file + '.in', + output: service_file, + configuration: config_data, + ) +endforeach -- GitLab From c2e6fe23bdd495769d87811ebe8d8b6de8639464 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 12 May 2023 11:43:04 +0200 Subject: [PATCH 113/214] feat(linux): Client side --- linux/ibus-keyman/meson.build | 8 +- linux/ibus-keyman/src/engine.c | 55 +------ .../src/keyman-system-service-client.c | 90 +++++++++++ .../src/keyman-system-service-client.h | 17 +++ linux/ibus-keyman/src/main.c | 2 + linux/ibus-keyman/src/meson.build | 8 +- linux/ibus-keyman/src/test/meson.build | 2 +- linux/ibus-keyman/tests/km-dbus-test-server.c | 140 ++++++++++++++++++ linux/ibus-keyman/tests/meson.build | 25 +++- linux/ibus-keyman/tests/scripts/run-tests.sh | 118 +++------------ .../ibus-keyman/tests/scripts/setup-tests.sh | 107 +------------ .../tests/scripts/teardown-tests.sh | 8 +- .../ibus-keyman/tests/scripts/test-helper.sh | 133 +++++++++++++++++ linux/ibus-keyman/tests/stop-test-server.c | 34 +++++ linux/ibus-keyman/tests/testfixture.cpp | 93 +----------- 15 files changed, 476 insertions(+), 364 deletions(-) create mode 100644 linux/ibus-keyman/src/keyman-system-service-client.c create mode 100644 linux/ibus-keyman/src/keyman-system-service-client.h create mode 100644 linux/ibus-keyman/tests/km-dbus-test-server.c create mode 100644 linux/ibus-keyman/tests/stop-test-server.c diff --git a/linux/ibus-keyman/meson.build b/linux/ibus-keyman/meson.build index e8548432d4..b7c7c4c596 100644 --- a/linux/ibus-keyman/meson.build +++ b/linux/ibus-keyman/meson.build @@ -9,10 +9,10 @@ project('ibus-keyman', 'c', 'cpp', cc = meson.get_compiler('c') conf = configuration_data() -ibus = dependency('ibus-1.0', version: '>= 1.2.0') -gtk = dependency('gtk+-3.0', version: '>= 2.4') -x11 = dependency('x11', version: '>= 1.6') -json_glib = dependency('json-glib-1.0', version: '>= 1.0') +ibus = dependency('ibus-1.0', version: '>= 1.2.0') +gtk = dependency('gtk+-3.0', version: '>= 2.4') +json_glib = dependency('json-glib-1.0', version: '>= 1.0') +systemd = dependency('libsystemd') core_dir = meson.current_source_dir() / '../../core' common_dir = meson.current_source_dir() / '../../common' diff --git a/linux/ibus-keyman/src/engine.c b/linux/ibus-keyman/src/engine.c index b7699f5562..4934eac470 100644 --- a/linux/ibus-keyman/src/engine.c +++ b/linux/ibus-keyman/src/engine.c @@ -3,7 +3,7 @@ /* * Keyman Input Method for IBUS (The Input Bus) * - * Copyright (C) 2009-2022 SIL International + * Copyright (C) 2009-2023 SIL International * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public @@ -28,21 +28,13 @@ #include #include -#ifdef GDK_WINDOWING_X11 -#include -#include -#endif - -#ifdef GDK_WINDOWING_WAYLAND -#include -#endif - #include #include #include "config.h" #include "keymanutil.h" #include "keyman-service.h" +#include "keyman-system-service-client.h" #include "engine.h" #include "keycodes.h" @@ -90,12 +82,6 @@ struct _IBusKeymanEngine { IBusLookupTable *table; IBusProperty *status_prop; IBusPropList *prop_list; -#ifdef GDK_WINDOWING_X11 - Display *xdisplay; -#endif -#ifdef GDK_WINDOWING_WAYLAND - GdkWaylandDisplay *wldisplay; -#endif commit_queue_item commit_queue[MAX_QUEUE_SIZE]; commit_queue_item *commit_item; @@ -311,29 +297,6 @@ ibus_keyman_engine_init(IBusKeymanEngine *keyman) { ibus_prop_list_append(keyman->prop_list, keyman->status_prop); keyman->state = NULL; -#ifdef GDK_WINDOWING_X11 - keyman->xdisplay = NULL; -#endif -#ifdef GDK_WINDOWING_WAYLAND - keyman->wldisplay = NULL; -#endif - - GdkDisplay *gdkDisplay = gdk_display_get_default(); -#ifdef GDK_WINDOWING_X11 - if (GDK_IS_X11_DISPLAY(gdkDisplay)) { - g_debug("Using X11"); - keyman->xdisplay = GDK_DISPLAY_XDISPLAY(gdkDisplay); - } else -#endif -#ifdef GDK_WINDOWING_WAYLAND - if (GDK_IS_WAYLAND_DISPLAY(gdkDisplay)) { - g_debug("Using Wayland"); - keyman->wldisplay = GDK_WAYLAND_DISPLAY(gdkDisplay); - } else -#endif - { - g_error("unsupported GDK backend"); - } } static km_kbp_cp* get_base_layout() @@ -752,19 +715,7 @@ process_capslock_action( ) { g_message("%s: %s caps-lock", __FUNCTION__, action_item->capsLock ? "Enable" : "Disable"); -#ifdef GDK_WINDOWING_X11 - if (keyman->xdisplay) { - XkbLockModifiers(keyman->xdisplay, XkbUseCoreKbd, LockMask, action_item->capsLock ? LockMask : 0); - - XSync(keyman->xdisplay, False); - } -#endif -#ifdef GDK_WINDOWING_WAYLAND - // TODO - if (keyman->wldisplay) { - - } -#endif + set_capslock_indicator(action_item->capsLock); return TRUE; } diff --git a/linux/ibus-keyman/src/keyman-system-service-client.c b/linux/ibus-keyman/src/keyman-system-service-client.c new file mode 100644 index 0000000000..634521c6d1 --- /dev/null +++ b/linux/ibus-keyman/src/keyman-system-service-client.c @@ -0,0 +1,90 @@ +#include +#include "keyman-system-service-client.h" + +extern gboolean testing; + +#define KEYMAN_BUS_NAME "com.keyman.SystemService1" +#define KEYMAN_INTERFACE_NAME "com.keyman.SystemService1.System" +#define KEYMAN_OBJECT_PATH "/com/keyman/SystemService1/System" + +static void +finish(sd_bus_error* error, sd_bus_message* msg, sd_bus * bus) { + if (error) { sd_bus_error_free(error); } + if (msg) { sd_bus_message_unref(msg); } + if (bus) { sd_bus_unref(bus); } +} + +static int get_bus(sd_bus** bus) { + if (testing) { + return sd_bus_open_user(bus); + } + return sd_bus_default_system(bus); +} + +void set_capslock_indicator( + guint32 capsLock +) { + sd_bus_error error = SD_BUS_ERROR_NULL; + sd_bus_message* msg = NULL; + sd_bus* bus = NULL; + int result; + + if (capsLock > 1) { + g_error("%s: Invalid value '%d' for parameter capsLock", __FUNCTION__, capsLock); + return; + } + + result = get_bus(&bus); + if (result < 0) { + g_error("%s: Can't get connection: %s", __FUNCTION__, strerror(-result)); + finish(&error, msg, bus); + return; + } + + result = sd_bus_call_method( + bus, KEYMAN_BUS_NAME, KEYMAN_OBJECT_PATH, KEYMAN_INTERFACE_NAME, + "SetCapsLockIndicator", &error, &msg, "b", capsLock); + if (result < 0) { + g_error("%s: Failed to call method SetCapsLockIndicator: %s. %s. %s.", + __FUNCTION__, strerror(-result), error.name, error.message); + finish(&error, msg, bus); + return; + } + + finish(&error, msg, bus); +} + +gint32 get_capslock_indicator() { + sd_bus_error error = SD_BUS_ERROR_NULL; + sd_bus_message* msg = NULL; + sd_bus* bus = NULL; + guint32 capsLock = 0; + int result; + + result = get_bus(&bus); + if (result < 0) { + g_error("%s: Can't get connection: %s", __FUNCTION__, strerror(-result)); + finish(&error, msg, bus); + return -1; + } + + result = sd_bus_call_method( + bus, KEYMAN_BUS_NAME, KEYMAN_OBJECT_PATH, KEYMAN_INTERFACE_NAME, + "GetCapsLockIndicator", &error, &msg, ""); + if (result < 0) { + g_error("%s: Failed to call method GetCapsLockIndicator: %s. %s. %s.", + __FUNCTION__, strerror(-result), error.name, error.message); + finish(&error, msg, bus); + return -1; + } + + result = sd_bus_message_read(msg, "b", &capsLock); + if (result < 0) { + g_error("%s: Failed to parse response message: %s", __FUNCTION__, strerror(-result)); + finish(&error, msg, bus); + return -1; + } + + finish(&error, msg, bus); + return capsLock; +} diff --git a/linux/ibus-keyman/src/keyman-system-service-client.h b/linux/ibus-keyman/src/keyman-system-service-client.h new file mode 100644 index 0000000000..0126e5d8db --- /dev/null +++ b/linux/ibus-keyman/src/keyman-system-service-client.h @@ -0,0 +1,17 @@ +#ifndef __KEYMAN_SYSTEM_SERVICE_CLIENT_H__ +#define __KEYMAN_SYSTEM_SERVICE_CLIENT_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void set_capslock_indicator(guint32 capsLockState); +gint32 get_capslock_indicator(); + +#ifdef __cplusplus +} +#endif + +#endif // __KEYMAN_SYSTEM_SERVICE_CLIENT_H__ diff --git a/linux/ibus-keyman/src/main.c b/linux/ibus-keyman/src/main.c index f791cb4564..4252fa93e8 100644 --- a/linux/ibus-keyman/src/main.c +++ b/linux/ibus-keyman/src/main.c @@ -36,12 +36,14 @@ static IBusFactory *factory = NULL; static gboolean xml = FALSE; static gboolean ibus = FALSE; static gboolean verbose = FALSE; +gboolean testing = FALSE; static const GOptionEntry entries[] = { { "xml", 'x', 0, G_OPTION_ARG_NONE, &xml, "generate xml for engines", NULL }, { "ibus", 'i', 0, G_OPTION_ARG_NONE, &ibus, "component is executed by ibus", NULL }, { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "verbose", NULL }, + { "testing", 0, 0, G_OPTION_ARG_NONE, &testing, "component is executed by integration testing", NULL}, { NULL }, }; diff --git a/linux/ibus-keyman/src/meson.build b/linux/ibus-keyman/src/meson.build index 29f265290d..0fe6c75bb7 100644 --- a/linux/ibus-keyman/src/meson.build +++ b/linux/ibus-keyman/src/meson.build @@ -1,17 +1,13 @@ util_files = files( 'keymanutil.c', - 'keymanutil.h', 'kmpdetails.c', - 'kmpdetails.h', ) engine_files = files( 'main.c', 'engine.c', - 'engine.h', - 'keycodes.h', 'keyman-service.c', - 'keyman-service.h', + 'keyman-system-service-client.c', ) include_dirs = [ @@ -20,7 +16,7 @@ include_dirs = [ include_directories(meson.current_build_dir() / '..'), ] -deps = [ibus, gtk, x11, json_glib, kmnkbp_lib] +deps = [ibus, gtk, json_glib, kmnkbp_lib, systemd] prefix = get_option('prefix') cfg = configuration_data() diff --git a/linux/ibus-keyman/src/test/meson.build b/linux/ibus-keyman/src/test/meson.build index c652d8f783..7e5cd21dbe 100644 --- a/linux/ibus-keyman/src/test/meson.build +++ b/linux/ibus-keyman/src/test/meson.build @@ -3,7 +3,7 @@ keymanutil_sources = [ util_files, ] -keymanutil_deps = [ibus, gtk, x11, json_glib, kmnkbp_lib] +keymanutil_deps = [ibus, gtk, json_glib, kmnkbp_lib] test_env = [ 'G_TEST_SRCDIR=' + meson.current_source_dir(), diff --git a/linux/ibus-keyman/tests/km-dbus-test-server.c b/linux/ibus-keyman/tests/km-dbus-test-server.c new file mode 100644 index 0000000000..086071988c --- /dev/null +++ b/linux/ibus-keyman/tests/km-dbus-test-server.c @@ -0,0 +1,140 @@ +// DBus test server. The server will start and listen on a +#include +#include + +#ifndef KEYMAN_TEST_SERVICE_PATH +#warning KEYMAN_TEST_SERVICE_PATH is undefined +#define KEYMAN_TEST_SERVICE_PATH "." +#endif + +#define KEYMAN_TESTSVC_BUS_NAME "com.keyman.ExitTestService" +#define KEYMAN_TESTSVC_INTERFACE_NAME "com.keyman.ExitTestService.Exit" +#define KEYMAN_TESTSVC_OBJECT_PATH "/com/keyman/ExitTestService/Exit" + +static GTestDBus * +startup() { + GTestDBus *dbus = g_test_dbus_new(G_TEST_DBUS_NONE); + + // Add the private directory with our in-tree service files. + g_test_dbus_add_service_dir(dbus, KEYMAN_TEST_SERVICE_PATH); + + printf("Add service dir to %s\n", KEYMAN_TEST_SERVICE_PATH); + + // Start the private D-Bus daemon + g_test_dbus_up(dbus); + + const gchar *address = g_test_dbus_get_bus_address(dbus); + + printf("Test server running on: %s\n", address); + FILE *f = fopen("/tmp/km-test-server.env", "w"); + if (f) { + // write the address to a file which can be sourced + fprintf(f, "export DBUS_SESSION_BUS_ADDRESS=%s\n", address); + fclose(f); + } + + return dbus; +} + +static void +finish(GTestDBus *dbus) { + // Stop the private D-Bus daemon + g_test_dbus_down(dbus); + g_object_unref(dbus); +} + +static int32_t +on_exit_method(sd_bus_message *msg, void *user_data, sd_bus_error *ret_error) { + g_debug("%s called", __FUNCTION__); + guint *exitFlag = (guint *)user_data; + *exitFlag = TRUE; + + return sd_bus_reply_method_return(msg, ""); +} + +static const sd_bus_vtable exit_test_service_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_METHOD("Exit", "", "", on_exit_method, 0), + SD_BUS_VTABLE_END +}; + +static const void exit_loop(sd_bus_slot *slot, sd_bus *bus) { + sd_bus_release_name(bus, KEYMAN_TESTSVC_BUS_NAME); + sd_bus_slot_unref(slot); + sd_bus_close_unref(bus); +} + +static void +loop() { + sd_bus_slot *slot = NULL; + sd_bus *bus = NULL; + int ret; + + ret = sd_bus_open_user(&bus); + + if (ret < 0) { + g_error("Failed to connect to system bus: %s", strerror(-ret)); + return; + } + + guint exitFlag = FALSE; + + // Install the object + ret = sd_bus_add_object_vtable(bus, &slot, KEYMAN_TESTSVC_OBJECT_PATH, + KEYMAN_TESTSVC_INTERFACE_NAME, exit_test_service_vtable, &exitFlag); + if (ret < 0) { + g_error("Failed to issue method call: %s", strerror(-ret)); + exit_loop(slot, bus); + return; + } + + // Take a well-known service name so that clients can find us + ret = sd_bus_request_name(bus, KEYMAN_TESTSVC_BUS_NAME, 0); + if (ret < 0) { + g_error("Failed to acquire service name: %s", strerror(-ret)); + exit_loop(slot, bus); + return; + } + + for (;;) { + // Process requests + ret = sd_bus_process(bus, NULL); + g_debug("sd_bus_process returned %d, exitFlag=%d", ret, exitFlag); + if (ret < 0) { + g_error("Failed to process bus: %s", strerror(-ret)); + exit_loop(slot, bus); + return; + } + if (exitFlag) { + g_debug("Exiting loop"); + exit_loop(slot, bus); + return; + } + + if (ret > 0) // we processed a request, try to process another one, right-away + continue; + + // Wait for the next request to process + ret = sd_bus_wait(bus, (uint64_t)-1); + g_debug("sd_bus_wait returned %d", ret); + if (ret < 0) { + g_error("Failed to wait on bus: %s", strerror(-ret)); + exit_loop(slot, bus); + return; + } + } + exit_loop(slot, bus); +} + +int +main(int argc, char *argv[]) { + GTestDBus *dbus; + + dbus = startup(); + + loop(); + + finish(dbus); + + return 0; +} diff --git a/linux/ibus-keyman/tests/meson.build b/linux/ibus-keyman/tests/meson.build index c67f9920a9..83b534a170 100644 --- a/linux/ibus-keyman/tests/meson.build +++ b/linux/ibus-keyman/tests/meson.build @@ -1,9 +1,8 @@ test_files = [ 'ibusimcontext.c', - 'ibusimcontext.h', 'testfixture.cpp', 'testmodule.c', - 'testmodule.h', + '../src/keyman-system-service-client.c', ] kmnkbp_tests_lib = cc.find_library( @@ -11,7 +10,8 @@ kmnkbp_tests_lib = cc.find_library( dirs: [ core_dir / 'build/arch' / get_option('buildtype') / 'tests/kmx_test_source' ] ) -deps = [ibus, gtk, x11, json_glib, kmnkbp_lib, kmnkbp_tests_lib] +test_deps = [ibus, gtk, json_glib, kmnkbp_lib, kmnkbp_tests_lib, systemd] +dbus_deps = [gtk, systemd] test_env = [ 'G_TEST_SRCDIR=' + meson.current_source_dir(), @@ -28,10 +28,27 @@ test_include_dirs = [ test_exe = executable( 'ibus-keyman-tests', test_files, util_files, - dependencies: deps, + dependencies: test_deps, include_directories: test_include_dirs, ) +system_service_dir = meson.current_source_dir() / '../../keyman-system-service/build' / build_machine.cpu_family() / get_option('buildtype') / 'tests/services' + +dbus_test_server = executable( + 'km-dbus-test-server', + 'km-dbus-test-server.c', + dependencies: dbus_deps, + c_args: [ + '-DKEYMAN_TEST_SERVICE_PATH="' + system_service_dir + '"' + ] +) + +stop_test_server = executable( + 'stop-test-server', + 'stop-test-server.c', + dependencies: dbus_deps, +) + env_file = '/tmp/env.txt' pid_file = '/tmp/ibus-keyman-test-pids' diff --git a/linux/ibus-keyman/tests/scripts/run-tests.sh b/linux/ibus-keyman/tests/scripts/run-tests.sh index 4c0934511f..17a4535c3e 100755 --- a/linux/ibus-keyman/tests/scripts/run-tests.sh +++ b/linux/ibus-keyman/tests/scripts/run-tests.sh @@ -5,9 +5,14 @@ TOP_SRCDIR=${top_srcdir:-$(realpath "$(dirname "$0")/../..")} TESTBASEDIR=${XDG_DATA_HOME:-$HOME/.local/share}/keyman TESTDIR=${TESTBASEDIR}/test_kmx PID_FILE=/tmp/ibus-keyman-test-pids +ENV_FILE=/tmp/keyman-env.txt . "$(dirname "$0")"/test-helper.sh +local_cleanup() { + cleanup "$PID_FILE" +} + if [ -v KEYMAN_PKG_BUILD ]; then # During package builds we skip these tests that require to start ibus because # ibus requires to find /var/lib/dbus/machine-id or /etc/machine-id, otherwise it fails with: @@ -23,16 +28,6 @@ if ! which Xvfb > /dev/null || ! which Xephyr > /dev/null || ! which metacity > exit 1 fi -function cleanup() { - if [ -f "$PID_FILE" ]; then - echo - echo "# Shutting down processes..." - bash "$PID_FILE" > /dev/null 2>&1 - rm "$PID_FILE" - echo "# Finished shutdown of processes." - fi -} - function help() { echo "Usage:" echo " $0 [-k] [--tap] [--surrounding-text] [--no-surrounding-text] [--no-wayland] [--no-x11] [[--] TEST...]" @@ -57,68 +52,22 @@ function run_tests() { DISPLAY_SERVER=$1 shift - echo > "$PID_FILE" - TEMP_DATA_DIR=$(mktemp --directory) - echo "rm -rf ${TEMP_DATA_DIR} || true" >> "$PID_FILE" - - COMMON_ARCH_DIR= - [ -d "${TOP_SRCDIR}"/../../core/build/arch ] && COMMON_ARCH_DIR=${TOP_SRCDIR}/../../core/build/arch - - if [ -d "${COMMON_ARCH_DIR}"/release ]; then - COMMON_ARCH_DIR=${COMMON_ARCH_DIR}/release - elif [ -d "${COMMON_ARCH_DIR}"/debug ]; then - COMMON_ARCH_DIR=${COMMON_ARCH_DIR}/debug + if [ -d "$(dirname "$0")/../../../build/$(arch)/debug" ]; then + CONFIG=debug + elif [ -d "$(dirname "$0")/../../../build/$(arch)/release" ]; then + CONFIG=release else - echo "Can't find neither ${COMMON_ARCH_DIR}/release nor ${COMMON_ARCH_DIR}/debug" - exit 2 + echo "Can't find neither ../../../build/$(arch)/debug nor ../../../build/$(arch)/release" + exit 9 fi - link_test_keyboards "${TOP_SRCDIR}/../../common/test/keyboards/baseline" "$TESTDIR" "$TESTBASEDIR" + G_TEST_BUILDDIR="$(dirname "$0")/../../../build/$(arch)/${CONFIG}/tests" - generate_kmpjson "$TESTDIR" + setup "$DISPLAY_SERVER" "$ENV_FILE" "$PID_FILE" echo "# NOTE: When the tests fail check /tmp/ibus-engine-keyman.log and /tmp/ibus-daemon.log!" echo "" - if [ "$DISPLAY_SERVER" == "wayland" ]; then - if ! can_run_wayland; then - # support for --headless got added in mutter 40.x - echo "ERROR: mutter doesn't support running headless. Can't run Wayland tests." - exit 7 - fi - echo "# Running on Wayland..." - TMPFILE=$(mktemp) - # mutter-Message: 18:56:15.422: Using Wayland display name 'wayland-1' - mutter --wayland --headless --no-x11 --virtual-monitor 1024x768 &> "$TMPFILE" & - echo "kill -9 $! || true" >> "$PID_FILE" - sleep 1s - export WAYLAND_DISPLAY - WAYLAND_DISPLAY=$(grep "Using Wayland display" "$TMPFILE" | cut -d"'" -f2) - rm "$TMPFILE" - else - echo "# Starting Xvfb..." - Xvfb -screen 0 1024x768x24 :33 &> /dev/null & - echo "kill -9 $! || true" >> "$PID_FILE" - sleep 1 - echo "# Starting Xephyr..." - DISPLAY=:33 Xephyr :32 -screen 1024x768 &> /dev/null & - echo "kill -9 $! || true" >> "$PID_FILE" - sleep 1 - echo "# Starting metacity" - metacity --display=:32 &> /dev/null & - echo "kill -9 $! || true" >> "$PID_FILE" - - export DISPLAY=:32 - fi - - # Install schema to temporary directory. This removes the build dependency on the keyman package. - SCHEMA_DIR=$TEMP_DATA_DIR/glib-2.0/schemas - export XDG_DATA_DIRS=$TEMP_DATA_DIR:$XDG_DATA_DIRS - - mkdir -p "$SCHEMA_DIR" - cp "${TOP_SRCDIR}"/../keyman-config/com.keyman.gschema.xml "$SCHEMA_DIR"/ - glib-compile-schemas "$SCHEMA_DIR" - if [ $# -gt 0 ]; then #shellcheck disable=SC2206 TESTFILES=($@) @@ -128,38 +77,11 @@ function run_tests() { popd > /dev/null || exit fi - export LD_LIBRARY_PATH=${COMMON_ARCH_DIR}/src:${LD_LIBRARY_PATH-} - - # Ubuntu 18.04 Bionic doesn't have ibus-memconf, and glib is not compiled with the keyfile - # backend enabled, so we just use the default backend. Otherwise we use the keyfile - # store which interferes less when running on a dev machine. - if [ -f /usr/libexec/ibus-memconf ]; then - export GSETTINGS_BACKEND=keyfile - IBUS_CONFIG=--config=/usr/libexec/ibus-memconf - fi - - #shellcheck disable=SC2086 - ibus-daemon "${ARG_VERBOSE-}" --panel=disable --address=unix:abstract="${TEMP_DATA_DIR}"/test-ibus ${IBUS_CONFIG-} &> /tmp/ibus-daemon.log & - echo "kill -9 $! || true" >> "$PID_FILE" - sleep 1s - - IBUS_ADDRESS=$(ibus address) - export IBUS_ADDRESS - - if [ -d "../../build/$(arch)/debug" ]; then - CONFIG=debug - elif [ -d "../../build/$(arch)/release" ]; then - CONFIG=release - else - echo "Can't find neither ../../build/$(arch)/debug nor ../../build/$(arch)/release" - exit 9 - fi - - "../../build/$(arch)/${CONFIG}/src/ibus-engine-keyman" "${ARG_VERBOSE-}" &> /tmp/ibus-engine-keyman.log & - echo "kill -9 $! || true" >> "$PID_FILE" - sleep 1s - echo "# Starting tests..." + # shellcheck disable=SC1090 + source "$ENV_FILE" + echo "DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS" + # Note: -k and --tap are consumed by the GLib testing framework #shellcheck disable=SC2068 # we want to split array elements! #shellcheck disable=SC2086 @@ -168,7 +90,7 @@ function run_tests() { --directory "$TESTDIR" --"${DISPLAY_SERVER}" ${TESTFILES[@]} echo "# Finished tests." - cleanup + cleanup "$PID_FILE" } USE_WAYLAND=1 @@ -191,7 +113,7 @@ while (( $# )); do shift || (echo "Error: The last argument is missing a value. Exiting."; false) || exit 5 done -if ! can_run_wayland; then +if ! can_run_wayland && [ "$USE_WAYLAND" == "0" ]; then # support for --headless got added in mutter 40.x echo "# WARNING: mutter doesn't support running headless. Skipping Wayland tests." USE_WAYLAND=0 @@ -212,7 +134,7 @@ if [ ! -f "${G_TEST_BUILDDIR}/ibus-keyman-tests" ]; then fi echo > "$PID_FILE" -trap cleanup EXIT SIGINT +trap local_cleanup EXIT SIGINT if [ "$USE_WAYLAND" == "1" ]; then ( run_tests wayland "$@" ) diff --git a/linux/ibus-keyman/tests/scripts/setup-tests.sh b/linux/ibus-keyman/tests/scripts/setup-tests.sh index 62f6a97817..0506ede395 100755 --- a/linux/ibus-keyman/tests/scripts/setup-tests.sh +++ b/linux/ibus-keyman/tests/scripts/setup-tests.sh @@ -1,109 +1,6 @@ #!/usr/bin/env bash set -eu -DISPLAY_SERVER=$1 -ENV_FILE=$2 -PID_FILE=$3 -TOP_SRCDIR=${G_TEST_SRCDIR:-$(realpath "$(dirname "$0")/..")}/.. -TOP_BINDIR=${G_TEST_BUILDDIR:-$(realpath "$(dirname "$0/..")")}/.. -TESTBASEDIR=${XDG_DATA_HOME:-$HOME/.local/share}/keyman -TESTDIR=${TESTBASEDIR}/test_kmx +. "$(dirname "$0")/test-helper.sh" -# shellcheck source=linux/ibus-keyman/tests/scripts/test-helper.sh -. "$(dirname "$0")"/test-helper.sh - -echo > "$ENV_FILE" - -if [ -f "$PID_FILE" ]; then - # kill previous instances - "$(dirname "$0")"/teardown-tests.sh "$PID_FILE" -fi - -echo > "$PID_FILE" -TEMP_DATA_DIR=$(mktemp --directory) -echo "rm -rf ${TEMP_DATA_DIR} || true" >> "$PID_FILE" - -COMMON_ARCH_DIR= -[ -d "${TOP_SRCDIR}"/../../core/build/arch ] && COMMON_ARCH_DIR=${TOP_SRCDIR}/../../core/build/arch - -if [ -d "${COMMON_ARCH_DIR}"/release ]; then - COMMON_ARCH_DIR=${COMMON_ARCH_DIR}/release -elif [ -d "${COMMON_ARCH_DIR}"/debug ]; then - COMMON_ARCH_DIR=${COMMON_ARCH_DIR}/debug -else - echo "Can't find neither ${COMMON_ARCH_DIR}/release nor ${COMMON_ARCH_DIR}/debug" - exit 2 -fi - -link_test_keyboards "${TOP_SRCDIR}/../../common/test/keyboards/baseline" "$TESTDIR" "$TESTBASEDIR" - -generate_kmpjson "$TESTDIR" - -if [ "$DISPLAY_SERVER" == "wayland" ]; then - if ! can_run_wayland; then - # support for --headless got added in mutter 40.x - echo "ERROR: mutter doesn't support running headless. Can't run Wayland tests." - exit 7 - fi - echo "Running on Wayland..." - TMPFILE=$(mktemp) - # mutter-Message: 18:56:15.422: Using Wayland display name 'wayland-1' - mutter --wayland --headless --no-x11 --virtual-monitor 1024x768 &> "$TMPFILE" & - echo "kill -9 $! || true" >> "$PID_FILE" - sleep 1s - export WAYLAND_DISPLAY - WAYLAND_DISPLAY=$(grep "Using Wayland display" "$TMPFILE" | cut -d"'" -f2) - rm "$TMPFILE" - echo "export WAYLAND_DISPLAY=\"$WAYLAND_DISPLAY\"" >> "$ENV_FILE" -else - echo "Starting Xvfb..." - Xvfb -screen 0 1024x768x24 :33 &> /dev/null & - echo "kill -9 $! || true" >> "$PID_FILE" - sleep 1 - echo "Starting Xephyr..." - DISPLAY=:33 Xephyr :32 -screen 1024x768 &> /dev/null & - echo "kill -9 $! || true" >> "$PID_FILE" - sleep 1 - echo "Starting metacity" - metacity --display=:32 &> /dev/null & - echo "kill -9 $! || true" >> "$PID_FILE" - - export DISPLAY=:32 - echo "export DISPLAY=\"$DISPLAY\"" >> "$ENV_FILE" -fi - -# Install schema to temporary directory. This removes the build dependency on the keyman package. -SCHEMA_DIR=$TEMP_DATA_DIR/glib-2.0/schemas -export XDG_DATA_DIRS=$TEMP_DATA_DIR:${XDG_DATA_DIRS-} -echo "export XDG_DATA_DIRS=\"$XDG_DATA_DIRS\"" >> "$ENV_FILE" - -mkdir -p "$SCHEMA_DIR" -cp "${TOP_SRCDIR}"/../keyman-config/com.keyman.gschema.xml "$SCHEMA_DIR"/ -glib-compile-schemas "$SCHEMA_DIR" - -export LD_LIBRARY_PATH=${COMMON_ARCH_DIR}/src:${LD_LIBRARY_PATH-} -echo "export LD_LIBRARY_PATH=\"$LD_LIBRARY_PATH\"" >> "$ENV_FILE" - -# Ubuntu 18.04 Bionic doesn't have ibus-memconf, and glib is not compiled with the keyfile -# backend enabled, so we just use the default backend. Otherwise we use the keyfile -# store which interferes less when running on a dev machine. -if [ -f /usr/libexec/ibus-memconf ]; then - export GSETTINGS_BACKEND=keyfile - echo "export GSETTINGS_BACKEND=\"$GSETTINGS_BACKEND\"" >> "$ENV_FILE" - IBUS_CONFIG=--config=/usr/libexec/ibus-memconf -fi - -#shellcheck disable=SC2086 -ibus-daemon ${ARG_VERBOSE-} --daemonize --panel=disable --address=unix:abstract="${TEMP_DATA_DIR}/test-ibus" ${IBUS_CONFIG-} &> /tmp/ibus-daemon.log -echo "kill -9 $! || true" >> "$PID_FILE" -sleep 1s - -IBUS_ADDRESS=$(ibus address) -export IBUS_ADDRESS - -echo "export IBUS_ADDRESS=\"$IBUS_ADDRESS\"" >> "$ENV_FILE" - -#shellcheck disable=SC2086 -"${TOP_BINDIR}/src/ibus-engine-keyman" ${ARG_VERBOSE-} &> /tmp/ibus-engine-keyman.log & -echo "kill -9 $! || true" >> "$PID_FILE" -sleep 1s +setup "$1" "$2" "$3" diff --git a/linux/ibus-keyman/tests/scripts/teardown-tests.sh b/linux/ibus-keyman/tests/scripts/teardown-tests.sh index 45cfce605d..cf85d7f7dc 100755 --- a/linux/ibus-keyman/tests/scripts/teardown-tests.sh +++ b/linux/ibus-keyman/tests/scripts/teardown-tests.sh @@ -1,8 +1,6 @@ #!/usr/bin/env bash set -eu -PID_FILE=$1 -echo "Shutting down processes..." -bash "$PID_FILE" > /dev/null 2>&1 -rm "$PID_FILE" -echo "Finished shutdown of processes." +. "$(dirname "$0")/test-helper.sh" + +cleanup "$1" diff --git a/linux/ibus-keyman/tests/scripts/test-helper.sh b/linux/ibus-keyman/tests/scripts/test-helper.sh index efee4c26f1..33ff368373 100755 --- a/linux/ibus-keyman/tests/scripts/test-helper.sh +++ b/linux/ibus-keyman/tests/scripts/test-helper.sh @@ -92,3 +92,136 @@ function link_test_keyboards() { exit 3 fi } + +function setup() { + local DISPLAY_SERVER ENV_FILE PID_FILE TOP_SRCDIR TOP_BINDIR TESTBASEDIR TESTDIR + DISPLAY_SERVER=$1 + ENV_FILE=$2 + PID_FILE=$3 + + TOP_SRCDIR=${G_TEST_SRCDIR:-$(realpath "$(dirname "$0")/..")}/.. + TOP_BINDIR=${G_TEST_BUILDDIR:-$(realpath "$(dirname "$0/..")")}/.. + TESTBASEDIR=${XDG_DATA_HOME:-$HOME/.local/share}/keyman + TESTDIR=${TESTBASEDIR}/test_kmx + + echo > "$ENV_FILE" + + if [ -f "$PID_FILE" ]; then + # kill previous instances + "$(dirname "$0")"/teardown-tests.sh "$PID_FILE" + fi + + echo > "$PID_FILE" + TEMP_DATA_DIR=$(mktemp --directory) + echo "rm -rf ${TEMP_DATA_DIR} || true" >> "$PID_FILE" + + COMMON_ARCH_DIR= + [ -d "${TOP_SRCDIR}"/../../core/build/arch ] && COMMON_ARCH_DIR=${TOP_SRCDIR}/../../core/build/arch + + if [ -d "${COMMON_ARCH_DIR}"/release ]; then + COMMON_ARCH_DIR=${COMMON_ARCH_DIR}/release + elif [ -d "${COMMON_ARCH_DIR}"/debug ]; then + COMMON_ARCH_DIR=${COMMON_ARCH_DIR}/debug + else + echo "Can't find neither ${COMMON_ARCH_DIR}/release nor ${COMMON_ARCH_DIR}/debug" + exit 2 + fi + + link_test_keyboards "${TOP_SRCDIR}/../../common/test/keyboards/baseline" "$TESTDIR" "$TESTBASEDIR" + + generate_kmpjson "$TESTDIR" + + # Start test dbus server + "${TOP_BINDIR}/tests/km-dbus-test-server" &> /dev/null & + sleep 1 + source /tmp/km-test-server.env + cat /tmp/km-test-server.env >> "$ENV_FILE" + cat /tmp/km-test-server.env >> "$PID_FILE" + echo "${TOP_BINDIR}/tests/stop-test-server" >> "$PID_FILE" + + if [ "$DISPLAY_SERVER" == "wayland" ]; then + if ! can_run_wayland; then + # support for --headless got added in mutter 40.x + echo "ERROR: mutter doesn't support running headless. Can't run Wayland tests." + exit 7 + fi + echo "Running on Wayland..." + TMPFILE=$(mktemp) + # mutter-Message: 18:56:15.422: Using Wayland display name 'wayland-1' + mutter --wayland --headless --no-x11 --virtual-monitor 1024x768 &> "$TMPFILE" & + echo "kill -9 $! || true" >> "$PID_FILE" + sleep 1s + export WAYLAND_DISPLAY + WAYLAND_DISPLAY=$(grep "Using Wayland display" "$TMPFILE" | cut -d"'" -f2) + rm "$TMPFILE" + echo "export WAYLAND_DISPLAY=\"$WAYLAND_DISPLAY\"" >> "$ENV_FILE" + else + echo "Starting Xvfb..." + Xvfb -screen 0 1024x768x24 :33 &> /dev/null & + echo "kill -9 $! || true" >> "$PID_FILE" + sleep 1 + echo "Starting Xephyr..." + DISPLAY=:33 Xephyr :32 -screen 1024x768 &> /dev/null & + echo "kill -9 $! || true" >> "$PID_FILE" + sleep 1 + echo "Starting metacity" + metacity --display=:32 &> /dev/null & + echo "kill -9 $! || true" >> "$PID_FILE" + + export DISPLAY=:32 + echo "export DISPLAY=\"$DISPLAY\"" >> "$ENV_FILE" + fi + + # Install schema to temporary directory. This removes the build dependency on the keyman package. + SCHEMA_DIR=$TEMP_DATA_DIR/glib-2.0/schemas + export XDG_DATA_DIRS=$TEMP_DATA_DIR:${XDG_DATA_DIRS-} + echo "export XDG_DATA_DIRS=$XDG_DATA_DIRS" >> "$ENV_FILE" + + export GSETTINGS_SCHEMA_DIR=${SCHEMA_DIR} + echo "export GSETTINGS_SCHEMA_DIR=\"$SCHEMA_DIR\"" >> "$ENV_FILE" + + mkdir -p "$SCHEMA_DIR" + cp "${TOP_SRCDIR}"/../keyman-config/com.keyman.gschema.xml "$SCHEMA_DIR"/ + glib-compile-schemas "$SCHEMA_DIR" + + export LD_LIBRARY_PATH=${COMMON_ARCH_DIR}/src:${LD_LIBRARY_PATH-} + echo "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH" >> "$ENV_FILE" + + # Ubuntu 18.04 Bionic doesn't have ibus-memconf, and glib is not compiled with the keyfile + # backend enabled, so we just use the default backend. Otherwise we use the keyfile + # store which interferes less when running on a dev machine. + if [ -f /usr/libexec/ibus-memconf ]; then + export GSETTINGS_BACKEND=keyfile + echo "export GSETTINGS_BACKEND=\"$GSETTINGS_BACKEND\"" >> "$ENV_FILE" + IBUS_CONFIG=--config=/usr/libexec/ibus-memconf + fi + + #shellcheck disable=SC2086 + ibus-daemon ${ARG_VERBOSE-} --daemonize --panel=disable --address=unix:abstract="${TEMP_DATA_DIR}/test-ibus" ${IBUS_CONFIG-} &> /tmp/ibus-daemon.log + echo "kill -9 $! || true" >> "$PID_FILE" + sleep 1s + + IBUS_ADDRESS=$(ibus address) + export IBUS_ADDRESS + + echo "export IBUS_ADDRESS=\"$IBUS_ADDRESS\"" >> "$ENV_FILE" + + echo "# DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS" + #shellcheck disable=SC2086 + "${TOP_BINDIR}/src/ibus-engine-keyman" --testing ${ARG_VERBOSE-} &> /tmp/ibus-engine-keyman.log & + echo "kill -9 $! || true" >> "$PID_FILE" + sleep 1s +} + +function cleanup() { + local PID_FILE + PID_FILE=$1 + + if [ -f "$PID_FILE" ]; then + echo + echo "# Shutting down processes..." + bash "$PID_FILE" > /dev/null 2>&1 + rm "$PID_FILE" + echo "# Finished shutdown of processes." + fi +} diff --git a/linux/ibus-keyman/tests/stop-test-server.c b/linux/ibus-keyman/tests/stop-test-server.c new file mode 100644 index 0000000000..311131c5d1 --- /dev/null +++ b/linux/ibus-keyman/tests/stop-test-server.c @@ -0,0 +1,34 @@ +#include + +void +finish(sd_bus_error* error, sd_bus_message* msg, sd_bus * bus) { + if (error) { sd_bus_error_free(error); } + if (msg) { sd_bus_message_unref(msg); } + if (bus) { sd_bus_unref(bus); } +} + +int main(int argc, char* argv[]) { + sd_bus_error error = SD_BUS_ERROR_NULL; + sd_bus_message* msg = NULL; + sd_bus* bus = NULL; + int result; + + result = sd_bus_open_user(&bus); + if (result < 0) { + fprintf(stderr, "Can't get connection: %s", strerror(-result)); + finish(&error, msg, bus); + return 1; + } + + result = sd_bus_call_method( + bus, "com.keyman.ExitTestService", "/com/keyman/ExitTestService/Exit", + "com.keyman.ExitTestService.Exit", "Exit", &error, &msg, ""); + if (result < 0) { + fprintf(stderr, "Failed to issue method call: %s", strerror(-result)); + finish(&error, msg, bus); + return 1; + } + + finish(&error, msg, bus); + return 0; +} diff --git a/linux/ibus-keyman/tests/testfixture.cpp b/linux/ibus-keyman/tests/testfixture.cpp index 3e189258bd..b811148c8f 100644 --- a/linux/ibus-keyman/tests/testfixture.cpp +++ b/linux/ibus-keyman/tests/testfixture.cpp @@ -13,17 +13,10 @@ #include "ibusimcontext.h" #include "keycodes.h" #include "keymanutil.h" +#include "keyman-system-service-client.h" #include "kmx_test_source.hpp" #include "testmodule.h" -#ifdef GDK_WINDOWING_X11 -#include -#include -#endif -#ifdef GDK_WINDOWING_WAYLAND -#include -#endif - typedef struct { IBusBus *bus; GtkIMContext *context; @@ -42,12 +35,7 @@ static gboolean use_wayland = FALSE; static GdkWindow *window = NULL; static GMainLoop *thread_loop = NULL; static GTypeModule *module = NULL; -#ifdef GDK_WINDOWING_X11 -static Display *display = NULL; -#endif -#ifdef GDK_WINDOWING_WAYLAND -static GdkWaylandDisplay *wldisplay = NULL; -#endif +gboolean testing = TRUE; static void module_register(GTypeModule *module) { @@ -69,18 +57,6 @@ ibus_keyman_tests_fixture_set_up(IBusKeymanTestsFixture *fixture, gconstpointer window = gtk_widget_get_window(widget); } - GdkDisplay *gdkDisplay = gdk_display_get_default(); -#ifdef GDK_WINDOWING_X11 - if (!use_wayland && !display && GDK_IS_X11_DISPLAY(gdkDisplay)) { - display = GDK_DISPLAY_XDISPLAY(gdkDisplay); - } -#endif -#ifdef GDK_WINDOWING_WAYLAND - if (use_wayland && !wldisplay && GDK_IS_WAYLAND_DISPLAY(gdkDisplay)) { - wldisplay = GDK_WAYLAND_DISPLAY(gdkDisplay); - } -#endif - if (!loaded) { ibus_init(); @@ -114,35 +90,12 @@ ibus_keyman_tests_fixture_tear_down(IBusKeymanTestsFixture *fixture, gconstpoint static void set_caps_lock_state(IBusKeymanTestsFixture *fixture, bool caps_lock_on) { -#ifdef GDK_WINDOWING_X11 - if (!use_wayland && display) { - XkbLockModifiers(display, XkbUseCoreKbd, LockMask, caps_lock_on ? LockMask : 0); - XSync(display, False); - } -#endif -#ifdef GDK_WINDOWING_WAYLAND - if (use_wayland && wldisplay) { - // TODO - } -#endif + set_capslock_indicator((guint32)caps_lock_on); } static bool get_caps_lock_state(IBusKeymanTestsFixture *fixture) { -#ifdef GDK_WINDOWING_X11 - if (!use_wayland && display) { - XKeyboardState state; - XGetKeyboardControl(display, &state); - return state.led_mask & 1; - } -#endif -#ifdef GDK_WINDOWING_WAYLAND - if (use_wayland && wldisplay) { - // TODO - } -#endif - - return false; + return get_capslock_indicator(); } static void @@ -493,23 +446,6 @@ main(int argc, char *argv[]) { return 2; } - if (!argWayland && !argX11) { - GdkDisplay *gdkDisplay = gdk_display_get_default(); -#ifdef GDK_WINDOWING_WAYLAND - if (GDK_IS_WAYLAND_DISPLAY(gdkDisplay)) { - argWayland = true; - } else -#endif -#ifdef GDK_WINDOWING_X11 - if (GDK_IS_X11_DISPLAY(gdkDisplay)) { - argX11 = true; - } else -#endif - { - g_error("Neither X11 nor Wayland display!"); - } - } - use_wayland = argWayland; int nTests = argc - iArg; char **tests = &argv[iArg]; @@ -528,13 +464,6 @@ main(int argc, char *argv[]) { skipReason = "mnemonic keyboards are not yet supported on Linux (#3345)"; } - // Wayland related tests - #4273 - if (use_wayland && ( - strcmp(filename->str, "k_031___caps_lock") == 0 || - strcmp(filename->str, "k_032___caps_control") == 0)) { - skipReason = "capslock related keyboards are not yet working with Wayland (#4273)"; - } - if (runSurroundingTextTests) { add_test(directory, filename->str, TRUE, skipReason, use_wayland); } @@ -549,20 +478,6 @@ main(int argc, char *argv[]) { // Run tests int retVal = g_test_run(); - // Cleanup -#ifdef GDK_WINDOWING_X11 - if (!use_wayland && display) { - XCloseDisplay(display); - display = NULL; - } -#endif -#ifdef GDK_WINDOWING_WAYLAND - if (use_wayland) { - // REVIEW: do we have to call something for cleanup? - wldisplay = NULL; - } -#endif - test_module_unuse(module); return retVal; } -- GitLab From 879a34a180e9916e0b408fa656c95ea59131af59 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 12 May 2023 11:43:09 +0200 Subject: [PATCH 114/214] feat(linux): Add package for keyman-system-service --- docs/linux/packaging.md | 2 +- linux/debian/control | 28 +++++++++++++- linux/debian/keyman-system-service.install | 5 +++ linux/debian/rules | 44 +++++++++------------- linux/scripts/dist.sh | 9 ++++- 5 files changed, 57 insertions(+), 31 deletions(-) create mode 100644 linux/debian/keyman-system-service.install diff --git a/docs/linux/packaging.md b/docs/linux/packaging.md index 91154934b4..59f16880eb 100644 --- a/docs/linux/packaging.md +++ b/docs/linux/packaging.md @@ -239,7 +239,7 @@ You'll have to create the docker image. ```bash cd $KEYMAN_ROOT docker run -v $(pwd):/source -i -t -w /source --platform=linux/amd64 \ - sillsdev/jammy keyman_*.dsc /source + sillsdev/jammy jammy keyman_*.dsc ``` This will create the binary packages in `$KEYMAN_ROOT/artifacts`. diff --git a/linux/debian/control b/linux/debian/control index 40b2065d7f..02dd064749 100644 --- a/linux/debian/control +++ b/linux/debian/control @@ -28,10 +28,12 @@ Build-Depends: python3-setuptools, meson (>= 0.53), ninja-build, + libevdev-dev, libgtk-3-dev, libicu-dev, libibus-1.0-dev (>= 1.2), libjson-glib-dev (>= 1.4.0), + libsystemd-dev, pkg-config, xserver-xephyr, xvfb, @@ -56,9 +58,9 @@ Recommends: Description: Type in your language with Keyman for Linux Keyman makes it possible for you to type in over 2,000 languages on Windows, macOS, Linux, iPhone, iPad, Android tablets and phones, and even instantly - in your web browser. With the world’s most powerful keyboarding engine, + in your web browser. With the world's most powerful keyboarding engine, intuitive and rapid text input is now possible in your language, and for - over 99% of the global population’s mother tongues! + over 99% of the global population's mother tongues! . Originally created in 1993 to type Lao on Windows, Keyman is now a free and open source keyboarding platform which allows anyone to write a keyboard @@ -160,6 +162,7 @@ Architecture: amd64 arm64 armel armhf i386 mipsel mips64el ppc64el riscv64 Depends: ibus (>= 1.3.7), libkmnkbp0-0 (= ${binary:Version}), + keyman-system-service (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends}, Provides: @@ -181,3 +184,24 @@ Description: Keyman engine for IBus . This package provides the Keyman IM engine for IBus. With this module, you can use keyboard layouts designed for Keyman under the IBus platform. + +Package: keyman-system-service +Architecture: any +Depends: + libevdev2, + ${misc:Depends}, + ${shlibs:Depends}, +Description: Keyman system service + Originally created in 1993 to type Lao on Windows, Keyman is now a free and + open source keyboarding platform which allows anyone to write a keyboard + layout for their language. Keyman is available for many platforms, including + Windows, macOS, iOS, Android, Linux and the web. + . + Keyboard layouts are defined with a clear and easy to understand keyboard + grammar. Keyman's contextual input model means keyboard layouts can be + intelligent and make it simple to type even the most complex languages. + Keyboard layouts are distributed through an open catalog to all major desktop + and mobile platforms. + . + This package provides a DBus/systemd system service as a helper for + running Keyman with Wayland. diff --git a/linux/debian/keyman-system-service.install b/linux/debian/keyman-system-service.install new file mode 100644 index 0000000000..f7ce93bd82 --- /dev/null +++ b/linux/debian/keyman-system-service.install @@ -0,0 +1,5 @@ +usr/lib/systemd/system/systemd-keyman.service +usr/libexec/keyman-system-service +usr/share/dbus-1/interfaces/com.keyman.SystemService1.System.xml +usr/share/dbus-1/system-services/com.keyman.SystemService1.service +usr/share/dbus-1/system.d/com.keyman.SystemService1.conf diff --git a/linux/debian/rules b/linux/debian/rules index 774371d252..ab4ad409e4 100755 --- a/linux/debian/rules +++ b/linux/debian/rules @@ -24,23 +24,20 @@ include /usr/share/dpkg/pkg-info.mk override_dh_auto_configure: # keymankeyboardprocessor - we need to configure and build core before # we can configure ibus-keyman! - cd core && \ - ./build.sh --no-tests configure:arch build:arch -- --wrap-mode=nodownload --prefix=/usr --sysconfdir=/etc \ - --localstatedir=/var --libdir=lib/$(DEB_TARGET_MULTIARCH) \ - --libexecdir=lib/$(DEB_TARGET_MULTIARCH) - # ibus-keyman - cd linux/ibus-keyman && \ - ./build.sh configure -- --wrap-mode=nodownload --prefix=/usr --sysconfdir=/etc \ - --localstatedir=/var + core/build.sh --no-tests configure:arch build:arch -- \ + --wrap-mode=nodownload --prefix=/usr --sysconfdir=/etc \ + --localstatedir=/var --libdir=lib/$(DEB_TARGET_MULTIARCH) \ + --libexecdir=lib/$(DEB_TARGET_MULTIARCH) + linux/ibus-keyman/build.sh configure -- \ + --wrap-mode=nodownload --prefix=/usr --sysconfdir=/etc --localstatedir=/var + linux/keyman-system-service/build.sh configure -- \ + --wrap-mode=nodownload --prefix=/usr --sysconfdir=/etc --localstatedir=/var # keyman-config override_dh_auto_build: - # keymankeyboardprocessor - cd core && \ - ./build.sh --no-tests build:arch - # ibus-keyman - cd linux/ibus-keyman && \ - ./build.sh build + core/build.sh --no-tests build:arch + linux/ibus-keyman/build.sh build + linux/keyman-system-service/build.sh build # keyman-config cd linux/keyman-config && \ make man && \ @@ -50,23 +47,18 @@ override_dh_auto_build: override_dh_auto_test: ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) - # keymankeyboardprocessor - cd core && \ - ./build.sh --no-tests test:arch - # ibus-keyman - cd linux/ibus-keyman && \ - ./build.sh test + core/build.sh --no-tests test:arch + linux/ibus-keyman/build.sh test + linux/keyman-system-service/build.sh test # keyman-config dh_auto_test --sourcedir=linux/keyman-config --buildsystem=pybuild $@ endif override_dh_auto_install: install -d $(CURDIR)/debian/tmp - cd core && \ - DESTDIR=$(CURDIR)/debian/tmp ./build.sh --no-tests install:arch - # ibus-keyman - cd linux/ibus-keyman && \ - DESTDIR=$(CURDIR)/debian/tmp ./build.sh install + DESTDIR=$(CURDIR)/debian/tmp core/build.sh --no-tests install:arch + DESTDIR=$(CURDIR)/debian/tmp linux/ibus-keyman/build.sh install + DESTDIR=$(CURDIR)/debian/tmp linux/keyman-system-service/build.sh install # keyman-config install -d $(CURDIR)/debian/keyman/usr/share/ cp -r linux/keyman-config/locale/ $(CURDIR)/debian/keyman/usr/share/ @@ -74,7 +66,7 @@ override_dh_auto_install: dh_auto_install --sourcedir=linux/keyman-config --buildsystem=pybuild $@ # Unfortunately bash-completion 2.10 (focal) doesn't yet provide dh-sequence-bash-completion, # which we could add as build-dependency, so we'll have to explicitly call - # dh_bash_completion here... + # dh_bash_completion here instead of using `dh $@ --with-python3 --with bash-completion` dh_bash-completion -O--buildsystem=pybuild dh_python3 -O--buildsystem=pybuild diff --git a/linux/scripts/dist.sh b/linux/scripts/dist.sh index f412531cd2..f81013f94f 100755 --- a/linux/scripts/dist.sh +++ b/linux/scripts/dist.sh @@ -33,6 +33,8 @@ dch keyman --newversion "${VERSION}" --force-bad-version --nomultimaint dpkg-source --tar-ignore=*~ --tar-ignore=.git --tar-ignore=.gitattributes \ --tar-ignore=.gitignore --tar-ignore=experiments --tar-ignore=debian \ --tar-ignore=.github --tar-ignore=.vscode --tar-ignore=android \ + --tar-ignore=.devcontainer \ + --tar-ignore=artifacts \ \ --tar-ignore=common/models \ --tar-ignore=common/predictive-text \ @@ -49,11 +51,14 @@ dpkg-source --tar-ignore=*~ --tar-ignore=.git --tar-ignore=.gitattributes \ --tar-ignore=linux/keyman-config/buildtools/build-langtags.py --tar-ignore=__pycache__ \ --tar-ignore=linux/help --tar-ignore=linux/Jenkinsfile \ --tar-ignore=mac --tar-ignore=node_modules --tar-ignore=oem \ - --tar-ignore=linux/build --tar-ignore=core/build \ + --tar-ignore=linux/build \ + --tar-ignore=linux/builddebs \ + --tar-ignore=linux/ibus-keyman/build \ + --tar-ignore=linux/keyman-system-service/build \ --tar-ignore=resources/devbox --tar-ignore=resources/git-hooks \ --tar-ignore=resources/scopes \ --tar-ignore=resources/build/*.lua --tar-ignore=resources/build/jq* \ - --tar-ignore=results \ + --tar-ignore=results --tar-ignore=tmp \ --tar-ignore=web --tar-ignore=windows --tar-ignore=keyman_1* \ --tar-ignore=dist --tar-ignore=.pbuilderrc --tar-ignore=VERSION -Zgzip -b . mv ../keyman_"${VERSION}".tar.gz linux/dist/keyman-"${VERSION}".tar.gz -- GitLab From 663e4195ffc3a4c96b4438e040c5fca32afb173a Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 15 May 2023 23:16:36 +1000 Subject: [PATCH 115/214] chore: Apply suggestions from code review --- .../src/compiler/package-version-validation.ts | 8 ++++---- .../test/fixtures/invalid/keyboardcontentfilenotfound.kps | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/developer/src/kmc-package/src/compiler/package-version-validation.ts b/developer/src/kmc-package/src/compiler/package-version-validation.ts index c240c77328..7288a58fbb 100644 --- a/developer/src/kmc-package/src/compiler/package-version-validation.ts +++ b/developer/src/kmc-package/src/compiler/package-version-validation.ts @@ -8,7 +8,7 @@ export class PackageVersionValidation { /** * Verifies version information in corresponding keyboards and updates kmpJson * metadata as the version information can be out of sync in the .kps file - * after update a contained keyboard. + * after updating a contained keyboard. * @param kpsFilename * @param kps * @param kmp @@ -23,13 +23,13 @@ export class PackageVersionValidation { } } - let result = true; - if(!kmp.keyboards) { - // Lexical model packages don't have version metadata + // Lexical models don't have version metadata; only their packages. return true; } + let result = true; + // We now know we have at least one keyboard in the package for(let keyboard of kmp.keyboards) { diff --git a/developer/src/kmc-package/test/fixtures/invalid/keyboardcontentfilenotfound.kps b/developer/src/kmc-package/test/fixtures/invalid/keyboardcontentfilenotfound.kps index 224dd52042..d641e7c83c 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/keyboardcontentfilenotfound.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/keyboardcontentfilenotfound.kps @@ -24,6 +24,7 @@ https://keyman.com/keyboards/khmer_angkor + ..\build\khmer_angkor.js File khmer_angkor.js -- GitLab From c31118cd6de0838e4e0a126d27de58d50ecb4788 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 15 May 2023 20:17:22 +0700 Subject: [PATCH 116/214] chore(developer): rename fixture --- ... error_package_cannot_contain_both_models_and_keyboards.kps} | 0 developer/src/kmc-package/test/test-package-compiler.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename developer/src/kmc-package/test/fixtures/invalid/{ERROR_PackageCannotContainBothModelsAndKeyboards.kps => error_package_cannot_contain_both_models_and_keyboards.kps} (100%) diff --git a/developer/src/kmc-package/test/fixtures/invalid/ERROR_PackageCannotContainBothModelsAndKeyboards.kps b/developer/src/kmc-package/test/fixtures/invalid/error_package_cannot_contain_both_models_and_keyboards.kps similarity index 100% rename from developer/src/kmc-package/test/fixtures/invalid/ERROR_PackageCannotContainBothModelsAndKeyboards.kps rename to developer/src/kmc-package/test/fixtures/invalid/error_package_cannot_contain_both_models_and_keyboards.kps diff --git a/developer/src/kmc-package/test/test-package-compiler.ts b/developer/src/kmc-package/test/test-package-compiler.ts index bf04fda493..8317573ba5 100644 --- a/developer/src/kmc-package/test/test-package-compiler.ts +++ b/developer/src/kmc-package/test/test-package-compiler.ts @@ -226,7 +226,7 @@ describe('KmpCompiler', function () { // ERROR_PackageCannotContainBothModelsAndKeyboards it('should generate ERROR_PackageCannotContainBothModelsAndKeyboards if package has both keyboards and models', async function() { - testForMessage(this, ['invalid', 'ERROR_PackageCannotContainBothModelsAndKeyboards.kps'], CompilerMessages.ERROR_PackageCannotContainBothModelsAndKeyboards); + testForMessage(this, ['invalid', 'error_package_cannot_contain_both_models_and_keyboards.kps'], CompilerMessages.ERROR_PackageCannotContainBothModelsAndKeyboards); }); // WARN_PackageShouldNotRepeatLanguages (models) -- GitLab From f08f44e29422607a54bd00ef830f89c2019d8be2 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Mon, 15 May 2023 17:39:16 +0200 Subject: [PATCH 117/214] chore(linux): Make postinst script comply with Debian policy Debian Policy section 10.4 requires `set -e` [1]. [1] https://www.debian.org/doc/debian-policy/ch-files.html#scripts --- linux/debian/ibus-keyman.postinst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/linux/debian/ibus-keyman.postinst b/linux/debian/ibus-keyman.postinst index 4143effb61..6cff5c525c 100644 --- a/linux/debian/ibus-keyman.postinst +++ b/linux/debian/ibus-keyman.postinst @@ -1,7 +1,7 @@ -#!/bin/sh +#!/bin/bash -# Don't call `set -e`. Even if some commands should fail, it's still -# worth running the rest of the commands. +# Exit on errors - Debian policy 10.4 +set -e case "$1" in @@ -12,7 +12,7 @@ case "$1" in if which sudo > /dev/null && which ps > /dev/null; then # check for gnome-shell as it works differently - gspid=$(ps -C gnome-shell -o pid=|head -n 1) + ! gspid=$(ps -C gnome-shell -o pid=|head -n 1) if [ "$gspid" != "" ]; then # gnome-shell has multiple ibus-daemon processes and needs exit instead of restart is_gnome_shell=1 @@ -21,7 +21,7 @@ case "$1" in fi # Restart IBus if it is running - ibuspid=$(ps -C ibus-daemon -o pid=|head -n 1) + ! ibuspid=$(ps -C ibus-daemon -o pid=|head -n 1) if [ "$ibuspid" != "" ]; then if [ "$is_gnome_shell" = "1" ]; then @@ -41,7 +41,7 @@ case "$1" in # Verify that it's running now if [ -n "$SUDO_USER" ] && id "$SUDO_USER" > /dev/null 2>/dev/null; then - ibusdaemon=$(ps --user "$SUDO_USER" -o s= -o cmd | grep --regexp="^[^ZT] \(/usr/bin/\)\?ibus-daemon .*--xim.*") + ! ibusdaemon=$(ps --user "$SUDO_USER" -o s= -o cmd | grep --regexp="^[^ZT] \(/usr/bin/\)\?ibus-daemon .*--xim.*") if [ "$ibusdaemon" = "" ]; then # otherwise try to start it for the user installing the package if [ "$is_gnome_shell" = "1" ]; then -- GitLab From a7b9e5bbb08a2f43abed268e401730a139479fbb Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Mon, 15 May 2023 14:01:40 -0400 Subject: [PATCH 118/214] auto: increment master version to 17.0.108 --- HISTORY.md | 5 +++++ VERSION.md | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index a90cd198d3..9725ba6423 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,10 @@ # Keyman Version History +## 17.0.107 alpha 2023-05-15 + +* chore(linux): Fix installation build step on TC (#8784) +* refactor(android/engine): Consolidate updateSelection (#8739) + ## 17.0.106 alpha 2023-05-12 * chore(developer): move package formats to common/web/types (#8729) diff --git a/VERSION.md b/VERSION.md index 58ff762bc8..34fa3ac13e 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.107 \ No newline at end of file +17.0.108 \ No newline at end of file -- GitLab From b2e293892da2bc21fa177bcab43354b8d056c587 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 16 May 2023 13:21:31 +1000 Subject: [PATCH 119/214] Update developer/src/kmc-package/test/fixtures/invalid/keyboardcontentfilenotfound.kps --- .../test/fixtures/invalid/keyboardcontentfilenotfound.kps | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/developer/src/kmc-package/test/fixtures/invalid/keyboardcontentfilenotfound.kps b/developer/src/kmc-package/test/fixtures/invalid/keyboardcontentfilenotfound.kps index d641e7c83c..cfcd527894 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/keyboardcontentfilenotfound.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/keyboardcontentfilenotfound.kps @@ -24,7 +24,9 @@ https://keyman.com/keyboards/khmer_angkor - + ..\build\khmer_angkor.js File khmer_angkor.js -- GitLab From f6e5e468c417da17837564a1f3f1ec3c65997629 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 16 May 2023 10:57:17 +0200 Subject: [PATCH 120/214] chore(linux): Rename test-helper.sh to test-helper.inc.sh Follow-up of code review. --- linux/ibus-keyman/tests/scripts/run-single-test.sh | 2 +- linux/ibus-keyman/tests/scripts/run-tests.sh | 2 +- linux/ibus-keyman/tests/scripts/setup-tests.sh | 2 +- linux/ibus-keyman/tests/scripts/teardown-tests.sh | 2 +- .../tests/scripts/{test-helper.sh => test-helper.inc.sh} | 4 +++- 5 files changed, 7 insertions(+), 5 deletions(-) rename linux/ibus-keyman/tests/scripts/{test-helper.sh => test-helper.inc.sh} (98%) diff --git a/linux/ibus-keyman/tests/scripts/run-single-test.sh b/linux/ibus-keyman/tests/scripts/run-single-test.sh index 8e4e84f2ca..19baca7dd6 100755 --- a/linux/ibus-keyman/tests/scripts/run-single-test.sh +++ b/linux/ibus-keyman/tests/scripts/run-single-test.sh @@ -2,7 +2,7 @@ set -eu TESTDIR=${XDG_DATA_HOME:-$HOME/.local/share}/keyman/test_kmx -. "$(dirname "$0")"/test-helper.sh +. "$(dirname "$0")"/test-helper.inc.sh if [ -v KEYMAN_PKG_BUILD ]; then # During package builds we skip these tests that require to start ibus because diff --git a/linux/ibus-keyman/tests/scripts/run-tests.sh b/linux/ibus-keyman/tests/scripts/run-tests.sh index 17a4535c3e..2f685e8807 100755 --- a/linux/ibus-keyman/tests/scripts/run-tests.sh +++ b/linux/ibus-keyman/tests/scripts/run-tests.sh @@ -7,7 +7,7 @@ TESTDIR=${TESTBASEDIR}/test_kmx PID_FILE=/tmp/ibus-keyman-test-pids ENV_FILE=/tmp/keyman-env.txt -. "$(dirname "$0")"/test-helper.sh +. "$(dirname "$0")"/test-helper.inc.sh local_cleanup() { cleanup "$PID_FILE" diff --git a/linux/ibus-keyman/tests/scripts/setup-tests.sh b/linux/ibus-keyman/tests/scripts/setup-tests.sh index 0506ede395..9d591869fb 100755 --- a/linux/ibus-keyman/tests/scripts/setup-tests.sh +++ b/linux/ibus-keyman/tests/scripts/setup-tests.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash set -eu -. "$(dirname "$0")/test-helper.sh" +. "$(dirname "$0")/test-helper.inc.sh" setup "$1" "$2" "$3" diff --git a/linux/ibus-keyman/tests/scripts/teardown-tests.sh b/linux/ibus-keyman/tests/scripts/teardown-tests.sh index cf85d7f7dc..c3b955a13a 100755 --- a/linux/ibus-keyman/tests/scripts/teardown-tests.sh +++ b/linux/ibus-keyman/tests/scripts/teardown-tests.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash set -eu -. "$(dirname "$0")/test-helper.sh" +. "$(dirname "$0")/test-helper.inc.sh" cleanup "$1" diff --git a/linux/ibus-keyman/tests/scripts/test-helper.sh b/linux/ibus-keyman/tests/scripts/test-helper.inc.sh similarity index 98% rename from linux/ibus-keyman/tests/scripts/test-helper.sh rename to linux/ibus-keyman/tests/scripts/test-helper.inc.sh index 33ff368373..930eb4fe2c 100755 --- a/linux/ibus-keyman/tests/scripts/test-helper.sh +++ b/linux/ibus-keyman/tests/scripts/test-helper.inc.sh @@ -145,7 +145,8 @@ function setup() { echo "ERROR: mutter doesn't support running headless. Can't run Wayland tests." exit 7 fi - echo "Running on Wayland..." + echo "Running on Wayland:" + echo "Starting mutter..." TMPFILE=$(mktemp) # mutter-Message: 18:56:15.422: Using Wayland display name 'wayland-1' mutter --wayland --headless --no-x11 --virtual-monitor 1024x768 &> "$TMPFILE" & @@ -156,6 +157,7 @@ function setup() { rm "$TMPFILE" echo "export WAYLAND_DISPLAY=\"$WAYLAND_DISPLAY\"" >> "$ENV_FILE" else + echo "Running on X11:" echo "Starting Xvfb..." Xvfb -screen 0 1024x768x24 :33 &> /dev/null & echo "kill -9 $! || true" >> "$PID_FILE" -- GitLab From a4ae39c15cb53518bb91d2a947d38033436c7237 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 16 May 2023 19:27:18 +1000 Subject: [PATCH 121/214] chore make oem/firstvoices/ios/Cartfile consistent with ios/Cartfile --- oem/firstvoices/ios/Cartfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oem/firstvoices/ios/Cartfile b/oem/firstvoices/ios/Cartfile index 3b128ec5d9..10efbc3d5a 100644 --- a/oem/firstvoices/ios/Cartfile +++ b/oem/firstvoices/ios/Cartfile @@ -1,4 +1,4 @@ -github "keymanapp/dependency-XCGLogger" "head" +github "keymanapp/dependency-XCGLogger" "master" github "devicekit/DeviceKit" ~> 5.0 github "ashleymills/Reachability.swift" github "getsentry/sentry-cocoa" ~> 8.7.0 -- GitLab From cfe62f72d39a5d246fa1e34de53cfe0412b624bc Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Tue, 16 May 2023 14:03:00 -0400 Subject: [PATCH 122/214] auto: increment master version to 17.0.109 --- HISTORY.md | 10 ++++++++++ VERSION.md | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 9725ba6423..8411458c0d 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,15 @@ # Keyman Version History +## 17.0.108 alpha 2023-05-16 + +* feat(windows): add text editor to the support makefile (#8750) +* feat(developer): verify keyboard versions in kmc-package (#8769) +* feat(developer): verify bcp47 tags are valid and minimal in kmc-package (#8778) +* feat(developer): verify at least one language in package (#8783) +* chore(developer): verify file types of content files in package (#8792) +* chore(developer): verify that package has at least a model or keyboard (#8793) +* chore(ios): Changes required for XCode 14.3 (#8746) + ## 17.0.107 alpha 2023-05-15 * chore(linux): Fix installation build step on TC (#8784) diff --git a/VERSION.md b/VERSION.md index 34fa3ac13e..46bc450937 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.108 \ No newline at end of file +17.0.109 \ No newline at end of file -- GitLab From 1f37ca6e614e8df2bc525a35f7d218b40c1ea50a Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Wed, 17 May 2023 10:27:12 +1000 Subject: [PATCH 123/214] chore(windows): use __FUNCTION__ for comment Co-authored-by: Eberhard Beilharz --- windows/src/engine/keyman32/K32_load.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index e17e58ad46..e29e504b2a 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -71,7 +71,7 @@ BOOL GetKeyboardFileName(LPSTR kbname, LPSTR buf, int nbuf) BOOL LoadlpKeyboard(int i) { - SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboard: Enter ---"); + SendDebugMessageFormat(0, sdmLoad, 0, "%s: Enter ---", __FUNCTION__); PKEYMAN64THREADDATA _td = ThreadGlobals(); if (!_td) return FALSE; -- GitLab From 28ecb56ae667e74cafc51d156b6ec3a90a1084c4 Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 17 May 2023 12:45:06 +1000 Subject: [PATCH 124/214] fix(windows): add wrap-symbols texteditor makefile --- windows/src/support/texteditor/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/windows/src/support/texteditor/Makefile b/windows/src/support/texteditor/Makefile index a01ac22203..8c35bbb835 100644 --- a/windows/src/support/texteditor/Makefile +++ b/windows/src/support/texteditor/Makefile @@ -23,6 +23,12 @@ install: $(COPY) $(PROGRAM)\support\editor32.exe "$(INSTALLPATH_KEYMANENGINE)" $(COPY) $(PROGRAM)\support\editor64.exe "$(INSTALLPATH_KEYMANENGINE)" +wrap-symbols: + $(SYMSTORE) $(PROGRAM)\support\editor32.exe /t keyman-windows + $(SYMSTORE) $(PROGRAM)\support\editor32.exe /t keyman-windows + $(SYMSTORE) $(DEBUGPATH)\support\editor32.pdb /t keyman-windows + $(SYMSTORE) $(DEBUGPATH)\support\editor32.pdb /t keyman-windows + !include ..\..\Target.mak # ---------------------------------------------------------------------- -- GitLab From acb6371f5150e64602deb3b4210ce61acb3334c7 Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 17 May 2023 12:51:24 +1000 Subject: [PATCH 125/214] fix(windows): cut and paste error --- windows/src/support/texteditor/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/windows/src/support/texteditor/Makefile b/windows/src/support/texteditor/Makefile index 8c35bbb835..473bf57598 100644 --- a/windows/src/support/texteditor/Makefile +++ b/windows/src/support/texteditor/Makefile @@ -25,9 +25,9 @@ install: wrap-symbols: $(SYMSTORE) $(PROGRAM)\support\editor32.exe /t keyman-windows - $(SYMSTORE) $(PROGRAM)\support\editor32.exe /t keyman-windows - $(SYMSTORE) $(DEBUGPATH)\support\editor32.pdb /t keyman-windows + $(SYMSTORE) $(PROGRAM)\support\editor64.exe /t keyman-windows $(SYMSTORE) $(DEBUGPATH)\support\editor32.pdb /t keyman-windows + $(SYMSTORE) $(DEBUGPATH)\support\editor64.pdb /t keyman-windows !include ..\..\Target.mak -- GitLab From 16daabd0f4932b3c2b94bd431f9dae7e633ada37 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Wed, 17 May 2023 10:46:20 +0200 Subject: [PATCH 126/214] feat(linux): Make cleanup more consistent Follow-up of code review comments. # Keyman Conventional Commit suggestions: # - Consider appending the text ". Fixes #4273" to your commit message. --- linux/ibus-keyman/tests/km-dbus-test-server.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/linux/ibus-keyman/tests/km-dbus-test-server.c b/linux/ibus-keyman/tests/km-dbus-test-server.c index 086071988c..1598a7a9ec 100644 --- a/linux/ibus-keyman/tests/km-dbus-test-server.c +++ b/linux/ibus-keyman/tests/km-dbus-test-server.c @@ -59,9 +59,9 @@ static const sd_bus_vtable exit_test_service_vtable[] = { }; static const void exit_loop(sd_bus_slot *slot, sd_bus *bus) { - sd_bus_release_name(bus, KEYMAN_TESTSVC_BUS_NAME); - sd_bus_slot_unref(slot); - sd_bus_close_unref(bus); + if (bus) sd_bus_release_name(bus, KEYMAN_TESTSVC_BUS_NAME); + if (slot) sd_bus_slot_unref(slot); + if (bus) sd_bus_close_unref(bus); } static void @@ -74,6 +74,7 @@ loop() { if (ret < 0) { g_error("Failed to connect to system bus: %s", strerror(-ret)); + exit_loop(slot, bus); return; } -- GitLab From 7f131b27daf2036d11a8b903e963b585ea9744ab Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Wed, 17 May 2023 14:02:14 -0400 Subject: [PATCH 127/214] auto: increment master version to 17.0.110 --- HISTORY.md | 6 ++++++ VERSION.md | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 8411458c0d..213b87a6f8 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,11 @@ # Keyman Version History +## 17.0.109 alpha 2023-05-17 + +* fix(windows): add wrap-symbols to Text Editor Makefile (#8819) +* chore(linux): Make postinst script comply with Debian policy (#8810) +* chore(windows): remove legacy core and flag ️ (#8593) + ## 17.0.108 alpha 2023-05-16 * feat(windows): add text editor to the support makefile (#8750) diff --git a/VERSION.md b/VERSION.md index 46bc450937..18bc0b4cd1 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.109 \ No newline at end of file +17.0.110 \ No newline at end of file -- GitLab From be2c0ccf45e016aacd13e5592c8af243b9fa614c Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 19 May 2023 16:36:05 +0700 Subject: [PATCH 128/214] fix(common): cleanup logging in builder --- resources/builder.inc.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/resources/builder.inc.sh b/resources/builder.inc.sh index fb474fcfc0..e862f149b6 100755 --- a/resources/builder.inc.sh +++ b/resources/builder.inc.sh @@ -359,7 +359,7 @@ _builder_failure_trap() { # finishes. # _builder_cleanup_deps() { - if ! builder_is_dep_build && [[ ! -z ${_builder_deps_built+x} ]]; then + if ! builder_is_dep_build && ! builder_is_child_build && [[ ! -z ${_builder_deps_built+x} ]]; then if $_builder_debug_internal; then builder_echo_debug "Dependencies that were built:" cat "$_builder_deps_built" @@ -558,7 +558,6 @@ builder_has_action() { function builder_run_action() { local action=$1 shift - echo "builder_run_action $action $@" if builder_start_action $action; then ($@) builder_finish_action success $action @@ -1733,6 +1732,8 @@ builder_has_dependencies() { builder_has_module_been_built() { local module="$1" + echo "builder_has_module_been_built: $module" + if [[ -z ${_builder_deps_built+x} ]]; then # not in a builder context, so we assume a build is needed return 1 -- GitLab From f8535c469effd4b57fed0e3731f6f48d64ba8af6 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 22 May 2023 11:32:45 +1000 Subject: [PATCH 129/214] chore: Update resources/builder.inc.sh --- resources/builder.inc.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/builder.inc.sh b/resources/builder.inc.sh index e862f149b6..f9440ae83e 100755 --- a/resources/builder.inc.sh +++ b/resources/builder.inc.sh @@ -1732,7 +1732,6 @@ builder_has_dependencies() { builder_has_module_been_built() { local module="$1" - echo "builder_has_module_been_built: $module" if [[ -z ${_builder_deps_built+x} ]]; then # not in a builder context, so we assume a build is needed -- GitLab From a820d34c0828d577e719e80973c5400d35be054b Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Mon, 22 May 2023 18:10:54 +0200 Subject: [PATCH 130/214] chore(linux): Fix meson warnings --- linux/ibus-keyman/meson.build | 2 +- linux/ibus-keyman/tests/meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/linux/ibus-keyman/meson.build b/linux/ibus-keyman/meson.build index b7c7c4c596..e4b31df7db 100644 --- a/linux/ibus-keyman/meson.build +++ b/linux/ibus-keyman/meson.build @@ -18,7 +18,7 @@ core_dir = meson.current_source_dir() / '../../core' common_dir = meson.current_source_dir() / '../../common' kmnkbp_lib = cc.find_library( - 'libkmnkbp0', + 'kmnkbp0', # meson will prefix 'lib' dirs: [ core_dir / 'build/arch' / get_option('buildtype') / 'src' ] ) diff --git a/linux/ibus-keyman/tests/meson.build b/linux/ibus-keyman/tests/meson.build index 83b534a170..2b742e6ff6 100644 --- a/linux/ibus-keyman/tests/meson.build +++ b/linux/ibus-keyman/tests/meson.build @@ -6,7 +6,7 @@ test_files = [ ] kmnkbp_tests_lib = cc.find_library( - 'libkmnkbp-tests', + 'kmnkbp-tests', # meson will prefix 'lib' dirs: [ core_dir / 'build/arch' / get_option('buildtype') / 'tests/kmx_test_source' ] ) -- GitLab From ab251573644e4aae23b8d0e04855740245a09ab5 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Mon, 22 May 2023 19:51:45 +0200 Subject: [PATCH 131/214] feat(linux): Refactor to benefit from C++ RAII Also apply changes from code review comments. --- .../src/KeymanSystemServiceClient.cpp | 97 +++++++++ ...e-client.h => KeymanSystemServiceClient.h} | 6 +- linux/ibus-keyman/src/engine.c | 2 +- .../src/keyman-system-service-client.c | 90 -------- linux/ibus-keyman/src/meson.build | 2 +- ...bus-test-server.c => KmDbusTestServer.cpp} | 103 ++++----- linux/ibus-keyman/tests/StopTestServer.cpp | 58 ++++++ linux/ibus-keyman/tests/meson.build | 8 +- linux/ibus-keyman/tests/scripts/run-tests.sh | 2 +- linux/ibus-keyman/tests/stop-test-server.c | 34 --- linux/ibus-keyman/tests/testfixture.cpp | 2 +- linux/keyman-system-service/build.sh | 15 +- .../src/KeyboardDevice.cpp | 49 ++--- .../src/KeymanSystemService.cpp | 195 ++++++++++++++++++ .../src/KeymanSystemService.h | 33 +++ .../src/ServerMethods.cpp | 80 ------- .../keyman-system-service/src/ServerMethods.h | 17 -- .../keyman-system-service/src/dbus-service.c | 121 ----------- linux/keyman-system-service/src/main.cpp | 10 + linux/keyman-system-service/src/meson.build | 4 +- .../tests/KeyboardDeviceMock.cpp | 12 +- linux/keyman-system-service/tests/meson.build | 4 +- linux/scripts/dist.sh | 3 +- 23 files changed, 500 insertions(+), 447 deletions(-) create mode 100644 linux/ibus-keyman/src/KeymanSystemServiceClient.cpp rename linux/ibus-keyman/src/{keyman-system-service-client.h => KeymanSystemServiceClient.h} (57%) delete mode 100644 linux/ibus-keyman/src/keyman-system-service-client.c rename linux/ibus-keyman/tests/{km-dbus-test-server.c => KmDbusTestServer.cpp} (72%) create mode 100644 linux/ibus-keyman/tests/StopTestServer.cpp delete mode 100644 linux/ibus-keyman/tests/stop-test-server.c create mode 100644 linux/keyman-system-service/src/KeymanSystemService.cpp create mode 100644 linux/keyman-system-service/src/KeymanSystemService.h delete mode 100644 linux/keyman-system-service/src/ServerMethods.cpp delete mode 100644 linux/keyman-system-service/src/ServerMethods.h delete mode 100644 linux/keyman-system-service/src/dbus-service.c create mode 100644 linux/keyman-system-service/src/main.cpp diff --git a/linux/ibus-keyman/src/KeymanSystemServiceClient.cpp b/linux/ibus-keyman/src/KeymanSystemServiceClient.cpp new file mode 100644 index 0000000000..8f2de148d2 --- /dev/null +++ b/linux/ibus-keyman/src/KeymanSystemServiceClient.cpp @@ -0,0 +1,97 @@ +#include +#include "KeymanSystemServiceClient.h" + +#define KEYMAN_BUS_NAME "com.keyman.SystemService1" +#define KEYMAN_INTERFACE_NAME "com.keyman.SystemService1.System" +#define KEYMAN_OBJECT_PATH "/com/keyman/SystemService1/System" + +extern gboolean testing; + +class KeymanSystemServiceClient { +private: + sd_bus_error *error = NULL; + sd_bus_message *msg = NULL; + sd_bus *bus = NULL; + +public: + KeymanSystemServiceClient(); + ~KeymanSystemServiceClient(); + + void SetCapsLockIndicator(guint32 capsLock); + gint32 GetCapsLockIndicator(); +}; + +KeymanSystemServiceClient::KeymanSystemServiceClient() { + int result; + if (testing) { + result = sd_bus_open_user(&bus); + } else { + result = sd_bus_default_system(&bus); + } + if (result < 0) { + g_error("%s: Can't get connection: %s", __FUNCTION__, strerror(-result)); + } +} + +KeymanSystemServiceClient::~KeymanSystemServiceClient() { + if (error) { sd_bus_error_free(error); } + if (msg) { sd_bus_message_unref(msg); } + if (bus) { sd_bus_unref(bus); } +} + +void KeymanSystemServiceClient::SetCapsLockIndicator(guint32 capsLock) { + if (!bus) { + // we already reported the error, so just return + return; + } + + if (capsLock > 1) { + g_error("%s: Invalid value '%d' for parameter capsLock", __FUNCTION__, capsLock); + return; + } + + int result = sd_bus_call_method(bus, KEYMAN_BUS_NAME, KEYMAN_OBJECT_PATH, + KEYMAN_INTERFACE_NAME, "SetCapsLockIndicator", error, &msg, "b", capsLock); + if (result < 0) { + g_error("%s: Failed to call method SetCapsLockIndicator: %s. %s. %s.", + __FUNCTION__, strerror(-result), error->name, error->message); + return; + } +} + +gint32 KeymanSystemServiceClient::GetCapsLockIndicator() { + if (!bus) { + // we already reported the error, so just return + return -1; + } + + int result = sd_bus_call_method(bus, KEYMAN_BUS_NAME, KEYMAN_OBJECT_PATH, + KEYMAN_INTERFACE_NAME, "GetCapsLockIndicator", error, &msg, ""); + if (result < 0) { + g_error("%s: Failed to call method GetCapsLockIndicator: %s. %s. %s.", + __FUNCTION__, strerror(-result), error->name, error->message); + return -1; + } + + guint32 capsLock = 0; + result = sd_bus_message_read(msg, "b", &capsLock); + if (result < 0) { + g_error("%s: Failed to parse response message: %s", + __FUNCTION__, strerror(-result)); + return -1; + } + + return capsLock; +} + +void set_capslock_indicator( + guint32 capsLock +) { + KeymanSystemServiceClient client; + client.SetCapsLockIndicator(capsLock); +} + +gint32 get_capslock_indicator() { + KeymanSystemServiceClient client; + return client.GetCapsLockIndicator(); +} diff --git a/linux/ibus-keyman/src/keyman-system-service-client.h b/linux/ibus-keyman/src/KeymanSystemServiceClient.h similarity index 57% rename from linux/ibus-keyman/src/keyman-system-service-client.h rename to linux/ibus-keyman/src/KeymanSystemServiceClient.h index 0126e5d8db..746974df51 100644 --- a/linux/ibus-keyman/src/keyman-system-service-client.h +++ b/linux/ibus-keyman/src/KeymanSystemServiceClient.h @@ -1,5 +1,5 @@ -#ifndef __KEYMAN_SYSTEM_SERVICE_CLIENT_H__ -#define __KEYMAN_SYSTEM_SERVICE_CLIENT_H__ +#ifndef __KEYMANSYSTEMSERVICECLIENT_H__ +#define __KEYMANSYSTEMSERVICECLIENT_H__ #include @@ -14,4 +14,4 @@ gint32 get_capslock_indicator(); } #endif -#endif // __KEYMAN_SYSTEM_SERVICE_CLIENT_H__ +#endif // __KEYMANSYSTEMSERVICECLIENT_H__ diff --git a/linux/ibus-keyman/src/engine.c b/linux/ibus-keyman/src/engine.c index 4934eac470..49b9161f9a 100644 --- a/linux/ibus-keyman/src/engine.c +++ b/linux/ibus-keyman/src/engine.c @@ -34,7 +34,7 @@ #include "config.h" #include "keymanutil.h" #include "keyman-service.h" -#include "keyman-system-service-client.h" +#include "KeymanSystemServiceClient.h" #include "engine.h" #include "keycodes.h" diff --git a/linux/ibus-keyman/src/keyman-system-service-client.c b/linux/ibus-keyman/src/keyman-system-service-client.c deleted file mode 100644 index 634521c6d1..0000000000 --- a/linux/ibus-keyman/src/keyman-system-service-client.c +++ /dev/null @@ -1,90 +0,0 @@ -#include -#include "keyman-system-service-client.h" - -extern gboolean testing; - -#define KEYMAN_BUS_NAME "com.keyman.SystemService1" -#define KEYMAN_INTERFACE_NAME "com.keyman.SystemService1.System" -#define KEYMAN_OBJECT_PATH "/com/keyman/SystemService1/System" - -static void -finish(sd_bus_error* error, sd_bus_message* msg, sd_bus * bus) { - if (error) { sd_bus_error_free(error); } - if (msg) { sd_bus_message_unref(msg); } - if (bus) { sd_bus_unref(bus); } -} - -static int get_bus(sd_bus** bus) { - if (testing) { - return sd_bus_open_user(bus); - } - return sd_bus_default_system(bus); -} - -void set_capslock_indicator( - guint32 capsLock -) { - sd_bus_error error = SD_BUS_ERROR_NULL; - sd_bus_message* msg = NULL; - sd_bus* bus = NULL; - int result; - - if (capsLock > 1) { - g_error("%s: Invalid value '%d' for parameter capsLock", __FUNCTION__, capsLock); - return; - } - - result = get_bus(&bus); - if (result < 0) { - g_error("%s: Can't get connection: %s", __FUNCTION__, strerror(-result)); - finish(&error, msg, bus); - return; - } - - result = sd_bus_call_method( - bus, KEYMAN_BUS_NAME, KEYMAN_OBJECT_PATH, KEYMAN_INTERFACE_NAME, - "SetCapsLockIndicator", &error, &msg, "b", capsLock); - if (result < 0) { - g_error("%s: Failed to call method SetCapsLockIndicator: %s. %s. %s.", - __FUNCTION__, strerror(-result), error.name, error.message); - finish(&error, msg, bus); - return; - } - - finish(&error, msg, bus); -} - -gint32 get_capslock_indicator() { - sd_bus_error error = SD_BUS_ERROR_NULL; - sd_bus_message* msg = NULL; - sd_bus* bus = NULL; - guint32 capsLock = 0; - int result; - - result = get_bus(&bus); - if (result < 0) { - g_error("%s: Can't get connection: %s", __FUNCTION__, strerror(-result)); - finish(&error, msg, bus); - return -1; - } - - result = sd_bus_call_method( - bus, KEYMAN_BUS_NAME, KEYMAN_OBJECT_PATH, KEYMAN_INTERFACE_NAME, - "GetCapsLockIndicator", &error, &msg, ""); - if (result < 0) { - g_error("%s: Failed to call method GetCapsLockIndicator: %s. %s. %s.", - __FUNCTION__, strerror(-result), error.name, error.message); - finish(&error, msg, bus); - return -1; - } - - result = sd_bus_message_read(msg, "b", &capsLock); - if (result < 0) { - g_error("%s: Failed to parse response message: %s", __FUNCTION__, strerror(-result)); - finish(&error, msg, bus); - return -1; - } - - finish(&error, msg, bus); - return capsLock; -} diff --git a/linux/ibus-keyman/src/meson.build b/linux/ibus-keyman/src/meson.build index 0fe6c75bb7..2e83a65106 100644 --- a/linux/ibus-keyman/src/meson.build +++ b/linux/ibus-keyman/src/meson.build @@ -7,7 +7,7 @@ engine_files = files( 'main.c', 'engine.c', 'keyman-service.c', - 'keyman-system-service-client.c', + 'KeymanSystemServiceClient.cpp', ) include_dirs = [ diff --git a/linux/ibus-keyman/tests/km-dbus-test-server.c b/linux/ibus-keyman/tests/KmDbusTestServer.cpp similarity index 72% rename from linux/ibus-keyman/tests/km-dbus-test-server.c rename to linux/ibus-keyman/tests/KmDbusTestServer.cpp index 1598a7a9ec..1d4746163d 100644 --- a/linux/ibus-keyman/tests/km-dbus-test-server.c +++ b/linux/ibus-keyman/tests/KmDbusTestServer.cpp @@ -1,5 +1,8 @@ -// DBus test server. The server will start and listen on a +// DBus test server. The server will start and listen on a non-standard DBus. +// It runs until the DBus Exit method gets called. +#include #include +#include #include #ifndef KEYMAN_TEST_SERVICE_PATH @@ -11,37 +14,21 @@ #define KEYMAN_TESTSVC_INTERFACE_NAME "com.keyman.ExitTestService.Exit" #define KEYMAN_TESTSVC_OBJECT_PATH "/com/keyman/ExitTestService/Exit" -static GTestDBus * -startup() { - GTestDBus *dbus = g_test_dbus_new(G_TEST_DBUS_NONE); +using namespace std; - // Add the private directory with our in-tree service files. - g_test_dbus_add_service_dir(dbus, KEYMAN_TEST_SERVICE_PATH); - - printf("Add service dir to %s\n", KEYMAN_TEST_SERVICE_PATH); - - // Start the private D-Bus daemon - g_test_dbus_up(dbus); - - const gchar *address = g_test_dbus_get_bus_address(dbus); - - printf("Test server running on: %s\n", address); - FILE *f = fopen("/tmp/km-test-server.env", "w"); - if (f) { - // write the address to a file which can be sourced - fprintf(f, "export DBUS_SESSION_BUS_ADDRESS=%s\n", address); - fclose(f); - } +class KmDbusTestServer +{ +private: + GTestDBus *dbus; + sd_bus_slot *slot = NULL; + sd_bus *bus = NULL; - return dbus; -} +public: + KmDbusTestServer(); + ~KmDbusTestServer(); -static void -finish(GTestDBus *dbus) { - // Stop the private D-Bus daemon - g_test_dbus_down(dbus); - g_object_unref(dbus); -} + void Loop(); +}; static int32_t on_exit_method(sd_bus_message *msg, void *user_data, sd_bus_error *ret_error) { @@ -58,23 +45,48 @@ static const sd_bus_vtable exit_test_service_vtable[] = { SD_BUS_VTABLE_END }; -static const void exit_loop(sd_bus_slot *slot, sd_bus *bus) { +KmDbusTestServer::KmDbusTestServer() +{ + dbus = g_test_dbus_new(G_TEST_DBUS_NONE); + + // Add the private directory with our in-tree service files. + g_test_dbus_add_service_dir(dbus, KEYMAN_TEST_SERVICE_PATH); + + std::cout << "Add service dir to " << KEYMAN_TEST_SERVICE_PATH << std::endl; + + // Start the private D-Bus daemon + g_test_dbus_up(dbus); + + const gchar *address = g_test_dbus_get_bus_address(dbus); + + std::cout << "Test server running on: " << address << std::endl; + + ofstream file("/tmp/km-test-server.env", ios_base::out); + if (file) { + // write the address to a file which can be sourced + file << "export DBUS_SESSION_BUS_ADDRESS=" << address << std::endl; + file.close(); + } +} + +KmDbusTestServer::~KmDbusTestServer() +{ if (bus) sd_bus_release_name(bus, KEYMAN_TESTSVC_BUS_NAME); if (slot) sd_bus_slot_unref(slot); if (bus) sd_bus_close_unref(bus); + + g_test_dbus_down(dbus); + g_object_unref(dbus); } -static void -loop() { - sd_bus_slot *slot = NULL; - sd_bus *bus = NULL; +void KmDbusTestServer::Loop() +{ int ret; ret = sd_bus_open_user(&bus); if (ret < 0) { g_error("Failed to connect to system bus: %s", strerror(-ret)); - exit_loop(slot, bus); return; } @@ -85,7 +97,6 @@ loop() { KEYMAN_TESTSVC_INTERFACE_NAME, exit_test_service_vtable, &exitFlag); if (ret < 0) { g_error("Failed to issue method call: %s", strerror(-ret)); - exit_loop(slot, bus); return; } @@ -93,7 +104,6 @@ loop() { ret = sd_bus_request_name(bus, KEYMAN_TESTSVC_BUS_NAME, 0); if (ret < 0) { g_error("Failed to acquire service name: %s", strerror(-ret)); - exit_loop(slot, bus); return; } @@ -103,39 +113,34 @@ loop() { g_debug("sd_bus_process returned %d, exitFlag=%d", ret, exitFlag); if (ret < 0) { g_error("Failed to process bus: %s", strerror(-ret)); - exit_loop(slot, bus); return; } if (exitFlag) { + // `exitFlag` can be modified by the callback function + // `on_exit_method` which can be called by `sd_bus_process` g_debug("Exiting loop"); - exit_loop(slot, bus); return; } - if (ret > 0) // we processed a request, try to process another one, right-away + if (ret > 0) { + // we processed a request, try to process another one, right-away continue; + } // Wait for the next request to process ret = sd_bus_wait(bus, (uint64_t)-1); g_debug("sd_bus_wait returned %d", ret); if (ret < 0) { g_error("Failed to wait on bus: %s", strerror(-ret)); - exit_loop(slot, bus); return; } } - exit_loop(slot, bus); } int main(int argc, char *argv[]) { - GTestDBus *dbus; - - dbus = startup(); - - loop(); - - finish(dbus); + KmDbusTestServer testServer; + testServer.Loop(); return 0; } diff --git a/linux/ibus-keyman/tests/StopTestServer.cpp b/linux/ibus-keyman/tests/StopTestServer.cpp new file mode 100644 index 0000000000..97ce5bfbe7 --- /dev/null +++ b/linux/ibus-keyman/tests/StopTestServer.cpp @@ -0,0 +1,58 @@ +// Call the Exit method on the km-dbus-test-server. Remember to source +// `/tmp/km-test-server.env` prior to running stop-test-server in order +// to run on our non-standard DBus. +#include +#include + +using namespace std; + +class StopTestServer +{ +private: + sd_bus_error* error = NULL; + sd_bus_message* msg = NULL; + sd_bus* bus = NULL; + +public: + StopTestServer(); + ~StopTestServer(); + + int Run(); +}; + +StopTestServer::StopTestServer() +{ +} + +StopTestServer::~StopTestServer() +{ + if (error) { sd_bus_error_free(error); } + if (msg) { sd_bus_message_unref(msg); } + if (bus) { sd_bus_unref(bus); } +} + +int StopTestServer::Run() +{ + int result; + + result = sd_bus_open_user(&bus); + if (result < 0) { + std::cerr << "Can't get connection: " << strerror(-result) << std::endl; + return 1; + } + + result = sd_bus_call_method(bus, "com.keyman.ExitTestService", + "/com/keyman/ExitTestService/Exit", "com.keyman.ExitTestService.Exit", + "Exit", error, &msg, ""); + if (result < 0) { + std::cerr << "Failed to issue method call: " << strerror(-result) << std::endl; + return 1; + } + return 0; +} + +int +main(int argc, char* argv[]) { + StopTestServer stopServer; + return stopServer.Run(); +} diff --git a/linux/ibus-keyman/tests/meson.build b/linux/ibus-keyman/tests/meson.build index 2b742e6ff6..130e3b8bce 100644 --- a/linux/ibus-keyman/tests/meson.build +++ b/linux/ibus-keyman/tests/meson.build @@ -2,7 +2,7 @@ test_files = [ 'ibusimcontext.c', 'testfixture.cpp', 'testmodule.c', - '../src/keyman-system-service-client.c', + '../src/KeymanSystemServiceClient.cpp', ] kmnkbp_tests_lib = cc.find_library( @@ -36,16 +36,16 @@ system_service_dir = meson.current_source_dir() / '../../keyman-system-service/b dbus_test_server = executable( 'km-dbus-test-server', - 'km-dbus-test-server.c', + 'KmDbusTestServer.cpp', dependencies: dbus_deps, - c_args: [ + cpp_args: [ '-DKEYMAN_TEST_SERVICE_PATH="' + system_service_dir + '"' ] ) stop_test_server = executable( 'stop-test-server', - 'stop-test-server.c', + 'StopTestServer.cpp', dependencies: dbus_deps, ) diff --git a/linux/ibus-keyman/tests/scripts/run-tests.sh b/linux/ibus-keyman/tests/scripts/run-tests.sh index 2f685e8807..92cae307ed 100755 --- a/linux/ibus-keyman/tests/scripts/run-tests.sh +++ b/linux/ibus-keyman/tests/scripts/run-tests.sh @@ -57,7 +57,7 @@ function run_tests() { elif [ -d "$(dirname "$0")/../../../build/$(arch)/release" ]; then CONFIG=release else - echo "Can't find neither ../../../build/$(arch)/debug nor ../../../build/$(arch)/release" + echo "Cannot find ../../../build/$(arch)/debug or ../../../build/$(arch)/release" exit 9 fi diff --git a/linux/ibus-keyman/tests/stop-test-server.c b/linux/ibus-keyman/tests/stop-test-server.c deleted file mode 100644 index 311131c5d1..0000000000 --- a/linux/ibus-keyman/tests/stop-test-server.c +++ /dev/null @@ -1,34 +0,0 @@ -#include - -void -finish(sd_bus_error* error, sd_bus_message* msg, sd_bus * bus) { - if (error) { sd_bus_error_free(error); } - if (msg) { sd_bus_message_unref(msg); } - if (bus) { sd_bus_unref(bus); } -} - -int main(int argc, char* argv[]) { - sd_bus_error error = SD_BUS_ERROR_NULL; - sd_bus_message* msg = NULL; - sd_bus* bus = NULL; - int result; - - result = sd_bus_open_user(&bus); - if (result < 0) { - fprintf(stderr, "Can't get connection: %s", strerror(-result)); - finish(&error, msg, bus); - return 1; - } - - result = sd_bus_call_method( - bus, "com.keyman.ExitTestService", "/com/keyman/ExitTestService/Exit", - "com.keyman.ExitTestService.Exit", "Exit", &error, &msg, ""); - if (result < 0) { - fprintf(stderr, "Failed to issue method call: %s", strerror(-result)); - finish(&error, msg, bus); - return 1; - } - - finish(&error, msg, bus); - return 0; -} diff --git a/linux/ibus-keyman/tests/testfixture.cpp b/linux/ibus-keyman/tests/testfixture.cpp index b811148c8f..84aab933c8 100644 --- a/linux/ibus-keyman/tests/testfixture.cpp +++ b/linux/ibus-keyman/tests/testfixture.cpp @@ -13,7 +13,7 @@ #include "ibusimcontext.h" #include "keycodes.h" #include "keymanutil.h" -#include "keyman-system-service-client.h" +#include "KeymanSystemServiceClient.h" #include "kmx_test_source.hpp" #include "testmodule.h" diff --git a/linux/keyman-system-service/build.sh b/linux/keyman-system-service/build.sh index ce62dbcec3..9b248c5113 100755 --- a/linux/keyman-system-service/build.sh +++ b/linux/keyman-system-service/build.sh @@ -22,7 +22,7 @@ builder_parse "$@" cd "$THIS_SCRIPT_PATH/" -if builder_has_option --debug; then +if builder_is_debug_build; then MESON_TARGET=debug export CPPFLAGS=-DG_MESSAGES_DEBUG export CFLAGS="-O0" @@ -36,17 +36,10 @@ builder_describe_outputs \ configure "${MESON_PATH}/build.ninja" \ build "${MESON_PATH}/src/keyman-system-service" -if builder_start_action clean; then - rm -rf "$THIS_SCRIPT_PATH/build/" - builder_finish_action success clean -fi +builder_run_action clean rm -rf "$THIS_SCRIPT_PATH/build/" -if builder_start_action configure; then - cd "$THIS_SCRIPT_PATH" - # shellcheck disable=SC2086 - meson setup "$MESON_PATH" --werror --buildtype $MESON_TARGET "${builder_extra_params[@]}" - builder_finish_action success configure -fi +# shellcheck disable=SC2086 +builder_run_action configure meson setup "$MESON_PATH" --werror --buildtype $MESON_TARGET "${builder_extra_params[@]}" if builder_start_action build; then cd "$MESON_PATH" diff --git a/linux/keyman-system-service/src/KeyboardDevice.cpp b/linux/keyman-system-service/src/KeyboardDevice.cpp index c93b86f5d3..a744a96b82 100644 --- a/linux/keyman-system-service/src/KeyboardDevice.cpp +++ b/linux/keyman-system-service/src/KeyboardDevice.cpp @@ -10,17 +10,20 @@ using namespace std; KeyboardDevice::KeyboardDevice() { - this->dev = nullptr; - this->fd = -1; - this->hasCapsLockLed = -1; - this->debug = false; + dev = nullptr; + fd = -1; + hasCapsLockLed = -1; + debug = false; } KeyboardDevice::~KeyboardDevice() { - libevdev_free(this->dev); - if (this->fd != -1) - close(this->fd); + if (dev) { + libevdev_free(dev); + } + if (fd != -1) { + close(fd); + } } bool KeyboardDevice::Initialize(const char* name) @@ -28,17 +31,17 @@ bool KeyboardDevice::Initialize(const char* name) string path("/dev/input/"); path.append(name); - this->fd = open(path.c_str(), O_RDWR); - if (this->fd < 0) { + fd = open(path.c_str(), O_RDWR); + if (fd < 0) { std::cerr << "Failed to open device " << path << ": " << strerror(errno) << std::endl; return false; } - int rc = libevdev_new_from_fd(this->fd, &this->dev); + int rc = libevdev_new_from_fd(fd, &dev); if (rc < 0) { std::cerr << "Failed to init libevdev for " << path << ": " << strerror(-rc) << std::endl; - close(this->fd); - this->fd = -1; + close(fd); + fd = -1; return false; } @@ -47,27 +50,27 @@ bool KeyboardDevice::Initialize(const char* name) bool KeyboardDevice::HasCapsLockLed() { - if (this->hasCapsLockLed < 0) { - if (!libevdev_has_event_code(this->dev, EV_LED, LED_CAPSL)) { - this->hasCapsLockLed = 0; - if (this->debug) { - std::cerr << "Device '" << libevdev_get_name(this->dev) << "' doesn't have " + if (hasCapsLockLed < 0) { + if (!libevdev_has_event_code(dev, EV_LED, LED_CAPSL)) { + hasCapsLockLed = 0; + if (debug) { + std::cerr << "Device '" << libevdev_get_name(dev) << "' doesn't have " << libevdev_event_code_get_name(EV_LED, LED_CAPSL) << "." << std::endl; } } else { - this->hasCapsLockLed = 1; + hasCapsLockLed = 1; } } - return this->hasCapsLockLed == 1; + return hasCapsLockLed == 1; } void KeyboardDevice::SetCapsLockLed(bool on) { - if (!this->HasCapsLockLed()) { + if (!HasCapsLockLed()) { return; } - int rc = libevdev_kernel_set_led_value(this->dev, LED_CAPSL, on ? LIBEVDEV_LED_ON : LIBEVDEV_LED_OFF); + int rc = libevdev_kernel_set_led_value(dev, LED_CAPSL, on ? LIBEVDEV_LED_ON : LIBEVDEV_LED_OFF); if (rc != 0) { std::cerr << "Failed to set LED " << libevdev_event_code_get_name(EV_LED, LED_CAPSL) << ": " << strerror(-rc) << std::endl; @@ -76,10 +79,10 @@ void KeyboardDevice::SetCapsLockLed(bool on) bool KeyboardDevice::GetCapsLockLed() { - if (!this->HasCapsLockLed()) { + if (!HasCapsLockLed()) { return false; } - int val = libevdev_get_event_value(this->dev, EV_LED, LED_CAPSL); + int val = libevdev_get_event_value(dev, EV_LED, LED_CAPSL); return val; } diff --git a/linux/keyman-system-service/src/KeymanSystemService.cpp b/linux/keyman-system-service/src/KeymanSystemService.cpp new file mode 100644 index 0000000000..deceafd0c3 --- /dev/null +++ b/linux/keyman-system-service/src/KeymanSystemService.cpp @@ -0,0 +1,195 @@ +// This file implements a service which will run on the system dbus, +// based on the sd-bus library, see +// https://0pointer.net/blog/the-new-sd-bus-api-of-systemd.html + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "KeymanSystemService.h" +#include "KeyboardDevice.h" + +#define KEYMAN_BUS_NAME "com.keyman.SystemService1" +#define KEYMAN_INTERFACE_NAME "com.keyman.SystemService1.System" +#define KEYMAN_OBJECT_PATH "/com/keyman/SystemService1/System" + +using namespace std; + +static int32_t +on_set_caps_lock_indicator( + sd_bus_message *msg, + void *user_data, + sd_bus_error *ret_error +) { + int32_t ret; + uint32_t state; + + *ret_error = SD_BUS_ERROR_NULL; + + ret = sd_bus_message_read_basic(msg, 'b', &state); + if (ret < 0) { + syslog(LOG_USER | LOG_NOTICE, "Failed to parse parameter: %s", strerror(-ret)); + return ret; + } + + KeymanSystemService *service = static_cast(user_data); + service->SetCapsLockIndicatorOnDevices(state); + return sd_bus_reply_method_return(msg, ""); +} + +static int32_t +on_get_caps_lock_indicator( + sd_bus_message *msg, + void *user_data, + sd_bus_error *ret_error +) { + uint32_t state; + + *ret_error = SD_BUS_ERROR_NULL; + + KeymanSystemService *service = static_cast(user_data); + state = service->GetCapsLockIndicatorOnDevices(); + return sd_bus_reply_method_return(msg, "b", state); +} + +static const sd_bus_vtable system_service_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_METHOD("SetCapsLockIndicator", "b", "", on_set_caps_lock_indicator, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetCapsLockIndicator", "", "b", on_get_caps_lock_indicator, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_VTABLE_END +}; + +KeymanSystemService::KeymanSystemService() +{ + int ret; + + GetKbdDevices(); + +#ifdef KEYMAN_TESTING + ret = sd_bus_open_user(&bus); +#else + ret = sd_bus_open_system(&bus); +#endif + + if (ret < 0) { + syslog(LOG_USER | LOG_NOTICE, "Failed to connect to system bus: %s", strerror(-ret)); + failed = true; + return; + } + + // Install the object + ret = sd_bus_add_object_vtable(bus, + &slot, + KEYMAN_OBJECT_PATH, + KEYMAN_INTERFACE_NAME, + system_service_vtable, + this); + if (ret < 0) { + syslog(LOG_USER | LOG_NOTICE, "Failed to issue method call: %s", strerror(-ret)); + failed = true; + return; + } + + // Take a well-known service name so that clients can find us + ret = sd_bus_request_name(bus, KEYMAN_BUS_NAME, 0); + if (ret < 0) { + syslog(LOG_USER | LOG_NOTICE, "Failed to acquire service name: %s", strerror(-ret)); + failed = true; + return; + } +} + +KeymanSystemService::~KeymanSystemService() +{ + if (slot) sd_bus_slot_unref(slot); + if (bus) sd_bus_unref(bus); + + if (kbd_devices) { + for (KeyboardDevice *device : *kbd_devices) { + delete device; + } + delete kbd_devices; + } +} + +int KeymanSystemService::Loop() +{ + for (;;) { + // Process requests + int ret = sd_bus_process(bus, NULL); + if (ret < 0) { + syslog(LOG_USER | LOG_NOTICE, "Failed to process bus: %s", strerror(-ret)); + failed = true; + return ret; + } + if (ret > 0) { + // we processed a request, try to process another one, right-away + continue; + } + + // Wait for the next request to process + ret = sd_bus_wait(bus, (uint64_t)-1); + if (ret < 0) { + syslog(LOG_USER | LOG_NOTICE, "Failed to wait on bus: %s", strerror(-ret)); + failed = true; + return ret; + } + } + return 0; +} + +void KeymanSystemService::GetKbdDevices() { + kbd_devices = new std::list(); + + DIR *dirstream; + struct dirent *dir; + dirstream = opendir("/dev/input"); + if (dirstream) { + while ((dir = readdir(dirstream)) != NULL) { + // we're looking for a character device like `event1` + if (dir->d_type == DT_CHR && strncmp(dir->d_name, "event", 5) == 0) { + KeyboardDevice *kbdDevice = new KeyboardDevice(); + if (!kbdDevice->Initialize(dir->d_name) || !kbdDevice->HasCapsLockLed()) { + delete kbdDevice; + continue; + } + kbd_devices->push_back(kbdDevice); + } + } + closedir(dirstream); + } +} + +// Set the CapsLock indicator on all keyboard devices. +void +KeymanSystemService::SetCapsLockIndicatorOnDevices(uint32_t state) { + for (KeyboardDevice *kbdDevice : *kbd_devices) { + if (!kbdDevice->HasCapsLockLed()) { + syslog(LOG_USER | LOG_NOTICE, "%s: No kbdDevice or no CapsLockLed", __FUNCTION__); + continue; + } + syslog(LOG_USER | LOG_NOTICE, "%s: Caps Lock indicator: %s", __FUNCTION__, (state != 0 ? "ON" : "OFF")); + kbdDevice->SetCapsLockLed(state != 0); + } +} + +// Get the CapsLock indicator state from the list of keyboard devices. +// This will return true if any keyboard has the CapsLock indicator lit. +uint32_t +KeymanSystemService::GetCapsLockIndicatorOnDevices() { + bool state = false; + for (KeyboardDevice *kbdDevice : *kbd_devices) { + if (!kbdDevice->HasCapsLockLed()) { + syslog(LOG_USER | LOG_NOTICE, "%s: No kbdDevice or no CapsLockLed", __FUNCTION__); + continue; + } + state = state || kbdDevice->GetCapsLockLed(); + } + return state; +} diff --git a/linux/keyman-system-service/src/KeymanSystemService.h b/linux/keyman-system-service/src/KeymanSystemService.h new file mode 100644 index 0000000000..2686bfb99f --- /dev/null +++ b/linux/keyman-system-service/src/KeymanSystemService.h @@ -0,0 +1,33 @@ +#ifndef __KEYMANSYSTEMSERVICE_H__ +#define __KEYMANSYSTEMSERVICE_H__ + +#include +#include +#include "KeyboardDevice.h" + +using namespace std; + +class KeymanSystemService { +private: + std::list* kbd_devices = NULL; + sd_bus_slot *slot = NULL; + sd_bus *bus = NULL; + bool failed = false; + + void GetKbdDevices(); + +public: + KeymanSystemService(); + ~KeymanSystemService(); + + bool + Failed() { + return failed; + } + + int Loop(); + void SetCapsLockIndicatorOnDevices(uint32_t state); + uint32_t GetCapsLockIndicatorOnDevices(); +}; + +#endif // __KEYMANSYSTEMSERVICE_H__ diff --git a/linux/keyman-system-service/src/ServerMethods.cpp b/linux/keyman-system-service/src/ServerMethods.cpp deleted file mode 100644 index 41e81b0b40..0000000000 --- a/linux/keyman-system-service/src/ServerMethods.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include "KeyboardDevice.h" -#include "ServerMethods.h" - -void * -get_kbd_devices() -{ - std::list* kbd_devices = new std::list(); - - DIR *dirstream; - struct dirent *dir; - dirstream = opendir("/dev/input"); - if (dirstream) { - while ((dir = readdir(dirstream)) != NULL) { - // we're looking for a character device like `event1` - if (dir->d_type == DT_CHR && strncmp(dir->d_name, "event", 5) == 0) { - KeyboardDevice *kbdDevice = new KeyboardDevice(); - if (!kbdDevice->Initialize(dir->d_name) || !kbdDevice->HasCapsLockLed()) { - delete kbdDevice; - continue; - } - kbd_devices->push_back(kbdDevice); - } - } - closedir(dirstream); - } - - return kbd_devices; -} - -void -close_kbd_devices( - void * data -) { - std::list *kbd_devices = static_cast*>(data); - for (KeyboardDevice *device : *kbd_devices) { - delete device; - } - delete kbd_devices; -} - -void -set_caps_lock_indicator_on_devices( - void *data, - void *user_data -) { - std::list *kbd_devices = static_cast*>(data); - uint *state = static_cast(user_data); - for (KeyboardDevice *kbdDevice : *kbd_devices) { - if (!kbdDevice->HasCapsLockLed()) { - syslog(LOG_USER | LOG_NOTICE, "%s: No kbdDevice or no CapsLockLed", __FUNCTION__); - continue; - } - syslog(LOG_USER | LOG_NOTICE, "%s: Caps Lock indicator: %s", __FUNCTION__, (*state != 0 ? "ON" : "OFF")); - kbdDevice->SetCapsLockLed(*state != 0); - } -} - -uint32_t -get_caps_lock_indicator_on_devices( - void *data -) { - std::list *kbd_devices = static_cast*>(data); - bool state = false; - for (KeyboardDevice *kbdDevice : *kbd_devices) { - if (!kbdDevice->HasCapsLockLed()) { - syslog(LOG_USER | LOG_NOTICE, "%s: No kbdDevice or no CapsLockLed", __FUNCTION__); - continue; - } - state |= kbdDevice->GetCapsLockLed(); - } - return state; -} diff --git a/linux/keyman-system-service/src/ServerMethods.h b/linux/keyman-system-service/src/ServerMethods.h deleted file mode 100644 index e03ec33b0a..0000000000 --- a/linux/keyman-system-service/src/ServerMethods.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __SERVERMETHODS_H__ -#define __SERVERMETHODS_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -void* get_kbd_devices(); -void close_kbd_devices(void *data); -void set_caps_lock_indicator_on_devices(void *data, void *user_data); -uint32_t get_caps_lock_indicator_on_devices(void *data); - -#ifdef __cplusplus -} -#endif - -#endif // __SERVERMETHODS_H__ diff --git a/linux/keyman-system-service/src/dbus-service.c b/linux/keyman-system-service/src/dbus-service.c deleted file mode 100644 index eafe4da857..0000000000 --- a/linux/keyman-system-service/src/dbus-service.c +++ /dev/null @@ -1,121 +0,0 @@ -// This file implements a service which will run on the system dbus, -// based on the sd-bus library, see -// https://0pointer.net/blog/the-new-sd-bus-api-of-systemd.html - -#include -#include -#include -#include "ServerMethods.h" - -#define KEYMAN_BUS_NAME "com.keyman.SystemService1" -#define KEYMAN_INTERFACE_NAME "com.keyman.SystemService1.System" -#define KEYMAN_OBJECT_PATH "/com/keyman/SystemService1/System" - -static int32_t -on_set_caps_lock_indicator( - sd_bus_message *msg, - void *user_data, - sd_bus_error *ret_error -) { - int32_t ret; - uint32_t state; - - ret_error = NULL; - - ret = sd_bus_message_read_basic(msg, 'b', &state); - if (ret < 0) { - syslog(LOG_USER | LOG_NOTICE, "Failed to parse parameter: %s", strerror(-ret)); - return ret; - } - - set_caps_lock_indicator_on_devices(user_data, &state); - return sd_bus_reply_method_return(msg, ""); -} - -static int32_t -on_get_caps_lock_indicator( - sd_bus_message *msg, - void *user_data, - sd_bus_error *ret_error -) { - uint32_t state; - - ret_error = NULL; - - state = get_caps_lock_indicator_on_devices(user_data); - return sd_bus_reply_method_return(msg, "b", state); -} - -static const sd_bus_vtable system_service_vtable[] = { - SD_BUS_VTABLE_START(0), - SD_BUS_METHOD("SetCapsLockIndicator", "b", "", on_set_caps_lock_indicator, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("GetCapsLockIndicator", "", "b", on_get_caps_lock_indicator, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_VTABLE_END -}; - -static int finish(int ret, void *kbd_devices, sd_bus_slot *slot, sd_bus *bus) { - close_kbd_devices(kbd_devices); - sd_bus_slot_unref(slot); - sd_bus_unref(bus); - - return ret < 0 ? 1 : 0; -} - -int main(int argc, char *argv[]) { - void *kbd_devices = NULL; - sd_bus_slot *slot = NULL; - sd_bus *bus = NULL; - int ret; - - kbd_devices = get_kbd_devices(); - -#ifdef KEYMAN_TESTING - ret = sd_bus_open_user(&bus); -#else - ret = sd_bus_open_system(&bus); -#endif - - if (ret < 0) { - syslog(LOG_USER | LOG_NOTICE, "Failed to connect to system bus: %s", strerror(-ret)); - return finish(ret, kbd_devices, slot, bus); - } - - // Install the object - ret = sd_bus_add_object_vtable(bus, - &slot, - KEYMAN_OBJECT_PATH, - KEYMAN_INTERFACE_NAME, - system_service_vtable, - kbd_devices); - if (ret < 0) { - syslog(LOG_USER | LOG_NOTICE, "Failed to issue method call: %s", strerror(-ret)); - return finish(ret, kbd_devices, slot, bus); - } - - // Take a well-known service name so that clients can find us - ret = sd_bus_request_name(bus, KEYMAN_BUS_NAME, 0); - if (ret < 0) { - syslog(LOG_USER | LOG_NOTICE, "Failed to acquire service name: %s", strerror(-ret)); - return finish(ret, kbd_devices, slot, bus); - } - - for (;;) { - // Process requests - ret = sd_bus_process(bus, NULL); - if (ret < 0) { - syslog(LOG_USER | LOG_NOTICE, "Failed to process bus: %s", strerror(-ret)); - return finish(ret, kbd_devices, slot, bus); - } - if (ret > 0) // we processed a request, try to process another one, right-away - continue; - - // Wait for the next request to process - ret = sd_bus_wait(bus, (uint64_t) -1); - if (ret < 0) { - syslog(LOG_USER | LOG_NOTICE, "Failed to wait on bus: %s", strerror(-ret)); - return finish(ret, kbd_devices, slot, bus); - } - } - - return finish(0, kbd_devices, slot, bus); -} diff --git a/linux/keyman-system-service/src/main.cpp b/linux/keyman-system-service/src/main.cpp new file mode 100644 index 0000000000..9a2bb2d0de --- /dev/null +++ b/linux/keyman-system-service/src/main.cpp @@ -0,0 +1,10 @@ +#include "KeymanSystemService.h" + +int main(int argc, char *argv[]) { + KeymanSystemService dbusService; + if (dbusService.Failed()) { + return 1; + } + + return dbusService.Loop(); +} diff --git a/linux/keyman-system-service/src/meson.build b/linux/keyman-system-service/src/meson.build index b5993d0319..51820ab9fa 100644 --- a/linux/keyman-system-service/src/meson.build +++ b/linux/keyman-system-service/src/meson.build @@ -1,7 +1,7 @@ service_files = files( - 'dbus-service.c', 'KeyboardDevice.cpp', - 'ServerMethods.cpp', + 'KeymanSystemService.cpp', + 'main.cpp', ) deps = [evdev, systemd] diff --git a/linux/keyman-system-service/tests/KeyboardDeviceMock.cpp b/linux/keyman-system-service/tests/KeyboardDeviceMock.cpp index 1baa20dcb8..dbaa6aafab 100644 --- a/linux/keyman-system-service/tests/KeyboardDeviceMock.cpp +++ b/linux/keyman-system-service/tests/KeyboardDeviceMock.cpp @@ -15,10 +15,10 @@ using namespace std; KeyboardDeviceMock::KeyboardDeviceMock() { - this->dev = nullptr; - this->fd = -1; - this->hasCapsLockLed = 1; - this->debug = false; + dev = nullptr; + fd = -1; + hasCapsLockLed = 1; + debug = false; } KeyboardDeviceMock::~KeyboardDeviceMock() { @@ -36,10 +36,10 @@ KeyboardDeviceMock::HasCapsLockLed() { void KeyboardDeviceMock::SetCapsLockLed(bool on) { - this->hasCapsLockLed = on ? 1 : 0; + hasCapsLockLed = on ? 1 : 0; } bool KeyboardDeviceMock::GetCapsLockLed() { - return this->hasCapsLockLed == 1; + return hasCapsLockLed == 1; } diff --git a/linux/keyman-system-service/tests/meson.build b/linux/keyman-system-service/tests/meson.build index 3ed97cde13..f90e12d16a 100644 --- a/linux/keyman-system-service/tests/meson.build +++ b/linux/keyman-system-service/tests/meson.build @@ -1,6 +1,6 @@ test_service_files = files( - '../src/dbus-service.c', - '../src/ServerMethods.cpp', + '../src/main.cpp', + '../src/KeymanSystemService.cpp', 'KeyboardDeviceMock.cpp', ) diff --git a/linux/scripts/dist.sh b/linux/scripts/dist.sh index f81013f94f..f8d63b63e3 100755 --- a/linux/scripts/dist.sh +++ b/linux/scripts/dist.sh @@ -58,7 +58,8 @@ dpkg-source --tar-ignore=*~ --tar-ignore=.git --tar-ignore=.gitattributes \ --tar-ignore=resources/devbox --tar-ignore=resources/git-hooks \ --tar-ignore=resources/scopes \ --tar-ignore=resources/build/*.lua --tar-ignore=resources/build/jq* \ - --tar-ignore=results --tar-ignore=tmp \ + --tar-ignore=results \ + --tar-ignore=tmp \ --tar-ignore=web --tar-ignore=windows --tar-ignore=keyman_1* \ --tar-ignore=dist --tar-ignore=.pbuilderrc --tar-ignore=VERSION -Zgzip -b . mv ../keyman_"${VERSION}".tar.gz linux/dist/keyman-"${VERSION}".tar.gz -- GitLab From e746ec1c0cb637bea9883df9d52bc58b2957a9bf Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Mon, 22 May 2023 14:01:39 -0400 Subject: [PATCH 132/214] auto: increment master version to 17.0.111 --- HISTORY.md | 4 ++++ VERSION.md | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 213b87a6f8..9841e4b838 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,9 @@ # Keyman Version History +## 17.0.110 alpha 2023-05-22 + +* fix(common): ensure child builds don't rebuild dependencies unnecessarily (#8834) + ## 17.0.109 alpha 2023-05-17 * fix(windows): add wrap-symbols to Text Editor Makefile (#8819) diff --git a/VERSION.md b/VERSION.md index 18bc0b4cd1..15aebb389a 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.110 \ No newline at end of file +17.0.111 \ No newline at end of file -- GitLab From 110514e9a63c4e46a4405f61c29252913e1d2e17 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Tue, 23 May 2023 06:56:15 +0700 Subject: [PATCH 133/214] fix(android/app): Pathing for publish script --- android/build-publish.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/android/build-publish.sh b/android/build-publish.sh index a77903c9fe..29c152c993 100755 --- a/android/build-publish.sh +++ b/android/build-publish.sh @@ -76,6 +76,7 @@ echo "BUILD_FLAGS $BUILD_FLAGS" if [ "$DO_KMAPRO" = true ]; then # Copy Release Notes generateReleaseNotes + cd "$KEYMAN_ROOT/android/KMAPro/" ./gradlew $DAEMON_FLAG $BUILD_FLAGS fi -- GitLab From 3828a5c16b8896f12001c349a8370f1177986f90 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 23 May 2023 08:31:29 +0700 Subject: [PATCH 134/214] refactor(developer): move message tests into test-messages.ts --- .../src/kmc-package/test/test-messages.ts | 186 +++++++++++++++++- .../kmc-package/test/test-package-compiler.ts | 176 ----------------- 2 files changed, 185 insertions(+), 177 deletions(-) diff --git a/developer/src/kmc-package/test/test-messages.ts b/developer/src/kmc-package/test/test-messages.ts index 48976fc6ad..bc827f1840 100644 --- a/developer/src/kmc-package/test/test-messages.ts +++ b/developer/src/kmc-package/test/test-messages.ts @@ -1,9 +1,193 @@ import 'mocha'; -import { verifyCompilerMessagesObject } from '@keymanapp/developer-test-helpers'; +import { assert } from 'chai'; +import { TestCompilerCallbacks, verifyCompilerMessagesObject } from '@keymanapp/developer-test-helpers'; import { CompilerMessages } from '../src/compiler/messages.js'; +import { makePathToFixture } from './helpers/index.js'; +import { KmpCompiler } from '../src/compiler/kmp-compiler.js'; +import { PackageValidation } from '../src/compiler/package-validation.js'; + +const debug = true; +const callbacks = new TestCompilerCallbacks(); describe('CompilerMessages', function () { it('should have a valid CompilerMessages object', function() { return verifyCompilerMessagesObject(CompilerMessages); }); + + + // + // Message tests + // + + function testForMessage(context: Mocha.Context, fixture: string[], messageId?: number) { + context.timeout(10000); + + callbacks.clear(); + + const kpsPath = makePathToFixture(...fixture); + const kmpCompiler = new KmpCompiler(callbacks); + + let kmpJson = kmpCompiler.transformKpsToKmpObject(kpsPath); + if(kmpJson && callbacks.messages.length == 0) { + const validator = new PackageValidation(callbacks); + validator.validate(kpsPath, kmpJson); // we'll ignore return value and rely on the messages + } + + if(kmpJson && callbacks.messages.length == 0) { + // We'll try building the package if we have not yet received any messages + kmpCompiler.buildKmpFile(kpsPath, kmpJson) + } + + if(debug) callbacks.printMessages(); + + if(messageId) { + assert.lengthOf(callbacks.messages, 1); + assert.isTrue(callbacks.hasMessage(messageId)); + } else { + assert.lengthOf(callbacks.messages, 0); + } + } + + // WARN_FileIsNotABinaryKvkFile + + it('should generate WARN_FileIsNotABinaryKvkFile if a non-binary kvk file is included', async function() { + testForMessage(this, ['xml_kvk_file', 'source', 'xml_kvk_file.kps'], CompilerMessages.WARN_FileIsNotABinaryKvkFile); + }); + + it('should not warn if a binary kvk file is included', async function() { + testForMessage(this, ['binary_kvk_file', 'source', 'binary_kvk_file.kps']); + }); + + // ERROR_FollowKeyboardVersionNotAllowedForModelPackages + + it('should generate ERROR_FollowKeyboardVersionNotAllowedForModelPackages if is set for model packages', async function() { + testForMessage(this, ['invalid', 'followkeyboardversion.qaa.sencoten.model.kps'], CompilerMessages.ERROR_FollowKeyboardVersionNotAllowedForModelPackages); + }); + + // ERROR_FollowKeyboardVersionButNoKeyboards + + it('should generate ERROR_FollowKeyboardVersionButNoKeyboards if is set for a package with no keyboards', async function() { + testForMessage(this, ['invalid', 'followkeyboardversion.empty.kps'], CompilerMessages.ERROR_FollowKeyboardVersionButNoKeyboards); + }); + + // ERROR_KeyboardContentFileNotFound + + it('should generate ERROR_KeyboardContentFileNotFound if a is listed in a package but not found in ', async function() { + testForMessage(this, ['invalid', 'keyboardcontentfilenotfound.kps'], CompilerMessages.ERROR_KeyboardContentFileNotFound); + }); + + // ERROR_KeyboardFileNotValid + + it('should generate ERROR_KeyboardFileNotValid if a .kmx is not valid in ', async function() { + testForMessage(this, ['invalid', 'keyboardfilenotvalid.kps'], CompilerMessages.ERROR_KeyboardFileNotValid); + }); + + // INFO_KeyboardFileHasNoKeyboardVersion + + it('should generate INFO_KeyboardFileHasNoKeyboardVersion if is set but keyboard has no version', async function() { + testForMessage(this, ['invalid', 'nokeyboardversion.kps'], CompilerMessages.INFO_KeyboardFileHasNoKeyboardVersion); + }); + + // ERROR_PackageCannotContainBothModelsAndKeyboards + + it('should generate ERROR_PackageCannotContainBothModelsAndKeyboards if package has both keyboards and models', async function() { + testForMessage(this, ['invalid', 'error_package_cannot_contain_both_models_and_keyboards.kps'], CompilerMessages.ERROR_PackageCannotContainBothModelsAndKeyboards); + }); + + // WARN_PackageShouldNotRepeatLanguages (models) + + it('should generate WARN_PackageShouldNotRepeatLanguages if model has same language repeated', async function() { + testForMessage(this, ['invalid', 'keyman.en.warn_package_should_not_repeat_languages.model.kps'], CompilerMessages.WARN_PackageShouldNotRepeatLanguages); + }); + + // WARN_PackageShouldNotRepeatLanguages (keyboards) + + it('should generate WARN_PackageShouldNotRepeatLanguages if keyboard has same language repeated', async function() { + testForMessage(this, ['invalid', 'warn_package_should_not_repeat_languages.kps'], CompilerMessages.WARN_PackageShouldNotRepeatLanguages); + }); + + // WARN_PackageNameDoesNotFollowLexicalModelConventions + + it('should generate WARN_PackageNameDoesNotFollowLexicalModelConventions if filename has wrong conventions', async function() { + testForMessage(this, ['invalid', 'WARN_PackageNameDoesNotFollowLexicalModelConventions.kps'], CompilerMessages.WARN_PackageNameDoesNotFollowLexicalModelConventions); + }); + + // WARN_PackageNameDoesNotFollowKeyboardConventions + + it('should generate WARN_PackageNameDoesNotFollowKeyboardConventions if filename has wrong conventions', async function() { + testForMessage(this, ['invalid', 'WARN_PackageNameDoesNotFollowKeyboardConventions.kps'], CompilerMessages.WARN_PackageNameDoesNotFollowKeyboardConventions); + }); + + // WARN_FileInPackageDoesNotFollowFilenameConventions + + it('should generate WARN_FileInPackageDoesNotFollowFilenameConventions if content filename has wrong conventions', async function() { + testForMessage(this, ['invalid', 'warn_file_in_package_does_not_follow_filename_conventions.kps'], CompilerMessages.WARN_FileInPackageDoesNotFollowFilenameConventions); + testForMessage(this, ['invalid', 'warn_file_in_package_does_not_follow_filename_conventions_2.kps'], CompilerMessages.WARN_FileInPackageDoesNotFollowFilenameConventions); + }); + + // ERROR_PackageNameCannotBeBlank + + it('should generate ERROR_PackageNameCannotBeBlank if package info has empty name', async function() { + testForMessage(this, ['invalid', 'error_package_name_cannot_be_blank.kps'], CompilerMessages.ERROR_PackageNameCannotBeBlank); // blank field + testForMessage(this, ['invalid', 'error_package_name_cannot_be_blank_2.kps'], CompilerMessages.ERROR_PackageNameCannotBeBlank); // missing field + }); + + // ERROR_KeyboardFileNotFound + + it('should generate ERROR_KeyboardFileNotFound if a is listed in a package but not found in ', async function() { + testForMessage(this, ['invalid', 'keyboardfilenotfound.kps'], CompilerMessages.ERROR_KeyboardFileNotFound); + }); + + // WARN_KeyboardVersionsDoNotMatch + + it('should generate WARN_KeyboardVersionsDoNotMatch if two have different versions', async function() { + testForMessage(this, ['invalid', 'warn_keyboard_versions_do_not_match.kps'], CompilerMessages.WARN_KeyboardVersionsDoNotMatch); + }); + + // WARN_KeyboardVersionsDoNotMatchPackageVersion + + it('should generate WARN_KeyboardVersionsDoNotMatchPackageVersion if version does not match package version', async function() { + testForMessage(this, ['invalid', 'warn_keyboard_versions_do_not_match_package_version.kps'], CompilerMessages.WARN_KeyboardVersionsDoNotMatchPackageVersion); + }); + + // ERROR_LanguageTagIsNotValid + + it('should generate ERROR_LanguageTagIsNotValid if keyboard has an invalid language tag', async function() { + testForMessage(this, ['invalid', 'error_language_tag_is_not_valid.kps'], CompilerMessages.ERROR_LanguageTagIsNotValid); + }); + + // WARN_LanguageTagIsNotMinimal + + it('should generate WARN_LanguageTagIsNotMinimal if keyboard has a non-minimal language tag', async function() { + testForMessage(this, ['invalid', 'warn_language_tag_is_not_minimal.kps'], CompilerMessages.WARN_LanguageTagIsNotMinimal); + }); + + // ERROR_MustHaveAtLeastOneLanguage + + it('should generate ERROR_MustHaveAtLeastOneLanguage if model or keyboard has zero language tags', async function() { + testForMessage(this, ['invalid', 'keyman.en.error_must_have_at_least_one_language.model.kps'], + CompilerMessages.ERROR_MustHaveAtLeastOneLanguage); + }); + + // WARN_RedistFileShouldNotBeInPackage + + it('should generate WARN_RedistFileShouldNotBeInPackage if package contains a redist file', async function() { + testForMessage(this, ['invalid', 'warn_redist_file_should_not_be_in_package.kps'], + CompilerMessages.WARN_RedistFileShouldNotBeInPackage); + }); + + // WARN_DocFileDangerous + + it('should generate WARN_DocFileDangerous if package contains a .doc file', async function() { + testForMessage(this, ['invalid', 'warn_doc_file_dangerous.kps'], + CompilerMessages.WARN_DocFileDangerous); + }); + + // ERROR_PackageMustContainAPackageOrAKeyboard + + it('should generate ERROR_PackageMustContainAModelOrAKeyboard if package contains a .doc file', async function() { + testForMessage(this, ['invalid', 'error_package_must_contain_a_model_or_a_keyboard.kps'], + CompilerMessages.ERROR_PackageMustContainAModelOrAKeyboard); + }); + }); diff --git a/developer/src/kmc-package/test/test-package-compiler.ts b/developer/src/kmc-package/test/test-package-compiler.ts index 731925a25e..23d421f90f 100644 --- a/developer/src/kmc-package/test/test-package-compiler.ts +++ b/developer/src/kmc-package/test/test-package-compiler.ts @@ -10,7 +10,6 @@ import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; import { makePathToFixture } from './helpers/index.js'; import { KmpCompiler } from '../src/compiler/kmp-compiler.js'; -import { PackageValidation } from '../src/compiler/package-validation.js'; import { CompilerMessages } from '../src/compiler/messages.js'; const debug = true; @@ -149,179 +148,4 @@ describe('KmpCompiler', function () { assert.deepEqual(callbacks.messages[0].code, CompilerMessages.WARN_AbsolutePath); assert.deepEqual(callbacks.messages[1].code, CompilerMessages.ERROR_FileDoesNotExist); }); - - // - // Message tests - // - - function testForMessage(context: Mocha.Context, fixture: string[], messageId?: number) { - context.timeout(10000); - - callbacks.clear(); - - const kpsPath = makePathToFixture(...fixture); - const kmpCompiler = new KmpCompiler(callbacks); - - let kmpJson = kmpCompiler.transformKpsToKmpObject(kpsPath); - if(kmpJson && callbacks.messages.length == 0) { - const validator = new PackageValidation(callbacks); - validator.validate(kpsPath, kmpJson); // we'll ignore return value and rely on the messages - } - - if(kmpJson && callbacks.messages.length == 0) { - // We'll try building the package if we have not yet received any messages - kmpCompiler.buildKmpFile(kpsPath, kmpJson) - } - - if(debug) callbacks.printMessages(); - - if(messageId) { - assert.lengthOf(callbacks.messages, 1); - assert.isTrue(callbacks.hasMessage(messageId)); - } else { - assert.lengthOf(callbacks.messages, 0); - } - } - - // WARN_FileIsNotABinaryKvkFile - - it('should generate WARN_FileIsNotABinaryKvkFile if a non-binary kvk file is included', async function() { - testForMessage(this, ['xml_kvk_file', 'source', 'xml_kvk_file.kps'], CompilerMessages.WARN_FileIsNotABinaryKvkFile); - }); - - it('should not warn if a binary kvk file is included', async function() { - testForMessage(this, ['binary_kvk_file', 'source', 'binary_kvk_file.kps']); - }); - - // ERROR_FollowKeyboardVersionNotAllowedForModelPackages - - it('should generate ERROR_FollowKeyboardVersionNotAllowedForModelPackages if is set for model packages', async function() { - testForMessage(this, ['invalid', 'followkeyboardversion.qaa.sencoten.model.kps'], CompilerMessages.ERROR_FollowKeyboardVersionNotAllowedForModelPackages); - }); - - // ERROR_FollowKeyboardVersionButNoKeyboards - - it('should generate ERROR_FollowKeyboardVersionButNoKeyboards if is set for a package with no keyboards', async function() { - testForMessage(this, ['invalid', 'followkeyboardversion.empty.kps'], CompilerMessages.ERROR_FollowKeyboardVersionButNoKeyboards); - }); - - // ERROR_KeyboardContentFileNotFound - - it('should generate ERROR_KeyboardContentFileNotFound if a is listed in a package but not found in ', async function() { - testForMessage(this, ['invalid', 'keyboardcontentfilenotfound.kps'], CompilerMessages.ERROR_KeyboardContentFileNotFound); - }); - - // ERROR_KeyboardFileNotValid - - it('should generate ERROR_KeyboardFileNotValid if a .kmx is not valid in ', async function() { - testForMessage(this, ['invalid', 'keyboardfilenotvalid.kps'], CompilerMessages.ERROR_KeyboardFileNotValid); - }); - - // INFO_KeyboardFileHasNoKeyboardVersion - - it('should generate INFO_KeyboardFileHasNoKeyboardVersion if is set but keyboard has no version', async function() { - testForMessage(this, ['invalid', 'nokeyboardversion.kps'], CompilerMessages.INFO_KeyboardFileHasNoKeyboardVersion); - }); - - // ERROR_PackageCannotContainBothModelsAndKeyboards - - it('should generate ERROR_PackageCannotContainBothModelsAndKeyboards if package has both keyboards and models', async function() { - testForMessage(this, ['invalid', 'error_package_cannot_contain_both_models_and_keyboards.kps'], CompilerMessages.ERROR_PackageCannotContainBothModelsAndKeyboards); - }); - - // WARN_PackageShouldNotRepeatLanguages (models) - - it('should generate WARN_PackageShouldNotRepeatLanguages if model has same language repeated', async function() { - testForMessage(this, ['invalid', 'keyman.en.warn_package_should_not_repeat_languages.model.kps'], CompilerMessages.WARN_PackageShouldNotRepeatLanguages); - }); - - // WARN_PackageShouldNotRepeatLanguages (keyboards) - - it('should generate WARN_PackageShouldNotRepeatLanguages if keyboard has same language repeated', async function() { - testForMessage(this, ['invalid', 'warn_package_should_not_repeat_languages.kps'], CompilerMessages.WARN_PackageShouldNotRepeatLanguages); - }); - - // WARN_PackageNameDoesNotFollowLexicalModelConventions - - it('should generate WARN_PackageNameDoesNotFollowLexicalModelConventions if filename has wrong conventions', async function() { - testForMessage(this, ['invalid', 'WARN_PackageNameDoesNotFollowLexicalModelConventions.kps'], CompilerMessages.WARN_PackageNameDoesNotFollowLexicalModelConventions); - }); - - // WARN_PackageNameDoesNotFollowKeyboardConventions - - it('should generate WARN_PackageNameDoesNotFollowKeyboardConventions if filename has wrong conventions', async function() { - testForMessage(this, ['invalid', 'WARN_PackageNameDoesNotFollowKeyboardConventions.kps'], CompilerMessages.WARN_PackageNameDoesNotFollowKeyboardConventions); - }); - - // WARN_FileInPackageDoesNotFollowFilenameConventions - - it('should generate WARN_FileInPackageDoesNotFollowFilenameConventions if content filename has wrong conventions', async function() { - testForMessage(this, ['invalid', 'warn_file_in_package_does_not_follow_filename_conventions.kps'], CompilerMessages.WARN_FileInPackageDoesNotFollowFilenameConventions); - testForMessage(this, ['invalid', 'warn_file_in_package_does_not_follow_filename_conventions_2.kps'], CompilerMessages.WARN_FileInPackageDoesNotFollowFilenameConventions); - }); - - // ERROR_PackageNameCannotBeBlank - - it('should generate ERROR_PackageNameCannotBeBlank if package info has empty name', async function() { - testForMessage(this, ['invalid', 'error_package_name_cannot_be_blank.kps'], CompilerMessages.ERROR_PackageNameCannotBeBlank); // blank field - testForMessage(this, ['invalid', 'error_package_name_cannot_be_blank_2.kps'], CompilerMessages.ERROR_PackageNameCannotBeBlank); // missing field - }); - - // ERROR_KeyboardFileNotFound - - it('should generate ERROR_KeyboardFileNotFound if a is listed in a package but not found in ', async function() { - testForMessage(this, ['invalid', 'keyboardfilenotfound.kps'], CompilerMessages.ERROR_KeyboardFileNotFound); - }); - - // WARN_KeyboardVersionsDoNotMatch - - it('should generate WARN_KeyboardVersionsDoNotMatch if two have different versions', async function() { - testForMessage(this, ['invalid', 'warn_keyboard_versions_do_not_match.kps'], CompilerMessages.WARN_KeyboardVersionsDoNotMatch); - }); - - // WARN_KeyboardVersionsDoNotMatchPackageVersion - - it('should generate WARN_KeyboardVersionsDoNotMatchPackageVersion if version does not match package version', async function() { - testForMessage(this, ['invalid', 'warn_keyboard_versions_do_not_match_package_version.kps'], CompilerMessages.WARN_KeyboardVersionsDoNotMatchPackageVersion); - }); - - // ERROR_LanguageTagIsNotValid - - it('should generate ERROR_LanguageTagIsNotValid if keyboard has an invalid language tag', async function() { - testForMessage(this, ['invalid', 'error_language_tag_is_not_valid.kps'], CompilerMessages.ERROR_LanguageTagIsNotValid); - }); - - // WARN_LanguageTagIsNotMinimal - - it('should generate WARN_LanguageTagIsNotMinimal if keyboard has a non-minimal language tag', async function() { - testForMessage(this, ['invalid', 'warn_language_tag_is_not_minimal.kps'], CompilerMessages.WARN_LanguageTagIsNotMinimal); - }); - - // ERROR_MustHaveAtLeastOneLanguage - - it('should generate ERROR_MustHaveAtLeastOneLanguage if model or keyboard has zero language tags', async function() { - testForMessage(this, ['invalid', 'keyman.en.error_must_have_at_least_one_language.model.kps'], - CompilerMessages.ERROR_MustHaveAtLeastOneLanguage); - }); - - // WARN_RedistFileShouldNotBeInPackage - - it('should generate WARN_RedistFileShouldNotBeInPackage if package contains a redist file', async function() { - testForMessage(this, ['invalid', 'warn_redist_file_should_not_be_in_package.kps'], - CompilerMessages.WARN_RedistFileShouldNotBeInPackage); - }); - - // WARN_DocFileDangerous - - it('should generate WARN_DocFileDangerous if package contains a .doc file', async function() { - testForMessage(this, ['invalid', 'warn_doc_file_dangerous.kps'], - CompilerMessages.WARN_DocFileDangerous); - }); - - // ERROR_PackageMustContainAPackageOrAKeyboard - - it('should generate ERROR_PackageMustContainAModelOrAKeyboard if package contains a .doc file', async function() { - testForMessage(this, ['invalid', 'error_package_must_contain_a_model_or_a_keyboard.kps'], - CompilerMessages.ERROR_PackageMustContainAModelOrAKeyboard); - }); }); -- GitLab From e293d7608c5a0bc6d03416010c65f6c12a114ffe Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 23 May 2023 09:28:26 +0700 Subject: [PATCH 135/214] chore(developer): add test for missing .js file --- .../src/compiler/keyman-targets.ts | 53 +++++++++ .../src/kmc-package/src/compiler/messages.ts | 4 + .../src/compiler/package-validation.ts | 2 + .../compiler/package-version-validation.ts | 102 +++++++++++++----- .../source/binary_kvk_file.kps | 12 +-- ...geNameDoesNotFollowKeyboardConventions.kps | 12 +-- .../test/fixtures/invalid/basic.kmn | 6 ++ .../test/fixtures/invalid/basic.kmx | Bin 0 -> 352 bytes .../error_language_tag_is_not_valid.kps | 12 +-- ...nnot_contain_both_models_and_keyboards.kps | 12 +-- .../error_package_name_cannot_be_blank.kps | 12 +-- .../error_package_name_cannot_be_blank_2.kps | 12 +-- .../fixtures/invalid/my special keyboard.kmx | Bin 26280 -> 352 bytes .../fixtures/invalid/my_special-keyboard.kmx | Bin 26280 -> 352 bytes .../invalid/warn_doc_file_dangerous.kps | 12 +-- ...e_does_not_follow_filename_conventions.kps | 4 +- ...does_not_follow_filename_conventions_2.kps | 6 +- .../warn_js_keyboard_file_is_missing.kmn | 8 ++ .../warn_js_keyboard_file_is_missing.kmx | Bin 0 -> 414 bytes .../warn_js_keyboard_file_is_missing.kps | 40 +++++++ .../warn_keyboard_versions_do_not_match.kps | 12 +-- .../warn_language_tag_is_not_minimal.kps | 12 +-- ...rn_package_should_not_repeat_languages.kps | 12 +-- ...n_redist_file_should_not_be_in_package.kps | 12 +-- .../xml_kvk_file/source/xml_kvk_file.kps | 12 +-- .../src/kmc-package/test/test-messages.ts | 9 +- .../kmc-package/test/test-package-compiler.ts | 2 +- 27 files changed, 273 insertions(+), 107 deletions(-) create mode 100644 developer/src/kmc-package/src/compiler/keyman-targets.ts create mode 100644 developer/src/kmc-package/test/fixtures/invalid/basic.kmn create mode 100644 developer/src/kmc-package/test/fixtures/invalid/basic.kmx create mode 100644 developer/src/kmc-package/test/fixtures/invalid/warn_js_keyboard_file_is_missing.kmn create mode 100644 developer/src/kmc-package/test/fixtures/invalid/warn_js_keyboard_file_is_missing.kmx create mode 100644 developer/src/kmc-package/test/fixtures/invalid/warn_js_keyboard_file_is_missing.kps diff --git a/developer/src/kmc-package/src/compiler/keyman-targets.ts b/developer/src/kmc-package/src/compiler/keyman-targets.ts new file mode 100644 index 0000000000..14fc6572c4 --- /dev/null +++ b/developer/src/kmc-package/src/compiler/keyman-targets.ts @@ -0,0 +1,53 @@ + +// +// This mirrors UKeymanTargets.pas +// + +export enum + KeymanTarget { + any = 'any', + windows = 'windows', macosx = 'macosx', linux = 'linux', + web = 'web', iphone = 'iphone', ipad = 'ipad', androidphone = 'androidphone', androidtablet = 'androidtablet', + mobile = 'mobile', desktop = 'desktop', tablet = 'tablet' + }; + +export const + // Note: if these change, update the copied values in KeyboardParser.pas accordingly + AllKeymanTargets: KeymanTarget[] = [ + KeymanTarget.any, + KeymanTarget.windows, KeymanTarget.macosx, KeymanTarget.linux, + KeymanTarget.web, KeymanTarget.iphone, KeymanTarget.ipad, KeymanTarget.androidphone, KeymanTarget.androidtablet, + KeymanTarget.mobile, KeymanTarget.desktop, KeymanTarget.tablet + ], + + TouchKeymanTargets: KeymanTarget[] = [ + KeymanTarget.iphone, KeymanTarget.ipad, KeymanTarget.androidphone, KeymanTarget.androidtablet, + KeymanTarget.mobile, KeymanTarget.tablet + ], + + // Compile to .kmx + KMXKeymanTargets: KeymanTarget[] = [ + KeymanTarget.windows, KeymanTarget.macosx, KeymanTarget.linux, KeymanTarget.desktop + ], + + // Compile to .js + KMWKeymanTargets: KeymanTarget[] = [ + KeymanTarget.web, KeymanTarget.iphone, KeymanTarget.ipad, KeymanTarget.androidphone, KeymanTarget.androidtablet, + KeymanTarget.mobile, KeymanTarget.tablet + ], + + // Supports .kvks + KeymanTargetsUsingKVK: KeymanTarget[] = [ + KeymanTarget.windows, KeymanTarget.macosx, KeymanTarget.linux, KeymanTarget.desktop, KeymanTarget.web + ], + + // Friendly names for targets, e.g. for documentation + + SKeymanTargetNames: { [index: string]: string } = { + [KeymanTarget.any]: 'All', + [KeymanTarget.windows]: 'Windows', [KeymanTarget.macosx]: 'macOS', [KeymanTarget.linux]: 'Linux', + [KeymanTarget.web]: 'Web', [KeymanTarget.iphone]: 'iPhone', [KeymanTarget.ipad]: 'iPad', + [KeymanTarget.androidphone]: 'Android phone', [KeymanTarget.androidtablet]: 'Android tablet', + [KeymanTarget.mobile]: 'Mobile devices', [KeymanTarget.desktop]: 'Desktop devices', + [KeymanTarget.tablet]: 'Tablet devices' + }; diff --git a/developer/src/kmc-package/src/compiler/messages.ts b/developer/src/kmc-package/src/compiler/messages.ts index 35eb5a8512..56727fea9b 100644 --- a/developer/src/kmc-package/src/compiler/messages.ts +++ b/developer/src/kmc-package/src/compiler/messages.ts @@ -110,5 +110,9 @@ export class CompilerMessages { static Error_PackageMustContainAModelOrAKeyboard = () => m(this.ERROR_PackageMustContainAModelOrAKeyboard, `Package must contain a lexical model or a keyboard.`); static ERROR_PackageMustContainAModelOrAKeyboard = SevError | 0x0019; + + static Warn_JsKeyboardFileIsMissing = (o:{id: string}) => m(this.WARN_JsKeyboardFileIsMissing, + `Keyboard ${o.id} targets touch devices but corresponding ${o.id}.js file is not in the package.`); + static WARN_JsKeyboardFileIsMissing = SevWarn | 0x001A; } diff --git a/developer/src/kmc-package/src/compiler/package-validation.ts b/developer/src/kmc-package/src/compiler/package-validation.ts index 0fd139bb47..d4317a3da0 100644 --- a/developer/src/kmc-package/src/compiler/package-validation.ts +++ b/developer/src/kmc-package/src/compiler/package-validation.ts @@ -130,6 +130,8 @@ export class PackageValidation { if(!this.checkForDuplicatedOrNonMinimalLanguages('keyboard', keyboard.id, keyboard.languages)) { return false; } + // Note: package-version-validation verifies that there is a corresponding + // content file for each keyboard } return true; diff --git a/developer/src/kmc-package/src/compiler/package-version-validation.ts b/developer/src/kmc-package/src/compiler/package-version-validation.ts index ffd7565912..4f8ad4a41c 100644 --- a/developer/src/kmc-package/src/compiler/package-version-validation.ts +++ b/developer/src/kmc-package/src/compiler/package-version-validation.ts @@ -1,6 +1,13 @@ import { KmpJsonFile, CompilerCallbacks, KpsFile, KmxFileReader, KMX } from '@keymanapp/common-types'; +import { KeymanTarget, TouchKeymanTargets } from './keyman-targets.js'; import { CompilerMessages } from './messages.js'; +// The DEFAULT_VERSION used to be '1.0', but we now use '0.0' to allow +// pre-release 0.x keyboards to be considered later than a keyboard without +// any version metadata at all. +// TODO: move to a better location +const DEFAULT_VERSION = '0.0'; + export class PackageVersionValidation { constructor(private callbacks: CompilerCallbacks) {} @@ -33,14 +40,32 @@ export class PackageVersionValidation { // We now know we have at least one keyboard in the package for(let keyboard of kmp.keyboards) { - result = this.updateKeyboardVersionFromKmx(kpsFilename, kmp, keyboard) && result; + const kmx = this.getKmxData(kpsFilename, kmp, keyboard); + if(!kmx) { + // Warnings or errors will have been raised by getKmxData + result = false; + continue; + } + + // get the targets from the .kmx + this.verifyTargets(keyboard, kmx, kmp); + + // Note: there is often version metadata in the .kps element, but + // we don't read from the metadata because we want to ensure we have the + // most up-to-date keyboard version data here, from the compiled keyboard. + let keyboardVersion = this.getKeyboardVersionFromKmx(kmx); + if(followKeyboardVersion && keyboardVersion === null) { + this.callbacks.reportMessage(CompilerMessages.Info_KeyboardFileHasNoKeyboardVersion({filename: keyboard.id})); + } + keyboard.version = keyboardVersion ?? DEFAULT_VERSION; + if(result) { if(kmp.keyboards[0].version !== keyboard.version) { this.callbacks.reportMessage(CompilerMessages.Warn_KeyboardVersionsDoNotMatch({ - keyboard:keyboard.id, - version:keyboard.version, - firstKeyboard:kmp.keyboards[0].id, - firstVersion:kmp.keyboards[0].version + keyboard: keyboard.id, + version: keyboard.version, + firstKeyboard: kmp.keyboards[0].id, + firstVersion: kmp.keyboards[0].version })); } } @@ -78,34 +103,22 @@ export class PackageVersionValidation { return true; } - private updateKeyboardVersionFromKmx( + private getKmxData( kpsFilename: string, kmp: KmpJsonFile.KmpJsonFile, keyboard: KmpJsonFile.KmpJsonFileKeyboard - ): boolean { - // The DEFAULT_VERSION used to be '1.0', but we now use '0.0' to allow - // pre-release 0.x keyboards to be considered later than a keyboard without - // any version metadata at all. - const DEFAULT_VERSION = '0.0'; - - // Note: there is often version metadata in the .kps element, but - // we don't read from the metadata because we want to ensure we have the - // most up-to-date keyboard version data here, from the compiled keyboard. - - // Reset the keyboard version to the default in the kmp.json metadata, for - // warning/failure code paths in this file - keyboard.version = DEFAULT_VERSION; + ): KMX.KEYBOARD { const file = kmp.files.find(file => this.callbacks.path.basename(file.name, '.kmx') == keyboard.id); if(!file) { this.callbacks.reportMessage(CompilerMessages.Error_KeyboardContentFileNotFound({id:keyboard.id})); - return false; + return null; } const filename = this.callbacks.resolveFilename(kpsFilename, file.name); if(!this.callbacks.fs.existsSync(filename)) { this.callbacks.reportMessage(CompilerMessages.Error_KeyboardFileNotFound({filename})); - return false; + return null; } // @@ -116,24 +129,57 @@ export class PackageVersionValidation { kmxFileData = this.callbacks.loadFile(filename); } catch(e) { this.callbacks.reportMessage(CompilerMessages.Error_FileCouldNotBeRead({filename, e})); - return false; + return null; } const kmxReader: KmxFileReader = new KmxFileReader(); const kmx: KMX.KEYBOARD = kmxReader.read(kmxFileData); if(!kmx) { // The file couldn't be read, it might not be a .kmx file this.callbacks.reportMessage(CompilerMessages.Error_KeyboardFileNotValid({filename})); - return false; + return null; } + return kmx; + } + + private getKeyboardVersionFromKmx( + kmx: KMX.KEYBOARD + ): string { const store = kmx.stores.find(store => store.dwSystemID == KMX.KMXFile.TSS_KEYBOARDVERSION); + return store ? store.dpString : null; + } + + /** + * Verify that the package contains a .js if the keyboard targets touch + * devices + */ + private verifyTargets( + keyboard: KmpJsonFile.KmpJsonFileKeyboard, + kmx: KMX.KEYBOARD, + kmp: KmpJsonFile.KmpJsonFile + ): void { + // TODO: this function doesn't really belong in version validation, but we + // don't want to read .kmx twice so we'll leave it here for now; a future + // refactor could move .kmx loading into another class + + const store = kmx.stores.find(store => store.dwSystemID == KMX.KMXFile.TSS_TARGETS); if(!store) { - // We have no version number store, so use default version - this.callbacks.reportMessage(CompilerMessages.Info_KeyboardFileHasNoKeyboardVersion({filename})); - return true; + // If there is no &TARGETS store, then there is nothing to check, + // because default is windows-only + return; } - keyboard.version = store.dpString; - return true; + // Note, if we have gotten this far, we've already located and loaded a + // .kmx, so no need to verify that the package includes a .kmx + + // If at least one target is a touch target, we need to check that the + // package also includes the .js + const targets = store.dpString.split(' '); + if(targets.some(target => ['any', ...TouchKeymanTargets].includes(target))) { + if(!kmp.files.find(file => this.callbacks.path.basename(file.name, '.js') == keyboard.id)) { + // .js version of the keyboard is not found, warn + this.callbacks.reportMessage(CompilerMessages.Warn_JsKeyboardFileIsMissing({id: keyboard.id})); + } + } } } diff --git a/developer/src/kmc-package/test/fixtures/binary_kvk_file/source/binary_kvk_file.kps b/developer/src/kmc-package/test/fixtures/binary_kvk_file/source/binary_kvk_file.kps index a95f5c6fe1..de17212a84 100644 --- a/developer/src/kmc-package/test/fixtures/binary_kvk_file/source/binary_kvk_file.kps +++ b/developer/src/kmc-package/test/fixtures/binary_kvk_file/source/binary_kvk_file.kps @@ -17,7 +17,7 @@ Binary KVK File - 1.3 + 1.0 @@ -27,17 +27,17 @@ .kvk - ../../invalid/khmer_angkor.kmx - Keyboard Khmer Angkor + ../../invalid/basic.kmx + Keyboard Basic 0 .kmx - Khmer Angkor - khmer_angkor - 1.3 + Basic + basic + 1.0 Khmer diff --git a/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowKeyboardConventions.kps b/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowKeyboardConventions.kps index 867129bac3..70f58d779b 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowKeyboardConventions.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/WARN_PackageNameDoesNotFollowKeyboardConventions.kps @@ -9,21 +9,21 @@ SENĆOŦEN (Saanich Dialect) Lexical Model © 2019 National Research Council Canada Eddie Antonio Santos - 1.3 + 1.0 - khmer_angkor.kmx - Keyboard Khmer Angkor + basic.kmx + Keyboard Basic 0 .kmx - Khmer Angkor - khmer_angkor - 1.3 + Basic + basic + 1.0 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/basic.kmn b/developer/src/kmc-package/test/fixtures/invalid/basic.kmn new file mode 100644 index 0000000000..48705f6b99 --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/basic.kmn @@ -0,0 +1,6 @@ +store(&name) 'basic desktop-only kmx' +store(&keyboardversion) '1.0' + +begin unicode > use(main) + +group(main) using keys \ No newline at end of file diff --git a/developer/src/kmc-package/test/fixtures/invalid/basic.kmx b/developer/src/kmc-package/test/fixtures/invalid/basic.kmx new file mode 100644 index 0000000000000000000000000000000000000000..bd6b832cab772d03a45460e6c982d79772a9ab6e GIT binary patch literal 352 zcmZvYyAAdPzftU-(5_7TAk3e<2#yh{6J%lpJ>i; zp8cfbGTcz0i3ZwI$I5E289asBOpaP`wxny)?MPoMtp7qQ?)E9)e`0JAA>To*E2jVe literal 0 HcmV?d00001 diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_language_tag_is_not_valid.kps b/developer/src/kmc-package/test/fixtures/invalid/error_language_tag_is_not_valid.kps index 3c47540d2b..06d9526651 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/error_language_tag_is_not_valid.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/error_language_tag_is_not_valid.kps @@ -8,21 +8,21 @@ SENĆOŦEN (Saanich Dialect) Lexical Model © 2019 National Research Council Canada Eddie Antonio Santos - 1.3 + 1.0 - khmer_angkor.kmx - Keyboard Khmer Angkor + basic.kmx + Keyboard Basic 0 .kmx - Khmer Angkor - khmer_angkor - 1.3 + Basic + basic + 1.0 English (Australian script) as spoken in Latin diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_package_cannot_contain_both_models_and_keyboards.kps b/developer/src/kmc-package/test/fixtures/invalid/error_package_cannot_contain_both_models_and_keyboards.kps index 5ee547dcf1..6483fe1c10 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/error_package_cannot_contain_both_models_and_keyboards.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/error_package_cannot_contain_both_models_and_keyboards.kps @@ -8,13 +8,13 @@ Khmer Angkor © 2015-2022 SIL International Makara Sok - 1.3 + 1.0 https://keyman.com/keyboards/khmer_angkor - khmer_angkor.kmx - Keyboard Khmer Angkor + basic.kmx + Keyboard Basic 0 .kmx @@ -38,9 +38,9 @@ - Khmer Angkor - khmer_angkor - 1.3 + Basic + basic + 1.0 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank.kps b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank.kps index 870d8ae55b..5b7d6d3d46 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank.kps @@ -9,21 +9,21 @@ © 2019 National Research Council Canada Eddie Antonio Santos - 1.3 + 1.0 - khmer_angkor.kmx - Keyboard Khmer Angkor + basic.kmx + Keyboard Basic 0 .kmx - Khmer Angkor - khmer_angkor - 1.3 + Basic + basic + 1.0 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_2.kps b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_2.kps index 01eba9981d..f9beefebb9 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_2.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/error_package_name_cannot_be_blank_2.kps @@ -8,21 +8,21 @@ © 2019 National Research Council Canada Eddie Antonio Santos - 1.3 + 1.0 - khmer_angkor.kmx - Keyboard Khmer Angkor + basic.kmx + Keyboard Basic 0 .kmx - Khmer Angkor - khmer_angkor - 1.3 + Basic + basic + 1.0 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/my special keyboard.kmx b/developer/src/kmc-package/test/fixtures/invalid/my special keyboard.kmx index c3d0289f4863c7c4a998c348eb1d425caadca79d..bd6b832cab772d03a45460e6c982d79772a9ab6e 100644 GIT binary patch literal 352 zcmZvYyAAdPzftU-(5_7TAk3e<2#yh{6J%lpJ>i; zp8cfbGTcz0i3ZwI$I5E289asBOpaP`wxny)?MPoMtp7qQ?)E9)e`0JAA>To*E2jVe literal 26280 zcmd^He|Qx~xt;)}N1EaRDYFM_JW|R{{4&iTUDd;z6+h=`0Z!{~^8(dp4|zP`)L;iDPrY#(^yaip9fX9`^I0 z5uY#q4LKfGK10QDF<1-%vc(9sAA*_)c3DCUHOD5Rrf&wNjX@dzD!zfT<|D^1P<}T2 zsLW3&D;sHC+$-)Dld!)V-qhy#*i-9u8y-aagt$kQ@ilnSndtV<5&w>sE`atRVAp#e zO8C0?D)P)id2zIW&btWwL6klVXCqV@-@^VIroCTL8n<_FkW2U0Cs5DBsPC)r{sda| zAj%`Y03{4Xd3Uy3l5R`;buC1FG>>7R_!C7mu%-uA)M!zkHQ|5G_}yi!FPI#xMg35l zVEo1zYlg|eTGS7<$;NN0vGPq0)}lUZ!VhzdH8~1Q4%VVRYr?Q;apqSksJk zud&7lR@7&|sOgu8>9vSY^$M|6J}Q^V@5&PSJy|NhFPF>5bM&>q5`JiX)*KD3upd5ej*=zBcKP3Ohy0D)DR;?Qxm(uB=VZOyBlpVR%6;;G zf^&$PzK{CclM(-fDq+8TULN>=aISPM+B=VqdV2NNPu)tZiy z-NBWK_#7Ki|8=AB2#Q!&Iy}mwAnJ$K@gT48*^2la5fL-0B0fii@OPQosAM7jOKy}u zmz(4-xkUY3qvZsajvLAmv1+{29OY3E zG4qk|X+9F-ck-}2C|{B!i1=Y^`K%&p3IkhoqYW|EP-F2qNB!YO<7*K0 z=`3_FaVZg>ONm(5G;BThb;PeVd3mmmSZ5xV%yUY_%s3IBTOaYcr4gTJu!zqyNyNmIRY3BH#^%#0r~_l=0TOGSLX4@G>MzlC^4>=FaS$Hm96YPnr}8f*D)i|>d+ ztmOxaLE=^1O+P8VB)%+ej%UX2z}@zJF;a~0>&0X7Pl-`tG}hd-0@o1{H~q_2#3xIL zo8ob?F7S)`!%V-07F`=5UX%Sqb)3uN>mW=Y37@Zn@cFt5Q=TwaSeVEXK1Y@?qeS?0 zt%YcoZ^#z;raUR%lCAP>c}o5vh%?W`fM@FVOx>QT+cR~0rf$#F?U}kgQ@0n?eNMh3 z&&zk^1^J%5DBqWtwPV(-M>j-8La8@mwuTkJ~gRO}D2=GdFD zKgCYQT4R@EZ^SOe-io~+doOl1))qS*`(x~4jAKt^@TxDvSe=a3*;rkSb%U|G8tX=5 zMU3?UV|6puO~%SJ*3HK1ZmbU)D{8DB#_DOT4;ibMv2HO|Z(~VgdB%zvtB(faT@_GtBC0N&1 zDf?;Im9WZ!a@OH2b$L&rgbI}NnDVGnYAM#qv?6{2t79Rmw%LeEK|k4T~CrqJ_J=wnjoV^ipNrO?Nv z&_A0(&rho7rRe`WT&HCHoQEryTul445AmJcKY9P>VJsx~Pu~A|B6OHD?z32;Z z{NqBj0Je4!{EDM>9VkR5Ffk}Ag1o)K`v7At?N;zOaKh61g7*hrx3mG^gMb1{8w{Qe z+-+&Yz;l7AmNpW6H1K&#^TEdfuUT3?_yk~zrA-1a06uGJQ^2PIcAKYz7XtTNeh+{b z0rY-}wumppEb!UDE~RK~4)|Q)3zjwyd;zf2(iVb00^DP1i@}!ylPql+cqx!$Y0JS^ z0wXMK75EyU-qOmzD*z6Mh%ZDX_*&pT%Woa{2H=a9wh??Y@SLSpgKq`KSXvGEcHmx1 z+W}q+KAw(BovZZwe?*`1Uv`p|QFx}F6g7*e^ zOhf43Rb-d=kL@LfT~TDFBZT(x!q>2l(7bn*sg+z-=aNCipCXW1O^yz~=xQ?KJpV zfah$|&VgS5c+Mg1BKT#1W1O@r;CS(1=3UY{fp-OX%#aoV&jfhBBCR`kPk`qa(t3e= zzzm@`()xgB0Xr=%4&D#od4v4=gAWAweni?J@F74v$V+228$1WN0ry|ELCXan4Ro!ejsLP2fz;jo~0cIZvv#H9R)uD^tQBS@K)d!OFIRA7U*SZ=fE!lAF{Md;8%g3 zmWJ13qASqD(jws9fvBZL!FvNAv@{Pq3lNqT2k#Gbx3mG^g8^FWsm(_`g69C8EG-v& zG;p(}`QZ7$jg~eZd@?X6C=M_FL;?6zON&CA20jD$hUHfXKGV|3uL%4h;G34;Z17@B zBfq)e^MSdR-vaPOmPUS$fG+_aw)~cYmslG4m4dGT;+Ee^@YR+^er4blmPY4W3BDHK z`y2VK1K$Af{7l+L@ES*}18;D&Ch!(VI}3i<(YoTN&z^u?M;7=%N6Q8u?P&Sn1&%fy ze3qjXgUjTmjfiDL5o=n;j@MQqse@QC=Uk-4assC1hmpR&6@J)`k z6?~_o?FB#RXh*=00=#CRdXJG0!0Qsyn!!&3ynZ3A75p^7>v7V~fS&_+Zl^Y%2fqaH znvk^1;8y{@e~^aP-=Yh^Yhcp4g7iowiLVs;58R%rQj<7zUHK@1YZqs zKa;iwyd2if0e8!V0dHiB;k_cIB`9H*r1 z13v(8{E^lGehA?BBkeHw5rE^5v?lOl0LLF`$HAKcjz7{`z*_;1KhjQtp8+`jNIMID z9^m*R?E?5Epg;s0w9DXE0ggZNqe-(1FePv!tt)spfa8y}Oz1bhj=aY}Ku z6uboBI3=wVd^B)j++_8)<96%YnAGE)d(=Bvw$J@H=p$Y-`I9-Ib<~WZ*l^ z{WA2-z&D)FgZ~6T46BsBP!WQ@T0mr~bfZc)sq|Tu{z9eCsPtDV)wy0*_RA_gq|)Om zZBi+H0f3oWrN39{F_qpNCp}Z8UnUd3R?~*56&pQF3V~%8w)a(v+dH;Gm3~L1BUSpU zO0l5FHoh;V11S++oKl|>5sOp$DN69$H*KR;`fZi=SLtmkt&Y>KpRzBgc3x8HIhDSn z((@{PSEcmZuMqF4^rA}NSLq*Pq@Pyl8I}H3rGHWBS(Ub^^v^0ir_y&+O21`d45{>8 zm0nQk-&A@jf#{+p1{UR!u>S9V)lXYm3??~PzIhChXN zQoq^y)A*u?j?s$F)++)%&(VJx=rmSre=1`X%BSmK>+9i9*V@(SdXN^jE-Oii+0b5q zCx1!%nzC;vLD285b{Y0OWtSUG@S=A1yhfqAf2YbD088L27}{P^%BPjROVW%--)K>K zM5WaJhM<4BAL-6->)ekc0{zSRNAW2w^e#d zrS#Pb?%w!9koI*d-4(DJ#a>bAXXvnaRoUBvGt&{T<57>Yz3RA*bc!3S36N6R1h%oN zP{;HLUZ!k4Ds_+P5kOxy3ZX}r9`n^o`K?OzD5_QVo}j%u71Q&;Ze{B+Q?KkTD&4Ho z7gc&trO!|``1X%dJ!bWcqvw%5O4nmm&p;Hf^eaB4jVfKLQaw-TSwWBaeM;B!fu5!G z9HM6&J?`7udf>GUUC|!6cT(CJ<U33D8+gOYmz}|Aer#o6P_$o(R55CXQj(}fuv~F004l)Z-U6T)99*FnOM{g2JCGt_$)_T1YYTA)!>I5tr@(NSrqG1dx7UT+IaA}j#dJ` z+0p93TO92IcyF`F)^!X3pWtYP;7c5BCHNLcs|Rm!v9mBw`ANb#h`I9{3PP8w)jE=@Dq-94m>g?vEDx5108J?_#{Vr0DP{a zEd^iaXgk1>%SE|*U`p<&vvxM;8l*c75t#1HG^Mqv?yLC3^FeibiF=! zp`*2er+JB_Yw8O=+R-M1&vCSc;3bZ>7JP@JHGrRVw2R7!r!n6?Z7&vCTz;FBG#5WL9I=7BGCv=Z=7akReR!yIiCxbJBB;1e9J0DP*W%>aME(Pn|qakP2h3mt7Sc!{H} z0k3qlP2gJ{Z990Kqa6TmaIc+}B)gZFW?ICwum zzs0cMVd!@rUDc5rQ8c~t(C-`R&6)k~qrF`G7A;p?PcDAPme+1B{mvz9A-%~g!~YRY zzjfie&+ExWJ)z%>UQaIl-t>BNRJD6PZV#-x?jE2V`aNZPEpzMPtD19N*N3m_h--2^ zq28X|pkhs5PkP_mLv%shHRAt`Qw!-AD*cvU$7(ux=vS;%dH8K!SWl%@54~Nyww_dZ zbUmEMK93AlN~(PNoapQZs}a^iq@P#UY3EI>OOIbJFLC^~KYGJFe4T0ZrkjVaGL79- zd2~F5_3+3| z^etaQ8mp=5ajyqoLmH{+<_YVeR%fXH2h6|B&^vS*O*{@#*Vl1gHx{TaeP4PZWn0}m z+}2$D7M1G!+&tVTdF|wJ&r8R3`gMeHoqnD$uG7z>+)efsr;dD5>Zy#DFe6Xr?3o-k(8 zuP4ltemy$Q(yxQ(TUx=TbN$J`3cl2$^!-z}Uyt8w<10t~?UCel=saN@bA0jIC|SGQ zdN@`_Tt_`&p48{lfWJmV_45q52R%ib$$+=ahjlb+`b9e8qo#^KX z%{=1Uk2dXY828hLj^qdvY9(=&<(C zv!mKWPrG)08l$fi=nE_UGG`C|>Xn{NQhU%B4>Z%H_TYI&&%64mAaT8@=ddg_lU@7F zlwQ7M&rA9l($3!*D-nL;yag705u#^H+n3j|`!oBtS8mwv;mn*~yF>r<$|o;=f=%7_#Otd4(<`6n z;&jT^zUh}sPsQn$TNQXFkHhdf^3!wba>MJWebZ~N{Z1@(*FRe8^yO(e{;tvwF$2?gkEHUtK;MVxFLTjbBTCs$^rJj{ z=hJzvT@i4Z*ZN+&3P|m%*BjT~b@fVs^Xc_MxKijW^zpEbbSzvQaK6O0X&*XkUJ>wE zAwRxL>lSgpkaw23x9iB@(sj?!She48(G_xg+OQR?l|U^Y)R%^}Br}@mWPbAy9jVIi=Z05=*m>*sFhzWF0$t z4D$%)Cj$K>5Heczhm2SF+=qNEsC`k@uicP%{<0}-nkVRgD9|_a<$=95u<72i0vhirW+^Z4Nq<(&g?vr% z)hCYA7x}LK>p(A0@Td2akKqV?)ldJAV2^rZN!E5ewd?<>q2FoHd$k=((=)<;%nam3 zvrPD&ldmGjw(bX3b?oqH$UxLIqVCW~NAxWTqlLWadf%c_iaYxM8PBNNb-(Fzz<0K) z?ezaIeyNT=3+w0jyUWxUWYN{qmi~Vk8MyyOqj8jo?<+Co^~QbxKqEO0WT+GdO^43* zv%#IkKQnF@&G=iqj5lDX1NKkcpFe+I5Sp8t)&9_-L*nq^!^%E!;)L4M@vy$c{I`kU ziD(W6Jjp+hf<<&Rd2#~*)OJo)64%5G?AP-S(L|8~(LJ{hZ4ZQQ-PR@Bzk oDtl0`t=LoFCZ2P9{7X|R#ncIv*OjNe@{%3dPzftU-(5_7TAk3e<2#yh{6J%lpJ>i; zp8cfbGTcz0i3ZwI$I5E289asBOpaP`wxny)?MPoMtp7qQ?)E9)e`0JAA>To*E2jVe literal 26280 zcmd^He|Qx~xt;)}N1EaRDYFM_JW|R{{4&iTUDd;z6+h=`0Z!{~^8(dp4|zP`)L;iDPrY#(^yaip9fX9`^I0 z5uY#q4LKfGK10QDF<1-%vc(9sAA*_)c3DCUHOD5Rrf&wNjX@dzD!zfT<|D^1P<}T2 zsLW3&D;sHC+$-)Dld!)V-qhy#*i-9u8y-aagt$kQ@ilnSndtV<5&w>sE`atRVAp#e zO8C0?D)P)id2zIW&btWwL6klVXCqV@-@^VIroCTL8n<_FkW2U0Cs5DBsPC)r{sda| zAj%`Y03{4Xd3Uy3l5R`;buC1FG>>7R_!C7mu%-uA)M!zkHQ|5G_}yi!FPI#xMg35l zVEo1zYlg|eTGS7<$;NN0vGPq0)}lUZ!VhzdH8~1Q4%VVRYr?Q;apqSksJk zud&7lR@7&|sOgu8>9vSY^$M|6J}Q^V@5&PSJy|NhFPF>5bM&>q5`JiX)*KD3upd5ej*=zBcKP3Ohy0D)DR;?Qxm(uB=VZOyBlpVR%6;;G zf^&$PzK{CclM(-fDq+8TULN>=aISPM+B=VqdV2NNPu)tZiy z-NBWK_#7Ki|8=AB2#Q!&Iy}mwAnJ$K@gT48*^2la5fL-0B0fii@OPQosAM7jOKy}u zmz(4-xkUY3qvZsajvLAmv1+{29OY3E zG4qk|X+9F-ck-}2C|{B!i1=Y^`K%&p3IkhoqYW|EP-F2qNB!YO<7*K0 z=`3_FaVZg>ONm(5G;BThb;PeVd3mmmSZ5xV%yUY_%s3IBTOaYcr4gTJu!zqyNyNmIRY3BH#^%#0r~_l=0TOGSLX4@G>MzlC^4>=FaS$Hm96YPnr}8f*D)i|>d+ ztmOxaLE=^1O+P8VB)%+ej%UX2z}@zJF;a~0>&0X7Pl-`tG}hd-0@o1{H~q_2#3xIL zo8ob?F7S)`!%V-07F`=5UX%Sqb)3uN>mW=Y37@Zn@cFt5Q=TwaSeVEXK1Y@?qeS?0 zt%YcoZ^#z;raUR%lCAP>c}o5vh%?W`fM@FVOx>QT+cR~0rf$#F?U}kgQ@0n?eNMh3 z&&zk^1^J%5DBqWtwPV(-M>j-8La8@mwuTkJ~gRO}D2=GdFD zKgCYQT4R@EZ^SOe-io~+doOl1))qS*`(x~4jAKt^@TxDvSe=a3*;rkSb%U|G8tX=5 zMU3?UV|6puO~%SJ*3HK1ZmbU)D{8DB#_DOT4;ibMv2HO|Z(~VgdB%zvtB(faT@_GtBC0N&1 zDf?;Im9WZ!a@OH2b$L&rgbI}NnDVGnYAM#qv?6{2t79Rmw%LeEK|k4T~CrqJ_J=wnjoV^ipNrO?Nv z&_A0(&rho7rRe`WT&HCHoQEryTul445AmJcKY9P>VJsx~Pu~A|B6OHD?z32;Z z{NqBj0Je4!{EDM>9VkR5Ffk}Ag1o)K`v7At?N;zOaKh61g7*hrx3mG^gMb1{8w{Qe z+-+&Yz;l7AmNpW6H1K&#^TEdfuUT3?_yk~zrA-1a06uGJQ^2PIcAKYz7XtTNeh+{b z0rY-}wumppEb!UDE~RK~4)|Q)3zjwyd;zf2(iVb00^DP1i@}!ylPql+cqx!$Y0JS^ z0wXMK75EyU-qOmzD*z6Mh%ZDX_*&pT%Woa{2H=a9wh??Y@SLSpgKq`KSXvGEcHmx1 z+W}q+KAw(BovZZwe?*`1Uv`p|QFx}F6g7*e^ zOhf43Rb-d=kL@LfT~TDFBZT(x!q>2l(7bn*sg+z-=aNCipCXW1O^yz~=xQ?KJpV zfah$|&VgS5c+Mg1BKT#1W1O@r;CS(1=3UY{fp-OX%#aoV&jfhBBCR`kPk`qa(t3e= zzzm@`()xgB0Xr=%4&D#od4v4=gAWAweni?J@F74v$V+228$1WN0ry|ELCXan4Ro!ejsLP2fz;jo~0cIZvv#H9R)uD^tQBS@K)d!OFIRA7U*SZ=fE!lAF{Md;8%g3 zmWJ13qASqD(jws9fvBZL!FvNAv@{Pq3lNqT2k#Gbx3mG^g8^FWsm(_`g69C8EG-v& zG;p(}`QZ7$jg~eZd@?X6C=M_FL;?6zON&CA20jD$hUHfXKGV|3uL%4h;G34;Z17@B zBfq)e^MSdR-vaPOmPUS$fG+_aw)~cYmslG4m4dGT;+Ee^@YR+^er4blmPY4W3BDHK z`y2VK1K$Af{7l+L@ES*}18;D&Ch!(VI}3i<(YoTN&z^u?M;7=%N6Q8u?P&Sn1&%fy ze3qjXgUjTmjfiDL5o=n;j@MQqse@QC=Uk-4assC1hmpR&6@J)`k z6?~_o?FB#RXh*=00=#CRdXJG0!0Qsyn!!&3ynZ3A75p^7>v7V~fS&_+Zl^Y%2fqaH znvk^1;8y{@e~^aP-=Yh^Yhcp4g7iowiLVs;58R%rQj<7zUHK@1YZqs zKa;iwyd2if0e8!V0dHiB;k_cIB`9H*r1 z13v(8{E^lGehA?BBkeHw5rE^5v?lOl0LLF`$HAKcjz7{`z*_;1KhjQtp8+`jNIMID z9^m*R?E?5Epg;s0w9DXE0ggZNqe-(1FePv!tt)spfa8y}Oz1bhj=aY}Ku z6uboBI3=wVd^B)j++_8)<96%YnAGE)d(=Bvw$J@H=p$Y-`I9-Ib<~WZ*l^ z{WA2-z&D)FgZ~6T46BsBP!WQ@T0mr~bfZc)sq|Tu{z9eCsPtDV)wy0*_RA_gq|)Om zZBi+H0f3oWrN39{F_qpNCp}Z8UnUd3R?~*56&pQF3V~%8w)a(v+dH;Gm3~L1BUSpU zO0l5FHoh;V11S++oKl|>5sOp$DN69$H*KR;`fZi=SLtmkt&Y>KpRzBgc3x8HIhDSn z((@{PSEcmZuMqF4^rA}NSLq*Pq@Pyl8I}H3rGHWBS(Ub^^v^0ir_y&+O21`d45{>8 zm0nQk-&A@jf#{+p1{UR!u>S9V)lXYm3??~PzIhChXN zQoq^y)A*u?j?s$F)++)%&(VJx=rmSre=1`X%BSmK>+9i9*V@(SdXN^jE-Oii+0b5q zCx1!%nzC;vLD285b{Y0OWtSUG@S=A1yhfqAf2YbD088L27}{P^%BPjROVW%--)K>K zM5WaJhM<4BAL-6->)ekc0{zSRNAW2w^e#d zrS#Pb?%w!9koI*d-4(DJ#a>bAXXvnaRoUBvGt&{T<57>Yz3RA*bc!3S36N6R1h%oN zP{;HLUZ!k4Ds_+P5kOxy3ZX}r9`n^o`K?OzD5_QVo}j%u71Q&;Ze{B+Q?KkTD&4Ho z7gc&trO!|``1X%dJ!bWcqvw%5O4nmm&p;Hf^eaB4jVfKLQaw-TSwWBaeM;B!fu5!G z9HM6&J?`7udf>GUUC|!6cT(CJ<U33D8+gOYmz}|Aer#o6P_$o(R55CXQj(}fuv~F004l)Z-U6T)99*FnOM{g2JCGt_$)_T1YYTA)!>I5tr@(NSrqG1dx7UT+IaA}j#dJ` z+0p93TO92IcyF`F)^!X3pWtYP;7c5BCHNLcs|Rm!v9mBw`ANb#h`I9{3PP8w)jE=@Dq-94m>g?vEDx5108J?_#{Vr0DP{a zEd^iaXgk1>%SE|*U`p<&vvxM;8l*c75t#1HG^Mqv?yLC3^FeibiF=! zp`*2er+JB_Yw8O=+R-M1&vCSc;3bZ>7JP@JHGrRVw2R7!r!n6?Z7&vCTz;FBG#5WL9I=7BGCv=Z=7akReR!yIiCxbJBB;1e9J0DP*W%>aME(Pn|qakP2h3mt7Sc!{H} z0k3qlP2gJ{Z990Kqa6TmaIc+}B)gZFW?ICwum zzs0cMVd!@rUDc5rQ8c~t(C-`R&6)k~qrF`G7A;p?PcDAPme+1B{mvz9A-%~g!~YRY zzjfie&+ExWJ)z%>UQaIl-t>BNRJD6PZV#-x?jE2V`aNZPEpzMPtD19N*N3m_h--2^ zq28X|pkhs5PkP_mLv%shHRAt`Qw!-AD*cvU$7(ux=vS;%dH8K!SWl%@54~Nyww_dZ zbUmEMK93AlN~(PNoapQZs}a^iq@P#UY3EI>OOIbJFLC^~KYGJFe4T0ZrkjVaGL79- zd2~F5_3+3| z^etaQ8mp=5ajyqoLmH{+<_YVeR%fXH2h6|B&^vS*O*{@#*Vl1gHx{TaeP4PZWn0}m z+}2$D7M1G!+&tVTdF|wJ&r8R3`gMeHoqnD$uG7z>+)efsr;dD5>Zy#DFe6Xr?3o-k(8 zuP4ltemy$Q(yxQ(TUx=TbN$J`3cl2$^!-z}Uyt8w<10t~?UCel=saN@bA0jIC|SGQ zdN@`_Tt_`&p48{lfWJmV_45q52R%ib$$+=ahjlb+`b9e8qo#^KX z%{=1Uk2dXY828hLj^qdvY9(=&<(C zv!mKWPrG)08l$fi=nE_UGG`C|>Xn{NQhU%B4>Z%H_TYI&&%64mAaT8@=ddg_lU@7F zlwQ7M&rA9l($3!*D-nL;yag705u#^H+n3j|`!oBtS8mwv;mn*~yF>r<$|o;=f=%7_#Otd4(<`6n z;&jT^zUh}sPsQn$TNQXFkHhdf^3!wba>MJWebZ~N{Z1@(*FRe8^yO(e{;tvwF$2?gkEHUtK;MVxFLTjbBTCs$^rJj{ z=hJzvT@i4Z*ZN+&3P|m%*BjT~b@fVs^Xc_MxKijW^zpEbbSzvQaK6O0X&*XkUJ>wE zAwRxL>lSgpkaw23x9iB@(sj?!She48(G_xg+OQR?l|U^Y)R%^}Br}@mWPbAy9jVIi=Z05=*m>*sFhzWF0$t z4D$%)Cj$K>5Heczhm2SF+=qNEsC`k@uicP%{<0}-nkVRgD9|_a<$=95u<72i0vhirW+^Z4Nq<(&g?vr% z)hCYA7x}LK>p(A0@Td2akKqV?)ldJAV2^rZN!E5ewd?<>q2FoHd$k=((=)<;%nam3 zvrPD&ldmGjw(bX3b?oqH$UxLIqVCW~NAxWTqlLWadf%c_iaYxM8PBNNb-(Fzz<0K) z?ezaIeyNT=3+w0jyUWxUWYN{qmi~Vk8MyyOqj8jo?<+Co^~QbxKqEO0WT+GdO^43* zv%#IkKQnF@&G=iqj5lDX1NKkcpFe+I5Sp8t)&9_-L*nq^!^%E!;)L4M@vy$c{I`kU ziD(W6Jjp+hf<<&Rd2#~*)OJo)64%5G?AP-S(L|8~(LJ{hZ4ZQQ-PR@Bzk oDtl0`t=LoFCZ2P9{7X|R#ncIv*OjNe@{%3SENĆOŦEN (Saanich Dialect) Lexical Model © 2019 National Research Council Canada Eddie Antonio Santos - 1.3 + 1.0 - khmer_angkor.kmx - Keyboard Khmer Angkor + basic.kmx + Keyboard Basic 0 .kmx @@ -27,9 +27,9 @@ - Khmer Angkor - khmer_angkor - 1.3 + Basic + basic + 1.0 Khmer diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions.kps index 6523df4813..9a8c6d5886 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions.kps @@ -8,7 +8,7 @@ SENĆOŦEN (Saanich Dialect) Lexical Model © 2019 National Research Council Canada Eddie Antonio Santos - 1.3 + 1.0 @@ -23,7 +23,7 @@ Khmer Angkor my special keyboard - 1.3 + 1.0 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions_2.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions_2.kps index d29a01c580..426592c271 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions_2.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_file_in_package_does_not_follow_filename_conventions_2.kps @@ -8,7 +8,7 @@ SENĆOŦEN (Saanich Dialect) Lexical Model © 2019 National Research Council Canada Eddie Antonio Santos - 1.3 + 1.0 @@ -20,7 +20,7 @@ - khmer_angkor.kmx + basic.kmx Keyboard my special keyboard 0 .kmx @@ -29,7 +29,7 @@ Khmer Angkor - khmer_angkor + basic 1.3 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_js_keyboard_file_is_missing.kmn b/developer/src/kmc-package/test/fixtures/invalid/warn_js_keyboard_file_is_missing.kmn new file mode 100644 index 0000000000..fe4f8457c4 --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_js_keyboard_file_is_missing.kmn @@ -0,0 +1,8 @@ +store(&NAME) "warn_js_keyboard_file_is_missing" +store(&VERSION) "10.0" +store(&keyboardversion) "1.0" +store(&targets) "any" + +begin unicode > use(main) + +group(main) using keys \ No newline at end of file diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_js_keyboard_file_is_missing.kmx b/developer/src/kmc-package/test/fixtures/invalid/warn_js_keyboard_file_is_missing.kmx new file mode 100644 index 0000000000000000000000000000000000000000..ca697e872c2dadb3afd3a9f659bb38539d19607d GIT binary patch literal 414 zcmZvYzfJ-{5Ql$9A%^;pmcmdHHYCK-M7k?A#_oh13J7?Fz zYxW3VA5hP5FYp|W1DEifD$O*}mNQdV?^?ifD4|koO)n=KlkM=83YEl)n&p)?+$j8v z(@1>{aHpYeJd0c>T4Kk9d%03Axt;0_omx{=te#PML32elCECQ=N86O^6+P#-n6e97 S?3K08&%J?$jz4N_7U6#hA2EUe literal 0 HcmV?d00001 diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_js_keyboard_file_is_missing.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_js_keyboard_file_is_missing.kps new file mode 100644 index 0000000000..82227ffea6 --- /dev/null +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_js_keyboard_file_is_missing.kps @@ -0,0 +1,40 @@ + + + + 15.0.266.0 + 7.0 + + + + + + + + + + Khmer Angkor + © 2015-2022 SIL International + Makara Sok + + https://keyman.com/keyboards/khmer_angkor + + + + warn_js_keyboard_file_is_missing.kmx + Keyboard Khmer Angkor + 0 + .kmx + + + + + Khmer Angkor + warn_js_keyboard_file_is_missing + 1.0 + + Central Khmer (Khmer, Cambodia) + + + + + diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_keyboard_versions_do_not_match.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_keyboard_versions_do_not_match.kps index 2eb09374c6..d6a8aaf201 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/warn_keyboard_versions_do_not_match.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_keyboard_versions_do_not_match.kps @@ -8,12 +8,12 @@ SENĆOŦEN (Saanich Dialect) Lexical Model © 2019 National Research Council Canada Eddie Antonio Santos - 1.3 + 1.0 - khmer_angkor.kmx - Keyboard Khmer Angkor + basic.kmx + Keyboard Basic 0 .kmx @@ -26,9 +26,9 @@ - Khmer Angkor - khmer_angkor - 1.3 + Basic + basic + 1.0 Khmer diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_language_tag_is_not_minimal.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_language_tag_is_not_minimal.kps index 8e4440e3da..cc757d6431 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/warn_language_tag_is_not_minimal.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_language_tag_is_not_minimal.kps @@ -8,21 +8,21 @@ SENĆOŦEN (Saanich Dialect) Lexical Model © 2019 National Research Council Canada Eddie Antonio Santos - 1.3 + 1.0 - khmer_angkor.kmx - Keyboard Khmer Angkor + basic.kmx + Keyboard Basic 0 .kmx - Khmer Angkor - khmer_angkor - 1.3 + Basic + basic + 1.0 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_package_should_not_repeat_languages.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_package_should_not_repeat_languages.kps index a1c6cffe9f..ef8fcfb89d 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/warn_package_should_not_repeat_languages.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_package_should_not_repeat_languages.kps @@ -8,21 +8,21 @@ SENĆOŦEN (Saanich Dialect) Lexical Model © 2019 National Research Council Canada Eddie Antonio Santos - 1.3 + 1.0 - khmer_angkor.kmx - Keyboard Khmer Angkor + basic.kmx + Keyboard Basic 0 .kmx - Khmer Angkor - khmer_angkor - 1.3 + Basic + basic + 1.0 Central Khmer (Khmer, Cambodia) diff --git a/developer/src/kmc-package/test/fixtures/invalid/warn_redist_file_should_not_be_in_package.kps b/developer/src/kmc-package/test/fixtures/invalid/warn_redist_file_should_not_be_in_package.kps index 1b5d1e246d..10d6212d67 100644 --- a/developer/src/kmc-package/test/fixtures/invalid/warn_redist_file_should_not_be_in_package.kps +++ b/developer/src/kmc-package/test/fixtures/invalid/warn_redist_file_should_not_be_in_package.kps @@ -8,12 +8,12 @@ SENĆOŦEN (Saanich Dialect) Lexical Model © 2019 National Research Council Canada Eddie Antonio Santos - 1.3 + 1.0 - khmer_angkor.kmx - Keyboard Khmer Angkor + basic.kmx + Keyboard Basic 0 .kmx @@ -27,9 +27,9 @@ - Khmer Angkor - khmer_angkor - 1.3 + Basic + basic + 1.0 Khmer diff --git a/developer/src/kmc-package/test/fixtures/xml_kvk_file/source/xml_kvk_file.kps b/developer/src/kmc-package/test/fixtures/xml_kvk_file/source/xml_kvk_file.kps index 9378181ad1..816a66d633 100644 --- a/developer/src/kmc-package/test/fixtures/xml_kvk_file/source/xml_kvk_file.kps +++ b/developer/src/kmc-package/test/fixtures/xml_kvk_file/source/xml_kvk_file.kps @@ -17,7 +17,7 @@ XML KVK File - 1.3 + 1.0 @@ -27,17 +27,17 @@ .kvk - ../../invalid/khmer_angkor.kmx - Keyboard Khmer Angkor + ../../invalid/basic.kmx + Keyboard Basic 0 .kmx - Khmer Angkor - khmer_angkor - 1.3 + Basic + basic + 1.0 Khmer diff --git a/developer/src/kmc-package/test/test-messages.ts b/developer/src/kmc-package/test/test-messages.ts index bc827f1840..5944ce956a 100644 --- a/developer/src/kmc-package/test/test-messages.ts +++ b/developer/src/kmc-package/test/test-messages.ts @@ -6,7 +6,7 @@ import { makePathToFixture } from './helpers/index.js'; import { KmpCompiler } from '../src/compiler/kmp-compiler.js'; import { PackageValidation } from '../src/compiler/package-validation.js'; -const debug = true; +const debug = false; const callbacks = new TestCompilerCallbacks(); describe('CompilerMessages', function () { @@ -190,4 +190,11 @@ describe('CompilerMessages', function () { CompilerMessages.ERROR_PackageMustContainAModelOrAKeyboard); }); + // WARN_JsKeyboardFileIsMissing + + it('should generate WARN_JsKeyboardFileIsMissing if package is missing corresponding .js for a touch .kmx', async function() { + testForMessage(this, ['invalid', 'warn_js_keyboard_file_is_missing.kps'], + CompilerMessages.WARN_JsKeyboardFileIsMissing); + }); + }); diff --git a/developer/src/kmc-package/test/test-package-compiler.ts b/developer/src/kmc-package/test/test-package-compiler.ts index 23d421f90f..59d2acb55a 100644 --- a/developer/src/kmc-package/test/test-package-compiler.ts +++ b/developer/src/kmc-package/test/test-package-compiler.ts @@ -12,7 +12,7 @@ import { makePathToFixture } from './helpers/index.js'; import { KmpCompiler } from '../src/compiler/kmp-compiler.js'; import { CompilerMessages } from '../src/compiler/messages.js'; -const debug = true; +const debug = false; describe('KmpCompiler', function () { const MODELS : string[] = [ -- GitLab From b6173fda3713622827358b3785a3015d3501f25f Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 23 May 2023 11:39:44 +0700 Subject: [PATCH 136/214] fix(developer): 'no keyboard version' no longer emitted The `Info_KeyboardFileHasNoKeyboardVersion` message is now only emitted if the package uses `FollowKeyboardVersion`, which broke a unit test in kmc. --- developer/src/kmc/test/test-project-build.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/developer/src/kmc/test/test-project-build.ts b/developer/src/kmc/test/test-project-build.ts index 68b5926933..e16c9fd464 100644 --- a/developer/src/kmc/test/test-project-build.ts +++ b/developer/src/kmc/test/test-project-build.ts @@ -16,9 +16,9 @@ describe('BuildProject', function () { debug: false, warnDeprecatedCode: true, }); - // 5 messages == starting build, info: no keyboard version, build successful x 2 + // 4 messages == starting build x 2, build successful x 2 // callbacks.printMessages(); - assert.equal(callbacks.messages.length, 5); + assert.equal(callbacks.messages.length, 4); assert.isTrue(result); }); }); -- GitLab From 15142e9a4b6613aebc824f9692f7a280481d1450 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 23 May 2023 11:52:37 +0700 Subject: [PATCH 137/214] chore(developer): cleanup --- .../src/kmcmplib/src/CompilerInterfaces.cpp | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/developer/src/kmcmplib/src/CompilerInterfaces.cpp b/developer/src/kmcmplib/src/CompilerInterfaces.cpp index 8e84e7ff7e..02dda9de10 100644 --- a/developer/src/kmcmplib/src/CompilerInterfaces.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfaces.cpp @@ -165,33 +165,27 @@ EXTERN bool kmcmp_CompileKeyboardFile(char* pszInfile, } FILE_KEYBOARD fk; - bool result = CompileKeyboard(pszInfile, &fk, ASaveDebug, ACompilerWarningsAsErrors, AWarnDeprecatedCode, - pMsgproc, AmsgprocContext, CKF_KEYMAN); - if(!result) { - return false; + if(!CompileKeyboard(pszInfile, &fk, ASaveDebug, ACompilerWarningsAsErrors, AWarnDeprecatedCode, + pMsgproc, AmsgprocContext, CKF_KEYMAN)) { + // any errors will have been reported directly by CompileKeyboard + return FALSE; } FILE* fp_out = Open_File(pszOutfile, "wb"); - if (fp_out == NULL) { SetError(CERR_CannotCreateOutfile); } - if(result) { - KMX_DWORD msg; - KMX_BYTE* data = nullptr; - size_t dataSize = 0; - if ((msg = WriteCompiledKeyboard(&fk, &data, dataSize)) != CERR_None) { - result = FALSE; - AddCompileError(msg); - } else { - if(fwrite(data, 1, dataSize, fp_out) != dataSize) { - AddCompileError(CERR_UnableToWriteFully); - } - delete[] data; - } + KMX_DWORD msg; + KMX_BYTE* data = nullptr; + size_t dataSize = 0; + if ((msg = WriteCompiledKeyboard(&fk, &data, dataSize)) != CERR_None) { + AddCompileError(msg); } else { - AddCompileError(CERR_InvalidValue); + if(fwrite(data, 1, dataSize, fp_out) != dataSize) { + AddCompileError(CERR_UnableToWriteFully); + } + delete[] data; } fclose(fp_out); @@ -201,7 +195,7 @@ EXTERN bool kmcmp_CompileKeyboardFile(char* pszInfile, return FALSE; } - return result; + return TRUE; } bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) -- GitLab From d1d6dc5d9922f67ef41b6f7285f25b9e9398c9cc Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 23 May 2023 15:26:28 +0700 Subject: [PATCH 138/214] refactor(developer): compiler interface part 1 for wasm This starts the refactor of the .kmn compiler interfaces for WASM, moving more file writes into typescript and out of the compiler. Adds a cleaner binding and structures for passing compile metadata back to typescript for additional build steps (e.g. kvk, js builds). Will rebase the Typescript-based KMW compiler onto this so it can start to benefit from the refactoring. * Fixes a minor issue with loading a .kvks file with an empty flags set. * Adds a writeFileSync method to the compiler callback interfaces. * Adds an e2e compiler test to verify that .kmx and .kvk are both correctly compiled. --- .../binary/caps_lock_layer_3620.kmx | Bin 0 -> 4330 bytes .../binary/caps_lock_layer_3620.kvk | Bin 0 -> 101 bytes common/web/types/src/kvk/kvks-file-reader.ts | 7 ++ .../web/types/src/util/compiler-interfaces.ts | 1 + .../src/kmc-kmn/src/compiler/compiler.ts | 98 +++++++++++++--- developer/src/kmc-kmn/test/test-compiler.ts | 50 +++++--- developer/src/kmcmplib/include/kmcmplibapi.h | 2 + developer/src/kmcmplib/src/Compiler.cpp | 5 +- .../src/kmcmplib/src/CompilerInterfaces.cpp | 110 ++++++++++++++++-- developer/src/kmcmplib/src/compfile.h | 11 +- developer/src/kmcmplib/src/kmcmplib.h | 2 +- developer/src/kmcmplib/src/meson.build | 2 +- 12 files changed, 244 insertions(+), 44 deletions(-) create mode 100644 common/test/keyboards/caps_lock_layer_3620/binary/caps_lock_layer_3620.kmx create mode 100644 common/test/keyboards/caps_lock_layer_3620/binary/caps_lock_layer_3620.kvk diff --git a/common/test/keyboards/caps_lock_layer_3620/binary/caps_lock_layer_3620.kmx b/common/test/keyboards/caps_lock_layer_3620/binary/caps_lock_layer_3620.kmx new file mode 100644 index 0000000000000000000000000000000000000000..563a139c19f7c6168fb49117503263b82ac5b616 GIT binary patch literal 4330 zcmeH~e~6A*6vr=Ft7+HXb~h_&o2+KFt;twfY1^I|V}8D7#>_ioX4+VcA2U0~m>J_o zk|arzBuSDaSxJ&4Ns=Tgt&$;KB zx3)FkA$+ff*y6d(Qz)$8#U4T=W7w17Cr+;3XI(;0xaI`7tPm zj|0Quc|IG!M0g*cU7!elfX_W(Ec_9lC&4%HM!879F)#xE5Pu5a0KO&v`XlZOmt}d@ zTL6R?@mUC_z@4jgOWZoQ!Yy@E_cCH+AURI#=rEaJ_TCgCef2cMYzM@2hr|uFB=fmZUq?;%swecuH}U z|Le}Ox^>}u^1)GwKhMe>tB7k_;JSy_Buv+|Ag!sG)eZt#OABjga?N~Gj=%q(cm8kR z_@Q=_-2nGr&3cx*$wMm;JrM4g<6dq2b2$=;tOUz8B~}K&|n;LjP%U;(LRB3v$Ny4n6#{ z4>|FTK#u}*jIRJa+T_IN(O-f(;~Rq>XL8~jk1hoD#y0_7WOCx0g#I2h7+*1Zs>z9O z8hQqpYkV`&KbxHRGITj;G`lM~-- z^c$e_Kzx6p-sgzf%xjsjV33) zJh~Osn?7hq&o?>o{fh1Y4aT<=-DPs(>qhqiod1JHROzK!V3CMUiv z=xspff%vwgcbc5|cA@tGod@FEi{5W?;yZvo1auyV?=bqP$%*e6`UKE~u zv5RAmYLq^V-57gKqx4hks@O9cr7vQ4#AmNjo^O20@fm8A=McR9LEToHJTJ%Pu# zGVmCC1CMc4;4$_E9%FytG0N{q-hLsjHgPcU7}o?I { source = r as KVKSourceFile }); source = this.boxArrays(source); + this.cleanupFlags(source); this.cleanupUnderscore('visualkeyboard', source.visualkeyboard); return source; } + private cleanupFlags(source: any) { + if(source.visualkeyboard?.header?.flags === '') { + source.visualkeyboard.header.flags = {}; + } + } + /** * The only element that allows spaces is . Remove * all other empty whitespace-only values. diff --git a/common/web/types/src/util/compiler-interfaces.ts b/common/web/types/src/util/compiler-interfaces.ts index c7058b1578..849e945321 100644 --- a/common/web/types/src/util/compiler-interfaces.ts +++ b/common/web/types/src/util/compiler-interfaces.ts @@ -109,6 +109,7 @@ export interface CompilerFileSystemCallbacks { readFileSync(path: string, options?: { encoding?: null; flag?: string; } | null): Uint8Array; readFileSync(path: string, options: { encoding: string; flag?: string; } | string): string; readFileSync(path: string, options?: { encoding?: string | null; flag?: string; } | string | null): string | Uint8Array; + writeFileSync(path: string, data: Uint8Array): void; existsSync(name: string): boolean; } diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index 2f83e83aee..352d597104 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -22,10 +22,21 @@ TODO: implement additional interfaces: */ // TODO: rename wasm-host? -import { CompilerCallbacks, CompilerEvent } from '@keymanapp/common-types'; +import { CompilerCallbacks, CompilerEvent, KvkFileWriter, KvksFileReader } from '@keymanapp/common-types'; import loadWasmHost from '../import/kmcmplib/wasm-host.js'; import { CompilerMessages, mapErrorFromKmcmplib } from './messages.js'; +export interface CompilerResultFile { + filename: string; + data: Uint8Array; +}; + +export interface CompilerResult { + kmx?: CompilerResultFile; + kvk?: CompilerResultFile; + js?: CompilerResultFile; +}; + export interface CompilerOptions { shouldAddCompilerVersion?: boolean; saveDebug?: boolean; @@ -136,7 +147,19 @@ export class KmnCompiler { // TODO: use callbacks for file access -- so kmc-kmn is entirely fs agnostic let result = this.runCompiler(infile, outfile, options); delete (globalThis as any)[this.callbackName]; - return result; + //TODO: write the file out! + if(result) { + if(result.kmx) { + this.callbacks.fs.writeFileSync(result.kmx.filename, result.kmx.data); + } + if(result.kvk) { + this.callbacks.fs.writeFileSync(result.kvk.filename, result.kvk.data); + } + if(result.js) { + this.callbacks.fs.writeFileSync(result.js.filename, result.js.data); + } + } + return !!result; } private compilerMessageCallback = (line: number, code: number, msg: string): number => { @@ -144,22 +167,71 @@ export class KmnCompiler { return 1; } - private runCompiler(infile: string, outfile: string, options: CompilerOptions): boolean { + private runCompiler(infile: string, outfile: string, options: CompilerOptions): CompilerResult { try { - if (!this.wasm.setCompilerOptions(options.shouldAddCompilerVersion ? 1 : 0)) { - this.callbacks.reportMessage(CompilerMessages.Fatal_UnableToSetCompilerOptions()); + let result: CompilerResult = {}; + let wasm_interface = new this.wasm.Module.CompilerInterface(); + let wasm_result = null; + try { + wasm_interface.saveDebug = options.saveDebug; + wasm_interface.compilerWarningsAsErrors = options.compilerWarningsAsErrors; + wasm_interface.warnDeprecatedCode = options.warnDeprecatedCode; + wasm_interface.messageCallback = this.callbackName; + wasm_interface.loadFileCallback = this.callbackName; + wasm_result = this.wasm.Module.kmcmp_compile(infile, wasm_interface); + if(!wasm_result.result) { + return null; + } + + if(wasm_result.kvksFilename) { + result.kvk = this.runKvkCompiler(wasm_result.kvksFilename, infile, outfile); + if(!result.kvk) { + return null; + } + } + + result.kmx = { + filename: outfile, + data: new Uint8Array(this.wasm.Module.HEAP8.buffer, wasm_result.kmx, wasm_result.kmxSize) + }; + + return result; + } finally { + if(wasm_result) { + wasm_result.delete(); + } + wasm_interface.delete(); } - return this.wasm.compileKeyboardFile( - infile, - outfile, - options.saveDebug ? 1 : 0, - options.compilerWarningsAsErrors ? 1 : 0, - options.warnDeprecatedCode ? 1 : 0, - this.callbackName); } catch(e) { this.callbacks.reportMessage(CompilerMessages.Fatal_UnexpectedException({e:e})); - return false; + return null; + } + } + + private runKvkCompiler(kvksFilename: string, kmnFilename: string, kmxFilename: string) { + // The compiler detected a .kvks file, which needs to be captured + let reader = new KvksFileReader(); + kvksFilename = this.callbacks.resolveFilename(kmnFilename, kvksFilename); + let kvks = reader.read(this.callbacks.loadFile(kvksFilename)); + try { + reader.validate(kvks, this.callbacks.loadSchema('kvks')); + } catch(e) { + console.log(e); + // TODO: this.callbacks.reportMessage(CompilerMessages.Error_InvalidKvksFile({e})); + return null; + } + let errors: any = []; //TODO: KVKSParseError[]; + let vk = reader.transform(kvks, errors); + if(!vk || errors.length) { + console.dir(errors); + // TODO: this.callbacks.reportMessage(CompilerMessages.Error_InvalidKvksFile({e})); + return null; } + let writer = new KvkFileWriter(); + return { + filename: this.callbacks.path.join(this.callbacks.path.dirname(kmxFilename), this.callbacks.path.basename(kvksFilename, '.kvks') + '.kvk'), + data: writer.write(vk) + }; } /** diff --git a/developer/src/kmc-kmn/test/test-compiler.ts b/developer/src/kmc-kmn/test/test-compiler.ts index 2eacd219e6..925656f8f5 100644 --- a/developer/src/kmc-kmn/test/test-compiler.ts +++ b/developer/src/kmc-kmn/test/test-compiler.ts @@ -1,7 +1,5 @@ import 'mocha'; -import sinon from 'sinon'; -import chai, { assert } from 'chai'; -import sinonChai from 'sinon-chai'; +import { assert } from 'chai'; import { KmnCompiler } from '../src/main.js'; import { dirname } from 'path'; import { fileURLToPath } from 'url'; @@ -9,21 +7,10 @@ import fs from 'fs'; import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; const __dirname = dirname(fileURLToPath(import.meta.url)).replace(/\\/g, '/'); -const baselineDir = __dirname + '/../../../../../common/test/keyboards/baseline/'; -chai.use(sinonChai); +const keyboardsDir = __dirname + '/../../../../../common/test/keyboards/'; +const baselineDir = keyboardsDir + 'baseline/'; describe('Compiler class', function() { - let consoleLog: any; - - // TODO: do we need this? - beforeEach(function() { - consoleLog = sinon.spy(console, 'log'); - }); - - afterEach(function() { - consoleLog.restore(); - }); - it('should throw on failure', async function() { const compiler = new KmnCompiler(); const callbacks : any = null; // ERROR @@ -87,4 +74,35 @@ describe('Compiler class', function() { } } }); + + it('should compile a keyboard with visual keyboard', async function() { + const compiler = new KmnCompiler(); + const callbacks = new TestCompilerCallbacks(); + assert(await compiler.init(callbacks)); + assert(compiler.verifyInitialized()); + + const fixtureDir = keyboardsDir + 'caps_lock_layer_3620/' + const infile = fixtureDir + 'source/caps_lock_layer_3620.kmn'; + const kmxFixture = fixtureDir + '/binary/caps_lock_layer_3620.kmx'; + const kvkFixture = fixtureDir + '/binary/caps_lock_layer_3620.kvk'; + + const kmxfile = __dirname + '/caps_lock_layer_3620.kmx'; + const kvkfile = __dirname + '/caps_lock_layer_3620.kvk'; + + assert(compiler.run(infile, kmxfile, {saveDebug: true, shouldAddCompilerVersion: false})); + + assert(fs.existsSync(kmxfile)); + assert(fs.existsSync(kvkfile)); + + const kmxData = fs.readFileSync(kmxfile); + const kmxFixtureData = fs.readFileSync(kmxFixture); + assert.equal(kmxData.byteLength, kmxFixtureData.byteLength); + assert.deepEqual(kmxData, kmxFixtureData); + + const kvkData = fs.readFileSync(kvkfile); + const kvkFixtureData = fs.readFileSync(kvkFixture); + assert.equal(kvkData.byteLength, kvkFixtureData.byteLength); + assert.deepEqual(kvkData, kvkFixtureData); + }); + }); diff --git a/developer/src/kmcmplib/include/kmcmplibapi.h b/developer/src/kmcmplib/include/kmcmplibapi.h index 97d46c3c36..2fb35979b2 100644 --- a/developer/src/kmcmplib/include/kmcmplibapi.h +++ b/developer/src/kmcmplib/include/kmcmplibapi.h @@ -4,6 +4,8 @@ #ifdef __EMSCRIPTEN__ #include +#include + #else #define EMSCRIPTEN_KEEPALIVE #endif diff --git a/developer/src/kmcmplib/src/Compiler.cpp b/developer/src/kmcmplib/src/Compiler.cpp index 7520bd0450..cb636126fd 100644 --- a/developer/src/kmcmplib/src/Compiler.cpp +++ b/developer/src/kmcmplib/src/Compiler.cpp @@ -784,7 +784,7 @@ KMX_DWORD ProcessStoreLine(PFILE_KEYBOARD fk, PKMX_WCHAR p) return CheckForDuplicateStore(fk, sp); } -KMX_DWORD AddStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, KMX_WCHAR const * str, KMX_DWORD *dwStoreID) +KMX_DWORD AddStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, const KMX_WCHAR * str, KMX_DWORD *dwStoreID) { PFILE_STORE sp; sp = new FILE_STORE[fk->cxStoreArray + 1]; @@ -1023,6 +1023,9 @@ KMX_DWORD ProcessSystemStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, PFILE_STORE case TSS_VISUALKEYBOARD: VERIFY_KEYBOARD_VERSION(fk, VERSION_70, CERR_70FeatureOnly); { + // Store extra metadata for callers as we mutate this store during + // compilation + fk->extra.kvksFilename = sp->dpString; // Strip path from the store, leaving bare filename only p = sp->dpString; diff --git a/developer/src/kmcmplib/src/CompilerInterfaces.cpp b/developer/src/kmcmplib/src/CompilerInterfaces.cpp index 02dda9de10..43655033fc 100644 --- a/developer/src/kmcmplib/src/CompilerInterfaces.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfaces.cpp @@ -14,6 +14,10 @@ #define SetError(err) { if(AddCompileError(err) || (err & CERR_FATAL)) return FALSE; } bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk); +bool CompileKeyboard(const char* pszInfile, + void* pfkBuffer, bool ASaveDebug, bool ACompilerWarningsAsErrors, + bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, const void* AmsgprocContext, + int Target); EXTERN bool kmcmp_SetCompilerOptions(KMCMP_COMPILER_OPTIONS* options) { //printf("°°-> changed to SetCompilerOptions() of kmcmplib \n"); @@ -44,6 +48,7 @@ int wasm_CompilerMessageProc(int line, uint32_t dwMsgCode, char* szText, void* c return wasm_msgproc(line, dwMsgCode, szText, msgProc); } +//DEPRECATED EXTERN bool kmcmp_Wasm_SetCompilerOptions(int ShouldAddCompilerVersion) { KMCMP_COMPILER_OPTIONS options; options.dwSize = sizeof(KMCMP_COMPILER_OPTIONS); @@ -51,6 +56,7 @@ EXTERN bool kmcmp_Wasm_SetCompilerOptions(int ShouldAddCompilerVersion) { return kmcmp_SetCompilerOptions(&options); } +//DEPRECATED EXTERN bool kmcmp_Wasm_CompileKeyboardFile(char* pszInfile, char* pszOutfile, int ASaveDebug, int ACompilerWarningsAsErrors, int AWarnDeprecatedCode, char* msgProc @@ -74,11 +80,97 @@ EXTERN int kmcmp_Wasm_ParseUnicodeSet(char* pat, ); } + +struct COMPILER_INTERFACE { + bool saveDebug; + bool compilerWarningsAsErrors; + bool warnDeprecatedCode; + bool shouldAddCompilerVersion; + int target; // CKF_KEYMAN, CKF_KEYMANWEB + std::string messageCallback; // int line, uint32_t dwMsgCode, char* szText + std::string loadFileCallback; // char* infile, char* filenameRelativeToInfile --> buffer +}; + +struct COMPILER_RESULT { + bool result; + // Following are pointer offsets in heap + buffer size + int kmx; + int kmxSize; + // Following are compiler side-channel data, required for + // follow-on transform + std::string kvksFilename; + // TODO: additional data to be passed back +}; + +COMPILER_RESULT kmcmp_compile(std::string pszInfile, const COMPILER_INTERFACE intf) { + COMPILER_RESULT r = {false}; + + FILE_KEYBOARD fk; + + // TODO: this should be included in CompileKeyboard? + kmcmp::FShouldAddCompilerVersion = intf.shouldAddCompilerVersion; + + r.result = CompileKeyboard( + pszInfile.c_str(), + &fk, + intf.saveDebug, + intf.compilerWarningsAsErrors, + intf.warnDeprecatedCode, + wasm_CompilerMessageProc, + intf.messageCallback.c_str(), + intf.target); + + if(!r.result) { + return r; + } + + KMX_DWORD msg; + KMX_BYTE* data = nullptr; + size_t dataSize = 0; + msg = WriteCompiledKeyboard(&fk, &data, dataSize); + //TODO: FreeKeyboardPointers(fk); + + if(msg != CERR_None) { + AddCompileError(msg); + r.result = FALSE; + return r; + } + + r.kmx = (int) data; + r.kmxSize = (int) dataSize; + r.kvksFilename = string_from_u16string(fk.extra.kvksFilename); // convert to UTF8 + + return r; +} + +EMSCRIPTEN_BINDINGS(compiler_interface) { + emscripten::class_("CompilerInterface") + .constructor<>() + .property("saveDebug", &COMPILER_INTERFACE::saveDebug) + .property("compilerWarningsAsErrors", &COMPILER_INTERFACE::compilerWarningsAsErrors) + .property("warnDeprecatedCode", &COMPILER_INTERFACE::warnDeprecatedCode) + .property("shouldAddCompilerVersion", &COMPILER_INTERFACE::shouldAddCompilerVersion) + .property("target", &COMPILER_INTERFACE::target) + .property("messageCallback", &COMPILER_INTERFACE::messageCallback) + .property("loadFileCallback", &COMPILER_INTERFACE::loadFileCallback) + ; + + emscripten::class_("CompilerResult") + .constructor<>() + .property("result", &COMPILER_RESULT::result) + .property("kmx", &COMPILER_RESULT::kmx) + .property("kmxSize", &COMPILER_RESULT::kmxSize) + .property("kvksFilename", &COMPILER_RESULT::kvksFilename) + ; + + emscripten::function("kmcmp_compile", &kmcmp_compile); +} + #endif -bool CompileKeyboard(char* pszInfile, +bool CompileKeyboard(const char* pszInfile, void* pfkBuffer, bool ASaveDebug, bool ACompilerWarningsAsErrors, - bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, void* AmsgprocContext, + bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, const void* AmsgprocContext, int Target) { FILE* fp_in = NULL; @@ -95,7 +187,7 @@ bool CompileKeyboard(char* pszInfile, PKMX_STR p; - if ((p = strrchr_slash(pszInfile)) != nullptr) + if ((p = strrchr_slash((char*)pszInfile)) != nullptr) { strncpy(kmcmp::CompileDir, pszInfile, (int)(p - pszInfile + 1)); // I3481 kmcmp::CompileDir[(int)(p - pszInfile + 1)] = 0; @@ -104,7 +196,7 @@ bool CompileKeyboard(char* pszInfile, kmcmp::CompileDir[0] = 0; msgproc = pMsgproc; - msgprocContext = AmsgprocContext; + msgprocContext = (void*)AmsgprocContext; kmcmp::currentLine = 0; kmcmp::nErrors = 0; @@ -231,7 +323,7 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) fk->dpDeadKeyArray = NULL; fk->cxVKDictionary = 0; // I3438 fk->dpVKDictionary = NULL; // I3438 - + fk->extra.kvksFilename = u""; /* fk->szMessage[0] = 0; fk->szLanguageName[0] = 0;*/ fk->dwBitmapSize = 0; @@ -251,12 +343,8 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) } /* Add a system store for the Keyman edition number */ - u16sprintf(str, LINESIZE, L"%d", 0); // I3481 - AddStore(fk, TSS_CUSTOMKEYMANEDITION, str); - - PKMX_WCHAR tbuf = strtowstr((KMX_CHAR*) "Keyman"); - AddStore(fk, TSS_CUSTOMKEYMANEDITIONNAME, tbuf); - delete tbuf; + AddStore(fk, TSS_CUSTOMKEYMANEDITION, u"0"); + AddStore(fk, TSS_CUSTOMKEYMANEDITIONNAME, u"Keyman"); // must preprocess for group and store names -> this isn't really necessary, but never mind! while ((msg = ReadLine(fp_in, str, TRUE)) == CERR_None) diff --git a/developer/src/kmcmplib/src/compfile.h b/developer/src/kmcmplib/src/compfile.h index 48be5f2048..3fb106411f 100644 --- a/developer/src/kmcmplib/src/compfile.h +++ b/developer/src/kmcmplib/src/compfile.h @@ -121,6 +121,13 @@ struct FILE_VKDICTIONARY }; typedef FILE_VKDICTIONARY *PFILE_VKDICTIONARY; +/** + * Extra metadata for API consumers + */ +struct FILE_KEYBOARD_EXTRA { + std::u16string kvksFilename; // original TSS_VISUALKEYBOARD value +}; + struct FILE_KEYBOARD { KMX_DWORD KeyboardID; // as stored in HKEY_LOCAL_MACHINE//system//currentcontrolset//control//keyboard layouts @@ -149,7 +156,9 @@ struct FILE_KEYBOARD { PFILE_DEADKEY dpDeadKeyArray; // temp - dead key array KMX_DWORD cxVKDictionary; PFILE_VKDICTIONARY dpVKDictionary; // temp - virtual key dictionary - }; + + FILE_KEYBOARD_EXTRA extra; +}; typedef FILE_KEYBOARD *PFILE_KEYBOARD; diff --git a/developer/src/kmcmplib/src/kmcmplib.h b/developer/src/kmcmplib/src/kmcmplib.h index b547ecf844..78e945ee0d 100644 --- a/developer/src/kmcmplib/src/kmcmplib.h +++ b/developer/src/kmcmplib/src/kmcmplib.h @@ -42,7 +42,7 @@ PKMX_WCHAR strtowstr(PKMX_STR in); PFILE_STORE FindSystemStore(PFILE_KEYBOARD fk, KMX_DWORD dwSystemID); FILE* UTF16TempFromUTF8(FILE* fp_in , KMX_BOOL hasPreamble); KMX_DWORD WriteCompiledKeyboard(PFILE_KEYBOARD fk, KMX_BYTE**data, size_t& dataSize); -KMX_DWORD AddStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, KMX_WCHAR const * str, KMX_DWORD *dwStoreID= NULL); +KMX_DWORD AddStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, const KMX_WCHAR * str, KMX_DWORD *dwStoreID= NULL); KMX_DWORD ReadLine(FILE* fp_in , PKMX_WCHAR wstr, KMX_BOOL PreProcess); KMX_DWORD ParseLine(PFILE_KEYBOARD fk, PKMX_WCHAR str); KMX_DWORD ProcessGroupLine(PFILE_KEYBOARD fk, PKMX_WCHAR p); diff --git a/developer/src/kmcmplib/src/meson.build b/developer/src/kmcmplib/src/meson.build index fa51ca28a5..292b158ce2 100644 --- a/developer/src/kmcmplib/src/meson.build +++ b/developer/src/kmcmplib/src/meson.build @@ -24,7 +24,7 @@ endif name_suffix = [] if cpp_compiler.get_id() == 'emscripten' - links += ['-lnodefs.js', '-sMODULARIZE', '-sEXPORT_ES6', '-sEXPORTED_RUNTIME_METHODS=[\'cwrap\', \'UTF8ToString\']'] + links += ['-lnodefs.js', '-sMODULARIZE', '-sEXPORT_ES6', '--whole-archive', '--bind', '-sEXPORTED_RUNTIME_METHODS=[\'cwrap\', \'UTF8ToString\']'] # tests are building as ES6 so we need to declare the file extension # note that meson currently struggles with the sanitycheckc_cross.exe # program, because it has a hard coded extension (.exe) which is not -- GitLab From 29a35f1b31883d5f24abd9e0bedbf347354faa32 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 23 May 2023 10:27:40 +0200 Subject: [PATCH 139/214] chore(linux): Add missing dependency to GHA Since we reference `sourcepackage` in the upload-to-llso step it should be listed in the `needs` list. --- .github/workflows/deb-packaging.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deb-packaging.yml b/.github/workflows/deb-packaging.yml index 7b12bf8880..8c745bef30 100644 --- a/.github/workflows/deb-packaging.yml +++ b/.github/workflows/deb-packaging.yml @@ -159,7 +159,7 @@ jobs: upload-to-llso: name: Upload packages to llso - needs: deb_signing + needs: [sourcepackage, deb_signing] runs-on: self-hosted environment: "deploy (linux)" if: github.event.client_payload.isTestBuild == 'false' -- GitLab From 1823e1febbbb204f88a5d4d70e7a4f4f24ac7e57 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 23 May 2023 11:11:11 +0200 Subject: [PATCH 140/214] feat(linux): Address code review comments --- linux/ibus-keyman/src/KeymanSystemServiceClient.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/linux/ibus-keyman/src/KeymanSystemServiceClient.cpp b/linux/ibus-keyman/src/KeymanSystemServiceClient.cpp index 8f2de148d2..90f459d1a2 100644 --- a/linux/ibus-keyman/src/KeymanSystemServiceClient.cpp +++ b/linux/ibus-keyman/src/KeymanSystemServiceClient.cpp @@ -1,3 +1,4 @@ +#include #include #include "KeymanSystemServiceClient.h" @@ -40,6 +41,10 @@ KeymanSystemServiceClient::~KeymanSystemServiceClient() { } void KeymanSystemServiceClient::SetCapsLockIndicator(guint32 capsLock) { + // If Set/GetCapsLockIndicator is called more than once and previously + // failed, we will leak `error`. + assert(error == NULL); + if (!bus) { // we already reported the error, so just return return; @@ -60,6 +65,10 @@ void KeymanSystemServiceClient::SetCapsLockIndicator(guint32 capsLock) { } gint32 KeymanSystemServiceClient::GetCapsLockIndicator() { + // If Set/GetCapsLockIndicator is called more than once and previously + // failed, we will leak `error`. + assert(error == NULL); + if (!bus) { // we already reported the error, so just return return -1; -- GitLab From cdf5f7a7c45b51ae32752946e5453f0d92f6a1a0 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 24 May 2023 12:14:41 +0700 Subject: [PATCH 141/214] chore(developer): consolidate 'extra' field for FILE_KEYBOARD FILE_KEYBOARD is a structure used in multiple libraries and languages. It is passed around between kmcmplib, kmcmpdll, and kmcomp, with three separate definitions (kmcmplib/compfile.h, kmcmpdll/compfile.h, and kmcomp/compile.pas). These duplicate definitions must be maintained for now because of type issues between the legacy kmcmpdll and kmcmplib, which means that the definitions must be kept in sync. Because FILE_KEYBOARD_EXTRA has a C++ class in it, it will be initialized in CompileKeyboardHandle rather than in the caller, so FILE_KEYBOARD.extra is now a pointer rather than a struct. When original kmcomp and kmcmpdll are eventually removed, these duplications will disappear and some of the memory management and lifecycle will become easier to manage. --- .../src/common/delphi/compiler/compile.pas | 6 +- .../src/kmc-kmn/src/compiler/compiler.ts | 20 +-- developer/src/kmcmpdll/compfile.h | 116 +++++++------- developer/src/kmcmpdll/kcframe/kcframe.cpp | 2 + developer/src/kmcmplib/meson.build | 3 +- developer/src/kmcmplib/src/Compiler.cpp | 2 +- .../src/kmcmplib/src/CompilerInterfaces.cpp | 5 +- developer/src/kmcmplib/src/compfile.h | 144 +++++++++--------- 8 files changed, 149 insertions(+), 149 deletions(-) diff --git a/developer/src/common/delphi/compiler/compile.pas b/developer/src/common/delphi/compiler/compile.pas index 9b304b39d8..b89ef0eb72 100644 --- a/developer/src/common/delphi/compiler/compile.pas +++ b/developer/src/common/delphi/compiler/compile.pas @@ -126,6 +126,8 @@ type dpDeadKeyArray: PFILE_DEADKEY; // temp - dead key array cxVKDictionary: DWORD; // I3438 dpVKDictionary: PFILE_VKDICTIONARY; // I3438 // temp - virtual key dictionary + + extra: Pointer; end; PFILE_KEYBOARD = ^FILE_KEYBOARD; @@ -152,13 +154,13 @@ const const // kcframe --sizeof returns these values {$IFDEF WIN64} - FILE_KEYBOARD_SIZE = 2984; + FILE_KEYBOARD_SIZE = 2992; FILE_GROUP_SIZE = 200; FILE_STORE_SIZE = 200; FILE_KEY_SIZE = 32; FILE_DEADKEY_SIZE = 160; {$ELSE} - FILE_KEYBOARD_SIZE = 2952; + FILE_KEYBOARD_SIZE = 2956; FILE_GROUP_SIZE = 188; FILE_STORE_SIZE = 192; FILE_KEY_SIZE = 20; diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index 352d597104..93ee3c36e8 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -1,24 +1,8 @@ /* TODO: implement additional interfaces: - extern "C" bool kmcmp_CompileKeyboardFileToBuffer( - char* pszInfile, - void* pfkBuffer, - bool ACompilerWarningsAsErrors, - bool AWarnDeprecatedCode, - kmcmp_CompilerMessageProc pMsgproc, - void* AmsgprocContext, - int Target - ); - - typedef bool (*kmcmp_ValidateJsonMessageProc)(int64_t offset, const char* szText, void* context); - - extern "C" bool kmcmp_ValidateJsonFile( - std::fstream& f, - std::fstream& fd, - kmcmp_ValidateJsonMessageProc MessageProc, - void* context - ); + typedef bool (*kmcmp_ValidateJsonMessageProc)(); + extern "C" bool kmcmp_ValidateJsonFile(); */ // TODO: rename wasm-host? diff --git a/developer/src/kmcmpdll/compfile.h b/developer/src/kmcmpdll/compfile.h index 4fd6e68eb5..2f6e2e654f 100644 --- a/developer/src/kmcmpdll/compfile.h +++ b/developer/src/kmcmpdll/compfile.h @@ -22,6 +22,13 @@ #include "../../../common/windows/cpp/include/legacy_kmx_file.h" + +// This file is deprecated; see kmcmplib/src/compfile.h. However, as long as +// this file continues to live, we need to keep structures in it in exact sync +// with kmcmplib/src/compfile.h, as FILE_KEYBOARD is passed between kmcmplib and +// kmcmpdll. KMX_WCHAR on Windows is identical to wchar_t, so it is safe to map +// accordingly. + #define LINESIZE 8192 #define GLOBAL_BUFSIZE 4096 @@ -70,9 +77,9 @@ enum FileStoreType { FST_STORE, FST_OPTION, FST_RESERVED }; struct FILE_STORE { - DWORD dwSystemID; - WCHAR szName[SZMAX_STORENAME]; // the name of the store - PWSTR dpString; // from start of store structure + DWORD dwSystemID; + WCHAR szName[SZMAX_STORENAME]; // the name of the store + PWSTR dpString; // from start of store structure //FileStoreType fstType; BOOL fIsStore; BOOL fIsReserved; @@ -80,28 +87,27 @@ struct FILE_STORE { BOOL fIsDebug; BOOL fIsCall; int line; // TODO: int vs dword, line vs Line (see FILE_KEY, FILE_GROUP) - }; + }; typedef FILE_STORE *PFILE_STORE; struct FILE_KEY { - WCHAR Key; // WCHAR for consistency; only a byte used however - WORD LineStoreIndex; - DWORD Line; - DWORD ShiftFlags; - PWSTR dpOutput; // from start of key structure - PWSTR dpContext; // from start of key structure - }; - + WCHAR Key; // WCHAR for consistency; only a byte used however + WORD LineStoreIndex; + DWORD Line; + DWORD ShiftFlags; + PWSTR dpOutput; // from start of key structure + PWSTR dpContext; // from start of key structure + }; typedef FILE_KEY *PFILE_KEY; struct FILE_GROUP { - WCHAR szName[SZMAX_GROUPNAME]; - PFILE_KEY dpKeyArray; // address of first item in key array, from start of group structure - PWSTR dpMatch; // from start of group structure - PWSTR dpNoMatch; // from start of group structure - DWORD cxKeyArray; // in array items - BOOL fUsingKeys; // group(xx) [using keys] <-- specified or not + WCHAR szName[SZMAX_GROUPNAME]; + PFILE_KEY dpKeyArray; // address of first item in key array, from start of group structure + PWSTR dpMatch; // from start of group structure + PWSTR dpNoMatch; // from start of group structure + DWORD cxKeyArray; // in array items + BOOL fUsingKeys; // group(xx) [using keys] <-- specified or not BOOL fReadOnly; // group(xx) [readonly] <-- specified or not DWORD Line; }; @@ -110,7 +116,7 @@ typedef FILE_GROUP *PFILE_GROUP; struct FILE_DEADKEY { - WCHAR szName[SZMAX_DEADKEYNAME]; + WCHAR szName[SZMAX_DEADKEYNAME]; }; typedef FILE_DEADKEY *PFILE_DEADKEY; @@ -123,34 +129,36 @@ struct FILE_VKDICTIONARY typedef FILE_VKDICTIONARY *PFILE_VKDICTIONARY; struct FILE_KEYBOARD { - DWORD KeyboardID; // as stored in HKEY_LOCAL_MACHINE//system//currentcontrolset//control//keyboard layouts + DWORD KeyboardID; // as stored in HKEY_LOCAL_MACHINE//system//currentcontrolset//control//keyboard layouts - DWORD version; // keyboard file version with VERSION keyword + DWORD version; // keyboard file version with VERSION keyword - PFILE_STORE dpStoreArray; // address of first item in store array, from start of store structure - PFILE_GROUP dpGroupArray; // address of first item in group array, from start of group structure + PFILE_STORE dpStoreArray; // address of first item in store array, from start of store structure + PFILE_GROUP dpGroupArray; // address of first item in group array, from start of group structure - DWORD cxStoreArray; // in number of items - DWORD cxGroupArray; // in number of items - DWORD StartGroup[2]; // index of starting groups [ANSI=0, Unicode=1] + DWORD cxStoreArray; // in number of items + DWORD cxGroupArray; // in number of items + DWORD StartGroup[2]; // index of starting groups [ANSI=0, Unicode=1] - DWORD dwHotKey; // standard windows hotkey (hiword=shift/ctrl/alt stuff, loword=vkey) + DWORD dwHotKey; // standard windows hotkey (hiword=shift/ctrl/alt stuff, loword=vkey) - WCHAR szName[SZMAX_KEYBOARDNAME]; // Keyboard layout name - WCHAR szLanguageName[SZMAX_LANGUAGENAME]; // Language name - WCHAR szCopyright[SZMAX_COPYRIGHT]; // Copyright information - WCHAR szMessage[SZMAX_MESSAGE]; // General information about the keyboard - PBYTE lpBitmap; - DWORD dwBitmapSize; - DWORD dwFlags; // Flags for the keyboard file + WCHAR szName[SZMAX_KEYBOARDNAME]; // Keyboard layout name + WCHAR szLanguageName[SZMAX_LANGUAGENAME]; // Language name + WCHAR szCopyright[SZMAX_COPYRIGHT]; // Copyright information + WCHAR szMessage[SZMAX_MESSAGE]; // General information about the keyboard + PBYTE lpBitmap; + DWORD dwBitmapSize; + DWORD dwFlags; // Flags for the keyboard file - DWORD currentGroup; // temp - current processing group - DWORD currentStore; // temp - current processing store - DWORD cxDeadKeyArray; - PFILE_DEADKEY dpDeadKeyArray; // temp - dead key array + DWORD currentGroup; // temp - current processing group + DWORD currentStore; // temp - current processing store + DWORD cxDeadKeyArray; + PFILE_DEADKEY dpDeadKeyArray; // temp - dead key array DWORD cxVKDictionary; PFILE_VKDICTIONARY dpVKDictionary; // temp - virtual key dictionary - }; + + void* extra; // used by kmcmplib and its consumers; unused in kmcmpdll +}; typedef FILE_KEYBOARD *PFILE_KEYBOARD; @@ -168,34 +176,34 @@ const DWORD sz_FILE_VKDICTIONARY = sizeof(FILE_VKDICTIONARY); const DWORD sz_FILE_KEYBOARD = sizeof(FILE_KEYBOARD); struct COMPMSG { - char szText[SZMAX_ERRORTEXT]; - DWORD Line; - DWORD dwMsgCode; - }; + char szText[SZMAX_ERRORTEXT]; + DWORD Line; + DWORD dwMsgCode; + }; typedef COMPMSG *PCOMPMSG; struct COMPILEMESSAGES { - int nMessages; - int nErrors; + int nMessages; + int nErrors; - PCOMPMSG cm; + PCOMPMSG cm; - DWORD fatalCode; - char szFatalText[SZMAX_ERRORTEXT]; + DWORD fatalCode; + char szFatalText[SZMAX_ERRORTEXT]; - DWORD currentLine; - }; + DWORD currentLine; + }; typedef COMPILEMESSAGES *PCOMPILEMESSAGES; /* struct TVersion { - //int MinVersion; // 0x0500 usually - //int CompilerVersion[4]; - //int MinCompilerVersion[4]; - int KeyboardVersion; // 0x0500 usually + //int MinVersion; // 0x0500 usually + //int CompilerVersion[4]; + //int MinCompilerVersion[4]; + int KeyboardVersion; // 0x0500 usually }; extern TVersion FVersionInfo; diff --git a/developer/src/kmcmpdll/kcframe/kcframe.cpp b/developer/src/kmcmpdll/kcframe/kcframe.cpp index 4ac80bfe18..22402e5230 100644 --- a/developer/src/kmcmpdll/kcframe/kcframe.cpp +++ b/developer/src/kmcmpdll/kcframe/kcframe.cpp @@ -24,6 +24,8 @@ #include +extern "C" BOOL CompileKeyboardFile(PSTR pszInfile, PSTR pszOutfile, BOOL FSaveDebug, BOOL ACompilerWarningsAsErrors, BOOL AWarnDeprecatedCode, CompilerMessageProc pMsgProc); // I4865 // I4866 + int WINAPI msgproc(int line, DWORD dwMsgCode, LPSTR szText) { printf("line %d error %x %s\n", line, (unsigned int) dwMsgCode, szText); diff --git a/developer/src/kmcmplib/meson.build b/developer/src/kmcmplib/meson.build index ae8fd6ac62..c996981f47 100644 --- a/developer/src/kmcmplib/meson.build +++ b/developer/src/kmcmplib/meson.build @@ -10,7 +10,8 @@ project('kmcmplib', 'cpp', 'c', default_options : ['buildtype=release', 'cpp_std=c++14', 'b_vscrt=static_from_buildtype', - 'default_library=static']) + 'default_library=static', + 'debug=true']) # Import our standard compiler defines; this is copied from # /resources/build/standard.meson.build by build.sh, because diff --git a/developer/src/kmcmplib/src/Compiler.cpp b/developer/src/kmcmplib/src/Compiler.cpp index cb636126fd..b09e36cbc1 100644 --- a/developer/src/kmcmplib/src/Compiler.cpp +++ b/developer/src/kmcmplib/src/Compiler.cpp @@ -1025,7 +1025,7 @@ KMX_DWORD ProcessSystemStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, PFILE_STORE { // Store extra metadata for callers as we mutate this store during // compilation - fk->extra.kvksFilename = sp->dpString; + fk->extra->kvksFilename = sp->dpString; // Strip path from the store, leaving bare filename only p = sp->dpString; diff --git a/developer/src/kmcmplib/src/CompilerInterfaces.cpp b/developer/src/kmcmplib/src/CompilerInterfaces.cpp index 43655033fc..d7b8118b58 100644 --- a/developer/src/kmcmplib/src/CompilerInterfaces.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfaces.cpp @@ -138,7 +138,7 @@ COMPILER_RESULT kmcmp_compile(std::string pszInfile, const COMPILER_INTERFACE in r.kmx = (int) data; r.kmxSize = (int) dataSize; - r.kvksFilename = string_from_u16string(fk.extra.kvksFilename); // convert to UTF8 + r.kvksFilename = string_from_u16string(fk.extra->kvksFilename); // convert to UTF8 return r; } @@ -323,7 +323,8 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) fk->dpDeadKeyArray = NULL; fk->cxVKDictionary = 0; // I3438 fk->dpVKDictionary = NULL; // I3438 - fk->extra.kvksFilename = u""; + fk->extra = new FILE_KEYBOARD_EXTRA; + fk->extra->kvksFilename = u""; /* fk->szMessage[0] = 0; fk->szLanguageName[0] = 0;*/ fk->dwBitmapSize = 0; diff --git a/developer/src/kmcmplib/src/compfile.h b/developer/src/kmcmplib/src/compfile.h index 3fb106411f..4b639a7eb1 100644 --- a/developer/src/kmcmplib/src/compfile.h +++ b/developer/src/kmcmplib/src/compfile.h @@ -22,6 +22,7 @@ #include "kmcompx.h" #include +#include #define LINESIZE 8192 #define GLOBAL_BUFSIZE 4096 @@ -71,53 +72,52 @@ enum FileStoreType { FST_STORE, FST_OPTION, FST_RESERVED }; struct FILE_STORE { - KMX_DWORD dwSystemID; - KMX_WCHAR szName[SZMAX_STORENAME]; // the name of the store - PKMX_WCHAR dpString; // from start of store structure - //FileStoreType fstType; - KMX_BOOL fIsStore; - KMX_BOOL fIsReserved; - KMX_BOOL fIsOption; - KMX_BOOL fIsDebug; - KMX_BOOL fIsCall; - int line; - }; - -typedef FILE_STORE * PFILE_STORE; - + KMX_DWORD dwSystemID; + KMX_WCHAR szName[SZMAX_STORENAME]; // the name of the store + PKMX_WCHAR dpString; // from start of store structure + //FileStoreType fstType; + KMX_BOOL fIsStore; + KMX_BOOL fIsReserved; + KMX_BOOL fIsOption; + KMX_BOOL fIsDebug; + KMX_BOOL fIsCall; + int line; + }; + +typedef FILE_STORE *PFILE_STORE; struct FILE_KEY { - KMX_WCHAR Key; // WCHAR for consistency; only a byte used however - KMX_WORD LineStoreIndex; - KMX_DWORD Line; - KMX_DWORD ShiftFlags; - PKMX_WCHAR dpOutput; // from start of key structure - PKMX_WCHAR dpContext; // from start of key structure - }; + KMX_WCHAR Key; // WCHAR for consistency; only a byte used however + KMX_WORD LineStoreIndex; + KMX_DWORD Line; + KMX_DWORD ShiftFlags; + PKMX_WCHAR dpOutput; // from start of key structure + PKMX_WCHAR dpContext; // from start of key structure + }; typedef FILE_KEY *PFILE_KEY; - struct FILE_GROUP { - KMX_WCHAR szName[SZMAX_GROUPNAME]; - PFILE_KEY dpKeyArray; // address of first item in key array, from start of group structure - PKMX_WCHAR dpMatch; // from start of group structure - PKMX_WCHAR dpNoMatch; // from start of group structure - KMX_DWORD cxKeyArray; // in array items - KMX_BOOL fUsingKeys; // group(xx) [using keys] <-- specified or not - KMX_BOOL fReadOnly; // group(xx) [readonly] <-- specified or not - KMX_DWORD Line; - }; + KMX_WCHAR szName[SZMAX_GROUPNAME]; + PFILE_KEY dpKeyArray; // address of first item in key array, from start of group structure + PKMX_WCHAR dpMatch; // from start of group structure + PKMX_WCHAR dpNoMatch; // from start of group structure + KMX_DWORD cxKeyArray; // in array items + KMX_BOOL fUsingKeys; // group(xx) [using keys] <-- specified or not + KMX_BOOL fReadOnly; // group(xx) [readonly] <-- specified or not + KMX_DWORD Line; +}; typedef FILE_GROUP *PFILE_GROUP; struct FILE_DEADKEY { - KMX_WCHAR szName[SZMAX_DEADKEYNAME]; + KMX_WCHAR szName[SZMAX_DEADKEYNAME]; }; + typedef FILE_DEADKEY *PFILE_DEADKEY; struct FILE_VKDICTIONARY { - KMX_WCHAR szName[SZMAX_VKDICTIONARYNAME]; + KMX_WCHAR szName[SZMAX_VKDICTIONARYNAME]; }; typedef FILE_VKDICTIONARY *PFILE_VKDICTIONARY; @@ -125,39 +125,41 @@ typedef FILE_VKDICTIONARY *PFILE_VKDICTIONARY; * Extra metadata for API consumers */ struct FILE_KEYBOARD_EXTRA { - std::u16string kvksFilename; // original TSS_VISUALKEYBOARD value + std::u16string kvksFilename; // original TSS_VISUALKEYBOARD value }; +typedef struct FILE_KEYBOARD_EXTRA* PFILE_KEYBOARD_EXTRA; + struct FILE_KEYBOARD { - KMX_DWORD KeyboardID; // as stored in HKEY_LOCAL_MACHINE//system//currentcontrolset//control//keyboard layouts + KMX_DWORD KeyboardID; // as stored in HKEY_LOCAL_MACHINE//system//currentcontrolset//control//keyboard layouts - KMX_DWORD version; // keyboard file version with VERSION keyword + KMX_DWORD version; // keyboard file version with VERSION keyword - PFILE_STORE dpStoreArray; // address of first item in store array, from start of store structure - PFILE_GROUP dpGroupArray; // address of first item in group array, from start of group structure + PFILE_STORE dpStoreArray; // address of first item in store array, from start of store structure + PFILE_GROUP dpGroupArray; // address of first item in group array, from start of group structure - KMX_DWORD cxStoreArray; // in number of items - KMX_DWORD cxGroupArray; // in number of items - KMX_DWORD StartGroup[2]; // index of starting groups [ANSI=0, Unicode=1] + KMX_DWORD cxStoreArray; // in number of items + KMX_DWORD cxGroupArray; // in number of items + KMX_DWORD StartGroup[2]; // index of starting groups [ANSI=0, Unicode=1] - KMX_DWORD dwHotKey; // standard windows hotkey (hiword=shift/ctrl/alt stuff, loword=vkey) + KMX_DWORD dwHotKey; // standard windows hotkey (hiword=shift/ctrl/alt stuff, loword=vkey) - KMX_WCHAR szName[SZMAX_KEYBOARDNAME]; // Keyboard layout name - KMX_WCHAR szLanguageName[SZMAX_LANGUAGENAME]; // Language name - KMX_WCHAR szCopyright[SZMAX_COPYRIGHT]; // Copyright information - KMX_WCHAR szMessage[SZMAX_MESSAGE]; // General information about the keyboard - PKMX_BYTE lpBitmap; - KMX_DWORD dwBitmapSize; - KMX_DWORD dwFlags; // Flags for the keyboard file + KMX_WCHAR szName[SZMAX_KEYBOARDNAME]; // Keyboard layout name + KMX_WCHAR szLanguageName[SZMAX_LANGUAGENAME]; // Language name + KMX_WCHAR szCopyright[SZMAX_COPYRIGHT]; // Copyright information + KMX_WCHAR szMessage[SZMAX_MESSAGE]; // General information about the keyboard + PKMX_BYTE lpBitmap; + KMX_DWORD dwBitmapSize; + KMX_DWORD dwFlags; // Flags for the keyboard file - KMX_DWORD currentGroup; // temp - current processing group - KMX_DWORD currentStore; // temp - current processing store - KMX_DWORD cxDeadKeyArray; - PFILE_DEADKEY dpDeadKeyArray; // temp - dead key array - KMX_DWORD cxVKDictionary; - PFILE_VKDICTIONARY dpVKDictionary; // temp - virtual key dictionary + KMX_DWORD currentGroup; // temp - current processing group + KMX_DWORD currentStore; // temp - current processing store + KMX_DWORD cxDeadKeyArray; + PFILE_DEADKEY dpDeadKeyArray; // temp - dead key array + KMX_DWORD cxVKDictionary; + PFILE_VKDICTIONARY dpVKDictionary; // temp - virtual key dictionary - FILE_KEYBOARD_EXTRA extra; + PFILE_KEYBOARD_EXTRA extra; }; typedef FILE_KEYBOARD *PFILE_KEYBOARD; @@ -176,34 +178,34 @@ const KMX_DWORD sz_FILE_VKDICTIONARY = sizeof(FILE_VKDICTIONARY); const KMX_DWORD sz_FILE_KEYBOARD = sizeof(FILE_KEYBOARD); struct COMPMSG { - KMX_CHAR szText[SZMAX_ERRORTEXT]; - KMX_DWORD Line; - KMX_DWORD dwMsgCode; - }; + KMX_CHAR szText[SZMAX_ERRORTEXT]; + KMX_DWORD Line; + KMX_DWORD dwMsgCode; + }; typedef COMPMSG *PCOMPMSG; struct COMPILEMESSAGES { - int nMessages; - int nErrors; + int nMessages; + int nErrors; - PCOMPMSG cm; + PCOMPMSG cm; - KMX_DWORD fatalCode; - KMX_CHAR szFatalText[SZMAX_ERRORTEXT]; + KMX_DWORD fatalCode; + KMX_CHAR szFatalText[SZMAX_ERRORTEXT]; - KMX_DWORD currentLine; - }; + KMX_DWORD currentLine; + }; typedef COMPILEMESSAGES *PCOMPILEMESSAGES; /* struct TVersion { - //int MinVersion; // 0x0500 usually - //int CompilerVersion[4]; - //int MinCompilerVersion[4]; - int KeyboardVersion; // 0x0500 usually + //int MinVersion; // 0x0500 usually + //int CompilerVersion[4]; + //int MinCompilerVersion[4]; + int KeyboardVersion; // 0x0500 usually }; extern TVersion FVersionInfo; -- GitLab From bc91a96ea7d802a3562e1d5dcd978585874b39b1 Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Wed, 24 May 2023 03:49:31 -0400 Subject: [PATCH 142/214] auto: increment master version to 17.0.112 --- HISTORY.md | 7 +++++++ VERSION.md | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 9841e4b838..05c1a80bcf 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,12 @@ # Keyman Version History +## 17.0.111 alpha 2023-05-24 + +* fix(android/app): Pathing for publish script (#8845) +* chore(developer): add test for missing .js file to kmc-package (#8846) +* feat(linux): Add dbus system service (#8509) +* chore(linux): Add missing dependency to GHA (#8849) + ## 17.0.110 alpha 2023-05-22 * fix(common): ensure child builds don't rebuild dependencies unnecessarily (#8834) diff --git a/VERSION.md b/VERSION.md index 15aebb389a..945e7e5abf 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.111 \ No newline at end of file +17.0.112 \ No newline at end of file -- GitLab From ef101d746c619d8b0f8c6695132f55a13c98e7b6 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 25 May 2023 08:24:09 +0700 Subject: [PATCH 143/214] chore(developer): address review comments --- .../src/kmc-kmn/src/compiler/compiler.ts | 58 +++++++++---------- developer/src/kmcmpdll/compfile.h | 17 +++--- developer/src/kmcmplib/src/compfile.h | 18 +++--- 3 files changed, 43 insertions(+), 50 deletions(-) diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index 93ee3c36e8..c46b894cb3 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -152,50 +152,48 @@ export class KmnCompiler { } private runCompiler(infile: string, outfile: string, options: CompilerOptions): CompilerResult { + let result: CompilerResult = {}; + let wasm_interface = new this.wasm.Module.CompilerInterface(); + let wasm_result = null; try { - let result: CompilerResult = {}; - let wasm_interface = new this.wasm.Module.CompilerInterface(); - let wasm_result = null; - try { - wasm_interface.saveDebug = options.saveDebug; - wasm_interface.compilerWarningsAsErrors = options.compilerWarningsAsErrors; - wasm_interface.warnDeprecatedCode = options.warnDeprecatedCode; - wasm_interface.messageCallback = this.callbackName; - wasm_interface.loadFileCallback = this.callbackName; - wasm_result = this.wasm.Module.kmcmp_compile(infile, wasm_interface); - if(!wasm_result.result) { - return null; - } + wasm_interface.saveDebug = options.saveDebug; + wasm_interface.compilerWarningsAsErrors = options.compilerWarningsAsErrors; + wasm_interface.warnDeprecatedCode = options.warnDeprecatedCode; + wasm_interface.messageCallback = this.callbackName; + wasm_interface.loadFileCallback = this.callbackName; // TODO: this is wrong, needs to be a new callback; not yet used though + wasm_result = this.wasm.Module.kmcmp_compile(infile, wasm_interface); + if(!wasm_result.result) { + return null; + } - if(wasm_result.kvksFilename) { - result.kvk = this.runKvkCompiler(wasm_result.kvksFilename, infile, outfile); - if(!result.kvk) { - return null; - } + if(wasm_result.kvksFilename) { + result.kvk = this.runKvkCompiler(wasm_result.kvksFilename, infile, outfile); + if(!result.kvk) { + return null; } + } - result.kmx = { - filename: outfile, - data: new Uint8Array(this.wasm.Module.HEAP8.buffer, wasm_result.kmx, wasm_result.kmxSize) - }; + result.kmx = { + filename: outfile, + data: new Uint8Array(this.wasm.Module.HEAP8.buffer, wasm_result.kmx, wasm_result.kmxSize) + }; - return result; - } finally { - if(wasm_result) { - wasm_result.delete(); - } - wasm_interface.delete(); - } + return result; } catch(e) { this.callbacks.reportMessage(CompilerMessages.Fatal_UnexpectedException({e:e})); return null; + } finally { + if(wasm_result) { + wasm_result.delete(); + } + wasm_interface.delete(); } } private runKvkCompiler(kvksFilename: string, kmnFilename: string, kmxFilename: string) { // The compiler detected a .kvks file, which needs to be captured let reader = new KvksFileReader(); - kvksFilename = this.callbacks.resolveFilename(kmnFilename, kvksFilename); + kvksFilename = this.callbacks.resolveFilename(kmnFilename, kvksFilename); let kvks = reader.read(this.callbacks.loadFile(kvksFilename)); try { reader.validate(kvks, this.callbacks.loadSchema('kvks')); diff --git a/developer/src/kmcmpdll/compfile.h b/developer/src/kmcmpdll/compfile.h index 2f6e2e654f..9e65c36600 100644 --- a/developer/src/kmcmpdll/compfile.h +++ b/developer/src/kmcmpdll/compfile.h @@ -87,7 +87,7 @@ struct FILE_STORE { BOOL fIsDebug; BOOL fIsCall; int line; // TODO: int vs dword, line vs Line (see FILE_KEY, FILE_GROUP) - }; +}; typedef FILE_STORE *PFILE_STORE; @@ -98,7 +98,7 @@ struct FILE_KEY { DWORD ShiftFlags; PWSTR dpOutput; // from start of key structure PWSTR dpContext; // from start of key structure - }; +}; typedef FILE_KEY *PFILE_KEY; struct FILE_GROUP { @@ -114,22 +114,19 @@ struct FILE_GROUP { typedef FILE_GROUP *PFILE_GROUP; -struct FILE_DEADKEY -{ +struct FILE_DEADKEY { WCHAR szName[SZMAX_DEADKEYNAME]; }; typedef FILE_DEADKEY *PFILE_DEADKEY; -struct FILE_VKDICTIONARY -{ +struct FILE_VKDICTIONARY { WCHAR szName[SZMAX_VKDICTIONARYNAME]; }; - typedef FILE_VKDICTIONARY *PFILE_VKDICTIONARY; struct FILE_KEYBOARD { - DWORD KeyboardID; // as stored in HKEY_LOCAL_MACHINE//system//currentcontrolset//control//keyboard layouts + DWORD KeyboardID; // deprecated, unused DWORD version; // keyboard file version with VERSION keyword @@ -179,7 +176,7 @@ struct COMPMSG { char szText[SZMAX_ERRORTEXT]; DWORD Line; DWORD dwMsgCode; - }; +}; typedef COMPMSG *PCOMPMSG; @@ -193,7 +190,7 @@ struct COMPILEMESSAGES { char szFatalText[SZMAX_ERRORTEXT]; DWORD currentLine; - }; +}; typedef COMPILEMESSAGES *PCOMPILEMESSAGES; diff --git a/developer/src/kmcmplib/src/compfile.h b/developer/src/kmcmplib/src/compfile.h index 4b639a7eb1..595d1fecec 100644 --- a/developer/src/kmcmplib/src/compfile.h +++ b/developer/src/kmcmplib/src/compfile.h @@ -82,7 +82,7 @@ struct FILE_STORE { KMX_BOOL fIsDebug; KMX_BOOL fIsCall; int line; - }; +}; typedef FILE_STORE *PFILE_STORE; @@ -93,7 +93,7 @@ struct FILE_KEY { KMX_DWORD ShiftFlags; PKMX_WCHAR dpOutput; // from start of key structure PKMX_WCHAR dpContext; // from start of key structure - }; +}; typedef FILE_KEY *PFILE_KEY; struct FILE_GROUP { @@ -108,15 +108,13 @@ struct FILE_GROUP { }; typedef FILE_GROUP *PFILE_GROUP; -struct FILE_DEADKEY -{ +struct FILE_DEADKEY { KMX_WCHAR szName[SZMAX_DEADKEYNAME]; }; typedef FILE_DEADKEY *PFILE_DEADKEY; -struct FILE_VKDICTIONARY -{ +struct FILE_VKDICTIONARY { KMX_WCHAR szName[SZMAX_VKDICTIONARYNAME]; }; typedef FILE_VKDICTIONARY *PFILE_VKDICTIONARY; @@ -131,7 +129,7 @@ struct FILE_KEYBOARD_EXTRA { typedef struct FILE_KEYBOARD_EXTRA* PFILE_KEYBOARD_EXTRA; struct FILE_KEYBOARD { - KMX_DWORD KeyboardID; // as stored in HKEY_LOCAL_MACHINE//system//currentcontrolset//control//keyboard layouts + KMX_DWORD KeyboardID; // deprecated, unused KMX_DWORD version; // keyboard file version with VERSION keyword @@ -159,7 +157,7 @@ struct FILE_KEYBOARD { KMX_DWORD cxVKDictionary; PFILE_VKDICTIONARY dpVKDictionary; // temp - virtual key dictionary - PFILE_KEYBOARD_EXTRA extra; + PFILE_KEYBOARD_EXTRA extra; }; typedef FILE_KEYBOARD *PFILE_KEYBOARD; @@ -181,7 +179,7 @@ struct COMPMSG { KMX_CHAR szText[SZMAX_ERRORTEXT]; KMX_DWORD Line; KMX_DWORD dwMsgCode; - }; +}; typedef COMPMSG *PCOMPMSG; @@ -195,7 +193,7 @@ struct COMPILEMESSAGES { KMX_CHAR szFatalText[SZMAX_ERRORTEXT]; KMX_DWORD currentLine; - }; +}; typedef COMPILEMESSAGES *PCOMPILEMESSAGES; -- GitLab From 50186e986e0757f3d02e60c428b72d90a0a83239 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 25 May 2023 09:03:22 +0700 Subject: [PATCH 144/214] chore(developer): remove SetError macro The `SetError` macro emitted `return FALSE;` which was confusing for reviewing code flow. Replaced with explicit `AddCompileMessage()` and `return FALSE;`. --- .../src/kmcmplib/src/CompilerInterfaces.cpp | 65 +++++++++++++------ 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/developer/src/kmcmplib/src/CompilerInterfaces.cpp b/developer/src/kmcmplib/src/CompilerInterfaces.cpp index d7b8118b58..a1609d3544 100644 --- a/developer/src/kmcmplib/src/CompilerInterfaces.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfaces.cpp @@ -11,8 +11,6 @@ #include "../../../../common/windows/cpp/include/ConvertUTF.h" #include "../../../../common/windows/cpp/include/keymanversion.h" -#define SetError(err) { if(AddCompileError(err) || (err & CERR_FATAL)) return FALSE; } - bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk); bool CompileKeyboard(const char* pszInfile, void* pfkBuffer, bool ASaveDebug, bool ACompilerWarningsAsErrors, @@ -182,8 +180,10 @@ bool CompileKeyboard(const char* pszInfile, kmcmp::CompileTarget = Target; - if (!pMsgproc || !pszInfile || !pfkBuffer) SetError(CERR_BadCallParams); - + if (!pMsgproc || !pszInfile || !pfkBuffer) { + AddCompileError(CERR_BadCallParams); + return FALSE; + } PKMX_STR p; @@ -203,14 +203,16 @@ bool CompileKeyboard(const char* pszInfile, fp_in = Open_File(pszInfile, "rb"); if (fp_in == NULL) { - SetError(CERR_InfileNotExist); + AddCompileError(CERR_InfileNotExist); + return FALSE; } // Transfer the file to a memory stream for processing UTF-8 or ANSI to UTF-16? // What about really large files? Transfer to a temp file... if (!fread(str, 1, 3, fp_in)) { fclose(fp_in); - SetError(CERR_CannotReadInfile); + AddCompileError(CERR_CannotReadInfile); + return FALSE; } fseek(fp_in, 0, SEEK_SET); @@ -221,7 +223,8 @@ bool CompileKeyboard(const char* pszInfile, else fp_in = UTF16TempFromUTF8(fp_in, FALSE); if (fp_in == NULL) { - SetError(CERR_CannotCreateTempfile); + AddCompileError(CERR_CannotCreateTempfile); + return FALSE; } kmcmp::CodeConstants = new kmcmp::NamedCodeConstants; @@ -241,7 +244,8 @@ EXTERN bool kmcmp_CompileKeyboardFileToBuffer(char* pszInfile, void* pfkBuffer, kmcmp_CompilerMessageProc pMsgproc, void* AmsgprocContext, int Target) // I4865 // I4866 { if (!pMsgproc || !pszInfile || !pfkBuffer) { - SetError(CERR_BadCallParams); + AddCompileError(CERR_BadCallParams); + return FALSE; } return CompileKeyboard(pszInfile, pfkBuffer, TRUE, ACompilerWarningsAsErrors, AWarnDeprecatedCode, @@ -253,7 +257,8 @@ EXTERN bool kmcmp_CompileKeyboardFile(char* pszInfile, bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, void* AmsgprocContext) // I4865 // I4866 { if (!pMsgproc || !pszInfile || !pszOutfile) { - SetError(CERR_BadCallParams); + AddCompileError(CERR_BadCallParams); + return FALSE; } FILE_KEYBOARD fk; @@ -265,7 +270,8 @@ EXTERN bool kmcmp_CompileKeyboardFile(char* pszInfile, FILE* fp_out = Open_File(pszOutfile, "wb"); if (fp_out == NULL) { - SetError(CERR_CannotCreateOutfile); + AddCompileError(CERR_CannotCreateOutfile); + return FALSE; } KMX_DWORD msg; @@ -299,12 +305,14 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) kmcmp::FMnemonicLayout = FALSE; if (!fk) { - SetError(CERR_SomewhereIGotItWrong); + AddCompileError(CERR_SomewhereIGotItWrong); + return FALSE; } str = new KMX_WCHAR[LINESIZE]; if (!str) { - SetError(CERR_CannotAllocateMemory); + AddCompileError(CERR_CannotAllocateMemory); + return FALSE; } fk->KeyboardID = 0; @@ -355,15 +363,24 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) { case T_VERSION: *(p + 4) = 0; - if ((msg = AddStore(fk, TSS_VERSION, p)) != CERR_None) SetError(msg); + if ((msg = AddStore(fk, TSS_VERSION, p)) != CERR_None) { + AddCompileError(msg); + return FALSE; + } break; case T_GROUP: - if ((msg = ProcessGroupLine(fk, p)) != CERR_None) SetError(msg); + if ((msg = ProcessGroupLine(fk, p)) != CERR_None) { + AddCompileError(msg); + return FALSE; + } break; case T_STORE: - if ((msg = ProcessStoreLine(fk, p)) != CERR_None) SetError(msg); + if ((msg = ProcessStoreLine(fk, p)) != CERR_None) { + AddCompileError(msg); + return FALSE; + } break; default: @@ -372,7 +389,8 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) } if (msg != CERR_EndOfFile) { - SetError(msg); + AddCompileError(msg); + return FALSE; } fseek( fp_in,2,SEEK_SET); @@ -387,12 +405,14 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) { msg = ParseLine(fk, str); if (msg != CERR_None) { - SetError(msg); + AddCompileError(msg); + return FALSE; } } if (msg != CERR_EndOfFile) { - SetError(msg); + AddCompileError(msg); + return FALSE; } ProcessGroupFinish(fk); @@ -401,15 +421,18 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) /* Add the compiler version as a system store */ if ((msg = kmcmp::AddCompilerVersionStore(fk)) != CERR_None) { - SetError(msg); + AddCompileError(msg); + return FALSE; } if ((msg = BuildVKDictionary(fk)) != CERR_None) { - SetError(msg); // I3438 + AddCompileError(msg); + return FALSE; } if ((msg = CheckFilenameConsistencyForCalls(fk)) != CERR_None) { - SetError(msg); + AddCompileError(msg); + return FALSE; } delete str; -- GitLab From a92917f947fabef7e798c1ed733e5d57444c8958 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 25 May 2023 12:54:27 +0700 Subject: [PATCH 145/214] chore(developer): replace cwrap wasm bindings This moves the remainder of the WASM interfaces in kmcmplib to using emscripten bind. It is a little bit of a step backwards at present for parseUnicodeSet, because I've changed the output buffer type to an int for the purposes of simplifying the binding just now. But that can be improved later, and at least we are consistent with the binding methods. Next step is to move the filesystem access out of kmcmplib. --- .../src/kmc-kmn/src/compiler/compiler.ts | 65 ++++--------------- developer/src/kmcmplib/include/kmcmplibapi.h | 15 ++--- .../src/kmcmplib/src/CompilerInterfaces.cpp | 34 +--------- developer/src/kmcmplib/src/meson.build | 2 +- developer/src/kmcmplib/src/uset-api.cpp | 13 ++-- .../src/kmcmplib/tests/uset-api-test.cpp | 30 +++++---- 6 files changed, 43 insertions(+), 116 deletions(-) diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index c46b894cb3..a88999e99c 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -42,50 +42,10 @@ const baseOptions: CompilerOptions = { */ let callbackProcIdentifier = 0; -/** - * Pointer in wasm-space - */ -type WasmPtr = number; - -/** - * The wrapped functions - */ -class WasmWrapper { - Module: any; - - compileKeyboardFile?: (pszInfile: string, pszOutfile: string, aSaveDebug: number, aCompilerWarningsAsErrors: number, aWarnDeprecatedCode: number, msgProc: string) => boolean; - parseUnicodeSet?: (pat: string, buf: WasmPtr, length: number) => number; - setCompilerOptions?: (shouldAddCompilerVersion: number) => boolean; - - constructor(wasmModule: any) { - this.Module = wasmModule; - if (!wasmModule) { - throw Error(`wasm host did not load`); - } - this.compileKeyboardFile = this.Module.cwrap('kmcmp_Wasm_CompileKeyboardFile', 'boolean', ['string', 'string', 'number', 'number', 'number', 'string']); - this.parseUnicodeSet = this.Module.cwrap('kmcmp_Wasm_ParseUnicodeSet', 'number', ['string', 'number', 'number']); - this.setCompilerOptions = this.Module.cwrap('kmcmp_Wasm_SetCompilerOptions', 'boolean', ['number']); - - if (this.parseUnicodeSet === undefined - || this.setCompilerOptions === undefined - || this.compileKeyboardFile === undefined) { - throw Error(`some wasm functions did not load properly.`); - } - } - - /** - * Entry point into Wasm functions - * @returns WasmWrapper - */ - public static async load() : Promise { - return new WasmWrapper(await loadWasmHost()); - } -}; - export class KmnCompiler { + private Module: any; callbackName: string; callbacks: CompilerCallbacks; - wasm: WasmWrapper; constructor() { this.callbackName = 'kmnCompilerCallback' + callbackProcIdentifier; @@ -94,9 +54,9 @@ export class KmnCompiler { public async init(callbacks: CompilerCallbacks): Promise { this.callbacks = callbacks; - if(!this.wasm) { + if(!this.Module) { try { - this.wasm = await WasmWrapper.load(); + this.Module = await loadWasmHost(); } catch(e: any) { this.callbacks.reportMessage(CompilerMessages.Fatal_MissingWasmModule({e})); return false; @@ -114,7 +74,7 @@ export class KmnCompiler { // Can't report a message here. throw Error('Must call Compiler.init(callbacks) before proceeding'); } - if(!this.wasm) { // fail if wasm not loaded or function not found + if(!this.Module) { // fail if wasm not loaded or function not found this.callbacks.reportMessage(CompilerMessages.Fatal_MissingWasmModule({})); return false; } @@ -153,7 +113,7 @@ export class KmnCompiler { private runCompiler(infile: string, outfile: string, options: CompilerOptions): CompilerResult { let result: CompilerResult = {}; - let wasm_interface = new this.wasm.Module.CompilerInterface(); + let wasm_interface = new this.Module.CompilerInterface(); let wasm_result = null; try { wasm_interface.saveDebug = options.saveDebug; @@ -161,7 +121,7 @@ export class KmnCompiler { wasm_interface.warnDeprecatedCode = options.warnDeprecatedCode; wasm_interface.messageCallback = this.callbackName; wasm_interface.loadFileCallback = this.callbackName; // TODO: this is wrong, needs to be a new callback; not yet used though - wasm_result = this.wasm.Module.kmcmp_compile(infile, wasm_interface); + wasm_result = this.Module.kmcmp_compile(infile, wasm_interface); if(!wasm_result.result) { return null; } @@ -175,7 +135,7 @@ export class KmnCompiler { result.kmx = { filename: outfile, - data: new Uint8Array(this.wasm.Module.HEAP8.buffer, wasm_result.kmx, wasm_result.kmxSize) + data: new Uint8Array(this.Module.HEAP8.buffer, wasm_result.kmx, wasm_result.kmxSize) }; return result; @@ -230,16 +190,15 @@ export class KmnCompiler { if (!bufferSize) { bufferSize = 100; // TODO-LDML: Preflight mode? Reuse buffer? } - const { Module } = this.wasm; - const buf = Module.asm.malloc(bufferSize * 2 * Module.HEAPU32.BYTES_PER_ELEMENT); + const buf = this.Module.asm.malloc(bufferSize * 2 * this.Module.HEAPU32.BYTES_PER_ELEMENT); // TODO-LDML: Catch OOM - const rc = this.wasm.parseUnicodeSet(pattern, buf, bufferSize); + const rc = this.Module.kmcmp_parseUnicodeSet(pattern, buf, bufferSize); if (rc >= 0) { const ranges = []; - const startu = (buf / Module.HEAPU32.BYTES_PER_ELEMENT); + const startu = (buf / this.Module.HEAPU32.BYTES_PER_ELEMENT); for (let i = 0; i < rc; i++) { - const low = Module.HEAPU32[startu + (i * 2) + 0]; - const high = Module.HEAPU32[startu + (i * 2) + 1]; + const low = this.Module.HEAPU32[startu + (i * 2) + 0]; + const high = this.Module.HEAPU32[startu + (i * 2) + 1]; ranges.push([low, high]); } // TODO-LDML: no free?? diff --git a/developer/src/kmcmplib/include/kmcmplibapi.h b/developer/src/kmcmplib/include/kmcmplibapi.h index 2fb35979b2..f4591612ec 100644 --- a/developer/src/kmcmplib/include/kmcmplibapi.h +++ b/developer/src/kmcmplib/include/kmcmplibapi.h @@ -62,7 +62,7 @@ EXTERN bool kmcmp_ValidateJsonFile( ); /** - * kmcmp_ParseUnicodeSet is successful if it returns >= USET_OK + * kmcmp_parseUnicodeSet is successful if it returns >= USET_OK */ static const int KMCMP_USET_OK = 0; @@ -83,24 +83,19 @@ static const int KMCMP_ERROR_UNSUPPORTED_PROPERTY = -3; */ static const int KMCMP_FATAL_OUT_OF_RANGE = -4; -/** - * Function pointer to kmcmp_ParseUnicodeSet - */ -typedef int (*kmcmp_ParseUnicodeSetProc)(const char* szText, uint32_t* output, uint32_t outputLength); - /** * Parse a UnicodeSet into 32-bit ranges. * For example, "[]" will return 0 (KMCMP_USET_OK) as a zero-length set. * "[" will return KMCMP_ERROR_SYNTAX_ERR, * and "[x A-C]" will return 2 and [0x41, 0x43, 0x78, 0x78] - * @param szText input txt, null terminated, in UTF-8 format + * @param text input txt, null terminated, in UTF-8 format * @param outputBuffer output buffer, owned by caller: Pairs of ranges in order * @param outputBufferSize length of output buffer. Needs to be twice the number of expected ranges * @return If >= KMCMP_USET_OK, number of ranges, otherwise one of the negative error values. */ -EXTERN int kmcmp_ParseUnicodeSet( - const char* szText, - uint32_t* outputBuffer, +EXTERN int kmcmp_parseUnicodeSet( + const std::string text, + uintptr_t outputBuffer_, uint32_t outputBufferSize ); diff --git a/developer/src/kmcmplib/src/CompilerInterfaces.cpp b/developer/src/kmcmplib/src/CompilerInterfaces.cpp index a1609d3544..56ecf4cdcf 100644 --- a/developer/src/kmcmplib/src/CompilerInterfaces.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfaces.cpp @@ -46,39 +46,6 @@ int wasm_CompilerMessageProc(int line, uint32_t dwMsgCode, char* szText, void* c return wasm_msgproc(line, dwMsgCode, szText, msgProc); } -//DEPRECATED -EXTERN bool kmcmp_Wasm_SetCompilerOptions(int ShouldAddCompilerVersion) { - KMCMP_COMPILER_OPTIONS options; - options.dwSize = sizeof(KMCMP_COMPILER_OPTIONS); - options.ShouldAddCompilerVersion = ShouldAddCompilerVersion; - return kmcmp_SetCompilerOptions(&options); -} - -//DEPRECATED -EXTERN bool kmcmp_Wasm_CompileKeyboardFile(char* pszInfile, - char* pszOutfile, int ASaveDebug, int ACompilerWarningsAsErrors, - int AWarnDeprecatedCode, char* msgProc -) { - return kmcmp_CompileKeyboardFile( - pszInfile, - pszOutfile, - ASaveDebug, - ACompilerWarningsAsErrors, - AWarnDeprecatedCode, - wasm_CompilerMessageProc, - msgProc - ); -} - -EXTERN int kmcmp_Wasm_ParseUnicodeSet(char* pat, - uint32_t* buf, int length -) { - return kmcmp_ParseUnicodeSet( - pat, buf, length - ); -} - - struct COMPILER_INTERFACE { bool saveDebug; bool compilerWarningsAsErrors; @@ -162,6 +129,7 @@ EMSCRIPTEN_BINDINGS(compiler_interface) { ; emscripten::function("kmcmp_compile", &kmcmp_compile); + emscripten::function("kmcmp_parseUnicodeSet", &kmcmp_parseUnicodeSet); } #endif diff --git a/developer/src/kmcmplib/src/meson.build b/developer/src/kmcmplib/src/meson.build index 292b158ce2..3cd9abd6e1 100644 --- a/developer/src/kmcmplib/src/meson.build +++ b/developer/src/kmcmplib/src/meson.build @@ -24,7 +24,7 @@ endif name_suffix = [] if cpp_compiler.get_id() == 'emscripten' - links += ['-lnodefs.js', '-sMODULARIZE', '-sEXPORT_ES6', '--whole-archive', '--bind', '-sEXPORTED_RUNTIME_METHODS=[\'cwrap\', \'UTF8ToString\']'] + links += ['-lnodefs.js', '-sMODULARIZE', '-sEXPORT_ES6', '--whole-archive', '--bind', '-sEXPORTED_RUNTIME_METHODS=[\'UTF8ToString\']'] # tests are building as ES6 so we need to declare the file extension # note that meson currently struggles with the sanitycheckc_cross.exe # program, because it has a hard coded extension (.exe) which is not diff --git a/developer/src/kmcmplib/src/uset-api.cpp b/developer/src/kmcmplib/src/uset-api.cpp index 1aa22477b2..c2c72cab34 100644 --- a/developer/src/kmcmplib/src/uset-api.cpp +++ b/developer/src/kmcmplib/src/uset-api.cpp @@ -4,16 +4,13 @@ #include "unicode/uniset.h" #include "unicode/unistr.h" -EXTERN int kmcmp_ParseUnicodeSet( - const char* szText, - uint32_t* outputBuffer, +EXTERN int kmcmp_parseUnicodeSet( + const std::string text, + uintptr_t outputBuffer_, uint32_t outputBufferSize ) { - if (szText == nullptr) { - // null string coming in - return KMCMP_ERROR_SYNTAX_ERR; - } - const icu::UnicodeString str = icu::UnicodeString::fromUTF8(szText); + uint32_t* outputBuffer = reinterpret_cast(outputBuffer_); + const icu::UnicodeString str = icu::UnicodeString::fromUTF8(text.c_str()); if (str.isBogus() || str.isEmpty()) { // empty string return KMCMP_ERROR_SYNTAX_ERR; diff --git a/developer/src/kmcmplib/tests/uset-api-test.cpp b/developer/src/kmcmplib/tests/uset-api-test.cpp index 4fe599ca2e..61d263ad15 100644 --- a/developer/src/kmcmplib/tests/uset-api-test.cpp +++ b/developer/src/kmcmplib/tests/uset-api-test.cpp @@ -19,30 +19,32 @@ #include "../src/compfile.h" #include -void test_kmcmp_ParseUnicodeSetProc(); +void test_kmcmp_parseUnicodeSet(); // std::vector error_vec; int main(int argc, char *argv[]) { - test_kmcmp_ParseUnicodeSetProc(); + test_kmcmp_parseUnicodeSet(); return 0; } -void test_kmcmp_ParseUnicodeSetProc() { +void test_kmcmp_parseUnicodeSet() { { // null test const auto bufsiz = 128; uint32_t buf[bufsiz]; - int rc = kmcmp_ParseUnicodeSet(u8"[]", buf, bufsiz); + uintptr_t buf_ = reinterpret_cast(buf); + int rc = kmcmp_parseUnicodeSet(u8"[]", buf_, bufsiz); assert(rc == KMCMP_USET_OK); } { // basic test const auto bufsiz = 128; uint32_t buf[bufsiz]; - int rc = kmcmp_ParseUnicodeSet(u8"[x A-C]", buf, bufsiz); + uintptr_t buf_ = reinterpret_cast(buf); + int rc = kmcmp_parseUnicodeSet(u8"[x A-C]", buf_, bufsiz); assert(rc == 2); assert(buf[0] == 0x41); assert(buf[1] == 0x43); @@ -53,7 +55,8 @@ void test_kmcmp_ParseUnicodeSetProc() { // bigger test const auto bufsiz = 128; uint32_t buf[bufsiz]; - int rc = kmcmp_ParseUnicodeSet(u8"[[🙀A-C]-[CB]]", buf, bufsiz); + uintptr_t buf_ = reinterpret_cast(buf); + int rc = kmcmp_parseUnicodeSet(u8"[[🙀A-C]-[CB]]", buf_, bufsiz); assert(rc == 2); assert(buf[0] == 0x41); assert(buf[1] == 0x41); @@ -64,35 +67,40 @@ void test_kmcmp_ParseUnicodeSetProc() { // overflow test const auto bufsiz = 1; uint32_t buf[bufsiz]; - int rc = kmcmp_ParseUnicodeSet(u8"[x A-C]", buf, bufsiz); + uintptr_t buf_ = reinterpret_cast(buf); + int rc = kmcmp_parseUnicodeSet(u8"[x A-C]", buf_, bufsiz); assert(rc == KMCMP_FATAL_OUT_OF_RANGE); } { // err test const auto bufsiz = 128; uint32_t buf[bufsiz]; - int rc = kmcmp_ParseUnicodeSet(u8"[:Adlm:]", buf, bufsiz); + uintptr_t buf_ = reinterpret_cast(buf); + int rc = kmcmp_parseUnicodeSet(u8"[:Adlm:]", buf_, bufsiz); assert(rc == KMCMP_ERROR_UNSUPPORTED_PROPERTY); } { // err test const auto bufsiz = 128; uint32_t buf[bufsiz]; - int rc = kmcmp_ParseUnicodeSet(u8"[[\\p{Mn}]&[A-Z]]", buf, bufsiz); + uintptr_t buf_ = reinterpret_cast(buf); + int rc = kmcmp_parseUnicodeSet(u8"[[\\p{Mn}]&[A-Z]]", buf_, bufsiz); assert(rc == KMCMP_ERROR_UNSUPPORTED_PROPERTY); } { // err test const auto bufsiz = 128; uint32_t buf[bufsiz]; - int rc = kmcmp_ParseUnicodeSet(u8"[abc{def}]", buf, bufsiz); + uintptr_t buf_ = reinterpret_cast(buf); + int rc = kmcmp_parseUnicodeSet(u8"[abc{def}]", buf_, bufsiz); assert(rc == KMCMP_ERROR_HAS_STRINGS); } { // err test const auto bufsiz = 128; uint32_t buf[bufsiz]; - int rc = kmcmp_ParseUnicodeSet(u8"[[]", buf, bufsiz); + uintptr_t buf_ = reinterpret_cast(buf); + int rc = kmcmp_parseUnicodeSet(u8"[[]", buf_, bufsiz); assert(rc == KMCMP_ERROR_SYNTAX_ERR); } } -- GitLab From c61535d56af7a42559d67cbc4ca1ebb4b6a2a5da Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Thu, 25 May 2023 11:35:50 +0200 Subject: [PATCH 146/214] fix(android): Fix build-utils.sh --- resources/build/build-utils.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/build/build-utils.sh b/resources/build/build-utils.sh index bba5589b19..7ae8db2ae1 100755 --- a/resources/build/build-utils.sh +++ b/resources/build/build-utils.sh @@ -293,7 +293,7 @@ set_keyman_standard_build_path() { # For CI compatbility of building Keyman for Android 16.0 with OpenJDK 8, # this overrides JAVA_HOME for the builder script to use OpenJDK 11. set_java_home() { - if [[ ! -z {$JAVA_HOME_11+x} ]]; then + if [[ ! -z ${JAVA_HOME_11+x} ]]; then builder_echo "Setting JAVA_HOME to JAVA_HOME_11 ($JAVA_HOME_11)" export JAVA_HOME="${JAVA_HOME_11}" fi -- GitLab From b80fdf88cac53167b8188d7908a07ddd167e2265 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Thu, 25 May 2023 11:35:13 +0200 Subject: [PATCH 147/214] docs(android): Fix documentation for building Android on Linux --- android/README.md | 52 +++++++++++++++++++++++++++----------- docs/build/linux-ubuntu.md | 38 +++++++++++++++++++++------- 2 files changed, 66 insertions(+), 24 deletions(-) diff --git a/android/README.md b/android/README.md index 2c776873a3..dd2c3402a4 100644 --- a/android/README.md +++ b/android/README.md @@ -1,33 +1,48 @@ # Keyman for Android & Keyman Engine for Android ## Prerequisites -See [build configuration](../docs/build/index.md) for details on how to configure your build environment. + +See [build configuration](../docs/build/index.md) for details on how to configure +your build environment. ## Keyman Minimum Android Requirements + Keyman for Android has a minSdkVersion of 21 for [Android 5.0 Lollipop](https://developer.android.com/about/versions/lollipop) ## Keyman for Android Development -Keyman for Android (formerly named KMAPro) can be built from a command line (preferred) or Android Studio. -Building Keyman Web is a precursor for compiling KMEA, so verify your system has all the [Minimum Web Compilation Requirements](../web/README.md#minimum-web-compilation-requirements) +Keyman for Android (formerly named KMAPro) can be built from a command line +(preferred) or Android Studio. + +Building Keyman Web is a precursor for compiling KMEA, so verify your system has +all the [Minimum Web Compilation Requirements](../web/README.md#minimum-web-compilation-requirements) + +When attempting to build via Android Studio the first time, you'll also need to +accept the SDK licenses. Depending on your OS, you may need to run a command +line similar to: -When attempting to build via Android Studio the first time, you'll also need to accept the SDK licenses. Depending on your OS, you may need to run a command line similar to: ```bash yes | ~/Library/Android/sdk/tools/bin/sdkmanager --licenses ``` ### Crash Reporting -Keyman for Android uses [Sentry](https://sentry.io) for crash reporting at a server https://sentry.keyman.com. The analytics for Debug are associated with an App Bundle ID `com.tavultesoft.kmapro.debug`. - + +Keyman for Android uses [Sentry](https://sentry.io) for crash reporting at a server +. The analytics for Debug are associated with an +App Bundle ID `com.tavultesoft.kmapro.debug`. + ### Compiling From Command Line + 1. Launch a command prompt and cd to the directory **keyman/android** 2. Run the top level build script `./build.sh configure build --debug` which will: * Compile KMEA (and its KMW dependency) * Download default keyboard and dictionary resources as needed * Compile KMAPro -3. The APK will be found in **keyman/android/KMAPro/kMAPro/build/outputs/apk/debug/keyman-${version}.apk** where `${version}` is the current version number. +3. The APK will be found in **keyman/android/KMAPro/kMAPro/build/outputs/apk/debug/keyman-\${version}.apk** + where `${version}` is the current version number. ### Compiling From Android Studio + 1. Ensure that [Keyman Engine for Android](#how-to-build-keyman-engine-for-android) is built. 2. Launch Android Studio and import the Gradle project **keyman/android/KMAPro/build.gradle** 3. From the project view, *configure* anything that Gradle reports. @@ -37,24 +52,31 @@ Keyman for Android uses [Sentry](https://sentry.io) for crash reporting at a ser 3. Change Module to kMAPro 4. Name your run configuration kMAPro (or as desired) 5. Run your new configuration: Select Run --> Run 'kMAPro' -6. Select a physical device or create a new virtual device to match your target API version - For Ubuntu 18.04, you will need to add your user to the `kvm` group for permission accessing the emulator. -``` +6. Select a physical device or create a new virtual device to match your target + API version. + + For Ubuntu 18.04, you will need to add your user to the `kvm` group + for permission accessing the emulator. + + ```bash sudo apt install qemu-kvm sudo adduser kvm -``` + ``` ### Running From Command Line + 1. Launch a command prompt 2. Ensure that a physical device is connected or an emulator is running. 1. To list physical devices: `$ANDROID_HOME/platform-tools/adb.exe devices` 2. To list created emulator devices: `$ANDROID_HOME/tools/emulator.exe -list-avds` - 3. [Create a new virtual device](https://developer.android.com/studio/run/managing-avds.html) if there are no - existing devices. + 3. [Create a new virtual device](https://developer.android.com/studio/run/managing-avds.html) + if there are no existing devices. 4. Start an emulator: `$ANDROID_HOME/tools/emulator.exe @nameofemulator` 3. Load the APK: `$ANDROID_HOME/platform-tools/adb.exe install -r path/to/apk.apk` - * If multiple devices are connected you may need `$ANDROID_HOME/platform-tools/adb.exe install -r -s SERIAL path/to/apk.apk`. Replace `SERIAL` with - the device serial number listed in step 2. + + * If multiple devices are connected you may need + `$ANDROID_HOME/platform-tools/adb.exe install -r -s SERIAL path/to/apk.apk`. + Replace `SERIAL` with the device serial number listed in step 2. ### Compiling the app's offline help Keyman for Android help is maintained in the Markdown files in android/help/. diff --git a/docs/build/linux-ubuntu.md b/docs/build/linux-ubuntu.md index 36583d4576..5b576a6ce8 100644 --- a/docs/build/linux-ubuntu.md +++ b/docs/build/linux-ubuntu.md @@ -100,25 +100,33 @@ docker run -it --rm -v $(pwd):/home/build/src/keyman -u root -w /home/build/src/ ## Keyman for Android -**Dependencies**: +**Dependencies:** + * [Base](#base-dependencies) * [Web](./windows#web-dependencies) -**Additional requirements**: +**Additional requirements:** + * Android SDK * [Android Studio](https://developer.android.com/studio/install#linux) * Gradle * Maven * OpenJDK 11 (for Keyman 17.0+) - +* pandoc Run Android Studio once after installation to install additional components such as emulator images and SDK updates. -**Required environment variables**: +**Required environment variable:** + +* `ANDROID_HOME` pointing to Android SDK (`$HOME/Android/Sdk`) + +**Recommended environment variable:** + * [`JAVA_HOME`](#java_home) Building: + * [Building Keyman for Android](../../android/README.md) ## Prerequisites @@ -127,20 +135,32 @@ Many dependencies are only required for specific projects. ### Base Dependencies -**Environment variables**: +**Environment variables:** +* -- ## Notes on Environment Variables ### JAVA_HOME -This environment variable tells Gradle what version of Java to use for building Keyman for Android. -OpenJDK 11 is used for master. It's recommended to set the environment variables to: +This environment variable tells Gradle what version of Java to use for building +Keyman for Android. OpenJDK 11 is used for master. + +It's recommended to set the environment variables to: + ```bash -EXPORT JAVA_HOME="[path to OpenJDK 11]" +export JAVA_HOME="[path to OpenJDK 11]" ``` Also edit `/etc/profile.d/jvm.sh` as sudo: + ```bash -EXPORT JAVA_HOME="[path to OpenJDK 11]" +export JAVA_HOME="[path to OpenJDK 11]" ``` + +**Multiple versions of Java:** If you need to build Keyman for Android 16.0 or +older versions, you can set `JAVA_HOME_11` to the OpenJDK 11 path and +`JAVA_HOME` to the OpenJDK 8 path. This will build both versions correctly +from command line. But note that you do need to update your `JAVA_HOME` env +var to the associated version before opening Android Studio and loading any +Android projects. `JAVA_HOME_11` is mostly used by CI. -- GitLab From 4f9f4fa1462baf46cb207b7edaa40f454cbd6eca Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Thu, 25 May 2023 14:01:53 -0400 Subject: [PATCH 148/214] auto: increment master version to 17.0.113 --- HISTORY.md | 4 ++++ VERSION.md | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 05c1a80bcf..089fbc0973 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,9 @@ # Keyman Version History +## 17.0.112 alpha 2023-05-25 + +* refactor(developer): move file write out of WriteCompiledKeyboard and CompileKeyboard merge (#8796) + ## 17.0.111 alpha 2023-05-24 * fix(android/app): Pathing for publish script (#8845) diff --git a/VERSION.md b/VERSION.md index 945e7e5abf..290c27a0bd 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.112 \ No newline at end of file +17.0.113 \ No newline at end of file -- GitLab From 654034791f25e37585e7241a08fe9674cedf5ffb Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 26 May 2023 10:19:20 +0200 Subject: [PATCH 149/214] Update android/README.md Co-authored-by: Marc Durdin --- android/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/android/README.md b/android/README.md index dd2c3402a4..9b138ccfce 100644 --- a/android/README.md +++ b/android/README.md @@ -27,9 +27,9 @@ yes | ~/Library/Android/sdk/tools/bin/sdkmanager --licenses ### Crash Reporting -Keyman for Android uses [Sentry](https://sentry.io) for crash reporting at a server -. The analytics for Debug are associated with an -App Bundle ID `com.tavultesoft.kmapro.debug`. +Keyman for Android uses [Sentry](https://sentry.io) for crash reporting. The +analytics for Debug are associated with an App Bundle ID +`com.tavultesoft.kmapro.debug`. ### Compiling From Command Line -- GitLab From 0b5e47cd93babfb30fe40a888f8a48198ae98bc7 Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Fri, 26 May 2023 14:02:19 -0400 Subject: [PATCH 150/214] auto: increment master version to 17.0.114 --- HISTORY.md | 7 +++++++ VERSION.md | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 089fbc0973..c05c241eff 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,12 @@ # Keyman Version History +## 17.0.113 alpha 2023-05-26 + +* docs(android): Update documentation for building Android on Linux (#8860) +* fix(android): Fix typo in build-utils.sh (#8859) +* refactor(developer): compiler interface part 1 for wasm (#8850) +* chore(developer): remove SetError macro (#8856) + ## 17.0.112 alpha 2023-05-25 * refactor(developer): move file write out of WriteCompiledKeyboard and CompileKeyboard merge (#8796) diff --git a/VERSION.md b/VERSION.md index 290c27a0bd..a3a3dc809e 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.113 \ No newline at end of file +17.0.114 \ No newline at end of file -- GitLab From d763cf315ab7581fe1eb45d8ec652d4af90eaf67 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 30 May 2023 08:14:23 +0700 Subject: [PATCH 151/214] chore(developer): refactor kmcmplib interfaces Relates to #8493. * Removes kmcmplib calls from kmcmpdll (now that we have kmc) * Removes old kmcmp_CompileKeyboardFile and kmcmp_CompileKeyboardFileToBuffer functions in preference for a much cleaner kmcmp_CompileKeyboard function * Removes json validation helper from kmcmplib (we'll use js-native json schema validation instead) This change means that we no longer need to keep compfile.h consistent between kmcmplib and kmcmpdll. This will simplify upcoming refactoring of kmcmplib. kmcmplib no longer writes files, but it does still read them. The next refactor will move file load responsibility into the caller. --- common/windows/cpp/include/legacy_kmx_file.h | 1 - .../src/common/delphi/compiler/compile.pas | 1 - .../src/kmc-kmn/src/compiler/compiler.ts | 12 +- developer/src/kmc-kmn/test/test-compiler.ts | 14 +- developer/src/kmcmpdll/Compiler.cpp | 38 ---- developer/src/kmcmpdll/json-validation.cpp | 10 - developer/src/kmcmpdll/kmcmpdll.vcxproj | 16 +- developer/src/kmcmplib/include/kmcmplibapi.h | 73 ++++--- developer/src/kmcmplib/include/meson.build | 4 +- .../src/kmcmplib/src/CompilerInterfaces.cpp | 202 ++++++------------ .../src/kmcmplib/src/json-validation.cpp | 68 ------ developer/src/kmcmplib/src/meson.build | 4 - developer/src/kmcmplib/tests/api-test.cpp | 38 +--- developer/src/kmcmplib/tests/kmcompxtest.cpp | 35 ++- ...er.System.Project.kmnProjectFileAction.pas | 2 +- 15 files changed, 160 insertions(+), 358 deletions(-) delete mode 100644 developer/src/kmcmplib/src/json-validation.cpp diff --git a/common/windows/cpp/include/legacy_kmx_file.h b/common/windows/cpp/include/legacy_kmx_file.h index ae18543312..d961250912 100644 --- a/common/windows/cpp/include/legacy_kmx_file.h +++ b/common/windows/cpp/include/legacy_kmx_file.h @@ -409,7 +409,6 @@ typedef COMP_GROUP *PCOMP_GROUP; typedef struct _COMPILER_OPTIONS { DWORD dwSize; BOOL ShouldAddCompilerVersion; - BOOL UseKmcmpLib; } COMPILER_OPTIONS; typedef COMPILER_OPTIONS *PCOMPILER_OPTIONS; diff --git a/developer/src/common/delphi/compiler/compile.pas b/developer/src/common/delphi/compiler/compile.pas index b89ef0eb72..0124150ef6 100644 --- a/developer/src/common/delphi/compiler/compile.pas +++ b/developer/src/common/delphi/compiler/compile.pas @@ -176,7 +176,6 @@ type TCompilerOptions = record dwSize: DWORD; ShouldAddCompilerVersion: BOOL; - UseKmcmpLib: BOOL; end; COMPILER_OPTIONS = TCompilerOptions; diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index a88999e99c..606bec638c 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -114,14 +114,17 @@ export class KmnCompiler { private runCompiler(infile: string, outfile: string, options: CompilerOptions): CompilerResult { let result: CompilerResult = {}; let wasm_interface = new this.Module.CompilerInterface(); + let wasm_options = new this.Module.CompilerOptions(); let wasm_result = null; try { - wasm_interface.saveDebug = options.saveDebug; - wasm_interface.compilerWarningsAsErrors = options.compilerWarningsAsErrors; - wasm_interface.warnDeprecatedCode = options.warnDeprecatedCode; + wasm_options.saveDebug = options.saveDebug; + wasm_options.compilerWarningsAsErrors = options.compilerWarningsAsErrors; + wasm_options.warnDeprecatedCode = options.warnDeprecatedCode; + wasm_options.shouldAddCompilerVersion = options.shouldAddCompilerVersion; + wasm_options.target = 0; //CKF_KEYMAN; TODO, support KMW wasm_interface.messageCallback = this.callbackName; wasm_interface.loadFileCallback = this.callbackName; // TODO: this is wrong, needs to be a new callback; not yet used though - wasm_result = this.Module.kmcmp_compile(infile, wasm_interface); + wasm_result = this.Module.kmcmp_compile(infile, wasm_options, wasm_interface); if(!wasm_result.result) { return null; } @@ -147,6 +150,7 @@ export class KmnCompiler { wasm_result.delete(); } wasm_interface.delete(); + wasm_options.delete(); } } diff --git a/developer/src/kmc-kmn/test/test-compiler.ts b/developer/src/kmc-kmn/test/test-compiler.ts index 925656f8f5..8c35398361 100644 --- a/developer/src/kmc-kmn/test/test-compiler.ts +++ b/developer/src/kmc-kmn/test/test-compiler.ts @@ -86,20 +86,20 @@ describe('Compiler class', function() { const kmxFixture = fixtureDir + '/binary/caps_lock_layer_3620.kmx'; const kvkFixture = fixtureDir + '/binary/caps_lock_layer_3620.kvk'; - const kmxfile = __dirname + '/caps_lock_layer_3620.kmx'; - const kvkfile = __dirname + '/caps_lock_layer_3620.kvk'; + const resultingKmxfile = __dirname + '/caps_lock_layer_3620.kmx'; + const resultingKvkfile = __dirname + '/caps_lock_layer_3620.kvk'; - assert(compiler.run(infile, kmxfile, {saveDebug: true, shouldAddCompilerVersion: false})); + assert(compiler.run(infile, resultingKmxfile, {saveDebug: true, shouldAddCompilerVersion: false})); - assert(fs.existsSync(kmxfile)); - assert(fs.existsSync(kvkfile)); + assert(fs.existsSync(resultingKmxfile)); + assert(fs.existsSync(resultingKvkfile)); - const kmxData = fs.readFileSync(kmxfile); + const kmxData = fs.readFileSync(resultingKmxfile); const kmxFixtureData = fs.readFileSync(kmxFixture); assert.equal(kmxData.byteLength, kmxFixtureData.byteLength); assert.deepEqual(kmxData, kmxFixtureData); - const kvkData = fs.readFileSync(kvkfile); + const kvkData = fs.readFileSync(resultingKvkfile); const kvkFixtureData = fs.readFileSync(kvkFixture); assert.equal(kvkData.byteLength, kvkFixtureData.byteLength); assert.deepEqual(kvkData, kvkFixtureData); diff --git a/developer/src/kmcmpdll/Compiler.cpp b/developer/src/kmcmpdll/Compiler.cpp index 8cc28d2ab7..100e43fc5b 100644 --- a/developer/src/kmcmpdll/Compiler.cpp +++ b/developer/src/kmcmpdll/Compiler.cpp @@ -90,8 +90,6 @@ #include "UnreachableRules.h" #include "CheckForDuplicates.h" -#include "../kmcmplib/include/kmcmplibapi.h" - int xatoi(PWSTR *p); int atoiW(PWSTR p); void safe_wcsncpy(PWSTR out, PWSTR in, int cbMax); @@ -291,33 +289,15 @@ BOOL AddCompileMessage(DWORD msg) return FALSE; } -bool flag_use_new_kmcomp = true; // flag to switch to new kmcompx - extern "C" BOOL __declspec(dllexport) SetCompilerOptions(PCOMPILER_OPTIONS options) { if(!options || options->dwSize < sizeof(COMPILER_OPTIONS)) { return FALSE; } - flag_use_new_kmcomp = options->UseKmcmpLib; - - //printf("\n---> started in SetCompilerOptions() of kmcmpdll\n"); - if ( flag_use_new_kmcomp ) - { - KMCMP_COMPILER_OPTIONS kmcmp_options = {0}; - kmcmp_options.dwSize = sizeof(KMCMP_COMPILER_OPTIONS); - kmcmp_options.ShouldAddCompilerVersion = options->ShouldAddCompilerVersion; - return kmcmp_SetCompilerOptions(&kmcmp_options); - } - //printf("---> stayed in SetCompilerOptions() of kmcmpdll\n"); - FShouldAddCompilerVersion = options->ShouldAddCompilerVersion; return TRUE; } -int kmcmpMsgproc(int line, uint32_t dwMsgCode, char* szText, void* context) { - return static_cast(context)(line, dwMsgCode, szText); -} - extern "C" BOOL __declspec(dllexport) CompileKeyboardFile(PSTR pszInfile, PSTR pszOutfile, BOOL ASaveDebug, BOOL ACompilerWarningsAsErrors, BOOL AWarnDeprecatedCode, CompilerMessageProc pMsgProc) // I4865 // I4866 { HANDLE hInfile = INVALID_HANDLE_VALUE, hOutfile = INVALID_HANDLE_VALUE; @@ -325,15 +305,6 @@ extern "C" BOOL __declspec(dllexport) CompileKeyboardFile(PSTR pszInfile, PSTR p DWORD len; char str[260]; - //printf("\n---> started in CompileKeyboardFile() of kmcmpdll\n"); - - if ( flag_use_new_kmcomp ) - { - return kmcmp_CompileKeyboardFile(pszInfile, pszOutfile, ASaveDebug, ACompilerWarningsAsErrors,AWarnDeprecatedCode, kmcmpMsgproc, (void*) pMsgProc); - } - - //printf("---> stayed in CompileKeyboardFile() of kmcmpdll\n"); - FSaveDebug = ASaveDebug; FCompilerWarningsAsErrors = ACompilerWarningsAsErrors; // I4865 FWarnDeprecatedCode = AWarnDeprecatedCode; // I4866 @@ -418,15 +389,6 @@ extern "C" BOOL __declspec(dllexport) CompileKeyboardFileToBuffer(PSTR pszInfile DWORD len; char str[260]; - //printf("\n---> started in CompileKeyboardFileToBuffer() of kmcmpdll\n"); - if ( flag_use_new_kmcomp ) - { - return kmcmp_CompileKeyboardFileToBuffer( pszInfile, (void*) pfkBuffer, ACompilerWarningsAsErrors, AWarnDeprecatedCode, kmcmpMsgproc, (void*) pMsgProc, Target); - } - - //printf("---> stayed in CompileKeyboardFileToBuffer() of kmcmpdll\n"); - - FSaveDebug = TRUE; // I3681 FCompilerWarningsAsErrors = ACompilerWarningsAsErrors; // I4865 FWarnDeprecatedCode = AWarnDeprecatedCode; // I4866 diff --git a/developer/src/kmcmpdll/json-validation.cpp b/developer/src/kmcmpdll/json-validation.cpp index e35dc0485d..c3c1af0484 100644 --- a/developer/src/kmcmpdll/json-validation.cpp +++ b/developer/src/kmcmpdll/json-validation.cpp @@ -1,14 +1,11 @@ #include #include -#include "../kmcmplib/include/kmcmplibapi.h" #include typedef bool (*kmcmp_ValidateJsonMessageProc)(int64_t offset, const char* szText, void* context); -extern bool flag_use_new_kmcomp; - using nlohmann::json; using nlohmann::json_uri; using nlohmann::json_schema_draft4::json_validator; @@ -35,13 +32,6 @@ bool kmcmpMessageProc(int64_t offset, const char* szText, void* context) { extern "C" BOOL __declspec(dllexport) ValidateJsonFile(PWSTR pwszSchemaFile, PWSTR pwszJsonFile, ValidateJsonMessageProc MessageProc) { - if ( flag_use_new_kmcomp ) - { - std::fstream f(pwszSchemaFile); - std::fstream fd(pwszJsonFile); - return kmcmp_ValidateJsonFile(f, fd, kmcmpMessageProc, (void*)MessageProc); - } - std::fstream f(pwszSchemaFile); if (!f.good()) { MessageProc(-1, "Schema file could not be loaded."); diff --git a/developer/src/kmcmpdll/kmcmpdll.vcxproj b/developer/src/kmcmpdll/kmcmpdll.vcxproj index c7f7e1f48f..2bcc038bd0 100644 --- a/developer/src/kmcmpdll/kmcmpdll.vcxproj +++ b/developer/src/kmcmpdll/kmcmpdll.vcxproj @@ -89,25 +89,25 @@ $(VC_IncludePath);$(WindowsSDK_IncludePath);$(KEYMAN_ROOT)\developer\src\common\include;$(KEYMAN_ROOT)\developer\src\ext\json;$(KEYMAN_ROOT)\developer\src\ext\json-schema-validator $(ProjectDir)bin\$(Platform)\$(Configuration)\ - $(KEYMAN_ROOT)\developer\src\kmcmplib\build\x86\$(Configuration)\src;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86) + $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86) $(VC_IncludePath);$(WindowsSDK_IncludePath);$(KEYMAN_ROOT)\developer\src\common\include;$(KEYMAN_ROOT)\developer\src\ext\json;$(KEYMAN_ROOT)\developer\src\ext\json-schema-validator $(ProjectDir)obj\$(Platform)\$(Configuration)\ $(ProjectName).x64 $(ProjectDir)bin\$(Platform)\$(Configuration)\ - $(KEYMAN_ROOT)\developer\src\kmcmplib\build\x64\$(Configuration)\src;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) + $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) $(VC_IncludePath);$(WindowsSDK_IncludePath);$(KEYMAN_ROOT)\developer\src\common\include;$(KEYMAN_ROOT)\developer\src\ext\json;$(KEYMAN_ROOT)\developer\src\ext\json-schema-validator - $(KEYMAN_ROOT)\developer\src\kmcmplib\build\x86\$(Configuration)\src;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86) + $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86) $(VC_IncludePath);$(WindowsSDK_IncludePath);$(KEYMAN_ROOT)\developer\src\common\include;$(KEYMAN_ROOT)\developer\src\ext\json;$(KEYMAN_ROOT)\developer\src\ext\json-schema-validator $(ProjectDir)obj\$(Platform)\$(Configuration)\ $(ProjectName).x64 $(ProjectDir)bin\$(Platform)\$(Configuration)\ - $(KEYMAN_ROOT)\developer\src\kmcmplib\build\x64\$(Configuration)\src;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) + $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) @@ -142,7 +142,7 @@ $(KEYMAN_ROOT)\windows\src\global\inc - libkmcmplib.a;version.lib;setupapi.lib;iphlpapi.lib;imm32.lib;crypt32.lib;wintrust.lib;imagehlp.lib;ws2_32.lib;%(AdditionalDependencies) + version.lib;setupapi.lib;iphlpapi.lib;imm32.lib;crypt32.lib;wintrust.lib;imagehlp.lib;ws2_32.lib;%(AdditionalDependencies) true true @@ -190,7 +190,7 @@ $(KEYMAN_ROOT)\windows\src\global\inc - libkmcmplib.a;version.lib;setupapi.lib;iphlpapi.lib;imm32.lib;crypt32.lib;wintrust.lib;imagehlp.lib;ws2_32.lib;%(AdditionalDependencies) + version.lib;setupapi.lib;iphlpapi.lib;imm32.lib;crypt32.lib;wintrust.lib;imagehlp.lib;ws2_32.lib;%(AdditionalDependencies) true true Windows @@ -233,7 +233,7 @@ $(KEYMAN_ROOT)\windows\src\global\inc - libkmcmplib.a;version.lib;setupapi.lib;iphlpapi.lib;imm32.lib;crypt32.lib;wintrust.lib;imagehlp.lib;ws2_32.lib;%(AdditionalDependencies) + version.lib;setupapi.lib;iphlpapi.lib;imm32.lib;crypt32.lib;wintrust.lib;imagehlp.lib;ws2_32.lib;%(AdditionalDependencies) true true true @@ -277,7 +277,7 @@ $(KEYMAN_ROOT)\windows\src\global\inc - libkmcmplib.a;version.lib;setupapi.lib;iphlpapi.lib;imm32.lib;crypt32.lib;wintrust.lib;imagehlp.lib;ws2_32.lib;%(AdditionalDependencies) + version.lib;setupapi.lib;iphlpapi.lib;imm32.lib;crypt32.lib;wintrust.lib;imagehlp.lib;ws2_32.lib;%(AdditionalDependencies) true true true diff --git a/developer/src/kmcmplib/include/kmcmplibapi.h b/developer/src/kmcmplib/include/kmcmplibapi.h index f4591612ec..4054d81e81 100644 --- a/developer/src/kmcmplib/include/kmcmplibapi.h +++ b/developer/src/kmcmplib/include/kmcmplibapi.h @@ -16,49 +16,48 @@ #define EXTERN EMSCRIPTEN_KEEPALIVE #endif -typedef struct _KMCMP_COMPILER_OPTIONS { - uint32_t dwSize; - bool ShouldAddCompilerVersion; -} KMCMP_COMPILER_OPTIONS; - -EXTERN bool kmcmp_SetCompilerOptions( - KMCMP_COMPILER_OPTIONS* options -); - -typedef int (*kmcmp_CompilerMessageProc)(int line, uint32_t dwMsgCode, char* szText, void* context); - -EXTERN bool kmcmp_CompileKeyboardFile( - char* pszInfile, - char* pszOutfile, - bool ASaveDebug, - bool ACompilerWarningsAsErrors, - bool AWarnDeprecatedCode, - kmcmp_CompilerMessageProc pMsgproc, - void* AmsgprocContext -); - /* Compile target */ #define CKF_KEYMAN 0 #define CKF_KEYMANWEB 1 -EXTERN bool kmcmp_CompileKeyboardFileToBuffer( - char* pszInfile, - void* pfkBuffer, - bool ACompilerWarningsAsErrors, - bool AWarnDeprecatedCode, - kmcmp_CompilerMessageProc pMsgproc, - void* AmsgprocContext, - int Target -); - -typedef bool (*kmcmp_ValidateJsonMessageProc)(int64_t offset, const char* szText, void* context); +struct KMCMP_COMPILER_OPTIONS { + bool saveDebug; + bool compilerWarningsAsErrors; + bool warnDeprecatedCode; + bool shouldAddCompilerVersion; + int target; // CKF_KEYMAN, CKF_KEYMANWEB +}; + +struct KMCMP_COMPILER_RESULT { + void* kmx; + size_t kmxSize; + std::string kvksFilename; +}; + +// TODO: parameters in UTF-8 +typedef int (*kmcmp_CompilerMessageProc)(int line, uint32_t dwMsgCode, char* szText, void* context); -EXTERN bool kmcmp_ValidateJsonFile( - std::fstream& f, - std::fstream& fd, - kmcmp_ValidateJsonMessageProc MessageProc, - void* context +// parameters in UTF-8 +// TODO typical usage: +// if(!kmcmp_LoadFileProc("filename.ico", "/tmp/filename.kmn", nullptr, &size)) { +// return error; +// } +// buf = new unsigned char[size]; +// if(!kmcmp_LoadFileProc("filename.ico", "/tmp/filename.kmn", buf, &size)) { +// delete[] buf; +// return error; +// } +typedef bool (*kmcmp_LoadFileProc)(char* loadFilename, char* baseFilename, void* buffer, int* bufferSize); + +// Parameters in UTF-8 +EXTERN bool kmcmp_CompileKeyboard( + const char* pszInfile, + const KMCMP_COMPILER_OPTIONS& options, + kmcmp_CompilerMessageProc messageProc, + kmcmp_LoadFileProc loadFileProc, + const void* procContext, + KMCMP_COMPILER_RESULT& result ); /** diff --git a/developer/src/kmcmplib/include/meson.build b/developer/src/kmcmplib/include/meson.build index f98a4d8c76..dde8e69f6b 100644 --- a/developer/src/kmcmplib/include/meson.build +++ b/developer/src/kmcmplib/include/meson.build @@ -20,7 +20,5 @@ configure_file( inc = include_directories( '.', '../../common/include', - '../../../../common/include', - '../../ext/json', - '../../ext/json-schema-validator' + '../../../../common/include' ) diff --git a/developer/src/kmcmplib/src/CompilerInterfaces.cpp b/developer/src/kmcmplib/src/CompilerInterfaces.cpp index 56ecf4cdcf..71e1e895f2 100644 --- a/developer/src/kmcmplib/src/CompilerInterfaces.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfaces.cpp @@ -12,19 +12,6 @@ #include "../../../../common/windows/cpp/include/keymanversion.h" bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk); -bool CompileKeyboard(const char* pszInfile, - void* pfkBuffer, bool ASaveDebug, bool ACompilerWarningsAsErrors, - bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, const void* AmsgprocContext, - int Target); - -EXTERN bool kmcmp_SetCompilerOptions(KMCMP_COMPILER_OPTIONS* options) { - //printf("°°-> changed to SetCompilerOptions() of kmcmplib \n"); - if(!options || options->dwSize < sizeof(KMCMP_COMPILER_OPTIONS)) { - return FALSE; - } - kmcmp::FShouldAddCompilerVersion = options->ShouldAddCompilerVersion; - return TRUE; -} #ifdef __EMSCRIPTEN__ @@ -46,17 +33,12 @@ int wasm_CompilerMessageProc(int line, uint32_t dwMsgCode, char* szText, void* c return wasm_msgproc(line, dwMsgCode, szText, msgProc); } -struct COMPILER_INTERFACE { - bool saveDebug; - bool compilerWarningsAsErrors; - bool warnDeprecatedCode; - bool shouldAddCompilerVersion; - int target; // CKF_KEYMAN, CKF_KEYMANWEB +struct WASM_COMPILER_INTERFACE { std::string messageCallback; // int line, uint32_t dwMsgCode, char* szText - std::string loadFileCallback; // char* infile, char* filenameRelativeToInfile --> buffer + std::string loadFileCallback; // TODO: char* filename, char* baseFilename --> buffer }; -struct COMPILER_RESULT { +struct WASM_COMPILER_RESULT { bool result; // Following are pointer offsets in heap + buffer size int kmx; @@ -67,104 +49,101 @@ struct COMPILER_RESULT { // TODO: additional data to be passed back }; -COMPILER_RESULT kmcmp_compile(std::string pszInfile, const COMPILER_INTERFACE intf) { - COMPILER_RESULT r = {false}; +WASM_COMPILER_RESULT kmcmp_wasm_compile(std::string pszInfile, const KMCMP_COMPILER_OPTIONS options, const WASM_COMPILER_INTERFACE intf) { + WASM_COMPILER_RESULT r = {false}; + KMCMP_COMPILER_RESULT kr; - FILE_KEYBOARD fk; - - // TODO: this should be included in CompileKeyboard? - kmcmp::FShouldAddCompilerVersion = intf.shouldAddCompilerVersion; + r.kmx = 0; + r.kmxSize = 0; + r.kvksFilename = ""; - r.result = CompileKeyboard( + r.result = kmcmp_CompileKeyboard( pszInfile.c_str(), - &fk, - intf.saveDebug, - intf.compilerWarningsAsErrors, - intf.warnDeprecatedCode, + options, wasm_CompilerMessageProc, + nullptr, //wasm_LoadFileProc, intf.messageCallback.c_str(), - intf.target); - - if(!r.result) { - return r; + kr + ); + + if(r.result) { + // TODO: additional data as required by kmc_kmw + r.kmx = (int) kr.kmx; + r.kmxSize = (int) kr.kmxSize; + r.kvksFilename = kr.kvksFilename; } - KMX_DWORD msg; - KMX_BYTE* data = nullptr; - size_t dataSize = 0; - msg = WriteCompiledKeyboard(&fk, &data, dataSize); - //TODO: FreeKeyboardPointers(fk); - - if(msg != CERR_None) { - AddCompileError(msg); - r.result = FALSE; - return r; - } - - r.kmx = (int) data; - r.kmxSize = (int) dataSize; - r.kvksFilename = string_from_u16string(fk.extra->kvksFilename); // convert to UTF8 - return r; } EMSCRIPTEN_BINDINGS(compiler_interface) { - emscripten::class_("CompilerInterface") + + emscripten::class_("CompilerOptions") + .constructor<>() + .property("saveDebug", &KMCMP_COMPILER_OPTIONS::saveDebug) + .property("compilerWarningsAsErrors", &KMCMP_COMPILER_OPTIONS::compilerWarningsAsErrors) + .property("warnDeprecatedCode", &KMCMP_COMPILER_OPTIONS::warnDeprecatedCode) + .property("shouldAddCompilerVersion", &KMCMP_COMPILER_OPTIONS::shouldAddCompilerVersion) + .property("target", &KMCMP_COMPILER_OPTIONS::target) + ; + + emscripten::class_("CompilerInterface") .constructor<>() - .property("saveDebug", &COMPILER_INTERFACE::saveDebug) - .property("compilerWarningsAsErrors", &COMPILER_INTERFACE::compilerWarningsAsErrors) - .property("warnDeprecatedCode", &COMPILER_INTERFACE::warnDeprecatedCode) - .property("shouldAddCompilerVersion", &COMPILER_INTERFACE::shouldAddCompilerVersion) - .property("target", &COMPILER_INTERFACE::target) - .property("messageCallback", &COMPILER_INTERFACE::messageCallback) - .property("loadFileCallback", &COMPILER_INTERFACE::loadFileCallback) + .property("messageCallback", &WASM_COMPILER_INTERFACE::messageCallback) + .property("loadFileCallback", &WASM_COMPILER_INTERFACE::loadFileCallback) ; - emscripten::class_("CompilerResult") + emscripten::class_("CompilerResult") .constructor<>() - .property("result", &COMPILER_RESULT::result) - .property("kmx", &COMPILER_RESULT::kmx) - .property("kmxSize", &COMPILER_RESULT::kmxSize) - .property("kvksFilename", &COMPILER_RESULT::kvksFilename) + .property("result", &WASM_COMPILER_RESULT::result) + .property("kmx", &WASM_COMPILER_RESULT::kmx) + .property("kmxSize", &WASM_COMPILER_RESULT::kmxSize) + .property("kvksFilename", &WASM_COMPILER_RESULT::kvksFilename) ; - emscripten::function("kmcmp_compile", &kmcmp_compile); + emscripten::function("kmcmp_compile", &kmcmp_wasm_compile); emscripten::function("kmcmp_parseUnicodeSet", &kmcmp_parseUnicodeSet); } #endif -bool CompileKeyboard(const char* pszInfile, - void* pfkBuffer, bool ASaveDebug, bool ACompilerWarningsAsErrors, - bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, const void* AmsgprocContext, - int Target) { +EXTERN bool kmcmp_CompileKeyboard( + const char* pszInfile, + const KMCMP_COMPILER_OPTIONS& options, + kmcmp_CompilerMessageProc messageProc, + kmcmp_LoadFileProc loadFileProc, + const void* procContext, + KMCMP_COMPILER_RESULT& result +) { FILE* fp_in = NULL; KMX_CHAR str[260]; + FILE_KEYBOARD fk; - kmcmp::FSaveDebug = ASaveDebug; // I3681 - kmcmp::FCompilerWarningsAsErrors = ACompilerWarningsAsErrors; // I4865 - AWarnDeprecatedCode_GLOBAL_LIB = AWarnDeprecatedCode; - - kmcmp::CompileTarget = Target; + kmcmp::FSaveDebug = options.saveDebug; // I3681 + kmcmp::FCompilerWarningsAsErrors = options.compilerWarningsAsErrors; // I4865 + AWarnDeprecatedCode_GLOBAL_LIB = options.warnDeprecatedCode; + kmcmp::FShouldAddCompilerVersion = options.shouldAddCompilerVersion; + kmcmp::CompileTarget = options.target; - if (!pMsgproc || !pszInfile || !pfkBuffer) { + if (!messageProc || !pszInfile) { // TODO: add loadFileProc AddCompileError(CERR_BadCallParams); return FALSE; } PKMX_STR p; - if ((p = strrchr_slash((char*)pszInfile)) != nullptr) - { + if ((p = strrchr_slash((char*)pszInfile)) != nullptr) { strncpy(kmcmp::CompileDir, pszInfile, (int)(p - pszInfile + 1)); // I3481 kmcmp::CompileDir[(int)(p - pszInfile + 1)] = 0; } - else + else { kmcmp::CompileDir[0] = 0; + } - msgproc = pMsgproc; - msgprocContext = (void*)AmsgprocContext; + msgproc = messageProc; + //TODO: loadfileproc = loadFileProc; + msgprocContext = (void*)procContext; kmcmp::currentLine = 0; kmcmp::nErrors = 0; @@ -196,71 +175,32 @@ bool CompileKeyboard(const char* pszInfile, } kmcmp::CodeConstants = new kmcmp::NamedCodeConstants; - bool result = CompileKeyboardHandle(fp_in, static_cast(pfkBuffer)); + bool success = CompileKeyboardHandle(fp_in, &fk); delete kmcmp::CodeConstants; fclose(fp_in); - if (kmcmp::nErrors > 0) { - return FALSE; - } - - return result; -} - -EXTERN bool kmcmp_CompileKeyboardFileToBuffer(char* pszInfile, void* pfkBuffer, bool ACompilerWarningsAsErrors, bool AWarnDeprecatedCode, - kmcmp_CompilerMessageProc pMsgproc, void* AmsgprocContext, int Target) // I4865 // I4866 -{ - if (!pMsgproc || !pszInfile || !pfkBuffer) { - AddCompileError(CERR_BadCallParams); - return FALSE; - } - - return CompileKeyboard(pszInfile, pfkBuffer, TRUE, ACompilerWarningsAsErrors, AWarnDeprecatedCode, - pMsgproc, AmsgprocContext, Target); -} - -EXTERN bool kmcmp_CompileKeyboardFile(char* pszInfile, - char* pszOutfile, bool ASaveDebug, bool ACompilerWarningsAsErrors, - bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, void* AmsgprocContext) // I4865 // I4866 -{ - if (!pMsgproc || !pszInfile || !pszOutfile) { - AddCompileError(CERR_BadCallParams); - return FALSE; - } - - FILE_KEYBOARD fk; - if(!CompileKeyboard(pszInfile, &fk, ASaveDebug, ACompilerWarningsAsErrors, AWarnDeprecatedCode, - pMsgproc, AmsgprocContext, CKF_KEYMAN)) { - // any errors will have been reported directly by CompileKeyboard - return FALSE; - } - - FILE* fp_out = Open_File(pszOutfile, "wb"); - if (fp_out == NULL) { - AddCompileError(CERR_CannotCreateOutfile); + if (kmcmp::nErrors > 0 || !success) { return FALSE; } + // fill in result data KMX_DWORD msg; KMX_BYTE* data = nullptr; size_t dataSize = 0; - if ((msg = WriteCompiledKeyboard(&fk, &data, dataSize)) != CERR_None) { - AddCompileError(msg); - } else { - if(fwrite(data, 1, dataSize, fp_out) != dataSize) { - AddCompileError(CERR_UnableToWriteFully); - } - delete[] data; - } + msg = WriteCompiledKeyboard(&fk, &data, dataSize); - fclose(fp_out); + //TODO: FreeKeyboardPointers(fk); - if (kmcmp::nErrors > 0) { - remove(pszOutfile); + if(msg != CERR_None) { + AddCompileError(msg); return FALSE; } + result.kmx = data; + result.kmxSize = dataSize; + result.kvksFilename = string_from_u16string(fk.extra->kvksFilename); // convert to UTF8 + return TRUE; } diff --git a/developer/src/kmcmplib/src/json-validation.cpp b/developer/src/kmcmplib/src/json-validation.cpp deleted file mode 100644 index f58d8c9505..0000000000 --- a/developer/src/kmcmplib/src/json-validation.cpp +++ /dev/null @@ -1,68 +0,0 @@ - -#include -#include - -#include -#include "kmcompx.h" - -using nlohmann::json; -using nlohmann::json_uri; -using nlohmann::json_schema_draft4::json_validator; - -static void loader(const json_uri &uri, json &schema) -{ - std::fstream lf("." + uri.path()); - if (!lf.good()) - throw std::invalid_argument("could not open " + uri.url() + " tried with " + uri.path()); - - lf >> schema; -} - -EXTERN bool kmcmp_ValidateJsonFile(std::fstream& f, std::fstream& fd, kmcmp_ValidateJsonMessageProc MessageProc, void* context) { - if (!f.good()) { - MessageProc(-1, "Schema file could not be loaded.", context); - return FALSE; - } - - // 1) Read the schema for the document you want to validate - json schema; - try { - f >> schema; - } - catch (std::exception &e) { - MessageProc(f.tellp(), e.what(), context); - return FALSE; - } - - // 2) create the validator and - json_validator validator(loader, [](const std::string &, const std::string &) {}); - - try { - // insert this schema as the root to the validator - // this resolves remote-schemas, sub-schemas and references via the given loader-function - validator.set_root_schema(schema); - } - catch (std::exception &e) { - MessageProc(-2, e.what(), context); - return FALSE; - } - - // 3) do the actual validation of the document - json document; - - if (!fd.good()) { - MessageProc(-3, "Json file could not be loaded.", context); - return FALSE; - } - - try { - fd >> document; - validator.validate(document); - } - catch (std::exception &e) { - MessageProc(fd.tellp(), e.what(), context); - return FALSE; - } - - return TRUE; -} \ No newline at end of file diff --git a/developer/src/kmcmplib/src/meson.build b/developer/src/kmcmplib/src/meson.build index 3cd9abd6e1..8264c3d28e 100644 --- a/developer/src/kmcmplib/src/meson.build +++ b/developer/src/kmcmplib/src/meson.build @@ -43,7 +43,6 @@ lib = library('kmcmplib', 'DeprecationChecks.cpp', 'Edition.cpp', 'filesystem.cpp', - 'json-validation.cpp', 'NamedCodeConstants.cpp', 'versioning.cpp', 'virtualcharkeys.cpp', @@ -62,9 +61,6 @@ lib = library('kmcmplib', '../../../../common/windows/cpp/src/vkeys.cpp', 'xstring.cpp', - '../../ext/json-schema-validator/json-schema-draft4.json.cpp', - '../../ext/json-schema-validator/json-uri.cpp', - '../../ext/json-schema-validator/json-validator.cpp', version_res, cpp_args: defns + warns + flags, link_args: links, diff --git a/developer/src/kmcmplib/tests/api-test.cpp b/developer/src/kmcmplib/tests/api-test.cpp index 4c46b1f1a4..4bb0276a79 100644 --- a/developer/src/kmcmplib/tests/api-test.cpp +++ b/developer/src/kmcmplib/tests/api-test.cpp @@ -20,8 +20,7 @@ #include void setup(); -void test_kmcmp_CompileKeyboardFile(); -void test_kmcmp_CompileKeyboardFileToBuffer(); +void test_kmcmp_CompileKeyboard(); std::vector error_vec; @@ -40,10 +39,7 @@ int msgproc(int line, uint32_t dwMsgCode, char* szText, void* context) { int main(int argc, char *argv[]) { setup(); - test_kmcmp_CompileKeyboardFile(); - - setup(); - test_kmcmp_CompileKeyboardFileToBuffer(); + test_kmcmp_CompileKeyboard(); return 0; } @@ -52,24 +48,7 @@ void setup() { error_vec.clear(); } -void test_kmcmp_CompileKeyboardFile() { - char kmn_file[L_tmpnam], kmx_file[L_tmpnam]; - tmpnam(kmn_file); - tmpnam(kmx_file); - - // Create an empty file - FILE *fp = fopen(kmn_file, "w"); - fclose(fp); - - // It should fail when a zero-byte file is passed in - assert(!kmcmp_CompileKeyboardFile(kmn_file, kmx_file, true, false, true, msgproc, nullptr)); - assert(error_vec.size() == 1); - assert(error_vec[0] == CERR_CannotReadInfile); - - unlink(kmn_file); -} - -void test_kmcmp_CompileKeyboardFileToBuffer() { +void test_kmcmp_CompileKeyboard() { char kmn_file[L_tmpnam], kmx_file[L_tmpnam]; tmpnam(kmn_file); tmpnam(kmx_file); @@ -78,10 +57,15 @@ void test_kmcmp_CompileKeyboardFileToBuffer() { FILE *fp = fopen(kmn_file, "w"); fclose(fp); - FILE_KEYBOARD fk; - // It should fail when a zero-byte file is passed in - assert(!kmcmp_CompileKeyboardFileToBuffer(kmn_file, &fk, true, false, msgproc, nullptr, CKF_KEYMAN)); + KMCMP_COMPILER_RESULT result; + KMCMP_COMPILER_OPTIONS options; + options.saveDebug = true; + options.compilerWarningsAsErrors = false; + options.warnDeprecatedCode = true; + options.shouldAddCompilerVersion = false; + options.target = CKF_KEYMAN; + assert(!kmcmp_CompileKeyboard(kmn_file, options, msgproc, nullptr, nullptr, result)); assert(error_vec.size() == 1); assert(error_vec[0] == CERR_CannotReadInfile); diff --git a/developer/src/kmcmplib/tests/kmcompxtest.cpp b/developer/src/kmcmplib/tests/kmcompxtest.cpp index 1ce542917d..87d9e53cf7 100644 --- a/developer/src/kmcmplib/tests/kmcompxtest.cpp +++ b/developer/src/kmcmplib/tests/kmcompxtest.cpp @@ -71,14 +71,15 @@ int main(int argc, char *argv[]) char first5[6] = "CERR_"; char* pfirst5 = first5; - KMCMP_COMPILER_OPTIONS kcopts; - kcopts.dwSize = sizeof(KMCMP_COMPILER_OPTIONS); - kcopts.ShouldAddCompilerVersion = false; // So we can compare against existing compiled keyboards that also don't have compiler version - if(!kmcmp_SetCompilerOptions(&kcopts)) { - return __LINE__; - } - - if(kmcmp_CompileKeyboardFile(kmn_file, kmx_file, true, false, true, msgproc, nullptr)) { + KMCMP_COMPILER_RESULT result; + KMCMP_COMPILER_OPTIONS options; + options.saveDebug = true; + options.compilerWarningsAsErrors = false; + options.warnDeprecatedCode = true; + options.shouldAddCompilerVersion = false; + options.target = CKF_KEYMAN; + + if(kmcmp_CompileKeyboard(kmn_file, options, msgproc, nullptr, nullptr, result)) { char* testname = strrchr( (char*) kmn_file, '/') + 1; if(strncmp(testname, pfirst5, 5) == 0){ return __LINE__; // exit code: CERR_ in Name + no Error found @@ -87,26 +88,24 @@ int main(int argc, char *argv[]) // On non-win32 platforms, we cannot get kmcmpdll.dll to build keyboards // legacy-mode, so we'll compare to a hopefully existing file that we've // been passed - FILE* fp1 = Open_File(kmx_file, "rb"); + FILE* fp1 = Open_File(kmx_file, "wb"); if(!fp1) return __LINE__; + // Write out for reference + fwrite(result.kmx, 1, result.kmxSize, fp1); + FILE* fp2 = Open_File(reference_kmx, "rb"); if(!fp2) return __LINE__; // exit code: fail if no reference kmx file in build-folder - fseek(fp1, 0, SEEK_END); - auto sz1 = ftell(fp1); - fseek(fp1, 0, SEEK_SET); fseek(fp2, 0, SEEK_END); auto sz2 = ftell(fp2); fseek(fp2, 0, SEEK_SET); - if (sz1 != sz2) return __LINE__; // exit code: size of kmx-file in build differs from size of kmx-file in source folder + if (result.kmxSize != sz2) return __LINE__; // exit code: size of kmx-file in build differs from size of kmx-file in source folder - char* buf1 = new char[sz1]; - char* buf2 = new char[sz1]; - fread(buf1, 1, sz1, fp1); - fread(buf2, 1, sz1, fp2); - return memcmp(buf1, buf2, sz1) ? __LINE__ : 0; // exit code: when contents of kmx-file in build differs from contents of kmx-file in source folder + char* buf2 = new char[result.kmxSize]; + fread(buf2, 1, result.kmxSize, fp2); + return memcmp(result.kmx, buf2, result.kmxSize) ? __LINE__ : 0; // exit code: when contents of kmx-file in build differs from contents of kmx-file in source folder // success: when contents of kmx-file in build and source folder are the same } else { /*if Errors found: check number (e.g. CERR_4061_balochi_phonetic.kmn should produce Error 4061)*/ diff --git a/developer/src/tike/project/Keyman.Developer.System.Project.kmnProjectFileAction.pas b/developer/src/tike/project/Keyman.Developer.System.Project.kmnProjectFileAction.pas index 703a1e4a0b..2b6dea94ec 100644 --- a/developer/src/tike/project/Keyman.Developer.System.Project.kmnProjectFileAction.pas +++ b/developer/src/tike/project/Keyman.Developer.System.Project.kmnProjectFileAction.pas @@ -115,7 +115,7 @@ begin TProject.CompilerMessageFile := Self; options.dwSize := sizeof(COMPILER_OPTIONS); options.ShouldAddCompilerVersion := addVersion; - options.UseKmcmpLib := not useLegacyCompiler; + // TODO: useLegacyCompiler means we switch to kmcmpdll vs kmc if not SetCompilerOptions(@options, ProjectCompilerMessage) then begin Log(plsFatal, 'Unable to set compiler options', CERR_FATAL, 0); -- GitLab From 05fe88bb3ada8437cc2e30d2bcb515c24fbadc93 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 30 May 2023 10:57:57 +0700 Subject: [PATCH 152/214] chore(developer): remove usekmcmplib flag from kmcomp --- developer/src/kmcomp/main.pas | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/developer/src/kmcomp/main.pas b/developer/src/kmcomp/main.pas index 5a29927a80..4aa29cf6c1 100644 --- a/developer/src/kmcomp/main.pas +++ b/developer/src/kmcomp/main.pas @@ -65,7 +65,7 @@ uses UKeymanTargets; function CompileKeyboard(FInFile, FOutFile: string; FDebug, FWarnAsError: Boolean): Boolean; forward; // I4706 -function KCSetCompilerOptions(const FInFile: string; FShouldAddCompilerVersion, FUseKmcmpLib: Boolean): Boolean; forward; +function KCSetCompilerOptions(const FInFile: string; FShouldAddCompilerVersion: Boolean): Boolean; forward; //function CompilerMessage(line: Integer; msgcode: LongWord; text: PAnsiChar): Integer; stdcall; forward; procedure FixupPathSlashes(var path: string); forward; @@ -90,7 +90,6 @@ var FParamDistribution: Boolean; FMergingValidateIds: Boolean; FShouldAddCompilerVersion: Boolean; - FUseKmcmpLib: Boolean; FJsonSchemaPath: string; FParamSourcePath: string; FParamHelpLink: string; @@ -117,7 +116,6 @@ begin FColorMode := cmDefault; FShouldAddCompilerVersion := True; - FUseKmcmpLib := True; FParamInfile := ''; FParamOutfile := ''; @@ -193,8 +191,6 @@ begin FColorMode := cmForceNoColor else if s = '-no-compiler-version' then FShouldAddCompilerVersion := False - else if s = '-use-legacy-compiler' then - FUseKmcmpLib := False else if (s = '-help') or (s = '-h') then begin // Force help @@ -223,8 +219,6 @@ begin writeln(SKeymanDeveloperName + ' Compiler (32-bit)'); {$ENDIF} writeln('Version ' + CKeymanVersionInfo.VersionWithTag + ', ' + GetVersionCopyright); - if not FUseKmcmpLib then - writeln('Note: using legacy compiler'); end; if FError or (FParamInfile = '') then @@ -234,7 +228,7 @@ begin writeln(''); writeln('Usage: '+cmd+' [-s[s]] [-nologo] [-c] [-d] [-w] [-cfc] [-v[s|d]] [-source-path path] [-schema-path path] '); writeln(' '+spc+' [-m] infile [-m infile] [-t target] [outfile.kmx|outfile.js [error.log]]'); // I4699 - writeln(' '+spc+' [-add-help-link path] [-color|-no-color] [-no-compiler-version] [-use-legacy-compiler]'); + writeln(' '+spc+' [-add-help-link path] [-color|-no-color] [-no-compiler-version]'); writeln(' '+spc+' [-extract-keyboard-info field[,field...]]'); writeln(' infile can be a .kmn file (Keyboard Source, .kps file (Package Source), or .kpj (project)'); // I4699 // I4825 writeln(' if -v specified, can also be a .keyboard_info file'); @@ -258,7 +252,6 @@ begin writeln(' uses console mode to determine whether color should be used.'); writeln; writeln(' -no-compiler-version Don''t embed the compiler version stores, useful for regression tests.'); - writeln(' -use-legacy-compiler Use legacy compiler (will be removed in 18.0)'); writeln; writeln(' JSON .keyboard_info compile targets:'); writeln(' -v[s] validate infile against source schema'); @@ -298,7 +291,7 @@ begin TProjectLogConsole.Create(FSilent, FFullySilent, hOutfile, FColorMode); - KCSetCompilerOptions(FParamInfile, FShouldAddCompilerVersion, FUseKmcmpLib); + KCSetCompilerOptions(FParamInfile, FShouldAddCompilerVersion); if FValidateRepoChanges then FError := not TValidateRepoChanges.Execute(FParamInfile, FParamOutfile) @@ -324,7 +317,7 @@ begin ExitCode := 1; end; -function KCSetCompilerOptions(const FInFile: string; FShouldAddCompilerVersion, FUseKmcmpLib: Boolean): Boolean; +function KCSetCompilerOptions(const FInFile: string; FShouldAddCompilerVersion: Boolean): Boolean; var opt: TCompilerOptions; begin @@ -332,7 +325,6 @@ begin opt.dwSize := sizeof(TCompilerOptions); opt.ShouldAddCompilerVersion := FShouldAddCompilerVersion; - opt.UseKmcmpLib := FUseKmcmpLib; Result := SetCompilerOptions(@opt, @CompilerMessageW); -- GitLab From f36a908d9435eb7fa19696298d04742e3d53dc6c Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 30 May 2023 13:04:39 +0700 Subject: [PATCH 153/214] chore(developer): move keyboard repo fixtures Relocates the keyboard-repo fixtures so we can add other local fixtures for unit tests. --- developer/src/kmcmplib/checkout-keyboards.inc.sh | 4 ++-- .../fixtures/{ => keyboards-repo}/adiga_danef.kmx | Bin .../fixtures/{ => keyboards-repo}/ahom_star.kmx | Bin .../{ => keyboards-repo}/aksarabali_panlex.kmx | Bin .../fixtures/{ => keyboards-repo}/alephwithbeth.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/anii.kmx | Bin .../fixtures/{ => keyboards-repo}/arabic_izza.kmx | Bin .../{ => keyboards-repo}/aramaic_hebrew.kmx | Bin .../{ => keyboards-repo}/armenian_mnemonic.kmx | Bin .../{ => keyboards-repo}/armenian_mnemonic_r.kmx | Bin .../fixtures/{ => keyboards-repo}/athinkra_vai.kmx | Bin .../athinkra_vai_typewriter.kmx | Bin .../fixtures/{ => keyboards-repo}/ausephon.kmx | Bin .../{ => keyboards-repo}/balochi_inpage.kmx | Bin .../fixtures/{ => keyboards-repo}/balochi_latin.kmx | Bin .../{ => keyboards-repo}/balochi_persian.kmx | Bin .../{ => keyboards-repo}/balochi_phonetic.kmx | Bin .../{ => keyboards-repo}/balochi_scientific.kmx | Bin .../fixtures/{ => keyboards-repo}/balochi_urdu.kmx | Bin .../fixtures/{ => keyboards-repo}/bangla_joy.kmx | Bin .../fixtures/{ => keyboards-repo}/bangla_munir.kmx | Bin .../{ => keyboards-repo}/bangla_probhat.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbda1.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbda2.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbda3.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdadlm.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdal.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdarme.kmx | Bin .../{ => keyboards-repo}/basic_kbdarmph.kmx | Bin .../{ => keyboards-repo}/basic_kbdarmty.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdarmw.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdaze.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdazel.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdazst.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdbash.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdbe.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdbene.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdbgph.kmx | Bin .../{ => keyboards-repo}/basic_kbdbgph1.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdbhc.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdblr.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdbr.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdbu.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdbug.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdbulg.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdca.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdcan.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdcher.kmx | Bin .../{ => keyboards-repo}/basic_kbdcherp.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdcr.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdcz.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdcz1.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdcz2.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdda.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbddiv1.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbddiv2.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbddv.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbddzo.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdes.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdest.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdfa.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdfar.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdfi.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdfi1.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdfo.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdfr.kmx | Bin .../{ => keyboards-repo}/basic_kbdfthrk.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdgae.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdgeo.kmx | Bin .../{ => keyboards-repo}/basic_kbdgeoer.kmx | Bin .../{ => keyboards-repo}/basic_kbdgeome.kmx | Bin .../{ => keyboards-repo}/basic_kbdgeooa.kmx | Bin .../{ => keyboards-repo}/basic_kbdgeoqw.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdgkl.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdgn.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdgr.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdgr1.kmx | Bin .../{ => keyboards-repo}/basic_kbdgrlnd.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdgthc.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdhau.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdhaw.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdhe.kmx | Bin .../{ => keyboards-repo}/basic_kbdhe220.kmx | Bin .../{ => keyboards-repo}/basic_kbdhe319.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdheb.kmx | Bin .../{ => keyboards-repo}/basic_kbdhebl3.kmx | Bin .../{ => keyboards-repo}/basic_kbdhela2.kmx | Bin .../{ => keyboards-repo}/basic_kbdhela3.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdhept.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdhu.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdhu1.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdibo.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdic.kmx | Bin .../{ => keyboards-repo}/basic_kbdinasa.kmx | Bin .../{ => keyboards-repo}/basic_kbdinbe2.kmx | Bin .../{ => keyboards-repo}/basic_kbdinben.kmx | Bin .../{ => keyboards-repo}/basic_kbdindev.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdinen.kmx | Bin .../{ => keyboards-repo}/basic_kbdinguj.kmx | Bin .../{ => keyboards-repo}/basic_kbdinhin.kmx | Bin .../{ => keyboards-repo}/basic_kbdinkan.kmx | Bin .../{ => keyboards-repo}/basic_kbdinmal.kmx | Bin .../{ => keyboards-repo}/basic_kbdinmar.kmx | Bin .../{ => keyboards-repo}/basic_kbdinori.kmx | Bin .../{ => keyboards-repo}/basic_kbdinpun.kmx | Bin .../{ => keyboards-repo}/basic_kbdintam.kmx | Bin .../{ => keyboards-repo}/basic_kbdintel.kmx | Bin .../{ => keyboards-repo}/basic_kbdinuk2.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdir.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdit.kmx | Bin .../{ => keyboards-repo}/basic_kbdit142.kmx | Bin .../{ => keyboards-repo}/basic_kbdiulat.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdjav.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdkaz.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdkhmr.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdkni.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdkurd.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdkyr.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdla.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdlao.kmx | Bin .../{ => keyboards-repo}/basic_kbdlisub.kmx | Bin .../{ => keyboards-repo}/basic_kbdlisus.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdlt.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdlt1.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdlt2.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdlv.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdlv1.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdlvst.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdmac.kmx | Bin .../{ => keyboards-repo}/basic_kbdmacst.kmx | Bin .../{ => keyboards-repo}/basic_kbdmaori.kmx | Bin .../{ => keyboards-repo}/basic_kbdmlt47.kmx | Bin .../{ => keyboards-repo}/basic_kbdmlt48.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdmon.kmx | Bin .../{ => keyboards-repo}/basic_kbdmonmo.kmx | Bin .../{ => keyboards-repo}/basic_kbdmonst.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdmyan.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdne.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdnepr.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdnko.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdno.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdno1.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdnso.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdntl.kmx | Bin .../{ => keyboards-repo}/basic_kbdogham.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdolch.kmx | Bin .../{ => keyboards-repo}/basic_kbdoldit.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdosa.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdosm.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdpash.kmx | Bin .../{ => keyboards-repo}/basic_kbdphags.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdpl.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdpl1.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdpo.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdropr.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdrost.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdru.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdru1.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdrum.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdsf.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdsg.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdsl.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdsl1.kmx | Bin .../{ => keyboards-repo}/basic_kbdsmsfi.kmx | Bin .../{ => keyboards-repo}/basic_kbdsmsno.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdsn1.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdsora.kmx | Bin .../{ => keyboards-repo}/basic_kbdsorex.kmx | Bin .../{ => keyboards-repo}/basic_kbdsors1.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdsp.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdsw.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdsw09.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdsyr1.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdsyr2.kmx | Bin .../{ => keyboards-repo}/basic_kbdtaile.kmx | Bin .../{ => keyboards-repo}/basic_kbdtajik.kmx | Bin .../{ => keyboards-repo}/basic_kbdtam99.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdth0.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdth1.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdth2.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdth3.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdtifi.kmx | Bin .../{ => keyboards-repo}/basic_kbdtifi2.kmx | Bin .../{ => keyboards-repo}/basic_kbdtiprd.kmx | Bin .../{ => keyboards-repo}/basic_kbdtt102.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdtuf.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdtuq.kmx | Bin .../{ => keyboards-repo}/basic_kbdturme.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdtzm.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdughr.kmx | Bin .../{ => keyboards-repo}/basic_kbdughr1.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbduk.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdukx.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdur.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdur1.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdurdu.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdus.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdusa.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdusl.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdusr.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdusx.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbduzb.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdvntc.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdwol.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdyak.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdyba.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdycc.kmx | Bin .../fixtures/{ => keyboards-repo}/basic_kbdycl.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/batak.kmx | Bin .../fixtures/{ => keyboards-repo}/baybayin.kmx | Bin .../{ => keyboards-repo}/bhaiksuki_inscript.kmx | Bin .../fixtures/{ => keyboards-repo}/bj_cree_east.kmx | Bin .../{ => keyboards-repo}/bj_cree_east_james_bay.kmx | Bin .../{ => keyboards-repo}/bj_cree_east_latn.kmx | Bin .../{ => keyboards-repo}/bj_cree_west_latn.kmx | Bin .../fixtures/{ => keyboards-repo}/bj_cree_woods.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/bj_innu.kmx | Bin .../{ => keyboards-repo}/bj_innu_phonemic.kmx | Bin .../{ => keyboards-repo}/bj_mista_wasaha_cree.kmx | Bin .../{ => keyboards-repo}/bj_naskapi_classic.kmx | Bin .../{ => keyboards-repo}/bj_naskapi_common.kmx | Bin .../fixtures/{ => keyboards-repo}/bj_oji_cree.kmx | Bin .../{ => keyboards-repo}/brahmi_inscript.kmx | Bin .../fixtures/{ => keyboards-repo}/btl_kenya.kmx | Bin .../fixtures/{ => keyboards-repo}/bu_phonetic.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/buhid.kmx | Bin .../{ => keyboards-repo}/burushaski_girminas.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/cabecar.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/carian.kmx | Bin .../fixtures/{ => keyboards-repo}/chalchiteko.kmx | Bin .../fixtures/{ => keyboards-repo}/chechen_latin.kmx | Bin .../fixtures/{ => keyboards-repo}/chinuk_wawa.kmx | Bin .../{ => keyboards-repo}/choctaw_modern.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/cim.kmx | Bin .../fixtures/{ => keyboards-repo}/clavbur9.kmx | Bin .../fixtures/{ => keyboards-repo}/colchis_latin.kmx | Bin .../{ => keyboards-repo}/colchis_phonetic.kmx | Bin .../{ => keyboards-repo}/common_devanagari.kmx | Bin .../fixtures/{ => keyboards-repo}/coptic_greek.kmx | Bin .../fixtures/{ => keyboards-repo}/coptic_qwerty.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/dagbani.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/dega.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/dene.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/deseret.kmx | Bin .../{ => keyboards-repo}/dogra_inscript.kmx | Bin .../fixtures/{ => keyboards-repo}/easy_chakma.kmx | Bin .../fixtures/{ => keyboards-repo}/ekwtamil99uni.kmx | Bin .../fixtures/{ => keyboards-repo}/el_dinka.kmx | Bin .../{ => keyboards-repo}/el_harari_latin.kmx | Bin .../fixtures/{ => keyboards-repo}/el_naija.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/el_nuer.kmx | Bin .../fixtures/{ => keyboards-repo}/el_pasifika.kmx | Bin .../fixtures/{ => keyboards-repo}/el_yolngu.kmx | Bin .../fixtures/{ => keyboards-repo}/embera_north.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/enga.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/enggano.kmx | Bin .../{ => keyboards-repo}/english_shavian_igc.kmx | Bin .../{ => keyboards-repo}/english_shavian_qwerty.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/engram.kmx | Bin .../fixtures/{ => keyboards-repo}/esperuni.kmx | Bin .../fixtures/{ => keyboards-repo}/farsiman.kmx | Bin .../fixtures/{ => keyboards-repo}/finongan.kmx | Bin .../{ => keyboards-repo}/fulfulde_ajami_qwerty.kmx | Bin .../{ => keyboards-repo}/fulfulde_latin_qwerty.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_dakelh.kmx | Bin .../{ => keyboards-repo}/fv_dane_zaa_zaage.kmx | Bin .../{ => keyboards-repo}/fv_denesuline_epsilon.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_diitiidatx.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_gitsenimx.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_gwichin.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_hailzaqvla.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_haisla.kmx | Bin .../{ => keyboards-repo}/fv_halqemeylem.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/fv_han.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_henqeminem.kmx | Bin .../fv_hlgaagilda_xaayda_kil.kmx | Bin .../{ => keyboards-repo}/fv_kanienkeha_e.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_ktunaxa.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_kwakwala.kmx | Bin .../{ => keyboards-repo}/fv_kwakwala_liqwala.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_migmaq.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_natwits.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_nisgaa.kmx | Bin .../{ => keyboards-repo}/fv_nlekepmxcin.kmx | Bin .../{ => keyboards-repo}/fv_northern_tutchone.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_nsilxcen.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_nuucaanul.kmx | Bin .../{ => keyboards-repo}/fv_secwepemctsin.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_sencoten.kmx | Bin .../{ => keyboards-repo}/fv_shashishalhem.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_smalgyax.kmx | Bin .../{ => keyboards-repo}/fv_southern_tutchone.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_statimcets.kmx | Bin .../{ => keyboards-repo}/fv_stlatlimxec.kmx | Bin .../{ => keyboards-repo}/fv_tagizi_dene.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_taltan.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_tlingit.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_tsekehne.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_tsilhqotin.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_uwikala.kmx | Bin .../fixtures/{ => keyboards-repo}/fv_xaislakala.kmx | Bin .../{ => keyboards-repo}/galaxie_greek_mnemonic.kmx | Bin .../galaxie_greek_positional.kmx | Bin .../galaxie_hebrew_mnemonic.kmx | Bin .../galaxie_hebrew_positional.kmx | Bin .../fixtures/{ => keyboards-repo}/gandhari.kmx | Bin .../fixtures/{ => keyboards-repo}/geezbrhan.kmx | Bin .../fixtures/{ => keyboards-repo}/gff_amh_7.kmx | Bin .../fixtures/{ => keyboards-repo}/gff_amharic.kmx | Bin .../fixtures/{ => keyboards-repo}/gff_blin.kmx | Bin .../{ => keyboards-repo}/gff_ethiopic_7.kmx | Bin .../fixtures/{ => keyboards-repo}/gff_geez.kmx | Bin .../fixtures/{ => keyboards-repo}/gff_gurage.kmx | Bin .../{ => keyboards-repo}/gff_gurage_legacy.kmx | Bin .../fixtures/{ => keyboards-repo}/gff_musnad.kmx | Bin .../{ => keyboards-repo}/gff_tigrinya_eritrea.kmx | Bin .../{ => keyboards-repo}/gff_tigrinya_ethiopia.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/ghana.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/gilaki.kmx | Bin .../{ => keyboards-repo}/gilaki_phonetic.kmx | Bin .../fixtures/{ => keyboards-repo}/gondi_dev.kmx | Bin .../fixtures/{ => keyboards-repo}/gondi_gunjala.kmx | Bin .../fixtures/{ => keyboards-repo}/gondi_tel.kmx | Bin .../{ => keyboards-repo}/greekclassical.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/hanunoo.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/haroi.kmx | Bin .../{ => keyboards-repo}/hatran_inscript.kmx | Bin .../{ => keyboards-repo}/hausa_ajami_qwerty.kmx | Bin .../fixtures/{ => keyboards-repo}/hausa_kano.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/hcesar.kmx | Bin .../fixtures/{ => keyboards-repo}/hieroglyphic.kmx | Bin .../{ => keyboards-repo}/himyarit_musnad.kmx | Bin .../fixtures/{ => keyboards-repo}/hindi_modular.kmx | Bin .../fixtures/{ => keyboards-repo}/indigenous_nt.kmx | Bin .../fixtures/{ => keyboards-repo}/indonesia.kmx | Bin .../{ => keyboards-repo}/indonesian_suku.kmx | Bin .../{ => keyboards-repo}/inuktitut_naqittaut.kmx | Bin .../{ => keyboards-repo}/ishkashimi_cyrillic.kmx | Bin .../{ => keyboards-repo}/itrans_bengali.kmx | Bin .../itrans_devanagari_hindi.kmx | Bin .../itrans_devanagari_sanskrit_vedic.kmx | Bin .../{ => keyboards-repo}/itrans_gujarati.kmx | Bin .../{ => keyboards-repo}/itrans_gurmukhi.kmx | Bin .../fixtures/{ => keyboards-repo}/itrans_odia.kmx | Bin .../fixtures/{ => keyboards-repo}/itrans_roman.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/jawa.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/jorai.kmx | Bin .../{ => keyboards-repo}/karakalpak_cyrillic.kmx | Bin .../{ => keyboards-repo}/karakalpak_latin.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/kayan.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/kbdsn1.kmx | Bin .../{ => keyboards-repo}/kharoshthi_inscript.kmx | Bin .../{ => keyboards-repo}/khmer_advanced.kmx | Bin .../fixtures/{ => keyboards-repo}/khmer_angkor.kmx | Bin .../{ => keyboards-repo}/khojki_inscript.kmx | Bin .../fixtures/{ => keyboards-repo}/kmhmu_2008.kmx | Bin .../fixtures/{ => keyboards-repo}/koalibrere.kmx | Bin .../fixtures/{ => keyboards-repo}/korean_rr.kmx | Bin .../fixtures/{ => keyboards-repo}/koreguaje.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/krung.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/lahu.kmx | Bin .../fixtures/{ => keyboards-repo}/lamkaang.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/landuma.kmx | Bin .../{ => keyboards-repo}/lao_2008_basic.kmx | Bin .../{ => keyboards-repo}/lao_2008_rapid.kmx | Bin .../fixtures/{ => keyboards-repo}/lao_pali.kmx | Bin .../fixtures/{ => keyboards-repo}/lao_pali_us.kmx | Bin .../fixtures/{ => keyboards-repo}/lao_phonetic.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/lazuri.kmx | Bin .../fixtures/{ => keyboards-repo}/libtralo.kmx | Bin .../{ => keyboards-repo}/makasar_inscript.kmx | Bin .../fixtures/{ => keyboards-repo}/malar_braille.kmx | Bin .../{ => keyboards-repo}/malar_malayalam.kmx | Bin .../malar_malayalam_inscript.kmx | Bin .../fixtures/{ => keyboards-repo}/malar_tirhuta.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/maltese.kmx | Bin .../{ => keyboards-repo}/mandaic_phonetic.kmx | Bin .../fixtures/{ => keyboards-repo}/masaram_gondi.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/me_en.kmx | Bin .../fixtures/{ => keyboards-repo}/meitei_legacy.kmx | Bin .../{ => keyboards-repo}/miluk_hanis_siuslaw.kmx | Bin .../fixtures/{ => keyboards-repo}/modi_inscript.kmx | Bin .../fixtures/{ => keyboards-repo}/mon_anonta.kmx | Bin .../fixtures/{ => keyboards-repo}/mon_phonetic.kmx | Bin .../mongolian_cyrillic_qwerty.kmx | Bin .../{ => keyboards-repo}/mozhi_malayalam.kmx | Bin .../fixtures/{ => keyboards-repo}/mro_phonetic.kmx | Bin .../{ => keyboards-repo}/multani_inscript.kmx | Bin .../{ => keyboards-repo}/multi_pak_phonetic.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/munji.kmx | Bin .../fixtures/{ => keyboards-repo}/myancode_san.kmx | Bin .../{ => keyboards-repo}/nabataean_inscript.kmx | Bin .../fixtures/{ => keyboards-repo}/naijatype.kmx | Bin .../fixtures/{ => keyboards-repo}/nailangs.kmx | Bin .../fixtures/{ => keyboards-repo}/nasa_yuwe.kmx | Bin .../{ => keyboards-repo}/nepali_traditional.kmx | Bin .../{ => keyboards-repo}/newa_romanized.kmx | Bin .../{ => keyboards-repo}/newa_traditional.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/nias.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/nisenan.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/nko.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/nkonya.kmx | Bin .../{ => keyboards-repo}/nlci_bengali_winscript.kmx | Bin .../nlci_devanagari_winscript.kmx | Bin .../nlci_gujarati_winscript.kmx | Bin .../nlci_gurmukhi_winscript.kmx | Bin .../fixtures/{ => keyboards-repo}/nlci_ipa.kmx | Bin .../{ => keyboards-repo}/nlci_kannada_winscript.kmx | Bin .../nlci_malayalam_winscript.kmx | Bin .../{ => keyboards-repo}/nlci_oriya_winscript.kmx | Bin .../{ => keyboards-repo}/nlci_tamil_winscript.kmx | Bin .../{ => keyboards-repo}/nlci_telugu_winscript.kmx | Bin .../fixtures/{ => keyboards-repo}/nrc_makah.kmx | Bin .../fixtures/{ => keyboards-repo}/ntl_onekey.kmx | Bin .../fixtures/{ => keyboards-repo}/numanggang.kmx | Bin .../{ => keyboards-repo}/nw_iranian_latin.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/o_tissi.kmx | Bin .../fixtures/{ => keyboards-repo}/obolo_chwerty.kmx | Bin .../fixtures/{ => keyboards-repo}/obolo_qwerty.kmx | Bin .../fixtures/{ => keyboards-repo}/old_hungarian.kmx | Bin .../old_turkic_udw21_qwerty.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/orma.kmx | Bin .../fixtures/{ => keyboards-repo}/osage_nation.kmx | Bin .../{ => keyboards-repo}/osage_nation_new.kmx | Bin .../{ => keyboards-repo}/otoe_missouria.kmx | Bin .../{ => keyboards-repo}/persian_phonetic.kmx | Bin .../fixtures/{ => keyboards-repo}/pid_piaroa.kmx | Bin .../fixtures/{ => keyboards-repo}/pingelap.kmx | Bin .../postmodern_english_uk_dualstroke.kmx | Bin .../postmodern_english_uk_natural.kmx | Bin .../postmodern_english_us_dualstroke.kmx | Bin .../postmodern_english_us_natural.kmx | Bin .../fixtures/{ => keyboards-repo}/pukapuka.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/qom.kmx | Bin .../fixtures/{ => keyboards-repo}/quinault.kmx | Bin .../fixtures/{ => keyboards-repo}/qwerty_farang.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/rac_aer.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_arabic.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_balti.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_brahui.kmx | Bin .../{ => keyboards-repo}/rac_brahui_latin.kmx | Bin .../{ => keyboards-repo}/rac_burushaski.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_dameli.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_dhatki.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_dogri.kmx | Bin .../{ => keyboards-repo}/rac_gawar_bati.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_gawri.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_hazaragi.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_hindko.kmx | Bin .../{ => keyboards-repo}/rac_indus_kohistani.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_kalasha.kmx | Bin .../{ => keyboards-repo}/rac_kashmir_shina.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_kashmiri.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_khowar.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_marwari.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_munji.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_oadki.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_ormuri.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_pahari.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_palula.kmx | Bin .../{ => keyboards-repo}/rac_parkari_koli.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_pashai.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_pashto.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_saraiki.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_shina.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_sindhi.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_torwali.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_urdu.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_ushojo.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_uyghur.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_wadiyara.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_wakhi.kmx | Bin .../{ => keyboards-repo}/rac_western_punjabi.kmx | Bin .../fixtures/{ => keyboards-repo}/rac_yidgha.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/rawang.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/rejang.kmx | Bin .../{ => keyboards-repo}/remington_gail.kmx | Bin .../fixtures/{ => keyboards-repo}/rohingya_arab.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/rossel.kmx | Bin .../fixtures/{ => keyboards-repo}/runeboard.kmx | Bin .../{ => keyboards-repo}/russian_mnemonic_r.kmx | Bin .../{ => keyboards-repo}/sabdalipi_assamese.kmx | Bin .../{ => keyboards-repo}/sahaptin_umatilla.kmx | Bin .../{ => keyboards-repo}/sahaptin_yakima.kmx | Bin .../{ => keyboards-repo}/sanjha_punjabi.kmx | Bin .../fixtures/{ => keyboards-repo}/santali_latin.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/saraiki.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/satere.kmx | Bin .../{ => keyboards-repo}/shahmukhi_phonetic.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/shan.kmx | Bin .../fixtures/{ => keyboards-repo}/shaw_2layer.kmx | Bin .../{ => keyboards-repo}/siddham_inscript.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_akha_act.kmx | Bin .../{ => keyboards-repo}/sil_arabic_phonetic.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_areare.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_bari.kmx | Bin .../{ => keyboards-repo}/sil_bengali_phonetic.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_bolivia.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_boonkit.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_brao.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/sil_bru.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_buang.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_bunong.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_busa.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_bwe_karen.kmx | Bin .../{ => keyboards-repo}/sil_cameroon_azerty.kmx | Bin .../{ => keyboards-repo}/sil_cameroon_qwerty.kmx | Bin .../{ => keyboards-repo}/sil_cherokee_nation.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_cheyenne.kmx | Bin .../{ => keyboards-repo}/sil_cipher_music.kmx | Bin .../sil_devanagari_phonetic.kmx | Bin .../sil_devanagari_romanized.kmx | Bin .../sil_devanagari_typewriter.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_dzongkha.kmx | Bin .../{ => keyboards-repo}/sil_eastern_congo.kmx | Bin .../{ => keyboards-repo}/sil_el_ethiopian_latin.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_ethiopic.kmx | Bin .../{ => keyboards-repo}/sil_ethiopic_power_g.kmx | Bin .../{ => keyboards-repo}/sil_euro_latin.kmx | Bin .../{ => keyboards-repo}/sil_extended_urdu_np.kmx | Bin .../{ => keyboards-repo}/sil_greek_polytonic.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_hawaiian.kmx | Bin .../{ => keyboards-repo}/sil_hebr_grek_trans.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_hebrew.kmx | Bin .../{ => keyboards-repo}/sil_hebrew_legacy.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_hmd_plrd.kmx | Bin .../{ => keyboards-repo}/sil_indic_roman.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/sil_ipa.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_jarai.kmx | Bin .../{ => keyboards-repo}/sil_kayah_kali.kmx | Bin .../{ => keyboards-repo}/sil_kayah_latn.kmx | Bin .../{ => keyboards-repo}/sil_kayah_mymr.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_khamti.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_khmer.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_khowar.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_kmhmu.kmx | Bin .../{ => keyboards-repo}/sil_korda_jamo.kmx | Bin .../{ => keyboards-repo}/sil_korda_latin.kmx | Bin .../{ => keyboards-repo}/sil_korean_morse.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_kvl_kayaw.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_lepcha.kmx | Bin .../{ => keyboards-repo}/sil_limbu_phonetic.kmx | Bin .../{ => keyboards-repo}/sil_limbu_typewriter.kmx | Bin .../{ => keyboards-repo}/sil_lisu_basic.kmx | Bin .../{ => keyboards-repo}/sil_lisu_standard.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_lpo_plrd.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_madi.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_makuri.kmx | Bin .../{ => keyboards-repo}/sil_mali_azerty.kmx | Bin .../{ => keyboards-repo}/sil_mali_qwerty.kmx | Bin .../{ => keyboards-repo}/sil_mali_qwertz.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_moore.kmx | Bin .../{ => keyboards-repo}/sil_myanmar_my3.kmx | Bin .../{ => keyboards-repo}/sil_myanmar_mywinext.kmx | Bin .../{ => keyboards-repo}/sil_nigeria_dot.kmx | Bin .../{ => keyboards-repo}/sil_nigeria_odd_vowels.kmx | Bin .../{ => keyboards-repo}/sil_nigeria_underline.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/sil_nko.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_nubian.kmx | Bin .../sil_pan_africa_mnemonic.kmx | Bin .../sil_pan_africa_positional.kmx | Bin .../{ => keyboards-repo}/sil_philippines.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_sahu.kmx | Bin .../{ => keyboards-repo}/sil_senegal_bsc_azerty.kmx | Bin .../{ => keyboards-repo}/sil_senegal_cou_azerty.kmx | Bin .../{ => keyboards-repo}/sil_senegal_dyo_azerty.kmx | Bin .../{ => keyboards-repo}/sil_senegal_gsl_azerty.kmx | Bin .../{ => keyboards-repo}/sil_senegal_krx_azerty.kmx | Bin .../{ => keyboards-repo}/sil_senegal_ndv_azerty.kmx | Bin .../{ => keyboards-repo}/sil_senegal_sav_azerty.kmx | Bin .../{ => keyboards-repo}/sil_senegal_snf_azerty.kmx | Bin .../{ => keyboards-repo}/sil_senegal_srr_azerty.kmx | Bin .../{ => keyboards-repo}/sil_senegal_wo_azerty.kmx | Bin .../{ => keyboards-repo}/sil_sgaw_karen.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_shan.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_tai_dam.kmx | Bin .../{ => keyboards-repo}/sil_tai_dam_lao.kmx | Bin .../{ => keyboards-repo}/sil_tai_dam_latin.kmx | Bin .../{ => keyboards-repo}/sil_tai_dam_typewriter.kmx | Bin .../{ => keyboards-repo}/sil_tawallammat.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_tchad.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_tepehuan.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_torwali.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_tunisian.kmx | Bin .../{ => keyboards-repo}/sil_uganda_tanzania.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/sil_vai.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_wayuu.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_ygp_plrd.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/sil_yi.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_yna_plrd.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_yoruba8.kmx | Bin .../{ => keyboards-repo}/sil_yoruba_bar.kmx | Bin .../{ => keyboards-repo}/sil_yoruba_dot.kmx | Bin .../{ => keyboards-repo}/sil_yupik_cyrillic.kmx | Bin .../{ => keyboards-repo}/sil_yupik_cyrillic_ru.kmx | Bin .../fixtures/{ => keyboards-repo}/sil_ywq_plrd.kmx | Bin .../fixtures/{ => keyboards-repo}/slc_saliba.kmx | Bin .../{ => keyboards-repo}/soqotri_arabic.kmx | Bin .../{ => keyboards-repo}/srr_ajami_qwerty.kmx | Bin .../fixtures/{ => keyboards-repo}/sundanese.kmx | Bin .../{ => keyboards-repo}/sundanese_latin.kmx | Bin .../{ => keyboards-repo}/swanalekha_malayalam.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/sxava.kmx | Bin .../fixtures/{ => keyboards-repo}/sxava_eo.kmx | Bin .../fixtures/{ => keyboards-repo}/sylheti_nagri.kmx | Bin .../fixtures/{ => keyboards-repo}/syriac_arabic.kmx | Bin .../{ => keyboards-repo}/syriac_phonetic.kmx | Bin .../{ => keyboards-repo}/tagbanwa_inscript.kmx | Bin .../fixtures/{ => keyboards-repo}/taigi_poj.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/tainua.kmx | Bin .../fixtures/{ => keyboards-repo}/tangsa_lakhum.kmx | Bin .../{ => keyboards-repo}/tawallammat_latin.kmx | Bin .../{ => keyboards-repo}/teggargrent_lat.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/tem_kdh.kmx | Bin .../{ => keyboards-repo}/thamizha_anjal_paangu.kmx | Bin .../{ => keyboards-repo}/thamizha_bamini.kmx | Bin .../thamizha_new_typewriter.kmx | Bin .../{ => keyboards-repo}/thamizha_tamil99_ext.kmx | Bin .../{ => keyboards-repo}/tibetan_direct_input.kmx | Bin .../fixtures/{ => keyboards-repo}/tibetan_ewts.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/tirhuta.kmx | Bin .../fixtures/{ => keyboards-repo}/tlahuica.kmx | Bin .../fixtures/{ => keyboards-repo}/tsakonian.kmx | Bin .../{ => keyboards-repo}/tuareg_tifinagh.kmx | Bin .../fixtures/{ => keyboards-repo}/turkmen_cyrl.kmx | Bin .../fixtures/{ => keyboards-repo}/txo_toto.kmx | Bin .../fixtures/{ => keyboards-repo}/udi_keyboard.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/ukwuani.kmx | Bin .../fixtures/{ => keyboards-repo}/uma_graphic.kmx | Bin .../fixtures/{ => keyboards-repo}/uma_phonetic.kmx | Bin .../fixtures/{ => keyboards-repo}/urdu_phonetic.kmx | Bin .../{ => keyboards-repo}/urdu_phonetic_crulp.kmx | Bin .../{ => keyboards-repo}/venetia_et_histria.kmx | Bin .../{ => keyboards-repo}/vm_tamil_modular.kmx | Bin .../{ => keyboards-repo}/vm_tamil_typewriter.kmx | Bin .../{ => keyboards-repo}/wakhi_anglicized.kmx | Bin .../{ => keyboards-repo}/wakhi_cyrillic.kmx | Bin .../{ => keyboards-repo}/wakhi_standard.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/wancho.kmx | Bin .../fixtures/{ => keyboards-repo}/warang_citi.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/wolofal.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/xinaliq.kmx | Bin .../{ => keyboards-repo}/yiddish_pasekh.kmx | Bin .../tests/fixtures/{ => keyboards-repo}/yidgha.kmx | Bin .../younger_futhark_short_twig.kmx | Bin developer/src/kmcmplib/tests/meson.build | 2 +- developer/src/kmcmplib/tests/prep.sh | 12 ++++++------ 647 files changed, 9 insertions(+), 9 deletions(-) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/adiga_danef.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/ahom_star.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/aksarabali_panlex.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/alephwithbeth.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/anii.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/arabic_izza.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/aramaic_hebrew.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/armenian_mnemonic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/armenian_mnemonic_r.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/athinkra_vai.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/athinkra_vai_typewriter.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/ausephon.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/balochi_inpage.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/balochi_latin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/balochi_persian.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/balochi_phonetic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/balochi_scientific.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/balochi_urdu.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/bangla_joy.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/bangla_munir.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/bangla_probhat.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbda1.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbda2.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbda3.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdadlm.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdal.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdarme.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdarmph.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdarmty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdarmw.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdaze.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdazel.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdazst.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdbash.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdbe.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdbene.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdbgph.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdbgph1.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdbhc.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdblr.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdbr.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdbu.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdbug.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdbulg.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdca.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdcan.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdcher.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdcherp.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdcr.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdcz.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdcz1.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdcz2.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdda.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbddiv1.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbddiv2.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbddv.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbddzo.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdes.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdest.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdfa.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdfar.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdfi.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdfi1.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdfo.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdfr.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdfthrk.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdgae.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdgeo.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdgeoer.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdgeome.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdgeooa.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdgeoqw.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdgkl.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdgn.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdgr.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdgr1.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdgrlnd.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdgthc.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdhau.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdhaw.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdhe.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdhe220.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdhe319.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdheb.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdhebl3.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdhela2.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdhela3.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdhept.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdhu.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdhu1.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdibo.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdinasa.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdinbe2.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdinben.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdindev.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdinen.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdinguj.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdinhin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdinkan.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdinmal.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdinmar.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdinori.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdinpun.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdintam.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdintel.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdinuk2.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdir.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdit.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdit142.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdiulat.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdjav.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdkaz.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdkhmr.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdkni.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdkurd.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdkyr.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdla.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdlao.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdlisub.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdlisus.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdlt.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdlt1.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdlt2.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdlv.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdlv1.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdlvst.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdmac.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdmacst.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdmaori.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdmlt47.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdmlt48.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdmon.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdmonmo.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdmonst.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdmyan.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdne.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdnepr.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdnko.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdno.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdno1.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdnso.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdntl.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdogham.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdolch.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdoldit.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdosa.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdosm.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdpash.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdphags.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdpl.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdpl1.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdpo.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdropr.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdrost.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdru.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdru1.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdrum.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdsf.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdsg.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdsl.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdsl1.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdsmsfi.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdsmsno.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdsn1.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdsora.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdsorex.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdsors1.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdsp.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdsw.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdsw09.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdsyr1.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdsyr2.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdtaile.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdtajik.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdtam99.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdth0.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdth1.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdth2.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdth3.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdtifi.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdtifi2.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdtiprd.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdtt102.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdtuf.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdtuq.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdturme.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdtzm.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdughr.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdughr1.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbduk.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdukx.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdur.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdur1.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdurdu.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdus.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdusa.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdusl.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdusr.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdusx.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbduzb.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdvntc.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdwol.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdyak.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdyba.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdycc.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/basic_kbdycl.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/batak.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/baybayin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/bhaiksuki_inscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/bj_cree_east.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/bj_cree_east_james_bay.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/bj_cree_east_latn.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/bj_cree_west_latn.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/bj_cree_woods.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/bj_innu.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/bj_innu_phonemic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/bj_mista_wasaha_cree.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/bj_naskapi_classic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/bj_naskapi_common.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/bj_oji_cree.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/brahmi_inscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/btl_kenya.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/bu_phonetic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/buhid.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/burushaski_girminas.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/cabecar.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/carian.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/chalchiteko.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/chechen_latin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/chinuk_wawa.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/choctaw_modern.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/cim.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/clavbur9.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/colchis_latin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/colchis_phonetic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/common_devanagari.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/coptic_greek.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/coptic_qwerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/dagbani.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/dega.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/dene.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/deseret.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/dogra_inscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/easy_chakma.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/ekwtamil99uni.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/el_dinka.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/el_harari_latin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/el_naija.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/el_nuer.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/el_pasifika.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/el_yolngu.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/embera_north.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/enga.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/enggano.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/english_shavian_igc.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/english_shavian_qwerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/engram.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/esperuni.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/farsiman.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/finongan.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fulfulde_ajami_qwerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fulfulde_latin_qwerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_dakelh.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_dane_zaa_zaage.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_denesuline_epsilon.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_diitiidatx.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_gitsenimx.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_gwichin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_hailzaqvla.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_haisla.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_halqemeylem.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_han.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_henqeminem.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_hlgaagilda_xaayda_kil.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_kanienkeha_e.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_ktunaxa.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_kwakwala.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_kwakwala_liqwala.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_migmaq.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_natwits.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_nisgaa.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_nlekepmxcin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_northern_tutchone.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_nsilxcen.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_nuucaanul.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_secwepemctsin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_sencoten.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_shashishalhem.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_smalgyax.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_southern_tutchone.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_statimcets.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_stlatlimxec.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_tagizi_dene.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_taltan.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_tlingit.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_tsekehne.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_tsilhqotin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_uwikala.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/fv_xaislakala.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/galaxie_greek_mnemonic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/galaxie_greek_positional.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/galaxie_hebrew_mnemonic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/galaxie_hebrew_positional.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/gandhari.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/geezbrhan.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/gff_amh_7.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/gff_amharic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/gff_blin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/gff_ethiopic_7.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/gff_geez.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/gff_gurage.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/gff_gurage_legacy.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/gff_musnad.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/gff_tigrinya_eritrea.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/gff_tigrinya_ethiopia.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/ghana.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/gilaki.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/gilaki_phonetic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/gondi_dev.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/gondi_gunjala.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/gondi_tel.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/greekclassical.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/hanunoo.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/haroi.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/hatran_inscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/hausa_ajami_qwerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/hausa_kano.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/hcesar.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/hieroglyphic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/himyarit_musnad.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/hindi_modular.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/indigenous_nt.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/indonesia.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/indonesian_suku.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/inuktitut_naqittaut.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/ishkashimi_cyrillic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/itrans_bengali.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/itrans_devanagari_hindi.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/itrans_devanagari_sanskrit_vedic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/itrans_gujarati.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/itrans_gurmukhi.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/itrans_odia.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/itrans_roman.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/jawa.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/jorai.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/karakalpak_cyrillic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/karakalpak_latin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/kayan.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/kbdsn1.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/kharoshthi_inscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/khmer_advanced.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/khmer_angkor.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/khojki_inscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/kmhmu_2008.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/koalibrere.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/korean_rr.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/koreguaje.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/krung.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/lahu.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/lamkaang.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/landuma.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/lao_2008_basic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/lao_2008_rapid.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/lao_pali.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/lao_pali_us.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/lao_phonetic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/lazuri.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/libtralo.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/makasar_inscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/malar_braille.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/malar_malayalam.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/malar_malayalam_inscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/malar_tirhuta.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/maltese.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/mandaic_phonetic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/masaram_gondi.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/me_en.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/meitei_legacy.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/miluk_hanis_siuslaw.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/modi_inscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/mon_anonta.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/mon_phonetic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/mongolian_cyrillic_qwerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/mozhi_malayalam.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/mro_phonetic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/multani_inscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/multi_pak_phonetic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/munji.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/myancode_san.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/nabataean_inscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/naijatype.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/nailangs.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/nasa_yuwe.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/nepali_traditional.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/newa_romanized.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/newa_traditional.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/nias.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/nisenan.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/nko.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/nkonya.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/nlci_bengali_winscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/nlci_devanagari_winscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/nlci_gujarati_winscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/nlci_gurmukhi_winscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/nlci_ipa.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/nlci_kannada_winscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/nlci_malayalam_winscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/nlci_oriya_winscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/nlci_tamil_winscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/nlci_telugu_winscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/nrc_makah.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/ntl_onekey.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/numanggang.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/nw_iranian_latin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/o_tissi.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/obolo_chwerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/obolo_qwerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/old_hungarian.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/old_turkic_udw21_qwerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/orma.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/osage_nation.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/osage_nation_new.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/otoe_missouria.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/persian_phonetic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/pid_piaroa.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/pingelap.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/postmodern_english_uk_dualstroke.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/postmodern_english_uk_natural.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/postmodern_english_us_dualstroke.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/postmodern_english_us_natural.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/pukapuka.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/qom.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/quinault.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/qwerty_farang.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_aer.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_arabic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_balti.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_brahui.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_brahui_latin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_burushaski.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_dameli.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_dhatki.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_dogri.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_gawar_bati.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_gawri.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_hazaragi.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_hindko.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_indus_kohistani.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_kalasha.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_kashmir_shina.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_kashmiri.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_khowar.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_marwari.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_munji.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_oadki.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_ormuri.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_pahari.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_palula.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_parkari_koli.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_pashai.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_pashto.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_saraiki.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_shina.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_sindhi.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_torwali.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_urdu.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_ushojo.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_uyghur.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_wadiyara.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_wakhi.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_western_punjabi.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rac_yidgha.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rawang.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rejang.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/remington_gail.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rohingya_arab.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/rossel.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/runeboard.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/russian_mnemonic_r.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sabdalipi_assamese.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sahaptin_umatilla.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sahaptin_yakima.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sanjha_punjabi.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/santali_latin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/saraiki.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/satere.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/shahmukhi_phonetic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/shan.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/shaw_2layer.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/siddham_inscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_akha_act.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_arabic_phonetic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_areare.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_bari.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_bengali_phonetic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_bolivia.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_boonkit.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_brao.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_bru.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_buang.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_bunong.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_busa.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_bwe_karen.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_cameroon_azerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_cameroon_qwerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_cherokee_nation.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_cheyenne.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_cipher_music.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_devanagari_phonetic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_devanagari_romanized.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_devanagari_typewriter.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_dzongkha.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_eastern_congo.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_el_ethiopian_latin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_ethiopic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_ethiopic_power_g.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_euro_latin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_extended_urdu_np.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_greek_polytonic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_hawaiian.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_hebr_grek_trans.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_hebrew.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_hebrew_legacy.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_hmd_plrd.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_indic_roman.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_ipa.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_jarai.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_kayah_kali.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_kayah_latn.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_kayah_mymr.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_khamti.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_khmer.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_khowar.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_kmhmu.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_korda_jamo.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_korda_latin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_korean_morse.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_kvl_kayaw.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_lepcha.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_limbu_phonetic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_limbu_typewriter.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_lisu_basic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_lisu_standard.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_lpo_plrd.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_madi.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_makuri.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_mali_azerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_mali_qwerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_mali_qwertz.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_moore.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_myanmar_my3.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_myanmar_mywinext.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_nigeria_dot.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_nigeria_odd_vowels.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_nigeria_underline.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_nko.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_nubian.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_pan_africa_mnemonic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_pan_africa_positional.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_philippines.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_sahu.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_senegal_bsc_azerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_senegal_cou_azerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_senegal_dyo_azerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_senegal_gsl_azerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_senegal_krx_azerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_senegal_ndv_azerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_senegal_sav_azerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_senegal_snf_azerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_senegal_srr_azerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_senegal_wo_azerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_sgaw_karen.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_shan.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_tai_dam.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_tai_dam_lao.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_tai_dam_latin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_tai_dam_typewriter.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_tawallammat.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_tchad.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_tepehuan.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_torwali.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_tunisian.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_uganda_tanzania.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_vai.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_wayuu.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_ygp_plrd.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_yi.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_yna_plrd.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_yoruba8.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_yoruba_bar.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_yoruba_dot.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_yupik_cyrillic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_yupik_cyrillic_ru.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sil_ywq_plrd.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/slc_saliba.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/soqotri_arabic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/srr_ajami_qwerty.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sundanese.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sundanese_latin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/swanalekha_malayalam.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sxava.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sxava_eo.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/sylheti_nagri.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/syriac_arabic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/syriac_phonetic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/tagbanwa_inscript.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/taigi_poj.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/tainua.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/tangsa_lakhum.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/tawallammat_latin.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/teggargrent_lat.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/tem_kdh.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/thamizha_anjal_paangu.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/thamizha_bamini.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/thamizha_new_typewriter.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/thamizha_tamil99_ext.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/tibetan_direct_input.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/tibetan_ewts.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/tirhuta.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/tlahuica.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/tsakonian.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/tuareg_tifinagh.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/turkmen_cyrl.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/txo_toto.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/udi_keyboard.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/ukwuani.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/uma_graphic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/uma_phonetic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/urdu_phonetic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/urdu_phonetic_crulp.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/venetia_et_histria.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/vm_tamil_modular.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/vm_tamil_typewriter.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/wakhi_anglicized.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/wakhi_cyrillic.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/wakhi_standard.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/wancho.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/warang_citi.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/wolofal.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/xinaliq.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/yiddish_pasekh.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/yidgha.kmx (100%) rename developer/src/kmcmplib/tests/fixtures/{ => keyboards-repo}/younger_futhark_short_twig.kmx (100%) diff --git a/developer/src/kmcmplib/checkout-keyboards.inc.sh b/developer/src/kmcmplib/checkout-keyboards.inc.sh index defcb479ef..6c76d53caa 100644 --- a/developer/src/kmcmplib/checkout-keyboards.inc.sh +++ b/developer/src/kmcmplib/checkout-keyboards.inc.sh @@ -9,8 +9,8 @@ function locate_keyboards_repo() { builder_die "keyboards_commit_ref.txt does not exist, run prep.sh" fi - if [[ ! -d "$THIS_SCRIPT_PATH/tests/fixtures" ]]; then - builder_die "fixtures folder does not exist, run prep.sh" + if [[ ! -d "$THIS_SCRIPT_PATH/tests/fixtures/keyboards-repo" ]]; then + builder_die "fixtures/keyboards-repo folder does not exist, run prep.sh" fi if [[ -z "${KEYBOARDS_ROOT+x}" ]]; then diff --git a/developer/src/kmcmplib/tests/fixtures/adiga_danef.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/adiga_danef.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/adiga_danef.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/adiga_danef.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/ahom_star.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/ahom_star.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/ahom_star.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/ahom_star.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/aksarabali_panlex.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/aksarabali_panlex.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/aksarabali_panlex.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/aksarabali_panlex.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/alephwithbeth.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/alephwithbeth.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/alephwithbeth.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/alephwithbeth.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/anii.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/anii.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/anii.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/anii.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/arabic_izza.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/arabic_izza.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/arabic_izza.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/arabic_izza.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/aramaic_hebrew.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/aramaic_hebrew.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/aramaic_hebrew.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/aramaic_hebrew.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/armenian_mnemonic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/armenian_mnemonic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/armenian_mnemonic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/armenian_mnemonic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/armenian_mnemonic_r.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/armenian_mnemonic_r.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/armenian_mnemonic_r.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/armenian_mnemonic_r.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/athinkra_vai.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/athinkra_vai.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/athinkra_vai.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/athinkra_vai.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/athinkra_vai_typewriter.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/athinkra_vai_typewriter.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/athinkra_vai_typewriter.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/athinkra_vai_typewriter.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/ausephon.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/ausephon.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/ausephon.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/ausephon.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/balochi_inpage.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/balochi_inpage.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/balochi_inpage.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/balochi_inpage.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/balochi_latin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/balochi_latin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/balochi_latin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/balochi_latin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/balochi_persian.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/balochi_persian.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/balochi_persian.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/balochi_persian.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/balochi_phonetic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/balochi_phonetic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/balochi_phonetic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/balochi_phonetic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/balochi_scientific.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/balochi_scientific.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/balochi_scientific.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/balochi_scientific.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/balochi_urdu.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/balochi_urdu.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/balochi_urdu.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/balochi_urdu.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/bangla_joy.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/bangla_joy.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/bangla_joy.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/bangla_joy.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/bangla_munir.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/bangla_munir.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/bangla_munir.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/bangla_munir.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/bangla_probhat.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/bangla_probhat.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/bangla_probhat.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/bangla_probhat.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbda1.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbda1.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbda1.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbda1.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbda2.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbda2.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbda2.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbda2.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbda3.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbda3.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbda3.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbda3.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdadlm.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdadlm.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdadlm.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdadlm.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdal.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdal.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdal.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdal.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdarme.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdarme.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdarme.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdarme.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdarmph.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdarmph.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdarmph.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdarmph.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdarmty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdarmty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdarmty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdarmty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdarmw.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdarmw.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdarmw.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdarmw.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdaze.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdaze.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdaze.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdaze.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdazel.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdazel.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdazel.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdazel.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdazst.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdazst.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdazst.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdazst.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdbash.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdbash.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdbash.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdbash.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdbe.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdbe.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdbe.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdbe.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdbene.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdbene.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdbene.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdbene.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdbgph.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdbgph.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdbgph.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdbgph.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdbgph1.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdbgph1.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdbgph1.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdbgph1.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdbhc.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdbhc.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdbhc.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdbhc.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdblr.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdblr.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdblr.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdblr.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdbr.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdbr.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdbr.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdbr.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdbu.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdbu.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdbu.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdbu.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdbug.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdbug.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdbug.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdbug.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdbulg.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdbulg.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdbulg.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdbulg.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdca.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdca.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdca.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdca.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdcan.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdcan.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdcan.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdcan.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdcher.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdcher.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdcher.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdcher.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdcherp.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdcherp.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdcherp.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdcherp.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdcr.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdcr.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdcr.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdcr.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdcz.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdcz.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdcz.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdcz.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdcz1.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdcz1.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdcz1.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdcz1.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdcz2.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdcz2.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdcz2.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdcz2.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdda.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdda.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdda.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdda.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbddiv1.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbddiv1.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbddiv1.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbddiv1.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbddiv2.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbddiv2.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbddiv2.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbddiv2.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbddv.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbddv.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbddv.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbddv.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbddzo.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbddzo.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbddzo.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbddzo.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdes.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdes.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdes.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdes.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdest.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdest.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdest.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdest.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdfa.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdfa.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdfa.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdfa.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdfar.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdfar.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdfar.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdfar.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdfi.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdfi.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdfi.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdfi.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdfi1.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdfi1.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdfi1.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdfi1.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdfo.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdfo.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdfo.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdfo.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdfr.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdfr.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdfr.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdfr.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdfthrk.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdfthrk.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdfthrk.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdfthrk.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdgae.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgae.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdgae.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgae.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdgeo.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgeo.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdgeo.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgeo.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdgeoer.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgeoer.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdgeoer.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgeoer.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdgeome.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgeome.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdgeome.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgeome.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdgeooa.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgeooa.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdgeooa.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgeooa.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdgeoqw.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgeoqw.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdgeoqw.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgeoqw.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdgkl.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgkl.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdgkl.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgkl.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdgn.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgn.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdgn.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgn.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdgr.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgr.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdgr.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgr.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdgr1.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgr1.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdgr1.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgr1.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdgrlnd.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgrlnd.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdgrlnd.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgrlnd.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdgthc.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgthc.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdgthc.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdgthc.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdhau.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhau.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdhau.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhau.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdhaw.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhaw.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdhaw.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhaw.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdhe.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhe.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdhe.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhe.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdhe220.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhe220.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdhe220.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhe220.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdhe319.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhe319.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdhe319.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhe319.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdheb.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdheb.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdheb.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdheb.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdhebl3.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhebl3.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdhebl3.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhebl3.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdhela2.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhela2.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdhela2.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhela2.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdhela3.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhela3.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdhela3.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhela3.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdhept.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhept.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdhept.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhept.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdhu.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhu.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdhu.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhu.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdhu1.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhu1.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdhu1.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdhu1.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdibo.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdibo.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdibo.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdibo.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdinasa.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinasa.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdinasa.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinasa.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdinbe2.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinbe2.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdinbe2.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinbe2.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdinben.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinben.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdinben.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinben.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdindev.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdindev.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdindev.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdindev.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdinen.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinen.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdinen.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinen.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdinguj.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinguj.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdinguj.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinguj.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdinhin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinhin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdinhin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinhin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdinkan.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinkan.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdinkan.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinkan.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdinmal.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinmal.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdinmal.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinmal.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdinmar.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinmar.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdinmar.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinmar.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdinori.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinori.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdinori.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinori.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdinpun.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinpun.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdinpun.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinpun.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdintam.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdintam.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdintam.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdintam.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdintel.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdintel.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdintel.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdintel.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdinuk2.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinuk2.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdinuk2.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdinuk2.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdir.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdir.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdir.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdir.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdit.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdit.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdit.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdit.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdit142.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdit142.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdit142.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdit142.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdiulat.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdiulat.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdiulat.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdiulat.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdjav.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdjav.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdjav.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdjav.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdkaz.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdkaz.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdkaz.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdkaz.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdkhmr.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdkhmr.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdkhmr.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdkhmr.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdkni.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdkni.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdkni.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdkni.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdkurd.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdkurd.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdkurd.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdkurd.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdkyr.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdkyr.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdkyr.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdkyr.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdla.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdla.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdla.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdla.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdlao.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdlao.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdlao.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdlao.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdlisub.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdlisub.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdlisub.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdlisub.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdlisus.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdlisus.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdlisus.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdlisus.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdlt.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdlt.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdlt.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdlt.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdlt1.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdlt1.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdlt1.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdlt1.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdlt2.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdlt2.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdlt2.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdlt2.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdlv.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdlv.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdlv.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdlv.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdlv1.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdlv1.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdlv1.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdlv1.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdlvst.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdlvst.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdlvst.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdlvst.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdmac.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdmac.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdmac.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdmac.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdmacst.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdmacst.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdmacst.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdmacst.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdmaori.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdmaori.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdmaori.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdmaori.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdmlt47.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdmlt47.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdmlt47.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdmlt47.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdmlt48.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdmlt48.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdmlt48.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdmlt48.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdmon.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdmon.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdmon.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdmon.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdmonmo.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdmonmo.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdmonmo.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdmonmo.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdmonst.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdmonst.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdmonst.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdmonst.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdmyan.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdmyan.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdmyan.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdmyan.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdne.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdne.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdne.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdne.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdnepr.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdnepr.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdnepr.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdnepr.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdnko.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdnko.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdnko.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdnko.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdno.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdno.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdno.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdno.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdno1.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdno1.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdno1.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdno1.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdnso.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdnso.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdnso.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdnso.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdntl.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdntl.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdntl.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdntl.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdogham.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdogham.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdogham.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdogham.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdolch.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdolch.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdolch.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdolch.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdoldit.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdoldit.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdoldit.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdoldit.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdosa.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdosa.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdosa.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdosa.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdosm.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdosm.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdosm.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdosm.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdpash.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdpash.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdpash.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdpash.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdphags.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdphags.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdphags.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdphags.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdpl.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdpl.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdpl.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdpl.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdpl1.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdpl1.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdpl1.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdpl1.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdpo.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdpo.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdpo.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdpo.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdropr.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdropr.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdropr.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdropr.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdrost.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdrost.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdrost.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdrost.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdru.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdru.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdru.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdru.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdru1.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdru1.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdru1.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdru1.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdrum.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdrum.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdrum.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdrum.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdsf.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsf.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdsf.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsf.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdsg.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsg.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdsg.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsg.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdsl.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsl.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdsl.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsl.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdsl1.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsl1.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdsl1.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsl1.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdsmsfi.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsmsfi.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdsmsfi.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsmsfi.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdsmsno.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsmsno.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdsmsno.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsmsno.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdsn1.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsn1.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdsn1.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsn1.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdsora.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsora.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdsora.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsora.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdsorex.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsorex.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdsorex.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsorex.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdsors1.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsors1.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdsors1.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsors1.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdsp.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsp.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdsp.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsp.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdsw.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsw.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdsw.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsw.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdsw09.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsw09.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdsw09.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsw09.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdsyr1.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsyr1.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdsyr1.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsyr1.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdsyr2.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsyr2.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdsyr2.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdsyr2.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdtaile.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdtaile.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdtaile.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdtaile.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdtajik.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdtajik.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdtajik.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdtajik.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdtam99.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdtam99.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdtam99.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdtam99.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdth0.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdth0.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdth0.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdth0.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdth1.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdth1.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdth1.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdth1.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdth2.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdth2.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdth2.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdth2.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdth3.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdth3.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdth3.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdth3.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdtifi.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdtifi.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdtifi.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdtifi.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdtifi2.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdtifi2.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdtifi2.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdtifi2.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdtiprd.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdtiprd.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdtiprd.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdtiprd.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdtt102.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdtt102.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdtt102.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdtt102.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdtuf.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdtuf.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdtuf.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdtuf.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdtuq.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdtuq.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdtuq.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdtuq.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdturme.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdturme.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdturme.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdturme.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdtzm.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdtzm.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdtzm.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdtzm.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdughr.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdughr.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdughr.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdughr.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdughr1.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdughr1.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdughr1.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdughr1.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbduk.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbduk.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbduk.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbduk.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdukx.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdukx.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdukx.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdukx.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdur.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdur.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdur.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdur.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdur1.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdur1.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdur1.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdur1.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdurdu.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdurdu.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdurdu.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdurdu.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdus.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdus.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdus.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdus.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdusa.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdusa.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdusa.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdusa.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdusl.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdusl.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdusl.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdusl.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdusr.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdusr.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdusr.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdusr.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdusx.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdusx.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdusx.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdusx.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbduzb.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbduzb.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbduzb.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbduzb.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdvntc.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdvntc.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdvntc.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdvntc.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdwol.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdwol.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdwol.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdwol.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdyak.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdyak.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdyak.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdyak.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdyba.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdyba.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdyba.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdyba.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdycc.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdycc.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdycc.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdycc.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/basic_kbdycl.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdycl.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/basic_kbdycl.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/basic_kbdycl.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/batak.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/batak.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/batak.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/batak.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/baybayin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/baybayin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/baybayin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/baybayin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/bhaiksuki_inscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/bhaiksuki_inscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/bhaiksuki_inscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/bhaiksuki_inscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/bj_cree_east.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_cree_east.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/bj_cree_east.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_cree_east.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/bj_cree_east_james_bay.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_cree_east_james_bay.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/bj_cree_east_james_bay.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_cree_east_james_bay.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/bj_cree_east_latn.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_cree_east_latn.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/bj_cree_east_latn.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_cree_east_latn.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/bj_cree_west_latn.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_cree_west_latn.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/bj_cree_west_latn.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_cree_west_latn.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/bj_cree_woods.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_cree_woods.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/bj_cree_woods.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_cree_woods.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/bj_innu.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_innu.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/bj_innu.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_innu.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/bj_innu_phonemic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_innu_phonemic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/bj_innu_phonemic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_innu_phonemic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/bj_mista_wasaha_cree.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_mista_wasaha_cree.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/bj_mista_wasaha_cree.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_mista_wasaha_cree.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/bj_naskapi_classic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_naskapi_classic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/bj_naskapi_classic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_naskapi_classic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/bj_naskapi_common.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_naskapi_common.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/bj_naskapi_common.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_naskapi_common.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/bj_oji_cree.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_oji_cree.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/bj_oji_cree.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/bj_oji_cree.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/brahmi_inscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/brahmi_inscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/brahmi_inscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/brahmi_inscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/btl_kenya.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/btl_kenya.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/btl_kenya.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/btl_kenya.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/bu_phonetic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/bu_phonetic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/bu_phonetic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/bu_phonetic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/buhid.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/buhid.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/buhid.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/buhid.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/burushaski_girminas.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/burushaski_girminas.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/burushaski_girminas.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/burushaski_girminas.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/cabecar.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/cabecar.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/cabecar.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/cabecar.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/carian.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/carian.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/carian.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/carian.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/chalchiteko.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/chalchiteko.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/chalchiteko.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/chalchiteko.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/chechen_latin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/chechen_latin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/chechen_latin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/chechen_latin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/chinuk_wawa.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/chinuk_wawa.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/chinuk_wawa.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/chinuk_wawa.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/choctaw_modern.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/choctaw_modern.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/choctaw_modern.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/choctaw_modern.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/cim.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/cim.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/cim.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/cim.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/clavbur9.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/clavbur9.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/clavbur9.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/clavbur9.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/colchis_latin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/colchis_latin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/colchis_latin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/colchis_latin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/colchis_phonetic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/colchis_phonetic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/colchis_phonetic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/colchis_phonetic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/common_devanagari.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/common_devanagari.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/common_devanagari.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/common_devanagari.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/coptic_greek.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/coptic_greek.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/coptic_greek.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/coptic_greek.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/coptic_qwerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/coptic_qwerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/coptic_qwerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/coptic_qwerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/dagbani.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/dagbani.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/dagbani.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/dagbani.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/dega.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/dega.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/dega.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/dega.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/dene.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/dene.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/dene.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/dene.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/deseret.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/deseret.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/deseret.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/deseret.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/dogra_inscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/dogra_inscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/dogra_inscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/dogra_inscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/easy_chakma.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/easy_chakma.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/easy_chakma.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/easy_chakma.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/ekwtamil99uni.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/ekwtamil99uni.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/ekwtamil99uni.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/ekwtamil99uni.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/el_dinka.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/el_dinka.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/el_dinka.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/el_dinka.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/el_harari_latin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/el_harari_latin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/el_harari_latin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/el_harari_latin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/el_naija.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/el_naija.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/el_naija.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/el_naija.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/el_nuer.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/el_nuer.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/el_nuer.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/el_nuer.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/el_pasifika.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/el_pasifika.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/el_pasifika.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/el_pasifika.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/el_yolngu.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/el_yolngu.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/el_yolngu.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/el_yolngu.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/embera_north.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/embera_north.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/embera_north.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/embera_north.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/enga.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/enga.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/enga.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/enga.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/enggano.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/enggano.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/enggano.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/enggano.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/english_shavian_igc.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/english_shavian_igc.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/english_shavian_igc.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/english_shavian_igc.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/english_shavian_qwerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/english_shavian_qwerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/english_shavian_qwerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/english_shavian_qwerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/engram.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/engram.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/engram.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/engram.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/esperuni.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/esperuni.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/esperuni.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/esperuni.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/farsiman.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/farsiman.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/farsiman.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/farsiman.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/finongan.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/finongan.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/finongan.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/finongan.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fulfulde_ajami_qwerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fulfulde_ajami_qwerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fulfulde_ajami_qwerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fulfulde_ajami_qwerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fulfulde_latin_qwerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fulfulde_latin_qwerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fulfulde_latin_qwerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fulfulde_latin_qwerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_dakelh.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_dakelh.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_dakelh.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_dakelh.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_dane_zaa_zaage.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_dane_zaa_zaage.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_dane_zaa_zaage.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_dane_zaa_zaage.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_denesuline_epsilon.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_denesuline_epsilon.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_denesuline_epsilon.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_denesuline_epsilon.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_diitiidatx.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_diitiidatx.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_diitiidatx.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_diitiidatx.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_gitsenimx.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_gitsenimx.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_gitsenimx.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_gitsenimx.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_gwichin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_gwichin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_gwichin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_gwichin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_hailzaqvla.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_hailzaqvla.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_hailzaqvla.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_hailzaqvla.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_haisla.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_haisla.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_haisla.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_haisla.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_halqemeylem.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_halqemeylem.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_halqemeylem.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_halqemeylem.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_han.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_han.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_han.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_han.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_henqeminem.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_henqeminem.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_henqeminem.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_henqeminem.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_hlgaagilda_xaayda_kil.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_hlgaagilda_xaayda_kil.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_hlgaagilda_xaayda_kil.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_hlgaagilda_xaayda_kil.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_kanienkeha_e.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_kanienkeha_e.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_kanienkeha_e.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_kanienkeha_e.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_ktunaxa.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_ktunaxa.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_ktunaxa.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_ktunaxa.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_kwakwala.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_kwakwala.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_kwakwala.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_kwakwala.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_kwakwala_liqwala.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_kwakwala_liqwala.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_kwakwala_liqwala.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_kwakwala_liqwala.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_migmaq.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_migmaq.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_migmaq.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_migmaq.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_natwits.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_natwits.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_natwits.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_natwits.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_nisgaa.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_nisgaa.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_nisgaa.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_nisgaa.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_nlekepmxcin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_nlekepmxcin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_nlekepmxcin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_nlekepmxcin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_northern_tutchone.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_northern_tutchone.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_northern_tutchone.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_northern_tutchone.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_nsilxcen.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_nsilxcen.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_nsilxcen.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_nsilxcen.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_nuucaanul.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_nuucaanul.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_nuucaanul.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_nuucaanul.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_secwepemctsin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_secwepemctsin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_secwepemctsin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_secwepemctsin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_sencoten.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_sencoten.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_sencoten.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_sencoten.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_shashishalhem.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_shashishalhem.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_shashishalhem.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_shashishalhem.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_smalgyax.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_smalgyax.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_smalgyax.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_smalgyax.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_southern_tutchone.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_southern_tutchone.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_southern_tutchone.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_southern_tutchone.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_statimcets.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_statimcets.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_statimcets.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_statimcets.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_stlatlimxec.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_stlatlimxec.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_stlatlimxec.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_stlatlimxec.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_tagizi_dene.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_tagizi_dene.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_tagizi_dene.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_tagizi_dene.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_taltan.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_taltan.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_taltan.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_taltan.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_tlingit.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_tlingit.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_tlingit.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_tlingit.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_tsekehne.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_tsekehne.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_tsekehne.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_tsekehne.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_tsilhqotin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_tsilhqotin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_tsilhqotin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_tsilhqotin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_uwikala.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_uwikala.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_uwikala.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_uwikala.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/fv_xaislakala.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_xaislakala.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/fv_xaislakala.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/fv_xaislakala.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/galaxie_greek_mnemonic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/galaxie_greek_mnemonic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/galaxie_greek_mnemonic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/galaxie_greek_mnemonic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/galaxie_greek_positional.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/galaxie_greek_positional.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/galaxie_greek_positional.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/galaxie_greek_positional.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/galaxie_hebrew_mnemonic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/galaxie_hebrew_mnemonic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/galaxie_hebrew_mnemonic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/galaxie_hebrew_mnemonic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/galaxie_hebrew_positional.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/galaxie_hebrew_positional.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/galaxie_hebrew_positional.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/galaxie_hebrew_positional.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/gandhari.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/gandhari.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/gandhari.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/gandhari.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/geezbrhan.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/geezbrhan.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/geezbrhan.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/geezbrhan.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/gff_amh_7.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/gff_amh_7.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/gff_amh_7.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/gff_amh_7.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/gff_amharic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/gff_amharic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/gff_amharic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/gff_amharic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/gff_blin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/gff_blin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/gff_blin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/gff_blin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/gff_ethiopic_7.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/gff_ethiopic_7.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/gff_ethiopic_7.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/gff_ethiopic_7.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/gff_geez.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/gff_geez.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/gff_geez.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/gff_geez.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/gff_gurage.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/gff_gurage.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/gff_gurage.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/gff_gurage.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/gff_gurage_legacy.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/gff_gurage_legacy.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/gff_gurage_legacy.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/gff_gurage_legacy.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/gff_musnad.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/gff_musnad.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/gff_musnad.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/gff_musnad.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/gff_tigrinya_eritrea.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/gff_tigrinya_eritrea.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/gff_tigrinya_eritrea.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/gff_tigrinya_eritrea.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/gff_tigrinya_ethiopia.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/gff_tigrinya_ethiopia.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/gff_tigrinya_ethiopia.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/gff_tigrinya_ethiopia.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/ghana.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/ghana.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/ghana.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/ghana.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/gilaki.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/gilaki.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/gilaki.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/gilaki.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/gilaki_phonetic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/gilaki_phonetic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/gilaki_phonetic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/gilaki_phonetic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/gondi_dev.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/gondi_dev.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/gondi_dev.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/gondi_dev.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/gondi_gunjala.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/gondi_gunjala.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/gondi_gunjala.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/gondi_gunjala.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/gondi_tel.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/gondi_tel.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/gondi_tel.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/gondi_tel.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/greekclassical.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/greekclassical.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/greekclassical.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/greekclassical.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/hanunoo.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/hanunoo.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/hanunoo.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/hanunoo.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/haroi.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/haroi.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/haroi.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/haroi.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/hatran_inscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/hatran_inscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/hatran_inscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/hatran_inscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/hausa_ajami_qwerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/hausa_ajami_qwerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/hausa_ajami_qwerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/hausa_ajami_qwerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/hausa_kano.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/hausa_kano.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/hausa_kano.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/hausa_kano.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/hcesar.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/hcesar.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/hcesar.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/hcesar.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/hieroglyphic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/hieroglyphic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/hieroglyphic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/hieroglyphic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/himyarit_musnad.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/himyarit_musnad.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/himyarit_musnad.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/himyarit_musnad.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/hindi_modular.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/hindi_modular.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/hindi_modular.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/hindi_modular.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/indigenous_nt.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/indigenous_nt.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/indigenous_nt.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/indigenous_nt.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/indonesia.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/indonesia.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/indonesia.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/indonesia.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/indonesian_suku.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/indonesian_suku.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/indonesian_suku.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/indonesian_suku.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/inuktitut_naqittaut.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/inuktitut_naqittaut.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/inuktitut_naqittaut.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/inuktitut_naqittaut.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/ishkashimi_cyrillic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/ishkashimi_cyrillic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/ishkashimi_cyrillic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/ishkashimi_cyrillic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/itrans_bengali.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/itrans_bengali.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/itrans_bengali.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/itrans_bengali.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/itrans_devanagari_hindi.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/itrans_devanagari_hindi.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/itrans_devanagari_hindi.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/itrans_devanagari_hindi.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/itrans_devanagari_sanskrit_vedic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/itrans_devanagari_sanskrit_vedic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/itrans_devanagari_sanskrit_vedic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/itrans_devanagari_sanskrit_vedic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/itrans_gujarati.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/itrans_gujarati.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/itrans_gujarati.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/itrans_gujarati.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/itrans_gurmukhi.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/itrans_gurmukhi.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/itrans_gurmukhi.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/itrans_gurmukhi.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/itrans_odia.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/itrans_odia.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/itrans_odia.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/itrans_odia.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/itrans_roman.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/itrans_roman.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/itrans_roman.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/itrans_roman.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/jawa.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/jawa.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/jawa.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/jawa.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/jorai.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/jorai.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/jorai.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/jorai.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/karakalpak_cyrillic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/karakalpak_cyrillic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/karakalpak_cyrillic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/karakalpak_cyrillic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/karakalpak_latin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/karakalpak_latin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/karakalpak_latin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/karakalpak_latin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/kayan.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/kayan.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/kayan.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/kayan.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/kbdsn1.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/kbdsn1.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/kbdsn1.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/kbdsn1.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/kharoshthi_inscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/kharoshthi_inscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/kharoshthi_inscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/kharoshthi_inscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/khmer_advanced.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/khmer_advanced.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/khmer_advanced.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/khmer_advanced.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/khmer_angkor.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/khmer_angkor.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/khmer_angkor.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/khmer_angkor.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/khojki_inscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/khojki_inscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/khojki_inscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/khojki_inscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/kmhmu_2008.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/kmhmu_2008.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/kmhmu_2008.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/kmhmu_2008.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/koalibrere.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/koalibrere.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/koalibrere.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/koalibrere.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/korean_rr.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/korean_rr.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/korean_rr.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/korean_rr.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/koreguaje.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/koreguaje.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/koreguaje.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/koreguaje.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/krung.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/krung.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/krung.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/krung.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/lahu.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/lahu.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/lahu.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/lahu.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/lamkaang.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/lamkaang.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/lamkaang.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/lamkaang.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/landuma.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/landuma.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/landuma.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/landuma.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/lao_2008_basic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/lao_2008_basic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/lao_2008_basic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/lao_2008_basic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/lao_2008_rapid.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/lao_2008_rapid.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/lao_2008_rapid.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/lao_2008_rapid.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/lao_pali.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/lao_pali.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/lao_pali.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/lao_pali.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/lao_pali_us.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/lao_pali_us.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/lao_pali_us.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/lao_pali_us.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/lao_phonetic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/lao_phonetic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/lao_phonetic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/lao_phonetic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/lazuri.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/lazuri.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/lazuri.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/lazuri.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/libtralo.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/libtralo.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/libtralo.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/libtralo.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/makasar_inscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/makasar_inscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/makasar_inscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/makasar_inscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/malar_braille.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/malar_braille.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/malar_braille.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/malar_braille.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/malar_malayalam.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/malar_malayalam.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/malar_malayalam.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/malar_malayalam.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/malar_malayalam_inscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/malar_malayalam_inscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/malar_malayalam_inscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/malar_malayalam_inscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/malar_tirhuta.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/malar_tirhuta.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/malar_tirhuta.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/malar_tirhuta.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/maltese.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/maltese.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/maltese.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/maltese.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/mandaic_phonetic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/mandaic_phonetic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/mandaic_phonetic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/mandaic_phonetic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/masaram_gondi.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/masaram_gondi.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/masaram_gondi.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/masaram_gondi.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/me_en.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/me_en.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/me_en.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/me_en.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/meitei_legacy.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/meitei_legacy.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/meitei_legacy.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/meitei_legacy.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/miluk_hanis_siuslaw.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/miluk_hanis_siuslaw.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/miluk_hanis_siuslaw.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/miluk_hanis_siuslaw.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/modi_inscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/modi_inscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/modi_inscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/modi_inscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/mon_anonta.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/mon_anonta.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/mon_anonta.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/mon_anonta.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/mon_phonetic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/mon_phonetic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/mon_phonetic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/mon_phonetic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/mongolian_cyrillic_qwerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/mongolian_cyrillic_qwerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/mongolian_cyrillic_qwerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/mongolian_cyrillic_qwerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/mozhi_malayalam.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/mozhi_malayalam.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/mozhi_malayalam.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/mozhi_malayalam.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/mro_phonetic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/mro_phonetic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/mro_phonetic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/mro_phonetic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/multani_inscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/multani_inscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/multani_inscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/multani_inscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/multi_pak_phonetic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/multi_pak_phonetic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/multi_pak_phonetic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/multi_pak_phonetic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/munji.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/munji.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/munji.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/munji.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/myancode_san.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/myancode_san.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/myancode_san.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/myancode_san.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/nabataean_inscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/nabataean_inscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/nabataean_inscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/nabataean_inscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/naijatype.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/naijatype.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/naijatype.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/naijatype.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/nailangs.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/nailangs.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/nailangs.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/nailangs.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/nasa_yuwe.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/nasa_yuwe.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/nasa_yuwe.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/nasa_yuwe.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/nepali_traditional.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/nepali_traditional.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/nepali_traditional.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/nepali_traditional.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/newa_romanized.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/newa_romanized.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/newa_romanized.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/newa_romanized.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/newa_traditional.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/newa_traditional.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/newa_traditional.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/newa_traditional.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/nias.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/nias.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/nias.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/nias.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/nisenan.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/nisenan.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/nisenan.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/nisenan.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/nko.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/nko.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/nko.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/nko.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/nkonya.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/nkonya.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/nkonya.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/nkonya.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/nlci_bengali_winscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/nlci_bengali_winscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/nlci_bengali_winscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/nlci_bengali_winscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/nlci_devanagari_winscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/nlci_devanagari_winscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/nlci_devanagari_winscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/nlci_devanagari_winscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/nlci_gujarati_winscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/nlci_gujarati_winscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/nlci_gujarati_winscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/nlci_gujarati_winscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/nlci_gurmukhi_winscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/nlci_gurmukhi_winscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/nlci_gurmukhi_winscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/nlci_gurmukhi_winscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/nlci_ipa.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/nlci_ipa.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/nlci_ipa.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/nlci_ipa.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/nlci_kannada_winscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/nlci_kannada_winscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/nlci_kannada_winscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/nlci_kannada_winscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/nlci_malayalam_winscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/nlci_malayalam_winscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/nlci_malayalam_winscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/nlci_malayalam_winscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/nlci_oriya_winscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/nlci_oriya_winscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/nlci_oriya_winscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/nlci_oriya_winscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/nlci_tamil_winscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/nlci_tamil_winscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/nlci_tamil_winscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/nlci_tamil_winscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/nlci_telugu_winscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/nlci_telugu_winscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/nlci_telugu_winscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/nlci_telugu_winscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/nrc_makah.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/nrc_makah.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/nrc_makah.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/nrc_makah.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/ntl_onekey.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/ntl_onekey.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/ntl_onekey.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/ntl_onekey.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/numanggang.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/numanggang.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/numanggang.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/numanggang.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/nw_iranian_latin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/nw_iranian_latin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/nw_iranian_latin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/nw_iranian_latin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/o_tissi.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/o_tissi.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/o_tissi.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/o_tissi.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/obolo_chwerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/obolo_chwerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/obolo_chwerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/obolo_chwerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/obolo_qwerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/obolo_qwerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/obolo_qwerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/obolo_qwerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/old_hungarian.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/old_hungarian.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/old_hungarian.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/old_hungarian.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/old_turkic_udw21_qwerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/old_turkic_udw21_qwerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/old_turkic_udw21_qwerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/old_turkic_udw21_qwerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/orma.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/orma.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/orma.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/orma.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/osage_nation.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/osage_nation.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/osage_nation.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/osage_nation.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/osage_nation_new.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/osage_nation_new.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/osage_nation_new.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/osage_nation_new.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/otoe_missouria.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/otoe_missouria.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/otoe_missouria.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/otoe_missouria.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/persian_phonetic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/persian_phonetic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/persian_phonetic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/persian_phonetic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/pid_piaroa.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/pid_piaroa.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/pid_piaroa.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/pid_piaroa.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/pingelap.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/pingelap.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/pingelap.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/pingelap.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/postmodern_english_uk_dualstroke.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/postmodern_english_uk_dualstroke.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/postmodern_english_uk_dualstroke.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/postmodern_english_uk_dualstroke.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/postmodern_english_uk_natural.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/postmodern_english_uk_natural.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/postmodern_english_uk_natural.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/postmodern_english_uk_natural.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/postmodern_english_us_dualstroke.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/postmodern_english_us_dualstroke.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/postmodern_english_us_dualstroke.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/postmodern_english_us_dualstroke.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/postmodern_english_us_natural.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/postmodern_english_us_natural.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/postmodern_english_us_natural.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/postmodern_english_us_natural.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/pukapuka.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/pukapuka.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/pukapuka.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/pukapuka.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/qom.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/qom.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/qom.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/qom.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/quinault.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/quinault.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/quinault.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/quinault.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/qwerty_farang.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/qwerty_farang.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/qwerty_farang.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/qwerty_farang.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_aer.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_aer.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_aer.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_aer.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_arabic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_arabic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_arabic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_arabic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_balti.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_balti.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_balti.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_balti.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_brahui.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_brahui.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_brahui.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_brahui.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_brahui_latin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_brahui_latin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_brahui_latin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_brahui_latin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_burushaski.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_burushaski.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_burushaski.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_burushaski.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_dameli.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_dameli.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_dameli.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_dameli.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_dhatki.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_dhatki.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_dhatki.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_dhatki.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_dogri.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_dogri.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_dogri.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_dogri.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_gawar_bati.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_gawar_bati.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_gawar_bati.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_gawar_bati.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_gawri.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_gawri.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_gawri.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_gawri.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_hazaragi.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_hazaragi.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_hazaragi.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_hazaragi.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_hindko.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_hindko.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_hindko.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_hindko.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_indus_kohistani.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_indus_kohistani.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_indus_kohistani.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_indus_kohistani.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_kalasha.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_kalasha.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_kalasha.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_kalasha.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_kashmir_shina.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_kashmir_shina.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_kashmir_shina.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_kashmir_shina.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_kashmiri.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_kashmiri.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_kashmiri.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_kashmiri.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_khowar.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_khowar.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_khowar.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_khowar.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_marwari.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_marwari.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_marwari.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_marwari.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_munji.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_munji.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_munji.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_munji.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_oadki.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_oadki.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_oadki.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_oadki.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_ormuri.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_ormuri.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_ormuri.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_ormuri.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_pahari.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_pahari.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_pahari.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_pahari.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_palula.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_palula.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_palula.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_palula.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_parkari_koli.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_parkari_koli.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_parkari_koli.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_parkari_koli.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_pashai.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_pashai.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_pashai.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_pashai.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_pashto.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_pashto.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_pashto.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_pashto.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_saraiki.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_saraiki.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_saraiki.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_saraiki.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_shina.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_shina.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_shina.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_shina.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_sindhi.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_sindhi.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_sindhi.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_sindhi.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_torwali.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_torwali.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_torwali.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_torwali.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_urdu.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_urdu.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_urdu.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_urdu.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_ushojo.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_ushojo.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_ushojo.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_ushojo.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_uyghur.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_uyghur.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_uyghur.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_uyghur.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_wadiyara.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_wadiyara.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_wadiyara.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_wadiyara.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_wakhi.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_wakhi.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_wakhi.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_wakhi.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_western_punjabi.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_western_punjabi.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_western_punjabi.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_western_punjabi.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rac_yidgha.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_yidgha.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rac_yidgha.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rac_yidgha.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rawang.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rawang.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rawang.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rawang.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rejang.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rejang.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rejang.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rejang.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/remington_gail.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/remington_gail.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/remington_gail.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/remington_gail.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rohingya_arab.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rohingya_arab.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rohingya_arab.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rohingya_arab.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/rossel.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/rossel.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/rossel.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/rossel.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/runeboard.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/runeboard.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/runeboard.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/runeboard.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/russian_mnemonic_r.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/russian_mnemonic_r.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/russian_mnemonic_r.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/russian_mnemonic_r.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sabdalipi_assamese.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sabdalipi_assamese.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sabdalipi_assamese.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sabdalipi_assamese.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sahaptin_umatilla.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sahaptin_umatilla.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sahaptin_umatilla.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sahaptin_umatilla.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sahaptin_yakima.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sahaptin_yakima.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sahaptin_yakima.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sahaptin_yakima.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sanjha_punjabi.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sanjha_punjabi.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sanjha_punjabi.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sanjha_punjabi.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/santali_latin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/santali_latin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/santali_latin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/santali_latin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/saraiki.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/saraiki.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/saraiki.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/saraiki.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/satere.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/satere.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/satere.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/satere.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/shahmukhi_phonetic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/shahmukhi_phonetic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/shahmukhi_phonetic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/shahmukhi_phonetic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/shan.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/shan.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/shan.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/shan.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/shaw_2layer.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/shaw_2layer.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/shaw_2layer.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/shaw_2layer.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/siddham_inscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/siddham_inscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/siddham_inscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/siddham_inscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_akha_act.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_akha_act.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_akha_act.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_akha_act.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_arabic_phonetic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_arabic_phonetic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_arabic_phonetic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_arabic_phonetic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_areare.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_areare.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_areare.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_areare.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_bari.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_bari.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_bari.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_bari.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_bengali_phonetic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_bengali_phonetic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_bengali_phonetic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_bengali_phonetic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_bolivia.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_bolivia.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_bolivia.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_bolivia.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_boonkit.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_boonkit.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_boonkit.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_boonkit.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_brao.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_brao.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_brao.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_brao.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_bru.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_bru.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_bru.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_bru.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_buang.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_buang.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_buang.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_buang.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_bunong.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_bunong.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_bunong.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_bunong.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_busa.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_busa.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_busa.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_busa.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_bwe_karen.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_bwe_karen.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_bwe_karen.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_bwe_karen.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_cameroon_azerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_cameroon_azerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_cameroon_azerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_cameroon_azerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_cameroon_qwerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_cameroon_qwerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_cameroon_qwerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_cameroon_qwerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_cherokee_nation.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_cherokee_nation.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_cherokee_nation.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_cherokee_nation.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_cheyenne.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_cheyenne.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_cheyenne.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_cheyenne.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_cipher_music.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_cipher_music.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_cipher_music.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_cipher_music.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_devanagari_phonetic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_devanagari_phonetic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_devanagari_phonetic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_devanagari_phonetic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_devanagari_romanized.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_devanagari_romanized.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_devanagari_romanized.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_devanagari_romanized.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_devanagari_typewriter.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_devanagari_typewriter.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_devanagari_typewriter.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_devanagari_typewriter.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_dzongkha.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_dzongkha.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_dzongkha.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_dzongkha.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_eastern_congo.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_eastern_congo.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_eastern_congo.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_eastern_congo.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_el_ethiopian_latin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_el_ethiopian_latin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_el_ethiopian_latin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_el_ethiopian_latin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_ethiopic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_ethiopic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_ethiopic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_ethiopic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_ethiopic_power_g.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_ethiopic_power_g.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_ethiopic_power_g.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_ethiopic_power_g.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_euro_latin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_euro_latin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_euro_latin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_euro_latin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_extended_urdu_np.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_extended_urdu_np.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_extended_urdu_np.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_extended_urdu_np.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_greek_polytonic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_greek_polytonic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_greek_polytonic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_greek_polytonic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_hawaiian.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_hawaiian.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_hawaiian.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_hawaiian.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_hebr_grek_trans.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_hebr_grek_trans.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_hebr_grek_trans.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_hebr_grek_trans.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_hebrew.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_hebrew.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_hebrew.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_hebrew.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_hebrew_legacy.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_hebrew_legacy.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_hebrew_legacy.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_hebrew_legacy.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_hmd_plrd.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_hmd_plrd.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_hmd_plrd.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_hmd_plrd.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_indic_roman.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_indic_roman.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_indic_roman.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_indic_roman.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_ipa.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_ipa.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_ipa.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_ipa.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_jarai.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_jarai.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_jarai.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_jarai.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_kayah_kali.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_kayah_kali.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_kayah_kali.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_kayah_kali.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_kayah_latn.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_kayah_latn.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_kayah_latn.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_kayah_latn.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_kayah_mymr.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_kayah_mymr.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_kayah_mymr.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_kayah_mymr.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_khamti.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_khamti.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_khamti.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_khamti.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_khmer.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_khmer.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_khmer.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_khmer.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_khowar.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_khowar.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_khowar.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_khowar.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_kmhmu.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_kmhmu.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_kmhmu.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_kmhmu.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_korda_jamo.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_korda_jamo.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_korda_jamo.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_korda_jamo.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_korda_latin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_korda_latin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_korda_latin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_korda_latin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_korean_morse.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_korean_morse.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_korean_morse.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_korean_morse.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_kvl_kayaw.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_kvl_kayaw.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_kvl_kayaw.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_kvl_kayaw.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_lepcha.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_lepcha.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_lepcha.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_lepcha.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_limbu_phonetic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_limbu_phonetic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_limbu_phonetic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_limbu_phonetic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_limbu_typewriter.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_limbu_typewriter.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_limbu_typewriter.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_limbu_typewriter.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_lisu_basic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_lisu_basic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_lisu_basic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_lisu_basic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_lisu_standard.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_lisu_standard.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_lisu_standard.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_lisu_standard.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_lpo_plrd.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_lpo_plrd.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_lpo_plrd.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_lpo_plrd.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_madi.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_madi.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_madi.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_madi.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_makuri.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_makuri.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_makuri.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_makuri.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_mali_azerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_mali_azerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_mali_azerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_mali_azerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_mali_qwerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_mali_qwerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_mali_qwerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_mali_qwerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_mali_qwertz.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_mali_qwertz.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_mali_qwertz.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_mali_qwertz.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_moore.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_moore.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_moore.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_moore.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_myanmar_my3.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_myanmar_my3.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_myanmar_my3.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_myanmar_my3.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_myanmar_mywinext.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_myanmar_mywinext.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_myanmar_mywinext.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_myanmar_mywinext.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_nigeria_dot.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_nigeria_dot.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_nigeria_dot.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_nigeria_dot.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_nigeria_odd_vowels.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_nigeria_odd_vowels.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_nigeria_odd_vowels.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_nigeria_odd_vowels.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_nigeria_underline.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_nigeria_underline.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_nigeria_underline.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_nigeria_underline.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_nko.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_nko.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_nko.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_nko.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_nubian.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_nubian.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_nubian.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_nubian.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_pan_africa_mnemonic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_pan_africa_mnemonic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_pan_africa_mnemonic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_pan_africa_mnemonic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_pan_africa_positional.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_pan_africa_positional.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_pan_africa_positional.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_pan_africa_positional.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_philippines.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_philippines.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_philippines.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_philippines.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_sahu.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_sahu.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_sahu.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_sahu.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_senegal_bsc_azerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_senegal_bsc_azerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_senegal_bsc_azerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_senegal_bsc_azerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_senegal_cou_azerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_senegal_cou_azerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_senegal_cou_azerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_senegal_cou_azerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_senegal_dyo_azerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_senegal_dyo_azerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_senegal_dyo_azerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_senegal_dyo_azerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_senegal_gsl_azerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_senegal_gsl_azerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_senegal_gsl_azerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_senegal_gsl_azerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_senegal_krx_azerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_senegal_krx_azerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_senegal_krx_azerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_senegal_krx_azerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_senegal_ndv_azerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_senegal_ndv_azerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_senegal_ndv_azerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_senegal_ndv_azerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_senegal_sav_azerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_senegal_sav_azerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_senegal_sav_azerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_senegal_sav_azerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_senegal_snf_azerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_senegal_snf_azerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_senegal_snf_azerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_senegal_snf_azerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_senegal_srr_azerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_senegal_srr_azerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_senegal_srr_azerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_senegal_srr_azerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_senegal_wo_azerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_senegal_wo_azerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_senegal_wo_azerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_senegal_wo_azerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_sgaw_karen.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_sgaw_karen.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_sgaw_karen.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_sgaw_karen.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_shan.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_shan.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_shan.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_shan.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_tai_dam.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_tai_dam.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_tai_dam.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_tai_dam.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_tai_dam_lao.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_tai_dam_lao.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_tai_dam_lao.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_tai_dam_lao.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_tai_dam_latin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_tai_dam_latin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_tai_dam_latin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_tai_dam_latin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_tai_dam_typewriter.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_tai_dam_typewriter.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_tai_dam_typewriter.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_tai_dam_typewriter.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_tawallammat.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_tawallammat.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_tawallammat.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_tawallammat.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_tchad.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_tchad.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_tchad.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_tchad.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_tepehuan.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_tepehuan.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_tepehuan.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_tepehuan.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_torwali.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_torwali.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_torwali.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_torwali.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_tunisian.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_tunisian.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_tunisian.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_tunisian.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_uganda_tanzania.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_uganda_tanzania.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_uganda_tanzania.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_uganda_tanzania.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_vai.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_vai.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_vai.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_vai.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_wayuu.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_wayuu.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_wayuu.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_wayuu.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_ygp_plrd.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_ygp_plrd.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_ygp_plrd.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_ygp_plrd.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_yi.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_yi.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_yi.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_yi.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_yna_plrd.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_yna_plrd.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_yna_plrd.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_yna_plrd.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_yoruba8.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_yoruba8.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_yoruba8.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_yoruba8.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_yoruba_bar.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_yoruba_bar.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_yoruba_bar.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_yoruba_bar.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_yoruba_dot.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_yoruba_dot.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_yoruba_dot.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_yoruba_dot.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_yupik_cyrillic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_yupik_cyrillic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_yupik_cyrillic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_yupik_cyrillic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_yupik_cyrillic_ru.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_yupik_cyrillic_ru.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_yupik_cyrillic_ru.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_yupik_cyrillic_ru.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sil_ywq_plrd.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_ywq_plrd.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sil_ywq_plrd.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sil_ywq_plrd.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/slc_saliba.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/slc_saliba.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/slc_saliba.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/slc_saliba.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/soqotri_arabic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/soqotri_arabic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/soqotri_arabic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/soqotri_arabic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/srr_ajami_qwerty.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/srr_ajami_qwerty.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/srr_ajami_qwerty.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/srr_ajami_qwerty.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sundanese.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sundanese.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sundanese.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sundanese.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sundanese_latin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sundanese_latin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sundanese_latin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sundanese_latin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/swanalekha_malayalam.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/swanalekha_malayalam.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/swanalekha_malayalam.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/swanalekha_malayalam.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sxava.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sxava.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sxava.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sxava.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sxava_eo.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sxava_eo.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sxava_eo.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sxava_eo.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/sylheti_nagri.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/sylheti_nagri.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/sylheti_nagri.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/sylheti_nagri.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/syriac_arabic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/syriac_arabic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/syriac_arabic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/syriac_arabic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/syriac_phonetic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/syriac_phonetic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/syriac_phonetic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/syriac_phonetic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/tagbanwa_inscript.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/tagbanwa_inscript.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/tagbanwa_inscript.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/tagbanwa_inscript.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/taigi_poj.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/taigi_poj.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/taigi_poj.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/taigi_poj.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/tainua.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/tainua.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/tainua.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/tainua.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/tangsa_lakhum.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/tangsa_lakhum.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/tangsa_lakhum.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/tangsa_lakhum.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/tawallammat_latin.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/tawallammat_latin.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/tawallammat_latin.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/tawallammat_latin.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/teggargrent_lat.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/teggargrent_lat.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/teggargrent_lat.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/teggargrent_lat.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/tem_kdh.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/tem_kdh.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/tem_kdh.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/tem_kdh.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/thamizha_anjal_paangu.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/thamizha_anjal_paangu.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/thamizha_anjal_paangu.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/thamizha_anjal_paangu.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/thamizha_bamini.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/thamizha_bamini.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/thamizha_bamini.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/thamizha_bamini.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/thamizha_new_typewriter.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/thamizha_new_typewriter.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/thamizha_new_typewriter.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/thamizha_new_typewriter.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/thamizha_tamil99_ext.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/thamizha_tamil99_ext.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/thamizha_tamil99_ext.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/thamizha_tamil99_ext.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/tibetan_direct_input.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/tibetan_direct_input.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/tibetan_direct_input.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/tibetan_direct_input.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/tibetan_ewts.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/tibetan_ewts.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/tibetan_ewts.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/tibetan_ewts.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/tirhuta.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/tirhuta.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/tirhuta.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/tirhuta.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/tlahuica.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/tlahuica.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/tlahuica.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/tlahuica.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/tsakonian.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/tsakonian.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/tsakonian.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/tsakonian.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/tuareg_tifinagh.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/tuareg_tifinagh.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/tuareg_tifinagh.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/tuareg_tifinagh.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/turkmen_cyrl.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/turkmen_cyrl.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/turkmen_cyrl.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/turkmen_cyrl.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/txo_toto.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/txo_toto.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/txo_toto.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/txo_toto.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/udi_keyboard.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/udi_keyboard.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/udi_keyboard.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/udi_keyboard.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/ukwuani.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/ukwuani.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/ukwuani.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/ukwuani.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/uma_graphic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/uma_graphic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/uma_graphic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/uma_graphic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/uma_phonetic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/uma_phonetic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/uma_phonetic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/uma_phonetic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/urdu_phonetic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/urdu_phonetic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/urdu_phonetic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/urdu_phonetic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/urdu_phonetic_crulp.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/urdu_phonetic_crulp.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/urdu_phonetic_crulp.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/urdu_phonetic_crulp.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/venetia_et_histria.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/venetia_et_histria.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/venetia_et_histria.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/venetia_et_histria.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/vm_tamil_modular.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/vm_tamil_modular.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/vm_tamil_modular.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/vm_tamil_modular.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/vm_tamil_typewriter.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/vm_tamil_typewriter.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/vm_tamil_typewriter.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/vm_tamil_typewriter.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/wakhi_anglicized.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/wakhi_anglicized.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/wakhi_anglicized.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/wakhi_anglicized.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/wakhi_cyrillic.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/wakhi_cyrillic.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/wakhi_cyrillic.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/wakhi_cyrillic.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/wakhi_standard.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/wakhi_standard.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/wakhi_standard.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/wakhi_standard.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/wancho.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/wancho.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/wancho.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/wancho.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/warang_citi.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/warang_citi.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/warang_citi.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/warang_citi.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/wolofal.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/wolofal.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/wolofal.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/wolofal.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/xinaliq.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/xinaliq.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/xinaliq.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/xinaliq.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/yiddish_pasekh.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/yiddish_pasekh.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/yiddish_pasekh.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/yiddish_pasekh.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/yidgha.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/yidgha.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/yidgha.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/yidgha.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/younger_futhark_short_twig.kmx b/developer/src/kmcmplib/tests/fixtures/keyboards-repo/younger_futhark_short_twig.kmx similarity index 100% rename from developer/src/kmcmplib/tests/fixtures/younger_futhark_short_twig.kmx rename to developer/src/kmcmplib/tests/fixtures/keyboards-repo/younger_futhark_short_twig.kmx diff --git a/developer/src/kmcmplib/tests/meson.build b/developer/src/kmcmplib/tests/meson.build index b81429806e..49924f2d78 100644 --- a/developer/src/kmcmplib/tests/meson.build +++ b/developer/src/kmcmplib/tests/meson.build @@ -96,7 +96,7 @@ if get_option('full_test') # kbd is going to be an absolute path kbd_obj = output_path / test_basename + '.kmx' - reference_kmx = meson.current_source_dir() / 'fixtures' / test_basename + '.kmx' + reference_kmx = meson.current_source_dir() / 'fixtures/keyboards-repo' / test_basename + '.kmx' if fs.is_file(reference_kmx) test(test_basename, kmcompxtest, args: [kbd, kbd_obj, reference_kmx]) diff --git a/developer/src/kmcmplib/tests/prep.sh b/developer/src/kmcmplib/tests/prep.sh index 058d4a1b9b..8ad9b81171 100755 --- a/developer/src/kmcmplib/tests/prep.sh +++ b/developer/src/kmcmplib/tests/prep.sh @@ -39,30 +39,30 @@ if [[ ! -d "$KEYBOARDS_ROOT/.git" ]] || [[ ! -f "$KEYBOARDS_ROOT/tools/regressio fi if builder_start_action clean; then - rm -rf "$THIS_SCRIPT_PATH/fixtures" + rm -rf "$THIS_SCRIPT_PATH/fixtures/keyboards-repo" rm -f "$THIS_SCRIPT_PATH/keyboards_commit_ref.txt" builder_finish_action success clean fi if builder_start_action build; then # yes, remove existing fixtures before build so we don't end up with stale fixtures - rm -rf "$THIS_SCRIPT_PATH/fixtures" + rm -rf "$THIS_SCRIPT_PATH/fixtures/keyboards-repo" # record the revision of the keyboards repo pushd "$KEYBOARDS_ROOT" > /dev/null git rev-parse head > "$THIS_SCRIPT_PATH/keyboards_commit_ref.txt" popd > /dev/null - "$KEYBOARDS_ROOT/tools/regression.sh" --use-legacy-compiler --local "$KEYMAN_ROOT/developer/bin/" --output "$THIS_SCRIPT_PATH/fixtures/" + "$KEYBOARDS_ROOT/tools/regression.sh" --use-legacy-compiler --local "$KEYMAN_ROOT/developer/bin/" --output "$THIS_SCRIPT_PATH/fixtures/keyboards-repo/" cd "$THIS_SCRIPT_PATH" # We don't need visual keyboards - rm ./fixtures/*.kvk + rm ./fixtures/keyboards-repo/*.kvk # Nor do we need kmw outputs - rm ./fixtures/*.js + rm ./fixtures/keyboards-repo/*.js # Finally, we remove any keyboards over 500kb, as we won't automatically test them for now # TODO: consider if we want to keep those large keyboards in the future - find ./fixtures/ -size +500k -exec rm {} \+ + find ./fixtures/keyboards-repo/ -size +500k -exec rm {} \+ builder_finish_action success build fi \ No newline at end of file -- GitLab From 71df68cd13fd06fcd1cdc5ff52b527a2fd76211d Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 30 May 2023 10:52:05 +0700 Subject: [PATCH 154/214] refactor(developer): move fs for kmn load to caller --- developer/src/kmcmplib/include/kmcmplibapi.h | 4 +- developer/src/kmcmplib/src/Compiler.cpp | 136 +++++++----------- .../src/kmcmplib/src/CompilerInterfaces.cpp | 89 ++++++++---- developer/src/kmcmplib/src/compfile.h | 29 ---- developer/src/kmcmplib/src/kmcmplib.h | 5 +- developer/src/kmcmplib/src/meson.build | 8 +- developer/src/kmcmplib/tests/api-test.cpp | 50 +++++-- developer/src/kmcmplib/tests/kmcompxtest.cpp | 33 ++++- developer/src/kmcmplib/tests/meson.build | 4 +- 9 files changed, 196 insertions(+), 162 deletions(-) diff --git a/developer/src/kmcmplib/include/kmcmplibapi.h b/developer/src/kmcmplib/include/kmcmplibapi.h index 4054d81e81..5c2ae46fda 100644 --- a/developer/src/kmcmplib/include/kmcmplibapi.h +++ b/developer/src/kmcmplib/include/kmcmplibapi.h @@ -36,7 +36,7 @@ struct KMCMP_COMPILER_RESULT { }; // TODO: parameters in UTF-8 -typedef int (*kmcmp_CompilerMessageProc)(int line, uint32_t dwMsgCode, char* szText, void* context); +typedef int (*kmcmp_CompilerMessageProc)(int line, uint32_t dwMsgCode, const char* szText, void* context); // parameters in UTF-8 // TODO typical usage: @@ -48,7 +48,7 @@ typedef int (*kmcmp_CompilerMessageProc)(int line, uint32_t dwMsgCode, char* szT // delete[] buf; // return error; // } -typedef bool (*kmcmp_LoadFileProc)(char* loadFilename, char* baseFilename, void* buffer, int* bufferSize); +typedef bool (*kmcmp_LoadFileProc)(const char* loadFilename, const char* baseFilename, void* buffer, int* bufferSize, void* context); // Parameters in UTF-8 EXTERN bool kmcmp_CompileKeyboard( diff --git a/developer/src/kmcmplib/src/Compiler.cpp b/developer/src/kmcmplib/src/Compiler.cpp index b09e36cbc1..8e0f94cb29 100644 --- a/developer/src/kmcmplib/src/Compiler.cpp +++ b/developer/src/kmcmplib/src/Compiler.cpp @@ -94,6 +94,9 @@ #include "CasedKeys.h" #include #include +#include +#include + #include "CheckFilenameConsistency.h" #include "UnreachableRules.h" #include "CheckForDuplicates.h" @@ -230,6 +233,8 @@ enum LinePrefixType { lptNone, lptKeymanAndKeymanWeb, lptKeymanWebOnly, lptKeyma /* Compile target */ kmcmp_CompilerMessageProc msgproc = NULL; +kmcmp_LoadFileProc loadfileproc = NULL; + void* msgprocContext = NULL; int kmcmp::currentLine = 0; @@ -3068,7 +3073,7 @@ KMX_DWORD WriteCompiledKeyboard(PFILE_KEYBOARD fk, KMX_BYTE**data, size_t& dataS return CERR_None; } -KMX_DWORD ReadLine(FILE* fp_in , PKMX_WCHAR wstr, KMX_BOOL PreProcess) +KMX_DWORD ReadLine(KMX_BYTE* infile, int sz, int& offset, PKMX_WCHAR wstr, KMX_BOOL PreProcess) { KMX_DWORD len; PKMX_WCHAR p; @@ -3076,21 +3081,26 @@ KMX_DWORD ReadLine(FILE* fp_in , PKMX_WCHAR wstr, KMX_BOOL PreProcess) KMX_DWORD n; KMX_WCHAR currentQuotes = 0; KMX_WCHAR str[LINESIZE + 3]; - len = (KMX_DWORD)fread( str , 1 ,LINESIZE * 2,fp_in); - if (ferror(fp_in) ) return CERR_CannotReadInfile; - len /= 2; - str[len] = 0; auto cur = ftell(fp_in); - fseek(fp_in, 0, SEEK_END); - auto fsize = ftell(fp_in); - fseek(fp_in, cur, SEEK_SET); - if (cur == fsize) + if(offset >= sz) { + return CERR_EndOfFile; + } - // \r\n is still added here even though Linux doesn`t use \r. - // This is to ensure to still have a working windows-only-version - u16ncat(str, u"\r\n", _countof(str)); // I3481 // Always a "\r\n" to the EOF, avoids funny bugs + len = offset + LINESIZE*2 > sz ? sz-offset : LINESIZE*2; + memcpy(str, infile+offset, len); + offset += len; + len /= 2; + str[len] = 0; - if (len == 0) return CERR_EndOfFile; + if(offset == sz) { + // \r\n is still added here even though Linux doesn`t use \r. + // This is to ensure to still have a working windows-only-version + u16ncat(str, u"\r\n", _countof(str)); // I3481 // Always a "\r\n" to the EOF, avoids funny bugs + } + + if (len == 0) { + return CERR_EndOfFile; + } // neccessary to add this block for using on non-windows platforms (removes all \r for platforms that use \n instead of \r\n) for (p = str, n = 0; n < len; n++, p++) { @@ -3172,9 +3182,13 @@ KMX_DWORD ReadLine(FILE* fp_in , PKMX_WCHAR wstr, KMX_BOOL PreProcess) return (PreProcess ? CERR_None : CERR_LineTooLong); } - if (*p == L'\n') kmcmp::currentLine++; + kmcmp::currentLine++; - fseek(fp_in, -(int)(len * 2 - (int)(p - str) * 2 - 2), SEEK_CUR); + offset -= (int)(len * 2 - (int)(p - str) * 2 - 2); + if(offset >= sz) { + // If we've appended a \n, we can go past EOF + offset = sz; + } p--; while (p >= str && iswspace(*p)) p--; @@ -3427,81 +3441,39 @@ KMX_BOOL kmcmp::IsValidCallStore(PFILE_STORE fs) return i == 1; } -FILE* CreateTempFile() -{ - return tmpfile(); +/////////////////// + +bool hasPreamble(std::u16string result) { + return result.size() > 0 && result[0] == 0xFEFF; } -/////////////////// +bool UTF16TempFromUTF8(KMX_BYTE* infile, int sz, KMX_BYTE** tempfile, int *sz16) { + if(sz == 0) { + return FALSE; + } -FILE* UTF16TempFromUTF8(FILE* fp_in , KMX_BOOL hasPreamble) -{ - FILE *fp_out = CreateTempFile(); - if(fp_out == NULL) // I3228 // I3510 - { - fclose(fp_in); - return NULL; //return INVALID_HANDLE_VALUE; _S2 can I exchange that? + std::u16string result; + + try { + std::wstring_convert, char16_t> converter; + result = converter.from_bytes((char*)infile, (char*)infile+sz-1); + } catch(std::range_error e) { + std::wstring_convert, char16_t> converter; + result = converter.from_bytes((char*)infile, (char*)infile+sz-1); } - PKMX_BYTE buf, p; - PKMX_WCHAR outbuf, poutbuf; - KMX_DWORD len; - KMX_DWORD len2; - KMX_WCHAR prolog = 0xFEFF; - fwrite(&prolog,2, 1, fp_out); - - fseek(fp_in, 0, SEEK_END); - len = (KMX_DWORD)ftell(fp_in); - fseek(fp_in, 0, SEEK_SET); - if (hasPreamble) { - fseek( fp_in,3,SEEK_SET); // Cut off UTF-8 marker - len -= 3; - } - - buf = new KMX_BYTE[len + 1]; // null terminated - outbuf = new KMX_WCHAR[len + 1]; - - len2= (KMX_DWORD)fread(buf,1,len,fp_in); - if (len2) { - buf[len2] = 0; - p = buf; - poutbuf = outbuf; - if (hasPreamble) { - // We have a preamble, so we attempt to read as UTF-8 and allow conversion errors to be filtered. This is not great for a - // compiler but matches existing behaviour -- in future versions we may not do lenient conversion. - ConvertUTF8toUTF16(&p, &buf[len2], (UTF16 **)&poutbuf, (const UTF16 *)&outbuf[len], lenientConversion); - fwrite(outbuf, (KMX_DWORD)(poutbuf - outbuf) * 2 , 1, fp_out); - } - else { - // No preamble, so we attempt to read as strict UTF-8 and fall back to ANSI if that fails - ConversionResult cr = ConvertUTF8toUTF16(&p, &buf[len2], (UTF16 **)&poutbuf, (const UTF16 *)&outbuf[len], strictConversion); - if (cr == sourceIllegal) { - // Not a valid UTF-8 file, so fall back to ANSI - // AddCompileError(CHINT_NonUnicodeFile); - // note, while this message is defined, for now we will not emit it - // because we don't support HINT/INFO messages yet and we don't want - // this to cause a blocking compile at this stage - // do strtowstr only when no invalid characters are found - if( p==0){ - poutbuf = strtowstr((PKMX_STR)buf); - fwrite(poutbuf, (KMX_DWORD)u16len(poutbuf) * 2 , 1, fp_out); - delete[] poutbuf; - } - else - AddCompileError(CERR_InvalidCharacter); - } + if(hasPreamble(result)) { + *sz16 = result.size() * 2 - 1; + *tempfile = new KMX_BYTE[*sz16]; + memcpy(*tempfile, result.c_str() + 2, *sz16); - else { - fwrite(outbuf, (KMX_DWORD)(poutbuf - outbuf) * 2 , 1, fp_out); - } - } } - fclose( fp_in); - delete[] buf; - delete[] outbuf; - fseek( fp_out,2,SEEK_SET); - return fp_out; + *sz16 = result.size() * 2; + *tempfile = new KMX_BYTE[*sz16]; + memcpy(*tempfile, result.c_str(), *sz16); + + return TRUE; } PFILE_STORE FindSystemStore(PFILE_KEYBOARD fk, KMX_DWORD dwSystemID) diff --git a/developer/src/kmcmplib/src/CompilerInterfaces.cpp b/developer/src/kmcmplib/src/CompilerInterfaces.cpp index 71e1e895f2..fd297f4332 100644 --- a/developer/src/kmcmplib/src/CompilerInterfaces.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfaces.cpp @@ -11,14 +11,14 @@ #include "../../../../common/windows/cpp/include/ConvertUTF.h" #include "../../../../common/windows/cpp/include/keymanversion.h" -bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk); +bool CompileKeyboardHandle(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk); #ifdef __EMSCRIPTEN__ /* WASM interface for compiler message callback */ -EM_JS(int, wasm_msgproc, (int line, int msgcode, char* text, char* context), { +EM_JS(int, wasm_msgproc, (int line, int msgcode, const char* text, char* context), { const proc = globalThis[UTF8ToString(context)]; if(!proc || typeof proc != 'function') { console.log(`[${line}: ${msgcode}: ${UTF8ToString(text)}]`); @@ -28,7 +28,21 @@ EM_JS(int, wasm_msgproc, (int line, int msgcode, char* text, char* context), { } }); -int wasm_CompilerMessageProc(int line, uint32_t dwMsgCode, char* szText, void* context) { +EM_JS(bool, wasm_loadfileproc, (const char* filename, const char* baseFilename, void* buffer, int* bufferSize, char* context), { + const proc = globalThis[UTF8ToString(context)]; + if(!proc || typeof proc != 'function') { + return 0; + } else { + return proc(UTF8ToString(filename), UTF8ToString(baseFilename), buffer, bufferSize); + } +}); + +bool wasm_LoadFileProc(const char* filename, const char* baseFilename, void* buffer, int* bufferSize, void* context) { + char* msgProc = static_cast(context); + return wasm_loadfileproc(filename, baseFilename, buffer, bufferSize, msgProc); +} + +int wasm_CompilerMessageProc(int line, uint32_t dwMsgCode, const char* szText, void* context) { char* msgProc = static_cast(context); return wasm_msgproc(line, dwMsgCode, szText, msgProc); } @@ -61,7 +75,7 @@ WASM_COMPILER_RESULT kmcmp_wasm_compile(std::string pszInfile, const KMCMP_COMPI pszInfile.c_str(), options, wasm_CompilerMessageProc, - nullptr, //wasm_LoadFileProc, + wasm_LoadFileProc, intf.messageCallback.c_str(), kr ); @@ -116,8 +130,6 @@ EXTERN bool kmcmp_CompileKeyboard( KMCMP_COMPILER_RESULT& result ) { - FILE* fp_in = NULL; - KMX_CHAR str[260]; FILE_KEYBOARD fk; kmcmp::FSaveDebug = options.saveDebug; // I3681 @@ -126,7 +138,7 @@ EXTERN bool kmcmp_CompileKeyboard( kmcmp::FShouldAddCompilerVersion = options.shouldAddCompilerVersion; kmcmp::CompileTarget = options.target; - if (!messageProc || !pszInfile) { // TODO: add loadFileProc + if (!messageProc || !loadFileProc || !pszInfile) { AddCompileError(CERR_BadCallParams); return FALSE; } @@ -142,43 +154,58 @@ EXTERN bool kmcmp_CompileKeyboard( } msgproc = messageProc; - //TODO: loadfileproc = loadFileProc; + loadfileproc = loadFileProc; msgprocContext = (void*)procContext; kmcmp::currentLine = 0; kmcmp::nErrors = 0; - fp_in = Open_File(pszInfile, "rb"); - - if (fp_in == NULL) { + int sz; + if(!loadFileProc(pszInfile, "", nullptr, &sz, msgprocContext)) { AddCompileError(CERR_InfileNotExist); return FALSE; } - // Transfer the file to a memory stream for processing UTF-8 or ANSI to UTF-16? - // What about really large files? Transfer to a temp file... - if (!fread(str, 1, 3, fp_in)) { - fclose(fp_in); + if(sz < 3) { + // Technically, a 3 byte file can never be a valid .kmn, so we can shortcut + // here and avoid testing outside memory bounds for looking at BOM AddCompileError(CERR_CannotReadInfile); return FALSE; } - fseek(fp_in, 0, SEEK_SET); - if (str[0] == UTF8Sig[0] && str[1] == UTF8Sig[1] && str[2] == UTF8Sig[2]) - fp_in = UTF16TempFromUTF8(fp_in, TRUE); - else if (str[0] == UTF16Sig[0] && str[1] == UTF16Sig[1]) - fseek(fp_in, 2, SEEK_SET); - else - fp_in = UTF16TempFromUTF8(fp_in, FALSE); - if (fp_in == NULL) { - AddCompileError(CERR_CannotCreateTempfile); + KMX_BYTE* infile = new KMX_BYTE[sz]; + if(!infile) { + AddCompileError(CERR_CannotAllocateMemory); return FALSE; } + if(!loadFileProc(pszInfile, "", infile, &sz, msgprocContext)) { + delete[] infile; + AddCompileError(CERR_CannotReadInfile); + return FALSE; + } + + int offset = 0; + if(infile[0] == (KMX_BYTE) UTF16Sig[0] && infile[1] == (KMX_BYTE) UTF16Sig[1]) { + // UTF-16 source file + offset = 2; + } else { + // UTF-8 source file + KMX_BYTE* infile16; + int sz16; + if(!UTF16TempFromUTF8(infile, sz, &infile16, &sz16)) { + delete[] infile; + AddCompileError(CERR_CannotCreateTempfile); + return FALSE; + } + delete[] infile; + infile = infile16; + sz = sz16; + } kmcmp::CodeConstants = new kmcmp::NamedCodeConstants; - bool success = CompileKeyboardHandle(fp_in, &fk); + bool success = CompileKeyboardHandle(infile+offset, sz-offset, &fk); delete kmcmp::CodeConstants; - fclose(fp_in); + delete[] infile; if (kmcmp::nErrors > 0 || !success) { return FALSE; @@ -204,7 +231,7 @@ EXTERN bool kmcmp_CompileKeyboard( return TRUE; } -bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) +bool CompileKeyboardHandle(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk) { PKMX_WCHAR str, p; @@ -263,8 +290,10 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) AddStore(fk, TSS_CUSTOMKEYMANEDITION, u"0"); AddStore(fk, TSS_CUSTOMKEYMANEDITIONNAME, u"Keyman"); + int offset = 0; + // must preprocess for group and store names -> this isn't really necessary, but never mind! - while ((msg = ReadLine(fp_in, str, TRUE)) == CERR_None) + while ((msg = ReadLine(infile, sz, offset, str, TRUE)) == CERR_None) { p = str; switch (LineTokenType(&p)) @@ -301,7 +330,7 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) return FALSE; } - fseek( fp_in,2,SEEK_SET); + offset = 0; kmcmp::currentLine = 0; /* Reindex the list of codeconstants after stores added */ @@ -309,7 +338,7 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) kmcmp::CodeConstants->reindex(); /* ReadLine will automatically skip over $Keyman lines, and parse wrapped lines */ - while ((msg = ReadLine(fp_in, str, FALSE)) == CERR_None) + while ((msg = ReadLine(infile, sz, offset, str, FALSE)) == CERR_None) { msg = ParseLine(fk, str); if (msg != CERR_None) { diff --git a/developer/src/kmcmplib/src/compfile.h b/developer/src/kmcmplib/src/compfile.h index 595d1fecec..7c262be090 100644 --- a/developer/src/kmcmplib/src/compfile.h +++ b/developer/src/kmcmplib/src/compfile.h @@ -197,33 +197,4 @@ struct COMPILEMESSAGES { typedef COMPILEMESSAGES *PCOMPILEMESSAGES; -/* -struct TVersion -{ - //int MinVersion; // 0x0500 usually - //int CompilerVersion[4]; - //int MinCompilerVersion[4]; - int KeyboardVersion; // 0x0500 usually -}; - -extern TVersion FVersionInfo; -*/ - -/* -#define bstrcpy(c,d) (LPBYTE)strcpy((LPSTR)(c),(LPSTR)(d)) -#define bstrlen(c) strlen((LPSTR)(c)) -#define bstrcmp(c,d) strcmp((LPSTR)(c),(LPSTR)(d)) -#define bstrncmp(c,d,n) strncmp((LPSTR)(c),(LPSTR)(d),(n)) -#define bstrnicmp(c,d,n) strnicmp((LPSTR)(c),(LPSTR)(d),(n)) -#define bstricmp(c,d) stricmp((LPSTR)(c),(LPSTR)(d)) -#define bstrchr(c,ch) (LPBYTE)strchr((LPSTR)(c),(char)ch) -#define bstrncpy(c,d,n) (LPBYTE)strncpy((LPSTR)(c),(LPSTR)(d),(n)) -#define bstrtok(c,d) (LPBYTE)strtok((LPSTR)(c),(LPSTR)(d)) -#define bstrcat(c,d) (LPBYTE)strcat((LPSTR)(c),(LPSTR)(d)) -#define bstrncat(c,d,n) (LPBYTE)strncat((LPSTR)(c),(LPSTR)(d),(n)) -#define bstrrev(c) (LPBYTE)strrev((LPSTR)(c)) -#define batoi(c) atoi((LPSTR)(c)) -#define bstrtol(c,d,n) strtol((LPSTR)(c),(LPSTR *)(d),(n)) -*/ - #endif // _COMPFILE_H diff --git a/developer/src/kmcmplib/src/kmcmplib.h b/developer/src/kmcmplib/src/kmcmplib.h index 78e945ee0d..70718f98bc 100644 --- a/developer/src/kmcmplib/src/kmcmplib.h +++ b/developer/src/kmcmplib/src/kmcmplib.h @@ -24,6 +24,7 @@ namespace kmcmp { } extern kmcmp_CompilerMessageProc msgproc; +extern kmcmp_LoadFileProc loadfileproc; extern void* msgprocContext; extern KMX_BOOL AWarnDeprecatedCode_GLOBAL_LIB; @@ -40,10 +41,10 @@ KMX_BOOL AddCompileError(KMX_DWORD msg); PKMX_WCHAR strtowstr(PKMX_STR in); PFILE_STORE FindSystemStore(PFILE_KEYBOARD fk, KMX_DWORD dwSystemID); -FILE* UTF16TempFromUTF8(FILE* fp_in , KMX_BOOL hasPreamble); +bool UTF16TempFromUTF8(KMX_BYTE* infile, int sz, KMX_BYTE** tempfile, int *sz16); KMX_DWORD WriteCompiledKeyboard(PFILE_KEYBOARD fk, KMX_BYTE**data, size_t& dataSize); KMX_DWORD AddStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, const KMX_WCHAR * str, KMX_DWORD *dwStoreID= NULL); -KMX_DWORD ReadLine(FILE* fp_in , PKMX_WCHAR wstr, KMX_BOOL PreProcess); +KMX_DWORD ReadLine(KMX_BYTE* infile, int sz, int& offset, PKMX_WCHAR wstr, KMX_BOOL PreProcess); KMX_DWORD ParseLine(PFILE_KEYBOARD fk, PKMX_WCHAR str); KMX_DWORD ProcessGroupLine(PFILE_KEYBOARD fk, PKMX_WCHAR p); KMX_DWORD ProcessGroupFinish(PFILE_KEYBOARD fk); diff --git a/developer/src/kmcmplib/src/meson.build b/developer/src/kmcmplib/src/meson.build index 8264c3d28e..727d6831e6 100644 --- a/developer/src/kmcmplib/src/meson.build +++ b/developer/src/kmcmplib/src/meson.build @@ -7,6 +7,7 @@ # TODO: is this required? It should be Keyman Core only defns += ['-DKMN_KBP_EXPORTING'] version_res = [] +lib_links = [] if cpp_compiler.get_id() == 'gcc' or cpp_compiler.get_id() == 'clang' warns += [ @@ -24,12 +25,13 @@ endif name_suffix = [] if cpp_compiler.get_id() == 'emscripten' - links += ['-lnodefs.js', '-sMODULARIZE', '-sEXPORT_ES6', '--whole-archive', '--bind', '-sEXPORTED_RUNTIME_METHODS=[\'UTF8ToString\']'] + lib_links = ['--whole-archive', '--bind', '-sMODULARIZE', '-sEXPORT_ES6'] + links += ['-lnodefs.js', '--bind', '-sEXPORTED_RUNTIME_METHODS=[\'UTF8ToString\']'] # tests are building as ES6 so we need to declare the file extension # note that meson currently struggles with the sanitycheckc_cross.exe # program, because it has a hard coded extension (.exe) which is not # valid for node programs in module mode. - name_suffix = '.mjs' + # name_suffix = '.mjs' endif icu = subproject('icu-for-uset', default_options: [ 'default_library=static', 'cpp_std=c++17', 'warning_level=0', 'werror=false']) @@ -63,7 +65,7 @@ lib = library('kmcmplib', version_res, cpp_args: defns + warns + flags, - link_args: links, + link_args: links + lib_links, version: meson.project_version(), include_directories: inc, install: true, diff --git a/developer/src/kmcmplib/tests/api-test.cpp b/developer/src/kmcmplib/tests/api-test.cpp index 4bb0276a79..b347773220 100644 --- a/developer/src/kmcmplib/tests/api-test.cpp +++ b/developer/src/kmcmplib/tests/api-test.cpp @@ -18,13 +18,14 @@ #include #include "../src/compfile.h" #include +#include "../src/filesystem.h" void setup(); -void test_kmcmp_CompileKeyboard(); +void test_kmcmp_CompileKeyboard(char *kmn_file); std::vector error_vec; -int msgproc(int line, uint32_t dwMsgCode, char* szText, void* context) { +int msgproc(int line, uint32_t dwMsgCode, const char* szText, void* context) { error_vec.push_back(dwMsgCode); const char*t = "unknown"; switch(dwMsgCode & 0xF000) { @@ -37,9 +38,42 @@ int msgproc(int line, uint32_t dwMsgCode, char* szText, void* context) { return 1; } +bool loadfileProc(const char* filename, const char* baseFilename, void* data, int* size, void* context) { + FILE* fp = Open_File(filename, "rb"); + if(!fp) { + return false; + } + + if(!data) { + // return size + if(fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + return false; + } + *size = ftell(fp); + if(*size == -1L) { + fclose(fp); + return false; + } + } else { + // return data + if(fread(data, 1, *size, fp) != *size) { + fclose(fp); + return false; + } + } + fclose(fp); + return true; +} + int main(int argc, char *argv[]) { + if(argc < 1) { + puts("Usage: api-test "); + puts("Warning: blank_keyboard will be overwritten"); + return 1; + } setup(); - test_kmcmp_CompileKeyboard(); + test_kmcmp_CompileKeyboard(argv[1]); return 0; } @@ -48,13 +82,9 @@ void setup() { error_vec.clear(); } -void test_kmcmp_CompileKeyboard() { - char kmn_file[L_tmpnam], kmx_file[L_tmpnam]; - tmpnam(kmn_file); - tmpnam(kmx_file); - +void test_kmcmp_CompileKeyboard(char *kmn_file) { // Create an empty file - FILE *fp = fopen(kmn_file, "w"); + FILE *fp = Open_File(kmn_file, "wb"); fclose(fp); // It should fail when a zero-byte file is passed in @@ -65,7 +95,7 @@ void test_kmcmp_CompileKeyboard() { options.warnDeprecatedCode = true; options.shouldAddCompilerVersion = false; options.target = CKF_KEYMAN; - assert(!kmcmp_CompileKeyboard(kmn_file, options, msgproc, nullptr, nullptr, result)); + assert(!kmcmp_CompileKeyboard(kmn_file, options, msgproc, loadfileProc, nullptr, result)); assert(error_vec.size() == 1); assert(error_vec[0] == CERR_CannotReadInfile); diff --git a/developer/src/kmcmplib/tests/kmcompxtest.cpp b/developer/src/kmcmplib/tests/kmcompxtest.cpp index 87d9e53cf7..c5d189798b 100644 --- a/developer/src/kmcmplib/tests/kmcompxtest.cpp +++ b/developer/src/kmcmplib/tests/kmcompxtest.cpp @@ -13,6 +13,7 @@ #include #include #include +#include "../src/filesystem.h" #ifdef _MSC_VER #else @@ -28,7 +29,7 @@ vector < int > error_vec; #define CERR_WARNING 0x00002000 #define CERR_HINT 0x00001000 -int msgproc(int line, uint32_t dwMsgCode, char* szText, void* context) +int msgproc(int line, uint32_t dwMsgCode, const char* szText, void* context) { error_vec.push_back(dwMsgCode); const char*t = "unknown"; @@ -42,6 +43,34 @@ int msgproc(int line, uint32_t dwMsgCode, char* szText, void* context) return 1; } +bool loadfileProc(const char* filename, const char* baseFilename, void* data, int* size, void* context) { + FILE* fp = Open_File(filename, "rb"); + if(!fp) { + return false; + } + + if(!data) { + // return size + if(fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + return false; + } + *size = ftell(fp); + if(*size == -1L) { + fclose(fp); + return false; + } + } else { + // return data + if(fread(data, 1, *size, fp) != *size) { + fclose(fp); + return false; + } + } + fclose(fp); + return true; +} + #include "../src/filesystem.h" int main(int argc, char *argv[]) @@ -79,7 +108,7 @@ int main(int argc, char *argv[]) options.shouldAddCompilerVersion = false; options.target = CKF_KEYMAN; - if(kmcmp_CompileKeyboard(kmn_file, options, msgproc, nullptr, nullptr, result)) { + if(kmcmp_CompileKeyboard(kmn_file, options, msgproc, loadfileProc, nullptr, result)) { char* testname = strrchr( (char*) kmn_file, '/') + 1; if(strncmp(testname, pfirst5, 5) == 0){ return __LINE__; // exit code: CERR_ in Name + no Error found diff --git a/developer/src/kmcmplib/tests/meson.build b/developer/src/kmcmplib/tests/meson.build index 49924f2d78..2468ac53b1 100644 --- a/developer/src/kmcmplib/tests/meson.build +++ b/developer/src/kmcmplib/tests/meson.build @@ -113,10 +113,10 @@ apitest = executable('api-test', 'api-test.cpp', name_suffix: name_suffix, link_args: links + tests_flags, objects: lib.extract_all_objects(), - dependencies: icuuc_dep, + dependencies: icuuc_dep ) -test('api-test', apitest) +test('api-test', apitest, args: [output_path / 'blank_keyboard.kmx']) usetapitest = executable('uset-api-test', 'uset-api-test.cpp', cpp_args: defns, -- GitLab From 9b4ca1aebd76286f7a223b757d306b5097f9850e Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 26 May 2023 19:32:14 +0200 Subject: [PATCH 155/214] chore(linux): Move build steps to build.sh Closes #8712. --- linux/keyman-config/Makefile | 53 +++++----------------- linux/keyman-config/build.sh | 70 ++++++++++++++++++++++++++++-- linux/scripts/install.sh | 16 +++---- linux/scripts/package-build.inc.sh | 5 +-- linux/scripts/reconf.sh | 2 +- 5 files changed, 86 insertions(+), 60 deletions(-) diff --git a/linux/keyman-config/Makefile b/linux/keyman-config/Makefile index 41eaab30ef..f057dcad0c 100644 --- a/linux/keyman-config/Makefile +++ b/linux/keyman-config/Makefile @@ -1,49 +1,19 @@ #!/usr/bin/make -default: clean version man langtags - python3 setup.py build - -langtags: - cd buildtools && python3 ./build-langtags.py +default: + ./build.sh clean build install: - if [ -n "${SUDO_USER}" ]; then \ - make install-sudo; \ - else \ - make install-temp; \ - fi - -install-sudo: # run as sudo - pip3 install qrcode sentry-sdk - # eventually change this to: pip3 install . - python3 setup.py install - # install icons - mkdir -p /usr/local/share/keyman/icons - cp keyman_config/icons/* /usr/local/share/keyman/icons - # install man pages - mkdir -p /usr/local/share/man/man1 - cp ../../debian/man/*.1 /usr/local/share/man/man1 - -install-temp: - mkdir -p /tmp/keyman/$(shell python3 -c 'import sys;import os;pythonver="python%d.%d" % (sys.version_info[0], sys.version_info[1]);sitedir = os.path.join("lib", pythonver, "site-packages");print(sitedir)') - # when we no longer have to support old pip version (python > 3.6) change this to: - # pip3 install --prefix /tmp/keyman . - PYTHONUSERBASE=/tmp/keyman python3 setup.py install --user - -uninstall: clean # run as sudo - rm -rf /usr/local/share/keyman/icons - rm -f /usr/local/share/man/man1/km-*.1 - pip3 uninstall keyman_config - rm -f /usr/local/bin/km-config - rm -f /usr/local/bin/km-kvk2ldml - rm -f /usr/local/bin/km-package-get - rm -f /usr/local/bin/km-package-install - rm -f /usr/local/bin/km-package-list-installed - rm -f /usr/local/bin/km-package-uninstall + ./build.sh install + +uninstall: # run as sudo + ./build.sh uninstall clean: - -rm -rf dist make_deb build keyman_config/version.py *.egg-info __pycache__ \ - keyman_config/standards/lang_tags_map.py + ./build.sh clean + +check: + ./build.sh test devdist: version python3 setup.py egg_info -b.`TZ=UTC git log -1 --pretty=format:%cd --date=format-local:%Y%m%d%H%M` sdist @@ -93,6 +63,3 @@ $(MOFILES): %/LC_MESSAGES/keyman-config.mo: %.po msgfmt -v --check --output-file=$@ $^ compile-po: $(MOFILES) - -check: - ./run-tests.sh diff --git a/linux/keyman-config/build.sh b/linux/keyman-config/build.sh index 38cf22e917..aba4ebcd41 100755 --- a/linux/keyman-config/build.sh +++ b/linux/keyman-config/build.sh @@ -24,9 +24,71 @@ cd "$THIS_SCRIPT_PATH" builder_describe_outputs \ build "/linux/keyman-config/keyman_config/standards/lang_tags_map.py" -builder_run_action clean make clean +clean_action() { + rm -rf dist make_deb build keyman_config/version.py ./*.egg-info __pycache__ \ + keyman_config/standards/lang_tags_map.py +} + +build_action() { + builder_echo "Create version.py" + pushd keyman_config + sed \ + -e "s/_VERSION_/${VERSION}/g" \ + -e "s/_VERSIONWITHTAG_/${VERSION_WITH_TAG}/g" \ + -e "s/_VERSIONGITTAG_/${VERSION_GIT_TAG}/g" \ + -e "s/_MAJORVERSION_/${VERSION_MAJOR}/g" \ + -e "s/_RELEASEVERSION_/${VERSION_RELEASE}/g" \ + -e "s/_TIER_/${TIER}/g" \ + -e "s/_ENVIRONMENT_/${VERSION_ENVIRONMENT}/g" \ + -e "s/_UPLOADSENTRY_/${UPLOAD_SENTRY}/g" \ + version.py.in > version.py + popd + pushd buildtools + builder_echo "Create lang_tags_map.py" + python3 ./build-langtags.py + popd + builder_echo "Building man pages" + ./build-help.sh --man --no-reconf + builder_echo "Building keyman-config" + python3 setup.py build +} + +install_action() { + if [ -n "${SUDO_USER:-}" ]; then + pip3 install qrcode sentry-sdk + # eventually change this to: pip3 install . + python3 setup.py install + # install icons + mkdir -p /usr/local/share/keyman/icons + cp keyman_config/icons/* /usr/local/share/keyman/icons + # install man pages + mkdir -p /usr/local/share/man/man1 + cp ../../debian/man/*.1 /usr/local/share/man/man1 + else + mkdir -p "/tmp/keyman/$(python3 -c 'import sys;import os;pythonver="python%d.%d" % (sys.version_info[0], sys.version_info[1]);sitedir = os.path.join("lib", pythonver, "site-packages");print(sitedir)')" + # when we no longer have to support old pip version (python > 3.6) change this to: + # pip3 install --prefix /tmp/keyman . + PYTHONUSERBASE=/tmp/keyman python3 setup.py install --user + fi +} + +uninstall_action() { + # run as sudo + clean_action + rm -rf /usr/local/share/keyman/icons + rm -f /usr/local/share/man/man1/km-*.1 + pip3 uninstall keyman_config + rm -f /usr/local/bin/km-config + rm -f /usr/local/bin/km-kvk2ldml + rm -f /usr/local/bin/km-package-get + rm -f /usr/local/bin/km-package-install + rm -f /usr/local/bin/km-package-list-installed + rm -f /usr/local/bin/km-package-uninstall +} + +builder_run_action clean clean_action builder_run_action configure # nothing to do -builder_run_action build make +builder_run_action build build_action builder_run_action test ./run-tests.sh -builder_run_action install make install -builder_run_action uninstall make uninstall +builder_run_action install install_action +builder_run_action uninstall uninstall_action diff --git a/linux/scripts/install.sh b/linux/scripts/install.sh index 40f2eb8f5b..55074f4848 100755 --- a/linux/scripts/install.sh +++ b/linux/scripts/install.sh @@ -15,7 +15,7 @@ INSTALLDIR=${INSTALLDIR:-"/usr/local"} if [[ "${SUDOINSTALL}" != "no" ]]; then if [ "$EUID" -ne 0 ] then - echo "Please run 'make un/install' with sudo" + echo "Please run 'build.sh un/install' with sudo" exit fi fi @@ -24,7 +24,7 @@ if [ -f "/usr/share/ibus/component/keyman.xml" ] && [ "${SUDOINSTALL}" == "yes" if grep -Fq "/usr/lib/ibus" /usr/share/ibus/component/keyman.xml then echo "component file is in ibus-keyman package version so move it" - echo "run 'sudo make uninstall' to put it back" + echo "run 'sudo build.sh uninstall' to put it back" mv /usr/share/ibus/component/keyman.xml /usr/share/doc/ibus-keyman/ else echo "component file is local one so overwrite it" @@ -37,10 +37,10 @@ cd "$BASEDIR" cd ibus-keyman if [[ "${SUDOINSTALL}" == "uninstall" ]]; then - echo "doing make uninstall of ibus-keyman" + echo "doing build.sh uninstall of ibus-keyman" ./build.sh uninstall else - echo "doing make install of ibus-keyman" + echo "doing build.sh install of ibus-keyman" ./build.sh install fi cd "$BASEDIR" @@ -49,20 +49,20 @@ cd keyman-config echo "SUDOINSTALL: ${SUDOINSTALL}" if [[ "${SUDOINSTALL}" == "yes" ]]; then if [ ! -d build ]; then - echo "keyman-config must be built before it is installed. Run 'make configure' if needed then 'make'" + echo "keyman-config must be built before it is installed. Run 'build.sh configure build'." exit 1 fi echo "doing sudo glib-compile-schemas for keyman-config" cp com.keyman.gschema.xml /usr/share/glib-2.0/schemas/ glib-compile-schemas /usr/share/glib-2.0/schemas/ echo "doing sudo install of keyman-config" - make install + ./build.sh install elif [[ "${SUDOINSTALL}" == "uninstall" ]]; then echo "doing sudo uninstall of keyman-config" - make uninstall + ./build.sh uninstall else echo "doing /tmp install of keyman-config" - make install-temp + ./build.sh install fi cd "$BASEDIR" diff --git a/linux/scripts/package-build.inc.sh b/linux/scripts/package-build.inc.sh index 39ea70f7d1..6c249891c1 100644 --- a/linux/scripts/package-build.inc.sh +++ b/linux/scripts/package-build.inc.sh @@ -28,10 +28,7 @@ function downloadSource() { if [ "${proj:=}" == "keyman" ]; then cd "${BASEDIR}" || exit - fi - - if [ "${proj}" == "keyman" ]; then - make clean + ./build.sh clean fi # Update tier in Debian watch files (replacing any previously set tier) and remove comment diff --git a/linux/scripts/reconf.sh b/linux/scripts/reconf.sh index cd74571a4a..4e4f5c1b11 100755 --- a/linux/scripts/reconf.sh +++ b/linux/scripts/reconf.sh @@ -21,7 +21,7 @@ cd "$BASEDIR/ibus-keyman" ./build.sh clean configure cd "$BASEDIR/keyman-config" -make clean +./build.sh clean cd keyman_config sed \ -- GitLab From fd562019dd18f577cb3a38d82b4765b2da773e7d Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 30 May 2023 11:35:24 +0200 Subject: [PATCH 156/214] chore(linux): Use build.sh for Debian packaging --- linux/debian/rules | 12 ++++++------ linux/keyman-config/build.sh | 10 +++++++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/linux/debian/rules b/linux/debian/rules index ab4ad409e4..db1f925017 100755 --- a/linux/debian/rules +++ b/linux/debian/rules @@ -9,7 +9,9 @@ export PYBUILD_INSTALL_ARGS=--install-scripts=/usr/share/keyman-config/ export KEYMAN_PKG_BUILD=1 +export HOME=$(shell mktemp -d) export XDG_DATA_HOME=$(shell mktemp -d) +export XDG_CONFIG_HOME=$(shell mktemp -d) # xenial needs this to be explicit export LC_ALL=C.UTF-8 @@ -32,26 +34,23 @@ override_dh_auto_configure: --wrap-mode=nodownload --prefix=/usr --sysconfdir=/etc --localstatedir=/var linux/keyman-system-service/build.sh configure -- \ --wrap-mode=nodownload --prefix=/usr --sysconfdir=/etc --localstatedir=/var - # keyman-config + linux/keyman-config/build.sh configure override_dh_auto_build: core/build.sh --no-tests build:arch linux/ibus-keyman/build.sh build linux/keyman-system-service/build.sh build - # keyman-config + linux/keyman-config/build.sh build cd linux/keyman-config && \ - make man && \ sed -i -e "s/^__pkgversion__ = \"[^\"]*\"/__pkgversion__ = \"$(DEB_VERSION)\"/g" keyman_config/version.py && \ make compile-po - dh_auto_build --sourcedir=linux/keyman-config --buildsystem=pybuild $@ override_dh_auto_test: ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) core/build.sh --no-tests test:arch linux/ibus-keyman/build.sh test linux/keyman-system-service/build.sh test - # keyman-config - dh_auto_test --sourcedir=linux/keyman-config --buildsystem=pybuild $@ + linux/keyman-config/build.sh test endif override_dh_auto_install: @@ -63,6 +62,7 @@ override_dh_auto_install: install -d $(CURDIR)/debian/keyman/usr/share/ cp -r linux/keyman-config/locale/ $(CURDIR)/debian/keyman/usr/share/ rm $(CURDIR)/debian/keyman/usr/share/locale/*.po* + # Don't call `build.sh install` - dh_auto_install does some extra smarts dh_auto_install --sourcedir=linux/keyman-config --buildsystem=pybuild $@ # Unfortunately bash-completion 2.10 (focal) doesn't yet provide dh-sequence-bash-completion, # which we could add as build-dependency, so we'll have to explicitly call diff --git a/linux/keyman-config/build.sh b/linux/keyman-config/build.sh index aba4ebcd41..23d138b28e 100755 --- a/linux/keyman-config/build.sh +++ b/linux/keyman-config/build.sh @@ -44,8 +44,12 @@ build_action() { version.py.in > version.py popd pushd buildtools - builder_echo "Create lang_tags_map.py" - python3 ./build-langtags.py + if [ -f build-langtags.py ]; then + builder_echo "Create lang_tags_map.py" + python3 ./build-langtags.py + else + builder_echo "Skip building lang_tags_map.py during package build" + fi popd builder_echo "Building man pages" ./build-help.sh --man --no-reconf @@ -68,7 +72,7 @@ install_action() { mkdir -p "/tmp/keyman/$(python3 -c 'import sys;import os;pythonver="python%d.%d" % (sys.version_info[0], sys.version_info[1]);sitedir = os.path.join("lib", pythonver, "site-packages");print(sitedir)')" # when we no longer have to support old pip version (python > 3.6) change this to: # pip3 install --prefix /tmp/keyman . - PYTHONUSERBASE=/tmp/keyman python3 setup.py install --user + PYTHONUSERBASE=${DESTDIR:-/tmp/keyman} python3 setup.py install --user fi } -- GitLab From ccba767e2e17e8f6128a6a987c40b34ac15544f6 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 30 May 2023 17:18:12 +0200 Subject: [PATCH 157/214] chore(linux): Allow to run tests when package building with sbuild --- linux/keyman-config/run-tests.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux/keyman-config/run-tests.sh b/linux/keyman-config/run-tests.sh index 3b8664512a..b390ce613b 100755 --- a/linux/keyman-config/run-tests.sh +++ b/linux/keyman-config/run-tests.sh @@ -1,6 +1,9 @@ #!/bin/bash PYTHONPATH=.:$PYTHONPATH +XDG_CONFIG_HOME=$(mktemp --directory) +export XDG_CONFIG_HOME + if [ -n "$TEAMCITY_VERSION" ]; then if ! pip3 list --format=columns | grep -q teamcity-messages; then pip3 install teamcity-messages @@ -9,3 +12,5 @@ if [ -n "$TEAMCITY_VERSION" ]; then else python3 -m unittest discover -v -s tests -p test_*.py fi + +rm -rf "$XDG_CONFIG_HOME" -- GitLab From c6f4541c839b54bfc66c5309fe9b85e8e1dbedf3 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 26 May 2023 18:36:29 +0200 Subject: [PATCH 158/214] feat(linux): Fix unit tests --- .../tests/test_gnome_keyboards_util.py | 4 +- linux/keyman-config/tests/test_install_kmp.py | 34 +++++----- .../tests/test_package_install_completion.py | 67 ++++++++++--------- 3 files changed, 57 insertions(+), 48 deletions(-) diff --git a/linux/keyman-config/tests/test_gnome_keyboards_util.py b/linux/keyman-config/tests/test_gnome_keyboards_util.py index b5a0cac842..a53908cdd3 100644 --- a/linux/keyman-config/tests/test_gnome_keyboards_util.py +++ b/linux/keyman-config/tests/test_gnome_keyboards_util.py @@ -9,14 +9,14 @@ class GnomeKeyboardsUtilTests(unittest.TestCase): def setUp(self): _reset_gnome_shell() - @patch('keyman_config.os.system') + @patch('os.system') def test_IsGnomeShell_RunningGnomeShell(self, mockSystem): # Setup mockSystem.return_value = 0 # Execute/Verify self.assertEqual(is_gnome_shell(), True) - @patch('keyman_config.os.system') + @patch('os.system') def test_IsGnomeShell_NotRunningGnomeShell(self, mockSystem): # Setup mockSystem.return_value = 1 diff --git a/linux/keyman-config/tests/test_install_kmp.py b/linux/keyman-config/tests/test_install_kmp.py index 2f250550cd..d1e10bd645 100644 --- a/linux/keyman-config/tests/test_install_kmp.py +++ b/linux/keyman-config/tests/test_install_kmp.py @@ -262,13 +262,11 @@ class InstallKmpTests(unittest.TestCase): def test_InstallKmp_FutureKeymanVersion(self): # Setup - workdir = tempfile.TemporaryDirectory().name - os.makedirs(workdir) - packagedir = tempfile.TemporaryDirectory().name - os.makedirs(packagedir) - self.mockGetKeyboardDir.return_value = packagedir - kmpfile = self._createEmptyKmp(workdir) - self._createKmpJson(packagedir, ', "fileVersion": "99.0"') + workdir = tempfile.TemporaryDirectory() + packagedir = tempfile.TemporaryDirectory() + self.mockGetKeyboardDir.return_value = packagedir.name + kmpfile = self._createEmptyKmp(workdir.name) + self._createKmpJson(packagedir.name, ', "fileVersion": "99.0"') # Execute with self.assertRaises(InstallError) as context: @@ -278,22 +276,24 @@ class InstallKmpTests(unittest.TestCase): self.assertTrue('foo.kmp requires Keyman 99.0 or higher' in context.exception.message) self.mockInstallToIbus.assert_not_called() + # Teardown + workdir.cleanup() + packagedir.cleanup() + def test_InstallKmp(self): for testcase in [ {'name': 'PreviousKeymanVersion', 'fileVersion': ', "fileVersion": "7.0"'}, - {'name': 'SameKeymanVersion', 'fileVersion': ', "fileVersion": "' + __version__ + '"'}, + {'name': 'SameKeymanVersion', 'fileVersion': f', "fileVersion": "{__version__}"'}, {'name': 'NoFileVersion', 'fileVersion': ''} ]: with self.subTest(msg=testcase['name'], data=testcase['fileVersion']): # Setup self.mockInstallToIbus.reset_mock() - workdir = tempfile.TemporaryDirectory().name - os.makedirs(workdir) - packagedir = tempfile.TemporaryDirectory().name - os.makedirs(packagedir) - self.mockGetKeyboardDir.return_value = packagedir - kmpfile = self._createEmptyKmp(workdir) - self._createKmpJson(packagedir, testcase['fileVersion']) + workdir = tempfile.TemporaryDirectory() + packagedir = tempfile.TemporaryDirectory() + self.mockGetKeyboardDir.return_value = packagedir.name + kmpfile = self._createEmptyKmp(workdir.name) + self._createKmpJson(packagedir.name, testcase['fileVersion']) # Execute InstallKmp()._install_kmp(kmpfile, 'km', InstallLocation.User) @@ -301,6 +301,10 @@ class InstallKmpTests(unittest.TestCase): # Verify self.mockInstallToIbus.assert_called_once() + # Teardown + workdir.cleanup() + packagedir.cleanup() + if __name__ == '__main__': unittest.main() diff --git a/linux/keyman-config/tests/test_package_install_completion.py b/linux/keyman-config/tests/test_package_install_completion.py index 97238e3dc2..61374a6c66 100644 --- a/linux/keyman-config/tests/test_package_install_completion.py +++ b/linux/keyman-config/tests/test_package_install_completion.py @@ -2,7 +2,7 @@ import os import tempfile import unittest -from unittest.mock import patch, ANY +from unittest.mock import patch from importlib.machinery import SourceFileLoader from importlib.util import module_from_spec, spec_from_loader @@ -10,17 +10,11 @@ from importlib.util import module_from_spec, spec_from_loader class PackageInstallCompletionTests(unittest.TestCase): def setUp(self): - patcher1 = patch('keyman_config.install_kmp.extract_kmp') - self.mockExtractKmp = patcher1.start() - self.addCleanup(patcher1.stop) - patcher2 = patch('keyman_config.kmpmetadata.get_metadata') - self.mockGetMetadata = patcher2.start() - self.addCleanup(patcher2.stop) - + self.mockExtractKmp = self._setupMock('keyman_config.install_kmp.extract_kmp') + self.mockGetMetadata = self._setupMock('keyman_config.kmpmetadata.get_metadata') loader = SourceFileLoader('km_package_install', os.path.join(os.path.dirname( os.path.abspath(__file__)), '../km-package-install')) - spec = spec_from_loader(loader.name, loader) - if spec: + if spec := spec_from_loader(loader.name, loader): self.mod = module_from_spec(spec) loader.exec_module(self.mod) @@ -29,32 +23,43 @@ class PackageInstallCompletionTests(unittest.TestCase): self.cacheDir = os.path.join(self.tempDir.name, 'keyman') os.makedirs(self.cacheDir) + def tearDown(self): + self.tempDir.cleanup() + + def _setupMock(self, arg0): + patcher = patch(arg0) + result = patcher.start() + self.addCleanup(patcher.stop) + return result + def _list_languages_for_keyboard_impl(self, packageId): return self.mod._list_languages_for_keyboard_impl(packageId, 'someDir') def test_PackageCompletionNoLanguage(self): - open(os.path.join(self.cacheDir, 'foo'), 'w') - self.mockGetMetadata.return_value = (None, None, None, [{}], None) - result = self._list_languages_for_keyboard_impl('foo') - self.assertEqual(result, "") + with open(os.path.join(self.cacheDir, 'foo'), 'w'): + self.mockGetMetadata.return_value = (None, None, None, [{}], None) + result = self._list_languages_for_keyboard_impl('foo') + self.assertEqual(result, "") def test_PackageCompletionOneLanguage(self): - open(os.path.join(self.cacheDir, 'khmer_angkor'), 'w') - self.mockGetMetadata.return_value = ( - None, None, None, - [{'languages': [{'name': 'Central Khmer (Khmer, Cambodia)', 'id': 'km'}]}], - None) - result = self._list_languages_for_keyboard_impl('khmer_angkor') - self.assertEqual(result, "km") + with open(os.path.join(self.cacheDir, 'khmer_angkor'), 'w'): + self.mockGetMetadata.return_value = ( + None, None, None, + [{'languages': [{'name': 'Central Khmer (Khmer, Cambodia)', 'id': 'km'}]}], + None + ) + result = self._list_languages_for_keyboard_impl('khmer_angkor') + self.assertEqual(result, "km") def test_PackageCompletionMultipleLanguages(self): - open(os.path.join(self.cacheDir, 'sil_euro_latin'), 'w') - self.mockGetMetadata.return_value = ( - None, None, None, - [{'languages': [ - {'name': 'English', 'id': 'en'}, - {'name': 'French', 'id': 'fr'}, - {'name': 'German', 'id': 'de'}]}], - None) - result = self._list_languages_for_keyboard_impl('sil_euro_latin') - self.assertEqual(result, 'en\nfr\nde') + with open(os.path.join(self.cacheDir, 'sil_euro_latin'), 'w'): + self.mockGetMetadata.return_value = ( + None, None, None, + [{'languages': [ + {'name': 'English', 'id': 'en'}, + {'name': 'French', 'id': 'fr'}, + {'name': 'German', 'id': 'de'}]}], + None + ) + result = self._list_languages_for_keyboard_impl('sil_euro_latin') + self.assertEqual(result, 'en\nfr\nde') -- GitLab From 4a0f061d4dec8523ad5f5f1edc4dcec7b4d310ac Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 6 Jan 2023 18:48:32 +0100 Subject: [PATCH 159/214] feat(linux): Use StackSidebar for km-config This change displays tabs at the left. It also adds a dummy "Options" page which isn't implemented yet. --- .../keyman_config/view_installed.py | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/linux/keyman-config/keyman_config/view_installed.py b/linux/keyman-config/keyman_config/view_installed.py index 01b1a59b89..ddb13239b0 100755 --- a/linux/keyman-config/keyman_config/view_installed.py +++ b/linux/keyman-config/keyman_config/view_installed.py @@ -94,7 +94,7 @@ class ViewInstalledWindowBase(Gtk.Window): self.close() def run(self): - self.resize(576, 324) + self.resize(776, 424) self.connect("destroy", Gtk.main_quit) self.show_all() Gtk.main() @@ -191,23 +191,41 @@ class ViewInstalledWindow(ViewInstalledWindowBase): bbox_top.add(self.options_button) vbox.pack_start(bbox_top, False, False, 12) + hbox.pack_start(vbox, False, False, 12) - bbox_bottom = Gtk.ButtonBox(spacing=12, orientation=Gtk.Orientation.VERTICAL) - bbox_bottom.set_layout(Gtk.ButtonBoxStyle.END) + outerHbox = Gtk.HBox() + sidebar = Gtk.StackSidebar() + stack = Gtk.Stack() - button = Gtk.Button.new_with_mnemonic(_("_Refresh")) - button.set_tooltip_text(_("Refresh keyboard list")) - button.connect("clicked", self.on_refresh_clicked) + outerHbox.pack_start(sidebar, False, False, 0) + outerHbox.pack_end(Gtk.Separator(), False, False, 0) + outerHbox.pack_end(stack, True, True, 0) + stack.set_hexpand(True) + stack.set_vexpand(True) + sidebar.set_stack(stack) + + stack.add_titled(hbox, "KeyboardLayouts", _("Keyboard Layouts")) + stack.add_titled(Gtk.Label("TODO - Options"), "Options", _("Options")) + + outmostVBox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + outmostVBox.pack_start(outerHbox, True, True, 0) + + bbox_bottom = Gtk.ButtonBox(spacing=12, orientation=Gtk.Orientation.HORIZONTAL) + bbox_bottom.set_layout(Gtk.ButtonBoxStyle.START) + + button = Gtk.Button.new_with_mnemonic(_("_Install keyboard...")) + button.set_tooltip_text(_("Install a keyboard from a file")) + button.connect("clicked", self.on_installfile_clicked) bbox_bottom.add(button) - button = Gtk.Button.new_with_mnemonic(_("_Download")) + button = Gtk.Button.new_with_mnemonic(_("_Download keyboard...")) button.set_tooltip_text(_("Download and install a keyboard from the Keyman website")) button.connect("clicked", self.on_download_clicked) bbox_bottom.add(button) - button = Gtk.Button.new_with_mnemonic(_("_Install")) - button.set_tooltip_text(_("Install a keyboard from a file")) - button.connect("clicked", self.on_installfile_clicked) + button = Gtk.Button.new_with_mnemonic(_("_Refresh")) + button.set_tooltip_text(_("Refresh keyboard list")) + button.connect("clicked", self.on_refresh_clicked) bbox_bottom.add(button) button = Gtk.Button.new_with_mnemonic(_("_Close")) @@ -217,10 +235,10 @@ class ViewInstalledWindow(ViewInstalledWindowBase): bind_accelerator(self.accelerators, button, 'w') bbox_bottom.add(button) - vbox.pack_end(bbox_bottom, False, False, 12) - - hbox.pack_start(vbox, False, False, 12) - self.add(hbox) + bbox_hbox = Gtk.HBox(spacing=12) + bbox_hbox.pack_start(bbox_bottom, True, True, 12) + outmostVBox.pack_end(bbox_hbox, False, True, 12) + self.add(outmostVBox) def addlistitems(self, installed_kmp, store, install_area): for kmp in sorted(installed_kmp): -- GitLab From 7f9ef0d35b386ab6f75a73b4cdd3600485f01900 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 26 May 2023 17:39:44 +0200 Subject: [PATCH 160/214] feat(linux): Add option to disable Sentry Closes #5027. --- linux/keyman-config/com.keyman.gschema.xml | 6 +- linux/keyman-config/keyman_config/__init__.py | 96 ++--------- .../keyman-config/keyman_config/dconf_util.py | 14 +- .../keyman_config/sentry_handling.py | 152 ++++++++++++++++++ .../keyman_config/view_installed.py | 141 ++++++++-------- 5 files changed, 256 insertions(+), 153 deletions(-) create mode 100644 linux/keyman-config/keyman_config/sentry_handling.py diff --git a/linux/keyman-config/com.keyman.gschema.xml b/linux/keyman-config/com.keyman.gschema.xml index 8f05a42bf9..df50060d8c 100644 --- a/linux/keyman-config/com.keyman.gschema.xml +++ b/linux/keyman-config/com.keyman.gschema.xml @@ -1,8 +1,12 @@ - + + true + Automatic error reporting + true to enable automatic reporting of errors to Sentry + diff --git a/linux/keyman-config/keyman_config/__init__.py b/linux/keyman-config/keyman_config/__init__.py index e5cecf4cc8..04098ade00 100644 --- a/linux/keyman-config/keyman_config/__init__.py +++ b/linux/keyman-config/keyman_config/__init__.py @@ -1,20 +1,18 @@ -import getpass import gettext -import importlib -import logging -import os -import platform -import sys -from .version import __version__ -from .version import __versionwithtag__ -from .version import __versiongittag__ -from .version import __majorversion__ -from .version import __releaseversion__ -from .version import __tier__ -from .version import __pkgversion__ -from .version import __environment__ -from .version import __uploadsentry__ +from keyman_config.sentry_handling import SentryErrorHandling + +from keyman_config.version import ( + __version__, + __versionwithtag__, + __versiongittag__, + __majorversion__, + __releaseversion__, + __tier__, + __pkgversion__, + __environment__, + __uploadsentry__ +) def _(txt): @@ -24,7 +22,7 @@ def _(txt): return translation -def secure_lookup(data, key1, key2 = None): +def secure_lookup(data, key1, key2=None): """ Return data[key1][key2] while dealing with data being None or key1 or key2 not existing """ @@ -38,18 +36,10 @@ def secure_lookup(data, key1, key2 = None): return None -def before_send(event, hint): - if 'exc_info' in hint: - exc_type, exc_value, tb = hint['exc_info'] - if isinstance(exc_value, KeyboardInterrupt): - # Ignore KeyboardInterrupt exception - return None - return event - - gettext.bindtextdomain('keyman-config', '/usr/share/locale') gettext.textdomain('keyman-config') + #if __tier__ == 'alpha' or __tier__ == 'beta': // #7227 disabling: # Alpha and beta versions will work against the staging server so that they # can access new APIs etc that will only be available there. The staging @@ -60,60 +50,8 @@ gettext.textdomain('keyman-config') KeymanComUrl = 'https://keyman.com' KeymanApiUrl = 'https://api.keyman.com' + # There's no staging site for downloads KeymanDownloadsUrl = 'https://downloads.keyman.com' -if 'unittest' in sys.modules.keys(): - print('Not reporting to Sentry', file=sys.stderr) -elif os.environ.get('KEYMAN_NOSENTRY'): - print('Not reporting to Sentry because KEYMAN_NOSENTRY environment variable set', file=sys.stderr) -elif not __uploadsentry__: - print('Not reporting to Sentry because UPLOAD_SENTRY is false (%s)' % __environment__, file=sys.stderr) -else: - try: - # Try new sentry-sdk first - sentry_sdk = importlib.import_module('sentry_sdk') - from sentry_sdk import configure_scope, set_user - from sentry_sdk.integrations.logging import LoggingIntegration - HaveSentryNewSdk = True - - sentry_logging = LoggingIntegration( - level=logging.INFO, # Capture info and above as breadcrumbs - event_level=logging.CRITICAL # Send critical errors as events - ) - SentryUrl = "https://1d0edbf2d0dc411b87119b6e92e2c357@o1005580.ingest.sentry.io/5983525" - sentry_sdk.init( - dsn=SentryUrl, - environment=__environment__, - release=__versiongittag__, - integrations=[sentry_logging], - before_send=before_send - ) - set_user({'id': hash(getpass.getuser())}) - with configure_scope() as scope: - scope.set_tag("app", os.path.basename(sys.argv[0])) - scope.set_tag("pkgversion", __pkgversion__) - scope.set_tag("platform", platform.platform()) - scope.set_tag("system", platform.system()) - scope.set_tag("tier", __tier__) - except ImportError: - try: - # sentry-sdk is not available, so use older raven - raven = importlib.import_module('raven') - from raven import Client - HaveSentryNewSdk = False - - # Note, legacy raven API requires secret (https://github.com/keymanapp/keyman/pull/5787#discussion_r721457909) - SentryUrl = "https://1d0edbf2d0dc411b87119b6e92e2c357:e6d5a81ee6944fc79bd9f0cbb1f2c2a4@o1005580.ingest.sentry.io/5983525" - client = Client(SentryUrl, environment=__environment__, release=__versiongittag__) - client.user_context({'id': hash(getpass.getuser())}) - client.tags_context({ - 'app': os.path.basename(sys.argv[0]), - 'pkgversion': __pkgversion__, - 'platform': platform.platform(), - 'system': platform.system(), - 'tier': __tier__, - }) - except ImportError: - # even raven is not available. This is the case on Ubuntu 16.04. Just ignore. - print(_('Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting.'), file=sys.stderr) +SentryErrorHandling().initialize_sentry() diff --git a/linux/keyman-config/keyman_config/dconf_util.py b/linux/keyman-config/keyman_config/dconf_util.py index 09b95d1815..c28ec3fd19 100644 --- a/linux/keyman-config/keyman_config/dconf_util.py +++ b/linux/keyman-config/keyman_config/dconf_util.py @@ -2,25 +2,25 @@ from gi.repository import Gio -# DConf path destkop/ibus/keyman/options -DCONF_BASE = "com.keyman.options" +# GSettings path destkop/ibus/keyman/options +GSETTINGS_BASE = "com.keyman.options" -# Utilities to get and set Keyman options in DConf: +# Utilities to get and set Keyman options in GSettings: # /desktop/ibus/keyman/options/packageID/keyboardID/options def get_child_schema(info): - settings = Gio.Settings.new(DCONF_BASE) + settings = Gio.Settings.new(GSETTINGS_BASE) path = settings.get_property('path') if not path.endswith('/'): path += '/' path += info['packageID'] + '/' + info['keyboardID'] + '/' - return Gio.Settings(DCONF_BASE + '.child', path) + return Gio.Settings(GSETTINGS_BASE + '.child', path) def get_option(info): """ - Get the Keyman keyboard options from DConf + Get the Keyman keyboard options from GSettings Convert from list of comma-separated strings into dictionary Args: @@ -41,7 +41,7 @@ def get_option(info): def set_option(info, options): """ - Store the Keyman keyboard options in DConf as a list of strings + Store the Keyman keyboard options in GSettings as a list of strings Args: info: dictionary diff --git a/linux/keyman-config/keyman_config/sentry_handling.py b/linux/keyman-config/keyman_config/sentry_handling.py new file mode 100644 index 0000000000..f2b2f8adc3 --- /dev/null +++ b/linux/keyman-config/keyman_config/sentry_handling.py @@ -0,0 +1,152 @@ +#!/usr/bin/python3 +import getpass +import importlib +import logging +import os +import platform +import sys +from keyman_config.gsettings import GSettings +from keyman_config.version import ( + __version__, + __versionwithtag__, + __versiongittag__, + __majorversion__, + __releaseversion__, + __tier__, + __pkgversion__, + __environment__, + __uploadsentry__ +) + +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gio, Gtk + + +class SentryErrorHandling: + def __init__(self) -> None: + self.settings = Gio.Settings.new('com.keyman.options') + + def initialize_sentry(self): + (enabled, reason) = self.is_sentry_enabled() + if not enabled: + print(reason, file=sys.stderr) + logging.info(reason) + return (enabled, reason) + else: + try: + self._sentry_sdk_initialize() + except ImportError: + try: + self._raven_initialize() + except ImportError: + # even raven is not available. This is the case on Ubuntu 16.04. Just ignore. + print(_('Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting.'), + file=sys.stderr) + logging.info('Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting.') + return (False, _('Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting.')) + return (True, '') + + def is_sentry_enabled(self): + if 'unittest' in sys.modules.keys(): + return (False, 'Running unit tests, not reporting to Sentry') + elif self._get_environ_nosentry(): + return (False, 'Not reporting to Sentry because KEYMAN_NOSENTRY environment variable set') + elif not __uploadsentry__: + return (False, f'Not reporting to Sentry because UPLOAD_SENTRY is false ({__environment__})') + elif not self._get_setting(): + return (False, 'Not reporting to Sentry because disabled in GSettings') + return (True, 'Reporting to Sentry') + + def is_sentry_disabled_by_variable(self): + return self._get_environ_nosentry() or not __uploadsentry__ + + def bind_checkbutton(self, button: Gtk.CheckButton): + self.settings.bind("error-reporting", button, "active", Gio.SettingsBindFlags.NO_SENSITIVITY) + self.settings.connect("changed::error-reporting", self._on_sentry_reporting_toggled) + + def set_enabled(self, enabled): + assert not self.is_sentry_disabled_by_variable() + was_enabled = self.is_sentry_enabled() + self._save_setting(enabled) + if enabled != was_enabled: + self._handle_enabled(enabled) + + def _get_environ_nosentry(self): + keyman_nosentry = os.environ.get('KEYMAN_NOSENTRY') + return keyman_nosentry and (int(keyman_nosentry) == 1) + + def _handle_enabled(self, enabled): + if enabled: + self.initialize_sentry() + else: + self._close_sentry() + + def _save_setting(self, enabled: bool): + self.settings.set_boolean('error-reporting', enabled) + + def _get_setting(self) -> bool: + return self.settings.get_boolean('error-reporting') + + def _on_sentry_reporting_toggled(self, settings, key): + self._handle_enabled(self.settings.get_boolean('error-reporting')) + + def _close_sentry(self): + from sentry_sdk import Hub + logging.info("Shutting down Sentry error reporting") + client = Hub.current.client + if client is not None: + client.close(timeout=2.0) + + def _sentry_sdk_initialize(self): + # Try new sentry-sdk first + sentry_sdk = importlib.import_module('sentry_sdk') + from sentry_sdk import configure_scope, set_user + from sentry_sdk.integrations.logging import LoggingIntegration + + sentry_logging = LoggingIntegration( + level=logging.INFO, # Capture info and above as breadcrumbs + event_level=logging.CRITICAL # Send critical errors as events + ) + SentryUrl = "https://1d0edbf2d0dc411b87119b6e92e2c357@o1005580.ingest.sentry.io/5983525" + sentry_sdk.init( + dsn=SentryUrl, + environment=__environment__, + release=__versiongittag__, + integrations=[sentry_logging], + before_send=self._before_send + ) + set_user({'id': hash(getpass.getuser())}) + with configure_scope() as scope: + scope.set_tag("app", os.path.basename(sys.argv[0])) + scope.set_tag("pkgversion", __pkgversion__) + scope.set_tag("platform", platform.platform()) + scope.set_tag("system", platform.system()) + scope.set_tag("tier", __tier__) + logging.info("Initialized Sentry error reporting") + + def _raven_initialize(self): + # sentry-sdk is not available, so use older raven + raven = importlib.import_module('raven') + from raven import Client + + # Note, legacy raven API requires secret (https://github.com/keymanapp/keyman/pull/5787#discussion_r721457909) + SentryUrl = "https://1d0edbf2d0dc411b87119b6e92e2c357:e6d5a81ee6944fc79bd9f0cbb1f2c2a4@o1005580.ingest.sentry.io/5983525" + client = Client(SentryUrl, environment=__environment__, release=__versiongittag__) + client.user_context({'id': hash(getpass.getuser())}) + client.tags_context({ + 'app': os.path.basename(sys.argv[0]), + 'pkgversion': __pkgversion__, + 'platform': platform.platform(), + 'system': platform.system(), + 'tier': __tier__, + }) + logging.info("Initialized Sentry error reporting (raven)") + + def _before_send(self, event, hint): + if 'exc_info' in hint: + exc_type, exc_value, tb = hint['exc_info'] + if isinstance(exc_value, KeyboardInterrupt): + # Ignore KeyboardInterrupt exception + return None + return event diff --git a/linux/keyman-config/keyman_config/view_installed.py b/linux/keyman-config/keyman_config/view_installed.py index ddb13239b0..1a378a106d 100755 --- a/linux/keyman-config/keyman_config/view_installed.py +++ b/linux/keyman-config/keyman_config/view_installed.py @@ -25,6 +25,7 @@ from keyman_config.keyboard_details import KeyboardDetailsView from keyman_config.kmpmetadata import get_fonts, parsemetadata from keyman_config.list_installed_kmp import get_installed_kmp from keyman_config.options import OptionsView +from keyman_config.sentry_handling import SentryErrorHandling from keyman_config.uninstall_kmp import uninstall_kmp from keyman_config.welcome import WelcomeView @@ -104,26 +105,60 @@ class ViewInstalledWindow(ViewInstalledWindowBase): def __init__(self): ViewInstalledWindowBase.__init__(self) -# window is split left/right hbox -# right is ButtonBox -# possibly 2 ButtonBox in a vbox -# top one with _Remove, _About, ?_Welcome? or ?Read_Me?, _Options -# bottom one with _Download, _Install, Re_fresh, _Close -# left is GtkTreeView - does it need to be inside anything else apart from the hbox? -# with liststore which defines columns -# GdkPixbuf icon -# gchararray name -# gchararray version -# gchararray packageID (hidden) -# enum? area (user, shared, system) (icon or hidden?) -# gchararray welcomefile (hidden) (or just use area and packageID?) -# changing selected item in treeview changes what buttons are activated -# on selected_item_changed signal set the data that the buttons will use in their callbacks -# see https://developer.gnome.org/gtk3/stable/TreeWidget.html#TreeWidget + self.sentry = SentryErrorHandling() + outerHbox = Gtk.HBox() + sidebar = Gtk.StackSidebar() + stack = Gtk.Stack() + + outerHbox.pack_start(sidebar, False, False, 0) + outerHbox.pack_end(Gtk.Separator(), False, False, 0) + outerHbox.pack_end(stack, True, True, 0) + stack.set_hexpand(True) + stack.set_vexpand(True) + sidebar.set_stack(stack) + + stack.add_titled(self.add_keyboard_layouts_widget(), "KeyboardLayouts", _("Keyboard Layouts")) + stack.add_titled(self.add_options_widget(), "Options", _("Options")) + + outmostVBox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + outmostVBox.pack_start(outerHbox, True, True, 0) + + bbox_bottom = Gtk.ButtonBox(spacing=12, orientation=Gtk.Orientation.HORIZONTAL) + bbox_bottom.set_layout(Gtk.ButtonBoxStyle.START) + + button = Gtk.Button.new_with_mnemonic(_("_Install keyboard...")) + button.set_tooltip_text(_("Install a keyboard from a file")) + button.connect("clicked", self.on_installfile_clicked) + bbox_bottom.add(button) + + button = Gtk.Button.new_with_mnemonic(_("_Download keyboard...")) + button.set_tooltip_text(_("Download and install a keyboard from the Keyman website")) + button.connect("clicked", self.on_download_clicked) + bbox_bottom.add(button) + + button = Gtk.Button.new_with_mnemonic(_("_Refresh")) + button.set_tooltip_text(_("Refresh keyboard list")) + button.connect("clicked", self.on_refresh_clicked) + bbox_bottom.add(button) + + button = Gtk.Button.new_with_mnemonic(_("_Close")) + button.set_tooltip_text(_("Close window")) + button.connect("clicked", self.on_close_clicked) + bind_accelerator(self.accelerators, button, 'q') + bind_accelerator(self.accelerators, button, 'w') + bbox_bottom.add(button) + + bbox_hbox = Gtk.HBox(spacing=12) + bbox_hbox.pack_start(bbox_bottom, True, True, 12) + outmostVBox.pack_end(bbox_hbox, False, True, 12) + self.add(outmostVBox) + + def add_keyboard_layouts_widget(self): hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) - s = Gtk.ScrolledWindow() - hbox.pack_start(s, True, True, 0) + + scrolledWindow = Gtk.ScrolledWindow() + hbox.pack_start(scrolledWindow, True, True, 0) self.store = Gtk.ListStore( GdkPixbuf.Pixbuf, # icon @@ -134,12 +169,6 @@ class ViewInstalledWindow(ViewInstalledWindowBase): str, # path to welcome file if it exists or None str) # path to options file if it exists or None - # add installed keyboards to the the store e.g. - # treeiter = store.append([GdkPixbuf.Pixbuf.new_from_file_at_size( - # "/usr/local/share/keyman/libtralo/libtralo.ico.png", 16, 16), \ - # "LIBTRALO", "1.6.1", \ - # "libtralo", KmpArea.SHARED, True]) - self.refresh_installed_kmp() self.tree = Gtk.TreeView(self.store) @@ -159,7 +188,7 @@ class ViewInstalledWindow(ViewInstalledWindowBase): select = self.tree.get_selection() select.connect("changed", self.on_tree_selection_changed) - s.add(self.tree) + scrolledWindow.add(self.tree) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12) @@ -193,52 +222,32 @@ class ViewInstalledWindow(ViewInstalledWindowBase): vbox.pack_start(bbox_top, False, False, 12) hbox.pack_start(vbox, False, False, 12) - outerHbox = Gtk.HBox() - sidebar = Gtk.StackSidebar() - stack = Gtk.Stack() - - outerHbox.pack_start(sidebar, False, False, 0) - outerHbox.pack_end(Gtk.Separator(), False, False, 0) - outerHbox.pack_end(stack, True, True, 0) - stack.set_hexpand(True) - stack.set_vexpand(True) - sidebar.set_stack(stack) + return hbox - stack.add_titled(hbox, "KeyboardLayouts", _("Keyboard Layouts")) - stack.add_titled(Gtk.Label("TODO - Options"), "Options", _("Options")) + def add_options_widget(self): + vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + label = Gtk.Label(_("General")) + label.set_padding(5, 5) + label.set_halign(Gtk.Align.START) + vbox.pack_start(label, False, False, 10) - outmostVBox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) - outmostVBox.pack_start(outerHbox, True, True, 0) + (enabled, reason) = self.sentry.is_sentry_enabled() + disabledByVariable = self.sentry.is_sentry_disabled_by_variable() - bbox_bottom = Gtk.ButtonBox(spacing=12, orientation=Gtk.Orientation.HORIZONTAL) - bbox_bottom.set_layout(Gtk.ButtonBoxStyle.START) + self.errorReportingButton = Gtk.CheckButton(_("Automatically report errors to keyman.com")) + self.errorReportingButton.set_active(enabled) + self.errorReportingButton.set_sensitive(not disabledByVariable) + self.sentry.bind_checkbutton(self.errorReportingButton) + vbox.pack_start(self.errorReportingButton, False, False, 0) - button = Gtk.Button.new_with_mnemonic(_("_Install keyboard...")) - button.set_tooltip_text(_("Install a keyboard from a file")) - button.connect("clicked", self.on_installfile_clicked) - bbox_bottom.add(button) + if disabledByVariable: + label = Gtk.Label(reason) + label.set_halign(Gtk.Align.START) + label.set_padding(25, 0) + label.set_sensitive(False) + vbox.pack_start(label, False, False, 0) - button = Gtk.Button.new_with_mnemonic(_("_Download keyboard...")) - button.set_tooltip_text(_("Download and install a keyboard from the Keyman website")) - button.connect("clicked", self.on_download_clicked) - bbox_bottom.add(button) - - button = Gtk.Button.new_with_mnemonic(_("_Refresh")) - button.set_tooltip_text(_("Refresh keyboard list")) - button.connect("clicked", self.on_refresh_clicked) - bbox_bottom.add(button) - - button = Gtk.Button.new_with_mnemonic(_("_Close")) - button.set_tooltip_text(_("Close window")) - button.connect("clicked", self.on_close_clicked) - bind_accelerator(self.accelerators, button, 'q') - bind_accelerator(self.accelerators, button, 'w') - bbox_bottom.add(button) - - bbox_hbox = Gtk.HBox(spacing=12) - bbox_hbox.pack_start(bbox_bottom, True, True, 12) - outmostVBox.pack_end(bbox_hbox, False, True, 12) - self.add(outmostVBox) + return vbox def addlistitems(self, installed_kmp, store, install_area): for kmp in sorted(installed_kmp): -- GitLab From a6c4c0763be416b1e86ddb339e45da24e7eadc66 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 30 May 2023 19:01:10 +0200 Subject: [PATCH 161/214] chore(linux): Properly set variables in GHA --- .github/workflows/deb-packaging.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deb-packaging.yml b/.github/workflows/deb-packaging.yml index 8c745bef30..8495f5577a 100644 --- a/.github/workflows/deb-packaging.yml +++ b/.github/workflows/deb-packaging.yml @@ -119,8 +119,8 @@ jobs: platform: "${{ matrix.arch }}" source_dir: "artifacts/keyman-srcpkg" sourcepackage: "keyman_${{ needs.sourcepackage.outputs.VERSION }}-1.dsc" - deb_fullname: $DEBFULLNAME - deb_email: $DEBEMAIL + deb_fullname: ${{env.DEBFULLNAME}} + deb_email: ${{env.DEBEMAIL}} prerelease_tag: ${{ needs.sourcepackage.outputs.PRERELEASE_TAG }} - name: Output resulting .deb files -- GitLab From b6c90c67b0ce69e4431cec383b8e64d23e3f009a Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 30 May 2023 19:21:41 +0200 Subject: [PATCH 162/214] chore(linux): Temporarily install schema during creation of man pages --- linux/keyman-config/build.sh | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/linux/keyman-config/build.sh b/linux/keyman-config/build.sh index 23d138b28e..7f63eaff1e 100755 --- a/linux/keyman-config/build.sh +++ b/linux/keyman-config/build.sh @@ -29,6 +29,21 @@ clean_action() { keyman_config/standards/lang_tags_map.py } +build_man_pages() { + local TEMP_DATA_DIR SCHEMA_DIR + TEMP_DATA_DIR=$(mktemp -d) + SCHEMA_DIR=$TEMP_DATA_DIR/glib-2.0/schemas + export XDG_DATA_DIRS=$TEMP_DATA_DIR:${XDG_DATA_DIRS-} + export GSETTINGS_SCHEMA_DIR=${SCHEMA_DIR} + mkdir -p "$SCHEMA_DIR" + cp ./com.keyman.gschema.xml "$SCHEMA_DIR"/ + glib-compile-schemas "$SCHEMA_DIR" + ./build-help.sh --man --no-reconf + export XDG_DATA_DIRS=${XDG_DATA_DIRS#*:} + unset GSETTINGS_SCHEMA_DIR + rm -rf $TEMP_DATA_DIR +} + build_action() { builder_echo "Create version.py" pushd keyman_config @@ -52,7 +67,7 @@ build_action() { fi popd builder_echo "Building man pages" - ./build-help.sh --man --no-reconf + build_man_pages builder_echo "Building keyman-config" python3 setup.py build } -- GitLab From 77da56e7487ee70d8acdee4492362a7ab248e149 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 31 May 2023 07:44:35 +0700 Subject: [PATCH 163/214] refactor(developer): complete fs move out of kmcmplib * Moves filesystem access out of kmcmplib into kmc-kmn * Adds filesystem access callback to kmcmplib unit tests * Cleans up callback interface through wasm * Adds unit tests for various file load scenarios * Removes nodefs dependency from kmcmplib wasm build, and removes corresponding path mappings which were previously required for wasm builds; note that these are still present for the unit tests for kmcmplib. --- .../src/kmc-kmn/src/compiler/compiler.ts | 55 ++++++++-- .../kmcmplib/src/CheckFilenameConsistency.cpp | 47 ++------ .../kmcmplib/src/CheckFilenameConsistency.h | 2 - developer/src/kmcmplib/src/Compiler.cpp | 102 ++++++++---------- .../src/kmcmplib/src/CompilerInterfaces.cpp | 44 ++++---- .../src/kmcmplib/src/NamedCodeConstants.cpp | 97 ++++++----------- .../src/kmcmplib/src/NamedCodeConstants.h | 5 +- developer/src/kmcmplib/src/compfile.h | 3 +- developer/src/kmcmplib/src/kmcmplib.h | 1 - developer/src/kmcmplib/src/meson.build | 9 +- developer/src/kmcmplib/src/pch.h | 2 - developer/src/kmcmplib/tests/api-test.cpp | 53 ++------- .../valid-keyboards/compile_legacy.bat | 4 + .../fixtures/valid-keyboards/k001_utf16.kmn | Bin 0 -> 452 bytes .../fixtures/valid-keyboards/k001_utf16.kmx | Bin 0 -> 356 bytes .../valid-keyboards/k002_utf8_without_bom.kmn | 11 ++ .../valid-keyboards/k002_utf8_without_bom.kmx | Bin 0 -> 378 bytes .../valid-keyboards/k003_utf8_with_bom.kmn | 11 ++ .../valid-keyboards/k003_utf8_with_bom.kmx | Bin 0 -> 372 bytes .../fixtures/valid-keyboards/k004_ansi.kmn | 13 +++ .../fixtures/valid-keyboards/k004_ansi.kmx | Bin 0 -> 350 bytes .../fixtures/valid-keyboards/k005_bitmap.bmp | Bin 0 -> 246 bytes .../fixtures/valid-keyboards/k005_bitmap.kmn | 12 +++ .../fixtures/valid-keyboards/k005_bitmap.kmx | Bin 0 -> 656 bytes .../fixtures/valid-keyboards/k006_icon.ico | Bin 0 -> 318 bytes .../fixtures/valid-keyboards/k006_icon.kmn | 12 +++ .../fixtures/valid-keyboards/k006_icon.kmx | Bin 0 -> 728 bytes .../valid-keyboards/k007_includecodes_r_n.kmn | 12 +++ .../valid-keyboards/k007_includecodes_r_n.kmx | Bin 0 -> 462 bytes .../valid-keyboards/k007_includecodes_r_n.txt | 2 + .../valid-keyboards/k008_includecodes_n.kmn | 12 +++ .../valid-keyboards/k008_includecodes_n.kmx | Bin 0 -> 454 bytes .../valid-keyboards/k008_includecodes_n.txt | 2 + developer/src/kmcmplib/tests/kmcompxtest.cpp | 49 +-------- developer/src/kmcmplib/tests/meson.build | 41 +++++-- .../src/kmcmplib/tests/util_callbacks.cpp | 59 ++++++++++ developer/src/kmcmplib/tests/util_callbacks.h | 8 ++ .../util_filesystem.cpp} | 41 ++++++- .../filesystem.h => tests/util_filesystem.h} | 5 +- 39 files changed, 406 insertions(+), 308 deletions(-) create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/compile_legacy.bat create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k001_utf16.kmn create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k001_utf16.kmx create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k002_utf8_without_bom.kmn create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k002_utf8_without_bom.kmx create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k003_utf8_with_bom.kmn create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k003_utf8_with_bom.kmx create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k004_ansi.kmn create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k004_ansi.kmx create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k005_bitmap.bmp create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k005_bitmap.kmn create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k005_bitmap.kmx create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k006_icon.ico create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k006_icon.kmn create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k006_icon.kmx create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k007_includecodes_r_n.kmn create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k007_includecodes_r_n.kmx create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k007_includecodes_r_n.txt create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k008_includecodes_n.kmn create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k008_includecodes_n.kmx create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k008_includecodes_n.txt create mode 100644 developer/src/kmcmplib/tests/util_callbacks.cpp create mode 100644 developer/src/kmcmplib/tests/util_callbacks.h rename developer/src/kmcmplib/{src/filesystem.cpp => tests/util_filesystem.cpp} (84%) rename developer/src/kmcmplib/{src/filesystem.h => tests/util_filesystem.h} (82%) diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index 606bec638c..b27440fd06 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -42,13 +42,16 @@ const baseOptions: CompilerOptions = { */ let callbackProcIdentifier = 0; +const + callbackPrefix = 'kmnCompilerCallbacks_'; + export class KmnCompiler { private Module: any; - callbackName: string; + callbackID: string; // a unique numeric id added to globals with prefixed names callbacks: CompilerCallbacks; constructor() { - this.callbackName = 'kmnCompilerCallback' + callbackProcIdentifier; + this.callbackID = callbackPrefix + callbackProcIdentifier.toString(); callbackProcIdentifier++; } @@ -58,6 +61,7 @@ export class KmnCompiler { try { this.Module = await loadWasmHost(); } catch(e: any) { + /* c8 ignore next 3 */ this.callbacks.reportMessage(CompilerMessages.Fatal_MissingWasmModule({e})); return false; } @@ -74,7 +78,9 @@ export class KmnCompiler { // Can't report a message here. throw Error('Must call Compiler.init(callbacks) before proceeding'); } - if(!this.Module) { // fail if wasm not loaded or function not found + if(!this.Module) { + /* c8 ignore next 4 */ + // fail if wasm not loaded or function not found this.callbacks.reportMessage(CompilerMessages.Fatal_MissingWasmModule({})); return false; } @@ -83,15 +89,17 @@ export class KmnCompiler { public run(infile: string, outfile: string, options?: CompilerOptions): boolean { if(!this.verifyInitialized()) { + /* c8 ignore next 2 */ return false; } options = {...baseOptions, ...options}; - (globalThis as any)[this.callbackName] = this.compilerMessageCallback; - // TODO: use callbacks for file access -- so kmc-kmn is entirely fs agnostic + (globalThis as any)[this.callbackID] = { + message: this.compilerMessageCallback, + loadFile: this.loadFileCallback + }; let result = this.runCompiler(infile, outfile, options); - delete (globalThis as any)[this.callbackName]; - //TODO: write the file out! + delete (globalThis as any)[this.callbackID]; if(result) { if(result.kmx) { this.callbacks.fs.writeFileSync(result.kmx.filename, result.kmx.data); @@ -111,6 +119,30 @@ export class KmnCompiler { return 1; } + private loadFileCallback = (filename: string, baseFilename: string, buffer: number, bufferSize: number): number => { + // TODO: we can optimize this in future by avoiding loading the file twice + let resolvedFilename = this.callbacks.resolveFilename(baseFilename, filename); + let data = this.callbacks.loadFile(resolvedFilename); + if(!data) { + return 0; + } + + if(buffer == 0) { + /* We need to return buffer size required */ + return data.byteLength; + } + + if(bufferSize != data.byteLength) { + // TODO: consider chucking a wobbly because this is a bug + /* c8 ignore next 2 */ + return 0; + } + + this.Module.HEAP8.set(data, buffer); + + return 1; + } + private runCompiler(infile: string, outfile: string, options: CompilerOptions): CompilerResult { let result: CompilerResult = {}; let wasm_interface = new this.Module.CompilerInterface(); @@ -122,8 +154,7 @@ export class KmnCompiler { wasm_options.warnDeprecatedCode = options.warnDeprecatedCode; wasm_options.shouldAddCompilerVersion = options.shouldAddCompilerVersion; wasm_options.target = 0; //CKF_KEYMAN; TODO, support KMW - wasm_interface.messageCallback = this.callbackName; - wasm_interface.loadFileCallback = this.callbackName; // TODO: this is wrong, needs to be a new callback; not yet used though + wasm_interface.callbacksKey = this.callbackID; // key of object on globalThis wasm_result = this.Module.kmcmp_compile(infile, wasm_options, wasm_interface); if(!wasm_result.result) { return null; @@ -143,6 +174,7 @@ export class KmnCompiler { return result; } catch(e) { + /* c8 ignore next 3 */ this.callbacks.reportMessage(CompilerMessages.Fatal_UnexpectedException({e:e})); return null; } finally { @@ -163,6 +195,7 @@ export class KmnCompiler { reader.validate(kvks, this.callbacks.loadSchema('kvks')); } catch(e) { console.log(e); + // TODO: also unit test // TODO: this.callbacks.reportMessage(CompilerMessages.Error_InvalidKvksFile({e})); return null; } @@ -170,6 +203,7 @@ export class KmnCompiler { let vk = reader.transform(kvks, errors); if(!vk || errors.length) { console.dir(errors); + // TODO: also unit test // TODO: this.callbacks.reportMessage(CompilerMessages.Error_InvalidKvksFile({e})); return null; } @@ -188,10 +222,12 @@ export class KmnCompiler { */ public parseUnicodeSet(pattern: string, bufferSize: number) : UnicodeSet | null { if(!this.verifyInitialized()) { + /* c8 ignore next 2 */ return null; } if (!bufferSize) { + /* c8 ignore next 2 */ bufferSize = 100; // TODO-LDML: Preflight mode? Reuse buffer? } const buf = this.Module.asm.malloc(bufferSize * 2 * this.Module.HEAPU32.BYTES_PER_ELEMENT); @@ -239,6 +275,7 @@ function getUnicodeSetError(rc: number) : CompilerEvent { case KMCMP_FATAL_OUT_OF_RANGE: return CompilerMessages.Fatal_UnicodeSetOutOfRange(); default: + /* c8 ignore next */ return CompilerMessages.Fatal_UnexpectedException({e: `Unexpected UnicodeSet error code ${rc}`}); } } diff --git a/developer/src/kmcmplib/src/CheckFilenameConsistency.cpp b/developer/src/kmcmplib/src/CheckFilenameConsistency.cpp index 627298bf37..3a185bc403 100644 --- a/developer/src/kmcmplib/src/CheckFilenameConsistency.cpp +++ b/developer/src/kmcmplib/src/CheckFilenameConsistency.cpp @@ -7,52 +7,12 @@ #include #include "CheckFilenameConsistency.h" #include "kmx_u16.h" -#include "filesystem.h" #ifdef _MSC_VER #include #endif -namespace kmcmp { - extern KMX_CHAR CompileDir[260]; // TODO: this should not be a fixed buffer -} -bool IsRelativePath(KMX_CHAR const * p) { - // Relative path (returns TRUE): - // ..\...\BITMAP.BMP - // PATH\BITMAP.BMP - // BITMAP.BMP - - // Semi-absolute path (returns FALSE): - // \...\BITMAP.BMP - - // Absolute path (returns FALSE): - // C:\...\BITMAP.BMP - // \\SERVER\SHARE\...\BITMAP.BMP - - if ((*p == '\\') || (*p == '/')) return FALSE; - if (*p && *(p + 1) == ':') return FALSE; - - return TRUE; -} - -bool IsRelativePath(KMX_WCHAR const * p) { - // Relative path (returns TRUE): - // ..\...\BITMAP.BMP - // PATH\BITMAP.BMP - // BITMAP.BMP - // Semi-absolute path (returns FALSE): - // \...\BITMAP.BMP - - // Absolute path (returns FALSE): - // C:\...\BITMAP.BMP - // \\SERVER\SHARE\...\BITMAP.BMP - - if ((*p == u'\\') || (*p == u'/'))return FALSE; - if (*p && *(p + 1) == u':') return FALSE; - - return TRUE; -} KMX_DWORD CheckFilenameConsistency( KMX_CHAR const * Filename, bool ReportMissingFile) { PKMX_WCHAR WFilename = strtowstr(( KMX_CHAR *)Filename); @@ -62,6 +22,12 @@ KMX_DWORD CheckFilenameConsistency( KMX_CHAR const * Filename, bool ReportMissin } KMX_DWORD CheckFilenameConsistency(KMX_WCHAR const * Filename, bool ReportMissingFile) { + // TODO: we no longer have filesystem access here. We could move this check to + // kmc itself, and make it consistent across all compilers that use the same + // loader callback + return CERR_None; + +#if 0 // not ready yet: needs more attention-> common includes for non-Windows platforms KMX_WCHAR Name[260]; // TODO: fixed buffer sizes bad @@ -115,6 +81,7 @@ KMX_DWORD CheckFilenameConsistency(KMX_WCHAR const * Filename, bool ReportMissin #endif return CERR_None; +#endif } KMX_DWORD CheckFilenameConsistencyForCalls(PFILE_KEYBOARD fk) { diff --git a/developer/src/kmcmplib/src/CheckFilenameConsistency.h b/developer/src/kmcmplib/src/CheckFilenameConsistency.h index 39f86db391..eba8f2d8bf 100644 --- a/developer/src/kmcmplib/src/CheckFilenameConsistency.h +++ b/developer/src/kmcmplib/src/CheckFilenameConsistency.h @@ -7,5 +7,3 @@ KMX_DWORD CheckFilenameConsistencyForCalls(PFILE_KEYBOARD fk); KMX_DWORD CheckFilenameConsistency(KMX_CHAR const * Filename, bool ReportMissingFile); KMX_DWORD CheckFilenameConsistency(KMX_WCHAR const * Filename, bool ReportMissingFile); -bool IsRelativePath(KMX_CHAR const * p); -bool IsRelativePath(KMX_WCHAR const * p); diff --git a/developer/src/kmcmplib/src/Compiler.cpp b/developer/src/kmcmplib/src/Compiler.cpp index 8e0f94cb29..91e02e14e7 100644 --- a/developer/src/kmcmplib/src/Compiler.cpp +++ b/developer/src/kmcmplib/src/Compiler.cpp @@ -101,7 +101,6 @@ #include "UnreachableRules.h" #include "CheckForDuplicates.h" #include "kmx_u16.h" -#include "filesystem.h" #include /* These macros are adapted from winnt.h and legacy use only */ @@ -125,7 +124,6 @@ namespace kmcmp{ KMX_BOOL FMnemonicLayout = FALSE; KMX_BOOL FOldCharPosMatching = FALSE; int CompileTarget; - KMX_CHAR CompileDir[260]; // TODO: this should not be a fixed buffer int BeginLine[4]; KMX_BOOL IsValidCallStore(PFILE_STORE fs); @@ -867,7 +865,6 @@ KMX_DWORD ProcessSystemStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, PFILE_STORE int i, j; KMX_DWORD msg; PKMX_WCHAR p, q; - KMX_CHAR *pp; if (!pssBuf) pssBuf = new KMX_WCHAR[GLOBAL_BUFSIZE]; PKMX_WCHAR buf = pssBuf; @@ -917,13 +914,9 @@ KMX_DWORD ProcessSystemStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, PFILE_STORE case TSS_INCLUDECODES: VERIFY_KEYBOARD_VERSION(fk, VERSION_60, CERR_60FeatureOnly_NamedCodes); - pp = wstrtostr(sp->dpString); - if (!kmcmp::CodeConstants->LoadFile(pp)) - { - delete[] pp; + if (!kmcmp::CodeConstants->LoadFile(fk, sp->dpString)) { return CERR_CannotLoadIncludeFile; } - delete[] pp; kmcmp::CodeConstants->reindex(); // I4982 break; @@ -3234,58 +3227,32 @@ KMX_BOOL IsSameToken(PKMX_WCHAR *p, KMX_WCHAR const * token) return FALSE; } -KMX_DWORD ImportBitmapFile(PFILE_KEYBOARD fk, PKMX_WCHAR szName, PKMX_DWORD FileSize, PKMX_BYTE *Buf) +static bool endsWith(const std::string& str, const std::string& suffix) { - FILE *fp; - KMX_WCHAR szNewName[260]; - - if (IsRelativePath(szName)) - { - PKMX_WCHAR WCompileDir = strtowstr(kmcmp::CompileDir); - u16ncpy(szNewName, WCompileDir, _countof(szNewName)); // I3481 - u16ncat(szNewName,szName, _countof(szNewName )); // I3481 - } - else - u16ncpy(szNewName, szName, _countof(szNewName)); // I3481 - - fp=Open_File(szNewName, u"rb"); - - if ( fp == NULL) - { - // else if filename.bmp is not in the folder -> attempt to open filename.bmp.bmp ! - if ( u16cmp(szNewName+u16len(szNewName)-4, u".bmp") ) - u16ncat(szNewName, u".bmp", _countof(szNewName)); // I3481 + return str.size() >= suffix.size() && 0 == str.compare(str.size()-suffix.size(), suffix.size(), suffix); +} - fp= Open_File(szNewName, u"rb"); +KMX_DWORD ImportBitmapFile(PFILE_KEYBOARD fk, PKMX_WCHAR szName, PKMX_DWORD FileSize, PKMX_BYTE *Buf) +{ + auto szNameUtf8 = string_from_u16string(szName); - if ( fp == NULL) + if(!loadfileproc(szNameUtf8.c_str(), fk->extra->kmnFilename.c_str(), nullptr, (int*) FileSize, msgprocContext)) { + // Append .bmp and try again + if(endsWith(szNameUtf8, ".bmp")) { return CERR_CannotReadBitmapFile; + } + szNameUtf8.append(".bmp"); + if(!loadfileproc(szNameUtf8.c_str(), fk->extra->kmnFilename.c_str(), nullptr, (int*) FileSize, msgprocContext)) { + return CERR_CannotReadBitmapFile; + } } - KMX_DWORD msg; - if ((msg = CheckFilenameConsistency(szNewName, FALSE)) != CERR_None) { - return msg; - } - - fseek(fp, 0, SEEK_END); - *FileSize = (KMX_DWORD)ftell(fp); - fseek(fp ,0,SEEK_SET); - if (*FileSize < 0) { - fclose(fp); - return CERR_CannotReadBitmapFile; - } - - if (*FileSize < 2) return CERR_CannotReadBitmapFile; *Buf = new KMX_BYTE[*FileSize]; - - if (fread(*Buf, 1, *FileSize, fp) < (size_t) *FileSize) { - delete[] * Buf; - *Buf = NULL; + if(!loadfileproc(szNameUtf8.c_str(), fk->extra->kmnFilename.c_str(), *Buf, (int*) FileSize, msgprocContext)) { + delete[] *Buf; return CERR_CannotReadBitmapFile; } - fclose(fp); - /* Test for version 7.0 icon support */ if (*((PKMX_CHAR)*Buf) != 'B' && *(((PKMX_CHAR)*Buf) + 1) != 'M') { VERIFY_KEYBOARD_VERSION(fk, VERSION_70, CERR_70FeatureOnly); @@ -3447,6 +3414,8 @@ bool hasPreamble(std::u16string result) { return result.size() > 0 && result[0] == 0xFEFF; } +#include "unicode/ucnv.h" + bool UTF16TempFromUTF8(KMX_BYTE* infile, int sz, KMX_BYTE** tempfile, int *sz16) { if(sz == 0) { return FALSE; @@ -3456,23 +3425,36 @@ bool UTF16TempFromUTF8(KMX_BYTE* infile, int sz, KMX_BYTE** tempfile, int *sz16) try { std::wstring_convert, char16_t> converter; - result = converter.from_bytes((char*)infile, (char*)infile+sz-1); + result = converter.from_bytes((char*)infile, (char*)infile+sz); } catch(std::range_error e) { - std::wstring_convert, char16_t> converter; - result = converter.from_bytes((char*)infile, (char*)infile+sz-1); + UErrorCode status = U_ZERO_ERROR; + // TODO: we need ICU data files here @srl295 plz help! + UConverter* conv = ucnv_open("windows-1252", &status); + if(U_FAILURE(status)) { + return FALSE; + } + + char16_t* dest = new char16_t[sz*2]; + ucnv_toUChars(conv, dest, sz*2, (char*)infile, sz, &status); + if(U_FAILURE(status)) { + delete[] dest; + return FALSE; + } + + result = dest; + delete[] dest; } if(hasPreamble(result)) { - *sz16 = result.size() * 2 - 1; + *sz16 = result.size() * 2 - 2; *tempfile = new KMX_BYTE[*sz16]; - memcpy(*tempfile, result.c_str() + 2, *sz16); - + memcpy(*tempfile, result.c_str() + 1, *sz16); + } else { + *sz16 = result.size() * 2; + *tempfile = new KMX_BYTE[*sz16]; + memcpy(*tempfile, result.c_str(), *sz16); } - *sz16 = result.size() * 2; - *tempfile = new KMX_BYTE[*sz16]; - memcpy(*tempfile, result.c_str(), *sz16); - return TRUE; } diff --git a/developer/src/kmcmplib/src/CompilerInterfaces.cpp b/developer/src/kmcmplib/src/CompilerInterfaces.cpp index fd297f4332..1a4e77f8e8 100644 --- a/developer/src/kmcmplib/src/CompilerInterfaces.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfaces.cpp @@ -3,7 +3,6 @@ #include #include #include "kmcmplib.h" -#include "filesystem.h" #include "CheckFilenameConsistency.h" #include "CheckNCapsConsistency.h" #include "DeprecationChecks.h" @@ -19,7 +18,7 @@ bool CompileKeyboardHandle(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk); WASM interface for compiler message callback */ EM_JS(int, wasm_msgproc, (int line, int msgcode, const char* text, char* context), { - const proc = globalThis[UTF8ToString(context)]; + const proc = globalThis[UTF8ToString(context)].message; if(!proc || typeof proc != 'function') { console.log(`[${line}: ${msgcode}: ${UTF8ToString(text)}]`); return 0; @@ -28,18 +27,27 @@ EM_JS(int, wasm_msgproc, (int line, int msgcode, const char* text, char* context } }); -EM_JS(bool, wasm_loadfileproc, (const char* filename, const char* baseFilename, void* buffer, int* bufferSize, char* context), { - const proc = globalThis[UTF8ToString(context)]; +EM_JS(int, wasm_loadfileproc, (const char* filename, const char* baseFilename, void* buffer, int bufferSize, char* context), { + const proc = globalThis[UTF8ToString(context)].loadFile; if(!proc || typeof proc != 'function') { return 0; } else { - return proc(UTF8ToString(filename), UTF8ToString(baseFilename), buffer, bufferSize); + if(buffer == 0) { + return proc(UTF8ToString(filename), UTF8ToString(baseFilename), 0, 0); + } else { + return proc(UTF8ToString(filename), UTF8ToString(baseFilename), buffer, bufferSize); + } } }); bool wasm_LoadFileProc(const char* filename, const char* baseFilename, void* buffer, int* bufferSize, void* context) { char* msgProc = static_cast(context); - return wasm_loadfileproc(filename, baseFilename, buffer, bufferSize, msgProc); + if(buffer == nullptr) { + *bufferSize = wasm_loadfileproc(filename, baseFilename, 0, 0, msgProc); + return *bufferSize != 0; + } else { + return wasm_loadfileproc(filename, baseFilename, buffer, *bufferSize, msgProc) == 1; + } } int wasm_CompilerMessageProc(int line, uint32_t dwMsgCode, const char* szText, void* context) { @@ -48,8 +56,7 @@ int wasm_CompilerMessageProc(int line, uint32_t dwMsgCode, const char* szText, v } struct WASM_COMPILER_INTERFACE { - std::string messageCallback; // int line, uint32_t dwMsgCode, char* szText - std::string loadFileCallback; // TODO: char* filename, char* baseFilename --> buffer + std::string callbacksKey; // key of callbacks object on globalThis }; struct WASM_COMPILER_RESULT { @@ -76,7 +83,7 @@ WASM_COMPILER_RESULT kmcmp_wasm_compile(std::string pszInfile, const KMCMP_COMPI options, wasm_CompilerMessageProc, wasm_LoadFileProc, - intf.messageCallback.c_str(), + intf.callbacksKey.c_str(), kr ); @@ -103,8 +110,7 @@ EMSCRIPTEN_BINDINGS(compiler_interface) { emscripten::class_("CompilerInterface") .constructor<>() - .property("messageCallback", &WASM_COMPILER_INTERFACE::messageCallback) - .property("loadFileCallback", &WASM_COMPILER_INTERFACE::loadFileCallback) + .property("callbacksKey", &WASM_COMPILER_INTERFACE::callbacksKey) ; emscripten::class_("CompilerResult") @@ -131,6 +137,8 @@ EXTERN bool kmcmp_CompileKeyboard( ) { FILE_KEYBOARD fk; + fk.extra = new FILE_KEYBOARD_EXTRA; + fk.extra->kmnFilename = pszInfile; kmcmp::FSaveDebug = options.saveDebug; // I3681 kmcmp::FCompilerWarningsAsErrors = options.compilerWarningsAsErrors; // I4865 @@ -143,16 +151,6 @@ EXTERN bool kmcmp_CompileKeyboard( return FALSE; } - PKMX_STR p; - - if ((p = strrchr_slash((char*)pszInfile)) != nullptr) { - strncpy(kmcmp::CompileDir, pszInfile, (int)(p - pszInfile + 1)); // I3481 - kmcmp::CompileDir[(int)(p - pszInfile + 1)] = 0; - } - else { - kmcmp::CompileDir[0] = 0; - } - msgproc = messageProc; loadfileproc = loadFileProc; msgprocContext = (void*)procContext; @@ -172,7 +170,7 @@ EXTERN bool kmcmp_CompileKeyboard( return FALSE; } - KMX_BYTE* infile = new KMX_BYTE[sz]; + KMX_BYTE* infile = new KMX_BYTE[sz+1]; if(!infile) { AddCompileError(CERR_CannotAllocateMemory); return FALSE; @@ -182,6 +180,7 @@ EXTERN bool kmcmp_CompileKeyboard( AddCompileError(CERR_CannotReadInfile); return FALSE; } + infile[sz] = 0; // zero-terminate for safety, not technically needed but helps avoid memory bugs int offset = 0; if(infile[0] == (KMX_BYTE) UTF16Sig[0] && infile[1] == (KMX_BYTE) UTF16Sig[1]) { @@ -266,7 +265,6 @@ bool CompileKeyboardHandle(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk) fk->dpDeadKeyArray = NULL; fk->cxVKDictionary = 0; // I3438 fk->dpVKDictionary = NULL; // I3438 - fk->extra = new FILE_KEYBOARD_EXTRA; fk->extra->kvksFilename = u""; /* fk->szMessage[0] = 0; fk->szLanguageName[0] = 0;*/ diff --git a/developer/src/kmcmplib/src/NamedCodeConstants.cpp b/developer/src/kmcmplib/src/NamedCodeConstants.cpp index e6b1ae6d70..30091b7cb8 100644 --- a/developer/src/kmcmplib/src/NamedCodeConstants.cpp +++ b/developer/src/kmcmplib/src/NamedCodeConstants.cpp @@ -27,15 +27,12 @@ #include "CheckFilenameConsistency.h" #include #include "kmcompx.h" -#include "filesystem.h" using namespace kmcmp; int IsHangulSyllable(const KMX_WCHAR *codename, int *code); namespace kmcmp { - extern KMX_CHAR CompileDir[]; - int __cdecl sort_entries(const void *elem1, const void *elem2) { return u16icmp( @@ -117,85 +114,61 @@ char *kmc_strupr(char *s) { return s; } -KMX_BOOL NamedCodeConstants::IntLoadFile(const KMX_CHAR *filename) -{ +KMX_BOOL NamedCodeConstants::LoadFile(PFILE_KEYBOARD fk, const KMX_WCHAR *filename) { const int str_size = 256; - FILE *fp = NULL; if (CheckFilenameConsistency(filename, FALSE) != 0) { return FALSE; } - fp = Open_File(filename, "rt"); - if(fp == NULL) { - return FALSE; // I3481 + auto szNameUtf8 = string_from_u16string(filename); + + int FileSize; + KMX_BYTE* Buf; + if(!loadfileproc(szNameUtf8.c_str(), fk->extra->kmnFilename.c_str(), nullptr, &FileSize, msgprocContext)) { + return FALSE; } - KMX_CHAR str[str_size], *p, *q, *context = NULL; - KMX_BOOL isEol , first = TRUE; + Buf = new KMX_BYTE[FileSize+1]; + if(!loadfileproc(szNameUtf8.c_str(), fk->extra->kmnFilename.c_str(), Buf, &FileSize, msgprocContext)) { + delete[] Buf; + return FALSE; + } + Buf[FileSize] = 0; // zero-terminate for strtok - while(fgets(str, str_size, fp)) - { - isEol = *(strchr(str, 0) - 1) == '\n'; - p = strtok_r(str, ";", &context); // I3481 - q = strtok_r(NULL, ";\n", &context); - if(p && q) - { - if(first && *p == (KMX_CHAR)0xEF && *(p+1) == (KMX_CHAR)0xBB && *(p+2) == (KMX_CHAR)0xBF) p += 3; // I3056 UTF-8 // I3512 - first = FALSE; + char* filetok; + char* filecontext; + filetok = strtok_r((char*)Buf, "\n", &filecontext); + + if(*filetok == (KMX_CHAR)0xEF && *(filetok+1) == (KMX_CHAR)0xBB && *(filetok+2) == (KMX_CHAR)0xBF) filetok += 3; // I3056 UTF-8 // I3512 + + while(filetok) { + KMX_CHAR str[str_size], *p, *q, *context = NULL; + + if(strlen(filetok) >= str_size) { + delete[] Buf; + // TODO chuck a wobbly + return FALSE; + } + strcpy(str, filetok); + p = strtok_r(str, ";\r", &context); // I3481 + q = strtok_r(nullptr, ";\r", &context); + if(p && q) { kmc_strupr(q); // I3481 // I3641 - long n = strtol(p, NULL, 16); + long n = strtol(p, nullptr, 16); if (*q != '<') { PKMX_WCHAR q0 = strtowstr(q); AddCode_IncludedCodes((int)n, q0); delete[] q0; } } - if(!isEol ) - { - while(fgets(str, str_size, fp)) if(*(strchr(str, 0)-1) == '\n') break; - } + filetok = strtok_r(nullptr, "\n", &filecontext); } - fclose(fp); - - return TRUE; -} - -KMX_BOOL NamedCodeConstants::LoadFile(const KMX_CHAR *filename) -{ - const int buf_size = 260; - KMX_CHAR buf[buf_size]; - // Look in current directory first -- REMOVED AS DANGEROUS - /* strncpy(buf, filename, (buf_size-1)); buf[buf_size-1] = 0; // I3481 - if(kmcmp_FileExists(buf)) - return IntLoadFile(buf); - */ - // Then look in keyboard file directory (CompileDir) - strncpy(buf, CompileDir, (buf_size-1)); buf[buf_size-1] = 0; // I3481 - strncat(buf, filename, (buf_size-1)-strlen(CompileDir)); buf[buf_size-1] = 0; - if(kmcmp_FileExists(buf)) - return IntLoadFile(buf); - - //TODO: sort out how to find common includes in non-Windows platforms: - #ifdef _WINDOWS_ - // Finally look in kmcmpdll.dll directory - GetModuleFileName(0, buf, buf_size); - - KMX_CHAR *p = strrchr_slash(buf); - if(p) - p++; - else - p = buf; - *p = 0; - strncat_s(buf, _countof(buf), filename, (buf_size-1)-strlen(buf)); buf[buf_size-1] = 0; // I3481 // I3641 - if(kmcmp_FileExists(buf)) - return IntLoadFile(buf); - #endif + delete[] Buf; reindex(); - - return FALSE; + return TRUE; } void NamedCodeConstants::reindex() diff --git a/developer/src/kmcmplib/src/NamedCodeConstants.h b/developer/src/kmcmplib/src/NamedCodeConstants.h index 83d707d092..c537a73361 100644 --- a/developer/src/kmcmplib/src/NamedCodeConstants.h +++ b/developer/src/kmcmplib/src/NamedCodeConstants.h @@ -2,6 +2,8 @@ #ifndef NAMEDCODECONSTANTS_H #define NAMEDCODECONSTANTS_H +#include "compfile.h" + #define MAX_ENAME 128 #define ALLOC_SIZE 256 @@ -23,14 +25,13 @@ namespace kmcmp{ int GetCode_IncludedCodes(const KMX_WCHAR *codename); void AddCode_IncludedCodes(int n, const KMX_WCHAR *p); - KMX_BOOL IntLoadFile(const KMX_CHAR *filename); public: NamedCodeConstants(); ~NamedCodeConstants(); void reindex(); void AddCode(int n, const KMX_WCHAR *p, KMX_DWORD storeIndex); - KMX_BOOL LoadFile(const KMX_CHAR *filename); + KMX_BOOL LoadFile(PFILE_KEYBOARD fk, const KMX_WCHAR *filename); int GetCode(const KMX_WCHAR *codename, KMX_DWORD *storeIndex); }; } diff --git a/developer/src/kmcmplib/src/compfile.h b/developer/src/kmcmplib/src/compfile.h index 7c262be090..c54663aba7 100644 --- a/developer/src/kmcmplib/src/compfile.h +++ b/developer/src/kmcmplib/src/compfile.h @@ -123,7 +123,8 @@ typedef FILE_VKDICTIONARY *PFILE_VKDICTIONARY; * Extra metadata for API consumers */ struct FILE_KEYBOARD_EXTRA { - std::u16string kvksFilename; // original TSS_VISUALKEYBOARD value + std::string kmnFilename; // utf-8 + std::u16string kvksFilename; // utf-16, original TSS_VISUALKEYBOARD value }; typedef struct FILE_KEYBOARD_EXTRA* PFILE_KEYBOARD_EXTRA; diff --git a/developer/src/kmcmplib/src/kmcmplib.h b/developer/src/kmcmplib/src/kmcmplib.h index 70718f98bc..f22c836bae 100644 --- a/developer/src/kmcmplib/src/kmcmplib.h +++ b/developer/src/kmcmplib/src/kmcmplib.h @@ -14,7 +14,6 @@ namespace kmcmp { extern KMX_BOOL FMnemonicLayout; extern KMX_BOOL FOldCharPosMatching; extern int CompileTarget; - extern KMX_CHAR CompileDir[260]; // TODO: this should not be a fixed buffer extern int BeginLine[4]; extern int currentLine; extern NamedCodeConstants *CodeConstants; diff --git a/developer/src/kmcmplib/src/meson.build b/developer/src/kmcmplib/src/meson.build index 727d6831e6..a81efac562 100644 --- a/developer/src/kmcmplib/src/meson.build +++ b/developer/src/kmcmplib/src/meson.build @@ -25,8 +25,10 @@ endif name_suffix = [] if cpp_compiler.get_id() == 'emscripten' - lib_links = ['--whole-archive', '--bind', '-sMODULARIZE', '-sEXPORT_ES6'] - links += ['-lnodefs.js', '--bind', '-sEXPORTED_RUNTIME_METHODS=[\'UTF8ToString\']'] + # wasm-exceptions supported in Node 18+, Chrome 95+, Firefox 100+, Safari 15.2+ + flags += ['-fwasm-exceptions'] + lib_links = ['--whole-archive', '-sMODULARIZE', '-sEXPORT_ES6'] + links += ['-fwasm-exceptions', '--bind', '-sEXPORTED_RUNTIME_METHODS=[\'UTF8ToString\']'] # tests are building as ES6 so we need to declare the file extension # note that meson currently struggles with the sanitycheckc_cross.exe # program, because it has a hard coded extension (.exe) which is not @@ -44,7 +46,6 @@ lib = library('kmcmplib', 'CompilerInterfaces.cpp', 'DeprecationChecks.cpp', 'Edition.cpp', - 'filesystem.cpp', 'NamedCodeConstants.cpp', 'versioning.cpp', 'virtualcharkeys.cpp', @@ -79,7 +80,7 @@ if cpp_compiler.get_id() == 'emscripten' host = executable('wasm-host', #'wasm-host.cpp', cpp_args: defns, include_directories: inc, - link_args: links, + link_args: links + lib_links, objects: lib.extract_all_objects(), dependencies: icuuc_dep) endif diff --git a/developer/src/kmcmplib/src/pch.h b/developer/src/kmcmplib/src/pch.h index f878ad11be..358e28998a 100644 --- a/developer/src/kmcmplib/src/pch.h +++ b/developer/src/kmcmplib/src/pch.h @@ -10,6 +10,4 @@ #include "../../../../common/windows/cpp/include/crc32.h" #include -#include - #include diff --git a/developer/src/kmcmplib/tests/api-test.cpp b/developer/src/kmcmplib/tests/api-test.cpp index b347773220..cdbabea4d5 100644 --- a/developer/src/kmcmplib/tests/api-test.cpp +++ b/developer/src/kmcmplib/tests/api-test.cpp @@ -18,54 +18,12 @@ #include #include "../src/compfile.h" #include -#include "../src/filesystem.h" +#include "util_filesystem.h" +#include "util_callbacks.h" void setup(); void test_kmcmp_CompileKeyboard(char *kmn_file); -std::vector error_vec; - -int msgproc(int line, uint32_t dwMsgCode, const char* szText, void* context) { - error_vec.push_back(dwMsgCode); - const char*t = "unknown"; - switch(dwMsgCode & 0xF000) { - case CERR_HINT: t=" hint"; break; - case CERR_WARNING: t="warning"; break; - case CERR_ERROR: t=" error"; break; - case CERR_FATAL: t=" fatal"; break; - } - printf("line %d %s %04.4x: %s\n", line, t, (unsigned int)dwMsgCode, szText); - return 1; -} - -bool loadfileProc(const char* filename, const char* baseFilename, void* data, int* size, void* context) { - FILE* fp = Open_File(filename, "rb"); - if(!fp) { - return false; - } - - if(!data) { - // return size - if(fseek(fp, 0, SEEK_END) != 0) { - fclose(fp); - return false; - } - *size = ftell(fp); - if(*size == -1L) { - fclose(fp); - return false; - } - } else { - // return data - if(fread(data, 1, *size, fp) != *size) { - fclose(fp); - return false; - } - } - fclose(fp); - return true; -} - int main(int argc, char *argv[]) { if(argc < 1) { puts("Usage: api-test "); @@ -82,6 +40,13 @@ void setup() { error_vec.clear(); } +/* + TODO: tests to run: + 4. ANSI (no BOM of course) + 8. file without blank last line (cannot compare with fixture due to bug in kmcmpdll...) + Hint to add: k004_ansi.kmn: Hint: 10A6 Keyman Developer has detected that the file has ANSI encoding. Consider converting this file to UTF-8 +*/ + void test_kmcmp_CompileKeyboard(char *kmn_file) { // Create an empty file FILE *fp = Open_File(kmn_file, "wb"); diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/compile_legacy.bat b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/compile_legacy.bat new file mode 100644 index 0000000000..e346418eb4 --- /dev/null +++ b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/compile_legacy.bat @@ -0,0 +1,4 @@ +@echo off +echo Compiles the keyboards using the legacy kmcomp.exe +echo to use as baseline comparisons for kmcmplib +for %%d in (*.kmn) do kmcomp -no-compiler-version -d %%d \ No newline at end of file diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k001_utf16.kmn b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k001_utf16.kmn new file mode 100644 index 0000000000000000000000000000000000000000..2b3180c36ab4b473e74b1b3487fc8f0a61d623f6 GIT binary patch literal 452 zcmZvX%}T>S6otRF;Ci;RG8IwmMz9N^r4>Z2P-{0*q)pQpYC6SO#HDW`K8}yz1F2_b zEO8;>PVStad(V7-rC7RTRHQsou;NLlV@XTQNQ_74DzC9(@0sYdEGXqE<#-S~6_Scs zhQAAVAtuv(qPk(oDf=`z;)0$KKQreYOjH}hfM HO;rB?W(q}E literal 0 HcmV?d00001 diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k001_utf16.kmx b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k001_utf16.kmx new file mode 100644 index 0000000000000000000000000000000000000000..13ea2a686e09c16db68ff7bb355e114b9125d76d GIT binary patch literal 356 zcmX|-y-EW?6h@CC{(@LJjfK^g5*smH5)hGKgd~cM=wcK?h&EbS+F6LTi1-vfKuBe6 zY2hPS_yT(Fx_IF%-}l|QGdt5f>~@%g>e1pi)hKINm-ap;#+1e%<2!;qYd!Vk use(main) + +group(main) using keys + ++ [K_A] > 'a' +'a' + [K_B] > 'ខ្មែរ' diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k002_utf8_without_bom.kmx b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k002_utf8_without_bom.kmx new file mode 100644 index 0000000000000000000000000000000000000000..0b9c9294182d9387165c98e1ffc84c8fe45452e3 GIT binary patch literal 378 zcmX|-zb}JP6owxn6pNv86O*ZdP*T+eoFYo)Fd(S=j8hhJK#^I(|T)`TOA8S;iuF8z!+fx45AU`;5awoSE5eup-GIf`;l(pDb^*mi- zgBt5Bs~4F|6HDysw`j7)rhS|MtM+EoD_MGH-mK1!I^)1;9k+mrTP?|74J)FJ+x_0F i=_X>k3LRTrscR?m>{x#(?dZ7 use(main) + +group(main) using keys + ++ [K_A] > 'a' +'a' + [K_B] > 'ខ្មែរ' diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k003_utf8_with_bom.kmx b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k003_utf8_with_bom.kmx new file mode 100644 index 0000000000000000000000000000000000000000..ee1cf4225502e3c7944b58f301e5be649af4ec00 GIT binary patch literal 372 zcmX|-y-EW?6h@B`{B116X{}O;1cXJqBp?!k5sZqJk{HD$Xi`MP(k_Kq2MIojmG}T+ zXuY}scO@6Efi@` zVV7<77VFupB1igtn$*~{k9%Rq-fA{K%}z+nsvN3Q&Yafqd|2~NN&bIY3KDI+*JNKs gw;=I(PHeTMs$I;pj=nFg=(!IcVH94&lMfV=KM7PUb^rhX literal 0 HcmV?d00001 diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k004_ansi.kmn b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k004_ansi.kmn new file mode 100644 index 0000000000..50a1b31ea1 --- /dev/null +++ b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k004_ansi.kmn @@ -0,0 +1,13 @@ +c Description: Verifies that kmcmplib can compile an ANSI file +c This has some high-ascii letters in cp1252 to ensure that +c it fails to load as 'utf8 without bom' + +store(&NAME) 'k004_ansi' +store(&VERSION) '9.0' + +begin unicode > use(main) + +group(main) using keys + ++ [K_A] > 'a' +'a' + [K_B] > 'ÀÐ' diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k004_ansi.kmx b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k004_ansi.kmx new file mode 100644 index 0000000000000000000000000000000000000000..6c41da979cb2a3ec20aadf6de0ca778fb8ce5ec1 GIT binary patch literal 350 zcmX|-y-EW?6h@CCYQTV1Y%Ef3DG6A_&MX88!36RnVxa_+Vi8S|DsPZN@&q9dkp~bf zYfGyKTe*wxmCUXD) literal 0 HcmV?d00001 diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k005_bitmap.bmp b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k005_bitmap.bmp new file mode 100644 index 0000000000000000000000000000000000000000..509b89ae6df7f09a442ae60f215a6c7b3211b34f GIT binary patch literal 246 zcmZvUF%Ez*2t_e5>FO~&hr4&_cK5)zF7R>OXdqB#E&96yg&T8zj G@{Su^DQ%(v literal 0 HcmV?d00001 diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k005_bitmap.kmn b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k005_bitmap.kmn new file mode 100644 index 0000000000..926ccdeeaf --- /dev/null +++ b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k005_bitmap.kmn @@ -0,0 +1,12 @@ +c Description: Verifies that kmcmplib can load a bitmap without file extension + +store(&NAME) 'k005_bitmap' +store(&VERSION) '9.0' +store(&BITMAP) 'k005_bitmap' + +begin unicode > use(main) + +group(main) using keys + ++ [K_A] > 'a' +'a' + [K_B] > 'ខ្មែរ' diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k005_bitmap.kmx b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k005_bitmap.kmx new file mode 100644 index 0000000000000000000000000000000000000000..bc9bc9b671724050e169e59fce976a18d54a030e GIT binary patch literal 656 zcmZ{hyGjF55QhJV5JkZh;`acRmwz7&=*hh@R?A}o^(Fw$>p)BB*B zffhV~2T#xjoA1IijKLecfV&^}PM(8l@|;2L6X&2nE|qnpYn`g0GgqI`FK9t~+E=Ix zr$i`ut*fMpR>+q$@22zGrmm`{HEp0v|4#>;sWV^Frn^B}<&If*f9SrwNI%dPd8h-O z>yVd8RbILaLmMHn(q5d*m8d36E=qSuO$aC_)80MxBQ&hmt@rA+ysp>gH(DpC*#9-V z0w3%j85xb@rP%qu9Eyo?oCG{6#Oic92&~e!$x2D|BF%`g<4g%dtuD`P6eIRAp=916x*GXhr`_H use(main) + +group(main) using keys + ++ [K_A] > 'a' +'a' + [K_B] > 'ខ្មែរ' diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k006_icon.kmx b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k006_icon.kmx new file mode 100644 index 0000000000000000000000000000000000000000..f994a1dcac9e5ae797eb88eed9cee4b0e6f85b00 GIT binary patch literal 728 zcmbu6JxhX76vzKYU{S*}M9=CF;v`N*4WU9rNH3^GLlE{dNK~#(-JqeGBgC;O`Vb+F zjedqcfJ@|NzjNS>L1T*-NfuF<9K>=T?=vWszRYPY!J|SPwy!O@9q0W6a zs|}U3t`#~KmG_fb?GRU0)0#G^OMfTx$qp&2GJSP+l(glyNUQA0_>-Idlm+r-ZR3ZN zkGPps<)(Wuk}(_$?Z#oQL^NgPqI6B^2FirfN$!sL0U8$TD(=PY_%-hEj3JX^Ulc{? zasM{<);X}Z%7EofoYz5F%?RQ`(K+8^8W)_p-7YPBsr@Qn>kZm|*}mHT`SFvrMGq4+QP0yrw1lmGw# literal 0 HcmV?d00001 diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k007_includecodes_r_n.kmn b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k007_includecodes_r_n.kmn new file mode 100644 index 0000000000..71d72d5120 --- /dev/null +++ b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k007_includecodes_r_n.kmn @@ -0,0 +1,12 @@ +c Description: Verifies that kmcmplib can load an includecodes file with \r\n line endings + +store(&NAME) 'k007_includecodes_r_n' +store(&VERSION) '9.0' +store(&includecodes) 'k007_includecodes_r_n.txt' + +begin unicode > use(main) + +group(main) using keys + ++ [K_A] > $LOWER_A +$LOWER_A + [K_B] > $LOWER_B diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k007_includecodes_r_n.kmx b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k007_includecodes_r_n.kmx new file mode 100644 index 0000000000000000000000000000000000000000..f8b4eac1b0d9103c7767e487b5109a06aed8e1ec GIT binary patch literal 462 zcma)%J4%C55JrzSDq4tzwy9Ev-%9L~fQZBwiHe=Z#3J|zmm`-ru-1)wlxv$dkL4`TUG*`bcreZN>By?W7ilL#L#M^jq*~&ofWJMn2 zUSj{dJj$$m%7-jT;@)rbqU@`;C3M|ihyS0LqfJlZ use(main) + +group(main) using keys + ++ [K_A] > $LOWER_A +$LOWER_A + [K_B] > $LOWER_B diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k008_includecodes_n.kmx b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k008_includecodes_n.kmx new file mode 100644 index 0000000000000000000000000000000000000000..aa158cdd546cdde915e4a55c1db521e57d4abb04 GIT binary patch literal 454 zcma)%zb=De6o;Q$N*Khz%F>vcZrIv}AYW9XNQWlUmZ3onNVox$!C+{51>y<}(!t;Y zT!2O58f-l0Q{9?4$@8Ay@0|1gOKQ7SCSc(<`M}7;Vq_(BQ96omLphAs!QiZwuH4I< zJV;Ms|C>C@xO~dH%*dj9zs%FJpf~T9ja`yZ6E%3TAmB8Bu*W5Yup0s-ZP)RHs)YS%IvAz p!xzGhzq^ya7*m9eU;geZ=_aFHgeP0iQr1olYJL5SG{V!AP(Sg;I(+~D literal 0 HcmV?d00001 diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k008_includecodes_n.txt b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k008_includecodes_n.txt new file mode 100644 index 0000000000..4cc3fe4351 --- /dev/null +++ b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k008_includecodes_n.txt @@ -0,0 +1,2 @@ +0061;LOWER_A +0062;LOWER_B diff --git a/developer/src/kmcmplib/tests/kmcompxtest.cpp b/developer/src/kmcmplib/tests/kmcompxtest.cpp index c5d189798b..5dbaee88bc 100644 --- a/developer/src/kmcmplib/tests/kmcompxtest.cpp +++ b/developer/src/kmcmplib/tests/kmcompxtest.cpp @@ -13,7 +13,8 @@ #include #include #include -#include "../src/filesystem.h" +#include "util_filesystem.h" +#include "util_callbacks.h" #ifdef _MSC_VER #else @@ -22,57 +23,11 @@ using namespace std; -vector < int > error_vec; - #define CERR_FATAL 0x00008000 #define CERR_ERROR 0x00004000 #define CERR_WARNING 0x00002000 #define CERR_HINT 0x00001000 -int msgproc(int line, uint32_t dwMsgCode, const char* szText, void* context) -{ - error_vec.push_back(dwMsgCode); - const char*t = "unknown"; - switch(dwMsgCode & 0xF000) { - case CERR_HINT: t=" hint"; break; - case CERR_WARNING: t="warning"; break; - case CERR_ERROR: t=" error"; break; - case CERR_FATAL: t=" fatal"; break; - } - printf("line %d %s %04.4x: %s\n", line, t, (unsigned int)dwMsgCode, szText); - return 1; -} - -bool loadfileProc(const char* filename, const char* baseFilename, void* data, int* size, void* context) { - FILE* fp = Open_File(filename, "rb"); - if(!fp) { - return false; - } - - if(!data) { - // return size - if(fseek(fp, 0, SEEK_END) != 0) { - fclose(fp); - return false; - } - *size = ftell(fp); - if(*size == -1L) { - fclose(fp); - return false; - } - } else { - // return data - if(fread(data, 1, *size, fp) != *size) { - fclose(fp); - return false; - } - } - fclose(fp); - return true; -} - -#include "../src/filesystem.h" - int main(int argc, char *argv[]) { if(argc < 4) { diff --git a/developer/src/kmcmplib/tests/meson.build b/developer/src/kmcmplib/tests/meson.build index 2468ac53b1..cc51189a63 100644 --- a/developer/src/kmcmplib/tests/meson.build +++ b/developer/src/kmcmplib/tests/meson.build @@ -6,16 +6,20 @@ fs = import('fs') -tests_flags = [] +tests_links = [] + +if cpp_compiler.get_id() == 'emscripten' + tests_links += ['-lnodefs.js'] +endif input_path = meson.current_source_dir() / '../../../../common/test/keyboards/baseline' output_path = meson.current_build_dir() -kmcompxtest = executable('kmcompxtest', 'kmcompxtest.cpp', - cpp_args: defns, +kmcompxtest = executable('kmcompxtest', ['kmcompxtest.cpp','util_filesystem.cpp','util_callbacks.cpp'], + cpp_args: defns + flags, include_directories: inc, name_suffix: name_suffix, - link_args: links + tests_flags, + link_args: links + tests_links, objects: lib.extract_all_objects(), dependencies: icuuc_dep, ) @@ -76,6 +80,25 @@ foreach kbd : tests test(kbd, kmcompxtest, args: [kbd_src, kbd_obj, join_paths(input_path, kbd) + '.kmx']) endforeach +valid_keyboard_tests = [ + 'k001_utf16', + 'k002_utf8_without_bom', + 'k003_utf8_with_bom', + # 'k004_ansi', # TODO: enable ansi test when we have the icu datafiles + 'k005_bitmap', + 'k006_icon', + 'k007_includecodes_r_n', + 'k008_includecodes_n' +] + +fixtures_path = meson.current_source_dir() / 'fixtures/valid-keyboards' + +foreach kbd : valid_keyboard_tests + kbd_src = join_paths(fixtures_path, kbd) + '.kmn' + kbd_obj = join_paths(output_path, kbd) + '.kmx' + test(kbd, kmcompxtest, args: [kbd_src, kbd_obj, join_paths(fixtures_path, kbd) + '.kmx']) +endforeach + # Test fixtures that come from keyboards repo -- but only for a "full" test, # which typically we run on CI no more than once a day, because it's expensive. @@ -107,11 +130,11 @@ endif # Test the API endpoints -apitest = executable('api-test', 'api-test.cpp', - cpp_args: defns, +apitest = executable('api-test', ['api-test.cpp','util_filesystem.cpp','util_callbacks.cpp'], + cpp_args: defns + flags, include_directories: inc, name_suffix: name_suffix, - link_args: links + tests_flags, + link_args: links + tests_links, objects: lib.extract_all_objects(), dependencies: icuuc_dep ) @@ -119,10 +142,10 @@ apitest = executable('api-test', 'api-test.cpp', test('api-test', apitest, args: [output_path / 'blank_keyboard.kmx']) usetapitest = executable('uset-api-test', 'uset-api-test.cpp', - cpp_args: defns, + cpp_args: defns + flags, include_directories: inc, name_suffix: name_suffix, - link_args: links + tests_flags, + link_args: links + tests_links, objects: lib.extract_all_objects(), dependencies: icuuc_dep, ) diff --git a/developer/src/kmcmplib/tests/util_callbacks.cpp b/developer/src/kmcmplib/tests/util_callbacks.cpp new file mode 100644 index 0000000000..e610a54c09 --- /dev/null +++ b/developer/src/kmcmplib/tests/util_callbacks.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include "util_filesystem.h" +#include "../src/compfile.h" +#include + +std::vector error_vec; + +int msgproc(int line, uint32_t dwMsgCode, const char* szText, void* context) { + error_vec.push_back(dwMsgCode); + const char*t = "unknown"; + switch(dwMsgCode & 0xF000) { + case CERR_HINT: t=" hint"; break; + case CERR_WARNING: t="warning"; break; + case CERR_ERROR: t=" error"; break; + case CERR_FATAL: t=" fatal"; break; + } + printf("line %d %s %04.4x: %s\n", line, t, (unsigned int)dwMsgCode, szText); + return 1; +} + +bool loadfileProc(const char* filename, const char* baseFilename, void* data, int* size, void* context) { + std::string resolvedFilename = filename; + if(baseFilename && *baseFilename && IsRelativePath(filename)) { + char* p; + if ((p = strrchr_slash((char*)baseFilename)) != nullptr) { + std::string basePath = std::string(baseFilename, (int)(p - baseFilename + 1)); + resolvedFilename = basePath; + resolvedFilename.append(filename); + } + } + + FILE* fp = Open_File(resolvedFilename.c_str(), "rb"); + if(!fp) { + return false; + } + + if(!data) { + // return size + if(fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + return false; + } + *size = ftell(fp); + if(*size == -1L) { + fclose(fp); + return false; + } + } else { + // return data + if(fread(data, 1, *size, fp) != *size) { + fclose(fp); + return false; + } + } + fclose(fp); + return true; +} \ No newline at end of file diff --git a/developer/src/kmcmplib/tests/util_callbacks.h b/developer/src/kmcmplib/tests/util_callbacks.h new file mode 100644 index 0000000000..345de64b9f --- /dev/null +++ b/developer/src/kmcmplib/tests/util_callbacks.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +int msgproc(int line, uint32_t dwMsgCode, const char* szText, void* context); +bool loadfileProc(const char* filename, const char* baseFilename, void* data, int* size, void* context); + +extern std::vector error_vec; \ No newline at end of file diff --git a/developer/src/kmcmplib/src/filesystem.cpp b/developer/src/kmcmplib/tests/util_filesystem.cpp similarity index 84% rename from developer/src/kmcmplib/src/filesystem.cpp rename to developer/src/kmcmplib/tests/util_filesystem.cpp index a343641acc..7f9edd6b36 100644 --- a/developer/src/kmcmplib/src/filesystem.cpp +++ b/developer/src/kmcmplib/tests/util_filesystem.cpp @@ -7,7 +7,7 @@ #include #include #include -#include "filesystem.h" +#include "util_filesystem.h" #ifdef _MSC_VER #include @@ -186,3 +186,42 @@ KMX_BOOL kmcmp_FileExists(const KMX_WCHAR* filename) { return FALSE; }; + + +bool IsRelativePath(KMX_CHAR const * p) { + // Relative path (returns TRUE): + // ..\...\BITMAP.BMP + // PATH\BITMAP.BMP + // BITMAP.BMP + + // Semi-absolute path (returns FALSE): + // \...\BITMAP.BMP + + // Absolute path (returns FALSE): + // C:\...\BITMAP.BMP + // \\SERVER\SHARE\...\BITMAP.BMP + + if ((*p == '\\') || (*p == '/')) return FALSE; + if (*p && *(p + 1) == ':') return FALSE; + + return TRUE; +} + +bool IsRelativePath(KMX_WCHAR const * p) { + // Relative path (returns TRUE): + // ..\...\BITMAP.BMP + // PATH\BITMAP.BMP + // BITMAP.BMP + + // Semi-absolute path (returns FALSE): + // \...\BITMAP.BMP + + // Absolute path (returns FALSE): + // C:\...\BITMAP.BMP + // \\SERVER\SHARE\...\BITMAP.BMP + + if ((*p == u'\\') || (*p == u'/'))return FALSE; + if (*p && *(p + 1) == u':') return FALSE; + + return TRUE; +} \ No newline at end of file diff --git a/developer/src/kmcmplib/src/filesystem.h b/developer/src/kmcmplib/tests/util_filesystem.h similarity index 82% rename from developer/src/kmcmplib/src/filesystem.h rename to developer/src/kmcmplib/tests/util_filesystem.h index 786b7268ac..4c94dae6bf 100644 --- a/developer/src/kmcmplib/src/filesystem.h +++ b/developer/src/kmcmplib/tests/util_filesystem.h @@ -1,7 +1,7 @@ #pragma once #include -#include "kmx_u16.h" +#include "../src/kmx_u16.h" // Opens files on windows and non-windows platforms. Datatypes for Filename and mode must be the same. // returns FILE* if file could be opened; FILE needs to be closed in calling function @@ -10,3 +10,6 @@ FILE* Open_File(const KMX_WCHART* Filename, const KMX_WCHART* mode); FILE* Open_File(const KMX_WCHAR* Filename, const KMX_WCHAR* mode); KMX_BOOL kmcmp_FileExists(const KMX_CHAR *filename); KMX_BOOL kmcmp_FileExists(const KMX_WCHAR *filename); + +bool IsRelativePath(KMX_CHAR const * p); +bool IsRelativePath(KMX_WCHAR const * p); -- GitLab From c95e232f3c51073b292c4706a84c14be9898da6b Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 31 May 2023 12:13:59 +1000 Subject: [PATCH 164/214] chore(developer): Add TODO issue numbers to PR --- developer/src/kmc-kmn/src/compiler/compiler.ts | 8 ++++---- developer/src/kmcmplib/include/kmcmplibapi.h | 2 +- developer/src/kmcmplib/src/CheckFilenameConsistency.cpp | 2 +- developer/src/kmcmplib/src/Compiler.cpp | 2 +- developer/src/kmcmplib/src/CompilerInterfaces.cpp | 3 +++ developer/src/kmcmplib/src/meson.build | 5 ----- developer/src/kmcmplib/tests/api-test.cpp | 2 +- developer/src/kmcmplib/tests/meson.build | 2 +- 8 files changed, 12 insertions(+), 14 deletions(-) diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index b27440fd06..3c6df80e7e 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -120,7 +120,7 @@ export class KmnCompiler { } private loadFileCallback = (filename: string, baseFilename: string, buffer: number, bufferSize: number): number => { - // TODO: we can optimize this in future by avoiding loading the file twice + // TODO: we can optimize this in future by avoiding loading the file twice #8885 let resolvedFilename = this.callbacks.resolveFilename(baseFilename, filename); let data = this.callbacks.loadFile(resolvedFilename); if(!data) { @@ -133,7 +133,7 @@ export class KmnCompiler { } if(bufferSize != data.byteLength) { - // TODO: consider chucking a wobbly because this is a bug + // TODO: consider chucking a wobbly because this is a bug #8885 /* c8 ignore next 2 */ return 0; } @@ -195,7 +195,7 @@ export class KmnCompiler { reader.validate(kvks, this.callbacks.loadSchema('kvks')); } catch(e) { console.log(e); - // TODO: also unit test + // TODO: also unit test #8886 // TODO: this.callbacks.reportMessage(CompilerMessages.Error_InvalidKvksFile({e})); return null; } @@ -203,7 +203,7 @@ export class KmnCompiler { let vk = reader.transform(kvks, errors); if(!vk || errors.length) { console.dir(errors); - // TODO: also unit test + // TODO: also unit test #8886 // TODO: this.callbacks.reportMessage(CompilerMessages.Error_InvalidKvksFile({e})); return null; } diff --git a/developer/src/kmcmplib/include/kmcmplibapi.h b/developer/src/kmcmplib/include/kmcmplibapi.h index 5c2ae46fda..0b41af6990 100644 --- a/developer/src/kmcmplib/include/kmcmplibapi.h +++ b/developer/src/kmcmplib/include/kmcmplibapi.h @@ -35,7 +35,7 @@ struct KMCMP_COMPILER_RESULT { std::string kvksFilename; }; -// TODO: parameters in UTF-8 +// TODO: parameters in UTF-8 #8887 typedef int (*kmcmp_CompilerMessageProc)(int line, uint32_t dwMsgCode, const char* szText, void* context); // parameters in UTF-8 diff --git a/developer/src/kmcmplib/src/CheckFilenameConsistency.cpp b/developer/src/kmcmplib/src/CheckFilenameConsistency.cpp index 3a185bc403..6d113d116b 100644 --- a/developer/src/kmcmplib/src/CheckFilenameConsistency.cpp +++ b/developer/src/kmcmplib/src/CheckFilenameConsistency.cpp @@ -24,7 +24,7 @@ KMX_DWORD CheckFilenameConsistency( KMX_CHAR const * Filename, bool ReportMissin KMX_DWORD CheckFilenameConsistency(KMX_WCHAR const * Filename, bool ReportMissingFile) { // TODO: we no longer have filesystem access here. We could move this check to // kmc itself, and make it consistent across all compilers that use the same - // loader callback + // loader callback -- see #8883 return CERR_None; #if 0 diff --git a/developer/src/kmcmplib/src/Compiler.cpp b/developer/src/kmcmplib/src/Compiler.cpp index 91e02e14e7..49484b1acc 100644 --- a/developer/src/kmcmplib/src/Compiler.cpp +++ b/developer/src/kmcmplib/src/Compiler.cpp @@ -3428,7 +3428,7 @@ bool UTF16TempFromUTF8(KMX_BYTE* infile, int sz, KMX_BYTE** tempfile, int *sz16) result = converter.from_bytes((char*)infile, (char*)infile+sz); } catch(std::range_error e) { UErrorCode status = U_ZERO_ERROR; - // TODO: we need ICU data files here @srl295 plz help! + // TODO: we need ICU data files here #8884 UConverter* conv = ucnv_open("windows-1252", &status); if(U_FAILURE(status)) { return FALSE; diff --git a/developer/src/kmcmplib/src/CompilerInterfaces.cpp b/developer/src/kmcmplib/src/CompilerInterfaces.cpp index 1a4e77f8e8..16b5b98654 100644 --- a/developer/src/kmcmplib/src/CompilerInterfaces.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfaces.cpp @@ -13,6 +13,9 @@ bool CompileKeyboardHandle(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk); #ifdef __EMSCRIPTEN__ +// TODO: move emscripten wrappers into their own .cpp. Also move CompileKeyboardHandle +// into its own .cpp, so CompilerInterfaces.cpp has only C public API functions listed. +// #8889 /* WASM interface for compiler message callback diff --git a/developer/src/kmcmplib/src/meson.build b/developer/src/kmcmplib/src/meson.build index a81efac562..e697a0dced 100644 --- a/developer/src/kmcmplib/src/meson.build +++ b/developer/src/kmcmplib/src/meson.build @@ -29,11 +29,6 @@ if cpp_compiler.get_id() == 'emscripten' flags += ['-fwasm-exceptions'] lib_links = ['--whole-archive', '-sMODULARIZE', '-sEXPORT_ES6'] links += ['-fwasm-exceptions', '--bind', '-sEXPORTED_RUNTIME_METHODS=[\'UTF8ToString\']'] - # tests are building as ES6 so we need to declare the file extension - # note that meson currently struggles with the sanitycheckc_cross.exe - # program, because it has a hard coded extension (.exe) which is not - # valid for node programs in module mode. - # name_suffix = '.mjs' endif icu = subproject('icu-for-uset', default_options: [ 'default_library=static', 'cpp_std=c++17', 'warning_level=0', 'werror=false']) diff --git a/developer/src/kmcmplib/tests/api-test.cpp b/developer/src/kmcmplib/tests/api-test.cpp index cdbabea4d5..cb0337caef 100644 --- a/developer/src/kmcmplib/tests/api-test.cpp +++ b/developer/src/kmcmplib/tests/api-test.cpp @@ -42,7 +42,7 @@ void setup() { /* TODO: tests to run: - 4. ANSI (no BOM of course) + 4. ANSI (no BOM of course) #8884 8. file without blank last line (cannot compare with fixture due to bug in kmcmpdll...) Hint to add: k004_ansi.kmn: Hint: 10A6 Keyman Developer has detected that the file has ANSI encoding. Consider converting this file to UTF-8 */ diff --git a/developer/src/kmcmplib/tests/meson.build b/developer/src/kmcmplib/tests/meson.build index cc51189a63..0d4c078ed3 100644 --- a/developer/src/kmcmplib/tests/meson.build +++ b/developer/src/kmcmplib/tests/meson.build @@ -84,7 +84,7 @@ valid_keyboard_tests = [ 'k001_utf16', 'k002_utf8_without_bom', 'k003_utf8_with_bom', - # 'k004_ansi', # TODO: enable ansi test when we have the icu datafiles + # 'k004_ansi', # TODO: enable ansi test when we have the icu datafiles #8884 'k005_bitmap', 'k006_icon', 'k007_includecodes_r_n', -- GitLab From 7ccd8bed4f016da38c9efd8d4fd8ac685e08372c Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 31 May 2023 10:23:42 +0700 Subject: [PATCH 165/214] chore(developer): fix npm pack for kmc-ldml --- package-lock.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package-lock.json b/package-lock.json index 20d7ce98c4..75d9e1abef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1030,6 +1030,7 @@ } }, "developer/src/kmc-ldml": { + "name": "@keymanapp/kmc-ldml", "license": "MIT", "dependencies": { "@keymanapp/keyman-version": "*", -- GitLab From bb675730a2065eb11fbc7a7b3943a6ade06ef037 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 31 May 2023 15:59:56 +0700 Subject: [PATCH 166/214] fix(common): tweak pack/publish support for npm 9.5.1 and node 18.16.0 The npm version command started failing when we updated to node 18.16.0, and it looks like it is related to the version numbers. This makes the pack file mangling idempotent and applies it to all package.json files in the repository. --- resources/build/build-utils-ci.inc.sh | 56 ++++++++++++++------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/resources/build/build-utils-ci.inc.sh b/resources/build/build-utils-ci.inc.sh index de36ae9e9b..fa72fd907b 100644 --- a/resources/build/build-utils-ci.inc.sh +++ b/resources/build/build-utils-ci.inc.sh @@ -100,18 +100,7 @@ function _builder_publish_npm_package() { dry_run=--dry-run fi - # We use --no-git-tag-version because our CI system controls version numbering - # and already tags releases. We also want to have the version of this match - # the release of Keyman Developer -- these two versions should be in sync. - # Because this is a large repo with multiple projects and build systems, it's - # better for us that individual build systems don't take too much ownership of - # git tagging. :) - npm version --allow-same-version --no-git-tag-version --no-commit-hooks "$VERSION_WITH_TAG" - - # Update all @keymanapp/* [*]dependencies in package.json to the current - # version-with-tag, so that the published version has precise dependencies, - # and we don't accidentally end up with either older or newer deps here - _builder_npm_set_dependency_version + _builder_write_npm_version # Note: In either case, npm publish MUST be given --access public to publish a # package in the @keymanapp scope on the public npm package index. @@ -128,18 +117,33 @@ function _builder_publish_npm_package() { fi } -# Updates all @keymanapp/* [*]dependencies in package.json to the current -# version-with-tag, so that the published version has precise dependencies, and -# we don't accidentally end up with either older or newer deps. This overwrites -# the local package.json, so it does need to be restored afterwards -function _builder_npm_set_dependency_version() { - cat package.json | "$JQ" --arg VERSION_WITH_TAG "$VERSION_WITH_TAG" \ - ' - . + - (try { dependencies: (.dependencies | to_entries | . + map(select(.key | match("@keymanapp/.*")) .value |= $VERSION_WITH_TAG) | from_entries) } catch {}) + - (try { devDependencies: (.devDependencies | to_entries | . + map(select(.key | match("@keymanapp/.*")) .value |= $VERSION_WITH_TAG) | from_entries) } catch {}) + - (try { bundleDependencies: (.bundleDependencies | to_entries | . + map(select(.key | match("@keymanapp/.*")) .value |= $VERSION_WITH_TAG) | from_entries) } catch {}) + - (try { optionalDependencies: (.optionalDependencies | to_entries | . + map(select(.key | match("@keymanapp/.*")) .value |= $VERSION_WITH_TAG) | from_entries) } catch {}) - ' > package1.json - mv -f package1.json package.json +function _builder_write_npm_version() { + # We use --no-git-tag-version because our CI system controls version numbering + # and already tags releases. We also want to have the version of this match + # the release of Keyman Developer -- these two versions should be in sync. + # Because this is a large repo with multiple projects and build systems, it's + # better for us that individual build systems don't take too much ownership of + # git tagging. :) + if ! "$JQ" -e '.version' package.json > /dev/null; then + pushd "$KEYMAN_ROOT" > /dev/null + npm version --allow-same-version --no-git-tag-version --no-commit-hooks --workspaces "$VERSION_WITH_TAG" + popd > /dev/null + fi + + # Updates all @keymanapp/* [*]dependencies in all package.jsons to the current + # version-with-tag, so that the published version has precise dependencies, and + # we don't accidentally end up with either older or newer deps. This overwrites + # the local package.json files, so they do need to be restored afterwards + find /c/Projects/keyman/app -name "package.json" -not -path '*/node_modules/*' -print0 | \ + while IFS= read -r -d '' line; do + cat "$line" | "$JQ" --arg VERSION_WITH_TAG "$VERSION_WITH_TAG" \ + ' + . + + (try { dependencies: (.dependencies | to_entries | . + map(select(.key | match("@keymanapp/.*")) .value |= $VERSION_WITH_TAG) | from_entries) } catch {}) + + (try { devDependencies: (.devDependencies | to_entries | . + map(select(.key | match("@keymanapp/.*")) .value |= $VERSION_WITH_TAG) | from_entries) } catch {}) + + (try { bundleDependencies: (.bundleDependencies | to_entries | . + map(select(.key | match("@keymanapp/.*")) .value |= $VERSION_WITH_TAG) | from_entries) } catch {}) + + (try { optionalDependencies: (.optionalDependencies | to_entries | . + map(select(.key | match("@keymanapp/.*")) .value |= $VERSION_WITH_TAG) | from_entries) } catch {}) + ' > "${line}_" + mv -f "${line}_" "$line" + done } \ No newline at end of file -- GitLab From 4b0f4e9c51121f626b93ac90e652bcb80de56a12 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 31 May 2023 19:12:20 +1000 Subject: [PATCH 167/214] chore: Update resources/build/build-utils-ci.inc.sh --- resources/build/build-utils-ci.inc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/build/build-utils-ci.inc.sh b/resources/build/build-utils-ci.inc.sh index fa72fd907b..cab449a463 100644 --- a/resources/build/build-utils-ci.inc.sh +++ b/resources/build/build-utils-ci.inc.sh @@ -134,7 +134,7 @@ function _builder_write_npm_version() { # version-with-tag, so that the published version has precise dependencies, and # we don't accidentally end up with either older or newer deps. This overwrites # the local package.json files, so they do need to be restored afterwards - find /c/Projects/keyman/app -name "package.json" -not -path '*/node_modules/*' -print0 | \ + find "$KEYMAN_ROOT" -name "package.json" -not -path '*/node_modules/*' -print0 | \ while IFS= read -r -d '' line; do cat "$line" | "$JQ" --arg VERSION_WITH_TAG "$VERSION_WITH_TAG" \ ' -- GitLab From fa66b4241022a71f6f45c361715d099433fe3058 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Wed, 31 May 2023 17:40:35 +0200 Subject: [PATCH 168/214] feat(linux): Add column for installation location Closes #8631. --- linux/keyman-config/keyman_config/view_installed.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux/keyman-config/keyman_config/view_installed.py b/linux/keyman-config/keyman_config/view_installed.py index 1a378a106d..aaa5196fbd 100755 --- a/linux/keyman-config/keyman_config/view_installed.py +++ b/linux/keyman-config/keyman_config/view_installed.py @@ -166,6 +166,7 @@ class ViewInstalledWindow(ViewInstalledWindowBase): str, # version str, # packageID int, # enum InstallLocation (KmpArea is GObject version) + str, # InstallLocation path str, # path to welcome file if it exists or None str) # path to options file if it exists or None @@ -184,6 +185,9 @@ class ViewInstalledWindow(ViewInstalledWindowBase): # i18n: column header in table displaying installed keyboards column = Gtk.TreeViewColumn(_("Version"), renderer, text=2) self.tree.append_column(column) + # i18n: column header in table displaying installed keyboards + column = Gtk.TreeViewColumn(_("Location"), renderer, text=5) + self.tree.append_column(column) select = self.tree.get_selection() select.connect("changed", self.on_tree_selection_changed) @@ -282,6 +286,7 @@ class ViewInstalledWindow(ViewInstalledWindowBase): kmpdata['version'], kmpdata['packageID'], install_area, + get_keyman_dir(install_area).replace(os.path.expanduser('~'), '~'), welcome_file, options_file]) -- GitLab From bbdcb1d5df47d38bc286cda6ebdd6abc3607613b Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Wed, 31 May 2023 14:02:54 -0400 Subject: [PATCH 169/214] auto: increment master version to 17.0.115 --- HISTORY.md | 7 +++++++ VERSION.md | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index c05c241eff..ff0cc6fbbe 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,12 @@ # Keyman Version History +## 17.0.114 alpha 2023-05-31 + +* chore(developer): replace cwrap wasm bindings (#8857) +* chore(developer): refactor kmcmplib interfaces (#8870) +* chore(developer): move keyboard repo fixtures (#8874) +* chore(linux): Move build steps to build.sh (#8864) + ## 17.0.113 alpha 2023-05-26 * docs(android): Update documentation for building Android on Linux (#8860) diff --git a/VERSION.md b/VERSION.md index a3a3dc809e..38d1ece2d6 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.114 \ No newline at end of file +17.0.115 \ No newline at end of file -- GitLab From 980b893644536d322f4a5196b35425de0581d5f5 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 30 May 2023 10:52:05 +0700 Subject: [PATCH 170/214] refactor(developer): move fs for kmn load to caller --- developer/src/kmcmplib/include/kmcmplibapi.h | 4 +- developer/src/kmcmplib/src/Compiler.cpp | 136 +++++++----------- .../src/kmcmplib/src/CompilerInterfaces.cpp | 89 ++++++++---- developer/src/kmcmplib/src/compfile.h | 29 ---- developer/src/kmcmplib/src/kmcmplib.h | 5 +- developer/src/kmcmplib/src/meson.build | 8 +- developer/src/kmcmplib/tests/api-test.cpp | 50 +++++-- developer/src/kmcmplib/tests/kmcompxtest.cpp | 33 ++++- developer/src/kmcmplib/tests/meson.build | 4 +- 9 files changed, 196 insertions(+), 162 deletions(-) diff --git a/developer/src/kmcmplib/include/kmcmplibapi.h b/developer/src/kmcmplib/include/kmcmplibapi.h index 4054d81e81..5c2ae46fda 100644 --- a/developer/src/kmcmplib/include/kmcmplibapi.h +++ b/developer/src/kmcmplib/include/kmcmplibapi.h @@ -36,7 +36,7 @@ struct KMCMP_COMPILER_RESULT { }; // TODO: parameters in UTF-8 -typedef int (*kmcmp_CompilerMessageProc)(int line, uint32_t dwMsgCode, char* szText, void* context); +typedef int (*kmcmp_CompilerMessageProc)(int line, uint32_t dwMsgCode, const char* szText, void* context); // parameters in UTF-8 // TODO typical usage: @@ -48,7 +48,7 @@ typedef int (*kmcmp_CompilerMessageProc)(int line, uint32_t dwMsgCode, char* szT // delete[] buf; // return error; // } -typedef bool (*kmcmp_LoadFileProc)(char* loadFilename, char* baseFilename, void* buffer, int* bufferSize); +typedef bool (*kmcmp_LoadFileProc)(const char* loadFilename, const char* baseFilename, void* buffer, int* bufferSize, void* context); // Parameters in UTF-8 EXTERN bool kmcmp_CompileKeyboard( diff --git a/developer/src/kmcmplib/src/Compiler.cpp b/developer/src/kmcmplib/src/Compiler.cpp index b09e36cbc1..8e0f94cb29 100644 --- a/developer/src/kmcmplib/src/Compiler.cpp +++ b/developer/src/kmcmplib/src/Compiler.cpp @@ -94,6 +94,9 @@ #include "CasedKeys.h" #include #include +#include +#include + #include "CheckFilenameConsistency.h" #include "UnreachableRules.h" #include "CheckForDuplicates.h" @@ -230,6 +233,8 @@ enum LinePrefixType { lptNone, lptKeymanAndKeymanWeb, lptKeymanWebOnly, lptKeyma /* Compile target */ kmcmp_CompilerMessageProc msgproc = NULL; +kmcmp_LoadFileProc loadfileproc = NULL; + void* msgprocContext = NULL; int kmcmp::currentLine = 0; @@ -3068,7 +3073,7 @@ KMX_DWORD WriteCompiledKeyboard(PFILE_KEYBOARD fk, KMX_BYTE**data, size_t& dataS return CERR_None; } -KMX_DWORD ReadLine(FILE* fp_in , PKMX_WCHAR wstr, KMX_BOOL PreProcess) +KMX_DWORD ReadLine(KMX_BYTE* infile, int sz, int& offset, PKMX_WCHAR wstr, KMX_BOOL PreProcess) { KMX_DWORD len; PKMX_WCHAR p; @@ -3076,21 +3081,26 @@ KMX_DWORD ReadLine(FILE* fp_in , PKMX_WCHAR wstr, KMX_BOOL PreProcess) KMX_DWORD n; KMX_WCHAR currentQuotes = 0; KMX_WCHAR str[LINESIZE + 3]; - len = (KMX_DWORD)fread( str , 1 ,LINESIZE * 2,fp_in); - if (ferror(fp_in) ) return CERR_CannotReadInfile; - len /= 2; - str[len] = 0; auto cur = ftell(fp_in); - fseek(fp_in, 0, SEEK_END); - auto fsize = ftell(fp_in); - fseek(fp_in, cur, SEEK_SET); - if (cur == fsize) + if(offset >= sz) { + return CERR_EndOfFile; + } - // \r\n is still added here even though Linux doesn`t use \r. - // This is to ensure to still have a working windows-only-version - u16ncat(str, u"\r\n", _countof(str)); // I3481 // Always a "\r\n" to the EOF, avoids funny bugs + len = offset + LINESIZE*2 > sz ? sz-offset : LINESIZE*2; + memcpy(str, infile+offset, len); + offset += len; + len /= 2; + str[len] = 0; - if (len == 0) return CERR_EndOfFile; + if(offset == sz) { + // \r\n is still added here even though Linux doesn`t use \r. + // This is to ensure to still have a working windows-only-version + u16ncat(str, u"\r\n", _countof(str)); // I3481 // Always a "\r\n" to the EOF, avoids funny bugs + } + + if (len == 0) { + return CERR_EndOfFile; + } // neccessary to add this block for using on non-windows platforms (removes all \r for platforms that use \n instead of \r\n) for (p = str, n = 0; n < len; n++, p++) { @@ -3172,9 +3182,13 @@ KMX_DWORD ReadLine(FILE* fp_in , PKMX_WCHAR wstr, KMX_BOOL PreProcess) return (PreProcess ? CERR_None : CERR_LineTooLong); } - if (*p == L'\n') kmcmp::currentLine++; + kmcmp::currentLine++; - fseek(fp_in, -(int)(len * 2 - (int)(p - str) * 2 - 2), SEEK_CUR); + offset -= (int)(len * 2 - (int)(p - str) * 2 - 2); + if(offset >= sz) { + // If we've appended a \n, we can go past EOF + offset = sz; + } p--; while (p >= str && iswspace(*p)) p--; @@ -3427,81 +3441,39 @@ KMX_BOOL kmcmp::IsValidCallStore(PFILE_STORE fs) return i == 1; } -FILE* CreateTempFile() -{ - return tmpfile(); +/////////////////// + +bool hasPreamble(std::u16string result) { + return result.size() > 0 && result[0] == 0xFEFF; } -/////////////////// +bool UTF16TempFromUTF8(KMX_BYTE* infile, int sz, KMX_BYTE** tempfile, int *sz16) { + if(sz == 0) { + return FALSE; + } -FILE* UTF16TempFromUTF8(FILE* fp_in , KMX_BOOL hasPreamble) -{ - FILE *fp_out = CreateTempFile(); - if(fp_out == NULL) // I3228 // I3510 - { - fclose(fp_in); - return NULL; //return INVALID_HANDLE_VALUE; _S2 can I exchange that? + std::u16string result; + + try { + std::wstring_convert, char16_t> converter; + result = converter.from_bytes((char*)infile, (char*)infile+sz-1); + } catch(std::range_error e) { + std::wstring_convert, char16_t> converter; + result = converter.from_bytes((char*)infile, (char*)infile+sz-1); } - PKMX_BYTE buf, p; - PKMX_WCHAR outbuf, poutbuf; - KMX_DWORD len; - KMX_DWORD len2; - KMX_WCHAR prolog = 0xFEFF; - fwrite(&prolog,2, 1, fp_out); - - fseek(fp_in, 0, SEEK_END); - len = (KMX_DWORD)ftell(fp_in); - fseek(fp_in, 0, SEEK_SET); - if (hasPreamble) { - fseek( fp_in,3,SEEK_SET); // Cut off UTF-8 marker - len -= 3; - } - - buf = new KMX_BYTE[len + 1]; // null terminated - outbuf = new KMX_WCHAR[len + 1]; - - len2= (KMX_DWORD)fread(buf,1,len,fp_in); - if (len2) { - buf[len2] = 0; - p = buf; - poutbuf = outbuf; - if (hasPreamble) { - // We have a preamble, so we attempt to read as UTF-8 and allow conversion errors to be filtered. This is not great for a - // compiler but matches existing behaviour -- in future versions we may not do lenient conversion. - ConvertUTF8toUTF16(&p, &buf[len2], (UTF16 **)&poutbuf, (const UTF16 *)&outbuf[len], lenientConversion); - fwrite(outbuf, (KMX_DWORD)(poutbuf - outbuf) * 2 , 1, fp_out); - } - else { - // No preamble, so we attempt to read as strict UTF-8 and fall back to ANSI if that fails - ConversionResult cr = ConvertUTF8toUTF16(&p, &buf[len2], (UTF16 **)&poutbuf, (const UTF16 *)&outbuf[len], strictConversion); - if (cr == sourceIllegal) { - // Not a valid UTF-8 file, so fall back to ANSI - // AddCompileError(CHINT_NonUnicodeFile); - // note, while this message is defined, for now we will not emit it - // because we don't support HINT/INFO messages yet and we don't want - // this to cause a blocking compile at this stage - // do strtowstr only when no invalid characters are found - if( p==0){ - poutbuf = strtowstr((PKMX_STR)buf); - fwrite(poutbuf, (KMX_DWORD)u16len(poutbuf) * 2 , 1, fp_out); - delete[] poutbuf; - } - else - AddCompileError(CERR_InvalidCharacter); - } + if(hasPreamble(result)) { + *sz16 = result.size() * 2 - 1; + *tempfile = new KMX_BYTE[*sz16]; + memcpy(*tempfile, result.c_str() + 2, *sz16); - else { - fwrite(outbuf, (KMX_DWORD)(poutbuf - outbuf) * 2 , 1, fp_out); - } - } } - fclose( fp_in); - delete[] buf; - delete[] outbuf; - fseek( fp_out,2,SEEK_SET); - return fp_out; + *sz16 = result.size() * 2; + *tempfile = new KMX_BYTE[*sz16]; + memcpy(*tempfile, result.c_str(), *sz16); + + return TRUE; } PFILE_STORE FindSystemStore(PFILE_KEYBOARD fk, KMX_DWORD dwSystemID) diff --git a/developer/src/kmcmplib/src/CompilerInterfaces.cpp b/developer/src/kmcmplib/src/CompilerInterfaces.cpp index 71e1e895f2..fd297f4332 100644 --- a/developer/src/kmcmplib/src/CompilerInterfaces.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfaces.cpp @@ -11,14 +11,14 @@ #include "../../../../common/windows/cpp/include/ConvertUTF.h" #include "../../../../common/windows/cpp/include/keymanversion.h" -bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk); +bool CompileKeyboardHandle(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk); #ifdef __EMSCRIPTEN__ /* WASM interface for compiler message callback */ -EM_JS(int, wasm_msgproc, (int line, int msgcode, char* text, char* context), { +EM_JS(int, wasm_msgproc, (int line, int msgcode, const char* text, char* context), { const proc = globalThis[UTF8ToString(context)]; if(!proc || typeof proc != 'function') { console.log(`[${line}: ${msgcode}: ${UTF8ToString(text)}]`); @@ -28,7 +28,21 @@ EM_JS(int, wasm_msgproc, (int line, int msgcode, char* text, char* context), { } }); -int wasm_CompilerMessageProc(int line, uint32_t dwMsgCode, char* szText, void* context) { +EM_JS(bool, wasm_loadfileproc, (const char* filename, const char* baseFilename, void* buffer, int* bufferSize, char* context), { + const proc = globalThis[UTF8ToString(context)]; + if(!proc || typeof proc != 'function') { + return 0; + } else { + return proc(UTF8ToString(filename), UTF8ToString(baseFilename), buffer, bufferSize); + } +}); + +bool wasm_LoadFileProc(const char* filename, const char* baseFilename, void* buffer, int* bufferSize, void* context) { + char* msgProc = static_cast(context); + return wasm_loadfileproc(filename, baseFilename, buffer, bufferSize, msgProc); +} + +int wasm_CompilerMessageProc(int line, uint32_t dwMsgCode, const char* szText, void* context) { char* msgProc = static_cast(context); return wasm_msgproc(line, dwMsgCode, szText, msgProc); } @@ -61,7 +75,7 @@ WASM_COMPILER_RESULT kmcmp_wasm_compile(std::string pszInfile, const KMCMP_COMPI pszInfile.c_str(), options, wasm_CompilerMessageProc, - nullptr, //wasm_LoadFileProc, + wasm_LoadFileProc, intf.messageCallback.c_str(), kr ); @@ -116,8 +130,6 @@ EXTERN bool kmcmp_CompileKeyboard( KMCMP_COMPILER_RESULT& result ) { - FILE* fp_in = NULL; - KMX_CHAR str[260]; FILE_KEYBOARD fk; kmcmp::FSaveDebug = options.saveDebug; // I3681 @@ -126,7 +138,7 @@ EXTERN bool kmcmp_CompileKeyboard( kmcmp::FShouldAddCompilerVersion = options.shouldAddCompilerVersion; kmcmp::CompileTarget = options.target; - if (!messageProc || !pszInfile) { // TODO: add loadFileProc + if (!messageProc || !loadFileProc || !pszInfile) { AddCompileError(CERR_BadCallParams); return FALSE; } @@ -142,43 +154,58 @@ EXTERN bool kmcmp_CompileKeyboard( } msgproc = messageProc; - //TODO: loadfileproc = loadFileProc; + loadfileproc = loadFileProc; msgprocContext = (void*)procContext; kmcmp::currentLine = 0; kmcmp::nErrors = 0; - fp_in = Open_File(pszInfile, "rb"); - - if (fp_in == NULL) { + int sz; + if(!loadFileProc(pszInfile, "", nullptr, &sz, msgprocContext)) { AddCompileError(CERR_InfileNotExist); return FALSE; } - // Transfer the file to a memory stream for processing UTF-8 or ANSI to UTF-16? - // What about really large files? Transfer to a temp file... - if (!fread(str, 1, 3, fp_in)) { - fclose(fp_in); + if(sz < 3) { + // Technically, a 3 byte file can never be a valid .kmn, so we can shortcut + // here and avoid testing outside memory bounds for looking at BOM AddCompileError(CERR_CannotReadInfile); return FALSE; } - fseek(fp_in, 0, SEEK_SET); - if (str[0] == UTF8Sig[0] && str[1] == UTF8Sig[1] && str[2] == UTF8Sig[2]) - fp_in = UTF16TempFromUTF8(fp_in, TRUE); - else if (str[0] == UTF16Sig[0] && str[1] == UTF16Sig[1]) - fseek(fp_in, 2, SEEK_SET); - else - fp_in = UTF16TempFromUTF8(fp_in, FALSE); - if (fp_in == NULL) { - AddCompileError(CERR_CannotCreateTempfile); + KMX_BYTE* infile = new KMX_BYTE[sz]; + if(!infile) { + AddCompileError(CERR_CannotAllocateMemory); return FALSE; } + if(!loadFileProc(pszInfile, "", infile, &sz, msgprocContext)) { + delete[] infile; + AddCompileError(CERR_CannotReadInfile); + return FALSE; + } + + int offset = 0; + if(infile[0] == (KMX_BYTE) UTF16Sig[0] && infile[1] == (KMX_BYTE) UTF16Sig[1]) { + // UTF-16 source file + offset = 2; + } else { + // UTF-8 source file + KMX_BYTE* infile16; + int sz16; + if(!UTF16TempFromUTF8(infile, sz, &infile16, &sz16)) { + delete[] infile; + AddCompileError(CERR_CannotCreateTempfile); + return FALSE; + } + delete[] infile; + infile = infile16; + sz = sz16; + } kmcmp::CodeConstants = new kmcmp::NamedCodeConstants; - bool success = CompileKeyboardHandle(fp_in, &fk); + bool success = CompileKeyboardHandle(infile+offset, sz-offset, &fk); delete kmcmp::CodeConstants; - fclose(fp_in); + delete[] infile; if (kmcmp::nErrors > 0 || !success) { return FALSE; @@ -204,7 +231,7 @@ EXTERN bool kmcmp_CompileKeyboard( return TRUE; } -bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) +bool CompileKeyboardHandle(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk) { PKMX_WCHAR str, p; @@ -263,8 +290,10 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) AddStore(fk, TSS_CUSTOMKEYMANEDITION, u"0"); AddStore(fk, TSS_CUSTOMKEYMANEDITIONNAME, u"Keyman"); + int offset = 0; + // must preprocess for group and store names -> this isn't really necessary, but never mind! - while ((msg = ReadLine(fp_in, str, TRUE)) == CERR_None) + while ((msg = ReadLine(infile, sz, offset, str, TRUE)) == CERR_None) { p = str; switch (LineTokenType(&p)) @@ -301,7 +330,7 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) return FALSE; } - fseek( fp_in,2,SEEK_SET); + offset = 0; kmcmp::currentLine = 0; /* Reindex the list of codeconstants after stores added */ @@ -309,7 +338,7 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) kmcmp::CodeConstants->reindex(); /* ReadLine will automatically skip over $Keyman lines, and parse wrapped lines */ - while ((msg = ReadLine(fp_in, str, FALSE)) == CERR_None) + while ((msg = ReadLine(infile, sz, offset, str, FALSE)) == CERR_None) { msg = ParseLine(fk, str); if (msg != CERR_None) { diff --git a/developer/src/kmcmplib/src/compfile.h b/developer/src/kmcmplib/src/compfile.h index 595d1fecec..7c262be090 100644 --- a/developer/src/kmcmplib/src/compfile.h +++ b/developer/src/kmcmplib/src/compfile.h @@ -197,33 +197,4 @@ struct COMPILEMESSAGES { typedef COMPILEMESSAGES *PCOMPILEMESSAGES; -/* -struct TVersion -{ - //int MinVersion; // 0x0500 usually - //int CompilerVersion[4]; - //int MinCompilerVersion[4]; - int KeyboardVersion; // 0x0500 usually -}; - -extern TVersion FVersionInfo; -*/ - -/* -#define bstrcpy(c,d) (LPBYTE)strcpy((LPSTR)(c),(LPSTR)(d)) -#define bstrlen(c) strlen((LPSTR)(c)) -#define bstrcmp(c,d) strcmp((LPSTR)(c),(LPSTR)(d)) -#define bstrncmp(c,d,n) strncmp((LPSTR)(c),(LPSTR)(d),(n)) -#define bstrnicmp(c,d,n) strnicmp((LPSTR)(c),(LPSTR)(d),(n)) -#define bstricmp(c,d) stricmp((LPSTR)(c),(LPSTR)(d)) -#define bstrchr(c,ch) (LPBYTE)strchr((LPSTR)(c),(char)ch) -#define bstrncpy(c,d,n) (LPBYTE)strncpy((LPSTR)(c),(LPSTR)(d),(n)) -#define bstrtok(c,d) (LPBYTE)strtok((LPSTR)(c),(LPSTR)(d)) -#define bstrcat(c,d) (LPBYTE)strcat((LPSTR)(c),(LPSTR)(d)) -#define bstrncat(c,d,n) (LPBYTE)strncat((LPSTR)(c),(LPSTR)(d),(n)) -#define bstrrev(c) (LPBYTE)strrev((LPSTR)(c)) -#define batoi(c) atoi((LPSTR)(c)) -#define bstrtol(c,d,n) strtol((LPSTR)(c),(LPSTR *)(d),(n)) -*/ - #endif // _COMPFILE_H diff --git a/developer/src/kmcmplib/src/kmcmplib.h b/developer/src/kmcmplib/src/kmcmplib.h index 78e945ee0d..70718f98bc 100644 --- a/developer/src/kmcmplib/src/kmcmplib.h +++ b/developer/src/kmcmplib/src/kmcmplib.h @@ -24,6 +24,7 @@ namespace kmcmp { } extern kmcmp_CompilerMessageProc msgproc; +extern kmcmp_LoadFileProc loadfileproc; extern void* msgprocContext; extern KMX_BOOL AWarnDeprecatedCode_GLOBAL_LIB; @@ -40,10 +41,10 @@ KMX_BOOL AddCompileError(KMX_DWORD msg); PKMX_WCHAR strtowstr(PKMX_STR in); PFILE_STORE FindSystemStore(PFILE_KEYBOARD fk, KMX_DWORD dwSystemID); -FILE* UTF16TempFromUTF8(FILE* fp_in , KMX_BOOL hasPreamble); +bool UTF16TempFromUTF8(KMX_BYTE* infile, int sz, KMX_BYTE** tempfile, int *sz16); KMX_DWORD WriteCompiledKeyboard(PFILE_KEYBOARD fk, KMX_BYTE**data, size_t& dataSize); KMX_DWORD AddStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, const KMX_WCHAR * str, KMX_DWORD *dwStoreID= NULL); -KMX_DWORD ReadLine(FILE* fp_in , PKMX_WCHAR wstr, KMX_BOOL PreProcess); +KMX_DWORD ReadLine(KMX_BYTE* infile, int sz, int& offset, PKMX_WCHAR wstr, KMX_BOOL PreProcess); KMX_DWORD ParseLine(PFILE_KEYBOARD fk, PKMX_WCHAR str); KMX_DWORD ProcessGroupLine(PFILE_KEYBOARD fk, PKMX_WCHAR p); KMX_DWORD ProcessGroupFinish(PFILE_KEYBOARD fk); diff --git a/developer/src/kmcmplib/src/meson.build b/developer/src/kmcmplib/src/meson.build index 8264c3d28e..727d6831e6 100644 --- a/developer/src/kmcmplib/src/meson.build +++ b/developer/src/kmcmplib/src/meson.build @@ -7,6 +7,7 @@ # TODO: is this required? It should be Keyman Core only defns += ['-DKMN_KBP_EXPORTING'] version_res = [] +lib_links = [] if cpp_compiler.get_id() == 'gcc' or cpp_compiler.get_id() == 'clang' warns += [ @@ -24,12 +25,13 @@ endif name_suffix = [] if cpp_compiler.get_id() == 'emscripten' - links += ['-lnodefs.js', '-sMODULARIZE', '-sEXPORT_ES6', '--whole-archive', '--bind', '-sEXPORTED_RUNTIME_METHODS=[\'UTF8ToString\']'] + lib_links = ['--whole-archive', '--bind', '-sMODULARIZE', '-sEXPORT_ES6'] + links += ['-lnodefs.js', '--bind', '-sEXPORTED_RUNTIME_METHODS=[\'UTF8ToString\']'] # tests are building as ES6 so we need to declare the file extension # note that meson currently struggles with the sanitycheckc_cross.exe # program, because it has a hard coded extension (.exe) which is not # valid for node programs in module mode. - name_suffix = '.mjs' + # name_suffix = '.mjs' endif icu = subproject('icu-for-uset', default_options: [ 'default_library=static', 'cpp_std=c++17', 'warning_level=0', 'werror=false']) @@ -63,7 +65,7 @@ lib = library('kmcmplib', version_res, cpp_args: defns + warns + flags, - link_args: links, + link_args: links + lib_links, version: meson.project_version(), include_directories: inc, install: true, diff --git a/developer/src/kmcmplib/tests/api-test.cpp b/developer/src/kmcmplib/tests/api-test.cpp index 4bb0276a79..b347773220 100644 --- a/developer/src/kmcmplib/tests/api-test.cpp +++ b/developer/src/kmcmplib/tests/api-test.cpp @@ -18,13 +18,14 @@ #include #include "../src/compfile.h" #include +#include "../src/filesystem.h" void setup(); -void test_kmcmp_CompileKeyboard(); +void test_kmcmp_CompileKeyboard(char *kmn_file); std::vector error_vec; -int msgproc(int line, uint32_t dwMsgCode, char* szText, void* context) { +int msgproc(int line, uint32_t dwMsgCode, const char* szText, void* context) { error_vec.push_back(dwMsgCode); const char*t = "unknown"; switch(dwMsgCode & 0xF000) { @@ -37,9 +38,42 @@ int msgproc(int line, uint32_t dwMsgCode, char* szText, void* context) { return 1; } +bool loadfileProc(const char* filename, const char* baseFilename, void* data, int* size, void* context) { + FILE* fp = Open_File(filename, "rb"); + if(!fp) { + return false; + } + + if(!data) { + // return size + if(fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + return false; + } + *size = ftell(fp); + if(*size == -1L) { + fclose(fp); + return false; + } + } else { + // return data + if(fread(data, 1, *size, fp) != *size) { + fclose(fp); + return false; + } + } + fclose(fp); + return true; +} + int main(int argc, char *argv[]) { + if(argc < 1) { + puts("Usage: api-test "); + puts("Warning: blank_keyboard will be overwritten"); + return 1; + } setup(); - test_kmcmp_CompileKeyboard(); + test_kmcmp_CompileKeyboard(argv[1]); return 0; } @@ -48,13 +82,9 @@ void setup() { error_vec.clear(); } -void test_kmcmp_CompileKeyboard() { - char kmn_file[L_tmpnam], kmx_file[L_tmpnam]; - tmpnam(kmn_file); - tmpnam(kmx_file); - +void test_kmcmp_CompileKeyboard(char *kmn_file) { // Create an empty file - FILE *fp = fopen(kmn_file, "w"); + FILE *fp = Open_File(kmn_file, "wb"); fclose(fp); // It should fail when a zero-byte file is passed in @@ -65,7 +95,7 @@ void test_kmcmp_CompileKeyboard() { options.warnDeprecatedCode = true; options.shouldAddCompilerVersion = false; options.target = CKF_KEYMAN; - assert(!kmcmp_CompileKeyboard(kmn_file, options, msgproc, nullptr, nullptr, result)); + assert(!kmcmp_CompileKeyboard(kmn_file, options, msgproc, loadfileProc, nullptr, result)); assert(error_vec.size() == 1); assert(error_vec[0] == CERR_CannotReadInfile); diff --git a/developer/src/kmcmplib/tests/kmcompxtest.cpp b/developer/src/kmcmplib/tests/kmcompxtest.cpp index 87d9e53cf7..c5d189798b 100644 --- a/developer/src/kmcmplib/tests/kmcompxtest.cpp +++ b/developer/src/kmcmplib/tests/kmcompxtest.cpp @@ -13,6 +13,7 @@ #include #include #include +#include "../src/filesystem.h" #ifdef _MSC_VER #else @@ -28,7 +29,7 @@ vector < int > error_vec; #define CERR_WARNING 0x00002000 #define CERR_HINT 0x00001000 -int msgproc(int line, uint32_t dwMsgCode, char* szText, void* context) +int msgproc(int line, uint32_t dwMsgCode, const char* szText, void* context) { error_vec.push_back(dwMsgCode); const char*t = "unknown"; @@ -42,6 +43,34 @@ int msgproc(int line, uint32_t dwMsgCode, char* szText, void* context) return 1; } +bool loadfileProc(const char* filename, const char* baseFilename, void* data, int* size, void* context) { + FILE* fp = Open_File(filename, "rb"); + if(!fp) { + return false; + } + + if(!data) { + // return size + if(fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + return false; + } + *size = ftell(fp); + if(*size == -1L) { + fclose(fp); + return false; + } + } else { + // return data + if(fread(data, 1, *size, fp) != *size) { + fclose(fp); + return false; + } + } + fclose(fp); + return true; +} + #include "../src/filesystem.h" int main(int argc, char *argv[]) @@ -79,7 +108,7 @@ int main(int argc, char *argv[]) options.shouldAddCompilerVersion = false; options.target = CKF_KEYMAN; - if(kmcmp_CompileKeyboard(kmn_file, options, msgproc, nullptr, nullptr, result)) { + if(kmcmp_CompileKeyboard(kmn_file, options, msgproc, loadfileProc, nullptr, result)) { char* testname = strrchr( (char*) kmn_file, '/') + 1; if(strncmp(testname, pfirst5, 5) == 0){ return __LINE__; // exit code: CERR_ in Name + no Error found diff --git a/developer/src/kmcmplib/tests/meson.build b/developer/src/kmcmplib/tests/meson.build index 49924f2d78..2468ac53b1 100644 --- a/developer/src/kmcmplib/tests/meson.build +++ b/developer/src/kmcmplib/tests/meson.build @@ -113,10 +113,10 @@ apitest = executable('api-test', 'api-test.cpp', name_suffix: name_suffix, link_args: links + tests_flags, objects: lib.extract_all_objects(), - dependencies: icuuc_dep, + dependencies: icuuc_dep ) -test('api-test', apitest) +test('api-test', apitest, args: [output_path / 'blank_keyboard.kmx']) usetapitest = executable('uset-api-test', 'uset-api-test.cpp', cpp_args: defns, -- GitLab From 47c8a95fb0743d471eee87b90ee2353469e99ad2 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 31 May 2023 07:44:35 +0700 Subject: [PATCH 171/214] refactor(developer): complete fs move out of kmcmplib * Moves filesystem access out of kmcmplib into kmc-kmn * Adds filesystem access callback to kmcmplib unit tests * Cleans up callback interface through wasm * Adds unit tests for various file load scenarios * Removes nodefs dependency from kmcmplib wasm build, and removes corresponding path mappings which were previously required for wasm builds; note that these are still present for the unit tests for kmcmplib. --- .../src/kmc-kmn/src/compiler/compiler.ts | 55 ++++++++-- .../kmcmplib/src/CheckFilenameConsistency.cpp | 47 ++------ .../kmcmplib/src/CheckFilenameConsistency.h | 2 - developer/src/kmcmplib/src/Compiler.cpp | 102 ++++++++---------- .../src/kmcmplib/src/CompilerInterfaces.cpp | 44 ++++---- .../src/kmcmplib/src/NamedCodeConstants.cpp | 97 ++++++----------- .../src/kmcmplib/src/NamedCodeConstants.h | 5 +- developer/src/kmcmplib/src/compfile.h | 3 +- developer/src/kmcmplib/src/kmcmplib.h | 1 - developer/src/kmcmplib/src/meson.build | 9 +- developer/src/kmcmplib/src/pch.h | 2 - developer/src/kmcmplib/tests/api-test.cpp | 53 ++------- .../valid-keyboards/compile_legacy.bat | 4 + .../fixtures/valid-keyboards/k001_utf16.kmn | Bin 0 -> 452 bytes .../fixtures/valid-keyboards/k001_utf16.kmx | Bin 0 -> 356 bytes .../valid-keyboards/k002_utf8_without_bom.kmn | 11 ++ .../valid-keyboards/k002_utf8_without_bom.kmx | Bin 0 -> 378 bytes .../valid-keyboards/k003_utf8_with_bom.kmn | 11 ++ .../valid-keyboards/k003_utf8_with_bom.kmx | Bin 0 -> 372 bytes .../fixtures/valid-keyboards/k004_ansi.kmn | 13 +++ .../fixtures/valid-keyboards/k004_ansi.kmx | Bin 0 -> 350 bytes .../fixtures/valid-keyboards/k005_bitmap.bmp | Bin 0 -> 246 bytes .../fixtures/valid-keyboards/k005_bitmap.kmn | 12 +++ .../fixtures/valid-keyboards/k005_bitmap.kmx | Bin 0 -> 656 bytes .../fixtures/valid-keyboards/k006_icon.ico | Bin 0 -> 318 bytes .../fixtures/valid-keyboards/k006_icon.kmn | 12 +++ .../fixtures/valid-keyboards/k006_icon.kmx | Bin 0 -> 728 bytes .../valid-keyboards/k007_includecodes_r_n.kmn | 12 +++ .../valid-keyboards/k007_includecodes_r_n.kmx | Bin 0 -> 462 bytes .../valid-keyboards/k007_includecodes_r_n.txt | 2 + .../valid-keyboards/k008_includecodes_n.kmn | 12 +++ .../valid-keyboards/k008_includecodes_n.kmx | Bin 0 -> 454 bytes .../valid-keyboards/k008_includecodes_n.txt | 2 + developer/src/kmcmplib/tests/kmcompxtest.cpp | 49 +-------- developer/src/kmcmplib/tests/meson.build | 41 +++++-- .../src/kmcmplib/tests/util_callbacks.cpp | 59 ++++++++++ developer/src/kmcmplib/tests/util_callbacks.h | 8 ++ .../util_filesystem.cpp} | 41 ++++++- .../filesystem.h => tests/util_filesystem.h} | 5 +- 39 files changed, 406 insertions(+), 308 deletions(-) create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/compile_legacy.bat create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k001_utf16.kmn create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k001_utf16.kmx create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k002_utf8_without_bom.kmn create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k002_utf8_without_bom.kmx create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k003_utf8_with_bom.kmn create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k003_utf8_with_bom.kmx create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k004_ansi.kmn create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k004_ansi.kmx create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k005_bitmap.bmp create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k005_bitmap.kmn create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k005_bitmap.kmx create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k006_icon.ico create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k006_icon.kmn create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k006_icon.kmx create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k007_includecodes_r_n.kmn create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k007_includecodes_r_n.kmx create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k007_includecodes_r_n.txt create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k008_includecodes_n.kmn create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k008_includecodes_n.kmx create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k008_includecodes_n.txt create mode 100644 developer/src/kmcmplib/tests/util_callbacks.cpp create mode 100644 developer/src/kmcmplib/tests/util_callbacks.h rename developer/src/kmcmplib/{src/filesystem.cpp => tests/util_filesystem.cpp} (84%) rename developer/src/kmcmplib/{src/filesystem.h => tests/util_filesystem.h} (82%) diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index 606bec638c..b27440fd06 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -42,13 +42,16 @@ const baseOptions: CompilerOptions = { */ let callbackProcIdentifier = 0; +const + callbackPrefix = 'kmnCompilerCallbacks_'; + export class KmnCompiler { private Module: any; - callbackName: string; + callbackID: string; // a unique numeric id added to globals with prefixed names callbacks: CompilerCallbacks; constructor() { - this.callbackName = 'kmnCompilerCallback' + callbackProcIdentifier; + this.callbackID = callbackPrefix + callbackProcIdentifier.toString(); callbackProcIdentifier++; } @@ -58,6 +61,7 @@ export class KmnCompiler { try { this.Module = await loadWasmHost(); } catch(e: any) { + /* c8 ignore next 3 */ this.callbacks.reportMessage(CompilerMessages.Fatal_MissingWasmModule({e})); return false; } @@ -74,7 +78,9 @@ export class KmnCompiler { // Can't report a message here. throw Error('Must call Compiler.init(callbacks) before proceeding'); } - if(!this.Module) { // fail if wasm not loaded or function not found + if(!this.Module) { + /* c8 ignore next 4 */ + // fail if wasm not loaded or function not found this.callbacks.reportMessage(CompilerMessages.Fatal_MissingWasmModule({})); return false; } @@ -83,15 +89,17 @@ export class KmnCompiler { public run(infile: string, outfile: string, options?: CompilerOptions): boolean { if(!this.verifyInitialized()) { + /* c8 ignore next 2 */ return false; } options = {...baseOptions, ...options}; - (globalThis as any)[this.callbackName] = this.compilerMessageCallback; - // TODO: use callbacks for file access -- so kmc-kmn is entirely fs agnostic + (globalThis as any)[this.callbackID] = { + message: this.compilerMessageCallback, + loadFile: this.loadFileCallback + }; let result = this.runCompiler(infile, outfile, options); - delete (globalThis as any)[this.callbackName]; - //TODO: write the file out! + delete (globalThis as any)[this.callbackID]; if(result) { if(result.kmx) { this.callbacks.fs.writeFileSync(result.kmx.filename, result.kmx.data); @@ -111,6 +119,30 @@ export class KmnCompiler { return 1; } + private loadFileCallback = (filename: string, baseFilename: string, buffer: number, bufferSize: number): number => { + // TODO: we can optimize this in future by avoiding loading the file twice + let resolvedFilename = this.callbacks.resolveFilename(baseFilename, filename); + let data = this.callbacks.loadFile(resolvedFilename); + if(!data) { + return 0; + } + + if(buffer == 0) { + /* We need to return buffer size required */ + return data.byteLength; + } + + if(bufferSize != data.byteLength) { + // TODO: consider chucking a wobbly because this is a bug + /* c8 ignore next 2 */ + return 0; + } + + this.Module.HEAP8.set(data, buffer); + + return 1; + } + private runCompiler(infile: string, outfile: string, options: CompilerOptions): CompilerResult { let result: CompilerResult = {}; let wasm_interface = new this.Module.CompilerInterface(); @@ -122,8 +154,7 @@ export class KmnCompiler { wasm_options.warnDeprecatedCode = options.warnDeprecatedCode; wasm_options.shouldAddCompilerVersion = options.shouldAddCompilerVersion; wasm_options.target = 0; //CKF_KEYMAN; TODO, support KMW - wasm_interface.messageCallback = this.callbackName; - wasm_interface.loadFileCallback = this.callbackName; // TODO: this is wrong, needs to be a new callback; not yet used though + wasm_interface.callbacksKey = this.callbackID; // key of object on globalThis wasm_result = this.Module.kmcmp_compile(infile, wasm_options, wasm_interface); if(!wasm_result.result) { return null; @@ -143,6 +174,7 @@ export class KmnCompiler { return result; } catch(e) { + /* c8 ignore next 3 */ this.callbacks.reportMessage(CompilerMessages.Fatal_UnexpectedException({e:e})); return null; } finally { @@ -163,6 +195,7 @@ export class KmnCompiler { reader.validate(kvks, this.callbacks.loadSchema('kvks')); } catch(e) { console.log(e); + // TODO: also unit test // TODO: this.callbacks.reportMessage(CompilerMessages.Error_InvalidKvksFile({e})); return null; } @@ -170,6 +203,7 @@ export class KmnCompiler { let vk = reader.transform(kvks, errors); if(!vk || errors.length) { console.dir(errors); + // TODO: also unit test // TODO: this.callbacks.reportMessage(CompilerMessages.Error_InvalidKvksFile({e})); return null; } @@ -188,10 +222,12 @@ export class KmnCompiler { */ public parseUnicodeSet(pattern: string, bufferSize: number) : UnicodeSet | null { if(!this.verifyInitialized()) { + /* c8 ignore next 2 */ return null; } if (!bufferSize) { + /* c8 ignore next 2 */ bufferSize = 100; // TODO-LDML: Preflight mode? Reuse buffer? } const buf = this.Module.asm.malloc(bufferSize * 2 * this.Module.HEAPU32.BYTES_PER_ELEMENT); @@ -239,6 +275,7 @@ function getUnicodeSetError(rc: number) : CompilerEvent { case KMCMP_FATAL_OUT_OF_RANGE: return CompilerMessages.Fatal_UnicodeSetOutOfRange(); default: + /* c8 ignore next */ return CompilerMessages.Fatal_UnexpectedException({e: `Unexpected UnicodeSet error code ${rc}`}); } } diff --git a/developer/src/kmcmplib/src/CheckFilenameConsistency.cpp b/developer/src/kmcmplib/src/CheckFilenameConsistency.cpp index 627298bf37..3a185bc403 100644 --- a/developer/src/kmcmplib/src/CheckFilenameConsistency.cpp +++ b/developer/src/kmcmplib/src/CheckFilenameConsistency.cpp @@ -7,52 +7,12 @@ #include #include "CheckFilenameConsistency.h" #include "kmx_u16.h" -#include "filesystem.h" #ifdef _MSC_VER #include #endif -namespace kmcmp { - extern KMX_CHAR CompileDir[260]; // TODO: this should not be a fixed buffer -} -bool IsRelativePath(KMX_CHAR const * p) { - // Relative path (returns TRUE): - // ..\...\BITMAP.BMP - // PATH\BITMAP.BMP - // BITMAP.BMP - - // Semi-absolute path (returns FALSE): - // \...\BITMAP.BMP - - // Absolute path (returns FALSE): - // C:\...\BITMAP.BMP - // \\SERVER\SHARE\...\BITMAP.BMP - - if ((*p == '\\') || (*p == '/')) return FALSE; - if (*p && *(p + 1) == ':') return FALSE; - - return TRUE; -} - -bool IsRelativePath(KMX_WCHAR const * p) { - // Relative path (returns TRUE): - // ..\...\BITMAP.BMP - // PATH\BITMAP.BMP - // BITMAP.BMP - // Semi-absolute path (returns FALSE): - // \...\BITMAP.BMP - - // Absolute path (returns FALSE): - // C:\...\BITMAP.BMP - // \\SERVER\SHARE\...\BITMAP.BMP - - if ((*p == u'\\') || (*p == u'/'))return FALSE; - if (*p && *(p + 1) == u':') return FALSE; - - return TRUE; -} KMX_DWORD CheckFilenameConsistency( KMX_CHAR const * Filename, bool ReportMissingFile) { PKMX_WCHAR WFilename = strtowstr(( KMX_CHAR *)Filename); @@ -62,6 +22,12 @@ KMX_DWORD CheckFilenameConsistency( KMX_CHAR const * Filename, bool ReportMissin } KMX_DWORD CheckFilenameConsistency(KMX_WCHAR const * Filename, bool ReportMissingFile) { + // TODO: we no longer have filesystem access here. We could move this check to + // kmc itself, and make it consistent across all compilers that use the same + // loader callback + return CERR_None; + +#if 0 // not ready yet: needs more attention-> common includes for non-Windows platforms KMX_WCHAR Name[260]; // TODO: fixed buffer sizes bad @@ -115,6 +81,7 @@ KMX_DWORD CheckFilenameConsistency(KMX_WCHAR const * Filename, bool ReportMissin #endif return CERR_None; +#endif } KMX_DWORD CheckFilenameConsistencyForCalls(PFILE_KEYBOARD fk) { diff --git a/developer/src/kmcmplib/src/CheckFilenameConsistency.h b/developer/src/kmcmplib/src/CheckFilenameConsistency.h index 39f86db391..eba8f2d8bf 100644 --- a/developer/src/kmcmplib/src/CheckFilenameConsistency.h +++ b/developer/src/kmcmplib/src/CheckFilenameConsistency.h @@ -7,5 +7,3 @@ KMX_DWORD CheckFilenameConsistencyForCalls(PFILE_KEYBOARD fk); KMX_DWORD CheckFilenameConsistency(KMX_CHAR const * Filename, bool ReportMissingFile); KMX_DWORD CheckFilenameConsistency(KMX_WCHAR const * Filename, bool ReportMissingFile); -bool IsRelativePath(KMX_CHAR const * p); -bool IsRelativePath(KMX_WCHAR const * p); diff --git a/developer/src/kmcmplib/src/Compiler.cpp b/developer/src/kmcmplib/src/Compiler.cpp index 8e0f94cb29..91e02e14e7 100644 --- a/developer/src/kmcmplib/src/Compiler.cpp +++ b/developer/src/kmcmplib/src/Compiler.cpp @@ -101,7 +101,6 @@ #include "UnreachableRules.h" #include "CheckForDuplicates.h" #include "kmx_u16.h" -#include "filesystem.h" #include /* These macros are adapted from winnt.h and legacy use only */ @@ -125,7 +124,6 @@ namespace kmcmp{ KMX_BOOL FMnemonicLayout = FALSE; KMX_BOOL FOldCharPosMatching = FALSE; int CompileTarget; - KMX_CHAR CompileDir[260]; // TODO: this should not be a fixed buffer int BeginLine[4]; KMX_BOOL IsValidCallStore(PFILE_STORE fs); @@ -867,7 +865,6 @@ KMX_DWORD ProcessSystemStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, PFILE_STORE int i, j; KMX_DWORD msg; PKMX_WCHAR p, q; - KMX_CHAR *pp; if (!pssBuf) pssBuf = new KMX_WCHAR[GLOBAL_BUFSIZE]; PKMX_WCHAR buf = pssBuf; @@ -917,13 +914,9 @@ KMX_DWORD ProcessSystemStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, PFILE_STORE case TSS_INCLUDECODES: VERIFY_KEYBOARD_VERSION(fk, VERSION_60, CERR_60FeatureOnly_NamedCodes); - pp = wstrtostr(sp->dpString); - if (!kmcmp::CodeConstants->LoadFile(pp)) - { - delete[] pp; + if (!kmcmp::CodeConstants->LoadFile(fk, sp->dpString)) { return CERR_CannotLoadIncludeFile; } - delete[] pp; kmcmp::CodeConstants->reindex(); // I4982 break; @@ -3234,58 +3227,32 @@ KMX_BOOL IsSameToken(PKMX_WCHAR *p, KMX_WCHAR const * token) return FALSE; } -KMX_DWORD ImportBitmapFile(PFILE_KEYBOARD fk, PKMX_WCHAR szName, PKMX_DWORD FileSize, PKMX_BYTE *Buf) +static bool endsWith(const std::string& str, const std::string& suffix) { - FILE *fp; - KMX_WCHAR szNewName[260]; - - if (IsRelativePath(szName)) - { - PKMX_WCHAR WCompileDir = strtowstr(kmcmp::CompileDir); - u16ncpy(szNewName, WCompileDir, _countof(szNewName)); // I3481 - u16ncat(szNewName,szName, _countof(szNewName )); // I3481 - } - else - u16ncpy(szNewName, szName, _countof(szNewName)); // I3481 - - fp=Open_File(szNewName, u"rb"); - - if ( fp == NULL) - { - // else if filename.bmp is not in the folder -> attempt to open filename.bmp.bmp ! - if ( u16cmp(szNewName+u16len(szNewName)-4, u".bmp") ) - u16ncat(szNewName, u".bmp", _countof(szNewName)); // I3481 + return str.size() >= suffix.size() && 0 == str.compare(str.size()-suffix.size(), suffix.size(), suffix); +} - fp= Open_File(szNewName, u"rb"); +KMX_DWORD ImportBitmapFile(PFILE_KEYBOARD fk, PKMX_WCHAR szName, PKMX_DWORD FileSize, PKMX_BYTE *Buf) +{ + auto szNameUtf8 = string_from_u16string(szName); - if ( fp == NULL) + if(!loadfileproc(szNameUtf8.c_str(), fk->extra->kmnFilename.c_str(), nullptr, (int*) FileSize, msgprocContext)) { + // Append .bmp and try again + if(endsWith(szNameUtf8, ".bmp")) { return CERR_CannotReadBitmapFile; + } + szNameUtf8.append(".bmp"); + if(!loadfileproc(szNameUtf8.c_str(), fk->extra->kmnFilename.c_str(), nullptr, (int*) FileSize, msgprocContext)) { + return CERR_CannotReadBitmapFile; + } } - KMX_DWORD msg; - if ((msg = CheckFilenameConsistency(szNewName, FALSE)) != CERR_None) { - return msg; - } - - fseek(fp, 0, SEEK_END); - *FileSize = (KMX_DWORD)ftell(fp); - fseek(fp ,0,SEEK_SET); - if (*FileSize < 0) { - fclose(fp); - return CERR_CannotReadBitmapFile; - } - - if (*FileSize < 2) return CERR_CannotReadBitmapFile; *Buf = new KMX_BYTE[*FileSize]; - - if (fread(*Buf, 1, *FileSize, fp) < (size_t) *FileSize) { - delete[] * Buf; - *Buf = NULL; + if(!loadfileproc(szNameUtf8.c_str(), fk->extra->kmnFilename.c_str(), *Buf, (int*) FileSize, msgprocContext)) { + delete[] *Buf; return CERR_CannotReadBitmapFile; } - fclose(fp); - /* Test for version 7.0 icon support */ if (*((PKMX_CHAR)*Buf) != 'B' && *(((PKMX_CHAR)*Buf) + 1) != 'M') { VERIFY_KEYBOARD_VERSION(fk, VERSION_70, CERR_70FeatureOnly); @@ -3447,6 +3414,8 @@ bool hasPreamble(std::u16string result) { return result.size() > 0 && result[0] == 0xFEFF; } +#include "unicode/ucnv.h" + bool UTF16TempFromUTF8(KMX_BYTE* infile, int sz, KMX_BYTE** tempfile, int *sz16) { if(sz == 0) { return FALSE; @@ -3456,23 +3425,36 @@ bool UTF16TempFromUTF8(KMX_BYTE* infile, int sz, KMX_BYTE** tempfile, int *sz16) try { std::wstring_convert, char16_t> converter; - result = converter.from_bytes((char*)infile, (char*)infile+sz-1); + result = converter.from_bytes((char*)infile, (char*)infile+sz); } catch(std::range_error e) { - std::wstring_convert, char16_t> converter; - result = converter.from_bytes((char*)infile, (char*)infile+sz-1); + UErrorCode status = U_ZERO_ERROR; + // TODO: we need ICU data files here @srl295 plz help! + UConverter* conv = ucnv_open("windows-1252", &status); + if(U_FAILURE(status)) { + return FALSE; + } + + char16_t* dest = new char16_t[sz*2]; + ucnv_toUChars(conv, dest, sz*2, (char*)infile, sz, &status); + if(U_FAILURE(status)) { + delete[] dest; + return FALSE; + } + + result = dest; + delete[] dest; } if(hasPreamble(result)) { - *sz16 = result.size() * 2 - 1; + *sz16 = result.size() * 2 - 2; *tempfile = new KMX_BYTE[*sz16]; - memcpy(*tempfile, result.c_str() + 2, *sz16); - + memcpy(*tempfile, result.c_str() + 1, *sz16); + } else { + *sz16 = result.size() * 2; + *tempfile = new KMX_BYTE[*sz16]; + memcpy(*tempfile, result.c_str(), *sz16); } - *sz16 = result.size() * 2; - *tempfile = new KMX_BYTE[*sz16]; - memcpy(*tempfile, result.c_str(), *sz16); - return TRUE; } diff --git a/developer/src/kmcmplib/src/CompilerInterfaces.cpp b/developer/src/kmcmplib/src/CompilerInterfaces.cpp index fd297f4332..1a4e77f8e8 100644 --- a/developer/src/kmcmplib/src/CompilerInterfaces.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfaces.cpp @@ -3,7 +3,6 @@ #include #include #include "kmcmplib.h" -#include "filesystem.h" #include "CheckFilenameConsistency.h" #include "CheckNCapsConsistency.h" #include "DeprecationChecks.h" @@ -19,7 +18,7 @@ bool CompileKeyboardHandle(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk); WASM interface for compiler message callback */ EM_JS(int, wasm_msgproc, (int line, int msgcode, const char* text, char* context), { - const proc = globalThis[UTF8ToString(context)]; + const proc = globalThis[UTF8ToString(context)].message; if(!proc || typeof proc != 'function') { console.log(`[${line}: ${msgcode}: ${UTF8ToString(text)}]`); return 0; @@ -28,18 +27,27 @@ EM_JS(int, wasm_msgproc, (int line, int msgcode, const char* text, char* context } }); -EM_JS(bool, wasm_loadfileproc, (const char* filename, const char* baseFilename, void* buffer, int* bufferSize, char* context), { - const proc = globalThis[UTF8ToString(context)]; +EM_JS(int, wasm_loadfileproc, (const char* filename, const char* baseFilename, void* buffer, int bufferSize, char* context), { + const proc = globalThis[UTF8ToString(context)].loadFile; if(!proc || typeof proc != 'function') { return 0; } else { - return proc(UTF8ToString(filename), UTF8ToString(baseFilename), buffer, bufferSize); + if(buffer == 0) { + return proc(UTF8ToString(filename), UTF8ToString(baseFilename), 0, 0); + } else { + return proc(UTF8ToString(filename), UTF8ToString(baseFilename), buffer, bufferSize); + } } }); bool wasm_LoadFileProc(const char* filename, const char* baseFilename, void* buffer, int* bufferSize, void* context) { char* msgProc = static_cast(context); - return wasm_loadfileproc(filename, baseFilename, buffer, bufferSize, msgProc); + if(buffer == nullptr) { + *bufferSize = wasm_loadfileproc(filename, baseFilename, 0, 0, msgProc); + return *bufferSize != 0; + } else { + return wasm_loadfileproc(filename, baseFilename, buffer, *bufferSize, msgProc) == 1; + } } int wasm_CompilerMessageProc(int line, uint32_t dwMsgCode, const char* szText, void* context) { @@ -48,8 +56,7 @@ int wasm_CompilerMessageProc(int line, uint32_t dwMsgCode, const char* szText, v } struct WASM_COMPILER_INTERFACE { - std::string messageCallback; // int line, uint32_t dwMsgCode, char* szText - std::string loadFileCallback; // TODO: char* filename, char* baseFilename --> buffer + std::string callbacksKey; // key of callbacks object on globalThis }; struct WASM_COMPILER_RESULT { @@ -76,7 +83,7 @@ WASM_COMPILER_RESULT kmcmp_wasm_compile(std::string pszInfile, const KMCMP_COMPI options, wasm_CompilerMessageProc, wasm_LoadFileProc, - intf.messageCallback.c_str(), + intf.callbacksKey.c_str(), kr ); @@ -103,8 +110,7 @@ EMSCRIPTEN_BINDINGS(compiler_interface) { emscripten::class_("CompilerInterface") .constructor<>() - .property("messageCallback", &WASM_COMPILER_INTERFACE::messageCallback) - .property("loadFileCallback", &WASM_COMPILER_INTERFACE::loadFileCallback) + .property("callbacksKey", &WASM_COMPILER_INTERFACE::callbacksKey) ; emscripten::class_("CompilerResult") @@ -131,6 +137,8 @@ EXTERN bool kmcmp_CompileKeyboard( ) { FILE_KEYBOARD fk; + fk.extra = new FILE_KEYBOARD_EXTRA; + fk.extra->kmnFilename = pszInfile; kmcmp::FSaveDebug = options.saveDebug; // I3681 kmcmp::FCompilerWarningsAsErrors = options.compilerWarningsAsErrors; // I4865 @@ -143,16 +151,6 @@ EXTERN bool kmcmp_CompileKeyboard( return FALSE; } - PKMX_STR p; - - if ((p = strrchr_slash((char*)pszInfile)) != nullptr) { - strncpy(kmcmp::CompileDir, pszInfile, (int)(p - pszInfile + 1)); // I3481 - kmcmp::CompileDir[(int)(p - pszInfile + 1)] = 0; - } - else { - kmcmp::CompileDir[0] = 0; - } - msgproc = messageProc; loadfileproc = loadFileProc; msgprocContext = (void*)procContext; @@ -172,7 +170,7 @@ EXTERN bool kmcmp_CompileKeyboard( return FALSE; } - KMX_BYTE* infile = new KMX_BYTE[sz]; + KMX_BYTE* infile = new KMX_BYTE[sz+1]; if(!infile) { AddCompileError(CERR_CannotAllocateMemory); return FALSE; @@ -182,6 +180,7 @@ EXTERN bool kmcmp_CompileKeyboard( AddCompileError(CERR_CannotReadInfile); return FALSE; } + infile[sz] = 0; // zero-terminate for safety, not technically needed but helps avoid memory bugs int offset = 0; if(infile[0] == (KMX_BYTE) UTF16Sig[0] && infile[1] == (KMX_BYTE) UTF16Sig[1]) { @@ -266,7 +265,6 @@ bool CompileKeyboardHandle(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk) fk->dpDeadKeyArray = NULL; fk->cxVKDictionary = 0; // I3438 fk->dpVKDictionary = NULL; // I3438 - fk->extra = new FILE_KEYBOARD_EXTRA; fk->extra->kvksFilename = u""; /* fk->szMessage[0] = 0; fk->szLanguageName[0] = 0;*/ diff --git a/developer/src/kmcmplib/src/NamedCodeConstants.cpp b/developer/src/kmcmplib/src/NamedCodeConstants.cpp index e6b1ae6d70..30091b7cb8 100644 --- a/developer/src/kmcmplib/src/NamedCodeConstants.cpp +++ b/developer/src/kmcmplib/src/NamedCodeConstants.cpp @@ -27,15 +27,12 @@ #include "CheckFilenameConsistency.h" #include #include "kmcompx.h" -#include "filesystem.h" using namespace kmcmp; int IsHangulSyllable(const KMX_WCHAR *codename, int *code); namespace kmcmp { - extern KMX_CHAR CompileDir[]; - int __cdecl sort_entries(const void *elem1, const void *elem2) { return u16icmp( @@ -117,85 +114,61 @@ char *kmc_strupr(char *s) { return s; } -KMX_BOOL NamedCodeConstants::IntLoadFile(const KMX_CHAR *filename) -{ +KMX_BOOL NamedCodeConstants::LoadFile(PFILE_KEYBOARD fk, const KMX_WCHAR *filename) { const int str_size = 256; - FILE *fp = NULL; if (CheckFilenameConsistency(filename, FALSE) != 0) { return FALSE; } - fp = Open_File(filename, "rt"); - if(fp == NULL) { - return FALSE; // I3481 + auto szNameUtf8 = string_from_u16string(filename); + + int FileSize; + KMX_BYTE* Buf; + if(!loadfileproc(szNameUtf8.c_str(), fk->extra->kmnFilename.c_str(), nullptr, &FileSize, msgprocContext)) { + return FALSE; } - KMX_CHAR str[str_size], *p, *q, *context = NULL; - KMX_BOOL isEol , first = TRUE; + Buf = new KMX_BYTE[FileSize+1]; + if(!loadfileproc(szNameUtf8.c_str(), fk->extra->kmnFilename.c_str(), Buf, &FileSize, msgprocContext)) { + delete[] Buf; + return FALSE; + } + Buf[FileSize] = 0; // zero-terminate for strtok - while(fgets(str, str_size, fp)) - { - isEol = *(strchr(str, 0) - 1) == '\n'; - p = strtok_r(str, ";", &context); // I3481 - q = strtok_r(NULL, ";\n", &context); - if(p && q) - { - if(first && *p == (KMX_CHAR)0xEF && *(p+1) == (KMX_CHAR)0xBB && *(p+2) == (KMX_CHAR)0xBF) p += 3; // I3056 UTF-8 // I3512 - first = FALSE; + char* filetok; + char* filecontext; + filetok = strtok_r((char*)Buf, "\n", &filecontext); + + if(*filetok == (KMX_CHAR)0xEF && *(filetok+1) == (KMX_CHAR)0xBB && *(filetok+2) == (KMX_CHAR)0xBF) filetok += 3; // I3056 UTF-8 // I3512 + + while(filetok) { + KMX_CHAR str[str_size], *p, *q, *context = NULL; + + if(strlen(filetok) >= str_size) { + delete[] Buf; + // TODO chuck a wobbly + return FALSE; + } + strcpy(str, filetok); + p = strtok_r(str, ";\r", &context); // I3481 + q = strtok_r(nullptr, ";\r", &context); + if(p && q) { kmc_strupr(q); // I3481 // I3641 - long n = strtol(p, NULL, 16); + long n = strtol(p, nullptr, 16); if (*q != '<') { PKMX_WCHAR q0 = strtowstr(q); AddCode_IncludedCodes((int)n, q0); delete[] q0; } } - if(!isEol ) - { - while(fgets(str, str_size, fp)) if(*(strchr(str, 0)-1) == '\n') break; - } + filetok = strtok_r(nullptr, "\n", &filecontext); } - fclose(fp); - - return TRUE; -} - -KMX_BOOL NamedCodeConstants::LoadFile(const KMX_CHAR *filename) -{ - const int buf_size = 260; - KMX_CHAR buf[buf_size]; - // Look in current directory first -- REMOVED AS DANGEROUS - /* strncpy(buf, filename, (buf_size-1)); buf[buf_size-1] = 0; // I3481 - if(kmcmp_FileExists(buf)) - return IntLoadFile(buf); - */ - // Then look in keyboard file directory (CompileDir) - strncpy(buf, CompileDir, (buf_size-1)); buf[buf_size-1] = 0; // I3481 - strncat(buf, filename, (buf_size-1)-strlen(CompileDir)); buf[buf_size-1] = 0; - if(kmcmp_FileExists(buf)) - return IntLoadFile(buf); - - //TODO: sort out how to find common includes in non-Windows platforms: - #ifdef _WINDOWS_ - // Finally look in kmcmpdll.dll directory - GetModuleFileName(0, buf, buf_size); - - KMX_CHAR *p = strrchr_slash(buf); - if(p) - p++; - else - p = buf; - *p = 0; - strncat_s(buf, _countof(buf), filename, (buf_size-1)-strlen(buf)); buf[buf_size-1] = 0; // I3481 // I3641 - if(kmcmp_FileExists(buf)) - return IntLoadFile(buf); - #endif + delete[] Buf; reindex(); - - return FALSE; + return TRUE; } void NamedCodeConstants::reindex() diff --git a/developer/src/kmcmplib/src/NamedCodeConstants.h b/developer/src/kmcmplib/src/NamedCodeConstants.h index 83d707d092..c537a73361 100644 --- a/developer/src/kmcmplib/src/NamedCodeConstants.h +++ b/developer/src/kmcmplib/src/NamedCodeConstants.h @@ -2,6 +2,8 @@ #ifndef NAMEDCODECONSTANTS_H #define NAMEDCODECONSTANTS_H +#include "compfile.h" + #define MAX_ENAME 128 #define ALLOC_SIZE 256 @@ -23,14 +25,13 @@ namespace kmcmp{ int GetCode_IncludedCodes(const KMX_WCHAR *codename); void AddCode_IncludedCodes(int n, const KMX_WCHAR *p); - KMX_BOOL IntLoadFile(const KMX_CHAR *filename); public: NamedCodeConstants(); ~NamedCodeConstants(); void reindex(); void AddCode(int n, const KMX_WCHAR *p, KMX_DWORD storeIndex); - KMX_BOOL LoadFile(const KMX_CHAR *filename); + KMX_BOOL LoadFile(PFILE_KEYBOARD fk, const KMX_WCHAR *filename); int GetCode(const KMX_WCHAR *codename, KMX_DWORD *storeIndex); }; } diff --git a/developer/src/kmcmplib/src/compfile.h b/developer/src/kmcmplib/src/compfile.h index 7c262be090..c54663aba7 100644 --- a/developer/src/kmcmplib/src/compfile.h +++ b/developer/src/kmcmplib/src/compfile.h @@ -123,7 +123,8 @@ typedef FILE_VKDICTIONARY *PFILE_VKDICTIONARY; * Extra metadata for API consumers */ struct FILE_KEYBOARD_EXTRA { - std::u16string kvksFilename; // original TSS_VISUALKEYBOARD value + std::string kmnFilename; // utf-8 + std::u16string kvksFilename; // utf-16, original TSS_VISUALKEYBOARD value }; typedef struct FILE_KEYBOARD_EXTRA* PFILE_KEYBOARD_EXTRA; diff --git a/developer/src/kmcmplib/src/kmcmplib.h b/developer/src/kmcmplib/src/kmcmplib.h index 70718f98bc..f22c836bae 100644 --- a/developer/src/kmcmplib/src/kmcmplib.h +++ b/developer/src/kmcmplib/src/kmcmplib.h @@ -14,7 +14,6 @@ namespace kmcmp { extern KMX_BOOL FMnemonicLayout; extern KMX_BOOL FOldCharPosMatching; extern int CompileTarget; - extern KMX_CHAR CompileDir[260]; // TODO: this should not be a fixed buffer extern int BeginLine[4]; extern int currentLine; extern NamedCodeConstants *CodeConstants; diff --git a/developer/src/kmcmplib/src/meson.build b/developer/src/kmcmplib/src/meson.build index 727d6831e6..a81efac562 100644 --- a/developer/src/kmcmplib/src/meson.build +++ b/developer/src/kmcmplib/src/meson.build @@ -25,8 +25,10 @@ endif name_suffix = [] if cpp_compiler.get_id() == 'emscripten' - lib_links = ['--whole-archive', '--bind', '-sMODULARIZE', '-sEXPORT_ES6'] - links += ['-lnodefs.js', '--bind', '-sEXPORTED_RUNTIME_METHODS=[\'UTF8ToString\']'] + # wasm-exceptions supported in Node 18+, Chrome 95+, Firefox 100+, Safari 15.2+ + flags += ['-fwasm-exceptions'] + lib_links = ['--whole-archive', '-sMODULARIZE', '-sEXPORT_ES6'] + links += ['-fwasm-exceptions', '--bind', '-sEXPORTED_RUNTIME_METHODS=[\'UTF8ToString\']'] # tests are building as ES6 so we need to declare the file extension # note that meson currently struggles with the sanitycheckc_cross.exe # program, because it has a hard coded extension (.exe) which is not @@ -44,7 +46,6 @@ lib = library('kmcmplib', 'CompilerInterfaces.cpp', 'DeprecationChecks.cpp', 'Edition.cpp', - 'filesystem.cpp', 'NamedCodeConstants.cpp', 'versioning.cpp', 'virtualcharkeys.cpp', @@ -79,7 +80,7 @@ if cpp_compiler.get_id() == 'emscripten' host = executable('wasm-host', #'wasm-host.cpp', cpp_args: defns, include_directories: inc, - link_args: links, + link_args: links + lib_links, objects: lib.extract_all_objects(), dependencies: icuuc_dep) endif diff --git a/developer/src/kmcmplib/src/pch.h b/developer/src/kmcmplib/src/pch.h index f878ad11be..358e28998a 100644 --- a/developer/src/kmcmplib/src/pch.h +++ b/developer/src/kmcmplib/src/pch.h @@ -10,6 +10,4 @@ #include "../../../../common/windows/cpp/include/crc32.h" #include -#include - #include diff --git a/developer/src/kmcmplib/tests/api-test.cpp b/developer/src/kmcmplib/tests/api-test.cpp index b347773220..cdbabea4d5 100644 --- a/developer/src/kmcmplib/tests/api-test.cpp +++ b/developer/src/kmcmplib/tests/api-test.cpp @@ -18,54 +18,12 @@ #include #include "../src/compfile.h" #include -#include "../src/filesystem.h" +#include "util_filesystem.h" +#include "util_callbacks.h" void setup(); void test_kmcmp_CompileKeyboard(char *kmn_file); -std::vector error_vec; - -int msgproc(int line, uint32_t dwMsgCode, const char* szText, void* context) { - error_vec.push_back(dwMsgCode); - const char*t = "unknown"; - switch(dwMsgCode & 0xF000) { - case CERR_HINT: t=" hint"; break; - case CERR_WARNING: t="warning"; break; - case CERR_ERROR: t=" error"; break; - case CERR_FATAL: t=" fatal"; break; - } - printf("line %d %s %04.4x: %s\n", line, t, (unsigned int)dwMsgCode, szText); - return 1; -} - -bool loadfileProc(const char* filename, const char* baseFilename, void* data, int* size, void* context) { - FILE* fp = Open_File(filename, "rb"); - if(!fp) { - return false; - } - - if(!data) { - // return size - if(fseek(fp, 0, SEEK_END) != 0) { - fclose(fp); - return false; - } - *size = ftell(fp); - if(*size == -1L) { - fclose(fp); - return false; - } - } else { - // return data - if(fread(data, 1, *size, fp) != *size) { - fclose(fp); - return false; - } - } - fclose(fp); - return true; -} - int main(int argc, char *argv[]) { if(argc < 1) { puts("Usage: api-test "); @@ -82,6 +40,13 @@ void setup() { error_vec.clear(); } +/* + TODO: tests to run: + 4. ANSI (no BOM of course) + 8. file without blank last line (cannot compare with fixture due to bug in kmcmpdll...) + Hint to add: k004_ansi.kmn: Hint: 10A6 Keyman Developer has detected that the file has ANSI encoding. Consider converting this file to UTF-8 +*/ + void test_kmcmp_CompileKeyboard(char *kmn_file) { // Create an empty file FILE *fp = Open_File(kmn_file, "wb"); diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/compile_legacy.bat b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/compile_legacy.bat new file mode 100644 index 0000000000..e346418eb4 --- /dev/null +++ b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/compile_legacy.bat @@ -0,0 +1,4 @@ +@echo off +echo Compiles the keyboards using the legacy kmcomp.exe +echo to use as baseline comparisons for kmcmplib +for %%d in (*.kmn) do kmcomp -no-compiler-version -d %%d \ No newline at end of file diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k001_utf16.kmn b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k001_utf16.kmn new file mode 100644 index 0000000000000000000000000000000000000000..2b3180c36ab4b473e74b1b3487fc8f0a61d623f6 GIT binary patch literal 452 zcmZvX%}T>S6otRF;Ci;RG8IwmMz9N^r4>Z2P-{0*q)pQpYC6SO#HDW`K8}yz1F2_b zEO8;>PVStad(V7-rC7RTRHQsou;NLlV@XTQNQ_74DzC9(@0sYdEGXqE<#-S~6_Scs zhQAAVAtuv(qPk(oDf=`z;)0$KKQreYOjH}hfM HO;rB?W(q}E literal 0 HcmV?d00001 diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k001_utf16.kmx b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k001_utf16.kmx new file mode 100644 index 0000000000000000000000000000000000000000..13ea2a686e09c16db68ff7bb355e114b9125d76d GIT binary patch literal 356 zcmX|-y-EW?6h@CC{(@LJjfK^g5*smH5)hGKgd~cM=wcK?h&EbS+F6LTi1-vfKuBe6 zY2hPS_yT(Fx_IF%-}l|QGdt5f>~@%g>e1pi)hKINm-ap;#+1e%<2!;qYd!Vk use(main) + +group(main) using keys + ++ [K_A] > 'a' +'a' + [K_B] > 'ខ្មែរ' diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k002_utf8_without_bom.kmx b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k002_utf8_without_bom.kmx new file mode 100644 index 0000000000000000000000000000000000000000..0b9c9294182d9387165c98e1ffc84c8fe45452e3 GIT binary patch literal 378 zcmX|-zb}JP6owxn6pNv86O*ZdP*T+eoFYo)Fd(S=j8hhJK#^I(|T)`TOA8S;iuF8z!+fx45AU`;5awoSE5eup-GIf`;l(pDb^*mi- zgBt5Bs~4F|6HDysw`j7)rhS|MtM+EoD_MGH-mK1!I^)1;9k+mrTP?|74J)FJ+x_0F i=_X>k3LRTrscR?m>{x#(?dZ7 use(main) + +group(main) using keys + ++ [K_A] > 'a' +'a' + [K_B] > 'ខ្មែរ' diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k003_utf8_with_bom.kmx b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k003_utf8_with_bom.kmx new file mode 100644 index 0000000000000000000000000000000000000000..ee1cf4225502e3c7944b58f301e5be649af4ec00 GIT binary patch literal 372 zcmX|-y-EW?6h@B`{B116X{}O;1cXJqBp?!k5sZqJk{HD$Xi`MP(k_Kq2MIojmG}T+ zXuY}scO@6Efi@` zVV7<77VFupB1igtn$*~{k9%Rq-fA{K%}z+nsvN3Q&Yafqd|2~NN&bIY3KDI+*JNKs gw;=I(PHeTMs$I;pj=nFg=(!IcVH94&lMfV=KM7PUb^rhX literal 0 HcmV?d00001 diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k004_ansi.kmn b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k004_ansi.kmn new file mode 100644 index 0000000000..50a1b31ea1 --- /dev/null +++ b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k004_ansi.kmn @@ -0,0 +1,13 @@ +c Description: Verifies that kmcmplib can compile an ANSI file +c This has some high-ascii letters in cp1252 to ensure that +c it fails to load as 'utf8 without bom' + +store(&NAME) 'k004_ansi' +store(&VERSION) '9.0' + +begin unicode > use(main) + +group(main) using keys + ++ [K_A] > 'a' +'a' + [K_B] > 'ÀÐ' diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k004_ansi.kmx b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k004_ansi.kmx new file mode 100644 index 0000000000000000000000000000000000000000..6c41da979cb2a3ec20aadf6de0ca778fb8ce5ec1 GIT binary patch literal 350 zcmX|-y-EW?6h@CCYQTV1Y%Ef3DG6A_&MX88!36RnVxa_+Vi8S|DsPZN@&q9dkp~bf zYfGyKTe*wxmCUXD) literal 0 HcmV?d00001 diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k005_bitmap.bmp b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k005_bitmap.bmp new file mode 100644 index 0000000000000000000000000000000000000000..509b89ae6df7f09a442ae60f215a6c7b3211b34f GIT binary patch literal 246 zcmZvUF%Ez*2t_e5>FO~&hr4&_cK5)zF7R>OXdqB#E&96yg&T8zj G@{Su^DQ%(v literal 0 HcmV?d00001 diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k005_bitmap.kmn b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k005_bitmap.kmn new file mode 100644 index 0000000000..926ccdeeaf --- /dev/null +++ b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k005_bitmap.kmn @@ -0,0 +1,12 @@ +c Description: Verifies that kmcmplib can load a bitmap without file extension + +store(&NAME) 'k005_bitmap' +store(&VERSION) '9.0' +store(&BITMAP) 'k005_bitmap' + +begin unicode > use(main) + +group(main) using keys + ++ [K_A] > 'a' +'a' + [K_B] > 'ខ្មែរ' diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k005_bitmap.kmx b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k005_bitmap.kmx new file mode 100644 index 0000000000000000000000000000000000000000..bc9bc9b671724050e169e59fce976a18d54a030e GIT binary patch literal 656 zcmZ{hyGjF55QhJV5JkZh;`acRmwz7&=*hh@R?A}o^(Fw$>p)BB*B zffhV~2T#xjoA1IijKLecfV&^}PM(8l@|;2L6X&2nE|qnpYn`g0GgqI`FK9t~+E=Ix zr$i`ut*fMpR>+q$@22zGrmm`{HEp0v|4#>;sWV^Frn^B}<&If*f9SrwNI%dPd8h-O z>yVd8RbILaLmMHn(q5d*m8d36E=qSuO$aC_)80MxBQ&hmt@rA+ysp>gH(DpC*#9-V z0w3%j85xb@rP%qu9Eyo?oCG{6#Oic92&~e!$x2D|BF%`g<4g%dtuD`P6eIRAp=916x*GXhr`_H use(main) + +group(main) using keys + ++ [K_A] > 'a' +'a' + [K_B] > 'ខ្មែរ' diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k006_icon.kmx b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k006_icon.kmx new file mode 100644 index 0000000000000000000000000000000000000000..f994a1dcac9e5ae797eb88eed9cee4b0e6f85b00 GIT binary patch literal 728 zcmbu6JxhX76vzKYU{S*}M9=CF;v`N*4WU9rNH3^GLlE{dNK~#(-JqeGBgC;O`Vb+F zjedqcfJ@|NzjNS>L1T*-NfuF<9K>=T?=vWszRYPY!J|SPwy!O@9q0W6a zs|}U3t`#~KmG_fb?GRU0)0#G^OMfTx$qp&2GJSP+l(glyNUQA0_>-Idlm+r-ZR3ZN zkGPps<)(Wuk}(_$?Z#oQL^NgPqI6B^2FirfN$!sL0U8$TD(=PY_%-hEj3JX^Ulc{? zasM{<);X}Z%7EofoYz5F%?RQ`(K+8^8W)_p-7YPBsr@Qn>kZm|*}mHT`SFvrMGq4+QP0yrw1lmGw# literal 0 HcmV?d00001 diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k007_includecodes_r_n.kmn b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k007_includecodes_r_n.kmn new file mode 100644 index 0000000000..71d72d5120 --- /dev/null +++ b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k007_includecodes_r_n.kmn @@ -0,0 +1,12 @@ +c Description: Verifies that kmcmplib can load an includecodes file with \r\n line endings + +store(&NAME) 'k007_includecodes_r_n' +store(&VERSION) '9.0' +store(&includecodes) 'k007_includecodes_r_n.txt' + +begin unicode > use(main) + +group(main) using keys + ++ [K_A] > $LOWER_A +$LOWER_A + [K_B] > $LOWER_B diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k007_includecodes_r_n.kmx b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k007_includecodes_r_n.kmx new file mode 100644 index 0000000000000000000000000000000000000000..f8b4eac1b0d9103c7767e487b5109a06aed8e1ec GIT binary patch literal 462 zcma)%J4%C55JrzSDq4tzwy9Ev-%9L~fQZBwiHe=Z#3J|zmm`-ru-1)wlxv$dkL4`TUG*`bcreZN>By?W7ilL#L#M^jq*~&ofWJMn2 zUSj{dJj$$m%7-jT;@)rbqU@`;C3M|ihyS0LqfJlZ use(main) + +group(main) using keys + ++ [K_A] > $LOWER_A +$LOWER_A + [K_B] > $LOWER_B diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k008_includecodes_n.kmx b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k008_includecodes_n.kmx new file mode 100644 index 0000000000000000000000000000000000000000..aa158cdd546cdde915e4a55c1db521e57d4abb04 GIT binary patch literal 454 zcma)%zb=De6o;Q$N*Khz%F>vcZrIv}AYW9XNQWlUmZ3onNVox$!C+{51>y<}(!t;Y zT!2O58f-l0Q{9?4$@8Ay@0|1gOKQ7SCSc(<`M}7;Vq_(BQ96omLphAs!QiZwuH4I< zJV;Ms|C>C@xO~dH%*dj9zs%FJpf~T9ja`yZ6E%3TAmB8Bu*W5Yup0s-ZP)RHs)YS%IvAz p!xzGhzq^ya7*m9eU;geZ=_aFHgeP0iQr1olYJL5SG{V!AP(Sg;I(+~D literal 0 HcmV?d00001 diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k008_includecodes_n.txt b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k008_includecodes_n.txt new file mode 100644 index 0000000000..4cc3fe4351 --- /dev/null +++ b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k008_includecodes_n.txt @@ -0,0 +1,2 @@ +0061;LOWER_A +0062;LOWER_B diff --git a/developer/src/kmcmplib/tests/kmcompxtest.cpp b/developer/src/kmcmplib/tests/kmcompxtest.cpp index c5d189798b..5dbaee88bc 100644 --- a/developer/src/kmcmplib/tests/kmcompxtest.cpp +++ b/developer/src/kmcmplib/tests/kmcompxtest.cpp @@ -13,7 +13,8 @@ #include #include #include -#include "../src/filesystem.h" +#include "util_filesystem.h" +#include "util_callbacks.h" #ifdef _MSC_VER #else @@ -22,57 +23,11 @@ using namespace std; -vector < int > error_vec; - #define CERR_FATAL 0x00008000 #define CERR_ERROR 0x00004000 #define CERR_WARNING 0x00002000 #define CERR_HINT 0x00001000 -int msgproc(int line, uint32_t dwMsgCode, const char* szText, void* context) -{ - error_vec.push_back(dwMsgCode); - const char*t = "unknown"; - switch(dwMsgCode & 0xF000) { - case CERR_HINT: t=" hint"; break; - case CERR_WARNING: t="warning"; break; - case CERR_ERROR: t=" error"; break; - case CERR_FATAL: t=" fatal"; break; - } - printf("line %d %s %04.4x: %s\n", line, t, (unsigned int)dwMsgCode, szText); - return 1; -} - -bool loadfileProc(const char* filename, const char* baseFilename, void* data, int* size, void* context) { - FILE* fp = Open_File(filename, "rb"); - if(!fp) { - return false; - } - - if(!data) { - // return size - if(fseek(fp, 0, SEEK_END) != 0) { - fclose(fp); - return false; - } - *size = ftell(fp); - if(*size == -1L) { - fclose(fp); - return false; - } - } else { - // return data - if(fread(data, 1, *size, fp) != *size) { - fclose(fp); - return false; - } - } - fclose(fp); - return true; -} - -#include "../src/filesystem.h" - int main(int argc, char *argv[]) { if(argc < 4) { diff --git a/developer/src/kmcmplib/tests/meson.build b/developer/src/kmcmplib/tests/meson.build index 2468ac53b1..cc51189a63 100644 --- a/developer/src/kmcmplib/tests/meson.build +++ b/developer/src/kmcmplib/tests/meson.build @@ -6,16 +6,20 @@ fs = import('fs') -tests_flags = [] +tests_links = [] + +if cpp_compiler.get_id() == 'emscripten' + tests_links += ['-lnodefs.js'] +endif input_path = meson.current_source_dir() / '../../../../common/test/keyboards/baseline' output_path = meson.current_build_dir() -kmcompxtest = executable('kmcompxtest', 'kmcompxtest.cpp', - cpp_args: defns, +kmcompxtest = executable('kmcompxtest', ['kmcompxtest.cpp','util_filesystem.cpp','util_callbacks.cpp'], + cpp_args: defns + flags, include_directories: inc, name_suffix: name_suffix, - link_args: links + tests_flags, + link_args: links + tests_links, objects: lib.extract_all_objects(), dependencies: icuuc_dep, ) @@ -76,6 +80,25 @@ foreach kbd : tests test(kbd, kmcompxtest, args: [kbd_src, kbd_obj, join_paths(input_path, kbd) + '.kmx']) endforeach +valid_keyboard_tests = [ + 'k001_utf16', + 'k002_utf8_without_bom', + 'k003_utf8_with_bom', + # 'k004_ansi', # TODO: enable ansi test when we have the icu datafiles + 'k005_bitmap', + 'k006_icon', + 'k007_includecodes_r_n', + 'k008_includecodes_n' +] + +fixtures_path = meson.current_source_dir() / 'fixtures/valid-keyboards' + +foreach kbd : valid_keyboard_tests + kbd_src = join_paths(fixtures_path, kbd) + '.kmn' + kbd_obj = join_paths(output_path, kbd) + '.kmx' + test(kbd, kmcompxtest, args: [kbd_src, kbd_obj, join_paths(fixtures_path, kbd) + '.kmx']) +endforeach + # Test fixtures that come from keyboards repo -- but only for a "full" test, # which typically we run on CI no more than once a day, because it's expensive. @@ -107,11 +130,11 @@ endif # Test the API endpoints -apitest = executable('api-test', 'api-test.cpp', - cpp_args: defns, +apitest = executable('api-test', ['api-test.cpp','util_filesystem.cpp','util_callbacks.cpp'], + cpp_args: defns + flags, include_directories: inc, name_suffix: name_suffix, - link_args: links + tests_flags, + link_args: links + tests_links, objects: lib.extract_all_objects(), dependencies: icuuc_dep ) @@ -119,10 +142,10 @@ apitest = executable('api-test', 'api-test.cpp', test('api-test', apitest, args: [output_path / 'blank_keyboard.kmx']) usetapitest = executable('uset-api-test', 'uset-api-test.cpp', - cpp_args: defns, + cpp_args: defns + flags, include_directories: inc, name_suffix: name_suffix, - link_args: links + tests_flags, + link_args: links + tests_links, objects: lib.extract_all_objects(), dependencies: icuuc_dep, ) diff --git a/developer/src/kmcmplib/tests/util_callbacks.cpp b/developer/src/kmcmplib/tests/util_callbacks.cpp new file mode 100644 index 0000000000..e610a54c09 --- /dev/null +++ b/developer/src/kmcmplib/tests/util_callbacks.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include "util_filesystem.h" +#include "../src/compfile.h" +#include + +std::vector error_vec; + +int msgproc(int line, uint32_t dwMsgCode, const char* szText, void* context) { + error_vec.push_back(dwMsgCode); + const char*t = "unknown"; + switch(dwMsgCode & 0xF000) { + case CERR_HINT: t=" hint"; break; + case CERR_WARNING: t="warning"; break; + case CERR_ERROR: t=" error"; break; + case CERR_FATAL: t=" fatal"; break; + } + printf("line %d %s %04.4x: %s\n", line, t, (unsigned int)dwMsgCode, szText); + return 1; +} + +bool loadfileProc(const char* filename, const char* baseFilename, void* data, int* size, void* context) { + std::string resolvedFilename = filename; + if(baseFilename && *baseFilename && IsRelativePath(filename)) { + char* p; + if ((p = strrchr_slash((char*)baseFilename)) != nullptr) { + std::string basePath = std::string(baseFilename, (int)(p - baseFilename + 1)); + resolvedFilename = basePath; + resolvedFilename.append(filename); + } + } + + FILE* fp = Open_File(resolvedFilename.c_str(), "rb"); + if(!fp) { + return false; + } + + if(!data) { + // return size + if(fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + return false; + } + *size = ftell(fp); + if(*size == -1L) { + fclose(fp); + return false; + } + } else { + // return data + if(fread(data, 1, *size, fp) != *size) { + fclose(fp); + return false; + } + } + fclose(fp); + return true; +} \ No newline at end of file diff --git a/developer/src/kmcmplib/tests/util_callbacks.h b/developer/src/kmcmplib/tests/util_callbacks.h new file mode 100644 index 0000000000..345de64b9f --- /dev/null +++ b/developer/src/kmcmplib/tests/util_callbacks.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +int msgproc(int line, uint32_t dwMsgCode, const char* szText, void* context); +bool loadfileProc(const char* filename, const char* baseFilename, void* data, int* size, void* context); + +extern std::vector error_vec; \ No newline at end of file diff --git a/developer/src/kmcmplib/src/filesystem.cpp b/developer/src/kmcmplib/tests/util_filesystem.cpp similarity index 84% rename from developer/src/kmcmplib/src/filesystem.cpp rename to developer/src/kmcmplib/tests/util_filesystem.cpp index a343641acc..7f9edd6b36 100644 --- a/developer/src/kmcmplib/src/filesystem.cpp +++ b/developer/src/kmcmplib/tests/util_filesystem.cpp @@ -7,7 +7,7 @@ #include #include #include -#include "filesystem.h" +#include "util_filesystem.h" #ifdef _MSC_VER #include @@ -186,3 +186,42 @@ KMX_BOOL kmcmp_FileExists(const KMX_WCHAR* filename) { return FALSE; }; + + +bool IsRelativePath(KMX_CHAR const * p) { + // Relative path (returns TRUE): + // ..\...\BITMAP.BMP + // PATH\BITMAP.BMP + // BITMAP.BMP + + // Semi-absolute path (returns FALSE): + // \...\BITMAP.BMP + + // Absolute path (returns FALSE): + // C:\...\BITMAP.BMP + // \\SERVER\SHARE\...\BITMAP.BMP + + if ((*p == '\\') || (*p == '/')) return FALSE; + if (*p && *(p + 1) == ':') return FALSE; + + return TRUE; +} + +bool IsRelativePath(KMX_WCHAR const * p) { + // Relative path (returns TRUE): + // ..\...\BITMAP.BMP + // PATH\BITMAP.BMP + // BITMAP.BMP + + // Semi-absolute path (returns FALSE): + // \...\BITMAP.BMP + + // Absolute path (returns FALSE): + // C:\...\BITMAP.BMP + // \\SERVER\SHARE\...\BITMAP.BMP + + if ((*p == u'\\') || (*p == u'/'))return FALSE; + if (*p && *(p + 1) == u':') return FALSE; + + return TRUE; +} \ No newline at end of file diff --git a/developer/src/kmcmplib/src/filesystem.h b/developer/src/kmcmplib/tests/util_filesystem.h similarity index 82% rename from developer/src/kmcmplib/src/filesystem.h rename to developer/src/kmcmplib/tests/util_filesystem.h index 786b7268ac..4c94dae6bf 100644 --- a/developer/src/kmcmplib/src/filesystem.h +++ b/developer/src/kmcmplib/tests/util_filesystem.h @@ -1,7 +1,7 @@ #pragma once #include -#include "kmx_u16.h" +#include "../src/kmx_u16.h" // Opens files on windows and non-windows platforms. Datatypes for Filename and mode must be the same. // returns FILE* if file could be opened; FILE needs to be closed in calling function @@ -10,3 +10,6 @@ FILE* Open_File(const KMX_WCHART* Filename, const KMX_WCHART* mode); FILE* Open_File(const KMX_WCHAR* Filename, const KMX_WCHAR* mode); KMX_BOOL kmcmp_FileExists(const KMX_CHAR *filename); KMX_BOOL kmcmp_FileExists(const KMX_WCHAR *filename); + +bool IsRelativePath(KMX_CHAR const * p); +bool IsRelativePath(KMX_WCHAR const * p); -- GitLab From 6f4f20acb8e90d9c25f6b5da56299b3148580f07 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 31 May 2023 12:13:59 +1000 Subject: [PATCH 172/214] chore(developer): Add TODO issue numbers to PR --- developer/src/kmc-kmn/src/compiler/compiler.ts | 8 ++++---- developer/src/kmcmplib/include/kmcmplibapi.h | 2 +- developer/src/kmcmplib/src/CheckFilenameConsistency.cpp | 2 +- developer/src/kmcmplib/src/Compiler.cpp | 2 +- developer/src/kmcmplib/src/CompilerInterfaces.cpp | 3 +++ developer/src/kmcmplib/src/meson.build | 5 ----- developer/src/kmcmplib/tests/api-test.cpp | 2 +- developer/src/kmcmplib/tests/meson.build | 2 +- 8 files changed, 12 insertions(+), 14 deletions(-) diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index b27440fd06..3c6df80e7e 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -120,7 +120,7 @@ export class KmnCompiler { } private loadFileCallback = (filename: string, baseFilename: string, buffer: number, bufferSize: number): number => { - // TODO: we can optimize this in future by avoiding loading the file twice + // TODO: we can optimize this in future by avoiding loading the file twice #8885 let resolvedFilename = this.callbacks.resolveFilename(baseFilename, filename); let data = this.callbacks.loadFile(resolvedFilename); if(!data) { @@ -133,7 +133,7 @@ export class KmnCompiler { } if(bufferSize != data.byteLength) { - // TODO: consider chucking a wobbly because this is a bug + // TODO: consider chucking a wobbly because this is a bug #8885 /* c8 ignore next 2 */ return 0; } @@ -195,7 +195,7 @@ export class KmnCompiler { reader.validate(kvks, this.callbacks.loadSchema('kvks')); } catch(e) { console.log(e); - // TODO: also unit test + // TODO: also unit test #8886 // TODO: this.callbacks.reportMessage(CompilerMessages.Error_InvalidKvksFile({e})); return null; } @@ -203,7 +203,7 @@ export class KmnCompiler { let vk = reader.transform(kvks, errors); if(!vk || errors.length) { console.dir(errors); - // TODO: also unit test + // TODO: also unit test #8886 // TODO: this.callbacks.reportMessage(CompilerMessages.Error_InvalidKvksFile({e})); return null; } diff --git a/developer/src/kmcmplib/include/kmcmplibapi.h b/developer/src/kmcmplib/include/kmcmplibapi.h index 5c2ae46fda..0b41af6990 100644 --- a/developer/src/kmcmplib/include/kmcmplibapi.h +++ b/developer/src/kmcmplib/include/kmcmplibapi.h @@ -35,7 +35,7 @@ struct KMCMP_COMPILER_RESULT { std::string kvksFilename; }; -// TODO: parameters in UTF-8 +// TODO: parameters in UTF-8 #8887 typedef int (*kmcmp_CompilerMessageProc)(int line, uint32_t dwMsgCode, const char* szText, void* context); // parameters in UTF-8 diff --git a/developer/src/kmcmplib/src/CheckFilenameConsistency.cpp b/developer/src/kmcmplib/src/CheckFilenameConsistency.cpp index 3a185bc403..6d113d116b 100644 --- a/developer/src/kmcmplib/src/CheckFilenameConsistency.cpp +++ b/developer/src/kmcmplib/src/CheckFilenameConsistency.cpp @@ -24,7 +24,7 @@ KMX_DWORD CheckFilenameConsistency( KMX_CHAR const * Filename, bool ReportMissin KMX_DWORD CheckFilenameConsistency(KMX_WCHAR const * Filename, bool ReportMissingFile) { // TODO: we no longer have filesystem access here. We could move this check to // kmc itself, and make it consistent across all compilers that use the same - // loader callback + // loader callback -- see #8883 return CERR_None; #if 0 diff --git a/developer/src/kmcmplib/src/Compiler.cpp b/developer/src/kmcmplib/src/Compiler.cpp index 91e02e14e7..49484b1acc 100644 --- a/developer/src/kmcmplib/src/Compiler.cpp +++ b/developer/src/kmcmplib/src/Compiler.cpp @@ -3428,7 +3428,7 @@ bool UTF16TempFromUTF8(KMX_BYTE* infile, int sz, KMX_BYTE** tempfile, int *sz16) result = converter.from_bytes((char*)infile, (char*)infile+sz); } catch(std::range_error e) { UErrorCode status = U_ZERO_ERROR; - // TODO: we need ICU data files here @srl295 plz help! + // TODO: we need ICU data files here #8884 UConverter* conv = ucnv_open("windows-1252", &status); if(U_FAILURE(status)) { return FALSE; diff --git a/developer/src/kmcmplib/src/CompilerInterfaces.cpp b/developer/src/kmcmplib/src/CompilerInterfaces.cpp index 1a4e77f8e8..16b5b98654 100644 --- a/developer/src/kmcmplib/src/CompilerInterfaces.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfaces.cpp @@ -13,6 +13,9 @@ bool CompileKeyboardHandle(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk); #ifdef __EMSCRIPTEN__ +// TODO: move emscripten wrappers into their own .cpp. Also move CompileKeyboardHandle +// into its own .cpp, so CompilerInterfaces.cpp has only C public API functions listed. +// #8889 /* WASM interface for compiler message callback diff --git a/developer/src/kmcmplib/src/meson.build b/developer/src/kmcmplib/src/meson.build index a81efac562..e697a0dced 100644 --- a/developer/src/kmcmplib/src/meson.build +++ b/developer/src/kmcmplib/src/meson.build @@ -29,11 +29,6 @@ if cpp_compiler.get_id() == 'emscripten' flags += ['-fwasm-exceptions'] lib_links = ['--whole-archive', '-sMODULARIZE', '-sEXPORT_ES6'] links += ['-fwasm-exceptions', '--bind', '-sEXPORTED_RUNTIME_METHODS=[\'UTF8ToString\']'] - # tests are building as ES6 so we need to declare the file extension - # note that meson currently struggles with the sanitycheckc_cross.exe - # program, because it has a hard coded extension (.exe) which is not - # valid for node programs in module mode. - # name_suffix = '.mjs' endif icu = subproject('icu-for-uset', default_options: [ 'default_library=static', 'cpp_std=c++17', 'warning_level=0', 'werror=false']) diff --git a/developer/src/kmcmplib/tests/api-test.cpp b/developer/src/kmcmplib/tests/api-test.cpp index cdbabea4d5..cb0337caef 100644 --- a/developer/src/kmcmplib/tests/api-test.cpp +++ b/developer/src/kmcmplib/tests/api-test.cpp @@ -42,7 +42,7 @@ void setup() { /* TODO: tests to run: - 4. ANSI (no BOM of course) + 4. ANSI (no BOM of course) #8884 8. file without blank last line (cannot compare with fixture due to bug in kmcmpdll...) Hint to add: k004_ansi.kmn: Hint: 10A6 Keyman Developer has detected that the file has ANSI encoding. Consider converting this file to UTF-8 */ diff --git a/developer/src/kmcmplib/tests/meson.build b/developer/src/kmcmplib/tests/meson.build index cc51189a63..0d4c078ed3 100644 --- a/developer/src/kmcmplib/tests/meson.build +++ b/developer/src/kmcmplib/tests/meson.build @@ -84,7 +84,7 @@ valid_keyboard_tests = [ 'k001_utf16', 'k002_utf8_without_bom', 'k003_utf8_with_bom', - # 'k004_ansi', # TODO: enable ansi test when we have the icu datafiles + # 'k004_ansi', # TODO: enable ansi test when we have the icu datafiles #8884 'k005_bitmap', 'k006_icon', 'k007_includecodes_r_n', -- GitLab From e2930fa08058d17cbb4be9da462bea520e1d4505 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 31 May 2023 10:23:42 +0700 Subject: [PATCH 173/214] chore(developer): fix npm pack for kmc-ldml --- package-lock.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package-lock.json b/package-lock.json index 20d7ce98c4..75d9e1abef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1030,6 +1030,7 @@ } }, "developer/src/kmc-ldml": { + "name": "@keymanapp/kmc-ldml", "license": "MIT", "dependencies": { "@keymanapp/keyman-version": "*", -- GitLab From 9d351f4798d80ef71044ae80812a7cc7b2e08322 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 31 May 2023 15:22:54 +0700 Subject: [PATCH 174/214] chore(developer): verify kvks files and report errors Fixes #8886. .kvks compiler now returns helpful errors for xml parse failures and schema validation errors, and for invalid virtual key codes. Introduces extra infrastructure for reporting and unit testing messages to kmc-kmn. This also fixes unhandled xml load exceptions and simplifies the error reporting coming out of the kvks loader, on the basis that only one type of error was being reported anyway. --- common/web/types/src/kvk/kvks-file-reader.ts | 25 ++++------ .../web/types/test/kvk/test-kvk-round-trip.ts | 14 +++--- common/web/types/test/kvk/test-kvks-file.ts | 14 +++--- .../src/kmc-kmn/src/compiler/compiler.ts | 48 +++++++++---------- .../src/kmc-kmn/src/compiler/messages.ts | 8 ++++ .../error_invalid_kvks_file.kmn | 12 +++++ .../error_invalid_kvks_file.kvks | 9 ++++ .../warn_invalid_vkey_in_kvks_file.kmn | 12 +++++ .../warn_invalid_vkey_in_kvks_file.kvks | 15 ++++++ developer/src/kmc-kmn/test/helpers/index.ts | 17 +++++++ developer/src/kmc-kmn/test/test-messages.ts | 47 +++++++++++++++++- developer/src/kmc-kmn/test/tsconfig.json | 3 +- 12 files changed, 167 insertions(+), 57 deletions(-) create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_invalid_kvks_file.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_invalid_kvks_file.kvks create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_invalid_vkey_in_kvks_file.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_invalid_vkey_in_kvks_file.kvks create mode 100644 developer/src/kmc-kmn/test/helpers/index.ts diff --git a/common/web/types/src/kvk/kvks-file-reader.ts b/common/web/types/src/kvk/kvks-file-reader.ts index c12b7036e4..184c162210 100644 --- a/common/web/types/src/kvk/kvks-file-reader.ts +++ b/common/web/types/src/kvk/kvks-file-reader.ts @@ -7,12 +7,6 @@ import { VisualKeyboard, VisualKeyboardHeaderFlags, VisualKeyboardKey, VisualKey import { USVirtualKeyCodes } from '../consts/virtual-key-constants.js'; import { BUILDER_KVK_HEADER_VERSION } from './kvk-file.js'; -export enum KVKSParseErrorType { invalidVkey }; -export class KVKSParseError extends Error { - public type: KVKSParseErrorType; - public vkey: string; -}; - export default class KVKSFileReader { public read(file: Uint8Array): KVKSourceFile { let source: KVKSourceFile; @@ -33,10 +27,12 @@ export default class KVKSFileReader { // rather than using the version tagged on npmjs.com. }); - parser.parseString(file, (e: unknown, r: unknown) => { source = r as KVKSourceFile }); - source = this.boxArrays(source); - this.cleanupFlags(source); - this.cleanupUnderscore('visualkeyboard', source.visualkeyboard); + parser.parseString(file, (e: unknown, r: unknown) => { if(e) { throw e }; source = r as KVKSourceFile }); + if(source) { + source = this.boxArrays(source); + this.cleanupFlags(source); + this.cleanupUnderscore('visualkeyboard', source.visualkeyboard); + } return source; } @@ -80,7 +76,7 @@ export default class KVKSFileReader { } } - public transform(source: KVKSourceFile, errors?: KVKSParseError[]): VisualKeyboard { + public transform(source: KVKSourceFile, invalidVkeys?: string[]): VisualKeyboard { // NOTE: at this point, the xml should have been validated // and matched the schema result so we can assume properties exist let result: VisualKeyboard = { @@ -118,11 +114,8 @@ export default class KVKSFileReader { for(let sourceKey of layer.key) { let vkey = (USVirtualKeyCodes as any)[sourceKey.$?.vkey]; if(!vkey) { - if(errors) { - let e = new KVKSParseError(); - e.type = KVKSParseErrorType.invalidVkey; - e.vkey = sourceKey.$?.vkey; - errors.push(e); + if(typeof invalidVkeys !== 'undefined') { + invalidVkeys.push(sourceKey.$?.vkey); } continue; } diff --git a/common/web/types/test/kvk/test-kvk-round-trip.ts b/common/web/types/test/kvk/test-kvk-round-trip.ts index 41dbe2dbc0..031ad60b9e 100644 --- a/common/web/types/test/kvk/test-kvk-round-trip.ts +++ b/common/web/types/test/kvk/test-kvk-round-trip.ts @@ -5,7 +5,7 @@ import Hexy from 'hexy'; import gitDiff from 'git-diff'; const { hexy } = Hexy; import { loadSchema, makePathToFixture } from '../helpers/index.js'; -import KvksFileReader, { KVKSParseError } from "../../src/kvk/kvks-file-reader.js"; +import KvksFileReader from "../../src/kvk/kvks-file-reader.js"; import KvkFileReader from "../../src/kvk/kvk-file-reader.js"; import KvkFileWriter from "../../src/kvk/kvk-file-writer.js"; import KvksFileWriter from "../../src/kvk/kvks-file-writer.js"; @@ -53,9 +53,9 @@ describe('kvks-file-reader', function () { assert.doesNotThrow(() => { reader.validate(kvks, loadSchema('kvks')); }); - const errors: KVKSParseError[] = []; - const vk = reader.transform(kvks, errors); - assert.isEmpty(errors); + const invalidVkeys: string[] = []; + const vk = reader.transform(kvks, invalidVkeys); + assert.isEmpty(invalidVkeys); const writer = new KvkFileWriter(); const output = writer.write(vk); assertBufferMatch(Buffer.from(output), compiled); @@ -76,9 +76,9 @@ describe('kvks-file-reader', function () { assert.doesNotThrow(() => { kvksReader.validate(kvks, loadSchema('kvks')); }); - const errors: KVKSParseError[] = []; - const vk2 = kvksReader.transform(kvks, errors); - assert.isEmpty(errors); + const invalidVkeys: string[] = []; + const vk2 = kvksReader.transform(kvks, invalidVkeys); + assert.isEmpty(invalidVkeys); // make sure the binary is the same assert.deepEqual(vk2, vk); diff --git a/common/web/types/test/kvk/test-kvks-file.ts b/common/web/types/test/kvk/test-kvks-file.ts index 523bfaf54d..4cbb299a00 100644 --- a/common/web/types/test/kvk/test-kvks-file.ts +++ b/common/web/types/test/kvk/test-kvks-file.ts @@ -1,7 +1,7 @@ import * as fs from 'fs'; import 'mocha'; import { loadSchema, makePathToFixture } from '../helpers/index.js'; -import KvksFileReader, { KVKSParseError } from "../../src/kvk/kvks-file-reader.js"; +import KvksFileReader from "../../src/kvk/kvks-file-reader.js"; import KvksFileWriter from "../../src/kvk/kvks-file-writer.js"; import { verify_khmer_angkor } from './test-kvk-utils.js'; import { assert } from 'chai'; @@ -16,9 +16,9 @@ describe('kvks-file-reader', function() { assert.doesNotThrow(() => { reader.validate(kvks, loadSchema('kvks')); }); - const errors: KVKSParseError[] = []; - const vk = reader.transform(kvks, errors); - assert.isEmpty(errors); + const invalidVkeys: string[] = []; + const vk = reader.transform(kvks, invalidVkeys); + assert.isEmpty(invalidVkeys); verify_khmer_angkor(vk); }); }); @@ -30,9 +30,9 @@ describe('kvks-file-writer', function() { const reader = new KvksFileReader(); const kvksExpected = reader.read(input); - const errors: KVKSParseError[] = []; - const vk = reader.transform(kvksExpected, errors); - assert.isEmpty(errors); + const invalidVkeys: string[] = []; + const vk = reader.transform(kvksExpected, invalidVkeys); + assert.isEmpty(invalidVkeys); const writer = new KvksFileWriter(); const output = writer.write(vk); diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index 3c6df80e7e..4761fc5c3b 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -88,18 +88,7 @@ export class KmnCompiler { } public run(infile: string, outfile: string, options?: CompilerOptions): boolean { - if(!this.verifyInitialized()) { - /* c8 ignore next 2 */ - return false; - } - - options = {...baseOptions, ...options}; - (globalThis as any)[this.callbackID] = { - message: this.compilerMessageCallback, - loadFile: this.loadFileCallback - }; let result = this.runCompiler(infile, outfile, options); - delete (globalThis as any)[this.callbackID]; if(result) { if(result.kmx) { this.callbacks.fs.writeFileSync(result.kmx.filename, result.kmx.data); @@ -133,9 +122,8 @@ export class KmnCompiler { } if(bufferSize != data.byteLength) { - // TODO: consider chucking a wobbly because this is a bug #8885 /* c8 ignore next 2 */ - return 0; + throw new Error(`Second call, expected file size ${bufferSize} == ${data.byteLength}`); } this.Module.HEAP8.set(data, buffer); @@ -143,7 +131,19 @@ export class KmnCompiler { return 1; } - private runCompiler(infile: string, outfile: string, options: CompilerOptions): CompilerResult { + public runCompiler(infile: string, outfile: string, options: CompilerOptions): CompilerResult { + if(!this.verifyInitialized()) { + /* c8 ignore next 2 */ + return null; + } + + options = {...baseOptions, ...options}; + + (globalThis as any)[this.callbackID] = { + message: this.compilerMessageCallback, + loadFile: this.loadFileCallback + }; + let result: CompilerResult = {}; let wasm_interface = new this.Module.CompilerInterface(); let wasm_options = new this.Module.CompilerOptions(); @@ -183,6 +183,7 @@ export class KmnCompiler { } wasm_interface.delete(); wasm_options.delete(); + delete (globalThis as any)[this.callbackID]; } } @@ -190,22 +191,19 @@ export class KmnCompiler { // The compiler detected a .kvks file, which needs to be captured let reader = new KvksFileReader(); kvksFilename = this.callbacks.resolveFilename(kmnFilename, kvksFilename); - let kvks = reader.read(this.callbacks.loadFile(kvksFilename)); + let filename = this.callbacks.path.basename(kvksFilename); + let kvks = null; try { + kvks = reader.read(this.callbacks.loadFile(kvksFilename)); reader.validate(kvks, this.callbacks.loadSchema('kvks')); } catch(e) { - console.log(e); - // TODO: also unit test #8886 - // TODO: this.callbacks.reportMessage(CompilerMessages.Error_InvalidKvksFile({e})); + this.callbacks.reportMessage(CompilerMessages.Error_InvalidKvksFile({filename, e})); return null; } - let errors: any = []; //TODO: KVKSParseError[]; - let vk = reader.transform(kvks, errors); - if(!vk || errors.length) { - console.dir(errors); - // TODO: also unit test #8886 - // TODO: this.callbacks.reportMessage(CompilerMessages.Error_InvalidKvksFile({e})); - return null; + let invalidVkeys: string[] = []; + let vk = reader.transform(kvks, invalidVkeys); + for(let invalidVkey of invalidVkeys) { + this.callbacks.reportMessage(CompilerMessages.Warn_InvalidVkeyInKvksFile({filename, invalidVkey})); } let writer = new KvkFileWriter(); return { diff --git a/developer/src/kmc-kmn/src/compiler/messages.ts b/developer/src/kmc-kmn/src/compiler/messages.ts index 10578870d7..0769096e07 100644 --- a/developer/src/kmc-kmn/src/compiler/messages.ts +++ b/developer/src/kmc-kmn/src/compiler/messages.ts @@ -67,6 +67,14 @@ export class CompilerMessages { static Error_UnicodeSetSyntaxError = () => m(this.ERROR_UnicodeSetSyntaxError, `UnicodeSet had a Syntax Error while parsing`); static ERROR_UnicodeSetSyntaxError = SevError | 0x1007; + + static Error_InvalidKvksFile = (o:{filename: string, e: any}) => m(this.ERROR_InvalidKvksFile, + `Error encountered parsing ${o.filename}: ${o.e}`); + static ERROR_InvalidKvksFile = SevError | 0x1008; + + static Warn_InvalidVkeyInKvksFile = (o:{filename: string, invalidVkey: string}) => m(this.WARN_InvalidVkeyInKvksFile, + `Invalid virtual key ${o.invalidVkey} found in ${o.filename}`); + static WARN_InvalidVkeyInKvksFile = SevWarn | 0x1009; } export function mapErrorFromKmcmplib(line: number, code: number, msg: string): CompilerEvent { diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_invalid_kvks_file.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_invalid_kvks_file.kmn new file mode 100644 index 0000000000..f37d6397c5 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_invalid_kvks_file.kmn @@ -0,0 +1,12 @@ +c Description: Verifies that kmc throws an error with an invalid .kvks file + +store(&NAME) 'error_invalid_kvks_file' +store(&VERSION) '9.0' +store(&VISUALKEYBOARD) 'error_invalid_kvks_file.kvks' + +begin unicode > use(main) + +group(main) using keys + ++ [K_A] > 'a' +'a' + [K_B] > 'ខ្មែរ' diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_invalid_kvks_file.kvks b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_invalid_kvks_file.kvks new file mode 100644 index 0000000000..c681064f5b --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_invalid_kvks_file.kvks @@ -0,0 +1,9 @@ + + +
+ 10.0 + caps_lock_layer_3620 + + +
+
diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_invalid_vkey_in_kvks_file.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_invalid_vkey_in_kvks_file.kmn new file mode 100644 index 0000000000..18a88973e9 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_invalid_vkey_in_kvks_file.kmn @@ -0,0 +1,12 @@ +c Description: Verifies that kmc reports a warning with an invalid vkey in the kvks + +store(&NAME) 'warn_invalid_vkey_in_kvks_file' +store(&VERSION) '9.0' +store(&VISUALKEYBOARD) 'warn_invalid_vkey_in_kvks_file.kvks' + +begin unicode > use(main) + +group(main) using keys + ++ [K_A] > 'a' +'a' + [K_B] > 'ខ្មែរ' diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_invalid_vkey_in_kvks_file.kvks b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_invalid_vkey_in_kvks_file.kvks new file mode 100644 index 0000000000..ff441fd7c5 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_invalid_vkey_in_kvks_file.kvks @@ -0,0 +1,15 @@ + + +
+ 10.0 + caps_lock_layer_3620 + + +
+ + + + ឞ + + +
diff --git a/developer/src/kmc-kmn/test/helpers/index.ts b/developer/src/kmc-kmn/test/helpers/index.ts new file mode 100644 index 0000000000..8250dfd101 --- /dev/null +++ b/developer/src/kmc-kmn/test/helpers/index.ts @@ -0,0 +1,17 @@ +/** + * Helpers and utilities for the Mocha tests. + */ +import * as path from 'path'; +import { fileURLToPath } from 'url'; + +/** + * Builds a path to the fixture with the given path components. + * + * e.g., makePathToFixture('example.qaa.trivial') + * e.g., makePathToFixture('example.qaa.trivial', 'model.ts') + * + * @param components One or more path components. + */ + export function makePathToFixture(...components: string[]): string { + return fileURLToPath(new URL(path.join('..', '..', '..', 'test', 'fixtures', ...components), import.meta.url)); +} diff --git a/developer/src/kmc-kmn/test/test-messages.ts b/developer/src/kmc-kmn/test/test-messages.ts index 0dee53f121..dce0c2477d 100644 --- a/developer/src/kmc-kmn/test/test-messages.ts +++ b/developer/src/kmc-kmn/test/test-messages.ts @@ -1,9 +1,54 @@ import 'mocha'; +import { assert } from 'chai'; import { CompilerMessages } from '../src/compiler/messages.js'; -import { verifyCompilerMessagesObject } from '@keymanapp/developer-test-helpers'; +import { TestCompilerCallbacks, verifyCompilerMessagesObject } from '@keymanapp/developer-test-helpers'; +import { makePathToFixture } from './helpers/index.js'; +import { KmnCompiler } from '../src/main.js'; describe('CompilerMessages', function () { + const callbacks = new TestCompilerCallbacks(); + it('should have a valid CompilerMessages object', function() { return verifyCompilerMessagesObject(CompilerMessages); }); + + // + // Message tests + // + + async function testForMessage(context: Mocha.Context, fixture: string[], messageId?: number) { + context.timeout(10000); + + callbacks.clear(); + + const compiler = new KmnCompiler(); + assert(await compiler.init(callbacks)); + assert(compiler.verifyInitialized()); + + const kmnPath = makePathToFixture(...fixture); + const outfile = callbacks.path.basename(kmnPath, '.kmn') + '.kmx'; + + // Note: throwing away compile results (just to memory) + compiler.runCompiler(kmnPath, outfile, {saveDebug: true, shouldAddCompilerVersion: false}); + + if(messageId) { + assert.isTrue(callbacks.hasMessage(messageId), `messageId ${messageId.toString(16)} not generated, instead got: `+JSON.stringify(callbacks.messages,null,2)); + assert.lengthOf(callbacks.messages, 1); + } else { + assert.lengthOf(callbacks.messages, 0, `messages should be empty, but instead got: `+JSON.stringify(callbacks.messages,null,2)); + } + } + + // ERROR_InvalidKvksFile + + it('should generate ERROR_InvalidKvksFile if the kvks is not valid XML', async function() { + await testForMessage(this, ['invalid-keyboards', 'error_invalid_kvks_file.kmn'], CompilerMessages.ERROR_InvalidKvksFile); + }); + + // WARN_InvalidVkeyInKvksFile + + it('should generate WARN_InvalidVkeyInKvksFile if the kvks contains an invalid virtual key', async function() { + await testForMessage(this, ['invalid-keyboards', 'warn_invalid_vkey_in_kvks_file.kmn'], CompilerMessages.WARN_InvalidVkeyInKvksFile); + }); + }); diff --git a/developer/src/kmc-kmn/test/tsconfig.json b/developer/src/kmc-kmn/test/tsconfig.json index 115412f57f..f61df15d4a 100644 --- a/developer/src/kmc-kmn/test/tsconfig.json +++ b/developer/src/kmc-kmn/test/tsconfig.json @@ -13,7 +13,8 @@ }, }, "include": [ - "**/test-*.ts" + "**/test-*.ts", + "./helpers/index.ts" ], "references": [ { "path": "../../../../common/web/keyman-version/tsconfig.esm.json" }, -- GitLab From 717b1eea9889db65c12c27e33ed871a7c0e85f6f Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 1 Jun 2023 08:04:34 +1000 Subject: [PATCH 175/214] chore: Apply code review suggestion Co-authored-by: Eberhard Beilharz --- .../invalid-keyboards/warn_invalid_vkey_in_kvks_file.kvks | 1 - 1 file changed, 1 deletion(-) diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_invalid_vkey_in_kvks_file.kvks b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_invalid_vkey_in_kvks_file.kvks index ff441fd7c5..f7b247db34 100644 --- a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_invalid_vkey_in_kvks_file.kvks +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_invalid_vkey_in_kvks_file.kvks @@ -3,7 +3,6 @@
10.0 caps_lock_layer_3620 -
-- GitLab From c3ecae4e98ce2898949bb0d60e68b3802b4e37b0 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 1 Jun 2023 05:29:19 +0700 Subject: [PATCH 176/214] refactor(developer): rearrange kmcmplib interface source Fixes #8889. No code changes, just moves WASM interfaces into CompilerInterfacesWasm.cpp, and CompileKeyboardHandle is renamed to CompileKeyboardBuffer and moved into its own source file. --- .../kmcmplib/src/CompileKeyboardBuffer.cpp | 166 ++++++++++ .../src/kmcmplib/src/CompileKeyboardBuffer.h | 5 + .../src/kmcmplib/src/CompilerInterfaces.cpp | 285 +----------------- .../kmcmplib/src/CompilerInterfacesWasm.cpp | 117 +++++++ developer/src/kmcmplib/src/meson.build | 2 + 5 files changed, 292 insertions(+), 283 deletions(-) create mode 100644 developer/src/kmcmplib/src/CompileKeyboardBuffer.cpp create mode 100644 developer/src/kmcmplib/src/CompileKeyboardBuffer.h create mode 100644 developer/src/kmcmplib/src/CompilerInterfacesWasm.cpp diff --git a/developer/src/kmcmplib/src/CompileKeyboardBuffer.cpp b/developer/src/kmcmplib/src/CompileKeyboardBuffer.cpp new file mode 100644 index 0000000000..c932f68a4f --- /dev/null +++ b/developer/src/kmcmplib/src/CompileKeyboardBuffer.cpp @@ -0,0 +1,166 @@ +#include "pch.h" +#include +#include "kmcmplib.h" +#include "CheckFilenameConsistency.h" +#include "CheckNCapsConsistency.h" +#include "DeprecationChecks.h" +#include "versioning.h" +#include "CompileKeyboardBuffer.h" +#include "../../../../common/windows/cpp/include/keymanversion.h" + +bool CompileKeyboardBuffer(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk) +{ + PKMX_WCHAR str, p; + + KMX_DWORD msg; + + kmcmp::FMnemonicLayout = FALSE; + + if (!fk) { + AddCompileError(CERR_SomewhereIGotItWrong); + return FALSE; + } + + str = new KMX_WCHAR[LINESIZE]; + if (!str) { + AddCompileError(CERR_CannotAllocateMemory); + return FALSE; + } + + fk->KeyboardID = 0; + fk->version = 0; + fk->dpStoreArray = NULL; + fk->dpGroupArray = NULL; + fk->cxStoreArray = 0; + fk->cxGroupArray = 0; + fk->StartGroup[0] = fk->StartGroup[1] = -1; + fk->szName[0] = 0; + fk->szCopyright[0] = 0; + fk->dwFlags = KF_AUTOMATICVERSION; + fk->currentGroup = 0xFFFFFFFF; + fk->currentStore = 0; + fk->cxDeadKeyArray = 0; + fk->dpDeadKeyArray = NULL; + fk->cxVKDictionary = 0; // I3438 + fk->dpVKDictionary = NULL; // I3438 + fk->extra->kvksFilename = u""; +/* fk->szMessage[0] = 0; + fk->szLanguageName[0] = 0;*/ + fk->dwBitmapSize = 0; + fk->dwHotKey = 0; + + kmcmp::BeginLine[BEGIN_ANSI] = -1; + kmcmp::BeginLine[BEGIN_UNICODE] = -1; + kmcmp::BeginLine[BEGIN_NEWCONTEXT] = -1; + kmcmp::BeginLine[BEGIN_POSTKEYSTROKE] = -1; + + + /* Add a store for the Keyman 6.0 copyright information string */ + + if(kmcmp::FShouldAddCompilerVersion) { + u16sprintf(str,LINESIZE, L"Created with Keyman Developer version %d.%d.%d.%d", KEYMAN_VersionMajor, KEYMAN_VersionMinor, KEYMAN_VersionPatch, 0); + AddStore(fk, TSS_KEYMANCOPYRIGHT, str); + } + + /* Add a system store for the Keyman edition number */ + AddStore(fk, TSS_CUSTOMKEYMANEDITION, u"0"); + AddStore(fk, TSS_CUSTOMKEYMANEDITIONNAME, u"Keyman"); + + int offset = 0; + + // must preprocess for group and store names -> this isn't really necessary, but never mind! + while ((msg = ReadLine(infile, sz, offset, str, TRUE)) == CERR_None) + { + p = str; + switch (LineTokenType(&p)) + { + case T_VERSION: + *(p + 4) = 0; + if ((msg = AddStore(fk, TSS_VERSION, p)) != CERR_None) { + AddCompileError(msg); + return FALSE; + } + break; + + case T_GROUP: + if ((msg = ProcessGroupLine(fk, p)) != CERR_None) { + AddCompileError(msg); + return FALSE; + } + break; + + case T_STORE: + if ((msg = ProcessStoreLine(fk, p)) != CERR_None) { + AddCompileError(msg); + return FALSE; + } + break; + + default: + break; + } + } + + if (msg != CERR_EndOfFile) { + AddCompileError(msg); + return FALSE; + } + + offset = 0; + kmcmp::currentLine = 0; + + /* Reindex the list of codeconstants after stores added */ + + kmcmp::CodeConstants->reindex(); + + /* ReadLine will automatically skip over $Keyman lines, and parse wrapped lines */ + while ((msg = ReadLine(infile, sz, offset, str, FALSE)) == CERR_None) + { + msg = ParseLine(fk, str); + if (msg != CERR_None) { + AddCompileError(msg); + return FALSE; + } + } + + if (msg != CERR_EndOfFile) { + AddCompileError(msg); + return FALSE; + } + + ProcessGroupFinish(fk); + + if (kmcmp::FSaveDebug) kmcmp::RecordDeadkeyNames(fk); + + /* Add the compiler version as a system store */ + if ((msg = kmcmp::AddCompilerVersionStore(fk)) != CERR_None) { + AddCompileError(msg); + return FALSE; + } + + if ((msg = BuildVKDictionary(fk)) != CERR_None) { + AddCompileError(msg); + return FALSE; + } + + if ((msg = CheckFilenameConsistencyForCalls(fk)) != CERR_None) { + AddCompileError(msg); + return FALSE; + } + + delete str; + + if (!kmcmp::CheckKeyboardFinalVersion(fk)) { + return FALSE; + } + + /* Warn on inconsistent use of NCAPS */ + if (!kmcmp::FMnemonicLayout) { + CheckNCapsConsistency(fk); + } + + /* Flag presence of deprecated features */ + kmcmp::CheckForDeprecatedFeatures(fk); + + return TRUE; +} diff --git a/developer/src/kmcmplib/src/CompileKeyboardBuffer.h b/developer/src/kmcmplib/src/CompileKeyboardBuffer.h new file mode 100644 index 0000000000..78bac66653 --- /dev/null +++ b/developer/src/kmcmplib/src/CompileKeyboardBuffer.h @@ -0,0 +1,5 @@ +#pragma once + +#include "compfile.h" + +bool CompileKeyboardBuffer(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk); diff --git a/developer/src/kmcmplib/src/CompilerInterfaces.cpp b/developer/src/kmcmplib/src/CompilerInterfaces.cpp index 16b5b98654..fdfbdf1961 100644 --- a/developer/src/kmcmplib/src/CompilerInterfaces.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfaces.cpp @@ -1,134 +1,9 @@ #include "pch.h" - #include #include #include "kmcmplib.h" -#include "CheckFilenameConsistency.h" -#include "CheckNCapsConsistency.h" -#include "DeprecationChecks.h" -#include "versioning.h" #include "../../../../common/windows/cpp/include/ConvertUTF.h" -#include "../../../../common/windows/cpp/include/keymanversion.h" - -bool CompileKeyboardHandle(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk); - -#ifdef __EMSCRIPTEN__ -// TODO: move emscripten wrappers into their own .cpp. Also move CompileKeyboardHandle -// into its own .cpp, so CompilerInterfaces.cpp has only C public API functions listed. -// #8889 - -/* - WASM interface for compiler message callback -*/ -EM_JS(int, wasm_msgproc, (int line, int msgcode, const char* text, char* context), { - const proc = globalThis[UTF8ToString(context)].message; - if(!proc || typeof proc != 'function') { - console.log(`[${line}: ${msgcode}: ${UTF8ToString(text)}]`); - return 0; - } else { - return proc(line, msgcode, UTF8ToString(text)); - } -}); - -EM_JS(int, wasm_loadfileproc, (const char* filename, const char* baseFilename, void* buffer, int bufferSize, char* context), { - const proc = globalThis[UTF8ToString(context)].loadFile; - if(!proc || typeof proc != 'function') { - return 0; - } else { - if(buffer == 0) { - return proc(UTF8ToString(filename), UTF8ToString(baseFilename), 0, 0); - } else { - return proc(UTF8ToString(filename), UTF8ToString(baseFilename), buffer, bufferSize); - } - } -}); - -bool wasm_LoadFileProc(const char* filename, const char* baseFilename, void* buffer, int* bufferSize, void* context) { - char* msgProc = static_cast(context); - if(buffer == nullptr) { - *bufferSize = wasm_loadfileproc(filename, baseFilename, 0, 0, msgProc); - return *bufferSize != 0; - } else { - return wasm_loadfileproc(filename, baseFilename, buffer, *bufferSize, msgProc) == 1; - } -} - -int wasm_CompilerMessageProc(int line, uint32_t dwMsgCode, const char* szText, void* context) { - char* msgProc = static_cast(context); - return wasm_msgproc(line, dwMsgCode, szText, msgProc); -} - -struct WASM_COMPILER_INTERFACE { - std::string callbacksKey; // key of callbacks object on globalThis -}; - -struct WASM_COMPILER_RESULT { - bool result; - // Following are pointer offsets in heap + buffer size - int kmx; - int kmxSize; - // Following are compiler side-channel data, required for - // follow-on transform - std::string kvksFilename; - // TODO: additional data to be passed back -}; - -WASM_COMPILER_RESULT kmcmp_wasm_compile(std::string pszInfile, const KMCMP_COMPILER_OPTIONS options, const WASM_COMPILER_INTERFACE intf) { - WASM_COMPILER_RESULT r = {false}; - KMCMP_COMPILER_RESULT kr; - - r.kmx = 0; - r.kmxSize = 0; - r.kvksFilename = ""; - - r.result = kmcmp_CompileKeyboard( - pszInfile.c_str(), - options, - wasm_CompilerMessageProc, - wasm_LoadFileProc, - intf.callbacksKey.c_str(), - kr - ); - - if(r.result) { - // TODO: additional data as required by kmc_kmw - r.kmx = (int) kr.kmx; - r.kmxSize = (int) kr.kmxSize; - r.kvksFilename = kr.kvksFilename; - } - - return r; -} - -EMSCRIPTEN_BINDINGS(compiler_interface) { - - emscripten::class_("CompilerOptions") - .constructor<>() - .property("saveDebug", &KMCMP_COMPILER_OPTIONS::saveDebug) - .property("compilerWarningsAsErrors", &KMCMP_COMPILER_OPTIONS::compilerWarningsAsErrors) - .property("warnDeprecatedCode", &KMCMP_COMPILER_OPTIONS::warnDeprecatedCode) - .property("shouldAddCompilerVersion", &KMCMP_COMPILER_OPTIONS::shouldAddCompilerVersion) - .property("target", &KMCMP_COMPILER_OPTIONS::target) - ; - - emscripten::class_("CompilerInterface") - .constructor<>() - .property("callbacksKey", &WASM_COMPILER_INTERFACE::callbacksKey) - ; - - emscripten::class_("CompilerResult") - .constructor<>() - .property("result", &WASM_COMPILER_RESULT::result) - .property("kmx", &WASM_COMPILER_RESULT::kmx) - .property("kmxSize", &WASM_COMPILER_RESULT::kmxSize) - .property("kvksFilename", &WASM_COMPILER_RESULT::kvksFilename) - ; - - emscripten::function("kmcmp_compile", &kmcmp_wasm_compile); - emscripten::function("kmcmp_parseUnicodeSet", &kmcmp_parseUnicodeSet); -} - -#endif +#include "CompileKeyboardBuffer.h" EXTERN bool kmcmp_CompileKeyboard( const char* pszInfile, @@ -204,7 +79,7 @@ EXTERN bool kmcmp_CompileKeyboard( } kmcmp::CodeConstants = new kmcmp::NamedCodeConstants; - bool success = CompileKeyboardHandle(infile+offset, sz-offset, &fk); + bool success = CompileKeyboardBuffer(infile+offset, sz-offset, &fk); delete kmcmp::CodeConstants; delete[] infile; @@ -233,159 +108,3 @@ EXTERN bool kmcmp_CompileKeyboard( return TRUE; } -bool CompileKeyboardHandle(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk) -{ - PKMX_WCHAR str, p; - - KMX_DWORD msg; - - kmcmp::FMnemonicLayout = FALSE; - - if (!fk) { - AddCompileError(CERR_SomewhereIGotItWrong); - return FALSE; - } - - str = new KMX_WCHAR[LINESIZE]; - if (!str) { - AddCompileError(CERR_CannotAllocateMemory); - return FALSE; - } - - fk->KeyboardID = 0; - fk->version = 0; - fk->dpStoreArray = NULL; - fk->dpGroupArray = NULL; - fk->cxStoreArray = 0; - fk->cxGroupArray = 0; - fk->StartGroup[0] = fk->StartGroup[1] = -1; - fk->szName[0] = 0; - fk->szCopyright[0] = 0; - fk->dwFlags = KF_AUTOMATICVERSION; - fk->currentGroup = 0xFFFFFFFF; - fk->currentStore = 0; - fk->cxDeadKeyArray = 0; - fk->dpDeadKeyArray = NULL; - fk->cxVKDictionary = 0; // I3438 - fk->dpVKDictionary = NULL; // I3438 - fk->extra->kvksFilename = u""; -/* fk->szMessage[0] = 0; - fk->szLanguageName[0] = 0;*/ - fk->dwBitmapSize = 0; - fk->dwHotKey = 0; - - kmcmp::BeginLine[BEGIN_ANSI] = -1; - kmcmp::BeginLine[BEGIN_UNICODE] = -1; - kmcmp::BeginLine[BEGIN_NEWCONTEXT] = -1; - kmcmp::BeginLine[BEGIN_POSTKEYSTROKE] = -1; - - - /* Add a store for the Keyman 6.0 copyright information string */ - - if(kmcmp::FShouldAddCompilerVersion) { - u16sprintf(str,LINESIZE, L"Created with Keyman Developer version %d.%d.%d.%d", KEYMAN_VersionMajor, KEYMAN_VersionMinor, KEYMAN_VersionPatch, 0); - AddStore(fk, TSS_KEYMANCOPYRIGHT, str); - } - - /* Add a system store for the Keyman edition number */ - AddStore(fk, TSS_CUSTOMKEYMANEDITION, u"0"); - AddStore(fk, TSS_CUSTOMKEYMANEDITIONNAME, u"Keyman"); - - int offset = 0; - - // must preprocess for group and store names -> this isn't really necessary, but never mind! - while ((msg = ReadLine(infile, sz, offset, str, TRUE)) == CERR_None) - { - p = str; - switch (LineTokenType(&p)) - { - case T_VERSION: - *(p + 4) = 0; - if ((msg = AddStore(fk, TSS_VERSION, p)) != CERR_None) { - AddCompileError(msg); - return FALSE; - } - break; - - case T_GROUP: - if ((msg = ProcessGroupLine(fk, p)) != CERR_None) { - AddCompileError(msg); - return FALSE; - } - break; - - case T_STORE: - if ((msg = ProcessStoreLine(fk, p)) != CERR_None) { - AddCompileError(msg); - return FALSE; - } - break; - - default: - break; - } - } - - if (msg != CERR_EndOfFile) { - AddCompileError(msg); - return FALSE; - } - - offset = 0; - kmcmp::currentLine = 0; - - /* Reindex the list of codeconstants after stores added */ - - kmcmp::CodeConstants->reindex(); - - /* ReadLine will automatically skip over $Keyman lines, and parse wrapped lines */ - while ((msg = ReadLine(infile, sz, offset, str, FALSE)) == CERR_None) - { - msg = ParseLine(fk, str); - if (msg != CERR_None) { - AddCompileError(msg); - return FALSE; - } - } - - if (msg != CERR_EndOfFile) { - AddCompileError(msg); - return FALSE; - } - - ProcessGroupFinish(fk); - - if (kmcmp::FSaveDebug) kmcmp::RecordDeadkeyNames(fk); - - /* Add the compiler version as a system store */ - if ((msg = kmcmp::AddCompilerVersionStore(fk)) != CERR_None) { - AddCompileError(msg); - return FALSE; - } - - if ((msg = BuildVKDictionary(fk)) != CERR_None) { - AddCompileError(msg); - return FALSE; - } - - if ((msg = CheckFilenameConsistencyForCalls(fk)) != CERR_None) { - AddCompileError(msg); - return FALSE; - } - - delete str; - - if (!kmcmp::CheckKeyboardFinalVersion(fk)) { - return FALSE; - } - - /* Warn on inconsistent use of NCAPS */ - if (!kmcmp::FMnemonicLayout) { - CheckNCapsConsistency(fk); - } - - /* Flag presence of deprecated features */ - kmcmp::CheckForDeprecatedFeatures(fk); - - return TRUE; -} diff --git a/developer/src/kmcmplib/src/CompilerInterfacesWasm.cpp b/developer/src/kmcmplib/src/CompilerInterfacesWasm.cpp new file mode 100644 index 0000000000..a20cd9f1b4 --- /dev/null +++ b/developer/src/kmcmplib/src/CompilerInterfacesWasm.cpp @@ -0,0 +1,117 @@ +#include "pch.h" +#include + +#ifdef __EMSCRIPTEN__ + +/* + WASM interface for compiler message callback +*/ +EM_JS(int, wasm_msgproc, (int line, int msgcode, const char* text, char* context), { + const proc = globalThis[UTF8ToString(context)].message; + if(!proc || typeof proc != 'function') { + console.log(`[${line}: ${msgcode}: ${UTF8ToString(text)}]`); + return 0; + } else { + return proc(line, msgcode, UTF8ToString(text)); + } +}); + +EM_JS(int, wasm_loadfileproc, (const char* filename, const char* baseFilename, void* buffer, int bufferSize, char* context), { + const proc = globalThis[UTF8ToString(context)].loadFile; + if(!proc || typeof proc != 'function') { + return 0; + } else { + if(buffer == 0) { + return proc(UTF8ToString(filename), UTF8ToString(baseFilename), 0, 0); + } else { + return proc(UTF8ToString(filename), UTF8ToString(baseFilename), buffer, bufferSize); + } + } +}); + +bool wasm_LoadFileProc(const char* filename, const char* baseFilename, void* buffer, int* bufferSize, void* context) { + char* msgProc = static_cast(context); + if(buffer == nullptr) { + *bufferSize = wasm_loadfileproc(filename, baseFilename, 0, 0, msgProc); + return *bufferSize != 0; + } else { + return wasm_loadfileproc(filename, baseFilename, buffer, *bufferSize, msgProc) == 1; + } +} + +int wasm_CompilerMessageProc(int line, uint32_t dwMsgCode, const char* szText, void* context) { + char* msgProc = static_cast(context); + return wasm_msgproc(line, dwMsgCode, szText, msgProc); +} + +struct WASM_COMPILER_INTERFACE { + std::string callbacksKey; // key of callbacks object on globalThis +}; + +struct WASM_COMPILER_RESULT { + bool result; + // Following are pointer offsets in heap + buffer size + int kmx; + int kmxSize; + // Following are compiler side-channel data, required for + // follow-on transform + std::string kvksFilename; + // TODO: additional data to be passed back +}; + +WASM_COMPILER_RESULT kmcmp_wasm_compile(std::string pszInfile, const KMCMP_COMPILER_OPTIONS options, const WASM_COMPILER_INTERFACE intf) { + WASM_COMPILER_RESULT r = {false}; + KMCMP_COMPILER_RESULT kr; + + r.kmx = 0; + r.kmxSize = 0; + r.kvksFilename = ""; + + r.result = kmcmp_CompileKeyboard( + pszInfile.c_str(), + options, + wasm_CompilerMessageProc, + wasm_LoadFileProc, + intf.callbacksKey.c_str(), + kr + ); + + if(r.result) { + // TODO: additional data as required by kmc_kmw + r.kmx = (int) kr.kmx; + r.kmxSize = (int) kr.kmxSize; + r.kvksFilename = kr.kvksFilename; + } + + return r; +} + +EMSCRIPTEN_BINDINGS(compiler_interface) { + + emscripten::class_("CompilerOptions") + .constructor<>() + .property("saveDebug", &KMCMP_COMPILER_OPTIONS::saveDebug) + .property("compilerWarningsAsErrors", &KMCMP_COMPILER_OPTIONS::compilerWarningsAsErrors) + .property("warnDeprecatedCode", &KMCMP_COMPILER_OPTIONS::warnDeprecatedCode) + .property("shouldAddCompilerVersion", &KMCMP_COMPILER_OPTIONS::shouldAddCompilerVersion) + .property("target", &KMCMP_COMPILER_OPTIONS::target) + ; + + emscripten::class_("CompilerInterface") + .constructor<>() + .property("callbacksKey", &WASM_COMPILER_INTERFACE::callbacksKey) + ; + + emscripten::class_("CompilerResult") + .constructor<>() + .property("result", &WASM_COMPILER_RESULT::result) + .property("kmx", &WASM_COMPILER_RESULT::kmx) + .property("kmxSize", &WASM_COMPILER_RESULT::kmxSize) + .property("kvksFilename", &WASM_COMPILER_RESULT::kvksFilename) + ; + + emscripten::function("kmcmp_compile", &kmcmp_wasm_compile); + emscripten::function("kmcmp_parseUnicodeSet", &kmcmp_parseUnicodeSet); +} + +#endif diff --git a/developer/src/kmcmplib/src/meson.build b/developer/src/kmcmplib/src/meson.build index e697a0dced..2ca06929bc 100644 --- a/developer/src/kmcmplib/src/meson.build +++ b/developer/src/kmcmplib/src/meson.build @@ -37,8 +37,10 @@ icuuc_dep = icu.get_variable('icuuc_dep') lib = library('kmcmplib', 'CasedKeys.cpp', 'CharToKeyConversion.cpp', + 'CompileKeyboardBuffer.cpp', 'Compiler.cpp', 'CompilerInterfaces.cpp', + 'CompilerInterfacesWasm.cpp', 'DeprecationChecks.cpp', 'Edition.cpp', 'NamedCodeConstants.cpp', -- GitLab From c5bd7611908ad5dc93c1eb3abeae56e96c47395c Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 1 Jun 2023 07:07:00 +0700 Subject: [PATCH 177/214] chore(ios): replace fv cert --- oem/firstvoices/ios/exportAppStore.plist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/oem/firstvoices/ios/exportAppStore.plist b/oem/firstvoices/ios/exportAppStore.plist index 123af31a0c..c4ac972730 100644 --- a/oem/firstvoices/ios/exportAppStore.plist +++ b/oem/firstvoices/ios/exportAppStore.plist @@ -7,9 +7,9 @@ teamID D7TR486TEH signingCertificate - EFA9DE793B2A25F38270468AE62060CFF55CD634 + C4726D4C8BD4C2FE38A551B84CEDB8E4B3FD12D6 installerSigningCertificate - EFA9DE793B2A25F38270468AE62060CFF55CD634 + C4726D4C8BD4C2FE38A551B84CEDB8E4B3FD12D6 provisioningProfiles com.firstvoices.keyboards -- GitLab From c3458d040cfe8950db7253367d88f78f06b9ff18 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 1 Jun 2023 15:11:38 +0700 Subject: [PATCH 178/214] refactor(developer): move filename consistency check to kmc kmcmplib no longer has any filesystem access, so it cannot verify if a referenced filename in a source file has the same case as the actual filename on disk (a risk when moving projects between platforms). So I opted to move this to the `loadFile` callback in kmc, which is the only place where filesystem is actually accessed, and added corresponding unit test. Small additional fixes here: 1. Move from `Buffer` to `Uint8Array` in all kmc-* modules, so that we remove that barrier to running on web. 2. Use `callbacks.loadFile` instead of `callbacks.fs.readFileSync`, so that we can be sure to run the filename consistency check. 3. Fixed kps parser silently swallowing xml errors on load. 4. Added silent mode to NodeCompilerCallbacks so we could cleanly test the new filename consistency hint. 5. Noted a location where we still have NodeJS deps in kmc-ldml. --- common/web/types/src/kpj/kpj-file-reader.ts | 4 +- common/web/types/src/kvk/kvks-file-reader.ts | 4 +- .../ldml-keyboard/ldml-keyboard-xml-reader.ts | 11 +- .../web/types/src/util/compiler-interfaces.ts | 6 +- .../test/helpers/TestCompilerCallbacks.ts | 2 +- .../src/common/include/kmn_compiler_errors.h | 4 +- .../src/common/web/test-helpers/index.ts | 4 +- developer/src/kmc-kmn/test/test-messages.ts | 3 +- .../kmc-package/src/compiler/kmp-compiler.ts | 27 ++++- .../kmc/src/messages/NodeCompilerCallbacks.ts | 48 +++++++- developer/src/kmc/src/messages/messages.ts | 6 +- .../hint_filename_has_differing_case.kmn | 6 + developer/src/kmc/test/test-messages.ts | 71 +++++++++++ .../kmcmplib/src/CheckFilenameConsistency.cpp | 112 ------------------ .../kmcmplib/src/CheckFilenameConsistency.h | 9 -- developer/src/kmcmplib/src/CompMsg.cpp | 2 - .../kmcmplib/src/CompileKeyboardBuffer.cpp | 6 - developer/src/kmcmplib/src/Compiler.cpp | 14 --- .../src/kmcmplib/src/NamedCodeConstants.cpp | 5 - developer/src/kmcmplib/src/meson.build | 16 +-- 20 files changed, 174 insertions(+), 186 deletions(-) create mode 100644 developer/src/kmc/test/fixtures/invalid-keyboards/hint_filename_has_differing_case.kmn delete mode 100644 developer/src/kmcmplib/src/CheckFilenameConsistency.cpp delete mode 100644 developer/src/kmcmplib/src/CheckFilenameConsistency.h diff --git a/common/web/types/src/kpj/kpj-file-reader.ts b/common/web/types/src/kpj/kpj-file-reader.ts index 5f768c54f1..21e92c975b 100644 --- a/common/web/types/src/kpj/kpj-file-reader.ts +++ b/common/web/types/src/kpj/kpj-file-reader.ts @@ -27,8 +27,8 @@ export class KPJFileReader { return data as KPJFile; } - public validate(source: KPJFile, schemaBuffer: Buffer): void { - const schema = JSON.parse(schemaBuffer.toString('utf8')); + public validate(source: KPJFile, schemaBuffer: Uint8Array): void { + const schema = JSON.parse(new TextDecoder().decode(schemaBuffer)); const ajv = new Ajv(); if(!ajv.validate(schema, source)) { throw new Error(ajv.errorsText()); diff --git a/common/web/types/src/kvk/kvks-file-reader.ts b/common/web/types/src/kvk/kvks-file-reader.ts index 184c162210..13c6c8716c 100644 --- a/common/web/types/src/kvk/kvks-file-reader.ts +++ b/common/web/types/src/kvk/kvks-file-reader.ts @@ -68,8 +68,8 @@ export default class KVKSFileReader { } } - public validate(source: KVKSourceFile, schemaBuffer: Buffer): void { - const schema = JSON.parse(schemaBuffer.toString('utf8')); + public validate(source: KVKSourceFile, schemaBuffer: Uint8Array): void { + const schema = JSON.parse(new TextDecoder().decode(schemaBuffer)); const ajv = new Ajv(); if(!ajv.validate(schema, source)) { throw new Error(ajv.errorsText()); diff --git a/common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts b/common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts index 35d7f62795..bc2779ab8e 100644 --- a/common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts +++ b/common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts @@ -7,6 +7,7 @@ import { CompilerCallbacks } from '../util/compiler-interfaces.js'; import { constants } from '@keymanapp/ldml-keyboard-constants'; import { CommonTypesMessages } from '../util/common-events.js'; import { LDMLKeyboardTestDataXMLSourceFile, LKTTest, LKTTests } from './ldml-keyboard-testdata-xml.js'; +import { fileURLToPath } from 'url'; interface NameAndProps { '$'?: any; // content @@ -21,9 +22,9 @@ export default class LDMLKeyboardXMLSourceFileReader { this.callbacks = callbacks; } - readImportFile(version: string, subpath: string): Buffer { - // TODO-LDML: sanitize input string - let importPath = new URL(`../import/${version}/${subpath}`, import.meta.url); + readImportFile(version: string, subpath: string): Uint8Array { + // TODO-LDML: use this.callbacks.resolveFilename to get the actual path + let importPath = fileURLToPath(new URL(`../import/${version}/${subpath}`, import.meta.url)); return this.callbacks.loadFile(importPath); } @@ -201,8 +202,8 @@ export default class LDMLKeyboardXMLSourceFileReader { /** * @returns true if valid, false if invalid */ - public validate(source: LDMLKeyboardXMLSourceFile | LDMLKeyboardTestDataXMLSourceFile, schemaSource: Buffer): boolean { - const schema = JSON.parse(schemaSource.toString('utf8')); + public validate(source: LDMLKeyboardXMLSourceFile | LDMLKeyboardTestDataXMLSourceFile, schemaSource: Uint8Array): boolean { + const schema = JSON.parse(new TextDecoder().decode(schemaSource)); const ajv = new Ajv(); if(!ajv.validate(schema, source)) { for (let err of ajv.errors) { diff --git a/common/web/types/src/util/compiler-interfaces.ts b/common/web/types/src/util/compiler-interfaces.ts index 849e945321..d3932b7bfa 100644 --- a/common/web/types/src/util/compiler-interfaces.ts +++ b/common/web/types/src/util/compiler-interfaces.ts @@ -120,13 +120,11 @@ export interface CompilerFileSystemCallbacks { export interface CompilerCallbacks { /** * Attempt to load a file. Return falsy if not found. - * TODO: accept only string * TODO: never return falsy, just throw if not found? - * TODO: Buffer is Node-only. * @param baseFilename * @param filename */ - loadFile(filename: string | URL): Buffer; + loadFile(filename: string): Uint8Array; get path(): CompilerPathCallbacks; get fs(): CompilerFileSystemCallbacks; @@ -138,7 +136,7 @@ export interface CompilerCallbacks { */ resolveFilename(baseFilename: string, filename: string): string; - loadSchema(schema: CompilerSchema): Buffer; + loadSchema(schema: CompilerSchema): Uint8Array; reportMessage(event: CompilerEvent): void; debug(msg: string): void; }; diff --git a/common/web/types/test/helpers/TestCompilerCallbacks.ts b/common/web/types/test/helpers/TestCompilerCallbacks.ts index 596a731d58..8316264a77 100644 --- a/common/web/types/test/helpers/TestCompilerCallbacks.ts +++ b/common/web/types/test/helpers/TestCompilerCallbacks.ts @@ -42,7 +42,7 @@ export class TestCompilerCallbacks implements CompilerCallbacks { return resolveFilename(baseFilename, filename); } - loadFile(filename: string | URL): Buffer { + loadFile(filename: string): Uint8Array { // TODO: error management, does it belong here? try { return loadFile(filename); diff --git a/developer/src/common/include/kmn_compiler_errors.h b/developer/src/common/include/kmn_compiler_errors.h index 6cfae03fc9..31c5faf0c7 100644 --- a/developer/src/common/include/kmn_compiler_errors.h +++ b/developer/src/common/include/kmn_compiler_errors.h @@ -224,8 +224,8 @@ #define CWARN_KeyShouldIncludeNCaps 0x000020AD #define CHINT_UnreachableRule 0x000010AE -#define CHINT_FilenameHasDifferingCase 0x000010AF -#define CWARN_MissingFile 0x000020B0 +#define CHINT_FilenameHasDifferingCase 0x000010AF // only used in kmcmpdll +#define CWARN_MissingFile 0x000020B0 // only used in kmcmpdll #define CERR_BufferOverflow 0x000080C0 #define CERR_Break 0x000080C1 diff --git a/developer/src/common/web/test-helpers/index.ts b/developer/src/common/web/test-helpers/index.ts index 7f34107dc9..0a85287d3d 100644 --- a/developer/src/common/web/test-helpers/index.ts +++ b/developer/src/common/web/test-helpers/index.ts @@ -36,7 +36,7 @@ export class TestCompilerCallbacks implements CompilerCallbacks { /* CompilerCallbacks */ - loadFile(filename: string | URL): Buffer { + loadFile(filename: string): Uint8Array { try { return fs.readFileSync(filename); } catch(e) { @@ -77,7 +77,7 @@ export class TestCompilerCallbacks implements CompilerCallbacks { this.messages.push(event); } - loadSchema(schema: CompilerSchema): Buffer { + loadSchema(schema: CompilerSchema): Uint8Array { return fs.readFileSync(new URL(SCHEMA_BASE + schema + '.schema.json', import.meta.url)); } diff --git a/developer/src/kmc-kmn/test/test-messages.ts b/developer/src/kmc-kmn/test/test-messages.ts index dce0c2477d..4d724daaf5 100644 --- a/developer/src/kmc-kmn/test/test-messages.ts +++ b/developer/src/kmc-kmn/test/test-messages.ts @@ -1,4 +1,5 @@ import 'mocha'; +import path from 'path'; import { assert } from 'chai'; import { CompilerMessages } from '../src/compiler/messages.js'; import { TestCompilerCallbacks, verifyCompilerMessagesObject } from '@keymanapp/developer-test-helpers'; @@ -26,7 +27,7 @@ describe('CompilerMessages', function () { assert(compiler.verifyInitialized()); const kmnPath = makePathToFixture(...fixture); - const outfile = callbacks.path.basename(kmnPath, '.kmn') + '.kmx'; + const outfile = path.basename(kmnPath, '.kmn') + '.kmx'; // Note: throwing away compile results (just to memory) compiler.runCompiler(kmnPath, outfile, {saveDebug: true, shouldAddCompilerVersion: false}); diff --git a/developer/src/kmc-package/src/compiler/kmp-compiler.ts b/developer/src/kmc-package/src/compiler/kmp-compiler.ts index b660641df9..198a1ef2de 100644 --- a/developer/src/kmc-package/src/compiler/kmp-compiler.ts +++ b/developer/src/kmc-package/src/compiler/kmp-compiler.ts @@ -16,7 +16,12 @@ export class KmpCompiler { public transformKpsToKmpObject(kpsFilename: string): KmpJsonFile.KmpJsonFile { // Load the KPS data from XML as JS structured data. - const data = this.callbacks.fs.readFileSync(kpsFilename, 'utf-8'); + const buffer = this.callbacks.loadFile(kpsFilename); + if(!buffer) { + this.callbacks.reportMessage(CompilerMessages.Error_FileDoesNotExist({filename: kpsFilename})); + return null; + } + const data = new TextDecoder().decode(buffer); const kpsPackage = (() => { let a: KpsFile.KpsPackage; @@ -24,7 +29,8 @@ export class KmpCompiler { tagNameProcessors: [xml2js.processors.firstCharLowerCase], explicitArray: false }); - parser.parseString(data, (e: unknown, r: unknown) => { a = r as KpsFile.KpsPackage }); + // TODO: add unit test for xml errors parsing .kps file + parser.parseString(data, (e: unknown, r: unknown) => { if(e) throw e; a = r as KpsFile.KpsPackage }); return a; })(); @@ -284,9 +290,20 @@ export class KmpCompiler { * we want that to remain the responsibility of the keyboard compiler, so we'll warn the * few users who are still doing this */ - private warnIfKvkFileIsNotBinary(filename: string, data: Buffer) { - // TODO: Buffer is not available on web - if(filename.match(/\.kvk$/) && data.compare(Buffer.from(KvkFile.KVK_HEADER_IDENTIFIER_BYTES), 0, 3, 0, 3) != 0) { + private warnIfKvkFileIsNotBinary(filename: string, data: Uint8Array) { + if(!filename.match(/\.kvk$/)) { + return; + } + + if(data.byteLength < 4) { + // TODO: Not a valid .kvk file; should we be reporting this? + return; + } + + if(data[0] != KvkFile.KVK_HEADER_IDENTIFIER_BYTES[0] || + data[1] != KvkFile.KVK_HEADER_IDENTIFIER_BYTES[1] || + data[2] != KvkFile.KVK_HEADER_IDENTIFIER_BYTES[2] || + data[3] != KvkFile.KVK_HEADER_IDENTIFIER_BYTES[3]) { this.callbacks.reportMessage(CompilerMessages.Warn_FileIsNotABinaryKvkFile({filename: filename})); } } diff --git a/developer/src/kmc/src/messages/NodeCompilerCallbacks.ts b/developer/src/kmc/src/messages/NodeCompilerCallbacks.ts index ceae18c4c5..f8232cde5f 100644 --- a/developer/src/kmc/src/messages/NodeCompilerCallbacks.ts +++ b/developer/src/kmc/src/messages/NodeCompilerCallbacks.ts @@ -1,14 +1,52 @@ import * as fs from 'fs'; import * as path from 'path'; import { CompilerCallbacks, CompilerSchema, CompilerEvent, compilerErrorSeverityName, CompilerPathCallbacks, CompilerFileSystemCallbacks } from '@keymanapp/common-types'; +import { InfrastructureMessages } from './messages.js'; /** * Concrete implementation for CLI use */ +// TODO: Make a common class for all the CompilerCallbacks implementations + export class NodeCompilerCallbacks implements CompilerCallbacks { - // TODO: REMOVE! - loadFile(filename: string | URL): Buffer { + /* NodeCompilerCallbacks */ + + messages: CompilerEvent[] = []; + silent: boolean; + + constructor(silent?: boolean) { + this.silent = !!silent; + } + + clear() { + this.messages = []; + } + + hasMessage(code: number): boolean { + return this.messages.find((item) => item.code == code) === undefined ? false : true; + } + + private verifyFilenameConsistency(originalFilename: string): void { + if(fs.existsSync(originalFilename)) { + // Note, we only check this if the file exists, because + // if it is not found, that will be returned as an error + // from loadFile anyway. + const filename = fs.realpathSync(originalFilename); + const nativeFilename = fs.realpathSync.native(filename); + if(filename != nativeFilename) { + this.reportMessage(InfrastructureMessages.Hint_FilenameHasDifferingCase({ + reference: originalFilename, + filename: nativeFilename + })); + } + } + } + + /* CompilerCallbacks */ + + loadFile(filename: string): Uint8Array { + this.verifyFilenameConsistency(filename); try { return fs.readFileSync(filename); } catch (e) { @@ -29,6 +67,10 @@ export class NodeCompilerCallbacks implements CompilerCallbacks { } reportMessage(event: CompilerEvent): void { + this.messages.push(event); + if(this.silent) { + return; + } const code = event.code.toString(16); if(event.line) { console.log(`${compilerErrorSeverityName(event.code)} ${code} [${event.line}]: ${event.message}`); @@ -41,7 +83,7 @@ export class NodeCompilerCallbacks implements CompilerCallbacks { console.debug(msg); } - loadSchema(schema: CompilerSchema) { + loadSchema(schema: CompilerSchema): Uint8Array { let schemaPath = new URL('../util/' + schema + '.schema.json', import.meta.url); return fs.readFileSync(schemaPath); } diff --git a/developer/src/kmc/src/messages/messages.ts b/developer/src/kmc/src/messages/messages.ts index 1f1761e715..358a59406b 100644 --- a/developer/src/kmc/src/messages/messages.ts +++ b/developer/src/kmc/src/messages/messages.ts @@ -2,7 +2,7 @@ import { CompilerErrorNamespace, CompilerErrorSeverity, CompilerMessageSpec as m const Namespace = CompilerErrorNamespace.Infrastructure; const SevInfo = CompilerErrorSeverity.Info | Namespace; -// const SevHint = CompilerErrorSeverity.Hint | Namespace; +const SevHint = CompilerErrorSeverity.Hint | Namespace; // const SevWarn = CompilerErrorSeverity.Warn | Namespace; const SevError = CompilerErrorSeverity.Error | Namespace; const SevFatal = CompilerErrorSeverity.Fatal | Namespace; @@ -39,5 +39,9 @@ export class InfrastructureMessages { static Error_InvalidProjectFile = (o:{message:string}) => m(this.ERROR_InvalidProjectFile, `Project file is not valid: ${o.message}`); static ERROR_InvalidProjectFile = SevError | 0x0008; + + static Hint_FilenameHasDifferingCase = (o:{reference:string, filename:string}) => m(this.HINT_FilenameHasDifferingCase, + `File ${o.filename} differs in case from reference ${o.reference}; this will fail on platforms with case-sensitive filesystems.`); + static HINT_FilenameHasDifferingCase = SevHint | 0x0009; } diff --git a/developer/src/kmc/test/fixtures/invalid-keyboards/hint_filename_has_differing_case.kmn b/developer/src/kmc/test/fixtures/invalid-keyboards/hint_filename_has_differing_case.kmn new file mode 100644 index 0000000000..5792016e10 --- /dev/null +++ b/developer/src/kmc/test/fixtures/invalid-keyboards/hint_filename_has_differing_case.kmn @@ -0,0 +1,6 @@ +store(&name) 'hint_filename_has_differing_case' +store(&version) '7.0' + +begin unicode > use(main) + +group(main) using keys diff --git a/developer/src/kmc/test/test-messages.ts b/developer/src/kmc/test/test-messages.ts index 7b591ad72d..045718075d 100644 --- a/developer/src/kmc/test/test-messages.ts +++ b/developer/src/kmc/test/test-messages.ts @@ -1,9 +1,80 @@ import 'mocha'; +import { assert } from 'chai'; import { InfrastructureMessages } from '../src/messages/messages.js'; import { verifyCompilerMessagesObject } from '@keymanapp/developer-test-helpers'; +import { makePathToFixture } from './helpers/index.js'; +import { NodeCompilerCallbacks } from '../src/messages/NodeCompilerCallbacks.js'; describe('InfrastructureMessages', function () { it('should have a valid InfrastructureMessages object', function() { return verifyCompilerMessagesObject(InfrastructureMessages); }); + + // + // Message tests + // + + /* + TODO: + + let callbacks = new TestCompilerCallbacks(); + + async function testForMessage(context: Mocha.Context, fixture: string[], messageId?: number) { + context.timeout(10000); + + callbacks.clear(); + + const builder = new BuildKmnKeyboard(); + const path = makePathToFixture(...fixture); + let result = await builder.build(path, callbacks, { + compilerVersion: false, + compilerWarningsAsErrors: true, + debug: false, + warnDeprecatedCode: true, + }); + + if(messageId) { + assert.isTrue(callbacks.hasMessage(messageId), `messageId ${messageId.toString(16)} not generated, instead got: `+JSON.stringify(callbacks.messages,null,2)); + assert.lengthOf(callbacks.messages, 1); + } else { + assert.lengthOf(callbacks.messages, 0, `messages should be empty, but instead got: `+JSON.stringify(callbacks.messages,null,2)); + assert.isTrue(result); + } + } + + // ERROR_FileDoesNotExist + + it('should generate ERROR_FileDoesNotExist if a file does not exist', async function() { + await testForMessage(this, ['invalid-keyboards', 'error_file_does_not_exist.kmn'], CompilerMessages.ERROR_FileDoesNotExist); + }); + + // ERROR_FileTypeNotRecognized + + it('should generate ERROR_FileTypeNotRecognized if a file is not a recognized type', async function() { + await testForMessage(this, ['invalid-keyboards', 'error_file_type_not_recognized.xxx'], CompilerMessages.ERROR_FileTypeNotRecognized); + }); + + // ERROR_OutFileNotValidForProjects + + it('should generate ERROR_OutFileNotValidForProjects if an output file is specified for a project build', async function() { + await testForMessage(this, ['invalid-keyboards', 'error_out_file_not_valid_for_projects.kpj'], CompilerMessages.ERROR_OutFileNotValidForProjects); + }); + + // ERROR_InvalidProjectFile + + it('should generate ERROR_InvalidProjectFile if a project file is invalid', async function() { + await testForMessage(this, ['invalid-keyboards', 'error_invalid_project_file.kpj'], CompilerMessages.ERROR_InvalidProjectFile); + }); + */ + + // HINT_FilenameHasDifferingCase + + it('should generate HINT_FilenameHasDifferingCase if a referenced file has differing case', async function() { + // This message is generated by NodeCompilerCallbacks, because that's where the filesystem is visible, + // so we can't use our usual testForMessage pattern. + const ncb = new NodeCompilerCallbacks(true); + ncb.loadFile(makePathToFixture('invalid-keyboards', 'Hint_Filename_Has_Differing_Case.kmn')); + assert.isTrue(ncb.hasMessage(InfrastructureMessages.HINT_FilenameHasDifferingCase), + `HINT_FilenameHasDifferingCase not generated, instead got: `+JSON.stringify(ncb.messages,null,2)); + }); }); diff --git a/developer/src/kmcmplib/src/CheckFilenameConsistency.cpp b/developer/src/kmcmplib/src/CheckFilenameConsistency.cpp deleted file mode 100644 index 6d113d116b..0000000000 --- a/developer/src/kmcmplib/src/CheckFilenameConsistency.cpp +++ /dev/null @@ -1,112 +0,0 @@ - -#define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING 1 -#include "pch.h" -#include "compfile.h" -#include -#include "kmcmplib.h" -#include -#include "CheckFilenameConsistency.h" -#include "kmx_u16.h" - -#ifdef _MSC_VER -#include -#endif - - - -KMX_DWORD CheckFilenameConsistency( KMX_CHAR const * Filename, bool ReportMissingFile) { - PKMX_WCHAR WFilename = strtowstr(( KMX_CHAR *)Filename); - KMX_DWORD const result = CheckFilenameConsistency(WFilename, ReportMissingFile); - delete WFilename; - return result; -} - -KMX_DWORD CheckFilenameConsistency(KMX_WCHAR const * Filename, bool ReportMissingFile) { - // TODO: we no longer have filesystem access here. We could move this check to - // kmc itself, and make it consistent across all compilers that use the same - // loader callback -- see #8883 - return CERR_None; - -#if 0 - // not ready yet: needs more attention-> common includes for non-Windows platforms - KMX_WCHAR Name[260]; // TODO: fixed buffer sizes bad - - - if (IsRelativePath(Filename)) { - PKMX_WCHAR WCompileDir = strtowstr(kmcmp::CompileDir); - u16ncpy(Name, WCompileDir, _countof(Name)); // I3481 - u16ncat(Name, Filename, _countof(Name)); // I3481 - delete[] WCompileDir; - } else { - u16ncpy(Name, Filename, _countof(Name)); // I3481 - } - -#ifndef _MSC_VER - // Filename consistency only needs to be checked on Windows, because other - // platforms are going to fail if the filename is inconsistent anyway! - if(!kmcmp_FileExists(Name)) { - if (ReportMissingFile) { - u16cpy(ErrExtraW, u"referenced file '"); - u16ncat(ErrExtraW, Filename, 256); - u16ncat(ErrExtraW, u"'", 256); - strcpy(ErrExtraLIB, string_from_u16string(ErrExtraW).c_str()); - AddWarning(CWARN_MissingFile); - } - return CERR_None; - } - return CERR_None; -#else - _wfinddata_t fi; - intptr_t n; - if ((n = _wfindfirst((const wchar_t*) Name, &fi)) == -1) { - if (ReportMissingFile) { - sprintf(ErrExtraLIB, "referenced file '%ls'", (wchar_t*) Filename); - AddWarning(CWARN_MissingFile); - } - return CERR_None; - } - - _findclose(n); - - KMX_WCHAR FName[_MAX_FNAME], Ext[_MAX_EXT]; - wchar_t WChName[_MAX_PATH]; - _wsplitpath_s((const wchar_t*)Filename, nullptr, 0, nullptr, 0, (wchar_t*) FName, _MAX_FNAME, (wchar_t*) Ext, _MAX_EXT); - _wmakepath_s(WChName, _MAX_PATH, nullptr, nullptr, (const wchar_t*) FName, (const wchar_t*) Ext); - if (wcscmp(WChName, fi.name) != 0) { - sprintf(ErrExtraLIB, "reference '%ls' does not match actual filename '%ls'", WChName, fi.name); - - AddWarning(CHINT_FilenameHasDifferingCase); - - } -#endif - - return CERR_None; -#endif -} - -KMX_DWORD CheckFilenameConsistencyForCalls(PFILE_KEYBOARD fk) { - // call() statements depend on a fairly ugly hack for js, - // where store(DllFunction) "my.dll:func" will look for a - // file called function.call_js. ( or should this be func.call_js ? ) - // This is ripe for rewrite! - // But let's check what we have anyway - - PFILE_STORE sp; - KMX_DWORD i, msg; - for (i = 0, sp = fk->dpStoreArray; i < fk->cxStoreArray; i++, sp++) { - if (!sp->fIsCall) continue; - - const std::u16string callsite(sp->dpString); - const auto colon = callsite.find(':'); - if (colon == std::u16string::npos) continue; - - auto func1 = callsite.substr(colon + 1); - std::u16string str_js(u".call_js"); - std::u16string func = func1+ str_js; - - if ((msg = CheckFilenameConsistency(func.c_str(), FALSE)) != CERR_None) { - return msg; - } - } - return CERR_None; -} diff --git a/developer/src/kmcmplib/src/CheckFilenameConsistency.h b/developer/src/kmcmplib/src/CheckFilenameConsistency.h deleted file mode 100644 index eba8f2d8bf..0000000000 --- a/developer/src/kmcmplib/src/CheckFilenameConsistency.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "compfile.h" -#include "kmcmplib.h" - -KMX_DWORD CheckFilenameConsistencyForCalls(PFILE_KEYBOARD fk); -KMX_DWORD CheckFilenameConsistency(KMX_CHAR const * Filename, bool ReportMissingFile); -KMX_DWORD CheckFilenameConsistency(KMX_WCHAR const * Filename, bool ReportMissingFile); - diff --git a/developer/src/kmcmplib/src/CompMsg.cpp b/developer/src/kmcmplib/src/CompMsg.cpp index 2fa0d68322..dd41336a0e 100644 --- a/developer/src/kmcmplib/src/CompMsg.cpp +++ b/developer/src/kmcmplib/src/CompMsg.cpp @@ -111,7 +111,6 @@ const struct CompilerError CompilerErrors[] = { { CERR_DuplicateStore , "A store with this name has already been defined."}, { CERR_RepeatedBegin , "Begin has already been set"}, - { CHINT_FilenameHasDifferingCase , "Casing differences may fail on some platforms: "}, { CHINT_UnreachableRule , "This rule will never be matched as another rule takes precedence"}, { CWARN_TooManyWarnings , "Too many warnings or errors"}, @@ -142,7 +141,6 @@ const struct CompilerError CompilerErrors[] = { { CWARN_NulNotFirstStatementInContext , "nul must be the first statement in the context"}, { CWARN_IfShouldBeAtStartOfContext , "if, platform and baselayout should be at start of context (after nul, if present)"}, { CWARN_KeyShouldIncludeNCaps , "Other rules which reference this key include CAPS or NCAPS modifiers, so this rule must include NCAPS modifier to avoid inconsistent matches"}, - { CWARN_MissingFile , "The referenced file could not be found: "}, { 0, nullptr } }; diff --git a/developer/src/kmcmplib/src/CompileKeyboardBuffer.cpp b/developer/src/kmcmplib/src/CompileKeyboardBuffer.cpp index c932f68a4f..e90938f18a 100644 --- a/developer/src/kmcmplib/src/CompileKeyboardBuffer.cpp +++ b/developer/src/kmcmplib/src/CompileKeyboardBuffer.cpp @@ -1,7 +1,6 @@ #include "pch.h" #include #include "kmcmplib.h" -#include "CheckFilenameConsistency.h" #include "CheckNCapsConsistency.h" #include "DeprecationChecks.h" #include "versioning.h" @@ -143,11 +142,6 @@ bool CompileKeyboardBuffer(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk) return FALSE; } - if ((msg = CheckFilenameConsistencyForCalls(fk)) != CERR_None) { - AddCompileError(msg); - return FALSE; - } - delete str; if (!kmcmp::CheckKeyboardFinalVersion(fk)) { diff --git a/developer/src/kmcmplib/src/Compiler.cpp b/developer/src/kmcmplib/src/Compiler.cpp index 49484b1acc..b862cb7d9f 100644 --- a/developer/src/kmcmplib/src/Compiler.cpp +++ b/developer/src/kmcmplib/src/Compiler.cpp @@ -97,7 +97,6 @@ #include #include -#include "CheckFilenameConsistency.h" #include "UnreachableRules.h" #include "CheckForDuplicates.h" #include "kmx_u16.h" @@ -1045,10 +1044,6 @@ KMX_DWORD ProcessSystemStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, PFILE_STORE delete[] sp->dpString; sp->dpString = q; - - if ((msg = CheckFilenameConsistency( (sp->dpString), FALSE)) != CERR_None) { - return msg; - } } break; case TSS_KMW_RTL: @@ -1059,16 +1054,10 @@ KMX_DWORD ProcessSystemStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, PFILE_STORE case TSS_KMW_HELPFILE: case TSS_KMW_EMBEDJS: VERIFY_KEYBOARD_VERSION(fk, VERSION_70, CERR_70FeatureOnly); - if ((msg = CheckFilenameConsistency(sp->dpString, FALSE)) != CERR_None) { - return msg; - } break; case TSS_KMW_EMBEDCSS: VERIFY_KEYBOARD_VERSION(fk, VERSION_90, CERR_90FeatureOnlyEmbedCSS); - if ((msg = CheckFilenameConsistency(sp->dpString, FALSE)) != CERR_None) { - return msg; - } break; case TSS_TARGETS: // I4504 @@ -1118,9 +1107,6 @@ KMX_DWORD ProcessSystemStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, PFILE_STORE case TSS_LAYOUTFILE: // I3483 VERIFY_KEYBOARD_VERSION(fk, VERSION_90, CERR_90FeatureOnlyLayoutFile); // I4140 - if ((msg = CheckFilenameConsistency(sp->dpString, FALSE)) != CERR_None) { - return msg; - } // Used by KMW compiler break; diff --git a/developer/src/kmcmplib/src/NamedCodeConstants.cpp b/developer/src/kmcmplib/src/NamedCodeConstants.cpp index 30091b7cb8..a8af8fa783 100644 --- a/developer/src/kmcmplib/src/NamedCodeConstants.cpp +++ b/developer/src/kmcmplib/src/NamedCodeConstants.cpp @@ -24,7 +24,6 @@ #include "pch.h" #include #include "NamedCodeConstants.h" -#include "CheckFilenameConsistency.h" #include #include "kmcompx.h" @@ -117,10 +116,6 @@ char *kmc_strupr(char *s) { KMX_BOOL NamedCodeConstants::LoadFile(PFILE_KEYBOARD fk, const KMX_WCHAR *filename) { const int str_size = 256; - if (CheckFilenameConsistency(filename, FALSE) != 0) { - return FALSE; - } - auto szNameUtf8 = string_from_u16string(filename); int FileSize; diff --git a/developer/src/kmcmplib/src/meson.build b/developer/src/kmcmplib/src/meson.build index 2ca06929bc..c6ed2b84b0 100644 --- a/developer/src/kmcmplib/src/meson.build +++ b/developer/src/kmcmplib/src/meson.build @@ -37,29 +37,25 @@ icuuc_dep = icu.get_variable('icuuc_dep') lib = library('kmcmplib', 'CasedKeys.cpp', 'CharToKeyConversion.cpp', + 'CheckForDuplicates.cpp', + 'CheckNCapsConsistency.cpp', 'CompileKeyboardBuffer.cpp', 'Compiler.cpp', 'CompilerInterfaces.cpp', 'CompilerInterfacesWasm.cpp', + 'CompMsg.cpp', 'DeprecationChecks.cpp', 'Edition.cpp', + 'kmx_u16.cpp', 'NamedCodeConstants.cpp', + 'UnreachableRules.cpp', + 'uset-api.cpp', 'versioning.cpp', 'virtualcharkeys.cpp', 'xstring.cpp', - 'CharToKeyConversion.cpp', - 'CheckFilenameConsistency.cpp', - 'CheckForDuplicates.cpp', - 'CheckNCapsConsistency.cpp', - 'UnreachableRules.cpp', - 'kmx_u16.cpp', - 'CompMsg.cpp', - 'uset-api.cpp', - '../../../../common/windows/cpp/src/ConvertUTF.c', '../../../../common/windows/cpp/src/crc32.cpp', '../../../../common/windows/cpp/src/vkeys.cpp', - 'xstring.cpp', version_res, cpp_args: defns + warns + flags, -- GitLab From 7301281247aaa42160ed7b17d363ce851fd9baf4 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 1 Jun 2023 15:31:31 +0700 Subject: [PATCH 179/214] chore(developer): loadFile callback error check and optimization Fixes #8885. Adds some optimization and error checking to the loadFile callback in kmc-kmn. Also handles case of zero-byte bitmap file so we won't crash on it. --- .../src/kmc-kmn/src/compiler/compiler.ts | 22 ++++++++++++++----- developer/src/kmcmplib/src/Compiler.cpp | 6 +++++ .../kmcmplib/src/CompilerInterfacesWasm.cpp | 2 +- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index 4761fc5c3b..9962ea6abd 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -108,12 +108,24 @@ export class KmnCompiler { return 1; } + private cachedFile: {filename: string; data: Uint8Array} = { + filename: null, + data: null + }; + private loadFileCallback = (filename: string, baseFilename: string, buffer: number, bufferSize: number): number => { - // TODO: we can optimize this in future by avoiding loading the file twice #8885 let resolvedFilename = this.callbacks.resolveFilename(baseFilename, filename); - let data = this.callbacks.loadFile(resolvedFilename); - if(!data) { - return 0; + let data: Uint8Array; + if(this.cachedFile.filename == resolvedFilename) { + data = this.cachedFile.data; + } + else { + data = this.callbacks.loadFile(resolvedFilename); + if(!data) { + return -1; + } + this.cachedFile.filename = resolvedFilename; + this.cachedFile.data = data; } if(buffer == 0) { @@ -123,7 +135,7 @@ export class KmnCompiler { if(bufferSize != data.byteLength) { /* c8 ignore next 2 */ - throw new Error(`Second call, expected file size ${bufferSize} == ${data.byteLength}`); + throw new Error(`loadFileCallback: second call, expected file size ${bufferSize} == ${data.byteLength}`); } this.Module.HEAP8.set(data, buffer); diff --git a/developer/src/kmcmplib/src/Compiler.cpp b/developer/src/kmcmplib/src/Compiler.cpp index b862cb7d9f..e5d5f94cbc 100644 --- a/developer/src/kmcmplib/src/Compiler.cpp +++ b/developer/src/kmcmplib/src/Compiler.cpp @@ -3233,6 +3233,12 @@ KMX_DWORD ImportBitmapFile(PFILE_KEYBOARD fk, PKMX_WCHAR szName, PKMX_DWORD File } } + if(*FileSize < 2) { + // Zero-byte file is invalid; 2 byte file is too, but we only really care + // about the prolog at this point so we don't overrun our buffer + return CERR_CannotReadBitmapFile; + } + *Buf = new KMX_BYTE[*FileSize]; if(!loadfileproc(szNameUtf8.c_str(), fk->extra->kmnFilename.c_str(), *Buf, (int*) FileSize, msgprocContext)) { delete[] *Buf; diff --git a/developer/src/kmcmplib/src/CompilerInterfacesWasm.cpp b/developer/src/kmcmplib/src/CompilerInterfacesWasm.cpp index a20cd9f1b4..0aab9ba51d 100644 --- a/developer/src/kmcmplib/src/CompilerInterfacesWasm.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfacesWasm.cpp @@ -33,7 +33,7 @@ bool wasm_LoadFileProc(const char* filename, const char* baseFilename, void* buf char* msgProc = static_cast(context); if(buffer == nullptr) { *bufferSize = wasm_loadfileproc(filename, baseFilename, 0, 0, msgProc); - return *bufferSize != 0; + return *bufferSize != -1; } else { return wasm_loadfileproc(filename, baseFilename, buffer, *bufferSize, msgProc) == 1; } -- GitLab From d615659d5ef71236005cdcee94f342bec4bd6d39 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Thu, 1 Jun 2023 19:14:17 +0200 Subject: [PATCH 180/214] chore(linux): Address code review comments --- linux/keyman-config/build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux/keyman-config/build.sh b/linux/keyman-config/build.sh index 7f63eaff1e..1cb603f091 100755 --- a/linux/keyman-config/build.sh +++ b/linux/keyman-config/build.sh @@ -34,14 +34,14 @@ build_man_pages() { TEMP_DATA_DIR=$(mktemp -d) SCHEMA_DIR=$TEMP_DATA_DIR/glib-2.0/schemas export XDG_DATA_DIRS=$TEMP_DATA_DIR:${XDG_DATA_DIRS-} - export GSETTINGS_SCHEMA_DIR=${SCHEMA_DIR} + export GSETTINGS_SCHEMA_DIR="${SCHEMA_DIR}" mkdir -p "$SCHEMA_DIR" cp ./com.keyman.gschema.xml "$SCHEMA_DIR"/ glib-compile-schemas "$SCHEMA_DIR" ./build-help.sh --man --no-reconf export XDG_DATA_DIRS=${XDG_DATA_DIRS#*:} unset GSETTINGS_SCHEMA_DIR - rm -rf $TEMP_DATA_DIR + rm -rf "$TEMP_DATA_DIR" } build_action() { -- GitLab From af6e162a27f48422f0ecfccc1c93818e09db6998 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Thu, 1 Jun 2023 19:16:28 +0200 Subject: [PATCH 181/214] feat(linux): Rename column and add tooltip This renames the column from "Location" to "Area" and shows only the area instead of the full path. This also adds a tooltip to the row which shows the full path to the keyboard. --- linux/keyman-config/keyman_config/get_kmp.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/linux/keyman-config/keyman_config/get_kmp.py b/linux/keyman-config/keyman_config/get_kmp.py index af7b34063d..ed3f7ec8a4 100755 --- a/linux/keyman-config/keyman_config/get_kmp.py +++ b/linux/keyman-config/keyman_config/get_kmp.py @@ -9,6 +9,7 @@ import requests import requests_cache from gi.repository import GObject +from keyman_config import _ from keyman_config import KeymanApiUrl, KeymanDownloadsUrl from keyman_config.deprecated_decorator import deprecated @@ -20,6 +21,16 @@ class InstallLocation(GObject.GEnum): Unknown = 99 +def get_install_area_string(area): + if area == InstallLocation.OS: + return _('System') + elif area == InstallLocation.Shared: + return _('Shared') + elif area == InstallLocation.User: + return _('User') + return _('Unknown') + + def get_package_download_data(packageID, weekCache=False): """ Get package download data from keyboards download api. -- GitLab From 51cc5afde70ba2e68d285f6be6de22bc0465c47c Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Thu, 1 Jun 2023 14:02:40 -0400 Subject: [PATCH 182/214] auto: increment master version to 17.0.116 --- HISTORY.md | 6 ++++++ VERSION.md | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index ff0cc6fbbe..e2c639b852 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,11 @@ # Keyman Version History +## 17.0.115 alpha 2023-06-01 + +* refactor(developer): complete fs move out of kmcmplib (#8882) +* fix(common): tweak pack/publish support for npm 9.5.1 and node 18.16.0 (#8894) +* feat(linux): Implement Options page and option to disable Sentry error reporting (#7989) + ## 17.0.114 alpha 2023-05-31 * chore(developer): replace cwrap wasm bindings (#8857) diff --git a/VERSION.md b/VERSION.md index 38d1ece2d6..ce5446d392 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.115 \ No newline at end of file +17.0.116 \ No newline at end of file -- GitLab From 78032df68364a0f19173dbe05f56d7586273305f Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Thu, 1 Jun 2023 20:16:18 +0200 Subject: [PATCH 183/214] fix(core): Fix compilation if hotdoc is installed Partially fixes #8880. --- core/doc/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/doc/meson.build b/core/doc/meson.build index 2772819ce7..a029383a99 100644 --- a/core/doc/meson.build +++ b/core/doc/meson.build @@ -16,7 +16,7 @@ if hotdoc.found() output: 'hotdoc.json', configuration: cfg) deps = files( - '../include/keyman/keyboardprocessor.h.in', + '../include/keyman/keyboardprocessor.h', '../src/jsonpp.hpp', '../src/utfcodec.hpp' ) -- GitLab From 29bc09b7b679b881577ef4d216279c4bfb68c5f7 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Thu, 1 Jun 2023 21:21:35 +0200 Subject: [PATCH 184/214] fix(core): Fix doc generation with hotdoc At least builds now, even though the C API documentation is still empty. --- core/doc/hotdoc.json | 6 +++--- core/doc/meson.build | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/core/doc/hotdoc.json b/core/doc/hotdoc.json index 61a0028fb0..27a54a876f 100644 --- a/core/doc/hotdoc.json +++ b/core/doc/hotdoc.json @@ -1,10 +1,10 @@ { "project_name": "@project_name@", "project_version": "@project_version@", - "sitemap": "../../doc/sitemap.txt", - "index": "../../doc/markdown_files/index.md", + "sitemap": "@source_dir@/sitemap.txt", + "index": "@source_dir@/markdown_files/index.md", "c_sources": [ - "../include/keyboardprocessor.h" + "@include_dir@/keyboardprocessor.h" ], "c_smart_index" : true, "output": ".", diff --git a/core/doc/meson.build b/core/doc/meson.build index a029383a99..57e96d3259 100644 --- a/core/doc/meson.build +++ b/core/doc/meson.build @@ -12,6 +12,8 @@ if hotdoc.found() cfg = configuration_data() cfg.set('project_name', meson.project_name()) cfg.set('project_version', meson.project_version()) + cfg.set('source_dir', meson.current_source_dir()) + cfg.set('include_dir', meson.current_source_dir() / '../include') configure_file(input: 'hotdoc.json', output: 'hotdoc.json', configuration: cfg) @@ -23,7 +25,7 @@ if hotdoc.found() docs = custom_target('docs', output: ['html'], - input: ['sitemap.txt', 'markdown_files/index.md'], + input: ['sitemap.txt', 'markdown_files/index.md', deps], command: [hotdoc, '--verbose', '--conf-file=doc/hotdoc.json', '--output=doc', 'run'], depend_files: deps, install: true, -- GitLab From b313272250be9869e1947fdac2eca37bed1d7392 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 2 Jun 2023 11:38:17 +0700 Subject: [PATCH 185/214] chore(common): remove url module ref from common/web/types The url module is a node module. We need to move responsibility for resolving the path of the LDML XML statements out of common/web/types, and into the ultimate consumer, so it's now surfaced as an option, along with a helper constant that reports the import.meta.url-relative base path of the standard imports that are compiled into common/web/types. This hopefully means we can use this module in both browser and node contexts without trouble. --- common/web/types/src/kvk/kvks-file-writer.ts | 1 - .../src/ldml-keyboard/ldml-keyboard-xml-reader.ts | 15 ++++++++------- common/web/types/src/main.ts | 2 +- common/web/types/test/helpers/index.ts | 5 ++++- .../types/test/helpers/reader-callback-test.ts | 12 +++++++++--- common/web/types/test/kpj/test-kpj-file-reader.ts | 2 -- developer/src/common/web/test-helpers/index.ts | 5 ++++- .../src/kmc-ldml/src/compiler/compiler-options.ts | 7 ++++++- developer/src/kmc-ldml/src/compiler/compiler.ts | 10 ++++------ developer/src/kmc-ldml/test/helpers/index.ts | 11 ++++++++--- developer/src/kmc-ldml/test/test-compiler-e2e.ts | 4 ++-- .../src/kmc-ldml/test/test-keymanweb-compiler.ts | 8 ++++---- .../src/kmc-ldml/test/test-metadata-compiler.ts | 6 +++--- developer/src/kmc-ldml/test/test-testdata-e2e.ts | 4 ++-- .../test/test-visual-keyboard-compiler-e2e.ts | 4 ++-- .../kmc/src/commands/build/BuildLdmlKeyboard.ts | 8 ++++++-- .../src/kmc/src/commands/buildTestData/index.ts | 8 ++++++-- .../src/kmc/src/messages/NodeCompilerCallbacks.ts | 5 ++++- 18 files changed, 73 insertions(+), 44 deletions(-) diff --git a/common/web/types/src/kvk/kvks-file-writer.ts b/common/web/types/src/kvk/kvks-file-writer.ts index 613c6caa51..1b3a819f58 100644 --- a/common/web/types/src/kvk/kvks-file-writer.ts +++ b/common/web/types/src/kvk/kvks-file-writer.ts @@ -96,7 +96,6 @@ export default class KVKSFileWriter { l.key.push(k); } - // console.dir(kvks, {depth:8}); let result = builder.buildObject(kvks); return result; //Uint8Array.from(result); } diff --git a/common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts b/common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts index bc2779ab8e..a1772a9554 100644 --- a/common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts +++ b/common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts @@ -7,7 +7,6 @@ import { CompilerCallbacks } from '../util/compiler-interfaces.js'; import { constants } from '@keymanapp/ldml-keyboard-constants'; import { CommonTypesMessages } from '../util/common-events.js'; import { LDMLKeyboardTestDataXMLSourceFile, LKTTest, LKTTests } from './ldml-keyboard-testdata-xml.js'; -import { fileURLToPath } from 'url'; interface NameAndProps { '$'?: any; // content @@ -15,16 +14,18 @@ interface NameAndProps { '$$'?: any; // children }; -export default class LDMLKeyboardXMLSourceFileReader { - callbacks: CompilerCallbacks; +export class LDMLKeyboardXMLSourceFileReaderOptions { + importsPath: string; +}; + +export const LDMLKeyboardXMLDefaultImportsURL = new URL(`../import/`, import.meta.url); - constructor(callbacks : CompilerCallbacks) { - this.callbacks = callbacks; +export class LDMLKeyboardXMLSourceFileReader { + constructor(private options: LDMLKeyboardXMLSourceFileReaderOptions, private callbacks : CompilerCallbacks) { } readImportFile(version: string, subpath: string): Uint8Array { - // TODO-LDML: use this.callbacks.resolveFilename to get the actual path - let importPath = fileURLToPath(new URL(`../import/${version}/${subpath}`, import.meta.url)); + const importPath = this.callbacks.resolveFilename(this.options.importsPath, `../import/${version}/${subpath}`); return this.callbacks.loadFile(importPath); } diff --git a/common/web/types/src/main.ts b/common/web/types/src/main.ts index 4e77550384..c1fa6a4a0a 100644 --- a/common/web/types/src/main.ts +++ b/common/web/types/src/main.ts @@ -14,7 +14,7 @@ export * as KvksFile from './kvk/kvk-file.js'; export * as LDMLKeyboard from './ldml-keyboard/ldml-keyboard-xml.js'; export { LDMLKeyboardTestDataXMLSourceFile } from './ldml-keyboard/ldml-keyboard-testdata-xml.js'; -export { default as LDMLKeyboardXMLSourceFileReader } from './ldml-keyboard/ldml-keyboard-xml-reader.js'; +export { LDMLKeyboardXMLSourceFileReader, LDMLKeyboardXMLSourceFileReaderOptions, LDMLKeyboardXMLDefaultImportsURL } from './ldml-keyboard/ldml-keyboard-xml-reader.js'; export * as Constants from './consts/virtual-key-constants.js'; diff --git a/common/web/types/test/helpers/index.ts b/common/web/types/test/helpers/index.ts index 58dc32dc9c..06906df148 100644 --- a/common/web/types/test/helpers/index.ts +++ b/common/web/types/test/helpers/index.ts @@ -28,7 +28,10 @@ export function loadSchema(schema: CompilerSchema): Buffer { } export function resolveFilename(baseFilename: string, filename: string) { - const basePath = path.dirname(baseFilename); + const basePath = + baseFilename.endsWith('/') || baseFilename.endsWith('\\') ? + baseFilename : + path.dirname(baseFilename); // Transform separators to platform separators -- we are agnostic // in our use here but path prefers files may use // either / or \, although older kps files were always \. diff --git a/common/web/types/test/helpers/reader-callback-test.ts b/common/web/types/test/helpers/reader-callback-test.ts index 8c85a759ac..a99eca71f4 100644 --- a/common/web/types/test/helpers/reader-callback-test.ts +++ b/common/web/types/test/helpers/reader-callback-test.ts @@ -1,11 +1,16 @@ import 'mocha'; import {assert} from 'chai'; import { loadFile, makePathToFixture, loadSchema } from '../helpers/index.js'; -import LDMLKeyboardXMLSourceFileReader from '../../src/ldml-keyboard/ldml-keyboard-xml-reader.js'; +import { LDMLKeyboardXMLDefaultImportsURL, LDMLKeyboardXMLSourceFileReader, LDMLKeyboardXMLSourceFileReaderOptions } from '../../src/ldml-keyboard/ldml-keyboard-xml-reader.js'; import { CompilerEvent } from '../../src/util/compiler-interfaces.js'; import { LDMLKeyboardXMLSourceFile } from '../../src/ldml-keyboard/ldml-keyboard-xml.js'; import { LDMLKeyboardTestDataXMLSourceFile } from '../ldml-keyboard/ldml-keyboard-testdata-xml.js'; import { TestCompilerCallbacks } from './TestCompilerCallbacks.js'; +import { fileURLToPath } from 'url'; + +const readerOptions: LDMLKeyboardXMLSourceFileReaderOptions = { + importsPath: fileURLToPath(LDMLKeyboardXMLDefaultImportsURL) +}; export interface CompilationCase { /** @@ -71,7 +76,7 @@ export interface TestDataCase { export function testReaderCases(cases : CompilationCase[]) { // we need our own callbacks rather than using the global so messages don't get mixed const callbacks = new TestCompilerCallbacks(); - const reader = new LDMLKeyboardXMLSourceFileReader(callbacks); + const reader = new LDMLKeyboardXMLSourceFileReader(readerOptions, callbacks); for (let testcase of cases) { const expectFailure = testcase.throws || !!(testcase.errors); // if true, we expect this to fail const testHeading = expectFailure ? `should fail to load: ${testcase.subpath}`: @@ -79,6 +84,7 @@ export function testReaderCases(cases : CompilationCase[]) { it(testHeading, function () { callbacks.clear(); + debugger; const data = loadFile(makePathToFixture(testcase.subpath)); assert.ok(data, `reading ${testcase.subpath}`); const source = reader.load(data); @@ -122,7 +128,7 @@ export function testReaderCases(cases : CompilationCase[]) { export function testTestdataReaderCases(cases : TestDataCase[]) { // we need our own callbacks rather than using the global so messages don't get mixed const callbacks = new TestCompilerCallbacks(); - const reader = new LDMLKeyboardXMLSourceFileReader(callbacks); + const reader = new LDMLKeyboardXMLSourceFileReader(readerOptions, callbacks); for (let testcase of cases) { const expectFailure = testcase.throws || !!(testcase.errors); // if true, we expect this to fail const testHeading = expectFailure ? `should fail to load: ${testcase.subpath}`: diff --git a/common/web/types/test/kpj/test-kpj-file-reader.ts b/common/web/types/test/kpj/test-kpj-file-reader.ts index b7c2f71013..95b5f1d01a 100644 --- a/common/web/types/test/kpj/test-kpj-file-reader.ts +++ b/common/web/types/test/kpj/test-kpj-file-reader.ts @@ -15,7 +15,6 @@ describe('kpj-file-reader', function () { const input = fs.readFileSync(path); const reader = new KPJFileReader(callbacks); const kpj = reader.read(input); - console.dir(kpj); assert.doesNotThrow(() => { reader.validate(kpj, loadSchema('kpj')); }); @@ -79,7 +78,6 @@ describe('kpj-file-reader', function () { assert.lengthOf(project.files, 2); let f: KeymanDeveloperProjectFile10 = project.files[0]; - console.dir(f); assert.equal(f.id, 'id_f347675c33d2e6b1c705c787fad4941a'); assert.equal(f.filename, 'khmer_angkor.kmn'); assert.equal(f.filePath, 'source/khmer_angkor.kmn'); diff --git a/developer/src/common/web/test-helpers/index.ts b/developer/src/common/web/test-helpers/index.ts index 0a85287d3d..a134aa67df 100644 --- a/developer/src/common/web/test-helpers/index.ts +++ b/developer/src/common/web/test-helpers/index.ts @@ -57,7 +57,10 @@ export class TestCompilerCallbacks implements CompilerCallbacks { } resolveFilename(baseFilename: string, filename: string): string { - const basePath = path.dirname(baseFilename); + const basePath = + baseFilename.endsWith('/') || baseFilename.endsWith('\\') ? + baseFilename : + path.dirname(baseFilename); // Transform separators to platform separators -- we are agnostic // in our use here but path prefers files may use // either / or \, although older kps files were always \. diff --git a/developer/src/kmc-ldml/src/compiler/compiler-options.ts b/developer/src/kmc-ldml/src/compiler/compiler-options.ts index 3d29e6393a..da81ef2f7d 100644 --- a/developer/src/kmc-ldml/src/compiler/compiler-options.ts +++ b/developer/src/kmc-ldml/src/compiler/compiler-options.ts @@ -1,4 +1,4 @@ - +import { LDMLKeyboardXMLSourceFileReaderOptions } from "@keymanapp/common-types"; export interface CompilerOptions { /** @@ -10,4 +10,9 @@ export interface CompilerOptions { * Add metadata about the compiler version to .kmx file when compiling */ addCompilerVersion?: boolean; + + /** + * Paths and other options required for reading .xml files + */ + readerOptions: LDMLKeyboardXMLSourceFileReaderOptions; }; diff --git a/developer/src/kmc-ldml/src/compiler/compiler.ts b/developer/src/kmc-ldml/src/compiler/compiler.ts index b7b46e49b2..e753beb317 100644 --- a/developer/src/kmc-ldml/src/compiler/compiler.ts +++ b/developer/src/kmc-ldml/src/compiler/compiler.ts @@ -30,16 +30,14 @@ const SECTION_COMPILERS = [ export class LdmlKeyboardCompiler { private readonly callbacks: CompilerCallbacks; - // private readonly options: CompilerOptions; // not currently used + private readonly options: CompilerOptions; // not currently used - constructor (callbacks: CompilerCallbacks, _options?: CompilerOptions) { - /* + constructor (callbacks: CompilerCallbacks, options: CompilerOptions) { this.options = { debug: false, addCompilerVersion: true, ...options }; - */ this.callbacks = callbacks; } @@ -54,7 +52,7 @@ export class LdmlKeyboardCompiler { * @returns the source file, or null if invalid */ public load(filename: string): LDMLKeyboardXMLSourceFile | null { - const reader = new LDMLKeyboardXMLSourceFileReader(this.callbacks); + const reader = new LDMLKeyboardXMLSourceFileReader(this.options.readerOptions, this.callbacks); const data = this.callbacks.loadFile(filename); if(!data) { this.callbacks.reportMessage(CompilerMessages.Error_InvalidFile({errorText: 'Unable to read XML file'})); @@ -84,7 +82,7 @@ export class LdmlKeyboardCompiler { * @returns the source file, or null if invalid */ public loadTestData(filename: string): LDMLKeyboardTestDataXMLSourceFile | null { - const reader = new LDMLKeyboardXMLSourceFileReader(this.callbacks); + const reader = new LDMLKeyboardXMLSourceFileReader(this.options.readerOptions, this.callbacks); const data = this.callbacks.loadFile(filename); if(!data) { this.callbacks.reportMessage(CompilerMessages.Error_InvalidFile({errorText: 'Unable to read XML file'})); diff --git a/developer/src/kmc-ldml/test/helpers/index.ts b/developer/src/kmc-ldml/test/helpers/index.ts index 8ba8a28aa8..a493af82f1 100644 --- a/developer/src/kmc-ldml/test/helpers/index.ts +++ b/developer/src/kmc-ldml/test/helpers/index.ts @@ -5,7 +5,7 @@ import 'mocha'; import * as path from 'path'; import { fileURLToPath } from 'url'; import { SectionCompiler } from '../../src/compiler/section-compiler.js'; -import { KMXPlus, LDMLKeyboardXMLSourceFileReader, VisualKeyboard, CompilerEvent, LDMLKeyboardTestDataXMLSourceFile } from '@keymanapp/common-types'; +import { KMXPlus, LDMLKeyboardXMLSourceFileReader, VisualKeyboard, CompilerEvent, LDMLKeyboardTestDataXMLSourceFile, LDMLKeyboardXMLDefaultImportsURL } from '@keymanapp/common-types'; import { LdmlKeyboardCompiler } from '../../src/compiler/compiler.js'; import { assert } from 'chai'; import { KMXPlusMetadataCompiler } from '../../src/compiler/metadata-compiler.js'; @@ -33,6 +33,12 @@ export function makePathToFixture(...components: string[]): string { export const compilerTestCallbacks = new TestCompilerCallbacks(); +export const compilerTestOptions: CompilerOptions = { + readerOptions: { + importsPath: fileURLToPath(LDMLKeyboardXMLDefaultImportsURL) + } +}; + beforeEach(function() { compilerTestCallbacks.clear(); }); @@ -43,14 +49,13 @@ afterEach(function() { } }); - export function loadSectionFixture(compilerClass: typeof SectionCompiler, filename: string, callbacks: TestCompilerCallbacks): Section { callbacks.messages = []; const inputFilename = makePathToFixture(filename); const data = callbacks.loadFile(inputFilename); assert.isNotNull(data); - const reader = new LDMLKeyboardXMLSourceFileReader(callbacks); + const reader = new LDMLKeyboardXMLSourceFileReader(compilerTestOptions.readerOptions, callbacks); const source = reader.load(data); assert.isNotNull(source); diff --git a/developer/src/kmc-ldml/test/test-compiler-e2e.ts b/developer/src/kmc-ldml/test/test-compiler-e2e.ts index ec71154905..7d8b179f31 100644 --- a/developer/src/kmc-ldml/test/test-compiler-e2e.ts +++ b/developer/src/kmc-ldml/test/test-compiler-e2e.ts @@ -2,7 +2,7 @@ import 'mocha'; import {assert} from 'chai'; import x_hextobin from '@keymanapp/hextobin'; import { KMXBuilder } from '@keymanapp/common-types'; -import {checkMessages, compileKeyboard, makePathToFixture} from './helpers/index.js'; +import {checkMessages, compileKeyboard, compilerTestOptions, makePathToFixture} from './helpers/index.js'; const hextobin = (x_hextobin as any).default; @@ -17,7 +17,7 @@ describe('compiler-tests', function() { const binaryFilename = makePathToFixture('basic.txt'); // Compile the keyboard - const kmx = compileKeyboard(inputFilename, {debug: true, addCompilerVersion: false}); + const kmx = compileKeyboard(inputFilename, {...compilerTestOptions, debug: true, addCompilerVersion: false}); assert.isNotNull(kmx); // Use the builder to generate the binary output file diff --git a/developer/src/kmc-ldml/test/test-keymanweb-compiler.ts b/developer/src/kmc-ldml/test/test-keymanweb-compiler.ts index fb4f28daee..711820e5e4 100644 --- a/developer/src/kmc-ldml/test/test-keymanweb-compiler.ts +++ b/developer/src/kmc-ldml/test/test-keymanweb-compiler.ts @@ -1,6 +1,6 @@ import 'mocha'; import { assert } from 'chai'; -import { checkMessages, compilerTestCallbacks, makePathToFixture } from './helpers/index.js'; +import { checkMessages, compilerTestCallbacks, compilerTestOptions, makePathToFixture } from './helpers/index.js'; import { LdmlKeyboardKeymanWebCompiler } from '../src/compiler/keymanweb-compiler.js'; import { LdmlKeyboardCompiler } from '../src/compiler/compiler.js'; import * as fs from 'fs'; @@ -16,7 +16,7 @@ describe('LdmlKeyboardKeymanWebCompiler', function() { // Load input data; we'll use the LDML keyboard compiler loader to save us // effort here - const k = new LdmlKeyboardCompiler(compilerTestCallbacks, {debug: true, addCompilerVersion: false}); + const k = new LdmlKeyboardCompiler(compilerTestCallbacks, {...compilerTestOptions, debug: true, addCompilerVersion: false}); const source = k.load(inputFilename); checkMessages(); assert.isNotNull(source, 'k.load should not have returned null'); @@ -27,7 +27,7 @@ describe('LdmlKeyboardKeymanWebCompiler', function() { assert.isTrue(valid, 'k.validate should not have failed'); // Actual test: compile to javascript - const jsCompiler = new LdmlKeyboardKeymanWebCompiler(compilerTestCallbacks, {debug: true}); + const jsCompiler = new LdmlKeyboardKeymanWebCompiler(compilerTestCallbacks, {...compilerTestOptions, debug: true}); const output = jsCompiler.compile('basic.xml', source); assert.isNotNull(output); @@ -36,7 +36,7 @@ describe('LdmlKeyboardKeymanWebCompiler', function() { assert.strictEqual(output, outputFixture); // Second test: compile to javascript without debug formatting - const jsCompilerNoDebug = new LdmlKeyboardKeymanWebCompiler(compilerTestCallbacks, {debug: false}); + const jsCompilerNoDebug = new LdmlKeyboardKeymanWebCompiler(compilerTestCallbacks, {...compilerTestOptions, debug: false}); const outputNoDebug = jsCompilerNoDebug.compile('basic.xml', source); assert.isNotNull(outputNoDebug); diff --git a/developer/src/kmc-ldml/test/test-metadata-compiler.ts b/developer/src/kmc-ldml/test/test-metadata-compiler.ts index 59500d0995..ede77ed4bc 100644 --- a/developer/src/kmc-ldml/test/test-metadata-compiler.ts +++ b/developer/src/kmc-ldml/test/test-metadata-compiler.ts @@ -1,6 +1,6 @@ import 'mocha'; import { assert } from 'chai'; -import { checkMessages, compileKeyboard, makePathToFixture } from './helpers/index.js'; +import { checkMessages, compileKeyboard, compilerTestOptions, makePathToFixture } from './helpers/index.js'; import { KMX } from '@keymanapp/common-types'; import KEYMAN_VERSION from '@keymanapp/keyman-version'; @@ -13,7 +13,7 @@ describe('kmx metadata compiler', function () { const inputFilename = makePathToFixture('basic.xml'); // Compile the keyboard - const kmx = compileKeyboard(inputFilename, {debug:true, addCompilerVersion:true}); + const kmx = compileKeyboard(inputFilename, {...compilerTestOptions, debug:true, addCompilerVersion:true}); checkMessages(); assert.isNotNull(kmx); @@ -48,7 +48,7 @@ describe('kmx metadata compiler', function () { const inputFilename = makePathToFixture('basic.xml'); // Compile the keyboard - const kmx = compileKeyboard(inputFilename, {debug:true, addCompilerVersion:false}); + const kmx = compileKeyboard(inputFilename, {...compilerTestOptions, debug:true, addCompilerVersion:false}); checkMessages(); assert.isNotNull(kmx); diff --git a/developer/src/kmc-ldml/test/test-testdata-e2e.ts b/developer/src/kmc-ldml/test/test-testdata-e2e.ts index 25ac196321..0d562584fa 100644 --- a/developer/src/kmc-ldml/test/test-testdata-e2e.ts +++ b/developer/src/kmc-ldml/test/test-testdata-e2e.ts @@ -1,7 +1,7 @@ import { readFileSync } from 'fs'; import 'mocha'; import {assert} from 'chai'; -import {loadTestdata, makePathToFixture} from './helpers/index.js'; +import {compilerTestOptions, loadTestdata, makePathToFixture} from './helpers/index.js'; describe('testdata-tests', function() { this.slow(500); // 0.5 sec -- json schema validation takes a while @@ -14,7 +14,7 @@ describe('testdata-tests', function() { const jsonFilename = makePathToFixture('test-fr.json'); // Compile the keyboard - const testData = loadTestdata(inputFilename, {debug: true, addCompilerVersion: false}); + const testData = loadTestdata(inputFilename, compilerTestOptions); assert.isNotNull(testData); const jsonData = JSON.parse(readFileSync(jsonFilename, 'utf-8')); diff --git a/developer/src/kmc-ldml/test/test-visual-keyboard-compiler-e2e.ts b/developer/src/kmc-ldml/test/test-visual-keyboard-compiler-e2e.ts index 1b1e34069e..4af6827838 100644 --- a/developer/src/kmc-ldml/test/test-visual-keyboard-compiler-e2e.ts +++ b/developer/src/kmc-ldml/test/test-visual-keyboard-compiler-e2e.ts @@ -2,7 +2,7 @@ import 'mocha'; import {assert} from 'chai'; import x_hextobin from '@keymanapp/hextobin'; import { KvkFileWriter } from '@keymanapp/common-types'; -import {checkMessages, compileVisualKeyboard, makePathToFixture} from './helpers/index.js'; +import {checkMessages, compilerTestOptions, compileVisualKeyboard, makePathToFixture} from './helpers/index.js'; const hextobin = (x_hextobin as any).default; @@ -17,7 +17,7 @@ describe('visual-keyboard-compiler', function() { const binaryFilename = makePathToFixture('basic-kvk.txt'); // Compile the visual keyboard - const vk = compileVisualKeyboard(inputFilename, {debug: true, addCompilerVersion: false}); + const vk = compileVisualKeyboard(inputFilename, {...compilerTestOptions, debug: true, addCompilerVersion: false}); assert.isNotNull(vk); // Use the builder to generate the binary output file diff --git a/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts b/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts index 024f7f5340..9c6c5c8731 100644 --- a/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts +++ b/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts @@ -1,8 +1,9 @@ import * as path from 'path'; import * as fs from 'fs'; import * as kmcLdml from '@keymanapp/kmc-ldml'; -import { KvkFileWriter, CompilerCallbacks } from '@keymanapp/common-types'; +import { KvkFileWriter, CompilerCallbacks, LDMLKeyboardXMLDefaultImportsURL } from '@keymanapp/common-types'; import { BuildActivity, BuildActivityOptions } from './BuildActivity.js'; +import { fileURLToPath } from 'url'; export class BuildLdmlKeyboard extends BuildActivity { public get name(): string { return 'LDML keyboard'; } @@ -46,11 +47,14 @@ function buildLdmlKeyboardToMemory(inputFilename: string, callbacks: CompilerCal let compilerOptions: kmcLdml.CompilerOptions = { debug: options.debug ?? false, addCompilerVersion: options.compilerVersion ?? true, + readerOptions: { + importsPath: fileURLToPath(LDMLKeyboardXMLDefaultImportsURL) + } // TODO: warnDeprecatedCode: options.warnDeprecatedCode, // TODO: treatWarningsAsErrors: options.treatWarningsAsErrors, } - const k = new kmcLdml.LdmlKeyboardCompiler(callbacks, options); + const k = new kmcLdml.LdmlKeyboardCompiler(callbacks, compilerOptions); let source = k.load(inputFilename); if (!source) { return [null, null, null]; diff --git a/developer/src/kmc/src/commands/buildTestData/index.ts b/developer/src/kmc/src/commands/buildTestData/index.ts index 0990b91edb..11a9789d6c 100644 --- a/developer/src/kmc/src/commands/buildTestData/index.ts +++ b/developer/src/kmc/src/commands/buildTestData/index.ts @@ -1,8 +1,9 @@ import * as fs from 'fs'; import * as path from 'path'; import * as kmc from '@keymanapp/kmc-ldml'; -import { CompilerCallbacks, LDMLKeyboardTestDataXMLSourceFile } from '@keymanapp/common-types'; +import { CompilerCallbacks, LDMLKeyboardTestDataXMLSourceFile, LDMLKeyboardXMLDefaultImportsURL } from '@keymanapp/common-types'; import { NodeCompilerCallbacks } from '../../messages/NodeCompilerCallbacks.js'; +import { fileURLToPath } from 'url'; export interface BuildTestDataOptions { outFile?: string; @@ -11,7 +12,10 @@ export interface BuildTestDataOptions { export function buildTestData(infile: string, options: BuildTestDataOptions) { let compilerOptions: kmc.CompilerOptions = { debug: false, - addCompilerVersion: false + addCompilerVersion: false, + readerOptions: { + importsPath: fileURLToPath(LDMLKeyboardXMLDefaultImportsURL) + } }; let testData = loadTestData(infile, compilerOptions); diff --git a/developer/src/kmc/src/messages/NodeCompilerCallbacks.ts b/developer/src/kmc/src/messages/NodeCompilerCallbacks.ts index f8232cde5f..dfcb7e2ecb 100644 --- a/developer/src/kmc/src/messages/NodeCompilerCallbacks.ts +++ b/developer/src/kmc/src/messages/NodeCompilerCallbacks.ts @@ -93,7 +93,10 @@ export class NodeCompilerCallbacks implements CompilerCallbacks { } resolveFilename(baseFilename: string, filename: string) { - const basePath = path.dirname(baseFilename); + const basePath = + baseFilename.endsWith('/') || baseFilename.endsWith('\\') ? + baseFilename : + path.dirname(baseFilename); // Transform separators to platform separators -- we are agnostic // in our use here but path prefers files may use // either / or \, although older kps files were always \. -- GitLab From a281e1ac6033a2ed99bddc16d97ceceeb72dcffa Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 2 Jun 2023 11:43:25 +0700 Subject: [PATCH 186/214] chore(common): remove redundant path --- common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts b/common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts index a1772a9554..35eba83e05 100644 --- a/common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts +++ b/common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts @@ -25,7 +25,7 @@ export class LDMLKeyboardXMLSourceFileReader { } readImportFile(version: string, subpath: string): Uint8Array { - const importPath = this.callbacks.resolveFilename(this.options.importsPath, `../import/${version}/${subpath}`); + const importPath = this.callbacks.resolveFilename(this.options.importsPath, `${version}/${subpath}`); return this.callbacks.loadFile(importPath); } -- GitLab From 4e535832d8a9cfe2e28d0727cdd172147c784b7e Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 2 Jun 2023 11:45:59 +0700 Subject: [PATCH 187/214] chore: cleanup --- common/web/types/test/helpers/reader-callback-test.ts | 1 - developer/src/kmc-ldml/src/compiler/compiler.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/common/web/types/test/helpers/reader-callback-test.ts b/common/web/types/test/helpers/reader-callback-test.ts index a99eca71f4..b4b68cb98f 100644 --- a/common/web/types/test/helpers/reader-callback-test.ts +++ b/common/web/types/test/helpers/reader-callback-test.ts @@ -84,7 +84,6 @@ export function testReaderCases(cases : CompilationCase[]) { it(testHeading, function () { callbacks.clear(); - debugger; const data = loadFile(makePathToFixture(testcase.subpath)); assert.ok(data, `reading ${testcase.subpath}`); const source = reader.load(data); diff --git a/developer/src/kmc-ldml/src/compiler/compiler.ts b/developer/src/kmc-ldml/src/compiler/compiler.ts index e753beb317..4b1472a585 100644 --- a/developer/src/kmc-ldml/src/compiler/compiler.ts +++ b/developer/src/kmc-ldml/src/compiler/compiler.ts @@ -30,7 +30,7 @@ const SECTION_COMPILERS = [ export class LdmlKeyboardCompiler { private readonly callbacks: CompilerCallbacks; - private readonly options: CompilerOptions; // not currently used + private readonly options: CompilerOptions; constructor (callbacks: CompilerCallbacks, options: CompilerOptions) { this.options = { -- GitLab From d7f22b186f3596e24765267c7fa0de759b61efdd Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 2 Jun 2023 12:01:58 +0700 Subject: [PATCH 188/214] chore(developer): verify long lines compile correctly Fixes #8888. Verifies that wrapped lines (ending in \) are handled correctly in kmcmplib. --- .../valid-keyboards/compile_legacy.bat | 2 +- .../valid-keyboards/k009_long_lines.kmn | 31 ++++++++++++++++++ .../valid-keyboards/k009_long_lines.kmx | Bin 0 -> 1686 bytes developer/src/kmcmplib/tests/meson.build | 5 +-- 4 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k009_long_lines.kmn create mode 100644 developer/src/kmcmplib/tests/fixtures/valid-keyboards/k009_long_lines.kmx diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/compile_legacy.bat b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/compile_legacy.bat index e346418eb4..5e8b891ea6 100644 --- a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/compile_legacy.bat +++ b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/compile_legacy.bat @@ -1,4 +1,4 @@ @echo off echo Compiles the keyboards using the legacy kmcomp.exe echo to use as baseline comparisons for kmcmplib -for %%d in (*.kmn) do kmcomp -no-compiler-version -d %%d \ No newline at end of file +for %%d in (*.kmn) do ..\..\..\..\..\bin\kmcomp -no-compiler-version -d %%d \ No newline at end of file diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k009_long_lines.kmn b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k009_long_lines.kmn new file mode 100644 index 0000000000..a0ad9d0d9f --- /dev/null +++ b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k009_long_lines.kmn @@ -0,0 +1,31 @@ +c Description: Verifies that kmcmplib can deal with long lines continued with backslashes, and also comments + +store(&NAME) 'k009_long_lines' +store(&VERSION) '9.0' + +begin unicode > use(main) + +group(main) using keys + +c +c ***Note*** This file has intentional whitespace at the end of line ending in [SHIFT K_N] +c in order to verify that line continuations are working correctly +c + +store(c_key) [K_K] [K_X] [SHIFT K_K] [SHIFT K_X] [K_G] \ + [K_C] [K_Q] [SHIFT K_C] [SHIFT K_Q] [SHIFT K_J] \ + [K_D] [K_Z] [SHIFT K_D] [SHIFT K_Z] [SHIFT K_N] \ + [K_T] [K_F] [SHIFT K_T] [SHIFT K_F] [K_N] \ + [K_B] [K_P] [SHIFT K_B] [SHIFT K_P] [K_M] \ + [K_Y] [K_R] [K_L] [K_V] [K_S] [K_H] [SHIFT K_L] [SHIFT K_G] \ + [RALT K_K] [RALT K_B] +store(c_out) U+1780 U+1781 U+1782 U+1783 U+1784 \ + U+1785 U+1786 U+1787 U+1788 U+1789 \ + U+178A U+178B U+178C U+178D U+178E \ + U+178F U+1790 U+1791 U+1792 U+1793 \ + U+1794 U+1795 U+1796 U+1797 U+1798 \ + U+1799 U+179A U+179B U+179C U+179F U+17A0 U+17A1 U+17A2 \ + U+179D U+179E c deprecated, but they are used in minority languages + ++ any(c_key) > index(c_out, 1) + diff --git a/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k009_long_lines.kmx b/developer/src/kmcmplib/tests/fixtures/valid-keyboards/k009_long_lines.kmx new file mode 100644 index 0000000000000000000000000000000000000000..4acd4cc051adc10d35c6ae842b24be5cf43f0cf4 GIT binary patch literal 1686 zcmYk5xldG46vmJHNGx6~I2MK&HN;pD3PZ$LTn8MG0fb>B1BFWj4T3`4O^9LN_kEQm z#=pS$7f=`rLqRBvg`psBu`m|K81y@bxtDvB-}lb<&AIo@ocAW0h?mhpqHpmpPY7$5 z2v!J4ZNTPkqJLN@-J00HU8dsl5-b7+ufZ#D0IY*IK+gIKHb4O6;J7E%HptrfXD3^~i2(RfDRU9-t$gis=Fs(M8nRl%c1j zQ#pK$%IFeZ#^*$5K^{IkrYFm8`JE~F(NTPd?JAM10+$8GW@PeQUyiFv-42@tW+y9f zeYvixbUSPon4PTH^~GHkaXV}l7@LvV*%5X-O56^c1;%D%idl%3PJ7 ztO8^E0ymeCn_9@oeTi=3N!9ApBx>SjZsAsL<96=gPVVAv?%`hU<9;6CK_22^9^p|Q z<8hwgNuJ_qp5a-Z;{{&iC0^!veu0-x&a9_L^bqG~fiPXcv#dd0PgS@V(H7pM&>j@Y zbpls;>Ew;te(qtoG!QaGEBlDvf~c3hgMSZfUx2<<_%)D|?2~LA{sYMMvXAheK*Y;7 z;5R{@mwkr+4hp>N2mDW9zl+@C7yNHf==J@9-vaVp%kPjr!hduxDDkrW@F}3w%MQT@ zAns*{;Zs4v%Z|Vw1(jZw27esbxsV|`34aRMxkz>zJ_FdfNR|nI21JtQNtOkF4%oR! zb{^h Date: Fri, 2 Jun 2023 12:28:13 +0700 Subject: [PATCH 189/214] chore(common): move const url to class prop We still have cjs modules that rely on the ldml-keyboard-xml-reader, and this meant that an exported const was being calculated with an invalid meta url, which crashed the cjs module require() call. --- .../web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts | 6 ++++-- common/web/types/src/main.ts | 2 +- common/web/types/test/helpers/reader-callback-test.ts | 4 ++-- developer/src/kmc-ldml/test/helpers/index.ts | 4 ++-- developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts | 4 ++-- developer/src/kmc/src/commands/buildTestData/index.ts | 4 ++-- 6 files changed, 13 insertions(+), 11 deletions(-) diff --git a/common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts b/common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts index 35eba83e05..fa74126462 100644 --- a/common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts +++ b/common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts @@ -18,12 +18,14 @@ export class LDMLKeyboardXMLSourceFileReaderOptions { importsPath: string; }; -export const LDMLKeyboardXMLDefaultImportsURL = new URL(`../import/`, import.meta.url); - export class LDMLKeyboardXMLSourceFileReader { constructor(private options: LDMLKeyboardXMLSourceFileReaderOptions, private callbacks : CompilerCallbacks) { } + static get defaultImportsURL() { + return new URL(`../import/`, import.meta.url); + } + readImportFile(version: string, subpath: string): Uint8Array { const importPath = this.callbacks.resolveFilename(this.options.importsPath, `${version}/${subpath}`); return this.callbacks.loadFile(importPath); diff --git a/common/web/types/src/main.ts b/common/web/types/src/main.ts index c1fa6a4a0a..ddaa318d3e 100644 --- a/common/web/types/src/main.ts +++ b/common/web/types/src/main.ts @@ -14,7 +14,7 @@ export * as KvksFile from './kvk/kvk-file.js'; export * as LDMLKeyboard from './ldml-keyboard/ldml-keyboard-xml.js'; export { LDMLKeyboardTestDataXMLSourceFile } from './ldml-keyboard/ldml-keyboard-testdata-xml.js'; -export { LDMLKeyboardXMLSourceFileReader, LDMLKeyboardXMLSourceFileReaderOptions, LDMLKeyboardXMLDefaultImportsURL } from './ldml-keyboard/ldml-keyboard-xml-reader.js'; +export { LDMLKeyboardXMLSourceFileReader, LDMLKeyboardXMLSourceFileReaderOptions } from './ldml-keyboard/ldml-keyboard-xml-reader.js'; export * as Constants from './consts/virtual-key-constants.js'; diff --git a/common/web/types/test/helpers/reader-callback-test.ts b/common/web/types/test/helpers/reader-callback-test.ts index b4b68cb98f..204e0ec5bf 100644 --- a/common/web/types/test/helpers/reader-callback-test.ts +++ b/common/web/types/test/helpers/reader-callback-test.ts @@ -1,7 +1,7 @@ import 'mocha'; import {assert} from 'chai'; import { loadFile, makePathToFixture, loadSchema } from '../helpers/index.js'; -import { LDMLKeyboardXMLDefaultImportsURL, LDMLKeyboardXMLSourceFileReader, LDMLKeyboardXMLSourceFileReaderOptions } from '../../src/ldml-keyboard/ldml-keyboard-xml-reader.js'; +import { LDMLKeyboardXMLSourceFileReader, LDMLKeyboardXMLSourceFileReaderOptions } from '../../src/ldml-keyboard/ldml-keyboard-xml-reader.js'; import { CompilerEvent } from '../../src/util/compiler-interfaces.js'; import { LDMLKeyboardXMLSourceFile } from '../../src/ldml-keyboard/ldml-keyboard-xml.js'; import { LDMLKeyboardTestDataXMLSourceFile } from '../ldml-keyboard/ldml-keyboard-testdata-xml.js'; @@ -9,7 +9,7 @@ import { TestCompilerCallbacks } from './TestCompilerCallbacks.js'; import { fileURLToPath } from 'url'; const readerOptions: LDMLKeyboardXMLSourceFileReaderOptions = { - importsPath: fileURLToPath(LDMLKeyboardXMLDefaultImportsURL) + importsPath: fileURLToPath(LDMLKeyboardXMLSourceFileReader.defaultImportsURL) }; export interface CompilationCase { diff --git a/developer/src/kmc-ldml/test/helpers/index.ts b/developer/src/kmc-ldml/test/helpers/index.ts index a493af82f1..f10af945c8 100644 --- a/developer/src/kmc-ldml/test/helpers/index.ts +++ b/developer/src/kmc-ldml/test/helpers/index.ts @@ -5,7 +5,7 @@ import 'mocha'; import * as path from 'path'; import { fileURLToPath } from 'url'; import { SectionCompiler } from '../../src/compiler/section-compiler.js'; -import { KMXPlus, LDMLKeyboardXMLSourceFileReader, VisualKeyboard, CompilerEvent, LDMLKeyboardTestDataXMLSourceFile, LDMLKeyboardXMLDefaultImportsURL } from '@keymanapp/common-types'; +import { KMXPlus, LDMLKeyboardXMLSourceFileReader, VisualKeyboard, CompilerEvent, LDMLKeyboardTestDataXMLSourceFile } from '@keymanapp/common-types'; import { LdmlKeyboardCompiler } from '../../src/compiler/compiler.js'; import { assert } from 'chai'; import { KMXPlusMetadataCompiler } from '../../src/compiler/metadata-compiler.js'; @@ -35,7 +35,7 @@ export const compilerTestCallbacks = new TestCompilerCallbacks(); export const compilerTestOptions: CompilerOptions = { readerOptions: { - importsPath: fileURLToPath(LDMLKeyboardXMLDefaultImportsURL) + importsPath: fileURLToPath(LDMLKeyboardXMLSourceFileReader.defaultImportsURL) } }; diff --git a/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts b/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts index 9c6c5c8731..40b9513d32 100644 --- a/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts +++ b/developer/src/kmc/src/commands/build/BuildLdmlKeyboard.ts @@ -1,7 +1,7 @@ import * as path from 'path'; import * as fs from 'fs'; import * as kmcLdml from '@keymanapp/kmc-ldml'; -import { KvkFileWriter, CompilerCallbacks, LDMLKeyboardXMLDefaultImportsURL } from '@keymanapp/common-types'; +import { KvkFileWriter, CompilerCallbacks, LDMLKeyboardXMLSourceFileReader } from '@keymanapp/common-types'; import { BuildActivity, BuildActivityOptions } from './BuildActivity.js'; import { fileURLToPath } from 'url'; @@ -48,7 +48,7 @@ function buildLdmlKeyboardToMemory(inputFilename: string, callbacks: CompilerCal debug: options.debug ?? false, addCompilerVersion: options.compilerVersion ?? true, readerOptions: { - importsPath: fileURLToPath(LDMLKeyboardXMLDefaultImportsURL) + importsPath: fileURLToPath(LDMLKeyboardXMLSourceFileReader.defaultImportsURL) } // TODO: warnDeprecatedCode: options.warnDeprecatedCode, // TODO: treatWarningsAsErrors: options.treatWarningsAsErrors, diff --git a/developer/src/kmc/src/commands/buildTestData/index.ts b/developer/src/kmc/src/commands/buildTestData/index.ts index 11a9789d6c..b6ebf34a73 100644 --- a/developer/src/kmc/src/commands/buildTestData/index.ts +++ b/developer/src/kmc/src/commands/buildTestData/index.ts @@ -1,7 +1,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as kmc from '@keymanapp/kmc-ldml'; -import { CompilerCallbacks, LDMLKeyboardTestDataXMLSourceFile, LDMLKeyboardXMLDefaultImportsURL } from '@keymanapp/common-types'; +import { CompilerCallbacks, LDMLKeyboardTestDataXMLSourceFile, LDMLKeyboardXMLSourceFileReader } from '@keymanapp/common-types'; import { NodeCompilerCallbacks } from '../../messages/NodeCompilerCallbacks.js'; import { fileURLToPath } from 'url'; @@ -14,7 +14,7 @@ export function buildTestData(infile: string, options: BuildTestDataOptions) { debug: false, addCompilerVersion: false, readerOptions: { - importsPath: fileURLToPath(LDMLKeyboardXMLDefaultImportsURL) + importsPath: fileURLToPath(LDMLKeyboardXMLSourceFileReader.defaultImportsURL) } }; -- GitLab From 16675ef46b0bfbe7e3d0c239ee6b5e09eda22e0e Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 2 Jun 2023 18:54:42 +1000 Subject: [PATCH 190/214] chore: extend from test options in e2e test --- developer/src/kmc-ldml/test/test-testdata-e2e.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/developer/src/kmc-ldml/test/test-testdata-e2e.ts b/developer/src/kmc-ldml/test/test-testdata-e2e.ts index 0d562584fa..ece4ce8560 100644 --- a/developer/src/kmc-ldml/test/test-testdata-e2e.ts +++ b/developer/src/kmc-ldml/test/test-testdata-e2e.ts @@ -14,7 +14,7 @@ describe('testdata-tests', function() { const jsonFilename = makePathToFixture('test-fr.json'); // Compile the keyboard - const testData = loadTestdata(inputFilename, compilerTestOptions); + const testData = loadTestdata(inputFilename, {...compilerTestOptions, debug: true, addCompilerVersion: false}); assert.isNotNull(testData); const jsonData = JSON.parse(readFileSync(jsonFilename, 'utf-8')); -- GitLab From f43f808a03174a67bbe7037c074449eefa64cb54 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 2 Jun 2023 17:31:04 +0200 Subject: [PATCH 191/214] feat(linux): Rename column and add tooltip Follow-up of #8631 where I forgot to add one of the changed files. --- linux/keyman-config/keyman_config/view_installed.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/linux/keyman-config/keyman_config/view_installed.py b/linux/keyman-config/keyman_config/view_installed.py index aaa5196fbd..263d665d25 100755 --- a/linux/keyman-config/keyman_config/view_installed.py +++ b/linux/keyman-config/keyman_config/view_installed.py @@ -19,7 +19,7 @@ from keyman_config.accelerators import bind_accelerator, init_accel from keyman_config.dbus_util import get_keyman_config_service from keyman_config.downloadkeyboard import DownloadKmpWindow from keyman_config.get_kmp import (InstallLocation, get_keyboard_dir, - get_keyman_dir) + get_keyman_dir, get_install_area_string) from keyman_config.install_window import InstallKmpWindow, find_keyman_image from keyman_config.keyboard_details import KeyboardDetailsView from keyman_config.kmpmetadata import get_fonts, parsemetadata @@ -166,7 +166,8 @@ class ViewInstalledWindow(ViewInstalledWindowBase): str, # version str, # packageID int, # enum InstallLocation (KmpArea is GObject version) - str, # InstallLocation path + str, # InstallLocation area + str, # Tooltip with InstallLocation path str, # path to welcome file if it exists or None str) # path to options file if it exists or None @@ -186,9 +187,11 @@ class ViewInstalledWindow(ViewInstalledWindowBase): column = Gtk.TreeViewColumn(_("Version"), renderer, text=2) self.tree.append_column(column) # i18n: column header in table displaying installed keyboards - column = Gtk.TreeViewColumn(_("Location"), renderer, text=5) + column = Gtk.TreeViewColumn(_("Area"), renderer, text=5) self.tree.append_column(column) + self.tree.set_tooltip_column(column=6) + select = self.tree.get_selection() select.connect("changed", self.on_tree_selection_changed) @@ -286,7 +289,8 @@ class ViewInstalledWindow(ViewInstalledWindowBase): kmpdata['version'], kmpdata['packageID'], install_area, - get_keyman_dir(install_area).replace(os.path.expanduser('~'), '~'), + get_install_area_string(install_area), + path.replace(os.path.expanduser('~'), '~'), welcome_file, options_file]) -- GitLab From 3c4f2251ebd500c103d8b0e2404195677ac7ea37 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 2 Jun 2023 18:42:35 +0200 Subject: [PATCH 192/214] fix(core): Fix C API documentation generation --- core/doc/hotdoc.json | 10 +++++--- core/doc/meson.build | 2 +- core/include/keyman/keyboardprocessor.h | 31 ++++++++++++++++++------- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/core/doc/hotdoc.json b/core/doc/hotdoc.json index 27a54a876f..4ece50d0f5 100644 --- a/core/doc/hotdoc.json +++ b/core/doc/hotdoc.json @@ -1,10 +1,14 @@ { "project_name": "@project_name@", "project_version": "@project_version@", - "sitemap": "@source_dir@/sitemap.txt", - "index": "@source_dir@/markdown_files/index.md", + "sitemap": "@doc_dir@/sitemap.txt", + "index": "@doc_dir@/markdown_files/index.md", "c_sources": [ - "@include_dir@/keyboardprocessor.h" + "@include_dir@/keyman/keyboardprocessor.h" + ], + "c_include_directories": [ + "@include_dir@", + "@doc_dir@/../../common/include" ], "c_smart_index" : true, "output": ".", diff --git a/core/doc/meson.build b/core/doc/meson.build index 57e96d3259..01fcb5c98a 100644 --- a/core/doc/meson.build +++ b/core/doc/meson.build @@ -12,7 +12,7 @@ if hotdoc.found() cfg = configuration_data() cfg.set('project_name', meson.project_name()) cfg.set('project_version', meson.project_version()) - cfg.set('source_dir', meson.current_source_dir()) + cfg.set('doc_dir', meson.current_source_dir()) cfg.set('include_dir', meson.current_source_dir() / '../include') configure_file(input: 'hotdoc.json', output: 'hotdoc.json', diff --git a/core/include/keyman/keyboardprocessor.h b/core/include/keyman/keyboardprocessor.h index 3513cdede2..429a8ae6cb 100644 --- a/core/include/keyman/keyboardprocessor.h +++ b/core/include/keyman/keyboardprocessor.h @@ -779,7 +779,7 @@ km_kbp_keyboard_get_key_list(km_kbp_keyboard const *keyboard, km_kbp_keyboard_key **out); -/* +/** ``` ### `km_kbp_keyboard_key_list_dispose` ##### Description: @@ -794,28 +794,41 @@ returned by `km_kbp_keyboard_get_key_list`. KMN_API void km_kbp_keyboard_key_list_dispose(km_kbp_keyboard_key *key_list); - /** - * Returns the list of IMX libraries and function names that are referenced by - * the keyboard. The matching dispose call needs to be called to free the memory. + * km_kbp_keyboard_get_imx_list: + * + * Returns: the list of IMX libraries and function names that are referenced by + * the keyboard.The matching dispose call needs to be called to free the memory. */ KMN_API -km_kbp_status km_kbp_keyboard_get_imx_list(km_kbp_keyboard const *keyboard, km_kbp_keyboard_imx** imx_list); +km_kbp_status km_kbp_keyboard_get_imx_list(km_kbp_keyboard const *keyboard, km_kbp_keyboard_imx **imx_list); /** + * km_kbp_keyboard_imx_list_dispose: + * * Disposes of the IMX list + * + * Returns: -- */ KMN_API void km_kbp_keyboard_imx_list_dispose(km_kbp_keyboard_imx *imx_list); /** + * km_kbp_state_imx_register_callback: + * * Register the IMX callback endpoint for the client. + * + * Returns: -- */ KMN_API void km_kbp_state_imx_register_callback(km_kbp_state *state, km_kbp_keyboard_imx_platform imx_callback, void *callback_object); /** + * km_kbp_state_imx_deregister_callback: + * * De-register IMX callback endpoint for the client. + * + * Returns: -- */ KMN_API void km_kbp_state_imx_deregister_callback(km_kbp_state *state); @@ -1042,6 +1055,8 @@ enum km_kbp_tech_value { }; /** + * km_kbp_event_flags: + * * Bit flags to be used with the event_flags parameter of km_kbp_process_event */ enum km_kbp_event_flags { @@ -1162,10 +1177,8 @@ km_kbp_event( ); enum km_kbp_event_code { - /** - * A keyboard has been activated by the user. The processor may use this - * event, for example, to switch caps lock state or provide other UX. - */ + // A keyboard has been activated by the user. The processor may use this + // event, for example, to switch caps lock state or provide other UX. KM_KBP_EVENT_KEYBOARD_ACTIVATED = 1, //future: KM_KBP_EVENT_KEYBOARD_DEACTIVATED = 2, }; -- GitLab From 36502ee9b420774c8aa5115433a690961e5d5883 Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Fri, 2 Jun 2023 14:03:15 -0400 Subject: [PATCH 193/214] auto: increment master version to 17.0.117 --- HISTORY.md | 9 +++++++++ VERSION.md | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index e2c639b852..03c58a8485 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,14 @@ # Keyman Version History +## 17.0.116 alpha 2023-06-02 + +* feat(linux): Add column for installation location (#8897) +* chore(developer): verify kvks files and report errors (#8892) +* refactor(developer): rearrange kmcmplib interface source (#8899) +* refactor(developer): move filename consistency check to kmc (#8907) +* chore(developer): loadFile callback error check and optimization (#8908) +* chore(common): remove url module ref from common/web/types (#8914) + ## 17.0.115 alpha 2023-06-01 * refactor(developer): complete fs move out of kmcmplib (#8882) diff --git a/VERSION.md b/VERSION.md index ce5446d392..52e25d110a 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.116 \ No newline at end of file +17.0.117 \ No newline at end of file -- GitLab From 80e6c2888f85ff5b28eb7be80e5b80528ec2fa4a Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Sun, 4 Jun 2023 14:02:04 -0400 Subject: [PATCH 194/214] auto: increment master version to 17.0.118 --- HISTORY.md | 4 ++++ VERSION.md | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 03c58a8485..2b501ebd15 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,9 @@ # Keyman Version History +## 17.0.117 alpha 2023-06-04 + +* chore(developer): verify long lines compile correctly (#8915) + ## 17.0.116 alpha 2023-06-02 * feat(linux): Add column for installation location (#8897) diff --git a/VERSION.md b/VERSION.md index 52e25d110a..2398e0d103 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.117 \ No newline at end of file +17.0.118 \ No newline at end of file -- GitLab From 18a3ef36bc6b8fe9c3954b90c69f4fdb5f8e720f Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 5 Jun 2023 15:46:40 +0700 Subject: [PATCH 195/214] chore(developer): ensure kmcmplib messages are all UTF-8 Fixes #8887. --- .../cerr_duplicate_group.kmn | 30 +++++++++++++++++++ .../cerr_duplicate_store.kmn | 13 ++++++++ developer/src/kmc-kmn/test/test-messages.ts | 14 +++++++++ developer/src/kmcmplib/include/kmcmplibapi.h | 8 +++-- .../src/kmcmplib/src/CheckForDuplicates.cpp | 6 ++-- developer/src/kmcmplib/src/Compiler.cpp | 3 +- .../src/kmcmplib/src/UnreachableRules.cpp | 3 +- developer/src/kmcmplib/src/kmcmplib.h | 2 -- 8 files changed, 67 insertions(+), 12 deletions(-) create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/cerr_duplicate_group.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/cerr_duplicate_store.kmn diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/cerr_duplicate_group.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/cerr_duplicate_group.kmn new file mode 100644 index 0000000000..8382b5ea7f --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/cerr_duplicate_group.kmn @@ -0,0 +1,30 @@ +c Description: Verifies that kmcmplib picks up on duplicated groups with Unicode names, +c and that the Unicode names are correctly reported in error messages in UTF-8 + +store(&NAME) 'cerr_duplicate_group' +store(&VERSION) '9.0' + +begin unicode > use(ខ្មែរ) + +group(ខ្មែរ) using keys + +store(c_key) [K_K] [K_X] [SHIFT K_K] [SHIFT K_X] [K_G] \ + [K_C] [K_Q] [SHIFT K_C] [SHIFT K_Q] [SHIFT K_J] \ + [K_D] [K_Z] [SHIFT K_D] [SHIFT K_Z] [SHIFT K_N] \ + [K_T] [K_F] [SHIFT K_T] [SHIFT K_F] [K_N] \ + [K_B] [K_P] [SHIFT K_B] [SHIFT K_P] [K_M] \ + [K_Y] [K_R] [K_L] [K_V] [K_S] [K_H] [SHIFT K_L] [SHIFT K_G] \ + [RALT K_K] [RALT K_B] +store(c_out) U+1780 U+1781 U+1782 U+1783 U+1784 \ + U+1785 U+1786 U+1787 U+1788 U+1789 \ + U+178A U+178B U+178C U+178D U+178E \ + U+178F U+1790 U+1791 U+1792 U+1793 \ + U+1794 U+1795 U+1796 U+1797 U+1798 \ + U+1799 U+179A U+179B U+179C U+179F U+17A0 U+17A1 U+17A2 \ + U+179D U+179E c deprecated, but they are used in minority languages + ++ any(c_key) > index(c_out, 1) + +group(ខ្មែរ) using keys + ++ 'a' > 'oops two groups!' diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/cerr_duplicate_store.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/cerr_duplicate_store.kmn new file mode 100644 index 0000000000..14d27d5be6 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/cerr_duplicate_store.kmn @@ -0,0 +1,13 @@ +c Description: Verifies that kmcmplib picks up on duplicated stores with Unicode names, +c and that the Unicode names are correctly reported in error messages in UTF-8 + +store(&NAME) 'cerr_duplicate_store' +store(&VERSION) '9.0' + +begin unicode > use(ខ្មែរ) + +group(ខ្មែរ) using keys + +store(ខ្មែរ) 'abc' +store(ខ្មែរ) 'def' + diff --git a/developer/src/kmc-kmn/test/test-messages.ts b/developer/src/kmc-kmn/test/test-messages.ts index 4d724daaf5..c551e1f223 100644 --- a/developer/src/kmc-kmn/test/test-messages.ts +++ b/developer/src/kmc-kmn/test/test-messages.ts @@ -52,4 +52,18 @@ describe('CompilerMessages', function () { await testForMessage(this, ['invalid-keyboards', 'warn_invalid_vkey_in_kvks_file.kmn'], CompilerMessages.WARN_InvalidVkeyInKvksFile); }); + // CERR_DuplicateGroup + + it('should generate CERR_DuplicateGroup if the kmn contains two groups with the same name', async function() { + await testForMessage(this, ['invalid-keyboards', 'cerr_duplicate_group.kmn'], 0x302071); //TODO: consolidate messages from kmcmplib, CompilerMessages.CERR_DuplicateGroup + assert.equal(callbacks.messages[0].message, "A group with this name has already been defined. Group 'ខ្មែរ' declared on line 9"); + }); + + // CERR_DuplicateStore + + it('should generate CERR_DuplicateStore if the kmn contains two stores with the same name', async function() { + await testForMessage(this, ['invalid-keyboards', 'cerr_duplicate_store.kmn'], 0x302072); //TODO: consolidate messages from kmcmplib, CompilerMessages.CERR_DuplicateStore + assert.equal(callbacks.messages[0].message, "A store with this name has already been defined. Store 'ខ្មែរ' declared on line 11"); + }); + }); diff --git a/developer/src/kmcmplib/include/kmcmplibapi.h b/developer/src/kmcmplib/include/kmcmplibapi.h index 0b41af6990..f37e393eea 100644 --- a/developer/src/kmcmplib/include/kmcmplibapi.h +++ b/developer/src/kmcmplib/include/kmcmplibapi.h @@ -35,7 +35,9 @@ struct KMCMP_COMPILER_RESULT { std::string kvksFilename; }; -// TODO: parameters in UTF-8 #8887 +/** + * @param szText UTF-8 string +*/ typedef int (*kmcmp_CompilerMessageProc)(int line, uint32_t dwMsgCode, const char* szText, void* context); // parameters in UTF-8 @@ -50,7 +52,9 @@ typedef int (*kmcmp_CompilerMessageProc)(int line, uint32_t dwMsgCode, const cha // } typedef bool (*kmcmp_LoadFileProc)(const char* loadFilename, const char* baseFilename, void* buffer, int* bufferSize, void* context); -// Parameters in UTF-8 +/** + * @param pszInfile UTF-8 path to file.kmn + */ EXTERN bool kmcmp_CompileKeyboard( const char* pszInfile, const KMCMP_COMPILER_OPTIONS& options, diff --git a/developer/src/kmcmplib/src/CheckForDuplicates.cpp b/developer/src/kmcmplib/src/CheckForDuplicates.cpp index 71268a4db5..56b6195fb4 100644 --- a/developer/src/kmcmplib/src/CheckForDuplicates.cpp +++ b/developer/src/kmcmplib/src/CheckForDuplicates.cpp @@ -18,8 +18,7 @@ KMX_DWORD CheckForDuplicateGroup(PFILE_KEYBOARD fk, PFILE_GROUP gp) noexcept { continue; } if (u16icmp(gp0->szName, gp->szName) == 0) { - u16sprintf(ErrExtraW, 256, L" Group '%ls' declared on line %d", u16fmt(gp0->szName).c_str(), gp0->Line); - strcpy(ErrExtraLIB, string_from_u16string(ErrExtraW).c_str()); + snprintf(ErrExtraLIB, ERR_EXTRA_LIB_LEN, " Group '%s' declared on line %d", string_from_u16string(gp->szName).c_str(), gp0->Line); return CERR_DuplicateGroup; } } @@ -39,8 +38,7 @@ KMX_DWORD CheckForDuplicateStore(PFILE_KEYBOARD fk, PFILE_STORE sp) noexcept { continue; } if (u16icmp(sp0->szName, sp->szName) == 0) { - u16sprintf(ErrExtraW,256, L" Store '%ls' declared on line %d", u16fmt(sp0->szName).c_str(), sp0->line); - strcpy(ErrExtraLIB, string_from_u16string(ErrExtraW).c_str()); + snprintf(ErrExtraLIB, ERR_EXTRA_LIB_LEN, " Store '%s' declared on line %d", string_from_u16string(sp0->szName).c_str(), sp0->line); return CERR_DuplicateStore; } } diff --git a/developer/src/kmcmplib/src/Compiler.cpp b/developer/src/kmcmplib/src/Compiler.cpp index e5d5f94cbc..1a28aab000 100644 --- a/developer/src/kmcmplib/src/Compiler.cpp +++ b/developer/src/kmcmplib/src/Compiler.cpp @@ -111,8 +111,7 @@ using namespace kmcmp; - char ErrExtraLIB[ERR_EXTRA_LIB_LEN]; - KMX_WCHAR ErrExtraW[ERR_EXTRA_W_LEN]; + char ErrExtraLIB[ERR_EXTRA_LIB_LEN]; // utf-8 KMX_BOOL AWarnDeprecatedCode_GLOBAL_LIB; namespace kmcmp{ diff --git a/developer/src/kmcmplib/src/UnreachableRules.cpp b/developer/src/kmcmplib/src/UnreachableRules.cpp index 9c6aaa23ad..d8980599a2 100644 --- a/developer/src/kmcmplib/src/UnreachableRules.cpp +++ b/developer/src/kmcmplib/src/UnreachableRules.cpp @@ -41,8 +41,7 @@ KMX_DWORD VerifyUnreachableRules(PFILE_GROUP gp) { if (kp->Line != k1.Line && reportedLines.count(kp->Line) == 0) { reportedLines.insert(kp->Line); kmcmp::currentLine = kp->Line; - u16sprintf(ErrExtraW, ERR_EXTRA_W_LEN, L" Overridden by rule on line %d", k1.Line); - strcpy(ErrExtraLIB, string_from_u16string(ErrExtraW).c_str()); + snprintf(ErrExtraLIB, ERR_EXTRA_LIB_LEN, " Overridden by rule on line %d", k1.Line); AddWarning(CHINT_UnreachableRule); } } diff --git a/developer/src/kmcmplib/src/kmcmplib.h b/developer/src/kmcmplib/src/kmcmplib.h index f22c836bae..0d7c4f9004 100644 --- a/developer/src/kmcmplib/src/kmcmplib.h +++ b/developer/src/kmcmplib/src/kmcmplib.h @@ -28,9 +28,7 @@ extern void* msgprocContext; extern KMX_BOOL AWarnDeprecatedCode_GLOBAL_LIB; #define ERR_EXTRA_LIB_LEN 256 -#define ERR_EXTRA_W_LEN 256 extern char ErrExtraLIB[ERR_EXTRA_LIB_LEN]; -extern KMX_WCHAR ErrExtraW[ERR_EXTRA_W_LEN]; KMX_BOOL AddCompileError(KMX_DWORD msg); /// Use AddWarningBool for functions that return bool or KMX_BOOL -- GitLab From 9d85712039d8ddb5300a61a2ed6d200ee1a37d12 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 5 Jun 2023 16:10:57 +0700 Subject: [PATCH 196/214] chore(developer): rollback unneeded kmcomp changes --- common/windows/cpp/include/legacy_kmx_file.h | 3 +- .../src/common/delphi/compiler/compile.pas | 29 +------------------ developer/src/kmcmpdll/Compiler.cpp | 7 +---- developer/src/kmcomp/kmcomp.dproj | 2 +- 4 files changed, 4 insertions(+), 37 deletions(-) diff --git a/common/windows/cpp/include/legacy_kmx_file.h b/common/windows/cpp/include/legacy_kmx_file.h index dbc81328c8..d961250912 100644 --- a/common/windows/cpp/include/legacy_kmx_file.h +++ b/common/windows/cpp/include/legacy_kmx_file.h @@ -415,8 +415,7 @@ typedef COMPILER_OPTIONS *PCOMPILER_OPTIONS; typedef int (CALLBACK *CompilerMessageProc)(int line, DWORD dwMsgCode, LPSTR szText); -extern "C" BOOL __declspec(dllexport) CompileKeyboardFile(PSTR pszInfile, PSTR pszOutfile, BOOL FSaveDebug, BOOL ACompilerWarningsAsErrors, BOOL AWarnDeprecatedCode, CompilerMessageProc pMsgProc); // I4865 // I4866 -extern "C" BOOL __declspec(dllexport) CompileKeyboardFileEx(PSTR pszInfile, PSTR pszOutfile, BOOL ASaveDebug, BOOL ACompilerWarningsAsErrors, BOOL AWarnDeprecatedCode, CompilerMessageProc pMsgProc, int Target); +//extern "C" BOOL __declspec(dllexport) CompileKeyboardFile(PSTR pszInfile, PSTR pszOutfile, BOOL FSaveDebug, BOOL ACompilerWarningsAsErrors, BOOL AWarnDeprecatedCode, CompilerMessageProc pMsgProc); // I4865 // I4866 #endif // _COMPILER_H diff --git a/developer/src/common/delphi/compiler/compile.pas b/developer/src/common/delphi/compiler/compile.pas index aeaf3cf8df..0124150ef6 100644 --- a/developer/src/common/delphi/compiler/compile.pas +++ b/developer/src/common/delphi/compiler/compile.pas @@ -143,7 +143,6 @@ type const CKF_KEYMAN = 0; CKF_KEYMANWEB = 1; - // CKF_KEYMANWEB_MODERN = 2; // used only by Typescript-based compiler const CERR_FATAL = $00008000; @@ -170,7 +169,6 @@ const function CompileKeyboardFile(kmnFile, kmxFile: PChar; FSaveDebug, CompilerWarningsAsErrors, WarnDeprecatedCode: BOOL; CallBack: TCompilerCallback): Integer; cdecl; // I4865 // I4866 function CompileKeyboardFileToBuffer(kmnFile: PChar; buf: PFILE_KEYBOARD; CompilerWarningsAsErrors, WarnDeprecatedCode: BOOL; CallBack: TCompilerCallback; Target: Integer): Integer; cdecl; // I4865 // I4866 -function CompileKeyboardFileEx(kmnFile, kmxfile: PChar; FSaveDebug, CompilerWarningsAsErrors, WarnDeprecatedCode: BOOL; CallBack: TCompilerCallback; Target: Integer): Integer; // I4865 // I4866 function Compiler_Diagnostic(mode: Integer): Integer; procedure Compiler_Diagnostic_Console(mode: Integer); @@ -203,18 +201,13 @@ var HKMCmpDll: THandle = 0; type - TCompileKeyboardFile = function (kmnFile, kmxFile: PAnsiChar; - FSaveDebug, CompilerWarningsAsErrors, WarnDeprecatedCode: BOOL; // I3310 // I4865 // I4866 + TCompileKeyboardFile = function (kmnFile, kmxFile: PAnsiChar; FSaveDebug, CompilerWarningsAsErrors, WarnDeprecatedCode: BOOL; // I3310 // I4865 // I4866 CallBack: TCompilerCallback): Integer; cdecl; // TODO: K9: Convert to Unicode TCompileKeyboardFileToBuffer = function (kmnFile: PAnsiChar; buf: PFILE_KEYBOARD; // I3310 CompilerWarningsAsErrors, WarnDeprecatedCode: BOOL; // I4865 // I4866 CallBack: TCompilerCallback; Target: Integer): Integer; cdecl; // TODO: K9: Convert to Unicode - TCompileKeyboardFileEx = function (kmnFile, kmxFile: PAnsiChar; - FSaveDebug, CompilerWarningsAsErrors, WarnDeprecatedCode: BOOL; - CallBack: TCompilerCallback; Target: Integer): Integer; cdecl; // TODO: K9: Convert to Unicode - TSetCompilerOptions = function (options: PCOMPILER_OPTIONS): BOOL; cdecl; function LoadCompiler(CallBack: TCompilerCallback = nil): Boolean; @@ -311,26 +304,6 @@ begin Result := ckf(PAnsiChar(AnsiString(kmnFile)), buf, CompilerWarningsAsErrors, WarnDeprecatedCode, Callback, Target); // I3310 // I4865 // I4866 end; -function CompileKeyboardFileEx(kmnFile, kmxfile: PChar; FSaveDebug, CompilerWarningsAsErrors, WarnDeprecatedCode: BOOL; CallBack: TCompilerCallback; Target: Integer): Integer; // I4865 // I4866 -var - ckf: TCompileKeyboardFileEx; -begin - //Result := 0; - - if not LoadCompiler(Callback) then Exit(-1); - - @ckf := GetProcAddress(HKMCmpDll, 'CompileKeyboardFileEx'); - if not Assigned(@ckf) then - begin - Callback(0, $8000, PAnsiChar(AnsiString('Could not access the compiler. Check that '+kmcmpdll_lib+' is in the program directory '+ // I4706 - 'and that it is not corrupt.'#13#10+'Windows error message: '+SysErrorMessage(GetLastError)))); - Result := -1; - Exit; - end; - - Result := ckf(PAnsiChar(AnsiString(kmnFile)), PAnsiChar(AnsiString(kmxfile)), FSaveDebug, CompilerWarningsAsErrors, WarnDeprecatedCode, Callback, Target); // I3310 // I4865 // I4866 -end; - type TKeyman_Diagnostic = procedure(mode: Integer); cdecl; diff --git a/developer/src/kmcmpdll/Compiler.cpp b/developer/src/kmcmpdll/Compiler.cpp index 23e23e791b..100e43fc5b 100644 --- a/developer/src/kmcmpdll/Compiler.cpp +++ b/developer/src/kmcmpdll/Compiler.cpp @@ -299,11 +299,6 @@ extern "C" BOOL __declspec(dllexport) SetCompilerOptions(PCOMPILER_OPTIONS optio } extern "C" BOOL __declspec(dllexport) CompileKeyboardFile(PSTR pszInfile, PSTR pszOutfile, BOOL ASaveDebug, BOOL ACompilerWarningsAsErrors, BOOL AWarnDeprecatedCode, CompilerMessageProc pMsgProc) // I4865 // I4866 -{ - return CompileKeyboardFileEx(pszInfile, pszOutfile, ASaveDebug, ACompilerWarningsAsErrors, AWarnDeprecatedCode, pMsgProc, CKF_KEYMAN); -} - -extern "C" BOOL __declspec(dllexport) CompileKeyboardFileEx(PSTR pszInfile, PSTR pszOutfile, BOOL ASaveDebug, BOOL ACompilerWarningsAsErrors, BOOL AWarnDeprecatedCode, CompilerMessageProc pMsgProc, int Target) // I4865 // I4866 { HANDLE hInfile = INVALID_HANDLE_VALUE, hOutfile = INVALID_HANDLE_VALUE; BOOL err; @@ -314,7 +309,7 @@ extern "C" BOOL __declspec(dllexport) CompileKeyboardFileEx(PSTR pszInfile, PSTR FCompilerWarningsAsErrors = ACompilerWarningsAsErrors; // I4865 FWarnDeprecatedCode = AWarnDeprecatedCode; // I4866 - CompileTarget = Target; + CompileTarget = CKF_KEYMAN; if (!pMsgProc || !pszInfile || !pszOutfile) SetError(CERR_BadCallParams); diff --git a/developer/src/kmcomp/kmcomp.dproj b/developer/src/kmcomp/kmcomp.dproj index 9bb6af3b5c..36c16e3535 100644 --- a/developer/src/kmcomp/kmcomp.dproj +++ b/developer/src/kmcomp/kmcomp.dproj @@ -109,7 +109,7 @@ RELEASE;$(DCC_Define)
- \Projects\keyman\keyboards\release\k\khmer_angkor\source\khmer_angkor.kmn c:\temp\ka.js + c:\temp\foo.kps -schema-path C:\Projects\keyman\app\common\schemas\kps\ true 2 1033 -- GitLab From eab503a8292f2b9e52a9ff64158815013a5c2561 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 5 Jun 2023 16:19:41 +0700 Subject: [PATCH 197/214] chore(developer): roll back CKF_KEYMANWEB_MODERN, not needed --- developer/src/kmcmplib/include/kmcmplibapi.h | 3 +-- developer/src/kmcmplib/src/Compiler.cpp | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/developer/src/kmcmplib/include/kmcmplibapi.h b/developer/src/kmcmplib/include/kmcmplibapi.h index 2b28aaa2d3..0b41af6990 100644 --- a/developer/src/kmcmplib/include/kmcmplibapi.h +++ b/developer/src/kmcmplib/include/kmcmplibapi.h @@ -19,8 +19,7 @@ /* Compile target */ #define CKF_KEYMAN 0 -#define CKF_KEYMANWEB 1 // For legacy kmcomp compiler, to be deprecated and removed -#define CKF_KEYMANWEB_MODERN 2 // For Typescript kmc-kmw compiler +#define CKF_KEYMANWEB 1 struct KMCMP_COMPILER_OPTIONS { bool saveDebug; diff --git a/developer/src/kmcmplib/src/Compiler.cpp b/developer/src/kmcmplib/src/Compiler.cpp index 322230a3e9..e5d5f94cbc 100644 --- a/developer/src/kmcmplib/src/Compiler.cpp +++ b/developer/src/kmcmplib/src/Compiler.cpp @@ -1212,7 +1212,7 @@ KMX_DWORD CheckStatementOffsets(PFILE_KEYBOARD fk, PFILE_GROUP gp, PKMX_WCHAR co // Due to a limitation in earlier versions of KeymanWeb, the minimum version // for context() referring to notany() is 14.0. See #917 for details. - if (kmcmp::CompileTarget != CKF_KEYMAN) { + if (kmcmp::CompileTarget == CKF_KEYMANWEB) { for (q = context, i = 1; *q && i < contextOffset; q = incxstr(q), i++); if (*q == UC_SENTINEL && *(q + 1) == CODE_NOTANY) { VERIFY_KEYBOARD_VERSION(fk, VERSION_140, CERR_140FeatureOnlyContextAndNotAnyWeb); @@ -1665,7 +1665,7 @@ int LineTokenType(PKMX_WCHAR *str) /* Test KeymanWeb, Keyman and KeymanOnly prefixes */ if (kmcmp::CompileTarget == CKF_KEYMAN && lpt == lptKeymanWebOnly) return T_BLANK; - if (kmcmp::CompileTarget != CKF_KEYMAN && lpt == lptKeymanOnly) return T_BLANK; + if (kmcmp::CompileTarget == CKF_KEYMANWEB && lpt == lptKeymanOnly) return T_BLANK; while (iswspace(*p)) p++; @@ -2146,7 +2146,7 @@ KMX_DWORD GetXStringImpl(PKMX_WCHAR tstr, PFILE_KEYBOARD fk, PKMX_WCHAR str, KMX // in the web target platform, even if there are platform() rules excluding this possibility. In that (rare) situation, the keyboard developer should simply specify // the &version to be 9.0 or whatever to avoid this behaviour. if (sFlag & (LCTRLFLAG | LALTFLAG | RCTRLFLAG | RALTFLAG | CAPITALFLAG | NOTCAPITALFLAG | NUMLOCKFLAG | NOTNUMLOCKFLAG | SCROLLFLAG | NOTSCROLLFLAG) && - kmcmp::CompileTarget != CKF_KEYMAN && + kmcmp::CompileTarget == CKF_KEYMANWEB && fk->dwFlags & KF_AUTOMATICVERSION) { VERIFY_KEYBOARD_VERSION(fk, VERSION_100, 0); } -- GitLab From 91f985de03ac9a349a7d3686845dd56fcde04d10 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 5 Jun 2023 16:33:38 +0700 Subject: [PATCH 198/214] chore(developer): cleanup build.sh --- developer/src/kmc-kmw/build.sh | 69 +++++++++++++++------------------- 1 file changed, 31 insertions(+), 38 deletions(-) diff --git a/developer/src/kmc-kmw/build.sh b/developer/src/kmc-kmw/build.sh index aa712d10ce..1e43793b16 100755 --- a/developer/src/kmc-kmw/build.sh +++ b/developer/src/kmc-kmw/build.sh @@ -1,31 +1,26 @@ #!/usr/bin/env bash -# -# Compiles the kmc KeymanWeb keyboard compiler. -# - -# Exit on command failure and when using unset variables: -set -eu - ## START STANDARD BUILD SCRIPT INCLUDE # adjust relative paths as necessary -THIS_SCRIPT="$(greadlink -f "${BASH_SOURCE[0]}" 2>/dev/null || readlink -f "${BASH_SOURCE[0]}")" -. "$(dirname "$THIS_SCRIPT")/../../../resources/build/build-utils.sh" +THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" +. "${THIS_SCRIPT%/*}/../../../resources/build/build-utils.sh" ## END STANDARD BUILD SCRIPT INCLUDE cd "$THIS_SCRIPT_PATH" . "$KEYMAN_ROOT/resources/shellHelperFunctions.sh" +. "$KEYMAN_ROOT/resources/build/build-utils-ci.inc.sh" builder_describe "Build Keyman kmc KMW Keyboard Compiler module" \ - "@/common/web/keyman-version" \ "@/common/web/types" \ "@/developer/src/kmc-kmn" \ "configure" \ "build" \ "clean" \ "test" \ + "pack build a local .tgz pack for testing" \ "publish publish to npm" \ "--dry-run,-n don't actually publish, just dry run" + builder_describe_outputs \ configure /node_modules \ build build/src/main.js @@ -34,42 +29,40 @@ builder_parse "$@" #------------------------------------------------------------------------------------------------------------------- -if builder_start_action clean; then - rm -rf ./build/ ./tsconfig.tsbuildinfo - builder_finish_action success clean -else - # We need the schema file at runtime and bundled, so always copy it for all actions except `clean` +function copy_schema() { + # We need the schema file at runtime and bundled, so always copy it for all + # actions except `clean` and `configure` mkdir -p "$THIS_SCRIPT_PATH/build/src/" cp "$KEYMAN_ROOT/common/schemas/keyman-touch-layout/keyman-touch-layout.spec.json" "$THIS_SCRIPT_PATH/build/src/" cp "$KEYMAN_ROOT/common/schemas/kvks/kvks.schema.json" "$THIS_SCRIPT_PATH/build/src/" -fi - -#------------------------------------------------------------------------------------------------------------------- - -if builder_start_action configure; then - verify_npm_setup - builder_finish_action success configure -fi +} -#------------------------------------------------------------------------------------------------------------------- - -if builder_start_action build; then +function do_build() { + copy_schema npm run build - builder_finish_action success build -fi - -#------------------------------------------------------------------------------------------------------------------- +} -if builder_start_action test; then +function do_test() { # TODO: add c8 for coverage + copy_schema npm test - builder_finish_action success test -fi +} + +function do_publish() { + copy_schema + builder_publish_to_npm +} + +function do_pack() { + copy_schema + builder_publish_to_pack +} #------------------------------------------------------------------------------------------------------------------- -if builder_start_action publish; then - . "$KEYMAN_ROOT/resources/build/npm-publish.inc.sh" - npm_publish - builder_finish_action success publish -fi +builder_run_action clean rm -rf ./build/ ./tsconfig.tsbuildinfo +builder_run_action configure verify_npm_setup +builder_run_action build do_build +builder_run_action test do_test +builder_run_action pack do_pack +builder_run_action publish do_publish -- GitLab From eaf7a6b6287561daafff242f19a712c931599b46 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 5 Jun 2023 16:34:23 +0700 Subject: [PATCH 199/214] chore(developer): merge changed interfaces in compiler --- common/web/types/src/main.ts | 2 +- .../src/kmc-kmw/src/compiler/write-compiled-keyboard.ts | 5 ++--- developer/src/kmc-kmw/test/test-compiler-manual.ts | 8 ++++---- developer/src/kmc-kmw/test/test-compiler.ts | 8 ++++---- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/common/web/types/src/main.ts b/common/web/types/src/main.ts index 9e65ccb99a..ddaa318d3e 100644 --- a/common/web/types/src/main.ts +++ b/common/web/types/src/main.ts @@ -7,7 +7,7 @@ export { KmxFileReader } from './kmx/kmx-file-reader.js'; export * as VisualKeyboard from './kvk/visual-keyboard.js'; export { default as KMXPlusBuilder} from './kmx/kmx-plus-builder/kmx-plus-builder.js'; export { default as KvkFileReader } from './kvk/kvk-file-reader.js'; -export { default as KvksFileReader, KVKSParseError } from './kvk/kvks-file-reader.js'; +export { default as KvksFileReader } from './kvk/kvks-file-reader.js'; export { default as KvkFileWriter } from './kvk/kvk-file-writer.js'; export * as KvkFile from './kvk/kvk-file.js'; export * as KvksFile from './kvk/kvk-file.js'; diff --git a/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts b/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts index 7e89aa7cdd..082c7a1881 100644 --- a/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts +++ b/developer/src/kmc-kmw/src/compiler/write-compiled-keyboard.ts @@ -1,4 +1,4 @@ -import { KVKSParseError, VisualKeyboard } from "@keymanapp/common-types"; +import { VisualKeyboard } from "@keymanapp/common-types"; import { KMX, CompilerCallbacks, KvkFileReader, KvksFileReader } from "@keymanapp/common-types"; import { ExpandSentinel, incxstr, xstrlen } from "../util/util.js"; // import { KEY, KEYBOARD, KMX.KMXFile, STORE } from "../../../../../common/web/types/src/kmx/kmx.js"; @@ -202,8 +202,7 @@ export function WriteCompiledKeyboard(callbacks: CompilerCallbacks, kmnfile: str let reader = new KvksFileReader(); let source = reader.read(callbacks.loadFile(path)); reader.validate(source, callbacks.loadSchema("kvks")); // TODO: handle exceptions - let errors: KVKSParseError[]; - kvk = reader.transform(source, errors); + kvk = reader.transform(source); // TODO: log errors } else { diff --git a/developer/src/kmc-kmw/test/test-compiler-manual.ts b/developer/src/kmc-kmw/test/test-compiler-manual.ts index 9f4f5ea4db..39869657f4 100644 --- a/developer/src/kmc-kmw/test/test-compiler-manual.ts +++ b/developer/src/kmc-kmw/test/test-compiler-manual.ts @@ -2,7 +2,7 @@ import { dirname } from 'path'; import { fileURLToPath } from 'url'; import fs from 'fs'; import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; -import { Compiler } from '@keymanapp/kmc-kmn'; +import { KmnCompiler } from '@keymanapp/kmc-kmn'; import { KMX, KmxFileReader } from '@keymanapp/common-types'; import { WriteCompiledKeyboard } from '../src/compiler/write-compiled-keyboard.js'; import { extractTouchLayout } from './util.js'; @@ -20,14 +20,14 @@ if(fs.existsSync(testOutfile)) { const callbacks = new TestCompilerCallbacks(); -const kmxCompiler = new Compiler(); -if(!await kmxCompiler.init()) { +const kmnCompiler = new KmnCompiler(); +if(!await kmnCompiler.init(callbacks)) { console.error('kmx compiler failed to init'); process.exit(1); } // TODO: runToMemory, add option to kmxCompiler to store debug-data for conversion to .js (e.g. store metadata, group readonly metadata, etc) -if(!kmxCompiler.run(infile, outfile, callbacks, { +if(!kmnCompiler.run(infile, outfile, { shouldAddCompilerVersion: false, saveDebug: true, target: 'js' diff --git a/developer/src/kmc-kmw/test/test-compiler.ts b/developer/src/kmc-kmw/test/test-compiler.ts index 7332d71bda..7f086ca0ad 100644 --- a/developer/src/kmc-kmw/test/test-compiler.ts +++ b/developer/src/kmc-kmw/test/test-compiler.ts @@ -6,7 +6,7 @@ import { dirname } from 'path'; import { fileURLToPath } from 'url'; import fs from 'fs'; import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; -import { Compiler } from '@keymanapp/kmc-kmn'; +import { KmnCompiler } from '@keymanapp/kmc-kmn'; import { KMX, KmxFileReader } from '@keymanapp/common-types'; import { extractTouchLayout } from './util.js'; @@ -35,11 +35,11 @@ describe('Compiler class', function() { fs.unlinkSync(testOutfile); } - const kmxCompiler = new Compiler(); - assert.isTrue(await kmxCompiler.init()); + const kmnCompiler = new KmnCompiler(); + assert.isTrue(await kmnCompiler.init(callbacks)); // TODO: runToMemory, add option to kmxCompiler to store debug-data for conversion to .js (e.g. store metadata, group readonly metadata, visual keyboard source filename, etc) - assert.isTrue(kmxCompiler.run(infile, outfile, callbacks, { + assert.isTrue(kmnCompiler.run(infile, outfile, { shouldAddCompilerVersion: false, saveDebug: true, target: 'js' -- GitLab From 749112660dad7ce1a8bf5e82a2bfedc3ca5188f2 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 2 Jun 2023 17:04:58 +0200 Subject: [PATCH 200/214] chore(linux): Move some files to keyman-config Some of the configuration files are useful for other distributions as well. So this change moves them out of `debian/` to `linux/keyman-config` so that they will be included in the source tar ball. Also remove zero-width space from one file. Closes #8880. --- linux/debian/com.keyman.config.appdata.xml | 6 +-- .../com.keyman.ibus_keyman.metainfo.xml | 50 +++++++++---------- linux/debian/keyman.install | 4 +- linux/debian/rules | 1 + linux/ibus-keyman/src/test/run-tests.sh | 2 +- .../tests/scripts/test-helper.inc.sh | 2 +- linux/keyman-config/MANIFEST.in | 2 +- linux/keyman-config/build.sh | 2 +- linux/keyman-config/createkeymandirs.sh | 8 --- .../{ => resources}/com.keyman.gschema.xml | 0 .../resources}/keyman.sharedmimeinfo | 0 .../{ => resources}/km-config.desktop | 0 linux/scripts/install.sh | 2 +- 13 files changed, 36 insertions(+), 43 deletions(-) delete mode 100755 linux/keyman-config/createkeymandirs.sh rename linux/keyman-config/{ => resources}/com.keyman.gschema.xml (100%) rename linux/{debian => keyman-config/resources}/keyman.sharedmimeinfo (100%) rename linux/keyman-config/{ => resources}/km-config.desktop (100%) diff --git a/linux/debian/com.keyman.config.appdata.xml b/linux/debian/com.keyman.config.appdata.xml index f137be461d..9df49a37dc 100644 --- a/linux/debian/com.keyman.config.appdata.xml +++ b/linux/debian/com.keyman.config.appdata.xml @@ -14,8 +14,8 @@

Keyman makes it possible for you to type in over 2,000 languages on Windows, macOS, Linux, iPhone, iPad, Android tablets and phones, and even instantly in your web browser. With the -world’s most powerful keyboarding engine, intuitive and rapid text input is now possible in -your language, and for over 99% of the global population’s mother tongues! +world's most powerful keyboarding engine, intuitive and rapid text input is now possible in +your language, and for over 99% of the global population's mother tongues!

Originally created in 1993 to type Lao on Windows, Keyman is now a free and @@ -40,7 +40,7 @@ and mobile platforms. The Keyman for Linux configuration window with a keyboard welcome window. - https://keyman.com/go/linux/11.0/linux-configuration.png + https://keyman.com/go/linux/17.0/linux-configuration.png diff --git a/linux/debian/com.keyman.ibus_keyman.metainfo.xml b/linux/debian/com.keyman.ibus_keyman.metainfo.xml index eb02001da0..1f021d2fce 100644 --- a/linux/debian/com.keyman.ibus_keyman.metainfo.xml +++ b/linux/debian/com.keyman.ibus_keyman.metainfo.xml @@ -1,39 +1,39 @@ -​ com.keyman.ibus_keyman -​ MIT + com.keyman.ibus_keyman + MIT GPL-2+ Keyman SIL International https://keyman.com/cdn/dev/img/keyman-logo.png -​ ibus-keyman -​

Keyman input method for IBus -​ -​

- This input method provides the Keyman IM engine for IBus. With this module, you can - use keyboard layouts designed for Keyman under the IBus platform. -

-

- Originally created in 1993 to type Lao on Windows, Keyman is now a free and - open source keyboarding platform which allows anyone to write a keyboard layout - for their language. Keyman is available for many platforms, including Windows, - macOS, iOS, Android, Linux and the web. -

+ ibus-keyman + Keyman input method for IBus +

- Keyboard layouts are defined with a clear and easy to understand keyboard - grammar. Keyman's contextual input model means keyboard layouts can be - intelligent and make it simple to type even the most complex languages. - Keyboard layouts are distributed through an open catalog to all major desktop - and mobile platforms. + This input method provides the Keyman IM engine for IBus. With this module, you can + use keyboard layouts designed for Keyman under the IBus platform. +

+

+ Originally created in 1993 to type Lao on Windows, Keyman is now a free and + open source keyboarding platform which allows anyone to write a keyboard layout + for their language. Keyman is available for many platforms, including Windows, + macOS, iOS, Android, Linux and the web. +

+

+ Keyboard layouts are defined with a clear and easy to understand keyboard + grammar. Keyman's contextual input model means keyboard layouts can be + intelligent and make it simple to type even the most complex languages. + Keyboard layouts are distributed through an open catalog to all major desktop + and mobile platforms. +

+

+ Input methods are typing systems allowing users to input complex languages.

-

-​ Input methods are typing systems allowing users to input complex languages. -​

-​
+
https://keyman.com/linux/ https://github.com/keymanapp/keyman/issues https://help.keyman.com/ https://community.software.sil.org/c/keyman https://donate.keyman.com/ -​ + diff --git a/linux/debian/keyman.install b/linux/debian/keyman.install index 8096e324ae..a036eb8a73 100644 --- a/linux/debian/keyman.install +++ b/linux/debian/keyman.install @@ -1,4 +1,3 @@ -linux/keyman-config/com.keyman.gschema.xml usr/share/glib-2.0/schemas/ linux/keyman-config/icons/128/km-config.png usr/share/icons/hicolor/128x128/apps/ linux/keyman-config/icons/16/application-x-kmp.png usr/share/icons/hicolor/16x16/mimetypes/ linux/keyman-config/icons/24/application-x-kmp.png usr/share/icons/hicolor/24x24/mimetypes/ @@ -10,5 +9,6 @@ linux/keyman-config/icons/48/km-config.png usr/share/icons/hicolor/48x48/apps/ linux/keyman-config/icons/64/application-x-kmp.png usr/share/icons/hicolor/64x64/mimetypes/ linux/keyman-config/icons/64/km-config.png usr/share/icons/hicolor/64x64/apps/ linux/keyman-config/keyman_config/icons/* usr/share/keyman/icons/ -linux/keyman-config/km-config.desktop usr/share/applications +linux/keyman-config/resources/com.keyman.gschema.xml usr/share/glib-2.0/schemas/ +linux/keyman-config/resources/km-config.desktop usr/share/applications debian/com.keyman.config.appdata.xml usr/share/metainfo diff --git a/linux/debian/rules b/linux/debian/rules index db1f925017..ec9178298c 100755 --- a/linux/debian/rules +++ b/linux/debian/rules @@ -37,6 +37,7 @@ override_dh_auto_configure: linux/keyman-config/build.sh configure override_dh_auto_build: + cp linux/keyman-config/resources/keyman.sharedmimeinfo debian/ core/build.sh --no-tests build:arch linux/ibus-keyman/build.sh build linux/keyman-system-service/build.sh build diff --git a/linux/ibus-keyman/src/test/run-tests.sh b/linux/ibus-keyman/src/test/run-tests.sh index 932f64b886..44a397582b 100755 --- a/linux/ibus-keyman/src/test/run-tests.sh +++ b/linux/ibus-keyman/src/test/run-tests.sh @@ -53,7 +53,7 @@ SCHEMA_DIR=$TEMP_DATA_DIR/glib-2.0/schemas export XDG_DATA_DIRS=$TEMP_DATA_DIR:$XDG_DATA_DIRS mkdir -p "$SCHEMA_DIR" -cp "$SRCDIR/../keyman-config/com.keyman.gschema.xml" "$SCHEMA_DIR/" +cp "$SRCDIR/../keyman-config/resources/com.keyman.gschema.xml" "$SCHEMA_DIR/" glib-compile-schemas "$SCHEMA_DIR" export GSETTINGS_BACKEND=memory diff --git a/linux/ibus-keyman/tests/scripts/test-helper.inc.sh b/linux/ibus-keyman/tests/scripts/test-helper.inc.sh index 930eb4fe2c..2a3735d708 100755 --- a/linux/ibus-keyman/tests/scripts/test-helper.inc.sh +++ b/linux/ibus-keyman/tests/scripts/test-helper.inc.sh @@ -183,7 +183,7 @@ function setup() { echo "export GSETTINGS_SCHEMA_DIR=\"$SCHEMA_DIR\"" >> "$ENV_FILE" mkdir -p "$SCHEMA_DIR" - cp "${TOP_SRCDIR}"/../keyman-config/com.keyman.gschema.xml "$SCHEMA_DIR"/ + cp "${TOP_SRCDIR}"/../keyman-config/resources/com.keyman.gschema.xml "$SCHEMA_DIR"/ glib-compile-schemas "$SCHEMA_DIR" export LD_LIBRARY_PATH=${COMMON_ARCH_DIR}/src:${LD_LIBRARY_PATH-} diff --git a/linux/keyman-config/MANIFEST.in b/linux/keyman-config/MANIFEST.in index e27020f36c..20705c6fc3 100644 --- a/linux/keyman-config/MANIFEST.in +++ b/linux/keyman-config/MANIFEST.in @@ -2,4 +2,4 @@ recursive-include keyman_config/icons * recursive-include icons * include README.md include *.bash-completion -include *.gschema.xml +include resources/*.gschema.xml diff --git a/linux/keyman-config/build.sh b/linux/keyman-config/build.sh index 1cb603f091..eaf77c05db 100755 --- a/linux/keyman-config/build.sh +++ b/linux/keyman-config/build.sh @@ -36,7 +36,7 @@ build_man_pages() { export XDG_DATA_DIRS=$TEMP_DATA_DIR:${XDG_DATA_DIRS-} export GSETTINGS_SCHEMA_DIR="${SCHEMA_DIR}" mkdir -p "$SCHEMA_DIR" - cp ./com.keyman.gschema.xml "$SCHEMA_DIR"/ + cp resources/com.keyman.gschema.xml "$SCHEMA_DIR"/ glib-compile-schemas "$SCHEMA_DIR" ./build-help.sh --man --no-reconf export XDG_DATA_DIRS=${XDG_DATA_DIRS#*:} diff --git a/linux/keyman-config/createkeymandirs.sh b/linux/keyman-config/createkeymandirs.sh deleted file mode 100755 index d9befe7f5d..0000000000 --- a/linux/keyman-config/createkeymandirs.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -sudo mkdir -p /usr/local/share/keyman -sudo mkdir -p /usr/local/share/fonts/keyman -sudo mkdir -p /usr/local/share/doc/keyman -sudo chmod 00777 /usr/local/share/keyman -sudo chmod 00777 /usr/local/share/fonts/keyman -sudo chmod 00777 /usr/local/share/doc/keyman diff --git a/linux/keyman-config/com.keyman.gschema.xml b/linux/keyman-config/resources/com.keyman.gschema.xml similarity index 100% rename from linux/keyman-config/com.keyman.gschema.xml rename to linux/keyman-config/resources/com.keyman.gschema.xml diff --git a/linux/debian/keyman.sharedmimeinfo b/linux/keyman-config/resources/keyman.sharedmimeinfo similarity index 100% rename from linux/debian/keyman.sharedmimeinfo rename to linux/keyman-config/resources/keyman.sharedmimeinfo diff --git a/linux/keyman-config/km-config.desktop b/linux/keyman-config/resources/km-config.desktop similarity index 100% rename from linux/keyman-config/km-config.desktop rename to linux/keyman-config/resources/km-config.desktop diff --git a/linux/scripts/install.sh b/linux/scripts/install.sh index 55074f4848..7e497232fc 100755 --- a/linux/scripts/install.sh +++ b/linux/scripts/install.sh @@ -53,7 +53,7 @@ if [[ "${SUDOINSTALL}" == "yes" ]]; then exit 1 fi echo "doing sudo glib-compile-schemas for keyman-config" - cp com.keyman.gschema.xml /usr/share/glib-2.0/schemas/ + cp resources/com.keyman.gschema.xml /usr/share/glib-2.0/schemas/ glib-compile-schemas /usr/share/glib-2.0/schemas/ echo "doing sudo install of keyman-config" ./build.sh install -- GitLab From cbc24f542178b3cd997c3ad15eb87df79feebbea Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 2 Jun 2023 17:18:14 +0200 Subject: [PATCH 201/214] chore(linux): Fix tests --- linux/keyman-config/build.sh | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/linux/keyman-config/build.sh b/linux/keyman-config/build.sh index eaf77c05db..2794544425 100755 --- a/linux/keyman-config/build.sh +++ b/linux/keyman-config/build.sh @@ -72,6 +72,21 @@ build_action() { python3 setup.py build } +test_action() { + local TEMP_DATA_DIR SCHEMA_DIR + TEMP_DATA_DIR=$(mktemp -d) + SCHEMA_DIR=$TEMP_DATA_DIR/glib-2.0/schemas + export XDG_DATA_DIRS=$TEMP_DATA_DIR:${XDG_DATA_DIRS-} + export GSETTINGS_SCHEMA_DIR="${SCHEMA_DIR}" + mkdir -p "$SCHEMA_DIR" + cp resources/com.keyman.gschema.xml "$SCHEMA_DIR"/ + glib-compile-schemas "$SCHEMA_DIR" + ./run-tests.sh + export XDG_DATA_DIRS=${XDG_DATA_DIRS#*:} + unset GSETTINGS_SCHEMA_DIR + rm -rf "$TEMP_DATA_DIR" +} + install_action() { if [ -n "${SUDO_USER:-}" ]; then pip3 install qrcode sentry-sdk @@ -108,6 +123,6 @@ uninstall_action() { builder_run_action clean clean_action builder_run_action configure # nothing to do builder_run_action build build_action -builder_run_action test ./run-tests.sh +builder_run_action test test_action builder_run_action install install_action builder_run_action uninstall uninstall_action -- GitLab From 5f5054b93cbe7d4422188adea00ab4e75e5ccfe2 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Mon, 5 Jun 2023 17:18:55 +0200 Subject: [PATCH 202/214] chore(linux): Fix lintian warnings - add rudimentary man page for keyman-system-service - remove hashbang for bash completion files - reword description for keyman-system-service This fixes these lintian warnings: keyman-system-service: description-is-pkg-name Keyman system service keyman: bash-completion-with-hashbang /usr/bin/env bash [usr/share/bash-completion/completions/km-config:1] keyman-system-service: no-manual-page [usr/libexec/keyman-system-service] --- linux/debian/control | 2 +- linux/debian/keyman-system-service.manpages | 1 + linux/keyman-config/km-config.bash-completion | 3 ++- linux/keyman-config/km-kvk2ldml.bash-completion | 3 ++- linux/keyman-config/km-package-get.bash-completion | 3 ++- linux/keyman-config/km-package-install.bash-completion | 3 ++- .../km-package-list-installed.bash-completion | 3 ++- .../keyman-config/km-package-uninstall.bash-completion | 3 ++- .../keyman-system-service/man/keyman-system-service.1 | 10 ++++++++++ 9 files changed, 24 insertions(+), 7 deletions(-) create mode 100644 linux/debian/keyman-system-service.manpages create mode 100644 linux/keyman-system-service/man/keyman-system-service.1 diff --git a/linux/debian/control b/linux/debian/control index 02dd064749..624f89fc0a 100644 --- a/linux/debian/control +++ b/linux/debian/control @@ -191,7 +191,7 @@ Depends: libevdev2, ${misc:Depends}, ${shlibs:Depends}, -Description: Keyman system service +Description: System service for Keyman Originally created in 1993 to type Lao on Windows, Keyman is now a free and open source keyboarding platform which allows anyone to write a keyboard layout for their language. Keyman is available for many platforms, including diff --git a/linux/debian/keyman-system-service.manpages b/linux/debian/keyman-system-service.manpages new file mode 100644 index 0000000000..cb4d9f0500 --- /dev/null +++ b/linux/debian/keyman-system-service.manpages @@ -0,0 +1 @@ +linux/keyman-system-service/man/keyman-system-service.1 diff --git a/linux/keyman-config/km-config.bash-completion b/linux/keyman-config/km-config.bash-completion index b1f46c0076..fd0eee394c 100644 --- a/linux/keyman-config/km-config.bash-completion +++ b/linux/keyman-config/km-config.bash-completion @@ -1,4 +1,5 @@ -#!/usr/bin/env bash +# shellcheck disable=SC2148 +# No hashbang for bash completion scripts! They are intended to be sourced, not executed. _km-config_completions() { diff --git a/linux/keyman-config/km-kvk2ldml.bash-completion b/linux/keyman-config/km-kvk2ldml.bash-completion index 3eb2950c39..1e8231a1a1 100644 --- a/linux/keyman-config/km-kvk2ldml.bash-completion +++ b/linux/keyman-config/km-kvk2ldml.bash-completion @@ -1,4 +1,5 @@ -#!/usr/bin/env bash +# shellcheck disable=SC2148 +# No hashbang for bash completion scripts! They are intended to be sourced, not executed. _km-kvk2ldml_completions() { diff --git a/linux/keyman-config/km-package-get.bash-completion b/linux/keyman-config/km-package-get.bash-completion index 9bacb1b8fe..0fb3a4d14c 100644 --- a/linux/keyman-config/km-package-get.bash-completion +++ b/linux/keyman-config/km-package-get.bash-completion @@ -1,4 +1,5 @@ -#!/usr/bin/env bash +# shellcheck disable=SC2148 +# No hashbang for bash completion scripts! They are intended to be sourced, not executed. _km-package-get_completions() { diff --git a/linux/keyman-config/km-package-install.bash-completion b/linux/keyman-config/km-package-install.bash-completion index 1a424e8ea6..06bfeb6aa5 100644 --- a/linux/keyman-config/km-package-install.bash-completion +++ b/linux/keyman-config/km-package-install.bash-completion @@ -1,4 +1,5 @@ -#!/usr/bin/env bash +# shellcheck disable=SC2148 +# No hashbang for bash completion scripts! They are intended to be sourced, not executed. _km-package-install_completions() { diff --git a/linux/keyman-config/km-package-list-installed.bash-completion b/linux/keyman-config/km-package-list-installed.bash-completion index a3758b467e..672353b9a1 100644 --- a/linux/keyman-config/km-package-list-installed.bash-completion +++ b/linux/keyman-config/km-package-list-installed.bash-completion @@ -1,4 +1,5 @@ -#!/usr/bin/env bash +# shellcheck disable=SC2148 +# No hashbang for bash completion scripts! They are intended to be sourced, not executed. _km-package-list-installed_completions() { diff --git a/linux/keyman-config/km-package-uninstall.bash-completion b/linux/keyman-config/km-package-uninstall.bash-completion index 191e709eab..4b81c38dac 100644 --- a/linux/keyman-config/km-package-uninstall.bash-completion +++ b/linux/keyman-config/km-package-uninstall.bash-completion @@ -1,4 +1,5 @@ -#!/usr/bin/env bash +# shellcheck disable=SC2148 +# No hashbang for bash completion scripts! They are intended to be sourced, not executed. _km-package-uninstall_completions() { diff --git a/linux/keyman-system-service/man/keyman-system-service.1 b/linux/keyman-system-service/man/keyman-system-service.1 new file mode 100644 index 0000000000..b506bd1607 --- /dev/null +++ b/linux/keyman-system-service/man/keyman-system-service.1 @@ -0,0 +1,10 @@ +.TH KEYMAN-SYSTEM-SERVICE "1" "May 2023" "keyman-system-service" "User Commands" +.SH NAME +keyman-system-service \- System service for Keyman +.SH DESCRIPTION +\&keyman\-system\-service +.TP +This command should not be run directly. It will be started as a DBUS +system service by systemd. +.SH "SEE ALSO" +.BR ibus-engine-keyman(1) -- GitLab From 2a0ee25c4a93eac0496b02d6459abd56fb1028e6 Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Mon, 5 Jun 2023 14:02:35 -0400 Subject: [PATCH 203/214] auto: increment master version to 17.0.119 --- HISTORY.md | 6 ++++++ VERSION.md | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 2b501ebd15..50d6433464 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,11 @@ # Keyman Version History +## 17.0.118 alpha 2023-06-05 + +* chore(ios): replace fv cert (#8900) +* fix(core): Fix compilation if hotdoc is installed (#8912) +* feat(linux): Rename column and add tooltip (#8918) + ## 17.0.117 alpha 2023-06-04 * chore(developer): verify long lines compile correctly (#8915) diff --git a/VERSION.md b/VERSION.md index 2398e0d103..7d14d88a17 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.118 \ No newline at end of file +17.0.119 \ No newline at end of file -- GitLab From 044a14f1d9ac0b201f4c99981c47f9ddc7ad8f21 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 6 Jun 2023 07:07:07 +0700 Subject: [PATCH 204/214] chore(core): look for emcc.py, not emcc Relates to #8913. --- core/commands.inc.sh | 35 +++++--------------------- developer/src/kmcmplib/commands.inc.sh | 33 +++--------------------- resources/locate_emscripten.inc.sh | 30 ++++++++++++++++++++++ 3 files changed, 40 insertions(+), 58 deletions(-) create mode 100644 resources/locate_emscripten.inc.sh diff --git a/core/commands.inc.sh b/core/commands.inc.sh index 2e5fb9e7b9..6916b61a9d 100644 --- a/core/commands.inc.sh +++ b/core/commands.inc.sh @@ -1,4 +1,7 @@ -#!/usr/bin/env bash +# shellcheck shell=bash +# no hashbang for .inc.sh + +. "$KEYMAN_ROOT/resources/locate_emscripten.inc.sh" # ---------------------------------------------------------------------------- # clean @@ -114,34 +117,6 @@ do_uninstall() { # utility functions # ---------------------------------------------------------------------------- -# -# We don't want to rely on emcc being on the path, because Emscripten puts far -# too many things onto the path (in particular for us, node). -# -# The following comment suggests that we don't need emcc on the path. -# https://github.com/emscripten-core/emscripten/issues/4848#issuecomment-1097357775 -# -# So we try and locate emcc in common locations ourselves. The search pattern -# is: -# -# 1. Look for $EMSCRIPTEN_BASE (our primary emscripten variable), which should -# point to the folder that emcc is located in -# 2. Look for $EMCC which should point to the emcc executable -# 3. Look for emcc on the path -# -locate_emscripten() { - if [[ -z ${EMSCRIPTEN_BASE+x} ]]; then - if [[ -z ${EMCC+x} ]]; then - local EMCC=`which emcc` - [[ -z $EMCC ]] && builder_die "locate_emscripten: Could not locate emscripten (emcc) on the path or with \$EMCC or \$EMSCRIPTEN_BASE" - fi - [[ -x $EMCC ]] || builder_die "locate_emscripten: Variable EMCC ($EMCC) does not point to a valid executable emcc" - EMSCRIPTEN_BASE="$(dirname "$EMCC")" - fi - - [[ -x ${EMSCRIPTEN_BASE}/emcc ]] || builder_die "locate_emscripten: Variable EMSCRIPTEN_BASE ($EMSCRIPTEN_BASE) does not point to emcc's folder" -} - build_meson_cross_file_for_wasm() { if [ $BUILDER_OS == win ]; then local R=$(cygpath -w $(echo $EMSCRIPTEN_BASE) | sed 's_\\_\\\\_g') @@ -159,6 +134,8 @@ build_meson_cross_file_for_wasm() { # This link.exe is not a linker. # You may need to reorder entries to your %PATH% variable to resolve this. # +# TODO: is this still required with meson 1.0? +# cleanup_visual_studio_path() { local _split_path _new_path="" diff --git a/developer/src/kmcmplib/commands.inc.sh b/developer/src/kmcmplib/commands.inc.sh index bdb8e0f139..d3647c41dd 100644 --- a/developer/src/kmcmplib/commands.inc.sh +++ b/developer/src/kmcmplib/commands.inc.sh @@ -1,4 +1,7 @@ -#!/usr/bin/env bash +# shellcheck shell=bash +# no hashbang for .inc.sh + +. "$KEYMAN_ROOT/resources/locate_emscripten.inc.sh" # ---------------------------------------------------------------------------- # clean @@ -115,34 +118,6 @@ do_command() { # utility functions # ---------------------------------------------------------------------------- -# -# We don't want to rely on emcc being on the path, because Emscripten puts far -# too many things onto the path (in particular for us, node). -# -# The following comment suggests that we don't need emcc on the path. -# https://github.com/emscripten-core/emscripten/issues/4848#issuecomment-1097357775 -# -# So we try and locate emcc in common locations ourselves. The search pattern -# is: -# -# 1. Look for $EMSCRIPTEN_BASE (our primary emscripten variable), which should -# point to the folder that emcc is located in -# 2. Look for $EMCC which should point to the emcc executable -# 3. Look for emcc on the path -# -locate_emscripten() { - if [[ -z ${EMSCRIPTEN_BASE+x} ]]; then - if [[ -z ${EMCC+x} ]]; then - local EMCC=`which emcc` - [[ -z $EMCC ]] && builder_die "locate_emscripten: Could not locate emscripten (emcc) on the path or with \$EMCC or \$EMSCRIPTEN_BASE" - fi - [[ -x $EMCC ]] || builder_die "locate_emscripten: Variable EMCC ($EMCC) does not point to a valid executable emcc" - EMSCRIPTEN_BASE="$(dirname "$EMCC")" - fi - - [[ -x ${EMSCRIPTEN_BASE}/emcc ]] || builder_die "locate_emscripten: Variable EMSCRIPTEN_BASE ($EMSCRIPTEN_BASE) does not point to emcc's folder" -} - build_meson_cross_file_for_wasm() { if [ $BUILDER_OS == win ]; then local R=$(cygpath -w $(echo $EMSCRIPTEN_BASE) | sed 's_\\_\\\\_g') diff --git a/resources/locate_emscripten.inc.sh b/resources/locate_emscripten.inc.sh new file mode 100644 index 0000000000..a58b384089 --- /dev/null +++ b/resources/locate_emscripten.inc.sh @@ -0,0 +1,30 @@ +# shellcheck shell=bash +# no hashbang for .inc.sh + +# +# We don't want to rely on emcc.py being on the path, because Emscripten puts far +# too many things onto the path (in particular for us, node). +# +# The following comment suggests that we don't need emcc.py on the path. +# https://github.com/emscripten-core/emscripten/issues/4848#issuecomment-1097357775 +# +# So we try and locate emcc.py in common locations ourselves. The search pattern +# is: +# +# 1. Look for $EMSCRIPTEN_BASE (our primary emscripten variable), which should +# point to the folder that emcc.py is located in +# 2. Look for $EMCC which should point to the emcc.py executable +# 3. Look for emcc.py on the path +# +locate_emscripten() { + if [[ -z ${EMSCRIPTEN_BASE+x} ]]; then + if [[ -z ${EMCC+x} ]]; then + local EMCC=`which emcc.py` + [[ -z $EMCC ]] && builder_die "locate_emscripten: Could not locate emscripten (emcc.py) on the path or with \$EMCC or \$EMSCRIPTEN_BASE" + fi + [[ -x $EMCC ]] || builder_die "locate_emscripten: Variable EMCC ($EMCC) does not point to a valid executable emcc.py" + EMSCRIPTEN_BASE="$(dirname "$EMCC")" + fi + + [[ -x ${EMSCRIPTEN_BASE}/emcc.py ]] || builder_die "locate_emscripten: Variable EMSCRIPTEN_BASE ($EMSCRIPTEN_BASE) does not point to emcc.py's folder" +} \ No newline at end of file -- GitLab From db6d8033a026d228a62714c9a996a9ef0386f9f6 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 6 Jun 2023 14:39:04 +0700 Subject: [PATCH 205/214] chore(developer): npm install --- package-lock.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package-lock.json b/package-lock.json index 568c70e2b3..fbd15530d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1032,6 +1032,7 @@ } }, "developer/src/kmc-kmw": { + "name": "@keymanapp/kmc-kmw", "license": "MIT", "dependencies": { "@keymanapp/common-types": "*", -- GitLab From 4873cda5cc4f917aca6d02d6c3cea194177a36c2 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 6 Jun 2023 12:01:48 +0200 Subject: [PATCH 206/214] chore(linux): Address code review comments and refactor This extracts common code in a separate function. --- linux/keyman-config/build.sh | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/linux/keyman-config/build.sh b/linux/keyman-config/build.sh index 2794544425..d84d59ca0f 100755 --- a/linux/keyman-config/build.sh +++ b/linux/keyman-config/build.sh @@ -29,19 +29,23 @@ clean_action() { keyman_config/standards/lang_tags_map.py } -build_man_pages() { +execute_with_temp_schema() { local TEMP_DATA_DIR SCHEMA_DIR TEMP_DATA_DIR=$(mktemp -d) - SCHEMA_DIR=$TEMP_DATA_DIR/glib-2.0/schemas - export XDG_DATA_DIRS=$TEMP_DATA_DIR:${XDG_DATA_DIRS-} + SCHEMA_DIR="${TEMP_DATA_DIR}/glib-2.0/schemas" + export XDG_DATA_DIRS="${TEMP_DATA_DIR}":${XDG_DATA_DIRS-} export GSETTINGS_SCHEMA_DIR="${SCHEMA_DIR}" - mkdir -p "$SCHEMA_DIR" - cp resources/com.keyman.gschema.xml "$SCHEMA_DIR"/ - glib-compile-schemas "$SCHEMA_DIR" - ./build-help.sh --man --no-reconf + mkdir -p "${SCHEMA_DIR}" + cp resources/com.keyman.gschema.xml "${SCHEMA_DIR}"/ + glib-compile-schemas "${SCHEMA_DIR}" + "$@" export XDG_DATA_DIRS=${XDG_DATA_DIRS#*:} unset GSETTINGS_SCHEMA_DIR - rm -rf "$TEMP_DATA_DIR" + rm -rf "${TEMP_DATA_DIR}" +} + +build_man_pages() { + execute_with_temp_schema ./build-help.sh --man --no-reconf } build_action() { @@ -73,18 +77,7 @@ build_action() { } test_action() { - local TEMP_DATA_DIR SCHEMA_DIR - TEMP_DATA_DIR=$(mktemp -d) - SCHEMA_DIR=$TEMP_DATA_DIR/glib-2.0/schemas - export XDG_DATA_DIRS=$TEMP_DATA_DIR:${XDG_DATA_DIRS-} - export GSETTINGS_SCHEMA_DIR="${SCHEMA_DIR}" - mkdir -p "$SCHEMA_DIR" - cp resources/com.keyman.gschema.xml "$SCHEMA_DIR"/ - glib-compile-schemas "$SCHEMA_DIR" - ./run-tests.sh - export XDG_DATA_DIRS=${XDG_DATA_DIRS#*:} - unset GSETTINGS_SCHEMA_DIR - rm -rf "$TEMP_DATA_DIR" + execute_with_temp_schema ./run-tests.sh } install_action() { -- GitLab From 979564f0a29c133003cb3496c436de89296020b8 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 6 Jun 2023 15:18:46 +0200 Subject: [PATCH 207/214] fix(linux): Fix title of reference page and links Fixes help.keyman.com#725 --- linux/help/reference/index.md | 4 ++-- linux/keyman-config/build-help.sh | 6 ++++-- linux/keyman-config/build.sh | 8 ++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/linux/help/reference/index.md b/linux/help/reference/index.md index 1089382c55..7b8f704018 100644 --- a/linux/help/reference/index.md +++ b/linux/help/reference/index.md @@ -1,8 +1,8 @@ --- -title: Keyman 16.0 for Linux Reference +title: Keyman 17.0 for Linux Reference --- -## Keyman 16.0 for Linux Overview +## Keyman 17.0 for Linux Overview Keyman for Linux makes it possible for you to type in over 2,000 languages on Linux. diff --git a/linux/keyman-config/build-help.sh b/linux/keyman-config/build-help.sh index 97f06ca3d0..0bf046ce6d 100755 --- a/linux/keyman-config/build-help.sh +++ b/linux/keyman-config/build-help.sh @@ -10,6 +10,8 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" THIS_DIR=$(dirname "$THIS_SCRIPT") +cd "${THIS_DIR}" + function display_usage { echo "Usage: $0 [--man] [--md] [--no-reconf]" echo " $0 --help" @@ -50,13 +52,13 @@ while [[ $# -gt 0 ]] ; do shift # past the processed argument done -if [ -z "$generate_man" -a -z "$generate_help" ]; then +if [ -z "$generate_man" ] && [ -z "$generate_help" ]; then generate_man=1 generate_help=1 fi if [ -n "$reconfigure" ]; then - pushd $THIS_DIR/.. > /dev/null + pushd "$THIS_DIR/.." > /dev/null ./scripts/reconf.sh popd > /dev/null fi diff --git a/linux/keyman-config/build.sh b/linux/keyman-config/build.sh index 1cb603f091..515003804f 100755 --- a/linux/keyman-config/build.sh +++ b/linux/keyman-config/build.sh @@ -29,7 +29,7 @@ clean_action() { keyman_config/standards/lang_tags_map.py } -build_man_pages() { +build_man_and_help_pages() { local TEMP_DATA_DIR SCHEMA_DIR TEMP_DATA_DIR=$(mktemp -d) SCHEMA_DIR=$TEMP_DATA_DIR/glib-2.0/schemas @@ -38,7 +38,7 @@ build_man_pages() { mkdir -p "$SCHEMA_DIR" cp ./com.keyman.gschema.xml "$SCHEMA_DIR"/ glib-compile-schemas "$SCHEMA_DIR" - ./build-help.sh --man --no-reconf + ./build-help.sh --no-reconf export XDG_DATA_DIRS=${XDG_DATA_DIRS#*:} unset GSETTINGS_SCHEMA_DIR rm -rf "$TEMP_DATA_DIR" @@ -66,8 +66,8 @@ build_action() { builder_echo "Skip building lang_tags_map.py during package build" fi popd - builder_echo "Building man pages" - build_man_pages + builder_echo "Building man and help pages" + build_man_and_help_pages builder_echo "Building keyman-config" python3 setup.py build } -- GitLab From 5fcd13892579ade583d45adade6877f9ef56bf65 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Tue, 6 Jun 2023 11:12:39 -0500 Subject: [PATCH 208/214] fix(android/engine): Re-enable KMManager tests --- .../src/main/java/com/keyman/engine/KMKeyboard.java | 8 ++++++-- .../src/main/java/com/keyman/engine/KMManager.java | 7 +++++-- .../test/java/com/keyman/engine/KMManagerTest.java | 12 ++++++------ 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboard.java b/android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboard.java index 88dc290322..bc0aed1d04 100644 --- a/android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboard.java +++ b/android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboard.java @@ -29,6 +29,7 @@ import android.Manifest; import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Color; @@ -223,8 +224,11 @@ final class KMKeyboard extends WebView { getSettings().setUseWideViewPort(true); getSettings().setLoadWithOverviewMode(true); - setWebContentsDebuggingEnabled(true); - + if (0 != (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE)) { + // Enable debugging of WebView via adb. Not used during unit tests + // Refer: https://developer.chrome.com/docs/devtools/remote-debugging/webviews/#configure_webviews_for_debugging + setWebContentsDebuggingEnabled(true); + } setWebChromeClient(new WebChromeClient() { public boolean onConsoleMessage(ConsoleMessage cm) { String msg = KMString.format("KMW JS Log: Line %d, %s:%s", cm.lineNumber(), cm.sourceId(), cm.message()); diff --git a/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java b/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java index ebb8727bef..c01b21db2c 100644 --- a/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java +++ b/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java @@ -624,8 +624,11 @@ public final class KMManager { return; } - RelativeLayout.LayoutParams params = getKeyboardLayoutParams(); - keyboard.setLayoutParams(params); + if (!isTestMode()) { + // Keyboard layout not needed in unit tests. #5125 + RelativeLayout.LayoutParams params = getKeyboardLayoutParams(); + keyboard.setLayoutParams(params); + } keyboard.setVerticalScrollBarEnabled(false); keyboard.setHorizontalScrollBarEnabled(false); keyboard.setWebViewClient(webViewClient); diff --git a/android/KMEA/app/src/test/java/com/keyman/engine/KMManagerTest.java b/android/KMEA/app/src/test/java/com/keyman/engine/KMManagerTest.java index 97515b7190..59a0237b37 100644 --- a/android/KMEA/app/src/test/java/com/keyman/engine/KMManagerTest.java +++ b/android/KMEA/app/src/test/java/com/keyman/engine/KMManagerTest.java @@ -29,13 +29,14 @@ public class KMManagerTest { private static final String OLD_KEYBOARDS_LIST = "old_keyboards_list.dat"; ArrayList> dat_list; - @Before - public void loadOldKeyboardsList() throws FileNotFoundException { + // For some keyboard list tests, load an existing keyboard list. + // Can't use @Before because context is null before running tests. + public void loadOldKeyboardsList() { KMManager.initialize(ApplicationProvider.getApplicationContext(), KMManager.KeyboardType.KEYBOARD_TYPE_INAPP); File keyboards_dat = new File(TEST_RESOURCE_ROOT, OLD_KEYBOARDS_LIST); if (keyboards_dat == null || !keyboards_dat.exists()) { - throw new FileNotFoundException(); + Assert.fail(TAG + ": keyboards list not found"); } try { ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(keyboards_dat)); @@ -46,7 +47,6 @@ public class KMManagerTest { } } - @Ignore("Investigate ResourcesNotFoundException") @Test public void test_getTier() { String versionName = "14.0.248-alpha"; @@ -109,9 +109,9 @@ public class KMManagerTest { /* * This test is manually run to edit/regenerate the old keyboards list */ - @Ignore @Test public void create_newKeyboardsList() { + loadOldKeyboardsList(); dat_list = new ArrayList>(); HashMap usInfo = new HashMap(); @@ -181,9 +181,9 @@ public class KMManagerTest { } } - @Ignore("Investigate ResourcesNotFoundException") @Test public void test_updateOldKeyboardsList() { + loadOldKeyboardsList(); Assert.assertNotNull(dat_list); // Verify old keyboards list contains deprecated keyboards -- GitLab From 8c44b9b15c9525967e0807c361dcdeb17dd60301 Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Tue, 6 Jun 2023 14:02:20 -0400 Subject: [PATCH 209/214] auto: increment master version to 17.0.120 --- HISTORY.md | 5 +++++ VERSION.md | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 50d6433464..668538bb42 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,10 @@ # Keyman Version History +## 17.0.119 alpha 2023-06-06 + +* chore(developer): ensure kmcmplib messages are all UTF-8 (#8927) +* chore(linux): Fix lintian warnings (#8931) + ## 17.0.118 alpha 2023-06-05 * chore(ios): replace fv cert (#8900) diff --git a/VERSION.md b/VERSION.md index 7d14d88a17..3be57aa49a 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.119 \ No newline at end of file +17.0.120 \ No newline at end of file -- GitLab From 82d86af91a2dead734d942a63970799c28c1f323 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Wed, 7 Jun 2023 10:18:58 +0200 Subject: [PATCH 210/214] chore(linux): Adjust documentation --- docs/linux/keyman-config.md | 12 +++++------- linux/keyman-config/build.sh | 2 ++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/linux/keyman-config.md b/docs/linux/keyman-config.md index f050fd96ad..cfea5d1437 100644 --- a/docs/linux/keyman-config.md +++ b/docs/linux/keyman-config.md @@ -35,10 +35,7 @@ or install it with pip: pip3 install sentry-sdk ``` -Run the script `./createkeymandirs.sh` to create the directories for these -programs to install the packages to. - -Also copy and compile the GSettings schema: +Copy and compile the GSettings schema: ```bash cd keyman_config @@ -50,15 +47,16 @@ sudo glib-compile-schemas /usr/share/glib-2.0/schemas Running `km-config` requires a language tag mapping file `keyman_config/standards/lang_tags_map.py`. This file gets generated during a package -build, and also when running `make`. +build, and also when running `build.sh build`. ## Installing manually from the repo -`make && sudo make install` will install locally to `/usr/local`. +`linux/keyman-config/build.sh build && sudo linux/keyman-config/build.sh install` +will install locally to `/usr/local`. `pip3 help install` will give you more install options. -To uninstall you can run `sudo make uninstall`. +To uninstall you can run `sudo linux/keyman-config/build.sh uninstall`. ## Things to run from the command line diff --git a/linux/keyman-config/build.sh b/linux/keyman-config/build.sh index d84d59ca0f..e0b7873517 100755 --- a/linux/keyman-config/build.sh +++ b/linux/keyman-config/build.sh @@ -82,6 +82,7 @@ test_action() { install_action() { if [ -n "${SUDO_USER:-}" ]; then + # with sudo install into /usr/local pip3 install qrcode sentry-sdk # eventually change this to: pip3 install . python3 setup.py install @@ -92,6 +93,7 @@ install_action() { mkdir -p /usr/local/share/man/man1 cp ../../debian/man/*.1 /usr/local/share/man/man1 else + # without sudo install into /tmp/keyman (or $DESTDIR) mkdir -p "/tmp/keyman/$(python3 -c 'import sys;import os;pythonver="python%d.%d" % (sys.version_info[0], sys.version_info[1]);sitedir = os.path.join("lib", pythonver, "site-packages");print(sitedir)')" # when we no longer have to support old pip version (python > 3.6) change this to: # pip3 install --prefix /tmp/keyman . -- GitLab From 55675e8f6dc9d3df39690146f9028285be268cd8 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Wed, 7 Jun 2023 10:20:38 +0200 Subject: [PATCH 211/214] fix(linux): address code review comment --- linux/keyman-config/build-help.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/linux/keyman-config/build-help.sh b/linux/keyman-config/build-help.sh index 0bf046ce6d..e05b8d284e 100755 --- a/linux/keyman-config/build-help.sh +++ b/linux/keyman-config/build-help.sh @@ -3,11 +3,7 @@ set -e set -u -## START STANDARD BUILD SCRIPT INCLUDE -# adjust relative paths as necessary THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" -## END STANDARD BUILD SCRIPT INCLUDE - THIS_DIR=$(dirname "$THIS_SCRIPT") cd "${THIS_DIR}" -- GitLab From 4843d71d744be919818a43583a40c53792e8bd23 Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Wed, 7 Jun 2023 14:25:52 -0400 Subject: [PATCH 212/214] auto: increment master version to 17.0.121 --- HISTORY.md | 7 +++++++ VERSION.md | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 668538bb42..3caaef473c 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,12 @@ # Keyman Version History +## 17.0.120 alpha 2023-06-07 + +* chore(core): look for emcc.py, not emcc (#8934) +* chore(linux): Move some files to keyman-config (#8917) +* fix(linux): Fix title of reference page and links (#8939) +* fix(android/engine): Re-enable KMManager tests (#8940) + ## 17.0.119 alpha 2023-06-06 * chore(developer): ensure kmcmplib messages are all UTF-8 (#8927) diff --git a/VERSION.md b/VERSION.md index 3be57aa49a..4df3b18e58 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.120 \ No newline at end of file +17.0.121 \ No newline at end of file -- GitLab From 483e43ca694b6ae08c4219edae3d47c96ed34167 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 8 Jun 2023 06:17:18 +0700 Subject: [PATCH 213/214] chore(developer): seed kmc-kmw --- developer/src/kmc-kmw/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 developer/src/kmc-kmw/README.md diff --git a/developer/src/kmc-kmw/README.md b/developer/src/kmc-kmw/README.md new file mode 100644 index 0000000000..27f1ebaa92 --- /dev/null +++ b/developer/src/kmc-kmw/README.md @@ -0,0 +1 @@ +# kmc-kmw \ No newline at end of file -- GitLab From 6421a1f6f40e7e132c6313a84e81ff72b189030b Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 8 Jun 2023 17:34:37 +1000 Subject: [PATCH 214/214] chore: Apply suggestions from code review Co-authored-by: Joshua Horton --- developer/src/kmc-kmw/src/compiler/javascript-strings.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/developer/src/kmc-kmw/src/compiler/javascript-strings.ts b/developer/src/kmc-kmw/src/compiler/javascript-strings.ts index 2504781b9b..731e837767 100644 --- a/developer/src/kmc-kmw/src/compiler/javascript-strings.ts +++ b/developer/src/kmc-kmw/src/compiler/javascript-strings.ts @@ -123,13 +123,10 @@ export function JavaScript_String(ch: number): string { // I2242 case 10: return '\\n'; case 13: return '\\r'; } - if(ch < 9) { - return '\\x0'+ch.toString(16).toUpperCase(); - } else { - return '\\x'+ch.toString(16).toUpperCase(); - } + return '\\x' + zeroPadHex(ch, 2); } else { + // Note: unpaired surrogates will be maintained return String.fromCodePoint(ch); } } @@ -776,7 +773,6 @@ function CheckStoreForInvalidFunctions(fk: KMX.KEYBOARD, key: KMX.KEY, store: KM // Used when targeting versions prior to 10.0, before the introduction of FullContextMatch/KFCM. function JavaScript_CompositeContextValue(fk: KMX.KEYBOARD, fkp: KMX.KEY, pwsz: string): string { - // Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions // var // StartQuotes, Len, Cur: Integer; // InQuotes: Boolean; -- GitLab