当前位置:Linux教程 - Linux - X-windows 系统使用指南(17)

X-windows 系统使用指南(17)



         第17章 定制你的键盘和滑鼠 -- 转译

    17.1 实际使用转译
    17.2 转译 -- 格式和规则
    17.3 在转译规格中常见的问题
    17.4 结论

    第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 的 Translation 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()实际上检查滑鼠左或中按钮是否有
    招唤它,其它方面不做任何事。

    .在一个转译中不指定修饰键,并不意味著当修饰键按下时转译会无效。
    它真正的意义为: \"我并不在乎有没有修饰键\" 。如果需要的话,使用
    发布人:netbull 来自:嵌入式Linux