更新:正如Thomas在评论中所建议的那样,shell肯定会在ncurses到达之前缓冲输入。我将ncurses调试到文件描述符上的原始read()
,我确认了块,直到我在新终端中输入两个字符。我确实找到了一个丑陋的黑客来解决这个问题 - 我可以用另一个不干扰终端的应用程序(例如xclock
)来吸引shell,然后连接到终端。没有更多缓冲 - ncurses成功读取每个字符。
原始问题:我正在尝试编写一个控制多个终端的ncurses程序。我一直在使用newterm() API,它允许我成功创建新的SCREEN句柄。但是,当我尝试从新终端读取输入时,getch()忽略我键入的第一个字符,并且仅在输入第二个字符时返回输入。
以下是我初始化屏幕的方式:
const char *term_fn = "/dev/pts/18"; // Filename of other terminal
FILE *term_fp = fopen(term_fn, "r+");
SCREEN *term = newterm(NULL, term_fp, term_fp);
set_term(term); // Ensure we're using the new screen
keypad(stdscr, TRUE); // Make ncurses interpret function keys
nodelay(stdscr, FALSE); // Make getch() blocking
cbreak(); // Don't buffer input until newline
echo(); // Echo the keyboard input back
我已经仔细检查过文件是否正确打开了,ncurses为我初始化了一个新的SCREEN。但是,当我尝试读取输入getch()块时,直到我输入2个字符。例如,当我运行以下代码时,重复读取&显示输入,直到输入'q':
void get_and_print_input() {
char cur;
mvprintw(0, 0, "Please enter a character: ");
refresh();
do {
/* getch() will *not* return until I type 2 characters */
cur = getch();
if(cur != ERR) {
mvprintw(1, 0, "Got a character: '%c'", cur);
move(0, 26);
refresh();
if(cur == 'q') break;
else cur = ERR;
}
} while(cur == ERR);
}
当我输入'a'时,我得到以下示例输出,等待30秒然后输入'b':
Please enter a character: ab
Got a character: 'b'
我在Ubuntu 16.04 LTS上运行,我的TERM环境变量是“屏幕”,虽然我正在使用tmux。我应该注意,当我使用标准屏幕时,getch()的行为符合预期(即,在输入单个字符时返回),即,而不是打开一个新的终端,我只需要调用initscr()。我是否错误地初始化了新屏幕?
下面的 编辑是一个独立的示例。为了运行该程序,我打开了2个终端 - 一个运行程序的终端,称为终端A,另一个终端由ncurses,终端B控制。该程序将终端B的文件名作为输入,如{{ 1}}命令(例如,我传递它tty
)。在终端A中运行的程序打开文件描述符&用于控制终端B的屏幕。然后调用-f /dev/pts/18
- 我输入字符,程序在终端B上打印所有输出。在检测到用户输入'q'后,程序清除所有数据结构和回报。
get_and_print_input()
编辑2:在将字符传递给ncurses之前,shell似乎正在进行一些缓冲。当我使用#include <unistd.h>
#include <assert.h>
#include <ncurses.h>
static const char *term_fn = NULL;
static FILE *term_fp = NULL;
static SCREEN *term = NULL;
void parse_args(int argc, char **argv) {
int c;
while((c = getopt(argc, argv, "f:")) != -1) {
switch(c) {
case 'f': term_fn = optarg; break;
default: break;
}
}
}
void get_and_print_input() {
char cur;
mvprintw(0, 0, "Please enter a character: ");
refresh();
do {
cur = getch();
if(cur != ERR) {
mvprintw(1, 0, "Got a character: '%c'", cur);
move(0, 26);
refresh();
if(cur == 'q') break;
else cur = ERR;
}
} while(cur == ERR);
}
int main(int argc, char **argv) {
/* Set up all data structures */
parse_args(argc, argv);
assert(term_fn != NULL && "Must supply a terminal file");
term_fp = fopen(term_fn, "r+");
assert(term_fp && "Couldn't open terminal file");
term = newterm(NULL, term_fp, term_fp);
assert(term && "Couldn't open terminal");
/* Configure screen */
set_term(term);
keypad(stdscr, TRUE);
nodelay(stdscr, FALSE);
cbreak();
echo();
get_and_print_input();
/* Cleanup */
endwin();
delscreen(term);
fclose(term_fp);
}
而不是noecho()
时,它仍会回显我输入的第一个字符,但不会回显第二个字符。例如,使用与上面相同的输入:
echo()