我正在用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
函数将终端返回到原始状态.
当按下箭头键等键时,特殊的"转义序列"会出现问题.例如,当按下箭头键时,字节序列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
语句,以准确地显示所有输入何时被处理.
然而,这个代码似乎挂起了.编译并运行此代码,您可以看到当您按下箭头键时代码不会返回,这是预期的.但是,当您在此之后按下另一个键时,它会返回,这表明程序挂在problem code
块内的getchar()
函数中.
据我所知,poll()
只在有可用输入时返回非零值.为什么它挂了,我该怎么解决这个问题?
如果需要的话,下面列出了帮助函数,其中包含了它们的required include.
#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
}