svgalib support
[btb/d2x.git] / input / dos_key.c
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 //#define PASS_KEYS_TO_BIOS     1                       //if set, bios gets keys
15
16 #include <conf.h>
17
18 #ifdef __ENV_DJGPP__
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <dos.h>
22
23 //#define WATCOM_10
24 #ifdef __DJGPP__
25 #include <dpmi.h>
26 #define _far
27 #define __far
28 #define __interrupt
29 #define near
30 _go32_dpmi_seginfo kbd_hand_info;
31 #endif
32 #include "error.h"
33 #include "key.h"
34 #include "timer.h"
35 #include "u_dpmi.h"
36
37 #define KEY_BUFFER_SIZE 16
38
39
40 //-------- Variable accessed by outside functions ---------
41 unsigned char                           keyd_buffer_type;               // 0=No buffer, 1=buffer ASCII, 2=buffer scans
42 unsigned char                           keyd_repeat;
43 unsigned char                           keyd_editor_mode;
44 volatile unsigned char  keyd_last_pressed;
45 volatile unsigned char  keyd_last_released;
46 volatile unsigned char  keyd_pressed[256];
47 volatile int                            keyd_time_when_last_pressed;
48
49 typedef struct keyboard {
50         unsigned short          keybuffer[KEY_BUFFER_SIZE];
51         fix                                     time_pressed[KEY_BUFFER_SIZE];
52         fix                                     TimeKeyWentDown[256];
53         fix                                     TimeKeyHeldDown[256];
54         unsigned int            NumDowns[256];
55         unsigned int            NumUps[256];
56         unsigned int            keyhead, keytail;
57         unsigned char           E0Flag;
58         unsigned char           E1Flag;
59         int                                     in_key_handler;
60 #ifdef __DJGPP__
61         _go32_dpmi_seginfo prev_int_9;
62 #else
63         void (__interrupt __far *prev_int_9)();
64 #endif
65 } keyboard;
66
67 static volatile keyboard key_data;
68
69 static unsigned char Installed=0;
70
71 unsigned char ascii_table[128] = 
72 { 255, 255, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=',255,255,
73   'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 255, 255,
74   'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 39, '`',
75   255, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 255,'*',
76   255, ' ', 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255,255,
77   255, 255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
78   255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
79   255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
80   255,255,255,255,255,255,255,255 };
81
82 unsigned char shifted_ascii_table[128] = 
83 { 255, 255, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+',255,255,
84   'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 255, 255,
85   'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', 
86   255, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 255,255,
87   255, ' ', 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255,255,
88   255, 255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
89   255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
90   255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
91   255,255,255,255,255,255,255,255 };
92 /*
93 char * key_text[256] = {
94 "","ESC","1","2","3","4","5","6","7","8","9","0","-",
95 "=","BSPC","TAB","Q","W","E","R","T","Y","U","I","O",
96 "P","[","]","\83","LCTRL","A","S","D","F",
97 "G","H","J","K","L",";","'","`",
98 "LSHFT","\\","Z","X","C","V","B","N","M",",",
99 ".","/","RSHFT","PAD*","LALT","SPC",
100 "CPSLK","F1","F2","F3","F4","F5","F6","F7","F8","F9",
101 "F10","NMLCK","SCLK","PAD7","PAD8","PAD9","PAD-",
102 "PAD4","PAD5","PAD6","PAD+","PAD1","PAD2","PAD3","PAD0",
103 "PAD.","","","","F11","F12","","","","","","","","","",
104 "","","","","","","","","","","","","","","","","","","","",
105 "","","","","","","","","","","","","","","","","","","","",
106 "","","","","","","","","","","","","","","","","","",
107 "PAD\83","RCTRL","","","","","","","","","","","","","",
108 "","","","","","","","","","","PAD/","","","RALT","",
109 "","","","","","","","","","","","","","HOME","\82","PGUP",
110 "","\81","","\7f","","END","\80","PGDN","INS",
111 "DEL","","","","","","","","","","","","","","","","","",
112 "","","","","","","","","","","","","","","","","","","","",
113 "","","","","","","" };
114 */
115 unsigned char key_to_ascii(int keycode )
116 {
117         int shifted;
118
119         shifted = keycode & KEY_SHIFTED;
120         keycode &= 0xFF;
121
122         if ( keycode>=127 )
123                 return 255;
124
125         if (shifted)
126                 return shifted_ascii_table[keycode];
127         else
128                 return ascii_table[keycode];
129 }
130
131 void key_clear_bios_buffer_all()
132 {
133 #ifdef __WATCOMC__
134         // Clear keyboard buffer...
135         *(ushort *)0x41a=*(ushort *)0x41c;
136         // Clear the status bits...
137         *(ubyte *)0x417 = 0;
138         *(ubyte *)0x418 = 0;
139 #else
140         _farpokew(_dos_ds,0x41a, _farpeekw(_dos_ds, 0x41c));
141         _farpokeb(_dos_ds,0x417, 0);
142         _farpokeb(_dos_ds,0x418, 0);
143 #endif
144 }
145
146 void key_clear_bios_buffer()
147 {
148 #ifdef __WATCOMC__
149         // Clear keyboard buffer...
150         *(ushort *)0x41a=*(ushort *)0x41c;
151 #else
152         _farpokew(_dos_ds,0x41a, _farpeekw(_dos_ds, 0x41c));
153 #endif
154 }
155
156 void key_flush()
157 {
158         int i;
159         fix CurTime;
160
161         _disable();
162
163         // Clear the BIOS buffer
164         key_clear_bios_buffer();
165
166         key_data.keyhead = key_data.keytail = 0;
167
168         //Clear the keyboard buffer
169         for (i=0; i<KEY_BUFFER_SIZE; i++ )      {
170                 key_data.keybuffer[i] = 0;
171                 key_data.time_pressed[i] = 0;
172         }
173         
174         //Clear the keyboard array
175
176         CurTime =timer_get_fixed_secondsX();
177
178         for (i=0; i<256; i++ )  {
179                 keyd_pressed[i] = 0;
180                 key_data.TimeKeyWentDown[i] = CurTime;
181                 key_data.TimeKeyHeldDown[i] = 0;
182                 key_data.NumDowns[i]=0;
183                 key_data.NumUps[i]=0;
184         }
185         _enable();
186 }
187
188 int add_one( int n )
189 {
190         n++;
191         if ( n >= KEY_BUFFER_SIZE ) n=0;
192         return n;
193 }
194
195 // Returns 1 if character waiting... 0 otherwise
196 int key_checkch()
197 {
198         int is_one_waiting = 0;
199
200         _disable();
201
202         key_clear_bios_buffer();
203
204         if (key_data.keytail!=key_data.keyhead)
205                 is_one_waiting = 1;
206         _enable();
207         return is_one_waiting;
208 }
209
210 int key_inkey()
211 {
212         int key = 0;
213
214         _disable();
215
216         key_clear_bios_buffer();
217
218         if (key_data.keytail!=key_data.keyhead) {
219                 key = key_data.keybuffer[key_data.keyhead];
220                 key_data.keyhead = add_one(key_data.keyhead);
221         }
222         _enable();
223         return key;
224 }
225
226 int key_inkey_time(fix * time)
227 {
228         int key = 0;
229
230         _disable();
231
232         key_clear_bios_buffer();
233
234         if (key_data.keytail!=key_data.keyhead) {
235                 key = key_data.keybuffer[key_data.keyhead];
236                 *time = key_data.time_pressed[key_data.keyhead];
237                 key_data.keyhead = add_one(key_data.keyhead);
238         }
239         _enable();
240         return key;
241 }
242
243
244
245 int key_peekkey()
246 {
247         int key = 0;
248
249         _disable();
250
251         key_clear_bios_buffer();
252
253         if (key_data.keytail!=key_data.keyhead) {
254                 key = key_data.keybuffer[key_data.keyhead];
255         }
256         _enable();
257         return key;
258 }
259
260 // If not installed, uses BIOS and returns getch();
261 //      Else returns pending key (or waits for one if none waiting).
262 int key_getch()
263 {
264         int dummy=0;
265         
266         if (!Installed)
267                 return getch();
268
269         while (!key_checkch())
270                 dummy++;
271         return key_inkey();
272 }
273
274 unsigned int key_get_shift_status()
275 {
276         unsigned int shift_status = 0;
277
278         _disable();
279
280         key_clear_bios_buffer();
281
282         if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] )
283                 shift_status |= KEY_SHIFTED;
284
285         if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] )
286                 shift_status |= KEY_ALTED;
287
288         if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] )
289                 shift_status |= KEY_CTRLED;
290
291 #ifndef NDEBUG
292         if (keyd_pressed[KEY_DELETE])
293                 shift_status |=KEY_DEBUGGED;
294 #endif
295
296         _enable();
297
298         return shift_status;
299 }
300
301 // Returns the number of seconds this key has been down since last call.
302 fix key_down_time(int scancode) {
303         fix time_down, time;
304
305         if ((scancode<0)|| (scancode>255)) return 0;
306
307 #ifndef NDEBUG
308         if (keyd_editor_mode && key_get_shift_status() )
309                 return 0;  
310 #endif
311
312         _disable();
313
314         if ( !keyd_pressed[scancode] )  {
315                 time_down = key_data.TimeKeyHeldDown[scancode];
316                 key_data.TimeKeyHeldDown[scancode] = 0;
317         } else  {
318                 time = timer_get_fixed_secondsX();
319                 time_down =  time - key_data.TimeKeyWentDown[scancode];
320                 key_data.TimeKeyWentDown[scancode] = time;
321         }
322         _enable();
323
324         return time_down;
325 }
326
327 // Returns number of times key has went from up to down since last call.
328 unsigned int key_down_count(int scancode)       {
329         int n;
330
331         if ((scancode<0)|| (scancode>255)) return 0;
332
333         _disable();
334         n = key_data.NumDowns[scancode];
335         key_data.NumDowns[scancode] = 0;
336         _enable();
337
338         return n;
339 }
340
341
342 // Returns number of times key has went from down to up since last call.
343 unsigned int key_up_count(int scancode) {
344         int n;
345
346         if ((scancode<0)|| (scancode>255)) return 0;
347
348         _disable();
349         n = key_data.NumUps[scancode];
350         key_data.NumUps[scancode] = 0;
351         _enable();
352
353         return n;
354 }
355
356 // Use intrinsic forms so that we stay in the locked interrup code.
357
358 #ifdef __WATCOMC__
359 void Int5();
360 #pragma aux Int5 = "int 5";
361 #else
362 #ifdef __GNUC__
363 #define Int5() asm volatile("int $5")
364 #endif
365 #endif
366
367 void __interrupt __far key_handler()
368 {
369         unsigned char scancode, breakbit, temp;
370         unsigned short keycode;
371
372 #ifndef WATCOM_10
373 #ifndef NDEBUG
374 #ifdef __WATCOMC__ /* must have _chain_intr */
375         ubyte * MONO = (ubyte *)(0x0b0000+24*80*2);
376         if (  ((MONO[0]=='D') && (MONO[2]=='B') && (MONO[4]=='G') && (MONO[6]=='>')) ||
377                         ((MONO[14]=='<') && (MONO[16]=='i') && (MONO[18]=='>') && (MONO[20]==' ') && (MONO[22]=='-')) ||
378                         ((MONO[0]==200 ) && (MONO[2]==27) && (MONO[4]==17) )
379                 )
380                 _chain_intr( key_data.prev_int_9 );
381 #endif
382 #endif
383 #endif
384
385         // Read in scancode
386         scancode = inp( 0x60 );
387
388         switch( scancode )      {
389         case 0xE0:
390                 key_data.E0Flag = 0x80;
391                 break;
392         default:
393                 // Parse scancode and break bit
394                 if (key_data.E1Flag > 0 )       {               // Special code for Pause, which is E1 1D 45 E1 9D C5
395                         key_data.E1Flag--;
396                         if ( scancode == 0x1D ) {
397                                 scancode        = KEY_PAUSE;
398                                 breakbit        = 0;
399                         } else if ( scancode == 0x9d ) {
400                                 scancode        = KEY_PAUSE;
401                                 breakbit        = 1;
402                         } else {
403                                 break;          // skip this keycode
404                         }
405                 } else if ( scancode==0xE1 )    {
406                         key_data.E1Flag = 2;
407                         break;
408                 } else {
409                         breakbit        = scancode & 0x80;              // Get make/break bit
410                         scancode &= 0x7f;                                               // Strip make/break bit off of scancode
411                         scancode |= key_data.E0Flag;                                    // Add in extended key code
412                 }
413                 key_data.E0Flag = 0;                                                            // Clear extended key code
414
415                 if (breakbit)   {
416                         // Key going up
417                         keyd_last_released = scancode;
418                         keyd_pressed[scancode] = 0;
419                         key_data.NumUps[scancode]++;
420                         temp = 0;
421                         temp |= keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT];
422                         temp |= keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT];
423                         temp |= keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL];
424 #ifndef NDEBUG
425                         temp |= keyd_pressed[KEY_DELETE];
426                         if ( !(keyd_editor_mode && temp) )
427 #endif          // NOTICE LINK TO ABOVE IF!!!!
428                                 key_data.TimeKeyHeldDown[scancode] += timer_get_fixed_secondsX() - key_data.TimeKeyWentDown[scancode];
429                 } else {
430                         // Key going down
431                         keyd_last_pressed = scancode;
432                         keyd_time_when_last_pressed = timer_get_fixed_secondsX();
433                         if (!keyd_pressed[scancode])    {
434                                 // First time down
435                                 key_data.TimeKeyWentDown[scancode] = timer_get_fixed_secondsX();
436                                 keyd_pressed[scancode] = 1;
437                                 key_data.NumDowns[scancode]++;
438 #ifndef NDEBUG
439                                 if ( (keyd_pressed[KEY_LSHIFT]) && (scancode == KEY_BACKSP) )   {
440                                         keyd_pressed[KEY_LSHIFT] = 0;
441                                         Int5();
442                                 }
443 #endif
444                         } else if (!keyd_repeat) {
445                                 // Don't buffer repeating key if repeat mode is off
446                                 scancode = 0xAA;
447                         }
448
449                         if ( scancode!=0xAA ) {
450                                 keycode = scancode;
451
452                                 if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] )
453                                         keycode |= KEY_SHIFTED;
454
455                                 if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] )
456                                         keycode |= KEY_ALTED;
457
458                                 if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] )
459                                         keycode |= KEY_CTRLED;
460
461 #ifndef NDEBUG
462                                 if ( keyd_pressed[KEY_DELETE] )
463                                         keycode |= KEY_DEBUGGED;
464 #endif
465
466                                 temp = key_data.keytail+1;
467                                 if ( temp >= KEY_BUFFER_SIZE ) temp=0;
468
469                                 if (temp!=key_data.keyhead)     {
470                                         key_data.keybuffer[key_data.keytail] = keycode;
471                                         key_data.time_pressed[key_data.keytail] = keyd_time_when_last_pressed;
472                                         key_data.keytail = temp;
473                                 }
474                         }
475                 }
476         }
477
478 #ifndef NDEBUG
479 #ifdef PASS_KEYS_TO_BIOS
480         _chain_intr( key_data.prev_int_9 );
481 #endif
482 #endif
483
484         temp = inp(0x61);               // Get current port 61h state
485         temp |= 0x80;                   // Turn on bit 7 to signal clear keybrd
486         outp( 0x61, temp );     // Send to port
487         temp &= 0x7f;                   // Turn off bit 7 to signal break
488         outp( 0x61, temp );     // Send to port
489         outp( 0x20, 0x20 );     // Reset interrupt controller
490 }
491
492
493 void key_handler_end()  {               // Dummy function to help calculate size of keyboard handler function
494 }
495
496 void key_init()
497 {
498         // Initialize queue
499
500         keyd_time_when_last_pressed = timer_get_fixed_seconds();
501         keyd_buffer_type = 1;
502         keyd_repeat = 1;
503         key_data.in_key_handler = 0;
504         key_data.E0Flag = 0;
505         key_data.E1Flag = 0;
506
507         // Clear the keyboard array
508         key_flush();
509
510         if (Installed) return;
511         Installed = 1;
512
513         //--------------- lock everything for the virtal memory ----------------------------------
514         if (!dpmi_lock_region ((void near *)key_handler, (char *)key_handler_end - (char near *)key_handler))   {
515                 printf( "Error locking keyboard handler!\n" );
516                 exit(1);
517         }
518         if (!dpmi_lock_region ((void *)&key_data, sizeof(keyboard)))    {
519                 printf( "Error locking keyboard handler's data1!\n" );
520                 exit(1);
521         }
522         if (!dpmi_lock_region (&keyd_buffer_type, sizeof(char)))        {
523                 printf( "Error locking keyboard handler's data2!\n" );
524                 exit(1);
525         }
526         if (!dpmi_lock_region (&keyd_repeat, sizeof(char)))     {
527                 printf( "Error locking keyboard handler's data3!\n" );
528                 exit(1);
529         }
530         if (!dpmi_lock_region (&keyd_editor_mode, sizeof(char)))        {
531                 printf( "Error locking keyboard handler's data4!\n" );
532                 exit(1);
533         }
534         if (!dpmi_lock_region ((void *)&keyd_last_pressed, sizeof(char)))       {
535                 printf( "Error locking keyboard handler's data5!\n" );
536                 exit(1);
537         }
538         if (!dpmi_lock_region ((void *)&keyd_last_released, sizeof(char)))      {
539                 printf( "Error locking keyboard handler's data6!\n" );
540                 exit(1);
541         }
542         if (!dpmi_lock_region ((void *)&keyd_pressed, sizeof(char)*256))        {
543                 printf( "Error locking keyboard handler's data7!\n" );
544                 exit(1);
545         }
546         if (!dpmi_lock_region ((void *)&keyd_time_when_last_pressed, sizeof(int)))      {
547                 printf( "Error locking keyboard handler's data8!\n" );
548                 exit(1);
549         }
550
551 #ifndef __DJGPP__
552         key_data.prev_int_9 = (void *)_dos_getvect( 9 );
553     _dos_setvect( 9, key_handler );
554 #else
555         _go32_dpmi_get_protected_mode_interrupt_vector(9,
556          (_go32_dpmi_seginfo *)&key_data.prev_int_9);
557         kbd_hand_info.pm_offset = (int)key_handler;
558         kbd_hand_info.pm_selector = _my_cs();
559         _go32_dpmi_allocate_iret_wrapper(&kbd_hand_info);
560         _go32_dpmi_set_protected_mode_interrupt_vector(9, &kbd_hand_info);
561 #endif
562
563         atexit( key_close );
564 }
565
566 void key_close()
567 {
568         if (!Installed) return;
569         Installed = 0;
570         
571 #ifndef __DJGPP__
572         _dos_setvect( 9, key_data.prev_int_9 );
573 #else
574         _go32_dpmi_set_protected_mode_interrupt_vector(9,
575          (_go32_dpmi_seginfo *)&key_data.prev_int_9);
576 #endif
577
578         _disable();
579         key_clear_bios_buffer_all();
580         _enable();
581
582 }
583
584 #endif // __ENV_DJGPP__