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.
--- 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<ITfDocumentMgr> my_Document_Manager;
+ CComPtr<ITfContext> my_Context;
+ DWORD my_Edit_Cookie;
+ CComPtr<ITextStoreACPSink> my_Sink;
+ DWORD my_Sink_Mask;
+ DWORD my_Lock;
+ DWORD my_Lock_Queued;
+ CComPtr<ITfCompositionView> my_Composition_View;
+ TS_SELECTION_ACP my_Composition_Selection;
+ };
+
TSF();
static bool COM_Initialized;
static CComPtr<ITfThreadMgr> Thread_Manager;
+ static TfClientId Client_Id;
+ static TSF_Text_Store *Text_Store;
};
#endif
--- 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<ITfThreadMgr> 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<void **>(&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<ITextStoreACP *>(this);
+ else if (IID_ITfContextOwnerCompositionSink == riid)
+ *ppvObject = static_cast<ITfContextOwnerCompositionSink *>(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<IUnknown> 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<IUnknown> 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<ITextStoreACP *>(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()
+{
+
+}