CEGUI中文输入的完美解决

EGUI中实现中文输入是一个老话题了,网上的资料也很多,但是实现的都不是那么完美,其中最重要的问题就是 输入法界面的跟随输入状态时对按键的屏蔽

先来说下如何把中文输入进入。
先添加一个中文注入的函数:
/////// 中文输入注入字符 (Added by Azure)
static bool ChnInjectChar(CEGUI::utf32 code_point);
///////
函数的实现如下:
bool Win32AppHelper::ChnInjectChar(CEGUI::utf32 code_point)
{
#ifndef UNICODE
   static char s_tempChar[3] = "";
   static wchar_t s_tempWchar[2] = L"";
   static bool s_flag = false;
   unsigned char uch = (unsigned char)code_point;
   if( uch >= 0xA1 )
   {
     if( !s_flag )
     {
       s_tempChar[0] = (char)uch; //第一个字节
       s_flag = true;
       return true;
     }
     else if( uch >= 0xA1 )
     {
       s_tempChar[1] = (char)uch; //第二个字节
       s_flag = false;
       MultiByteToWideChar( 0, 0, s_tempChar, 2, s_tempWchar, 1); //转成宽字节
       s_tempWchar[1] = L'\0';
       CEGUI::utf32 code = (CEGUI::utf32)s_tempWchar[0];
       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
}
此函数是我从网上抄来的一个,没有什么特别的,挺好用的。

然后在WndProc回调函数中添加:
case WM_CHAR:
// 不要这个
//CEGUI::System::getSingleton().injectChar((CEGUI::utf32)wParam);
// 改用自己的注入
ChnInjectChar((CEGUI::utf32)wParam);
break;
这样中文就可以基本输入了,但是还有很多问题,原来不能BackSpace删除,和游标移动啊!

下面我们来添加控制按键的处理。
由于wParam不能直接传入CEGUI中,我们必须写一个虚拟按键到扫描码的翻译函数,我们添加下面一个函数。
/////// 虚拟按键转扫描码 (Added by Azure)
static UINT VirtualKeyToScanCode(WPARAM wParam, LPARAM lParam);
该函数的实现为:
UINT Win32AppHelper::VirtualKeyToScanCode(WPARAM wParam, LPARAM lParam)
{
   if(HIWORD(lParam) & 0x0F00)
   {
     UINT scancode = MapVirtualKey(wParam, 0);
     return scancode | 0x80;
   }
   else
   {
     return HIWORD(lParam) & 0x00FF;
   }
}
同样的我们在WndProc消息回调中添加代码:
case WM_KEYDOWN:
{
//输入法跟随
IMEFollow(hWnd);
    
//输入法状态时,输入不传递到UI系统中去。
UINT vk = (UINT)ImmGetVirtualKey(hWnd);
if(vk == wParam)
   break;
      
CEGUI::System::getSingleton().injectKeyDown((CEGUI::utf32)( VirtualKeyToScanCode(wParam, lParam)));
}
break;

case WM_KEYUP:
CEGUI::System::getSingleton().injectKeyUp((CEGUI::utf32)( VirtualKeyToScanCode(wParam, lParam)));
break;
有两个陌生的函数,IMEFollow(hWnd) 和 ImmGetVirtualKey() 分别是为了输入法跟随,和过滤掉输入法处理过的按键,比较关键。

关于输入法跟随的函数体为:
/////// 获得输入框的坐标 (Added by Azure)
static bool getFocusedInputBoxCoord(POINT& point, float& height);

////// 输入法跟随 (Added by Azure)
static bool IMEFollow(HWND hWnd);
实现为:
bool Win32AppHelper::getFocusedInputBoxCoord(POINT& point, float& height)
{
   //寻找到有输入焦点的EditBox的左上坐标
   //遍历所有窗口
   CEGUI::WindowManager::WindowIterator wit = CEGUI::WindowManager::getSingleton().getIterator();
   while(!wit.isAtEnd())
   {
     const CEGUI::Window* widget = (*wit)->getActiveChild();
     //如果是EditBox或者MultiLineEditBox
     if(widget)
     {
       CEGUI::String windowType = widget->getType();
       if(windowType == "Vanilla/Editbox")                 //根据具体的scheme来修改。
       {
         const CEGUI::UVector2& winPos = widget->getPosition();
         height = widget->getPixelRect().getHeight();
          
         CEGUI::Vector2 winPos1 = CEGUI::CoordConverter::windowToScreen(*widget, winPos);

         point.x = winPos1.d_x;
         point.y = winPos1.d_y;
         return true;
       }
     }
     wit++;
   }

   return false;
}

bool Win32AppHelper::IMEFollow(HWND hWnd)
{
   //判断输入法是否打开
   if (!ImmIsIME(GetKeyboardLayout(0)))
     return false;
  
   //获得输入框左上坐标
   bool result;
   POINT point;
   float height;
   result = getFocusedInputBoxCoord(point, height);
   if(!result)
     return false;
  
   //获得客户区的坐标
   RECT rect;
   GetClientRect(hWnd, &rect);
   point.x+=rect.left;
   point.y+=rect.top;

   //设置输入法位置
   HIMC hImc = ImmGetContext(hWnd);
   if(hImc==NULL) return false;
   COMPOSITIONFORM form;
   ImmGetCompositionWindow(hImc, &form);
   form.ptCurrentPos.x = point.x;
   form.ptCurrentPos.y = point.y + height;
   ImmSetCompositionWindow(hImc, &form);

   return true;  
}
这样一来一个完整的CEGUI输入法解决方案就完成了。
相关参考代码如下:

点击下载

你可能感兴趣的:(GUI)