(南通中遠(yuǎn)川崎船舶工程有限公司,江蘇 南通 226005)
Tribon M3是AVEVA公司開發(fā)的輔助船舶設(shè)計和建造的計算機(jī)軟件集成系統(tǒng),廣泛應(yīng)用于船舶設(shè)計領(lǐng)域。通過使用Tribon對傳統(tǒng)的配管現(xiàn)場放樣等作業(yè)在計算機(jī)中進(jìn)行模擬,可節(jié)省工時,減少物量浪費。然而,歷經(jīng)多次升級,其用戶界面及界面擴(kuò)展方面卻始終不能令人滿意。Tribon原版僅提供了用于基本操作的快捷鍵或工具欄,而大量操作只能通過選取菜單來完成,各公司只能根據(jù)各自的需求投入相當(dāng)?shù)娜肆凸r進(jìn)行二次開發(fā)以實現(xiàn)其它常用操作的快捷鍵,而即便是二次開發(fā)仍難以實現(xiàn)單個終端用戶快捷鍵的個性化配置(注:目前已有第三方工具如Tribon Mx Package可實現(xiàn)此功能)。
合理的快捷鍵設(shè)置可有效改善Tribon繪圖作業(yè)的效率,找到Tribon自定義快捷鍵的通用方法,最大程度上滿足用戶便捷使用,成為亟待解決的問題。
Tribon主要使用Python作為其二次開發(fā)語言,其官方推薦使用Toolbar Functions及Accelerator Functions兩套函數(shù)用于擴(kuò)展快捷鍵。
Toolbar Functions以提供自定義工具欄的方式,可將Tribon菜單中已有的命令或用戶自定義的模塊可視化展現(xiàn);Accelerator Functions則直接增加了系統(tǒng)的快捷鍵數(shù)量,將繁瑣的鼠標(biāo)點擊工作代之以鍵盤操作。兩套函數(shù)主要接口見表1。
其中,關(guān)鍵函數(shù)toolbar_button_std_add和accelerator_add都包含一個Function參數(shù),其表示的是Tribon命令的ID號,在Tribon安裝目錄的Vitesse文檔中可以找到大部分命令的ID號。
表1 Tribon快捷鍵擴(kuò)展主要函數(shù)接口
在實際使用過程中,兩種方式各有優(yōu)缺點。Toolbar Fuctions擴(kuò)展嚴(yán)格意義上說并不是快捷鍵,但卻以直觀的優(yōu)點為大多數(shù)用戶所使用,而Accelerator Functions擴(kuò)展真正體現(xiàn)了快捷鍵的含義,但難以實現(xiàn)類似AutoCAD等主流工程軟件的單鍵快捷鍵操作,使得應(yīng)用具有較大的局限性。此外,由于Tribon自定義界面函數(shù)被設(shè)計為必須用于Initialize Dafting Post-trigger中,而在多用戶共同使用的環(huán)境中,修改trigger的權(quán)限一般又僅限于系統(tǒng)管理員,且由于各工種的特殊性,使得相同操作使用頻率不同,使上述兩種擴(kuò)展方式難以在單個終端用戶的使用中得到有效利用。
Windows窗口程序是事件驅(qū)動的,用戶在鍵盤上按下相應(yīng)的加速鍵將產(chǎn)生相應(yīng)的命令消息。通常意義上,加速鍵就是菜單的快捷鍵,其實現(xiàn)對程序員來說僅僅是維護(hù)特定的鍵盤按鍵組合與處理例程的一個索引。最終系統(tǒng)接收到按鍵按下消息時會檢測加速鍵資源,看按鍵是否符合某個加速鍵,如符合則向目標(biāo)窗口發(fā)送命令消息[1]。
微軟在Windows平臺程序開發(fā)包中提供了加速鍵相關(guān)的API,對程序開發(fā)而言,不僅可加載資源表中內(nèi)置的加速鍵資源,還能創(chuàng)建運行時加速鍵表,甚至提供了相當(dāng)完整的代碼“Creating User-Editable Accelerators”,只需稍加修改即可使用。
在Windows程序界面開發(fā)過程中,工具欄往往用作菜單的補充,為用戶提供一個快捷的程序功能選擇方式,而快捷鍵一般被定義為最常用的菜單命令。為了共用相同的代碼,通常將工具欄銨鈕和快捷鍵命令I(lǐng)D與對應(yīng)的菜單命令I(lǐng)D設(shè)置為相同的。
雖然使用的是Python作為其推薦的界面開發(fā)語言,但通過對其菜單ID和Tribon可用的功能ID對比發(fā)現(xiàn),Tribon仍然遵循了這一通用規(guī)則。一般情況下,直接獲取其它程序的菜單命令I(lǐng)D需要使用第三方軟件,但Tribon這種特有的擴(kuò)展方式將其菜單命令I(lǐng)D以正式文檔的形式提供給用戶,從而促使其在系統(tǒng)升級時能很大程度保證不同版本菜單命令I(lǐng)D的可兼容性,從而使下面的探討有意義。
由于Tribon系統(tǒng)本身沒有提供良好的支持單個用戶快捷鍵個性化定制的接口,在無源碼的情況下采用非常規(guī)手段修改程序雖可達(dá)到擴(kuò)展快捷鍵的效果(注:詳細(xì)方法見tribon.cn),但風(fēng)險不小,一般公司用戶不會采納。因此考慮通過開發(fā)程序,“替”Tribon實現(xiàn)快捷鍵。
Windows是消息驅(qū)動式系統(tǒng),是Windows消息提供應(yīng)用程序與應(yīng)用程序之間、應(yīng)用程序與Windows系統(tǒng)之間進(jìn)行通信的手段[2]。Windows加速鍵的核心也是基于按鍵消息的檢測,而使用系統(tǒng)提供的接口,通過編程完全可以檢測特定按鍵消息,再通過窗口間通信即可控制Tribon完成相應(yīng)的功能。此外,在不同應(yīng)用程序之間的窗口中可以通過SendMessage或PostMessage函數(shù)互發(fā)消息 實現(xiàn)窗口通信,這些特性使得模擬Tribon快捷鍵實現(xiàn)成為可能。
下面介紹通過全局熱鍵或檢測特定擊鍵的發(fā)生等方式,操控Tribon完成某一操作曲線實現(xiàn)Tribon的快捷鍵定制。
Windows除了提供作用于單個應(yīng)用程序的加速鍵機(jī)制之外,還提供了系統(tǒng)范圍的熱鍵響應(yīng)接口。Windows對熱鍵的處理是當(dāng)每個按鍵按下時,系統(tǒng)都會首先檢測已有的熱鍵,如果找到匹配的就向注冊該熱鍵的程序發(fā)送特定的消息。應(yīng)用程序通過RegisterHotKey接口注冊熱鍵,并在消息循環(huán)中響應(yīng)WM_HOTKEY消息。利用此接口的優(yōu)先權(quán),Windows將在Tribon窗口產(chǎn)生的特定組合按鍵消息派送給擴(kuò)展程序,由擴(kuò)展程序發(fā)送操作命令給Tribon,從而利用系統(tǒng)的接口改變了常規(guī)的消息路由,實現(xiàn)了自定義Tribon快捷鍵。
這種方法實際是將擴(kuò)展程序自身的熱鍵轉(zhuǎn)換為Tribon的快捷鍵,這種實現(xiàn)方式最為便捷,但只能定義組合鍵作為快捷鍵。下面介紹通過主動改變消息路由來擴(kuò)展Tribon任意快捷鍵。
通常情況下,Windows會檢測系統(tǒng)消息隊列里消息的發(fā)生位置,將消息派的送到對應(yīng)應(yīng)用程序的消息隊列。此外,Windows系統(tǒng)還提供了其它方式讓應(yīng)用程序得以在特定消息發(fā)生時截獲消息。
Windows鉤子可以截獲系統(tǒng)的消息流,從而改變消息路由或者直接對消息進(jìn)行修改。一種可行的方法是使用WH_KEYBOARD等鉤子對鍵盤輸入進(jìn)行過濾,處理快捷鍵按鍵消息。
安裝Windows鉤子尤其是系統(tǒng)級別的鉤子對系統(tǒng)性能有影響,而對于按鍵消息,Windows還提供了更為便捷的接口Raw input,即原始輸入接口。原始輸入的API主要是被設(shè)計來處理輸入設(shè)備的數(shù)據(jù)。調(diào)用Register Raw Input Device,應(yīng)用程序可以注冊系統(tǒng)當(dāng)前沒有的設(shè)備,設(shè)備可用之后,Windows自動向應(yīng)用程序發(fā)送WM-INPUT消息,而不管應(yīng)用程序在前臺還是后臺。
使用原始輸入接口包括設(shè)備的注冊及WM_INPUT消息的處理關(guān)鍵代碼如下:
BOOL C_AccDlg::OnInitDialog()
{
CDialog::OnInitDialog();
//
// RAWINPUTDEVICE rid[2];
rid[0].usUsagePage = 0x01;
rid[0].usUsage = 0x06;
rid[0].dwFlags = RIDEV_INPUTSINK;
rid[0].hwndTarget = m_hWnd;
rid[1].usUsagePage = 0x01;
rid[1].usUsage = 0x02;
rid[1].dwFlags = RIDEV_INPUTSINK;
rid[1].hwndTarget = m_hWnd;
return TRUE;
}
LRESULT C_AccDlg::OnInput(WPARAM wParam, LPARAM lParam)
{
int i;
BYTE lpKeyboard[256];
WORD wKey;
RAWINPUT *buffer;
UINT dwSize;
GetKeyState(VK_CAPITAL);
GetKeyState(VK_SCROLL);
GetKeyState(VK_NUMLOCK);
GetKeyboardState(lpKeyboard);
// request size of the raw input buffer to dwSize
GetRawInputData((HRAWINPUT)lParam,RID_INPUT,NULL,&dwSize,sizeof(RAWINPUTHEADER));
// allocate buffer for input data
buffer=(RAWINPUT*)HeapAlloc(GetProcessHeap(),0,dwSize);
if(GetRawInputData((HRAWINPUT)lParam,RID_INPUT,buffer,&dwSize,sizeof(RAWINPUTHEADER)))
{
if(buffer->header.dwType==RIM_TYPEKEYBOARD && buffer->data.keyboard.Message==WM_KEYDOWN)
{
UINT uCode=buffer->data.keyboard.VKey;
//檢測當(dāng)前窗口
if(ToAscii(uCode,MapVirtualKey(uCode, 0), lpKeyboard,&wKey,0)== 1)
{
//查詢匹配命令I(lǐng)D
}
}
}
HeapFree(GetProcessHeap(), 0, buffer);
return 0;
}
擴(kuò)展程序接收到按鍵消息,需要經(jīng)過處理再轉(zhuǎn)發(fā)給Tribon程序,其流程見圖1。
圖1 擴(kuò)展程序按鍵消息處理流程
按鍵消息的處理即是查找按鍵消息跟指定操作的對應(yīng)關(guān)系。擴(kuò)展程序?qū)⒖旖萱I配置信息存放在Accesss數(shù)據(jù)庫文件中,在接收到按鍵信息后,在配置文件中查找匹配的按鍵,如查到則獲取其對應(yīng)的命令I(lǐng)D,配置表包括使用全局熱鍵和Rawinput接口兩種方式的按鍵信息、Tribon命令I(lǐng)D、操作說明和其它程序控制信息,其關(guān)鍵結(jié)構(gòu)見2。
表2 快捷鍵配置表的結(jié)構(gòu)
在此表中,存儲示例表示使用組合鍵Ctrl+Alt+F和單鍵t實現(xiàn)在Tribon中插入文本的功能,其中32982即Tribon插入多行文本命令對應(yīng)的ID號,對應(yīng)Tribon二次開發(fā)快捷鍵擴(kuò)展函數(shù)中的Function參數(shù)。
擴(kuò)展程序在完成了按鍵消息的處理后,必須將快捷鍵消息“翻譯”為特定的操作轉(zhuǎn)發(fā)給Tribon,否則Tribon接收到的只有普通的按鍵消息。查看MSDN可以知道,點擊菜單或快捷鍵會向窗口發(fā)送WM_COMMAND消息,故使用PostMessage接口向Tribon窗口發(fā)送此消息即可實現(xiàn)按鍵消息的轉(zhuǎn)發(fā)。在實際程序中可通過GetForegroundWindow函數(shù)獲取前臺窗口句柄并簡單地通過窗口標(biāo)題比較檢測是否為Tribon窗口。代碼如下:
CWnd* hTBWin = GetForegroundWindow ();
CString szWinTitle;
//檢測當(dāng)前窗口是否為Tribon窗口
hTBWin->GetWindowText(szWinTitle);
if(!szWinTitle.GetLength()|| szWinTitle.Left(9).Compare(TEXT("Tribon M3")))
{
szWinTitle.Empty();
return TRUE;
}
hTBWin->PostMessage(WM_COMMAND,Func,0);
其中:GetForegroundWindow用于獲取當(dāng)前窗口句柄,lstrcmp用于判斷當(dāng)前窗口是否為Tribon窗口,PostMessage函數(shù)的參數(shù)Func為配置表存儲的命令I(lǐng)D號。
通過擴(kuò)展程序,可以實現(xiàn)Tribon的任意快捷鍵個性化定制,可彌補軟件界面設(shè)計本身的不足,同時也為Tribon終端用戶自定義程序界面提供了新的思路。
事實上,加入動態(tài)獲取菜單ID的模塊,上述方法可用于大部分應(yīng)用程序的快捷鍵擴(kuò)展。
[1] 羅云彬.琢石成器—Windows環(huán)境下32位匯編語言程序設(shè)計[M].北京:電子工業(yè)出版社,2009.
[2] 段 鋼.加密與解密[M].3版.北京:電子工業(yè)出版社,2009.