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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

VC++ 输入法编程

發(fā)布時(shí)間:2023/12/29 c/c++ 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 VC++ 输入法编程 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一直想寫一點(diǎn)關(guān)于輸入法編程的東西,今天終于有點(diǎn)時(shí)間,希望對(duì)后來(lái)者有點(diǎn)幫助。在此要特別感謝“自由拼音”的作者李振春,我剛開(kāi)始的幾個(gè)問(wèn)題都是在他的幫助下才解決。

首先我們需要明白輸入法是什么東西。目前常用的輸入法基本上有兩種類型:外掛式(如早期的萬(wàn)能五筆)及輸入法接口式(Input Method Editor-IME)。外掛式比較簡(jiǎn)單,就是一個(gè)exe文件,通過(guò)模擬一些Windows輸入消息來(lái)給當(dāng)前處于活動(dòng)狀態(tài)的編輯窗口輸入文字,一個(gè)顯著的優(yōu)點(diǎn)是輸入法只要啟動(dòng)一次,就可以在所有進(jìn)程中使用;但缺點(diǎn)不不容忽視,首先實(shí)現(xiàn)起來(lái)也不容易,一個(gè)更大的不足是兼容性不夠好,通常一個(gè)Windows版本需要一人對(duì)應(yīng)的輸入法版本,此外這類輸入法為了能夠截獲用戶輸入,通常需要掛接鍵盤鉤子,容易造成系統(tǒng)不穩(wěn)定或者效率不高。大部分的輸入法還是采用IME來(lái)實(shí)現(xiàn),下面本文主要討論一下IME編程需要注意的問(wèn)題及解決辦法。

IME是什么?IME是在Windows平臺(tái)上使用的標(biāo)準(zhǔn)的輸入法接口規(guī)范。它實(shí)質(zhì)是一個(gè)DLL,Windows為這個(gè)DLL定義一系列的接口,不同的接口實(shí)現(xiàn)指定的功能。程序員在編寫輸入法程序時(shí)只需要實(shí)現(xiàn)這些接口并導(dǎo)出就可以作為輸入法使用。關(guān)于具體接口的定義不是本文的重點(diǎn),如果您需要了解只需要在網(wǎng)絡(luò)中搜索“輸入法編程指南”就可以明白 ,更多信息參考MSDN。

剛開(kāi)始輸入法編程最棘手的問(wèn)題通常是程序框架搭好了卻不知道如何使用及調(diào)試。這里涉及到一個(gè)很重要的問(wèn)題就是輸入法的安裝。輸入法就是Windows的一個(gè)插件,需要先進(jìn)行注冊(cè),Windows才能識(shí)別并使用。為此您需要先將您生成的DLL復(fù)制到系統(tǒng)目錄(Windows\System32)再調(diào)用API ImmInstallIME就可以實(shí)現(xiàn)了,在我的實(shí)踐中是先編一個(gè)簡(jiǎn)單的程序來(lái)做安裝工作,在每次輸入法重新編譯完成以后調(diào)用一次以完成輸入法的注冊(cè)。這里還有一個(gè)需要注意的問(wèn)題是:Windows提供了一種機(jī)制,它允許輸入法程序一旦啟動(dòng)就就不再退出,這就意味著如果你的程序代碼經(jīng)過(guò)修改需要重新安裝時(shí)將不得不重新啟動(dòng)電腦。在IME定義的接口中有一個(gè)接口是提供IME的初始化的,它就是

  BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo,LPTSTR lpszUIClass,LPCTSTR lpszOption)

下面的代碼來(lái)自我寫的輸入法:

