OSDN Git Service

Reduce invocations of CoInitializeEx
[xkeymacs/xkeymacs.git] / xkeymacsdll / TSFHandler.cpp
1 #include "StdAfx.h"\r
2 #include "TSFHandler.h"\r
3 #include "Utils.h"\r
4 #include "TLS.h"\r
5 #include "xkeymacsdll.h"\r
6 #include <ObjBase.h>\r
7 \r
8 #ifdef DEBUG_IME\r
9 #define DebugLog(fmt, ...) CUtils::Log(_T(__FUNCTION__ ## ": " ## fmt), __VA_ARGS__)\r
10 #else\r
11 #define DebugLog(fmt, ...)\r
12 #endif\r
13 \r
14 TSFHandler::TSFHandler()\r
15 {\r
16         m_RefCount = 1;\r
17         m_ThreadMgr = nullptr;\r
18         m_Cookie = TF_INVALID_COOKIE;\r
19         m_Context = nullptr;\r
20         m_CompositionState = false;\r
21 }\r
22 \r
23 TSFHandler::~TSFHandler()\r
24 {\r
25         if (m_ThreadMgr)\r
26                 m_ThreadMgr->Release();\r
27         if (m_Context)\r
28                 m_Context->Release();\r
29 }\r
30 \r
31 void TSFHandler::InitSink()\r
32 {\r
33         if (TLS::GetTSFHandler())\r
34                 return;\r
35         ITfThreadMgr *thread;\r
36         HRESULT hr = CoCreateInstance(CLSID_TF_ThreadMgr, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&thread));\r
37         if (hr == CO_E_NOTINITIALIZED) {\r
38                 hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);\r
39                 if (FAILED(hr)) {\r
40                         DebugLog("CoInitializeEx failed.");\r
41                         return;\r
42                 }\r
43                 if (hr == S_FALSE)\r
44                         CoUninitialize();\r
45                 hr = CoCreateInstance(CLSID_TF_ThreadMgr, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&thread));\r
46         }\r
47         if (FAILED(hr)) {\r
48                 DebugLog("CoCreateInstance for ThreadMgr failed.");\r
49                 return;\r
50         }\r
51         TSFHandler *tsfh = new TSFHandler();\r
52         TLS::PutTSFHandler(tsfh);\r
53         tsfh->m_ThreadMgr = thread;\r
54         ITfSource *src;\r
55         if (FAILED(thread->QueryInterface(&src))) {\r
56                 DebugLog("ThreadMgr->QueryInterface failed.");\r
57                 goto fail;\r
58         }\r
59         DWORD cookie;\r
60         if (FAILED(src->AdviseSink(IID_ITfThreadMgrEventSink, static_cast<ITfThreadMgrEventSink *>(tsfh), &cookie))) {\r
61                 DebugLog("Souece->AdviseSink failed.");\r
62                 src->Release();\r
63                 goto fail;\r
64         }\r
65         src->Release();\r
66         return;\r
67 fail:\r
68         delete tsfh;\r
69         return;\r
70 }\r
71 \r
72 STDMETHODIMP TSFHandler::QueryInterface(REFIID iid, void **obj)\r
73 {\r
74         if (obj == nullptr)\r
75                 return E_INVALIDARG;\r
76         *obj = nullptr;\r
77         if (IsEqualIID(iid, IID_IUnknown) || iid == IID_ITfThreadMgrEventSink)\r
78                 *obj = static_cast<ITfThreadMgrEventSink *>(this);\r
79         else if (iid == IID_ITfTextEditSink)\r
80                 *obj = static_cast<ITfTextEditSink *>(this);\r
81         else\r
82                 return E_NOINTERFACE;\r
83         AddRef();\r
84         return S_OK;\r
85 }\r
86 \r
87 STDMETHODIMP_(ULONG) TSFHandler::AddRef()\r
88 {\r
89         return ++m_RefCount;\r
90 }\r
91 \r
92 STDMETHODIMP_(ULONG) TSFHandler::Release()\r
93 {\r
94         if (--m_RefCount == 0)\r
95                 delete this;\r
96         return m_RefCount;\r
97 }\r
98 \r
99 // ITfThreadMgrEventSink\r
100 STDMETHODIMP TSFHandler::OnInitDocumentMgr(ITfDocumentMgr *)\r
101 {\r
102         DebugLog("OnInitDocumentMgr");\r
103         return S_OK;\r
104 }\r
105 \r
106 STDMETHODIMP TSFHandler::OnPopContext(ITfContext *)\r
107 {\r
108         DebugLog("OnPopContext");\r
109         return S_OK;\r
110 }\r
111 \r
112 STDMETHODIMP TSFHandler::OnPushContext(ITfContext *)\r
113 {\r
114         DebugLog("OnPushContext");\r
115         return S_OK;\r
116 }\r
117 \r
118 STDMETHODIMP TSFHandler::OnSetFocus(ITfDocumentMgr *docMgr, ITfDocumentMgr *)\r
119 {\r
120         DebugLog("OnSetFocus");\r
121         if (docMgr == nullptr)\r
122                 return S_OK;\r
123         if (m_Cookie != TF_INVALID_COOKIE) {\r
124                 ITfSource *src;\r
125                 if (FAILED(m_Context->QueryInterface(&src))) {\r
126                         DebugLog("Context->QueryInterface:0 failed.");\r
127                         return S_OK;\r
128                 }\r
129                 HRESULT hr = src->UnadviseSink(m_Cookie);\r
130                 src->Release();\r
131                 if (FAILED(hr)) {\r
132                         DebugLog("Source->UnadviceThink failed.");\r
133                         return S_OK;\r
134                 }\r
135                 m_Context->Release();\r
136                 m_Context = nullptr;\r
137                 m_Cookie = TF_INVALID_COOKIE;\r
138         }\r
139         ITfContext *cxt;\r
140         if (FAILED(docMgr->GetTop(&cxt))) {\r
141                 DebugLog("DocumentMgr->GetTop failed.");\r
142                 return S_OK;\r
143         }\r
144         if (cxt == nullptr) {\r
145                 DebugLog("ITfContext is null.");\r
146                 return S_OK;\r
147         }\r
148         ITfSource *src;\r
149         if (FAILED(cxt->QueryInterface(&src))) {\r
150                 DebugLog("Context->QueryInterface:1 failed.");\r
151                 goto fail;\r
152         }\r
153         if (FAILED(src->AdviseSink(IID_ITfTextEditSink, static_cast<ITfTextEditSink *>(this), &m_Cookie))) {\r
154                 DebugLog("Source->AdviseSink(ITfTextEditSink) failed.");\r
155                 src->Release();\r
156                 goto fail;\r
157         }\r
158         src->Release();\r
159         m_Context = cxt;\r
160         return S_OK;\r
161 fail:\r
162         cxt->Release();\r
163         return S_OK;\r
164 }\r
165 \r
166 STDMETHODIMP TSFHandler::OnUninitDocumentMgr(ITfDocumentMgr *)\r
167 {\r
168         DebugLog("OnUninitDocumentMgr");\r
169         return S_OK;\r
170 }\r
171 \r
172 STDMETHODIMP TSFHandler::OnEndEdit(ITfContext *cxt, TfEditCookie, ITfEditRecord *)\r
173 {\r
174         DebugLog("OnEndEdit");\r
175         ITfContextComposition *comp;\r
176         if (FAILED(cxt->QueryInterface(&comp))) {\r
177                 DebugLog("Context->QueryInterface(ITfContextComposition) failed.");\r
178                 return S_OK;\r
179         }\r
180         IEnumITfCompositionView *enumCompView;\r
181         if (FAILED(comp->EnumCompositions(&enumCompView))) {\r
182                 DebugLog("ContextComposition->EnumCompositions failed.");\r
183                 goto fail;\r
184         }\r
185         ITfCompositionView *view;\r
186         ULONG fetched;\r
187         HRESULT hr = enumCompView->Next(1, &view, &fetched);\r
188         if (FAILED(hr)) {\r
189                 DebugLog("EnumCompositions->Next failed.");\r
190                 enumCompView->Release();\r
191                 goto fail;\r
192         }\r
193         DebugLog("EnumComposition->Next succeeded. fetched=%d", fetched);\r
194         if (fetched) {\r
195                 if (!m_CompositionState)\r
196                         CXkeymacsDll::SetIMEState(true);\r
197                 m_CompositionState = true;\r
198                 view->Release();\r
199         }\r
200         else {\r
201                 if (m_CompositionState)\r
202                         CXkeymacsDll::SetIMEState(false);\r
203                 m_CompositionState = false;\r
204         }\r
205         enumCompView->Release();\r
206 fail:\r
207         comp->Release();\r
208         return S_OK;\r
209 }