wsl 下的 Ubuntu bash 终端意外切换到“跳过单词”输入模式

wsl 下的 Ubuntu bash 终端意外切换到“跳过单词”输入模式

下面我假设终端(控制台)有两种输入模式:

  1. 在“正常模式”下,按下时光标向左移动1 个符号,按下时光标向右移动1 个符号(或者根本不移动,如果已经在输入的开始/结束)
  2. 在“跳过单词”模式下,按下时光标会向左移动1 个词到上一个空格符号,按下时光标向右移动1 个词到下一个空格符号(如果已经在输入的开始/结束,则根本不移动)

默认情况下是“正常模式”。如果只想使用一次“跳过单词”模式(这在编辑历史记录中的命令时很有用),您应该按Ctrl+Ctrl+而不是

问题是有时候(我不知道是什么原因造成的)我的终端会意外地永久切换到“跳过单词”输入模式,所以我的光标会跳过单词按下。

这种行为的原因是什么?如何在不退出终端的情况下将切换后的输入模式恢复为默认输入模式?

我只在当前设置中遇到此问题,因此它可能与我的特定环境有关。我bash在 Ubuntu 22.04 下运行wsl2,通过 Windows 终端访问1.18.2822.01.18.3181.0(“新 Windows 终端”,不旧cmd.exe也不新PowerShell.exe)。

正常模式下 和的代码为: ,跳字模式下 的代码为:^[[D^[[C^[OD^[OC

按下时Ctrl+Ctrl+的代码明显:^[[1;5D^[[1;5C

cat ~/.inputrc

"\e[2~": overwrite-mode
"\e[5~": beginning-of-history
"\e[6~": end-of-history
"\e[1;5C": forward-word
"\eOC": forward-word
"\e[1;5D": backward-word
"\eOD": backward-word
"\C-h": backward-kill-word

答案1

你的一个程序输出一个终端控制代码来启用“应用程序密钥”模式,它将许多特殊键切换为交替序列。例如,它使数字键盘键输出自己的特殊序列而不是普通符号(例如,可以Num 2与常规符号区分开来2——这对于古老的 DEC 文本编辑器很重要,例如美东时间)。

然后程序又忘记禁用该模式。(例如,您可能一直在通过 SSH 使用全屏文本编辑器,然后 SSH 连接被关闭而没有给编辑器清理的机会。我在 Linux 上使用 Wine 时也遇到过类似的问题,即使它在本地运行。)

症状此模式的一个特点是光标键开始使用前缀ESC O而不是常规 CSI。虽然这不是意味着在这个模式下,“向后一个单词”恰好与另一个方言的键序列相冲突,意思是——我怀疑是 Rxvt,它不像 Xterm 风格的终端那样报告修饰符,而是使用ESC O dCtrl-left 等。(尽管 Rxvt 使用小写字母,abcd而按键发送大写字母,所以我真的不能 100% 确定这是否与 Rxvt 有冲突;可能是其他类似的东西。)

另一个问题是 Bash 的键映射显然是静态的;它没有查看 $TERM 并从 terminfo 数据库加载键,而是为多个终端提供了静态的“尽力而为”的映射组合。而且由于 Bash 没有预计在“应用程序键”模式下运行,其映射假设“ESC O DCtrl- 以正常模式左移”,因此它会向后移动一个单词。

在以下位置搜索 DECCKMXterm 控制序列有关更多详细信息;该文档包含相关的控制序列,甚至还有一个表格,其中列出了哪些键重新映射到哪些输入序列。

Terminfo 知道如何控制此模式,因此你可以使用以下命令退出该模式tput rmkx是 的逆tput smkx。1但是,通常这不是唯一意外启用的模式,因此,我建议运行以下命令,而不是上述“tput”或“printf”reset希望清除所有不需要的终端状态。

(例如,如果问题确实是由全屏文本编辑器引起的,那么您还将处于“备用屏幕”模式,该模式禁用回滚 -tput rmcup退出,tput smcup再次进入 - 并且您可能已启用鼠标报告等)

1(用于infocmp查看正在使用的序列。如果您更喜欢在没有 terminfo 的情况下手动执行此操作,则模式通过 DECSET 序列控制CSI ? Pm h/ CSI ? Pm lDECCKM 的 Pm=1,因此您可以使用printf '\e[?1l'它来禁用或\e[?1h启用该模式。)

通过 Windows Terminal 1.18.2822.0 1.18.3181.0(“新 Windows 终端”,而不是旧的 cmd.exe 或较新的 PowerShell.exe)访问。

cmd.exe 不是终端,它是一个与 Bash 非常相似的纯 shell。“旧式”控制台窗口是名为 Conhost 的系统组件(cmd.exe 和 PowerShell 之间也一样)。

这里可能与 cmd.exe 没有使用Conhost 就像一个终端——事实上,直到 Windows 8.1 之前,Conhost 都没有任何类似“终端”的功能——相反,它使用较旧的“Windows 控制台”模型,该模型使用带外控制 API 而不是 ESC 序列,因此零散的 ESC 序列没有机会做很多事情。(除此之外,cmd.exe 中的行编辑也由它处理完全由 Conhost 实现,而不是 Cmd 实现;尽管在 PowerShell 中它转向了更类似 Unix 的架构。)

相关内容