Sonntag, 30. Dezember 2012

pdcurses - timeout example

Introduction

In PDCurses there is a halfdelay(TENTHS) mode which implements a small delay (TENTHS tenths of a second) after each input. If there is no input after this time, the corresponding input function returns ERR. Somewhat confusingly, the symbol ERR doesn't actually mean an "error" occured in this case. Only that no input has been received yet. In this mode, it is possible to call the input function as part of a loop -- we can be sure that the function will exit after at most TENTHS tenths of a second. Then we can do some intermediate processing and then repeat the input function in a loop.

Example

Let's write a program that uses curses in halfdelay mode to get an input string from the user. As intermediate processing we will echo the characters to the screen and store them in a buffer. Additionally, we will also check to see if a timeout has occured, and abort the input early if this is the case. Notice that our notion of "timeout" (specified by the parameter TIMEOUT) is independent from the curses notion of "timeout" (specified by the parameter TENTHS).

Note

In halfdelay mode, functions like scanw(3) do not seem to work properly, at least with pdcurses. Therefore, in halfdelay mode, we must obligate ourselves to "roll our own" line input functions as demonstrated in the below example.

Usage

The program takes two parameters: the PROMPT and the TIMEOUT. If the timeout is reached, the input aborts early. The input finishes normally when the user types a newline. The erase key (e.g. "backspace") is interpreted as normally would be expected, and all other special characters are ignored.

Source Listing

 #include <curses.h>  
 #include <stdio.h>  
 #include <stdlib.h>  
 #include <stdbool.h>  
 #include <time.h>  
 #include <ctype.h>  
   
 #define TENTHS 1  
 #define MAX 80  
   
 void do_endwin(void) {endwin();}  
   
 #define SELF_EXE argv[0]  
 #define PROMPT argv[1]  
 #define TIMEOUT argv[2]  
 int main(int argc, char *argv[])  
 {  
     if (argc != 3) {  
         fprintf(stderr, "Usage: %s PROMPT TIMEOUT\n", SELF_EXE);  
         exit(EXIT_FAILURE);  
     }  
     if (initscr() == NULL) {  
         fprintf(stderr, "Could not initialize screen\n");  
         exit(EXIT_FAILURE);  
     }  
     atexit(do_endwin);  
     halfdelay(TENTHS);            // halfdelay mode ON  
     keypad(stdscr, TRUE);        // keypad mode ON  
     noecho();                    // echo mode OFF  
   
     // Parameters for custom input routine  
     int timeout = atoi(TIMEOUT);  
     char buf[MAX] = {'\0'};  
     bool timeout_occured = false;  
   
     // Begin custom input routine  
     // Show PROMPT and receive input from the user into buf  
     // Abort if timeout seconds have elapsed; in this case timeout_occured  
     // is set to true  
     // Up to MAX-1 characters may be typed or stored in buf  
     printw("%s\n", PROMPT);  
     refresh();  
     time_t now = time(NULL);  
     int i=0;  
     for (;;) {  
         // check for timeout  
         time_t diff = time(NULL) - now;  
         struct tm *t = localtime(&diff);  
         if (t->tm_sec >= timeout) {  
             timeout_occured = true;  
             buf[i] = '\0';  
             break;  
         }  
                       
         // Read a character into ch and check for various errors  
         // ERR is not really an error; it just means there was no input yet  
         // erasechar() returns this terminal's "erase key" (e.g. backspace)  
         int ch = getch();  
         if (ch == ERR) {   
             continue;  
         }else if (ch == erasechar() && i==0) { // erase key at line start  
             flash();  
             continue;  
         }else if (ch == erasechar()) { // erase key at non-line start  
             i--;  
             printw("%c %c", ch, ch); // delete the previous character  
             refresh();  
             continue;  
         }else if (ch == '\n') { // newline was pressed  
             buf[i] = '\0';  
             break;  
         }else if (iscntrl(ch)) { // control key (e.g. CTRL-C) pressed  
             flash();  
             continue;  
         }else if (ch != (char)ch) { // non-character key pressed  
             flash();  
             continue;  
         }else if (i == MAX-1) { // other key pressed but no more room in buf  
             flash();  
             continue;  
         }  
           
         // store and echo the character  
         buf[i++] = ch;          
         printw("%c", ch);  
         refresh();  
     }  
     printw("\n");  
     refresh();  
     // End custom input routine  
       
     // Results of the custom input routine  
     printw("\nInput string received:\n");  
     printw("%s\n", buf);  
     printw("\nTimeout occured: %s\n", timeout_occured ? "YES" : "NO");  
     refresh();  
       
     // Print message and wait for user to press a key  
     printw("Press any key to end the program...");  
     refresh();  
     for (;;) {  
         int ch = getch();  
         if (ch == ERR)  
             continue;  
         break;  
     }  
     exit(EXIT_SUCCESS);  
 }  
   


References

http://www.mkssoftware.com/docs/man3/curs_beep.3.asp
http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/init.html

Keine Kommentare:

Kommentar veröffentlichen