Support timeout in the menu
authorhpa <hpa>
Tue, 21 Dec 2004 23:31:45 +0000 (23:31 +0000)
committerhpa <hpa>
Tue, 21 Dec 2004 23:31:45 +0000 (23:31 +0000)
com32/include/sys/times.h
com32/libutil/get_key.c
com32/libutil/include/getkey.h
com32/modules/menu.c
com32/samples/keytest.c

index 173efe2..8d03af0 100644 (file)
@@ -11,8 +11,8 @@ struct tms {
   /* Empty */
 };
 
-#define HZ      18             /* Piddly resolution... */
-#define CLK_TCK        HZ
+#define HZ             18      /* Piddly resolution... */
+#define CLK_TCK                HZ
 
 typedef uint16_t clock_t;
 
index b9042d6..5cc147f 100644 (file)
@@ -111,7 +111,7 @@ static const struct keycode keycodes[] = {
 };
 #define NCODES ((int)(sizeof keycodes/sizeof(struct keycode)))
 
-int get_key(FILE *f)
+int get_key(FILE *f, clock_t timeout)
 {
   unsigned char buffer[MAXLEN];
   int nc, i, rv;
@@ -120,19 +120,23 @@ int get_key(FILE *f)
   unsigned char ch;
   clock_t start;
 
+  /* We typically start in the middle of a clock tick */
+  if ( timeout )
+    timeout++;
+
   nc = 0;
   start = times(NULL);
   do {
     rv = read(fileno(f), &ch, 1);
     if ( rv == 0 || (rv == -1 && errno == EAGAIN) ) {
-      if ( nc && (clock_t)(times(NULL)-start) >= 2+CLK_TCK/20 )
-       return buffer[0];       /* timeout */
-      else {
-       if ( !nc )
-         start = times(NULL);
-       another = 1;
-       continue;
-      }
+      clock_t lateness = times(NULL)-start;
+      if ( nc && lateness > 1+CLK_TCK/20 )
+       return buffer[0];       /* timeout in sequence */
+      else if ( !nc && timeout && lateness > timeout )
+       return KEY_NONE;        /* timeout before sequence */
+
+      another = 1;
+      continue;
     }
 
     start = times(NULL);
index 99171e1..37efc66 100644 (file)
@@ -36,6 +36,9 @@
 #define LIBUTIL_GETKEY_H
 
 #include <stdio.h>
+#include <sys/times.h>
+
+#define KEY_NONE       (-1)
 
 #define KEY_CTRL(x)    ((x) & 0x001f)
 #define KEY_BACKSPACE  0x0008
@@ -67,6 +70,6 @@
 #define KEY_INS                0x0128
 #define KEY_DEL                0x0129
 
-int get_key(FILE *);
+int get_key(FILE *, clock_t);
 
 #endif /* LIBUTIL_GETKEY_H */
index c9794c2..fe4d94a 100644 (file)
 #include <consoles.h>
 #include <getkey.h>
 #include <minmax.h>
+#include <time.h>
+#include <sys/times.h>
+#include <unistd.h>
 #ifdef __COM32__
 #include <com32.h>
 #endif
 
 #include "menu.h"
 
+#ifndef CLK_TCK
+# define CLK_TCK sysconf(_SC_CLK_TCK)
+#endif
+
 struct menu_attrib {
   const char *border;          /* Border area */
   const char *title;           /* Title bar */
@@ -135,11 +142,11 @@ void draw_menu(int sel, int top)
   printf("%s\033[%d;1H", menu_attrib->screen, END_ROW);
 }
 
-char *edit_cmdline(char *input)
+char *edit_cmdline(char *input, int top)
 {
   static char cmdline[MAX_CMDLINE_LEN];
   int key, len;
-  int redraw = 1;
+  int redraw = 2;
 
   strncpy(cmdline, input, MAX_CMDLINE_LEN);
   cmdline[MAX_CMDLINE_LEN-1] = '\0';
@@ -147,7 +154,14 @@ char *edit_cmdline(char *input)
   len = strlen(cmdline);
 
   for (;;) {
-    if ( redraw ) {
+    if ( redraw > 1 ) {
+      /* Clear and redraw whole screen */
+      printf("%s\033[2J", menu_attrib->screen);
+      draw_menu(-1, top);
+    }
+
+    if ( redraw > 0 ) {
+      /* Redraw the command line */
       printf("\033[%d;1H%s> %s%s",
             CMDLINE_ROW, menu_attrib->cmdmark,
             menu_attrib->cmdline, pad_line(cmdline, 0, MAX_CMDLINE_LEN-1));
@@ -156,11 +170,14 @@ char *edit_cmdline(char *input)
       redraw = 0;
     }
 
-    key = get_key(stdin);
+    key = get_key(stdin, 0);
 
     /* FIX: should handle arrow keys and edit-in-middle */
 
     switch( key ) {
+    case KEY_CTRL('L'):
+      redraw = 2;
+      break;
     case KEY_ENTER:
     case KEY_CTRL('J'):
       return cmdline;
@@ -212,6 +229,11 @@ const char *run_menu(void)
   int top = 0;
   int clear = 1;
   char *cmdline;
+  clock_t key_timeout;
+
+  /* Convert timeout from deciseconds to clock ticks */
+  /* Note: for both key_timeout and timeout == 0 means no limit */
+  key_timeout = (clock_t)(CLK_TCK*timeout+9)/10;
 
   while ( !done ) {
     if ( entry < 0 )
@@ -231,8 +253,20 @@ const char *run_menu(void)
 
     draw_menu(entry, top);
 
-    key = get_key(stdin);
+    key = get_key(stdin, key_timeout);
     switch ( key ) {
+    case KEY_NONE:             /* Timeout */
+      /* This is somewhat hacky, but this at least lets the user
+        know what's going on, and still deals with "phantom inputs"
+        e.g. on serial ports. */
+      if ( entry != defentry )
+       entry = defentry;
+      else
+       done = 1;
+      break;
+    case KEY_CTRL('L'):
+      clear = 1;
+      break;
     case KEY_ENTER:
     case KEY_CTRL('J'):
       done = 1;
@@ -268,8 +302,7 @@ const char *run_menu(void)
       break;
     case KEY_TAB:
       if ( allowedit ) {
-       draw_menu(-1, top);     /* Disable bar */
-       cmdline = edit_cmdline(menu_entries[entry].cmdline);
+       cmdline = edit_cmdline(menu_entries[entry].cmdline, top);
        if ( cmdline )
          return cmdline;
        else
index d10bd66..0433201 100644 (file)
@@ -33,7 +33,7 @@ static void cooked_keys(void)
   printf("[cooked]");
 
   for(;;) {
-    key = get_key(stdin);
+    key = get_key(stdin, 0);
 
     if ( key == 0x03 ) {
       printf("[done]\n");