实现CEGUI中文汉字输入法光标跟随(C/C++源码)
来源:互联网 发布:山东大学网络教育 编辑:程序博客网 时间:2024/06/05 14:59
作者:庄晓立(liigo)
日期:2011年7月20日
原创链接:http://blog.csdn.net/liigo/article/details/6621104
转载请注明出处:http://blog.csdn.net/liigo
最新0.7.5版本的CEGUI是直接支持中文输入的,只要正常设置中文字体就行了。不过也仅限于“支持”、“够用”而已,有不足之处:在窗口模式(非全屏)下,汉字输入提示框显示在窗口左下角,不支持光标跟随功能,使用不方便;在全屏模式下,更是连汉字输入提示框都不显示了,只能盲打输入汉字。本文主要解决CEGUI中文汉字输入法“光标跟随”功能中最核心的地方,获取CEGUI编辑框(Editbox, MultiLineEditbox)中当前光标(Caret)的屏幕坐标。
目前CEGUI0.7.5自身并不支持返回光标位置。两年前有人在CEGUI官方论坛提问如何得到编辑框光标位置,CEGUI老大CrazyEddie亲自回复给出了详细的办法,不过他的办法只是针对“多行编辑框MultiLineEditbox”(对单行编辑框Editbox无效),而且没有考虑多行编辑框有纵向滚动条的情况。
我(liigo)的解决方案是在研究和修改CEGUI源代码之后得到的。
先说多行编辑框MultiLineEditbox的情况吧,相对简单点。思路就是CrazyEddie老大的思路:通过光标序号索引(MultiLineEditbox::getCaratIndex())得到光标所在行号(MultiLineEditbox::getLineNumberFromIndex),然后想办法得到最顶行的行号,两行号之差乘以行高(getFont()->getLineSpacing()),得纵向高度值Y;根据各文本行信息(MultiLineEditbox::getFormattedLines()),得到光标所在行中光标之前的文本,计算其横向宽度值X;多行编辑框左上角的屏幕坐标很容易取得,加上前面的X、Y值,就得到了光标的屏幕坐标。其中,“取最顶行行号”的办法是我(liigo)从CEGUI源码里翻出来的代码:
//取第一个可见行索引, 代码来自 FalagardMultiLineEditbox::cacheTextLines()int topLineNo = static_cast<size_t>(pMultiLine->getVertScrollbar()->getScrollPosition() / pMultiLine->getFont()->getLineSpacing());
下面是多行编辑框(CEGUI::MultiLineEditbox)取光标位置的核心代码:
if(activeWindow->testClassName("MultiLineEditbox")){CEGUI::MultiLineEditbox* pMultiLine = static_cast<CEGUI::MultiLineEditbox*>(activeWindow);CEGUI::Rect textRenderArea = CEGUI::CoordConverter::windowToScreen(*pMultiLine, pMultiLine->getTextRenderArea());x = textRenderArea.d_left;y = textRenderArea.d_top;int lineNo = pMultiLine->getLineNumberFromIndex(pMultiLine->getCaratIndex());int topLineNo = static_cast<size_t>(pMultiLine->getVertScrollbar()->getScrollPosition() / pMultiLine->getFont()->getLineSpacing()); //取第一个可见行索引, 代码来自 FalagardMultiLineEditbox::cacheTextLines()y += (lineNo - topLineNo) * (pMultiLine->getFont()->getLineSpacing());const CEGUI::MultiLineEditbox::LineList& lineList = pMultiLine->getFormattedLines();CEGUI::String lineBeforeCaret = pMultiLine->getTextVisual().substr(lineList[lineNo].d_startIdx, pMultiLine->getCaratIndex() - lineList[lineNo].d_startIdx);x += pMultiLine->getFont()->getTextExtent(lineBeforeCaret);}
由于多行编辑框的滚动条是以像素为单位滚动,而不是以行为单位滚动,所以上面的代码计算出的纵坐标y会有一些偏差,但最多偏差一行文本的高度,问题应该不大。如果要想完美解决,恐怕还得修改CEGUI源码才行。
下面是单行编辑框(CEGUI::Editbox)取光标位置的核心代码:
if(activeWindow->testClassName("Editbox")){CEGUI::Editbox * pEditbox = static_cast<CEGUI::Editbox*>(activeWindow);CEGUI::String textBeforeCaret;if(pEditbox->isTextMasked())textBeforeCaret = CEGUI::String(pEditbox->getCaratIndex(), pEditbox->getMaskCodePoint());elsetextBeforeCaret = pEditbox->getTextVisual().substr(0, pEditbox->getCaratIndex());CEGUI::Rect screenArea = CEGUI::CoordConverter::windowToScreen(*pEditbox->getParent(), pEditbox->getArea());//下面这个判断用于临时绕过CoordConverter::windowToScreen的一个BUG//详见: http://www.cegui.org.uk/phpBB2/viewtopic.php?f=10&t=5728if(pEditbox->getParent()->testClassName("FrameWindow")){CEGUI::FrameWindow* pFrame = (CEGUI::FrameWindow*) pEditbox->getParent();screenArea.offset(CEGUI::Point(8, 35)); //横向加上FrameWindow边框宽度,纵向加上FrameWindow标题栏的高度}x = screenArea.d_left;x += pEditbox->getFont()->getTextExtent(textBeforeCaret);x += pEditbox->getTextOffset(); //需修改CEGUI源码y = screenArea.d_top;y += (screenArea.getHeight() - pEditbox->getFont()->getFontHeight()) / 2; //文字垂直居中显示}
需要修改CEGUI源码之处,说明如下:
/*//Need modify CEGUI's source code://CEGUIEditbox.h, class EditboxWindowRenderer, add a virtua method, //and overrides it in FalEditbox.h, class FalagardEditbox: // float getTextOffset() const { return d_lastTextOffset; }//and add the same name method to class CEGUI::Editbox, just like Editbox::getTextIndexFromPosition()需修改CEGUI源码文件CEGUIEditbox.h里面:class EditboxWindowRenderer加一个虚函数: virtual float getTextOffset() const = 0;class Editbox加一个成员函数定义: float getTextOffset() const;文件FalEditbox.h里面:class FalagardEditbox加一个函数: virtual float getTextOffset() const override { return d_lastTextOffset; }文件CEGUIEditbox.cpp:float Editbox::getTextOffset() const{ if (d_windowRenderer != 0) { EditboxWindowRenderer* wr = (EditboxWindowRenderer*)d_windowRenderer; return wr->getTextOffset(); } else { CEGUI_THROW(InvalidRequestException("Editbox::getTextOffset: " "This function must be implemented by the window renderer")); }}*/
前面代码中出现的变量 activeWindow,是getGUISheet()->getActiveChild()返回的当前激活的控件。但是还要考虑特殊情况,在鼠标点击多行编辑框(MultiEditbox)纵向滚动条的情况下,当前拥有焦点(focus)的仍是多行编辑框,光标(caret)也仍在多行编辑框内,可是,但是,可但是,activeWindow已经不是多行编辑框了,它成了滚动条控件或滚动条的子控件(视鼠标点击位置而定)。所以我们的代码要处理这种情况:
CEGUI::Window* activeWindow = CEGUI::System::getSingleton().getGUISheet()->getActiveChild();if(activeWindow == NULL) return FALSE;//处理activeWindow是多行编辑框的滚动条控件,或滚动条子控件的情况if(activeWindow->testClassName("Scrollbar")){activeWindow = activeWindow->getParent();}else{//Thumb or PushButton of ScrollbarCEGUI::Window* parentWindow = activeWindow->getParent();if(parentWindow && parentWindow->testClassName("Scrollbar"))activeWindow = parentWindow->getParent();}if(activeWindow == NULL) return FALSE;
好了,有了光标的屏幕坐标,再把编辑框内文字的高度(getFont()->getFontHeight())考虑进去,定位输入法提示框是没什么难度了。至于输入法提示框内要显示的内容(输入码、候选字词),则超出了本文范畴,那属于IME编程领域,网上有很多公开的资料可供参考。
还有其它一些额外内容,我(liigo)也简单提一提,只盼对读者有用。
//注册"窗口创建"事件处理函数CEGUI::WindowManager::getSingleton().subscribeEvent(CEGUI::WindowManager::EventWindowCreated, _internal_OnCreateWindow);//处理编辑框创建事件, 注册其"焦点得失"事件处理函数static bool _internal_OnCreateWindow(const CEGUI::EventArgs& args){const CEGUI::WindowEventArgs& winEventArgs = static_cast<const CEGUI::WindowEventArgs&>(args);//对于编辑框(Editbox,MultiLineEditbox),注册焦点得失事件处理函数,以便关联输入法if(winEventArgs.window->testClassName("Editbox") || winEventArgs.window->testClassName("MultiLineEditbox")){winEventArgs.window->subscribeEvent(CEGUI::Window::EventActivated, _internal_OnEditboxSetFocus);winEventArgs.window->subscribeEvent(CEGUI::Window::EventDeactivated, _internal_OnEditboxKillFocus);}return true;}
全文完。谢谢。liigo 2011/7/20 夜,于大连。
- 实现CEGUI中文汉字输入法光标跟随(C/C++源码)
- linux中文输入法,ibus光标不跟随
- 图片跟随光标的网页实现
- ubuntu 10.10 google拼音输入法 实现光标跟随
- Reiiden制作笔记C(OGRE/CEGUI配置)
- sublime 中文乱码,输入法光标不跟随的使用问题
- NetBeans 中文输入法词语候选区不跟随光标
- 好烦啊,IDEA输入中文时输入法候选词框不跟随光标
- Android studio 中搜狗输入法 中文提示不跟随光标
- 跟随c++primer学c++(十一、十二章)
- CEGUI自定义光标
- CentOS安装中文汉字输入法ibus
- CentOS安装中文汉字输入法ibus
- CentOS安装中文汉字输入法ibus
- CentOS安装中文汉字输入法ibus
- [C++]Vector源码实现
- 使用消息钩子实现CEGUI中文输入
- 实现CEGUI的中文显示和输入
- C#操作配置文件
- 使用dtree方式创建树形结构
- Android网络开发详解
- 清华为何比不上美国二流大学
- Bind 配置非递归服务器
- 实现CEGUI中文汉字输入法光标跟随(C/C++源码)
- cookie与session
- winCE嵌入式开发学习(一)--winCE简介
- [黑马 笔记 整理]
- linux中的 测用时函数
- OCP 042、043、047最新题库+考试模拟器免费共享(命中率>99%)
- 目前游戏行业内部主要几款游戏引擎的技术对比
- 动态组装sql(解决where1=1低效的方案)
- #pragma once 与 #ifndef 一个利用文件检查,一个利用宏检查