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