Python 在向标准输出显示消息时不要干扰用户输入

Python 在向标准输出显示消息时不要干扰用户输入,python,stdout,stdin,readline,Python,Stdout,Stdin,Readline,我刚刚制作了一个聊天CLI应用程序,它实际上运行得很好 不幸的是,当一方键入一条消息并同时接收另一方的消息时,两者都交错。。。这就相当糟糕了: elton: Hey! john: how are you doing? fine anjohn: still not to bed?! d john: haha you?elton: fine and you? 我正在寻找一种方法来避免这种问题。例如,“保留”最后一行供用户输入,或在收到数据时处理某些操作以重新计算用户输入的位置 经过一些研究,我发现

我刚刚制作了一个聊天CLI应用程序,它实际上运行得很好

不幸的是,当一方键入一条消息并同时接收另一方的消息时,两者都交错。。。这就相当糟糕了:

elton: Hey!
john: how are you doing?
fine anjohn: still not to bed?!
d john: haha
you?elton: fine and you?
我正在寻找一种方法来避免这种问题。例如,“保留”最后一行供用户输入,或在收到数据时处理某些操作以重新计算用户输入的位置

经过一些研究,我发现我将使用getch()逐个检索每个字符。因此,我可以定期检查是否有新消息等待显示,并处理此情况


但是,如果我使用getch(),我必须手动重新定义基本动作(例如退格、向左和向右移动…),有些字符会占用多个字节。简而言之,它是不可用的。

完成这类工作的常用方法是编写“控制台模式GUI”,而不是编写纯CLI

例如,您可以非常轻松地创建一个非常简单的界面,其中包含一个
ROWS-2
x
COLS
输出窗口、一个
1
x
COLS
分隔器或模式行,以及一个
1
x
COLS
输入窗口,如IRC客户端、emacs等。例如:

或者,您可以使用一个拆分视图,其中一个
ROWS/2
x
COLS
窗口用于其他人/人的聊天,另一个
ROWS/2
x
COLS
窗口位于该窗口下方,用于显示用户的当前和以前的消息,这在大多数早期Unix聊天程序中都可以看到

或者像一些现代的IRC客户机那样,到处都有窗口,可以随时弹出或消失

Python内置了
curses
支持,但不支持Windows。如果您想要一个跨平台的解决方案,或者只需要Windows的解决方案,请参阅,答案可能就在那里

以下是IRC客户端BitchX的屏幕截图,让您了解无需做太多工作即可实现的功能:

据我所知,您在这里有一些选择。通常,只要调用getch,您就可以在所谓的“熟”模式下运行终端。这意味着终端只是按照字符到达的顺序显示字符,没有什么特别的。然而,正如你所发现的,你会在比赛条件下奔跑

选项1:一次读取一个字符,缓冲整行内容。当新行到达并要打印出来时,您必须(a)抓住某种打印互斥锁(程序内部),(b)清除当前行(打印“\r[space][space][space]…\r”),(c)打印输入行+“\n”,以及(d)将以前的缓冲区恢复到屏幕(通过打印)并解锁互斥锁

这很难看。快速的正如您所发现的,没有行编辑支持或任何花哨的东西。这种方法唯一的好处是,它可能在99%的终端上都能工作

选项2:将终端置于原始模式。在这种模式下,您可以完全控制终端,但您会失去非常基本的功能(例如,键入一个键,除非您手动输出它,否则不会显示它)。您仍然需要手动实现导航之类的功能,但至少它可以工作。这种方法可能是最灵活的,给你最多的控制,但是像这样工作是非常困难的,这就是为什么他们发明了

选项3:使用ncurses(或类似的终端库)。这些概念有点难,但要比在纯原始模式下学习容易得多。编辑和窗口设置(或者如您所说,保留一行)是内置的。界面可以比烹饪模式下的界面漂亮得多


编辑我在这里谈论了很多*nix终端,其中大多数不适用于Windows。

通常,您会将输入和输出分离到单独的窗格中。您不能在纯CLI中真正“保留一行”。但是你需要一个纯CLI,还是一个
curses
-风格的界面可以吗?@abarnert我从来没有写过curses风格的界面,但这可能是正确的解决方案。选项2和3都是特定于Unix的,关于熟食模式和生食模式的整个讨论也是如此。但我怀疑这是在Windows上。(stdlib中有一个
msvcrt.getch
,但是对于Unix来说没有现成的等价物。)@abarnert我在GNU/Linux上,但是我在Unix上找到了一个getch的补丁。无论如何,我必须让它在Windows和Unix上工作。所以我将使用诅咒解决方案。@abarnert你绝对正确。我确实做出了这样的假设。我将对此进行编辑以反映这一点。