<p>如果在终端中执行此操作,则需要在代码中使用自定义逻辑来处理它</p>
<p>背景:据您的程序所知,它可能连接到一个传输速率为每秒300位的老式硬件终端。当按下<kbd>向上箭头时,该终端可能有一个向上箭头键自动发送字符<code>^[</code>、<code>[</code>、<code>A</code>,或者它甚至可能没有向上箭头,在这种情况下,用户必须按顺序按这三个组合键以获得向上箭头行为(<kbd>^</kbd>+<kbd>[</kbd>和<kbd>esc</kbd>)都发送命令<code>^[</code>字符)。或者,当按下<kbd>向上箭头时,它可能是发送不同字符序列的不同型号的终端。如果在Python中使用<code>input()</code>,操作系统将负责从<code>stdin</code>读取,识别远程终端(或用户终端应用程序模拟的终端),并在命令行上将这些序列转换为适当的编辑操作。但是,如果您直接从<code>stdin</code>读取,则每当用户按下特殊键时,您将获得一些任意字符序列(这可能会因他们模拟的终端型号而异)</p>
<p>在我的终端中,向上箭头发送字符序列<code>^[</code>{<cd2>}{<cd3>}(您可以通过运行<code>cat</code>,然后按键并查看显示的内容来检查)。因此,如果您正在逐个字符地读取终端,则无法判断用户是否刚刚按下了<kbd>esc</kbd>,或者他们是否按下了发出字符序列的其他键</p>
<p>假设您有一个很好的方法将字符序列转换回击键,处理这个问题的一种方法是读取<code>sys.stdin</code>上当前可用的所有内容(使用<code>sys.stdin.read()</code>而不是<code>sys.stdin.read(1)</code>),然后处理缓冲区中的所有内容。有时这会起作用,因为终端会同时将所有字符推入缓冲区,而你的应用程序会同时获取所有字符。但这不是100%保证的<code>read</code>原则上,你可以用任何一种感觉来分解流。通过缓慢的终端连接,你的应用程序可能有时间在下一个待处理字符出现之前处理每个字符</p>
<p>你可以在没有新输入的情况下等待一段安静的时间,然后处理你目前拥有的一切。但是安静时间的长短将取决于连接速度、处理器负载等,所以这是不确定的。而且,延迟越长,你的程序越可靠,但也越滞后</p>
<p>在某种程度上,您正在尝试重新定义什么是程序的输入。因此,也许您应该一直这样做?我的意思是,命令行应用程序通常不会自行响应<kbd>esc</kbd>字符;相反,它们会接受它并等待接下来的任何操作。因此,用户可以键入<kbd>esc[</kbd>,<kbd>[</kbd>,<kbd>A</kbd>尽可能慢,应用程序将依次处理每一个,并最终确定它有一个完整的序列,然后执行<kbd>向上箭头。如果你的应用程序应该响应<kbd>esc</kbd>,那么也许你应该这样做,记住大多数人的终端都会发送^{<cd1>当他们按下<kbd>向上箭头时,后面跟着一堆附加字符。因此,如果其他内容不重要,您可以扔掉它们,或者等待,然后像其他终端程序一样对整个序列执行操作</p>
<p>另一种选择可能是使用Python <a href="https://docs.python.org/3/howto/curses.html" rel="nofollow noreferrer">^{<cd17>}</a>库更直接地与终端交互,但我对此不太熟悉</p>
<p>我认为这种情况的总结版本是:每当用户按下<kbd>esc</kbd>或其他各种终端特定键时,<code>stdin</code>不可避免地会给您一个<code>^[</code>字符。区分按下哪个键的唯一方法是开始检查<code>^[</code>之后的其他字符,可能会有短暂的延迟每个字符(可能是0.1s,使用<code>select.select</code>)。如果您获得了与特定键对应的字符序列,则可以使用该序列。如果有足够长的延迟且没有额外的字符,那么您将放弃并处理到目前为止所拥有的内容(可能只是<code>^[</code>,可能是部分转义序列)。如果这还不够好,那么您需要使用一个与本地硬件更直接交互的库</p>
<p>curses库<a href="https://linux.die.net/man/3/timeout" rel="nofollow noreferrer">provides these behaviors</a>-超时,汇编序列,使用terminfo数据库转换为通用击键。可能有一些更轻的解决方案,但我还没有看到</p>
<p>只是为了完成讨论:一些终端允许您向控制台打印转义序列,该序列将重新编程功能键,包括箭头键,以发送不同的字符或字符序列。e、 g.有一个用于VT100终端和模拟器的DECPFK命令。这可能比使用<code>curses</code>更简单(只需将箭头键编程为发送<code><</code>和<code>></code>或除<code>^[</code>以外的任何内容)。但是,序列可能因终端而异,因此您需要在terminfo数据库中查找它(如果有的话)。我怀疑这是否值得费心</p>
<p>其中一些可能提供有用的背景:</p>
<ul>
<li><a href="https://stackoverflow.com/a/51276045/3830997">"reading arrow keys without Curses module" (don't)</a></li>
<li><a href="https://stackoverflow.com/q/10679188/3830997">using ^{<cd27>} to respond to arrow keys</a></li>
<li><a href="https://unix.stackexchange.com/questions/480081/bash-question-using-read-can-i-capture-a-single-char-or-arrow-key-on-keyup">bash capture a single char OR arrow key (on keyup)</a></li>
<li><a href="https://stackoverflow.com/a/4136019/3830997">Recognizing arrow keys with stdin (c)</a></li>
<li><a href="https://stackoverflow.com/a/32386410/3830997">"Detect key press in python?" (use curses)</a></li>
<li><a href="https://unix.stackexchange.com/a/76591/34344">terminal key codes</a></li>
</ul>