世界上的键盘有很多种, 它们按键数不同, 针对的市场, 用途, 国家, 人群也不同, 每个人都希望自己的键盘以自己习惯的方式工作. 所以在 X 中, 关于键盘的配置也是很复杂的, 因此 X 将与键盘配置有关的部分放到了 XKB extension 中.
整个键盘的配置, 叫做 keyboard map, 或者 keymap. 一个 keymap 中包含按键的数量, 键盘 model, 键盘的 layout 等.
当一个按键按下时, 键盘会发送一个被称作 scancode 的码值, 当按键松开时, 键盘会发送另一个码值, 如此系统就会知道这个按键被按下了多久. 这个 scancode 标识着按键在键盘上的位置, 要想这个按键对应到字符的话, 就需要查阅 keymap. 一个一般的 keymap 能够囊括美国语里的所有符号, 所以这么一个标准的 layout 足够美国语使用了. 但是除了美洲地区之外, 有很多其他的符号, 这些符号有的在美国语系里也有, 有的是美国语系没有的, 比如英国的英镑符号.
就算是被许多国家通用的罗马字符, 其在不同国家的键盘的排布可能也不一样, 比如北美使用 QWERTY, 而德国使用 QWERTZ, 法国使用 AZERTY.
在一个 keyboard map 中, 有一些按键按下时会产生比较直接的结果, 比如字母建, 这可以键入英美国家的所有字符; 而有一些按键单独按下时不会有什么结果, 但与其它按键搭配时会改变其他按键的效果, 比如 Alt, Ctrl, Shift, 这样的按键被称作 modifier; 还有一些按键叫做 dead keys, 这种按键也是单独按下不产生任何效果, 但是紧随其后的字符键会被加上重音符, 这是为一些大量使用重音字符的国家设计的.
世界上的最复杂的文字莫过于亚洲的文字了, 亚洲的文字有着数目巨大的表意字母[1]
[1]. 在英语中, 每一个字母 a, b, c 都是一个字母, 英语有 26 个字母, 26 个字母组成所有的英语单词, 句子; 而在汉语中, 每一个汉字都是一个字母, 所以汉字共有几万个字母, 几万个字母组成了汉语里的词语, 句子.
英语的输入是简单了, 每个按键都对应一个字母, 但是汉语的输入就不同了, 不可能制造一个包含上万按键的键盘, 人的十指也驾驭不了. 要在几十个按键上打出上万个汉语字母, 就注定要使用比键入英语复杂得多的汉字输入方法.
关于 keyboard 的详细信息可以看一下 X Power Tools, Keyboard Configuration.
XIM (X Input Method) 是 X Window System 下的输入法协议和框架. XIM 主要使用 CS 架构, 制定了 IM library (Client) 和 IM Server (Server) 端的通信细节.
XIM 制定了两种框架模型, 一种是采用 CS 架构的模型, 另一种叫 Library 模型, Library 模型简单, 一般比较简单的语言输入使用这种模型, 比如拉丁字母, 只需要按键盘上对应的键就能输入. 所以我们着重看 CS 模型.
在 CS 架构中, 还有两种事件处理模型: BackEnd 和 FrontEnd.
在 BackEnd 这种方式中, 应用程序的窗口, 输入事件总是由 X server 先传给 IM library (Xlib 中的 IM 部分), 再传给 IM server, 事件是串行传递的, 所以 IM library 和 IM server 之间不会有同步问题.
在 FrontEnd 方式中, 应用程序窗口的输入事件由 X server 同时传给 IM library 和 IM server, 这样一来 IM library 和 IM server 之间会存在同步问题.
BackEnd 的方式是 XIM 协议支持的核心方式, FrontEnd 的方式是作为扩展协议引进的.
X Window 里下面三个名词和我一直认为的不太一样, 记录一下, 看 x.org 官方文档的时候看到这几个名词好知道是什么意思
Display 的意思是一台电脑, 有显示器, 有键盘, 有鼠标的电脑
Screen 的意思是有显示功能的东西, 比如可以是显示器 (Monitor), 可以是图形终端 (不能是文字终端, 因为文字终端上面只能显示文字, 不能画图) (通常还要搭配显卡, 现在的显卡一般都支持同时连接多个显示器或者图形终端, 这样每个显示器或图形终端都是一个 screen)
Window 的意思就是 Screen 上的一个矩形的区域
下面这篇文章虽然有点老, 但是看了比较有收获, 它解释了上面那三个名词
http://www.linuxjournal.com/article/4879?page=0,0
另外 X Power Tools, OReilly 的第一章也详细的介绍了这几个概念
IMdkit 是 xorg 的人开发出来的, 为了方便那些想要给 X 写 IM Server 的开发者.
IMdkit 本身是 C 语言写的, 它为 IM server 开发者提供的接口也是 C 语言的函数调用. 这些调用都是囊括了 IMProtocol 协议的非常低级的调用, 使用 IMdkit 你不需要自己操心 IMProtocol 协议里繁琐的消息发送顺序, 构造消息头和消息体等等, 就可以写出一个能够与 IM client 正常通信的 IM server, 因为 IM client 都使用 X11 客户端库 --- Xlib (也就是 libX11.so) 提供的 XIM API (XOpenIM, XCloseIM 等)
IMdkit 为开发者带来了如下的便利:
封装了 IMProtocol 里的一些基本操作
IMdkit 将 IMProtocol 里 client 与 server 通信时的的字节流, 报文替你封装成更加友好的数据结构呈现给你, 方便你的开发.
提供统一的消息传输接口
不管 Input Method library (IMlibrary, Xlib 的一部分) 与 IM server 之间通过 X Protocol, TCP/IP, 还是 Decnet 通信, 你都不须操心了.
帮你处理字节序的细节
IMdkit 会帮你处理好 IM server 与 client 之间字节序的差异. 使用 IMdkit 写 IM server, 就能轻易的写出一个能同时支持大端和小端客户端的 IM server.
封装了多种 IMProtocol 模型
IMdkit 被设计为可扩展的, 与具体的 IMProtocol 模型无关的架构. 目前 IMdkit 能够支持两种 IMProtocol 模型: 一是 Ximp 模型, 也就是 X11R5 时的模型; 第二就是 X11R6 的模型, 也就是 X 里当前最新的模型 (X11R7 相对 R6 没有对 IMProtocol 模型做多少改动)
IMdkit API 和 Xlib 的 XIM API 是一一对应的
IMdkit 之于 IM server 开发者, 就好比 XIM 之于 I18N 应用程序开发者, 因此 IMdkit API 和 XIM API 基本是一一对应的. 这使得我们不需要花太多时间去学习 IMdkit 的 API --- 如果你熟悉 XIM API 的话.
XIM 有 XOpenIM 和 XCloseIM, 对应的, IMdkit 有 IMOpenIM 和 IMCloseIM.
XIM 有 IMValues 的概念并且提供了 XSetIMValues 与 XGetIMValues, IMdkit 也提供了 IMSetIMValues 与 IMGetIMValues.
http://xorg.freedesktop.org/archive/unsupported/lib/IMdkit/README
http://xorg.freedesktop.org/archive/unsupported/lib/IMdkit/doc/API.text
IMdkit 在很多年前已经是一个不再维护的项目了, 得益于 X11 的长年稳定不变性, IMdkit 依然被现如今的项目所使用. 我的 Bitbucket 中有一份用 wget 从 Xorg 官网上下载下来的 IMdkit 源码备份: http://xorg.freedesktop.org/archive/unsupported/lib/IMdkit/
iBus 使用了 DBus
iBus 能够启动一个 xim server, 它的可执行文件的名字是 ibus-x11, 使用了上面提到的 IMdkit. ibus-x11 的源码位于 ibus 源码树的 client/x11/ 目录下, 之所以位于 client/x11/ 目录下, 是因为 ibus-x11 实际上也是 ibus server 的 client --- 虽然它是 xim server.
iBus 使用 BackEnd 模型, 所以 ibus server 不需要和 X server 通信, 只需和 IM library 或者 toolkit (gtk, qt) 提供的 im module 通信即可.
DBus 是 freedesktop 开发的, 一种 IPC 机制.
xterm 是一个使用了标准的 Xlib 中 IM 方法的 X 客户端的例子, 在 xterm 的源代码中我们能够看到其调用了 XOpenIM 等.
Fcitx 也使用 DBus, 也使用了 IMdkit (从而支持 XIM).