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