zoukankan      html  css  js  c++  java
  • 基于visual c++之windows核心编程代码分析(61)打造自己的Windows输入法

    IMM(Input Method Manager)只在安装了亚洲语言包之后才能使用。

    通过调用GetSystemMetrics(SM_IMMENABLED)知道IMM是否使能。

    一共由三部分组成:

    status window  输入法状态栏   表示正在处于中文输入状态可以知道是什么输入法

    composition window 当你开始输入字母的时候,显示字母

    candidates window  紧靠在composition window下面,指示可能的字符组合(就是中文备选)

    最终中文通过WM_IME_CHAR消息发送到对应的程序。

    IME Window Class是系统预定义的窗口类。一般用于IME-aware程序定制输入法只用。

    当一个窗口激活时,操作系统发送WM_IME_SETCONTEXT到程序。如果是IME-unaware程序,程序会把它传递给

    DefWindowProc函数,然后由其发送给缺省的输入法。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

    下面我们来实现一个输入法框架

    #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;    // 当输入法退出时是否卸载客户DLL  0-是,1-否
    DWORD LoadNextWhenActive=1;    // 当本输入法激活时,是否自动打开下一个输入法 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);    // 输入法退出时卸载客户DLL
    		  }
            break;
          default:
            break;
        }
    	return true;
    }
    
    
    
    
    //************************************************************
    //	基本输入法窗口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标准输入法扩展服务 V1.0  ","关于输入法扩展",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)
    {
    	// 输入法初始化过程
        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);  // 注意该输入法基本窗口类必须注册,否则输入法不能正常运行
    
        return TRUE;
    }
    
    /*
    系统调用这个接口来判断IME是否处理当前键盘输入
    HIMC hIMC:输入上下文
    UINT uKey:键值
    LPARAM lKeyData: unknown
    CONST 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();   // 在切换输入法时判断是否需要加载客户DLL
    
        if (!hIMC) {
            return (FALSE);
        }
    	if (fSelect==TRUE && LoadNextWhenActive!=0)
    	{
    		//ActivateKeyboardLayout((HKL)HKL_NEXT,0);  // 不要在该接口中使用此函数切换到下一个输入法,否则函数返回时输入法又会切换回去
    		
    	}
        return TRUE;
    }
    
    
    /*
    使一个输入上下文激活或者失活,并通知输入法最新的输入上下文,可以在此做一些初始化工作
    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;
    }
    
    
    /*
    应用程序调用这个接口来进行输入上下文的转换,输入法程序在这个接口中转换用户的输入
    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;
    }
    
    
    //由应用程序发给输入法的消息,输入法可以在此响应用程序的请求
    //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()                                                        */
    /*                                                                    */
    /* 输入法界面窗口的窗口处理过程                                       */
    /*                                                                    */
    /**********************************************************************/
    
    //需导出函数
    LRESULT WINAPI UIWndProc(HWND hUIWnd,UINT message,WPARAM wParam,LPARAM lParam)
    {
        return 0;
    }
    //需导出函数
    LRESULT WINAPI StatusWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
    {
    	// 输入法状态条的窗口处理过程
    	return 0;
    }
    //需导出函数
    LRESULT WINAPI CompWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
    {
    	// 输入法显示候选字的窗口的的窗口处理过程
    	return 0;
    }
    //需导出函数
    LRESULT WINAPI CandWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
    {
    	// 输入法编码窗口的窗口处理过程
    	return 0;
    }
    


     

    我们如何安装输入法呢

    #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文件
    	ReleaseFile();
    	
    
    	//安装
    	HKL MyIME = ImmInstallIME(MyIMEFileName,MyLayoutText);
    	if (MyIME)
    	{
    		MessageBox(NULL,"安装成功","安装成功",MB_OK);
    	}
    	else
    	{
    		MessageBox(NULL,"安装失败","安装失败",MB_OK);
    	}
    	return 0;
    }


     

  • 相关阅读:
    游千佛塔有感
    时刻坚持高标准:成大事者的十条“箴言”
    谁愿意嫁给我这样的人
    成功的秘诀之一,就是敢于提出大设想、大思考
    寒冬里的暖阳
    世界最伟大的管理原则
    把你藏在心里
    登天门有感
    办公室保持最佳状态的诀窍
    “领悟”的价值是什么?思维能力训练问答
  • 原文地址:https://www.cnblogs.com/new0801/p/6177764.html
Copyright © 2011-2022 走看看