Leaked source code of windows server 2003
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

//
// 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;
}