OSDN Git Service

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