我通过注册回调函数,以"选择"的方式使用GNU Readline:
rl_callback_handler_install("", on_readline_input);
Run Code Online (Sandbox Code Playgroud)
然后挂钩rl_callback_read_char作为我的select()循环的回调STDIN_FILENO.这都是非常标准的东西,并且工作正常.
现在,我的程序异步地将消息打印到屏幕上,有时与用户的输入交错."干净"的会话看起来像这样:
user input
SERVER OUTPUT
SERVER OUTPUT
user input
SERVER OUTPUT
Run Code Online (Sandbox Code Playgroud)
但是,如果用户在服务器响应到达时位于线路中间,该怎么办?然后它变得丑陋:
user input
SERVER OUTPUT
user inSERVER OUTPUT
put
SERVER OUTPUT
Run Code Online (Sandbox Code Playgroud)
如果用户输入任何内容(通过检查很容易判断rl_line_buffer),然后rl_forced_update_display()在打印服务器输出后执 现在它看起来像这样:
user input
SERVER OUTPUT
user in
SERVER OUTPUT
user input
SERVER OUTPUT
Run Code Online (Sandbox Code Playgroud)
这更好,但仍然不完美.当用户键入整行但尚未按Enter键时出现问题 - 那么它看起来像这样:
user input
SERVER OUTPUT
user input
SERVER OUTPUT
user input
SERVER OUTPUT
Run Code Online (Sandbox Code Playgroud)
这很糟糕,因为用户看起来他们输入了三个命令(三个输入的三个响应与两个输入的三个响应一样可能,这实际上是发生的).
讨厌的黑客(有效)是这样做的:
user input
SERVER OUTPUT
user input - INCOMPLETE
SERVER OUTPUT
user input
SERVER OUTPUT
Run Code Online (Sandbox Code Playgroud)
我想我可以通过打印退格('\ b')字符来改进这一点而不是" - INCOMPLETE",但这似乎在我的终端上没有做任何事情(Ubuntu Hardy上的gnome-terminal). printf("ABC\b");只是打印ABC,无论出于何种原因.
那么如何擦除不完整的输入线?要么以某种方式打印退格(我可以弄清楚要打印多少 - 它是strlen(rl_line_buffer)),或者使用一些我还不知道的Readline工具?
经过大量的黑客攻击,我能够获得这种机制。我希望其他人会觉得它有用。它甚至不使用 select(),但我希望你能明白这一点。
#include <readline/readline.h>
#include <readline/history.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
const char const* prompt = "PROMPT> ";
void printlog(int c) {
char* saved_line;
int saved_point;
saved_point = rl_point;
saved_line = rl_copy_text(0, rl_end);
rl_set_prompt("");
rl_replace_line("", 0);
rl_redisplay();
printf("Message: %d\n", c);
rl_set_prompt(prompt);
rl_replace_line(saved_line, 0);
rl_point = saved_point;
rl_redisplay();
free(saved_line);
}
void handle_line(char* ch) {
printf("%s\n", ch);
add_history(ch);
}
int main() {
int c = 1;
printf("Start.\n");
rl_callback_handler_install(prompt, handle_line);
while (1) {
if (((++c) % 5) == 0) {
printlog(c);
}
usleep(10);
rl_callback_read_char();
}
rl_callback_handler_remove();
}
Run Code Online (Sandbox Code Playgroud)
有空格吗?尝试打印"\b \b"您想要“删除”的每个字符,而不是单个'\b'.
编辑
它是如何工作的
假设您写了“Hello, world!” 到显示设备并且您想要替换“world!” 与“吉姆”。
Hello, world!
^ /* active position */ /* now write "\b \b" */
/* '\b' moves the active position back;
// ' ' writes a space (erases the '!')
// and another '\b' to go back again */
Hello, world
^ /* active position */ /* now write "\b \b" again */
Hello, worl
^ /* active position */ /* now write "\b \b" 4 times ... */
Hello,
^ /* active position */ /* now write "Jim." */
Hello, Jim.
^ /* active position */
Run Code Online (Sandbox Code Playgroud)
可移植性
我不确定,但标准具体描述了 '\b' 和 '\r' 的行为,正如您问题的答案中所描述的那样。
5.2.2 字符显示语义
> 1 The active position is that location on a display device where the next character output by
> the fputc function would appear. The intent of writing a printing character (as defined
> by the isprint function) to a display device is to display a graphic representation of
> that character at the active position and then advance the active position to the next
> position on the current line. The direction of writing is locale-specific. If the active
> position is at the final position of a line (if there is one), the behavior of the display devic e
> is unspecified.
>
> 2 Alphabetic escape sequences representing nongraphic characters in the execution
> character set are intended to produce actions on display devices as follows:
> \a (alert) Produces an audible or visible alert without changing the active position.
> \b (backspace) Moves the active position to the previous position on the current line. If
> the active position is at the initial position of a line, the behavior of the display
> device is unspecified.
> \f ( form feed) Moves the active position to the initial position at the start of the next
> logical page.
> \n (new line) Moves the active position to the initial position of the next line.
> \r (carriage return) Moves the active position to the initial position of the current line.
> \t (horizontal tab) Moves the active position to the next horizontal tabulation position
> on the current line. If the active position is at or past the last defined horizontal
> tabulation position, the behavior of the display device is unspecified.
> \v (vertical tab) Moves the active position to the initial position of the next vertical
> tabulation position. If the active position is at or past the last defined vertical
> tabulation position, the behavior of the display device is unspecified.
>
> 3 Each of these escape sequences shall produce a unique implementation-defined value
> which can be stored in a single char object. The external representations in a text file
> need not be identical to the internal representations, and are outside the scope of this
> International Standard.
Run Code Online (Sandbox Code Playgroud)