本來這個blog是記錄開發輸入法的點滴的,後來越來越雜,現在什麼都記錄了。

2008年12月17日 星期三

Problem with Microsoft's Text Service Framework (TSF) Examples.

Problem with Microsoft's Text Service Framework (TSF) Examples.

In the previous version of YLam Input method, one of the bugs is when you are typing towards the windows of an application, and then you switch to another application, the YLam Input method windows does not hide itself.

The reason is YLam Input method is based on Microsoft's "Sample Code for Text Services Framework" and there is no examples shows how to auto hide the input method window when the application loses its focus.

After the email discussion with a net friend "zhangruisen", it is known that to support auto show/hide, the "IID_ITfThreadFocusSink" event sink is needed, and in the appropriate functions (i.e. STDAPI CTextService::OnSetThreadFocus() and STDAPI CTextService::OnKillThreadFocus() ), call the show / hide input method window. In Windows SDK, Windows SDK 的 Samples\WinUI\TSFcase, there is an example.

So, I added the following code to my YLam Input Method:

  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;
  }

Then in CTextService::Activate(), I called CTextService::_InitThreadFocusSink() and expect that is all! However, no matter how hard I tried to tweak the code, calling _InitThreadFocusSink() always returns S_FAILED. This puzzled me for more that 1/2 years.

Until last evening after back home from work, though very tired, I still tried to compare the Windows SDK's TSF Case example and my YLam Input Method carefully and I finally know what's wroong! It turns out:

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_ITfThreadFocusSink)) {
        *ppvObj = (ITfThreadFocusSink *)this;
    }

else if (IsEqualIID(riid, IID_ITfTextEditSink)) {
        *ppvObj = (ITfTextEditSink *)this;
    } else if (IsEqualIID(riid, IID_ITfKeyEventSink)) {
        *ppvObj = (ITfKeyEventSink *)this;
    } else if (IsEqualIID(riid, IID_ITfCompositionSink)) {
        *ppvObj = (ITfKeyEventSink *)this;
    } else if (IsEqualIID(riid, IID_ITfDisplayAttributeProvider)) {
        *ppvObj = (ITfDisplayAttributeProvider *)this;
    }

    if (*ppvObj) {
        AddRef();
        return S_OK;
    }

    return E_NOINTERFACE;
}
 

In Windows SDK's TSF Case, the part in box above exits and it does not exist in YLam Input Method and other TSF Sample code!!!!!!!! After adding the few lines above, now my YLam input method can do auto show /hide!!!

Oh my god, such a few lines spent me 1/2 years!

3 則留言:

匿名 提到...

Lastly, you should know that the online therapist finder is really appropriate.
You got to get hold of the best professional therapist in
town who can help you to fine tune and perfect your
personality traits and bolster your confidence level to new high.
Step 3: Determine the goal(s) you would like to achieve during each session.
Here is my homepage ... beeplog.com

匿名 提到...

I'm gone to inform my little brother, that he should also pay a quick visit this blog on regular basis to get updated from latest news update.

Here is my weblog: ideal waist to height ratio

Blogger 提到...

Did you know you can shorten your links with AdFly and earn cash from every click on your short links.