home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / jove-4.16-src.tgz / tar.out / bsd / jove / msgetch.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  7KB  |  254 lines

  1. /************************************************************************
  2.  * This program is Copyright (C) 1986-1996 by Jonathan Payne.  JOVE is  *
  3.  * provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is *
  5.  * included in all the files.                                           *
  6.  ************************************************************************/
  7.  
  8. /* MSDOS keyboard routines */
  9.  
  10. #include "jove.h"
  11.  
  12. #ifdef MSDOS    /* the body is the rest of this file */
  13.  
  14. #include "chars.h"
  15. #include "disp.h"    /* for redisplay() */
  16.  
  17. #include <bios.h>
  18. #include <dos.h>
  19.  
  20.  
  21. private void rawkey_wait proto((void));
  22.  
  23. #ifdef IBMPCDOS
  24. private ZXchar    last = EOF;
  25.  
  26. bool enhanced_keybrd;    /* VAR: exploit "enhanced" keyboard? */
  27.  
  28. /* Unlike the other _NKEYBRD services, the _NKEYBRD_READY service
  29.  * *requires* specific support within _bios_keybrd.  In particular
  30.  * the key information is returned in the ZF flag, which is not
  31.  * captured otherwise.  If _NKEYBRD_READY is defined in the headers,
  32.  * we presume that _bios_keybrd supports it.
  33.  */
  34. # ifdef _NKEYBRD_READY
  35. #  define jkbready() \
  36.     (_bios_keybrd(enhanced_keybrd? _NKEYBRD_READY : _KEYBRD_READY) != 0)
  37. # else /* !_NKEYBRD_READY */
  38. #  ifdef ZTCDOS
  39.     /* Workaround for Zortech 3.0: use Zortech's asm() capability.
  40.      *
  41.      * Interrupt 16h, service 1h (get keyboard status) and
  42.      * interrupt 16h, service 11h (get enhanced keyboard status)
  43.      * return with ZF cleared iff there is a character.
  44.      * The zkbready macro returns YES iff there is a character.
  45.      *
  46.      * Note that the nature of the Zortech asm facility demands
  47.      * that the "service" argument be a constant expression.
  48.      */
  49. #   define zkbready(service)    (0 == (int) asm( \
  50.     0xB4, service,    /* mov ah,service */ \
  51.     0xCD, 0x16,    /* int 16h */ \
  52.     0x9F,        /* lahf */ \
  53.     0x25, 0x00, 0x40,    /* and ax,04000h */ \
  54.     0x99        /* cwd [needed due to a Zortech bug] */ \
  55.     ))
  56. #   define _NKEYBRD_READY    0x11
  57. #   define jkbready()    \
  58.     (enhanced_keybrd? zkbready(_NKEYBRD_READY) : zkbready(_KEYBRD_READY))
  59. #  endif/* ZTCDOS */
  60. # endif /* !_NKEYBRD_READY */
  61.  
  62. # ifdef jkbready    /* we can support enhanced keyboard */
  63. #  ifndef _NKEYBRD_READ
  64. #   define _NKEYBRD_READ        0x10
  65. #  endif
  66. #  define jkbread()    _bios_keybrd(enhanced_keybrd? _NKEYBRD_READ : _KEYBRD_READ)
  67.  
  68. #  ifndef _NKEYBRD_SHIFTSTATUS
  69. #   define _NKEYBRD_SHIFTSTATUS    0x12
  70. #  endif
  71. #  define jkbshift()    _bios_keybrd(enhanced_keybrd? _NKEYBRD_SHIFTSTATUS : _KEYBRD_SHIFTSTATUS)
  72. # else /* !kebready */
  73.    /* We don't know how to support the enhanced keyboard, so we won't */
  74. #  define jkbready()    _bios_keybrd(_KEYBRD_READY)
  75. #  define jkbread()    _bios_keybrd(_KEYBRD_READ)
  76. #  define jkbshift()    _bios_keybrd(_KEYBRD_SHIFTSTATUS)
  77. # endif /* !kebready */
  78.  
  79. /* This table returns an Ascii character corresponding to a Scan Code index.
  80.  * If a key has no ASCII equivalent, the table contains 0.
  81.  */
  82. static const char scanToAsciiLower[] = {
  83.     /* 00 */ 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\\', '\b',
  84.     /* 10 */ '-', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 0, 0, 'a',
  85.     /* 20 */ 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 0, '\r', 0, 'z', 'x',
  86.     /* 30 */ 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, 0, 0, 0, 0, ' ', 0, 0 };
  87.  
  88. static const char scanToAsciiUpper[] = {
  89.     /* 00 */ 0, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '|', '\177',
  90.     /* 10 */ '_', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 0, 0, 'A',
  91.     /* 20 */ 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '\"', 0, '\r', 0, 'Z', 'X',
  92.     /* 30 */ 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, 0, 0, 0, 0, ' ', 0, 0 };
  93.  
  94. #endif /* IBMPCDOS */
  95.  
  96. ZXchar
  97. getrawinchar()
  98. {
  99. #ifdef IBMPCDOS
  100.     unsigned scan;
  101.  
  102.     if (last != EOF) {
  103.         scan = last;
  104.         last = EOF;
  105.         return scan;
  106.     }
  107.  
  108.     rawkey_wait();
  109.     scan = jkbread();
  110.  
  111.     /* check for Ctrl-spacebar and magically turn it into a Ctrl-@
  112.      * (scan == 0x03, char == 0x00).  Because keystrokes are queued
  113.      * but shift state is real-time, we add a (heuristic!) check
  114.      * requiring that no further characters are in the queue.
  115.      * Warning: the heuristic is not perfect.  The control could be
  116.      * recognized even if the it was pressed after the spacebar was
  117.      * released!
  118.      */
  119.     if ((scan&0xff) == ' ' && (jkbshift() & 0x04) && !jkbready())
  120.         scan = 0x0300;
  121.  
  122.     if ((scan&0xff) == 0 || (scan&0xff) == 0xe0) {
  123.         ZXchar    next = ZXRC(scan >> 8);
  124.         ZXchar  asciiChar;
  125.  
  126.         if (MetaKey && next < sizeof(scanToAsciiUpper)
  127.         && 0 != (asciiChar = ((jkbshift() & 0x03) && !jkbready()
  128.             ? scanToAsciiUpper : scanToAsciiLower)[next]))
  129.         {
  130.             last = asciiChar;
  131.             scan = ESC;
  132.         } else {
  133.             /* Re-map shifted arrow keys and shifted Insert, Delete, Home, End,
  134.              * PgUp, and PgDn from 71-83 to 171-183.  This hack depends on
  135.              * the same heuristic as the ctrl-spacebar hack.
  136.              */
  137.             if (71 <= next && next <= 83 && (jkbshift() & 0x03) && !jkbready())
  138.                 next += 100;
  139.             /* Re-map keys that should have been ASCII */
  140.             switch (next) {
  141.             case 0x03:    /* ^@ and ^Space key */
  142.                 scan = '\0';    /* ASCII NUL */
  143.                 break;
  144.             case 0x53:    /* Delete key */
  145.                 scan = DEL;    /* ASCII DEL */
  146.                 break;
  147.             default:
  148.                 last = next;    /* not ASCII: more to come next time */
  149.                 scan = PCNONASCII;
  150.                 break;
  151.             }
  152.         }
  153.     }
  154.     return scan&0xff;
  155.  
  156. #else /* !IBMPCDOS */
  157. # ifdef RAINBOW
  158.  
  159.     union REGS regs;
  160.  
  161.     rawkey_wait();
  162.  
  163.     for (;;) {
  164.         regs.x.di = 2;
  165.         int86(0x18, ®s, ®s);
  166.         if (regs.h.al != 0)    /* should never happen, but who knows */
  167.             return regs.h.al;
  168.     }
  169. # else /* !RAINBOW */
  170.     rawkey_wait();
  171.     return bdos(0x06, 0x00ff, 0xff) & 0xff;
  172. # endif /* !RAINBOW */
  173. #endif /* !IBMPCDOS */
  174. }
  175.  
  176. private bool    waiting = NO;
  177.  
  178. bool
  179. rawkey_ready()
  180. {
  181. #ifdef IBMPCDOS
  182.     return !waiting && (last != EOF || jkbready());
  183. #else /* !IBMPCDOS */
  184.     union REGS regs;
  185.  
  186.     if (waiting)
  187.         return NO;
  188. # ifdef RAINBOW
  189.     regs.x.di = 4;
  190.     int86(0x18, ®s, ®s);
  191.     return regs.h.cl != 0;
  192. # else /* !RAINBOW */
  193.     regs.h.ah = 0x44;        /* ioctl call */
  194.     regs.x.bx = 0;            /* stdin file handle */
  195.     regs.h.al = 0x06;        /* get input status */
  196.     intdos(®s, ®s);
  197.     return regs.h.al & 1;
  198. # endif /* !RAINBOW */
  199. #endif /* !IBMPCDOS */
  200. }
  201.  
  202. /* Wait for next character, updating the modeline if it displays the time.
  203.  * NOTE: this is a busy wait.
  204.  */
  205. private void
  206. rawkey_wait()
  207. {
  208.     while (!rawkey_ready()) {
  209.         if (UpdModLine) {
  210.             waiting = YES;
  211.             redisplay();
  212.             waiting = NO;
  213.         } else if (TimeDisplayed) {
  214.             struct dostime_t tc;
  215.             static char lastmin = 0;
  216.  
  217.             _dos_gettime(&tc);
  218.             if (tc.minute != lastmin) {
  219.                 UpdModLine = YES;
  220.                 lastmin = tc.minute;
  221.             }
  222.         } else {
  223.             /* No reason to busy wait: return to do a blocking read.
  224.              * This might improve performance in multitasking systems.
  225.              */
  226.             break;
  227.         }
  228.     }
  229. }
  230.  
  231. void
  232. ttysetattr(n)
  233. bool    n;    /* also used as subscript! */
  234. {
  235.     static char break_state;
  236.  
  237.     if (n) {
  238.         /* set the break state to off */
  239.         union REGS regs;
  240.  
  241.         regs.h.ah = 0x33;        /* break status */
  242.         regs.h.al = 0x00;        /* request current state */
  243.         intdos(®s, ®s);
  244.         break_state = regs.h.dl;
  245.  
  246.         bdos(0x33, 0, 1);    /* turn off break */
  247.     } else {
  248.         /* restore the break state */
  249.         bdos(0x33, break_state, 1);
  250.     }
  251. }
  252.  
  253. #endif /* MSDOS */
  254.