如何为定义 GNU 屏幕“命令字符”提供全面的可能性?

kjo*_*kjo 6 gnu-screen keyboard

我想以某种方式生成一个全面的“菜单”,其中包含为标准的、现成的“美国键盘”和特定的终端模拟器(例如xfce4-terminal )设置 GNU 屏幕“命令字符”的所有可能方法。

我想象这个充满可能性的世界会分解成三个列表:

  • 列表A:escape指令的所有可能值
  • 列表B:<CODE>表达式中参数的所有可能值bindkey -k <CODE> command,以及“空设置”(即.screenrc未使用bindkey -k <CODE> command指令的配置)
  • 列表C:从任何对(a,  b)(其中a  ∈  A和b  ∈  B)到一个关于如何在标准美国键盘上键入相应的 GNU 屏幕命令字符的明确描述的映射,并假设一个特定的终端模拟器(IOW,相当于,例如,“同时按下Ctrl和\”)。

但是请记住,这些规范是真正不了解底层基础知识的人(我)的“最大努力” 。我希望那些确实了解这些基础知识的人能够“从字里行间阅读”,并根据需要修改这些规范,同时仍然保留问题的精神(参见背景),使问题易于处理。

我意识到我希望的“菜单”可能非常大,但我认为它不可能如此棘手,因为毕竟标准美式键盘上的键数是有限的,而且并不多,而且可以用于此目的的一组手指更是如此。(以防万一,我可以进一步规定我只对最多包含 2 个连续“键和弦”的键组合感兴趣,每个键和弦最多 3 个键。“键和弦”我的意思是“设置要同时按下的键”。)


背景

(又名 tl;博士)

这个问题实际上是 Gilles 在我之前开始的一个线程中的评论的后续。事实证明,该评论所说的大部分内容都超出了我的理解范围。我认为我对这里的基础知识的理解存在一些巨大的差距,事实上如此之大,以至于我什至无法表达足够清晰的问题来填补它们。

简而言之,对我来说,这是一个巨大的谜团,例如,组合键Ctrl+\可用于为 GNU-screen 键入“命令字符”,而其他外观相似的组合键,例如 (maybe) Ctrl+ ',则不能1 .

