世 界上大多數語言是基於字母表的,一些字母的集合組成了單詞,當在計算機中輸入這些語言時,用戶通常是在鍵盤上鍵入相應的字符或一些組合鍵來實現。但表意文 字(如中,日,韓等)卻不能在鍵盤上找到相應的鍵,如果想在計算機中輸入這些文字,就需要相應的輸入法。輸入法有很多種,如拼音,五筆等,但這些輸入法的 一個共同的特徵是用戶敲多個鍵來組成一個文字(或一組文字),統稱爲編碼輸入。
XIM(X Input Method)是X-Window系統下的符合國際化標準的輸入法協議,只要應用程序和系統都支持這種輸入協議,應用程序就不必具體考慮在不同語言環境下的輸入問題,系統可以根據相應的locale去尋找相應的輸入法,從而達到國際化的要求。
-
1.1 實現模型 在X-Window 系統環境下,XIM的實現有以下兩種典型的體系結構:
1)Client/Server模型:
IM服務器是一個獨立的進程,由它來處理輸入、預編輯、轉換和確認。IM庫存在於應用程序中,就象IM服務器的一個客戶,它只是簡單的從IM服務器接收確認字符串。
2)Library模型:
所有的輸入都由應用程序中的IM庫來處理。事件處理在IM庫中就被關閉了,所以就不再需要一個獨立的IM服務器。
大多數語言,如亞洲語言一般都有複雜的預編輯,所以都採用Client/Server模型來實現,其他的只有一些死鍵或組合鍵的語言,如歐洲語言一般都採用Library模型來實現。
下面主要都討論Client/Server模型,如圖1所示:
-
客戶程序通過連接IM服務器來實現XIM輸入,它們之間的通訊是利用XIM的協議來實現的。IM子系統完成文字查找和文本的組合。
- 1.2 IM結構 當客戶程序向服務器發出連接或斷開請求時,在客戶和服務器之間會產生打開和關閉操作。
函數XopenIM()設置或修改客戶的locale,IM是根據相應的locale來指定的。另外,客戶支持的IM類型可以通過函數XGetIMValues()來獲得。
一 個客戶程序通常有多個輸入域,Xlib提供了一個結構“Input Context”(IC)來管理每個輸入域。函數XCreateIC()可以指定XIM並創建一個相應的IC,函數XDestroyIC()用來刪除此 IC。許多重要的信息,比如確認字符串都通過IC來從IM服務器送到客戶程序。每一個IC與一個輸入域相關,函數XSetICFocus()用來通知IM 服務器當前IC獲得了焦點(XUnSetICFocus()表示失去焦點)。
-
1.3 事件處理模型 現存的輸入法都支持前端輸入法和後端輸入法或其中的一種。XIM把後端輸入法作爲一種默認的輸入法,但也支持前端輸入法。
1)後端輸入法:
在後端輸入法中,客戶窗口的輸入事件總是送到IM庫中,然後IM庫把此事件送到IM服務器中。事件以傳送的順序來處理,因此在IM庫和IM服務器中沒有需要同步的問題。
2)前端輸入法:
在 前端輸入法中,客戶窗口的輸入事件由XServer直接傳送到IM庫和IM服務器中。因此這種方法提供了更好的接口性能(尤其在IM服務器運行在一臺工作 站而客戶程序運行在另一臺工作站上,且網絡又相對較慢時)。而,前端模型在處理鍵的時候有同步問題,時會引起事件丟失或時間重複。因此後端輸入法是由核心 輸入法支持的,前端輸入法是從擴展性能的目的出發的。
- 1.4 事件流控制
XIM協議在IM庫和IM服務器之間的通訊支持兩種事件流:靜態和動態。
1)靜態事件流是客戶程序的輸入事件總是發送到IM服務器。
2) 動態事件流是輸入事件中需要處理的事件發送到IM服務器。例如,在即輸入ASCII字符又輸入中文字符的時候,ASCII字符就不必送到IM服務器了。因 此,採用動態事件流後,在XServer、客戶和IM服務器之間的需求事件大大減少了,從而性能有所提高。IM服務器發送 XIM_REGISTER_TRIGGERKEYS事件來切換動態事件流。
下圖2是一個最簡單的協議流的例子:
當 應用程序發生按鍵事件時,它調用Xlib API的XNextEvent函數,對於後端輸入法模型,事件都由IM庫來處理,IM庫先發出XIM_FORWARD_EVENT作爲同步請求,IM服務 器接收到此協議後發出XIM_FORWARD_EVENT或XIM_COMMIT作爲同步應答,雙方完成同步。然後,IM服務器阻塞從IM庫接收到的 XIM_FORWARD_EVENT消息,進行處理,結束後把結果返回到應用程序。
IMdkit(IMServer Develops Kit)是X11R6的Xi18n執行工作組發佈的XIM服務器開發工具,它提供了一個低級的C語言接口,把每個IM協議操作都綁定到了簡單的C語言接 口,這樣用戶就可以很容易的使你的IM服務器與XIM客戶程序很容易的通訊,而不用直接處理複雜的IM協議。XIM客戶程序是指利用在X11R6中定義的 XIM API國際化過的應用程序。IMdkit封裝了實際的IM協議操作,這樣用戶自己就不必處理實際包,可以利用它提供的數據結構,簡化了許多細節麻煩;封裝 了不同的傳輸機制(包括X協議,TCP/IP,DECNET),這些協議用來在IM庫和IM服務器之間傳輸數據包;封裝了多種IM協議模型,包括Ximp 和Xi18n。
IMdkit定義了一個不透明的數據結構XIMS,用來抽象輸入法服務器的結構。它由函數IMOpenIM返回,函數IMOpenIM如果成功的話,返回一個XIMS結構,否則返回NULL。
對於每一個XIM協議輸入,在IMdkit的頭文件中都定義了一些相應的結構,對於R6標準的IM協議模型,中定義了所有的IM協議結構。
1)IM協議的通用數據結構
在R6的標準IM協議模型中,所有的事件結構有如下的通用成員:
typedef struct{ |
major_code和minor_code指定了唯一鑑別這個IM協議類型本身的常量名。connect_id指定了連接的客戶ID。
2)協議處理
一些由IM庫發送的IM協議請求由IMdkit內部處理了,不需要發送到IM服務器。因爲IMdkit會根據你在XIMS結構中設置的值來決定對這個IM協議請求的應答。需要處理的一些IM協議請求參看下面介紹的XIM的實現。
以下討論的具體實現是利用IMdkit開發的XIM服務器。
ims = IMOpenIM(display,IMModifiers,”Xi18n”,IMServerWindow,window, |
函數IMOpenIM初始化輸入法服務的連接,並設置一個或多個由變長的參數列表指定的IM的屬性。
下面簡介上面函數中的參數:
Display是當前的屏幕顯示。
IMModifiers定義XIM的協議模型,有兩種:
“Xi18n”指定R6標準的IM協議模型。
“XIMP”指定R5標準的Ximp模型。
IMServerWindow指定IM服務器的窗口以便於與XIM客戶程序進行通訊。
IMServerName指定IM服務器的名字。
IMLocale指定IM服務器支持的locale列表。
IMServerTransport指定IM服務器用來與客戶程序間的通訊技術。
IMIputStyles指定IM服務器支持的輸入風格列表。如:XIMPeeditPosition|XIMStatusNothing爲光標跟隨,不需要狀態顯示風格。下面的具體協議處理就是根據這種風格來介紹的。
IMProtocolHandler指定當IM主循環接收到客戶程序的協議時的時間處理函數。
IMEncodingList指定IM服務器支持的傳輸編碼列表。
下面函數用於處理整個客戶協議,由於篇幅原因,本文只列出了相應的協議,而沒有具體的處理函數,實際應用中,每一個分支都由一個相應的函數來處理。
MyProtoHandler(XIMS ims,IMProtocol *call_data) |
函數MyProtoHandler是由 IMOpenIM登記的處理客戶程序發送到IM服務器的協議的函數,在參數call_data中有相應的協議。上面列出了一些主要的協議,對於不同的情況 (主要是根據不同的輸入法風格),有一些協議不必處理,或根本不會發生。下面簡介一些主要的協議處理過程。
XIM_OPEN:XIM客戶程序啓動時,要在IM庫和IM服務器之間建立邏輯連接。
XIM_CLOSE:關閉在IM庫和IM服務器之間建立 的邏輯連接。
XIM_CREATE_IC:當客戶程序創建了一個輸入法上下文(IC)時,發送此協議到IM服務器,這時在IM服務器中爲此IC申請了一個相應的結構,用於記錄一些必要的信息,包括字體、位置、前背景色等等。
XIM_DESTROY_IC:當客戶程序退出時,刪除相應的IC,釋放一些與IC相關的存儲空間。
XIM_SET_IC_VALUES:設置當前連接IM服務器的IC的屬性。實際XIM服務器定期發送此協議來修改IC的屬性值。
XIM_GET_IC_VALUES:取得當前連接IM服務器的IC的屬性。
XIM_FORWARD_EVENT: 當有按鍵發生時,客戶程序發送此協議到IM服務器,此按鍵事件放在call_data的event結構中。在相應的處理函數中,讀出相應的鍵值,如果是一 些控制鍵,就作相應的操作,如輸入法的開啓,不同輸入法之間的切換等;如果是輸入法不需要處理的鍵,就直接送回客戶程序,如一些功能鍵,組合鍵等;否則調 用輸入法的處理程序,輸入法處理程序對這個字符進行處理,此時在預編輯區和選擇區會有相應的變化,如果有結果字符串生成,輸入法服務器會按照開始時確定的 編碼方式把這個字符串發送到客戶程序,這樣就完成了一次輸入過程。
XIM_SET_IC_FOCUS:當在不同的應用程序間進行切換時,當前的IC會發生變化,此時新的應用程序會發送此協議到IM服務器,輸入法服務器會改變當前的焦點,當前的一些與IC有關的屬性和全局變量也要有相應的變化。
XIM_UNSET_IC_FOCUS:當前IC失去焦點。在此處可以釋放一些與當前IC相關的資源。
XIM_RESET_IC:重置在IM服務器中的IC的狀態。
XIM_TRIGGER_NOTIFY:IM庫通知IM服務器匹配啓動(on-keys)和關閉(off-keys)的事件發生了。
在主程序中要用XselectInput選擇輸入法窗口要處理的所有X事件,
XSelectInput(display,window,ExposureMask|ButtonPressMask|ButtonReleaseMask| |
然後在主循環中要處理所有這些事件,如下由函數MyXEventHandler完成。
for(::){ |
函數MyEventHandler要處理輸入法窗口的事件。包括在屏幕上的顯示,窗口的改變,拖動窗口,及與其他窗口進行通訊等消息。通過此函數,可以使程序達到對用戶友好的目的。
以上三點是一個XIM服務器的必須要處理的,我們還需要包含以下頭文件:X11/Xlib.h、IMdkit.h和Xi18n.h,後面兩個頭文件是IMdkit提供的面向R6標準的一些結構定義。另外連接的時候要連接IMdkit的libXimd.so。
以 前的X Window下的輸入法的實現大都是通過截取X的通訊函數的方法來實現在X下的應用程序中進行文本輸入。具體方法是修改libX11.so.6裏面的 XNextEvent函數,當時按鍵事件時,如果此是在中文狀態,就把按鍵消息發送到輸入法去處理,並等待輸入法的迴應。相應的要修改 XlookupString函數,和一些顯示函數。這種方法屬於非標準的方法,在實際應用中如果有一些應用程序通過其它方法接收輸入時,輸入法就會起不到 作用,爲了達到目的需要修改很多應用程序,另外對於其他語言不兼容,每一種語言都要有不同的輸入法,給程序的開發者和應用者帶來了很多困難。採用了XIM 協議後,完全符合國際化標準,這樣X下的應用程序根本不必過多的考慮輸入問題,就可以達到國際化的要求,在不同的語言環境下可以自由的應用,減少了應用程 序開發者的麻煩。
-
參考文獻
- [1] Open Software Foundation:X Window System Version 11 Input Method Secifications,November 1990
- [2] X11R6 Xi18n Implementation Group:IM Server Developers Kit-C Language Interface,May 15 1994