2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/Io/Key.cpp $
15 * <insert description of file here>
18 * Revision 1.12 2004/06/11 01:14:12 tigital
19 * OSX: switched to __APPLE__
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
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)
27 * Revision 1.8 2002/06/17 23:11:39 relnev
28 * enable sdl key repeating.
32 * Revision 1.7 2002/06/09 04:41:21 relnev
33 * added copyright header
35 * Revision 1.6 2002/06/05 04:03:32 relnev
36 * finished cfilesystem.
38 * removed some old code.
40 * fixed mouse save off-by-one.
44 * Revision 1.5 2002/05/31 03:34:02 theoddone33
48 * Revision 1.4 2002/05/30 23:46:29 theoddone33
49 * some minor key changes (not necessarily fixes)
51 * Revision 1.3 2002/05/30 16:50:24 theoddone33
52 * Keyboard partially fixed
54 * Revision 1.2 2002/05/29 23:17:50 theoddone33
55 * Non working text code and fixed keys
57 * Revision 1.1.1.1 2002/05/03 03:28:09 root
61 * 6 10/29/99 6:10p Jefff
62 * squashed the damned y/z german issues once and for all
64 * 5 6/07/99 1:21p Dave
65 * Fixed debug console scrolling problem. Thread related.
67 * 4 6/02/99 6:18p Dave
68 * Fixed TNT lockup problems! Wheeeee!
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
75 * 2 10/07/98 10:53a Dave
78 * 1 10/07/98 10:49a Dave
80 * 37 6/19/98 3:50p Lawrance
81 * change GERMAN to GR_BUILD
83 * 36 6/17/98 11:05a Lawrance
84 * translate french and german keys
86 * 35 6/12/98 4:49p Hoffoss
87 * Added code to remap scancodes for german and french keyboards.
89 * 34 5/20/98 12:10a Mike
92 * 33 5/19/98 12:19p Mike
95 * 32 5/19/98 12:28a Mike
98 * 31 5/18/98 11:01p Mike
99 * Adding support for cheat system.
101 * 30 5/11/98 12:09a Lawrance
102 * Put in code to turn on/off NumLock key when running under 95
104 * 29 5/01/98 4:23p Lawrance
105 * Remap the scancode for the UK "\" key
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.
111 * 27 4/13/98 10:16a John
112 * Switched gettime back to timer_get_milliseconds, which is now thread
115 * 26 4/12/98 11:08p Lawrance
116 * switch back to using gettime() in separate threads
118 * 25 4/12/98 5:31p Lawrance
119 * use timer_get_milliseconds() instead of gettime()
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.
125 * 23 1/23/98 3:49p Mike
126 * Fix bug in negative time-down due to latency.
128 * 22 1/07/98 6:41p Lawrance
129 * Pass message latency to the keyboard lib.
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.
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".
140 * 19 9/13/97 9:30a Lawrance
141 * added ability to block certain keys from the keyboard
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.
147 * 17 9/09/97 11:08a Sandeep
148 * fixed warning level 4
150 * 16 7/29/97 5:30p Lawrance
151 * move gettime() to timer module
153 * 15 4/22/97 10:56a John
154 * fixed some resource leaks.
156 * 14 2/03/97 4:23p Allender
157 * use F11 as debug key now
159 * 13 1/10/97 5:15p Mike
160 * Moved ship-specific parameters from obj_subsystem to ship_subsys.
162 * Added turret code to AI system.
167 //#define USE_DIRECTINPUT
171 #include <windowsx.h>
174 #include <ctype.h> // for toupper
180 #include "localize.h"
182 #define KEY_BUFFER_SIZE 16
184 //-------- Variable accessed by outside functions ---------
185 ubyte keyd_buffer_type; // 0=No buffer, 1=buffer ASCII, 2=buffer scans
187 uint keyd_last_pressed;
188 uint keyd_last_released;
189 ubyte keyd_pressed[NUM_KEYS];
190 int keyd_time_when_last_pressed;
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;
208 CRITICAL_SECTION key_lock;
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
216 int SDLtoFS2[SDLK_LAST];
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 };
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 };
241 // used to limit the keypresses that are accepted from the keyboard
242 #define MAX_FILTER_KEYS 64
244 int Key_filter[MAX_FILTER_KEYS];
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
249 int Cheats_enabled = 0;
250 int Key_normal_game = 0;
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;
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;
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;
302 SDLtoFS2[SDLK_WORLD_92] = KEY_LBRACKET;
303 SDLtoFS2[SDLK_PLUS] = KEY_RBRACKET;
305 SDLtoFS2[SDLK_CARET] = KEY_LAPOSTRO;
306 SDLtoFS2[SDLK_WORLD_68] = KEY_RAPOSTRO;
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;
317 SDLtoFS2[SDLK_LEFTBRACKET] = KEY_LBRACKET;
318 SDLtoFS2[SDLK_RIGHTBRACKET] = KEY_RBRACKET;
320 SDLtoFS2[SDLK_BACKQUOTE] = KEY_LAPOSTRO;
321 SDLtoFS2[SDLK_QUOTE] = KEY_RAPOSTRO;
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;
330 SDLtoFS2[SDLK_NUMLOCK] = KEY_NUMLOCK;
331 SDLtoFS2[SDLK_SCROLLOCK] = KEY_SCROLLOCK;
332 SDLtoFS2[SDLK_CAPSLOCK] = KEY_CAPSLOCK;
334 SDLtoFS2[SDLK_LSHIFT] = KEY_LSHIFT;
335 SDLtoFS2[SDLK_RSHIFT] = KEY_RSHIFT;
337 SDLtoFS2[SDLK_LALT] = KEY_LALT;
338 SDLtoFS2[SDLK_RALT] = KEY_RALT;
340 SDLtoFS2[SDLK_LCTRL] = KEY_LCTRL;
341 SDLtoFS2[SDLK_RCTRL] = KEY_RCTRL;
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;
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;
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;
384 SDLtoFS2[SDLK_PRINT] = KEY_PRINT_SCRN;
385 SDLtoFS2[SDLK_PAUSE] = KEY_PAUSE;
386 SDLtoFS2[SDLK_BREAK] = KEY_BREAK;
390 int key_numlock_is_on()
394 SDL_GetKeyState(keys);
395 if ( keys[SDLK_NUMLOCK] ) {
399 unsigned char keys[256];
400 GetKeyboardState(keys);
401 if ( keys[VK_NUMLOCK] ) {
408 void key_turn_off_numlock()
411 // STUB_FUNCTION; /* sdl doesn't support this */
413 unsigned char keys[256];
414 GetKeyboardState(keys);
415 keys[VK_NUMLOCK] = 0;
416 SetKeyboardState(keys);
420 void key_turn_on_numlock()
423 // STUB_FUNCTION; /* sdl doesn't support this */
425 unsigned char keys[256];
426 GetKeyboardState(keys);
427 keys[VK_NUMLOCK] = 1;
428 SetKeyboardState(keys);
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 )
439 if ( !key_inited ) return 255;
441 shifted = keycode & KEY_SHIFTED;
448 return shifted_ascii_table[keycode];
450 return ascii_table[keycode];
453 // Flush the keyboard buffer.
454 // Clear the keyboard array (keyd_pressed).
460 if ( !key_inited ) return;
462 ENTER_CRITICAL_SECTION(&key_lock);
464 key_data.keyhead = key_data.keytail = 0;
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;
472 //Clear the keyboard array
474 CurTime = timer_get_milliseconds();
477 for (i=0; i<NUM_KEYS; i++ ) {
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;
486 LEAVE_CRITICAL_SECTION(&key_lock);
489 // A nifty function which performs the function:
490 // n = (n+1) % KEY_BUFFER_SIZE
491 // (assuming positive values of n).
495 if ( n >= KEY_BUFFER_SIZE ) n=0;
499 // Returns 1 if character waiting... 0 otherwise
502 int is_one_waiting = 0;
504 if ( !key_inited ) return 0;
506 ENTER_CRITICAL_SECTION(&key_lock);
508 if (key_data.keytail != key_data.keyhead){
512 LEAVE_CRITICAL_SECTION(&key_lock);
514 return is_one_waiting;
517 // Return key scancode if a key has been pressed,
519 // Reads keys out of the key buffer and updates keyhead.
524 if ( !key_inited ) return 0;
526 ENTER_CRITICAL_SECTION(&key_lock);
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);
533 LEAVE_CRITICAL_SECTION(&key_lock);
538 // Unget a key. Puts it back in the input queue.
539 void key_outkey(int key)
543 if ( !key_inited ) return;
545 ENTER_CRITICAL_SECTION(&key_lock);
547 bufp = key_data.keytail+1;
549 if (bufp >= KEY_BUFFER_SIZE){
553 key_data.keybuffer[key_data.keytail] = (unsigned short)key;
555 key_data.keytail = bufp;
557 LEAVE_CRITICAL_SECTION(&key_lock);
562 // Return amount of time last key was held down.
563 // This is currently (July 17, 1996) bogus because our timing is
565 int key_inkey_time(uint * time)
574 ENTER_CRITICAL_SECTION(&key_lock);
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);
582 LEAVE_CRITICAL_SECTION(&key_lock);
588 // Returns scancode of last key pressed, if any (returns 0 if no key pressed)
589 // but does not update keyhead pointer.
594 if ( !key_inited ) return 0;
596 ENTER_CRITICAL_SECTION(&key_lock);
598 if (key_data.keytail!=key_data.keyhead) {
599 key = key_data.keybuffer[key_data.keyhead];
601 LEAVE_CRITICAL_SECTION(&key_lock);
606 // If not installed, uses BIOS and returns getch();
607 // Else returns pending key (or waits for one if none waiting).
613 if ( !key_inited ) return 0;
615 while (!key_checkch()){
625 // Set global shift_status with modifier results (shift, ctrl, alt).
626 uint key_get_shift_status()
628 unsigned int shift_status = 0;
630 if ( !key_inited ) return 0;
632 ENTER_CRITICAL_SECTION(&key_lock);
634 if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] )
635 shift_status |= KEY_SHIFTED;
637 if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] )
638 shift_status |= KEY_ALTED;
640 if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] )
641 shift_status |= KEY_CTRLED;
644 if (keyd_pressed[KEY_DEBUG_KEY])
645 shift_status |= KEY_DEBUGGED;
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;
655 LEAVE_CRITICAL_SECTION(&key_lock);
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)
664 uint time_down, time;
667 if ( !key_inited ) return 0.0f;
669 if ((scancode<0)|| (scancode>=NUM_KEYS)) return 0.0f;
671 ENTER_CRITICAL_SECTION(&key_lock);
673 time = timer_get_milliseconds();
674 delta_time = time - key_data.TimeKeyDownChecked[scancode];
675 key_data.TimeKeyDownChecked[scancode] = time;
677 if ( delta_time <= 1 ) {
678 key_data.TimeKeyWentDown[scancode] = time;
679 if (keyd_pressed[scancode]) {
680 LEAVE_CRITICAL_SECTION(&key_lock);
683 LEAVE_CRITICAL_SECTION(&key_lock);
688 if ( !keyd_pressed[scancode] ) {
689 time_down = key_data.TimeKeyHeldDown[scancode];
690 key_data.TimeKeyHeldDown[scancode] = 0;
692 time_down = time - key_data.TimeKeyWentDown[scancode];
693 key_data.TimeKeyWentDown[scancode] = time;
696 LEAVE_CRITICAL_SECTION(&key_lock);
698 return i2fl(time_down) / i2fl(delta_time);
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 )
706 uint time_down, time;
709 if ( !key_inited ) return 0.0f;
711 if ((scancode<0)|| (scancode>=NUM_KEYS)) return 0.0f;
713 EnterCriticalSection( &key_lock );
715 time = timer_get_milliseconds();
716 delta_time = time - TimeKeyDownChecked[scancode];
717 TimeKeyDownChecked[scancode] = time;
719 if ( delta_time <= 1 ) {
720 LeaveCriticalSection( &key_lock );
721 if (keyd_pressed[scancode])
727 if ( !keyd_pressed[scancode] ) {
728 time_down = key_data.TimeKeyHeldDown[scancode];
729 key_data.TimeKeyHeldDown[scancode] = 0;
731 time_down = time - key_data.TimeKeyWentDown[scancode];
732 key_data.TimeKeyWentDown[scancode] = time;
735 LeaveCriticalSection( &key_lock );
737 return fixmuldiv( time_down, F1_0, delta_time );
742 // Returns number of times key has went from up to down since last call.
743 int key_down_count(int scancode)
747 if ( !key_inited ) return 0;
749 if ((scancode<0)|| (scancode>=NUM_KEYS)) return 0;
751 ENTER_CRITICAL_SECTION(&key_lock);
753 n = key_data.NumDowns[scancode];
754 key_data.NumDowns[scancode] = 0;
756 LEAVE_CRITICAL_SECTION(&key_lock);
762 // Returns number of times key has went from down to up since last call.
763 int key_up_count(int scancode)
767 if ( !key_inited ) return 0;
768 if ((scancode<0)|| (scancode>=NUM_KEYS)) return 0;
770 ENTER_CRITICAL_SECTION(&key_lock);
772 n = key_data.NumUps[scancode];
773 key_data.NumUps[scancode] = 0;
775 LEAVE_CRITICAL_SECTION(&key_lock);
780 int key_check(int key)
782 return key_data.down_check[key];
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 )
790 uint scancode, breakbit, temp, event_time;
793 if ( !key_inited ) return;
795 ENTER_CRITICAL_SECTION(&key_lock);
797 // If running in the UK, need to translate their wacky slash scancode to ours
798 if ( code == KEY_SLASH_UK ) {
832 #if !defined(PLAT_UNIX) || defined(__APPLE__)
846 if ( (code == 0xc5) && !Key_running_NT ) {
847 key_turn_off_numlock();
850 Assert( code < NUM_KEYS );
852 event_time = timer_get_milliseconds() - latency;
853 // event_time = timeGetTime() - latency;
856 scancode = code & (NUM_KEYS-1);
861 keyd_last_released = scancode;
862 keyd_pressed[scancode] = 0;
863 key_data.NumUps[scancode]++;
865 // What is the point of this code? "temp" is never used!
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];
871 temp |= keyd_pressed[KEY_DEBUG_KEY];
873 if (event_time < key_data.TimeKeyWentDown[scancode])
874 key_data.TimeKeyHeldDown[scancode] = 0;
876 key_data.TimeKeyHeldDown[scancode] += event_time - key_data.TimeKeyWentDown[scancode];
879 keyd_last_pressed = scancode;
880 keyd_time_when_last_pressed = event_time;
881 if (!keyd_pressed[scancode]) {
883 key_data.TimeKeyWentDown[scancode] = event_time;
884 keyd_pressed[scancode] = 1;
885 key_data.NumDowns[scancode]++;
886 key_data.down_check[scancode]++;
888 // mprintf(( "Scancode = %x\n", scancode ));
890 // if ( scancode == KEY_BREAK )
894 } else if (!keyd_repeat) {
895 // Don't buffer repeating key if repeat mode is off
899 if ( scancode!=0xAA ) {
900 keycode = (unsigned short)scancode;
902 if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] )
903 keycode |= KEY_SHIFTED;
905 if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] )
906 keycode |= KEY_ALTED;
908 if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] )
909 keycode |= KEY_CTRLED;
912 if ( keyd_pressed[KEY_DEBUG_KEY] )
913 keycode |= KEY_DEBUGGED;
914 // if ( keycode == (KEY_BACKSP + KEY_DEBUGGED) ) {
916 // keyd_pressed[KEY_DEBUG_KEY] = 0;
917 // keyd_pressed[KEY_BACKSP] = 0;
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;
931 temp = key_data.keytail+1;
932 if ( temp >= KEY_BUFFER_SIZE ) temp=0;
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++ ) {
940 if ( Key_filter[i] == keycode ) {
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;
956 LEAVE_CRITICAL_SECTION(&key_lock);
959 #ifdef USE_DIRECTINPUT
967 if ( !key_inited ) return;
969 #ifdef USE_DIRECTINPUT
973 if ( Key_numlock_was_on ) {
974 key_turn_on_numlock();
975 Key_numlock_was_on = 0;
980 // STUB_FUNCTION; /* don't need this? */
982 DeleteCriticalSection( &key_lock );
989 if ( key_inited ) return;
994 // STUB_FUNCTION; /* don't need this */
996 InitializeCriticalSection( &key_lock );
998 ENTER_CRITICAL_SECTION(&key_lock);
1001 keyd_time_when_last_pressed = timer_get_milliseconds();
1002 keyd_buffer_type = 1;
1005 // Clear the keyboard array
1012 // STUB_FUNCTION; /* don't need this */
1014 LEAVE_CRITICAL_SECTION(&key_lock);
1016 #ifdef USE_DIRECTINPUT
1021 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1023 if ( ver.dwPlatformId == VER_PLATFORM_WIN32_NT ) {
1027 if ( key_numlock_is_on() ) {
1028 Key_numlock_was_on = 1;
1029 key_turn_off_numlock();
1037 void key_level_init()
1041 for (i=0; i<NUM_KEYS; i++)
1042 key_data.down_check[i] = 0;
1045 void key_lost_focus()
1047 if ( !key_inited ) return;
1052 void key_got_focus()
1054 if ( !key_inited ) return;
1059 // Restricts the keys that are accepted from the keyboard
1061 // filter_array => array of keys to act as a filter
1062 // num => number of keys in filter_array
1064 void key_set_filter(int *filter_array, int num)
1068 if ( num >= MAX_FILTER_KEYS ) {
1070 num = MAX_FILTER_KEYS;
1073 Num_filter_keys = num;
1075 for ( i = 0; i < num; i++ ) {
1076 Key_filter[i] = filter_array[i];
1080 // Clear the key filter, so all keypresses are accepted from keyboard
1082 void key_clear_filter()
1086 Num_filter_keys = 0;
1087 for ( i = 0; i < MAX_FILTER_KEYS; i++ ) {
1093 #ifdef USE_DIRECTINPUT
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
1102 //============================================================================
1103 // Direct Input code
1104 // For the keyboard, this basically replaces our old functionallity of:
1109 //============================================================================
1112 #include "vdinput.h"
1114 #define MAX_BUFFERED_KEYBOARD_EVENTS 10
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;
1122 DWORD di_process(DWORD lparam)
1125 if ( WaitForSingleObject( Di_event, INFINITE )==WAIT_OBJECT_0 ) {
1127 //mprintf(( "Got event!\n" ));
1131 DIDEVICEOBJECTDATA rgdod[10];
1132 DWORD dwItems = MAX_BUFFERED_KEYBOARD_EVENTS;
1135 hr = Di_keyboard->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), rgdod, &dwItems, 0);
1137 if (hr == DIERR_INPUTLOST) {
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
1145 Sleep(1000); // Pause a second...
1146 hr = Di_keyboard->Acquire();
1147 if (SUCCEEDED(hr)) {
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" ));
1160 //mprintf(( "Got %d events\n", dwItems ));
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;
1168 latency = timeGetTime() - stamp;
1172 // if ( key == KEY_PRINT_SCRN ) {
1173 // key_mark( key, 1, latency );
1175 // key_mark( key, (state&0x80?1:0), latency );
1176 mprintf(( "Key=%x, State=%x, Time=%d, Latency=%d\n", key, state, stamp, latency ));
1196 * Register with the DirectInput subsystem and get a pointer
1197 * to a IDirectInput interface we can use.
1203 * Instance handle to our application or DLL.
1205 * DIRECTINPUT_VERSION
1207 * The version of DirectInput we were designed for.
1208 * We take the value from the <dinput.h> header file.
1212 * Receives pointer to the IDirectInput interface
1217 * We do not use OLE aggregation, so this parameter
1221 hr = DirectInputCreate(GetModuleHandle(NULL), 0x300, &Di_object, NULL);
1224 mprintf(( "DirectInputCreate failed!\n" ));
1229 * Obtain an interface to the system keyboard device.
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.
1241 * Receives pointer to the IDirectInputDevice interface
1246 * We do not use OLE aggregation, so this parameter
1250 hr = Di_object->CreateDevice(GUID_SysKeyboard, &Di_keyboard, NULL);
1253 mprintf(( "CreateDevice failed!\n" ));
1258 * Set the data format to "keyboard format".
1260 * A data format specifies which controls on a device we
1261 * are interested in, and how they should be reported.
1263 * This tells DirectInput that we will be passing an array
1264 * of 256 bytes to IDirectInputDevice::GetDeviceState.
1270 * Predefined data format which describes
1271 * an array of 256 bytes, one per scancode.
1273 hr = Di_keyboard->SetDataFormat(&c_dfDIKeyboard);
1276 mprintf(( "SetDataFormat failed!\n" ));
1282 * Set the cooperativity level to let DirectInput know how
1283 * this device should interact with the system and with other
1284 * DirectInput applications.
1288 * DISCL_NONEXCLUSIVE
1290 * Retrieve keyboard data when acquired, not interfering
1291 * with any other applications which are reading keyboard
1296 * If the user switches away from our application,
1297 * automatically release the keyboard back to the system.
1300 hr = Di_keyboard->SetCooperativeLevel((HWND)os_get_window(), DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
1303 mprintf(( "SetCooperativeLevel failed!\n" ));
1309 // Turn on buffering
1310 hdr.diph.dwSize = sizeof(DIPROPDWORD);
1311 hdr.diph.dwHeaderSize = sizeof(DIPROPHEADER);
1313 hdr.diph.dwHow = DIPH_DEVICE; // Apply to entire device
1314 hdr.dwData = 16; //MAX_BUFFERED_KEYBOARD_EVENTS;
1316 hr = Di_keyboard->SetProperty( DIPROP_BUFFERSIZE, &hdr.diph );
1318 mprintf(( "SetProperty DIPROP_BUFFERSIZE failed\n" ));
1323 Di_event = CreateEvent( NULL, FALSE, FALSE, NULL );
1324 Assert(Di_event != NULL);
1326 Di_thread = CreateThread(NULL, 1024, (LPTHREAD_START_ROUTINE)di_process, NULL, 0, &Di_thread_id);
1327 Assert( Di_thread != NULL );
1329 SetThreadPriority(Di_thread, THREAD_PRIORITY_HIGHEST);
1331 hr = Di_keyboard->SetEventNotification(Di_event);
1333 mprintf(( "SetEventNotification failed\n" ));
1337 Di_keyboard->Acquire();
1345 * Destroy any lingering IDirectInputDevice object.
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.
1354 Di_keyboard->Unacquire();
1356 Di_keyboard->Release();
1361 * Destroy any lingering IDirectInput object.
1364 Di_object->Release();
1369 CloseHandle(Di_event);