2015-04-09 2 views
0

Рассмотрите следующий код. Я хочу, чтобы программа закончилась после нажатия, например. F10. Я не хочу изменять поведение программы, я хотел бы сделать это в фоновом режиме, ожидая нажатия клавиши, а затем закончится. Как изменить программу для достижения этой цели?Ncurses фон ожидания выхода

#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

Может быть, вы могли бы прочитать вход где-то внутри время цикла

keypad(field, TRUE); 
int loop = 1; 
while(loop) { 
    ... 
    int c = wgetch(field); 
    switch(c) { 
    case KEY_F(10): 
     loop = 0; 
     break; 
    default: 
     break; 
    } 
    ... 
} 
0

ссылку: https://www.mkssoftware.com/docs/man3/curs_inopts.3.asp обсуждает CBREAK() и halfdelay() (среди команд других Ncurses)

призывающего CBREAK () в начале программы. тогда, когда вы ищете нажатие клавиши (без блокировки навсегда), используйте halfdelay().

Между этими двумя функциями код должен иметь возможность проверять определенное нажатие клавиши и немедленно реагировать, не имея программного блока, например, getch().

+0

На самом деле вопрос был о ncurses. Этот источник фактически документирует (не замечая факта) старую версию ncurses. –

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; 
} 
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(), который я оставлю в качестве упражнения для вас.

Смежные вопросы