From 18a72a1dd5c14152f10de202646034d4e105289f Mon Sep 17 00:00:00 2001 From: Ross Cruickshank Date: Thu, 3 Jun 2021 10:26:39 +1000 Subject: [PATCH 01/63] feat(windows): initial skeleton for integeration --- windows/src/engine/keyman32/K32_load.cpp | 12 ++++++++++- windows/src/engine/keyman32/globals.h | 4 ++++ windows/src/engine/keyman32/kmprocess.cpp | 8 ++++++++ windows/src/global/inc/keyman64.h | 25 +++++++++++------------ 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index d166a3394b..99dbd0f1d4 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -80,6 +80,7 @@ BOOL LoadlpKeyboard(int i) PKEYMAN64THREADDATA _td = ThreadGlobals(); if(!_td) return FALSE; if(_td->lpKeyboards[i].Keyboard) return TRUE; + // if(_td->lpKeyboards[i]) return TRUE; // This test it is active but doesn't set it as acitve why? if(_td->lpActiveKeyboard == &_td->lpKeyboards[i]) _td->lpActiveKeyboard = NULL; // I822 TSF not working @@ -87,11 +88,20 @@ BOOL LoadlpKeyboard(int i) if(!GetKeyboardFileName(_td->lpKeyboards[i].Name, buf, 255)) return FALSE; if(!LoadKeyboard(buf, &_td->lpKeyboards[i].Keyboard)) return FALSE; // I5136 +// if (KM_KBP_STATUS_OK != km_kbp_keyboard_load(buf, &_td->lpKeyboards[i])) return FALSE; - LoadDLLs(&_td->lpKeyboards[i]); + //LoadDLLs(&_td->lpKeyboards[i]); + // TODO: 5011 The activeKBState needs to maintian the state fror the context and options for + // the current active keypoard + + //(km_kbp_state_create(&_td->lpKeyboards[i], env_opts, &activeKBState)); + +// (km_kbp_state_options_update(activeKBState, keyboard_opts)) LoadKeyboardOptions(&_td->lpKeyboards[i]); + + return TRUE; } diff --git a/windows/src/engine/keyman32/globals.h b/windows/src/engine/keyman32/globals.h index 8041cd55b2..be5495a856 100644 --- a/windows/src/engine/keyman32/globals.h +++ b/windows/src/engine/keyman32/globals.h @@ -191,6 +191,10 @@ typedef struct tagKEYMAN64THREADDATA { LPINTKEYBOARDINFO lpKeyboards; // keyboard definitions LPINTKEYBOARDINFO lpActiveKeyboard; + + // km_kbp_keyboard* lpKeyboards; // keyboard definitions + // km_kbp_keyboard* lpActiveKeyboard; + // km_kbp_keyboard activeKBState // I3616 LPMSG msgbuf; // Message buffer (alloc at runtime) diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index 83b0bdc0a7..d5a924ba73 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -141,8 +141,16 @@ BOOL ProcessHook() _td->app->QueueDebugInformation(QID_BEGIN_ANSI, NULL, NULL, NULL, NULL, (DWORD_PTR) &keyinfo); } + // TODO: 5011 km_kbp_process_event(_td->activeKbState, state.vkey, "modifier_state") ProcessGroup(gp); + // TODO: 5011 process all the actions and data munge them into here. + + for (auto act = km_kbp_state_action_items(_td->activeKbState, nullptr); act->type != KM_KBP_IT_END; act++) { + apply_action(test_state, *act, text_store, options); + } + + if (fOutputKeystroke && !_td->app->IsQueueEmpty()) { // // #2759: The keyboard has requested that the default output diff --git a/windows/src/global/inc/keyman64.h b/windows/src/global/inc/keyman64.h index ec13946018..88352cd402 100644 --- a/windows/src/global/inc/keyman64.h +++ b/windows/src/global/inc/keyman64.h @@ -51,7 +51,7 @@ 03 Feb 2015 - mcdurdin - I4582 - V9.0 - Most underlying layout code in Keyman32 is now obsolete and needs to be removed 09 Aug 2015 - mcdurdin - I4844 - Tidy up PostDummyKeyEvent calls */ -/***************************************************************************/ // I4006 // I4169 +/***************************************************************************/ // I4006 // I4169 #ifndef _KEYMAN64_H #define _KEYMAN64_H @@ -85,7 +85,6 @@ #define NOT_IMPLEMENTED assert(FALSE) - #define ERROR_APP_MASK 0x20000000L #define ERROR_KEYMAN_ALREADY_INIT (ERROR_APP_MASK | 0x00000001L) #define ERROR_KEYMAN_SHUTTING_DOWN (ERROR_APP_MASK | 0x00000002L) @@ -100,14 +99,14 @@ /* RefreshKeyboards message parameters */ -#define KR_REQUEST_REFRESH 0 -#define KR_PRE_REFRESH 1 -#define KR_REFRESH 2 -#define KR_SETTINGS_CHANGED 3 // Broadcast when Keyman Configuration settings change +#define KR_REQUEST_REFRESH 0 +#define KR_PRE_REFRESH 1 +#define KR_REFRESH 2 +#define KR_SETTINGS_CHANGED 3 // Broadcast when Keyman Configuration settings change /* WM_KEY* message analysis */ -#define KEYMSG_LPARAM_SCAN(lParam) ((BYTE)(((lParam) & 0xFF0000) >> 16)) +#define KEYMSG_LPARAM_SCAN(lParam) ((BYTE)(((lParam)&0xFF0000) >> 16)) #define KEYMSG_FLAG_EXTENDED(lParam) (HIWORD(lParam) & KF_EXTENDED ? 1 : 0) #define KEYMSG_FLAG_DLGMODE(lParam) (HIWORD(lParam) & KF_DLGMODE ? 1 : 0) #define KEYMSG_FLAG_MENUMODE(lParam) (HIWORD(lParam) & KF_MENUMODE ? 1 : 0) @@ -116,7 +115,7 @@ #define KEYMSG_FLAG_UP(lParam) (HIWORD(lParam) & KF_UP ? 1 : 0) // TODO: Deprecate overloading of scancodes and use dwExtraInfo instead -#define SCAN_FLAG_KEYMAN_KEY_EVENT 0xFF +#define SCAN_FLAG_KEYMAN_KEY_EVENT 0xFF #define EXTRAINFO_FLAG_SERIALIZED_USER_KEY_EVENT 0x4B4D0000 @@ -127,13 +126,13 @@ // wParam for wm_keyman // These messages should be posted to a window -#define KM_DISABLEUI 1 -#define KM_ENABLEUI 2 +#define KM_DISABLEUI 1 +#define KM_ENABLEUI 2 // These messages should be sent to a window //#define KM_GETUISTATE 3 -#define KM_FOCUSCHANGED 5 // Never use this flag: internal to Keyman -#define KM_ACTIVECHANGED 6 // Never use this flag: internal to Keyman -#define KM_EXITFLUSH 8 // Disconnects GetMessage hook +#define KM_FOCUSCHANGED 5 // Never use this flag: internal to Keyman +#define KM_ACTIVECHANGED 6 // Never use this flag: internal to Keyman +#define KM_EXITFLUSH 8 // Disconnects GetMessage hook #define KMF_WINDOWCHANGED 1 From ece7addfeda6f9e81ba09cccba32528e8b1e9da3 Mon Sep 17 00:00:00 2001 From: Ross Cruickshank Date: Tue, 8 Jun 2021 17:01:25 +1000 Subject: [PATCH 02/63] feat(windows): mark out changes with 5011 feature TODOs --- windows/src/engine/keyman32/appint/appint.cpp | 4 +- windows/src/engine/keyman32/kmprocess.cpp | 66 +++++++++++++++++-- 2 files changed, 63 insertions(+), 7 deletions(-) diff --git a/windows/src/engine/keyman32/appint/appint.cpp b/windows/src/engine/keyman32/appint/appint.cpp index 1ca6eff025..fa1cd0e79c 100644 --- a/windows/src/engine/keyman32/appint/appint.cpp +++ b/windows/src/engine/keyman32/appint/appint.cpp @@ -1,5 +1,5 @@ /* - Name: appint + Name: appintO Copyright: Copyright (C) SIL International. Documentation: Description: @@ -114,7 +114,7 @@ void AppContext::Get(WCHAR *buf, int bufsize) for (WCHAR *p = this->BufMax(bufsize); *p && bufsize > 0; p++, bufsize--) { *buf = *p; - if(Uni_IsSurrogate1(*p) && bufsize - 2 > 0) { + if(Uni_IsSurrogate1(*p) && bufsize - 2 > 0) { buf++; p++; *buf = *p; bufsize--; diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index d5a924ba73..a6124e9a31 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -122,6 +122,9 @@ BOOL ProcessHook() //app->NoSetShift = FALSE; _td->app->ReadContext(); + /// TODO: 5011 Could set context of the core engine here (every time there is a ReadContext or Write Context) + // To make sure they are syncronised. However it also probably safest to read the context just before processing an event + // also. if(_td->state.msg.message == wm_keymankeydown) { // I4827 if (ShouldDebug(sdmKeyboard)) { @@ -140,17 +143,70 @@ BOOL ProcessHook() else _td->app->QueueDebugInformation(QID_BEGIN_ANSI, NULL, NULL, NULL, NULL, (DWORD_PTR) &keyinfo); } - - // TODO: 5011 km_kbp_process_event(_td->activeKbState, state.vkey, "modifier_state") + /// TODO: 5011 Need to make sure the context is set correctly before processing event + WCHAR buf[MAXCONTEXT]; + // _td->app->GetWindowContext(buf, MAXCONTEXT); + // km_kbp_context_item *citems = nullptr; + // km_kbp_context_items_from_utf16(buf, &citems); + // km_kbp_context_set(km_kbp_state_context(_td->activeKbState), citems); + // km_kbp_context_items_dispose(citems); + /// TODO: 5011 km_kbp_process_event(_td->activeKbState, state.vkey, "modifier_state") ProcessGroup(gp); - // TODO: 5011 process all the actions and data munge them into here. + /// TODO: 5011 process all the actions and data munge them into here. + /// Need to update(replace) the platform layer keyman32 context with the context from the core engine + buf[0] = 0; // clear buffer + size_t contextSize; + km_kbp_context_items_to_utf16(_td->activeKbState,buf, &contextSize); + // call a public function to set the Context Or if we aren't going to update the interface for aiTIP + // Then reset the context and call append for each char in buf. + + // Now that we have updated the context update that action queue in the AIINT for (auto act = km_kbp_state_action_items(_td->activeKbState, nullptr); act->type != KM_KBP_IT_END; act++) { - apply_action(test_state, *act, text_store, options); + + switch (act.type) + { + case KM_KBP_IT_END: + // error assert(false); + break; + case KM_KBP_IT_ALERT: + _td->app->QueueAction(QIT_BELL, 0); + break; + case KM_KBP_IT_CHAR: + // unicode scalar value is stored in + //act->character; + _td->app->QueueAction(QIT_CHAR,Convert_to_utf16(act->character)); + break; + case KM_KBP_IT_MARKER: + // act->marker + _td->app->QueueAction(QIT_DEADKEY,Convert_To_KEY(act->marker)); + break; + case KM_KBP_IT_BACK: + /// TODO: 5011 The context is changed in processing engine so this may not match the cached context in the (this) keyman32 layer. + _td->app->QueueAction(QIT_BACK,BK_DEADKEY); + break; + case KM_KBP_IT_PERSIST_OPT: + /// update keyboard options at the platform layer. + break; + case KM_KBP_IT_INVALIDATE_CONTEXT: + // Reset context + _td->app->ResetContext(); + break; + case KM_KBP_IT_EMIT_KEYSTROKE: + fOutputKeystroke = TRUE; + break; + default: + assert(false); // NOT SUPPORTED + break; + + } + + } - + /// Do we want to process this when we find the action in the list from the core engine or + // do we process the emit key stroke with whatever we have queued up to this point. if (fOutputKeystroke && !_td->app->IsQueueEmpty()) { // // #2759: The keyboard has requested that the default output From 5d2df77e7d352d536721c8de0d5c9e8aa19c0e03 Mon Sep 17 00:00:00 2001 From: Ross Cruickshank Date: Thu, 10 Jun 2021 08:37:09 +1000 Subject: [PATCH 03/63] feat(windows): work in progress --- windows/src/engine/keyman32/appint/aiTIP.cpp | 3 ++- windows/src/engine/keyman32/appint/appint.cpp | 2 +- windows/src/engine/keyman32/globals.h | 8 ++++---- windows/src/engine/keyman32/kmprocess.cpp | 7 ++++--- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/windows/src/engine/keyman32/appint/aiTIP.cpp b/windows/src/engine/keyman32/appint/aiTIP.cpp index 0b24dadf11..50f54c9133 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.cpp +++ b/windows/src/engine/keyman32/appint/aiTIP.cpp @@ -205,7 +205,8 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM _td->state.msg.lParam = 0; _td->state.msg.message = wm_keymankeydown; _td->state.vkey = (WORD) wParam; - + /// TODO: 5011 set the modifier _td->state.modifer + /// TODO: 5011 set the correct active keyboard. _td->state.lpkb = _td->lpActiveKeyboard->Keyboard; _td->state.windowunicode = TRUE; diff --git a/windows/src/engine/keyman32/appint/appint.cpp b/windows/src/engine/keyman32/appint/appint.cpp index fa1cd0e79c..1349b2918a 100644 --- a/windows/src/engine/keyman32/appint/appint.cpp +++ b/windows/src/engine/keyman32/appint/appint.cpp @@ -1,5 +1,5 @@ /* - Name: appintO + Name: appint Copyright: Copyright (C) SIL International. Documentation: Description: diff --git a/windows/src/engine/keyman32/globals.h b/windows/src/engine/keyman32/globals.h index be5495a856..11180d95d0 100644 --- a/windows/src/engine/keyman32/globals.h +++ b/windows/src/engine/keyman32/globals.h @@ -190,11 +190,11 @@ typedef struct tagKEYMANHKLPAIR typedef struct tagKEYMAN64THREADDATA { LPINTKEYBOARDINFO lpKeyboards; // keyboard definitions - LPINTKEYBOARDINFO lpActiveKeyboard; + //LPINTKEYBOARDINFO lpActiveKeyboard; + // TODO: 5011 + km_kbp_keyboard* lpKeyboards; // keyboard definitions + km_kbp_keyboard* lpActiveKeyboard; - // km_kbp_keyboard* lpKeyboards; // keyboard definitions - // km_kbp_keyboard* lpActiveKeyboard; - // km_kbp_keyboard activeKBState // I3616 LPMSG msgbuf; // Message buffer (alloc at runtime) diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index a6124e9a31..2786fa7b32 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -109,7 +109,7 @@ BOOL ProcessHook() LPGROUP gp = _td->state.startgroup; - fOutputKeystroke = FALSE; + fOutputKeystroke = FALSE; // TODO: 5011 no longer needs to be global // // If we are running in the debugger, don't do a second run through @@ -143,8 +143,9 @@ BOOL ProcessHook() else _td->app->QueueDebugInformation(QID_BEGIN_ANSI, NULL, NULL, NULL, NULL, (DWORD_PTR) &keyinfo); } + /// TODO: 5011 Need to make sure the context is set correctly before processing event - WCHAR buf[MAXCONTEXT]; + // WCHAR buf[MAXCONTEXT]; // _td->app->GetWindowContext(buf, MAXCONTEXT); // km_kbp_context_item *citems = nullptr; // km_kbp_context_items_from_utf16(buf, &citems); @@ -205,7 +206,7 @@ BOOL ProcessHook() } - /// Do we want to process this when we find the action in the list from the core engine or + /// TODO: 5011 process this in action items iterations. Do we want to process this when we find the action in the list from the core engine or // do we process the emit key stroke with whatever we have queued up to this point. if (fOutputKeystroke && !_td->app->IsQueueEmpty()) { // From ee43514149b5ee6f831f48baf351de75aa6c5b23 Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 23 Jun 2021 09:47:56 +1000 Subject: [PATCH 04/63] refactor(windows): annotate code --- linux/ibus-keyman/src/engine.c | 1 + windows/src/engine/keyman32/K32_load.cpp | 4 ++-- windows/src/engine/keyman32/appint/aiTIP.h | 18 ++++++++--------- windows/src/engine/keyman32/globals.h | 6 +++--- .../src/engine/keyman32/keyboardoptions.cpp | 20 +++++++++---------- 5 files changed, 25 insertions(+), 24 deletions(-) diff --git a/linux/ibus-keyman/src/engine.c b/linux/ibus-keyman/src/engine.c index 0d8ed41111..a100e4eff6 100644 --- a/linux/ibus-keyman/src/engine.c +++ b/linux/ibus-keyman/src/engine.c @@ -216,6 +216,7 @@ static void reset_context(IBusEngine *engine) ibus_engine_get_surrounding_text(engine, &text, &cursor_pos, &anchor_pos); context_pos = anchor_pos < cursor_pos ? anchor_pos : cursor_pos; + context_start = context_pos > MAXCONTEXT_ITEMS ? context_pos - MAXCONTEXT_ITEMS : 0; surrounding_text = g_utf8_substring(ibus_text_get_text(text), context_start, context_pos); g_message("new context is:%u:%s: cursor:%d anchor:%d", context_pos - context_start, surrounding_text, cursor_pos, anchor_pos); diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index 99dbd0f1d4..d6b28c0ec0 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -88,13 +88,13 @@ BOOL LoadlpKeyboard(int i) if(!GetKeyboardFileName(_td->lpKeyboards[i].Name, buf, 255)) return FALSE; if(!LoadKeyboard(buf, &_td->lpKeyboards[i].Keyboard)) return FALSE; // I5136 -// if (KM_KBP_STATUS_OK != km_kbp_keyboard_load(buf, &_td->lpKeyboards[i])) return FALSE; +// if (KM_KBP_STATUS_OK != km_kbp_keyboard_load(buf, &_td->lpKeyboards[i].coreKeyboard)) return FALSE; //LoadDLLs(&_td->lpKeyboards[i]); // TODO: 5011 The activeKBState needs to maintian the state fror the context and options for // the current active keypoard - + // km_kbp_option_item test_env_opts //(km_kbp_state_create(&_td->lpKeyboards[i], env_opts, &activeKBState)); // (km_kbp_state_options_update(activeKBState, keyboard_opts)) diff --git a/windows/src/engine/keyman32/appint/aiTIP.h b/windows/src/engine/keyman32/appint/aiTIP.h index fd64847168..49eeb5c88d 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.h +++ b/windows/src/engine/keyman32/appint/aiTIP.h @@ -1,18 +1,18 @@ /* Name: aiTIP Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 11 Dec 2009 Modified Date: 23 Feb 2016 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 11 Dec 2009 - mcdurdin - I934 - x64 - Initial version 24 Jun 2010 - mcdurdin - I2436 - Add space to context for AIWin2000Unicode when not matched 24 Apr 2014 - mcdurdin - I4196 - V9.0 - wm_kmmoreposting must be refactored for TIP work as it is not sequential @@ -78,7 +78,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); @@ -89,7 +89,7 @@ public: virtual void ReadContext(); /* Queue and sending functions */ - + virtual BOOL SendActions(); // I4196 virtual BOOL QueueDebugInformation(int ItemType, LPGROUP Group, LPKEY Rule, PWSTR fcontext, PWSTR foutput, DWORD_PTR dwExtraFlags); diff --git a/windows/src/engine/keyman32/globals.h b/windows/src/engine/keyman32/globals.h index 11180d95d0..f2bc2d11ac 100644 --- a/windows/src/engine/keyman32/globals.h +++ b/windows/src/engine/keyman32/globals.h @@ -190,10 +190,10 @@ typedef struct tagKEYMANHKLPAIR typedef struct tagKEYMAN64THREADDATA { LPINTKEYBOARDINFO lpKeyboards; // keyboard definitions - //LPINTKEYBOARDINFO lpActiveKeyboard; + LPINTKEYBOARDINFO lpActiveKeyboard; // TODO: 5011 - km_kbp_keyboard* lpKeyboards; // keyboard definitions - km_kbp_keyboard* lpActiveKeyboard; + //km_kbp_keyboard* lpKeyboards; // keyboard definitions + //km_kbp_keyboard* lpActiveKeyboard; // I3616 LPMSG msgbuf; // Message buffer (alloc at runtime) diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index e0964cfd97..7f6986448a 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -1,18 +1,18 @@ /* Name: keyboardoptions Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 25 May 2010 Modified Date: 28 Nov 2012 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 25 May 2010 - mcdurdin - I1632 - Keyboard Options 31 May 2010 - mcdurdin - I2397 - Assertion failure - keyboard options loading twice 28 Nov 2012 - mcdurdin - I3594 - V9.0 - Remove old SelectKeyboard code and related messages @@ -75,7 +75,7 @@ void SetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSet, int nStoreToRead) { 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; @@ -129,7 +129,7 @@ BOOL IntLoadKeyboardOptions(LPCSTR key, LPINTKEYBOARDINFO kp) 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); @@ -156,7 +156,7 @@ BOOL IntLoadKeyboardOptions(LPCSTR key, LPINTKEYBOARDINFO kp) break; } - } + } } n++; } From f0f1e966a2ad1c1369588005c067bba5e2a792d5 Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 21 Jul 2021 10:54:48 +1000 Subject: [PATCH 05/63] feat(windows): update project include files --- .gitignore | 3 +- windows/src/engine/keyman32/K32_load.cpp | 34 +++++++- windows/src/engine/keyman32/Keyman32.vcxproj | 2 +- windows/src/engine/keyman32/globals.h | 2 + windows/src/engine/keyman32/k32_globals.cpp | 8 ++ .../src/engine/keyman32/keyman-engine.vcxproj | 2 +- windows/src/engine/keyman32/kmprocess.cpp | 80 ++++++++--------- .../src/engine/keyman32/selectkeyboard.cpp | 86 ++++++++++++++++++- .../keyman32-tests/keyman32-tests.vcxproj | 12 +-- windows/src/global/inc/keyman64.h | 1 + windows/src/global/inc/registry.h | 26 +++--- 11 files changed, 193 insertions(+), 63 deletions(-) diff --git a/.gitignore b/.gitignore index 1566ecf622..ffe48fa739 100644 --- a/.gitignore +++ b/.gitignore @@ -162,7 +162,8 @@ resources/environment.sh # Copy of the master VERSION.md used for Linux packaging /common/core/desktop/VERSION.md - +# Test common core keyboard files +common/core/desktop/tests/unit/kmx/*.kmx **/node_modules/ lerna-debug.log diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index d6b28c0ec0..a16cea84d6 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -75,6 +75,38 @@ BOOL GetKeyboardFileName(LPSTR kbname, LPSTR buf, int nbuf) return n; } + +//BOOL LoadlpKeyboardCore(int i) +//{ +// PKEYMAN64THREADDATA _td = ThreadGlobals(); +// if (!_td) return FALSE; +// if (_td->lpKeyboards[i].coreKeyboard) 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 +// +// if (KM_KBP_STATUS_OK != km_kbp_keyboard_load(buf, &_td->lpKeyboards[i].coreKeyboard)) return FALSE; +// +// //LoadDLLs(&_td->lpKeyboards[i]); +// +// // TODO: 5011 The activeKBState needs to maintian the state fror the context and options for +// // the current active keyoard +// // km_kbp_option_item test_env_opts +// //(km_kbp_state_create(&_td->lpKeyboards[i], env_opts, &activeKBState)); +// +//// (km_kbp_state_options_update(activeKBState, keyboard_opts)) +// LoadKeyboardOptions(&_td->lpKeyboards[i]); +// +// +// +// return TRUE; +//} + BOOL LoadlpKeyboard(int i) { PKEYMAN64THREADDATA _td = ThreadGlobals(); @@ -93,7 +125,7 @@ BOOL LoadlpKeyboard(int i) //LoadDLLs(&_td->lpKeyboards[i]); // TODO: 5011 The activeKBState needs to maintian the state fror the context and options for - // the current active keypoard + // the current active keyoard // km_kbp_option_item test_env_opts //(km_kbp_state_create(&_td->lpKeyboards[i], env_opts, &activeKBState)); diff --git a/windows/src/engine/keyman32/Keyman32.vcxproj b/windows/src/engine/keyman32/Keyman32.vcxproj index ec24837adf..87ef5b5b92 100644 --- a/windows/src/engine/keyman32/Keyman32.vcxproj +++ b/windows/src/engine/keyman32/Keyman32.vcxproj @@ -55,7 +55,7 @@ $(ProjectDir)..\..\..\..\common\core\desktop\build\x86\$(Configuration)\src;$(ProjectDir)..\..\..\..\common\core\desktop\build\rust\x86\$(Configuration);$(LibraryPath) - $(ProjectDir)..\..\..\..\common\core\desktop\build\x86\$(Configuration)\include;$(IncludePath) + $(ProjectDir)..\..\..\..\common\core\desktop\include;$(ProjectDir)..\..\..\..\common\core\desktop\build\x86\$(Configuration)\include;$(IncludePath) $(ProjectDir)..\..\..\..\common\core\desktop\build\x86\$(Configuration)\src;$(ProjectDir)..\..\..\..\common\core\desktop\build\rust\x86\$(Configuration);$(LibraryPath) diff --git a/windows/src/engine/keyman32/globals.h b/windows/src/engine/keyman32/globals.h index f2bc2d11ac..3d7118fa6d 100644 --- a/windows/src/engine/keyman32/globals.h +++ b/windows/src/engine/keyman32/globals.h @@ -149,7 +149,9 @@ public: static BOOL get_debug_KeymanLog(); static BOOL get_debug_ToConsole(); + static BOOL get_CoreIntegration(); static void LoadDebugSettings(); + }; /* External interface functions */ diff --git a/windows/src/engine/keyman32/k32_globals.cpp b/windows/src/engine/keyman32/k32_globals.cpp index 7c650e4283..efae536e99 100644 --- a/windows/src/engine/keyman32/k32_globals.cpp +++ b/windows/src/engine/keyman32/k32_globals.cpp @@ -287,6 +287,10 @@ static BOOL f_debug_KeymanLog = FALSE, f_debug_ToConsole = FALSE; +static BOOL + f_CoreIntegration = TRUE; + + #pragma data_seg() /***************************************************************************/ @@ -361,6 +365,8 @@ 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); @@ -379,6 +385,8 @@ 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_CoreIntegration, FALSE); f_vk_prefix = _VK_PREFIX_DEFAULT; RegistryReadOnly reg(HKEY_LOCAL_MACHINE); if (reg.OpenKeyReadOnly(REGSZ_KeymanLM) && diff --git a/windows/src/engine/keyman32/keyman-engine.vcxproj b/windows/src/engine/keyman32/keyman-engine.vcxproj index 45718f5bff..fb987da126 100644 --- a/windows/src/engine/keyman32/keyman-engine.vcxproj +++ b/windows/src/engine/keyman32/keyman-engine.vcxproj @@ -55,7 +55,7 @@ $(ProjectDir)..\..\..\..\common\core\desktop\build\x86\$(Configuration)\src;$(ProjectDir)..\..\..\..\common\core\desktop\build\rust\x86\$(Configuration);$(LibraryPath) - $(ProjectDir)..\..\..\..\common\core\desktop\build\x86\$(Configuration)\include;$(IncludePath) + $(ProjectDir)..\..\..\..\common\core\desktop\build\x86\$(Configuration)\include;$(ProjectDir)..\..\..\..\common\core\desktop\include;$(IncludePath) $(ProjectDir)..\..\..\..\common\core\desktop\build\x86\$(Configuration)\src;$(ProjectDir)..\..\..\..\common\core\desktop\build\rust\x86\$(Configuration);$(LibraryPath) diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index 2786fa7b32..83987e3ce3 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -157,54 +157,54 @@ BOOL ProcessHook() /// TODO: 5011 process all the actions and data munge them into here. /// Need to update(replace) the platform layer keyman32 context with the context from the core engine - buf[0] = 0; // clear buffer - size_t contextSize; - km_kbp_context_items_to_utf16(_td->activeKbState,buf, &contextSize); + //buf[0] = 0; // clear buffer + //size_t contextSize; + //km_kbp_context_items_to_utf16(_td->activeKbState,buf, &contextSize); // call a public function to set the Context Or if we aren't going to update the interface for aiTIP // Then reset the context and call append for each char in buf. // Now that we have updated the context update that action queue in the AIINT - for (auto act = km_kbp_state_action_items(_td->activeKbState, nullptr); act->type != KM_KBP_IT_END; act++) { + // for (auto act = km_kbp_state_action_items(_td->activeKbState, nullptr); act->type != KM_KBP_IT_END; act++) { - switch (act.type) - { - case KM_KBP_IT_END: - // error assert(false); - break; - case KM_KBP_IT_ALERT: - _td->app->QueueAction(QIT_BELL, 0); - break; - case KM_KBP_IT_CHAR: - // unicode scalar value is stored in - //act->character; - _td->app->QueueAction(QIT_CHAR,Convert_to_utf16(act->character)); - break; - case KM_KBP_IT_MARKER: - // act->marker - _td->app->QueueAction(QIT_DEADKEY,Convert_To_KEY(act->marker)); - break; - case KM_KBP_IT_BACK: - /// TODO: 5011 The context is changed in processing engine so this may not match the cached context in the (this) keyman32 layer. - _td->app->QueueAction(QIT_BACK,BK_DEADKEY); - break; - case KM_KBP_IT_PERSIST_OPT: - /// update keyboard options at the platform layer. - break; - case KM_KBP_IT_INVALIDATE_CONTEXT: - // Reset context - _td->app->ResetContext(); - break; - case KM_KBP_IT_EMIT_KEYSTROKE: - fOutputKeystroke = TRUE; - break; - default: - assert(false); // NOT SUPPORTED - break; + // switch (act.type) + // { + // case KM_KBP_IT_END: + // // error assert(false); + // break; + // case KM_KBP_IT_ALERT: + // _td->app->QueueAction(QIT_BELL, 0); + // break; + // case KM_KBP_IT_CHAR: + // // unicode scalar value is stored in + // //act->character; + // _td->app->QueueAction(QIT_CHAR,Convert_to_utf16(act->character)); + // break; + // case KM_KBP_IT_MARKER: + // // act->marker + // _td->app->QueueAction(QIT_DEADKEY,Convert_To_KEY(act->marker)); + // break; + // case KM_KBP_IT_BACK: + // /// TODO: 5011 The context is changed in processing engine so this may not match the cached context in the (this) keyman32 layer. + // _td->app->QueueAction(QIT_BACK,BK_DEADKEY); + // break; + // case KM_KBP_IT_PERSIST_OPT: + // /// update keyboard options at the platform layer. + // break; + // case KM_KBP_IT_INVALIDATE_CONTEXT: + // // Reset context + // _td->app->ResetContext(); + // break; + // case KM_KBP_IT_EMIT_KEYSTROKE: + // fOutputKeystroke = TRUE; + // break; + // default: + // assert(false); // NOT SUPPORTED + // break; - } + // } - } + // } /// TODO: 5011 process this in action items iterations. Do we want to process this when we find the action in the list from the core engine or // do we process the emit key stroke with whatever we have queued up to this point. diff --git a/windows/src/engine/keyman32/selectkeyboard.cpp b/windows/src/engine/keyman32/selectkeyboard.cpp index 408a9c685f..c40ec66c14 100644 --- a/windows/src/engine/keyman32/selectkeyboard.cpp +++ b/windows/src/engine/keyman32/selectkeyboard.cpp @@ -53,9 +53,91 @@ // I3594 // I4220 +BOOL SelectKeyboardCore(DWORD 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(); + /** TODO: 5011 is this just IDML dlls */ + //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 SelectKeyboard(DWORD KeymanID) { - int i; + if (Globals::get_CoreIntegration()) + { + return SelectKeyboardCore(KeymanID); + } + int i; HWND hwnd = GetFocus(); PKEYMAN64THREADDATA _td = ThreadGlobals(); @@ -78,7 +160,7 @@ BOOL SelectKeyboard(DWORD KeymanID) } KMHideIM(); - + /** TODO: 5011 is this just IDML dlls */ if(_td->lpActiveKeyboard) DeactivateDLLs(_td->lpActiveKeyboard); _td->lpActiveKeyboard = NULL; _td->ActiveKeymanID = KEYMANID_NONKEYMAN; diff --git a/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj b/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj index 7c41040c93..d3fc67cceb 100644 --- a/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj +++ b/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj @@ -33,9 +33,10 @@ - $(ProjectDir)..\..\..\..\global\inc;$(ProjectDir)..\..;$(IncludePath) - $(ProjectDir)bin\$(Platform)\$(Configuration)\ - $(ProjectDir)obj\$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\..\..\..\..\common\core\desktop\include;$(ProjectDir)..\..\..\..\..\..\common\core\desktop\build\x86\$(Configuration)\include;$(ProjectDir)..\..\..\..\global\inc;$(ProjectDir)..\..;$(IncludePath) + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + $(ProjectDir)..\..\..\..\..\..\common\core\desktop\build\x86\$(Configuration)\src;$(LibraryPath) $(ProjectDir)..\..\..\..\global\inc;$(ProjectDir)..\..;$(IncludePath) @@ -89,11 +90,12 @@ EnableFastChecks MultiThreadedDebug Level3 + %(AdditionalIncludeDirectories) true Console - version.lib;psapi.lib;imm32.lib;%(AdditionalDependencies) + version.lib;psapi.lib;imm32.lib;kmnkbp0.lib;%(AdditionalDependencies) @@ -149,4 +151,4 @@ - \ No newline at end of file + diff --git a/windows/src/global/inc/keyman64.h b/windows/src/global/inc/keyman64.h index 88352cd402..a0b2092720 100644 --- a/windows/src/global/inc/keyman64.h +++ b/windows/src/global/inc/keyman64.h @@ -76,6 +76,7 @@ #include #include #include "compiler.h" +#include #ifdef _WIN64 #define LIBRARY_NAME "KEYMAN64" diff --git a/windows/src/global/inc/registry.h b/windows/src/global/inc/registry.h index 5eccd5c0a2..19c479a0c4 100644 --- a/windows/src/global/inc/registry.h +++ b/windows/src/global/inc/registry.h @@ -1,18 +1,18 @@ /* Name: registry Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 20 Jun 2006 Modified Date: 28 Mar 2016 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 20 Jun 2006 - mcdurdin - Initial version 01 Aug 2006 - mcdurdin - Add KeymanHotkeys reg 05 Nov 2007 - mcdurdin - I1087 - Add hotkeys to switch languages @@ -44,7 +44,7 @@ #else // this below is same in NT 4 and Win95; others will be different -#define REGSZ_Keyman "software\\keyman\\keyman engine" +#define REGSZ_Keyman "software\\keyman\\keyman engine" #define REGSZ_KeymanDeveloper "software\\keyman\\keyman developer" #define REGSZ_KeymanCU REGSZ_Keyman #define REGSZ_KeymanLM REGSZ_Keyman @@ -83,7 +83,7 @@ //#define REGSZ_SystemNLSLocale "system\\currentcontrolset\\control\\Nls\\Locale" // I4220 - + #define REGSZ_KeymanFile "keyman file" #define REGSZ_KeymanFile_MnemonicOverride "keyman file mnemonic override" // I4169 #define REGSZ_KeymanFile_MnemonicOverride_Deadkey "keyman file mnemonic override deadkey" // I4552 @@ -110,7 +110,7 @@ #define REGSZ_KeyboardHotkeysAreToggle "hotkeys are toggles" #define REGSZ_DeadkeyConversionMode "deadkey conversion mode" // CU // I4552 #define REGSZ_ZapVirtualKeyCode "zap virtual key code" // LM, defaults to 0x0E (_VK_PREFIX_DEFAULT) -/* +/* Debug flags These are all stored in HKCU\Software\Keyman\Debug */ @@ -140,7 +140,9 @@ #define REGSZ_AutomaticallyReportErrors "automatically report errors" // CU, SRegKey_IDEOptions and SRegKey_KeymanEngine_CU #define REGSZ_AutomaticallyReportUsage "automatically report usage" // CU, SRegKey_IDEOptions and SRegKey_KeymanEngine_CU -/* Splitting Registry into ReadOnly and FullAccess makes it much easier to ensure that we are using the registry +#define REGSZ_CoreIntegration "Turn on common core" // Turns on the common core - instead of windows core + +/* Splitting Registry into ReadOnly and FullAccess makes it much easier to ensure that we are using the registry correctly -- readonly wherever possible. */ class RegistryReadOnly @@ -173,7 +175,7 @@ public: class RegistryFullAccess: public RegistryReadOnly { -protected: +protected: HKEY GetKey(LPCSTR AKey); BOOL IntRecursiveDeleteKey(HKEY hkey); From 01d10ce3bf48b9693164e16a2f1c31cd58f0d749 Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 7 Jul 2021 16:10:40 +1000 Subject: [PATCH 06/63] feat(windows): loadKeyboardOptionsREGCore using the core api --- windows/src/engine/keyman32/K32_load.cpp | 77 ++++++++--------- .../src/engine/keyman32/keyboardoptions.cpp | 82 ++++++++++++++++++- windows/src/engine/keyman32/keyboardoptions.h | 24 ++++-- .../src/engine/keyman32/selectkeyboard.cpp | 4 +- 4 files changed, 135 insertions(+), 52 deletions(-) diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index a16cea84d6..2f458aa1ce 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -76,43 +76,47 @@ BOOL GetKeyboardFileName(LPSTR kbname, LPSTR buf, int nbuf) } -//BOOL LoadlpKeyboardCore(int i) -//{ -// PKEYMAN64THREADDATA _td = ThreadGlobals(); -// if (!_td) return FALSE; -// if (_td->lpKeyboards[i].coreKeyboard) 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 -// -// if (KM_KBP_STATUS_OK != km_kbp_keyboard_load(buf, &_td->lpKeyboards[i].coreKeyboard)) return FALSE; -// -// //LoadDLLs(&_td->lpKeyboards[i]); -// -// // TODO: 5011 The activeKBState needs to maintian the state fror the context and options for -// // the current active keyoard -// // km_kbp_option_item test_env_opts -// //(km_kbp_state_create(&_td->lpKeyboards[i], env_opts, &activeKBState)); -// -//// (km_kbp_state_options_update(activeKBState, keyboard_opts)) -// LoadKeyboardOptions(&_td->lpKeyboards[i]); -// -// -// -// return TRUE; -//} +BOOL LoadlpKeyboardCore(int i) +{ + PKEYMAN64THREADDATA _td = ThreadGlobals(); + if (!_td) return FALSE; + if (_td->lpKeyboards[i].coreKeyboard) 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; + size_t charSize = strlen(buf) + 1; + + wchar_t* keyboardPath = new wchar_t[charSize]; + + // Convert char* string to a wchar_t* string. + size_t convertedChars = 0; + mbstowcs_s(&convertedChars, keyboardPath, charSize, buf, _TRUNCATE); + + if (KM_KBP_STATUS_OK != km_kbp_keyboard_load(keyboardPath, &_td->lpKeyboards[i].coreKeyboard)) return FALSE; + // TODO: 5011 handle dlls + //LoadDLLs(&_td->lpKeyboards[i]); + const km_kbp_option_item test_env_opts[] = + { + KM_KBP_OPTIONS_END + }; + km_kbp_state_create(_td->lpKeyboards[i].coreKeyboard, test_env_opts, &_td->state.lpActiveKBState); + LoadKeyboardOptionsREGCore(&_td->lpKeyboards[i], _td->state.lpActiveKBState); + + // free keyboardPath + delete [] keyboardPath; + + return TRUE; +} BOOL LoadlpKeyboard(int i) { PKEYMAN64THREADDATA _td = ThreadGlobals(); if(!_td) return FALSE; if(_td->lpKeyboards[i].Keyboard) return TRUE; - // if(_td->lpKeyboards[i]) return TRUE; // This test it is active but doesn't set it as acitve why? + if(_td->lpActiveKeyboard == &_td->lpKeyboards[i]) _td->lpActiveKeyboard = NULL; // I822 TSF not working @@ -120,20 +124,9 @@ BOOL LoadlpKeyboard(int i) if(!GetKeyboardFileName(_td->lpKeyboards[i].Name, buf, 255)) return FALSE; if(!LoadKeyboard(buf, &_td->lpKeyboards[i].Keyboard)) return FALSE; // I5136 -// if (KM_KBP_STATUS_OK != km_kbp_keyboard_load(buf, &_td->lpKeyboards[i].coreKeyboard)) return FALSE; - //LoadDLLs(&_td->lpKeyboards[i]); - - // TODO: 5011 The activeKBState needs to maintian the state fror the context and options for - // the current active keyoard - // km_kbp_option_item test_env_opts - //(km_kbp_state_create(&_td->lpKeyboards[i], env_opts, &activeKBState)); - -// (km_kbp_state_options_update(activeKBState, keyboard_opts)) LoadKeyboardOptions(&_td->lpKeyboards[i]); - - return TRUE; } diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index 7f6986448a..a9a50754bf 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -19,9 +19,11 @@ */ #include "pch.h" #include "registry.h" +#include 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 LoadKeyboardOptions(LPINTKEYBOARDINFO kp) { // I3594 @@ -30,6 +32,10 @@ void LoadKeyboardOptions(LPINTKEYBOARDINFO kp) void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp) { + if (Globals::get_CoreIntegration()) + { + return; // should never be called if using core processor + } // Called when another thread changes keyboard options and we are sharing keyboard settings assert(kp != NULL); assert(kp->Keyboard != NULL); @@ -41,6 +47,10 @@ void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp) void FreeKeyboardOptions(LPINTKEYBOARDINFO kp) { + if (Globals::get_CoreIntegration()) + { + return; // should never be called if using core processor + } // 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) @@ -58,6 +68,11 @@ void FreeKeyboardOptions(LPINTKEYBOARDINFO kp) void SetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSet, int nStoreToRead) { + if (Globals::get_CoreIntegration()) + { + return; // should never be called if using core processor + } + assert(kp != NULL); assert(kp->Keyboard != NULL); assert(kp->KeyboardOptions != NULL); @@ -83,6 +98,10 @@ void SetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSet, int nStoreToRead) void ResetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToReset) { + if (Globals::get_CoreIntegration()) + { + return; // should never be called if using core processor + } assert(kp != NULL); assert(kp->Keyboard != NULL); assert(kp->KeyboardOptions != NULL); @@ -119,6 +138,10 @@ void ResetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToReset) void SaveKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSave) { + if (Globals::get_CoreIntegration()) + { + return; // should never be called if using core processor + } IntSaveKeyboardOption(REGSZ_KeyboardOptions, kp, nStoreToSave); } @@ -148,7 +171,7 @@ BOOL IntLoadKeyboardOptions(LPCSTR key, LPINTKEYBOARDINFO kp) { if(kp->Keyboard->dpStoreArray[i].dpName != NULL && _wcsicmp(kp->Keyboard->dpStoreArray[i].dpName, buf) == 0) { - kp->KeyboardOptions[i].Value = new WCHAR[wcslen(val)+1]; + kp->KeyboardOptions[i].Value = new WCHAR[wcslen(val)+1]; // is this a memory leak as wcscpy_s(kp->KeyboardOptions[i].Value, wcslen(val)+1, val); kp->KeyboardOptions[i].OriginalStore = kp->Keyboard->dpStoreArray[i].dpString; @@ -182,3 +205,60 @@ void IntSaveKeyboardOption(LPCSTR key, LPINTKEYBOARDINFO kp, int nStoreToSave) r.WriteString(kp->Keyboard->dpStoreArray[nStoreToSave].dpName, kp->Keyboard->dpStoreArray[nStoreToSave].dpString); } } + +void LoadKeyboardOptionsREGCore(LPINTKEYBOARDINFO kp, km_kbp_state* const state) +{ + IntLoadKeyboardOptionsCore(REGSZ_KeyboardOptions, kp, state); +} + +BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* state) +{ + assert(key != NULL); + assert(kp != NULL); + assert(kp->Keyboard != NULL); + assert(kp->KeyboardOptions == NULL); // not used for common core + + RegistryReadOnly r(HKEY_CURRENT_USER); + if (r.OpenKeyReadOnly(REGSZ_KeymanActiveKeyboards) && r.OpenKeyReadOnly(kp->Name) && r.OpenKeyReadOnly(key)) + { + WCHAR buf[256]; + int n = 0; + // Get the list of default options to determine size of list + const km_kbp_keyboard_attrs* keyboadAttrs; + km_kbp_keyboard_get_attrs(kp->coreKeyboard, &keyboadAttrs); + size_t listSize = km_kbp_options_list_size(keyboadAttrs->default_options); + km_kbp_option_item* keyboardOpts = new km_kbp_option_item[listSize+1]; + + while (r.GetValueNames(buf, sizeof(buf) / sizeof(buf[0]), n)) + { + buf[255] = 0; + WCHAR val[256]; + WCHAR* PWVAL; + if (r.ReadString(buf, val, sizeof(val) / sizeof(val[0])) && val[0]) + { + val[255] = 0; + keyboardOpts[n].scope = KM_KBP_OPT_KEYBOARD; + + size_t charSize = strlen(key) + 1; + wchar_t* KeyWCHAR = new WCHAR[charSize]; + size_t convertedChars = 0; + mbstowcs_s(&convertedChars, KeyWCHAR, charSize, key, _TRUNCATE); + keyboardOpts[n].key = reinterpret_cast(KeyWCHAR); + + PWVAL = new WCHAR[wcslen(val) + 1]; // is this a memory leak as + wcscpy_s(PWVAL, wcslen(val) + 1, val); + keyboardOpts[n].value = reinterpret_cast(PWVAL); + } + n++; + } + /// once we have the option list we can then update the options using the public api call + km_kbp_state_options_update(state, keyboardOpts); + for (int i = 0; i < (int)listSize + 1; i++) { + delete[] keyboardOpts[i].key; + delete[] keyboardOpts[i].value; + } + delete keyboardOpts; + return TRUE; + } + return FALSE; +} diff --git a/windows/src/engine/keyman32/keyboardoptions.h b/windows/src/engine/keyman32/keyboardoptions.h index d47e3adb13..a190b1bb01 100644 --- a/windows/src/engine/keyman32/keyboardoptions.h +++ b/windows/src/engine/keyman32/keyboardoptions.h @@ -1,18 +1,18 @@ /* Name: keyboardoptions Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 25 May 2010 Modified Date: 25 May 2010 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 25 May 2010 - mcdurdin - I1632 - Keyboard Options */ @@ -22,3 +22,13 @@ void SetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSet, int nStoreToRead); void ResetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToReset); void SaveKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSave); void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp); + +/* Common core integration functions */ + +/** + * Loads the keyboard options from the windows registry + * + * @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); diff --git a/windows/src/engine/keyman32/selectkeyboard.cpp b/windows/src/engine/keyman32/selectkeyboard.cpp index c40ec66c14..c704803093 100644 --- a/windows/src/engine/keyman32/selectkeyboard.cpp +++ b/windows/src/engine/keyman32/selectkeyboard.cpp @@ -106,8 +106,8 @@ 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); + // TODO: 5011 + //ActivateDLLs(_td->lpActiveKeyboard); return TRUE; } From fb2a246f530de839bc40dcca7cd57566b635bfaf Mon Sep 17 00:00:00 2001 From: Ross Date: Tue, 13 Jul 2021 16:59:40 +1000 Subject: [PATCH 07/63] feat(windows): update update windows engine action que from core processor --- .../keyman32/appint/aiWin2000Unicode.cpp | 5 + .../engine/keyman32/appint/aiWin2000Unicode.h | 19 +-- .../src/engine/keyman32/keyboardoptions.cpp | 37 +++-- windows/src/engine/keyman32/keyboardoptions.h | 2 + windows/src/engine/keyman32/kmprocess.cpp | 146 +++++++++++------- 5 files changed, 131 insertions(+), 78 deletions(-) diff --git a/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp b/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp index 4027e7a318..52f051c63c 100644 --- a/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp +++ b/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp @@ -116,6 +116,11 @@ WCHAR *AIWin2000Unicode::ContextBufMax(int n) { return context->BufMax(n); } + +void AIWin2000Unicode::SetContext(const WCHAR* buf) +{ + return context->Set(buf); +} BYTE SavedKbdState[256]; diff --git a/windows/src/engine/keyman32/appint/aiWin2000Unicode.h b/windows/src/engine/keyman32/appint/aiWin2000Unicode.h index 3866137074..005d43b8b6 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); @@ -56,9 +56,10 @@ public: virtual void AddContext(WCHAR ch); //I2436 virtual WCHAR *ContextBuf(int n); virtual WCHAR *ContextBufMax(int n); + 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); }; diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index a9a50754bf..e4f039c94b 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -24,6 +24,7 @@ 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, LPCWSTR value); void LoadKeyboardOptions(LPINTKEYBOARDINFO kp) { // I3594 @@ -145,6 +146,25 @@ void SaveKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSave) IntSaveKeyboardOption(REGSZ_KeyboardOptions, kp, nStoreToSave); } +void SaveKeyboardOptionREGCore(LPINTKEYBOARDINFO kp, LPCWSTR key, LPCWSTR value) +{ + IntSaveKeyboardOptionREGCore(REGSZ_KeyboardOptions, kp, key, value); +} + +void IntSaveKeyboardOptionREGCore(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR key, LPCWSTR value) +{ + assert(REGKey != NULL); + assert(kp != NULL); + assert(kp->coreKeyboard != NULL); + assert(kp->coreKeyboardOptions != NULL); + // TODO: 5011 just check for yourself that the core processor now checks if there size limit of the keyboard store has been reached. + RegistryFullAccess r(HKEY_CURRENT_USER); + if (r.OpenKey(REGSZ_KeymanActiveKeyboards, TRUE) && r.OpenKey(kp->Name, TRUE) && r.OpenKey(REGKey, TRUE)) + { + std::wstring tempValue(value); + r.WriteString(key, &tempValue[0]); + } +} BOOL IntLoadKeyboardOptions(LPCSTR key, LPINTKEYBOARDINFO kp) { @@ -171,7 +191,7 @@ BOOL IntLoadKeyboardOptions(LPCSTR key, LPINTKEYBOARDINFO kp) { if(kp->Keyboard->dpStoreArray[i].dpName != NULL && _wcsicmp(kp->Keyboard->dpStoreArray[i].dpName, buf) == 0) { - kp->KeyboardOptions[i].Value = new WCHAR[wcslen(val)+1]; // is this a memory leak as + kp->KeyboardOptions[i].Value = new WCHAR[wcslen(val)+1]; // is this a memory leak as wcscpy_s(kp->KeyboardOptions[i].Value, wcslen(val)+1, val); kp->KeyboardOptions[i].OriginalStore = kp->Keyboard->dpStoreArray[i].dpString; @@ -233,21 +253,16 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* { buf[255] = 0; WCHAR val[256]; - WCHAR* PWVAL; if (r.ReadString(buf, val, sizeof(val) / sizeof(val[0])) && val[0]) { val[255] = 0; keyboardOpts[n].scope = KM_KBP_OPT_KEYBOARD; - - size_t charSize = strlen(key) + 1; - wchar_t* KeyWCHAR = new WCHAR[charSize]; - size_t convertedChars = 0; - mbstowcs_s(&convertedChars, KeyWCHAR, charSize, key, _TRUNCATE); - keyboardOpts[n].key = reinterpret_cast(KeyWCHAR); - PWVAL = new WCHAR[wcslen(val) + 1]; // is this a memory leak as - wcscpy_s(PWVAL, wcslen(val) + 1, val); - keyboardOpts[n].value = reinterpret_cast(PWVAL); + std::wstring tempKey(buf); + keyboardOpts[n].key = reinterpret_cast(&tempKey[0]); + + std::wstring tempValue(value); + keyboardOpts[n].value = reinterpret_cast(&tempValue[0]); } n++; } diff --git a/windows/src/engine/keyman32/keyboardoptions.h b/windows/src/engine/keyman32/keyboardoptions.h index a190b1bb01..7e7ddb5f87 100644 --- a/windows/src/engine/keyman32/keyboardoptions.h +++ b/windows/src/engine/keyman32/keyboardoptions.h @@ -32,3 +32,5 @@ void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp); * @param state core keyboard state used to update keyboard options */ void LoadKeyboardOptionsREGCore(LPINTKEYBOARDINFO kp, km_kbp_state* state); + +void SaveKeyboardOptionREGCore(LPINTKEYBOARDINFO kp, LPCWSTR key, LPCWSTR value); diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index 83987e3ce3..880732b6be 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -109,8 +109,8 @@ BOOL ProcessHook() LPGROUP gp = _td->state.startgroup; - fOutputKeystroke = FALSE; // TODO: 5011 no longer needs to be global - + 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 // @@ -122,9 +122,6 @@ BOOL ProcessHook() //app->NoSetShift = FALSE; _td->app->ReadContext(); - /// TODO: 5011 Could set context of the core engine here (every time there is a ReadContext or Write Context) - // To make sure they are syncronised. However it also probably safest to read the context just before processing an event - // also. if(_td->state.msg.message == wm_keymankeydown) { // I4827 if (ShouldDebug(sdmKeyboard)) { @@ -144,70 +141,103 @@ BOOL ProcessHook() _td->app->QueueDebugInformation(QID_BEGIN_ANSI, NULL, NULL, NULL, NULL, (DWORD_PTR) &keyinfo); } - /// TODO: 5011 Need to make sure the context is set correctly before processing event - // WCHAR buf[MAXCONTEXT]; - // _td->app->GetWindowContext(buf, MAXCONTEXT); - // km_kbp_context_item *citems = nullptr; - // km_kbp_context_items_from_utf16(buf, &citems); - // km_kbp_context_set(km_kbp_state_context(_td->activeKbState), citems); - // km_kbp_context_items_dispose(citems); - /// TODO: 5011 km_kbp_process_event(_td->activeKbState, state.vkey, "modifier_state") - ProcessGroup(gp); + if (isUsingCoreProcessor) { + PWSTR buf; + buf = _td->app->ContextBufMax(MAXCONTEXT); + km_kbp_context_item *citems = nullptr; + km_kbp_context_items_from_utf16(reinterpret_cast(buf), &citems); + km_kbp_context_set(km_kbp_state_context(_td->state.lpActiveKBState), citems); + km_kbp_context_items_dispose(citems); + km_kbp_process_event(_td->state.lpActiveKBState, _td->state.vkey, static_cast(Globals::get_ShiftState())); + } + else { + ProcessGroup(gp); // TODO: 5442 remove + } + /// TODO: 5011 process all the actions and data munge them into here. /// Need to update(replace) the platform layer keyman32 context with the context from the core engine - //buf[0] = 0; // clear buffer - //size_t contextSize; - //km_kbp_context_items_to_utf16(_td->activeKbState,buf, &contextSize); - // call a public function to set the Context Or if we aren't going to update the interface for aiTIP - // Then reset the context and call append for each char in buf. + km_kbp_cp buf[MAXCONTEXT]; + size_t contextSize; + km_kbp_context_item* context_items; + km_kbp_context* LPCONTEXT = km_kbp_state_context(_td->state.lpActiveKBState); + + + if (km_kbp_context_get(LPCONTEXT, &context_items) == KM_KBP_STATUS_OK) { + km_kbp_context_items_to_utf16(context_items, NULL, &contextSize); + //buf = new km_kbp_cp[contextSize]; + km_kbp_context_items_to_utf16(context_items, buf, &contextSize); + } + km_kbp_context_items_dispose(context_items); + _td->app->SetContext(reinterpret_cast(buf)); // Now that we have updated the context update that action queue in the AIINT - // for (auto act = km_kbp_state_action_items(_td->activeKbState, nullptr); act->type != KM_KBP_IT_END; act++) { + for (auto act = km_kbp_state_action_items(_td->state.lpActiveKBState, nullptr); act->type != KM_KBP_IT_END; act++) { - // switch (act.type) - // { - // case KM_KBP_IT_END: - // // error assert(false); - // break; - // case KM_KBP_IT_ALERT: - // _td->app->QueueAction(QIT_BELL, 0); - // break; - // case KM_KBP_IT_CHAR: - // // unicode scalar value is stored in - // //act->character; - // _td->app->QueueAction(QIT_CHAR,Convert_to_utf16(act->character)); - // break; - // case KM_KBP_IT_MARKER: - // // act->marker - // _td->app->QueueAction(QIT_DEADKEY,Convert_To_KEY(act->marker)); - // break; - // case KM_KBP_IT_BACK: - // /// TODO: 5011 The context is changed in processing engine so this may not match the cached context in the (this) keyman32 layer. - // _td->app->QueueAction(QIT_BACK,BK_DEADKEY); - // break; - // case KM_KBP_IT_PERSIST_OPT: - // /// update keyboard options at the platform layer. - // break; - // case KM_KBP_IT_INVALIDATE_CONTEXT: - // // Reset context - // _td->app->ResetContext(); - // break; - // case KM_KBP_IT_EMIT_KEYSTROKE: - // fOutputKeystroke = TRUE; - // break; - // default: - // assert(false); // NOT SUPPORTED - // break; + switch (act->type) + { + case KM_KBP_IT_END: + // error assert(false); + break; + case KM_KBP_IT_ALERT: + _td->app->QueueAction(QIT_BELL, 0); + break; + case KM_KBP_IT_CHAR: + if (Uni_IsSMP(act->character)) { + _td->app->QueueAction(QIT_CHAR, (Uni_UTF32ToSurrogate1(act->character))); + _td->app->QueueAction(QIT_CHAR, (Uni_UTF32ToSurrogate2(act->character))); + } + else { + _td->app->QueueAction(QIT_CHAR, act->character); + } + break; + case KM_KBP_IT_BACK: + // TODO: extract exact infor from DEADKEY in actin tiem + _td->app->QueueAction(QIT_BACK,BK_DEADKEY); + break; + case KM_KBP_IT_PERSIST_OPT: + /// update keyboard options at the platform layer. ie this where keyboardoptions.cpp will have save keyboard option that needs to be written + if (act->option != NULL) + { + // Allocate for 1 option plus 1 pad struct of 0's + km_kbp_option_item* keyboardOpts = new km_kbp_option_item[2]; + memmove(&(keyboardOpts[0]), act->option, sizeof(km_kbp_option_item)); + km_kbp_status eventStatus = km_kbp_state_options_update(_td->state.lpActiveKBState, keyboardOpts); + if (eventStatus != KM_KBP_STATUS_OK) + { + // log warning "problem saving option for km_kbp_keyboard"); + } + delete[] keyboardOpts; - // } + // Put the keyboard option into Windows Registry + if (act->option != NULL && act->option->key != NULL && + act->option->value != NULL) + { + // log"Saving keyboard option to registry"); + SaveKeyboardOptionREGCore(_td->lpActiveKeyboard, reinterpret_cast(act->option->key), reinterpret_cast(act->option->value)); + } + } + break; + case KM_KBP_IT_INVALIDATE_CONTEXT: + // Reset context + _td->app->ResetContext(); + break; + case KM_KBP_IT_EMIT_KEYSTROKE: + fOutputKeystroke = TRUE; + break; + case KM_KBP_IT_MARKER: + break; + default: + assert(false); // NOT SUPPORTED + break; + + } - // } + } - /// TODO: 5011 process this in action items iterations. Do we want to process this when we find the action in the list from the core engine or - // do we process the emit key stroke with whatever we have queued up to this point. + /// TODO: 5011 Emit Keystroke will always be the last action item if it exits in the action item quue if (fOutputKeystroke && !_td->app->IsQueueEmpty()) { // // #2759: The keyboard has requested that the default output From 99b4bc73b84d835064c11f8cb81592cb615098e9 Mon Sep 17 00:00:00 2001 From: Ross Date: Tue, 20 Jul 2021 11:43:57 +1000 Subject: [PATCH 08/63] feat(windows): appcontext to core kb_kmn_context --- windows/src/engine/keyman32/appint/appint.cpp | 35 +++++++++++++++++++ windows/src/engine/keyman32/appint/appint.h | 3 ++ .../src/engine/keyman32/keyboardoptions.cpp | 16 ++++----- windows/src/engine/keyman32/keyboardoptions.h | 2 +- windows/src/engine/keyman32/kmprocess.cpp | 34 +++++++----------- windows/src/global/inc/keyman64.h | 1 + 6 files changed, 59 insertions(+), 32 deletions(-) diff --git a/windows/src/engine/keyman32/appint/appint.cpp b/windows/src/engine/keyman32/appint/appint.cpp index 1349b2918a..abe45c532e 100644 --- a/windows/src/engine/keyman32/appint/appint.cpp +++ b/windows/src/engine/keyman32/appint/appint.cpp @@ -203,3 +203,38 @@ AppIntegration::AppIntegration() hwnd = NULL; FShiftFlags = 0; } + +/* Helper function to convert App context array into core engine context */ +BOOL context_items_from_aapcontext(WCHAR const* buf, km_kbp_context_item** outPtr) +{ + + km_kbp_context_item* context_items = new km_kbp_context_item[wcslen(buf) + 1]; + // would like to check bad allocation but nothrow not known to this compilier + WCHAR const *p = buf; + uint8_t contextIndex = 0; + while (*p) { + if (*p == UC_SENTINEL) { + // we know the only uc_sentinel code in the context is code_deadkey, which has only 1 parameter: uc_sentinel code_deadkey + // setup dead key context item + p += 2; + context_items[contextIndex++] = km_kbp_context_item{ KM_KBP_CT_MARKER, {0,}, {*p} }; + } + else { // setup character need to handl surrogate + if (*p >= 0xD800 && *p <= 0xDBFF && *(p + 1) >= 0xDC00 && *(p + 1) <= 0xDFFF) { + DWORD uni32char = (((*p) - 0xD800) * 0x400 + ((*(p + 1)) - 0xDBFF) + 0x10000); + context_items[contextIndex++] = km_kbp_context_item{ KM_KBP_CT_CHAR, {0,}, {uni32char} }; + p++; + } + else { + // handle as a single + context_items[contextIndex++] = km_kbp_context_item{ KM_KBP_CT_CHAR, {0,}, {*p} }; + } + } + p++; + } + // terminate the context_items array. + context_items[contextIndex] = km_kbp_context_item KM_KBP_CONTEXT_ITEM_END; + + *outPtr = context_items; + return true; +} diff --git a/windows/src/engine/keyman32/appint/appint.h b/windows/src/engine/keyman32/appint/appint.h index 55f6c4a693..5196beaa0a 100644 --- a/windows/src/engine/keyman32/appint/appint.h +++ b/windows/src/engine/keyman32/appint/appint.h @@ -208,6 +208,9 @@ public: virtual BOOL SendActions() = 0; // I4196 }; +/* Helper function to convert App context array into core engine context */ +BOOL context_items_from_aapcontext(WCHAR const* buf, km_kbp_context_item** outPtr); + extern const LPSTR ItemTypes[]; #endif diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index e4f039c94b..1b8bcad4e8 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -19,12 +19,11 @@ */ #include "pch.h" #include "registry.h" -#include 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, LPCWSTR value); +void IntSaveKeyboardOptionREGCore(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value); void LoadKeyboardOptions(LPINTKEYBOARDINFO kp) { // I3594 @@ -146,12 +145,12 @@ void SaveKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSave) IntSaveKeyboardOption(REGSZ_KeyboardOptions, kp, nStoreToSave); } -void SaveKeyboardOptionREGCore(LPINTKEYBOARDINFO kp, LPCWSTR key, LPCWSTR value) +void SaveKeyboardOptionREGCore(LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value) { IntSaveKeyboardOptionREGCore(REGSZ_KeyboardOptions, kp, key, value); } -void IntSaveKeyboardOptionREGCore(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR key, LPCWSTR value) +void IntSaveKeyboardOptionREGCore(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value) { assert(REGKey != NULL); assert(kp != NULL); @@ -161,8 +160,7 @@ void IntSaveKeyboardOptionREGCore(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR k RegistryFullAccess r(HKEY_CURRENT_USER); if (r.OpenKey(REGSZ_KeymanActiveKeyboards, TRUE) && r.OpenKey(kp->Name, TRUE) && r.OpenKey(REGKey, TRUE)) { - std::wstring tempValue(value); - r.WriteString(key, &tempValue[0]); + r.WriteString(key, value); } } @@ -258,11 +256,9 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* val[255] = 0; keyboardOpts[n].scope = KM_KBP_OPT_KEYBOARD; - std::wstring tempKey(buf); - keyboardOpts[n].key = reinterpret_cast(&tempKey[0]); + keyboardOpts[n].key = reinterpret_cast(&buf[0]); - std::wstring tempValue(value); - keyboardOpts[n].value = reinterpret_cast(&tempValue[0]); + keyboardOpts[n].value = reinterpret_cast(&buf[0]); } n++; } diff --git a/windows/src/engine/keyman32/keyboardoptions.h b/windows/src/engine/keyman32/keyboardoptions.h index 7e7ddb5f87..fce86a9216 100644 --- a/windows/src/engine/keyman32/keyboardoptions.h +++ b/windows/src/engine/keyman32/keyboardoptions.h @@ -33,4 +33,4 @@ void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp); */ void LoadKeyboardOptionsREGCore(LPINTKEYBOARDINFO kp, km_kbp_state* state); -void SaveKeyboardOptionREGCore(LPINTKEYBOARDINFO kp, LPCWSTR key, LPCWSTR value); +void SaveKeyboardOptionREGCore(LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value); diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index 880732b6be..1fe80faceb 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -89,6 +89,7 @@ char *getcontext_debug() { return Debug_UnicodeString(_td->app->ContextBufMax(128)); } + /* * BOOL ProcessHook(); * @@ -145,7 +146,7 @@ BOOL ProcessHook() PWSTR buf; buf = _td->app->ContextBufMax(MAXCONTEXT); km_kbp_context_item *citems = nullptr; - km_kbp_context_items_from_utf16(reinterpret_cast(buf), &citems); + context_items_from_aapcontext(buf, &citems); km_kbp_context_set(km_kbp_state_context(_td->state.lpActiveKBState), citems); km_kbp_context_items_dispose(citems); km_kbp_process_event(_td->state.lpActiveKBState, _td->state.vkey, static_cast(Globals::get_ShiftState())); @@ -158,19 +159,6 @@ BOOL ProcessHook() /// TODO: 5011 process all the actions and data munge them into here. /// Need to update(replace) the platform layer keyman32 context with the context from the core engine - km_kbp_cp buf[MAXCONTEXT]; - size_t contextSize; - km_kbp_context_item* context_items; - km_kbp_context* LPCONTEXT = km_kbp_state_context(_td->state.lpActiveKBState); - - - if (km_kbp_context_get(LPCONTEXT, &context_items) == KM_KBP_STATUS_OK) { - km_kbp_context_items_to_utf16(context_items, NULL, &contextSize); - //buf = new km_kbp_cp[contextSize]; - km_kbp_context_items_to_utf16(context_items, buf, &contextSize); - } - km_kbp_context_items_dispose(context_items); - _td->app->SetContext(reinterpret_cast(buf)); // Now that we have updated the context update that action queue in the AIINT for (auto act = km_kbp_state_action_items(_td->state.lpActiveKBState, nullptr); act->type != KM_KBP_IT_END; act++) { @@ -184,7 +172,7 @@ BOOL ProcessHook() _td->app->QueueAction(QIT_BELL, 0); break; case KM_KBP_IT_CHAR: - if (Uni_IsSMP(act->character)) { + if (Uni_IsSMP(act->character)) { _td->app->QueueAction(QIT_CHAR, (Uni_UTF32ToSurrogate1(act->character))); _td->app->QueueAction(QIT_CHAR, (Uni_UTF32ToSurrogate2(act->character))); } @@ -192,12 +180,16 @@ BOOL ProcessHook() _td->app->QueueAction(QIT_CHAR, act->character); } break; + case KM_KBP_IT_MARKER: + // Marker in the kmx_processor is the unicode character cast to uint64_t + // however it is not meant to be the key. we just will not be able to have our + // engine cache track the dead key. + _td->app->QueueAction(QIT_DEADKEY, act->marker); + break; case KM_KBP_IT_BACK: - // TODO: extract exact infor from DEADKEY in actin tiem _td->app->QueueAction(QIT_BACK,BK_DEADKEY); break; case KM_KBP_IT_PERSIST_OPT: - /// update keyboard options at the platform layer. ie this where keyboardoptions.cpp will have save keyboard option that needs to be written if (act->option != NULL) { // Allocate for 1 option plus 1 pad struct of 0's @@ -215,7 +207,9 @@ BOOL ProcessHook() act->option->value != NULL) { // log"Saving keyboard option to registry"); - SaveKeyboardOptionREGCore(_td->lpActiveKeyboard, reinterpret_cast(act->option->key), reinterpret_cast(act->option->value)); + LPWSTR value = new WCHAR[sizeof(act->option->value) + 1]; + wcscpy_s(value, sizeof(act->option->value) + 1, reinterpret_cast(act->option->value)); + SaveKeyboardOptionREGCore(_td->lpActiveKeyboard, reinterpret_cast(act->option->key), value); } } break; @@ -226,15 +220,13 @@ BOOL ProcessHook() case KM_KBP_IT_EMIT_KEYSTROKE: fOutputKeystroke = TRUE; break; - case KM_KBP_IT_MARKER: - break; + default: assert(false); // NOT SUPPORTED break; } - } /// TODO: 5011 Emit Keystroke will always be the last action item if it exits in the action item quue diff --git a/windows/src/global/inc/keyman64.h b/windows/src/global/inc/keyman64.h index a0b2092720..327daac01d 100644 --- a/windows/src/global/inc/keyman64.h +++ b/windows/src/global/inc/keyman64.h @@ -201,5 +201,6 @@ typedef struct tagKEYBOARD #include "registry.h" #include "unicode.h" #include "xstring.h" +#include #endif // _KEYMAN64_H From 7a9ee207a81a3b3ede602b1393b414ecbe1a8d8b Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 21 Jul 2021 16:53:00 +1000 Subject: [PATCH 09/63] feat(windows): update project include paths for core --- windows/src/developer/kmanalyze/kmanalyze.vcxproj | 6 +++--- .../developer/kmanalyze/kmanalyze.vcxproj.filters | 6 +++--- windows/src/developer/kmdecomp/kmdecomp.vcxproj | 2 ++ windows/src/engine/keyman32/Keyman32.vcxproj | 2 +- windows/src/engine/keyman32/k32_globals.cpp | 3 ++- windows/src/engine/keyman32/kmprocess.cpp | 2 +- .../tests/keyman32-tests/keyman32-tests.vcxproj | 2 +- windows/src/engine/keyman64/keyman64.vcxproj | 4 ++-- windows/src/engine/kmtip/kmtip.vcxproj | 12 ++++++++++++ windows/src/global/inc/registry.h | 2 +- 10 files changed, 28 insertions(+), 13 deletions(-) diff --git a/windows/src/developer/kmanalyze/kmanalyze.vcxproj b/windows/src/developer/kmanalyze/kmanalyze.vcxproj index d60e309d1e..676dfa1524 100644 --- a/windows/src/developer/kmanalyze/kmanalyze.vcxproj +++ b/windows/src/developer/kmanalyze/kmanalyze.vcxproj @@ -72,7 +72,7 @@ true - $(VC_IncludePath);$(WindowsSDK_IncludePath);$(KEYMAN_ROOT)\windows\src\global\inc;$(KEYMAN_ROOT)\windows\src\ext\sentry + $(KEYMAN_ROOT)\common\core\desktop\include;$(KEYMAN_ROOT)\common\core\desktop\build\x86\$(Configuration)\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(KEYMAN_ROOT)\windows\src\global\inc;$(KEYMAN_ROOT)\windows\src\ext\sentry $(ProjectDir)bin\$(Platform)\$(Configuration)\ $(ProjectDir)obj\$(Platform)\$(Configuration)\ @@ -84,7 +84,7 @@ false - $(VC_IncludePath);$(WindowsSDK_IncludePath);$(KEYMAN_ROOT)\windows\src\global\inc;$(KEYMAN_ROOT)\windows\src\ext\sentry + $(KEYMAN_ROOT)\common\core\desktop\build\x86\$(Configuration)\include;$(KEYMAN_ROOT)\common\core\desktop\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(KEYMAN_ROOT)\windows\src\global\inc;$(KEYMAN_ROOT)\windows\src\ext\sentry $(ProjectDir)bin\$(Platform)\$(Configuration)\ $(ProjectDir)obj\$(Platform)\$(Configuration)\ @@ -179,8 +179,8 @@ - + diff --git a/windows/src/developer/kmanalyze/kmanalyze.vcxproj.filters b/windows/src/developer/kmanalyze/kmanalyze.vcxproj.filters index 895a3532fa..cc0f741f89 100644 --- a/windows/src/developer/kmanalyze/kmanalyze.vcxproj.filters +++ b/windows/src/developer/kmanalyze/kmanalyze.vcxproj.filters @@ -18,15 +18,15 @@ Header Files - - Header Files - Header Files Header Files + + Header Files + diff --git a/windows/src/developer/kmdecomp/kmdecomp.vcxproj b/windows/src/developer/kmdecomp/kmdecomp.vcxproj index 6c72b02a6c..287dd85247 100644 --- a/windows/src/developer/kmdecomp/kmdecomp.vcxproj +++ b/windows/src/developer/kmdecomp/kmdecomp.vcxproj @@ -54,9 +54,11 @@ $(ProjectDir)bin\$(Platform)\$(Configuration)\ $(ProjectDir)obj\$(Platform)\$(Configuration)\ + $(KEYMAN_ROOT)\common\core\desktop\build\x86\$(Configuration)\include;$(KEYMAN_ROOT)\common\core\desktop\include;$(IncludePath) $(ProjectDir)bin\$(Platform)\$(Configuration)\ + $(KEYMAN_ROOT)\common\core\desktop\build\x86\$(Configuration)\include;$(KEYMAN_ROOT)\common\core\desktop\include;$(IncludePath) diff --git a/windows/src/engine/keyman32/Keyman32.vcxproj b/windows/src/engine/keyman32/Keyman32.vcxproj index 87ef5b5b92..894e9d3318 100644 --- a/windows/src/engine/keyman32/Keyman32.vcxproj +++ b/windows/src/engine/keyman32/Keyman32.vcxproj @@ -59,7 +59,7 @@ $(ProjectDir)..\..\..\..\common\core\desktop\build\x86\$(Configuration)\src;$(ProjectDir)..\..\..\..\common\core\desktop\build\rust\x86\$(Configuration);$(LibraryPath) - $(ProjectDir)..\..\..\..\common\core\desktop\build\x86\$(Configuration)\include;$(IncludePath) + $(ProjectDir)..\..\..\..\common\core\desktop\build\x86\$(Configuration)\include;$(ProjectDir)..\..\..\..\common\core\desktop\include;$(IncludePath) diff --git a/windows/src/engine/keyman32/k32_globals.cpp b/windows/src/engine/keyman32/k32_globals.cpp index efae536e99..87f2997ae6 100644 --- a/windows/src/engine/keyman32/k32_globals.cpp +++ b/windows/src/engine/keyman32/k32_globals.cpp @@ -386,7 +386,8 @@ void Globals::SetBaseKeyboardFlags(char *baseKeyboard, BOOL simulateAltGr, BOOL */ BOOL Globals::InitSettings() { /* Check for common core vs windows core */ - f_CoreIntegration = Reg_GetDebugFlag(REGSZ_CoreIntegration, FALSE); + f_CoreIntegration = Reg_GetDebugFlag(REGSZ_CoreIntegration, TRUE); + SendDebugMessageFormat(0, sdmAIDefault, 0, "Globals::InitSettings - Coreintegration set in '" REGSZ_CoreIntegration "' 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/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index 1fe80faceb..ad57747fbc 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -184,7 +184,7 @@ BOOL ProcessHook() // Marker in the kmx_processor is the unicode character cast to uint64_t // however it is not meant to be the key. we just will not be able to have our // engine cache track the dead key. - _td->app->QueueAction(QIT_DEADKEY, act->marker); + _td->app->QueueAction(QIT_DEADKEY, (DWORD)act->marker); break; case KM_KBP_IT_BACK: _td->app->QueueAction(QIT_BACK,BK_DEADKEY); diff --git a/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj b/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj index d3fc67cceb..0f5a1e193f 100644 --- a/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj +++ b/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj @@ -151,4 +151,4 @@ - + \ No newline at end of file diff --git a/windows/src/engine/keyman64/keyman64.vcxproj b/windows/src/engine/keyman64/keyman64.vcxproj index f1b91af99e..8cbbcab9ad 100644 --- a/windows/src/engine/keyman64/keyman64.vcxproj +++ b/windows/src/engine/keyman64/keyman64.vcxproj @@ -55,11 +55,11 @@ $(ProjectDir)..\..\..\..\common\core\desktop\build\x64\$(Configuration)\src;$(ProjectDir)..\..\..\..\common\core\desktop\build\rust\x64\$(Configuration);$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) - $(ProjectDir)..\..\..\..\common\core\desktop\build\x64\$(Configuration)\include;$(IncludePath) + $(ProjectDir)..\..\..\..\common\core\desktop\build\x64\$(Configuration)\include;$(ProjectDir)..\..\..\..\common\core\desktop\include;$(IncludePath) $(ProjectDir)..\..\..\..\common\core\desktop\build\x64\$(Configuration)\src;$(ProjectDir)..\..\..\..\common\core\desktop\build\rust\x64\$(Configuration);$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) - $(ProjectDir)..\..\..\..\common\core\desktop\build\x64\$(Configuration)\include;$(IncludePath) + $(ProjectDir)..\..\..\..\common\core\desktop\build\x64\$(Configuration)\include;$(ProjectDir)..\..\..\..\common\core\desktop\include;$(IncludePath) diff --git a/windows/src/engine/kmtip/kmtip.vcxproj b/windows/src/engine/kmtip/kmtip.vcxproj index e8af27c61a..a6bd20855e 100644 --- a/windows/src/engine/kmtip/kmtip.vcxproj +++ b/windows/src/engine/kmtip/kmtip.vcxproj @@ -104,6 +104,18 @@ kmtip64 kmtip64 + + $(ProjectDir)..\..\..\..\common\core\desktop\build\x86\$(Configuration)\include;$(ProjectDir)..\..\..\..\common\core\desktop\include;$(IncludePath) + + + $(ProjectDir)..\..\..\..\common\core\desktop\build\x86\$(Configuration)\include;$(ProjectDir)..\..\..\..\common\core\desktop\include;$(IncludePath) + + + $(ProjectDir)..\..\..\..\common\core\desktop\build\x86\$(Configuration)\include;$(ProjectDir)..\..\..\..\common\core\desktop\include;$(IncludePath) + + + $(ProjectDir)..\..\..\..\common\core\desktop\build\x86\$(Configuration)\include;$(ProjectDir)..\..\..\..\common\core\desktop\include;$(IncludePath) + NDEBUG;%(PreprocessorDefinitions) diff --git a/windows/src/global/inc/registry.h b/windows/src/global/inc/registry.h index 19c479a0c4..aec4e38de5 100644 --- a/windows/src/global/inc/registry.h +++ b/windows/src/global/inc/registry.h @@ -140,7 +140,7 @@ #define REGSZ_AutomaticallyReportErrors "automatically report errors" // CU, SRegKey_IDEOptions and SRegKey_KeymanEngine_CU #define REGSZ_AutomaticallyReportUsage "automatically report usage" // CU, SRegKey_IDEOptions and SRegKey_KeymanEngine_CU -#define REGSZ_CoreIntegration "Turn on common core" // Turns on the common core - instead of windows core +#define REGSZ_CoreIntegration "use common core" // Turns on the common core - instead of windows core /* Splitting Registry into ReadOnly and FullAccess makes it much easier to ensure that we are using the registry correctly -- readonly wherever possible. */ From 7d5187ae644f5dd7bdf6bbee524fb93f29caacaf Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 22 Jul 2021 15:48:51 +1000 Subject: [PATCH 10/63] feat(windows): add correct memory free calls for core --- .../include/keyman/keyboardprocessor.h.in | 4 +++- windows/src/engine/keyman32/K32_load.cpp | 21 +++++++++++++++-- windows/src/engine/keyman32/Keyman32.cpp | 6 +++++ windows/src/engine/keyman32/appint/aiTIP.cpp | 6 +++-- windows/src/engine/keyman32/appint/appint.cpp | 9 ++++---- windows/src/engine/keyman32/appint/appint.h | 11 +++++++-- windows/src/engine/keyman32/globals.h | 3 --- windows/src/engine/keyman32/k32_globals.cpp | 1 - .../src/engine/keyman32/keyboardoptions.cpp | 18 +++++++++------ windows/src/engine/keyman32/keyboardoptions.h | 11 +++++++-- windows/src/engine/keyman32/kmprocess.cpp | 23 ++++++++----------- .../src/engine/keyman32/selectkeyboard.cpp | 16 ++++++------- 12 files changed, 82 insertions(+), 47 deletions(-) diff --git a/common/core/desktop/include/keyman/keyboardprocessor.h.in b/common/core/desktop/include/keyman/keyboardprocessor.h.in index 33b2eef253..fd387a08ea 100644 --- a/common/core/desktop/include/keyman/keyboardprocessor.h.in +++ b/common/core/desktop/include/keyman/keyboardprocessor.h.in @@ -838,7 +838,9 @@ Get the list of action items generated by the last call to A pointer to a `km_kbp_action_item` list, of `*num_items` in length. This data becomes invalid when the state object is destroyed, or after a call to `km_kbp_process_event`. Do not modify the contents of this data. The returned -array is terminated with a `KM_KBP_IT_END` entry. +array is terminated with a `KM_KBP_IT_END` entry. Emit Keystroke `KM_KBP_IT_EMIT_KEYSTROKE` +will always be the last action item if it exits. +in the action item queue. ##### Parameters: - __state__: A pointer to the opaque `km_kbp_state` object to be queried. - __num_items__: diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index 2f458aa1ce..c06541d041 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -89,19 +89,32 @@ BOOL LoadlpKeyboardCore(int i) if (!GetKeyboardFileName(_td->lpKeyboards[i].Name, buf, 255)) return FALSE; size_t charSize = strlen(buf) + 1; - wchar_t* keyboardPath = new wchar_t[charSize]; + LPWSTR keyboardPath = new WCHAR[charSize]; // Convert char* string to a wchar_t* string. size_t convertedChars = 0; mbstowcs_s(&convertedChars, keyboardPath, charSize, buf, _TRUNCATE); + if (_td->lpKeyboards[i].coreKeyboard) + { + km_kbp_keyboard_dispose(_td->lpKeyboards[i].coreKeyboard); + _td->lpKeyboards[i].coreKeyboard = NULL; + } + if (KM_KBP_STATUS_OK != km_kbp_keyboard_load(keyboardPath, &_td->lpKeyboards[i].coreKeyboard)) return FALSE; - // TODO: 5011 handle dlls + // TODO: 5442 handle dlls //LoadDLLs(&_td->lpKeyboards[i]); const km_kbp_option_item test_env_opts[] = { KM_KBP_OPTIONS_END }; + + if (_td->state.lpActiveKBState) + { + km_kbp_state_dispose(_td->state.lpActiveKBState); + _td->state.lpActiveKBState = NULL; + } + km_kbp_state_create(_td->lpKeyboards[i].coreKeyboard, test_env_opts, &_td->state.lpActiveKBState); LoadKeyboardOptionsREGCore(&_td->lpKeyboards[i], _td->state.lpActiveKBState); @@ -113,6 +126,10 @@ BOOL LoadlpKeyboardCore(int i) 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; diff --git a/windows/src/engine/keyman32/Keyman32.cpp b/windows/src/engine/keyman32/Keyman32.cpp index 99965bcbe9..611f8ba01a 100644 --- a/windows/src/engine/keyman32/Keyman32.cpp +++ b/windows/src/engine/keyman32/Keyman32.cpp @@ -982,6 +982,12 @@ void ReleaseKeyboards(BOOL Lock) if(Lock) UnloadDLLs(&_td->lpKeyboards[i]); FreeKeyboardOptions(&_td->lpKeyboards[i]); ReleaseKeyboardMemory(_td->lpKeyboards[i].Keyboard); + // release core keyboard memory. + if (_td->lpKeyboards[i].coreKeyboard) { + km_kbp_keyboard_dispose(_td->lpKeyboards[i].coreKeyboard); + _td->lpKeyboards[i].coreKeyboard = NULL; + } + if(_td->lpKeyboards[i].Profiles) delete _td->lpKeyboards[i].Profiles; // I3581 } diff --git a/windows/src/engine/keyman32/appint/aiTIP.cpp b/windows/src/engine/keyman32/appint/aiTIP.cpp index 50f54c9133..223b7e503f 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.cpp +++ b/windows/src/engine/keyman32/appint/aiTIP.cpp @@ -205,9 +205,11 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM _td->state.msg.lParam = 0; _td->state.msg.message = wm_keymankeydown; _td->state.vkey = (WORD) wParam; - /// TODO: 5011 set the modifier _td->state.modifer - /// TODO: 5011 set the correct active keyboard. + + _td->state.lpkb = _td->lpActiveKeyboard->Keyboard; + /// TODO: 5442 set the correct active keyboard - need with call backs + _td->state.lpCoreKb = _td->lpActiveKeyboard->coreKeyboard; _td->state.windowunicode = TRUE; _td->state.startgroup = &_td->state.lpkb->dpGroupArray[_td->state.lpkb->StartGroup[BEGIN_UNICODE]]; diff --git a/windows/src/engine/keyman32/appint/appint.cpp b/windows/src/engine/keyman32/appint/appint.cpp index abe45c532e..8bd56c6267 100644 --- a/windows/src/engine/keyman32/appint/appint.cpp +++ b/windows/src/engine/keyman32/appint/appint.cpp @@ -204,12 +204,11 @@ AppIntegration::AppIntegration() FShiftFlags = 0; } -/* Helper function to convert App context array into core engine context */ -BOOL context_items_from_aapcontext(WCHAR const* buf, km_kbp_context_item** outPtr) +BOOL ContextItemsFromAppContext(WCHAR const* buf, km_kbp_context_item** outPtr) { - + km_kbp_context_item* context_items = new km_kbp_context_item[wcslen(buf) + 1]; - // would like to check bad allocation but nothrow not known to this compilier + // would like to check bad allocation but nothrow not known to this compiler WCHAR const *p = buf; uint8_t contextIndex = 0; while (*p) { @@ -219,7 +218,7 @@ BOOL context_items_from_aapcontext(WCHAR const* buf, km_kbp_context_item** outPt p += 2; context_items[contextIndex++] = km_kbp_context_item{ KM_KBP_CT_MARKER, {0,}, {*p} }; } - else { // setup character need to handl surrogate + else { // setup character need to handle surrogate if (*p >= 0xD800 && *p <= 0xDBFF && *(p + 1) >= 0xDC00 && *(p + 1) <= 0xDFFF) { DWORD uni32char = (((*p) - 0xD800) * 0x400 + ((*(p + 1)) - 0xDBFF) + 0x10000); context_items[contextIndex++] = km_kbp_context_item{ KM_KBP_CT_CHAR, {0,}, {uni32char} }; diff --git a/windows/src/engine/keyman32/appint/appint.h b/windows/src/engine/keyman32/appint/appint.h index 5196beaa0a..4e258a8bde 100644 --- a/windows/src/engine/keyman32/appint/appint.h +++ b/windows/src/engine/keyman32/appint/appint.h @@ -208,8 +208,15 @@ public: virtual BOOL SendActions() = 0; // I4196 }; -/* Helper function to convert App context array into core engine context */ -BOOL context_items_from_aapcontext(WCHAR const* buf, km_kbp_context_item** outPtr); +/** + * Convert AppContext array into a array of core context items. + * Caller is responsible for freeing the memory. + * + * @param buf appcontext character array + * @param outPtr The ouput array of context items. caller to free memory + * @return BOOL True if array created succesfully + */ +BOOL ContextItemsFromAppContext(WCHAR const* buf, km_kbp_context_item** outPtr); extern const LPSTR ItemTypes[]; diff --git a/windows/src/engine/keyman32/globals.h b/windows/src/engine/keyman32/globals.h index 3d7118fa6d..1e73e51835 100644 --- a/windows/src/engine/keyman32/globals.h +++ b/windows/src/engine/keyman32/globals.h @@ -193,9 +193,6 @@ typedef struct tagKEYMAN64THREADDATA { LPINTKEYBOARDINFO lpKeyboards; // keyboard definitions LPINTKEYBOARDINFO lpActiveKeyboard; - // TODO: 5011 - //km_kbp_keyboard* lpKeyboards; // keyboard definitions - //km_kbp_keyboard* lpActiveKeyboard; // I3616 LPMSG msgbuf; // Message buffer (alloc at runtime) diff --git a/windows/src/engine/keyman32/k32_globals.cpp b/windows/src/engine/keyman32/k32_globals.cpp index 87f2997ae6..454300b06e 100644 --- a/windows/src/engine/keyman32/k32_globals.cpp +++ b/windows/src/engine/keyman32/k32_globals.cpp @@ -290,7 +290,6 @@ static BOOL static BOOL f_CoreIntegration = TRUE; - #pragma data_seg() /***************************************************************************/ diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index 1b8bcad4e8..21e029c438 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -154,9 +154,6 @@ void IntSaveKeyboardOptionREGCore(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR k { assert(REGKey != NULL); assert(kp != NULL); - assert(kp->coreKeyboard != NULL); - assert(kp->coreKeyboardOptions != NULL); - // TODO: 5011 just check for yourself that the core processor now checks if there size limit of the keyboard store has been reached. RegistryFullAccess r(HKEY_CURRENT_USER); if (r.OpenKey(REGSZ_KeymanActiveKeyboards, TRUE) && r.OpenKey(kp->Name, TRUE) && r.OpenKey(REGKey, TRUE)) { @@ -189,7 +186,7 @@ BOOL IntLoadKeyboardOptions(LPCSTR key, LPINTKEYBOARDINFO kp) { if(kp->Keyboard->dpStoreArray[i].dpName != NULL && _wcsicmp(kp->Keyboard->dpStoreArray[i].dpName, buf) == 0) { - kp->KeyboardOptions[i].Value = new WCHAR[wcslen(val)+1]; // is this a memory leak as + 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; @@ -251,24 +248,31 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* { buf[255] = 0; WCHAR val[256]; + if (r.ReadString(buf, val, sizeof(val) / sizeof(val[0])) && val[0]) { val[255] = 0; keyboardOpts[n].scope = KM_KBP_OPT_KEYBOARD; - keyboardOpts[n].key = reinterpret_cast(&buf[0]); + km_kbp_cp* cp = new km_kbp_cp[wcslen(buf) + 1]; + wcscpy_s(reinterpret_cast(cp), wcslen(buf) + 1, buf); + keyboardOpts[n].key = cp; - keyboardOpts[n].value = reinterpret_cast(&buf[0]); + cp = new km_kbp_cp[wcslen(val) + 1]; + wcscpy_s(reinterpret_cast(cp), wcslen(val) + 1, val); + keyboardOpts[n].value = cp; } n++; } + + keyboardOpts[n] = KM_KBP_OPTIONS_END; /// once we have the option list we can then update the options using the public api call km_kbp_state_options_update(state, keyboardOpts); for (int i = 0; i < (int)listSize + 1; i++) { delete[] keyboardOpts[i].key; delete[] keyboardOpts[i].value; } - delete keyboardOpts; + delete[] keyboardOpts; return TRUE; } return FALSE; diff --git a/windows/src/engine/keyman32/keyboardoptions.h b/windows/src/engine/keyman32/keyboardoptions.h index fce86a9216..1de2ae47e4 100644 --- a/windows/src/engine/keyman32/keyboardoptions.h +++ b/windows/src/engine/keyman32/keyboardoptions.h @@ -28,9 +28,16 @@ void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp); /** * Loads the keyboard options from the windows registry * - * @param kp keyboard info object with options to be updated - * @param state core keyboard state used to update keyboard options + * @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); +/** + * Saves the keyboard option to the windows registry + * + * @param kp keyboard info object with for which the option is to be updated + * @param key keyboard key to save + * @param value keyboard option value to save + */ void SaveKeyboardOptionREGCore(LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value); diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index ad57747fbc..4c34b16bee 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -110,7 +110,7 @@ BOOL ProcessHook() LPGROUP gp = _td->state.startgroup; - fOutputKeystroke = FALSE; // TODO: 5442 no longer needs to be global once we use core processor + 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 @@ -146,7 +146,7 @@ BOOL ProcessHook() PWSTR buf; buf = _td->app->ContextBufMax(MAXCONTEXT); km_kbp_context_item *citems = nullptr; - context_items_from_aapcontext(buf, &citems); + ContextItemsFromAppContext(buf, &citems); km_kbp_context_set(km_kbp_state_context(_td->state.lpActiveKBState), citems); km_kbp_context_items_dispose(citems); km_kbp_process_event(_td->state.lpActiveKBState, _td->state.vkey, static_cast(Globals::get_ShiftState())); @@ -155,18 +155,15 @@ BOOL ProcessHook() ProcessGroup(gp); // TODO: 5442 remove } - - /// TODO: 5011 process all the actions and data munge them into here. - /// Need to update(replace) the platform layer keyman32 context with the context from the core engine - - - // Now that we have updated the context update that action queue in the AIINT + + // Process the action items from the core. This actions will modify the windows context (AppContext). + // Therefore it is not required to copy the context from the core to the windows context. for (auto act = km_kbp_state_action_items(_td->state.lpActiveKBState, nullptr); act->type != KM_KBP_IT_END; act++) { switch (act->type) { case KM_KBP_IT_END: - // error assert(false); + assert(false); break; case KM_KBP_IT_ALERT: _td->app->QueueAction(QIT_BELL, 0); @@ -181,9 +178,6 @@ BOOL ProcessHook() } break; case KM_KBP_IT_MARKER: - // Marker in the kmx_processor is the unicode character cast to uint64_t - // however it is not meant to be the key. we just will not be able to have our - // engine cache track the dead key. _td->app->QueueAction(QIT_DEADKEY, (DWORD)act->marker); break; case KM_KBP_IT_BACK: @@ -192,13 +186,14 @@ BOOL ProcessHook() case KM_KBP_IT_PERSIST_OPT: if (act->option != NULL) { - // Allocate for 1 option plus 1 pad struct of 0's + // Allocate for 1 option plus 1 pad struct of 0's for KM_KBP_IT_END km_kbp_option_item* keyboardOpts = new km_kbp_option_item[2]; memmove(&(keyboardOpts[0]), act->option, sizeof(km_kbp_option_item)); km_kbp_status eventStatus = km_kbp_state_options_update(_td->state.lpActiveKBState, keyboardOpts); if (eventStatus != KM_KBP_STATUS_OK) { // log warning "problem saving option for km_kbp_keyboard"); + SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessHook: Problems saving optionf for keybooard [%s].", _td->lpActiveKeyboard->Name); } delete[] keyboardOpts; @@ -207,6 +202,7 @@ BOOL ProcessHook() act->option->value != NULL) { // log"Saving keyboard option to registry"); + SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessHook: Saving option to registry for keybooard [%s].", _td->lpActiveKeyboard->Name); LPWSTR value = new WCHAR[sizeof(act->option->value) + 1]; wcscpy_s(value, sizeof(act->option->value) + 1, reinterpret_cast(act->option->value)); SaveKeyboardOptionREGCore(_td->lpActiveKeyboard, reinterpret_cast(act->option->key), value); @@ -229,7 +225,6 @@ BOOL ProcessHook() } - /// TODO: 5011 Emit Keystroke will always be the last action item if it exits in the action item quue if (fOutputKeystroke && !_td->app->IsQueueEmpty()) { // // #2759: The keyboard has requested that the default output diff --git a/windows/src/engine/keyman32/selectkeyboard.cpp b/windows/src/engine/keyman32/selectkeyboard.cpp index c704803093..2e825d5230 100644 --- a/windows/src/engine/keyman32/selectkeyboard.cpp +++ b/windows/src/engine/keyman32/selectkeyboard.cpp @@ -61,8 +61,8 @@ BOOL SelectKeyboardCore(DWORD KeymanID) 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", + SendDebugMessageFormat(hwnd, sdmGlobal, 0, "ENTER SelectKeyboardCore-------------------------------------------"); + SendDebugMessageFormat(hwnd, sdmGlobal, 0, "ENTER SelectKeyboardCore: 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, @@ -91,14 +91,14 @@ BOOL SelectKeyboardCore(DWORD KeymanID) { if (!_td->lpKeyboards[i].Keyboard && !LoadlpKeyboard(i)) { - SendDebugMessageFormat(hwnd, sdmGlobal, 0, "SelectKeyboard: Unable to load"); + SendDebugMessageFormat(hwnd, sdmGlobal, 0, "SelectKeyboardCore: Unable to load"); return TRUE; } _td->lpActiveKeyboard = &_td->lpKeyboards[i]; _td->ActiveKeymanID = _td->lpActiveKeyboard->KeymanID; - SendDebugMessageFormat(hwnd, sdmGlobal, 0, "SelectKeyboard: NewKeymanID: %x", _td->ActiveKeymanID); + SendDebugMessageFormat(hwnd, sdmGlobal, 0, "SelectKeyboardCore: NewKeymanID: %x", _td->ActiveKeymanID); if (_td->app) _td->app->ResetContext(); ResetCapsLock(); @@ -113,19 +113,19 @@ BOOL SelectKeyboardCore(DWORD KeymanID) } if (IsFocusedThread()) { - SendDebugMessageFormat(hwnd, sdmGlobal, 0, "SelectKeyboard: Keyboard Not Found"); + SendDebugMessageFormat(hwnd, sdmGlobal, 0, "SelectKeyboardCore: 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", + SendDebugMessageFormat(hwnd, sdmGlobal, 0, "EXIT SelectKeyboardCore: 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-------------------------------------------"); + SendDebugMessageFormat(hwnd, sdmGlobal, 0, "EXIT SelectKeyboardCore-------------------------------------------"); } return TRUE; @@ -160,7 +160,7 @@ BOOL SelectKeyboard(DWORD KeymanID) } KMHideIM(); - /** TODO: 5011 is this just IDML dlls */ + if(_td->lpActiveKeyboard) DeactivateDLLs(_td->lpActiveKeyboard); _td->lpActiveKeyboard = NULL; _td->ActiveKeymanID = KEYMANID_NONKEYMAN; From 5f4902cde94f685ebdcdf271a92d7fc8054503c4 Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 26 Jul 2021 11:15:16 +1000 Subject: [PATCH 11/63] feat(windows): revert whitespace changes --- linux/ibus-keyman/src/engine.c | 1 - windows/src/engine/keyman32/appint/aiTIP.h | 16 ++++++------ .../engine/keyman32/appint/aiWin2000Unicode.h | 18 ++++++------- windows/src/engine/keyman32/appint/appint.cpp | 2 +- windows/src/global/inc/keyman64.h | 26 +++++++++---------- windows/src/global/inc/registry.h | 22 ++++++++-------- 6 files changed, 42 insertions(+), 43 deletions(-) diff --git a/linux/ibus-keyman/src/engine.c b/linux/ibus-keyman/src/engine.c index a100e4eff6..0d8ed41111 100644 --- a/linux/ibus-keyman/src/engine.c +++ b/linux/ibus-keyman/src/engine.c @@ -216,7 +216,6 @@ static void reset_context(IBusEngine *engine) ibus_engine_get_surrounding_text(engine, &text, &cursor_pos, &anchor_pos); context_pos = anchor_pos < cursor_pos ? anchor_pos : cursor_pos; - context_start = context_pos > MAXCONTEXT_ITEMS ? context_pos - MAXCONTEXT_ITEMS : 0; surrounding_text = g_utf8_substring(ibus_text_get_text(text), context_start, context_pos); g_message("new context is:%u:%s: cursor:%d anchor:%d", context_pos - context_start, surrounding_text, cursor_pos, anchor_pos); diff --git a/windows/src/engine/keyman32/appint/aiTIP.h b/windows/src/engine/keyman32/appint/aiTIP.h index 49eeb5c88d..f8cd328eb6 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.h +++ b/windows/src/engine/keyman32/appint/aiTIP.h @@ -1,18 +1,18 @@ /* Name: aiTIP Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 11 Dec 2009 Modified Date: 23 Feb 2016 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 11 Dec 2009 - mcdurdin - I934 - x64 - Initial version 24 Jun 2010 - mcdurdin - I2436 - Add space to context for AIWin2000Unicode when not matched 24 Apr 2014 - mcdurdin - I4196 - V9.0 - wm_kmmoreposting must be refactored for TIP work as it is not sequential @@ -78,7 +78,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); diff --git a/windows/src/engine/keyman32/appint/aiWin2000Unicode.h b/windows/src/engine/keyman32/appint/aiWin2000Unicode.h index 005d43b8b6..73db7ac907 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,7 +59,7 @@ 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); }; diff --git a/windows/src/engine/keyman32/appint/appint.cpp b/windows/src/engine/keyman32/appint/appint.cpp index 8bd56c6267..d574e9caf0 100644 --- a/windows/src/engine/keyman32/appint/appint.cpp +++ b/windows/src/engine/keyman32/appint/appint.cpp @@ -114,7 +114,7 @@ void AppContext::Get(WCHAR *buf, int bufsize) for (WCHAR *p = this->BufMax(bufsize); *p && bufsize > 0; p++, bufsize--) { *buf = *p; - if(Uni_IsSurrogate1(*p) && bufsize - 2 > 0) { + if(Uni_IsSurrogate1(*p) && bufsize - 2 > 0) { buf++; p++; *buf = *p; bufsize--; diff --git a/windows/src/global/inc/keyman64.h b/windows/src/global/inc/keyman64.h index 327daac01d..40912d7040 100644 --- a/windows/src/global/inc/keyman64.h +++ b/windows/src/global/inc/keyman64.h @@ -51,7 +51,7 @@ 03 Feb 2015 - mcdurdin - I4582 - V9.0 - Most underlying layout code in Keyman32 is now obsolete and needs to be removed 09 Aug 2015 - mcdurdin - I4844 - Tidy up PostDummyKeyEvent calls */ -/***************************************************************************/ // I4006 // I4169 +/***************************************************************************/ // I4006 // I4169 #ifndef _KEYMAN64_H #define _KEYMAN64_H @@ -86,6 +86,7 @@ #define NOT_IMPLEMENTED assert(FALSE) + #define ERROR_APP_MASK 0x20000000L #define ERROR_KEYMAN_ALREADY_INIT (ERROR_APP_MASK | 0x00000001L) #define ERROR_KEYMAN_SHUTTING_DOWN (ERROR_APP_MASK | 0x00000002L) @@ -100,14 +101,14 @@ /* RefreshKeyboards message parameters */ -#define KR_REQUEST_REFRESH 0 -#define KR_PRE_REFRESH 1 -#define KR_REFRESH 2 -#define KR_SETTINGS_CHANGED 3 // Broadcast when Keyman Configuration settings change +#define KR_REQUEST_REFRESH 0 +#define KR_PRE_REFRESH 1 +#define KR_REFRESH 2 +#define KR_SETTINGS_CHANGED 3 // Broadcast when Keyman Configuration settings change /* WM_KEY* message analysis */ -#define KEYMSG_LPARAM_SCAN(lParam) ((BYTE)(((lParam)&0xFF0000) >> 16)) +#define KEYMSG_LPARAM_SCAN(lParam) ((BYTE)(((lParam) & 0xFF0000) >> 16)) #define KEYMSG_FLAG_EXTENDED(lParam) (HIWORD(lParam) & KF_EXTENDED ? 1 : 0) #define KEYMSG_FLAG_DLGMODE(lParam) (HIWORD(lParam) & KF_DLGMODE ? 1 : 0) #define KEYMSG_FLAG_MENUMODE(lParam) (HIWORD(lParam) & KF_MENUMODE ? 1 : 0) @@ -116,7 +117,7 @@ #define KEYMSG_FLAG_UP(lParam) (HIWORD(lParam) & KF_UP ? 1 : 0) // TODO: Deprecate overloading of scancodes and use dwExtraInfo instead -#define SCAN_FLAG_KEYMAN_KEY_EVENT 0xFF +#define SCAN_FLAG_KEYMAN_KEY_EVENT 0xFF #define EXTRAINFO_FLAG_SERIALIZED_USER_KEY_EVENT 0x4B4D0000 @@ -127,13 +128,13 @@ // wParam for wm_keyman // These messages should be posted to a window -#define KM_DISABLEUI 1 -#define KM_ENABLEUI 2 +#define KM_DISABLEUI 1 +#define KM_ENABLEUI 2 // These messages should be sent to a window //#define KM_GETUISTATE 3 -#define KM_FOCUSCHANGED 5 // Never use this flag: internal to Keyman -#define KM_ACTIVECHANGED 6 // Never use this flag: internal to Keyman -#define KM_EXITFLUSH 8 // Disconnects GetMessage hook +#define KM_FOCUSCHANGED 5 // Never use this flag: internal to Keyman +#define KM_ACTIVECHANGED 6 // Never use this flag: internal to Keyman +#define KM_EXITFLUSH 8 // Disconnects GetMessage hook #define KMF_WINDOWCHANGED 1 @@ -201,6 +202,5 @@ typedef struct tagKEYBOARD #include "registry.h" #include "unicode.h" #include "xstring.h" -#include #endif // _KEYMAN64_H diff --git a/windows/src/global/inc/registry.h b/windows/src/global/inc/registry.h index aec4e38de5..02cfce92a3 100644 --- a/windows/src/global/inc/registry.h +++ b/windows/src/global/inc/registry.h @@ -1,18 +1,18 @@ /* Name: registry Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 20 Jun 2006 Modified Date: 28 Mar 2016 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 20 Jun 2006 - mcdurdin - Initial version 01 Aug 2006 - mcdurdin - Add KeymanHotkeys reg 05 Nov 2007 - mcdurdin - I1087 - Add hotkeys to switch languages @@ -44,7 +44,7 @@ #else // this below is same in NT 4 and Win95; others will be different -#define REGSZ_Keyman "software\\keyman\\keyman engine" +#define REGSZ_Keyman "software\\keyman\\keyman engine" #define REGSZ_KeymanDeveloper "software\\keyman\\keyman developer" #define REGSZ_KeymanCU REGSZ_Keyman #define REGSZ_KeymanLM REGSZ_Keyman @@ -83,7 +83,7 @@ //#define REGSZ_SystemNLSLocale "system\\currentcontrolset\\control\\Nls\\Locale" // I4220 - + #define REGSZ_KeymanFile "keyman file" #define REGSZ_KeymanFile_MnemonicOverride "keyman file mnemonic override" // I4169 #define REGSZ_KeymanFile_MnemonicOverride_Deadkey "keyman file mnemonic override deadkey" // I4552 @@ -110,7 +110,7 @@ #define REGSZ_KeyboardHotkeysAreToggle "hotkeys are toggles" #define REGSZ_DeadkeyConversionMode "deadkey conversion mode" // CU // I4552 #define REGSZ_ZapVirtualKeyCode "zap virtual key code" // LM, defaults to 0x0E (_VK_PREFIX_DEFAULT) -/* +/* Debug flags These are all stored in HKCU\Software\Keyman\Debug */ @@ -175,7 +175,7 @@ public: class RegistryFullAccess: public RegistryReadOnly { -protected: +protected: HKEY GetKey(LPCSTR AKey); BOOL IntRecursiveDeleteKey(HKEY hkey); From 09611b600dbc967b74af8302f34d78db81ee2d52 Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 28 Jul 2021 13:42:59 +1000 Subject: [PATCH 12/63] feat(windows): address review comments --- windows/src/engine/keyman32/K32_load.cpp | 38 +++++---- windows/src/engine/keyman32/Keyman32.cpp | 16 ++-- windows/src/engine/keyman32/Keyman32.vcxproj | 2 + .../engine/keyman32/Keyman32.vcxproj.filters | 8 +- windows/src/engine/keyman32/appint/appint.cpp | 19 ++--- windows/src/engine/keyman32/appint/appint.h | 2 +- .../src/engine/keyman32/keyboardoptions.cpp | 24 ++++-- windows/src/engine/keyman32/kmprocess.cpp | 81 ++----------------- 8 files changed, 71 insertions(+), 119 deletions(-) diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index c06541d041..7b23dab130 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -80,8 +80,9 @@ BOOL LoadlpKeyboardCore(int i) { PKEYMAN64THREADDATA _td = ThreadGlobals(); if (!_td) return FALSE; + if (_td->lpKeyboards[i].coreKeyboard) return TRUE; - + if (_td->lpActiveKeyboard == &_td->lpKeyboards[i]) _td->lpActiveKeyboard = NULL; // I822 TSF not working @@ -93,15 +94,15 @@ BOOL LoadlpKeyboardCore(int i) // Convert char* string to a wchar_t* string. size_t convertedChars = 0; - mbstowcs_s(&convertedChars, keyboardPath, charSize, buf, _TRUNCATE); - - if (_td->lpKeyboards[i].coreKeyboard) - { - km_kbp_keyboard_dispose(_td->lpKeyboards[i].coreKeyboard); - _td->lpKeyboards[i].coreKeyboard = NULL; + if (!mbstowcs_s(&convertedChars, keyboardPath, charSize, buf, _TRUNCATE)) { + goto ExitError; + } + if (KM_KBP_STATUS_OK != km_kbp_keyboard_load(keyboardPath, &_td->lpKeyboards[i].coreKeyboard)) { + goto ExitError; } - if (KM_KBP_STATUS_OK != km_kbp_keyboard_load(keyboardPath, &_td->lpKeyboards[i].coreKeyboard)) return FALSE; + delete[] keyboardPath; + // TODO: 5442 handle dlls //LoadDLLs(&_td->lpKeyboards[i]); const km_kbp_option_item test_env_opts[] = @@ -109,19 +110,23 @@ BOOL LoadlpKeyboardCore(int i) KM_KBP_OPTIONS_END }; - if (_td->state.lpActiveKBState) + if (_td->lpKeyboards[i].lpActiveKBState) { - km_kbp_state_dispose(_td->state.lpActiveKBState); - _td->state.lpActiveKBState = NULL; + km_kbp_state_dispose(_td->lpKeyboards[i].lpActiveKBState); + _td->lpKeyboards[i].lpActiveKBState = NULL; } - km_kbp_state_create(_td->lpKeyboards[i].coreKeyboard, test_env_opts, &_td->state.lpActiveKBState); - LoadKeyboardOptionsREGCore(&_td->lpKeyboards[i], _td->state.lpActiveKBState); + if (KM_KBP_STATUS_OK != km_kbp_state_create(_td->lpKeyboards[i].coreKeyboard, test_env_opts, &_td->lpKeyboards[i].lpActiveKBState)) return FALSE; - // free keyboardPath - delete [] keyboardPath; + LoadKeyboardOptionsREGCore(&_td->lpKeyboards[i], _td->lpKeyboards[i].lpActiveKBState); return TRUE; + +ExitError: + if (keyboardPath) { + delete[] keyboardPath; + } + return FALSE; } BOOL LoadlpKeyboard(int i) @@ -134,7 +139,6 @@ BOOL LoadlpKeyboard(int i) 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]; @@ -142,6 +146,8 @@ BOOL LoadlpKeyboard(int i) if(!LoadKeyboard(buf, &_td->lpKeyboards[i].Keyboard)) return FALSE; // I5136 + LoadDLLs(&_td->lpKeyboards[i]); + LoadKeyboardOptions(&_td->lpKeyboards[i]); return TRUE; diff --git a/windows/src/engine/keyman32/Keyman32.cpp b/windows/src/engine/keyman32/Keyman32.cpp index 611f8ba01a..562f049dc2 100644 --- a/windows/src/engine/keyman32/Keyman32.cpp +++ b/windows/src/engine/keyman32/Keyman32.cpp @@ -653,6 +653,14 @@ BOOL ReleaseKeyboardMemory(LPKEYBOARD kbd) return TRUE; } +BOOL ReleaseKeyboardMemoryCore(km_kbp_keyboard* kbd) +{ + if (!kbd) return TRUE; + km_kbp_keyboard_dispose(kbd); + kbd = NULL; + return TRUE; +} + //--------------------------------------------------------------------------------------------------------- // // Selecting Keyman Keyboards @@ -982,12 +990,8 @@ void ReleaseKeyboards(BOOL Lock) if(Lock) UnloadDLLs(&_td->lpKeyboards[i]); FreeKeyboardOptions(&_td->lpKeyboards[i]); ReleaseKeyboardMemory(_td->lpKeyboards[i].Keyboard); - // release core keyboard memory. - if (_td->lpKeyboards[i].coreKeyboard) { - km_kbp_keyboard_dispose(_td->lpKeyboards[i].coreKeyboard); - _td->lpKeyboards[i].coreKeyboard = NULL; - } - + ReleaseKeyboardMemoryCore(_td->lpKeyboards[i].coreKeyboard); + if(_td->lpKeyboards[i].Profiles) delete _td->lpKeyboards[i].Profiles; // I3581 } diff --git a/windows/src/engine/keyman32/Keyman32.vcxproj b/windows/src/engine/keyman32/Keyman32.vcxproj index 894e9d3318..0a292855b8 100644 --- a/windows/src/engine/keyman32/Keyman32.vcxproj +++ b/windows/src/engine/keyman32/Keyman32.vcxproj @@ -295,6 +295,7 @@ %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) + Create Create @@ -371,6 +372,7 @@ + diff --git a/windows/src/engine/keyman32/Keyman32.vcxproj.filters b/windows/src/engine/keyman32/Keyman32.vcxproj.filters index d3fbf2a430..e75258f2c5 100644 --- a/windows/src/engine/keyman32/Keyman32.vcxproj.filters +++ b/windows/src/engine/keyman32/Keyman32.vcxproj.filters @@ -135,6 +135,9 @@ Source Files + + Source Files + @@ -243,8 +246,11 @@ Header Files + + Header Files + - \ No newline at end of file + diff --git a/windows/src/engine/keyman32/appint/appint.cpp b/windows/src/engine/keyman32/appint/appint.cpp index d574e9caf0..96cb35a431 100644 --- a/windows/src/engine/keyman32/appint/appint.cpp +++ b/windows/src/engine/keyman32/appint/appint.cpp @@ -206,28 +206,25 @@ AppIntegration::AppIntegration() BOOL ContextItemsFromAppContext(WCHAR const* buf, km_kbp_context_item** outPtr) { - + assert(buf); km_kbp_context_item* context_items = new km_kbp_context_item[wcslen(buf) + 1]; - // would like to check bad allocation but nothrow not known to this compiler WCHAR const *p = buf; uint8_t contextIndex = 0; while (*p) { if (*p == UC_SENTINEL) { + assert(*(p + 1) == CODE_DEADKEY); // we know the only uc_sentinel code in the context is code_deadkey, which has only 1 parameter: uc_sentinel code_deadkey // setup dead key context item p += 2; context_items[contextIndex++] = km_kbp_context_item{ KM_KBP_CT_MARKER, {0,}, {*p} }; } - else { // setup character need to handle surrogate - if (*p >= 0xD800 && *p <= 0xDBFF && *(p + 1) >= 0xDC00 && *(p + 1) <= 0xDFFF) { - DWORD uni32char = (((*p) - 0xD800) * 0x400 + ((*(p + 1)) - 0xDBFF) + 0x10000); - context_items[contextIndex++] = km_kbp_context_item{ KM_KBP_CT_CHAR, {0,}, {uni32char} }; - p++; - } - else { - // handle as a single + else if (*p >= 0xD800 && *p <= 0xDBFF && *(p + 1) >= 0xDC00 && *(p + 1) <= 0xDFFF) { + // handle surrogate + context_items[contextIndex++] = km_kbp_context_item{ KM_KBP_CT_CHAR, {0,}, {(char32_t)Uni_SurrogateToUTF32(*p, *(p + 1))} }; + p++; + } + else { context_items[contextIndex++] = km_kbp_context_item{ KM_KBP_CT_CHAR, {0,}, {*p} }; - } } p++; } diff --git a/windows/src/engine/keyman32/appint/appint.h b/windows/src/engine/keyman32/appint/appint.h index 4e258a8bde..3ce82edf2c 100644 --- a/windows/src/engine/keyman32/appint/appint.h +++ b/windows/src/engine/keyman32/appint/appint.h @@ -209,7 +209,7 @@ public: }; /** - * Convert AppContext array into a array of core context items. + * Convert AppContext array into an array of core context items. * Caller is responsible for freeing the memory. * * @param buf appcontext character array diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index 21e029c438..0482456ccb 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -34,7 +34,8 @@ void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp) { if (Globals::get_CoreIntegration()) { - return; // should never be called if using core processor + assert(TRUE); // should never be called if using core processor + return; } // Called when another thread changes keyboard options and we are sharing keyboard settings assert(kp != NULL); @@ -49,7 +50,8 @@ void FreeKeyboardOptions(LPINTKEYBOARDINFO kp) { if (Globals::get_CoreIntegration()) { - return; // should never be called if using core processor + assert(TRUE); // should never be called if using core processor + return; } // This is a cleanup routine; we don't want to precondition all calls to it // so we do not assert @@ -70,7 +72,8 @@ void SetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSet, int nStoreToRead) { if (Globals::get_CoreIntegration()) { - return; // should never be called if using core processor + assert(TRUE); // should never be called if using core processor + return; } assert(kp != NULL); @@ -100,7 +103,8 @@ void ResetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToReset) { if (Globals::get_CoreIntegration()) { - return; // should never be called if using core processor + assert(TRUE); // should never be called if using core processor + return; } assert(kp != NULL); assert(kp->Keyboard != NULL); @@ -140,7 +144,8 @@ void SaveKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSave) { if (Globals::get_CoreIntegration()) { - return; // should never be called if using core processor + assert(TRUE); // should never be called if using core processor + return; } IntSaveKeyboardOption(REGSZ_KeyboardOptions, kp, nStoreToSave); } @@ -154,6 +159,9 @@ void IntSaveKeyboardOptionREGCore(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR k { assert(REGKey != NULL); assert(kp != NULL); + assert(key); + assert(value); + RegistryFullAccess r(HKEY_CURRENT_USER); if (r.OpenKey(REGSZ_KeymanActiveKeyboards, TRUE) && r.OpenKey(kp->Name, TRUE) && r.OpenKey(REGKey, TRUE)) { @@ -239,9 +247,9 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* WCHAR buf[256]; int n = 0; // Get the list of default options to determine size of list - const km_kbp_keyboard_attrs* keyboadAttrs; - km_kbp_keyboard_get_attrs(kp->coreKeyboard, &keyboadAttrs); - size_t listSize = km_kbp_options_list_size(keyboadAttrs->default_options); + const km_kbp_keyboard_attrs* keyboardAttrs; + km_kbp_keyboard_get_attrs(kp->coreKeyboard, &keyboardAttrs); + size_t listSize = km_kbp_options_list_size(keyboardAttrs->default_options); km_kbp_option_item* keyboardOpts = new km_kbp_option_item[listSize+1]; while (r.GetValueNames(buf, sizeof(buf) / sizeof(buf[0]), n)) diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index 4c34b16bee..7f520e14c0 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -89,7 +89,6 @@ char *getcontext_debug() { return Debug_UnicodeString(_td->app->ContextBufMax(128)); } - /* * BOOL ProcessHook(); * @@ -143,88 +142,18 @@ BOOL ProcessHook() } if (isUsingCoreProcessor) { - PWSTR buf; - buf = _td->app->ContextBufMax(MAXCONTEXT); + PWSTR contextBuf = _td->app->ContextBufMax(MAXCONTEXT); km_kbp_context_item *citems = nullptr; - ContextItemsFromAppContext(buf, &citems); - km_kbp_context_set(km_kbp_state_context(_td->state.lpActiveKBState), citems); + ContextItemsFromAppContext(contextBuf, &citems); + km_kbp_context_set(km_kbp_state_context(_td->lpActiveKeyboard->lpActiveKBState), citems); km_kbp_context_items_dispose(citems); - km_kbp_process_event(_td->state.lpActiveKBState, _td->state.vkey, static_cast(Globals::get_ShiftState())); + if (KM_KBP_STATUS_OK != km_kbp_process_event(_td->lpActiveKeyboard->lpActiveKBState, _td->state.vkey, static_cast(Globals::get_ShiftState()))) return FALSE; + ProcessActions(&fOutputKeystroke); } else { ProcessGroup(gp); // TODO: 5442 remove } - - // Process the action items from the core. This actions will modify the windows context (AppContext). - // Therefore it is not required to copy the context from the core to the windows context. - for (auto act = km_kbp_state_action_items(_td->state.lpActiveKBState, nullptr); act->type != KM_KBP_IT_END; act++) { - - switch (act->type) - { - case KM_KBP_IT_END: - assert(false); - break; - case KM_KBP_IT_ALERT: - _td->app->QueueAction(QIT_BELL, 0); - break; - case KM_KBP_IT_CHAR: - if (Uni_IsSMP(act->character)) { - _td->app->QueueAction(QIT_CHAR, (Uni_UTF32ToSurrogate1(act->character))); - _td->app->QueueAction(QIT_CHAR, (Uni_UTF32ToSurrogate2(act->character))); - } - else { - _td->app->QueueAction(QIT_CHAR, act->character); - } - break; - case KM_KBP_IT_MARKER: - _td->app->QueueAction(QIT_DEADKEY, (DWORD)act->marker); - break; - case KM_KBP_IT_BACK: - _td->app->QueueAction(QIT_BACK,BK_DEADKEY); - break; - case KM_KBP_IT_PERSIST_OPT: - if (act->option != NULL) - { - // Allocate for 1 option plus 1 pad struct of 0's for KM_KBP_IT_END - km_kbp_option_item* keyboardOpts = new km_kbp_option_item[2]; - memmove(&(keyboardOpts[0]), act->option, sizeof(km_kbp_option_item)); - km_kbp_status eventStatus = km_kbp_state_options_update(_td->state.lpActiveKBState, keyboardOpts); - if (eventStatus != KM_KBP_STATUS_OK) - { - // log warning "problem saving option for km_kbp_keyboard"); - SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessHook: Problems saving optionf for keybooard [%s].", _td->lpActiveKeyboard->Name); - } - delete[] keyboardOpts; - - // Put the keyboard option into Windows Registry - if (act->option != NULL && act->option->key != NULL && - act->option->value != NULL) - { - // log"Saving keyboard option to registry"); - SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessHook: Saving option to registry for keybooard [%s].", _td->lpActiveKeyboard->Name); - LPWSTR value = new WCHAR[sizeof(act->option->value) + 1]; - wcscpy_s(value, sizeof(act->option->value) + 1, reinterpret_cast(act->option->value)); - SaveKeyboardOptionREGCore(_td->lpActiveKeyboard, reinterpret_cast(act->option->key), value); - } - } - break; - case KM_KBP_IT_INVALIDATE_CONTEXT: - // Reset context - _td->app->ResetContext(); - break; - case KM_KBP_IT_EMIT_KEYSTROKE: - fOutputKeystroke = TRUE; - break; - - default: - assert(false); // NOT SUPPORTED - break; - - } - - } - if (fOutputKeystroke && !_td->app->IsQueueEmpty()) { // // #2759: The keyboard has requested that the default output From 22a0fd53a06be4422797e7f1b8c33163db66b2a6 Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 28 Jul 2021 13:47:47 +1000 Subject: [PATCH 13/63] feat(windows): add km process actions to win engine --- .../src/engine/keyman32/kmprocessactions.cpp | 133 ++++++++++++++++++ .../src/engine/keyman32/kmprocessactions.h | 13 ++ 2 files changed, 146 insertions(+) create mode 100644 windows/src/engine/keyman32/kmprocessactions.cpp create mode 100644 windows/src/engine/keyman32/kmprocessactions.h diff --git a/windows/src/engine/keyman32/kmprocessactions.cpp b/windows/src/engine/keyman32/kmprocessactions.cpp new file mode 100644 index 0000000000..3200973531 --- /dev/null +++ b/windows/src/engine/keyman32/kmprocessactions.cpp @@ -0,0 +1,133 @@ +/* + * Keyman is copyright (C) SIL International. MIT License. + * + * Description: Used for apply core processor actions to + * Keyman for Windows engine. + */ +#include "pch.h" + +static BOOL processUnicodeChar(AITIP* app, const km_kbp_action_item* actionItem) { + if (Uni_IsSMP(actionItem->character)) { + app->QueueAction(QIT_CHAR, (Uni_UTF32ToSurrogate1(actionItem->character))); + app->QueueAction(QIT_CHAR, (Uni_UTF32ToSurrogate2(actionItem->character))); + } + else { + app->QueueAction(QIT_CHAR, actionItem->character); + } + return TRUE; +} + +static BOOL processMarker(AITIP* app, const km_kbp_action_item* actionItem) { + app->QueueAction(QIT_DEADKEY, (DWORD)actionItem->marker); + return TRUE; +} + +static BOOL processAlert(AITIP* app) { + app->QueueAction(QIT_BELL, 0); + return TRUE; +} + +static BOOL processBack(AITIP* app) { + app->QueueAction(QIT_BACK, BK_DEADKEY); + return TRUE; +} + +static BOOL processPersistOpt( + const km_kbp_action_item* actionItem, + km_kbp_state* keyboardState, + LPINTKEYBOARDINFO activeKeyboard +) { + if (actionItem->option != NULL) + { + // Allocate for 1 option plus 1 pad struct of 0's for KM_KBP_IT_END + km_kbp_option_item keyboardOpts[2] = { 0 }; + + km_kbp_cp* cp = new km_kbp_cp[sizeof(actionItem->option->key) + 1]; + wcscpy_s(reinterpret_cast(cp), sizeof(actionItem->option->key) + 1, reinterpret_cast(actionItem->option->key)); + keyboardOpts[0].key = cp; + + cp = new km_kbp_cp[sizeof(actionItem->option->value) + 1]; + wcscpy_s(reinterpret_cast(cp), sizeof(actionItem->option->value) + 1, reinterpret_cast(actionItem->option->value)); + keyboardOpts[0].value = cp; + keyboardOpts[1] = KM_KBP_OPTIONS_END; + km_kbp_status eventStatus = km_kbp_state_options_update(keyboardState, keyboardOpts); + if (eventStatus != KM_KBP_STATUS_OK) + { + // log warning "problem saving option for km_kbp_keyboard"); + SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessHook: Problems saving optionf for keybooard [%s].", activeKeyboard->Name); + } + + for (int i = 0; i < 2; i++) { + delete[] keyboardOpts[i].key; + delete[] keyboardOpts[i].value; + } + // Put the keyboard option into Windows Registry + if (actionItem->option != NULL && actionItem->option->key != NULL && + actionItem->option->value != NULL) + { + // log"Saving keyboard option to registry"); + SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessHook: Saving option to registry for keybooard [%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); + } + } + return TRUE; +} + +static BOOL processInvalidateContext( + AITIP* app, + km_kbp_state* keyboardState +) { + km_kbp_context_clear(km_kbp_state_context(keyboardState)); + app->ResetContext(); + return TRUE; +} + + // TODO: 5011 make this function a new file +BOOL ProcessActions(BOOL* emitKeyStroke) +{ + PKEYMAN64THREADDATA _td = ThreadGlobals(); + if (!_td) return FALSE; + + // Process the action items from the core. This actions will modify the windows context (AppContext). + // Therefore it is not required to copy the context from the core to the windows context. + + for (auto act = km_kbp_state_action_items(_td->lpActiveKeyboard->lpActiveKBState, nullptr); act->type != KM_KBP_IT_END; act++) { + BOOL continueProcessingActions = TRUE; + switch (act->type) + { + case KM_KBP_IT_CHAR: + continueProcessingActions = processUnicodeChar(_td->app, act); + break; + case KM_KBP_IT_MARKER: + continueProcessingActions = processMarker(_td->app, act); + break; + case KM_KBP_IT_ALERT: + continueProcessingActions = processAlert(_td->app); + break; + case KM_KBP_IT_BACK: + continueProcessingActions = processBack(_td->app); + break; + case KM_KBP_IT_PERSIST_OPT: + continueProcessingActions = processPersistOpt(act, _td->lpActiveKeyboard->lpActiveKBState, _td->lpActiveKeyboard); + break; + case KM_KBP_IT_EMIT_KEYSTROKE: + *emitKeyStroke = TRUE; + continueProcessingActions = TRUE; + break; + case KM_KBP_IT_INVALIDATE_CONTEXT: + continueProcessingActions = processInvalidateContext(_td->app, _td->lpActiveKeyboard->lpActiveKBState); + break; + case KM_KBP_IT_END: + assert(false); + break; + default: + assert(false); // NOT SUPPORTED + break; + } + if (!continueProcessingActions) + return FALSE; + } + return TRUE; +} diff --git a/windows/src/engine/keyman32/kmprocessactions.h b/windows/src/engine/keyman32/kmprocessactions.h new file mode 100644 index 0000000000..1bc0ba1d99 --- /dev/null +++ b/windows/src/engine/keyman32/kmprocessactions.h @@ -0,0 +1,13 @@ + +/* + * Keyman is copyright (C) SIL International. MIT License. + * + * Description: Used for apply core processor actions to + * Keyman for Windows engine. + */ +#ifndef _KMPROCESSACTIONS_H +#define _KMPROCESSACTIONS_h + +BOOL ProcessActions(BOOL* emitKeyStroke); + +#endif From ba20e7eb37776c91ccc4b2388482111919de9a95 Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 28 Jul 2021 14:12:50 +1000 Subject: [PATCH 14/63] feat(windows): revert kmx files from git ignore --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index ffe48fa739..1566ecf622 100644 --- a/.gitignore +++ b/.gitignore @@ -162,8 +162,7 @@ resources/environment.sh # Copy of the master VERSION.md used for Linux packaging /common/core/desktop/VERSION.md -# Test common core keyboard files -common/core/desktop/tests/unit/kmx/*.kmx + **/node_modules/ lerna-debug.log From 40b96f2a827941be111f0faf8e822292a0a6487b Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 2 Aug 2021 15:07:22 +1000 Subject: [PATCH 15/63] feat(windows): update kmprocess_event call with new arg --- windows/src/engine/keyman32/kmprocess.cpp | 3 ++- windows/src/global/inc/keymanengine.h | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index 7f520e14c0..0035d29e92 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -147,7 +147,8 @@ BOOL ProcessHook() ContextItemsFromAppContext(contextBuf, &citems); km_kbp_context_set(km_kbp_state_context(_td->lpActiveKeyboard->lpActiveKBState), citems); km_kbp_context_items_dispose(citems); - if (KM_KBP_STATUS_OK != km_kbp_process_event(_td->lpActiveKeyboard->lpActiveKBState, _td->state.vkey, static_cast(Globals::get_ShiftState()))) return FALSE; + //_td->state.vkey == VK_DOWN + if (KM_KBP_STATUS_OK != km_kbp_process_event(_td->lpActiveKeyboard->lpActiveKBState, _td->state.vkey, static_cast(Globals::get_ShiftState()), 1)) return FALSE; ProcessActions(&fOutputKeystroke); } else { diff --git a/windows/src/global/inc/keymanengine.h b/windows/src/global/inc/keymanengine.h index 9b45029e00..ce0d2a0afc 100644 --- a/windows/src/global/inc/keymanengine.h +++ b/windows/src/global/inc/keymanengine.h @@ -77,6 +77,9 @@ typedef struct tagINTKEYBOARDINFO LPINTKEYBOARDOPTIONS KeyboardOptions; int nProfiles; LPINTKEYBOARDPROFILE Profiles; + km_kbp_keyboard* coreKeyboard; + km_kbp_option_item* coreKeyboardOptions; + km_kbp_state* lpActiveKBState; } INTKEYBOARDINFO, * LPINTKEYBOARDINFO; typedef struct tagINI @@ -89,14 +92,17 @@ typedef struct tagINI typedef struct tagKMSTATE { BOOL NoMatches; + MSG msg; + // TODO: 5442 will remove these once windows core is deprecated BOOL StopOutput; int LoopTimes; - MSG msg; - WORD vkey; // I934 - WCHAR charCode; // I4582 - BOOL windowunicode; // I4287 + // TODO: 5442 + WORD vkey; // I934 + WCHAR charCode; // I4582 + BOOL windowunicode; // I4287 LPKEYBOARD lpkb; - LPGROUP startgroup; + km_kbp_keyboard* lpCoreKb; // future use with IMDLL + LPGROUP startgroup; // TODO: 5442 will remove this once windows core is deprecated } KMSTATE; // I3616 @@ -232,6 +238,7 @@ void keybd_shift(LPINPUT pInputs, int* n, BOOL isReset, LPBYTE const kbd); #include "addins.h" #include "keymancontrol.h" #include "keyboardoptions.h" +#include "kmprocessactions.h" #include "syskbd.h" #include "vkscancodes.h" From c0826e9930694caf2f90664f4b0989e6d1d18b7b Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 4 Aug 2021 09:36:42 +1000 Subject: [PATCH 16/63] feat(windows): use static library for keyboard core --- common/core/desktop/build.bat | 9 +-------- common/core/desktop/meson.build | 3 ++- common/core/desktop/src/kmx/kmx_file.cpp | 2 +- windows/src/engine/keyman32/Keyman32.vcxproj | 2 +- windows/src/engine/keyman32/keyman-engine.vcxproj | 2 ++ .../src/engine/keyman32/keyman-engine.vcxproj.filters | 6 ++++++ windows/src/engine/keyman32/kmprocess.cpp | 4 ++++ .../tests/keyman32-tests/keyman32-tests.vcxproj | 4 ++-- windows/src/engine/keyman64/keyman64.vcxproj | 2 ++ windows/src/engine/keyman64/keyman64.vcxproj.filters | 2 ++ windows/src/global/inc/keyman64.h | 1 - windows/src/global/inc/keymanengine.h | 10 ++++++++++ 12 files changed, 33 insertions(+), 14 deletions(-) diff --git a/common/core/desktop/build.bat b/common/core/desktop/build.bat index fdcc18a7e6..856db992da 100644 --- a/common/core/desktop/build.bat +++ b/common/core/desktop/build.bat @@ -70,14 +70,7 @@ cd %KEYMAN_ROOT%\common\core\desktop set BUILDTYPE=%2 -if "%3" == "--static" ( - set STATIC_LIBRARY=--default-library static - shift -) else ( - set STATIC_LIBRARY= -) - -echo "Is static build = !STATIC_LIBRARY! (%3)" +set STATIC_LIBRARY=--default-library both if "%3" == "build" ( echo === Calling meson build for Windows !ARCH! !BUILDTYPE! === diff --git a/common/core/desktop/meson.build b/common/core/desktop/meson.build index aec0bb12f2..a2bea70b7a 100644 --- a/common/core/desktop/meson.build +++ b/common/core/desktop/meson.build @@ -9,7 +9,8 @@ project('keyboardprocessor', 'cpp', 'c', version: run_command(find_program('getversion.bat', 'getversion.sh')).stdout().strip(), license: 'MIT', default_options : ['buildtype=release', - 'cpp_std=c++14']) + 'cpp_std=c++14', + 'b_vscrt=mt']) message('meson.project_version(): ' + meson.project_version() + '\n') compiler = meson.get_compiler('cpp') diff --git a/common/core/desktop/src/kmx/kmx_file.cpp b/common/core/desktop/src/kmx/kmx_file.cpp index 1a6bdf64f3..dfcac5f890 100644 --- a/common/core/desktop/src/kmx/kmx_file.cpp +++ b/common/core/desktop/src/kmx/kmx_file.cpp @@ -59,7 +59,7 @@ const unsigned long CRCTable[256] = { * and returns the updated value. */ -unsigned long CalculateBufferCRC(unsigned long count, KMX_BYTE *p) +static unsigned long CalculateBufferCRC(unsigned long count, KMX_BYTE *p) { unsigned long temp1; unsigned long temp2; diff --git a/windows/src/engine/keyman32/Keyman32.vcxproj b/windows/src/engine/keyman32/Keyman32.vcxproj index 0a292855b8..997526067c 100644 --- a/windows/src/engine/keyman32/Keyman32.vcxproj +++ b/windows/src/engine/keyman32/Keyman32.vcxproj @@ -151,7 +151,7 @@ /verbose:lib /section:.SHARDATA,rws %(AdditionalOptions) - kmnkbp0.lib;keyman_keyboard_processor_native.lib;psapi.lib;rpcrt4.lib;version.lib;setupapi.lib;iphlpapi.lib;imm32.lib;crypt32.lib;wintrust.lib;imagehlp.lib;ws2_32.lib;%(AdditionalDependencies) + libkmnkbp0.a;keyman_keyboard_processor_native.lib;psapi.lib;rpcrt4.lib;version.lib;setupapi.lib;iphlpapi.lib;imm32.lib;crypt32.lib;wintrust.lib;imagehlp.lib;ws2_32.lib;%(AdditionalDependencies) true keyman32.def true diff --git a/windows/src/engine/keyman32/keyman-engine.vcxproj b/windows/src/engine/keyman32/keyman-engine.vcxproj index fb987da126..49c69d7907 100644 --- a/windows/src/engine/keyman32/keyman-engine.vcxproj +++ b/windows/src/engine/keyman32/keyman-engine.vcxproj @@ -307,6 +307,7 @@ %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) + Create Create @@ -383,6 +384,7 @@ + diff --git a/windows/src/engine/keyman32/keyman-engine.vcxproj.filters b/windows/src/engine/keyman32/keyman-engine.vcxproj.filters index d3fbf2a430..eedeaa07be 100644 --- a/windows/src/engine/keyman32/keyman-engine.vcxproj.filters +++ b/windows/src/engine/keyman32/keyman-engine.vcxproj.filters @@ -135,6 +135,9 @@ Source Files + + Source Files + @@ -243,6 +246,9 @@ Header Files + + Header Files + diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index 0035d29e92..80d282edf2 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -142,6 +142,8 @@ BOOL ProcessHook() } if (isUsingCoreProcessor) { + // TODO: 5011 remove debug message + SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessActions: "); PWSTR contextBuf = _td->app->ContextBufMax(MAXCONTEXT); km_kbp_context_item *citems = nullptr; ContextItemsFromAppContext(contextBuf, &citems); @@ -152,6 +154,8 @@ BOOL ProcessHook() ProcessActions(&fOutputKeystroke); } else { + // TODO: 5011 remove debug message + SendDebugMessageFormat(0, sdmGlobal, 0,"ProcessGroup: "); ProcessGroup(gp); // TODO: 5442 remove } diff --git a/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj b/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj index 0f5a1e193f..2690a68801 100644 --- a/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj +++ b/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj @@ -36,7 +36,7 @@ $(ProjectDir)..\..\..\..\..\..\common\core\desktop\include;$(ProjectDir)..\..\..\..\..\..\common\core\desktop\build\x86\$(Configuration)\include;$(ProjectDir)..\..\..\..\global\inc;$(ProjectDir)..\..;$(IncludePath) $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ - $(ProjectDir)..\..\..\..\..\..\common\core\desktop\build\x86\$(Configuration)\src;$(LibraryPath) + $(ProjectDir)..\..\..\..\..\..\common\core\desktop\build\x86\$(Configuration)\src;$(ProjectDir)..\..\..\..\..\..\common\core\desktop\build\rust\x86\$(Configuration);$(LibraryPath) $(ProjectDir)..\..\..\..\global\inc;$(ProjectDir)..\..;$(IncludePath) @@ -95,7 +95,7 @@ true Console - version.lib;psapi.lib;imm32.lib;kmnkbp0.lib;%(AdditionalDependencies) + version.lib;psapi.lib;imm32.lib;libkmnkbp0.a;keyman_keyboard_processor_native.lib;%(AdditionalDependencies) diff --git a/windows/src/engine/keyman64/keyman64.vcxproj b/windows/src/engine/keyman64/keyman64.vcxproj index 8cbbcab9ad..04714bc1e0 100644 --- a/windows/src/engine/keyman64/keyman64.vcxproj +++ b/windows/src/engine/keyman64/keyman64.vcxproj @@ -243,6 +243,7 @@ $(IntDir)%(Filename)1.xdc + Create Create @@ -307,6 +308,7 @@ + diff --git a/windows/src/engine/keyman64/keyman64.vcxproj.filters b/windows/src/engine/keyman64/keyman64.vcxproj.filters index 6f353e6489..3fa862afc9 100644 --- a/windows/src/engine/keyman64/keyman64.vcxproj.filters +++ b/windows/src/engine/keyman64/keyman64.vcxproj.filters @@ -37,6 +37,7 @@ + @@ -84,6 +85,7 @@ + diff --git a/windows/src/global/inc/keyman64.h b/windows/src/global/inc/keyman64.h index 40912d7040..ec13946018 100644 --- a/windows/src/global/inc/keyman64.h +++ b/windows/src/global/inc/keyman64.h @@ -76,7 +76,6 @@ #include #include #include "compiler.h" -#include #ifdef _WIN64 #define LIBRARY_NAME "KEYMAN64" diff --git a/windows/src/global/inc/keymanengine.h b/windows/src/global/inc/keymanengine.h index ce0d2a0afc..948c2086ab 100644 --- a/windows/src/global/inc/keymanengine.h +++ b/windows/src/global/inc/keymanengine.h @@ -18,6 +18,15 @@ #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1 #endif +// For keyboardprocessor_bits.h +#ifndef KMN_KBP_STATIC +#define KMN_KBP_STATIC +#endif +// For keyboardprocessor_bits.h +#ifndef _WIN32 +#define _WIN32 1 +#endif + #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0600 #endif @@ -30,6 +39,7 @@ #include #include #include "compiler.h" +#include /***************************************************************************/ From a901f349b014f77384998aa29599be6f50d2bb34 Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 4 Aug 2021 10:32:05 +1000 Subject: [PATCH 17/63] feat(windows): fix vs project settings --- windows/src/engine/keyman32/kmprocessactions.cpp | 6 +++--- .../keyman32/tests/keyman32-tests/keyman32-tests.vcxproj | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/windows/src/engine/keyman32/kmprocessactions.cpp b/windows/src/engine/keyman32/kmprocessactions.cpp index 3200973531..2123626b8f 100644 --- a/windows/src/engine/keyman32/kmprocessactions.cpp +++ b/windows/src/engine/keyman32/kmprocessactions.cpp @@ -4,7 +4,7 @@ * Description: Used for apply core processor actions to * Keyman for Windows engine. */ -#include "pch.h" +#include "pch.h" static BOOL processUnicodeChar(AITIP* app, const km_kbp_action_item* actionItem) { if (Uni_IsSMP(actionItem->character)) { @@ -54,9 +54,9 @@ static BOOL processPersistOpt( if (eventStatus != KM_KBP_STATUS_OK) { // log warning "problem saving option for km_kbp_keyboard"); - SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessHook: Problems saving optionf for keybooard [%s].", activeKeyboard->Name); + SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessHook: Error %d saving option for keyboard [%s].", eventStatus, activeKeyboard->Name); } - + for (int i = 0; i < 2; i++) { delete[] keyboardOpts[i].key; delete[] keyboardOpts[i].value; diff --git a/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj b/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj index 2690a68801..1349356c66 100644 --- a/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj +++ b/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj @@ -34,8 +34,8 @@ $(ProjectDir)..\..\..\..\..\..\common\core\desktop\include;$(ProjectDir)..\..\..\..\..\..\common\core\desktop\build\x86\$(Configuration)\include;$(ProjectDir)..\..\..\..\global\inc;$(ProjectDir)..\..;$(IncludePath) - $(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ + $(ProjectDir)bin\$(Platform)\$(Configuration)\ + $(ProjectDir)obj\$(Platform)\$(Configuration)\ $(ProjectDir)..\..\..\..\..\..\common\core\desktop\build\x86\$(Configuration)\src;$(ProjectDir)..\..\..\..\..\..\common\core\desktop\build\rust\x86\$(Configuration);$(LibraryPath) @@ -151,4 +151,4 @@ - \ No newline at end of file + From ae9ba52ab95855a54e25b168a84f0b3e445a322e Mon Sep 17 00:00:00 2001 From: Ross Date: Tue, 10 Aug 2021 17:43:55 +1000 Subject: [PATCH 18/63] fix(windows): meson build for static lib --- common/core/desktop/meson.build | 2 +- windows/src/engine/keyman32/K32_load.cpp | 33 +++++++++++++------ windows/src/engine/keyman32/Keyman32.vcxproj | 2 +- .../src/engine/keyman32/keyboardoptions.cpp | 17 +++++----- .../keyman32-tests/keyman32-tests.vcxproj | 5 +-- windows/src/engine/keyman64/keyman64.vcxproj | 11 ++++--- 6 files changed, 41 insertions(+), 29 deletions(-) diff --git a/common/core/desktop/meson.build b/common/core/desktop/meson.build index a2bea70b7a..dea4c55703 100644 --- a/common/core/desktop/meson.build +++ b/common/core/desktop/meson.build @@ -10,7 +10,7 @@ project('keyboardprocessor', 'cpp', 'c', license: 'MIT', default_options : ['buildtype=release', 'cpp_std=c++14', - 'b_vscrt=mt']) + 'b_vscrt=static_from_buildtype']) message('meson.project_version(): ' + meson.project_version() + '\n') compiler = meson.get_compiler('cpp') diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index 7b23dab130..bccada4231 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -78,6 +78,7 @@ BOOL GetKeyboardFileName(LPSTR kbname, LPSTR buf, int nbuf) BOOL LoadlpKeyboardCore(int i) { + SendDebugMessageFormat(0, sdmAIDefault, 0, "LoadlpKeyboardCore: Enter ---"); PKEYMAN64THREADDATA _td = ThreadGlobals(); if (!_td) return FALSE; @@ -94,11 +95,17 @@ BOOL LoadlpKeyboardCore(int i) // Convert char* string to a wchar_t* string. size_t convertedChars = 0; - if (!mbstowcs_s(&convertedChars, keyboardPath, charSize, buf, _TRUNCATE)) { - goto ExitError; + if (mbstowcs_s(&convertedChars, keyboardPath, charSize, buf, _TRUNCATE)) { + //goto ExitError; + delete[] keyboardPath; + return FALSE; } - if (KM_KBP_STATUS_OK != km_kbp_keyboard_load(keyboardPath, &_td->lpKeyboards[i].coreKeyboard)) { - goto ExitError; + km_kbp_status_codes err_code = (km_kbp_status_codes)km_kbp_keyboard_load(keyboardPath, &_td->lpKeyboards[i].coreKeyboard); + //if (KM_KBP_STATUS_OK != km_kbp_keyboard_load(keyboardPath, &_td->lpKeyboards[i].coreKeyboard)) { + if (err_code != KM_KBP_STATUS_OK) { + //goto ExitError; + delete[] keyboardPath; + return FALSE; } delete[] keyboardPath; @@ -116,17 +123,23 @@ BOOL LoadlpKeyboardCore(int i) _td->lpKeyboards[i].lpActiveKBState = NULL; } - if (KM_KBP_STATUS_OK != km_kbp_state_create(_td->lpKeyboards[i].coreKeyboard, test_env_opts, &_td->lpKeyboards[i].lpActiveKBState)) return FALSE; + // if (KM_KBP_STATUS_OK != km_kbp_state_create(_td->lpKeyboards[i].coreKeyboard, test_env_opts, &_td->lpKeyboards[i].lpActiveKBState)) return FALSE; + err_code = (km_kbp_status_codes)km_kbp_state_create(_td->lpKeyboards[i].coreKeyboard, test_env_opts, &_td->lpKeyboards[i].lpActiveKBState); + if (err_code != KM_KBP_STATUS_OK) { + return FALSE; + } + LoadKeyboardOptionsREGCore(&_td->lpKeyboards[i], _td->lpKeyboards[i].lpActiveKBState); return TRUE; + //return FALSE; -ExitError: - if (keyboardPath) { - delete[] keyboardPath; - } - return FALSE; +//ExitError: +// if (keyboardPath) { +// delete[] keyboardPath; +// } +// return FALSE; } BOOL LoadlpKeyboard(int i) diff --git a/windows/src/engine/keyman32/Keyman32.vcxproj b/windows/src/engine/keyman32/Keyman32.vcxproj index 997526067c..ead16e3609 100644 --- a/windows/src/engine/keyman32/Keyman32.vcxproj +++ b/windows/src/engine/keyman32/Keyman32.vcxproj @@ -95,7 +95,7 @@ /verbose:lib /section:.SHARDATA,rws %(AdditionalOptions) - kmnkbp0.lib;keyman_keyboard_processor_native.lib;psapi.lib;rpcrt4.lib;version.lib;setupapi.lib;iphlpapi.lib;imm32.lib;crypt32.lib;wintrust.lib;imagehlp.lib;ws2_32.lib;%(AdditionalDependencies) + libkmnkbp0.a;keyman_keyboard_processor_native.lib;psapi.lib;rpcrt4.lib;version.lib;setupapi.lib;iphlpapi.lib;imm32.lib;crypt32.lib;wintrust.lib;imagehlp.lib;ws2_32.lib;%(AdditionalDependencies) true keyman32.def true diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index 0482456ccb..7b2d328b92 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -18,7 +18,7 @@ 28 Nov 2012 - mcdurdin - I3594 - V9.0 - Remove old SelectKeyboard code and related messages */ #include "pch.h" -#include "registry.h" +//#include "registry.h" void IntSaveKeyboardOption(LPCSTR key, LPINTKEYBOARDINFO kp, int nStoreToSave); BOOL IntLoadKeyboardOptions(LPCSTR key, LPINTKEYBOARDINFO kp); @@ -34,7 +34,7 @@ void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp) { if (Globals::get_CoreIntegration()) { - assert(TRUE); // should never be called if using core processor + SendDebugMessageFormat(0, sdmAIDefault, 0, "LoadSharedKeyboardOptions: Error called in core integration mode"); return; } // Called when another thread changes keyboard options and we are sharing keyboard settings @@ -48,11 +48,11 @@ void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp) void FreeKeyboardOptions(LPINTKEYBOARDINFO kp) { - if (Globals::get_CoreIntegration()) + /*if (Globals::get_CoreIntegration()) { - assert(TRUE); // should never be called if using core processor + SendDebugMessageFormat(0, sdmAIDefault, 0, "FreeKeyboardOptions: Error called in core integration mode"); return; - } + }*/ // 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) @@ -72,7 +72,7 @@ void SetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSet, int nStoreToRead) { if (Globals::get_CoreIntegration()) { - assert(TRUE); // should never be called if using core processor + SendDebugMessageFormat(0, sdmAIDefault, 0, "SetKeyboardOption: Error called in core integration mode"); return; } @@ -103,7 +103,7 @@ void ResetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToReset) { if (Globals::get_CoreIntegration()) { - assert(TRUE); // should never be called if using core processor + SendDebugMessageFormat(0, sdmAIDefault, 0, "ResetKeyboardOption: Error called in core integration mode"); return; } assert(kp != NULL); @@ -144,7 +144,7 @@ void SaveKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSave) { if (Globals::get_CoreIntegration()) { - assert(TRUE); // should never be called if using core processor + SendDebugMessageFormat(0, sdmAIDefault, 0, "SaveKeyboardOption: Error called in core integration mode"); return; } IntSaveKeyboardOption(REGSZ_KeyboardOptions, kp, nStoreToSave); @@ -231,6 +231,7 @@ void IntSaveKeyboardOption(LPCSTR key, LPINTKEYBOARDINFO kp, int nStoreToSave) void LoadKeyboardOptionsREGCore(LPINTKEYBOARDINFO kp, km_kbp_state* const state) { + SendDebugMessageFormat(0, sdmAIDefault, 0, "LoadKeyboardOptionsREGCore: Enter"); IntLoadKeyboardOptionsCore(REGSZ_KeyboardOptions, kp, state); } diff --git a/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj b/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj index 1349356c66..dc8c6faa78 100644 --- a/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj +++ b/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj @@ -72,9 +72,6 @@ {a7069186-5ae7-4504-8926-861b7a34ba9e} - - {bd5564fb-35a5-4a3c-b96a-4a6578e2b593} - @@ -151,4 +148,4 @@ - + \ No newline at end of file diff --git a/windows/src/engine/keyman64/keyman64.vcxproj b/windows/src/engine/keyman64/keyman64.vcxproj index 04714bc1e0..e73e229544 100644 --- a/windows/src/engine/keyman64/keyman64.vcxproj +++ b/windows/src/engine/keyman64/keyman64.vcxproj @@ -45,7 +45,7 @@ false $(ProjectDir)bin\$(Platform)\$(Configuration)\ $(ProjectDir)obj\$(Platform)\$(Configuration)\ - true + false AllRules.ruleset @@ -96,7 +96,7 @@ /verbose:lib /section:.SHARDATA,rws %(AdditionalOptions) - keyman_keyboard_processor_native.lib;kmnkbp0.lib;psapi.lib;version.lib;setupapi.lib;iphlpapi.lib;imm32.lib;crypt32.lib;wintrust.lib;imagehlp.lib;ws2_32.lib;libcmt.lib;%(AdditionalDependencies) + libkmnkbp0.a;keyman_keyboard_processor_native.lib;psapi.lib;version.lib;setupapi.lib;iphlpapi.lib;imm32.lib;crypt32.lib;wintrust.lib;imagehlp.lib;ws2_32.lib;libcmt.lib;%(AdditionalDependencies) true C:\Program Files\Microsoft SDKs\Windows\v7.0\Lib\x64;$(VCInstallDir)lib\amd64;$(VCInstallDir)lib;%(AdditionalLibraryDirectories) false @@ -152,11 +152,12 @@ /verbose:lib /section:.SHARDATA,rws %(AdditionalOptions) - keyman_keyboard_processor_native.lib;kmnkbp0.lib;psapi.lib;version.lib;setupapi.lib;iphlpapi.lib;imm32.lib;crypt32.lib;wintrust.lib;imagehlp.lib;ws2_32.lib;libcmt.lib;%(AdditionalDependencies) + libkmnkbp0.a;keyman_keyboard_processor_native.lib;psapi.lib;version.lib;setupapi.lib;iphlpapi.lib;imm32.lib;crypt32.lib;wintrust.lib;imagehlp.lib;ws2_32.lib;libcmt.lib;%(AdditionalDependencies) true - C:\Program Files\Microsoft SDKs\Windows\v7.0A\Lib\x64;$(VCInstallDir)lib\amd64;$(VCInstallDir)lib;%(AdditionalLibraryDirectories) + C:\Program Files\Microsoft SDKs\Windows\v7.0\Lib\x64;$(VCInstallDir)lib\amd64;$(VCInstallDir)lib;%(AdditionalLibraryDirectories) false - %(IgnoreSpecificDefaultLibraries) + + true From 0f4e3d1768d5960f4b8fb4d033904f18c91cba52 Mon Sep 17 00:00:00 2001 From: Ross Date: Tue, 17 Aug 2021 14:10:44 +1000 Subject: [PATCH 19/63] feat(windows): core saving context null pointer check --- windows/src/engine/keyman32/Keyman32.cpp | 38 +++++++--- windows/src/engine/keyman32/appint/aiTIP.cpp | 71 +++++++++++++------ windows/src/engine/keyman32/appint/aiTIP.h | 31 +++++--- windows/src/engine/keyman32/calldll.cpp | 3 +- windows/src/engine/keyman32/capsstate.cpp | 4 ++ .../src/engine/keyman32/keyboardoptions.cpp | 8 +-- .../src/engine/keyman32/kmhook_getmessage.cpp | 2 + windows/src/engine/keyman32/kmprocess.cpp | 25 +++++-- .../src/engine/keyman32/kmprocessactions.cpp | 10 ++- .../src/engine/keyman32/selectkeyboard.cpp | 6 +- 10 files changed, 141 insertions(+), 57 deletions(-) diff --git a/windows/src/engine/keyman32/Keyman32.cpp b/windows/src/engine/keyman32/Keyman32.cpp index 562f049dc2..4e75a12409 100644 --- a/windows/src/engine/keyman32/Keyman32.cpp +++ b/windows/src/engine/keyman32/Keyman32.cpp @@ -566,17 +566,33 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_ForceKeyboard(PCSTR FileName _td->lpActiveKeyboard->KeyboardOptions = NULL;*/ _splitpath_s(FileName, NULL, 0, NULL, 0, _td->lpActiveKeyboard->Name, sizeof(_td->lpActiveKeyboard->Name), NULL, 0); - 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; - } - + if (Globals::get_CoreIntegration()) { + LPWSTR keyboardPath = new WCHAR[MAX_PATH]; + size_t convertedChars = 0; + if (mbstowcs_s(&convertedChars, keyboardPath, MAX_PATH, _td->ForceFileName, _TRUNCATE)) { + delete[] keyboardPath; + return FALSE; + } + + km_kbp_status_codes err_code = (km_kbp_status_codes)km_kbp_keyboard_load(keyboardPath, &_td->lpActiveKeyboard->coreKeyboard); + if (err_code != KM_KBP_STATUS_OK) { + delete[] keyboardPath; + return FALSE; + } + delete[] keyboardPath; + SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard: %s OK", FileName); + 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; + } + } SendDebugMessageFormat(0,sdmGlobal,0,"Keyman_ForceKeyboard: %s FAIL", FileName); delete _td->lpActiveKeyboard; diff --git a/windows/src/engine/keyman32/appint/aiTIP.cpp b/windows/src/engine/keyman32/appint/aiTIP.cpp index 223b7e503f..69961ac2e5 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.cpp +++ b/windows/src/engine/keyman32/appint/aiTIP.cpp @@ -198,6 +198,7 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM *Globals::ShiftState() = (LocalShiftState & K_NOTMODIFIERFLAG) | NewShiftState; // I3588 } + BOOL isUsingCoreProcessor = Globals::get_CoreIntegration(); _td->TIPFUpdateable = Updateable; _td->TIPFPreserved = Preserved; // I4290 @@ -205,39 +206,57 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM _td->state.msg.lParam = 0; _td->state.msg.message = wm_keymankeydown; _td->state.vkey = (WORD) wParam; - - - _td->state.lpkb = _td->lpActiveKeyboard->Keyboard; - /// TODO: 5442 set the correct active keyboard - need with call backs - _td->state.lpCoreKb = _td->lpActiveKeyboard->coreKeyboard; + + if (isUsingCoreProcessor) { + /// TODO: 5442 set the correct active keyboard - need with call backs + _td->state.lpCoreKb = _td->lpActiveKeyboard->coreKeyboard; + + } else { + _td->state.lpkb = _td->lpActiveKeyboard->Keyboard; + _td->state.startgroup = &_td->state.lpkb->dpGroupArray[_td->state.lpkb->StartGroup[BEGIN_UNICODE]]; + } _td->state.windowunicode = TRUE; - _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.NoMatches = TRUE; + _td->state.LoopTimes = 0; + _td->state.StopOutput = FALSE; _td->state.charCode = CharFromVK(&_td->state.vkey, Globals::get_ShiftState()); // I4582 _td->TIPProcessOutput = outfunc; _td->TIPGetContext = ctfunc; - AppContextWithStores *savedContext = NULL; // I4370 // I4978 - if(!Updateable) { // I4370 - savedContext = new AppContextWithStores(_td->lpActiveKeyboard->Keyboard->cxStoreArray); // I4978 - _td->app->SaveContext(savedContext); - } + AppContextWithStores *savedContext = NULL; // I4370 // I4978 + AppContext *savedContextUsingCore = NULL; // used for common core - BOOL res = ProcessHook(); - - if(!Updateable) { // I4370 - if(res) { // I4585 - // Reset the context if match found - _td->app->RestoreContext(savedContext); + if (!Updateable) { + if (isUsingCoreProcessor) { + savedContextUsingCore = new AppContext(); + _td->app->CopyContext(savedContextUsingCore); + } else { // I4370 + savedContext = new AppContextWithStores(_td->lpActiveKeyboard->Keyboard->cxStoreArray); // I4978 + _td->app->SaveContext(savedContext); + } + } + BOOL res = ProcessHook(); + + if (!Updateable) { + if (isUsingCoreProcessor) { + if (res) { + // Reset the context if match found + _td->app->RestoreContextOnly(savedContextUsingCore); + } + delete savedContextUsingCore; + savedContextUsingCore = NULL; + } else { // I4370 + if (res) { // I4585 + // Reset the context if match found + _td->app->RestoreContext(savedContext); + } + delete savedContext; + savedContext = NULL; } - delete savedContext; - savedContext = NULL; } _td->TIPProcessOutput = NULL; @@ -457,6 +476,14 @@ void AITIP::RestoreContext(AppContextWithStores *savedContext) { // I4370 // } } +void AITIP::CopyContext(AppContext *savedContext) { + savedContext->CopyFrom(context); +} + +void AITIP::RestoreContextOnly(AppContext *savedContext) { + context->CopyFrom(savedContext); +} + /* Output actions */ BOOL AITIP::QueueAction(int ItemType, DWORD dwData) { diff --git a/windows/src/engine/keyman32/appint/aiTIP.h b/windows/src/engine/keyman32/appint/aiTIP.h index f8cd328eb6..bb0c790d49 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.h +++ b/windows/src/engine/keyman32/appint/aiTIP.h @@ -1,18 +1,18 @@ /* Name: aiTIP Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 11 Dec 2009 Modified Date: 23 Feb 2016 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 11 Dec 2009 - mcdurdin - I934 - x64 - Initial version 24 Jun 2010 - mcdurdin - I2436 - Add space to context for AIWin2000Unicode when not matched 24 Apr 2014 - mcdurdin - I4196 - V9.0 - wm_kmmoreposting must be refactored for TIP work as it is not sequential @@ -71,14 +71,29 @@ 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 + * + * @param[out] savedContext the copied context + */ + void CopyContext(AppContext *savedContext); + + /** + * Restore the passed context to the member context + * + * @param savedContext the context to restore + */ + void RestoreContextOnly(AppContext *savedContext); virtual BOOL QueueAction(int ItemType, DWORD dwData); /* Information functions */ - + virtual BOOL CanHandleWindow(HWND ahwnd); virtual BOOL IsWindowHandled(HWND ahwnd); virtual BOOL HandleWindow(HWND ahwnd); diff --git a/windows/src/engine/keyman32/calldll.cpp b/windows/src/engine/keyman32/calldll.cpp index 2db3fd6643..2bd64e5871 100644 --- a/windows/src/engine/keyman32/calldll.cpp +++ b/windows/src/engine/keyman32/calldll.cpp @@ -144,6 +144,7 @@ BOOL LoadDLLs(LPINTKEYBOARDINFO lpkbi) if(lpkbi->nIMDLLs > 0) if(!UnloadDLLs(lpkbi)) return FALSE; if(!GetKeyboardFileName(lpkbi->Name, fullname, _MAX_PATH)) return FALSE; + if (!lpkbi->Keyboard) return FALSE; for(DWORD i = 0; i < lpkbi->Keyboard->cxStoreArray; i++) { @@ -224,7 +225,7 @@ BOOL DeactivateDLLs(LPINTKEYBOARDINFO lpkbi) 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]; diff --git a/windows/src/engine/keyman32/capsstate.cpp b/windows/src/engine/keyman32/capsstate.cpp index 3e35022c74..5fe53fd3b7 100644 --- a/windows/src/engine/keyman32/capsstate.cpp +++ b/windows/src/engine/keyman32/capsstate.cpp @@ -37,6 +37,8 @@ void ResetCapsLock(void) if (!_td->lpActiveKeyboard) return; + if (!_td->lpActiveKeyboard->Keyboard) return; + SendDebugMessageFormat(0, sdmGlobal, 0, "ResetCapsLock: enter"); if (_td->lpActiveKeyboard->Keyboard->dwFlags & KF_CAPSALWAYSOFF) @@ -58,6 +60,7 @@ 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) { @@ -85,6 +88,7 @@ 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) { diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index 7b2d328b92..2862910da9 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -35,7 +35,7 @@ void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp) if (Globals::get_CoreIntegration()) { SendDebugMessageFormat(0, sdmAIDefault, 0, "LoadSharedKeyboardOptions: Error called in core integration mode"); - return; + return; } // Called when another thread changes keyboard options and we are sharing keyboard settings assert(kp != NULL); @@ -48,11 +48,11 @@ void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp) void FreeKeyboardOptions(LPINTKEYBOARDINFO kp) { - /*if (Globals::get_CoreIntegration()) + if (Globals::get_CoreIntegration()) { SendDebugMessageFormat(0, sdmAIDefault, 0, "FreeKeyboardOptions: Error called in core integration mode"); return; - }*/ + } // 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) @@ -239,8 +239,6 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* { assert(key != NULL); assert(kp != NULL); - assert(kp->Keyboard != NULL); - assert(kp->KeyboardOptions == NULL); // not used for common core RegistryReadOnly r(HKEY_CURRENT_USER); if (r.OpenKeyReadOnly(REGSZ_KeymanActiveKeyboards) && r.OpenKeyReadOnly(kp->Name) && r.OpenKeyReadOnly(key)) diff --git a/windows/src/engine/keyman32/kmhook_getmessage.cpp b/windows/src/engine/keyman32/kmhook_getmessage.cpp index 2ecec7f2ac..4a568744d2 100644 --- a/windows/src/engine/keyman32/kmhook_getmessage.cpp +++ b/windows/src/engine/keyman32/kmhook_getmessage.cpp @@ -264,6 +264,7 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam) if(_td->lpActiveKeyboard) { _td->state.lpkb = _td->lpActiveKeyboard->Keyboard; + _td->state.lpCoreKb = _td->lpActiveKeyboard->coreKeyboard; } // I4412 if(mp->message == wm_keymanshift) @@ -350,6 +351,7 @@ void ProcessWMKeyman(HWND hwnd, WPARAM wParam, LPARAM lParam) if(_td->lpActiveKeyboard) { _td->state.lpkb = _td->lpActiveKeyboard->Keyboard; + _td->state.lpCoreKb = _td->lpActiveKeyboard->coreKeyboard; } SelectApplicationIntegration(); diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index 80d282edf2..faee0f5c0b 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -140,9 +140,11 @@ BOOL ProcessHook() else _td->app->QueueDebugInformation(QID_BEGIN_ANSI, NULL, NULL, NULL, NULL, (DWORD_PTR) &keyinfo); } - + // TODO: 5011 remove debug message + // PWSTR contextTestBuf = _td->app->ContextBufMax(MAXCONTEXT); + // SendDebugMessageFormat(0, sdmAIDefault, 0, "Kmprocess::ProcessHook Before cxt=%s", Debug_UnicodeString(contextTestBuf, 1)); if (isUsingCoreProcessor) { - // TODO: 5011 remove debug message + SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessActions: "); PWSTR contextBuf = _td->app->ContextBufMax(MAXCONTEXT); km_kbp_context_item *citems = nullptr; @@ -211,6 +213,9 @@ BOOL ProcessHook() _td->app->SetCurrentShiftState(Globals::get_ShiftState()); _td->app->SendActions(); // I4196 } + // output context for debugging + // 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); @@ -233,7 +238,11 @@ BOOL ProcessHook() BOOL ProcessGroup(LPGROUP gp) { - DWORD i; + if (Globals::get_CoreIntegration()) { + SendDebugMessageFormat(0, sdmAIDefault, 0, "KMPROCESS:ProcessGroup: Error called in core integration mode"); + return FALSE; + } + DWORD i; LPKEY kkp = NULL; PWSTR p; int sdmfI; @@ -531,7 +540,11 @@ BOOL ProcessGroup(LPGROUP gp) int PostString(PWSTR str, LPMSG mp, LPKEYBOARD lpkb, PWSTR endstr) { - PWSTR p, q, temp; + if (Globals::get_CoreIntegration()) { + SendDebugMessageFormat(0, sdmAIDefault, 0, "KMPROCESS:PostString: Error called in core integration mode"); + return FALSE; + } + PWSTR p, q, temp; LPSTORE s; int n1, n2; int i, n, shift; @@ -696,6 +709,10 @@ BOOL IsMatchingPlatform(LPSTORE s) // I3432 BOOL ContextMatch(LPKEY kkp) { + if (Globals::get_CoreIntegration()) { + SendDebugMessageFormat(0, sdmAIDefault, 0, "KMPROCESS:ContextMatch: Error called in core integration mode"); + return FALSE; + } WORD /*i,*/ n; PWSTR p, q, qbuf, temp; LPWORD indexp; diff --git a/windows/src/engine/keyman32/kmprocessactions.cpp b/windows/src/engine/keyman32/kmprocessactions.cpp index 2123626b8f..629d9a548e 100644 --- a/windows/src/engine/keyman32/kmprocessactions.cpp +++ b/windows/src/engine/keyman32/kmprocessactions.cpp @@ -27,8 +27,12 @@ static BOOL processAlert(AITIP* app) { return TRUE; } -static BOOL processBack(AITIP* app) { - app->QueueAction(QIT_BACK, BK_DEADKEY); +static BOOL processBack(AITIP* app, const km_kbp_action_item* actionItem) { + if (actionItem->backspace.expected_type == KM_KBP_IT_MARKER) { + app->QueueAction(QIT_BACK, BK_DEADKEY); + } else if (actionItem->backspace.expected_type == KM_KBP_IT_CHAR) { + app->QueueAction(QIT_BACK, 0); + } return TRUE; } @@ -107,7 +111,7 @@ BOOL ProcessActions(BOOL* emitKeyStroke) continueProcessingActions = processAlert(_td->app); break; case KM_KBP_IT_BACK: - continueProcessingActions = processBack(_td->app); + continueProcessingActions = processBack(_td->app, act); break; case KM_KBP_IT_PERSIST_OPT: continueProcessingActions = processPersistOpt(act, _td->lpActiveKeyboard->lpActiveKBState, _td->lpActiveKeyboard); diff --git a/windows/src/engine/keyman32/selectkeyboard.cpp b/windows/src/engine/keyman32/selectkeyboard.cpp index 2e825d5230..7dd2e777af 100644 --- a/windows/src/engine/keyman32/selectkeyboard.cpp +++ b/windows/src/engine/keyman32/selectkeyboard.cpp @@ -79,7 +79,7 @@ BOOL SelectKeyboardCore(DWORD KeymanID) KMHideIM(); /** TODO: 5011 is this just IDML dlls */ - //if (_td->lpActiveKeyboard) DeactivateDLLs(_td->lpActiveKeyboard); + if (_td->lpActiveKeyboard) DeactivateDLLs(_td->lpActiveKeyboard); _td->lpActiveKeyboard = NULL; _td->ActiveKeymanID = KEYMANID_NONKEYMAN; @@ -89,7 +89,7 @@ BOOL SelectKeyboardCore(DWORD KeymanID) { if (_td->lpKeyboards[i].KeymanID == KeymanID) { - if (!_td->lpKeyboards[i].Keyboard && !LoadlpKeyboard(i)) + if (!_td->lpKeyboards[i].coreKeyboard && !LoadlpKeyboard(i)) { SendDebugMessageFormat(hwnd, sdmGlobal, 0, "SelectKeyboardCore: Unable to load"); return TRUE; @@ -128,7 +128,7 @@ BOOL SelectKeyboardCore(DWORD KeymanID) SendDebugMessageFormat(hwnd, sdmGlobal, 0, "EXIT SelectKeyboardCore-------------------------------------------"); } return TRUE; - + } BOOL SelectKeyboard(DWORD KeymanID) From 3b3ea6e75b14bac712b7761c859bbe9013775d38 Mon Sep 17 00:00:00 2001 From: Ross Date: Tue, 17 Aug 2021 17:16:56 +1000 Subject: [PATCH 20/63] feat(windows): clean up formating --- windows/src/developer/kmanalyze/kmanalyze.vcxproj | 6 +++--- windows/src/developer/kmdecomp/kmdecomp.vcxproj | 4 ++-- windows/src/engine/keyman32/K32_load.cpp | 5 ----- windows/src/engine/keyman32/calldll.cpp | 4 ++-- windows/src/engine/keyman32/capsstate.cpp | 2 -- windows/src/engine/keyman32/globals.h | 1 - windows/src/engine/keyman32/keyboardoptions.cpp | 15 +++++++-------- windows/src/engine/keyman32/selectkeyboard.cpp | 1 - windows/src/engine/keyman64/keyman64.vcxproj | 4 ++-- windows/src/engine/kmtip/kmtip.h | 6 +++--- windows/src/engine/kmtip/kmtip.vcxproj | 10 +++++----- 11 files changed, 24 insertions(+), 34 deletions(-) diff --git a/windows/src/developer/kmanalyze/kmanalyze.vcxproj b/windows/src/developer/kmanalyze/kmanalyze.vcxproj index 676dfa1524..2c0a3da3a4 100644 --- a/windows/src/developer/kmanalyze/kmanalyze.vcxproj +++ b/windows/src/developer/kmanalyze/kmanalyze.vcxproj @@ -72,7 +72,7 @@ true - $(KEYMAN_ROOT)\common\core\desktop\include;$(KEYMAN_ROOT)\common\core\desktop\build\x86\$(Configuration)\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(KEYMAN_ROOT)\windows\src\global\inc;$(KEYMAN_ROOT)\windows\src\ext\sentry + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(KEYMAN_ROOT)\windows\src\global\inc;$(KEYMAN_ROOT)\windows\src\ext\sentry $(ProjectDir)bin\$(Platform)\$(Configuration)\ $(ProjectDir)obj\$(Platform)\$(Configuration)\ @@ -84,7 +84,7 @@ false - $(KEYMAN_ROOT)\common\core\desktop\build\x86\$(Configuration)\include;$(KEYMAN_ROOT)\common\core\desktop\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(KEYMAN_ROOT)\windows\src\global\inc;$(KEYMAN_ROOT)\windows\src\ext\sentry + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(KEYMAN_ROOT)\windows\src\global\inc;$(KEYMAN_ROOT)\windows\src\ext\sentry $(ProjectDir)bin\$(Platform)\$(Configuration)\ $(ProjectDir)obj\$(Platform)\$(Configuration)\ @@ -207,4 +207,4 @@ - \ No newline at end of file + diff --git a/windows/src/developer/kmdecomp/kmdecomp.vcxproj b/windows/src/developer/kmdecomp/kmdecomp.vcxproj index 287dd85247..490a97f401 100644 --- a/windows/src/developer/kmdecomp/kmdecomp.vcxproj +++ b/windows/src/developer/kmdecomp/kmdecomp.vcxproj @@ -54,11 +54,11 @@ $(ProjectDir)bin\$(Platform)\$(Configuration)\ $(ProjectDir)obj\$(Platform)\$(Configuration)\ - $(KEYMAN_ROOT)\common\core\desktop\build\x86\$(Configuration)\include;$(KEYMAN_ROOT)\common\core\desktop\include;$(IncludePath) + $(IncludePath) $(ProjectDir)bin\$(Platform)\$(Configuration)\ - $(KEYMAN_ROOT)\common\core\desktop\build\x86\$(Configuration)\include;$(KEYMAN_ROOT)\common\core\desktop\include;$(IncludePath) + $(IncludePath) diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index bccada4231..1f591070b4 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -81,10 +81,7 @@ BOOL LoadlpKeyboardCore(int i) SendDebugMessageFormat(0, sdmAIDefault, 0, "LoadlpKeyboardCore: Enter ---"); PKEYMAN64THREADDATA _td = ThreadGlobals(); if (!_td) return FALSE; - if (_td->lpKeyboards[i].coreKeyboard) return TRUE; - - if (_td->lpActiveKeyboard == &_td->lpKeyboards[i]) _td->lpActiveKeyboard = NULL; // I822 TSF not working char buf[256]; @@ -133,7 +130,6 @@ BOOL LoadlpKeyboardCore(int i) LoadKeyboardOptionsREGCore(&_td->lpKeyboards[i], _td->lpKeyboards[i].lpActiveKBState); return TRUE; - //return FALSE; //ExitError: // if (keyboardPath) { @@ -151,7 +147,6 @@ BOOL LoadlpKeyboard(int 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]; diff --git a/windows/src/engine/keyman32/calldll.cpp b/windows/src/engine/keyman32/calldll.cpp index 2bd64e5871..27ecac7cb0 100644 --- a/windows/src/engine/keyman32/calldll.cpp +++ b/windows/src/engine/keyman32/calldll.cpp @@ -143,7 +143,7 @@ BOOL LoadDLLs(LPINTKEYBOARDINFO lpkbi) if(lpkbi->nIMDLLs > 0) if(!UnloadDLLs(lpkbi)) return FALSE; - if(!GetKeyboardFileName(lpkbi->Name, fullname, _MAX_PATH)) return FALSE; + if(!GetKeyboardFileName(lpkbi->Name, fullname, _MAX_PATH)) return FALSE; if (!lpkbi->Keyboard) return FALSE; for(DWORD i = 0; i < lpkbi->Keyboard->cxStoreArray; i++) @@ -226,7 +226,7 @@ void CallDLL(LPINTKEYBOARDINFO lpkbi, DWORD storenum) { //SendDebugMessageFormat(0, sdmKeyboard, 0, "CallDll: Enter"); if (!lpkbi->Keyboard) return; - if(storenum >= lpkbi->Keyboard->cxStoreArray) return; + if(storenum >= lpkbi->Keyboard->cxStoreArray) return; LPSTORE s = &lpkbi->Keyboard->dpStoreArray[storenum]; if(s->dwSystemID != TSS_CALLDEFINITION) return; diff --git a/windows/src/engine/keyman32/capsstate.cpp b/windows/src/engine/keyman32/capsstate.cpp index 5fe53fd3b7..c9d283cde4 100644 --- a/windows/src/engine/keyman32/capsstate.cpp +++ b/windows/src/engine/keyman32/capsstate.cpp @@ -34,9 +34,7 @@ void ResetCapsLock(void) { PKEYMAN64THREADDATA _td = ThreadGlobals(); if (!_td) return; - if (!_td->lpActiveKeyboard) return; - if (!_td->lpActiveKeyboard->Keyboard) return; SendDebugMessageFormat(0, sdmGlobal, 0, "ResetCapsLock: enter"); diff --git a/windows/src/engine/keyman32/globals.h b/windows/src/engine/keyman32/globals.h index 1e73e51835..03f82a4393 100644 --- a/windows/src/engine/keyman32/globals.h +++ b/windows/src/engine/keyman32/globals.h @@ -151,7 +151,6 @@ public: static BOOL get_debug_ToConsole(); static BOOL get_CoreIntegration(); static void LoadDebugSettings(); - }; /* External interface functions */ diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index 2862910da9..362264d0d4 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -1,24 +1,23 @@ /* Name: keyboardoptions Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 25 May 2010 Modified Date: 28 Nov 2012 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 25 May 2010 - mcdurdin - I1632 - Keyboard Options 31 May 2010 - mcdurdin - I2397 - Assertion failure - keyboard options loading twice 28 Nov 2012 - mcdurdin - I3594 - V9.0 - Remove old SelectKeyboard code and related messages */ #include "pch.h" -//#include "registry.h" void IntSaveKeyboardOption(LPCSTR key, LPINTKEYBOARDINFO kp, int nStoreToSave); BOOL IntLoadKeyboardOptions(LPCSTR key, LPINTKEYBOARDINFO kp); diff --git a/windows/src/engine/keyman32/selectkeyboard.cpp b/windows/src/engine/keyman32/selectkeyboard.cpp index 7dd2e777af..16aae7bbf7 100644 --- a/windows/src/engine/keyman32/selectkeyboard.cpp +++ b/windows/src/engine/keyman32/selectkeyboard.cpp @@ -128,7 +128,6 @@ BOOL SelectKeyboardCore(DWORD KeymanID) SendDebugMessageFormat(hwnd, sdmGlobal, 0, "EXIT SelectKeyboardCore-------------------------------------------"); } return TRUE; - } BOOL SelectKeyboard(DWORD KeymanID) diff --git a/windows/src/engine/keyman64/keyman64.vcxproj b/windows/src/engine/keyman64/keyman64.vcxproj index e73e229544..44c5f155b3 100644 --- a/windows/src/engine/keyman64/keyman64.vcxproj +++ b/windows/src/engine/keyman64/keyman64.vcxproj @@ -45,7 +45,7 @@ false $(ProjectDir)bin\$(Platform)\$(Configuration)\ $(ProjectDir)obj\$(Platform)\$(Configuration)\ - false + true AllRules.ruleset @@ -346,4 +346,4 @@ - \ No newline at end of file + diff --git a/windows/src/engine/kmtip/kmtip.h b/windows/src/engine/kmtip/kmtip.h index aabe098b8b..793e1388a3 100644 --- a/windows/src/engine/kmtip/kmtip.h +++ b/windows/src/engine/kmtip/kmtip.h @@ -2,10 +2,10 @@ Name: kmtip Copyright: Copyright (C) SIL International. Documentation: - Description: CKMTipTextService declaration. - Create Date: 7 Sep 2009 + Description: + Create Date: 11 Dec 2009 - Modified Date: 27 Jan 2015 + Modified Date: 23 Feb 2016 Authors: mcdurdin Related Files: Dependencies: diff --git a/windows/src/engine/kmtip/kmtip.vcxproj b/windows/src/engine/kmtip/kmtip.vcxproj index a6bd20855e..9601065d67 100644 --- a/windows/src/engine/kmtip/kmtip.vcxproj +++ b/windows/src/engine/kmtip/kmtip.vcxproj @@ -105,16 +105,16 @@ kmtip64 - $(ProjectDir)..\..\..\..\common\core\desktop\build\x86\$(Configuration)\include;$(ProjectDir)..\..\..\..\common\core\desktop\include;$(IncludePath) + $(IncludePath) - $(ProjectDir)..\..\..\..\common\core\desktop\build\x86\$(Configuration)\include;$(ProjectDir)..\..\..\..\common\core\desktop\include;$(IncludePath) + $(IncludePath) - $(ProjectDir)..\..\..\..\common\core\desktop\build\x86\$(Configuration)\include;$(ProjectDir)..\..\..\..\common\core\desktop\include;$(IncludePath) + $(IncludePath) - $(ProjectDir)..\..\..\..\common\core\desktop\build\x86\$(Configuration)\include;$(ProjectDir)..\..\..\..\common\core\desktop\include;$(IncludePath) + $(IncludePath) @@ -438,4 +438,4 @@ - \ No newline at end of file + From e2b73af029f142b56c6c43c9940ab0859c088f0d Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 18 Aug 2021 15:44:45 +1000 Subject: [PATCH 21/63] fix(windows): rename reg key prefix dw for DWORD --- windows/src/engine/keyman32/k32_globals.cpp | 4 ++-- windows/src/global/inc/registry.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/windows/src/engine/keyman32/k32_globals.cpp b/windows/src/engine/keyman32/k32_globals.cpp index 454300b06e..d8680ff612 100644 --- a/windows/src/engine/keyman32/k32_globals.cpp +++ b/windows/src/engine/keyman32/k32_globals.cpp @@ -385,8 +385,8 @@ void Globals::SetBaseKeyboardFlags(char *baseKeyboard, BOOL simulateAltGr, BOOL */ BOOL Globals::InitSettings() { /* Check for common core vs windows core */ - f_CoreIntegration = Reg_GetDebugFlag(REGSZ_CoreIntegration, TRUE); - SendDebugMessageFormat(0, sdmAIDefault, 0, "Globals::InitSettings - Coreintegration set in '" REGSZ_CoreIntegration "' to %x", f_CoreIntegration); + f_CoreIntegration = Reg_GetDebugFlag(REGDW_CoreIntegration, TRUE); + SendDebugMessageFormat(0, sdmAIDefault, 0, "Globals::InitSettings - Coreintegration set in '" REGDW_CoreIntegration "' 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/global/inc/registry.h b/windows/src/global/inc/registry.h index 02cfce92a3..82bc317f01 100644 --- a/windows/src/global/inc/registry.h +++ b/windows/src/global/inc/registry.h @@ -140,7 +140,7 @@ #define REGSZ_AutomaticallyReportErrors "automatically report errors" // CU, SRegKey_IDEOptions and SRegKey_KeymanEngine_CU #define REGSZ_AutomaticallyReportUsage "automatically report usage" // CU, SRegKey_IDEOptions and SRegKey_KeymanEngine_CU -#define REGSZ_CoreIntegration "use common core" // Turns on the common core - instead of windows core +#define REGDW_CoreIntegration "use common core" // Turns on the common core - instead of windows core /* Splitting Registry into ReadOnly and FullAccess makes it much easier to ensure that we are using the registry correctly -- readonly wherever possible. */ From a681f4631912d843f50fce61d611f8c1ba2c936c Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Thu, 19 Aug 2021 09:07:30 +1000 Subject: [PATCH 22/63] feat(windows): apply review suggestions Co-authored-by: Eberhard Beilharz Co-authored-by: Marc Durdin --- windows/src/engine/keyman32/Keyman32.cpp | 12 ++++++------ windows/src/engine/keyman32/appint/aiTIP.cpp | 2 +- windows/src/engine/keyman32/keyboardoptions.cpp | 5 +++-- windows/src/engine/keyman32/kmprocessactions.cpp | 7 +++---- windows/src/global/inc/registry.h | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/windows/src/engine/keyman32/Keyman32.cpp b/windows/src/engine/keyman32/Keyman32.cpp index 4e75a12409..a2402d081d 100644 --- a/windows/src/engine/keyman32/Keyman32.cpp +++ b/windows/src/engine/keyman32/Keyman32.cpp @@ -568,17 +568,17 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_ForceKeyboard(PCSTR FileName if (Globals::get_CoreIntegration()) { LPWSTR keyboardPath = new WCHAR[MAX_PATH]; - size_t convertedChars = 0; + size_t convertedChars = 0; if (mbstowcs_s(&convertedChars, keyboardPath, MAX_PATH, _td->ForceFileName, _TRUNCATE)) { delete[] keyboardPath; return FALSE; } km_kbp_status_codes err_code = (km_kbp_status_codes)km_kbp_keyboard_load(keyboardPath, &_td->lpActiveKeyboard->coreKeyboard); - if (err_code != KM_KBP_STATUS_OK) { - delete[] keyboardPath; - return FALSE; - } + if (err_code != KM_KBP_STATUS_OK) { + delete[] keyboardPath; + return FALSE; + } delete[] keyboardPath; SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard: %s OK", FileName); return TRUE; @@ -1006,7 +1006,7 @@ void ReleaseKeyboards(BOOL Lock) if(Lock) UnloadDLLs(&_td->lpKeyboards[i]); FreeKeyboardOptions(&_td->lpKeyboards[i]); ReleaseKeyboardMemory(_td->lpKeyboards[i].Keyboard); - ReleaseKeyboardMemoryCore(_td->lpKeyboards[i].coreKeyboard); + ReleaseKeyboardMemoryCore(_td->lpKeyboards[i].coreKeyboard); if(_td->lpKeyboards[i].Profiles) delete _td->lpKeyboards[i].Profiles; // I3581 } diff --git a/windows/src/engine/keyman32/appint/aiTIP.cpp b/windows/src/engine/keyman32/appint/aiTIP.cpp index 69961ac2e5..5aaa985571 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.cpp +++ b/windows/src/engine/keyman32/appint/aiTIP.cpp @@ -208,7 +208,7 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM _td->state.vkey = (WORD) wParam; if (isUsingCoreProcessor) { - /// TODO: 5442 set the correct active keyboard - need with call backs + // TODO: 5442 set the correct active keyboard - need with call backs _td->state.lpCoreKb = _td->lpActiveKeyboard->coreKeyboard; } else { diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index 362264d0d4..66e434b03a 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -272,9 +272,10 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* } keyboardOpts[n] = KM_KBP_OPTIONS_END; - /// once we have the option list we can then update the options using the public api call + // once we have the option list we can then update the options using the public api call km_kbp_state_options_update(state, keyboardOpts); - for (int i = 0; i < (int)listSize + 1; i++) { + + for (int i = 0; i < (int)listSize + 1; i++) { delete[] keyboardOpts[i].key; delete[] keyboardOpts[i].value; } diff --git a/windows/src/engine/keyman32/kmprocessactions.cpp b/windows/src/engine/keyman32/kmprocessactions.cpp index 629d9a548e..316304c585 100644 --- a/windows/src/engine/keyman32/kmprocessactions.cpp +++ b/windows/src/engine/keyman32/kmprocessactions.cpp @@ -28,9 +28,9 @@ static BOOL processAlert(AITIP* app) { } static BOOL processBack(AITIP* app, const km_kbp_action_item* actionItem) { - if (actionItem->backspace.expected_type == KM_KBP_IT_MARKER) { + if (actionItem->backspace.expected_type == KM_KBP_BT_MARKER) { app->QueueAction(QIT_BACK, BK_DEADKEY); - } else if (actionItem->backspace.expected_type == KM_KBP_IT_CHAR) { + } else /* actionItem->backspace.expected_type == KM_KBP_BT_CHAR, KM_KBP_BT_UNKNOWN */ { app->QueueAction(QIT_BACK, 0); } return TRUE; @@ -99,8 +99,7 @@ BOOL ProcessActions(BOOL* emitKeyStroke) for (auto act = km_kbp_state_action_items(_td->lpActiveKeyboard->lpActiveKBState, nullptr); act->type != KM_KBP_IT_END; act++) { BOOL continueProcessingActions = TRUE; - switch (act->type) - { + switch (act->type) { case KM_KBP_IT_CHAR: continueProcessingActions = processUnicodeChar(_td->app, act); break; diff --git a/windows/src/global/inc/registry.h b/windows/src/global/inc/registry.h index 82bc317f01..78399da1d7 100644 --- a/windows/src/global/inc/registry.h +++ b/windows/src/global/inc/registry.h @@ -175,7 +175,7 @@ public: class RegistryFullAccess: public RegistryReadOnly { -protected: +protected: HKEY GetKey(LPCSTR AKey); BOOL IntRecursiveDeleteKey(HKEY hkey); From 4350c5a63d4d137b3634afec19aafebc61d31ef9 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 19 Aug 2021 11:51:31 +1000 Subject: [PATCH 23/63] feat(windows): review comments rename keyman32-tests --- .../include/keyman/keyboardprocessor.h.in | 3 +-- windows/src/engine/engine.sln | 2 +- windows/src/engine/keyman32/K32_load.cpp | 26 +++---------------- windows/src/engine/keyman32/Keyman32.cpp | 16 ++++-------- windows/src/engine/keyman32/appint/appint.cpp | 3 +-- .../src/engine/keyman32/kmprocessactions.cpp | 3 +-- .../appinttests.cpp | 0 .../keyman-engine-tests.vcxproj} | 1 + .../packages.config | 0 .../pch.cpp | 0 .../pch.h | 0 11 files changed, 13 insertions(+), 41 deletions(-) rename windows/src/engine/keyman32/tests/{keyman32-tests => keyman-engine-tests}/appinttests.cpp (100%) rename windows/src/engine/keyman32/tests/{keyman32-tests/keyman32-tests.vcxproj => keyman-engine-tests/keyman-engine-tests.vcxproj} (99%) rename windows/src/engine/keyman32/tests/{keyman32-tests => keyman-engine-tests}/packages.config (100%) rename windows/src/engine/keyman32/tests/{keyman32-tests => keyman-engine-tests}/pch.cpp (100%) rename windows/src/engine/keyman32/tests/{keyman32-tests => keyman-engine-tests}/pch.h (100%) diff --git a/common/core/desktop/include/keyman/keyboardprocessor.h.in b/common/core/desktop/include/keyman/keyboardprocessor.h.in index fd387a08ea..68bf3e4c33 100644 --- a/common/core/desktop/include/keyman/keyboardprocessor.h.in +++ b/common/core/desktop/include/keyman/keyboardprocessor.h.in @@ -838,8 +838,7 @@ Get the list of action items generated by the last call to A pointer to a `km_kbp_action_item` list, of `*num_items` in length. This data becomes invalid when the state object is destroyed, or after a call to `km_kbp_process_event`. Do not modify the contents of this data. The returned -array is terminated with a `KM_KBP_IT_END` entry. Emit Keystroke `KM_KBP_IT_EMIT_KEYSTROKE` -will always be the last action item if it exits. +array is terminated with a `KM_KBP_IT_END` entry. in the action item queue. ##### Parameters: - __state__: A pointer to the opaque `km_kbp_state` object to be queried. diff --git a/windows/src/engine/engine.sln b/windows/src/engine/engine.sln index f20492513d..13bdd83f00 100644 --- a/windows/src/engine/engine.sln +++ b/windows/src/engine/engine.sln @@ -15,7 +15,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mcompile", "mcompile\mcompi EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kmrefresh", "kmrefresh\kmrefresh.vcxproj", "{A3B8F75F-E63E-434E-8A2A-034AD9B66571}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "keyman32-tests", "keyman32\tests\keyman32-tests\keyman32-tests.vcxproj", "{46399ED7-79A1-4E7E-BD96-4B1AEEC838AE}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "keyman-engine-tests", "keyman32\tests\keyman-engine-tests\keyman-engine-tests.vcxproj", "{46399ED7-79A1-4E7E-BD96-4B1AEEC838AE}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "keyman-engine", "keyman32\keyman-engine.vcxproj", "{A7069186-5AE7-4504-8926-861B7A34BA9E}" EndProject diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index 1f591070b4..7ab62ea0c5 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -86,26 +86,13 @@ BOOL LoadlpKeyboardCore(int i) char buf[256]; if (!GetKeyboardFileName(_td->lpKeyboards[i].Name, buf, 255)) return FALSE; - size_t charSize = strlen(buf) + 1; - - LPWSTR keyboardPath = new WCHAR[charSize]; - - // Convert char* string to a wchar_t* string. - size_t convertedChars = 0; - if (mbstowcs_s(&convertedChars, keyboardPath, charSize, buf, _TRUNCATE)) { - //goto ExitError; - delete[] keyboardPath; - return FALSE; - } + PWCHAR keyboardPath = strtowstr(buf); km_kbp_status_codes err_code = (km_kbp_status_codes)km_kbp_keyboard_load(keyboardPath, &_td->lpKeyboards[i].coreKeyboard); - //if (KM_KBP_STATUS_OK != km_kbp_keyboard_load(keyboardPath, &_td->lpKeyboards[i].coreKeyboard)) { if (err_code != KM_KBP_STATUS_OK) { - //goto ExitError; - delete[] keyboardPath; + delete keyboardPath; return FALSE; } - - delete[] keyboardPath; + delete keyboardPath; // TODO: 5442 handle dlls //LoadDLLs(&_td->lpKeyboards[i]); @@ -125,17 +112,10 @@ BOOL LoadlpKeyboardCore(int i) if (err_code != KM_KBP_STATUS_OK) { return FALSE; } - LoadKeyboardOptionsREGCore(&_td->lpKeyboards[i], _td->lpKeyboards[i].lpActiveKBState); return TRUE; - -//ExitError: -// if (keyboardPath) { -// delete[] keyboardPath; -// } -// return FALSE; } BOOL LoadlpKeyboard(int i) diff --git a/windows/src/engine/keyman32/Keyman32.cpp b/windows/src/engine/keyman32/Keyman32.cpp index a2402d081d..0d2a33597c 100644 --- a/windows/src/engine/keyman32/Keyman32.cpp +++ b/windows/src/engine/keyman32/Keyman32.cpp @@ -565,22 +565,16 @@ 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()) { - LPWSTR keyboardPath = new WCHAR[MAX_PATH]; - size_t convertedChars = 0; - if (mbstowcs_s(&convertedChars, keyboardPath, MAX_PATH, _td->ForceFileName, _TRUNCATE)) { - delete[] keyboardPath; - return FALSE; - } - + PWCHAR keyboardPath = strtowstr(_td->ForceFileName); km_kbp_status_codes err_code = (km_kbp_status_codes)km_kbp_keyboard_load(keyboardPath, &_td->lpActiveKeyboard->coreKeyboard); if (err_code != KM_KBP_STATUS_OK) { - delete[] keyboardPath; + delete keyboardPath; return FALSE; } - delete[] keyboardPath; - SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard: %s OK", FileName); + delete keyboardPath; + SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard Core: %s OK", FileName); // TODO: 5442 - remove word Core return TRUE; } else { if (LoadKeyboard(_td->ForceFileName, &_td->lpActiveKeyboard->Keyboard)) { diff --git a/windows/src/engine/keyman32/appint/appint.cpp b/windows/src/engine/keyman32/appint/appint.cpp index 96cb35a431..b3fd050cb7 100644 --- a/windows/src/engine/keyman32/appint/appint.cpp +++ b/windows/src/engine/keyman32/appint/appint.cpp @@ -217,8 +217,7 @@ BOOL ContextItemsFromAppContext(WCHAR const* buf, km_kbp_context_item** outPtr) // setup dead key context item p += 2; context_items[contextIndex++] = km_kbp_context_item{ KM_KBP_CT_MARKER, {0,}, {*p} }; - } - else if (*p >= 0xD800 && *p <= 0xDBFF && *(p + 1) >= 0xDC00 && *(p + 1) <= 0xDFFF) { + } else if (Uni_IsSurrogate1(*p) && Uni_IsSurrogate2(*(p + 1))) { // handle surrogate context_items[contextIndex++] = km_kbp_context_item{ KM_KBP_CT_CHAR, {0,}, {(char32_t)Uni_SurrogateToUTF32(*p, *(p + 1))} }; p++; diff --git a/windows/src/engine/keyman32/kmprocessactions.cpp b/windows/src/engine/keyman32/kmprocessactions.cpp index 316304c585..5e244e3b90 100644 --- a/windows/src/engine/keyman32/kmprocessactions.cpp +++ b/windows/src/engine/keyman32/kmprocessactions.cpp @@ -123,8 +123,7 @@ BOOL ProcessActions(BOOL* emitKeyStroke) continueProcessingActions = processInvalidateContext(_td->app, _td->lpActiveKeyboard->lpActiveKBState); break; case KM_KBP_IT_END: - assert(false); - break; + // fallthrough default: assert(false); // NOT SUPPORTED break; diff --git a/windows/src/engine/keyman32/tests/keyman32-tests/appinttests.cpp b/windows/src/engine/keyman32/tests/keyman-engine-tests/appinttests.cpp similarity index 100% rename from windows/src/engine/keyman32/tests/keyman32-tests/appinttests.cpp rename to windows/src/engine/keyman32/tests/keyman-engine-tests/appinttests.cpp diff --git a/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj b/windows/src/engine/keyman32/tests/keyman-engine-tests/keyman-engine-tests.vcxproj similarity index 99% rename from windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj rename to windows/src/engine/keyman32/tests/keyman-engine-tests/keyman-engine-tests.vcxproj index dc8c6faa78..4931f7e718 100644 --- a/windows/src/engine/keyman32/tests/keyman32-tests/keyman32-tests.vcxproj +++ b/windows/src/engine/keyman32/tests/keyman-engine-tests/keyman-engine-tests.vcxproj @@ -25,6 +25,7 @@ Application v142 Unicode + keyman-engine-tests diff --git a/windows/src/engine/keyman32/tests/keyman32-tests/packages.config b/windows/src/engine/keyman32/tests/keyman-engine-tests/packages.config similarity index 100% rename from windows/src/engine/keyman32/tests/keyman32-tests/packages.config rename to windows/src/engine/keyman32/tests/keyman-engine-tests/packages.config diff --git a/windows/src/engine/keyman32/tests/keyman32-tests/pch.cpp b/windows/src/engine/keyman32/tests/keyman-engine-tests/pch.cpp similarity index 100% rename from windows/src/engine/keyman32/tests/keyman32-tests/pch.cpp rename to windows/src/engine/keyman32/tests/keyman-engine-tests/pch.cpp diff --git a/windows/src/engine/keyman32/tests/keyman32-tests/pch.h b/windows/src/engine/keyman32/tests/keyman-engine-tests/pch.h similarity index 100% rename from windows/src/engine/keyman32/tests/keyman32-tests/pch.h rename to windows/src/engine/keyman32/tests/keyman-engine-tests/pch.h From 937bf8a4856210edc4787d0795dfe5fd6e4a6b18 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 19 Aug 2021 14:17:34 +1000 Subject: [PATCH 24/63] feat(windows): review comments --- .../desktop/include/keyman/keyboardprocessor.h.in | 1 - windows/src/engine/keyman32/K32_load.cpp | 13 +++++-------- windows/src/engine/keyman32/Keyman32.cpp | 2 +- windows/src/engine/keyman32/kmprocess.cpp | 14 ++++++++++++-- windows/src/engine/keyman32/kmprocessactions.cpp | 2 +- 5 files changed, 19 insertions(+), 13 deletions(-) diff --git a/common/core/desktop/include/keyman/keyboardprocessor.h.in b/common/core/desktop/include/keyman/keyboardprocessor.h.in index 68bf3e4c33..33b2eef253 100644 --- a/common/core/desktop/include/keyman/keyboardprocessor.h.in +++ b/common/core/desktop/include/keyman/keyboardprocessor.h.in @@ -839,7 +839,6 @@ A pointer to a `km_kbp_action_item` list, of `*num_items` in length. This data becomes invalid when the state object is destroyed, or after a call to `km_kbp_process_event`. Do not modify the contents of this data. The returned array is terminated with a `KM_KBP_IT_END` entry. -in the action item queue. ##### Parameters: - __state__: A pointer to the opaque `km_kbp_state` object to be queried. - __num_items__: diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index 7ab62ea0c5..965fab99fe 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -75,7 +75,6 @@ BOOL GetKeyboardFileName(LPSTR kbname, LPSTR buf, int nbuf) return n; } - BOOL LoadlpKeyboardCore(int i) { SendDebugMessageFormat(0, sdmAIDefault, 0, "LoadlpKeyboardCore: Enter ---"); @@ -84,6 +83,11 @@ BOOL LoadlpKeyboardCore(int i) if (_td->lpKeyboards[i].coreKeyboard) return TRUE; if (_td->lpActiveKeyboard == &_td->lpKeyboards[i]) _td->lpActiveKeyboard = NULL; // I822 TSF not working + if (_td->lpKeyboards[i].lpActiveKBState) { + km_kbp_state_dispose(_td->lpKeyboards[i].lpActiveKBState); + _td->lpKeyboards[i].lpActiveKBState = NULL; + } + char buf[256]; if (!GetKeyboardFileName(_td->lpKeyboards[i].Name, buf, 255)) return FALSE; PWCHAR keyboardPath = strtowstr(buf); @@ -101,13 +105,6 @@ BOOL LoadlpKeyboardCore(int i) KM_KBP_OPTIONS_END }; - if (_td->lpKeyboards[i].lpActiveKBState) - { - km_kbp_state_dispose(_td->lpKeyboards[i].lpActiveKBState); - _td->lpKeyboards[i].lpActiveKBState = NULL; - } - - // if (KM_KBP_STATUS_OK != km_kbp_state_create(_td->lpKeyboards[i].coreKeyboard, test_env_opts, &_td->lpKeyboards[i].lpActiveKBState)) return FALSE; err_code = (km_kbp_status_codes)km_kbp_state_create(_td->lpKeyboards[i].coreKeyboard, test_env_opts, &_td->lpKeyboards[i].lpActiveKBState); if (err_code != KM_KBP_STATUS_OK) { return FALSE; diff --git a/windows/src/engine/keyman32/Keyman32.cpp b/windows/src/engine/keyman32/Keyman32.cpp index 0d2a33597c..295390dd40 100644 --- a/windows/src/engine/keyman32/Keyman32.cpp +++ b/windows/src/engine/keyman32/Keyman32.cpp @@ -1000,7 +1000,7 @@ void ReleaseKeyboards(BOOL Lock) if(Lock) UnloadDLLs(&_td->lpKeyboards[i]); FreeKeyboardOptions(&_td->lpKeyboards[i]); ReleaseKeyboardMemory(_td->lpKeyboards[i].Keyboard); - ReleaseKeyboardMemoryCore(_td->lpKeyboards[i].coreKeyboard); + ReleaseKeyboardMemoryCore(_td->lpKeyboards[i].coreKeyboard); if(_td->lpKeyboards[i].Profiles) delete _td->lpKeyboards[i].Profiles; // I3581 } diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index faee0f5c0b..f5cf4f4239 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -149,10 +149,20 @@ BOOL ProcessHook() PWSTR contextBuf = _td->app->ContextBufMax(MAXCONTEXT); km_kbp_context_item *citems = nullptr; ContextItemsFromAppContext(contextBuf, &citems); - km_kbp_context_set(km_kbp_state_context(_td->lpActiveKeyboard->lpActiveKBState), citems); + if (KM_KBP_STATUS_OK != + (km_kbp_status_codes)km_kbp_context_set( + km_kbp_state_context(_td->lpActiveKeyboard->lpActiveKBState), citems)) { + km_kbp_context_items_dispose(citems); + return FALSE; + } km_kbp_context_items_dispose(citems); //_td->state.vkey == VK_DOWN - if (KM_KBP_STATUS_OK != km_kbp_process_event(_td->lpActiveKeyboard->lpActiveKBState, _td->state.vkey, static_cast(Globals::get_ShiftState()), 1)) return FALSE; + if (KM_KBP_STATUS_OK != + (km_kbp_status_codes)km_kbp_process_event( + _td->lpActiveKeyboard->lpActiveKBState, _td->state.vkey, static_cast(Globals::get_ShiftState()), 1)) { + return FALSE; + } + ProcessActions(&fOutputKeystroke); } else { diff --git a/windows/src/engine/keyman32/kmprocessactions.cpp b/windows/src/engine/keyman32/kmprocessactions.cpp index 5e244e3b90..a8c7fdf958 100644 --- a/windows/src/engine/keyman32/kmprocessactions.cpp +++ b/windows/src/engine/keyman32/kmprocessactions.cpp @@ -54,7 +54,7 @@ static BOOL processPersistOpt( wcscpy_s(reinterpret_cast(cp), sizeof(actionItem->option->value) + 1, reinterpret_cast(actionItem->option->value)); keyboardOpts[0].value = cp; keyboardOpts[1] = KM_KBP_OPTIONS_END; - km_kbp_status eventStatus = km_kbp_state_options_update(keyboardState, keyboardOpts); + km_kbp_status eventStatus = (km_kbp_status_codes)km_kbp_state_options_update(keyboardState, keyboardOpts); if (eventStatus != KM_KBP_STATUS_OK) { // log warning "problem saving option for km_kbp_keyboard"); From aab8cb178c416c0b712b982702a4be52d2ce9653 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Mon, 23 Aug 2021 09:51:10 +1000 Subject: [PATCH 25/63] fix(windows): apply suggestion changes core integration review Co-authored-by: Marc Durdin --- windows/src/engine/keyman32/K32_load.cpp | 6 +++--- windows/src/engine/keyman32/Keyman32.cpp | 4 ++-- windows/src/engine/keyman32/appint/appint.cpp | 4 ++-- windows/src/engine/keyman32/kmprocessactions.cpp | 3 +-- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index 965fab99fe..8abee596c3 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -92,11 +92,11 @@ BOOL LoadlpKeyboardCore(int i) if (!GetKeyboardFileName(_td->lpKeyboards[i].Name, buf, 255)) return FALSE; PWCHAR keyboardPath = strtowstr(buf); km_kbp_status_codes err_code = (km_kbp_status_codes)km_kbp_keyboard_load(keyboardPath, &_td->lpKeyboards[i].coreKeyboard); - if (err_code != KM_KBP_STATUS_OK) { - delete keyboardPath; + delete keyboardPath; + if (err_code != KM_KBP_STATUS_OK) {\ + SendDebugMessageFormat(...); // TODO: log err_code return FALSE; } - delete keyboardPath; // TODO: 5442 handle dlls //LoadDLLs(&_td->lpKeyboards[i]); diff --git a/windows/src/engine/keyman32/Keyman32.cpp b/windows/src/engine/keyman32/Keyman32.cpp index 295390dd40..2ed7c9f98b 100644 --- a/windows/src/engine/keyman32/Keyman32.cpp +++ b/windows/src/engine/keyman32/Keyman32.cpp @@ -569,11 +569,11 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_ForceKeyboard(PCSTR FileName if (Globals::get_CoreIntegration()) { PWCHAR keyboardPath = strtowstr(_td->ForceFileName); km_kbp_status_codes err_code = (km_kbp_status_codes)km_kbp_keyboard_load(keyboardPath, &_td->lpActiveKeyboard->coreKeyboard); + delete keyboardPath; if (err_code != KM_KBP_STATUS_OK) { - delete keyboardPath; + // TODO log failure return FALSE; } - delete keyboardPath; SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard Core: %s OK", FileName); // TODO: 5442 - remove word Core return TRUE; } else { diff --git a/windows/src/engine/keyman32/appint/appint.cpp b/windows/src/engine/keyman32/appint/appint.cpp index b3fd050cb7..ea7c33f1b1 100644 --- a/windows/src/engine/keyman32/appint/appint.cpp +++ b/windows/src/engine/keyman32/appint/appint.cpp @@ -207,6 +207,7 @@ AppIntegration::AppIntegration() BOOL ContextItemsFromAppContext(WCHAR const* buf, km_kbp_context_item** outPtr) { assert(buf); + assert(outPtr); km_kbp_context_item* context_items = new km_kbp_context_item[wcslen(buf) + 1]; WCHAR const *p = buf; uint8_t contextIndex = 0; @@ -221,8 +222,7 @@ BOOL ContextItemsFromAppContext(WCHAR const* buf, km_kbp_context_item** outPtr) // handle surrogate context_items[contextIndex++] = km_kbp_context_item{ KM_KBP_CT_CHAR, {0,}, {(char32_t)Uni_SurrogateToUTF32(*p, *(p + 1))} }; p++; - } - else { + } else { context_items[contextIndex++] = km_kbp_context_item{ KM_KBP_CT_CHAR, {0,}, {*p} }; } p++; diff --git a/windows/src/engine/keyman32/kmprocessactions.cpp b/windows/src/engine/keyman32/kmprocessactions.cpp index a8c7fdf958..c8dbbd4e0a 100644 --- a/windows/src/engine/keyman32/kmprocessactions.cpp +++ b/windows/src/engine/keyman32/kmprocessactions.cpp @@ -70,7 +70,7 @@ static BOOL processPersistOpt( actionItem->option->value != NULL) { // log"Saving keyboard option to registry"); - SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessHook: Saving option to registry for keybooard [%s].", activeKeyboard->Name); + 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); @@ -88,7 +88,6 @@ static BOOL processInvalidateContext( return TRUE; } - // TODO: 5011 make this function a new file BOOL ProcessActions(BOOL* emitKeyStroke) { PKEYMAN64THREADDATA _td = ThreadGlobals(); From a4801373dbb86ad606e50edc5268aba8dc1ac711 Mon Sep 17 00:00:00 2001 From: Ross Date: Tue, 24 Aug 2021 17:17:26 +1000 Subject: [PATCH 26/63] feat(windows): err logs, DEBUG_ASSERT macro Added some more error logs Added a DEBUG_ASSERT macro Update variable names --- windows/src/engine/keyman32/K32_load.cpp | 26 ++++++----- windows/src/engine/keyman32/Keyman32.cpp | 42 ++++++++++++----- windows/src/engine/keyman32/appint/aiTIP.cpp | 9 ++-- windows/src/engine/keyman32/k32_dbg.cpp | 9 ++++ windows/src/engine/keyman32/k32_globals.cpp | 4 +- .../src/engine/keyman32/keyboardoptions.cpp | 45 +++++++------------ .../src/engine/keyman32/kmhook_getmessage.cpp | 4 +- windows/src/engine/keyman32/kmprocess.cpp | 19 +++----- .../src/engine/keyman32/kmprocessactions.cpp | 21 +++------ .../src/engine/keyman32/selectkeyboard.cpp | 2 +- windows/src/engine/kmtip/kmtip.h | 6 +-- windows/src/engine/kmtip/kmtip.vcxproj | 15 +------ windows/src/global/inc/keymanengine.h | 31 +++++++++++-- windows/src/global/inc/registry.h | 2 +- 14 files changed, 125 insertions(+), 110 deletions(-) diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index 8abee596c3..9233da3b25 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -77,24 +77,26 @@ BOOL GetKeyboardFileName(LPSTR kbname, LPSTR buf, int nbuf) BOOL LoadlpKeyboardCore(int i) { - SendDebugMessageFormat(0, sdmAIDefault, 0, "LoadlpKeyboardCore: Enter ---"); + SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboardCore: Enter ---"); + + PKEYMAN64THREADDATA _td = ThreadGlobals(); if (!_td) return FALSE; - if (_td->lpKeyboards[i].coreKeyboard) return TRUE; + if (_td->lpKeyboards[i].lpCoreKeyboard) return TRUE; if (_td->lpActiveKeyboard == &_td->lpKeyboards[i]) _td->lpActiveKeyboard = NULL; // I822 TSF not working - if (_td->lpKeyboards[i].lpActiveKBState) { - km_kbp_state_dispose(_td->lpKeyboards[i].lpActiveKBState); - _td->lpKeyboards[i].lpActiveKBState = NULL; + if (_td->lpKeyboards[i].lpCoreKeyboardState) { + km_kbp_state_dispose(_td->lpKeyboards[i].lpCoreKeyboardState); + _td->lpKeyboards[i].lpCoreKeyboardState = NULL; } char buf[256]; if (!GetKeyboardFileName(_td->lpKeyboards[i].Name, buf, 255)) return FALSE; PWCHAR keyboardPath = strtowstr(buf); - km_kbp_status_codes err_code = (km_kbp_status_codes)km_kbp_keyboard_load(keyboardPath, &_td->lpKeyboards[i].coreKeyboard); + km_kbp_status err_status = km_kbp_keyboard_load(keyboardPath, &_td->lpKeyboards[i].lpCoreKeyboard); delete keyboardPath; - if (err_code != KM_KBP_STATUS_OK) {\ - SendDebugMessageFormat(...); // TODO: log err_code + if (err_status != KM_KBP_STATUS_OK) { + SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboardCore: km_kbp_keyboard_load failed with error status [%d]", err_status); return FALSE; } @@ -105,12 +107,14 @@ BOOL LoadlpKeyboardCore(int i) KM_KBP_OPTIONS_END }; - err_code = (km_kbp_status_codes)km_kbp_state_create(_td->lpKeyboards[i].coreKeyboard, test_env_opts, &_td->lpKeyboards[i].lpActiveKBState); - if (err_code != KM_KBP_STATUS_OK) { + err_status = km_kbp_state_create(_td->lpKeyboards[i].lpCoreKeyboard, test_env_opts, &_td->lpKeyboards[i].lpCoreKeyboardState); + if (err_status != KM_KBP_STATUS_OK) { + SendDebugMessageFormat( + 0, sdmLoad, 0, "LoadlpKeyboardCore: km_kbp_state_create failed with error status [%d]", err_status); return FALSE; } - LoadKeyboardOptionsREGCore(&_td->lpKeyboards[i], _td->lpKeyboards[i].lpActiveKBState); + LoadKeyboardOptionsREGCore(&_td->lpKeyboards[i], _td->lpKeyboards[i].lpCoreKeyboardState); return TRUE; } diff --git a/windows/src/engine/keyman32/Keyman32.cpp b/windows/src/engine/keyman32/Keyman32.cpp index 2ed7c9f98b..097543bbb3 100644 --- a/windows/src/engine/keyman32/Keyman32.cpp +++ b/windows/src/engine/keyman32/Keyman32.cpp @@ -568,13 +568,25 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_ForceKeyboard(PCSTR FileName // 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_codes err_code = (km_kbp_status_codes)km_kbp_keyboard_load(keyboardPath, &_td->lpActiveKeyboard->coreKeyboard); + km_kbp_status err_status = km_kbp_keyboard_load(keyboardPath, &_td->lpActiveKeyboard->lpCoreKeyboard); delete keyboardPath; - if (err_code != KM_KBP_STATUS_OK) { - // TODO log failure + if (err_status != KM_KBP_STATUS_OK) { + SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard Core: km_kbp_keyboard_load failed with error status [%d]", err_status); // TODO: 5442 - remove word Core return FALSE; } - SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard Core: %s OK", FileName); // TODO: 5442 - remove word Core + SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard Core: %s OK", FileName); // TODO: 5442 - remove word Core + + // LoadDLLs(&_td->lpKeyboards[i]); + const km_kbp_option_item test_env_opts[] = {KM_KBP_OPTIONS_END}; + err_status = + km_kbp_state_create(_td->lpActiveKeyboard->lpCoreKeyboard, test_env_opts, &_td->lpActiveKeyboard->lpCoreKeyboardState); + if (err_status != KM_KBP_STATUS_OK) { + SendDebugMessageFormat( + 0, sdmGlobal, 0, "Keyman_ForceKeyboard Core: km_kbp_state_create failed with error status [%d]", err_status); + return FALSE; + } + LoadKeyboardOptionsREGCore(_td->lpActiveKeyboard, _td->lpActiveKeyboard->lpCoreKeyboardState); + RefreshPreservedKeys(TRUE); return TRUE; } else { if (LoadKeyboard(_td->ForceFileName, &_td->lpActiveKeyboard->Keyboard)) { @@ -619,6 +631,8 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_StopForcingKeyboard() _td->ForceFileName[0] = 0; FreeKeyboardOptions(_td->lpActiveKeyboard); ReleaseKeyboardMemory(_td->lpActiveKeyboard->Keyboard); + ReleaseStateMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboardState); + ReleaseKeyboardMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboard); RefreshPreservedKeys(FALSE); delete _td->lpActiveKeyboard; _td->lpActiveKeyboard = NULL; @@ -663,11 +677,18 @@ BOOL ReleaseKeyboardMemory(LPKEYBOARD kbd) return TRUE; } -BOOL ReleaseKeyboardMemoryCore(km_kbp_keyboard* kbd) -{ - if (!kbd) return TRUE; - km_kbp_keyboard_dispose(kbd); - kbd = NULL; +BOOL ReleaseStateMemoryCore(km_kbp_state **state) { + if (!*state) return TRUE; + km_kbp_state_dispose(*state); + *state = NULL; + return TRUE; +} + +BOOL ReleaseKeyboardMemoryCore(km_kbp_keyboard **kbd) { + if (!*kbd) + return TRUE; + km_kbp_keyboard_dispose(*kbd); + *kbd = NULL; return TRUE; } @@ -1000,7 +1021,8 @@ void ReleaseKeyboards(BOOL Lock) if(Lock) UnloadDLLs(&_td->lpKeyboards[i]); FreeKeyboardOptions(&_td->lpKeyboards[i]); ReleaseKeyboardMemory(_td->lpKeyboards[i].Keyboard); - ReleaseKeyboardMemoryCore(_td->lpKeyboards[i].coreKeyboard); + 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/appint/aiTIP.cpp b/windows/src/engine/keyman32/appint/aiTIP.cpp index 5aaa985571..53953f1d4e 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.cpp +++ b/windows/src/engine/keyman32/appint/aiTIP.cpp @@ -209,19 +209,18 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM if (isUsingCoreProcessor) { // TODO: 5442 set the correct active keyboard - need with call backs - _td->state.lpCoreKb = _td->lpActiveKeyboard->coreKeyboard; + _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.windowunicode = TRUE; - _td->state.NoMatches = TRUE; - _td->state.LoopTimes = 0; - _td->state.StopOutput = FALSE; - _td->state.charCode = CharFromVK(&_td->state.vkey, Globals::get_ShiftState()); // I4582 _td->TIPProcessOutput = outfunc; diff --git a/windows/src/engine/keyman32/k32_dbg.cpp b/windows/src/engine/keyman32/k32_dbg.cpp index b58eb8df85..580d7370e0 100644 --- a/windows/src/engine/keyman32/k32_dbg.cpp +++ b/windows/src/engine/keyman32/k32_dbg.cpp @@ -314,6 +314,15 @@ void _OutputThreadDebugString(char *s) { } #endif +BOOL IsDebugAssertEnabled() +{ +#ifdef _DEBUG + return IsDebuggerPresent(); +#else + return FALSE; +#endif +} + void WINAPI Keyman_Diagnostic(int mode) { if (mode == 0) { RaiseException(0xDEADBEEF, EXCEPTION_NONCONTINUABLE, 0, NULL); diff --git a/windows/src/engine/keyman32/k32_globals.cpp b/windows/src/engine/keyman32/k32_globals.cpp index d8680ff612..454300b06e 100644 --- a/windows/src/engine/keyman32/k32_globals.cpp +++ b/windows/src/engine/keyman32/k32_globals.cpp @@ -385,8 +385,8 @@ void Globals::SetBaseKeyboardFlags(char *baseKeyboard, BOOL simulateAltGr, BOOL */ BOOL Globals::InitSettings() { /* Check for common core vs windows core */ - f_CoreIntegration = Reg_GetDebugFlag(REGDW_CoreIntegration, TRUE); - SendDebugMessageFormat(0, sdmAIDefault, 0, "Globals::InitSettings - Coreintegration set in '" REGDW_CoreIntegration "' to %x", f_CoreIntegration); + f_CoreIntegration = Reg_GetDebugFlag(REGSZ_CoreIntegration, TRUE); + SendDebugMessageFormat(0, sdmAIDefault, 0, "Globals::InitSettings - Coreintegration set in '" REGSZ_CoreIntegration "' 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 66e434b03a..d7ea003a65 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -31,11 +31,7 @@ void LoadKeyboardOptions(LPINTKEYBOARDINFO kp) void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp) { - if (Globals::get_CoreIntegration()) - { - SendDebugMessageFormat(0, sdmAIDefault, 0, "LoadSharedKeyboardOptions: Error called in core integration mode"); - return; - } + DebugAssert(!Globals::get_CoreIntegration(), "LoadSharedKeyboardOptions: Error called in core integration mode"); // Called when another thread changes keyboard options and we are sharing keyboard settings assert(kp != NULL); assert(kp->Keyboard != NULL); @@ -47,11 +43,7 @@ void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp) void FreeKeyboardOptions(LPINTKEYBOARDINFO kp) { - if (Globals::get_CoreIntegration()) - { - SendDebugMessageFormat(0, sdmAIDefault, 0, "FreeKeyboardOptions: Error called in core integration mode"); - return; - } + DebugAssert(!Globals::get_CoreIntegration(),"FreeKeyboardOptions: Error called in core integration mode"); // 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) @@ -69,12 +61,7 @@ void FreeKeyboardOptions(LPINTKEYBOARDINFO kp) void SetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSet, int nStoreToRead) { - if (Globals::get_CoreIntegration()) - { - SendDebugMessageFormat(0, sdmAIDefault, 0, "SetKeyboardOption: Error called in core integration mode"); - return; - } - + DebugAssert(!Globals::get_CoreIntegration(), "SetKeyboardOption: Error called in core integration mode"); assert(kp != NULL); assert(kp->Keyboard != NULL); assert(kp->KeyboardOptions != NULL); @@ -100,11 +87,7 @@ void SetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSet, int nStoreToRead) void ResetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToReset) { - if (Globals::get_CoreIntegration()) - { - SendDebugMessageFormat(0, sdmAIDefault, 0, "ResetKeyboardOption: Error called in core integration mode"); - return; - } + DebugAssert(!Globals::get_CoreIntegration(), "ResetKeyboardOption: Error called in core integration mode"); assert(kp != NULL); assert(kp->Keyboard != NULL); assert(kp->KeyboardOptions != NULL); @@ -141,11 +124,7 @@ void ResetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToReset) void SaveKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSave) { - if (Globals::get_CoreIntegration()) - { - SendDebugMessageFormat(0, sdmAIDefault, 0, "SaveKeyboardOption: Error called in core integration mode"); - return; - } + DebugAssert(!Globals::get_CoreIntegration(), "SaveKeyboardOption: Error called in core integration mode"); IntSaveKeyboardOption(REGSZ_KeyboardOptions, kp, nStoreToSave); } @@ -230,7 +209,7 @@ void IntSaveKeyboardOption(LPCSTR key, LPINTKEYBOARDINFO kp, int nStoreToSave) void LoadKeyboardOptionsREGCore(LPINTKEYBOARDINFO kp, km_kbp_state* const state) { - SendDebugMessageFormat(0, sdmAIDefault, 0, "LoadKeyboardOptionsREGCore: Enter"); + SendDebugMessageFormat(0, sdmKeyboard, 0, "LoadKeyboardOptionsREGCore: Enter"); IntLoadKeyboardOptionsCore(REGSZ_KeyboardOptions, kp, state); } @@ -246,7 +225,11 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* int n = 0; // Get the list of default options to determine size of list const km_kbp_keyboard_attrs* keyboardAttrs; - km_kbp_keyboard_get_attrs(kp->coreKeyboard, &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, "LoadKeyboardOptionsREGCore: km_kbp_keyboard_get_attrs failed with error status [%d]", err_status); + } size_t listSize = km_kbp_options_list_size(keyboardAttrs->default_options); km_kbp_option_item* keyboardOpts = new km_kbp_option_item[listSize+1]; @@ -273,7 +256,11 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* keyboardOpts[n] = KM_KBP_OPTIONS_END; // once we have the option list we can then update the options using the public api call - km_kbp_state_options_update(state, keyboardOpts); + 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); + } for (int i = 0; i < (int)listSize + 1; i++) { delete[] keyboardOpts[i].key; diff --git a/windows/src/engine/keyman32/kmhook_getmessage.cpp b/windows/src/engine/keyman32/kmhook_getmessage.cpp index 4a568744d2..81026a84e9 100644 --- a/windows/src/engine/keyman32/kmhook_getmessage.cpp +++ b/windows/src/engine/keyman32/kmhook_getmessage.cpp @@ -264,7 +264,7 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam) if(_td->lpActiveKeyboard) { _td->state.lpkb = _td->lpActiveKeyboard->Keyboard; - _td->state.lpCoreKb = _td->lpActiveKeyboard->coreKeyboard; + _td->state.lpCoreKb = _td->lpActiveKeyboard->lpCoreKeyboard; } // I4412 if(mp->message == wm_keymanshift) @@ -351,7 +351,7 @@ void ProcessWMKeyman(HWND hwnd, WPARAM wParam, LPARAM lParam) if(_td->lpActiveKeyboard) { _td->state.lpkb = _td->lpActiveKeyboard->Keyboard; - _td->state.lpCoreKb = _td->lpActiveKeyboard->coreKeyboard; + _td->state.lpCoreKb = _td->lpActiveKeyboard->lpCoreKeyboard; } SelectApplicationIntegration(); diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index f5cf4f4239..df6f823aeb 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -151,7 +151,7 @@ BOOL ProcessHook() ContextItemsFromAppContext(contextBuf, &citems); if (KM_KBP_STATUS_OK != (km_kbp_status_codes)km_kbp_context_set( - km_kbp_state_context(_td->lpActiveKeyboard->lpActiveKBState), citems)) { + km_kbp_state_context(_td->lpActiveKeyboard->lpCoreKeyboardState), citems)) { km_kbp_context_items_dispose(citems); return FALSE; } @@ -159,7 +159,7 @@ BOOL ProcessHook() //_td->state.vkey == VK_DOWN if (KM_KBP_STATUS_OK != (km_kbp_status_codes)km_kbp_process_event( - _td->lpActiveKeyboard->lpActiveKBState, _td->state.vkey, static_cast(Globals::get_ShiftState()), 1)) { + _td->lpActiveKeyboard->lpCoreKeyboardState, _td->state.vkey, static_cast(Globals::get_ShiftState()), 1)) { return FALSE; } @@ -248,10 +248,7 @@ BOOL ProcessHook() BOOL ProcessGroup(LPGROUP gp) { - if (Globals::get_CoreIntegration()) { - SendDebugMessageFormat(0, sdmAIDefault, 0, "KMPROCESS:ProcessGroup: Error called in core integration mode"); - return FALSE; - } + DebugAssertRetValue(!Globals::get_CoreIntegration(), "KMPROCESS:ProcessGroup: Error called in core integration mode", FALSE); DWORD i; LPKEY kkp = NULL; PWSTR p; @@ -550,10 +547,7 @@ BOOL ProcessGroup(LPGROUP gp) int PostString(PWSTR str, LPMSG mp, LPKEYBOARD lpkb, PWSTR endstr) { - if (Globals::get_CoreIntegration()) { - SendDebugMessageFormat(0, sdmAIDefault, 0, "KMPROCESS:PostString: Error called in core integration mode"); - return FALSE; - } + DebugAssertRetValue(!Globals::get_CoreIntegration(), "KKMPROCESS:PostString: Error called in core integration mode", FALSE); PWSTR p, q, temp; LPSTORE s; int n1, n2; @@ -719,10 +713,7 @@ BOOL IsMatchingPlatform(LPSTORE s) // I3432 BOOL ContextMatch(LPKEY kkp) { - if (Globals::get_CoreIntegration()) { - SendDebugMessageFormat(0, sdmAIDefault, 0, "KMPROCESS:ContextMatch: Error called in core integration mode"); - return FALSE; - } + DebugAssertRetValue(!Globals::get_CoreIntegration(), "KMPROCESS:ContextMatch: Error called in core integration mode", FALSE); WORD /*i,*/ n; PWSTR p, q, qbuf, temp; LPWORD indexp; diff --git a/windows/src/engine/keyman32/kmprocessactions.cpp b/windows/src/engine/keyman32/kmprocessactions.cpp index c8dbbd4e0a..9f13bc4afb 100644 --- a/windows/src/engine/keyman32/kmprocessactions.cpp +++ b/windows/src/engine/keyman32/kmprocessactions.cpp @@ -45,15 +45,8 @@ static BOOL processPersistOpt( { // Allocate for 1 option plus 1 pad struct of 0's for KM_KBP_IT_END km_kbp_option_item keyboardOpts[2] = { 0 }; - - km_kbp_cp* cp = new km_kbp_cp[sizeof(actionItem->option->key) + 1]; - wcscpy_s(reinterpret_cast(cp), sizeof(actionItem->option->key) + 1, reinterpret_cast(actionItem->option->key)); - keyboardOpts[0].key = cp; - - cp = new km_kbp_cp[sizeof(actionItem->option->value) + 1]; - wcscpy_s(reinterpret_cast(cp), sizeof(actionItem->option->value) + 1, reinterpret_cast(actionItem->option->value)); - keyboardOpts[0].value = cp; - keyboardOpts[1] = KM_KBP_OPTIONS_END; + keyboardOpts[0].key = actionItem->option->key; + keyboardOpts[0].value = actionItem->option->value; km_kbp_status eventStatus = (km_kbp_status_codes)km_kbp_state_options_update(keyboardState, keyboardOpts); if (eventStatus != KM_KBP_STATUS_OK) { @@ -61,10 +54,6 @@ static BOOL processPersistOpt( SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessHook: Error %d saving option for keyboard [%s].", eventStatus, activeKeyboard->Name); } - for (int i = 0; i < 2; i++) { - delete[] keyboardOpts[i].key; - delete[] keyboardOpts[i].value; - } // Put the keyboard option into Windows Registry if (actionItem->option != NULL && actionItem->option->key != NULL && actionItem->option->value != NULL) @@ -96,7 +85,7 @@ BOOL ProcessActions(BOOL* emitKeyStroke) // Process the action items from the core. This actions will modify the windows context (AppContext). // Therefore it is not required to copy the context from the core to the windows context. - for (auto act = km_kbp_state_action_items(_td->lpActiveKeyboard->lpActiveKBState, nullptr); act->type != KM_KBP_IT_END; act++) { + for (auto act = km_kbp_state_action_items(_td->lpActiveKeyboard->lpCoreKeyboardState, nullptr); act->type != KM_KBP_IT_END; act++) { BOOL continueProcessingActions = TRUE; switch (act->type) { case KM_KBP_IT_CHAR: @@ -112,14 +101,14 @@ BOOL ProcessActions(BOOL* emitKeyStroke) continueProcessingActions = processBack(_td->app, act); break; case KM_KBP_IT_PERSIST_OPT: - continueProcessingActions = processPersistOpt(act, _td->lpActiveKeyboard->lpActiveKBState, _td->lpActiveKeyboard); + continueProcessingActions = processPersistOpt(act, _td->lpActiveKeyboard->lpCoreKeyboardState, _td->lpActiveKeyboard); break; case KM_KBP_IT_EMIT_KEYSTROKE: *emitKeyStroke = TRUE; continueProcessingActions = TRUE; break; case KM_KBP_IT_INVALIDATE_CONTEXT: - continueProcessingActions = processInvalidateContext(_td->app, _td->lpActiveKeyboard->lpActiveKBState); + continueProcessingActions = processInvalidateContext(_td->app, _td->lpActiveKeyboard->lpCoreKeyboardState); break; case KM_KBP_IT_END: // fallthrough diff --git a/windows/src/engine/keyman32/selectkeyboard.cpp b/windows/src/engine/keyman32/selectkeyboard.cpp index 16aae7bbf7..b26fbefa33 100644 --- a/windows/src/engine/keyman32/selectkeyboard.cpp +++ b/windows/src/engine/keyman32/selectkeyboard.cpp @@ -89,7 +89,7 @@ BOOL SelectKeyboardCore(DWORD KeymanID) { if (_td->lpKeyboards[i].KeymanID == KeymanID) { - if (!_td->lpKeyboards[i].coreKeyboard && !LoadlpKeyboard(i)) + if (!_td->lpKeyboards[i].lpCoreKeyboard && !LoadlpKeyboard(i)) { SendDebugMessageFormat(hwnd, sdmGlobal, 0, "SelectKeyboardCore: Unable to load"); return TRUE; diff --git a/windows/src/engine/kmtip/kmtip.h b/windows/src/engine/kmtip/kmtip.h index 793e1388a3..aabe098b8b 100644 --- a/windows/src/engine/kmtip/kmtip.h +++ b/windows/src/engine/kmtip/kmtip.h @@ -2,10 +2,10 @@ Name: kmtip Copyright: Copyright (C) SIL International. Documentation: - Description: - Create Date: 11 Dec 2009 + Description: CKMTipTextService declaration. + Create Date: 7 Sep 2009 - Modified Date: 23 Feb 2016 + Modified Date: 27 Jan 2015 Authors: mcdurdin Related Files: Dependencies: diff --git a/windows/src/engine/kmtip/kmtip.vcxproj b/windows/src/engine/kmtip/kmtip.vcxproj index 9601065d67..c19f306a62 100644 --- a/windows/src/engine/kmtip/kmtip.vcxproj +++ b/windows/src/engine/kmtip/kmtip.vcxproj @@ -104,18 +104,7 @@ kmtip64 kmtip64 - - $(IncludePath) - - - $(IncludePath) - - - $(IncludePath) - - - $(IncludePath) - + NDEBUG;%(PreprocessorDefinitions) @@ -438,4 +427,4 @@ - + \ No newline at end of file diff --git a/windows/src/global/inc/keymanengine.h b/windows/src/global/inc/keymanengine.h index 948c2086ab..03d8f3d62d 100644 --- a/windows/src/global/inc/keymanengine.h +++ b/windows/src/global/inc/keymanengine.h @@ -87,9 +87,9 @@ typedef struct tagINTKEYBOARDINFO LPINTKEYBOARDOPTIONS KeyboardOptions; int nProfiles; LPINTKEYBOARDPROFILE Profiles; - km_kbp_keyboard* coreKeyboard; - km_kbp_option_item* coreKeyboardOptions; - km_kbp_state* lpActiveKBState; + km_kbp_keyboard* lpCoreKeyboard; + km_kbp_option_item* lpCoreKeyboardOptions; + km_kbp_state* lpCoreKeyboardState; } INTKEYBOARDINFO, * LPINTKEYBOARDINFO; typedef struct tagINI @@ -127,6 +127,8 @@ LRESULT CALLBACK kmnLowLevelKeyboardProc( // I4124 ); BOOL ReleaseKeyboardMemory(LPKEYBOARD kbd); +BOOL ReleaseStateMemoryCore(km_kbp_state** state); +BOOL ReleaseKeyboardMemoryCore(km_kbp_keyboard** kbd); void PostGETNEXT(HWND hwnd); BOOL CompareMsg(LPMSG MsgA, LPMSG MsgB); @@ -167,6 +169,8 @@ void PostDummyKeyEvent(); // I3301 - Handle I3250 regression with inadvertent m /* Debugging functions */ +BOOL IsDebugAssertEnabled(); + #ifndef SendDebugMessage // I4379 typedef enum ATSDMState { sdmInternat, sdmAIDefault, sdmMessage, sdmKeyboard, sdmGlobal, sdmMenu, sdmDebug, sdmLoad, sdmOther } TSDMState; @@ -192,6 +196,27 @@ char* Debug_UnicodeString(PWSTR s, int x = 0); BOOL ShouldDebug_1(); // TSDMState state); +#define DebugAssertRetValue(condition, message, retValue) \ + { \ + if (!(condition)) { \ + SendDebugMessage_1(0, sdmGlobal, 0, __FILE__, __LINE__, message); \ + if (IsDebugAssertEnabled()) { \ + assert(condition); \ + } \ + return retValue; \ + } \ + } + +#define DebugAssert(condition, message) \ + { \ + if (!(condition)) { \ + SendDebugMessage_1(0, sdmGlobal, 0, __FILE__, __LINE__, message); \ + if (IsDebugAssertEnabled()) { \ + assert(condition); \ + } \ + return; \ + } \ + } #endif #ifdef _DEBUG diff --git a/windows/src/global/inc/registry.h b/windows/src/global/inc/registry.h index 78399da1d7..307ce061f9 100644 --- a/windows/src/global/inc/registry.h +++ b/windows/src/global/inc/registry.h @@ -140,7 +140,7 @@ #define REGSZ_AutomaticallyReportErrors "automatically report errors" // CU, SRegKey_IDEOptions and SRegKey_KeymanEngine_CU #define REGSZ_AutomaticallyReportUsage "automatically report usage" // CU, SRegKey_IDEOptions and SRegKey_KeymanEngine_CU -#define REGDW_CoreIntegration "use common core" // Turns on the common core - instead of windows core +#define REGSZ_CoreIntegration "use common core" // Turns on the common core - instead of windows core /* Splitting Registry into ReadOnly and FullAccess makes it much easier to ensure that we are using the registry correctly -- readonly wherever possible. */ From 0663fcbeb7645c7ddaccc3d52862afa2b0f02b89 Mon Sep 17 00:00:00 2001 From: Ross Date: Fri, 27 Aug 2021 14:18:14 +1000 Subject: [PATCH 27/63] feat(windows): Add unit tests for process actions --- windows/src/engine/keyman32/K32_load.cpp | 3 + windows/src/engine/keyman32/Keyman32.cpp | 2 + .../keyman-engine-tests.vcxproj | 1 + .../kmprocessactionstests.cpp | 209 ++++++++++++++++++ windows/src/global/inc/keymanengine.h | 2 + 5 files changed, 217 insertions(+) create mode 100644 windows/src/engine/keyman32/tests/keyman-engine-tests/kmprocessactionstests.cpp diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index 9233da3b25..febb506616 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -86,6 +86,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"); km_kbp_state_dispose(_td->lpKeyboards[i].lpCoreKeyboardState); _td->lpKeyboards[i].lpCoreKeyboardState = NULL; } @@ -111,6 +112,8 @@ 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); + // Dispose of the keyboard to leave us in a consitent state + ReleaseKeyboardMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboard); return FALSE; } diff --git a/windows/src/engine/keyman32/Keyman32.cpp b/windows/src/engine/keyman32/Keyman32.cpp index 097543bbb3..c810dfe676 100644 --- a/windows/src/engine/keyman32/Keyman32.cpp +++ b/windows/src/engine/keyman32/Keyman32.cpp @@ -583,6 +583,8 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_ForceKeyboard(PCSTR FileName 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; } LoadKeyboardOptionsREGCore(_td->lpActiveKeyboard, _td->lpActiveKeyboard->lpCoreKeyboardState); diff --git a/windows/src/engine/keyman32/tests/keyman-engine-tests/keyman-engine-tests.vcxproj b/windows/src/engine/keyman32/tests/keyman-engine-tests/keyman-engine-tests.vcxproj index 4931f7e718..7014ad359a 100644 --- a/windows/src/engine/keyman32/tests/keyman-engine-tests/keyman-engine-tests.vcxproj +++ b/windows/src/engine/keyman32/tests/keyman-engine-tests/keyman-engine-tests.vcxproj @@ -59,6 +59,7 @@ + Create Create diff --git a/windows/src/engine/keyman32/tests/keyman-engine-tests/kmprocessactionstests.cpp b/windows/src/engine/keyman32/tests/keyman-engine-tests/kmprocessactionstests.cpp new file mode 100644 index 0000000000..66c5fc3206 --- /dev/null +++ b/windows/src/engine/keyman32/tests/keyman-engine-tests/kmprocessactionstests.cpp @@ -0,0 +1,209 @@ +#include "pch.h" +#include "kmprocessactions.cpp" + +// Test the Process Actions private functions +// Note: The following actions are not tested KM_KBP_IT_ALERT, KM_KBP_IT_PERSIST_OPT, KM_KBP_IT_EMIT_KEYSTROKE + +// KM_KBP_IT_CHAR - processUnicodeChar + TEST(AITIP, processUnicodeChartest) { + Globals_InitProcess(); + + WCHAR callbuf[MAXCONTEXT]; + AITIP testApp; + WCHAR *expectedContext = L"A"; + const km_kbp_action_item *actionItem; + km_kbp_action_item itemAddChar = { + KM_KBP_IT_CHAR, + { + 0, + }, + {'A'}}; + + processUnicodeChar(&testApp, &itemAddChar); + WCHAR *contextBuf = testApp.ContextBufMax(MAXCONTEXT); + EXPECT_STREQ(contextBuf, expectedContext); + + km_kbp_usv testSurrogateChar = Uni_SurrogateToUTF32(0xD801, 0xDC37); //𐐷'; + km_kbp_action_item itemAddChar2 = { + KM_KBP_IT_CHAR, + { + 0, + }, + {testSurrogateChar}}; + WCHAR expectedStringSurrogate[] = {'A', 0xD801, 0xDC37, 0}; + processUnicodeChar(&testApp, &itemAddChar2); + contextBuf = testApp.ContextBufMax(MAXCONTEXT); + EXPECT_STREQ(contextBuf, &expectedStringSurrogate[0]); + + UninitialiseProcess(FALSE); + Globals_UninitProcess(); +} + +// KM_KBP_IT_MARKER - processMarker Deadkey +TEST(AITIP, processMarkertest) { + Globals_InitProcess(); + + WCHAR callbuf[MAXCONTEXT]; + AITIP testApp; + WCHAR expectedContext[] = {UC_SENTINEL, CODE_DEADKEY, 2, 0}; + const km_kbp_action_item *actionItem; + uintptr_t marker = 2; + km_kbp_action_item itemAddMarker = { + KM_KBP_IT_MARKER, + { + 0, + }, + {marker}}; + processMarker(&testApp, &itemAddMarker); + WCHAR *contextBuf = testApp.ContextBufMax(MAXCONTEXT); + EXPECT_STREQ(contextBuf, expectedContext); + + UninitialiseProcess(FALSE); + Globals_UninitProcess(); +} + +// KM_KBP_IT_BACK - processBack +// First test processing a backspace for a deadkey +TEST(AITIP, processBackDeadkeytest) { + Globals_InitProcess(); + Globals_InitThread(); + + WCHAR callbuf[MAXCONTEXT]; + AITIP testApp; + WCHAR expectedContext[] = {'A', 0}; + + km_kbp_action_item itemAddChar = { + KM_KBP_IT_CHAR, + { + 0, + }, + {'A'}}; + processUnicodeChar(&testApp, &itemAddChar); + uintptr_t marker = 2; + km_kbp_action_item itemAddMarker = { + KM_KBP_IT_MARKER, + { + 0, + }, + {marker}}; + processMarker(&testApp, &itemAddMarker); + km_kbp_action_item itemBackSpace = {KM_KBP_IT_BACK}; + itemBackSpace.backspace.expected_type = KM_KBP_IT_MARKER; + itemBackSpace.backspace.expected_value = marker; + processBack(&testApp, &itemBackSpace); + WCHAR *contextBuf = testApp.ContextBufMax(MAXCONTEXT); + EXPECT_STREQ(contextBuf, expectedContext); + + UninitialiseProcess(FALSE); + Globals_UninitProcess(); +} + +// KM_KBP_IT_BACK - processBack +// Press Backspace for a normal character +// Also test for Unknown Character +TEST(AITIP, processBackCharactertest) { + Globals_InitProcess(); + Globals_InitThread(); + + WCHAR callbuf[MAXCONTEXT]; + AITIP testApp; + WCHAR expectedContext[] = {'A', 0}; + WCHAR expectedContextFinal[] = {0}; + + km_kbp_action_item itemAddChar = { + KM_KBP_IT_CHAR, + { + 0, + }, + {'A'}}; + processUnicodeChar(&testApp, &itemAddChar); + itemAddChar.character = 'B'; + processUnicodeChar(&testApp, &itemAddChar); + km_kbp_action_item itemBackSpace = {KM_KBP_IT_BACK}; + itemBackSpace.backspace.expected_type = KM_KBP_IT_CHAR; + itemBackSpace.backspace.expected_value = 'B'; + // backspace + processBack(&testApp, &itemBackSpace); + WCHAR *contextBuf = testApp.ContextBufMax(MAXCONTEXT); + EXPECT_STREQ(contextBuf, expectedContext); + // backspace for unknown it should backspace a character + itemBackSpace.type = KM_KBP_BT_UNKNOWN; + processBack(&testApp, &itemBackSpace); + contextBuf = testApp.ContextBufMax(MAXCONTEXT); + EXPECT_STREQ(contextBuf, expectedContextFinal); + + UninitialiseProcess(FALSE); + Globals_UninitProcess(); +} + +// KM_KBP_IT_BACK - processBack +// Press Backspace for a character doesn't match expected character +// Note currently we don't check for a character match this should be updated +TEST(AITIP, processBackUnexpectedChartest) { + Globals_InitProcess(); + Globals_InitThread(); + + WCHAR callbuf[MAXCONTEXT]; + AITIP testApp; + WCHAR expectedContext[] = {'A', 0}; + + km_kbp_action_item itemAddChar = { + KM_KBP_IT_CHAR, + { + 0, + }, + {'A'}}; + processUnicodeChar(&testApp, &itemAddChar); + itemAddChar.character = 'C'; + processUnicodeChar(&testApp, &itemAddChar); + km_kbp_action_item itemBackSpace = {KM_KBP_IT_BACK}; + itemBackSpace.backspace.expected_type = KM_KBP_IT_CHAR; + itemBackSpace.backspace.expected_value = 'B'; + // backspace + processBack(&testApp, &itemBackSpace); + WCHAR *contextBuf = testApp.ContextBufMax(MAXCONTEXT); + EXPECT_STREQ(contextBuf, expectedContext); + + UninitialiseProcess(FALSE); + Globals_UninitProcess(); +} + +// KM_KBP_IT_INVALIDATE_CONTEXT - processInvalidateContext +TEST(AITIP, processInvalidateContextTest) { + Globals_InitProcess(); + Globals_InitThread(); + + WCHAR callbuf[MAXCONTEXT]; + AITIP testApp; + WCHAR expectedContext[] = {0}; + + km_kbp_action_item itemAddChar = { + KM_KBP_IT_CHAR, + { + 0, + }, + {'A'}}; + processUnicodeChar(&testApp, &itemAddChar); + itemAddChar.character = 'B'; + processUnicodeChar(&testApp, &itemAddChar); + + // A keyboard a state is need to test processInvalidateContext + km_kbp_option_item test_env_opts[] = {{u"hello", u"world", 0}, KM_KBP_OPTIONS_END}; + km_kbp_keyboard *testKB = nullptr; + km_kbp_state *testState = nullptr, *test_clone = nullptr; + km_kbp_path_name dummyPath = L"dummyActions.mock"; + km_kbp_status err_status = km_kbp_keyboard_load(dummyPath, &testKB); + EXPECT_EQ(km_kbp_keyboard_load(dummyPath, &testKB), KM_KBP_STATUS_OK); + EXPECT_EQ(km_kbp_state_create(testKB, test_env_opts, &testState), KM_KBP_STATUS_OK); + + processInvalidateContext(&testApp,testState); + WCHAR *contextBuf = testApp.ContextBufMax(MAXCONTEXT); + EXPECT_STREQ(contextBuf, expectedContext); + + // dispose keyboard + km_kbp_state_dispose(testState); + km_kbp_keyboard_dispose(testKB); + + UninitialiseProcess(FALSE); + Globals_UninitProcess(); +} diff --git a/windows/src/global/inc/keymanengine.h b/windows/src/global/inc/keymanengine.h index 03d8f3d62d..dd0dfe78f8 100644 --- a/windows/src/global/inc/keymanengine.h +++ b/windows/src/global/inc/keymanengine.h @@ -196,6 +196,8 @@ char* Debug_UnicodeString(PWSTR s, int x = 0); BOOL ShouldDebug_1(); // TSDMState state); +// On failed condition it will always log "message" and return "retValue" +// it will also assert if a debugger is attached for a debug build. #define DebugAssertRetValue(condition, message, retValue) \ { \ if (!(condition)) { \ From e125736e0e4f6826cc90c627dcfd535151a80a3f Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 30 Aug 2021 10:18:57 +1000 Subject: [PATCH 28/63] feat(windows): Update all TODOs with Issue numbers --- windows/src/engine/keyman32/K32_load.cpp | 2 +- windows/src/engine/keyman32/Keyman32.cpp | 5 +- windows/src/engine/keyman32/appint/aiTIP.cpp | 1 - windows/src/engine/keyman32/kmprocess.cpp | 6 +- .../src/engine/keyman32/selectkeyboard.cpp | 4 +- .../kmprocessactionstests.cpp | 61 +++---------------- 6 files changed, 18 insertions(+), 61 deletions(-) diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index febb506616..c414823112 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -101,7 +101,7 @@ BOOL LoadlpKeyboardCore(int i) return FALSE; } - // TODO: 5442 handle dlls + // TODO: 5650 handle dlls //LoadDLLs(&_td->lpKeyboards[i]); const km_kbp_option_item test_env_opts[] = { diff --git a/windows/src/engine/keyman32/Keyman32.cpp b/windows/src/engine/keyman32/Keyman32.cpp index c810dfe676..45aeb01817 100644 --- a/windows/src/engine/keyman32/Keyman32.cpp +++ b/windows/src/engine/keyman32/Keyman32.cpp @@ -575,7 +575,7 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_ForceKeyboard(PCSTR FileName return FALSE; } SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard Core: %s OK", FileName); // TODO: 5442 - remove word Core - + // TODO: #5650 Equivalent for common core // LoadDLLs(&_td->lpKeyboards[i]); const km_kbp_option_item test_env_opts[] = {KM_KBP_OPTIONS_END}; err_status = @@ -587,6 +587,9 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_ForceKeyboard(PCSTR FileName ReleaseKeyboardMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboard); return FALSE; } + // TODO: 5650 LoadDLLs + // TODO: 5652 verify - ResetCapsLock(); + ResetCapsLock(); LoadKeyboardOptionsREGCore(_td->lpActiveKeyboard, _td->lpActiveKeyboard->lpCoreKeyboardState); RefreshPreservedKeys(TRUE); return TRUE; diff --git a/windows/src/engine/keyman32/appint/aiTIP.cpp b/windows/src/engine/keyman32/appint/aiTIP.cpp index 53953f1d4e..e9113e3b46 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.cpp +++ b/windows/src/engine/keyman32/appint/aiTIP.cpp @@ -208,7 +208,6 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM _td->state.vkey = (WORD) wParam; if (isUsingCoreProcessor) { - // TODO: 5442 set the correct active keyboard - need with call backs _td->state.lpCoreKb = _td->lpActiveKeyboard->lpCoreKeyboard; } else { diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index df6f823aeb..3aa43f2713 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -140,9 +140,7 @@ BOOL ProcessHook() else _td->app->QueueDebugInformation(QID_BEGIN_ANSI, NULL, NULL, NULL, NULL, (DWORD_PTR) &keyinfo); } - // TODO: 5011 remove debug message - // PWSTR contextTestBuf = _td->app->ContextBufMax(MAXCONTEXT); - // SendDebugMessageFormat(0, sdmAIDefault, 0, "Kmprocess::ProcessHook Before cxt=%s", Debug_UnicodeString(contextTestBuf, 1)); + if (isUsingCoreProcessor) { SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessActions: "); @@ -166,8 +164,6 @@ BOOL ProcessHook() ProcessActions(&fOutputKeystroke); } else { - // TODO: 5011 remove debug message - SendDebugMessageFormat(0, sdmGlobal, 0,"ProcessGroup: "); ProcessGroup(gp); // TODO: 5442 remove } diff --git a/windows/src/engine/keyman32/selectkeyboard.cpp b/windows/src/engine/keyman32/selectkeyboard.cpp index b26fbefa33..02fd5bc5eb 100644 --- a/windows/src/engine/keyman32/selectkeyboard.cpp +++ b/windows/src/engine/keyman32/selectkeyboard.cpp @@ -78,7 +78,7 @@ BOOL SelectKeyboardCore(DWORD KeymanID) } KMHideIM(); - /** TODO: 5011 is this just IDML dlls */ + // TODO: 5650 Equivalent for core keyboard IDML dlls 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(); - // TODO: 5011 + // TODO: 5650 Equivalent for corekeyboard //ActivateDLLs(_td->lpActiveKeyboard); return TRUE; diff --git a/windows/src/engine/keyman32/tests/keyman-engine-tests/kmprocessactionstests.cpp b/windows/src/engine/keyman32/tests/keyman-engine-tests/kmprocessactionstests.cpp index 66c5fc3206..70fe802bdc 100644 --- a/windows/src/engine/keyman32/tests/keyman-engine-tests/kmprocessactionstests.cpp +++ b/windows/src/engine/keyman32/tests/keyman-engine-tests/kmprocessactionstests.cpp @@ -11,25 +11,14 @@ WCHAR callbuf[MAXCONTEXT]; AITIP testApp; WCHAR *expectedContext = L"A"; - const km_kbp_action_item *actionItem; - km_kbp_action_item itemAddChar = { - KM_KBP_IT_CHAR, - { - 0, - }, - {'A'}}; + km_kbp_action_item itemAddChar = { KM_KBP_IT_CHAR, {0,}, {'A'}}; processUnicodeChar(&testApp, &itemAddChar); WCHAR *contextBuf = testApp.ContextBufMax(MAXCONTEXT); EXPECT_STREQ(contextBuf, expectedContext); km_kbp_usv testSurrogateChar = Uni_SurrogateToUTF32(0xD801, 0xDC37); //𐐷'; - km_kbp_action_item itemAddChar2 = { - KM_KBP_IT_CHAR, - { - 0, - }, - {testSurrogateChar}}; + km_kbp_action_item itemAddChar2 = {KM_KBP_IT_CHAR, {0,}, {testSurrogateChar}}; WCHAR expectedStringSurrogate[] = {'A', 0xD801, 0xDC37, 0}; processUnicodeChar(&testApp, &itemAddChar2); contextBuf = testApp.ContextBufMax(MAXCONTEXT); @@ -46,14 +35,9 @@ TEST(AITIP, processMarkertest) { WCHAR callbuf[MAXCONTEXT]; AITIP testApp; WCHAR expectedContext[] = {UC_SENTINEL, CODE_DEADKEY, 2, 0}; - const km_kbp_action_item *actionItem; uintptr_t marker = 2; - km_kbp_action_item itemAddMarker = { - KM_KBP_IT_MARKER, - { - 0, - }, - {marker}}; + km_kbp_action_item itemAddMarker = {KM_KBP_IT_MARKER, {0,}, {marker}}; + processMarker(&testApp, &itemAddMarker); WCHAR *contextBuf = testApp.ContextBufMax(MAXCONTEXT); EXPECT_STREQ(contextBuf, expectedContext); @@ -71,21 +55,11 @@ TEST(AITIP, processBackDeadkeytest) { WCHAR callbuf[MAXCONTEXT]; AITIP testApp; WCHAR expectedContext[] = {'A', 0}; - - km_kbp_action_item itemAddChar = { - KM_KBP_IT_CHAR, - { - 0, - }, - {'A'}}; + km_kbp_action_item itemAddChar = {KM_KBP_IT_CHAR, {0,}, {'A'}}; + processUnicodeChar(&testApp, &itemAddChar); uintptr_t marker = 2; - km_kbp_action_item itemAddMarker = { - KM_KBP_IT_MARKER, - { - 0, - }, - {marker}}; + km_kbp_action_item itemAddMarker = {KM_KBP_IT_MARKER, {0,}, {marker}}; processMarker(&testApp, &itemAddMarker); km_kbp_action_item itemBackSpace = {KM_KBP_IT_BACK}; itemBackSpace.backspace.expected_type = KM_KBP_IT_MARKER; @@ -109,13 +83,8 @@ TEST(AITIP, processBackCharactertest) { AITIP testApp; WCHAR expectedContext[] = {'A', 0}; WCHAR expectedContextFinal[] = {0}; + km_kbp_action_item itemAddChar = {KM_KBP_IT_CHAR, {0,}, {'A'}}; - km_kbp_action_item itemAddChar = { - KM_KBP_IT_CHAR, - { - 0, - }, - {'A'}}; processUnicodeChar(&testApp, &itemAddChar); itemAddChar.character = 'B'; processUnicodeChar(&testApp, &itemAddChar); @@ -146,13 +115,8 @@ TEST(AITIP, processBackUnexpectedChartest) { WCHAR callbuf[MAXCONTEXT]; AITIP testApp; WCHAR expectedContext[] = {'A', 0}; + km_kbp_action_item itemAddChar = {KM_KBP_IT_CHAR, {0,}, {'A'}}; - km_kbp_action_item itemAddChar = { - KM_KBP_IT_CHAR, - { - 0, - }, - {'A'}}; processUnicodeChar(&testApp, &itemAddChar); itemAddChar.character = 'C'; processUnicodeChar(&testApp, &itemAddChar); @@ -176,13 +140,8 @@ TEST(AITIP, processInvalidateContextTest) { WCHAR callbuf[MAXCONTEXT]; AITIP testApp; WCHAR expectedContext[] = {0}; + km_kbp_action_item itemAddChar = {KM_KBP_IT_CHAR, {0,}, {'A'}}; - km_kbp_action_item itemAddChar = { - KM_KBP_IT_CHAR, - { - 0, - }, - {'A'}}; processUnicodeChar(&testApp, &itemAddChar); itemAddChar.character = 'B'; processUnicodeChar(&testApp, &itemAddChar); From 5ffb136acf5f20ac2197fddc564e5e98c2c20113 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 2 Sep 2021 11:57:44 +1000 Subject: [PATCH 29/63] feat(windows): Added UpdateKeyboardOptions This functions was to update the keyboard options in the windows engine with the current options in the core However it is not needed as first thought. This is because the options will not be updated in first Non updatable call kmtip. This is due to the fact the actions will not be processed. A variation on the current core implementation. I am still pushing the branch as the unit test will be usefull. --- .../core/desktop/src/km_kbp_options_api.cpp | 4 +- .../src/engine/keyman32/keyboardoptions.cpp | 45 ++++++++++++++++--- windows/src/engine/keyman32/keyboardoptions.h | 1 + .../keyman-engine-tests.vcxproj | 1 + 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/common/core/desktop/src/km_kbp_options_api.cpp b/common/core/desktop/src/km_kbp_options_api.cpp index 1a82877c1c..74a39b7ddb 100644 --- a/common/core/desktop/src/km_kbp_options_api.cpp +++ b/common/core/desktop/src/km_kbp_options_api.cpp @@ -25,7 +25,9 @@ km_kbp_options_list_size(km_kbp_option_item const *opts) if (!opts) return 0; auto n = 0; - while (opts->key) ++n; + for (; opts->key; ++opts) + ++n; + return n; } diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index d7ea003a65..acfa9d34cb 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -252,6 +252,7 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* keyboardOpts[n].value = cp; } n++; + // TODO: 5653 check that n doesn't exceed the listSize from the keyboard. } keyboardOpts[n] = KM_KBP_OPTIONS_END; @@ -261,13 +262,45 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* SendDebugMessageFormat( 0, sdmKeyboard, 0, "LoadKeyboardOptionsREGCore: km_kbp_state_options_update failed with error status [%d]", err_status); } - - for (int i = 0; i < (int)listSize + 1; i++) { - delete[] keyboardOpts[i].key; - delete[] keyboardOpts[i].value; - } - delete[] keyboardOpts; + // TODO: 5653 let maintain a copy of the keyboard core here + kp->lpCoreKeyboardOptions = keyboardOpts; + //for (int i = 0; i < (int)listSize + 1; i++) { + // delete[] keyboardOpts[i].key; + // delete[] keyboardOpts[i].value; + // } + // delete[] keyboardOpts; return TRUE; } + // TODO: 5653 free the memory. return FALSE; } + + +// call this get curret options +BOOL +UpdateKeyboardOptions(km_kbp_state* const kpState, km_kbp_option_item *kbOptions) { + + int listSize = km_kbp_options_list_size(kbOptions); + // 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. + + km_kbp_cp const* retValue = nullptr; + for (int i = 0; i < listSize; i++) { + km_kbp_status err_status = km_kbp_state_option_lookup(kpState, kbOptions[i].scope, kbOptions[i].key, + &retValue); + if (err_status != KM_KBP_STATUS_OK) { + SendDebugMessageFormat( + 0, sdmKeyboard, 0, "SaveCoreOptions: 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(kbOptions[i].value)) != 0) { + //delete kbOptions[i].value; + LPCWSTR val = reinterpret_cast(retValue); + km_kbp_cp* cp = new km_kbp_cp[wcslen(val) + 1]; + wcscpy_s(reinterpret_cast(cp), wcslen(val) + 1, val); + kbOptions[i].value = cp; + } + } + return TRUE; +} diff --git a/windows/src/engine/keyman32/keyboardoptions.h b/windows/src/engine/keyman32/keyboardoptions.h index 1de2ae47e4..a20609077f 100644 --- a/windows/src/engine/keyman32/keyboardoptions.h +++ b/windows/src/engine/keyman32/keyboardoptions.h @@ -22,6 +22,7 @@ void SetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSet, int nStoreToRead); void ResetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToReset); void SaveKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSave); void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp); +BOOL UpdateKeyboardOptions(km_kbp_state* const kpState, km_kbp_option_item *kbOptions); /* Common core integration functions */ diff --git a/windows/src/engine/keyman32/tests/keyman-engine-tests/keyman-engine-tests.vcxproj b/windows/src/engine/keyman32/tests/keyman-engine-tests/keyman-engine-tests.vcxproj index 7014ad359a..c3a28664a3 100644 --- a/windows/src/engine/keyman32/tests/keyman-engine-tests/keyman-engine-tests.vcxproj +++ b/windows/src/engine/keyman32/tests/keyman-engine-tests/keyman-engine-tests.vcxproj @@ -59,6 +59,7 @@ + Create From 8719a27ee92f56a8e7a0056945ff86d26e2abc0f Mon Sep 17 00:00:00 2001 From: Ross Date: Fri, 3 Sep 2021 13:45:18 +1000 Subject: [PATCH 30/63] feat(windows): add save and restore options Add save and restore methods for saving and restoring keyboard processor options. --- windows/src/engine/keyman32/appint/aiTIP.cpp | 30 ++++-- .../src/engine/keyman32/keyboardoptions.cpp | 92 ++++++++++++++----- windows/src/engine/keyman32/keyboardoptions.h | 32 ++++++- .../keyboardoptionstests.cpp | 72 +++++++++++++++ 4 files changed, 197 insertions(+), 29 deletions(-) create mode 100644 windows/src/engine/keyman32/tests/keyman-engine-tests/keyboardoptionstests.cpp diff --git a/windows/src/engine/keyman32/appint/aiTIP.cpp b/windows/src/engine/keyman32/appint/aiTIP.cpp index e9113e3b46..fed3936e24 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.cpp +++ b/windows/src/engine/keyman32/appint/aiTIP.cpp @@ -226,17 +226,29 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM _td->TIPGetContext = ctfunc; AppContextWithStores *savedContext = NULL; // I4370 // I4978 - AppContext *savedContextUsingCore = NULL; // used for common core - + AppContext *savedContextUsingCore = NULL; // used for common core + km_kbp_option_item *SavedKBDOptions = NULL; // used for common core if (!Updateable) { if (isUsingCoreProcessor) { savedContextUsingCore = new AppContext(); _td->app->CopyContext(savedContextUsingCore); + SavedKBDOptions = SaveKeyboardOptionsCore(_td->lpActiveKeyboard); + // TODO: 5653 ---- Alternate option --- + // Instead of allocating memory for each option + // just update the changed options. Consider the commented out method UpdateCoreKeyboard + // options. + /*if (_td->lpActiveKeyboard->lpCoreKeyboardOptions) { + UpdateKeyboardOptionsCore(_td->lpActiveKeyboard->lpCoreKeyboardState, _td->lpActiveKeyboard->lpCoreKeyboardOptions); + } else { + _td->lpActiveKeyboard->lpCoreKeyboardOptions = SaveKeyboardOptionsCore(_td->lpActiveKeyboard); + }*/ + //////// End alternate option } else { // I4370 savedContext = new AppContextWithStores(_td->lpActiveKeyboard->Keyboard->cxStoreArray); // I4978 _td->app->SaveContext(savedContext); } } + BOOL res = ProcessHook(); if (!Updateable) { @@ -244,16 +256,22 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM if (res) { // Reset the context if match found _td->app->RestoreContextOnly(savedContextUsingCore); + RestoreKeyboardOptionsCore(_td->lpActiveKeyboard->lpCoreKeyboardState, SavedKBDOptions); + delete SavedKBDOptions; + SavedKBDOptions = NULL; + // TODO: 5653 ---- Alternate option --- Instead of allocating memory for each option + //RestoreKeyboardOptionsCore(_td->lpActiveKeyboard->lpCoreKeyboardState, _td->lpActiveKeyboard->lpCoreKeyboardOptions); + /// --- End Alternate option + delete savedContextUsingCore; + savedContextUsingCore = NULL; } - delete savedContextUsingCore; - savedContextUsingCore = NULL; } else { // I4370 if (res) { // I4585 // Reset the context if match found _td->app->RestoreContext(savedContext); + delete savedContext; + savedContext = NULL; } - delete savedContext; - savedContext = NULL; } } diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index acfa9d34cb..98489c8145 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -24,6 +24,13 @@ 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); +static km_kbp_cp* CloneKMKBPCP(const km_kbp_cp* cp) { + LPCWSTR buf = reinterpret_cast(cp); + km_kbp_cp* clone = new km_kbp_cp[wcslen(buf) + 1]; + wcscpy_s(reinterpret_cast(clone), wcslen(buf) + 1, buf); + return clone; +} + void LoadKeyboardOptions(LPINTKEYBOARDINFO kp) { // I3594 IntLoadKeyboardOptions(REGSZ_KeyboardOptions, kp); @@ -233,7 +240,7 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* size_t listSize = km_kbp_options_list_size(keyboardAttrs->default_options); km_kbp_option_item* keyboardOpts = new km_kbp_option_item[listSize+1]; - while (r.GetValueNames(buf, sizeof(buf) / sizeof(buf[0]), n)) + while ((r.GetValueNames(buf, sizeof(buf) / sizeof(buf[0]), n)) && (n < (int)listSize)) { buf[255] = 0; WCHAR val[256]; @@ -252,7 +259,6 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* keyboardOpts[n].value = cp; } n++; - // TODO: 5653 check that n doesn't exceed the listSize from the keyboard. } keyboardOpts[n] = KM_KBP_OPTIONS_END; @@ -262,31 +268,28 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* SendDebugMessageFormat( 0, sdmKeyboard, 0, "LoadKeyboardOptionsREGCore: km_kbp_state_options_update failed with error status [%d]", err_status); } - // TODO: 5653 let maintain a copy of the keyboard core here - kp->lpCoreKeyboardOptions = keyboardOpts; - //for (int i = 0; i < (int)listSize + 1; i++) { - // delete[] keyboardOpts[i].key; - // delete[] keyboardOpts[i].value; - // } - // delete[] keyboardOpts; + for (int i = 0; i < (int)listSize + 1; i++) { + delete[] keyboardOpts[i].key; + delete[] keyboardOpts[i].value; + } + delete[] keyboardOpts; return TRUE; } - // TODO: 5653 free the memory. return FALSE; } - -// call this get curret options BOOL -UpdateKeyboardOptions(km_kbp_state* const kpState, km_kbp_option_item *kbOptions) { +UpdateKeyboardOptionsCore( + km_kbp_state* const lpCoreKeyboardState, + km_kbp_option_item *lpCoreKeyboardOptions) { - int listSize = km_kbp_options_list_size(kbOptions); + int listSize = 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(kpState, kbOptions[i].scope, kbOptions[i].key, + 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( @@ -294,13 +297,58 @@ UpdateKeyboardOptions(km_kbp_state* const kpState, km_kbp_option_item *kbOptions continue; } // compare to see if changed - if (wcscmp(reinterpret_cast(retValue), reinterpret_cast(kbOptions[i].value)) != 0) { - //delete kbOptions[i].value; - LPCWSTR val = reinterpret_cast(retValue); - km_kbp_cp* cp = new km_kbp_cp[wcslen(val) + 1]; - wcscpy_s(reinterpret_cast(cp), wcslen(val) + 1, val); - kbOptions[i].value = cp; + 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, "LoadKeyboardOptionsREGCore: km_kbp_keyboard_get_attrs failed with error status [%d]", err_status); + return nullptr; + } + int listSize = 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, "SaveCoreOptions: 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, "LoadKeyboardOptionsREGCore: km_kbp_state_options_update failed with error status [%d]", err_status); + return FALSE; + } return TRUE; } diff --git a/windows/src/engine/keyman32/keyboardoptions.h b/windows/src/engine/keyman32/keyboardoptions.h index a20609077f..0002db3cf6 100644 --- a/windows/src/engine/keyman32/keyboardoptions.h +++ b/windows/src/engine/keyman32/keyboardoptions.h @@ -22,7 +22,37 @@ void SetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSet, int nStoreToRead); void ResetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToReset); void SaveKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSave); void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp); -BOOL UpdateKeyboardOptions(km_kbp_state* const kpState, km_kbp_option_item *kbOptions); +/** + * Updates the supplied Keyboard processor options list from the keyboard processor pointed + * to by the state pointer. + * + * @param lpCoreKeyboardState The core keyboardprocessor state which as 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 the keyboard info object that constains 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 from 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 */ diff --git a/windows/src/engine/keyman32/tests/keyman-engine-tests/keyboardoptionstests.cpp b/windows/src/engine/keyman32/tests/keyman-engine-tests/keyboardoptionstests.cpp new file mode 100644 index 0000000000..05a53381e0 --- /dev/null +++ b/windows/src/engine/keyman32/tests/keyman-engine-tests/keyboardoptionstests.cpp @@ -0,0 +1,72 @@ + +#include "pch.h" +#include +#include +#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); + 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); + + delete NewKBDOptions; + delete SavedKBDOptions; + delete kp; +} From f56c1839fdcada695b50298d063d5e7bd9af4e1c Mon Sep 17 00:00:00 2001 From: Ross Date: Fri, 3 Sep 2021 14:30:53 +1000 Subject: [PATCH 31/63] feat(windows): formating of km_kbp_options_list_size --- common/core/desktop/src/km_kbp_options_api.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/core/desktop/src/km_kbp_options_api.cpp b/common/core/desktop/src/km_kbp_options_api.cpp index 74a39b7ddb..3ca0cea617 100644 --- a/common/core/desktop/src/km_kbp_options_api.cpp +++ b/common/core/desktop/src/km_kbp_options_api.cpp @@ -25,9 +25,9 @@ km_kbp_options_list_size(km_kbp_option_item const *opts) if (!opts) return 0; auto n = 0; - for (; opts->key; ++opts) + for (; opts->key; ++opts){ ++n; - + } return n; } From a90a99784a346623116f4766f6c7af4814f8b678 Mon Sep 17 00:00:00 2001 From: Ross Date: Tue, 7 Sep 2021 12:00:34 +1000 Subject: [PATCH 32/63] feat(windows): cast size_t to int for list size --- windows/src/engine/keyman32/keyboardoptions.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index 98489c8145..1aa9dbcb84 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -283,7 +283,7 @@ UpdateKeyboardOptionsCore( km_kbp_state* const lpCoreKeyboardState, km_kbp_option_item *lpCoreKeyboardOptions) { - int listSize = km_kbp_options_list_size(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; @@ -317,7 +317,7 @@ SaveKeyboardOptionsCore(LPINTKEYBOARDINFO kp) { 0, sdmKeyboard, 0, "LoadKeyboardOptionsREGCore: km_kbp_keyboard_get_attrs failed with error status [%d]", err_status); return nullptr; } - int listSize = km_kbp_options_list_size(keyboardAttrs->default_options); + 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; From a8a19b2a2ee6b030e9ebf8e2b0fe1887d0c68dfb Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 17 Sep 2021 06:37:23 +1000 Subject: [PATCH 33/63] fix(windows): handle edge cases using default language Fixes #5091. If the user has a default language that is not a minimal BCP47 tag, such as `zh-Hans-CN` vs `zh-CN`, or if the default language does not have a mapping in our `TLanguageCodeUtils.TranslateWindowsLanguagesToBCP47` function, then kmshell would crash on install of a keyboard that had no language metadata specified (i.e. neither legacy metadata in .kmx nor modern metadata in .kmp). This crash arose because the elevated instance of kmshell would install a local-machine reference to `zh-CN` (as it back-translated from a LangID), but the current user install would look for `zh-Hans-CN`, read from the Windows registry `HKCU\Control Panel\International\User Profile`. To further complicate matters, it is possible for the current user to have a different default language than the elevated user on the machine. Keyman was assuming that the default language was the same in both cases. This fix passes in the current user's default BCP47 and LangID to the elevated portion of the keyboard install, so we can guarantee that keyboard install which needs to use the default language, actually installs for the current user's actual language code, and not a canonicalized version (or a totally different code in the case of elevation to an alternate admin user account). --- ...an.Configuration.System.TIPMaintenance.pas | 62 +++++++++++++++++-- .../Keyman.Configuration.UI.InstallFile.pas | 4 +- .../kmshell/install/UfrmInstallKeyboard.pas | 3 +- windows/src/desktop/kmshell/main/initprog.pas | 31 +++++++--- .../kmcomapi/com/keyman_implementation.pas | 10 ++- windows/src/engine/kmcomapi/keymanapi_TLB.pas | 25 +++++++- windows/src/engine/kmcomapi/keymancontext.pas | 5 ++ windows/src/engine/kmcomapi/kmcomapi.dproj | 2 +- windows/src/engine/kmcomapi/kmcomapi.ridl | 14 ++++- .../processes/keyboard/kpinstallkeyboard.pas | 26 +++++--- 10 files changed, 156 insertions(+), 26 deletions(-) diff --git a/windows/src/desktop/kmshell/install/Keyman.Configuration.System.TIPMaintenance.pas b/windows/src/desktop/kmshell/install/Keyman.Configuration.System.TIPMaintenance.pas index fb5f912dc5..1392d13353 100644 --- a/windows/src/desktop/kmshell/install/Keyman.Configuration.System.TIPMaintenance.pas +++ b/windows/src/desktop/kmshell/install/Keyman.Configuration.System.TIPMaintenance.pas @@ -33,7 +33,11 @@ type class function GetFirstLanguage(Keyboard: IKeymanKeyboardFile): string; overload; /// Get the BCP47 tag for the user's default language - class function GetUserDefaultLanguage: string; static; + class function GetUserDefaultLanguage: string; overload; static; + class procedure GetUserDefaultLanguage(var BCP47: string; var LangID: Integer); overload; static; + + /// Get the -default-lang parameter string for kmshell + class function GetUserDefaultLangParameterString: string; static; private class function GetKeyboardLanguage(const KeyboardID, BCP47Tag: string): IKeymanKeyboardLanguageInstalled; static; @@ -152,7 +156,7 @@ begin if RegistrationRequired then begin // This calls back into TTIPMaintenance.RegisterTip - if WaitForElevatedConfiguration(0, '-register-tip '+IntToHex(LangID,4)+' "'+KeyboardID+'" "'+lang.BCP47Code+'"') <> 0 then + if WaitForElevatedConfiguration(0, '-register-tip '+IntToHex(LangID,4)+' "'+KeyboardID+'" "'+lang.BCP47Code+'" '+GetUserDefaultLangParameterString) <> 0 then Exit(False); end; @@ -204,16 +208,61 @@ begin Result := False; end; +class function TTIPMaintenance.GetUserDefaultLangParameterString: string; +var + LangID: Integer; + BCP47: string; +begin + GetUserDefaultLanguage(BCP47, LangID); + Result := '-default-lang '+BCP47+' '+IntToHex(LangID,4); +end; + class function TTIPMaintenance.GetUserDefaultLanguage: string; +var + LangID: Integer; +begin + GetUserDefaultLanguage(Result, LangID); +end; + +class procedure TTIPMaintenance.GetUserDefaultLanguage(var BCP47: string; var LangID: Integer); var r: TRegistry; tags: TStringList; v: string; keys: TStringList; key: string; + + function GetLangIDFromValueName: Integer; + var + values: TStringList; + v: string; + begin + // In HKCU\Control Panel\International\User Profile\, already opened + // by the caller, look for a value name such as '0453:00000453' or + // '0804:{81D4E9C9-1D3B-41BC-9E6C-4B40BF79E35E}{FA550B04-5AD7-411F-A5AC-CA038EC515D7}' + // and grab the LangID from there. + values := TStringList.Create; + try + r.GetValueNames(values); + for v in values do + begin + if Copy(v, 5, 1) = ':' then + begin + Result := StrToIntDef('$' + Copy(v, 1, 4), 0); + if Result > 0 then + Exit; + end; + end; + finally + values.Free; + end; + Result := 0; + end; + begin // Fallback result - Result := TLanguageCodeUtils.TranslateWindowsLanguagesToBCP47(HKLToLanguageID(GetDefaultHKL)); + LangID := HKLToLanguageID(GetDefaultHKL); + BCP47 := TLanguageCodeUtils.TranslateWindowsLanguagesToBCP47(LangID); // For Win10, look in CPL/International/UserProfile r := TRegistry.Create; @@ -232,7 +281,8 @@ begin if r.OpenKeyReadOnly('\' + SRegKey_ControlPanelInternationalUserProfile + '\' + key) and r.ValueExists(v) then begin - Result := key; + BCP47 := key; + LangID := GetLangIDFromValueName; Break; end; end; @@ -248,7 +298,9 @@ begin r.ReadMultiString(SRegValue_CPIUP_Languages, tags); if tags.Count > 0 then begin - Result := tags[0].Trim; + BCP47 := tags[0].Trim; + if r.OpenKeyReadOnly('\' + SRegKey_ControlPanelInternationalUserProfile + '\' + tags[0].Trim) then + LangID := GetLangIDFromValueName; end; finally tags.Free; diff --git a/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.InstallFile.pas b/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.InstallFile.pas index 00bf0e44a7..2636eba7ea 100644 --- a/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.InstallFile.pas +++ b/windows/src/desktop/kmshell/install/Keyman.Configuration.UI.InstallFile.pas @@ -169,12 +169,12 @@ begin if Length(FilenameBCP47) > 1 then RegisterKeyboardPackageLanguage(FPackage, FilenameBCP47[1]) else RegisterKeyboardPackageLanguage(FPackage, ''); - // The keyboard will be installed for current user as a separate step + // The keyboard will be installed for current user as a separate step end else begin FKeyboard := (kmcom.Keyboards as IKeymanKeyboardsInstalled2).Install2(FileName, True); - if Length(FilenameBCP47) > 1 + if (Length(FilenameBCP47) > 1) and (Trim(FilenameBCP47[1]) <> '') then BCP47Tag := FilenameBCP47[1] else BCP47Tag := TTIPMaintenance.GetFirstLanguage(FKeyboard); TTIPMaintenance.DoRegister(FKeyboard.ID, BCP47Tag); diff --git a/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas b/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas index 6250db1030..8e780442e6 100644 --- a/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas +++ b/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas @@ -303,7 +303,8 @@ begin Manager.UpdateProgress('Installing Keyboard', 0, 0); t := TTempFileManager.Get('.log'); try - if WaitForElevatedConfiguration(GetForegroundWindow, '-log "'+t.Name+'" -s -i "'+FInstallFile+'='+BCP47Tag+'" -nowelcome') = 0 then + if WaitForElevatedConfiguration(GetForegroundWindow, '-log "'+t.Name+'" -s -i "'+FInstallFile+'='+BCP47Tag+'"'+ + ' -nowelcome '+TTIPMaintenance.GetUserDefaultLangParameterString) = 0 then begin // install the keyboard tip if not InstallTipForKeyboard(BCP47Tag) then diff --git a/windows/src/desktop/kmshell/main/initprog.pas b/windows/src/desktop/kmshell/main/initprog.pas index d77ca982f0..c22591e79c 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -195,7 +195,8 @@ begin end; function Init(var FMode: TKMShellMode; KeyboardFileNames: TStrings; var FSilent, FForce, FNoWelcome: Boolean; - var FLogFile, FQuery: string; var FDisablePackages, FDefaultUILanguage: string; var FStartWithConfiguration: Boolean; var FParentWindow: THandle): Boolean; + var FLogFile, FQuery: string; var FDisablePackages, FDefaultUILanguage: string; var FStartWithConfiguration: Boolean; + var FParentWindow: THandle; var FDefaultBCP47: string; var FDefaultLangID: Integer): Boolean; var s: string; i: Integer; @@ -269,7 +270,13 @@ begin FQuery := Trim(FQuery); end else if Copy(s, 1, 3) = '-ur' then UnRegCRC := StrToIntDef('$'+Copy(s, 4, 8), 0) - + else if s = '-default-lang' then + begin + Inc(i); + FDefaultBCP47 := ParamStr(i); + Inc(i); + FDefaultLangID := StrToIntDef('$'+ParamStr(i), 0); + end // Controls from Keyman Engine else if s = '-showhint' then FMode := fmShowHint else if s = '-parentwindow' then @@ -301,7 +308,8 @@ begin end; procedure RunKMCOM(FMode: TKMShellMode; KeyboardFileNames: TStrings; FSilent, FForce, FNoWelcome: Boolean; - FLogFile, FQuery: string; FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; FParentWindow: THandle); forward; + FLogFile, FQuery: string; FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; FParentWindow: THandle; + const FDefaultBCP47: string; FDefaultLangID: Integer); forward; procedure Run; var @@ -312,7 +320,8 @@ var FForce: Boolean; FParentWindow: THandle; FLogFile: string; - FDisablePackages, FDefaultUILanguage: string; + FDefaultLangID: Integer; + FDefaultBCP47, FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; begin RegisterControlClasses; @@ -320,7 +329,7 @@ begin KeyboardFileNames := TStringList.Create; try FParentWindow := 0; - if not Init(FMode, KeyboardFileNames, FSilent, FForce, FNoWelcome, FLogFile, FQuery, FDisablePackages, FDefaultUILanguage, FStartWithConfiguration, FParentWindow) then + if not Init(FMode, KeyboardFileNames, FSilent, FForce, FNoWelcome, FLogFile, FQuery, FDisablePackages, FDefaultUILanguage, FStartWithConfiguration, FParentWindow, FDefaultBCP47, FDefaultLangID) then begin //TODO: TUtilExecute.Shell(PChar('hh.exe mk:@MSITStore:'+ExtractFilePath(KMShellExe)+'keyman.chm::/context/keyman_usage.html'), SW_SHOWNORMAL); Exit; @@ -328,7 +337,7 @@ begin if not LoadKMCOM then Exit; try - RunKMCOM(FMode, KeyboardFileNames, FSilent, FForce, FNoWelcome, FLogFile, FQuery, FDisablePackages, FDefaultUILanguage, FStartWithConfiguration, FParentWindow); + RunKMCOM(FMode, KeyboardFileNames, FSilent, FForce, FNoWelcome, FLogFile, FQuery, FDisablePackages, FDefaultUILanguage, FStartWithConfiguration, FParentWindow, FDefaultBCP47, FDefaultLangID); finally kmcom := nil; end; @@ -366,8 +375,10 @@ begin end; procedure RunKMCOM(FMode: TKMShellMode; KeyboardFileNames: TStrings; FSilent, FForce, FNoWelcome: Boolean; - FLogFile, FQuery: string; FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; FParentWindow: THandle); + FLogFile, FQuery: string; FDisablePackages, FDefaultUILanguage: string; FStartWithConfiguration: Boolean; + FParentWindow: THandle; const FDefaultBCP47: string; FDefaultLangID: Integer); var + kdl: IKeymanDefaultLanguage; FIcon: string; FMutex: TKeymanMutex; // I2720 function FirstKeyboardFileName: WideString; @@ -440,6 +451,12 @@ begin if FileExists(FIcon) then Application.Icon.LoadFromFile(FIcon); + if (FDefaultBCP47 <> '') or (FDefaultLangID <> 0) then + begin + if Supports(kmcom, IKeymanDefaultLanguage, kdl) then + kdl.SetDefaultLanguage(FDefaultBCP47, FDefaultLangID); + end; + case FMode of fmKeyboardWelcome: // I2569 ShowKeyboardWelcome(FirstKeyboardFileName); diff --git a/windows/src/engine/kmcomapi/com/keyman_implementation.pas b/windows/src/engine/kmcomapi/com/keyman_implementation.pas index 74766bad76..fe0c117fa5 100644 --- a/windows/src/engine/kmcomapi/com/keyman_implementation.pas +++ b/windows/src/engine/kmcomapi/com/keyman_implementation.pas @@ -48,7 +48,7 @@ uses keymansysteminfo; type - TKeyman = class(TAutoObject, IKeyman, IIntKeyman, IKeymanBCP47Canonicalization) + TKeyman = class(TAutoObject, IKeyman, IIntKeyman, IKeymanBCP47Canonicalization, IKeymanDefaultLanguage) private FInitialized: Boolean; FContext: TKeymanContext; @@ -84,6 +84,8 @@ type // Reimplement as a special case for this interface function SerializeXML(Flags: TOleEnum; const ImagePath: WideString; out References: OleVariant): WideString; safecall; + { IKeymanDefaultLanguage } + procedure SetDefaultLanguage(const BCP47: WideString; LangID: Integer); safecall; public procedure Initialize; override; destructor Destroy; override; @@ -290,6 +292,12 @@ begin end; end; +procedure TKeyman.SetDefaultLanguage(const BCP47: WideString; LangID: Integer); +begin + FContext.DefaultBCP47 := BCP47; + FContext.DefaultLangID := LangID; +end; + procedure TKeyman.Set_AutoApply(Value: WordBool); begin if not FInitialized then raise Exception.Create(SErrorUninitialised); diff --git a/windows/src/engine/kmcomapi/keymanapi_TLB.pas b/windows/src/engine/kmcomapi/keymanapi_TLB.pas index 56ec2f90e7..3ceb5b15cd 100644 --- a/windows/src/engine/kmcomapi/keymanapi_TLB.pas +++ b/windows/src/engine/kmcomapi/keymanapi_TLB.pas @@ -12,7 +12,7 @@ unit keymanapi_TLB; // ************************************************************************ // // $Rev: 52393 $ -// File generated on 1/02/2021 8:52:41 AM from Type Library described below. +// File generated on 16/09/2021 6:54:44 PM from Type Library described below. // ************************************************************************ // // Type Lib: C:\Projects\keyman\app\windows\src\engine\kmcomapi\kmcomapi (1) @@ -93,6 +93,7 @@ const IID_IKeymanKeyboardLanguageInstalled2: TGUID = '{414C26E6-BFAC-4A70-9EA1-E525BA9BBA7E}'; IID_IKeymanKeyboardLanguagesInstalled2: TGUID = '{628FF2E6-B490-462E-8FC7-7AE53B9D392C}'; CLASS_Keyman: TGUID = '{CF46549D-4D2D-4679-A2E1-23A815F172F8}'; + IID_IKeymanDefaultLanguage: TGUID = '{77BAB934-B7DF-4304-AFA6-B8F6BEC16516}'; // *********************************************************************// // Declaration of Enumerations defined in Type Library @@ -257,6 +258,8 @@ type IKeymanKeyboardLanguageInstalled2Disp = dispinterface; IKeymanKeyboardLanguagesInstalled2 = interface; IKeymanKeyboardLanguagesInstalled2Disp = dispinterface; + IKeymanDefaultLanguage = interface; + IKeymanDefaultLanguageDisp = dispinterface; // *********************************************************************// // Declaration of CoClasses defined in Type Library @@ -1765,6 +1768,26 @@ type out References: OleVariant): WideString; dispid 401; end; +// *********************************************************************// +// Interface: IKeymanDefaultLanguage +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {77BAB934-B7DF-4304-AFA6-B8F6BEC16516} +// *********************************************************************// + IKeymanDefaultLanguage = interface(IDispatch) + ['{77BAB934-B7DF-4304-AFA6-B8F6BEC16516}'] + procedure SetDefaultLanguage(const DefaultBCP47: WideString; DefaultLangID: Integer); safecall; + end; + +// *********************************************************************// +// DispIntf: IKeymanDefaultLanguageDisp +// Flags: (4416) Dual OleAutomation Dispatchable +// GUID: {77BAB934-B7DF-4304-AFA6-B8F6BEC16516} +// *********************************************************************// + IKeymanDefaultLanguageDisp = dispinterface + ['{77BAB934-B7DF-4304-AFA6-B8F6BEC16516}'] + procedure SetDefaultLanguage(const DefaultBCP47: WideString; DefaultLangID: Integer); dispid 201; + end; + // *********************************************************************// // The Class CoKeyman provides a Create and CreateRemote method to // create instances of the default interface IKeyman exposed by diff --git a/windows/src/engine/kmcomapi/keymancontext.pas b/windows/src/engine/kmcomapi/keymancontext.pas index 085810eb2d..fdd3e76567 100644 --- a/windows/src/engine/kmcomapi/keymancontext.pas +++ b/windows/src/engine/kmcomapi/keymancontext.pas @@ -32,6 +32,8 @@ type private FKeyman: TObject; FController: TKeymanController; + FDefaultBCP47: string; + FDefaultLangID: Integer; function GetErrors: IIntKeymanErrors; function GetKeyboards: IIntKeymanKeyboardsInstalled; function GetPackages: IIntKeymanPackagesInstalled; @@ -50,6 +52,9 @@ type property SystemInfo: IIntKeymanSystemInfo read GetSystemInfo; property Control: IIntKeymanControl read GetControl; property Controller: TKeymanController read FController; + + property DefaultBCP47: string read FDefaultBCP47 write FDefaultBCP47; + property DefaultLangID: Integer read FDefaultLangID write FDefaultLangID; end; implementation diff --git a/windows/src/engine/kmcomapi/kmcomapi.dproj b/windows/src/engine/kmcomapi/kmcomapi.dproj index cf51be0329..fd9b6c51d7 100644 --- a/windows/src/engine/kmcomapi/kmcomapi.dproj +++ b/windows/src/engine/kmcomapi/kmcomapi.dproj @@ -124,7 +124,7 @@ false false - ..\..\desktop\kmshell\kmshell.exe + ..\..\desktop\kmshell\bin\win32\debug\kmshell.exe CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) -c false diff --git a/windows/src/engine/kmcomapi/kmcomapi.ridl b/windows/src/engine/kmcomapi/kmcomapi.ridl index bdee680f06..ac20310a87 100644 --- a/windows/src/engine/kmcomapi/kmcomapi.ridl +++ b/windows/src/engine/kmcomapi/kmcomapi.ridl @@ -6,7 +6,7 @@ // However, when applying changes via the Editor this file will be regenerated // and comments or formatting changes will be lost. // ************************************************************************ // -// File generated on 1/02/2021 8:52:42 AM (- $Rev: 12980 $, 9519671). +// File generated on 16/09/2021 6:54:45 PM (- $Rev: 12980 $, 32940875). [ uuid(F16E2A9A-DA46-4EA3-BFF3-BA46B480C961), @@ -66,6 +66,7 @@ library keymanapi interface IKeymanKeyboardLanguageInstalled2; interface IKeymanKeyboardLanguagesInstalled2; interface IKeymanBCP47Canonicalization; + interface IKeymanDefaultLanguage; [ @@ -1019,6 +1020,17 @@ library keymanapi HRESULT _stdcall GetFullTagList([in] BSTR Tag, [out, retval] VARIANT* Result); }; + [ + uuid(77BAB934-B7DF-4304-AFA6-B8F6BEC16516), + dual, + oleautomation + ] + interface IKeymanDefaultLanguage: IDispatch + { + [id(0x000000C9)] + HRESULT _stdcall SetDefaultLanguage([in] BSTR DefaultBCP47, [in] long DefaultLangID); + }; + [ uuid(CF46549D-4D2D-4679-A2E1-23A815F172F8), version(10.0) diff --git a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas index e91cab0eeb..147bb9aef6 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas @@ -326,6 +326,7 @@ var kpil: TKPInstallKeyboardLanguage; ml: TMitigateWin10_1803.TMitigatedLanguage; KeyboardName: string; + FDefaultBCP47: string; type TWSLCallback = reference to procedure(r: TRegistryErrorControlled); @@ -366,7 +367,11 @@ begin ErrorFmt(KMN_E_Install_InvalidFile, VarArrayOf([ExtractFileName(FileName), E.Message])); end; - FDefaultHKL := GetDefaultHKL; + FDefaultHKL := Context.DefaultLangID; + if FDefaultHKL = 0 then + FDefaultHKL := GetDefaultHKL; + + FDefaultBCP47 := Context.DefaultBCP47; KeyboardID := GetShortKeyboardName(FileName); @@ -456,12 +461,6 @@ begin begin FLanguages := GetLanguageCodesFromKeyboard(ki); - // - // Final fallback is to install against default language for system // I4607 - // - if Length(FLanguages) = 0 then - AddLanguage(HKLToLanguageID(FDefaultHKL)); - for i := 0 to High(Flanguages) do if TMitigateWin10_1803.IsMitigationRequired(FLanguages[i], ml) then begin @@ -483,6 +482,19 @@ begin i: Integer; BCP47Tag: string; begin + if Length(FLanguages) = 0 then + begin + // + // Final fallback is to install against default language for system + // + kpil := TKPInstallKeyboardLanguage.Create(Context); + try + kpil.RegisterTip(KeyboardID, FDefaultBCP47, KeyboardName, FDefaultHKL, FIconFileName, ''); //TODO: language name + finally + kpil.Free; + end; + r.WriteString(FDefaultBCP47, ''); // TODO: language name + end; for i := 0 to High(FLanguages) do begin BCP47Tag := TLanguageCodeUtils.TranslateWindowsLanguagesToBCP47(FLanguages[i]); From 6fa5399cda8b13c3115d5e564679666ad1c3de91 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 17 Sep 2021 10:30:41 +1000 Subject: [PATCH 34/63] chore(windows): Apply suggestion Co-authored-by: Darcy Wong --- .../install/Keyman.Configuration.System.TIPMaintenance.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/src/desktop/kmshell/install/Keyman.Configuration.System.TIPMaintenance.pas b/windows/src/desktop/kmshell/install/Keyman.Configuration.System.TIPMaintenance.pas index 1392d13353..f61aa57d25 100644 --- a/windows/src/desktop/kmshell/install/Keyman.Configuration.System.TIPMaintenance.pas +++ b/windows/src/desktop/kmshell/install/Keyman.Configuration.System.TIPMaintenance.pas @@ -299,7 +299,7 @@ begin if tags.Count > 0 then begin BCP47 := tags[0].Trim; - if r.OpenKeyReadOnly('\' + SRegKey_ControlPanelInternationalUserProfile + '\' + tags[0].Trim) then + if r.OpenKeyReadOnly('\' + SRegKey_ControlPanelInternationalUserProfile + '\' + BCP47) then LangID := GetLangIDFromValueName; end; finally From 9305bae3ba1319b7895d6a9627d198316b590c1a Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Mon, 20 Sep 2021 11:34:06 +1000 Subject: [PATCH 35/63] fix(windows): commit review suggestions Co-authored-by: Marc Durdin --- windows/src/engine/keyman32/K32_load.cpp | 7 ++++--- windows/src/engine/keyman32/Keyman32.cpp | 5 +++-- windows/src/engine/keyman32/appint/appint.cpp | 2 +- .../tests/keyman-engine-tests/kmprocessactionstests.cpp | 4 ++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index c414823112..64479c9743 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -95,11 +95,12 @@ BOOL LoadlpKeyboardCore(int i) if (!GetKeyboardFileName(_td->lpKeyboards[i].Name, buf, 255)) return FALSE; PWCHAR keyboardPath = strtowstr(buf); km_kbp_status err_status = km_kbp_keyboard_load(keyboardPath, &_td->lpKeyboards[i].lpCoreKeyboard); - delete keyboardPath; if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboardCore: km_kbp_keyboard_load failed with error status [%d]", err_status); + SendDebugMessageFormat(0, sdmLoad, 0, "LoadlpKeyboardCore: km_kbp_keyboard_load failed for %ls with error status [%d]", keyboardPath, err_status); + delete keyboardPath; return FALSE; } + delete keyboardPath; // TODO: 5650 handle dlls //LoadDLLs(&_td->lpKeyboards[i]); @@ -112,7 +113,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); - // Dispose of the keyboard to leave us in a consitent state + // Dispose of the keyboard to leave us in a consistent state ReleaseKeyboardMemoryCore(&_td->lpActiveKeyboard->lpCoreKeyboard); return FALSE; } diff --git a/windows/src/engine/keyman32/Keyman32.cpp b/windows/src/engine/keyman32/Keyman32.cpp index 45aeb01817..87c5eabfd6 100644 --- a/windows/src/engine/keyman32/Keyman32.cpp +++ b/windows/src/engine/keyman32/Keyman32.cpp @@ -569,11 +569,12 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_ForceKeyboard(PCSTR FileName if (Globals::get_CoreIntegration()) { PWCHAR keyboardPath = strtowstr(_td->ForceFileName); km_kbp_status err_status = km_kbp_keyboard_load(keyboardPath, &_td->lpActiveKeyboard->lpCoreKeyboard); - delete keyboardPath; if (err_status != KM_KBP_STATUS_OK) { - SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard Core: km_kbp_keyboard_load failed with error status [%d]", err_status); // TODO: 5442 - remove word Core + 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; } + delete keyboardPath; SendDebugMessageFormat(0, sdmGlobal, 0, "Keyman_ForceKeyboard Core: %s OK", FileName); // TODO: 5442 - remove word Core // TODO: #5650 Equivalent for common core // LoadDLLs(&_td->lpKeyboards[i]); diff --git a/windows/src/engine/keyman32/appint/appint.cpp b/windows/src/engine/keyman32/appint/appint.cpp index ea7c33f1b1..4e8e87941d 100644 --- a/windows/src/engine/keyman32/appint/appint.cpp +++ b/windows/src/engine/keyman32/appint/appint.cpp @@ -223,7 +223,7 @@ BOOL ContextItemsFromAppContext(WCHAR const* buf, km_kbp_context_item** outPtr) context_items[contextIndex++] = km_kbp_context_item{ KM_KBP_CT_CHAR, {0,}, {(char32_t)Uni_SurrogateToUTF32(*p, *(p + 1))} }; p++; } else { - context_items[contextIndex++] = km_kbp_context_item{ KM_KBP_CT_CHAR, {0,}, {*p} }; + context_items[contextIndex++] = km_kbp_context_item{ KM_KBP_CT_CHAR, {0,}, {*p} }; } p++; } diff --git a/windows/src/engine/keyman32/tests/keyman-engine-tests/kmprocessactionstests.cpp b/windows/src/engine/keyman32/tests/keyman-engine-tests/kmprocessactionstests.cpp index 70fe802bdc..d996f089c0 100644 --- a/windows/src/engine/keyman32/tests/keyman-engine-tests/kmprocessactionstests.cpp +++ b/windows/src/engine/keyman32/tests/keyman-engine-tests/kmprocessactionstests.cpp @@ -2,10 +2,10 @@ #include "kmprocessactions.cpp" // Test the Process Actions private functions -// Note: The following actions are not tested KM_KBP_IT_ALERT, KM_KBP_IT_PERSIST_OPT, KM_KBP_IT_EMIT_KEYSTROKE +// TODO: The following actions are not tested KM_KBP_IT_ALERT, KM_KBP_IT_PERSIST_OPT, KM_KBP_IT_EMIT_KEYSTROKE // KM_KBP_IT_CHAR - processUnicodeChar - TEST(AITIP, processUnicodeChartest) { +TEST(AITIP, processUnicodeChartest) { Globals_InitProcess(); WCHAR callbuf[MAXCONTEXT]; From 52b67b9d6f6a013ec9b9e3e6bc3fe40c52946026 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Mon, 20 Sep 2021 09:36:18 +0700 Subject: [PATCH 36/63] chore(ios,android): Update crowdin strings for Amharic --- .../src/main/res/values-am-rET/strings.xml | 34 ++++++++++++++++-- .../src/main/res/values-am-rET/strings.xml | 6 ++++ .../KeymanEngine/am.lproj/Localizable.strings | 36 +++++++++++++++++++ 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/android/KMAPro/kMAPro/src/main/res/values-am-rET/strings.xml b/android/KMAPro/kMAPro/src/main/res/values-am-rET/strings.xml index 817d731403..ae3fbbb1c6 100644 --- a/android/KMAPro/kMAPro/src/main/res/values-am-rET/strings.xml +++ b/android/KMAPro/kMAPro/src/main/res/values-am-rET/strings.xml @@ -18,6 +18,10 @@ ማሻሻያዎችን ይጫኑ ስሪት %1$s + + ኪይማን የክሮም ስሪትን 57 ወይም አዲስ ይፈልጋል። + + ክሮምን ማዘመን እዚህ ጋር መጻፍ ይጀምሩ … @@ -37,7 +41,7 @@ ኪይማኑን ለሲስተም ኪቦርድ እንዲሆን ያድርጉ - ኪማኑን መደበና የፊደል ገበታ ይሰይሙ + ኪማኑን መደበኛ የፊደል ገበታ ይሰይሙ ተጨማሪ መረጃ @@ -56,7 +60,27 @@ የተጫነ የፊደል ገበታ ወይም መዝገበ ቃላት - የኪማኑን የገጽታ ቋንቋ ይቀይሩ + የገጽታ ቋንቋ + + የቋንቋ ገበታውን ቁመት ማስተካከል + + የስፔስባሩ መግለጫ ጽሁፍ + + የፊደል ገበታ + + ቋንቋ + + ቋንቋና የፊደል ገበታ + + ባዶ + + የፊደል ገበታ ሰሌዳውን በስፔስ ባሩ ላይ አሳይ + + የቋንቋውን ስም በስፔስ ባሩ ላይ አሳይ + + ቋንቋና የፊደል ገበታውን በስፔስ ባሩ ላይ + + የስፔስባሩ መግለጫ ጽሁፍ አታሳይ ሁልጊዜ ባነሩን አሳይ @@ -87,6 +111,12 @@ %1$s የተጨመረ ቋንቋ %2$s ሁሉም ቋንቋዎች ቀደም ሲል ተጭኗል + + የፊደል ገበታ ሰሌዳውን በመጎተት ቁመቱን አስተካክል + + ዲቫይሱን በማሽከርከር ፖርትሬቱንና ላንድስኬፑን አስተካክል + + ወደ ቀደመው ሴቲንግ መልስ ፈልግ ወይም URL ጻፍ diff --git a/android/KMEA/app/src/main/res/values-am-rET/strings.xml b/android/KMEA/app/src/main/res/values-am-rET/strings.xml index 417d02d5b5..49620d7315 100644 --- a/android/KMEA/app/src/main/res/values-am-rET/strings.xml +++ b/android/KMEA/app/src/main/res/values-am-rET/strings.xml @@ -24,6 +24,10 @@ ኪይማኑን ዝጋ + ወደፊት + + የሚቀጥለውን የመቀበያ ዘዴ + ወርዷል ጫን @@ -69,6 +73,8 @@ የእገዛ ፋይልን ለማየት ፋይል ፕሮቫይደሩ ቤተ መጽሐፍት ያስፈልገዋል %1$s የገበታ ሰሌዳ ፋታል ችግር ዝርዝር %1$s:%2$s ለ %3$s ቋንቋ፤ መደበኛ ቋንቋ ጭኗል። + + የፊደል ገበታ ሰሌዳው ችግር %1$s:%2$s ለ %3$s ቋንቋ። ተያያዥነት ያለውን መዝገበ ቃላት ለመጫን እየፈተሸ ነው። diff --git a/ios/engine/KMEI/KeymanEngine/am.lproj/Localizable.strings b/ios/engine/KMEI/KeymanEngine/am.lproj/Localizable.strings index efd3bd7e52..f694d584a3 100644 --- a/ios/engine/KMEI/KeymanEngine/am.lproj/Localizable.strings +++ b/ios/engine/KMEI/KeymanEngine/am.lproj/Localizable.strings @@ -49,6 +49,12 @@ /* Confirmation text to display before uninstalling a lexical model */ "command-uninstall-lexical-model-confirm" = "ይህንን መዝገበ ቃላት ልታጠፋው ትፈልጋለህ?"; +/* Text for error when a keyboard cannot load properly */ +"error-loading-keyboard" = "የተጠየቀው የፊደል ገበታ ሰሌዳውን ሊጫን አልተቻለም"; + +/* Text for error when a lexical model cannot load properly */ +"error-loading-lexical-model" = "የተጠየቀው ዲክሽናሪ ሊጫን አልተቻለም"; + /* Text for error when an installed file is unexpectedly missing */ "error-missing-file" = "የእርዳታ ሰነዱን ማግኘት አልተቻለም።"; @@ -181,6 +187,36 @@ /* Title for the main Settings menu */ "menu-settings-title" = "የኪይማን ቅንብሮች"; +/* Secondary text showing current setting for spacebar caption - blank */ +"menu-settings-spacebar-hint-blank" = "የስፔስባሩ መግለጫ ጽሁፍ አታሳይ"; + +/* Secondary text showing current setting for spacebar caption - keyboard */ +"menu-settings-spacebar-hint-keyboard" = "የፊደል ገበታ ሰሌዳውን ስም በስፔስ ባሩ ላይ አሳይ"; + +/* Secondary text showing current setting for spacebar caption - language */ +"menu-settings-spacebar-hint-language" = "የቋንቋውን ስም በስፔስ ባሩ ላይ አሳይ"; + +/* Secondary text showing current setting for spacebar caption - language + keyboard */ +"menu-settings-spacebar-hint-languageKeyboard" = "ቋንቋና የፊደል ገበታውን በስፔስ ባሩ ላይ"; + +/* Label for the "Spacebar Caption" item on the main settings screen */ +"menu-settings-spacebar-text" = "የስፔስባሩ መግለጫ ጽሁፍ"; + +/* Title for the "Spacebar Caption" settings screen */ +"menu-settings-spacebar-title" = "የስፔስባሩ መግለጫ ጽሁፍ"; + +/* Text showing name of spacebar caption - blank */ +"menu-settings-spacebar-item-blank" = "ባዶ"; + +/* Text showing name of spacebar caption - keyboard */ +"menu-settings-spacebar-item-keyboard" = "የፊደል ገበታ ሰሌዳ"; + +/* Text showing name of spacebar caption - language */ +"menu-settings-spacebar-item-language" = "ቋንቋ"; + +/* Text showing name of spacebar caption - language + keyboard */ +"menu-settings-spacebar-item-languageKeyboard" = "ቋንቋና የፊደል ገበታ"; + /* Short text for notification: download failure for keyboard */ "notification-download-failure-keyboard" = "የፊደል ገበታ ሰሌዳ መውረድ አልቻለም"; From d450543253b0ec269f594be41d26cc660f912953 Mon Sep 17 00:00:00 2001 From: Ross Date: Tue, 21 Sep 2021 09:59:17 +1000 Subject: [PATCH 37/63] feat(windows): address review comments Add test fixture to allow Setup and Teardown methods to be used for all km process action tests. Modified the DebugAssert macro to not do the early return on its own. --- windows/src/engine/keyman32/k32_dbg.cpp | 12 ++++ .../src/engine/keyman32/keyboardoptions.cpp | 21 ++++-- windows/src/engine/keyman32/kmprocess.cpp | 12 +++- .../kmprocessactionstests.cpp | 66 ++++++++----------- windows/src/global/inc/keymanengine.h | 28 ++------ 5 files changed, 69 insertions(+), 70 deletions(-) diff --git a/windows/src/engine/keyman32/k32_dbg.cpp b/windows/src/engine/keyman32/k32_dbg.cpp index 580d7370e0..b2cd0edbcd 100644 --- a/windows/src/engine/keyman32/k32_dbg.cpp +++ b/windows/src/engine/keyman32/k32_dbg.cpp @@ -306,6 +306,18 @@ char *Debug_UnicodeString(PWSTR s, int x) { return bufout[x]; } +BOOL DebugAssert_1(BOOL condition, char *message, char *file, int line) +{ + if (!(condition)) { + SendDebugMessage_1(0, sdmGlobal, 0, file, line, message); + if (IsDebugAssertEnabled()) { + assert(condition); + } + return FALSE; + } + return TRUE; +} + #ifdef _DEBUG void _OutputThreadDebugString(char *s) { char buf[256]; diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index d7ea003a65..10bf533b2e 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -31,7 +31,9 @@ void LoadKeyboardOptions(LPINTKEYBOARDINFO kp) void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp) { - DebugAssert(!Globals::get_CoreIntegration(), "LoadSharedKeyboardOptions: Error called in core integration mode"); + 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); @@ -43,7 +45,9 @@ void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp) void FreeKeyboardOptions(LPINTKEYBOARDINFO kp) { - DebugAssert(!Globals::get_CoreIntegration(),"FreeKeyboardOptions: Error called in core integration mode"); + if (!DebugAssert(!Globals::get_CoreIntegration(), "FreeKeyboardOptions: Error called in core integration mode")) { + return; + } // 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) @@ -61,7 +65,9 @@ void FreeKeyboardOptions(LPINTKEYBOARDINFO kp) void SetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSet, int nStoreToRead) { - DebugAssert(!Globals::get_CoreIntegration(), "SetKeyboardOption: Error called in core integration mode"); + if (!DebugAssert(!Globals::get_CoreIntegration(), "SetKeyboardOption: Error called in core integration mode")) { + return; + } assert(kp != NULL); assert(kp->Keyboard != NULL); assert(kp->KeyboardOptions != NULL); @@ -87,7 +93,9 @@ void SetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSet, int nStoreToRead) void ResetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToReset) { - DebugAssert(!Globals::get_CoreIntegration(), "ResetKeyboardOption: Error called in core integration mode"); + if (!DebugAssert(!Globals::get_CoreIntegration(), "ResetKeyboardOption: Error called in core integration mode")) { + return; + } assert(kp != NULL); assert(kp->Keyboard != NULL); assert(kp->KeyboardOptions != NULL); @@ -124,7 +132,9 @@ void ResetKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToReset) void SaveKeyboardOption(LPINTKEYBOARDINFO kp, int nStoreToSave) { - DebugAssert(!Globals::get_CoreIntegration(), "SaveKeyboardOption: Error called in core integration mode"); + if (!DebugAssert(!Globals::get_CoreIntegration(), "SaveKeyboardOption: Error called in core integration mode")) { + return; + } IntSaveKeyboardOption(REGSZ_KeyboardOptions, kp, nStoreToSave); } @@ -229,6 +239,7 @@ BOOL IntLoadKeyboardOptionsCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_kbp_state* if (err_status != KM_KBP_STATUS_OK) { SendDebugMessageFormat( 0, sdmKeyboard, 0, "LoadKeyboardOptionsREGCore: km_kbp_keyboard_get_attrs failed with error status [%d]", err_status); + return FALSE; } size_t listSize = km_kbp_options_list_size(keyboardAttrs->default_options); km_kbp_option_item* keyboardOpts = new km_kbp_option_item[listSize+1]; diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index 3aa43f2713..502779ca81 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -244,7 +244,9 @@ BOOL ProcessHook() BOOL ProcessGroup(LPGROUP gp) { - DebugAssertRetValue(!Globals::get_CoreIntegration(), "KMPROCESS:ProcessGroup: Error called in core integration mode", FALSE); + if (!DebugAssert(!Globals::get_CoreIntegration(), "KMPROCESS:ProcessGroup: Error called in core integration mode")) { + return FALSE; + } DWORD i; LPKEY kkp = NULL; PWSTR p; @@ -543,7 +545,9 @@ BOOL ProcessGroup(LPGROUP gp) int PostString(PWSTR str, LPMSG mp, LPKEYBOARD lpkb, PWSTR endstr) { - DebugAssertRetValue(!Globals::get_CoreIntegration(), "KKMPROCESS:PostString: Error called in core integration mode", FALSE); + if (!DebugAssert(!Globals::get_CoreIntegration(), "KKMPROCESS:PostString: Error called in core integration mode")) { + return FALSE; + } PWSTR p, q, temp; LPSTORE s; int n1, n2; @@ -709,7 +713,9 @@ BOOL IsMatchingPlatform(LPSTORE s) // I3432 BOOL ContextMatch(LPKEY kkp) { - DebugAssertRetValue(!Globals::get_CoreIntegration(), "KMPROCESS:ContextMatch: Error called in core integration mode", FALSE); + 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; diff --git a/windows/src/engine/keyman32/tests/keyman-engine-tests/kmprocessactionstests.cpp b/windows/src/engine/keyman32/tests/keyman-engine-tests/kmprocessactionstests.cpp index d996f089c0..1127f36d78 100644 --- a/windows/src/engine/keyman32/tests/keyman-engine-tests/kmprocessactionstests.cpp +++ b/windows/src/engine/keyman32/tests/keyman-engine-tests/kmprocessactionstests.cpp @@ -1,12 +1,30 @@ #include "pch.h" #include "kmprocessactions.cpp" -// Test the Process Actions private functions +// Test the Process Actions private functions // TODO: The following actions are not tested KM_KBP_IT_ALERT, KM_KBP_IT_PERSIST_OPT, KM_KBP_IT_EMIT_KEYSTROKE +// Fixture for kmprocessactons tests +class KMPROCESSACTIONS : public ::testing::Test { +public: + KMPROCESSACTIONS() {} + + void + SetUp() { + Globals_InitProcess(); + } + + void + TearDown() { + UninitialiseProcess(FALSE); + Globals_UninitProcess(); + } + + ~KMPROCESSACTIONS() {} +}; + // KM_KBP_IT_CHAR - processUnicodeChar -TEST(AITIP, processUnicodeChartest) { - Globals_InitProcess(); +TEST_F(KMPROCESSACTIONS, processUnicodeChartest) { WCHAR callbuf[MAXCONTEXT]; AITIP testApp; @@ -16,21 +34,17 @@ TEST(AITIP, processUnicodeChartest) { processUnicodeChar(&testApp, &itemAddChar); WCHAR *contextBuf = testApp.ContextBufMax(MAXCONTEXT); EXPECT_STREQ(contextBuf, expectedContext); - + km_kbp_usv testSurrogateChar = Uni_SurrogateToUTF32(0xD801, 0xDC37); //𐐷'; km_kbp_action_item itemAddChar2 = {KM_KBP_IT_CHAR, {0,}, {testSurrogateChar}}; WCHAR expectedStringSurrogate[] = {'A', 0xD801, 0xDC37, 0}; processUnicodeChar(&testApp, &itemAddChar2); contextBuf = testApp.ContextBufMax(MAXCONTEXT); EXPECT_STREQ(contextBuf, &expectedStringSurrogate[0]); - - UninitialiseProcess(FALSE); - Globals_UninitProcess(); } // KM_KBP_IT_MARKER - processMarker Deadkey -TEST(AITIP, processMarkertest) { - Globals_InitProcess(); +TEST_F(KMPROCESSACTIONS, processMarkertest) { WCHAR callbuf[MAXCONTEXT]; AITIP testApp; @@ -41,16 +55,11 @@ TEST(AITIP, processMarkertest) { processMarker(&testApp, &itemAddMarker); WCHAR *contextBuf = testApp.ContextBufMax(MAXCONTEXT); EXPECT_STREQ(contextBuf, expectedContext); - - UninitialiseProcess(FALSE); - Globals_UninitProcess(); } -// KM_KBP_IT_BACK - processBack +// KM_KBP_IT_BACK - processBack // First test processing a backspace for a deadkey -TEST(AITIP, processBackDeadkeytest) { - Globals_InitProcess(); - Globals_InitThread(); +TEST_F(KMPROCESSACTIONS, processBackDeadkeytest) { WCHAR callbuf[MAXCONTEXT]; AITIP testApp; @@ -67,17 +76,12 @@ TEST(AITIP, processBackDeadkeytest) { processBack(&testApp, &itemBackSpace); WCHAR *contextBuf = testApp.ContextBufMax(MAXCONTEXT); EXPECT_STREQ(contextBuf, expectedContext); - - UninitialiseProcess(FALSE); - Globals_UninitProcess(); } // KM_KBP_IT_BACK - processBack // Press Backspace for a normal character // Also test for Unknown Character -TEST(AITIP, processBackCharactertest) { - Globals_InitProcess(); - Globals_InitThread(); +TEST_F(KMPROCESSACTIONS, processBackCharactertest) { WCHAR callbuf[MAXCONTEXT]; AITIP testApp; @@ -100,17 +104,12 @@ TEST(AITIP, processBackCharactertest) { processBack(&testApp, &itemBackSpace); contextBuf = testApp.ContextBufMax(MAXCONTEXT); EXPECT_STREQ(contextBuf, expectedContextFinal); - - UninitialiseProcess(FALSE); - Globals_UninitProcess(); } // KM_KBP_IT_BACK - processBack // Press Backspace for a character doesn't match expected character // Note currently we don't check for a character match this should be updated -TEST(AITIP, processBackUnexpectedChartest) { - Globals_InitProcess(); - Globals_InitThread(); +TEST_F(KMPROCESSACTIONS, processBackUnexpectedChartest) { WCHAR callbuf[MAXCONTEXT]; AITIP testApp; @@ -127,16 +126,10 @@ TEST(AITIP, processBackUnexpectedChartest) { processBack(&testApp, &itemBackSpace); WCHAR *contextBuf = testApp.ContextBufMax(MAXCONTEXT); EXPECT_STREQ(contextBuf, expectedContext); - - UninitialiseProcess(FALSE); - Globals_UninitProcess(); } // KM_KBP_IT_INVALIDATE_CONTEXT - processInvalidateContext -TEST(AITIP, processInvalidateContextTest) { - Globals_InitProcess(); - Globals_InitThread(); - +TEST_F(KMPROCESSACTIONS, processInvalidateContextTest) { WCHAR callbuf[MAXCONTEXT]; AITIP testApp; WCHAR expectedContext[] = {0}; @@ -162,7 +155,4 @@ TEST(AITIP, processInvalidateContextTest) { // dispose keyboard km_kbp_state_dispose(testState); km_kbp_keyboard_dispose(testKB); - - UninitialiseProcess(FALSE); - Globals_UninitProcess(); } diff --git a/windows/src/global/inc/keymanengine.h b/windows/src/global/inc/keymanengine.h index dd0dfe78f8..574162049f 100644 --- a/windows/src/global/inc/keymanengine.h +++ b/windows/src/global/inc/keymanengine.h @@ -185,6 +185,9 @@ extern "C" void _declspec(dllexport) WINAPI Keyman_WriteDebugEvent(char* file, i #define ShouldDebug(state) ShouldDebug_1() #define DebugLastError(context) (DebugLastError_1(GetLastError(), (context), __FILE__,__LINE__,__FUNCTION__)) #define DebugLastError0(error, context) (DebugLastError_1((error), (context), __FILE__,__LINE__,__FUNCTION__)) +// On failed condition log "message", return FALSE +// and assert if a debugger is attached for a debug build. +#define DebugAssert(condition, message) (DebugAssert_1((condition),(message), __FILE__, __LINE__)) int SendDebugMessage_1(HWND hwnd, TSDMState state, int kmn_lineno, char* file, int line, char* msg); int SendDebugMessageFormat_1(HWND hwnd, TSDMState state, int kmn_lineno, char* file, int line, char* fmt, ...); void DebugLastError_1(DWORD err, char* context, char* file, int line, char* func); @@ -193,32 +196,9 @@ void DebugShift(char* function, char* point); BOOL DebugSignalPause(BOOL fIsUp); char* Debug_VirtualKey(WORD vk); char* Debug_UnicodeString(PWSTR s, int x = 0); - +BOOL DebugAssert_1(BOOL condition, char* msg, char* file, int line); BOOL ShouldDebug_1(); // TSDMState state); -// On failed condition it will always log "message" and return "retValue" -// it will also assert if a debugger is attached for a debug build. -#define DebugAssertRetValue(condition, message, retValue) \ - { \ - if (!(condition)) { \ - SendDebugMessage_1(0, sdmGlobal, 0, __FILE__, __LINE__, message); \ - if (IsDebugAssertEnabled()) { \ - assert(condition); \ - } \ - return retValue; \ - } \ - } - -#define DebugAssert(condition, message) \ - { \ - if (!(condition)) { \ - SendDebugMessage_1(0, sdmGlobal, 0, __FILE__, __LINE__, message); \ - if (IsDebugAssertEnabled()) { \ - assert(condition); \ - } \ - return; \ - } \ - } #endif #ifdef _DEBUG From 00d4bcded84e58ef4ed4db8d70f37a49206d7860 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Tue, 21 Sep 2021 11:48:56 +1000 Subject: [PATCH 38/63] feat(windows): Apply suggestions from code review Co-authored-by: Marc Durdin --- 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 1aa9dbcb84..531f6e6514 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -317,9 +317,9 @@ SaveKeyboardOptionsCore(LPINTKEYBOARDINFO kp) { 0, sdmKeyboard, 0, "LoadKeyboardOptionsREGCore: 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; + 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) { From deb358de5a731062e331849aa0ea98d9748bec47 Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 22 Sep 2021 11:28:28 +1000 Subject: [PATCH 39/63] feat(windows): add memory leak tests - fix memory leaks --- windows/src/engine/keyman32/appint/aiTIP.cpp | 15 +---- .../src/engine/keyman32/keyboardoptions.cpp | 21 +++++-- windows/src/engine/keyman32/keyboardoptions.h | 8 +++ .../keyboardoptionstests.cpp | 12 +++- .../keyman-engine-tests.vcxproj | 1 + .../kmprocessactionstests.cpp | 18 ++---- .../tests/keyman-engine-tests/pch.cpp | 57 +++++++++++++++++-- 7 files changed, 93 insertions(+), 39 deletions(-) diff --git a/windows/src/engine/keyman32/appint/aiTIP.cpp b/windows/src/engine/keyman32/appint/aiTIP.cpp index fed3936e24..3d523d40fd 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.cpp +++ b/windows/src/engine/keyman32/appint/aiTIP.cpp @@ -233,16 +233,6 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM savedContextUsingCore = new AppContext(); _td->app->CopyContext(savedContextUsingCore); SavedKBDOptions = SaveKeyboardOptionsCore(_td->lpActiveKeyboard); - // TODO: 5653 ---- Alternate option --- - // Instead of allocating memory for each option - // just update the changed options. Consider the commented out method UpdateCoreKeyboard - // options. - /*if (_td->lpActiveKeyboard->lpCoreKeyboardOptions) { - UpdateKeyboardOptionsCore(_td->lpActiveKeyboard->lpCoreKeyboardState, _td->lpActiveKeyboard->lpCoreKeyboardOptions); - } else { - _td->lpActiveKeyboard->lpCoreKeyboardOptions = SaveKeyboardOptionsCore(_td->lpActiveKeyboard); - }*/ - //////// End alternate option } else { // I4370 savedContext = new AppContextWithStores(_td->lpActiveKeyboard->Keyboard->cxStoreArray); // I4978 _td->app->SaveContext(savedContext); @@ -257,11 +247,8 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM // Reset the context if match found _td->app->RestoreContextOnly(savedContextUsingCore); RestoreKeyboardOptionsCore(_td->lpActiveKeyboard->lpCoreKeyboardState, SavedKBDOptions); - delete SavedKBDOptions; + DisposeKeyboardOptionsCore(&SavedKBDOptions); SavedKBDOptions = NULL; - // TODO: 5653 ---- Alternate option --- Instead of allocating memory for each option - //RestoreKeyboardOptionsCore(_td->lpActiveKeyboard->lpCoreKeyboardState, _td->lpActiveKeyboard->lpCoreKeyboardOptions); - /// --- End Alternate option delete savedContextUsingCore; savedContextUsingCore = NULL; } diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index 531f6e6514..c3d76a8a61 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -332,12 +332,12 @@ SaveKeyboardOptionsCore(LPINTKEYBOARDINFO kp) { 0, sdmKeyboard, 0, "SaveCoreOptions: 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[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; + savedKeyboardOpts[listSize] = KM_KBP_OPTIONS_END; + return savedKeyboardOpts; } BOOL @@ -352,3 +352,14 @@ RestoreKeyboardOptionsCore( } return TRUE; } + +BOOL +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; + return TRUE; +} diff --git a/windows/src/engine/keyman32/keyboardoptions.h b/windows/src/engine/keyman32/keyboardoptions.h index 0002db3cf6..b6ec1853a5 100644 --- a/windows/src/engine/keyman32/keyboardoptions.h +++ b/windows/src/engine/keyman32/keyboardoptions.h @@ -72,3 +72,11 @@ void LoadKeyboardOptionsREGCore(LPINTKEYBOARDINFO kp, km_kbp_state* state); * @param value keyboard option value to save */ 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 + */ +BOOL 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 05a53381e0..8bed42b510 100644 --- a/windows/src/engine/keyman32/tests/keyman-engine-tests/keyboardoptionstests.cpp +++ b/windows/src/engine/keyman32/tests/keyman-engine-tests/keyboardoptionstests.cpp @@ -31,6 +31,9 @@ TEST(KEYBOARDOPTIONS, UpdateKeyboardOptionsCore) { value = kp->lpCoreKeyboardOptions[0].value; expectedValue = u"triggered"; EXPECT_TRUE(value == expectedValue); + DisposeKeyboardOptionsCore(&kp->lpCoreKeyboardOptions); + ReleaseStateMemoryCore(&kp->lpCoreKeyboardState); + ReleaseKeyboardMemoryCore(&kp->lpCoreKeyboard); delete kp; } @@ -61,12 +64,15 @@ TEST(KEYBOARDOPTIONS, SaveRestoreKeyboardOptionsCore) { 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); - delete NewKBDOptions; - delete SavedKBDOptions; + DisposeKeyboardOptionsCore(&NewKBDOptions); + DisposeKeyboardOptionsCore(&SavedKBDOptions); + + ReleaseStateMemoryCore(&kp->lpCoreKeyboardState); + ReleaseKeyboardMemoryCore(&kp->lpCoreKeyboard); delete kp; } diff --git a/windows/src/engine/keyman32/tests/keyman-engine-tests/keyman-engine-tests.vcxproj b/windows/src/engine/keyman32/tests/keyman-engine-tests/keyman-engine-tests.vcxproj index c3a28664a3..58ee5917d5 100644 --- a/windows/src/engine/keyman32/tests/keyman-engine-tests/keyman-engine-tests.vcxproj +++ b/windows/src/engine/keyman32/tests/keyman-engine-tests/keyman-engine-tests.vcxproj @@ -38,6 +38,7 @@ $(ProjectDir)bin\$(Platform)\$(Configuration)\ $(ProjectDir)obj\$(Platform)\$(Configuration)\ $(ProjectDir)..\..\..\..\..\..\common\core\desktop\build\x86\$(Configuration)\src;$(ProjectDir)..\..\..\..\..\..\common\core\desktop\build\rust\x86\$(Configuration);$(LibraryPath) + true $(ProjectDir)..\..\..\..\global\inc;$(ProjectDir)..\..;$(IncludePath) diff --git a/windows/src/engine/keyman32/tests/keyman-engine-tests/kmprocessactionstests.cpp b/windows/src/engine/keyman32/tests/keyman-engine-tests/kmprocessactionstests.cpp index 70fe802bdc..dee6d7986f 100644 --- a/windows/src/engine/keyman32/tests/keyman-engine-tests/kmprocessactionstests.cpp +++ b/windows/src/engine/keyman32/tests/keyman-engine-tests/kmprocessactionstests.cpp @@ -1,7 +1,7 @@ #include "pch.h" #include "kmprocessactions.cpp" -// Test the Process Actions private functions +// Test the Process Actions private functions // Note: The following actions are not tested KM_KBP_IT_ALERT, KM_KBP_IT_PERSIST_OPT, KM_KBP_IT_EMIT_KEYSTROKE // KM_KBP_IT_CHAR - processUnicodeChar @@ -16,7 +16,7 @@ processUnicodeChar(&testApp, &itemAddChar); WCHAR *contextBuf = testApp.ContextBufMax(MAXCONTEXT); EXPECT_STREQ(contextBuf, expectedContext); - + km_kbp_usv testSurrogateChar = Uni_SurrogateToUTF32(0xD801, 0xDC37); //𐐷'; km_kbp_action_item itemAddChar2 = {KM_KBP_IT_CHAR, {0,}, {testSurrogateChar}}; WCHAR expectedStringSurrogate[] = {'A', 0xD801, 0xDC37, 0}; @@ -46,11 +46,10 @@ TEST(AITIP, processMarkertest) { Globals_UninitProcess(); } -// KM_KBP_IT_BACK - processBack +// KM_KBP_IT_BACK - processBack // First test processing a backspace for a deadkey TEST(AITIP, processBackDeadkeytest) { Globals_InitProcess(); - Globals_InitThread(); WCHAR callbuf[MAXCONTEXT]; AITIP testApp; @@ -77,7 +76,6 @@ TEST(AITIP, processBackDeadkeytest) { // Also test for Unknown Character TEST(AITIP, processBackCharactertest) { Globals_InitProcess(); - Globals_InitThread(); WCHAR callbuf[MAXCONTEXT]; AITIP testApp; @@ -110,7 +108,6 @@ TEST(AITIP, processBackCharactertest) { // Note currently we don't check for a character match this should be updated TEST(AITIP, processBackUnexpectedChartest) { Globals_InitProcess(); - Globals_InitThread(); WCHAR callbuf[MAXCONTEXT]; AITIP testApp; @@ -135,7 +132,6 @@ TEST(AITIP, processBackUnexpectedChartest) { // KM_KBP_IT_INVALIDATE_CONTEXT - processInvalidateContext TEST(AITIP, processInvalidateContextTest) { Globals_InitProcess(); - Globals_InitThread(); WCHAR callbuf[MAXCONTEXT]; AITIP testApp; @@ -147,11 +143,10 @@ TEST(AITIP, processInvalidateContextTest) { processUnicodeChar(&testApp, &itemAddChar); // A keyboard a state is need to test processInvalidateContext - km_kbp_option_item test_env_opts[] = {{u"hello", u"world", 0}, KM_KBP_OPTIONS_END}; + km_kbp_option_item test_env_opts[] = {{u"hello", u"world", KM_KBP_OPT_KEYBOARD}, KM_KBP_OPTIONS_END}; km_kbp_keyboard *testKB = nullptr; - km_kbp_state *testState = nullptr, *test_clone = nullptr; - km_kbp_path_name dummyPath = L"dummyActions.mock"; - km_kbp_status err_status = km_kbp_keyboard_load(dummyPath, &testKB); + km_kbp_state *testState = nullptr; + km_kbp_path_name dummyPath = L"dummyActions.mock"; EXPECT_EQ(km_kbp_keyboard_load(dummyPath, &testKB), KM_KBP_STATUS_OK); EXPECT_EQ(km_kbp_state_create(testKB, test_env_opts, &testState), KM_KBP_STATUS_OK); @@ -162,7 +157,6 @@ TEST(AITIP, processInvalidateContextTest) { // dispose keyboard km_kbp_state_dispose(testState); km_kbp_keyboard_dispose(testKB); - UninitialiseProcess(FALSE); Globals_UninitProcess(); } diff --git a/windows/src/engine/keyman32/tests/keyman-engine-tests/pch.cpp b/windows/src/engine/keyman32/tests/keyman-engine-tests/pch.cpp index 97b544ec11..c2f9fa87ea 100644 --- a/windows/src/engine/keyman32/tests/keyman-engine-tests/pch.cpp +++ b/windows/src/engine/keyman32/tests/keyman-engine-tests/pch.cpp @@ -1,6 +1,53 @@ -// -// pch.cpp -// Include the standard header and generate the precompiled header. -// - +/** + * @file + * @copyright (c) 2013 Stephan Brenner + * @license This project is released under the MIT License. + * + * Adapted in 2021 from the gtest_mem.cpp + * This file implements a main() function for Google Test that runs all tests + * and detects memory leaks. + */ #include "pch.h" +#include +#include +#include + +using namespace std; +using namespace testing; + +namespace testing { +class MemoryLeakDetector : public EmptyTestEventListener { +#ifdef _DEBUG +public: + virtual void + OnTestStart(const TestInfo&) { + _CrtMemCheckpoint(&memState_); + } + + virtual void + OnTestEnd(const TestInfo& test_info) { + if (test_info.result()->Passed()) { + _CrtMemState stateNow, stateDiff; + _CrtMemCheckpoint(&stateNow); + int diffResult = _CrtMemDifference(&stateDiff, &memState_, &stateNow); + if (diffResult) { + FAIL() << "Memory leak of " << stateDiff.lSizes[1] << " byte(s) detected."; + } + } + } + +private: + _CrtMemState memState_; +#endif // _DEBUG +}; +} // namespace testing + +GTEST_API_ int +main(int argc, char** argv) { + cout << "Running main() from pch.cpp" << endl; + + InitGoogleTest(&argc, argv); + UnitTest::GetInstance()->listeners().Append(new MemoryLeakDetector()); + + return RUN_ALL_TESTS(); +} From 64dbaad37102a9846acaf2a0fa5347a1408c4e33 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Wed, 22 Sep 2021 16:11:36 +1000 Subject: [PATCH 40/63] feat(windows): Apply suggestions from code review Co-authored-by: Marc Durdin --- windows/src/engine/keyman32/keyboardoptions.cpp | 10 +++++----- windows/src/engine/keyman32/keyboardoptions.h | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index c3d76a8a61..be8a5e303f 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -293,7 +293,7 @@ UpdateKeyboardOptionsCore( &retValue); if (err_status != KM_KBP_STATUS_OK) { SendDebugMessageFormat( - 0, sdmKeyboard, 0, "SaveCoreOptions: km_kbp_state_option_lookup failed with error status [%d]", err_status); + 0, sdmKeyboard, 0, "UpdateKeyboardOptionsCore: km_kbp_state_option_lookup failed with error status [%d]", err_status); continue; } // compare to see if changed @@ -314,7 +314,7 @@ SaveKeyboardOptionsCore(LPINTKEYBOARDINFO kp) { 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, "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); @@ -329,7 +329,7 @@ SaveKeyboardOptionsCore(LPINTKEYBOARDINFO kp) { 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, "SaveCoreOptions: km_kbp_state_option_lookup failed with error status [%d]", err_status); + 0, sdmKeyboard, 0, "SaveKeyboardOptionsCore: km_kbp_state_option_lookup failed with error status [%d]", err_status); continue; } savedKeyboardOpts[i].key = CloneKMKBPCP(kbDefaultOpts->key); @@ -347,13 +347,13 @@ RestoreKeyboardOptionsCore( km_kbp_status err_status = km_kbp_state_options_update(lpCoreKeyboardState, lpCoreKeyboardOptions); 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, "RestoreKeyboardOptionsCore: km_kbp_state_options_update failed with error status [%d]", err_status); return FALSE; } return TRUE; } -BOOL +void DisposeKeyboardOptionsCore(km_kbp_option_item** lpCoreKeyboardOptions) { size_t listSize = km_kbp_options_list_size(*lpCoreKeyboardOptions); for (int i = 0; i < (int)listSize; i++) { diff --git a/windows/src/engine/keyman32/keyboardoptions.h b/windows/src/engine/keyman32/keyboardoptions.h index b6ec1853a5..cef9ae6df1 100644 --- a/windows/src/engine/keyman32/keyboardoptions.h +++ b/windows/src/engine/keyman32/keyboardoptions.h @@ -26,7 +26,7 @@ void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp); * Updates the supplied Keyboard processor options list from the keyboard processor pointed * to by the state pointer. * - * @param lpCoreKeyboardState The core keyboardprocessor state which as the source options + * @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 */ @@ -36,7 +36,7 @@ BOOL UpdateKeyboardOptionsCore(km_kbp_state* const lpCoreKeyboardState, km_kbp_o * 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 the keyboard info object that constains the + * @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 @@ -44,7 +44,7 @@ BOOL UpdateKeyboardOptionsCore(km_kbp_state* const lpCoreKeyboardState, km_kbp_o km_kbp_option_item* SaveKeyboardOptionsCore(LPINTKEYBOARDINFO kp); /** - * Restore the core keyboard processor options to from the supplied keyboard + * 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 @@ -79,4 +79,4 @@ void SaveKeyboardOptionREGCore(LPINTKEYBOARDINFO kp, LPCWSTR key, LPWSTR value); * * @param lpCoreKeyboardOptions keyboard options items to be freed */ -BOOL DisposeKeyboardOptionsCore(km_kbp_option_item** lpCoreKeyboardOptions); +void DisposeKeyboardOptionsCore(km_kbp_option_item** lpCoreKeyboardOptions); From 1c405c51421b692e04d800e272e7adf66814c97f Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 22 Sep 2021 16:33:30 +1000 Subject: [PATCH 41/63] feat(windows): Address review comments --- windows/src/engine/keyman32/appint/aiTIP.cpp | 1 - .../src/engine/keyman32/keyboardoptions.cpp | 2 +- .../tests/keyman-engine-tests/gtest_main.cpp | 53 +++++++++++++++++ .../keyman-engine-tests.vcxproj | 1 + .../tests/keyman-engine-tests/pch.cpp | 57 ++----------------- 5 files changed, 60 insertions(+), 54 deletions(-) create mode 100644 windows/src/engine/keyman32/tests/keyman-engine-tests/gtest_main.cpp diff --git a/windows/src/engine/keyman32/appint/aiTIP.cpp b/windows/src/engine/keyman32/appint/aiTIP.cpp index 3d523d40fd..c14ceee360 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.cpp +++ b/windows/src/engine/keyman32/appint/aiTIP.cpp @@ -248,7 +248,6 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM _td->app->RestoreContextOnly(savedContextUsingCore); RestoreKeyboardOptionsCore(_td->lpActiveKeyboard->lpCoreKeyboardState, SavedKBDOptions); DisposeKeyboardOptionsCore(&SavedKBDOptions); - SavedKBDOptions = NULL; delete savedContextUsingCore; savedContextUsingCore = NULL; } diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index be8a5e303f..4a731185ce 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -361,5 +361,5 @@ DisposeKeyboardOptionsCore(km_kbp_option_item** lpCoreKeyboardOptions) { delete[] (*lpCoreKeyboardOptions)[i].value; } delete[] *lpCoreKeyboardOptions; - return TRUE; + *lpCoreKeyboardOptions = NULL; } diff --git a/windows/src/engine/keyman32/tests/keyman-engine-tests/gtest_main.cpp b/windows/src/engine/keyman32/tests/keyman-engine-tests/gtest_main.cpp new file mode 100644 index 0000000000..2372920b53 --- /dev/null +++ b/windows/src/engine/keyman32/tests/keyman-engine-tests/gtest_main.cpp @@ -0,0 +1,53 @@ +/** + * @file + * @copyright (c) 2013 Stephan Brenner + * @license This project is released under the MIT License. + * + * Adapted in 2021 from the gtest_mem.cpp + * This file implements a main() function for Google Test that runs all tests + * and detects memory leaks. + */ +#include "pch.h" +#include +#include +#include + +using namespace std; +using namespace testing; + +namespace testing { +class MemoryLeakDetector : public EmptyTestEventListener { +#ifdef _DEBUG +public: + virtual void + OnTestStart(const TestInfo&) { + _CrtMemCheckpoint(&memState_); + } + + virtual void + OnTestEnd(const TestInfo& test_info) { + if (test_info.result()->Passed()) { + _CrtMemState stateNow, stateDiff; + _CrtMemCheckpoint(&stateNow); + int diffResult = _CrtMemDifference(&stateDiff, &memState_, &stateNow); + if (diffResult) { + FAIL() << "Memory leak of " << stateDiff.lSizes[1] << " byte(s) detected."; + } + } + } + +private: + _CrtMemState memState_; +#endif // _DEBUG +}; +} // namespace testing + +GTEST_API_ int +main(int argc, char** argv) { + cout << "Running main() from pch.cpp" << endl; + + InitGoogleTest(&argc, argv); + UnitTest::GetInstance()->listeners().Append(new MemoryLeakDetector()); + + return RUN_ALL_TESTS(); +} diff --git a/windows/src/engine/keyman32/tests/keyman-engine-tests/keyman-engine-tests.vcxproj b/windows/src/engine/keyman32/tests/keyman-engine-tests/keyman-engine-tests.vcxproj index 58ee5917d5..ba8ae6d7ae 100644 --- a/windows/src/engine/keyman32/tests/keyman-engine-tests/keyman-engine-tests.vcxproj +++ b/windows/src/engine/keyman32/tests/keyman-engine-tests/keyman-engine-tests.vcxproj @@ -60,6 +60,7 @@ + diff --git a/windows/src/engine/keyman32/tests/keyman-engine-tests/pch.cpp b/windows/src/engine/keyman32/tests/keyman-engine-tests/pch.cpp index c2f9fa87ea..97b544ec11 100644 --- a/windows/src/engine/keyman32/tests/keyman-engine-tests/pch.cpp +++ b/windows/src/engine/keyman32/tests/keyman-engine-tests/pch.cpp @@ -1,53 +1,6 @@ -/** - * @file - * @copyright (c) 2013 Stephan Brenner - * @license This project is released under the MIT License. - * - * Adapted in 2021 from the gtest_mem.cpp - * This file implements a main() function for Google Test that runs all tests - * and detects memory leaks. - */ +// +// pch.cpp +// Include the standard header and generate the precompiled header. +// + #include "pch.h" -#include -#include -#include - -using namespace std; -using namespace testing; - -namespace testing { -class MemoryLeakDetector : public EmptyTestEventListener { -#ifdef _DEBUG -public: - virtual void - OnTestStart(const TestInfo&) { - _CrtMemCheckpoint(&memState_); - } - - virtual void - OnTestEnd(const TestInfo& test_info) { - if (test_info.result()->Passed()) { - _CrtMemState stateNow, stateDiff; - _CrtMemCheckpoint(&stateNow); - int diffResult = _CrtMemDifference(&stateDiff, &memState_, &stateNow); - if (diffResult) { - FAIL() << "Memory leak of " << stateDiff.lSizes[1] << " byte(s) detected."; - } - } - } - -private: - _CrtMemState memState_; -#endif // _DEBUG -}; -} // namespace testing - -GTEST_API_ int -main(int argc, char** argv) { - cout << "Running main() from pch.cpp" << endl; - - InitGoogleTest(&argc, argv); - UnitTest::GetInstance()->listeners().Append(new MemoryLeakDetector()); - - return RUN_ALL_TESTS(); -} From 71f97d46aa86a824793d20144cc1eb24c2a15715 Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 22 Sep 2021 16:51:14 +1000 Subject: [PATCH 42/63] feat(windows): add link to mem leak github repo --- .../engine/keyman32/tests/keyman-engine-tests/gtest_main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/windows/src/engine/keyman32/tests/keyman-engine-tests/gtest_main.cpp b/windows/src/engine/keyman32/tests/keyman-engine-tests/gtest_main.cpp index 2372920b53..0b5471de2f 100644 --- a/windows/src/engine/keyman32/tests/keyman-engine-tests/gtest_main.cpp +++ b/windows/src/engine/keyman32/tests/keyman-engine-tests/gtest_main.cpp @@ -2,7 +2,7 @@ * @file * @copyright (c) 2013 Stephan Brenner * @license This project is released under the MIT License. - * + * repo: https://github.com/stbrenner/gtest_mem * Adapted in 2021 from the gtest_mem.cpp * This file implements a main() function for Google Test that runs all tests * and detects memory leaks. @@ -44,7 +44,7 @@ private: GTEST_API_ int main(int argc, char** argv) { - cout << "Running main() from pch.cpp" << endl; + cout << "Running main() from gtest_main.cpp" << endl; InitGoogleTest(&argc, argv); UnitTest::GetInstance()->listeners().Append(new MemoryLeakDetector()); From d4b9f1810602470e9b2438e5f378b4e68cce76c3 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 24 Sep 2021 14:01:24 +1000 Subject: [PATCH 43/63] fix(developer): move ampersand to shift+7 on touch Fixes #5702. On the phone layout for two templates, ampersand (`&`) was on Shift+6 instead of on Shift+7. --- .../template-basic.keyman-touch-layout | 2 +- .../template-traditional.keyman-touch-layout | 54 +++++++++---------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/windows/src/developer/TIKE/xml/layoutbuilder/template-basic.keyman-touch-layout b/windows/src/developer/TIKE/xml/layoutbuilder/template-basic.keyman-touch-layout index 967ba6e179..2887e3b0a6 100644 --- a/windows/src/developer/TIKE/xml/layoutbuilder/template-basic.keyman-touch-layout +++ b/windows/src/developer/TIKE/xml/layoutbuilder/template-basic.keyman-touch-layout @@ -377,7 +377,7 @@ {"id": "K_2","layer":"shift","text": "@"}, {"id": "K_3","layer":"shift","text": "#"}, {"id": "K_5","layer":"shift","text": "%"}, - {"id": "K_6","layer":"shift","text": "&"}, + {"id": "K_7","layer":"shift","text": "&"}, {"id": "K_HYPHEN","layer":"shift","text": "_"}, {"id": "K_EQUAL","text": "=","layer":"default"}, {"id": "K_BKSLASH","layer":"shift","text": "|"}, diff --git a/windows/src/developer/TIKE/xml/layoutbuilder/template-traditional.keyman-touch-layout b/windows/src/developer/TIKE/xml/layoutbuilder/template-traditional.keyman-touch-layout index 7ebac15051..09bc393bb9 100644 --- a/windows/src/developer/TIKE/xml/layoutbuilder/template-traditional.keyman-touch-layout +++ b/windows/src/developer/TIKE/xml/layoutbuilder/template-traditional.keyman-touch-layout @@ -22,7 +22,7 @@ {"id": "K_EQUAL","text": "="}, {"id": "K_BKSP","text": "*BkSp*","width": "100","sp": "1"} ] - }, + }, { "id": 2, "key": [ @@ -38,7 +38,7 @@ {"id": "K_P","text":"p"}, {"id": "K_LBRKT","text":"["}, {"id": "K_RBRKT","text":"]"}, - {"sp":"10","width":"10"} + {"sp":"10","width":"10"} ] }, { @@ -84,7 +84,7 @@ {"id": "K_LALT","text": "*Alt*","width": "130","sp": "1"}, {"id": "K_SPACE","text": "","width": "675","sp": "0"}, {"id": "K_RALT","text": "*AltGr*","width": "130","sp": "1"}, - {"id": "K_RCONTROL","text": "*Ctrl*","width": "130","sp": "1"} + {"id": "K_RCONTROL","text": "*Ctrl*","width": "130","sp": "1"} ] } ] @@ -109,7 +109,7 @@ {"id": "K_EQUAL","text": "+"}, {"id": "K_BKSP","text": "*BkSp*","width": "100","sp": "1"} ] - }, + }, { "id": 2, "key": [ @@ -125,7 +125,7 @@ {"id": "K_P","text":"P"}, {"id": "K_LBRKT","text":"{"}, {"id": "K_RBRKT","text":"}"}, - {"sp":"10","width":"10"} + {"sp":"10","width":"10"} ] }, { @@ -171,7 +171,7 @@ {"id": "K_LALT","text": "*Alt*","width": "130","sp": "1"}, {"id": "K_SPACE","text": "","width": "675","sp": "0"}, {"id": "K_RALT","text": "*AltGr*","width": "130","sp": "1"}, - {"id": "K_RCONTROL","text": "*Ctrl*","width": "130","sp": "1"} + {"id": "K_RCONTROL","text": "*Ctrl*","width": "130","sp": "1"} ] } ] @@ -196,7 +196,7 @@ {"id": "K_EQUAL"}, {"id": "K_BKSP","text": "*BkSp*","width": "100","sp": "1"} ] - }, + }, { "id": 2, "key": [ @@ -212,7 +212,7 @@ {"id": "K_P"}, {"id": "K_LBRKT"}, {"id": "K_RBRKT"}, - {"sp":"10","width":"10"} + {"sp":"10","width":"10"} ] }, { @@ -258,7 +258,7 @@ {"id": "K_LALT","text": "*Alt*","width": "130","sp": "1"}, {"id": "K_SPACE","text": "","width": "675","sp": "0"}, {"id": "K_RALT","text": "*AltGr*","width": "130","sp": "1"}, - {"id": "K_RCONTROL","text": "*Ctrl*","width": "130","sp": "2"} + {"id": "K_RCONTROL","text": "*Ctrl*","width": "130","sp": "2"} ] } ] @@ -283,7 +283,7 @@ {"id": "K_EQUAL"}, {"id": "K_BKSP","text": "*BkSp*","width": "100","sp": "1"} ] - }, + }, { "id": 2, "key": [ @@ -299,7 +299,7 @@ {"id": "K_P"}, {"id": "K_LBRKT"}, {"id": "K_RBRKT"}, - {"sp":"10","width":"10"} + {"sp":"10","width":"10"} ] }, { @@ -345,7 +345,7 @@ {"id": "K_LALT","text": "*Alt*","width": "130","sp": "1"}, {"id": "K_SPACE","text": "","width": "675","sp": "0"}, {"id": "K_RALT","text": "*AltGr*","width": "130","sp": "1"}, - {"id": "K_RCONTROL","text": "*Ctrl*","width": "130","sp": "2"} + {"id": "K_RCONTROL","text": "*Ctrl*","width": "130","sp": "2"} ] } ] @@ -370,7 +370,7 @@ {"id": "K_EQUAL"}, {"id": "K_BKSP","text": "*BkSp*","width": "100","sp": "1"} ] - }, + }, { "id": 2, "key": [ @@ -386,7 +386,7 @@ {"id": "K_P"}, {"id": "K_LBRKT"}, {"id": "K_RBRKT"}, - {"sp":"10","width":"10"} + {"sp":"10","width":"10"} ] }, { @@ -432,7 +432,7 @@ {"id": "K_LALT","text": "*Alt*","width": "130","sp": "2"}, {"id": "K_SPACE","text": "","width": "675","sp": "0"}, {"id": "K_RALT","text": "*AltGr*","width": "130","sp": "2"}, - {"id": "K_RCONTROL","text": "*Ctrl*","width": "130","sp": "1"} + {"id": "K_RCONTROL","text": "*Ctrl*","width": "130","sp": "1"} ] } ] @@ -457,7 +457,7 @@ {"id": "K_EQUAL"}, {"id": "K_BKSP","text": "*BkSp*","width": "100","sp": "1"} ] - }, + }, { "id": 2, "key": [ @@ -473,7 +473,7 @@ {"id": "K_P"}, {"id": "K_LBRKT"}, {"id": "K_RBRKT"}, - {"sp":"10","width":"10"} + {"sp":"10","width":"10"} ] }, { @@ -519,7 +519,7 @@ {"id": "K_LALT","text": "*Alt*","width": "130","sp": "2"}, {"id": "K_SPACE","text": "","width": "675","sp": "0"}, {"id": "K_RALT","text": "*AltGr*","width": "130","sp": "2"}, - {"id": "K_RCONTROL","text": "*Ctrl*","width": "130","sp": "1"} + {"id": "K_RCONTROL","text": "*Ctrl*","width": "130","sp": "1"} ] } ] @@ -544,7 +544,7 @@ {"id": "K_EQUAL"}, {"id": "K_BKSP","text": "*BkSp*","width": "100","sp": "1"} ] - }, + }, { "id": 2, "key": [ @@ -560,7 +560,7 @@ {"id": "K_P"}, {"id": "K_LBRKT"}, {"id": "K_RBRKT"}, - {"sp":"10","width":"10"} + {"sp":"10","width":"10"} ] }, { @@ -606,7 +606,7 @@ {"id": "K_LALT","text": "*Alt*","width": "130","sp": "2"}, {"id": "K_SPACE","text": "","width": "675","sp": "0"}, {"id": "K_RALT","text": "*AltGr*","width": "130","sp": "2"}, - {"id": "K_RCONTROL","text": "*Ctrl*","width": "130","sp": "2"} + {"id": "K_RCONTROL","text": "*Ctrl*","width": "130","sp": "2"} ] } ] @@ -631,7 +631,7 @@ {"id": "K_EQUAL"}, {"id": "K_BKSP","text": "*BkSp*","width": "100","sp": "1"} ] - }, + }, { "id": 2, "key": [ @@ -647,7 +647,7 @@ {"id": "K_P"}, {"id": "K_LBRKT"}, {"id": "K_RBRKT"}, - {"sp":"10","width":"10"} + {"sp":"10","width":"10"} ] }, { @@ -693,7 +693,7 @@ {"id": "K_LALT","text": "*Alt*","width": "130","sp": "2"}, {"id": "K_SPACE","text": "","width": "675","sp": "0"}, {"id": "K_RALT","text": "*AltGr*","width": "130","sp": "2"}, - {"id": "K_RCONTROL","text": "*Ctrl*","width": "130","sp": "2"} + {"id": "K_RCONTROL","text": "*Ctrl*","width": "130","sp": "2"} ] } ] @@ -733,7 +733,7 @@ {"id": "K_J","text":"j"}, {"id": "K_K","text":"k"}, {"id": "K_L","text":"l"}, - {"text": "","width": "10","sp": "10"} + {"text": "","width": "10","sp": "10"} ] }, { @@ -802,7 +802,7 @@ {"id": "K_J","text":"J"}, {"id": "K_K","text":"K"}, {"id": "K_L","text":"L"}, - {"text": "","width": "10","sp": "10"} + {"text": "","width": "10","sp": "10"} ] }, { @@ -866,7 +866,7 @@ {"id": "K_2","layer":"shift","text": "@"}, {"id": "K_3","layer":"shift","text": "#"}, {"id": "K_5","layer":"shift","text": "%"}, - {"id": "K_6","layer":"shift","text": "&"}, + {"id": "K_7","layer":"shift","text": "&"}, {"id": "K_HYPHEN","layer":"shift","text": "_"}, {"id": "K_EQUAL","text": "=","layer":"default"}, {"id": "K_BKSLASH","layer":"shift","text": "|"}, From a65b55e1b5ce7b647c06935da9e4c43512339817 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 27 Sep 2021 06:54:24 +1000 Subject: [PATCH 44/63] fix(web): support variable stores with predictive text Fixes #2924. When a keyboard includes variable stores, predictive text fat-fingering tests will no longer affect the variable store values. --- .../src/keyboards/keyboard.ts | 82 +++++++++++++++---- .../src/text/kbdInterface.ts | 22 +++++ .../src/text/ruleBehavior.ts | 21 +++-- .../TIKE/compile/CompileKeymanWeb.pas | 14 +++- 4 files changed, 114 insertions(+), 25 deletions(-) diff --git a/common/core/web/keyboard-processor/src/keyboards/keyboard.ts b/common/core/web/keyboard-processor/src/keyboards/keyboard.ts index bedfadfb00..857d2c223d 100644 --- a/common/core/web/keyboard-processor/src/keyboards/keyboard.ts +++ b/common/core/web/keyboard-processor/src/keyboards/keyboard.ts @@ -20,9 +20,14 @@ namespace com.keyman.keyboards { CALIBRATED = 2 } + export interface VariableStoreDictionary { + [name: string]: string; + }; + + /** * Acts as a wrapper class for Keyman keyboards compiled to JS, providing type information - * and keyboard-centered functionality in an object-oriented way without modifying the + * and keyboard-centered functionality in an object-oriented way without modifying the * wrapped keyboard itself. */ export class Keyboard { @@ -37,7 +42,7 @@ namespace com.keyman.keyboards { /** * This is the object provided to KeyboardInterface.registerKeyboard - that is, the keyboard * being wrapped. - * + * * TODO: Make this private instead. But there are a LOT of references that must be rooted out first. */ public readonly scriptObject: any; @@ -71,6 +76,51 @@ namespace com.keyman.keyboards { return this.scriptObject['KN']; } + /** + * Cache variable store values + * + * Primarily used for predictive text to prevent variable store + * values from being changed in 'fat finger' processing. + * + * KVS is available in keyboards compiled with Keyman Developer 15 + * and later versions. See #2924. + * + * @returns an object with each property referencing a variable store + */ + get variableStores(): VariableStoreDictionary { + const storeNames = this.scriptObject['KVS']; + let values = {}; + if(Array.isArray(storeNames)) { + for(let store of storeNames) { + values[store] = this.scriptObject[store]; + } + } + return values; + } + + /** + * Restore variable store values from cache + * + * KVS is available in keyboards compiled with Keyman Developer 15 + * and later versions. See #2924. + * + * @param values name-value pairs for each store value + */ + set variableStores(values: VariableStoreDictionary) { + const storeNames = this.scriptObject['KVS']; + if(Array.isArray(storeNames)) { + for(let store of storeNames) { + // If the value is not present in the cache, don't overwrite it; + // while this is not used in initial implementation, we could use + // it in future to update a single variable store value rather than + // the whole cache. + if(typeof values[store] == 'string') { + this.scriptObject[store] = values[store]; + } + } + } + } + // TODO: Better typing. private get _legacyLayoutSpec(): any { return this.scriptObject['KV']; // used with buildDefaultLayout; layout must be constructed at runtime. @@ -99,7 +149,7 @@ namespace com.keyman.keyboards { /** * HTML help text, as specified by either the &kmw_helptext or &kmw_helpfile system stores. - * + * * Reference: https://help.keyman.com/developer/language/reference/kmw_helptext, * https://help.keyman.com/developer/language/reference/kmw_helpfile */ @@ -121,7 +171,7 @@ namespace com.keyman.keyboards { * Embeds a custom script for use by the OSK, which may be interactive (like with sil_euro_latin). * Note: this must be called AFTER any contents of `helpText` have been inserted into the DOM. * (See sil_euro_latin's source -> sil_euro_latin_js.txt) - * + * * Reference: https://help.keyman.com/developer/language/reference/kmw_embedjs */ embedScript(e: any) { @@ -136,10 +186,10 @@ namespace com.keyman.keyboards { /** * true if this keyboard uses a (legacy) pick list (Chinese, Japanese, Korean, etc.) - * + * * TODO: Make a property on keyboards (say, `isPickList` / `KPL`) to signal this when we * get around to better, generalized picker-list support. - */ + */ get isCJK(): boolean { // I3363 (Build 301) var lg: string; if(typeof(this.scriptObject['KLC']) != 'undefined') { @@ -147,7 +197,7 @@ namespace com.keyman.keyboards { } else if(typeof(this.scriptObject['LanguageCode']) != 'undefined') { lg = this.scriptObject['LanguageCode']; } - + // While some of these aren't proper BCP-47 language codes, the CJK keyboards predate our use of BCP-47. // So, we preserve the old ISO 639-3 codes, as that's what the keyboards are matching against. return ((lg == 'cmn') || (lg == 'jpn') || (lg == 'kor')); @@ -186,7 +236,7 @@ namespace com.keyman.keyboards { this.scriptObject['_kmw'] = tag; } - return tag; + return tag; } get explodedStores(): {[storeName: string]: text.ComplexKeyboardStore} { @@ -209,7 +259,7 @@ namespace com.keyman.keyboards { if(this._legacyLayoutSpec == null) { return false; } - + // Only exists in KMW 10.0+, but before that Web had no chirality support, so... return false. let layers = this._legacyLayoutSpec['KLS']; if(!layers) { @@ -219,18 +269,18 @@ namespace com.keyman.keyboards { var emulationMask = modifierCodes['LCTRL'] | modifierCodes['LALT']; var unshiftedEmulationLayer = layers[Layouts.getLayerId(emulationMask)]; var shiftedEmulationLayer = layers[Layouts.getLayerId(modifierCodes['SHIFT'] | emulationMask)]; - + // buildDefaultLayout ensures that these are aliased to the original modifier set being emulated. // As a result, we can directly test for reference equality. // // This allows us to still return `true` after creating the layers for emulation; during keyboard // construction, the two layers should be null for AltGr emulation to succeed. - if(unshiftedEmulationLayer != null && + if(unshiftedEmulationLayer != null && unshiftedEmulationLayer != layers[Layouts.getLayerId(modifierCodes['RALT'])]) { return false; } - if(shiftedEmulationLayer != null && + if(shiftedEmulationLayer != null && shiftedEmulationLayer != layers[Layouts.getLayerId(modifierCodes['RALT'] | modifierCodes['SHIFT'])]) { return false; } @@ -273,9 +323,9 @@ namespace com.keyman.keyboards { /** * @param {number} _PCommand event code (16,17,18) or 0 * @param {Object} _PTarget target element - * @param {number} _PData 1 or 0 + * @param {number} _PData 1 or 0 * Notifies keyboard of keystroke or other event - */ + */ notify(_PCommand: number, _PTarget: text.OutputTarget, _PData: number) { // I2187 // Good example use case - the Japanese CJK-picker keyboard if(typeof(this.scriptObject['KNS']) == 'function') { @@ -318,7 +368,7 @@ namespace com.keyman.keyboards { rawSpecifications = {'F':'Tahoma', 'BK': Layouts.dfltText}; } - // Regardless of success, we'll want to initialize the field that backs the property; + // Regardless of success, we'll want to initialize the field that backs the property; // may as well cache the default layout we just built, or a 'null' if it shouldn't exist.. if(!this._layouts) { this._layouts = {}; @@ -339,7 +389,7 @@ namespace com.keyman.keyboards { /** * Returns an ActiveLayout object representing the keyboard's layout for this form factor. May return null if a custom desktop "help" OSK is defined, as with sil_euro_latin. - * + * * In such cases, please use either `helpText` or `insertHelpHTML` instead. * @param formFactor {string} The desired form factor for the layout. */ diff --git a/common/core/web/keyboard-processor/src/text/kbdInterface.ts b/common/core/web/keyboard-processor/src/text/kbdInterface.ts index 1324a9f167..e80229fe7f 100644 --- a/common/core/web/keyboard-processor/src/text/kbdInterface.ts +++ b/common/core/web/keyboard-processor/src/text/kbdInterface.ts @@ -972,6 +972,9 @@ namespace com.keyman.text { // Capture the initial state of the OutputTarget before any rules are matched. let preInput = Mock.from(outputTarget); + // Capture the initial state of any variable stores + const cachedVariableStores = this.activeKeyboard.variableStores; + // Establishes the results object, allowing corresponding commands to set values here as appropriate. this.ruleBehavior = new RuleBehavior(); @@ -987,6 +990,12 @@ namespace com.keyman.text { // Finalize the rule's results. this.ruleBehavior.transcription = outputTarget.buildTranscriptionFrom(preInput, keystroke); + // We always backup the changes to variable stores to the RuleBehavior, to + // be applied during finalization, then restore them to the cached initial + // values to avoid side-effects with predictive text mocks. + this.ruleBehavior.variableStores = this.activeKeyboard.variableStores; + this.activeKeyboard.variableStores = cachedVariableStores; + // `matched` refers to whether or not the FINAL rule (from any group) matched, rather than // whether or not ANY rule matched. If the final rule doesn't match, we trigger the key's // default behavior (if appropriate). @@ -1001,6 +1010,19 @@ namespace com.keyman.text { return behavior; } + /** + * Applies the dictionary of variable store values to the active keyboard + * + * Has no effect on keyboards compiled with 14.0 or earlier; system store + * names are not exposed unless compiled with Developer 15.0 or later. + * + * @param VariableStoreDictionary A dictionary of stores which should be + * found in the keyboard + */ + applyVariableStores(stores: com.keyman.keyboards.VariableStoreDictionary): void { + this.activeKeyboard.variableStores = stores; + } + /** * Publishes the KeyboardInterface's shorthand API names. As this assigns the current functions * held by the longform versions, note that this should be called after replacing any of them via diff --git a/common/core/web/keyboard-processor/src/text/ruleBehavior.ts b/common/core/web/keyboard-processor/src/text/ruleBehavior.ts index 2ce6df5d77..27eadcfe3e 100644 --- a/common/core/web/keyboard-processor/src/text/ruleBehavior.ts +++ b/common/core/web/keyboard-processor/src/text/ruleBehavior.ts @@ -24,6 +24,11 @@ namespace com.keyman.text { */ saveStore: {[name: string]: VariableStore} = {}; + /** + * A set of variable stores with possible changes to be applied during finalization. + */ + variableStores: keyboards.VariableStoreDictionary = {}; + /** * Denotes a non-output default behavior; this should be evaluated later, against the true keystroke. */ @@ -46,9 +51,9 @@ namespace com.keyman.text { /** * In reference to https://github.com/keymanapp/keyman/pull/4350#issuecomment-768753852: - * - * If the final group processed is a context and keystroke group (using keys), - * and there is no nomatch rule, and the keystroke is not matched in the group, + * + * If the final group processed is a context and keystroke group (using keys), + * and there is no nomatch rule, and the keystroke is not matched in the group, * the keystroke's default behavior should trigger, regardless of whether or not any * rules in prior groups matched. */ @@ -78,6 +83,8 @@ namespace com.keyman.text { } } + processor.keyboardInterface.applyVariableStores(this.variableStores); + if(processor.keyboardInterface.variableStoreSerializer) { for(let storeID in this.saveStore) { processor.keyboardInterface.variableStoreSerializer.saveStore(processor.activeKeyboard.id, storeID, this.saveStore[storeID]); @@ -99,13 +106,13 @@ namespace com.keyman.text { /** * Merges default-related behaviors from another RuleBehavior into this one. Assumes that the current instance * "came first" chronologically. Both RuleBehaviors must be sourced from the same keystroke. - * + * * Intended use: merging rule-based behavior with default key behavior during scenarios like those described * at https://github.com/keymanapp/keyman/pull/4350#issuecomment-768753852. - * + * * This function does not attempt a "complete" merge for two fully-constructed RuleBehaviors! Things * WILL break for unintended uses. - * @param other + * @param other */ mergeInDefaults(other: RuleBehavior) { let keystroke = this.transcription.keystroke; @@ -115,7 +122,7 @@ namespace com.keyman.text { } this.triggersDefaultCommand = this.triggersDefaultCommand || other.triggersDefaultCommand; - + let mergingMock = Mock.from(this.transcription.preInput); mergingMock.apply(this.transcription.transform); mergingMock.apply(other.transcription.transform); diff --git a/windows/src/developer/TIKE/compile/CompileKeymanWeb.pas b/windows/src/developer/TIKE/compile/CompileKeymanWeb.pas index 469052c962..086700df0d 100644 --- a/windows/src/developer/TIKE/compile/CompileKeymanWeb.pas +++ b/windows/src/developer/TIKE/compile/CompileKeymanWeb.pas @@ -1856,6 +1856,7 @@ var HasRules: Boolean; sModifierBitmask: string; fDisplayUnderlying: Boolean; + FOptionStores: string; begin Result := '';//UTF16SignatureW; // + '// compiled by Keyman Developer'+nl; // I3474 { Locate the name of the keyboard } @@ -2067,6 +2068,7 @@ begin Result := Result + Format('%sthis.KCSS="%s";%s', [FTabStop, RequotedString(sEmbedCSS), nl]); { Write the stores out } + FOptionStores := ''; fsp := fk.dpStoreArray; for i := 0 to fk.cxStoreArray - 1 do begin @@ -2081,18 +2083,26 @@ begin //else if fsp.dwSystemID = TSS_VKDICTIONARY then // I3438, required for vkdictionary // Result := Result + Format('%sthis.s%s=%s;%s', [FTabStop, JavaScript_Name(i, fsp.szName), JavaScript_Store(fsp.line, fsp.dpString), nl]) else if fsp.fIsOption and not fsp.fIsReserved then + begin Result := Result + Format('%sthis.s%s=KeymanWeb.KLOAD(this.KI,"%s",%s);%s', [FTabstop, JavaScript_Name(i,fsp.szName), JavaScript_Name(i,fsp.szName,True), JavaScript_Store(fsp.line, fsp.dpString), - nl]) // I3429 - else if fsp.dwSystemID = TSS_NONE then + nl]); // I3429 + + if FOptionStores <> '' then + FOptionStores := FOptionStores + ','; + FOptionStores := FOptionStores + Format('''s%s''', [JavaScript_Name(i,fsp.szName)]); + end + else if fsp.dwSystemID = TSS_NONE {aka not fsp.fIsReserved} then Result := Result + Format('%sthis.s%s=%s;%s', [FTabStop, JavaScript_Name(i, fsp.szName), JavaScript_Store(fsp.line, fsp.dpString), nl]); // I3681 end; Inc(fsp); end; + Result := Result + Format('%sthis.KVS=[%s];%s', [FTabStop, FOptionStores, nl]); + { Write the groups out } // I853 - begin unicode missing causes crash From 920861e7bbb6ed6f664eab59eb94323361a97d86 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 27 Sep 2021 10:17:12 +1000 Subject: [PATCH 45/63] chore(web): unit tests for fat finger and variable store --- web/testing/common/test.css | 22 ++++ web/testing/index.html | 1 + web/testing/issue2924/dmg.dv.test.model.js | 55 ++++++++++ web/testing/issue2924/header.js | 34 ++++++ web/testing/issue2924/index.html | 25 +++++ .../issue2924/source/dmg.dv.test/HISTORY.md | 6 ++ .../issue2924/source/dmg.dv.test/LICENSE.md | 21 ++++ .../issue2924/source/dmg.dv.test/README.md | 29 +++++ .../source/dmg.dv.test/dmg.dv.test.kpj | 83 ++++++++++++++ .../source/dmg.dv.test/dmg.dv.test.model_info | 7 ++ .../dmg.dv.test/source/dmg.dv.test.model.kps | 54 ++++++++++ .../dmg.dv.test/source/dmg.dv.test.model.ts | 14 +++ .../source/dmg.dv.test/source/readme.htm | 23 ++++ .../source/dmg.dv.test/source/welcome.htm | 27 +++++ .../source/dmg.dv.test/source/wordlist.tsv | 16 +++ .../issue2924/source/testvariable/HISTORY.md | 6 ++ .../issue2924/source/testvariable/LICENSE.md | 21 ++++ .../issue2924/source/testvariable/README.md | 29 +++++ .../source/testvariable/source/readme.htm | 23 ++++ .../source/testvariable.keyman-touch-layout | 57 ++++++++++ .../testvariable/source/testvariable.kmn | 18 ++++ .../testvariable/source/testvariable.kps | 67 ++++++++++++ .../testvariable/source/testvariable.kvks | 15 +++ .../source/testvariable/source/welcome.htm | 27 +++++ .../testvariable/testvariable.keyboard_info | 7 ++ .../source/testvariable/testvariable.kpj | 102 ++++++++++++++++++ web/testing/issue2924/testvariable.js | 1 + 27 files changed, 790 insertions(+) create mode 100644 web/testing/common/test.css create mode 100644 web/testing/issue2924/dmg.dv.test.model.js create mode 100644 web/testing/issue2924/header.js create mode 100644 web/testing/issue2924/index.html create mode 100644 web/testing/issue2924/source/dmg.dv.test/HISTORY.md create mode 100644 web/testing/issue2924/source/dmg.dv.test/LICENSE.md create mode 100644 web/testing/issue2924/source/dmg.dv.test/README.md create mode 100644 web/testing/issue2924/source/dmg.dv.test/dmg.dv.test.kpj create mode 100644 web/testing/issue2924/source/dmg.dv.test/dmg.dv.test.model_info create mode 100644 web/testing/issue2924/source/dmg.dv.test/source/dmg.dv.test.model.kps create mode 100644 web/testing/issue2924/source/dmg.dv.test/source/dmg.dv.test.model.ts create mode 100644 web/testing/issue2924/source/dmg.dv.test/source/readme.htm create mode 100644 web/testing/issue2924/source/dmg.dv.test/source/welcome.htm create mode 100644 web/testing/issue2924/source/dmg.dv.test/source/wordlist.tsv create mode 100644 web/testing/issue2924/source/testvariable/HISTORY.md create mode 100644 web/testing/issue2924/source/testvariable/LICENSE.md create mode 100644 web/testing/issue2924/source/testvariable/README.md create mode 100644 web/testing/issue2924/source/testvariable/source/readme.htm create mode 100644 web/testing/issue2924/source/testvariable/source/testvariable.keyman-touch-layout create mode 100644 web/testing/issue2924/source/testvariable/source/testvariable.kmn create mode 100644 web/testing/issue2924/source/testvariable/source/testvariable.kps create mode 100644 web/testing/issue2924/source/testvariable/source/testvariable.kvks create mode 100644 web/testing/issue2924/source/testvariable/source/welcome.htm create mode 100644 web/testing/issue2924/source/testvariable/testvariable.keyboard_info create mode 100644 web/testing/issue2924/source/testvariable/testvariable.kpj create mode 100644 web/testing/issue2924/testvariable.js diff --git a/web/testing/common/test.css b/web/testing/common/test.css new file mode 100644 index 0000000000..88eacbf7e4 --- /dev/null +++ b/web/testing/common/test.css @@ -0,0 +1,22 @@ +body { + font-family: Tahoma,helvetica; +} + +h3 { + font-size: 1em; + font-weight:normal; + color: darkred; + margin-bottom: 4px +} + +.test { + font-size: 1.5em; + width:80%; + min-height:30px; + border: 1px solid gray; +} + +#KeymanWebControl { + width:50%; + min-width:600px; +} diff --git a/web/testing/index.html b/web/testing/index.html index ff0ee91c11..c8821e4ade 100644 --- a/web/testing/index.html +++ b/web/testing/index.html @@ -59,6 +59,7 @@

Test page for context() and notany() interaction

Test SpacebarText APIs (#949)

Test inline OSK (#5665)

+

Test variable stores and predictive text (#2924)

Return to main index. diff --git a/web/testing/issue2924/dmg.dv.test.model.js b/web/testing/issue2924/dmg.dv.test.model.js new file mode 100644 index 0000000000..59d6e71cd5 --- /dev/null +++ b/web/testing/issue2924/dmg.dv.test.model.js @@ -0,0 +1,55 @@ +(function() { +'use strict'; +var definitions = { + defaults: { + version: "undefined", + applyCasing: function defaultApplyCasing(casing, text) { + switch (casing) { + case 'lower': + return text.toLowerCase(); + case 'upper': + return text.toUpperCase(); + case 'initial': + var headCode = text.charCodeAt(0); + // The length of the first code unit, as measured in code points. + var headUnitLength = 1; + // Is the first character a high surrogate, indicating possible use of UTF-16 + // surrogate pairs? Also, is the string long enough for there to BE a pair? + if (text.length > 1 && headCode >= 0xD800 && headCode <= 0xDBFF) { + // It's possible, so now we check for low surrogates. + var lowSurrogateCode = text.charCodeAt(1); + if (lowSurrogateCode >= 0xDC00 && lowSurrogateCode <= 0xDFFF) { + // We have a surrogate pair; this pair is the 'first' character. + headUnitLength++; + } + } + // Capitalizes the first code unit of the string, leaving the rest intact. + return text.substring(0, headUnitLength).toUpperCase() // head - uppercased + .concat(text.substring(headUnitLength)); // tail - lowercased + } +} + }, model: { + searchTermToKey: function defaultCasedSearchTermToKey(wordform, applyCasing) { + // While this is a bit WET, as the basic `defaultSearchTermToKey` exists and performs some of + // the same functions, repetition is the easiest way to allow the function to be safely compiled + // with ease by use of `.toString()`. + return Array.from(wordform + .normalize('NFKD') + // Remove any combining diacritics (if input is in NFKD) + .replace(/[\u0300-\u036F]/g, '')) // end of `Array.from` + .map(function (c) { return applyCasing('lower', c); }) + .join(''); +} + }, + applyCasing: function(caseToApply, text) { + return definitions.defaults.applyCasing(caseToApply, text); + }, + searchTermToKey: function(text) { + return definitions.model.searchTermToKey(text, definitions.applyCasing); + } +}; +LMLayerWorker.loadModel(new models.TrieModel({"totalWeight":126,"root":{"type":"internal","weight":100,"values":["t","h","w","e"],"children":{"t":{"type":"leaf","weight":100,"entries":[{"key":"the","weight":100,"content":"the"}]},"e":{"type":"leaf","weight":5,"entries":[{"key":"example","weight":5,"content":"example"}]},"h":{"type":"leaf","weight":10,"entries":[{"key":"hello","weight":10,"content":"hello"}]},"w":{"type":"internal","weight":8,"values":["o"],"children":{"o":{"type":"internal","weight":8,"values":["r"],"children":{"r":{"type":"internal","weight":8,"values":["l","d"],"children":{"l":{"type":"leaf","weight":8,"entries":[{"key":"world","weight":8,"content":"world"}]},"d":{"type":"leaf","weight":3,"entries":[{"key":"wordlist","weight":3,"content":"wordlist"}]}}}}}}}}}}, { + wordBreaker: wordBreakers['default'], + searchTermToKey: definitions.searchTermToKey, +})); +})(); \ No newline at end of file diff --git a/web/testing/issue2924/header.js b/web/testing/issue2924/header.js new file mode 100644 index 0000000000..64f7eb209c --- /dev/null +++ b/web/testing/issue2924/header.js @@ -0,0 +1,34 @@ +keyman.init({ + attachType: 'auto' +}); + +window.addEventListener('load', function() { + keyman.addKeyboards({ + id: 'testvariable', + name: 'testvariable', + languages: [{ + id:'en', name:'English' + }], + filename: './testvariable.js' + }); + + keyman.addKeyboards({ + id: 'us', + name: 'English US', + languages: [{ + id: 'en', + name: 'English' + }], + filename: '../us-1.0.js' + }); + + const pageRef = (window.location.protocol == 'file:') + ? window.location.href.substr(0, window.location.href.lastIndexOf('/')+1) + : window.location.href; + + keyman.modelManager.register({ + id: 'nrc.en.mtnt', + languages: ['en'], + path: pageRef + 'dmg.dv.test.model.js' + }); +}, false); diff --git a/web/testing/issue2924/index.html b/web/testing/issue2924/index.html new file mode 100644 index 0000000000..8f51a81270 --- /dev/null +++ b/web/testing/issue2924/index.html @@ -0,0 +1,25 @@ + + + + + + KeymanWeb Issue 2924 - Variable Stores and Predictive Text + + + + + + + +

KeymanWeb Test Page - Variable Stores and Predictive Text

+

Ref: issue #2924

+
+
+
+

Type in your language in this text area:

+ +
+
+

Return to testing home page

+ + diff --git a/web/testing/issue2924/source/dmg.dv.test/HISTORY.md b/web/testing/issue2924/source/dmg.dv.test/HISTORY.md new file mode 100644 index 0000000000..1be9a3fd18 --- /dev/null +++ b/web/testing/issue2924/source/dmg.dv.test/HISTORY.md @@ -0,0 +1,6 @@ +test Change History +==================== + +1.0 (2020-05-27) +---------------- +* Created by dmg diff --git a/web/testing/issue2924/source/dmg.dv.test/LICENSE.md b/web/testing/issue2924/source/dmg.dv.test/LICENSE.md new file mode 100644 index 0000000000..ebf6171968 --- /dev/null +++ b/web/testing/issue2924/source/dmg.dv.test/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +© 2020 dmg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/web/testing/issue2924/source/dmg.dv.test/README.md b/web/testing/issue2924/source/dmg.dv.test/README.md new file mode 100644 index 0000000000..5aa6013c38 --- /dev/null +++ b/web/testing/issue2924/source/dmg.dv.test/README.md @@ -0,0 +1,29 @@ +test lexical model +=================== + +© 2020 dmg + +Version 1.0 + +Description +----------- + +test generated from template + +Links +----- + +Supported Platforms +------------------- + * Windows + * macOS + * Linux + * Web + * iPhone + * iPad + * Android phone + * Android tablet + * Mobile devices + * Desktop devices + * Tablet devices + diff --git a/web/testing/issue2924/source/dmg.dv.test/dmg.dv.test.kpj b/web/testing/issue2924/source/dmg.dv.test/dmg.dv.test.kpj new file mode 100644 index 0000000000..e4d5c9c567 --- /dev/null +++ b/web/testing/issue2924/source/dmg.dv.test/dmg.dv.test.kpj @@ -0,0 +1,83 @@ + + + + $PROJECTPATH\build + True + True + True + lexicalmodel + + + + id_6d8c9bbe8c11c08cca045e5e87c342c6 + dmg.dv.test.model.ts + source\dmg.dv.test.model.ts + 1.0 + .ts + + + id_521f7de068a80527c98d0c04c05faa94 + dmg.dv.test.model.kps + source\dmg.dv.test.model.kps + 1.0 + .kps +
+ test + © 2020 dmg + 1.0 +
+
+ + id_ede98e4633e239f933cbfd1f4e1b766c + HISTORY.md + HISTORY.md + + .md + + + id_53e892b8b41cc4caece1cfd5ef21d6e7 + LICENSE.md + LICENSE.md + + .md + + + id_0730bb7c2e8f9ea2438b52e419dd86c9 + README.md + README.md + + .md + + + id_4b12eec2a4d0bfc7b5441a4a59691eab + dmg.dv.test.model_info + dmg.dv.test.model_info + + .model_info + + + id_6ee5fa96871fb96ecebf2cbe9ec7425b + dmg.dv.test.model.js + source\..\build\dmg.dv.test.model.js + + .js + id_521f7de068a80527c98d0c04c05faa94 + + + id_356e5d149c1e539356d72698c1e401a6 + welcome.htm + source\welcome.htm + + .htm + id_521f7de068a80527c98d0c04c05faa94 + + + id_8da344c4cea6f467013357fe099006f5 + readme.htm + source\readme.htm + + .htm + id_521f7de068a80527c98d0c04c05faa94 + +
+
diff --git a/web/testing/issue2924/source/dmg.dv.test/dmg.dv.test.model_info b/web/testing/issue2924/source/dmg.dv.test/dmg.dv.test.model_info new file mode 100644 index 0000000000..03399a9f8e --- /dev/null +++ b/web/testing/issue2924/source/dmg.dv.test/dmg.dv.test.model_info @@ -0,0 +1,7 @@ +{ + "license": "mit", + "languages": [ + "dv" + ], + "description": "test generated from template" +} diff --git a/web/testing/issue2924/source/dmg.dv.test/source/dmg.dv.test.model.kps b/web/testing/issue2924/source/dmg.dv.test/source/dmg.dv.test.model.kps new file mode 100644 index 0000000000..1aad80f3ff --- /dev/null +++ b/web/testing/issue2924/source/dmg.dv.test/source/dmg.dv.test.model.kps @@ -0,0 +1,54 @@ + + + + 13.0.108.0 + 12.0 + + + + readme.htm + + + + + + + + + test + © 2020 dmg + dmg + 1.0 + + + + ..\build\dmg.dv.test.model.js + + 0 + .js + + + welcome.htm + + 0 + .htm + + + readme.htm + + 0 + .htm + + + + + + test + dmg.dv.test + + Dhivehi + + + + + diff --git a/web/testing/issue2924/source/dmg.dv.test/source/dmg.dv.test.model.ts b/web/testing/issue2924/source/dmg.dv.test/source/dmg.dv.test.model.ts new file mode 100644 index 0000000000..69c3e6acbd --- /dev/null +++ b/web/testing/issue2924/source/dmg.dv.test/source/dmg.dv.test.model.ts @@ -0,0 +1,14 @@ +/* + test 1.0 generated from template. + + This is a minimal lexical model source that uses a tab delimited wordlist. + See documentation online at https://help.keyman.com/developer/ for + additional parameters. +*/ + +const source: LexicalModelSource = { + format: 'trie-1.0', + wordBreaker: 'default', + sources: ['wordlist.tsv'], +}; +export default source; \ No newline at end of file diff --git a/web/testing/issue2924/source/dmg.dv.test/source/readme.htm b/web/testing/issue2924/source/dmg.dv.test/source/readme.htm new file mode 100644 index 0000000000..ded2822a56 --- /dev/null +++ b/web/testing/issue2924/source/dmg.dv.test/source/readme.htm @@ -0,0 +1,23 @@ + + + + + test + + + + +

test

+ +

+ test 1.0 generated from template. +

+ +

© 2020 dmg

+ + + diff --git a/web/testing/issue2924/source/dmg.dv.test/source/welcome.htm b/web/testing/issue2924/source/dmg.dv.test/source/welcome.htm new file mode 100644 index 0000000000..592fb47d7e --- /dev/null +++ b/web/testing/issue2924/source/dmg.dv.test/source/welcome.htm @@ -0,0 +1,27 @@ + + + + + Start Using test + + + + +

Start Using test

+ +

+ test 1.0 generated from template. +

+ +

Wordlist Model Documentation

+ + + +

© 2020 dmg

+ + + \ No newline at end of file diff --git a/web/testing/issue2924/source/dmg.dv.test/source/wordlist.tsv b/web/testing/issue2924/source/dmg.dv.test/source/wordlist.tsv new file mode 100644 index 0000000000..73d581f275 --- /dev/null +++ b/web/testing/issue2924/source/dmg.dv.test/source/wordlist.tsv @@ -0,0 +1,16 @@ +# +# test 1.0 generated from template. +# +# This is an example tab-separated wordlist file that can be edited in a spreadsheet +# program or regenerated from a wordlist tool. See lexical model documentation at +# https://help.keyman.com/developer/ for tools. +# +# Columns +# ======= +# WORD FREQUENCY (Optional)NOTES +# +the 100 +example 5 +hello 10 +world 8 +wordlist 3 \ No newline at end of file diff --git a/web/testing/issue2924/source/testvariable/HISTORY.md b/web/testing/issue2924/source/testvariable/HISTORY.md new file mode 100644 index 0000000000..c9cc218cd7 --- /dev/null +++ b/web/testing/issue2924/source/testvariable/HISTORY.md @@ -0,0 +1,6 @@ +testvariable Change History +==================== + +1.0 (2020-05-26) +---------------- +* Created by diff --git a/web/testing/issue2924/source/testvariable/LICENSE.md b/web/testing/issue2924/source/testvariable/LICENSE.md new file mode 100644 index 0000000000..714cb32594 --- /dev/null +++ b/web/testing/issue2924/source/testvariable/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +© + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/web/testing/issue2924/source/testvariable/README.md b/web/testing/issue2924/source/testvariable/README.md new file mode 100644 index 0000000000..ef79c3b972 --- /dev/null +++ b/web/testing/issue2924/source/testvariable/README.md @@ -0,0 +1,29 @@ +testvariable keyboard +============== + +© + +Version 1.0 + +Description +----------- + +testvariable generated from template + +Links +----- + +Supported Platforms +------------------- + * Windows + * macOS + * Linux + * Web + * iPhone + * iPad + * Android phone + * Android tablet + * Mobile devices + * Desktop devices + * Tablet devices + diff --git a/web/testing/issue2924/source/testvariable/source/readme.htm b/web/testing/issue2924/source/testvariable/source/readme.htm new file mode 100644 index 0000000000..716786bf70 --- /dev/null +++ b/web/testing/issue2924/source/testvariable/source/readme.htm @@ -0,0 +1,23 @@ + + + + + testvariable + + + + +

testvariable

+ +

+ testvariable 1.0 generated from template. +

+ +

©

+ + + diff --git a/web/testing/issue2924/source/testvariable/source/testvariable.keyman-touch-layout b/web/testing/issue2924/source/testvariable/source/testvariable.keyman-touch-layout new file mode 100644 index 0000000000..2bc510c34c --- /dev/null +++ b/web/testing/issue2924/source/testvariable/source/testvariable.keyman-touch-layout @@ -0,0 +1,57 @@ +{ + "tablet": { + "displayUnderlying": false, + "layer": [ + { + "id": "default", + "row": [ + { + "id": 1, + "key": [ + { + "id": "K_S", + "text": "Set" + }, + { + "id": "K_C", + "text": "Clear" + }, + { + "id": "K_R", + "text": "Reveal" + }, + { + "id": "K_BKSP", + "text": "*BkSp*", + "width": "100", + "sp": "1" + } + ] + }, + { + "id": 2, + "key": [ + { + "id": "K_LOPT", + "text": "*Menu*", + "width": "140", + "sp": "1" + }, + { + "id": "K_SPACE", + "text": "", + "width": "" + }, + { + "id": "K_ENTER", + "text": "*Enter*", + "width": "145", + "sp": "1" + } + ] + } + ] + } + ] + } +} \ No newline at end of file diff --git a/web/testing/issue2924/source/testvariable/source/testvariable.kmn b/web/testing/issue2924/source/testvariable/source/testvariable.kmn new file mode 100644 index 0000000000..3e6b8fe234 --- /dev/null +++ b/web/testing/issue2924/source/testvariable/source/testvariable.kmn @@ -0,0 +1,18 @@ +store(&VERSION) '10.0' +store(&NAME) 'testvariable' +store(©RIGHT) '©' +store(&KEYBOARDVERSION) '1.0' +store(&TARGETS) 'any' +store(&LAYOUTFILE) 'testvariable.keyman-touch-layout' + +store (myVar) "1" +store(&VISUALKEYBOARD) 'testvariable.kvks' + +begin Unicode > use(main) + +group(main) using keys + ++ [K_S] > "(+)" set(myVar="1") c S will Set the variable, and output (+) ++ [K_C] > "(-)" set(myVar="0") c C will Clear the variable, and output (-) +if (myVar = "1") + [K_R] > "+" c R will Reveal the variable's state with + or - +if (myVar!= "1") + [K_R] > "-" diff --git a/web/testing/issue2924/source/testvariable/source/testvariable.kps b/web/testing/issue2924/source/testvariable/source/testvariable.kps new file mode 100644 index 0000000000..72de7413e6 --- /dev/null +++ b/web/testing/issue2924/source/testvariable/source/testvariable.kps @@ -0,0 +1,67 @@ + + + + 13.0.108.0 + 7.0 + + + + readme.htm + + + + + + + + + + testvariable + © + + + + + + ..\build\testvariable.kmx + + 0 + .kmx + + + ..\build\testvariable.js + + 0 + .js + + + ..\build\testvariable.kvk + + 0 + .kvk + + + welcome.htm + + 0 + .htm + + + readme.htm + + 0 + .htm + + + + + testvariable + testvariable + 1.0 + + Dhivehi + + + + + diff --git a/web/testing/issue2924/source/testvariable/source/testvariable.kvks b/web/testing/issue2924/source/testvariable/source/testvariable.kvks new file mode 100644 index 0000000000..3a8b604523 --- /dev/null +++ b/web/testing/issue2924/source/testvariable/source/testvariable.kvks @@ -0,0 +1,15 @@ + + +
+ 10.0 + testvariable + +
+ + + Clear + Reveal + Set + + +
diff --git a/web/testing/issue2924/source/testvariable/source/welcome.htm b/web/testing/issue2924/source/testvariable/source/welcome.htm new file mode 100644 index 0000000000..4fc9b434de --- /dev/null +++ b/web/testing/issue2924/source/testvariable/source/welcome.htm @@ -0,0 +1,27 @@ + + + + + Start Using testvariable + + + + +

Start Using testvariable

+ +

+ testvariable 1.0 generated from template. +

+ +

Keyboard Layout

+ + + +

©

+ + + \ No newline at end of file diff --git a/web/testing/issue2924/source/testvariable/testvariable.keyboard_info b/web/testing/issue2924/source/testvariable/testvariable.keyboard_info new file mode 100644 index 0000000000..5e54349207 --- /dev/null +++ b/web/testing/issue2924/source/testvariable/testvariable.keyboard_info @@ -0,0 +1,7 @@ +{ + "license": "mit", + "languages": [ + "en" + ], + "description": "testvariable generated from template" +} diff --git a/web/testing/issue2924/source/testvariable/testvariable.kpj b/web/testing/issue2924/source/testvariable/testvariable.kpj new file mode 100644 index 0000000000..a138eda11b --- /dev/null +++ b/web/testing/issue2924/source/testvariable/testvariable.kpj @@ -0,0 +1,102 @@ + + + + $PROJECTPATH\build + True + True + True + keyboard + + + + id_a8c52d62d9f15eb62fde81d1a591d3b7 + testvariable.kmn + source\testvariable.kmn + 1.0 + .kmn +
+ testvariable + © +
+
+ + id_25e4c084428d0ee657e7a56c3ad5dc3c + testvariable.kps + source\testvariable.kps + + .kps +
+ testvariable + © +
+
+ + id_ede98e4633e239f933cbfd1f4e1b766c + HISTORY.md + HISTORY.md + + .md + + + id_53e892b8b41cc4caece1cfd5ef21d6e7 + LICENSE.md + LICENSE.md + + .md + + + id_0730bb7c2e8f9ea2438b52e419dd86c9 + README.md + README.md + + .md + + + id_efaa79249320cda8d8e2886ddbf0475e + testvariable.keyboard_info + testvariable.keyboard_info + + .keyboard_info + + + id_0c280146c90477c06029a32b48581f90 + testvariable.kmx + source\..\build\testvariable.kmx + + .kmx + id_25e4c084428d0ee657e7a56c3ad5dc3c + + + id_694dbba5eb4cd5c4f122133b889f7eb4 + testvariable.js + source\..\build\testvariable.js + + .js + id_25e4c084428d0ee657e7a56c3ad5dc3c + + + id_6c3d7ac2bff7cba3383a3d6ca5e2a2ef + testvariable.kvk + source\..\build\testvariable.kvk + + .kvk + id_25e4c084428d0ee657e7a56c3ad5dc3c + + + id_356e5d149c1e539356d72698c1e401a6 + welcome.htm + source\welcome.htm + + .htm + id_25e4c084428d0ee657e7a56c3ad5dc3c + + + id_8da344c4cea6f467013357fe099006f5 + readme.htm + source\readme.htm + + .htm + id_25e4c084428d0ee657e7a56c3ad5dc3c + +
+
diff --git a/web/testing/issue2924/testvariable.js b/web/testing/issue2924/testvariable.js new file mode 100644 index 0000000000..cf442a5e64 --- /dev/null +++ b/web/testing/issue2924/testvariable.js @@ -0,0 +1 @@ +if(typeof keyman === 'undefined') {console.log('Keyboard requires KeymanWeb 10.0 or later');if(typeof tavultesoft !== 'undefined') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later");} else {KeymanWeb.KR(new Keyboard_testvariable());}function Keyboard_testvariable(){this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9;this.KI="Keyboard_testvariable";this.KN="testvariable";this.KMINVER="10.0";this.KV={F:' 1em "Arial"',K102:0};this.KV.KLS={"default": ["","","","","","","","","","","","","","","","","","","","Reveal","","","","","","","","","","","","","","Set","","","","","","","","","","","","","","","","","","Clear","","","","","","","","","","","","",""]};this.KV.BK=(function(x){var e=Array.apply(null,Array(65)).map(String.prototype.valueOf,""),r=[],v,i,m=['default','shift','ctrl','shift-ctrl','alt','shift-alt','ctrl-alt','shift-ctrl-alt'];for(i=m.length-1;i>=0;i--)if((v=x[m[i]])||r.length)r=(v?v:e).slice().concat(r);return r})(this.KV.KLS);this.KDU=0;this.KH='';this.KM=0;this.KBVER="1.0";this.KMBM=0x0000;this.KVKL={"tablet":{"displayUnderlying":false,"layer":[{"id":"default","row":[{"id":"1","key":[{"id":"K_S","text":"Set"},{"id":"K_C","text":"Clear"},{"id":"K_R","text":"Reveal"},{"width":"100","id":"K_BKSP","sp":"1","text":"*BkSp*"}]},{"id":"2","key":[{"width":"140","id":"K_LOPT","sp":"1","text":"*Menu*"},{"id":"K_SPACE"},{"width":"145","id":"K_ENTER","sp":"1","text":"*Enter*"}]}]}]}};this.s9=KeymanWeb.KLOAD(this.KI,"myVar","1");this.s13="1";this.s14="0";this.s15="1";this.s16="1";this.KVER="15.0.105.0";this.KSS=['s9'];this.gs=function(t,e) {return this.g0(t,e);};this.g0=function(t,e) {var k=KeymanWeb,r=0,m=0;if(k.KKM(e,16384,67)) {if(1){r=m=1;k.KDC(0,t);k.KO(-1,t,"(-)");this.s9=this.s14;}}else if(k.KKM(e,16384,82)) {if(this.s9===this.s15){r=m=1;k.KDC(0,t);k.KO(-1,t,"+");}else if(this.s9!==this.s16){r=m=1;k.KDC(0,t);k.KO(-1,t,"-");}}else if(k.KKM(e,16384,83)) {if(1){r=m=1;k.KDC(0,t);k.KO(-1,t,"(+)");this.s9=this.s13;}}return r;};} \ No newline at end of file From 2f280052ec626e296bfe0c55cc2d0f6a9e6a0aab Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 27 Sep 2021 10:25:16 +1000 Subject: [PATCH 46/63] chore(web): cleanup comment --- common/core/web/keyboard-processor/src/text/kbdInterface.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/core/web/keyboard-processor/src/text/kbdInterface.ts b/common/core/web/keyboard-processor/src/text/kbdInterface.ts index e80229fe7f..fb729c0468 100644 --- a/common/core/web/keyboard-processor/src/text/kbdInterface.ts +++ b/common/core/web/keyboard-processor/src/text/kbdInterface.ts @@ -1016,8 +1016,8 @@ namespace com.keyman.text { * Has no effect on keyboards compiled with 14.0 or earlier; system store * names are not exposed unless compiled with Developer 15.0 or later. * - * @param VariableStoreDictionary A dictionary of stores which should be - * found in the keyboard + * @param stores A dictionary of stores which should be found in the + * keyboard */ applyVariableStores(stores: com.keyman.keyboards.VariableStoreDictionary): void { this.activeKeyboard.variableStores = stores; From 670f20a5f7ae18a0e1a869e16fb6f5e84e18eb5f Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 27 Sep 2021 10:32:53 +1000 Subject: [PATCH 47/63] chore(web): add baseline old version keyboard Adds oldtestvariable.js to demonstrate old, broken behaviour with predictive text and variable stores. --- web/testing/issue2924/header.js | 9 +++++++++ web/testing/issue2924/oldtestvariable.js | 1 + web/testing/issue2924/testvariable.js | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 web/testing/issue2924/oldtestvariable.js diff --git a/web/testing/issue2924/header.js b/web/testing/issue2924/header.js index 64f7eb209c..8e3ecb745a 100644 --- a/web/testing/issue2924/header.js +++ b/web/testing/issue2924/header.js @@ -12,6 +12,15 @@ window.addEventListener('load', function() { filename: './testvariable.js' }); + keyman.addKeyboards({ + id: 'oldtestvariable', + name: 'oldtestvariable', + languages: [{ + id:'en', name:'English' + }], + filename: './oldtestvariable.js' + }); + keyman.addKeyboards({ id: 'us', name: 'English US', diff --git a/web/testing/issue2924/oldtestvariable.js b/web/testing/issue2924/oldtestvariable.js new file mode 100644 index 0000000000..2abeed428d --- /dev/null +++ b/web/testing/issue2924/oldtestvariable.js @@ -0,0 +1 @@ +if(typeof keyman === 'undefined') {console.log('Keyboard requires KeymanWeb 10.0 or later');if(typeof tavultesoft !== 'undefined') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later");} else {KeymanWeb.KR(new Keyboard_oldtestvariable());}function Keyboard_oldtestvariable(){this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9;this.KI="Keyboard_oldtestvariable";this.KN="oldtestvariable";this.KMINVER="10.0";this.KV={F:' 1em "Arial"',K102:0};this.KV.KLS={"default": ["","","","","","","","","","","","","","","","","","","","Reveal","","","","","","","","","","","","","","Set","","","","","","","","","","","","","","","","","","Clear","","","","","","","","","","","","",""]};this.KV.BK=(function(x){var e=Array.apply(null,Array(65)).map(String.prototype.valueOf,""),r=[],v,i,m=['default','shift','ctrl','shift-ctrl','alt','shift-alt','ctrl-alt','shift-ctrl-alt'];for(i=m.length-1;i>=0;i--)if((v=x[m[i]])||r.length)r=(v?v:e).slice().concat(r);return r})(this.KV.KLS);this.KDU=0;this.KH='';this.KM=0;this.KBVER="1.0";this.KMBM=0x0000;this.KVKL={"tablet":{"displayUnderlying":false,"layer":[{"id":"default","row":[{"id":"1","key":[{"id":"K_S","text":"Set"},{"id":"K_C","text":"Clear"},{"id":"K_R","text":"Reveal"},{"width":"100","id":"K_BKSP","sp":"1","text":"*BkSp*"}]},{"id":"2","key":[{"width":"140","id":"K_LOPT","sp":"1","text":"*Menu*"},{"id":"K_SPACE"},{"width":"145","id":"K_ENTER","sp":"1","text":"*Enter*"}]}]}]}};this.s9=KeymanWeb.KLOAD(this.KI,"myVar","1");this.s13="1";this.s14="0";this.s15="1";this.s16="1";this.KVER="15.0.105.0";this.gs=function(t,e) {return this.g0(t,e);};this.g0=function(t,e) {var k=KeymanWeb,r=0,m=0;if(k.KKM(e,16384,67)) {if(1){r=m=1;k.KDC(0,t);k.KO(-1,t,"(-)");this.s9=this.s14;}}else if(k.KKM(e,16384,82)) {if(this.s9===this.s15){r=m=1;k.KDC(0,t);k.KO(-1,t,"+");}else if(this.s9!==this.s16){r=m=1;k.KDC(0,t);k.KO(-1,t,"-");}}else if(k.KKM(e,16384,83)) {if(1){r=m=1;k.KDC(0,t);k.KO(-1,t,"(+)");this.s9=this.s13;}}return r;};} \ No newline at end of file diff --git a/web/testing/issue2924/testvariable.js b/web/testing/issue2924/testvariable.js index cf442a5e64..fd9b6410ec 100644 --- a/web/testing/issue2924/testvariable.js +++ b/web/testing/issue2924/testvariable.js @@ -1 +1 @@ -if(typeof keyman === 'undefined') {console.log('Keyboard requires KeymanWeb 10.0 or later');if(typeof tavultesoft !== 'undefined') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later");} else {KeymanWeb.KR(new Keyboard_testvariable());}function Keyboard_testvariable(){this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9;this.KI="Keyboard_testvariable";this.KN="testvariable";this.KMINVER="10.0";this.KV={F:' 1em "Arial"',K102:0};this.KV.KLS={"default": ["","","","","","","","","","","","","","","","","","","","Reveal","","","","","","","","","","","","","","Set","","","","","","","","","","","","","","","","","","Clear","","","","","","","","","","","","",""]};this.KV.BK=(function(x){var e=Array.apply(null,Array(65)).map(String.prototype.valueOf,""),r=[],v,i,m=['default','shift','ctrl','shift-ctrl','alt','shift-alt','ctrl-alt','shift-ctrl-alt'];for(i=m.length-1;i>=0;i--)if((v=x[m[i]])||r.length)r=(v?v:e).slice().concat(r);return r})(this.KV.KLS);this.KDU=0;this.KH='';this.KM=0;this.KBVER="1.0";this.KMBM=0x0000;this.KVKL={"tablet":{"displayUnderlying":false,"layer":[{"id":"default","row":[{"id":"1","key":[{"id":"K_S","text":"Set"},{"id":"K_C","text":"Clear"},{"id":"K_R","text":"Reveal"},{"width":"100","id":"K_BKSP","sp":"1","text":"*BkSp*"}]},{"id":"2","key":[{"width":"140","id":"K_LOPT","sp":"1","text":"*Menu*"},{"id":"K_SPACE"},{"width":"145","id":"K_ENTER","sp":"1","text":"*Enter*"}]}]}]}};this.s9=KeymanWeb.KLOAD(this.KI,"myVar","1");this.s13="1";this.s14="0";this.s15="1";this.s16="1";this.KVER="15.0.105.0";this.KSS=['s9'];this.gs=function(t,e) {return this.g0(t,e);};this.g0=function(t,e) {var k=KeymanWeb,r=0,m=0;if(k.KKM(e,16384,67)) {if(1){r=m=1;k.KDC(0,t);k.KO(-1,t,"(-)");this.s9=this.s14;}}else if(k.KKM(e,16384,82)) {if(this.s9===this.s15){r=m=1;k.KDC(0,t);k.KO(-1,t,"+");}else if(this.s9!==this.s16){r=m=1;k.KDC(0,t);k.KO(-1,t,"-");}}else if(k.KKM(e,16384,83)) {if(1){r=m=1;k.KDC(0,t);k.KO(-1,t,"(+)");this.s9=this.s13;}}return r;};} \ No newline at end of file +if(typeof keyman === 'undefined') {console.log('Keyboard requires KeymanWeb 10.0 or later');if(typeof tavultesoft !== 'undefined') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later");} else {KeymanWeb.KR(new Keyboard_testvariable());}function Keyboard_testvariable(){this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9;this.KI="Keyboard_testvariable";this.KN="testvariable";this.KMINVER="10.0";this.KV={F:' 1em "Arial"',K102:0};this.KV.KLS={"default": ["","","","","","","","","","","","","","","","","","","","Reveal","","","","","","","","","","","","","","Set","","","","","","","","","","","","","","","","","","Clear","","","","","","","","","","","","",""]};this.KV.BK=(function(x){var e=Array.apply(null,Array(65)).map(String.prototype.valueOf,""),r=[],v,i,m=['default','shift','ctrl','shift-ctrl','alt','shift-alt','ctrl-alt','shift-ctrl-alt'];for(i=m.length-1;i>=0;i--)if((v=x[m[i]])||r.length)r=(v?v:e).slice().concat(r);return r})(this.KV.KLS);this.KDU=0;this.KH='';this.KM=0;this.KBVER="1.0";this.KMBM=0x0000;this.KVKL={"tablet":{"displayUnderlying":false,"layer":[{"id":"default","row":[{"id":"1","key":[{"id":"K_S","text":"Set"},{"id":"K_C","text":"Clear"},{"id":"K_R","text":"Reveal"},{"width":"100","id":"K_BKSP","sp":"1","text":"*BkSp*"}]},{"id":"2","key":[{"width":"140","id":"K_LOPT","sp":"1","text":"*Menu*"},{"id":"K_SPACE"},{"width":"145","id":"K_ENTER","sp":"1","text":"*Enter*"}]}]}]}};this.s9=KeymanWeb.KLOAD(this.KI,"myVar","1");this.s13="1";this.s14="0";this.s15="1";this.s16="1";this.KVER="15.0.105.0";this.KVS=['s9'];this.gs=function(t,e) {return this.g0(t,e);};this.g0=function(t,e) {var k=KeymanWeb,r=0,m=0;if(k.KKM(e,16384,67)) {if(1){r=m=1;k.KDC(0,t);k.KO(-1,t,"(-)");this.s9=this.s14;}}else if(k.KKM(e,16384,82)) {if(this.s9===this.s15){r=m=1;k.KDC(0,t);k.KO(-1,t,"+");}else if(this.s9!==this.s16){r=m=1;k.KDC(0,t);k.KO(-1,t,"-");}}else if(k.KKM(e,16384,83)) {if(1){r=m=1;k.KDC(0,t);k.KO(-1,t,"(+)");this.s9=this.s13;}}return r;};} \ No newline at end of file From 1fe0cc050afecc28cf6f699d0fd3a1e2174eab1b Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 27 Sep 2021 10:43:18 +1000 Subject: [PATCH 48/63] chore(web): use debug versions of keyboard --- web/testing/issue2924/oldtestvariable.js | 137 ++++++++++++++++++++++- web/testing/issue2924/testvariable.js | 137 ++++++++++++++++++++++- 2 files changed, 272 insertions(+), 2 deletions(-) diff --git a/web/testing/issue2924/oldtestvariable.js b/web/testing/issue2924/oldtestvariable.js index 2abeed428d..678f522626 100644 --- a/web/testing/issue2924/oldtestvariable.js +++ b/web/testing/issue2924/oldtestvariable.js @@ -1 +1,136 @@ -if(typeof keyman === 'undefined') {console.log('Keyboard requires KeymanWeb 10.0 or later');if(typeof tavultesoft !== 'undefined') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later");} else {KeymanWeb.KR(new Keyboard_oldtestvariable());}function Keyboard_oldtestvariable(){this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9;this.KI="Keyboard_oldtestvariable";this.KN="oldtestvariable";this.KMINVER="10.0";this.KV={F:' 1em "Arial"',K102:0};this.KV.KLS={"default": ["","","","","","","","","","","","","","","","","","","","Reveal","","","","","","","","","","","","","","Set","","","","","","","","","","","","","","","","","","Clear","","","","","","","","","","","","",""]};this.KV.BK=(function(x){var e=Array.apply(null,Array(65)).map(String.prototype.valueOf,""),r=[],v,i,m=['default','shift','ctrl','shift-ctrl','alt','shift-alt','ctrl-alt','shift-ctrl-alt'];for(i=m.length-1;i>=0;i--)if((v=x[m[i]])||r.length)r=(v?v:e).slice().concat(r);return r})(this.KV.KLS);this.KDU=0;this.KH='';this.KM=0;this.KBVER="1.0";this.KMBM=0x0000;this.KVKL={"tablet":{"displayUnderlying":false,"layer":[{"id":"default","row":[{"id":"1","key":[{"id":"K_S","text":"Set"},{"id":"K_C","text":"Clear"},{"id":"K_R","text":"Reveal"},{"width":"100","id":"K_BKSP","sp":"1","text":"*BkSp*"}]},{"id":"2","key":[{"width":"140","id":"K_LOPT","sp":"1","text":"*Menu*"},{"id":"K_SPACE"},{"width":"145","id":"K_ENTER","sp":"1","text":"*Enter*"}]}]}]}};this.s9=KeymanWeb.KLOAD(this.KI,"myVar","1");this.s13="1";this.s14="0";this.s15="1";this.s16="1";this.KVER="15.0.105.0";this.gs=function(t,e) {return this.g0(t,e);};this.g0=function(t,e) {var k=KeymanWeb,r=0,m=0;if(k.KKM(e,16384,67)) {if(1){r=m=1;k.KDC(0,t);k.KO(-1,t,"(-)");this.s9=this.s14;}}else if(k.KKM(e,16384,82)) {if(this.s9===this.s15){r=m=1;k.KDC(0,t);k.KO(-1,t,"+");}else if(this.s9!==this.s16){r=m=1;k.KDC(0,t);k.KO(-1,t,"-");}}else if(k.KKM(e,16384,83)) {if(1){r=m=1;k.KDC(0,t);k.KO(-1,t,"(+)");this.s9=this.s13;}}return r;};} \ No newline at end of file +if(typeof keyman === 'undefined') { + console.log('Keyboard requires KeymanWeb 10.0 or later'); + if(typeof tavultesoft !== 'undefined') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later"); +} else { +KeymanWeb.KR(new Keyboard_testvariable()); +} +function Keyboard_testvariable() +{ + var modCodes = keyman.osk.modifierCodes; + var keyCodes = keyman.osk.keyCodes; + + this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9; + this.KI="Keyboard_testvariable"; + this.KN="testvariable"; + this.KMINVER="10.0"; + this.KV={F:' 1em "Arial"',K102:0}; + this.KV.KLS={ + "default": ["","","","","","","","","","","","","","","","","","","","Reveal","","","","","","","","","","","","","","Set","","","","","","","","","","","","","","","","","","Clear","","","","","","","","","","","","",""] + }; + this.KV.BK=(function(x){ + var + empty=Array.apply(null, Array(65)).map(String.prototype.valueOf,""), + result=[], v, i, + modifiers=['default','shift','ctrl','shift-ctrl','alt','shift-alt','ctrl-alt','shift-ctrl-alt']; + for(i=modifiers.length-1;i>=0;i--) { + v = x[modifiers[i]]; + if(v || result.length > 0) { + result=(v ? v : empty).slice().concat(result); + } + } + return result; + })(this.KV.KLS); + this.KDU=0; + this.KH=''; + this.KM=0; + this.KBVER="1.0"; + this.KMBM=0 /* 0x0000 */; + this.KVKL={ + "tablet": { + "displayUnderlying": false, + "layer": [ + { + "id": "default", + "row": [ + { + "id": "1", + "key": [ + { + "id": "K_S", + "text": "Set" + }, + { + "id": "K_C", + "text": "Clear" + }, + { + "id": "K_R", + "text": "Reveal" + }, + { + "width": "100", + "id": "K_BKSP", + "sp": "1", + "text": "*BkSp*" + } + ] + }, + { + "id": "2", + "key": [ + { + "width": "140", + "id": "K_LOPT", + "sp": "1", + "text": "*Menu*" + }, + { + "id": "K_SPACE" + }, + { + "width": "145", + "id": "K_ENTER", + "sp": "1", + "text": "*Enter*" + } + ] + } + ] + } + ] + } +} +; + this.s_myVar_9=KeymanWeb.KLOAD(this.KI,"myVar","1"); + this.s13="1"; + this.s14="0"; + this.s15="1"; + this.s16="1"; + this.KVER="15.0.105.0"; + //this.KVS=['s_myVar_9']; <-- manually stubbed out to demonstrate old behaviour + this.gs=function(t,e) { + return this.g_main_0(t,e); + }; + this.g_main_0=function(t,e) { + var k=KeymanWeb,r=0,m=0; + if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_C /* 0x43 */)) { + if(1){ + r=m=1; // Line 16 + k.KDC(0,t); + k.KO(-1,t,"(-)"); + this.s_myVar_9=this.s14; + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_R /* 0x52 */)) { + if(this.s_myVar_9===this.s15){ + r=m=1; // Line 17 + k.KDC(0,t); + k.KO(-1,t,"+"); + } + else if(this.s_myVar_9!==this.s16){ + r=m=1; // Line 18 + k.KDC(0,t); + k.KO(-1,t,"-"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_S /* 0x53 */)) { + if(1){ + r=m=1; // Line 15 + k.KDC(0,t); + k.KO(-1,t,"(+)"); + this.s_myVar_9=this.s13; + } + } + return r; + }; +} diff --git a/web/testing/issue2924/testvariable.js b/web/testing/issue2924/testvariable.js index fd9b6410ec..0958c59f70 100644 --- a/web/testing/issue2924/testvariable.js +++ b/web/testing/issue2924/testvariable.js @@ -1 +1,136 @@ -if(typeof keyman === 'undefined') {console.log('Keyboard requires KeymanWeb 10.0 or later');if(typeof tavultesoft !== 'undefined') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later");} else {KeymanWeb.KR(new Keyboard_testvariable());}function Keyboard_testvariable(){this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9;this.KI="Keyboard_testvariable";this.KN="testvariable";this.KMINVER="10.0";this.KV={F:' 1em "Arial"',K102:0};this.KV.KLS={"default": ["","","","","","","","","","","","","","","","","","","","Reveal","","","","","","","","","","","","","","Set","","","","","","","","","","","","","","","","","","Clear","","","","","","","","","","","","",""]};this.KV.BK=(function(x){var e=Array.apply(null,Array(65)).map(String.prototype.valueOf,""),r=[],v,i,m=['default','shift','ctrl','shift-ctrl','alt','shift-alt','ctrl-alt','shift-ctrl-alt'];for(i=m.length-1;i>=0;i--)if((v=x[m[i]])||r.length)r=(v?v:e).slice().concat(r);return r})(this.KV.KLS);this.KDU=0;this.KH='';this.KM=0;this.KBVER="1.0";this.KMBM=0x0000;this.KVKL={"tablet":{"displayUnderlying":false,"layer":[{"id":"default","row":[{"id":"1","key":[{"id":"K_S","text":"Set"},{"id":"K_C","text":"Clear"},{"id":"K_R","text":"Reveal"},{"width":"100","id":"K_BKSP","sp":"1","text":"*BkSp*"}]},{"id":"2","key":[{"width":"140","id":"K_LOPT","sp":"1","text":"*Menu*"},{"id":"K_SPACE"},{"width":"145","id":"K_ENTER","sp":"1","text":"*Enter*"}]}]}]}};this.s9=KeymanWeb.KLOAD(this.KI,"myVar","1");this.s13="1";this.s14="0";this.s15="1";this.s16="1";this.KVER="15.0.105.0";this.KVS=['s9'];this.gs=function(t,e) {return this.g0(t,e);};this.g0=function(t,e) {var k=KeymanWeb,r=0,m=0;if(k.KKM(e,16384,67)) {if(1){r=m=1;k.KDC(0,t);k.KO(-1,t,"(-)");this.s9=this.s14;}}else if(k.KKM(e,16384,82)) {if(this.s9===this.s15){r=m=1;k.KDC(0,t);k.KO(-1,t,"+");}else if(this.s9!==this.s16){r=m=1;k.KDC(0,t);k.KO(-1,t,"-");}}else if(k.KKM(e,16384,83)) {if(1){r=m=1;k.KDC(0,t);k.KO(-1,t,"(+)");this.s9=this.s13;}}return r;};} \ No newline at end of file +if(typeof keyman === 'undefined') { + console.log('Keyboard requires KeymanWeb 10.0 or later'); + if(typeof tavultesoft !== 'undefined') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later"); +} else { +KeymanWeb.KR(new Keyboard_testvariable()); +} +function Keyboard_testvariable() +{ + var modCodes = keyman.osk.modifierCodes; + var keyCodes = keyman.osk.keyCodes; + + this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9; + this.KI="Keyboard_testvariable"; + this.KN="testvariable"; + this.KMINVER="10.0"; + this.KV={F:' 1em "Arial"',K102:0}; + this.KV.KLS={ + "default": ["","","","","","","","","","","","","","","","","","","","Reveal","","","","","","","","","","","","","","Set","","","","","","","","","","","","","","","","","","Clear","","","","","","","","","","","","",""] + }; + this.KV.BK=(function(x){ + var + empty=Array.apply(null, Array(65)).map(String.prototype.valueOf,""), + result=[], v, i, + modifiers=['default','shift','ctrl','shift-ctrl','alt','shift-alt','ctrl-alt','shift-ctrl-alt']; + for(i=modifiers.length-1;i>=0;i--) { + v = x[modifiers[i]]; + if(v || result.length > 0) { + result=(v ? v : empty).slice().concat(result); + } + } + return result; + })(this.KV.KLS); + this.KDU=0; + this.KH=''; + this.KM=0; + this.KBVER="1.0"; + this.KMBM=0 /* 0x0000 */; + this.KVKL={ + "tablet": { + "displayUnderlying": false, + "layer": [ + { + "id": "default", + "row": [ + { + "id": "1", + "key": [ + { + "id": "K_S", + "text": "Set" + }, + { + "id": "K_C", + "text": "Clear" + }, + { + "id": "K_R", + "text": "Reveal" + }, + { + "width": "100", + "id": "K_BKSP", + "sp": "1", + "text": "*BkSp*" + } + ] + }, + { + "id": "2", + "key": [ + { + "width": "140", + "id": "K_LOPT", + "sp": "1", + "text": "*Menu*" + }, + { + "id": "K_SPACE" + }, + { + "width": "145", + "id": "K_ENTER", + "sp": "1", + "text": "*Enter*" + } + ] + } + ] + } + ] + } +} +; + this.s_myVar_9=KeymanWeb.KLOAD(this.KI,"myVar","1"); + this.s13="1"; + this.s14="0"; + this.s15="1"; + this.s16="1"; + this.KVER="15.0.105.0"; + this.KVS=['s_myVar_9']; + this.gs=function(t,e) { + return this.g_main_0(t,e); + }; + this.g_main_0=function(t,e) { + var k=KeymanWeb,r=0,m=0; + if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_C /* 0x43 */)) { + if(1){ + r=m=1; // Line 16 + k.KDC(0,t); + k.KO(-1,t,"(-)"); + this.s_myVar_9=this.s14; + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_R /* 0x52 */)) { + if(this.s_myVar_9===this.s15){ + r=m=1; // Line 17 + k.KDC(0,t); + k.KO(-1,t,"+"); + } + else if(this.s_myVar_9!==this.s16){ + r=m=1; // Line 18 + k.KDC(0,t); + k.KO(-1,t,"-"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_S /* 0x53 */)) { + if(1){ + r=m=1; // Line 15 + k.KDC(0,t); + k.KO(-1,t,"(+)"); + this.s_myVar_9=this.s13; + } + } + return r; + }; +} From afab4a2b56d8604edc7cfce8be0b656ecab3e7bc Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 27 Sep 2021 10:43:58 +1000 Subject: [PATCH 49/63] chore(web): fixup name of oldtestvariable.js --- web/testing/issue2924/oldtestvariable.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/testing/issue2924/oldtestvariable.js b/web/testing/issue2924/oldtestvariable.js index 678f522626..0b7c3bc135 100644 --- a/web/testing/issue2924/oldtestvariable.js +++ b/web/testing/issue2924/oldtestvariable.js @@ -2,16 +2,16 @@ if(typeof keyman === 'undefined') { console.log('Keyboard requires KeymanWeb 10.0 or later'); if(typeof tavultesoft !== 'undefined') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later"); } else { -KeymanWeb.KR(new Keyboard_testvariable()); +KeymanWeb.KR(new Keyboard_oldtestvariable()); } -function Keyboard_testvariable() +function Keyboard_oldtestvariable() { var modCodes = keyman.osk.modifierCodes; var keyCodes = keyman.osk.keyCodes; this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9; - this.KI="Keyboard_testvariable"; - this.KN="testvariable"; + this.KI="Keyboard_oldtestvariable"; + this.KN="oldtestvariable"; this.KMINVER="10.0"; this.KV={F:' 1em "Arial"',K102:0}; this.KV.KLS={ From 56d18bfab30a75baa7e158b67da36db092393a4c Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 29 Sep 2021 11:34:16 +1000 Subject: [PATCH 50/63] fix(windows): change canonicalization strategy for Windows 7 On Windows 7, we will no longer attempt to canonicalize BCP 47 tags in the same was as on later OS versions, because there appear to be some significant differences in how they work, for example, zh-CN is not converted to zh-Hans-CN on Windows 7, whereas it is on Windows 10. This commit also refreshes the `KLog` unit which is useful for debugging these types of scenarios. --- ...an.Configuration.System.TIPMaintenance.pas | 301 +++++++++++------- .../kmshell/install/UfrmInstallKeyboard.pas | 46 +-- ...yman.System.CanonicalLanguageCodeUtils.pas | 7 + windows/src/global/delphi/general/klog.pas | 102 +++--- 4 files changed, 281 insertions(+), 175 deletions(-) diff --git a/windows/src/desktop/kmshell/install/Keyman.Configuration.System.TIPMaintenance.pas b/windows/src/desktop/kmshell/install/Keyman.Configuration.System.TIPMaintenance.pas index f61aa57d25..775c33c059 100644 --- a/windows/src/desktop/kmshell/install/Keyman.Configuration.System.TIPMaintenance.pas +++ b/windows/src/desktop/kmshell/install/Keyman.Configuration.System.TIPMaintenance.pas @@ -52,6 +52,7 @@ uses Keyman.System.LanguageCodeUtils, + KLog, BCP47Tag, glossary, kmint, @@ -67,9 +68,14 @@ var i: Integer; begin Result := True; - for i := 0 to Packages.Count - 1 do - // We'll attempt every package but return failure if any of them have issues - Result := InstallTipForPackage(Packages.Names[i], Packages.ValueFromIndex[i]) and Result; + KL.MethodEnter(nil, 'TTIPMaintenance.InstallTipsForPackages', [Packages.Text]); + try + for i := 0 to Packages.Count - 1 do + // We'll attempt every package but return failure if any of them have issues + Result := InstallTipForPackage(Packages.Names[i], Packages.ValueFromIndex[i]) and Result; + finally + KL.MethodExit(nil, 'TTIPMaintenance.InstallTipsForPackages', [Result]); + end; end; class function TTIPMaintenance.InstallTipForPackage(const PackageFilename, BCP47Tag: string): Boolean; @@ -78,23 +84,29 @@ var n: Integer; pack: IKeymanPackageInstalled; begin - // This function has a known limitation: if a package contains more than one keyboard, - // then the BCP47 association will be made only for the first keyboard. This is - // considered an acceptable limitation at this time + Result := False; + KL.MethodEnter(nil, 'TTIPMaintenance.InstallTipForPackage', [PackageFilename, BCP47Tag]); + try + // This function has a known limitation: if a package contains more than one keyboard, + // then the BCP47 association will be made only for the first keyboard. This is + // considered an acceptable limitation at this time - PackageID := ChangeFileExt(ExtractFileName(PackageFilename), ''); - n := kmcom.Packages.IndexOf(PackageID); - if n < 0 then - Exit(False); + PackageID := ChangeFileExt(ExtractFileName(PackageFilename), ''); + n := kmcom.Packages.IndexOf(PackageID); + if n < 0 then + Exit(False); - pack := kmcom.Packages[n]; + pack := kmcom.Packages[n]; - if pack.Keyboards.Count = 0 then - Exit(False); + if pack.Keyboards.Count = 0 then + Exit(False); - if BCP47Tag = '' - then Result := DoInstall(pack.Keyboards[0].ID, GetFirstLanguage(pack.Keyboards[0] as IKeymanKeyboardInstalled)) - else Result := DoInstall(pack.Keyboards[0].ID, BCP47Tag); + if BCP47Tag = '' + then Result := DoInstall(pack.Keyboards[0].ID, GetFirstLanguage(pack.Keyboards[0] as IKeymanKeyboardInstalled)) + else Result := DoInstall(pack.Keyboards[0].ID, BCP47Tag); + finally + KL.MethodExit(nil, 'TTIPMaintenance.InstallTipForPackage', [Result]); + end; end; class function TTIPMaintenance.InstallTip(LangID: Integer; const KeyboardID, BCP47Tag, @@ -102,13 +114,19 @@ class function TTIPMaintenance.InstallTip(LangID: Integer; const KeyboardID, BCP var lang: IKeymanKeyboardLanguageInstalled; begin - lang := GetKeyboardLanguage(KeyboardID, BCP47Tag); - if lang = nil then - Exit(False); + Result := False; + KL.MethodEnter(nil, 'TTIPMaintenance.InstallTip', [LangID, KeyboardID, BCP47Tag, KeyboardToRemove]); + try + lang := GetKeyboardLanguage(KeyboardID, BCP47Tag); + if lang = nil then + Exit(False); - // TODO: can this fail? - (lang as IKeymanKeyboardLanguageInstalled2).InstallTip(LangID, KeyboardToRemove); - Result := True; + // TODO: can this fail? + (lang as IKeymanKeyboardLanguageInstalled2).InstallTip(LangID, KeyboardToRemove); + Result := True; + finally + KL.MethodExit(nil, 'TTIPMaintenance.InstallTip', [Result]); + end; end; class function TTIPMaintenance.RegisterTip(LangID: Integer; const KeyboardID, @@ -116,13 +134,19 @@ class function TTIPMaintenance.RegisterTip(LangID: Integer; const KeyboardID, var lang: IKeymanKeyboardLanguageInstalled; begin - lang := GetKeyboardLanguage(KeyboardID, BCP47Tag); - if lang = nil then - Exit(False); + Result := False; + KL.MethodEnter(nil, 'TTIPMaintenance.RegisterTip', [KeyboardID, BCP47Tag]); + try + lang := GetKeyboardLanguage(KeyboardID, BCP47Tag); + if lang = nil then + Exit(False); - // TODO: can this fail? - (lang as IKeymanKeyboardLanguageInstalled2).RegisterTip(LangID); - Result := True; + // TODO: can this fail? + (lang as IKeymanKeyboardLanguageInstalled2).RegisterTip(LangID); + Result := True; + finally + KL.MethodExit(nil, 'TTIPMaintenance.RegisterTip', [Result]); + end; end; class function TTIPMaintenance.DoInstall(const KeyboardID, @@ -133,44 +157,59 @@ var TemporaryKeyboardID: WideString; LangID: Integer; childExitCode: Cardinal; + CanonicalTag, Command: string; begin - lang := GetKeyboardLanguage(KeyboardID, (kmcom as IKeymanBCP47Canonicalization).GetCanonicalTag(BCP47Tag)); - if lang = nil then - // The keyboard was not found - Exit(False); - - if lang.IsInstalled then - // After canonicalization, we may find the language is already installed - Exit(True); - - TemporaryKeyboardID := ''; - LangID := 0; - RegistrationRequired := False; - - if not (lang as IKeymanKeyboardLanguageInstalled2).FindInstallationLangID(LangID, TemporaryKeyboardID, RegistrationRequired, kifInstallTransientLanguage) then - begin - // We were not able to find a TIP, perhaps all transient TIPs have been used - Exit(False); - end; - - if RegistrationRequired then - begin - // This calls back into TTIPMaintenance.RegisterTip - if WaitForElevatedConfiguration(0, '-register-tip '+IntToHex(LangID,4)+' "'+KeyboardID+'" "'+lang.BCP47Code+'" '+GetUserDefaultLangParameterString) <> 0 then + Result := False; + KL.MethodEnter(nil, 'TTIPMaintenance.DoInstall', [KeyboardID, BCP47Tag]); + try + CanonicalTag := (kmcom as IKeymanBCP47Canonicalization).GetCanonicalTag(BCP47Tag); + lang := GetKeyboardLanguage(KeyboardID, CanonicalTag); + KL.Log('BCP47Tag = %s, CanonicalTag = %s, lang.BCP47Code = %s', [BCP47Tag, CanonicalTag, lang.BCP47Code]); + if lang = nil then + // The keyboard was not found Exit(False); - end; - // This calls back into TTIPMaintenance.InstallTip - if not TUtilExecute.WaitForProcess('"'+ParamStr(0)+'" -install-tip '+IntToHex(LangID,4)+' "'+KeyboardID+'" "'+lang.BCP47Code+'" "'+TemporaryKeyboardID+'"', - GetCurrentDir, childExitCode) or - (childExitCode <> 0) then - begin + if lang.IsInstalled then + // After canonicalization, we may find the language is already installed + Exit(True); + + TemporaryKeyboardID := ''; + LangID := 0; + RegistrationRequired := False; + + if not (lang as IKeymanKeyboardLanguageInstalled2).FindInstallationLangID(LangID, TemporaryKeyboardID, RegistrationRequired, kifInstallTransientLanguage) then + begin + KL.Log('Failed to find installation langid'); + // We were not able to find a TIP, perhaps all transient TIPs have been used + Exit(False); + end; + + KL.Log('LangID=%x, TemporaryKeyboardID=%s, RegistrationRequired=%s', [LangID, TemporaryKeyboardID, BoolToStr(RegistrationRequired, True)]); + + if RegistrationRequired then + begin + Command := '-register-tip '+IntToHex(LangID,4)+' "'+KeyboardID+'" "'+lang.BCP47Code+'" '+GetUserDefaultLangParameterString; + KL.Log('Calling elevated kmshell %s', [Command]); + // This calls back into TTIPMaintenance.RegisterTip + if WaitForElevatedConfiguration(0, Command) <> 0 then + Exit(False); + end; + + Command := '-install-tip '+IntToHex(LangID,4)+' "'+KeyboardID+'" "'+lang.BCP47Code+'" "'+TemporaryKeyboardID+'"'; + KL.Log('Calling user kmshell %s', [Command]); + // This calls back into TTIPMaintenance.InstallTip + if not TUtilExecute.WaitForProcess('"'+ParamStr(0)+'" '+Command, GetCurrentDir, childExitCode) or + (childExitCode <> 0) then + begin + kmcom.Refresh; + Exit(False); + end; + kmcom.Refresh; - Exit(False); + Result := True; + finally + KL.MethodExit(nil, 'TTIPMaintenance.DoInstall', [Result]); end; - - kmcom.Refresh; - Result := True; end; function GetDefaultHKL: HKL; @@ -187,25 +226,31 @@ var TemporaryKeyboardID: WideString; RegistrationRequired: WordBool; begin - lang := GetKeyboardLanguage(KeyboardID, (kmcom as IKeymanBCP47Canonicalization).GetCanonicalTag(BCP47Tag)); - if lang = nil then - // The keyboard was not found - Exit(False); + Result := False; + KL.MethodEnter(nil, 'TTIPMaintenance.DoRegister', [KeyboardID, BCP47Tag]); + try + lang := GetKeyboardLanguage(KeyboardID, (kmcom as IKeymanBCP47Canonicalization).GetCanonicalTag(BCP47Tag)); + if lang = nil then + // The keyboard was not found + Exit(False); - if lang.IsInstalled or (lang as IKeymanKeyboardLanguageInstalled2).IsRegistered then - // After canonicalization, we may find the language is already installed - Exit(True); + if lang.IsInstalled or (lang as IKeymanKeyboardLanguageInstalled2).IsRegistered then + // After canonicalization, we may find the language is already installed + Exit(True); - TemporaryKeyboardID := ''; - LangID := 0; - RegistrationRequired := False; + TemporaryKeyboardID := ''; + LangID := 0; + RegistrationRequired := False; - if (lang as IKeymanKeyboardLanguageInstalled2).FindInstallationLangID(LangID, TemporaryKeyboardID, RegistrationRequired, 0) then - begin - Result := not RegistrationRequired or RegisterTip(LangID, KeyboardID, lang.BCP47Code); - end - else - Result := False; + if (lang as IKeymanKeyboardLanguageInstalled2).FindInstallationLangID(LangID, TemporaryKeyboardID, RegistrationRequired, 0) then + begin + Result := not RegistrationRequired or RegisterTip(LangID, KeyboardID, lang.BCP47Code); + end + else + Result := False; + finally + KL.MethodExit(nil, 'TTIPMaintenance.DoRegister', [Result]); + end; end; class function TTIPMaintenance.GetUserDefaultLangParameterString: string; @@ -213,15 +258,25 @@ var LangID: Integer; BCP47: string; begin - GetUserDefaultLanguage(BCP47, LangID); - Result := '-default-lang '+BCP47+' '+IntToHex(LangID,4); + KL.MethodEnter(nil, 'TTIPMaintenance.GetUserDefaultLangParameterString', []); + try + GetUserDefaultLanguage(BCP47, LangID); + Result := '-default-lang '+BCP47+' '+IntToHex(LangID,4); + finally + KL.MethodExit(nil, 'TTIPMaintenance.GetUserDefaultLangParameterString', [Result]); + end; end; class function TTIPMaintenance.GetUserDefaultLanguage: string; var LangID: Integer; begin - GetUserDefaultLanguage(Result, LangID); + KL.MethodEnter(nil, 'TTIPMaintenance.GetUserDefaultLanguage', []); + try + GetUserDefaultLanguage(Result, LangID); + finally + KL.MethodExit(nil, 'TTIPMaintenance.GetUserDefaultLanguage', [Result]); + end; end; class procedure TTIPMaintenance.GetUserDefaultLanguage(var BCP47: string; var LangID: Integer); @@ -260,54 +315,60 @@ var end; begin - // Fallback result - LangID := HKLToLanguageID(GetDefaultHKL); - BCP47 := TLanguageCodeUtils.TranslateWindowsLanguagesToBCP47(LangID); - - // For Win10, look in CPL/International/UserProfile - r := TRegistry.Create; + KL.MethodEnter(nil, 'TTIPMaintenance.GetUserDefaultLanguage', []); try - if not r.OpenKeyReadOnly(SRegKey_ControlPanelInternationalUserProfile) then - Exit; - if r.ValueExists(SRegValue_CPIUP_InputMethodOverride) then - begin - // Lookup the override input method BCP 47 tag - v := r.ReadString(SRegValue_CPIUP_InputMethodOverride); - keys := TStringList.Create; - try - r.GetKeyNames(keys); - for key in keys do - begin - if r.OpenKeyReadOnly('\' + SRegKey_ControlPanelInternationalUserProfile + '\' + key) and - r.ValueExists(v) then + // Fallback result + LangID := HKLToLanguageID(GetDefaultHKL); + BCP47 := TLanguageCodeUtils.TranslateWindowsLanguagesToBCP47(LangID); + + // For Win10, look in CPL/International/UserProfile + r := TRegistry.Create; + try + if not r.OpenKeyReadOnly(SRegKey_ControlPanelInternationalUserProfile) then + Exit; + if r.ValueExists(SRegValue_CPIUP_InputMethodOverride) then + begin + // Lookup the override input method BCP 47 tag + v := r.ReadString(SRegValue_CPIUP_InputMethodOverride); + keys := TStringList.Create; + try + r.GetKeyNames(keys); + for key in keys do begin - BCP47 := key; - LangID := GetLangIDFromValueName; - Break; + if r.OpenKeyReadOnly('\' + SRegKey_ControlPanelInternationalUserProfile + '\' + key) and + r.ValueExists(v) then + begin + BCP47 := key; + LangID := GetLangIDFromValueName; + Break; + end; end; + finally + keys.Free; end; - finally - keys.Free; - end; - end - else if r.ValueExists(SRegValue_CPIUP_Languages) then - begin - // The first tag is the default language tag - tags := TStringList.Create; - try - r.ReadMultiString(SRegValue_CPIUP_Languages, tags); - if tags.Count > 0 then - begin - BCP47 := tags[0].Trim; - if r.OpenKeyReadOnly('\' + SRegKey_ControlPanelInternationalUserProfile + '\' + BCP47) then - LangID := GetLangIDFromValueName; + end + else if r.ValueExists(SRegValue_CPIUP_Languages) then + begin + // The first tag is the default language tag + tags := TStringList.Create; + try + r.ReadMultiString(SRegValue_CPIUP_Languages, tags); + if tags.Count > 0 then + begin + BCP47 := tags[0].Trim; + if r.OpenKeyReadOnly('\' + SRegKey_ControlPanelInternationalUserProfile + '\' + BCP47) then + LangID := GetLangIDFromValueName; + end; + finally + tags.Free; end; - finally - tags.Free; end; + finally + r.Free; end; finally - r.Free; + KL.Log('TTIPMaintenance.GetUserDefaultLanguage = BCP47:%s LangID:%d', [BCP47, LangID]); + KL.MethodExit(nil, 'TTIPMaintenance.GetUserDefaultLanguage'); end; end; diff --git a/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas b/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas index 8e780442e6..34421ca37e 100644 --- a/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas +++ b/windows/src/desktop/kmshell/install/UfrmInstallKeyboard.pas @@ -118,6 +118,7 @@ uses System.Win.ComObj, Winapi.ShellApi, + KLog, custinterfaces, GetOSVersion, MessageIdentifierConsts, @@ -270,7 +271,6 @@ end; procedure TfrmInstallKeyboard.FireCommand(const command: WideString; params: TStringList); var - t: TTempFile; BCP47Tag: string; begin BCP47Tag := ''; @@ -297,28 +297,38 @@ begin BCP47Tag := params.ValueFromIndex[0]; TfrmProgress.Execute(Self, function(Manager: IProgressManager): Boolean + var + t: TTempFile; + ExecParams: string; begin - Manager.Title := 'Installing Keyboard'; - Manager.CanCancel := False; - Manager.UpdateProgress('Installing Keyboard', 0, 0); - t := TTempFileManager.Get('.log'); + KL.MethodEnter(Self, '"keyboard_install"', [params.Text]); try - if WaitForElevatedConfiguration(GetForegroundWindow, '-log "'+t.Name+'" -s -i "'+FInstallFile+'='+BCP47Tag+'"'+ - ' -nowelcome '+TTIPMaintenance.GetUserDefaultLangParameterString) = 0 then - begin - // install the keyboard tip - if not InstallTipForKeyboard(BCP47Tag) then - Exit(False); + Manager.Title := 'Installing Keyboard'; + Manager.CanCancel := False; + Manager.UpdateProgress('Installing Keyboard', 0, 0); + t := TTempFileManager.Get('.log'); + try + ExecParams := '-log "'+t.Name+'" -s -i "'+FInstallFile+'='+BCP47Tag+'"'+ + ' -nowelcome '+TTIPMaintenance.GetUserDefaultLangParameterString; + KL.Log('Calling elevated kmshell %s', [ExecParams]); + if WaitForElevatedConfiguration(GetForegroundWindow, ExecParams) = 0 then + begin + // install the keyboard tip + if not InstallTipForKeyboard(BCP47Tag) then + Exit(False); - CheckForMitigationWarningFor_Win10_1803(False, ''); - ModalResult := mrOk; - end - else - ModalResult := mrCancel; + CheckForMitigationWarningFor_Win10_1803(False, ''); + ModalResult := mrOk; + end + else + ModalResult := mrCancel; - CheckLogFileForWarnings(t.Name, False); + CheckLogFileForWarnings(t.Name, False); + finally + t.Free; + end; finally - t.Free; + KL.MethodExit(Self, '"keyboard_install"'); end; Result := True; end diff --git a/windows/src/global/delphi/general/Keyman.System.CanonicalLanguageCodeUtils.pas b/windows/src/global/delphi/general/Keyman.System.CanonicalLanguageCodeUtils.pas index 3d13b07a8a..4da9557054 100644 --- a/windows/src/global/delphi/general/Keyman.System.CanonicalLanguageCodeUtils.pas +++ b/windows/src/global/delphi/general/Keyman.System.CanonicalLanguageCodeUtils.pas @@ -14,6 +14,7 @@ implementation uses BCP47Tag, + GetOsVersion, Keyman.System.LanguageCodeUtils, Keyman.System.Standards.LangTagsRegistry, System.SysUtils; @@ -34,6 +35,12 @@ var t: TBCP47Tag; LangTag: TLangTag; begin + // We do not try and canonicalize language tags on Windows 7, because it does + // not follow the same patterns as for later versions of Windows. For example, + // zh-CN is not canonicalized to zh-Hans-CN + if GetOs = osWin7 then + Exit(Tag); + if Tag = '' then Exit(''); diff --git a/windows/src/global/delphi/general/klog.pas b/windows/src/global/delphi/general/klog.pas index 0915696743..2787f8b347 100644 --- a/windows/src/global/delphi/general/klog.pas +++ b/windows/src/global/delphi/general/klog.pas @@ -1,18 +1,18 @@ (* Name: klog Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 1 Aug 2006 Modified Date: 8 Jun 2012 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 01 Aug 2006 - mcdurdin - Disable logging with KLOGGING define 14 Sep 2006 - mcdurdin - Add Current Tick Count to logs (for correlation with system.log) 04 May 2012 - mcdurdin - I3309 - V9.0 - Migrate to Delphi XE2, VS2010, svn 1.7 @@ -23,8 +23,6 @@ unit klog; // I3309 interface -{TNT-IGNORE-UNIT} - {DEFINE KLOGGING} {$IFDEF KLOGGING} @@ -41,6 +39,7 @@ type FLogFile: TextFile; FMethodStack: TStringList; FFileOpen: Boolean; + function VarRecToString(const vr: TVarRec): string; {$ENDIF} public constructor Create; @@ -50,7 +49,8 @@ type procedure LogError(const msg: string); overload; procedure LogError(const msg: string; const fmt: array of const); overload; procedure MethodEnter(instance: TObject; const name: string; const parameters: array of const); - procedure MethodExit(instance: TObject; const name: string); + procedure MethodExit(instance: TObject; const name: string); overload; + procedure MethodExit(instance: TObject; const name: string; const result: array of const); overload; end; function KL: TKLog; @@ -60,8 +60,7 @@ implementation {$IFDEF KLOGGING} uses - Variants, Windows, SysUtils, ErrorControlledRegistry, ErrLogPath, VersionInfo, Unicode; - + Variants, Windows, SysUtils, ErrorControlledRegistry, KeymanPaths, VersionInfo, Unicode; {$ENDIF} var @@ -75,6 +74,7 @@ end; { TKLog } +{$WARN SYMBOL_PLATFORM OFF} constructor TKLog.Create; {$IFDEF KLOGGING} @@ -88,21 +88,21 @@ constructor TKLog.Create; var buf: array[0..260] of char; - FRootPath: string; begin inherited Create; - FRootPath := GetErrLogPath; FMethodStack := TStringList.Create; - GetModuleFileName(hInstance, buf, 260); FAppName := buf; - FLogFileName := FRootPath+ChangeFileExt(ExtractFileName(FAppName), '') + IntToStr(GetCurrentProcessId) + '.log'; + GetModuleFileName(hInstance, buf, 260); FAppName := ChangeFileExt(ExtractFileName(buf),''); + FLogFileName := TKeymanPaths.ErrorLogPath(FAppName); Log(StringOfChar('=', 160)); - Log('Starting application '+FAppName+', version '+GetFileVersionString(FAppName)); + Log('Starting application %s, version %s', [FAppName, GetFileVersionString(FAppName)]); + Log('Command line: %s', [String(CmdLine)]); {$ELSE} begin inherited Create; {$ENDIF} end; +{$WARN SYMBOL_PLATFORM DEFAULT} destructor TKLog.Destroy; {$IFDEF KLOGGING} @@ -163,26 +163,7 @@ begin begin vr := TVarRec(parameters[i]); if i > Low(parameters) then s := s + ', '; - case vr.VType of - vtInteger: s := s + IntToStr(vr.VInteger); - vtBoolean: if vr.VBoolean then s := s + 'True' else s := s + 'False'; - vtChar: s := s + ''''+Char(vr.VChar)+''''; // I3310 - vtExtended: s := s + FloatToStr(vr.VExtended^); - vtString: s := s + ''''+String_AtoU(vr.VString^)+''''; // I3310 // I3310 - vtPointer: s := s + '$'+IntToHex(Integer(vr.VPointer), 8); - vtPChar: s := s + ''''+String_AtoU(vr.VPChar)+''''; // I3310 - vtObject: if vr.VObject = nil then s := s + 'object ' else s := s + 'object '+vr.VObject.ClassName+' [$'+IntToHex(Integer(Pointer(vr.VObject)), 8)+']'; - vtClass: if vr.VClass = nil then s := s + 'class ' else s := s + 'class '+vr.VClass.ClassName; - vtWideChar: s := s + ''''+vr.VWideChar+''''; - vtPWideChar: s := s + ''''+vr.VPWideChar+''''; - vtAnsiString: s := s + ''''+string(vr.VAnsiString)+''''; - vtCurrency: s := s + CurrToStr(vr.VCurrency^); - vtVariant: try s := s + VarToStr(vr.VVariant^); except s := s + ''; end; - vtInterface: s := s + 'interface $'+IntToHex(Integer(vr.VInterface), 8); - vtWideString: s := s + ''''+widestring(vr.VWideString)+''''; - vtInt64: s := s + IntToStr(vr.VInt64^); - vtUnicodeString: s := s + ''''+WideString(vr.VUnicodeString)+''''; // I3309 - end; + s := s + VarRecToString(vr); end; if Assigned(instance) then begin @@ -199,6 +180,26 @@ begin {$ENDIF} end; +procedure TKLog.MethodExit(instance: TObject; const name: string; const result: array of const); +{$IFDEF KLOGGING} +var + s: string; +begin + if Assigned(instance) + then s := instance.ClassName+'.'+name + else s := name; + while (FMethodStack.Count > 0) and (FMethodStack[FMethodStack.Count-1] <> s) do + begin + Log(FMethodStack[FMethodStack.Count-1] + ' not exiting properly!'); + FMethodStack.Delete(FMethodStack.Count-1); + end; + if FMethodStack.Count > 0 then FMethodStack.Delete(FMethodStack.Count-1); + Log(s+'() exit('+VarRecToString(TVarRec(result[0]))+')'); +{$ELSE} +begin +{$ENDIF} +end; + procedure TKLog.MethodExit(instance: TObject; const name: string); {$IFDEF KLOGGING} var @@ -226,6 +227,33 @@ begin {$ENDIF} end; +{$IFDEF KLOGGING} +function TKLog.VarRecToString(const vr: TVarRec): string; +begin + case vr.VType of + vtInteger: Result := IntToStr(vr.VInteger); + vtBoolean: if vr.VBoolean then Result := 'True' else Result := 'False'; + vtChar: Result := ''''+Char(vr.VChar)+''''; // I3310 + vtExtended: Result := FloatToStr(vr.VExtended^); + vtString: Result := ''''+String_AtoU(vr.VString^)+''''; // I3310 // I3310 + vtPointer: Result := '$'+IntToHex(Integer(vr.VPointer), 8); + vtPChar: Result := ''''+String_AtoU(vr.VPChar)+''''; // I3310 + vtObject: if vr.VObject = nil then Result := 'object ' else Result := 'object '+vr.VObject.ClassName+' [$'+IntToHex(Integer(Pointer(vr.VObject)), 8)+']'; + vtClass: if vr.VClass = nil then Result := 'class ' else Result := 'class '+vr.VClass.ClassName; + vtWideChar: Result := ''''+vr.VWideChar+''''; + vtPWideChar: Result := ''''+vr.VPWideChar+''''; + vtAnsiString: Result := ''''+string(vr.VAnsiString)+''''; + vtCurrency: Result := CurrToStr(vr.VCurrency^); + vtVariant: try Result := VarToStr(vr.VVariant^); except Result := ''; end; + vtInterface: Result := 'interface $'+IntToHex(Integer(vr.VInterface), 8); + vtWideString: Result := ''''+widestring(vr.VWideString)+''''; + vtInt64: Result := IntToStr(vr.VInt64^); + vtUnicodeString: Result := ''''+UnicodeString(vr.VUnicodeString)+''''; // I3309 + else Result := '???'; + end; +end; +{$ENDIF} + function KLEnabled: Boolean; begin {$IFDEF KLOGGING} From de475b8602b55f402b8f1b5dcdbe7513d7f775e0 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Wed, 29 Sep 2021 08:45:45 +0700 Subject: [PATCH 51/63] docs(mac): Add note about installing with homebrew --- mac/help/start/install-keyman.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mac/help/start/install-keyman.md b/mac/help/start/install-keyman.md index 1296a58673..508ecf26be 100644 --- a/mac/help/start/install-keyman.md +++ b/mac/help/start/install-keyman.md @@ -3,7 +3,12 @@ title: Install Keyman for macOS --- *Keyman for macOS* is available for [download](https://keyman.com/mac/download) as a standard -Apple Disk Image (.dmg) file. It should be installed according to the following instructions. +Apple Disk Image (.dmg) file. You can also get the installer through Homebrew with the command: +``` +brew install --cask keyman +``` + +It should be installed according to the following instructions. [![Play](../mac_images/video.png) Watch Video](https://youtu.be/7Ax71QeUNfo) From b138aab3a1a40b13f5cedf0c227d33294793da66 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Wed, 29 Sep 2021 09:06:15 +0700 Subject: [PATCH 52/63] docs(mac): Tweak install instructions --- mac/help/start/install-keyman.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/mac/help/start/install-keyman.md b/mac/help/start/install-keyman.md index 508ecf26be..8cba3e8936 100644 --- a/mac/help/start/install-keyman.md +++ b/mac/help/start/install-keyman.md @@ -2,13 +2,17 @@ title: Install Keyman for macOS --- -*Keyman for macOS* is available for [download](https://keyman.com/mac/download) as a standard -Apple Disk Image (.dmg) file. You can also get the installer through Homebrew with the command: +*Keyman for macOS* is available as a standard +Apple Disk Image (.dmg) file. You can install through Homebrew with the command: ``` brew install --cask keyman ``` -It should be installed according to the following instructions. +Then configure the macOS [security permissions](../troubleshooting/configure-security) for Keyman to run. + +---- + +Alternatively, Keyman can also be [downloaded](https://keyman.com/mac/download) and installed according to the following instructions. [![Play](../mac_images/video.png) Watch Video](https://youtu.be/7Ax71QeUNfo) From 6d94dba5d9097539db0628564e7f759ea669ad38 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 29 Sep 2021 12:12:48 +1000 Subject: [PATCH 53/63] fix(windows): unit test os version --- .../unit-tests/standards-data/GetOsVersion.pas | 18 ++++++++++++++++++ .../standards-data/standardsdata.dpr | 3 ++- .../standards-data/standardsdata.dproj | 3 ++- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 windows/src/test/unit-tests/standards-data/GetOsVersion.pas diff --git a/windows/src/test/unit-tests/standards-data/GetOsVersion.pas b/windows/src/test/unit-tests/standards-data/GetOsVersion.pas new file mode 100644 index 0000000000..a3068b51cd --- /dev/null +++ b/windows/src/test/unit-tests/standards-data/GetOsVersion.pas @@ -0,0 +1,18 @@ +unit GetOsVersion; + +interface + +// This is a stub version of GetOsVersion for unit tests +type + TOS = (osLegacy, osVista, osWin7, osWin8, osWin10, osOther); + +function GetOs: TOS; + +implementation + +function GetOs: TOS; +begin + Result := osWin10; +end; + +end. diff --git a/windows/src/test/unit-tests/standards-data/standardsdata.dpr b/windows/src/test/unit-tests/standards-data/standardsdata.dpr index 8ed4edae64..ed5fc9ff6e 100644 --- a/windows/src/test/unit-tests/standards-data/standardsdata.dpr +++ b/windows/src/test/unit-tests/standards-data/standardsdata.dpr @@ -22,7 +22,8 @@ uses Keyman.System.Standards.LangTagsRegistry in '..\..\..\global\delphi\standards\Keyman.System.Standards.LangTagsRegistry.pas', Keyman.System.Standards.LCIDToBCP47Registry in '..\..\..\global\delphi\standards\Keyman.System.Standards.LCIDToBCP47Registry.pas', utilstr in '..\..\..\global\delphi\general\utilstr.pas', - Unicode in '..\..\..\global\delphi\general\Unicode.pas'; + Unicode in '..\..\..\global\delphi\general\Unicode.pas', + GetOsVersion in 'GetOsVersion.pas'; var runner : ITestRunner; diff --git a/windows/src/test/unit-tests/standards-data/standardsdata.dproj b/windows/src/test/unit-tests/standards-data/standardsdata.dproj index 9b34d0b20e..6da4551ac8 100644 --- a/windows/src/test/unit-tests/standards-data/standardsdata.dproj +++ b/windows/src/test/unit-tests/standards-data/standardsdata.dproj @@ -100,6 +100,7 @@ + Cfg_2 Base @@ -141,7 +142,7 @@ true - + standardsdata.exe true From 0d366637a8887f9c22511bc420529c38b5bafa94 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Wed, 29 Sep 2021 10:20:28 +0700 Subject: [PATCH 54/63] chore(android,windows): Update Amharic strings --- .../kMAPro/src/main/res/values-am-rET/strings.xml | 4 ++-- .../src/desktop/kmshell/locale/am-ET/strings.xml | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/android/KMAPro/kMAPro/src/main/res/values-am-rET/strings.xml b/android/KMAPro/kMAPro/src/main/res/values-am-rET/strings.xml index ae3fbbb1c6..0ba117dd7c 100644 --- a/android/KMAPro/kMAPro/src/main/res/values-am-rET/strings.xml +++ b/android/KMAPro/kMAPro/src/main/res/values-am-rET/strings.xml @@ -45,7 +45,7 @@ ተጨማሪ መረጃ - በሚነሳበት ሰአት ይታይ\"%1$s\" + በሚነሳበት ሰአት ይታይ \"%1$s\" የፊደል ገበታውን ሰሌዳ ጥቅሎችን ለመጫን ለኪይማኑ ውጫዊ ማከማቻ ለማንበብ ፈቃድ ይስጡት። @@ -54,7 +54,7 @@ አደረጃጀት - የተጫኑ ቋንዎች (%1$d) + የተጫኑ ቋንቋዎች (%1$d) የተጫኑ ቋንዎች (%1$d) diff --git a/windows/src/desktop/kmshell/locale/am-ET/strings.xml b/windows/src/desktop/kmshell/locale/am-ET/strings.xml index 259b2a781a..0894c84b74 100644 --- a/windows/src/desktop/kmshell/locale/am-ET/strings.xml +++ b/windows/src/desktop/kmshell/locale/am-ET/strings.xml @@ -215,7 +215,7 @@ - የፊደል ገበታ ሰሌዳን ጫን... + የፊደል ገበታ ሰሌዳ ጫን... @@ -276,7 +276,7 @@ - የሃርድዌር ዴድኪዎችን እንደ ተራ ቁልፍ አድርገው ይይዟቸው + የሃርድዌር ዴድኪዎችን እንደ ተራ ቁልፍ አድርገው ይያዟቸው @@ -312,7 +312,7 @@ - የስክሪን ላይ ኪቦርዱን ፊደሉን ከተጫኑ በኋላ Shift/Ctrl/Alt ይልቀቁ + የስክሪን ኪቦርድ ላይ ያለውን ፊደል ከተጫኑ በኋላ Shift/Ctrl/Alt ይልቀቁ @@ -365,11 +365,11 @@ - ኪይማኑን ያጥፉ + ኪይማኑን አጥፋ - የፊደል ገበታውን ዝርዝር ይክፈቱ + የፊደል ገበታውን ዝርዝር ክፈት @@ -629,7 +629,7 @@ - በውስጥ አሳይ + ቋንቋ በ @@ -733,7 +733,7 @@ - ኪይማኑን ያጥፉ + ኪይማኑን አጥፋ (&O) From f82fa964495cd3bb0c252f136d4c542a832ee365 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 29 Sep 2021 13:51:51 +1000 Subject: [PATCH 55/63] chore(windows): Keyman Core UI and Settings * Adds a taskbar icon to highlight to user when Keyman Core library is in use, with a crummy core.ico. This visual feedback will be removed in late beta. * Renames the 'use common core' registry setting to match other flags * Adds a System Setting to make the Keyman Core setting visible in System Settings and kmconfig. --- windows/src/desktop/branding/core.ico | Bin 0 -> 32988 bytes windows/src/desktop/inst/keymandesktop.wxs | 4 ++ windows/src/engine/keyman/UfrmKeyman7Main.pas | 37 ++++++++++++++++++ windows/src/engine/keyman32/k32_globals.cpp | 4 +- .../src/global/delphi/cust/StockFileNames.pas | 7 +++- .../delphi/general/Keyman.System.Settings.pas | 14 ++++++- .../global/delphi/general/RegistryKeys.pas | 2 + windows/src/global/inc/registry.h | 24 ++++++------ 8 files changed, 76 insertions(+), 16 deletions(-) create mode 100644 windows/src/desktop/branding/core.ico diff --git a/windows/src/desktop/branding/core.ico b/windows/src/desktop/branding/core.ico new file mode 100644 index 0000000000000000000000000000000000000000..1b6fb8ae64032394781e98043267919ada143422 GIT binary patch literal 32988 zcmeHP30M?I+Gcn2?B?HplQky5a3nFiNjBzEK{O`W^+>Yjb~pLW;l^y-T$>9y1_ovT zM?|BEi3SxVYCNJF7fnn&nTr`fK@J6hnPC`i1#da#fSKv;`oFKof~Fk^hHQ4T&&=~Q z)m>dx-}k;%_0?C^RRje5B;cxmY10BA920N{gntYO2pBWw((|Z*fM|%5NG?79Pe4G{ zp8^6#K|G)Ss(^sJ7Xt$BfIN^aKnWMdkMu_Z0?3c)8Yy0J{vQ)|)K#qiNT2=qhiL!l z>4dmkWWZ0Wy}ZB7ol8h}cYm^zCkdG`qd(n-4c_;dPTb#&#{PVGhiS!W1kWR_Z*l%X zWg$+nJ`|@AALR&fP(AS;`Ji|Q!!J%p%Nl|MvHl}{?$ep-j^R*x(08;QAO;~Hn4j`Q z)A+)VaoD!7JfUpNBQ8(yex!KC`3K0Ra(rQ;?=YnAo2gpV_L$zsv9)0;J z4q+R>dtu!oM*IoWP^`Yvi8&F-73)9J=RO<)89wWjzDIsmt{hlrw7$J42V%#3hzD&- zLxVSk(7q!l^yh0lpmHyTBgHGu?-M_*Q(yH!-wnq;igfoW>k89|^&jc;pgJKw{0TXr z^(?HvE7X5bdBZGcqoht!AS^)li8`){gus;5~0kv`LMe=Olh@rv{RSa4H4#rl8W z&k7y6IVGRXP~>^q-#<#o>)#M^=Mo!xLt;0%F2P2othBSsiag}?uX@c z2fsqVy$?#V|3#?h#1Ku)eK(epiD8;SuSwwsGAX=(Obp3=R+#r+bw4W3Jz?zP-nBBV zrz@kJkkouak~MC!K<_5Xyk73^C3fbQu{Lr|oQ=%d25$or zB_Wa|TcJ?j$WZ+a<0a~@iD7zj&kZUvAw-zUWD&M~+XA7kw_kJc&sg^pB)Qyk_ZKmX->PA^ zENY;E?R@*aKG8;QOSiGI++I#x|JVjF?&Td$j}rRBj5QAC*HRm~UN$)PV7Y@x zQavO{;k;j{XUeNppDuf^g~;bsd9u^$xJ`>1$nrQ7cmFLq_U`LdeeEAPn0%9ln|W^m z^URdPOzOOPl9|}px@Ud!EyD7Kb03t_`&&thXKAp)bqec5lEwjMFK%kP(6&ujX5-TH z2i8690}G%JV853h=;i*pqldXp3jJV^ddGN4Dno*0ohQR%39Mv$e>uvUpJ%078@FV% zk@XAe$y!An*`TZ^ih0L5>NC-XkSU>Z?`E!oSzJ=gz1m58hg6{#C%% zAX?^7VX*AtJrad`Q;^*0;BlwA2enmb$3vi9|7~XvqXeuJH?8~mdwaN-b~xS0L+pWG zHYBNw#rhwN1ME|hwJPl&0omJ zlaYnYyvNEs(!W$P&plAYj2(55y#BbEWG2*=R_L4H%fR5jV3}i9aEhx3aR-AP9!yVR z{AlO{Hz~T=*n_>S&;}sp=eIgNfS*k-@bF{8QyZMjC};ziM_2~ENBqGu`y8Q$Sqf{~ z){OIg*pY+mR4Z8#XF}}k*ipGqzj-Y7g_j>L0qmuoNjGZQ2@)0GJ|aTYz*Pk?f2UFZZb35!7McN_XF(v@9gPelwb2lHo_ zbMv1)#;k}pvn!=$Hd|T8rM`NcTm1JL7RLu1Bku{!CDJ(+>;|Qkdue(N`TMM+Uy%Uv z6QK-xADGnXlqg(2>xR~muW%IDfvDwn2FLvYeE`M;Y!h?;;bdZ<{VTNC4m>1D)yvJ> z)x%Ey*v^cGykPH1h!X5eQukr13x*pMjW@4Owz{%Y8ZX0-9Bf=zPd-a;;M>Ex6f4Pw zYuo!xWb2X!7#|CH{CADcC2u}m#zsF^;X&K*;vcG^uc)>N<encWzI_T5Jv4;A-o z@Mj)b=U}mZh4|@xDsUjz^m8MJwt;=(1Mmr-+2Y{+L<#n}WXB?^3x;cwYhT^6=$udN z)E3YX@h^`xaj!pK#ylB$h=~mK`b9V%%(&CQOuk9Wj}?EoP0Kwqxr#g)QLsuV3-3c^ z-LrW7Fb)lcSNsm~&)VqV2E$Kzpdt2+n0>w6Gh3X@{{T?+R=H_TxXSva?D-|EE}eg_thtW4k9%*2UbMYV-VNp_2-2Z)HM|%*xr-!>E!{(0N-^(Ox zU92LXBX580Di-RoR&Jg78Q47thmC&&_y_54RD6cG_5|nH&L4P+`)DLjH8lBk1jazDC9)r2uoNZ1f7REUA z^#{W&j7R)aS2@XDOS;)Kor{xeJY-QRA#yF#R|h#c`b7DF-9z2YKbpznUPUX{3BJ2JrB%^;k^v-v>*%S@5Tj<9W)0KpX zIpRZ`2iw3>STk5y40W$@4e#JkWL-*wPad$&=RaTJdExiP9vJ7@ z+pjsmuL)p#j|v|g@4)(pIn#}Y$;41qJ;hDK&^OwD3AWHGS%7n&Zi4f-sjF=;&VM)T z$WxkuBU9HA60IU+Q89ZoQO!I}<%z>}X$>!~OKZtpE3fyUEx>tzuoV z^VX~~E`Cl0Gy8!e&z$K;JZR&^IDI`wh2=r}FC&rR>es~b@mV6bO%GWB^D?;;*0Q?E zU%qg{IOp5X8LAzm8UQc!b7(sQVDncc z*K!Zus$+k5Z7xB7cjn;r)JcQJm2-doqW4w_=%RA~jwETz(S8#m>?5n(Nm ze$-t4QB!OA`^46^n{+g7CugdclT$|*kj~cKCT>opNA}lB7x;9*#o+y)ulF$Rj&H*(eh(aM2n3(tx8U!*xx0s1 zRN!6XN&&o!z=uiEd7LmVe6GkR1JsO_iUr zEj61xMqM0JTad~&AOFfYOYl|{NwUVq`FD)vmvJ|os~Ye_1x99l>kj(p&5u3YCi)3Aq}vVKKQ7`L-0 zOxroUZ@291yH3~bB0Xmgk_#<+*i+VBX<``>63xa)Nhv|UfABVseoh&Q3ey>;gcl9E z1|lw7{2ZLzH908FQwu!Ueii3DI(4->I`fzLeOv8La;|YVai3R{(+yw3$8ll5QvUSO zdkZwrJ#ZXszOQ!g_3@%Y@=7M(df-}Lx?V}#m{*#vzIg=+87z-EKlYwFy>wlDk$ zz5e+JOPV7?4#BuDc1wo6FKB$-OhBO z-nU%6@AojDVR2sP9plvC+Z`d3LJih&;d{e`X}`~VysY6)HJ?M@|AK3W`?lJgOZ{ON&k^#3 zxRJl+%4|S;!*w-wEcoy2gy+0JTE0L3vGy7-t2I=dT z{DjlzEZM|Tw1llM`Os~|_5fI*?K7>Wf1r)vPB)-!_y%nI*MNOHTazb+HUVQL;2i8S z=SfMoDV><~@$;`luOB*XxhDE1i#}F+8pZ`vo($^GiwQZX*2IBrkg=Ac_gQS;7#blB z^ar1~q0f`%qGaCIVE=+PcBDolyXl9aH_L3mXa(WsL>W|H!_6B|O4hM~NKJaT0N3UxqP+;J9%T#?ZRF_>0#3gguRg zNpG07akpPd`9FrVFovg~&vdpTjhsH3N}3KQfi0IdgYUfAqEC3fNuK~G+y1+MRoa*- z_4x@YwRs7N) z)&IwY;xi}0^I`OijP}ym96XUCJd1;8sl;c@#N~G&hvdfBR{A+*GsjAmGFUQ#f`&tQJxPJ}KGe8LE43Y`|&2Dva zUH2NfmCZ`2=f9cYzQKuMS~6#Pu`T(P;}>R*FSu-9h(u;f19=_@;j9Xji|3h8288eK z>FuIA#2@T+;=bq5WIO19`+QL@?s>LfL5YyqlpiX0zJO(|NvZ4PWy2m0eqYZeE;8OSb>Q9=tc!>4Fu14R zZt%b!M(2!MawlOvI7jekFmM@+-1D-%d#DlrJxd%tzT`i$*4a62b#F)12aa=CMrKO& zZ?o`B!6oco`H0<0GLx)s#Qw~EMfS%g~e1%Aor`~RtCReqRdFVkPEmX;p|&v zn6?S?2PnzU1Cwn|YU^;%&WL5Yq-V>6s?DoYs3)Gjtj z>((V7aNUV{Dt5<=YOY-SZhP$)8?1-Z;U976ufq71sg@|<+=BHH{aj_oLwDwR-h8^8 zZ-YYlQDK_P_Ke*5Hu+Vc%+dSuKYMw8QNB#mYfsWR*Sw-9S7Z6@<{f{u6eJc}@>4Fr zeg|h`=|^2B%-bF9)}5XaJ18axGOGdO#-OFW6tge`AJc_>RoB*Z&j# zb5=kA*qpDY!TwRc{x8Xo4AtsrnZpTdG;u57o0Y?)mAYDuTRaVAA9u7=gKU(E@-d_r z|C~eM`=0~8gFT7m!(ROgzRmISRYk**Nz<6L@$-#3`n@QYm<@2K<;c>G)|$_H+RWRS z`qJeWt;I_(q8|8tt-gF^N8O=?XR0-^@VzD0PWb&w%AbOKQ$)D>04?`Q!YWn#9k9N= z%BYKNz;Be6LuodXA-UUZkUHAx{z;lDR(G}6@t~HxS4J-$>)uUx}=5 zOKZ-He*?aoI-z_P^nveW@@|lOu{K}P1>a-g8w-4!y~G!MlY?)I->-bs&y*VzQlpJO zhjMBVCw%+E%Y^#q;#?44V$vkMrPoj6`{TD^`Y!Lw_bPu0^6Eejz!=*JGWVL*3Ha~i z{69YfSHu9W6X1uL@o@b|tP_a+Z#uW4a{)S!q479BpmQ2J-=b;6zB`tU^I@E4P~V@< zc`!~mSH^fOS6DvY<3;m|Lz-R~k1`j+MoTRJDEvbK`i_<*EFWbGf5LSK%qL7s%c0>= z`cs{$Ow5CN;T#b|T81zE={pQDKm7^$KY!jkZ`-=nTPCIv>rQ3*;-Bg#l=WTj5f9co z{ZT!?YkB`A`EZ^_=XZGS2j>@KGwhf7n$K_RvEv*-lH4o-AoD+f%kNL6ui630wfUr|8QF#oO|&4%n@O#U6>x`$A{p5X^=6gb~f%{?`3n7=zT8s$&EeT z$!d2MriXJ!U33lzXOGDzNp(HXJy2}Ja;Z>SeB_hY25TtlYZ0HnW@$ZAmeQGv&TALno(@S^8u*0 zcP^uD5ud$~B-$;rKkw~G(zrSkRjv%wwWanS&zbWT$4vS}`^nmWa3{>$Z0I+()$L^3 ztzUeqhc$>9cjnh&naB->Amc)0ht5&Bu?yaZ=M=|>$c z#`VtTV_CNPvXvbtEju{aOW0{XoPG}cK^A=UhbP{gKLO^K_2a_!4{MJ_PLA^DX5IXE z!EZfhIh5W}qlqQW;NOF<4}1Go@_r@nYof2Gi??_+`)+@$wQ;##Us32c!roF{TrbQs z3cz2T{@qIM&t+1_Zbly*u5R$x_Zii3mz_80Pwl@OE(7Q%;Xhm$1J_V~(%UdzjO0qc z^G?!IUQW)zI_?>Zg*2Cz5{xU}w28FW)R0pq6EPkcv%M)Eh49DYe~c5 z!{qSBjihSt-aZ{LP0fJ=q^YEYtbOV!vJ!lx6P19D(uQq*4*>^5p~aW15=%`+5B= zd3k(@`gef;fn^wTbNMo=_wD2LXf7+`F(Yooe{k_)5_`=x4>$-~2W z9XG!40-vrhJDV@Nv#pJkZrjGk4Yy8UO|wV>Yk}Ue63?^a8Y8aH*<7$Ta(?VBhi{Gy z>EDwd6{@{B0oKy^vkKvARk*Tiv;@{uA$=F057!l8T!g&Nz(jjhM6l+*NI1ui_B$d> z?SZ^K{cA#M7Md5F({n5U`JMclAfMNMA|#>nHIpvpwc5P6Wy_j690 z1$i&RIsuFGXDGMXR~}z+Ap0G#zp&Rh)?rk~tE=;*1J>Vs + + + + diff --git a/windows/src/engine/keyman/UfrmKeyman7Main.pas b/windows/src/engine/keyman/UfrmKeyman7Main.pas index 5a9cb2f16f..a118a1d191 100644 --- a/windows/src/engine/keyman/UfrmKeyman7Main.pas +++ b/windows/src/engine/keyman/UfrmKeyman7Main.pas @@ -208,6 +208,7 @@ type procedure tmrCheckInputPaneTimer(Sender: TObject); procedure tmrRefreshTimer(Sender: TObject); private + FCoreTrayIcon: TKeymanTrayIcon; InMenuLoop: Integer; // I1082 - Avoid menu nasty flicker with rapid click FClosingApp: Boolean; FRunningProduct: TRunningProduct; @@ -301,6 +302,7 @@ type procedure HotkeyWndProc(var Message: TMessage); procedure DoLanguageHotkey(Index: Integer); + procedure CreateCoreTrayIcon; protected procedure DoInterfaceHotkey(Target: Integer); @@ -502,6 +504,40 @@ begin end; end; +procedure TfrmKeyman7Main.CreateCoreTrayIcon; +var + cust: IKeymanCustomisation; + istrm: IStream; + olestrm: TOleStream; +const + REGSZ_CoreIntegation = 'use common core'; +begin + if not Reg_GetDebugFlag(REGSZ_CoreIntegation, True) then + Exit; + + FCoreTrayIcon := TKeymanTrayIcon.Create(Self); + + cust := kmint.KeymanCustomisation; + istrm := cust.CustFile['core.ico']; + if istrm <> nil then + 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; + FCoreTrayIcon.Icon.LoadFromStream(olestrm); + FCoreTrayIcon.Hint := 'Keyman Engine is using Keyman Core library ("engine.compatibility.use_keyman_core" system setting)'; + FCoreTrayIcon.Visible := True; + finally + olestrm.Free; + istrm := nil; + end; + end; + +end; + procedure TfrmKeyman7Main.FormCreate(Sender: TObject); begin if GetOs in [osVista, osWin7] then // I4576 @@ -1283,6 +1319,7 @@ begin end; end; + CreateCoreTrayIcon; //Windows.MessageBox(Handle, PChar(IntToStr(kmcom._AddRef)), 'RefCount+1', MB_OK); try diff --git a/windows/src/engine/keyman32/k32_globals.cpp b/windows/src/engine/keyman32/k32_globals.cpp index 454300b06e..f49e632714 100644 --- a/windows/src/engine/keyman32/k32_globals.cpp +++ b/windows/src/engine/keyman32/k32_globals.cpp @@ -385,8 +385,8 @@ void Globals::SetBaseKeyboardFlags(char *baseKeyboard, BOOL simulateAltGr, BOOL */ BOOL Globals::InitSettings() { /* Check for common core vs windows core */ - f_CoreIntegration = Reg_GetDebugFlag(REGSZ_CoreIntegration, TRUE); - SendDebugMessageFormat(0, sdmAIDefault, 0, "Globals::InitSettings - Coreintegration set in '" REGSZ_CoreIntegration "' to %x", f_CoreIntegration); + 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/global/delphi/cust/StockFileNames.pas b/windows/src/global/delphi/cust/StockFileNames.pas index d9b573107e..8a3719e6a7 100644 --- a/windows/src/global/delphi/cust/StockFileNames.pas +++ b/windows/src/global/delphi/cust/StockFileNames.pas @@ -28,11 +28,14 @@ const StockFileName_Menu = 'menu.txt'; // do not localise const StockFileName_AppIcon = 'appicon.ico'; // do not localise const StockFileName_ConfigIcon = 'cfgicon.ico'; // do not localise -const SStockFileNames: array[0..3] of string = ( +const StockFileName_CoreIcon = 'core.ico'; // do not localise + +const SStockFileNames: array[0..4] of string = ( StockFileName_TrayIcon, StockFileName_Menu, StockFileName_AppIcon, - StockFileName_ConfigIcon); + StockFileName_ConfigIcon, + StockFileName_CoreIcon); // Following file names are standard names within a .kmp file diff --git a/windows/src/global/delphi/general/Keyman.System.Settings.pas b/windows/src/global/delphi/general/Keyman.System.Settings.pas index 2e30cfb540..b22e47056f 100644 --- a/windows/src/global/delphi/general/Keyman.System.Settings.pas +++ b/windows/src/global/delphi/general/Keyman.System.Settings.pas @@ -95,7 +95,7 @@ const ValueType: kstInteger ); - BaseKeymanSettings: array[0..33] of TKeymanSettingBase = ( + BaseKeymanSettings: array[0..34] of TKeymanSettingBase = ( // TIKE:UTikeDebugMode.TikeDebugMode ( @@ -388,6 +388,18 @@ const ValueType: kstInteger ), + ( + ID: 'engine.compatibility.use_keyman_core'; + Name: SRegValue_Flag_UseKeymanCore; + RootKey: HKCU; + Key: SRegKey_KeymanEngineDebug_CU; + Description: 'When set to 1, uses the new Keyman Core common library; '+ + 'if compatibility issues are encountered, set to 0 '+ + 'to use the legacy Keyman for Windows core.'; + DefaultInt: 1; + ValueType: kstInteger + ), + // keyman32:k32_lowlevelkeyboardhook ( ID: 'engine.compatibility.old_cached_hotkey_modifier_state'; diff --git a/windows/src/global/delphi/general/RegistryKeys.pas b/windows/src/global/delphi/general/RegistryKeys.pas index 9bb9731e6c..5500f63611 100644 --- a/windows/src/global/delphi/general/RegistryKeys.pas +++ b/windows/src/global/delphi/general/RegistryKeys.pas @@ -452,6 +452,8 @@ const SRegValue_Flag_UseAutoStartTask = 'Flag_UseAutoStartTask'; SRegValue_Flag_SyncLanguagesToCloud = 'Flag_SyncLanguagesToCloud'; + SRegValue_Flag_UseKeymanCore = 'Flag_UseKeymanCore'; + // Fixed path names const // PF = CSIDL_PROGRAM_FILES diff --git a/windows/src/global/inc/registry.h b/windows/src/global/inc/registry.h index 307ce061f9..4e2fe9ae35 100644 --- a/windows/src/global/inc/registry.h +++ b/windows/src/global/inc/registry.h @@ -1,18 +1,18 @@ /* Name: registry Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 20 Jun 2006 Modified Date: 28 Mar 2016 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 20 Jun 2006 - mcdurdin - Initial version 01 Aug 2006 - mcdurdin - Add KeymanHotkeys reg 05 Nov 2007 - mcdurdin - I1087 - Add hotkeys to switch languages @@ -44,7 +44,7 @@ #else // this below is same in NT 4 and Win95; others will be different -#define REGSZ_Keyman "software\\keyman\\keyman engine" +#define REGSZ_Keyman "software\\keyman\\keyman engine" #define REGSZ_KeymanDeveloper "software\\keyman\\keyman developer" #define REGSZ_KeymanCU REGSZ_Keyman #define REGSZ_KeymanLM REGSZ_Keyman @@ -83,7 +83,7 @@ //#define REGSZ_SystemNLSLocale "system\\currentcontrolset\\control\\Nls\\Locale" // I4220 - + #define REGSZ_KeymanFile "keyman file" #define REGSZ_KeymanFile_MnemonicOverride "keyman file mnemonic override" // I4169 #define REGSZ_KeymanFile_MnemonicOverride_Deadkey "keyman file mnemonic override deadkey" // I4552 @@ -110,7 +110,7 @@ #define REGSZ_KeyboardHotkeysAreToggle "hotkeys are toggles" #define REGSZ_DeadkeyConversionMode "deadkey conversion mode" // CU // I4552 #define REGSZ_ZapVirtualKeyCode "zap virtual key code" // LM, defaults to 0x0E (_VK_PREFIX_DEFAULT) -/* +/* Debug flags These are all stored in HKCU\Software\Keyman\Debug */ @@ -129,6 +129,9 @@ #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" @@ -140,7 +143,6 @@ #define REGSZ_AutomaticallyReportErrors "automatically report errors" // CU, SRegKey_IDEOptions and SRegKey_KeymanEngine_CU #define REGSZ_AutomaticallyReportUsage "automatically report usage" // CU, SRegKey_IDEOptions and SRegKey_KeymanEngine_CU -#define REGSZ_CoreIntegration "use common core" // Turns on the common core - instead of windows core /* Splitting Registry into ReadOnly and FullAccess makes it much easier to ensure that we are using the registry correctly -- readonly wherever possible. */ From 4523a04409957626ba5932af4d50f8e99c13fef4 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 29 Sep 2021 15:05:41 +1000 Subject: [PATCH 56/63] chore(windows): address review comments and fix installer bug --- windows/src/desktop/inst/keymandesktop.wxs | 1 + windows/src/engine/keyman/UfrmKeyman7Main.pas | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/windows/src/desktop/inst/keymandesktop.wxs b/windows/src/desktop/inst/keymandesktop.wxs index 199f6861c6..01ec175bde 100644 --- a/windows/src/desktop/inst/keymandesktop.wxs +++ b/windows/src/desktop/inst/keymandesktop.wxs @@ -246,6 +246,7 @@ + diff --git a/windows/src/engine/keyman/UfrmKeyman7Main.pas b/windows/src/engine/keyman/UfrmKeyman7Main.pas index a118a1d191..3edaa25559 100644 --- a/windows/src/engine/keyman/UfrmKeyman7Main.pas +++ b/windows/src/engine/keyman/UfrmKeyman7Main.pas @@ -509,10 +509,8 @@ var cust: IKeymanCustomisation; istrm: IStream; olestrm: TOleStream; -const - REGSZ_CoreIntegation = 'use common core'; begin - if not Reg_GetDebugFlag(REGSZ_CoreIntegation, True) then + if not Reg_GetDebugFlag(SRegValue_Flag_UseKeymanCore, True) then Exit; FCoreTrayIcon := TKeymanTrayIcon.Create(Self); From 1fd26dcf886d976508c90d688a03a9ebf68db8fc Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Wed, 29 Sep 2021 12:35:19 +0200 Subject: [PATCH 57/63] fix(linux): Fix debian package script --- linux/scripts/debian.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux/scripts/debian.sh b/linux/scripts/debian.sh index c81ba49efe..ab27887c66 100755 --- a/linux/scripts/debian.sh +++ b/linux/scripts/debian.sh @@ -31,7 +31,7 @@ for proj in ${projects}; do downloadSource debianpackage cd ${proj}-${version} - if [ -n $DIST ]; then + if [ -n "$DIST" ]; then EXTRA_ARGS="--distribution $DIST --force-distribution" fi dch --newversion ${version}-1 ${EXTRA_ARGS} "Re-release to Debian" From ee5b071d3900b03db9719f04a6c9f93264c0f5c7 Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Wed, 29 Sep 2021 14:01:41 -0400 Subject: [PATCH 58/63] auto: increment master version to 15.0.122 --- HISTORY.md | 6 ++++++ VERSION.md | 2 +- .../web/input-processor/package-lock.json | 2 +- common/core/web/input-processor/package.json | 16 +++++++-------- .../web/keyboard-processor/package-lock.json | 2 +- .../core/web/keyboard-processor/package.json | 10 +++++----- .../core/web/tools/recorder/package-lock.json | 2 +- common/core/web/tools/recorder/package.json | 10 +++++----- .../tools/sentry-manager/package-lock.json | 2 +- .../web/tools/sentry-manager/package.json | 4 ++-- common/core/web/utils/package-lock.json | 2 +- common/core/web/utils/package.json | 6 +++--- common/models/templates/package-lock.json | 2 +- common/models/templates/package.json | 8 ++++---- common/models/types/package-lock.json | 2 +- common/models/types/package.json | 2 +- common/models/wordbreakers/package-lock.json | 2 +- common/models/wordbreakers/package.json | 4 ++-- common/predictive-text/package-lock.json | 2 +- common/predictive-text/package.json | 14 ++++++------- developer/js/package-lock.json | 2 +- developer/js/package.json | 8 ++++---- lerna.json | 2 +- resources/gosh/package-lock.json | 2 +- resources/gosh/package.json | 2 +- resources/web-environment/package-lock.json | 2 +- resources/web-environment/package.json | 4 ++-- web/package-lock.json | 2 +- web/package.json | 20 +++++++++---------- 29 files changed, 75 insertions(+), 69 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 0be1d88ab8..7d67dda64d 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,11 @@ # Keyman Version History +## 15.0.121 alpha 2021-09-29 + +* fix(developer): remove empty touch rows on save (#5720) +* chore(common): Check in crowdin strings for Shuwa Latin (#5734) +* chore(windows): fix broken links in help (#5765) + ## 15.0.120 alpha 2021-09-28 * fix: help.keyman.com script file cleanup (#5751) diff --git a/VERSION.md b/VERSION.md index d805a0328c..fb8a7113a1 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -15.0.121 \ No newline at end of file +15.0.122 \ No newline at end of file diff --git a/common/core/web/input-processor/package-lock.json b/common/core/web/input-processor/package-lock.json index dd83bff172..254353245a 100644 --- a/common/core/web/input-processor/package-lock.json +++ b/common/core/web/input-processor/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/input-processor", - "version": "15.0.121", + "version": "15.0.122", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/input-processor/package.json b/common/core/web/input-processor/package.json index 5f33938636..9109b68720 100644 --- a/common/core/web/input-processor/package.json +++ b/common/core/web/input-processor/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/input-processor", - "version": "15.0.121", + "version": "15.0.122", "description": "The core text and prediction processing engine for KeymanWeb", "repository": { "type": "git", @@ -18,8 +18,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/lexical-model-compiler": "^15.0.121", - "@keymanapp/resources-gosh": "^15.0.121", + "@keymanapp/lexical-model-compiler": "^15.0.122", + "@keymanapp/resources-gosh": "^15.0.122", "@types/node": "^11.9.4", "chai": "^4.3.4", "mocha": "^8.4.0", @@ -34,11 +34,11 @@ "mocha": "mocha" }, "dependencies": { - "@keymanapp/keyboard-processor": "^15.0.121", - "@keymanapp/lexical-model-layer": "^15.0.121", - "@keymanapp/models-types": "^15.0.121", - "@keymanapp/web-environment": "^15.0.121", - "@keymanapp/web-utils": "^15.0.121", + "@keymanapp/keyboard-processor": "^15.0.122", + "@keymanapp/lexical-model-layer": "^15.0.122", + "@keymanapp/models-types": "^15.0.122", + "@keymanapp/web-environment": "^15.0.122", + "@keymanapp/web-utils": "^15.0.122", "eventemitter3": "^4.0.0" } } diff --git a/common/core/web/keyboard-processor/package-lock.json b/common/core/web/keyboard-processor/package-lock.json index cb4e711ce0..a71318bfcc 100644 --- a/common/core/web/keyboard-processor/package-lock.json +++ b/common/core/web/keyboard-processor/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/keyboard-processor", - "version": "15.0.121", + "version": "15.0.122", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/keyboard-processor/package.json b/common/core/web/keyboard-processor/package.json index 18b73c1c9b..71a9e8a928 100644 --- a/common/core/web/keyboard-processor/package.json +++ b/common/core/web/keyboard-processor/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/keyboard-processor", - "version": "15.0.121", + "version": "15.0.122", "description": "Core module for Keyman keyboard support in KeymanWeb.", "repository": { "type": "git", @@ -18,7 +18,7 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.121", + "@keymanapp/resources-gosh": "^15.0.122", "chai": "^4.3.4", "mocha": "^8.4.0", "mocha-teamcity-reporter": "^4.0.0", @@ -32,9 +32,9 @@ "mocha": "mocha" }, "dependencies": { - "@keymanapp/models-types": "^15.0.121", - "@keymanapp/web-environment": "^15.0.121", - "@keymanapp/web-utils": "^15.0.121", + "@keymanapp/models-types": "^15.0.122", + "@keymanapp/web-environment": "^15.0.122", + "@keymanapp/web-utils": "^15.0.122", "@types/node": "^11.9.4" } } diff --git a/common/core/web/tools/recorder/package-lock.json b/common/core/web/tools/recorder/package-lock.json index ac0c8d95b1..b7735e3829 100644 --- a/common/core/web/tools/recorder/package-lock.json +++ b/common/core/web/tools/recorder/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/recorder-core", - "version": "15.0.121", + "version": "15.0.122", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/tools/recorder/package.json b/common/core/web/tools/recorder/package.json index e8d6bbce66..ef899aab88 100644 --- a/common/core/web/tools/recorder/package.json +++ b/common/core/web/tools/recorder/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/recorder-core", - "version": "15.0.121", + "version": "15.0.122", "description": "Core classes used to develop KeymanWeb test cases based on keystrokes", "main": "index.js", "scripts": { @@ -17,10 +17,10 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "dependencies": { - "@keymanapp/keyboard-processor": "^15.0.121", - "@keymanapp/models-types": "^15.0.121", - "@keymanapp/web-environment": "^15.0.121", - "@keymanapp/web-utils": "^15.0.121", + "@keymanapp/keyboard-processor": "^15.0.122", + "@keymanapp/models-types": "^15.0.122", + "@keymanapp/web-environment": "^15.0.122", + "@keymanapp/web-utils": "^15.0.122", "@types/node": "^11.9.4" }, "devDependencies": { diff --git a/common/core/web/tools/sentry-manager/package-lock.json b/common/core/web/tools/sentry-manager/package-lock.json index 15c05ef78e..6637d5ccac 100644 --- a/common/core/web/tools/sentry-manager/package-lock.json +++ b/common/core/web/tools/sentry-manager/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-sentry-manager", - "version": "15.0.121", + "version": "15.0.122", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/tools/sentry-manager/package.json b/common/core/web/tools/sentry-manager/package.json index a4e36fc5c6..df229f940f 100644 --- a/common/core/web/tools/sentry-manager/package.json +++ b/common/core/web/tools/sentry-manager/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-sentry-manager", - "version": "15.0.121", + "version": "15.0.122", "description": "Common setup for KeymanWeb's Sentry-based error reporting", "main": "dist/index.js", "scripts": { @@ -20,7 +20,7 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/web-environment": "^15.0.121", + "@keymanapp/web-environment": "^15.0.122", "@sentry/browser": "^5.27.4" } } diff --git a/common/core/web/utils/package-lock.json b/common/core/web/utils/package-lock.json index 0ae7ed2778..22662d2b4a 100644 --- a/common/core/web/utils/package-lock.json +++ b/common/core/web/utils/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-utils", - "version": "15.0.121", + "version": "15.0.122", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/utils/package.json b/common/core/web/utils/package.json index cb77f098e0..fee6fec7b3 100644 --- a/common/core/web/utils/package.json +++ b/common/core/web/utils/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-utils", - "version": "15.0.121", + "version": "15.0.122", "description": "Common utility functions used throughout other Keyman packages", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -20,8 +20,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.121", - "@keymanapp/web-environment": "^15.0.121", + "@keymanapp/resources-gosh": "^15.0.122", + "@keymanapp/web-environment": "^15.0.122", "@types/node": "^14.0.5", "typescript": "^3.8.3" } diff --git a/common/models/templates/package-lock.json b/common/models/templates/package-lock.json index 2d33f3e9fb..95e680b169 100644 --- a/common/models/templates/package-lock.json +++ b/common/models/templates/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-templates", - "version": "15.0.121", + "version": "15.0.122", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/models/templates/package.json b/common/models/templates/package.json index 0e8e0895fd..bdc61994d3 100644 --- a/common/models/templates/package.json +++ b/common/models/templates/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-templates", - "version": "15.0.121", + "version": "15.0.122", "description": "Backing model implementations (templates) for Keyman's modelling layer", "keywords": [ "lm", @@ -42,8 +42,8 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/models-types": "^15.0.121", - "@keymanapp/web-utils": "^15.0.121", + "@keymanapp/models-types": "^15.0.122", + "@keymanapp/web-utils": "^15.0.122", "@types/chai": "^4.2.11", "@types/mocha": "^7.0.2", "@types/node": "^14.0.4", @@ -52,6 +52,6 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/models-wordbreakers": "^15.0.121" + "@keymanapp/models-wordbreakers": "^15.0.122" } } diff --git a/common/models/types/package-lock.json b/common/models/types/package-lock.json index 481f13e65f..7e037b236f 100644 --- a/common/models/types/package-lock.json +++ b/common/models/types/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-types", - "version": "15.0.121", + "version": "15.0.122", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/models/types/package.json b/common/models/types/package.json index 7502298fc4..0979c5907c 100644 --- a/common/models/types/package.json +++ b/common/models/types/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-types", - "version": "15.0.121", + "version": "15.0.122", "description": "Type definitions in used in the modeling (lexical model/predictive text) component of Keyman.", "types": "./index.d.ts", "scripts": { diff --git a/common/models/wordbreakers/package-lock.json b/common/models/wordbreakers/package-lock.json index 41f552fa4c..3d272f4dd3 100644 --- a/common/models/wordbreakers/package-lock.json +++ b/common/models/wordbreakers/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-wordbreakers", - "version": "15.0.121", + "version": "15.0.122", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/models/wordbreakers/package.json b/common/models/wordbreakers/package.json index b0808fe26b..d26f27a5d5 100644 --- a/common/models/wordbreakers/package.json +++ b/common/models/wordbreakers/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-wordbreakers", - "version": "15.0.121", + "version": "15.0.122", "description": "Word breakers bundled in the modeling layer", "keywords": [ "lexical model", @@ -40,7 +40,7 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/models-types": "^15.0.121", + "@keymanapp/models-types": "^15.0.122", "@types/chai": "^4.2.11", "@types/mocha": "^7.0.2", "chai": "^4.3.4", diff --git a/common/predictive-text/package-lock.json b/common/predictive-text/package-lock.json index 4136d44a9e..fa37abcc0f 100644 --- a/common/predictive-text/package-lock.json +++ b/common/predictive-text/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-layer", - "version": "15.0.121", + "version": "15.0.122", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/predictive-text/package.json b/common/predictive-text/package.json index a0b9cbafcc..42d3ad74c5 100644 --- a/common/predictive-text/package.json +++ b/common/predictive-text/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-layer", - "version": "15.0.121", + "version": "15.0.122", "description": "Keyman/Predictive Text integration layer", "main": "build/index.js", "scripts": { @@ -21,8 +21,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/models-types": "^15.0.121", - "@keymanapp/resources-gosh": "^15.0.121", + "@keymanapp/models-types": "^15.0.122", + "@keymanapp/resources-gosh": "^15.0.122", "@types/node": "^10.17.21", "chai": "^4.3.4", "karma": "^6.3.4", @@ -46,10 +46,10 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/models-templates": "^15.0.121", - "@keymanapp/models-wordbreakers": "^15.0.121", - "@keymanapp/web-environment": "^15.0.121", - "@keymanapp/web-utils": "^15.0.121", + "@keymanapp/models-templates": "^15.0.122", + "@keymanapp/models-wordbreakers": "^15.0.122", + "@keymanapp/web-environment": "^15.0.122", + "@keymanapp/web-utils": "^15.0.122", "es6-shim": "^0.35.5", "string.prototype.codepointat": "^0.2.1", "string.prototype.startswith": "^0.2.0" diff --git a/developer/js/package-lock.json b/developer/js/package-lock.json index 5eddd448b8..b59da2a17a 100644 --- a/developer/js/package-lock.json +++ b/developer/js/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-compiler", - "version": "15.0.121", + "version": "15.0.122", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/developer/js/package.json b/developer/js/package.json index 554458907c..1aa373cadd 100644 --- a/developer/js/package.json +++ b/developer/js/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-compiler", - "version": "15.0.121", + "version": "15.0.122", "description": "Keyman Developer lexical model compiler", "keywords": [ "keyboard", @@ -37,14 +37,14 @@ "node": ">=12.0.0" }, "dependencies": { - "@keymanapp/models-types": "^15.0.121", + "@keymanapp/models-types": "^15.0.122", "commander": "^3.0.0", "typescript": "^3.8.3", "xml2js": "^0.4.19" }, "devDependencies": { - "@keymanapp/models-templates": "^15.0.121", - "@keymanapp/models-wordbreakers": "^15.0.121", + "@keymanapp/models-templates": "^15.0.122", + "@keymanapp/models-wordbreakers": "^15.0.122", "@types/chai": "^4.1.7", "@types/mocha": "^5.2.7", "@types/node": "^10.14.6", diff --git a/lerna.json b/lerna.json index 576ecc9c1e..30ff454560 100644 --- a/lerna.json +++ b/lerna.json @@ -20,5 +20,5 @@ "ts-node", "typescript" ], - "version": "15.0.121" + "version": "15.0.122" } diff --git a/resources/gosh/package-lock.json b/resources/gosh/package-lock.json index 5feba92c70..16672ab001 100644 --- a/resources/gosh/package-lock.json +++ b/resources/gosh/package-lock.json @@ -1,5 +1,5 @@ { "name": "@keymanapp/resources-gosh", - "version": "15.0.121", + "version": "15.0.122", "lockfileVersion": 1 } diff --git a/resources/gosh/package.json b/resources/gosh/package.json index d9e6f251a7..0f60d0579f 100644 --- a/resources/gosh/package.json +++ b/resources/gosh/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/resources-gosh", - "version": "15.0.121", + "version": "15.0.122", "description": "Good Ol' Shell", "author": "Marc Durdin (https://github.com/mcdurdin)", "contributors": [ diff --git a/resources/web-environment/package-lock.json b/resources/web-environment/package-lock.json index 2731c1c514..555f927c17 100644 --- a/resources/web-environment/package-lock.json +++ b/resources/web-environment/package-lock.json @@ -1,5 +1,5 @@ { "name": "@keymanapp/web-environment", - "version": "15.0.121", + "version": "15.0.122", "lockfileVersion": 1 } diff --git a/resources/web-environment/package.json b/resources/web-environment/package.json index 7119795fb3..f23ef66dfb 100644 --- a/resources/web-environment/package.json +++ b/resources/web-environment/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-environment", - "version": "15.0.121", + "version": "15.0.122", "description": "A compilation utility for passing select environment variables into our TS builds", "author": "Joshua Horton (https://github.com/jahorton)", "homepage": "https://github.com/keymanapp/keyman", @@ -17,6 +17,6 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.121" + "@keymanapp/resources-gosh": "^15.0.122" } } diff --git a/web/package-lock.json b/web/package-lock.json index 12256bd7b6..d1547bf018 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,6 +1,6 @@ { "name": "keyman", - "version": "15.0.121", + "version": "15.0.122", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/web/package.json b/web/package.json index a00a78847b..aa6b134950 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "keyman", - "version": "15.0.121", + "version": "15.0.122", "description": "Facilitates text input in any language.", "repository": { "type": "git", @@ -18,8 +18,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.121", - "@keymanapp/web-sentry-manager": "^15.0.121", + "@keymanapp/resources-gosh": "^15.0.122", + "@keymanapp/web-sentry-manager": "^15.0.122", "@sentry/cli": "^1.52.3", "chai": "^4.3.4", "google-closure-compiler-java": "^20200224.0.0", @@ -52,13 +52,13 @@ "sentry-cli": "sentry-cli" }, "dependencies": { - "@keymanapp/input-processor": "^15.0.121", - "@keymanapp/keyboard-processor": "^15.0.121", - "@keymanapp/lexical-model-layer": "^15.0.121", - "@keymanapp/models-types": "^15.0.121", - "@keymanapp/recorder-core": "^15.0.121", - "@keymanapp/web-environment": "^15.0.121", - "@keymanapp/web-utils": "^15.0.121", + "@keymanapp/input-processor": "^15.0.122", + "@keymanapp/keyboard-processor": "^15.0.122", + "@keymanapp/lexical-model-layer": "^15.0.122", + "@keymanapp/models-types": "^15.0.122", + "@keymanapp/recorder-core": "^15.0.122", + "@keymanapp/web-environment": "^15.0.122", + "@keymanapp/web-utils": "^15.0.122", "@types/node": "^11.9.4", "es6-shim": "^0.35.5", "eventemitter3": "^4.0.0" From 394b33da9ce589e10a4fdc1717a445b04e58746a Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Thu, 30 Sep 2021 14:04:26 +0700 Subject: [PATCH 59/63] docs(mac): Reorder install instructions --- mac/help/start/install-keyman.md | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/mac/help/start/install-keyman.md b/mac/help/start/install-keyman.md index 8cba3e8936..348f2c7d6e 100644 --- a/mac/help/start/install-keyman.md +++ b/mac/help/start/install-keyman.md @@ -2,17 +2,8 @@ title: Install Keyman for macOS --- -*Keyman for macOS* is available as a standard -Apple Disk Image (.dmg) file. You can install through Homebrew with the command: -``` -brew install --cask keyman -``` - -Then configure the macOS [security permissions](../troubleshooting/configure-security) for Keyman to run. - ----- - -Alternatively, Keyman can also be [downloaded](https://keyman.com/mac/download) and installed according to the following instructions. +*Keyman for macOS* is available for [downloaded](https://keyman.com/mac/download) as a standard +Apple Disk Image (.dmg) file. It should be installed according to the following instructions. [![Play](../mac_images/video.png) Watch Video](https://youtu.be/7Ax71QeUNfo) @@ -41,6 +32,18 @@ Alternatively, Keyman can also be [downloaded](https://keyman.com/mac/download) 5. Now you can start typing with the selected keyboard in any text editor or application that uses standard macOS input methods. +--- + +If you're using Homebrew, you can also install Keyman with the command: + +1. +``` +brew install --cask keyman +``` + +2. Configure the macOS [security permissions](../troubleshooting/configure-security) for Keyman to run. + +---- ## How To - Updating Keyman for macOS When a new version of Keyman is released, you can update by following the instructions From c10fee5d269d84f91b0398fd314f0f782874ab35 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Thu, 30 Sep 2021 15:34:48 +0700 Subject: [PATCH 60/63] Update mac/help/start/install-keyman.md Co-authored-by: Marc Durdin --- mac/help/start/install-keyman.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mac/help/start/install-keyman.md b/mac/help/start/install-keyman.md index 348f2c7d6e..a3bbdb0733 100644 --- a/mac/help/start/install-keyman.md +++ b/mac/help/start/install-keyman.md @@ -2,7 +2,7 @@ title: Install Keyman for macOS --- -*Keyman for macOS* is available for [downloaded](https://keyman.com/mac/download) as a standard +*Keyman for macOS* is available for [download](https://keyman.com/mac/download) as a standard Apple Disk Image (.dmg) file. It should be installed according to the following instructions. [![Play](../mac_images/video.png) Watch Video](https://youtu.be/7Ax71QeUNfo) From 01789142bc29d321859755254ac0ee3fed900a0b Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Thu, 30 Sep 2021 16:48:25 +0200 Subject: [PATCH 61/63] fix(common): Fix cherry-pick labeling My previous commit escaped the parens which should be part of the regex. --- .github/multi-labeler.yml | 2 +- .github/workflows/labeler.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/multi-labeler.yml b/.github/multi-labeler.yml index a06a0b23e6..1278db2a28 100644 --- a/.github/multi-labeler.yml +++ b/.github/multi-labeler.yml @@ -64,4 +64,4 @@ labels: - label: 'cherry-pick' matcher: - title: '\(🍒|:cherries:\)' + title: '(🍒|:cherries:)' diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 38e27cad8c..1c8704da25 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -12,7 +12,7 @@ jobs: repo-token: "${{ secrets.GITHUB_TOKEN }}" - name: Update labels based on PR title id: labeler - uses: fuxingloh/multi-labeler@8afa186ed03230c98fe24ebf9fe35093072ad46e + uses: fuxingloh/multi-labeler@8afa186ed03230c98fe24ebf9fe35093072ad46e # v1.4.0 with: github-token: ${{secrets.GITHUB_TOKEN}} config-path: .github/multi-labeler.yml From edaea587adbd34e956bf106d77fbbc1fca13cfb8 Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Thu, 30 Sep 2021 14:02:02 -0400 Subject: [PATCH 62/63] auto: increment master version to 15.0.123 --- HISTORY.md | 8 ++++++++ VERSION.md | 2 +- .../web/input-processor/package-lock.json | 2 +- common/core/web/input-processor/package.json | 16 +++++++-------- .../web/keyboard-processor/package-lock.json | 2 +- .../core/web/keyboard-processor/package.json | 10 +++++----- .../core/web/tools/recorder/package-lock.json | 2 +- common/core/web/tools/recorder/package.json | 10 +++++----- .../tools/sentry-manager/package-lock.json | 2 +- .../web/tools/sentry-manager/package.json | 4 ++-- common/core/web/utils/package-lock.json | 2 +- common/core/web/utils/package.json | 6 +++--- common/models/templates/package-lock.json | 2 +- common/models/templates/package.json | 8 ++++---- common/models/types/package-lock.json | 2 +- common/models/types/package.json | 2 +- common/models/wordbreakers/package-lock.json | 2 +- common/models/wordbreakers/package.json | 4 ++-- common/predictive-text/package-lock.json | 2 +- common/predictive-text/package.json | 14 ++++++------- developer/js/package-lock.json | 2 +- developer/js/package.json | 8 ++++---- lerna.json | 2 +- resources/gosh/package-lock.json | 2 +- resources/gosh/package.json | 2 +- resources/web-environment/package-lock.json | 2 +- resources/web-environment/package.json | 4 ++-- web/package-lock.json | 2 +- web/package.json | 20 +++++++++---------- 29 files changed, 77 insertions(+), 69 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 7d67dda64d..c176bc607f 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,13 @@ # Keyman Version History +## 15.0.122 alpha 2021-09-30 + +* fix(developer): move ampersand to shift+7 on touch (#5746) +* feat(windows): Keyman Core integration (#5443) +* chore(windows): Keyman Core UI and Settings (#5769) +* fix(linux): Fix debian package script (#5771) +* docs(mac): Add note about installing with homebrew (#5767) + ## 15.0.121 alpha 2021-09-29 * fix(developer): remove empty touch rows on save (#5720) diff --git a/VERSION.md b/VERSION.md index fb8a7113a1..9b06d0e542 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -15.0.122 \ No newline at end of file +15.0.123 \ No newline at end of file diff --git a/common/core/web/input-processor/package-lock.json b/common/core/web/input-processor/package-lock.json index 254353245a..62490af262 100644 --- a/common/core/web/input-processor/package-lock.json +++ b/common/core/web/input-processor/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/input-processor", - "version": "15.0.122", + "version": "15.0.123", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/input-processor/package.json b/common/core/web/input-processor/package.json index 9109b68720..c271a38f53 100644 --- a/common/core/web/input-processor/package.json +++ b/common/core/web/input-processor/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/input-processor", - "version": "15.0.122", + "version": "15.0.123", "description": "The core text and prediction processing engine for KeymanWeb", "repository": { "type": "git", @@ -18,8 +18,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/lexical-model-compiler": "^15.0.122", - "@keymanapp/resources-gosh": "^15.0.122", + "@keymanapp/lexical-model-compiler": "^15.0.123", + "@keymanapp/resources-gosh": "^15.0.123", "@types/node": "^11.9.4", "chai": "^4.3.4", "mocha": "^8.4.0", @@ -34,11 +34,11 @@ "mocha": "mocha" }, "dependencies": { - "@keymanapp/keyboard-processor": "^15.0.122", - "@keymanapp/lexical-model-layer": "^15.0.122", - "@keymanapp/models-types": "^15.0.122", - "@keymanapp/web-environment": "^15.0.122", - "@keymanapp/web-utils": "^15.0.122", + "@keymanapp/keyboard-processor": "^15.0.123", + "@keymanapp/lexical-model-layer": "^15.0.123", + "@keymanapp/models-types": "^15.0.123", + "@keymanapp/web-environment": "^15.0.123", + "@keymanapp/web-utils": "^15.0.123", "eventemitter3": "^4.0.0" } } diff --git a/common/core/web/keyboard-processor/package-lock.json b/common/core/web/keyboard-processor/package-lock.json index a71318bfcc..adf3d6c9d4 100644 --- a/common/core/web/keyboard-processor/package-lock.json +++ b/common/core/web/keyboard-processor/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/keyboard-processor", - "version": "15.0.122", + "version": "15.0.123", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/keyboard-processor/package.json b/common/core/web/keyboard-processor/package.json index 71a9e8a928..63bab46ec4 100644 --- a/common/core/web/keyboard-processor/package.json +++ b/common/core/web/keyboard-processor/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/keyboard-processor", - "version": "15.0.122", + "version": "15.0.123", "description": "Core module for Keyman keyboard support in KeymanWeb.", "repository": { "type": "git", @@ -18,7 +18,7 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.122", + "@keymanapp/resources-gosh": "^15.0.123", "chai": "^4.3.4", "mocha": "^8.4.0", "mocha-teamcity-reporter": "^4.0.0", @@ -32,9 +32,9 @@ "mocha": "mocha" }, "dependencies": { - "@keymanapp/models-types": "^15.0.122", - "@keymanapp/web-environment": "^15.0.122", - "@keymanapp/web-utils": "^15.0.122", + "@keymanapp/models-types": "^15.0.123", + "@keymanapp/web-environment": "^15.0.123", + "@keymanapp/web-utils": "^15.0.123", "@types/node": "^11.9.4" } } diff --git a/common/core/web/tools/recorder/package-lock.json b/common/core/web/tools/recorder/package-lock.json index b7735e3829..af86dc54c8 100644 --- a/common/core/web/tools/recorder/package-lock.json +++ b/common/core/web/tools/recorder/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/recorder-core", - "version": "15.0.122", + "version": "15.0.123", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/tools/recorder/package.json b/common/core/web/tools/recorder/package.json index ef899aab88..fd14c34991 100644 --- a/common/core/web/tools/recorder/package.json +++ b/common/core/web/tools/recorder/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/recorder-core", - "version": "15.0.122", + "version": "15.0.123", "description": "Core classes used to develop KeymanWeb test cases based on keystrokes", "main": "index.js", "scripts": { @@ -17,10 +17,10 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "dependencies": { - "@keymanapp/keyboard-processor": "^15.0.122", - "@keymanapp/models-types": "^15.0.122", - "@keymanapp/web-environment": "^15.0.122", - "@keymanapp/web-utils": "^15.0.122", + "@keymanapp/keyboard-processor": "^15.0.123", + "@keymanapp/models-types": "^15.0.123", + "@keymanapp/web-environment": "^15.0.123", + "@keymanapp/web-utils": "^15.0.123", "@types/node": "^11.9.4" }, "devDependencies": { diff --git a/common/core/web/tools/sentry-manager/package-lock.json b/common/core/web/tools/sentry-manager/package-lock.json index 6637d5ccac..184d1a07e4 100644 --- a/common/core/web/tools/sentry-manager/package-lock.json +++ b/common/core/web/tools/sentry-manager/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-sentry-manager", - "version": "15.0.122", + "version": "15.0.123", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/tools/sentry-manager/package.json b/common/core/web/tools/sentry-manager/package.json index df229f940f..01abe87c4f 100644 --- a/common/core/web/tools/sentry-manager/package.json +++ b/common/core/web/tools/sentry-manager/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-sentry-manager", - "version": "15.0.122", + "version": "15.0.123", "description": "Common setup for KeymanWeb's Sentry-based error reporting", "main": "dist/index.js", "scripts": { @@ -20,7 +20,7 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/web-environment": "^15.0.122", + "@keymanapp/web-environment": "^15.0.123", "@sentry/browser": "^5.27.4" } } diff --git a/common/core/web/utils/package-lock.json b/common/core/web/utils/package-lock.json index 22662d2b4a..5a065dbe6f 100644 --- a/common/core/web/utils/package-lock.json +++ b/common/core/web/utils/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-utils", - "version": "15.0.122", + "version": "15.0.123", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/utils/package.json b/common/core/web/utils/package.json index fee6fec7b3..3b4b30b56b 100644 --- a/common/core/web/utils/package.json +++ b/common/core/web/utils/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-utils", - "version": "15.0.122", + "version": "15.0.123", "description": "Common utility functions used throughout other Keyman packages", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -20,8 +20,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.122", - "@keymanapp/web-environment": "^15.0.122", + "@keymanapp/resources-gosh": "^15.0.123", + "@keymanapp/web-environment": "^15.0.123", "@types/node": "^14.0.5", "typescript": "^3.8.3" } diff --git a/common/models/templates/package-lock.json b/common/models/templates/package-lock.json index 95e680b169..8582bbdc4c 100644 --- a/common/models/templates/package-lock.json +++ b/common/models/templates/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-templates", - "version": "15.0.122", + "version": "15.0.123", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/models/templates/package.json b/common/models/templates/package.json index bdc61994d3..d7835fab44 100644 --- a/common/models/templates/package.json +++ b/common/models/templates/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-templates", - "version": "15.0.122", + "version": "15.0.123", "description": "Backing model implementations (templates) for Keyman's modelling layer", "keywords": [ "lm", @@ -42,8 +42,8 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/models-types": "^15.0.122", - "@keymanapp/web-utils": "^15.0.122", + "@keymanapp/models-types": "^15.0.123", + "@keymanapp/web-utils": "^15.0.123", "@types/chai": "^4.2.11", "@types/mocha": "^7.0.2", "@types/node": "^14.0.4", @@ -52,6 +52,6 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/models-wordbreakers": "^15.0.122" + "@keymanapp/models-wordbreakers": "^15.0.123" } } diff --git a/common/models/types/package-lock.json b/common/models/types/package-lock.json index 7e037b236f..26e5808aa3 100644 --- a/common/models/types/package-lock.json +++ b/common/models/types/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-types", - "version": "15.0.122", + "version": "15.0.123", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/models/types/package.json b/common/models/types/package.json index 0979c5907c..e68051ae66 100644 --- a/common/models/types/package.json +++ b/common/models/types/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-types", - "version": "15.0.122", + "version": "15.0.123", "description": "Type definitions in used in the modeling (lexical model/predictive text) component of Keyman.", "types": "./index.d.ts", "scripts": { diff --git a/common/models/wordbreakers/package-lock.json b/common/models/wordbreakers/package-lock.json index 3d272f4dd3..d33efffe36 100644 --- a/common/models/wordbreakers/package-lock.json +++ b/common/models/wordbreakers/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-wordbreakers", - "version": "15.0.122", + "version": "15.0.123", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/models/wordbreakers/package.json b/common/models/wordbreakers/package.json index d26f27a5d5..dcb4f01eda 100644 --- a/common/models/wordbreakers/package.json +++ b/common/models/wordbreakers/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-wordbreakers", - "version": "15.0.122", + "version": "15.0.123", "description": "Word breakers bundled in the modeling layer", "keywords": [ "lexical model", @@ -40,7 +40,7 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/models-types": "^15.0.122", + "@keymanapp/models-types": "^15.0.123", "@types/chai": "^4.2.11", "@types/mocha": "^7.0.2", "chai": "^4.3.4", diff --git a/common/predictive-text/package-lock.json b/common/predictive-text/package-lock.json index fa37abcc0f..a61c86dae8 100644 --- a/common/predictive-text/package-lock.json +++ b/common/predictive-text/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-layer", - "version": "15.0.122", + "version": "15.0.123", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/predictive-text/package.json b/common/predictive-text/package.json index 42d3ad74c5..30e4b41441 100644 --- a/common/predictive-text/package.json +++ b/common/predictive-text/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-layer", - "version": "15.0.122", + "version": "15.0.123", "description": "Keyman/Predictive Text integration layer", "main": "build/index.js", "scripts": { @@ -21,8 +21,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/models-types": "^15.0.122", - "@keymanapp/resources-gosh": "^15.0.122", + "@keymanapp/models-types": "^15.0.123", + "@keymanapp/resources-gosh": "^15.0.123", "@types/node": "^10.17.21", "chai": "^4.3.4", "karma": "^6.3.4", @@ -46,10 +46,10 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/models-templates": "^15.0.122", - "@keymanapp/models-wordbreakers": "^15.0.122", - "@keymanapp/web-environment": "^15.0.122", - "@keymanapp/web-utils": "^15.0.122", + "@keymanapp/models-templates": "^15.0.123", + "@keymanapp/models-wordbreakers": "^15.0.123", + "@keymanapp/web-environment": "^15.0.123", + "@keymanapp/web-utils": "^15.0.123", "es6-shim": "^0.35.5", "string.prototype.codepointat": "^0.2.1", "string.prototype.startswith": "^0.2.0" diff --git a/developer/js/package-lock.json b/developer/js/package-lock.json index b59da2a17a..f1594c515e 100644 --- a/developer/js/package-lock.json +++ b/developer/js/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-compiler", - "version": "15.0.122", + "version": "15.0.123", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/developer/js/package.json b/developer/js/package.json index 1aa373cadd..18f016add5 100644 --- a/developer/js/package.json +++ b/developer/js/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-compiler", - "version": "15.0.122", + "version": "15.0.123", "description": "Keyman Developer lexical model compiler", "keywords": [ "keyboard", @@ -37,14 +37,14 @@ "node": ">=12.0.0" }, "dependencies": { - "@keymanapp/models-types": "^15.0.122", + "@keymanapp/models-types": "^15.0.123", "commander": "^3.0.0", "typescript": "^3.8.3", "xml2js": "^0.4.19" }, "devDependencies": { - "@keymanapp/models-templates": "^15.0.122", - "@keymanapp/models-wordbreakers": "^15.0.122", + "@keymanapp/models-templates": "^15.0.123", + "@keymanapp/models-wordbreakers": "^15.0.123", "@types/chai": "^4.1.7", "@types/mocha": "^5.2.7", "@types/node": "^10.14.6", diff --git a/lerna.json b/lerna.json index 30ff454560..8be8cbc890 100644 --- a/lerna.json +++ b/lerna.json @@ -20,5 +20,5 @@ "ts-node", "typescript" ], - "version": "15.0.122" + "version": "15.0.123" } diff --git a/resources/gosh/package-lock.json b/resources/gosh/package-lock.json index 16672ab001..8d9f18f857 100644 --- a/resources/gosh/package-lock.json +++ b/resources/gosh/package-lock.json @@ -1,5 +1,5 @@ { "name": "@keymanapp/resources-gosh", - "version": "15.0.122", + "version": "15.0.123", "lockfileVersion": 1 } diff --git a/resources/gosh/package.json b/resources/gosh/package.json index 0f60d0579f..d2a4fa73b8 100644 --- a/resources/gosh/package.json +++ b/resources/gosh/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/resources-gosh", - "version": "15.0.122", + "version": "15.0.123", "description": "Good Ol' Shell", "author": "Marc Durdin (https://github.com/mcdurdin)", "contributors": [ diff --git a/resources/web-environment/package-lock.json b/resources/web-environment/package-lock.json index 555f927c17..d1206bd7ac 100644 --- a/resources/web-environment/package-lock.json +++ b/resources/web-environment/package-lock.json @@ -1,5 +1,5 @@ { "name": "@keymanapp/web-environment", - "version": "15.0.122", + "version": "15.0.123", "lockfileVersion": 1 } diff --git a/resources/web-environment/package.json b/resources/web-environment/package.json index f23ef66dfb..d32be55779 100644 --- a/resources/web-environment/package.json +++ b/resources/web-environment/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-environment", - "version": "15.0.122", + "version": "15.0.123", "description": "A compilation utility for passing select environment variables into our TS builds", "author": "Joshua Horton (https://github.com/jahorton)", "homepage": "https://github.com/keymanapp/keyman", @@ -17,6 +17,6 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.122" + "@keymanapp/resources-gosh": "^15.0.123" } } diff --git a/web/package-lock.json b/web/package-lock.json index d1547bf018..f747c057ce 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,6 +1,6 @@ { "name": "keyman", - "version": "15.0.122", + "version": "15.0.123", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/web/package.json b/web/package.json index aa6b134950..f05d83b00a 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "keyman", - "version": "15.0.122", + "version": "15.0.123", "description": "Facilitates text input in any language.", "repository": { "type": "git", @@ -18,8 +18,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.122", - "@keymanapp/web-sentry-manager": "^15.0.122", + "@keymanapp/resources-gosh": "^15.0.123", + "@keymanapp/web-sentry-manager": "^15.0.123", "@sentry/cli": "^1.52.3", "chai": "^4.3.4", "google-closure-compiler-java": "^20200224.0.0", @@ -52,13 +52,13 @@ "sentry-cli": "sentry-cli" }, "dependencies": { - "@keymanapp/input-processor": "^15.0.122", - "@keymanapp/keyboard-processor": "^15.0.122", - "@keymanapp/lexical-model-layer": "^15.0.122", - "@keymanapp/models-types": "^15.0.122", - "@keymanapp/recorder-core": "^15.0.122", - "@keymanapp/web-environment": "^15.0.122", - "@keymanapp/web-utils": "^15.0.122", + "@keymanapp/input-processor": "^15.0.123", + "@keymanapp/keyboard-processor": "^15.0.123", + "@keymanapp/lexical-model-layer": "^15.0.123", + "@keymanapp/models-types": "^15.0.123", + "@keymanapp/recorder-core": "^15.0.123", + "@keymanapp/web-environment": "^15.0.123", + "@keymanapp/web-utils": "^15.0.123", "@types/node": "^11.9.4", "es6-shim": "^0.35.5", "eventemitter3": "^4.0.0" From bfa34828d34c5972f90e6cf6d90d2979c36da8de Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Fri, 1 Oct 2021 14:01:32 -0400 Subject: [PATCH 63/63] auto: increment master version to 15.0.124 --- HISTORY.md | 5 +++++ VERSION.md | 2 +- .../web/input-processor/package-lock.json | 2 +- common/core/web/input-processor/package.json | 16 +++++++-------- .../web/keyboard-processor/package-lock.json | 2 +- .../core/web/keyboard-processor/package.json | 10 +++++----- .../core/web/tools/recorder/package-lock.json | 2 +- common/core/web/tools/recorder/package.json | 10 +++++----- .../tools/sentry-manager/package-lock.json | 2 +- .../web/tools/sentry-manager/package.json | 4 ++-- common/core/web/utils/package-lock.json | 2 +- common/core/web/utils/package.json | 6 +++--- common/models/templates/package-lock.json | 2 +- common/models/templates/package.json | 8 ++++---- common/models/types/package-lock.json | 2 +- common/models/types/package.json | 2 +- common/models/wordbreakers/package-lock.json | 2 +- common/models/wordbreakers/package.json | 4 ++-- common/predictive-text/package-lock.json | 2 +- common/predictive-text/package.json | 14 ++++++------- developer/js/package-lock.json | 2 +- developer/js/package.json | 8 ++++---- lerna.json | 2 +- resources/gosh/package-lock.json | 2 +- resources/gosh/package.json | 2 +- resources/web-environment/package-lock.json | 2 +- resources/web-environment/package.json | 4 ++-- web/package-lock.json | 2 +- web/package.json | 20 +++++++++---------- 29 files changed, 74 insertions(+), 69 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index c176bc607f..377de392e8 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,10 @@ # Keyman Version History +## 15.0.123 alpha 2021-10-01 + +* fix(common): Fix cherry-pick labeling (#5782) +* chore(ios,android,windows): Update crowdin strings for Amharic (#5722) + ## 15.0.122 alpha 2021-09-30 * fix(developer): move ampersand to shift+7 on touch (#5746) diff --git a/VERSION.md b/VERSION.md index 9b06d0e542..80a9265582 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -15.0.123 \ No newline at end of file +15.0.124 \ No newline at end of file diff --git a/common/core/web/input-processor/package-lock.json b/common/core/web/input-processor/package-lock.json index 62490af262..acf36f841b 100644 --- a/common/core/web/input-processor/package-lock.json +++ b/common/core/web/input-processor/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/input-processor", - "version": "15.0.123", + "version": "15.0.124", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/input-processor/package.json b/common/core/web/input-processor/package.json index c271a38f53..1edd2c4696 100644 --- a/common/core/web/input-processor/package.json +++ b/common/core/web/input-processor/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/input-processor", - "version": "15.0.123", + "version": "15.0.124", "description": "The core text and prediction processing engine for KeymanWeb", "repository": { "type": "git", @@ -18,8 +18,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/lexical-model-compiler": "^15.0.123", - "@keymanapp/resources-gosh": "^15.0.123", + "@keymanapp/lexical-model-compiler": "^15.0.124", + "@keymanapp/resources-gosh": "^15.0.124", "@types/node": "^11.9.4", "chai": "^4.3.4", "mocha": "^8.4.0", @@ -34,11 +34,11 @@ "mocha": "mocha" }, "dependencies": { - "@keymanapp/keyboard-processor": "^15.0.123", - "@keymanapp/lexical-model-layer": "^15.0.123", - "@keymanapp/models-types": "^15.0.123", - "@keymanapp/web-environment": "^15.0.123", - "@keymanapp/web-utils": "^15.0.123", + "@keymanapp/keyboard-processor": "^15.0.124", + "@keymanapp/lexical-model-layer": "^15.0.124", + "@keymanapp/models-types": "^15.0.124", + "@keymanapp/web-environment": "^15.0.124", + "@keymanapp/web-utils": "^15.0.124", "eventemitter3": "^4.0.0" } } diff --git a/common/core/web/keyboard-processor/package-lock.json b/common/core/web/keyboard-processor/package-lock.json index adf3d6c9d4..6d1e5b37f7 100644 --- a/common/core/web/keyboard-processor/package-lock.json +++ b/common/core/web/keyboard-processor/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/keyboard-processor", - "version": "15.0.123", + "version": "15.0.124", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/keyboard-processor/package.json b/common/core/web/keyboard-processor/package.json index 63bab46ec4..ed74c02e1e 100644 --- a/common/core/web/keyboard-processor/package.json +++ b/common/core/web/keyboard-processor/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/keyboard-processor", - "version": "15.0.123", + "version": "15.0.124", "description": "Core module for Keyman keyboard support in KeymanWeb.", "repository": { "type": "git", @@ -18,7 +18,7 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.123", + "@keymanapp/resources-gosh": "^15.0.124", "chai": "^4.3.4", "mocha": "^8.4.0", "mocha-teamcity-reporter": "^4.0.0", @@ -32,9 +32,9 @@ "mocha": "mocha" }, "dependencies": { - "@keymanapp/models-types": "^15.0.123", - "@keymanapp/web-environment": "^15.0.123", - "@keymanapp/web-utils": "^15.0.123", + "@keymanapp/models-types": "^15.0.124", + "@keymanapp/web-environment": "^15.0.124", + "@keymanapp/web-utils": "^15.0.124", "@types/node": "^11.9.4" } } diff --git a/common/core/web/tools/recorder/package-lock.json b/common/core/web/tools/recorder/package-lock.json index af86dc54c8..5e0568b4f6 100644 --- a/common/core/web/tools/recorder/package-lock.json +++ b/common/core/web/tools/recorder/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/recorder-core", - "version": "15.0.123", + "version": "15.0.124", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/core/web/tools/recorder/package.json b/common/core/web/tools/recorder/package.json index fd14c34991..9123cb3f6d 100644 --- a/common/core/web/tools/recorder/package.json +++ b/common/core/web/tools/recorder/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/recorder-core", - "version": "15.0.123", + "version": "15.0.124", "description": "Core classes used to develop KeymanWeb test cases based on keystrokes", "main": "index.js", "scripts": { @@ -17,10 +17,10 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "dependencies": { - "@keymanapp/keyboard-processor": "^15.0.123", - "@keymanapp/models-types": "^15.0.123", - "@keymanapp/web-environment": "^15.0.123", - "@keymanapp/web-utils": "^15.0.123", + "@keymanapp/keyboard-processor": "^15.0.124", + "@keymanapp/models-types": "^15.0.124", + "@keymanapp/web-environment": "^15.0.124", + "@keymanapp/web-utils": "^15.0.124", "@types/node": "^11.9.4" }, "devDependencies": { diff --git a/common/core/web/tools/sentry-manager/package-lock.json b/common/core/web/tools/sentry-manager/package-lock.json index 184d1a07e4..dcb0e19252 100644 --- a/common/core/web/tools/sentry-manager/package-lock.json +++ b/common/core/web/tools/sentry-manager/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-sentry-manager", - "version": "15.0.123", + "version": "15.0.124", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/tools/sentry-manager/package.json b/common/core/web/tools/sentry-manager/package.json index 01abe87c4f..1fda2f123d 100644 --- a/common/core/web/tools/sentry-manager/package.json +++ b/common/core/web/tools/sentry-manager/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-sentry-manager", - "version": "15.0.123", + "version": "15.0.124", "description": "Common setup for KeymanWeb's Sentry-based error reporting", "main": "dist/index.js", "scripts": { @@ -20,7 +20,7 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/web-environment": "^15.0.123", + "@keymanapp/web-environment": "^15.0.124", "@sentry/browser": "^5.27.4" } } diff --git a/common/core/web/utils/package-lock.json b/common/core/web/utils/package-lock.json index 5a065dbe6f..e6bd801152 100644 --- a/common/core/web/utils/package-lock.json +++ b/common/core/web/utils/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-utils", - "version": "15.0.123", + "version": "15.0.124", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/core/web/utils/package.json b/common/core/web/utils/package.json index 3b4b30b56b..d1dbe167de 100644 --- a/common/core/web/utils/package.json +++ b/common/core/web/utils/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-utils", - "version": "15.0.123", + "version": "15.0.124", "description": "Common utility functions used throughout other Keyman packages", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -20,8 +20,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.123", - "@keymanapp/web-environment": "^15.0.123", + "@keymanapp/resources-gosh": "^15.0.124", + "@keymanapp/web-environment": "^15.0.124", "@types/node": "^14.0.5", "typescript": "^3.8.3" } diff --git a/common/models/templates/package-lock.json b/common/models/templates/package-lock.json index 8582bbdc4c..5d0fa0670c 100644 --- a/common/models/templates/package-lock.json +++ b/common/models/templates/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-templates", - "version": "15.0.123", + "version": "15.0.124", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/models/templates/package.json b/common/models/templates/package.json index d7835fab44..94da18b688 100644 --- a/common/models/templates/package.json +++ b/common/models/templates/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-templates", - "version": "15.0.123", + "version": "15.0.124", "description": "Backing model implementations (templates) for Keyman's modelling layer", "keywords": [ "lm", @@ -42,8 +42,8 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/models-types": "^15.0.123", - "@keymanapp/web-utils": "^15.0.123", + "@keymanapp/models-types": "^15.0.124", + "@keymanapp/web-utils": "^15.0.124", "@types/chai": "^4.2.11", "@types/mocha": "^7.0.2", "@types/node": "^14.0.4", @@ -52,6 +52,6 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/models-wordbreakers": "^15.0.123" + "@keymanapp/models-wordbreakers": "^15.0.124" } } diff --git a/common/models/types/package-lock.json b/common/models/types/package-lock.json index 26e5808aa3..d1bb3374d4 100644 --- a/common/models/types/package-lock.json +++ b/common/models/types/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-types", - "version": "15.0.123", + "version": "15.0.124", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/common/models/types/package.json b/common/models/types/package.json index e68051ae66..703f43f83d 100644 --- a/common/models/types/package.json +++ b/common/models/types/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-types", - "version": "15.0.123", + "version": "15.0.124", "description": "Type definitions in used in the modeling (lexical model/predictive text) component of Keyman.", "types": "./index.d.ts", "scripts": { diff --git a/common/models/wordbreakers/package-lock.json b/common/models/wordbreakers/package-lock.json index d33efffe36..8cb6c98709 100644 --- a/common/models/wordbreakers/package-lock.json +++ b/common/models/wordbreakers/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-wordbreakers", - "version": "15.0.123", + "version": "15.0.124", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/models/wordbreakers/package.json b/common/models/wordbreakers/package.json index dcb4f01eda..7130127573 100644 --- a/common/models/wordbreakers/package.json +++ b/common/models/wordbreakers/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/models-wordbreakers", - "version": "15.0.123", + "version": "15.0.124", "description": "Word breakers bundled in the modeling layer", "keywords": [ "lexical model", @@ -40,7 +40,7 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/models-types": "^15.0.123", + "@keymanapp/models-types": "^15.0.124", "@types/chai": "^4.2.11", "@types/mocha": "^7.0.2", "chai": "^4.3.4", diff --git a/common/predictive-text/package-lock.json b/common/predictive-text/package-lock.json index a61c86dae8..d01ea25722 100644 --- a/common/predictive-text/package-lock.json +++ b/common/predictive-text/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-layer", - "version": "15.0.123", + "version": "15.0.124", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/common/predictive-text/package.json b/common/predictive-text/package.json index 30e4b41441..d42f85e2af 100644 --- a/common/predictive-text/package.json +++ b/common/predictive-text/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-layer", - "version": "15.0.123", + "version": "15.0.124", "description": "Keyman/Predictive Text integration layer", "main": "build/index.js", "scripts": { @@ -21,8 +21,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/models-types": "^15.0.123", - "@keymanapp/resources-gosh": "^15.0.123", + "@keymanapp/models-types": "^15.0.124", + "@keymanapp/resources-gosh": "^15.0.124", "@types/node": "^10.17.21", "chai": "^4.3.4", "karma": "^6.3.4", @@ -46,10 +46,10 @@ "typescript": "^3.8.3" }, "dependencies": { - "@keymanapp/models-templates": "^15.0.123", - "@keymanapp/models-wordbreakers": "^15.0.123", - "@keymanapp/web-environment": "^15.0.123", - "@keymanapp/web-utils": "^15.0.123", + "@keymanapp/models-templates": "^15.0.124", + "@keymanapp/models-wordbreakers": "^15.0.124", + "@keymanapp/web-environment": "^15.0.124", + "@keymanapp/web-utils": "^15.0.124", "es6-shim": "^0.35.5", "string.prototype.codepointat": "^0.2.1", "string.prototype.startswith": "^0.2.0" diff --git a/developer/js/package-lock.json b/developer/js/package-lock.json index f1594c515e..0bfd153446 100644 --- a/developer/js/package-lock.json +++ b/developer/js/package-lock.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-compiler", - "version": "15.0.123", + "version": "15.0.124", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/developer/js/package.json b/developer/js/package.json index 18f016add5..3b14ce5457 100644 --- a/developer/js/package.json +++ b/developer/js/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/lexical-model-compiler", - "version": "15.0.123", + "version": "15.0.124", "description": "Keyman Developer lexical model compiler", "keywords": [ "keyboard", @@ -37,14 +37,14 @@ "node": ">=12.0.0" }, "dependencies": { - "@keymanapp/models-types": "^15.0.123", + "@keymanapp/models-types": "^15.0.124", "commander": "^3.0.0", "typescript": "^3.8.3", "xml2js": "^0.4.19" }, "devDependencies": { - "@keymanapp/models-templates": "^15.0.123", - "@keymanapp/models-wordbreakers": "^15.0.123", + "@keymanapp/models-templates": "^15.0.124", + "@keymanapp/models-wordbreakers": "^15.0.124", "@types/chai": "^4.1.7", "@types/mocha": "^5.2.7", "@types/node": "^10.14.6", diff --git a/lerna.json b/lerna.json index 8be8cbc890..e062c20e3c 100644 --- a/lerna.json +++ b/lerna.json @@ -20,5 +20,5 @@ "ts-node", "typescript" ], - "version": "15.0.123" + "version": "15.0.124" } diff --git a/resources/gosh/package-lock.json b/resources/gosh/package-lock.json index 8d9f18f857..63518a6743 100644 --- a/resources/gosh/package-lock.json +++ b/resources/gosh/package-lock.json @@ -1,5 +1,5 @@ { "name": "@keymanapp/resources-gosh", - "version": "15.0.123", + "version": "15.0.124", "lockfileVersion": 1 } diff --git a/resources/gosh/package.json b/resources/gosh/package.json index d2a4fa73b8..1b32bb03e4 100644 --- a/resources/gosh/package.json +++ b/resources/gosh/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/resources-gosh", - "version": "15.0.123", + "version": "15.0.124", "description": "Good Ol' Shell", "author": "Marc Durdin (https://github.com/mcdurdin)", "contributors": [ diff --git a/resources/web-environment/package-lock.json b/resources/web-environment/package-lock.json index d1206bd7ac..f7d69dba86 100644 --- a/resources/web-environment/package-lock.json +++ b/resources/web-environment/package-lock.json @@ -1,5 +1,5 @@ { "name": "@keymanapp/web-environment", - "version": "15.0.123", + "version": "15.0.124", "lockfileVersion": 1 } diff --git a/resources/web-environment/package.json b/resources/web-environment/package.json index d32be55779..a866727f55 100644 --- a/resources/web-environment/package.json +++ b/resources/web-environment/package.json @@ -1,6 +1,6 @@ { "name": "@keymanapp/web-environment", - "version": "15.0.123", + "version": "15.0.124", "description": "A compilation utility for passing select environment variables into our TS builds", "author": "Joshua Horton (https://github.com/jahorton)", "homepage": "https://github.com/keymanapp/keyman", @@ -17,6 +17,6 @@ "url": "https://github.com/keymanapp/keyman/issues" }, "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.123" + "@keymanapp/resources-gosh": "^15.0.124" } } diff --git a/web/package-lock.json b/web/package-lock.json index f747c057ce..957989ef76 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,6 +1,6 @@ { "name": "keyman", - "version": "15.0.123", + "version": "15.0.124", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/web/package.json b/web/package.json index f05d83b00a..d02db532eb 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "keyman", - "version": "15.0.123", + "version": "15.0.124", "description": "Facilitates text input in any language.", "repository": { "type": "git", @@ -18,8 +18,8 @@ }, "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { - "@keymanapp/resources-gosh": "^15.0.123", - "@keymanapp/web-sentry-manager": "^15.0.123", + "@keymanapp/resources-gosh": "^15.0.124", + "@keymanapp/web-sentry-manager": "^15.0.124", "@sentry/cli": "^1.52.3", "chai": "^4.3.4", "google-closure-compiler-java": "^20200224.0.0", @@ -52,13 +52,13 @@ "sentry-cli": "sentry-cli" }, "dependencies": { - "@keymanapp/input-processor": "^15.0.123", - "@keymanapp/keyboard-processor": "^15.0.123", - "@keymanapp/lexical-model-layer": "^15.0.123", - "@keymanapp/models-types": "^15.0.123", - "@keymanapp/recorder-core": "^15.0.123", - "@keymanapp/web-environment": "^15.0.123", - "@keymanapp/web-utils": "^15.0.123", + "@keymanapp/input-processor": "^15.0.124", + "@keymanapp/keyboard-processor": "^15.0.124", + "@keymanapp/lexical-model-layer": "^15.0.124", + "@keymanapp/models-types": "^15.0.124", + "@keymanapp/recorder-core": "^15.0.124", + "@keymanapp/web-environment": "^15.0.124", + "@keymanapp/web-utils": "^15.0.124", "@types/node": "^11.9.4", "es6-shim": "^0.35.5", "eventemitter3": "^4.0.0"