Squeekboard增加拼音输入法实践

我手头有一台PinePhone Pro手机,可以涮不少系统,我比较喜欢基于GTK的Phosh的桌面,不过它的虚拟键盘Squeekboard不支持中文拼音输入。好在自己也是开发者一个,Squeekboard是个开源项目,使用C和Rust混编。在买PinePhone Pro之前就已经研究了Rust一段时间,所以一开始我觉得自己应该可以魔改一番增加一个简单的拼音输入法的功能。一开始并不顺利,迟迟没有进展。后来我停滞了一段时间,最近马上要过年了。我又开始折腾这个项目了,或许是停滞了一段时间的缘故,这次的思路比上次的能清晰一些。开源项目最大的问题就是它只有代码,它是怎么运行的需要你自己去研究。最初我之所以没有进展或许还是过于分散了,忽略了第一性原则,就是Squeekboard实际是基于Gtk的项目,那么最基本的东西一定是基于Gtk提供的那些基本的东西。有了这个思路后,我这次的进展就比上次快多了,另外也借助于AI的帮助。

基本架构

如果一个应用的输入框被激活,那么就会显示Squeekboard。另外也可以通过桌面下面的常驻按钮点击也可以显示或者隐藏键盘,这个是通过DBus来控制。Squeekboard的显示我一开始以为在覆盖在应用的上层,但现在觉得更像是把一个手机界面分成了上下两部分,底下是键盘,具体如果显示的还需要进一步的研究。

Squeekboard其实是一个大控件,键盘的按钮主要是自定义的绘制,没有使用标准的按钮控件。通过一个统一的事件处理,判断点击了哪个区域的按钮。键盘的布局会通过配置文件,可以动态的更新。

程序是由C驱动的,绘制按钮等一些逻辑的部分则是通过Rust来实现的,所以Rust等于一个程序库一样,二者相互调用。

拼音功能的实现

Squeekboard支持了大部分的字母类型的输入法,但是汉字的话,目前是不支持的。汉字的难点在于它不是直接由字母组合而成,需要通过某种间接的方式产生汉字,比如拼音、五笔。记得大学时,那会计算机还没有那么普及,一开始老师要求的是五笔输入法,我当时还买了一本五笔的书籍,实际上那会平时在网吧都用的是拼音输入法,五笔完全是一开始为了应付考试,后来真的考试也不要求五笔,拼音也可以,五笔很快就忘了。因为这次开发的缘故,我又一次想到了五笔,因为那其实是一种从汉字结构拆分的输入法,所以你必须能知道自己要输入的那个字的结构。

回到拼音输入法,拼音输入法其实就是拼音与汉字的键值对,只不过一个拼音可能对应很多的字,有时一个字会有好几个发音。

不过一开始我并没有考虑太细,开始主要的经历花在界面上了,逻辑上有个大概的想法,关键是如何实现的问题。实现的基本逻辑就是拦截按键,不过一开始我把精力花在了其他的方面,比如一个按键按下后,是如何传个输入框的?Squeekboard使用了Wayland协议,Wayland其实支持两种输入协议,我一开始只关注了zwp_input_method_v2,这个更像组合,但是默认的字母输入并没有走这个协议,走的另外一个协议就是简单字母按键的对应。

汉字的输入实际上需要使用zwp_input_method_v2这个来提交,一开始我就是想着先在键盘的上方增加一个候选字的栏,我先实现用按钮点击提交看是否可以成功。虽然这个要求很简单,但是在一开始修改的时候话费了我很多的时间,虽然我那段时间也有写关于GTK的应用,但是那个主要是Rust绑定的,很少涉及用C来写GTK。但是Squeekboard最基础的部分就是用C写的,当时我还借助Chatgpt,但是那会的Chatgpt也老出错,很多代码并不能直接用,要不就是没有用对版本。Squeekboard使用的是GTK3,而最新的则是GTK4,其实我也是用的GTK4的Rust绑定。总之那会花了好多时间,一直无法给键盘的上方添加一个控件,这么简单的事,尽然如此的花费时间,现在回想起来,那会太过于依赖Chatgpt了,自己思考的少,所以很被动。当然现在据说有那种可以分析整个工程的AI,或许那个可能要好一些,不过我目前还没有用过,因为那个要花钱。单就把一些工程的局部代码给AI,这种方式觉得还是不够完美。而我自己会写编程,是可以思考的,但是放弃思考这是一种愚蠢的做法,是你的想法在驱动AI,而不是被AI驱动,这是我得到的最大教训。

