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