From 9af0fa55ffe2189fd206bdc2134df01e930ddb92 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Mon, 4 Nov 2019 16:41:36 +0100 Subject: [PATCH 01/28] chore(linux): Pass parameters in Jenkinsfile --- linux/Jenkinsfile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/linux/Jenkinsfile b/linux/Jenkinsfile index 3b2adcdb1c..bf7ad63347 100644 --- a/linux/Jenkinsfile +++ b/linux/Jenkinsfile @@ -4,4 +4,7 @@ @Library('lsdev-pipeline-library') _ -keymanPackaging +keymanPackaging { + distributionsToPackage = 'xenial bionic' + arches = 'amd64 i386' +} From ccc64987390b240d5b1db7aef9975ce3170da04f Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 6 Nov 2019 17:44:32 +1100 Subject: [PATCH 02/28] fix(windows): Keyman was crashing sporadically Fixes #2147. This potentially addresses the issues reported in #2147 where Keyman would crash due to a race condition as a critical section was not deleted before attempting to recreate it. Some logging has been added for debugging these issues. Also fixes memory leaks and another race on startup relating to loading the taskbar icon. There are still some known memory leaks because DLL_THREAD_DETACH is not called for all threads before keyman32.dll is unloaded, so those threads don't get the opportunity to clean themsselves up. However, the key danger with the csGlobals critical section has been addressed. --- windows/src/engine/keyman/UfrmKeyman7Main.pas | 4 + windows/src/engine/keyman/keyman.dpr | 7 +- windows/src/engine/keyman32/K32_DBG.CPP | 10 ++- windows/src/engine/keyman32/Keyman32.cpp | 30 +++++-- windows/src/engine/keyman32/hookutils.cpp | 82 ++++++++++--------- windows/src/engine/keyman32/hotkeys.cpp | 12 +++ windows/src/engine/keyman32/hotkeys.h | 3 +- windows/src/engine/keyman32/k32_globals.cpp | 7 +- .../keyman32/k32_lowlevelkeyboardhook.cpp | 2 +- .../src/engine/keyman32/keyboardoptions.cpp | 7 +- .../engine/keyman32/kmhook_callwndproc.cpp | 3 +- .../engine/keyman32/serialkeyeventclient.cpp | 2 + windows/src/global/delphi/general/klog.pas | 2 +- windows/src/global/inc/keyman64.h | 7 ++ 14 files changed, 121 insertions(+), 57 deletions(-) diff --git a/windows/src/engine/keyman/UfrmKeyman7Main.pas b/windows/src/engine/keyman/UfrmKeyman7Main.pas index 8c198f699f..c37b73fb95 100644 --- a/windows/src/engine/keyman/UfrmKeyman7Main.pas +++ b/windows/src/engine/keyman/UfrmKeyman7Main.pas @@ -442,6 +442,10 @@ begin begin olestrm := TOLEStream.Create(istrm); try + // In some situations, launching the app multiple times rapidly can + // cause the icon to be loaded multiple times. Make sure we reset the + // stream position before we try and read. + olestrm.Position := 0; Application.Icon.LoadFromStream(olestrm); finally olestrm.Free; diff --git a/windows/src/engine/keyman/keyman.dpr b/windows/src/engine/keyman/keyman.dpr index b2352c3a7e..2f9bed1197 100644 --- a/windows/src/engine/keyman/keyman.dpr +++ b/windows/src/engine/keyman/keyman.dpr @@ -1,7 +1,5 @@ program keyman; - - uses Forms, Dialogs, @@ -148,6 +146,11 @@ uses {$R VERSION.RES} {$R MANIFEST.RES} +// +// PEOPTFLAGS $140 turns on Data Execution Prevention +// +{$SETPEOPTFLAGS $140} + begin //InitTntEnvironment; //ShowMessage('Start'); diff --git a/windows/src/engine/keyman32/K32_DBG.CPP b/windows/src/engine/keyman32/K32_DBG.CPP index 7fcc025762..a6e28b0873 100644 --- a/windows/src/engine/keyman32/K32_DBG.CPP +++ b/windows/src/engine/keyman32/K32_DBG.CPP @@ -304,4 +304,12 @@ char *Debug_UnicodeString(PWSTR s, int x) { } //WideCharToMultiByte(CP_ACP, 0, buf, -1, bufout, 128, NULL, NULL); return bufout[x]; -} \ No newline at end of file +} + +#ifdef _DEBUG +void _OutputThreadDebugString(char *s) { + char buf[256]; + wsprintf(buf, "[%d]: %s\n", GetCurrentThreadId(), s); + OutputDebugString(buf); +} +#endif diff --git a/windows/src/engine/keyman32/Keyman32.cpp b/windows/src/engine/keyman32/Keyman32.cpp index 9f4948f35b..58245b1c97 100644 --- a/windows/src/engine/keyman32/Keyman32.cpp +++ b/windows/src/engine/keyman32/Keyman32.cpp @@ -157,11 +157,13 @@ BOOL __stdcall DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID reserved) case DLL_PROCESS_ATTACH: //if(!TestDebugProcess()) return FALSE; //if(!ShouldAttachToProcess()) return FALSE; + OutputThreadDebugString("DLL_PROCESS_ATTACH"); if(!Globals_InitProcess()) return FALSE; break; case DLL_PROCESS_DETACH: //if(!TestDebugProcess()) return FALSE; if (reserved == NULL) { + OutputThreadDebugString("DLL_PROCESS_DETACH not terminating"); // If reserved == NULL, that means the library is being unloaded, but // the process is not terminating. // @@ -180,15 +182,20 @@ BOOL __stdcall DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID reserved) // CloseTSF from here. This needs further investigation... UninitialiseProcess(FALSE); Globals_UninitProcess(); + } + else { + OutputThreadDebugString("DLL_PROCESS_DETACH terminating"); } break; case DLL_THREAD_ATTACH: //if(!TestDebugProcess()) return FALSE; + OutputThreadDebugString("DLL_THREAD_ATTACH"); Globals_InitThread(); break; case DLL_THREAD_DETACH: //if(!TestDebugProcess()) return FALSE; - UninitialiseProcess(FALSE); + OutputThreadDebugString("DLL_THREAD_DETACH"); + UninitialiseProcess(FALSE); Globals_UninitThread(); break; } @@ -214,8 +221,13 @@ BOOL UninitialiseProcess(BOOL Lock) if(_td->IndexStack) delete _td->IndexStack; _td->IndexStack = NULL; - } + if (_td->miniContext) delete _td->miniContext; + _td->miniContext = NULL; + + if (_td->msgbuf) delete _td->msgbuf; + _td->msgbuf = NULL; + } return TRUE; } @@ -512,6 +524,10 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_Exit(void) return FALSE; } +#ifndef WIN64 + Hotkeys::Unload(); +#endif + *Globals::InitialisingThread() = 0; BOOL RetVal = TRUE; @@ -801,6 +817,7 @@ void LoadBaseLayoutSettings() { // I4552 // I4583 void RefreshKeyboards(BOOL Initialising) { + OutputThreadDebugString("RefreshKeyboards"); char sz[_MAX_FNAME]; char oldname[_MAX_FNAME]; RegistryReadOnly *reg2; @@ -828,7 +845,7 @@ void RefreshKeyboards(BOOL Initialising) _td->ActiveKeymanID = KEYMANID_NONKEYMAN; } - ReleaseKeyboards(TRUE); + ReleaseKeyboards(TRUE); /* Read the "keyboard off hotkey", simulate Alt+Gr, Hotkeys-Toggle flags */ @@ -938,13 +955,14 @@ void RefreshKeyboards(BOOL Initialising) _td->FInRefreshKeyboards = FALSE; } - void ReleaseKeyboards(BOOL Lock) { + OutputThreadDebugString("ReleaseKeyboards"); PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td || _td->lpKeyboards) return; + if(!_td || !_td->lpKeyboards) return; - if(Lock) if(_td->lpActiveKeyboard && !_td->ForceFileName[0]) DeactivateDLLs(_td->lpActiveKeyboard); + + if(Lock) if(_td->lpActiveKeyboard && !_td->ForceFileName[0]) DeactivateDLLs(_td->lpActiveKeyboard); for(int i = 0; i < _td->nKeyboards; i++) { diff --git a/windows/src/engine/keyman32/hookutils.cpp b/windows/src/engine/keyman32/hookutils.cpp index 15c24283b9..008bda99d1 100644 --- a/windows/src/engine/keyman32/hookutils.cpp +++ b/windows/src/engine/keyman32/hookutils.cpp @@ -15,45 +15,44 @@ typedef BOOL IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL ); - -DWORD ExceptionMessage(LPSTR Proc, LPEXCEPTION_POINTERS ep) -{ +DWORD ExceptionMessage(LPSTR Proc, LPEXCEPTION_POINTERS ep) { MINIDUMP_EXCEPTION_INFORMATION mei; char filename[MAX_PATH], temppath[MAX_PATH]; - if(GetTempPath(MAX_PATH, temppath) == 0 || - GetTempFileName(temppath, "kmc", 0, filename) == 0) - SendDebugMessageFormat(0, sdmGlobal, 0, "Minidump failed to generate temp file name"); - else - { + if (GetTempPath(MAX_PATH, temppath) == 0 || + GetTempFileName(temppath, "kmc", 0, filename) == 0) { + OutputThreadDebugString("Minidump failed to generate temp file name\n"); + } + else { HANDLE hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); - if(!hFile) - SendDebugMessageFormat(0, sdmGlobal, 0, "Minidump failed to create file %s", filename); - else - { + if (!hFile) { + OutputThreadDebugString("Minidump failed to create file "); + OutputThreadDebugString(filename); + } + else { mei.ClientPointers = TRUE; mei.ExceptionPointers = ep; mei.ThreadId = GetCurrentThreadId(); HMODULE hDbgHelp = LoadLibrary("dbghelp.dll"); - if(!hDbgHelp) - SendDebugMessage(0, sdmGlobal, 0, "dbghelp.dll not available"); - else - { + if (!hDbgHelp) { + OutputThreadDebugString("dbghelp.dll not available"); + } + else { PMiniDumpWriteDump mdwd = (PMiniDumpWriteDump) GetProcAddress(hDbgHelp, "MiniDumpWriteDump"); - if(!mdwd) - SendDebugMessage(0, sdmGlobal, 0, "MiniDumpWriteDump not available"); - else - { + if (!mdwd) { + OutputThreadDebugString("MiniDumpWriteDump not available"); + } + else { if (!(*mdwd)(GetCurrentProcess(), GetCurrentProcessId(), hFile, - (MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithHandleData), - &mei, NULL, NULL)) + (MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithHandleData), + &mei, NULL, NULL)) { DebugLastError("MiniDumpWriteDump"); - else - { - SendDebugMessageFormat(0, sdmGlobal, 0, "Minidump written to %s", filename); + } + else { + OutputThreadDebugString("Minidump written to "); + OutputThreadDebugString(filename); HKEY hkey; if(RegCreateKeyEx(HKEY_CURRENT_USER, REGSZ_KeymanEngineDiag, 0, NULL, 0, KEY_ALL_ACCESS, - NULL, &hkey, NULL) == ERROR_SUCCESS) - { + NULL, &hkey, NULL) == ERROR_SUCCESS) { DWORD v = 0; RegSetValueEx(hkey, filename, 0, REG_DWORD, (PBYTE)&v, sizeof(DWORD)); RegCloseKey(hkey); @@ -66,23 +65,26 @@ DWORD ExceptionMessage(LPSTR Proc, LPEXCEPTION_POINTERS ep) } } - if(!ep || !ep->ExceptionRecord) - { - SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT UNKNOWN EXCEPTION"); + if(!ep || !ep->ExceptionRecord) { + OutputThreadDebugString("CAUGHT UNKNOWN EXCEPTION"); return EXCEPTION_CONTINUE_SEARCH; } LPEXCEPTION_RECORD er = ep->ExceptionRecord; - while(er != NULL) - { - if(er->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) - SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d (ACCESS VIOLATION) IN %s AT %x; attempted to %s %x", - er->ExceptionCode, Proc, er->ExceptionAddress, - er->ExceptionInformation[0] == 0 ? "read from" : "write to", - er->ExceptionInformation[1]); - else - SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d IN %s AT %x", - er->ExceptionCode, Proc, er->ExceptionAddress); + while(er != NULL) { + if (er->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { + OutputThreadDebugString("EXCEPTION_ACCESS_VIOLATION in "); + OutputThreadDebugString(Proc); + SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d (ACCESS VIOLATION) IN %s AT %x; attempted to %s %x", + er->ExceptionCode, Proc, er->ExceptionAddress, + er->ExceptionInformation[0] == 0 ? "read from" : "write to", + er->ExceptionInformation[1]); + } + else { + OutputThreadDebugString("CAUGHT EXCEPTION"); + SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d IN %s AT %x", + er->ExceptionCode, Proc, er->ExceptionAddress); + } er = er->ExceptionRecord; } diff --git a/windows/src/engine/keyman32/hotkeys.cpp b/windows/src/engine/keyman32/hotkeys.cpp index a3363c49cc..cead296f8d 100644 --- a/windows/src/engine/keyman32/hotkeys.cpp +++ b/windows/src/engine/keyman32/hotkeys.cpp @@ -45,6 +45,18 @@ Hotkeys *Hotkeys::Instance() { // I4326 return g_Hotkeys; } +void Hotkeys::Unload() { + if (GetCurrentThreadId() != Globals::get_InitialisingThread()) { + OutputThreadDebugString("Unexpected: no other thread should be attempting to unload hotkeys"); + return; + } + + if (g_Hotkeys != NULL) { + delete g_Hotkeys; + g_Hotkeys = NULL; + } +} + void Hotkeys::Reload() { // I4326 // I4390 Hotkeys *hotkeys = Hotkeys::Instance(); // I4641 if(hotkeys == NULL) { diff --git a/windows/src/engine/keyman32/hotkeys.h b/windows/src/engine/keyman32/hotkeys.h index b011d20547..863be3636c 100644 --- a/windows/src/engine/keyman32/hotkeys.h +++ b/windows/src/engine/keyman32/hotkeys.h @@ -43,4 +43,5 @@ public: Hotkey *GetHotkey(DWORD hotkey); static void Reload(); // I4326 static Hotkeys *Instance(); // I4326 -}; + static void Unload(); + }; diff --git a/windows/src/engine/keyman32/k32_globals.cpp b/windows/src/engine/keyman32/k32_globals.cpp index af59056a15..2a08e6c293 100644 --- a/windows/src/engine/keyman32/k32_globals.cpp +++ b/windows/src/engine/keyman32/k32_globals.cpp @@ -138,7 +138,11 @@ PKEYMAN64THREADDATA Globals_InitThread() void Globals_UninitThread() { - if(!Globals_ProcessInitialised()) return; + OutputThreadDebugString("Globals_UninitThread"); + if (!Globals_ProcessInitialised()) { + OutputThreadDebugString("Globals_UninitThread aborted without cleanup"); + return; + } CloseTSF(); // I3933 @@ -185,6 +189,7 @@ void Globals_UninitProcess() TlsFree(dwTlsIndex); dwTlsIndex = TLS_OUT_OF_INDEXES; LeaveCriticalSection(&csGlobals); + DeleteCriticalSection(&csGlobals); } PKEYMAN64THREADDATA ThreadGlobals() diff --git a/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp b/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp index b50e0486e4..fee747f486 100644 --- a/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp +++ b/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp @@ -53,7 +53,7 @@ LRESULT CALLBACK kmnLowLevelKeyboardProc( __except(ExceptionMessage("kmnLowLevelKeyboardProc", GetExceptionInformation())) { } #endif - return res; + return res; } BOOL KeyLanguageSwitchPress(WPARAM wParam, BOOL extended, BOOL isUp, DWORD ShiftState); diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index 2e907c6460..1e0e0a8511 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -41,9 +41,10 @@ void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp) void FreeKeyboardOptions(LPINTKEYBOARDINFO kp) { - assert(kp != NULL); - assert(kp->Keyboard != NULL); - assert(kp->KeyboardOptions != NULL); + // 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) diff --git a/windows/src/engine/keyman32/kmhook_callwndproc.cpp b/windows/src/engine/keyman32/kmhook_callwndproc.cpp index 4b72ab7bd6..7178ed5fea 100644 --- a/windows/src/engine/keyman32/kmhook_callwndproc.cpp +++ b/windows/src/engine/keyman32/kmhook_callwndproc.cpp @@ -66,6 +66,7 @@ LRESULT _kmnCallWndProc(int nCode, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK kmnCallWndProc(int nCode, WPARAM wParam, LPARAM lParam) { LRESULT res = 0; + #ifdef _DEBUG_EXCEPTION res = _kmnCallWndProc(nCode,wParam,lParam); #else @@ -77,7 +78,7 @@ LRESULT CALLBACK kmnCallWndProc(int nCode, WPARAM wParam, LPARAM lParam) { } #endif - return res; + return res; } // I3617 BOOL IsSysTrayWindow(HWND hwnd); diff --git a/windows/src/engine/keyman32/serialkeyeventclient.cpp b/windows/src/engine/keyman32/serialkeyeventclient.cpp index 3719b9409a..722903e6c3 100644 --- a/windows/src/engine/keyman32/serialkeyeventclient.cpp +++ b/windows/src/engine/keyman32/serialkeyeventclient.cpp @@ -149,6 +149,7 @@ public: }; void ISerialKeyEventClient::Startup() { + OutputThreadDebugString("ISerialKeyEventClient::Startup"); PKEYMAN64THREADDATA _td = ThreadGlobals(); if (_td) { _td->pSerialKeyEventClient = new SerialKeyEventClient(); @@ -156,6 +157,7 @@ void ISerialKeyEventClient::Startup() { } void ISerialKeyEventClient::Shutdown() { + OutputThreadDebugString("ISerialKeyEventClient::Shutdown"); PKEYMAN64THREADDATA _td = ThreadGlobals(); if (_td && _td->pSerialKeyEventClient) { delete _td->pSerialKeyEventClient; diff --git a/windows/src/global/delphi/general/klog.pas b/windows/src/global/delphi/general/klog.pas index 8f8198bf31..0915696743 100644 --- a/windows/src/global/delphi/general/klog.pas +++ b/windows/src/global/delphi/general/klog.pas @@ -133,7 +133,7 @@ begin end; writeln(FLogFile, Format('%12.12d ', [GetTickCount()])+FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', Now) + ': ' + StringOfChar(' ', FMethodStack.Count*2) + msg); flush(FLogFile); - OutputDebugString(PChar(msg)); + OutputDebugString(PChar('KLog:' + msg + #13#10)); {$ENDIF} end; diff --git a/windows/src/global/inc/keyman64.h b/windows/src/global/inc/keyman64.h index ca8961501e..65e17b6db9 100644 --- a/windows/src/global/inc/keyman64.h +++ b/windows/src/global/inc/keyman64.h @@ -347,6 +347,13 @@ BOOL ShouldDebug_1(); // TSDMState state); #endif +#ifdef _DEBUG +#define OutputThreadDebugString(s) _OutputThreadDebugString(s) +void _OutputThreadDebugString(char *s); +#else +#define OutputThreadDebugString(s) +#endif + /* Keyboard selection functions */ void HandleRefresh(int code, LONG tag); From fc330e621ab2f04faf201cbd505517b243c32fda Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 7 Nov 2019 17:24:56 +1100 Subject: [PATCH 03/28] fix(windows): tweak preprocessor conditional --- windows/src/engine/keyman32/Keyman32.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/src/engine/keyman32/Keyman32.cpp b/windows/src/engine/keyman32/Keyman32.cpp index 58245b1c97..f146f3eae0 100644 --- a/windows/src/engine/keyman32/Keyman32.cpp +++ b/windows/src/engine/keyman32/Keyman32.cpp @@ -524,7 +524,7 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_Exit(void) return FALSE; } -#ifndef WIN64 +#ifndef _WIN64 Hotkeys::Unload(); #endif From be1b8f6457e46b218e1384aa490b02870db5fdc9 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 7 Nov 2019 17:31:03 +1100 Subject: [PATCH 04/28] chore(developer): tidy up from review comments --- windows/src/engine/keyman32/hookutils.cpp | 8 ++++---- windows/src/engine/keyman32/{K32_DBG.CPP => k32_dbg.cpp} | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) rename windows/src/engine/keyman32/{K32_DBG.CPP => k32_dbg.cpp} (99%) diff --git a/windows/src/engine/keyman32/hookutils.cpp b/windows/src/engine/keyman32/hookutils.cpp index 008bda99d1..da03f4ac5e 100644 --- a/windows/src/engine/keyman32/hookutils.cpp +++ b/windows/src/engine/keyman32/hookutils.cpp @@ -75,15 +75,15 @@ DWORD ExceptionMessage(LPSTR Proc, LPEXCEPTION_POINTERS ep) { if (er->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { OutputThreadDebugString("EXCEPTION_ACCESS_VIOLATION in "); OutputThreadDebugString(Proc); - SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d (ACCESS VIOLATION) IN %s AT %x; attempted to %s %x", + /*SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d (ACCESS VIOLATION) IN %s AT %x; attempted to %s %x", er->ExceptionCode, Proc, er->ExceptionAddress, er->ExceptionInformation[0] == 0 ? "read from" : "write to", - er->ExceptionInformation[1]); + er->ExceptionInformation[1]);*/ } else { OutputThreadDebugString("CAUGHT EXCEPTION"); - SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d IN %s AT %x", - er->ExceptionCode, Proc, er->ExceptionAddress); + /*SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d IN %s AT %x", + er->ExceptionCode, Proc, er->ExceptionAddress);*/ } er = er->ExceptionRecord; } diff --git a/windows/src/engine/keyman32/K32_DBG.CPP b/windows/src/engine/keyman32/k32_dbg.cpp similarity index 99% rename from windows/src/engine/keyman32/K32_DBG.CPP rename to windows/src/engine/keyman32/k32_dbg.cpp index a6e28b0873..f78eb737fa 100644 --- a/windows/src/engine/keyman32/K32_DBG.CPP +++ b/windows/src/engine/keyman32/k32_dbg.cpp @@ -309,7 +309,7 @@ char *Debug_UnicodeString(PWSTR s, int x) { #ifdef _DEBUG void _OutputThreadDebugString(char *s) { char buf[256]; - wsprintf(buf, "[%d]: %s\n", GetCurrentThreadId(), s); + sprintf_s(buf, "[%d]: %s\n", GetCurrentThreadId(), s); OutputDebugString(buf); } #endif From b7d4e83270de4dc2e2a8c1df29b63e9cdfe7f074 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 8 Nov 2019 09:40:40 +1100 Subject: [PATCH 05/28] chore(windows): unreferenced param in release build --- windows/src/engine/keyman32/hookutils.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/windows/src/engine/keyman32/hookutils.cpp b/windows/src/engine/keyman32/hookutils.cpp index da03f4ac5e..6ccccae719 100644 --- a/windows/src/engine/keyman32/hookutils.cpp +++ b/windows/src/engine/keyman32/hookutils.cpp @@ -16,6 +16,10 @@ typedef BOOL ); DWORD ExceptionMessage(LPSTR Proc, LPEXCEPTION_POINTERS ep) { +#ifndef _DEBUG + UNREFERENCED_PARAMETER(Proc); +#endif + MINIDUMP_EXCEPTION_INFORMATION mei; char filename[MAX_PATH], temppath[MAX_PATH]; if (GetTempPath(MAX_PATH, temppath) == 0 || From f67b259bc25b4d79201ae6872ba3dbe469bad546 Mon Sep 17 00:00:00 2001 From: Sandra Forberger Date: Fri, 8 Nov 2019 13:59:12 +0700 Subject: [PATCH 06/28] feat[android]: add waiting dialog when catalog is updating --- .../kmea/LanguageListActivity.java | 44 ++++++++++++++++--- .../data/CloudCatalogDownloadCallback.java | 4 ++ .../kmea/data/CloudRepository.java | 17 ++++--- .../activity_list_with_progress_layout.xml | 15 +++++++ .../src/main/res/layout/progress_layout.xml | 24 ++++++++++ .../KMEA/app/src/main/res/values/strings.xml | 2 +- 6 files changed, 93 insertions(+), 13 deletions(-) create mode 100644 android/KMEA/app/src/main/res/layout/activity_list_with_progress_layout.xml create mode 100644 android/KMEA/app/src/main/res/layout/progress_layout.xml diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java index 7d77337573..6390309e19 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java @@ -4,9 +4,6 @@ package com.tavultesoft.kmea; -import java.io.File; -import java.io.FileInputStream; -import java.io.ObjectInputStream; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -29,6 +26,7 @@ import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import android.content.Context; import android.content.Intent; +import android.database.DataSetObserver; import android.os.Bundle; import androidx.appcompat.widget.Toolbar; import android.util.Log; @@ -39,6 +37,7 @@ import android.view.Window; import android.widget.AdapterView; import android.widget.ImageView; import android.widget.ListView; +import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; @@ -59,6 +58,8 @@ public final class LanguageListActivity extends AppCompatActivity implements OnK // These two JSON objects and their getters are still used by legacy metadata functions. private static JSONArray languages = null; + private DataSetObserver repoObserver; + private Dataset repo; protected static JSONArray languages() { return languages; @@ -76,12 +77,27 @@ public final class LanguageListActivity extends AppCompatActivity implements OnK private static AlertDialog alertDialog; + private void updateProgressBar() + { + RelativeLayout _progress = findViewById(R.id.progress); + boolean _updaterunning= CloudRepository.shared.isUpdateRunning(); + ListView _list = findViewById(R.id.listView); + if(_updaterunning) + { + _progress.setVisibility(View.VISIBLE); + _list.setVisibility(View.GONE); + } + else { + _progress.setVisibility(View.GONE); + _list.setVisibility(View.VISIBLE); + } + } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); supportRequestWindowFeature(Window.FEATURE_NO_TITLE); context = this; - setContentView(R.layout.activity_list_layout); + setContentView(R.layout.activity_list_with_progress_layout); toolbar = (Toolbar) findViewById(R.id.list_toolbar); setSupportActionBar(toolbar); @@ -91,11 +107,21 @@ public final class LanguageListActivity extends AppCompatActivity implements OnK TextView textView = (TextView) findViewById(R.id.bar_title); textView.setText(getString(R.string.title_add_language)); - listView = (ListView) findViewById(R.id.listView); + listView = findViewById(R.id.listView); listView.setFastScrollEnabled(true); // Establish the list view based on the CloudRepository's Dataset. - Dataset repo = CloudRepository.shared.fetchDataset(this); + repo = CloudRepository.shared.fetchDataset(this); + + repoObserver = new DataSetObserver() { + @Override + public void onChanged() { + updateProgressBar(); + } + }; + repo.registerDataSetObserver(repoObserver); + + updateProgressBar(); listView.setAdapter(new LanguagesAdapter(this, repo)); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @@ -416,4 +442,10 @@ public final class LanguageListActivity extends AppCompatActivity implements OnK return !KeyboardPickerActivity.containsKeyboard(context, kbKey); } } + + @Override + protected void onDestroy() { + super.onDestroy(); + repo.unregisterDataSetObserver(repoObserver); + } } \ No newline at end of file diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudCatalogDownloadCallback.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudCatalogDownloadCallback.java index 8d3e9a2269..becfba3f16 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudCatalogDownloadCallback.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudCatalogDownloadCallback.java @@ -131,6 +131,7 @@ public class CloudCatalogDownloadCallback implements ICloudDownloadCallback + + + + + + + + + diff --git a/android/KMEA/app/src/main/res/layout/progress_layout.xml b/android/KMEA/app/src/main/res/layout/progress_layout.xml new file mode 100644 index 0000000000..f1ef38d391 --- /dev/null +++ b/android/KMEA/app/src/main/res/layout/progress_layout.xml @@ -0,0 +1,24 @@ + + + + + + + diff --git a/android/KMEA/app/src/main/res/values/strings.xml b/android/KMEA/app/src/main/res/values/strings.xml index df77ff5223..cbf5aa0daf 100644 --- a/android/KMEA/app/src/main/res/values/strings.xml +++ b/android/KMEA/app/src/main/res/values/strings.xml @@ -59,7 +59,7 @@ Downloading dictionary… The resource catalog is unavailable\n Catalog update started in background.\n - The catalog is still downloading; please try again in a moment!\n + The catalog is still downloading;\nplease try again in a moment!\n Failed to access server!\n From 59b18d144325661ea8d42ee87a455b72af0bd4e1 Mon Sep 17 00:00:00 2001 From: Sandra Forberger Date: Fri, 8 Nov 2019 15:22:15 +0700 Subject: [PATCH 07/28] feat[android]: add progressbar to add language dialog --- .../main/java/com/tavultesoft/kmea/LanguageListActivity.java | 2 +- .../main/java/com/tavultesoft/kmea/data/CloudRepository.java | 2 +- android/KMEA/app/src/main/res/layout/progress_layout.xml | 2 +- android/KMEA/app/src/main/res/values/strings.xml | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java index 6390309e19..3135c1cb4a 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java @@ -80,7 +80,7 @@ public final class LanguageListActivity extends AppCompatActivity implements OnK private void updateProgressBar() { RelativeLayout _progress = findViewById(R.id.progress); - boolean _updaterunning= CloudRepository.shared.isUpdateRunning(); + boolean _updaterunning= CloudRepository.shared.updateIsRunning(); ListView _list = findViewById(R.id.listView); if(_updaterunning) { diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudRepository.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudRepository.java index 5d576c08b3..e433d4d5fe 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudRepository.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudRepository.java @@ -399,7 +399,7 @@ public class CloudRepository { updateIsRunning=false; } - public boolean isUpdateRunning() { + public boolean updateIsRunning() { return updateIsRunning; } } diff --git a/android/KMEA/app/src/main/res/layout/progress_layout.xml b/android/KMEA/app/src/main/res/layout/progress_layout.xml index f1ef38d391..927f0e2f7c 100644 --- a/android/KMEA/app/src/main/res/layout/progress_layout.xml +++ b/android/KMEA/app/src/main/res/layout/progress_layout.xml @@ -17,7 +17,7 @@ android:id="@+id/progressbarmessage" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/catalog_download_is_running_in_background" + android:text="@string/progress_message_catalog_download_is_running" android:layout_centerInParent="true" android:layout_below="@+id/progressbar" /> diff --git a/android/KMEA/app/src/main/res/values/strings.xml b/android/KMEA/app/src/main/res/values/strings.xml index cbf5aa0daf..f34995b617 100644 --- a/android/KMEA/app/src/main/res/values/strings.xml +++ b/android/KMEA/app/src/main/res/values/strings.xml @@ -59,7 +59,8 @@ Downloading dictionary… The resource catalog is unavailable\n Catalog update started in background.\n - The catalog is still downloading;\nplease try again in a moment!\n + The catalog is still downloading; please try again in a moment!\n + The catalog is still downloading!\n Failed to access server!\n From 1575dede55d19d8b9d64847a3f5cfa1368483e9f Mon Sep 17 00:00:00 2001 From: Sandra Forberger Date: Fri, 8 Nov 2019 15:50:13 +0700 Subject: [PATCH 08/28] feat[android]: add progress to add keyboard function --- .../kmea/KeyboardListActivity.java | 49 ++++++++++++++++++- .../kmea/LanguageListActivity.java | 38 ++++++++------ 2 files changed, 70 insertions(+), 17 deletions(-) diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardListActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardListActivity.java index 26eca3f0bc..4bbadf9bf7 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardListActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardListActivity.java @@ -21,6 +21,7 @@ import androidx.appcompat.widget.Toolbar; import android.content.Context; import android.content.Intent; +import android.database.DataSetObserver; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; @@ -30,6 +31,7 @@ import android.view.Window; import android.widget.AdapterView; import android.widget.ImageView; import android.widget.ListView; +import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; @@ -40,13 +42,16 @@ public final class KeyboardListActivity extends AppCompatActivity implements OnK private static ListView listView = null; private static final String TAG = "KeyboardListActivity"; + private DataSetObserver repoObserver; + private Dataset repo; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); supportRequestWindowFeature(Window.FEATURE_NO_TITLE); final Context context = this; - setContentView(R.layout.activity_list_layout); + setContentView(R.layout.activity_list_with_progress_layout); toolbar = (Toolbar) findViewById(R.id.list_toolbar); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); @@ -61,7 +66,20 @@ public final class KeyboardListActivity extends AppCompatActivity implements OnK String langID = getIntent().getStringExtra("languageCode"); String langName = getIntent().getStringExtra("languageName"); - Dataset repo = CloudRepository.shared.fetchDataset(this); + repo = CloudRepository.shared.fetchDataset(this); + + // add listener to dataset to get event for catalog update. + repoObserver = new DataSetObserver() { + @Override + public void onChanged() { + updateProgressBar(); + } + }; + repo.registerDataSetObserver(repoObserver); + + // init progress bar state + updateProgressBar(); + final FilteredKeyboardsAdapter adapter = new FilteredKeyboardsAdapter(this, repo, langID); textView.setText(langName); @@ -103,6 +121,25 @@ public final class KeyboardListActivity extends AppCompatActivity implements OnK }); } + /** + * switch between progress and listview. + */ + private void updateProgressBar() + { + RelativeLayout _progress = findViewById(R.id.progress); + boolean _updaterunning= CloudRepository.shared.updateIsRunning(); + ListView _list = findViewById(R.id.listView); + if(_updaterunning) + { + _progress.setVisibility(View.VISIBLE); + _list.setVisibility(View.GONE); + } + else { + _progress.setVisibility(View.GONE); + _list.setVisibility(View.VISIBLE); + } + } + @Override protected void onResume() { super.onResume(); @@ -117,6 +154,14 @@ public final class KeyboardListActivity extends AppCompatActivity implements OnK // ensure onKeyboardDownloadFinished() gets called } + @Override + protected void onDestroy() { + super.onDestroy(); + // remove listener from dataset. + repo.unregisterDataSetObserver(repoObserver); + } + + @Override public boolean onSupportNavigateUp() { onBackPressed(); diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java index 3135c1cb4a..be67aaadd3 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java @@ -77,21 +77,6 @@ public final class LanguageListActivity extends AppCompatActivity implements OnK private static AlertDialog alertDialog; - private void updateProgressBar() - { - RelativeLayout _progress = findViewById(R.id.progress); - boolean _updaterunning= CloudRepository.shared.updateIsRunning(); - ListView _list = findViewById(R.id.listView); - if(_updaterunning) - { - _progress.setVisibility(View.VISIBLE); - _list.setVisibility(View.GONE); - } - else { - _progress.setVisibility(View.GONE); - _list.setVisibility(View.VISIBLE); - } - } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -113,14 +98,17 @@ public final class LanguageListActivity extends AppCompatActivity implements OnK // Establish the list view based on the CloudRepository's Dataset. repo = CloudRepository.shared.fetchDataset(this); + // add listener to dataset to get event for catalog update. repoObserver = new DataSetObserver() { @Override public void onChanged() { updateProgressBar(); } }; + repo.registerDataSetObserver(repoObserver); + // init progress bar state updateProgressBar(); listView.setAdapter(new LanguagesAdapter(this, repo)); @@ -186,6 +174,25 @@ public final class LanguageListActivity extends AppCompatActivity implements OnK listView.setSelectionFromTop(i.getIntExtra("listPosition", 0), i.getIntExtra("offsetY", 0)); } + /** + * switch between progress and listview. + */ + private void updateProgressBar() + { + RelativeLayout _progress = findViewById(R.id.progress); + boolean _updaterunning= CloudRepository.shared.updateIsRunning(); + ListView _list = findViewById(R.id.listView); + if(_updaterunning) + { + _progress.setVisibility(View.VISIBLE); + _list.setVisibility(View.GONE); + } + else { + _progress.setVisibility(View.GONE); + _list.setVisibility(View.VISIBLE); + } + } + @Override protected void onResume() { super.onResume(); @@ -446,6 +453,7 @@ public final class LanguageListActivity extends AppCompatActivity implements OnK @Override protected void onDestroy() { super.onDestroy(); + // remove listener from dataset. repo.unregisterDataSetObserver(repoObserver); } } \ No newline at end of file From 7222ca07d74a87f8e6db236d3f57f431df4de82d Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Fri, 8 Nov 2019 13:32:35 +0700 Subject: [PATCH 09/28] fix(android): Sanitize version for API query Fixes #2298 Sanitize the app version to `#.#.#` to match the API query spec --- .../com/tavultesoft/kmea/data/CloudRepository.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudRepository.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudRepository.java index c4dc76bb8d..dcd81e5e42 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudRepository.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudRepository.java @@ -28,6 +28,8 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; +import java.util.regex.Pattern; +import java.util.regex.Matcher; public class CloudRepository { static public final CloudRepository shared = new CloudRepository(); @@ -123,9 +125,18 @@ public class CloudRepository { { String deviceType = CloudDataJsonUtil.getDeviceTypeForCloudQuery(aContext); + // Sanitize appVersion to #.#.# to match the API spec + // Regex needs to match the entire string + String appVersion = BuildConfig.VERSION_NAME; + Pattern pattern = Pattern.compile("(\\d+\\.\\d+\\.\\d+).*"); + Matcher matcher = pattern.matcher(appVersion); + if (matcher.matches() && matcher.groupCount() >= 1) { + appVersion = matcher.group(1); + } + // Retrieves the cloud-based keyboard catalog in Android's preferred format. String keyboardURL = String.format("%s?version=%s&device=%s&languageidtype=bcp47", - KMKeyboardDownloaderActivity.kKeymanApiBaseURL, BuildConfig.VERSION_NAME, deviceType); + KMKeyboardDownloaderActivity.kKeymanApiBaseURL, appVersion, deviceType); //cloudQueries[cloudQueryEntries++] = new CloudApiParam(ApiTarget.Keyboards, keyboardURL, JSONType.Object); return new CloudApiTypes.CloudApiParam( From c8f66dd9cecf8b1a8c0a4862e3bfb9694d154705 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Mon, 11 Nov 2019 12:02:57 +0100 Subject: [PATCH 10/28] chore(linux): Update dependencies for Linux packaging Also fix a typo in section name. --- linux/build/agent/dependencies.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux/build/agent/dependencies.config b/linux/build/agent/dependencies.config index bf070fd82e..83c5e48313 100644 --- a/linux/build/agent/dependencies.config +++ b/linux/build/agent/dependencies.config @@ -20,10 +20,10 @@ # any=@precise.any [common] -any=git autotools-dev build-essential dh-autoreconf libibus-1.0-dev flex bison +any=git autotools-dev build-essential dh-autoreconf libibus-1.0-dev flex bison meson [xenial] any=libx11-dev -[bionix] +[bionic] any=@xenial.any From 798a638499f7009c34e5c649ac0319823980282f Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Mon, 11 Nov 2019 15:33:15 +0100 Subject: [PATCH 11/28] style(linux): normalize whitespace --- linux/scripts/reconf.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linux/scripts/reconf.sh b/linux/scripts/reconf.sh index d783a9db35..e2dd557838 100755 --- a/linux/scripts/reconf.sh +++ b/linux/scripts/reconf.sh @@ -15,18 +15,18 @@ extra_projects="keyboardprocessor keyman-config" if [ "$1" != "" ]; then if [ "$1" == "keyboardprocessor" ]; then - echo "reconfiguring only keyboardprocessor" + echo "reconfiguring only keyboardprocessor" extra_projects="keyboardprocessor" autotool_projects="" elif [ ! -d "$1" ]; then echo "project $1 does not exist" exit 1 elif [ "$1" == "keyman-config" ]; then - echo "reconfiguring only keyman-config" + echo "reconfiguring only keyman-config" extra_projects="keyman-config" autotool_projects="" else - echo "reconfiguring only $1" + echo "reconfiguring only $1" autotool_projects="$1" extra_projects="" fi From adbf174c5546e02cb1c00c291cbb0fa8d6c21ca8 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Mon, 11 Nov 2019 15:34:38 +0100 Subject: [PATCH 12/28] chore(linux): Allow to skip calculation of version number This change allows to calculate the version number once at the beginning and then skip the calculation when we create the source packages for the various packages. This allows to set the version number in Jenkins early on. --- linux/scripts/reconf.sh | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/linux/scripts/reconf.sh b/linux/scripts/reconf.sh index e2dd557838..dd87062218 100755 --- a/linux/scripts/reconf.sh +++ b/linux/scripts/reconf.sh @@ -32,15 +32,20 @@ if [ "$1" != "" ]; then fi fi -JENKINS=${JENKINS:="no"} -oldvers=`cat VERSION` +if [ -n $SKIPVERSION ]; then + oldvers=$(cat OLDVERSION) + newvers=$(cat VERSION) +else + JENKINS=${JENKINS:="no"} + oldvers=`cat VERSION` -. $(dirname "$0")/version.sh + . $(dirname "$0")/version.sh -version + version -echo "version: ${newvers}" -echo "${newvers}" > VERSION + echo "version: ${newvers}" + echo "${newvers}" > VERSION +fi # autoreconf the projects for proj in ${autotool_projects}; do From 5c490feb0383e4a2c1ab70a30d48fa75a930f32e Mon Sep 17 00:00:00 2001 From: safolit <52272980+safolit@users.noreply.github.com> Date: Tue, 12 Nov 2019 10:44:10 +0700 Subject: [PATCH 13/28] Update history.md --- android/history.md | 1 + 1 file changed, 1 insertion(+) diff --git a/android/history.md b/android/history.md index b231893425..d5bcee3744 100644 --- a/android/history.md +++ b/android/history.md @@ -4,6 +4,7 @@ * Start version 13.0 * New Features: * Adding a download manager to execute downloads in background and cleanup the existing implementation (#2247, #2275, #2308) + * Show spinner (without blocking UI), if user wants to add a language/keyboard and catalog download is in progress (#2313) * Improve custom package installation: Show readme.htm before starting installation process (#2286) * Update target Android SDK version to 29 (#2279) * Add linting to Debug builds and resolve lint errors (#2305) From a26e9862136d00e5669fee35699ba8902b8a637c Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Tue, 12 Nov 2019 13:59:42 +0700 Subject: [PATCH 14/28] fix(android): Add `^` anchor to regex Per review comment --- .../main/java/com/tavultesoft/kmea/data/CloudRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudRepository.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudRepository.java index dcd81e5e42..b15ff31472 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudRepository.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudRepository.java @@ -128,7 +128,7 @@ public class CloudRepository { // Sanitize appVersion to #.#.# to match the API spec // Regex needs to match the entire string String appVersion = BuildConfig.VERSION_NAME; - Pattern pattern = Pattern.compile("(\\d+\\.\\d+\\.\\d+).*"); + Pattern pattern = Pattern.compile("^(\\d+\\.\\d+\\.\\d+).*"); Matcher matcher = pattern.matcher(appVersion); if (matcher.matches() && matcher.groupCount() >= 1) { appVersion = matcher.group(1); From cfddb6a4889996ee22cc38cec58ad2db2c2cf07d Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Tue, 12 Nov 2019 14:06:14 +0700 Subject: [PATCH 15/28] chore(android): Update history.md --- android/history.md | 1 + 1 file changed, 1 insertion(+) diff --git a/android/history.md b/android/history.md index b231893425..a37baadf6a 100644 --- a/android/history.md +++ b/android/history.md @@ -7,6 +7,7 @@ * Improve custom package installation: Show readme.htm before starting installation process (#2286) * Update target Android SDK version to 29 (#2279) * Add linting to Debug builds and resolve lint errors (#2305) + * Sanitize the app version to `#.#.#` for the API cloud query (#2319) ## 2019-10-30 12.0.4206 stable * Bug fix: From 4aa2afb10ccb2c1b949a0fb10d44fc1762a17c52 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 12 Nov 2019 08:39:30 +0100 Subject: [PATCH 16/28] fix(linux): Fix Linux package build --- linux/scripts/reconf.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux/scripts/reconf.sh b/linux/scripts/reconf.sh index dd87062218..076acd14bc 100755 --- a/linux/scripts/reconf.sh +++ b/linux/scripts/reconf.sh @@ -32,7 +32,7 @@ if [ "$1" != "" ]; then fi fi -if [ -n $SKIPVERSION ]; then +if [ -n "$SKIPVERSION" -a -f OLDVERSION ]; then oldvers=$(cat OLDVERSION) newvers=$(cat VERSION) else From 0a85fef86ba6b8bac7e16dd58aecb73c85d605e4 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 12 Nov 2019 18:42:04 +0100 Subject: [PATCH 17/28] chore(common): Add .editorconfig file This allows IDEs to automatically pick up the preferred coding style and might help with a more consistent use of spaces/tabs for indentation. --- .editorconfig | 13 +++++++++++++ linux/scripts/.editorconfig | 4 ++++ 2 files changed, 17 insertions(+) create mode 100644 .editorconfig create mode 100644 linux/scripts/.editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..e89330a618 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/linux/scripts/.editorconfig b/linux/scripts/.editorconfig new file mode 100644 index 0000000000..020438e0c6 --- /dev/null +++ b/linux/scripts/.editorconfig @@ -0,0 +1,4 @@ +# Editor configuration, see https://editorconfig.org +[*] +indent_style = space +indent_size = 4 From 3c4ac01dd5230ae45ef010b00efddce3c6380bc9 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 12 Nov 2019 18:54:34 +0100 Subject: [PATCH 18/28] style(linux): normalize whitespace --- linux/scripts/reconf.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linux/scripts/reconf.sh b/linux/scripts/reconf.sh index 076acd14bc..a8b3ea127a 100755 --- a/linux/scripts/reconf.sh +++ b/linux/scripts/reconf.sh @@ -15,18 +15,18 @@ extra_projects="keyboardprocessor keyman-config" if [ "$1" != "" ]; then if [ "$1" == "keyboardprocessor" ]; then - echo "reconfiguring only keyboardprocessor" + echo "reconfiguring only keyboardprocessor" extra_projects="keyboardprocessor" autotool_projects="" elif [ ! -d "$1" ]; then echo "project $1 does not exist" exit 1 elif [ "$1" == "keyman-config" ]; then - echo "reconfiguring only keyman-config" + echo "reconfiguring only keyman-config" extra_projects="keyman-config" autotool_projects="" else - echo "reconfiguring only $1" + echo "reconfiguring only $1" autotool_projects="$1" extra_projects="" fi From 5a8f5a958de7075317fcebfb1bdbc34e9e8f0cfd Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 13 Nov 2019 07:14:16 +1100 Subject: [PATCH 19/28] chore(web): history --- web/history.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/web/history.md b/web/history.md index 021fd33d8f..ececec1c82 100644 --- a/web/history.md +++ b/web/history.md @@ -2,10 +2,17 @@ ## 13.0 alpha * Start version 13.0 -* Testing for upcoming patch to stable: - * Fixes issue with mnemonic keyboard handling of backspace and delete keys (#2288) - * Fix for iOS Safari's "Request Desktop Website" option disabling touch interactivity (#2283) - * Fix for keyboards using rules with the `nul` statement that replace the full context (#2284) + +## 2019-11-13 12.0.102 stable +* Fixes issue with mnemonic keyboard handling of backspace and delete keys (#2288) +* Fix for iOS Safari's "Request Desktop Website" option disabling touch interactivity (#2283) +* Fix for keyboards using rules with the `nul` statement that replace the full context (#2284) + +## 2019-10-10 12.0.101 stable +* Fixes issue with keyboards requiring special state notifications, such as the CJK picker keyboards (#2194) + +## 2019-10-07 12.0.100 stable +* Release 12.0 ## 2019-10-04 12.0.90 beta * Fixes next-layer management complications with predictive correction data computation (#2172) From 3ebddd9f25c2fe1995cd6b2124b4c3b7c1c59e25 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 13 Nov 2019 08:28:14 +1100 Subject: [PATCH 20/28] fix(windows): OSK restores to wrong monitor If the On Screen Keyboard was closed when on a monitor other than the primary monitor, it would restore to the primary monitor in the top- left corner instead of the previous location. This fix allows the OSK to be restored to another monitor, but still avoids positioning the window off screen if the monitor has been disconnected. Fixes #2270. --- .../keyman/viskbd/UfrmVisualKeyboard.pas | 62 +++++++++++++++++-- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/windows/src/engine/keyman/viskbd/UfrmVisualKeyboard.pas b/windows/src/engine/keyman/viskbd/UfrmVisualKeyboard.pas index 9417d4597c..5205cc0b54 100644 --- a/windows/src/engine/keyman/viskbd/UfrmVisualKeyboard.pas +++ b/windows/src/engine/keyman/viskbd/UfrmVisualKeyboard.pas @@ -280,6 +280,8 @@ type implementation uses + System.Types, + CommCtrl, GraphUtil, KeymanHints, @@ -303,7 +305,7 @@ uses VistaMessages, MessageIdentifierConsts, messageidentifiers, - BitmapIPicture, Types; + BitmapIPicture; {$R *.DFM} @@ -1331,12 +1333,62 @@ begin end; procedure TfrmVisualKeyboard.LoadSettings; - procedure MoveBounds(R: TRect); + function FitRectInBounds(R, BR: TRect): TRect; begin - if (R.Left < R.Right) and (R.Top < R.Bottom) and (R.Left >= 0) and (R.Top >= 0) and - (R.Bottom <= Screen.Height) and (R.Right <= Screen.Width) then - BoundsRect := R; + if R.Width > BR.Width then + R.Width := BR.Width; + + if R.Height > BR.Height then + R.Height := BR.Height; + + if R.Left < BR.Left then + R.Offset(BR.Left-R.Left, 0); + + if R.Right > BR.Right then + R.Offset(BR.Right-R.Right, 0); + + if R.Top < BR.Top then + R.Offset(0, BR.Top-R.Top); + + if R.Bottom > BR.Bottom then + R.Offset(0, BR.Bottom-R.Bottom); + + Result := R; end; + + procedure MoveBounds(R: TRect); + var + area, i: Integer; + m: Integer; + BR, RI: TRect; + begin + // Adjust the rectangle to ensure TopLeft <= BottomRight + R.NormalizeRect; + + // Move the rect onto the screen (e.g. when monitor is disconnected, + // we don't want to show the OSK off the screen). It is valid for the window + // rect to go negative, if for example primary monitor is not left-most. + + // If the OSK is partially on-screen, move it onto the monitor where it has + // the most real-estate. + m := 0; area := 0; + for i := 0 to Screen.MonitorCount - 1 do + begin + if System.Types.IntersectRect(RI, R, Screen.Monitors[i].BoundsRect) then + begin + if RI.Width * RI.Height > area then + begin + area := RI.Width * RI.Height; + m := i; + end; + end; + end; + + BR := Screen.Monitors[m].WorkareaRect; + + Self.BoundsRect := FitRectInBounds(R, BR); + end; + procedure MoveDefault; begin SetBounds(Screen.WorkAreaRect.Right - Width, Screen.WorkAreaRect.Bottom - Height, Width, Height); From 13567d2a769ff45a6186e934f09c0dc19d79c502 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 13 Nov 2019 10:44:23 +1100 Subject: [PATCH 21/28] fix(windows): focus is incorrect for CEF The focus code paths for Chromium frames (CEF4Delphi) were incorrect. The return value for preventing focus on navigation events was inverted, and then other code was attempting to work around this inversion, wrongly. Fixed the root issue of the inverted test (it would help if the parameter cefSetFocus was known as `Handled` rather than `Result`!) and then the remaining code pathways became far simpler. Fixes #2314. --- .../Keyman.Developer.UI.UframeCEFHost.dfm | 1 - .../Keyman.Developer.UI.UframeCEFHost.pas | 29 ++++--------------- .../developer/TIKE/main/UframeTextEditor.pas | 1 - 3 files changed, 6 insertions(+), 25 deletions(-) diff --git a/windows/src/developer/TIKE/main/Keyman.Developer.UI.UframeCEFHost.dfm b/windows/src/developer/TIKE/main/Keyman.Developer.UI.UframeCEFHost.dfm index bdbacd30c4..b326cf9e21 100644 --- a/windows/src/developer/TIKE/main/Keyman.Developer.UI.UframeCEFHost.dfm +++ b/windows/src/developer/TIKE/main/Keyman.Developer.UI.UframeCEFHost.dfm @@ -34,7 +34,6 @@ inherited frameCEFHost: TframeCEFHost Top = 208 end object cef: TChromium - OnWidgetCompMsg = cefWidgetCompMsg OnLoadEnd = cefLoadEnd OnSetFocus = cefSetFocus OnRunContextMenu = cefRunContextMenu diff --git a/windows/src/developer/TIKE/main/Keyman.Developer.UI.UframeCEFHost.pas b/windows/src/developer/TIKE/main/Keyman.Developer.UI.UframeCEFHost.pas index 818205d189..63d0138cfb 100644 --- a/windows/src/developer/TIKE/main/Keyman.Developer.UI.UframeCEFHost.pas +++ b/windows/src/developer/TIKE/main/Keyman.Developer.UI.UframeCEFHost.pas @@ -35,7 +35,6 @@ const CEF_AFTERCREATE = WM_USER + 302; CEF_SHOW = WM_USER + 303; CEF_LOADEND = WM_USER + 304; - CEF_SETFOCUS = WM_USER + 305; CEF_KEYEVENT = WM_USER + 306; CEF_BEFOREBROWSE = WM_USER + 307; CEF_CONSOLEMESSAGE = WM_USER + 308; @@ -106,7 +105,6 @@ type var settings: TCefBrowserSettings; var noJavascriptAccess: Boolean; var Result: Boolean); - procedure cefWidgetCompMsg(var aMessage: TMessage; var aHandled: Boolean); procedure cefSetFocus(Sender: TObject; const browser: ICefBrowser; source: TCefFocusSource; out Result: Boolean); private @@ -134,7 +132,6 @@ type procedure Handle_CEF_AFTERCREATE(var Message: TMessage); procedure Handle_CEF_SHOW(var message: TMessage); procedure Handle_CEF_LOADEND(var message: TMessage); - procedure Handle_CEF_SETFOCUS(var message: TMessage); procedure Handle_CEF_KEYEVENT(var message: TMessage); procedure Handle_CEF_BEFOREBROWSE(var message: TMessage); procedure Handle_CEF_CONSOLEMESSAGE(var message: TMessage); @@ -268,14 +265,6 @@ begin CreateBrowser; end; -procedure TframeCEFHost.cefWidgetCompMsg(var aMessage: TMessage; - var aHandled: Boolean); -begin - AssertCefThread; - if aMessage.Msg = WM_SETFOCUS then - PostMessage(FCallbackWnd, CEF_SETFOCUS, 0, 0); -end; - procedure TframeCEFHost.CreateBrowser; begin AssertVclThread; @@ -308,9 +297,11 @@ end; procedure TframeCEFHost.SetFocus; begin AssertVclThread; - inherited; - if not FIsClosing and cefwp.CanFocus then - cefwp.SetFocus; + if not FIsClosing and cefwp.CanFocus and Assigned(cef) then + begin + GetParentForm(Self).ActiveControl := Self; + cef.SetFocus(True); + end; end; procedure TframeCEFHost.CallbackWndProc(var Message: TMessage); @@ -322,7 +313,6 @@ begin CEF_AFTERCREATE: Handle_CEF_AFTERCREATE(Message); CEF_SHOW: Handle_CEF_SHOW(Message); CEF_LOADEND: Handle_CEF_LOADEND(Message); - CEF_SETFOCUS: Handle_CEF_SETFOCUS(Message); CEF_KEYEVENT: Handle_CEF_KEYEVENT(Message); CEF_BEFOREBROWSE: Handle_CEF_BEFOREBROWSE(Message); CEF_CONSOLEMESSAGE: Handle_CEF_CONSOLEMESSAGE(Message); @@ -534,13 +524,6 @@ begin FOnLoadEnd(Self); end; -procedure TframeCEFHost.Handle_CEF_SETFOCUS(var message: TMessage); -begin - AssertVclThread; - if Assigned(cefwp) and cefwp.Visible and cefwp.CanFocus then - GetParentForm(cefwp).ActiveControl := cefwp; -end; - procedure TframeCEFHost.cefPreKeyEvent(Sender: TObject; const browser: ICefBrowser; const event: PCefKeyEvent; osEvent: PMsg; out isKeyboardShortcut, Result: Boolean); @@ -614,7 +597,7 @@ end; procedure TframeCEFHost.cefSetFocus(Sender: TObject; const browser: ICefBrowser; source: TCefFocusSource; out Result: Boolean); begin - Result := source <> FOCUS_SOURCE_NAVIGATION; + Result := source = FOCUS_SOURCE_NAVIGATION; end; procedure TframeCEFHost.WMEnterMenuLoop(var aMessage: TMessage); diff --git a/windows/src/developer/TIKE/main/UframeTextEditor.pas b/windows/src/developer/TIKE/main/UframeTextEditor.pas index 5b97d4b8f3..fca4d88760 100644 --- a/windows/src/developer/TIKE/main/UframeTextEditor.pas +++ b/windows/src/developer/TIKE/main/UframeTextEditor.pas @@ -656,7 +656,6 @@ end; procedure TframeTextEditor.SetFocus; begin - inherited; cef.SetFocus; end; From 773ed6224b07666caab4eb7c8fbb3cc4f07a3fef Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 13 Nov 2019 13:23:55 +1100 Subject: [PATCH 22/28] fix(developer): keyboard_info merge mobile wrong The .keyboard_info merge of `platformSupport` would not always give the right result, for .js keyboards. We have a certain lack of information in the .js which makes it a little tricky to determine precisely what the set of supported platforms are. Thus, if we find a .js within a .kmp, we'll assume it supports mobile; if we find a .js by itself, we'll assume it supports web. (Thus, a keyboard that builds a .js is assumed to always support web -- but not necessarily mobile now). Some keyboards that have incorrectly added a .js into a package, e.g. sil_cipher_music, will be marked as supporting mobile even though they don't. The correct fix here is to remove the .js from the package for that keyboard. --- .../TIKE/compile/MergeKeyboardInfo.pas | 33 +++++++------------ 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/windows/src/developer/TIKE/compile/MergeKeyboardInfo.pas b/windows/src/developer/TIKE/compile/MergeKeyboardInfo.pas index 4cefbe964c..86f1fe6501 100644 --- a/windows/src/developer/TIKE/compile/MergeKeyboardInfo.pas +++ b/windows/src/developer/TIKE/compile/MergeKeyboardInfo.pas @@ -327,9 +327,11 @@ begin SetLength(FPackageJSFileInfos, Length(FPackageJSFileInfos)+1); FPackageJSFileInfos[High(FPackageJSFileInfos)].Filename := Zip.FileNames[j]; - // For now, apply JS keyboard to all web and mobile targets + // Apply JS keyboard only to mobile targets, because web is not supported + // in a package. If a package does not support mobile, it should not include + // the .js. // Not using GetKeyboardInfo because that only handles kmx files - FPackageJSFileInfos[High(FPackageJSFileInfos)].Info.Targets := 'web mobile'; + FPackageJSFileInfos[High(FPackageJSFileInfos)].Info.Targets := 'mobile'; end; end; end; @@ -976,8 +978,6 @@ begin AddNewPair('windows', 'full'); AddNewPair('macos', 'full'); AddNewPair('linux', 'full'); - AddNewPair('desktopWeb', 'full'); - AddNewPair('mobileWeb', 'full'); AddNewPair('android', 'full'); AddNewPair('ios', 'full'); end @@ -1008,11 +1008,6 @@ begin // FPackageKMXFileInfos can contain target information for web/mobile targets. // This is a current limitation of FPackageJSFileInfos if there's no kmx files - if target = ktWeb then - begin - AddNewPair('desktopWeb', 'full'); - AddNewPair('mobileWeb', 'full'); - end; if (target = ktMobile) then begin AddNewPair('android', 'full'); @@ -1035,11 +1030,6 @@ begin targets := StringToKeymanTargets(keyboardFile.Info.Targets); for target in targets do begin - if (target = ktWeb) then - begin - AddNewPair('desktopWeb', 'full'); - AddNewPair('mobileWeb', 'full'); - end; if (target = ktMobile) then begin AddNewPair('android', 'full'); @@ -1056,16 +1046,17 @@ begin end; end; - // Handle JS file not in kmp - if FJsFile <> '' then + // Handle JS file not in kmp. Because it is isolated, we cannot detect + // whether it supports mobile vs desktop web because that is not included + // in the .js. So, for now we assume both. + // + // We no longer assume that the presence of a .js means support for + // native mobile apps. These apps now work on the basis of having a + // .kmp file available + if (FJsFile <> '') then begin AddNewPair('desktopWeb', 'full'); AddNewPair('mobileWeb', 'full'); - - // TODO: Don't add Android and iOS when we complete the addition of all .js keyboards - // to packages in the repository (including legacy keyboards) - AddNewPair('android', 'full'); - AddNewPair('ios', 'full'); end; json.AddPair('platformSupport', v); From f08f65ea90e3377feb386ac4734e64a6b19123e8 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Wed, 13 Nov 2019 11:17:59 +0100 Subject: [PATCH 23/28] chore(common): Update .editorconfig Follow-up of code review comments. --- .editorconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index e89330a618..1ba19987d4 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,4 +10,3 @@ trim_trailing_whitespace = true [*.md] max_line_length = off -trim_trailing_whitespace = false From 5513385edf6ec6fe7e53f1dcc9724acab2959818 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 15 Nov 2019 11:12:54 +1100 Subject: [PATCH 24/28] chore(windows): history.md --- windows/src/desktop/history.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/windows/src/desktop/history.md b/windows/src/desktop/history.md index 74e7f90de9..7a93845e62 100644 --- a/windows/src/desktop/history.md +++ b/windows/src/desktop/history.md @@ -3,6 +3,19 @@ ## 13.0 alpha * Start version 13.0 +## 2019-11-15 12.0.54 stable +* Bug Fix: On Screen Keyboard restored to wrong screen and position when reloading (#2330) + +## 2019-11-12 12.0.53 stable +* Bug Fix: Address instability when exiting Keyman on some systems (#2324) +* Bug Fix: Keyman was not working with Skype, Windows Search on some systems (#2324) + +## 2019-10-20 12.0.52 stable +* Upgrades from 11.0 and 12.0 were losing installed keyboards and settings (#2214) + +## 2019-10-07 12.0.50 stable +* Release 12.0 + ## 2019-10-03 12.0.42 beta * Bug Fix: Additional shutdown issues that sporadically occurred (#2157) * Fix issues starting debug logging for non-administrative users (#2153) From 8cdd68d88c9ba950c6fe452a7f49f75841f081ff Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 15 Nov 2019 11:08:00 +1100 Subject: [PATCH 25/28] chore(developer): history.md --- windows/src/developer/history.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/windows/src/developer/history.md b/windows/src/developer/history.md index 380d0457d8..69c69d909a 100644 --- a/windows/src/developer/history.md +++ b/windows/src/developer/history.md @@ -3,6 +3,12 @@ ## 13.0 alpha * Start version 13.0 +## 2019-11-15 12.0.54 stable +* Bug Fix: Text editor and other controls did not receive focus correctly (#2331) + +## 2019-10-07 12.0.50 stable +* Release 12.0 + ## 2019-10-05 12.0.45 beta * Touch Layout Editor: Make default padding in touch layout editor match default padding in KeymanWeb. (#2170) From f7a21e6d848444111832fb370bca31d56bf7a2b9 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 18 Nov 2019 16:10:38 +1100 Subject: [PATCH 26/28] fix(web): displayUnderlying flag was ignored Fixes #2311. The `displayUnderlying` flag introduced in #1539 was somehow missed from the 12.0 work. This PR restores the behaviour from 11.0 by adding the relevant changes from #1539. Tested in Chrome Emulator. --- web/source/osk/visualKeyboard.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/web/source/osk/visualKeyboard.ts b/web/source/osk/visualKeyboard.ts index 663f1e9d71..74a594766e 100644 --- a/web/source/osk/visualKeyboard.ts +++ b/web/source/osk/visualKeyboard.ts @@ -617,7 +617,12 @@ namespace com.keyman.osk { } // Set flag to add default (US English) key label if specified by keyboard - layout.keyLabels = activeKeyboard && ((typeof(activeKeyboard['KDU']) != 'undefined') && activeKeyboard['KDU']); + if(typeof layout['displayUnderlying'] != 'undefined') { + layout.keyLabels = layout['displayUnderlying'] == true; // force bool + } else { + layout.keyLabels = activeKeyboard && ((typeof(activeKeyboard['KDU']) != 'undefined') && activeKeyboard['KDU']); + } + let divLayerContainer = this.deviceDependentLayout(layout, util.device.formFactor); this.ddOSK = true; @@ -2126,7 +2131,11 @@ namespace com.keyman.osk { // Cannot create an OSK if no layout defined, just return empty DIV if(layout != null) { - layout.keyLabels=((typeof(PKbd['KDU']) != 'undefined') && PKbd['KDU']); + if(typeof layout['displayUnderlying'] != 'undefined') { + layout.keyLabels = layout['displayUnderlying'] == true; // force bool + } else { + layout.keyLabels = typeof(PKbd['KDU']) != 'undefined' && PKbd['KDU']; + } } // TODO: Fix this method's link! From d2df06a646b7ade390ed9d56a4671181d2888d7b Mon Sep 17 00:00:00 2001 From: jahorton Date: Mon, 18 Nov 2019 12:22:43 +0700 Subject: [PATCH 27/28] fix(web): Fixes #2322, updates to tsc 3.7.2 --- web/package-lock.json | 6 +++--- web/package.json | 2 +- web/source/kmwexthtml.ts | 2 -- web/source/osk/visualKeyboard.ts | 18 +++++++++++++----- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 027a9b9997..1c76459b5d 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -2314,9 +2314,9 @@ } }, "typescript": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.2.tgz", - "integrity": "sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.2.tgz", + "integrity": "sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==", "dev": true }, "uc.micro": { diff --git a/web/package.json b/web/package.json index fe57e635c7..c8e684ad7a 100644 --- a/web/package.json +++ b/web/package.json @@ -37,7 +37,7 @@ "karma-teamcity-reporter": "^1.1.0", "mocha": "^5.2.0", "modernizr": "^3.7.1", - "typescript": "^3.2.2" + "typescript": "^3.7.2" }, "scripts": { "tsc": "tsc", diff --git a/web/source/kmwexthtml.ts b/web/source/kmwexthtml.ts index d298110958..dede010fc0 100644 --- a/web/source/kmwexthtml.ts +++ b/web/source/kmwexthtml.ts @@ -23,8 +23,6 @@ interface Element { kmwInput: boolean, _kmwResizeHandler: (e: any) => void, - onselectstart: any, - // Used by our util.wait / util.alert system dismiss: () => void } diff --git a/web/source/osk/visualKeyboard.ts b/web/source/osk/visualKeyboard.ts index 663f1e9d71..54a5505d78 100644 --- a/web/source/osk/visualKeyboard.ts +++ b/web/source/osk/visualKeyboard.ts @@ -204,7 +204,7 @@ namespace com.keyman.osk { ts.fontFamily=spec['font']; } - if(typeof spec['fontsize'] == 'string' && spec['fontsize'] != 0) { + if(typeof spec['fontsize'] == 'string' && spec['fontsize'] != '') { ts.fontSize=spec['fontsize']; } @@ -564,12 +564,12 @@ namespace com.keyman.osk { // Function fields (fleshed out by kmwnative.ts and/or kmwembedded.ts) touchHold: (key: KeyElement) => void; optionKey: (e: KeyElement, keyName: string, keyDown: boolean) => void; - highlightSubKeys: (key: KeyElement, x: number, y: number) => void = this.highlightSubKeys || function(k,x,y) {}; + highlightSubKeys: (key: KeyElement, x: number, y: number) => void; showKeyTip: (key: KeyElement, on: boolean) => void; - drawPreview: (canvas: HTMLCanvasElement, w: number, h: number, edge: number) => void = this.drawPreview || function(c,w,h,e) {}; + drawPreview: (canvas: HTMLCanvasElement, w: number, h: number, edge: number) => void; createKeyTip: () => void; - addCallout: (key: KeyElement) => HTMLDivElement = this.addCallout || function(key) {return null}; - waitForFonts: (kfd,ofd) => boolean = this.waitForFonts || function(kfd,ofd){return true;}; // Default is used by embedded. + addCallout: (key: KeyElement) => HTMLDivElement; + waitForFonts: (kfd,ofd) => boolean; //#region OSK constructor and helpers @@ -581,6 +581,14 @@ namespace com.keyman.osk { * Description Generates the base visual keyboard element, prepping for attachment to KMW */ constructor(PVK, Lhelp, layout0: LayoutFormFactor, kbdBitmask: number) { + // Add handler stubs if not otherwise defined. (We can no longer in-line default-define with the declaration.) + this.highlightSubKeys = this.highlightSubKeys || function(k,x,y) {}; + this.drawPreview = this.drawPreview || function(c,w,h,e) {}; + this.addCallout = this.addCallout || function(key) {return null}; + this.waitForFonts = this.waitForFonts || function(kfd,ofd){return true;}; // Default is used by embedded. + + // Do normal constructor stuff. + let keyman = com.keyman.singleton; let util = keyman.util; From 3314125fd4df5e235e2e9f4706709ece4bdda8b5 Mon Sep 17 00:00:00 2001 From: jahorton Date: Mon, 18 Nov 2019 12:29:11 +0700 Subject: [PATCH 28/28] fix(web): Fixes #2328 - links reference for test resource compliation --- web/source/kmwdevice.ts | 3 +++ web/source/utils/version.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/web/source/kmwdevice.ts b/web/source/kmwdevice.ts index e08eab92f4..209587c65e 100644 --- a/web/source/kmwdevice.ts +++ b/web/source/kmwdevice.ts @@ -1,3 +1,6 @@ +// Includes version-related functionality +/// + // The Device object definition ------------------------------------------------- namespace com.keyman { diff --git a/web/source/utils/version.ts b/web/source/utils/version.ts index 7b64b37e53..de364dc71c 100644 --- a/web/source/utils/version.ts +++ b/web/source/utils/version.ts @@ -1,3 +1,6 @@ +// Ensure that this class contains no reference into core KMW code - it is referenced +// by components intended to be modular and possible to separate from core KMW. + namespace com.keyman.utils { // Dotted-decimal version export class Version {