SCIM架构的缺陷
在做输入法的过程中,手写输入法倒是出人意料的简单。相反,开始认为最简单的字母输入法,反而给我们出了难题。SCIM的架构毫无疑问是优良的,只是移植到手机平台上,外界条件变化太大,导致一些问题无法处理。不管怎么说,我认为这仍然是SCIM的一个缺陷。
所谓的字母输入法就是在手机上输入字母,手机键盘比较特殊,通常几个字母放在一个按键上。比如,数字2键上同时有abc三个键,输入时,该键按一下输入a,连按两下输入b,连按三下输入c,如此循环。
在SCIM中,所有传统(除手写和语音外)输入法,如拼音和五笔,都称为输入法Engine。所有输入法Engine都要实现IMEngineInstanceBase接口。这些Engine可以通过panel来切换。Engine不在应用程序进程中运行,也不在panel进程中运行,而是在scim服务进程中运行的。
scim服务进程是一个标准的服务器,客户端通过socket,以请求/响应的方式与服务器进行通信。输入法独立成一个进程,这是SCIM的一大优点,让多个应用程序共享输入法数据,可以节省资源。同时SCIM和应用程序是独立的进程,有利于提高系统的稳定性。
但是这种请求/响应的服务方式,有一个重要的限制,那就是服务器无法主动向客户端push数据。在大多数情况下,或者说在PC上的所有情况下,这种方式都工作得很好。偏偏在我们的字母输入法中遇到了麻烦:字母输入法要求在超时主动提交输入的字母,比如按一下数字键2时,向编辑器先提交字母a,a处于preedit状态,此时再按一下数字2时,用字母b代替字母a,不断的按该键,abc三个字母不断循环切换,直到有一小段时间内没有按了,输入法认为超时了,才把当前字母正式提交给编辑器。
麻烦在于两点:
首先,在SCIM服务器中很难实现定时器。原因是SCIM服务进程是通过select直接挂在socket上的,而不能像glib的mainloop那样可以挂在多个数据源(source)上。当然我们可以通过一个线程来实现定时功能,但是SCIM服务器假想它是以单进程运行的,所有对象没有同步保护,在定时线程中提交输入字母,势必引起资源竞争问题。
其次,既使前面的问题可以解决,SCIM中的Engine仍然无法主动提交数据。SCIM的框架假想它工作在请求/响应模式下,很多条件检查时都禁止这种情况发生,简单的去掉这些限制,可能会引起其它潜在的问题。
目前还没有想到好的办法,除非对SCIM的架构做调整,否则让字母输入法当作Engine来实现是比较困难的。要实现这个功能倒是不难,比如可以在GTK+的输入法插件中做特殊处理,只是感觉这样做有背于SCIM的一贯精神。究竟用什么方法好呢,还在考虑之中,望各位高手指迷津。
~~end~~