日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Win32 IME 编程心得【转】

發布時間:2024/3/13 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Win32 IME 编程心得【转】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一些術語

  • IME: Input Method Editor/Engine, 輸入法編輯器, 引擎
  • IMM: Input Method Manager, 輸入法管理器
  • Comp: Composition String, 一般是用戶輸入的字串, 比如拼音輸入香'字要打xiang', 這個`xiang'就是用戶輸入的Comp. 你可以告訴IMM當前的Comp是什么, 這樣如果應用能自己顯示Comp/Cands的話它就自己顯示; 你也可以不告訴IMM, 這樣你自己負責顯示就行了.
  • Cands: Candidates, 候選詞組
  • Commit: 提交上屏

其他一些軟鍵盤啊, GuideLine啊之類的對我的輸入法沒什么用, 我就全部無視了.

簡介

Win32下的輸入法編程概括地來說就是要寫一個DLL. 這個DLL要實現并在.def文件中指定輸出M$指定的一些API. Win32在裝載你的輸入法DLL時會檢查是不是每個API都能查詢到, 如果不是的話, 這個輸入法就不會被成功的裝載.

建議下載2600.1106版本的win32 DDK, 里面有區位輸入法的源程序, 我的影舞筆就是參考這個程序寫的. 可以看看里面的wingb.def文件, 總共輸出了將近20個API. 其實大部分都沒什么用, 直接套就行了, 重要的也就5~6個.

$cat wingb.def LIBRARY ? ? ? ? WINGBEXPORTSImeConversionListImeConfigureImeDestroyImeEscapeImeInquireImeProcessKeyImeSelectImeSetActiveContextImeSetCompositionStringImeToAsciiExNotifyIMEImeRegisterWordImeUnregisterWordImeGetRegisterWordStyleImeEnumRegisterWordUIWndProcStatusWndProcCompWndProcCandWndProc

事實上win32 DLL還有一個隱含的輸出函數, 就是DLL的入口函數, 一般都是名為DllMain的一個函數, 但是在區位輸入法里這個函數的名字是ImeDllInit. 你可以在你的makefile (或類似于vc6的.dsp/vc789的.vcproj等文件)里指定入口函數的名字.

初始化的大概的順序是:

  • DllMain里注冊窗口類
  • ImeInquire里告訴imm你的ime消息窗口的類名
  • imm根據這個類名創建你的ime消息窗口
  • 你的消息窗口的回調函數被調用, 消息是wm_create
  • 至此, 用戶就可以開始使用你的輸入法了, 這之后有意義的順序是大概這樣的:

  • 用戶按下一個鍵
  • ImeProcessKey返回true, 表示輸入法想處理這個鍵
  • ImeToAsciiEx被調用
  • 此函數創建一些ime消息, 如開始/結束輸入法編輯, 設置comp串, cand串, 顯示comp窗口, 顯示狀態欄窗口, 提交等
  • 相應的窗口被創建, 顯示,
  • 如果當前的應用程序是懂輸入法的, 它自己也會顯示comp串, 前提是你的ImeToAsciiEx需要告訴它comp串是什么, 如果你只想自己來顯示comp串的話, 那么這種程序是不會顯示的
  • 我為了自己編程方便, 就沒有通知應用程序自己去顯示comp和cands. 同時也是因為我覺得實在是沒有必要.

    DllMain

    這個函數肯定是最重要的, 一個DLL沒有這個入口函數的話就不是DLL了. 在DDK的區位輸入法代碼里有一個sources的文件, 里面有一行:

    DLLENTRY=ImeDllInit

    你如果用別的build系統, 比如Visual Studio或者mingw, 你就應該自己配置你的入口函數是哪個.

    這個函數在dll load的時候需要初始化你的輸入法里要用到的全局變量, 以及注冊win32的幾個窗口類. 在區位輸入法里注冊了四個窗口類, UI, Status, Comp, Cand. 其中UI窗口是一個純消息窗口, 也是win32 IME必須要求的一個窗口. 這個窗口的類名會在ImeInquire里傳給win32 IME以便讓win32 IME知道它應該去跟誰通訊. 我的影舞筆輸入法把Comp和Cand的窗口合并為一個了.

    如果這個函數返回false的話那這個DLL就會load失敗, 當前嘗試load你的輸入法的這個程序就沒法用你的輸入法了. 所以在這個函數里你可以干一些很``酷'' 的事情, 比如, 在測試階段, 你可以指定只有notepad才能成功load你的輸入法, 通過GetModuleFileName你可以得到當前調用的程序的路徑, 如果不是notepad, 那就不讓它用你的輸入法. 然后呢, 你在win32的控制面板→區域設置里指定你當前正在測試開發的輸入法為默認的輸入法, 這樣你一打開notepad, 就可以開始測試你的輸入法了, 而不需要按一下輸入法切換鍵才能開始測. 雖然只是省下按一個鍵, 但是也是值得的, 因為相信你會按很多次的. 而這時候其他的程序不會受影響, 你可以隨便殺死notepad.exe, 做下一輪的開發, 測試迭代.

    (win32下一個DLL被load了的話, 是不允許替換這個dll文件的. 所以當你發現一個bug, 做了修正, 你沒法把build出來的這個新的dll拷到系統路徑里, 必須先把所有的load了這個dll的程序殺死. 如果你的輸入法不是默認的, 那你每次都要按一下切換鍵才能開始測試; 如果它是默認的但是你不把除了notepad的其他程序排除的話, 你每次都要殺死很多程序, 比如explorer.exe等. 尤其是如果你只能手工一個一個的刪的話, 很快你會瘋掉的. 你甚至都不知道哪個程序load了你的輸入法. 只能一個一個的猜? 如果你知道sysinternal的process explorer的話, 那你還可以用一下它的查找功能).

    還有一個特別有用的功能是, 即使你的輸入法還有bug, 但是如果這個bug只是針對某個程序的話(或者說某個程序有bug, 但只針對你的輸入法:-), 你可以把這個程序排除在外. 比如, Cygwin下的X窗口程序都是由xwin.exe來畫窗口的, 這些窗口都不能處理win32的輸入法, 但是win32的輸入法切換鍵又能把輸入法的狀態欄給切出來, 很明顯沒什么意義, 我就把xwin.exe在我的輸入法里排除了. 又比如, 所有的DOS窗口的輸入法處理都是由一個叫conime.exe的程序處理的, 這個程序好像會對我的輸入法提很非分的要求, 我干脆就把它也拒之門外:-) 以后我就打定主意在終端窗口里再也不用輸入法了, 呵呵! (造成這個的原因是前面提到的conime是個`懂''輸入法的應用, 它太`懂''了, 它要求你必須設置comp串/cands告訴它知道, 你還不能自己顯示! 我懷疑這個應用的imm是不是壓根就不會幫你創建那個ime消息窗口. 一句話, 它太霸道了).

    做這樣的選擇, 我的生活會更簡單.

    ImeInquire

    這個函數是除了DllMain后第一個會被win32 IMM調用的函數. IMM通過調用這個函數知道你的輸入法有什么特性. 比如, 除了按鍵消息外, 你是不是還想處理鍵放開的消息. 以下是我的影舞筆的此函數代碼(注釋版)

    BOOL WINAPI ImeInquire(LPIMEINFO lpImeInfo, LPTSTR lpszWndCls, DWORD dwSystemInfoFlags) {if (!lpImeInfo) { //簡單出錯處理return FALSE;}lpImeInfo->dwPrivateDataSize = 0; //IMM會根據這個值自動為你的輸入法分配一塊內存, 你可以用它來保存一些你的context數據. 我嫌這玩意兒太"聰明"了, 不用之.lpImeInfo->fdwProperty = IME_PROP_KBD_CHAR_FIRST | IME_PROP_UNICODE | IME_PROP_IGNORE_UPKEYS | IME_PROP_SPECIAL_UI;// IME_PROP_KBD_CHAR_FIRST 是說IMM調用你的ImeProcessKey和ImeToAsciiEx函數之前是不是把按鍵消息的char值算出來, 在第一個整型參數的前兩個字節里傳給你, 其實你也可以自己算的// 如果你不設這個標志的話那第一個參數就只有低位的兩個字節有意義 (好像是所按的鍵的虛擬鍵值).// IME_PROP_UNICODE, 意義應該很明顯了, 一般肯定得設上// IME_PROP_IGNORE_UPKEYS, 就是上文說的要不要處理鍵放開的消息. 不設這個標志就是要處理, 設了就是不處理(IMM針對鍵放開的消息就不會來調你的ImeProcessKey和ImeToAsciiEx了).// IME_PROP_SPECIAL_UI, 不記得什么意思了, 可以上google查一下.lpImeInfo->fdwConversionCaps =IME_CMODE_NATIVE | IME_CMODE_NOCONVERSION;lpImeInfo->fdwSentenceCaps = 0;lpImeInfo->fdwUICaps = UI_CAP_ROT90;lpImeInfo->fdwSCSCaps = SCS_CAP_COMPSTR | SCS_CAP_MAKEREAD;lpImeInfo->fdwSelectCaps = (DWORD) 0;// 這之上的這段代碼是什么意思我也不明白, 但是這樣寫對我的影舞筆就夠用了, 所以我也懶得去弄明白.lstrcpy(lpszWndCls, get_ui_class_name().c_str());// 這里你要把你的UI窗口的類名拷到IMM傳給你的輸出參數里.return (TRUE);// 一定要返回true, 沒試過這里返回false會怎樣. }

    LPIMEINFO的定義可以在ddk的immdev.h里查到.

    ImeProcessKey

    win32 IMM在收到一個鍵盤消息之后, 會先問一下這個函數, 你的IME是不是想處理這個鍵, 如果你在這個函數里返回true, 意思就是你想處理, 那么imm就會接著調下一個函數ImeToAsciiEx, 否則它就會自己處理這個鍵盤消息.

    ImeToAsciiEx

    這個函數的返回值有點意思. 返回值應該是你這個函數的這次調用一共給win32產生的多少個消息. 比如用戶輸入了一個完整的五筆編碼, 希望提交他/她選中的候選詞了, 你就把要提交的數據(一個unicode字符串)寫到輸入法上下文的提交字串的內存句柄中, 再把 (WM_IME_COMPOSITION, 0, GCS_COMP|GCS_RESULT|GCS_RESULTREAD) 這樣一個消息添加到輸入法上下文的消息內存中, 把要返回多少個消息加一.

    以下是輸入法上下文結構的定義:

    typedef struct tagINPUTCONTEXT {HWND ? ? ? ? ? ? ? ?hWnd;BOOL ? ? ? ? ? ? ? ?fOpen;POINT ? ? ? ? ? ? ? ptStatusWndPos;POINT ? ? ? ? ? ? ? ptSoftKbdPos;DWORD ? ? ? ? ? ? ? fdwConversion;DWORD ? ? ? ? ? ? ? fdwSentence;union ? {LOGFONTA ? ? ? ?A;LOGFONTW ? ? ? ?W;} lfFont;COMPOSITIONFORM ? ? cfCompForm;CANDIDATEFORM ? ? ? cfCandForm[4];HIMCC ? ? ? ? ? ? ? hCompStr;HIMCC ? ? ? ? ? ? ? hCandInfo;HIMCC ? ? ? ? ? ? ? hGuideLine;HIMCC ? ? ? ? ? ? ? hPrivate;DWORD ? ? ? ? ? ? ? dwNumMsgBuf;HIMCC ? ? ? ? ? ? ? hMsgBuf;DWORD ? ? ? ? ? ? ? fdwInit;DWORD ? ? ? ? ? ? ? dwReserve[3]; } INPUTCONTEXT

    UIWndProc

    這個函數里要處理IME消息. 其實UI窗口根本沒有UI, 沒有圖形! 這個窗口是一個純消息窗口, 你不會收到wm_paint的消息. 所以我直接把區位輸入法里處理wm_paint的回調函數刪了. 我覺得把這個窗口命名為ImePureMsgWnd更合適一些.

    話說回來, 這個IME第一重要的窗口是誰創建的呢? 答案是IMM. 你在區位輸入法的代碼里不會看到這個窗口被CreateWindowEx. 在DllMain里你會注冊這個窗口的類, 在ImeInquire里你會把這個窗口的類名傳給IMM. 之后你就會收到這個窗口的創建消息了. 說明肯定是IMM負責創建了這個窗口.

    這個函數根據收到的消息要負責創建Comp, Status等窗口, 移動這些窗口的位置, 等等.

    CompWndProc 和 StatusWndProc

    這兩個窗口函數最重要的當然是負責畫窗口了.

    其他不怎么重要的API

    • ImeConfigure 這個函數就是按理你應該彈一個對話框給用戶配置你的輸入法的地方了, 像我們這種高級電腦用戶, 對這種功能直接無視.
    • ImeConversionList 這個函數是讓另一個輸入法來反查一個漢字在你的這個輸入法里是怎么打出來的. 比如區位輸入法可以指定用微軟拼音來反查一個漢字的拼音. 在區位輸入法的unicode模式下按`9999'';輸入香'', 輸入完后還會繼續顯示編輯窗, 內容是`xiang''. 這么無厘頭的功能, 無視!
    • ImeDestroy 沒什么好說的,
    • ImeEscape 也沒什么好說的, 沒什么鳥用. 以下是我的代碼:
    • ImeSelect Google出來的文檔是說在這個函數里初始化或析構你的私有數據, 好吧, 我前面已經說了, 我沒什么私有數據, 所以這個函數也可以簡化了.
    • ImeSetActiveContext
    • ImeRegisterWord
    • ImeUnregisterWord
    • ImeGetRegisterWordStyle
    • ImeEnumRegisterWord
    • ImeSetCompositionString
    • NotifyIME

    可以上這兒去看文檔. 這些函數都沒有什么用.

    一些注意事項

    win32輸入法編程的陷阱還是挺多的, 搞不好會很迷惑.

  • 一定要用版本管理工具(廢話), 但是用了版本管理工具還不一定夠, 在前期開發的時候, 要時不時地重啟一下機器, 有時候測著沒問題, 重啟一次就不行了. 如果改動量大的話就會不知道是哪個版本引進的問題.
  • ime消息窗口的類名不能隨便換. win32的IMM好像裝載過一次以后就會把你這個輸入法的各個窗口的類名給記下來, 你要是換了的話下次就裝載不上了, 必須重啟一次機器. 靠, 發現這個問題當時花了我很多時間.
  • 某種情況下winlogon.exe不能被排除在外. 如果你的輸入法開發的差不多了, 你把它設成默認的輸入法, 準備以后一直用它了, 嗯, 用的好好的, 一重啟, 嘿, 用不了了. 這是因為winlogon是你的第一個用戶, 而這個進程好像比較特別, 如果它load這個默認輸入法失敗的話, windows就會認為這個輸入法有問題. 所以你想把winlogon排除在外的話記得重啟前要把另一個輸入法換成默認的再重啟.
  • 出現以上兩個問題時你也可以不重啟, 只要把你的.dll換一個名字, 在注冊表里換一個注冊鍵.
  • 往注冊表里添的時候內容大概是這樣的: (E0330804的0804比較重要, 這代表這是中文輸入法, 更關鍵的是你的資源文件.rc里面也有0804, 如果這個不匹配的話這個ime也是load不了的. 前面的e033可以隨便換).

    Windows Registry Editor Version 5.00[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\E0330804] "Ime File"="ywb.dll" "Layout File"="kbdus.dll" "Layout Text"="Chinese (Simplified) - YWB"

    影舞筆的運行方法

    編譯用VS2008, 同時還要求安裝了python3.1, 安裝路徑必須是C:/python31, 同時你必須把代碼co到Q:\gcode\scim-cs下, 如果沒有Q:盤可以用subst.exe掛一個. 當然也可以自己改一下源代碼.



    原文:http://code.google.com/p/windows-config/wiki/Win32IME


    總結

    以上是生活随笔為你收集整理的Win32 IME 编程心得【转】的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 国产区二区| 哪里有毛片看 | 国产欧美一区二区三区在线看蜜臀 | 欧美精品在线一区二区 | 高潮毛片无遮挡免费看 | 女人夜夜春 | 男人的天堂色偷偷 | 妺妺窝人体色www婷婷 | 国产又粗又大又爽视频 | 国产女人叫床高潮大片免费 | 午夜久久久精品 | 天天爽夜夜爽夜夜爽精品视频 | 国产白丝袜美女久久久久 | 国精品一区二区三区 | 软萌小仙自慰喷白浆 | 理论片午午伦夜理片影院99 | 日韩av图片 | 亚洲成人网在线观看 | 色香影视 | 成人欧美一区二区三区 | 亚洲a精品 | 桃色激情网| 黄色网址中文字幕 | 日本老熟妇毛茸茸 | 西西午夜视频 | 五月婷视频 | 一级做a爰片 | 永久免费汤不热视频 | 国产凹凸一区二二区 | 欧美理论片在线观看 | 亚洲AV无码一区二区伊人久久 | 精品产国自在拍 | 午夜宅男影院 | 精品国产av一区二区三区 | 韩日精品中文字幕 | 免费性视频 | 伊人7| 日本成人一区 | 天天天天色 | 欧美一级免费大片 | 日韩毛片一区二区三区 | 中文字幕十一区 | 国产在线视频一区二区 | 青青操在线 | 91视频在线看 | 人妻av无码一区二区三区 | 国产又粗又猛又爽视频 | 久草资源在线播放 | 人妻精品久久久久中文字幕 | 欧美日韩电影一区二区三区 | 国产一区二区三区精品在线 | av免费观看在线 | 日韩电影在线观看一区 | 精品视频一区二区在线观看 | av大帝在线观看 | 欧美性视频网站 | 国产成人精品综合在线观看 | 日韩骚片 | 成人羞羞免费 | 蜜桃精品成人影片 | 欧美日韩亚洲成人 | 国产在线传媒 | 色狠av| 国产无人区码熟妇毛片多 | 亚州视频在线 | 日本公妇乱偷中文字幕 | av在线亚洲天堂 | 亚洲图片小说区 | 亚洲天天在线 | 国产精品视频一区二区三区不卡 | 欧美乱妇狂野欧美在线视频 | 青青草91久久久久久久久 | 久久婷婷伊人 | 黄色一级大片在线免费看国产 | 日韩在线第一区 | 美女黄色小视频 | 六月丁香综合网 | 黄色成人一级片 | 五月天久久久久久 | 天天搞天天| 亚洲成人中文字幕在线 | 亚洲一级色 | 亚洲字幕成人中文在线观看 | 亚洲色欧美| 欧美网| www.在线观看网站 | 久久久久无码国产精品不卡 | 日韩特级毛片 | 欧美色香蕉| 国产伦精品一区二区三区照片 | 欧美成年网站 | www成年人| 久久精品久久久精品美女 | 日韩亚洲欧美综合 | 亚洲一区二区在线电影 | 五月天丁香视频 | 欧美大色| 新婚之夜玷污岳丰满少妇在线观看 | 中文字幕人妻一区二 |