提示使用来自 sys.stdin 的先前输入
Prompting with previous input from sys.stdin
我有一个标准的服务器-客户端 TCP 设置。基本思想是一个聊天系统。仅查看对话的客户端,客户端提示用户输入:
sys.stdout.write('<%s> ' % username)
sys.stdout.flush()
使用以下逻辑:
while True:
socket_list = [sys.stdin, s]
read_sockets, write_sockets, error_sockets = select.select(socket_list, [], [])
for sock in read_sockets:
if sock == s:
data = sock.recv(4096)
if data:
output('\a\r%s' % data) #output incoming message
sys.stdout.write('<%s> ' % username) #prompt for input
sys.stdout.flush()
else:
raise SystemExit
else:
msg = getASCII(sys.stdin.readline()) # returns only the ascii
if msg:
s.send(msg)
sys.stdout.write('<%s> ' % username)
sys.stdout.flush())
(注意:截断的片段。 可以找到完整代码 here 链接代码已更新,因此不再相关。)
问题是,当用户正在输入时,它从服务器收到一条传入消息,客户端输出消息并再次提示输入。正在键入的消息仍在标准输入缓冲区中,但已从屏幕上消失。如果用户按回车键发送消息,整个消息将被发送,包括缓冲区中的内容,但在用户屏幕上,将仅显示消息的第二部分,即中断后的部分。
我有一个可能的解决方案,就是当我提示输入时,我检查缓冲区中是否有任何东西并随着提示输出,但我不知道如何实现它。感谢任何帮助。
作为问题评论中讨论的实现您自己的编辑行输入功能的替代方法,请考虑以下方法:更改滚动区域以忽略屏幕的底线(用户输入行)并仅输入滚动区域临时输出传入的服务器消息。 That answer 包含示例。
问题似乎是您让来自其他用户的消息打断了输入。我建议你要么一次只听一件事(当用户输入时你让他完成并在监听远程消息之前按回车键)或者你监听用户的输入一个键一次并建立您自己的缓冲区(参见 Polling the keyboard (detect a keypress) in python)。后一种方法的缺点是您需要实现键编辑等。可能有一个库可以为您完成此操作。
请注意,在大多数聊天程序中,您键入的区域与您查看消息的区域位于不同的 window/screen 区域。完成后,所有消息(您的和其他人的消息)都会显示在此消息区域中。也许您可以在屏幕上的其他地方使用仅显示消息(独立于输入)。
要实施您的解决方案,您必须以无缓冲的方式从标准输入读取数据。 readline() 和 read() 阻塞直到 EOL 或 EOF。在按下 return 键之前,您需要来自 stdin 的数据。要实现这一点,这可能会有所帮助: http://code.activestate.com/recipes/134892-getch-like-unbuffered-character-reading-from-stdin/ 当您要写入数据时,您可以从标准输入读取数据,将其存储在某个地方,并在输出消息后再次输出。由于不会为标准输入调用 select,因此创建一个单独的读取线程来读取标准输入。到目前为止使用锁访问标准输入的数据。
我有一个标准的服务器-客户端 TCP 设置。基本思想是一个聊天系统。仅查看对话的客户端,客户端提示用户输入:
sys.stdout.write('<%s> ' % username)
sys.stdout.flush()
使用以下逻辑:
while True:
socket_list = [sys.stdin, s]
read_sockets, write_sockets, error_sockets = select.select(socket_list, [], [])
for sock in read_sockets:
if sock == s:
data = sock.recv(4096)
if data:
output('\a\r%s' % data) #output incoming message
sys.stdout.write('<%s> ' % username) #prompt for input
sys.stdout.flush()
else:
raise SystemExit
else:
msg = getASCII(sys.stdin.readline()) # returns only the ascii
if msg:
s.send(msg)
sys.stdout.write('<%s> ' % username)
sys.stdout.flush())
(注意:截断的片段。 可以找到完整代码 here 链接代码已更新,因此不再相关。)
问题是,当用户正在输入时,它从服务器收到一条传入消息,客户端输出消息并再次提示输入。正在键入的消息仍在标准输入缓冲区中,但已从屏幕上消失。如果用户按回车键发送消息,整个消息将被发送,包括缓冲区中的内容,但在用户屏幕上,将仅显示消息的第二部分,即中断后的部分。
我有一个可能的解决方案,就是当我提示输入时,我检查缓冲区中是否有任何东西并随着提示输出,但我不知道如何实现它。感谢任何帮助。
作为问题评论中讨论的实现您自己的编辑行输入功能的替代方法,请考虑以下方法:更改滚动区域以忽略屏幕的底线(用户输入行)并仅输入滚动区域临时输出传入的服务器消息。 That answer 包含示例。
问题似乎是您让来自其他用户的消息打断了输入。我建议你要么一次只听一件事(当用户输入时你让他完成并在监听远程消息之前按回车键)或者你监听用户的输入一个键一次并建立您自己的缓冲区(参见 Polling the keyboard (detect a keypress) in python)。后一种方法的缺点是您需要实现键编辑等。可能有一个库可以为您完成此操作。
请注意,在大多数聊天程序中,您键入的区域与您查看消息的区域位于不同的 window/screen 区域。完成后,所有消息(您的和其他人的消息)都会显示在此消息区域中。也许您可以在屏幕上的其他地方使用仅显示消息(独立于输入)。
要实施您的解决方案,您必须以无缓冲的方式从标准输入读取数据。 readline() 和 read() 阻塞直到 EOL 或 EOF。在按下 return 键之前,您需要来自 stdin 的数据。要实现这一点,这可能会有所帮助: http://code.activestate.com/recipes/134892-getch-like-unbuffered-character-reading-from-stdin/ 当您要写入数据时,您可以从标准输入读取数据,将其存储在某个地方,并在输出消息后再次输出。由于不会为标准输入调用 select,因此创建一个单独的读取线程来读取标准输入。到目前为止使用锁访问标准输入的数据。