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

2008年10月30日 星期四

繁體字轉換日文漢字的表格

為了為我的輸入法搞搞新意思,增加了一些漢字對換日文字的功能。

乘乗亞亜佛仏來来傳伝僞偽價価儉倹兒児冨富
凉涼剩剰劍剣勳勲卷巻卽即單単嚴厳圈圏國国
圓円團団埜野增増壘塁壞壊壯壮壽寿奧奥奬奨
孃嬢寢寝實実寬寛將将專専峯峰峽峡嶋島巢巣
帶帯廣広廳庁彈弾從従徵徴德徳恆恒惠恵惡悪
愼慎應応懷懐戰戦戲戯拂払拔抜拜拝揭掲搖揺
搜捜擊撃攝摂收収敍叙晚晩晝昼曆暦曉暁條条
榮栄樂楽樣様橫横檢検櫻桜步歩歷歴每毎氣気
涉渉淚涙淨浄渴渇溫温滯滞澁渋濕湿瀧滝瀨瀬
燈灯燒焼爭争爲為狀状狹狭獸獣疊畳盃杯盜盗
盡尽眞真碎砕祕秘禪禅禮礼稻稲穗穂粹粋綠緑
緖緒緣縁縣県縱縦纖繊聽聴臟臓與与莊荘萬万
薗園薰薫藏蔵藝芸藥薬虛虚衞衛裝装覽覧謠謡
讓譲賣売賴頼轉転郞郎醉酔釀醸錄録鍊錬鎭鎮
鑄鋳陷陥險険雜雑靜静顯顕飜翻駈駆騷騒驗験
髮髪鷄鶏黃黄黑黒默黙齊斉龍竜稱称涉渉狀状
瀨瀬雙双巢巣增増徵徴鬬闘德徳晚晩步歩豐豊
每毎賴頼綠緑淚涙戾戻曆暦歷歴鍊錬錄録亞亜
惡悪壓圧圍囲醫医爲為壹壱隱隠榮栄營営衞衛
驛駅圓円鹽塩緣縁應応歐欧毆殴櫻桜奧奥橫横
溫温穩穏假仮價価畫画會会繪絵壞壊懷懐擴拡
殼殻覺覚學学嶽岳樂楽渴渇罐缶卷巻陷陥勸勧
寬寛關関歡歓觀観氣気歸帰僞偽戲戯犧犠舊旧
據拠擧挙虛虚峽峡挾挟狹狭鄉郷曉暁區区驅駆
勳勲薰薫徑径莖茎惠恵揭掲溪渓經経螢蛍輕軽
繼継鷄鶏藝芸擊撃缺欠縣県儉倹嚴厳廣広效効
恆恒黃黄鑛鉱號号國国黑黒碎砕濟済齋斎劑剤
雜雑參参棧桟蠶蚕慘惨贊賛殘残絲糸齒歯兒児
辭辞濕湿實実寫写釋釈壽寿收収從従澁渋獸獣
縱縦肅粛處処敍叙將将燒焼證証奬奨繩縄壤壌
孃嬢讓譲釀醸條条乘乗淨浄剩剰疊畳觸触囑嘱
眞真寢寝愼慎盡尽圖図粹粋醉酔穗穂隨随髓髄
樞枢數数聲声齊斉靜静竊窃攝摂專専淺浅戰戦
踐践錢銭潛潜纖繊禪禅壯壮爭争莊荘搜捜插挿
裝装總総騷騒藏蔵臟臓墮堕屬属續続對対體体
帶帯滯滞臺台瀧滝擇択澤沢擔担單単膽胆團団
斷断彈弾遲遅癡痴蟲虫晝昼鑄鋳廳庁聽聴敕勅
鎭鎮遞逓鐵鉄點点轉転傳伝燈灯當当黨党盜盗
稻稲獨独讀読屆届貳弐惱悩腦脳霸覇拜拝廢廃
賣売麥麦發発髮髪拔抜蠻蛮祕秘濱浜拂払佛仏
竝並邊辺變変寶宝襃褒飜翻萬万滿満默黙譯訳
藥薬與与豫予餘余譽誉搖揺樣様謠謡來来亂乱
覽覧龍竜兩両獵猟壘塁禮礼勵励靈霊齡齢戀恋
爐炉勞労樓楼灣湾辨弁瓣弁辯弁000

2008年10月24日 星期五

微軟公佈的 TSF 輸入法例子的問題

微軟公佈的 TSF 輸入法例子的問題

在之前版本的歪林輸入法,其中一個問題就是當在某程式打字時,切換去另一個程式,歪林輸入法的視窗不會自動隱藏。

其原因是歪林輸入法是基於微軟的"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_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;
}
 

Windows SDK 的 TSF Case 有「框」的部分,而歪林輸入法和其他 TSF Sample code 就沒有。一加了上面的 code,歪林輸入法就可以在切換視窗時,自動隱蔽起來。

天啊!一耽誤就是半年!