我正在用 C 语言制作一个文本编辑器,并使用
poll()
函数来确定输入是否准备就绪(如果没有,则继续使用本例中未显示的其他功能。然后,如果有字符可用(即 if (!poll(...))
条件为假),用getchar()
收集并处理。代码如下:
#include <poll.h>
#include <stdio.h>
int main(void) {
input_set_tty_raw();
char input_history[1000];
int curr = 0;
struct pollfd in = {.fd = 0, .events = POLLIN};
while (1) {
if (!poll(&in, 1, 20)) { // arbitrary timeout for poll function
continue;
}
char c = getchar();
/* problem code */
if (input_history[curr - 1] == '\033' && c == '[') {
while (poll(&in, 1, 0)) {
getchar();
}
return input_restore_tty();
}
// handle inputs
input_history[curr++] = c;
}
return input_restore_tty();
}
如果您想知道,
input_set_tty_raw()
相当于运行$ stty raw
,允许逐个字符地纯(或raw
)处理输入。 input_restore_tty
函数将终端返回到原始状态。
当按下箭头键等键时,会传递到
stdin
的特殊“转义序列”会出现问题。例如,当按下箭头键时,会传入一系列字节 27
-91
-6x
。您可以使用这个小实用程序来检查此行为:
#include <stdio.h>
int main(void) {
input_set_tty_raw();
while (1) {
char c = getchar();
if (c == 'q') {
return input_restore_tty();
}
printf("%d\n\r", c);
}
}
前面提到的
27
-91
-6x
行为似乎与其他转义序列共享 27
-91
标头(这是一个 "\033["
),例如按删除(而不是退格)键在键盘上输入 27
-91
-51
-126
。
因此,在标记为
problem code
的第二个条件中,我检查先前输入的字符是否为 \033
转义字符以及当前字符是否为 91
(或 [
)字符。如果是这样,我使用 while
语句让所有其他输入通过。
从测试来看,
\033
和[
之间的延迟似乎不为零,而转义序列中的其余字符似乎是立即输入的,因此内部poll
的超时为0 .我在条件中放置了一个 return
语句,以准确显示何时处理所有输入。
但是,这段代码似乎挂起。编译并运行它,您可以看到当您按箭头键时代码不会像预期的那样返回。但是,当您在此之后再按另一个键时,它会返回,表明程序挂在
getchar()
块内的 problem code
函数中。
据我所知,
poll()
仅在有可用输入时返回非零值。那么,为什么它挂起,我该如何解决这个问题?
如果需要,辅助函数如下所示,及其所需的包含内容。
#include <termios.h>
static struct termios tbufsave;
int input_set_tty_raw(void) {
struct termios tbuf;
if (tcgetattr(0, &tbufsave) == -1) {
return 1;
}
tbuf = tbufsave;
tbuf.c_iflag &= ~(INLCR | ICRNL | ISTRIP | IXON | BRKINT);
tbuf.c_oflag &= ~OPOST;
tbuf.c_lflag &= ~(ICANON | ISIG | ECHO);
tbuf.c_cc[VMIN] = 1;
tbuf.c_cc[VTIME] = 0;
return tcsetattr(0, TCSANOW, &tbuf) == -1; // 1 for error
}
int input_restore_tty(void) {
return tcsetattr(0, TCSANOW, &tbufsave) == -1; // 1 for error
}