From fb2a246f530de839bc40dcca7cd57566b635bfaf Mon Sep 17 00:00:00 2001 From: Ross Date: Tue, 13 Jul 2021 16:59:40 +1000 Subject: [PATCH] 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