注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

回首望星辰

See you in the next world

 
 
 

日志

 
 

CEGUI中文输入(windows)  

2010-02-04 10:18:55|  分类: 软件开发 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

一:中文显示,分两步走1)添加中文字体

                                  2)将layout转化为utf8保存(不转化好像不能显示,会出错)

二:中文输入,1)使用win32手动创建ogre窗体

                       2)case WM_CHAR: //j该消息处理
  if (ImmIsIME(GetKeyboardLayout(0)))//获取输入法开关,测试时好像打开后不会关闭
  {
   _injectChar((CEGUI::utf32)wParam);
  }
  else
   CEGUI::System::getSingleton().injectChar((CEGUI::utf32)wParam); 
  break; 
================================

//unicode转换处理,工程设置unicode的情况下即跳过处理

   bool _injectChar(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];
        //Font* fnt = System::getSingleton().getDefaultFont();
        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
   }

 ========================================

疑问:处理WM_IME_CHAR消息不成功,原因未知,以下转贴的方法还未测试

=========================================

先来说下如何把中文输入进入。
先添加一个中文注入的函数:

/////// 中文输入注入字符 (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输入法解决方案就完成了。
  评论这张
 
阅读(1611)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017