歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Unix知識 >> 關於Unix

X Window 系統使用指南--17


第17章 定制你的鍵盤和滑鼠 -- 轉譯
電腦的鍵盤通常含有一些 "特殊功能" (special function)鍵,在此有一
些方法來 "制定"(program)這些特殊功能鍵,使它們能完成特定的功能以適合
你工作的方式。例如,你可以定義一些鍵來輸入那些你常用的命令,或只需按
一個鍵便能夠輸入一些程式的片段。
在X中,你能制定的不只是功能鍵而已,其它一般的鍵和滑鼠的按鈕也都
可制定。對每一個應用程式,你均可指定特別的功能給鍵盤和滑鼠按鈕,或兩
者之組合。 (例如在 xedit中你可以結合SHIFT 鍵和滑鼠的右按鈕來讓你向前
移動一個單字)。 所有使用X Toolkit的程式均允許使用者利用一個被稱之為
鍵盤轉譯 (translations) 的設施來執行此種定義,且此種定義藉著正規的
resources 結構傳遞給應用程式。 (那些不使用X Toolkit的應用程式,同樣
地也可以用相同的設施來制定, 但它們需個別的定義所以不能廣泛地應用,從
現在起,我們假設每當討論有關轉譯的種種,均為對那些使用X Toolkit的應
用程式而言。)
就如同所有的 resources一樣,轉譯是當應用程式執行時才被處置。例如
你可以擁有數個具備不同轉譯設定的 xedit,在同時一起執行。( 你可以讓一
個xedit 適合編輯本文,另一個適合編輯程式碼,而另一個適合編輯文書)。
本章討論轉譯 -- 包刮它們的定義格式,如何將它們設定到應用程式,和
它們所涵蓋功能的□圍。我們首先以實例來介紹,逐漸地導引你看到不同的角
度。而後比較正式和詳細地討論轉譯。最後,我們列出當你使用轉譯時常會碰
到的錯誤,並給你一些如何克服這些問題的提示。
17.1 實際使用轉譯
Toolkit 轉譯結構最簡單的用途便是讓你制定你鍵盤的鍵。例如,當你使
用xterm 為一個執行一般shell 命令的視窗時,你可能希望定義一些特殊功能
鍵來輸入你常用的命令,且希望指定的關系如下:
當我按下這個鍵時... 我希望這個字串被輸入
F1 rm core *.tmp
利用Toolkit 達到此目的方法為:指定一個值給使用轉譯的widget中的resources
。此值設定應用程式中所必需的定制 (customisation),且被Toolkit 的 Trans-
lation Manager (轉譯管理器) 所處理。此 resources屬於類別Translation,
且其成員名稱幾乎一定是translations。
在下一節我們將看到設定到resources 中的值的格式。
17.1.1 如何對一個應用程式指定轉譯
對前述xterm 的例子,我們定義 (在即將被應用程式讀入的resource資料
庫中或一些resource檔案中) 一個規格類似:
xterm*VT100*Translations: (contd.)
F1: string("rm core *.tmp") 注意:不完整!!
其意為在任何類別 VT100的 xterm widget 中,當鍵 F1 被按下時,插入
字串 "rm core *.tmp")。
不幸的是,並沒有這麽簡單,轉譯管理器會把上面的規格解釋為 "去掉所
有現存的轉譯,且加入... " ,所以所有正常的像 " A鍵是插入一個 A" 這種
系結 (binding)都會消失。為了克服這點,你必需使用一些被稱為 directive
(指引)的語法插入在 resource 值之前:
xterm*VT100*Translations: #override(contd.)
F1: string("rm core *.tmp")
通常你會希望保持大部份現存的系結,而只是把你明確指定的值覆蓋上去
,所以你一般都是在你的轉譯表中,指定 #override。
現在這個規格可以開始工作了,藉著啟始一個 xterm且把此規格 (在兩個
單引號 (')中間的部份) 當成選項 -xrm 的引數來測試它:
xterm -xrm 'xterm*VT100*Translations: ... 等等'
按下特殊功能鍵 F1,你將看到指定的字串成功的插入,但並未包含新列字元
(newline) ,你可以用一點語法的技巧來克服它,像:
xterm*VT100*Translations: #override(contd.)
F1: string("rm core *.tmp")string(0xd)
這解釋了以下兩點:
1. string()的作用和它的引數相關。你可以直接輸入本文 (例如 string(lpq))
,但如果本文包含空白或非字母字元,則必需在本文前後加上雙引號。
如果引數是以 "0X" 開頭,則將其後解釋為十六進位,並插入相對的
ASCII 字元。(例如,0xd是RETURN)
2. 在你指定此功能時可結合一個以上的作用,在上例,我們用到 string()
作用兩次,如果我們知道其它的作用,我們也一樣可以系結起來。
定義許多的轉譯在一起
你可以根據需求在一個表中定義許多的轉譯。假設,我們在前面的轉譯中增加
系結:
當我按下這個鍵時... 我希望這個字串被輸入
F2 lpq-Plpa3
對此的轉譯為:
F2: string("lpq-Plpa3")string(0xd)
所以可以將本列加入前面的表中。但是轉譯管理器的格式規則告訴我們必需將
兩個轉譯以 "\n" 分開且獨立成為一列:
xterm*VT100*Translations: #override(contd.)
F1: string("rm core *.tmp")sting(0xd) \n(cond.)
F2: string("lpq-Plpa3")string(0xd)
以上的形式將造成管理上的困難,你可以藉著包含 "隱藏的新列字元" 來使它
具可讀性一些: (新列字元以倒斜線 "\"處理)
xterm*VT100*Translations: #override\n\
F1: string("rm core *.tmp")sting(0xd)\n\
F2: string("lpq-Plpa3")string(0xd)
你可以放置任意多個你所需的 "隱藏的新列字元" , 且幾乎在任何地方均可,
它們只是被忽略而已。 (只要和轉譯管理器相關,甚至你每隔一個單字便使用
一個也沒關系。但千萬不要在一個規格的 resource 特徵部份使用它們,它們
無法被resource manager解釋,也沒有相同的效果。) 如果你感覺有些混淆,
不用擔心。簡單地說,resource結構需要的是要在一列中的一個resource規格
的 "值" 的部份,而轉譯管理器以分開的列來分開 (也就是以\n終結),而使用
者剛好以每一個實際分開的列代表一個意義以增加可讀性,所以規則很簡單:
在除了最後一列的每一個轉譯列均加上一個 "\n\"。
17.1.2 轉譯可系結許多型式的作用
上述的 xterm□例,展示了如何能夠當你按下一個鍵時,插入任意的字串。但
轉譯結構的功能比這更多 -- 它可以系結任何widget所提供的作用到按鍵,讓
我們詳細一點地看一下這些作用。
前述的例子,我們在 xterm的 VT100 widget完成了鍵F1和F2在 string()
上的對應。我們將仍以 xterm為例,說明更多的作用。
查閱xterm 的指南頁,在標題KEY TRANSLATIONS 和 KEY/BUTTON BINDINGS
你將發現列有數個作用。我們將定義一個轉譯對應鍵F3到insert-selection()
作用之上,所以我們可以用鍵盤來取代滑鼠,將先前 "剪"下的本文 "貼"出。
指南頁告訴我們此作用需要一個引數,從列出的預設系結,我們可以看出預設
的 "剪貼" 結構為使用 CUT_BUFFER0, 所以我們將CUT_BUFFER0當作引數。我們
的resource規格是:
xterm*VT100*Translations: #override\n\
F3: insert-selection(CUT_BUFFER0)
到目前為止,這只是一點小小的便利。然而,假定說你花了許多時間在本文文
件上工作,你用 tbl格式化,你用 nroff在螢幕上預視 (preview)它們,用
troff 排版,且將輸出送到你的一個用過濾器 (filter) 為tr2printer的印表
機上。設定轉譯為:
xterm*VT100*Translations: #override\n\
F3: string("ed") insert-selection(CUT_BUFFER0)\
string(0xd)\n\
F4: string("tbl") insert-selection(CUT_BUFFER0)\
string("| nroff -man") string(0xd)\n\
F5: string("tbl") insert-selection(CUT_BUFFER0)\
string("| troff -man -t | tr2printer") string(0dx)
xterm 會確定這些轉譯是以xrdb自資料庫載入或是在一個resource檔案中,並
加以處理。現在當你啟始xterm,用滑鼠 "剪"取你所需的工作的檔案名稱。接
下來,便可按F3鍵編輯它,按F4鍵預視它,和按F5鍵在硬拷貝上排版它。
更多的widget作用□例 -- xbiff
查閱xbiff 的指南頁:在ACTIONS 的標題下,你將看到Mailbox widget所支援
作用的名單。它惟一預設的轉譯為當你按下任何按鈕時降下信件 (mail)的旗幟
(flag)(作用unset())。我們將設定轉譯讓你以鍵盤來運用這些作用,將這些作
用對應到 "?" 和 "UP" "DOWN"兩個方向鍵如下:
? check() 有新的信件嗎?
UP set() 升起信件的旗幟
DOWN unset() 降下信件的旗幟
以下是相關的轉譯表:
xbiff*Mailbox*Translations: #override\n\
?: check()\n\
Down: unset()\n\
Up: set()
以此測試之:用xrdb從你的resource資料庫載入這些設定,然後啟動xbiff ,
將指標移到視窗內。重復地按下Up和Down游標控制鍵以升起和降下信件旗
幟。
找出有哪些作用被提供
你對widget作用將和widget名稱遭遇相同的問題:如何找出某個widget到底提
供哪些作用以及它們能做些什麽?同樣地,沒有一個完美的解答,但有一個合
理的方法來處理:
1. 查看應用程式的指南頁。大多數的應用程式有它們自己專門的作用文件
。例如:xbiff 有一節叫做ACTION,而xterm 有兩節關於轉譯和作用的
文件 -- KEY TRANSLATIONS 和 KEY/BUTTON BINDING。
2. 最初的指南頁可能給你提示,或甚至直接告訴你它用到何種widget的類
別,所以你可以查看它的widget set文件中的特定的widget。(在 core
版中惟一的widget set為Athena,所以你在此不易出錯)。即使指南頁未
告訴你widget的類別,當你對系統熟悉之後,你將對一個widget是否為
標准型態較具有概念,如果還是不行 ...
3. 查看程式的原始碼,看看用到什麽widget的類別,以及widget提供了哪
些作用。
17.1.3 轉譯系結作用到一序列事件,不只是單一鍵
我們已經看到轉譯讓你設定插入,轉譯結構也能讓你系結這些作用:它可以是
單一的鍵,或是一序列的鍵,或者是事實上一序列任何的X事件。
讓我們繼續以xbiff 為例,看看如何轉譯一序列的鍵盤字元。例如我們定
義字元字串的轉譯如下:
look check()
raise set()
lower unset()
以下為相關的轉譯表:
xbiff*Mailbox*Translation: #override\n\
l,o,o,k: check()\n\
r,a,i,s,e: set()
l,o,w,e,r: unset()
以此測試之 -- 載入設定和啟動xbiff ,將指標移到視窗內。現在你可藉
著輸入完整的字串來升起和降下旗幟。例如鍵入五個字元 r, a, i, s, e以升
起旗幟。對xbiff 的兩個表有幾點值得說明:
. 鍵的名稱可以用不同的方式指定。正常的印出字元直接指定 (如"w")
, 其它的字元則拼出全名(如"Down").附錄A "文件指引" 告訴你
在何處可查到鍵的名稱,但在本節下面有更簡單的方法。
. 對字元字串,你必需一一指定,並以逗點分開
(如"l,o,o,k").
. 轉譯可允許相同開頭的鍵,例如 "look" 和 "lower" 均擁有相同的開頭
"lo",對轉譯管理器不會形成問題。
找出鍵的名稱
找出轉譯所需的鍵的名稱,最簡單的方法為執行xev ,將指標移到視窗內,按
下你所需的鍵,則鍵的名稱會出現在括弧內字串keysym和一個十六進位數之後
。例如在xev 的視窗內按下游標控制鍵DOWN,它的輸出如圖17 - 1,在其中你
會看到
(keysym 0xff54, Down)
也就是說,鍵的名稱為Down。
┌————————————————┐
│ P209. fig 17 - 1 │
│ │
│ │
│ │
│ 圖 17 - 1 xev 顯示鍵名稱的輸出 │
└————————————————┘
你可以在轉譯中使用任何型態的事件
到目前為止,我們所寫的轉譯都是系結作用到一個按下的鍵盤字元。但我們曾
說過,轉譯結構可系結作用到任何事件,而不只於按下鍵盤而已。可能的事件
型態非常的多,在此我們只提及一小部份:
型態 意義
按下一個鍵
按下一個鍵 (只是另一個名稱)
放松一個鍵
按下一個滑鼠按鈕
放松一個滑鼠按鈕
指標進入視窗內
指標移出視窗外
我們已經使用過按下一個鍵的事件,讓我們系結xbiff 作用到滑鼠按鈕以取代之:
xbiff*Mailbox*Translations: #override\n\
Button1: unset()\n\
Button2: check()\n\
Button3: set()
你可以看到語法和前面相似:你先給定一般性的事件型態 (例如
),其後跟著你所需事件的事件細節部份 (例如s 和Button3) (
Button 1, 2, 3分別對應到左、中、右按鈕)
對一序列的事件的轉譯
就如同我們定義了一序列按下鍵事件的轉譯(set,unset和check),我們當然
也可以定義一序列的滑鼠事件。事實上你轉譯的一序列的事件可以任意組合在
一起,你可以在一個轉譯的左邊隨意混合事件的型態。所以你可以定義如下的
轉譯表:
xbiff*Mailbox*Translations: #override\n\
Button1, ?, Button3: check()\n\
Button1: u, Button3: unset()\n\
Button1: s, Button3: set()
也就是說,用到check(),你必需依序先按下按鈕1 (左按鈕),然後按下"?"
鍵 ,最後按下按鈕3 (右按鈕)。 這個□例並不是很好,但對於一些危險或不
可取消 (irreversible) 的作用 (例如刪除一個檔案,或是覆寫一個緩沖區的
內容) ,你可以依照這種方式來使用轉譯。你需要使用一個非常謹慎的命令序
列,才能用到此作用,這樣使得使用者不可能因意外而輸入此命令。
使用非鍵盤和非滑鼠事件的轉譯
通常你是對按下或放松滑鼠按鈕或鍵盤的鍵定義轉譯。但我們曾經說過,你可
以對任何事件設定轉譯,例如指標移入或移出一個widget的視窗。讓我們以
xman的主選項視窗 (圖10 - 3) 為□例來解釋它。這是一個相當人為的□例,
因為它沒有任何用途。但無論如何,它很容易被看出在做些什麽操作。
查看xman的指南頁,在X DEFAULTS標題下,你將看到概括的xman所用到的widget
的名稱和類別:主選擇項視窗widget的名稱叫topBox,類別名為Command。這
是一個好的猜測,因為在選單操作盒的方法。我們可用第15章所提過的技巧
來確認它,使用以下的命令:
xman -xrm "*Command*backgroundPixmap: scales"
且所有的Command widget將會有魚鱗狀的背景)。
這和我們先前的□例有一個重要的不同:我們所用到的作用不是由特定的應用
程式指定,而是由標准的widget提供 (本例中為Command widget,在 "X
Toolkit Athena Widget"使用手冊中有描述)。
在我們定義任何東西之前,先來看一看此widget預設的功用,以便我們能
夠了解有些什麽事發生和有哪些widget的作用會做。啟動xman,移動指標進入
Help 盒,你會看到盒的外框變成高亮度 -- 這是highlight() 在作用。將指
標移出,盒的外框恢復正常 -- 這是unhighlight() 作用。將指標再度移入
Help 盒,按下一個滑鼠按鈕,保持按住不放。則盒內的色彩反轉 (盒內的文
字變成預設的背景色,而原來視窗的背景變成視窗的前景色)。-- 這是set()
在作用。繼續保持按住滑鼠按鈕,將指標移出視窗外,盒內色彩恢復正常 --
這是reset() 在作用。一個正常 "碰觸一下" (clicking on) Help盒的次序為:
1. 移動指標進入盒中:highlight()將外框變為高亮度。
2. 按下按鈕:set() 反轉盒中的色彩。
3. 松開按鈕:notify()開始作用,造成程式建立求助視窗(help window)
。在進行中時,盒的色彩保持反相。當視窗建立完成之後,reset()反
轉盒內的色彩為正常,但外框仍保持高亮度。
4. 將指標移出視窗:unhighlight()將外框恢復正常。
現在你了解了有哪些作用,我們將定義一些轉譯來改變原先進出視窗的作
用:
*Command*translations: #override\n\
: reset()\n\
: set()
用這個奇怪的轉譯表,當你一開始移動指標進入盒中,什麽事也不會發生,但
當你移出指標時,色彩會反轉。如果你再度移動指標進入盒中,色彩會變回正
常。其它的作用和前述相同。
使用修飾鍵來修飾事件規格
有時你指定的轉譯希望能同時按下一或多個修飾鍵 (modifiers) ,例如你要系
結一個作用到和META鍵同時按下的一個鍵,或是當CTRL和SHIFT 同時按下的滑
鼠按鈕。到目前為止我們還沒有任何辦法可指定如此。我們不能用事件序列達
成這點,因為它是依序定義的,而我們需要的是指定同時,例如 "按下X 鍵且
CTRL鍵同時被按下"。
欲在轉譯中指定修飾鍵,你只需在事件名稱之前加上你所需的修飾鍵名。
例如在xterm 中,定義meta-i為 "貼" 上一次 "剪" 的本文,使用:
*VT100*Translations: #override\
Meta i: insert-selection(PRIMARY, CUT_BUFFER0)
因為這種修飾鍵/事件型態的組合十分常見,轉譯管理器允許使用一種縮寫的
形式。相等於上面第二列的寫法為:
i: insert-selection(PRIMARY, CUT_BUFFER0)
我們可以對滑鼠事件做同樣的處理。讓我們對xedit 定義轉譯,使得使用
滑鼠可以在本文上方便地移動,我們首先的嘗試如下:
*Text*Translation: #override\
Shift : forward-character()\n\
Shift : forward-word()\n\
Shift : next-line()\n\
Ctrl : backward-character()\n\
Ctrl : backward-word()\n\
Ctrl : previous-line()
如果你測試它,奇怪的現象會發生 -- 游標好像會自行其是,而且本文的片段
會一下子被選擇,一下子又取消選擇。發生這種現象的原因是Text widget 的
預設系結仍然會作用,它包含的轉譯像:
: extend-end(PRIMARY, CUT_BUFFER0)
你可能認為這不會影響你,因為當你松開按鈕時你總是按著SHIFT 鍵或CTRL鍵
。但事實上會作用:轉譯管理器對於你未定義的修飾鍵解釋為你不在乎它們的
影響,所以松開Button1 時會對應到上述的規格。為了克服這點,我們對那些
可能不小心便會發生的按鈕松開事件定義轉譯,並系結到一個空 (null) 作用
。這些轉譯當被對應到時會蓋掉預設的轉譯。對使用Text widget 我們需再增
加兩列,才是一個完整的轉譯表:
*Text*Translation: #override\
Shift : forward-character()\n\
Shift : forward-word()\n\
Shift : next-line()\n\
Ctrl : backward-character()\n\
Ctrl : backward-word()\n\
Ctrl : previous-line()\n\
Shift : do-nothing()\n\
Ctrl : do-nothing()
這解釋了下列幾點:
.我們對滑鼠事件使用了縮寫的語法,也就是先前的語法像Button1
取代。轉譯管理器容許一些縮寫的語法存在。 (我們在前
面看到的 也是一例)。
.我們用 do-nothing() 當作一個啞 (dummy)作用,就好像它是列在Text
widget的文件中一般。事實上這個作用是不存在的,因此會導致錯誤的
訊息出現,但因為我們本來就是要用它來什麽事也不做的,所以無需介
意。
.對於我們方才指定的啞作用,我們用了一個事件 便代表了三個
按鈕。相同地,轉譯管理器把從缺的修飾規格的解釋為 "對任何",在一
個事件中缺少細節部份 (例如在規格"Button1"中"Button1"的部
份) 解釋為 "對任何所有的細節部份"。
這點在轉譯中有一個非常常用的形式為:
: ...
因為缺少細節部份,所以可被用於所有按下鍵 (key-press)事件,也就
是對所有的鍵。事實上在Text widget 上有一個預設的轉譯為:
: insert-char()
insert-char()作用的功能為當一個鍵被按下時,插入相對應的ASCII字
元。
17.1.4 復合的轉譯表及□例
到目前為止,我們把所有的轉譯均應用於整體的widget類別。但你能對個別的
widget指定轉譯,就如同resource一般。在此我們將對xman定義更多的轉譯。
我們將對Help盒widget (對應作用到助憶(mnemonic)字元)只用到鍵盤事件,對
Quit盒只用到視窗事件。為了達到此點,我們將對轉譯應用到的widget 給予明
確的名稱。我們的轉譯表如下:
*Help*translations: \
h: highlight()\n\
u: unhighlight()\n\
n: notify()\n\
s: set()\n\
r: reset()\n\
LineFeed: set() notify()
Quit*translations: #override\n\
: reset()\n\
: set()
有幾點特別的語法需要注意:
.在此我們對相同類別中不同的widget指定不同的轉譯,所以我們需要知
道成員 (instance) 名稱。不幸的是,這些成員名稱 (Help,Quit,
Manual Page)並不明顯。如果它們在文件中找不到 (本例即找不到),那
你只能用猜的或是去查看原始程式了。
.對於Help,我們省略了常用的#override,因為我們對此widget不需要考
慮任何預設的系結。特別的是,當指標進入視窗時,我們不要此widget
呈現高亮度,如此我們才能看出這個轉譯的效用。
.由於省略 #override,我們將這個轉譯規格移至第一列。(如果不這麽作
,而且對第一列仍以\n\ 作結束,我們將得到錯誤:
X Toolkit Warning: translation table syntax er-
ror: Missing ':' after event sequence.
X Toolkit Warning: ... found while parsing ''
因為\n是用來區隔轉譯規格或類似像 #override 指令的)。而將此列和
第一個規格以隱藏的新列字元區隔,就如同:
*Help*translations: \
h: highlight()\n\
...
.對LineFeed那一列的轉譯,包含了復合的作用,和前面xterm 中復合的
string()作用類似。
我們已大致涵蓋了你所常用的轉譯。基本的概念很簡單,生成它們的結構
也不復雜,但它們非常的令人迷惑。原因是它是一個發展中的糸統,隨著發行
版本所附的文件並不是很多。下一節重復本節所述的,本節均以例子來介紹觀
念,下一節我們將對轉譯的規則,作比較正式的描述。
17.2 轉譯 -- 格式和規則
轉譯是一個由Toolkit 提供的一般性結構,它讓使用者指定當某些特定的事件
由widget接收到時,一個widget應完成何種作用。Toolkit 中處理轉譯的部份
被稱之為轉譯管理器。
轉譯由widget指定,它的確是一個widget的每一個成員。一個轉譯的集合
稱之為一個轉譯表,而這個表藉著標准的resource結構傳遞給應用程式。widget
(對轉譯而言意味深長) 會有一個Translation 類別的resource屬性,通常的
成員名稱為translation。這個轉譯resource期待的一個值即為一個轉譯表。就
像所有其它的resource一般,你可以在同一個應用程式對不同的widget指定不同
的resource,而且你能以類別名稱或成員名稱或二者混合來指定它們。
每一個widget定義了它所提供的作用,不論是在數量或型態上,它們都是
極富變化的。
轉譯可被各種不同型態的事件指定,不僅只於鍵盤和滑鼠事件而已。任何
序列的事件均能被處理,就如同單一事件一般。
轉譯和轉譯表在 " X Toolkit Intrinsics " 使用手冊附錄B一節中,有
簡潔地描述。它不是初學者查看轉譯的好地方,但它含有完整的事件型態、修
飾名稱等等的表列,在此不再贅述。
17.2.1 轉譯表的格式
一個轉譯表大體上的格式如下:
[optional-directive\n] list-of-translations
每一個 list-of-translations 由一或多個轉譯組成,格式如下:
event-sequence : list-of-actions
當event-sequence發生時,規格中的list-of-actions 會由widget所完成。如
果在一個表中,有多於一個的轉譯,每一個需以 "\n" 區隔開。
我們首先來看一下選項的指令,然後看一下list-of-translations的細節
部份。
17.2.2 轉譯指引 -- #override 等等
選項指引 (directive) 告訴轉譯管理器,它應對任何已設定之相關widget在此
轉譯集合中應如何處理。
#replace : 清除所有現存的對應,只采用在轉譯表中所含有的。(只使用新
的)。
#override : 強制留下現有的對應,加入轉譯表中。如果在表中有任何項
目設定,舊有的即被覆寫。也就是說,舊有的被新有的取代。 (結合
舊有的和新的,但新的比較重要)。
#augment : 強制留下現有的對應,加入轉譯表中。如果在表中有任何項
目設定在現有的設定存在,使用舊的而忽略新的。 (結合舊有的和新的
,但舊的比較重要)。
如果未設定指引,預設為 #replace 。
17.2.3 個別的轉譯規格格式
每一個轉譯的格式為:
event-sequence : list-of-actions
讓我們來看一看此規格的兩個部份。
事件和事件序列(event-sequence)的格式
一個事件序列包含一或多個事件規格(event-specs), 其格式為:
[modifiers] [repeat-count] [detail]
除了事件型態(event type)外,均為可選擇。(<>中為必需)。
modifiers : 這是基本設計中比較精巧的部份,我們在下一段說明。
event-type : 指定我們有興趣的事件的型態,例如按鍵()、
松開按鈕()或指標離開視窗()等等。
detail : 指定我們有興趣的特定型態。如果你省略細節欄(detail field
),事件規格將對應到任何detail,如此,將對應到所有的按鍵
事件。此格式指定到每一個事件型態。對指定事件型態的細節欄為:
.對事件,細節如果不是鍵的名稱(例如
"s"),便是 keysym (keysym是按鍵以開頭為"0x"的十六進位
數表示,將於下一章詳細解釋)。
.對於按鈕事件,細節就是按鈕的名稱,也就是 Button1 ... Button5
中的一個。例如我們先前使用過的"Button1"。
型態/細節的縮寫:常用於轉譯管理器的一些事件型態和細節的組合,允許
你對它們使用縮寫:
縮寫 相等的全名
Button1
...
Button5
Button1
...
Button5
repeat-count : 這指定了事件需要的次數。如果被指定,它們被包含在
括弧之中。例如:
(2)
指定需對一號按鈕(button-1)碰觸兩次。如果你在後面再加上加號(+)
,其意為碰觸的數目需大於或等於指定。例如:
(3+)
意為需碰觸三或更多次。預設的重復次數為一次。
一個事件序列以一或多個事件規格組成,以逗點分開。當這個事件的序列
在其widget發生時,相關的作用便會運作。
當序列發生時,轉譯管理器會根據一些規則決定它自己是否被滿足。我們
用一個例子以便仔細地觀察,假設你對兩個字元序列set 和unset定義了轉譯:
.概略地說,如果個別的事件依序發生,轉譯管理器會被滿足,其它的事
件 (那些你未指定的事件) 如果在指定的序列中間發生,不會妨礙序列
被滿足。例如,set 可被sweat 和serpent 對應。
.如果介於其間的未指定事件,啟動了轉譯表中的另一個事件序列,轉譯
管理器會放棄原先的序列,而嘗試著去滿足新的序列。例如,set 不會
被sauerkraut對應,因為u 會使得轉譯管理器對應到unset。
.如果在一個事件的集合中有超過一個的事件序列發生,轉譯管理器只會
應用到一個轉譯:
- 如果一個序列對應到結束 (右端),較短的那個序列只有在不包含於
較長的序列才會發生。所以如果unset 被對應到,對set 轉譯將不會
作用。
- 如果一個序列是在另一個序列的中間發生,例如,如果你定義序列
at和rate,則較長的那個永遠不會被對應到。
事件修飾鍵
修飾鍵 (modifiers)是一些鍵或按鈕,系指當主要事件發生時,那些必需被按
下才會讓轉譯管理器滿足的鍵或按鈕。你可以對鍵、按鈕、移動、進出視窗等
事件指定修飾鍵。常見的修飾鍵為:
Button1 ... Button5
Ctrl Shift Meta
Lock
如果你未指定任何的修飾鍵,轉譯管理器會解釋為: "當事件發生時,不
論修飾鍵是否被按下,均會被接受"。例如,會被滿足,不論當時
SHIFT 或META鍵是否有被按下。
如果你真的需要指定 "只有在沒有修飾鍵被按下時才接受此事件"。則需使
用虛擬修飾鍵 (pseudo-modifier) None。例如,None 會使得當按
鈕按下時若META鍵也被按下則不會滿足。
對一個事件指定一些修飾鍵意為 "只要符合轉譯中指定的修飾鍵,其它的
修飾鍵不需介意"。它並沒有 "一定要完全恰好符合才可以"的意思。例如,
Ctrl a 在你按下 meta-ctl-shift-a 時仍會被滿足。
如果你真的要指定 "只有剛好符合修飾鍵的才要",在修飾鍵之前加一個驚
歎號 (!)。例如,!Ctrl a 在你按下 meta-ctl-shift-a 時不會被滿足。
對一個修飾鍵的集合 (可能是空集合) 作限制,意為 "除了這些修飾鍵不
不接受",需要在不接受的修飾鍵之前加一個(~)號。例如,Shift~Meta t
會被ctl-shift-t滿足,不會被meta-shift-t滿足。
鍵事件通常忽略大小寫,如果你要區分,需在之前加一個冒號(:)。例如,
不論 H或 h均可符合H,但只有H 才符合 :H。
就如同對常用的事件型態/細節配對有縮寫一般,轉譯管理器對常用的修
飾鍵/事件型態配對同樣地提供縮寫:
縮寫 相等的全名
Ctrl
Shift
Meta
Button1
...
Button5
任何按鈕的
作用的格式和作用的表列
每一個轉譯在一或多個作用之上系結一個序列的一或多個事件。在表列中的個
別作用是以空白分開的。 (不可用逗點分開,那將會導致錯誤)。
個別的作用格式如下:
action-name(parameters)
即使沒有參數被指定,在作用名稱 (action-name)後的括弧,仍然不可省略。
例如:
start-selection()
如果在作用名稱和左括弧中間留有空白,你將會得到一個錯誤。
作用名稱只包含了字母、數字、錢號($)、底線(_)四種字元。每一個widget
提供它自己的作用集合 (如果有的話) ,且自我包含這些作用名稱的硬碼
(hard-coded)表列。
參數(parameters)是一個零到多個字元字串的表列,中間以逗點分開。參
數的意義為對特定的作用作指定 (事實上大多數的作用並沒有任何參數) 。參
數字串可以不加引號,例如:
insert-selection(PRIMARY)
或者前後加上雙引號,這種情形通常為參數字串內包含了空白或一個逗點,例
如:
string("plot")
沒有一個一般性的方法,讓你在參數字串中的任何位置包含一個雙引號,雖然
像這樣 string(ab"cd)'將雙引號放在字串中間是可被處理的。也沒有一般性的
方法在同一個參數字串中同時包含字串和雙引號。因為如此,有些widget在解
釋它們自己的參數時,可以自行加入它們自己的語法規則。例如:對xterm 的
VT100 widget的 string()作用,如果一個不帶雙引號且開頭為 "0x"的字串,
此字串被解釋為代表一個ASCII 字元的十六進位數。
在此結束我們對轉譯規格及格式的描述。由此,你應有能力了解在不同X
手冊列出的轉譯,且可寫你自己的轉譯。為了幫助你,下節列出你常見的問題
,以及如何克服它們。
17.3 在轉譯規格中常見的問題
轉譯在觀念上簡單,但實際上很混亂。即使你常常使用,語法仍然復雜而難解。
無論如何,如果你是初學者,最好的方式是你以別人的轉譯當作自己的轉譯的
基礎。在指南頁中有幾個對xbiff、xdm(目前尚未介紹過,將於第20章介紹
)、xterm 的轉譯□例,將對你有所幫助。
如果你發現你的轉譯有錯誤的話,有幾點值得去檢查:
.轉譯只能應用在使用Toolkit的程式上。如果你試圖對非Toolkit應用程
式定義轉譯,看起來不會有任何問題,只是轉譯不會作用而已。
讓我們來看一下為什麽,以對xcalc (這是一個非Toolkit程式)使用轉譯
為例。你對一個resource名稱像 *xcalc*translations定義一個轉譯表,
且用xrdb載入至你的資料庫。xrdb並不會抱怨,因為它不知道是那一個
應用程式使用到resource,它只會設定資料庫,稍後供Resource Manager
查詢。現在你執行xcalc ,它對轉譯是一無所知,所以不會向資料庫查
詢轉譯,當然也絕不會編譯它們了。
.不要省略 #override,除非你確實知道你要做什麽。如果你因錯誤省略
它,例如在xedit 中,你將發現沒有任何的鍵可輸入任何的東西 (因為
預設的轉譯 ":insert-char()"被去掉了)。
.檢查你對每一列均有終結。如果你在轉譯表中的一列忽略了"\n\"或"\n"
,在其後所有的轉譯都會被忽略。如果你在最後一列的末端加上一個倒
斜線(\) ,或是省略了檔案中最後一個新列字元(newline),整個轉譯表
都會被忽略。(不過這是xrdb的問題,而非轉譯管理器的問題)。
這種錯誤在你編輯一個現存的轉譯表時特別容易發生。
.當你定義的轉譯和預設有沖突時,可能會導致奇怪的行為,特別是對滑
鼠按鈕事件,每一次按下或"Down"事件,會相關到一個松開或"Up"事件
,當你對此部份沒有明確定義時,可能會有一個預設的系結仍然存在,
(鍵盤的按下和松開也是成對的事件) .所以:
1.檢查預設系結的文件。
2.如果你只對按下/松開配對的一半指定一個轉譯,確定另一半並非預設
轉譯的一部份,如果是的話,需對它明確地指定一個轉譯。
3.如果你仍然不能解決,暫時由表中移去#override,這將去掉所有的預
設轉譯,讓你了解問題是由於和預設轉譯沖突所造成,還是因為你的
轉譯表有錯誤。
.轉譯管理器對語法不正確的問題,無法很好的告訴你原因何在。例如如
   果你有一個轉譯像:
F6: string("abc""def")
參數的語法並不正確,F6鍵將沒有作用,但你也看不到錯誤訊息。
.如果你轉譯一序列的事件,且需要對每一個均指定修飾鍵,你必需明確
地對每一個都指定。例如如果你需要一個轉譯使用ctl-X ctl-K:
Ctrl X, Ctrl K: ...
而如果你使用:
Ctrl X, K: ...
你的指定為 ctl-X K
.檢查你所需的widget是否有你指定的名稱和類別。例如對xterm ,你可
以在一個表的開頭指定:
xterm*Text*translations:
這將什麽事也沒作,xterm 正規視窗widget的類別VT100。通常,不論
xrdb或轉譯管理器均不會有反應,因為看起來沒錯。
.轉譯可能指定正確,也可以工作,但它的作用和你預期的不符。例如對
xterm 的轉譯:
Meta Ctrl m: mode-menu()
是正確的,且會工作。但mode-menu()實際上檢查滑鼠左或中按鈕是否有
招喚它,其它方面不做任何事。
.在一個轉譯中不指定修飾鍵,並不意味著當修飾鍵按下時轉譯會無效。
它真正的意義為: "我並不在乎有沒有修飾鍵" 。如果需要的話,使用
"None",""或!符號。使用時要小心預設的轉譯是否會妨礙到你。
.轉譯是針對widget而指定的,所有在轉譯中的作用必需由widget提供。
在你指定轉譯resource名稱的地方很容易忘掉這一點。例如:
xman*translations: \
: reset()\n\
: set()
將導致許多錯誤:set()和reset()作用只有被Command widget定義,但
xman有數種其它型態的widget可接受轉譯,且轉譯管理器會抱怨這些
widget並未提供set()和reset()。解決之道為更完整些的指定resource
名稱,例如在本例為 xman*Command*translations 。
.對任何給定的resource,當resource資料庫被詢問時,Resource Manager
會傳回一個值給widget,這個傳回的值的 "特徵值" (characteristic)
(resource名稱)大多與widget的和屬性的完整類別/成員名稱相符。所
以你對所有的Text widget指定一個一般性的轉譯後,又對xedit指定一
個轉譯,希望它們並存是不可能的,只有一個轉譯表會傳給widget。例
如:
*Text*Translation: #override\
(對Text一般性的轉譯)
...
xedit*Text*Translation: #override\
(對xedit 的Text特定的轉譯)
...
你只能得到在xedit 中特定的轉譯,或是在別處得到一般性的轉譯。
#override 會有所混淆,它的意義為 "把轉譯加入現存的之中" 。但這
完全由轉譯管理器處理,當時候到時,轉譯管理器會決定傳遞哪個值給
由Resource Manager所造的widget。對Resource Manager而言,#override
只是傳遞給widget值的部份中的一個文字字串而已。
因為你使用resource來指定轉譯,所以錯誤可能在兩個領域均會發生。為
了減少錯誤的□圍,當你對轉譯頗有經驗時,在你已載入轉譯resource之後,
最好能明確地列印出你的resource資料庫。例如:如果你對xprog 寫入轉譯,
且轉譯在檔案mytrans 中,以下列命令來執行程式:
xrdb mytrans xrdb -q xprog ...
17.4 結論
這漫長的一章涵蓋了被X Toolkit 所使用的標准轉譯結構,它讓你指定
按下一個鍵或按鈕會有什麽影響。這些轉譯指定到每一個widget,且你藉著使
用標准resource結構傳送轉譯表給widget。你看到如何對一個鍵盤的鍵、滑鼠
按鈕和其它像移動一個指標進入視窗的事件作指定轉譯。然後我們藉著指定不
同狀態的修飾鍵所造成的影響,比較嚴謹地定義我們需要轉譯的事件。
本章的第二個部份涵蓋相同的領域,但較為正式,且詳細解釋在轉譯規格
中,可用到的語法,特別是修飾鍵。
最後,我們簡列使用轉譯常見的問題,及一些如何解決它們的建議。
本章包含了許多材料。它們運用了極少的觀念,但語法復雜,易生錯誤,
且不顯而易見。如果一開始覺得困難,不必擔心。從一些簡單的轉譯著手 (也
許是xterm),且以指南頁中的□例或別人的轉譯表為基礎來發展修改。當你有
經驗之後會進展快速;你將洞悉語法且能看出其後會發生什麽狀況。
Copyright © Linux教程網 All Rights Reserved