在QT4.X时代,QT自己提供了一个软键盘的例子,清晰明了,在tools/inputpannel,可以在这个基础上修改出各种软键盘。但需要注意的是,如果需要在模态窗口中使用软键盘,需要把按键窗口也设置成模态的。
在QT5.X时代,inputpanel使用的InputContext类已经不存在了,取而代之的是QPlatformInputContext,输入法变成了一个插件,可以自己编写这个插件,请看
这篇文章(需要翻墙),也可以用现成的输入法框架,例如
Maliit。今天这篇文章要写的是如何使用Maliit。
开始之前说点别的,Source Navigator又回归了!这真的是个好东西,不知道RedHat为什么要停止维护它。虽然现在已经是别人维护了,但好歹在linux下有个能和Source Insight差不多功能的东西了。
地址在这里,不过现在的维护者显然无力开发更多的功能,只是升级了tk和tcl,避免在编译过程中出现各种错误。用刚才这个地址提供的压缩包编译之后没有字体防锯齿功能,字看起来相当恶心。不过,还是有牛叉人士把它改了,
请看这里。git clone之后,git checkout origin/8.4这个branch,然后编译就行。
开始正题,先下载源码。可以在
这里下载,也可以用git从https://github.com/maliit/framework和
https://github.com/maliit/plugings下载,我用的是git,版本
17fdf8699c。
Maliit包括两部分,框架和插件,先编译框架,然后安装到目标板在本机上的开发用根文件系统,然后再编译插件,最后把框架和插件都安装到目标板文件系统。注意,前提是,你的目标板根文件系统系统DBus支持、对QT有合适的图形后端支持、还有合适的窗口管理器,这些可以参照我之前的
这个文章和
这个文章来做。
编译framework:
cd [framework代码目录]
qmake CONFIG+=qt5-inputcontext CONFIG+=nodoc CONFIG+=notest
make
make INSTALL_ROOT=[开发用根文件系统] install
上面的配置选项,qt5-inputcontext用来编译我之前提到的QPlatformInputContext插件,nodoc指定不编译文档,notest不编译测试代码。
注意,[开发用根文件系统]是qt编译的时候指定的sysroot,包含各种头文件。
编译plugin,假设你的qmake在/QTSDK:
export QMAKEFEATURES=[开发用根文件系统
/QTSDK/mkspecs/features]
cd [plugin代码目录]
qmake CONFIG+=nodoc CONFIG+=notest CONFIG+=disable-preedit MALIIT_DEFAULT_PROFILE=[gnome3/nokia-n9/nokia-n9-droid/olpc-xo/ubuntu这几个任选一个] -r
make
上面的配置选项,disable-preedit指定禁用预编辑,MALIIT_DEFAULT_PROFILE指定键盘的style,style路径在plugin代码目录下maliit-keyboard/data/styles,以目录名区分。你可以参考已有的style,建立自己的style。
安装,假设目标板根文件系统中,QT插件的目录是/usr/plugins:
cd [framework代码目录]
make INSTALL_ROOT=[目标板根文件系统] install
cd [plugin代码目录]
make INSTALL_ROOT=[目标板根文件系统] install
mkdir [目标板根文件系统/usr/plugins/platforminputcontexts]
cp [framework代码目录]/input-context/libmaliitplatforminputco
ntextplugin.so [目标板根文件系统/usr/plugins/platforminputcontexts]
在目标板上测试、启用输入法(目标板终端里输入):
export QT_IM_MODULE=Maliit
maliit-exampleapp-plainqt
然后点击启动输入法服务器按钮,再把光标留在任意一个TextEdit里面,输入法就出来了,第一次加载有些慢。
maliit-exampleapp-plainqt的代码在[framework代码目录]/examples/app/plainqt,如果出现问题了,可以编译这个,然后调试。在/examples/app/plainqt/mainwindow.cpp里,也写出了输入法的调用方法,请看MainWindow::eventFilter。
需要注意的是,要在MainWindow::show()之后调用
windowHandle()->reportContentOrientation
Change(windowHandle()->screen()->primaryOrientation());
来修改默认键盘方向,否则会出现Segmentation Fault。
因为用的是开发版本,BUG比较多,一些可能会遇到的问题:(2014年3月7日更新)
- 警告提示
WARING: QSGContext::initialize: depth buffer support missing, expect rendering errorsWARING: QSGContext::initialize: stencil buffer support missing, expect rendering errors目前只能查到是QOpenGLContext中,depthbuffersize和stencilbuffersize的数值不对,原因不知道,暂时看来不影响使用。以后更新这部分。
- 默认输入法语言是阿拉伯语
QT通过系统环境变量LANG来识别语言,这个环境变量在 [framework代码目录/src/mimpluginmanager.cpp]中的MImOnScreenPlugins::autoDetectEnabledSubViews()函数,通过QStringList langs = QLocal::System().uiLanguages();这句来检测,如果没有LANG环境变量,langs会被设为"C",这个函数的调用者MImOnScreenPlugins::autoDetectActiveSubView()会选择[目标板根文件系统/Maliit安装目录/share/maliit/plugins/languages]里面,按字幕序的第一个文件作为默认的键盘布局。 解决方法可以是:export LANG=en_US.UTF-8别看这个问题解决方法这么简单,我看了一天代码才发现原因,真郁闷。
- 软键盘太宽
因为maliit-keyboard插件的所有style里,键盘设定的宽度都>=854,所以横向分辨率小于这个数值的屏幕,显示会有一些不正常。解决方法是修改你选择的style目录下的main.ini,比如我的屏幕是800*600的:[default]landscape\key-area-width=800...landscape\key-width=70
- 按键放大镜乱跑
还没找到原因,因为我的屏幕大,不需要这东西,所以把按键放大镜屏蔽了,注释掉[plugin代码目录/maliit-keyboard/plugin/inputmethod.cpp],InputMethod::show里面最后一行:
//d->magnifier_surface->show();
以后更新这部分。
- 屏幕出现不明黑块
这些黑块是初始化不正确的按键放大镜或者扩展输入面板,所谓扩展输入面板,就是你长按一个按键(比如"e")的时候弹出来的那个选择框。我觉得初始化不正确的原因可能是QT Widget获取焦点过于频繁。解决方法是把按键放大镜和扩展输入面板初始化到屏幕外面去,在[plugin代码目录/maliit-keyboard/plugin/inputmethod.cpp]的InputMethod::show()中,d->surface->setGeometry(...);这一句下面增加:
d->extended_surface->setGeometry(QRect(QPoint(rect.width(), rect.y()), QSize(1, 1)));
d->magnifier_surface->setGeometry(QRect(QPoint(rect.width(), rect.y()), QSize(1, 1)));
- 在弹出扩展输入面板的时候的切换焦点或隐藏软键盘,之后再调出软键盘无法工作
这是因为扩展输入面板的机制没有复位,在[plugin代码目录/maliit-keyboard/plugin/inputmethod.cpp]的InputMethod::show()中,d->surface->show();前面增加:
d->extended_layout.updater.resetOnKeyboardClosed();
[plugin代码目录/maliit-keyboard/plugin/inputmethod.cpp]的InputMethod::hide()中,d->layout.updater.resetOnKeyboardClosed();后面增加:d->extended_layout.updater.resetOnKeyboardClosed();
- 长按弹出扩展面板之后,抬起按键时输入按键的字符
本来按出扩展面板就是要选择扩展字符,出来一个不想要的按键字符真恶心,这是maliit-keyboard插件的bug。解决方法很简单,在EventHandlderPrivate里面加一个标志位,初始化清除, EventHandlder:: onPressed清除, EventHandlder::onPressAndHold事件的时候置位, EventHandlder:: onPressed事件末尾判断一下,如果已置位就不触发EventHandlder::keyReleased信号。这个改得地方太多,用文章末尾我贴的补丁吧。
- 用鼠标操作软键盘,鼠标移动到空格和退格键上时,就出现连击输入
不知道什么原因,Maliit要设置移动到按键上和按下按键两个连击机制,把移动到按键上的连击定时器触发代码关掉就行。在[plugin代码目录/maliit-keyboard/lib/logic/abstracttexteditor.cpp],AbstractTextEditor::onKeyEntered中,注释掉d->auto_repeat.timer.start(d->auto_repeat.delay);
- 长按删除键,输入出现混乱;在使用软键盘时,物理键盘无法使用
第一个问题的原因是,在[plugin代码目录/maliit-keyboard/lib/logic/abstracttexteditor.cpp],AbstractTextEditor::onCursorPositionChanged中,设计了自动获取当前光标位置的词语并提供联想的功能。但是,由于目标板的CPU速度可能不够快,而且输入法服务器和用户程序是两个进程,在连续按删除键时,进入这个函数时的光标位置和这个函数处理完提交预编辑字串时候的光标位置会不同,于是就会出现预编辑字串位置错误,引起输入混乱。我不知道怎么解决,只好先把这个函数的信号槽连接屏蔽掉,在[plugin代码目录/maliit-keyboard/plugin/inputmethod.cpp],InputMethodPrivate::connectToNotifier中,注释掉
QObject::connect(¬ifier, SIGNAL(cursorPositionChanged(int, QString)), ...
这一句。同时,这样做也可以解决在使用软键盘时,物理键盘无法使用的问题。
- 在预编辑显示的时候切换焦点,预编辑内容会在下一次按键时被带到新焦点widget
这是因为在切换焦点的时候没有清除预编辑,简单的做法可以在[plugin代码目录/maliit-keyboard/plugin/inputmethod.cpp]的InputMethod::show()中,d->surface->show();前面增加:setPreedit("", 0);
- 中文输入法
貌似需要写一定的代码,还在研究。
以后更新这部分。
- 输入法会覆盖输入区
这个问题的解决改的地方太多, 用文章末尾我贴的补丁吧。我用的是Maliit框架内建的机制,传输当前光标位置,但是maliit-keyboard里面却没有使用这个机制;另一个问题是,Qt的DBus支持有些问题,传输“a{sv}”类型,似乎这个v只能是基本数据类型,不能是QRect这样的复杂类型,所以我把这段改掉了,直接传输光标的坐标(int)而不是光标的形状(QRect)。为方便大家开发,光标位置从应用程序发送到插件的路径是:MInputContext::update > DBusServerConnection::updateWidgetInformation > ComMeegoInputmethodUiserver1Interface::updateWidgetInformation > (DBus传输,用XML文件描述,位于[framework代码目录]/dbus_interfaces/minputmethodserver1interface.xml) Uiserver1Adaptor::updateWidgetInformation > DBusInputContextConnection::updateWidgetInformation > MInputContextConnection::updateWidgetInformation >(MIMPluginManager::MIMPluginManager中做的信号槽连接)MIMPluginManager::handleWidgetStateChanged> InputMethod::update
有图有真相,最后贴张我的运行效果图,这个Style是我自己定义的,源码里没有。
我的修改补丁连接
在这里,这个补丁包含我上面所说的所有问题的解决方案。
FROM: http://blog.sina.com.cn/s/blog_70bb32080101rvu1.html