打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
输入法编辑器(IME)-- 如何在DirectDraw下做中文输入 - Welcome to my blog -- Z...


#pragma comment ( lib, "imm32.lib" )
#include
#include
class CIme
{
    bool g_bIme; //ime允许标志
    char g_szCompStr[ MAX_PATH ]; //存储转换后的串
    char g_szCompReadStr[ MAX_PATH ];//存储输入的串
    char g_szCandList[ MAX_PATH ]; //存储整理成字符串选字表
    int g_nImeCursor; //存储转换后的串中的光标位置
    CANDIDATELIST *g_lpCandList; //存储标准的选字表
    char g_szImeName[ 64 ]; //存储输入法的名字
    bool g_bImeSharp; //全角标志
    bool g_bImeSymbol; //中文标点标志
    void ConvertCandList( CANDIDATELIST *pCandList, char *pszCandList ); //将选字表整理成串
public:
    CIme() : g_lpCandList( NULL )
    {
        DisableIme();
    }
    //通过DisableIme初始化一些数据
    ~CIme()
    {
        DisableIme();
        if( g_lpCandList )
        {
            GlobalFree( (HANDLE)g_lpCandList );
            g_lpCandList = NULL;
        }
    }
    //控制函数
    void DisableIme(); //关闭并禁止输入法,如ime已经打开则关闭,此后玩家不能用热键呼出ime
    void EnableIme(); //允许输入法,此后玩家可以用热键呼出ime
    void NextIme(); //切换到下一种输入法,必须EnableIme后才有效
    void SharpIme( HWND hWnd ); //切换全角/半角
    void SymbolIme( HWND hWnd );//切换中/英文标点
    //状态函数
    char* GetImeName(); //得到输入法名字,如果当前是英文则返回NULL
    bool IfImeSharp(); //是否全角
    bool IfImeSymbol(); //是否中文标点
    void GetImeInput( char **pszCompStr, char **pszCompReadStr, int *pnImeCursor, char **pszCandList );
    //得到输入法状态,四个指针任意可为NULL则此状态不回返回
    //在pszCompStr中返回转换后的串
    //在pszCompReadStr中返回键盘直接输入的串
    //在pnImeCursor中返回szCompStr的光标位置
    //在pszCandList中返回选字表,每项之间以\t分隔
    //必须在消息中调用的函数,如果返回是true,则窗口函数应直接返回0,否则应传递给DefWindowProc
    bool OnWM_INPUTLANGCHANGEREQUEST();
    bool OnWM_INPUTLANGCHANGE( HWND hWnd );
    bool OnWM_IME_SETCONTEXT()
    {
        return true;
    }
    bool OnWM_IME_STARTCOMPOSITION()
    {
        return true;
    }
    bool OnWM_IME_ENDCOMPOSITION()
    {
        return true;
    }
    bool OnWM_IME_NOTIFY( HWND hWnd, WPARAM wParam );
    bool OnWM_IME_COMPOSITION( HWND hWnd, LPARAM lParam );
};


void CIme:isableIme()
{
    while( ImmIsIME( GetKeyboardLayout( 0 )))
    ActivateKeyboardLayout(( HKL )HKL_NEXT, 0 );//如果ime打开通过循环切换到下一个关闭
    g_bIme = false;
    g_szCompStr[ 0 ] = 0;
    g_szCompReadStr[ 0 ] = 0;
    g_nImeCursor = 0;
    g_szImeName[ 0 ] = 0;
    g_szCandList[ 0 ] = 0;
}


void CIme::EnableIme()
{
    g_bIme = true;
}


void CIme::NextIme()
{
    if( !g_bIme )
    return;
    ActivateKeyboardLayout(( HKL )HKL_NEXT, 0 );
}


void CIme::SharpIme( HWND hWnd )
{
    ImmSimulateHotKey( hWnd, IME_CHOTKEY_SHAPE_TOGGLE );
}


void CIme::SymbolIme( HWND hWnd )
{
    ImmSimulateHotKey( hWnd, IME_CHOTKEY_SYMBOL_TOGGLE );
}


void CIme::ConvertCandList( CANDIDATELIST *pCandList, char *pszCandList ) //转换CandidateList到一个串,\t分隔每一项
{
    unsigned int i;
    if( pCandList->dwCount < pCandList->dwSelection )
    {
        pszCandList[ 0 ] = 0;
        return;
    }
    //待选字序号超出总数,微软拼音第二次到选字表最后一页后再按PageDown会出现这种情况,并且会退出选字状态,开始一个新的输入
    //但微软拼音自己的ime窗口可以解决这个问题,估计微软拼音实现了更多的接口,所以使用了这种不太标准的数据
    //我现在无法解决这个问题,而且实际使用中也很少遇到这种事,而且其它标准输入法不会引起这种bug
    //非标准输入法估计实现的接口比较少,所以应该也不会引起这种bug
    for( i = 0; ( i < pCandList->dwCount - pCandList->dwSelection )&&( i < pCandList->dwPageSize ); i++ )
    {
        *pszCandList++ = ( i % 10 != 9 )? i % 10 + ‘1‘ : ‘0‘;//每项对应的数字键
        *pszCandList++ = ‘.‘;//用‘.‘分隔
        strcpy( pszCandList, (char*)pCandList + pCandList->dwOffset[ pCandList->dwSelection + i ] );//每项实际的内容
        pszCandList += strlen( pszCandList );
        *pszCandList++ = ‘\t‘;//项之间以‘\t‘分隔
    }
    *( pszCandList - 1 )= 0;//串尾,并覆盖最后一个‘\t‘
}


bool CIme::OnWM_INPUTLANGCHANGEREQUEST()
{
    return !g_bIme;//如果禁止ime则返回false,此时窗口函数应返回0,否则DefWindowProc会打开输入法
}


