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