home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 3 Comm / 03-Comm.zip / mincom15.zip / wkeys.c < prev   
C/C++ Source or Header  |  1993-10-14  |  6KB  |  312 lines

  1. /*
  2.  * This file is part of the Minicom Communications Program,
  3.  * written by Miquel van Smoorenburg 1991/1992/1993.
  4.  *
  5.  * Read a keypress from the standard input. If it is an escape
  6.  * code, return a special value.
  7.  *
  8.  * WARNING: possibly the most ugly code in this package!
  9.  */
  10. #if defined(_BSD43) && defined(_SELECT)
  11. #  undef _POSIX_SOURCE
  12. #endif
  13. #include <sys/types.h>
  14. #if defined(MINIX) || defined(linux)
  15. #  include <termcap.h>
  16. #else
  17. char *tgetstr();
  18. int tgetent();
  19. #endif
  20. #if defined (_POSIX_SOURCE) || defined(_BSD43)
  21. #  include <stdlib.h>
  22. #  include <unistd.h>
  23. #else
  24. char *getenv();
  25. #endif
  26. #ifdef _SELECT
  27. #  include <sys/time.h>
  28. #else
  29. #  include <signal.h>
  30. #endif
  31. #include <string.h>
  32. #include <errno.h>
  33. #include "window.h"
  34. #ifndef BBS
  35. #  include "config.h"
  36. #endif
  37.  
  38. #if KEY_KLUDGE && defined(linux)
  39. #  include <sys/kd.h>
  40. #  include <sys/ioctl.h>
  41. #endif
  42.  
  43. static struct key _keys[NUM_KEYS];
  44. extern int setcbreak();
  45. extern WIN *us;
  46.  
  47. /*
  48.  * The following is an external pointer to the termcap info.
  49.  * If it's NOT zero then the main program has already
  50.  * read the termcap for us. No sense in doing it twice.
  51.  */
  52. extern char *_tptr;
  53.  
  54. static char erasechar;
  55. static int gotalrm;
  56. extern int errno;
  57. int pendingkeys = 0;
  58.  
  59. #ifdef _MINIX
  60. /*
  61.  * MINIX (and some others, sigh) use F1-10. BSD uses k1-a (mostly..)
  62.  */
  63. static char *func_key[] = { 
  64.     "", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F0",
  65.     "kh", "kP", "ku", "kl", "kr", "kd", "kH", "kN", "kI", "kD",
  66.     (char *)0 };
  67. #else
  68. static char *func_key[] = { 
  69.     "", "k1", "k2", "k3", "k4", "k5", "k6", "k7", "k8", "k9", "ka",
  70.     "kh", "kP", "ku", "kl", "kr", "kd", "kH", "kN", "kI", "kD",
  71.     (char *)0 };
  72. #endif    
  73.  
  74. #if KEY_KLUDGE
  75. #ifdef _V7
  76. #  include <sgtty.h>
  77. #endif
  78. /*
  79.  * A VERY DIRTY HACK FOLLOWS:
  80.  * This routine figures out if the tty we're using is a serial
  81.  * device OR an IBM PC console. If we're using a console, we can
  82.  * easily reckognize single escape-keys since escape sequences
  83.  * always return > 1 characters from a read()
  84.  */
  85. static int isconsole;
  86.  
  87. static int testconsole()
  88. {
  89. #ifndef linux
  90.   struct sgttyb sg, ng;
  91.  
  92.   /* Get parameters */
  93.   ioctl(0, TIOCGETP, &ng);
  94.   /* Save old parameters */
  95.   ioctl(0, TIOCGETP, &sg);
  96.   
  97.   ng.sg_ispeed = 0;
  98.   ng.sg_ospeed = 1;
  99.   
  100.   /* Set new speed */
  101.   ioctl(0, TIOCSETP, &ng);
  102.   /* Read new speed */
  103.   ioctl(0, TIOCGETP, &ng);
  104.   /* Restore old value */
  105.   ioctl(0, TIOCSETP, &sg);
  106.   
  107.   /* RS 232 lines will have defaulted the ispeed since it was too low! */
  108.   return (ng.sg_ispeed == 0);
  109. #else
  110.   /* For Linux it's easy to see if this is a VC. */
  111.   int info;
  112.  
  113.   return( ioctl(0, KDGETLED, &info) == 0);
  114. #endif
  115. }
  116.  
  117. /*
  118.  * Function to read chunks of data from fd 0 all at once
  119.  */
  120. static int keys_in_buf;
  121.  
  122. static int cread(c)
  123. char *c;
  124. {
  125.   static char buf[32];
  126.   static int idx = 0;
  127.   static int lastread = 0;
  128.  
  129.   if (idx > 0 && idx < lastread) {
  130.       *c = buf[idx++];
  131.     keys_in_buf--;
  132.       return(lastread);
  133.   }
  134.   idx = 0;
  135.   do {
  136.     lastread = read(0, buf, 32);
  137.     keys_in_buf = lastread - 1;
  138.   } while(lastread < 0 && errno == EINTR);
  139.  
  140.   *c = buf[0];
  141.   if (lastread > 1) idx = 1;
  142.   return(lastread);
  143. }
  144. #endif
  145.  
  146. static void _initkeys()
  147. {
  148.   int i;
  149.   static char *cbuf, *tbuf;
  150.   char *term;
  151.  
  152.   if (_tptr == CNULL) {
  153.     if ((tbuf = (char *)malloc(512)) == CNULL || 
  154.         (cbuf = (char *)malloc(1024)) == CNULL) {
  155.           write(2, "Out of memory.\n", 15);
  156.           exit(1);
  157.     }
  158.     term = getenv("TERM");
  159.     switch(tgetent(cbuf, term)) {
  160.           case 0:
  161.               write(2, "No termcap entry.\n", 18);
  162.               exit(1);
  163.           case -1:
  164.               write(2, "No /etc/termcap present!\n", 25);
  165.               exit(1);
  166.           default:
  167.               break;
  168.       }
  169.     _tptr = tbuf;
  170.   }    
  171. /* Initialize codes for special keys */
  172.   for(i = 0; func_key[i]; i++) {
  173.       if ((_keys[i].cap = tgetstr(func_key[i], &_tptr)) == CNULL)
  174.           _keys[i].cap = "";
  175.       _keys[i].len = strlen(_keys[i].cap);
  176.   }
  177. #if KEY_KLUDGE
  178.   isconsole = testconsole();
  179. #endif
  180. }
  181.   
  182. /*
  183.  * Dummy routine for the alarm signal
  184.  */
  185. #ifndef _SELECT
  186. static void dummy()
  187. {
  188.   gotalrm = 1;
  189. }
  190. #endif
  191.   
  192. /*
  193.  * Read a character from the keyboard.
  194.  * Handle special characters too!
  195.  */
  196. int getch()
  197. {
  198.   int f, g;
  199.   int match = 1;
  200.   int len;
  201.   unsigned char c;
  202.   static unsigned char mem[8];
  203.   static int leftmem = 0;
  204.   static int init = 0;
  205.   int nfound = 0;
  206. #ifdef _SELECT
  207.   struct timeval timeout;
  208.   fd_set readfds;
  209.   static fd_set *nofds = (fd_set *)0;
  210. #endif
  211.  
  212.   if (init == 0) {
  213.       _initkeys();
  214.       init++;
  215.       erasechar = setcbreak(3);
  216.   }
  217.  
  218.   /* Some sequence still in memory ? */
  219.   if (leftmem) {
  220.     leftmem--;
  221.     if (leftmem == 0) pendingkeys = 0;
  222.     return(mem[leftmem]);
  223.   }
  224.   gotalrm = 0;
  225.   pendingkeys = 0;
  226.  
  227.   for (len = 1; len < 8 && match; len++) {
  228. #ifdef _SELECT
  229. #if KEY_KLUDGE
  230.     if (len > 1 && keys_in_buf == 0) {
  231. #else
  232.     if (len > 1) {
  233. #endif
  234.         timeout.tv_sec = 0;
  235.         timeout.tv_usec = 400000; /* 400 ms */
  236. #ifdef FD_SET
  237.         FD_ZERO(&readfds);
  238.         FD_SET(0, &readfds);
  239. #else
  240.         readfs = 1; /* First bit means file descriptor #0 */
  241. #endif
  242. #ifdef _HPUX_SOURCE
  243.         /* HPUX prototype of select is mangled */
  244.         nfound = select(1, (int *)&readfds,
  245.                 (int *)nofds, (int *)nofds, &timeout);
  246. #else
  247.         nfound = select(1, &readfds, nofds, nofds, &timeout);
  248. #endif
  249.         if (nfound == 0) {
  250.             break;
  251.         }
  252.     }
  253. #else
  254.     if (len > 1) {
  255.         signal(SIGALRM, dummy);
  256.         alarm(1);
  257.     }
  258. #endif
  259. #if KEY_KLUDGE
  260.     while((nfound = cread(&c)) < 0 && (errno == EINTR && !gotalrm))
  261.         ;
  262. #else
  263.       while ((nfound = read(0, &c, 1)) < 0 && (errno == EINTR && !gotalrm))
  264.           ;
  265. #endif
  266. #ifndef _SELECT
  267.     if (len > 1) alarm(0);
  268. #endif
  269.     if (nfound < 1) break;
  270.  
  271.       if (len == 1) {
  272.       /* Enter and erase have precedence over anything else */
  273.           if (c == (unsigned char)'\n')
  274.               return c;
  275.         if (c == (unsigned char)erasechar)
  276.             return K_ERA;
  277.       }
  278. #if KEY_KLUDGE
  279.     if (isconsole && nfound == 1 && len == 1) return(c);
  280. #endif
  281.       mem[len - 1] = c;
  282.       match = 0;
  283.       for (f = 0; f < NUM_KEYS; f++)
  284.           if (_keys[f].len >= len && strncmp(_keys[f].cap, (char *)mem, len) == 0){
  285.               match++;
  286.               if (_keys[f].len == len) {
  287.                   return(f + KEY_OFFS);
  288.               }
  289.           }
  290.   }
  291.   /* No match. in len we have the number of characters + 1 */
  292.   len--; /* for convenience */
  293.   if (len == 1) return(mem[0]);
  294.   /* Remember there are more keys waiting in the buffer */
  295.   pendingkeys++;
  296.  
  297. #ifndef _SELECT
  298.   /* Pressing eg escape twice means escape */
  299.   if (len == 2 && mem[0] == mem[1]) return(mem[0]);
  300. #endif
  301.   
  302.   /* Reverse the "mem" array */
  303.   for(f = 0; f < len / 2; f++) {
  304.       g = mem[f];
  305.       mem[f] = mem[len - f - 1];
  306.       mem[len - f - 1] = g;
  307.   }
  308.   leftmem = len - 1;
  309.   return(mem[leftmem]);
  310. }
  311.  
  312.