考虑以下代码。我希望程序在按下例如后结束。 F10 。我不想改变程序的行为,我想在后台做,等待按键然后结束。如何修改程序来实现这个目标?
#include <ncurses.h>
#include <unistd.h>
int main () {
int parent_x, parent_y;
int score_size =10;
int counter =0 ;
initscr();
noecho();
curs_set(FALSE);
getmaxyx(stdscr, parent_y, parent_x);
WINDOW *field = newwin(parent_y - score_size, parent_x, 0, 0);
WINDOW *score = newwin(score_size, parent_x, parent_y - score_size, 0);
while(true) {
mvwprintw(field, 0, counter, "Field");
mvwprintw(score, 0, counter, "Score");
wrefresh(field);
wrefresh(score);
sleep(5);
wclear(score);
wclear(field);
counter++;
}
delwin(field);
delwin(score);
endwin();
}
答案 0 :(得分:0)
也许你可以在while循环中的某处读取输入
keypad(field, TRUE);
int loop = 1;
while(loop) {
...
int c = wgetch(field);
switch(c) {
case KEY_F(10):
loop = 0;
break;
default:
break;
}
...
}
答案 1 :(得分:0)
此链接:https://www.mkssoftware.com/docs/man3/curs_inopts.3.asp 讨论了cbreak()和halfdelay()(以及其他ncurses命令)
在程序开头附近调用cbreak()。 然后在寻找击键时(不会永远阻挡)使用halfdelay()。
在这两个函数之间,代码应该能够检查某个键击并立即响应,而不需要像getch()这样的程序块。
答案 2 :(得分:0)
组合两者(既不完整),要识别 F10 ,你必须调用keypad
,而要进行单字符处理,你需要像cbreak
这样的东西,或者甚至是raw
。这是一个完整的例子:
#include <ncurses.h>
#include <stdlib.h>
int main (void) {
int parent_x, parent_y;
int score_size =10;
int counter =0 ;
bool loop = TRUE;
WINDOW *field;
WINDOW *score;
initscr();
cbreak();
noecho();
curs_set(FALSE);
getmaxyx(stdscr, parent_y, parent_x);
field = newwin(parent_y - score_size, parent_x, 0, 0);
score = newwin(score_size, parent_x, parent_y - score_size, 0);
keypad(field, TRUE);
halfdelay(1);
while(loop) {
int c = wgetch(field);
switch(c) {
case KEY_F(10):
loop = FALSE;
continue;
default:
break;
}
mvwprintw(field, 0, counter, "Field");
mvwprintw(score, 0, counter, "Score");
wrefresh(field);
wrefresh(score);
napms(5000); /* don't use sleep(5) */
wclear(score);
wclear(field);
counter++;
}
delwin(field);
delwin(score);
endwin();
return EXIT_SUCCESS;
}
答案 3 :(得分:0)
最简单的方法是将您的sleep(5)
替换为select()
,并暂停5秒,例如:
#include <stdlib.h>
#include <ncurses.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
int main(void) {
int parent_x, parent_y;
int score_size = 10;
int counter = 0;
WINDOW * mainwin = initscr();
noecho();
crmode();
keypad(mainwin, TRUE);
wrefresh(mainwin);
curs_set(FALSE);
getmaxyx(stdscr, parent_y, parent_x);
WINDOW *field = newwin(parent_y - score_size, parent_x, 0, 0);
WINDOW *score = newwin(score_size, parent_x, parent_y - score_size, 0);
while ( true ) {
mvwprintw(field, 0, counter, "Field");
mvwprintw(score, 0, counter, "Score");
wrefresh(field);
wrefresh(score);
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
int status = select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv);
if ( status == -1 ) {
perror("error calling select()");
exit(EXIT_FAILURE);
}
else if ( status == 1 ) {
if ( wgetch(mainwin) == KEY_F(10) ) {
break;
}
}
wclear(score);
wclear(field);
counter++;
}
delwin(field);
delwin(score);
endwin();
}
这样做的缺点是,如果你按下 F10 以外的键,你的循环将立即重复,5秒的延迟将重新启动。解决此问题的最简单方法是使延迟取决于计时器,例如:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <ncurses.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
/* Signal handler, doesn't need to do anything */
void handler(int signum)
{
(void) signum; /* Do nothing */
}
int main(void)
{
int parent_x, parent_y;
int score_size = 10;
int counter = 0;
/* Register signal handler for SIGALRM */
struct sigaction sa;
sa.sa_handler = handler;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
if ( sigaction(SIGALRM, &sa, NULL) == -1 ) {
perror("error calling sigaction()");
exit(EXIT_FAILURE);
}
/* Create timer */
struct itimerval itv;
itv.it_interval.tv_sec = 5;
itv.it_interval.tv_usec = 0;
itv.it_value.tv_sec = 5;
itv.it_value.tv_usec = 0;
if ( setitimer(ITIMER_REAL, &itv, NULL) != 0 ) {
perror("seeor calling setitimer()");
exit(EXIT_FAILURE);
}
/* Initialize curses */
WINDOW * mainwin = initscr();
noecho();
crmode();
keypad(mainwin, TRUE);
wrefresh(mainwin);
curs_set(FALSE);
/* Create windows */
getmaxyx(stdscr, parent_y, parent_x);
WINDOW *field = newwin(parent_y - score_size, parent_x, 0, 0);
WINDOW *score = newwin(score_size, parent_x, parent_y - score_size, 0);
while ( true ) {
mvwprintw(field, 0, counter, "Field");
mvwprintw(score, 0, counter, "Score");
wrefresh(field);
wrefresh(score);
/* Wait for available input */
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
int status = select(STDIN_FILENO + 1, &fds, NULL, NULL, NULL);
if ( status == -1 ) {
/* select() returned an error... */
if ( errno == EINTR ) {
/* Interrupted by SIGALRM, so update counter */
wclear(score);
wclear(field);
counter++;
}
else {
/* Other error, so quit */
delwin(field);
delwin(score);
endwin();
perror("error calling select()");
exit(EXIT_FAILURE);
}
}
else if ( status == 1 ) {
/* Input ready, so get and check for F10 */
if ( wgetch(mainwin) == KEY_F(10) ) {
break;
}
}
}
/* Clean up and exit */
delwin(field);
delwin(score);
endwin();
return 0;
}
这将完全符合您的要求。在SIGALRM
次调用之间可能会触发select()
的可能性很小,导致更新被跳过。你可以通过切换到pselect()
来解决这个问题,我将把它作为练习留给你。