于是增加拼音的功能就此搁置了好长一段时间,直到最近才重新开始。这次最大的特点就是主动性,另外就是从最基本的东西开始考虑,毕竟Squeekboard它是基于GTK的,所以很快就完成了给虚拟键盘上方增加一个候选字的栏。之后遇到的最大问题是,点击按钮后提交会报错,应用直接奔溃掉了,遇到这种问题时,当时有点头大。但冷静下来思考发现,肯定是哪里的问题,只要解决问题就行,不要陷入到一种什么也不做的境地。在AI的帮助下发现我因为安装了Fcitx5的缘故,zwp_input_method_v2一直没有被激活,所以才导致了强行提交后的奔溃问题。最后直接用killall -9 fcitx5关闭了Fcitx5后,就好了。

后面就是如何把虚拟键盘的按键与汉字对应起来,一开始我只是想把这个工作交给一个外部的库,最终选择了一个Rust的库,结果编译报错。后来我依旧从最基本的实现开始,本质上不就是输入拼音的组合与汉字的对照表吗?有了这个基本的思路后,我找到了一个文本的数据,然后读取后,直接在表了查找。就这样一个基本的拼音输入法的功能便实现了。

不过也有一些问题,比如中英文的切换,另外如果连续的敲击按键时,会出现严重的卡顿,这是因为有些对应的汉字很多,这样的话就会添加很多的按钮,这种效率感觉并不高,所以现在的拼音输入法,只能一个按键一个按键的敲击,得留出缓冲的时间。另外那个文本的数据里面汉字的排列没有按照常用字的顺序来排列,所以有些很常用的字可能在后面。

后续的改进

现在算是满足了基本的需求,不过这个输入法现在来看效率不高。一种是重新弄一个只有3500字的小型数据集,这样可能会效率高一些。另外可能需要新开一个线程来专门处理拼音的东西,这样也许可以解决连续敲击的卡顿问题。当然想要到达现在iOS这样流畅的输入法,最后获取需要采用开源的一些输入法引擎来专门处理拼音的问题。

总结

这个项目对我而言算是一个挑战吧,因为最初我买了PinePhone Pro后,想着用Rust来开发应用,一开始确实也是尝试的开发了一个类似Notes的应用,当时还尝试在交叉编译,不过库稍微变动一下就要改很多的东西。另外Notes的应用运行效率并不高,反而还会有偶发的卡顿,我一度尝试用Python的Gtk绑定开发了一个,感觉差不多,所以最初使用Rust来提高应用的运行速度的想法被否定。主要是Rust开发效率与Python相比太低了,所以一段时间我有点气馁,开发PinePhone Pro的应用的想法一度搁置。

后来我又尝试的了解关于相机的相关东西的研究,PinePhone Pro的相机不是在所有的系统都可用的,有些直接用不了,后来调试了好长一段时间最后勉强可用,但那个是基于命令行的,其实开发一个专用的应用才是后续可能要做的。另外还尝试了GPS的定位的研究,发现定位从在偏移,这个也是从命令行研究的,缺少一个应用。最后还有蓝牙的研究。

那些跟硬件有点关系,但是虚拟键盘则是纯软件的,这个项目一开始确实没有进展,让我很沮丧,怀疑我的Rust和C的研究,不过基本的功能完成后,算是对GTK一些东西有所涉猎。而PinePhone Pro 上如果想在Phosh下使用,那么C语言看来是逃不过了,和Rust的混编确实能提高效率。纯Rust应用虽然有可能,但是和C混编或许更自由一些。不过对于我而言能用C语言也是一种期许吧,毕竟我对C的投入其实还是蛮大的,买了好的的书籍。另外也曾尝试写过一些操作系统的雏形,不过那个的话是汇编语言与C的混编,不过整个现在回想起来一个操作系统不就是由一堆在上层的脚本语言之类的混合搭建而成吗?所以混编是常态,而单纯的依赖某个语言是不现实的。