1750 lines
52 KiB
C++
1750 lines
52 KiB
C++
/**************************************************************************
|
|
THIS CODE AND INFORMATION IS PROVIDED 'AS IS' WITHOUT WARRANTY OF
|
|
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
PARTICULAR PURPOSE.
|
|
|
|
Copyright 2001 Microsoft Corporation. All Rights Reserved.
|
|
**************************************************************************/
|
|
|
|
/**************************************************************************
|
|
|
|
File: TSFEdit.cpp
|
|
|
|
Description: CTSFEditWnd Class Implementation
|
|
|
|
**************************************************************************/
|
|
|
|
/**************************************************************************
|
|
#include statements
|
|
**************************************************************************/
|
|
|
|
#include "TSFEdit.h"
|
|
#include "Globals.h"
|
|
#include <ctffunc.h>
|
|
|
|
/*
|
|
None of the GUIDs in TSATTRS.H are defined in a LIB, so you have to include
|
|
INITGUID.H just before the first time you include TSATTRS.H
|
|
*/
|
|
#include <initguid.h>
|
|
#include <tsattrs.h>
|
|
#include <tchar.h>
|
|
|
|
/**************************************************************************
|
|
local function prototypes
|
|
**************************************************************************/
|
|
|
|
/**************************************************************************
|
|
global variables and definitions
|
|
**************************************************************************/
|
|
|
|
TCHAR g_szTSFEditClassName[] = TEXT("TSFEditWndClass");
|
|
|
|
#define THIS_POINTER_OFFSET GWLP_USERDATA
|
|
|
|
//#define USE_ASSOC_FOCUS
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::CTSFEditWnd()
|
|
|
|
**************************************************************************/
|
|
|
|
CTSFEditWnd::CTSFEditWnd(HINSTANCE hInstance, HWND hwndParent)
|
|
{
|
|
m_hWnd = NULL;
|
|
m_hwndEdit = NULL;
|
|
m_hwndStatus = NULL;
|
|
m_hInst = hInstance;
|
|
m_ObjRefCount = 1;
|
|
m_hwndParent = hwndParent;
|
|
m_pThreadMgr = NULL;
|
|
m_pDocMgr = NULL;
|
|
m_pPrevDocMgr = NULL;
|
|
m_pContext = NULL;
|
|
m_fLocked = FALSE;
|
|
m_dwLockType = 0;
|
|
m_fPendingLockUpgrade = FALSE;
|
|
m_acpStart = 0;
|
|
m_acpEnd = 0;
|
|
m_fInterimChar = FALSE;
|
|
m_ActiveSelEnd = TS_AE_START;
|
|
m_pServices = NULL;
|
|
m_cCompositions = 0;
|
|
m_pCategoryMgr = NULL;
|
|
m_pDisplayAttrMgr = NULL;
|
|
m_fLayoutChanged = FALSE;
|
|
m_fNotify = TRUE;
|
|
m_cchOldLength = 0;
|
|
|
|
ZeroMemory(&m_AdviseSink, sizeof(m_AdviseSink));
|
|
ZeroMemory(&m_rgCompositions, sizeof(m_rgCompositions));
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::~CTSFEditWnd()
|
|
|
|
**************************************************************************/
|
|
|
|
CTSFEditWnd::~CTSFEditWnd()
|
|
{
|
|
/*
|
|
Make sure the advise sink is cleaned up. This should have been done
|
|
before, but this is just in case.
|
|
*/
|
|
_ClearAdviseSink(&m_AdviseSink);
|
|
|
|
if(m_pServices)
|
|
{
|
|
m_pServices->Release();
|
|
m_pServices = NULL;
|
|
}
|
|
|
|
_Uninitialize();
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_Initialize()
|
|
|
|
**************************************************************************/
|
|
|
|
BOOL CTSFEditWnd::_Initialize(ITfThreadMgr *ptm, TfClientId tfcId)
|
|
{
|
|
HRESULT hr;
|
|
|
|
InitCommonControls();
|
|
|
|
m_tfClientID = tfcId;
|
|
hr = ptm->QueryInterface(IID_ITfThreadMgr, (LPVOID*)&m_pThreadMgr);
|
|
if(FAILED(hr))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
hr = CoCreateInstance( CLSID_TF_CategoryMgr,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_ITfCategoryMgr,
|
|
(LPVOID*)&m_pCategoryMgr);
|
|
if(FAILED(hr))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//create the display attribute manager
|
|
hr = CoCreateInstance( CLSID_TF_DisplayAttributeMgr,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_ITfDisplayAttributeMgr,
|
|
(LPVOID*)&m_pDisplayAttrMgr);
|
|
if(FAILED(hr))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//create the document manager
|
|
hr = m_pThreadMgr->CreateDocumentMgr(&m_pDocMgr);
|
|
if(FAILED(hr))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//create the context
|
|
hr = m_pDocMgr->CreateContext( tfcId,
|
|
0,
|
|
(ITextStoreACP*)this,
|
|
&m_pContext,
|
|
&m_EditCookie);
|
|
if(FAILED(hr))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//push the context onto the document stack
|
|
hr = m_pDocMgr->Push(m_pContext);
|
|
if(FAILED(hr))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
WNDCLASS wc;
|
|
|
|
//If the class is not already registered, register it.
|
|
if(!GetClassInfo(m_hInst, g_szTSFEditClassName, &wc))
|
|
{
|
|
ZeroMemory(&wc, sizeof(wc));
|
|
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
wc.lpfnWndProc = CTSFEditWnd::_WndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = sizeof(CTSFEditWnd*);
|
|
wc.hInstance = m_hInst;
|
|
wc.hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_MAIN_ICON));
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
|
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAIN_MENU);
|
|
wc.lpszClassName = g_szTSFEditClassName;
|
|
|
|
if(0 == RegisterClass(&wc))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
//create the main window
|
|
m_hWnd = CreateWindowEx( 0,
|
|
g_szTSFEditClassName,
|
|
NULL,
|
|
WS_OVERLAPPED |
|
|
WS_CHILD |
|
|
WS_VISIBLE |
|
|
WS_TABSTOP,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
m_hwndParent,
|
|
NULL,
|
|
m_hInst,
|
|
(LPVOID)this);
|
|
|
|
if(NULL != m_hWnd)
|
|
{
|
|
m_hwndEdit = CreateWindowEx( WS_EX_CLIENTEDGE,
|
|
TEXT("edit"),
|
|
NULL,
|
|
WS_CLIPSIBLINGS |
|
|
WS_CHILD |
|
|
WS_VISIBLE |
|
|
WS_BORDER |
|
|
WS_VSCROLL |
|
|
ES_AUTOVSCROLL |
|
|
ES_MULTILINE,
|
|
0, 0, 0, 0,
|
|
m_hWnd,
|
|
(HMENU)IDC_EDIT,
|
|
m_hInst,
|
|
NULL);
|
|
if(NULL == m_hwndEdit)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//create the status bar
|
|
m_hwndStatus = CreateStatusWindow( WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP,
|
|
NULL,
|
|
m_hWnd,
|
|
IDC_STATUSBAR);
|
|
|
|
if(m_hwndStatus)
|
|
{
|
|
_UpdateStatusBar();
|
|
}
|
|
|
|
#ifdef USE_ASSOC_FOCUS
|
|
/*
|
|
Associate the focus with this window. The TSF Manager watches for
|
|
focus changes throughout the system. When a window handle that has
|
|
been associated gets the focus, it then knows the window receiving
|
|
the focus is TSF enabled.
|
|
*/
|
|
hr = m_pThreadMgr->AssociateFocus(m_hwndEdit, m_pDocMgr, &m_pPrevDocMgr);
|
|
#endif
|
|
|
|
//initialize the supported attributes
|
|
TfGuidAtom guidatom;
|
|
|
|
//mode bias
|
|
m_rgAttributes[ATTR_INDEX_MODEBIAS].dwFlags = 0;
|
|
m_rgAttributes[ATTR_INDEX_MODEBIAS].attrid = &GUID_PROP_MODEBIAS;
|
|
VariantInit(&(m_rgAttributes[ATTR_INDEX_MODEBIAS].varValue));
|
|
hr = m_pCategoryMgr->RegisterGUID(GUID_MODEBIAS_NONE, &guidatom);
|
|
if(FAILED(hr))
|
|
{
|
|
guidatom = TF_INVALID_GUIDATOM;
|
|
}
|
|
m_rgAttributes[ATTR_INDEX_MODEBIAS].varDefaultValue.vt = VT_I4;
|
|
m_rgAttributes[ATTR_INDEX_MODEBIAS].varDefaultValue.lVal = guidatom;
|
|
|
|
//text orientation - this is a VT_I4 that is always zero in this app
|
|
m_rgAttributes[ATTR_INDEX_TEXT_ORIENTATION].dwFlags = 0;
|
|
m_rgAttributes[ATTR_INDEX_TEXT_ORIENTATION].attrid = &TSATTRID_Text_Orientation;
|
|
VariantInit(&m_rgAttributes[ATTR_INDEX_TEXT_ORIENTATION].varValue);
|
|
m_rgAttributes[ATTR_INDEX_TEXT_ORIENTATION].varDefaultValue.vt = VT_I4;
|
|
m_rgAttributes[ATTR_INDEX_TEXT_ORIENTATION].varDefaultValue.lVal = 0;
|
|
|
|
//vertical writing - this is a VT_BOOL that is always FALSE in this app
|
|
m_rgAttributes[ATTR_INDEX_TEXT_VERTICALWRITING].dwFlags = 0;
|
|
m_rgAttributes[ATTR_INDEX_TEXT_VERTICALWRITING].attrid = &TSATTRID_Text_VerticalWriting;
|
|
VariantInit(&m_rgAttributes[ATTR_INDEX_TEXT_VERTICALWRITING].varValue);
|
|
m_rgAttributes[ATTR_INDEX_TEXT_VERTICALWRITING].varDefaultValue.vt = VT_BOOL;
|
|
m_rgAttributes[ATTR_INDEX_TEXT_VERTICALWRITING].varDefaultValue.lVal = FALSE;
|
|
|
|
_InitFunctionProvider();
|
|
|
|
UpdateWindow(m_hWnd);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_Uninitialize()
|
|
|
|
**************************************************************************/
|
|
|
|
void CTSFEditWnd::_Uninitialize()
|
|
{
|
|
if(m_pThreadMgr)
|
|
{
|
|
_UninitFunctionProvider();
|
|
|
|
#ifdef USE_ASSOC_FOCUS
|
|
ITfDocumentMgr *pTempDocMgr = NULL;
|
|
|
|
/*
|
|
Its okay if m_pPrevDocMgr is NULL as this will just disassociate the
|
|
focus from the window.
|
|
*/
|
|
m_pThreadMgr->AssociateFocus(m_hwndEdit, m_pPrevDocMgr, &pTempDocMgr);
|
|
|
|
if(pTempDocMgr)
|
|
{
|
|
pTempDocMgr->Release();
|
|
}
|
|
|
|
if(m_pPrevDocMgr)
|
|
{
|
|
m_pPrevDocMgr->Release();
|
|
m_pPrevDocMgr = NULL;
|
|
}
|
|
#endif
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < NUM_SUPPORTED_ATTRS; i++)
|
|
{
|
|
VariantClear(&m_rgAttributes[i].varValue);
|
|
VariantClear(&m_rgAttributes[i].varDefaultValue);
|
|
m_rgAttributes[i].dwFlags = ATTR_FLAG_NONE;
|
|
}
|
|
|
|
if(m_pDocMgr)
|
|
{
|
|
//pop all of the contexts off of the stack
|
|
m_pDocMgr->Pop(TF_POPF_ALL);
|
|
|
|
m_pDocMgr->Release();
|
|
m_pDocMgr = NULL;
|
|
}
|
|
|
|
if(m_pDisplayAttrMgr)
|
|
{
|
|
m_pDisplayAttrMgr->Release();
|
|
m_pDisplayAttrMgr = NULL;
|
|
}
|
|
|
|
if(m_pContext)
|
|
{
|
|
m_pContext->Release();
|
|
m_pContext = NULL;
|
|
}
|
|
|
|
if(m_pCategoryMgr)
|
|
{
|
|
m_pCategoryMgr->Release();
|
|
m_pCategoryMgr = NULL;
|
|
}
|
|
|
|
m_pThreadMgr->Release();
|
|
m_pThreadMgr = NULL;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_GetWindow()
|
|
|
|
**************************************************************************/
|
|
|
|
HWND CTSFEditWnd::_GetWindow()
|
|
{
|
|
return m_hWnd;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_OnGetPreservedKey()
|
|
|
|
**************************************************************************/
|
|
|
|
HRESULT CTSFEditWnd::_OnGetPreservedKey()
|
|
{
|
|
HRESULT hr;
|
|
ITfKeystrokeMgr *pKeyMgr;
|
|
|
|
hr = m_pThreadMgr->QueryInterface(IID_ITfKeystrokeMgr, (LPVOID*)&pKeyMgr);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
GUID guid;
|
|
TF_PRESERVEDKEY tfPreKey;
|
|
|
|
tfPreKey.uVKey = 'F';
|
|
tfPreKey.uModifiers = TF_MOD_CONTROL;
|
|
|
|
hr = pKeyMgr->GetPreservedKey(m_pContext, &tfPreKey, &guid);
|
|
|
|
if(SUCCEEDED(hr) && !IsEqualGUID(guid, GUID_NULL))
|
|
{
|
|
BOOL fPreserved;
|
|
|
|
hr = pKeyMgr->IsPreservedKey(guid, &tfPreKey, &fPreserved);
|
|
|
|
|
|
BOOL fEaten;
|
|
|
|
guid.Data1 = 12;
|
|
hr = pKeyMgr->SimulatePreservedKey(m_pContext, guid, &fEaten);
|
|
}
|
|
|
|
pKeyMgr->Release();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_WndProc()
|
|
|
|
**************************************************************************/
|
|
|
|
LRESULT CALLBACK CTSFEditWnd::_WndProc( HWND hWnd,
|
|
UINT uMessage,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
CTSFEditWnd *pThis = (CTSFEditWnd*)GetWindowLongPtr(hWnd, THIS_POINTER_OFFSET);
|
|
|
|
if((NULL == pThis) && (uMessage != WM_NCCREATE))
|
|
{
|
|
return DefWindowProc(hWnd, uMessage, wParam, lParam);
|
|
}
|
|
|
|
switch (uMessage)
|
|
{
|
|
case WM_NCCREATE:
|
|
{
|
|
LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
|
|
pThis = (CTSFEditWnd*)(lpcs->lpCreateParams);
|
|
SetWindowLongPtr(hWnd, THIS_POINTER_OFFSET, (LONG_PTR)pThis);
|
|
|
|
//set the window handle
|
|
pThis->m_hWnd = hWnd;
|
|
|
|
/*
|
|
AddRef() the object. Release() will be called in WM_NCDESTROY.
|
|
Many owners will call Release during their WM_DESTROY, but the
|
|
child window isn't destroyed until after the parent, so the object
|
|
gets deleted while the window still exists. Calling Release()
|
|
ourselves in WM_NCDESTROY ensures the object exists for the entire
|
|
life of the window.
|
|
*/
|
|
pThis->AddRef();
|
|
}
|
|
break;
|
|
|
|
case WM_CREATE:
|
|
return pThis->_OnCreate();
|
|
|
|
case WM_SIZE:
|
|
return pThis->_OnSize(wParam, lParam);
|
|
|
|
case WM_DESTROY:
|
|
return pThis->_OnDestroy();
|
|
|
|
case WM_SETFOCUS:
|
|
return pThis->_OnSetFocus();
|
|
|
|
case WM_KILLFOCUS:
|
|
return pThis->_OnKillFocus();
|
|
|
|
case WM_COMMAND:
|
|
return pThis->_OnCommand( GET_WM_COMMAND_ID(wParam, lParam),
|
|
GET_WM_COMMAND_CMD(wParam, lParam),
|
|
GET_WM_COMMAND_HWND(wParam, lParam));
|
|
|
|
case WM_NCDESTROY:
|
|
pThis->Release();
|
|
|
|
pThis->m_hWnd = NULL;
|
|
break;
|
|
|
|
}
|
|
|
|
return DefWindowProc(hWnd, uMessage, wParam, lParam);
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_OnCreate()
|
|
|
|
**************************************************************************/
|
|
|
|
LRESULT CTSFEditWnd::_OnCreate(VOID)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_OnDestroy()
|
|
|
|
**************************************************************************/
|
|
|
|
LRESULT CTSFEditWnd::_OnDestroy(VOID)
|
|
{
|
|
_Uninitialize();
|
|
|
|
PostQuitMessage(0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_OnCommand()
|
|
|
|
**************************************************************************/
|
|
|
|
LRESULT CTSFEditWnd::_OnCommand(WORD wID, WORD wCmd, HWND hWnd)
|
|
{
|
|
switch(wID)
|
|
{
|
|
case IDC_EDIT:
|
|
switch(wCmd)
|
|
{
|
|
case EN_SETFOCUS:
|
|
_OnEditSetFocus();
|
|
break;
|
|
|
|
case EN_KILLFOCUS:
|
|
_OnEditKillFocus();
|
|
break;
|
|
|
|
case EN_CHANGE:
|
|
_OnEditChange();
|
|
break;
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_OnSetFocus()
|
|
|
|
**************************************************************************/
|
|
|
|
LRESULT CTSFEditWnd::_OnSetFocus(VOID)
|
|
{
|
|
OutputDebugString(TEXT("CTSFEditWnd::_OnSetFocus\n"));
|
|
|
|
SetFocus(m_hwndEdit);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_OnEditSetFocus()
|
|
|
|
**************************************************************************/
|
|
|
|
LRESULT CTSFEditWnd::_OnEditSetFocus(VOID)
|
|
{
|
|
OutputDebugString(TEXT("CTSFEditWnd::_OnEditSetFocus\n"));
|
|
|
|
#ifndef USE_ASSOC_FOCUS
|
|
m_pThreadMgr->SetFocus(m_pDocMgr);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_OnEditChange()
|
|
|
|
**************************************************************************/
|
|
|
|
LRESULT CTSFEditWnd::_OnEditChange(void)
|
|
{
|
|
if(m_fNotify && m_AdviseSink.pTextStoreACPSink && (m_AdviseSink.dwMask & TS_AS_TEXT_CHANGE))
|
|
{
|
|
DWORD dwFlags;
|
|
TS_TEXTCHANGE tc;
|
|
ULONG cch;
|
|
|
|
cch = GetWindowTextLength(m_hwndEdit);
|
|
|
|
/*
|
|
dwFlags can be 0 or TS_TC_CORRECTION
|
|
*/
|
|
dwFlags = 0;
|
|
|
|
tc.acpStart = 0;
|
|
tc.acpOldEnd = m_cchOldLength;
|
|
tc.acpNewEnd = cch;
|
|
|
|
m_AdviseSink.pTextStoreACPSink->OnTextChange(dwFlags, &tc);
|
|
|
|
m_cchOldLength = cch;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_OnKillFocus()
|
|
|
|
**************************************************************************/
|
|
|
|
LRESULT CTSFEditWnd::_OnKillFocus(VOID)
|
|
{
|
|
OutputDebugString(TEXT("CTSFEditWnd::_OnKillFocus\n"));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_OnEditKillFocus()
|
|
|
|
**************************************************************************/
|
|
|
|
LRESULT CTSFEditWnd::_OnEditKillFocus(VOID)
|
|
{
|
|
OutputDebugString(TEXT("CTSFEditWnd::_OnEditKillFocus\n"));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_OnNotify()
|
|
|
|
**************************************************************************/
|
|
|
|
LRESULT CTSFEditWnd::_OnNotify(UINT, LPNMHDR)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_OnSize()
|
|
|
|
**************************************************************************/
|
|
|
|
LRESULT CTSFEditWnd::_OnSize(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
//adjust the size and location of the status bar
|
|
SendMessage(m_hwndStatus, WM_SIZE, wParam, lParam);
|
|
|
|
RECT rc;
|
|
|
|
GetWindowRect(m_hwndStatus, &rc);
|
|
|
|
MoveWindow( m_hwndEdit,
|
|
0,
|
|
0,
|
|
LOWORD(lParam),
|
|
HIWORD(lParam) - (rc.bottom - rc.top),
|
|
TRUE);
|
|
|
|
m_AdviseSink.pTextStoreACPSink->OnLayoutChange(TS_LC_CHANGE, EDIT_VIEW_COOKIE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_IsLocked()
|
|
|
|
**************************************************************************/
|
|
|
|
BOOL CTSFEditWnd::_IsLocked(DWORD dwLockType)
|
|
{
|
|
if(m_dwInternalLockType)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return m_fLocked && (m_dwLockType & dwLockType);
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_ClearAdviseSink()
|
|
|
|
**************************************************************************/
|
|
|
|
HRESULT CTSFEditWnd::_ClearAdviseSink(PADVISE_SINK pAdviseSink)
|
|
{
|
|
if(pAdviseSink->punkID)
|
|
{
|
|
pAdviseSink->punkID->Release();
|
|
pAdviseSink->punkID = NULL;
|
|
}
|
|
|
|
if(pAdviseSink->pTextStoreACPSink)
|
|
{
|
|
pAdviseSink->pTextStoreACPSink->Release();
|
|
pAdviseSink->pTextStoreACPSink = NULL;
|
|
}
|
|
|
|
pAdviseSink->dwMask = 0;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_LockDocument()
|
|
|
|
**************************************************************************/
|
|
|
|
BOOL CTSFEditWnd::_LockDocument(DWORD dwLockFlags)
|
|
{
|
|
if(m_fLocked)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
m_fLocked = TRUE;
|
|
m_dwLockType = dwLockFlags;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_InternalLockDocument()
|
|
|
|
**************************************************************************/
|
|
|
|
BOOL CTSFEditWnd::_InternalLockDocument(DWORD dwLockFlags)
|
|
{
|
|
m_dwInternalLockType = dwLockFlags;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_UnlockDocument
|
|
|
|
**************************************************************************/
|
|
|
|
void CTSFEditWnd::_UnlockDocument()
|
|
{
|
|
HRESULT hr;
|
|
|
|
m_fLocked = FALSE;
|
|
m_dwLockType = 0;
|
|
|
|
//if there is a pending lock upgrade, grant it
|
|
if(m_fPendingLockUpgrade)
|
|
{
|
|
m_fPendingLockUpgrade = FALSE;
|
|
|
|
RequestLock(TS_LF_READWRITE, &hr);
|
|
}
|
|
|
|
//if any layout changes occurred during the lock, notify the manager
|
|
if(m_fLayoutChanged)
|
|
{
|
|
m_fLayoutChanged = FALSE;
|
|
m_AdviseSink.pTextStoreACPSink->OnLayoutChange(TS_LC_CHANGE, EDIT_VIEW_COOKIE);
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_InternalUnlockDocument()
|
|
|
|
**************************************************************************/
|
|
|
|
void CTSFEditWnd::_InternalUnlockDocument()
|
|
{
|
|
m_dwInternalLockType = 0;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_GetCurrentSelection()
|
|
|
|
**************************************************************************/
|
|
|
|
BOOL CTSFEditWnd::_GetCurrentSelection(void)
|
|
{
|
|
//get the selection from the edit control
|
|
::SendMessage(m_hwndEdit, EM_GETSEL, (WPARAM)&m_acpStart, (LPARAM)&m_acpEnd);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_OnUpdate()
|
|
|
|
**************************************************************************/
|
|
|
|
void CTSFEditWnd::_OnUpdate(void)
|
|
{
|
|
//something changed, but it is not known what specifically changed
|
|
//just update the status bar
|
|
_UpdateStatusBar();
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_UpdateStatusBar()
|
|
|
|
**************************************************************************/
|
|
|
|
void CTSFEditWnd::_UpdateStatusBar(void)
|
|
{
|
|
int nParts[2];
|
|
HDC hdc;
|
|
HFONT hFont;
|
|
SIZE size;
|
|
TCHAR szComposition[MAX_PATH];
|
|
|
|
hdc = GetDC(m_hwndStatus);
|
|
hFont = (HFONT)SendMessage(m_hwndStatus, WM_GETFONT, 0, 0);
|
|
hFont = (HFONT)SelectObject(hdc, hFont);
|
|
|
|
if(m_cCompositions)
|
|
{
|
|
_tcscpy_s(szComposition, ARRAYSIZE(szComposition), TEXT("In Composition"));
|
|
}
|
|
else
|
|
{
|
|
_tcscpy_s(szComposition, ARRAYSIZE(szComposition), TEXT("No Composition"));
|
|
}
|
|
|
|
GetTextExtentPoint32(hdc, szComposition, lstrlen(szComposition), &size);
|
|
nParts[0] = size.cx + (GetSystemMetrics(SM_CXEDGE) * 4);
|
|
|
|
nParts[1] = -1;
|
|
|
|
SendMessage(m_hwndStatus, SB_SIMPLE, FALSE, 0);
|
|
SendMessage(m_hwndStatus, SB_SETPARTS, ARRAYSIZE(nParts), (LPARAM)nParts);
|
|
|
|
SendMessage(m_hwndStatus, SB_SETTEXT, 0, (LPARAM)szComposition);
|
|
SendMessage(m_hwndStatus, SB_SETTEXT, 1, (LPARAM)TEXT(""));
|
|
|
|
//reset the DC
|
|
SelectObject(hdc, hFont);
|
|
ReleaseDC(m_hwndStatus, hdc);
|
|
|
|
//enable/disable the menu items as necessary
|
|
HMENU hMenu = GetMenu(m_hwndParent);
|
|
if(NULL != hMenu)
|
|
{
|
|
}
|
|
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_OnInitMenuPopup()
|
|
|
|
**************************************************************************/
|
|
|
|
LRESULT CTSFEditWnd::_OnInitMenuPopup(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HMENU hMenu = (HMENU)wParam;
|
|
|
|
if(NULL != hMenu)
|
|
{
|
|
EnableMenuItem(hMenu, IDM_TERMINATE_COMPOSITION, m_cCompositions ? MF_ENABLED : MF_DISABLED | MF_GRAYED);
|
|
EnableMenuItem(hMenu, IDM_RECONVERT, _CanReconvertSelection() ? MF_ENABLED : MF_DISABLED | MF_GRAYED);
|
|
EnableMenuItem(hMenu, IDM_PLAYBACK, _CanPlaybackSelection() ? MF_ENABLED : MF_DISABLED | MF_GRAYED);
|
|
EnableMenuItem(hMenu, IDM_LOAD, !_IsLocked(TS_LF_READ) ? MF_ENABLED : MF_DISABLED | MF_GRAYED);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_ClearRequestedAttributes()
|
|
|
|
**************************************************************************/
|
|
|
|
void CTSFEditWnd::_ClearRequestedAttributes(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < NUM_SUPPORTED_ATTRS; i++)
|
|
{
|
|
VariantClear(&m_rgAttributes[i].varValue);
|
|
m_rgAttributes[i].dwFlags = ATTR_FLAG_NONE;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_ClearText()
|
|
|
|
**************************************************************************/
|
|
|
|
void CTSFEditWnd::_ClearText(void)
|
|
{
|
|
//can't do this if someone has a lock
|
|
if(_IsLocked(TS_LF_READ))
|
|
{
|
|
return;
|
|
}
|
|
|
|
_LockDocument(TS_LF_READWRITE);
|
|
|
|
//empty the text in the edit control, but don't send a change notification
|
|
BOOL fOldNotify = m_fNotify;
|
|
m_fNotify = FALSE;
|
|
SetWindowTextW(m_hwndEdit, NULL);
|
|
m_fNotify = fOldNotify;
|
|
|
|
//update current selection
|
|
m_acpStart = m_acpEnd = 0;
|
|
|
|
//notify TSF about the changes
|
|
m_AdviseSink.pTextStoreACPSink->OnSelectionChange();
|
|
|
|
_OnEditChange();
|
|
|
|
_UnlockDocument();
|
|
|
|
// make sure to send the OnLayoutChange notification AFTER releasing the lock
|
|
// so clients can do something useful during the notification
|
|
m_AdviseSink.pTextStoreACPSink->OnLayoutChange(TS_LC_CHANGE, EDIT_VIEW_COOKIE);
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_GetText()
|
|
|
|
**************************************************************************/
|
|
|
|
HRESULT CTSFEditWnd::_GetText(LPWSTR *ppwsz, LPLONG pcch)
|
|
{
|
|
DWORD cch;
|
|
LPWSTR pwszText;
|
|
|
|
*ppwsz = NULL;
|
|
|
|
cch = GetWindowTextLength(m_hwndEdit);
|
|
pwszText = (LPWSTR)GlobalAlloc(GMEM_FIXED, (cch + 1) * sizeof(WCHAR));
|
|
if(NULL == pwszText)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
GetWindowTextW(m_hwndEdit, pwszText, cch + 1);
|
|
|
|
*ppwsz = pwszText;
|
|
|
|
if(pcch)
|
|
{
|
|
*pcch = cch;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_GetDisplayAttributes()
|
|
|
|
**************************************************************************/
|
|
|
|
void CTSFEditWnd::_GetDisplayAttributes(void)
|
|
{
|
|
HRESULT hr;
|
|
const GUID *rGuidProperties[1];
|
|
ITfReadOnlyProperty *pTrackProperty;
|
|
|
|
//get the tracking property for the attributes
|
|
rGuidProperties[0] = &GUID_PROP_ATTRIBUTE;
|
|
hr = m_pContext->TrackProperties( rGuidProperties,
|
|
1,
|
|
NULL,
|
|
0,
|
|
&pTrackProperty);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ITfRangeACP *pRangeAllText;
|
|
LONG acpEnd;
|
|
|
|
//get the range of the entire text
|
|
acpEnd = GetWindowTextLength(m_hwndEdit);
|
|
hr = m_pServices->CreateRange(0, acpEnd, &pRangeAllText);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
IEnumTfRanges *pEnumRanges;
|
|
|
|
hr = pTrackProperty->EnumRanges(m_EditCookie, &pEnumRanges, pRangeAllText);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ITfRange *pPropRange;
|
|
ULONG uFetched;
|
|
|
|
/*
|
|
Each range in pEnumRanges represents a span of text that has
|
|
the same properties specified in TrackProperties.
|
|
*/
|
|
while((hr = pEnumRanges->Next(1, &pPropRange, &uFetched)) == S_OK && uFetched)
|
|
{
|
|
//get the attribute property for the property range
|
|
VARIANT var;
|
|
|
|
VariantInit(&var);
|
|
|
|
hr = pTrackProperty->GetValue(m_EditCookie, pPropRange, &var);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
/*
|
|
The property is actually a VT_UNKNOWN that contains an
|
|
IEnumTfPropertyValue object.
|
|
*/
|
|
IEnumTfPropertyValue *pEnumPropertyVal;
|
|
|
|
hr = var.punkVal->QueryInterface(IID_IEnumTfPropertyValue, (LPVOID*)&pEnumPropertyVal);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
TF_PROPERTYVAL tfPropVal;
|
|
|
|
while((hr = pEnumPropertyVal->Next(1, &tfPropVal, &uFetched)) == S_OK && uFetched)
|
|
{
|
|
if(VT_EMPTY == tfPropVal.varValue.vt)
|
|
{
|
|
//the property for this range has no value
|
|
continue;
|
|
}
|
|
else if(VT_I4 == tfPropVal.varValue.vt)
|
|
{
|
|
//the property is a guidatom
|
|
TfGuidAtom gaVal;
|
|
GUID guid;
|
|
|
|
gaVal = (TfGuidAtom)tfPropVal.varValue.lVal;
|
|
|
|
hr = m_pCategoryMgr->GetGUID(gaVal, &guid);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ITfDisplayAttributeInfo *pDispInfo;
|
|
|
|
hr = m_pDisplayAttrMgr->GetDisplayAttributeInfo(guid, &pDispInfo, NULL);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
TF_DISPLAYATTRIBUTE da;
|
|
|
|
hr = pDispInfo->GetAttributeInfo(&da);
|
|
|
|
{
|
|
GUID guidDispInfo;
|
|
hr = pDispInfo->GetGUID(&guidDispInfo);
|
|
guidDispInfo.Data1 = 0;
|
|
}
|
|
|
|
{
|
|
BSTR bstr;
|
|
|
|
hr = pDispInfo->GetDescription(&bstr);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
SysFreeString(bstr);
|
|
}
|
|
}
|
|
|
|
pDispInfo->Release();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//the property is not recognized
|
|
}
|
|
}
|
|
|
|
pEnumPropertyVal->Release();
|
|
}
|
|
|
|
VariantClear(&var);
|
|
}
|
|
|
|
pPropRange->Release();
|
|
}
|
|
|
|
pEnumRanges->Release();
|
|
}
|
|
|
|
pRangeAllText->Release();
|
|
}
|
|
|
|
pTrackProperty->Release();
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_GetTextOwner()
|
|
|
|
**************************************************************************/
|
|
|
|
void CTSFEditWnd::_GetTextOwner(void)
|
|
{
|
|
HRESULT hr;
|
|
const GUID *rGuidProperties[1];
|
|
ITfReadOnlyProperty *pTrackProperty;
|
|
|
|
//get the tracking property for the attributes
|
|
rGuidProperties[0] = &GUID_PROP_TEXTOWNER;
|
|
hr = m_pContext->TrackProperties( rGuidProperties,
|
|
1,
|
|
NULL,
|
|
0,
|
|
&pTrackProperty);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ITfRangeACP *pRangeAllText;
|
|
LONG acpEnd;
|
|
|
|
//get the range of the entire text
|
|
acpEnd = GetWindowTextLength(m_hwndEdit);
|
|
hr = m_pServices->CreateRange(0, acpEnd, &pRangeAllText);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
IEnumTfRanges *pEnumRanges;
|
|
|
|
hr = pTrackProperty->EnumRanges(m_EditCookie, &pEnumRanges, pRangeAllText);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ITfRange *pPropRange;
|
|
ULONG uFetched;
|
|
|
|
/*
|
|
Each range in pEnumRanges represents a span of text that has
|
|
the same properties specified in TrackProperties.
|
|
*/
|
|
while((hr = pEnumRanges->Next(1, &pPropRange, &uFetched)) == S_OK && uFetched)
|
|
{
|
|
//get the attribute property for the property range
|
|
VARIANT var;
|
|
|
|
VariantInit(&var);
|
|
|
|
hr = pTrackProperty->GetValue(m_EditCookie, pPropRange, &var);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
/*
|
|
The property is actually a VT_UNKNOWN that contains an
|
|
IEnumTfPropertyValue object.
|
|
*/
|
|
IEnumTfPropertyValue *pEnumPropertyVal;
|
|
|
|
hr = var.punkVal->QueryInterface(IID_IEnumTfPropertyValue, (LPVOID*)&pEnumPropertyVal);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
TF_PROPERTYVAL tfPropVal;
|
|
|
|
while((hr = pEnumPropertyVal->Next(1, &tfPropVal, &uFetched)) == S_OK && uFetched)
|
|
{
|
|
/*
|
|
The GUID_PROP_TEXTOWNER attribute value is the CLSID of the text service that owns the text. If the text is not owned, the value is VT_EMPTY.
|
|
*/
|
|
if(VT_EMPTY == tfPropVal.varValue.vt)
|
|
{
|
|
//the text is not owned
|
|
continue;
|
|
}
|
|
else if(VT_I4 == tfPropVal.varValue.vt)
|
|
{
|
|
//the property is a guidatom that represents the CLSID of the text service that owns the text.
|
|
TfGuidAtom gaVal;
|
|
CLSID clsidOwner;
|
|
|
|
gaVal = (TfGuidAtom)tfPropVal.varValue.lVal;
|
|
|
|
hr = m_pCategoryMgr->GetGUID(gaVal, &clsidOwner);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//the property is not recognized
|
|
}
|
|
}
|
|
|
|
pEnumPropertyVal->Release();
|
|
}
|
|
|
|
VariantClear(&var);
|
|
}
|
|
|
|
pPropRange->Release();
|
|
}
|
|
|
|
pEnumRanges->Release();
|
|
}
|
|
|
|
pRangeAllText->Release();
|
|
}
|
|
|
|
pTrackProperty->Release();
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_GetReadingText()
|
|
|
|
**************************************************************************/
|
|
|
|
void CTSFEditWnd::_GetReadingText(void)
|
|
{
|
|
HRESULT hr;
|
|
const GUID *rGuidProperties[1];
|
|
ITfReadOnlyProperty *pTrackProperty;
|
|
|
|
//get the tracking property for the attributes
|
|
rGuidProperties[0] = &GUID_PROP_READING;
|
|
hr = m_pContext->TrackProperties( rGuidProperties,
|
|
1,
|
|
NULL,
|
|
0,
|
|
&pTrackProperty);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ITfRangeACP *pRangeAllText;
|
|
LONG acpEnd;
|
|
|
|
//get the range of the entire text
|
|
acpEnd = GetWindowTextLength(m_hwndEdit);
|
|
hr = m_pServices->CreateRange(0, acpEnd, &pRangeAllText);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
IEnumTfRanges *pEnumRanges;
|
|
|
|
hr = pTrackProperty->EnumRanges(m_EditCookie, &pEnumRanges, pRangeAllText);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ITfRange *pPropRange;
|
|
ULONG uFetched;
|
|
|
|
/*
|
|
Each range in pEnumRanges represents a span of text that has
|
|
the same properties specified in TrackProperties.
|
|
*/
|
|
while((hr = pEnumRanges->Next(1, &pPropRange, &uFetched)) == S_OK && uFetched)
|
|
{
|
|
//get the attribute property for the property range
|
|
VARIANT var;
|
|
|
|
VariantInit(&var);
|
|
|
|
hr = pTrackProperty->GetValue(m_EditCookie, pPropRange, &var);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
/*
|
|
The property is actually a VT_UNKNOWN that contains an
|
|
IEnumTfPropertyValue object.
|
|
*/
|
|
IEnumTfPropertyValue *pEnumPropertyVal;
|
|
|
|
hr = var.punkVal->QueryInterface(IID_IEnumTfPropertyValue, (LPVOID*)&pEnumPropertyVal);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
TF_PROPERTYVAL tfPropVal;
|
|
|
|
while((hr = pEnumPropertyVal->Next(1, &tfPropVal, &uFetched)) == S_OK && uFetched)
|
|
{
|
|
/*
|
|
The GUID_PROP_TEXTOWNER attribute value is the CLSID of the text service that owns the text. If the text is not owned, the value is VT_EMPTY.
|
|
*/
|
|
if(VT_EMPTY == tfPropVal.varValue.vt)
|
|
{
|
|
//the text is not owned
|
|
continue;
|
|
}
|
|
else if(VT_BSTR == tfPropVal.varValue.vt)
|
|
{
|
|
//the property is a BSTR.
|
|
tfPropVal.varValue.bstrVal;
|
|
|
|
HRESULT hr;
|
|
WCHAR wsz[MAX_PATH];
|
|
ULONG cch;
|
|
hr = pPropRange->GetText(m_EditCookie, 0, wsz, MAX_PATH-1, &cch);
|
|
wsz[cch] = 0;
|
|
}
|
|
else
|
|
{
|
|
//the property is not recognized
|
|
}
|
|
}
|
|
|
|
pEnumPropertyVal->Release();
|
|
}
|
|
|
|
VariantClear(&var);
|
|
}
|
|
|
|
pPropRange->Release();
|
|
}
|
|
|
|
pEnumRanges->Release();
|
|
}
|
|
|
|
pRangeAllText->Release();
|
|
}
|
|
|
|
pTrackProperty->Release();
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_GetComposing()
|
|
|
|
**************************************************************************/
|
|
|
|
void CTSFEditWnd::_GetComposing(void)
|
|
{
|
|
HRESULT hr;
|
|
const GUID *rGuidProperties[1];
|
|
ITfReadOnlyProperty *pTrackProperty;
|
|
|
|
//get the tracking property for the attributes
|
|
rGuidProperties[0] = &GUID_PROP_COMPOSING;
|
|
hr = m_pContext->TrackProperties( rGuidProperties,
|
|
1,
|
|
NULL,
|
|
0,
|
|
&pTrackProperty);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ITfRangeACP *pRangeAllText;
|
|
LONG acpEnd;
|
|
|
|
//get the range of the entire text
|
|
acpEnd = GetWindowTextLength(m_hwndEdit);
|
|
hr = m_pServices->CreateRange(0, acpEnd, &pRangeAllText);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
IEnumTfRanges *pEnumRanges;
|
|
|
|
hr = pTrackProperty->EnumRanges(m_EditCookie, &pEnumRanges, pRangeAllText);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ITfRange *pPropRange;
|
|
ULONG uFetched;
|
|
|
|
/*
|
|
Each range in pEnumRanges represents a span of text that has
|
|
the same properties specified in TrackProperties.
|
|
*/
|
|
while((hr = pEnumRanges->Next(1, &pPropRange, &uFetched)) == S_OK && uFetched)
|
|
{
|
|
//get the attribute property for the property range
|
|
VARIANT var;
|
|
|
|
VariantInit(&var);
|
|
|
|
hr = pTrackProperty->GetValue(m_EditCookie, pPropRange, &var);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
/*
|
|
The property is actually a VT_UNKNOWN that contains an
|
|
IEnumTfPropertyValue object.
|
|
*/
|
|
IEnumTfPropertyValue *pEnumPropertyVal;
|
|
|
|
hr = var.punkVal->QueryInterface(IID_IEnumTfPropertyValue, (LPVOID*)&pEnumPropertyVal);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
TF_PROPERTYVAL tfPropVal;
|
|
|
|
while((hr = pEnumPropertyVal->Next(1, &tfPropVal, &uFetched)) == S_OK && uFetched)
|
|
{
|
|
/*
|
|
The GUID_PROP_COMPOSING attribute value is a VT_I4 that contains a boolean indicating if the text is part of a composition.
|
|
*/
|
|
BOOL fComposing = FALSE;
|
|
|
|
if(VT_EMPTY == tfPropVal.varValue.vt)
|
|
{
|
|
//the text is not part of a composition
|
|
}
|
|
else if(VT_I4 == tfPropVal.varValue.vt)
|
|
{
|
|
//the property is a VT_I4.
|
|
if(tfPropVal.varValue.lVal)
|
|
{
|
|
//The text is part of a composition
|
|
fComposing = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//the property is not recognized
|
|
}
|
|
}
|
|
|
|
pEnumPropertyVal->Release();
|
|
}
|
|
|
|
VariantClear(&var);
|
|
}
|
|
|
|
pPropRange->Release();
|
|
}
|
|
|
|
pEnumRanges->Release();
|
|
}
|
|
|
|
pRangeAllText->Release();
|
|
}
|
|
|
|
pTrackProperty->Release();
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_CanReconvertSelection()
|
|
|
|
**************************************************************************/
|
|
|
|
BOOL CTSFEditWnd::_CanReconvertSelection(void)
|
|
{
|
|
BOOL fConv = FALSE;
|
|
HRESULT hr;
|
|
ITfFunctionProvider *pFuncProv;
|
|
|
|
_InternalLockDocument(TS_LF_READ);
|
|
|
|
hr = m_pThreadMgr->GetFunctionProvider(GUID_SYSTEM_FUNCTIONPROVIDER, &pFuncProv);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ITfFnReconversion *pRecon;
|
|
|
|
hr = pFuncProv->GetFunction(GUID_NULL, IID_ITfFnReconversion, (IUnknown**)&pRecon);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
TF_SELECTION ts;
|
|
ULONG uFetched;
|
|
|
|
hr = m_pContext->GetSelection(m_EditCookie, TF_DEFAULT_SELECTION, 1, &ts, &uFetched);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ITfRange *pRange = NULL;
|
|
|
|
hr = pRecon->QueryRange(ts.range, &pRange, &fConv);
|
|
if(SUCCEEDED(hr) && pRange)
|
|
{
|
|
pRange->Release();
|
|
}
|
|
|
|
ts.range->Release();
|
|
}
|
|
|
|
pRecon->Release();
|
|
}
|
|
|
|
pFuncProv->Release();
|
|
}
|
|
|
|
_InternalUnlockDocument();
|
|
|
|
return fConv;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_Reconvert()
|
|
|
|
**************************************************************************/
|
|
|
|
void CTSFEditWnd::_Reconvert(void)
|
|
{
|
|
HRESULT hr;
|
|
ITfFunctionProvider *pFuncProv;
|
|
|
|
_InternalLockDocument(TS_LF_READ);
|
|
|
|
hr = m_pThreadMgr->GetFunctionProvider(GUID_SYSTEM_FUNCTIONPROVIDER, &pFuncProv);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ITfFnReconversion *pRecon;
|
|
|
|
hr = pFuncProv->GetFunction(GUID_NULL, IID_ITfFnReconversion, (IUnknown**)&pRecon);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
TF_SELECTION ts;
|
|
ULONG uFetched;
|
|
|
|
hr = m_pContext->GetSelection(m_EditCookie, TF_DEFAULT_SELECTION, 1, &ts, &uFetched);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ITfRange *pRange;
|
|
BOOL fConv;
|
|
|
|
//get the range that covers the text to be reconverted
|
|
hr = pRecon->QueryRange(ts.range, &pRange, &fConv);
|
|
if(SUCCEEDED(hr) && pRange)
|
|
{
|
|
{
|
|
WCHAR wsz[MAX_PATH];
|
|
ULONG cch = 0;
|
|
pRange->GetText(m_EditCookie, 0, wsz, MAX_PATH-1, &cch);
|
|
wsz[cch] = 0;
|
|
}
|
|
|
|
//get the list of reconversion candidates
|
|
ITfCandidateList *pCandList;
|
|
hr = pRecon->GetReconversion(pRange, &pCandList);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ULONG i;
|
|
ULONG uCandidateCount = 0;
|
|
|
|
hr = pCandList->GetCandidateNum(&uCandidateCount);
|
|
|
|
for(i = 0; i < uCandidateCount; i++)
|
|
{
|
|
ITfCandidateString *pCandString;
|
|
|
|
hr = pCandList->GetCandidate(i, &pCandString);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
BSTR bstr;
|
|
|
|
hr = pCandString->GetString(&bstr);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
OutputDebugString(TEXT("\tCandidate - \""));
|
|
OutputDebugStringW(bstr);
|
|
OutputDebugString(TEXT("\"\n"));
|
|
SysFreeString(bstr);
|
|
}
|
|
|
|
pCandString->Release();
|
|
}
|
|
}
|
|
|
|
pCandList->Release();
|
|
}
|
|
//cause the reconversion to happen
|
|
hr = pRecon->Reconvert(pRange);
|
|
|
|
}
|
|
}
|
|
|
|
pRecon->Release();
|
|
}
|
|
|
|
pFuncProv->Release();
|
|
}
|
|
|
|
_InternalUnlockDocument();
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_CanPlaybackSelection()
|
|
|
|
**************************************************************************/
|
|
|
|
BOOL CTSFEditWnd::_CanPlaybackSelection(void)
|
|
{
|
|
BOOL fCanPlayback = FALSE;
|
|
HRESULT hr;
|
|
ITfFunctionProvider *pFuncProv;
|
|
|
|
_InternalLockDocument(TS_LF_READ);
|
|
|
|
hr = m_pThreadMgr->GetFunctionProvider(CLSID_SapiLayr, &pFuncProv);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ITfFnPlayBack *pPlayback;
|
|
|
|
hr = pFuncProv->GetFunction(GUID_NULL, IID_ITfFnPlayBack, (IUnknown**)&pPlayback);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
TF_SELECTION ts;
|
|
ULONG uFetched;
|
|
|
|
hr = m_pContext->GetSelection(m_EditCookie, TF_DEFAULT_SELECTION, 1, &ts, &uFetched);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ITfRange *pRange = NULL;
|
|
|
|
hr = pPlayback->QueryRange(ts.range, &pRange, &fCanPlayback);
|
|
if(SUCCEEDED(hr) && pRange)
|
|
{
|
|
pRange->Release();
|
|
}
|
|
|
|
ts.range->Release();
|
|
}
|
|
|
|
pPlayback->Release();
|
|
}
|
|
|
|
pFuncProv->Release();
|
|
}
|
|
|
|
_InternalUnlockDocument();
|
|
|
|
return fCanPlayback;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::_Playback()
|
|
|
|
**************************************************************************/
|
|
|
|
void CTSFEditWnd::_Playback(void)
|
|
{
|
|
HRESULT hr;
|
|
ITfFunctionProvider *pFuncProv;
|
|
|
|
_InternalLockDocument(TS_LF_READ);
|
|
|
|
hr = m_pThreadMgr->GetFunctionProvider(CLSID_SapiLayr, &pFuncProv);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ITfFnPlayBack *pPlayback;
|
|
|
|
hr = pFuncProv->GetFunction(GUID_NULL, IID_ITfFnPlayBack, (IUnknown**)&pPlayback);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
TF_SELECTION ts;
|
|
ULONG uFetched;
|
|
|
|
hr = m_pContext->GetSelection(m_EditCookie, TF_DEFAULT_SELECTION, 1, &ts, &uFetched);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
BOOL fCanPlayback;
|
|
ITfRange *pRange = NULL;
|
|
|
|
hr = pPlayback->QueryRange(ts.range, &pRange, &fCanPlayback);
|
|
if(SUCCEEDED(hr) && pRange)
|
|
{
|
|
hr = pPlayback->Play(pRange);
|
|
|
|
pRange->Release();
|
|
}
|
|
|
|
ts.range->Release();
|
|
}
|
|
|
|
pPlayback->Release();
|
|
}
|
|
|
|
pFuncProv->Release();
|
|
}
|
|
|
|
_InternalUnlockDocument();
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// IUnknown Implementation
|
|
//
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::QueryInterface
|
|
|
|
**************************************************************************/
|
|
|
|
STDMETHODIMP CTSFEditWnd::QueryInterface(REFIID riid, LPVOID *ppReturn)
|
|
{
|
|
*ppReturn = NULL;
|
|
|
|
//IUnknown
|
|
if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITextStoreACP))
|
|
{
|
|
*ppReturn = (ITextStoreACP*)this;
|
|
}
|
|
|
|
//ITfContextOwnerCompositionSink
|
|
else if(IsEqualIID(riid, IID_ITfContextOwnerCompositionSink))
|
|
{
|
|
*ppReturn = (ITfContextOwnerCompositionSink*)this;
|
|
}
|
|
|
|
//ITfFunctionProvider
|
|
else if(IsEqualIID(riid, IID_ITfFunctionProvider))
|
|
{
|
|
*ppReturn = (ITfFunctionProvider*)this;
|
|
}
|
|
|
|
if(*ppReturn)
|
|
{
|
|
(*(LPUNKNOWN*)ppReturn)->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::AddRef
|
|
|
|
**************************************************************************/
|
|
|
|
STDMETHODIMP_(DWORD) CTSFEditWnd::AddRef()
|
|
{
|
|
return ++m_ObjRefCount;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
CTSFEditWnd::Release
|
|
|
|
**************************************************************************/
|
|
|
|
STDMETHODIMP_(DWORD) CTSFEditWnd::Release()
|
|
{
|
|
if(--m_ObjRefCount == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
return m_ObjRefCount;
|
|
}
|
|
|