前面我們介紹了QteIME的基本設計思路,以及一個最簡單的例子,那麼,Qte的IME是如何工作的呢?本節我們就來看一下Qte的原始碼,一起來解開這個謎團。
在Qte的Client/Server體繫結構中,QWSServer類負責管理Qte的Server,監聽系統事件,尤其是鍵盤和滑鼠事件。當這些監聽的事件發生的時候,server會做出判斷,這些事件應該發送給那一個用戶端。
如果當前系統安裝了IME,那麼鍵盤和滑鼠事件在派發之前,就會先送給IME,讓IME來做一下判斷,看IME是否會處理這個鍵盤按鍵,如果IME已經處理,就不在繼續分發這個事件,否則就會按照原先的事件分發機制繼續分發這個事件。也就是說,IME會在應用程式之前接收到鍵盤事件。
Qte已經定義了一個IME基類QWSInputMethod,在這個類中封裝了一些基本的IME函數。我們一起來看看QWSInputMethod類的定義:
class QWSInputMethod : public QObject
{
Q_OBJECT
public:
QWSInputMethod();
virtual ~QWSInputMethod();
enum UpdateType {Update, FocusIn, FocusOut, Reset, Destroyed};
virtual bool filter(int unicode, int keycode, int modifiers,
bool isPress, bool autoRepeat);
virtual bool filter(const QPoint &, int state, int wheel);
virtual void reset();
virtual void updateHandler(int type);
virtual void mouseHandler(int pos, int state);
virtual void queryResponse(int property, const QVariant&);
protected:
uint setInputResolution(bool isHigh);
uint inputResolutionShift() const;
void sendMouseEvent(const QPoint &pos, int state, int wheel);
void sendEvent(const QInputMethodEvent*);
void sendPreeditString(const QString &preeditString, int cursorPosition, int selectionLength = 0);
void sendCommitString(const QString &commitString, int replaceFrom = 0, int replaceLength = 0);
void sendQuery(int property);
private:
bool mIResolution;
};
這個類從QObject類繼承而來,定義了 Q_OBJECT 宏,說明這個類支援Qt物件模型的操作,signal/slot,property,都沒有問題,這裡最關鍵的幾個函數有,兩個重載的filter函數,一個用來過濾鍵盤事件,另一個用來過濾滑鼠事件,sendEvent函數用來發送IME事件,在這個事件中可以打包preedit string, commit string,它還有一個list,可以添加任意多的其它資料。sendPreeditString函數用來把正在輸入過程中的字串發送到當前編輯視窗,而sendCommitString則用來把最終的使用者選擇的字串發送到當前編輯視窗。
QWSServer類提供了一個函數來安裝IME,void setCurrentInputMethod ( QWSInputMethod * method),這個函數的參數就是一個QWSInputMethod類的指標。QWSServer是如何管理QWSInputMethod的呢?在Server端,定義了這麼幾個變數,
static QWSInputMethod *current_IM = 0;
static QWSWindow *current_IM_composing_win = 0;
static int current_IM_winId = -1;
static bool force_reject_strokeIM = false;
其中,最重要的就是current_IM了,這個指標指向當前安裝的IME對象,它就是在QWSServer::setCurrentInputMethod函數中賦值的。
這裡是QWSServer::setCurrentInputMethod這個函數的原始碼:
void QWSServer::setCurrentInputMethod(QWSInputMethod *im)
{
if (current_IM)
current_IM->reset();
current_IM = im;
}
再看看這個鍵盤事件處理函數:
void QWSServer::sendKeyEvent(int unicode, int keycode, Qt::KeyboardModifiers modifiers,
bool isPress, bool autoRepeat)
{
//………………………..
#ifndef QT_NO_QWS_INPUTMETHODS
if (!current_IM || !current_IM->filter(unicode, keycode, modifiers, isPress, autoRepeat))
QWSServerPrivate::sendKeyEventUnfiltered(unicode, keycode, modifiers, isPress, autoRepeat);
#else
QWSServerPrivate::sendKeyEventUnfiltered(unicode, keycode, modifiers, isPress, autoRepeat);
#endif
}
在QWSServer::sendKeyEvent函數中,會去檢查當前是否安裝了IME,如果是,就會去調用這個IME的filter函數來過濾鍵盤事件,如果這個函數傳回值為true,就不在繼續分發這個key事件。
再看看這個滑鼠事件處理函數:
void QWSServer::sendMouseEvent(const QPoint& pos, int state, int wheel)
{
// ————————–
const int btnMask = Qt::LeftButton | Qt::RightButton | Qt::MidButton;
int stroke_count; // number of strokes to keep shown.
if (force_reject_strokeIM || !current_IM)
{
stroke_count = 0;
} else {
stroke_count = current_IM->filter(tpos, state, wheel);
}
}
在 QWSServer::sendMouseEvent 函數裡面,同樣會去檢查當前是否安裝了IME,如果是,就會去調用IME的filter函數來過濾滑鼠事件,如果這個函數傳回值為true,就不在繼續分發這個key事件。
看,Qt/Embedded IME的工作原理其實就是這麼簡單!
下面以一張簡單的UML sequence圖來說明一下:
======================================================================
聲明:
《Inside Qt Series》專欄文章是(http://www.qkevin.com)原創技術文章。
本系列專欄文章可隨意轉載,但必須保留本段聲明和每一篇文章的原始地址。
作者保留著作權,未經作者同意,不得用於任何商業用途
《Inside Qt Series》專欄文章總索引: http://www.qkevin.com/qt
本文原始地址:http://www.qkevin.com/archives/106