bool CIme::OnWM_INPUTLANGCHANGE( HWND hWnd ) //ime改变
{
    HKL hKL = GetKeyboardLayout( 0 );
    if( ImmIsIME( hKL ))
    {
        HIMC hIMC = ImmGetContext( hWnd );
        ImmEscape( hKL, hIMC, IME_ESC_IME_NAME, g_szImeName );//取得新输入法名字
        DWORD dwConversion, dwSentence;
        ImmGetConversionStatus( hIMC, &dwConversion, &dwSentence );
        g_bImeSharp = ( dwConversion & IME_CMODE_FULLSHAPE )? true : false;//取得全角标志
        g_bImeSymbol = ( dwConversion & IME_CMODE_SYMBOL )? true : false;//取得中文标点标志
        ImmReleaseContext( hWnd, hIMC );
    }
    else//英文输入
    g_szImeName[ 0 ] = 0;
    return false;//总是返回false,因为需要窗口函数调用DefWindowProc继续处理
}


bool CIme::OnWM_IME_NOTIFY( HWND hWnd, WPARAM wParam )
{
    HIMC hIMC;
    DWORD dwSize;
    DWORD dwConversion, dwSentence;
    switch( wParam )
    {
    case IMN_SETCONVERSIONMODE:
        //全角/半角,中/英文标点改变
        hIMC = ImmGetContext( hWnd );
        ImmGetConversionStatus( hIMC, &dwConversion, &dwSentence );
        g_bImeSharp = ( dwConversion & IME_CMODE_FULLSHAPE )? true : false;
        g_bImeSymbol = ( dwConversion & IME_CMODE_SYMBOL )? true : false;
        ImmReleaseContext( hWnd, hIMC );
        break;
    case IMN_OPENCANDIDATE:
        //进入选字状态
    case IMN_CHANGECANDIDATE:
        //选字表翻页
        hIMC = ImmGetContext( hWnd );
        if( g_lpCandList )
        {
            GlobalFree( (HANDLE)g_lpCandList );
            g_lpCandList = NULL;
        }
        //释放以前的选字表
        if( dwSize = ImmGetCandidateList( hIMC, 0, NULL, 0 ))
        {
            g_lpCandList = (LPCANDIDATELIST)GlobalAlloc( GPTR, dwSize );
            if( g_lpCandList )
            ImmGetCandidateList( hIMC, 0, g_lpCandList, dwSize );
        }
        //得到新的选字表
        ImmReleaseContext( hWnd, hIMC );
        if( g_lpCandList )ConvertCandList( g_lpCandList, g_szCandList );//选字表整理成串
        break;
    case IMN_CLOSECANDIDATE:
        //关闭选字表
        if( g_lpCandList )
        {
            GlobalFree( (HANDLE)g_lpCandList );
            g_lpCandList = NULL;
        }
        //释放
        g_szCandList[ 0 ] = 0;
        break;
    }
    return true;//总是返回true,防止ime窗口打开
}


bool CIme::OnWM_IME_COMPOSITION( HWND hWnd, LPARAM lParam ) //输入改变
{
    HIMC hIMC;
    DWORD dwSize;
    hIMC = ImmGetContext( hWnd );
    if( lParam & GCS_COMPSTR )
    {
        dwSize = ImmGetCompositionString( hIMC, GCS_COMPSTR, (void*)g_szCompStr, sizeof( g_szCompStr ));
        g_szCompStr[ dwSize ] = 0;
    }
    //取得szCompStr
    if( lParam & GCS_COMPREADSTR )
    {
        dwSize = ImmGetCompositionString( hIMC, GCS_COMPREADSTR, (void*)g_szCompReadStr, sizeof( g_szCompReadStr ));
        g_szCompReadStr[ dwSize ] = 0;
    }
    //取得szCompReadStr
    if( lParam & GCS_CURSORPOS )
    {
        g_nImeCursor = 0xffff & ImmGetCompositionString( hIMC, GCS_CURSORPOS, NULL, 0 );
    }
    //取得nImeCursor
    if( lParam & GCS_RESULTSTR )
    {
        unsigned char str[ MAX_PATH ];
        dwSize = ImmGetCompositionString( hIMC, GCS_RESULTSTR, (void*)str, sizeof( str ));//取得汉字输入串
        str[ dwSize ] = 0;
        unsigned char *p = str;
        while( *p )PostMessage( hWnd, WM_CHAR, (WPARAM)(*p++), 1 );//转成WM_CHAR消息
    }
    ImmReleaseContext( hWnd, hIMC );
    return true;//总是返回true,防止ime窗口打开
}


char* CIme::GetImeName()
{
    return g_szImeName[ 0 ]? g_szImeName : NULL;
}


bool CIme::IfImeSharp() //是否全角
{
    return g_bImeSharp;
}


bool CIme::IfImeSymbol() //是否中文标点
{
    return g_bImeSymbol;
}


void CIme::GetImeInput( char **pszCompStr, char **pszCompReadStr, int *pnImeCursor, char **pszCandList )
{
    if( pszCompStr )
    *pszCompStr = g_szCompStr;
    if( pszCompReadStr )
    *pszCompReadStr = g_szCompReadStr;
    if( pnImeCursor )
    *pnImeCursor = g_nImeCursor;
    if( pszCandList )
    *pszCandList = g_szCandList;
}

 



Trackback: http://tb.donews.net/TrackBack.aspx?PostId=49345

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
delphi 输入法注入完整版
深入浅出Win32多线程程序设计之综合实例
wincc技巧大全
mciSendString的使用2
游戏引擎与游戏引擎开发入门
给msn messager装个钩子 - 笨笨历险记
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服