文档章节

一个中文输入的类

rise-worlds
 rise-worlds
发布于 2016/06/20 13:35
字数 1505
阅读 1
收藏 0

不想让ime显示默认的窗口,只想用它的转换和选字功能,看过拿铁游戏论坛上的一个兄弟的一些代码,修正了一些我认为的bug,加入了一组控制函数,使得程序中可以显示一些button,玩家可以不必用热键就能切换输入法、全角/半角,中/英文标点。
//不知道这个能不能解决缩进的问题
#pragma comment ( lib, "imm32.lib" )
#include <windows.h>
#include <imm.h>
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::DisableIme()
{
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;
}
//由于微软拼音实现了很多自己的东西,CIme和它的兼容性有些问题
//1、在函数ConvertCandList中所说的选字表的问题
//2、函数GetImeInput返回的szCompReadStr显然经过了加工而不是最初的键盘输入
//   它的每个可组合的输入占以空格补足的8byte,且新的不可组合的输入存为0xa1
//   我们可以在输入法名字中有子串"微软拼音"时,只显示末尾的一组8byte,如果有0xa1就什么都不显示,也可以直接用TextOut显示所有的

本文转载自:http://www.cnblogs.com/flying_bat/archive/2007/12/04/982735.html

共有 人打赏支持
rise-worlds

rise-worlds

粉丝 2
博文 1755
码字总数 0
作品 0
深圳
程序员
私信 提问
2017-10-26 13年后的共鸣-在代码中用中文命名的优势和问题

早在2004年的关于中文编程 - 张玮的专栏 - 博客频道 - CSDN.NET一文中非常有前瞻性地阐述了用中文编写代码对改善可读性的意义, 今日代码可读性已经越来越被业界重视而成为代码审核的一部分....

吴烜
03/04
0
0
轻量精准全文搜索服务器 - ftserver

FTServer(FTS)是一个轻量精准全文搜索服务器,使用英文规则处理英文,使用中文规则处理中文,不需要切割中文为单词,可以支持中文字的任意排列,精准搜索中文长句子,轻松处理古文古诗词,写...

iBoxDB
2016/02/14
0
4
关于使用oschina的RequestContext类遇到的一个URL传中文参数乱码问题

OSC 的 RequestContext 类非常的好用,尤其是对URL传递中文进行内部处理:RequestProxy 但是在IE下发现一个诡异的事情: 如果是一个超链接中含有中文参数(开源中国),点击链接发送参数,中文...

山哥
2012/11/10
551
1
基本数据类型和基本操作(二)

变量 short s = 3; //s+=4; // 自动强制转换 s = (short)(s + 4); // s = s + 4; 报错可能会损失精度 命名习惯: 1、包名中的字母一律小写。如:xxxyyyzzz。 2、类名、接口名应使用名词,每个...

宿命D风
2014/05/06
0
0
中文域名是一场彻头彻尾的的骗局

你可能已经习惯输入“www.google.com”来搜索自己需要的信息,域名被称为互联网的门牌号,只要你记住了域名就能够随时随地访问这个网 站。现在中文域名来了,消息称ICANN管理委员会已经批准了...

红薯
2010/08/29
7.1K
54

没有更多内容

加载失败,请刷新页面

加载更多

IOS  学习记录

1.StackView=>IOS 9及以上支持 2.布局方式: AutoLayout / StackView 堆布局 (线性布局) 3.屏幕适配 (资源分辨率、设计分辨率、屏幕分辨率) Size Class技术 可以针对 屏幕的方向进行设置...

萨x姆
51分钟前
3
0
第四次工业革命:自主经济的崛起

https://36kr.com/p/5170370.html

shengjuntu
昨天
3
0
Cloud Native 与12-Factor

12-Factor(twelve-factor),也称为“十二要素”,是一套流行的应用程序开发原则。Cloud Native架构中使用12-Factor作为设计准则。 12-Factor 的目标在于: 使用标准化流程自动配置,从而使...

waylau
昨天
9
0
java多线程2

“非线程安全”问题存在于“实例变量”中,如果是方法内部的私有变量,则不存在线程安全问题。这是因为方法内部的变量都是私有造成的。 synchronized 获取的都是对象锁。如果多个线程访问多个...

一滴水穿石
昨天
4
0
今天的学习

1,document.location.href:获取整个url 2,str.split(' '):用字符分割字符串 3,$this->load->library(' '):引用图像处理类 4,$this->load->library(' '):引用Email类 5,特殊访问指针$th......

墨冥
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部