如果用户(像我一样)对底层基础知识没有清晰的理解,那么寻找合适的 GNU 屏幕命令字符就会简化为一系列孤立的建议(“ +怎么样?毕竟,没有人将它用于其他任何事情。CtrlH ") 用户依次评估,直到弹出一个可接受的。

这一系列建议和评估需要持续多长时间取决于该用户可接受的组合键集的大小。显然,这个大小会因一个用户而异。就我而言,它似乎比平均值小,因此这种方法还没有给我一个可接受的 GNU 屏幕“命令字符”。

无论如何,在我看来,这种方法本质上是低效的。能够从明确的“宇宙”(即“详尽的集合”)可能性中选择最佳选项对我来说更有意义。这就是我想要在这里得到的。


编辑:好的,经过一些学习,我现在清楚地了解了如何在\0001和之间的 ASCII 范围内键入(1 字节)字符\0177,包括。这些包括所有“真正的”“控制字符”。

此外,我认为列表A可以描述为\0001和之间的所有可能的整数对\0377,尽管其中许多对可能完全不切实际。(例如,该对的第一个元素是常见的“可打印字符”,例如“e”或“8”)。

我仍在试图弄清楚以下几点:

  • 如何在ASCII范围键入(1字节)字符\0200于\0377,包括端值; 我预计终端和终端仿真器之间会有一些变化,但目前我不知道变化有多混乱;是否有这些角色的子集达成了实质性共识?如果是这样,我很想知道这些字符是什么(以及如何输入它们)

  • 如何获取列表B 的有用值;我意识到这些值是termcap代码;我在这里的困难是没有办法识别那些termcap巧妙地映射到一个方便的组合键的代码;例如,我知道代码F2映射到F12(原文如此),但我想大多数termcap代码与单个键没有如此巧妙的关联。

  • 如何完成列表C,即使对于特定的终端仿真器,以及列表B 中的“空设置” 。


1请不要试图向我解释这个谜:许多知识渊博、非常耐心的人已经尝试过,但我仍然不明白。那些了解正在发生的事情的人和我之间的“知识鸿沟”是如此之大,以至于他们的答案总是像他们想要解决的那样让我感到困惑。我希望通过这篇文章实现的正是解决这个巨大的知识差距,通过将问题转换为搜索,本质上,可以通过甚至可以实现的算法(构建规定的有限可能性集)不了解底层基础知识的人。

Gil*_*il' 7

要理解这个问题的答案,您需要对键盘输入的处理方式有一定的了解。我向您推荐键盘输入和文本输出如何工作?为背景。在这个答案中,我将以不同的方式解释相关部分,但我会假设我之前的答案给出了一些普遍的熟悉度。

我在这里的回答涉及典型的 unix 系统;非 Unix 系统的行为可能有所不同。我会在这里和那里做一些简化;额外的复杂性与回答这个问题无关。(这个答案已经足够复杂了。)

大多数通信和存储,包括基于终端的应用程序和终端(硬件或软件)之间的通信,都采用字节流的形式。一个字节是一个信息单位,可以取 256 个不同的值;它可以细分为 8位。字节由 0 到 255 之间的数字表示。

为了传输信息,各方需要就将该信息编码为字节的方式达成一致。有多种方法可以将字符流编码为字节流,但所有这些方法都以一种或另一种方式基于ASCII。ASCII 定义了从 0 到 127 的 7 位值与一组 128 个字符之间的对应关系;这会在每个字节中留下一个未使用的位。这 128 个字符分为两类:

  • 95 个可打印字符:字母(A-Z、小写和大写)、数字 (0-9)、空格、一些标点符号;
  • 33 个控制字符。

控制字符对发送到终端或从终端发送的命令和辅助信息进行编码,例如“将光标移动到下一行”、“按铃”、“等我”、“再见”等。 历史终端引入了一个标记为“的键” Control”(或简称“Ctrl”),允许用户输入控制字符。为了保持终端的电子设备简单,Ctrl与一个键一起按下将在字符通常发送的字节值中执行一个简单的位掩码。比如A发送A字节65(二进制1000001)所代表的字符;Ctrl+A发送由字节值 1(二进制为 0000001)表示的字符,称为“control-A”字符,通常写作^A.

大多数控制字符对应一个大写字母,位模式为 10xxxxx,第 6 位设置为 0 而不是 1。这占了其中的 26 个。还有 6 个控制字符对应于同样具有 10xxxxx 形式的位模式的标点字符:这些是@[\]^_(请参阅ASCII 可打印字符表。除了 0-31 范围之外,字符 127 也是一个控制字符;它是已知的作为“控制-?”(?是 0111111;控制-?是 1111111)。

多年来,非 ASCII 字节值被赋予了不同的含义。世界正在趋同于Unicode作为任何人可能想要的所有字符的集合。Unix 世界(以及 Internet)主要将UTF-8标准化为一种将字符编码为字节序列的方法。UTF-8 通过将与 ASCII 相同的字符分配给 0-127 范围内的任何字节,并使用 128-255 范围内的 2 到 4 个字节序列来表示一百万左右的其他字符,从而保持与 ASCII 的兼容性。unix 世界中还使用了一些其他字符编码;大多数基于 ASCII 并且对于 128 以上的字节有不同的含义。

我现在可以回答您的后续问题之一:

如何键入 ASCII 范围内的(1 个字节)字符\0200以\0377

这取决于您使用的字符编码。如果您使用最常见的 UTF-8,发送这些单个字节是不可能的,因为它们仅用作表示单个字符的 2 到 4 个字节序列的一部分。

至于

列表 A:escape指令的所有可能值

那只是字节值。该escape指令需要一个两字节的参数。如果 Screen 从终端接收到第一个字节值,它决定它的转义键已被按下。如果终端发送的下一个字节是设置中的第二个字节escape,则 Screen 决定您最终要将第一个字节发送到在 Screen 窗口内运行的应用程序。

bind命令的描述解释了如何以 Screen 理解的方式指定字节值。在文档读取“字符”的地方,改为读取“字节”。

在我们列出 B 之前,我们需要了解主和弦。甲keychord是一个密钥一起的与改性剂如冲压Ctrl,Shift等。我们前面所看到的,通过所述终端发送的所有信息被编码为字节流。为简单起见,所有可打印字符都以标准方式编码,如果它们是 ASCII 字符,则为 32-126 范围内的一个字节,其他字符则为 128-255 范围内的字节。这仅留下控制字符来编码功能键和带有除Shift.以外的修饰符的字符。但是只有33个控制字符!

一些功能键发送一个控制字符。例如,Tab键发送^I(字节值 9),因为字节 9 是 TAB 控制字符,指示打印机移动到下一个选项卡列。的Return密钥发送^M(字节值13),因为字节13是指示打印机以它的头部移动到行的开头的CR控制字符。出于类似的原因,Escape发送^[和BackSpace发送要么^H或^?由于一些我不会在这里讨论的历史胡说八道。

大多数功能键和键和弦都会发送一个转义序列:从字节 27 开始的字节序列,即由 ASCII 定义的转义字符(ESC),恰好是^[(control-[)。不同的终端发送不同的转义序列。有标准,但它们并没有为所有键和弦定义编码,远非如此,并且在某种程度上存在相互竞争的标准。

我们现在准备好理解

列表 B:<CODE>表达式中参数的所有可能值bindkey -k <CODE>

该屏幕文档解释了这些代码是termcap的键盘功能名称。Termcap 是一个编程库,应用程序可以使用它从终端之间的差异中抽象出自己。(现在大部分已经被Terminfo取代了。)Termcap 数据库专门包含了关于终端的信息,比如行数和列数(在 Termcap 出现的时候,终端是硬件设备,没有调整大小的概念) ,应用程序可以用来执行诸如移动光标或清除屏幕等操作的字节序列(通常以 ESC 开头),以及由各种键发送的字节序列。Termcap 赋予功能键的符号名称是您可以在bindkey -k.

该TERMCAP手册列出该数据库中所有条目。这些条目都有两个字符的名称;FreeBSD 手册还为每个条目提供了一个更具表现力的名称。FreeBSD在第一列中列出的条目是描述功能键的条目;在你需要的是在第二列的名称,如对,对,对,等等。key_SOMETHING<CODE>bindkey -kklLeftk1F1F1F11

您会注意到该数据库缺少很多键和弦。如果此数据库中没有键和弦的条目,则没有可用于带有 .key 的键的名称bindkey -k。请注意,受支持的密钥集因 unix 变体而异。

bindkey也可以传递一个转义序列。要使用此功能,您需要知道您的终端为您感兴趣的键和弦发送了什么。虽然不同的终端为同一个键和弦发送不同的转义序列,但幸运的是,从一个转义序列到另一个键和弦很少有歧义:很少有转义序列对应不同终端上的不同键和弦。

您可以通过按Ctrl+V然后按键和键来找出键和键发送的转义序列。在默认模式下的终端中,以及在所有常见 shell 的命令行上,Ctrl+V表示“按字面解释下一个字节”。如果它后面跟着一个转义序列,这会导致按字面插入 ESC 字节,而不是启动对转义序列的解析。由于转义序列几乎总是由 ESC 之后的可打印字符组成,因此这有效地按字面插入了转义序列。例如,按Ctrl+V然后Ctrl+Left以查看转义序列Ctrl+Left发送的内容:您将看到类似^[O5Dwhere^[是 ESC 控制字符的可视化表示。(再一次,您的终端可能会发送不同的转义序列。)

至于 null 设置,当 Screen 读取一个 ESC 字节时,它进入转义序列解析模式。每个新字节都被添加到累积的转义序列中。如果累积序列具有关联的绑定,则 Screen 退出转义序列解析模式并触发绑定。如果累积序列不是具有关联绑定的任何序列的前缀,则 Screen 退出转义序列解析模式并丢弃累积序列。所以这里的 null 设置是一种“什么都没有发生”的复杂形式。

完成所有这些工作后,让我们转向

列表 C:从任何对 ( a , b )(其中a ? A和b ? B)到明确描述如何在标准美国键盘上键入相应的 GNU 屏幕命令字符的映射,并假设一个特定的终端模拟器

正如我上面所暗示的,特定的终端模拟器在这里很重要:不同的终端以不同的方式对键和弦进行编码,并且一些终端可以以不同的方式进行配置。该映射不对应于一对 ( a , b ):A × B不是一个有趣的集合。大多数键和弦被映射到可打印字符(如我们上面所见,扩展A)或转义序列(如我们上面所见,扩展B)。换句话说,映射是到A的超集?乙。

对您来说不幸的是,许多终端没有完整记录如何发送转义序列。幸运的是,这很少需要。不是从转义序列到键和弦,而是从键和弦到转义序列。如上所述,可以使用Ctrl+为每个终端确定这一点V。

一些终端,特别是 xterm,可以配置为以系统的方式编码键和弦。有关Emacs 的讨论,请参阅使用终端时的键绑定问题。不幸的是,这不包括许多终端模拟器使用的 vte 库,尤其是在 GNOME 世界中。