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
字符。我不知道为什么会这样,但这很可能是导致终端回显的各种组件之间竞争条件的结果。
我只是无意中注意到了这一点,代码如下。在下面的代码中,
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
字符。我不知道为什么会这样,但这很可能是导致终端回显的各种组件之间竞争条件的结果。