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