663 lines
16 KiB
C++
663 lines
16 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 "LanguageBar.h"
|
|
#include "Globals.h"
|
|
#include "Compartment.h"
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CSampleIME::_UpdateLanguageBarOnSetFocus
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CSampleIME::_UpdateLanguageBarOnSetFocus(_In_ ITfDocumentMgr *pDocMgrFocus)
|
|
{
|
|
BOOL needDisableButtons = FALSE;
|
|
|
|
if (!pDocMgrFocus)
|
|
{
|
|
needDisableButtons = TRUE;
|
|
}
|
|
else
|
|
{
|
|
IEnumTfContexts* pEnumContext = nullptr;
|
|
|
|
if (FAILED(pDocMgrFocus->EnumContexts(&pEnumContext)) || !pEnumContext)
|
|
{
|
|
needDisableButtons = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ULONG fetched = 0;
|
|
ITfContext* pContext = nullptr;
|
|
|
|
if (FAILED(pEnumContext->Next(1, &pContext, &fetched)) || fetched != 1)
|
|
{
|
|
needDisableButtons = TRUE;
|
|
}
|
|
|
|
if (!pContext)
|
|
{
|
|
// context is not associated
|
|
needDisableButtons = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pContext->Release();
|
|
}
|
|
}
|
|
|
|
if (pEnumContext)
|
|
{
|
|
pEnumContext->Release();
|
|
}
|
|
}
|
|
|
|
CCompositionProcessorEngine* pCompositionProcessorEngine = nullptr;
|
|
pCompositionProcessorEngine = _pCompositionProcessorEngine;
|
|
|
|
pCompositionProcessorEngine->SetLanguageBarStatus(TF_LBI_STATUS_DISABLED, needDisableButtons);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CCompositionProcessorEngine::SetLanguageBarStatus
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
VOID CCompositionProcessorEngine::SetLanguageBarStatus(DWORD status, BOOL isSet)
|
|
{
|
|
if (_pLanguageBar_IMEMode) {
|
|
_pLanguageBar_IMEMode->SetStatus(status, isSet);
|
|
}
|
|
if (_pLanguageBar_DoubleSingleByte) {
|
|
_pLanguageBar_DoubleSingleByte->SetStatus(status, isSet);
|
|
}
|
|
if (_pLanguageBar_Punctuation) {
|
|
_pLanguageBar_Punctuation->SetStatus(status, isSet);
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CLangBarItemButton::ctor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CLangBarItemButton::CLangBarItemButton(REFGUID guidLangBar, LPCWSTR description, LPCWSTR tooltip, DWORD onIconIndex, DWORD offIconIndex, BOOL isSecureMode)
|
|
{
|
|
DWORD bufLen = 0;
|
|
|
|
DllAddRef();
|
|
|
|
// initialize TF_LANGBARITEMINFO structure.
|
|
_tfLangBarItemInfo.clsidService = Global::SampleIMECLSID; // This LangBarItem belongs to this TextService.
|
|
_tfLangBarItemInfo.guidItem = guidLangBar; // GUID of this LangBarItem.
|
|
_tfLangBarItemInfo.dwStyle = (TF_LBI_STYLE_BTN_BUTTON | TF_LBI_STYLE_SHOWNINTRAY); // This LangBar is a button type.
|
|
_tfLangBarItemInfo.ulSort = 0; // The position of this LangBar Item is not specified.
|
|
StringCchCopy(_tfLangBarItemInfo.szDescription, ARRAYSIZE(_tfLangBarItemInfo.szDescription), description); // Set the description of this LangBar Item.
|
|
|
|
// Initialize the sink pointer to NULL.
|
|
_pLangBarItemSink = nullptr;
|
|
|
|
// Initialize ICON index and file name.
|
|
_onIconIndex = onIconIndex;
|
|
_offIconIndex = offIconIndex;
|
|
|
|
// Initialize compartment.
|
|
_pCompartment = nullptr;
|
|
_pCompartmentEventSink = nullptr;
|
|
|
|
_isAddedToLanguageBar = FALSE;
|
|
_isSecureMode = isSecureMode;
|
|
_status = 0;
|
|
|
|
_refCount = 1;
|
|
|
|
// Initialize Tooltip
|
|
_pTooltipText = nullptr;
|
|
if (tooltip)
|
|
{
|
|
size_t len = 0;
|
|
if (StringCchLength(tooltip, STRSAFE_MAX_CCH, &len) != S_OK)
|
|
{
|
|
len = 0;
|
|
}
|
|
bufLen = static_cast<DWORD>(len) + 1;
|
|
_pTooltipText = (LPCWSTR) new (std::nothrow) WCHAR[ bufLen ];
|
|
if (_pTooltipText)
|
|
{
|
|
StringCchCopy((LPWSTR)_pTooltipText, bufLen, tooltip);
|
|
}
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CLangBarItemButton::dtor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CLangBarItemButton::~CLangBarItemButton()
|
|
{
|
|
DllRelease();
|
|
CleanUp();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CLangBarItemButton::CleanUp
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CLangBarItemButton::CleanUp()
|
|
{
|
|
if (_pTooltipText)
|
|
{
|
|
delete [] _pTooltipText;
|
|
_pTooltipText = nullptr;
|
|
}
|
|
|
|
ITfThreadMgr* pThreadMgr = nullptr;
|
|
HRESULT hr = CoCreateInstance(CLSID_TF_ThreadMgr,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_ITfThreadMgr,
|
|
(void**)&pThreadMgr);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
_UnregisterCompartment(pThreadMgr);
|
|
|
|
_RemoveItem(pThreadMgr);
|
|
pThreadMgr->Release();
|
|
pThreadMgr = nullptr;
|
|
}
|
|
|
|
if (_pCompartment)
|
|
{
|
|
delete _pCompartment;
|
|
_pCompartment = nullptr;
|
|
}
|
|
|
|
if (_pCompartmentEventSink)
|
|
{
|
|
delete _pCompartmentEventSink;
|
|
_pCompartmentEventSink = nullptr;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CLangBarItemButton::QueryInterface
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CLangBarItemButton::QueryInterface(REFIID riid, _Outptr_ void **ppvObj)
|
|
{
|
|
if (ppvObj == nullptr)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*ppvObj = nullptr;
|
|
|
|
if (IsEqualIID(riid, IID_IUnknown) ||
|
|
IsEqualIID(riid, IID_ITfLangBarItem) ||
|
|
IsEqualIID(riid, IID_ITfLangBarItemButton))
|
|
{
|
|
*ppvObj = (ITfLangBarItemButton *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_ITfSource))
|
|
{
|
|
*ppvObj = (ITfSource *)this;
|
|
}
|
|
|
|
if (*ppvObj)
|
|
{
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CLangBarItemButton::AddRef
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI_(ULONG) CLangBarItemButton::AddRef()
|
|
{
|
|
return ++_refCount;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CLangBarItemButton::Release
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI_(ULONG) CLangBarItemButton::Release()
|
|
{
|
|
LONG cr = --_refCount;
|
|
|
|
assert(_refCount >= 0);
|
|
|
|
if (_refCount == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
return cr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetInfo
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CLangBarItemButton::GetInfo(_Out_ TF_LANGBARITEMINFO *pInfo)
|
|
{
|
|
_tfLangBarItemInfo.dwStyle |= TF_LBI_STYLE_SHOWNINTRAY;
|
|
*pInfo = _tfLangBarItemInfo;
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetStatus
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CLangBarItemButton::GetStatus(_Out_ DWORD *pdwStatus)
|
|
{
|
|
if (pdwStatus == nullptr)
|
|
{
|
|
E_INVALIDARG;
|
|
}
|
|
|
|
*pdwStatus = _status;
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// SetStatus
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CLangBarItemButton::SetStatus(DWORD dwStatus, BOOL fSet)
|
|
{
|
|
BOOL isChange = FALSE;
|
|
|
|
if (fSet)
|
|
{
|
|
if (!(_status & dwStatus))
|
|
{
|
|
_status |= dwStatus;
|
|
isChange = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_status & dwStatus)
|
|
{
|
|
_status &= ~dwStatus;
|
|
isChange = TRUE;
|
|
}
|
|
}
|
|
|
|
if (isChange && _pLangBarItemSink)
|
|
{
|
|
_pLangBarItemSink->OnUpdate(TF_LBI_STATUS | TF_LBI_ICON);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Show
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CLangBarItemButton::Show(BOOL fShow)
|
|
{
|
|
fShow;
|
|
if (_pLangBarItemSink)
|
|
{
|
|
_pLangBarItemSink->OnUpdate(TF_LBI_STATUS);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetTooltipString
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CLangBarItemButton::GetTooltipString(_Out_ BSTR *pbstrToolTip)
|
|
{
|
|
*pbstrToolTip = SysAllocString(_pTooltipText);
|
|
|
|
return (*pbstrToolTip == nullptr) ? E_OUTOFMEMORY : S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// OnClick
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CLangBarItemButton::OnClick(TfLBIClick click, POINT pt, _In_ const RECT *prcArea)
|
|
{
|
|
click;pt;
|
|
prcArea;
|
|
|
|
BOOL isOn = FALSE;
|
|
|
|
_pCompartment->_GetCompartmentBOOL(isOn);
|
|
_pCompartment->_SetCompartmentBOOL(isOn ? FALSE : TRUE);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// InitMenu
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CLangBarItemButton::InitMenu(_In_ ITfMenu *pMenu)
|
|
{
|
|
pMenu;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// OnMenuSelect
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CLangBarItemButton::OnMenuSelect(UINT wID)
|
|
{
|
|
wID;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetIcon
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CLangBarItemButton::GetIcon(_Out_ HICON *phIcon)
|
|
{
|
|
BOOL isOn = FALSE;
|
|
|
|
if (!_pCompartment)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
if (!phIcon)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
*phIcon = nullptr;
|
|
|
|
_pCompartment->_GetCompartmentBOOL(isOn);
|
|
|
|
DWORD status = 0;
|
|
GetStatus(&status);
|
|
|
|
// If IME is working on the UAC mode, the size of ICON should be 24 x 24.
|
|
int desiredSize = 16;
|
|
if (_isSecureMode) // detect UAC mode
|
|
{
|
|
desiredSize = _isSecureMode ? 24 : 16;
|
|
}
|
|
|
|
if (isOn && !(status & TF_LBI_STATUS_DISABLED))
|
|
{
|
|
if (Global::dllInstanceHandle)
|
|
{
|
|
*phIcon = reinterpret_cast<HICON>(LoadImage(Global::dllInstanceHandle, MAKEINTRESOURCE(_onIconIndex), IMAGE_ICON, desiredSize, desiredSize, 0));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Global::dllInstanceHandle)
|
|
{
|
|
*phIcon = reinterpret_cast<HICON>(LoadImage(Global::dllInstanceHandle, MAKEINTRESOURCE(_offIconIndex), IMAGE_ICON, desiredSize, desiredSize, 0));
|
|
}
|
|
}
|
|
|
|
return (*phIcon != NULL) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetText
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CLangBarItemButton::GetText(_Out_ BSTR *pbstrText)
|
|
{
|
|
*pbstrText = SysAllocString(_tfLangBarItemInfo.szDescription);
|
|
|
|
return (*pbstrText == nullptr) ? E_OUTOFMEMORY : S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// AdviseSink
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CLangBarItemButton::AdviseSink(__RPC__in REFIID riid, __RPC__in_opt IUnknown *punk, __RPC__out DWORD *pdwCookie)
|
|
{
|
|
// We allow only ITfLangBarItemSink interface.
|
|
if (!IsEqualIID(IID_ITfLangBarItemSink, riid))
|
|
{
|
|
return CONNECT_E_CANNOTCONNECT;
|
|
}
|
|
|
|
// We support only one sink once.
|
|
if (_pLangBarItemSink != nullptr)
|
|
{
|
|
return CONNECT_E_ADVISELIMIT;
|
|
}
|
|
|
|
// Query the ITfLangBarItemSink interface and store it into _pLangBarItemSink.
|
|
if (punk == nullptr)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
if (punk->QueryInterface(IID_ITfLangBarItemSink, (void **)&_pLangBarItemSink) != S_OK)
|
|
{
|
|
_pLangBarItemSink = nullptr;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
// return our cookie.
|
|
*pdwCookie = _cookie;
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UnadviseSink
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CLangBarItemButton::UnadviseSink(DWORD dwCookie)
|
|
{
|
|
// Check the given cookie.
|
|
if (dwCookie != _cookie)
|
|
{
|
|
return CONNECT_E_NOCONNECTION;
|
|
}
|
|
|
|
// If there is nno connected sink, we just fail.
|
|
if (_pLangBarItemSink == nullptr)
|
|
{
|
|
return CONNECT_E_NOCONNECTION;
|
|
}
|
|
|
|
_pLangBarItemSink->Release();
|
|
_pLangBarItemSink = nullptr;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _AddItem
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CLangBarItemButton::_AddItem(_In_ ITfThreadMgr *pThreadMgr)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ITfLangBarItemMgr* pLangBarItemMgr = nullptr;
|
|
|
|
if (_isAddedToLanguageBar)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
hr = pThreadMgr->QueryInterface(IID_ITfLangBarItemMgr, (void **)&pLangBarItemMgr);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pLangBarItemMgr->AddItem(this);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
_isAddedToLanguageBar = TRUE;
|
|
}
|
|
pLangBarItemMgr->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _RemoveItem
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CLangBarItemButton::_RemoveItem(_In_ ITfThreadMgr *pThreadMgr)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ITfLangBarItemMgr* pLangBarItemMgr = nullptr;
|
|
|
|
if (!_isAddedToLanguageBar)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
hr = pThreadMgr->QueryInterface(IID_ITfLangBarItemMgr, (void **)&pLangBarItemMgr);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pLangBarItemMgr->RemoveItem(this);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
_isAddedToLanguageBar = FALSE;
|
|
}
|
|
pLangBarItemMgr->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _RegisterCompartment
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CLangBarItemButton::_RegisterCompartment(_In_ ITfThreadMgr *pThreadMgr, TfClientId tfClientId, REFGUID guidCompartment)
|
|
{
|
|
_pCompartment = new (std::nothrow) CCompartment(pThreadMgr, tfClientId, guidCompartment);
|
|
if (_pCompartment)
|
|
{
|
|
// Advice ITfCompartmentEventSink
|
|
_pCompartmentEventSink = new (std::nothrow) CCompartmentEventSink(_CompartmentCallback, this);
|
|
if (_pCompartmentEventSink)
|
|
{
|
|
_pCompartmentEventSink->_Advise(pThreadMgr, guidCompartment);
|
|
}
|
|
else
|
|
{
|
|
delete _pCompartment;
|
|
_pCompartment = nullptr;
|
|
}
|
|
}
|
|
|
|
return _pCompartment ? TRUE : FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _UnregisterCompartment
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CLangBarItemButton::_UnregisterCompartment(_In_ ITfThreadMgr *pThreadMgr)
|
|
{
|
|
pThreadMgr;
|
|
if (_pCompartment)
|
|
{
|
|
// Unadvice ITfCompartmentEventSink
|
|
if (_pCompartmentEventSink)
|
|
{
|
|
_pCompartmentEventSink->_Unadvise();
|
|
}
|
|
|
|
// clear ITfCompartment
|
|
_pCompartment->_ClearCompartment();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _CompartmentCallback
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
// static
|
|
HRESULT CLangBarItemButton::_CompartmentCallback(_In_ void *pv, REFGUID guidCompartment)
|
|
{
|
|
CLangBarItemButton* fakeThis = (CLangBarItemButton*)pv;
|
|
|
|
GUID guid = GUID_NULL;
|
|
fakeThis->_pCompartment->_GetGUID(&guid);
|
|
|
|
if (IsEqualGUID(guid, guidCompartment))
|
|
{
|
|
if (fakeThis->_pLangBarItemSink)
|
|
{
|
|
fakeThis->_pLangBarItemSink->OnUpdate(TF_LBI_STATUS | TF_LBI_ICON);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|