home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / bios / key.c < prev    next >
Text File  |  1998-06-08  |  17KB  |  648 lines

  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: f:/miner/source/bios/rcs/key.c $
  15.  * $Revision: 1.35 $
  16.  * $Author: john $
  17.  * $Date: 1995/01/25 20:13:30 $
  18.  * 
  19.  * Functions for keyboard handler.
  20.  * 
  21.  * $Log: key.c $
  22.  * Revision 1.35  1995/01/25  20:13:30  john
  23.  * Took out not passing keys to debugger if w10.
  24.  * 
  25.  * Revision 1.34  1995/01/14  19:19:31  john
  26.  * Made so when you press Shift+Baskspace, it release keys autmatically.
  27.  * 
  28.  * Revision 1.33  1994/12/13  09:21:48  john
  29.  * Took out keyd_editor_mode, and KEY_DEBUGGED stuff for NDEBUG versions.
  30.  * 
  31.  * Revision 1.32  1994/11/12  13:52:01  john
  32.  * Fixed bug with code that cleared bios buffer.
  33.  * 
  34.  * Revision 1.31  1994/10/24  15:16:16  john
  35.  * Added code to detect KEY_PAUSE.
  36.  * 
  37.  * Revision 1.30  1994/10/24  13:57:53  john
  38.  * Hacked in support for pause key onto code 0x61.
  39.  * 
  40.  * Revision 1.29  1994/10/21  15:18:13  john
  41.  * *** empty log message ***
  42.  * 
  43.  * Revision 1.28  1994/10/21  15:17:24  john
  44.  * Made LSHIFT+BACKSPACE do what PrtScr used to.
  45.  * 
  46.  * Revision 1.27  1994/09/22  16:09:18  john
  47.  * Fixed some virtual memory lockdown problems with timer and
  48.  * joystick.
  49.  * 
  50.  * Revision 1.26  1994/09/15  21:32:47  john
  51.  * Added bounds checking for down_count scancode
  52.  * parameter.
  53.  * 
  54.  * Revision 1.25  1994/08/31  12:22:20  john
  55.  * Added KEY_DEBUGGED
  56.  * 
  57.  * Revision 1.24  1994/08/24  18:53:48  john
  58.  * Made Cyberman read like normal mouse; added dpmi module; moved
  59.  * mouse from assembly to c. Made mouse buttons return time_down.
  60.  * 
  61.  * Revision 1.23  1994/08/18  15:17:51  john
  62.  * *** empty log message ***
  63.  * 
  64.  * Revision 1.22  1994/08/18  15:16:38  john
  65.  * fixed some bugs with clear_key_times and then
  66.  * removed it because i fixed key_flush to do the
  67.  * same.
  68.  * 
  69.  * Revision 1.21  1994/08/17  19:01:25  john
  70.  * Attempted to fix a bug with a key being held down
  71.  * key_flush called, then the key released having too 
  72.  * long of a time.
  73.  * 
  74.  * Revision 1.20  1994/08/08  10:43:48  john
  75.  * Recorded when a key was pressed for key_inkey_time.
  76.  * 
  77.  * Revision 1.19  1994/06/22  15:00:03  john
  78.  * Made keyboard close automatically on exit.
  79.  * 
  80.  * Revision 1.18  1994/06/21  09:16:29  john
  81.  * *** empty log message ***
  82.  * 
  83.  * Revision 1.17  1994/06/21  09:08:23  john
  84.  * *** empty log message ***
  85.  * 
  86.  * Revision 1.16  1994/06/21  09:05:01  john
  87.  * *** empty log message ***
  88.  * 
  89.  * Revision 1.15  1994/06/21  09:04:24  john
  90.  * Made PrtScreen do an int5
  91.  * 
  92.  * Revision 1.14  1994/06/17  17:17:06  john
  93.  * Added keyd_time_last_key_was_pressed or something like that.
  94.  * 
  95.  * Revision 1.13  1994/05/14  13:55:16  matt
  96.  * Added #define to control key passing to bios
  97.  * 
  98.  * Revision 1.12  1994/05/05  18:09:39  john
  99.  * Took out BIOS to prevent stuck keys.
  100.  * 
  101.  * Revision 1.11  1994/05/03  17:39:12  john
  102.  * *** empty log message ***
  103.  * 
  104.  * Revision 1.10  1994/04/29  12:14:20  john
  105.  * Locked all memory used during interrupts so that program
  106.  * won't hang when using virtual memory.
  107.  * 
  108.  * Revision 1.9  1994/04/28  23:49:41  john
  109.  * Made key_flush flush more keys and also did something else but i forget what.
  110.  * 
  111.  * Revision 1.8  1994/04/22  12:52:12  john
  112.  * *** empty log message ***
  113.  * 
  114.  * Revision 1.7  1994/04/01  10:44:59  mike
  115.  * Change key_getch() to call getch() if our interrupt hasn't been installed.
  116.  * 
  117.  * Revision 1.6  1994/03/09  10:45:48  john
  118.  * Neatend code a bit.
  119.  * 
  120.  * Revision 1.5  1994/02/17  17:24:16  john
  121.  * Neatened up a bit.
  122.  * 
  123.  * Revision 1.4  1994/02/17  16:30:29  john
  124.  * Put in code to pass keys when in debugger.
  125.  * 
  126.  * Revision 1.3  1994/02/17  15:57:59  john
  127.  * Made handler not chain to BIOS handler.
  128.  * 
  129.  * Revision 1.2  1994/02/17  15:56:06  john
  130.  * Initial version.
  131.  * 
  132.  * Revision 1.1  1994/02/17  15:54:07  john
  133.  * Initial revision
  134.  * 
  135.  * 
  136.  */
  137.  
  138. //#define PASS_KEYS_TO_BIOS    1            //if set, bios gets keys
  139.  
  140. #pragma off (unreferenced)
  141. static char rcsid[] = "$Id: key.c 1.35 1995/01/25 20:13:30 john Exp $";
  142. #pragma on (unreferenced)
  143.  
  144. #include <stdlib.h>
  145. #include <stdio.h>
  146. #include <conio.h>
  147. #include <dos.h>
  148. #include <i86.h>
  149.  
  150. //#define WATCOM_10
  151.  
  152. #include "error.h"
  153. #include "key.h"
  154. #include "timer.h"
  155. #include "dpmi.h"
  156.  
  157. #define KEY_BUFFER_SIZE 16
  158.  
  159. //-------- Variable accessed by outside functions ---------
  160. unsigned char                 keyd_buffer_type;        // 0=No buffer, 1=buffer ASCII, 2=buffer scans
  161. unsigned char                 keyd_repeat;
  162. unsigned char                 keyd_editor_mode;
  163. volatile unsigned char     keyd_last_pressed;
  164. volatile unsigned char     keyd_last_released;
  165. volatile unsigned char    keyd_pressed[256];
  166. volatile int                keyd_time_when_last_pressed;
  167.  
  168. typedef struct keyboard    {
  169.     unsigned short        keybuffer[KEY_BUFFER_SIZE];
  170.     fix                    time_pressed[KEY_BUFFER_SIZE];
  171.     fix                    TimeKeyWentDown[256];
  172.     fix                    TimeKeyHeldDown[256];
  173.     unsigned int        NumDowns[256];
  174.     unsigned int        NumUps[256];
  175.     unsigned int         keyhead, keytail;
  176.     unsigned char         E0Flag;
  177.     unsigned char         E1Flag;
  178.     int                     in_key_handler;
  179.     void (__interrupt __far *prev_int_9)();
  180. } keyboard;
  181.  
  182. static volatile keyboard key_data;
  183.  
  184. static unsigned char Installed=0;
  185.  
  186. unsigned char ascii_table[128] = 
  187. { 255, 255, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=',255,255,
  188.   'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 255, 255,
  189.   'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 39, '`',
  190.   255, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 255,'*',
  191.   255, ' ', 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255,255,
  192.   255, 255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
  193.   255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
  194.   255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
  195.   255,255,255,255,255,255,255,255 };
  196.  
  197. unsigned char shifted_ascii_table[128] = 
  198. { 255, 255, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+',255,255,
  199.   'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 255, 255,
  200.   'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', 
  201.   255, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 255,255,
  202.   255, ' ', 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255,255,
  203.   255, 255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
  204.   255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
  205.   255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
  206.   255,255,255,255,255,255,255,255 };
  207.  
  208.  
  209. extern char key_to_ascii(int keycode )
  210. {
  211.     int shifted;
  212.  
  213.     shifted = keycode & KEY_SHIFTED;
  214.     keycode &= 0xFF;
  215.  
  216.     if ( keycode>=127 )
  217.         return 255;
  218.  
  219.     if (shifted)
  220.         return shifted_ascii_table[keycode];
  221.     else
  222.         return ascii_table[keycode];
  223. }
  224.  
  225. void key_clear_bios_buffer_all()
  226. {
  227.     // Clear keyboard buffer...
  228.     *(ushort *)0x41a=*(ushort *)0x41c;
  229.     // Clear the status bits...
  230.     *(ubyte *)0x417 = 0;
  231.     *(ubyte *)0x418 = 0;
  232. }
  233.  
  234. void key_clear_bios_buffer()
  235. {
  236.     // Clear keyboard buffer...
  237.     *(ushort *)0x41a=*(ushort *)0x41c;
  238. }
  239.  
  240. void key_flush()
  241. {
  242.     int i;
  243.     fix CurTime;
  244.  
  245.     _disable();
  246.  
  247.     // Clear the BIOS buffer
  248.     key_clear_bios_buffer();
  249.  
  250.     key_data.keyhead = key_data.keytail = 0;
  251.  
  252.     //Clear the keyboard buffer
  253.     for (i=0; i<KEY_BUFFER_SIZE; i++ )    {
  254.         key_data.keybuffer[i] = 0;
  255.         key_data.time_pressed[i] = 0;
  256.     }
  257.     
  258.     //Clear the keyboard array
  259.  
  260.     CurTime =timer_get_fixed_secondsX();
  261.  
  262.     for (i=0; i<256; i++ )    {
  263.         keyd_pressed[i] = 0;
  264.         key_data.TimeKeyWentDown[i] = CurTime;
  265.         key_data.TimeKeyHeldDown[i] = 0;
  266.         key_data.NumDowns[i]=0;
  267.         key_data.NumUps[i]=0;
  268.     }
  269.     _enable();
  270. }
  271.  
  272. int add_one( int n )
  273. {
  274.     n++;
  275.     if ( n >= KEY_BUFFER_SIZE ) n=0;
  276.     return n;
  277. }
  278.  
  279. // Returns 1 if character waiting... 0 otherwise
  280. int key_checkch()
  281. {
  282.     int is_one_waiting = 0;
  283.  
  284.     _disable();
  285.  
  286.     key_clear_bios_buffer();
  287.  
  288.     if (key_data.keytail!=key_data.keyhead)
  289.         is_one_waiting = 1;
  290.     _enable();
  291.     return is_one_waiting;
  292. }
  293.  
  294. int key_inkey()
  295. {
  296.     int key = 0;
  297.  
  298.     _disable();
  299.  
  300.     key_clear_bios_buffer();
  301.  
  302.     if (key_data.keytail!=key_data.keyhead)    {
  303.         key = key_data.keybuffer[key_data.keyhead];
  304.         key_data.keyhead = add_one(key_data.keyhead);
  305.     }
  306.     _enable();
  307.     return key;
  308. }
  309.  
  310. int key_inkey_time(fix * time)
  311. {
  312.     int key = 0;
  313.  
  314.     _disable();
  315.  
  316.     key_clear_bios_buffer();
  317.  
  318.     if (key_data.keytail!=key_data.keyhead)    {
  319.         key = key_data.keybuffer[key_data.keyhead];
  320.         *time = key_data.time_pressed[key_data.keyhead];
  321.         key_data.keyhead = add_one(key_data.keyhead);
  322.     }
  323.     _enable();
  324.     return key;
  325. }
  326.  
  327.  
  328.  
  329. int key_peekkey()
  330. {
  331.     int key = 0;
  332.  
  333.     _disable();
  334.  
  335.     key_clear_bios_buffer();
  336.  
  337.     if (key_data.keytail!=key_data.keyhead)    {
  338.         key = key_data.keybuffer[key_data.keyhead];
  339.     }
  340.     _enable();
  341.     return key;
  342. }
  343.  
  344. // If not installed, uses BIOS and returns getch();
  345. //    Else returns pending key (or waits for one if none waiting).
  346. int key_getch()
  347. {
  348.     int dummy=0;
  349.     
  350.     if (!Installed)
  351.         return getch();
  352.  
  353.     while (!key_checkch())
  354.         dummy++;
  355.     return key_inkey();
  356. }
  357.  
  358. unsigned int key_get_shift_status()
  359. {
  360.     unsigned int shift_status = 0;
  361.  
  362.     _disable();
  363.  
  364.     key_clear_bios_buffer();
  365.  
  366.     if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] )
  367.         shift_status |= KEY_SHIFTED;
  368.  
  369.     if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] )
  370.         shift_status |= KEY_ALTED;
  371.  
  372.     if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] )
  373.         shift_status |= KEY_CTRLED;
  374.  
  375. #ifndef NDEBUG
  376.     if (keyd_pressed[KEY_DELETE])
  377.         shift_status |=KEY_DEBUGGED;
  378. #endif
  379.  
  380.     _enable();
  381.  
  382.     return shift_status;
  383. }
  384.  
  385. // Returns the number of seconds this key has been down since last call.
  386. fix key_down_time(int scancode)    {
  387.     fix time_down, time;
  388.  
  389.     if ((scancode<0)|| (scancode>255)) return 0;
  390.  
  391. #ifndef NDEBUG
  392.     if (keyd_editor_mode && key_get_shift_status() )
  393.         return 0;  
  394. #endif
  395.  
  396.     _disable();
  397.  
  398.     if ( !keyd_pressed[scancode] )    {
  399.         time_down = key_data.TimeKeyHeldDown[scancode];
  400.         key_data.TimeKeyHeldDown[scancode] = 0;
  401.     } else    {
  402.         time = timer_get_fixed_secondsX();
  403.         time_down =  time - key_data.TimeKeyWentDown[scancode];
  404.         key_data.TimeKeyWentDown[scancode] = time;
  405.     }
  406.     _enable();
  407.  
  408.     return time_down;
  409. }
  410.  
  411. // Returns number of times key has went from up to down since last call.
  412. unsigned int key_down_count(int scancode)    {
  413.     int n;
  414.  
  415.     if ((scancode<0)|| (scancode>255)) return 0;
  416.  
  417.     _disable();
  418.     n = key_data.NumDowns[scancode];
  419.     key_data.NumDowns[scancode] = 0;
  420.     _enable();
  421.  
  422.     return n;
  423. }
  424.  
  425.  
  426. // Returns number of times key has went from down to up since last call.
  427. unsigned int key_up_count(int scancode)    {
  428.     int n;
  429.  
  430.     if ((scancode<0)|| (scancode>255)) return 0;
  431.  
  432.     _disable();
  433.     n = key_data.NumUps[scancode];
  434.     key_data.NumUps[scancode] = 0;
  435.     _enable();
  436.  
  437.     return n;
  438. }
  439.  
  440. // Use intrinsic forms so that we stay in the locked interrup code.
  441.  
  442. void Int5();
  443. #pragma aux Int5 = "int 5";
  444.  
  445. #pragma off (check_stack)
  446. void __interrupt __far key_handler()
  447. {
  448.     unsigned char scancode, breakbit, temp;
  449.     unsigned short keycode;
  450.  
  451. #ifndef WATCOM_10
  452. #ifndef NDEBUG
  453.     ubyte * MONO = (ubyte *)(0x0b0000+24*80*2);
  454.     if (  ((MONO[0]=='D') && (MONO[2]=='B') && (MONO[4]=='G') && (MONO[6]=='>')) ||
  455.             ((MONO[14]=='<') && (MONO[16]=='i') && (MONO[18]=='>') && (MONO[20]==' ') && (MONO[22]=='-')) ||
  456.             ((MONO[0]==200 ) && (MONO[2]==27) && (MONO[4]==17) )
  457.         )
  458.          _chain_intr( key_data.prev_int_9 );
  459. #endif
  460. #endif
  461.  
  462.     // Read in scancode
  463.     scancode = inp( 0x60 );
  464.  
  465.     switch( scancode )    {
  466.     case 0xE0:
  467.         key_data.E0Flag = 0x80;
  468.         break;
  469.     default:
  470.         // Parse scancode and break bit
  471.         if (key_data.E1Flag > 0 )    {        // Special code for Pause, which is E1 1D 45 E1 9D C5
  472.             key_data.E1Flag--;
  473.             if ( scancode == 0x1D )    {
  474.                 scancode    = KEY_PAUSE;
  475.                 breakbit    = 0;
  476.             } else if ( scancode == 0x9d ) {
  477.                 scancode    = KEY_PAUSE;
  478.                 breakbit    = 1;
  479.             } else {
  480.                 break;        // skip this keycode
  481.             }
  482.         } else if ( scancode==0xE1 )    {
  483.             key_data.E1Flag = 2;
  484.             break;
  485.         } else {
  486.             breakbit    = scancode & 0x80;        // Get make/break bit
  487.             scancode &= 0x7f;                        // Strip make/break bit off of scancode
  488.             scancode |= key_data.E0Flag;                    // Add in extended key code
  489.         }
  490.         key_data.E0Flag = 0;                                // Clear extended key code
  491.  
  492.         if (breakbit)    {
  493.             // Key going up
  494.             keyd_last_released = scancode;
  495.             keyd_pressed[scancode] = 0;
  496.             key_data.NumUps[scancode]++;
  497.             temp = 0;
  498.             temp |= keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT];
  499.             temp |= keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT];
  500.             temp |= keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL];
  501. #ifndef NDEBUG
  502.             temp |= keyd_pressed[KEY_DELETE];
  503.             if ( !(keyd_editor_mode && temp) )
  504. #endif        // NOTICE LINK TO ABOVE IF!!!!
  505.                 key_data.TimeKeyHeldDown[scancode] += timer_get_fixed_secondsX() - key_data.TimeKeyWentDown[scancode];
  506.         } else {
  507.             // Key going down
  508.             keyd_last_pressed = scancode;
  509.             keyd_time_when_last_pressed = timer_get_fixed_secondsX();
  510.             if (!keyd_pressed[scancode])    {
  511.                 // First time down
  512.                 key_data.TimeKeyWentDown[scancode] = timer_get_fixed_secondsX();
  513.                 keyd_pressed[scancode] = 1;
  514.                 key_data.NumDowns[scancode]++;
  515. #ifndef NDEBUG
  516.                 if ( (keyd_pressed[KEY_LSHIFT]) && (scancode == KEY_BACKSP) )     {
  517.                     keyd_pressed[KEY_LSHIFT] = 0;
  518.                     Int5();
  519.                 }
  520. #endif
  521.             } else if (!keyd_repeat) {
  522.                 // Don't buffer repeating key if repeat mode is off
  523.                 scancode = 0xAA;        
  524.             } 
  525.  
  526.             if ( scancode!=0xAA ) {
  527.                 keycode = scancode;
  528.  
  529.                 if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] )
  530.                     keycode |= KEY_SHIFTED;
  531.  
  532.                 if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] )
  533.                     keycode |= KEY_ALTED;
  534.  
  535.                 if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] )
  536.                     keycode |= KEY_CTRLED;
  537.  
  538. #ifndef NDEBUG
  539.                 if ( keyd_pressed[KEY_DELETE] )
  540.                     keycode |= KEY_DEBUGGED;
  541. #endif
  542.  
  543.                 temp = key_data.keytail+1;
  544.                 if ( temp >= KEY_BUFFER_SIZE ) temp=0;
  545.  
  546.                 if (temp!=key_data.keyhead)    {
  547.                     key_data.keybuffer[key_data.keytail] = keycode;
  548.                     key_data.time_pressed[key_data.keytail] = keyd_time_when_last_pressed;
  549.                     key_data.keytail = temp;
  550.                 }
  551.             }
  552.         }
  553.     }
  554.  
  555. #ifndef NDEBUG
  556. #ifdef PASS_KEYS_TO_BIOS
  557.     _chain_intr( key_data.prev_int_9 );
  558. #endif
  559. #endif
  560.  
  561.     temp = inp(0x61);        // Get current port 61h state
  562.     temp |= 0x80;            // Turn on bit 7 to signal clear keybrd
  563.     outp( 0x61, temp );    // Send to port
  564.     temp &= 0x7f;            // Turn off bit 7 to signal break
  565.     outp( 0x61, temp );    // Send to port
  566.     outp( 0x20, 0x20 );    // Reset interrupt controller
  567. }
  568.  
  569. #pragma on (check_stack)
  570.  
  571. void key_handler_end()    {        // Dummy function to help calculate size of keyboard handler function
  572. }
  573.  
  574. void key_init()
  575. {
  576.     // Initialize queue
  577.  
  578.     keyd_time_when_last_pressed = timer_get_fixed_seconds();
  579.     keyd_buffer_type = 1;
  580.     keyd_repeat = 1;
  581.     key_data.in_key_handler = 0;
  582.     key_data.E0Flag = 0;
  583.     key_data.E1Flag = 0;
  584.  
  585.     // Clear the keyboard array
  586.     key_flush();
  587.  
  588.     if (Installed) return;
  589.     Installed = 1;
  590.  
  591.     //--------------- lock everything for the virtal memory ----------------------------------
  592.     if (!dpmi_lock_region ((void near *)key_handler, (char *)key_handler_end - (char near *)key_handler))    {
  593.         printf( "Error locking keyboard handler!\n" );
  594.         exit(1);
  595.     }
  596.     if (!dpmi_lock_region (&key_data, sizeof(keyboard)))    {
  597.         printf( "Error locking keyboard handler's data!\n" );
  598.         exit(1);
  599.     }
  600.     if (!dpmi_lock_region (&keyd_buffer_type, sizeof(char)))    {
  601.         printf( "Error locking keyboard handler's data!\n" );
  602.         exit(1);
  603.     }
  604.     if (!dpmi_lock_region (&keyd_repeat, sizeof(char)))    {
  605.         printf( "Error locking keyboard handler's data!\n" );
  606.         exit(1);
  607.     }
  608.     if (!dpmi_lock_region (&keyd_editor_mode, sizeof(char)))    {
  609.         printf( "Error locking keyboard handler's data!\n" );
  610.         exit(1);
  611.     }
  612.     if (!dpmi_lock_region (&keyd_last_pressed, sizeof(char)))    {
  613.         printf( "Error locking keyboard handler's data!\n" );
  614.         exit(1);
  615.     }
  616.     if (!dpmi_lock_region (&keyd_last_released, sizeof(char)))    {
  617.         printf( "Error locking keyboard handler's data!\n" );
  618.         exit(1);
  619.     }
  620.     if (!dpmi_lock_region (&keyd_pressed, sizeof(char)*256))    {
  621.         printf( "Error locking keyboard handler's data!\n" );
  622.         exit(1);
  623.     }
  624.     if (!dpmi_lock_region (&keyd_time_when_last_pressed, sizeof(int)))    {
  625.         printf( "Error locking keyboard handler's data!\n" );
  626.         exit(1);
  627.     }
  628.  
  629.     key_data.prev_int_9 = _dos_getvect( 9 );
  630.     _dos_setvect( 9, key_handler );
  631.  
  632.     atexit( key_close );
  633. }
  634.  
  635. void key_close()
  636. {
  637.     if (!Installed) return;
  638.     Installed = 0;
  639.     
  640.     _dos_setvect( 9, key_data.prev_int_9 );
  641.  
  642.     _disable();
  643.     key_clear_bios_buffer_all();
  644.     _enable();
  645.  
  646. }
  647. 
  648.