432 lines
10 KiB
C++
432 lines
10 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 "globals.h"
|
|
#include "SampleIME.h"
|
|
#include "CandidateListUIPresenter.h"
|
|
#include "CompositionProcessorEngine.h"
|
|
#include "Compartment.h"
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CreateInstance
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
/* static */
|
|
HRESULT CSampleIME::CreateInstance(_In_ IUnknown *pUnkOuter, REFIID riid, _Outptr_ void **ppvObj)
|
|
{
|
|
CSampleIME* pSampleIME = nullptr;
|
|
HRESULT hr = S_OK;
|
|
|
|
if (ppvObj == nullptr)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*ppvObj = nullptr;
|
|
|
|
if (nullptr != pUnkOuter)
|
|
{
|
|
return CLASS_E_NOAGGREGATION;
|
|
}
|
|
|
|
pSampleIME = new (std::nothrow) CSampleIME();
|
|
if (pSampleIME == nullptr)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
hr = pSampleIME->QueryInterface(riid, ppvObj);
|
|
|
|
pSampleIME->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ctor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CSampleIME::CSampleIME()
|
|
{
|
|
DllAddRef();
|
|
|
|
_pThreadMgr = nullptr;
|
|
|
|
_threadMgrEventSinkCookie = TF_INVALID_COOKIE;
|
|
|
|
_pTextEditSinkContext = nullptr;
|
|
_textEditSinkCookie = TF_INVALID_COOKIE;
|
|
|
|
_activeLanguageProfileNotifySinkCookie = TF_INVALID_COOKIE;
|
|
|
|
_dwThreadFocusSinkCookie = TF_INVALID_COOKIE;
|
|
|
|
_pComposition = nullptr;
|
|
|
|
_pCompositionProcessorEngine = nullptr;
|
|
|
|
_candidateMode = CANDIDATE_NONE;
|
|
_pCandidateListUIPresenter = nullptr;
|
|
_isCandidateWithWildcard = FALSE;
|
|
|
|
_pDocMgrLastFocused = nullptr;
|
|
|
|
_pSIPIMEOnOffCompartment = nullptr;
|
|
_dwSIPIMEOnOffCompartmentSinkCookie = 0;
|
|
_msgWndHandle = nullptr;
|
|
|
|
_pContext = nullptr;
|
|
|
|
_refCount = 1;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// dtor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CSampleIME::~CSampleIME()
|
|
{
|
|
if (_pCandidateListUIPresenter)
|
|
{
|
|
delete _pCandidateListUIPresenter;
|
|
_pCandidateListUIPresenter = nullptr;
|
|
}
|
|
DllRelease();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// QueryInterface
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CSampleIME::QueryInterface(REFIID riid, _Outptr_ void **ppvObj)
|
|
{
|
|
if (ppvObj == nullptr)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*ppvObj = nullptr;
|
|
|
|
if (IsEqualIID(riid, IID_IUnknown) ||
|
|
IsEqualIID(riid, IID_ITfTextInputProcessor))
|
|
{
|
|
*ppvObj = (ITfTextInputProcessor *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_ITfTextInputProcessorEx))
|
|
{
|
|
*ppvObj = (ITfTextInputProcessorEx *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_ITfThreadMgrEventSink))
|
|
{
|
|
*ppvObj = (ITfThreadMgrEventSink *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_ITfTextEditSink))
|
|
{
|
|
*ppvObj = (ITfTextEditSink *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_ITfKeyEventSink))
|
|
{
|
|
*ppvObj = (ITfKeyEventSink *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_ITfActiveLanguageProfileNotifySink))
|
|
{
|
|
*ppvObj = (ITfActiveLanguageProfileNotifySink *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_ITfCompositionSink))
|
|
{
|
|
*ppvObj = (ITfKeyEventSink *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_ITfDisplayAttributeProvider))
|
|
{
|
|
*ppvObj = (ITfDisplayAttributeProvider *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_ITfThreadFocusSink))
|
|
{
|
|
*ppvObj = (ITfThreadFocusSink *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_ITfFunctionProvider))
|
|
{
|
|
*ppvObj = (ITfFunctionProvider *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_ITfFunction))
|
|
{
|
|
*ppvObj = (ITfFunction *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_ITfFnGetPreferredTouchKeyboardLayout))
|
|
{
|
|
*ppvObj = (ITfFnGetPreferredTouchKeyboardLayout *)this;
|
|
}
|
|
|
|
if (*ppvObj)
|
|
{
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// AddRef
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI_(ULONG) CSampleIME::AddRef()
|
|
{
|
|
return ++_refCount;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Release
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI_(ULONG) CSampleIME::Release()
|
|
{
|
|
LONG cr = --_refCount;
|
|
|
|
assert(_refCount >= 0);
|
|
|
|
if (_refCount == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
return cr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ITfTextInputProcessorEx::ActivateEx
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CSampleIME::ActivateEx(ITfThreadMgr *pThreadMgr, TfClientId tfClientId, DWORD dwFlags)
|
|
{
|
|
_pThreadMgr = pThreadMgr;
|
|
_pThreadMgr->AddRef();
|
|
|
|
_tfClientId = tfClientId;
|
|
_dwActivateFlags = dwFlags;
|
|
|
|
if (!_InitThreadMgrEventSink())
|
|
{
|
|
goto ExitError;
|
|
}
|
|
|
|
ITfDocumentMgr* pDocMgrFocus = nullptr;
|
|
if (SUCCEEDED(_pThreadMgr->GetFocus(&pDocMgrFocus)) && (pDocMgrFocus != nullptr))
|
|
{
|
|
_InitTextEditSink(pDocMgrFocus);
|
|
pDocMgrFocus->Release();
|
|
}
|
|
|
|
if (!_InitKeyEventSink())
|
|
{
|
|
goto ExitError;
|
|
}
|
|
|
|
if (!_InitActiveLanguageProfileNotifySink())
|
|
{
|
|
goto ExitError;
|
|
}
|
|
|
|
if (!_InitThreadFocusSink())
|
|
{
|
|
goto ExitError;
|
|
}
|
|
|
|
if (!_InitDisplayAttributeGuidAtom())
|
|
{
|
|
goto ExitError;
|
|
}
|
|
|
|
if (!_InitFunctionProviderSink())
|
|
{
|
|
goto ExitError;
|
|
}
|
|
|
|
if (!_AddTextProcessorEngine())
|
|
{
|
|
goto ExitError;
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
ExitError:
|
|
Deactivate();
|
|
return E_FAIL;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ITfTextInputProcessorEx::Deactivate
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CSampleIME::Deactivate()
|
|
{
|
|
if (_pCompositionProcessorEngine)
|
|
{
|
|
delete _pCompositionProcessorEngine;
|
|
_pCompositionProcessorEngine = nullptr;
|
|
}
|
|
|
|
ITfContext* pContext = _pContext;
|
|
if (_pContext)
|
|
{
|
|
pContext->AddRef();
|
|
_EndComposition(_pContext);
|
|
}
|
|
|
|
if (_pCandidateListUIPresenter)
|
|
{
|
|
delete _pCandidateListUIPresenter;
|
|
_pCandidateListUIPresenter = nullptr;
|
|
|
|
if (pContext)
|
|
{
|
|
pContext->Release();
|
|
}
|
|
|
|
_candidateMode = CANDIDATE_NONE;
|
|
_isCandidateWithWildcard = FALSE;
|
|
}
|
|
|
|
_UninitFunctionProviderSink();
|
|
|
|
_UninitThreadFocusSink();
|
|
|
|
_UninitActiveLanguageProfileNotifySink();
|
|
|
|
_UninitKeyEventSink();
|
|
|
|
_UninitThreadMgrEventSink();
|
|
|
|
CCompartment CompartmentKeyboardOpen(_pThreadMgr, _tfClientId, GUID_COMPARTMENT_KEYBOARD_OPENCLOSE);
|
|
CompartmentKeyboardOpen._ClearCompartment();
|
|
|
|
CCompartment CompartmentDoubleSingleByte(_pThreadMgr, _tfClientId, Global::SampleIMEGuidCompartmentDoubleSingleByte);
|
|
CompartmentDoubleSingleByte._ClearCompartment();
|
|
|
|
CCompartment CompartmentPunctuation(_pThreadMgr, _tfClientId, Global::SampleIMEGuidCompartmentPunctuation);
|
|
CompartmentDoubleSingleByte._ClearCompartment();
|
|
|
|
if (_pThreadMgr != nullptr)
|
|
{
|
|
_pThreadMgr->Release();
|
|
}
|
|
|
|
_tfClientId = TF_CLIENTID_NULL;
|
|
|
|
if (_pDocMgrLastFocused)
|
|
{
|
|
_pDocMgrLastFocused->Release();
|
|
_pDocMgrLastFocused = nullptr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ITfFunctionProvider::GetType
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CSampleIME::GetType(__RPC__out GUID *pguid)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
if (pguid)
|
|
{
|
|
*pguid = Global::SampleIMECLSID;
|
|
hr = S_OK;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ITfFunctionProvider::::GetDescription
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CSampleIME::GetDescription(__RPC__deref_out_opt BSTR *pbstrDesc)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
if (pbstrDesc != nullptr)
|
|
{
|
|
*pbstrDesc = nullptr;
|
|
hr = E_NOTIMPL;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ITfFunctionProvider::::GetFunction
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CSampleIME::GetFunction(__RPC__in REFGUID rguid, __RPC__in REFIID riid, __RPC__deref_out_opt IUnknown **ppunk)
|
|
{
|
|
HRESULT hr = E_NOINTERFACE;
|
|
|
|
if ((IsEqualGUID(rguid, GUID_NULL))
|
|
&& (IsEqualGUID(riid, __uuidof(ITfFnSearchCandidateProvider))))
|
|
{
|
|
hr = _pITfFnSearchCandidateProvider->QueryInterface(riid, (void**)ppunk);
|
|
}
|
|
else if (IsEqualGUID(rguid, GUID_NULL))
|
|
{
|
|
hr = QueryInterface(riid, (void **)ppunk);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ITfFunction::GetDisplayName
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CSampleIME::GetDisplayName(_Out_ BSTR *pbstrDisplayName)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
if (pbstrDisplayName != nullptr)
|
|
{
|
|
*pbstrDisplayName = nullptr;
|
|
hr = E_NOTIMPL;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ITfFnGetPreferredTouchKeyboardLayout::GetLayout
|
|
// The tkblayout will be Optimized layout.
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CSampleIME::GetLayout(_Out_ TKBLayoutType *ptkblayoutType, _Out_ WORD *pwPreferredLayoutId)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
if ((ptkblayoutType != nullptr) && (pwPreferredLayoutId != nullptr))
|
|
{
|
|
*ptkblayoutType = TKBLT_OPTIMIZED;
|
|
*pwPreferredLayoutId = TKBL_OPT_SIMPLIFIED_CHINESE_PINYIN;
|
|
hr = S_OK;
|
|
}
|
|
return hr;
|
|
} |