OSG中使用CEGUI时的中文输入问题的解决方法
在OSG中使用CEGUI时中文输入是比较麻烦的,必须自己建立Hook,经过了一天的研究终于弄出来了,在这里与大家分享一下#include <Imm.h>#include <stdio.h>
HHOOK Chinese_hHook = NULL;
HHOOK Input_hook = NULL;
void InitHook()
{
Input_hook = SetWindowsHookEx(WH_CALLWNDPROC ,IMM_GetMsgProc,GetModuleHandle( NULL ),GetCurrentThreadId());
Chinese_hHook = SetWindowsHookEx(WH_GETMESSAGE,ChineseCharHookProc,NULL,GetCurrentThreadId());
}
void ReleaseHook()
{
if(Input_hook && Chinese_hHook)
{
UnhookWindowsHookEx(Input_hook);
UnhookWindowsHookEx(Chinese_hHook);
}
}
LRESULT CALLBACK IMM_GetMsgProc( int nCode, WPARAM wParam, LPARAM lParam )
{
CWPSTRUCT* cw = (CWPSTRUCT*)lParam;
if (nCode < 0)
{
return CallNextHookEx(Input_hook, nCode, wParam, lParam);
}
HIMC hIMC;
HWND hWnd;
DWORD dwSize;
HGLOBAL hstr;
LPSTR lpstr;
if (nCode == HC_ACTION/*&& wParam != 0*/)
{
switch (cw->message)
{
case WM_IME_STARTCOMPOSITION:
{
CEGUI::Editbox * eb = (CEGUI::Editbox *)CEGUI::WindowManager::getSingleton().getWindow("IME/Composition");
eb->setVisible(true);
CEGUI::Editbox * win = (CEGUI::Editbox *)CEGUI::WindowManager::getSingleton().getWindow("Root/show");
win->setVisible(true);
//以上是现实输入法输入框
}
//可以自己建立一个CEGUI::EditBox来接收输入的数据
break;
case WM_IME_ENDCOMPOSITION:
{
CEGUI::Editbox * eb = (CEGUI::Editbox *)CEGUI::WindowManager::getSingleton().getWindow("IME/Composition");
eb->setVisible(false);
CEGUI::Editbox * win = (CEGUI::Editbox *)CEGUI::WindowManager::getSingleton().getWindow("Root/show");
win->setVisible(false);
//以上是隐藏输入法输入框
}
break;
case WM_IME_COMPOSITION:
{
//1.获得并设置输入框
//先获取当前正在输入的窗口的输入法句柄
HIMC hIMC = ImmGetContext(GetActiveWindow());
// 先将ImmGetCompositionString的获取长度设为0来获取字符串大小.
LONG dwSize = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, NULL, 0);
WCHAR * lpstr = new WCHAR;
// 再调用一次.ImmGetCompositionString获取字符串
ImmGetCompositionStringW(hIMC, GCS_COMPSTR , lpstr, dwSize);
lpstr = L'\0';
//int num = MultiByteToWideChar(CP_ACP, NULL, lpstr, dwSize, NULL, 0);
//WCHAR * pstr = new WCHAR;
//MultiByteToWideChar(CP_ACP, NULL, lpstr, dwSize, pstr, num);
//pstr = L'\0';
int utf8Num = WideCharToMultiByte(CP_UTF8, NULL, lpstr, dwSize, NULL, 0, NULL, NULL);
char * str = new char;
WideCharToMultiByte(CP_UTF8, NULL, lpstr, dwSize, str, utf8Num, NULL, NULL);
str = '\0';
CEGUI::String string((CEGUI::utf8*)str);
CEGUI::Editbox * eb = (CEGUI::Editbox *)CEGUI::WindowManager::getSingleton().getWindow("IME/Composition");
float weight = eb->getFont()->getTextExtent(string);//getTextExtent(string.data());
eb->setWidth(CEGUI::UDim(0.018f,weight));
eb->setText(string.data());
LONG cursorIndex = ImmGetCompositionStringW(hIMC, GCS_CURSORPOS, NULL, 0);
eb->setCaratIndex(cursorIndex);
//2.获得并设置候选框
CEGUI::Window * win = CEGUI::WindowManager::getSingleton().getWindow("Root/show");
LPCANDIDATELIST pList;
dwSize = ImmGetCandidateListA(hIMC,0,NULL,0);
pList = (LPCANDIDATELIST)GlobalAlloc( GPTR, dwSize);
ImmGetCandidateListA(hIMC,0,pList,dwSize);
//dwSize /= 2;
DWORD * dwOffset = &pList->dwOffset;
dwOffset += pList->dwPageStart;
char buf;
DWORD j = 0;
for (DWORD i=0;i<pList->dwCount;i++)
{
LPSTR s = (LPSTR)pList + *dwOffset++;
sprintf( buf + j,"%d.%s ",i+1,s);
j += strlen(s) + 3;
}
buf = '\0';
int num = MultiByteToWideChar(CP_ACP, NULL, buf, j + 1, NULL, 0);
WCHAR * pstr = new WCHAR;
MultiByteToWideChar(CP_ACP, NULL, buf, strlen(buf), pstr, num);
pstr = L'\0';
utf8Num = WideCharToMultiByte(CP_UTF8, NULL, pstr, wcslen(pstr), NULL, 0, NULL, NULL);
char * str2 = new char;
WideCharToMultiByte(CP_UTF8, NULL, pstr, wcslen(pstr), str2, utf8Num, NULL, NULL);
str2 = '\0';
CEGUI::String string2((CEGUI::utf8*)str2);
weight = win->getFont()->getTextExtent(string2);
win->setWidth(CEGUI::UDim(0.018f,weight));
win->setText(string2.data());
}
break;
}
}//if (nCode == HC_ACTION)
return 0;
}
LRESULT CALLBACK ChineseCharHookProc( int nCode, WPARAM wParam, LPARAM lParam )
{
if(nCode < 0)
return CallNextHookEx(Chinese_hHook,nCode,wParam,lParam);
// if(!ImmIsIME(GetKeyboardLayout(0)))
// return CallNextHookEx(g_hHook,nCode,wParam,lParam);
MSG* msg = (MSG*)lParam;
switch(msg->message)
{
case WM_CHAR:
{
switch(msg->wParam)
{
//输入状态下的特殊功能键位处理
case VK_RETURN:
{
CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::Return);
break;
}
case VK_TAB:
{
CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::Tab);
break;
}
case VK_BACK:
{
CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::Backspace);
break;
}
case VK_SPACE:
{
CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::Space);
CEGUI::System::getSingleton().injectChar((CEGUI::utf32)msg->wParam);
break;
}
default:
{
//IMMFollow();//窗口跟随,暂时还没有实现
ChnInjectChar((CEGUI::utf32)msg->wParam);
return true;
}
break;
}
}
}
return CallNextHookEx(Chinese_hHook,nCode,wParam,lParam);
}
bool ChnInjectChar( CEGUI::utf32 code_point )
{
#ifndef UNICODE
static char s_tempChar = "";
static wchar_t s_tempWchar = L"";
static bool s_flag = false;
unsigned char uch = (unsigned char)code_point;
if( uch >= 0x80 )
{
if( !s_flag )
{
s_tempChar = (char)uch; //第二个字节
s_flag = true;
return true;
}
else if( uch >= 0x80 )
{
s_tempChar = (char)uch; //第一个字节
s_flag = false;
MultiByteToWideChar( 0, 0, s_tempChar, 2, s_tempWchar, 1); //转成宽字节
s_tempWchar = L'\0';
CEGUI::utf32 code = (CEGUI::utf32)s_tempWchar;
return CEGUI::System::getSingleton().injectChar( code );
}
else
{
return CEGUI::System::getSingleton().injectChar(code_point);
}
}
else
{
s_flag = false;
return CEGUI::System::getSingleton().injectChar(code_point);
}
#else
return CEGUI::System::getSingleton().injectChar(code_point );
#endif
} Very cool~~ 非常棒的分享啊 感谢 楼主 分享:lol 感谢 楼主 分享:lol 感谢 楼主 分享:lol 请问一下怎么切换到中文输入法呢。在osg的窗口中,按下Ctrl+Shift没有反应,输入法的窗口都没有。 回复 8# zzq11105229
您开始打字,窗口中就会有显示了,只要切换输入法成功。 回复 9# liuzhiyu123
谢谢,现在就是不能成功切换输入法,
在窗口里面只能输入英文字符呀,不能切换到汉字输入法。
是不是要添加些什么代码,让输入法认为这个窗口是可输入的?
一般的osg程序,也是不能切换输入法的,它没有可输入的地方,而记事本程序就可以,它们有什么不同啊? 谢谢,问题解决了。可以切换输入法,只是消息处理不及时,看起来就没反应了。 呵呵,楼主好强大啊,你研究的东西我现在也正在弄,像ODE做碰撞检测,cegui做界面。我用cegui做个树状的界面用来显示节点,也用到了中文显示,自己摸索了半天。单独的界面是可以了但与OSG结合就有点问题了。 :lol 马克一下!好东西,不过现在有些地方还看不懂!继续学习 太好了真心有用只是我想问问 MultiEditBox这个如何显示中文呢 动态显示 在代码里用setText(字符串)该如何显示呢?字符串是未知大小的 从数据库里读取 亲 Imm.h需要什么库啊?我在控制台下有这个错误 error LNK2019: 无法解析的外部符号 _ImmGetCandidateListA@16,该符号在函数 "long __stdcall IMM_GetMsgProc(int,unsigned int,long)" (?IMM_GetMsgProc@@YGJHIJ@Z) 中被引用
1>main.obj : error LNK2019: 无法解析的外部符号 _ImmGetCompositionStringW@16,该符号在函数 "long __stdcall IMM_GetMsgProc(int,unsigned int,long)" (?IMM_GetMsgProc@@YGJHIJ@Z) 中被引用
1>main.obj : error LNK2019: 无法解析的外部符号 _ImmGetContext@4,该符号在函数 "long __stdcall IMM_GetMsgProc(int,unsigned int,long)" (?IMM_GetMsgProc@@YGJHIJ@Z) 中被引用 已经找到 谢谢 #pragma comment(lib,"imm32.lib") w910916 发表于 2013-5-17 16:15 static/image/common/back.gif
亲 Imm.h需要什么库啊?我在控制台下有这个错误 error LNK2019: 无法解析的外部符号 _ImmGetCandidateListA ...
输入法的接口 imm32.lib 亲 您这完善了么?有很多bug 由于没有用过输入法的这个库 :'( w910916 发表于 2013-5-18 21:42 static/image/common/back.gif
亲 您这完善了么?有很多bug
bug 可以自己解决这个只是一个解决方案 w910916 发表于 2013-5-18 21:43 static/image/common/back.gif
由于没有用过输入法的这个库
输入法 编程 网上的资料很多 您可以自己查找
页:
[1]