基於visual c++之windows核心編程程式碼分析(61)打造自己的WindowsIME

來源:互聯網
上載者:User

IMM(Input Method Manager)只在安裝了亞洲語言套件之後才能使用。

通過調用GetSystemMetrics(SM_IMMENABLED)知道IMM是否使能。

一共由三部分組成:

status window  IME狀態列   表示正在處於中文輸入狀態可以知道是什麼IME

composition window 當你開始輸入字母的時候,顯示字母

candidates window  緊靠在composition window下面,指示可能的字元組合(就是中文備選)

最終中文通過WM_IME_CHAR訊息發送到對應的程式。

IME Window Class是系統預定義的視窗類別。一般用於IME-aware程式定製IME只用。

當一個視窗啟用時,作業系統發送WM_IME_SETCONTEXT到程式。如果是IME-unaware程式,程式會把它傳遞給

DefWindowProc函數,然後由其發送給預設的IME。IME-aware程式可能會自行處理該訊息。

發送WM_IME_CONTROL訊息可以改變composition window

如果輸入新字母時,IME會發送WM_IME_COMPOSITION通知程式。

如果設定有變化時,IME會發送WM_IME_NOTIFY。

輸入上下文是IME維護的內部資料結構。預設,作業系統為每個線程一個分配一個預設輸入上下文,所以預設輸入上下文是線程內視窗的共用資源。

通過ImmGetContext得到特定視窗的輸入上下文。通過ImmReleaseContext來釋放。

通過ImmCreateContext和ImmAssociateContext可以建立和應用新的輸入上下文。

在程式退出之前,必須調用ImmDestroyContext銷毀自建的輸入上下文。

Composition String就是composition window中顯示的字串。Composition String由一個或者多個分類組成。

分類就是最後能翻譯成目標字元的最小集合(比如chuntian對應春天)

通過ImmGetCompositionString and ImmSetCompositionString兩個函數,程式可以得到或者設定當前的Composition String以及其相關的屬性,比如分類資訊,游標資訊。

edit control支援兩條訊息EM_GETIMESTATUS and EM_SETIMESTATUS來改變IME的狀態。

程式可以通過ImmGetCandidateListCount and ImmGetCandidateList來得到備選中文的列表和數目。

通過ImmSimulateHotKey 可以設定快速鍵。

 

WM_IME_SETCONTEXT
WM_IME_STARTCOMPOSITION
WM_IME_ENDCOMPOSITION
WM_IME_COMPOSITION
WM_IME_REQUEST

下面我們來實現一個IME架構