BOOL WINAPI ImeInquire(LPIMEINFOlpIMEInfo,LPTSTR lpszUIClass,LPCTSTR lpszOption){ lpIMEInfo->dwPrivateDataSize = sizeof(CONTEXTPRIV);//系統(tǒng)根據(jù)它為INPUTCONTEXT.hPrivate分配空間lpIMEInfo->fdwProperty = IME_PROP_KBD_CHAR_FIRST |#ifdef _UNICODEIME_PROP_UNICODE |#endif IME_PROP_SPECIAL_UI | IME_PROP_END_UNLOAD ;lpIMEInfo->fdwConversionCaps = IME_CMODE_FULLSHAPE |IME_CMODE_NATIVE;lpIMEInfo->fdwSentenceCaps = IME_SMODE_NONE;lpIMEInfo->fdwUICaps = UI_CAP_2700;lpIMEInfo->fdwSCSCaps = 0;lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION;_tcscpy(lpszUIClass,CLSNAME_UI);return TRUE; }

lpIMEInfo->fdwProperty告訴Windows系統(tǒng)您編寫的輸入法的一些特征,注意一下IME_PROP_END_UNLOAD這個(gè)標(biāo)志,有了它您編寫的輸入法會(huì)隨著啟動(dòng)您的輸入法的應(yīng)用程序(如NotePad)的退出而退出,否則它將長(zhǎng)駐于系統(tǒng)中,這也是為什么很多輸入法在升級(jí)安裝時(shí)需要首先重新啟動(dòng)電腦的原因。

在這個(gè)接口中還有一點(diǎn)需要特別注意,那就是lpIMEInfo->dwPrivateDataSize,至少我是經(jīng)過(guò)很多次測(cè)試才基本證實(shí)Windows根據(jù)該值為INPUTCONTEXT.hPrivate分配空間。此外如果您修改了這個(gè)接口,按照我個(gè)人的經(jīng)驗(yàn)是需要重新調(diào)用ImmInstallIME來(lái)安裝。

在安裝完成后,在輸入法列表中應(yīng)該已經(jīng)有了您自己的輸入法。點(diǎn)擊調(diào)試,由于它是一個(gè)DLL,您需要先選擇一個(gè)宿主程序,一般選擇“記事本”,以調(diào)試方式啟動(dòng)“記事本”后,在這個(gè)“記事本”中打開(kāi)您的輸入法,您就可以在源代碼中設(shè)置斷點(diǎn)了。需要說(shuō)明的是,VC6.0調(diào)試DLL不太好用,首先需要打上SP5或者SP6,這樣也不能夠在DLL啟動(dòng)的時(shí)候就設(shè)置斷點(diǎn),推薦使用.net來(lái)調(diào)試。

輸入法上下文(HIMC):HIMC是什么?在輸入法編程時(shí)必然要接觸到輸入法上下文這個(gè)術(shù)語(yǔ),剛接觸時(shí)聽(tīng)起來(lái)實(shí)在是半懂不懂。由于輸入法是一個(gè)插件,它需要和調(diào)用它的應(yīng)用程序通訊,在輸入法中生成的編碼及重碼信息保存在哪里應(yīng)用程序才能正確的讀取呢?答案就在于輸入法上下文。輸入法上下文是由User.exe(一個(gè)系統(tǒng)進(jìn)程)為應(yīng)用程序分配的內(nèi)存句柄,在應(yīng)用程序中啟動(dòng)的輸入法在這塊內(nèi)存中寫入數(shù)據(jù),User.exe再將數(shù)據(jù)傳遞到應(yīng)用程序。

UIWnd:在IME中需要導(dǎo)出一個(gè)接口,原型如LRESULT WINAPI UIWndProc(HWND hUIWnd, UINT message,WPARAM wParam, LPARAM lParam),hUIWnd是由User.exe傳過(guò)來(lái)的窗口句柄,它是輸入法中創(chuàng)建的窗口如編碼窗口,重碼窗口,狀態(tài)欄窗口的宿主(Owner),初學(xué)輸入法編程的人可能會(huì)問(wèn)這個(gè)窗口顯示在哪里呢?其實(shí)它并不是一個(gè)普通的窗口,它只是一個(gè)用來(lái)傳遞Windows消息的窗口(Message Only),在使用時(shí),您不需要關(guān)心它在哪里,只需要使用它就好了。

一個(gè)IME需要導(dǎo)出19個(gè)(Win98版本)接口,但是對(duì)于一個(gè)只需要實(shí)現(xiàn)一般意義的文字輸入的軟件,您只需要實(shí)現(xiàn)幾個(gè)基本的接口就可以讓輸入法正常工作了。下面逐一介紹一下這幾個(gè)接口。

/**********************************************************************/

/* ImeSelect() */

/* Return Value: */

/* TRUE - successful, FALSE - failure */

/**********************************************************************/

BOOL WINAPI ImeSelect(HIMC hIMC,BOOL fSelect)

在這個(gè)接口中,系統(tǒng)通知輸入法當(dāng)前是否打開(kāi)了輸入法輸入。一般輸入法啟動(dòng)時(shí)會(huì)調(diào)用一次,在一些軟件(如EmEditor)中提供打開(kāi)與關(guān)閉輸入法的功能就是通過(guò)這個(gè)接口實(shí)現(xiàn)的。如果打開(kāi)輸入法,一般會(huì)在這個(gè)接口中做一些數(shù)據(jù)的初始化工作。

/***********************************************************************/

/*系統(tǒng)調(diào)用這個(gè)接口來(lái)判斷IME是否處理當(dāng)前鍵盤輸入 */

/*HIMC hIMC:輸入上下文 */

/*UINT uKey:鍵值 */

/*LPARAM lKeyData: unknown */

/*CONST LPBYTE lpbKeyState:鍵盤狀態(tài),包含256鍵的狀態(tài) */

/*return : TRUE-IME處理,FALSE-系統(tǒng)處理 */

/*系統(tǒng)則調(diào)用ImeToAsciiEx,否則直接將鍵盤消息發(fā)到應(yīng)用程序 */

/**********************************************************************/

BOOL WINAPI ImeProcessKey(HIMC hIMC,UINT uKey,LPARAM lKeyData,CONST LPBYTE lpbKeyState)
復(fù)制代碼
觀察注釋您可以看到在個(gè)接口是用來(lái)判斷用戶敲擊的哪個(gè)鍵需要處理,哪個(gè)鍵又應(yīng)該交給系統(tǒng)自己處理,如果輸入法需要自己處理用戶輸入的鍵,則在這個(gè)接口中返回true,否則返回false。

/****************************************************************************************************************/

/* function:應(yīng)用程序調(diào)用這個(gè)接口來(lái)進(jìn)行輸入上下文的轉(zhuǎn)換,輸入法程序在這個(gè)接口中轉(zhuǎn)換用戶的輸入 */

/* UINT uVKey:鍵值,如果在ImeInquire接口中為fdwProperty設(shè)置了屬性IME_PROP_KBD_CHAR_FIRST,則高字節(jié)是輸入鍵值*/

/* UINT uScanCode:按鍵的掃描碼,有時(shí)兩個(gè)鍵有同樣的鍵值,這時(shí)需要使用uScanCode來(lái)區(qū)分 */

/* CONST LPBYTE lpbKeyState:鍵盤狀態(tài),包含256鍵的狀態(tài) */

/* LPDWORD lpdwTransKey:消息緩沖區(qū),用來(lái)保存IME要發(fā)給應(yīng)用程序的消息,第一個(gè)雙字是緩沖區(qū)可以容納的最大消息條數(shù) */

/* UINT fuState:Active menu flag(come from msdn) */

/* HIMC hIMC:輸入上下文 */

/* return : 返回保存在消息緩沖區(qū)lpdwTransKey中的消息個(gè)數(shù) */

/****************************************************************************************************************/

UINT WINAPI ImeToAsciiEx (UINT uVKey,UINT uScanCode,CONST LPBYTE lpbKeyState,LPDWORD lpdwTransKey,UINT fuState,HIMC hIMC)
復(fù)制代碼
這個(gè)接口可以說(shuō)是輸入法最重要的部分,程序員需要在這個(gè)接口中實(shí)現(xiàn)編碼與重碼的轉(zhuǎn)換,轉(zhuǎn)換完成或者顯示在編碼窗口及重碼窗口,或者發(fā)送到應(yīng)用程序。由于在這個(gè)接口中沒(méi)有傳入窗口句柄,如果通知輸入法程序的窗口更新顯示呢?當(dāng)然我們可以使用全局變量,在此我個(gè)人推薦的方法是使用IME消息(沒(méi)有什么道理),您將消息類型、參數(shù)保存到lpdwTransKey指示的緩沖區(qū)中,User.exe會(huì)根據(jù)消息類型做相應(yīng)的處理并傳遞到UIWnd這個(gè)窗口中。
那么如何輸入文字呢?要輸入文字需要3個(gè)消息配合使用,分別是WM_IME_STARTCOMPOSITION、WM_IME_COMPOSITION和WM_IME_ENDCOMPOSITION,它們分別指示開(kāi)始輸入編碼,輸入編碼或者結(jié)果(視參數(shù)而異)及編碼輸入完成。在開(kāi)始編寫輸入法的時(shí)候,為了省事,我的輸入法在用戶確定要輸入一個(gè)重碼時(shí)才連續(xù)調(diào)用這3個(gè)消息以向編碼器中輸入文字。由于WM_IME_STARTCOMPOSITION和WM_IME_ENDCOMPOSITION需要成對(duì)使用,這種方法可以確保它們配對(duì)。最初這種方式工作得很好,但是后來(lái)發(fā)現(xiàn)在一些軟件中出現(xiàn)兼容性問(wèn)題。如“智能五筆”在“遨游”中就存在這個(gè)問(wèn)題,在“遨游”中的地址欄中打開(kāi)“智能五筆”,當(dāng)需要使用回退鍵來(lái)刪除錯(cuò)誤輸入的編碼時(shí),會(huì)發(fā)現(xiàn)刪除的不是編碼窗口中的編碼而是編輯器中的文字。這是因?yàn)轭愃啤板塾巍边@類軟件主動(dòng)接管了按鍵輸入如處理一些控制鍵,當(dāng)它發(fā)現(xiàn)這些控制鍵不在WM_IME_STARTCOMPOSITION和WM_IME_ENDCOMPOSITION這兩個(gè)消息之間時(shí)就自己處理控制鍵而不是先交給User.exe了。因此正確的流程應(yīng)該是在開(kāi)始輸入編碼時(shí)發(fā)送WM_IME_STARTCOMPOSITION,輸入結(jié)束后發(fā)送WM_IME_ENDCOMPOSITION消息。

