You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3040 lines
84 KiB
3040 lines
84 KiB
//
|
|
// candui.cpp
|
|
//
|
|
|
|
#include "private.h"
|
|
#include "globals.h"
|
|
#include "candui.h"
|
|
#include "wcand.h"
|
|
#include "immxutil.h"
|
|
#include "computil.h"
|
|
#include "candutil.h"
|
|
#include "candobj.h"
|
|
#include "msctfp.h"
|
|
|
|
//
|
|
// default key command definition
|
|
//
|
|
|
|
// key command definition in list style
|
|
|
|
const CANDUIKEYDATA rgKeyDefList[] =
|
|
{
|
|
/*
|
|
{ flag, keydata, command, paramater }
|
|
*/
|
|
{ CANDUIKEY_VKEY, VK_ESCAPE, CANDUICMD_CANCEL, 0 },
|
|
{ CANDUIKEY_VKEY, VK_RETURN, CANDUICMD_COMPLETE, 0 },
|
|
{ CANDUIKEY_VKEY|CANDUIKEY_SHIFT, VK_CONVERT, CANDUICMD_MOVESELPREV, 0 },
|
|
{ CANDUIKEY_VKEY, VK_CONVERT, CANDUICMD_MOVESELNEXT, 0 },
|
|
{ CANDUIKEY_VKEY|CANDUIKEY_SHIFT, VK_SPACE, CANDUICMD_MOVESELPREV, 0 },
|
|
{ CANDUIKEY_VKEY, VK_SPACE, CANDUICMD_MOVESELNEXT, 0 },
|
|
{ CANDUIKEY_VKEY, VK_UP, CANDUICMD_MOVESELUP, 0 }, // horz only
|
|
{ CANDUIKEY_VKEY, VK_DOWN, CANDUICMD_MOVESELDOWN, 0 }, // horz only
|
|
{ CANDUIKEY_VKEY, VK_LEFT, CANDUICMD_MOVESELLEFT, 0 }, // vert only
|
|
{ CANDUIKEY_VKEY, VK_RIGHT, CANDUICMD_MOVESELRIGHT, 0 }, // vert only
|
|
{ CANDUIKEY_VKEY, VK_PRIOR, CANDUICMD_MOVESELPREVPG, 0 },
|
|
{ CANDUIKEY_VKEY, VK_NEXT, CANDUICMD_MOVESELNEXTPG, 0 },
|
|
{ CANDUIKEY_VKEY, VK_HOME, CANDUICMD_MOVESELFIRST, 0 },
|
|
{ CANDUIKEY_VKEY, VK_END, CANDUICMD_MOVESELLAST, 0 },
|
|
{ CANDUIKEY_VKEY|CANDUIKEY_NOSHIFT|CANDUIKEY_NOCTRL, L'1', CANDUICMD_SELECTLINE, 1 },
|
|
{ CANDUIKEY_VKEY|CANDUIKEY_NOSHIFT|CANDUIKEY_NOCTRL, L'2', CANDUICMD_SELECTLINE, 2 },
|
|
{ CANDUIKEY_VKEY|CANDUIKEY_NOSHIFT|CANDUIKEY_NOCTRL, L'3', CANDUICMD_SELECTLINE, 3 },
|
|
{ CANDUIKEY_VKEY|CANDUIKEY_NOSHIFT|CANDUIKEY_NOCTRL, L'4', CANDUICMD_SELECTLINE, 4 },
|
|
{ CANDUIKEY_VKEY|CANDUIKEY_NOSHIFT|CANDUIKEY_NOCTRL, L'5', CANDUICMD_SELECTLINE, 5 },
|
|
{ CANDUIKEY_VKEY|CANDUIKEY_NOSHIFT|CANDUIKEY_NOCTRL, L'6', CANDUICMD_SELECTLINE, 6 },
|
|
{ CANDUIKEY_VKEY|CANDUIKEY_NOSHIFT|CANDUIKEY_NOCTRL, L'7', CANDUICMD_SELECTLINE, 7 },
|
|
{ CANDUIKEY_VKEY|CANDUIKEY_NOSHIFT|CANDUIKEY_NOCTRL, L'8', CANDUICMD_SELECTLINE, 8 },
|
|
{ CANDUIKEY_VKEY|CANDUIKEY_NOSHIFT|CANDUIKEY_NOCTRL, L'9', CANDUICMD_SELECTLINE, 9 },
|
|
{ CANDUIKEY_VKEY|CANDUIKEY_NOSHIFT|CANDUIKEY_NOCTRL, L'0', CANDUICMD_SELECTEXTRACAND, 0 },
|
|
{ CANDUIKEY_VKEY, VK_OEM_MINUS, CANDUICMD_SELECTRAWDATA, 0 },
|
|
{ CANDUIKEY_VKEY, VK_NUMPAD1, CANDUICMD_SELECTLINE, 1 },
|
|
{ CANDUIKEY_VKEY, VK_NUMPAD2, CANDUICMD_SELECTLINE, 2 },
|
|
{ CANDUIKEY_VKEY, VK_NUMPAD3, CANDUICMD_SELECTLINE, 3 },
|
|
{ CANDUIKEY_VKEY, VK_NUMPAD4, CANDUICMD_SELECTLINE, 4 },
|
|
{ CANDUIKEY_VKEY, VK_NUMPAD5, CANDUICMD_SELECTLINE, 5 },
|
|
{ CANDUIKEY_VKEY, VK_NUMPAD6, CANDUICMD_SELECTLINE, 6 },
|
|
{ CANDUIKEY_VKEY, VK_NUMPAD7, CANDUICMD_SELECTLINE, 7 },
|
|
{ CANDUIKEY_VKEY, VK_NUMPAD8, CANDUICMD_SELECTLINE, 8 },
|
|
{ CANDUIKEY_VKEY, VK_NUMPAD9, CANDUICMD_SELECTLINE, 9 },
|
|
{ CANDUIKEY_VKEY, VK_NUMPAD0, CANDUICMD_SELECTEXTRACAND, 0 },
|
|
{ CANDUIKEY_VKEY, VK_SUBTRACT, CANDUICMD_SELECTRAWDATA, 0 },
|
|
{ CANDUIKEY_VKEY, VK_APPS, CANDUICMD_OPENCANDMENU, 0 },
|
|
};
|
|
|
|
|
|
// key command definition in row style
|
|
|
|
const CANDUIKEYDATA rgKeyDefRow[] =
|
|
{
|
|
/*
|
|
{ flag, keydata, command, paramater }
|
|
*/
|
|
{ CANDUIKEY_VKEY, VK_ESCAPE, CANDUICMD_CANCEL, 0 },
|
|
{ CANDUIKEY_VKEY, VK_RETURN, CANDUICMD_CANCEL, 0 },
|
|
{ CANDUIKEY_VKEY, VK_SPACE, CANDUICMD_COMPLETE, 0 },
|
|
{ CANDUIKEY_VKEY, VK_UP, CANDUICMD_MOVESELLEFT, 0 }, // horz only
|
|
{ CANDUIKEY_VKEY, VK_DOWN, CANDUICMD_MOVESELRIGHT, 0 }, // horz only
|
|
{ CANDUIKEY_VKEY, VK_LEFT, CANDUICMD_MOVESELUP, 0 }, // vert only
|
|
{ CANDUIKEY_VKEY, VK_RIGHT, CANDUICMD_MOVESELDOWN, 0 }, // vert only
|
|
{ CANDUIKEY_VKEY, VK_PRIOR, CANDUICMD_MOVESELPREVPG, 0 },
|
|
{ CANDUIKEY_VKEY, VK_NEXT, CANDUICMD_MOVESELNEXTPG, 0 },
|
|
// { CANDUIKEY_CHAR, L'1', CANDUICMD_SELECTLINE, 1 },
|
|
// { CANDUIKEY_CHAR, L'2', CANDUICMD_SELECTLINE, 2 },
|
|
// { CANDUIKEY_CHAR, L'3', CANDUICMD_SELECTLINE, 3 },
|
|
// { CANDUIKEY_CHAR, L'4', CANDUICMD_SELECTLINE, 4 },
|
|
// { CANDUIKEY_CHAR, L'5', CANDUICMD_SELECTLINE, 5 },
|
|
// { CANDUIKEY_CHAR, L'6', CANDUICMD_SELECTLINE, 6 },
|
|
// { CANDUIKEY_CHAR, L'7', CANDUICMD_SELECTLINE, 7 },
|
|
// { CANDUIKEY_CHAR, L'8', CANDUICMD_SELECTLINE, 8 },
|
|
// { CANDUIKEY_CHAR, L'9', CANDUICMD_SELECTLINE, 9 },
|
|
{ CANDUIKEY_VKEY, L'1', CANDUICMD_SELECTLINE, 1 },
|
|
{ CANDUIKEY_VKEY, L'2', CANDUICMD_SELECTLINE, 2 },
|
|
{ CANDUIKEY_VKEY, L'3', CANDUICMD_SELECTLINE, 3 },
|
|
{ CANDUIKEY_VKEY, L'4', CANDUICMD_SELECTLINE, 4 },
|
|
{ CANDUIKEY_VKEY, L'5', CANDUICMD_SELECTLINE, 5 },
|
|
{ CANDUIKEY_VKEY, L'6', CANDUICMD_SELECTLINE, 6 },
|
|
{ CANDUIKEY_VKEY, L'7', CANDUICMD_SELECTLINE, 7 },
|
|
{ CANDUIKEY_VKEY, L'8', CANDUICMD_SELECTLINE, 8 },
|
|
{ CANDUIKEY_VKEY, L'9', CANDUICMD_SELECTLINE, 9 },
|
|
{ CANDUIKEY_VKEY, VK_NUMPAD1, CANDUICMD_SELECTLINE, 1 },
|
|
{ CANDUIKEY_VKEY, VK_NUMPAD2, CANDUICMD_SELECTLINE, 2 },
|
|
{ CANDUIKEY_VKEY, VK_NUMPAD3, CANDUICMD_SELECTLINE, 3 },
|
|
{ CANDUIKEY_VKEY, VK_NUMPAD4, CANDUICMD_SELECTLINE, 4 },
|
|
{ CANDUIKEY_VKEY, VK_NUMPAD5, CANDUICMD_SELECTLINE, 5 },
|
|
{ CANDUIKEY_VKEY, VK_NUMPAD6, CANDUICMD_SELECTLINE, 6 },
|
|
{ CANDUIKEY_VKEY, VK_NUMPAD7, CANDUICMD_SELECTLINE, 7 },
|
|
{ CANDUIKEY_VKEY, VK_NUMPAD8, CANDUICMD_SELECTLINE, 8 },
|
|
{ CANDUIKEY_VKEY, VK_NUMPAD9, CANDUICMD_SELECTLINE, 9 },
|
|
{ CANDUIKEY_CHAR, L'-', CANDUICMD_MOVESELPREVPG, 0 },
|
|
{ CANDUIKEY_CHAR, L'_', CANDUICMD_MOVESELPREVPG, 0 },
|
|
{ CANDUIKEY_CHAR, L'[', CANDUICMD_MOVESELPREVPG, 0 },
|
|
{ CANDUIKEY_CHAR, L'+', CANDUICMD_MOVESELNEXTPG, 0 },
|
|
{ CANDUIKEY_CHAR, L'=', CANDUICMD_MOVESELNEXTPG, 0 },
|
|
{ CANDUIKEY_CHAR, L']', CANDUICMD_MOVESELNEXTPG, 0 },
|
|
{ CANDUIKEY_VKEY, VK_APPS, CANDUICMD_OPENCANDMENU, 0 },
|
|
};
|
|
|
|
|
|
//
|
|
// rule definitions
|
|
//
|
|
|
|
typedef struct _RULEDEF
|
|
{
|
|
LPCWSTR szRuleName;
|
|
CANDUICOMMAND cmd;
|
|
UINT uiParam;
|
|
} RULEDEF;
|
|
|
|
|
|
// rule definition in normal state
|
|
|
|
const RULEDEF rgRuleNorm[] =
|
|
{
|
|
/*
|
|
{ "rule name", command, paramater }
|
|
*/
|
|
{ L"Finalize", CANDUICMD_COMPLETE, 0 },
|
|
{ L"Cancel", CANDUICMD_CANCEL, 0 },
|
|
{ L"Next", CANDUICMD_MOVESELNEXT, 0 },
|
|
{ L"Prev", CANDUICMD_MOVESELPREV, 0 },
|
|
{ L"First", CANDUICMD_MOVESELFIRST, 0 },
|
|
{ L"Last", CANDUICMD_MOVESELLAST, 0 },
|
|
{ L"Menu", CANDUICMD_OPENCANDMENU, 0 },
|
|
{ L"Select1", CANDUICMD_SELECTLINE, 1 },
|
|
{ L"Select2", CANDUICMD_SELECTLINE, 2 },
|
|
{ L"Select3", CANDUICMD_SELECTLINE, 3 },
|
|
{ L"Select4", CANDUICMD_SELECTLINE, 4 },
|
|
{ L"Select5", CANDUICMD_SELECTLINE, 5 },
|
|
{ L"Select6", CANDUICMD_SELECTLINE, 6 },
|
|
{ L"Select7", CANDUICMD_SELECTLINE, 7 },
|
|
{ L"Select8", CANDUICMD_SELECTLINE, 8 },
|
|
{ L"Select9", CANDUICMD_SELECTLINE, 9 },
|
|
{ L"PageDown", CANDUICMD_MOVESELNEXTPG, 0 },
|
|
{ L"PageUp", CANDUICMD_MOVESELPREVPG, 0 },
|
|
};
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
class CTfCandidateUIContextOwner : public ITfCandidateUIContextOwner
|
|
{
|
|
public:
|
|
CTfCandidateUIContextOwner( CCandidateUI *pCandUI );
|
|
virtual ~CTfCandidateUIContextOwner( void );
|
|
|
|
//
|
|
// IUnknown methods
|
|
//
|
|
STDMETHODIMP QueryInterface( REFIID riid, void **ppvObj );
|
|
STDMETHODIMP_(ULONG) AddRef( void );
|
|
STDMETHODIMP_(ULONG) Release( void );
|
|
|
|
//
|
|
// ITfCandidateUIContextOwner methods
|
|
//
|
|
STDMETHODIMP ProcessCommand(CANDUICOMMAND cmd, INT iParam);
|
|
STDMETHODIMP TestText(BSTR bstr, BOOL *pfHandles);
|
|
|
|
protected:
|
|
ULONG m_cRef;
|
|
CCandidateUI *m_pCandUI;
|
|
};
|
|
|
|
|
|
/*============================================================================*/
|
|
/* */
|
|
/* C C A N D I D A T E U I */
|
|
/* */
|
|
/*============================================================================*/
|
|
|
|
/* C C A N D I D A T E U I */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
CCandidateUI::CCandidateUI()
|
|
{
|
|
Dbg_MemSetThisName(TEXT("CCandidateUI"));
|
|
|
|
TF_CreateThreadMgr(&_ptim);
|
|
m_hWndParent = NULL;
|
|
m_pCandWnd = NULL;
|
|
|
|
m_pic = NULL;
|
|
m_pdim = NULL;
|
|
m_picParent = NULL;
|
|
m_pTargetRange = NULL;
|
|
m_codepage = GetACP();
|
|
|
|
m_fContextEventSinkAdvised = FALSE;
|
|
m_dwCookieContextOwnerSink = 0;
|
|
m_dwCookieContextKeySink = 0;
|
|
|
|
m_fTextEventSinkAdvised = FALSE;
|
|
m_dwCookieTextEditSink = 0;
|
|
m_dwCookieTextLayoutSink = 0;
|
|
m_dwCookieTransactionSink = 0;
|
|
|
|
m_pTextEventSink = NULL;
|
|
|
|
m_pCandUIKeyTable = NULL;
|
|
|
|
m_fInTransaction = FALSE;
|
|
m_pSelectionStart = NULL;
|
|
m_pSelectionCur = NULL;
|
|
|
|
m_fInCallback = FALSE;
|
|
m_pSpTask = NULL;
|
|
|
|
// create candidate list manager, function manager, functions
|
|
|
|
CCandListMgr::Initialize( this );
|
|
CCandUIObjectMgr::Initialize( this );
|
|
CCandUIPropertyMgr::Initialize( this );
|
|
CCandUICompartmentMgr::Initialize( this );
|
|
CCandUIFunctionMgr::Initialize( this );
|
|
CCandUIExtensionMgr::Initialize( this );
|
|
}
|
|
|
|
|
|
/* ~ C C A N D I D A T E U I */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
CCandidateUI::~CCandidateUI()
|
|
{
|
|
// this call was for the case that CandidateUI was released wihtout
|
|
// CloseCandidateUI() call, but it should not happn (because it will be
|
|
// referenced by event sink or interfnal objects by OpenCandidateUI(), so
|
|
// ref count nevet be zero unless CloseCandidateUI() call...
|
|
|
|
// CloseCandidateUIProc();
|
|
|
|
//
|
|
|
|
SafeReleaseClear( m_pCandUIKeyTable );
|
|
|
|
//
|
|
|
|
CCandUIExtensionMgr::Uninitialize();
|
|
CCandUIFunctionMgr::Uninitialize();
|
|
CCandUICompartmentMgr::Uninitialize();
|
|
CCandUIPropertyMgr::Uninitialize();
|
|
CCandUIObjectMgr::Uninitialize();
|
|
CCandListMgr::Uninitialize();
|
|
|
|
// remove ref to this in TLS
|
|
|
|
SafeRelease( _ptim );
|
|
SafeRelease( m_pTargetRange );
|
|
DoneTextEventSinks( m_picParent );
|
|
ClearSelectionCur();
|
|
ClearWndCand();
|
|
|
|
// release speech
|
|
|
|
if(m_pSpTask) {
|
|
delete m_pSpTask;
|
|
}
|
|
}
|
|
|
|
|
|
/* E N D C A N D I D A T E L I S T */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
void CCandidateUI::EndCandidateList()
|
|
{
|
|
DoneContextEventSinks( m_pic );
|
|
ClearCompartment( m_tidClient, m_pic, GUID_COMPARTMENT_MSCANDIDATEUI_CONTEXTOWNER, FALSE );
|
|
|
|
DoneTextEventSinks( m_picParent );
|
|
ClearSelectionCur();
|
|
|
|
SafeReleaseClear( m_pic );
|
|
SafeReleaseClear( m_pTargetRange );
|
|
SafeReleaseClear( m_pCandUIKeyTable );
|
|
|
|
if (m_pdim) {
|
|
m_pdim->Pop(0);
|
|
m_pdim->Release();
|
|
m_pdim = NULL;
|
|
|
|
SafeRelease( m_picParent );
|
|
}
|
|
}
|
|
|
|
|
|
/* S E T C L I E N T I D */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
STDAPI CCandidateUI::SetClientId( TfClientId tid )
|
|
{
|
|
m_tidClient = tid;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/* O P E N C A N D I D A T E U I */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
STDAPI CCandidateUI::OpenCandidateUI( HWND hWndParent, ITfDocumentMgr *pdim, TfEditCookie ec, ITfRange *pRange )
|
|
{
|
|
ITfInputProcessorProfiles *pProfile;
|
|
ITfRange *pSelection = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
Assert(!m_pic);
|
|
Assert(!m_pdim);
|
|
|
|
// sanity check
|
|
|
|
if ((pdim == NULL) || (pRange == NULL)) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// check if candidate list has been set
|
|
|
|
if (GetCandListMgr()->GetCandList() == NULL) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
// fail when it's opening candidate window already
|
|
|
|
if (m_pCandWnd != NULL) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
// ensure that speech is enabled
|
|
|
|
// BUGBUG - THIS IS TOO LATE TO ENSURE ENGINE IS FORCED TO SYNC VIA A RECOSTATE(INACTIVE) CALL.
|
|
EnsureSpeech();
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
m_pdim = pdim;
|
|
m_pdim->AddRef();
|
|
|
|
// store current top IC
|
|
|
|
GetTopIC( pdim, &m_picParent );
|
|
|
|
//
|
|
// create candidate window
|
|
//
|
|
|
|
ClearWndCand();
|
|
if (CreateCandWindowObject( m_picParent, &m_pCandWnd ) == S_OK) {
|
|
BOOL fClipped;
|
|
RECT rc;
|
|
|
|
SetCompartmentDWORD( m_tidClient, m_picParent, GUID_COMPARTMENT_MSCANDIDATEUI_WINDOW, 0x00000001, FALSE );
|
|
|
|
m_pCandWnd->Initialize();
|
|
|
|
// set target clause poisition
|
|
|
|
GetTextExtInActiveView( ec, pRange, &rc, &fClipped );
|
|
m_pCandWnd->SetTargetRect( &rc, fClipped );
|
|
|
|
// initialize candidate list
|
|
|
|
m_pCandWnd->InitCandidateList();
|
|
|
|
// create window
|
|
|
|
m_pCandWnd->CreateWnd( m_hWndParent );
|
|
|
|
hr = S_OK;
|
|
}
|
|
|
|
//
|
|
// create context for CandidteUI
|
|
//
|
|
|
|
SafeReleaseClear( m_pic );
|
|
if (SUCCEEDED(hr)) {
|
|
TfEditCookie ecTmp;
|
|
|
|
// create context
|
|
|
|
hr = pdim->CreateContext( m_tidClient, 0, NULL, &m_pic, &ecTmp );
|
|
|
|
// disable keyboard while candidate UI open
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
SetCompartmentDWORD( m_tidClient, m_pic, GUID_COMPARTMENT_KEYBOARD_DISABLED, 0x00000001, FALSE );
|
|
SetCompartmentDWORD( m_tidClient, m_pic, GUID_COMPARTMENT_MSCANDIDATEUI_CONTEXT, 0x00000001, FALSE );
|
|
}
|
|
|
|
// create context owner instance
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
CTfCandidateUIContextOwner *pCxtOwner;
|
|
|
|
pCxtOwner = new CTfCandidateUIContextOwner( this );
|
|
if (pCxtOwner == NULL) {
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else {
|
|
SetCompartmentUnknown( m_tidClient, m_pic, GUID_COMPARTMENT_MSCANDIDATEUI_CONTEXTOWNER, (IUnknown*)pCxtOwner );
|
|
}
|
|
}
|
|
|
|
// init context event sinks
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
hr = InitContextEventSinks( m_pic );
|
|
}
|
|
|
|
// push context
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
hr = pdim->Push( m_pic );
|
|
}
|
|
}
|
|
|
|
//
|
|
// cleanup all when failed
|
|
//
|
|
|
|
if (FAILED(hr)) {
|
|
// cleanup context
|
|
|
|
if (m_pic != NULL) {
|
|
DoneContextEventSinks( m_pic );
|
|
ClearCompartment( m_tidClient, m_pic, GUID_COMPARTMENT_MSCANDIDATEUI_CONTEXTOWNER, FALSE );
|
|
SafeReleaseClear( m_pic );
|
|
}
|
|
|
|
// cleanup candidate window
|
|
|
|
if (m_pCandWnd != NULL) {
|
|
m_pCandWnd->DestroyWnd();
|
|
ClearWndCand();
|
|
}
|
|
|
|
// release objects
|
|
|
|
SafeReleaseClear( m_picParent );
|
|
SafeReleaseClear( m_pdim );
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// initialize miscs
|
|
//
|
|
|
|
// get current codepage from current assembly
|
|
|
|
m_codepage = GetACP();
|
|
if (SUCCEEDED(CoCreateInstance( CLSID_TF_InputProcessorProfiles, NULL, CLSCTX_INPROC_SERVER, IID_ITfInputProcessorProfiles, (void **)&pProfile ))) {
|
|
LANGID langid;
|
|
char szCpg[ 16 ];
|
|
|
|
if (pProfile->GetCurrentLanguage( &langid ) == S_OK) {
|
|
if (GetLocaleInfo( MAKELCID(langid, SORT_DEFAULT), LOCALE_IDEFAULTANSICODEPAGE, szCpg, ARRAYSIZE(szCpg) ) != 0) {
|
|
m_codepage = atoi( szCpg );
|
|
}
|
|
}
|
|
pProfile->Release();
|
|
}
|
|
|
|
// get key table
|
|
|
|
SafeRelease( m_pCandUIKeyTable );
|
|
m_pCandUIKeyTable = GetKeyTableProc( m_picParent );
|
|
|
|
// make copy target range
|
|
|
|
pRange->Clone( &m_pTargetRange );
|
|
|
|
// store selection first
|
|
|
|
ClearSelectionCur();
|
|
if (GetSelectionSimple( ec, m_picParent, &pSelection ) == S_OK) {
|
|
SetSelectionCur( pSelection );
|
|
SafeRelease( pSelection );
|
|
}
|
|
|
|
// init text event sinks
|
|
|
|
DoneTextEventSinks( m_picParent );
|
|
InitTextEventSinks( m_picParent );
|
|
|
|
//
|
|
// show candidate window at last
|
|
//
|
|
|
|
m_pCandWnd->Show( GetPropertyMgr()->GetCandWindowProp()->IsVisible() );
|
|
m_pCandWnd->UpdateAllWindow();
|
|
|
|
// notify initial seletion
|
|
|
|
NotifySelectCand( GetCandListMgr()->GetCandList()->GetSelection() );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* C L O S E C A N D I D A T E U I */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
STDAPI CCandidateUI::CloseCandidateUI( void )
|
|
{
|
|
HRESULT hr;
|
|
|
|
// Windows#502340
|
|
// CandidateUI will be released during DestroyWindow(). As result,
|
|
// ref count will be zero and instance will be disposed during closeing UI.
|
|
// prevent from it, keep one refcount until closing process will finished.
|
|
|
|
AddRef();
|
|
hr = CloseCandidateUIProc();
|
|
Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* S E T C A N D I D A T E L I S T */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
STDAPI CCandidateUI::SetCandidateList( ITfCandidateList *pCandList )
|
|
{
|
|
// release before change candidate list
|
|
|
|
GetCandListMgr()->ClearCandiateList();
|
|
|
|
// set new candidate list
|
|
|
|
return GetCandListMgr()->SetCandidateList( pCandList );
|
|
}
|
|
|
|
|
|
/* S E T S E L E C T I O N */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
STDAPI CCandidateUI::SetSelection( ULONG nIndex )
|
|
{
|
|
HRESULT hr;
|
|
int iCandItem;
|
|
|
|
// check if candidate list has been set
|
|
|
|
if (GetCandListMgr()->GetCandList() == NULL) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
// map index to icanditem
|
|
|
|
hr = GetCandListMgr()->GetCandList()->MapIndexToIItem( nIndex, &iCandItem );
|
|
if (FAILED(hr)) {
|
|
Assert( FALSE );
|
|
return hr;
|
|
}
|
|
|
|
return GetCandListMgr()->SetSelection( iCandItem, NULL /* no cand function */ );
|
|
}
|
|
|
|
|
|
/* G E T S E L E C T I O N */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
STDAPI CCandidateUI::GetSelection( ULONG *pnIndex )
|
|
{
|
|
HRESULT hr;
|
|
int iCandItem;
|
|
ULONG nIndex;
|
|
|
|
if (pnIndex == NULL) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// check if candidate list has been set
|
|
|
|
if (GetCandListMgr()->GetCandList() == NULL) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
iCandItem = GetCandListMgr()->GetCandList()->GetSelection();
|
|
|
|
hr = GetCandListMgr()->GetCandList()->MapIItemToIndex( iCandItem, &nIndex );
|
|
if (FAILED(hr)) {
|
|
Assert( FALSE );
|
|
return hr;
|
|
}
|
|
|
|
*pnIndex = nIndex;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/* S E T T A R G E T R A N G E */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Set target range
|
|
Memo: This method works while candidate UI is opened.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
STDAPI CCandidateUI::SetTargetRange( ITfRange *pRange )
|
|
{
|
|
CEditSession *pes;
|
|
|
|
if (pRange == NULL) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (m_pCandWnd == NULL) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
SafeReleaseClear( m_pTargetRange );
|
|
pRange->Clone( &m_pTargetRange );
|
|
|
|
// move candidate window
|
|
|
|
if (pes = new CEditSession( EditSessionCallback )) {
|
|
HRESULT hr;
|
|
|
|
pes->_state.u = ESCB_RESETTARGETPOS;
|
|
pes->_state.pv = this;
|
|
pes->_state.wParam = 0;
|
|
pes->_state.pRange = m_pTargetRange;
|
|
pes->_state.pic = m_picParent;
|
|
|
|
m_picParent->RequestEditSession( m_tidClient, pes, TF_ES_READ | TF_ES_SYNC, &hr );
|
|
|
|
pes->Release();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/* G E T T A R G E T R A N G E */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
STDAPI CCandidateUI::GetTargetRange( ITfRange **ppRange )
|
|
{
|
|
if (m_pTargetRange == NULL) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
Assert( ppRange != NULL );
|
|
return m_pTargetRange->Clone( ppRange );
|
|
}
|
|
|
|
|
|
/* G E T U I O B J E C T */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
STDAPI CCandidateUI::GetUIObject( REFIID riid, IUnknown **ppunk )
|
|
{
|
|
return GetPropertyMgr()->GetObject( riid, (void **)ppunk );
|
|
}
|
|
|
|
|
|
/* G E T F U N C T I O N */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
STDAPI CCandidateUI::GetFunction( REFIID riid, IUnknown **ppunk )
|
|
{
|
|
if (ppunk == NULL) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// extension manager
|
|
|
|
if (IsEqualGUID( riid, IID_ITfCandUIFnExtension )) {
|
|
CCandUIFnExtension *pObject;
|
|
HRESULT hr;
|
|
|
|
pObject = new CCandUIFnExtension( this, GetExtensionMgr() );
|
|
if (pObject == NULL) {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
hr = pObject->QueryInterface( riid, (void **)ppunk );
|
|
pObject->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
// key config
|
|
|
|
if (IsEqualGUID( riid, IID_ITfCandUIFnKeyConfig )) {
|
|
CCandUIFnKeyConfig *pObject;
|
|
HRESULT hr;
|
|
|
|
pObject = new CCandUIFnKeyConfig( this );
|
|
if (pObject == NULL) {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
hr = pObject->QueryInterface( riid, (void **)ppunk );
|
|
pObject->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
// UI config
|
|
|
|
if (IsEqualGUID( riid, IID_ITfCandUIFnUIConfig )) {
|
|
CCandUIFnUIConfig *pObject;
|
|
HRESULT hr;
|
|
|
|
pObject = new CCandUIFnUIConfig( this );
|
|
if (pObject == NULL) {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
hr = pObject->QueryInterface( riid, (void **)ppunk );
|
|
pObject->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
// regular functions
|
|
|
|
return GetFunctionMgr()->GetObject( riid, (void **)ppunk );
|
|
}
|
|
|
|
|
|
/* P R O C E S S C O M M A N D */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
STDAPI CCandidateUI::ProcessCommand( CANDUICOMMAND cmd, INT iParam )
|
|
{
|
|
//
|
|
|
|
if (cmd == CANDUICMD_NONE) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (m_pCandWnd == NULL) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
return m_pCandWnd->ProcessCommand( cmd, iParam );
|
|
}
|
|
|
|
|
|
/* C L O S E C A N D I D A T E U I P R O C */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
close candidate u i proc
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::CloseCandidateUIProc( void )
|
|
{
|
|
if (m_picParent && m_pCandWnd) {
|
|
SetCompartmentDWORD( m_tidClient, m_picParent, GUID_COMPARTMENT_MSCANDIDATEUI_WINDOW, 0x00000000, FALSE );
|
|
}
|
|
|
|
if (m_pCandWnd) {
|
|
m_pCandWnd->DestroyWnd();
|
|
ClearWndCand();
|
|
EndCandidateList();
|
|
}
|
|
|
|
GetCandListMgr()->ClearCandiateList();
|
|
|
|
if (m_pSpTask)
|
|
m_pSpTask->_Activate(FALSE);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// key config function methods
|
|
//
|
|
|
|
/* S E T K E Y T A B L E */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::SetKeyTable( ITfContext *pic, ITfCandUIKeyTable *pCandUIKeyTable )
|
|
{
|
|
HRESULT hr;
|
|
CCandUIKeyTable *pCandUIKeyTableCopy;
|
|
|
|
if ((pic == NULL) || (pCandUIKeyTable == NULL)) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (GetCompartmentMgr() == NULL) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
// store copy of key table to input context
|
|
|
|
pCandUIKeyTableCopy = new CCandUIKeyTable();
|
|
if (pCandUIKeyTableCopy == NULL) {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
hr = pCandUIKeyTableCopy->SetKeyTable( pCandUIKeyTable );
|
|
if (FAILED( hr )) {
|
|
pCandUIKeyTableCopy->Release();
|
|
return hr;
|
|
}
|
|
|
|
hr = GetCompartmentMgr()->SetKeyTable( pic, pCandUIKeyTableCopy );
|
|
if (FAILED( hr )) {
|
|
pCandUIKeyTableCopy->Release();
|
|
return hr;
|
|
}
|
|
pCandUIKeyTableCopy->Release();
|
|
|
|
// reload key table if exist
|
|
|
|
// REVIEW: KOJIW: If we support changing keytable of candidate UI in other IC,
|
|
// need to do this in compartment event sink.
|
|
|
|
if (m_pCandUIKeyTable != NULL) {
|
|
m_pCandUIKeyTable->Release();
|
|
|
|
Assert( m_picParent != NULL );
|
|
m_pCandUIKeyTable = GetKeyTableProc( m_picParent );
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/* G E T K E Y T A B L E */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::GetKeyTable( ITfContext *pic, ITfCandUIKeyTable **ppCandUIKeyTable)
|
|
{
|
|
if ((pic == NULL) || (ppCandUIKeyTable == NULL)) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// load key table from input context
|
|
|
|
*ppCandUIKeyTable = GetKeyTableProc( pic );
|
|
return (*ppCandUIKeyTable != NULL) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
|
|
/* R E S E T K E Y T A B L E */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::ResetKeyTable( ITfContext *pic )
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (pic == NULL) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (GetCompartmentMgr() == NULL) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
hr = GetCompartmentMgr()->ClearKeyTable( pic );
|
|
if (FAILED( hr )) {
|
|
return hr;
|
|
}
|
|
|
|
// reload key table if exist
|
|
|
|
if (m_pCandUIKeyTable != NULL) {
|
|
m_pCandUIKeyTable->Release();
|
|
|
|
Assert( m_picParent != NULL );
|
|
m_pCandUIKeyTable = GetKeyTableProc( m_picParent );
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// UI config function methods
|
|
//
|
|
|
|
/* S E T U I S T Y L E */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::SetUIStyle( ITfContext *pic, CANDUISTYLE style )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (pic == NULL) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (GetCompartmentMgr() == NULL) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
// store ui style to input context
|
|
|
|
GetCompartmentMgr()->SetUIStyle( pic, style );
|
|
|
|
// rebuild candidate window
|
|
|
|
// REVIEW: KOJIW: If we support changing ui style of candidate UI in other IC,
|
|
// need to do this in compartment event sink.
|
|
|
|
if ((m_picParent == pic) && (m_pCandWnd != NULL)) {
|
|
// destory candidate window object
|
|
|
|
m_pCandWnd->DestroyWnd();
|
|
ClearWndCand();
|
|
|
|
// create and initialize window object
|
|
|
|
hr = CreateCandWindowObject( m_picParent, &m_pCandWnd );
|
|
if (SUCCEEDED(hr)) {
|
|
hr = InitCandWindow();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* G E T U I S T Y L E */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::GetUIStyle( ITfContext *pic, CANDUISTYLE *pstyle )
|
|
{
|
|
if ((pic == NULL) || (pstyle == NULL)) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (GetCompartmentMgr() == NULL) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (FAILED( GetCompartmentMgr()->GetUIStyle( pic, pstyle ))) {
|
|
*pstyle = CANDUISTY_LIST;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/* S E T U I O P T I O N */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::SetUIOption( ITfContext *pic, DWORD dwOption )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (pic == NULL) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (GetCompartmentMgr() == NULL) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
// store ui style to input context
|
|
|
|
GetCompartmentMgr()->SetUIOption( pic, dwOption );
|
|
|
|
// rebuild candidate window
|
|
|
|
// REVIEW: KOJIW: If we support changing ui style of candidate UI in other IC,
|
|
// need to do this in compartment event sink.
|
|
|
|
if ((m_picParent == pic) && (m_pCandWnd != NULL)) {
|
|
// destory candidate window object
|
|
|
|
m_pCandWnd->DestroyWnd();
|
|
ClearWndCand();
|
|
|
|
// create and initialize window object
|
|
|
|
hr = CreateCandWindowObject( m_picParent, &m_pCandWnd );
|
|
if (SUCCEEDED(hr)) {
|
|
hr = InitCandWindow();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* G E T U I O P T I O N */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::GetUIOption( ITfContext *pic, DWORD *pdwOption )
|
|
{
|
|
if ((pic == NULL) || (pdwOption == NULL)) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (GetCompartmentMgr() == NULL) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (FAILED( GetCompartmentMgr()->GetUIOption( pic, pdwOption ))) {
|
|
*pdwOption = 0;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// callback functions
|
|
//
|
|
|
|
/* I N I T C O N T E X T E V E N T S I N K S */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
initialize sinks for input context events
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::InitContextEventSinks( ITfContext *pic )
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
ITfSource *pSource = NULL;
|
|
|
|
Assert( pic == m_picParent );
|
|
Assert( !m_fContextEventSinkAdvised );
|
|
|
|
m_fContextEventSinkAdvised = FALSE;
|
|
if (pic->QueryInterface( IID_ITfSource, (void **)&pSource) == S_OK) {
|
|
if (FAILED(pSource->AdviseSink( IID_ITfContextOwner, (ITfContextOwner *)this, &m_dwCookieContextOwnerSink ))) {
|
|
pSource->Release();
|
|
return hr;
|
|
}
|
|
|
|
if (FAILED(pSource->AdviseSink( IID_ITfContextKeyEventSink, (ITfContextKeyEventSink *)this, &m_dwCookieContextKeySink ))) {
|
|
pSource->UnadviseSink( m_dwCookieContextOwnerSink );
|
|
pSource->Release();
|
|
return hr;
|
|
}
|
|
pSource->Release();
|
|
|
|
m_fContextEventSinkAdvised = TRUE;
|
|
hr = S_OK;
|
|
}
|
|
|
|
// advise text event sink for own IC
|
|
|
|
// NOTE: This is a temporary fix for Satori#3644 (Cicero#3407) to handle
|
|
// a text event from HW Tip. So the detect logic is very tiny (it just
|
|
// handles half-width alphanumeric numbers). In the next version of Cicero,
|
|
// we will use commanding feature to do same thing...
|
|
// (related functions: TextEventCallback, HandleTextDeltas)
|
|
|
|
m_pTextEventSink = new CTextEventSink( TextEventCallback, this );
|
|
if (m_pTextEventSink != NULL) {
|
|
m_pTextEventSink->_Advise( pic, ICF_TEXTDELTA );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* D O N E C O N T E X T E V E N T S I N K S */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
uninitialize sinks for input context events
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::DoneContextEventSinks( ITfContext *pic )
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
ITfSource *pSource;
|
|
|
|
Assert( pic == m_picParent );
|
|
|
|
// unadvise text event sink for own IC
|
|
|
|
if (m_pTextEventSink != NULL) {
|
|
m_pTextEventSink->_Unadvise();
|
|
SafeReleaseClear( m_pTextEventSink );
|
|
}
|
|
|
|
if (!m_fContextEventSinkAdvised) {
|
|
return S_OK;
|
|
}
|
|
|
|
if (pic->QueryInterface( IID_ITfSource, (void **)&pSource) == S_OK) {
|
|
pSource->UnadviseSink( m_dwCookieContextOwnerSink );
|
|
pSource->UnadviseSink( m_dwCookieContextKeySink );
|
|
pSource->Release();
|
|
|
|
m_fContextEventSinkAdvised = FALSE;
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* G E T A C P F R O M P O I N T */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Get acp from point
|
|
(ITfContextOwner method)
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::GetACPFromPoint( const POINT *pt, DWORD dwFlags, LONG *pacp )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
/* G E T S C R E E N E X T */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Get screen extent of context
|
|
(ITfContextOwner method)
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::GetScreenExt( RECT *prc )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
/* G E T T E X T E X T */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Get text externt of context
|
|
(ITfContextOwner method)
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::GetTextExt( LONG acpStart, LONG acpEnd, RECT *prc, BOOL *pfClipped )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
/* G E T S T A T U S */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Get status of context
|
|
(ITfContextOwner method)
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::GetStatus( TF_STATUS *pdcs )
|
|
{
|
|
if (pdcs == NULL) {
|
|
return E_POINTER;
|
|
}
|
|
|
|
memset(pdcs, 0, sizeof(*pdcs));
|
|
pdcs->dwDynamicFlags = 0;
|
|
pdcs->dwStaticFlags = 0;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/* G E T W N D */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Get window of context
|
|
(ITfContextOwner method)
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::GetWnd( HWND *phwnd )
|
|
{
|
|
if (phwnd == NULL) {
|
|
return E_POINTER;
|
|
}
|
|
|
|
*phwnd = NULL;
|
|
if (m_pCandWnd != NULL) {
|
|
*phwnd = m_pCandWnd->GetWnd();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/* G E T A T T R I B U T E */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Get attribute of context
|
|
(ITfContextOwner method)
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::GetAttribute( REFGUID rguidAttribute, VARIANT *pvarValue )
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
/* O N K E Y D O W N */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
event sink for key down event
|
|
(ITfContextKeyEventSink method)
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::OnKeyDown( WPARAM wParam, LPARAM lParam, BOOL *pfEaten )
|
|
{
|
|
return OnKeyEvent( ICO_KEYDOWN, wParam, lParam, pfEaten );
|
|
}
|
|
|
|
|
|
/* O N K E Y U P */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
event sink for key up event
|
|
(ITfContextKeyEventSink method)
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::OnKeyUp( WPARAM wParam, LPARAM lParam, BOOL *pfEaten )
|
|
{
|
|
return OnKeyEvent( ICO_KEYUP, wParam, lParam, pfEaten );
|
|
}
|
|
|
|
|
|
/* O N T E S T K E Y D O W N */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
event sink for key down testing event
|
|
(ITfContextKeyEventSink method)
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::OnTestKeyDown( WPARAM wParam, LPARAM lParam, BOOL *pfEaten )
|
|
{
|
|
return OnKeyEvent( ICO_TESTKEYDOWN, wParam, lParam, pfEaten );
|
|
}
|
|
|
|
|
|
/* O N T E S T K E Y U P */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
event sink for key up testing event
|
|
(ITfContextKeyEventSink method)
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::OnTestKeyUp( WPARAM wParam, LPARAM lParam, BOOL *pfEaten )
|
|
{
|
|
return OnKeyEvent( ICO_TESTKEYUP, wParam, lParam, pfEaten );
|
|
}
|
|
|
|
|
|
/* T E X T E V E N T C A L L B A C K */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
text event (for own IC) callback function
|
|
(static function)
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::TextEventCallback( UINT uCode, VOID *pv, VOID *pvData )
|
|
{
|
|
HRESULT hr;
|
|
CCandidateUI *pCandUI;
|
|
|
|
//
|
|
|
|
pCandUI = (CCandidateUI *)pv;
|
|
Assert( pCandUI != NULL );
|
|
|
|
// ignore event of myself
|
|
|
|
if (uCode == ICF_TEXTDELTA) {
|
|
TESENDEDIT *pTESEndEdit = (TESENDEDIT*)pvData;
|
|
IEnumTfRanges *pEnumRanges;
|
|
|
|
if (SUCCEEDED(pTESEndEdit->pEditRecord->GetTextAndPropertyUpdates( TF_GTP_INCL_TEXT, NULL, 0, &pEnumRanges ))) {
|
|
CEditSession *pes;
|
|
|
|
if (pes = new CEditSession(EditSessionCallback)) {
|
|
pes->_state.u = ESCB_TEXTEVENT;
|
|
pes->_state.pv = (void *)pCandUI;
|
|
pes->_state.pic = pCandUI->m_pic;
|
|
pes->_state.pv1 = pEnumRanges; // DONT FORGET TO RELESE IT IN EDIT SESSION!!!
|
|
|
|
pCandUI->m_pic->RequestEditSession( 0, pes, TF_ES_READ | TF_ES_SYNC, &hr );
|
|
|
|
pes->Release();
|
|
}
|
|
else {
|
|
pEnumRanges->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// text event sink functions
|
|
//
|
|
|
|
/* I N I T T E X T E V E N T S I N K S */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
initialize sinks for text events
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::InitTextEventSinks( ITfContext *pic )
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
ITfSource *pSource = NULL;
|
|
|
|
Assert( pic == m_picParent );
|
|
Assert( !m_fTextEventSinkAdvised );
|
|
Assert( !IsInEditTransaction() );
|
|
|
|
m_fTextEventSinkAdvised = FALSE;
|
|
LeaveEditTransaction();
|
|
|
|
if (pic->QueryInterface( IID_ITfSource, (void **)&pSource) == S_OK) {
|
|
if (FAILED(pSource->AdviseSink( IID_ITfTextEditSink, (ITfTextEditSink *)this, &m_dwCookieTextEditSink ))) {
|
|
pSource->Release();
|
|
return hr;
|
|
}
|
|
|
|
if (FAILED(pSource->AdviseSink( IID_ITfTextLayoutSink, (ITfTextLayoutSink *)this, &m_dwCookieTextLayoutSink ))) {
|
|
pSource->UnadviseSink( m_dwCookieTextEditSink );
|
|
pSource->Release();
|
|
return hr;
|
|
}
|
|
|
|
if (FAILED(pSource->AdviseSink( IID_ITfEditTransactionSink, (ITfEditTransactionSink *)this, &m_dwCookieTransactionSink ))) {
|
|
pSource->UnadviseSink( m_dwCookieTextEditSink );
|
|
pSource->UnadviseSink( m_dwCookieTextLayoutSink );
|
|
pSource->Release();
|
|
return hr;
|
|
}
|
|
pSource->Release();
|
|
|
|
m_fTextEventSinkAdvised = TRUE;
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* D O N E T E X T E V E N T S I N K S */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
uninitialize sinks for text events
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::DoneTextEventSinks( ITfContext *pic )
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
ITfSource *pSource;
|
|
|
|
Assert( pic == m_picParent );
|
|
|
|
LeaveEditTransaction();
|
|
|
|
if (!m_fTextEventSinkAdvised) {
|
|
return S_OK;
|
|
}
|
|
|
|
if (pic->QueryInterface( IID_ITfSource, (void **)&pSource) == S_OK) {
|
|
pSource->UnadviseSink( m_dwCookieTextEditSink );
|
|
pSource->UnadviseSink( m_dwCookieTextLayoutSink );
|
|
pSource->UnadviseSink( m_dwCookieTransactionSink );
|
|
pSource->Release();
|
|
|
|
m_fTextEventSinkAdvised = FALSE;
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* O N E N D E D I T */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
event sink for text edit event
|
|
(ITfTextEditSink method)
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::OnEndEdit( ITfContext *pic, TfEditCookie ecReadOnly, ITfEditRecord *pEditRecord )
|
|
{
|
|
BOOL fInWriteSession = FALSE;
|
|
BOOL fSelChanged = FALSE;
|
|
|
|
// get selection status
|
|
|
|
if (FAILED(pEditRecord->GetSelectionStatus(&fSelChanged))) {
|
|
return S_OK;
|
|
}
|
|
|
|
// keep current selection always
|
|
|
|
if (fSelChanged) {
|
|
ITfRange *pSelection = NULL;
|
|
|
|
if (GetSelectionSimple( ecReadOnly, pic, &pSelection ) == S_OK) {
|
|
SetSelectionCur( pSelection );
|
|
}
|
|
|
|
SafeRelease( pSelection );
|
|
}
|
|
|
|
// ignore events during edit transaction
|
|
|
|
if (IsInEditTransaction()) {
|
|
return S_OK;
|
|
}
|
|
|
|
// ignore events made by client tip
|
|
|
|
pic->InWriteSession( m_tidClient, &fInWriteSession );
|
|
if (fInWriteSession) {
|
|
return S_OK;
|
|
}
|
|
|
|
// cancel candidate session when selection has been moved
|
|
|
|
if (fSelChanged) {
|
|
NotifyCancelCand();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/* O N L A Y O U T C H A N G E */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
event sink for text layout event
|
|
(ITfTextLayoutSink method)
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::OnLayoutChange( ITfContext *pic, TfLayoutCode lcode, ITfContextView *pView )
|
|
{
|
|
BOOL fInWriteSession = FALSE;
|
|
CEditSession *pes;
|
|
|
|
// ignore events made by client tip
|
|
|
|
pic->InWriteSession( m_tidClient, &fInWriteSession );
|
|
if (fInWriteSession) {
|
|
return S_OK;
|
|
}
|
|
|
|
// we only care about the active view
|
|
|
|
if (!IsActiveView( m_picParent, (ITfContextView *)pView )) {
|
|
return S_OK;
|
|
}
|
|
|
|
// move candidate window
|
|
|
|
Assert( m_pCandWnd != NULL );
|
|
if (pes = new CEditSession( EditSessionCallback )) {
|
|
HRESULT hr;
|
|
|
|
pes->_state.u = ESCB_RESETTARGETPOS;
|
|
pes->_state.pv = this;
|
|
pes->_state.wParam = 0;
|
|
pes->_state.pRange = m_pTargetRange;
|
|
pes->_state.pic = m_picParent;
|
|
|
|
m_picParent->RequestEditSession( m_tidClient, pes, TF_ES_READ | TF_ES_SYNC, &hr );
|
|
|
|
pes->Release();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/* O N S T A R T E D I T T R A N S A C T I O N */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
event sink for start of application transaction
|
|
(ITfEditTransactionSink method)
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::OnStartEditTransaction( ITfContext *pic )
|
|
{
|
|
// enter transaction session
|
|
|
|
Assert( !IsInEditTransaction() );
|
|
EnterEditTransaction( GetSelectionCur() );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/* O N E N D E D I T T R A N S A C T I O N */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
event sink for end of application transaction
|
|
(ITfEditTransactionSink method)
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::OnEndEditTransaction( ITfContext *pic )
|
|
{
|
|
CEditSession *pes;
|
|
// sanity check
|
|
|
|
if (!IsInEditTransaction()) {
|
|
return S_OK;
|
|
}
|
|
|
|
// check selection movement
|
|
|
|
if (pes = new CEditSession( EditSessionCallback )) {
|
|
HRESULT hr;
|
|
|
|
pes->_state.u = ESCB_COMPARERANGEANDCLOSECANDIDATE;
|
|
pes->_state.pv = this;
|
|
pes->_state.pv1 = GetSelectionStart();
|
|
pes->_state.pv2 = GetSelectionCur();
|
|
pes->_state.pic = m_picParent;
|
|
|
|
m_picParent->RequestEditSession( m_tidClient, pes, TF_ES_READ | TF_ES_ASYNC, &hr );
|
|
|
|
pes->Release();
|
|
}
|
|
|
|
// leave transaction session
|
|
|
|
LeaveEditTransaction();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// edit session
|
|
//
|
|
|
|
/* E D I T S E S S I O N C A L L B A C K */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::EditSessionCallback( TfEditCookie ec, CEditSession *pes )
|
|
{
|
|
CCandidateUI *pCandUI;
|
|
|
|
switch (pes->_state.u)
|
|
{
|
|
case ESCB_RESETTARGETPOS:
|
|
{
|
|
pCandUI = (CCandidateUI *)pes->_state.pv;
|
|
RECT rc;
|
|
BOOL fClipped;
|
|
|
|
if (pes->_state.pRange == NULL || pCandUI->m_pCandWnd == NULL) {
|
|
break;
|
|
}
|
|
|
|
if (!pCandUI->GetPropertyMgr()->GetCandWindowProp()->IsAutoMoveEnabled()) {
|
|
break;
|
|
}
|
|
|
|
// reset target clause poisition
|
|
|
|
GetTextExtInActiveView( ec, pes->_state.pRange, &rc, &fClipped );
|
|
pCandUI->m_pCandWnd->SetTargetRect( &rc, fClipped );
|
|
break;
|
|
}
|
|
|
|
case ESCB_COMPARERANGEANDCLOSECANDIDATE:
|
|
{
|
|
ITfContext *pic = pes->_state.pic;
|
|
BOOL fRangeIdentical = FALSE;
|
|
ITfRange *pRange1 = (ITfRange*)pes->_state.pv1;
|
|
ITfRange *pRange2 = (ITfRange*)pes->_state.pv2;
|
|
LONG lStart;
|
|
LONG lEnd;
|
|
CCandidateUI *_this = (CCandidateUI *)pes->_state.pv;
|
|
|
|
pRange1->CompareStart( ec, pRange2, TF_ANCHOR_START, &lStart );
|
|
pRange1->CompareEnd( ec, pRange2, TF_ANCHOR_END, &lEnd );
|
|
|
|
fRangeIdentical = (lStart == 0) && (lEnd == 0);
|
|
|
|
// Since we made this call asynchronous, we need
|
|
if (!fRangeIdentical)
|
|
{
|
|
_this->NotifyCancelCand();
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ESCB_TEXTEVENT:
|
|
{
|
|
pCandUI = (CCandidateUI *)pes->_state.pv;
|
|
ITfContext *pic = pes->_state.pic;
|
|
IEnumTfRanges *pEnumRanges = (IEnumTfRanges *)pes->_state.pv1;
|
|
|
|
// handle textevent
|
|
pCandUI->HandleTextDeltas( ec, pic, pEnumRanges );
|
|
|
|
pEnumRanges->Release();
|
|
break;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// selection
|
|
//
|
|
|
|
/* S E T S E L E C T I O N C U R */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
void CCandidateUI::SetSelectionCur( ITfRange *pSelection )
|
|
{
|
|
SafeReleaseClear( m_pSelectionCur );
|
|
m_pSelectionCur = pSelection;
|
|
if (m_pSelectionCur != NULL) {
|
|
m_pSelectionCur->AddRef();
|
|
}
|
|
}
|
|
|
|
|
|
/* C L E A R S E L E C T I O N C U R */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
void CCandidateUI::ClearSelectionCur( void )
|
|
{
|
|
SafeReleaseClear( m_pSelectionCur );
|
|
}
|
|
|
|
|
|
/* G E T S E L E C T I O N C U R */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
ITfRange *CCandidateUI::GetSelectionCur( void )
|
|
{
|
|
return m_pSelectionCur;
|
|
}
|
|
|
|
|
|
//
|
|
// transaction session functions
|
|
//
|
|
|
|
/* S E T S E L E C T I O N S T A R T */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
void CCandidateUI::SetSelectionStart( ITfRange *pSelection )
|
|
{
|
|
SafeReleaseClear( m_pSelectionStart );
|
|
m_pSelectionStart = pSelection;
|
|
if (m_pSelectionStart != NULL) {
|
|
m_pSelectionStart->AddRef();
|
|
}
|
|
}
|
|
|
|
|
|
/* C L E A R S E L E C T I O N S T A R T */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
void CCandidateUI::ClearSelectionStart( void )
|
|
{
|
|
SafeReleaseClear( m_pSelectionStart );
|
|
}
|
|
|
|
|
|
/* G E T S E L E C T I O N S T A R T */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
ITfRange *CCandidateUI::GetSelectionStart( void )
|
|
{
|
|
return m_pSelectionStart;
|
|
}
|
|
|
|
|
|
/* E N T E R E D I T T R A N S A C T I O N */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
void CCandidateUI::EnterEditTransaction( ITfRange *pSelection )
|
|
{
|
|
Assert( !m_fInTransaction );
|
|
|
|
if (pSelection == NULL) {
|
|
return;
|
|
}
|
|
|
|
m_fInTransaction = TRUE;
|
|
SetSelectionStart( pSelection );
|
|
}
|
|
|
|
|
|
/* L E A V E E D I T T R A N S A C T I O N */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
void CCandidateUI::LeaveEditTransaction( void )
|
|
{
|
|
m_fInTransaction = FALSE;
|
|
ClearSelectionStart();
|
|
}
|
|
|
|
|
|
//
|
|
// notification function (notification to client)
|
|
//
|
|
|
|
/* N O T I F Y C A N C E L C A N D */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Send notification (callback) to TIP that to cancel candidate
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::NotifyCancelCand( void )
|
|
{
|
|
if (m_pCandWnd) {
|
|
m_pCandWnd->UpdateAllWindow();
|
|
}
|
|
|
|
return CallSetResult( 0, CAND_CANCELED );
|
|
}
|
|
|
|
|
|
/* N O T I F Y S E L E C T C A N D */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Send notification (callback) to TIP that selection has been changed
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::NotifySelectCand( int iCandItem )
|
|
{
|
|
HRESULT hr;
|
|
ULONG nIndex;
|
|
|
|
// NOTE: Do not send a notification to TIP to prevent from updating inline
|
|
// text during filtering.
|
|
// This will be called by filtering candidates, and aslo sorting candidates
|
|
// because selection in UI will be changed by sorting. But the actual selected
|
|
// item never changed by sorting. When the selection has been changed by
|
|
// user action such as hitting arrow key, the filtering string has already
|
|
// been reset. So, we can send notify correctly in that case.
|
|
|
|
if (GetFunctionMgr()->GetCandFnAutoFilter()->IsEnabled()) {
|
|
if (GetFunctionMgr()->GetCandFnAutoFilter()->GetFilterString() != NULL) {
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
Assert( GetCandListMgr()->GetCandList() != NULL );
|
|
|
|
hr = GetCandListMgr()->GetCandList()->MapIItemToIndex( iCandItem, &nIndex );
|
|
if (FAILED(hr)) {
|
|
Assert( FALSE );
|
|
return hr;
|
|
}
|
|
|
|
if (m_pCandWnd) {
|
|
m_pCandWnd->UpdateAllWindow();
|
|
}
|
|
|
|
return CallSetResult( nIndex, CAND_SELECTED );
|
|
}
|
|
|
|
|
|
/* N O T I F Y C O M P L E T E O P T I O N */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Send notification (callback) to TIP that to complete option
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::NotifyCompleteOption( int iCandItem )
|
|
{
|
|
HRESULT hr;
|
|
ULONG nIndex;
|
|
|
|
Assert( GetCandListMgr()->GetOptionsList() != NULL );
|
|
|
|
hr = GetCandListMgr()->GetOptionsList()->MapIItemToIndex( iCandItem, &nIndex );
|
|
if (FAILED(hr)) {
|
|
Assert( FALSE );
|
|
return hr;
|
|
}
|
|
|
|
if (m_pCandWnd) {
|
|
m_pCandWnd->UpdateAllWindow();
|
|
}
|
|
|
|
return CallSetOptionResult( nIndex, CAND_FINALIZED );
|
|
}
|
|
|
|
|
|
/* N O T I F Y C O M P L E T E C A N D */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Send notification (callback) to TIP that to complete candidate
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::NotifyCompleteCand( int iCandItem )
|
|
{
|
|
HRESULT hr;
|
|
ULONG nIndex;
|
|
|
|
Assert( GetCandListMgr()->GetCandList() != NULL );
|
|
|
|
hr = GetCandListMgr()->GetCandList()->MapIItemToIndex( iCandItem, &nIndex );
|
|
if (FAILED(hr)) {
|
|
Assert( FALSE );
|
|
return hr;
|
|
}
|
|
|
|
if (m_pCandWnd) {
|
|
m_pCandWnd->UpdateAllWindow();
|
|
}
|
|
|
|
return CallSetResult( nIndex, CAND_FINALIZED );
|
|
}
|
|
|
|
|
|
/* N O T I F Y E X T E N S I O N E V E N T */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::NotifyExtensionEvent( int iExtension, DWORD dwCommand, LPARAM lParam )
|
|
{
|
|
CCandUIExtension *pExtension;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
pExtension = GetExtensionMgr()->GetExtension( iExtension );
|
|
if (pExtension != NULL) {
|
|
hr = pExtension->NotifyExtensionEvent( dwCommand, lParam );
|
|
}
|
|
|
|
if (m_pCandWnd) {
|
|
m_pCandWnd->UpdateAllWindow();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* N O T I F Y F I L T E R I N G E V E N T */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::NotifyFilteringEvent( CANDUIFILTEREVENT ev )
|
|
{
|
|
Assert( GetFunctionMgr()->GetCandFnAutoFilter()->IsEnabled() );
|
|
|
|
if (m_pCandWnd) {
|
|
m_pCandWnd->UpdateAllWindow();
|
|
}
|
|
|
|
if (GetFunctionMgr()->GetCandFnAutoFilter()->GetEventSink() != NULL) {
|
|
return GetFunctionMgr()->GetCandFnAutoFilter()->GetEventSink()->OnFilterEvent( ev );
|
|
}
|
|
else {
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
|
|
/* N O T I F Y S O R T E V E N T */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::NotifySortEvent( CANDUISORTEVENT ev )
|
|
{
|
|
if (m_pCandWnd) {
|
|
m_pCandWnd->UpdateAllWindow();
|
|
}
|
|
|
|
if (GetFunctionMgr()->GetCandFnSort()->GetEventSink() != NULL) {
|
|
return GetFunctionMgr()->GetCandFnSort()->GetEventSink()->OnSortEvent( ev );
|
|
}
|
|
else {
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
|
|
/* N O T I F Y C O M P L E T E R A W D A T A */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::NotifyCompleteRawData( void )
|
|
{
|
|
HRESULT hr;
|
|
|
|
Assert( GetCandListMgr()->GetCandList() != NULL );
|
|
|
|
if (m_pCandWnd) {
|
|
m_pCandWnd->UpdateAllWindow();
|
|
}
|
|
|
|
hr = CallSetResult( GetCandListMgr()->GetCandList()->GetRawDataIndex(), CAND_FINALIZED );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* N O T I F Y C O M P L E T E E X T R A C A N D */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::NotifyCompleteExtraCand( void )
|
|
{
|
|
HRESULT hr;
|
|
|
|
Assert( GetCandListMgr()->GetCandList() != NULL );
|
|
|
|
if (m_pCandWnd) {
|
|
m_pCandWnd->UpdateAllWindow();
|
|
}
|
|
|
|
hr = CallSetResult( GetCandListMgr()->GetCandList()->GetExtraCandIndex(), CAND_FINALIZED );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* C A L L S E T R E S U L T */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Send notification to TIP
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::CallSetOptionResult( int nIndex, TfCandidateResult imcr )
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
AddRef();
|
|
|
|
if (!m_fInCallback) {
|
|
ITfOptionsCandidateList *pCandList;
|
|
|
|
m_fInCallback = TRUE;
|
|
if (SUCCEEDED(GetCandListMgr()->GetOptionsCandidateList( &pCandList ))) {
|
|
hr = pCandList->SetOptionsResult( nIndex, imcr );
|
|
pCandList->Release();
|
|
}
|
|
m_fInCallback = FALSE;
|
|
}
|
|
|
|
Release();
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* C A L L S E T R E S U L T */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Send notification to TIP
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::CallSetResult( int nIndex, TfCandidateResult imcr )
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
AddRef();
|
|
|
|
if (!m_fInCallback) {
|
|
ITfCandidateList *pCandList;
|
|
|
|
m_fInCallback = TRUE;
|
|
if (SUCCEEDED(GetCandListMgr()->GetCandidateList( &pCandList ))) {
|
|
hr = pCandList->SetResult( nIndex, imcr );
|
|
pCandList->Release();
|
|
}
|
|
m_fInCallback = FALSE;
|
|
}
|
|
|
|
Release();
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// internal functions
|
|
//
|
|
|
|
/* C R E A T E C A N D W I N D O W O B J E C T */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::CreateCandWindowObject( ITfContext *pic, CCandWindowBase** ppCandWnd )
|
|
{
|
|
CANDUISTYLE style;
|
|
DWORD dwOption;
|
|
DWORD dwStyle;
|
|
|
|
Assert( ppCandWnd );
|
|
*ppCandWnd = NULL;
|
|
|
|
if (FAILED( GetCompartmentMgr()->GetUIStyle( pic, &style ))) {
|
|
style = CANDUISTY_LIST;
|
|
}
|
|
|
|
if (FAILED( GetCompartmentMgr()->GetUIOption( pic, &dwOption ))) {
|
|
dwOption = 0;
|
|
}
|
|
|
|
dwStyle = 0;
|
|
if ((dwOption & CANDUIOPT_ENABLETHEME) != 0) {
|
|
dwStyle |= UIWINDOW_WHISTLERLOOK;
|
|
}
|
|
|
|
switch (style) {
|
|
default:
|
|
case CANDUISTY_LIST: {
|
|
*ppCandWnd = new CCandWindow( this, dwStyle );
|
|
break;
|
|
}
|
|
|
|
case CANDUISTY_ROW: {
|
|
*ppCandWnd = new CChsCandWindow( this, dwStyle );
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (*ppCandWnd != NULL) ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
/* I N I T C A N D W I N D O W */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::InitCandWindow( void )
|
|
{
|
|
CEditSession *pes;
|
|
|
|
if (m_pCandWnd == NULL) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
m_pCandWnd->Initialize();
|
|
|
|
// move candidate window
|
|
|
|
Assert( m_pCandWnd != NULL );
|
|
if (pes = new CEditSession( EditSessionCallback )) {
|
|
HRESULT hr;
|
|
|
|
pes->_state.u = ESCB_RESETTARGETPOS;
|
|
pes->_state.pv = this;
|
|
pes->_state.wParam = 0;
|
|
pes->_state.pRange = m_pTargetRange;
|
|
pes->_state.pic = m_picParent;
|
|
|
|
m_picParent->RequestEditSession( m_tidClient, pes, TF_ES_READ | TF_ES_SYNC, &hr );
|
|
|
|
pes->Release();
|
|
}
|
|
|
|
// initialize candidate list
|
|
|
|
m_pCandWnd->InitCandidateList();
|
|
|
|
// create window
|
|
|
|
m_pCandWnd->CreateWnd( m_hWndParent );
|
|
m_pCandWnd->Show( GetPropertyMgr()->GetCandWindowProp()->IsVisible() );
|
|
m_pCandWnd->UpdateAllWindow();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
/* O N K E Y E V E N T */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::OnKeyEvent( UINT uCode, WPARAM wParam, LPARAM lParam, BOOL *pfEaten )
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
BOOL fHandled = FALSE;
|
|
BYTE rgbKeyState[ 256 ];
|
|
|
|
Assert( pfEaten != NULL );
|
|
Assert( uCode == ICO_KEYDOWN || uCode == ICO_KEYUP || uCode == ICO_TESTKEYDOWN || uCode == ICO_TESTKEYUP );
|
|
|
|
if (pfEaten == NULL) {
|
|
return E_POINTER;
|
|
}
|
|
|
|
*pfEaten = FALSE;
|
|
|
|
if (m_pCandWnd == NULL) {
|
|
return hr;
|
|
}
|
|
|
|
if (GetKeyboardState( rgbKeyState )) {
|
|
if (GetFunctionMgr()->GetCandFnAutoFilter()->IsEnabled()) {
|
|
fHandled = FHandleFilteringKey( uCode, (int)wParam, rgbKeyState, pfEaten );
|
|
}
|
|
|
|
if (!fHandled) {
|
|
fHandled = FHandleKeyEvent( uCode, (int)wParam, rgbKeyState, pfEaten );
|
|
}
|
|
|
|
// cancel candidate when unknown key has come
|
|
|
|
if (!fHandled) {
|
|
NotifyCancelCand();
|
|
}
|
|
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* H A N D L E K E Y E V E N T */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Handling key event
|
|
return S_OK when processed the key event.
|
|
|
|
------------------------------------------------------------------------------*/
|
|
BOOL CCandidateUI::FHandleKeyEvent( UINT uCode, UINT uVKey, BYTE *pbKeyState, BOOL *pfEatKey )
|
|
{
|
|
CANDUICOMMAND cmd;
|
|
UINT uiParam;
|
|
|
|
// NOTE: KOJIW: We need to ignore keyup events to not close candidate UI
|
|
// immediately after TIP opens CandidateUI with KEYDOWN of unknown key.
|
|
|
|
if (uCode == ICO_KEYUP || uCode == ICO_TESTKEYUP) {
|
|
return TRUE;
|
|
}
|
|
|
|
// process command on keydown
|
|
|
|
CommandFromKey( uVKey, pbKeyState, &cmd, &uiParam );
|
|
if (cmd == CANDUICMD_NONE) {
|
|
switch (uVKey) {
|
|
case VK_SHIFT:
|
|
case VK_CONTROL: {
|
|
return TRUE;
|
|
}
|
|
|
|
default: {
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (uCode == ICO_KEYDOWN) {
|
|
*pfEatKey = SUCCEEDED(m_pCandWnd->ProcessCommand( cmd, uiParam ));
|
|
}
|
|
else {
|
|
*pfEatKey = TRUE;
|
|
}
|
|
|
|
return *pfEatKey;
|
|
}
|
|
|
|
|
|
/* H A N D L E T E X T D E L T A S */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
BOOL CCandidateUI::HandleTextDeltas( TfEditCookie ec, ITfContext *pic, IEnumTfRanges *pEnumRanges )
|
|
{
|
|
ULONG ulFetched;
|
|
ITfRange *pRange;
|
|
|
|
pEnumRanges->Reset();
|
|
while (pEnumRanges->Next( 1, &pRange, &ulFetched ) == S_OK) {
|
|
WCHAR szText[ 256 ];
|
|
ULONG cch;
|
|
|
|
// check text in the range
|
|
|
|
szText[0] = L'\0';
|
|
cch = 0;
|
|
if (pRange != NULL) {
|
|
pRange->GetText( ec, 0, szText, ARRAYSIZE(szText), &cch );
|
|
pRange->Release();
|
|
}
|
|
|
|
//
|
|
|
|
if (0 < cch) {
|
|
int i = 0;
|
|
ULONG ich;
|
|
|
|
for (ich = 0; ich < cch; ich++) {
|
|
if ((L'0' <= szText[ich]) && (szText[ich] <= L'9')) {
|
|
i = i * 10 + (szText[ich] - L'0');
|
|
}
|
|
else if (szText[ich] == L' ') {
|
|
break;
|
|
}
|
|
else {
|
|
i = -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (0 <= i) {
|
|
if (i == 0) {
|
|
PostCommand( CANDUICMD_SELECTEXTRACAND, 0 );
|
|
}
|
|
else {
|
|
PostCommand( CANDUICMD_SELECTLINE, i );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* P O S T C O M M A N D */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
void CCandidateUI::PostCommand( CANDUICOMMAND cmd, INT iParam )
|
|
{
|
|
if ((cmd != CANDUICMD_NONE) && (m_pCandWnd != NULL)) {
|
|
PostMessage( m_pCandWnd->GetWnd(), WM_USER, (WPARAM)cmd, (LPARAM)iParam );
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Auto filtering functions
|
|
//
|
|
|
|
/* H A N D L E F I L T E R I N G K E Y */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Handle key event for filtering
|
|
Returns TRUE to eat the event (when key has been handled)
|
|
|
|
------------------------------------------------------------------------------*/
|
|
BOOL CCandidateUI::FHandleFilteringKey( UINT uCode, UINT uVKey, BYTE *pbKeyState, BOOL *pfEatKey )
|
|
{
|
|
BOOL fHandled = FALSE;
|
|
BOOL fUpdateList = FALSE;
|
|
|
|
switch (uVKey) {
|
|
case VK_RETURN: {
|
|
break;
|
|
}
|
|
|
|
case VK_TAB: {
|
|
if (GetCandListMgr()->GetCandList() != NULL) {
|
|
if (uCode == ICO_KEYDOWN) {
|
|
int iCandItem;
|
|
|
|
iCandItem = GetCandListMgr()->GetCandList()->GetSelection();
|
|
NotifyCompleteCand( iCandItem );
|
|
|
|
*pfEatKey = TRUE;
|
|
}
|
|
else {
|
|
*pfEatKey = TRUE;
|
|
}
|
|
|
|
fHandled = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case VK_BACK: {
|
|
if (uCode == ICO_KEYDOWN) {
|
|
*pfEatKey = (DelFilteringChar( &fUpdateList ) == S_OK);
|
|
}
|
|
else {
|
|
*pfEatKey = TRUE;
|
|
}
|
|
|
|
fHandled = TRUE;
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
WCHAR wch;
|
|
|
|
// Check this is not a control + key combination as we do not want to pass this on to the filtering system.
|
|
|
|
if (pbKeyState[VK_CONTROL] & 0x80) {
|
|
break;
|
|
}
|
|
|
|
// convert key to char
|
|
|
|
wch = CharFromKey( uVKey, pbKeyState );
|
|
if (wch == L'\0') {
|
|
break;
|
|
}
|
|
|
|
// add filtering character
|
|
|
|
if (uCode == ICO_KEYDOWN) {
|
|
*pfEatKey = (AddFilteringChar( wch, &fUpdateList ) == S_OK);
|
|
}
|
|
else {
|
|
*pfEatKey = TRUE;
|
|
}
|
|
|
|
fHandled = *pfEatKey;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// update candidate list
|
|
|
|
if (fUpdateList) {
|
|
*pfEatKey &= (FilterCandidateList() == S_OK);
|
|
}
|
|
|
|
return fHandled;
|
|
}
|
|
|
|
|
|
/* A D D F I L T E R I N G C H A R */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::AddFilteringChar( WCHAR wch, BOOL *pfUpdateList )
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
LPCWSTR szFilterCur;
|
|
WCHAR *szFilterNew;
|
|
int cch;
|
|
|
|
*pfUpdateList = FALSE;
|
|
if (!GetFunctionMgr()->GetCandFnAutoFilter()->IsEnabled()) {
|
|
return S_FALSE;
|
|
}
|
|
|
|
// append a character and set filtering string
|
|
|
|
szFilterCur = GetFunctionMgr()->GetCandFnAutoFilter()->GetFilterString();
|
|
if (szFilterCur == NULL) {
|
|
cch = 0;
|
|
szFilterNew = new WCHAR[ 2 ];
|
|
}
|
|
else {
|
|
cch = wcslen(szFilterCur);
|
|
szFilterNew = new WCHAR[ cch + 2 ];
|
|
}
|
|
|
|
if (szFilterNew == NULL) {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (szFilterCur != NULL) {
|
|
StringCchCopyW( szFilterNew, cch+2, szFilterCur );
|
|
}
|
|
*(szFilterNew + cch) = wch;
|
|
*(szFilterNew + cch + 1) = L'\0';
|
|
|
|
// Satori#3632: check if there is item matches with new filter string
|
|
// (return S_FALSE when no item matches to pass key event to keyboard command handler)
|
|
|
|
if (GetFunctionMgr()->GetCandFnAutoFilter()->FExistItemMatches( szFilterNew )) {
|
|
GetFunctionMgr()->GetCandFnAutoFilter()->SetFilterString( szFilterNew );
|
|
*pfUpdateList = TRUE;
|
|
hr = S_OK;
|
|
}
|
|
else {
|
|
|
|
// Only when alpha, punctation, space key is pressed,
|
|
// and there is no alternate match because of this input,
|
|
// we want to notify client of NONMATCH event, so that
|
|
// client can inject the previous filter string to document,
|
|
//
|
|
// for all other key input, we don't notify that event.
|
|
|
|
if ( iswalpha(wch) || iswpunct(wch) )
|
|
{
|
|
// Notify client of non-matching.
|
|
NotifyFilteringEvent( CANDUIFEV_NONMATCH );
|
|
NotifyCancelCand();
|
|
}
|
|
|
|
hr = S_FALSE;
|
|
|
|
}
|
|
|
|
delete szFilterNew;
|
|
|
|
//
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* D E L F I L T E R I N G C H A R */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::DelFilteringChar( BOOL *pfUpdateList )
|
|
{
|
|
LPCWSTR szFilterCur;
|
|
WCHAR *szFilterNew;
|
|
int cch;
|
|
|
|
*pfUpdateList = FALSE;
|
|
if (!GetFunctionMgr()->GetCandFnAutoFilter()->IsEnabled()) {
|
|
return S_OK;
|
|
}
|
|
|
|
// get current filtering string
|
|
|
|
szFilterCur = GetFunctionMgr()->GetCandFnAutoFilter()->GetFilterString();
|
|
if (szFilterCur == NULL) {
|
|
NotifyCancelCand();
|
|
return S_FALSE;
|
|
}
|
|
|
|
// delete last character and set filtering string
|
|
|
|
cch = wcslen(szFilterCur);
|
|
Assert( 0 < cch );
|
|
|
|
szFilterNew = new WCHAR[ cch + 1 ];
|
|
if (szFilterNew == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
StringCchCopyW( szFilterNew, cch+1, szFilterCur );
|
|
*(szFilterNew + cch - 1) = L'\0';
|
|
|
|
GetFunctionMgr()->GetCandFnAutoFilter()->SetFilterString( szFilterNew );
|
|
|
|
delete szFilterNew;
|
|
|
|
//
|
|
|
|
*pfUpdateList = TRUE;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/* F I L T E R C A N D I D A T E L I S T */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::FilterCandidateList( void )
|
|
{
|
|
int nItemVisible;
|
|
|
|
if (!GetFunctionMgr()->GetCandFnAutoFilter()->IsEnabled()) {
|
|
return S_OK;
|
|
}
|
|
|
|
Assert( GetCandListMgr()->GetCandList() != NULL );
|
|
|
|
// build candidate list with filtering
|
|
|
|
nItemVisible = GetFunctionMgr()->GetCandFnAutoFilter()->FilterCandidateList();
|
|
|
|
// close candidate when no item has been mathced
|
|
|
|
if (nItemVisible == 0) {
|
|
NotifyCancelCand();
|
|
return E_FAIL;
|
|
}
|
|
|
|
// complete candidate when only one item matched and user typed fully
|
|
|
|
if (nItemVisible == 1) {
|
|
CCandidateItem *pCandItem;
|
|
int iCandItem;
|
|
BOOL fComplete = FALSE;
|
|
|
|
iCandItem = GetCandListMgr()->GetCandList()->GetSelection();
|
|
pCandItem = GetCandListMgr()->GetCandList()->GetCandidateItem( iCandItem );
|
|
Assert( pCandItem != NULL );
|
|
|
|
if ((pCandItem != NULL) && (GetFunctionMgr()->GetCandFnAutoFilter()->GetFilterString() != NULL)) {
|
|
fComplete = (wcslen(pCandItem->GetString()) == wcslen(GetFunctionMgr()->GetCandFnAutoFilter()->GetFilterString()));
|
|
}
|
|
|
|
if (fComplete) {
|
|
NotifyCompleteCand( iCandItem );
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
// notify TIP that filtering has been updated
|
|
|
|
NotifyFilteringEvent( CANDUIFEV_UPDATED );
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/* FHandleSpellingChar */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::FHandleSpellingChar(WCHAR ch)
|
|
{
|
|
BOOL fUpdateList = FALSE;
|
|
|
|
if (S_OK == AddFilteringChar( ch, &fUpdateList ) && fUpdateList) {
|
|
return FilterCandidateList();
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
/*
|
|
**
|
|
** Speech handling functions
|
|
**
|
|
**
|
|
*/
|
|
|
|
/* E N S U R E S P E E C H */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
void CCandidateUI::EnsureSpeech(void)
|
|
{
|
|
if (m_pSpTask)
|
|
{
|
|
// make sure grammars are up/running
|
|
m_pSpTask->_LoadGrammars();
|
|
m_pSpTask->_Activate(TRUE);
|
|
return;
|
|
|
|
}
|
|
|
|
m_pSpTask = new CSpTask(this);
|
|
if (m_pSpTask)
|
|
{
|
|
if (!m_pSpTask->IsSpeechInitialized())
|
|
{
|
|
m_pSpTask->InitializeSpeech();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* N O T I F Y S P E E C H C M D */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Speech command handler
|
|
|
|
------------------------------------------------------------------------------*/
|
|
HRESULT CCandidateUI::NotifySpeechCmd(SPPHRASE *pPhrase, const WCHAR *pszRuleName, ULONG ulRuleId)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CANDUICOMMAND cmd;
|
|
UINT uiParam;
|
|
|
|
if (m_pCandWnd == NULL) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
CommandFromRule( pszRuleName, &cmd, &uiParam );
|
|
if (cmd != CANDUICMD_NONE) {
|
|
m_pCandWnd->ProcessCommand( cmd, uiParam );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* C H A R F R O M K E Y */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
WCHAR CCandidateUI::CharFromKey( UINT uVKey, BYTE *pbKeyState )
|
|
{
|
|
WORD wBuf;
|
|
char rgch[2];
|
|
WCHAR wch;
|
|
int cch;
|
|
int cwch;
|
|
|
|
cch = ToAscii( uVKey, 0, pbKeyState, &wBuf, 0 );
|
|
|
|
rgch[0] = LOBYTE(wBuf);
|
|
rgch[1] = HIBYTE(wBuf);
|
|
cwch = MultiByteToWideChar( m_codepage, 0, rgch, cch, &wch, 1 );
|
|
if (cwch != 1) {
|
|
wch = L'\0';
|
|
}
|
|
|
|
return wch;
|
|
}
|
|
|
|
|
|
/* G E T K E Y C O N F I G P R O C */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
CCandUIKeyTable *CCandidateUI::GetKeyTableProc( ITfContext *pic )
|
|
{
|
|
CCandUIKeyTable *pCandUIKeyTable;
|
|
CANDUISTYLE style;
|
|
|
|
// check key table in input context
|
|
|
|
if (GetCompartmentMgr() != NULL) {
|
|
if (SUCCEEDED(GetCompartmentMgr()->GetKeyTable( pic, &pCandUIKeyTable ))) {
|
|
return pCandUIKeyTable;
|
|
}
|
|
}
|
|
|
|
// use default key table
|
|
|
|
if (FAILED(GetCompartmentMgr()->GetUIStyle( pic, &style ))) {
|
|
style = CANDUISTY_LIST;
|
|
}
|
|
|
|
pCandUIKeyTable = new CCandUIKeyTable();
|
|
if (pCandUIKeyTable)
|
|
{
|
|
switch (style) {
|
|
default:
|
|
case CANDUISTY_LIST: {
|
|
pCandUIKeyTable->SetKeyTable( rgKeyDefList, ARRAYSIZE(rgKeyDefList) );
|
|
break;
|
|
}
|
|
|
|
case CANDUISTY_ROW: {
|
|
pCandUIKeyTable->SetKeyTable( rgKeyDefRow, ARRAYSIZE(rgKeyDefRow) );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return pCandUIKeyTable;
|
|
}
|
|
|
|
|
|
/* C O M M A N D F R O M K E Y */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Get command from key
|
|
|
|
------------------------------------------------------------------------------*/
|
|
void CCandidateUI::CommandFromKey( UINT uVKey, BYTE *pbKeyState, CANDUICOMMAND *pcmd, UINT *pParam )
|
|
{
|
|
Assert( pcmd != NULL );
|
|
Assert( pParam != NULL );
|
|
Assert( pbKeyState != NULL );
|
|
|
|
*pcmd = CANDUICMD_NONE;
|
|
*pParam = 0;
|
|
|
|
// check special keys
|
|
|
|
switch( uVKey) {
|
|
case VK_TAB: {
|
|
*pcmd = CANDUICMD_NOP;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (*pcmd != CANDUICMD_NONE) {
|
|
return;
|
|
}
|
|
|
|
// find from key table
|
|
|
|
if (m_pCandUIKeyTable != NULL) {
|
|
WCHAR wch = CharFromKey( uVKey, pbKeyState );
|
|
|
|
m_pCandUIKeyTable->CommandFromKey( uVKey, wch, pbKeyState, GetPropertyMgr()->GetCandWindowProp()->GetUIDirection(), pcmd, pParam );
|
|
}
|
|
}
|
|
|
|
|
|
/* C O M M A N D F R O M R U L E */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Get command from speech rule
|
|
|
|
------------------------------------------------------------------------------*/
|
|
void CCandidateUI::CommandFromRule( LPCWSTR szRule, CANDUICOMMAND *pcmd, UINT *pParam )
|
|
{
|
|
const RULEDEF *pRuleDef = NULL;
|
|
int nRuleDef = 0;
|
|
|
|
Assert( pcmd != NULL );
|
|
Assert( pParam != NULL );
|
|
|
|
*pcmd = CANDUICMD_NONE;
|
|
*pParam = 0;
|
|
|
|
//
|
|
// find ruledef table from current state
|
|
//
|
|
|
|
// NOTE: Currently CandidateUI doesn't have candidate Menu... only Normal state is available
|
|
if (!m_pCandWnd->FCandMenuOpen()) {
|
|
pRuleDef = rgRuleNorm;
|
|
nRuleDef = ARRAYSIZE(rgRuleNorm);
|
|
}
|
|
|
|
//
|
|
// get command from ruledef table
|
|
//
|
|
|
|
if (pRuleDef != NULL) {
|
|
while (0 < nRuleDef) {
|
|
if (wcscmp( szRule, pRuleDef->szRuleName ) == 0) {
|
|
*pcmd = pRuleDef->cmd;
|
|
*pParam = pRuleDef->uiParam;
|
|
break;
|
|
}
|
|
nRuleDef--;
|
|
pRuleDef++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
/* C T F C A N D I D A T E U I C O N T E X T O W N E R */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
constructor of CTfCandidateUIContextOwner
|
|
|
|
------------------------------------------------------------------------------*/
|
|
CTfCandidateUIContextOwner::CTfCandidateUIContextOwner( CCandidateUI *pCandUI )
|
|
{
|
|
m_pCandUI = pCandUI;
|
|
if (m_pCandUI != NULL) {
|
|
m_pCandUI->AddRef();
|
|
}
|
|
}
|
|
|
|
|
|
/* ~ C T F C A N D I D A T E U I C O N T E X T O W N E R */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
destructor of CTfCandidateUIContextOwner
|
|
|
|
------------------------------------------------------------------------------*/
|
|
CTfCandidateUIContextOwner::~CTfCandidateUIContextOwner( void )
|
|
{
|
|
if (m_pCandUI != NULL) {
|
|
m_pCandUI->Release();
|
|
}
|
|
}
|
|
|
|
|
|
/* Q U E R Y I N T E R F A C E */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Query interface
|
|
(IUnknown method)
|
|
|
|
------------------------------------------------------------------------------*/
|
|
STDAPI CTfCandidateUIContextOwner::QueryInterface( REFIID riid, void **ppvObj )
|
|
{
|
|
if (ppvObj == NULL) {
|
|
return E_POINTER;
|
|
}
|
|
|
|
*ppvObj = NULL;
|
|
|
|
if (IsEqualIID( riid, IID_IUnknown ) || IsEqualIID( riid, IID_ITfCandidateUIContextOwner )) {
|
|
*ppvObj = SAFECAST( this, ITfCandidateUIContextOwner* );
|
|
}
|
|
|
|
if (*ppvObj == NULL) {
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/* A D D R E F */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Increment reference count
|
|
(IUnknown method)
|
|
|
|
------------------------------------------------------------------------------*/
|
|
STDAPI_(ULONG) CTfCandidateUIContextOwner::AddRef( void )
|
|
{
|
|
m_cRef++;
|
|
return m_cRef;
|
|
}
|
|
|
|
|
|
/* R E L E A S E */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Decrement reference count and release object
|
|
(IUnknown method)
|
|
|
|
------------------------------------------------------------------------------*/
|
|
STDAPI_(ULONG) CTfCandidateUIContextOwner::Release( void )
|
|
{
|
|
m_cRef--;
|
|
if (0 < m_cRef) {
|
|
return m_cRef;
|
|
}
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* P R O C E S S C O M M A N D */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
process command
|
|
|
|
------------------------------------------------------------------------------*/
|
|
STDAPI CTfCandidateUIContextOwner::ProcessCommand(CANDUICOMMAND cmd, INT iParam)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (m_pCandUI != NULL) {
|
|
m_pCandUI->PostCommand( cmd, iParam );
|
|
hr = S_OK;
|
|
}
|
|
else {
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* T E S T T E X T */
|
|
/*------------------------------------------------------------------------------
|
|
|
|
test text
|
|
|
|
------------------------------------------------------------------------------*/
|
|
STDAPI CTfCandidateUIContextOwner::TestText(BSTR bstr, BOOL *pfHandles)
|
|
{
|
|
HRESULT hr;
|
|
int i;
|
|
ULONG ich;
|
|
ULONG cch;
|
|
|
|
if (bstr == NULL || pfHandles == NULL) {
|
|
hr = E_INVALIDARG;
|
|
goto Exit;
|
|
}
|
|
|
|
if (m_pCandUI == NULL) {
|
|
hr = E_FAIL;
|
|
goto Exit;
|
|
}
|
|
|
|
*pfHandles = FALSE;
|
|
|
|
i = 0;
|
|
cch = SysStringLen( bstr );
|
|
for (ich = 0; ich < cch; ich++) {
|
|
if ((L'0' <= bstr[ich]) && (bstr[ich] <= L'9')) {
|
|
i = i * 10 + (bstr[ich] - L'0');
|
|
}
|
|
else if (bstr[ich] == L' ') {
|
|
break;
|
|
}
|
|
else {
|
|
i = -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (0 <= i) {
|
|
if (i == 0) {
|
|
if (m_pCandUI->GetCandListMgr()->GetCandList() != NULL) {
|
|
*pfHandles = (m_pCandUI->GetCandListMgr()->GetCandList()->GetExtraCandItem() != NULL);
|
|
}
|
|
}
|
|
else {
|
|
if (m_pCandUI->GetCandWindow() != NULL) {
|
|
m_pCandUI->GetCandWindow()->IsIndexValid( i, pfHandles );
|
|
}
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
|