C++ Ansi 转义码及其手动完成时的解释

C++ Ansi escape codes and it's interpretation when done manually

我只是无意中注意到了这一点,代码如下。在下面的代码中,

char teststring[20];
cin.getline(teststring, 20);

用户输入时提示停止,当我按下向上箭头时,我出于肌肉记忆检查了 bash 历史记录,它打印了 Ansi Escape 代码(从 here) ^[[A 并且当我按下一个退格键并按下回车键时,字符 A 被删除并打印出不可读的垃圾,而不是 ^[[,但是当我输入手动或再次复制粘贴相同的键(以确保它不是 ASCII 中看起来相似的符号)而没有最后一个字母,它打印 ^[[。 输入的字符相同是什么原因?

Unix 终端是一个非常复杂的野兽。 Posix 包含 pretty thorough description 个特征;以下只是简要总结。

正常情况下,终端输入设备运行在"canonical"模式。在那种模式下,终端驱动程序维护一个行缓冲区,必要时通过读取用户输入来填充它。如果缓冲区为空并且程序请求更多数据,则驱动程序将在向程序提供更多数据之前读取整行输入。因此,如果缓冲区为空,即使 getc 读取单个字符也会导致在 getc return 之前将整个字符读入终端驱动程序的缓冲区。

当驱动程序读取输入字符时,它会检查某些特殊字符;任何其他内容都会添加到行缓冲区并回显到终端设备。 (终端设备的输入和输出是独立的;如果驱动程序或程序没有回显输入,屏幕上不会出现任何内容,这通常会造成混淆。程序关闭回显以便能够接受密码,因为例如。)

所有特殊字符都是可配置的。有很多;以下是一些比较常见的:

  • Enter 将换行符插入缓冲区,并终止输入行,以便等待读取 return.
  • Ctrl-D (EOF) 字符本身被丢弃,但输入被终止,一个挂起的读取returns。如果输入缓冲区为空——即在一行的开头按下 Ctrl-D,零长度缓冲区将 returned 到挂起的读取,这将被解释为文件结尾标记。
  • Bksp (ERASE) 除非输入缓冲区为空,否则从输入缓冲区中删除最后一个字符并将其从屏幕上删除。
  • Ctrl-C (INTR) 发送 SIGINT 到进程。
  • Ctrl-Z (SUSP) 发送 SIGTSTP 到进程。
  • Ctrl-U (KILL) 删除整个输入缓冲区。
  • Ctrl-S (STOP) 停止输出。
  • Ctrl-Q (START) 如果已使用 STOP 字符停止,则恢复输出。

当Linux终端驱动回显字符时,它通常会将控制字符(ASCII码小于0x20的字符)回显为脱字符(^)后面是代码比0x40高的字符,通常是一个字母。 ESC 字符的代码为 0x1B,因此它通常会作为插入符号回显,后跟字符 0x5B,这是一个开放的方括号。因此,您通常会期望 ESC 回显为 ^[.

键盘上的许多键实际上发送的字符不止一个,而且几乎所有这些序列都以ESC[开头。例如,向上箭头发送代码 ESC[A,因此如果您是 运行 一个不处理光标移动字符的天真的程序,当你按下向上箭头键时,你会看到 ^[[A 回显。

您看到的字符是用于显示不对应于任何 Unicode 字形的字符的方式之一。该框包含四个十六进制数字,对应于 Unicode 代码点,在本例中为 U+001B,它是一个 ESC 字符。我不知道为什么会这样,但这很可能是导致终端回显的各种组件之间竞争条件的结果。