home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume2 / window / part2 / getch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-11-30  |  6.1 KB  |  300 lines

  1. /*
  2.  *************
  3.  * DISTRIBUTION NOTICE  July 30 1985
  4.  * A Revised Edition of WM, by Matt Lennon and Tom Truscott,
  5.  *        Research Triangle Institute, (919) 541-7005.
  6.  * Based on the original by Robert Jacob (decvax!nrl-css!jacob),
  7.  *        Naval Research Laboratory, (202) 767-3365.
  8.  * No claims or warranties of any sort are made for this distribution.
  9.  * General permission is granted to copy, but not for profit,
  10.  * any of this distribution, provided that this notice
  11.  * is always included in the copies.
  12.  *************
  13.  */
  14. #include "wm.h"
  15. #include <signal.h>
  16.  
  17. char keycap[200];    /* termcap entries for keypad functions */
  18.  
  19. int tty_backcnt;    /* number of pre-read terminal chars */
  20. char tty_backbuf[10];    /* stack of pre-read chars */
  21. char tty_text[10];    /* actual text corresponding to tty_getch code */
  22. int tty_textlen;    /* strlen(tty_text) */
  23.  
  24. /*
  25.  * Returns true iff a call to tty_realgetch would not block.
  26.  */
  27. tty_inputpending()
  28. {
  29.     long n;
  30.  
  31.     if (tty_backcnt > 0)
  32.     return(TRUE);
  33.     if (ioctl(0, (int)FIONREAD, (char *)&n) == 0 && n > 0)
  34.     return(TRUE);
  35.     return(FALSE);
  36. }
  37.  
  38. /*
  39.  * Read the next character from the terminal (or the backbuf),
  40.  * return EOF if end of file, else (int)the_char, sans parity
  41.  */
  42. int
  43. tty_realgetch()
  44. {
  45.     char c;
  46.  
  47.     if (tty_backcnt > 0)
  48.     c = tty_backbuf[--tty_backcnt];
  49.     else if (read(0, &c, 1) <= 0) {
  50.     tty_text[0] = '\0';
  51.     tty_textlen = 0;
  52.     return(EOF);
  53.     }
  54.     c = toascii(c);
  55.     tty_text[0] = c;
  56.     tty_text[1] = '\0';
  57.     tty_textlen = 1;
  58.     return(c);
  59. }
  60.  
  61. #ifdef GAGMEKEYPAD
  62. init_keypad()
  63. {
  64.     register int i;
  65.     register char *p;
  66.     char buf1[10];
  67.  
  68.     if (p = getcap("ks"))
  69.         putp(p);
  70.     for (i=1,p = "kbkukdklkrkhk0k1k2k3k4k5k6k7k8k9"; *p; i++,p+= 2) {
  71.         (void) sprintf(buf1, "%2.2s", p);
  72.         add_to_try(buf1, i+0400);
  73.     }
  74. }
  75.  
  76. /*
  77. **      add_to_try() (Copyright Pavel Curtis, see notice in hacks.c)
  78. **
  79. **      Construct the try for the current terminal's keypad keys.
  80. **
  81. */
  82. struct try
  83. {
  84.     struct try      *child;     /* ptr to child.  NULL if none          */
  85.     struct try      *sibling;   /* ptr to sibling.  NULL if none        */
  86.     char            ch;         /* character at this node               */
  87.     short           value;      /* code of string so far.  NULL if none */
  88. };
  89.  
  90. static struct  try *newtry;
  91.  
  92. add_to_try(capname, code)
  93. char    *capname;
  94. int code;
  95. {
  96.     register struct try *ptr, *savedptr;
  97.     register char *str, *s;
  98.     static bool     out_of_memory = FALSE;
  99.  
  100.     str = getcap(capname);
  101.     if (! str  ||  out_of_memory)
  102.         return;
  103.     strcat(keycap, capname); strcat(keycap, "=");
  104.     for (s = str; *s; s++) {
  105.         strcat(keycap, mkprint(*s));
  106.     }
  107.     strcat(keycap, ":");
  108.     
  109.     if (newtry != NULL)    
  110.     {
  111.         ptr = newtry;
  112.         
  113.         for (;;)
  114.         {
  115.         while (ptr->ch != *str  &&  ptr->sibling != NULL)
  116.             ptr = ptr->sibling;
  117.         
  118.         if (ptr->ch == *str)
  119.         {
  120.             if (*(++str))
  121.             {
  122.             if (ptr->child != NULL)
  123.                 ptr = ptr->child;
  124.             else
  125.                 break;
  126.             }
  127.             else
  128.             {
  129.             ptr->value = code;
  130.             return;
  131.             }
  132.         }
  133.         else
  134.         {
  135.             if ((ptr->sibling = alloc(1, struct try)) == NULL)
  136.             {
  137.             out_of_memory = TRUE;
  138.             return;
  139.             }
  140.             
  141.             savedptr = ptr = ptr->sibling;
  142.             ptr->child = ptr->sibling = NULL;
  143.             ptr->ch = *str++;
  144.             ptr->value = NULL;
  145.             
  146.             break;
  147.         }
  148.         } /* end for (;;) */  
  149.     }
  150.     else    /* newtry == NULL :: First sequence to be added */
  151.     {
  152.         savedptr = ptr = newtry = alloc(1, struct try);
  153.         
  154.         if (ptr == NULL)
  155.         {
  156.         out_of_memory = TRUE;
  157.         return;
  158.         }
  159.         
  160.         ptr->child = ptr->sibling = NULL;
  161.         ptr->ch = *(str++);
  162.         ptr->value = NULL;
  163.     }
  164.     
  165.         /* at this point, we are adding to the try.  ptr->child == NULL */
  166.         
  167.     while (*str)
  168.     {
  169.         ptr->child = alloc(1, struct try);
  170.         
  171.         ptr = ptr->child;
  172.         
  173.         if (ptr == NULL)
  174.         {
  175.         out_of_memory = TRUE;
  176.         
  177.         ptr = savedptr;
  178.         while (ptr != NULL) 
  179.         {
  180.             savedptr = ptr->child;
  181.             free((char *)ptr);
  182.             ptr = savedptr;
  183.         }
  184.         
  185.         return;
  186.         }
  187.         
  188.         ptr->child = ptr->sibling = NULL;
  189.         ptr->ch = *(str++);
  190.         ptr->value = NULL;
  191.     }
  192.     
  193.     ptr->value = code;
  194.     return;
  195. }
  196.  
  197. #include <setjmp.h>
  198. static jmp_buf jmpbuf;
  199.  
  200. /*
  201. **      tty_getch() (Copyright Pavel Curtis, see notice in hacks.c)
  202. **
  203. **      Get an input character, but take care of keypad sequences, returning
  204. **      an appropriate code when one matches the input.  After each character
  205. **      is received, set an alarm call.  If no more of the sequence
  206. **      is received by the time the alarm goes off, pass through the sequence
  207. **      gotten so far.
  208. **
  209. */
  210. tty_getch()
  211. {
  212.     /* longjmp alert!  beware of register variables */
  213.     register struct try  *ptr;
  214.     int        ch;
  215.     char        buffer[10];     /* Assume no sequences longer than 10 */
  216.     char *bufp = buffer;
  217.     int         (*oldsigalrm)();
  218.     int         sigalrm();
  219.     bool    alarmset;
  220.  
  221.     ptr = newtry;
  222.     alarmset = FALSE;
  223.     oldsigalrm = SIG_DFL;    /* to quiet lint */
  224.     
  225.     do
  226.     {
  227.         if (setjmp(jmpbuf))
  228.         break;
  229.         ch = tty_realgetch();
  230.         if (ch != EOF)              /* returns EOF on error, too */
  231.         *(bufp++) = ch;
  232.         
  233.         while (ptr != NULL  &&  ptr->ch != ch)
  234.         ptr = ptr->sibling;
  235.         
  236.         if (ptr != NULL)
  237.         {
  238.         if (ptr->value != NULL)
  239.         {
  240.             if (alarmset) {
  241.             (void) ualarm(0L);
  242.             (void) signal(SIGALRM, oldsigalrm);
  243.             }
  244.             tty_textlen = bufp-buffer;
  245.             bcopy(buffer, tty_text, tty_textlen);
  246.             return(ptr->value);
  247.         }
  248.         else
  249.         {
  250.             ptr = ptr->child;
  251.             if (!alarmset) {
  252.             alarmset = TRUE;
  253.             oldsigalrm = signal(SIGALRM, sigalrm);
  254.             }
  255.             (void) ualarm(200000L);
  256.         }
  257.         }
  258.         
  259.     } while (ptr != NULL);
  260.     
  261.     if (alarmset) {
  262.         (void) ualarm(0L);
  263.         (void) signal(SIGALRM, oldsigalrm);
  264.     }
  265.     
  266.     if (bufp <= buffer)
  267.         return(EOF);
  268.     while (--bufp > buffer)
  269.         tty_backbuf[tty_backcnt++] = *bufp;
  270.     return(*bufp);
  271. }
  272.  
  273. static
  274. sigalrm()
  275. {
  276.     longjmp(jmpbuf, 1);
  277. }
  278.  
  279. /*
  280.  * ualarm(usec).  If this doesn't compile, just use alarm(0) and alarm(1).
  281.  */
  282. #include <sys/time.h>
  283.  
  284. #define    MILLION    1000000L
  285.  
  286. ualarm(usecs)
  287.     long usecs;
  288. {
  289.     struct itimerval it, oitv;
  290.     register struct itimerval *itp = ⁢
  291.  
  292.     timerclear(&itp->it_interval);
  293.     itp->it_value.tv_sec = usecs/MILLION;
  294.     itp->it_value.tv_usec = usecs%MILLION;
  295.     if (setitimer(ITIMER_REAL, itp, &oitv) < 0)
  296.         return (-1);
  297.     return (oitv.it_value.tv_sec*MILLION+oitv.it_value.tv_usec);
  298. }
  299. #endif
  300.