]> icculus.org git repositories - taylor/freespace2.git/blob - src/io/key.cpp
Initial revision
[taylor/freespace2.git] / src / io / key.cpp
1 /*
2  * $Logfile: /Freespace2/code/Io/Key.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * <insert description of file here>
8  *
9  * $Log$
10  * Revision 1.1  2002/05/03 03:28:09  root
11  * Initial revision
12  *
13  * 
14  * 6     10/29/99 6:10p Jefff
15  * squashed the damned y/z german issues once and for all
16  * 
17  * 5     6/07/99 1:21p Dave
18  * Fixed debug console scrolling problem. Thread related.
19  * 
20  * 4     6/02/99 6:18p Dave
21  * Fixed TNT lockup problems! Wheeeee!
22  * 
23  * 3     11/05/98 4:18p Dave
24  * First run nebula support. Beefed up localization a bit. Removed all
25  * conditional compiles for foreign versions. Modified mission file
26  * format.
27  * 
28  * 2     10/07/98 10:53a Dave
29  * Initial checkin.
30  * 
31  * 1     10/07/98 10:49a Dave
32  * 
33  * 37    6/19/98 3:50p Lawrance
34  * change GERMAN to GR_BUILD
35  * 
36  * 36    6/17/98 11:05a Lawrance
37  * translate french and german keys
38  * 
39  * 35    6/12/98 4:49p Hoffoss
40  * Added code to remap scancodes for german and french keyboards.
41  * 
42  * 34    5/20/98 12:10a Mike
43  * Remove mprintfs.
44  * 
45  * 33    5/19/98 12:19p Mike
46  * Cheat codes!
47  * 
48  * 32    5/19/98 12:28a Mike
49  * Cheat stuff.
50  * 
51  * 31    5/18/98 11:01p Mike
52  * Adding support for cheat system.
53  * 
54  * 30    5/11/98 12:09a Lawrance
55  * Put in code to turn on/off NumLock key when running under 95
56  * 
57  * 29    5/01/98 4:23p Lawrance
58  * Remap the scancode for the UK "\" key
59  * 
60  * 28    4/18/98 12:42p John
61  * Added code to use DirectInput to read keyboard. Took out because it
62  * didn't differentiate btwn Pause and Numlock and sometimes Ctrl.
63  * 
64  * 27    4/13/98 10:16a John
65  * Switched gettime back to timer_get_milliseconds, which is now thread
66  * safe.
67  * 
68  * 26    4/12/98 11:08p Lawrance
69  * switch back to using gettime() in separate threads
70  * 
71  * 25    4/12/98 5:31p Lawrance
72  * use timer_get_milliseconds() instead of gettime()
73  * 
74  * 24    3/25/98 8:08p John
75  * Restructured software rendering into two modules; One for windowed
76  * debug mode and one for DirectX fullscreen.   
77  * 
78  * 23    1/23/98 3:49p Mike
79  * Fix bug in negative time-down due to latency.
80  * 
81  * 22    1/07/98 6:41p Lawrance
82  * Pass message latency to the keyboard lib.
83  * 
84  * 21    11/17/97 10:42a John
85  * On Debug+Backsp, cleared out keys so that it looks like nothing ever
86  * happened, so they're not stuck down.
87  * 
88  * 20    11/14/97 4:33p Mike
89  * Change Debug key to backquote (from F11).
90  * Balance a ton of subsystems in ships.tbl.
91  * Change "Heavy Laser" to "Disruptor".
92  * 
93  * 19    9/13/97 9:30a Lawrance
94  * added ability to block certain keys from the keyboard
95  * 
96  * 18    9/10/97 6:02p Hoffoss
97  * Added code to check for key-pressed sexp operator in FreeSpace as part
98  * of training mission stuff.
99  * 
100  * 17    9/09/97 11:08a Sandeep
101  * fixed warning level 4
102  * 
103  * 16    7/29/97 5:30p Lawrance
104  * move gettime() to timer module
105  * 
106  * 15    4/22/97 10:56a John
107  * fixed some resource leaks.
108  * 
109  * 14    2/03/97 4:23p Allender
110  * use F11 as debug key now
111  * 
112  * 13    1/10/97 5:15p Mike
113  * Moved ship-specific parameters from obj_subsystem to ship_subsys.
114  * 
115  * Added turret code to AI system.
116  *
117  * $NoKeywords: $
118  */
119
120 //#define USE_DIRECTINPUT
121
122 #ifndef PLAT_UNIX
123 #include <windows.h>
124 #include <windowsx.h>
125 #endif
126
127 #include "pstypes.h"
128 #include "key.h"
129 #include "fix.h"
130 #include "timer.h"
131 #include "osapi.h"
132 #include "localize.h"
133
134 #define KEY_BUFFER_SIZE 16
135
136 //-------- Variable accessed by outside functions ---------
137 ubyte                           keyd_buffer_type;               // 0=No buffer, 1=buffer ASCII, 2=buffer scans
138 ubyte                           keyd_repeat;
139 uint                            keyd_last_pressed;
140 uint                            keyd_last_released;
141 ubyte                           keyd_pressed[NUM_KEYS];
142 int                             keyd_time_when_last_pressed;
143
144 typedef struct keyboard {
145         ushort                  keybuffer[KEY_BUFFER_SIZE];
146         uint                            time_pressed[KEY_BUFFER_SIZE];
147         uint                            TimeKeyWentDown[NUM_KEYS];
148         uint                            TimeKeyHeldDown[NUM_KEYS];
149         uint                            TimeKeyDownChecked[NUM_KEYS];
150         uint                            NumDowns[NUM_KEYS];
151         uint                            NumUps[NUM_KEYS];
152         int                             down_check[NUM_KEYS];  // nonzero if has been pressed yet this mission
153         uint                            keyhead, keytail;
154 } keyboard;
155
156 keyboard key_data;
157
158 int key_inited = 0;
159
160 CRITICAL_SECTION key_lock;
161
162 //int Backspace_debug=1;        // global flag that will enable/disable the backspace key from stopping execution
163                                                                 // This flag was created since the backspace key is also used to correct mistakes
164                                                                 // when typing in your pilots callsign.  This global flag is checked before execution
165                                                                 // is stopped.
166
167 int ascii_table[128] = 
168 { 255, 255, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=',255,255,
169   'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 255, 255,
170   'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 39, '`',
171   255, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 255,'*',
172   255, ' ', 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255,255,
173   255, 255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
174   255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
175   255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
176   255,255,255,255,255,255,255,255 };
177
178 int shifted_ascii_table[128] = 
179 { 255, 255, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+',255,255,
180   'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 255, 255,
181   'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', 
182   255, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 255,255,
183   255, ' ', 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255,255,
184   255, 255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
185   255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
186   255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
187   255,255,255,255,255,255,255,255 };
188
189 // used to limit the keypresses that are accepted from the keyboard
190 #define MAX_FILTER_KEYS 64
191 int Num_filter_keys;
192 int Key_filter[MAX_FILTER_KEYS];
193
194 static int Key_numlock_was_on = 0;      // Flag to indicate whether NumLock is on at start
195 static int Key_running_NT = 0;          // NT is the OS
196
197 int Cheats_enabled = 0;
198 int Key_normal_game = 0;
199
200 int key_numlock_is_on()
201 {
202 #ifdef PLAT_UNIX
203         int keys[SDLK_LAST];
204         SDL_GetKeyState(keys);
205         if ( keys[SDLK_NUMLOCK] ) {
206                 return 1;
207         }
208 #else
209         unsigned char keys[256];
210         GetKeyboardState(keys);
211         if ( keys[VK_NUMLOCK]  ) {
212                 return 1;
213         }
214 #endif
215         return 0;
216 }
217
218 void key_turn_off_numlock()
219 {
220 #ifdef PLAT_UNIX
221         STUB_FUNCTION;
222 #else
223         unsigned char keys[256];
224         GetKeyboardState(keys);
225         keys[VK_NUMLOCK] = 0;
226         SetKeyboardState(keys);
227 #endif
228 }
229
230 void key_turn_on_numlock()
231 {
232 #ifdef PLAT_UNIX
233         STUB_FUNCTION;
234 #else
235         unsigned char keys[256];
236         GetKeyboardState(keys);
237         keys[VK_NUMLOCK] = 1;
238         SetKeyboardState(keys);
239 #endif
240 }
241
242 //      Convert a BIOS scancode to ASCII.
243 //      If scancode >= 127, returns 255, meaning there is no corresponding ASCII code.
244 //      Uses ascii_table and shifted_ascii_table to translate scancode to ASCII.
245 int key_to_ascii(int keycode )
246 {
247         int shifted;
248
249         if ( !key_inited ) return 255;
250
251         shifted = keycode & KEY_SHIFTED;
252         keycode &= 0xFF;
253
254         if ( keycode>=127 )
255                 return 255;
256
257         if (shifted)
258                 return shifted_ascii_table[keycode];
259         else
260                 return ascii_table[keycode];
261 }
262
263 //      Flush the keyboard buffer.
264 //      Clear the keyboard array (keyd_pressed).
265 void key_flush()
266 {
267         int i;
268         uint CurTime;
269
270         if ( !key_inited ) return;
271
272 #ifdef PLAT_UNIX
273         STUB_FUNCTION;
274 #else
275         ENTER_CRITICAL_SECTION(&key_lock);      
276
277         key_data.keyhead = key_data.keytail = 0;
278
279         //Clear the keyboard buffer
280         for (i=0; i<KEY_BUFFER_SIZE; i++ )      {
281                 key_data.keybuffer[i] = 0;
282                 key_data.time_pressed[i] = 0;
283         }
284         
285         //Clear the keyboard array
286
287         CurTime = timer_get_milliseconds();
288
289
290         for (i=0; i<NUM_KEYS; i++ )     {
291                 keyd_pressed[i] = 0;
292                 key_data.TimeKeyDownChecked[i] = CurTime;
293                 key_data.TimeKeyWentDown[i] = CurTime;
294                 key_data.TimeKeyHeldDown[i] = 0;
295                 key_data.NumDowns[i]=0;
296                 key_data.NumUps[i]=0;
297         }
298
299         LEAVE_CRITICAL_SECTION(&key_lock);      
300 #endif
301 }
302
303 //      A nifty function which performs the function:
304 //              n = (n+1) % KEY_BUFFER_SIZE
305 //      (assuming positive values of n).
306 int add_one( int n )
307 {
308         n++;
309         if ( n >= KEY_BUFFER_SIZE ) n=0;
310         return n;
311 }
312
313 // Returns 1 if character waiting... 0 otherwise
314 int key_checkch()
315 {
316         int is_one_waiting = 0;
317
318         if ( !key_inited ) return 0;
319
320         ENTER_CRITICAL_SECTION(&key_lock);      
321
322         if (key_data.keytail != key_data.keyhead){
323                 is_one_waiting = 1;
324         }
325
326         LEAVE_CRITICAL_SECTION(&key_lock);              
327
328         return is_one_waiting;
329 }
330
331 //      Return key scancode if a key has been pressed,
332 //      else return 0.
333 //      Reads keys out of the key buffer and updates keyhead.
334 int key_inkey()
335 {
336         int key = 0;
337
338         if ( !key_inited ) return 0;
339
340         ENTER_CRITICAL_SECTION(&key_lock);      
341
342         if (key_data.keytail!=key_data.keyhead) {
343                 key = key_data.keybuffer[key_data.keyhead];
344                 key_data.keyhead = add_one(key_data.keyhead);
345         }
346
347         LEAVE_CRITICAL_SECTION(&key_lock);      
348
349         return key;
350 }
351
352 //      Unget a key.  Puts it back in the input queue.
353 void key_outkey(int key)
354 {
355         int     bufp;
356
357         if ( !key_inited ) return;
358
359         ENTER_CRITICAL_SECTION(&key_lock);              
360
361         bufp = key_data.keytail+1;
362
363         if (bufp >= KEY_BUFFER_SIZE){
364                 bufp = 0;
365         }
366
367         key_data.keybuffer[key_data.keytail] = (unsigned short)key;
368
369         key_data.keytail = bufp;
370
371         LEAVE_CRITICAL_SECTION(&key_lock);              
372 }
373
374
375
376 //      Return amount of time last key was held down.
377 //      This is currently (July 17, 1996) bogus because our timing is
378 //      not accurate.
379 int key_inkey_time(uint * time)
380 {
381         int key = 0;
382
383         if ( !key_inited ) {
384                 *time = 0;
385                 return 0;
386         }
387         
388         ENTER_CRITICAL_SECTION(&key_lock);              
389
390         if (key_data.keytail!=key_data.keyhead) {
391                 key = key_data.keybuffer[key_data.keyhead];
392                 *time = key_data.time_pressed[key_data.keyhead];
393                 key_data.keyhead = add_one(key_data.keyhead);
394         }
395
396         LEAVE_CRITICAL_SECTION(&key_lock);              
397
398         return key;
399 }
400
401
402 //      Returns scancode of last key pressed, if any (returns 0 if no key pressed)
403 //      but does not update keyhead pointer.
404 int key_peekkey()
405 {
406         int key = 0;
407
408         if ( !key_inited ) return 0;
409
410         ENTER_CRITICAL_SECTION(&key_lock);              
411
412         if (key_data.keytail!=key_data.keyhead) {
413                 key = key_data.keybuffer[key_data.keyhead];
414         }
415         LEAVE_CRITICAL_SECTION(&key_lock);              
416
417         return key;
418 }
419
420 // If not installed, uses BIOS and returns getch();
421 //      Else returns pending key (or waits for one if none waiting).
422 int key_getch()
423 {
424         int dummy=0;
425         int in;
426
427         if ( !key_inited ) return 0;
428         
429         while (!key_checkch()){
430                 os_poll();
431
432                 dummy++;
433         }
434         in = key_inkey();
435
436         return in;
437 }
438
439 //      Set global shift_status with modifier results (shift, ctrl, alt).
440 uint key_get_shift_status()
441 {
442         unsigned int shift_status = 0;
443
444         if ( !key_inited ) return 0;
445
446         ENTER_CRITICAL_SECTION(&key_lock);              
447
448         if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] )
449                 shift_status |= KEY_SHIFTED;
450
451         if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] )
452                 shift_status |= KEY_ALTED;
453
454         if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] )
455                 shift_status |= KEY_CTRLED;
456
457 #ifndef NDEBUG
458         if (keyd_pressed[KEY_DEBUG_KEY])
459                 shift_status |= KEY_DEBUGGED;
460 #else
461         if (keyd_pressed[KEY_DEBUG_KEY]) {
462                 mprintf(("Cheats_enabled = %i, Key_normal_game = %i\n", Cheats_enabled, Key_normal_game));
463                 if ((Cheats_enabled) && Key_normal_game) {
464                         mprintf(("Debug key\n"));
465                         shift_status |= KEY_DEBUGGED1;
466                 }
467         }
468 #endif
469         LEAVE_CRITICAL_SECTION(&key_lock);              
470
471         return shift_status;
472 }
473
474 //      Returns amount of time key (specified by "code") has been down since last call.
475 //      Returns float, unlike key_down_time() which returns a fix.
476 float key_down_timef(uint scancode)     
477 {
478         uint time_down, time;
479         uint delta_time;
480
481         if ( !key_inited ) return 0.0f;
482
483         if ((scancode<0)|| (scancode>=NUM_KEYS)) return 0.0f;
484
485         ENTER_CRITICAL_SECTION(&key_lock);              
486
487         time = timer_get_milliseconds();
488         delta_time = time - key_data.TimeKeyDownChecked[scancode];
489         key_data.TimeKeyDownChecked[scancode] = time;
490
491         if ( delta_time <= 1 ) {
492                 key_data.TimeKeyWentDown[scancode] = time;
493                 if (keyd_pressed[scancode])     {
494                         LEAVE_CRITICAL_SECTION(&key_lock);              
495                         return 1.0f;
496                 } else  {
497                         LEAVE_CRITICAL_SECTION(&key_lock);              
498                         return 0.0f;
499                 }
500         }
501
502         if ( !keyd_pressed[scancode] )  {
503                 time_down = key_data.TimeKeyHeldDown[scancode];
504                 key_data.TimeKeyHeldDown[scancode] = 0;
505         } else  {
506                 time_down =  time - key_data.TimeKeyWentDown[scancode];
507                 key_data.TimeKeyWentDown[scancode] = time;
508         }
509
510         LEAVE_CRITICAL_SECTION(&key_lock);              
511
512         return i2fl(time_down) / i2fl(delta_time);
513 }
514
515 /*
516 //      Returns amount of time key (specified by "code") has been down since last call.
517 //      Returns float, unlike key_down_time() which returns a fix.
518 fix key_down_time( uint code )
519 {
520         uint time_down, time;
521         uint delta_time;
522
523         if ( !key_inited ) return 0.0f;
524
525         if ((scancode<0)|| (scancode>=NUM_KEYS)) return 0.0f;
526
527         EnterCriticalSection( &key_lock );
528
529         time = timer_get_milliseconds();
530         delta_time = time - TimeKeyDownChecked[scancode];
531         TimeKeyDownChecked[scancode] = time;
532
533         if ( delta_time <= 1 ) {
534                 LeaveCriticalSection( &key_lock );
535                 if (keyd_pressed[scancode])
536                         return F1_0;
537                 else
538                         return 0;
539         }
540
541         if ( !keyd_pressed[scancode] )  {
542                 time_down = key_data.TimeKeyHeldDown[scancode];
543                 key_data.TimeKeyHeldDown[scancode] = 0;
544         } else  {
545                 time_down =  time - key_data.TimeKeyWentDown[scancode];
546                 key_data.TimeKeyWentDown[scancode] = time;
547         }
548
549         LeaveCriticalSection( &key_lock );
550
551         return fixmuldiv( time_down, F1_0, delta_time );
552 }
553 */
554
555
556 // Returns number of times key has went from up to down since last call.
557 int key_down_count(int scancode)        
558 {
559         int n;
560
561         if ( !key_inited ) return 0;
562         if ((scancode<0)|| (scancode>=NUM_KEYS)) return 0;
563
564         ENTER_CRITICAL_SECTION(&key_lock);              
565
566         n = key_data.NumDowns[scancode];
567         key_data.NumDowns[scancode] = 0;
568
569         LEAVE_CRITICAL_SECTION(&key_lock);              
570
571         return n;
572 }
573
574
575 // Returns number of times key has went from down to up since last call.
576 int key_up_count(int scancode)  
577 {
578         int n;
579
580         if ( !key_inited ) return 0;
581         if ((scancode<0)|| (scancode>=NUM_KEYS)) return 0;
582
583         ENTER_CRITICAL_SECTION(&key_lock);              
584
585         n = key_data.NumUps[scancode];
586         key_data.NumUps[scancode] = 0;
587
588         LEAVE_CRITICAL_SECTION(&key_lock);              
589
590         return n;
591 }
592
593 int key_check(int key)
594 {
595         return key_data.down_check[key];
596 }
597
598 //      Add a key up or down code to the key buffer.  state=1 -> down, state=0 -> up
599 // latency => time difference in ms between when key was actually pressed and now
600 //void key_mark( uint code, int state )
601 void key_mark( uint code, int state, uint latency )
602 {
603         uint scancode, breakbit, temp, event_time;
604         ushort keycode; 
605
606         if ( !key_inited ) return;
607
608         ENTER_CRITICAL_SECTION(&key_lock);              
609
610         // If running in the UK, need to translate their wacky slash scancode to ours
611         if ( code == KEY_SLASH_UK ) {
612                 code = KEY_SLASH;
613         }
614
615         if(Lcl_fr){
616                 switch (code) {
617                 case KEY_A:
618                         code = KEY_Q;
619                         break;
620
621                 case KEY_M:
622                         code = KEY_COMMA;
623                         break;
624
625                 case KEY_Q:
626                         code = KEY_A;
627                         break;
628
629                 case KEY_W:
630                         code = KEY_Z;
631                         break;
632
633                 case KEY_Z:
634                         code = KEY_W;
635                         break;
636
637                 case KEY_SEMICOL:
638                         code = KEY_M;
639                         break;
640
641                 case KEY_COMMA:
642                         code = KEY_SEMICOL;
643                         break;
644                 }
645         } else if(Lcl_gr){
646                 switch (code) {
647                 case KEY_Y:
648                         code = KEY_Z;
649                         break;
650
651                 case KEY_Z:
652                         code = KEY_Y;
653                         break;
654                 }
655                 
656         }
657
658         if ( (code == 0xc5) && !Key_running_NT ) {
659                 key_turn_off_numlock();
660         }
661
662         Assert( code < NUM_KEYS );      
663
664         event_time = timer_get_milliseconds() - latency;
665         // event_time = timeGetTime() - latency;
666
667         // Read in scancode
668         scancode = code & (NUM_KEYS-1);
669         breakbit = !state;
670         
671         if (breakbit)   {
672                 // Key going up
673                 keyd_last_released = scancode;
674                 keyd_pressed[scancode] = 0;
675                 key_data.NumUps[scancode]++;
676
677                 //      What is the point of this code?  "temp" is never used!
678                 temp = 0;
679                 temp |= keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT];
680                 temp |= keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT];
681                 temp |= keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL];
682 //#ifndef NDEBUG
683                 temp |= keyd_pressed[KEY_DEBUG_KEY];
684 //#endif        
685                 if (event_time < key_data.TimeKeyWentDown[scancode])
686                         key_data.TimeKeyHeldDown[scancode] = 0;
687                 else
688                         key_data.TimeKeyHeldDown[scancode] += event_time - key_data.TimeKeyWentDown[scancode];
689         } else {
690                 // Key going down
691                 keyd_last_pressed = scancode;
692                 keyd_time_when_last_pressed = event_time;
693                 if (!keyd_pressed[scancode])    {
694                         // First time down
695                         key_data.TimeKeyWentDown[scancode] = event_time;
696                         keyd_pressed[scancode] = 1;
697                         key_data.NumDowns[scancode]++;
698                         key_data.down_check[scancode]++;
699
700 //                      mprintf(( "Scancode = %x\n", scancode ));
701
702 //                      if ( scancode == KEY_BREAK )
703 //                              Int3();
704
705
706                 } else if (!keyd_repeat) {
707                         // Don't buffer repeating key if repeat mode is off
708                         scancode = 0xAA;                
709                 } 
710
711                 if ( scancode!=0xAA ) {
712                         keycode = (unsigned short)scancode;
713
714                         if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] )
715                                 keycode |= KEY_SHIFTED;
716
717                         if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] )
718                                 keycode |= KEY_ALTED;
719
720                         if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] )
721                                 keycode |= KEY_CTRLED;
722
723 #ifndef NDEBUG
724                         if ( keyd_pressed[KEY_DEBUG_KEY] )
725                                 keycode |= KEY_DEBUGGED;
726 //                      if ( keycode == (KEY_BACKSP + KEY_DEBUGGED) )   {
727 //                              keycode = 0;
728 //                              keyd_pressed[KEY_DEBUG_KEY] = 0;
729 //                              keyd_pressed[KEY_BACKSP] = 0;
730 //                              Int3();
731 //                      }
732 #else
733                         if ( keyd_pressed[KEY_DEBUG_KEY] ) {
734                                 mprintf(("Cheats_enabled = %i, Key_normal_game = %i\n", Cheats_enabled, Key_normal_game));
735                                 if (Cheats_enabled && Key_normal_game) {
736                                         keycode |= KEY_DEBUGGED1;
737                                 }
738                         }
739
740 #endif
741
742                         if ( keycode )  {
743                                 temp = key_data.keytail+1;
744                                 if ( temp >= KEY_BUFFER_SIZE ) temp=0;
745
746                                 if (temp!=key_data.keyhead)     {
747                                         int i, accept_key = 1;
748                                         // Num_filter_keys will only be non-zero when a key filter has
749                                         // been explicity set up via key_set_filter()
750                                         for ( i = 0; i < Num_filter_keys; i++ ) {
751                                                 accept_key = 0;
752                                                 if ( Key_filter[i] == keycode ) {
753                                                         accept_key = 1;
754                                                         break;
755                                                 }
756                                         }
757
758                                         if ( accept_key ) {
759                                                 key_data.keybuffer[key_data.keytail] = keycode;
760                                                 key_data.time_pressed[key_data.keytail] = keyd_time_when_last_pressed;
761                                                 key_data.keytail = temp;
762                                         }
763                                 }
764                         }
765                 }
766         }
767
768         LEAVE_CRITICAL_SECTION(&key_lock);              
769 }
770
771 #ifdef USE_DIRECTINPUT
772 void di_cleanup();
773 int di_init();
774 #endif
775
776
777 void key_close()
778 {
779         if ( !key_inited ) return;
780
781         #ifdef USE_DIRECTINPUT
782                 di_cleanup();
783         #endif
784
785         if ( Key_numlock_was_on ) {
786                 key_turn_on_numlock();
787                 Key_numlock_was_on = 0;
788         }
789
790         key_inited = 0;
791 #ifdef PLAT_UNIX
792         STUB_FUNCTION;
793 #else
794         DeleteCriticalSection( &key_lock );
795 #endif
796 }
797
798 void key_init()
799 {
800         // Initialize queue
801         if ( key_inited ) return;
802         key_inited = 1;
803
804 #ifdef PLAT_UNIX
805         STUB_FUNCTION;
806 #else
807         InitializeCriticalSection( &key_lock );
808
809         ENTER_CRITICAL_SECTION(&key_lock);              
810 #endif
811
812         keyd_time_when_last_pressed = timer_get_milliseconds();
813         keyd_buffer_type = 1;
814         keyd_repeat = 1;
815
816         // Clear the keyboard array
817         key_flush();
818
819         // Clear key filter
820         key_clear_filter();
821
822 #ifdef PLAT_UNIX
823         STUB_FUNCTION;
824 #else
825         LEAVE_CRITICAL_SECTION(&key_lock);              
826
827         #ifdef USE_DIRECTINPUT
828                 di_init();
829         #endif
830
831         OSVERSIONINFO ver;
832         ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
833         GetVersionEx(&ver);
834         if ( ver.dwPlatformId == VER_PLATFORM_WIN32_NT ) {
835                 Key_running_NT = 1;
836         } else {
837                 Key_running_NT = 0;
838                 if ( key_numlock_is_on() ) {
839                         Key_numlock_was_on = 1;
840                         key_turn_off_numlock();
841                 }
842         }
843 #endif
844
845         atexit(key_close);
846 }
847
848 void key_level_init()
849 {
850         int i;
851
852         for (i=0; i<NUM_KEYS; i++)
853                 key_data.down_check[i] = 0;
854 }
855
856 void key_lost_focus()
857 {
858         if ( !key_inited ) return;
859
860         key_flush();    
861 }
862
863 void key_got_focus()
864 {
865         if ( !key_inited ) return;
866         
867         key_flush();    
868 }
869
870 // Restricts the keys that are accepted from the keyboard
871 //
872 //      filter_array    =>              array of keys to act as a filter
873 //      num                             =>              number of keys in filter_array
874 //
875 void key_set_filter(int *filter_array, int num)
876 {
877         int i;
878
879         if ( num >= MAX_FILTER_KEYS ) {
880                 Int3();
881                 num = MAX_FILTER_KEYS;
882         }
883
884         Num_filter_keys = num;
885
886         for ( i = 0; i < num; i++ ) {
887                 Key_filter[i] = filter_array[i];
888         }
889 }
890
891 // Clear the key filter, so all keypresses are accepted from keyboard 
892 //
893 void key_clear_filter()
894 {
895         int i;
896
897         Num_filter_keys = 0;
898         for ( i = 0; i < MAX_FILTER_KEYS; i++ ) {
899                 Key_filter[i] = -1;
900         }
901 }
902
903
904 #ifdef USE_DIRECTINPUT
905
906 // JAS - April 18, 1998
907 // Not using because DI has the following problems:  (Everything else works ok)
908 // Under NT, Pause and Numlock report as identical keys.
909 // Under 95, Pause is the same as pressing Ctrl then Numlock.  So the game fires each
910 // time you hit it.
911 // 
912
913 //============================================================================
914 // Direct Input code
915 // For the keyboard, this basically replaces our old functionallity of:
916 // WM_KEYDOWN:
917 //    key_mark(...);
918 // WM_KEYUP:
919 //    key_mark(...);
920 //============================================================================
921
922
923 #include "vdinput.h"
924
925 #define MAX_BUFFERED_KEYBOARD_EVENTS 10
926
927 static LPDIRECTINPUT                    Di_object = NULL;
928 static LPDIRECTINPUTDEVICE      Di_keyboard = NULL;
929 static HANDLE                                   Di_thread = NULL;
930 static DWORD                                    Di_thread_id = NULL;
931 static HANDLE                                   Di_event = NULL;
932
933 DWORD di_process(DWORD lparam)
934 {
935         while (1) {
936                 if ( WaitForSingleObject( Di_event, INFINITE )==WAIT_OBJECT_0 ) {
937
938                         //mprintf(( "Got event!\n" ));
939
940                         HRESULT hr;
941
942                         DIDEVICEOBJECTDATA rgdod[10]; 
943                         DWORD dwItems = MAX_BUFFERED_KEYBOARD_EVENTS; 
944
945 again:;
946                         hr = Di_keyboard->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), rgdod,  &dwItems, 0); 
947
948                         if (hr == DIERR_INPUTLOST) {
949                                 /*
950                                 *  DirectInput is telling us that the input stream has
951                                 *  been interrupted.  We aren't tracking any state
952                                 *  between polls, so we don't have any special reset
953                                 *  that needs to be done.  We just re-acquire and
954                                 *  try again.
955                                 */
956                                 Sleep(1000);            // Pause a second...
957                                 hr = Di_keyboard->Acquire();
958                                 if (SUCCEEDED(hr)) {
959                                         goto again;
960                                 }
961                         }
962
963                         if (SUCCEEDED(hr)) { 
964                                  // dwItems = number of elements read (could be zero)
965                                  if (hr == DI_BUFFEROVERFLOW) { 
966                                         // Buffer had overflowed. 
967                                         mprintf(( "Buffer overflowed!\n" ));
968                                  } 
969                                         int i;
970
971                                         //mprintf(( "Got %d events\n", dwItems ));
972
973                                         for (i=0; i<(int)dwItems; i++ ) {
974                                                 int key = rgdod[i].dwOfs;
975                                                 int state = rgdod[i].dwData;
976                                                 int stamp = rgdod[i].dwTimeStamp;
977
978                                                 int latency;
979                                                 latency = timeGetTime() - stamp;
980                                                 if ( latency < 0 )
981                                                         latency=0;
982
983 //                                              if ( key == KEY_PRINT_SCRN )    {
984 //                                                      key_mark( key, 1, latency );
985 //                                              }
986 //                                              key_mark( key, (state&0x80?1:0), latency );
987                                                 mprintf(( "Key=%x, State=%x, Time=%d, Latency=%d\n", key, state, stamp, latency ));
988                                         }
989
990                         } 
991                 } 
992
993         }
994
995         return 0;
996 }
997
998
999 int di_init()
1000 {
1001     HRESULT hr;
1002
1003          return 0;
1004
1005
1006     /*
1007      *  Register with the DirectInput subsystem and get a pointer
1008      *  to a IDirectInput interface we can use.
1009      *
1010      *  Parameters:
1011      *
1012      *      g_hinst
1013      *
1014      *          Instance handle to our application or DLL.
1015      *
1016      *      DIRECTINPUT_VERSION
1017      *
1018      *          The version of DirectInput we were designed for.
1019      *          We take the value from the <dinput.h> header file.
1020      *
1021      *      &g_pdi
1022      *
1023      *          Receives pointer to the IDirectInput interface
1024      *          that was created.
1025      *
1026      *      NULL
1027      *
1028      *          We do not use OLE aggregation, so this parameter
1029      *          must be NULL.
1030      *
1031      */
1032     hr = DirectInputCreate(GetModuleHandle(NULL), 0x300, &Di_object, NULL);
1033
1034     if (FAILED(hr)) {
1035         mprintf(( "DirectInputCreate failed!\n" ));
1036         return FALSE;
1037     }
1038
1039     /*
1040      *  Obtain an interface to the system keyboard device.
1041      *
1042      *  Parameters:
1043      *
1044      *      GUID_SysKeyboard
1045      *
1046      *          The instance GUID for the device we wish to access.
1047      *          GUID_SysKeyboard is a predefined instance GUID that
1048      *          always refers to the system keyboard device.
1049      *
1050      *      &g_pKeyboard
1051      *
1052      *          Receives pointer to the IDirectInputDevice interface
1053      *          that was created.
1054      *
1055      *      NULL
1056      *
1057      *          We do not use OLE aggregation, so this parameter
1058      *          must be NULL.
1059      *
1060      */
1061     hr = Di_object->CreateDevice(GUID_SysKeyboard, &Di_keyboard, NULL);
1062
1063     if (FAILED(hr)) {
1064         mprintf(( "CreateDevice failed!\n" ));
1065         return FALSE;
1066     }
1067
1068     /*
1069      *  Set the data format to "keyboard format".
1070      *
1071      *  A data format specifies which controls on a device we
1072      *  are interested in, and how they should be reported.
1073      *
1074      *  This tells DirectInput that we will be passing an array
1075      *  of 256 bytes to IDirectInputDevice::GetDeviceState.
1076      *
1077      *  Parameters:
1078      *
1079      *      c_dfDIKeyboard
1080      *
1081      *          Predefined data format which describes
1082      *          an array of 256 bytes, one per scancode.
1083      */
1084     hr = Di_keyboard->SetDataFormat(&c_dfDIKeyboard);
1085
1086     if (FAILED(hr)) {
1087         mprintf(( "SetDataFormat failed!\n" ));
1088         return FALSE;
1089     }
1090
1091
1092     /*
1093      *  Set the cooperativity level to let DirectInput know how
1094      *  this device should interact with the system and with other
1095      *  DirectInput applications.
1096      *
1097      *  Parameters:
1098      *
1099      *      DISCL_NONEXCLUSIVE
1100      *
1101      *          Retrieve keyboard data when acquired, not interfering
1102      *          with any other applications which are reading keyboard
1103      *          data.
1104      *
1105      *      DISCL_FOREGROUND
1106      *
1107      *          If the user switches away from our application,
1108      *          automatically release the keyboard back to the system.
1109      *
1110      */
1111         hr = Di_keyboard->SetCooperativeLevel((HWND)os_get_window(), DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
1112
1113         if (FAILED(hr)) {
1114                 mprintf(( "SetCooperativeLevel failed!\n" ));
1115                 return FALSE;
1116         }
1117
1118         DIPROPDWORD hdr;
1119
1120         // Turn on buffering
1121         hdr.diph.dwSize = sizeof(DIPROPDWORD); 
1122         hdr.diph.dwHeaderSize = sizeof(DIPROPHEADER);
1123         hdr.diph.dwObj = 0;             
1124         hdr.diph.dwHow = DIPH_DEVICE;   // Apply to entire device
1125         hdr.dwData = 16;        //MAX_BUFFERED_KEYBOARD_EVENTS;
1126
1127         hr = Di_keyboard->SetProperty( DIPROP_BUFFERSIZE, &hdr.diph );
1128         if (FAILED(hr)) {
1129                 mprintf(( "SetProperty DIPROP_BUFFERSIZE failed\n" ));
1130                 return FALSE;
1131         }
1132
1133
1134         Di_event = CreateEvent( NULL, FALSE, FALSE, NULL );
1135         Assert(Di_event != NULL);
1136
1137         Di_thread = CreateThread(NULL, 1024, (LPTHREAD_START_ROUTINE)di_process, NULL, 0, &Di_thread_id);
1138         Assert( Di_thread != NULL );
1139
1140         SetThreadPriority(Di_thread, THREAD_PRIORITY_HIGHEST);
1141
1142         hr = Di_keyboard->SetEventNotification(Di_event);
1143         if (FAILED(hr)) {
1144                 mprintf(( "SetEventNotification failed\n" ));
1145                 return FALSE;
1146         }
1147
1148         Di_keyboard->Acquire();
1149
1150         return TRUE;
1151 }
1152
1153 void di_cleanup()
1154 {
1155     /*
1156      *  Destroy any lingering IDirectInputDevice object.
1157      */
1158     if (Di_keyboard) {
1159
1160         /*
1161          *  Cleanliness is next to godliness.  Unacquire the device
1162          *  one last time just in case we got really confused and tried
1163          *  to exit while the device is still acquired.
1164          */
1165         Di_keyboard->Unacquire();
1166
1167         Di_keyboard->Release();
1168         Di_keyboard = NULL;
1169     }
1170
1171     /*
1172      *  Destroy any lingering IDirectInput object.
1173      */
1174     if (Di_object) {
1175         Di_object->Release();
1176         Di_object = NULL;
1177     }
1178
1179         if ( Di_event ) {
1180                 CloseHandle(Di_event);
1181                 Di_event = NULL;
1182         }
1183
1184 }
1185
1186 #endif
1187
1188
1189
1190