コミットメタ情報

リビジョンc1bfc099f4dcea4eed11297e3aaaa911bdca8f11 (tree)
日時2014-09-13 16:44:07
作者Kazuhiro Fujieda <fujieda@user...>
コミッターKazuhiro Fujieda

ログメッセージ

Support TSF-based IMEs on TSF-aware applications

XKeymacs can't recognize the start and end of a composition by a
TSF-based IME on a TSF-aware application. It therefore doesn't switch
the current configuration from the application to the IME on the start
of a composition. One of such cases is Microsoft IME and Internet
Explorer 11 on Windows 7. This patch lets XKeymacs recognize the start
and end of a composition in such cases.

変更サマリ

差分

--- a/xkeymacsdll/TLS.cpp
+++ b/xkeymacsdll/TLS.cpp
@@ -36,6 +36,9 @@ void TLS::FreeLocal()
3636 LPVOID data = TlsGetValue(m_TlsIndex);
3737 if (!data)
3838 return;
39+ TSFHandler *tmp = reinterpret_cast<TLS *>(data)->m_TSFHandler;
40+ if (tmp)
41+ tmp->Release();
3942 LocalFree(data);
4043 TlsSetValue(m_TlsIndex, nullptr);
4144 }
@@ -51,4 +54,17 @@ void TLS::PutKeyboardHook(HHOOK hook)
5154 TLS *tls = AllocLocal();
5255 if (tls)
5356 tls->m_KeyboardHook = hook;
57+}
58+
59+TSFHandler *TLS::GetTSFHandler()
60+{
61+ TLS *tls = AllocLocal();
62+ return tls ? tls->m_TSFHandler : nullptr;
63+}
64+
65+void TLS::PutTSFHandler(TSFHandler *tsf)
66+{
67+ TLS *tls = AllocLocal();
68+ if (tls)
69+ tls->m_TSFHandler = tsf;
5470 }
\ No newline at end of file
--- a/xkeymacsdll/TLS.h
+++ b/xkeymacsdll/TLS.h
@@ -1,4 +1,6 @@
11 #pragma once
2+#include "TSFHandler.h"
3+
24 class TLS
35 {
46 public:
@@ -7,11 +9,13 @@ public:
79 static void FreeLocal();
810 static HHOOK GetKeyboardHook();
911 static void PutKeyboardHook(HHOOK hook);
12+ static TSFHandler *GetTSFHandler();
13+ static void PutTSFHandler(TSFHandler *tsf);
1014
1115 private:
1216 static DWORD m_TlsIndex;
13- static TLS *m_LocalData;
14- HHOOK m_KeyboardHook;
1517 static TLS *AllocLocal();
18+ HHOOK m_KeyboardHook;
19+ TSFHandler *m_TSFHandler;
1620 };
1721
--- /dev/null
+++ b/xkeymacsdll/TSFHandler.cpp
@@ -0,0 +1,194 @@
1+#include "StdAfx.h"
2+#include "TSFHandler.h"
3+#include "Utils.h"
4+#include "TLS.h"
5+#include "xkeymacsdll.h"
6+#include <ObjBase.h>
7+
8+#ifdef DEBUG_IME
9+#define DebugLog(fmt, ...) CUtils::Log(fmt, __VA_ARGS__)
10+#else
11+#define DebugLog(fmt, ...)
12+#endif
13+
14+TSFHandler::TSFHandler()
15+{
16+ m_RefCount = 1;
17+ m_ThreadMgr = nullptr;
18+ m_ClientId = 0;
19+ m_Context = nullptr;
20+ m_CompositionState = false;
21+}
22+
23+TSFHandler::~TSFHandler()
24+{
25+ if (m_ThreadMgr) {
26+ m_ThreadMgr->Deactivate();
27+ m_ThreadMgr->Release();
28+ }
29+ if (m_Context)
30+ m_Context->Release();
31+}
32+
33+void TSFHandler::InitSink()
34+{
35+ if (TLS::GetTSFHandler())
36+ return;
37+ TSFHandler *tsfh = new TSFHandler();
38+ TLS::PutTSFHandler(tsfh);
39+
40+ HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
41+ if (FAILED(hr)) {
42+ DebugLog(_T("CoInitializeEx failed."));
43+ return;
44+ }
45+ if (hr == S_FALSE)
46+ CoUninitialize();
47+ ITfThreadMgr *thread;
48+ if (FAILED(CoCreateInstance(CLSID_TF_ThreadMgr, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&thread)))) {
49+ DebugLog(_T("CoCreateInstance for ThreadMgr failed."));
50+ return;
51+ }
52+ tsfh->m_ThreadMgr = thread;
53+ if (FAILED(thread->Activate(&tsfh->m_ClientId))) {
54+ DebugLog(_T("ThreadMgr->Activate failed."));
55+ goto fail;
56+ }
57+ ITfSource *src;
58+ if (FAILED(thread->QueryInterface(&src))) {
59+ DebugLog(_T("ThreadMgr->QueryInterface failed."));
60+ goto fail;
61+ }
62+ if (FAILED(src->AdviseSink(IID_ITfThreadMgrEventSink, static_cast<ITfThreadMgrEventSink *>(tsfh), &tsfh->m_ClientId))) {
63+ DebugLog(_T("Souece->AdviseSink failed."));
64+ src->Release();
65+ goto fail;
66+ }
67+ src->Release();
68+ return;
69+fail:
70+ delete tsfh;
71+ return;
72+}
73+
74+STDMETHODIMP TSFHandler::QueryInterface(REFIID iid, void **obj)
75+{
76+ if (obj == nullptr)
77+ return E_INVALIDARG;
78+ *obj = nullptr;
79+ if (IsEqualIID(iid, IID_IUnknown) || iid == IID_ITfThreadMgrEventSink)
80+ *obj = static_cast<ITfThreadMgrEventSink *>(this);
81+ else if (iid == IID_ITfTextEditSink)
82+ *obj = static_cast<ITfTextEditSink *>(this);
83+ else
84+ return E_NOINTERFACE;
85+ AddRef();
86+ return S_OK;
87+}
88+
89+STDMETHODIMP_(ULONG) TSFHandler::AddRef()
90+{
91+ return ++m_RefCount;
92+}
93+
94+STDMETHODIMP_(ULONG) TSFHandler::Release()
95+{
96+ if (--m_RefCount == 0)
97+ delete this;
98+ return m_RefCount;
99+}
100+
101+// ITfThreadMgrEventSink
102+STDMETHODIMP TSFHandler::OnInitDocumentMgr(ITfDocumentMgr *)
103+{
104+ DebugLog(_T("OnInitDocumentMgr"));
105+ return S_OK;
106+}
107+
108+STDMETHODIMP TSFHandler::OnPopContext(ITfContext *)
109+{
110+ DebugLog(_T("OnPopContext"));
111+ return S_OK;
112+}
113+
114+STDMETHODIMP TSFHandler::OnPushContext(ITfContext *)
115+{
116+ DebugLog(_T("OnPushContext"));
117+ return S_OK;
118+}
119+
120+STDMETHODIMP TSFHandler::OnSetFocus(ITfDocumentMgr *docMgr, ITfDocumentMgr *)
121+{
122+ DebugLog(_T("OnSetFocus"));
123+ if (docMgr == nullptr)
124+ return S_OK;
125+ ITfContext *cxt;
126+ if (FAILED(docMgr->GetTop(&cxt))) {
127+ DebugLog(_T("DocumentMgr->GetTop failed."));
128+ return S_OK;
129+ }
130+ if (m_Context == cxt)
131+ goto fail;
132+ ITfSource *src = nullptr;
133+ if (FAILED(cxt->QueryInterface(&src))) {
134+ DebugLog(_T("Context->QueryInterface(ITfSource) failed."));
135+ goto fail;
136+ }
137+ DWORD cookie;
138+ if (FAILED(src->AdviseSink(IID_ITfTextEditSink, static_cast<ITfTextEditSink *>(this), &cookie))) {
139+ DebugLog(_T("Source->AdviseSink(ITfTextEditSink) failed."));
140+ src->Release();
141+ goto fail;
142+ }
143+ src->Release();
144+ m_Context = cxt;
145+ return S_OK;
146+fail:
147+ cxt->Release();
148+ return S_OK;
149+}
150+
151+STDMETHODIMP TSFHandler::OnUninitDocumentMgr(ITfDocumentMgr *)
152+{
153+ DebugLog(_T("OnUninitDocumentMgr"));
154+ return S_OK;
155+}
156+
157+STDMETHODIMP TSFHandler::OnEndEdit(ITfContext *cxt, TfEditCookie, ITfEditRecord *)
158+{
159+ DebugLog(_T("OnEndEdit"));
160+ ITfContextComposition *comp;
161+ if (FAILED(cxt->QueryInterface(&comp))) {
162+ DebugLog(_T("Context->QueryInterface(ITfContextComposition) failed."));
163+ return S_OK;
164+ }
165+ IEnumITfCompositionView *enumCompView;
166+ if (FAILED(comp->EnumCompositions(&enumCompView))) {
167+ DebugLog(_T("ContextComposition->EnumCompositions failed."));
168+ goto fail;
169+ }
170+ ITfCompositionView *view;
171+ ULONG fetched;
172+ HRESULT hr = enumCompView->Next(1, &view, &fetched);
173+ if (FAILED(hr)) {
174+ DebugLog(_T("EnumCompositions->Next failed."));
175+ enumCompView->Release();
176+ goto fail;
177+ }
178+ DebugLog(_T("EnumComposition->Next succeeded. fetched=%d"), fetched);
179+ if (fetched) {
180+ if (!m_CompositionState)
181+ CXkeymacsDll::SetIMEState(true);
182+ m_CompositionState = true;
183+ view->Release();
184+ }
185+ else {
186+ if (m_CompositionState)
187+ CXkeymacsDll::SetIMEState(false);
188+ m_CompositionState = false;
189+ }
190+ enumCompView->Release();
191+fail:
192+ comp->Release();
193+ return S_OK;
194+}
\ No newline at end of file
--- /dev/null
+++ b/xkeymacsdll/TSFHandler.h
@@ -0,0 +1,35 @@
1+#pragma once
2+
3+#include <msctf.h>
4+
5+class TSFHandler: public ITfThreadMgrEventSink, public ITfTextEditSink
6+{
7+public:
8+ TSFHandler();
9+ ~TSFHandler();
10+ static void InitSink();
11+ static void SetFocus();
12+
13+ // IUnknown
14+ STDMETHODIMP QueryInterface(REFIID riid, void **obj);
15+ STDMETHODIMP_(ULONG) AddRef();
16+ STDMETHODIMP_(ULONG) Release();
17+
18+ // ITfThreadMgrEventSink
19+ STDMETHODIMP OnInitDocumentMgr(ITfDocumentMgr *);
20+ STDMETHODIMP OnPopContext(ITfContext *);
21+ STDMETHODIMP OnPushContext(ITfContext *);
22+ STDMETHODIMP OnSetFocus(ITfDocumentMgr *, ITfDocumentMgr *);
23+ STDMETHODIMP OnUninitDocumentMgr(ITfDocumentMgr *);
24+
25+ // ITfTextEditSink
26+ STDMETHODIMP OnEndEdit(ITfContext *, TfEditCookie , ITfEditRecord *);
27+
28+private:
29+ ULONG m_RefCount;
30+ ITfThreadMgr *m_ThreadMgr;
31+ TfClientId m_ClientId;
32+ ITfContext *m_Context;
33+ bool m_CompositionState;
34+};
35+
--- a/xkeymacsdll/xkeymacsdll-vc10.vcxproj
+++ b/xkeymacsdll/xkeymacsdll-vc10.vcxproj
@@ -216,6 +216,7 @@
216216 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
217217 </ClCompile>
218218 <ClCompile Include="TLS.cpp" />
219+ <ClCompile Include="TSFHandler.cpp" />
219220 <ClCompile Include="Utils.cpp" />
220221 <ClCompile Include="xkeymacsdll.cpp" />
221222 </ItemGroup>
@@ -236,6 +237,7 @@
236237 <ClInclude Include="resource.h" />
237238 <ClInclude Include="StdAfx.h" />
238239 <ClInclude Include="TLS.h" />
240+ <ClInclude Include="TSFHandler.h" />
239241 <ClInclude Include="tstring.h" />
240242 <ClInclude Include="Utils.h" />
241243 <ClInclude Include="xkeymacsdll.h" />
--- a/xkeymacsdll/xkeymacsdll-vc10.vcxproj.filters
+++ b/xkeymacsdll/xkeymacsdll-vc10.vcxproj.filters
@@ -51,6 +51,9 @@
5151 <ClCompile Include="TLS.cpp">
5252 <Filter>Source Files</Filter>
5353 </ClCompile>
54+ <ClCompile Include="TSFHandler.cpp">
55+ <Filter>Source Files</Filter>
56+ </ClCompile>
5457 </ItemGroup>
5558 <ItemGroup>
5659 <None Include="xkeymacsdll.def">
@@ -106,6 +109,9 @@
106109 <ClInclude Include="TLS.h">
107110 <Filter>Header Files</Filter>
108111 </ClInclude>
112+ <ClInclude Include="TSFHandler.h">
113+ <Filter>Header Files</Filter>
114+ </ClInclude>
109115 </ItemGroup>
110116 <ItemGroup>
111117 <ResourceCompile Include="xkeymacsdll.rc">
--- a/xkeymacsdll/xkeymacsdll.cpp
+++ b/xkeymacsdll/xkeymacsdll.cpp
@@ -6,6 +6,7 @@
66 #include "Commands.h"
77 #include "CmdTable.h"
88 #include "TLS.h"
9+#include "TSFHandler.h"
910 #include "../xkeymacs/resource.h"
1011 #include <math.h>
1112 #include <Imm.h>
@@ -242,26 +243,29 @@ void CXkeymacsDll::ShowHookState()
242243 LRESULT CALLBACK CXkeymacsDll::CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
243244 {
244245 SetKeyboardHook();
246+ TSFHandler::InitSink();
245247 if (nCode >= 0) {
246248 const CWPSTRUCT *cwps = reinterpret_cast<CWPSTRUCT *>(lParam);
247249 switch (cwps->message) {
248250 case WM_IME_STARTCOMPOSITION:
249- AppName::SetIMEState(true);
250- InitKeyboardProc();
251+#ifdef DEBUG_IME
252+ CUtils::Log(_T("WM_IME_STARTCOMPOSITION"));
253+#endif
254+ SetIMEState(true);
251255 break;
252256 case WM_IME_ENDCOMPOSITION:
253- AppName::SetIMEState(false);
254- InitKeyboardProc();
257+#ifdef DEBUG_IME
258+ CUtils::Log(_T("WM_IME_ENDCOMPOSITION"));
259+#endif
260+ SetIMEState(false);
255261 break;
256262 case WM_SETFOCUS:
257- AppName::SetIMEState(false);
258- InitKeyboardProc();
263+ SetIMEState(false);
259264 ShowHookState();
260265 break;
261266 case WM_NCACTIVATE:
262267 if (cwps->wParam && cwps->hwnd == GetForegroundWindow()) {
263- AppName::SetIMEState(false);
264- InitKeyboardProc();
268+ SetIMEState(false);
265269 ShowHookState();
266270 }
267271 break;
@@ -295,18 +299,28 @@ LRESULT CALLBACK CXkeymacsDll::GetMsgProc(int nCode, WPARAM wParam, LPARAM lPara
295299 const MSG *msg = reinterpret_cast<MSG *>(lParam);
296300 switch (msg->message) {
297301 case WM_IME_STARTCOMPOSITION:
298- AppName::SetIMEState(true);
299- InitKeyboardProc();
302+#ifdef DEBUG_IME
303+ CUtils::Log(_T("WM_IME_STARTCOMPOSITION"));
304+#endif
305+ SetIMEState(true);
300306 break;
301307 case WM_IME_ENDCOMPOSITION:
302- AppName::SetIMEState(false);
303- InitKeyboardProc();
308+#ifdef DEBUG_IME
309+ CUtils::Log(_T("WM_IME_ENDCOMPOSITION"));
310+#endif
311+ SetIMEState(false);
304312 break;
305313 }
306314 }
307315 return CallNextHookEx(NULL, nCode, wParam, lParam);
308316 }
309317
318+void CXkeymacsDll::SetIMEState(bool on)
319+{
320+ AppName::SetIMEState(on);
321+ InitKeyboardProc();
322+}
323+
310324 LRESULT CALLBACK CXkeymacsDll::ShellProc(int nCode, WPARAM wParam, LPARAM lParam)
311325 {
312326 if (nCode == HSHELL_WINDOWACTIVATED) {
--- a/xkeymacsdll/xkeymacsdll.h
+++ b/xkeymacsdll/xkeymacsdll.h
@@ -24,7 +24,6 @@ public:
2424 static BOOL LoadConfig();
2525 static void SetConfig(const Config& config);
2626 static void SetHooks();
27- static void SetKeyboardHook(DWORD threadId = 0);
2827 static void ResetHooks();
2928 static void ReleaseHooks();
3029 static void ReleaseKeyboardHook();
@@ -32,6 +31,7 @@ public:
3231 static void ToggleHookState();
3332 static bool GetHookState();
3433 static void ShowHookState();
34+ static void SetIMEState(bool on);
3535 static void SetM_xTip(LPCTSTR szPath);
3636 static void SendIconMessage(IconState *state, int num);
3737 static BOOL IsDown(BYTE bVk, BOOL bPhysicalKey = TRUE);
@@ -64,6 +64,7 @@ private:
6464 static HHOOK m_hHookGetMessage;
6565 static HHOOK m_hHookShell;
6666 static bool m_bEnableKeyboardHook;
67+ static void SetKeyboardHook(DWORD threadId = 0);
6768 static bool m_bHook;
6869 static void SetHookState(bool enable);
6970 static DWORD m_nHookAltRelease;
旧リポジトリブラウザで表示