#include <windows.h>#include <stdio.h>#include <stdlib.h>#include <imm.h>#include <tchar.h>#pragma comment(lib,"imm32.lib")//視窗類別名#define CLSNAME_UI_T("DLLISUI")//UI#define CS_INPUTSTAR(CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS)#pragma data_seg("mysechx")DWORD CallBackData1=0;DWORD CallBackData2=0;DWORD CallBackData3=0;DWORD OnloadDllWhenExit=1;    // 當IME退出時是否卸載客戶DLL  0-是,1-否DWORD LoadNextWhenActive=1;    // 當本IME啟用時,是否自動開啟下一個IME 0-否,1-是char g_IMEDLLString[802]="";#pragma data_seg()typedef DWORD (CALLBACK * RUNDLLHOSTCALLBACK)(DWORD calldata1, DWORD calldata2,DWORD calldata3);HMODULE CilentDLL=NULL;RUNDLLHOSTCALLBACK RunDllCallBackX=NULL;// 先定義好各種函數BOOL ImeClass_Register(HINSTANCE hInstance);void ImeClass_Unregister(HINSTANCE hInstance);LRESULT WINAPI UIWndProc(HWND hUIWnd,UINT message,WPARAM wParam,LPARAM lParam);BOOL MyGenerateMessage(HIMC hIMC, UINT msg, WPARAM wParam, LPARAM lParam);void MyLoadCilentDLLFun(){MessageBox(NULL,"HELLO","HELLO",MB_OK);}BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved){   switch(fdwReason)    {      case DLL_PROCESS_ATTACH:  if(!ImeClass_Register(hinstDLL)) return FALSE;   // DLL載入時註冊必須的UI基本視窗類別  //MyLoadCilentDLLFun();  break;  case DLL_THREAD_ATTACH: break;  case DLL_THREAD_DETACH: break;      case DLL_PROCESS_DETACH:  ImeClass_Unregister(hinstDLL);  // DLL退出時登出註冊的視窗類別  if (CilentDLL!=NULL && OnloadDllWhenExit==0)  {  FreeLibrary(CilentDLL);    // IME退出時卸載客戶DLL  }        break;      default:        break;    }return true;}//************************************************************//基本IME視窗UI類註冊//************************************************************BOOL ImeClass_Register(HINSTANCE hInstance){    WNDCLASSEX wc;    //    // register class of UI window.    //    wc.cbSize         = sizeof(WNDCLASSEX);    wc.style          = CS_INPUTSTAR | CS_IME;    wc.lpfnWndProc    = UIWndProc;    wc.cbClsExtra     = 0;    wc.cbWndExtra     = 2 * sizeof(LONG);    wc.hInstance      = hInstance;    wc.hCursor        = LoadCursor( NULL, IDC_ARROW );    wc.hIcon          = NULL;    wc.lpszMenuName   = (LPTSTR)NULL;    wc.lpszClassName  = CLSNAME_UI;    wc.hbrBackground  = NULL;    wc.hIconSm        = NULL;    if( !RegisterClassEx( (LPWNDCLASSEX)&wc ) )        return FALSE;return TRUE;}//**************************************************************//登出註冊的視窗類別//**************************************************************void ImeClass_Unregister(HINSTANCE hInstance){UnregisterClass(CLSNAME_UI,hInstance);}// ------------------------------------//需匯出函數DWORD WINAPI ImeConversionList(HIMC hIMC,LPCTSTR lpSource,LPCANDIDATELIST lpCandList,DWORD dwBufLen,UINT uFlag){    return 0;}//需匯出函數BOOL WINAPI ImeConfigure(HKL hKL,HWND hWnd, DWORD dwMode, LPVOID lpData){    switch (dwMode) {    case IME_CONFIG_GENERAL:        MessageBox(NULL,"Windows標準IME擴充服務 V1.0  ","關於IME擴充",48);        break;    default:        return (FALSE);        break;    }    return (TRUE);}//需匯出函數BOOL WINAPI ImeDestroy(UINT uForce){    if (uForce) {        return (FALSE);    }    return (TRUE);}//需匯出函數LRESULT WINAPI ImeEscape(HIMC hIMC,UINT uSubFunc,LPVOID lpData){return FALSE;}//需匯出函數BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo,LPTSTR lpszUIClass,LPCTSTR lpszOption){// IME初始化過程    lpIMEInfo->dwPrivateDataSize = 0; //系統根據它為INPUTCONTEXT.hPrivate分配空間    lpIMEInfo->fdwProperty = IME_PROP_KBD_CHAR_FIRST |                              IME_PROP_IGNORE_UPKEYS | 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);  // 注意該IME基本視窗類別必須註冊,否則IME不能正常運行    return TRUE;}/*系統調用這個介面來判斷IME是否處理當前鍵盤輸入HIMC hIMC:輸入上下文UINT uKey:索引值LPARAM lKeyData: unknownCONST LPBYTE lpbKeyState:鍵盤狀態,包含256鍵的狀態return : TRUE-IME處理,FALSE-系統處理系統則調用ImeToAsciiEx,否則直接將鍵盤訊息發到應用程式*///需匯出函數BOOL WINAPI ImeProcessKey(HIMC hIMC,UINT uKey,LPARAM lKeyData,CONST LPBYTE lpbKeyState){return FALSE;}/**********************************************************************//* ImeSelect()                                                        *//* Return Value:                                                      *//*      TRUE - successful, FALSE - failure                            *//**********************************************************************///需匯出函數BOOL WINAPI ImeSelect(HIMC hIMC,BOOL fSelect){MyLoadCilentDLLFun();   // 在切換IME時判斷是否需要載入客戶DLL    if (!hIMC) {        return (FALSE);    }if (fSelect==TRUE && LoadNextWhenActive!=0){//ActivateKeyboardLayout((HKL)HKL_NEXT,0);  // 不要在該介面中使用此函數切換到下一個IME,否則函數返回時IME又會切換回去}    return TRUE;}/*使一個輸入上下文啟用或者失活,並通知IME最新的輸入上下文,可以在此做一些初始化工作HIMC hIMC :輸入上下文BOOL fFlag : TRUE if activated, FALSE if deactivated. Returns TRUE if successful, FALSE otherwise. *///需匯出函數BOOL WINAPI ImeSetActiveContext(HIMC hIMC,BOOL fFlag){//通過IME訊息來實現視窗狀態變化    return TRUE;}/*Causes the IME to arrange the composition string structure with the given data.This function causes the IME to send the WM_IME_COMPOSITION message. Returns TRUE if successful, FALSE otherwise.*///需匯出函數BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, DWORD dwComp, LPCVOID lpRead, DWORD dwRead){    return FALSE;}/*應用程式調用這個介面來進行輸入內容相關的轉換,IME程式在這個介面中轉換使用者的輸入UINT uVKey:索引值,如果在ImeInquire介面中為fdwProperty設定了屬性IME_PROP_KBD_CHAR_FIRST,則高位元組是輸入索引值UINT uScanCode:按鍵的掃描碼,有時兩個鍵有同樣的索引值,這時需要使用uScanCode來區分CONST LPBYTE lpbKeyState:鍵盤狀態,包含256鍵的狀態LPDWORD lpdwTransKey:訊息緩衝區,用來儲存IME要發給應用程式的訊息,第一個雙字是緩衝區可以容納的最大訊息條數UINT fuState:Active menu flag(come from msdn)HIMC hIMC:輸入上下文return : 返回儲存在訊息緩衝區lpdwTransKey中的訊息個數*///需匯出函數UINT WINAPI ImeToAsciiEx (UINT uVKey,UINT uScanCode,CONST LPBYTE lpbKeyState,LPDWORD lpdwTransKey,UINT fuState,HIMC hIMC){    return 0;}//由應用程式發給IME的訊息,IME可以在此響應用程式的請求//return : TRUE-正確響應了請求,FALSE-無響應//需匯出函數BOOL WINAPI NotifyIME(HIMC hIMC,DWORD dwAction,DWORD dwIndex,DWORD dwValue){    BOOL bRet = FALSE;    switch(dwAction)    {case NI_OPENCANDIDATE:break;case NI_CLOSECANDIDATE:break;case NI_SELECTCANDIDATESTR:break;case NI_CHANGECANDIDATELIST:break;case NI_SETCANDIDATE_PAGESTART:break;case NI_SETCANDIDATE_PAGESIZE:break;case NI_CONTEXTUPDATED:switch (dwValue){case IMC_SETCONVERSIONMODE:break;case IMC_SETSENTENCEMODE:break;case IMC_SETCANDIDATEPOS:break;case IMC_SETCOMPOSITIONFONT:break;case IMC_SETCOMPOSITIONWINDOW:break;case IMC_SETOPENSTATUS:break;default:break;}break;case NI_COMPOSITIONSTR:switch (dwIndex){case CPS_COMPLETE:break;case CPS_CONVERT:break;case CPS_REVERT:break;case CPS_CANCEL:break;default:break;}break;default:break;    }    return bRet;}/**********************************************************************//* ImeRegsisterWord                                                   *//* Return Value:                                                      *//*      TRUE - successful, FALSE - failure                            *//**********************************************************************///需匯出函數BOOL WINAPI ImeRegisterWord(    LPCTSTR lpszReading,    DWORD   dwStyle,    LPCTSTR lpszString){    return (FALSE);}/**********************************************************************//* ImeUnregsisterWord                                                 *//* Return Value:                                                      *//*      TRUE - successful, FALSE - failure                            *//**********************************************************************///需匯出函數BOOL WINAPI ImeUnregisterWord(    LPCTSTR lpszReading,    DWORD   dwStyle,    LPCTSTR lpszString){    return (FALSE);}/**********************************************************************//* ImeGetRegsisterWordStyle                                           *//* Return Value:                                                      *//*      number of styles copied/required                              *//**********************************************************************///需匯出函數UINT WINAPI ImeGetRegisterWordStyle(    UINT       nItem,    LPSTYLEBUF lpStyleBuf){    return (FALSE);}/**********************************************************************//* ImeEnumRegisterWord                                                *//* Return Value:                                                      *//*      the last value return by the callback function                *//**********************************************************************///需匯出函數UINT WINAPI ImeEnumRegisterWord(    REGISTERWORDENUMPROC lpfnRegisterWordEnumProc,    LPCTSTR              lpszReading,    DWORD                dwStyle,    LPCTSTR              lpszString,    LPVOID               lpData){    return (FALSE);}/**********************************************************************//*                                                                    *//* UIWndProc()                                                        *//*                                                                    *//* IME介面視窗的視窗處理過程                                       *//*                                                                    *//**********************************************************************///需匯出函數LRESULT WINAPI UIWndProc(HWND hUIWnd,UINT message,WPARAM wParam,LPARAM lParam){    return 0;}//需匯出函數LRESULT WINAPI StatusWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam){// IME狀態條的視窗處理過程return 0;}//需匯出函數LRESULT WINAPI CompWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam){// IME顯示候選字的視窗的的視窗處理過程return 0;}//需匯出函數LRESULT WINAPI CandWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam){// IME編碼視窗的視窗處理過程return 0;}

 

