我正在尝试使用ncurses编写一个程序,该程序轮询主循环中的各种文件描述符。我设法用一个文件描述符将其缩减为一个示例,并且达到了预期的行为:
代码:
#include <stdio.h>
#include <stdlib.h>
#include <panel.h>
#include <unistd.h>
#include <poll.h>
#include <sys/eventfd.h>
#define POLL_STDIN
int main() {
int event_fd, cursor_x, cursor_y, ch, n_fds;
bool trigd;
uint64_t event;
WINDOW *win_a, *win_b;
PANEL *panel_a, *panel_b;
event_fd = eventfd(0, 0);
if (event_fd < 0) {
perror("eventfd");
exit(1);
}
struct pollfd poll_fds[2];
poll_fds[0].fd = STDIN_FILENO;
#ifdef POLL_STDIN
poll_fds[0].events = POLLIN;
#else
poll_fds[0].events = 0;
#endif
poll_fds[1].fd = event_fd;
poll_fds[1].events = POLLIN;
initscr();
halfdelay(1);
noecho();
win_a = newwin(10, 10, 0, 0);
win_b = newwin(10, 10, 0, 10);
panel_a = new_panel(win_a);
panel_b = new_panel(win_b);
cursor_x = 0;
cursor_y = 0;
wmove(win_a, cursor_y, cursor_x);
do {
for (int i=0; i<10; ++i) {
for (int j=0; j<10; ++j) {
mvwaddch(win_a, i, j, '.');
mvwaddch(win_b, i, j, '_');
}
}
mvwprintw(win_a, 0, 0, trigd ? "foo" : "bar");
update_panels();
doupdate();
wmove(win_a, cursor_y, cursor_x);
#ifdef POLL_STDIN
n_fds = poll(poll_fds, 2, -1);
#else
n_fds = poll(poll_fds, 2, 0);
#endif
if (n_fds < 0) {
perror("poll");
break;
}
ch = wgetch(win_a);
if (poll_fds[1].revents & POLLIN) {
if (read(event_fd, &event, 8) != 8) {
perror("read");
break;
}
trigd = !trigd;
}
if (' ' == ch) {
cursor_x = (cursor_x + 1) % 10;
} else if ('t' == ch) {
event = 1;
if (write(event_fd, &event, 8) != 8) {
perror("write");
break;
}
}
} while ('q' != ch);
endwin();
return 0;
}
如果未定义POLL_STDIN
,则程序将按预期运行。如果已定义,则程序的工作原理几乎相同,但是光标显示在窗口B的右下角,并且不会移动。按下t
后,光标会暂时移至预期位置。
运行预处理程序后,我查看了该程序,发现没有任何意外,只有mvaddch
被扩展了。
我只是认为等待中的版本有点不雅观,并且还想知道为什么在看似无关的更改之后光标显示在错误的位置。
我发现调用getch
是使光标显示的原因。在两个窗口上都使用nodelay
,并两次调用getch
之后,该程序现在可以在两个版本中运行,并且可以将第二个getch
设为有条件的。这是更新的代码:
#include <stdio.h>
#include <stdlib.h>
#include <panel.h>
#include <unistd.h>
#include <poll.h>
#include <sys/eventfd.h>
int main() {
int event_fd, cursor_x, cursor_y, ch, n_fds;
bool trigd;
uint64_t event;
WINDOW *win_a, *win_b;
PANEL *panel_a, *panel_b;
event_fd = eventfd(0, 0);
if (event_fd < 0) {
perror("eventfd");
exit(1);
}
struct pollfd poll_fds[2];
poll_fds[0].fd = STDIN_FILENO;
poll_fds[0].events = POLLIN;
poll_fds[1].fd = event_fd;
poll_fds[1].events = POLLIN;
initscr();
cbreak();
noecho();
win_a = newwin(10, 10, 0, 0);
win_b = newwin(10, 10, 0, 10);
panel_a = new_panel(win_a);
panel_b = new_panel(win_b);
cursor_x = 0;
cursor_y = 0;
wmove(win_a, cursor_y, cursor_x);
do {
for (int i=0; i<10; ++i) {
for (int j=0; j<10; ++j) {
mvwaddch(win_a, i, j, '.');
mvwaddch(win_b, i, j, '_');
}
}
mvwprintw(win_a, 0, 0, trigd ? "foo" : "bar");
update_panels();
doupdate();
wmove(win_a, cursor_y, cursor_x);
wrefresh(win_a);
n_fds = poll(poll_fds, 2, -1);
if (n_fds < 0) {
perror("poll");
break;
}
if (poll_fds[0].revents & POLLIN) {
ch = wgetch(win_a);
}
if (poll_fds[1].revents & POLLIN) {
if (read(event_fd, &event, 8) != 8) {
perror("read");
break;
}
trigd = !trigd;
}
if (' ' == ch) {
cursor_x = (cursor_x + 1) % 10;
} else if ('t' == ch) {
event = 1;
if (write(event_fd, &event, 8) != 8) {
perror("write");
break;
}
}
} while ('q' != ch);
endwin();
return 0;
}
我不确定这是否是显示光标的最佳方法,但是如果没有其他人发布它,我将其发布为答案。
在@Thomas Dickey评论后编辑的后代代码。
答案 0 :(得分:0)
我认为添加wrefresh
是显示光标的正确方法,由this answer判断(编辑是在@Thomas Dickey评论:wgetch
之后更新的不必要)。因此可以归结为:
nodelay(win_a); // to make wgetch non-blocking
/* ... */
wrefresh(win_a); // to show the cursor
poll(poll_fds, 2, -1);
if (poll_fds[0].revents & POLLIN) {
ch = wgetch(win_a); // to get the actual character
}