终端上的键盘输入有很多不足之处。我希望它们都固定。我有一个计划,但需要您的帮助
我希望终端按键能够正常工作。我是什么意思?我的意思是程序可以通过简单的正交方式确定按下的键,并且该模型应该可以轻松映射到用户的期望。
为什么现在不行?当前,终端使用相同的字节编码的物理上按键区分的类别很多。某些ASCII字符的特殊名称与Ctrl修改的字母冲突。例如,Tab是Ctrl-I。
UTF-8与8位高字符碰撞;例如Alt-C可能被编码为0xc3,它是许多Unicode字符(例如é)的第一个UTF-8字节。
有时程序会依赖时序信息来区分(例如,Alt-C与两次单独的Escape键,然后再按下C键)。如果时间太长,则会导致延迟识别纯Escape键的时间,或者错误地识别Escape键,然后再按一次。如果输入速度太快或时间限制太短,则将字母作为Alt修改字母。
即使密钥产生唯一的明确字节序列,也可能是某些程序无法识别它们。终端对修改后的按键进行编码的方式是对1970年代使用的原始方法的扩展,并且一些较旧的代码无法正确解析它们。在现代的xterm上按Ctrl-Up并观看程序以各种有趣的方式失败并死亡,因为它们没有真正的CSI解析器。
通过在终端交互的两端都建立一个理智而明智的模型,以及一种明确定义的沟通方式,我们如何做到这一点实际上取决于您是谁:
解决此问题的最简单方法是使用我的终端UI库libtickit的键输入处理功能,如果您使用的是某些现有的键盘输入系统(例如GNU Readline),则失败,建议您施加压力直到该系统的维护人员采用这种读取扩展按键的方法。
考虑到编码方案已经以可能类似于工作中的基础输入系统(例如X11或Win32)的方式拆分修饰符和键符号,使终端发送正确的键编码应该是相对容易的任务。
即使您不是这样的程序的作者,您仍然可以帮助解决这种情况。编写程序的维护者,报告错误。说明您要使用这样的键绑定,或者出现任何问题。向他们说明,因为他们的程序无法正确处理这些情况,所以不可能,但是如果他们采用这种方案,那么它将可以解决您的问题。有了足够的声音,即使是最坚决的开发者,他们相信1970年左右,每个人都住在9600波特调制解调器上的绿磷玻璃电传打字机后面,仍然可以改变他的方式。
该方案的主要动机是对任何可能的按键进行唯一编码。按键映射到一个可能的字节序列,而有效的字节序列仅编码一次按键。为了向后兼容,还要求在不使用此方案的情况下可以表示的任何按键也必须由其中的相同字节表示;例如,也就是说,此方案是现有编码的扩展,而不是替代。
本规范用于编码修饰符的两种编码形式均以数字作为其第二个参数,其值为1 +编码修饰符的位掩码。我们加1是因为按照惯例,缺少的CSI参数等于1,因此在" unmodified"中,声明修饰符字段为1-我们必须向其添加1,以便无位集(未修改)被编码为1(尽管实际上,我们很少明确使用1形式)。因此,使用这些修饰符的各种编码形式将如下所示:这些各种形式将在下面进行详细说明。
未修改时,只需照常发送UTF-8字节即可。常规字符的UTF-8序列都不以C0或C1字节开头,因此它们将是唯一的。 Shift键不应被视为Unicode字符的修饰符,因为它很可能首先用于获取字符(例如,经常需要使用Shift键才能获得!符号)。某些按键具有修饰键的特殊行为。 Alt往往以Escape作为前缀。 Ctrl倾向于用0x1f遮罩。当按下这些键的最简单形式时,它们应该按照以前的方式进行编码。现有的方案目前缺乏一种使用Unicode代码点对更通用的修饰符进行编码的方法,因此我们可以自由地为这些键发明一些新的东西。 CSI u命令位于专用区域中,因此目前没有固定的含义。我们可以用它来表示有问题的键组合。例如字母" A"的变体(ASCII十进制值65)和" a&#34 ;:其他字母继续相同的模式,除了的尴尬情况我们现在可以明确表示常见的有问题的键:因为其他C0字节没有普通的备用名称或按键,可以继续使用简单的单字节编码发送。这对于确保遗留系统继续正确地解释它们至关重要(例如termios仍在Ctrl-C上发送SIGINT)。Space键在打印Unicode键中是唯一的,因为它的行为通常不会由于以下原因而改变: Shift修饰符。我们可以通过使用CSIu对其进行编码来捕获它-唯一地,这是我们唯一使用它的印刷Unicode密钥:
如果存在任何修饰符,可以使用CSI u编码来表示上面列出的有问题的键以及Backspace。由于这些符号几乎都可以在其自身的物理键帽上找到,因此对Shift修饰符的值1进行编码也没有问题。我们使用它们的常规ASCII码点值对这些键进行编码。空格键比较棘手,因为它通常与Ctrl修饰符一起使用,以获取NUL字节编码。由于大多数终端都将Shift-Tab用作CSI Z,因此也需要特别处理。
现有方案通常使用CSI〜来编码特殊的(即非Unicode)按键。 XTerm和其他终端使用第二个CSI参数传递对有效的修饰符集进行编码。如果修饰符值为1;也就是说,没有修饰符,则为了向后兼容发送与以前相同的字节,应省略它,仅发送(*):请注意,某些终端更喜欢使用较短的CSI编码Home,End和F1至F4功能键字母编码。解析器或其他接收程序应接受相同的编码。 (**):还请注意编号的功能键的间断性。在每组5个F键之后,缺少一个数字。因此F键不会使用每6个数字(10、16、22、28等)。这纯粹是出于历史原因;原始VTxx键盘上编号的F键在这些位置上存在物理间隙。
一些终端在CSI〜编码之外对某些密钥进行编码,而不是选择其他CSI命令。这也可以使修饰符处于第二位置。和以前一样,如果修改器为1,则应省略修改器参数。由于还暗示了前导数字,因此也可以省略。
优点:解决了以上问题。可以花最少的钱就可以安装到现有程序中,而又不会破坏反向兼容。
扩展:我们可以更进一步,要求将CSI作为单个8位代码0x9b发送,而绝不作为7bit多字节0x1b 0x4b发送(Escape [)。这将仅将0x1b字节保留给Escape键。如果已知这是有效的,则不再需要使用时间信息来恢复准确的按键信息,因为每个可能的按键现在都具有唯一的编码。即使不知道这是有效的,程序也应该无论如何都要接受CSI的0x9b字节编码,因为终端可能会默认以这种方式发送它。