1940 lines
65 KiB
C++
1940 lines
65 KiB
C++
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved
|
|
|
|
#include "Private.h"
|
|
#include "SampleIME.h"
|
|
#include "CompositionProcessorEngine.h"
|
|
#include "TableDictionaryEngine.h"
|
|
#include "DictionarySearch.h"
|
|
#include "TfInputProcessorProfile.h"
|
|
#include "Globals.h"
|
|
#include "Compartment.h"
|
|
#include "LanguageBar.h"
|
|
#include "RegKey.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CSampleIME implementation.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _AddTextProcessorEngine
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CSampleIME::_AddTextProcessorEngine()
|
|
{
|
|
LANGID langid = 0;
|
|
CLSID clsid = GUID_NULL;
|
|
GUID guidProfile = GUID_NULL;
|
|
|
|
// Get default profile.
|
|
CTfInputProcessorProfile profile;
|
|
|
|
if (FAILED(profile.CreateInstance()))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (FAILED(profile.GetCurrentLanguage(&langid)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (FAILED(profile.GetDefaultLanguageProfile(langid, GUID_TFCAT_TIP_KEYBOARD, &clsid, &guidProfile)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Is this already added?
|
|
if (_pCompositionProcessorEngine != nullptr)
|
|
{
|
|
LANGID langidProfile = 0;
|
|
GUID guidLanguageProfile = GUID_NULL;
|
|
|
|
guidLanguageProfile = _pCompositionProcessorEngine->GetLanguageProfile(&langidProfile);
|
|
if ((langid == langidProfile) && IsEqualGUID(guidProfile, guidLanguageProfile))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// Create composition processor engine
|
|
if (_pCompositionProcessorEngine == nullptr)
|
|
{
|
|
_pCompositionProcessorEngine = new (std::nothrow) CCompositionProcessorEngine();
|
|
}
|
|
if (!_pCompositionProcessorEngine)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// setup composition processor engine
|
|
if (FALSE == _pCompositionProcessorEngine->SetupLanguageProfile(langid, guidProfile, _GetThreadMgr(), _GetClientId(), _IsSecureMode(), _IsComLess()))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CompositionProcessorEngine implementation.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ctor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CCompositionProcessorEngine::CCompositionProcessorEngine()
|
|
{
|
|
_pTableDictionaryEngine = nullptr;
|
|
_pDictionaryFile = nullptr;
|
|
|
|
_langid = 0xffff;
|
|
_guidProfile = GUID_NULL;
|
|
_tfClientId = TF_CLIENTID_NULL;
|
|
|
|
_pLanguageBar_IMEMode = nullptr;
|
|
_pLanguageBar_DoubleSingleByte = nullptr;
|
|
_pLanguageBar_Punctuation = nullptr;
|
|
|
|
_pCompartmentConversion = nullptr;
|
|
_pCompartmentKeyboardOpenEventSink = nullptr;
|
|
_pCompartmentConversionEventSink = nullptr;
|
|
_pCompartmentDoubleSingleByteEventSink = nullptr;
|
|
_pCompartmentPunctuationEventSink = nullptr;
|
|
|
|
_hasWildcardIncludedInKeystrokeBuffer = FALSE;
|
|
|
|
_isWildcard = FALSE;
|
|
_isDisableWildcardAtFirst = FALSE;
|
|
_hasMakePhraseFromText = FALSE;
|
|
_isKeystrokeSort = FALSE;
|
|
|
|
_candidateListPhraseModifier = 0;
|
|
|
|
_candidateWndWidth = CAND_WIDTH;
|
|
|
|
InitKeyStrokeTable();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// dtor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CCompositionProcessorEngine::~CCompositionProcessorEngine()
|
|
{
|
|
if (_pTableDictionaryEngine)
|
|
{
|
|
delete _pTableDictionaryEngine;
|
|
_pTableDictionaryEngine = nullptr;
|
|
}
|
|
|
|
if (_pLanguageBar_IMEMode)
|
|
{
|
|
_pLanguageBar_IMEMode->CleanUp();
|
|
_pLanguageBar_IMEMode->Release();
|
|
_pLanguageBar_IMEMode = nullptr;
|
|
}
|
|
if (_pLanguageBar_DoubleSingleByte)
|
|
{
|
|
_pLanguageBar_DoubleSingleByte->CleanUp();
|
|
_pLanguageBar_DoubleSingleByte->Release();
|
|
_pLanguageBar_DoubleSingleByte = nullptr;
|
|
}
|
|
if (_pLanguageBar_Punctuation)
|
|
{
|
|
_pLanguageBar_Punctuation->CleanUp();
|
|
_pLanguageBar_Punctuation->Release();
|
|
_pLanguageBar_Punctuation = nullptr;
|
|
}
|
|
|
|
if (_pCompartmentConversion)
|
|
{
|
|
delete _pCompartmentConversion;
|
|
_pCompartmentConversion = nullptr;
|
|
}
|
|
if (_pCompartmentKeyboardOpenEventSink)
|
|
{
|
|
_pCompartmentKeyboardOpenEventSink->_Unadvise();
|
|
delete _pCompartmentKeyboardOpenEventSink;
|
|
_pCompartmentKeyboardOpenEventSink = nullptr;
|
|
}
|
|
if (_pCompartmentConversionEventSink)
|
|
{
|
|
_pCompartmentConversionEventSink->_Unadvise();
|
|
delete _pCompartmentConversionEventSink;
|
|
_pCompartmentConversionEventSink = nullptr;
|
|
}
|
|
if (_pCompartmentDoubleSingleByteEventSink)
|
|
{
|
|
_pCompartmentDoubleSingleByteEventSink->_Unadvise();
|
|
delete _pCompartmentDoubleSingleByteEventSink;
|
|
_pCompartmentDoubleSingleByteEventSink = nullptr;
|
|
}
|
|
if (_pCompartmentPunctuationEventSink)
|
|
{
|
|
_pCompartmentPunctuationEventSink->_Unadvise();
|
|
delete _pCompartmentPunctuationEventSink;
|
|
_pCompartmentPunctuationEventSink = nullptr;
|
|
}
|
|
|
|
if (_pDictionaryFile)
|
|
{
|
|
delete _pDictionaryFile;
|
|
_pDictionaryFile = nullptr;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// SetupLanguageProfile
|
|
//
|
|
// Setup language profile for Composition Processor Engine.
|
|
// param
|
|
// [in] LANGID langid = Specify language ID
|
|
// [in] GUID guidLanguageProfile - Specify GUID language profile which GUID is as same as Text Service Framework language profile.
|
|
// [in] ITfThreadMgr - pointer ITfThreadMgr.
|
|
// [in] tfClientId - TfClientId value.
|
|
// [in] isSecureMode - secure mode
|
|
// returns
|
|
// If setup succeeded, returns true. Otherwise returns false.
|
|
// N.B. For reverse conversion, ITfThreadMgr is NULL, TfClientId is 0 and isSecureMode is ignored.
|
|
//+---------------------------------------------------------------------------
|
|
|
|
BOOL CCompositionProcessorEngine::SetupLanguageProfile(LANGID langid, REFGUID guidLanguageProfile, _In_ ITfThreadMgr *pThreadMgr, TfClientId tfClientId, BOOL isSecureMode, BOOL isComLessMode)
|
|
{
|
|
BOOL ret = TRUE;
|
|
if ((tfClientId == 0) && (pThreadMgr == nullptr))
|
|
{
|
|
ret = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
_isComLessMode = isComLessMode;
|
|
_langid = langid;
|
|
_guidProfile = guidLanguageProfile;
|
|
_tfClientId = tfClientId;
|
|
|
|
SetupPreserved(pThreadMgr, tfClientId);
|
|
InitializeSampleIMECompartment(pThreadMgr, tfClientId);
|
|
SetupPunctuationPair();
|
|
SetupLanguageBar(pThreadMgr, tfClientId, isSecureMode);
|
|
SetupKeystroke();
|
|
SetupConfiguration();
|
|
SetupDictionaryFile();
|
|
|
|
Exit:
|
|
return ret;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// AddVirtualKey
|
|
// Add virtual key code to Composition Processor Engine for used to parse keystroke data.
|
|
// param
|
|
// [in] uCode - Specify virtual key code.
|
|
// returns
|
|
// State of Text Processor Engine.
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CCompositionProcessorEngine::AddVirtualKey(WCHAR wch)
|
|
{
|
|
if (!wch)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// append one keystroke in buffer.
|
|
//
|
|
DWORD_PTR srgKeystrokeBufLen = _keystrokeBuffer.GetLength();
|
|
PWCHAR pwch = new (std::nothrow) WCHAR[ srgKeystrokeBufLen + 1 ];
|
|
if (!pwch)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
memcpy(pwch, _keystrokeBuffer.Get(), srgKeystrokeBufLen * sizeof(WCHAR));
|
|
pwch[ srgKeystrokeBufLen ] = wch;
|
|
|
|
if (_keystrokeBuffer.Get())
|
|
{
|
|
delete [] _keystrokeBuffer.Get();
|
|
}
|
|
|
|
_keystrokeBuffer.Set(pwch, srgKeystrokeBufLen + 1);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// RemoveVirtualKey
|
|
// Remove stored virtual key code.
|
|
// param
|
|
// [in] dwIndex - Specified index.
|
|
// returns
|
|
// none.
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCompositionProcessorEngine::RemoveVirtualKey(DWORD_PTR dwIndex)
|
|
{
|
|
DWORD_PTR srgKeystrokeBufLen = _keystrokeBuffer.GetLength();
|
|
|
|
if (dwIndex + 1 < srgKeystrokeBufLen)
|
|
{
|
|
// shift following eles left
|
|
memmove((BYTE*)_keystrokeBuffer.Get() + (dwIndex * sizeof(WCHAR)),
|
|
(BYTE*)_keystrokeBuffer.Get() + ((dwIndex + 1) * sizeof(WCHAR)),
|
|
(srgKeystrokeBufLen - dwIndex - 1) * sizeof(WCHAR));
|
|
}
|
|
|
|
_keystrokeBuffer.Set(_keystrokeBuffer.Get(), srgKeystrokeBufLen - 1);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// PurgeVirtualKey
|
|
// Purge stored virtual key code.
|
|
// param
|
|
// none.
|
|
// returns
|
|
// none.
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCompositionProcessorEngine::PurgeVirtualKey()
|
|
{
|
|
if (_keystrokeBuffer.Get())
|
|
{
|
|
delete [] _keystrokeBuffer.Get();
|
|
_keystrokeBuffer.Set(NULL, 0);
|
|
}
|
|
}
|
|
|
|
WCHAR CCompositionProcessorEngine::GetVirtualKey(DWORD_PTR dwIndex)
|
|
{
|
|
if (dwIndex < _keystrokeBuffer.GetLength())
|
|
{
|
|
return *(_keystrokeBuffer.Get() + dwIndex);
|
|
}
|
|
return 0;
|
|
}
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetReadingStrings
|
|
// Retrieves string from Composition Processor Engine.
|
|
// param
|
|
// [out] pReadingStrings - Specified returns pointer of CUnicodeString.
|
|
// returns
|
|
// none
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCompositionProcessorEngine::GetReadingStrings(_Inout_ CSampleImeArray<CStringRange> *pReadingStrings, _Out_ BOOL *pIsWildcardIncluded)
|
|
{
|
|
CStringRange oneKeystroke;
|
|
|
|
_hasWildcardIncludedInKeystrokeBuffer = FALSE;
|
|
|
|
if (pReadingStrings->Count() == 0 && _keystrokeBuffer.GetLength())
|
|
{
|
|
CStringRange* pNewString = nullptr;
|
|
|
|
pNewString = pReadingStrings->Append();
|
|
if (pNewString)
|
|
{
|
|
*pNewString = _keystrokeBuffer;
|
|
}
|
|
|
|
for (DWORD index = 0; index < _keystrokeBuffer.GetLength(); index++)
|
|
{
|
|
oneKeystroke.Set(_keystrokeBuffer.Get() + index, 1);
|
|
|
|
if (IsWildcard() && IsWildcardChar(*oneKeystroke.Get()))
|
|
{
|
|
_hasWildcardIncludedInKeystrokeBuffer = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
*pIsWildcardIncluded = _hasWildcardIncludedInKeystrokeBuffer;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetCandidateList
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCompositionProcessorEngine::GetCandidateList(_Inout_ CSampleImeArray<CCandidateListItem> *pCandidateList, BOOL isIncrementalWordSearch, BOOL isWildcardSearch)
|
|
{
|
|
if (!IsDictionaryAvailable())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (isIncrementalWordSearch)
|
|
{
|
|
CStringRange wildcardSearch;
|
|
DWORD_PTR keystrokeBufLen = _keystrokeBuffer.GetLength() + 2;
|
|
PWCHAR pwch = new (std::nothrow) WCHAR[ keystrokeBufLen ];
|
|
if (!pwch)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// check keystroke buffer already has wildcard char which end user want wildcard serach
|
|
DWORD wildcardIndex = 0;
|
|
BOOL isFindWildcard = FALSE;
|
|
|
|
if (IsWildcard())
|
|
{
|
|
for (wildcardIndex = 0; wildcardIndex < _keystrokeBuffer.GetLength(); wildcardIndex++)
|
|
{
|
|
if (IsWildcardChar(*(_keystrokeBuffer.Get() + wildcardIndex)))
|
|
{
|
|
isFindWildcard = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
StringCchCopyN(pwch, keystrokeBufLen, _keystrokeBuffer.Get(), _keystrokeBuffer.GetLength());
|
|
|
|
if (!isFindWildcard)
|
|
{
|
|
// add wildcard char for incremental search
|
|
StringCchCat(pwch, keystrokeBufLen, L"*");
|
|
}
|
|
|
|
size_t len = 0;
|
|
if (StringCchLength(pwch, STRSAFE_MAX_CCH, &len) == S_OK)
|
|
{
|
|
wildcardSearch.Set(pwch, len);
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
_pTableDictionaryEngine->CollectWordForWildcard(&wildcardSearch, pCandidateList);
|
|
|
|
if (0 >= pCandidateList->Count())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (IsKeystrokeSort())
|
|
{
|
|
_pTableDictionaryEngine->SortListItemByFindKeyCode(pCandidateList);
|
|
}
|
|
|
|
// Incremental search would show keystroke data from all candidate list items
|
|
// but wont show identical keystroke data for user inputted.
|
|
for (UINT index = 0; index < pCandidateList->Count(); index++)
|
|
{
|
|
CCandidateListItem *pLI = pCandidateList->GetAt(index);
|
|
DWORD_PTR keystrokeBufferLen = 0;
|
|
|
|
if (IsWildcard())
|
|
{
|
|
keystrokeBufferLen = wildcardIndex;
|
|
}
|
|
else
|
|
{
|
|
keystrokeBufferLen = _keystrokeBuffer.GetLength();
|
|
}
|
|
|
|
CStringRange newFindKeyCode;
|
|
newFindKeyCode.Set(pLI->_FindKeyCode.Get() + keystrokeBufferLen, pLI->_FindKeyCode.GetLength() - keystrokeBufferLen);
|
|
pLI->_FindKeyCode.Set(newFindKeyCode);
|
|
}
|
|
|
|
delete [] pwch;
|
|
}
|
|
else if (isWildcardSearch)
|
|
{
|
|
_pTableDictionaryEngine->CollectWordForWildcard(&_keystrokeBuffer, pCandidateList);
|
|
}
|
|
else
|
|
{
|
|
_pTableDictionaryEngine->CollectWord(&_keystrokeBuffer, pCandidateList);
|
|
}
|
|
|
|
for (UINT index = 0; index < pCandidateList->Count();)
|
|
{
|
|
CCandidateListItem *pLI = pCandidateList->GetAt(index);
|
|
CStringRange startItemString;
|
|
CStringRange endItemString;
|
|
|
|
startItemString.Set(pLI->_ItemString.Get(), 1);
|
|
endItemString.Set(pLI->_ItemString.Get() + pLI->_ItemString.GetLength() - 1, 1);
|
|
|
|
index++;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetCandidateStringInConverted
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCompositionProcessorEngine::GetCandidateStringInConverted(CStringRange &searchString, _In_ CSampleImeArray<CCandidateListItem> *pCandidateList)
|
|
{
|
|
if (!IsDictionaryAvailable())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Search phrase from SECTION_TEXT's converted string list
|
|
CStringRange wildcardSearch;
|
|
DWORD_PTR srgKeystrokeBufLen = searchString.GetLength() + 2;
|
|
PWCHAR pwch = new (std::nothrow) WCHAR[ srgKeystrokeBufLen ];
|
|
if (!pwch)
|
|
{
|
|
return;
|
|
}
|
|
|
|
StringCchCopyN(pwch, srgKeystrokeBufLen, searchString.Get(), searchString.GetLength());
|
|
StringCchCat(pwch, srgKeystrokeBufLen, L"*");
|
|
|
|
// add wildcard char
|
|
size_t len = 0;
|
|
if (StringCchLength(pwch, STRSAFE_MAX_CCH, &len) != S_OK)
|
|
{
|
|
return;
|
|
}
|
|
wildcardSearch.Set(pwch, len);
|
|
|
|
_pTableDictionaryEngine->CollectWordFromConvertedStringForWildcard(&wildcardSearch, pCandidateList);
|
|
|
|
if (IsKeystrokeSort())
|
|
{
|
|
_pTableDictionaryEngine->SortListItemByFindKeyCode(pCandidateList);
|
|
}
|
|
|
|
wildcardSearch.Clear();
|
|
delete [] pwch;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IsPunctuation
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CCompositionProcessorEngine::IsPunctuation(WCHAR wch)
|
|
{
|
|
for (int i = 0; i < ARRAYSIZE(Global::PunctuationTable); i++)
|
|
{
|
|
if (Global::PunctuationTable[i]._Code == wch)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
for (UINT j = 0; j < _PunctuationPair.Count(); j++)
|
|
{
|
|
CPunctuationPair* pPuncPair = _PunctuationPair.GetAt(j);
|
|
|
|
if (pPuncPair->_punctuation._Code == wch)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
for (UINT k = 0; k < _PunctuationNestPair.Count(); k++)
|
|
{
|
|
CPunctuationNestPair* pPuncNestPair = _PunctuationNestPair.GetAt(k);
|
|
|
|
if (pPuncNestPair->_punctuation_begin._Code == wch)
|
|
{
|
|
return TRUE;
|
|
}
|
|
if (pPuncNestPair->_punctuation_end._Code == wch)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetPunctuationPair
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
WCHAR CCompositionProcessorEngine::GetPunctuation(WCHAR wch)
|
|
{
|
|
for (int i = 0; i < ARRAYSIZE(Global::PunctuationTable); i++)
|
|
{
|
|
if (Global::PunctuationTable[i]._Code == wch)
|
|
{
|
|
return Global::PunctuationTable[i]._Punctuation;
|
|
}
|
|
}
|
|
|
|
for (UINT j = 0; j < _PunctuationPair.Count(); j++)
|
|
{
|
|
CPunctuationPair* pPuncPair = _PunctuationPair.GetAt(j);
|
|
|
|
if (pPuncPair->_punctuation._Code == wch)
|
|
{
|
|
if (! pPuncPair->_isPairToggle)
|
|
{
|
|
pPuncPair->_isPairToggle = TRUE;
|
|
return pPuncPair->_punctuation._Punctuation;
|
|
}
|
|
else
|
|
{
|
|
pPuncPair->_isPairToggle = FALSE;
|
|
return pPuncPair->_pairPunctuation;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (UINT k = 0; k < _PunctuationNestPair.Count(); k++)
|
|
{
|
|
CPunctuationNestPair* pPuncNestPair = _PunctuationNestPair.GetAt(k);
|
|
|
|
if (pPuncNestPair->_punctuation_begin._Code == wch)
|
|
{
|
|
if (pPuncNestPair->_nestCount++ == 0)
|
|
{
|
|
return pPuncNestPair->_punctuation_begin._Punctuation;
|
|
}
|
|
else
|
|
{
|
|
return pPuncNestPair->_pairPunctuation_begin;
|
|
}
|
|
}
|
|
if (pPuncNestPair->_punctuation_end._Code == wch)
|
|
{
|
|
if (--pPuncNestPair->_nestCount == 0)
|
|
{
|
|
return pPuncNestPair->_punctuation_end._Punctuation;
|
|
}
|
|
else
|
|
{
|
|
return pPuncNestPair->_pairPunctuation_end;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IsDoubleSingleByte
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CCompositionProcessorEngine::IsDoubleSingleByte(WCHAR wch)
|
|
{
|
|
if (L' ' <= wch && wch <= L'~')
|
|
{
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// SetupKeystroke
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCompositionProcessorEngine::SetupKeystroke()
|
|
{
|
|
SetKeystrokeTable(&_KeystrokeComposition);
|
|
return;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// SetKeystrokeTable
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCompositionProcessorEngine::SetKeystrokeTable(_Inout_ CSampleImeArray<_KEYSTROKE> *pKeystroke)
|
|
{
|
|
for (int i = 0; i < 26; i++)
|
|
{
|
|
_KEYSTROKE* pKS = nullptr;
|
|
|
|
pKS = pKeystroke->Append();
|
|
if (!pKS)
|
|
{
|
|
break;
|
|
}
|
|
*pKS = _keystrokeTable[i];
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// SetupPreserved
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCompositionProcessorEngine::SetupPreserved(_In_ ITfThreadMgr *pThreadMgr, TfClientId tfClientId)
|
|
{
|
|
TF_PRESERVEDKEY preservedKeyImeMode;
|
|
preservedKeyImeMode.uVKey = VK_SHIFT;
|
|
preservedKeyImeMode.uModifiers = _TF_MOD_ON_KEYUP_SHIFT_ONLY;
|
|
SetPreservedKey(Global::SampleIMEGuidImeModePreserveKey, preservedKeyImeMode, Global::ImeModeDescription, &_PreservedKey_IMEMode);
|
|
|
|
TF_PRESERVEDKEY preservedKeyDoubleSingleByte;
|
|
preservedKeyDoubleSingleByte.uVKey = VK_SPACE;
|
|
preservedKeyDoubleSingleByte.uModifiers = TF_MOD_SHIFT;
|
|
SetPreservedKey(Global::SampleIMEGuidDoubleSingleBytePreserveKey, preservedKeyDoubleSingleByte, Global::DoubleSingleByteDescription, &_PreservedKey_DoubleSingleByte);
|
|
|
|
TF_PRESERVEDKEY preservedKeyPunctuation;
|
|
preservedKeyPunctuation.uVKey = VK_OEM_PERIOD;
|
|
preservedKeyPunctuation.uModifiers = TF_MOD_CONTROL;
|
|
SetPreservedKey(Global::SampleIMEGuidPunctuationPreserveKey, preservedKeyPunctuation, Global::PunctuationDescription, &_PreservedKey_Punctuation);
|
|
|
|
InitPreservedKey(&_PreservedKey_IMEMode, pThreadMgr, tfClientId);
|
|
InitPreservedKey(&_PreservedKey_DoubleSingleByte, pThreadMgr, tfClientId);
|
|
InitPreservedKey(&_PreservedKey_Punctuation, pThreadMgr, tfClientId);
|
|
|
|
return;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// SetKeystrokeTable
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCompositionProcessorEngine::SetPreservedKey(const CLSID clsid, TF_PRESERVEDKEY & tfPreservedKey, _In_z_ LPCWSTR pwszDescription, _Out_ XPreservedKey *pXPreservedKey)
|
|
{
|
|
pXPreservedKey->Guid = clsid;
|
|
|
|
TF_PRESERVEDKEY *ptfPsvKey1 = pXPreservedKey->TSFPreservedKeyTable.Append();
|
|
if (!ptfPsvKey1)
|
|
{
|
|
return;
|
|
}
|
|
*ptfPsvKey1 = tfPreservedKey;
|
|
|
|
size_t srgKeystrokeBufLen = 0;
|
|
if (StringCchLength(pwszDescription, STRSAFE_MAX_CCH, &srgKeystrokeBufLen) != S_OK)
|
|
{
|
|
return;
|
|
}
|
|
pXPreservedKey->Description = new (std::nothrow) WCHAR[srgKeystrokeBufLen + 1];
|
|
if (!pXPreservedKey->Description)
|
|
{
|
|
return;
|
|
}
|
|
|
|
StringCchCopy((LPWSTR)pXPreservedKey->Description, srgKeystrokeBufLen, pwszDescription);
|
|
|
|
return;
|
|
}
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// InitPreservedKey
|
|
//
|
|
// Register a hot key.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CCompositionProcessorEngine::InitPreservedKey(_In_ XPreservedKey *pXPreservedKey, _In_ ITfThreadMgr *pThreadMgr, TfClientId tfClientId)
|
|
{
|
|
ITfKeystrokeMgr *pKeystrokeMgr = nullptr;
|
|
|
|
if (IsEqualGUID(pXPreservedKey->Guid, GUID_NULL))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (pThreadMgr->QueryInterface(IID_ITfKeystrokeMgr, (void **)&pKeystrokeMgr) != S_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
for (UINT i = 0; i < pXPreservedKey->TSFPreservedKeyTable.Count(); i++)
|
|
{
|
|
TF_PRESERVEDKEY preservedKey = *pXPreservedKey->TSFPreservedKeyTable.GetAt(i);
|
|
preservedKey.uModifiers &= 0xffff;
|
|
|
|
size_t lenOfDesc = 0;
|
|
if (StringCchLength(pXPreservedKey->Description, STRSAFE_MAX_CCH, &lenOfDesc) != S_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
pKeystrokeMgr->PreserveKey(tfClientId, pXPreservedKey->Guid, &preservedKey, pXPreservedKey->Description, static_cast<ULONG>(lenOfDesc));
|
|
}
|
|
|
|
pKeystrokeMgr->Release();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CheckShiftKeyOnly
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CCompositionProcessorEngine::CheckShiftKeyOnly(_In_ CSampleImeArray<TF_PRESERVEDKEY> *pTSFPreservedKeyTable)
|
|
{
|
|
for (UINT i = 0; i < pTSFPreservedKeyTable->Count(); i++)
|
|
{
|
|
TF_PRESERVEDKEY *ptfPsvKey = pTSFPreservedKeyTable->GetAt(i);
|
|
|
|
if (((ptfPsvKey->uModifiers & (_TF_MOD_ON_KEYUP_SHIFT_ONLY & 0xffff0000)) && !Global::IsShiftKeyDownOnly) ||
|
|
((ptfPsvKey->uModifiers & (_TF_MOD_ON_KEYUP_CONTROL_ONLY & 0xffff0000)) && !Global::IsControlKeyDownOnly) ||
|
|
((ptfPsvKey->uModifiers & (_TF_MOD_ON_KEYUP_ALT_ONLY & 0xffff0000)) && !Global::IsAltKeyDownOnly) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// OnPreservedKey
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCompositionProcessorEngine::OnPreservedKey(REFGUID rguid, _Out_ BOOL *pIsEaten, _In_ ITfThreadMgr *pThreadMgr, TfClientId tfClientId)
|
|
{
|
|
if (IsEqualGUID(rguid, _PreservedKey_IMEMode.Guid))
|
|
{
|
|
if (!CheckShiftKeyOnly(&_PreservedKey_IMEMode.TSFPreservedKeyTable))
|
|
{
|
|
*pIsEaten = FALSE;
|
|
return;
|
|
}
|
|
BOOL isOpen = FALSE;
|
|
CCompartment CompartmentKeyboardOpen(pThreadMgr, tfClientId, GUID_COMPARTMENT_KEYBOARD_OPENCLOSE);
|
|
CompartmentKeyboardOpen._GetCompartmentBOOL(isOpen);
|
|
CompartmentKeyboardOpen._SetCompartmentBOOL(isOpen ? FALSE : TRUE);
|
|
|
|
*pIsEaten = TRUE;
|
|
}
|
|
else if (IsEqualGUID(rguid, _PreservedKey_DoubleSingleByte.Guid))
|
|
{
|
|
if (!CheckShiftKeyOnly(&_PreservedKey_DoubleSingleByte.TSFPreservedKeyTable))
|
|
{
|
|
*pIsEaten = FALSE;
|
|
return;
|
|
}
|
|
BOOL isDouble = FALSE;
|
|
CCompartment CompartmentDoubleSingleByte(pThreadMgr, tfClientId, Global::SampleIMEGuidCompartmentDoubleSingleByte);
|
|
CompartmentDoubleSingleByte._GetCompartmentBOOL(isDouble);
|
|
CompartmentDoubleSingleByte._SetCompartmentBOOL(isDouble ? FALSE : TRUE);
|
|
*pIsEaten = TRUE;
|
|
}
|
|
else if (IsEqualGUID(rguid, _PreservedKey_Punctuation.Guid))
|
|
{
|
|
if (!CheckShiftKeyOnly(&_PreservedKey_Punctuation.TSFPreservedKeyTable))
|
|
{
|
|
*pIsEaten = FALSE;
|
|
return;
|
|
}
|
|
BOOL isPunctuation = FALSE;
|
|
CCompartment CompartmentPunctuation(pThreadMgr, tfClientId, Global::SampleIMEGuidCompartmentPunctuation);
|
|
CompartmentPunctuation._GetCompartmentBOOL(isPunctuation);
|
|
CompartmentPunctuation._SetCompartmentBOOL(isPunctuation ? FALSE : TRUE);
|
|
*pIsEaten = TRUE;
|
|
}
|
|
else
|
|
{
|
|
*pIsEaten = FALSE;
|
|
}
|
|
*pIsEaten = TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// SetupConfiguration
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCompositionProcessorEngine::SetupConfiguration()
|
|
{
|
|
_isWildcard = TRUE;
|
|
_isDisableWildcardAtFirst = TRUE;
|
|
_hasMakePhraseFromText = TRUE;
|
|
_isKeystrokeSort = TRUE;
|
|
_candidateWndWidth = CAND_WIDTH;
|
|
|
|
SetInitialCandidateListRange();
|
|
|
|
SetDefaultCandidateTextFont();
|
|
|
|
return;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// SetupLanguageBar
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCompositionProcessorEngine::SetupLanguageBar(_In_ ITfThreadMgr *pThreadMgr, TfClientId tfClientId, BOOL isSecureMode)
|
|
{
|
|
DWORD dwEnable = 1;
|
|
CreateLanguageBarButton(dwEnable, GUID_LBI_INPUTMODE, Global::LangbarImeModeDescription, Global::ImeModeDescription, Global::ImeModeOnIcoIndex, Global::ImeModeOffIcoIndex, &_pLanguageBar_IMEMode, isSecureMode);
|
|
CreateLanguageBarButton(dwEnable, Global::SampleIMEGuidLangBarDoubleSingleByte, Global::LangbarDoubleSingleByteDescription, Global::DoubleSingleByteDescription, Global::DoubleSingleByteOnIcoIndex, Global::DoubleSingleByteOffIcoIndex, &_pLanguageBar_DoubleSingleByte, isSecureMode);
|
|
CreateLanguageBarButton(dwEnable, Global::SampleIMEGuidLangBarPunctuation, Global::LangbarPunctuationDescription, Global::PunctuationDescription, Global::PunctuationOnIcoIndex, Global::PunctuationOffIcoIndex, &_pLanguageBar_Punctuation, isSecureMode);
|
|
|
|
InitLanguageBar(_pLanguageBar_IMEMode, pThreadMgr, tfClientId, GUID_COMPARTMENT_KEYBOARD_OPENCLOSE);
|
|
InitLanguageBar(_pLanguageBar_DoubleSingleByte, pThreadMgr, tfClientId, Global::SampleIMEGuidCompartmentDoubleSingleByte);
|
|
InitLanguageBar(_pLanguageBar_Punctuation, pThreadMgr, tfClientId, Global::SampleIMEGuidCompartmentPunctuation);
|
|
|
|
_pCompartmentConversion = new (std::nothrow) CCompartment(pThreadMgr, tfClientId, GUID_COMPARTMENT_KEYBOARD_INPUTMODE_CONVERSION);
|
|
_pCompartmentKeyboardOpenEventSink = new (std::nothrow) CCompartmentEventSink(CompartmentCallback, this);
|
|
_pCompartmentConversionEventSink = new (std::nothrow) CCompartmentEventSink(CompartmentCallback, this);
|
|
_pCompartmentDoubleSingleByteEventSink = new (std::nothrow) CCompartmentEventSink(CompartmentCallback, this);
|
|
_pCompartmentPunctuationEventSink = new (std::nothrow) CCompartmentEventSink(CompartmentCallback, this);
|
|
|
|
if (_pCompartmentKeyboardOpenEventSink)
|
|
{
|
|
_pCompartmentKeyboardOpenEventSink->_Advise(pThreadMgr, GUID_COMPARTMENT_KEYBOARD_OPENCLOSE);
|
|
}
|
|
if (_pCompartmentConversionEventSink)
|
|
{
|
|
_pCompartmentConversionEventSink->_Advise(pThreadMgr, GUID_COMPARTMENT_KEYBOARD_INPUTMODE_CONVERSION);
|
|
}
|
|
if (_pCompartmentDoubleSingleByteEventSink)
|
|
{
|
|
_pCompartmentDoubleSingleByteEventSink->_Advise(pThreadMgr, Global::SampleIMEGuidCompartmentDoubleSingleByte);
|
|
}
|
|
if (_pCompartmentPunctuationEventSink)
|
|
{
|
|
_pCompartmentPunctuationEventSink->_Advise(pThreadMgr, Global::SampleIMEGuidCompartmentPunctuation);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CreateLanguageBarButton
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCompositionProcessorEngine::CreateLanguageBarButton(DWORD dwEnable, GUID guidLangBar, _In_z_ LPCWSTR pwszDescriptionValue, _In_z_ LPCWSTR pwszTooltipValue, DWORD dwOnIconIndex, DWORD dwOffIconIndex, _Outptr_result_maybenull_ CLangBarItemButton **ppLangBarItemButton, BOOL isSecureMode)
|
|
{
|
|
dwEnable;
|
|
|
|
if (ppLangBarItemButton)
|
|
{
|
|
*ppLangBarItemButton = new (std::nothrow) CLangBarItemButton(guidLangBar, pwszDescriptionValue, pwszTooltipValue, dwOnIconIndex, dwOffIconIndex, isSecureMode);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// InitLanguageBar
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CCompositionProcessorEngine::InitLanguageBar(_In_ CLangBarItemButton *pLangBarItemButton, _In_ ITfThreadMgr *pThreadMgr, TfClientId tfClientId, REFGUID guidCompartment)
|
|
{
|
|
if (pLangBarItemButton)
|
|
{
|
|
if (pLangBarItemButton->_AddItem(pThreadMgr) == S_OK)
|
|
{
|
|
if (pLangBarItemButton->_RegisterCompartment(pThreadMgr, tfClientId, guidCompartment))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// SetupDictionaryFile
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CCompositionProcessorEngine::SetupDictionaryFile()
|
|
{
|
|
// Not yet registered
|
|
// Register CFileMapping
|
|
WCHAR wszFileName[MAX_PATH] = {'\0'};
|
|
DWORD cchA = GetModuleFileName(Global::dllInstanceHandle, wszFileName, ARRAYSIZE(wszFileName));
|
|
size_t iDicFileNameLen = cchA + wcslen(TEXTSERVICE_DIC);
|
|
WCHAR *pwszFileName = new (std::nothrow) WCHAR[iDicFileNameLen + 1];
|
|
if (!pwszFileName)
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
*pwszFileName = L'\0';
|
|
|
|
// find the last '/'
|
|
while (cchA--)
|
|
{
|
|
WCHAR wszChar = wszFileName[cchA];
|
|
if (wszChar == '\\' || wszChar == '/')
|
|
{
|
|
StringCchCopyN(pwszFileName, iDicFileNameLen + 1, wszFileName, cchA + 1);
|
|
StringCchCatN(pwszFileName, iDicFileNameLen + 1, TEXTSERVICE_DIC, wcslen(TEXTSERVICE_DIC));
|
|
break;
|
|
}
|
|
}
|
|
|
|
// create CFileMapping object
|
|
if (_pDictionaryFile == nullptr)
|
|
{
|
|
_pDictionaryFile = new (std::nothrow) CFileMapping();
|
|
if (!_pDictionaryFile)
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
if (!(_pDictionaryFile)->CreateFile(pwszFileName, GENERIC_READ, OPEN_EXISTING, FILE_SHARE_READ))
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
|
|
_pTableDictionaryEngine = new (std::nothrow) CTableDictionaryEngine(GetLocale(), _pDictionaryFile);
|
|
if (!_pTableDictionaryEngine)
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
|
|
delete []pwszFileName;
|
|
return TRUE;
|
|
ErrorExit:
|
|
if (pwszFileName)
|
|
{
|
|
delete []pwszFileName;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetDictionaryFile
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CFile* CCompositionProcessorEngine::GetDictionaryFile()
|
|
{
|
|
return _pDictionaryFile;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// SetupPunctuationPair
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCompositionProcessorEngine::SetupPunctuationPair()
|
|
{
|
|
// Punctuation pair
|
|
const int pair_count = 2;
|
|
CPunctuationPair punc_quotation_mark(L'"', 0x201C, 0x201D);
|
|
CPunctuationPair punc_apostrophe(L'\'', 0x2018, 0x2019);
|
|
|
|
CPunctuationPair puncPairs[pair_count] = {
|
|
punc_quotation_mark,
|
|
punc_apostrophe,
|
|
};
|
|
|
|
for (int i = 0; i < pair_count; ++i)
|
|
{
|
|
CPunctuationPair *pPuncPair = _PunctuationPair.Append();
|
|
*pPuncPair = puncPairs[i];
|
|
}
|
|
|
|
// Punctuation nest pair
|
|
CPunctuationNestPair punc_angle_bracket(L'<', 0x300A, 0x3008, L'>', 0x300B, 0x3009);
|
|
|
|
CPunctuationNestPair* pPuncNestPair = _PunctuationNestPair.Append();
|
|
*pPuncNestPair = punc_angle_bracket;
|
|
}
|
|
|
|
void CCompositionProcessorEngine::InitializeSampleIMECompartment(_In_ ITfThreadMgr *pThreadMgr, TfClientId tfClientId)
|
|
{
|
|
// set initial mode
|
|
CCompartment CompartmentKeyboardOpen(pThreadMgr, tfClientId, GUID_COMPARTMENT_KEYBOARD_OPENCLOSE);
|
|
CompartmentKeyboardOpen._SetCompartmentBOOL(TRUE);
|
|
|
|
CCompartment CompartmentDoubleSingleByte(pThreadMgr, tfClientId, Global::SampleIMEGuidCompartmentDoubleSingleByte);
|
|
CompartmentDoubleSingleByte._SetCompartmentBOOL(FALSE);
|
|
|
|
CCompartment CompartmentPunctuation(pThreadMgr, tfClientId, Global::SampleIMEGuidCompartmentPunctuation);
|
|
CompartmentPunctuation._SetCompartmentBOOL(TRUE);
|
|
|
|
PrivateCompartmentsUpdated(pThreadMgr);
|
|
}
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CompartmentCallback
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
// static
|
|
HRESULT CCompositionProcessorEngine::CompartmentCallback(_In_ void *pv, REFGUID guidCompartment)
|
|
{
|
|
CCompositionProcessorEngine* fakeThis = (CCompositionProcessorEngine*)pv;
|
|
if (nullptr == fakeThis)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
ITfThreadMgr* pThreadMgr = nullptr;
|
|
HRESULT hr = CoCreateInstance(CLSID_TF_ThreadMgr, nullptr, CLSCTX_INPROC_SERVER, IID_ITfThreadMgr, (void**)&pThreadMgr);
|
|
if (FAILED(hr))
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (IsEqualGUID(guidCompartment, Global::SampleIMEGuidCompartmentDoubleSingleByte) ||
|
|
IsEqualGUID(guidCompartment, Global::SampleIMEGuidCompartmentPunctuation))
|
|
{
|
|
fakeThis->PrivateCompartmentsUpdated(pThreadMgr);
|
|
}
|
|
else if (IsEqualGUID(guidCompartment, GUID_COMPARTMENT_KEYBOARD_INPUTMODE_CONVERSION) ||
|
|
IsEqualGUID(guidCompartment, GUID_COMPARTMENT_KEYBOARD_INPUTMODE_SENTENCE))
|
|
{
|
|
fakeThis->ConversionModeCompartmentUpdated(pThreadMgr);
|
|
}
|
|
else if (IsEqualGUID(guidCompartment, GUID_COMPARTMENT_KEYBOARD_OPENCLOSE))
|
|
{
|
|
fakeThis->KeyboardOpenCompartmentUpdated(pThreadMgr);
|
|
}
|
|
|
|
pThreadMgr->Release();
|
|
pThreadMgr = nullptr;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UpdatePrivateCompartments
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCompositionProcessorEngine::ConversionModeCompartmentUpdated(_In_ ITfThreadMgr *pThreadMgr)
|
|
{
|
|
if (!_pCompartmentConversion)
|
|
{
|
|
return;
|
|
}
|
|
|
|
DWORD conversionMode = 0;
|
|
if (FAILED(_pCompartmentConversion->_GetCompartmentDWORD(conversionMode)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
BOOL isDouble = FALSE;
|
|
CCompartment CompartmentDoubleSingleByte(pThreadMgr, _tfClientId, Global::SampleIMEGuidCompartmentDoubleSingleByte);
|
|
if (SUCCEEDED(CompartmentDoubleSingleByte._GetCompartmentBOOL(isDouble)))
|
|
{
|
|
if (!isDouble && (conversionMode & TF_CONVERSIONMODE_FULLSHAPE))
|
|
{
|
|
CompartmentDoubleSingleByte._SetCompartmentBOOL(TRUE);
|
|
}
|
|
else if (isDouble && !(conversionMode & TF_CONVERSIONMODE_FULLSHAPE))
|
|
{
|
|
CompartmentDoubleSingleByte._SetCompartmentBOOL(FALSE);
|
|
}
|
|
}
|
|
BOOL isPunctuation = FALSE;
|
|
CCompartment CompartmentPunctuation(pThreadMgr, _tfClientId, Global::SampleIMEGuidCompartmentPunctuation);
|
|
if (SUCCEEDED(CompartmentPunctuation._GetCompartmentBOOL(isPunctuation)))
|
|
{
|
|
if (!isPunctuation && (conversionMode & TF_CONVERSIONMODE_SYMBOL))
|
|
{
|
|
CompartmentPunctuation._SetCompartmentBOOL(TRUE);
|
|
}
|
|
else if (isPunctuation && !(conversionMode & TF_CONVERSIONMODE_SYMBOL))
|
|
{
|
|
CompartmentPunctuation._SetCompartmentBOOL(FALSE);
|
|
}
|
|
}
|
|
|
|
BOOL fOpen = FALSE;
|
|
CCompartment CompartmentKeyboardOpen(pThreadMgr, _tfClientId, GUID_COMPARTMENT_KEYBOARD_OPENCLOSE);
|
|
if (SUCCEEDED(CompartmentKeyboardOpen._GetCompartmentBOOL(fOpen)))
|
|
{
|
|
if (fOpen && !(conversionMode & TF_CONVERSIONMODE_NATIVE))
|
|
{
|
|
CompartmentKeyboardOpen._SetCompartmentBOOL(FALSE);
|
|
}
|
|
else if (!fOpen && (conversionMode & TF_CONVERSIONMODE_NATIVE))
|
|
{
|
|
CompartmentKeyboardOpen._SetCompartmentBOOL(TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// PrivateCompartmentsUpdated()
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCompositionProcessorEngine::PrivateCompartmentsUpdated(_In_ ITfThreadMgr *pThreadMgr)
|
|
{
|
|
if (!_pCompartmentConversion)
|
|
{
|
|
return;
|
|
}
|
|
|
|
DWORD conversionMode = 0;
|
|
DWORD conversionModePrev = 0;
|
|
if (FAILED(_pCompartmentConversion->_GetCompartmentDWORD(conversionMode)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
conversionModePrev = conversionMode;
|
|
|
|
BOOL isDouble = FALSE;
|
|
CCompartment CompartmentDoubleSingleByte(pThreadMgr, _tfClientId, Global::SampleIMEGuidCompartmentDoubleSingleByte);
|
|
if (SUCCEEDED(CompartmentDoubleSingleByte._GetCompartmentBOOL(isDouble)))
|
|
{
|
|
if (!isDouble && (conversionMode & TF_CONVERSIONMODE_FULLSHAPE))
|
|
{
|
|
conversionMode &= ~TF_CONVERSIONMODE_FULLSHAPE;
|
|
}
|
|
else if (isDouble && !(conversionMode & TF_CONVERSIONMODE_FULLSHAPE))
|
|
{
|
|
conversionMode |= TF_CONVERSIONMODE_FULLSHAPE;
|
|
}
|
|
}
|
|
|
|
BOOL isPunctuation = FALSE;
|
|
CCompartment CompartmentPunctuation(pThreadMgr, _tfClientId, Global::SampleIMEGuidCompartmentPunctuation);
|
|
if (SUCCEEDED(CompartmentPunctuation._GetCompartmentBOOL(isPunctuation)))
|
|
{
|
|
if (!isPunctuation && (conversionMode & TF_CONVERSIONMODE_SYMBOL))
|
|
{
|
|
conversionMode &= ~TF_CONVERSIONMODE_SYMBOL;
|
|
}
|
|
else if (isPunctuation && !(conversionMode & TF_CONVERSIONMODE_SYMBOL))
|
|
{
|
|
conversionMode |= TF_CONVERSIONMODE_SYMBOL;
|
|
}
|
|
}
|
|
|
|
if (conversionMode != conversionModePrev)
|
|
{
|
|
_pCompartmentConversion->_SetCompartmentDWORD(conversionMode);
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// KeyboardOpenCompartmentUpdated
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCompositionProcessorEngine::KeyboardOpenCompartmentUpdated(_In_ ITfThreadMgr *pThreadMgr)
|
|
{
|
|
if (!_pCompartmentConversion)
|
|
{
|
|
return;
|
|
}
|
|
|
|
DWORD conversionMode = 0;
|
|
DWORD conversionModePrev = 0;
|
|
if (FAILED(_pCompartmentConversion->_GetCompartmentDWORD(conversionMode)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
conversionModePrev = conversionMode;
|
|
|
|
BOOL isOpen = FALSE;
|
|
CCompartment CompartmentKeyboardOpen(pThreadMgr, _tfClientId, GUID_COMPARTMENT_KEYBOARD_OPENCLOSE);
|
|
if (SUCCEEDED(CompartmentKeyboardOpen._GetCompartmentBOOL(isOpen)))
|
|
{
|
|
if (isOpen && !(conversionMode & TF_CONVERSIONMODE_NATIVE))
|
|
{
|
|
conversionMode |= TF_CONVERSIONMODE_NATIVE;
|
|
}
|
|
else if (!isOpen && (conversionMode & TF_CONVERSIONMODE_NATIVE))
|
|
{
|
|
conversionMode &= ~TF_CONVERSIONMODE_NATIVE;
|
|
}
|
|
}
|
|
|
|
if (conversionMode != conversionModePrev)
|
|
{
|
|
_pCompartmentConversion->_SetCompartmentDWORD(conversionMode);
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// XPreservedKey implementation.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UninitPreservedKey
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CCompositionProcessorEngine::XPreservedKey::UninitPreservedKey(_In_ ITfThreadMgr *pThreadMgr)
|
|
{
|
|
ITfKeystrokeMgr* pKeystrokeMgr = nullptr;
|
|
|
|
if (IsEqualGUID(Guid, GUID_NULL))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (FAILED(pThreadMgr->QueryInterface(IID_ITfKeystrokeMgr, (void **)&pKeystrokeMgr)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
for (UINT i = 0; i < TSFPreservedKeyTable.Count(); i++)
|
|
{
|
|
TF_PRESERVEDKEY pPreservedKey = *TSFPreservedKeyTable.GetAt(i);
|
|
pPreservedKey.uModifiers &= 0xffff;
|
|
|
|
pKeystrokeMgr->UnpreserveKey(Guid, &pPreservedKey);
|
|
}
|
|
|
|
pKeystrokeMgr->Release();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
CCompositionProcessorEngine::XPreservedKey::XPreservedKey()
|
|
{
|
|
Guid = GUID_NULL;
|
|
Description = nullptr;
|
|
}
|
|
|
|
CCompositionProcessorEngine::XPreservedKey::~XPreservedKey()
|
|
{
|
|
ITfThreadMgr* pThreadMgr = nullptr;
|
|
|
|
HRESULT hr = CoCreateInstance(CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, IID_ITfThreadMgr, (void**)&pThreadMgr);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
UninitPreservedKey(pThreadMgr);
|
|
pThreadMgr->Release();
|
|
pThreadMgr = nullptr;
|
|
}
|
|
|
|
if (Description)
|
|
{
|
|
delete [] Description;
|
|
}
|
|
}
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CSampleIME::CreateInstance
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CSampleIME::CreateInstance(REFCLSID rclsid, REFIID riid, _Outptr_result_maybenull_ LPVOID* ppv, _Out_opt_ HINSTANCE* phInst, BOOL isComLessMode)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if (phInst == nullptr)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*phInst = nullptr;
|
|
|
|
if (!isComLessMode)
|
|
{
|
|
hr = ::CoCreateInstance(rclsid,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
riid,
|
|
ppv);
|
|
}
|
|
else
|
|
{
|
|
hr = CSampleIME::ComLessCreateInstance(rclsid, riid, ppv, phInst);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CSampleIME::ComLessCreateInstance
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CSampleIME::ComLessCreateInstance(REFGUID rclsid, REFIID riid, _Outptr_result_maybenull_ void **ppv, _Out_opt_ HINSTANCE *phInst)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HINSTANCE sampleIMEDllHandle = nullptr;
|
|
WCHAR wchPath[MAX_PATH] = {'\0'};
|
|
WCHAR szExpandedPath[MAX_PATH] = {'\0'};
|
|
DWORD dwCnt = 0;
|
|
*ppv = nullptr;
|
|
|
|
hr = phInst ? S_OK : E_FAIL;
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*phInst = nullptr;
|
|
hr = CSampleIME::GetComModuleName(rclsid, wchPath, ARRAYSIZE(wchPath));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
dwCnt = ExpandEnvironmentStringsW(wchPath, szExpandedPath, ARRAYSIZE(szExpandedPath));
|
|
hr = (0 < dwCnt && dwCnt <= ARRAYSIZE(szExpandedPath)) ? S_OK : E_FAIL;
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
sampleIMEDllHandle = LoadLibraryEx(szExpandedPath, NULL, 0);
|
|
hr = sampleIMEDllHandle ? S_OK : E_FAIL;
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*phInst = sampleIMEDllHandle;
|
|
FARPROC pfn = GetProcAddress(sampleIMEDllHandle, "DllGetClassObject");
|
|
hr = pfn ? S_OK : E_FAIL;
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IClassFactory *pClassFactory = nullptr;
|
|
hr = ((HRESULT (STDAPICALLTYPE *)(REFCLSID rclsid, REFIID riid, LPVOID *ppv))(pfn))(rclsid, IID_IClassFactory, (void **)&pClassFactory);
|
|
if (SUCCEEDED(hr) && pClassFactory)
|
|
{
|
|
hr = pClassFactory->CreateInstance(NULL, riid, ppv);
|
|
pClassFactory->Release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!SUCCEEDED(hr) && phInst && *phInst)
|
|
{
|
|
FreeLibrary(*phInst);
|
|
*phInst = 0;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CSampleIME::GetComModuleName
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CSampleIME::GetComModuleName(REFGUID rclsid, _Out_writes_(cchPath)WCHAR* wchPath, DWORD cchPath)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CRegKey key;
|
|
WCHAR wchClsid[CLSID_STRLEN + 1];
|
|
hr = CLSIDToString(rclsid, wchClsid) ? S_OK : E_FAIL;
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
WCHAR wchKey[MAX_PATH];
|
|
hr = StringCchPrintfW(wchKey, ARRAYSIZE(wchKey), L"CLSID\\%s\\InProcServer32", wchClsid);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = (key.Open(HKEY_CLASSES_ROOT, wchKey, KEY_READ) == ERROR_SUCCESS) ? S_OK : E_FAIL;
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
WCHAR wszModel[MAX_PATH];
|
|
ULONG cch = ARRAYSIZE(wszModel);
|
|
hr = (key.QueryStringValue(L"ThreadingModel", wszModel, &cch) == ERROR_SUCCESS) ? S_OK : E_FAIL;
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (CompareStringOrdinal(wszModel,
|
|
-1,
|
|
L"Apartment",
|
|
-1,
|
|
TRUE) == CSTR_EQUAL)
|
|
{
|
|
hr = (key.QueryStringValue(NULL, wchPath, &cchPath) == ERROR_SUCCESS) ? S_OK : E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
void CCompositionProcessorEngine::InitKeyStrokeTable()
|
|
{
|
|
for (int i = 0; i < 26; i++)
|
|
{
|
|
_keystrokeTable[i].VirtualKey = 'A' + i;
|
|
_keystrokeTable[i].Modifiers = 0;
|
|
_keystrokeTable[i].Function = FUNCTION_INPUT;
|
|
}
|
|
}
|
|
|
|
void CCompositionProcessorEngine::ShowAllLanguageBarIcons()
|
|
{
|
|
SetLanguageBarStatus(TF_LBI_STATUS_HIDDEN, FALSE);
|
|
}
|
|
|
|
void CCompositionProcessorEngine::HideAllLanguageBarIcons()
|
|
{
|
|
SetLanguageBarStatus(TF_LBI_STATUS_HIDDEN, TRUE);
|
|
}
|
|
|
|
void CCompositionProcessorEngine::SetInitialCandidateListRange()
|
|
{
|
|
for (DWORD i = 1; i <= 10; i++)
|
|
{
|
|
DWORD* pNewIndexRange = nullptr;
|
|
|
|
pNewIndexRange = _candidateListIndexRange.Append();
|
|
if (pNewIndexRange != nullptr)
|
|
{
|
|
if (i != 10)
|
|
{
|
|
*pNewIndexRange = i;
|
|
}
|
|
else
|
|
{
|
|
*pNewIndexRange = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CCompositionProcessorEngine::SetDefaultCandidateTextFont()
|
|
{
|
|
// Candidate Text Font
|
|
if (Global::defaultlFontHandle == nullptr)
|
|
{
|
|
WCHAR fontName[50] = {'\0'};
|
|
LoadString(Global::dllInstanceHandle, IDS_DEFAULT_FONT, fontName, 50);
|
|
Global::defaultlFontHandle = CreateFont(-MulDiv(10, GetDeviceCaps(GetDC(NULL), LOGPIXELSY), 72), 0, 0, 0, FW_MEDIUM, 0, 0, 0, 0, 0, 0, 0, 0, fontName);
|
|
if (!Global::defaultlFontHandle)
|
|
{
|
|
LOGFONT lf;
|
|
SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0);
|
|
// Fall back to the default GUI font on failure.
|
|
Global::defaultlFontHandle = CreateFont(-MulDiv(10, GetDeviceCaps(GetDC(NULL), LOGPIXELSY), 72), 0, 0, 0, FW_MEDIUM, 0, 0, 0, 0, 0, 0, 0, 0, lf.lfFaceName);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CCompositionProcessorEngine
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CCompositionProcessorEngine::IsVirtualKeyNeed
|
|
//
|
|
// Test virtual key code need to the Composition Processor Engine.
|
|
// param
|
|
// [in] uCode - Specify virtual key code.
|
|
// [in/out] pwch - char code
|
|
// [in] fComposing - Specified composing.
|
|
// [in] fCandidateMode - Specified candidate mode.
|
|
// [out] pKeyState - Returns function regarding virtual key.
|
|
// returns
|
|
// 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)
|
|
{
|
|
if (pKeyState)
|
|
{
|
|
pKeyState->Category = CATEGORY_NONE;
|
|
pKeyState->Function = FUNCTION_NONE;
|
|
}
|
|
|
|
if (candidateMode == CANDIDATE_ORIGINAL || candidateMode == CANDIDATE_PHRASE || candidateMode == CANDIDATE_WITH_NEXT_COMPOSITION)
|
|
{
|
|
fComposing = FALSE;
|
|
}
|
|
|
|
if (fComposing || candidateMode == CANDIDATE_INCREMENTAL || candidateMode == CANDIDATE_NONE)
|
|
{
|
|
if (IsVirtualKeyKeystrokeComposition(uCode, pKeyState, FUNCTION_NONE))
|
|
{
|
|
return TRUE;
|
|
}
|
|
else if ((IsWildcard() && IsWildcardChar(*pwch) && !IsDisableWildcardAtFirst()) ||
|
|
(IsWildcard() && IsWildcardChar(*pwch) && IsDisableWildcardAtFirst() && _keystrokeBuffer.GetLength()))
|
|
{
|
|
if (pKeyState)
|
|
{
|
|
pKeyState->Category = CATEGORY_COMPOSING;
|
|
pKeyState->Function = FUNCTION_INPUT;
|
|
}
|
|
return TRUE;
|
|
}
|
|
else if (_hasWildcardIncludedInKeystrokeBuffer && uCode == VK_SPACE)
|
|
{
|
|
if (pKeyState) { pKeyState->Category = CATEGORY_COMPOSING; pKeyState->Function = FUNCTION_CONVERT_WILDCARD; } return TRUE;
|
|
}
|
|
}
|
|
|
|
if (candidateMode == CANDIDATE_ORIGINAL || candidateMode == CANDIDATE_PHRASE || candidateMode == CANDIDATE_WITH_NEXT_COMPOSITION)
|
|
{
|
|
BOOL isRetCode = TRUE;
|
|
if (IsVirtualKeyKeystrokeCandidate(uCode, pKeyState, candidateMode, &isRetCode, &_KeystrokeCandidate))
|
|
{
|
|
return isRetCode;
|
|
}
|
|
|
|
if (hasCandidateWithWildcard)
|
|
{
|
|
if (IsVirtualKeyKeystrokeCandidate(uCode, pKeyState, candidateMode, &isRetCode, &_KeystrokeCandidateWildcard))
|
|
{
|
|
return isRetCode;
|
|
}
|
|
}
|
|
|
|
// Candidate list could not handle key. We can try to restart the composition.
|
|
if (IsVirtualKeyKeystrokeComposition(uCode, pKeyState, FUNCTION_INPUT))
|
|
{
|
|
if (candidateMode != CANDIDATE_ORIGINAL)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (pKeyState) { pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_FINALIZE_CANDIDATELIST_AND_INPUT; }
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// CANDIDATE_INCREMENTAL should process Keystroke.Candidate virtual keys.
|
|
else if (candidateMode == CANDIDATE_INCREMENTAL)
|
|
{
|
|
BOOL isRetCode = TRUE;
|
|
if (IsVirtualKeyKeystrokeCandidate(uCode, pKeyState, candidateMode, &isRetCode, &_KeystrokeCandidate))
|
|
{
|
|
return isRetCode;
|
|
}
|
|
}
|
|
|
|
if (!fComposing && candidateMode != CANDIDATE_ORIGINAL && candidateMode != CANDIDATE_PHRASE && candidateMode != CANDIDATE_WITH_NEXT_COMPOSITION)
|
|
{
|
|
if (IsVirtualKeyKeystrokeComposition(uCode, pKeyState, FUNCTION_INPUT))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// System pre-defined keystroke
|
|
if (fComposing)
|
|
{
|
|
if ((candidateMode != CANDIDATE_INCREMENTAL))
|
|
{
|
|
switch (uCode)
|
|
{
|
|
case VK_LEFT: if (pKeyState) { pKeyState->Category = CATEGORY_COMPOSING; pKeyState->Function = FUNCTION_MOVE_LEFT; } return TRUE;
|
|
case VK_RIGHT: if (pKeyState) { pKeyState->Category = CATEGORY_COMPOSING; pKeyState->Function = FUNCTION_MOVE_RIGHT; } return TRUE;
|
|
case VK_RETURN: if (pKeyState) { pKeyState->Category = CATEGORY_COMPOSING; pKeyState->Function = FUNCTION_FINALIZE_CANDIDATELIST; } return TRUE;
|
|
case VK_ESCAPE: if (pKeyState) { pKeyState->Category = CATEGORY_COMPOSING; pKeyState->Function = FUNCTION_CANCEL; } return TRUE;
|
|
case VK_BACK: if (pKeyState) { pKeyState->Category = CATEGORY_COMPOSING; pKeyState->Function = FUNCTION_BACKSPACE; } return TRUE;
|
|
|
|
case VK_UP: if (pKeyState) { pKeyState->Category = CATEGORY_COMPOSING; pKeyState->Function = FUNCTION_MOVE_UP; } return TRUE;
|
|
case VK_DOWN: if (pKeyState) { pKeyState->Category = CATEGORY_COMPOSING; pKeyState->Function = FUNCTION_MOVE_DOWN; } return TRUE;
|
|
case VK_PRIOR: if (pKeyState) { pKeyState->Category = CATEGORY_COMPOSING; pKeyState->Function = FUNCTION_MOVE_PAGE_UP; } return TRUE;
|
|
case VK_NEXT: if (pKeyState) { pKeyState->Category = CATEGORY_COMPOSING; pKeyState->Function = FUNCTION_MOVE_PAGE_DOWN; } return TRUE;
|
|
|
|
case VK_HOME: if (pKeyState) { pKeyState->Category = CATEGORY_COMPOSING; pKeyState->Function = FUNCTION_MOVE_PAGE_TOP; } return TRUE;
|
|
case VK_END: if (pKeyState) { pKeyState->Category = CATEGORY_COMPOSING; pKeyState->Function = FUNCTION_MOVE_PAGE_BOTTOM; } return TRUE;
|
|
|
|
case VK_SPACE: if (pKeyState) { pKeyState->Category = CATEGORY_COMPOSING; pKeyState->Function = FUNCTION_CONVERT; } return TRUE;
|
|
}
|
|
}
|
|
else if ((candidateMode == CANDIDATE_INCREMENTAL))
|
|
{
|
|
switch (uCode)
|
|
{
|
|
// VK_LEFT, VK_RIGHT - set *pIsEaten = FALSE for application could move caret left or right.
|
|
// and for CUAS, invoke _HandleCompositionCancel() edit session due to ignore CUAS default key handler for send out terminate composition
|
|
case VK_LEFT:
|
|
case VK_RIGHT:
|
|
{
|
|
if (pKeyState)
|
|
{
|
|
pKeyState->Category = CATEGORY_INVOKE_COMPOSITION_EDIT_SESSION;
|
|
pKeyState->Function = FUNCTION_CANCEL;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case VK_RETURN: if (pKeyState) { pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_FINALIZE_CANDIDATELIST; } return TRUE;
|
|
case VK_ESCAPE: if (pKeyState) { pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_CANCEL; } return TRUE;
|
|
|
|
// VK_BACK - remove one char from reading string.
|
|
case VK_BACK: if (pKeyState) { pKeyState->Category = CATEGORY_COMPOSING; pKeyState->Function = FUNCTION_BACKSPACE; } return TRUE;
|
|
|
|
case VK_UP: if (pKeyState) { pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_MOVE_UP; } return TRUE;
|
|
case VK_DOWN: if (pKeyState) { pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_MOVE_DOWN; } return TRUE;
|
|
case VK_PRIOR: if (pKeyState) { pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_MOVE_PAGE_UP; } return TRUE;
|
|
case VK_NEXT: if (pKeyState) { pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_MOVE_PAGE_DOWN; } return TRUE;
|
|
|
|
case VK_HOME: if (pKeyState) { pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_MOVE_PAGE_TOP; } return TRUE;
|
|
case VK_END: if (pKeyState) { pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_MOVE_PAGE_BOTTOM; } return TRUE;
|
|
|
|
case VK_SPACE:
|
|
{
|
|
if (candidateMode == CANDIDATE_INCREMENTAL)
|
|
{
|
|
if (pKeyState) { pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_CONVERT; } return TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (pKeyState) { pKeyState->Category = CATEGORY_COMPOSING; pKeyState->Function = FUNCTION_CONVERT; } return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((candidateMode == CANDIDATE_ORIGINAL) || (candidateMode == CANDIDATE_WITH_NEXT_COMPOSITION))
|
|
{
|
|
switch (uCode)
|
|
{
|
|
case VK_UP: if (pKeyState) { pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_MOVE_UP; } return TRUE;
|
|
case VK_DOWN: if (pKeyState) { pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_MOVE_DOWN; } return TRUE;
|
|
case VK_PRIOR: if (pKeyState) { pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_MOVE_PAGE_UP; } return TRUE;
|
|
case VK_NEXT: if (pKeyState) { pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_MOVE_PAGE_DOWN; } return TRUE;
|
|
case VK_HOME: if (pKeyState) { pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_MOVE_PAGE_TOP; } return TRUE;
|
|
case VK_END: if (pKeyState) { pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_MOVE_PAGE_BOTTOM; } return TRUE;
|
|
case VK_RETURN: if (pKeyState) { pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_FINALIZE_CANDIDATELIST; } return TRUE;
|
|
case VK_SPACE: if (pKeyState) { pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_CONVERT; } return TRUE;
|
|
case VK_BACK: if (pKeyState) { pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_CANCEL; } return TRUE;
|
|
|
|
case VK_ESCAPE:
|
|
{
|
|
if (candidateMode == CANDIDATE_WITH_NEXT_COMPOSITION)
|
|
{
|
|
if (pKeyState)
|
|
{
|
|
pKeyState->Category = CATEGORY_INVOKE_COMPOSITION_EDIT_SESSION;
|
|
pKeyState->Function = FUNCTION_FINALIZE_TEXTSTORE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (pKeyState)
|
|
{
|
|
pKeyState->Category = CATEGORY_CANDIDATE;
|
|
pKeyState->Function = FUNCTION_CANCEL;
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (candidateMode == CANDIDATE_WITH_NEXT_COMPOSITION)
|
|
{
|
|
if (IsVirtualKeyKeystrokeComposition(uCode, NULL, FUNCTION_NONE))
|
|
{
|
|
if (pKeyState) { pKeyState->Category = CATEGORY_COMPOSING; pKeyState->Function = FUNCTION_FINALIZE_TEXTSTORE_AND_INPUT; } return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (candidateMode == CANDIDATE_PHRASE)
|
|
{
|
|
switch (uCode)
|
|
{
|
|
case VK_UP: if (pKeyState) { pKeyState->Category = CATEGORY_PHRASE; pKeyState->Function = FUNCTION_MOVE_UP; } return TRUE;
|
|
case VK_DOWN: if (pKeyState) { pKeyState->Category = CATEGORY_PHRASE; pKeyState->Function = FUNCTION_MOVE_DOWN; } return TRUE;
|
|
case VK_PRIOR: if (pKeyState) { pKeyState->Category = CATEGORY_PHRASE; pKeyState->Function = FUNCTION_MOVE_PAGE_UP; } return TRUE;
|
|
case VK_NEXT: if (pKeyState) { pKeyState->Category = CATEGORY_PHRASE; pKeyState->Function = FUNCTION_MOVE_PAGE_DOWN; } return TRUE;
|
|
case VK_HOME: if (pKeyState) { pKeyState->Category = CATEGORY_PHRASE; pKeyState->Function = FUNCTION_MOVE_PAGE_TOP; } return TRUE;
|
|
case VK_END: if (pKeyState) { pKeyState->Category = CATEGORY_PHRASE; pKeyState->Function = FUNCTION_MOVE_PAGE_BOTTOM; } return TRUE;
|
|
case VK_RETURN: if (pKeyState) { pKeyState->Category = CATEGORY_PHRASE; pKeyState->Function = FUNCTION_FINALIZE_CANDIDATELIST; } return TRUE;
|
|
case VK_SPACE: if (pKeyState) { pKeyState->Category = CATEGORY_PHRASE; pKeyState->Function = FUNCTION_CONVERT; } return TRUE;
|
|
case VK_ESCAPE: if (pKeyState) { pKeyState->Category = CATEGORY_PHRASE; pKeyState->Function = FUNCTION_CANCEL; } return TRUE;
|
|
case VK_BACK: if (pKeyState) { pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_CANCEL; } return TRUE;
|
|
}
|
|
}
|
|
|
|
if (IsKeystrokeRange(uCode, pKeyState, candidateMode))
|
|
{
|
|
return TRUE;
|
|
}
|
|
else if (pKeyState && pKeyState->Category != CATEGORY_NONE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (*pwch && !IsVirtualKeyKeystrokeComposition(uCode, pKeyState, FUNCTION_NONE))
|
|
{
|
|
if (pKeyState)
|
|
{
|
|
pKeyState->Category = CATEGORY_INVOKE_COMPOSITION_EDIT_SESSION;
|
|
pKeyState->Function = FUNCTION_FINALIZE_TEXTSTORE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CCompositionProcessorEngine::IsVirtualKeyKeystrokeComposition
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CCompositionProcessorEngine::IsVirtualKeyKeystrokeComposition(UINT uCode, _Out_opt_ _KEYSTROKE_STATE *pKeyState, KEYSTROKE_FUNCTION function)
|
|
{
|
|
if (pKeyState == nullptr)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pKeyState->Category = CATEGORY_NONE;
|
|
pKeyState->Function = FUNCTION_NONE;
|
|
|
|
for (UINT i = 0; i < _KeystrokeComposition.Count(); i++)
|
|
{
|
|
_KEYSTROKE *pKeystroke = nullptr;
|
|
|
|
pKeystroke = _KeystrokeComposition.GetAt(i);
|
|
|
|
if ((pKeystroke->VirtualKey == uCode) && Global::CheckModifiers(Global::ModifiersValue, pKeystroke->Modifiers))
|
|
{
|
|
if (function == FUNCTION_NONE)
|
|
{
|
|
pKeyState->Category = CATEGORY_COMPOSING;
|
|
pKeyState->Function = pKeystroke->Function;
|
|
return TRUE;
|
|
}
|
|
else if (function == pKeystroke->Function)
|
|
{
|
|
pKeyState->Category = CATEGORY_COMPOSING;
|
|
pKeyState->Function = pKeystroke->Function;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CCompositionProcessorEngine::IsVirtualKeyKeystrokeCandidate
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CCompositionProcessorEngine::IsVirtualKeyKeystrokeCandidate(UINT uCode, _In_ _KEYSTROKE_STATE *pKeyState, CANDIDATE_MODE candidateMode, _Out_ BOOL *pfRetCode, _In_ CSampleImeArray<_KEYSTROKE> *pKeystrokeMetric)
|
|
{
|
|
if (pfRetCode == nullptr)
|
|
{
|
|
return FALSE;
|
|
}
|
|
*pfRetCode = FALSE;
|
|
|
|
for (UINT i = 0; i < pKeystrokeMetric->Count(); i++)
|
|
{
|
|
_KEYSTROKE *pKeystroke = nullptr;
|
|
|
|
pKeystroke = pKeystrokeMetric->GetAt(i);
|
|
|
|
if ((pKeystroke->VirtualKey == uCode) && Global::CheckModifiers(Global::ModifiersValue, pKeystroke->Modifiers))
|
|
{
|
|
*pfRetCode = TRUE;
|
|
if (pKeyState)
|
|
{
|
|
pKeyState->Category = (candidateMode == CANDIDATE_ORIGINAL ? CATEGORY_CANDIDATE :
|
|
candidateMode == CANDIDATE_PHRASE ? CATEGORY_PHRASE : CATEGORY_CANDIDATE);
|
|
|
|
pKeyState->Function = pKeystroke->Function;
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CCompositionProcessorEngine::IsKeyKeystrokeRange
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CCompositionProcessorEngine::IsKeystrokeRange(UINT uCode, _Out_ _KEYSTROKE_STATE *pKeyState, CANDIDATE_MODE candidateMode)
|
|
{
|
|
if (pKeyState == nullptr)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pKeyState->Category = CATEGORY_NONE;
|
|
pKeyState->Function = FUNCTION_NONE;
|
|
|
|
if (_candidateListIndexRange.IsRange(uCode))
|
|
{
|
|
if (candidateMode == CANDIDATE_PHRASE)
|
|
{
|
|
// Candidate phrase could specify modifier
|
|
if ((GetCandidateListPhraseModifier() == 0 && Global::ModifiersValue == 0) ||
|
|
(GetCandidateListPhraseModifier() != 0 && Global::CheckModifiers(Global::ModifiersValue, GetCandidateListPhraseModifier())))
|
|
{
|
|
pKeyState->Category = CATEGORY_PHRASE; pKeyState->Function = FUNCTION_SELECT_BY_NUMBER;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
pKeyState->Category = CATEGORY_INVOKE_COMPOSITION_EDIT_SESSION; pKeyState->Function = FUNCTION_FINALIZE_TEXTSTORE_AND_INPUT;
|
|
return FALSE;
|
|
}
|
|
}
|
|
else if (candidateMode == CANDIDATE_WITH_NEXT_COMPOSITION)
|
|
{
|
|
// Candidate phrase could specify modifier
|
|
if ((GetCandidateListPhraseModifier() == 0 && Global::ModifiersValue == 0) ||
|
|
(GetCandidateListPhraseModifier() != 0 && Global::CheckModifiers(Global::ModifiersValue, GetCandidateListPhraseModifier())))
|
|
{
|
|
pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_SELECT_BY_NUMBER;
|
|
return TRUE;
|
|
}
|
|
// else next composition
|
|
}
|
|
else if (candidateMode != CANDIDATE_NONE)
|
|
{
|
|
pKeyState->Category = CATEGORY_CANDIDATE; pKeyState->Function = FUNCTION_SELECT_BY_NUMBER;
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
} |