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