# HG changeset patch # User dewyatt # Date 1277154997 14400 # Node ID f51a9f01b50811f1a6a143f6815c8ba06b1632dd # Parent 381d402a5e9082b8197325eb9375e96e0f06dff3 Starting to implement ITextStoreACP. It's very incomplete and will probably change quite a bit but it's a start. ITextStoreACP is the minimum interface to be considered TSF-aware. diff -r 381d402a5e90 -r f51a9f01b508 EXCLUDE/GLTSF/include/TSF.hpp --- a/EXCLUDE/GLTSF/include/TSF.hpp Sat Jun 12 03:21:54 2010 -0400 +++ b/EXCLUDE/GLTSF/include/TSF.hpp Mon Jun 21 17:16:37 2010 -0400 @@ -11,11 +11,73 @@ static void Finalize(); private: + class TSF_Text_Store : public ITextStoreACP, public ITfContextOwnerCompositionSink + { + public: + //IUnknown + STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + //ITextStoreACP + STDMETHODIMP AdviseSink(REFIID riid, IUnknown *punk, DWORD dwMask); + STDMETHODIMP UnadviseSink(IUnknown *punk); + STDMETHODIMP RequestLock(DWORD dwLockFlags, HRESULT *phrSession); + STDMETHODIMP GetStatus(TS_STATUS *pdcs); + STDMETHODIMP QueryInsert(LONG acpTestStart, LONG acpTestEnd, ULONG cch, LONG *pacpResultStart, LONG *pacpResultEnd); + STDMETHODIMP GetSelection(ULONG ulIndex, ULONG ulCount, TS_SELECTION_ACP *pSelection, ULONG *pcFetched); + STDMETHODIMP SetSelection(ULONG ulCount, const TS_SELECTION_ACP *pSelection); + STDMETHODIMP GetText(LONG acpStart, LONG acpEnd, WCHAR *pchPlain, ULONG cchPlainReq, ULONG *pcchPlainRet, TS_RUNINFO *prgRunInfo, ULONG cRunInfoReq, ULONG *pcRunInfoRet, LONG *pacpNext); + STDMETHODIMP SetText(DWORD dwFlags, LONG acpStart, LONG acpEnd, const WCHAR *pchText, ULONG cch, TS_TEXTCHANGE *pChange); + STDMETHODIMP GetFormattedText(LONG acpStart, LONG acpEnd, IDataObject **ppDataObject); + STDMETHODIMP GetEmbedded(LONG acpPos, REFGUID rguidService, REFIID riid, IUnknown **ppunk); + STDMETHODIMP QueryInsertEmbedded(const GUID *pguidService, const FORMATETC *pFormatEtc, BOOL *pfInsertable); + STDMETHODIMP InsertEmbedded(DWORD dwFlags, LONG acpStart, LONG acpEnd, IDataObject *pDataObject, TS_TEXTCHANGE *pChange); + STDMETHODIMP InsertTextAtSelection(DWORD dwFlags, const WCHAR *pchText, ULONG cch, LONG *pacpStart, LONG *pacpEnd, TS_TEXTCHANGE *pChange); + STDMETHODIMP InsertEmbeddedAtSelection(DWORD dwFlags, IDataObject *pDataObject, LONG *pacpStart, LONG *pacpEnd, TS_TEXTCHANGE *pChange); + STDMETHODIMP RequestSupportedAttrs(DWORD dwFlags, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs); + STDMETHODIMP RequestAttrsAtPosition(LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags); + STDMETHODIMP RequestAttrsTransitioningAtPosition(LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags); + STDMETHODIMP FindNextAttrTransition(LONG acpStart, LONG acpHalt, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags, LONG *pacpNext, BOOL *pfFound, LONG *plFoundOffset); + STDMETHODIMP RetrieveRequestedAttrs(ULONG ulCount, TS_ATTRVAL *paAttrVals, ULONG *pcFetched); + STDMETHODIMP GetEndACP(LONG *pacp); + STDMETHODIMP GetActiveView(TsViewCookie *pvcView); + STDMETHODIMP GetACPFromPoint(TsViewCookie vcView, const POINT *ptScreen, DWORD dwFlags, LONG *pacp); + STDMETHODIMP GetTextExt(TsViewCookie vcView, LONG acpStart, LONG acpEnd, RECT *prc, BOOL *pfClipped); + STDMETHODIMP GetScreenExt(TsViewCookie vcView, RECT *prc); + STDMETHODIMP GetWnd(TsViewCookie vcView, HWND *phwnd); + + //ITfOwnerCompositionSink + STDMETHODIMP OnStartComposition(ITfCompositionView *pComposition, BOOL *pfOk); + STDMETHODIMP OnUpdateComposition(ITfCompositionView *pComposition, ITfRange *pRangeNew); + STDMETHODIMP OnEndComposition(ITfCompositionView *pComposition); + + void Initialize(); + void Finalize(); + + TSF_Text_Store(); + ~TSF_Text_Store(); + + private: + ULONG my_Reference_Count; + CComPtr my_Document_Manager; + CComPtr my_Context; + DWORD my_Edit_Cookie; + CComPtr my_Sink; + DWORD my_Sink_Mask; + DWORD my_Lock; + DWORD my_Lock_Queued; + CComPtr my_Composition_View; + TS_SELECTION_ACP my_Composition_Selection; + }; + TSF(); static bool COM_Initialized; static CComPtr Thread_Manager; + static TfClientId Client_Id; + static TSF_Text_Store *Text_Store; }; #endif diff -r 381d402a5e90 -r f51a9f01b508 EXCLUDE/GLTSF/src/TSF.cpp --- a/EXCLUDE/GLTSF/src/TSF.cpp Sat Jun 12 03:21:54 2010 -0400 +++ b/EXCLUDE/GLTSF/src/TSF.cpp Mon Jun 21 17:16:37 2010 -0400 @@ -3,6 +3,8 @@ bool TSF::COM_Initialized = false; CComPtr TSF::Thread_Manager; +TfClientId TSF::Client_Id; +TSF::TSF_Text_Store *TSF::Text_Store = NULL; void TSF::Initialize() { @@ -19,9 +21,11 @@ if (FAILED(CoCreateInstance(CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, IID_ITfThreadMgr, reinterpret_cast(&Thread_Manager)))) throw std::runtime_error("Failed to create ITfThreadMgr instance"); - TfClientId ClientId; - if (FAILED(Thread_Manager->Activate(&ClientId))) + if (FAILED(Thread_Manager->Activate(&Client_Id))) throw std::runtime_error("ITfThreadMgr::Activate failed"); + + Text_Store = new TSF_Text_Store; + Text_Store->Initialize(); } } @@ -38,3 +42,304 @@ COM_Initialized = false; } } + +STDMETHODIMP TSF::TSF_Text_Store::QueryInterface(REFIID riid, void **ppvObject) +{ + *ppvObject = NULL; + if (IID_IUnknown == riid || IID_ITextStoreACP == riid) + *ppvObject = static_cast(this); + else if (IID_ITfContextOwnerCompositionSink == riid) + *ppvObject = static_cast(this); + + if (*ppvObject) + { + AddRef(); + return S_OK; + } + return E_NOINTERFACE; +} + +STDMETHODIMP_(ULONG) TSF::TSF_Text_Store::AddRef() +{ + return ++my_Reference_Count; +} + +STDMETHODIMP_(ULONG) TSF::TSF_Text_Store::Release() +{ + --my_Reference_Count; + if (0 != my_Reference_Count) + return my_Reference_Count; + + delete this; + return 0; +} + +STDMETHODIMP TSF::TSF_Text_Store::AdviseSink(REFIID riid, IUnknown *punk, DWORD dwMask) +{ + if (!punk || IID_ITextStoreACPSink != riid) + return E_INVALIDARG; + + if (!my_Sink) + { + punk->QueryInterface(&my_Sink); + if (!my_Sink) + return E_UNEXPECTED; + } + else + { + CComPtr Unknown_1, Unknown_2; + punk->QueryInterface(&Unknown_1); + my_Sink->QueryInterface(&Unknown_2); + if (Unknown_1 != Unknown_2) + return CONNECT_E_ADVISELIMIT; + } + my_Sink_Mask = dwMask; + return S_OK; +} + +STDMETHODIMP TSF::TSF_Text_Store::UnadviseSink(IUnknown *punk) +{ + if (!punk) + return E_INVALIDARG; + + if (!my_Sink) + return CONNECT_E_NOCONNECTION; + + CComPtr Unknown_1, Unknown_2; + punk->QueryInterface(&Unknown_1); + my_Sink->QueryInterface(&Unknown_2); + + if (Unknown_1 != Unknown_2) + return CONNECT_E_NOCONNECTION; + + my_Sink = NULL; + my_Sink_Mask = 0; + return S_OK; +} + +STDMETHODIMP TSF::TSF_Text_Store::RequestLock(DWORD dwLockFlags, HRESULT *phrSession) +{ + if (!my_Sink) + return E_FAIL; + + if (!phrSession) + return E_INVALIDARG; + + if (my_Lock) + { + if (TS_LF_READ == (my_Lock & TS_LF_READWRITE) + && TS_LF_READWRITE == (dwLockFlags & TS_LF_READWRITE) + && !(dwLockFlags & TS_LF_SYNC)) + { + *phrSession = TS_S_ASYNC; + my_Lock_Queued = dwLockFlags & (~TS_LF_SYNC); + } + else + { + *phrSession = TS_E_SYNCHRONOUS; + return E_FAIL; + } + } + else + { + my_Lock = dwLockFlags & (~TS_LF_SYNC); + *phrSession = my_Sink->OnLockGranted(my_Lock); + while (my_Lock_Queued) + { + my_Lock = my_Lock_Queued; + my_Lock_Queued = 0; + my_Sink->OnLockGranted(my_Lock); + } + my_Lock = 0; + } + return S_OK; +} + +STDMETHODIMP TSF::TSF_Text_Store::GetStatus(TS_STATUS *pdcs) +{ + if (!pdcs) + return E_INVALIDARG; + + pdcs->dwDynamicFlags = 0; + pdcs->dwStaticFlags = TS_SS_NOHIDDENTEXT; + return S_OK; +} + +STDMETHODIMP TSF::TSF_Text_Store::QueryInsert(LONG acpTestStart, LONG acpTestEnd, ULONG cch, LONG *pacpResultStart, LONG *pacpResultEnd) +{ + if (acpTestStart < 0 || acpTestStart > acpTestEnd || !pacpResultStart || !pacpResultEnd) + return E_INVALIDARG; + + *pacpResultStart = acpTestStart; + *pacpResultEnd = acpTestStart + cch; + return S_OK; +} + +STDMETHODIMP TSF::TSF_Text_Store::GetSelection(ULONG ulIndex, ULONG ulCount, TS_SELECTION_ACP *pSelection, ULONG *pcFetched) +{ + if (TS_LF_READ != (my_Lock & TS_LF_READ)) + return TS_E_NOLOCK; + + if (!ulCount || !pSelection || !pcFetched) + return E_INVALIDARG; + + *pcFetched = 0; + if (TS_DEFAULT_SELECTION != ulIndex && 0 != ulIndex) + return TS_E_NOSELECTION; + + if (my_Composition_View) + { + *pSelection = my_Composition_Selection; + } + else + { + //TODO + } + return S_OK; +} + +STDMETHODIMP TSF::TSF_Text_Store::SetSelection(ULONG ulCount, const TS_SELECTION_ACP *pSelection) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::GetText(LONG acpStart, LONG acpEnd, WCHAR *pchPlain, ULONG cchPlainReq, ULONG *pcchPlainRet, TS_RUNINFO *prgRunInfo, ULONG cRunInfoReq, ULONG *pcRunInfoRet, LONG *pacpNext) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::SetText(DWORD dwFlags, LONG acpStart, LONG acpEnd, const WCHAR *pchText, ULONG cch, TS_TEXTCHANGE *pChange) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::GetFormattedText(LONG acpStart, LONG acpEnd, IDataObject **ppDataObject) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::GetEmbedded(LONG acpPos, REFGUID rguidService, REFIID riid, IUnknown **ppunk) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::QueryInsertEmbedded(const GUID *pguidService, const FORMATETC *pFormatEtc, BOOL *pfInsertable) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::InsertEmbedded(DWORD dwFlags, LONG acpStart, LONG acpEnd, IDataObject *pDataObject, TS_TEXTCHANGE *pChange) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::InsertTextAtSelection(DWORD dwFlags, const WCHAR *pchText, ULONG cch, LONG *pacpStart, LONG *pacpEnd, TS_TEXTCHANGE *pChange) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::InsertEmbeddedAtSelection(DWORD dwFlags, IDataObject *pDataObject, LONG *pacpStart, LONG *pacpEnd, TS_TEXTCHANGE *pChange) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::RequestSupportedAttrs(DWORD dwFlags, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::RequestAttrsAtPosition(LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::RequestAttrsTransitioningAtPosition(LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::FindNextAttrTransition(LONG acpStart, LONG acpHalt, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags, LONG *pacpNext, BOOL *pfFound, LONG *plFoundOffset) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::RetrieveRequestedAttrs(ULONG ulCount, TS_ATTRVAL *paAttrVals, ULONG *pcFetched) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::GetEndACP(LONG *pacp) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::GetActiveView(TsViewCookie *pvcView) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::GetACPFromPoint(TsViewCookie vcView, const POINT *ptScreen, DWORD dwFlags, LONG *pacp) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::GetTextExt(TsViewCookie vcView, LONG acpStart, LONG acpEnd, RECT *prc, BOOL *pfClipped) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::GetScreenExt(TsViewCookie vcView, RECT *prc) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::GetWnd(TsViewCookie vcView, HWND *phwnd) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::OnStartComposition(ITfCompositionView *pComposition, BOOL *pfOk) +{ + *pfOk = FALSE; + return S_OK; +} + +STDMETHODIMP TSF::TSF_Text_Store::OnUpdateComposition(ITfCompositionView *pComposition, ITfRange *pRangeNew) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TSF::TSF_Text_Store::OnEndComposition(ITfCompositionView *pComposition) +{ + return E_NOTIMPL; +} + +TSF::TSF_Text_Store::TSF_Text_Store() : my_Reference_Count(1), + my_Edit_Cookie(0), + my_Lock(0), + my_Lock_Queued(0) +{ + +} + +TSF::TSF_Text_Store::~TSF_Text_Store() +{ + +} + +void TSF::TSF_Text_Store::Initialize() +{ + if (FAILED(Thread_Manager->CreateDocumentMgr(&my_Document_Manager))) + throw std::runtime_error("Failed to create document manager"); + + if (FAILED(my_Document_Manager->CreateContext(Client_Id, 0, static_cast(this), &my_Context, &my_Edit_Cookie))) + throw std::runtime_error("Failed to create document context"); + + if (FAILED(my_Document_Manager->Push(my_Context))) + throw std::runtime_error("Failed to push context"); +} + +void TSF::TSF_Text_Store::Finalize() +{ + +}