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

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

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

我想象这个充满可能性的宇宙将分解为三个列表:

  • 列表Aescape:指令的所有可能值
  • 列表<CODE>:表达式中参数的所有可能值bindkey -k <CODE> command,以及“空设置”(即.screenrcbindkey -k <CODE> command使用指令的配置)
  • 列表C: 任意对 (A) (在哪里A ε A, 和 ε )到一个明确描述如何打字标准美国键盘上相应的 GNU 屏幕命令字符,并假设有一个特定的终端仿真器(IOW,相当于“同时按下Ctrl\”)。

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

我意识到我希望的“菜单”可能非常大,但我认为它不会那么棘手,因为毕竟标准美国键盘上的按键数量是有限的并且不是巨大的,并且可以用于此目的的一组手指更是如此。 (如果重要的话,我可以进一步规定,我只对最多由 2 个连续的“主和弦”组成的键组合感兴趣,每个主和弦最多有 3 个键。我所说的“主和弦”是指“设置同时按下的键的数量”。)


背景

(又名 tl;博士)

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

简而言之,对我来说这是一个巨大的谜团,例如,组合键Ctrl+\可以用于键入 GNU 屏幕的“命令字符”,而其他类似的组合键,例如(也许)Ctrl+ ',则不能1 .

如果用户(像我一样)对底层基础知识没有清晰的了解,对合适的 GNU 屏幕命令字符的搜索就会简化为一系列孤立的建议(“Ctrl+怎么样H?毕竟,没有人将其用于其他用途。”),用户依次评估,直到弹出可接受的结果。

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

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


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

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

我仍在尝试弄清楚以下问题:

  • \0200如何键入 ASCII 范围内的(1 字节)字符\0377(含);我预计终端和终端模拟器之间会存在一些差异,但目前我不知道这种差异有多么混乱;这些角色中是否有一个子集已达成实质性共识?如果是这样,我很想知道这些字符是什么(以及如何输入它们)

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

  • 如何完成列表C, 甚至对于特定的终端模拟器,以及列表中的“空设置”


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

答案1

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

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

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

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

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

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

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

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

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

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

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

至于

清单Aescape:指令的所有可能值

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

的描述bind命令解释如何以 Screen 理解的方式指定字节值。如果文档中显示“字符”,请改为“字节”。

在我们进入列表 B 之前,我们需要了解键和弦。键和弦是按下一个键以及诸如CtrlShift等修饰符。我们之前看到终端传输的所有信息都被编码为字节流。为了简单起见,所有可打印字符都以标准方式编码,如果它们是 ASCII 字符,则编码为 32–126 范围内的一个字节;对于其他字符,编码为 128–255 范围内的字节。这样就只剩下控制字符来编码功能键和带有除 之外的修饰符的字符Shift。但控制字符只有33个!

一些功能键发送控制字符。例如,Tab按键发送^I(字节值 9),因为字节 9 是 TAB 控制字符,指示打印机移至下一个选项卡列。键Return发送^M(字节值 13),因为字节 13 是 CR 控制字符,指示打印机将其头移至行首。出于类似的原因,Escape发送^[BackSpace发送^H^?由于一些历史胡言乱语,我不会在这里讨论。

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

我们现在准备好理解

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

屏幕文档解释说这些代码是术语帽键盘功能名称。 Termcap 是一个编程库,应用程序可以使用它来从终端之间的差异中抽象出来。 (现在已经大部分被取代了术语信息.) Termcap 数据库专门包含有关终端的信息,例如行数和列数(当 Termcap 出现时,终端是硬件设备,调整大小的概念不适用)、字节序列(通常以 ESC 开头) ),应用程序可以使用它来执行移动光标或清除屏幕等操作,以及通过各种按键发送的字节序列。 Termcap 为功能键指定的符号名称可以在 后使用bindkey -k

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

您会注意到该数据库缺少很多键和弦。如果此数据库中没有键和弦的条目,则没有可用于带有 的键的名称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,) (在哪里AεA, 和ε)明确描述如何在标准美国键盘上键入相应的 GNU 屏幕命令字符,并假设使用特定的终端模拟器

正如我上面所暗示的,特定终端仿真器这里很重要:不同的终端以不同的方式对键和弦进行编码,并且某些终端可以以不同的方式进行配置。该映射不对应于一对 (A,):A×不是一个有趣的集合。大多数键和弦都映射到任何一个一个可打印的字符(正如我们上面所看到的,它扩展了A或者转义序列(正如我们上面看到的,它扩展了)。换句话说,映射是到一个超集A

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

一些终端,尤其是 xterm,可以配置为以系统方式编码键和弦。看使用终端时的键绑定问题面向 Emacs 的讨论。不幸的是,这不包括vte库许多终端仿真器都使用它,尤其是在 GNOME 世界中。

相关内容