/**********************************************************************/

/* UIWndProc() */

/* IME UI window procedure */

/**********************************************************************/

LRESULT WINAPI UIWndProc(HWND hUIWnd, UINT message,WPARAM wParam, LPARAM lParam)
復(fù)制代碼
這是一個(gè)非常重要的接口,基本上一它負(fù)責(zé)各種消息的傳遞。一般您需要在這個(gè)接口中根據(jù)不同的消息類型,實(shí)現(xiàn)輸入法窗口(如編碼窗口、重碼窗口、狀態(tài)欄窗口)的顯示、隱藏及更新等操作。這個(gè)接口實(shí)現(xiàn)的功能可能非常復(fù)雜,視情況而異,在此就不做更加深入的說(shuō)明了。在使用時(shí)可以參見(jiàn)示例工程。

BOOL WINAPI ImeConfigure(HKL hKL,HWND hWnd, DWORD dwMode, LPVOID lpData)
復(fù)制代碼
這是最后一個(gè)需要注意的接口,在顯示輸入法屬性配置時(shí)會(huì)Windows會(huì)調(diào)用這個(gè)接口。

基本的接口就介紹到這里,下面談一談我個(gè)人在編寫輸入法程序時(shí)遇到的一些問(wèn)題或者發(fā)現(xiàn)的一些需要注意的地方。

