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