From 8f20507a8237c576ca745df2ec8e3c7ea4991c95 Mon Sep 17 00:00:00 2001 From: Ross Date: Fri, 14 Apr 2023 13:59:49 +1000 Subject: [PATCH 01/63] 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 | 339 ++++----- 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 | 101 ++- windows/src/engine/keyman32/keymanengine.h | 5 - .../src/engine/keyman32/kmhook_getmessage.cpp | 23 +- windows/src/engine/keyman32/kmprocess.cpp | 665 +----------------- .../src/engine/keyman32/preservedkeymap.cpp | 110 +-- .../src/engine/keyman32/selectkeyboard.cpp | 88 +-- 15 files changed, 255 insertions(+), 1417 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 + case VK_SHIFT: + ProcessModifierChange((UINT)wParam, isUp, extended); + break; } - } 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 - } - } // 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; - } - 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); - } - 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; - } - delete[] actionItems; - //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMSetOutputCore: Exit"); - return TRUE; + 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; + } + 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); + } + 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; + } + 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; - } - - 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; - } - delete[] actionItem; - //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMQueueActionCore: Exit"); - return TRUE; + 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; + } + 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 (!ContextItemToAppContext(citems, buf, len)) { - km_kbp_context_items_dispose(citems); - return FALSE; - } - km_kbp_context_items_dispose(citems); - //SendDebugMessageFormat(0, sdmKeyboard, 0, "KMGetContext: Exit"); - return TRUE; + if(!_td) { + return FALSE; } + + if(!_td->app) { + return FALSE; + } + + 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); + 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; - - 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; - } - - 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); - return FALSE; - } - - 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; - } - - 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; - } + goto fail; } - SendDebugMessageFormat(0,sdmGlobal,0,"Keyman_ForceKeyboard: %s FAIL", FileName); + 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; + } + + 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; + } + + 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. + // 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; - } + // 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); - } - } - 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()) { From ec8539543bd01a1561dd6ed8514baa1879c3ed9b Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 19 Apr 2023 14:27:03 +1000 Subject: [PATCH 02/63] 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; From 1b46bc1d010af451e372a2e566fbe7cd14ad1733 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 20 Apr 2023 16:55:54 +1000 Subject: [PATCH 03/63] 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; From 616dcc8420a8aed70b6b64839a2d7048d1b2433f Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 20 Apr 2023 21:27:59 +1000 Subject: [PATCH 04/63] 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); From 4019a79676310cd2b1ddc63bdf218c9b6fd2fa39 Mon Sep 17 00:00:00 2001 From: Ross Date: Fri, 21 Apr 2023 18:43:50 +1000 Subject: [PATCH 05/63] 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); From 5f07f7ad080991bd9f2feebec0d9cc261be107c5 Mon Sep 17 00:00:00 2001 From: Ross Date: Fri, 21 Apr 2023 19:02:03 +1000 Subject: [PATCH 06/63] 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 @@ - From ec01969adc539200e84f994cd9d5974d5bf05bc3 Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 26 Apr 2023 23:00:21 +1000 Subject: [PATCH 07/63] 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); From 0ee25dc59fe145b74a5fdc9291319c624e0e05b2 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 27 Apr 2023 14:15:06 +1000 Subject: [PATCH 08/63] 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 @@ + From 3de6d819c08756c372c2e99a735ed137021b81a4 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 27 Apr 2023 16:15:09 +1000 Subject: [PATCH 09/63] 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); From bc40860b09e7dff050fbdd263663238075bd1d1d Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 3 May 2023 14:13:17 +1000 Subject: [PATCH 10/63] 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); From 9aa6ab2ee0dd8b5126910cbf1a8093fa535102f5 Mon Sep 17 00:00:00 2001 From: Ross Date: Fri, 21 Apr 2023 19:02:03 +1000 Subject: [PATCH 11/63] 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 @@ - From 2935084b45fb7ebde0a721ff350d7ea1d6926042 Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 3 May 2023 15:09:45 +1000 Subject: [PATCH 12/63] 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 } /* From ebac0bb54b1a2b257c3d49ae020769b53afad521 Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 3 May 2023 15:19:16 +1000 Subject: [PATCH 13/63] 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) { From 504e4bd671f806da98591e5a69e00e28512c10e0 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 4 May 2023 13:08:31 +1000 Subject: [PATCH 14/63] 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); } From 708b6bcf688779e5c34380f14a732bb3449c524e Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 4 May 2023 14:16:09 +1000 Subject: [PATCH 15/63] 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; From ae80062815979ee4ec8800abc7974b874afaa3eb Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 4 May 2023 15:11:14 +1000 Subject: [PATCH 16/63] 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); From c6380fbaf9eddf0569dfcf92189483cc28709051 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Fri, 5 May 2023 14:24:29 -0500 Subject: [PATCH 17/63] =?UTF-8?q?feat(developer):=20uset=20api=20from=20wa?= =?UTF-8?q?sm!=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 +} From 806a757da21a5922e74465e35e42b0aeae31adcf Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 8 May 2023 14:48:53 +1000 Subject: [PATCH 18/63] 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; From 46267e347fc11e393db64349070db727b284ee55 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 9 May 2023 14:28:21 +0700 Subject: [PATCH 19/63] 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; From 009e2a11aec1e945fb1f49a9a613338d76f9cb75 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Tue, 9 May 2023 12:19:31 -0500 Subject: [PATCH 20/63] =?UTF-8?q?feat(developer):=20kmc-kmn:=20updates=20t?= =?UTF-8?q?o=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": { From 348e3281bd9c79b6c2fca2e14f84dbe6d3671397 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Tue, 9 May 2023 18:40:12 -0500 Subject: [PATCH 21/63] =?UTF-8?q?feat(developer):=20kmc-kmn:=20updates=20t?= =?UTF-8?q?o=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 From 52f1d87f02d4efe9071c83c3b44476fc6268f894 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Thu, 27 Apr 2023 14:31:49 +0700 Subject: [PATCH 22/63] 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; } From 184182f83e05770134eadbcc404754417641a5f7 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Wed, 3 May 2023 12:57:21 +0700 Subject: [PATCH 23/63] 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); From c4abc4fadbc153f592de8e6105a096c5fb58768f Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 10 May 2023 22:20:57 +1000 Subject: [PATCH 24/63] 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: - - 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 From 7e830794990d6ac4a1428bd0f2dc7922e5b68ddb Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 10 May 2023 22:48:03 +1000 Subject: [PATCH 25/63] 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 */ From 589e6b8faf6045a4b5121eade517ca5e69125f18 Mon Sep 17 00:00:00 2001 From: davidmoore1 Date: Wed, 10 May 2023 10:44:07 -0400 Subject: [PATCH 26/63] 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" From b6afda598b14976178dbd95e72c693b3631da175 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 11 May 2023 11:00:15 +1000 Subject: [PATCH 27/63] 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"), From 9136e571575afbbd2c38d8a5044febe9aa667b90 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 11 May 2023 14:03:18 +1000 Subject: [PATCH 28/63] 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(); From 2462472b38385895e36e79a3593d6098d6003061 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 11 May 2023 14:48:38 +1000 Subject: [PATCH 29/63] 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"), From 1f3e8f768d47fc7f82962473b98994f4f2de7c2a Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 11 May 2023 14:57:01 +1000 Subject: [PATCH 30/63] 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. - From be8d5b08c62237948bfc02c9a135de2c4f586745 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 11 May 2023 15:20:50 +1000 Subject: [PATCH 31/63] 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 From 631758352805324cb564de60e90389e3aca9a611 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Thu, 11 May 2023 10:37:46 -0500 Subject: [PATCH 32/63] =?UTF-8?q?feat(developer):=20kmc-kmn:=20wasm=20and?= =?UTF-8?q?=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}`); } }); }); From 3c3a363478082d26c666a79e7f17ca0fa96cdefe Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 12 May 2023 07:19:33 +0700 Subject: [PATCH 33/63] 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 From 53c51b79e692336365dfcbec4f5f5dfc9b7d827e Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 12 May 2023 08:26:54 +0700 Subject: [PATCH 34/63] 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); + }); + }); From d3e4762b527c1b1ccf4ee8038fe4a83fe9529e39 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 12 May 2023 09:07:46 +0700 Subject: [PATCH 35/63] 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); }); }); From e4ad95550eb3dbc545398f0fab38cc5d5e1866cb Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 12 May 2023 13:21:13 +0700 Subject: [PATCH 36/63] 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); + }); }); From b3436b8aff3b021998c58a7d53e14a262473566b Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 12 May 2023 13:31:56 +0700 Subject: [PATCH 37/63] 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); From 187a25240a3fef2d0410f3e36c5441ee551a2711 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 12 May 2023 14:14:32 +0700 Subject: [PATCH 38/63] 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); From 2528731b583e041422da9415f104b33b482c143e Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 12 May 2023 14:15:24 +0700 Subject: [PATCH 39/63] 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'; From 8446775dd5987f298cbafd7ae7dab5a5b52f617a Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 12 May 2023 14:42:07 +0700 Subject: [PATCH 40/63] 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); + }); }); From 65ef3d0982162bf183c190ab5a6e711b5a8deb24 Mon Sep 17 00:00:00 2001 From: Ross Date: Fri, 12 May 2023 18:21:44 +1000 Subject: [PATCH 41/63] 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; } From 02a3b412229325aeaaf8e258476da44962c1641d Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Fri, 12 May 2023 08:37:32 -0500 Subject: [PATCH 42/63] 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()); From e795287b93bd4c6704ffb639458262088eff0fda Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Fri, 12 May 2023 08:44:50 -0500 Subject: [PATCH 43/63] =?UTF-8?q?feat(developer):=20kmc-kmn:=20merge=20con?= =?UTF-8?q?flict=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 From 83615b9d6c649a0efaf946dda1c1695575453a54 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 12 May 2023 17:57:19 +0200 Subject: [PATCH 44/63] 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 From db619deb66d0a0edf23d93e14bd9ffc2ff813ec9 Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Fri, 12 May 2023 14:02:41 -0400 Subject: [PATCH 45/63] 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 From 3c9492dd563c65f0af7f4b13676d95ce048dec91 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Sun, 14 May 2023 09:31:32 +0700 Subject: [PATCH 46/63] 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); + }); }); From abd174557c9e26bbb843357b263141ebc340b38e Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Sun, 14 May 2023 09:53:36 +0700 Subject: [PATCH 47/63] 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); + }); }); From 7f1c05cba466e74b13444e045d0705974a0480a0 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Sun, 14 May 2023 17:18:59 +1000 Subject: [PATCH 48/63] 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; } From 135d6f9c0f94446d36b1f5856e30ba5d92ad371a Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Sun, 14 May 2023 17:23:21 +1000 Subject: [PATCH 49/63] 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); }); }); From 0908f91719aaec2746fcd9b857c73f530ab563ce Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 15 May 2023 10:25:30 +1000 Subject: [PATCH 50/63] 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); From 663e4195ffc3a4c96b4438e040c5fca32afb173a Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 15 May 2023 23:16:36 +1000 Subject: [PATCH 51/63] 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 From c31118cd6de0838e4e0a126d27de58d50ecb4788 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 15 May 2023 20:17:22 +0700 Subject: [PATCH 52/63] 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) From f08f44e29422607a54bd00ef830f89c2019d8be2 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Mon, 15 May 2023 17:39:16 +0200 Subject: [PATCH 53/63] 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 From a7b9e5bbb08a2f43abed268e401730a139479fbb Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Mon, 15 May 2023 14:01:40 -0400 Subject: [PATCH 54/63] 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 From b2e293892da2bc21fa177bcab43354b8d056c587 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 16 May 2023 13:21:31 +1000 Subject: [PATCH 55/63] 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 From a4ae39c15cb53518bb91d2a947d38033436c7237 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 16 May 2023 19:27:18 +1000 Subject: [PATCH 56/63] 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 From cfe62f72d39a5d246fa1e34de53cfe0412b624bc Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Tue, 16 May 2023 14:03:00 -0400 Subject: [PATCH 57/63] 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 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 58/63] 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; From 28ecb56ae667e74cafc51d156b6ec3a90a1084c4 Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 17 May 2023 12:45:06 +1000 Subject: [PATCH 59/63] 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 # ---------------------------------------------------------------------- From acb6371f5150e64602deb3b4210ce61acb3334c7 Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 17 May 2023 12:51:24 +1000 Subject: [PATCH 60/63] 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 From 7f131b27daf2036d11a8b903e963b585ea9744ab Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Wed, 17 May 2023 14:02:14 -0400 Subject: [PATCH 61/63] 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 From be2c0ccf45e016aacd13e5592c8af243b9fa614c Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 19 May 2023 16:36:05 +0700 Subject: [PATCH 62/63] 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 From f8535c469effd4b57fed0e3731f6f48d64ba8af6 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 22 May 2023 11:32:45 +1000 Subject: [PATCH 63/63] 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