奇怪的 Konsole 字符编码行为

奇怪的 Konsole 字符编码行为

我将Lubuntu中Konsole的字符编码设置为UTF-16(不确定Konsole使用UTF-16小端还是UTF-16大端)。

然后我在“运行”窗口中运行以下命令:

在此输入图像描述

然后我按下键盘上的“a”按钮(在 Lubuntu 中选择的键盘布局是英语),我认为这会导致字节61 00(如果 Konsole 使用 UTF-16 小端)发送到线路纪律,以及线路纪律依次将这些字节回显给 Konsole,Konsole 将显示字符“a”。但我得到了以下结果:

在此输入图像描述

我再次按下“a”按钮,得到以下信息:

在此输入图像描述

我再次按下“a”按钮,得到以下信息:

在此输入图像描述

我再次按下“a”按钮,得到以下信息:

在此输入图像描述

为什么我得到这些奇怪的字符而不是简单地得到字符“aaaa”?


编辑:

这些是 Konsole 中显示的字符:

觉醒`觉醒䁞觉醒`觉醒䁞

答案1

让我们进一步强调这xxd -p是无关紧要的,我们不是谈论它是输出。由于内核端的行缓冲,它甚至没有看到输入,因此没有产生任何输出。就其价值而言,它也可以是 acat或 asleep 100000或其他任何形式。我们正在谈论如何核心(线路规则)回显输入。

如果切换回 UTF-8,然后按 Enter 键xxd -p,其输出将类似于fffe6100fffe6100。确认了如此少的字节序(或者可能是架构的本机字节顺序),但令人惊讶的是,每个字符之前都有一个 BOM。让我怀疑 Konsole 开发人员没有正确考虑这一点,他们只是盲目地以 UTF-16(未指定 BE 或 LE)作为目标字符集调用 iconv,对于每个可用的输入块,并且 iconv 放置它在那里。

让我们通过stracekonsole 看看它对连接到的文件描述符做了什么/dev/ptmx

write(..., "\377\376a\0", 4)             = 4
[...]
read(..., "\377\376a^@", 5)              = 5

NUL 字节 (0x00) 以文字形式返回^@,即 0x5e 后跟 0x40。

a(0x61) 一起,这将为您提供 U+5e61,这正是您看到的第一个字形。另外,您将偏离一个字节,也就是说,下一个所谓的低字节将被解释为高字节,反之亦然。

对于字节,0x00内核只是破坏了它的回显方式。对于其他一些字节,它也执行其他操作。例如,字节0x03( ^C) 通常会触发发送到前台进程的中断,0x15( ^U) 会清除您到目前为止输入的数据,0x0a和/或0x0d(即换行符)将数据刷新到您的应用程序等。所有这些bytes 可以(并且确实)合法地出现在字符的 UTF-16 表示形式中,并且您肯定不希望在键入输入时发生任何这些情况。

为了在门徒行上使用 UTF-16,内核需要为此提供明确的支持,并且需要被告知正在使用这种编码(类似于 an 的方式stty utf16)。据我所知,这并没有实现(幸运的是——这完全是对开发人员资源的浪费)。内核期望使用与 ASCII 兼容的编码,而 UTF-16 则不然。

即使在内核中为 tty 线路实现了 UTF-16,整个生态系统也必然非常脆弱。终端可以同时从多个源接收数据,并且无法保证所有数据生产者和所有传输者(例如ssh)始终保持字节成对耦合。一旦它丢失了一个字节(如上所示),其余的就无法使用。

我现在更加确定 Konsole 开发人员没有正确考虑这一点。在我看来,UTF-16 应该从他们提供的编码列表中删除,或者至少应该显示一个警告。我已提交Konsole 错误 395171

相关内容