mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-09 13:01:29 -10:00
git-svn-id: svn://svn.icculus.org/fs2open/trunk/fs2_open@10166 387891d4-d844-0410-90c0-e4c51a9137d3
1218 lines
28 KiB
C++
1218 lines
28 KiB
C++
/*
|
|
* Copyright (C) Volition, Inc. 1999. All rights reserved.
|
|
*
|
|
* All source code herein is the property of Volition, Inc. You may not sell
|
|
* or otherwise commercially exploit the source or things you created based on the
|
|
* source.
|
|
*
|
|
*/
|
|
|
|
|
|
|
|
//#define USE_DIRECTINPUT
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#else
|
|
#include "SDL.h"
|
|
#endif
|
|
|
|
#include "controlconfig/controlsconfig.h" //For textify scancode
|
|
#include "globalincs/pstypes.h"
|
|
#include "graphics/2d.h"
|
|
#include "io/key.h"
|
|
#include "math/fix.h"
|
|
#include "io/timer.h"
|
|
#include "localization/localize.h"
|
|
#include "parse/scripting.h"
|
|
#include "cmdline/cmdline.h"
|
|
|
|
#define THREADED // to use the proper set of macros
|
|
#include "osapi/osapi.h"
|
|
|
|
|
|
#define KEY_BUFFER_SIZE 16
|
|
|
|
//-------- Variable accessed by outside functions ---------
|
|
ubyte keyd_buffer_type; // 0=No buffer, 1=buffer ASCII, 2=buffer scans
|
|
ubyte keyd_repeat;
|
|
uint keyd_last_pressed;
|
|
uint keyd_last_released;
|
|
ubyte keyd_pressed[NUM_KEYS];
|
|
int keyd_time_when_last_pressed;
|
|
|
|
typedef struct keyboard {
|
|
ushort keybuffer[KEY_BUFFER_SIZE];
|
|
uint time_pressed[KEY_BUFFER_SIZE];
|
|
uint TimeKeyWentDown[NUM_KEYS];
|
|
uint TimeKeyHeldDown[NUM_KEYS];
|
|
uint TimeKeyDownChecked[NUM_KEYS];
|
|
uint NumDowns[NUM_KEYS];
|
|
uint NumUps[NUM_KEYS];
|
|
int down_check[NUM_KEYS]; // nonzero if has been pressed yet this mission
|
|
uint keyhead, keytail;
|
|
} keyboard;
|
|
|
|
keyboard key_data;
|
|
|
|
int key_inited = 0;
|
|
|
|
CRITICAL_SECTION key_lock;
|
|
|
|
//int Backspace_debug=1; // global flag that will enable/disable the backspace key from stopping execution
|
|
// This flag was created since the backspace key is also used to correct mistakes
|
|
// when typing in your pilots callsign. This global flag is checked before execution
|
|
// is stopped.
|
|
|
|
#ifdef SCP_UNIX
|
|
int SDLtoFS2[SDLK_LAST];
|
|
#endif
|
|
|
|
int ascii_table[128] =
|
|
{ 255, 255, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=',255,255,
|
|
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 255, 255,
|
|
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 39, '`',
|
|
255, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 255,'*',
|
|
255, ' ', 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255,255,
|
|
255, 255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
|
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
|
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
|
255,255,255,255,255,255,255,255 };
|
|
|
|
int shifted_ascii_table[128] =
|
|
{ 255, 255, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+',255,255,
|
|
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 255, 255,
|
|
'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~',
|
|
255, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 255,255,
|
|
255, ' ', 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255,255,
|
|
255, 255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
|
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
|
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
|
255,255,255,255,255,255,255,255 };
|
|
|
|
static int Key_numlock_was_on = 0; // Flag to indicate whether NumLock is on at start
|
|
|
|
#ifdef _WIN32
|
|
static int Key_running_NT = 0; // NT is the OS
|
|
#endif
|
|
|
|
int Cheats_enabled = 0;
|
|
int Key_normal_game = 0;
|
|
|
|
#ifdef SCP_UNIX
|
|
/**
|
|
* Keyboard layouts
|
|
*/
|
|
enum KeyboardLayout {
|
|
KEYBOARD_LAYOUT_DEFAULT, //!< American
|
|
KEYBOARD_LAYOUT_QWERTZ, //!< German
|
|
KEYBOARD_LAYOUT_AZERTY //!< French
|
|
};
|
|
|
|
void FillSDLArray ()
|
|
{
|
|
KeyboardLayout layout = KEYBOARD_LAYOUT_DEFAULT;
|
|
|
|
if (Cmdline_keyboard_layout) {
|
|
if (!strcmp(Cmdline_keyboard_layout, "qwertz")) {
|
|
layout = KEYBOARD_LAYOUT_QWERTZ;
|
|
}
|
|
|
|
if (!strcmp(Cmdline_keyboard_layout, "azerty")) {
|
|
layout = KEYBOARD_LAYOUT_AZERTY;
|
|
}
|
|
|
|
}
|
|
|
|
if(layout == KEYBOARD_LAYOUT_AZERTY) {
|
|
SDLtoFS2[SDLK_WORLD_64] = KEY_0;
|
|
SDLtoFS2[SDLK_AMPERSAND] = KEY_1;
|
|
SDLtoFS2[SDLK_WORLD_73] = KEY_2;
|
|
SDLtoFS2[SDLK_QUOTEDBL] = KEY_3;
|
|
SDLtoFS2[SDLK_QUOTE] = KEY_4;
|
|
SDLtoFS2[SDLK_LEFTPAREN] = KEY_5;
|
|
SDLtoFS2[SDLK_MINUS] = KEY_6;
|
|
SDLtoFS2[SDLK_WORLD_72] = KEY_7;
|
|
SDLtoFS2[SDLK_UNDERSCORE] = KEY_8;
|
|
SDLtoFS2[SDLK_WORLD_71] = KEY_9;
|
|
} else {
|
|
SDLtoFS2[SDLK_0] = KEY_0;
|
|
SDLtoFS2[SDLK_1] = KEY_1;
|
|
SDLtoFS2[SDLK_2] = KEY_2;
|
|
SDLtoFS2[SDLK_3] = KEY_3;
|
|
SDLtoFS2[SDLK_4] = KEY_4;
|
|
SDLtoFS2[SDLK_5] = KEY_5;
|
|
SDLtoFS2[SDLK_6] = KEY_6;
|
|
SDLtoFS2[SDLK_7] = KEY_7;
|
|
SDLtoFS2[SDLK_8] = KEY_8;
|
|
SDLtoFS2[SDLK_9] = KEY_9;
|
|
}
|
|
|
|
SDLtoFS2[SDLK_a] = KEY_A;
|
|
SDLtoFS2[SDLK_b] = KEY_B;
|
|
SDLtoFS2[SDLK_c] = KEY_C;
|
|
SDLtoFS2[SDLK_d] = KEY_D;
|
|
SDLtoFS2[SDLK_e] = KEY_E;
|
|
SDLtoFS2[SDLK_f] = KEY_F;
|
|
SDLtoFS2[SDLK_g] = KEY_G;
|
|
SDLtoFS2[SDLK_h] = KEY_H;
|
|
SDLtoFS2[SDLK_i] = KEY_I;
|
|
SDLtoFS2[SDLK_j] = KEY_J;
|
|
SDLtoFS2[SDLK_k] = KEY_K;
|
|
SDLtoFS2[SDLK_l] = KEY_L;
|
|
SDLtoFS2[SDLK_m] = KEY_M;
|
|
SDLtoFS2[SDLK_n] = KEY_N;
|
|
SDLtoFS2[SDLK_o] = KEY_O;
|
|
SDLtoFS2[SDLK_p] = KEY_P;
|
|
SDLtoFS2[SDLK_q] = KEY_Q;
|
|
SDLtoFS2[SDLK_r] = KEY_R;
|
|
SDLtoFS2[SDLK_s] = KEY_S;
|
|
SDLtoFS2[SDLK_t] = KEY_T;
|
|
SDLtoFS2[SDLK_u] = KEY_U;
|
|
SDLtoFS2[SDLK_v] = KEY_V;
|
|
SDLtoFS2[SDLK_w] = KEY_W;
|
|
SDLtoFS2[SDLK_x] = KEY_X;
|
|
SDLtoFS2[SDLK_y] = KEY_Y;
|
|
SDLtoFS2[SDLK_z] = KEY_Z;
|
|
|
|
if(layout == KEYBOARD_LAYOUT_DEFAULT) {
|
|
SDLtoFS2[SDLK_MINUS] = KEY_MINUS;
|
|
SDLtoFS2[SDLK_EQUALS] = KEY_EQUAL;
|
|
SDLtoFS2[SDLK_SLASH] = KEY_DIVIDE; // No idea - DDOI
|
|
SDLtoFS2[SDLK_BACKSLASH] = KEY_SLASH;
|
|
//SDLtoFS2[SDLK_BACKSLASH] = KEY_SLASH_UK; // ?
|
|
SDLtoFS2[SDLK_COMMA] = KEY_COMMA;
|
|
SDLtoFS2[SDLK_PERIOD] = KEY_PERIOD;
|
|
SDLtoFS2[SDLK_SEMICOLON] = KEY_SEMICOL;
|
|
|
|
SDLtoFS2[SDLK_LEFTBRACKET] = KEY_LBRACKET;
|
|
SDLtoFS2[SDLK_RIGHTBRACKET] = KEY_RBRACKET;
|
|
|
|
SDLtoFS2[SDLK_BACKQUOTE] = KEY_LAPOSTRO;
|
|
SDLtoFS2[SDLK_QUOTE] = KEY_RAPOSTRO;
|
|
}
|
|
|
|
if(layout == KEYBOARD_LAYOUT_QWERTZ) {
|
|
SDLtoFS2[SDLK_WORLD_63] = KEY_MINUS;
|
|
SDLtoFS2[SDLK_WORLD_20] = KEY_EQUAL;
|
|
SDLtoFS2[SDLK_MINUS] = KEY_DIVIDE;
|
|
SDLtoFS2[SDLK_HASH] = KEY_SLASH;
|
|
SDLtoFS2[SDLK_COMMA] = KEY_COMMA;
|
|
SDLtoFS2[SDLK_PERIOD] = KEY_PERIOD;
|
|
SDLtoFS2[SDLK_WORLD_86] = KEY_SEMICOL;
|
|
|
|
SDLtoFS2[SDLK_WORLD_92] = KEY_LBRACKET;
|
|
SDLtoFS2[SDLK_PLUS] = KEY_RBRACKET;
|
|
|
|
SDLtoFS2[SDLK_CARET] = KEY_LAPOSTRO;
|
|
SDLtoFS2[SDLK_WORLD_68] = KEY_RAPOSTRO;
|
|
}
|
|
|
|
if(layout == KEYBOARD_LAYOUT_AZERTY) {
|
|
SDLtoFS2[SDLK_RIGHTPAREN] = KEY_MINUS;
|
|
SDLtoFS2[SDLK_EQUALS] = KEY_EQUAL;
|
|
SDLtoFS2[SDLK_EXCLAIM] = KEY_DIVIDE;
|
|
SDLtoFS2[SDLK_ASTERISK] = KEY_SLASH;
|
|
SDLtoFS2[SDLK_COMMA] = KEY_COMMA;
|
|
SDLtoFS2[SDLK_COLON] = KEY_PERIOD;
|
|
SDLtoFS2[SDLK_SEMICOLON] = KEY_SEMICOL;
|
|
|
|
SDLtoFS2[SDLK_CARET] = KEY_LBRACKET;
|
|
SDLtoFS2[SDLK_DOLLAR] = KEY_RBRACKET;
|
|
|
|
SDLtoFS2[SDLK_WORLD_18] = KEY_LAPOSTRO;
|
|
SDLtoFS2[SDLK_WORLD_89] = KEY_RAPOSTRO;
|
|
}
|
|
|
|
SDLtoFS2[SDLK_ESCAPE] = KEY_ESC;
|
|
SDLtoFS2[SDLK_RETURN] = KEY_ENTER;
|
|
SDLtoFS2[SDLK_BACKSPACE] = KEY_BACKSP;
|
|
SDLtoFS2[SDLK_TAB] = KEY_TAB;
|
|
SDLtoFS2[SDLK_SPACE] = KEY_SPACEBAR;
|
|
|
|
SDLtoFS2[SDLK_NUMLOCK] = KEY_NUMLOCK;
|
|
SDLtoFS2[SDLK_SCROLLOCK] = KEY_SCROLLOCK;
|
|
SDLtoFS2[SDLK_CAPSLOCK] = KEY_CAPSLOCK;
|
|
|
|
SDLtoFS2[SDLK_LSHIFT] = KEY_LSHIFT;
|
|
SDLtoFS2[SDLK_RSHIFT] = KEY_RSHIFT;
|
|
|
|
SDLtoFS2[SDLK_LALT] = KEY_LALT;
|
|
SDLtoFS2[SDLK_RALT] = KEY_RALT;
|
|
|
|
SDLtoFS2[SDLK_LCTRL] = KEY_LCTRL;
|
|
SDLtoFS2[SDLK_RCTRL] = KEY_RCTRL;
|
|
|
|
SDLtoFS2[SDLK_F1] = KEY_F1;
|
|
SDLtoFS2[SDLK_F2] = KEY_F2;
|
|
SDLtoFS2[SDLK_F3] = KEY_F3;
|
|
SDLtoFS2[SDLK_F4] = KEY_F4;
|
|
SDLtoFS2[SDLK_F5] = KEY_F5;
|
|
SDLtoFS2[SDLK_F6] = KEY_F6;
|
|
SDLtoFS2[SDLK_F7] = KEY_F7;
|
|
SDLtoFS2[SDLK_F8] = KEY_F8;
|
|
SDLtoFS2[SDLK_F9] = KEY_F9;
|
|
SDLtoFS2[SDLK_F10] = KEY_F10;
|
|
SDLtoFS2[SDLK_F11] = KEY_F11;
|
|
SDLtoFS2[SDLK_F12] = KEY_F12;
|
|
|
|
SDLtoFS2[SDLK_KP0] = KEY_PAD0;
|
|
SDLtoFS2[SDLK_KP1] = KEY_PAD1;
|
|
SDLtoFS2[SDLK_KP2] = KEY_PAD2;
|
|
SDLtoFS2[SDLK_KP3] = KEY_PAD3;
|
|
SDLtoFS2[SDLK_KP4] = KEY_PAD4;
|
|
SDLtoFS2[SDLK_KP5] = KEY_PAD5;
|
|
SDLtoFS2[SDLK_KP6] = KEY_PAD6;
|
|
SDLtoFS2[SDLK_KP7] = KEY_PAD7;
|
|
SDLtoFS2[SDLK_KP8] = KEY_PAD8;
|
|
SDLtoFS2[SDLK_KP9] = KEY_PAD9;
|
|
SDLtoFS2[SDLK_KP_MINUS] = KEY_PADMINUS;
|
|
SDLtoFS2[SDLK_KP_PLUS] = KEY_PADPLUS;
|
|
SDLtoFS2[SDLK_KP_PERIOD] = KEY_PADPERIOD;
|
|
SDLtoFS2[SDLK_KP_DIVIDE] = KEY_PADDIVIDE;
|
|
SDLtoFS2[SDLK_KP_MULTIPLY] = KEY_PADMULTIPLY;
|
|
SDLtoFS2[SDLK_KP_ENTER] = KEY_PADENTER;
|
|
|
|
SDLtoFS2[SDLK_INSERT] = KEY_INSERT;
|
|
SDLtoFS2[SDLK_HOME] = KEY_HOME;
|
|
SDLtoFS2[SDLK_PAGEUP] = KEY_PAGEUP;
|
|
SDLtoFS2[SDLK_DELETE] = KEY_DELETE;
|
|
SDLtoFS2[SDLK_END] = KEY_END;
|
|
SDLtoFS2[SDLK_PAGEDOWN] = KEY_PAGEDOWN;
|
|
SDLtoFS2[SDLK_UP] = KEY_UP;
|
|
SDLtoFS2[SDLK_DOWN] = KEY_DOWN;
|
|
SDLtoFS2[SDLK_LEFT] = KEY_LEFT;
|
|
SDLtoFS2[SDLK_RIGHT] = KEY_RIGHT;
|
|
|
|
SDLtoFS2[SDLK_PRINT] = KEY_PRINT_SCRN;
|
|
SDLtoFS2[SDLK_PAUSE] = KEY_PAUSE;
|
|
SDLtoFS2[SDLK_BREAK] = KEY_BREAK;
|
|
}
|
|
#endif
|
|
|
|
int key_numlock_is_on()
|
|
{
|
|
#ifdef _WIN32
|
|
unsigned char keys[256];
|
|
GetKeyboardState(keys);
|
|
if ( keys[VK_NUMLOCK] ) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
#else
|
|
int keys[SDLK_LAST];
|
|
SDL_GetKeyState(keys);
|
|
if ( keys[SDLK_NUMLOCK] ) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
void key_turn_off_numlock()
|
|
{
|
|
#ifdef _WIN32
|
|
unsigned char keys[256];
|
|
GetKeyboardState(keys);
|
|
keys[VK_NUMLOCK] = 0;
|
|
SetKeyboardState(keys);
|
|
#endif
|
|
}
|
|
|
|
void key_turn_on_numlock()
|
|
{
|
|
#ifdef _WIN32
|
|
unsigned char keys[256];
|
|
GetKeyboardState(keys);
|
|
keys[VK_NUMLOCK] = 1;
|
|
SetKeyboardState(keys);
|
|
#endif
|
|
}
|
|
|
|
// Convert a BIOS scancode to ASCII.
|
|
// If scancode >= 127, returns 255, meaning there is no corresponding ASCII code.
|
|
// Uses ascii_table and shifted_ascii_table to translate scancode to ASCII.
|
|
int key_to_ascii(int keycode )
|
|
{
|
|
int shifted;
|
|
|
|
if ( !key_inited ) return 255;
|
|
|
|
shifted = keycode & KEY_SHIFTED;
|
|
keycode &= 0xFF;
|
|
|
|
if ( keycode>=127 )
|
|
return 255;
|
|
|
|
if (shifted)
|
|
return shifted_ascii_table[keycode];
|
|
else
|
|
return ascii_table[keycode];
|
|
}
|
|
|
|
// Flush the keyboard buffer.
|
|
// Clear the keyboard array (keyd_pressed).
|
|
void key_flush()
|
|
{
|
|
int i;
|
|
uint CurTime;
|
|
|
|
if ( !key_inited ) return;
|
|
|
|
ENTER_CRITICAL_SECTION( key_lock );
|
|
|
|
key_data.keyhead = key_data.keytail = 0;
|
|
|
|
//Clear the keyboard buffer
|
|
for (i=0; i<KEY_BUFFER_SIZE; i++ ) {
|
|
key_data.keybuffer[i] = 0;
|
|
key_data.time_pressed[i] = 0;
|
|
}
|
|
|
|
//Clear the keyboard array
|
|
|
|
CurTime = timer_get_milliseconds();
|
|
|
|
|
|
for (i=0; i<NUM_KEYS; i++ ) {
|
|
keyd_pressed[i] = 0;
|
|
key_data.TimeKeyDownChecked[i] = CurTime;
|
|
key_data.TimeKeyWentDown[i] = CurTime;
|
|
key_data.TimeKeyHeldDown[i] = 0;
|
|
key_data.NumDowns[i]=0;
|
|
key_data.NumUps[i]=0;
|
|
}
|
|
|
|
LEAVE_CRITICAL_SECTION( key_lock );
|
|
}
|
|
|
|
// A nifty function which performs the function:
|
|
// n = (n+1) % KEY_BUFFER_SIZE
|
|
// (assuming positive values of n).
|
|
int add_one( int n )
|
|
{
|
|
n++;
|
|
if ( n >= KEY_BUFFER_SIZE ) n=0;
|
|
return n;
|
|
}
|
|
|
|
// Returns 1 if character waiting... 0 otherwise
|
|
int key_checkch()
|
|
{
|
|
int is_one_waiting = 0;
|
|
|
|
if ( !key_inited ) return 0;
|
|
|
|
ENTER_CRITICAL_SECTION( key_lock );
|
|
|
|
if (key_data.keytail != key_data.keyhead){
|
|
is_one_waiting = 1;
|
|
}
|
|
|
|
LEAVE_CRITICAL_SECTION( key_lock );
|
|
|
|
return is_one_waiting;
|
|
}
|
|
|
|
// Return key scancode if a key has been pressed,
|
|
// else return 0.
|
|
// Reads keys out of the key buffer and updates keyhead.
|
|
|
|
//WMC - Added so scripting can get at keys.
|
|
int Current_key_down = 0;
|
|
int key_inkey()
|
|
{
|
|
int key = 0;
|
|
|
|
if ( !key_inited ) return 0;
|
|
|
|
ENTER_CRITICAL_SECTION( key_lock );
|
|
|
|
if (key_data.keytail!=key_data.keyhead) {
|
|
key = key_data.keybuffer[key_data.keyhead];
|
|
key_data.keyhead = add_one(key_data.keyhead);
|
|
}
|
|
|
|
LEAVE_CRITICAL_SECTION( key_lock );
|
|
|
|
Current_key_down = key;
|
|
|
|
return key;
|
|
}
|
|
|
|
// Unget a key. Puts it back in the input queue.
|
|
void key_outkey(int key)
|
|
{
|
|
int bufp;
|
|
|
|
if ( !key_inited ) return;
|
|
|
|
ENTER_CRITICAL_SECTION( key_lock );
|
|
|
|
bufp = key_data.keytail+1;
|
|
|
|
if (bufp >= KEY_BUFFER_SIZE){
|
|
bufp = 0;
|
|
}
|
|
|
|
key_data.keybuffer[key_data.keytail] = (unsigned short)key;
|
|
|
|
key_data.keytail = bufp;
|
|
|
|
LEAVE_CRITICAL_SECTION( key_lock );
|
|
}
|
|
|
|
|
|
|
|
// Return amount of time last key was held down.
|
|
// This is currently (July 17, 1996) bogus because our timing is
|
|
// not accurate.
|
|
int key_inkey_time(uint * time)
|
|
{
|
|
int key = 0;
|
|
|
|
if ( !key_inited ) {
|
|
*time = 0;
|
|
return 0;
|
|
}
|
|
|
|
ENTER_CRITICAL_SECTION( key_lock );
|
|
|
|
if (key_data.keytail!=key_data.keyhead) {
|
|
key = key_data.keybuffer[key_data.keyhead];
|
|
*time = key_data.time_pressed[key_data.keyhead];
|
|
key_data.keyhead = add_one(key_data.keyhead);
|
|
}
|
|
|
|
LEAVE_CRITICAL_SECTION( key_lock );
|
|
|
|
return key;
|
|
}
|
|
|
|
|
|
// Returns scancode of last key pressed, if any (returns 0 if no key pressed)
|
|
// but does not update keyhead pointer.
|
|
int key_peekkey()
|
|
{
|
|
int key = 0;
|
|
|
|
if ( !key_inited ) return 0;
|
|
|
|
ENTER_CRITICAL_SECTION( key_lock );
|
|
|
|
if (key_data.keytail!=key_data.keyhead) {
|
|
key = key_data.keybuffer[key_data.keyhead];
|
|
}
|
|
LEAVE_CRITICAL_SECTION( key_lock );
|
|
|
|
return key;
|
|
}
|
|
|
|
// If not installed, uses BIOS and returns getch();
|
|
// Else returns pending key (or waits for one if none waiting).
|
|
int key_getch()
|
|
{
|
|
int dummy=0;
|
|
int in;
|
|
|
|
if ( !key_inited ) return 0;
|
|
|
|
while (!key_checkch()){
|
|
os_poll();
|
|
|
|
dummy++;
|
|
}
|
|
in = key_inkey();
|
|
|
|
return in;
|
|
}
|
|
|
|
// Set global shift_status with modifier results (shift, ctrl, alt).
|
|
uint key_get_shift_status()
|
|
{
|
|
unsigned int shift_status = 0;
|
|
|
|
if ( !key_inited ) return 0;
|
|
|
|
ENTER_CRITICAL_SECTION( key_lock );
|
|
|
|
if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] )
|
|
shift_status |= KEY_SHIFTED;
|
|
|
|
if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] )
|
|
shift_status |= KEY_ALTED;
|
|
|
|
if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] )
|
|
shift_status |= KEY_CTRLED;
|
|
|
|
#ifndef NDEBUG
|
|
if (keyd_pressed[KEY_DEBUG_KEY])
|
|
shift_status |= KEY_DEBUGGED;
|
|
#else
|
|
if (keyd_pressed[KEY_DEBUG_KEY]) {
|
|
mprintf(("Cheats_enabled = %i, Key_normal_game = %i\n", Cheats_enabled, Key_normal_game));
|
|
if ((Cheats_enabled) && Key_normal_game) {
|
|
mprintf(("Debug key\n"));
|
|
shift_status |= KEY_DEBUGGED1;
|
|
}
|
|
}
|
|
#endif
|
|
LEAVE_CRITICAL_SECTION( key_lock );
|
|
|
|
return shift_status;
|
|
}
|
|
|
|
// Returns amount of time key (specified by "code") has been down since last call.
|
|
// Returns float, unlike key_down_time() which returns a fix.
|
|
float key_down_timef(uint scancode)
|
|
{
|
|
uint time_down, time;
|
|
uint delta_time;
|
|
|
|
if ( !key_inited ) {
|
|
return 0.0f;
|
|
}
|
|
|
|
if (scancode >= NUM_KEYS) {
|
|
return 0.0f;
|
|
}
|
|
|
|
ENTER_CRITICAL_SECTION( key_lock );
|
|
|
|
time = timer_get_milliseconds();
|
|
delta_time = time - key_data.TimeKeyDownChecked[scancode];
|
|
key_data.TimeKeyDownChecked[scancode] = time;
|
|
|
|
if ( delta_time <= 1 ) {
|
|
key_data.TimeKeyWentDown[scancode] = time;
|
|
if (keyd_pressed[scancode]) {
|
|
LEAVE_CRITICAL_SECTION( key_lock );
|
|
return 1.0f;
|
|
} else {
|
|
LEAVE_CRITICAL_SECTION( key_lock );
|
|
return 0.0f;
|
|
}
|
|
}
|
|
|
|
if ( !keyd_pressed[scancode] ) {
|
|
time_down = key_data.TimeKeyHeldDown[scancode];
|
|
key_data.TimeKeyHeldDown[scancode] = 0;
|
|
} else {
|
|
time_down = time - key_data.TimeKeyWentDown[scancode];
|
|
key_data.TimeKeyWentDown[scancode] = time;
|
|
}
|
|
|
|
LEAVE_CRITICAL_SECTION( key_lock );
|
|
|
|
return i2fl(time_down) / i2fl(delta_time);
|
|
}
|
|
|
|
/*
|
|
// Returns amount of time key (specified by "code") has been down since last call.
|
|
// Returns float, unlike key_down_time() which returns a fix.
|
|
fix key_down_time( uint code )
|
|
{
|
|
uint time_down, time;
|
|
uint delta_time;
|
|
|
|
if ( !key_inited ) return 0.0f;
|
|
|
|
if ((scancode<0)|| (scancode>=NUM_KEYS)) return 0.0f;
|
|
|
|
EnterCriticalSection( &key_lock );
|
|
|
|
time = timer_get_milliseconds();
|
|
delta_time = time - TimeKeyDownChecked[scancode];
|
|
TimeKeyDownChecked[scancode] = time;
|
|
|
|
if ( delta_time <= 1 ) {
|
|
LeaveCriticalSection( &key_lock );
|
|
if (keyd_pressed[scancode])
|
|
return F1_0;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
if ( !keyd_pressed[scancode] ) {
|
|
time_down = key_data.TimeKeyHeldDown[scancode];
|
|
key_data.TimeKeyHeldDown[scancode] = 0;
|
|
} else {
|
|
time_down = time - key_data.TimeKeyWentDown[scancode];
|
|
key_data.TimeKeyWentDown[scancode] = time;
|
|
}
|
|
|
|
LeaveCriticalSection( &key_lock );
|
|
|
|
return fixmuldiv( time_down, F1_0, delta_time );
|
|
}
|
|
*/
|
|
|
|
|
|
// Returns number of times key has went from up to down since last call.
|
|
int key_down_count(int scancode)
|
|
{
|
|
int n;
|
|
|
|
if ( !key_inited ) return 0;
|
|
if ((scancode<0)|| (scancode>=NUM_KEYS)) return 0;
|
|
|
|
ENTER_CRITICAL_SECTION( key_lock );
|
|
|
|
n = key_data.NumDowns[scancode];
|
|
key_data.NumDowns[scancode] = 0;
|
|
|
|
LEAVE_CRITICAL_SECTION( key_lock );
|
|
|
|
return n;
|
|
}
|
|
|
|
|
|
// Returns number of times key has went from down to up since last call.
|
|
int key_up_count(int scancode)
|
|
{
|
|
int n;
|
|
|
|
if ( !key_inited ) return 0;
|
|
if ((scancode<0)|| (scancode>=NUM_KEYS)) return 0;
|
|
|
|
ENTER_CRITICAL_SECTION( key_lock );
|
|
|
|
n = key_data.NumUps[scancode];
|
|
key_data.NumUps[scancode] = 0;
|
|
|
|
LEAVE_CRITICAL_SECTION( key_lock );
|
|
|
|
return n;
|
|
}
|
|
|
|
int key_check(int key)
|
|
{
|
|
return key_data.down_check[key];
|
|
}
|
|
|
|
// Add a key up or down code to the key buffer. state=1 -> down, state=0 -> up
|
|
// latency => time difference in ms between when key was actually pressed and now
|
|
//void key_mark( uint code, int state )
|
|
void key_mark( uint code, int state, uint latency )
|
|
{
|
|
uint scancode, breakbit, temp, event_time;
|
|
ushort keycode;
|
|
|
|
if ( !key_inited ) return;
|
|
|
|
ENTER_CRITICAL_SECTION( key_lock );
|
|
|
|
// If running in the UK, need to translate their wacky slash scancode to ours
|
|
if ( code == KEY_SLASH_UK ) {
|
|
code = KEY_SLASH;
|
|
}
|
|
|
|
#ifndef SCP_UNIX
|
|
|
|
if ( (code == 0xc5) && !Key_running_NT ) {
|
|
key_turn_off_numlock();
|
|
}
|
|
#endif
|
|
|
|
Assert( code < NUM_KEYS );
|
|
|
|
event_time = timer_get_milliseconds() - latency;
|
|
// event_time = timeGetTime() - latency;
|
|
|
|
// Read in scancode
|
|
scancode = code & (NUM_KEYS-1);
|
|
breakbit = !state;
|
|
|
|
if (breakbit) {
|
|
// Key going up
|
|
keyd_last_released = scancode;
|
|
keyd_pressed[scancode] = 0;
|
|
key_data.NumUps[scancode]++;
|
|
|
|
// What is the point of this code? "temp" is never used!
|
|
temp = 0;
|
|
temp |= keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT];
|
|
temp |= keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT];
|
|
temp |= keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL];
|
|
temp |= keyd_pressed[KEY_DEBUG_KEY];
|
|
|
|
if (event_time < key_data.TimeKeyWentDown[scancode]) {
|
|
key_data.TimeKeyHeldDown[scancode] = 0;
|
|
} else {
|
|
key_data.TimeKeyHeldDown[scancode] += event_time - key_data.TimeKeyWentDown[scancode];
|
|
}
|
|
|
|
Current_key_down = scancode;
|
|
if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] ) {
|
|
Current_key_down |= KEY_SHIFTED;
|
|
}
|
|
|
|
if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] ) {
|
|
Current_key_down |= KEY_ALTED;
|
|
}
|
|
|
|
if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] ) {
|
|
Current_key_down |= KEY_CTRLED;
|
|
}
|
|
|
|
Script_system.SetHookVar("Key", 's', textify_scancode(Current_key_down));
|
|
Script_system.RunCondition(CHA_KEYRELEASED);
|
|
Script_system.RemHookVar("Key");
|
|
} else {
|
|
// Key going down
|
|
keyd_last_pressed = scancode;
|
|
keyd_time_when_last_pressed = event_time;
|
|
if (!keyd_pressed[scancode]) {
|
|
// First time down
|
|
key_data.TimeKeyWentDown[scancode] = event_time;
|
|
keyd_pressed[scancode] = 1;
|
|
key_data.NumDowns[scancode]++;
|
|
key_data.down_check[scancode]++;
|
|
|
|
//WMC - For scripting
|
|
Current_key_down = scancode;
|
|
if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] ) {
|
|
Current_key_down |= KEY_SHIFTED;
|
|
}
|
|
|
|
if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] ) {
|
|
Current_key_down |= KEY_ALTED;
|
|
}
|
|
|
|
if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] ) {
|
|
Current_key_down |= KEY_CTRLED;
|
|
}
|
|
|
|
Script_system.SetHookVar("Key", 's', textify_scancode(Current_key_down));
|
|
Script_system.RunCondition(CHA_KEYPRESSED);
|
|
Script_system.RemHookVar("Key");
|
|
} else if (!keyd_repeat) {
|
|
// Don't buffer repeating key if repeat mode is off
|
|
scancode = 0xAA;
|
|
}
|
|
|
|
if ( scancode!=0xAA ) {
|
|
keycode = (unsigned short)scancode;
|
|
|
|
if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] ) {
|
|
keycode |= KEY_SHIFTED;
|
|
}
|
|
|
|
if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] ) {
|
|
keycode |= KEY_ALTED;
|
|
}
|
|
|
|
if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] ) {
|
|
keycode |= KEY_CTRLED;
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
if ( keyd_pressed[KEY_DEBUG_KEY] ) {
|
|
keycode |= KEY_DEBUGGED;
|
|
}
|
|
#else
|
|
if ( keyd_pressed[KEY_DEBUG_KEY] ) {
|
|
mprintf(("Cheats_enabled = %i, Key_normal_game = %i\n", Cheats_enabled, Key_normal_game));
|
|
if (Cheats_enabled && Key_normal_game) {
|
|
keycode |= KEY_DEBUGGED1;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
if ( keycode ) {
|
|
temp = key_data.keytail+1;
|
|
if ( temp >= KEY_BUFFER_SIZE ) temp=0;
|
|
|
|
if (temp!=key_data.keyhead) {
|
|
key_data.keybuffer[key_data.keytail] = keycode;
|
|
key_data.time_pressed[key_data.keytail] = keyd_time_when_last_pressed;
|
|
key_data.keytail = temp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LEAVE_CRITICAL_SECTION( key_lock );
|
|
}
|
|
|
|
#ifdef USE_DIRECTINPUT
|
|
void di_cleanup();
|
|
int di_init();
|
|
#endif
|
|
|
|
|
|
void key_close()
|
|
{
|
|
if ( !key_inited ) return;
|
|
|
|
#ifdef USE_DIRECTINPUT
|
|
di_cleanup();
|
|
#endif
|
|
|
|
if ( Key_numlock_was_on ) {
|
|
key_turn_on_numlock();
|
|
Key_numlock_was_on = 0;
|
|
}
|
|
|
|
key_inited = 0;
|
|
|
|
DELETE_CRITICAL_SECTION( key_lock );
|
|
}
|
|
|
|
void key_init()
|
|
{
|
|
// Initialize queue
|
|
if ( key_inited ) return;
|
|
key_inited = 1;
|
|
|
|
INITIALIZE_CRITICAL_SECTION( key_lock );
|
|
|
|
ENTER_CRITICAL_SECTION( key_lock );
|
|
|
|
#ifdef SCP_UNIX
|
|
FillSDLArray();
|
|
#endif
|
|
|
|
keyd_time_when_last_pressed = timer_get_milliseconds();
|
|
keyd_buffer_type = 1;
|
|
keyd_repeat = 1;
|
|
|
|
// Clear the keyboard array
|
|
key_flush();
|
|
|
|
LEAVE_CRITICAL_SECTION( key_lock );
|
|
|
|
#ifdef _WIN32
|
|
#ifdef USE_DIRECTINPUT
|
|
di_init();
|
|
#endif
|
|
|
|
OSVERSIONINFO ver;
|
|
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
GetVersionEx(&ver);
|
|
if ( ver.dwPlatformId == VER_PLATFORM_WIN32_NT ) {
|
|
Key_running_NT = 1;
|
|
} else {
|
|
Key_running_NT = 0;
|
|
if ( key_numlock_is_on() ) {
|
|
Key_numlock_was_on = 1;
|
|
key_turn_off_numlock();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
atexit(key_close);
|
|
}
|
|
|
|
void key_level_init()
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i<NUM_KEYS; i++)
|
|
key_data.down_check[i] = 0;
|
|
}
|
|
|
|
void key_lost_focus()
|
|
{
|
|
if ( !key_inited ) return;
|
|
|
|
key_flush();
|
|
}
|
|
|
|
void key_got_focus()
|
|
{
|
|
if ( !key_inited ) return;
|
|
|
|
key_flush();
|
|
}
|
|
|
|
#ifdef USE_DIRECTINPUT
|
|
|
|
// JAS - April 18, 1998
|
|
// Not using because DI has the following problems: (Everything else works ok)
|
|
// Under NT, Pause and Numlock report as identical keys.
|
|
// Under 95, Pause is the same as pressing Ctrl then Numlock. So the game fires each
|
|
// time you hit it.
|
|
//
|
|
|
|
//============================================================================
|
|
// Direct Input code
|
|
// For the keyboard, this basically replaces our old functionallity of:
|
|
// WM_KEYDOWN:
|
|
// key_mark(...);
|
|
// WM_KEYUP:
|
|
// key_mark(...);
|
|
//============================================================================
|
|
|
|
|
|
#include "directx/vdinput.h"
|
|
|
|
#define MAX_BUFFERED_KEYBOARD_EVENTS 10
|
|
|
|
static LPDIRECTINPUT Di_object = NULL;
|
|
static LPDIRECTINPUTDEVICE Di_keyboard = NULL;
|
|
static HANDLE Di_thread = NULL;
|
|
static DWORD Di_thread_id = NULL;
|
|
static HANDLE Di_event = NULL;
|
|
|
|
DWORD di_process(DWORD lparam)
|
|
{
|
|
while (1) {
|
|
if ( WaitForSingleObject( Di_event, INFINITE )==WAIT_OBJECT_0 ) {
|
|
|
|
//mprintf(( "Got event!\n" ));
|
|
|
|
HRESULT hr;
|
|
|
|
DIDEVICEOBJECTDATA rgdod[10];
|
|
DWORD dwItems = MAX_BUFFERED_KEYBOARD_EVENTS;
|
|
|
|
again:;
|
|
hr = Di_keyboard->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), rgdod, &dwItems, 0);
|
|
|
|
if (hr == DIERR_INPUTLOST) {
|
|
/*
|
|
* DirectInput is telling us that the input stream has
|
|
* been interrupted. We aren't tracking any state
|
|
* between polls, so we don't have any special reset
|
|
* that needs to be done. We just re-acquire and
|
|
* try again.
|
|
*/
|
|
Sleep(1000); // Pause a second...
|
|
hr = Di_keyboard->Acquire();
|
|
if (SUCCEEDED(hr)) {
|
|
goto again;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
// dwItems = number of elements read (could be zero)
|
|
if (hr == DI_BUFFEROVERFLOW) {
|
|
// Buffer had overflowed.
|
|
mprintf(( "Buffer overflowed!\n" ));
|
|
}
|
|
int i;
|
|
|
|
//mprintf(( "Got %d events\n", dwItems ));
|
|
|
|
for (i=0; i<(int)dwItems; i++ ) {
|
|
int key = rgdod[i].dwOfs;
|
|
int state = rgdod[i].dwData;
|
|
int stamp = rgdod[i].dwTimeStamp;
|
|
|
|
int latency;
|
|
latency = timeGetTime() - stamp;
|
|
if ( latency < 0 )
|
|
latency=0;
|
|
|
|
// if ( key == KEY_PRINT_SCRN ) {
|
|
// key_mark( key, 1, latency );
|
|
// }
|
|
// key_mark( key, (state&0x80?1:0), latency );
|
|
mprintf(( "Key=%x, State=%x, Time=%d, Latency=%d\n", key, state, stamp, latency ));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int di_init()
|
|
{
|
|
HRESULT hr;
|
|
|
|
return 0;
|
|
|
|
|
|
/*
|
|
* Register with the DirectInput subsystem and get a pointer
|
|
* to a IDirectInput interface we can use.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* g_hinst
|
|
*
|
|
* Instance handle to our application or DLL.
|
|
*
|
|
* DIRECTINPUT_VERSION
|
|
*
|
|
* The version of DirectInput we were designed for.
|
|
* We take the value from the <dinput.h> header file.
|
|
*
|
|
* &g_pdi
|
|
*
|
|
* Receives pointer to the IDirectInput interface
|
|
* that was created.
|
|
*
|
|
* NULL
|
|
*
|
|
* We do not use OLE aggregation, so this parameter
|
|
* must be NULL.
|
|
*
|
|
*/
|
|
hr = DirectInputCreate(GetModuleHandle(NULL), 0x300, &Di_object, NULL);
|
|
|
|
if (FAILED(hr)) {
|
|
mprintf(( "DirectInputCreate failed!\n" ));
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Obtain an interface to the system keyboard device.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* GUID_SysKeyboard
|
|
*
|
|
* The instance GUID for the device we wish to access.
|
|
* GUID_SysKeyboard is a predefined instance GUID that
|
|
* always refers to the system keyboard device.
|
|
*
|
|
* &g_pKeyboard
|
|
*
|
|
* Receives pointer to the IDirectInputDevice interface
|
|
* that was created.
|
|
*
|
|
* NULL
|
|
*
|
|
* We do not use OLE aggregation, so this parameter
|
|
* must be NULL.
|
|
*
|
|
*/
|
|
hr = Di_object->CreateDevice(GUID_SysKeyboard, &Di_keyboard, NULL);
|
|
|
|
if (FAILED(hr)) {
|
|
mprintf(( "CreateDevice failed!\n" ));
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Set the data format to "keyboard format".
|
|
*
|
|
* A data format specifies which controls on a device we
|
|
* are interested in, and how they should be reported.
|
|
*
|
|
* This tells DirectInput that we will be passing an array
|
|
* of 256 bytes to IDirectInputDevice::GetDeviceState.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* c_dfDIKeyboard
|
|
*
|
|
* Predefined data format which describes
|
|
* an array of 256 bytes, one per scancode.
|
|
*/
|
|
hr = Di_keyboard->SetDataFormat(&c_dfDIKeyboard);
|
|
|
|
if (FAILED(hr)) {
|
|
mprintf(( "SetDataFormat failed!\n" ));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Set the cooperativity level to let DirectInput know how
|
|
* this device should interact with the system and with other
|
|
* DirectInput applications.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* DISCL_NONEXCLUSIVE
|
|
*
|
|
* Retrieve keyboard data when acquired, not interfering
|
|
* with any other applications which are reading keyboard
|
|
* data.
|
|
*
|
|
* DISCL_FOREGROUND
|
|
*
|
|
* If the user switches away from our application,
|
|
* automatically release the keyboard back to the system.
|
|
*
|
|
*/
|
|
hr = Di_keyboard->SetCooperativeLevel((HWND)os_get_window(), DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
|
|
|
|
if (FAILED(hr)) {
|
|
mprintf(( "SetCooperativeLevel failed!\n" ));
|
|
return FALSE;
|
|
}
|
|
|
|
DIPROPDWORD hdr;
|
|
|
|
// Turn on buffering
|
|
hdr.diph.dwSize = sizeof(DIPROPDWORD);
|
|
hdr.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
|
hdr.diph.dwObj = 0;
|
|
hdr.diph.dwHow = DIPH_DEVICE; // Apply to entire device
|
|
hdr.dwData = 16; //MAX_BUFFERED_KEYBOARD_EVENTS;
|
|
|
|
hr = Di_keyboard->SetProperty( DIPROP_BUFFERSIZE, &hdr.diph );
|
|
if (FAILED(hr)) {
|
|
mprintf(( "SetProperty DIPROP_BUFFERSIZE failed\n" ));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
Di_event = CreateEvent( NULL, FALSE, FALSE, NULL );
|
|
Assert(Di_event != NULL);
|
|
|
|
Di_thread = CreateThread(NULL, 1024, (LPTHREAD_START_ROUTINE)di_process, NULL, 0, &Di_thread_id);
|
|
Assert( Di_thread != NULL );
|
|
|
|
SetThreadPriority(Di_thread, THREAD_PRIORITY_HIGHEST);
|
|
|
|
hr = Di_keyboard->SetEventNotification(Di_event);
|
|
if (FAILED(hr)) {
|
|
mprintf(( "SetEventNotification failed\n" ));
|
|
return FALSE;
|
|
}
|
|
|
|
Di_keyboard->Acquire();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void di_cleanup()
|
|
{
|
|
/*
|
|
* Destroy any lingering IDirectInputDevice object.
|
|
*/
|
|
if (Di_keyboard) {
|
|
|
|
/*
|
|
* Cleanliness is next to godliness. Unacquire the device
|
|
* one last time just in case we got really confused and tried
|
|
* to exit while the device is still acquired.
|
|
*/
|
|
Di_keyboard->Unacquire();
|
|
|
|
Di_keyboard->Release();
|
|
Di_keyboard = NULL;
|
|
}
|
|
|
|
/*
|
|
* Destroy any lingering IDirectInput object.
|
|
*/
|
|
if (Di_object) {
|
|
Di_object->Release();
|
|
Di_object = NULL;
|
|
}
|
|
|
|
if ( Di_event ) {
|
|
CloseHandle(Di_event);
|
|
Di_event = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|