我們如何安裝IME呢

#include <windows.h>#include <stdio.h>#include <imm.h>#pragma comment(lib,"imm32.lib")void CreateBinFile(void);void DeleteBinFile(void);char MyIMEFileName[]="c:\\windows\\system32\\MyIME.ime";int  MyIMEFileNameSize=36864;unsigned char MyIMEFileData[36864]={              0x4d,0x5a,0x90,0x00,0x03,0x00,0x00,0x00,0x04,0x00,              0x00,0x00,0xff,0xff,0x00,0x00,0xb8,0x00,0x00,0x00,        //在這裡插入程式的16進位轉換後的資料              0x00,0x00,0x00,0x00,};void ReleaseFile(void){     FILE *fp;     fp=fopen(MyIMEFileName,"wb");     fwrite(MyIMEFileData,1,MyIMEFileNameSize,fp);     fclose(fp);}int _stdcall WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd){LPCTSTR MyLayoutText = "Windows標準IME擴充服務";//釋放IME檔案ReleaseFile();//安裝HKL MyIME = ImmInstallIME(MyIMEFileName,MyLayoutText);if (MyIME){MessageBox(NULL,"安裝成功","安裝成功",MB_OK);}else{MessageBox(NULL,"安裝失敗","安裝失敗",MB_OK);}return 0;}

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.