1、關(guān)于輸入法窗口:閱讀一些輸入法的代碼會(huì)奇怪,為什么輸入法窗口在創(chuàng)建時(shí)需要指定WM_DISABLE屬性呢?原來(lái)是因?yàn)槿绻恢付ㄟ@個(gè)屬性標(biāo)志,在打開(kāi)輸入法時(shí),會(huì)導(dǎo)致當(dāng)前的應(yīng)用程序失去輸入焦點(diǎn)。但是指定了這個(gè)標(biāo)志后,輸入法窗口不能收到鼠標(biāo)消息怎么辦?解決的方法就在于WM_SETCURSOR這個(gè)消息。這個(gè)消息不管窗口是否可用,只要有鼠標(biāo)在窗口內(nèi)窗口都會(huì)收到。您可以在這個(gè)消息中模擬鼠標(biāo)消息也可以選擇調(diào)用SetCapture這個(gè)函數(shù),這樣窗口就可以收到鼠標(biāo)消息了。

2、關(guān)于窗口模式:使用了幾種輸入法后,你會(huì)發(fā)現(xiàn),有的輸入法的編碼窗口和重碼窗口是一個(gè)窗口,有的又是兩個(gè)窗口,它們有什么區(qū)別?或者有的人會(huì)覺(jué)得這個(gè)問(wèn)題很可笑,但是當(dāng)您研究了一段輸入法可能就會(huì)發(fā)現(xiàn)您也有類似的問(wèn)題:因?yàn)樵谳斎敕ǖ膶?dǎo)出接口中關(guān)于用戶界面的函數(shù)就有4個(gè),其它3個(gè)分類對(duì)應(yīng)3個(gè)窗口回調(diào)函數(shù)。事實(shí)上它們并沒(méi)有本質(zhì)的區(qū)別,關(guān)鍵在于您的輸入法的使用范圍。一些軟件(如某些游戲)為了界面的整體美觀,不希望用戶在打開(kāi)輸入法時(shí)顯示輸入法自己的窗口,而是希望輸入法按照它的意愿將輸入法窗口需要顯示的內(nèi)容顯示在它創(chuàng)建的窗口中,英文稱之為IME Aware。由于我自己的輸入法目標(biāo)不是在游戲中使用,所在并沒(méi)有按照這個(gè)規(guī)矩來(lái)管理輸入法窗口,而是為了簡(jiǎn)化,將編碼窗口和重碼窗口顯示的內(nèi)容放到了一個(gè)窗口中。

