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