gpt4 book ai didi

c - ncurses、面板、光标位置和轮询 STDIN

转载 作者:行者123 更新时间:2023-11-30 16:23:42 24 4
gpt4 key购买 nike

我正在尝试使用 ncurses 编写一个程序,该程序轮询主循环中的各种文件描述符。我设法将其缩减为具有单个文件描述符的示例,并且出现了预期的行为:

  • 有两个窗口,由面板库管理。
  • 按空格键会将光标向右移动,当光标到达第一个窗口的末尾时环绕。
  • 按“t”会更改左上角的文本。
  • 按“q”退出程序。

代码:

#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;
}

我不确定这是否是显示光标的最佳方式,但如果没有其他人发布,我会将其作为答案发布。

编辑2:

在 @Thomas Dickey 发表评论后为后代编辑了代码。

最佳答案

根据 this answer 判断,我认为添加 wrefresh 是显示光标的正确方法。 (编辑在@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
}

关于c - ncurses、面板、光标位置和轮询 STDIN,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53922334/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com