3、關(guān)于自定義消息:UIWndProc在WM_IME_NOTIFY中提供了一個(gè)IMN_PRIVATE,最初我理解為這個(gè)消息應(yīng)該和WM_USER一樣,當(dāng)我需要不只一人自定義消息時(shí)只需要在這個(gè)ID的基礎(chǔ)上增加值就好了。但事實(shí)是您定義的值可能是系統(tǒng)已經(jīng)占用的(視Windows的版本而異),您能夠使用的自定義消息應(yīng)該只有這一個(gè),為了指示多個(gè)消息類型,我使用的方法是在WM_IME_NOTIFY的LPARAM中進(jìn)行區(qū)分。

4、調(diào)試信息輸出:一般編寫輸入法都不會(huì)使用MFC,為了輸出調(diào)試信息,一般只能使用OutputDebugString這個(gè)API,在示例代碼中的helper.c中我編寫了一個(gè)模擬TRACE的函數(shù)Helper_Trace,您可以用這個(gè)函數(shù)來(lái)將調(diào)試信息輸出到調(diào)試窗口。

5、最后再談一談?shì)斎敕愋?#xff1a;前面提到輸入法分為外掛式和IME兩種,但是目前一些輸入法發(fā)展了第3種類型,那就是結(jié)合這兩種類型的優(yōu)點(diǎn)。例如拼音加加,啟動(dòng)拼音加加您會(huì)發(fā)現(xiàn)進(jìn)程列表里會(huì)多一個(gè)拼音加加的服務(wù)進(jìn)程,其實(shí)它才是拼音加加輸入法的內(nèi)核即數(shù)據(jù)處理部分。拼音加加的IME部分只是一個(gè)外殼,它提供傳統(tǒng)的IME輸入法一樣的系統(tǒng)兼容性。在我的輸入法中也采用了這種結(jié)構(gòu),使用內(nèi)存文件映射及普通的Windows消息結(jié)合來(lái)實(shí)現(xiàn)兩個(gè)進(jìn)程間的通訊。您可以在我的輸入法的源代碼中找到進(jìn)程間的通訊源代碼及輸入法代碼。

好象沒(méi)有更多的經(jīng)驗(yàn)可言,總之,輸入法其實(shí)并不神秘,在我看來(lái),只要能夠在VC中跟蹤代碼,我就不相信我會(huì)搞不定它!

一家之言,如果有什么錯(cuò)誤,還請(qǐng)大家批評(píng)指正。

關(guān)于示例代碼:示例代碼是我編寫的一個(gè)最基本的輸入法程序的框架,它顯示您輸入的編碼,并顯示一個(gè)固定的重碼,輸入空格后實(shí)現(xiàn)該重碼上屏的功能。通常我們能找到的代碼是一個(gè)完整的工程,這樣對(duì)于初學(xué)輸入法編程的人可能會(huì)陷入大量的非輸入法編碼框架的閱讀中,對(duì)于實(shí)際的輸入法編程并沒(méi)有多大的意義。這份代碼就是為了讓您擺脫那些無(wú)謂代碼的閱讀。


如果需要更加完整的輸入法代碼,推薦參考“自由拼音”的源代碼,當(dāng)然也可以參考我寫的輸入法《啟程輸入之星》的代碼,您可以在我的網(wǎng)站上找到下載,http://www.setoutsoft.cn。這份代碼的界面部分我自認(rèn)為是當(dāng)前的輸入法中寫得非常出色的。

?

轉(zhuǎn)載于:https://www.cnblogs.com/rogee/archive/2011/02/01/1948734.html

總結(jié)

以上是生活随笔為你收集整理的VC++ 输入法编程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。