OSDN Git Service

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