From 1016052ccff4f03b66efe5a67ee936d2f8fcbe86 Mon Sep 17 00:00:00 2001 From: fanlumaster <1730976608@qq.com> Date: Sun, 22 Jun 2025 23:21:50 +0800 Subject: [PATCH] [dev]: Refactor punctuation logic --- .../CompositionProcessorEngine.cpp | 28 +- src/Composition/CompositionProcessorEngine.h | 13 +- src/Global/Globals.cpp | 44 +- src/Global/Globals.h | 2 +- src/IME/MetasequoiaIMEBaseStructure.cpp | 61 +- src/IME/MetasequoiaIMEBaseStructure.h | 20 +- src/Key/KeyEventSink.cpp | 1081 +++++++++-------- src/Key/KeyHandler.cpp | 33 +- 8 files changed, 667 insertions(+), 615 deletions(-) diff --git a/src/Composition/CompositionProcessorEngine.cpp b/src/Composition/CompositionProcessorEngine.cpp index 353a0527..bc9c1d66 100644 --- a/src/Composition/CompositionProcessorEngine.cpp +++ b/src/Composition/CompositionProcessorEngine.cpp @@ -1,5 +1,6 @@ #ifndef UNICODE #define UNICODE +#include #endif #include "Private.h" @@ -615,7 +616,7 @@ BOOL CCompositionProcessorEngine::IsPunctuation(WCHAR wch) // //---------------------------------------------------------------------------- -WCHAR CCompositionProcessorEngine::GetPunctuation(WCHAR wch) +const WCHAR *CCompositionProcessorEngine::GetPunctuation(WCHAR wch) { for (int i = 0; i < ARRAYSIZE(Global::PunctuationTable); i++) { @@ -1167,9 +1168,9 @@ void CCompositionProcessorEngine::SetupPunctuationPair() // Punctuation pair const int pair_count = 2; // Left quotation mark and right quotation mark “” - CPunctuationPair punc_quotation_mark(L'"', 0x201C, 0x201D); + CPunctuationPair punc_quotation_mark(L'"', L"“", L"”"); // Left single quotation mark and right single quotation mark ‘’ - CPunctuationPair punc_apostrophe(L'\'', 0x2018, 0x2019); + CPunctuationPair punc_apostrophe(L'\'', L"‘", L"’"); CPunctuationPair puncPairs[pair_count] = { punc_quotation_mark, @@ -1183,7 +1184,7 @@ void CCompositionProcessorEngine::SetupPunctuationPair() } // Punctuation nest pair - CPunctuationNestPair punc_angle_bracket(L'<', 0x300A, 0x3008, L'>', 0x300B, 0x3009); + CPunctuationNestPair punc_angle_bracket(L'<', L"《", L"〈", L'>', L"》", L"〉"); CPunctuationNestPair *pPuncNestPair = _PunctuationNestPair.Append(); *pPuncNestPair = punc_angle_bracket; @@ -1678,9 +1679,14 @@ void CCompositionProcessorEngine::SetDefaultCandidateTextFont() // If engine need this virtual key code, returns true. Otherwise returns false. //---------------------------------------------------------------------------- -BOOL CCompositionProcessorEngine::IsVirtualKeyNeed(UINT uCode, _In_reads_(1) WCHAR *pwch, BOOL fComposing, - CANDIDATE_MODE candidateMode, BOOL hasCandidateWithWildcard, - _Out_opt_ _KEYSTROKE_STATE *pKeyState) +BOOL CCompositionProcessorEngine::IsVirtualKeyNeed( // + UINT uCode, // + _In_reads_(1) WCHAR *pwch, // + BOOL fComposing, // + CANDIDATE_MODE candidateMode, // + BOOL hasCandidateWithWildcard, // + _Out_opt_ _KEYSTROKE_STATE *pKeyState // +) { if (pKeyState) { @@ -2303,6 +2309,7 @@ BOOL CCompositionProcessorEngine::IsVirtualKeyNeed(UINT uCode, _In_reads_(1) WCH if (*pwch && !IsVirtualKeyKeystrokeComposition(uCode, pKeyState, FUNCTION_NONE)) { + OutputDebugString(L"Will commit original keystroke string."); if (pKeyState) { pKeyState->Category = CATEGORY_INVOKE_COMPOSITION_EDIT_SESSION; @@ -2323,8 +2330,11 @@ BOOL CCompositionProcessorEngine::IsVirtualKeyNeed(UINT uCode, _In_reads_(1) WCH // //---------------------------------------------------------------------------- -BOOL CCompositionProcessorEngine::IsVirtualKeyKeystrokeComposition(UINT uCode, _Out_opt_ _KEYSTROKE_STATE *pKeyState, - KEYSTROKE_FUNCTION function) +BOOL CCompositionProcessorEngine::IsVirtualKeyKeystrokeComposition( // + UINT uCode, // + _Out_opt_ _KEYSTROKE_STATE *pKeyState, // + KEYSTROKE_FUNCTION function // +) { #ifdef FANY_DEBUG OutputDebugString(L"Fany Here: IsVirtualKeyKeystrokeComposition 26."); diff --git a/src/Composition/CompositionProcessorEngine.h b/src/Composition/CompositionProcessorEngine.h index a9a8a911..b959995f 100644 --- a/src/Composition/CompositionProcessorEngine.h +++ b/src/Composition/CompositionProcessorEngine.h @@ -49,9 +49,14 @@ class CCompositionProcessorEngine }; WCHAR GetVirtualKey(DWORD_PTR dwIndex); - void GetReadingStrings(_Inout_ CMetasequoiaImeArray *pReadingStrings, _Out_ BOOL *pIsWildcardIncluded); - void GetCandidateList(_Inout_ CMetasequoiaImeArray *pCandidateList, BOOL isIncrementalWordSearch, - BOOL isWildcardSearch); + void GetReadingStrings( // + _Inout_ CMetasequoiaImeArray *pReadingStrings, // + _Out_ BOOL *pIsWildcardIncluded // + ); + void GetCandidateList( // + _Inout_ CMetasequoiaImeArray *pCandidateList, // + BOOL isIncrementalWordSearch, BOOL isWildcardSearch // + ); void GetCandidateStringInConverted(CStringRange &searchString, _In_ CMetasequoiaImeArray *pCandidateList); @@ -64,7 +69,7 @@ class CCompositionProcessorEngine // Punctuation BOOL IsPunctuation(WCHAR wch); - WCHAR GetPunctuation(WCHAR wch); + const WCHAR *GetPunctuation(WCHAR wch); BOOL IsDoubleSingleByte(WCHAR wch); BOOL IsWildcard() diff --git a/src/Global/Globals.cpp b/src/Global/Globals.cpp index 48c65c57..2f726786 100644 --- a/src/Global/Globals.cpp +++ b/src/Global/Globals.cpp @@ -260,26 +260,30 @@ extern const WCHAR FullWidthCharTable[] = { //--------------------------------------------------------------------- // defined punctuation characters //--------------------------------------------------------------------- -extern const struct _PUNCTUATION PunctuationTable[19] = { - {L'!', 0xFF01}, // ! - {L'$', 0xFFE5}, // ¥ - {L'&', L'&'}, // & - {L'(', 0xFF08}, // ( - {L')', 0xFF09}, // ) - {L',', 0xFF0C}, // , - {L'.', 0x3002}, // 。 - {L':', 0xFF1A}, // : - {L';', 0xFF1B}, // ; - {L'?', 0xFF1F}, // ? - {L'@', L'@'}, // @ - {L'\\', 0x3001}, // 、 - {L'^', 0x2026}, // …… - {L'_', 0x2014}, // —— - {L'<', L'《'}, // 《 - {L'>', L'》'}, // 》 - {L'`', L'·'}, // · - {L'[', L'【'}, // 【 - {L']', L'】'} // 】 +extern const struct _PUNCTUATION PunctuationTable[24] = { + {L'`', L"·"}, // · + {L'~', L"~"}, // ~ + {L'!', L"!"}, // ! + {L'@', L"@"}, // @ + {L'#', L"#"}, // # + {L'$', L"¥"}, // ¥ + {L'%', L"%"}, // % + {L'^', L"……"}, // …… + {L'&', L"&"}, // & + {L'*', L"*"}, // * + {L'(', L"("}, // ( + {L')', L")"}, // ) + {L'_', L"——"}, // —— + {L'[', L"【"}, // 【 + {L']', L"】"}, // 】 + {L'\\', L"、"}, // 、 + {L';', L";"}, // ; + {L':', L":"}, // : + {L',', L","}, // , + {L'<', L"《"}, // 《 + {L'.', L"。"}, // 。 + {L'>', L"》"}, // 》 + {L'?', L"?"}, // ? }; //+--------------------------------------------------------------------------- diff --git a/src/Global/Globals.h b/src/Global/Globals.h index 427216eb..c2e04714 100644 --- a/src/Global/Globals.h +++ b/src/Global/Globals.h @@ -133,7 +133,7 @@ extern const GUID MetasequoiaIMEGuidCompartmentDoubleSingleByte; extern const GUID MetasequoiaIMEGuidCompartmentPunctuation; extern const WCHAR FullWidthCharTable[]; -extern const struct _PUNCTUATION PunctuationTable[19]; +extern const struct _PUNCTUATION PunctuationTable[24]; extern const GUID MetasequoiaIMEGuidLangBarIMEMode; extern const GUID MetasequoiaIMEGuidLangBarDoubleSingleByte; diff --git a/src/IME/MetasequoiaIMEBaseStructure.cpp b/src/IME/MetasequoiaIMEBaseStructure.cpp index 6f6b9ed0..ee9ed32f 100644 --- a/src/IME/MetasequoiaIMEBaseStructure.cpp +++ b/src/IME/MetasequoiaIMEBaseStructure.cpp @@ -292,44 +292,75 @@ int CCandidateRange::GetIndex(UINT vKey) CPunctuationPair::CPunctuationPair() { _punctuation._Code = 0; - _punctuation._Punctuation = 0; - _pairPunctuation = 0; + _punctuation._Punctuation[0] = 0; + _pairPunctuation[0] = 0; _isPairToggle = FALSE; } -CPunctuationPair::CPunctuationPair(WCHAR code, WCHAR punctuation, WCHAR pair) +CPunctuationPair::CPunctuationPair( // + WCHAR code, // + const WCHAR *punctuation, // + const WCHAR *pair // +) { _punctuation._Code = code; - _punctuation._Punctuation = punctuation; - _pairPunctuation = pair; + + wcsncpy_s(_punctuation._Punctuation, _countof(_punctuation._Punctuation), punctuation, _TRUNCATE); + wcsncpy_s(_pairPunctuation, _countof(_pairPunctuation), pair, _TRUNCATE); _isPairToggle = FALSE; } CPunctuationNestPair::CPunctuationNestPair() { _punctuation_begin._Code = 0; - _punctuation_begin._Punctuation = 0; - _pairPunctuation_begin = 0; + _punctuation_begin._Punctuation[0] = 0; + _pairPunctuation_begin[0] = 0; _punctuation_end._Code = 0; - _punctuation_end._Punctuation = 0; - _pairPunctuation_end = 0; + _punctuation_end._Punctuation[0] = 0; + _pairPunctuation_end[0] = 0; _nestCount = 0; } -CPunctuationNestPair::CPunctuationNestPair(WCHAR codeBegin, WCHAR punctuationBegin, WCHAR pairBegin, WCHAR codeEnd, - WCHAR punctuationEnd, WCHAR pairEnd) +CPunctuationNestPair::CPunctuationNestPair( // + WCHAR codeBegin, // + const WCHAR *punctuationBegin, // + const WCHAR *pairBegin, // + const WCHAR codeEnd, // + const WCHAR *punctuationEnd, // + const WCHAR *pairEnd // +) { pairEnd; punctuationEnd; _punctuation_begin._Code = codeBegin; - _punctuation_begin._Punctuation = punctuationBegin; - _pairPunctuation_begin = pairBegin; + wcsncpy_s( // + _punctuation_begin._Punctuation, // + _countof(_punctuation_begin._Punctuation), // + punctuationBegin, // + _TRUNCATE // + ); + wcsncpy_s( // + _pairPunctuation_begin, // + _countof(_pairPunctuation_begin), // + pairBegin, // + _TRUNCATE // + ); _punctuation_end._Code = codeEnd; - _punctuation_end._Punctuation = punctuationBegin; - _pairPunctuation_end = pairBegin; + wcsncpy_s( // + _punctuation_end._Punctuation, // + _countof(_punctuation_end._Punctuation), // + punctuationEnd, // + _TRUNCATE // + ); + wcsncpy_s( // + _pairPunctuation_end, // + _countof(_pairPunctuation_end), // + pairEnd, // + _TRUNCATE // + ); _nestCount = 0; } diff --git a/src/IME/MetasequoiaIMEBaseStructure.h b/src/IME/MetasequoiaIMEBaseStructure.h index c5045bbd..b2ed77e0 100644 --- a/src/IME/MetasequoiaIMEBaseStructure.h +++ b/src/IME/MetasequoiaIMEBaseStructure.h @@ -86,7 +86,7 @@ struct _KEYSTROKE_STATE struct _PUNCTUATION { WCHAR _Code; - WCHAR _Punctuation; + WCHAR _Punctuation[3]; }; BOOL CLSIDToString(REFGUID refGUID, _Out_writes_(39) WCHAR *pCLSIDString); @@ -241,10 +241,10 @@ class CPunctuationPair { public: CPunctuationPair(); - CPunctuationPair(WCHAR code, WCHAR punctuation, WCHAR pair); + CPunctuationPair(WCHAR code, const WCHAR *punctuation, const WCHAR *pair); struct _PUNCTUATION _punctuation; - WCHAR _pairPunctuation; + WCHAR _pairPunctuation[3]; BOOL _isPairToggle; }; @@ -252,14 +252,20 @@ class CPunctuationNestPair { public: CPunctuationNestPair(); - CPunctuationNestPair(WCHAR wchCode_begin, WCHAR wch_begin, WCHAR wchPair_begin, WCHAR wchCode_end, WCHAR wch_end, - WCHAR wchPair_end); + CPunctuationNestPair( // + WCHAR codeBegin, // + const WCHAR *punctuationBegin, // + const WCHAR *pairBegin, // + const WCHAR codeEnd, // + const WCHAR *punctuationEnd, // + const WCHAR *pairEnd // + ); struct _PUNCTUATION _punctuation_begin; - WCHAR _pairPunctuation_begin; + WCHAR _pairPunctuation_begin[3]; struct _PUNCTUATION _punctuation_end; - WCHAR _pairPunctuation_end; + WCHAR _pairPunctuation_end[3]; int _nestCount; }; diff --git a/src/Key/KeyEventSink.cpp b/src/Key/KeyEventSink.cpp index 9bb4a91d..c08b71c2 100644 --- a/src/Key/KeyEventSink.cpp +++ b/src/Key/KeyEventSink.cpp @@ -1,535 +1,546 @@ -#include "Private.h" -#include "Globals.h" -#include "MetasequoiaIME.h" -#include "CandidateListUIPresenter.h" -#include "CompositionProcessorEngine.h" -#include "KeyHandlerEditSession.h" -#include "Compartment.h" -#include "MetasequoiaIMEBaseStructure.h" -#include "fmt/xchar.h" -#include -#include -#include "Ipc.h" -#include "FanyUtils.h" - -// 0xF003, 0xF004 are the keys that the touch keyboard sends for next/previous -#define THIRDPARTY_NEXTPAGE static_cast(0xF003) -#define THIRDPARTY_PREVPAGE static_cast(0xF004) - -// Because the code mostly works with VKeys, here map a WCHAR back to a VKKey for certain -// vkeys that the IME handles specially -__inline UINT VKeyFromVKPacketAndWchar(UINT vk, WCHAR wch) -{ - UINT vkRet = vk; - if (LOWORD(vk) == VK_PACKET) - { - if (wch == L' ') - { - vkRet = VK_SPACE; - } - else if ((wch >= L'0') && (wch <= L'9')) - { - vkRet = static_cast(wch); - } - else if ((wch >= L'a') && (wch <= L'z')) - { - vkRet = (UINT)(L'A') + ((UINT)(L'z') - static_cast(wch)); - } - else if ((wch >= L'A') && (wch <= L'Z')) - { - vkRet = static_cast(wch); - } - else if (wch == THIRDPARTY_NEXTPAGE) - { - vkRet = VK_NEXT; - } - else if (wch == THIRDPARTY_PREVPAGE) - { - vkRet = VK_PRIOR; - } - } - return vkRet; -} - -//+--------------------------------------------------------------------------- -// -// _IsKeyEaten -// -//---------------------------------------------------------------------------- - -BOOL CMetasequoiaIME::_IsKeyEaten(_In_ ITfContext *pContext, UINT codeIn, _Out_ UINT *pCodeOut, _Out_writes_(1) WCHAR *pwch, - _Out_opt_ _KEYSTROKE_STATE *pKeyState) -{ - pContext; - - *pCodeOut = codeIn; - - BOOL isOpen = FALSE; - CCompartment CompartmentKeyboardOpen(_pThreadMgr, _tfClientId, GUID_COMPARTMENT_KEYBOARD_OPENCLOSE); - CompartmentKeyboardOpen._GetCompartmentBOOL(isOpen); - - BOOL isDoubleSingleByte = FALSE; - CCompartment CompartmentDoubleSingleByte(_pThreadMgr, _tfClientId, - Global::MetasequoiaIMEGuidCompartmentDoubleSingleByte); - CompartmentDoubleSingleByte._GetCompartmentBOOL(isDoubleSingleByte); - - BOOL isPunctuation = FALSE; - CCompartment CompartmentPunctuation(_pThreadMgr, _tfClientId, Global::MetasequoiaIMEGuidCompartmentPunctuation); - CompartmentPunctuation._GetCompartmentBOOL(isPunctuation); - - if (pKeyState) - { - pKeyState->Category = CATEGORY_NONE; - pKeyState->Function = FUNCTION_NONE; - } - if (pwch) - { - *pwch = L'\0'; - } - - // If the keyboard is disabled(means IME is English mode), we don't eat keys. - if (_IsKeyboardDisabled()) - { - return FALSE; - } - - // - // Map virtual key to character code - // - BOOL isTouchKeyboardSpecialKeys = FALSE; - WCHAR wch = ConvertVKey(codeIn); - *pCodeOut = VKeyFromVKPacketAndWchar(codeIn, wch); -#ifdef FANY_DEBUG - std::wstring msg = fmt::format(L"fany iseat: codeIn: {}, wch: {}, *pCodeOut: {}", codeIn, wch, *pCodeOut); - OutputDebugString(msg.c_str()); -#endif - if ((wch == THIRDPARTY_NEXTPAGE) || (wch == THIRDPARTY_PREVPAGE)) - { - // We always eat the above softkeyboard special keys - isTouchKeyboardSpecialKeys = TRUE; - if (pwch) - { - *pwch = wch; - } - } - - // if the keyboard is closed, we don't eat keys, with the exception of the touch keyboard specials keys - if (!isOpen && !isDoubleSingleByte && !isPunctuation) - { - return isTouchKeyboardSpecialKeys; - } - - if (pwch) - { - *pwch = wch; - } - - // - // Get composition engine - // - CCompositionProcessorEngine *pCompositionProcessorEngine; - pCompositionProcessorEngine = _pCompositionProcessorEngine; - - if (isOpen) // Chinese mode - { - // - // The candidate or phrase list handles the keys through ITfKeyEventSink. - // - // eat only keys that CKeyHandlerEditSession can handles. - // - if (pCompositionProcessorEngine->IsVirtualKeyNeed(*pCodeOut, pwch, _IsComposing(), _candidateMode, - _isCandidateWithWildcard, pKeyState)) - { - return TRUE; - } - } - - // - // Punctuation - // - if (pCompositionProcessorEngine->IsPunctuation(wch)) - { - if ((_candidateMode == CANDIDATE_NONE) && isPunctuation) - { - if (pKeyState) - { - pKeyState->Category = CATEGORY_COMPOSING; - pKeyState->Function = FUNCTION_PUNCTUATION; - } - return TRUE; - } - } - - // - // Double/Single byte - // - if (isDoubleSingleByte && pCompositionProcessorEngine->IsDoubleSingleByte(wch)) - { - if (_candidateMode == CANDIDATE_NONE) - { - if (pKeyState) - { - pKeyState->Category = CATEGORY_COMPOSING; - pKeyState->Function = FUNCTION_DOUBLE_SINGLE_BYTE; - } - return TRUE; - } - } - - return isTouchKeyboardSpecialKeys; -} - -//+--------------------------------------------------------------------------- -// -// ConvertVKey -// -//---------------------------------------------------------------------------- - -WCHAR CMetasequoiaIME::ConvertVKey(UINT code) -{ - // - // Map virtual key to scan code - // - UINT scanCode = 0; - scanCode = MapVirtualKey(code, 0); - - // - // Keyboard state - // - BYTE abKbdState[256] = {'\0'}; - if (!GetKeyboardState(abKbdState)) - { - return 0; - } - - // - // Map virtual key to character code - // - WCHAR wch = '\0'; - if (ToUnicode(code, scanCode, abKbdState, &wch, 1, 0) == 1) - { - return wch; - } - - return 0; -} - -//+--------------------------------------------------------------------------- -// -// _IsKeyboardDisabled -// -//---------------------------------------------------------------------------- - -BOOL CMetasequoiaIME::_IsKeyboardDisabled() -{ - ITfDocumentMgr *pDocMgrFocus = nullptr; - ITfContext *pContext = nullptr; - BOOL isDisabled = FALSE; - - if ((_pThreadMgr->GetFocus(&pDocMgrFocus) != S_OK) || (pDocMgrFocus == nullptr)) - { - // if there is no focus document manager object, the keyboard - // is disabled. - isDisabled = TRUE; - } - else if ((pDocMgrFocus->GetTop(&pContext) != S_OK) || (pContext == nullptr)) - { - // if there is no context object, the keyboard is disabled. - isDisabled = TRUE; - } - else - { - CCompartment CompartmentKeyboardDisabled(_pThreadMgr, _tfClientId, GUID_COMPARTMENT_KEYBOARD_DISABLED); - CompartmentKeyboardDisabled._GetCompartmentBOOL(isDisabled); - - CCompartment CompartmentEmptyContext(_pThreadMgr, _tfClientId, GUID_COMPARTMENT_EMPTYCONTEXT); - CompartmentEmptyContext._GetCompartmentBOOL(isDisabled); - } - - if (pContext) - { - pContext->Release(); - } - - if (pDocMgrFocus) - { - pDocMgrFocus->Release(); - } - - return isDisabled; -} - -//+--------------------------------------------------------------------------- -// -// ITfKeyEventSink::OnSetFocus -// -// Called by the system whenever this service gets the keystroke device focus. -//---------------------------------------------------------------------------- - -STDAPI CMetasequoiaIME::OnSetFocus(BOOL fForeground) -{ - fForeground; - - return S_OK; -} - -//+--------------------------------------------------------------------------- -// -// ITfKeyEventSink::OnTestKeyDown -// -// Called by the system to query this service wants a potential keystroke. -//---------------------------------------------------------------------------- - -STDAPI CMetasequoiaIME::OnTestKeyDown(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pIsEaten) -{ - Global::UpdateModifiers(wParam, lParam); - - _KEYSTROKE_STATE KeystrokeState; - WCHAR wch = '\0'; - UINT code = 0; - *pIsEaten = _IsKeyEaten(pContext, (UINT)wParam, &code, &wch, &KeystrokeState); - - if (KeystrokeState.Category == CATEGORY_INVOKE_COMPOSITION_EDIT_SESSION) - { - // - // Invoke key handler edit session - // - KeystrokeState.Category = CATEGORY_COMPOSING; - - _InvokeKeyHandler(pContext, code, wch, (DWORD)lParam, KeystrokeState); - } - - return S_OK; -} - -//+--------------------------------------------------------------------------- -// -// ITfKeyEventSink::OnKeyDown -// -// Called by the system to offer this service a keystroke. -// on exit, the application will not handle the keystroke. -//---------------------------------------------------------------------------- - -STDAPI CMetasequoiaIME::OnKeyDown(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pIsEaten) -{ - Global::UpdateModifiers(wParam, lParam); - - _KEYSTROKE_STATE KeystrokeState; - WCHAR wch = '\0'; - UINT code = 0; - - *pIsEaten = _IsKeyEaten(pContext, (UINT)wParam, &code, &wch, &KeystrokeState); - if (*pIsEaten) - { - Global::Keycode = code; - if ((GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0) - Global::ModifiersDown |= 0b00000001; - else - Global::ModifiersDown &= ~0b00000001; - WriteDataToSharedMemory(Global::Keycode, Global::ModifiersDown, nullptr, 0, L"", 0b00011); - SendKeyEventToUIProcess(); - } - Global::firefox_like_cnt = 0; -#ifdef FANY_DEBUG - if (Global::Keycode == VK_TAB) - { - OutputDebugString(L"Tab key pressed."); - OutputDebugString(fmt::format(L"eat: {}", *pIsEaten).c_str()); - } -#endif - -#ifdef FANY_DEBUG - std::wstring msg = L"Whether to eat it?" + std::to_wstring(*pIsEaten); - // TODO: Log msg -#endif - - if (*pIsEaten) - { -#ifdef FANY_DEBUG - OutputDebugString(L"Yes, eat it."); -#endif - bool needInvokeKeyHandler = true; - // - // Invoke key handler edit session - // - if (code == VK_ESCAPE) - { - KeystrokeState.Category = CATEGORY_COMPOSING; - } - - // Always eat THIRDPARTY_NEXTPAGE and THIRDPARTY_PREVPAGE keys, but don't always process them. - if ((wch == THIRDPARTY_NEXTPAGE) || (wch == THIRDPARTY_PREVPAGE)) - { - needInvokeKeyHandler = - !((KeystrokeState.Category == CATEGORY_NONE) && (KeystrokeState.Function == FUNCTION_NONE)); - } - - if (needInvokeKeyHandler) - { - TF_STATUS tfStatus; - if (SUCCEEDED(pContext->GetStatus(&tfStatus))) - { - if (tfStatus.dwDynamicFlags & TF_SD_READONLY) - { - std::wstring str = std::wstring(1, wch); - FanyUtils::SendKeys(str); -#ifdef FANY_DEBUG - OutputDebugString(L"pContext is read-only"); -#endif - } - else - { -#ifdef FANY_DEBUG - OutputDebugString(L"pContext is editable"); -#endif - } - } - - _InvokeKeyHandler(pContext, code, wch, (DWORD)lParam, KeystrokeState); - } - } - else if (KeystrokeState.Category == CATEGORY_INVOKE_COMPOSITION_EDIT_SESSION) - { - // Invoke key handler edit session - KeystrokeState.Category = CATEGORY_COMPOSING; - _InvokeKeyHandler(pContext, code, wch, (DWORD)lParam, KeystrokeState); - } - - return S_OK; -} - -//+--------------------------------------------------------------------------- -// -// ITfKeyEventSink::OnTestKeyUp -// -// Called by the system to query this service wants a potential keystroke. -//---------------------------------------------------------------------------- - -STDAPI CMetasequoiaIME::OnTestKeyUp(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pIsEaten) -{ - if (pIsEaten == nullptr) - { - return E_INVALIDARG; - } - - Global::UpdateModifiers(wParam, lParam); - - WCHAR wch = '\0'; - UINT code = 0; - - *pIsEaten = _IsKeyEaten(pContext, (UINT)wParam, &code, &wch, NULL); - - return S_OK; -} - -//+--------------------------------------------------------------------------- -// -// ITfKeyEventSink::OnKeyUp -// -// Called by the system to offer this service a keystroke. If *pIsEaten == TRUE -// on exit, the application will not handle the keystroke. -//---------------------------------------------------------------------------- - -STDAPI CMetasequoiaIME::OnKeyUp(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pIsEaten) -{ - Global::UpdateModifiers(wParam, lParam); - - _KEYSTROKE_STATE KeystrokeState; - WCHAR wch = '\0'; - UINT code = 0; - *pIsEaten = _IsKeyEaten(pContext, (UINT)wParam, &code, &wch, &KeystrokeState); - -#ifdef FANY_DEBUG - OutputDebugString(L"fanyfull ITfKeyEventSink::OnKeyUp"); - OutputDebugString(fmt::format(L"Global::PureShiftKeyUp: {}", Global::PureShiftKeyUp).c_str()); -#endif - - // if (code == VK_SHIFT) - // { - // if (Global::PureShiftKeyUp) - // { - // KeystrokeState.Category = CATEGORY_COMPOSING; - // KeystrokeState.Function = FUNCTION_TOGGLE_IME_MODE; - // _InvokeKeyHandler(pContext, code, wch, (DWORD)lParam, KeystrokeState); - // } - // } - - return S_OK; -} - -//+--------------------------------------------------------------------------- -// -// ITfKeyEventSink::OnPreservedKey -// -// Called when a hotkey (registered by us, or by the system) is typed. -//---------------------------------------------------------------------------- - -STDAPI CMetasequoiaIME::OnPreservedKey(ITfContext *pContext, REFGUID rguid, BOOL *pIsEaten) -{ - pContext; - - CCompositionProcessorEngine *pCompositionProcessorEngine; - pCompositionProcessorEngine = _pCompositionProcessorEngine; - - BOOL pNeedToggleIMEMode = FALSE; - - pCompositionProcessorEngine->OnPreservedKey(pContext, rguid, pIsEaten, _GetThreadMgr(), _GetClientId(), - &pNeedToggleIMEMode); - - if (pNeedToggleIMEMode) - { - _KEYSTROKE_STATE KeystrokeState; - WCHAR wch = '\0'; - UINT code = 0; - KeystrokeState.Category = CATEGORY_COMPOSING; - KeystrokeState.Function = FUNCTION_TOGGLE_IME_MODE; - _InvokeKeyHandler(pContext, code, wch, (DWORD)0, KeystrokeState); - } - - return S_OK; -} - -//+--------------------------------------------------------------------------- -// -// _InitKeyEventSink -// -// Advise a keystroke sink. -//---------------------------------------------------------------------------- - -BOOL CMetasequoiaIME::_InitKeyEventSink() -{ - ITfKeystrokeMgr *pKeystrokeMgr = nullptr; - HRESULT hr = S_OK; - - if (FAILED(_pThreadMgr->QueryInterface(IID_ITfKeystrokeMgr, (void **)&pKeystrokeMgr))) - { - return FALSE; - } - - hr = pKeystrokeMgr->AdviseKeyEventSink(_tfClientId, (ITfKeyEventSink *)this, TRUE); - - pKeystrokeMgr->Release(); - - return (hr == S_OK); -} - -//+--------------------------------------------------------------------------- -// -// _UninitKeyEventSink -// -// Unadvise a keystroke sink. Assumes we have advised one already. -//---------------------------------------------------------------------------- - -void CMetasequoiaIME::_UninitKeyEventSink() -{ - ITfKeystrokeMgr *pKeystrokeMgr = nullptr; - - if (FAILED(_pThreadMgr->QueryInterface(IID_ITfKeystrokeMgr, (void **)&pKeystrokeMgr))) - { - return; - } - - pKeystrokeMgr->UnadviseKeyEventSink(_tfClientId); - - pKeystrokeMgr->Release(); -} +#include "Private.h" +#include "Globals.h" +#include "MetasequoiaIME.h" +#include "CandidateListUIPresenter.h" +#include "CompositionProcessorEngine.h" +#include "KeyHandlerEditSession.h" +#include "Compartment.h" +#include "MetasequoiaIMEBaseStructure.h" +#include "fmt/xchar.h" +#include +#include +#include "Ipc.h" +#include "FanyUtils.h" + +// 0xF003, 0xF004 are the keys that the touch keyboard sends for next/previous +#define THIRDPARTY_NEXTPAGE static_cast(0xF003) +#define THIRDPARTY_PREVPAGE static_cast(0xF004) + +// Because the code mostly works with VKeys, here map a WCHAR back to a VKKey for certain +// vkeys that the IME handles specially +__inline UINT VKeyFromVKPacketAndWchar(UINT vk, WCHAR wch) +{ + UINT vkRet = vk; + if (LOWORD(vk) == VK_PACKET) + { + if (wch == L' ') + { + vkRet = VK_SPACE; + } + else if ((wch >= L'0') && (wch <= L'9')) + { + vkRet = static_cast(wch); + } + else if ((wch >= L'a') && (wch <= L'z')) + { + vkRet = (UINT)(L'A') + ((UINT)(L'z') - static_cast(wch)); + } + else if ((wch >= L'A') && (wch <= L'Z')) + { + vkRet = static_cast(wch); + } + else if (wch == THIRDPARTY_NEXTPAGE) + { + vkRet = VK_NEXT; + } + else if (wch == THIRDPARTY_PREVPAGE) + { + vkRet = VK_PRIOR; + } + } + return vkRet; +} + +//+--------------------------------------------------------------------------- +// +// _IsKeyEaten +// +//---------------------------------------------------------------------------- + +BOOL CMetasequoiaIME::_IsKeyEaten( // + _In_ ITfContext *pContext, // + UINT codeIn, // + _Out_ UINT *pCodeOut, // + _Out_writes_(1) WCHAR *pwch, // + _Out_opt_ _KEYSTROKE_STATE *pKeyState // +) +{ + pContext; + + *pCodeOut = codeIn; + + BOOL isOpen = FALSE; + CCompartment CompartmentKeyboardOpen(_pThreadMgr, _tfClientId, GUID_COMPARTMENT_KEYBOARD_OPENCLOSE); + CompartmentKeyboardOpen._GetCompartmentBOOL(isOpen); + + BOOL isDoubleSingleByte = FALSE; + CCompartment CompartmentDoubleSingleByte(_pThreadMgr, _tfClientId, + Global::MetasequoiaIMEGuidCompartmentDoubleSingleByte); + CompartmentDoubleSingleByte._GetCompartmentBOOL(isDoubleSingleByte); + + BOOL isPunctuation = FALSE; + CCompartment CompartmentPunctuation(_pThreadMgr, _tfClientId, Global::MetasequoiaIMEGuidCompartmentPunctuation); + CompartmentPunctuation._GetCompartmentBOOL(isPunctuation); + + if (pKeyState) + { + pKeyState->Category = CATEGORY_NONE; + pKeyState->Function = FUNCTION_NONE; + } + if (pwch) + { + *pwch = L'\0'; + } + + // If the keyboard is disabled(means IME is English mode), we don't eat keys. + if (_IsKeyboardDisabled()) + { + return FALSE; + } + + // + // Map virtual key to character code + // + BOOL isTouchKeyboardSpecialKeys = FALSE; + WCHAR wch = ConvertVKey(codeIn); + *pCodeOut = VKeyFromVKPacketAndWchar(codeIn, wch); + if ((wch == THIRDPARTY_NEXTPAGE) || (wch == THIRDPARTY_PREVPAGE)) + { + // We always eat the above softkeyboard special keys + isTouchKeyboardSpecialKeys = TRUE; + if (pwch) + { + *pwch = wch; + } + } + + // if the keyboard is closed, we don't eat keys, with the exception of the touch keyboard specials keys + if (!isOpen && !isDoubleSingleByte && !isPunctuation) + { + return isTouchKeyboardSpecialKeys; + } + + if (pwch) + { + *pwch = wch; + } + + // + // Get composition engine + // + CCompositionProcessorEngine *pCompositionProcessorEngine; + pCompositionProcessorEngine = _pCompositionProcessorEngine; + + if (isOpen) // Chinese mode + { + // + // The candidate or phrase list handles the keys through ITfKeyEventSink. + // + // eat only keys that CKeyHandlerEditSession can handles. + // + auto ret = pCompositionProcessorEngine->IsVirtualKeyNeed( // + *pCodeOut, // + pwch, // + _IsComposing(), // + _candidateMode, // + _isCandidateWithWildcard, // + pKeyState // + ); + if (ret) + { + return TRUE; + } + } + + OutputDebugString( + fmt::format(L"IsPunctuation _candidateMode: {}, isPunctuation: {}", (int)_candidateMode, isPunctuation) + .c_str()); + // + // Punctuation + // + if (pCompositionProcessorEngine->IsPunctuation(wch)) + { + if ((_candidateMode == CANDIDATE_NONE || _candidateMode == CANDIDATE_INCREMENTAL) && isPunctuation) + { + if (pKeyState) + { + pKeyState->Category = CATEGORY_COMPOSING; + pKeyState->Function = FUNCTION_PUNCTUATION; + } + return TRUE; + } + } + + // + // Double/Single byte + // + if (isDoubleSingleByte && pCompositionProcessorEngine->IsDoubleSingleByte(wch)) + { + if (_candidateMode == CANDIDATE_NONE) + { + if (pKeyState) + { + pKeyState->Category = CATEGORY_COMPOSING; + pKeyState->Function = FUNCTION_DOUBLE_SINGLE_BYTE; + } + return TRUE; + } + } + + return isTouchKeyboardSpecialKeys; +} + +//+--------------------------------------------------------------------------- +// +// ConvertVKey +// +//---------------------------------------------------------------------------- + +WCHAR CMetasequoiaIME::ConvertVKey(UINT code) +{ + // + // Map virtual key to scan code + // + UINT scanCode = 0; + scanCode = MapVirtualKey(code, 0); + + // + // Keyboard state + // + BYTE abKbdState[256] = {'\0'}; + if (!GetKeyboardState(abKbdState)) + { + return 0; + } + + // + // Map virtual key to character code + // + WCHAR wch = '\0'; + if (ToUnicode(code, scanCode, abKbdState, &wch, 1, 0) == 1) + { + return wch; + } + + return 0; +} + +//+--------------------------------------------------------------------------- +// +// _IsKeyboardDisabled +// +//---------------------------------------------------------------------------- + +BOOL CMetasequoiaIME::_IsKeyboardDisabled() +{ + ITfDocumentMgr *pDocMgrFocus = nullptr; + ITfContext *pContext = nullptr; + BOOL isDisabled = FALSE; + + if ((_pThreadMgr->GetFocus(&pDocMgrFocus) != S_OK) || (pDocMgrFocus == nullptr)) + { + // if there is no focus document manager object, the keyboard + // is disabled. + isDisabled = TRUE; + } + else if ((pDocMgrFocus->GetTop(&pContext) != S_OK) || (pContext == nullptr)) + { + // if there is no context object, the keyboard is disabled. + isDisabled = TRUE; + } + else + { + CCompartment CompartmentKeyboardDisabled(_pThreadMgr, _tfClientId, GUID_COMPARTMENT_KEYBOARD_DISABLED); + CompartmentKeyboardDisabled._GetCompartmentBOOL(isDisabled); + + CCompartment CompartmentEmptyContext(_pThreadMgr, _tfClientId, GUID_COMPARTMENT_EMPTYCONTEXT); + CompartmentEmptyContext._GetCompartmentBOOL(isDisabled); + } + + if (pContext) + { + pContext->Release(); + } + + if (pDocMgrFocus) + { + pDocMgrFocus->Release(); + } + + return isDisabled; +} + +//+--------------------------------------------------------------------------- +// +// ITfKeyEventSink::OnSetFocus +// +// Called by the system whenever this service gets the keystroke device focus. +//---------------------------------------------------------------------------- + +STDAPI CMetasequoiaIME::OnSetFocus(BOOL fForeground) +{ + fForeground; + + return S_OK; +} + +//+--------------------------------------------------------------------------- +// +// ITfKeyEventSink::OnTestKeyDown +// +// Called by the system to query this service wants a potential keystroke. +//---------------------------------------------------------------------------- + +STDAPI CMetasequoiaIME::OnTestKeyDown(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pIsEaten) +{ + Global::UpdateModifiers(wParam, lParam); + + _KEYSTROKE_STATE KeystrokeState; + WCHAR wch = '\0'; + UINT code = 0; + *pIsEaten = _IsKeyEaten(pContext, (UINT)wParam, &code, &wch, &KeystrokeState); + + if (KeystrokeState.Category == CATEGORY_INVOKE_COMPOSITION_EDIT_SESSION) + { + // + // Invoke key handler edit session + // + KeystrokeState.Category = CATEGORY_COMPOSING; + + _InvokeKeyHandler(pContext, code, wch, (DWORD)lParam, KeystrokeState); + } + + return S_OK; +} + +//+--------------------------------------------------------------------------- +// +// ITfKeyEventSink::OnKeyDown +// +// Called by the system to offer this service a keystroke. +// on exit, the application will not handle the keystroke. +//---------------------------------------------------------------------------- + +STDAPI CMetasequoiaIME::OnKeyDown(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pIsEaten) +{ + Global::UpdateModifiers(wParam, lParam); + + _KEYSTROKE_STATE KeystrokeState; + WCHAR wch = '\0'; + UINT code = 0; + + *pIsEaten = _IsKeyEaten(pContext, (UINT)wParam, &code, &wch, &KeystrokeState); + if (*pIsEaten) + { + Global::Keycode = code; + if ((GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0) + Global::ModifiersDown |= 0b00000001; + else + Global::ModifiersDown &= ~0b00000001; + WriteDataToSharedMemory(Global::Keycode, Global::ModifiersDown, nullptr, 0, L"", 0b00011); + SendKeyEventToUIProcess(); + } + Global::firefox_like_cnt = 0; +#ifdef FANY_DEBUG + if (Global::Keycode == VK_TAB) + { + OutputDebugString(L"Tab key pressed."); + OutputDebugString(fmt::format(L"eat: {}", *pIsEaten).c_str()); + } +#endif + +#ifdef FANY_DEBUG + std::wstring msg = L"Whether to eat it?" + std::to_wstring(*pIsEaten); + // TODO: Log msg +#endif + + if (*pIsEaten) + { +#ifdef FANY_DEBUG + OutputDebugString(L"Yes, eat it."); +#endif + bool needInvokeKeyHandler = true; + // + // Invoke key handler edit session + // + if (code == VK_ESCAPE) + { + KeystrokeState.Category = CATEGORY_COMPOSING; + } + + // Always eat THIRDPARTY_NEXTPAGE and THIRDPARTY_PREVPAGE keys, but don't always process them. + if ((wch == THIRDPARTY_NEXTPAGE) || (wch == THIRDPARTY_PREVPAGE)) + { + needInvokeKeyHandler = + !((KeystrokeState.Category == CATEGORY_NONE) && (KeystrokeState.Function == FUNCTION_NONE)); + } + + if (needInvokeKeyHandler) + { + TF_STATUS tfStatus; + if (SUCCEEDED(pContext->GetStatus(&tfStatus))) + { + if (tfStatus.dwDynamicFlags & TF_SD_READONLY) + { + std::wstring str = std::wstring(1, wch); + FanyUtils::SendKeys(str); +#ifdef FANY_DEBUG + OutputDebugString(L"pContext is read-only"); +#endif + } + else + { +#ifdef FANY_DEBUG + OutputDebugString(L"pContext is editable"); +#endif + } + } + + _InvokeKeyHandler(pContext, code, wch, (DWORD)lParam, KeystrokeState); + } + } + else if (KeystrokeState.Category == CATEGORY_INVOKE_COMPOSITION_EDIT_SESSION) + { + // Invoke key handler edit session + KeystrokeState.Category = CATEGORY_COMPOSING; + _InvokeKeyHandler(pContext, code, wch, (DWORD)lParam, KeystrokeState); + } + + return S_OK; +} + +//+--------------------------------------------------------------------------- +// +// ITfKeyEventSink::OnTestKeyUp +// +// Called by the system to query this service wants a potential keystroke. +//---------------------------------------------------------------------------- + +STDAPI CMetasequoiaIME::OnTestKeyUp(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pIsEaten) +{ + if (pIsEaten == nullptr) + { + return E_INVALIDARG; + } + + Global::UpdateModifiers(wParam, lParam); + + WCHAR wch = '\0'; + UINT code = 0; + + *pIsEaten = _IsKeyEaten(pContext, (UINT)wParam, &code, &wch, NULL); + + return S_OK; +} + +//+--------------------------------------------------------------------------- +// +// ITfKeyEventSink::OnKeyUp +// +// Called by the system to offer this service a keystroke. If *pIsEaten == TRUE +// on exit, the application will not handle the keystroke. +//---------------------------------------------------------------------------- + +STDAPI CMetasequoiaIME::OnKeyUp(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pIsEaten) +{ + Global::UpdateModifiers(wParam, lParam); + + _KEYSTROKE_STATE KeystrokeState; + WCHAR wch = '\0'; + UINT code = 0; + *pIsEaten = _IsKeyEaten(pContext, (UINT)wParam, &code, &wch, &KeystrokeState); + +#ifdef FANY_DEBUG + OutputDebugString(L"fanyfull ITfKeyEventSink::OnKeyUp"); + OutputDebugString(fmt::format(L"Global::PureShiftKeyUp: {}", Global::PureShiftKeyUp).c_str()); +#endif + + // if (code == VK_SHIFT) + // { + // if (Global::PureShiftKeyUp) + // { + // KeystrokeState.Category = CATEGORY_COMPOSING; + // KeystrokeState.Function = FUNCTION_TOGGLE_IME_MODE; + // _InvokeKeyHandler(pContext, code, wch, (DWORD)lParam, KeystrokeState); + // } + // } + + return S_OK; +} + +//+--------------------------------------------------------------------------- +// +// ITfKeyEventSink::OnPreservedKey +// +// Called when a hotkey (registered by us, or by the system) is typed. +//---------------------------------------------------------------------------- + +STDAPI CMetasequoiaIME::OnPreservedKey(ITfContext *pContext, REFGUID rguid, BOOL *pIsEaten) +{ + pContext; + + CCompositionProcessorEngine *pCompositionProcessorEngine; + pCompositionProcessorEngine = _pCompositionProcessorEngine; + + BOOL pNeedToggleIMEMode = FALSE; + + pCompositionProcessorEngine->OnPreservedKey(pContext, rguid, pIsEaten, _GetThreadMgr(), _GetClientId(), + &pNeedToggleIMEMode); + + if (pNeedToggleIMEMode) + { + _KEYSTROKE_STATE KeystrokeState; + WCHAR wch = '\0'; + UINT code = 0; + KeystrokeState.Category = CATEGORY_COMPOSING; + KeystrokeState.Function = FUNCTION_TOGGLE_IME_MODE; + _InvokeKeyHandler(pContext, code, wch, (DWORD)0, KeystrokeState); + } + + return S_OK; +} + +//+--------------------------------------------------------------------------- +// +// _InitKeyEventSink +// +// Advise a keystroke sink. +//---------------------------------------------------------------------------- + +BOOL CMetasequoiaIME::_InitKeyEventSink() +{ + ITfKeystrokeMgr *pKeystrokeMgr = nullptr; + HRESULT hr = S_OK; + + if (FAILED(_pThreadMgr->QueryInterface(IID_ITfKeystrokeMgr, (void **)&pKeystrokeMgr))) + { + return FALSE; + } + + hr = pKeystrokeMgr->AdviseKeyEventSink(_tfClientId, (ITfKeyEventSink *)this, TRUE); + + pKeystrokeMgr->Release(); + + return (hr == S_OK); +} + +//+--------------------------------------------------------------------------- +// +// _UninitKeyEventSink +// +// Unadvise a keystroke sink. Assumes we have advised one already. +//---------------------------------------------------------------------------- + +void CMetasequoiaIME::_UninitKeyEventSink() +{ + ITfKeystrokeMgr *pKeystrokeMgr = nullptr; + + if (FAILED(_pThreadMgr->QueryInterface(IID_ITfKeystrokeMgr, (void **)&pKeystrokeMgr))) + { + return; + } + + pKeystrokeMgr->UnadviseKeyEventSink(_tfClientId); + + pKeystrokeMgr->Release(); +} diff --git a/src/Key/KeyHandler.cpp b/src/Key/KeyHandler.cpp index 9f6fe789..b398f995 100644 --- a/src/Key/KeyHandler.cpp +++ b/src/Key/KeyHandler.cpp @@ -192,7 +192,7 @@ Exit: //---------------------------------------------------------------------------- HRESULT CMetasequoiaIME::_HandleCompositionInputWorker(_In_ CCompositionProcessorEngine *pCompositionProcessorEngine, - TfEditCookie ec, _In_ ITfContext *pContext) + TfEditCookie ec, _In_ ITfContext *pContext) { HRESULT hr = S_OK; CMetasequoiaImeArray readingStrings; @@ -260,7 +260,7 @@ HRESULT CMetasequoiaIME::_HandleCompositionInputWorker(_In_ CCompositionProcesso //---------------------------------------------------------------------------- HRESULT CMetasequoiaIME::_CreateAndStartCandidate(_In_ CCompositionProcessorEngine *pCompositionProcessorEngine, - TfEditCookie ec, _In_ ITfContext *pContext) + TfEditCookie ec, _In_ ITfContext *pContext) { HRESULT hr = S_OK; @@ -523,7 +523,7 @@ Exit: //---------------------------------------------------------------------------- HRESULT CMetasequoiaIME::_HandleCompositionArrowKey(TfEditCookie ec, _In_ ITfContext *pContext, - KEYSTROKE_FUNCTION keyFunction) + KEYSTROKE_FUNCTION keyFunction) { ITfRange *pRangeComposition = nullptr; TF_SELECTION tfSelection; @@ -566,11 +566,6 @@ Exit: HRESULT CMetasequoiaIME::_HandleCompositionPunctuation(TfEditCookie ec, _In_ ITfContext *pContext, WCHAR wch) { HRESULT hr = S_OK; -#ifdef FANY_DEBUG - std::wstring msg = L"You pressed punctuation key: "; - msg += wch; - OutputDebugString(msg.c_str()); -#endif if (_candidateMode != CANDIDATE_NONE && _pCandidateListUIPresenter) { DWORD_PTR candidateLen = 0; @@ -583,7 +578,8 @@ HRESULT CMetasequoiaIME::_HandleCompositionPunctuation(TfEditCookie ec, _In_ ITf if (candidateLen) { - _AddComposingAndChar(ec, pContext, &candidateString); + /* TODO: Currently we do not commit selected candidate while typing punctuation */ + // _AddComposingAndChar(ec, pContext, &candidateString); } } // @@ -592,21 +588,10 @@ HRESULT CMetasequoiaIME::_HandleCompositionPunctuation(TfEditCookie ec, _In_ ITf CCompositionProcessorEngine *pCompositionProcessorEngine = nullptr; pCompositionProcessorEngine = _pCompositionProcessorEngine; - WCHAR punctuation = pCompositionProcessorEngine->GetPunctuation(wch); + const WCHAR *punctuation = pCompositionProcessorEngine->GetPunctuation(wch); CStringRange punctuationString; - if (punctuation == L'…') - { - punctuationString.Set(L"……", 2); - } - else if (punctuation == L'—') - { - punctuationString.Set(L"——", 2); - } - else - { - punctuationString.Set(&punctuation, 1); - } + punctuationString.Set(punctuation, wcslen(punctuation)); // Finalize character hr = _AddCharAndFinalize(ec, pContext, &punctuationString); @@ -615,7 +600,7 @@ HRESULT CMetasequoiaIME::_HandleCompositionPunctuation(TfEditCookie ec, _In_ ITf return hr; } - _HandleCancel(ec, pContext); + _HandleComplete(ec, pContext); return S_OK; } @@ -662,7 +647,7 @@ HRESULT CMetasequoiaIME::_HandleCompositionDoubleSingleByte(TfEditCookie ec, _In //---------------------------------------------------------------------------- HRESULT CMetasequoiaIME::_InvokeKeyHandler(_In_ ITfContext *pContext, UINT code, WCHAR wch, DWORD flags, - _KEYSTROKE_STATE keyState) + _KEYSTROKE_STATE keyState) { flags;