查看原文
其他

linux输入法概述

什么是输入系统


引用Wikipedia给输入系统来个定义:


输入系统,也就是俗称的输入法(Input Method,简称IM)用于计算机操作系统,将外部输入设备信号转换为系统可识别的字符。主要外设是键盘,主要的应用环境是通过标准键盘上有限的按键,输入全球各种语言。输入系统编辑器(Input Method Editor、Input Method Engine、Input Method Environment、Input Method Platform,简称IME)才是真正的操作系统上的程序,负责实现上述IM系统的功能。


世界上大多数语言是基于字母表的,一些字母的集合组成了单词,当在计算机中输入这些语言时,用户通常是在键盘上键入相应的字符或一些组合键来实现。但表意文字(如中,日,韩(CJK)等)却不能在键盘上找到相应的键,如果想在计算机中输入这些文字,就需要相应的输入法(把一个键盘序列转换为一个对应的CJK字符)。输入法有很多种,如拼音,五笔等,但这些输入法的一个共同的特征是用户敲多个键来组成一个文字(或一组文字),统称为编码输入。


linux下的IME


从使用角度看,输入法一般要显示预编辑区域和候选字区域,有时候还会有状态区域。预编辑区域通常用来提示用户的输入产生的中间结果。比如用户输入了一个拼音的字母序列,预编辑区通常会回显拼音序列,或者已经确定的字加上部分不完整拼音等,这有时候取决于使用了什么样的输入风格。候选字区域通常是由于具体输入法本身的模糊性而必须给用户提供多个选择。比如一个拼音可能会对应多个汉字等。


XIM是Linux上最古老的CJK输入协议,被X11程序广泛支持。它从一开始就定义了四种风格:

  • root window 输入法提供一个独立的窗口在屏幕的某个单独的位置来显示预编辑区域的内容

  • over the spot 输入法提供一个独立的窗口来显示预编辑区域的内容,但是该窗口会跟随输入光标的位置。

  • on the spot 由客户程序提供一个区域(内嵌在输入位置)来显示预编辑的内容

  • off the spot 由客户程序提供一个独立的窗口,内容由输入法填充


现在常见的输入法引擎一般支持over the spot和on the spot风格。


我们可以在系统中安装多个输入法引擎,并且可以通过im-config进行切换。比如im-config -n fcitx切换到fcitx输入法。im-config其实就是设置了一组环境变量,并在登陆时启动输入法引擎的后台进程。其实可以手动同时启动多个不同输入法引擎,并根据需要为特定的app设置环境变量,这在调试输入法的时候有用。


如果没有im-config,也可以手动启动输入法引擎。比如要使用fctix,通常要启动fcitx的后台服务,另外还要设置几个环境变量

export GTK_IM_MODULE=fcitx #支持Gtk程序的输入
export GTK_IM_MODULE=fcitx #支持Qt程序的输入
export XMODIFIERS=@im=fcitx #支持遗留X11程序的输入


事实上,没有哪个变量是必须设置的。如果不需要支持X11程序的输入,就不需要设置XMODIFIERS,其他两个也类似。还有一个有趣的事实是,即使不设置GTK_IM_MODULE,基于gtk3的程序也能正确的输入中文。这是因为gtk2/3自带了一个im module(im-xim),能够把XIM的消息转换为Gtk的协议进行处理(当然,这个时候就要求XMODIFIERS必须被正确设置)。这样,只要输入法引擎实现了XIM服务器,就能直接使用了。

 

从客户程序角度看,目前在Linux下的一些主流输入法引擎包括fcitx,ibus等。他们都至少实现了对遗留X11程序的输入支持,以及基于Gtk+ 3.0以及Qt 5.0等控件库实现的程序的输入支持。Linux下最早的输入法协议是XIM,在Gtk,Qt这些控件库流行之前,原始的X11要支持国际化输入,都必须编写复杂的XIM代码与支持XIM协议的输入法服务器进行通讯。XIM支持两种结构:


  • C/S模型:IM服务器是一个独立的进程,由它来处理输入、预编辑、转换和确认。IM库存在于应用程序中,就象IM服务器的一个客户,它只是简单的从IM服务器接收确认字符串。

  • Library模型:所有的输入都由应用程序中的IM库来处理。事件处理在IM库中就被关闭了,所以就不再需要一个独立的IM服务器。


基本上,现在看不到Library模式的引擎了,而且使用XIM支持国际化输入比较复杂。现在,Gtk,Qt这些主流控件库都有自己完整的国际化输入架构。通常都是通过其提供的API接口实现一个动态库就可以实现一个输入法。为了最大程度的支持所有类型的程序的国际化输入,现代输入法引擎都实现为一个独立的守护进程,同时为X11、Gtk、Qt程序分别实现对应的模块。要支持X11,必须在守护进程内部实现XIM服务器的功能(一般都是用IMdkit开发库),支持Gtk就要实现GtkImContext,支持Qt就要实现QPlatformInputContext,这两个实现都是作为动态库被Gtk/Qt加载到客户程序的进程空间,然后通过某种IPC与输入法引擎交互。


所以从实现角度看,一个输入法引擎常有三个部分组成:

  • 用来与各个客户程序进行通讯以及交互信息的部分。

  • 实现各种具体输入法(比如拼音,五笔等)逻辑以及管理输入法切换等的部分。

  • 用来提供预编辑、候选字、状态栏等显示的UI组件。


这是从功能上来说的。下面我们以fcitx为例,来具体看看在linux下要实现输入中文,引擎具体需要做哪些工作或者说提供哪些组件。


首先,输入法引擎的核心组件是一个独立的后台进程(fcitx)。引擎实现了多个具体的输入法,如五笔,拼音,区位码等,这些输入法通过fcitx定义好的接口与核心代码交互信息,并且以插件的形式被fcitx加载。用户在客户程序上输入的每一个按键都会转发给引擎(要么走X11协议,要么通过fcitx实现的GtkImContext或者QPlatformInputContext)。引擎首先会做必要的处理和过滤后将序列传给具体的输入法模块,由输入法根据自己的规则进行处理,生成匹配的候选字列表,回送给引擎。引擎根据这些信息,更新预编辑区域、候选字区域以及状态区域的内容。这些区域的内容,根据输入风格的不同,有点显示在客户程序端,有的由引擎自绘窗口显示。引擎对于从客户程序来的按键事件流会做一个处理,比如识别快捷键,交由一些可动态加载的模块进行处理等。引擎还必须正确管理输入上下文(Input Context)的切换。即使一个客户程序里,也可能会有多个输入上下文,必须保证预编辑数据、用户选定的候选字等正确传给焦点上下文。焦点发生改变时,状态要即使的更新,保证一致性。


其次,为了实现客户程序与引擎的通讯,fcitx需要在客户程序这边加载一个小的模块,用来过滤用户的按键和焦点事件等,通过socket转发给引擎的后台进程。传统的X11程序可以通过直接实现XIM协议来与引擎通讯,fctix为不同版本的Gtk和Qt都实现了一个im module(fcitx-frontend-gtk2,fcitx-frontend-gtk3,fcitx-frontend-qt4,fcitx-frontend-qt5),即前面提到的GtkImContext和QPlatformInputContext。


参考

  • XIM协议:https://www.x.org/releases/X11R7.6/doc/libX11/specs/XIM/xim.html

  • XIM原理及实现:https://www.ibm.com/developerworks/cn/linux/i18n/xim/xim-2/index.html




【相关链接】

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存