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