怎樣在 Mac OS X 下寫一套輸入法?(三)

到目前為止的介紹所介紹的,都只是一個輸入法系統元件的「外殼」,而還沒有介紹作業系統如何與輸入法的核心演算法溝通。接下來要介紹的,就是輸入法如何取得使用者輸入的按鍵的資訊,然後給予適當的回應。

作業系統會將使用者按了某個鍵盤按鍵這樣的事情,當成是一種「事件」(Event),而在 Mac OS X 中,有非常多不同種類的事件,包括滑鼠事件與鍵盤事件的類型,而每個類型下又有許多更進一步的區別,例如,滑鼠事件就有滑鼠移動、點選、拖拉、放開,鍵盤則有打一下、按著不放…等等,蘋果在 Carbon Event Manager Reference 這份文件中,便完整列出了各種事件。輸入法則透過前一篇介紹的 kCMTextServiceEvent,獲得這些事件,以 CIM 這個範例來說,可以在 CIMcomponent.cpp 裡頭,在遇到 kCMTextServiceEvent ,就丟到 CIMSessionEvent() 裡頭處理, CIMSessionEvent() 則寫在 CIM.cpp 裡頭。

在 CIMSessionEvent() 這裡,可以先看到:


if (GetEventClass(evnt)!=kEventClassKeyboard ||
!(eventkind==kEventRawKeyDown || eventkind==kEventRawKeyRepeat))
return FALSE;

這一段程式的意義在於篩選我們所需要的事件類型,輸入法其實需要的就是只有鍵盤事件而已,所以我們只需要 kEventClassKeyboard (代表鍵盤事件這個類別)。而在鍵盤事件中又有很多種,我們只需要「打一下」(kEventRawKeyDown)還有「按著不放」(kEventRawKeyRepeat)兩個項目,其他的事件就都不要了,您可以在這裡看到所有的鍵盤事件列表。不過,如果您要做手寫辨識這類不是透過鍵盤的文字輸入,您可能就需要偵測滑鼠事件,但是就 OpenVanilla 專案來說,並沒有做過這樣的嘗試,也就無法解說了。

然後可以看到這幾行:


UInt32 keycode, modifiers;
unsigned char charcode;

GetEventParameter(evnt, kEventParamKeyCode, typeUInt32, nil,
sizeof(keycode), nil, &keycode);
GetEventParameter(evnt, kEventParamKeyMacCharCodes, typeChar, nil,
sizeof(charcode), nil, &charcode);
GetEventParameter(evnt, kEventParamKeyModifiers, typeUInt32, nil,
sizeof(modifiers), nil, &modifiers);

我們現在要用GetEventParameter(),從傳入的事件中,過濾出我們所需要的資料。從前面三行程式,我們分別取得 kEventParamKeyCode 、kEventParamKeyMacCharCodes 以及 kEventParamKeyModifiers,分別存放在 keycode 、 charcode 以及 modifiers 裡頭。

其中 charcode 就是使用者所輸入的按鍵,那麼 keycode 又是什麼呢?—這就是有時讓人不禁痛恨蘋果的地方,在蘋果的開發者文件當中,根本沒有對於這些參數的意義給予完整的解釋,而在 CIM 的範例中,其實只有使用到 charcode 而已,而這樣的寫法基本上完全都是繼承 BIM 的範例而來,在取得了 charcode 之後,可以看到我們把後續工作,都丟進 CIMCustomHandleInput() 處理…而您的輸入法的各種演算,會從這個地方開始,而從這個地方開始,也都要看您自己的了。

需要注意的是(其實,在這邊提到「需要注意的是」這樣的句子,都是過去一年來花了很多時間 debug 才了解的心得),Mac 的鍵盤與其他的系統略有不同,例如在各種筆記型電腦上,都可以看到鍵盤上除了有 Return 按鍵之外,另外還有一個 Enter 鍵,通常來說,兩個按鍵做的都是同樣的事情,也始終搞不清楚為什麼要區分成兩個按鍵,但是在輸入法的部份來說,會偵測到兩個不同的按鍵,一是 0x03,一是 0x0D,另外就是在外接鍵盤上,除了 Backspace 之外,還有一個 Delete 鍵,也會分別送出 0x08 以及 0x7F,如果某些按鍵並沒有指定定義的話,是會造成問題的。

另外就是快速鍵,所有的快速鍵都表列在 Event Modifier Bits 這份文件中。需要特別注意的是,在這份表格中並沒有列出 num lock 這個快速鍵,如果您對於在設定了 num lock 後,在數字鍵盤上做一些比較特別的行為,那,num lock 的 modifier 的名稱為 kEventKeyModifierNumLockMask 。

3 thoughts on “怎樣在 Mac OS X 下寫一套輸入法?(三)

  1. 其實 keycode 是什麼,在以前的 Inside Macintosh (yes, 都是 pre-OS X 時代的東西) 應該都找得到。只是隨著 Apple 不斷 phase out 掉所有的舊文件,輸入法就越來越像「KK 音標」這種孤島效應的產物,離 OS X 核心越來越遠,所有的支援文件跟 debug 方法都消失了。

    附帶一提:Apple 竟然完全沒有任何文件提到 Cocoa 的繪圖座標怎麼跟 Carbon (QuickDraw) 繪圖座標做轉換。OpenVanilla 的游標定位那段程式,是參考很多網路上不知哪來的、別人程式碼裡的做法,才知道「喔,原來是這樣轉換的」,而且還沒有 API 可用咧。很離譜吧?!

  2. 我已经找到了不用在.r文件里使用原始的icons信息,而直接通过.icns文件来做为输入法的图标的办法;QIM FIX 4就是这样做的,其实很简单.

    1.准备一个icns图标文件16X16
    2.拷贝到输入法的Resources目录
    3.在输入法的Info.plist添加一个tsInputMethodIconFile键,值为string类型的对应的icon文件名;

    完成了.

Comments are closed.