在之前版本的歪林輸入法,其中一個問題就是當在某程式打字時,切換去另一個程式,歪林輸入法的視窗不會自動隱藏。
其原因是歪林輸入法是基於微軟的"Sample Code for Text Services Framework",裡面沒有將視窗自動隱藏的部分。
後來在網友zhangruisen 的電郵中,得知只要在程式碼中,添加IID_ITfThreadFocusSink事件接收器,然后在相應的函數里(即STDAPI CTextService::OnSetThreadFocus() 和 STDAPI CTextService::OnKillThreadFocus() )顯示/隱藏窗口即可。在 Windows SDK 的 Samples\WinUI\TSFcase 有範例程式碼。
得此訊息後,就在歪林輸入法加了:
BOOL CTextService::_InitThreadFocusSink() { HRESULT hr; ITfSource *pSource = NULL; if (_pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource) != S_OK) return FALSE; hr = pSource->AdviseSink(IID_ITfThreadFocusSink, (ITfThreadFocusSink *)this, &_dwThreadFocusSinkCookie); pSource->Release(); return (hr == S_OK); } // _UninitThreadFocusSink // Unadvise a Focus sink. Assumes a sink has been advised already. void CTextService::_UninitThreadFocusSink() { ITfSource *pSource; if (_pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource) != S_OK) return; pSource->UnadviseSink(_dwThreadFocusSinkCookie); pSource->Release(); } STDAPI CTextService::OnSetThreadFocus() { if (_pCandidateWin) _pCandidateWin->Show(TRUE); return S_OK; } STDAPI CTextService::OnKillThreadFocus() { if (_pCandidateWin) _pCandidateWin->Show(FALSE); return S_OK; } |
在加入上面程式碼後,以為在 CTextService::Activate() 裡面呼叫 CTextService::_InitThreadFocusSink() 就可以了。怎料,每次呼叫這函數,都 返回 S_FAILED 值。這問題一直困擾我很久,超越大半年時間。(也是因為懶惰)
直到昨天晚上下班後,又提起精神,再仔細比較 Windows SDK 的 TSF Case 和我 歪林輸入法程式碼的分別。終於找到了!原來:
STDAPI CTextService::QueryInterface(REFIID riid, void **ppvObj) { if (ppvObj == NULL) return E_INVALIDARG; *ppvObj = NULL; if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfTextInputProcessor)) { *ppvObj = (ITfTextInputProcessor *)this; } else if (IsEqualIID(riid, IID_ITfThreadMgrEventSink)) { *ppvObj = (ITfThreadMgrEventSink *)this; }
else if (IsEqualIID(riid, IID_ITfTextEditSink)) { |
Windows SDK 的 TSF Case 有「框」的部分,而歪林輸入法和其他 TSF Sample code 就沒有。一加了上面的 code,歪林輸入法就可以在切換視窗時,自動隱蔽起來。
天啊!一耽誤就是半年!
沒有留言:
張貼留言