2 * $Logfile: /Freespace2/code/Io/Key.cpp $
7 * <insert description of file here>
10 * Revision 1.4 2002/05/30 23:46:29 theoddone33
11 * some minor key changes (not necessarily fixes)
13 * Revision 1.3 2002/05/30 16:50:24 theoddone33
14 * Keyboard partially fixed
16 * Revision 1.2 2002/05/29 23:17:50 theoddone33
17 * Non working text code and fixed keys
19 * Revision 1.1.1.1 2002/05/03 03:28:09 root
23 * 6 10/29/99 6:10p Jefff
24 * squashed the damned y/z german issues once and for all
26 * 5 6/07/99 1:21p Dave
27 * Fixed debug console scrolling problem. Thread related.
29 * 4 6/02/99 6:18p Dave
30 * Fixed TNT lockup problems! Wheeeee!
32 * 3 11/05/98 4:18p Dave
33 * First run nebula support. Beefed up localization a bit. Removed all
34 * conditional compiles for foreign versions. Modified mission file
37 * 2 10/07/98 10:53a Dave
40 * 1 10/07/98 10:49a Dave
42 * 37 6/19/98 3:50p Lawrance
43 * change GERMAN to GR_BUILD
45 * 36 6/17/98 11:05a Lawrance
46 * translate french and german keys
48 * 35 6/12/98 4:49p Hoffoss
49 * Added code to remap scancodes for german and french keyboards.
51 * 34 5/20/98 12:10a Mike
54 * 33 5/19/98 12:19p Mike
57 * 32 5/19/98 12:28a Mike
60 * 31 5/18/98 11:01p Mike
61 * Adding support for cheat system.
63 * 30 5/11/98 12:09a Lawrance
64 * Put in code to turn on/off NumLock key when running under 95
66 * 29 5/01/98 4:23p Lawrance
67 * Remap the scancode for the UK "\" key
69 * 28 4/18/98 12:42p John
70 * Added code to use DirectInput to read keyboard. Took out because it
71 * didn't differentiate btwn Pause and Numlock and sometimes Ctrl.
73 * 27 4/13/98 10:16a John
74 * Switched gettime back to timer_get_milliseconds, which is now thread
77 * 26 4/12/98 11:08p Lawrance
78 * switch back to using gettime() in separate threads
80 * 25 4/12/98 5:31p Lawrance
81 * use timer_get_milliseconds() instead of gettime()
83 * 24 3/25/98 8:08p John
84 * Restructured software rendering into two modules; One for windowed
85 * debug mode and one for DirectX fullscreen.
87 * 23 1/23/98 3:49p Mike
88 * Fix bug in negative time-down due to latency.
90 * 22 1/07/98 6:41p Lawrance
91 * Pass message latency to the keyboard lib.
93 * 21 11/17/97 10:42a John
94 * On Debug+Backsp, cleared out keys so that it looks like nothing ever
95 * happened, so they're not stuck down.
97 * 20 11/14/97 4:33p Mike
98 * Change Debug key to backquote (from F11).
99 * Balance a ton of subsystems in ships.tbl.
100 * Change "Heavy Laser" to "Disruptor".
102 * 19 9/13/97 9:30a Lawrance
103 * added ability to block certain keys from the keyboard
105 * 18 9/10/97 6:02p Hoffoss
106 * Added code to check for key-pressed sexp operator in FreeSpace as part
107 * of training mission stuff.
109 * 17 9/09/97 11:08a Sandeep
110 * fixed warning level 4
112 * 16 7/29/97 5:30p Lawrance
113 * move gettime() to timer module
115 * 15 4/22/97 10:56a John
116 * fixed some resource leaks.
118 * 14 2/03/97 4:23p Allender
119 * use F11 as debug key now
121 * 13 1/10/97 5:15p Mike
122 * Moved ship-specific parameters from obj_subsystem to ship_subsys.
124 * Added turret code to AI system.
129 //#define USE_DIRECTINPUT
133 #include <windowsx.h>
136 #include <ctype.h> // for toupper
142 #include "localize.h"
144 #define KEY_BUFFER_SIZE 16
146 //-------- Variable accessed by outside functions ---------
147 ubyte keyd_buffer_type; // 0=No buffer, 1=buffer ASCII, 2=buffer scans
149 uint keyd_last_pressed;
150 uint keyd_last_released;
151 ubyte keyd_pressed[NUM_KEYS];
152 int keyd_time_when_last_pressed;
154 typedef struct keyboard {
155 ushort keybuffer[KEY_BUFFER_SIZE];
156 uint time_pressed[KEY_BUFFER_SIZE];
157 uint TimeKeyWentDown[NUM_KEYS];
158 uint TimeKeyHeldDown[NUM_KEYS];
159 uint TimeKeyDownChecked[NUM_KEYS];
160 uint NumDowns[NUM_KEYS];
161 uint NumUps[NUM_KEYS];
162 int down_check[NUM_KEYS]; // nonzero if has been pressed yet this mission
163 uint keyhead, keytail;
170 CRITICAL_SECTION key_lock;
172 //int Backspace_debug=1; // global flag that will enable/disable the backspace key from stopping execution
173 // This flag was created since the backspace key is also used to correct mistakes
174 // when typing in your pilots callsign. This global flag is checked before execution
177 int ascii_table[128] =
178 { 255, 255, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=',255,255,
179 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 255, 255,
180 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 39, '`',
181 255, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 255,'*',
182 255, ' ', 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255,255,
183 255, 255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
184 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
185 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
186 255,255,255,255,255,255,255,255 };
188 int shifted_ascii_table[128] =
189 { 255, 255, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+',255,255,
190 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 255, 255,
191 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~',
192 255, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 255,255,
193 255, ' ', 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255,255,
194 255, 255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
195 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
196 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
197 255,255,255,255,255,255,255,255 };
199 // used to limit the keypresses that are accepted from the keyboard
200 #define MAX_FILTER_KEYS 64
202 int Key_filter[MAX_FILTER_KEYS];
204 static int Key_numlock_was_on = 0; // Flag to indicate whether NumLock is on at start
205 static int Key_running_NT = 0; // NT is the OS
207 int Cheats_enabled = 0;
208 int Key_normal_game = 0;
210 int key_numlock_is_on()
214 SDL_GetKeyState(keys);
215 if ( keys[SDLK_NUMLOCK] ) {
219 unsigned char keys[256];
220 GetKeyboardState(keys);
221 if ( keys[VK_NUMLOCK] ) {
228 void key_turn_off_numlock()
233 unsigned char keys[256];
234 GetKeyboardState(keys);
235 keys[VK_NUMLOCK] = 0;
236 SetKeyboardState(keys);
240 void key_turn_on_numlock()
245 unsigned char keys[256];
246 GetKeyboardState(keys);
247 keys[VK_NUMLOCK] = 1;
248 SetKeyboardState(keys);
252 // Convert a BIOS scancode to ASCII.
253 // If scancode >= 127, returns 255, meaning there is no corresponding ASCII code.
254 // Uses ascii_table and shifted_ascii_table to translate scancode to ASCII.
255 int key_to_ascii(int keycode )
259 if ( !key_inited ) return 255;
261 shifted = keycode & KEY_SHIFTED;
269 return toupper (keycode);
274 return shifted_ascii_table[keycode];
276 return ascii_table[keycode];
280 // Flush the keyboard buffer.
281 // Clear the keyboard array (keyd_pressed).
287 if ( !key_inited ) return;
289 ENTER_CRITICAL_SECTION(&key_lock);
291 key_data.keyhead = key_data.keytail = 0;
293 //Clear the keyboard buffer
294 for (i=0; i<KEY_BUFFER_SIZE; i++ ) {
295 key_data.keybuffer[i] = 0;
296 key_data.time_pressed[i] = 0;
299 //Clear the keyboard array
301 CurTime = timer_get_milliseconds();
304 for (i=0; i<NUM_KEYS; i++ ) {
306 key_data.TimeKeyDownChecked[i] = CurTime;
307 key_data.TimeKeyWentDown[i] = CurTime;
308 key_data.TimeKeyHeldDown[i] = 0;
309 key_data.NumDowns[i]=0;
310 key_data.NumUps[i]=0;
313 LEAVE_CRITICAL_SECTION(&key_lock);
316 // A nifty function which performs the function:
317 // n = (n+1) % KEY_BUFFER_SIZE
318 // (assuming positive values of n).
322 if ( n >= KEY_BUFFER_SIZE ) n=0;
326 // Returns 1 if character waiting... 0 otherwise
329 int is_one_waiting = 0;
331 if ( !key_inited ) return 0;
333 ENTER_CRITICAL_SECTION(&key_lock);
335 if (key_data.keytail != key_data.keyhead){
339 LEAVE_CRITICAL_SECTION(&key_lock);
341 return is_one_waiting;
344 // Return key scancode if a key has been pressed,
346 // Reads keys out of the key buffer and updates keyhead.
351 if ( !key_inited ) return 0;
353 ENTER_CRITICAL_SECTION(&key_lock);
355 if (key_data.keytail!=key_data.keyhead) {
356 key = key_data.keybuffer[key_data.keyhead];
357 key_data.keyhead = add_one(key_data.keyhead);
360 LEAVE_CRITICAL_SECTION(&key_lock);
365 // Unget a key. Puts it back in the input queue.
366 void key_outkey(int key)
370 if ( !key_inited ) return;
372 ENTER_CRITICAL_SECTION(&key_lock);
374 bufp = key_data.keytail+1;
376 if (bufp >= KEY_BUFFER_SIZE){
380 key_data.keybuffer[key_data.keytail] = (unsigned short)key;
382 key_data.keytail = bufp;
384 LEAVE_CRITICAL_SECTION(&key_lock);
389 // Return amount of time last key was held down.
390 // This is currently (July 17, 1996) bogus because our timing is
392 int key_inkey_time(uint * time)
401 ENTER_CRITICAL_SECTION(&key_lock);
403 if (key_data.keytail!=key_data.keyhead) {
404 key = key_data.keybuffer[key_data.keyhead];
405 *time = key_data.time_pressed[key_data.keyhead];
406 key_data.keyhead = add_one(key_data.keyhead);
409 LEAVE_CRITICAL_SECTION(&key_lock);
415 // Returns scancode of last key pressed, if any (returns 0 if no key pressed)
416 // but does not update keyhead pointer.
421 if ( !key_inited ) return 0;
423 ENTER_CRITICAL_SECTION(&key_lock);
425 if (key_data.keytail!=key_data.keyhead) {
426 key = key_data.keybuffer[key_data.keyhead];
428 LEAVE_CRITICAL_SECTION(&key_lock);
433 // If not installed, uses BIOS and returns getch();
434 // Else returns pending key (or waits for one if none waiting).
440 if ( !key_inited ) return 0;
442 while (!key_checkch()){
452 // Set global shift_status with modifier results (shift, ctrl, alt).
453 uint key_get_shift_status()
455 unsigned int shift_status = 0;
457 if ( !key_inited ) return 0;
459 ENTER_CRITICAL_SECTION(&key_lock);
461 if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] )
462 shift_status |= KEY_SHIFTED;
464 if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] )
465 shift_status |= KEY_ALTED;
467 if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] )
468 shift_status |= KEY_CTRLED;
471 if (keyd_pressed[KEY_DEBUG_KEY])
472 shift_status |= KEY_DEBUGGED;
474 if (keyd_pressed[KEY_DEBUG_KEY]) {
475 mprintf(("Cheats_enabled = %i, Key_normal_game = %i\n", Cheats_enabled, Key_normal_game));
476 if ((Cheats_enabled) && Key_normal_game) {
477 mprintf(("Debug key\n"));
478 shift_status |= KEY_DEBUGGED1;
482 LEAVE_CRITICAL_SECTION(&key_lock);
487 // Returns amount of time key (specified by "code") has been down since last call.
488 // Returns float, unlike key_down_time() which returns a fix.
489 float key_down_timef(uint scancode)
491 uint time_down, time;
494 if ( !key_inited ) return 0.0f;
497 scancode &= KEY_MASK;
500 if ((scancode<0)|| (scancode>=NUM_KEYS)) return 0.0f;
502 ENTER_CRITICAL_SECTION(&key_lock);
504 time = timer_get_milliseconds();
505 delta_time = time - key_data.TimeKeyDownChecked[scancode];
506 key_data.TimeKeyDownChecked[scancode] = time;
508 if ( delta_time <= 1 ) {
509 key_data.TimeKeyWentDown[scancode] = time;
510 if (keyd_pressed[scancode]) {
511 LEAVE_CRITICAL_SECTION(&key_lock);
514 LEAVE_CRITICAL_SECTION(&key_lock);
519 if ( !keyd_pressed[scancode] ) {
520 time_down = key_data.TimeKeyHeldDown[scancode];
521 key_data.TimeKeyHeldDown[scancode] = 0;
523 time_down = time - key_data.TimeKeyWentDown[scancode];
524 key_data.TimeKeyWentDown[scancode] = time;
527 LEAVE_CRITICAL_SECTION(&key_lock);
529 return i2fl(time_down) / i2fl(delta_time);
533 // Returns amount of time key (specified by "code") has been down since last call.
534 // Returns float, unlike key_down_time() which returns a fix.
535 fix key_down_time( uint code )
537 uint time_down, time;
540 if ( !key_inited ) return 0.0f;
542 if ((scancode<0)|| (scancode>=NUM_KEYS)) return 0.0f;
544 EnterCriticalSection( &key_lock );
546 time = timer_get_milliseconds();
547 delta_time = time - TimeKeyDownChecked[scancode];
548 TimeKeyDownChecked[scancode] = time;
550 if ( delta_time <= 1 ) {
551 LeaveCriticalSection( &key_lock );
552 if (keyd_pressed[scancode])
558 if ( !keyd_pressed[scancode] ) {
559 time_down = key_data.TimeKeyHeldDown[scancode];
560 key_data.TimeKeyHeldDown[scancode] = 0;
562 time_down = time - key_data.TimeKeyWentDown[scancode];
563 key_data.TimeKeyWentDown[scancode] = time;
566 LeaveCriticalSection( &key_lock );
568 return fixmuldiv( time_down, F1_0, delta_time );
573 // Returns number of times key has went from up to down since last call.
574 int key_down_count(int scancode)
578 if ( !key_inited ) return 0;
581 scancode &= KEY_MASK;
583 if ((scancode<0)|| (scancode>=NUM_KEYS)) return 0;
585 ENTER_CRITICAL_SECTION(&key_lock);
587 n = key_data.NumDowns[scancode];
588 key_data.NumDowns[scancode] = 0;
590 LEAVE_CRITICAL_SECTION(&key_lock);
596 // Returns number of times key has went from down to up since last call.
597 int key_up_count(int scancode)
601 if ( !key_inited ) return 0;
603 scancode &= KEY_MASK;
605 if ((scancode<0)|| (scancode>=NUM_KEYS)) return 0;
607 ENTER_CRITICAL_SECTION(&key_lock);
609 n = key_data.NumUps[scancode];
610 key_data.NumUps[scancode] = 0;
612 LEAVE_CRITICAL_SECTION(&key_lock);
617 int key_check(int key)
619 return key_data.down_check[key];
622 // Add a key up or down code to the key buffer. state=1 -> down, state=0 -> up
623 // latency => time difference in ms between when key was actually pressed and now
624 //void key_mark( uint code, int state )
625 void key_mark( uint code, int state, uint latency )
627 uint scancode, breakbit, temp, event_time;
630 if ( !key_inited ) return;
632 ENTER_CRITICAL_SECTION(&key_lock);
637 // If running in the UK, need to translate their wacky slash scancode to ours
638 if ( code == KEY_SLASH_UK ) {
685 if ( (code == 0xc5) && !Key_running_NT ) {
686 key_turn_off_numlock();
689 Assert( code < NUM_KEYS );
691 event_time = timer_get_milliseconds() - latency;
692 // event_time = timeGetTime() - latency;
696 scancode = code & (NUM_KEYS-1);
704 keyd_last_released = scancode;
705 keyd_pressed[scancode] = 0;
706 key_data.NumUps[scancode]++;
708 // What is the point of this code? "temp" is never used!
710 temp |= keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT];
711 temp |= keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT];
712 temp |= keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL];
714 temp |= keyd_pressed[KEY_DEBUG_KEY];
716 if (event_time < key_data.TimeKeyWentDown[scancode])
717 key_data.TimeKeyHeldDown[scancode] = 0;
719 key_data.TimeKeyHeldDown[scancode] += event_time - key_data.TimeKeyWentDown[scancode];
722 keyd_last_pressed = scancode;
723 keyd_time_when_last_pressed = event_time;
724 if (!keyd_pressed[scancode]) {
726 key_data.TimeKeyWentDown[scancode] = event_time;
727 keyd_pressed[scancode] = 1;
728 key_data.NumDowns[scancode]++;
729 key_data.down_check[scancode]++;
731 // mprintf(( "Scancode = %x\n", scancode ));
733 // if ( scancode == KEY_BREAK )
737 } else if (!keyd_repeat) {
738 // Don't buffer repeating key if repeat mode is off
742 if ( scancode!=0xAA ) {
743 keycode = (unsigned short)scancode;
745 if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] )
746 keycode |= KEY_SHIFTED;
748 if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] )
749 keycode |= KEY_ALTED;
751 if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] )
752 keycode |= KEY_CTRLED;
755 if ( keyd_pressed[KEY_DEBUG_KEY] )
756 keycode |= KEY_DEBUGGED;
757 // if ( keycode == (KEY_BACKSP + KEY_DEBUGGED) ) {
759 // keyd_pressed[KEY_DEBUG_KEY] = 0;
760 // keyd_pressed[KEY_BACKSP] = 0;
764 if ( keyd_pressed[KEY_DEBUG_KEY] ) {
765 mprintf(("Cheats_enabled = %i, Key_normal_game = %i\n", Cheats_enabled, Key_normal_game));
766 if (Cheats_enabled && Key_normal_game) {
767 keycode |= KEY_DEBUGGED1;
774 temp = key_data.keytail+1;
775 if ( temp >= KEY_BUFFER_SIZE ) temp=0;
777 if (temp!=key_data.keyhead) {
778 int i, accept_key = 1;
779 // Num_filter_keys will only be non-zero when a key filter has
780 // been explicity set up via key_set_filter()
781 for ( i = 0; i < Num_filter_keys; i++ ) {
783 if ( Key_filter[i] == keycode ) {
790 key_data.keybuffer[key_data.keytail] = keycode;
791 key_data.time_pressed[key_data.keytail] = keyd_time_when_last_pressed;
792 key_data.keytail = temp;
799 LEAVE_CRITICAL_SECTION(&key_lock);
802 #ifdef USE_DIRECTINPUT
810 if ( !key_inited ) return;
812 #ifdef USE_DIRECTINPUT
816 if ( Key_numlock_was_on ) {
817 key_turn_on_numlock();
818 Key_numlock_was_on = 0;
825 DeleteCriticalSection( &key_lock );
832 if ( key_inited ) return;
838 InitializeCriticalSection( &key_lock );
840 ENTER_CRITICAL_SECTION(&key_lock);
843 keyd_time_when_last_pressed = timer_get_milliseconds();
844 keyd_buffer_type = 1;
847 // Clear the keyboard array
856 LEAVE_CRITICAL_SECTION(&key_lock);
858 #ifdef USE_DIRECTINPUT
863 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
865 if ( ver.dwPlatformId == VER_PLATFORM_WIN32_NT ) {
869 if ( key_numlock_is_on() ) {
870 Key_numlock_was_on = 1;
871 key_turn_off_numlock();
879 void key_level_init()
883 for (i=0; i<NUM_KEYS; i++)
884 key_data.down_check[i] = 0;
887 void key_lost_focus()
889 if ( !key_inited ) return;
896 if ( !key_inited ) return;
901 // Restricts the keys that are accepted from the keyboard
903 // filter_array => array of keys to act as a filter
904 // num => number of keys in filter_array
906 void key_set_filter(int *filter_array, int num)
910 if ( num >= MAX_FILTER_KEYS ) {
912 num = MAX_FILTER_KEYS;
915 Num_filter_keys = num;
917 for ( i = 0; i < num; i++ ) {
918 Key_filter[i] = filter_array[i];
922 // Clear the key filter, so all keypresses are accepted from keyboard
924 void key_clear_filter()
929 for ( i = 0; i < MAX_FILTER_KEYS; i++ ) {
935 #ifdef USE_DIRECTINPUT
937 // JAS - April 18, 1998
938 // Not using because DI has the following problems: (Everything else works ok)
939 // Under NT, Pause and Numlock report as identical keys.
940 // Under 95, Pause is the same as pressing Ctrl then Numlock. So the game fires each
944 //============================================================================
946 // For the keyboard, this basically replaces our old functionallity of:
951 //============================================================================
956 #define MAX_BUFFERED_KEYBOARD_EVENTS 10
958 static LPDIRECTINPUT Di_object = NULL;
959 static LPDIRECTINPUTDEVICE Di_keyboard = NULL;
960 static HANDLE Di_thread = NULL;
961 static DWORD Di_thread_id = NULL;
962 static HANDLE Di_event = NULL;
964 DWORD di_process(DWORD lparam)
967 if ( WaitForSingleObject( Di_event, INFINITE )==WAIT_OBJECT_0 ) {
969 //mprintf(( "Got event!\n" ));
973 DIDEVICEOBJECTDATA rgdod[10];
974 DWORD dwItems = MAX_BUFFERED_KEYBOARD_EVENTS;
977 hr = Di_keyboard->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), rgdod, &dwItems, 0);
979 if (hr == DIERR_INPUTLOST) {
981 * DirectInput is telling us that the input stream has
982 * been interrupted. We aren't tracking any state
983 * between polls, so we don't have any special reset
984 * that needs to be done. We just re-acquire and
987 Sleep(1000); // Pause a second...
988 hr = Di_keyboard->Acquire();
995 // dwItems = number of elements read (could be zero)
996 if (hr == DI_BUFFEROVERFLOW) {
997 // Buffer had overflowed.
998 mprintf(( "Buffer overflowed!\n" ));
1002 //mprintf(( "Got %d events\n", dwItems ));
1004 for (i=0; i<(int)dwItems; i++ ) {
1005 int key = rgdod[i].dwOfs;
1006 int state = rgdod[i].dwData;
1007 int stamp = rgdod[i].dwTimeStamp;
1010 latency = timeGetTime() - stamp;
1014 // if ( key == KEY_PRINT_SCRN ) {
1015 // key_mark( key, 1, latency );
1017 // key_mark( key, (state&0x80?1:0), latency );
1018 mprintf(( "Key=%x, State=%x, Time=%d, Latency=%d\n", key, state, stamp, latency ));
1038 * Register with the DirectInput subsystem and get a pointer
1039 * to a IDirectInput interface we can use.
1045 * Instance handle to our application or DLL.
1047 * DIRECTINPUT_VERSION
1049 * The version of DirectInput we were designed for.
1050 * We take the value from the <dinput.h> header file.
1054 * Receives pointer to the IDirectInput interface
1059 * We do not use OLE aggregation, so this parameter
1063 hr = DirectInputCreate(GetModuleHandle(NULL), 0x300, &Di_object, NULL);
1066 mprintf(( "DirectInputCreate failed!\n" ));
1071 * Obtain an interface to the system keyboard device.
1077 * The instance GUID for the device we wish to access.
1078 * GUID_SysKeyboard is a predefined instance GUID that
1079 * always refers to the system keyboard device.
1083 * Receives pointer to the IDirectInputDevice interface
1088 * We do not use OLE aggregation, so this parameter
1092 hr = Di_object->CreateDevice(GUID_SysKeyboard, &Di_keyboard, NULL);
1095 mprintf(( "CreateDevice failed!\n" ));
1100 * Set the data format to "keyboard format".
1102 * A data format specifies which controls on a device we
1103 * are interested in, and how they should be reported.
1105 * This tells DirectInput that we will be passing an array
1106 * of 256 bytes to IDirectInputDevice::GetDeviceState.
1112 * Predefined data format which describes
1113 * an array of 256 bytes, one per scancode.
1115 hr = Di_keyboard->SetDataFormat(&c_dfDIKeyboard);
1118 mprintf(( "SetDataFormat failed!\n" ));
1124 * Set the cooperativity level to let DirectInput know how
1125 * this device should interact with the system and with other
1126 * DirectInput applications.
1130 * DISCL_NONEXCLUSIVE
1132 * Retrieve keyboard data when acquired, not interfering
1133 * with any other applications which are reading keyboard
1138 * If the user switches away from our application,
1139 * automatically release the keyboard back to the system.
1142 hr = Di_keyboard->SetCooperativeLevel((HWND)os_get_window(), DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
1145 mprintf(( "SetCooperativeLevel failed!\n" ));
1151 // Turn on buffering
1152 hdr.diph.dwSize = sizeof(DIPROPDWORD);
1153 hdr.diph.dwHeaderSize = sizeof(DIPROPHEADER);
1155 hdr.diph.dwHow = DIPH_DEVICE; // Apply to entire device
1156 hdr.dwData = 16; //MAX_BUFFERED_KEYBOARD_EVENTS;
1158 hr = Di_keyboard->SetProperty( DIPROP_BUFFERSIZE, &hdr.diph );
1160 mprintf(( "SetProperty DIPROP_BUFFERSIZE failed\n" ));
1165 Di_event = CreateEvent( NULL, FALSE, FALSE, NULL );
1166 Assert(Di_event != NULL);
1168 Di_thread = CreateThread(NULL, 1024, (LPTHREAD_START_ROUTINE)di_process, NULL, 0, &Di_thread_id);
1169 Assert( Di_thread != NULL );
1171 SetThreadPriority(Di_thread, THREAD_PRIORITY_HIGHEST);
1173 hr = Di_keyboard->SetEventNotification(Di_event);
1175 mprintf(( "SetEventNotification failed\n" ));
1179 Di_keyboard->Acquire();
1187 * Destroy any lingering IDirectInputDevice object.
1192 * Cleanliness is next to godliness. Unacquire the device
1193 * one last time just in case we got really confused and tried
1194 * to exit while the device is still acquired.
1196 Di_keyboard->Unacquire();
1198 Di_keyboard->Release();
1203 * Destroy any lingering IDirectInput object.
1206 Di_object->Release();
1211 CloseHandle(Di_event);